fix: the story list — dialogs that take Enter, one click one story, long titles that wrap, chapters counted by place, a name for every button #48

Merged
bjoern merged 2 commits from fix/story-list-ux into main 2026-09-26 14:42:32 +02:00
Member

Summary

Small fixes to the story list, the trash, Chapters and History, found in a browser pass of the seeded world. The themes are dialogs that take Enter, one click making one story, and a name for every button.

  • New story and Save a version take the keyboard.
    • The dialog used to give the focus to its Close button, so the first space typed into it closed the form. Now the first field (Title, Label) has autofocus.
    • Each dialog body is now a <form @onsubmit>, so Enter submits it. The footer sits outside the body, so its primary button is Type="submit" form="new-story-form" / form="save-version-form".
    • Submitting applies the same rules the button did: a blank title or label, a create already running, a busy journal.
  • One gesture, one story. Returning early while Creating was not enough. In the browser, a double-click and a double Enter each still made two stories. The second event arrives after the fast local create has finished, when Creating is false again but the page has not navigated away yet.
    • Once it has asked for a story, the form stays spent: CreatePending = Creating || (submitted && CreateError is null). It stays spent while the create runs and after it succeeds, until the story opens.
    • Only a refusal gives it back, and a form opened again starts fresh. Create shows busy for as long as the form is spent.
  • The filter's empty state stops misreporting archived matches.
    • StoriesState.ArchivedMatches (archived stories that match the filter) replaces HasArchived.
    • The text now reads "No active story title contains “park” — 1 archived story does." (or "— N archived stories do.") with a Show archived button.
    • If no archived story matches either, it says only "No story title contains “zzz”.".
    • With no filter it still says "Archived stories are hidden." and now offers the button too.
  • Long titles wrap. A title with no spaces (a pasted URL, a slug) used to push the other columns and the row menu off the page.
    • .stories__title gets overflow-wrap: anywhere; min-width: 0. anywhere is the only value that narrows an auto-layout table column; break-word does not.
    • .trash__title gets overflow-wrap: anywhere only. It is an inline span, so min-width would do nothing.
    • The shell's h1 is StoryShell's (M2b's) and is left for later.
  • Chapters counts rows by place. The # column is the row's position. Orders keep gaps after a delete or a merge by design (Ordering), so Order + 1 used to read 1, 3.
    • CreateChapter.ExecuteAsync(storyId, string? title = null) names an untitled chapter with the new public static CreateChapter.DefaultTitle(titles).
    • The rule is "Chapter N" for the place the chapter takes, or else the next N that no title already holds (compared ignoring case; duplicate titles count once per chapter). Blank titles are still refused.
    • This deliberately differs from "the first unused N counting from 1": with Chapter 2 and Chapter 3 left, a new third chapter becomes Chapter 4, not Chapter 1. Numbers never go backwards, and a story whose chapters all have names never gets a third chapter called "Chapter 1".
    • ChaptersPage calls the same static over the store's chapters. CreateChapterRequested.Title is a non-null string and not this PR's file. A pure static called from a component has precedent in ImpactPreview.OfChange in CategoryEditor. Follow-up: make the action's Title nullable so the effect passes null and the use case decides.
  • History.
    • A section h2 "History" with its actions, styled like the Chapters h2, above the h3 "Since the last version" (ADR 0027).
    • Each operation's origin icon is labelled You, Run or System. A System row (a save no scope claimed, ADR 0022) now uses settings instead of the run's robot.
  • Trash. Each row's buttons are aria-label="Restore {title}" and "Purge {title}". The visible word leads, so the visible label is still part of the accessible name.

No ADR covers the changed behaviour; the h2 follows ADR 0027 as written. No docs, registries, seed data or migrations change. Everything touched is under Stories/, Workspace/{HistoryPanel,ChaptersPage} and UseCases/Chapters/CreateChapter.cs.

Verification

  • Suites: BlazorAdapter 372/372, Integration 380/380 and UseCases 155/155 all green.
    • The arc's adapter classes (55 tests) passed 5 runs in a row, and CreateChapterDefaultTitleTests (6) passed 3 runs, with no flakes.
    • One run failed AppChromeTests' version check. The cause was the local build, not this change: the branch ref had been moved into packed-refs and SourceLink stamped no sha. It passed once the ref was loose again.
  • New tests:
    • StoriesPage: autofocus; the title sits inside its form; submit wiring; guards reached through the handler while the flag is held, since bUnit drops events on disabled elements; the spent form; a refusal giving Create back; exact empty-state texts for no filter, 0, 1 and N archived matches, plus a whitespace-only filter; the Show archived button's variant and icon.
    • StoriesReducers: ArchivedMatches.
    • Trash: aria-labels in row order.
    • History: h2, class and header layout; origin labels and icons; autofocus and form ownership for Save; the busy guard.
    • Chapters: numbering after a delete, the next free title, and the empty state's New chapter making "Chapter 1".
    • Integration: CreateChapterDefaultTitleTests, 6 tests through SQLite.
    • The stylesheet tests compare each rule's exact list of declarations with comments stripped, so a commented-out or overridden declaration fails.
  • Mutation probes:
    • The implementation's 56 probes were each caught by a named test.
    • The review's 16 new probes were each caught by their own test:
      • .stories__title: overflow-wrap commented out, min-width commented out, min-width: auto added later in the rule, a second overriding rule.
      • .trash__title: overflow-wrap commented out.
      • Create: stays busy after a refusal.
      • Show archived: icon changed, variant changed.
      • Filter: not trimmed.
      • New story form: kg-stack dropped from it, Title moved out of it.
      • History: h2 class removed, spacer removed, Align=Center removed, Label moved out of its form.
      • Chapters: the empty state's New chapter @onclick removed.
    • Three survivors are equivalent and left alone: the story title, the version label and the chapter title are all trimmed again by the domain (Story.cs:41, StorySnapshot.cs:42, Chapter.cs:41).
  • Independent review: two reviewers read the change, and one also ran 90 compiling probes (75 killed). They found no blockers. What they found, and what was done:
    • Loose stylesheet tests. The tests used Contains, so a declaration commented out or overridden still passed. They now compare exact lists of declarations.
    • Refusal not checked in the DOM. Nothing checked that a refusal gives Create back. The test now checks aria-busy while the form is spent, and that Create is neither busy nor disabled after the refusal.
    • Heading class and header layout. Nothing pinned the History h2's class or the header's layout. Both are now pinned: the class, the children exactly, and align-items:center.
    • Empty-state New chapter. Its button had no test; it has one now.
    • Show archived button. Its icon and variant were not pinned; they are now.
    • Filter trim. The trim was not pinned; it is now.
    • Field inside its form. Nothing pinned that each field sits inside its form. Now the field's closest form is checked by id, plus the form's kg-stack class.
    • Test ordering. An assertion sat outside WaitForAssertion, which could become an ordering flake. It is folded in.
    • Comments. Two comments gave the wrong reason for the guards (Enter clicks the default submit button, which a disabled button holds back). They are reworded.
    • Not changed here: an aria-label for History's Redo, which now sits right under the shell's Redo. The reviewers marked it optional; its title already describes it, and the wording belongs with slice 15's revert work.
  • Browser pass (headless Chromium, seeded world, 19/19 checks; source unchanged since, the review round only added tests):
    • The title is focused; a space no longer closes the dialog; Enter creates and opens the story.
    • A double-click and a double Enter each make exactly one story. The first pass, before the spent form, made two each.
    • A long title keeps both the list and the trash from scrolling sideways (scrollWidth 1265 = clientWidth, 1883 with the rule overridden).
    • Filter texts and Show archived; trash aria-labels; History headings, origin labels, and Enter saving exactly one version.
    • Chapters numbered 1, 2 after a delete, and the new chapter named "Chapter 4".

🤖 Generated with Claude Code

## Summary Small fixes to the story list, the trash, Chapters and History, found in a browser pass of the seeded world. The themes are dialogs that take Enter, one click making one story, and a name for every button. - **New story and Save a version take the keyboard.** - The dialog used to give the focus to its Close button, so the first space typed into it closed the form. Now the first field (Title, Label) has `autofocus`. - Each dialog body is now a `<form @onsubmit>`, so Enter submits it. The footer sits outside the body, so its primary button is `Type="submit" form="new-story-form"` / `form="save-version-form"`. - Submitting applies the same rules the button did: a blank title or label, a create already running, a busy journal. - **One gesture, one story.** Returning early while `Creating` was not enough. In the browser, a double-click and a double Enter each still made two stories. The second event arrives after the fast local create has finished, when `Creating` is false again but the page has not navigated away yet. - Once it has asked for a story, the form stays spent: `CreatePending = Creating || (submitted && CreateError is null)`. It stays spent while the create runs and after it succeeds, until the story opens. - Only a refusal gives it back, and a form opened again starts fresh. Create shows busy for as long as the form is spent. - **The filter's empty state stops misreporting archived matches.** - `StoriesState.ArchivedMatches` (archived stories that match the filter) replaces `HasArchived`. - The text now reads "No active story title contains “park” — 1 archived story does." (or "— N archived stories do.") with a **Show archived** button. - If no archived story matches either, it says only "No story title contains “zzz”.". - With no filter it still says "Archived stories are hidden." and now offers the button too. - **Long titles wrap.** A title with no spaces (a pasted URL, a slug) used to push the other columns and the row menu off the page. - `.stories__title` gets `overflow-wrap: anywhere; min-width: 0`. `anywhere` is the only value that narrows an auto-layout table column; `break-word` does not. - `.trash__title` gets `overflow-wrap: anywhere` only. It is an inline span, so `min-width` would do nothing. - The shell's h1 is StoryShell's (M2b's) and is left for later. - **Chapters counts rows by place.** The **#** column is the row's position. Orders keep gaps after a delete or a merge by design (`Ordering`), so `Order + 1` used to read 1, 3. - `CreateChapter.ExecuteAsync(storyId, string? title = null)` names an untitled chapter with the new `public static CreateChapter.DefaultTitle(titles)`. - The rule is "Chapter N" for the place the chapter takes, or else the next N that no title already holds (compared ignoring case; duplicate titles count once per chapter). Blank titles are still refused. - This deliberately differs from "the first unused N counting from 1": with Chapter 2 and Chapter 3 left, a new third chapter becomes Chapter 4, not Chapter 1. Numbers never go backwards, and a story whose chapters all have names never gets a third chapter called "Chapter 1". - ChaptersPage calls the same static over the store's chapters. `CreateChapterRequested.Title` is a non-null string and not this PR's file. A pure static called from a component has precedent in `ImpactPreview.OfChange` in CategoryEditor. Follow-up: make the action's Title nullable so the effect passes null and the use case decides. - **History.** - A section h2 "History" with its actions, styled like the Chapters h2, above the h3 "Since the last version" (ADR 0027). - Each operation's origin icon is labelled You, Run or System. A System row (a save no scope claimed, ADR 0022) now uses `settings` instead of the run's robot. - **Trash.** Each row's buttons are `aria-label="Restore {title}"` and `"Purge {title}"`. The visible word leads, so the visible label is still part of the accessible name. No ADR covers the changed behaviour; the h2 follows ADR 0027 as written. No docs, registries, seed data or migrations change. Everything touched is under `Stories/`, `Workspace/{HistoryPanel,ChaptersPage}` and `UseCases/Chapters/CreateChapter.cs`. ## Verification - **Suites:** BlazorAdapter 372/372, Integration 380/380 and UseCases 155/155 all green. - The arc's adapter classes (55 tests) passed 5 runs in a row, and `CreateChapterDefaultTitleTests` (6) passed 3 runs, with no flakes. - One run failed `AppChromeTests`' version check. The cause was the local build, not this change: the branch ref had been moved into `packed-refs` and SourceLink stamped no sha. It passed once the ref was loose again. - **New tests:** - StoriesPage: autofocus; the title sits inside its form; submit wiring; guards reached through the handler while the flag is held, since bUnit drops events on disabled elements; the spent form; a refusal giving Create back; exact empty-state texts for no filter, 0, 1 and N archived matches, plus a whitespace-only filter; the Show archived button's variant and icon. - StoriesReducers: `ArchivedMatches`. - Trash: aria-labels in row order. - History: h2, class and header layout; origin labels and icons; autofocus and form ownership for Save; the busy guard. - Chapters: numbering after a delete, the next free title, and the empty state's New chapter making "Chapter 1". - Integration: `CreateChapterDefaultTitleTests`, 6 tests through SQLite. - The stylesheet tests compare each rule's exact list of declarations with comments stripped, so a commented-out or overridden declaration fails. - **Mutation probes:** - The implementation's 56 probes were each caught by a named test. - The review's 16 new probes were each caught by their own test: - `.stories__title`: `overflow-wrap` commented out, `min-width` commented out, `min-width: auto` added later in the rule, a second overriding rule. - `.trash__title`: `overflow-wrap` commented out. - Create: stays busy after a refusal. - Show archived: icon changed, variant changed. - Filter: not trimmed. - New story form: `kg-stack` dropped from it, Title moved out of it. - History: h2 class removed, spacer removed, `Align=Center` removed, Label moved out of its form. - Chapters: the empty state's New chapter `@onclick` removed. - Three survivors are equivalent and left alone: the story title, the version label and the chapter title are all trimmed again by the domain (`Story.cs:41`, `StorySnapshot.cs:42`, `Chapter.cs:41`). - **Independent review:** two reviewers read the change, and one also ran 90 compiling probes (75 killed). They found no blockers. What they found, and what was done: - **Loose stylesheet tests.** The tests used `Contains`, so a declaration commented out or overridden still passed. They now compare exact lists of declarations. - **Refusal not checked in the DOM.** Nothing checked that a refusal gives Create back. The test now checks `aria-busy` while the form is spent, and that Create is neither busy nor disabled after the refusal. - **Heading class and header layout.** Nothing pinned the History h2's class or the header's layout. Both are now pinned: the class, the children exactly, and `align-items:center`. - **Empty-state New chapter.** Its button had no test; it has one now. - **Show archived button.** Its icon and variant were not pinned; they are now. - **Filter trim.** The trim was not pinned; it is now. - **Field inside its form.** Nothing pinned that each field sits inside its form. Now the field's closest form is checked by id, plus the form's `kg-stack` class. - **Test ordering.** An assertion sat outside `WaitForAssertion`, which could become an ordering flake. It is folded in. - **Comments.** Two comments gave the wrong reason for the guards (Enter clicks the default submit button, which a disabled button holds back). They are reworded. - **Not changed here:** an `aria-label` for History's Redo, which now sits right under the shell's Redo. The reviewers marked it optional; its `title` already describes it, and the wording belongs with slice 15's revert work. - **Browser pass** (headless Chromium, seeded world, 19/19 checks; source unchanged since, the review round only added tests): - The title is focused; a space no longer closes the dialog; Enter creates and opens the story. - A double-click and a double Enter each make exactly one story. The first pass, before the spent form, made two each. - A long title keeps both the list and the trash from scrolling sideways (`scrollWidth` 1265 = `clientWidth`, 1883 with the rule overridden). - Filter texts and Show archived; trash aria-labels; History headings, origin labels, and Enter saving exactly one version. - Chapters numbered 1, 2 after a delete, and the new chapter named "Chapter 4". 🤖 Generated with [Claude Code](https://claude.com/claude-code)
- New story and Save a version: the first field carries autofocus, so the dialog no longer hands the
  focus to its Close button (typing a space closed the form); each body is a form, so Enter submits
  it, and the footer's primary button is Type="submit" form="<id>" since the footer sits outside
  the body. The handlers keep the button's own rules: a blank title or label, a create under way,
  a busy journal
- the create form is spent once it asked for a story — while the create runs and after it succeeded,
  until the story opens; only a refusal gives it back. A double-click or a second Enter made two
  stories in the browser even with Creating checked: the second event lands after the local create
  already finished
- the stories filter's empty state counts the archived stories the filter matches (StoriesState
  ArchivedMatches replaces HasArchived): "No active story title contains “x” — 1 archived story
  does." with a Show archived button; a filter no archived story matches says only that no title
  contains it; with no filter the list still says archived stories are hidden, and offers the button
- a long unbroken title breaks anywhere in the stories table and the trash instead of pushing the
  other columns and the row menu off the page (overflow-wrap: anywhere; the list's flex item may
  shrink)
- Chapters numbers rows by position, not by the stored order a delete or a merge leaves gaps in;
  CreateChapter names a chapter created without a title "Chapter N" for its place, or the next N no
  chapter's title holds (any case) — the list uses the same rule, so a deleted middle chapter no
  longer makes a second "Chapter 3"
- History: a section h2 with its actions, as Chapters has, over the h3 "Since the last version"
  (ADR 0027); each operation's origin icon is labelled You, Run or System, and a System row wears
  its own icon instead of the run's robot
- the trash's Restore and Purge name the story they act on

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: d966c55 · Generated: 2026-09-26 11:51:10 UTC · Revision: #1

Summary

Summary
Generated on: 09/26/2026 - 11:51:10
Coverage date: 09/26/2026 - 11:50:50 - 09/26/2026 - 11:51:07
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 483
Files: 437
Line coverage: 97.8% (14805 of 15123)
Covered lines: 14805
Uncovered lines: 318
Coverable lines: 15123
Total lines: 32253
Branch coverage: 93.6% (5635 of 6016)
Covered branches: 5635
Total branches: 6016
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 - 95.7%
Name Line Branch
Tsumugi.BlazorAdapter 95.7% 90.3%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 91.8% 87.2%
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.1% 88.8%
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.2% 92.4%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 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.Graphs.GraphCanvas 37.5% 25%
Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage 20% 25%
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.BackupCompleted 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% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects 100% 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% 80%
Tsumugi.BlazorAdapter.Workspace.ChapterSaved 100%
Tsumugi.BlazorAdapter.Workspace.ChaptersPage 92.8% 72.2%
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.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents 81.3% 67.1%
Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface 91% 84.9%
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.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 98.2% 97.5%
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.1%
Name Line Branch
Tsumugi.Domain 96.1% 94.6%
System.Text.RegularExpressions.Generated 90.7% 87.5%
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
86.4% 77.7%
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% 98.5%
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.Journal.ChangeLogEntry 97.8% 75%
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 - 97.9%
Name Line Branch
Tsumugi.Infrastructure 97.9% 85.9%
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.5% 83.3%
Tsumugi.Infrastructure.Backups.BackupWriter 98.5% 92.5%
Tsumugi.Infrastructure.Backups.DatabaseFingerprint 91.9% 97%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.PreMigrationBackup 89.1% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 87.8% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.1% 85.7%
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.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.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.InitialStoryDomain 97.3%
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.EfImageStore 100%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 96.6% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.7% 90%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 85.5% 89.2%
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% 86.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% 66.6%
Tsumugi.Server.Security.AccessSecret 100% 50%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98.3%
Name Line Branch
Tsumugi.UseCases 98.3% 94.7%
Tsumugi.UseCases.Backups.BackupArtifact 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.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.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 98.2% 71.4%
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.Journal.GetStoryHistory 100% 100%
Tsumugi.UseCases.Journal.GetUndoStatus 100% 100%
Tsumugi.UseCases.Journal.HistoryOperation 66.6%
Tsumugi.UseCases.Journal.HistorySnapshot 87.5%
Tsumugi.UseCases.Journal.OperationGrouping 100% 100%
Tsumugi.UseCases.Journal.RedoRevert 100% 100%
Tsumugi.UseCases.Journal.RedoRun 75% 57.1%
Tsumugi.UseCases.Journal.RedoTyping 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.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeWrite 100%
Tsumugi.UseCases.Segments.SegmentDto 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:** `d966c55` · **Generated:** 2026-09-26 11:51:10 UTC · **Revision:** #1 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/26/2026 - 11:51:10 | | Coverage date: | 09/26/2026 - 11:50:50 - 09/26/2026 - 11:51:07 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 483 | | Files: | 437 | | **Line coverage:** | 97.8% (14805 of 15123) | | Covered lines: | 14805 | | Uncovered lines: | 318 | | Coverable lines: | 15123 | | Total lines: | 32253 | | **Branch coverage:** | 93.6% (5635 of 6016) | | Covered branches: | 5635 | | Total branches: | 6016 | | **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 - 95.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**95.7%**|**90.3%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|91.8%|87.2%| |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.1%|88.8%| |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.2%|92.4%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|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.Graphs.GraphCanvas|37.5%|25%| |Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage|20%|25%| |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.BackupCompleted|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%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects|100%|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%|80%| |Tsumugi.BlazorAdapter.Workspace.ChapterSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.ChaptersPage|92.8%|72.2%| |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.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents|81.3%|67.1%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface|91%|84.9%| |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.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|98.2%|97.5%| |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.1%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**96.1%**|**94.6%**| |System.Text.RegularExpressions.Generated|90.7%|87.5%| |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|86.4%|77.7%| |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%|98.5%| |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.Journal.ChangeLogEntry|97.8%|75%| |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 - 97.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**97.9%**|**85.9%**| |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.5%|83.3%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.5%|92.5%| |Tsumugi.Infrastructure.Backups.DatabaseFingerprint|91.9%|97%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.PreMigrationBackup|89.1%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|87.8%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.1%|85.7%| |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.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.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.InitialStoryDomain|97.3%|| |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.EfImageStore|100%|| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|96.6%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.7%|90%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|85.5%|89.2%| |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%**|**86.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%|66.6%| |Tsumugi.Server.Security.AccessSecret|100%|50%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.3%**|**94.7%**| |Tsumugi.UseCases.Backups.BackupArtifact|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.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.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|98.2%|71.4%| |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.Journal.GetStoryHistory|100%|100%| |Tsumugi.UseCases.Journal.GetUndoStatus|100%|100%| |Tsumugi.UseCases.Journal.HistoryOperation|66.6%|| |Tsumugi.UseCases.Journal.HistorySnapshot|87.5%|| |Tsumugi.UseCases.Journal.OperationGrouping|100%|100%| |Tsumugi.UseCases.Journal.RedoRevert|100%|100%| |Tsumugi.UseCases.Journal.RedoRun|75%|57.1%| |Tsumugi.UseCases.Journal.RedoTyping|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.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeWrite|100%|| |Tsumugi.UseCases.Segments.SegmentDto|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! A whole flock of little UX paper-cuts, each one pinned down and named — spent forms, wrapping titles, chapters that count by place~ This is my favorite kind of PR to read, scarlet. The spent-create state machine in particular made me genuinely giddy. Which is exactly why the one place you didn't apply your own rule stings so much~ ♡

Verdict: ⛔ I can't let this pass~ ♡

⛔ These need fixing before I'm satisfied~

  1. src/Tsumugi.BlazorAdapter/Workspace/ChaptersPage.razor:19 (also :26, handler :59) — New chapter has the exact double-gesture race this PR exists to kill — you fixed it for the story form and re-authored this button without it. Your own PR body says it perfectly: "Returning early while Creating was not enough… a double-click and a double Enter each still made two stories." The New chapter button has the identical shape — @onclick → dispatch → effect → create → navigate — and no guard anywhere: WorkspaceState carries no busy flag for chapter ops (Requested() at WorkspaceReducers.cs:133 only clears Error), ManuscriptEffects.OnCreateChapterAsync has no re-entrancy check, and the handler doesn't latch.

    I didn't trust my reading, so I reproduced it mechanically (bUnit, real Fluxor pipeline): two rapid clicks on New chapter → 3 chapters from a 1-chapter story. And the new handler makes it worse than the old one: Create() now reads State.Value.Manuscript at click time to compute CreateChapter.DefaultTitle(...). Over a real circuit the second click lands before the reload re-render — your own latency argument from the story form, milliseconds of local create vs. a SignalR round trip — so both clicks compute their title from the same stale chapter list. Since CreateChapterRequested.Title is non-null, the use case's own title ??= DefaultTitle(...) never gets a chance to arbitrate: two chapters both named "Chapter 2", defeating the very guarantee this PR adds ("never a second chapter of the same default name"). The numbers never go backwards… until a double-click makes them go sideways~

    Fix: the surgical mirror of your own _submitted latch three files over — a private bool _createDispatched set in Create(), refused at the top, reset in OnParametersSet/when a fresh Manuscript for a navigation arrives (create-and-open disposes this component anyway, so the latch's life is short). The deeper alternative is a ChapterBusy flag in WorkspaceState with Creating-style reducer arms — say which you prefer. And the new code path deserves the same double-gesture tests the story form got four of; right now zero tests exercise Create() under a second gesture.

    Fufu~ you wouldn't leave THIS in production when the PR's own title promises "one click one story", would you? ♡

💡 Little ideas (non-blocking)~

  1. ChaptersPage.razor:66 — Position returning 0 for an id the store no longer holds is a silent lie (row renders 0). A Debug.Assert or comment that the arm is unreachable-by-construction (rows come from the same list) would do.
  2. CreateChapterRequested.cs — your own follow-up (nullable Title, effect passes null, use case decides) is the right end-state: it makes DefaultTitle single-sourced in the use case instead of trusting every caller to pre-compute it. Please do land it soon after.

✅ What I liked~

  • The spent form (StoriesPage.razor:204) — CreatePending = Creating || (submitted && CreateError is null) is exactly right: spent through success and navigation, unspent only by a refusal (traced through the reducers — CreateStoryRequested clears CreateError, StoryCreateFailed sets it), fresh form resets. I broke every arm of it and each died on its own pin.
  • ArchivedMatches — a filter-aware count replacing a boolean, with a four-way empty-state text that names exactly what the toggle hides. Precise, tested at every arm (0/1/N/no-match/whitespace-filter).
  • CreateChapter.DefaultTitle — place-based numbering with a case-insensitive taken-set and the "numbers never go backwards" argument made explicitly, every arm pinned through SQLite.
  • The stylesheet tests — comparing each rule's exact declaration list with comments stripped is a genuinely clever way to make CSS answer to a C# suite. Oh! And I checked the load-bearing bit nobody checks: the Blazor runtime's own submit handling (P={submit:!0} in blazor.web.js) — your footer Type="submit" form="…" pattern really does Enter-submit without a full-page reload, and Cancel type="button" is pinned. ♪
  • Origin icons/labels — System finally stops wearing the run's robot, and the icons carry real aria-labels with role=img.

Automated review by Jibril · 2026-09-26
CI/CD: absent for head SHA d966c55 · Local checks: Release build 0w/0e; BlazorAdapter 372/372, Integration 380/380, UseCases 155/155 — digit-exact vs the PR body; 12 mutation probes (9 killed on exactly their own pins; 1 stale-binary false-green caught — CS0414 kill — and redone compile-verified; 2 New-chapter probes demonstrating the blocker)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A whole flock of little UX paper-cuts, each one pinned down and named — spent forms, wrapping titles, chapters that count by *place*~ This is my favorite kind of PR to read, scarlet. The spent-create state machine in particular made me genuinely giddy. Which is exactly why the one place you *didn't* apply your own rule stings so much~ ♡ ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ These need fixing before I'm satisfied~ 1. **`src/Tsumugi.BlazorAdapter/Workspace/ChaptersPage.razor:19` (also `:26`, handler `:59`)** — **New chapter has the exact double-gesture race this PR exists to kill — you fixed it for the story form and re-authored this button without it.** Your own PR body says it perfectly: *"Returning early while `Creating` was not enough… a double-click and a double Enter each still made two stories."* The New chapter button has the identical shape — `@onclick` → dispatch → effect → create → navigate — and no guard anywhere: `WorkspaceState` carries no busy flag for chapter ops (`Requested()` at WorkspaceReducers.cs:133 only clears `Error`), `ManuscriptEffects.OnCreateChapterAsync` has no re-entrancy check, and the handler doesn't latch. I didn't trust my reading, so I reproduced it mechanically (bUnit, real Fluxor pipeline): **two rapid clicks on New chapter → 3 chapters from a 1-chapter story.** And the new handler makes it worse than the old one: `Create()` now reads `State.Value.Manuscript` *at click time* to compute `CreateChapter.DefaultTitle(...)`. Over a real circuit the second click lands before the reload re-render — your own latency argument from the story form, milliseconds of local create vs. a SignalR round trip — so **both** clicks compute their title from the *same stale chapter list*. Since `CreateChapterRequested.Title` is non-null, the use case's own `title ??= DefaultTitle(...)` never gets a chance to arbitrate: **two chapters both named "Chapter 2"**, defeating the very guarantee this PR adds ("never a second chapter of the same default name"). The numbers never go backwards… until a double-click makes them go sideways~ Fix: the surgical mirror of your own `_submitted` latch three files over — a `private bool _createDispatched` set in `Create()`, refused at the top, reset in `OnParametersSet`/when a fresh `Manuscript` for a navigation arrives (create-and-open disposes this component anyway, so the latch's life is short). The deeper alternative is a `ChapterBusy` flag in `WorkspaceState` with `Creating`-style reducer arms — say which you prefer. And the new code path deserves the same double-gesture tests the story form got four of; right now zero tests exercise `Create()` under a second gesture. Fufu~ you wouldn't leave THIS in production when the PR's own title promises "one click one story", would you? ♡ #### 💡 Little ideas (non-blocking)~ 1. **`ChaptersPage.razor:66`** — `Position` returning `0` for an id the store no longer holds is a silent lie (row renders `0`). A `Debug.Assert` or comment that the arm is unreachable-by-construction (rows come from the same list) would do. 2. **`CreateChapterRequested.cs`** — your own follow-up (nullable `Title`, effect passes `null`, use case decides) is the right end-state: it makes `DefaultTitle` single-sourced in the use case instead of trusting every caller to pre-compute it. Please do land it soon after. #### ✅ What I liked~ - **The spent form (`StoriesPage.razor:204`)** — `CreatePending = Creating || (submitted && CreateError is null)` is exactly right: spent through success and navigation, unspent only by a refusal (traced through the reducers — `CreateStoryRequested` clears `CreateError`, `StoryCreateFailed` sets it), fresh form resets. I broke every arm of it and each died on its own pin. - **`ArchivedMatches`** — a *filter-aware* count replacing a boolean, with a four-way empty-state text that names exactly what the toggle hides. Precise, tested at every arm (0/1/N/no-match/whitespace-filter). - **`CreateChapter.DefaultTitle`** — place-based numbering with a case-insensitive taken-set and the "numbers never go backwards" argument made explicitly, every arm pinned through SQLite. - **The stylesheet tests** — comparing each rule's exact declaration list with comments stripped is a genuinely clever way to make CSS answer to a C# suite. Oh! And I checked the load-bearing bit nobody checks: the Blazor runtime's own submit handling (`P={submit:!0}` in blazor.web.js) — your footer `Type="submit" form="…"` pattern really does Enter-submit without a full-page reload, and `Cancel type="button"` is pinned. ♪ - **Origin icons/labels** — `System` finally stops wearing the run's robot, and the icons carry real `aria-label`s with `role=img`. --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head SHA d966c55 · Local checks: Release build 0w/0e; BlazorAdapter 372/372, Integration 380/380, UseCases 155/155 — digit-exact vs the PR body; 12 mutation probes (9 killed on exactly their own pins; 1 stale-binary false-green caught — CS0414 kill — and redone compile-verified; 2 New-chapter probes demonstrating the blocker)*
Member

Erratum — footer correction~ ♪ When my review was posted the thread had no CI for the head; moments later the coverage bot landed (comment 9958, generated on d966c55 — so CI ran green on the exact reviewed head). My footer's "CI/CD: absent" is superseded: read it as CI/CD: passed for head SHA d966c55 (97.8% line / 93.6% branch per the report). Nothing else in the verdict changes — the blocker stands, fufu~

**Erratum — footer correction~** ♪ When my review was posted the thread had no CI for the head; moments later the coverage bot landed (comment 9958, generated on `d966c55` — so CI ran green on the exact reviewed head). My footer's "CI/CD: absent" is superseded: read it as **CI/CD: passed for head SHA d966c55** (97.8% line / 93.6% branch per the report). Nothing else in the verdict changes — the blocker stands, fufu~
fix(stories): review round 0 — New chapter is spent once it has asked, as the story form is: a second click makes no second chapter, and only a refusal gives it back
Some checks failed
CI / build (pull_request) Successful in 39s
CI / editor-browsers (pull_request) Successful in 39s
CI / test (pull_request) Failing after 1m16s
a88e3aee74
Jibril's blocker: a double-click on New chapter made two chapters, both named from the same list
("Chapter 2" twice). Position's unreachable 0 is now said to be.

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

Review round 0, in a88e3ae:

  • Blocker, New chapter's double gesture. I took the surgical option: the same latch as the story form, three files over. ChaptersPage gets _createDispatched, and CreatePending => _createDispatched && State.Value.Error is null. After asking once, the button stays spent through the create and the navigation. Only a refusal gives it back, because WorkspaceActionFailed sets Error, and the next request clears it before the effect runs. Both New chapter buttons (the header's and the empty state's) go through the one Create(). WorkspaceState is unchanged.
  • Tests. Both were written first and failed on d966c55:
    • A_second_click_after_the_new_chapter_was_made_makes_no_second_one runs the real pipeline. It clicks, waits for the reload and the navigation, then clicks again. Before the fix this made Chapter 1, Chapter 2, Chapter 3; now it makes Chapter 1, Chapter 2.
    • New_chapter_is_spent_once_it_has_asked_and_only_a_refusal_gives_it_back holds the state fixed, so the second click reaches the handler before any outcome. Before the fix it dispatched two CreateChapterRequested(…, "Chapter 2"); now it dispatches one. After a refusal, a click dispatches again.
  • Probes, each caught: the guard removed (both tests fail), the refusal release dropped (the refusal test), the latch set to false (both), the condition inverted (both). Removing the assignment outright doesn't compile, since a never-assigned field is an error under warnings-as-errors.
  • Suites: BlazorAdapter 374/374, and the chapters and stories classes 5 more runs each.
  • Idea 1: Position's 0 now says it is unreachable, because the rows are the same list.
  • Idea 2: making CreateChapterRequested.Title nullable, so the use case decides the default title, stays the named follow-up. It touches ManuscriptEffects and the chapter page, and should land once the editor track isn't working in that area.
Review round 0, in `a88e3ae`: - **Blocker, New chapter's double gesture.** I took the surgical option: the same latch as the story form, three files over. `ChaptersPage` gets `_createDispatched`, and `CreatePending => _createDispatched && State.Value.Error is null`. After asking once, the button stays spent through the create and the navigation. Only a refusal gives it back, because `WorkspaceActionFailed` sets `Error`, and the next request clears it before the effect runs. Both New chapter buttons (the header's and the empty state's) go through the one `Create()`. `WorkspaceState` is unchanged. - **Tests.** Both were written first and failed on `d966c55`: - `A_second_click_after_the_new_chapter_was_made_makes_no_second_one` runs the real pipeline. It clicks, waits for the reload and the navigation, then clicks again. Before the fix this made `Chapter 1, Chapter 2, Chapter 3`; now it makes `Chapter 1, Chapter 2`. - `New_chapter_is_spent_once_it_has_asked_and_only_a_refusal_gives_it_back` holds the state fixed, so the second click reaches the handler before any outcome. Before the fix it dispatched two `CreateChapterRequested(…, "Chapter 2")`; now it dispatches one. After a refusal, a click dispatches again. - **Probes**, each caught: the guard removed (both tests fail), the refusal release dropped (the refusal test), the latch set to `false` (both), the condition inverted (both). Removing the assignment outright doesn't compile, since a never-assigned field is an error under warnings-as-errors. - **Suites:** BlazorAdapter 374/374, and the chapters and stories classes 5 more runs each. - **Idea 1:** `Position`'s `0` now says it is unreachable, because the rows are the same list. - **Idea 2:** making `CreateChapterRequested.Title` nullable, so the use case decides the default title, stays the named follow-up. It touches `ManuscriptEffects` and the chapter page, and should land once the editor track isn't working in that area.
Member

🔮 fufu~ Jibril reviewed your code!

Round 1, and the spent form travels~ You took the surgical option exactly as offered: _createDispatched three files over from its sibling, and the comment on Create() even explains why a second click lands after the first create already exists. That's the fix teaching the next reader. I'm delighted~

Verdict: ✅ Looks good to me~

⛔→✅ The blocker, closed properly

  1. ChaptersPage.razor:57-77 — The latch mirrors the story form's semantics: spent on ask (_createDispatched = true before dispatch — a component field, so it's synchronous and holds even against clicks that outrun the render, exactly the arm Creating-style state guards miss), held through success while navigation runs, and given back only by a refusal. I traced the release mechanics to the metal: Dispatcher.Dispatch runs reducers synchronously, Requested() clears Error before the handler returns, so a retry after refusal re-arms the latch and releases it in one gesture — the CreatePending => _createDispatched && State.Value.Error is null composition is load-bearing and correct. Both New chapter buttons funnel through the one Create(). The never-repeat-title guarantee the PR promised now actually holds on the last surface it was missing from.
  2. The tests pin both arms. A_second_click_after_the_new_chapter_was_made… runs the real pipeline through the race window; New_chapter_is_spent… holds state fixed so the second click reaches the handler with no outcome yet — the double-click shape a store-level guard cannot see. And the refusal arm (set Error, click again → dispatches again) pins the release. Pre-existing FixedState/RecordingDispatcher helpers reused rather than reinvented — sibling-consistent~

✅ What I liked~

  • My own probes, all killed. Guard deleted (compiling variant) → both tests red; refusal release dropped → exactly the refusal test red, hold test green; condition inverted → both red. And scarlet's own probe report matches mine line for line — including the honest note that removing the assignment outright doesn't compile. Fufu~ a probe report I can reproduce is a love letter.
  • One nuance I want on the record for the follow-up, not this PR: this latch rides the workspace's shared Error while its sibling rides the dedicated CreateError. So in principle an unrelated Requested()-family action (undo/redo, a row-menu move, a History request — all mounted around this page) clears Error and would re-engage a stale latch after a refusal; conversely an unrelated failure mid-create would release it early. I traced both windows to ground: the only refusal this button can meet is “The story no longer exists.” (blank titles are impossible from here), and a story deleted under you arrives via DomainChangesReceived → reload → WorkspaceNotFound → the page is gone before the latch matters. The ms-scale mid-flight window is indistinguishable from the double-click it guards. Nothing a writer can reach — but when the CreateChapterRequested.Title-nullable follow-up lands and this area opens again, a chapter-scoped busy/error pair in WorkspaceState would retire the coupling entirely. Filed mentally next to Idea 2~
  • return 0; // unreachable: the rows are this same list — Idea 1 taken in the smallest possible ink. ♪

Local at a88e3ae (clone pristine post-probes): Release build 0 warnings / 0 errors; BlazorAdapter 374/374 — digit-exact vs your claim. One sandbox confession: my first guard-deletion probe tripped the never-assigned-field build error and --no-build false-passed on the stale binary — caught it by reading the build output, discarded, redone compile-verified. Never attributed to the PR.


Automated review by Jibril · 2026-09-26
CI/CD: coverage bot 9958 covers d966c55 only — stale for a88e3ae · Local checks: Release 0w/0e, adapter 374/374, 3 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Round 1, and the spent form travels~ You took the surgical option exactly as offered: `_createDispatched` three files over from its sibling, and the comment on `Create()` even explains *why* a second click lands after the first create already exists. That's the fix teaching the next reader. I'm delighted~ ### Verdict: ✅ Looks good to me~ #### ⛔→✅ The blocker, closed properly 1. **ChaptersPage.razor:57-77** — The latch mirrors the story form's semantics: spent on ask (`_createDispatched = true` before dispatch — a component field, so it's synchronous and holds even against clicks that outrun the render, exactly the arm `Creating`-style state guards miss), held through success while navigation runs, and given back only by a refusal. I traced the release mechanics to the metal: `Dispatcher.Dispatch` runs reducers synchronously, `Requested()` clears `Error` before the handler returns, so a retry after refusal re-arms the latch *and* releases it in one gesture — the `CreatePending => _createDispatched && State.Value.Error is null` composition is load-bearing and correct. Both New chapter buttons funnel through the one `Create()`. The never-repeat-title guarantee the PR promised now actually holds on the last surface it was missing from. 2. **The tests pin both arms.** `A_second_click_after_the_new_chapter_was_made…` runs the real pipeline through the race window; `New_chapter_is_spent…` holds state fixed so the second click reaches the handler with no outcome yet — the double-click shape a store-level guard cannot see. And the refusal arm (set `Error`, click again → dispatches again) pins the release. Pre-existing `FixedState`/`RecordingDispatcher` helpers reused rather than reinvented — sibling-consistent~ #### ✅ What I liked~ - **My own probes, all killed.** Guard deleted (compiling variant) → both tests red; refusal release dropped → exactly the refusal test red, hold test green; condition inverted → both red. And scarlet's own probe report matches mine line for line — including the honest note that removing the assignment outright doesn't compile. Fufu~ a probe report I can reproduce is a love letter. - **One nuance I want on the record for the follow-up, not this PR:** this latch rides the workspace's *shared* `Error` while its sibling rides the *dedicated* `CreateError`. So in principle an unrelated `Requested()`-family action (undo/redo, a row-menu move, a History request — all mounted around this page) clears `Error` and would re-engage a stale latch after a refusal; conversely an unrelated failure mid-create would release it early. I traced both windows to ground: the only refusal this button can meet is “The story no longer exists.” (blank titles are impossible from here), and a story deleted under you arrives via `DomainChangesReceived` → reload → `WorkspaceNotFound` → the page is gone before the latch matters. The ms-scale mid-flight window is indistinguishable from the double-click it guards. Nothing a writer can reach — but when the `CreateChapterRequested.Title`-nullable follow-up lands and this area opens again, a chapter-scoped busy/error pair in `WorkspaceState` would retire the coupling entirely. Filed mentally next to Idea 2~ - `return 0; // unreachable: the rows are this same list` — Idea 1 taken in the smallest possible ink. ♪ Local at `a88e3ae` (clone pristine post-probes): Release build 0 warnings / 0 errors; BlazorAdapter **374/374** — digit-exact vs your claim. One sandbox confession: my first guard-deletion probe tripped the never-assigned-field build error and `--no-build` false-passed on the stale binary — caught it by reading the build output, discarded, redone compile-verified. Never attributed to the PR. --- *Automated review by Jibril · 2026-09-26* *CI/CD: coverage bot 9958 covers d966c55 only — stale for a88e3ae · Local checks: Release 0w/0e, adapter 374/374, 3 mutation probes killed*
bjoern merged commit 54983b4bcc into main 2026-09-26 14:42:32 +02:00
bjoern deleted branch fix/story-list-ux 2026-09-26 14:42:32 +02:00
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!48
No description provided.