Skip to content

test(mission): guard that the controller model pin is EXPORTED, not just assigned (#696) - #741

Merged
sunholo-voight-kampff merged 1 commit into
devfrom
sprint/iter216-model-export-guard
Aug 17, 2026
Merged

test(mission): guard that the controller model pin is EXPORTED, not just assigned (#696)#741
sunholo-voight-kampff merged 1 commit into
devfrom
sprint/iter216-model-export-guard

Conversation

@sunholo-voight-kampff

Copy link
Copy Markdown
Collaborator

What

Adds a CI-gated regression guard proving the mission controller's model pin is exported, not merely assigned — and gitignores a stray root-level build artifact.

Why — #696, ghost-disciplined at HEAD

#696 reported that tools/launchd/mission-control.sh never exported MODEL, so the skill's routing contract ($MODEL/$MODEL_WHY, and the #611 end-of-chain fallback every role terminates at) was reading an always-empty variable.

The defect was REAL when filed (2026-08-13) and is FIXED at HEAD. de0e41099 (2026-08-15) introduced _mc_set_controller, whose single export CONTROLLER_PROVIDER CONTROLLER_ID MODEL MODEL_WHY MISSION_ANTHROPIC_AVAILABLE (:234) runs on all four select_model paths — env pin (:239), override file (:249), probe-ok (:257), Anthropic-unavailable Codex fallback (:267). Live-confirmed in a scheduled fire: MODEL=claude-opus-5, MODEL_WHY=probe ok.

#696's own measurement was an over-anchored pattern (^\s*export MODEL=|^\s*export MODEL$) that cannot match a multi-variable bare export, which is why the fix arriving incidentally went unnoticed.

Nothing guarded it, so it could regress silently. test_mission_routing.sh already sourced the real selector into a lab, but read MODEL_WHY in the same shell — an assertion that passes whether or not export is present. Prior coverage was hollow for exactly this defect.

The new arm

Reads the variables from a child process (/usr/bin/env) — the only observable the export keyword moves — with an in-call known-positive control (MC_EXPORT_CONTROL) so a broken pipeline cannot masquerade as a missing export.

Mutation drills (both under /bin/bash 3.2.57 — the rig's shell; CI asserts 3.x)

drill result
Reproduce #696: drop MODEL MODEL_WHY from the export list. Mutant LANDED (sha256 changed) and valid (bash -n rc=0) all 9 pre-existing arms green, only the new arm failed, control still firing → the new arm is the killer, not a bystander
Precondition-neutering: weaken the arm's own unset, keep the mutant arm PASSED vacuously — a suite run by the mission loop inherits the controller's real MODEL/MODEL_WHY, which match the expected string exactly. The unset is what closes this.

Driver restored from a copy (not git checkout --) and verified byte-identical by sha256 + git diff --quiet.

Also

/govulncheck-filter added to .gitignore, root-anchored so it cannot shadow the tracked tools/govulncheck-filter/ source dir — the same hazard the adjacent /wasm entry documents. Verified with four controls (root artifact ignored; tracked source not ignored; /wasm still ignored; a random new file not ignored). It has sat untracked in the driver-pin worktree since 2026-08-15, and mission iterations 213/214/215 each had to note and route around it at Gate 0.

Gates

Baselined on pristine origin/dev first (rc=0, 9 passed / 0 failed), so these measure the change rather than the repo:

  • make test-launchd-driversrc=0, 10 passed / 0 failed
  • make check-changelog → rc=0
  • gofmt -l → 0 files

Platform: green on darwin/arm64; the ubuntu and windows CI legs are unrun locally.

Fixes #696

🤖 Generated with Claude Code

…ust assigned (#696)

#696 reported that `mission-control.sh` never exported `MODEL`, leaving the skill's
routing contract (`$MODEL`/`$MODEL_WHY`, and the #611 end-of-chain fallback) reading an
always-empty variable. Ghost-disciplined at HEAD: the defect was REAL when filed and is
FIXED by de0e410 (2026-08-15), whose `_mc_set_controller` exports both at :234 on all
four `select_model` paths. Live-confirmed in a scheduled fire (MODEL=claude-opus-5,
MODEL_WHY="probe ok").

Nothing guarded it, so the fix could regress silently. `test_mission_routing.sh` already
sourced the real selector into a lab but read `MODEL_WHY` in the SAME shell — an assertion
that passes whether or not `export` is present. The new arm reads the variables from a
CHILD process (`/usr/bin/env`), the only observable the `export` keyword moves, with an
in-call known-positive control (MC_EXPORT_CONTROL) so a broken pipeline cannot masquerade
as a missing export.

Mutation drills, both under /bin/bash 3.2.57 (the rig's shell; CI asserts 3.x):
- Reproducing #696 (drop `MODEL MODEL_WHY` from the export list) — mutant LANDED (sha256
  changed) and syntactically valid (`bash -n` rc=0): all NINE pre-existing arms stayed
  green, only the new arm failed, and the control still fired. So the new arm is the
  killer rather than a bystander, and prior coverage was genuinely hollow here.
- Precondition-neutering: weakening the arm's own `unset` made it PASS under that same
  mutant, because a suite run by the mission loop inherits the controller's real
  MODEL/MODEL_WHY (which match the expected string exactly). The guard would have been
  vacuous precisely where it matters; the `unset` is what closes that.
Driver restored from a copy and verified byte-identical (sha256 + `git diff --quiet`).

Also gitignores the root-level `govulncheck-filter` build artifact, root-anchored so it
cannot shadow the tracked `tools/govulncheck-filter/` source dir (same hazard the adjacent
`/wasm` entry documents). It has sat untracked in the driver-pin worktree since 2026-08-15
and iterations 213/214/215 each had to note and route around it at Gate 0.

Gates (darwin/arm64; ubuntu + windows legs unrun locally): `make test-launchd-drivers`
rc=0 (10 passed, 0 failed) · `make check-changelog` rc=0 · `gofmt -l` 0 files.
Baselined on pristine origin/dev first: rc=0, 9 passed / 0 failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@sunholo-voight-kampff
sunholo-voight-kampff merged commit 3a75ec7 into dev Aug 17, 2026
21 checks passed
@sunholo-voight-kampff
sunholo-voight-kampff deleted the sprint/iter216-model-export-guard branch August 17, 2026 05:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mission-control driver: $MODEL is never exported, so the controller cannot read its own routing pin (fallback rule is unreadable every fire)

1 participant