Recorded at V1 iteration 191 and again at 192, so it is a pattern rather than an incident — but the first diagnosis was imprecise and this issue corrects it.
Measured
tools/launchd/mission-control.sh resolves the controller model into a shell variable MODEL (:215 env pin, :225 override file, :233 probe-ok) and passes it to the session as a flag — claude -p --model "$MODEL". It never exports it:
grep -cE '^[[:space:]]*export MODEL=|^[[:space:]]*export MODEL$' -> 0
grep -cE '^[[:space:]]*export MISSION_EVALUATOR_MODEL=' -> 1 # known-positive control
grep -c '^export MISSION_' -> 9 # the vars that ARE exported
So inside the controller session, echo $MODEL is empty on every fire — confirmed live at iterations 191 and 192.
Why it matters (and what it is NOT)
It is not that the controller runs on the wrong model: the --model flag still pins the session. Iteration 191's record says the controller "rode fable-5 by session inheritance because $MODEL was UNSET" — the unset variable is real, but it is not evidence about which model ran, and that record overstates it. Iteration 192 rode opus with $MODEL equally empty.
What it actually breaks is the skill's routing contract, which is written against an exported value:
All three read a variable that is always empty, so the end-of-chain fallback is unreachable as written and the routing-evidence row cannot name the controller's model by measurement. Today that is papered over because the session default happens to match the policy pin — i.e. the invariant holds by luck, not by configuration.
Fix
Export it alongside the nine MISSION_* vars, and export the reason too so the evidence row can cite provenance rather than infer it:
export MODEL MODEL_WHY # MODEL_WHY is already computed at :215/:225/:233
Then the Gate-4 routing-evidence row can record controller=$MODEL ($MODEL_WHY) as a measurement.
Acceptance
MODEL and MODEL_WHY readable inside the controller session (assert non-empty at Gate 0; an empty MODEL should FLAG rather than pass silently).
- The value matches the
--model flag actually passed — one drill where the two disagree must be detectable.
Related: #611 (the ratified fallback chain that terminates at $MODEL), #493 (a different driver-env defect on the same script).
Recorded at V1 iteration 191 and again at 192, so it is a pattern rather than an incident — but the first diagnosis was imprecise and this issue corrects it.
Measured
tools/launchd/mission-control.shresolves the controller model into a shell variableMODEL(:215env pin,:225override file,:233probe-ok) and passes it to the session as a flag —claude -p --model "$MODEL". It never exports it:So inside the controller session,
echo $MODELis empty on every fire — confirmed live at iterations 191 and 192.Why it matters (and what it is NOT)
It is not that the controller runs on the wrong model: the
--modelflag still pins the session. Iteration 191's record says the controller "rode fable-5 by session inheritance because$MODELwas UNSET" — the unset variable is real, but it is not evidence about which model ran, and that record overstates it. Iteration 192 rode opus with$MODELequally empty.What it actually breaks is the skill's routing contract, which is written against an exported value:
$MODEL".$MODELfor that role and FLAG it" — and the Gate-3 chain rule (mission driver: executor fallback chain codex → pi-deepseek → opus (Mark 2026-08-06) — replace the hardcoded opus fallback #611) makes$MODELthe documented end-of-chain.All three read a variable that is always empty, so the end-of-chain fallback is unreachable as written and the routing-evidence row cannot name the controller's model by measurement. Today that is papered over because the session default happens to match the policy pin — i.e. the invariant holds by luck, not by configuration.
Fix
Export it alongside the nine
MISSION_*vars, and export the reason too so the evidence row can cite provenance rather than infer it:Then the Gate-4 routing-evidence row can record
controller=$MODEL ($MODEL_WHY)as a measurement.Acceptance
MODELandMODEL_WHYreadable inside the controller session (assert non-empty at Gate 0; an emptyMODELshould FLAG rather than pass silently).--modelflag actually passed — one drill where the two disagree must be detectable.Related: #611 (the ratified fallback chain that terminates at
$MODEL), #493 (a different driver-env defect on the same script).