Problem
The calibration corpus (#8101/#8104 fired events + human overrides) only accumulates from the moment those writers shipped — audit_events had 0 calibration.* rows and a young signal history on 2026-07-22, while the ledger holds 10k+ historical reviews whose decisions and human outcomes are already durably recorded (review_targets/review_audit, orb_pr_outcomes, agent.action.close/agent.action.merge events, reversal_reopened/reversal_reverted events). Backfilling turns the backtest/trend system from "starts learning today" into "starts with years of ground truth."
What is honestly reconstructable (verified against the live schema, 2026-07-23)
| Corpus ingredient |
Backfillable? |
Source |
Human verdict labels (confirmed/reversed) |
Yes |
terminal PR outcomes + the reversal events recordReversalSignals already writes; a decision later reversed ⇒ reversed, a terminal decision left standing ⇒ confirmed |
| Rule firings per blocker code |
Mostly |
review_audit/decision_json blocker lists where recorded; coverage varies by era of the ledger schema |
metadata.confidence |
Partial |
present where decision_json carried per-finding confidence (AI-review-era rows); absent for older deterministic-only rows |
Raw prompt context (issueText/prTitle/prBody/diff) |
Re-fetchable (phase 2) |
the PRs/issues still exist on GitHub for public repos — a bounded, rate-limit-aware re-fetch job can reconstruct them |
modelResponseText |
No — permanently |
never stored before the #8139 capture; not reproducible (no deterministic model output) |
Net effect: threshold backtests (#8138) and the precision/accuracy trends (#8113/#8140) gain instant deep history; logic-replay backtests (#8139) can only accumulate forward — no backfill can manufacture the model responses.
Requirements
⚠️ Required pattern. Pure-core/thin-IO split exactly like scripts/backtest-corpus-export-core.ts / backtest-corpus-export.ts. The transform (ledger rows → synthesized RuleFiredEvent/HumanOverrideEvent pairs) is the tested pure core; the CLI does the D1 reads/writes.
- Synthesized events must be idempotent and distinguishable: dedupe on (eventType, targetKey, provenance) and tag
metadata.backfilled: true so trend/backtest consumers can include or exclude them explicitly, and re-runs never double-write.
- Dry-run mode is the default (
--apply opts in), printing per-rule counts of what would be written.
- Never fabricate what isn't there: a row without a recorded blocker list yields NO fired events (skip + count), never a guess.
modelResponseText is never synthesized.
- Phase 2 (separate flag, separate PR if large): the GitHub re-fetch of raw context for public-repo rows, bounded and resumable.
Deliverables
Test Coverage Requirements
scripts/** sits outside coverage.include, so Codecov does not gate this patch — the pure core still requires full unit tests per house convention (both label directions, reversal precedence, dedupe/idempotency, the skip-don't-guess paths).
Links & Resources
Boundaries
Backfilled events are additive, tagged, and reversible (deletable by the backfilled tag). No GitHub re-fetch in phase 1. modelResponseText is out of scope permanently.
maintainer-only — one-shot data migration against the production ledger.
Problem
The calibration corpus (#8101/#8104 fired events + human overrides) only accumulates from the moment those writers shipped —
audit_eventshad 0calibration.*rows and a young signal history on 2026-07-22, while the ledger holds 10k+ historical reviews whose decisions and human outcomes are already durably recorded (review_targets/review_audit,orb_pr_outcomes,agent.action.close/agent.action.mergeevents,reversal_reopened/reversal_revertedevents). Backfilling turns the backtest/trend system from "starts learning today" into "starts with years of ground truth."What is honestly reconstructable (verified against the live schema, 2026-07-23)
confirmed/reversed)recordReversalSignalsalready writes; a decision later reversed ⇒reversed, a terminal decision left standing ⇒confirmedreview_audit/decision_jsonblocker lists where recorded; coverage varies by era of the ledger schemametadata.confidencedecision_jsoncarried per-finding confidence (AI-review-era rows); absent for older deterministic-only rowsissueText/prTitle/prBody/diff)modelResponseTextNet effect: threshold backtests (#8138) and the precision/accuracy trends (#8113/#8140) gain instant deep history; logic-replay backtests (#8139) can only accumulate forward — no backfill can manufacture the model responses.
Requirements
metadata.backfilled: trueso trend/backtest consumers can include or exclude them explicitly, and re-runs never double-write.--applyopts in), printing per-rule counts of what would be written.modelResponseTextis never synthesized.Deliverables
scripts/backfill-calibration-corpus-core.ts(pure transform + dedupe/provenance logic, fully unit-tested)scripts/backfill-calibration-corpus.ts(thin IO: D1 read of the ledger eras, dry-run/apply, summary output)--applyTest Coverage Requirements
scripts/**sits outside coverage.include, so Codecov does not gate this patch — the pure core still requires full unit tests per house convention (both label directions, reversal precedence, dedupe/idempotency, the skip-don't-guess paths).Links & Resources
src/review/signal-tracking-wire.ts(the event shapes to match),src/services/public-accuracy-trend.ts'sloadReversalDayRows(the reversal-derivation SQL precedent)Boundaries
Backfilled events are additive, tagged, and reversible (deletable by the
backfilledtag). No GitHub re-fetch in phase 1.modelResponseTextis out of scope permanently.maintainer-only — one-shot data migration against the production ledger.