Skip to content

feat(research): define evidence-bound CEX snapshot V2 - #781

Merged
proerror77 merged 10 commits into
mainfrom
codex/cex-research-contract-v2
Aug 9, 2026
Merged

proerror77 merged 10 commits into
mainfrom
codex/cex-research-contract-v2

Conversation

@proerror77

@proerror77 proerror77 commented Aug 9, 2026

Copy link
Copy Markdown
Owner

Change contract

Define the CEX ResearchSnapshot V2 contract with independently timed funding/OI evidence, authenticated data/manifest/_SUCCESS digests, point-in-time rule and fee validity, and verified order-lifecycle latency cost. Retain V1 only for immutable read-only decoding and reserve a new outer materialization schema.

Issue relationship

Refs #773

Out of scope

Materialization, evaluation consumption, production jobs, and live trading activation are separate rollout units.

Dependencies and merge order

None

Focused validation

  • cargo test -p hft-research-manifest --locked (10 passed)
  • Counterexample: a stale open-interest tail is rejected independently of funding coverage.
  • V1 has validation/read types but no writer constructor; V2 is the only new writer contract.

Rollout and rollback

Contract-only; no runtime mutation. Revert this PR before adding V2 producers if review rejects the schema.

Scope exception

None

Summary by CodeRabbit

  • New Features

    • Added CEX replay schema V2 support for research snapshots and dataset manifests.
    • Added metadata for instruments, fees, funding, open interest, derivatives references, latency costs, and artifact evidence.
    • Added integrity checks using digest-bound manifests and snapshot validation.
    • Preserved support for reading historical V1 snapshot and dataset formats.
  • Bug Fixes

    • Added validation to reject invalid symbols, incomplete source coverage, invalid fees, missing derivatives evidence, incorrect point-in-time data, and inconsistent latency-cost information.

@coderabbitai

coderabbitai Bot commented Aug 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 39 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: 009ead17-49de-4d5a-a8c1-c30eaef65b07

📥 Commits

Reviewing files that changed from the base of the PR and between 2b6f560 and d4421bd.

📒 Files selected for processing (1)
  • rust_hft/research-core/manifest/src/lib.rs
📝 Walkthrough

Walkthrough

The manifest package adds CEX replay schema V2 types, evidence metadata, validation, and digest-bound dataset manifests. V1 types remain available for historical decoding. Worktree metadata and dependencies now target the research manifest package.

Changes

CEX replay manifest contract

Layer / File(s) Summary
V2 schema and evidence contract
agent-worktree.yml, rust_hft/research-core/manifest/Cargo.toml, rust_hft/research-core/manifest/src/lib.rs
The worktree targets the CEX research contract. The manifest adds V2 constants, evidence structures, metadata types, and decimal support. V1 remains available for historical read-only decoding.
Snapshot validation and shared helpers
rust_hft/research-core/manifest/src/lib.rs
CexReplaySnapshotV2 validates metadata, modalities, source coverage, PIT rules, fees, derivatives evidence, latency costs, and artifact triplets. Shared helpers also support V1 validation and hashing.
Dataset manifests and validation coverage
rust_hft/research-core/manifest/src/lib.rs
CexReplayDatasetManifestV2 binds snapshot digests and validates evidence, symbols, decimal ordering, and equality. Fixtures and tests cover valid V2 data and invalid evidence cases.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

  • proerror77/monday issue 773 — Directly covers the CEX PIT ResearchSnapshot V2 schema, evidence, modalities, fees, latency, and digest-bound validation implemented here.

Possibly related PRs

  • proerror77/monday#406 — Introduced the replay manifest types and validation that this PR evolves from V1 to V2.
  • proerror77/monday#661 — Related replay-manifest and artifact-evidence contracts support the V2 materializer output.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: defining an evidence-bound CEX snapshot V2 contract.
Description check ✅ Passed The description includes all required sections and provides the contract, issue reference, scope, validation, rollout, and rollback details.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/cex-research-contract-v2

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.

@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: 033d21ca8a

ℹ️ 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".

Comment thread rust_hft/research-core/manifest/src/lib.rs Outdated
Comment thread rust_hft/research-core/manifest/src/lib.rs Outdated
Comment thread rust_hft/research-core/manifest/src/lib.rs Outdated
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head e5f335e

@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: e5f335e918

ℹ️ 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".

Comment thread rust_hft/research-core/manifest/src/lib.rs
Comment thread rust_hft/research-core/manifest/src/lib.rs Outdated
Comment thread rust_hft/research-core/manifest/src/lib.rs
Comment thread rust_hft/research-core/manifest/src/lib.rs
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head c06145724a9d8d5b4e409e5e565824daf9510aa8

@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head c061457 (corrected full SHA)

@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head e85ad31

@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: e85ad31634

ℹ️ 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".

Comment thread rust_hft/research-core/manifest/src/lib.rs
Comment thread rust_hft/research-core/manifest/src/lib.rs
Comment thread rust_hft/research-core/manifest/src/lib.rs
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head 2b6f560

@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 (5)
rust_hft/research-core/manifest/src/lib.rs (5)

559-561: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Make equal_decimals fail closed on unparseable input.

left.parse().ok() == right.parse().ok() returns true when both strings fail to parse, because None == None. The only caller at line 286 is protected, because ordered_nonnegative_decimals at line 279 already rejects unparseable values and the || chain returns first. The helper is therefore safe today. Make the helper self-contained so a future caller cannot inherit the trap.

♻️ Proposed fix
 fn equal_decimals(left: &str, right: &str) -> bool {
-    left.parse::<Decimal>().ok() == right.parse::<Decimal>().ok()
+    matches!(
+        (left.parse::<Decimal>(), right.parse::<Decimal>()),
+        (Ok(left), Ok(right)) if left == right
+    )
 }
🤖 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 `@rust_hft/research-core/manifest/src/lib.rs` around lines 559 - 561, Update
equal_decimals to return true only when both inputs parse successfully and their
Decimal values are equal; ensure any unparseable input returns false instead of
allowing None == None.

326-344: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a parameter struct for validate_snapshot_core.

The function takes 15 positional parameters, and six of them are &str. A caller can transpose venue, instrument_type, symbol, or replay_clock without a compile error. Both current call sites are correct, so this is a future-proofing suggestion. Group the shared fields into a SnapshotCoreView<'_> borrow struct and pass one argument. The #[allow(clippy::too_many_arguments)] attribute then becomes unnecessary.

🤖 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 `@rust_hft/research-core/manifest/src/lib.rs` around lines 326 - 344, Introduce
a borrowed `SnapshotCoreView<'_>` struct containing the shared validation fields
currently passed to `validate_snapshot_core`, update both call sites to
construct and pass that view, and change `validate_snapshot_core` to accept it
alongside the remaining distinct arguments. Remove the now-unnecessary
`#[allow(clippy::too_many_arguments)]` attribute while preserving validation
behavior and field mappings.

1026-1036: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add tests for the spot derivatives branch.

The fixture is usdm only, so the match arms at lines 256-269 are partly unexercised. Three cases have no test:

  • spot with derivatives_reference: None must validate. This is the accepting arm at line 267.
  • spot with derivatives_reference: Some(..) must be rejected.
  • usdm with derivatives_reference: None must be rejected.

The same gap applies to the required-modality set at lines 203-210, because no test proves that a spot snapshot must omit funding and open_interest. The instrument-dependent behaviour is the central new rule in this contract, so it needs direct coverage.

Do you want me to generate these tests?

🤖 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 `@rust_hft/research-core/manifest/src/lib.rs` around lines 1026 - 1036, Add
direct validation tests for the instrument-dependent derivatives rules in the
existing manifest test module: cover spot snapshots with derivatives_reference
None as valid, spot with Some(..) as invalid, and usdm with None as invalid.
Also assert the required-modality behavior for spot by verifying it rejects
snapshots containing funding or open_interest, reusing the existing snapshot
fixtures and ManifestError expectations.

114-123: 🗄️ Data Integrity & Integration | 🔵 Trivial | 💤 Low value

Document the canonical decimal string requirement.

The decimal fields are String and enter the snapshot digest verbatim. equal_decimals treats "0.10" and "0.1" as equal, but sha256() produces two different manifest_id values for them. Writers must therefore emit a canonical decimal form to keep dataset identity stable. Add a doc comment on these fields that states the canonicalization requirement.

Also applies to: 153-153, 168-170

🤖 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 `@rust_hft/research-core/manifest/src/lib.rs` around lines 114 - 123, Add a
Rust doc comment to the decimal string fields in CexInstrumentRulesV2 and the
corresponding fields at the referenced locations, stating that writers must emit
canonical decimal representations because values are included verbatim in
snapshot digests. Ensure the guidance covers tick_size, step_size, min_notional,
and any matching decimal fields without changing their types or behavior.

237-292: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Split the fused validation conditions to report the failing field.

Lines 237-255 fuse 14 predicates into one error, "PIT rules or fee evidence is invalid". Lines 270-292 fuse 11 predicates into "measured latency cost evidence is invalid". A rejected snapshot therefore does not identify which bound failed. For a fail-closed contract, an operator must inspect the code to diagnose a rejection.

Extract per-group helpers that return distinct error strings, for example "instrument rules are invalid", "fee account binding is invalid", "fee validity window is too short", and "latency percentiles are nonmonotonic". The existing tests already assert on the coarse strings, so update them together with the split.

🤖 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 `@rust_hft/research-core/manifest/src/lib.rs` around lines 237 - 292, Split the
fused validation in the snapshot validation method into focused per-group checks
or helpers that return field-specific error messages, covering instrument rules,
fee account binding and validity bounds, derivatives reference, and latency
evidence (including percentile monotonicity). Preserve fail-closed behavior and
update existing tests to assert the new distinct error strings instead of the
coarse messages.
🤖 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 `@rust_hft/research-core/manifest/src/lib.rs`:
- Around line 559-561: Update equal_decimals to return true only when both
inputs parse successfully and their Decimal values are equal; ensure any
unparseable input returns false instead of allowing None == None.
- Around line 326-344: Introduce a borrowed `SnapshotCoreView<'_>` struct
containing the shared validation fields currently passed to
`validate_snapshot_core`, update both call sites to construct and pass that
view, and change `validate_snapshot_core` to accept it alongside the remaining
distinct arguments. Remove the now-unnecessary
`#[allow(clippy::too_many_arguments)]` attribute while preserving validation
behavior and field mappings.
- Around line 1026-1036: Add direct validation tests for the
instrument-dependent derivatives rules in the existing manifest test module:
cover spot snapshots with derivatives_reference None as valid, spot with
Some(..) as invalid, and usdm with None as invalid. Also assert the
required-modality behavior for spot by verifying it rejects snapshots containing
funding or open_interest, reusing the existing snapshot fixtures and
ManifestError expectations.
- Around line 114-123: Add a Rust doc comment to the decimal string fields in
CexInstrumentRulesV2 and the corresponding fields at the referenced locations,
stating that writers must emit canonical decimal representations because values
are included verbatim in snapshot digests. Ensure the guidance covers tick_size,
step_size, min_notional, and any matching decimal fields without changing their
types or behavior.
- Around line 237-292: Split the fused validation in the snapshot validation
method into focused per-group checks or helpers that return field-specific error
messages, covering instrument rules, fee account binding and validity bounds,
derivatives reference, and latency evidence (including percentile monotonicity).
Preserve fail-closed behavior and update existing tests to assert the new
distinct error strings instead of the coarse messages.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0227dcde-9343-4d1a-ba65-044a9d2811ce

📥 Commits

Reviewing files that changed from the base of the PR and between c1a2b93 and 2b6f560.

⛔ Files ignored due to path filters (1)
  • rust_hft/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • agent-worktree.yml
  • rust_hft/research-core/manifest/Cargo.toml
  • rust_hft/research-core/manifest/src/lib.rs

@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: 2b6f5600d2

ℹ️ 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".

Comment thread rust_hft/research-core/manifest/src/lib.rs Outdated
Comment thread rust_hft/research-core/manifest/src/lib.rs
@proerror77
proerror77 enabled auto-merge (squash) August 9, 2026 19:40
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review exact head d4421bd

@proerror77
proerror77 merged commit a15880c into main Aug 9, 2026
54 checks passed
@proerror77
proerror77 deleted the codex/cex-research-contract-v2 branch August 9, 2026 19:56

@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: d4421bd21b

ℹ️ 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".

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CexFeeScheduleV2 {
pub account_fingerprint: String,

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 Bind fee evidence to venue, market, and symbol

When one account has fee artifacts for multiple symbols or both spot and USDM, this contract accepts the wrong artifact because CexFeeScheduleV2 retains only the account fingerprint and validation never compares the other identities. The canonical artifact records venue, market, and symbol in tools/collector/src/binance_fee_artifact.rs:27-32; fresh evidence at exact head is that latency evidence now binds all three identities while fee evidence remains unscoped. Preserve these identities in the fee schedule and require them to match the snapshot before admission.

AGENTS.md reference: AGENTS.md:L67-L68

Useful? React with 👍 / 👎.

Comment on lines +407 to +408
if first_event_ns < source_segments[0].start_received_at_ns
|| last_event_ns > final_segment_end_ns

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 Require event bounds to fall inside source segments

When two authenticated segments cover [0,1] and [10,20], a V2 snapshot can claim first_event_time=5 and last_event_time=6 and still pass because these checks compare only against the outermost start and end. Both purported feature events are then inside an unauthenticated gap, so the snapshot fabricates source coverage; require each event boundary to be contained in an actual segment rather than merely inside the aggregate envelope.

AGENTS.md reference: AGENTS.md:L65-L66

Useful? React with 👍 / 👎.

Comment on lines +530 to +533
&& evidence
.iter()
.enumerate()
.all(|(index, item)| !evidence[..index].contains(item))

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 Use a set for duplicate evidence detection

When a funding or open-interest snapshot spans a normal long research window, observations == evidence.len() forces thousands of triplets, while scanning every preceding prefix makes validation quadratic. For example, covering 30 days under the 90-second maximum gap requires about 28,800 entries and roughly 415 million equality checks per series; insert identities into a BTreeSet while iterating so duplicate rejection remains practical.

Useful? React with 👍 / 👎.

self.snapshot.validate()?;
if self.dataset_kind != CEX_REPLAY_DATASET_KIND
|| self.schema_version != CEX_REPLAY_DATASET_SCHEMA_V2
|| self.feature_manifest_id.trim().is_empty()

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 Bind the feature manifest ID to the snapshot artifact

When feature_manifest_id is mistyped or points to another feature manifest, V2 accepts it as long as it is nonblank even though the canonical feature writer derives the ID as dataset-{artifact_sha256} in tools/collector/src/feature_matrix.rs:135-137. Two otherwise identical admissions can therefore carry different feature lineage while receiving the same snapshot-derived manifest_id, causing an immutable registry identity collision; require this field to equal the ID derived from snapshot.feature_artifact_sha256.

AGENTS.md reference: AGENTS.md:L67-L68

Useful? React with 👍 / 👎.

Comment thread agent-worktree.yml
worktree: /Users/proerror/Documents/monday/.worktrees/codex/binance-fee-snapshot-v2
branch: codex/binance-fee-snapshot-v2
base_sha: 32e01918a88355f0708bbacd9ae6d4d5eb32aa13
contract: cex-research-contract-v2

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 Split this change at the repository size limit

This change contains 772 non-generated changed lines (682 additions and 90 deletions), exceeding the repository's 750-line split threshold, while the commit declares no atomic exception or named reviewer approval. Split the contract into independently testable rollout units or record the required approved exception before merging.

AGENTS.md reference: AGENTS.md:L79-L80

Useful? React with 👍 / 👎.

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