de677b231a623a7dfbd4a5eeefa8d44fef47d2b7
2 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
63e1f81244 |
fix(gate): a dropped SQL-literal count tightens the baseline instead of failing the gate (#2888)
## 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> |
||
|
|
ef50244234 |
feat(gate): freeze the SQL column-literal surface — 30 sites, none may be added (#2841)
Instruments a surface no existing check can see. Follows #2839, and **corrects the count I reported there** (12 → 14). ## Why it was invisible The lifecycle census parses TypeScript **comparisons**; a legacy id inside a SQL string is string data. The inert-seam gate reasons about parameters and call sites. Neither has ever looked here. **What it cost:** `cleanupStaleMergeQueueRowsImpl` filtered on `t.column != 'in-review'`, so on a renamed board every queued card looked stale, its `merge_queue` row was deleted, and the card became **unleaseable**. The operator found it reviewing #2819 — in SQL I had already read past during that same work. The quieter half is analytics: five sites count `"column" = 'done'`, so throughput, cycle time, and team dashboards report **zero completed work** on a renamed board. Nothing errors, which is why nobody files it. ## What this does, and does not do It does **not** fix the sites. `resolveProjectColumnsForRoles` is the mechanism and its migration has an owner (#2839). This freezes the population so the surface cannot grow underneath that migration: a new file or a higher count fails, **and a lower count fails too** — so the baseline ratchets down as sites migrate rather than leaving slots to silently regrow into. That is the same rot as an allow-list entry for a deleted function, which this repo already hit once. AST-based, deliberately: a line grep for the same pattern reports **37** hits, **25 of them prose** quoting `column === "done"` in explanatory notes. A guard that is 68% false positives trains its readers to skip it — a lesson this program has already paid for. ## Two corrections found by mutation-testing my own gate **1. Clause fragments were missed.** Requiring a SQL keyword *in the same literal* skipped `team-analytics.ts`, which builds `["assignedAgentId IS NOT NULL", `"column" = 'done'`, ...]` and joins them into a `WHERE` later. That fragment is as vocabulary-bound as any full query but contains no keyword. Fixing it took the population **12 → 14**, so the number I put on #2839 was low. **2. My first mutation test proved a direction it had not.** I replaced the first textual occurrence in a file — which was inside a **comment** — and read the unchanged count as the scanner being broken. The scanner was right; my test was wrong. All three directions are now driven against real SQL: | mutation | result | |---|---| | add a full query with a legacy comparison | `3 SQL column literal(s), baseline allows 2` | | add a bare clause **fragment** (no keyword) | caught — same failure | | migrate one away (count drops) | `1 site(s) now, baseline still allows 2 — re-record it` | | restore | exit 0 | I am flagging that second one because it is the exact failure mode this program keeps finding: a green result read as evidence when the experiment was invalid. ## Verification `pnpm test:gate` green with the new check in it · lint 0 · single AST pass. Wired into `test:gate` and both `pretest` hooks. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Added automated checks to detect increases in legacy SQL column literals. * Added baseline tracking to ensure known SQL literal counts do not regress. * **Tests** * Expanded pre-test and gated verification steps with SQL literal and mock completeness checks. * Updated test validation workflows to enforce the new safeguards. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |