Repository navigation
feat(pr-fix): persist authoritative evidence versions and attempt-snapshot freshness #1249
Description
Grooming update (2026-10-15): P1 / READY. The design dependency #1248 is merged. Implement this narrowly as the freshness evidence primitive, reusing #1119/#940 behavior; do not add automatic reactivation here. Follow it with #1253. Production backlog order: Courier quota recovery #327 first; Dispatch #1250 (false external waits), #1249 (fresh evidence), then #1253 (reactivation).
Why
Fresh PR feedback can be discovered after an earlier worker settles. Today's bounded evidenceKeys / postDispatchEvidenceKeys and FIXED tombstones cannot reliably distinguish a first-seen post-dispatch review from a webhook replay, especially after eviction or a missed sync. This is an implementation child of #1244, design PR #1248.
Work
- Extend the PR-fix queue's durable evidence/disposition contract with forge-authoritative identity, state/version, bounded content signature, observation provenance, and the evidence snapshot actually available to generation g at hand-out. Preserve existing generation and history.
- Define replay-safe freshness across dispositions and cache eviction, including long-lived
merge_state/merge_conflictconditions without forge timestamps. Use a durable per-condition/attempt baseline rather than a singledisposedEvidencekey. - Record review state changes, current-head check outcomes, and resolved/outdated review comments through the configured forge capability. Do not count duplicate events, repeated text or an already-resolved thread as new work.
- Make enqueue/settlement writes generation- and evidence-snapshot-pinned, preserving the existing PR-fix evidence that arrives mid-attempt is absorbed and never delivered to the worker #1119 post-dispatch handoff, [P2] A pr-fix item marked FIXED on workload exit alone strands the PR forever, with no way back #940 same-head untrusted-
FIXEDrecovery, human holds and attempt history. Do not implement automatic PARKED/WAITING_EXTERNAL reactivation here; expose a tested shared freshness decision for that follow-up.
Acceptance / negative tests
- Review submitted after hand-out but first discovered by periodic sync after the worker wrote FIXED is fresh, even if review.submitted_at predates disposedAt.
- Replayed old review and persistent old dirty/merge-conflict state after bounded-cache eviction are not fresh; same-head duplicate text and resolved/outdated comments don't reopen.
- Changed review state, new-head failing check and genuinely new review do count; missing/unknown forge evidence is not silently deemed resolved.
- Concurrent settlement vs enqueue and controller restart cannot discard an observation or let an old generation settle a new one. No invented head/timestamp, no new worker-specific requirements.
Dependencies / sequencing
Blocked until #1248's freshness contract is accepted (resolve the human review's late-webhook / timestamp-less-condition findings). Reuse #1119/#1134 mechanisms; do not reimplement their already-shipped fixes. Downstream: operational recovery/reconciliation issue to be linked here. No new credential/deployment requirement.
Activity
merge: origin/main into courier/misospace/dispatch/issue-1249
fix(pr-fix): address review round on the evidence ledger (#1276)
fix(pr-fix): stamp the evidence watermark with a monotonic lower bound (
feat(pr-fix): persist authoritative evidence versions and attempt-sna…