Preserve accepted messages for paused recipients (#16679)

Keep accepted deferred requests pending while their recipient is paused and deliver through normal gates after resume. Preserve company, task hold, and cleanup checks.

Verification: 247 focused checks, recursive typecheck, the full CI test and build matrix, and Apex 5/5. The local Git fixture initial-branch limitation is documented in the PR.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Devin FoleyandPaperclip authored and GitHub committed 2026-10-17 18:38:17 -07:00
1 parent 391dd15ff2
commit d30648dee8
11 files changed
+133 -8

No files matched your search

@@ -247,6 +247,28 @@ describe("decideWakeOutcome", () => {
facts: { ...baseWakeOutcomeFacts, agent: { agentFound: false, invokable: false } },
expected: { kind: "fail_not_invokable" },
},
{
name: "defer_agent_pause: a paused recipient keeps its accepted request",
facts: { ...baseWakeOutcomeFacts, agent: { agentFound: true, invokable: false, paused: true } },
expected: { kind: "defer_agent_pause" },
},
{
name: "fail_not_invokable: a pause cannot authorize a missing recipient",
facts: { ...baseWakeOutcomeFacts, agent: { agentFound: false, invokable: false, paused: true } },
expected: { kind: "fail_not_invokable" },
},
{
name: "cancel_pause_hold: an explicit task hold still suppresses a paused recipient",
facts: { agent: { agentFound: true, invokable: false, paused: true },
pauseHold: { activePauseHold: true, treeHoldInteractionWake: false } },
expected: { kind: "cancel_pause_hold" },
},
{
name: "defer_agent_pause: a permitted tree interaction cannot invoke a paused agent",
facts: { agent: { agentFound: true, invokable: false, paused: true },
pauseHold: { activePauseHold: true, treeHoldInteractionWake: true } },
expected: { kind: "defer_agent_pause" },
},
{
name: "fail_not_invokable: the agent is found but not invokable",
facts: { ...baseWakeOutcomeFacts, agent: { agentFound: true, invokable: false } },
@@ -142,6 +142,7 @@ export type DeferredWakeAgentFacts = {
agentFound: boolean;
/** True when the agent is invokable (status, org chain). Meaningless when agentFound is false. */
invokable: boolean;
paused?: boolean;
};
export type DeferredWakePauseHoldFacts = {
@@ -158,6 +159,7 @@ export type DeferredWakeOutcomeFacts = {
export type DeferredWakeOutcomeDecision =
| { kind: "fail_not_invokable" }
| { kind: "defer_agent_pause" }
| { kind: "cancel_pause_hold" }
| { kind: "promote" };
@@ -180,11 +182,10 @@ export function decideQueuedCommentAction(
return { kind: "proceed" };
}
/** Decides the outcome for a deferred wake whose queued-comment action resolved to "proceed" (or finished its rewrite): fail, cancel, or promote. */
export function decideWakeOutcome(facts: DeferredWakeOutcomeFacts): DeferredWakeOutcomeDecision {
const { agent, pauseHold } = facts;
if (!agent.agentFound || !agent.invokable) {
if (!agent.agentFound || (!agent.invokable && !agent.paused)) {
return { kind: "fail_not_invokable" };
}
@@ -192,6 +193,8 @@ export function decideWakeOutcome(facts: DeferredWakeOutcomeFacts): DeferredWake
return { kind: "cancel_pause_hold" };
}
if (agent.paused) return { kind: "defer_agent_pause" };
return { kind: "promote" };
}