Skip to content

migrate: rename --quiesced to --block-writes and require the table - #260

Merged
Kiran01bm merged 4 commits into
mainfrom
kiran01bm/quiesced-table-ack
Oct 28, 2026
Merged

Kiran01bm merged 4 commits into
mainfrom
kiran01bm/quiesced-table-ack

Conversation

@Kiran01bm

@Kiran01bm Kiran01bm commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

The flag for running a copy-and-swap offline is now --block-writes SCHEMA.TABLE. It replaces the bare --quiesced and has to name the table whose writes it blocks, the same way --restart and --force do.

Why

A copy-and-swap that blocks writes is not an online operation. It fences the source, and every write to the table fails with 55006 until the swap, which on a large table can take hours. Until now that was one bare boolean flag, --quiesced. A --quiesced left in a script or CI template takes whatever table the next statement names offline, with no record that anyone chose to. An operator should have to type the table they are taking offline.

The name says what the run does to the table, not what the operator declares about it. "Quiesced" read as a promise that the table is idle, when the run actually blocks the table's writes for its whole length.

What

  • --quiesced is replaced by --block-writes SCHEMA.TABLE. A bare --block-writes is a parse error, and an old --quiesced is an unknown flag, so it fails instead of running.
  • CopySwapOptions.Quiesced bool becomes CopySwapOptions.BlockWrites string, a typed acknowledgement. This breaks library callers; no release shipped the boolean. An empty value still means the live path.
  • Run checks the acknowledgement against the resolved target before anything executes, next to the restart check. A mismatch returns an error with no verdict, no shadow, and no fence.
    • In a desired-state plan, every planned statement makes this check, so a mismatch stops the plan at its first statement and no native statement ahead of the retype commits.
    • An index rename refuses the acknowledgement, as it refuses --restart.
  • Before the fence goes on, an acknowledged run writes an unconditional warn-level audit naming the table and the 55006 refusal, matching the force and restart audits.
  • A stopped run that blocked writes resumes only with the same acknowledgement. Without it, the run is refused with resume-row-decoding and the fence stays as it was. schemabot-integration.md now says this.
  • Docs: limitations.md, cli-output-examples.md, schemabot-integration.md. They call this "offline mode"; internal engine names such as the write fence and "quiesced target" are unchanged.
  • Tests:
    • A mismatched acknowledgement leaves the table writable and unchanged, both for a single statement and for a desired-state plan with a native statement ahead of the retype. Each fails without the check.
    • An index rename refuses --block-writes.
    • The CLI rejects a bare --block-writes.
    • The existing offline-mode tests now pass the table.

Before / after

The same command, run against public.orders from a script that still carries the flag from an earlier change on public.customers. Before, the run fences orders, and the application's writes to it fail for the whole copy. After, the acknowledgement names customers, so the run stops before touching orders.

Before                                        After
------                                        -----
migrate --quiesced                            migrate --block-writes public.customers
  'ALTER TABLE public.orders ...'               'ALTER TABLE public.orders ...'
        |                                             |
        v                                             v
resolve target public.orders                  resolve target public.orders
        |                                     acknowledgement names public.customers
        v                                       -> error, nothing executed;
fence public.orders                              orders keeps taking writes
  -> every app write fails 55006                      |
     until the swap; no audit record                  v
        |                                     operator retypes it for orders:
        v                                     migrate --block-writes public.orders ...
copy, verify, swap                              -> warn audit "every write to the
                                                   table will be refused until the
                                                   swap", then fence, copy, swap

🤖 Generated with Amp (Claude Opus 4.6)

A quiesced run refuses every write to the table until the swap, so the
declaration becomes a typed SCHEMA.TABLE acknowledgement like --restart,
checked before anything executes and audited before the fence goes on.
@Kiran01bm
Kiran01bm marked this pull request as ready for review October 27, 2026 19:31
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-27T19:31:30.447563Z
We couldn’t complete this review. Comment @codex review to try again.
2a9d5de Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@JashLal

JashLal commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

🤖 Adversarial correctness review by Codex on behalf of JashLal, reviewed at head 2a9d5dee.

Verdict: No confirmed correctness defect in the inspected diff; verification is incomplete. The change makes the offline-write acknowledgement table-specific and rejects a mismatch before the shown live-facts read.

Findings

No must-fix finding established. The new mismatch integration test checks a zero verdict, no shadow, a successful subsequent insert, and an unchanged column type. Existing quiesced fixtures now supply their target names.

Action items

  1. (Optional) Add a desired-state mismatch test containing both a native addition and a copy-and-swap retype, asserting that neither executes. This would explicitly protect acknowledgement handling across plan admission and per-statement execution.
  2. (Optional) Cover the new index-rename rejection and capture the warn audit with diagnostics disabled, asserting the table and SQLSTATE.

Verified

Read the full diff, PR body, issue comments, review summaries, and check rollup; no test functions or test cases were deleted. The CLI assertions change from boolean assertions to the corresponding string value and empty default. All 16 reported checks succeeded, including PostgreSQL 14–18 and Supabase. I could not retrieve exact-head surrounding source, repository guidance, or inline review threads, and did not build or run tests locally; the check results are CI evidence only.

Generated by Codex (GPT-6).

@JashLal

JashLal commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

🤖 Codex OSS adoption / SchemaBot integration review at 2a9d5dee.

OSS adoption: The table-specific acknowledgement and explicit 55006 warning make the offline-write cost clearer. Consider documenting the boolean-to-string upgrade with a small before/after snippet.

SchemaBot integration: The library change is intentionally breaking: callers must replace the boolean with a deliberately supplied SCHEMA.TABLE acknowledgement, while an empty string selects the live path. Retain an explicit operator decision in any adapter that supplies this field, and include the acknowledgement when retrying or resuming a quiesced run. The mixed desired-state mismatch test recommended above would protect this integration boundary.

This is an integration recommendation, not evidence of a defect. Review was limited to the current diff and PR metadata; no local tests were run.

Generated by Codex (GPT-6).

@JashLal JashLal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Approving on Jash's behalf under the authorized review workflow at 2a9d5de. No confirmed correctness defect found in the inspected diff. Optional desired-state acknowledgement, rename rejection, and audit coverage suggestions are recorded in the review. Exact-head surrounding source and inline threads were unavailable, and no local build or tests ran. Approval does not certify those unverified paths. Generated by Codex.

The flag takes the table offline for writes, and "quiesced" read as a
promise about the table rather than a warning about what the run does.
Keeps both acknowledgement checks in migrate.run: this branch's
--block-writes and main's --allow-destructive (#253). The #253 test that
set the old Quiesced field now sets BlockWrites to the table it names.
A desired-state plan with a mismatched acknowledgement runs neither its
native statement nor its retype, and an index rename refuses it. The
resume row in the SchemaBot guide now says a run that blocked writes
resumes only with the same acknowledgement.
@Kiran01bm Kiran01bm changed the title migrate: require --quiesced to name the table it takes offline migrate: rename --quiesced to --block-writes and require the table Oct 28, 2026
@Kiran01bm

Copy link
Copy Markdown
Collaborator Author

🤖 Adversarial review response — created by Kiran's code review agent (Amp, Claude Opus 4.6) — pull/260, follow-up commit

Both coverage gaps are closed with tests that fail without the checks, and the resume contract is now documented. Two suggestions are rejected below. Since the review, --quiesced / Quiesced has been renamed to --block-writes / BlockWrites; the table below uses the new names.

# Finding Status Explanation
C1-F1 A desired-state plan with a native statement plus a copy-and-swap retype and a mismatched acknowledgement should execute neither fixed There was no defect: run() checks the acknowledgement for every planned statement, so the plan stops at the first one, the native ADD COLUMN. The new TestRunDesiredCopyAndSwap subtest locks this in: the result is failed with no verdicts, the column count and type are unchanged, and the table still takes writes. It fails if the check is removed from run().
C1-F2 (rename) Cover the index-rename rejection fixed TestRenameIndexRejectsTheBlockWritesAcknowledgement passes the index's own table and asserts ErrIndexRenameAcknowledgement with the index unrenamed. It fails without the rejection.
C1-F2 (audit) Capture the warn audit with diagnostics disabled and assert the table and SQLSTATE rejected The repo rule is that log output is never a test surface, and no existing audit (force, restart) is asserted through logs. A machine-readable signal would be a verdict field, which #262 adds as writes_blocked.
C2-F1 Document the boolean-to-string upgrade with a before/after snippet rejected No release (v0.3.1–v0.3.3) shipped the boolean, so no released caller has anything to upgrade. The PR body's before/after shows the change.
C2-F2 Adapters must keep the acknowledgement an explicit operator decision and re-supply it on retry and resume fixed Resuming already fails closed: a run of the other kind is refused with resume-row-decoding and leaves the hold as it is (TestRunnerRefusesTheOtherKindOfRunsRow). The Resume row in schemabot-integration.md now says to resume with the same --block-writes SCHEMA.TABLE.
Review Approval no action —

Source: block/pg-sprite#260, review comments 6452850115 and 6452852502 and review 5673897460 at head 2a9d5dee; fixes in the follow-up commit.

@Kiran01bm
Kiran01bm merged commit 41e22a0 into main Oct 28, 2026
16 checks passed
@Kiran01bm
Kiran01bm deleted the kiran01bm/quiesced-table-ack branch October 28, 2026 03:54
Kiran01bm added a commit that referenced this pull request Oct 28, 2026
Main renamed --quiesced to --block-writes SCHEMA.TABLE (#260), so the
data-fault test now sets BlockWrites to its table and is renamed to match.
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.

2 participants