Files
fusion/packages
gsxdsm 1d0f21b428 U12 R12: lifecycle-column literal ratchet — and the raw count's floor is not zero (#2630)
The anti-regression ratchet U12 R12 calls for. Counts lifecycle-column
**literal comparisons** in production source and fails when the count
rises.

## Two jobs

**1. Ratchet.** A converted guard cannot silently come back as a
literal. Ceilings only go down.

**Mutation-verified both ways:** adding one `t.column === "triage"`
fails with *"rose to 49 (ceiling 48)"*; lowering the ceiling to 47 fails
with *"rose to 48 (ceiling 47)"*. The number is exact, not approximately
right.

**2. Honest denominator — the finding.**

`triage` is overloaded in this codebase: a column id, an **agent role**,
a **session purpose**, a **prompt-template family**, and a **CLI glyph
key**. A raw grep counts them together, which makes "reach zero"
unreachable by construction — converting `role === "triage"` in
`agent-prompts.ts` would break the planning agent's prompt-template
resolution, and the failure would look nothing like a column bug.

| | count |
|---|---:|
| raw `triage` matches | 72 |
| **not a column at all** | **10** |
| genuine column comparisons | **48** |

The 10: `agent-prompts.ts` ×3 (`role`), `usage-limit-detector.ts` ×2
(`agentType`), `skill-resolver.ts` (`sessionPurpose`),
`tool-availability.ts` (`surface`), `cli/commands/task.ts` (a glyph
key), plus two in comments.

Ceilings recorded for all four ids — **`in-progress` (133) and
`in-review` (200) were untracked entirely.**

## A measurement error of mine that writing this caught

A grep over `packages/<pkg>/src` **misses `packages/dashboard/app`**,
where the board components live. That undercounted `triage` as 43 in an
earlier audit of mine when it was 62. The source roots are now listed
explicitly in code so the number cannot drift with someone's glob.

## The classifier is under test, not trusted

A ratchet that matched nothing would pass forever while measuring
nothing — the failure mode this program keeps finding. Three self-tests
prevent it:

- it asserts **positively** that `agent-prompts` / `skill-resolver` /
`tool-availability` are excluded, so a classifier change that swallowed
them would fail rather than quietly shrink the number;
- it asserts the classifier still **matches** real column comparisons;
- it pins `live-agent-count.ts`'s two sites as **permanent** no-flags
fallbacks, with the reason, so a future edit that deletes them has to
argue with it rather than silently drop stranded cards from the footer's
queued total.

The classifier keys on the **left-hand side naming a column** —
deliberately syntactic, so a reader can audit it against the source
without running anything, and conservative: an unrecognised shape counts
**as** a column comparison, erring toward demanding conversion rather
than excusing it.

7 tests green; lint clean.

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

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 23:03:14 -07:00
..
2026-07-26 18:11:47 -07:00