fix(tests): main red — a census source guard that a COMMENT could invert (#2825)

## Red on main

```
lifecycle-column-census > the baseline can always be re-recorded
  > writes the baseline BEFORE the rise check can exit
AssertionError: expected 19345 to be greater than 26374
```

Read literally, that says the CLI now runs its rise check *before* the
`--update-baseline` write — which would break the one command whose
entire job is re-recording, and would be a genuine bug worth stopping
for.

**It does not.** The order in code is correct and unchanged:

| | line |
|---|---|
| `if (updateBaseline) { … writeBaseline() … process.exit(0)` |
`scripts/lifecycle-column-census.mjs:487` |
| `"column-guard count ROSE"` + `process.exit(1)` | `:510` |

## What actually moved was a comment

Line **359** explains this exact failure mode and quotes the marker
verbatim:

> …`"column-guard count ROSE"`, which is the opposite of what happened
and sends the reader looking for…

So `cli.indexOf("column-guard count ROSE")` found the **prose**, 7000
characters before the branch it was meant to locate.

A guard that a comment can invert is not measuring control flow. And the
honest-looking fix — reword the comment — silently re-arms the same trap
for whoever explains this next.

`cliSource()` now strips comments before indexing. The same defence is
already used by `archived-column-gate-parity.test.ts`, for the same
reason: notes documenting *why* a literal is dangerous have to mention
the literal.

## Kept, not deleted

The end-to-end block below these does cover the contract — it drives the
real CLI and asserts exit code, baseline content and printed output, and
its own comment names the ordering bug. It would have been defensible to
delete the two source-text cases as redundant.

I kept them because two guards at different levels is the point: **e2e
proves the behaviour, these locate the branch that provides it.** They
only needed to stop being defeated by prose.

## Evidence

The real ordering bug — make a rise exit before the update branch writes
— fires **all three**:

| guard | failure |
|---|---|
| source order | `expected 9454 to be greater than 9505` |
| slice / uniqueness | `expected 10433 to be -1` |
| end-to-end | `expected 1 to be +0` (exit code) |

**My first mutation attempt was invalid** and I nearly reported it as
evidence: it moved the block by line range, mangled the file, and both
markers disappeared — the resulting `-1`s look like a firing guard but
prove nothing. A mutation that corrupts its target is not evidence that
a guard works.

Engine **10991 passed / 0 failed** · gate **732 green** · lint clean.
Test-only; the CLI is restored clean.

## Note on duplicated effort

#2811 and my #2814 both re-recorded the census baseline for #2783's
rise, concurrently. No harm done — but this file is now a fleet-wide
contention point, and the per-file baseline shape exists precisely to
avoid that. Worth one owner for census/ratchet fixes rather than whoever
notices first.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
gsxdsm
2026-07-30 13:14:36 -07:00
committed by GitHub
parent ed83fd6ec3
commit 9a5155c71a

View File

@@ -368,9 +368,32 @@ repeated marker is the magic-number problem wearing a name.
describe("the baseline can always be re-recorded", () => {
const cliPath = new URL("../../../../scripts/lifecycle-column-census.mjs", import.meta.url).pathname;
/*
FNXC:LifecycleColumnCensus 2026-07-31-06:30:
STRIP COMMENTS — the assertions below index on marker strings, and the CLI's own prose names them.
These two cases went red on main claiming the ORDER was inverted: `updateAt` 26374, `riseAt` 19345.
The order in CODE is unchanged and correct (`if (updateBaseline) {` at line 487, the rise message at
510). What moved was a COMMENT: line 359 explains the failure mode and quotes
"column-guard count ROSE" verbatim, so `indexOf` found the prose 7000 characters before the branch
it was meant to locate.
A guard that a comment can invert is not measuring control flow. Worse, the honest-looking fix is to
reword the comment, which silently re-arms the same trap for whoever explains this next.
The same defence is already used by `archived-column-gate-parity.test.ts` for the same reason: the
notes documenting WHY a literal is dangerous have to mention the literal.
Deliberately NOT deleting these in favour of the end-to-end block below, even though that block does
cover this contract (it drives the real CLI and asserts exit code, baseline content and output — and
its own comment names the ordering bug). Two guards at different levels is the point: the e2e one
proves the behaviour, these locate the branch that provides it. They only needed to stop being
defeated by prose.
*/
function cliSource(): string {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require("node:fs").readFileSync(cliPath, "utf8") as string;
const raw = require("node:fs").readFileSync(cliPath, "utf8") as string;
return raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
}
function sliceBetween(cli: string, from: string, to: string): string {