From 02b2fecdf7a08221da7493e3442768586cd7ec59 Mon Sep 17 00:00:00 2001 From: Van Echeverri Date: Wed, 3 Jun 2026 06:42:40 -0400 Subject: [PATCH 1/2] fix: resolve missing_disposition recovery loop for blocked issues with active blockers When an issue is `blocked` with unresolved first-class blockers, it has a valid disposition. But `classifySourceRecoveryRevalidation()` gated the `blocked + unresolvedBlockerCount > 0` check behind `durableSourceChange`, which was only true when status/assignee/blockers/etc. actually changed in the PATCH. Heartbeat comment-only PATCHes had `durableSourceChange = false`, so the function returned `null` (no resolution) even though the issue was correctly blocked. This caused a `missing_disposition` recovery action to stay `active` indefinitely, waking the agent on every scheduler tick. Fix: move the `blocked + unresolvedBlockerCount > 0` check before the `read_projection` early-return gate so it fires on every revalidation regardless of what changed. A blocked issue with active blockers always has a valid disposition. Co-Authored-By: Paperclip --- server/src/routes/issues.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server/src/routes/issues.ts b/server/src/routes/issues.ts index 85492638c7..1a39da5c9c 100644 --- a/server/src/routes/issues.ts +++ b/server/src/routes/issues.ts @@ -995,6 +995,17 @@ export function issueRoutes( return "Recovery action became stale because the source issue was manually moved from blocked to todo."; } + // Check blocked+blockers before any trigger-based early returns: a blocked issue with + // active first-class blockers always has a valid disposition regardless of what changed. + // This prevents recovery-action loops where the issue is correctly blocked but the + // missing_disposition action stays active because no "durable change" has occurred. + if (issue.status === "blocked") { + const readiness = await svc.getDependencyReadiness(issue.id); + if (readiness.unresolvedBlockerCount > 0) { + return "Recovery action became stale because the source issue now has unresolved first-class blockers."; + } + } + if (input.trigger === "read_projection") return null; if ( input.trigger === "comment" && From e1d83c565755ce9b44536d7d2d15a44c501f5609 Mon Sep 17 00:00:00 2001 From: Van Echeverri Date: Sun, 7 Jun 2026 22:33:40 -0400 Subject: [PATCH 2/2] fix(inbox-lite): include in_review issues in agent compact inbox GET /api/agents/me/inbox-lite previously returned only todo, in_progress, and blocked issues. When a board comment triggered a heartbeat wake on an in_review issue, the agent's inbox scan would not find the issue, causing it to exit with "no actionable work" and post nothing. Add in_review to the status filter so all non-terminal agent-owned issues are visible in both the fast path (PAPERCLIP_TASK_ID check) and the broad path (inbox-lite scan). Fixes: INTA-271 Co-Authored-By: Paperclip --- server/src/routes/agents.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/routes/agents.ts b/server/src/routes/agents.ts index 05c1675e4b..0bcba37617 100644 --- a/server/src/routes/agents.ts +++ b/server/src/routes/agents.ts @@ -1740,7 +1740,7 @@ export function agentRoutes( const recoveryActionsSvc = issueRecoveryActionService(db); const rows = await issuesSvc.list(req.actor.companyId, { assigneeAgentId: req.actor.agentId, - status: "todo,in_progress,blocked", + status: "todo,in_progress,blocked,in_review", includeRoutineExecutions: true, limit: ISSUE_LIST_DEFAULT_LIMIT, });