Files
fusion/packages
gsxdsm 1469d57477 U12 drift: ListView.tsx — one tested column-role helper (5 -> 0) (#2620)
**File claimed: `packages/dashboard/app/components/ListView.tsx`.**
Per-file lifecycle-column guard count: **5 → 0** (3 live, 2 in comment
prose that described the deleted code).

## What was actually wrong

All three live sites were *already* flags-first. The defect was that
each carried its own inline copy of the same fallback:

```ts
targetFlags ? Boolean(targetFlags.intake || targetFlags.hold) : column === "todo" || column === "triage"
```

Three copies, none reachable from a test, each reading like a lifecycle
rule rather than the degraded mode it is. A fourth copy was the natural
next step.

## Why the fallback survives instead of being deleted

`columnFlagsById` is legitimately empty in two states: the pre-load
window before the workflows fetch resolves, and a card stranded in a
column its workflow no longer declares. A bare `flags.intake === true`
returns false in both, and **both failures are silent** — the Planning
badge stops appearing, and a backwards move stops asking whether to
preserve step progress, so the operator loses completed steps with no
prompt and no error. Deleting the fallback is not the cleanup it looks
like.

So it is kept, named (`isPreImplementationColumnRole`,
`isIntakeColumnRole` in `app/utils/columnRoles.ts`), defined once, and
documented with that reason at the definition. The legacy ids now live
in a named `LEGACY_PRE_IMPLEMENTATION_COLUMN_IDS` set — a last-resort
guess, not a comparison masquerading as a rule.

## Tests, and the case that never had one

`app/__tests__/columnRoles.test.ts` (6). The degraded branch is now
covered for the first time — it was unreachable while inline inside two
`handleMove` closures and a `useCallback`.

It also pins the **inversion** a fourth copy would eventually get wrong:
a resolved column whose traits say it is *not* pre-implementation must
not be overridden by an id that happens to be `todo` or `triage`. That
is the direction that trains operators to dismiss the prompt.

Mutation-checked, measured:

| mutation | result |
|---|---|
| ignore the flags argument (`return LEGACY_….has(columnId)`) | **4
failed / 2 passed** |
| ignore the id fallback (`return Boolean(flags?.intake \|\|
flags?.hold)`) | **4 failed / 2 passed** |

## Behaviour preservation

`ListView.test.tsx` + `workflow-resolved-columns.test.tsx`: **260
passed**, unchanged. The extraction is a pure move — the two helper
bodies are the inline expressions verbatim, with the id set hoisted.
`pnpm lint` clean. `tsc -p tsconfig.app.json` clean (the app config, not
the root one that silently skips `app/`).

No changeset: behaviour-preserving refactor.

## Backlog measured on `origin/main` at time of writing

48 total. `self-healing.ts` (10) is the capacity worker's;
`register-task-workflow-routes.ts` (7) is my #2614. Remaining unowned in
this area after this PR: `TaskCard.tsx` 4, `TaskDetailModal.tsx` 3,
`TaskContextMenu.tsx` 2, `Column.tsx` 2, `taskActivity.ts` 2. Several of
those hold the *same* fallback pattern and can now call this helper
rather than grow another copy.

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