diff --git a/src/research.ts b/src/research.ts index 04ca3e2..07d3fd4 100644 --- a/src/research.ts +++ b/src/research.ts @@ -657,8 +657,14 @@ export function recoverRun( } } // The most recent unfinished attempt at this question, if there is one. + // Notes are what makes an attempt worth resuming, and a ledger without them + // is worse than nothing: the pages count as spent against the source budget, + // and the synthesizer is handed a numbered source list it has no notes about, + // so nothing can cite them. Runs from before workers filed their notes into + // the log look exactly like this — a real one in this database had 84 pages + // read and not a word recovered. Start those over. const candidates = [...attempts.values()].filter( - (a) => !a.done && a.question === question && (a.byAngle.size > 0 || a.ledger.length > 0), + (a) => !a.done && a.question === question && a.byAngle.size > 0, ); const last = candidates[candidates.length - 1]; if (!last) return null; diff --git a/tests/research.test.ts b/tests/research.test.ts index 78fc5b1..2cc2fd5 100644 --- a/tests/research.test.ts +++ b/tests/research.test.ts @@ -693,3 +693,17 @@ test("a resumed run sends a worker back to an angle that only jotted", async () .map((p) => (p.data as { angle: string }).angle); expect(angles).toEqual(["the open angle"]); // reopened, not skipped }); + +test("an attempt with pages but no notes is not resumed", () => { + // Found against the real database: runs from before workers filed notes into + // the log recover a ledger and nothing else. Inheriting that means the pages + // count as spent while nothing was learned from them, and the synthesizer + // gets a source list it cannot cite — strictly worse than starting over. + const events = [ + progressEvent("planning", { question: "what happened" }), + progressEvent("read", { url: "https://a.test", title: "A" }), + progressEvent("read", { url: "https://b.test", title: "B" }), + progressEvent("agent-done", { agent: 0 }), // the old payload: no notes + ]; + expect(recoverRun(events, "what happened")).toBeNull(); +});