## Main is red, and the red is pointing at a real defect
`unwired-lane-parameter-guard` fails on `origin/main` after #2951. This
is not a stale allow-list — the parameter genuinely never reaches the
function.
#2951 added `reviewColumns?: ReadonlySet<string>` to three signal
modules and wired two of them completely. **`getInReviewStallReason` was
wired at none of its four call sites.** Measured by brace-matching each
call's option literal:
```
getInReviewStallReason L227=NO L390=NO L599=NO L729=NO
getInReviewStalledSignal all 4 wired
getStalePausedReviewSignal both wired
```
## The user-visible consequence
`reads.ts` computes two adjacent signals for the same card. On a board
declaring a **separate merge lane beside its human-review lane**,
`inReviewStall` read the *first* review column only, while
`inReviewStalled` — three lines below — read the *set*.
**The same card is "in review" for one signal and not the other.** Two
signals disagreeing is worse than both being legacy, and it is invisible
on every builtin board because there the review set has exactly one
element.
At three of the four sites the resolve sat *below* the call, which is
why the parameter could not be passed. Those are hoisted.
## I have to correct my own earlier report
On #2951 I said *"3 of 4 call sites wired, `reads.ts:227` is the gap."*
**That was wrong.** I had measured with a 12-line proximity grep, which
bled into the adjacent `getInReviewStalledSignal` call and counted its
`reviewColumns:` as the first call's. Brace-matching the literal shows 0
of 4. The defect was four times larger than I reported, and the cause
was exactly the anti-pattern I have spent this session filing against
other people's guards — a proximity window standing in for structure.
## Naming the context types
The guard keys an interface member to its **owner symbol** and only
counts a mention from a file that also names that owner, so passing the
property inline reads as unwired even when every site supplies it.
`satisfies InReviewStalledContext` / `satisfies
StalePausedReviewContext` on the option literals is real type-checking,
not a decorative import — lint rejected the decorative version,
correctly.
## New test, because the existing guard cannot see this
Measured: **deleting the `reviewColumns:` line from a fixed call site
leaves `unwired-lane-parameter-guard` at 9/9 green**, because the file
still names the type. So the wiring I just fixed had no coverage at all.
The new ratchet brace-matches each call site's option literal:
| mutation | result |
|---|---|
| remove lanes from one call site | **1 failed** — *"1 of 4
getInReviewStallReason call sites omit reviewColumns"* |
It also asserts it **found** call sites before checking them — a parse
that matched nothing would be vacuous, which is the failure mode this
guard family keeps producing. (It caught me mid-change too: an earlier
scripted edit left the file syntactically invalid and the source-text
test still passed 3/3. It is a wiring ratchet, not a substitute for
`tsc`.)
## Verification
Core **4861 passed / 0 failed** · guard **9/9** with `KNOWN_UNWIRED`
**unchanged** · `pnpm test:gate` **exit 0** · lint clean · core `tsc`
**0 errors**.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>