fix: the undo floor — Ctrl+Z stops at a story's creation, a version turns Undo off on every open page, an unchanged save journals nothing #44

Merged
bjoern merged 2 commits from fix/journal-undo-floor into main 2026-09-26 13:41:27 +02:00
Member

Summary

Three undo gaps from the journal review. A fourth item was tried and left out; see below.

  • Ctrl+Z stops at a story's creation. On a story with no snapshot, Ctrl+Z walked back through every edit and then undid CreateStory's own operation. The Story row was deleted outright, its chapters and categories by cascade, past the trash and its confirmation, onto a Story not found page with no Redo. Its journal rows and pictures were orphaned, and PurgeStory refused them. Now UndoTyping never targets an operation that holds the Story's Create row, and GetUndoStatus follows: Undo is off on a fresh story, and a story walks back to its creation and stops there. RedoTyping's doc notes the creation is never a candidate.
  • A saved version turns Undo off on every open page. A snapshot moves Ctrl+Z's floor, but nothing re-read the head's undo state. After Save a version, Undo stayed on with a stale tooltip and a click did nothing. HistoryEffects now takes GetUndoStatus:
    • after a successful save it dispatches UndoStatusChanged;
    • on any StorySnapshot doorbell while a story is open (manuscript loaded, whether or not History is), it re-reads the open story's state. The doorbell carries the snapshot's id, not the story's.
  • A save that changes nothing journals nothing. Story.Rename, Describe, Archive, Unarchive and SetActiveGraph stamp UpdatedAt only on a real change. A trailing space, a letter typed and taken back within the pause, or a second archive from another tab leaves the row unchanged: no journal row, no History entry, no Ctrl+Z step. UpdateStory, SetStoryArchived and SetActiveGraph return the same StoryDetail, so StoryDetails' echo (keyed on UpdatedAt) behaves as before.
  • Not in this PR: Ctrl+Y after Revert to here on an older snapshot. Two rules were tried: the brief's (newest active row over the whole journal) and a narrower one (a writer's row undone beneath the floor). Both also refuse the ordinary round trip after a version saved over an undone edit: Ctrl+Z, Save a version, edit, Ctrl+Z, Ctrl+Y. The journal cannot tell a row a revert undid from one the writer undid before saving the version. Ctrl+Y keeps main's window above the newest snapshot, and a new test pins the round trip. The fix waits for a ChangeLog column that records which revert undid a row (follow-ups).

Docs: ADR 0022 is amended (Status line; the Ctrl+Z bullet now says the creation is a floor). ADR 0029 is amended in four places:

  • its Status line;
  • the Kept for the story's lifetime bullet: no foreign key because only a purge deletes a story's row, and the purge removes the pictures in its own transaction;
  • the Later sweep item;
  • the rejected foreign-key alternative.

The StoryImageConfiguration comment says the same. No migration, no new content kind, so no seed change.

Follow-ups, not in this PR:

  • Ctrl+Y after Revert to here on an older snapshot. It re-applies the edits above the newest snapshot onto a story that lacks the operations between the two snapshots. The redo branch coming back after undoing a new edit is the same gap. Both need a ChangeLog column recording which revert undid a row, so a migration.
  • A replayed update over a missing entity. EfUndoStore marks the row active even when its entity is missing. So after a Revert to here across a run whose paragraph the writer then edited, Ctrl+Y re-applies that edit to nothing, and History's Redo then answers Nothing to redo. This is pre-existing.
  • Unbounded journal loads. UndoTyping, RedoTyping and RedoRevert read the story's whole journal when it has no snapshot.
  • Undoing a restore from the trash. Undoing restored the story from the trash moves it back to the trash without the confirmation. It stays recoverable there.
  • Docs. docs/stories/story-workspace.md and docs/REQUIREMENTS.md could say that Ctrl+Z stops at a story's creation.

Verification

  • Suites. dotnet test on the branch rebased onto main 3b892bd (M2b and slice 8c in): Domain 470, UseCases 155, Integration 377, BlazorAdapter 358, all green, 0 build warnings. The touched classes ran 5 more times: Integration HistoryAndRevert, ImageField, AppSettings, StoryUseCase, FieldJournal and Journal (68 tests); adapter HistoryEffects, HistoryPage, HistoryPanel, StoryGeneralPage and ChapterPage (56); Domain StoryTests (9). The full adapter suite ran 8 more times.

  • Flake note, not this change's. M2b's ChapterPageTests.Changes_made_elsewhere_reach_the_module_as_deltas_of_what_differs_and_its_own_writes_never_do failed 2 of those 5 runs on a 15 s WaitForAssertion timeout while the machine was under load. It then passed 10/10 alone, 6/6 with the touched classes and 8/8 in the full adapter suite. It publishes only Segment doorbells, for which HistoryEffects dispatches nothing, as on main. It advances its clock with Clock.Advance, not AdvanceAsync.

  • New and rewritten tests:

    • HistoryAndRevertTests.Ctrl_Z_walks_a_new_story_back_to_its_creation_and_stops_there: Undo is off on a fresh story; after edits the story walks back and stops, still listed and whole; redo brings the edits back.
    • HistoryAndRevertTests.A_version_saved_over_an_undone_edit_leaves_Ctrl_Y_the_edits_made_after_it: the round trip.
    • ImageFieldTests.Ctrl_Z_walks_a_new_story_back_to_its_creation_and_its_pictures_stay_for_the_redo and AppSettingsTests.Undo_reaches_past_a_settings_change_to_the_writers_last_content_change: both rewritten; they used to undo a creation.
    • StoryTests.A_mutator_handed_what_the_story_holds_stamps_nothing, plus UpdatedAt asserts on the archive and graph tests.
    • StoryUseCaseTests.A_save_that_changes_nothing_journals_nothing_and_leaves_no_undo_step.
    • HistoryEffectsTests.A_snapshot_taken_anywhere_re_reads_the_open_storys_undo_state_on_any_page, and the save-a-version test now asserts the re-read.
    • HistoryPageTests: the head's Undo, pinned by DOM (disabled, title Nothing to undo (Ctrl+Z)), after a version saved on the page and after one saved in another tab while the General page is open.
  • Mutation probes, each caught by its own test:

    • Creation floor:
      • predicate never true: caught by the four creation tests above;
      • Operation == Create dropped: HistoryAndRevert, AppSettings and StoryUseCase;
      • EntityKind == Story dropped: HistoryAndRevert and ImageField;
      • undone rows returned too: FieldJournalTests.A_forced_run_revert_…;
      • only the newest row checked: HistoryAndRevert and three others.
    • Ctrl+Y:
      • the beneath-the-floor rule put back: the round-trip test;
      • the brief's rule put back: the round-trip test and FieldJournalTests.Once_Ctrl_Z_has_made_the_field_change_whole_….
    • HistoryEffects:
      • no re-read after a version: HistoryEffectsTests and HistoryPageTests.Saving_a_version_… (DOM);
      • wrong story id on the action: the same two;
      • a refused version re-reading: HistoryEffectsTests (action count);
      • doorbell without the manuscript-open condition, without the StorySnapshot condition, with History-loaded instead of manuscript-open, matched on the story id, or with the wrong id: A_snapshot_taken_anywhere_… and A_version_saved_in_another_tab_….
    • Story: each of the five guards defeated, Rename comparing the untrimmed title, Describe comparing the raw input, and Rename stamping with its guard kept. Each is caught by the domain test and the use-case test.
    • Two survivors are equivalent: the status read after a version for another story id. Right after a snapshot the status is always empty, so only a concurrent write between the snapshot and the re-read could tell them apart.
  • Independent review (two reviewers, 37 probes) found:

    • Blocker: the Ctrl+Y beneath-the-floor rule refused the plain Ctrl+Z, Save a version, edit, Ctrl+Z, Ctrl+Y round trip. That was a regression against main. Fixed by dropping the rule, restoring main's RedoTyping window and pinning the round trip.
    • Now moot: the unpinned StoryId filter in the new MAX query (major), the unpinned System-origin rule (minor), the run exception letting a content replay through (minor) and the ADR wording (nit). They went with the rule and IChangeJournal.LatestActivePositionAsync; the replay is listed as a follow-up.
    • Minor: HistoryPageTests drove the History panel's Save a version dialog, which the story-list PR in this batch turns into a form submit. The test now dispatches SaveVersionRequested (HistoryPanelTests drive the dialog) and still pins the head by DOM.
    • Minor: AppSettingsTests.The_provider_view_asks_nobody failed once in about 35 runs. The likely cause is environmental: SqliteBackedTest keeps its databases under Path.GetTempPath(), and the shared /tmp quota ran full on this machine during the session. It did not recur in 7 runs here with TMPDIR off the tmpfs.
  • Browser pass: the implementer's, before the rebase; headless Chromium, seeded world. It confirmed:

    • on a new story, Undo is disabled and Ctrl+Z leaves the story in place;
    • after a description edit Undo is on, and after Save a version it is off;
    • a trailing space typed in the title leaves Undo off, with no journal row;
    • when tab A saves a version, tab B's Undo turns off.

    It was not repeated after the rebase, which touched none of these files. HistoryPageTests pins the head by DOM on the rebased code.

🤖 Generated with Claude Code

## Summary Three undo gaps from the journal review. A fourth item was tried and left out; see below. - **Ctrl+Z stops at a story's creation.** On a story with no snapshot, Ctrl+Z walked back through every edit and then undid `CreateStory`'s own operation. The Story row was deleted outright, its chapters and categories by cascade, past the trash and its confirmation, onto a *Story not found* page with no Redo. Its journal rows and pictures were orphaned, and `PurgeStory` refused them. Now `UndoTyping` never targets an operation that holds the Story's Create row, and `GetUndoStatus` follows: Undo is off on a fresh story, and a story walks back to its creation and stops there. `RedoTyping`'s doc notes the creation is never a candidate. - **A saved version turns Undo off on every open page.** A snapshot moves Ctrl+Z's floor, but nothing re-read the head's undo state. After *Save a version*, Undo stayed on with a stale tooltip and a click did nothing. `HistoryEffects` now takes `GetUndoStatus`: - after a successful save it dispatches `UndoStatusChanged`; - on any `StorySnapshot` doorbell while a story is open (manuscript loaded, whether or not History is), it re-reads the open story's state. The doorbell carries the snapshot's id, not the story's. - **A save that changes nothing journals nothing.** `Story.Rename`, `Describe`, `Archive`, `Unarchive` and `SetActiveGraph` stamp `UpdatedAt` only on a real change. A trailing space, a letter typed and taken back within the pause, or a second archive from another tab leaves the row unchanged: no journal row, no History entry, no Ctrl+Z step. `UpdateStory`, `SetStoryArchived` and `SetActiveGraph` return the same `StoryDetail`, so `StoryDetails`' echo (keyed on `UpdatedAt`) behaves as before. - **Not in this PR: Ctrl+Y after *Revert to here* on an older snapshot.** Two rules were tried: the brief's (newest active row over the whole journal) and a narrower one (a writer's row undone beneath the floor). Both also refuse the ordinary round trip after a version saved over an undone edit: Ctrl+Z, *Save a version*, edit, Ctrl+Z, Ctrl+Y. The journal cannot tell a row a revert undid from one the writer undid before saving the version. Ctrl+Y keeps main's window above the newest snapshot, and a new test pins the round trip. The fix waits for a `ChangeLog` column that records which revert undid a row (follow-ups). Docs: ADR 0022 is amended (Status line; the Ctrl+Z bullet now says the creation is a floor). ADR 0029 is amended in four places: - its Status line; - the *Kept for the story's lifetime* bullet: no foreign key because only a purge deletes a story's row, and the purge removes the pictures in its own transaction; - the *Later* sweep item; - the rejected foreign-key alternative. The `StoryImageConfiguration` comment says the same. No migration, no new content kind, so no seed change. Follow-ups, not in this PR: - **Ctrl+Y after *Revert to here* on an older snapshot.** It re-applies the edits above the newest snapshot onto a story that lacks the operations between the two snapshots. The redo branch coming back after undoing a new edit is the same gap. Both need a `ChangeLog` column recording which revert undid a row, so a migration. - **A replayed update over a missing entity.** `EfUndoStore` marks the row active even when its entity is missing. So after a *Revert to here* across a run whose paragraph the writer then edited, Ctrl+Y re-applies that edit to nothing, and History's Redo then answers *Nothing to redo*. This is pre-existing. - **Unbounded journal loads.** `UndoTyping`, `RedoTyping` and `RedoRevert` read the story's whole journal when it has no snapshot. - **Undoing a restore from the trash.** Undoing *restored the story from the trash* moves it back to the trash without the confirmation. It stays recoverable there. - **Docs.** `docs/stories/story-workspace.md` and `docs/REQUIREMENTS.md` could say that Ctrl+Z stops at a story's creation. ## Verification - **Suites.** `dotnet test` on the branch rebased onto main `3b892bd` (M2b and slice 8c in): Domain 470, UseCases 155, Integration 377, BlazorAdapter 358, all green, 0 build warnings. The touched classes ran 5 more times: Integration HistoryAndRevert, ImageField, AppSettings, StoryUseCase, FieldJournal and Journal (68 tests); adapter HistoryEffects, HistoryPage, HistoryPanel, StoryGeneralPage and ChapterPage (56); Domain StoryTests (9). The full adapter suite ran 8 more times. - **Flake note, not this change's.** M2b's `ChapterPageTests.Changes_made_elsewhere_reach_the_module_as_deltas_of_what_differs_and_its_own_writes_never_do` failed 2 of those 5 runs on a 15 s `WaitForAssertion` timeout while the machine was under load. It then passed 10/10 alone, 6/6 with the touched classes and 8/8 in the full adapter suite. It publishes only Segment doorbells, for which `HistoryEffects` dispatches nothing, as on main. It advances its clock with `Clock.Advance`, not `AdvanceAsync`. - **New and rewritten tests:** - `HistoryAndRevertTests.Ctrl_Z_walks_a_new_story_back_to_its_creation_and_stops_there`: Undo is off on a fresh story; after edits the story walks back and stops, still listed and whole; redo brings the edits back. - `HistoryAndRevertTests.A_version_saved_over_an_undone_edit_leaves_Ctrl_Y_the_edits_made_after_it`: the round trip. - `ImageFieldTests.Ctrl_Z_walks_a_new_story_back_to_its_creation_and_its_pictures_stay_for_the_redo` and `AppSettingsTests.Undo_reaches_past_a_settings_change_to_the_writers_last_content_change`: both rewritten; they used to undo a creation. - `StoryTests.A_mutator_handed_what_the_story_holds_stamps_nothing`, plus `UpdatedAt` asserts on the archive and graph tests. - `StoryUseCaseTests.A_save_that_changes_nothing_journals_nothing_and_leaves_no_undo_step`. - `HistoryEffectsTests.A_snapshot_taken_anywhere_re_reads_the_open_storys_undo_state_on_any_page`, and the save-a-version test now asserts the re-read. - `HistoryPageTests`: the head's Undo, pinned by DOM (disabled, title *Nothing to undo (Ctrl+Z)*), after a version saved on the page and after one saved in another tab while the General page is open. - **Mutation probes, each caught by its own test:** - Creation floor: - predicate never true: caught by the four creation tests above; - `Operation == Create` dropped: HistoryAndRevert, AppSettings and StoryUseCase; - `EntityKind == Story` dropped: HistoryAndRevert and ImageField; - undone rows returned too: `FieldJournalTests.A_forced_run_revert_…`; - only the newest row checked: HistoryAndRevert and three others. - Ctrl+Y: - the beneath-the-floor rule put back: the round-trip test; - the brief's rule put back: the round-trip test and `FieldJournalTests.Once_Ctrl_Z_has_made_the_field_change_whole_…`. - `HistoryEffects`: - no re-read after a version: `HistoryEffectsTests` and `HistoryPageTests.Saving_a_version_…` (DOM); - wrong story id on the action: the same two; - a refused version re-reading: `HistoryEffectsTests` (action count); - doorbell without the manuscript-open condition, without the `StorySnapshot` condition, with History-loaded instead of manuscript-open, matched on the story id, or with the wrong id: `A_snapshot_taken_anywhere_…` and `A_version_saved_in_another_tab_…`. - `Story`: each of the five guards defeated, `Rename` comparing the untrimmed title, `Describe` comparing the raw input, and `Rename` stamping with its guard kept. Each is caught by the domain test and the use-case test. - Two survivors are equivalent: the status read after a version for another story id. Right after a snapshot the status is always empty, so only a concurrent write between the snapshot and the re-read could tell them apart. - **Independent review (two reviewers, 37 probes)** found: - **Blocker:** the Ctrl+Y beneath-the-floor rule refused the plain Ctrl+Z, *Save a version*, edit, Ctrl+Z, Ctrl+Y round trip. That was a regression against main. Fixed by dropping the rule, restoring main's `RedoTyping` window and pinning the round trip. - **Now moot:** the unpinned `StoryId` filter in the new MAX query (major), the unpinned System-origin rule (minor), the run exception letting a content replay through (minor) and the ADR wording (nit). They went with the rule and `IChangeJournal.LatestActivePositionAsync`; the replay is listed as a follow-up. - **Minor:** `HistoryPageTests` drove the History panel's *Save a version* dialog, which the story-list PR in this batch turns into a form submit. The test now dispatches `SaveVersionRequested` (HistoryPanelTests drive the dialog) and still pins the head by DOM. - **Minor:** `AppSettingsTests.The_provider_view_asks_nobody` failed once in about 35 runs. The likely cause is environmental: `SqliteBackedTest` keeps its databases under `Path.GetTempPath()`, and the shared `/tmp` quota ran full on this machine during the session. It did not recur in 7 runs here with `TMPDIR` off the tmpfs. - **Browser pass:** the implementer's, before the rebase; headless Chromium, seeded world. It confirmed: - on a new story, Undo is disabled and Ctrl+Z leaves the story in place; - after a description edit Undo is on, and after *Save a version* it is off; - a trailing space typed in the title leaves Undo off, with no journal row; - when tab A saves a version, tab B's Undo turns off. It was not repeated after the rebase, which touched none of these files. `HistoryPageTests` pins the head by DOM on the rebased code. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(journal): the undo floor — a story's creation stops Ctrl+Z, a version turns Undo off on every open page, and a save that changes nothing journals nothing
Some checks failed
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
97ae75b116
Ctrl+Z on a story with no snapshot walked back through every edit and then
undid the story's own creation: the Story row went, its chapters and
categories by cascade, past the trash and its confirmation, onto a "Story not
found" page with no Redo. The creation is now Ctrl+Z's floor, as a snapshot
is: UndoTyping never targets an operation holding the Story's Create row, and
GetUndoStatus follows, so Undo is off on a fresh story. ADR 0022 is amended,
and ADR 0029, whose no-foreign-key rationale and Later sweep rested on that
undo: StoryImages.storyId keeps no key because only the purge deletes a
story's row and it removes the pictures in its own transaction, and an
earlier build may have left pictures of a story whose creation was undone.

A snapshot moves Ctrl+Z's floor, but nothing re-read the head's undo state:
after Save a version, Undo stayed on with a stale tooltip and a click did
nothing. HistoryEffects re-reads GetUndoStatus after a version is saved, and
on any StorySnapshot doorbell while a story is open on any page — the
doorbell carries the snapshot's id, so every open story re-reads its own.

Story.Rename, Describe, Archive, Unarchive and SetActiveGraph stamp UpdatedAt
only on a real change, so a details pause that changes nothing (a trailing
space, a letter typed and taken back) or a second archive leaves the row as
it was: no journal row, no History entry, no Ctrl+Z step, and StoryDetails'
echo, keyed on UpdatedAt, sees the same record back.

Ctrl+Y keeps its window above the newest snapshot. A rule that also looked
beneath it cannot tell a writer's edit a Revert to here undid from one the
writer undid before saving a version, and refused the plain Ctrl+Z / Ctrl+Y
round trip after such a version; a test now pins that round trip. The
Ctrl+Y after a Revert to here on an older snapshot waits for a record of
which revert undid a row.

Tests: the creation floor, the rewritten image and settings cases that undid
a creation, the round trip after a version saved over an undone edit, the
no-op saves at domain and use-case level, the effects' re-read, and the
head's Undo by DOM after a version here and in another tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bjoern referenced this pull request from a commit 2026-09-26 13:10:24 +02:00
docs: the undo floor's PR is #44
All checks were successful
CI / build (pull_request) Successful in 38s
CI / editor-browsers (pull_request) Successful in 39s
CI / test (pull_request) Successful in 1m18s
47fdf78cf5
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: 47fdf78 · Generated: 2026-09-26 11:13:03 UTC · Revision: #1

Summary

Summary
Generated on: 09/26/2026 - 11:13:03
Coverage date: 09/26/2026 - 11:12:43 - 09/26/2026 - 11:13:00
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 483
Files: 437
Line coverage: 97.8% (14750 of 15068)
Covered lines: 14750
Uncovered lines: 318
Coverable lines: 15068
Total lines: 32206
Branch coverage: 93.7% (5645 of 6022)
Covered branches: 5645
Total branches: 6022
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.6%
Name Line Branch
Tsumugi.BlazorAdapter 95.6% 90.5%
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 90% 83.3%
Tsumugi.BlazorAdapter.Workspace.ChapterWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterWritten 100%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.CreatedWire 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeltaWire 100%
Tsumugi.BlazorAdapter.Workspace.HistoryEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryLoaded 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPage 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPanel 100% 100%
Tsumugi.BlazorAdapter.Workspace.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.7%
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.6%
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:** `47fdf78` · **Generated:** 2026-09-26 11:13:03 UTC · **Revision:** #1 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/26/2026 - 11:13:03 | | Coverage date: | 09/26/2026 - 11:12:43 - 09/26/2026 - 11:13:00 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 483 | | Files: | 437 | | **Line coverage:** | 97.8% (14750 of 15068) | | Covered lines: | 14750 | | Uncovered lines: | 318 | | Coverable lines: | 15068 | | Total lines: | 32206 | | **Branch coverage:** | 93.7% (5645 of 6022) | | Covered branches: | 5645 | | Total branches: | 6022 | | **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.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**95.6%**|**90.5%**| |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|90%|83.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterWritten|100%|| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.CreatedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeltaWire|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPage|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPanel|100%|100%| |Tsumugi.BlazorAdapter.Workspace.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.7%**| |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.6%**| |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 my~ An undo floor! The one boundary every journaling editor eventually bleeds on — Ctrl+Z calmly walking a story back through its own birth and deleting it past the trash, past the confirmation, onto a page with no Redo. Delicious. I read every line of the diff, then the whole files around it, then I started breaking things to see if your tests would catch me. Fufu~ they did. Every time. ♡

Verdict: ✅ Looks good to me~

✅ What I liked~

  1. The floor itself (UndoTyping.TargetAsync) — grouping by OperationId first and then checking EntityKind == Story && Operation == Create is exactly right: CreateStory journals the story, its first chapter and both starter categories under one operation id, so the whole creation group is the floor, not just the Story row. And because a floor only exists below the newest active row, an undone creation beneath a saved version stays reachable for Ctrl+Y — the round trip your independent reviewers fought over is now pinned (A_version_saved_over_an_undone_edit_leaves_Ctrl_Y_the_edits_made_after_it). The rejected narrower rule is documented with the reason. That's how a decision should be buried. ♪
  2. The unchanged-save guards in Story — the loveliest part: the guard lives in the domain mutator, so no journal row, no UpdatedAt stamp, no doorbell, nothing — because the journal is ChangeTracker-driven (TsumugiDbContext.BuildJournal). One guard, four effects for free. And Story now mirrors its own sibling: Segment.Write has guarded stored == Text since forever; SoftDelete/Restore already guarded; now all seven mutators are consistent. The StoryDetails echo claim is real, too — OnParametersSet keys on (Id, UpdatedAt, Title, Description) and the trim-echo arm at line 47 tolerates the untrimmed field exactly as before.
  3. The doorbell re-read (HistoryEffects.OnDomainChangesAsync) — Manuscript is not null && action.Touches(EntityKinds.StorySnapshot) is precisely scoped: the shell renders the head row only when the manuscript is loaded (loading state has no Undo button to stale), Touches(kind) ignores ids on purpose (the doorbell carries the snapshot's id — verified in TakeSnapshot's publish), and the reducer's staleness rule drops any late answer. This mirrors DocumentsEffects.SettleAsync's unconditional UndoStatusChanged — sibling-exact.
  4. The tests bite. I ran my own probes at head, each restored pristine and rebuilt:
    • floor guard deleted → 3 creation tests RED;
    • floor weakened to Operation == Create alone → 2 RED;
    • Rename comparing raw title → domain + use-case RED;
    • Describe comparing raw input → RED;
    • doorbell without Manuscript gate → RED;
    • doorbell gated on History is not null instead → RED.
      Six mutants, six clean kills on their own pins, no collateral. And the DOM-level pins (disabled + Nothing to undo (Ctrl+Z) title, after a save on the page and one from another tab through the real DomainChangedBridge) are exactly the seams a user would feel.
  5. The ADR 0029 rewrite is honest — it doesn't pretend the no-FK decision was always for this reason; it records that an earlier build's Ctrl+Z could orphan pictures, why a key would now buy nothing, and updates the sweep item to match. History that tells the truth about itself~ ♡

💡 Little ideas (non-blocking)~

  1. HistoryEffectsTests — Doorbell(...) stamps every fake change with ChangeOperation.Create regardless of kind. Touches only reads the kind so nothing is wrong today, but a future assertion on Operation would silently test a fiction. A ChangeOperation op = ChangeOperation.Create parameter would keep the helper honest.
  2. The two await getUndoStatus.ExecuteAsync(...) dispatches in OnSaveVersionAsync/OnDomainChangesAsync read beautifully as-is — I only note DocumentsEffects already has this exact shape five times; if a sixth home appears, a tiny shared ResendUndoStatus(storyId, dispatcher) helper would DRY it. Not yet — two sites is not a pattern violation. ♪

The disclosed follow-ups (Ctrl+Y after Revert to here needing a ChangeLog column, the replay-over-missing-entity pre-existing gap, unbounded journal loads) are correctly out of scope and honestly named — the two "equivalent survivors" analysis was a nice touch of rigor.

Local verification (CI absent for 47fdf78, no coverage bot yet): Release build 0 warnings / 0 errors; suites digit-exact with the PR body — Domain 470/470, Integration 377/377, BlazorAdapter 358/358; six mutation probes all killed, tree restored pristine at 47fdf78 (git status clean). The known-flaky ChapterPageTests.Changes_made_elsewhere… under load passed in my full adapter run, matching your flake note.

Fufu~ a story is safe from its own undo now. Merge it before I change my mind~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: absent for head SHA · Local checks: build 0w/0e · 470/377/358 green · 6/6 probes red-on-target

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ An undo *floor*! The one boundary every journaling editor eventually bleeds on — Ctrl+Z calmly walking a story back through its own birth and deleting it past the trash, past the confirmation, onto a page with no Redo. *Delicious.* I read every line of the diff, then the whole files around it, then I started breaking things to see if your tests would catch me. Fufu~ they did. Every time. ♡ ### Verdict: ✅ Looks good to me~ #### ✅ What I liked~ 1. **The floor itself (`UndoTyping.TargetAsync`)** — grouping by `OperationId` *first* and then checking `EntityKind == Story && Operation == Create` is exactly right: `CreateStory` journals the story, its first chapter and both starter categories under **one** operation id, so the whole creation group is the floor, not just the Story row. And because a floor only exists below the newest *active* row, an undone creation beneath a saved version stays reachable for Ctrl+Y — the round trip your independent reviewers fought over is now pinned (`A_version_saved_over_an_undone_edit_leaves_Ctrl_Y_the_edits_made_after_it`). The rejected narrower rule is documented *with* the reason. That's how a decision should be buried. ♪ 2. **The unchanged-save guards in `Story`** — the loveliest part: the guard lives in the domain mutator, so no journal row, no `UpdatedAt` stamp, no doorbell, nothing — because the journal is ChangeTracker-driven (`TsumugiDbContext.BuildJournal`). One guard, four effects for free. And `Story` now mirrors its own sibling: `Segment.Write` has guarded `stored == Text` since forever; `SoftDelete`/`Restore` already guarded; now all seven mutators are consistent. The `StoryDetails` echo claim is real, too — `OnParametersSet` keys on `(Id, UpdatedAt, Title, Description)` and the trim-echo arm at line 47 tolerates the untrimmed field exactly as before. 3. **The doorbell re-read (`HistoryEffects.OnDomainChangesAsync`)** — `Manuscript is not null && action.Touches(EntityKinds.StorySnapshot)` is precisely scoped: the shell renders the head row only when the manuscript is loaded (loading state has no Undo button to stale), `Touches(kind)` ignores ids on purpose (the doorbell carries the *snapshot's* id — verified in `TakeSnapshot`'s publish), and the reducer's staleness rule drops any late answer. This mirrors `DocumentsEffects.SettleAsync`'s unconditional `UndoStatusChanged` — sibling-exact. 4. **The tests bite.** I ran my own probes at head, each restored pristine and rebuilt: - floor guard deleted → 3 creation tests RED; - floor weakened to `Operation == Create` alone → 2 RED; - `Rename` comparing raw title → domain + use-case RED; - `Describe` comparing raw input → RED; - doorbell without `Manuscript` gate → RED; - doorbell gated on `History is not null` instead → RED. Six mutants, six clean kills on their own pins, no collateral. And the DOM-level pins (`disabled` + `Nothing to undo (Ctrl+Z)` title, after a save on the page and one from another tab through the real `DomainChangedBridge`) are exactly the seams a user would feel. 5. **The ADR 0029 rewrite is honest** — it doesn't pretend the no-FK decision was always for this reason; it records that an earlier build's Ctrl+Z could orphan pictures, why a key would now buy nothing, and updates the sweep item to match. History that tells the truth about itself~ ♡ #### 💡 Little ideas (non-blocking)~ 1. **HistoryEffectsTests** — `Doorbell(...)` stamps every fake change with `ChangeOperation.Create` regardless of kind. `Touches` only reads the kind so nothing is wrong today, but a future assertion on `Operation` would silently test a fiction. A `ChangeOperation op = ChangeOperation.Create` parameter would keep the helper honest. 2. The two `await getUndoStatus.ExecuteAsync(...)` dispatches in `OnSaveVersionAsync`/`OnDomainChangesAsync` read beautifully as-is — I only note `DocumentsEffects` already has this exact shape five times; if a sixth home appears, a tiny shared `ResendUndoStatus(storyId, dispatcher)` helper would DRY it. Not yet — two sites is not a pattern violation. ♪ The disclosed follow-ups (Ctrl+Y after *Revert to here* needing a `ChangeLog` column, the replay-over-missing-entity pre-existing gap, unbounded journal loads) are correctly out of scope and honestly named — the two "equivalent survivors" analysis was a nice touch of rigor. Local verification (CI absent for `47fdf78`, no coverage bot yet): Release build **0 warnings / 0 errors**; suites digit-exact with the PR body — Domain **470/470**, Integration **377/377**, BlazorAdapter **358/358**; six mutation probes all killed, tree restored pristine at `47fdf78` (`git status` clean). The known-flaky `ChapterPageTests.Changes_made_elsewhere…` under load passed in my full adapter run, matching your flake note. Fufu~ a story is safe from its own undo now. Merge it before I change my mind~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head SHA · Local checks: build 0w/0e · 470/377/358 green · 6/6 probes red-on-target*
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! An undo floor — the kind of fix where the bug report is a horror story ("Ctrl+Z deleted my story past the trash with no Redo") and the fix is one honest predicate. And you made the journal's silence do the work — no-op saves journal nothing because the change tracker sees nothing. I got genuinely giddy tracing that. ♪

Verdict: ✅ Looks good to me~

What I verified mechanically (clone at 47fdf78, submodules Kagaku.UI d512741 / OpenRouter.Net b002f5e, pristine — git status clean after all probes):

  • The floor predicate. CreateStory opens ONE operations.Begin scope for story + chapter + starter categories, so every row of the creation shares one OperationId. UndoTyping.TargetAsync refuses the whole operation when any row is Story+Create — the story can never be deleted from under itself. GetUndoStatus rides the same TargetAsync, so the button and the behavior cannot disagree. That shared-target design is exactly right.
  • The no-op guards. Segment.Write already had this pattern (stored == Text && provenance == Provenance → return false), so Story's five guards extend an established domain idiom, and SoftDelete/Restore siblings already guarded the same way. Since journaling is change-tracker-driven (BuildJournal over TrackedMutations()), a guard's early return means no modified entry, no row, and no doorbell — the claim "no journal row, no History entry, no Ctrl+Z step" holds mechanically, not by assertion. The old unconditional UpdatedAt stamp would itself have marked the row Modified; the guards are load-bearing. Fufu~ clever girl. ♡
  • The doorbell re-read. Manuscript is non-null on every open story page (WorkspaceLoaded), the StorySnapshot kind match is right (the doorbell carries the snapshot's id, not the story's — so every open story re-reads its own), and the reducer's staleness guard (action.StoryId != state.StoryId) is inherited for free. DocumentsEffects already dispatched UndoStatusChanged the same way — sibling-consistent.
  • My 3 mutation probes, each killed on exactly its own pin (each restored pristine + rebuilt, test project rebuilt too — I caught my own stale-binary false-green once and redid it, never counted it):
    1. Floor predicate deleted → Ctrl_Z_walks_a_new_story_back_to_its_creation_and_stops_there RED on the fresh-story UndoStatus assert (CanUndo = True, NextUndo = User — created 'Fresh').
    2. Rename guard deleted → RED in both StoryTests.A_mutator_handed_what_the_story_holds and StoryUseCaseTests.A_save_that_changes_nothing_journals_nothing (the two-layer pin works).
    3. Doorbell re-read block deleted → RED in both HistoryEffectsTests.A_snapshot_taken_anywhere… and HistoryPageTests.A_version_saved_in_another_tab… (effects-level and DOM-level).
  • Full suite at head: Domain 470, UseCases 155, Integration 377, BlazorAdapter 358, Flow 1103, Flow.OR 592+4 live-skipped — all green, 0 warnings, 0 errors, matching your table to the digit.
  • The rewritten tests are honest rewrites, not retreats: AppSettingsTests still proves the key survives undo (now of a real edit), and adds the second-press floor refusal; ImageFieldTests now proves the pictures survive the walk-back while the story still exists — a stronger assertion set than before, honestly earning its rename.
  • ADR 0022/0029 amendments and the StoryImageConfiguration comment say true things (the purge does delete pictures in its own transaction; only a purge deletes a story's row now).

💡 Little ideas (non-blocking)~

  1. Chapter.Rename / Chapter.SetSummary / DocumentCategory.Describe still stamp UpdatedAt unconditionally, so a chapter rename with a trailing space journals a row — the exact noise this PR removes for Story. Pre-existing on main and outside this PR's declared scope, so just a follow-up: the Segment.Write/Story idiom wants to be everywhere a mutator can be handed what it already holds. ♪

✅ What I liked~

  • The refused Ctrl+Y-after-revert gap was left out with a written reason — two rules tried, both regress the ordinary round trip, waiting for a ChangeLog column. Knowing what NOT to ship is my favorite kind of clever. ♡
  • A_version_saved_in_another_tab… mounting the bridge beside the page to let the doorbell reach the shell — testing the real notification path instead of poking state directly.
  • The flake note separating your change from M2b's WaitForAssertion timeout, with counts. That's how you report a flake.

Merge it before I keep it for myself~ fufu~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: absent for head 47fdf78 (no bot comment yet) · Local checks: Release build 0w/0e; full matrix green (2955+4 skipped); 3/3 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! An *undo floor* — the kind of fix where the bug report is a horror story ("Ctrl+Z deleted my story past the trash with no Redo") and the fix is one honest predicate. And you made the journal's *silence* do the work — no-op saves journal nothing because the change tracker sees nothing. I got genuinely giddy tracing that. ♪ ### Verdict: ✅ Looks good to me~ **What I verified mechanically** (clone at `47fdf78`, submodules `Kagaku.UI d512741` / `OpenRouter.Net b002f5e`, pristine — `git status` clean after all probes): - **The floor predicate.** `CreateStory` opens ONE `operations.Begin` scope for story + chapter + starter categories, so every row of the creation shares one `OperationId`. `UndoTyping.TargetAsync` refuses the whole operation when any row is `Story`+`Create` — the story can never be deleted from under itself. `GetUndoStatus` rides the same `TargetAsync`, so the button and the behavior cannot disagree. That shared-target design is *exactly* right. - **The no-op guards.** `Segment.Write` already had this pattern (`stored == Text && provenance == Provenance → return false`), so `Story`'s five guards extend an established domain idiom, and `SoftDelete`/`Restore` siblings already guarded the same way. Since journaling is change-tracker-driven (`BuildJournal` over `TrackedMutations()`), a guard's early return means no modified entry, no row, **and no doorbell** — the claim "no journal row, no History entry, no Ctrl+Z step" holds mechanically, not by assertion. The old unconditional `UpdatedAt` stamp would itself have marked the row Modified; the guards are load-bearing. Fufu~ clever girl. ♡ - **The doorbell re-read.** `Manuscript` is non-null on every open story page (`WorkspaceLoaded`), the `StorySnapshot` kind match is right (the doorbell carries the snapshot's id, not the story's — so every open story re-reads its own), and the reducer's staleness guard (`action.StoryId != state.StoryId`) is inherited for free. `DocumentsEffects` already dispatched `UndoStatusChanged` the same way — sibling-consistent. - **My 3 mutation probes, each killed on exactly its own pin** (each restored pristine + rebuilt, test project rebuilt too — I caught my own stale-binary false-green once and redid it, never counted it): 1. Floor predicate deleted → `Ctrl_Z_walks_a_new_story_back_to_its_creation_and_stops_there` RED on the fresh-story `UndoStatus` assert (`CanUndo = True, NextUndo = User — created 'Fresh'`). 2. `Rename` guard deleted → RED in **both** `StoryTests.A_mutator_handed_what_the_story_holds` and `StoryUseCaseTests.A_save_that_changes_nothing_journals_nothing` (the two-layer pin works). 3. Doorbell re-read block deleted → RED in both `HistoryEffectsTests.A_snapshot_taken_anywhere…` and `HistoryPageTests.A_version_saved_in_another_tab…` (effects-level *and* DOM-level). - **Full suite at head:** Domain 470, UseCases 155, Integration 377, BlazorAdapter 358, Flow 1103, Flow.OR 592+4 live-skipped — all green, 0 warnings, 0 errors, matching your table to the digit. - The rewritten tests are honest rewrites, not retreats: `AppSettingsTests` still proves the key survives undo (now of a real edit), and adds the second-press floor refusal; `ImageFieldTests` now proves the pictures survive the walk-back *while the story still exists* — a stronger assertion set than before, honestly earning its rename. - ADR 0022/0029 amendments and the `StoryImageConfiguration` comment say true things (the purge does delete pictures in its own transaction; only a purge deletes a story's row now). #### 💡 Little ideas (non-blocking)~ 1. **`Chapter.Rename` / `Chapter.SetSummary` / `DocumentCategory.Describe`** still stamp `UpdatedAt` unconditionally, so a chapter rename with a trailing space journals a row — the exact noise this PR removes for `Story`. Pre-existing on main and outside this PR's declared scope, so just a follow-up: the `Segment.Write`/`Story` idiom wants to be everywhere a mutator can be handed what it already holds. ♪ #### ✅ What I liked~ - The refused Ctrl+Y-after-revert gap was *left out with a written reason* — two rules tried, both regress the ordinary round trip, waiting for a `ChangeLog` column. Knowing what NOT to ship is my favorite kind of clever. ♡ - `A_version_saved_in_another_tab…` mounting the bridge beside the page to let the doorbell reach the shell — testing the real notification path instead of poking state directly. - The flake note separating your change from M2b's `WaitForAssertion` timeout, with counts. That's how you report a flake. Merge it before I keep it for myself~ fufu~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head `47fdf78` (no bot comment yet) · Local checks: Release build 0w/0e; full matrix green (2955+4 skipped); 3/3 mutation probes killed*
bjoern merged commit 75a023cd2d into main 2026-09-26 13:41:27 +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!44
No description provided.