pr_outcome (which the fleet calibration export inner-joins on) is written two ways, both in-process best-effort: recordPrOutcome (src/review/outcomes-wire.ts ~404, webhook-only) and recordTerminalActionOutcome (~365) called inside performAction right after the mutation (agent-action-executor.ts ~1055 merge, ~1066 close). The doc comment at ~349-359 documents #8823 and that roughly 55% of closes once had no pr_outcome row, biasing accuracy upward.
#8823 narrowed but did not close the window. A kill between mergePullRequest/closePullRequest and the record call loses the direct write. On re-run the PR is already terminal, so the planner plans nothing and the record never fires. The remaining chance is the inbound closed webhook — which GitHub fired while the container was down and which is never redelivered.
There is no boot or periodic reconciler that scans for merged/closed PRs lacking a pr_outcome row (confirmed by absence — the repair sweep only touches OPEN PRs). Given the calibration work in flight, silent outcome loss corrupts the ground truth the close guarantee is computed from.
Fix
Add a periodic reconciler that lists recently closed/merged PRs (or reads completed agent.action.merge|close audit events) and backfills any missing pr_outcome via recordTerminalActionOutcome — which is already idempotent (~373-378).
Refs #9007.
pr_outcome(which the fleet calibration export inner-joins on) is written two ways, both in-process best-effort:recordPrOutcome(src/review/outcomes-wire.ts~404, webhook-only) andrecordTerminalActionOutcome(~365) called insideperformActionright after the mutation (agent-action-executor.ts~1055 merge, ~1066 close). The doc comment at ~349-359 documents #8823 and that roughly 55% of closes once had nopr_outcomerow, biasing accuracy upward.#8823 narrowed but did not close the window. A kill between
mergePullRequest/closePullRequestand the record call loses the direct write. On re-run the PR is already terminal, so the planner plans nothing and the record never fires. The remaining chance is the inboundclosedwebhook — which GitHub fired while the container was down and which is never redelivered.There is no boot or periodic reconciler that scans for merged/closed PRs lacking a
pr_outcomerow (confirmed by absence — the repair sweep only touches OPEN PRs). Given the calibration work in flight, silent outcome loss corrupts the ground truth the close guarantee is computed from.Fix
Add a periodic reconciler that lists recently closed/merged PRs (or reads completed
agent.action.merge|closeaudit events) and backfills any missingpr_outcomeviarecordTerminalActionOutcome— which is already idempotent (~373-378).Refs #9007.