Skip to content

feat(collector): gate USD-M reference shadow - #259

Merged
proerror77 merged 3 commits into
mainfrom
codex/cex-usdm-reference-shadow-gate-222
Jul 23, 2026
Merged

feat(collector): gate USD-M reference shadow#259
proerror77 merged 3 commits into
mainfrom
codex/cex-usdm-reference-shadow-gate-222

Conversation

@proerror77

@proerror77 proerror77 commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Part of #222

Change contract: publish an isolated USD-M reference shadow service and a fail-closed canonical-readback gate bound to an exact candidate, source revision, and dedicated control bundle.

Out of scope: ECS installation or execution, production collector replacement/cutover, collector source/artifact/runtime logic, issues #223/#224, snapshot construction, evaluator/MCTS, and research logic.

Dependency or merge order: depends on merged #257 release packaging. This is issue #222 layer 3B; host evidence generation follows in a separate PR.

Focused validation:

  • bash -n deployment/aliyun/test-binance-usdm-reference-shadow-gate.sh
  • shellcheck deployment/aliyun/test-binance-usdm-reference-shadow-gate.sh
  • bash deployment/aliyun/test-binance-usdm-reference-shadow-gate.sh
  • bash deployment/aliyun/test-binance-usdm-reference-release-contract.sh
  • git diff --check
  • independent spec and standards reviews: no blocker

Rollout/rollback impact: no host mutation. The release artifact gains a dedicated reference control bundle. Rollback is reverting this PR; the existing Polymarket control bundle identity is unchanged.

Summary by CodeRabbit

  • New Features

    • Added a Binance USD-M reference collector shadow service for periodic data collection.
    • Added deployment validation for reference shadow evidence, including coverage, freshness, integrity, health, and artifact consistency checks.
    • Added dedicated packaging and release metadata for Binance USD-M reference control assets.
  • Tests

    • Added automated acceptance and rejection tests for valid and invalid deployment evidence.
    • Added checks ensuring reference and Polymarket control asset bundles remain distinct and correctly recorded.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Binance USD-M reference control-asset packaging, a templated shadow collector service, a jq-based evidence gate policy, and Bash tests covering valid, invalid, and deployment-configuration cases.

Changes

Binance USD-M reference shadow

Layer / File(s) Summary
Reference packaging and collector deployment
.github/workflows/acr-publish.yml, deployment/aliyun/binance-usdm-reference-collector-shadow@.service
The workflow creates reference control manifests and archives, records their SHA256 values, and generates the reference release. The systemd template runs the collector with configured output, timing, resource, and hardening settings.
Reference shadow gate policy
deployment/aliyun/binance-usdm-reference-shadow-gate-policy.jq
The jq policy validates canonical metadata, endpoint coverage, hashes, service identity, artifact ordering, health state, and timing constraints.
Gate evidence and configuration tests
deployment/aliyun/test-binance-usdm-reference-shadow-gate.sh
The test script checks accepted evidence, rejects mutated invalid cases, and verifies required service and workflow configuration.

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

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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.
Title check ✅ Passed It clearly summarizes the main change: gating the USD-M reference shadow.
Description check ✅ Passed It covers the required sections with clear contract, scope, dependency, validation, and rollback details.
✨ Finishing Touches
📝 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-usdm-reference-shadow-gate-222

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: 1d998e979b

ℹ️ 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 on lines +74 to +80
and ([.artifacts[].observed_at_ns] as $times
| $times == ($times | sort)
and ($times | unique | length) == ($times | length)
and ([range(1; $times | length) as $index
| $times[$index] - $times[$index - 1]] as $gaps
| all($gaps[]; . > 0 and . <= 90000000000)
and .max_artifact_gap_ns == ($gaps | max)))

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 Require artifacts to span the claimed gate duration

The policy validates duration_seconds >= 3600 independently from the artifact timestamps, so evidence claiming a one-hour run can pass with only three readbacks collected within seconds. The checked-in positive fixture demonstrates this by claiming 3,600 seconds while its artifacts span only 60 seconds, meaning the production-eligibility gate does not establish continuous canonical output for the required hour. Require the first-to-last artifact span to cover the claimed/minimum duration and add a rejection test for this counterexample.

AGENTS.md reference: AGENTS.md:L93-L96

Useful? React with 👍 / 👎.

Comment on lines +13 to +17
(.active_contracts | type) == "number"
and .active_contracts == (.active_contracts | floor)
and .active_contracts > 0
and .metadata_observations == .active_contracts
and .mark_index_funding_observations == .active_contracts

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 Reject implausibly small USD-M contract universes

Requiring only one active contract lets a partial but syntactically valid exchangeInfo response qualify for production: the collector treats the returned contracts as the expected set, filters premiumIndex to that set, and requests open interest only for those symbols, so even a one-symbol response can produce three artifacts with “complete” coverage and pass this gate. The existing USD-M shadow policy requires at least 400 symbols (rust-lob-shadow-gate-policy.jq lines 70-73); enforce a comparable production floor or a trusted catalog baseline here and add a low-universe rejection test so an incomplete reference dataset cannot be promoted.

AGENTS.md reference: AGENTS.md:L93-L96

Useful? React with 👍 / 👎.

Comment on lines +53 to +56
and .service.unit == ("binance-usdm-reference-collector-shadow@" + $candidate_sha256 + ".service")
and .service.active == true
and .service.restart_count == 0
and .service.binary_sha256 == $candidate_sha256

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 Pin one systemd invocation for the entire gate

The service evidence records only the unit name, current active state, restart counter, and binary digest, so a process replacement during the observation window can still pass using the persistent spool: after a quick replacement, the new candidate process is active with the same digest, while artifacts from before and after it can remain ordered with gaps below 90 seconds. The established collector control plane explicitly treats PID and NRestarts as insufficient and pins InvocationID as well (deployment/aliyun/README.md lines 325-330); capture the initial PID/invocation and require the same identity at completion, with a replacement counterexample test.

AGENTS.md reference: AGENTS.md:L93-L96

Useful? React with 👍 / 👎.

and .observed_at_ns == (.observed_at_ns | floor)
and .observed_at_ns > 0
and (.coverage | complete_coverage)
and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms

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 Pin the canonical readback staleness threshold

The artifact manifest carries max_staleness_ms, but this policy omits it and therefore interprets stale_* == 0 using whatever threshold produced the artifact. The candidate CLI permits values up to 300,000 ms, and the runtime evidence does not validate its arguments, so a modified unit or drop-in can run the expected binary with a five-minute threshold and have five-minute-old rows pass as non-stale even though the shipped service pins 30,000 ms. Include the read-back threshold in each artifact and require exactly 30,000 ms.

AGENTS.md reference: AGENTS.md:L50-L54

Useful? React with 👍 / 👎.

@proerror77

Copy link
Copy Markdown
Owner Author

Addressed all four Codex review P1s in a29ef206:

  • bind artifact timestamp span to duration_seconds
  • require at least 400 active USD-M contracts
  • pin one systemd InvocationID across the gate
  • require max_staleness_ms == 30000 on every canonical artifact

Added a focused counterexample for each condition. Both independent read-only reviewers report no blocker; the local gate test and shellcheck pass.

@proerror77 proerror77 closed this Jul 23, 2026
@proerror77 proerror77 reopened this Jul 23, 2026
@proerror77
proerror77 merged commit 2f59a31 into main Jul 23, 2026
32 of 33 checks passed

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@deployment/aliyun/binance-usdm-reference-shadow-gate-policy.jq`:
- Around line 27-46: Update canonical_artifact to require type == "number" for
all four time_bounds fields—min_source_time_ms, max_source_time_ms,
min_received_at_ns, and max_received_at_ns—before the existing ordering
comparisons. Preserve the current bounds checks and fail-closed behavior for
missing or null time_bounds values.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3ba396cb-8579-4e5f-8e79-39715656e676

📥 Commits

Reviewing files that changed from the base of the PR and between a874b28 and 2bbef95.

📒 Files selected for processing (4)
  • .github/workflows/acr-publish.yml
  • deployment/aliyun/binance-usdm-reference-collector-shadow@.service
  • deployment/aliyun/binance-usdm-reference-shadow-gate-policy.jq
  • deployment/aliyun/test-binance-usdm-reference-shadow-gate.sh

Comment on lines +27 to +46
def canonical_artifact:
.canonical_readback == true
and .venue == "binance_usdm"
and .dataset == "reference"
and .manifest_schema == "binance.usdm_reference_manifest.v1"
and .data_schema == "binance.usdm_reference.v2"
and .source_origin == "https://fapi.binance.com"
and (.source_endpoints | endpoints)
and .max_staleness_ms == 30000
and (.data_sha256 | sha256)
and (.manifest_sha256 | sha256)
and .success_sha256 == .data_sha256
and .content_rows_verified == true
and (.observed_at_ns | type) == "number"
and .observed_at_ns == (.observed_at_ns | floor)
and .observed_at_ns > 0
and (.coverage | complete_coverage)
and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms
and .time_bounds.min_received_at_ns <= .time_bounds.max_received_at_ns
and .time_bounds.max_received_at_ns <= .observed_at_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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Missing/null time_bounds silently passes the ordering checks.

None of the four time_bounds fields (min_source_time_ms, max_source_time_ms, min_received_at_ns, max_received_at_ns) have a type == "number" guard before the <= comparisons at Line 44-46, unlike observed_at_ns, active_contracts, duration_seconds, and artifact_count, which all get explicit numeric-type checks elsewhere in this file.

In jq, comparison operators use a total ordering where null sorts below every other type, and <=/>= never raise a type error (unlike arithmetic -). So if an artifact's time_bounds object (or any of its subfields) is missing, each becomes null, and null <= null and null <= <number> both evaluate to true. An artifact with time_bounds deleted entirely (e.g. del(.artifacts[1].time_bounds)) would therefore still satisfy all three ordering checks and pass canonical_artifact, defeating the fail-closed intent of this gate. No existing reject counterexample in the test script covers this case.

🛡️ Proposed fix: add explicit numeric-type guards
   and (.coverage | complete_coverage)
-  and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms
-  and .time_bounds.min_received_at_ns <= .time_bounds.max_received_at_ns
-  and .time_bounds.max_received_at_ns <= .observed_at_ns;
+  and (.time_bounds.min_source_time_ms | type) == "number"
+  and (.time_bounds.max_source_time_ms | type) == "number"
+  and (.time_bounds.min_received_at_ns | type) == "number"
+  and (.time_bounds.max_received_at_ns | type) == "number"
+  and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms
+  and .time_bounds.min_received_at_ns <= .time_bounds.max_received_at_ns
+  and .time_bounds.max_received_at_ns <= .observed_at_ns;

Would you like me to also draft a reject counterexample (e.g. del(.artifacts[1].time_bounds)) for the test script to cover this case going forward?

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def canonical_artifact:
.canonical_readback == true
and .venue == "binance_usdm"
and .dataset == "reference"
and .manifest_schema == "binance.usdm_reference_manifest.v1"
and .data_schema == "binance.usdm_reference.v2"
and .source_origin == "https://fapi.binance.com"
and (.source_endpoints | endpoints)
and .max_staleness_ms == 30000
and (.data_sha256 | sha256)
and (.manifest_sha256 | sha256)
and .success_sha256 == .data_sha256
and .content_rows_verified == true
and (.observed_at_ns | type) == "number"
and .observed_at_ns == (.observed_at_ns | floor)
and .observed_at_ns > 0
and (.coverage | complete_coverage)
and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms
and .time_bounds.min_received_at_ns <= .time_bounds.max_received_at_ns
and .time_bounds.max_received_at_ns <= .observed_at_ns;
def canonical_artifact:
.canonical_readback == true
and .venue == "binance_usdm"
and .dataset == "reference"
and .manifest_schema == "binance.usdm_reference_manifest.v1"
and .data_schema == "binance.usdm_reference.v2"
and .source_origin == "https://fapi.binance.com"
and (.source_endpoints | endpoints)
and .max_staleness_ms == 30000
and (.data_sha256 | sha256)
and (.manifest_sha256 | sha256)
and .success_sha256 == .data_sha256
and .content_rows_verified == true
and (.observed_at_ns | type) == "number"
and .observed_at_ns == (.observed_at_ns | floor)
and .observed_at_ns > 0
and (.coverage | complete_coverage)
and (.time_bounds.min_source_time_ms | type) == "number"
and (.time_bounds.max_source_time_ms | type) == "number"
and (.time_bounds.min_received_at_ns | type) == "number"
and (.time_bounds.max_received_at_ns | type) == "number"
and .time_bounds.min_source_time_ms <= .time_bounds.max_source_time_ms
and .time_bounds.min_received_at_ns <= .time_bounds.max_received_at_ns
and .time_bounds.max_received_at_ns <= .observed_at_ns;
🤖 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 `@deployment/aliyun/binance-usdm-reference-shadow-gate-policy.jq` around lines
27 - 46, Update canonical_artifact to require type == "number" for all four
time_bounds fields—min_source_time_ms, max_source_time_ms, min_received_at_ns,
and max_received_at_ns—before the existing ordering comparisons. Preserve the
current bounds checks and fail-closed behavior for missing or null time_bounds
values.

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