fix(recovery): preserve lock handover evidence (BLO-19160) - #1489
Conversation
Co-Authored-By: Paperclip <noreply@paperclip.ing>
|
Hey @kkroo! Before this PR can be reviewed, a few things need attention: Missing or incomplete:
Once updated, push a new commit and these checks will re-run automatically. — commitperclip |
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 412bec9
Critical Issues (0)
Important Issues (1)
- [native-codex]
server/src/services/recovery/service.ts:6104— the new lock-owner check is not atomic with the recovery side effects it is intended to protect. After this read returns,adoptStaleCheckoutRuncan commit a new owner beforeensureSourceScopedStrandedRecoveryAction,ensureProviderQuotaWaitRecoveryMonitor,enqueueSourceScopedStrandedRecoveryWake, or the later issue update run. The later assignee/status checks do not undo an already-created recovery action, monitor, or wake, so a live adopter can still receive competing recovery work or leave stale escalation artifacts.- Move the handover decision and all dependent mutations behind a shared row/advisory lock or add a mutation-time compare-and-set/rollback path that prevents action, monitor, and wake creation when ownership changes. The PR's limitation note correctly identifies this race, but leaving it open means the handover safety guarantee remains incomplete.
Suggestions (0)
Strengths
- The handover marker is now used as issue-scoped retry provenance instead of borrowing terminal evidence from the adopter's other issue.
- The regression coverage checks foreign non-retryable/quota outcomes and adoption interleaving with a live owner.
Recommended Action
- Fix the Important issue before merge.
- Re-run the focused recovery tests and typecheck after the synchronization change.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: df89ec6
Prior Findings Dispositioned (1)
- prior:412bec9 important 1 — still-present —
server/src/services/recovery/service.ts:6643— the post-commit recovery wake still relies on a read-then-enqueue check.enqueueSourceScopedStrandedRecoveryWakecallsissueLockOwnerStateChangedbeforeenqueueWakeup, but adoption can commit after that read and before the enqueue, allowing a competing recovery wake to be created for an issue now owned by the adopter. The quota-monitor path is serialized, but this wake path still needs the shared advisory/row lock or a mutation-time compare-and-set guard.
Critical Issues (0)
Important Issues (1)
- [prior:412bec9]
server/src/services/recovery/service.ts:6643— the post-commit recovery wake remains vulnerable to the ownership handover race described above. The read-only guard atserver/src/services/recovery/service.ts:2307does not make the subsequent enqueue atomic.- Hold the ownership lock through wake creation, or make the enqueue operation itself conditionally reject when the expected lock/owner tuple no longer matches.
Suggestions (0)
Strengths
- The handover marker is now treated as issue-scoped provenance rather than foreign adopter evidence.
- The quota-monitor callback now rechecks the issue and action while holding the shared ownership lock, preventing stale monitor creation.
- The regression tests cover foreign failure/quota outcomes and adoption interleavings.
Recommended Action
- Fix the Important issue before merge.
- Re-run the focused recovery tests and typecheck after making wake creation atomic.
- Consider Suggestions opportunistically.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 8e08e7b
Prior Findings Dispositioned (1)
- prior:412bec9 important 1 — fixed —
server/src/services/recovery/service.ts:2459—enqueueSourceScopedStrandedRecoveryWakenow revalidates the expected lock/owner tuple through the ownership-serialized wake path before enqueueing; the post-commit call site atserver/src/services/recovery/service.ts:6643passes that expected state.
Critical Issues (0)
Important Issues (1)
- [native-codex]
server/src/services/recovery/service.ts:5903— the new outer transaction changes the transaction boundary used byresolveContinuationWaitingOnReview, and the existing server regression test now fails before it reaches the intended cycle-forming relation error path. CI reportsheartbeat-process-recovery.test.ts:6329throwingError: Blocking relations cannot contain cycles; the test expects the helper to catch the write-time cycle and park the issue inin_review, but the mockeddb.transactionnow intercepts this newly added outer transaction instead. This leaves the current PR with a failing server test shard.- Preserve the intended production transaction structure while updating the regression seam to inject the cycle at the actual relation-write/update boundary, or otherwise make the cycle-error test exercise the refactored transaction path. Re-run the affected server tests and the full test shard until green.
Suggestions (0)
Strengths
- Handover provenance is now kept scoped to the source issue instead of borrowing terminal evidence from the adopter's other issue.
- Ownership-sensitive recovery mutations use a shared advisory lock, row locks, and expected-state checks across escalation, monitor creation, and wake dispatch.
- The regression coverage now exercises foreign failure/quota outcomes, stale-snapshot adoption, stale wake refunds, and rollback behavior.
Recommended Action
- Fix the Important issue before merge.
- Re-run the focused recovery tests and the full server test shard.
- Consider Suggestions opportunistically.
There was a problem hiding this comment.
Ally — Consolidated PR Review
Lenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex.
Reviewed head: 24e8ab5
Critical Issues (0)
Important Issues (0)
Suggestions (0)
Strengths
- Handover evidence remains scoped to the source issue rather than borrowing terminal outcomes from a foreign adopter run.
- Ownership-sensitive recovery mutations are serialized with shared advisory locks, row locks, and expected-state checks.
- Recovery action, monitor, wake, blocker, comment, and activity paths have targeted regression coverage, including rollback and interleaving cases.
Recommended Action
- No blocking changes identified; the PR is suitable for merge.
Thinking Path
Linked Issues or Issue Description
What Changed
Verification
pnpm --filter @paperclipai/server typecheckissue-recovery-actions.test.tssuite: 115 tests passed in the prepared verification run.git diff --checkRisks
Model Used
Checklist