Skip to content

calibration: Pareto-floor comparator between two BacktestScoreReports #8086

Description

@JSONbored

Context

A Pareto-floor discipline — a proposed change may not regress on ANY measured axis even while improving another, so "trading one axis for the other" is treated as a regression, not a net win — is the correct standard for this kind of comparison. packages/loopover-engine/src/calibration/backtest-score.ts's BacktestScoreReport (#8085) gives Loopover the same two axes (precision, recall) for a candidate rule change; this issue adds the pure comparator that applies the no-regression discipline to a baseline-vs-candidate pair of reports.

Requirements

  • Add a new file packages/loopover-engine/src/calibration/backtest-compare.ts.
  • Export a type:
    export type BacktestComparison = {
      ruleId: string;
      baseline: BacktestScoreReport;
      candidate: BacktestScoreReport;
      regressedAxes: Array<"precision" | "recall">;
      improvedAxes: Array<"precision" | "recall">;
      verdict: "improved" | "regressed" | "unchanged";
    };
  • Export a function compareBacktestScores(baseline: BacktestScoreReport, candidate: BacktestScoreReport): BacktestComparison:
    • Throws a plain Error (message must include both reports' ruleId values, e.g. `cannot compare backtest scores for different rules: ${baseline.ruleId} vs ${candidate.ruleId}`) when baseline.ruleId !== candidate.ruleId — comparing scores for two different rules is a caller bug, not a valid comparison.
    • For each axis (precision, recall): if either value is null, the axis is excluded from both regressedAxes and improvedAxes — a report with insufficient decided data can't be compared on that axis. Never treat null as 0 or as "no change."
    • An axis is regressed when candidate's value is strictly less than baseline's value on that axis; improved when strictly greater; when neither is null and the values are equal, the axis appears in neither list.
    • verdict is "regressed" whenever regressedAxes.length > 0a regression on even a single axis wins, regardless of whether the other axis improved. This is the Pareto-floor rule and the entire point of this function; do not compute a weighted/averaged score instead. Otherwise verdict is "improved" when improvedAxes.length > 0, else "unchanged".

Deliverables

  • packages/loopover-engine/src/calibration/backtest-compare.ts with BacktestComparison and compareBacktestScores as specified above.
  • packages/loopover-engine/test/backtest-compare.test.ts covering: both axes improve → verdict: "improved", regressedAxes empty; one axis improves while the other regresses → verdict: "regressed" (the Pareto-floor case — this is the single most important test in this issue; do not omit it); one side null on an axis → that axis appears in neither regressedAxes nor improvedAxes; mismatched ruleId → throws, and the thrown message contains both rule IDs; all axes equal → verdict: "unchanged".
  • Add export * from "./calibration/backtest-compare.js"; to packages/loopover-engine/src/index.ts, on its own new line immediately after the export * from "./calibration/backtest-score.js"; line added by calibration: pure confusion-matrix scorer for a candidate rule classifier against the backtest corpus #8085.

Test Coverage Requirements

99%+ patch coverage (branch-counted). The mixed improve/regress branch described above is a required test case, not optional — a PR without it does not satisfy this issue even if aggregate coverage happens to reach 99% some other way.

Expected Outcome

Given a baseline and candidate score for the same rule, get an unambiguous improved/regressed/unchanged verdict that cannot be gamed by trading one axis for another.

Links & Resources

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
    Status
    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions