fix(census): the census WROTE to the tree it was checking — same defect as #3287 (#3289)

## What

**Port of #3287 to the sibling tool.** `lifecycle-column-census.mjs
--strict` called `writeBaseline()` during a plain **check**, so running
the gate modified the tree it was checking.

```
clean:  0 files dirty
$ node scripts/lifecycle-column-census.mjs --strict        # no --update-baseline
  rc=0
after:  M scripts/lib/lifecycle-column-census-baseline.json
```

## Why it matters — measured by #3287, reproduced here

#3287 established what this costs: every worker who runs the gate
receives a **byte-identical uncommitted diff they did not author**, and
reasonably commits it. #3283 and #3285 are the same `+0/-1`, five
minutes apart, by two different authors, **neither of whom wrote that
line** — the gate wrote it in both checkouts.

I hit this one the same way, which is the part worth recording: I saw a
modified baseline on my own branch and started reasoning about where
*my* change had touched it. It had not. A check that writes turns every
reader into an author.

The tightening is right in substance, and this tool's `COMMIT IT`
message made the diff *explained* rather than mysterious — better than
fnxc's was. **Neither addresses the mechanism.**

## The shape, matching #3287

Still computed, still reported loudly, written only under an explicit
`--update-baseline` (which has its own path above and is untouched):

```
lifecycle-column-census --strict: baseline CAN BE TIGHTENED — the tree has fewer guards than it allowed
  packages/engine/src/scheduler.ts: allows 1, tree has 0

Not written. Record it deliberately, so the diff has one author:

  node scripts/lifecycle-column-census.mjs --strict --update-baseline
```

**A plain run stays green rather than failing.** Guard counts drop when
someone *else's* merge removes a literal, so failing on a tightening
would redden main on a change the author never made. Report, don't
enforce — same reasoning #3287 gives for stamps aging into the past.

## Measured, all three directions

| scenario | result |
|---|---|
| plain `--strict`, stale baseline | reports + hint; **tree clean**
(was: 1 file dirty) |
| `--strict --update-baseline` | writes, rc=0 |
| a new guard added | **rc=1** — regression detection intact |

```
lint clean
```

## Note

Claimed on #3287 before starting, since it is that author's fix and they
may have had the port in flight. The two differences from the fnxc case
are noted there: this one fires under `--strict` rather than a bare run
(but `--strict` is what `package.json` and CI invoke, so it is the
common path), and its message was already loud.
This commit is contained in:
gsxdsm
2026-07-31 18:33:30 -07:00
committed by GitHub
parent ad15113872
commit 65af9fd694

View File

@@ -1061,12 +1061,30 @@ if (stale.length > 0) {
console.error("\nRe-record it:\n\n node scripts/lifecycle-column-census.mjs --strict --update-baseline\n");
process.exit(1);
}
writeBaseline();
console.log("\nlifecycle-column-census --strict: baseline TIGHTENED — the tree has fewer guards than it allowed\n");
/*
FNXC:LifecycleColumnCensus 2026-08-01-01:35 (#3287's defect, same shape in this tool):
REPORT THE TIGHTENING, DO NOT WRITE IT. This branch used to call `writeBaseline()` during a plain
`--strict` CHECK, so running the gate modified the tree it was checking.
#3287 measured what that costs on the sibling fnxc gate: every worker who ran it received a
byte-identical uncommitted diff they had not authored and reasonably committed it — #3283 and
#3285 are the same `+0/-1`, five minutes apart, by two authors, neither of whom wrote that line.
The gate wrote it in both checkouts. I hit it here the same way, on my own branch, and started
looking for where my change had touched the baseline. It had not.
The tightening itself is right, and the "COMMIT IT" message made the diff explained rather than
mysterious. Neither fixes the mechanism: a check that writes turns every reader into an author.
Still computed, still reported loudly, written only under an explicit `--update-baseline` — which
has its own path above, so a deliberate re-record is unaffected. A plain run stays GREEN rather
than failing, because guard counts drop on merges the author never touched; failing would redden
main on someone else's cleanup.
*/
console.log("\nlifecycle-column-census --strict: baseline CAN BE TIGHTENED — the tree has fewer guards than it allowed\n");
for (const line of lines) console.log(line);
console.log(
"\nThe baseline file has been rewritten downward. COMMIT IT so the allowance cannot be regrown into;\n"
+ "in CI this write is discarded with the runner, which is why the gate is green and not silent.\n",
"\nNot written. Record it deliberately, so the diff has one author:\n\n"
+ " node scripts/lifecycle-column-census.mjs --strict --update-baseline\n",
);
process.exit(0);
}