Skip to content

feat(miner,ingester,server): snapshot restore v2 — per-tenant restore + startup recovery driver - #187

Merged
jensholdgaard merged 6 commits into
mainfrom
feat/snapshot-restore-driver
Jun 12, 2026
Merged

feat(miner,ingester,server): snapshot restore v2 — per-tenant restore + startup recovery driver#187
jensholdgaard merged 6 commits into
mainfrom
feat/snapshot-restore-driver

Conversation

@jensholdgaard

@jensholdgaard jensholdgaard commented Jun 12, 2026

Copy link
Copy Markdown
Owner

What

PR 3 — the final slice of the snapshot-restore workstream (spec #185, WAL mechanism #186). The ingester now restores miner state from per-tenant snapshots and replays only the WAL tail, end to end in the served binary.

  • Miner restore v2 (ourios-miner): recover() returns the parsed SnapshotState on a known version (RecoveryOutcome::Restored) instead of discarding it; MinerCluster::restore_tenant rebuilds a tenant tree from a snapshot — leaves re-descend by their creation-time masked path (a path-position wildcard resolves to its singleton mask tag; widening/type-expansion are impossible at path positions because tree candidates share their first walk_depth masked tokens by construction, so this is total), structured-template map and template_count rebuilt, and the cluster-wide template_id allocator bumps past every restored id. Semantically inconsistent snapshots are RestoreError::Inconsistent → discarded as corrupt (§6.9).
  • Recovery driver (ourios-ingester::recovery): restore per tenant → Wal::replay through a sink that decodes, fans out, and feeds the miner only frames above that tenant's high-water mark (per-tenant horizons — RFC 0001 §6.9 is per-tenant scope, so the single S of RFC0008.10 generalises per tenant). The Parquet horizon (last_checkpoint) is read and reported. Stale-gap detection per §3.5.4: S < checkpoint ∧ S.segment ∉ replayed segments — internally unreachable under the §6.7 retain floor, so a hit means external mutation; surfaced loudly, never silent.
  • Snapshot store (ourios-ingester::snapshot_store): <wal_root>/snapshots/<tenant>.snap, atomic tmp → fsync → rename → parent-fsync (the CHECKPOINT writer's pattern).
  • Server wiring (serve()): open WAL → recover → warn stale gaps → write post-recovery snapshots → then construct the pipeline and bind listeners (RFC0008.10 ordering: recovery completes before serving). shutdown() writes snapshots again after both listeners stop; a write failure degrades to a warning — the snapshot is a rebuildable cache, never durable state.

RFC-gated contract change (explicit, per CLAUDE.md §6.2)

The miner test asserting the v1 "known version is still discarded" contract is retired and replaced by the restore contract — this is exactly the contract change the RFC 0001 §6.9 v2 amendment (#185) approved. The §3.5.2 invariant test is updated to the new recover signature with its assertions strengthened (adds restored == None), not weakened.

Tests

  • §3.5.3 restore-equivalence: restored + tail-replayed miner equals a from-scratch control (compared via the snapshot payloads of both trees), with the suppression counter proving no frame ≤ S reached the miner (the v1 double-apply hazard, now pinned).
  • §3.5.4 stale-gap: external deletion of the segment holding S with a checkpoint above it → loud per-tenant report, survivors still fold.
  • §3.5.2 corrupt-version fallback, cold start, and the served-binary RFC0008.10 end-to-end (pre-populated WAL + snapshot → serve() → live HTTP export → shutdown artefacts equal a control).
  • Miner-level: restore round-trip, identical continuation after restore (including id allocation), wildcard-in-prefix-path, live-tenant/inconsistent rejections, allocator bump.

Invariants / hazards

  • §3.4 WAL-before-ack: untouched on the ack path; Journal::sync now returns the offset Wal::sync already produced (no new fsync). The WAL remains the truth — a lost/corrupt/inconsistent snapshot degrades to full replay in every branch.
  • §3.7 multi-tenancy: snapshots, horizons, restore, and the report are all per-tenant; no cross-tenant state.
  • Hazard docs(rfc-0001): fill in drafted-bar content for the template miner #5 (template drift): the per-tenant horizon + suppression counter prevent double-apply; the stale-gap rule surfaces externally-induced holes instead of silently re-minting.
  • Hazard docs: add verification process spec #1 (miner correctness): restore-equivalence is asserted field-by-field via the snapshot payload, and continuation-equality pins that a restored tree matches/allocates identically to a never-stopped one.

Honest deferrals (not faked)

  1. Per-rotation snapshot cadence (§6.9's primary cadence) is blocked on rotation itself (RFC0008.6, red). Implemented cadence points: post-recovery + graceful shutdown.
  2. Parquet-side suppression has no consumer yet — no Parquet write path exists in the live pipeline; the horizon is read and reported so the routing is in place when it joins.
  3. Housekeeping timer (periodic pass with the retain floor) deferred — nothing calls checkpoint in production yet (no atomic-publish callback), so the timer would be dead machinery.
  4. Snapshot-load-outcome telemetry: named in §6.9 prose; its metric names must go through the semconv weaver registry, so it lands as a registry-first slice.
  5. Stale-gap warnings use stderr — the documented stopgap until structured logging lands (no tracing/log crate exists in the workspace).

Checks run

cargo fmt --all --check, cargo clippy --all-targets --all-features -- -D warnings, cargo test --all-features (648 tests, zero failures), cargo doc --no-deps --all-features — all green locally.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Snapshot persistence and atomic per-tenant snapshot files for durable cache.
    • Startup recovery that restores snapshots and replays only WAL tails, with stale-gap detection.
    • Exposed last-persisted WAL offset (durable high-water) and seeded durable horizon on startup.
    • Graceful shutdown writes shutdown snapshots capturing the durable offset.
  • Tests

    • Extensive unit and end-to-end recovery tests covering snapshot round-trip, restore/discard paths, and shutdown behavior.

jensholdgaard and others added 4 commits June 12, 2026 16:01
…re_tenant rebuilds the tree

RFC 0001 §6.9 v2 (amended 2026-06-12, PR #185): the known-version
branch now restores instead of discarding. recover() returns
(Option<SnapshotState>, RecoveryOutcome) — Restored replaces
KnownVersionDiscarded; the v1 discard-contract test is retired per
the RFC-gated amendment and replaced by the restore contract.

MinerCluster::restore_tenant rebuilds a tenant tree from a
SnapshotState: leaves re-descend by their creation-time masked path
(a path-position wildcard resolves to its singleton mask tag —
widening/type-expansion are impossible at path positions because
candidates share their first walk_depth masked tokens by
construction); structured-template map and template_count rebuilt;
the cluster-wide template_id allocator bumps past every restored id.
Semantically inconsistent snapshots (empty template, slot-count
mismatch, non-mask path slot) are RestoreError::Inconsistent — the
driver treats them as corrupt (discard, full replay) per §6.9.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…RFC 0008 §6.6 / RFC0008.10)

recovery::recover restores each tenant's snapshot into the miner
(uuid-parse failures and restore_tenant rejections discard the
artefact as corrupt — §6.9), then replays the WAL through a sink
that decodes, fans out, and feeds the miner only frames above that
tenant's high-water mark; the Parquet horizon (last_checkpoint) is
read and reported — its consumer joins when the Parquet write path
does. Stale-gap detection per §3.5.4: S below the checkpoint with
S's segment absent from the replayed set (internally unreachable
under the §6.7 retain floor; a hit means external mutation and is
surfaced, never silent — hazard #5). A frame that fails decode or
fan-out stops replay loudly: it was valid when acked, so this is
corruption-adjacent.

snapshot_store: <wal_root>/snapshots/<tenant>.snap artefacts, atomic
tmp -> fsync -> rename -> parent fsync; load_all returns raw bytes
(version dispatch stays in recover). Journal::sync now returns the
durable offset so the pipeline can track last_durable for the
shutdown-cadence snapshot.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…overy + shutdown

serve() now runs the RFC0008.10 sequence: open WAL, restore + replay
through the recovery driver, warn per stale-gap tenant (stderr — the
documented stopgap until structured logging lands), write fresh
snapshots at the replayed high-water, and only then construct the
pipeline and bind both listeners. ReceiverHandle::shutdown writes
snapshots again after both listeners stop; a write failure degrades
to a warning — the snapshot is a rebuildable cache (§6.9), never
durable state. Per-rotation cadence stays blocked on RFC0008.6.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Restore-equivalence (restored + tail-replayed miner equals a
from-scratch control, with the suppression counter proving no frame
at or below S reached it), corrupt-version full-replay fallback,
the stale-gap arm (external segment deletion past S with a
checkpoint above it -> loud report, survivors still fold), cold
start, and the served-binary end-to-end (pre-populated WAL +
snapshot -> serve -> live export -> shutdown artefacts equal a
control).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jensholdgaard
jensholdgaard requested a review from Copilot June 12, 2026 14:23
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR implements RFC 0008/0001 WAL recovery and snapshot restore across ingester and miner: pipeline durable-offset tracking, per-tenant snapshot persistence, miner restore APIs, a recovery driver with suppression horizons and stale-gap detection, server startup/shutdown integration, and extensive tests.

Changes

WAL Recovery and Snapshot Restore Implementation

Layer / File(s) Summary
Pipeline Durability & Module Exports
crates/ourios-ingester/src/receiver/pipeline.rs, crates/ourios-ingester/src/lib.rs, crates/ourios-ingester/Cargo.toml, crates/ourios-ingester/tests/ingest_support/mod.rs
Journal::sync now returns Result<Option<WalOffset>, ReceiveError>; IngestPipeline stores and exposes last_durable with with_last_durable/last_durable; test journals updated to return Ok(None); ourios-ingester adds uuid dependency and exports recovery and snapshot_store.
Miner Snapshot v2 Recovery & Restore APIs
crates/ourios-miner/src/snapshot.rs, crates/ourios-miner/src/cluster.rs, crates/ourios-miner/src/mask.rs, crates/ourios-miner/tests/invariants.rs
Switch snapshot recovery to v2 dispatch: recover returns (Option<SnapshotState>, RecoveryOutcome) with Restored/NoSnapshot/UnknownOrCorruptDiscarded; add MinerCluster::restore_tenant() and tenant_ids(), RestoreError, and tag_str_for mask helper; tests updated for new contract.
Snapshot Disk Store
crates/ourios-ingester/src/snapshot_store.rs
New snapshot store: atomic write to <root>/<percent-encoded tenant>.snap, canonical percent-decode on load, deterministic sort, and labeled I/O/encoding errors with unit tests for round-trip, overwrite, skipped artefacts, and directory skipping.
Recovery Driver Orchestration
crates/ourios-ingester/src/recovery.rs
Adds recover() that loads snapshots, attempts per-tenant restore, replays WAL via DriverSink honoring per-tenant snapshot horizons and a parquet checkpoint horizon for stale-gap detection; adds write_snapshots, parse_high_water, reject, and unit tests.
Server Startup/Shutdown Recovery Integration
crates/ourios-server/src/receiver.rs
Run recovery::recover before binding transports, seed pipeline last-durable from the recovery report, write post-recovery snapshots best-effort, and on shutdown lock pipeline to best-effort write shutdown snapshots; ReceiverHandle extended to hold pipeline and snapshots_root.
Recovery Tests & Test Support
crates/ourios-ingester/tests/ingest_support/mod.rs, crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs, crates/ourios-server/tests/rfc0008_10_recovery_driver.rs
Adds RFC0001 §3.5 snapshot-restore tests (durable-boundary restore, corrupt snapshot discard, no-horizon discard, stale-gap, cold start) and RFC0008.10 end-to-end server recovery tests; provides WAL segment builders, OTLP request helpers, HTTP test post helper, and state comparison utilities; updates test support for new Journal::sync signature.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • jensholdgaard/ourios#170: Related miner snapshot format and recovery foundations that this PR builds upon with v2 restore semantics.
  • jensholdgaard/ourios#135: Overlaps Journal trait and ingest pipeline changes (sync/send semantics) related to durability plumbing.
  • jensholdgaard/ourios#134: Related ingester WAL-before-ack pipeline changes and Wal sync/replay behavior used by this PR.

"🐰
Snapshots bloom as recovery blooms,
From durable marks we leap,
No replay of yesterday's gloom—
Just tail frames we keep,
Shutdown writes the harvest we reap."

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: implementing per-tenant snapshot restore and a startup recovery driver, which are the primary objectives of this comprehensive PR.
Description check ✅ Passed The description comprehensively covers the implementation details, RFC contract changes, test coverage, invariants, deferrals, and verification steps, exceeding the template requirements with substantial technical depth.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/snapshot-restore-driver

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 and usage tips.

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.

Pull request overview

Implements snapshot-restore v2 end-to-end: the miner can now restore per-tenant state from snapshots, and the ingester/server run a startup recovery driver that restores snapshots and replays only the WAL tail above each tenant’s high-water mark before binding listeners (RFC0008.10 / RFC0001 §6.9 v2).

Changes:

  • Add ingester recovery driver + snapshot store (<wal_root>/snapshots/<tenant>.snap) with atomic write semantics, plus server wiring to run recovery before serving and to write snapshots post-recovery and at shutdown.
  • Upgrade miner snapshot recovery dispatch so known-version snapshots are returned for restore (instead of discarded), and add MinerCluster::restore_tenant to rebuild per-tenant state from snapshot payloads.
  • Add/adjust RFC-gated tests covering restore+tail-replay equivalence, stale-gap detection, and served-binary end-to-end recovery behavior.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/ourios-server/tests/rfc0008_10_recovery_driver.rs New end-to-end served-binary test asserting recovery-before-serving + coherent shutdown snapshots.
crates/ourios-server/src/receiver.rs Run recovery before binding; write snapshots post-recovery and on shutdown; plumb snapshot root and pipeline handle.
crates/ourios-miner/tests/invariants.rs Update §3.5.2 invariant test to new recover() signature and v2 semantics.
crates/ourios-miner/src/snapshot.rs Switch recovery dispatch to return SnapshotState on known version; update outcomes/docs/tests accordingly.
crates/ourios-miner/src/mask.rs Expose mask-tag strings for restore-time path wildcard reconstruction (tag_str_for).
crates/ourios-miner/src/cluster.rs Add tenant_ids() and restore_tenant() to rebuild tenant tree + maps from snapshot state; add restore-focused unit tests.
crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs New driver-level tests for restore equivalence, corrupt-version fallback, stale-gap detection, and cold start.
crates/ourios-ingester/tests/ingest_support/mod.rs Update Journal::sync test doubles to return an optional durable WAL offset.
crates/ourios-ingester/src/snapshot_store.rs New on-disk per-tenant snapshot store with percent-encoded tenant filenames and atomic writes.
crates/ourios-ingester/src/recovery.rs New startup recovery driver: per-tenant snapshot restore + WAL replay routing with per-tenant suppression horizons and stale-gap detection.
crates/ourios-ingester/src/receiver/pipeline.rs Journal::sync returns durable offset; pipeline tracks last_durable for snapshot stamping.
crates/ourios-ingester/src/lib.rs Export new recovery + snapshot_store modules and related error/report types.
crates/ourios-ingester/Cargo.toml Add uuid dependency (for parsing snapshot-recorded WAL segment IDs).
Cargo.lock Lockfile update for uuid.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread crates/ourios-ingester/src/recovery.rs
Comment thread crates/ourios-ingester/src/receiver/pipeline.rs
Comment thread crates/ourios-server/src/receiver.rs Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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/ourios-ingester/src/recovery.rs`:
- Around line 213-217: write_snapshots is overwriting every tenant's
state.wal_high_water with a single global high_water; instead preserve
per-tenant replay horizons by retaining the tenant's existing wal_high_water
when appropriate. In the block that sets state.wal_high_water after calling
miner.snapshot_state(&tenant_id), check the tenant's current
snapshot/wal_high_water and whether the tenant is marked stale_gap (or compare
to the original S stored for that tenant) and only update to the new high_water
when the tenant is not stale_gap or when the new offset is strictly ahead of the
tenant’s existing horizon; otherwise leave the tenant’s original horizon (or S)
unchanged so serve() and report.max_delivered do not get flattened to a single
global offset. Ensure this logic references write_snapshots,
miner.snapshot_state, state.wal_high_water, stale_gap and report.max_delivered
so reviewers can find and verify the change.
- Around line 113-305: Add a colocated #[cfg(test)] mod with focused unit tests
next to the recovery code: 1) tests for parse_high_water covering None, valid
UUID → Ok(Some(WalOffset)), and invalid UUID → Err(()) by calling
parse_high_water directly; 2) tests that exercise the stale-gap classification
branch in recover by creating a controlled test scenario (use an in-memory/temp
snapshots_root, a test Wal that returns a chosen parquet_horizon via
last_checkpoint(), and a MinerCluster test double with one restored tenant and a
matching horizon) and assert tenant.stale_gap true/false for the checkpoint vs
segment visibility cases; 3) tests for DriverSink::consume/reject by
constructing a DriverSink with a test MinerCluster and TenantRule and calling
consume with payloads that cause ExportLogsServiceRequest::decode or fan_out to
fail, asserting the returned RecoveryError (SinkRejected) and that
frames/records counters update as expected; keep tests small, use test-only
helpers/doubles in the same module so no public API changes are needed.

In `@crates/ourios-ingester/src/snapshot_store.rs`:
- Around line 115-127: In load_all(), the directory iteration treats any path
with EXTENSION (".snap") as a file and calls std::fs::read(&path), which fails
if the entry is a directory like "tenant.snap/"; add a guard that skips
non-files (e.g., path.is_file() or fs::metadata(&path)?.is_file()) before
attempting to read or process the file (place this check in the entries loop
before calling std::fs::read and before percent_decode_tenant), so only real
snapshot files are read and non-file artefacts are silently skipped.

In `@crates/ourios-miner/src/cluster.rs`:
- Around line 1896-1994: The restore loop must reject duplicate
structured-template keys and duplicate template_ids instead of silently
overwriting and double-counting: when iterating state.structured_templates,
check if tenant.structured_templates already contains the key (severity_number,
scope_name) and return Err(RestoreError::Inconsistent { detail: ... }) on
duplicates; also build a set of seen template_id values while processing
state.leaves and state.structured_templates and return
Err(RestoreError::Inconsistent { detail: ... }) if any template_id is
encountered twice (including collisions between leaves and
structured_templates); finally compute tenant.template_count from the actual
lengths of tenant.leaves and tenant.structured_templates (or the seen set) and
keep the next_template_id bump logic unchanged.

In `@crates/ourios-server/src/receiver.rs`:
- Around line 130-131: IngestPipeline::new currently initializes last_durable to
None, discarding the recovered durable mark; after constructing the pipeline
(the SharedPipeline Arc<Mutex<IngestPipeline>> stored in variable pipeline) you
must seed its last_durable with the recovered high-water value produced by
recovery so shutdown() doesn't overwrite it with None. Fix by setting the
recovered durable mark into the pipeline right after creation (either via an
existing setter on IngestPipeline or by adding a small method like
set_last_durable or a constructor parameter) so the pipeline's last_durable
reflects the recovered durable mark instead of None.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9b811a5f-0322-4298-b824-401494782b6c

📥 Commits

Reviewing files that changed from the base of the PR and between e9322ed and f1f3683.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • crates/ourios-ingester/Cargo.toml
  • crates/ourios-ingester/src/lib.rs
  • crates/ourios-ingester/src/receiver/pipeline.rs
  • crates/ourios-ingester/src/recovery.rs
  • crates/ourios-ingester/src/snapshot_store.rs
  • crates/ourios-ingester/tests/ingest_support/mod.rs
  • crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs
  • crates/ourios-miner/src/cluster.rs
  • crates/ourios-miner/src/mask.rs
  • crates/ourios-miner/src/snapshot.rs
  • crates/ourios-miner/tests/invariants.rs
  • crates/ourios-server/src/receiver.rs
  • crates/ourios-server/tests/rfc0008_10_recovery_driver.rs

Comment thread crates/ourios-ingester/src/recovery.rs
Comment thread crates/ourios-ingester/src/recovery.rs
Comment thread crates/ourios-ingester/src/snapshot_store.rs
Comment thread crates/ourios-miner/src/cluster.rs
Comment thread crates/ourios-server/src/receiver.rs Outdated
… last_durable from recovery

Review round 1:
- a known-version snapshot whose wal_high_water is absent or
  unparseable is discarded (full replay) instead of restored —
  restoring without a horizon cannot suppress, which is exactly the
  v1 double-apply hazard (§6.9 maps it to the discard class)
- IngestPipeline::with_last_durable seeds the recovered high-water,
  so a zero-traffic shutdown no longer overwrites the post-recovery
  snapshots with a horizonless artefact that would force full replay
- restore_tenant rejects duplicate template_ids (across leaves +
  structured) and duplicate structured (severity, scope) keys as
  Inconsistent
- load_all skips non-file *.snap entries instead of aborting recovery
- colocated unit tests for recovery.rs (parse_high_water, the
  extracted stale_gap classification helper, sink rejection)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

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.

Pull request overview

Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.

Comment thread crates/ourios-server/src/receiver.rs Outdated
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs (1)

207-216: 💤 Low value

Consider adding stale_gap assertion for consistency with the corrupt-version test.

The analogous rfc0001_3_5_2_corrupt_version_discards_and_full_replays test asserts !report.tenants[0].stale_gap at line 166. Adding the same assertion here would maintain consistency across discard-scenario tests.

     assert_eq!(
         report.tenants[0].outcome,
         RecoveryOutcome::UnknownOrCorruptDiscarded,
     );
+    assert!(!report.tenants[0].stale_gap);
     assert_eq!(report.records_suppressed_for_miner, 0);
🤖 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/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs` around lines
207 - 216, Add the missing assertion to check that the tenant's stale_gap is
false in this discard-scenario test: locate the assertions block in the
rfc0001_3_5_snapshot_restore test (where report.tenants.len(), outcome,
records_suppressed_for_miner, records_fed_to_miner, and assert_equivalent are
asserted) and insert an assertion like assert!(!report.tenants[0].stale_gap)
immediately after the outcome check to mirror the behavior asserted in
rfc0001_3_5_2_corrupt_version_discards_and_full_replays.
🤖 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.

Nitpick comments:
In `@crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs`:
- Around line 207-216: Add the missing assertion to check that the tenant's
stale_gap is false in this discard-scenario test: locate the assertions block in
the rfc0001_3_5_snapshot_restore test (where report.tenants.len(), outcome,
records_suppressed_for_miner, records_fed_to_miner, and assert_equivalent are
asserted) and insert an assertion like assert!(!report.tenants[0].stale_gap)
immediately after the outcome check to mirror the behavior asserted in
rfc0001_3_5_2_corrupt_version_discards_and_full_replays.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5aeb01d9-8ad8-4073-9691-62b2190f3b11

📥 Commits

Reviewing files that changed from the base of the PR and between f1f3683 and ee7f6fe.

📒 Files selected for processing (7)
  • crates/ourios-ingester/src/receiver/pipeline.rs
  • crates/ourios-ingester/src/recovery.rs
  • crates/ourios-ingester/src/snapshot_store.rs
  • crates/ourios-ingester/tests/rfc0001_3_5_snapshot_restore.rs
  • crates/ourios-miner/src/cluster.rs
  • crates/ourios-server/src/receiver.rs
  • crates/ourios-server/tests/rfc0008_10_recovery_driver.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/ourios-server/src/receiver.rs
  • crates/ourios-ingester/src/snapshot_store.rs
  • crates/ourios-ingester/src/recovery.rs
  • crates/ourios-miner/src/cluster.rs

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.

2 participants