ci: add the mutation tier over the governance core - #724
Conversation
StrykerJS 9.6.1 and @hughescr/stryker-bun-runner 1.3.8, pinned exact, mutate src/guards, src/chain and src/floor — nightly, on demand, and on the pull request that touches them. thresholds.break = 85 is a floor and a ratchet: the core kills 60.30% of 1,946 mutants, so the gate is red from its first run and stays red until the core climbs. The path filter guards-adversarial copied was a measured no-op (a shallow checkout cannot diff origin/<base>, so the job reported "skipped" for its whole life): both jobs now fetch history and fail hard when the diff cannot be computed, because a gate that cannot run is red, never green. This branch also carries the in-flight work that was uncommitted in the worktree, and the milestone's own slot (.ai-engineering/spec.html + plan.html + brainstorm.md, approved and pinned). Receipt-Id: fcc53011
@hughescr/stryker-bun-runner@1.3.8 pins smol-toml to 1.7.0 exactly, and that version is in the advisory range (<=1.7.0, denial of service via malformed TOML). The exact pin is also why `bun audit fix` cannot move it: the range check blocks the upgrade. An override installs the patched 1.7.2 for every consumer, which is what keeps the security job's `bun audit --audit-level=high` gate green now that the mutation tier has brought the dependency in. Receipt-Id: 1c83ca7d
The pull-request job ran cold on ubuntu-latest: 59.72% of 1,946 mutants, campaign 4m 29s, job wall-clock 4m 44s. timeout-minutes goes from the provisional 30 to 15, which covers the slower of the two measurements (11m 21s at concurrency: 2 on the laptop that built the tier) with room for the plugin's known flake. The recap carries the CI number beside the local one, and plan.html carries the run's evidence plus the contract findings the loop is not allowed to fix itself. Receipt-Id: 4da587a9
Receipt-Id: b15ac910
🌱 graft blast radius5 areas changed → 7 areas can be affected. 55 dependent symbols, depth 2. flowchart TB
A0(("Command Management<br/>22 symbols"))
A1(("CLI Interface<br/>14 symbols"))
A2(("Floor Management<br/>6 symbols"))
A3(("Guard Logic<br/>5 symbols"))
A4(("AI Verification<br/>4 symbols"))
AX(("2 smaller areas<br/>4 symbols"))
classDef reached fill:#D9EDF3,stroke:#3AA7C9,stroke-width:1.5px,color:#0E313C;
class A0,A1,A2,A3,A4 reached;
classDef tail fill:#EEF2F3,stroke:#9AA4A9,stroke-width:1px,color:#3A4247;
class AX tail;
All 55 dependent symbols, grouped by areaCommand Management — 22 symbols in 6 files
CLI Interface — 14 symbols in 4 files
Floor Management — 6 symbols in 3 files
Guard Logic — 5 symbols in 3 files
AI Verification — 4 symbols in 2 files
Chain Execution — 2 symbols in 1 file
Feature Verification — 2 symbols in 1 file
Test signal per changed area — 4 ✓ · 1 –Reached = a node under a test path has a resolved edge into the changed symbol. It undercounts anything called indirectly — through a CLI, a spawned process or a dynamic import — so read a low ratio as “look here”, never as a coverage gate.
9 test suites also reference this code9 symbols, kept out of the diagram and the table so they cannot crowd out the areas a reviewer has to look at.
Open the interactive graph → — click an area to see the code that changed, and the line that reaches it. |
The installer replaced arch.rules.json with its bootstrap template and dropped .ai-engineering/security/run-*; restore the real layer map and trim the sample-runs check it can no longer answer. Receipt-Id: 12c0a179
Narrow terminals hard-wrapped long log rows at column 0; rows now wrap ANSI-aware with the spine indent carried onto continuation lines. README tightened to the stats table + cli-tour gif; smol-toml pin surfaced in package.json; stryker-sandbox wrap tolerance in the uninstall spec. Receipt-Id: eaf2155e
Receipt-Id: 8f677cf7
brand-generated.spec.ts reads the private ai-engineering-web checkout, which CI has never had, so the check tier failed on every commit of this branch. The tests now skip where the tree is missing and still assert against the real files locally. Receipt-Id: 1d305e41
Receipt-Id: 61beea39
Receipt-Id: 834d9a1c
|



The mutation tier (§17.1), implemented against the approved contract in
.ai-engineering/spec.html(whose sha256 is pinned inai-eng.lock).What it adds
stryker.conf.mjs— StrykerJS 9.6.1 +@hughescr/stryker-bun-runner1.3.8, pinned exact; mutatingsrc/guards,src/chain,src/floor;ignoreStatic,concurrency: 2, the incremental cache,thresholds { high: 90, low: 85, break: 85 }..github/workflows/mutation.yml— nightly onschedule+workflow_dispatch, plus a pull-request job routed by the governance paths. The campaign's exit code is the gate; the clear-text and JSON reports are uploaded as an artifact.check.yml— theguards-adversarialpath filter fetched no history, sogit diff origin/<base>...HEADfailed and the job reported "skipped" for its whole life. Both jobs now fetch history and fail hard when the diff cannot be computed.Why the gate is red on purpose. Measured locally, cold: 60.30% of 1,946 mutants, 11m 21s.
break = 85is a floor and a ratchet — red from the first run until the core climbs. The report names the survivors, so the red says what is missing.This is an evidence PR. It exists to prove two things in CI that cannot be proven locally: that the oracle in
guards-adversarialactually runs (not "oracle skipped"), and that the mutation job runs on a pull request that touches the core, with its real wall-clock number becomingtimeout-minutes. It is not meant to be merged as-is: it also carries in-flight work that was uncommitted in the worktree, and the milestone's own slot files.