Repository navigation
fix(cron): refuse cross-vendor model/provider pairs at create/update time - #641
Merged
Merged
Conversation
…time A cron job pinned to a model and provider from different vendors (e.g. model='gpt-5.6-sol' + provider='claude-apr') is accepted today, persisted, and then fails EVERY fire with HTTP 400 'the model field names a different vendor model than this endpoint serves; retrying will not help'. It is a recurring class — it burned real scheduled jobs on 2026-08-19 and again on 2026-08-29, each time only noticed after the job had already failed fires. Promote the post-hoc cron-config-lint Rule #20b into a create/update-time admission gate alongside the existing Rule #5 I1 / #4a checks: * Infer each side's vendor from a conservative name-prefix map and refuse a provably cross-vendor pair. Unknown model or provider names yield vendor None and are NOT flagged (fail-open) — this catches obvious mis-pairs, it does not maintain a model catalog. * CREATE: check the requested pin before create_job() persists anything. * UPDATE: check the EFFECTIVE post-update pair, since an update may supply only 'model' or only 'provider' — repointing an openai-pinned job at an anthropic provider is only detectable after merging with the stored job. * Handle both stored model shapes: a plain name, and the {model, provider} object (whose inner provider is checked against the effective top-level provider too). The error names both inferred vendors and states retrying will not help, so the caller can fix the pin instead of re-trying a dead job. Tests: create rejected/allowed, fail-open on unrecognized names, update rejected when only the provider (or only the model) changes, update allowed when the pair stays consistent, and both model shapes.
Kyzcreig
force-pushed
the
fix/cron-vendor-consistency-admission
branch
from
August 29, 2026 13:32
c8ab7d1 to
40ac822
Compare
Collaborator
Author
FleetReviewConfidence: 3/5 Findings
FleetReview provenance · models: B=gpt-5.6-sol, C=claude-code-opus-4-8, D=grok-4.5, F=gpt-5.6-sol, G=grok-4.5 · cost: $6.14 · duration: 30m 36s · rounds: 3 · files examined: 2 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
cronjob(action='create')accepts a model and provider from different vendors. The job is persisted and then fails every fire with:This is a recurring class, not a one-off — it hit real scheduled jobs on 2026-08-19 and again on 2026-08-29 (
model="gpt-5.6-sol"+provider="claude-apr"). Each time it was only noticed after the job had burned failed fires, because nothing rejects the pair at admission time. A post-hoc lint catches it (Rule #20b), which is strictly too late for a job that is dead on arrival.Change
Promote that post-hoc rule into a create/update-time admission gate in
_creation_admission_error(), alongside the existing Rule #5 I1 (sub-hourlydeliver=origin) and Rule #4a (bare platform deliver) checks.claude/gpt-/gemini/grok/… → vendor;claude-*/openai*/codex/… → vendor). An unrecognized model or provider name yields vendorNoneand is not flagged. This catches obvious mis-pairs; it deliberately does not try to maintain a model catalog, so custom/local/proxied names are never blocked.create_job()persists anything.modelor onlyprovider, so repointing an openai-pinned job at an anthropic provider is only detectable after merging the update over the stored job.{"model": ..., "provider": ...}object (whose inner provider is also checked against the effective top-level provider, since either can be the one that routes).Example message:
Tests
tests/tools/test_cronjob_tools.py— newTestModelProviderVendorConsistency:Wider cron slice (62 files, 889 passed) has one pre-existing failure,
test_cronjob_run_background.py::test_dispatches_and_returns_handle_immediately— a 5sthreading.Eventtimeout that reproduces identically on unmodifiedfork/mainunder thesame parallel load and passes on both trees when run alone. Not introduced here.