Skip to content

fix(collector): enforce hard Polymarket cycle deadline - #44

Merged
proerror77 merged 5 commits into
mainfrom
codex/polymarket-hard-cycle-watchdog
Jul 15, 2026
Merged

fix(collector): enforce hard Polymarket cycle deadline#44
proerror77 merged 5 commits into
mainfrom
codex/polymarket-hard-cycle-watchdog

Conversation

@proerror77

@proerror77 proerror77 commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Summary

  • enforce the 180-second Polymarket reference cycle deadline with an independent OS-thread watchdog, including synchronous fsync/state publication
  • calibrate shadow and production cgroups to 512MiB/768MiB from the Tokyo cold-start evidence
  • restore a fail-closed, source-bound Polymarket shadow/cutover control plane and package its exact assets with the ACR artifact
  • verify binary, source revision, control tar, manifest, deployment bundle, and exact member set before installation

Validation

  • cargo test -p hft-collector --features collector-binance --locked
  • cargo clippy -p hft-collector --features collector-binance --all-targets --locked -- -D warnings
  • targeted hard-watchdog tests (2 passed, 1 ignored subprocess target)
  • deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
  • shellcheck for gate/cutover/control-plane scripts
  • cargo fmt --check and git diff --check

Safety

No trading path is enabled. Production remains on the existing Python reference collector until a new immutable artifact completes the one-hour shadow plus parity tail and the same reviewed bundle performs cutover.

Summary by CodeRabbit

  • New Features
    • Introduced Polymarket raw-ops shadow-gate, cutover, and rollback workflows with fail-closed eligibility checks and durable recovery evidence.
    • Added deployment bundle/control-asset integrity verification and stronger source/version pinning.
  • Reliability
    • Increased collector systemd memory limits.
    • Added a hard cycle watchdog to terminate stalled collection safely.
  • Documentation
    • Expanded Polymarket deployment and added memory calibration reporting.
  • Tests
    • Added end-to-end control-plane integration testing, including shadow parity and watchdog behavior.
  • Chores
    • Improved CI enforcement and ACR publish artifact hashing/digests.

@coderabbitai

coderabbitai Bot commented Jul 15, 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: 2 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

Run ID: b3c745ea-2a25-4520-8aec-096a9d770668

📥 Commits

Reviewing files that changed from the base of the PR and between 747bb36 and d270ed7.

📒 Files selected for processing (8)
  • .github/workflows/acr-publish.yml
  • .github/workflows/ci.yml
  • deployment/aliyun/README.md
  • deployment/aliyun/polymarket-raw-ops-cutover.sh
  • deployment/aliyun/polymarket-raw-ops-shadow-gate.sh
  • deployment/aliyun/polymarket-shadow-gate-policy.jq
  • deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
  • rust_hft/tools/collector/src/polymarket_raw.rs
📝 Walkthrough

Walkthrough

The PR adds digest-pinned deployment bundles, a Polymarket shadow gate and cutover/rollback control plane, a hard Rust cycle watchdog, updated memory limits, calibration documentation, and extensive integration and CI validation.

Changes

Polymarket raw-ops promotion controls

Layer / File(s) Summary
Release artifact packaging and installation
.github/workflows/acr-publish.yml, deployment/aliyun/README.md
Deployment assets are packaged into deterministic hashed artifacts, while installation verifies source, bundle, tarball, manifest, and allowlisted contents.
Shadow gate execution and evidence
deployment/aliyun/polymarket-raw-ops-shadow-gate.sh, deployment/aliyun/polymarket-shadow-gate-policy.jq
Candidate and legacy runtimes are identity-checked while a shadow instance runs; health, parity, OSS readback, and eligibility are recorded in gate evidence.
Cutover and rollback lifecycle
deployment/aliyun/polymarket-raw-ops-cutover.sh
Cutover snapshots the legacy runtime, transitions systemd and the active binary to Rust, publishes evidence, and restores the snapshot on rollback or failed transition.
Cycle deadline and memory envelope
rust_hft/tools/collector/src/polymarket_raw.rs, deployment/aliyun/polymarket-reference-collector*.service, deployment/aliyun/README.md, docs/reports/*, .github/workflows/ci.yml
A hard watchdog terminates overdue cycles and disarms on completion; service limits, calibration records, and locked CI coverage reflect the updated envelope.
Control-plane contract validation
deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
Integration checks cover marker verification, parity failures, policy mutations, deployment ordering, runtime invariants, and release-bundle consistency.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Operator
  participant ShadowGate
  participant Cutover
  participant Systemd
  participant RustCollector
  Operator->>ShadowGate: validate candidate and run shadow gate
  ShadowGate->>Systemd: start shadow collector
  Systemd->>RustCollector: execute candidate
  ShadowGate->>ShadowGate: write gate evidence
  Operator->>Cutover: invoke cutover with gate evidence
  Cutover->>Systemd: stop legacy units and install Rust units
  Systemd->>RustCollector: start Rust collector
  Cutover->>Cutover: write cutover evidence
Loading

Possibly related PRs

  • proerror77/monday#34: Modifies the same Polymarket Rust collector and Aliyun control-plane artifacts.
  • proerror77/monday#37: Changes the same collector cycle path alongside this PR’s hard watchdog logic.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 38.46% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: enforcing a hard Polymarket cycle deadline in the collector.
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
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/polymarket-hard-cycle-watchdog

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.

#[test]
fn hard_cycle_watchdog_terminates_non_yielding_work() {
let started = Instant::now();
let output = std::process::Command::new(std::env::current_exe().unwrap())

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

🤖 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 @.github/workflows/acr-publish.yml:
- Around line 96-100: Bind the candidate SHA, source revision, control-manifest
SHA, and control-archive SHA in one immutable manifest generated by the workflow
around the existing checksum and source-revision steps in
.github/workflows/acr-publish.yml (lines 96-100). Update
deployment/aliyun/README.md (lines 148-159) to require manifest verification
before accepting any component. Update polymarket-raw-ops-shadow-gate.sh (lines
226-240) to load identities only from the verified pinned metadata and reject
mismatches against CLI values or the installed bundle.

In `@deployment/aliyun/polymarket-raw-ops-cutover.sh`:
- Around line 344-347: Update the rollback snapshot creation flow around the
sha256sum command to flush the rollback directory and its captured runtime state
to durable storage before publishing cutover success. Ensure the rollback
snapshot, installed units/binaries, configuration/control files, and
directory-entry updates are synchronized, not just cutover.json via sync
"$evidence_dir/cutover.json".

In `@deployment/aliyun/polymarket-raw-ops-shadow-gate.sh`:
- Around line 26-31: Harden every trusted directory used by
pol​​ymarket-raw-ops-shadow-gate.sh, including SCRIPT_DIR and the directories
checked around the referenced ranges, so each path component is root-owned and
not group- or world-writable before reading executables or policies and before
publishing evidence. Update the existing directory-validation logic (including
direct_directory* usage) rather than relying only on symlink rejection, and
apply the same checks to the completed evidence directory.

In `@rust_hft/tools/collector/src/polymarket_raw.rs`:
- Around line 72-77: Update the watchdog timeout branch around the
wait/completed check to replace eprintln! with a best-effort stderr write that
cannot prevent termination if writing fails. Preserve the timeout message and
ensure std::process::exit(HARD_CYCLE_WATCHDOG_EXIT_CODE) executes
unconditionally after the write attempt.
🪄 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

Run ID: f5b15f64-9489-4287-9d53-7cd497377abc

📥 Commits

Reviewing files that changed from the base of the PR and between 2ba1c81 and c17c1c9.

📒 Files selected for processing (10)
  • .github/workflows/acr-publish.yml
  • .github/workflows/ci.yml
  • deployment/aliyun/README.md
  • deployment/aliyun/polymarket-raw-ops-cutover.sh
  • deployment/aliyun/polymarket-raw-ops-shadow-gate.sh
  • deployment/aliyun/polymarket-reference-collector-shadow@.service
  • deployment/aliyun/polymarket-reference-collector.service
  • deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
  • docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md
  • rust_hft/tools/collector/src/polymarket_raw.rs

Comment thread .github/workflows/acr-publish.yml Outdated
Comment thread deployment/aliyun/polymarket-raw-ops-cutover.sh
Comment thread deployment/aliyun/polymarket-raw-ops-shadow-gate.sh
Comment on lines +72 to +77
if wait.timed_out() && !*completed {
eprintln!(
"Polymarket reference cycle exceeded the hard {}ms wall-clock deadline",
timeout.as_millis()
);
std::process::exit(HARD_CYCLE_WATCHDOG_EXIT_CODE);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
sed -n '55,99p' rust_hft/tools/collector/src/polymarket_raw.rs
sed -n '/^\[profile\./,/^\[/p' rust_hft/Cargo.toml
fd -H -t f '^rust-toolchain(\.toml)?$' -x sed -n '1,120p' {}

Repository: proerror77/monday

Length of output: 2050


🌐 Web query:

Rust eprintln macro panic if writing to stderr fails std::io::stderr write failure process::exit spawned thread panic behavior

💡 Result:

In Rust, the eprintln! and eprint! macros are explicitly designed to panic if writing to standard error (stderr) fails [1][2]. This behavior is documented in the Rust standard library, which states that these macros will panic if an I/O error occurs while writing to io::stderr [1][3]. A common cause for such a panic is when stderr is configured as non-blocking and the operation cannot complete immediately [1][4]. Because this panic occurs within the macro implementation, it follows standard Rust panic behavior: 1. If the panic occurs in a thread, the thread will terminate (unwind or abort, depending on configuration). 2. Because stderr is often used for logging or critical error reporting, this design forces the developer to handle or acknowledge potential failures in the output stream, rather than silently failing to report critical information. It is important to note that the Rust standard library provides specific internal functions, such as attempt_print_to_stderr, which are used in contexts where panicking is undesirable (e.g., when the runtime needs to print error messages during the termination of a main function or test). These internal functions intentionally ignore I/O errors to avoid secondary panics during the program's cleanup phase [5]. If your application requires handling stderr failures without crashing, you should avoid using the eprintln! or eprint! macros. Instead, obtain a handle to stderr using std::io::stderr and use the standard Write trait methods (such as write_all), which return a Result type that you can handle programmatically [6][7].

Citations:


Avoid eprintln! on the watchdog timeout path
eprintln! can panic if stderr writes fail, so this branch may never reach process::exit(HARD_CYCLE_WATCHDOG_EXIT_CODE). Use a best-effort stderr write, then exit unconditionally.

🤖 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_raw.rs` around lines 72 - 77, Update
the watchdog timeout branch around the wait/completed check to replace eprintln!
with a best-effort stderr write that cannot prevent termination if writing
fails. Preserve the timeout message and ensure
std::process::exit(HARD_CYCLE_WATCHDOG_EXIT_CODE) executes unconditionally after
the write attempt.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md (2)

34-37: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not overstate the reclaim root cause as proven.

These observations support a cgroup-reclaim hypothesis, but the isolated probes used different diagnostic directories and execution conditions, so they do not prove that reclaim was the sole cause. Please soften “This proves” to “This supports” and preserve the controlled-comparison limitations in the evidence.

🤖 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 `@docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md` around lines
34 - 37, In the report passage describing the first failed shadow and its
persistence metrics, replace the definitive “This proves” claim with “This
supports” and retain the limitation that the evidence supports, but does not
establish, cgroup reclaim as the sole cause.

54-55: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Correct the simultaneous memory-limit total.

512M + 768M equals 1,280 MiB (1.25 GiB), not 1.5 GiB. This overstates the cgroup allocation by 256 MiB and makes the host-capacity calculation inconsistent with the stated limits.

🤖 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 `@docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md` around lines
54 - 55, Correct the simultaneous memory-limit total in the reviewed service
envelope discussion: replace the stated 1.5 GiB with the accurate 1,280 MiB
(1.25 GiB) value derived from MemoryHigh=512M and MemoryMax=768M, and keep the
host-capacity calculation consistent.
🤖 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 @.github/workflows/ci.yml:
- Around line 124-129: Remove the three migration-control script exclusions from
the scanner pathspecs in the CI workflow. Keep these files included in Python,
pip, uv, and related checks, and add a narrowly scoped, explicit allowlist that
validates only the required legacy-runtime references rather than bypassing
scanning for entire files.

In `@deployment/aliyun/polymarket-raw-ops-cutover.sh`:
- Around line 148-149: Update the rollback invalidation sequence around the
marker rename and sync operations to durably persist the parent-directory rename
before rollback begins. After moving the success marker to the pending name,
synchronize the containing directory rather than only the renamed file, while
preserving failure propagation through the existing return paths.

In `@deployment/aliyun/test-polymarket-raw-ops-control-plane.sh`:
- Around line 219-225: Extend the evidence-marker tests to cover pre-existing
and concurrently created destinations, asserting the original marker bytes
remain unchanged for every listed publication path, including
finalize_rollback_evidence outputs. Replace forced-overwrite moves with atomic
no-replace publication so PASSED.invalid.sha256, PASSED.rolled-back.sha256, and
all other evidence markers cannot be clobbered.

---

Outside diff comments:
In `@docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md`:
- Around line 34-37: In the report passage describing the first failed shadow
and its persistence metrics, replace the definitive “This proves” claim with
“This supports” and retain the limitation that the evidence supports, but does
not establish, cgroup reclaim as the sole cause.
- Around line 54-55: Correct the simultaneous memory-limit total in the reviewed
service envelope discussion: replace the stated 1.5 GiB with the accurate 1,280
MiB (1.25 GiB) value derived from MemoryHigh=512M and MemoryMax=768M, and keep
the host-capacity calculation consistent.
🪄 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

Run ID: b9373ebc-d749-4189-a774-c182457468f8

📥 Commits

Reviewing files that changed from the base of the PR and between c17c1c9 and 747bb36.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • deployment/aliyun/README.md
  • deployment/aliyun/polymarket-raw-ops-cutover.sh
  • deployment/aliyun/polymarket-raw-ops-shadow-gate.sh
  • deployment/aliyun/polymarket-shadow-gate-policy.jq
  • deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
  • docs/reports/polymarket-shadow-memory-calibration-2026-07-16.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • deployment/aliyun/polymarket-raw-ops-shadow-gate.sh

Comment thread .github/workflows/ci.yml Outdated
Comment thread deployment/aliyun/polymarket-raw-ops-cutover.sh
Comment thread deployment/aliyun/test-polymarket-raw-ops-control-plane.sh
#[test]
fn hard_cycle_watchdog_exits_124_while_stderr_is_locked() {
let started = Instant::now();
let status = std::process::Command::new(std::env::current_exe().unwrap())
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.

2 participants