Skip to content

Commit bb5835b

Browse files
committed
fix(stats): drop counterfactual-replay rows from the public per-rule precision
The public "Measured accuracy per rule" table published `ai_consensus_defect` and `slop_gate_score` with byte-identical decided=460 / confirmed=287 / precision=62.4%. That is not a coincidence: `slop_gate_score`'s override rows are the same label set, copied. #8277's slop backfill re-scores the deterministic slop signals over archived diffs but takes each label verbatim from the `ai_consensus_defect` corpus's human verdict on the same target (`manifestToSourceCases` in backfill-slop-corpus.ts passes `backtestCase.label` straight through). That is exactly what it was built to be — internal evidence for a flip-to-live decision, and by its own module header a LOWER BOUND on live scoring — but the public table describes itself as "precision of each automated rule over its human-decided cases", and those were another rule's human-decided cases. Corroborating that the rows cannot be live: `slop_gate_score` is in GATE_SCORE_SIGNAL_CODES, which `recordImplicitTerminalConfirmations` excludes, and `recordConfiguredGateBlockerOverrides` only ever writes `reversed` — so on the live path the rule has no route to a `confirmed` verdict at all. A 62.4% could only ever have come from replayed rows. Excluded by provenance rather than by rule id, so the next cross-rule replay inherits the same protection. `review_targets_decision_level` (#8083's own backfill) is deliberately NOT excluded: its labels come from what happened to the PRs that rule actually fired on, so they do support a precision claim for it. Refs #9676
1 parent 5ecb771 commit bb5835b

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

src/review/public-rule-precision.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,23 @@ export type PublicRulePrecision = {
4444
latestBacktestRun: { corpusChecksum: string; at: string } | null;
4545
};
4646

47+
/**
48+
* Provenance tags whose override rows carry a verdict that was NOT a human decision about the rule the row is
49+
* filed under, and so cannot support a per-rule "measured accuracy" claim.
50+
*
51+
* `slop_replay_backfill_v1` (#8277) is the counterfactual replay: it re-scores the deterministic slop signals
52+
* over archived diffs, but takes each label verbatim from the `ai_consensus_defect` corpus's human verdict on
53+
* the same target (`scripts/backfill-slop-corpus.ts`'s `manifestToSourceCases`). That is exactly the evidence
54+
* it was built to be -- internal input to a flip-to-live decision, and by its own module header a LOWER BOUND
55+
* on live scoring -- but published under "precision of each automated rule over its human-decided cases" it
56+
* asserts something untrue: those were another rule's human-decided cases. It also made the public table print
57+
* one number twice, since both rules then shared a label set and a target set.
58+
*
59+
* NOT excluded: `review_targets_decision_level` (#8083's own backfill), whose labels come from what actually
60+
* happened to the PRs THAT rule fired on -- synthesized rows, but genuinely about that rule.
61+
*/
62+
const NON_ATTRIBUTABLE_OVERRIDE_PROVENANCES = ["slop_replay_backfill_v1"] as const;
63+
4764
/**
4865
* Load the public per-rule precision block. Fail-safe per section (the same degradation contract as
4966
* loadCalibrationTrend): a read error yields an empty/absent section, never a thrown public endpoint.
@@ -57,6 +74,7 @@ export async function loadPublicRulePrecision(env: Env, nowMs: number = Date.now
5774
SUM(CASE WHEN json_extract(metadata_json, '$.verdict') = 'reversed' THEN 1 ELSE 0 END) AS reversed
5875
FROM audit_events
5976
WHERE event_type LIKE '${HUMAN_OVERRIDE_EVENT_TYPE_PREFIX}%' AND created_at >= ?
77+
AND COALESCE(json_extract(metadata_json, '$.provenance'), '') NOT IN (${NON_ATTRIBUTABLE_OVERRIDE_PROVENANCES.map((tag) => `'${tag}'`).join(", ")})
6078
GROUP BY rule_id`,
6179
sinceIso,
6280
);

test/unit/public-rule-precision.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,46 @@ describe("loadPublicRulePrecision (#8230)", () => {
5555
expect(block.rules).toEqual([{ ruleId: "sparse_rule", decided: PUBLIC_PRECISION_MIN_DECIDED - 1, confirmed: PUBLIC_PRECISION_MIN_DECIDED - 1, precision: null }]);
5656
});
5757

58+
it("REGRESSION: excludes counterfactual-replay rows whose label came from a DIFFERENT rule's human verdicts", async () => {
59+
// #8277's slop replay copies each label verbatim from the ai_consensus_defect corpus's verdict on the same
60+
// target, so publishing it under "precision over its human-decided cases" both misattributes the verdict and
61+
// made the public table print one number twice (both rules showed decided=460/confirmed=287 in production).
62+
const env = createTestEnv();
63+
await seedVerdicts(env, "ai_consensus_defect", 15, 5);
64+
const store = createSignalStore(env);
65+
for (let i = 0; i < 20; i += 1) {
66+
await store.recordHumanOverride({
67+
ruleId: "slop_gate_score",
68+
targetKey: `acme/widgets#${i + 1}`,
69+
verdict: i < 15 ? "confirmed" : "reversed",
70+
occurredAt: new Date(NOW - 1000 - i).toISOString(),
71+
metadata: { backfilled: true, provenance: "slop_replay_backfill_v1" },
72+
});
73+
}
74+
75+
const block = await loadPublicRulePrecision(env, NOW);
76+
expect(block.rules).toEqual([{ ruleId: "ai_consensus_defect", decided: 20, confirmed: 15, precision: 0.75 }]);
77+
});
78+
79+
it("keeps synthesized rows whose labels ARE about the rule they are filed under", async () => {
80+
// review_targets_decision_level is #8083's own backfill: the labels come from what happened to the PRs that
81+
// rule fired on, so they support a precision claim for it. Only the cross-rule copy is excluded.
82+
const env = createTestEnv();
83+
const store = createSignalStore(env);
84+
for (let i = 0; i < 12; i += 1) {
85+
await store.recordHumanOverride({
86+
ruleId: "ai_consensus_defect",
87+
targetKey: `acme/widgets#${i + 1}`,
88+
verdict: i < 9 ? "confirmed" : "reversed",
89+
occurredAt: new Date(NOW - 1000 - i).toISOString(),
90+
metadata: { backfilled: true, provenance: "review_targets_decision_level" },
91+
});
92+
}
93+
94+
const block = await loadPublicRulePrecision(env, NOW);
95+
expect(block.rules).toEqual([{ ruleId: "ai_consensus_defect", decided: 12, confirmed: 9, precision: 0.75 }]);
96+
});
97+
5898
it("counts all three reversal shapes over the window and surfaces the latest backtest run's corpus checksum", async () => {
5999
const env = createTestEnv();
60100
for (const [eventType, count] of [

0 commit comments

Comments
 (0)