Found during ADR-280 review (non-blocking, pre-existing — not introduced by the metadata delta work).
store.rs:3916: if newest_first.len() > MAX_META_DELTAS { return Err(MetadataReplayLimitExceeded) } aborts the newest-first walk before it can reach a readable snapshot.
Repro: 130 single-record metadata ingests (snapshots land at generations 1/34/67/100), then corrupt the snapshots at indices 99 and 66. Both open and open_readonly return MetadataReplayLimitExceeded; the intact snapshot at index 33 is never reached, and compact() is unreachable because open itself fails.
This is the same "hard error, no repair path" class the D2 recovery work eliminated, and it contradicts the doc comment at store.rs:3893 ("Only a chain with no readable snapshot at all is an error"). It requires corrupting two snapshots, so it is narrower than the cases already fixed.
Fix direction: let the newest-first walk continue past MAX_META_DELTAS looking for a readable snapshot, and enforce the replay budget on the applied chain rather than the scanned one.
🤖 Generated with claude-flow
Found during ADR-280 review (non-blocking, pre-existing — not introduced by the metadata delta work).
store.rs:3916:if newest_first.len() > MAX_META_DELTAS { return Err(MetadataReplayLimitExceeded) }aborts the newest-first walk before it can reach a readable snapshot.Repro: 130 single-record metadata ingests (snapshots land at generations 1/34/67/100), then corrupt the snapshots at indices 99 and 66. Both
openandopen_readonlyreturnMetadataReplayLimitExceeded; the intact snapshot at index 33 is never reached, andcompact()is unreachable because open itself fails.This is the same "hard error, no repair path" class the D2 recovery work eliminated, and it contradicts the doc comment at
store.rs:3893("Only a chain with no readable snapshot at all is an error"). It requires corrupting two snapshots, so it is narrower than the cases already fixed.Fix direction: let the newest-first walk continue past MAX_META_DELTAS looking for a readable snapshot, and enforce the replay budget on the applied chain rather than the scanned one.
🤖 Generated with claude-flow