blocked issue: an assignee's own blocked write re-arms its own wake (neither wake deduplicates)
What happens
An issue whose assignee blocks its own issue — with itself as unblockDescriptor.owner, and/or with an already-done blocker — gets woken about its own write, and the wake never deduplicates. The agent runs, re-asserts blocked with a near-identical comment, that write refreshes blockedTransitionAt, and the next wake is armed again. Observed in our self-hosted instance: one run every ~30 s, each succeeding, comment count climbing (issue ran >40 near-identical "still holds blocked" comments before we paused the agent).
The two wakes
server/src/routes/issues.ts— therestoredBlockedReadyDependencybranch callsaddDependencyResolvedWakeup({ ..., source: "issue.blockers_restored" })for the assignee. It fires whenissue.status === "blocked"and the transition was made by the assignee itself.server/src/services/routable-blocked.ts—deliverAgentUnblockNotificationwakesunblockDescriptor.ownerwithreason: "issue_unblock_requested"andidempotencyKey: \issue-unblock:${issue.id}:${issue.blockedTransitionAt.toISOString()}``. When the owner is the assignee, the assignee is woken by its own write.
Both keys embed blockedTransitionAt, which the triggering write itself refreshes, so neither wake can ever be deduplicated.
Proposed fix
Suppress both wakes when the wake target is the acting assignee, and log the suppression (so a genuinely stuck assignee is still diagnosable):
// routes/issues.ts, before the dependency-readiness wake
const dependencyWakeIsAssigneeSelfWrite =
restoredBlockedReadyDependency &&
actor.actorType === "agent" &&
actor.agentId === issue.assigneeAgentId;
if (dependencyWakeIsAssigneeSelfWrite) {
logger.info({ issueId: issue.id, agentId: actor.agentId, runId: actor.runId },
"suppressed blockers-restored wake for the assignee's own blocked-state write");
}
if (restoredBlockedReadyDependency && !dependencyWakeIsAssigneeSelfWrite && ...) { ... }
// services/routable-blocked.ts, after the owner check
if (issue.assigneeAgentId && owner.agentId === issue.assigneeAgentId) return false;
Unit test added in server/src/__tests__/routable-blocked.test.ts: an assignee that named itself returns false and neither wakeup nor markNotified is called. I verified it fails without the guard and passes with it.
Related
#10361 and #12098 cover the same corner from the other side: an agent may only name itself as unblockDescriptor.owner (403), so blocking on a human is not expressible for an agent — which is what pushes agents into these self-owned descriptors in the first place.
Source: paperclipai/paperclip