The `archived` family is the largest unclaimed cluster (52 sites) and
its blocker is that **nobody has scoped it**. This scopes it. It
converts nothing.
## The two options both read as enormous because 52 sites are counted as
one lump
They are not one lump. The sites answer **two different questions**:
| question | renameable? |
|---|---|
| **LANE** — "is this row resting in the board's archive lane?" | yes —
must resolve |
| **STATE** — "did Fusion archive this row?" (the marker `archiveTask`
writes) | **no** |
`async-maintenance.ts` already draws that line and marks its own site
DELIBERATE-LITERAL:
> `'archived'` is the STATE marker here, not a lane. This sweep collects
rows Fusion itself archived or soft-deleted; a card merely sitting in a
workflow's archived-TRAIT lane is live work and must not be collected.
Widening to the resolved archived set would pull real cards into a
cleanup pass.
**Converting that site would be a bug, not progress.**
`async-archive-lineage.ts`'s soft-delete path is the same shape —
`column = 'archived', deleted_at IS NOT NULL` is the storage state it
has just written.
So the first question is a **triage**, not a conversion: which of the 52
are lane questions? Nobody has answered it, which is exactly why the
cost reads as unbounded.
## Measured: the SQL half, which the existing note calls the hard part
8 Drizzle sites across 7 files.
**Four already have `store` in scope** — they could take a resolved set
today with no signature change:
- `branch-group-ops.ts` — `clearNearDuplicateReferencesToImpl(store,
...)`
- `branch-and-pr-entities.ts` —
`findRecentTasksByContentFingerprintImpl(store, ...)` (2 sites)
- `task-mutation-ops.ts` — `cleanupArchivedTasksImpl(store)`
**Four need one parameter each**, the same optional-lane-set shape used
throughout this program:
- `async-lifecycle.ts` — `liveLineageChildFilter(parentId, projectId?)`
- `async-search.ts` — `liveSearchPredicate(includeArchived, projectId?)`
- `async-self-healing.ts` — `listSoftDeletedColumnDriftCandidates(db,
...)`
- `store.ts` — the revert-lookup conditions (already holds
`this.asyncLayer`)
That is not *"threading a resolver into the persistence layer"*. It is
four call sites that already have what they need, plus four
one-parameter widenings — **before** any triage removes the STATE sites
from the count entirely.
## What I did not do, and why
The triage itself: a per-site judgement about what each guard *means*.
That belongs to whoever owns this gate, not to a passing fleet lane —
and getting it wrong in the STATE direction pulls live cards into a
cleanup sweep, which is the one failure mode here that destroys work
rather than hiding an affordance.
What was cheap and missing was the **shape** of the problem.
## Measured
- Comment-only; parity test **2/2**.
- `tsc --noEmit -p packages/core` clean; census `--strict` clean.
- `check-fnxc-future-dates` is red from `main`'s own #3128 stamps —
**#3139** fixes that; this branch inherits and does not add to it.
## Census
No movement.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>