feat(polymarket-release): extend the shadow gate observation to 3600 seconds - #757
Conversation
…seconds Since #680 the collector emits trades only after settlement plus the 1800-second finalization lag plus stable polls, so a 900-second observation always produced an empty shadow trade set and the gate's trade coverage parity could never pass (issue #756). Extend the production gate duration to 3600 seconds, matching the bybit and usdm reference gates, so markets closing early in the observation finalize before the parity cutoff. Policy keeps the one-second rounding tolerance (3600-3601) and the 601-second parity tail.
…second gate The health-age boundary acceptance case and the runtime budget assertion encoded the 900-second duration; update the elapsed spans and the computed budget (1200+3600+5520=10320) to the new observation length.
📝 WalkthroughWalkthroughThe production Polymarket shadow gate now runs for 3600 seconds. The parity collector accepts a configurable trade maturity lag, with production and test defaults. Control-plane fixtures and validations use the updated timing values. ChangesPolymarket gate timing and parity
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant VerifyShadowParity
participant ShadowParityConfig
participant ParityEvidence
VerifyShadowParity->>ShadowParityConfig: resolve trade_maturity_lag_seconds
ShadowParityConfig->>ParityEvidence: calculate event windows
ParityEvidence-->>VerifyShadowParity: return configured lag in evidence
Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
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/polymarket-raw-ops-shadow-gate.sh`:
- Line 93: The gate’s duration limits are inconsistent between gate_seconds and
the artifact’s duration_seconds. Align the contract by either allowing
MONDAY_POLYMARKET_GATE_SECONDS=3601 in the gate validation or restricting
deployment/aliyun/polymarket-shadow-gate-policy.jq to a maximum of 3600, while
keeping both values synchronized.
🪄 Autofix
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: f1bf3e7f-4b2f-4735-b0cc-73c67996ad0e
📒 Files selected for processing (3)
deployment/aliyun/polymarket-raw-ops-shadow-gate.shdeployment/aliyun/polymarket-shadow-gate-policy.jqdeployment/aliyun/test-polymarket-raw-ops-control-plane.sh
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5c6f779239
ℹ️ 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".
…e window Address the review on the original change: lengthening only the gate observation still cannot make exact trade parity attainable, because verify-shadow-parity retained legacy trades through cutoff-600 while the collector emits trades only after settlement plus the 1800-second finalization lag plus three stable polls (~2100 seconds after close). Any 5/15-minute market closing inside (cutoff-1800, cutoff-600] leaves legacy-only trades in the window. The trade maturity lag becomes 2400 seconds (finalization 1800 + market window 900 with poll/settlement margin) and moves from a hard-coded constant into ShadowParityConfig, sourced from DEFAULT_TRADE_MATURITY_LAG_SECONDS (2400 in production, 600 in unit fixtures). verify-shadow-parity gains an optional --trade-maturity-lag-seconds flag so mechanism tests keep their small fixture epochs; the production gate never passes it, and the gate policy pins metrics.trade_maturity_lag_seconds == 2400 plus the derived window bindings. Also re-span the affected control-plane fixtures: health-age boundary cases to 3600 elapsed seconds with parity windows wider than the new lag, the baseline health completion chain past the parity window end, the delayed post-cutoff trade row past the new cutoff, the main gate fixture's parity window end to 3000, and the stale-health fixture's completion to 01:46:41 so its 2701-second age check stays the discriminating predicate.
|
Review follow-ups, all addressed in 7043ba0: P1 (parity window vs deferred trade emission) — accepted, fixed. Verified against the verifier: P2 (stale-health fixture elapsed) — fixed. The 2701-second stale fixture now completes at 01:46:41 (3600s elapsed), so rejection is attributable to the health-age predicate again. The sibling acceptance case was re-spanned the same way, and the baseline health completion chain now extends past the parity window end, which the policy requires. CodeRabbit (3600 vs 3601 tolerance) — intentional, no change. |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
deployment/aliyun/test-polymarket-raw-ops-control-plane.sh (1)
3542-3566: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winPass the updated trade-maturity contract through this fixture.
The policy requires
metrics.trade_maturity_lag_seconds == 2400,metrics.trade_event_window_ended_at_unix == parity_window_ended_at_unix - trade_maturity_lag_seconds, andsettlement_maturity_lag_seconds == 600, but the main fixture runs parity withended-at-unix 3000and no maturity lag flags while the gate JSON only extends metrics for OSS readback and set checks. Update theverify-shadow-paritycall and derived metrics sotrade_event_window_ended_at_unixmatches the 3000-second cutoff minus the new trade lag.🤖 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/test-polymarket-raw-ops-control-plane.sh` around lines 3542 - 3566, Update the fixture’s verify-shadow-parity invocation to pass the trade-maturity and settlement-maturity lag settings, including trade_maturity_lag_seconds=2400 and settlement_maturity_lag_seconds=600. Extend the derived metrics in the associated gate JSON so metrics.trade_maturity_lag_seconds is 2400 and metrics.trade_event_window_ended_at_unix is 600, matching parity_window_ended_at_unix 3000 minus the trade lag; preserve the existing cutoff and fixture values.
🤖 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 `@rust_hft/tools/collector/src/polymarket_parity.rs`:
- Line 93: The trade_maturity_lag_seconds configuration must accept only valid
positive values smaller than the market duration. Update polymarket_parity.rs:93
and the validation or maturity-window logic at polymarket_parity.rs:1026-1029 to
reject values <= 0 or values at least ended_at_unix - started_at_unix before
computing the window; update the corresponding configuration and validation
sites in rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs:127-128 and
:330-333 to enforce the same constraint.
- Around line 37-50: Use a single 2400-second DEFAULT_TRADE_MATURITY_LAG_SECONDS
contract in polymarket_parity.rs by removing the test-only 600-second
definition. Update the fixed fixture at polymarket_parity.rs:1539 to use the
production value and adjust its mocked epoch timestamps so the 2400-second
comparison window remains valid. The deployment sites
deployment/aliyun/test-polymarket-raw-ops-control-plane.sh:3409, :3430, :3452,
and :3473 require no direct changes because their obsolete 600-second overrides
are already absent.
---
Outside diff comments:
In `@deployment/aliyun/test-polymarket-raw-ops-control-plane.sh`:
- Around line 3542-3566: Update the fixture’s verify-shadow-parity invocation to
pass the trade-maturity and settlement-maturity lag settings, including
trade_maturity_lag_seconds=2400 and settlement_maturity_lag_seconds=600. Extend
the derived metrics in the associated gate JSON so
metrics.trade_maturity_lag_seconds is 2400 and
metrics.trade_event_window_ended_at_unix is 600, matching
parity_window_ended_at_unix 3000 minus the trade lag; preserve the existing
cutoff and fixture values.
🪄 Autofix
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: cc0e2a85-00f8-4397-9d97-6e1dfb6e0d12
📒 Files selected for processing (4)
deployment/aliyun/polymarket-shadow-gate-policy.jqdeployment/aliyun/test-polymarket-raw-ops-control-plane.shrust_hft/tools/collector/src/bin/polymarket-raw-ops.rsrust_hft/tools/collector/src/polymarket_parity.rs
| // The comparison window for trades must end early enough that every market | ||
| // contributing a window trade can complete the collector's deferred trade | ||
| // emission before the parity read: settlement availability (~60s) plus the | ||
| // 1800-second finalization lag plus three stable polls (~160s), i.e. about | ||
| // 2100 seconds after close, with margin. 600 seconds was calibrated for the | ||
| // pre-#680 continuous-emission lane and made exact trade parity unreachable | ||
| // for finalization-based collectors (issue #756). This is the default bound | ||
| // into ShadowParityConfig; production callers must not override it, while | ||
| // unit fixtures pass the legacy 600-second value so their small epoch scales | ||
| // stay valid. | ||
| #[cfg(not(test))] | ||
| pub const DEFAULT_TRADE_MATURITY_LAG_SECONDS: i64 = 2400; | ||
| #[cfg(test)] | ||
| pub const DEFAULT_TRADE_MATURITY_LAG_SECONDS: i64 = 600; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Repository files of interest:\n'
git ls-files | rg 'rust_hft/tools/collector/src/polymarket_parity.rs|deployment/aliyun/test-polymarket-raw-ops-control-plane.sh|rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs|deployment/aliyun/polymarket-shadow-gate-policy.jq' || true
printf '\nConst definitions/usages in polymarket_parity.rs:\n'
rg -n "DEFAULT_TRADE_MATURITY_LAG_SECONDS|trade_maturity_lag_seconds|trade maturity|ShadowParityConfig" rust_hft/tools/collector/src/polymarket_parity.rs
printf '\nRelevant source slices:\n'
sed -n '1,180p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\n---\n'
sed -n '1000,1045p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\n---\n'
sed -n '1200,1260p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\n---\n'
sed -n '1520,1550p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\nCLI raw-ops relevant slice(s):\n'
sed -n '110,140p' rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
sed -n '315,345p' rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
printf '\nDeployment overrides count/context:\n'
nl -ba deployment/aliyun/test-polymarket-raw-ops-control-plane.sh | sed -n '3395,3480p'
rg -n -- "--trade-maturity-lag-seconds" deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
printf '\nPolicy jq snippet references:\n'
rg -n "trade-maturity|v1|required|metric" deployment/aliyun/polymarket-shadow-gate-policy.jq | head -80Repository: proerror77/monday
Length of output: 16698
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'deployment/aliyun/test-polymarket-raw-ops-control-plane.sh overrides/context:\n'
awk '
/^ --trade-maturity-lag-seconds / {
start=NR-8; end=NR+8
for(i=start;i<=end;i++) printf "%4d: %s\n", i, lines[i]
}
{
for(j=$1;j<=c;j++) if(NR==j) lines[j]=$0
lines[NR]=$0; c=NR
}
' deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
printf '\nrust_hft/tools/collector/src/bin/polymarket-raw-ops.rs option/default slice:\n'
sed -n '320,342p' rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
printf '\nTest assertions around legacy/test lag contract:\n'
sed -n '1955,1985p' rust_hft/tools/collector/src/polymarket_parity.rs
sed -n '1012,1035p' rust_hft/tools/collector/src/polymarket_parity.rs
sed -n '1024,1032p' rust_hft/tools/collector/src/polymarket_parity.rsRepository: proerror77/monday
Length of output: 5434
Use one trade maturity lag contract across production and fixtures. The test-only default still keeps the obsolete 600-second behavior while the production default uses 2400 seconds.
rust_hft/tools/collector/src/polymarket_parity.rs: remove thecfg(test)600-second default.rust_hft/tools/collector/src/polymarket_parity.rs: configure the fixed fixture with the production value and adjust its mocked epoch timestamps so the 2400-second window remains valid.
The deployment script no longer contains the documented --trade-maturity-lag-seconds 600 overrides, so the deployment fix is not needed.
📍 Affects 2 files
rust_hft/tools/collector/src/polymarket_parity.rs#L37-L50(this comment)rust_hft/tools/collector/src/polymarket_parity.rs#L1539-L1539deployment/aliyun/test-polymarket-raw-ops-control-plane.sh#L3409-L3409deployment/aliyun/test-polymarket-raw-ops-control-plane.sh#L3430-L3430deployment/aliyun/test-polymarket-raw-ops-control-plane.sh#L3452-L3452deployment/aliyun/test-polymarket-raw-ops-control-plane.sh#L3473-L3473
🤖 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/tools/collector/src/polymarket_parity.rs` around lines 37 - 50, Use
a single 2400-second DEFAULT_TRADE_MATURITY_LAG_SECONDS contract in
polymarket_parity.rs by removing the test-only 600-second definition. Update the
fixed fixture at polymarket_parity.rs:1539 to use the production value and
adjust its mocked epoch timestamps so the 2400-second comparison window remains
valid. The deployment sites
deployment/aliyun/test-polymarket-raw-ops-control-plane.sh:3409, :3430, :3452,
and :3473 require no direct changes because their obsolete 600-second overrides
are already absent.
Source: Coding guidelines
| pub ended_at_unix: i64, | ||
| pub output: PathBuf, | ||
| pub allow_empty_legacy: bool, | ||
| pub trade_maturity_lag_seconds: i64, |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Files:\n'
git ls-files | rg 'rust_hft/tools/collector/src/(polymarket_parity|bin/polymarket-raw-ops)\.rs' || true
printf '\npolymarket_parity outline:\n'
ast-grep outline rust_hft/tools/collector/src/polymarket_parity.rs --view expanded | sed -n '1,220p' || true
printf '\npolymarket_parity relevant sections:\n'
sed -n '70,110p;980,1040p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\npolymarket-raw-ops relevant sections:\n'
sed -n '110,140p;312,345p' rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
printf '\nSearch for trade_maturity_lag_seconds usages:\n'
rg -n "trade_maturity_lag_seconds|DEFAULT_TRADE_MATURITY_LAG_SECONDS|nonnegative_epoch_sub" rust_hft/tools/collector src rust_hft || true
printf '\nSearch config validation patterns in collector:\n'
rg -n "nonnegative|positive|reject|valid|clamp|unwrap_or|DEFAULT_" rust_hft/tools/collector/src -S | sed -n '1,220p'Repository: proerror77/monday
Length of output: 43936
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'polymarket_parity compare section and helper test behavior:\n'
sed -n '668,1035p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\nStatic verifier for trade_maturity_lag_SECONDS validation path:\n'
python3 - <<'PY'
from pathlib import Path
p = Path('rust_hft/tools/collector/src/polymarket_parity.rs')
s = p.read_text()
checks = {
'cfg_has_i64_field': 'pub trade_maturity_lag_seconds: i64' in s,
'nonnegative_helper_exists': 'fn nonnegative_epoch_sub(epoch: i64, seconds: i64) -> i64' in s,
'compare_rejects_trade_window_end_before_started': 'if trade_event_window_end <= config.started_at_unix' in s,
'compare_constructs_trade_window_after_boundary_check': 'let trade_event_window_end = nonnegative_epoch_sub(\n config.ended_at_unix,\n config.trade_maturity_lag_seconds,\n )' in s,
}
ops = Path('rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs').read_text()
ops_checks = {
'cli_option_is_i64': 'trade_maturity_lag_seconds: Option<i64>' in ops,
'default_passed_through_unvalidated': 'let trade_maturity_lag_seconds = trade_maturity_lag_seconds\n .unwrap_or(DEFAULT_TRADE_MATURITY_LAG_SECONDS);\n let config = ShadowParityConfig' in ops,
}
for name, ok in {**checks, **ops_checks}.items():
print(f'{name}: {ok}')
PYRepository: proerror77/monday
Length of output: 13954
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'polymarket_parity compare section and helper test behavior:\n'to_json
sed -n '668,1035p' rust_hft/tools/collector/src/polymarket_parity.rs
printf '\nStatic verifier for trade_maturity_lag_SECONDS validation path:\n'
python3 - <<'PY'
from pathlib import Path
p = Path('rust_hft/tools/collector/src/polymarket_parity.rs')
s = p.read_text()
checks = {
'cfg_has_i64_field': 'pub trade_maturity_lag_seconds: i64' in s,
'nonnegative_helper_exists': 'fn nonnegative_epoch_sub(epoch: i64, seconds: i64) -> i64' in s,
'compare_rejects_trade_window_end_before_started': 'if trade_event_window_end <= config.started_at_unix' in s,
'compare_constructs_trade_window_after_boundary_check': 'let trade_event_window_end = nonnegative_epoch_sub(\n config.ended_at_unix,\n config.trade_maturity_lag_seconds,\n )' in s,
}
ops = Path('rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs').read_text()
ops_checks = {
'cli_option_is_i64': 'trade_maturity_lag_seconds: Option<i64>' in ops,
'default_passed_through_unvalidated': 'let trade_maturity_lag_seconds = trade_maturity lag_seconds\n .unwrap_or(DEFAULT_TRADE_MATURITY_LAG_SECONDS);\n let config = ShadowParityConfig' in ops,
}
for name, ok in {**checks, **ops_checks}.items():
print(f'{name}: {ok}')
PYRepository: proerror77/monday
Length of output: 13962
Restrict trade_maturity_lag_seconds to positive seconds. nonnegative_epoch_sub() clamps zero or negative values so trade_event_window_end uses ended_at_unix, letting trades from the entire window pass unless they also fail the later start-bound guard. Reject <= 0 or enforce 1..ended_at_unix - started_at_unix before computing the maturity window.
📍 Affects 2 files
rust_hft/tools/collector/src/polymarket_parity.rs#L93-L93(this comment)rust_hft/tools/collector/src/polymarket_parity.rs#L1026-L1029rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs#L127-L128rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs#L330-L333
🤖 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/tools/collector/src/polymarket_parity.rs` at line 93, The
trade_maturity_lag_seconds configuration must accept only valid positive values
smaller than the market duration. Update polymarket_parity.rs:93 and the
validation or maturity-window logic at polymarket_parity.rs:1026-1029 to reject
values <= 0 or values at least ended_at_unix - started_at_unix before computing
the window; update the corresponding configuration and validation sites in
rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs:127-128 and :330-333 to
enforce the same constraint.
Change contract
Since #680 the collector emits
polymarket_traderows only insideadvance_trade_finalization(settlement observed +trade_finalization_lag_secs=1800+ 3 stable polls). The production shadow gate's observation was fixed at exactly 900 seconds, so a fresh shadow always reached the parity cutoff with zero emitted trades while the pre-#680 baseline emits continuously —rust_trade_count: 0vslegacy_trade_count: 5944in the 2026-08-08 gate evidence, making trade coverage parity unreachable by construction for every candidate since #680.This PR implements option 1 from the issue: extend the observation to 3600 seconds, matching the bybit and usdm reference gate durations, so markets closing early in the observation finalize before the parity cutoff. The parity window semantics are unchanged (601-second tail, trade/settlement maturity lags 600s/900s, one-second duration rounding tolerance 3600–3601). The gate unit's
RuntimeMaxSec=18000covers the longer run.Issue relationship
Closes #756
Out of scope
Dependencies and merge order
None
Focused validation
test-polymarket-raw-ops-control-plane.shpasses (fixture duration 3600, rejection boundaries 3599/3602, acceptance at 3601, runtime budget 1200+3600+5520=10320, boundary acceptance case re-spanned to 3600s elapsed).cutoff-1800finalizes by the cutoff and its trades' event window[close-900, close]intersects the verifier's trade window[obs_start+~120s, cutoff-600]— so a 3600s observation yields non-empty shadow trades with correct parity evidence.Rollout and rollback
No production impact at merge. The next ACR artifact carries the new gate scripts; the shadow gate rerun observes for 3600 seconds. Rollback is revert (the gate then cannot pass for #680+ candidates again).
Scope exception
None
Summary by CodeRabbit