Skip to content

feat(polymarket): publish immutable normalized evidence - #98

Merged
proerror77 merged 1 commit into
mainfrom
codex/polymarket-evidence-artifact
Jul 17, 2026
Merged

feat(polymarket): publish immutable normalized evidence#98
proerror77 merged 1 commit into
mainfrom
codex/polymarket-evidence-artifact

Conversation

@proerror77

@proerror77 proerror77 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Change contract

Publish an already normalized NormalizedPolymarketEvidence payload as one immutable, content-addressed, no-clobber data/manifest/_SUCCESS triplet, exposed through polymarket-raw-ops publish-polymarket-evidence.

Out of scope

  • Importing evidence into PostgreSQL or any canonical prediction-market table.
  • Creating a research snapshot, snapshot_contract_hash, evaluator labels, or execution signals.
  • Changing raw Polymarket collection, selection, normalization, production collector runtime, or live-trading policy.

Dependency / merge order

Depends on the neutral normalization contract from #96, which is already merged into main. No outstanding stacked dependency remains; this PR is independently mergeable and rollbackable.

Focused validation

  • cargo fmt --package hft-collector -- --check
  • cargo test -p hft-collector --locked (177 passed, 2 ignored; all package binaries passed on macOS)
  • cargo clippy -p hft-collector --locked --all-targets -- -D warnings
  • cargo check -p hft-collector --locked --target x86_64-unknown-linux-gnu
  • cargo clippy -p hft-collector --locked --all-targets --no-deps --target x86_64-unknown-linux-gnu -- -D warnings
  • git diff --check origin/main
  • Targeted trust-boundary counterexamples cover anonymous-inode publication, attacker-created named decoys, no-clobber idempotence, orphan _SUCCESS refusal, parent-directory swap refusal, exact 0444 publication, writable-mode drift, conflicting bytes, and payload reread before _SUCCESS.
  • Matt Standards review: no P0-P3 findings.
  • Matt Spec review: no P0-P3 findings.
  • Linux runtime execution of the O_TMPFILE counterexamples is required from current-head CI before merge.

Rollout / rollback impact

Rollout is opt-in through the new CLI command and writes only beneath an explicitly supplied output root. It does not alter running collectors, databases, snapshots, or execution. Rollback is removal of the CLI/module; already published content-addressed artifacts remain immutable evidence and require no migration.

Scope evidence

  • 3 changed files, 749 non-generated inserted lines.
  • One Research-domain behavior and one rollback unit: immutable publication of the normalized evidence contract.

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The collector adds a publish-polymarket-evidence CLI command and public publishing API. Evidence is validated, described in a JSON manifest, and installed as immutable data, manifest, and _SUCCESS files under a digest-named directory.

Changes

Polymarket evidence publishing

Layer / File(s) Summary
Evidence contract and manifest validation
rust_hft/tools/collector/src/lib.rs, rust_hft/tools/collector/src/polymarket_evidence_artifact.rs
The collector exposes artifact types and validates evidence digests, sizes, row counts, surfaces, symbols, windows, and recording semantics before generating a newline-terminated manifest.
Bound-directory immutable publication
rust_hft/tools/collector/src/polymarket_evidence_artifact.rs
The publisher verifies directory and file identities, installs matching bytes without clobbering, publishes the artifact triplet under a digest directory, and tests idempotency, incomplete-marker handling, and directory replacement detection.
CLI contract and publishing entrypoint
rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
The CLI adds bounded event-window and output-root arguments, constructs the publishing configuration, prints the publication report as JSON, and tests Clap parsing.

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

Sequence Diagram(s)

sequenceDiagram
  participant CLI as polymarket-raw-ops
  participant Publisher as publish_polymarket_evidence
  participant Validator as validate_dataset
  participant Filesystem as bound artifact directory
  CLI->>Publisher: submit evidence configuration and output root
  Publisher->>Validator: validate evidence and generate report
  Validator-->>Publisher: return validated evidence
  Publisher->>Filesystem: install data, manifest, and _SUCCESS
  Filesystem-->>Publisher: return published artifact paths
  Publisher-->>CLI: print publication report as JSON
Loading

Possibly related PRs

  • proerror77/monday#96: Provides the typed Polymarket evidence normalization and digest semantics used by this publisher.
  • proerror77/monday#34: Introduced the Polymarket raw-operations CLI that this change extends.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise and matches the main change: publishing immutable normalized Polymarket evidence.
Description check ✅ Passed The description covers the required sections and includes contract, out-of-scope, dependency, validation, and rollout 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/polymarket-evidence-artifact

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

Copy link
Copy Markdown
Owner Author

@codex review current head b011983

Comment on lines +227 to +233
let descriptor = unsafe {
libc::openat(
directory.as_raw_fd(),
name.as_ptr(),
libc::O_RDONLY | libc::O_CLOEXEC | libc::O_DIRECTORY | libc::O_NOFOLLOW,
)
};
return Err(std::io::Error::last_os_error())
.with_context(|| format!("bind artifact directory {}", path.display()));
}
directory = unsafe { File::from_raw_fd(descriptor) };
Comment on lines +246 to +253
let result = unsafe {
libc::fstatat(
directory.as_raw_fd(),
name.as_ptr(),
stat.as_mut_ptr(),
libc::AT_SYMLINK_NOFOLLOW,
)
};
}
return Err(error).with_context(|| format!("inspect artifact target {}", path.display()));
}
let stat = unsafe { stat.assume_init() };
Comment on lines +281 to +287
let descriptor = unsafe {
libc::openat(
directory.as_raw_fd(),
name.as_ptr(),
libc::O_RDONLY | libc::O_CLOEXEC | libc::O_NOFOLLOW,
)
};
return Err(std::io::Error::last_os_error())
.with_context(|| format!("open immutable artifact {}", path.display()));
}
let mut file = unsafe { File::from_raw_fd(descriptor) };
Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Fixed
Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Fixed
Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Fixed
Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Fixed

@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 `@rust_hft/tools/collector/src/polymarket_evidence_artifact.rs`:
- Around line 361-370: Make published artifact and manifest files read-only by
removing all write permission bits after creation, and re-read and validate
their bytes immediately before publishing _SUCCESS, including newly written data
and manifest files. Update the relevant completion test to assert zero write
bits while preserving a deliberate permission-change scenario that detects
conflicting bytes.
🪄 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: b2869bf3-d634-4f47-81b2-df873b14fd82

📥 Commits

Reviewing files that changed from the base of the PR and between ae8d8a8 and b011983.

📒 Files selected for processing (3)
  • rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
  • rust_hft/tools/collector/src/lib.rs
  • rust_hft/tools/collector/src/polymarket_evidence_artifact.rs

Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Outdated
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Can't wait for the next one!

Reviewed commit: b011983347

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

@proerror77
proerror77 force-pushed the codex/polymarket-evidence-artifact branch from b011983 to 068983f Compare July 17, 2026 12:53
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review current head 068983f after the Linux dev_t clippy portability fix

@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: 068983f6b3

ℹ️ 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 +389 to +391
drop(output);
verify_bound_directory(directory_path, directory)?;
let linked = unsafe {

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 Keep the temp inode bound through linkat

When the selected output_root is writable by another process/user, closing the temp file before the path-based linkat leaves the temporary pathname replaceable: a racer can unlink .tmp, create different bytes at the same name, and have this code link that replacement as the final artifact. Because the successful link path is not read back before publishing _SUCCESS, the marker can attest bytes that this command did not write; keep the fd-bound inode through publication or verify the linked target before success can be installed.

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 9281195: the temp FD now remains open through linkat, and the linked entry identity plus bytes/mode are verified before publication can continue.

| libc::O_EXCL
| libc::O_CLOEXEC
| libc::O_NOFOLLOW,
0o600,

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 Publish artifacts with readable permissions

When the publisher runs under a collector/service account and downstream evidence importers run as a different user or group, the final data, manifest, and _SUCCESS files inherit this temp file's 0600 mode because they are hard-linked from the temp inode. The command can report a successful content-addressed artifact that downstream consumers cannot open; create the temp with the normal shared artifact mode, or otherwise set intended readable permissions before linking.

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 9281195: data, manifest, and _SUCCESS are published as exact 0444 files, so downstream users can read them while no write bits remain.

@proerror77
proerror77 force-pushed the codex/polymarket-evidence-artifact branch from 068983f to 9281195 Compare July 17, 2026 13:41

@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 `@rust_hft/tools/collector/src/polymarket_evidence_artifact.rs`:
- Around line 351-360: Change the artifact finalization flow around
temporary_identity and linkat so linking uses a non-replaceable staging location
or the already-open descriptor, rather than resolving the replaceable temporary
pathname. On identity mismatch, safely remove the mismatched final target and
ensure cleanup cannot unlink an attacker-replaced entry. Add a targeted
counterexample test that swaps the temporary directory entry immediately before
linking and verifies the immutable artifact is not poisoned.
🪄 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: 125b2400-396c-46d5-8c1a-6fd67b2a81a7

📥 Commits

Reviewing files that changed from the base of the PR and between b011983 and 9281195.

📒 Files selected for processing (3)
  • rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
  • rust_hft/tools/collector/src/lib.rs
  • rust_hft/tools/collector/src/polymarket_evidence_artifact.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • rust_hft/tools/collector/src/bin/polymarket-raw-ops.rs
  • rust_hft/tools/collector/src/lib.rs

Comment thread rust_hft/tools/collector/src/polymarket_evidence_artifact.rs Outdated
Constraint: Downstream importers need content-addressed collector evidence without inheriting research snapshot authority semantics before PR #96 merges
Rejected: reuse research artifact naming | it leaked snapshot-oriented identifiers and banned settlement surface semantics
Directive: Keep content_sha256/content_bytes distinct from snapshot contracts and preserve the no-clobber triplet publisher as one rollout unit with the CLI
Confidence: high
Scope-risk: narrow
Tested: cargo fmt --all; cargo test -p hft-collector manifest_semantics_disclose_content_digest_and_recording_limits --locked; cargo test -p hft-collector publish_polymarket_evidence_cli_requires_a_bounded_window_and_output_root --locked; cargo test -p hft-collector --locked; cargo clippy -p hft-collector --lib --locked -- -D warnings; git diff --check; git diff --cached --check
@proerror77
proerror77 force-pushed the codex/polymarket-evidence-artifact branch from 9281195 to b3fb50c Compare July 17, 2026 14:34
Comment on lines +364 to +371
let descriptor = unsafe {
libc::openat(
directory.as_raw_fd(),
c".".as_ptr(),
libc::O_WRONLY | libc::O_TMPFILE | libc::O_CLOEXEC,
0o600,
)
};
if descriptor < 0 {
return Err(std::io::Error::last_os_error()).context("create anonymous artifact file");
}
Ok(unsafe { File::from_raw_fd(descriptor) })
Comment on lines +381 to +389
Ok(unsafe {
libc::linkat(
libc::AT_FDCWD,
source.as_ptr(),
directory.as_raw_fd(),
name.as_ptr(),
libc::AT_SYMLINK_FOLLOW,
)
})
@proerror77

Copy link
Copy Markdown
Owner Author

@codex review current head b3fb50c after replacing named staging paths with Linux O_TMPFILE anonymous-inode publication

@proerror77
proerror77 merged commit 687c3d9 into main Jul 17, 2026
25 checks passed
@proerror77
proerror77 deleted the codex/polymarket-evidence-artifact branch July 17, 2026 14:41

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

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

bail!("artifact payload disappeared before success publication");
}
install_no_clobber(directory_path, &directory, success_path, bytes.success)?;
if !exact_or_missing(directory_path, &directory, success_path, bytes.success)? {

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 Recheck payloads after publishing _SUCCESS

In a shared output directory, data and manifest are validated before _SUCCESS is published, but after install_no_clobber returns this only re-reads the marker. If another publisher or cleanup job unlinks/replaces the data or manifest between the data_ready/manifest_ready checks and this final check, publish_triplet can return Ok while leaving the completion marker for an incomplete or non-matching triplet; revalidate the payload files after the marker is installed before reporting success.

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.

2 participants