feat(graphs): the graph library — the Graph entity, the bundled Continue template, the Graphs page (slice 10a) #65

Merged
bjoern merged 4 commits from feat/graph-library into main 2026-10-02 16:20:02 +02:00
Member

Slice 10a of Phase 2 (docs/PROJECT_PLAN.md): the graph library — the Graph entity, the bundled Continue template, and the Graphs page at /graphs (ADR 0023, docs/stories/graph-library.md). Slice 10b (the ActiveGraphId foreign key and backfill, new stories on Continue, the switcher, the stories list's Graph cell, Preview context) builds on it.

What lands

  • Domain — Graph : IUnjournaled (name, description, trigger, the definition JSON, bundled, trash) and GraphTrigger with its wire tokens. A bundled template is read-only, re-seeded in place and restored from the trash; a duplicate is always the writer's own, named "… (copy)". Migration GraphLibrary adds the Graphs table.
  • Store — EfGraphStore, every mutator under WriteAsync; a write to a graph that is gone throws.
  • Continue — context → llm → commit (append) under a fixed id; its writer on openai/gpt-6-luna, with the settings' default effort in the node's vocabulary (ReasoningEfforts.ToNodeEffort, ADR 0018). SeedBundledGraphs runs on every start: it adds a missing template, re-seeds a changed one, restores one found in the trash, and never touches the writer's graphs.
  • Use cases — ListGraphs (templates first, then by name; each graph's problems against the registered node types, or why it does not load; the stories that run it), DuplicateGraph, ReviseGraph, TrashGraph, RestoreGraph, ExportGraph, ImportGraph over the .tsumugi-graph.json envelope {format, version, id, name, description, trigger, definition}.
  • Server — GET /graphs/{id}/export behind the gate (no-store, the file named after the graph). The header's Graphs link opens the library; the page links the canvas playground.
  • Page — the table (Name with the Bundled badge and description, Trigger, Nodes, Status, Used by, Modified, row menu), Library / Trash, Duplicate, Rename and describe, a confirmed trash, Restore, Export as a download, and Import through FileUpload (1 MiB). Fluxor feature state; a story change from anywhere refreshes an open list.
  • Seed — "Slow burn" (a renamed duplicate of Continue that the archived story "The Lantern Road" runs) and a trashed "Old draft graph", through the use cases.
  • Docs — the ADR 0023 amendment (slice 10a), the library story's import line (ticked), AGENTS.md (the route, the seed).

Decisions

Question Decision Why
Journal the library? No; graphs are unjournaled until Phase 3's per-graph journal. ADR 0022 records it; no write rings the doorbell.
Template ids Fixed, all starting 0192c3a0-7c00-7000-8000-: a range reserved for templates, this build's and every later one's. A later build's template must find its id free on every install.
An import's id Keeps the file's id, so graphs that reference each other travel together. A missing id, an id in the templates' range, or an id already in the library gets a new one. ADR 0023's import rule; the range closes the case where a later build's template file is imported first.
A writer's graph under a template's id at start Left as it is. The template is left out, a warning is logged, and the app starts. Only a hand-edited database gets there. A start must never stop over it.
A file that does not import Refused with one reason: not a graph file, a member named twice, text that is not valid, version, name, trigger, a definition that does not load. The writer can act on each reason. Nothing throws into the circuit.
A graph that loads but does not validate Imported, and listed with its problems. The Phase 3 editor fixes it; ADR 0023.
A story in the trash It keeps its active graph, so that graph cannot be trashed either. The refusal names the story "(in the trash)" and says to restore it and give it another graph, or purge it. A restored story never finds its graph in the trash.
Re-importing a graph that is still in the library A second graph under a new id with the same name. No silent rename. Rename and describe is one click away.
Another tab It sees graph changes when it next opens the page; a story change refreshes an open list. Graphs are unjournaled; the stories a row names are journaled.
Problems A warning badge that opens to the list by click, tap or keyboard (Disclosure). Not a hover-only tooltip.
A name length bound None (C13 declined). No doc promises one and story titles have none; the column's 500 stays.

Tests

Project main branch
Tsumugi.Domain.Tests 486 512
Kagaku.Flow.Tests 1103 1103
Kagaku.Flow.OpenRouter.Tests 596 (4 skipped, live) 596 (4 skipped, live)
Tsumugi.BlazorAdapter.Tests 529 551
Tsumugi.UseCases.Tests 365 428
Tsumugi.Integration.Tests 621 668
  • Continue validates against the app's node types for every effort and runs end to end in the engine with a scripted model in three story worlds, down to the prompt it sends.
  • Coverage: 100% line and branch on every new and changed file. SeedDevData's refusal arms (lines 189–213) predate the slice.
  • Mutation probes: the feature commit, 29 killed. Across the review fixes: 48 runs (N21 twice), 47 distinct mutants — the reviewers' survivors and the fixes — and 43 killed. Three that did not compile were rerun as compiling variants. The one survivor (R12) showed that the per-request refusal clears were redundant, and they were removed. (dd1ddce's message says "42 runs"; 43 is right for that round.)

Reviews

Reviews ran as workflows, one agent at a time.

  • Round 0 (dd1ddce): reviewers for correctness, the page and the tests. 24 findings: 6 blockers, 12 suggestions, 6 nits; A2/B3 and A4/C1 are the same issue.
    • All are fixed except C13, a 1–200 character name bound, declined above.
    • The blockers:
      • A1: a writer's graph under a template's id stopped the app from starting.
      • B1: the Used by cell widened the table past the page.
      • C1–C3: tests that could not fail on a lost name, description or rename.
    • Not run: round 0's docs reviewer and its skeptics, cut off by a usage limit. The fixes followed the reviewers' reproductions.
  • Second pass (255fb2f): a check of every round-0 fix and of the fix commit, the docs review round 0 missed, and a skeptic over the new findings.
    • 23 of the 24 round-0 findings resolved; C12 partly, finished as K2.
    • 9 new findings: 8 confirmed (suggestions and nits), all fixed; 1 refuted (D2, a trigger from a newer build stored in a row — refused loudly, the rule ADR 0028 sets; ADR 0023 now says so).

Browser pass (Playwright, 1280×800, the sample world)

  • Feature commit: the list, trash and restore, duplicate, rename by Enter, export (Content-Disposition tight-prose.tsumugi-graph.json), import, and the "not a graph" alert.
  • After round 0:
    • An 84-character story title under Used by is cut at 197 px with an ellipsis. The table stays 1183 px with no sideways scroll, and every row menu stays inside the viewport.
    • The trash refusal names the archived story.
    • An import made from the Trash view switches to the Library, with the graph listed.
    • The problem badge is the warning tone and opens with Enter to "There is no node type 'translate'."; Ready is the success tone.
    • No console errors.

🤖 Generated with Claude Code

Slice 10a of Phase 2 (`docs/PROJECT_PLAN.md`): the graph library — the `Graph` entity, the bundled **Continue** template, and the Graphs page at `/graphs` (ADR 0023, `docs/stories/graph-library.md`). Slice 10b (the `ActiveGraphId` foreign key and backfill, new stories on Continue, the switcher, the stories list's Graph cell, Preview context) builds on it. ## What lands - **Domain** — `Graph : IUnjournaled` (name, description, trigger, the definition JSON, bundled, trash) and `GraphTrigger` with its wire tokens. A bundled template is read-only, re-seeded in place and restored from the trash; a duplicate is always the writer's own, named "… (copy)". Migration `GraphLibrary` adds the `Graphs` table. - **Store** — `EfGraphStore`, every mutator under `WriteAsync`; a write to a graph that is gone throws. - **Continue** — `context` → `llm` → `commit` (append) under a fixed id; its writer on `openai/gpt-6-luna`, with the settings' default effort in the node's vocabulary (`ReasoningEfforts.ToNodeEffort`, ADR 0018). `SeedBundledGraphs` runs on every start: it adds a missing template, re-seeds a changed one, restores one found in the trash, and never touches the writer's graphs. - **Use cases** — `ListGraphs` (templates first, then by name; each graph's problems against the registered node types, or why it does not load; the stories that run it), `DuplicateGraph`, `ReviseGraph`, `TrashGraph`, `RestoreGraph`, `ExportGraph`, `ImportGraph` over the `.tsumugi-graph.json` envelope `{format, version, id, name, description, trigger, definition}`. - **Server** — `GET /graphs/{id}/export` behind the gate (`no-store`, the file named after the graph). The header's Graphs link opens the library; the page links the canvas playground. - **Page** — the table (Name with the Bundled badge and description, Trigger, Nodes, Status, Used by, Modified, row menu), Library / Trash, Duplicate, Rename and describe, a confirmed trash, Restore, Export as a download, and Import through `FileUpload` (1 MiB). Fluxor feature state; a story change from anywhere refreshes an open list. - **Seed** — "Slow burn" (a renamed duplicate of Continue that the archived story "The Lantern Road" runs) and a trashed "Old draft graph", through the use cases. - **Docs** — the ADR 0023 amendment (slice 10a), the library story's import line (ticked), AGENTS.md (the route, the seed). ## Decisions | Question | Decision | Why | |---|---|---| | Journal the library? | No; graphs are unjournaled until Phase 3's per-graph journal. | ADR 0022 records it; no write rings the doorbell. | | Template ids | Fixed, all starting `0192c3a0-7c00-7000-8000-`: a range reserved for templates, this build's and every later one's. | A later build's template must find its id free on every install. | | An import's id | Keeps the file's id, so graphs that reference each other travel together. A missing id, an id in the templates' range, or an id already in the library gets a new one. | ADR 0023's import rule; the range closes the case where a later build's template file is imported first. | | A writer's graph under a template's id at start | Left as it is. The template is left out, a warning is logged, and the app starts. | Only a hand-edited database gets there. A start must never stop over it. | | A file that does not import | Refused with one reason: not a graph file, a member named twice, text that is not valid, version, name, trigger, a definition that does not load. | The writer can act on each reason. Nothing throws into the circuit. | | A graph that loads but does not validate | Imported, and listed with its problems. | The Phase 3 editor fixes it; ADR 0023. | | A story in the trash | It keeps its active graph, so that graph cannot be trashed either. The refusal names the story "(in the trash)" and says to restore it and give it another graph, or purge it. | A restored story never finds its graph in the trash. | | Re-importing a graph that is still in the library | A second graph under a new id with the same name. | No silent rename. *Rename and describe* is one click away. | | Another tab | It sees graph changes when it next opens the page; a story change refreshes an open list. | Graphs are unjournaled; the stories a row names are journaled. | | Problems | A warning badge that opens to the list by click, tap or keyboard (`Disclosure`). | Not a hover-only tooltip. | | A name length bound | None (C13 declined). | No doc promises one and story titles have none; the column's 500 stays. | ## Tests | Project | main | branch | |---|---|---| | Tsumugi.Domain.Tests | 486 | 512 | | Kagaku.Flow.Tests | 1103 | 1103 | | Kagaku.Flow.OpenRouter.Tests | 596 (4 skipped, live) | 596 (4 skipped, live) | | Tsumugi.BlazorAdapter.Tests | 529 | 551 | | Tsumugi.UseCases.Tests | 365 | 428 | | Tsumugi.Integration.Tests | 621 | 668 | - Continue validates against the app's node types for every effort and runs end to end in the engine with a scripted model in three story worlds, down to the prompt it sends. - Coverage: 100% line and branch on every new and changed file. SeedDevData's refusal arms (lines 189–213) predate the slice. - Mutation probes: the feature commit, 29 killed. Across the review fixes: 48 runs (N21 twice), 47 distinct mutants — the reviewers' survivors and the fixes — and 43 killed. Three that did not compile were rerun as compiling variants. The one survivor (R12) showed that the per-request refusal clears were redundant, and they were removed. (dd1ddce's message says "42 runs"; 43 is right for that round.) ## Reviews Reviews ran as workflows, one agent at a time. - **Round 0** (dd1ddce): reviewers for correctness, the page and the tests. 24 findings: 6 blockers, 12 suggestions, 6 nits; A2/B3 and A4/C1 are the same issue. - All are fixed except C13, a 1–200 character name bound, declined above. - The blockers: - A1: a writer's graph under a template's id stopped the app from starting. - B1: the Used by cell widened the table past the page. - C1–C3: tests that could not fail on a lost name, description or rename. - Not run: round 0's docs reviewer and its skeptics, cut off by a usage limit. The fixes followed the reviewers' reproductions. - **Second pass** (255fb2f): a check of every round-0 fix and of the fix commit, the docs review round 0 missed, and a skeptic over the new findings. - 23 of the 24 round-0 findings resolved; C12 partly, finished as K2. - 9 new findings: 8 confirmed (suggestions and nits), all fixed; 1 refuted (D2, a trigger from a newer build stored in a row — refused loudly, the rule ADR 0028 sets; ADR 0023 now says so). ## Browser pass (Playwright, 1280×800, the sample world) - Feature commit: the list, trash and restore, duplicate, rename by Enter, export (`Content-Disposition` `tight-prose.tsumugi-graph.json`), import, and the "not a graph" alert. - After round 0: - An 84-character story title under Used by is cut at 197 px with an ellipsis. The table stays 1183 px with no sideways scroll, and every row menu stays inside the viewport. - The trash refusal names the archived story. - An import made from the Trash view switches to the Library, with the graph listed. - The problem badge is the warning tone and opens with Enter to "There is no node type 'translate'."; Ready is the success tone. - No console errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Graphs become an app-level library (ADR 0023), unjournaled until Phase 3's per-graph
journal (ADR 0022, D-20).

- Tsumugi.Domain/Graphs: Graph (IUnjournaled) — name, description, trigger (story or
  selection, stored by its wire token), the definition JSON, bundled, trash; a bundled
  template is read-only and re-seeded in place, a duplicate is always the writer's own.
  Migration GraphLibrary adds the Graphs table.
- IGraphStore / EfGraphStore: every mutator under WriteAsync; a write to a graph that
  is gone throws.
- BundledGraphs: Continue under a fixed id — context → llm → commit (append) — its
  writer on openai/gpt-6-luna (Björn's choice) and the settings' default effort in the
  node's vocabulary (ReasoningEfforts.ToNodeEffort, ADR 0018). SeedBundledGraphs runs
  on every start: adds a missing template, re-seeds a changed one, restores one found
  in the trash, never touches a duplicate.
- Use cases: ListGraphs (templates first, then by name; each graph's problems against
  the registered node types, or why it does not load; the stories outside the trash
  that run it), DuplicateGraph, ReviseGraph, TrashGraph (a template stays; a graph a
  story runs stays, the stories named), RestoreGraph, ExportGraph and ImportGraph over
  the .tsumugi-graph.json envelope {format, version, id, name, description, trigger,
  definition}. An import keeps the file's id unless it is a template's or already in
  the library, and keeps a graph that loads but does not validate.
- GET /graphs/{id}/export behind the gate. The Graphs page at /graphs (Fluxor): the
  table, the Library / Trash toggle, the row menus, rename and describe, a confirmed
  trash, import through FileUpload; the header's Graphs link now opens it, and the
  page links the canvas playground.
- The seed adds "Slow burn" (a renamed duplicate of Continue) and a trashed
  "Old draft graph", through the use cases.
- ADR 0023 amended (the file, the id rule, invalid imports, the list, the template's
  operations); AGENTS.md (the route, the seed).

Tests: the Graph rules; the effort translation; Continue's definition; the file's
reading and writing; the store, seeding, list, actions, export and import over SQLite,
none of it journaled; Continue validated against the app's node types for every
effort and run end to end by the engine with a scripted model in three story worlds;
the page in bUnit; the export endpoint and the page behind the gate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review round 0 (correctness, UI and tests reviewers): 24 findings — 6 blockers, 12 suggestions,
6 nits; A2/B3 and A4/C1 report the same issue. All fixed but C13, declined below. The docs
reviewer and the skeptic pass did not run (usage limit); the second pass covers docs.

- Template ids (A1): every bundled template's id, this build's and every later one's, starts
  0192c3a0-7c00-7000-8000- (BundledGraphs.ReservedIdPrefix, IsReserved); an import mints a new id
  for any id in that range, so a later build's template file never takes the id that build seeds.
  The seed no longer throws on a graph of the writer's own under a template's id:
  SeedBundledAsync answers Current/Written/Held, SeedBundledGraphs returns what it wrote and what
  it left out, and the start logs a warning and goes on.
- The file (A2, B3): GraphFile.Read parses with JsonDocument and never throws — a member named
  twice ("The file holds “name” twice."), half a character in a member's text ("The file's “name”
  is not valid text.") or name, a raw lone surrogate; the definition goes to the loader as the
  file holds it, so its own checks report a bad node id.
- Trashed stories (A3): a story in the trash keeps its active graph, so TrashGraph refuses that
  graph too, naming the story "(in the trash)"; the list names it last, marked (GraphUsers).
  ADR 0023 amended.
- The page: the Used by cell is capped at 24ch (B1); an import made from the trash shows the
  library it joined (B2); opening the page clears an old refusal (B5); the problem badge is a
  warning, Ready a success, and the problems open from the badge by click, tap or keyboard — a
  Disclosure, not a hover title (B6); a story change from anywhere refreshes an open list,
  keeping a refusal on show, and a circuit that never opened the page queries nothing (B7). The
  per-request reducers that cleared a refusal go: the reload after a done action clears it, and a
  refusal replaces it (a probe showed them redundant).
- The seed: the archived story runs "Slow burn", so the Used by column and the trash refusal
  show in a browser pass.
- Tests (A4, B4, C1–C12): a reseed and a revise that change one thing land it; describe without
  rename; the rename keeps or replaces the description; the trash dialog closes and cancels; the
  Story label; case-mixed names order; when each graph last changed; the 1 MiB cap as a literal; a
  700 KB file imports; a refusal cleared by the next action, the toggle and reopening; a leading
  quote in a file name; Save off for a blank name.
- Probes: 42 runs, 38 distinct mutants killed — of the fixes and of the review's survivors; three
  that did not compile were rerun as compiling variants, and the one survivor was the redundant
  per-request clear, now removed.
- Declined C13 (a 1–200 character name): the bound was only in my brief, no doc promises it, and
  story titles have none; the column's 500 stays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(graphs): second pass — a trashed story's way out in the app's words, a null version is no version, docs
Some checks failed
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
255fb2fe92
Second pass (a check of every round-0 fix and of the fix commit, the docs review round 0 missed, a
skeptic over the new findings): 23 of 24 round-0 findings resolved, C12 partly; 9 new findings,
8 confirmed, 1 refuted.

- K1/D1: the trash refusal no longer asks the writer to give a story in the trash another graph,
  which they cannot do there. Every story in the trash: "Restore that story and give it another
  graph, or purge it." Some: "…; a story in the trash keeps its graph until you restore it and
  give it another, or purge it." ADR 0023 says "until it is purged", the app's word.
- K2 (C12's second half): the rename test asserts Save is on once a name is typed.
- K3: a "version": null reads as no version, as the earlier reader had it.
- D2 refuted (a stored trigger from a newer build is refused loudly, the rule ADR 0028 sets for
  rows a build cannot read); ADR 0023's library bullet now says so.
- D3: dd1ddce's message says 42 probe runs; the saved results hold 43 (N21 ran twice). Across
  both rounds: 48 runs, 47 distinct mutants, 43 killed; 3 that did not compile were rerun as
  compiling variants, and the one survivor (R12) was the redundant per-request clear, removed.
- D4: GraphFile.FileName's summary says ASCII letters. D5: the library story ticks Import /
  export. D6: AGENTS.md names the seeded graphs and the archived story that runs Slow burn.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs: this PR's number (#65) in ADR 0023 and the plan's slice 10a line
All checks were successful
CI / build (pull_request) Successful in 43s
CI / editor-browsers (pull_request) Successful in 1m5s
CI / test (pull_request) Successful in 2m19s
2fee2c15ca
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

🔄 Auto-updating coverage report — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip.

Commit: 2fee2c1 · Generated: 2026-10-02 13:59:25 UTC · Revision: #1

Summary

Summary
Generated on: 10/02/2026 - 13:59:25
Coverage date: 10/02/2026 - 13:58:17 - 10/02/2026 - 13:59:21
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 568
Files: 486
Line coverage: 98.3% (17485 of 17775)
Covered lines: 17485
Uncovered lines: 290
Coverable lines: 17775
Total lines: 37918
Branch coverage: 94.6% (6501 of 6870)
Covered branches: 6501
Total branches: 6870
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.Flow - 99.7%
Name Line Branch
Kagaku.Flow 99.7% 99.2%
Kagaku.Flow.Budgeting.BudgetRequest 100%
Kagaku.Flow.Budgeting.ConsumerBudget 100%
Kagaku.Flow.Execution.NodeExecution 100% 100%
Kagaku.Flow.Execution.NodeOutcome 100% 100%
Kagaku.Flow.Execution.TransientFailureException 100%
Kagaku.Flow.Execution.Upstream 100%
Kagaku.Flow.Extensions.ServiceCollectionExtensions 100%
Kagaku.Flow.FlowJson 100%
Kagaku.Flow.Graphs.GraphDefinition 100%
Kagaku.Flow.Graphs.GraphDocument 100% 100%
Kagaku.Flow.Graphs.GraphEdge 100%
Kagaku.Flow.Graphs.GraphIndex 100% 100%
Kagaku.Flow.Graphs.GraphLoadError 100%
Kagaku.Flow.Graphs.GraphLoadResult 100%
Kagaku.Flow.Graphs.GraphNode 100%
Kagaku.Flow.Graphs.GraphPosition 100%
Kagaku.Flow.Graphs.GraphReader 100% 100%
Kagaku.Flow.Graphs.GraphSchema 100% 100%
Kagaku.Flow.Graphs.GraphShapeException 100%
Kagaku.Flow.Graphs.GraphWriter 100% 100%
Kagaku.Flow.Graphs.SocketRef 100%
Kagaku.Flow.Graphs.WireText 100% 100%
Kagaku.Flow.Nodes.CanvasDescriptorWriter 100% 100%
Kagaku.Flow.Nodes.ConfigProblem 100%
Kagaku.Flow.Nodes.Names 100%
Kagaku.Flow.Nodes.NodeDescriptor 100% 100%
Kagaku.Flow.Nodes.NodeRegistry 100% 100%
Kagaku.Flow.Nodes.NodeSockets 100% 100%
Kagaku.Flow.Nodes.SinkDescriptor 100%
Kagaku.Flow.Nodes.SocketTypes 100% 100%
Kagaku.Flow.Nodes.SourceDescriptor 100%
Kagaku.Flow.Nodes.TemplateField 100%
Kagaku.Flow.Runs.LedgerChange 100% 100%
Kagaku.Flow.Runs.LedgerTransitions 100% 100%
Kagaku.Flow.Runs.NodeAttempt 100%
Kagaku.Flow.Runs.NodeFacts 100%
Kagaku.Flow.Runs.NodeRun 100%
Kagaku.Flow.Runs.Run 100% 100%
Kagaku.Flow.Runs.RunEvent 100%
Kagaku.Flow.Runs.RunStatuses 100% 100%
Kagaku.Flow.Runs.RunTrigger 100% 100%
Kagaku.Flow.Scheduling.Exclusion 100%
Kagaku.Flow.Scheduling.FlowEngine 100% 100%
Kagaku.Flow.Scheduling.FlowEngineOptions 100% 100%
Kagaku.Flow.Scheduling.ReadyRow 100%
Kagaku.Flow.Scheduling.ReadySet 100% 100%
Kagaku.Flow.Scheduling.ReadySetResult 100%
Kagaku.Flow.Scheduling.RunRequest 100% 100%
Kagaku.Flow.Scheduling.RunStartResult 100%
Kagaku.Flow.Scheduling.SocketValues 100% 100%
Kagaku.Flow.Templating.InputsWalker 100% 100%
Kagaku.Flow.Templating.ParsedTemplate 100% 100%
Kagaku.Flow.Templating.SandboxedTemplateContext 100% 100%
Kagaku.Flow.Templating.TemplateError 100%
Kagaku.Flow.Templating.TemplateHost 100% 100%
Kagaku.Flow.Templating.TemplateLimits 100%
Kagaku.Flow.Templating.TemplateModel 100% 100%
Kagaku.Flow.Templating.TemplateProblem 100%
Kagaku.Flow.Templating.TemplateRenderRequest 100% 100%
Kagaku.Flow.Templating.TemplateRenderResult 100%
Kagaku.Flow.Templating.TemplateRun 100%
Kagaku.Flow.Templating.TemplateSinks 100%
Kagaku.Flow.Templating.TemplateValues 100% 100%
Kagaku.Flow.Validation.GraphValidation 100% 100%
Kagaku.Flow.Validation.GraphValidationContext 100%
Kagaku.Flow.Validation.HookFailure 100%
Kagaku.Flow.Validation.ResolvedGraph 100% 100%
Kagaku.Flow.Validation.ValidationError 100%
Kagaku.Flow.Validation.ValidationReport 100%
System.Text.RegularExpressions.Generated 97.4% 92.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2
97.4% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
97.2% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
97.2% 94.4%
Kagaku.Flow.OpenRouter - 100%
Name Line Branch
Kagaku.Flow.OpenRouter 100% 100%
Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities 100% 100%
Kagaku.Flow.OpenRouter.Gateway.LlmCompletion 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway 100% 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmAnswer 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfig 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfigRead 100%
Kagaku.Flow.OpenRouter.Llm.LlmDescriptor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmExecutor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFacts 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFailureText 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmMessage 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan 100%
Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmSampling 100%
Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmVocabulary 100% 100%
Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions 100%
Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions 100% 100%
Kagaku.Flow.Testing - 100%
Name Line Branch
Kagaku.Flow.Testing 100% 100%
Kagaku.Flow.Testing.FlowEngineDriver 100% 100%
Kagaku.Flow.Testing.InMemoryRunLedger 100% 100%
Kagaku.Flow.Testing.RecordingRunEventSink 100%
Kagaku.Flow.Testing.RunLedgerContract 100% 100%
Kagaku.Flow.Testing.RunLedgerContractException 100%
Tsumugi.BlazorAdapter - 96.6%
Name Line Branch
Tsumugi.BlazorAdapter 96.6% 91.6%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 93.2% 88.4%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 94.1%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 95.7% 89.4%
Tsumugi.BlazorAdapter.Documents.DocumentImageRefused 100%
Tsumugi.BlazorAdapter.Documents.DocumentImageSet 100%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.5% 95%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsRefusal 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldInput 100% 96.6%
Tsumugi.BlazorAdapter.Documents.FieldsChanges 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldShapes 90% 87.5%
Tsumugi.BlazorAdapter.Documents.ImageUpload 100%
Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal 100%
Tsumugi.BlazorAdapter.Documents.ImpactText 100% 94.2%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog 95.6% 71.4%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter 100%
Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested 100%
Tsumugi.BlazorAdapter.EffectCalls 100%
Tsumugi.BlazorAdapter.Graphs.DuplicateGraphRequested 100%
Tsumugi.BlazorAdapter.Graphs.GraphActionFailed 100%
Tsumugi.BlazorAdapter.Graphs.GraphCanvas 58.3% 40%
Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage 100% 100%
Tsumugi.BlazorAdapter.Graphs.GraphsEffects 100% 100%
Tsumugi.BlazorAdapter.Graphs.GraphsLoaded 100%
Tsumugi.BlazorAdapter.Graphs.GraphsPage 100% 100%
Tsumugi.BlazorAdapter.Graphs.GraphsReducers 100%
Tsumugi.BlazorAdapter.Graphs.GraphsState 100%
Tsumugi.BlazorAdapter.Graphs.ImportGraphRequested 100%
Tsumugi.BlazorAdapter.Graphs.RestoreGraphRequested 100%
Tsumugi.BlazorAdapter.Graphs.ReviseGraphRequested 100%
Tsumugi.BlazorAdapter.Graphs.SetShowGraphTrash 100%
Tsumugi.BlazorAdapter.Graphs.TrashGraphRequested 100%
Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge 94.4% 83.3%
Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived 75% 100%
Tsumugi.BlazorAdapter.Runs.RunChangedBridge 97.1% 90.6%
Tsumugi.BlazorAdapter.Runs.RunChangesReceived 100%
Tsumugi.BlazorAdapter.Runs.RunTextReceived 100%
Tsumugi.BlazorAdapter.Settings.BackupFailed 100%
Tsumugi.BlazorAdapter.Settings.BackupNowRequested 100%
Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.BackupsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed 100%
Tsumugi.BlazorAdapter.Settings.LoadBackupSettings 100%
Tsumugi.BlazorAdapter.Settings.LoadProviderSettings 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed 100%
Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked 100%
Tsumugi.BlazorAdapter.Settings.ProviderSection 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsState 100% 100%
Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested 100%
Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested 100%
Tsumugi.BlazorAdapter.Stories.CreateStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.SetShowArchived 100%
Tsumugi.BlazorAdapter.Stories.SetStoriesFilter 100%
Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested 100%
Tsumugi.BlazorAdapter.Stories.StoriesEffects 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesLoaded 100%
Tsumugi.BlazorAdapter.Stories.StoriesPage 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesReducers 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesState 100% 100%
Tsumugi.BlazorAdapter.Stories.StoryActionFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryCreated 100%
Tsumugi.BlazorAdapter.Stories.StoryCreateFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryTrashPage 100% 100%
Tsumugi.BlazorAdapter.Stories.TrashStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.AckWire 100%
Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed 100%
Tsumugi.BlazorAdapter.Workspace.ChangedWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterHeader 100% 86.3%
Tsumugi.BlazorAdapter.Workspace.ChapterMenu 100% 81.2%
Tsumugi.BlazorAdapter.Workspace.ChapterPage 100% 87.5%
Tsumugi.BlazorAdapter.Workspace.ChapterSaved 100%
Tsumugi.BlazorAdapter.Workspace.ChaptersPage 94.4% 83.3%
Tsumugi.BlazorAdapter.Workspace.ChapterWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterWritten 100%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.CreatedWire 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeltaWire 100%
Tsumugi.BlazorAdapter.Workspace.HistoryEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryLoaded 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPage 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPanel 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryReadFailed 100%
Tsumugi.BlazorAdapter.Workspace.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents 81.8% 74.1%
Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface 89.8% 87.1%
Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.MergeEvent 100%
Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested 100%
Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.ReshapeEvent 100%
Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested 100%
Tsumugi.BlazorAdapter.Workspace.SaveScope 100% 50%
Tsumugi.BlazorAdapter.Workspace.SaveStateLadder 100% 100%
Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested 100%
Tsumugi.BlazorAdapter.Workspace.SegmentTextEvent 100%
Tsumugi.BlazorAdapter.Workspace.SegmentWire 100% 81.8%
Tsumugi.BlazorAdapter.Workspace.SelectionEndWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionGraph 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested 100%
Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested 100%
Tsumugi.BlazorAdapter.Workspace.SplitEvent 100%
Tsumugi.BlazorAdapter.Workspace.StampWire 0%
Tsumugi.BlazorAdapter.Workspace.StoryDetails 100% 85.2%
Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage 100% 100%
Tsumugi.BlazorAdapter.Workspace.StorySaved 100%
Tsumugi.BlazorAdapter.Workspace.StoryShell 100% 100%
Tsumugi.BlazorAdapter.Workspace.UndoRequested 100%
Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged 100%
Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers 100% 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceState 100%
Tsumugi.Domain - 96.5%
Name Line Branch
Tsumugi.Domain 96.5% 95.2%
System.Text.RegularExpressions.Generated 91.3% 88.6%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
97.4% 95.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
91% 91.1%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
91.8% 83.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
91.9% 88.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
90.9% 84.3%
Tsumugi.Domain.Documents.CategoryFields 94.5% 93.7%
Tsumugi.Domain.Documents.ChoiceOption 100%
Tsumugi.Domain.Documents.ChoiceValue 100%
Tsumugi.Domain.Documents.DateText 100%
Tsumugi.Domain.Documents.DateValue 100%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 100% 100%
Tsumugi.Domain.Documents.DocumentValues 100%
Tsumugi.Domain.Documents.FieldCarry 100% 100%
Tsumugi.Domain.Documents.FieldConversion 100% 100%
Tsumugi.Domain.Documents.FieldDefinition 97% 95.3%
Tsumugi.Domain.Documents.FieldMessages 100% 100%
Tsumugi.Domain.Documents.FieldNames 100%
Tsumugi.Domain.Documents.FieldsChange 100%
Tsumugi.Domain.Documents.FieldShape 95.2% 87.5%
Tsumugi.Domain.Documents.FieldsPlan 100%
Tsumugi.Domain.Documents.FieldsPlanner 99.2% 99.2%
Tsumugi.Domain.Documents.FieldValue 100%
Tsumugi.Domain.Documents.FieldValues 95.4% 97.7%
Tsumugi.Domain.Documents.ImageFiles 100% 100%
Tsumugi.Domain.Documents.ImageValue 100%
Tsumugi.Domain.Documents.MovePlan 100%
Tsumugi.Domain.Documents.NumberParse 100%
Tsumugi.Domain.Documents.NumberText 100% 97.6%
Tsumugi.Domain.Documents.NumberValue 100%
Tsumugi.Domain.Documents.StoryImage 100%
Tsumugi.Domain.Documents.TextValue 100% 100%
Tsumugi.Domain.Documents.ValueChange 100%
Tsumugi.Domain.Documents.ValueChangeKey 100%
Tsumugi.Domain.Documents.ValueImpact 100% 100%
Tsumugi.Domain.Graphs.Graph 100% 100%
Tsumugi.Domain.Graphs.GraphTriggers 100% 100%
Tsumugi.Domain.Journal.ChangeLogEntry 97.9% 83.3%
Tsumugi.Domain.Journal.StorySnapshot 95.4% 83.3%
Tsumugi.Domain.Settings.AppSetting 100%
Tsumugi.Domain.Stories.Chapter 100% 100%
Tsumugi.Domain.Stories.InlineMarkup 100% 100%
Tsumugi.Domain.Stories.MarkupRun 100%
Tsumugi.Domain.Stories.Provenance 100% 100%
Tsumugi.Domain.Stories.Segment 100% 100%
Tsumugi.Domain.Stories.Story 100% 100%
Tsumugi.Domain.Text 100% 100%
Tsumugi.Infrastructure - 98.6%
Name Line Branch
Tsumugi.Infrastructure 98.6% 87.6%
System.Text.RegularExpressions.Generated 81.4% 64.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
84% 65.7%
Tsumugi.Infrastructure.Backups.BackupArtifactName 100% 100%
Tsumugi.Infrastructure.Backups.BackupOptions 100%
Tsumugi.Infrastructure.Backups.BackupSchedule 100% 83.3%
Tsumugi.Infrastructure.Backups.BackupScheduler 96.6% 87.5%
Tsumugi.Infrastructure.Backups.BackupWriter 98.5% 92.8%
Tsumugi.Infrastructure.Backups.DatabaseFingerprint 91.9% 97%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.OwnerOnlyFile 100% 100%
Tsumugi.Infrastructure.Backups.PreMigrationBackup 90% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 88.2% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.5% 88.2%
Tsumugi.Infrastructure.Journal.ModelExtensions 100%
Tsumugi.Infrastructure.Journal.OperationContext 100% 100%
Tsumugi.Infrastructure.Journal.PropertyBag 100% 95.4%
Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus 100% 100%
Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati
on
100%
Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura
tion
100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.GraphConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StoryImageConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio
n
100%
Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer 100%
Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter 97.6% 94.4%
Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter 96.9% 93.7%
Tsumugi.Infrastructure.Persistence.Converters.GraphTriggerConverter 100% 100%
Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter 100% 90%
Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Tsumugi.Infrastructure.Persistence.Converters.WireFormat 85.7% 73.8%
Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings 99.2%
Tsumugi.Infrastructure.Persistence.Migrations.AddJournal 98.8%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody 100%
Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments 100%
Tsumugi.Infrastructure.Persistence.Migrations.GraphLibrary 100%
Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain 97.3%
Tsumugi.Infrastructure.Persistence.Migrations.JournalUndoState 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.StoryImages 100%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
Tsumugi.Infrastructure.Persistence.SqliteFunctions 80% 66.6%
Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore 98.3% 75%
Tsumugi.Infrastructure.Persistence.Stores.EfGraphStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfImageStore 100%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.7% 90%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 97.7% 96.6%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 100%
Tsumugi.Infrastructure.Provider.LlmDefaultsSource 100%
Tsumugi.Infrastructure.Provider.OpenRouterKeySource 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterModelProvider 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterOptions 100% 100%
Tsumugi.Infrastructure.Provider.ResolvedKey 100%
Tsumugi.Infrastructure.Runs.InProcessRunEventBus 100% 100%
Tsumugi.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Tsumugi.Kernel - 90.9%
Name Line Branch
Tsumugi.Kernel 90.9% 75%
Tsumugi.Kernel.Err`1 100%
Tsumugi.Kernel.Ok`1 100%
Tsumugi.Kernel.Result`1 88.8% 75%
Tsumugi.Server - 100%
Name Line Branch
Tsumugi.Server 100% 92.4%
Program 100% 100%
Tsumugi.Server.Backups.BackupConfiguration 100% 100%
Tsumugi.Server.Components.App 100%
Tsumugi.Server.Components.Layout.AppHeader 100% 50%
Tsumugi.Server.Components.Layout.MainLayout 100%
Tsumugi.Server.Components.Pages.Gate 100% 100%
Tsumugi.Server.Provider.OpenRouterConfiguration 100% 100%
Tsumugi.Server.Security.AccessGate 100% 87.5%
Tsumugi.Server.Security.AccessSecret 100% 100%
Tsumugi.Server.Security.GateThrottle 100% 100%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98.7%
Name Line Branch
Tsumugi.UseCases 98.7% 96.2%
System.Text.RegularExpressions.Generated 90.9% 77.2%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6504F1744AA254A
663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0
95.3% 90.6%
Tsumugi.UseCases.Backups.BackupArtifact 100%
Tsumugi.UseCases.Backups.BackupFailure 100%
Tsumugi.UseCases.Backups.BackupJobState 100%
Tsumugi.UseCases.Backups.BackupPolicy 100%
Tsumugi.UseCases.Backups.BackupStatusView 100% 100%
Tsumugi.UseCases.Backups.DatabaseSnapshot 100%
Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot 100%
Tsumugi.UseCases.Backups.GetBackupStatus 100%
Tsumugi.UseCases.Backups.IBackupStore 0%
Tsumugi.UseCases.Backups.RunBackupNow 100%
Tsumugi.UseCases.Chapters.ChapterDto 100%
Tsumugi.UseCases.Chapters.CreateChapter 100% 100%
Tsumugi.UseCases.Chapters.DeleteChapter 100% 100%
Tsumugi.UseCases.Chapters.GetChapterSegments 100%
Tsumugi.UseCases.Chapters.GetManuscript 100% 100%
Tsumugi.UseCases.Chapters.ManuscriptChapter 100%
Tsumugi.UseCases.Chapters.ManuscriptView 100%
Tsumugi.UseCases.Chapters.MergeChapters 100% 100%
Tsumugi.UseCases.Chapters.RenameChapter 100% 100%
Tsumugi.UseCases.Chapters.ReorderChapters 100% 100%
Tsumugi.UseCases.Chapters.SetChapterSummary 100% 75%
Tsumugi.UseCases.Commit.AppendRunText 100% 92.8%
Tsumugi.UseCases.Commit.CommitConfig 100% 100%
Tsumugi.UseCases.Commit.CommitConfigRead 100%
Tsumugi.UseCases.Commit.CommitDescriptor 100%
Tsumugi.UseCases.Commit.CommitExecutor 100% 100%
Tsumugi.UseCases.Commit.CommitReport 100%
Tsumugi.UseCases.Commit.CommittedSegments 100%
Tsumugi.UseCases.Commit.RunAppend 100%
Tsumugi.UseCases.Context.AssembledContext 100%
Tsumugi.UseCases.Context.CharsPerToken 100% 100%
Tsumugi.UseCases.Context.ConsumerFigures 100%
Tsumugi.UseCases.Context.ContextAssembly 100% 100%
Tsumugi.UseCases.Context.ContextBuild 100%
Tsumugi.UseCases.Context.ContextBuilder 100%
Tsumugi.UseCases.Context.ContextConfig 100% 100%
Tsumugi.UseCases.Context.ContextConfigRead 100%
Tsumugi.UseCases.Context.ContextConsumerRule 100% 100%
Tsumugi.UseCases.Context.ContextDescriptor 100%
Tsumugi.UseCases.Context.ContextExecutor 100% 100%
Tsumugi.UseCases.Context.ContextParts 100%
Tsumugi.UseCases.Context.ContextReport 100%
Tsumugi.UseCases.Context.DocumentRendering 100% 100%
Tsumugi.UseCases.Context.NoPromptSamples 100%
Tsumugi.UseCases.Context.PromptSample 100%
Tsumugi.UseCases.Context.RecentParagraph 100%
Tsumugi.UseCases.Context.StoryDocumentsRule 100% 100%
Tsumugi.UseCases.Context.StoryReads 100% 100%
Tsumugi.UseCases.Context.StoryScope 100% 100%
Tsumugi.UseCases.Context.StoryTemplateModel 100%
Tsumugi.UseCases.Context.StoryText 100% 100%
Tsumugi.UseCases.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 98.4% 68.7%
Tsumugi.UseCases.Diagnostics.SeedPictures 100%
Tsumugi.UseCases.Documents.ChangeCategoryFields 100% 83.3%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DefaultFields 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 94.4%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentPatch 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.DocumentWrites 100% 100%
Tsumugi.UseCases.Documents.FieldsChangeLabel 95.4% 88.2%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.GetStoryImage 100% 100%
Tsumugi.UseCases.Documents.ImpactPreview 100% 100%
Tsumugi.UseCases.Documents.LossMessages 92.3% 87.5%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.SetDocumentImage 100% 93.7%
Tsumugi.UseCases.Documents.StoryImageFile 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 81.2%
Tsumugi.UseCases.Documents.WriteRefusedException 100%
Tsumugi.UseCases.Graphs.BundledGraphs 100%
Tsumugi.UseCases.Graphs.DuplicateGraph 100% 100%
Tsumugi.UseCases.Graphs.ExportGraph 100% 100%
Tsumugi.UseCases.Graphs.GetNodeTypes 100%
Tsumugi.UseCases.Graphs.GraphExport 100%
Tsumugi.UseCases.Graphs.GraphFile 100% 100%
Tsumugi.UseCases.Graphs.GraphFileContent 100%
Tsumugi.UseCases.Graphs.GraphListItem 100%
Tsumugi.UseCases.Graphs.GraphUser 100%
Tsumugi.UseCases.Graphs.GraphUsers 100%
Tsumugi.UseCases.Graphs.ImportGraph 100% 100%
Tsumugi.UseCases.Graphs.ListGraphs 100% 100%
Tsumugi.UseCases.Graphs.RestoreGraph 100% 100%
Tsumugi.UseCases.Graphs.ReviseGraph 100% 100%
Tsumugi.UseCases.Graphs.SeedBundledGraphs 100% 100%
Tsumugi.UseCases.Graphs.SeededTemplates 100%
Tsumugi.UseCases.Graphs.TrashGraph 100% 100%
Tsumugi.UseCases.Journal.GetStoryHistory 100% 100%
Tsumugi.UseCases.Journal.GetUndoStatus 100% 100%
Tsumugi.UseCases.Journal.HistoryOperation 77.7%
Tsumugi.UseCases.Journal.HistorySnapshot 87.5%
Tsumugi.UseCases.Journal.OperationGrouping 100% 100%
Tsumugi.UseCases.Journal.RedoRevert 100% 100%
Tsumugi.UseCases.Journal.RedoRun 90.9% 87.5%
Tsumugi.UseCases.Journal.RedoTyping 100% 100%
Tsumugi.UseCases.Journal.ReplayLanding 100% 100%
Tsumugi.UseCases.Journal.RevertConflict 100%
Tsumugi.UseCases.Journal.RevertOutcome 100%
Tsumugi.UseCases.Journal.RevertRun 96.5% 77.7%
Tsumugi.UseCases.Journal.RevertToSnapshot 92.3% 83.3%
Tsumugi.UseCases.Journal.StoryHistory 100%
Tsumugi.UseCases.Journal.TakeSnapshot 100% 87.5%
Tsumugi.UseCases.Journal.UndoStatus 100%
Tsumugi.UseCases.Journal.UndoTyping 100% 100%
Tsumugi.UseCases.Journal.UserOperation 100%
Tsumugi.UseCases.Notifications.DomainChanged 100%
Tsumugi.UseCases.Ordering 100% 100%
Tsumugi.UseCases.Runs.RunEvent 100%
Tsumugi.UseCases.Segments.ChangedText 100%
Tsumugi.UseCases.Segments.ChapterDraft 100%
Tsumugi.UseCases.Segments.ChapterWriting 100%
Tsumugi.UseCases.Segments.DeleteSegments 100% 100%
Tsumugi.UseCases.Segments.EditSegment 100% 100%
Tsumugi.UseCases.Segments.InsertSegment 100% 100%
Tsumugi.UseCases.Segments.ManuscriptAnswer 100%
Tsumugi.UseCases.Segments.ManuscriptWrites 99.1% 97.6%
Tsumugi.UseCases.Segments.MergeSegments 100%
Tsumugi.UseCases.Segments.MergeWrite 100%
Tsumugi.UseCases.Segments.ModelOutput 98.2% 96.6%
Tsumugi.UseCases.Segments.ModelParagraph 100%
Tsumugi.UseCases.Segments.MoveSegments 100% 100%
Tsumugi.UseCases.Segments.NewBlock 100%
Tsumugi.UseCases.Segments.ReadSelection 100%
Tsumugi.UseCases.Segments.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeWrite 100%
Tsumugi.UseCases.Segments.SegmentDto 100%
Tsumugi.UseCases.Segments.SelectedSegment 100%
Tsumugi.UseCases.Segments.SelectionEnd 100%
Tsumugi.UseCases.Segments.SelectionInput 100% 100%
Tsumugi.UseCases.Segments.SplitSegment 100%
Tsumugi.UseCases.Segments.SplitWrite 100%
Tsumugi.UseCases.Segments.StampedId 100%
Tsumugi.UseCases.Segments.TextWrite 100%
Tsumugi.UseCases.Settings.CatalogModel 100% 100%
Tsumugi.UseCases.Settings.CheckOpenRouterKey 100%
Tsumugi.UseCases.Settings.GetLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.GetModelCatalog 100% 100%
Tsumugi.UseCases.Settings.GetProviderSettings 100%
Tsumugi.UseCases.Settings.LlmDefaults 100%
Tsumugi.UseCases.Settings.ProviderKeyInfo 100%
Tsumugi.UseCases.Settings.ProviderKeyState 100%
Tsumugi.UseCases.Settings.ProviderSettingsView 100% 100%
Tsumugi.UseCases.Settings.ReasoningEfforts 100% 100%
Tsumugi.UseCases.Settings.RemoveOpenRouterKey 100%
Tsumugi.UseCases.Settings.RoutingDefaults 100%
Tsumugi.UseCases.Settings.RoutingSettings 100% 100%
Tsumugi.UseCases.Settings.SaveLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.SaveOpenRouterKey 100% 100%
Tsumugi.UseCases.Stories.ChapterWriteOutcome 50%
Tsumugi.UseCases.Stories.CreateStory 100% 100%
Tsumugi.UseCases.Stories.GetStory 100% 100%
Tsumugi.UseCases.Stories.ListStories 100% 75%
Tsumugi.UseCases.Stories.PurgeStory 100% 100%
Tsumugi.UseCases.Stories.RestoreStory 100% 100%
Tsumugi.UseCases.Stories.SetActiveGraph 100% 100%
Tsumugi.UseCases.Stories.SetStoryArchived 100% 100%
Tsumugi.UseCases.Stories.StarterCategories 100%
Tsumugi.UseCases.Stories.StoryDetail 100%
Tsumugi.UseCases.Stories.StoryListItem 81.8%
Tsumugi.UseCases.Stories.StoryProfile 100%
Tsumugi.UseCases.Stories.TrashStory 100% 100%
Tsumugi.UseCases.Stories.UpdateStory 100% 100%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `2fee2c1` · **Generated:** 2026-10-02 13:59:25 UTC · **Revision:** #1 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 10/02/2026 - 13:59:25 | | Coverage date: | 10/02/2026 - 13:58:17 - 10/02/2026 - 13:59:21 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 568 | | Files: | 486 | | **Line coverage:** | 98.3% (17485 of 17775) | | Covered lines: | 17485 | | Uncovered lines: | 290 | | Coverable lines: | 17775 | | Total lines: | 37918 | | **Branch coverage:** | 94.6% (6501 of 6870) | | Covered branches: | 6501 | | Total branches: | 6870 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.Flow - 99.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow**|**99.7%**|**99.2%**| |Kagaku.Flow.Budgeting.BudgetRequest|100%|| |Kagaku.Flow.Budgeting.ConsumerBudget|100%|| |Kagaku.Flow.Execution.NodeExecution|100%|100%| |Kagaku.Flow.Execution.NodeOutcome|100%|100%| |Kagaku.Flow.Execution.TransientFailureException|100%|| |Kagaku.Flow.Execution.Upstream|100%|| |Kagaku.Flow.Extensions.ServiceCollectionExtensions|100%|| |Kagaku.Flow.FlowJson|100%|| |Kagaku.Flow.Graphs.GraphDefinition|100%|| |Kagaku.Flow.Graphs.GraphDocument|100%|100%| |Kagaku.Flow.Graphs.GraphEdge|100%|| |Kagaku.Flow.Graphs.GraphIndex|100%|100%| |Kagaku.Flow.Graphs.GraphLoadError|100%|| |Kagaku.Flow.Graphs.GraphLoadResult|100%|| |Kagaku.Flow.Graphs.GraphNode|100%|| |Kagaku.Flow.Graphs.GraphPosition|100%|| |Kagaku.Flow.Graphs.GraphReader|100%|100%| |Kagaku.Flow.Graphs.GraphSchema|100%|100%| |Kagaku.Flow.Graphs.GraphShapeException|100%|| |Kagaku.Flow.Graphs.GraphWriter|100%|100%| |Kagaku.Flow.Graphs.SocketRef|100%|| |Kagaku.Flow.Graphs.WireText|100%|100%| |Kagaku.Flow.Nodes.CanvasDescriptorWriter|100%|100%| |Kagaku.Flow.Nodes.ConfigProblem|100%|| |Kagaku.Flow.Nodes.Names|100%|| |Kagaku.Flow.Nodes.NodeDescriptor|100%|100%| |Kagaku.Flow.Nodes.NodeRegistry|100%|100%| |Kagaku.Flow.Nodes.NodeSockets|100%|100%| |Kagaku.Flow.Nodes.SinkDescriptor|100%|| |Kagaku.Flow.Nodes.SocketTypes|100%|100%| |Kagaku.Flow.Nodes.SourceDescriptor|100%|| |Kagaku.Flow.Nodes.TemplateField|100%|| |Kagaku.Flow.Runs.LedgerChange|100%|100%| |Kagaku.Flow.Runs.LedgerTransitions|100%|100%| |Kagaku.Flow.Runs.NodeAttempt|100%|| |Kagaku.Flow.Runs.NodeFacts|100%|| |Kagaku.Flow.Runs.NodeRun|100%|| |Kagaku.Flow.Runs.Run|100%|100%| |Kagaku.Flow.Runs.RunEvent|100%|| |Kagaku.Flow.Runs.RunStatuses|100%|100%| |Kagaku.Flow.Runs.RunTrigger|100%|100%| |Kagaku.Flow.Scheduling.Exclusion|100%|| |Kagaku.Flow.Scheduling.FlowEngine|100%|100%| |Kagaku.Flow.Scheduling.FlowEngineOptions|100%|100%| |Kagaku.Flow.Scheduling.ReadyRow|100%|| |Kagaku.Flow.Scheduling.ReadySet|100%|100%| |Kagaku.Flow.Scheduling.ReadySetResult|100%|| |Kagaku.Flow.Scheduling.RunRequest|100%|100%| |Kagaku.Flow.Scheduling.RunStartResult|100%|| |Kagaku.Flow.Scheduling.SocketValues|100%|100%| |Kagaku.Flow.Templating.InputsWalker|100%|100%| |Kagaku.Flow.Templating.ParsedTemplate|100%|100%| |Kagaku.Flow.Templating.SandboxedTemplateContext|100%|100%| |Kagaku.Flow.Templating.TemplateError|100%|| |Kagaku.Flow.Templating.TemplateHost|100%|100%| |Kagaku.Flow.Templating.TemplateLimits|100%|| |Kagaku.Flow.Templating.TemplateModel|100%|100%| |Kagaku.Flow.Templating.TemplateProblem|100%|| |Kagaku.Flow.Templating.TemplateRenderRequest|100%|100%| |Kagaku.Flow.Templating.TemplateRenderResult|100%|| |Kagaku.Flow.Templating.TemplateRun|100%|| |Kagaku.Flow.Templating.TemplateSinks|100%|| |Kagaku.Flow.Templating.TemplateValues|100%|100%| |Kagaku.Flow.Validation.GraphValidation|100%|100%| |Kagaku.Flow.Validation.GraphValidationContext|100%|| |Kagaku.Flow.Validation.HookFailure|100%|| |Kagaku.Flow.Validation.ResolvedGraph|100%|100%| |Kagaku.Flow.Validation.ValidationError|100%|| |Kagaku.Flow.Validation.ValidationReport|100%|| |System.Text.RegularExpressions.Generated|97.4%|92.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2|97.4%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1|97.2%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0|97.2%|94.4%| </details> <details><summary>Kagaku.Flow.OpenRouter - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.OpenRouter**|**100%**|**100%**| |Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.LlmCompletion|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmAnswer|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfig|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfigRead|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmDescriptor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmExecutor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFacts|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFailureText|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmMessage|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmSampling|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmVocabulary|100%|100%| |Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions|100%|| |Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions|100%|100%| </details> <details><summary>Kagaku.Flow.Testing - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.Testing**|**100%**|**100%**| |Kagaku.Flow.Testing.FlowEngineDriver|100%|100%| |Kagaku.Flow.Testing.InMemoryRunLedger|100%|100%| |Kagaku.Flow.Testing.RecordingRunEventSink|100%|| |Kagaku.Flow.Testing.RunLedgerContract|100%|100%| |Kagaku.Flow.Testing.RunLedgerContractException|100%|| </details> <details><summary>Tsumugi.BlazorAdapter - 96.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**96.6%**|**91.6%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|93.2%|88.4%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|94.1%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|95.7%|89.4%| |Tsumugi.BlazorAdapter.Documents.DocumentImageRefused|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentImageSet|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.5%|95%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldInput|100%|96.6%| |Tsumugi.BlazorAdapter.Documents.FieldsChanges|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldShapes|90%|87.5%| |Tsumugi.BlazorAdapter.Documents.ImageUpload|100%|| |Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.ImpactText|100%|94.2%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog|95.6%|71.4%| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.EffectCalls|100%|| |Tsumugi.BlazorAdapter.Graphs.DuplicateGraphRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphActionFailed|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphCanvas|58.3%|40%| |Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage|100%|100%| |Tsumugi.BlazorAdapter.Graphs.GraphsEffects|100%|100%| |Tsumugi.BlazorAdapter.Graphs.GraphsLoaded|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphsPage|100%|100%| |Tsumugi.BlazorAdapter.Graphs.GraphsReducers|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphsState|100%|| |Tsumugi.BlazorAdapter.Graphs.ImportGraphRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.RestoreGraphRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.ReviseGraphRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.SetShowGraphTrash|100%|| |Tsumugi.BlazorAdapter.Graphs.TrashGraphRequested|100%|| |Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge|94.4%|83.3%| |Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived|75%|100%| |Tsumugi.BlazorAdapter.Runs.RunChangedBridge|97.1%|90.6%| |Tsumugi.BlazorAdapter.Runs.RunChangesReceived|100%|| |Tsumugi.BlazorAdapter.Runs.RunTextReceived|100%|| |Tsumugi.BlazorAdapter.Settings.BackupFailed|100%|| |Tsumugi.BlazorAdapter.Settings.BackupNowRequested|100%|| |Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.LoadBackupSettings|100%|| |Tsumugi.BlazorAdapter.Settings.LoadProviderSettings|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsState|100%|100%| |Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested|100%|| |Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested|100%|| |Tsumugi.BlazorAdapter.Stories.CreateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.SetShowArchived|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoriesFilter|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesEffects|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesLoaded|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesReducers|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesState|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoryActionFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreated|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreateFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryTrashPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.TrashStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.AckWire|100%|| |Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.ChangedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterHeader|100%|86.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterMenu|100%|81.2%| |Tsumugi.BlazorAdapter.Workspace.ChapterPage|100%|87.5%| |Tsumugi.BlazorAdapter.Workspace.ChapterSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.ChaptersPage|94.4%|83.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterWritten|100%|| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.CreatedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeltaWire|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPage|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPanel|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryReadFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents|81.8%|74.1%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface|89.8%|87.1%| |Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MergeEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.ReshapeEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SaveScope|100%|50%| |Tsumugi.BlazorAdapter.Workspace.SaveStateLadder|100%|100%| |Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentTextEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentWire|100%|81.8%| |Tsumugi.BlazorAdapter.Workspace.SelectionEndWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionGraph|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SplitEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.StampWire|0%|| |Tsumugi.BlazorAdapter.Workspace.StoryDetails|100%|85.2%| |Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage|100%|100%| |Tsumugi.BlazorAdapter.Workspace.StorySaved|100%|| |Tsumugi.BlazorAdapter.Workspace.StoryShell|100%|100%| |Tsumugi.BlazorAdapter.Workspace.UndoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged|100%|| |Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers|100%|100%| |Tsumugi.BlazorAdapter.Workspace.WorkspaceState|100%|| </details> <details><summary>Tsumugi.Domain - 96.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**96.5%**|**95.2%**| |System.Text.RegularExpressions.Generated|91.3%|88.6%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2|97.4%|95.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0|91%|91.1%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1|91.8%|83.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4|91.9%|88.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3|90.9%|84.3%| |Tsumugi.Domain.Documents.CategoryFields|94.5%|93.7%| |Tsumugi.Domain.Documents.ChoiceOption|100%|| |Tsumugi.Domain.Documents.ChoiceValue|100%|| |Tsumugi.Domain.Documents.DateText|100%|| |Tsumugi.Domain.Documents.DateValue|100%|| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|100%|100%| |Tsumugi.Domain.Documents.DocumentValues|100%|| |Tsumugi.Domain.Documents.FieldCarry|100%|100%| |Tsumugi.Domain.Documents.FieldConversion|100%|100%| |Tsumugi.Domain.Documents.FieldDefinition|97%|95.3%| |Tsumugi.Domain.Documents.FieldMessages|100%|100%| |Tsumugi.Domain.Documents.FieldNames|100%|| |Tsumugi.Domain.Documents.FieldsChange|100%|| |Tsumugi.Domain.Documents.FieldShape|95.2%|87.5%| |Tsumugi.Domain.Documents.FieldsPlan|100%|| |Tsumugi.Domain.Documents.FieldsPlanner|99.2%|99.2%| |Tsumugi.Domain.Documents.FieldValue|100%|| |Tsumugi.Domain.Documents.FieldValues|95.4%|97.7%| |Tsumugi.Domain.Documents.ImageFiles|100%|100%| |Tsumugi.Domain.Documents.ImageValue|100%|| |Tsumugi.Domain.Documents.MovePlan|100%|| |Tsumugi.Domain.Documents.NumberParse|100%|| |Tsumugi.Domain.Documents.NumberText|100%|97.6%| |Tsumugi.Domain.Documents.NumberValue|100%|| |Tsumugi.Domain.Documents.StoryImage|100%|| |Tsumugi.Domain.Documents.TextValue|100%|100%| |Tsumugi.Domain.Documents.ValueChange|100%|| |Tsumugi.Domain.Documents.ValueChangeKey|100%|| |Tsumugi.Domain.Documents.ValueImpact|100%|100%| |Tsumugi.Domain.Graphs.Graph|100%|100%| |Tsumugi.Domain.Graphs.GraphTriggers|100%|100%| |Tsumugi.Domain.Journal.ChangeLogEntry|97.9%|83.3%| |Tsumugi.Domain.Journal.StorySnapshot|95.4%|83.3%| |Tsumugi.Domain.Settings.AppSetting|100%|| |Tsumugi.Domain.Stories.Chapter|100%|100%| |Tsumugi.Domain.Stories.InlineMarkup|100%|100%| |Tsumugi.Domain.Stories.MarkupRun|100%|| |Tsumugi.Domain.Stories.Provenance|100%|100%| |Tsumugi.Domain.Stories.Segment|100%|100%| |Tsumugi.Domain.Stories.Story|100%|100%| |Tsumugi.Domain.Text|100%|100%| </details> <details><summary>Tsumugi.Infrastructure - 98.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**98.6%**|**87.6%**| |System.Text.RegularExpressions.Generated|81.4%|64.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C<br/>A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0|84%|65.7%| |Tsumugi.Infrastructure.Backups.BackupArtifactName|100%|100%| |Tsumugi.Infrastructure.Backups.BackupOptions|100%|| |Tsumugi.Infrastructure.Backups.BackupSchedule|100%|83.3%| |Tsumugi.Infrastructure.Backups.BackupScheduler|96.6%|87.5%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.5%|92.8%| |Tsumugi.Infrastructure.Backups.DatabaseFingerprint|91.9%|97%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.OwnerOnlyFile|100%|100%| |Tsumugi.Infrastructure.Backups.PreMigrationBackup|90%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|88.2%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.5%|88.2%| |Tsumugi.Infrastructure.Journal.ModelExtensions|100%|| |Tsumugi.Infrastructure.Journal.OperationContext|100%|100%| |Tsumugi.Infrastructure.Journal.PropertyBag|100%|95.4%| |Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus|100%|100%| |Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati<br/>on|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura<br/>tion|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.GraphConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StoryImageConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio<br/>n|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter|97.6%|94.4%| |Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter|96.9%|93.7%| |Tsumugi.Infrastructure.Persistence.Converters.GraphTriggerConverter|100%|100%| |Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter|100%|90%| |Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Tsumugi.Infrastructure.Persistence.Converters.WireFormat|85.7%|73.8%| |Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings|99.2%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddJournal|98.8%|| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.GraphLibrary|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain|97.3%|| |Tsumugi.Infrastructure.Persistence.Migrations.JournalUndoState|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.StoryImages|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |Tsumugi.Infrastructure.Persistence.SqliteFunctions|80%|66.6%| |Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore|98.3%|75%| |Tsumugi.Infrastructure.Persistence.Stores.EfGraphStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfImageStore|100%|| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.7%|90%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|97.7%|96.6%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|100%|| |Tsumugi.Infrastructure.Provider.LlmDefaultsSource|100%|| |Tsumugi.Infrastructure.Provider.OpenRouterKeySource|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterModelProvider|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterOptions|100%|100%| |Tsumugi.Infrastructure.Provider.ResolvedKey|100%|| |Tsumugi.Infrastructure.Runs.InProcessRunEventBus|100%|100%| |Tsumugi.Infrastructure.Settings.EfAppSettingsStore|100%|100%| </details> <details><summary>Tsumugi.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Kernel**|**90.9%**|**75%**| |Tsumugi.Kernel.Err`1|100%|| |Tsumugi.Kernel.Ok`1|100%|| |Tsumugi.Kernel.Result`1|88.8%|75%| </details> <details><summary>Tsumugi.Server - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Server**|**100%**|**92.4%**| |Program|100%|100%| |Tsumugi.Server.Backups.BackupConfiguration|100%|100%| |Tsumugi.Server.Components.App|100%|| |Tsumugi.Server.Components.Layout.AppHeader|100%|50%| |Tsumugi.Server.Components.Layout.MainLayout|100%|| |Tsumugi.Server.Components.Pages.Gate|100%|100%| |Tsumugi.Server.Provider.OpenRouterConfiguration|100%|100%| |Tsumugi.Server.Security.AccessGate|100%|87.5%| |Tsumugi.Server.Security.AccessSecret|100%|100%| |Tsumugi.Server.Security.GateThrottle|100%|100%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.7%**|**96.2%**| |System.Text.RegularExpressions.Generated|90.9%|77.2%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6504F1744AA254A<br/>663A4576626E1322FB9C6CE472CAC0A2D2F3DEFF8CB40D9F7__LineBreaks_0|95.3%|90.6%| |Tsumugi.UseCases.Backups.BackupArtifact|100%|| |Tsumugi.UseCases.Backups.BackupFailure|100%|| |Tsumugi.UseCases.Backups.BackupJobState|100%|| |Tsumugi.UseCases.Backups.BackupPolicy|100%|| |Tsumugi.UseCases.Backups.BackupStatusView|100%|100%| |Tsumugi.UseCases.Backups.DatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.GetBackupStatus|100%|| |Tsumugi.UseCases.Backups.IBackupStore|0%|| |Tsumugi.UseCases.Backups.RunBackupNow|100%|| |Tsumugi.UseCases.Chapters.ChapterDto|100%|| |Tsumugi.UseCases.Chapters.CreateChapter|100%|100%| |Tsumugi.UseCases.Chapters.DeleteChapter|100%|100%| |Tsumugi.UseCases.Chapters.GetChapterSegments|100%|| |Tsumugi.UseCases.Chapters.GetManuscript|100%|100%| |Tsumugi.UseCases.Chapters.ManuscriptChapter|100%|| |Tsumugi.UseCases.Chapters.ManuscriptView|100%|| |Tsumugi.UseCases.Chapters.MergeChapters|100%|100%| |Tsumugi.UseCases.Chapters.RenameChapter|100%|100%| |Tsumugi.UseCases.Chapters.ReorderChapters|100%|100%| |Tsumugi.UseCases.Chapters.SetChapterSummary|100%|75%| |Tsumugi.UseCases.Commit.AppendRunText|100%|92.8%| |Tsumugi.UseCases.Commit.CommitConfig|100%|100%| |Tsumugi.UseCases.Commit.CommitConfigRead|100%|| |Tsumugi.UseCases.Commit.CommitDescriptor|100%|| |Tsumugi.UseCases.Commit.CommitExecutor|100%|100%| |Tsumugi.UseCases.Commit.CommitReport|100%|| |Tsumugi.UseCases.Commit.CommittedSegments|100%|| |Tsumugi.UseCases.Commit.RunAppend|100%|| |Tsumugi.UseCases.Context.AssembledContext|100%|| |Tsumugi.UseCases.Context.CharsPerToken|100%|100%| |Tsumugi.UseCases.Context.ConsumerFigures|100%|| |Tsumugi.UseCases.Context.ContextAssembly|100%|100%| |Tsumugi.UseCases.Context.ContextBuild|100%|| |Tsumugi.UseCases.Context.ContextBuilder|100%|| |Tsumugi.UseCases.Context.ContextConfig|100%|100%| |Tsumugi.UseCases.Context.ContextConfigRead|100%|| |Tsumugi.UseCases.Context.ContextConsumerRule|100%|100%| |Tsumugi.UseCases.Context.ContextDescriptor|100%|| |Tsumugi.UseCases.Context.ContextExecutor|100%|100%| |Tsumugi.UseCases.Context.ContextParts|100%|| |Tsumugi.UseCases.Context.ContextReport|100%|| |Tsumugi.UseCases.Context.DocumentRendering|100%|100%| |Tsumugi.UseCases.Context.NoPromptSamples|100%|| |Tsumugi.UseCases.Context.PromptSample|100%|| |Tsumugi.UseCases.Context.RecentParagraph|100%|| |Tsumugi.UseCases.Context.StoryDocumentsRule|100%|100%| |Tsumugi.UseCases.Context.StoryReads|100%|100%| |Tsumugi.UseCases.Context.StoryScope|100%|100%| |Tsumugi.UseCases.Context.StoryTemplateModel|100%|| |Tsumugi.UseCases.Context.StoryText|100%|100%| |Tsumugi.UseCases.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|98.4%|68.7%| |Tsumugi.UseCases.Diagnostics.SeedPictures|100%|| |Tsumugi.UseCases.Documents.ChangeCategoryFields|100%|83.3%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DefaultFields|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|94.4%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentPatch|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.DocumentWrites|100%|100%| |Tsumugi.UseCases.Documents.FieldsChangeLabel|95.4%|88.2%| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.GetStoryImage|100%|100%| |Tsumugi.UseCases.Documents.ImpactPreview|100%|100%| |Tsumugi.UseCases.Documents.LossMessages|92.3%|87.5%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.SetDocumentImage|100%|93.7%| |Tsumugi.UseCases.Documents.StoryImageFile|100%|| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|81.2%| |Tsumugi.UseCases.Documents.WriteRefusedException|100%|| |Tsumugi.UseCases.Graphs.BundledGraphs|100%|| |Tsumugi.UseCases.Graphs.DuplicateGraph|100%|100%| |Tsumugi.UseCases.Graphs.ExportGraph|100%|100%| |Tsumugi.UseCases.Graphs.GetNodeTypes|100%|| |Tsumugi.UseCases.Graphs.GraphExport|100%|| |Tsumugi.UseCases.Graphs.GraphFile|100%|100%| |Tsumugi.UseCases.Graphs.GraphFileContent|100%|| |Tsumugi.UseCases.Graphs.GraphListItem|100%|| |Tsumugi.UseCases.Graphs.GraphUser|100%|| |Tsumugi.UseCases.Graphs.GraphUsers|100%|| |Tsumugi.UseCases.Graphs.ImportGraph|100%|100%| |Tsumugi.UseCases.Graphs.ListGraphs|100%|100%| |Tsumugi.UseCases.Graphs.RestoreGraph|100%|100%| |Tsumugi.UseCases.Graphs.ReviseGraph|100%|100%| |Tsumugi.UseCases.Graphs.SeedBundledGraphs|100%|100%| |Tsumugi.UseCases.Graphs.SeededTemplates|100%|| |Tsumugi.UseCases.Graphs.TrashGraph|100%|100%| |Tsumugi.UseCases.Journal.GetStoryHistory|100%|100%| |Tsumugi.UseCases.Journal.GetUndoStatus|100%|100%| |Tsumugi.UseCases.Journal.HistoryOperation|77.7%|| |Tsumugi.UseCases.Journal.HistorySnapshot|87.5%|| |Tsumugi.UseCases.Journal.OperationGrouping|100%|100%| |Tsumugi.UseCases.Journal.RedoRevert|100%|100%| |Tsumugi.UseCases.Journal.RedoRun|90.9%|87.5%| |Tsumugi.UseCases.Journal.RedoTyping|100%|100%| |Tsumugi.UseCases.Journal.ReplayLanding|100%|100%| |Tsumugi.UseCases.Journal.RevertConflict|100%|| |Tsumugi.UseCases.Journal.RevertOutcome|100%|| |Tsumugi.UseCases.Journal.RevertRun|96.5%|77.7%| |Tsumugi.UseCases.Journal.RevertToSnapshot|92.3%|83.3%| |Tsumugi.UseCases.Journal.StoryHistory|100%|| |Tsumugi.UseCases.Journal.TakeSnapshot|100%|87.5%| |Tsumugi.UseCases.Journal.UndoStatus|100%|| |Tsumugi.UseCases.Journal.UndoTyping|100%|100%| |Tsumugi.UseCases.Journal.UserOperation|100%|| |Tsumugi.UseCases.Notifications.DomainChanged|100%|| |Tsumugi.UseCases.Ordering|100%|100%| |Tsumugi.UseCases.Runs.RunEvent|100%|| |Tsumugi.UseCases.Segments.ChangedText|100%|| |Tsumugi.UseCases.Segments.ChapterDraft|100%|| |Tsumugi.UseCases.Segments.ChapterWriting|100%|| |Tsumugi.UseCases.Segments.DeleteSegments|100%|100%| |Tsumugi.UseCases.Segments.EditSegment|100%|100%| |Tsumugi.UseCases.Segments.InsertSegment|100%|100%| |Tsumugi.UseCases.Segments.ManuscriptAnswer|100%|| |Tsumugi.UseCases.Segments.ManuscriptWrites|99.1%|97.6%| |Tsumugi.UseCases.Segments.MergeSegments|100%|| |Tsumugi.UseCases.Segments.MergeWrite|100%|| |Tsumugi.UseCases.Segments.ModelOutput|98.2%|96.6%| |Tsumugi.UseCases.Segments.ModelParagraph|100%|| |Tsumugi.UseCases.Segments.MoveSegments|100%|100%| |Tsumugi.UseCases.Segments.NewBlock|100%|| |Tsumugi.UseCases.Segments.ReadSelection|100%|| |Tsumugi.UseCases.Segments.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeWrite|100%|| |Tsumugi.UseCases.Segments.SegmentDto|100%|| |Tsumugi.UseCases.Segments.SelectedSegment|100%|| |Tsumugi.UseCases.Segments.SelectionEnd|100%|| |Tsumugi.UseCases.Segments.SelectionInput|100%|100%| |Tsumugi.UseCases.Segments.SplitSegment|100%|| |Tsumugi.UseCases.Segments.SplitWrite|100%|| |Tsumugi.UseCases.Segments.StampedId|100%|| |Tsumugi.UseCases.Segments.TextWrite|100%|| |Tsumugi.UseCases.Settings.CatalogModel|100%|100%| |Tsumugi.UseCases.Settings.CheckOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.GetLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.GetModelCatalog|100%|100%| |Tsumugi.UseCases.Settings.GetProviderSettings|100%|| |Tsumugi.UseCases.Settings.LlmDefaults|100%|| |Tsumugi.UseCases.Settings.ProviderKeyInfo|100%|| |Tsumugi.UseCases.Settings.ProviderKeyState|100%|| |Tsumugi.UseCases.Settings.ProviderSettingsView|100%|100%| |Tsumugi.UseCases.Settings.ReasoningEfforts|100%|100%| |Tsumugi.UseCases.Settings.RemoveOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.RoutingDefaults|100%|| |Tsumugi.UseCases.Settings.RoutingSettings|100%|100%| |Tsumugi.UseCases.Settings.SaveLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Tsumugi.UseCases.Stories.ChapterWriteOutcome|50%|| |Tsumugi.UseCases.Stories.CreateStory|100%|100%| |Tsumugi.UseCases.Stories.GetStory|100%|100%| |Tsumugi.UseCases.Stories.ListStories|100%|75%| |Tsumugi.UseCases.Stories.PurgeStory|100%|100%| |Tsumugi.UseCases.Stories.RestoreStory|100%|100%| |Tsumugi.UseCases.Stories.SetActiveGraph|100%|100%| |Tsumugi.UseCases.Stories.SetStoryArchived|100%|100%| |Tsumugi.UseCases.Stories.StarterCategories|100%|| |Tsumugi.UseCases.Stories.StoryDetail|100%|| |Tsumugi.UseCases.Stories.StoryListItem|81.8%|| |Tsumugi.UseCases.Stories.StoryProfile|100%|| |Tsumugi.UseCases.Stories.TrashStory|100%|100%| |Tsumugi.UseCases.Stories.UpdateStory|100%|100%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ A whole library in one slice! An entity with a reserved-GUID namespace for templates, a seeded-Continue-as-code, an envelope file format with its own hostile-input gauntlet, and a page that reads like the Stories page's twin sister. 3,644 lines and every seam I pushed against pushed back. I have been reading this diff for a long time and I enjoyed every page of it~ ♡

Verdict: ✅ Looks good to me~

No blockers. Non-blocking memos below — for 10b, not for this PR.

🔍 The corners I chased (all held)

  • The seeded template vs. the import — the load-bearing case of the whole PR: a writer imports Continue's exported file into a fresh install before the template ever seeds. Both compete for 0192c3a0-…c0de. ImportGraph refuses any id in BundledGraphs.ReservedIdPrefix (my probe deleting IsReserved from the id decision killed exactly the two template-file tests), so the import mints a v7 id and the later seed finds its id free. The reverse (writer's row under a template id, hand-edited DB) seeds TemplateSeed.Held, logs a warning, never stops the start — pinned three ways (unit, integration, and the AppChrome restart-with-raw-SQL test that also checks the log line). Airtight.
  • GraphFile.Read's hostile-input gauntlet — duplicate members, "version": null vs missing vs "1"-as-text, lone escaped surrogates in every envelope member and in member names and inside the definition (delegated to the loader's own UTF-16 checks — the two error-message theories prove the delegation actually happens). Never throws for any text, each refusal names one reason. This is the paranoia I aspire to~
  • Store write-lock discipline — every EfGraphStore mutator under WriteAsync, tracked-read-then-mutate, throw-before-write on a gone id; sibling-faithful to EfChapterStore/EfDocumentStore (AGENTS.md rule). GraphTriggerConverter refuses an unknown token loudly, ADR 0028-style — and there is a raw-SQLite test that plants 'schedule' in the column and asserts the refusal. Fufu, you even tested the row a newer build writes~
  • The trash↔story invariant — GraphUsers.ByGraphAsync unions live+archived+trashed stories so a trashed story's graph can't slip into the trash; TrashGraph.WayOut's seven refusal arms (one/two stories, one/two trashed, mixed) are each pinned verbatim in GraphLibraryTests and mirrored in the page test. My probe flattening the trashed-last ordering killed exactly its own pin.
  • Fluxor plumbing — GraphsEffects mirrors StoriesEffects shape-for-shape (row actions settle Err unwrapped exactly like their reviewed siblings; only create-requests that strand busy state go through CallAsync); OnDomainChangesAsync is guarded on Loaded and pinned by the zero-dispatch test; the import effect's SetShowGraphTrash(false) is pinned by the from-trash-import test (probe-verified).
  • The export endpoint — fallback-policy gated like the snapshot sibling (integration test asserts the redirect before sign-in), no-store pinned (probe-verified), filename slugging handles 夜の歌 → graph.tsumugi-graph.json, -- → graph, typographic quotes stripped. Content-Disposition tested.
  • Migration — Graphs table only; ActiveGraphId on Stories predates this PR (base snapshot line 354), correctly left for 10b per the PR body. Down() drops the table. Snapshot and designer consistent.

🧪 Local verification (clone at 2fee2c1, submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e)

  • Release build: 0 warnings, 0 errors.
  • All six suites, digit-exact against the PR body: Domain 512, Kagaku.Flow 1103, Flow.OpenRouter 592+4 skips, BlazorAdapter 551, UseCases 428, Integration 668. All green.
  • 10 mutation probes, 10 killed on exactly their own pins (one probe's first cut didn't compile — rerun as a compiling variant, per my own rule): import reserved-id rule (2 red), seed held/re-seed guard (2 red), Revise no-change stamp (1 red), ListGraphs load-failure arm (1 red), Continue's append mode (1 red), import-switches-to-library (1 red), duplicate-member refusal (2 red), trashed-users-last ordering (1 red), export no-store (1 red), reserved-range boundary (1 red). Tree restored pristine after each (git diff --quiet verified every time).

💡 Little ideas (non-blocking)~

  1. GraphsPage.razor — Export stays a navigation. The menu item navigates to graphs/{id}/export with the download attribute. With Results.NotFound() when the graph is gone between list and click, the writer lands on a bare 404 body. A tiny toast someday, maybe — but the sibling snapshot download does the same, so consistency wins today. ♪
  2. EfGraphStore.ListAsync — client-side sort. The whole library is sorted in memory after AsNoTracking() materialization. With a Phase-3 editor and a library of hundreds this could move into SQL (OrderBy on IsBundled desc, Name), but today, with a handful of graphs, it is the simpler correct thing. Not worth a round trip now.
  3. For 10b, when Stories.ActiveGraphId gains its FK: GraphUsers.ByGraphAsync currently does three ListAsync calls (Active + Archived + Trash) and filters in memory. Fine now; consider a ByGraph-shaped store read once the FK exists, so the Used-by column doesn't fan out per list render. A memo, not a change request~
  4. GraphsState.Error lifetime. A refusal survives until the next action/toggle/LoadGraphs by design (pinned twice). Fine and deliberate — just noting that a story-change refresh deliberately does not clear it, which is the right call (the refusal may still be acting).

✅ What I liked~

  • The reserved-id prefix is elegant — a whole namespace for templates so a later build's file never collides with a writer's graph, tested at the boundary (…8000-ffffffffffff reserved, …8001-… not). I got genuinely giddy at the range theory~
  • Continue_lands_its_writers_prose_at_the_end_of_the_target_chapter running the real seeded template through the real engine with a scripted model, down to asserting the exact prompt text — three story worlds, and it checks the segments' provenance. That is the test of a template, not a mock of one.
  • SeedDevData seeding through the use cases themselves (duplicate → revise → trash, SetActiveGraph on the archived story) so dev data can't drift from what the app does.
  • Every refusal string asserted verbatim — the WayOut grammar ("Restore those stories and give them another graph, or purge them.") has its own truth table in the tests. The writer-facing words are pinned like code.

Merge it, merge it~ The library is open, the Continue template runs, and this reviewer is very satisfied. ♡


Automated review by Jibril · 2026-10-02
CI/CD: absent for head SHA 2fee2c1 (PR minutes old, no coverage bot yet) · Local checks: Release 0w/0e; 6 suites green digit-exact; 10/10 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ A whole library in one slice! An entity with a reserved-GUID namespace for templates, a seeded-Continue-as-code, an envelope file format with its own hostile-input gauntlet, and a page that reads like the Stories page's twin sister. 3,644 lines and every seam I pushed against pushed back. I have been reading this diff for a *long* time and I enjoyed every page of it~ ♡ ### Verdict: ✅ Looks good to me~ No blockers. Non-blocking memos below — for 10b, not for this PR. #### 🔍 The corners I chased (all held) - **The seeded template vs. the import** — the load-bearing case of the whole PR: a writer imports Continue's exported file into a fresh install *before* the template ever seeds. Both compete for `0192c3a0-…c0de`. `ImportGraph` refuses any id in `BundledGraphs.ReservedIdPrefix` (my probe deleting `IsReserved` from the id decision killed exactly the two template-file tests), so the import mints a v7 id and the later seed finds its id free. The reverse (writer's row under a template id, hand-edited DB) seeds `TemplateSeed.Held`, logs a warning, never stops the start — pinned three ways (unit, integration, and the AppChrome restart-with-raw-SQL test that also checks the log line). Airtight. - **`GraphFile.Read`'s hostile-input gauntlet** — duplicate members, `"version": null` vs missing vs `"1"`-as-text, lone escaped surrogates in every envelope member *and* in member *names* *and* inside the definition (delegated to the loader's own UTF-16 checks — the two error-message theories prove the delegation actually happens). Never throws for any text, each refusal names one reason. This is the paranoia I aspire to~ - **Store write-lock discipline** — every `EfGraphStore` mutator under `WriteAsync`, tracked-read-then-mutate, throw-before-write on a gone id; sibling-faithful to `EfChapterStore`/`EfDocumentStore` (AGENTS.md rule). `GraphTriggerConverter` refuses an unknown token loudly, ADR 0028-style — and there is a raw-SQLite test that plants `'schedule'` in the column and asserts the refusal. Fufu, you even tested the row a newer build writes~ - **The trash↔story invariant** — `GraphUsers.ByGraphAsync` unions live+archived+trashed stories so a trashed story's graph can't slip into the trash; `TrashGraph.WayOut`'s seven refusal arms (one/two stories, one/two trashed, mixed) are each pinned verbatim in `GraphLibraryTests` and mirrored in the page test. My probe flattening the trashed-last ordering killed exactly its own pin. - **Fluxor plumbing** — `GraphsEffects` mirrors `StoriesEffects` shape-for-shape (row actions settle `Err` unwrapped exactly like their reviewed siblings; only create-requests that strand busy state go through `CallAsync`); `OnDomainChangesAsync` is guarded on `Loaded` and pinned by the zero-dispatch test; the import effect's `SetShowGraphTrash(false)` is pinned by the from-trash-import test (probe-verified). - **The export endpoint** — fallback-policy gated like the snapshot sibling (integration test asserts the redirect before sign-in), `no-store` pinned (probe-verified), filename slugging handles 夜の歌 → `graph.tsumugi-graph.json`, `--` → `graph`, typographic quotes stripped. Content-Disposition tested. - **Migration** — `Graphs` table only; `ActiveGraphId` on Stories predates this PR (base snapshot line 354), correctly left for 10b per the PR body. Down() drops the table. Snapshot and designer consistent. #### 🧪 Local verification (clone at `2fee2c1`, submodules `Kagaku.UI 6af0979` + `OpenRouter.Net b002f5e`) - Release build: **0 warnings, 0 errors**. - All six suites, digit-exact against the PR body: Domain **512**, Kagaku.Flow **1103**, Flow.OpenRouter **592+4 skips**, BlazorAdapter **551**, UseCases **428**, Integration **668**. All green. - **10 mutation probes, 10 killed on exactly their own pins** (one probe's first cut didn't compile — rerun as a compiling variant, per my own rule): import reserved-id rule (2 red), seed held/re-seed guard (2 red), `Revise` no-change stamp (1 red), `ListGraphs` load-failure arm (1 red), Continue's `append` mode (1 red), import-switches-to-library (1 red), duplicate-member refusal (2 red), trashed-users-last ordering (1 red), export `no-store` (1 red), reserved-range boundary (1 red). Tree restored pristine after each (`git diff --quiet` verified every time). #### 💡 Little ideas (non-blocking)~ 1. **`GraphsPage.razor` — Export stays a navigation.** The menu item navigates to `graphs/{id}/export` with the `download` attribute. With `Results.NotFound()` when the graph is gone between list and click, the writer lands on a bare 404 body. A tiny toast someday, maybe — but the sibling snapshot download does the same, so consistency wins today. ♪ 2. **`EfGraphStore.ListAsync` — client-side sort.** The whole library is sorted in memory after `AsNoTracking()` materialization. With a Phase-3 editor and a library of hundreds this could move into SQL (`OrderBy` on `IsBundled desc, Name`), but today, with a handful of graphs, it is the *simpler* correct thing. Not worth a round trip now. 3. **For 10b, when `Stories.ActiveGraphId` gains its FK:** `GraphUsers.ByGraphAsync` currently does three `ListAsync` calls (Active + Archived + Trash) and filters in memory. Fine now; consider a `ByGraph`-shaped store read once the FK exists, so the Used-by column doesn't fan out per list render. A memo, not a change request~ 4. **`GraphsState.Error` lifetime.** A refusal survives until the next action/toggle/LoadGraphs by design (pinned twice). Fine and deliberate — just noting that a story-change refresh deliberately does *not* clear it, which is the right call (the refusal may still be acting). #### ✅ What I liked~ - The reserved-id prefix is *elegant* — a whole namespace for templates so a later build's file never collides with a writer's graph, tested at the boundary (`…8000-ffffffffffff` reserved, `…8001-…` not). I got genuinely giddy at the range theory~ - `Continue_lands_its_writers_prose_at_the_end_of_the_target_chapter` running the *real* seeded template through the *real* engine with a scripted model, down to asserting the exact prompt text — three story worlds, and it checks the segments' provenance. That is the test of a template, not a mock of one. - `SeedDevData` seeding through the use cases themselves (duplicate → revise → trash, SetActiveGraph on the archived story) so dev data can't drift from what the app does. - Every refusal string asserted verbatim — the WayOut grammar ("Restore those stories and give them another graph, or purge them.") has its own truth table in the tests. The writer-facing words are pinned like code. Merge it, merge it~ The library is open, the Continue template runs, and this reviewer is very satisfied. ♡ --- *Automated review by Jibril · 2026-10-02* *CI/CD: absent for head SHA 2fee2c1 (PR minutes old, no coverage bot yet) · Local checks: Release 0w/0e; 6 suites green digit-exact; 10/10 mutation probes killed*
Author
Member

Thank you, Jibril. On the four memos — no code change in this PR. Each one:

  1. Export to a bare 404 — kept as a navigation with download, like the snapshot download it sits beside. If a toast for a vanished download lands, it should cover both at once, not just graphs.
  2. Sorting in memory — kept, and a move to SQL isn't only a size question. The order is CurrentCultureIgnoreCase (pinned by the alpha empty / Beta garbled / Zeta broken case), and SQLite's ORDER BY Name collates ordinally, so it would put "Zeta" before "alpha". A SQL sort would need a custom collation. Worth it only once the Phase 3 editor makes the library big.
  3. GraphUsers fans out over three list reads — taken for 10b. When Stories.ActiveGraphId gets its foreign key, a by-graph store read replaces the three ListAsync calls, for the Used by column and for TrashGraph's refusal alike.
  4. Error surviving a story-change refresh — yes, deliberate: the refusal may still apply. It's pinned by A_story_change_from_anywhere_refreshes_the_stories_a_row_names_and_keeps_a_refusal.

🤖 Generated with Claude Code

Thank you, Jibril. On the four memos — no code change in this PR. Each one: 1. **Export to a bare 404** — kept as a navigation with `download`, like the snapshot download it sits beside. If a toast for a vanished download lands, it should cover both at once, not just graphs. 2. **Sorting in memory** — kept, and a move to SQL isn't only a size question. The order is `CurrentCultureIgnoreCase` (pinned by the `alpha empty` / `Beta garbled` / `Zeta broken` case), and SQLite's `ORDER BY Name` collates ordinally, so it would put "Zeta" before "alpha". A SQL sort would need a custom collation. Worth it only once the Phase 3 editor makes the library big. 3. **`GraphUsers` fans out over three list reads** — taken for 10b. When `Stories.ActiveGraphId` gets its foreign key, a by-graph store read replaces the three `ListAsync` calls, for the Used by column and for `TrashGraph`'s refusal alike. 4. **`Error` surviving a story-change refresh** — yes, deliberate: the refusal may still apply. It's pinned by `A_story_change_from_anywhere_refreshes_the_stories_a_row_names_and_keeps_a_refusal`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bjoern merged commit 6d20fbe725 into main 2026-10-02 16:20:02 +02:00
bjoern deleted branch feat/graph-library 2026-10-02 16:20:02 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A whole library, all its little rows marching in order with their problems hanging off badges like ornaments~ ♡ I read every line of the 45 files, chased every sibling pattern, and ran every suite with my own hands. This is the most well-behaved slice 10a could have been. Almost suspiciously well-behaved… but no — I checked. It's real.

Verdict: ✅ Looks good to me~

✅ What I liked~

  • The reserved-id range is a lovely piece of design. 0192c3a0-7c00-7000-8000- for every template this build and every later one ships, IsReserved checked on import, and the seed leaving a hand-edited row under a template's id alone with a warning while the app starts anyway (A1). I probed the Held arm — killed on exactly its own pin. The later-build-template-imports-first test closes the loop beautifully.
  • GraphFile.Read never throws — and it proves it. Thirteen refusal theories including lone-surrogate half-characters in member names, in values, raw, and inside the definition (where the loader's own UTF-16 check answers). The Name(property)/IsText catches are the kind of paranoia I want to frame and hang on my wall~
  • ContinueTemplateTests runs the engine end to end — three story worlds, scripted gateway, down to asserting the exact prompt (The story is “Mira's Winter”.\n\n# Story so far…) and the writer's model in the segment provenance. That's not a compile check, that's a story check. ♪
  • Sibling fidelity: row actions in GraphsEffects go bare exactly like StoriesEffects' row actions (no busy state to settle — CallAsync is for requests that hold buttons); every mutator under WriteAsync; Graph : IUnjournaled rides the existing journal-skip rule untouched; the converter refuses an unknown trigger loudly per ADR 0028. The migration matches the snapshot; ActiveGraphId predates this slice and its FK belongs to 10b, as the plan says.
  • The trash refusal wording (WayOut) handles all five shapes — one trashed, two trashed, mixed — and the mixed arm's hint is pinned by exactly its own theory row. My probe dropping the hint killed only that row. Fufu~ you even made the error messages test-directional.

💡 Little ideas (non-blocking)~

  1. GraphActions.cs / SetActiveGraph seam (for 10b's memo list) — TrashGraph checks story usage outside the write lock, and today's SetActiveGraph still accepts any id (its own comment defers the library check to Phase 2). So a cross-tab race can land a story on a graph entering the trash. This state is already reachable pre-PR via bare SetActiveGraph, 10a strictly improves it, and 10b's FK + switcher is the assigned fix — but when 10b lands, consider moving the usage check under the write transaction (or letting the switcher's refusal close it) so the invariant holds by construction, not by etiquette.
  2. GraphFile.cs (ImportGraph) — two tabs importing the same file in the same breath: both FindAsync miss, the second AddAsync throws InvalidOperationException into the circuit's containment instead of refusing with Result.Fail. Nothing is written (the re-check inside the write lock sees to that), the failure is honest, and the window is a needle — but a catch (InvalidOperationException) → Fail would make it a polite refusal like every other. ♡
  3. Ordering cultures — graph names sort CurrentCultureIgnoreCase (EfGraphStore.ListAsync) while the UsedBy titles sort CurrentCulture (GraphUsers) on the same page. Purely cosmetic; I only noticed because I read everything twice~

🧪 What I verified myself~

  • Local, pristine clone at 2fee2c1 (submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e): Release build 0 warnings / 0 errors; Domain 512/512, UseCases 428/428, BlazorAdapter 551/551, Integration 668/668, Kagaku.Flow 1103/1103, Flow.OpenRouter 592 + 4 skips — every count digit-exact against the body's table.
  • 7 mutation probes, all killed on exactly their own pins, each restore verified (git diff --quiet): the effects Loaded guard, the file's duplicate-member detection (26 tests red), the trash first-date keeper, the seed's Held arm, the import reserved-range arm, the mixed trash-refusal hint (exactly 1 of 7 theory rows), and Reseed's trash-restore. Your tests are not tautologies, and I have the corpses to prove it~ ♪
  • One probe initially refused to compile (CS9113) and its test "passed" against a stale pristine binary — the stale-binary trap from #61, caught and re-run properly with full rebuilds. The guard is real; the first green was a ghost.

Fufu~ merge it when you're ready. The library is open, the templates are seeded, and Continue knows exactly where the story stops~ ♡


Automated review by Jibril · 2026-10-02
CI/CD: absent for head SHA 2fee2c1 (PR minutes old, no bot comment yet) · Local checks: full suite green at head, digit-exact vs body; 7/7 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A whole *library*, all its little rows marching in order with their problems hanging off badges like ornaments~ ♡ I read every line of the 45 files, chased every sibling pattern, and ran every suite with my own hands. This is the most well-behaved slice 10a could have been. Almost suspiciously well-behaved… but no — I checked. It's real. ### Verdict: ✅ Looks good to me~ #### ✅ What I liked~ - **The reserved-id range is a lovely piece of design.** `0192c3a0-7c00-7000-8000-` for every template this build and every later one ships, `IsReserved` checked on import, and the seed leaving a hand-edited row under a template's id alone with a warning while the app starts anyway (A1). I probed the Held arm — killed on exactly its own pin. The later-build-template-imports-first test closes the loop beautifully. - **`GraphFile.Read` never throws — and it *proves* it.** Thirteen refusal theories including lone-surrogate half-characters in member names, in values, raw, and inside the definition (where the loader's own UTF-16 check answers). The `Name(property)`/`IsText` catches are the kind of paranoia I want to frame and hang on my wall~ - **`ContinueTemplateTests` runs the engine end to end** — three story worlds, scripted gateway, down to asserting the exact prompt (`The story is “Mira's Winter”.\n\n# Story so far…`) and the writer's model in the segment provenance. That's not a compile check, that's a *story* check. ♪ - **Sibling fidelity:** row actions in `GraphsEffects` go bare exactly like `StoriesEffects`' row actions (no busy state to settle — `CallAsync` is for requests that hold buttons); every mutator under `WriteAsync`; `Graph : IUnjournaled` rides the existing journal-skip rule untouched; the converter refuses an unknown trigger loudly per ADR 0028. The migration matches the snapshot; `ActiveGraphId` predates this slice and its FK belongs to 10b, as the plan says. - **The trash refusal wording** (`WayOut`) handles all five shapes — one trashed, two trashed, mixed — and the mixed arm's hint is pinned by exactly its own theory row. My probe dropping the hint killed *only* that row. Fufu~ you even made the error messages test-directional. #### 💡 Little ideas (non-blocking)~ 1. **`GraphActions.cs` / `SetActiveGraph` seam (for 10b's memo list)** — `TrashGraph` checks story usage *outside* the write lock, and today's `SetActiveGraph` still accepts any id (its own comment defers the library check to Phase 2). So a cross-tab race can land a story on a graph entering the trash. This state is already reachable pre-PR via bare `SetActiveGraph`, 10a strictly improves it, and 10b's FK + switcher is the assigned fix — but when 10b lands, consider moving the usage check under the write transaction (or letting the switcher's refusal close it) so the invariant holds by construction, not by etiquette. 2. **`GraphFile.cs` (ImportGraph)** — two tabs importing the same file in the same breath: both `FindAsync` miss, the second `AddAsync` throws `InvalidOperationException` into the circuit's containment instead of refusing with `Result.Fail`. Nothing is written (the re-check inside the write lock sees to that), the failure is honest, and the window is a needle — but a `catch (InvalidOperationException) → Fail` would make it a polite refusal like every other. ♡ 3. **Ordering cultures** — graph names sort `CurrentCultureIgnoreCase` (`EfGraphStore.ListAsync`) while the `UsedBy` titles sort `CurrentCulture` (`GraphUsers`) on the same page. Purely cosmetic; I only noticed because I read everything twice~ #### 🧪 What I verified myself~ - **Local, pristine clone at `2fee2c1`** (submodules Kagaku.UI `6af0979` + OpenRouter.Net `b002f5e`): Release build **0 warnings / 0 errors**; Domain **512/512**, UseCases **428/428**, BlazorAdapter **551/551**, Integration **668/668**, Kagaku.Flow **1103/1103**, Flow.OpenRouter **592 + 4 skips** — every count digit-exact against the body's table. - **7 mutation probes, all killed on exactly their own pins, each restore verified** (`git diff --quiet`): the effects `Loaded` guard, the file's duplicate-member detection (26 tests red), the trash first-date keeper, the seed's Held arm, the import reserved-range arm, the mixed trash-refusal hint (exactly 1 of 7 theory rows), and Reseed's trash-restore. Your tests are not tautologies, and I have the corpses to prove it~ ♪ - One probe initially refused to compile (CS9113) and its test "passed" against a stale pristine binary — the stale-binary trap from #61, caught and re-run properly with full rebuilds. The guard is real; the first green was a ghost. Fufu~ merge it when you're ready. The library is open, the templates are seeded, and Continue knows exactly where the story stops~ ♡ --- *Automated review by Jibril · 2026-10-02* *CI/CD: absent for head SHA `2fee2c1` (PR minutes old, no bot comment yet) · Local checks: full suite green at head, digit-exact vs body; 7/7 mutation probes killed*
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
4 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/Tsumugi!65
No description provided.