Skip to content

Fix local ledger downloads after snapshot recovery - #8302

Open
Eddy Ashton (eddyashton) wants to merge 4 commits into
mainfrom
agents/fix-recovery-ledger-readability-bug
Open

Fix local ledger downloads after snapshot recovery#8302
Eddy Ashton (eddyashton) wants to merge 4 commits into
mainfrom
agents/fix-recovery-ledger-readability-bug

Conversation

@eddyashton

@eddyashton Eddy Ashton (eddyashton) commented Sep 7, 2026

Copy link
Copy Markdown
Member

Bug

This fixes an actual test-infrastructure failure, not code readability or production recovery behavior. In the original #8117 ASAN run, recovery node 18 loaded snapshot 423, replayed the old service through 436, and created the new service at 437. The local-only downloader nevertheless started at 424 and received 404 responses for 20 seconds.

startup_seqno identifies the startup snapshot, not the beginning of locally HTTP-readable history. Ledger::committed_ledger_path_with_idx searches only the main ledger directory and excludes recovery-marked files. The test infrastructure supplies already-committed old-service files through read-only recovery directories. If the relevant old-service chunk is still current at shutdown, it instead goes into the main directory and can later be served; this is why the bad watermark sometimes works.

The original incident used the default, unshuffled suite order. A plain recovery/readability pair reproduced both failure and success in a normal Debug build: ASAN is not required, but chunk commitment timing matters.

Fix

Check StartType.recover before checking the startup snapshot. For local-only downloads, recovery-start nodes begin at current_service_create_txid; snapshot joiners retain startup_seqno + 1, and genesis/snapshot-less joiners retain 1. The recovery bound is conservative: earlier history may be locally available, but is not guaranteed to be. Explicit starting-sequence requests and normal non-local-only downloads are unchanged. No production endpoint or timeout changes.

Regression coverage

Removed the standalone e2e test, CMake registration, and CI bucket entry. A 16-line recovery variant now:

  1. Copies committed snapshots using the existing helper.
  2. Forces and waits for a committed ledger chunk beyond the copied snapshot.
  3. Recovers using that unchanged snapshot copy.

This reliably places the first post-snapshot entry in read-only recovery input. The variant is included alongside the existing recovery cases in full_test_suite, and a named recovery_ledger two-step ordering runs it immediately before governance_history.test_ledger_is_readable. No private-helper or hard-coded 404 assertions remain.

Validation

All executions used build-directory tests.sh:

  • Reduced two-step sequence, normal Debug: old helper failed 3/3 with the original download timeout; fixed helper passed 3/3.
  • Final full suite, default order: 44 passed, 1 existing quorum-requirement skip (test_node_replacement).
  • Final full suite with SHUFFLE_SUITE=1 and SHUFFLE_SUITE_SEED=1, 2, and 3: 45/45 passed for each seed; the new recovery variant executed successfully in all runs.
  • scripts/ci-checks.sh -f: all checks passed.
  • Independent review of the lightweight replacement: no significant issues found.

Earlier normal and ASAN runs verified the helper fix using the now-removed standalone repro; the replacement suite coverage above was validated in the normal build.

Follow-up to #8266; related to #8248.

Copilot AI lite review requested due to automatic review settings September 7, 2026 14:39
@eddyashton
Eddy Ashton (eddyashton) requested a review from a team as a code owner September 7, 2026 14:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new test asserts a 404 for /node/ledger_chunk?since=... where the server logic should typically return a permanent redirect (308) when other nodes exist, making the test likely to fail.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR fixes how the test infrastructure determines a node’s locally-servable ledger “watermark” during service recovery (so recovery nodes don’t incorrectly use a startup snapshot boundary), and adds a focused end-to-end test to prevent regressions in recovery-ledger readability.

Changes:

  • Adjust Node._get_local_ledger_start_seqno() to prioritise recovery semantics (use current_service_create_txid for recovery nodes) before considering startup_seqno.
  • Add a new recovery_ledger_readability e2e test covering snapshot and non-snapshot recovery paths and verifying expected watermark behaviour.
  • Register the new test in CMake and CI bucket configuration.

Custom instructions used

  • None (no repository instruction files from .github/copilot-instructions.md or .github/instructions/ were loaded via tools in this review).
File summaries
File Description
tests/recovery_ledger.py New e2e test validating recovery ledger readability/watermarks across snapshot/no-snapshot scenarios.
tests/infra/node.py Fixes local ledger start seqno selection for recovery nodes to avoid using snapshot-derived startup seqno.
tests/ci-buckets.txt Adds the new recovery ledger readability test to bucket_b.
CMakeLists.txt Registers the new recovery_ledger_readability e2e test target.
Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/recovery_ledger.py Outdated
Prioritise the recovery lifecycle over the startup snapshot when selecting locally downloadable ledger history. Previous-service recovery input may be read-only, so every recovery-start node must begin at the current service creation transaction.

Add deterministic snapshot and ledger-only recovery/readability coverage, including explicit lifecycle watermark assertions for recovery nodes, snapshot joiners, and genesis or snapshot-less joiners. Follow up on #8266 and the residual failure exposed by #8117 ASAN.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eddyashton
Eddy Ashton (eddyashton) force-pushed the agents/fix-recovery-ledger-readability-bug branch from 6232dd3 to 998720a Compare September 7, 2026 15:52
Comment thread tests/recovery_ledger.py Outdated
Comment thread tests/infra/node.py

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand what this PR aims to do, is it only improving readability (not a bug), or fixing an actual test failure that was surface with ASAN as claimed at the bottom of the description? What is the test failure?

I see two changes, a new test, and a change to _get_local_ledger_start_seqno() that does not seem right to me. I am unable to reconcile them with the description.

@eddyashton
Eddy Ashton (eddyashton) marked this pull request as draft September 8, 2026 08:54
@eddyashton

Copy link
Copy Markdown
Member Author

I do not understand what this PR aims to do, is it only improving readability (not a bug), or fixing an actual test failure that was surface with ASAN as claimed at the bottom of the description? What is the test failure?

I see two changes, a new test, and a change to _get_local_ledger_start_seqno() that does not seem right to me. I am unable to reconcile them with the description.

Here's the ASAN failure: https://github.com/microsoft/CCF/actions/runs/34121620500/job/101740738617

It's fixing a "ledger readability" bug, as in "what is readable from the ledger". Not code readability. Still iterating on a more sensible repro.

Replace the standalone recovery ledger e2e test with a small recovery variant and a fixed two-step regression ordering. Copy the startup snapshot before forcing a committed chunk beyond it, so recovery reliably receives the first post-snapshot entry in read-only ledger input rather than the current main-directory chunk.

Include the variant alongside the existing full-suite recovery cases. Verified the reduced sequence fails three times with the old helper and passes three times with the fix; the final full suite passes in default order and with shuffle seeds 1, 2 and 3.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@eddyashton Eddy Ashton (eddyashton) changed the title Fix recovery ledger readability bug and improve test structure Fix local ledger downloads after snapshot recovery Sep 8, 2026
@eddyashton
Eddy Ashton (eddyashton) marked this pull request as ready for review September 8, 2026 11:12
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

4 participants