Parent: #9492
Summary
#9028/#9256 shipped "replayable time": exactly ONE Date.now() per decision pass, captured as decisionClock and recorded into DecisionReplayInput. That guarantee is worth nothing if a second, unrecorded clock read in the same pass also decides an outcome — the recorded instant is then not the instant that decided, and the decision is unreplayable.
The captured clock reached exactly one consumer (maybeForceFreshRebase, processors.ts:3911). At least three other reads still decided outcomes.
Why this fails silently, in the worst direction
replayDecision pins action and only re-derives evaluateGateCheck. So replaying a decision that was actually made on an unrecorded clock read reports verdict: "match" — a false certification. The determinism feature actively vouches for the pipeline precisely where the pipeline is not deterministic. A divergence that is reported as a match is strictly worse than no replay at all.
The three reads
processors.ts:2907 — activeMergeBlockedSha(pr, pr.headSha, Date.now()). Feeds the plan AND the recorded reason code. It is a second, unrecorded clock read in the very same pass that captures decisionClock at :3184.
processors.ts:3498 — account age. Date.now() → isNewAccount → halves the contributor cap → can flip a cap close. decisionClock is already in scope and simply unused. The twin helper src/queue/account-age-throttle.ts:13 has no nowMs seam at all.
src/review/unlinked-issue-guardrail.ts:277 (also :192, :92) — a wall-clock gap chooses close vs hold.
There is also a class no JS-side grep can see: SQL-side datetime('now', ?) in src/review/submitter-reputation.ts.
Requirements
- Every clock read that can change a decision inside the recorded pass must consume the captured instant.
- A read deliberately left on the live clock must be named in
decision-replay.ts's honest-scope note. The current note does not list them, and a scope claim that silently widens is worse than a narrow one.
- No behaviour change for callers outside the decision pass.
Deliverables
Tests (must fail against current main)
Expected outcome
A decision made in the recorded pass is replayable from the recorded instant, and verdict: "match" means what it claims.
Parent: #9492
Summary
#9028/#9256 shipped "replayable time": exactly ONE
Date.now()per decision pass, captured asdecisionClockand recorded intoDecisionReplayInput. That guarantee is worth nothing if a second, unrecorded clock read in the same pass also decides an outcome — the recorded instant is then not the instant that decided, and the decision is unreplayable.The captured clock reached exactly one consumer (
maybeForceFreshRebase,processors.ts:3911). At least three other reads still decided outcomes.Why this fails silently, in the worst direction
replayDecisionpinsactionand only re-derivesevaluateGateCheck. So replaying a decision that was actually made on an unrecorded clock read reportsverdict: "match"— a false certification. The determinism feature actively vouches for the pipeline precisely where the pipeline is not deterministic. A divergence that is reported as a match is strictly worse than no replay at all.The three reads
processors.ts:2907—activeMergeBlockedSha(pr, pr.headSha, Date.now()). Feeds the plan AND the recorded reason code. It is a second, unrecorded clock read in the very same pass that capturesdecisionClockat:3184.processors.ts:3498— account age.Date.now()→isNewAccount→ halves the contributor cap → can flip a cap close.decisionClockis already in scope and simply unused. The twin helpersrc/queue/account-age-throttle.ts:13has nonowMsseam at all.src/review/unlinked-issue-guardrail.ts:277(also:192,:92) — a wall-clock gap chooses close vs hold.There is also a class no JS-side grep can see: SQL-side
datetime('now', ?)insrc/review/submitter-reputation.ts.Requirements
decision-replay.ts's honest-scope note. The current note does not list them, and a scope claim that silently widens is worse than a narrow one.Deliverables
decisionClock.nowMsinto the merge-blocked, account-age and unlinked-issue paths.isBelowAccountAgeThresholdanowMsseam.src/review/decision-replay.ts:26-33to name every read still on the live clock.Tests (must fail against current main)
isNewAccount.Expected outcome
A decision made in the recorded pass is replayable from the recorded instant, and
verdict: "match"means what it claims.