The final `column === "triage"` in production source, and it was a live
defect rather than dead vocabulary.
## The defect
`isPreExecutionHoldColumn` ORed the legacy id with the traits
**unconditionally**:
```ts
return column === "triage" || flags?.intake === true || flags?.hold === true;
```
That is not a fallback. A resolved column merely *named* `triage`
answered true even when its own traits said work was underway — so the
context menu offered **Plan**, which re-plans, on a card that is already
executing.
Now flags-first, with the id as the documented no-metadata answer.
## Why the file's earlier conversion missed it
Every existing case in `TaskContextMenu.test.tsx` passes a column with
**no flags**, or with `hold`/`intake` set. All of them agree under both
forms, so the suite could not distinguish them. Nothing exercised a
column whose **name and traits disagree**, which is the only shape that
separates an OR from a fallback.
Three new cases cover it. Revert check: restoring the OR form fails the
first one — Plan reappears on a mid-flight card.
## The asymmetry is preserved, and now tested
The degraded set stays `{triage}` **alone**, deliberately not the
`{todo, triage}` used by `isPreImplementationColumnRole`. That helper
drives the preserve-progress prompt, where a flagless `todo` *should*
prompt because losing steps is unrecoverable. This drives Plan, where a
flagless `todo` must **not** offer to re-plan a card that may already be
planned. The file documented that difference; nothing asserted it. Now a
test does.
## On reaching zero honestly
The surviving literal is marked `DELIBERATE-LITERAL`. It is the degraded
answer, not an unconverted guard — there is no trait to read when
`flags` is `undefined`, which happens during first paint and for a card
in a column its workflow no longer declares. Deleting it would silently
withdraw Plan from exactly the stranded cards that most need
re-planning.
So **`triage → 0` means "no unconverted guards remain", not "the string
is gone"**, and I would rather say that than move a number by deleting a
fallback.
| branch | triage |
|---|---:|
| `origin/main` | 5 |
| this PR | **4** |
| #2655 (flag resolution, removes 4 in `moves.ts`) | 1 → **0** combined
|
I found it with the census's own AST classifier rather than grep — my
grep of the same tree returned only comment prose and would have had me
report the bar as met while a real defect sat in
`TaskContextMenu.tsx:179`.
## Verification
`pnpm lint` clean. `pnpm test:gate` green (10 / 158 / 487 / 71). `pnpm
check:lifecycle-columns` exits 0 with the baseline re-recorded in this
PR (column 769 → 768, deliberate 12 → 13). `tsc -p tsconfig.app.json`
clean. `TaskContextMenu.test.tsx` 18/18.
Depends on nothing; stacks cleanly with #2655 and #2661.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
9.5 KiB
9.5 KiB