Skip to content

fix(collector): prove exact Binance stream coverage - #295

Merged
proerror77 merged 1 commit into
mainfrom
codex/cex-l2-static-gate-224
Jul 23, 2026
Merged

proerror77 merged 1 commit into
mainfrom
codex/cex-l2-static-gate-224

Conversation

@proerror77

@proerror77 proerror77 commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Relates to #224.

Change contract: Make the Rust Binance collector prove the exact per-shard LIST_SUBSCRIPTIONS set for depth plus aggTrade before snapshots, persist that proof into every segment, and treat unchanged two-sided books as complete without fabricating a trade or diff while preserving real USD-M bridge state.

Out of scope: Deployment/gate scripts and docs (follow-up layer C), ECS cutover, historical reconstruction, the incomplete 2026-07-20 cohort, snapshot construction, evaluator/MCTS, research logic, and Polymarket collection.

Dependency or merge order: #293 is merged. This is layer B and must merge before the deployment/gate layer C PR. No production cutover is permitted until layer C is merged and a fresh full ECS shadow gate passes. Rollback order is C, then this PR, then #293.

Focused validation:

  • cargo test -p hft-collector (214 passed, 2 ignored library; remaining binaries passed)
  • cargo test -p hft-collector --bin binance-lob-archiver (46 passed)
  • cargo clippy -p hft-collector --lib --bin binance-lob-archiver -- -D warnings
  • Numeric LIST_SUBSCRIPTIONS request/response ID accepted by both Spot and USD-M; string response ID is rejected.
  • One absolute subscription-proof deadline covers WebSocket reads and proof-before archive queue backpressure; ready-frame and full-queue WebSocket counterexamples pass.
  • Combined verifier/runtime counterexamples cover static symbols and the cross-segment USD-M overlap bridge.
  • Read-only specification and standards reviews approved.

Rollout/rollback impact: No deployment configuration or production rollout in this PR. The existing gate cannot promote the new producer evidence until layer C lands, so the intermediate state remains fail closed. Roll back layer C before this producer layer.

PRD note: This is the already-approved collector runtime defect in issue #224; implementation followed focused failing tests, so a separate PRD is unnecessary.

@coderabbitai

coderabbitai Bot commented Jul 23, 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: 9 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4eed42cd-d76d-430b-95be-e24efc0d5f3b

📥 Commits

Reviewing files that changed from the base of the PR and between 33369ac and c74b787.

📒 Files selected for processing (2)
  • rust_hft/tools/collector/src/bin/binance-lob-archiver.rs
  • rust_hft/tools/collector/src/lob_archiver.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cex-l2-static-gate-224

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 force-pushed the codex/cex-l2-static-gate-224 branch from 7988bdb to f718c27 Compare July 23, 2026 21:04
@proerror77
proerror77 changed the base branch from codex/cex-market-tape-verifier-224 to main July 23, 2026 21:04
@proerror77
proerror77 force-pushed the codex/cex-l2-static-gate-224 branch from f718c27 to 2f428e9 Compare July 23, 2026 21:05

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7988bdb8ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.context("websocket connect timed out")??;
websocket
.send(Message::Text(
json!({"method":"LIST_SUBSCRIPTIONS","id":SUBSCRIPTION_PROOF_ID})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Send a protocol-valid subscription proof ID

When either USD-M shard starts, this sends monday-subscription-proof as the request ID, but Binance's USD-M live-subscription protocol defines id as an unsigned integer; the Spot protocol permits integers or alphanumeric strings, but this value also contains hyphens. Binance can therefore reject LIST_SUBSCRIPTIONS, after which no valid result reaches validate_subscription_listing and the collector exits before requesting snapshots, preventing the two-market shadow gate from passing. Use a numeric ID supported by both protocols and match the numeric response.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 2d16f54: the proof ID is now numeric u64 value 1 in both the request and response validator, with a counterexample rejecting string ID "1".

Comment on lines +1338 to +1340
message = tokio::time::timeout(Duration::from_secs(20), websocket.next()) => {
message.context("websocket subscription proof timed out")?
.ok_or_else(|| anyhow::anyhow!("websocket closed before subscription proof"))??

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Bound the subscription proof with one absolute deadline

If the LIST_SUBSCRIPTIONS response is lost or never arrives while ordinary market frames continue, this per-call timeout restarts after every frame and therefore never expires. Those frames also call watchdog.mark_data(), so the watchdog does not recover the session; the shard can remain connected indefinitely while snapshots never start and health never becomes eligible. Apply one deadline to the entire proof loop rather than a fresh timeout around each websocket.next().

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Fixed in 2d16f54: receive_url computes one tokio Instant deadline before the loop and every websocket.next() uses timeout_at against that unchanged deadline. The new subscription_proof_uses_one_absolute_deadline test proves a second ordinary wait cannot reset the budget.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Follow-up: the final fix is stronger than the earlier timeout_at version. It pre-checks the absolute deadline, uses a deadline-first biased select, post-checks after a ready future, and applies that same deadline to proof-before archive queue backpressure. A real local WebSocket counterexample pre-fills the queue, sends a market frame without a LIST response, fails on the old path at the outer 250ms timeout, and now returns the inner subscription-proof timeout at 50ms. The archiver binary suite is 46/46 and clippy -D warnings passes.

@proerror77
proerror77 force-pushed the codex/cex-l2-static-gate-224 branch from 2f428e9 to 2d16f54 Compare July 23, 2026 21:11
@proerror77 proerror77 changed the title fix(collector): gate exact Binance stream coverage fix(collector): prove exact Binance stream coverage Jul 23, 2026
@proerror77
proerror77 force-pushed the codex/cex-l2-static-gate-224 branch from 2d16f54 to c74b787 Compare July 23, 2026 21:24
@proerror77
proerror77 merged commit 6ac5815 into main Jul 23, 2026
19 of 20 checks passed
@proerror77
proerror77 deleted the codex/cex-l2-static-gate-224 branch July 24, 2026 08:44
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