isStalePayload (src/db/repositories.ts ~396) guards only state, headSha, mergedAt, githubUpdatedAt, labelsJson (~400-409). These are written unconditionally from a possibly-stale payload:
| column |
line |
consumer |
linkedIssuesJson / linkedIssueClaimedAt |
~462-463 |
the linked-issue gate — a hard blocker and close reason |
payloadJson (→ body) |
~467 |
AI review prompt, screenshot gate, linked-issue extraction |
baseRef |
~458 |
required contexts, migration-collision base, CI aggregate key |
title |
~452 |
PR-type label, AI-review cache key, title-keyword skip |
authorAssociation, headRef |
~455-457 |
first-timer heuristics |
Sequence: contributor pushes (synchronize, updated_at=T1), then edits the body to add Fixes #123 (edited, updated_at=T2). GitHub does not guarantee order, and once heads diverge the two have different coalesce keys, so the synchronize job can be dequeued after the edited one. isStalePayload correctly preserves state/headSha/labels — and then reverts body and linkedIssuesJson to the pre-edit snapshot. synchronize is itself in PR_PUBLIC_SURFACE_ACTIONS, so the same pass re-runs the gate against the reverted body.
Result: with requireLinkedIssue / linkedIssueGateMode: block — which we run — a wrong autonomous close for "No linked issue detected" on a PR that has one. That close reason appears in our live ledger.
It also reverts baseRef, compounding the base-retarget issue.
The comment at ~392 explicitly notes the guard was "deliberately NOT extended" — this is the follow-through.
Fix
Extend the resolved-value set to title, baseRef, headRef, authorAssociation, and the payloadJson/linkedIssuesJson/linkedIssueClaimedAt trio — the body-derived group must move together, like the existing preserveSparseBody block.
isStalePayload(src/db/repositories.ts~396) guards onlystate,headSha,mergedAt,githubUpdatedAt,labelsJson(~400-409). These are written unconditionally from a possibly-stale payload:linkedIssuesJson/linkedIssueClaimedAtpayloadJson(→body)baseReftitleauthorAssociation,headRefSequence: contributor pushes (
synchronize,updated_at=T1), then edits the body to addFixes #123(edited,updated_at=T2). GitHub does not guarantee order, and once heads diverge the two have different coalesce keys, so thesynchronizejob can be dequeued after theeditedone.isStalePayloadcorrectly preservesstate/headSha/labels— and then revertsbodyandlinkedIssuesJsonto the pre-edit snapshot.synchronizeis itself inPR_PUBLIC_SURFACE_ACTIONS, so the same pass re-runs the gate against the reverted body.Result: with
requireLinkedIssue/linkedIssueGateMode: block— which we run — a wrong autonomous close for "No linked issue detected" on a PR that has one. That close reason appears in our live ledger.It also reverts
baseRef, compounding the base-retarget issue.The comment at ~392 explicitly notes the guard was "deliberately NOT extended" — this is the follow-through.
Fix
Extend the resolved-value set to
title,baseRef,headRef,authorAssociation, and thepayloadJson/linkedIssuesJson/linkedIssueClaimedAttrio — the body-derived group must move together, like the existingpreserveSparseBodyblock.