Skip to content

miner: calibration backtest-eligibility — replay a candidate ContributionProfile against the captured exclusion corpus #8545

Description

@JSONbored

Problem

#8184 gave AMS a real backtest for ONE knob: calibration backtest-threshold replays a candidate min-rank skip threshold against the node's own history (backtestMinRankCandidate in packages/loopover-miner/lib/ams-calibration.ts, pure core in packages/loopover-engine/src/calibration/ams-rank-corpus.ts). The eligibility-exclusion rules — AMS's other deterministic gate — have no equivalent: a proposed ContributionProfile change ships on a read of the diff, exactly the backtest-before-ship gap #8082 closed for ORB. With bounded raw context captured on exclusion events (blocked-by, see callout), a candidate profile can be replayed over the recorded exclusion history and Pareto-compared before it ships.

Requirements

⚠️ BLOCKED — do not open a PR until the "capture bounded candidate context in eligibility-exclusion fired events" issue is CLOSED (it is linked as blocked-by on this issue). A PR opened while that issue is open will be closed. Fired events recorded before that capture landed have no metadata and MUST be skipped (counted, not guessed at) — see below.

  • New miner lib module packages/loopover-miner/lib/ams-eligibility-backtest.ts exporting a pure backtestEligibilityCandidate(events, currentProfiles, candidateProfiles):
    • Reads signal_rule_fired / signal_human_override events for the four eligibility ruleIds (exclusion_label, missing_eligibility_label, conflicting_signals, excluded_assignee) via the same event-reading conventions ams-calibration.ts uses.
    • Reconstructs each fired event's FilterCandidate from its metadata (labels/assignees/owner + targetKey's repoFullName); events with no metadata are excluded from the corpus and counted in a skippedNoContext stat the CLI must print.
    • Classifier: re-run filterCandidatesByProfiles (imported from contribution-profile-filter.ts — do not reimplement its logic) under the candidate profiles; a candidate profile excluding the reconstructed candidate (any reason) classifies as the fired outcome, kept classifies as not-fired.
    • Ground truth via buildBacktestCorpus; split via splitBacktestCorpus reusing ams-rank-corpus.ts's held-out fraction constant and a new pinned seed constant; score via scoreBacktest; compare current-vs-candidate via compareBacktestScores on visible AND held-out splits.
    • Sample floors: reuse the exact floor constants backtestMinRankCandidate applies (read them from ams-calibration.ts — do not invent new numbers); under-floored corpus returns null exactly like backtestMinRankCandidate does.
  • CLI subcommand calibration backtest-eligibility --profile <path> in packages/loopover-miner/lib/calibration-cli.ts, mirroring runBacktestThreshold's structure verbatim: --json support; missing/invalid --profile file (JSON map of repoFullNameContributionProfile) → reportCliFailure; under-floored corpus prints an explicit line and exits 0; success prints current→candidate summary, skippedNoContext, and renderBacktestComparison for both splits; exit is nonzero only on operational error, never on verdict (the Scaffold the advisory backtest CI workflow + threshold-only comparison, and persist each run's result #8138 advisory guarantee).
  • Persist each completed run via a new MINER_AMS_ELIGIBILITY_BACKTEST_EVENT = "ams_eligibility_backtest_run" ledger event mirroring recordAmsThresholdBacktestRun's shape, and include the new event type in computeAmsBacktestTrackRecord's aggregation (parity with ams-calibration: aggregate backtest track record into the miner calibration report + snapshot event #8185).
  • Tests, all Codecov-visible (root-vitest mirror per test(miner): mirror shouldReenter under root vitest for Codecov (#8347) #8479 if needed): corpus reconstruction (with/without metadata → skippedNoContext both arms), classifier agreement with filterCandidatesByProfiles on a fixture, under-floor null arm and success arm, CLI --json and text outputs, persistence event shape, track-record inclusion. 100% of changed lines and branches — both arms of every ??/ternary/&&.

Deliverables

  • ams-eligibility-backtest.ts pure core per the exact contract above
  • calibration backtest-eligibility subcommand mirroring runBacktestThreshold
  • Run persistence + track-record aggregation parity
  • Full both-arms test coverage, Codecov-visible

Links & Resources

Boundaries

Advisory only — nothing under this issue changes live discovery behavior or applies a profile. No new profile-mutation paths; no reimplementation of filter logic; overrides may be sparse or absent (the scorer's decided ≤ fired discipline handles that — never fabricate verdicts).

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:featureGittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.help wantedExtra attention is needed

    Projects

    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions