|
| 1 | +# Bibliogon v0.20.0 |
| 2 | + |
| 3 | +AI Review Extension is the headline feature. The existing chapter review grows from a single sync path into a three-mode async flow with persistent Markdown reports, cost estimates, and full 8-language prompt parity. Three real backend bugs in the backup/import/export data paths are fixed along the way. The Playwright smoke suite drops from 31 failures to zero. |
| 4 | + |
| 5 | +## Added |
| 6 | + |
| 7 | +### AI Review Extension |
| 8 | + |
| 9 | +- **Three primary focus modes** in the Editor's AI panel: **Style** (prose polish), **Consistency** (within-chapter contradictions, distinct from the legacy `coherence` focus), and **Beta Reader** (open-ended simulated first-read feedback). Mutually exclusive radio buttons; the four legacy focus values (`coherence`, `pacing`, `dialogue`, `tension`) stay on the API for power users but no longer appear in the UI. |
| 10 | +- **Async review flow** with Server-Sent Events progress. New endpoints: `POST /api/ai/review/async` (submit job), `GET /api/ai/jobs/{id}` (poll), `GET /api/ai/jobs/{id}/stream` (SSE), `DELETE /api/ai/jobs/{id}` (cancel). The worker publishes `review_start` / `review_llm_call` / `review_done` / `stream_end` events; the editor UI translates them into rotating book-language status messages while the editor stays usable. |
| 11 | +- **Persistent Markdown reports** at `uploads/{book_id}/reviews/{review_id}-{chapter-slug}-{YYYY-MM-DD}.md`. Inline results are unchanged; the new `GET /api/ai/review/{id}/report.md?book_id=...` endpoint returns a `FileResponse`. A **Download report** button appears on the result panel. |
| 12 | +- **Cascade delete on chapter removal**: when a chapter is deleted, review files whose filename contains that chapter's slug are wiped alongside the chapter row. Prevents orphaned files growing silently. |
| 13 | +- **Chapter-type-aware prompts**: the system prompt prepends a short guidance line for all 31 `ChapterType` values (e.g. `dedication` -> "brief, personal, tone-focused", `copyright` -> "legal, skip prose review"). `ReviewRequest` gained a `chapter_type` field; the legacy synchronous `POST /api/ai/review` threads it through the same builder. |
| 14 | +- **Non-prose warning**: 12 chapter types (`title_page`, `copyright`, `toc`, `imprint`, `index`, `half_title`, `also_by_author`, `next_in_series`, `call_to_action`, `endnotes`, `bibliography`, `glossary`) get an inline warning above the Start button, rendered in the book's language (not the UI language), matching the review output language. |
| 15 | +- **Token + USD cost preview** on the Start button. `POST /api/ai/review/estimate` returns a rough `input_tokens` + `cost_usd` based on a chars/4 heuristic and a small per-model pricing dict; the UI shows `~5k tokens, ~$0.075` when the configured model is known. Unknown models render the token count only. |
| 16 | +- **UI metadata endpoint** `GET /api/ai/review/meta` exposes focus values, primary UI focus, non-prose types, supported languages, and chapter types so the frontend avoids hardcoding them. |
| 17 | +- **Full 8-language prompt parity**: extended `LANG_MAP` (DE, EN, ES, FR, EL, PT, TR, JA) is the single source for review + marketing prompt builders. `build_review_system_prompt` now writes the review in the book's language for every supported value, not just DE/EN. |
| 18 | +- **Module split**: new `backend/app/ai/prompts.py` (LANG_MAP, FOCUS_DESCRIPTIONS, CHAPTER_TYPE_GUIDANCE, NON_PROSE_TYPES, builder), `pricing.py` (PROVIDER_PRICING + estimator), `review_store.py` (slugify, filename shape, write_report, find_report, delete_reviews_for_chapter). Keeps `app/ai/routes.py` thin. |
| 19 | +- **i18n**: six new UI keys per language x 8 languages (`ai_review_focus`, `ai_review_focus_style`, `ai_review_focus_consistency`, `ai_review_focus_beta_reader`, `ai_review_download`, `ai_review_tokens`). |
| 20 | + |
| 21 | +### Tests + quality gates |
| 22 | + |
| 23 | +- **31 new backend tests** in `test_ai_review.py` (extended) and `test_ai_review_store.py` (new) covering: new focus values in the prompt, chapter_type injection + fallback, all-8-languages prompt parity, pricing estimate endpoint, meta endpoint, async submit -> poll -> download roundtrip, 403 when AI disabled, 404 for missing review, slugify edge cases, cascade-delete boundary safety, cascade via `DELETE /api/books/{id}/chapters/{id}`. |
| 24 | +- **9 regression tests** in `test_backup_import_revive.py` pinning the three backend fixes (soft-delete revival, idempotent live re-import, merge with non-empty DB, multi-doc YAML, smart-import roundtrip, pandoc-gated batch-export integration). |
| 25 | +- **8 frontend Vitest tests** in `ai-review-strings.test.ts` (8-language coverage of book-language status strings, non-prose chapter-type set parity with backend). |
| 26 | +- **4 Playwright smoke tests** in `ai-review.spec.ts` (three radio buttons render, non-prose warning visibility per chapter type, mocked happy-path download-report flow). |
| 27 | +- **16 smoke test-infra fixes** in the triage sweep: dashboard-filters selector (10 tests), content-safety recovery seed, Ctrl+Z typing delay, theme persist reload via one-shot evaluate, export project ZIP content-type tolerance, trash restore view switch, Classic first-line indent CSS specificity override (`h* + p:not(:first-child)`), CreateBookModal Radix Select testid + `pickAuthor` variant helper, dashboard sort-direction expectation, export dialog migrated from `window.open` to `page.waitForEvent('download')`. |
| 28 | + |
| 29 | +## Fixed |
| 30 | + |
| 31 | +- **`backup_import` now restores soft-deleted books** instead of silently skipping. The dedup check predated the trash feature; a backup made before trashing could not be restored once books were moved to trash. Fix: when the pre-existing row is soft-deleted, hard-delete it + chapters + assets, then fall through to the fresh-insert path. Sidesteps SQLAlchemy NOT-NULL landmines that the partial-attribute revive approach stepped on. Regression pins in `test_backup_import_revive.py`. |
| 32 | +- **Batch export no longer raises `FileNotFoundError`**. `plugin-export.export_batch_route` collected per-format output paths into a list across a loop, but manuscripta's `run_export` moves `project/output/` to `project/backup/` at the start of every call - the earlier paths pointed to moved files by the time zipping started. Fix: after each `run_pandoc`, copy the produced file into a stable `tmp_dir/batch/` staging dir and zip from there. |
| 33 | +- **`smart-import` handles Pandoc-wrapped `metadata.yaml`**. The project exporter writes `---` / `---` delimited metadata, which yields a multi-document YAML stream; `yaml.safe_load` rejected it with `ComposerError`. Fix: `yaml.safe_load_all` + first non-empty document. |
| 34 | +- **Launcher release workflows publish binaries again**. Inherits the `permissions: contents: write` grant from the v0.19.1 workflow fix; confirms that the Windows / macOS / Linux binaries attach as GitHub release assets on tag push. |
| 35 | + |
| 36 | +## Changed |
| 37 | + |
| 38 | +- **`POST /api/ai/review`** (sync) accepts `chapter_type`; the prompt builder threads it through. Backward-compatible: the field defaults to `"chapter"`. |
| 39 | +- **`_build_review_system_prompt`** (legacy import) kept as a thin alias for `prompts.build_review_system_prompt`. Existing test imports keep working. |
| 40 | +- **Classic palette first-line indent** CSS now uses `h* + p:not(:first-child)` overrides to beat the `p:not(:first-child)` base rule's specificity. Visual result is the same as before the `:not(:first-child)` base rule was added; the override simply wins the cascade again. |
| 41 | +- **CreateBookModal** Radix Select trigger gains `data-testid="create-book-author-select"` so tests can handle both the bare input and the Select variants. |
| 42 | + |
| 43 | +## Documentation |
| 44 | + |
| 45 | +- **AI help pages** (`docs/help/en/ai.md`, `docs/help/de/ai.md`) rewrite the Chapter Review section: three focus modes with when-to-use guidance, non-prose warning explanation, cost estimate, async progress, persistence + download. |
| 46 | +- **API.md** documents the 8 new `/api/ai/` endpoints (sync review gaining `chapter_type`, async review + jobs + SSE + cancel, download report, estimate, meta). |
| 47 | +- **lessons-learned.md** gets a new "AI Review extension" section with 7 pitfalls: backup-import-vs-soft-delete dedup, manuscripta `output/` cleanup between format runs, Pandoc multi-doc YAML, CSS specificity trap (`h2 + p` vs `p:not(:first-child)`), TipTap useEditor not flushing `editor.storage` reads, prefix testid selector overmatch, IndexedDB recovery draft `contentHash` contract. |
| 48 | +- **current-coverage.md** gains a v0.20.0 addendum with the +181 test delta and the 4 Playwright failures tracked in issue #9. |
| 49 | +- **explorations/README.md** adds a tier-ranked tracking table; donations-ux + donations-roadmap-integration + the children's-book scaffolding prompt move to `explorations/archive/`. |
| 50 | +- **Medium blog post** for v0.19.1 archived under `docs/blog/`. |
| 51 | + |
| 52 | +## Known pending post-release |
| 53 | + |
| 54 | +- **4 Playwright smoke skips** tracked in GitHub issue #9: three chapter-sidebar dropdown / layout tests at 125% + 150% CSS zoom (Radix Popper collision + page overflow under zoom), one editor word-count test (TipTap useEditor not flushing `editor.storage.characterCount` reads without an explicit `editor.on('update')` subscribe). Each has a `test.skip` with an inline comment pointing to the issue. |
| 55 | +- **Deferred major dependency bumps**: elevenlabs 0.2 -> 2.43, starlette 0.46 -> 1.0, rich 14 -> 15. Each gets its own dedicated session per the release-workflow stability filter. |
| 56 | +- **Pillow 12** still blocked upstream by manuscripta; Bibliogon carries pillow 11 for now. |
0 commit comments