Skip to content

feat(research): add prediction MCTS training evidence - #199

Merged
proerror77 merged 1 commit into
mainfrom
codex/prediction-mcts-training-evidence-197
Jul 22, 2026
Merged

proerror77 merged 1 commit into
mainfrom
codex/prediction-mcts-training-evidence-197

Conversation

@proerror77

@proerror77 proerror77 commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Closes #197

Change contract

Add a fail-closed evaluator mode that scores one typed MCTS probability candidate on training settlement events only.

Out of scope

Shared runner, official entrypoint switch, LLM selection, checkpointing, hold-out scoring, token execution, collectors, snapshots, publication, and live execution.

Dependency / merge order

Base layer. Merge before #198, then #187.

Focused validation

  • cargo test -p ploy-research settlement_training_report_never_scores_the_held_out_event --no-default-features
  • cargo test -p ploy-research --bin monday-prediction-evaluator --features db --no-default-features
  • cargo test -p ploy-research checked_in_btc_and_sol_templates_pin_current_brief_and_rust_policy --no-default-features
  • cargo clippy -p ploy-research --features db --no-default-features --no-deps -- -D warnings
  • cargo fmt --check

Rollout / rollback impact

Dormant evaluator flag only; no production entrypoint changes. Revert this PR to remove the capability.

Summary by CodeRabbit

  • New Features

    • Added support for generating prediction MCTS training evidence from a candidate JSON input.
    • Added training-only settlement probability reports with cohort identifiers, event counts, and evaluation metrics.
    • Training evidence reports now include candidate details, snapshot provenance, probability blend information, and scoring results.
  • Configuration

    • Updated the pinned search policy snapshots for BTC and SOL prediction market research missions.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds training-only settlement probability reporting, exposes the new report API, and adds an optional evaluator mode that validates a prediction-MCTS candidate and emits content-addressed training evidence. Two mission templates receive updated policy snapshot identifiers.

Changes

Prediction MCTS training evidence

Layer / File(s) Summary
Training report contract and calculation
rust_hft/prediction-markets/crates/ploy-research/src/factors_v2.rs, rust_hft/prediction-markets/crates/ploy-research/src/lib.rs
Adds a serializable training report, event-disjoint training calculations, distinct-event counting, public re-exports, and coverage for held-out event exclusion.
Evaluator training-evidence mode
rust_hft/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs, rust_hft/prediction-markets/config/research_missions/*
Adds the candidate JSON flag, governed-prior and identity validation, training evidence artifact generation, early termination, and updated mission policy snapshot identifiers.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

  • Issue 187: Extends the evaluator to consume and evaluate MCTS candidates, connecting to this PR’s training-evidence evaluator path.

Possibly related PRs

  • proerror77/monday#76: Updates the same mission template JSON files’ search_policy_snapshot_id values.
  • proerror77/monday#143: Also extends governed time-cohort handling used by the training report and evaluator.
  • proerror77/monday#139: Changes prediction-policy identity inputs related to the governed snapshots used here.

Sequence Diagram(s)

sequenceDiagram
  participant CandidateJson
  participant MondayPredictionEvaluator
  participant TrainingReportBuilder
  participant ReportOutputDirectory
  MondayPredictionEvaluator->>CandidateJson: Load PredictionMctsCandidate
  MondayPredictionEvaluator->>MondayPredictionEvaluator: Validate candidate and governed prior
  MondayPredictionEvaluator->>TrainingReportBuilder: Build training-only probability report
  TrainingReportBuilder-->>MondayPredictionEvaluator: Return training baselines
  MondayPredictionEvaluator->>ReportOutputDirectory: Write content-addressed evidence artifact
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR also changes snapshot-pinning config files, which are explicitly listed as out of scope in the issue and description. Remove the search_policy_snapshot_id updates unless they are required for #197; keep the PR limited to the evaluator training-evidence path.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: adding prediction MCTS training evidence.
Description check ✅ Passed The description covers the contract, out-of-scope items, merge order, validation, and rollback, matching the template closely.
Linked Issues check ✅ Passed The changes validate candidate identity and prior, skip held-out/token/promotion paths, and emit one training evidence artifact, matching #197.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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/prediction-mcts-training-evidence-197

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: 71f2c3111e

ℹ️ 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 +1647 to +1652
if prior.mission_id.as_deref() != Some(candidate.identity.mission_id.as_str())
|| prior.data_snapshot_id.as_deref()
!= Some(candidate.identity.data_snapshot_id.as_str())
|| prior.symbols.as_slice() != [candidate.identity.symbol.as_str()]
|| prior.horizon.as_deref() != Some(candidate.identity.horizon.as_str())
|| prior.probability_blends[0] != candidate.probability_blend

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 Validate candidate identifiers before emitting evidence

When the externally supplied candidate JSON has a forged or stale candidate_id or probability_blend_sha256, this check still accepts it because it compares only the identity and blend payload; the unverified values are then copied into a content-addressed artifact and the evaluator reports success. Recompute and verify the blend digest and candidate identity before scoring so this advertised fail-closed mode cannot emit evidence bound to a different candidate.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

Comment on lines +3152 to +3156
let event_count = training
.iter()
.map(|row| row.event_id.as_str())
.collect::<HashSet<_>>()
.len();

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 Count only events contributing to candidate metrics

When the training slice contains events without a settlement label, a fillable full-depth entry, or a usable candidate probability, this counts those events even though build_settlement_probability_report_with_surface subsequently excludes their rows. The emitted event_count can therefore materially overstate the number of settlement events behind the reported Brier score and log loss; derive it from the eligible samples for the selected candidate model instead.

Useful? React with 👍 / 👎.

min_bucket_observations: options.review.min_observations.max(20),
..Default::default()
},
time_cohort: settlement_time_cohort,

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 Bind the training boundary to the governed candidate

When this mode is invoked with a --time-cohort-boundary-ms different from the mission boundary that produced the candidate, no validation detects it because neither PredictionMctsIdentity nor the governed prior carries that boundary, and this value is passed directly into training. Moving the boundary later admits intended held-out events into the reward cohort, while PredictionMctsEngine::observe accepts the resulting arbitrary nonempty cohort ID, so a misconfigured runner can leak holdout outcomes into MCTS search; bind and validate the mission boundary before evaluation.

AGENTS.md reference: AGENTS.md:L23-L27

Useful? React with 👍 / 👎.

@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

🧹 Nitpick comments (2)
rust_hft/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs (2)

1636-1706: 🧹 Nitpick | 🔵 Trivial

Run sidecar-focused checks given the new evidence contract is consumed by ploy-agent-sidecar.

PredictionMctsEvaluation/SettlementTrainingEvidence populated here are validated and consumed by observe() in the sidecar crate (per provided context). Beyond the evaluator-binary tests already listed for this PR, consider also running cargo test -p ploy-agent-sidecar to confirm the identity/blend-digest checks in observe() still accept evidence shaped this way.

As per path instructions: "Run sidecar checks with cargo test -p ploy-agent-sidecar."

🤖 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/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs`
around lines 1636 - 1706, Run the required sidecar-focused validation with cargo
test -p ploy-agent-sidecar, confirming observe() accepts the
PredictionMctsEvaluation and SettlementTrainingEvidence identity and
blend-digest fields populated in this training path.

Source: Path instructions


1636-1636: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

--prediction-mcts-training-candidate-json silently takes precedence over --reprice-pilot-10s if both are passed.

The training-candidate branch returns early (Line 1705) with no check that reprice_pilot_10s (or other mutually exclusive modes) wasn't also requested. If an orchestration script mistakenly sets both flags, the reprice pilot silently never runs instead of failing loudly. validate_reprice_pilot_config already validates other flag interactions for the reprice path — consider adding an equivalent guard for this new dormant mode.

🛡️ Proposed guard
     if let Some(candidate_path) = prediction_mcts_training_candidate_json.as_deref() {
+        if reprice_pilot_10s {
+            panic!("--prediction-mcts-training-candidate-json cannot be combined with --reprice-pilot-10s");
+        }
         let candidate: PredictionMctsCandidate = std::fs::read(candidate_path)

As per coding guidelines: "Never simplify away validation, security, data-loss prevention, or other trust-boundary checks."

Also applies to: 1707-1747

🤖 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/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs`
at line 1636, Guard the prediction_mcts_training_candidate_json branch before
its early return so it rejects reprice_pilot_10s and any other mutually
exclusive modes instead of silently taking precedence. Reuse or extend
validate_reprice_pilot_config where appropriate, and ensure invalid flag
combinations fail loudly before entering the training-candidate flow.

Source: Coding guidelines

🤖 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/prediction-markets/crates/ploy-research/src/factors_v2.rs`:
- Around line 12658-12679: Add an explicit non-empty assertion for
report.baselines in settlement_training_report_never_scores_the_held_out_event
before the existing all-baselines n == 1 check, ensuring the test cannot pass
vacuously while preserving its current assertions.

---

Nitpick comments:
In
`@rust_hft/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs`:
- Around line 1636-1706: Run the required sidecar-focused validation with cargo
test -p ploy-agent-sidecar, confirming observe() accepts the
PredictionMctsEvaluation and SettlementTrainingEvidence identity and
blend-digest fields populated in this training path.
- Line 1636: Guard the prediction_mcts_training_candidate_json branch before its
early return so it rejects reprice_pilot_10s and any other mutually exclusive
modes instead of silently taking precedence. Reuse or extend
validate_reprice_pilot_config where appropriate, and ensure invalid flag
combinations fail loudly before entering the training-candidate flow.
🪄 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: 212445e5-7fcf-4217-9ff5-a19b895ede86

📥 Commits

Reviewing files that changed from the base of the PR and between bfa9c29 and 71f2c31.

📒 Files selected for processing (5)
  • rust_hft/prediction-markets/config/research_missions/polymarket-btc-5m.example.json
  • rust_hft/prediction-markets/config/research_missions/polymarket-sol-5m.example.json
  • rust_hft/prediction-markets/crates/ploy-research/src/bin/monday-prediction-evaluator.rs
  • rust_hft/prediction-markets/crates/ploy-research/src/factors_v2.rs
  • rust_hft/prediction-markets/crates/ploy-research/src/lib.rs

Comment on lines +12658 to +12679
#[test]
fn settlement_training_report_never_scores_the_held_out_event() {
let (start, boundary, end, rows, options) = short_settlement_time_cohort_case();
let options = SettlementProbabilityWalkForwardOptions {
time_cohort: Some(SettlementProbabilityTimeCohort::new(boundary, 300).unwrap()),
..options
};
let report = build_settlement_training_probability_report_with_prior(
&rows, start, end, None, options,
);

assert_eq!(report.event_count, 1);
assert!(report.baselines.iter().all(|baseline| baseline.n == 1));
assert_eq!(
report.training_cohort_id,
format!(
"settlement-training-before-{}-300s",
boundary.timestamp_millis()
)
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Test doesn't assert baselines is non-empty, so it can pass vacuously.

assert!(report.baselines.iter().all(|baseline| baseline.n == 1)) (Line 12670) is true for an empty Vec too. If a future regression made build_settlement_training_probability_report_with_prior always return empty baselines (e.g., threshold/model-selection bug), this test would still pass. Compare with the sibling test settlement_probability_short_time_cohort_emits_one_held_out_window, which explicitly asserts !report.windows.is_empty() before checking window contents.

🧪 Proposed fix
         assert_eq!(report.event_count, 1);
+        assert!(!report.baselines.is_empty());
         assert!(report.baselines.iter().all(|baseline| baseline.n == 1));
📝 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
#[test]
fn settlement_training_report_never_scores_the_held_out_event() {
let (start, boundary, end, rows, options) = short_settlement_time_cohort_case();
let options = SettlementProbabilityWalkForwardOptions {
time_cohort: Some(SettlementProbabilityTimeCohort::new(boundary, 300).unwrap()),
..options
};
let report = build_settlement_training_probability_report_with_prior(
&rows, start, end, None, options,
);
assert_eq!(report.event_count, 1);
assert!(report.baselines.iter().all(|baseline| baseline.n == 1));
assert_eq!(
report.training_cohort_id,
format!(
"settlement-training-before-{}-300s",
boundary.timestamp_millis()
)
);
}
#[test]
fn settlement_training_report_never_scores_the_held_out_event() {
let (start, boundary, end, rows, options) = short_settlement_time_cohort_case();
let options = SettlementProbabilityWalkForwardOptions {
time_cohort: Some(SettlementProbabilityTimeCohort::new(boundary, 300).unwrap()),
..options
};
let report = build_settlement_training_probability_report_with_prior(
&rows, start, end, None, options,
);
assert_eq!(report.event_count, 1);
assert!(!report.baselines.is_empty());
assert!(report.baselines.iter().all(|baseline| baseline.n == 1));
assert_eq!(
report.training_cohort_id,
format!(
"settlement-training-before-{}-300s",
boundary.timestamp_millis()
)
);
}
🤖 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/prediction-markets/crates/ploy-research/src/factors_v2.rs` around
lines 12658 - 12679, Add an explicit non-empty assertion for report.baselines in
settlement_training_report_never_scores_the_held_out_event before the existing
all-baselines n == 1 check, ensuring the test cannot pass vacuously while
preserving its current assertions.

@proerror77
proerror77 merged commit c1a5af8 into main Jul 22, 2026
30 checks passed
@proerror77
proerror77 deleted the codex/prediction-mcts-training-evidence-197 branch July 24, 2026 08:44
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.

Add training-only settlement evidence for prediction MCTS

1 participant