Files
fusion/packages/engine
gsxdsm e711fbab15 The ratchet's baseline could not be re-recorded once a file rose — the one state that blocks a correct conversion (#2668)
Unowned (no open PR touches the census CLI — only its baseline JSON) and
**live**, since #2654 gates CI on `--strict`.

## The problem

`--update-baseline` sat **behind** the rise exit, so the only supported
way to re-record was unavailable in exactly the situation that needs it.

That matters because **a conversion legitimately adds a literal.** The
correct shape for a caller that may have no traits is `flags ? flags.x :
columnId === "legacy"`, and each one raises a file's count by one.
Measured on current main: `columnRoles.ts` went **0 → 1** from precisely
that shape (added by #2647, documented at the site, correct code).

So a worker doing the right thing meets a red gate whose only escape is
hand-editing the JSON. That is how a ratchet becomes something people
route around rather than run — and then it guards nothing. This is the
same failure mode as a guard that cannot fire, arrived at from the other
side.

## The change

`--update-baseline` is an explicit operator action, so it re-records
**unconditionally** and prints what it accepted under `ACCEPTED RISES`.
Swallowing a rise silently is the real danger; refusing to let anyone
re-record is the same danger one step later, wearing a red check nobody
trusts. **The rise check is unchanged** and still exits 1 without the
flag.

**One writer now.** The old second `writeFileSync` behind the rise exit
is deleted rather than left unreachable — two writers for one artifact
is how they drift. The `!deliberateTracked && updateBaseline` special
case went with it, since the unconditional block covers the legacy-shape
migration too.

## Exercised end to end

On a real rise injected into `live-agent-count.ts`:

```
rise + plain --strict              exit 1   (the ratchet still bites)
rise + --strict --update-baseline  exit 0   "ACCEPTED RISES  live-agent-count.ts: 6 -> 7"
```

Four cases assert the CLI's own source, because exit codes are the
contract and the pure summarizer cannot express them: the write precedes
the rise check, the branches exit 0 and 1 respectively, accepted rises
are **named**, and there is exactly **one** writer.

## A note on the revert proof, because it caught me twice

My first attempt to move the block back was a **no-op**: the marker I
sliced on (`if (regressions.length > 0) {`) also appears *inside* the
update block, so the "revert" reassembled the file unchanged and the
suite stayed green. **A revert proof that does not go red can mean the
guard is vacuous *or* that the revert did not land** — and the second is
easy to miss when you are expecting the first. The real revert fails **2
of 27**, and the assertions now verify marker *uniqueness* before
slicing on it.

## Verification

- 27/27 census suites; `--strict` exits 0; `pnpm test:gate` **71/71**;
`pnpm lint` clean
- census on this tree: 748 column guards, **4 triage** (all in
`moves.ts`'s flag-OFF block, deletion-scheduled with #2655)

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 01:46:36 -07:00
..
2026-07-26 18:11:47 -07:00