mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-11-03 17:51:58 +01:00
fix: recover deferred messages and completed unblock waits (#16673)
Recover accepted deferred messages through the latest finished issue run and recognize exact completed agent unblock notifications as passive idle waits. Preserve assignment handoffs, pause and Stop, failed outcomes, and cleanup ownership. Honor local and SSH release contracts and atomically settle cleanup claims. Add PostgreSQL recovery, concurrency, and interruption regressions. Validation: recursive typecheck and build pass; 678 focused tests pass; full CI passes; Apex review is 5/5 with no unresolved findings. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
27ab902d3d
commit
391dd15ff2
19 files changed
+546
-62
No files matched your search
@@ -235,7 +235,7 @@ export interface WakeQueueTransaction {
|
||||
*/
|
||||
export interface IssueLockWriter {
|
||||
withIssueExecutionLock(
|
||||
input: { companyId: string; runId: string; now: Date },
|
||||
input: { companyId: string; runId: string; now: Date; resumeStrandedQueue?: boolean },
|
||||
fn: (
|
||||
locked: LockedIssueExecution,
|
||||
ports: { host: WakeQueueHost; transaction: WakeQueueTransaction },
|
||||
|
||||
@@ -120,6 +120,7 @@ export type ReleaseIssueExecutionInput = {
|
||||
runId: string;
|
||||
now: Date;
|
||||
suppressImmediateRecovery?: boolean;
|
||||
resumeStrandedQueue?: boolean;
|
||||
};
|
||||
|
||||
type PauseHoldFacts = Awaited<ReturnType<WakeQueueTransaction["getPauseHoldFacts"]>>;
|
||||
@@ -200,7 +201,7 @@ async function runReleaseDrain(
|
||||
!candidate.preservesIndependentContinuation && candidate.queuedCommentIds.length > 0 &&
|
||||
["issue_commented", "issue_reopened_via_comment"].includes(candidate.wakeReason ?? candidate.reason ?? "");
|
||||
if (ordinaryTaskComment && candidate.agentId !== issue.assigneeAgentId) {
|
||||
if (run.agentId !== issue.assigneeAgentId) {
|
||||
if (input.resumeStrandedQueue || run.agentId !== issue.assigneeAgentId) {
|
||||
// The old owner can release before assignment admission adopts these
|
||||
// exact IDs. Leave its receipt intact, skip it for this drain, and let
|
||||
// a current-assignee wake behind it proceed.
|
||||
@@ -968,7 +969,8 @@ export function createReleaseIssueExecution(deps: {
|
||||
input: ReleaseIssueExecutionInput,
|
||||
): Promise<{ outcome: ReleaseOutcome; postCommitEffects: PostCommitEffect[] }> {
|
||||
const result = await deps.issueLock.withIssueExecutionLock(
|
||||
{ companyId: input.companyId, runId: input.runId, now: input.now },
|
||||
{ companyId: input.companyId, runId: input.runId, now: input.now,
|
||||
...(input.resumeStrandedQueue ? { resumeStrandedQueue: true } : {}) },
|
||||
(locked, ports) => runReleaseDrain(locked, ports, input),
|
||||
);
|
||||
|
||||
|
||||
Reference in new issue
Block a user