Files
fusion/packages
gsxdsm 1f149d21de fix(engine): TAKING spec-staleness.ts + mission-feature-sync.ts — planner lanes (2 triage guards → 0) (#2616)
**Claiming `packages/engine/src/spec-staleness.ts` and
`packages/engine/src/mission-feature-sync.ts`.** Deliberately *not*
`self-healing.ts` (contended) or `task-creation.ts` (#2589 in flight).

## Guard counts

| scope | before | after |
|---|---|---|
| `spec-staleness.ts` | 1 | **0** |
| `mission-feature-sync.ts` | 1 | **0** |
| repo-wide `column === / !== "triage"` in `packages/*/src` (excl.
tests) | 26 | **24** |

**21** once #2612 (comments-ops, 3 guards) also lands.

## What was silently broken

**mission-feature-sync** — *"has this task returned to a planner lane?"*
decided whether a mission feature drops from `in-progress` back to
`triaged`. Keyed on the legacy pair, a card sent back for re-planning on
a renamed board left its feature stuck at `in-progress` **forever**: the
mission board showed work in flight that nobody was doing, and nothing
said so.

**spec-staleness** — the preserved-progress skip refuses to fire for an
**intake** card, since a card being specified has no progress to
protect. Keyed on `triage`, a renamed-board intake card looked like
started work and its stale spec was skipped instead of re-planned.

## The union is a deliberate call, and the existing suite forced it

My first cut *replaced* the legacy pair with the resolved lanes. That
broke a real case: **post-U11 the default lineage has no `triage`**, so
a legacy row still resting there stopped counting as a planner lane.

`usage-limit-detector` already made this call for the same situation and
wrote down why — **over-inclusion is the safe direction**. Marking a
feature `triaged` for a card in a legacy planner column is recoverable;
a mission board permanently showing phantom work is the bug. So the
legacy pair stands and resolved lanes are *added* to it.

Worth noting the existing test is what caught this, not review — which
is the argument for converting against a real suite rather than in
isolation.

## A parameter, and why that needs the ratchet

`spec-staleness`'s predicate is **pure** (a task, no store), so the role
arrives as a parameter and both callers resolve it. That optionality is
exactly the caller-omission hazard this program has already shipped
twice, so the function is also registered in core's
`role-parameter-caller-audit` (#2588).

**This PR's tests prove the parameter is honoured; the audit proves it
is passed. Neither alone is enough** — that split is the whole lesson of
#2586.

## Mutation-verified

| mutation | result |
|---|---|
| mission-feature-sync → legacy pair only | the two renamed cases fail |
| spec-staleness → restore the `triage` literal | its renamed case fails
|

Negatives included in both: demoting a **WIP** card's feature would
report running work as un-started, and never-skipping would discard
every card with real progress.

## Verification

- new suites 4/4 and 3/3; `mission-feature-sync` + `spec-staleness`
27/27
- engine `tsc --noEmit` clean; `pnpm test:gate` green (482 + 132 + 10)
- `executor-prompt` reports 3 failures **both with and without** this
change — pre-existing, baselined by stashing rather than assumed

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

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-30 00:54:01 -07:00
..
2026-07-26 18:11:47 -07:00