Skip to content

test(state): exercise pruning in the header-store coherence harness#499

Draft
p0mvn wants to merge 8 commits into
zakura-canonical-suffixfrom
zakura-prune-coherence
Draft

test(state): exercise pruning in the header-store coherence harness#499
p0mvn wants to merge 8 commits into
zakura-canonical-suffixfrom
zakura-prune-coherence

Conversation

@p0mvn

@p0mvn p0mvn commented Jul 7, 2026

Copy link
Copy Markdown

Motivation

The startup audit's committed-height predicate was deliberately chosen as contains_height (the consensus hash row, which pruning retains) rather than body presence — but that choice had never been exercised against an actually-pruned store, and pruning was explicitly out of the coherence harness's op alphabet. This closes that residual.

Stacks on #495 (zakura-canonical-suffix).

Solution

  • Op::Prune joins the op alphabet, driving the production prepare_prune_batch below the finalized body tip with a monotone marker. The harness asserts pruning is membership-neutral: the zakura store is byte-identical, pruned heights keep their consensus hash rows and lose their bodies, and the oracle's predictions are unchanged. Added to the discovery proptest's op distribution and pinned by scenario s11 (prune → reorg → restart → deeper prune).
  • startup_removes_stale_rows_at_pruned_heights: hand-planted zakura rows at actually-pruned heights (the pre-fix(state): validate linkage in zakura header-store writers #491 bug-2 shape: contains_height true, contains_body_at_height false) are classified StaleRowAtCommittedHeight and deleted, while a verified roots row at a pruned height survives untouched — the test the predicate choice was made for.
  • Fixes a harness-model bug the new test exposed: the test-side audit's roots-row rule used body presence, which would misclassify pruning-retained verified roots rows as violations; it now uses the committed-height predicate like the production audit.

Tests

Tests only. All gates green locally:

  • cargo test -p zebra-state --lib (345 passed)
  • cargo fmt --all -- --check, cargo clippy -p zebra-state -p zebrad --all-targets -- -D warnings
  • PROPTEST_CASES=1024 cargo test -p zebra-state --release --lib prop_random_sequences_uphold_invariants (discovery sweep with Op::Prune in the distribution)

Follow-up Work

The fleet↔main reconciliation should carry this alongside the fleet-lineage test restore (#498).

AI Disclosure

  • AI tools were used: Claude Code wrote the tests and the harness changes under review; the author reviewed every line and ran all gates locally.

PR Checklist

  • The PR title follows conventional commits format: type(scope): description
  • The solution is tested.

p0mvn added 8 commits July 6, 2026 16:35
Close the three write-path corruption bugs proven by the Phase-1
header-store coherence suite (PR #490):

1. prepare_header_range_batch_with_roots now rejects ranges whose first
   header does not link to the anchor or whose headers are not
   internally contiguous (new CommitHeaderRangeError::UnlinkedRange,
   classified as a local non-scoring failure in zebrad).
2. The range insert loop skips heights that already have a committed
   block, so re-deliveries can no longer strand provisional zakura rows
   below the body tip.
3. prepare_zakura_header_from_committed_block refuses seeds that do not
   link to the stored row below them as silent no-ops; header-range
   sync converges the store instead (scenario s11).

Flip the four *_upholds_invariants twins to permanent regression gates,
delete the corruption_repro_* tests, remove the discovery masking, and
un-ignore the random invariant sweep (clean at PROPTEST_CASES=4096).
Pillar 2 of the REORG_PLAN: a corrupted header store can no longer poison
difficulty validation — readers surface the storage fault explicitly.

- recent_header_context verifies, at every step of its walk, that the
  stored header is the block its hash row names (HeaderHashMismatch),
  that it links to the row below (BrokenLinkage), and that no row is
  missing below a stored one (Gap), returning the new StoreIncoherentError
  instead of a poisoned or silently shortened difficulty window.
- The range writer's anchor round-trip distinguishes a bijection
  violation in our own indexes (StoreIncoherent::BijectionMismatch) from
  a genuinely unknown anchor (UnknownAnchor).
- CommitHeaderRangeError::StoreIncoherent is classified as a local,
  non-peer-scoring commit failure in zebrad: the range was rejected
  because our store cannot supply trustworthy context, not because the
  peer's range was shown invalid.

New reads.rs suite in header_store_coherence hand-corrupts the column
families and pins the reader/writer behavior for all four fault shapes,
including side-effect freedom of the rejections.
Closes the REORG_PLAN §1c residual (INTEGRATION_TEST_PLAN.md T2):

- Op::Prune joins the op alphabet, driving the production
  prepare_prune_batch below the finalized body tip with a monotone
  marker. Pruning is membership-neutral: the harness asserts the zakura
  store is byte-identical, pruned heights keep their consensus hash
  rows and lose their bodies, and the oracle's predictions are
  unchanged. Added to the discovery proptest distribution (1024-case
  sweep green) and pinned by scenario s11 (prune → reorg → restart →
  deeper prune).
- startup_removes_stale_rows_at_pruned_heights: hand-planted zakura
  rows at actually-pruned heights (the pre-#491 bug-2 shape:
  contains_height true, contains_body_at_height false) are classified
  StaleRowAtCommittedHeight and deleted, while a verified roots row at
  a pruned height survives untouched — the test the audit's
  contains_height predicate choice was made for.
- Fixes the harness-side audit model the new test exposed: the test
  audit's roots-row rule used body presence, which would misclassify
  pruning-retained verified roots rows as violations; it now uses the
  committed-height predicate like the production audit.
@v12-auditor

v12-auditor Bot commented Jul 7, 2026

Copy link
Copy Markdown

Warning

No auditable source files found in this PR's diff.

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.

1 participant