Executed rollout and theoretical database review

Migration operational rehearsal

10/10 expected outcomes matched. This record separates real SQLite behavior from the modeled PostgreSQL rollout.

Acceptance record

CaseRequirementMethodExpectedObservedCheck
backfill-after-commitResume actual recipe after process deathreal SIGKILL at transaction boundary750 committed rows retained; uncommitted batch absent; 4250 rows resume; integrity ok{'persisted_rows': 750, 'persisted_checkpoint': 750, 'resume_rows': 4250, 'integrity': 'ok', 'kill_boundary': {'mode': 'backfill-after-commit', 'boundary': 'after-third-commit', 'checkpoint': 750}}Matched
backfill-before-commitResume actual recipe after process deathreal SIGKILL at transaction boundary750 committed rows retained; uncommitted batch absent; 4250 rows resume; integrity ok{'persisted_rows': 750, 'persisted_checkpoint': 750, 'resume_rows': 4250, 'integrity': 'ok', 'kill_boundary': {'mode': 'backfill-before-commit', 'boundary': 'transaction-written-before-commit', 'checkpoint': 1000}}Matched
contract-before-commitResume actual recipe after process deathreal SIGKILL at transaction boundarypre-contract schema and triggers restored; clean retry contracts{'recovered_stage': 'cutover', 'legacy_tag_present': True, 'integrity': 'ok', 'kill_boundary': {'mode': 'contract-before-commit', 'boundary': 'transaction-written-before-commit', 'checkpoint': 5000}}Matched
overlap-trafficPreserve old-application writes during migrationtwo SQLite connections with a writer thread100 updates and 100 inserts retained; both contracts agree{'writer_commits': 100, 'writer_errors': [], 'rows': 20100, 'normalized_updates': 100, 'missing_keys': 0, 'contracts_agree': True}Matched
forward-recoveryRecover removed source tags without losing newer contentexecuted forward schema change using pre-contract archiveexact original tags and post-contract description retained{'archived_rows': 20100, 'archive_sha256': 'e3cffd9a88fd5d81f2701d07b5a9c99aa7886f9d04c6019736a8f57cb8869e9c', 'restored_sha256': 'e3cffd9a88fd5d81f2701d07b5a9c99aa7886f9d04c6019736a8f57cb8869e9c', 'newer_content_preserved': True}Matched
lock-abort-retryTimeout leaves the schema unchanged and a later attempt succeedsreal SQLite held write transactionlocked error; legacy schema retained; retry expands{'error': 'database is locked', 'observed_wait_seconds': 0.075993, 'timeout_seconds': 0.075, 'unchanged_on_timeout': True, 'retry_succeeded': True}Matched
size-and-batch-sweepPreserve contents across fixture size and batch sizesfive executed SQLite rolloutsall row counts, content digests and integrity checks match{'cases': 5, 'largest_rows': 100000, 'all_preserved': True}Matched
postgres-lock-modelEvaluate DDL/index contention under declared PostgreSQL lock modestheoretical lock compatibility and timeline modelDDL times out; regular index waits; concurrent index admits writer; concurrent builders conflict{'modeled_cases': 4, 'matched': 4}Matched
postgres-invalid-index-modelBlock cutover until a repaired concurrent index is validtheoretical failed-build/catalog/retry state modelinvalid named index blocks cutover; rebuild becomes valid{'cutover_allowed_after_failure': False, 'cutover_allowed_after_validated_retry': True}Matched
postgres-stage-boundaryKeep concurrent index creation outside a transaction blocktheoretical executor scheduleconcurrent index stage is standalone[{'stage': 'expand', 'transaction': True}, {'stage': 'backfill_batch', 'transaction': True}, {'stage': 'create_index_concurrently', 'transaction': False}, {'stage': 'validate_index', 'transaction': True}, {'stage': 'contract', 'transaction': True}]Matched

Recovery behavior

Backfill survives a process kill both between committed batches and inside an uncommitted batch. Killing contraction after its table rebuild but before commit restores the previous schema on reconnect. A separate forward-recovery exercise adds the original tag back from a retained archive while preserving a post-contract description update.

Recorded workload and model inputs

{
  "size_sweep": [
    {
      "rows": 5000,
      "batch_rows": 100,
      "seconds": 0.059222,
      "rows_per_second_observed": 84428.8,
      "database_and_wal_bytes": 2013056,
      "content_preserved": true,
      "committed_batches": 50
    },
    {
      "rows": 5000,
      "batch_rows": 1000,
      "seconds": 0.02121,
      "rows_per_second_observed": 235742.0,
      "database_and_wal_bytes": 1172576,
      "content_preserved": true,
      "committed_batches": 5
    },
    {
      "rows": 50000,
      "batch_rows": 100,
      "seconds": 0.881005,
      "rows_per_second_observed": 56753.4,
      "database_and_wal_bytes": 12307128,
      "content_preserved": true,
      "committed_batches": 500
    },
    {
      "rows": 50000,
      "batch_rows": 1000,
      "seconds": 0.288573,
      "rows_per_second_observed": 173266.6,
      "database_and_wal_bytes": 12212368,
      "content_preserved": true,
      "committed_batches": 50
    },
    {
      "rows": 100000,
      "batch_rows": 1000,
      "seconds": 0.671821,
      "rows_per_second_observed": 148849.1,
      "database_and_wal_bytes": 24696312,
      "content_preserved": true,
      "committed_batches": 100
    }
  ],
  "postgresql_lock_model": [
    {
      "scenario": "ddl-reader",
      "held": "AccessShare",
      "requested": "AccessExclusive",
      "holder_release_s": 2.0,
      "lock_timeout_s": 0.25,
      "modeled_wait_s": 0.25,
      "outcome": "timeout",
      "expected": "timeout"
    },
    {
      "scenario": "index-writer",
      "held": "RowExclusive",
      "requested": "Share",
      "holder_release_s": 0.8,
      "lock_timeout_s": 2.0,
      "modeled_wait_s": 0.8,
      "outcome": "granted_after_wait",
      "expected": "granted_after_wait"
    },
    {
      "scenario": "concurrent-index-writer",
      "held": "RowExclusive",
      "requested": "ShareUpdateExclusive",
      "holder_release_s": 0.8,
      "lock_timeout_s": 0.25,
      "modeled_wait_s": 0,
      "outcome": "granted",
      "expected": "granted"
    },
    {
      "scenario": "two-index-builds",
      "held": "ShareUpdateExclusive",
      "requested": "ShareUpdateExclusive",
      "holder_release_s": 2.0,
      "lock_timeout_s": 0.25,
      "modeled_wait_s": 0.25,
      "outcome": "timeout",
      "expected": "timeout"
    }
  ],
  "postgresql_index_model": [
    {
      "action": "start_build",
      "exists": true,
      "valid": false,
      "release_allowed": false
    },
    {
      "action": "duplicate_detected",
      "exists": true,
      "valid": false,
      "release_allowed": false
    },
    {
      "action": "inspect_catalog",
      "exists": true,
      "valid": false,
      "release_allowed": false
    },
    {
      "action": "drop_invalid",
      "exists": false,
      "valid": false,
      "release_allowed": false
    },
    {
      "action": "repair_fixture",
      "exists": false,
      "valid": false,
      "release_allowed": false
    },
    {
      "action": "retry_build",
      "exists": true,
      "valid": true,
      "release_allowed": false
    },
    {
      "action": "validate_catalog",
      "exists": true,
      "valid": true,
      "release_allowed": true
    }
  ],
  "postgresql_stage_plan": [
    {
      "stage": "expand",
      "transaction": true
    },
    {
      "stage": "backfill_batch",
      "transaction": true
    },
    {
      "stage": "create_index_concurrently",
      "transaction": false
    },
    {
      "stage": "validate_index",
      "transaction": true
    },
    {
      "stage": "contract",
      "transaction": true
    }
  ]
}

Evidence boundaries

Verification record · Acceptance CSV · Runbook and PostgreSQL review · Reproduction source