Skip to content

db-apply: fix two gates that reported the opposite of the truth - #1900

Open
njrini99-code wants to merge 1 commit into
mainfrom
agent/mobile-messages-audit
Open

db-apply: fix two gates that reported the opposite of the truth#1900
njrini99-code wants to merge 1 commit into
mainfrom
agent/mobile-messages-audit

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

Two defects in the production apply path, both found while applying 20260907160000, both currently live on main. Neither is theoretical — the first one blocked a real apply today, the second would have reported failure after a successful production commit.

1. The order guard reported ZERO pending while production was missing ten

It scraped supabase migration list text with awk, matching a row shape CLI 2.115.0 no longer prints. It then failed the run with "version is not pending — already applied" — the exact opposite of the truth (run 34177...502).

Replaced with .github/scripts/order-guard.mjs: reads the ledger as JSON, diffs it against the migrations directory. Nothing parses human-facing output.

Because a single-file apply skips other pending migrations rather than sweeping them in, the guard's job also changed — allow_sweep becomes allow_out_of_order, and it blocks on older pending migrations, which are the real ordering hazard.

2. The VERIFY block would have reported FAIL after a successful commit

apply.mjs took one line as one query, but a readable VERIFY spans continuation lines. 20260907160000's three queries became thirteen fragments, ten of them syntax errors — and fragment 1 is valid SQL, returns thousands of rows, and passes while verifying nothing.

Production would have committed correctly and the run gone red with a ROLLBACK recipe sitting in the header — inverting the recorded-vs-applied distinction this path exists to provide.

Fixed in the extractor, not the migrations. Reflowing each query onto one line was tried first and was wrong twice over: it added 6 sqlfluff LT05 violations (the ratchet caught it — the baseline was not raised), and it would have edited a migration already applied to production. Both migration files are byte-identical to what ran.

Verification

  • Order-guard suite runs against real production ledger state
  • Repo-wide suite asserts every extracted VERIFY is one complete statement — proven to fail on the old form (13 of 13 fragments)
  • An unterminated trailing fragment is still emitted, so a malformed block fails loudly rather than silently passing

Gates: typecheck=0 lint=0 test=0 test:rls=0 docs=0 sql-ratchet=0.
check:migration-headers fails on 5 untouched 20260906* HOLD files — pre-existing, not from this branch.

Also in this PR

20260907160000 is applied to production (2026-09-08, via the dashboard SQL editor, since db-apply could not run it for reason 1). Verified against the live catalog: function present with search_path pinned and no anon/PUBLIC grant, both policies carrying their new branches, ledger row recorded, all three VERIFY queries returning a row, and Ben Potter's 13-person team chat at 13/13 with 84 messages intact.

Consequent doc work: db:types regenerated; the schema-drift-absent exemption for golf_user_on_conversation_team removed from all four files that carried it (the object is live now — an exemption would hide it); feature docs and ledgers corrected from "written but NOT applied".

HELD.md also records pre-existing drift worth your attention: 20260907120000's columns and CHECK constraint are live in production with no ledger row. Reconciliation is a one-row decision and is deliberately left to you.

🤖 Generated with Claude Code

https://claude.ai/code/session_01P6v9ed3vngusQ3N6Na1etZ

Both found while applying 20260907160000, both live on main.

1. THE ORDER GUARD REPORTED ZERO PENDING WHILE PRODUCTION WAS MISSING TEN.
   It scraped `supabase migration list` text with awk, matching a row shape
   CLI 2.115.0 no longer prints. It then failed the run with "version is not
   pending — already applied", the exact opposite of the truth (run
   34178071502). Replaced with .github/scripts/order-guard.mjs, which reads
   the ledger as JSON and diffs it against the migrations directory. Nothing
   parses human-facing output.

2. THE VERIFY BLOCK WOULD HAVE REPORTED FAIL AFTER A SUCCESSFUL COMMIT.
   apply.mjs took one line as one query, but a readable VERIFY spans
   continuation lines. 20260907160000's three queries became THIRTEEN
   fragments, ten of them syntax errors — and fragment 1 is valid, returns
   thousands of rows, and PASSES while verifying nothing. Production would
   have committed correctly and the run gone red with a ROLLBACK recipe in
   the header, inverting the recorded-vs-applied distinction this path exists
   to provide.

   Fixed in the EXTRACTOR, not the migrations: it now joins fragments until a
   `;`. Reflowing each query onto one line was tried first and was wrong twice
   over — it added 6 sqlfluff LT05 violations (the ratchet caught it; the
   baseline was NOT raised), and it would have edited a migration already
   applied to production. Both files are byte-identical to what ran. An
   unterminated trailing fragment is still emitted, so a malformed block fails
   loudly rather than silently passing.

Caught by db-migration-reviewer, not by me. Tests pin both: the order-guard
suite uses real production ledger state, and a repo-wide suite asserts every
extracted VERIFY is one complete statement.

eslint.config.mjs gains a .github/scripts/** node-globals block, same shape and
same reason as the scripts/** and .claude/hooks/** blocks above it.

Also: 20260907160000 is now APPLIED to production (2026-09-08, via the
dashboard SQL editor, since db-apply could not run it for reason 1). db:types
regenerated for the new function; the schema-drift-absent exemption for
golf_user_on_conversation_team removed from all four files that carried it,
since the object is live and an exemption would hide it; feature docs and
ledgers corrected from "written but NOT applied"; HELD.md records the apply
route and, separately, that 20260907120000's columns are live in production
with no ledger row — pre-existing drift, reconciliation left to the owner.

Gates: typecheck=0 lint=0 test=0 test:rls=0 docs=0 sql-ratchet=0.
check:migration-headers fails on 5 untouched 20260906* HOLD files, pre-existing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01P6v9ed3vngusQ3N6Na1etZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant