Subagent routing is not fail-closed: incompatible full-history forks silently inherit another model/quota pool (0.149.0)

Open 💬 1 comment Opened Aug 21, 2026 by AmeerJ97

What version of Codex CLI is running?

codex-cli 0.149.0, the current npm release at the time of this report.

What subscription do you have?

ChatGPT Pro 20x.

Which models were you using?

  • Affected coordinator: GPT-5.6 Terra, medium reasoning.
  • Requested child model: GPT-5.3-Codex-Spark, low reasoning.
  • Actual affected children: GPT-5.6 Terra, medium reasoning.
  • Controls: GPT-5.3-Codex-Spark low and GPT-5.6 Terra low.

What platform is your computer?

Ubuntu 24.04, Linux x86_64, Konsole under tmux.

Codex doctor report

codex doctor --json reported overall status OK. ChatGPT authentication,
provider reachability, WebSocket handshake, config parsing, and installation
checks passed. multi_agent and multi_agent_v2 were enabled.

What issue are you seeing?

Subagent model routing does not fail closed when a coordinator chooses a
full-history fork that is incompatible with the model the user requested.

In a long-running conversation, the user requested a Codex Spark fleet. After
a fresh restart exposed native delegation, the coordinator said it was starting
and operating that requested fleet.

It issued 26 spawn_agent calls. Every call used fork_turns: "all" and
omitted both model and reasoning_effort. Twenty-five child rollout files
were created; all 25 inherited the Terra-medium coordinator and reported the
ordinary weekly Codex pool. No affected child ran Spark.

The incompatibility is reproducible:

  1. A bounded explicit Spark-low spawn with fork_turns: "none" succeeds, and

the child runtime records Spark low with separate five-hour and weekly
windows.

  1. A bounded explicit Terra-low spawn with fork_turns: "none" succeeds, and

the child runtime records Terra low.

  1. A fresh coordinator instructed to combine Spark low with

fork_turns: "all", and to fail closed, reports that full-history forks
cannot accept model or reasoning-effort overrides and correctly spawns no
fallback.

The affected long-running coordinator encountered the same incompatibility but
did not fail closed. It silently emitted model-omitting full-history spawns and
continued the workflow with Terra children.

What steps can reproduce the bug?

  1. Start a parent on model A.
  2. Ask it to orchestrate model B subagents, where B has a materially different

quota bucket.

  1. Have the coordinator choose full-history forks.
  2. Observe that fork_turns: "all" is emitted without model or

reasoning_effort.

  1. Inspect the child rollout and observe that it silently inherited model A.
  2. Observe that the normal subagent surface does not disclose the resolved

model, setting source, or quota bucket.

Across 52 in-window spawn calls in the audited corpus:

  • 17 explicit model requests matched actual child runtime records.
  • 0 explicit model requests mismatched.
  • 33 calls omitted model and effort and inherited or used role defaults.
  • 2 calls had no child rollout record.

This report does not claim that explicit routing always fails. It reports that
an incompatible full-history choice can silently discard user-requested model
identity and quota expectations.

What is the expected behavior?

  • If requested child model B cannot be combined with the chosen fork mode,

Codex must reject the spawn rather than silently inherit parent model A.

  • An explicit user model request should be strict unless the user authorizes a

fallback.

  • The subagent UI and status API should show the resolved model, reasoning

effort, setting source (explicit, role pin, inherited, or fallback), and
effective quota bucket before and during execution.

  • The coordinator should not claim the requested fleet is running until runtime

metadata confirms the child model.

Additional information

Related but distinct reports:

  • #32283 — resolved subagent model and reasoning effort hidden in the UI
  • #33881 — configured subagent model pins and inheritance
  • #36432 — missing model-to-rate-limit-bucket mapping
  • #23150 — Spark usage appearing in regular and specialized buckets

I can provide exact thread identifiers and sanitized rollout-derived metadata
privately to maintainers if requested. No chat content, prompts, project names,
local paths, account identifiers, or credentials are included in this report.

View original on GitHub ↗

1 Comment

dajiaohuang · 6 days ago

I traced this in 0.149.0 and current main; there is a public guidance/runtime mismatch:

  • multi_agents.rs tells the coordinator that full-history forks do not accept model/effort overrides.
  • The same release's V2 spawn handler nevertheless applies requested model/effort for full-history forks. Merged #33631 explicitly added and tested fork_turns:"all" plus model/effort while retaining parent history; #37252 did likewise for role-selected models.

So full-history model switching is supported by public core. In the reported calls, model/effort are omitted because the injected usage hint tells the coordinator not to send them. Once omitted, the handler cannot distinguish intentional inheritance from a forgotten natural-language request. The closed #21404 guard would not catch omitted inputs and predates the two merged changes above.

A bounded fix is to align the V2 guidance/tool description with runtime and preserve explicit requested model/effort; core already validates both. For observability, V1 already emits a completed CollabAgentToolCall from the child snapshot, and current main captures the same resolved snapshot for V2 analytics, so V2 could emit the existing public item shape. Quota attribution remains separate: public model metadata has no rate-limit-bucket mapping, and a thread can consume another model during compaction. Cross-provider history normalization in #38365 is also separate because spawn_agent model overrides do not change provider.