Skip to content

Withdraw the signed head and mirror copy when a poll blocks (RD-2B) - #49

Merged
dbccpage merged 4 commits into
mainfrom
claude/rd2-signed-head-bootstrap-and-withdraw
Nov 11, 2026
Merged

dbccpage merged 4 commits into
mainfrom
claude/rd2-signed-head-bootstrap-and-withdraw

Conversation

@dbccpage

Copy link
Copy Markdown
Owner

Requested by Jeremy · project thread

Stacked on #48 (RD-1). Review that first; this diff is only the last commit.

What

  • New Publisher.block(reason): durably blocks the namespace, then deletes every Redis copy (SignedMirror.withdraw_all: head first, then the whole-generation key). A Redis failure here cannot undo the block.
  • PostgresWorker routes its safety blocks through it, so TRUNCATE/DDL stops bounded hits immediately instead of up to head_ttl_ms (15 s) later.

RD-2A did not reproduce

On PostgreSQL 16.15 the walsender releases a new slot as soon as CREATE_REPLICATION_SLOT ... (SNAPSHOT 'export') returns, so pg_replication_slots.active is false while the exported snapshot is read and SignedMirror.put() signs fine during bootstrap(). Probe: active=False, active_pid=NULL right after slot creation with the replication connection still open. I added test_production_bounded_bootstrap_signs_its_own_head (bootstrap straight through SignedMirror) to keep that pinned, and made no code change for 2A.

Evidence

  • test_production_bounded_block_withdraws_head_at_once[truncate|schema_change]: fails on main (still a hit after the block), passes here.
  • Unit tests for Publisher.block with and without a Redis failure.

Generated by Claude Code

Publisher.block() durably blocks the namespace and then deletes every
Redis copy (SignedMirror: head first, then the whole-generation key), so a
TRUNCATE or DDL stops bounded hits at once instead of up to head_ttl_ms
later. PostgresWorker routes its safety blocks through it.

RD-2A (bootstrap self-refusal) did not reproduce on PostgreSQL 16.15: the
walsender releases a new slot as soon as CREATE_REPLICATION_SLOT returns,
so pg_replication_slots.active is false during the exported snapshot.
Added a direct SignedMirror bootstrap test to keep that pinned.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0194kAmY4QqQGabdoB3xGFsr

Copy link
Copy Markdown
Owner Author

Live Database Containers failed on one test only: test_production_read_contention_during_publication[bounded] ("native source did not catch up within 30 seconds"). Every other native test passed, including all the new ones in this stack.

This failure is not from this PR. It is the known drain-rate limit on main: the worker publishes one generation per WAL transaction, about 13–25 tx/s, while the test writes 20 tx/s. main has failed the same way (run 42984776547). The same job passed on #48 and #50. #47 fixes it (coalescing committed WAL transactions into one generation per poll). I have not copied that fix here, to keep these PRs small. I will re-run the job once, when the build jobs in this run finish.


Generated by Claude Code

@dbccpage
dbccpage added this pull request to stack #52 November 11, 2026 10:07
@dbccpage
dbccpage marked this pull request as ready for review November 11, 2026 10:07
@dbccpage
dbccpage removed this pull request from stack #52 November 11, 2026 10:38
Base automatically changed from claude/rd1-post-commit-recovery to main November 11, 2026 10:38
@dbccpage
dbccpage added this pull request to stack #54 November 11, 2026 10:39
@dbccpage
dbccpage removed this pull request from stack #54 November 11, 2026 11:07
@dbccpage
dbccpage merged commit dc40098 into main Nov 11, 2026
5 checks passed
@dbccpage
dbccpage deleted the claude/rd2-signed-head-bootstrap-and-withdraw branch November 11, 2026 11:07
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