Files
fusion/packages/core
gsxdsm ea008b4064 docs(core): an empty role result has TWO meanings — correcting a rule I applied across three PRs (#2765)
## A correction to a rule I introduced, prompted by #2760 and then
measured

`synthesizeDefaultColumns` (`workflow-ir.ts`) upgrades a v1 graph by
emitting `{ id, name: id, traits: [] }` for the five default ids —
**placement only, by design**, with the real trait set living in
`BUILTIN_CODING_WORKFLOW_IR`.

So a v1-upgraded board arrives at every role resolver looking exactly
like a v2 board that declares nothing. Measured on such an IR:

| resolver | result |
|---|---|
| `resolveLifecycleColumns` | `{}` — every role undefined |
| `resolveReviewColumns` | `[]` |
| `columnsWithFlag(…, "countsTowardWip")` | `[]` |
| `resolveTerminalColumns` | `["done","archived"]` — its own legacy
fallback saves it |

## The correction I owe

I introduced **"resolved and empty means this board declares no such
lane"** deliberately across #2731, #2733 and #2734, to fix the
*opposite* bug — a legacy fallback masking a genuinely absent lane. I
argued for it repeatedly and applied it in several files.

It is right for hand-written v2. It is **wrong for the upgrade path**,
where it withdraws every role at once. And the two cases are
indistinguishable at the call site: both arrive as an empty array.

The contrast the test pins is the sharpest evidence —
`resolveTerminalColumns` survives the identical IR purely because it
never adopted that reading. **The data is the same; the reading is what
differs.**

## Affected, named rather than left to be rediscovered

- **on `main` today**: `default-workflow-hooks.ts` → `inRole` (from
#2734)
- **in my open PRs**: the store bypass guard (#2709) and the
tracking-state terminal classifier (#2754)

Consumers that kept a `length > 0 ? resolved : legacy` guard are
unaffected — including the notifier (#2722), which I checked.

## Not fixed here

The root repair is for the upgrade to carry real traits instead of
placeholders. That changes behaviour for **every persisted v1
workflow**, so it wants its own change with its own measurement — not
something slipped into a doc commit. Flagged at the source so the next
consumer chooses knowingly.

## Verification

34 trait tests green · core `tsc` clean · lint clean (0 errors) · gate
green (487 + 158 + 10 + 71). No production behaviour change; no census
movement.
2026-07-30 08:25:08 -07:00
..
2026-07-26 18:11:47 -07:00