Skip to content

cli: prove a data fault abandons the run and leaves nothing behind - #266

Open
Kiran01bm wants to merge 2 commits into
mainfrom
kiran01bm/cs12-data-fault-proof
Open

Kiran01bm wants to merge 2 commits into
mainfrom
kiran01bm/cs12-data-fault-proof

Conversation

@Kiran01bm

@Kiran01bm Kiran01bm commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Two front-door integration tests prove that a copy-and-swap run which meets a value the new type cannot hold is abandoned cleanly: failed / data-fault on stdout, exit 1, and nothing left on the server.

Why

The abandon path exists and is tested at the Runner (pkg/schemachange) and at migrate.Run, but neither test drives it the way a user or an orchestrator does — through pg-sprite migrate --json — and neither holds the server to the whole promise the data-fault row in docs/execution-model.md makes: shadow dropped, write fence off or slot and publication dropped, checkpoint row deleted, source untouched and writable. The existing migrate.Run test also makes every row violate, so the fault fires on the first chunk; a realistic fault is one bad row deep in a table that has already landed chunks in the shadow. The live abandon under load has no front-door coverage at all.

What

internal/cli/data_fault_integration_test.go adds two tests over the workload table, each with one planted 64-character label at row 3000 of 4000 and the statement ALTER COLUMN label TYPE varchar(32):

  • TestMigrateReportsABlockWritesDataFaultAndLeavesNothingBehind — --block-writes SCHEMA.TABLE, so the run holds the write fence.
  • TestMigrateReportsALiveDataFaultAndLeavesNothingBehind — a wal_level=logical server with an insert/update load running throughout, so the run holds a replication slot and publication; the load is never fenced and reports no write error.

Both assert the run's error is the Runner's AbandonedError carrying SQLSTATE 22001 and is not ErrRefused (exit 1, not 2); the JSON verdict is failed / data-fault for the table, not forced, with a detail that says the run was abandoned, names what was released, and offers no --restart; and the server has no shadow, no pgsprite_write_fence trigger, no checkpoint row, label still text, the planted row still the only violator, every seeded row present, and the source accepting an insert. The live test also asserts zero rows in pg_replication_slots and pg_publication.

No production code or docs change; the tests hold the code to claims the docs already make.

Before / after

The same statement and the same table on both sides: 4000 rows, one label of 64 characters at row 3000, narrowed to varchar(32). Before, the front-door path had no proof past the first chunk and no proof of what a live run releases; after, both runs are driven through cmd.run with --json and the server is checked field by field.

Before: what was proven about a data fault

  pkg/schemachange Runner test ─── live, every row violates ─── slot dropped, no row
  pkg/migrate Run test ───── writes blocked, every row violates ─ shadow gone, source writable
  internal/cli ─────────────────── (no data-fault test)

After: the same fault, driven the way a user runs it

  pg-sprite migrate --json [--block-writes SCHEMA.TABLE]
    ALTER TABLE s.workload ALTER COLUMN label TYPE varchar(32)
          │
          ▼  copier lands chunks 1..k into the shadow
          ▼  chunk holding row 3000: server raises 22001 (value too long)
          ▼  Runner abandons: DROP shadow, fence off / slot + publication dropped, row deleted
          │
          ├─ stdout: {"outcome":"failed","code":"data-fault","table":"s.workload",
          │           "detail":"... the run was abandoned ... <fence off | slot dropped> ..."}
          ├─ cmd.run returns *AbandonedError (not ErrRefused)  ──► process exit 1
          │
          └─ server after the verdict
               shadow table ............ absent
               pgsprite_write_fence .... absent        (run that blocked writes)
               pg_replication_slots .... 0 rows        (live run)
               pg_publication .......... 0 rows        (live run)
               checkpoint row .......... ErrNotFound
               label ................... text, 4000+ rows, 1 violator
               INSERT INTO s.workload .. succeeds

🤖 Generated with Amp (Claude Opus 4.6)

The abandon was proven at the Runner and at migrate.Run, but not through
the front door, not on a live run under load, and not for the fence,
slot, publication, and checkpoint row together. These two tests hold the
CLI's verdict, exit mapping, and server state to the data-fault contract
the execution-model doc states.
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.
@Kiran01bm
Kiran01bm marked this pull request as ready for review October 29, 2026 00:04
@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-29T00:04:45.591965Z
We couldn’t complete this review. Comment @codex review to try again.
789a204 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.

@Kiran01bm
Kiran01bm requested a review from morgo as a code owner October 29, 2026 00:04
@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 29, 2026

Copy link
Copy Markdown
Collaborator

🤖 Reviewed on Jash's behalf at 789a204edabe834d697895a3be10cb6bade3e6c2.

Verdict: no blocking defect found in this test-only diff. The two CLI cases check the typed abandonment and SQLSTATE, JSON outcome, released resources, unchanged column type, and ability to write afterward. Keeping deletes out of the live workload avoids intentionally removing the planted violator.

Two optional coverage improvements:

  1. In internal/cli/data_fault_integration_test.go:194–195, the total row-count assertion does not prove its message, “every seeded row is still in the source”: concurrent inserts can hide a missing seeded row. Check preservation of the seeded key set separately from the growing total, so a cleanup regression that deletes a source row cannot pass on replacement inserts.
  2. The setup at lines 22–30 places the fault late in key order, but the test never observes that an earlier shadow chunk actually committed before abandonment. If the goal is specifically cleanup after partial progress, add a deterministic progress observation; otherwise a change to chunk sizing or scheduling could reduce this to first-chunk failure coverage while it stays green.

Verification: read the full 200-line diff and PR description, and checked the current head. GitHub reports all 16 checks successful, including PostgreSQL 14–18 integration jobs. I did not run a local build or tests. The source-file API was unavailable, so I could not inspect the unchanged workload, copier, or CLI exit-mapping implementations; the asserted error classification is not itself a subprocess exit-code test.

— Codex

@JashLal

JashLal commented Oct 29, 2026

Copy link
Copy Markdown
Collaborator

🤖 Product review at 789a204.

OSS adoption: This improves coverage of an actionable failure contract: failed / data-fault, the original table still writable, and no misleading --restart suggestion after successful abandonment. There is no new CLI surface to learn.

SchemaBot integration: Preserving AbandonedError, the underlying PostgreSQL SQLSTATE, and a structured verdict gives callers machine-readable signals rather than requiring detail-text parsing. This PR exercises the CLI adapter; it does not directly test an engine integration, and I could not inspect that caller here. No integration blocker identified in the diff.

— Codex

@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 after the reviews above at 789a204. The optional coverage improvements and verification limits are recorded there. — Codex

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