| RC1 | Reconcile requires a committed chunk run | rivet reconcile bails when no chunk_run exists for the export. Operator must run the chunked export with chunk_checkpoint: true first. | reconcile_chunked_inner — get_latest_chunk_run |
| RC2 | Partition SQL parity with extraction | The per-partition source COUNT(*) is built from the exact same build_chunk_query_sql shape used during extraction — same WHERE, same dense/range/by-days branch, same identifier quoting. | reconcile_chunked_tasks |
| RC3 | Per-partition classification | Each chunk_task is classified as match (counts equal), mismatch (both counts known and differ), or unknown (either count missing). Unknown is always a repair candidate. | PartitionResult::classify |
| RC4 | Reconcile scope v1 | Only chunked exports. time_window bails with a clear “use chunk_by_days” message; snapshot / incremental receive “use rivet run --reconcile”. | reconcile_cmd::run_reconcile_command |
| RC5 | Report shape stability | ReconcileReport JSON fields (export_name, run_id, strategy, partitions[], summary) form a stable schema; new fields are additive only. | plan::reconcile, serde defaults |
| RC6 | Verified advances only on full match | Verified boundary (ADR-0008 PG5) is written iff summary.mismatches == 0 && summary.unknown == 0. | reconcile_cmd::reconcile_chunked |
| RR1 | Repair derives only from reconcile | RepairPlan::from_reconcile is the single path that produces repair actions — no direct config paths, no operator-typed ranges. | plan::repair::RepairPlan::from_reconcile |
| RR2 | Plan before execute | Without --execute, rivet repair prints the plan and exits; no destination files are written and nothing is re-exported. When --report is omitted it first builds a fresh reconcile in-process, issuing one read-only SELECT COUNT(*) per partition against the source (and, on a fully-clean result, advancing the verified boundary per RC6); only the --report <file> path is source-query-free. | repair_cmd::run_repair_command |
| RR3 | Repair SQL parity | Repair chunk queries use the same build_chunk_query_sql as extraction and reconcile — repair is apples-to-apples with the original run. | run_chunked_sequential(ChunkSource::Precomputed) |
| RR4 | Committed boundary not moved by repair | Repair re-exports chunks already covered by committed progression; last_committed_* is not re-stamped by repair. Operator advances verified by running rivet reconcile afterwards. | repair_cmd::execute_repair (no record_committed_* call) |
| RR5 | Destination files are additive | Repair writes new files alongside originals using <export>_<ts>_chunk<idx>_<nonce>.<ext> naming; the 64-bit <nonce> makes the name collision-proof so a re-export of the same chunk never overwrites the original even when it lands in the same wall-clock second (the second-granularity <ts> alone would collide). Rivet does not delete or overwrite prior files. The manifest declares the replacement (amended 2026-09-26): the chunk’s previously committed part(s) are re-marked superseded, so row_count, part_count, column_checksums (the superseded parts’ contribution is re-read and subtracted), validate, and rivet load all see each row once. The superseded files stay on disk until opt-in load.gc_orphans collects them (never while a run is active on the prefix). When an original cannot be mapped to its chunk without guessing (a manifest from another run, a part name with no chunk index, a repair part the rename could not relabel), that chunk stays additive and repair warns. A warehouse that already loaded the old part without a primary key keeps those rows. | chunked::chunk_part_filename, repair_cmd::superseded_parts |
| RR6 | Unparseable identifiers are skipped | Partitions whose identifier does not match "chunk N [start..end]" with parseable i64 bounds are recorded in skipped[] — never silently dropped, never executed. | RepairAction::from_identifier, execute_repair |
| RR7 | Strategy scope v1 | Repair requires mode: chunked. Other modes bail with a clear error (same policy as reconcile scope). | repair_cmd::run_repair_command |
| RR8 | Report shape stability | RepairPlan / RepairReport JSON is a stable additive schema (same policy as RC5). | plan::repair, serde defaults |