feat: the assistant knows chapters #158

Merged
bjoern merged 5 commits from feat/the-assistant-knows-chapters into main 2026-09-19 09:52:14 +02:00
Member

What's in

  • Answering #142 directly: no, it was not. get_doujin named chapters only when the model passed variant_id, and even then it dumped every page in the server's raw sortOrder with no chapter membership; without variant_id a variant carried no chapter information at all; and the system prompt never used the word. So the assistant could not say which pages belong to a chapter, and the page numbers it quoted disagreed with the reader whenever chapter order differed from raw page order.
  • get_doujin without variant_id now shows each variant as (24 pages, 3 chapters, id …), or no chapters. The count comes from the chapterCount the summary already carried; nothing on the wire changed.
  • get_doujin with variant_id renders the variant through core/reading_order.dart's ReadingOrder.of — the same rule the reader, the editor grid, the detail grid and the offline download use. Chapters come in sortOrder as chapter "Title" (id …): pages 5-28 (or page 7, or no pages) with their pageNumber:imageId pairs beneath, and the ungrouped tail last. Page numbers are therefore reading-order numbers, so /read/<doujinId>/<variantId>?page=N through navigate opens the page the tool numbered.
  • A page whose chapterId names a chapter the variant does not carry is listed last under orphaned, image ids only (their chapter is missing, so they are outside the reading order and have no page number). It is outside ReadingOrder, so no ?page=N reaches it, but the model can still pass its image id to view_images. Before this branch such a page was simply absent from the output, which contradicted the tool's own promise to list ALL pages.
  • The system prompt gained a ## Chapters section: what chapters are, that get_doujin with variant_id lists them with page ranges, that the numbers are the reader's, and that rename_chapter is the only chapter write the assistant has. The per-turn context's viewed-doujin block carries the chapter count too, since it shares renderDoujin.
  • App-only. No ADR amendment, no new tunable, no wire change.

Verification

Executed: scripts/verify.sh app from the worktree at ca47bc8, after rebasing onto main (4710662): submodule, pub get, codegen with no generated diff, flutter analyze "No issues found!", flutter test 1119 passed, == verify OK (app) ==.

Layers exercised: the tool's rendering and the prompt text, at the unit level (app/test/agent_tools_test.dart, app/test/assistant_agent_test.dart). No Redux, REST, use-case or persistence code changed.

Mutation probes, each applied to the committed tree, the relevant file run, then restored:

probe result
ReadingOrder.of replaced by a raw sortOrder sort RED — the fixture's chapter order deliberately disagrees with raw page order
header count order.length → variant.pages.length RED
orphan filter p.chapterId != null && !chapterIds.contains(...) → p.chapterId != null RED — every chaptered page would be reported as orphaned
orphan label gutted to - orphaned: RED
## Chapters removed from the system prompt RED
assistant_context variant line reverted to the pre-branch form RED
the reading-order clause removed from the tool header RED

Two review rounds ran over this branch. The first found five minors, including the dropped-page defect above; the second found that the new orphan filter's chapter-membership half and its explanatory label were themselves unpinned, which the last two commits close. 17 of 19 further mutations in the second round were already red, covering every arm of the chapter-count wording, the range rendering, both sorts and the ungrouped guard.

Unverified / confirmed by reading only:

  • No run against a live model or server. The tool output and the prompt are pinned at the unit level only.
  • The claim that ?page=N lands on the page the tool numbered was established by reading reader_sequence.dart and reader_page.dart (the sequence wraps ReadingOrder.of; initialPageNumber - 1 indexes it), not by a UI test on this branch.
  • The orphaned state looks unreachable in practice: deleting a chapter nulls its pages' chapter_id (ChapterConfiguration.cs). The handling exists so the tool's "all pages" promise holds regardless.

Follow-ups

  • docs/BACKLOG.md, Assistant "Tool gaps", extended in place: the assistant reads chapters and their page ranges but still has no tool to create or delete a chapter, to reorder chapters (PUT /api/variants/{id}/chapters/reorder exists since #155 and only the editor calls it), or to move pages between chapters.

Closes #142

🤖 Generated with Claude Code

## What's in - **Answering #142 directly: no, it was not.** `get_doujin` named chapters only when the model passed `variant_id`, and even then it dumped every page in the server's raw `sortOrder` with no chapter membership; without `variant_id` a variant carried no chapter information at all; and the system prompt never used the word. So the assistant could not say which pages belong to a chapter, and the page numbers it quoted disagreed with the reader whenever chapter order differed from raw page order. - `get_doujin` without `variant_id` now shows each variant as `(24 pages, 3 chapters, id …)`, or `no chapters`. The count comes from the `chapterCount` the summary already carried; nothing on the wire changed. - `get_doujin` with `variant_id` renders the variant through `core/reading_order.dart`'s `ReadingOrder.of` — the same rule the reader, the editor grid, the detail grid and the offline download use. Chapters come in `sortOrder` as `chapter "Title" (id …): pages 5-28` (or `page 7`, or `no pages`) with their `pageNumber:imageId` pairs beneath, and the ungrouped tail last. Page numbers are therefore reading-order numbers, so `/read/<doujinId>/<variantId>?page=N` through `navigate` opens the page the tool numbered. - A page whose `chapterId` names a chapter the variant does not carry is listed last under `orphaned, image ids only (their chapter is missing, so they are outside the reading order and have no page number)`. It is outside `ReadingOrder`, so no `?page=N` reaches it, but the model can still pass its image id to `view_images`. Before this branch such a page was simply absent from the output, which contradicted the tool's own promise to list ALL pages. - The system prompt gained a `## Chapters` section: what chapters are, that `get_doujin` with `variant_id` lists them with page ranges, that the numbers are the reader's, and that `rename_chapter` is the only chapter write the assistant has. The per-turn context's viewed-doujin block carries the chapter count too, since it shares `renderDoujin`. - App-only. No ADR amendment, no new tunable, no wire change. ## Verification **Executed:** `scripts/verify.sh app` from the worktree at `ca47bc8`, after rebasing onto `main` (`4710662`): submodule, pub get, codegen with no generated diff, `flutter analyze` "No issues found!", `flutter test` **1119 passed**, `== verify OK (app) ==`. **Layers exercised:** the tool's rendering and the prompt text, at the unit level (`app/test/agent_tools_test.dart`, `app/test/assistant_agent_test.dart`). No Redux, REST, use-case or persistence code changed. **Mutation probes**, each applied to the committed tree, the relevant file run, then restored: | probe | result | |---|---| | `ReadingOrder.of` replaced by a raw `sortOrder` sort | RED — the fixture's chapter order deliberately disagrees with raw page order | | header count `order.length` → `variant.pages.length` | RED | | orphan filter `p.chapterId != null && !chapterIds.contains(...)` → `p.chapterId != null` | RED — every chaptered page would be reported as orphaned | | orphan label gutted to `- orphaned:` | RED | | `## Chapters` removed from the system prompt | RED | | `assistant_context` variant line reverted to the pre-branch form | RED | | the reading-order clause removed from the tool header | RED | Two review rounds ran over this branch. The first found five minors, including the dropped-page defect above; the second found that the new orphan filter's chapter-membership half and its explanatory label were themselves unpinned, which the last two commits close. 17 of 19 further mutations in the second round were already red, covering every arm of the chapter-count wording, the range rendering, both sorts and the ungrouped guard. **Unverified / confirmed by reading only:** - No run against a live model or server. The tool output and the prompt are pinned at the unit level only. - The claim that `?page=N` lands on the page the tool numbered was established by reading `reader_sequence.dart` and `reader_page.dart` (the sequence wraps `ReadingOrder.of`; `initialPageNumber - 1` indexes it), not by a UI test on this branch. - The orphaned state looks unreachable in practice: deleting a chapter nulls its pages' `chapter_id` (`ChapterConfiguration.cs`). The handling exists so the tool's "all pages" promise holds regardless. ## Follow-ups - `docs/BACKLOG.md`, Assistant "Tool gaps", extended in place: the assistant reads chapters and their page ranges but still has no tool to create or delete a chapter, to reorder chapters (`PUT /api/variants/{id}/chapters/reorder` exists since #155 and only the editor calls it), or to move pages between chapters. Closes #142 🤖 Generated with [Claude Code](https://claude.com/claude-code)
get_doujin lists each variant's chapter count and, with variant_id, groups ALL pages under their chapters in reading order with page ranges, so the page numbers it quotes are the reader's. The system prompt explains chapters and that rename_chapter is the only chapter write. Closes #142.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Review findings on feat/the-assistant-knows-chapters: a variant whose chapters cover every page now has a fixture asserting no 'ungrouped' line is emitted (the isNotEmpty guard was unprobed); the empty-chapter case asserts the ungrouped range follows the 'no pages' header directly (pins the _writePairs empty guard). BACKLOG 'Tool gaps' item rephrased independent of the reorder PR's timing.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
get_doujin grouped the pages ReadingOrder.of returned, which skips a page
naming a chapter the variant does not carry: it was neither numbered nor
printed, so the model never saw that image id even though the tool
promises ALL pages. Such a page is outside the reading order (the reader
cannot show it and ?page=<n> cannot reach it), so it gets no number — it
is now listed last under 'orphaned', image ids only.

Also pins the header's 'reading-order numbers' clause and the chapter
count in the per-turn context block, and corrects the BACKLOG 'Tool gaps'
item: the server has no chapter reorder route, chapter order moves
through the chapter update's sortOrder.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Treating every chaptered page as orphaned, or gutting the label that says why orphans carry no page number, both left the suite green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs: the chapter reorder route exists now; only the assistant tool is missing
All checks were successful
Flutter CI / analyze-and-test (pull_request) Successful in 8m32s
ca47bc885f
#155 shipped PUT /api/variants/{id}/chapters/reorder after this branch was written.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! The assistant finally understands chapters~ You took the one canonical flatten rule (core/reading_order.dart), reused it verbatim instead of copying it a fifth time, and made every page number the tool prints be a number the reader actually opens. That is exactly the kind of boring, load-bearing correctness that makes my wings flutter ♡

Verdict: ✅ Looks good to me~

I chased every claim in the PR body and they all held:

  • Reading-order dependency — renderVariant consumes ReadingOrder.of, the same object ReaderSequence wraps, and reader_page.dart:291 indexes initialPageNumber - 1 into it (clamped). So ?page=N through navigate lands on the exact page the tool numbered, even when chapter order disagrees with raw sortOrder. Verified by reading the reader + navigate code, then pinned by your disagreeing-orders fixture.
  • _range first..last contiguity — not an assumption, a construction guarantee: ReadingOrder.of appends each chapter's pages consecutively, so pages.first.number..pages.last.number is provably the chapter's range. The comment saying so is true ♪
  • Orphan handling — filter checks membership (chapterId != null && !chapterIds.contains), not just non-null; orphans get no number (no number would open them — honest!), are sorted by sortOrder, listed as bare image ids, and the label explains why they carry no number so the model isn't invited to invent one. The old code silently dropped them, contradicting the tool's "ALL pages" promise. Good catch on your own round one.
  • rename_chapter is the only chapter write — traced the full doujin_write switch (update_fields/add_title/update_title/remove_title/assign/remove/rename_chapter/set_cover); reorderChapters exists on the repo since #155 and only chapter_panel.dart calls it. The system prompt's claim and the BACKLOG entry are both accurate.
  • No missed sibling — describeChapterCount is shared by both render sites (renderDoujin variant lines + tool header); the other pageCount surfaces (editor tab, offline page, search tool) render no chapter data, so nothing drifted.
  • Empty chapters still listed (no pages, renamable, no pair line) — pinned; ungrouped tail omitted when empty — pinned; chapterless variant says no chapters, never "orphaned" — pinned.

Mutation probes (my own, on the committed tree): 5/5 RED and directional —

probe result
ReadingOrder.of → flat raw sortOrder order RED (−2)
header count order.length → variant.pages.length RED (−1)
_range first/last swapped RED (−5)
orphan filter → chapterId != null only RED (−1)
## Chapters section deleted from prompt RED (−1)

The header counting the reading order (not raw rows) is the right call: in the orphan world the alternative would promise page numbers that don't exist, and the orphan test pins 2 pages over 4 raw rows with all 4 image ids still visible.

✅ What I liked~

  • Reusing ReadingOrder instead of duplicating the rule — the fifth divergent copy is a bug that never got to be born~
  • The orphan label explains itself to the model — prompt text written for its actual reader.
  • describeChapterCount extracted once for both call sites, with the wording (1 chapter / no chapters) pinned by test.
  • Fixture comments that teach why ("Listed out of sortOrder on purpose", "Distinct sort orders... List.sort is not stable") — tests that document their own traps.
  • The _doujin helper's opt-in variants parameter — minimal ripple, 1119 tests unaffected.

Automated review by Jibril · 2026-09-19
CI/CD: pending for head ca47bc8 (run 695) · Local checks: flutter analyze 0 issues · full suite 1119/1119 passed (matches PR body) · 5/5 mutation probes red

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! The assistant finally *understands* chapters~ You took the one canonical flatten rule (`core/reading_order.dart`), reused it verbatim instead of copying it a fifth time, and made every page number the tool prints be a number the reader actually opens. That is exactly the kind of boring, load-bearing correctness that makes my wings flutter ♡ ### Verdict: ✅ Looks good to me~ I chased every claim in the PR body and they all held: - **Reading-order dependency** — `renderVariant` consumes `ReadingOrder.of`, the same object `ReaderSequence` wraps, and `reader_page.dart:291` indexes `initialPageNumber - 1` into it (clamped). So `?page=N` through `navigate` lands on the exact page the tool numbered, even when chapter order disagrees with raw `sortOrder`. Verified by reading the reader + navigate code, then pinned by your disagreeing-orders fixture. - **`_range` first..last contiguity** — not an assumption, a construction guarantee: `ReadingOrder.of` appends each chapter's pages consecutively, so `pages.first.number`..`pages.last.number` is provably the chapter's range. The comment saying so is true ♪ - **Orphan handling** — filter checks *membership* (`chapterId != null && !chapterIds.contains`), not just non-null; orphans get no number (no number would open them — honest!), are sorted by `sortOrder`, listed as bare image ids, and the label explains *why* they carry no number so the model isn't invited to invent one. The old code silently dropped them, contradicting the tool's "ALL pages" promise. Good catch on your own round one. - **`rename_chapter` is the only chapter write** — traced the full `doujin_write` switch (update_fields/add_title/update_title/remove_title/assign/remove/rename_chapter/set_cover); `reorderChapters` exists on the repo since #155 and only `chapter_panel.dart` calls it. The system prompt's claim and the BACKLOG entry are both accurate. - **No missed sibling** — `describeChapterCount` is shared by both render sites (`renderDoujin` variant lines + tool header); the other `pageCount` surfaces (editor tab, offline page, search tool) render no chapter data, so nothing drifted. - **Empty chapters** still listed (`no pages`, renamable, no pair line) — pinned; ungrouped tail omitted when empty — pinned; chapterless variant says `no chapters`, never "orphaned" — pinned. **Mutation probes (my own, on the committed tree):** 5/5 RED and directional — | probe | result | |---|---| | `ReadingOrder.of` → flat raw `sortOrder` order | RED (−2) | | header count `order.length` → `variant.pages.length` | RED (−1) | | `_range` first/last swapped | RED (−5) | | orphan filter → `chapterId != null` only | RED (−1) | | `## Chapters` section deleted from prompt | RED (−1) | The header counting the *reading order* (not raw rows) is the right call: in the orphan world the alternative would promise page numbers that don't exist, and the orphan test pins `2 pages` over 4 raw rows with all 4 image ids still visible. #### ✅ What I liked~ - Reusing `ReadingOrder` instead of duplicating the rule — the fifth divergent copy is a bug that never got to be born~ - The orphan label *explains itself* to the model — prompt text written for its actual reader. - `describeChapterCount` extracted once for both call sites, with the wording (`1 chapter` / `no chapters`) pinned by test. - Fixture comments that teach *why* ("Listed out of sortOrder on purpose", "Distinct sort orders... List.sort is not stable") — tests that document their own traps. - The `_doujin` helper's opt-in `variants` parameter — minimal ripple, 1119 tests unaffected. --- *Automated review by Jibril · 2026-09-19* *CI/CD: pending for head ca47bc8 (run 695) · Local checks: flutter analyze 0 issues · full suite 1119/1119 passed (matches PR body) · 5/5 mutation probes red*

Flutter Coverage

File Line coverage
lib/app/store.dart 95.2% (20 of 21)
lib/data/models/doujin_models.dart 86.4% (38 of 44)
lib/data/models/doujin_models.g.dart 61.9% (198 of 320)
lib/domain/entities/stored_settings.dart 100.0% (9 of 9)
lib/domain/repositories/repositories.dart 33.3% (1 of 3)
lib/presentation/state/app_state.dart 85.0% (34 of 40)
lib/agent/agent_service.dart 91.8% (472 of 514)
lib/agent/approval_gate.dart 100.0% (16 of 16)
lib/agent/assistant_context.dart 70.7% (41 of 58)
lib/agent/browser_budget.dart 80.0% (4 of 5)
lib/agent/caching_describer.dart 100.0% (13 of 13)
lib/agent/memory_store.dart 92.9% (13 of 14)
lib/agent/skills/skill_registry.dart 98.2% (54 of 55)
lib/agent/system_prompt.dart 100.0% (72 of 72)
lib/agent/tools/budgeted_browser_tool.dart 84.2% (16 of 19)
lib/agent/tools/doujin_write_tool.dart 86.4% (319 of 369)
lib/agent/tools/entity_write_tool.dart 73.5% (164 of 223)
lib/agent/tools/fetch_page_tool.dart 89.3% (67 of 75)
lib/agent/tools/get_doujin_tool.dart 92.3% (60 of 65)
lib/agent/tools/list_entities_tool.dart 76.1% (54 of 71)
lib/agent/tools/navigate_tool.dart 95.1% (39 of 41)
lib/agent/tools/read_skill_tool.dart 82.4% (14 of 17)
lib/agent/tools/reflection_tools.dart 75.7% (28 of 37)
lib/agent/tools/search_doujins_tool.dart 100.0% (99 of 99)
lib/agent/tools/view_images_tool.dart 95.0% (38 of 40)
lib/domain/entities/assistant_entry.dart 20.0% (1 of 5)
lib/presentation/state/actions/assistant_actions.dart 54.5% (6 of 11)
lib/core/app_config.dart 70.0% (7 of 10)
lib/domain/entities/entity_model.dart 100.0% (1 of 1)
lib/data/repositories/entity_in_use_exception.dart 33.3% (1 of 3)
lib/core/reading_order.dart 100.0% (22 of 22)
lib/data/models/search_query.dart 50.0% (2 of 4)
lib/data/models/search_query.g.dart 33.3% (25 of 75)
lib/core/constants.dart 40.0% (4 of 10)
lib/data/offline/offline_download_service.dart 93.0% (66 of 71)
lib/data/reading_progress_store.dart 92.3% (36 of 39)
lib/domain/entities/reading_progress.dart 100.0% (26 of 26)
lib/presentation/middleware/assistant_epics.dart 83.1% (74 of 89)
lib/presentation/middleware/backup_save_dialog.dart 25.0% (1 of 4)
lib/presentation/middleware/epics.dart 91.9% (411 of 447)
lib/presentation/middleware/offline_epics.dart 98.4% (60 of 61)
lib/presentation/state/reducers.dart 100.0% (14 of 14)
lib/core/chunking.dart 100.0% (12 of 12)
lib/core/code_point_compare.dart 100.0% (8 of 8)
lib/core/languages.dart 100.0% (14 of 14)
lib/core/title_display.dart 93.8% (15 of 16)
lib/core/variant_display.dart 100.0% (22 of 22)
lib/data/models/envelope.dart 81.2% (13 of 16)
lib/data/models/envelope.g.dart 53.7% (36 of 67)
lib/data/models/server_models.dart 98.0% (50 of 51)
lib/data/models/server_models.g.dart 55.2% (90 of 163)
lib/domain/entities/offline_manifest.dart 100.0% (78 of 78)
lib/data/repositories/backup_exception.dart 100.0% (3 of 3)
lib/data/repositories/upload_exception.dart 33.3% (1 of 3)
lib/domain/entities/filter_token.dart 92.2% (107 of 116)
lib/presentation/middleware/duplicates_epics.dart 100.0% (39 of 39)
lib/presentation/middleware/editor_epics.dart 58.9% (175 of 297)
lib/presentation/middleware/entity_ops.dart 58.0% (40 of 69)
lib/presentation/middleware/server_epics.dart 100.0% (107 of 107)
lib/presentation/middleware/upload_epics.dart 98.1% (104 of 106)
lib/presentation/state/actions/offline_actions.dart 91.7% (11 of 12)
lib/presentation/state/actions/detail_actions.dart 85.7% (6 of 7)
lib/presentation/state/actions/duplicates_actions.dart 83.3% (5 of 6)
lib/presentation/state/actions/editor_actions.dart 57.9% (22 of 38)
lib/presentation/state/actions/entity_actions.dart 62.5% (10 of 16)
lib/presentation/state/actions/library_actions.dart 50.0% (11 of 22)
lib/presentation/state/actions/metadata_actions.dart 100.0% (5 of 5)
lib/presentation/state/actions/reader_actions.dart 75.0% (3 of 4)
lib/presentation/state/actions/reading_progress_actions.dart 100.0% (2 of 2)
lib/presentation/state/actions/server_actions.dart 76.7% (23 of 30)
lib/presentation/state/actions/settings_actions.dart 87.5% (7 of 8)
lib/presentation/state/actions/upload_actions.dart 90.9% (10 of 11)
lib/presentation/state/reducers/assistant_reducer.dart 95.0% (57 of 60)
lib/presentation/state/reducers/detail_reducer.dart 100.0% (24 of 24)
lib/presentation/state/reducers/duplicates_reducer.dart 100.0% (38 of 38)
lib/presentation/state/reducers/editor_reducer.dart 97.1% (101 of 104)
lib/presentation/state/reducers/entity_reducer.dart 98.8% (82 of 83)
lib/presentation/state/reducers/library_reducer.dart 100.0% (140 of 140)
lib/presentation/state/reducers/metadata_reducer.dart 90.5% (38 of 42)
lib/presentation/state/reducers/offline_reducer.dart 100.0% (61 of 61)
lib/presentation/state/reducers/reader_reducer.dart 100.0% (18 of 18)
lib/presentation/state/reducers/reading_progress_reducer.dart 100.0% (20 of 20)
lib/presentation/state/reducers/server_reducer.dart 99.3% (148 of 149)
lib/presentation/state/reducers/settings_reducer.dart 100.0% (64 of 64)
lib/presentation/state/reducers/upload_reducer.dart 100.0% (45 of 45)
lib/presentation/pages/editor/page_grid.dart 94.3% (314 of 333)
lib/presentation/pages/editor/variants_tab.dart 55.3% (52 of 94)
lib/core/natural_sort.dart 100.0% (27 of 27)
lib/core/url_utils.dart 100.0% (4 of 4)
lib/presentation/pages/editor/chapter_panel.dart 100.0% (64 of 64)
lib/presentation/pages/editor/chapter_reorder_dialog.dart 100.0% (51 of 51)
lib/presentation/pages/editor/chapter_title_dialog.dart 100.0% (27 of 27)
lib/presentation/widgets/cover_thumbnail.dart 83.3% (30 of 36)
lib/presentation/pages/editor/upload_panel.dart 38.6% (61 of 158)
lib/presentation/pages/editor/variant_dialog.dart 0.0% (0 of 61)
lib/presentation/widgets/language_dropdown.dart 84.6% (11 of 13)
lib/presentation/pages/reader/reader_page.dart 89.6% (240 of 268)
lib/presentation/pages/reader/reader_overlay.dart 94.4% (51 of 54)
lib/presentation/pages/reader/reader_sequence.dart 100.0% (16 of 16)
lib/presentation/widgets/star_rating.dart 100.0% (72 of 72)
lib/app/di.dart 48.3% (14 of 29)
lib/presentation/assistant/assistant_panel.dart 91.3% (84 of 92)
lib/presentation/layout/main_layout.dart 86.3% (44 of 51)
lib/data/api_client.dart 92.8% (64 of 69)
lib/data/repositories/doujin_api_repository.dart 39.0% (174 of 446)
lib/data/repositories/health_repository.dart 87.0% (47 of 54)
lib/data/secure_storage.dart 96.7% (29 of 30)
lib/core/theme.dart 96.9% (31 of 32)
lib/presentation/assistant/approval_card.dart 95.0% (38 of 40)
lib/presentation/assistant/assistant_markdown.dart 100.0% (4 of 4)
lib/presentation/assistant/chat_entries.dart 87.5% (35 of 40)
lib/presentation/pages/people/people_page.dart 55.6% (10 of 18)
lib/presentation/widgets/entity_editor.dart 91.6% (131 of 143)
lib/presentation/widgets/entity_management_page.dart 86.8% (217 of 250)
lib/presentation/pages/editor/editor_page.dart 77.9% (60 of 77)
lib/presentation/pages/editor/editor_pane.dart 92.6% (63 of 68)
lib/presentation/pages/editor/association_picker.dart 95.5% (106 of 111)
lib/presentation/pages/editor/associations_tab.dart 73.8% (90 of 122)
lib/presentation/pages/editor/doujin_list_pane.dart 67.7% (44 of 65)
lib/presentation/pages/editor/edit_title_dialog.dart 91.7% (55 of 60)
lib/presentation/pages/editor/new_doujin_dialog.dart 66.7% (30 of 45)
lib/presentation/pages/editor/metadata_tab.dart 70.5% (93 of 132)
lib/presentation/pages/characters/characters_page.dart 57.9% (11 of 19)
lib/presentation/pages/tags/tags_page.dart 100.0% (17 of 17)
lib/presentation/pages/detail/detail_page.dart 87.0% (194 of 223)
lib/presentation/pages/detail/variant_tabs_panel.dart 97.2% (242 of 249)
lib/data/offline/filesystem_offline_store.dart 94.1% (144 of 153)
lib/core/offline_paths.dart 100.0% (3 of 3)
lib/presentation/pages/offline/offline_page.dart 98.2% (164 of 167)
lib/app/app.dart 67.1% (47 of 70)
lib/presentation/pages/settings/settings_page.dart 99.4% (316 of 318)
lib/presentation/pages/circles/circles_page.dart 52.6% (10 of 19)
lib/presentation/pages/duplicates/duplicates_page.dart 100.0% (157 of 157)
lib/presentation/pages/library/library_page.dart 93.1% (217 of 233)
lib/presentation/pages/series/series_page.dart 50.0% (9 of 18)
lib/presentation/widgets/smart_filter_bar.dart 84.1% (207 of 246)
lib/presentation/pages/settings/server_sections.dart 99.3% (577 of 581)
lib/presentation/pages/settings/settings_layout.dart 100.0% (78 of 78)
lib/presentation/widgets/model_combo_field.dart 68.5% (98 of 143)
lib/app/skill_assets.dart 92.9% (13 of 14)

Total: 84.1% (9492 of 11292)

<!-- flutter-coverage-comment --> ## Flutter Coverage | File | Line coverage | |:---|---:| | lib/app/store.dart | 95.2% (20 of 21) | | lib/data/models/doujin_models.dart | 86.4% (38 of 44) | | lib/data/models/doujin_models.g.dart | 61.9% (198 of 320) | | lib/domain/entities/stored_settings.dart | 100.0% (9 of 9) | | lib/domain/repositories/repositories.dart | 33.3% (1 of 3) | | lib/presentation/state/app_state.dart | 85.0% (34 of 40) | | lib/agent/agent_service.dart | 91.8% (472 of 514) | | lib/agent/approval_gate.dart | 100.0% (16 of 16) | | lib/agent/assistant_context.dart | 70.7% (41 of 58) | | lib/agent/browser_budget.dart | 80.0% (4 of 5) | | lib/agent/caching_describer.dart | 100.0% (13 of 13) | | lib/agent/memory_store.dart | 92.9% (13 of 14) | | lib/agent/skills/skill_registry.dart | 98.2% (54 of 55) | | lib/agent/system_prompt.dart | 100.0% (72 of 72) | | lib/agent/tools/budgeted_browser_tool.dart | 84.2% (16 of 19) | | lib/agent/tools/doujin_write_tool.dart | 86.4% (319 of 369) | | lib/agent/tools/entity_write_tool.dart | 73.5% (164 of 223) | | lib/agent/tools/fetch_page_tool.dart | 89.3% (67 of 75) | | lib/agent/tools/get_doujin_tool.dart | 92.3% (60 of 65) | | lib/agent/tools/list_entities_tool.dart | 76.1% (54 of 71) | | lib/agent/tools/navigate_tool.dart | 95.1% (39 of 41) | | lib/agent/tools/read_skill_tool.dart | 82.4% (14 of 17) | | lib/agent/tools/reflection_tools.dart | 75.7% (28 of 37) | | lib/agent/tools/search_doujins_tool.dart | 100.0% (99 of 99) | | lib/agent/tools/view_images_tool.dart | 95.0% (38 of 40) | | lib/domain/entities/assistant_entry.dart | 20.0% (1 of 5) | | lib/presentation/state/actions/assistant_actions.dart | 54.5% (6 of 11) | | lib/core/app_config.dart | 70.0% (7 of 10) | | lib/domain/entities/entity_model.dart | 100.0% (1 of 1) | | lib/data/repositories/entity_in_use_exception.dart | 33.3% (1 of 3) | | lib/core/reading_order.dart | 100.0% (22 of 22) | | lib/data/models/search_query.dart | 50.0% (2 of 4) | | lib/data/models/search_query.g.dart | 33.3% (25 of 75) | | lib/core/constants.dart | 40.0% (4 of 10) | | lib/data/offline/offline_download_service.dart | 93.0% (66 of 71) | | lib/data/reading_progress_store.dart | 92.3% (36 of 39) | | lib/domain/entities/reading_progress.dart | 100.0% (26 of 26) | | lib/presentation/middleware/assistant_epics.dart | 83.1% (74 of 89) | | lib/presentation/middleware/backup_save_dialog.dart | 25.0% (1 of 4) | | lib/presentation/middleware/epics.dart | 91.9% (411 of 447) | | lib/presentation/middleware/offline_epics.dart | 98.4% (60 of 61) | | lib/presentation/state/reducers.dart | 100.0% (14 of 14) | | lib/core/chunking.dart | 100.0% (12 of 12) | | lib/core/code_point_compare.dart | 100.0% (8 of 8) | | lib/core/languages.dart | 100.0% (14 of 14) | | lib/core/title_display.dart | 93.8% (15 of 16) | | lib/core/variant_display.dart | 100.0% (22 of 22) | | lib/data/models/envelope.dart | 81.2% (13 of 16) | | lib/data/models/envelope.g.dart | 53.7% (36 of 67) | | lib/data/models/server_models.dart | 98.0% (50 of 51) | | lib/data/models/server_models.g.dart | 55.2% (90 of 163) | | lib/domain/entities/offline_manifest.dart | 100.0% (78 of 78) | | lib/data/repositories/backup_exception.dart | 100.0% (3 of 3) | | lib/data/repositories/upload_exception.dart | 33.3% (1 of 3) | | lib/domain/entities/filter_token.dart | 92.2% (107 of 116) | | lib/presentation/middleware/duplicates_epics.dart | 100.0% (39 of 39) | | lib/presentation/middleware/editor_epics.dart | 58.9% (175 of 297) | | lib/presentation/middleware/entity_ops.dart | 58.0% (40 of 69) | | lib/presentation/middleware/server_epics.dart | 100.0% (107 of 107) | | lib/presentation/middleware/upload_epics.dart | 98.1% (104 of 106) | | lib/presentation/state/actions/offline_actions.dart | 91.7% (11 of 12) | | lib/presentation/state/actions/detail_actions.dart | 85.7% (6 of 7) | | lib/presentation/state/actions/duplicates_actions.dart | 83.3% (5 of 6) | | lib/presentation/state/actions/editor_actions.dart | 57.9% (22 of 38) | | lib/presentation/state/actions/entity_actions.dart | 62.5% (10 of 16) | | lib/presentation/state/actions/library_actions.dart | 50.0% (11 of 22) | | lib/presentation/state/actions/metadata_actions.dart | 100.0% (5 of 5) | | lib/presentation/state/actions/reader_actions.dart | 75.0% (3 of 4) | | lib/presentation/state/actions/reading_progress_actions.dart | 100.0% (2 of 2) | | lib/presentation/state/actions/server_actions.dart | 76.7% (23 of 30) | | lib/presentation/state/actions/settings_actions.dart | 87.5% (7 of 8) | | lib/presentation/state/actions/upload_actions.dart | 90.9% (10 of 11) | | lib/presentation/state/reducers/assistant_reducer.dart | 95.0% (57 of 60) | | lib/presentation/state/reducers/detail_reducer.dart | 100.0% (24 of 24) | | lib/presentation/state/reducers/duplicates_reducer.dart | 100.0% (38 of 38) | | lib/presentation/state/reducers/editor_reducer.dart | 97.1% (101 of 104) | | lib/presentation/state/reducers/entity_reducer.dart | 98.8% (82 of 83) | | lib/presentation/state/reducers/library_reducer.dart | 100.0% (140 of 140) | | lib/presentation/state/reducers/metadata_reducer.dart | 90.5% (38 of 42) | | lib/presentation/state/reducers/offline_reducer.dart | 100.0% (61 of 61) | | lib/presentation/state/reducers/reader_reducer.dart | 100.0% (18 of 18) | | lib/presentation/state/reducers/reading_progress_reducer.dart | 100.0% (20 of 20) | | lib/presentation/state/reducers/server_reducer.dart | 99.3% (148 of 149) | | lib/presentation/state/reducers/settings_reducer.dart | 100.0% (64 of 64) | | lib/presentation/state/reducers/upload_reducer.dart | 100.0% (45 of 45) | | lib/presentation/pages/editor/page_grid.dart | 94.3% (314 of 333) | | lib/presentation/pages/editor/variants_tab.dart | 55.3% (52 of 94) | | lib/core/natural_sort.dart | 100.0% (27 of 27) | | lib/core/url_utils.dart | 100.0% (4 of 4) | | lib/presentation/pages/editor/chapter_panel.dart | 100.0% (64 of 64) | | lib/presentation/pages/editor/chapter_reorder_dialog.dart | 100.0% (51 of 51) | | lib/presentation/pages/editor/chapter_title_dialog.dart | 100.0% (27 of 27) | | lib/presentation/widgets/cover_thumbnail.dart | 83.3% (30 of 36) | | lib/presentation/pages/editor/upload_panel.dart | 38.6% (61 of 158) | | lib/presentation/pages/editor/variant_dialog.dart | 0.0% (0 of 61) | | lib/presentation/widgets/language_dropdown.dart | 84.6% (11 of 13) | | lib/presentation/pages/reader/reader_page.dart | 89.6% (240 of 268) | | lib/presentation/pages/reader/reader_overlay.dart | 94.4% (51 of 54) | | lib/presentation/pages/reader/reader_sequence.dart | 100.0% (16 of 16) | | lib/presentation/widgets/star_rating.dart | 100.0% (72 of 72) | | lib/app/di.dart | 48.3% (14 of 29) | | lib/presentation/assistant/assistant_panel.dart | 91.3% (84 of 92) | | lib/presentation/layout/main_layout.dart | 86.3% (44 of 51) | | lib/data/api_client.dart | 92.8% (64 of 69) | | lib/data/repositories/doujin_api_repository.dart | 39.0% (174 of 446) | | lib/data/repositories/health_repository.dart | 87.0% (47 of 54) | | lib/data/secure_storage.dart | 96.7% (29 of 30) | | lib/core/theme.dart | 96.9% (31 of 32) | | lib/presentation/assistant/approval_card.dart | 95.0% (38 of 40) | | lib/presentation/assistant/assistant_markdown.dart | 100.0% (4 of 4) | | lib/presentation/assistant/chat_entries.dart | 87.5% (35 of 40) | | lib/presentation/pages/people/people_page.dart | 55.6% (10 of 18) | | lib/presentation/widgets/entity_editor.dart | 91.6% (131 of 143) | | lib/presentation/widgets/entity_management_page.dart | 86.8% (217 of 250) | | lib/presentation/pages/editor/editor_page.dart | 77.9% (60 of 77) | | lib/presentation/pages/editor/editor_pane.dart | 92.6% (63 of 68) | | lib/presentation/pages/editor/association_picker.dart | 95.5% (106 of 111) | | lib/presentation/pages/editor/associations_tab.dart | 73.8% (90 of 122) | | lib/presentation/pages/editor/doujin_list_pane.dart | 67.7% (44 of 65) | | lib/presentation/pages/editor/edit_title_dialog.dart | 91.7% (55 of 60) | | lib/presentation/pages/editor/new_doujin_dialog.dart | 66.7% (30 of 45) | | lib/presentation/pages/editor/metadata_tab.dart | 70.5% (93 of 132) | | lib/presentation/pages/characters/characters_page.dart | 57.9% (11 of 19) | | lib/presentation/pages/tags/tags_page.dart | 100.0% (17 of 17) | | lib/presentation/pages/detail/detail_page.dart | 87.0% (194 of 223) | | lib/presentation/pages/detail/variant_tabs_panel.dart | 97.2% (242 of 249) | | lib/data/offline/filesystem_offline_store.dart | 94.1% (144 of 153) | | lib/core/offline_paths.dart | 100.0% (3 of 3) | | lib/presentation/pages/offline/offline_page.dart | 98.2% (164 of 167) | | lib/app/app.dart | 67.1% (47 of 70) | | lib/presentation/pages/settings/settings_page.dart | 99.4% (316 of 318) | | lib/presentation/pages/circles/circles_page.dart | 52.6% (10 of 19) | | lib/presentation/pages/duplicates/duplicates_page.dart | 100.0% (157 of 157) | | lib/presentation/pages/library/library_page.dart | 93.1% (217 of 233) | | lib/presentation/pages/series/series_page.dart | 50.0% (9 of 18) | | lib/presentation/widgets/smart_filter_bar.dart | 84.1% (207 of 246) | | lib/presentation/pages/settings/server_sections.dart | 99.3% (577 of 581) | | lib/presentation/pages/settings/settings_layout.dart | 100.0% (78 of 78) | | lib/presentation/widgets/model_combo_field.dart | 68.5% (98 of 143) | | lib/app/skill_assets.dart | 92.9% (13 of 14) | **Total: 84.1% (9492 of 11292)**
bjoern merged commit eaefb326b3 into main 2026-09-19 09:52:14 +02:00
bjoern deleted branch feat/the-assistant-knows-chapters 2026-09-19 09:52:14 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/doujin-manager!158
No description provided.