Surfaces finished Audiobook + Story renders so they're re-downloadable from the
Projects view — closing the resume/history loop of the convergence.
Backend (new, no migration — reads existing job_store rows):
- routers/longform_jobs.py: GET /longform/jobs lists finished audiobook/story
jobs newest-first, recovering output/chapters/duration from each job's
persisted 'done' SSE event. Pure build_longform_library() over the job_store
callables; defensive (skips unparseable jobs, never 500s). Registered in main.py.
Frontend:
- Projects.jsx: new "Audiobooks" category fed by /longform/jobs; each row opens
the rendered file (/audio/<output>) with type/chapters/duration. Offline-safe
(empty on fetch failure). en.json keys added.
Built via parallel worktree agent; backend tests/test_longform_jobs.py (9) green;
334 frontend tests + build clean.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>