Skip to content

Commit 5b09356

Browse files
claude[bot]claude
andauthored
fix(pm): governed-merges self-test refuses as NOT MEASURED when its generator toolchain is absent (#15283)
* fix(pm): refuse the governed-merges self-test as NOT MEASURED when its generator toolchain is absent In a freshly created worktree, before `pnpm install`, `pnpm check:pm-governed-merges` exited 1 — a finding's code — and reported self-test battery "#11705 end to end, against the REAL generator" registered 5 case(s), below its pinned floor of 7 — cases that used to run no longer do. Nothing had stopped running. The battery's live case execs the real generator (`pnpm --filter @objectstack/spec exec tsx …`), which in an uninstalled checkout exits 254 with `Command "tsx" not found`; that arrives at `sinkGeneratorVerdict` wearing the same `outputs: null` shape as every other generator failure, the battery takes its one-assertion branch, and the floor renders a NOT-MEASURED condition as a measured red — prescribing a hunt through the generator for a deleted block that was never deleted. Three sibling gates met the same worktree in the same minute and answered correctly with exit 3 PREREQUISITE NOT MET. This gate now does too: - `generatorToolchainPrerequisite()` asks whether the row's recompute can run at all, by looking for the same binary `pnpm exec` would. It is consulted at the top of `selfTest()`, before a single case runs, so the shared frame's load-bearing clause is literally true when it prints. It is strictly a narrowing of one exit code into another — no branch in it can turn a red into a green, and the audit paths never consult it. - The refusal reuses `scripts/import-prerequisite.mjs` — the exit code, the frame and the pipe advisory are the repo's, not a sixth spelling. - The reason string is deliberately NOT classified: an uninstalled checkout and a generator reporting real drift both arrive as a non-zero `--check` exit, so reading that text would fold a finding into a refusal. - `batteryFloorFailures()` is lifted to module scope and takes its ledger as an argument, so the direction that matters most — a genuinely deleted case still reds, and still names WHICH battery — is asserted for the first time. Its behaviour, order and every message it prints are unchanged. Both directions are pinned (15 new cases, 245 -> 260 assertions): an uninstalled checkout refuses with exit 3 end to end, on a copy of this file's own module graph, naming the prerequisite and the remedy and no longer printing the shrunken-battery words; a ledger one case short of any floor still reds and still names that battery. No floor is lowered, no case is deleted or skipped, and the post-merge audit's verdicts are untouched. Fixes #15272 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox * fix(pm): name the command that re-runs these cases in the refusal The shared advisory names the importer by PATH, which is right for the gates it was written for but incomplete here: this file has modes, and `node scripts/pm/check-governed-merges.mjs` without `--self-test` runs the network SWEEP rather than the cases that just refused. The helper has no seam for an invocation, so the correct entry point is stated in this gate's own detail lines, where the claim about what went unmeasured already lives. Pinned end to end: 245 -> 261 assertions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox * fix(pm): stop the end-to-end fixture from spawning an unbounded chain of itself Found by ablating the probe: the fixture child reaches the prerequisite battery only when the probe did NOT refuse, and there its own copied tree is a perfect seed for the next copy. Measured, an ablated probe produced one self-test per second, each waiting on the next — 67 processes before it was cut off by hand. A hang is the worst reading a gate can return: neither green nor red, and nothing in CI distinguishes it from slow. The child is now marked in its argv, a marked run refuses to spawn a grandchild, and the cases it would have measured FAIL with that reason instead — the same number of cases, in both worlds, and a loud red where there was an unbounded wait. 261 -> 262 assertions. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019RfFHiRCSs3JXLK4cwcfox --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 0cbd5f2 commit 5b09356

1 file changed

Lines changed: 312 additions & 41 deletions

File tree

0 commit comments

Comments
 (0)