Files
fusion/packages/engine
gsxdsm f91b8a4178 TAKING mission-feature-sync.ts: roadmap reconciliation resolves lifecycle roles (unowned drift site) (#2602)
> **Taking `packages/engine/src/mission-feature-sync.ts`** from the
shared backlog — announced in the title per the collision protocol.
Based on `main`, no dependencies.

It is in **no unit's file list**: absent from the plan's per-file census
*and* from the drift review's ownership split (self-healing, dashboard,
triage/replan-target, core, executor). It is a planning-lane reader.

## What was broken

`reconcileMissionFeatureState` maps a task's lifecycle **position** onto
its mission feature's roadmap status, and read five column literals:
`done`, `archived`, `in-progress`, `in-review`, `triage`/`todo`.

On a renamed workflow **every branch answers "no"**, so the function
collapses to a permanent `noop`.

**What an operator sees:** a mission roadmap frozen at whatever status
it last held, while the tasks underneath it run to completion. Nothing
errors, nothing retries. Worse than a wrong status, because a stale
roadmap reads as a stable one.

## Guard counts (per the reporting requirement)

| Metric | Before | After |
|---|---:|---:|
| `column === / !== "triage"` in this file | **1** | **1** |
| role comparisons converted | — | **5** |

**The metric does not move here, and I am not claiming it does.** The
five role comparisons are converted; the one literal that remains is the
deliberate scoped migration acceptance this change *adds*. That is the
third time on this program the real fix has been invisible to the
convergence count — the count finds the site, it does not define done.
Worth knowing while the shared backlog is being tracked by that number:
repo-wide it currently reads **29** triage comparisons (including 4 in
`plugins/`, which are also unowned).

## Fallback direction matters

**Unresolvable workflow falls back to the legacy ids, not to `noop`.** A
mission whose workflow cannot be read should keep tracking on the
default vocabulary rather than go silent — going silent *is* the failure
being fixed, so the fallback must not reproduce it.

**The planner-lane branch also accepts an orphaned legacy id.** A
pre-existing test asserted a card in `triage` returns its feature to
`triaged`; that stopped holding for the default lineage after #2515 —
the migration-window population again. Accepting `triage`/`todo`
additively keeps those rows tracked, **scoped to ids the workflow does
not declare**, for the reason greptile gave on #2593: a custom workflow
may legitimately name its **review** lane `triage`, and mapping a card
there to `triaged` would walk the roadmap backwards while the task is
awaiting merge.

## A test of mine that proved nothing until fixed

The scoping case first used a `triaged` feature. The planner-lane branch
only fires for an **in-progress** feature, so the fixture fell through
to the review branch and **passed under both implementations**. It
discriminates only once the feature status lets the wrong branch win —
verified by reverting the scoping and watching exactly that case fail.

## Revert proofs

| Reverted | Result |
|---|---|
| all five literals restored | **5 of 15 fail** — every renamed case;
every default case passes |
| legacy acceptance unscoped | **1 of 15 fails** — the
custom-`triage`-as-review case |

## Verification

| Check | Result |
|---|---|
| new suite | 15/15 |
| pre-existing mission-feature-sync + mission-autopilot +
scheduler-trait-dispatch | 94/94, **no expectation edits** |
| `tsc --noEmit` (engine) | clean |
| `pnpm lint` | clean |
| `pnpm test:gate` | green (482 + 10 + 71) |
| `pnpm check:changesets` | clean |

## Next from the shared backlog

Taking
`plugins/fusion-plugin-even-realities-glasses/src/agent-actions.ts` (3)
and `plugins/fusion-plugin-dependency-graph/src/GraphTaskNode.tsx` (1)
next — 4 sites in `plugins/`, which no unit owns and which the #2587
ratchet now scans. Shout if anyone is already there.

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

---------

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