The wave-guard was killed after its 11:13 renewal and never wrote
logs/WAVE5-DONE, despite the worker succeeding at 11:21. That makes this
file's own first-command heuristic actively misleading — "no sentinel +
no processes -> workers were KILLED" would have thrown away a completed,
verified wave. Recorded the reliable signals instead: the size of
logs/<name>.json and the tail of logs/<name>.state.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Explicit pathspec only — a worker is writing to the tree right now
(hazard #7: `git add -A` mid-wave has swept half-finished source into
commits twice on this project).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SPEC now states that a source which could not be reached must never be
reported as a book that does not exist: Found / NotFound / Unavailable,
where NotFound requires every source to have answered authoritatively.
Also records that a rejected barcode must not be silent, and that the
by-ISBN cover URL is not evidence a cover exists.
run-task.sh exports CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0, per the wave-4
post-mortem: `claude -p` otherwise kills background tasks at 600s, so a
worker that backgrounds a Gradle build can never report on it. Safe to
edit now — no workers are running (hazard: never edit it while they are).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDcPottghJXEvfYKqFM7zf
The user supplied the failing ISBNs: 9781883937386 (The Hittite Warrior)
and 9781883937676 (Shadow Hawk), both Bethlehem Books. Both resolve
against the source the app already queries — title, author, publisher,
page count, cover art — and both real responses parse correctly through
the app's own OpenLibraryClient. Captured as fixtures with a regression
test, because these are the specific books that motivated the research.
That kills the coverage hypothesis for these two and demotes Harvard,
which holds neither: its 93% in the sample table is inflated by
construction (the sample was drawn from Harvard) and misleading in
exactly the direction that matters — it is a research library and does
not carry small-press children's historical fiction.
The failure is upstream of the metadata sources. Documented the three
candidates; the leading one is that the barcode never decoded into a
valid ISBN-13, which ScanCodeFilter drops silently with no UI feedback
whatsoever. Revised the recommendation accordingly: make the app say
what happened before adding any source.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDcPottghJXEvfYKqFM7zf
Records the coil3 StateFlow trap (a Kotlin warning, not an error, that
silently blanked every book cover) so a future session greps for it, and
the two Open Library cover defects behind it.
METADATA-SOURCES.md answers the user's research question about
alternative lookup sources: measurements over a 60-ISBN sample drawn
from a third-party catalogue, the options with costs, and a
recommendation to fix diagnosis before buying coverage. Nothing there is
implemented — the user asked to be consulted first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CDcPottghJXEvfYKqFM7zf
Wave 4 is verified complete. Also records the two mechanisms that stopped F3
from reporting (the 600s background-task ceiling in `claude -p`, then the quota
wait) so the next worker launch does not repeat it, and flags the one thing
wave 4 owed and never delivered: nobody has looked at the fourteen new
screenshots.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014TyzeWmdTqi7U85iYNGy7P
The wave-3 loss was caused by sprite auto-suspend, not nohup process-group
semantics. /.sprite/llm.txt: 'When idle, sprites pause automatically. Services and
sessions keep sprites alive.' Detached processes are on neither list, so setsid is
necessary but not sufficient.
tasks/wave-guard.sh holds a /v1/tasks lease (max 3600s, renewal is DELETE+POST since
re-POST returns 409), renews every 15 min while workers run, writes logs/WAVE<N>-DONE,
then releases the lease so the sprite can suspend rather than idle hot.
Also documents hazard #6 (pgrep -f / pkill -f matching the orchestrator's own shell)
and adds the wave-3 worker prompts and shared screen contract.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>