#850·openwiki

Page worker ending without submit_page is skipped with no retry; run finalizes interrupted and the documented base never advances

Author: drmikecroweCreated Sep 9, 2026Updated Sep 9, 2026

Description

A page worker whose stream ends without calling submit_page is marked skipped, its snapshot restored, and the run finalizes with status: "interrupted"without advancing the documented base (gitHead in openwiki/.last-update.json) and with openwiki/.run.json deleted. Neither 0.4.3 nor 0.5.0 retries the page. The next --update therefore diffs against the same old base and re-researches the entire changeset again.

For a tool whose architecture is "resumable page jobs, partial progress banked", the missing retry turns a single unlucky final turn into a full-cost regeneration loop.

Observed trigger

A reasoning model that spends its entire completion budget on thinking and returns an empty final message. With glm-5.3-flash (via an Anthropic-compatible endpoint), one failing worker made 94 clean LLM calls, then ended its stream with no text and no tool call — the final turn's AIMessage content blocks are thinking only (diagnosed by pulling the worker's turns from LangSmith and printing the content-block kinds; healthy turns are thinking,tool_use / thinking,text,tool_use). The agent loop simply ends; nothing throws.

Measured cost

Over four consecutive daily runs (2026-09-01..04), each ended interrupted on one such worker, the base stayed frozen at the same commit, and every run re-researched the full 74-file changeset — 8h, then 13h × 3. The completed pages were banked each time, but the un-advanced base means the next run re-derives them anyway. The first run to finalize cleanly took 1.7h for what the frozen-base runs were paying 13h.

A secondary observation, possibly by design but worth a look: a run that finalizes interrupted deletes .run.json, so "rerunning after an interruption resumes the durable queue" holds only for hard kills, not for finalized-interrupted runs — there is nothing left to resume, and the skipped page's work is fully discarded.

Suggested fix

One fresh retry of the page worker before marking it skipped — a new agent instance over the same page job. Transient empty final turns then cost one retry instead of the whole page; the deterministic case still skips as today.

We carry a local patch implementing exactly this (rewrites runPageAgent to construct the worker agent per attempt and retry once when the stream ends without submit_page, preserving the skip path when the retry also fails) and would be glad to turn it into a PR against either line if the approach sounds right.