Second of the 39 audited `triage` sites from #2515's safety audit.
Unlike the first, this one is **real breakage**, not a proof of safety.
## The defect
The usage-limit pauser decides which tasks are on a rate-limited
provider by asking, per lane, whether the card sits in that lane's
column. The **planning** lane asked for the literal `triage`.
Now that Todo is merged into Planning, a card being planned on the
default workflow rests in `todo`. The branch resolves to an empty
provider list, so the card is not recognised as using the planning
provider — and is **neither parked when that provider hits its limit nor
resumed when it recovers**. It runs into the limit and fails.
Silent by construction: the detector reports nothing, it simply matches
no tasks.
## The test caught my own first attempt at testing it
The initial version asserted on the task that **triggered** the
usage-limit hit — and **passed against unfixed code**, because the
trigger is always parked directly without consulting `taskUsesProvider`.
Only a **bystander** card reaches the lane/column branch.
All three assertions now use a separate trigger, and the comment says
why, because the obvious test shape is the one that proves nothing.
## Why a paired literal rather than trait resolution
`taskUsesProvider` is a synchronous predicate over a task and settings,
with no IR in scope and no call site that could supply one without a
signature change reaching several callers.
Both ids name a pre-implementation column in every built-in — `triage`
for the split shape, `todo` for the merged one and for Coding (Ideas) —
so the pair covers the planning lane in all of them. Flagged for U12's
ratchet allowlist with that reason attached.
**Over-inclusion is the safe direction and is deliberate.** On a split
workflow a `todo` card is capacity-parked rather than actively planning,
so it may now be parked during an outage it was not using. Parking one
extra idle card is recoverable; failing to park a card whose provider is
rate-limited is not.
Regression direction asserted: widening the **column** match must not
widen the **provider** match — a planning card on a different provider
is still not parked.
## Audit progress
39 exclusive `triage` sites (from
`docs/solutions/architecture-patterns/u11-triage-literal-safety-audit.md`,
merged in #2515):
| status | sites |
|---|---|
| proven safe as-is | `spec-staleness.ts` — the guard is carried by
**status**, not column; the mechanical conversion was tried and is
*wrong* |
| confirmed safe by inspection | `mission-feature-sync.ts` (already
OR-pairs), `TaskContextMenu.tsx` (already trait-paired) |
| **fixed here** | `usage-limit-detector.ts` |
| remaining | 35, with the owners named in the audit |
Gate 309/309, lint clean.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>