Skip to content

Persist filesystem WAL writer epochs - #715

Merged
flyingrobots merged 11 commits into
mainfrom
task/714-persist-writer-epoch-fencing
Jul 30, 2026
Merged

Persist filesystem WAL writer epochs#715
flyingrobots merged 11 commits into
mainfrom
task/714-persist-writer-epoch-fencing

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Persists single-owner filesystem WAL writer epochs and exact predecessor evidence across host restarts. Proves fenced external-action recovery and replay across independent processes.

Closes #714.

Summary by CodeRabbit

  • New Features

    • Added durable, checksummed writer-epoch tracking for strict filesystem WAL storage.
    • Added filesystem writer leasing to prevent overlapping writers and unsafe appends.
    • Improved recovery after process loss by safely closing abandoned epochs and creating linked successors.
    • Preserved external-action request, claim, settlement, and replay evidence across processes.
  • Bug Fixes

    • WAL recovery now fails closed when epoch records are missing, corrupted, duplicated, stale, skipped, or improperly linked.
  • Documentation

    • Updated WAL documentation with writer-epoch durability and multi-process recovery details.

@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@flyingrobots

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@flyingrobots

Copy link
Copy Markdown
Owner Author

@codex please review

@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.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@flyingrobots, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 37 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: aa8ccdb6-8cac-430f-aaca-1dcdf9c1d68e

📥 Commits

Reviewing files that changed from the base of the PR and between 88a5c73 and 12a67f6.

📒 Files selected for processing (8)
  • .ban-nondeterminism-allowlist
  • CHANGELOG.md
  • crates/warp-core/src/causal_wal.rs
  • crates/warp-core/src/trusted_runtime_host.rs
  • crates/warp-core/tests/causal_wal_hardening_tests.rs
  • crates/warp-core/tests/external_action_protocol_tests.rs
  • crates/warp-core/tests/support/child_process.rs
  • docs/topics/WAL.md
📝 Walkthrough

Walkthrough

Changes

The filesystem WAL now persists checksummed writer-epoch ledgers, acquires OS-backed writer leases, validates monotonic epoch chains, and reconciles recovery evidence. Trusted runtime integration derives store-specific epochs and uses in-memory rollback snapshots. Tests cover corruption, overlap, recovery, and external-action replay across processes.

Filesystem WAL hardening

Layer / File(s) Summary
Epoch ledger contract
crates/warp-core/src/causal_wal.rs
Adds persisted epoch structures, codecs, digest validation, reconciliation, stricter predecessor checks, and ledger-specific errors.
Filesystem epoch lifecycle
crates/warp-core/src/causal_wal.rs
Loads and persists epoch state, holds writer_epoch.lock, recovers abandoned epochs, and requires the lease for WAL mutations.
Runtime epoch and rollback integration
crates/warp-core/src/trusted_runtime_host.rs
Derives epochs by store kind and restores in-memory WAL snapshots when tick commits fail.
Cross-process validation and documentation
crates/warp-core/tests/*, docs/topics/WAL.md, CHANGELOG.md
Adds filesystem epoch and external-action process tests and documents the new WAL evidence claims.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HostProcess
  participant FilesystemWalStore
  participant WriterEpochLedger
  participant WAL
  HostProcess->>FilesystemWalStore: acquire fresh writer epoch
  FilesystemWalStore->>WriterEpochLedger: reload and reconcile evidence
  FilesystemWalStore->>FilesystemWalStore: acquire writer lease
  FilesystemWalStore->>WriterEpochLedger: persist successor epoch
  HostProcess->>FilesystemWalStore: record request, claim, or settlement
  FilesystemWalStore->>WAL: append and commit evidence
  FilesystemWalStore->>WriterEpochLedger: persist final LSN and digest
  HostProcess->>FilesystemWalStore: recover and replay settled result
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.05% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately names the main change: persisting filesystem WAL writer epochs.
Linked Issues check ✅ Passed The changes add persistent writer-epoch fencing, recovery, stricter chain validation, and multi-process tests matching #714.
Out of Scope Changes check ✅ Passed The diff stays focused on WAL persistence, host rollback, tests, and docs; no unrelated feature work stands out.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task/714-persist-writer-epoch-fencing

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/warp-core/src/causal_wal.rs (2)

6062-6064: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

truncate_tail_after mutates segments without the writer lease.

Every other mutating filesystem path in this PR gained ensure_writer_lock()append_frame (5977), flush_commit_with_capabilities (5848), rotate_segment (5910), publish_manifest (6071), close_epoch (6100). truncate_tail_after calls rewrite_filesystem_segments_after_truncation, which rewrites on-disk segment content, and is unguarded. A second process that opens the same root without acquiring the lease can therefore truncate committed tail data underneath the live epoch holder, and the epoch ledger's final_lsn/final_commit_digest evidence for the active epoch silently stops matching the segments.

🔒 Guard the truncation path
     fn truncate_tail_after(&mut self, after_lsn: Lsn) -> Result<(), WalStoreError> {
+        self.ensure_writer_lock()?;
         rewrite_filesystem_segments_after_truncation(&self.root, after_lsn)
     }

If recovery legitimately needs to truncate before an epoch is acquired, make that an explicit lease-acquiring recovery entrypoint rather than an unguarded port method.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/warp-core/src/causal_wal.rs` around lines 6062 - 6064, Update
truncate_tail_after to require the writer lease before calling
rewrite_filesystem_segments_after_truncation, consistent with append_frame,
flush_commit_with_capabilities, rotate_segment, publish_manifest, and
close_epoch. If recovery needs pre-epoch truncation, route it through an
explicit lease-acquiring recovery entrypoint instead of leaving this mutating
method unguarded.

5872-5879: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

Per-commit ledger rewrite triples fsyncs on the durable ACK path, and it's redundant.

Every flush_commit_with_capabilities now does: segment append + sync_all, then write_writer_epoch_ledger_atomic → temp sync_all + rename + sync_directory_store. That's three durability barriers per committed transaction instead of one, plus a full re-encode of the entire closed-epoch history (which grows with every process restart).

reconcile_writer_epoch_closures (Line 8375) already reconstructs final_lsn/final_commit_digest from scanned commits at open, and the tests only depend on reopen-visible state. The closure evidence for the active epoch therefore does not need a synchronous ledger write per commit — persisting on epoch close (Line 6112) plus reconcile-at-open yields the same recovered ledger.

Also note the in-memory epoch_closures insert at Line 5872 is not rolled back when the persist at Line 5879 fails, unlike the careful restore in close_epoch. If you keep the write, make the failure path symmetric.

As per path instructions for crates/warp-core/**: "Performance matters — flag unnecessary allocations in hot paths."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/warp-core/src/causal_wal.rs` around lines 5872 - 5879, The per-commit
update in flush_commit_with_capabilities should stop calling
persist_writer_epoch_ledger, avoiding redundant synchronous ledger rewrites;
retain the in-memory epoch_closures update and rely on epoch-close persistence
plus reconcile_writer_epoch_closures during reopen. If persistence is
intentionally retained, make its error path restore the prior epoch_closures
entry symmetrically with close_epoch.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/warp-core/src/causal_wal.rs`:
- Around line 8236-8254: Bound the retained history in WriterEpochLedger during
the decode/append flow around closed_epochs, preserving only the latest closed
epoch plus a bounded window while folding older entries into a chain digest.
Update validate_writer_epoch_request and ledger serialization/reopen logic to
validate successors from the retained state and digest without scanning the full
lifetime history. Ensure compaction occurs under the existing lease and
preserves deterministic reopen validation.
- Around line 5740-5791: Update the writer-epoch creation flow around
derive_filesystem_writer_epoch_evidence so process_identity and host_identity
incorporate explicit caller-supplied host/process identity, while preserving
deterministic derivation and existing chain-position inputs. Ensure
storage_fencing_token and lease_or_lock_evidence are likewise bound to the
supplied identity where they represent takeover evidence, and thread the new
identity input through the relevant caller APIs instead of reading global state,
randomness, or system time. Update the associated WAL documentation and
CHANGELOG wording only if the implementation instead remains purely
chain-derived.
- Around line 5669-5692: Update persist_writer_epoch_ledger and the write/encode
path it invokes to borrow the existing epoch ledger data instead of constructing
an owned WriterEpochLedger via writer_epoch_ledger; preserve writer_epoch_ledger
unchanged for rollback snapshots, and ensure encoding accepts read-only
references while retaining the current persisted output.

In `@crates/warp-core/src/trusted_runtime_host.rs`:
- Around line 2135-2138: In the rollback path around runtime_wal_before, do not
use ? when the in-memory snapshot is unavailable, because returning there skips
the remaining rollback actions. Restore or record the WAL rollback failure while
continuing through the rollback of self.runtime, self.provenance,
echo_operation_action_outcomes, and admitted_echo_operation_actions, then return
the appropriate TrustedRuntimeWalError after all rollback state has been
processed.

In `@crates/warp-core/tests/causal_wal_hardening_tests.rs`:
- Around line 1126-1147: Extract a shared run_child_phase helper for
crates/warp-core/tests/causal_wal_hardening_tests.rs:1126-1147 and
crates/warp-core/tests/external_action_protocol_tests.rs:987-1018 that spawns
each child with --test-threads=1, polls try_wait() until the supplied deadline,
kills timed-out children, cleans up the root, and panics with the phase name;
use it for the filesystem writer phases in
filesystem_writer_epoch_chain_crosses_independent_processes and all request,
claim, settlement, and replay phases, replacing every blocking status() call.

---

Outside diff comments:
In `@crates/warp-core/src/causal_wal.rs`:
- Around line 6062-6064: Update truncate_tail_after to require the writer lease
before calling rewrite_filesystem_segments_after_truncation, consistent with
append_frame, flush_commit_with_capabilities, rotate_segment, publish_manifest,
and close_epoch. If recovery needs pre-epoch truncation, route it through an
explicit lease-acquiring recovery entrypoint instead of leaving this mutating
method unguarded.
- Around line 5872-5879: The per-commit update in flush_commit_with_capabilities
should stop calling persist_writer_epoch_ledger, avoiding redundant synchronous
ledger rewrites; retain the in-memory epoch_closures update and rely on
epoch-close persistence plus reconcile_writer_epoch_closures during reopen. If
persistence is intentionally retained, make its error path restore the prior
epoch_closures entry symmetrically with close_epoch.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 45ccccd8-0886-4adf-b038-077c66643bad

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1d961 and 88a5c73.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • crates/warp-core/src/causal_wal.rs
  • crates/warp-core/src/trusted_runtime_host.rs
  • crates/warp-core/tests/causal_wal_hardening_tests.rs
  • crates/warp-core/tests/external_action_protocol_tests.rs
  • crates/warp-core/tests/trusted_runtime_host_loop_tests.rs
  • docs/topics/WAL.md

Comment thread crates/warp-core/src/causal_wal.rs
Comment thread crates/warp-core/src/causal_wal.rs
Comment thread crates/warp-core/src/causal_wal.rs
Comment thread crates/warp-core/src/trusted_runtime_host.rs Outdated
Comment thread crates/warp-core/tests/causal_wal_hardening_tests.rs
@flyingrobots
flyingrobots merged commit c354d53 into main Jul 30, 2026
40 checks passed
@flyingrobots
flyingrobots deleted the task/714-persist-writer-epoch-fencing branch July 30, 2026 13:49
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.

Persist filesystem WAL writer-epoch fencing across host restarts

1 participant