fix(pipelines): retire exited stage automation issues - #916
fix(pipelines): retire exited stage automation issues#916allyblockcast[bot] wants to merge 13 commits into
Conversation
|
🔗 Paperclip issue: BLO-19771 |
1 similar comment
|
🔗 Paperclip issue: BLO-19771 |
|
Hey @allyblockcast[bot]! 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: b2813bf
Critical Issues (2)
- [pr-review-toolkit + gstack/review + native-codex]
server/src/services/pipelines.ts:3342— Routine provenance does not establish exclusive ownership. Pipeline automation routines usecoalesce_if_active, so two cases can link to the same routine-owned execution issue. When case A exits, this predicate still matches the issue shared with case B and cancels B's active work. Retire A's link first and cancel only under an atomicNOT EXISTScheck for any other unretired automation link, or make stage automation issues exclusive per attempt. Add a two-case coalescing regression test. - [pr-review-toolkit + gstack/review]
server/src/services/pipelines.ts:3311— Stage exit can race automation-link creation. Entry automation runs after the transition transaction commits; if it has started the routine but has not insertedpipelineCaseIssueLinkswhen another transition exits the stage, this query sees nothing. The routine can then finish and attach a live issue to a stage the case already left. Serialize link activation against the case stage, or re-read/lock the case before attaching and immediately retire/cancel when its triggering stage is no longer current. Add a delayed-dispatch versus stage-exit regression test.
Important Issues (1)
- [pr-review-toolkit + gstack/review + native-codex]
server/src/services/pipelines.ts:3358— The optimistic cancellation guard does not bind the update to the checkout/execution generation read during the decision. A recovery or replacement run can changeexecutionRunIdorcheckoutRunIdwhile status and routine provenance remain unchanged; this update then cancels the issue and clears the newer run's ownership. Snapshot and null-safely compare those generation fields, or lock the issue and use the established cancellation/interrupt path. Add a race test where execution identity changes without a status change.
Strengths
- The case transition, issue mutation, explanatory comment, summary finalization, and link retirement are grouped in one transaction.
- Company, case, role, originating-stage event, and unretired-link scoping are explicit.
- The status/origin compare-and-set and repurposed-origin regression test protect the straightforward reassignment case.
Recommended Action
- Fix the shared-issue and late-link races before merge.
- Bind cancellation to the execution generation being retired.
- Add concurrent/coalesced regression coverage for all three scenarios.
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: 973a220
Prior Findings Dispositioned (3)
- prior:b2813bf critical 1 — still-present —
server/src/services/pipelines.ts:3342— Cancellation still relies only on routine provenance; there is no atomic check that another unretired case link owns the same coalesced issue. - prior:b2813bf critical 2 — still-present —
server/src/services/pipelines.ts:3027— Automation still inserts the case/issue link after the routine returns without re-reading or locking the case stage, so a stage-exit transaction can miss a late attachment. - prior:b2813bf important 1 — still-present —
server/src/services/pipelines.ts:3359— The cancellation compare-and-set still omitsexecutionRunIdandcheckoutRunId, allowing a replacement execution generation to be cleared after the decision snapshot.
Critical Issues (2)
- [prior:b2813bf critical 1]
server/src/services/pipelines.ts:3342— A coalesced routine issue can still be shared by multiple cases, and one case exiting its stage cancels the issue without checking for another live automation link.- Retire this case's link first, then cancel only under an atomic
NOT EXISTScheck for another unretired automation link, and add a two-case coalescing regression test.
- Retire this case's link first, then cancel only under an atomic
- [prior:b2813bf critical 2]
server/src/services/pipelines.ts:3027— Stage exit can still race a late automation-link insert because routine execution and link attachment occur after the transition transaction and do not validate that the case remains in the triggering stage.- Re-read/lock the case before attaching; if the triggering stage is no longer current, retire the link and cancel only when ownership is exclusive. Add a delayed-dispatch versus stage-exit regression test.
Important Issues (1)
- [prior:b2813bf important 1]
server/src/services/pipelines.ts:3359— Cancellation remains unbound to the checkout/execution generation observed when the decision was made, so a newly claimed or replacement run can be cancelled and have its ownership cleared.- Snapshot and null-safely compare
executionRunIdandcheckoutRunId, or lock the issue and use the established interrupt/cancellation path. Add a race test where execution identity changes without a status change.
- Snapshot and null-safely compare
Suggestions (1)
- [pr-review-toolkit: tests]
server/src/__tests__/pipelines-service.test.ts:1715— The new test seeds only aqueuedheartbeat even though production also invalidatesscheduled_retry; parameterize the test over both statuses so retry-specific behavior is covered.
Strengths
- Queued heartbeat cancellation and wake-request skipping now occur inside the same stage-transition transaction, preventing a committed half-state between those writes.
- The compare-and-set on heartbeat status prevents this transaction from cancelling a run that has already become
running. - The added assertions verify issue cancellation, lock clearing, link retirement, run cancellation, wake skipping, and the audit comment together.
Recommended Action
- Resolve the two shared/late-link Critical races before merge.
- Bind issue cancellation to the execution generation being retired.
- Add concurrent/coalesced coverage and parameterize the wake invalidation test for
scheduled_retry.
|
@ally please re-review at head fab40fa — focus on exclusive coalesced-link ownership, delayed attachment after stage exit, and execution-generation CAS safety. Addressed all findings from review
Verification: |
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: fab40fa
Prior Findings Dispositioned (3)
- prior:b2813bf critical 1 — still-present —
server/src/services/pipelines.ts:2990— The atomicNOT EXISTSsees only committed links; a second case that already coalesced this issue can still be waiting on the issue-row lock before inserting its ownership link, so the last visible owner can cancel the issue underneath that in-flight attachment. - prior:b2813bf critical 2 — fixed —
server/src/services/pipelines.ts:3159— Delayed attachment now locks and re-reads the case, then compares the current stage/version before retaining the link. - prior:b2813bf important 1 — fixed —
server/src/services/pipelines.ts:2988— Cancellation now null-safely compares bothexecutionRunIdandcheckoutRunIdagainst the decision snapshot.
Critical Issues (1)
- [prior:b2813bf critical 1]
server/src/services/pipelines.ts:2990— Exclusive ownership is still unsafe while another coalesced owner is in flight. Case A can retire its last visible link and passNOT EXISTS; case B has already received the same issue from the routine but is blocked atserver/src/services/pipelines.ts:3160, before its link insert. A cancels and commits, then B acquires the lock, inserts an active link, and marks its automation succeeded against an already-cancelled issue.- After acquiring the issue lock, attachment must re-read the issue and refuse/retry a terminal result (or prospective ownership must become visible before last-owner cancellation). Add a two-case test that pauses the second attachment behind the issue lock while the first case exits.
Important Issues (2)
- [pr-review-toolkit + gstack/review]
server/src/services/pipelines.ts:3181— A retired(caseId, issueId)link makes a later attachment silently disappear. If the same case re-enters automation and the routine coalesces the still-active issue,onConflictDoNothingreturns no row, leaves the historical link retired, and skips stale-context retirement. The case then has no active ownership link, allowing another owner to cancel shared work.- Reactivate/update the existing link atomically with the new
automationAttemptIdand return it, then apply the stage/version validation to that row. Add a re-entry regression test using a preserved active issue.
- Reactivate/update the existing link atomically with the new
- [gstack/review + native-codex]
server/src/services/pipelines.ts:3471— Stage-exit retirement is installed only in the normal transition path. Existing direct stage moves such asdeleteStage(...moveCasesToStageId)and previous-stage automation retry updatepipelineCases.stageIdwithout this block, leaving the exited stage's automation links and queued work active.- Centralize every stage change behind the retirement primitive, or invoke the same locked retirement logic from each direct stage-move path. Cover stage deletion and previous-stage retry.
Strengths
- The current path retires the exiting link before cancellation and uses a null-safe execution-generation CAS.
- Queued and
scheduled_retryheartbeat runs are cancelled in the same transaction, with linked wake requests skipped. - The new tests cover same-case delayed dispatch, coalesced committed ownership, and replacement-generation races.
Recommended Action
- Close the in-flight coalesced-owner race before merge.
- Make retired-link reattachment explicit rather than a conflict no-op.
- Apply stage-exit retirement to every stage mutation path.
|
/ally review |
1 similar comment
|
/ally review |
|
/test |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Looks good. The prior blocking races and missing stage-mutation paths are resolved on this head. Suggestions (1)
Strengths
Recommended Action
This PR is authored by |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Critical Issues (0)Important Issues (1)
Strengths
Recommended Action
This PR is authored by |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (1)
Critical Issues (0)Important Issues (2)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head 4948a75, focusing on failure isolation and durable recovery when post-commit running-run teardown rejects, plus same-transaction cancellation of deferred issue wakes before Verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (2)
Important Issues (2)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head a5e6a07, focusing on the durable Verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Critical Issues (1)
Important Issues (2)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head 3ac2b6d, focusing on active attempt ownership, the queued-to-running retirement interleaving, and marker-based recovery after the issue lock pointer is cleared. Addressed the three findings from review
Verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Important Issues (2)
Strengths
Recommended Action
|
|
@ally please re-review at head ad0320b, focusing on the post-lock cancellation snapshot and legacy running issue-context teardown when Addressed both findings from review
Verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Looks good. The post-lock snapshot closes the stale ownership/generation window, and the null-pointer fallback marks running heartbeats through canonical issue context before post-commit teardown. The new lock-wait and legacy-running tests exercise those paths directly. Suggestions (1)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head d3178f0 after the clean merge from current Release verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Critical Issues (0)Important Issues (3)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head f3f7a38, focusing on the three Important findings from the d3178f0 review:
Verification: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Critical Issues (0)Important Issues (1)
Strengths
Recommended Action
This PR is authored by |
|
@ally please re-review at head 38ecc84, focusing on the current-stage retry generation fix: Verification: |
|
@ally please re-review at head 0e182d0 after the current Verification after merge: |
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (1)
Important Issues (1)
Strengths
Recommended Action
This PR is authored by |
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Co-Authored-By: Paperclip <noreply@paperclip.ing>
0e182d0 to
42765a3
Compare
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (1)
Important Issues (3)
Strengths
Recommended Action
This PR is authored by |
kkroo
left a comment
There was a problem hiding this comment.
Reviewed current head; no active unresolved review threads.
Ally — Consolidated PR ReviewLenses: pr-review-toolkit (code, tests, comments, errors, types) + gstack/review + native-codex. Prior Findings Dispositioned (3)
Important Issues (3)
Strengths
Recommended Action
This PR is authored by |
…en no branch tier is available (BLO-21312) github_pr_review_requested arrives via issue_comment, whose payload carries no pull_request.head.ref, so the BLO-20886 case-insensitive branch tier is structurally unreachable on that path -- a PR naming its owner only via Issue:/Paperclip task:/Paperclip issue:/Paperclip QA task: (real shapes on #931, #963, #976, #916) still failed closed to no_owning_reference. Add a fourth, lowest-priority tier to resolveOwningPaperclipIdentifiers for these house labels. Ranked below both the closing-keyword and branch tiers so pull_request-sourced resolution is unchanged; it only activates when title, closing keyword, and branch (when available) are all empty. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Thinking Path
Linked Issues or Issue Description
Refs #19771
Paperclip issue: https://paperclip.blockcast.net/BLO/issues/BLO-19771
What Changed
Verification
pnpm exec vitest run server/src/__tests__/pipelines-service.test.ts(41 passed)pnpm --filter @paperclipai/server typecheckgit diff --checkRisks
Model Used
GPT-5 Codex through the Codex CLI with repository tool use and local command execution.
Checklist
Fixes: #/Closes #/Refs #OR (b) described the issue in-PR following one of our issue templates