Files
fusion/packages
gsxdsm 58f1e41aa0 test(dashboard): keep the renamed-board tracking suite — its source changes landed as #2715 and #2737 (#2714)
**Claim announced on #2706 before starting.**
`github-tracking-comments.ts` + `github-tracking-reconciler.ts` — one
coherent subsystem, 9 guards each.

**18 → 7 by census, 18 → 0 behaviourally.** The gap is explained at the
bottom and it is not hand-waving.

## Both halves failed quietly, in the way that suppresses its own
evidence

| surface | what a renamed board got |
|---|---|
| the comment poster | returned early for **every** move — the tracked
issue silently stopped receiving both its "in progress" and its "done"
comment. The operator sees a linked GitHub issue that never updates. |
| the reconciler (3 scan passes) | matched **zero** tasks, so completed
work's issues were never closed — and the pass reported a clean
`scanned: 0`. |

That second one is the shape worth internalising: **the number that
would have revealed the problem is the number the bug suppresses.** No
error, no warning, a green sweep.

## The comment poster needed a derivation, not a swap

`event.to` was **both** compared against the two literals **and** passed
into `formatTrackingComment` as its `transition` argument (typed
`"in-progress" | "done"`). One value carrying two meanings: a lane id
and a comment kind.

Eight independent swaps would have had to keep agreeing with each other
forever — and a ninth site (the template's own `transition === "done"`)
is *not* a column at all, so a mechanical sweep would have converted it
wrongly. Resolving the lanes once and deriving the kind separates the
two meanings permanently. Log details still print the real column, so
the operator reads their own board's name.

## The reconciler

Per task through **one shared IR cache per scan**, resolved into a `Set`
of terminal ids rather than an async predicate inside `.filter(...)` —
`Array.filter` ignores promises, so an async predicate there silently
keeps **every** row. That is a trap worth naming for other fleet workers
converting list filters.

The archived-vs-complete distinction keeps its own resolver rather than
reusing the terminal pair: it decides GitHub's `state_reason`, and
closing a finished issue as `not_planned` is operator-visible and wrong
— as is the reverse.

## Revert proof

**5 of 8 new cases redden.** 201/201 across the nine `github-tracking`
suites (193 were already there and still pass).

## Why the census says 7 and not 0

The reconciler goes **9 → 0**. The comment poster still reports **7**,
and every one of those is `transition === "in-progress" | "done"` — the
derived comment **kind**, not a column. There is no lane comparison left
in the file.

That is exactly the vocabulary-collision class **#2692** is fixing (it
already lists five misclassified receivers: an SSE event type, a
cache-key mode, an evidence kind, a telemetry event kind, an agent
state). **`transition` is a sixth and I have reported it there.** Until
that lands the census counts them, so I am reporting both numbers rather
than the flattering one.

I deliberately did **not** mark them `DELIBERATE-LITERAL` to move the
count: that marker means "a lifecycle literal reviewed and kept", and
these are not lifecycle literals at all. Using it as a census-silencer
would put a wrong reason in the code to make a number look better.

## Verification

`pnpm test:gate` **487 / 71** · **201/201** github-tracking suites ·
`tsc -p packages/dashboard` clean · `pnpm lint` clean · census
`--strict` exit 0 (it also tightened three entries other workers' merges
left stale — the #2679 auto-tighten working).

No changeset: `@fusion/dashboard` is private and this is internal
behaviour on renamed boards.

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

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