diff --git a/src/core/minions/handler-timeouts.ts b/src/core/minions/handler-timeouts.ts index 8269add1e..4523664df 100644 --- a/src/core/minions/handler-timeouts.ts +++ b/src/core/minions/handler-timeouts.ts @@ -43,6 +43,11 @@ export const HANDLER_DEFAULT_TIMEOUT_MS: Readonly> = { // few writes. Generous 10-min budget (vs the tight null-default) covers a // slow gateway without the 30-min loop budget. chronicle_extract: TEN_MIN_MS, + // #3207 — same shape as chronicle_extract: one page = one LLM extraction + // call + a few writes. Was missing from this map, so it inherited the tight + // null-default and got dead-lettered mid-generation on slow chat providers + // (facts silently lost) — exactly the failure this file exists to prevent. + 'facts-absorb': TEN_MIN_MS, // Per-page contextual reindex jobs process chunks sequentially with one // rate-leased LLM synopsis call per chunk; large transcript pages need more // than the standard 30-min long-job budget. diff --git a/test/minions.test.ts b/test/minions.test.ts index 90148361e..afeabe15c 100644 --- a/test/minions.test.ts +++ b/test/minions.test.ts @@ -354,6 +354,15 @@ describe('MinionQueue: #1737 per-handler default timeout', () => { expect(sub.timeout_ms).toBe(30 * 60 * 1000); }); + // #3207 — facts-absorb is one LLM extraction call per page (same shape as + // chronicle_extract) but was missing from HANDLER_DEFAULT_TIMEOUT_MS, so it + // inherited the tight null-default wall-clock and was dead-lettered + // mid-generation on slow chat providers (facts silently lost). + test('facts-absorb gets the 10-min LLM-extraction default (#3207)', async () => { + const job = await queue.add('facts-absorb', { slug: 'people/alice-example' }); + expect(job.timeout_ms).toBe(10 * 60 * 1000); + }); + test('contextual per-chunk reindex gets the 60-min default', async () => { const job = await queue.add('contextual_reindex_per_chunk', { page_slug: 'large-transcript' }, undefined, { allowProtectedSubmit: true,