## Why
`check-sql-column-literals` runs inside `pnpm test:gate` — the
**blocking** lane. It hard-fails when a count *drops*, so a single
converting PR that doesn't re-record takes down the gate for **every
worker in the program** until someone fixes the baseline by hand.
That is not hypothetical. It is happening on `main` right now
(`team-analytics.ts` 6 → 3, fixed by #2880), and it is the **second**
instance of the shape — the lifecycle census hit it from a merge wave
that dropped eleven files at once.
## The census already resolved this exact trade-off
From `docs/testing.md`, on why the census stopped hard-failing on a
drop:
> "the drop is almost never the failing author's to fix ... A
permanently-red gate is a bigger hole than a stale allowance, because it
gets ignored and then nothing is guarded at all."
That reasoning applies here **with more force**, because the census is
*not* in the blocking lane and this check *is*. Same failure mode,
higher cost, opposite policy — this aligns them.
## What changes
A drop now rewrites the baseline downward, reports what it lowered, and
exits 0:
```
[check-sql-column-literals] baseline TIGHTENED — fewer literals than it allowed
packages/core/src/team-analytics.ts: allowed 6, now 3
The baseline has been rewritten downward. COMMIT IT so the allowance cannot be regrown into;
in CI this write is discarded with the runner, which is why the gate is green and not silent.
```
**The rise check is untouched.** "No new SQL column literals" is the
ratchet's actual purpose and still fails hard.
The stale-allowance concern the old comment raised is real and is
preserved: the rewritten file must be committed, and in CI the write is
discarded with the runner — so the gate goes green rather than silently
passing a stale allowance, exactly as the census does.
## Verified in both directions
| scenario | result |
|---|---|
| drop (`team-analytics.ts` 6 → 3, the live case) | **tightens, exit 0**
|
| rise (a literal added to a zero-allowance file) | **fails, exit 1** —
`task-age-staleness.ts: 1 SQL column literal(s), baseline allows 0` |
The rise probe needed a zero-allowance file: adding one literal to
`team-analytics.ts` keeps it at 4 against an allowance of 6, which is
correctly *not* a rise. Worth noting because it is an easy way to
conclude the guard is dead when it is working.
## Relationship to #2880#2880 fixes the **instance** — it re-records the current drift so the
gate goes green now. This fixes the **class**, so the next conversion
doesn't take the gate down again. They are independent and either can
land first; if #2880 lands first, this becomes a no-op on a matching
baseline.
## Verification
- `pnpm test:gate` — exit 0 with this change applied
- `pnpm lint` — clean
No changeset: gate tooling, not published behaviour.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>