Skip to content

fix(collector): make Polymarket parity verification append-tolerant - #753

Merged
proerror77 merged 3 commits into
mainfrom
codex/pm-parity-high-rate-tapes-747
Aug 8, 2026
Merged

proerror77 merged 3 commits into
mainfrom
codex/pm-parity-high-rate-tapes-747

Conversation

@proerror77

Copy link
Copy Markdown
Owner

Change contract

Make the Polymarket shadow parity validator able to verify high-rate tapes: the validator's read model was "read the entire spool twice and require the world not to move" while the gate contract keeps the baseline lane collecting, so on high-rate tapes the stable-read race exhausted the retry budget and the verifier bailed with spool changed while reading parity window, failing the gate closed with no parity evidence (operational block, not a correctness finding). The fix changes what is read and how stability is judged:

  • Append-tolerant stability. Tapes are append-only, so growth is safe: TapeSnapshot captures (device, inode, size) at pass start, the read is capped at the snapshot size, and afterwards only identity (same device/inode, no shrink) is re-verified. An in-flight partial final row is ignored on the live active tape but stays fail-closed on closed tapes. Truncation, replacement, rename, and symlink indirection keep failing/ retrying exactly as before.
  • Window-scoped reads. A rotated tape's name stamp is its rotation wall time, so every row in it predates the stamp. Closed segments rotated before started_at - TAPE_WINDOW_LOOKBACK_SECONDS (1h) cannot contain comparison rows — trades and settlements are admitted only near the window, and metadata enters the projection at most 900 s before the window start while collector discovery only fetches markets ending within 30 minutes of retrieval — so they are never parsed. Read cost now tracks the comparison window, not spool retention.

Analysis and acceptance criteria: docs/reports/2026-08-08-polymarket-parity-high-rate-tapes-known-issue.md (items 1 and 2 of the proposed fix direction; items 3 and 4 — relaxed post-cutoff schema validity and bounded-memory streaming comparison — are deliberately left out as separate shippable behavior).

Issue relationship

Refs #747

Out of scope

  • Gate recover logic (owned by a separate follow-up) and all gate-control scripts/policies: deployment/aliyun/polymarket-shadow-gate-policy.jq predicates are untouched and the monday.polymarket_shadow_parity.v1 evidence schema is unchanged.
  • Collector write paths (polymarket_raw.rs); no runtime or host mutation.
  • Bounded-memory streaming comparison (doc item 4) — degrades, does not break; can ship independently.

Dependencies and merge order

None. Branched from origin/main b02c1ddf; written after #743 (7b8a61a6, Polymarket trade-row dedup) and verified orthogonal to it — that change is collector-internal poll dedup and does not alter tape format or validator semantics.

Focused validation

From rust_hft/: cargo test -p hft-collector --locked — 311 lib + 72 bin + integration tests, 0 failed. cargo clippy -p hft-collector --locked --all-targets — no lints (one pre-existing workspace-level sqlx patch notice, unrelated).

New tests in polymarket_parity.rs, each shown red against the pre-fix logic where applicable:

  • concurrent_appends_to_the_live_legacy_tape_do_not_block_parity — a writer appends valid rows to the live legacy active tape at ≥100 rows/s while compare() runs over a 50k-row in-lookback segment; verification succeeds within the existing 5-attempt budget with passing evidence. Red on old code with the production failure mode (spool changed while reading parity window / enumeration variants).
  • closed_segments_outside_the_window_lookback_are_never_parsed — a retained segment rotated long before the window contains unparseable garbage; a passing comparison deterministically proves it is never read (any read is a hard error).
  • appends_after_the_snapshot_are_excluded_not_retried — mid-pass growth under the same identity neither aborts nor is read by the pass (red on old code: fingerprint mismatch retry).
  • Fail-closed regressions: mid_read_truncation_is_retried_instead_of_compared, replaced_tape_identity_between_passes_fails_closed, a_partial_trailing_row_on_a_closed_tape_fails_closed, symlinked_tape_still_fails_closed; sequence gaps, in-window schema violations, and duplicate record_id remain covered by the unchanged existing tests (out_of_window_rows_still_require_sequence_integrity, malformed_active_rust_trade_fails_before_rotation, duplicate_rust_trade_fails_dedupe_parity, …) — all passing.

Counterexample boundary: a same-inode, same-size in-place rewrite with preserved mtime is not detected (as before, mtime equality was the only guard and it is gone); tapes are append-only by collector contract and replacement/rename/truncation are all still caught by device/inode/shrink checks plus directory re-enumeration between passes.

Environment note: .github/scripts/agent-worktree-preflight.sh check currently aborts with SIGPIPE (141) on this repo — git worktree list --porcelain | awk … exit under pipefail with 130+ registered worktrees; its exact checks were replicated manually for this worktree (verdict=ok, base b02c1ddf). Not fixed here (outside this PR's file scope).

Rollout and rollback

None. The verifier runs inside the shadow gate on already-collected evidence; this change only makes previously unattainable evidence producible. Rollback is reverting this single-file commit; no state, schema, or configuration changes.

Scope exception

None (1 file, 291 insertions / 27 deletions).

The shadow parity validator read every tape in both spools twice and
required each tape fingerprint (size and mtime included) to stay
bit-identical across both passes. The gate keeps the baseline lane
collecting by contract, so on high-rate tapes an append or rotation lands
mid-pass with probability approaching 1, the fixed retry budget exhausts,
and the verifier bails with "spool changed while reading parity window",
failing the gate closed with no parity evidence at all.

Tapes are append-only, so treat growth as safe: snapshot (device, inode,
size) at pass start, cap the read at the snapshot size, and afterwards
verify only that identity held and the tape never shrank. An in-flight
partial final row is ignored on the live active tape but stays fail-closed
on closed tapes. Truncation, replacement, rename, and symlink indirection
still fail or retry exactly as before. Closed segments whose rotation
stamp predates started_at - 1h cannot contain comparison rows (trades and
settlements are window-bound, and metadata enters the projection at most
900 s before the window while discovery only fetches markets ending within
30 minutes of retrieval), so they are skipped entirely and read cost now
tracks the comparison window instead of spool retention.

The monday.polymarket_shadow_parity.v1 evidence schema and every gate
predicate are unchanged; fail-closed behavior for sequence gaps, in-window
schema violations, and duplicate record ids is covered by unchanged
existing tests plus new truncation/replacement/symlink regressions.

Refs #747
@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 Aug 8, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

Next review available in: 59 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 @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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 51b90f5c-67a3-42d8-b54c-ccadb30315e6

📥 Commits

Reviewing files that changed from the base of the PR and between d0f9fc9 and b13d2a9.

📒 Files selected for processing (1)
  • rust_hft/tools/collector/src/polymarket_parity.rs

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.

@proerror77
proerror77 enabled auto-merge (squash) August 8, 2026 06:07
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.

1 participant