Skip to content

Adding/removing a linked-issue reference resets linkedIssueClaimedAt for the WHOLE PR, letting a later PR steal duplicate-winner priority #6404

Description

@JSONbored

Severity: CRITICAL
Location: src/db/repositories.ts:460

Found via a full-system adversarial audit of the ORB review/scoring engine (2026-07-15) — 2 independent skeptic passes, both had to vote "confirmed" for this to survive.

Failure scenario

resolveLinkedIssueClaimedAt (src/db/repositories.ts:460-479) stamps a single PR-level linkedIssueClaimedAt timestamp, and resets it to now whenever the PR's linked-issue SET changes at all (sameLinkedIssueSet compares the full set, not per-issue) — confirmed by the existing test at test/unit/db-parsers.test.ts:193-208 ('Expanded claim'). Concretely: PR #100 opens with body 'Closes #10' at T1 -> linkedIssueClaimedAt=T1. PR #200 opens later with body 'Closes #10' at T3 (T3>T1) -> linkedIssueClaimedAt=T3. At this point isDuplicateClusterWinnerByClaim (packages/loopover-engine/src/duplicate-winner.ts:57-78) correctly elects PR #100 as winner (earliest claim). Later, PR #100's author pushes an unrelated, well-intentioned update that also references a second issue, e.g. 'Closes #10, Closes #30', at T4 (T4>T3). Because the linked-issue SET changed ([10] -> [10,30]), resolveLinkedIssueClaimedAt discards T1 and re-stamps PR #100's claim at T4 for its ENTIRE linked-issue set, including #10. On the next duplicate-cluster evaluation, PR #200 (T3) now precedes PR #100 (T4), so PR #200 becomes the elected winner and PR #100 -- the PR that actually claimed issue #10 first -- is treated as the loser and auto-closed as a duplicate via the duplicate_pr_risk path (src/queue/duplicate-detection.ts:27-40, packages/loopover-engine/src/signals/engine.ts's isPullRequestInDuplicateCluster).

Impact

A legitimate contributor's PR that genuinely claimed an issue first can be auto-closed as a 'duplicate of another open PR' purely because they later added an unrelated second issue reference to the body -- the exact kind of backdating-immune priority theft the claim-time design (explicitly documented in packages/loopover-engine/src/duplicate-winner.ts's module doc) was built to prevent, just triggered from the opposite direction. Per this repo's own gate semantics, a contributor PR close is one-shot/unrecoverable, so the wronged contributor has no path back except opening a brand-new PR.

Metadata

Metadata

Assignees

Labels

maintainer-onlyOwner-only work — yields no Gittensor points.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions