Claiming the **github-tracking pair**. This converts the comments half;
the reconciler half is the flagged class, with the evidence below.
## Census before/after
| | before | after |
|---|---:|---:|
| `github-tracking-comments.ts` | **9** | **3** |
Baseline re-recorded; `--strict` exits 0.
## Converted: 6
The `event.to === "in-progress"` / `=== "done"` sites in
`handleTaskMoved`, to the **wip** and **complete** roles. One
resolution, placed **immediately after the tracking-enabled gate** — so
a move on an **untracked** task pays nothing, which is most moves in
most projects.
## Deliberately not converted: 2 — the ordering is the reason
```ts
if (event.to !== "in-progress" && event.to !== "done") return; // line 232
```
This runs **before** the tracked-task gate. Converting it moves the
resolution ahead of that gate and makes **every task move in the
project** resolve a workflow just to decide the task has no GitHub
issue. That's a real cost on the hottest event in the system, to convert
a guard whose only job is a cheap filter. Recorded at the site.
## The remaining 1
**Line 165** — `transition === "done"` inside `formatTrackingComment`, a
**pure formatter** with no store and no task. Same shape as
`project-engine.ts:2555`. Threading a resolution into a formatter to
pick a string is the wrong trade.
## `github-tracking-reconciler.ts` (9) — not claimed here, and here is
why
All nine are:
```ts
.filter((task) => task.column === "done" || task.column === "archived")
```
Synchronous filters over task **lists**, where per-task resolution is N
awaits inside a sync predicate.
**This is the fourth file with that exact shape** — after `store.ts`
(#2709), and the dependency pairs in `TaskDetailModal` (#2696) and
`register-task-workflow-routes` (#2700). By my count **roughly 25 sites
across four files now wait on one decision**:
1. **Prefetch lifecycle columns alongside the task list** and pass a
resolved map into these predicates — keeps them synchronous, one
resolution per *distinct workflow* rather than per task. This is the one
I'd argue for.
2. Make the predicates async and accept per-task resolution.
It's a design change, and four workers guessing separately is exactly
how two halves of one rule drift apart. One decision covers all of them.
## Verification
`pnpm test:gate` **GREEN** (158 + 10 + 487 + 71) ·
`github-tracking-comments` + `github-issue-comment` **81/81** · `pnpm
lint` clean · dashboard `tsc` clean · `--strict` exits 0.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>