You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(orb): gate determinism — deterministic test-evidence facts, decision confidence, and replayable time (#8833, #8834, #9028) (#9256)
* fix(review): demote whole-PR test-absence blockers the path classifier contradicts (#8833)
Whether a PR carries test-path evidence is a deterministic fact — signals/test-evidence.ts's
isTestPath owns it, and slop.ts's missing_test_evidence finding already decides its severity.
The reviewer prompt nonetheless fed the same fact as free text and let the model re-decide
blocker-vs-nit, so a model could close a PR on a claim the engine had already answered the
other way.
Extends the existing parse-time fact-authority pattern (demoteCiClaimBlockers #8845,
demoteEvidenceAbsenceBlockers #8961) to this criterion: a whole-PR "no tests were added"
blocker is demoted to a nit when the classifier confirms the PR does change test paths.
Fires only in the arm where the claim is provably a fact error — a genuine test-absence
blocker on a genuinely test-free PR is untouched — and demotes rather than drops, so the
observation still reaches the human.
Coverage-DEPTH claims that narrow to a specific target ("no tests for the nullish branch")
are deliberately excluded: the classifier cannot check those, so they remain the model's
judgment to make and keep blocking.
* feat(orb): capture the decision-time wall clock so staleness rules are replayable (#9028)
gate.requireFreshRebaseWindow compared the base branch's tip against an inline Date.now()
read inside maybeForceFreshRebase. Time is a decision INPUT, and nothing recorded which
instant the comparison used — so re-deriving such a decision later could silently reach the
opposite answer purely because the wall clock had moved, and report it as a match.
The decision pass now takes ONE Date.now() reading, records it into
decision_replay_inputs.replay_json as `clock`, and passes it to every clock-dependent rule
instead of each calling the clock itself. Both staleness rules move to a pure, clock-injected
module: isWithinFreshRebaseWindow takes the instant explicitly, and isBaseStaleByAheadBy is
stated as the commit-count comparison it is — provably instant-independent, not merely
assumed so.
replayDecision gains a stage-0 `clock` check: replaying at the recorded instant (the CLI
default) is bit-exact, while naming a different instant reports a `clock` divergence rather
than silently certifying a re-derivation that never reproduced the original evaluation.
Records written before this change carry no instant, so the stage is skipped rather than
guessed. The CLI exposes it as `--at <epoch ms>`.
Also corrects the decision_replay_inputs migration reference in two doc comments (0181 is
alert_dedup_claims; the table is created in 0182).
* feat(orb): record a per-decision confidence signal from inter-run agreement (#8834)
Verbalized confidence alone is poorly calibrated — #8845 already had to stop reading an
absent confidence as certainty. Sampling-based consistency is the better-behaved signal, and
the risk-control literature this epic builds on finds two samples capture most of the benefit.
Scores inter-run agreement across the reviewer stances the engine ALREADY produces (#8229's
reviewerVotes) and folds it into the verbalized confidence, at zero additional AI spend. The
combined score multiplies the two so it is monotonically below either input — a judgment is
only as trustworthy as both how sure the judge said it was and how reproducibly the judges
reached it, which is the property an abstention threshold depends on.
A lone run is recorded as UNCORROBORATED at a 0.5 agreement floor rather than fabricated
unanimity, so a single-reviewer or budget-degraded review records a strictly lower confidence
than a genuinely corroborated one. Zero samples refuses to invent a score at all.
The signal rides to DecisionRecord.aiAgreement (schema v5) so every decision joins the
risk-control calibration set with its reproducibility attached. Deliberately ADDITIVE: it
does not re-route the gate. Disagreement already routes to a hold today — differing stances
ARE the ai_review_split finding, which blocks or holds via the existing confidence floor — so
a second parallel route would double-count the same evidence instead of measuring it.
* test(orb): update decision-record schema assertions for the v5 agreement field (#8834)
The DECISION_RECORD_SCHEMA_VERSION bump to v5 moves the pinned version assertions in the
backfill bundle and queue decision-record suites. The #9124 record test additionally carries
the agreement on its cached finding and asserts it threads through to the record, mirroring
exactly how that test already proves modelIds/promptDigest pass through rather than being
re-derived.
---------
Co-authored-by: JSONbored <airdroptopian@gmail.com>
0 commit comments