Files
fusion/packages/engine
gsxdsm 719cf281fd test(engine): pin the startup stale-planning sweep's planner-lane read (#3221)
## What

Pins the **startup stale-planning sweep's** planner-lane read in
`triage.ts`. Test-only — no product change.

A card can hold `status: "planning"` while triage specifies it in place.
A crash or restart before planning completes leaves that status set, and
a startup sweep clears it. If the sweep misses the card, it occupies a
planning admission slot **permanently** and new triage work is never
admitted.

The lane read was converted from `resolvePlannerLanes(store, "")` —
called with an **empty task id**, so it could never resolve a task and
always answered with the default board — to a project-level
`resolveProjectColumnsForRoles(store, ["intake", "hold"])`.

**No test could observe that conversion.** All 25 existing triage test
files stayed green (375/375) with the resolver neutered — under *both*
blinds tried.

## Measured

| | default (control) | legacy ids | renamed | differential |
|---|---|---|---|---|
| converted | pass | pass | pass | pass |
| blinded to empty set | pass | pass | **FAIL** | **FAIL** |
| blinded to legacy pair | pass | pass | **FAIL** | **FAIL** |

```
converted:            Tests 4 passed (4)
blinded to empty set: Tests 2 failed | 2 passed (4)
blinded to legacy:    Tests 2 failed | 2 passed (4)
existing 25 files:    green under BOTH blinds  (only this new file fails)
triage suite: 25 files/375 tests -> 26 files/379 tests, all green
lint clean; fnxc-future-dates: none added; census unchanged
```

## A prediction I got wrong, and what it changes

The site is **seed-then-union**:

```ts
const sweepColumns = [...new Set(["triage", "todo", ...projectPlannerColumns])];
```

I expected blinding the resolver to its legacy pair `["triage","todo"]`
to be a **no-op by construction** — the seed already contains both. It
is not. That reasoning holds only for a *default* board; on a renamed
board the resolver is the sole contributor of `drafting`, so the legacy
blind drops it and the renamed cases fail.

The corrected rule, which is narrower than the one I was carrying: **a
seed-then-union site hides a defect only while every lane you assert on
is already in the seed.** Assert on a lane that is not, and the union
stops protecting it. The empty-set blind remains the stricter of the two
because it also models a resolver returning nothing at all. Both are
recorded in the test file so the next person does not re-derive it.

## A tooling failure worth naming

My first triage measurement reported **375/375 green under blinding** —
and was a lie. The blinding script had no mapping for
`["intake","hold"]` and exited `2` **silently**; the `&&`
short-circuited the check while a `;` let vitest run against
**unmodified source**. A no-op blind produces a green run that is
indistinguishable from real coverage.

The script now prints what it substituted and where, fails loudly on an
unmapped role or a missing variable, and I self-tested both directions
(bogus var → rc 2 with a message; real var → rc 0 with the substitution
echoed) before trusting any number above. This is the same standard I
have been applying to other people's guards — *a guard that reports
success without checking anything is worse than no guard* — and my own
instrument failed it.

## Also pinned

The **legacy half** of the union. `triage`/`todo` stay in the sweep even
on a board whose workflow declares neither, because pre-U11 and Coding
(Ideas) rows can rest there. Dropping them in favour of the resolved
lanes alone would strand exactly those rows, so there is now a case
asserting it.

## Flagged, not guessed

- The FNXC stamp at `triage.ts:987` reads `2026-07-31-23:59`, hours
ahead of the `date -u` clock. It is one of the 181 grandfathered stamps
so the gate is green; I left it rather than widen this PR.
2026-07-31 12:01:00 -07:00
..
2026-07-26 18:11:47 -07:00