## What
The census prints **"a new guard cannot land silently"** next to a zero.
That claim was true only for the guard form it happened to parse. This
closes the two it could not see. No product change.
The comparison walk visits `BinaryExpression` only, so neither of these
was visible:
```ts
["done", "archived"].includes(task.column)
switch (task.column) { case "todo": ... }
```
Both are lifecycle-column guards by any reading.
## How I found it
By applying this program's own rule — **break the guard on purpose** —
to the guard itself. I staged a probe file with five guard forms and
measured which moved the count:
| form | counted before |
|---|---|
| `t.column === "todo"` | ✅ |
| `t.column !== "in-review"` | ✅ |
| `["done","archived"].includes(t.column)` | ❌ |
| `switch (t.column) { case "triage": }` | ❌ |
| SQL string `"column" = 'done'` | ❌ (separate gate owns this) |
A worker converting a `===` chain into an array membership would have
scored the conversion **and kept the guard**.
*(The first probe run was itself invalid — the file was untracked and
the census enumerates git-tracked files, so the scanned count stayed at
1961 and nothing was measured. Staging it moved the scan to 1962.
Checking the scanned count is what caught that.)*
## The near-miss worth reading
My first implementation counted **unless** the receiver looked like a
role or status — mirroring the `===` walk. On the real tree it reported
**7 column guards**, and I nearly published that as a hidden backlog.
Six were false: `switch (eventName)`, `switch (state)`, `switch (event)`
— event and state enums routinely carry `case "done"` / `case
"archived"`. Landing it would have injected six phantom guards into a
backlog the ratchet treats as zero, and `--strict` would then have
**failed every other worker's PR**.
So the new walks require a **positive** column signal instead. That
regression is pinned by a test asserting all three receivers stay
uncounted.
## Measured
```
real repo, before and after: COLUMN guards 0, STATUS 185 (no false positives)
staged probe: 2 detected before -> 4 after
new tests: 6/6 pass; 3 FAIL with the extension reverted
existing lifecycle-census test: 9/9 still green
lint clean; census --strict passes; fnxc-future-dates: none added
```
## Known limit, stated rather than left to be discovered
The positive signal is the receiver **name**, so `switch (column.id)` —
a `Column` object rather than a task's column — is **not** counted. That
is a real guard shape and it is deliberately out of scope: widening to
reach it is exactly what produced the six false positives, so it needs
its own discrimination rather than a looser regex. Flagged here so the
next person extends it deliberately instead of assuming coverage.
## Why this and not another conversion PR
The conversion queue has been genuinely empty for several cycles —
census 0, 116 resolver sites unchanged across four commits, every site
blinded and pinned. The remaining risk in this program was never another
literal; it was that **the instrument defining "done" could not see two
of the shapes it claims to protect against**. A zero from a detector
with blind spots is the exact failure this phase has spent its time
documenting.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Added lifecycle-column guard detection for array membership checks and
`switch` cases.
* Recognizes supported column receiver names and classifies findings
consistently with existing guards.
* Ignores status, event, and state receivers, and avoids duplicate trait
fallback findings.
* **Tests**
* Added coverage for membership checks, `indexOf`, `switch` guards, and
deliberate-literal suppression.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->