Parent
Part of #25 (Screen Solver v1: implementation spec), itself under the map #1.
What to build
Durable memory of what the app has done, independent of whether anyone was watching. Two append-only JSONL files under the state root: answers.jsonl gets one entry per done or interrupted outcome only — never for a bail (# No exercise on screen) or an error — holding title (the answer's # heading), final answer text only (no delta history, no image), timestamp, model, usage, source window identity, and an interrupted: true tag where applicable. usage.jsonl gets one entry per attempted call, every outcome including bail and error, always recording usage/cost regardless of content — pure observability, nothing reads the running total to cap or throttle anything. GET /answers serves the full answers.jsonl backlog as a JSON array, independent of the live /events connection. A client connecting to /events while a solve is already in flight receives sync{text} — the accumulated text so far — in place of start.
Acceptance criteria
Blocked by
#29 (Solve loop over HTTP + SSE) — needs real done/interrupted/error/bail outcomes to persist.
Parent
Part of #25 (Screen Solver v1: implementation spec), itself under the map #1.
What to build
Durable memory of what the app has done, independent of whether anyone was watching. Two append-only JSONL files under the state root:
answers.jsonlgets one entry perdoneorinterruptedoutcome only — never for a bail (# No exercise on screen) or anerror— holding title (the answer's#heading), final answer text only (no delta history, no image), timestamp, model, usage, source window identity, and aninterrupted: truetag where applicable.usage.jsonlgets one entry per attempted call, every outcome including bail and error, always recording usage/cost regardless of content — pure observability, nothing reads the running total to cap or throttle anything.GET /answersserves the fullanswers.jsonlbacklog as a JSON array, independent of the live/eventsconnection. A client connecting to/eventswhile a solve is already in flight receivessync{text}— the accumulated text so far — in place ofstart.Acceptance criteria
done) appends exactly oneanswers.jsonlentry with all specified fields, and exactly oneusage.jsonlentry.answers.jsonlentry taggedinterrupted: true, plus its ownusage.jsonlentry.# No exercise on screen) appends ausage.jsonlentry but noanswers.jsonlentry.error) appends ausage.jsonlentry but noanswers.jsonlentry.GET /answersreturns the full current backlog as JSON, matching the contents ofanswers.jsonl./eventsmid-solve receivessync{text}carrying the accumulated text so far, notstart./eventswhen nothing is in flight receives nosyncand simply waits for the nextstart.Blocked by
#29 (Solve loop over HTTP + SSE) — needs real
done/interrupted/error/bail outcomes to persist.