Problem
Thread ccb18d07 (connector handle 9380eb6c, Discord message.received) accumulated 77 messages over 8 days (2026-07-10 to 2026-07-18) and never generated a threads.summary. The summary and summary_through columns remained NULL throughout.
Without a summary, context quality degrades with every wakeup — the model works from raw messages with no compaction, and the cross-thread summary injection (#178) cannot surface the thread's state to siblings.
Two contributing mechanisms
1. Backend acquisition may silently fail
agent-loop.ts:252 calls this.acquireSummaryBackend(summaryModelId) where summaryModelId = this.modelRouter.getDefaultId() (line 246). If the default model is not resolvable from the spoke where the event task runs, acquireSummaryBackend returns null and extraction is skipped entirely:
// agent-loop.ts:265-269
} else {
this.ctx.logger.info("Skipping summary extraction — model unresolvable cluster-wide", {
threadId: this.config.threadId,
summaryModelId,
});
}
The summary backend uses the default model ID, not the model that was actually routed for the turn. Event-task threads on spokes may hit this path if the default model is local-only and the spoke has no local backends, even though the turn itself ran on a remote model successfully.
2. Regeneration throttle requires role: "user" messages
summary-extraction.ts:243-250 gates regeneration on a role: "user" message existing after summary_through:
const previousSummary = thread.summary;
if (previousSummary) {
const hasNewUserMessage = messages.some((m) => m.role === "user");
if (!hasNewUserMessage) {
return { ok: true, value: { summaryGenerated: false, memoriesExtracted: 0 } };
}
}
Event-task threads do not produce role: "user" messages. Their events arrive as role: "developer" wakeups ([Task wakeup] Scheduled event task ... triggered) and tool_result payloads (connector event XML). So even if the first summary fires (the first-run path at line 289 does not check for user messages), all subsequent regeneration is permanently blocked.
Suggested fix
- For mechanism (1): use the turn's resolved model (or the last successfully used model) for summary extraction instead of
getDefaultId().
- For mechanism (2): broaden the regeneration trigger for event-task threads to include
role: "developer" messages, or use a different trigger signal (new tool_result messages, or a message-count threshold relative to summary_through).
Problem
Thread
ccb18d07(connector handle9380eb6c, Discordmessage.received) accumulated 77 messages over 8 days (2026-07-10 to 2026-07-18) and never generated athreads.summary. Thesummaryandsummary_throughcolumns remained NULL throughout.Without a summary, context quality degrades with every wakeup — the model works from raw messages with no compaction, and the cross-thread summary injection (#178) cannot surface the thread's state to siblings.
Two contributing mechanisms
1. Backend acquisition may silently fail
agent-loop.ts:252callsthis.acquireSummaryBackend(summaryModelId)wheresummaryModelId = this.modelRouter.getDefaultId()(line 246). If the default model is not resolvable from the spoke where the event task runs,acquireSummaryBackendreturnsnulland extraction is skipped entirely:The summary backend uses the default model ID, not the model that was actually routed for the turn. Event-task threads on spokes may hit this path if the default model is local-only and the spoke has no local backends, even though the turn itself ran on a remote model successfully.
2. Regeneration throttle requires
role: "user"messagessummary-extraction.ts:243-250gates regeneration on arole: "user"message existing aftersummary_through:Event-task threads do not produce
role: "user"messages. Their events arrive asrole: "developer"wakeups ([Task wakeup] Scheduled event task ... triggered) andtool_resultpayloads (connector event XML). So even if the first summary fires (the first-run path at line 289 does not check for user messages), all subsequent regeneration is permanently blocked.Suggested fix
getDefaultId().role: "developer"messages, or use a different trigger signal (newtool_resultmessages, or a message-count threshold relative tosummary_through).