Repository navigation
Description
Problem
Found by Codex review on PR #871 (head 07e72e8, P1, packages/core/src/session/model-governance.ts): governance (routeTargets/leaf()) prunes a leaf that cannot produce the pinned/route-requested variant, mirroring plugin expansion (#869). But in the retarget path, a model transform can add a leaf without the requested variant while the route still advertises that variant; ModelResolver.resolveSelected() then accepts the variant and model-resolver.ts loads that deployment with an undefined variant — it runs bare on failover. Because governance omitted the deployment entirely, a subagent exclusion naming that deployment no longer blocks it.
Why this is not a one-line fix
PR #871 deliberately implements — and tests — the opposite semantics for the catalog path (model-governance.test.ts: "a leaf that cannot produce the requested variant is pruned from governance, as in expansion (#869)"), where expansion really does drop the leaf and it never runs. The bypass needs the retarget/resolver path, where the leaf survives and runs bare. Reconciling the two needs a design call: either governance keeps a bare ref for leaves the resolver can run bare (and the #869 pruning test is re-scoped to the pure-expansion case), or runtime resolution guarantees such leaves cannot execute (resolver-side), or governance judges the retargeted definitions rather than the catalog.
Acceptance
- A retarget-added leaf that the resolver can run bare under a route-requested variant is judged by governance (an exclusion naming it denies), or the resolver demonstrably cannot run it bare, with a regression test for the transform + retarget + exclusion scenario from the Codex thread on PR fix(core): judge door-set variants through remaps and retarget across doors #871.
- The existing fix(routes): door-set governance variant remaps + retarget across concrete doors (PR #810 follow-up) #869 governance semantics for the pure catalog/expansion path stay intact or are explicitly re-decided in the PR.
- CI green.
Refs: PR #871, issue #869, task 3411. Filed by repo-queue-worker Lane A, 2026-10-29.
Acceptance criteria
- A retarget-added leaf that the resolver can run bare under a route-requested variant is judged by governance (an exclusion naming it denies), OR the resolver demonstrably cannot run it bare — with a regression test for the transform + retarget + exclusion scenario from the Codex thread on PR fix(core): judge door-set variants through remaps and retarget across doors #871
- The existing fix(routes): door-set governance variant remaps + retarget across concrete doors (PR #810 follow-up) #869 governance semantics for the pure catalog/expansion path stay intact (the pruning test re-scoped, not deleted, if semantics change)
- The chosen reconciliation (governance keeps a bare ref / resolver-side guarantee / governance judges retargeted definitions) is recorded on this issue with its rationale
Activity
developing-today commentedon Oct 29, 2026
OPENCODE-217
dezren39 commentedon Oct 29, 2026
Intake review
Related: PR #871 (Codex P1, head 07e72e8, packages/core/src/session/model-governance.ts); #869 (plugin-expansion pruning semantics this must not regress)
Notes: Filed 2026-10-29T13:56Z from a Codex P1 on PR #871, which is still OPEN — the bypass it describes is live in that PR's retarget path. Still live: no open or merged PR references #889. The issue body itself explains why it is not a one-line fix: #871 deliberately implements the opposite semantics for the catalog path.
Risks: A subagent exclusion that silently stops blocking a deployment is a governance/safety hole, not a cosmetic bug — hence priority/high. The fix must not break the deliberate #869 expansion pruning.
Suggested approach: Decide the reconciliation layer first (the issue lists the three candidate designs), then implement with the Codex scenario as the regression test.
🤖 Agent note · filed
meta/enrichedapplied. Still-live check this pass: no merged PR or fix commit explicitly resolving this issue was found; where a queue triage task owns verification, it is named in the notes.dezren39 commentedon Oct 29, 2026
Verified against PR #871 head
d77f8128a4(laneopenchamber-scheduled-lane, task 3411): the bypass this issue describes is closed by the variant refresh in203b8f7d1d, so the issue is being closed as addressed by #871.The premise no longer holds. The finding assumed "retargeting updates the route's settings but leaves its advertised variants unchanged".
retargetDefinition()now returnsrouteVariants(leaves)computed over the post-transform leaves, and the model transform writes it back (packages/core/src/config/plugin/model-routes.ts, model transform:draft.variants = variants). When a transform adds a deployment that cannot produce the requested variant natively or through its remap, that variant leaves the route's advertised set.Consequence at resolution time.
ModelResolver.resolveSelected()rejects any requested variant the route does not advertise (packages/core/src/model-resolver.ts~611:if (requestedVariant && !selected.variants.some(...)) VariantUnavailableError) beforeresolveRoute()picks a target. So the retarget-added deployment is never loaded with an undefined variant under that route variant, and an exclusion naming it has nothing to bypass: the run set is empty, not "the leaf runs bare". Governance pruning the same leaf is therefore consistent with the runtime — the judged set and the run set still agree.Regression coverage (
packages/core/test/model-route-transform-models.test.ts, "advertised variants after retargeting (#869)"):*/*over a catalog model offeringmax,high, transform adds a variant-less deployment, retarget yieldsvariants === [](the exact scenario from the Codex thread).maxis kept when the deployment offers it.Acceptance item 3 (rationale recorded): the reconciliation chosen is governance judges the variant the runtime can actually run, and the route advertises only what every leaf can produce, i.e. neither "keep a bare ref" nor a resolver-side rewrite was needed — the resolver already refuses an unadvertised variant.
Reopen if any resolution path can reach a route target without going through
resolveSelected(); none was found.