Test-only. Fifth E2E family. Closes three of the four `live-agent-count`
classifications.
## Why this one is a scheduler bug, not a display bug
`live-agent-count.ts` classifies a card's column, and
`persistedTopLevelAgentSlotsFromStore` turns that into **the number
admission control compares against the cap**. So a mis-classified column
fails in whichever direction hurts:
| mis-classification | consequence |
|---|---|
| wip column not recognised | under-count → **over-admits past the
operator's cap** |
| complete column not recognised | a finished card counts forever →
**board silently stalls** |
Both are silent, and both land only on a renamed board.
Everything in the path is real: PostgreSQL store, real persisted
workflows, cards walked through the real transition policy, and the real
counting function resolving each card's own IR. Nothing about counting
is reimplemented here.
## Two of my own cases were vacuous — mutation-testing caught it
This is the more useful half of the PR.
**1. "does not count a card in the COMPLETE column" passed with the
terminal classification hardcoded to `done`.** `isRunningAgentTask`
rejects that card at the *wip* check anyway, so the test was really
asserting "shipped isn't a wip column". `terminalKind` short-circuits
**first**, so it only changes the answer for a card whose status would
otherwise make it count. Now covered by a complete card carrying a
live-looking `planning` status — the state a crashed run leaves behind,
which on a renamed board consumes a slot forever.
**2. The review/merge lane had no case at all.** A review status is
deliberately *not* globally live (a stale `fixing` in wip must not
consume capacity), so it is gated on `columnIsReviewOrMerge`. If the
renamed review lane isn't recognised, a genuinely-active reviewer stops
counting and admission control lets another agent in over the cap. Now
covered by a review card with an active merge-pipeline status.
Both new cases assert their fixture took effect first, so they can't
degrade back into the weaker version silently.
## Mutation-verified independently
| classification | mutation | result |
|---|---|---|
| `countsTowardWip` | → `"in-progress"` | 3 renamed cases fail |
| `complete` | → `id === "done"` | exactly the new terminal case fails |
| `mergeBlocker` | → `id === "in-review"` | exactly the new review case
fails |
## What this does NOT cover, stated plainly
The fourth classification, `columnIsIntakeOrHold`, is read only by the
**waiting** predicate, which the admission count never calls. It stays
in the ledger as unproven rather than being claimed by proximity — the
mistake I made last slice with `resolveMergeOrchestrationColumn`.
## Verification
- five live-E2E suites green together: **52/52**
- engine `tsc --noEmit` clean
- `pnpm test:gate` green (309 + 10 + 71)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Added end-to-end coverage for live agent-count admission across
workflow lanes and lifecycle states.
* Verified slot handling for active, completed, held, and mid-review
tasks, including stale statuses.
* Confirmed mixed-lane counts and renamed board vocabularies produce
consistent results.
* **Documentation**
* Expanded coverage notes for live agent-count classifications and
waiting-state behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>