> **Based on `main`** — independent of my U7 stack and of #2561; merges in any order. Third unowned drift-review site. `isRunnableAutoClaimCandidate` is the single source of truth for *"may an agent claim this task?"* (FN-6873), and it carried **three** lifecycle literals that fail in **opposite directions**. ## The two failures **`column === "todo"` gated candidacy** on the hold role. Keyed on the literal, a renamed workflow's candidate set was **permanently empty** — agents were never offered its work, and nothing anywhere reported it. Silence, not an error. **`dependency?.column === "done" || "archived"` gated dependency satisfaction**, and this is the more dangerous half: a dependency that finished in a renamed **complete** column was never recognised as done, so the dependent stayed **blocked forever**. One makes work invisible; the other makes it permanently ineligible. Both are silent. ## Roles resolve per task, not per pass The non-obvious part: **a dependency may sit on a different workflow from the claimant.** A single per-pass answer is wrong for one of them on any mixed board — so the map is keyed by task id, and the dependency check reads the *dependency's* roles, not the claimant's. Asserted directly: a dependency completed in `done` (default vocabulary) satisfying a claimant waiting in `drafting` (renamed). ## Shape Both callers already have the store and are async, so they resolve for real rather than taking the injected-lane fallback the *synchronous* predicates needed (#2551). The predicate itself stays synchronous — a resolved-roles map is passed in — because it runs inside two `filter`/`flatMap` bodies. Tasks absent from the map keep the legacy ids, so a partially-resolvable board degrades to today's behavior instead of silently emptying the candidate set. **Type narrowing preserved.** The two callers take `Pick<TaskStore, "listTasks">`, which is what makes them testable without a real store. Rather than widening to the whole `TaskStore`, they now take `Pick<TaskStore, "listTasks"> & WorkflowIrResolverStore` — the minimal additional shape resolution needs. ## Revert proofs, isolated per literal | Restored | Result | |---|---| | hold literal only | **3 of 6 fail** | | dependency-completion literals only | **1 of 6 fails** | The three default-vocabulary cases pass under both. Splitting the proof matters here: it confirms the two halves are **independently** load-bearing rather than one masking the other — a single combined revert would have shown 3 failures and told me nothing about the dependency half. ## Convergence Measured on `main`, comment-stripped scan of `column === / !== "todo" | "triage"` in `packages/*/src` excluding tests: - this file alone: **103 → 102** - with #2561: **103 → 100** The `done` / `archived` literals fixed here sit outside that pattern and are not counted — same caveat as #2561's gridlock `active` filter. Two PRs now where the real fix is larger than the metric shows. ## Verification | Check | Result | |---|---| | new suite | 6/6 | | pre-existing auto-claim suite | 17/17, **no expectation edits** | | `tsc --noEmit` (engine) | clean | | `pnpm lint` | clean | | `pnpm test:gate` | green (414 + 10 + 71) | | `pnpm check:changesets` | clean | ## Remaining unowned in my area `mission-feature-sync.ts` (1, a planning-lane check) and `notification-service.ts` (1, *"has progressed past"* — a different semantic needing its own thinking, not a mechanical swap). Taking those next unless claimed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Changeset Format Guide
Each changeset file in this directory describes one user-facing change for release notes.
Required body format
---
"@runfusion/fusion": minor
---
summary: Add a Command Center productivity control for LOC backfills.
category: feature
dev: Uses the new `fn_backfill_loc` tool; settings key `commandCenter.locBackfill`.
Fields
| Field | Required | Description |
|---|---|---|
summary |
Yes | One line, user-facing, max 120 chars. Describe what changed for the operator. |
category |
Yes | One of: feature, fix, breaking, security, performance, internal. |
dev |
No | Developer or migration detail. Preserved in per-package CHANGELOGs but excluded from distilled release notes. |
Audience
The summary is the only content that appears in end-user release notes by default. Write for Fusion operators — describe behavior, fixes, and what changed. Avoid internal class names, file paths, and implementation detail.
Bump types
patch— bug fixes, internal changesminor— new features, CLI additions, toolsmajor— breaking changes
Validation
Run pnpm check:changesets to validate. The linter runs in the PR-check gate and test:gate. Legacy freeform changesets pass with a warning during the transition period.