test(sources): reproduce membership-replay conflict at growth-chain scale - #3666
Conversation
…cale Problem: polylogue-5iz4's AC required a structural fixture reproducing the real 804-revision Codex session's crash shape (many incremental full-snapshot captures of one growing file, plus a same-identity duplicate from a second "incident recovery" path) before the fix in #3646 could be verified against something closer to the real shape than the original small #2718 pin (2-3 message sessions). Investigation: reading the live archive read-only confirmed the real 22 full-revision blobs for this session form ONE clean, unforked byte- prefix chain (every smaller blob is an exact prefix of every larger one) and that raw_revision_heads/sessions are empty for this identity today. Reproducing the actual MembershipReplayConflictError therefore needed the SAME mechanism as test_bundle_replay_respects_unconvertible_ single_session_head (a same-identity bundle arriving at a second path, colliding with a QUARANTINED dangling append fragment hanging off the accepted head), scaled to a growth chain with many messages rather than 2-3, plus a working demonstration that the guard is a transient, recoverable refusal, not a permanent one, per its own docstring: once the accepted head no longer interferes, a retry over the SAME durable raw succeeds and reaches the index with a plausible message_count. Solution: added test_growing_file_incident_recovery_duplicate_recovers_after_head_ advances to tests/unit/sources/test_live_batch_support.py. Notable finding during construction: storage/repair.py's offline repair_raw_materialization reprocesses every retained typed-'full' raw for a logical_source_key on every pass (including the accepted head's own cohort), which re-establishes the interfering head before ever reaching the colliding raw in the same pass -- so this recovery can only be demonstrated here via the live watcher's own retry path (_ingest_full_paths_sync again), not via repair_raw_materialization. That offline-repair gap is noted in the test as a real follow-up, not papered over. Root cause conclusion for the live production session: the retry- eligibility fix already merged in #3646 (dedicated MembershipReplayConflictError type + storage/repair.py recognizing its parse_error prefix) is the actual fix -- PR #3646's own read-only investigation already confirmed the codex parser succeeds on the real 90.8MB blob and that raw_revision_heads has zero rows for this identity today, so a fresh rebuild-index pass over the real archive should reach the SIMPLE byte-chain replay path directly (the real content is one clean chain) without ever re-tripping the membership-governance guard. No further production code change was found necessary this session; this PR is fixture/regression-test work only. Verification: - devtools test tests/unit/sources/test_live_batch_support.py -k test_growing_file_incident_recovery_duplicate_recovers_after_head_advances -- 1 passed (verified stable across 4 repeated runs). - devtools test tests/unit/sources/test_live_batch_support.py -k "revision_replay or membership" -- 7 passed. - devtools test tests/unit/storage/test_repair.py -k membership -- 2 passed. - devtools verify --quick -- 20260803T172208Z-quick-3717286-f717e8bf, exit 0. Ref polylogue-5iz4 Co-Authored-By: Claude <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 23 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
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. Comment |
Summary
Adds a regression test reproducing the real production shape behind polylogue-5iz4 (many incremental full-snapshot captures of one growing Codex session, plus a same-identity duplicate arriving from a second "incident recovery" path) and demonstrates that
MembershipReplayConflictErroris a transient, recoverable refusal, not a permanent one.Problem
polylogue-5iz4's AC required a redacted structural fixture reproducing the real 804-revision Codex session's crash shape before the retry-eligibility fix in PR #3646 could be verified against something closer to the real shape than the original small #2718 pin (2-3 message sessions). PR #3646 fixed the retry-eligibility bug (a stale
parse_errortext that permanently excluded the raw from every future rebuild) but did not add the growth-chain-scale fixture the bead's AC calls for, and its own scope note said it could not claim the retried classification actually succeeds without live evidence.Reading the live archive read-only (
/realm/db/polylogue,mode=ro) confirmed the real 22 full-revision blobs for this session form ONE clean, unforked byte-prefix chain (every smaller blob is an exact prefix of every larger one, verified pairwise) and thatraw_revision_heads/sessionsare empty for this identity today. Reproducing the actualMembershipReplayConflictErrorneeded the same mechanism as the existingtest_bundle_replay_respects_unconvertible_single_session_headpin (a same-identity bundle arriving at a second path, colliding with a QUARANTINED dangling append fragment hanging off the accepted head), scaled up to a growth chain with many messages instead of 2-3.Solution
Added
test_growing_file_incident_recovery_duplicate_recovers_after_head_advancestotests/unit/sources/test_live_batch_support.py. It:MembershipReplayConflictError(fail-closed, correct behavior).parse_errorcarries the retry-eligibleMembershipReplayConflictError:markerstorage/repair.pyrecognizes (polylogue-5iz4 / fix(storage): make membership-replay conflicts retry-eligible by type #3646).raw_revision_headsrow for this identity) and retries — the same durable raw now succeeds and reaches the index with the expected message_count.Notable finding during construction:
storage/repair.py's offlinerepair_raw_materializationreprocesses every retained typed-'full'raw for alogical_source_keyon every pass (including the accepted head's own cohort), which re-establishes the interfering head before ever reaching the colliding raw in the same pass — so the recovery in this test is demonstrated via the live watcher's own retry path (_ingest_full_paths_syncagain), not viarepair_raw_materialization. That offline-repair gap is noted directly in the test as a real follow-up rather than papered over.Root cause conclusion for the live production session: the retry-eligibility fix already merged in #3646 is the actual fix. #3646's own read-only investigation already confirmed the codex parser succeeds on the real 90.8MB blob and that
raw_revision_headshas zero rows for this identity today, so a fresh rebuild-index pass over the real archive should reach the simple byte-chain replay path directly (the real content is one clean chain) without ever re-tripping the membership-governance guard. No further production code change was found necessary this session; this PR is fixture/regression-test work only.Verification
devtools test tests/unit/sources/test_live_batch_support.py -k test_growing_file_incident_recovery_duplicate_recovers_after_head_advances— 1 passed, verified stable across 4 repeated runs.devtools test tests/unit/sources/test_live_batch_support.py -k "revision_replay or membership"— 7 passed.devtools test tests/unit/storage/test_repair.py -k membership— 2 passed.devtools verify --quick— exit 0.Ref polylogue-5iz4