fix(journal): Ctrl+Y lands nothing on what the journal took away — a forced revert's discarded edit of a run's paragraph, and an edit of one Redo run deleted again, wait instead of being marked redone over nothing #58

Merged
bjoern merged 2 commits from fix/redo-missing-entity into main 2026-09-26 18:32:09 +02:00
Member

Summary

This is the third follow-up from Jibril's review of #56: "EfUndoStore marks a replayed update active when its entity is missing (reachable through a cut-out discarded edit over an entity a reverted run created)." It was meant to go into #56 as one more commit, but #56 merged first (817465f), so it is a PR of its own on top of that merge.

EfUndoStore.ApplyAsync does nothing when FindAsync returns null, yet ReplayAsync still marks the row active. Ctrl+Y could reach that two ways. The new tests failed on both before the fix:

  • A forced run revert, then an edit elsewhere. A run creates a paragraph; the writer polishes it, then writes another paragraph. A forced Revert run cuts the create and the polish out from under the later paragraph, and Ctrl+Z takes that paragraph back. Below the run's snapshot the cut-out create is stepped over, so the polish becomes the candidate. GetUndoStatus offered "User — polished the run's paragraph", and Ctrl+Y answered Ok(1, 1), changed nothing, and marked the polish active. A later Redo run then counted the polish as a conflict.
  • A delete that stands again. A run deletes the writer's paragraph. Revert run brings it back, an edit typed on it is undone, and Redo run deletes it again. The edit, waiting above the delete, was "redone" the same way.

The fix: Ctrl+Y refuses up front. Before it re-applies anything, RedoTyping.TargetAsync asks the journal whether any entity that the replayed rows find (rather than create) is gone. Gone means its create is undone, or a delete of it still stands. The check is a new IChangeJournal.AnyRemovedAsync, one Any on the indexed EntityId, skipped when the list is empty. If the entity is gone, Ctrl+Y answers "Nothing to redo."

  • Why not the undo store: TargetAsync is also what GetUndoStatus reads, so the button and the key agree and the status never offers a redo it would refuse. A store-level refusal would leave the button enabled on a candidate that fails on every press.
  • Which rows count: only rows Ctrl+Y actually replays. A row a new operation cleared is not replayed, so a gone entity under it does not cost the rest of its operation its redo. Rows the operation creates itself are excluded, because their own creates are undone until the redo runs.
  • Rows from before the upgrade: a create undone before the JournalUndoState upgrade has no state, and it counts like any other undone create.
  • What stays the same: History's Redo and Redo run keep their behaviour. The whole-row redo of a forced revert's discarded edit on an entity that is there (PR #25) is unchanged.

ADR 0022 amended. A new Status line: "Amended 2026-09-26 (PR #58, a redo onto nothing)". The rule and the forced-revert case also go into the Ctrl+Z / Ctrl+Y bullet. The #56 line is unchanged. A second commit, docs: the redo-onto-nothing PR is #58, fills in the number.

Everything is inside the journal's paths: UseCases/Journal (IChangeJournal, RedoTyping), Infrastructure/Journal/EfChangeJournal, ADR 0022, HistoryAndRevertTests, JournalUndoStateMigrationTests, and the adapter's FakeChangeJournal for the new port member. There is no migration and no seed change, since the change adds no user-authored content.

Verification

  • Suites on 817465f, built with -nodeReuse:false -m:2 -p:SkipModuleBuild=true (0 warnings):
    • Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486.
    • The journal filter (HistoryAndRevert, JournalUndoStateMigration, FieldJournal, Journal: 49 tests) passed 6 more runs in a row.
    • The Kagaku.Flow suites were not run, because nothing here touches them.
  • New tests (5 cases):
    • HistoryAndRevertTests.A_forced_run_revert_under_an_edit_elsewhere_leaves_Ctrl_Y_nothing_to_land_on_the_runs_paragraph (×2), the first route. The status is UndoStatus(false, false, null, null), Ctrl+Y returns "Nothing to redo.", no segment appears, and the polish row stays (true, CutOut). After that, either History's Redo gives (3, 3), or Redo run gives (1, 1) and ["By the run."], followed by Ctrl+Y (1, 1) for the polish and (1, 1) for the paragraph written elsewhere. Both end at ["By the run, polished.", "Mine."].
    • HistoryAndRevertTests.Ctrl_Y_lands_nothing_on_a_paragraph_whose_delete_stands_and_offers_the_redo_on_one_whose_delete_was_undone, the second route. While the delete is undone, the status offers "User — typed". Once Redo run deletes the paragraph again, the status is (false, false, null, null), Ctrl+Y returns "Nothing to redo.", and the row stays (true, Rewound).
    • HistoryAndRevertTests.Ctrl_Y_redoes_what_it_replays_of_an_operation_whose_cleared_row_touched_a_paragraph_that_is_gone. One polish covers the run's paragraph and the writer's; a forced revert, then a new edit that clears the discarded row, then Ctrl+Z twice. The status offers "User — polished both", Ctrl+Y gives (1, 1) and ["Mine, polished."], the cleared row stays (true, Cleared), and the writer's row is active.
    • JournalUndoStateMigrationTests.A_run_s_create_undone_before_the_upgrade_leaves_Ctrl_Y_nothing_to_land_on_its_paragraph. The first route, written, then walked down to SegmentTextMarkup and back up, so the three undone rows come back with UndoState IS NULL. The status is (false, false, null, null), Ctrl+Y returns "Nothing to redo.", and the polish stays undone.
  • Mutation probes. Each one compiled, restored its file on every exit through a trap, and the file was touched afterwards.
Mutation Result
Check removed Killed by both route tests (3 cases) and the pre-upgrade test
Created-entity exclusion removed Killed by 4 tests, among them the Redo run arm and FieldJournalTests.A_new_operation_clears_the_row…(history: False)
Entities taken from the whole operation, cleared rows included (review survivor m4) Killed by the cleared-row test
Create arm ignores IsUndone Killed by 14 journal tests
Create arm removed Killed by the first route (Redo run arm) and the pre-upgrade test
Create arm counts only CutOut creates (review survivor m10) Killed by the pre-upgrade test
Delete arm ignores IsUndone Killed by the second route
Delete arm removed Killed by the second route
Entity filter dropped Killed by 5 tests, among them Ctrl_Z_of_a_new_edit_brings_back_that_edit_and_never_the_split_the_edit_cleared
The empty-list guard's > 0 changed to > 1 Killed by 4 tests

Left alone:

  • Excluding the operation's own creates rather than the replayed rows' creates is equivalent in every reachable state, because an operation's own create cannot be cut out or cleared while its later row on the same entity still waits.
  • The adapter's FakeChangeJournal is only exercised on its "nothing removed" side. That is accepted for a fake: forcing it to true fails 5 adapter tests.
  • Review before this PR. Jibril reviewed the commit while it was still meant for #56. Findings and what was done:
    • Blocker: #56 had merged. Resolved by this separate PR. The clause moved out of #56's amendment into its own Status line, and the commit message no longer calls itself part of #56.
    • Major: survivor m4. Now pinned by the cleared-row test above, and m4 fails it.
    • Minor: the summary promised an escape route that does not exist. It said an edit of a paragraph that Redo run deleted again waits "until Revert run takes the delete back". It doesn't: the rewound delete below the snapshot still leaves Ctrl+Y nothing. The clause is dropped.
    • Nits: the second route's test is renamed, since it offers the redo and does not perform it. The garbled "waits so once" is reworded in both the ADR and RedoTyping. m10 is pinned with pre-upgrade rows. The empty-list query is skipped.

Follow-ups (the brief kept these behaviours unchanged; each was confirmed with a throwaway test, then removed):

  • History's Redo still replays onto a paragraph that a standing delete removed. In the second route, after Redo run deletes the paragraph again, RedoRevert returns Ok(1, 1), no segment appears, and "typed" is marked active.
  • Redo run still replays a run's edit onto a paragraph whose create is undone. The sequence: a snapshot, the writer writes the paragraph, a run replaces it, Revert to here on that snapshot, then Redo run. It returns Ok(1, 1), no segment appears, and the run row is marked active. History's Redo then reports nothing to redo, which strands the writer's create.
  • Both share the cause (EfUndoStore's silent no-op on a missing entity). The same AnyRemovedAsync check in RedoRun and RedoRevert, or a refusal at the store, would close both. ADR 0022 covers both behaviours, so each needs its own amendment.

🤖 Generated with Claude Code

## Summary This is the third follow-up from Jibril's review of #56: "`EfUndoStore` marks a replayed update active when its entity is missing (reachable through a cut-out discarded edit over an entity a reverted run created)." It was meant to go into #56 as one more commit, but #56 merged first (817465f), so it is a PR of its own on top of that merge. `EfUndoStore.ApplyAsync` does nothing when `FindAsync` returns null, yet `ReplayAsync` still marks the row active. Ctrl+Y could reach that two ways. The new tests failed on both before the fix: - **A forced run revert, then an edit elsewhere.** A run creates a paragraph; the writer polishes it, then writes another paragraph. A forced Revert run cuts the create and the polish out from under the later paragraph, and Ctrl+Z takes that paragraph back. Below the run's snapshot the cut-out create is stepped over, so the polish becomes the candidate. `GetUndoStatus` offered "User — polished the run's paragraph", and Ctrl+Y answered `Ok(1, 1)`, changed nothing, and marked the polish active. A later Redo run then counted the polish as a conflict. - **A delete that stands again.** A run deletes the writer's paragraph. Revert run brings it back, an edit typed on it is undone, and Redo run deletes it again. The edit, waiting above the delete, was "redone" the same way. **The fix: Ctrl+Y refuses up front.** Before it re-applies anything, `RedoTyping.TargetAsync` asks the journal whether any entity that the replayed rows *find* (rather than create) is gone. Gone means its create is undone, or a delete of it still stands. The check is a new `IChangeJournal.AnyRemovedAsync`, one `Any` on the indexed `EntityId`, skipped when the list is empty. If the entity is gone, Ctrl+Y answers "Nothing to redo." - **Why not the undo store:** `TargetAsync` is also what `GetUndoStatus` reads, so the button and the key agree and the status never offers a redo it would refuse. A store-level refusal would leave the button enabled on a candidate that fails on every press. - **Which rows count:** only rows Ctrl+Y actually replays. A row a new operation cleared is not replayed, so a gone entity under it does not cost the rest of its operation its redo. Rows the operation creates itself are excluded, because their own creates are undone until the redo runs. - **Rows from before the upgrade:** a create undone before the `JournalUndoState` upgrade has no state, and it counts like any other undone create. - **What stays the same:** History's Redo and Redo run keep their behaviour. The whole-row redo of a forced revert's discarded edit on an entity that is there (PR #25) is unchanged. **ADR 0022 amended.** A new Status line: "Amended 2026-09-26 (PR #58, a redo onto nothing)". The rule and the forced-revert case also go into the Ctrl+Z / Ctrl+Y bullet. The #56 line is unchanged. A second commit, `docs: the redo-onto-nothing PR is #58`, fills in the number. Everything is inside the journal's paths: `UseCases/Journal` (`IChangeJournal`, `RedoTyping`), `Infrastructure/Journal/EfChangeJournal`, ADR 0022, `HistoryAndRevertTests`, `JournalUndoStateMigrationTests`, and the adapter's `FakeChangeJournal` for the new port member. There is no migration and no seed change, since the change adds no user-authored content. ## Verification - **Suites** on `817465f`, built with `-nodeReuse:false -m:2 -p:SkipModuleBuild=true` (0 warnings): - Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486. - The journal filter (HistoryAndRevert, JournalUndoStateMigration, FieldJournal, Journal: 49 tests) passed 6 more runs in a row. - The Kagaku.Flow suites were not run, because nothing here touches them. - **New tests** (5 cases): - `HistoryAndRevertTests.A_forced_run_revert_under_an_edit_elsewhere_leaves_Ctrl_Y_nothing_to_land_on_the_runs_paragraph` (×2), the first route. The status is `UndoStatus(false, false, null, null)`, Ctrl+Y returns "Nothing to redo.", no segment appears, and the polish row stays `(true, CutOut)`. After that, either History's Redo gives `(3, 3)`, or Redo run gives `(1, 1)` and `["By the run."]`, followed by Ctrl+Y `(1, 1)` for the polish and `(1, 1)` for the paragraph written elsewhere. Both end at `["By the run, polished.", "Mine."]`. - `HistoryAndRevertTests.Ctrl_Y_lands_nothing_on_a_paragraph_whose_delete_stands_and_offers_the_redo_on_one_whose_delete_was_undone`, the second route. While the delete is undone, the status offers "User — typed". Once Redo run deletes the paragraph again, the status is `(false, false, null, null)`, Ctrl+Y returns "Nothing to redo.", and the row stays `(true, Rewound)`. - `HistoryAndRevertTests.Ctrl_Y_redoes_what_it_replays_of_an_operation_whose_cleared_row_touched_a_paragraph_that_is_gone`. One polish covers the run's paragraph and the writer's; a forced revert, then a new edit that clears the discarded row, then Ctrl+Z twice. The status offers "User — polished both", Ctrl+Y gives `(1, 1)` and `["Mine, polished."]`, the cleared row stays `(true, Cleared)`, and the writer's row is active. - `JournalUndoStateMigrationTests.A_run_s_create_undone_before_the_upgrade_leaves_Ctrl_Y_nothing_to_land_on_its_paragraph`. The first route, written, then walked down to `SegmentTextMarkup` and back up, so the three undone rows come back with `UndoState IS NULL`. The status is `(false, false, null, null)`, Ctrl+Y returns "Nothing to redo.", and the polish stays undone. - **Mutation probes.** Each one compiled, restored its file on every exit through a trap, and the file was touched afterwards. | Mutation | Result | |---|---| | Check removed | Killed by both route tests (3 cases) and the pre-upgrade test | | Created-entity exclusion removed | Killed by 4 tests, among them the Redo run arm and `FieldJournalTests.A_new_operation_clears_the_row…(history: False)` | | Entities taken from the whole operation, cleared rows included (review survivor m4) | Killed by the cleared-row test | | Create arm ignores `IsUndone` | Killed by 14 journal tests | | Create arm removed | Killed by the first route (Redo run arm) and the pre-upgrade test | | Create arm counts only `CutOut` creates (review survivor m10) | Killed by the pre-upgrade test | | Delete arm ignores `IsUndone` | Killed by the second route | | Delete arm removed | Killed by the second route | | Entity filter dropped | Killed by 5 tests, among them `Ctrl_Z_of_a_new_edit_brings_back_that_edit_and_never_the_split_the_edit_cleared` | | The empty-list guard's `> 0` changed to `> 1` | Killed by 4 tests | Left alone: - Excluding the operation's own creates rather than the replayed rows' creates is equivalent in every reachable state, because an operation's own create cannot be cut out or cleared while its later row on the same entity still waits. - The adapter's `FakeChangeJournal` is only exercised on its "nothing removed" side. That is accepted for a fake: forcing it to `true` fails 5 adapter tests. - **Review before this PR.** Jibril reviewed the commit while it was still meant for #56. Findings and what was done: - **Blocker: #56 had merged.** Resolved by this separate PR. The clause moved out of #56's amendment into its own Status line, and the commit message no longer calls itself part of #56. - **Major: survivor m4.** Now pinned by the cleared-row test above, and m4 fails it. - **Minor: the summary promised an escape route that does not exist.** It said an edit of a paragraph that Redo run deleted again waits "until Revert run takes the delete back". It doesn't: the rewound delete below the snapshot still leaves Ctrl+Y nothing. The clause is dropped. - **Nits:** the second route's test is renamed, since it offers the redo and does not perform it. The garbled "waits so once" is reworded in both the ADR and `RedoTyping`. m10 is pinned with pre-upgrade rows. The empty-list query is skipped. **Follow-ups** (the brief kept these behaviours unchanged; each was confirmed with a throwaway test, then removed): - History's Redo still replays onto a paragraph that a standing delete removed. In the second route, after Redo run deletes the paragraph again, `RedoRevert` returns `Ok(1, 1)`, no segment appears, and "typed" is marked active. - Redo run still replays a run's edit onto a paragraph whose create is undone. The sequence: a snapshot, the writer writes the paragraph, a run replaces it, Revert to here on that snapshot, then Redo run. It returns `Ok(1, 1)`, no segment appears, and the run row is marked active. History's Redo then reports nothing to redo, which strands the writer's create. - Both share the cause (`EfUndoStore`'s silent no-op on a missing entity). The same `AnyRemovedAsync` check in `RedoRun` and `RedoRevert`, or a refusal at the store, would close both. ADR 0022 covers both behaviours, so each needs its own amendment. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(journal): Ctrl+Y lands nothing on what the journal took away — a forced revert's discarded edit of a run's paragraph, and an edit of one Redo run deleted again, wait instead of being marked redone over nothing
Some checks failed
CI / build (pull_request) Has been cancelled
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
31aeff7110
The follow-up Jibril's review of #56 left open: EfUndoStore replays an
update onto a missing entity as a no-op and still marks the row active.
Ctrl+Y reached it two ways:

- A run creates a paragraph, the writer polishes it, then writes elsewhere; a
  forced Revert run cuts the create and the polish out from under the later
  paragraph, and Ctrl+Z takes that one back. Below the run's snapshot the
  cut-out create is stepped over, the polish is the candidate, and Ctrl+Y
  answered Ok(1, 1), changed nothing and marked the polish active — which
  GetUndoStatus had offered, and which a later Redo run took for a conflict.
- A run deletes the writer's paragraph; Revert run brings it back, an edit
  typed on it is undone, and Redo run deletes it again: the edit, waiting
  above the delete, went the same way.

Ctrl+Y now refuses up front. RedoTyping.TargetAsync asks the journal whether
any entity the rows it would replay find rather than create is gone — a new
IChangeJournal.AnyRemovedAsync: a create of it undone, or a delete of it
still standing (one Any on the indexed EntityId) — and answers "Nothing to
redo." if so. A row a new operation cleared is not replayed, so the entity it
touched does not count against the rest of its operation; a create undone
before the JournalUndoState upgrade, with no state, counts as any other. The
refusal lives in the use case, not the store: TargetAsync is what
GetUndoStatus reads too, so the button and the key agree and the status never
offers a redo it would refuse; which rows to replay is the use cases' call by
IUndoStore's contract; and History's Redo and Redo run keep their behaviour.
The whole-row redo of a forced revert's discarded edit on an entity that is
there (PR #25) is unchanged.

ADR 0022: an amendment line of its own, and the rule in the Ctrl+Y bullet.

Left, and reported: History's Redo and Redo run still mark a replay onto a
missing entity active — History's Redo in the second route above, and Redo run
of a run's edit after Revert to here on a version older than the paragraph.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bjoern referenced this pull request from a commit 2026-09-26 18:01:00 +02:00
docs: the redo-onto-nothing PR is #58
All checks were successful
CI / build (pull_request) Successful in 39s
CI / editor-browsers (pull_request) Successful in 54s
CI / test (pull_request) Successful in 1m35s
d9448c6517
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: d9448c6 · Generated: 2026-09-26 16:06:54 UTC · Revision: #1

Summary

Summary
Generated on: 09/26/2026 - 16:06:54
Coverage date: 09/26/2026 - 16:06:26 - 09/26/2026 - 16:06:50
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 495
Files: 449
Line coverage: 98.1% (15698 of 15994)
Covered lines: 15698
Uncovered lines: 296
Coverable lines: 15994
Total lines: 34006
Branch coverage: 94.1% (5955 of 6322)
Covered branches: 5955
Total branches: 6322
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.Flow - 99.7%
Name Line Branch
Kagaku.Flow 99.7% 99.2%
Kagaku.Flow.Budgeting.BudgetRequest 100%
Kagaku.Flow.Budgeting.ConsumerBudget 100%
Kagaku.Flow.Execution.NodeExecution 100% 100%
Kagaku.Flow.Execution.NodeOutcome 100% 100%
Kagaku.Flow.Execution.TransientFailureException 100%
Kagaku.Flow.Execution.Upstream 100%
Kagaku.Flow.Extensions.ServiceCollectionExtensions 100%
Kagaku.Flow.FlowJson 100%
Kagaku.Flow.Graphs.GraphDefinition 100%
Kagaku.Flow.Graphs.GraphDocument 100% 100%
Kagaku.Flow.Graphs.GraphEdge 100%
Kagaku.Flow.Graphs.GraphIndex 100% 100%
Kagaku.Flow.Graphs.GraphLoadError 100%
Kagaku.Flow.Graphs.GraphLoadResult 100%
Kagaku.Flow.Graphs.GraphNode 100%
Kagaku.Flow.Graphs.GraphPosition 100%
Kagaku.Flow.Graphs.GraphReader 100% 100%
Kagaku.Flow.Graphs.GraphSchema 100% 100%
Kagaku.Flow.Graphs.GraphShapeException 100%
Kagaku.Flow.Graphs.GraphWriter 100% 100%
Kagaku.Flow.Graphs.SocketRef 100%
Kagaku.Flow.Graphs.WireText 100% 100%
Kagaku.Flow.Nodes.CanvasDescriptorWriter 100% 100%
Kagaku.Flow.Nodes.ConfigProblem 100%
Kagaku.Flow.Nodes.Names 100%
Kagaku.Flow.Nodes.NodeDescriptor 100% 100%
Kagaku.Flow.Nodes.NodeRegistry 100% 100%
Kagaku.Flow.Nodes.NodeSockets 100% 100%
Kagaku.Flow.Nodes.SinkDescriptor 100%
Kagaku.Flow.Nodes.SocketTypes 100% 100%
Kagaku.Flow.Nodes.SourceDescriptor 100%
Kagaku.Flow.Nodes.TemplateField 100%
Kagaku.Flow.Runs.LedgerChange 100% 100%
Kagaku.Flow.Runs.LedgerTransitions 100% 100%
Kagaku.Flow.Runs.NodeAttempt 100%
Kagaku.Flow.Runs.NodeFacts 100%
Kagaku.Flow.Runs.NodeRun 100%
Kagaku.Flow.Runs.Run 100% 100%
Kagaku.Flow.Runs.RunEvent 100%
Kagaku.Flow.Runs.RunStatuses 100% 100%
Kagaku.Flow.Runs.RunTrigger 100% 100%
Kagaku.Flow.Scheduling.Exclusion 100%
Kagaku.Flow.Scheduling.FlowEngine 100% 100%
Kagaku.Flow.Scheduling.FlowEngineOptions 100% 100%
Kagaku.Flow.Scheduling.ReadyRow 100%
Kagaku.Flow.Scheduling.ReadySet 100% 100%
Kagaku.Flow.Scheduling.ReadySetResult 100%
Kagaku.Flow.Scheduling.RunRequest 100% 100%
Kagaku.Flow.Scheduling.RunStartResult 100%
Kagaku.Flow.Scheduling.SocketValues 100% 100%
Kagaku.Flow.Templating.InputsWalker 100% 100%
Kagaku.Flow.Templating.ParsedTemplate 100% 100%
Kagaku.Flow.Templating.SandboxedTemplateContext 100% 100%
Kagaku.Flow.Templating.TemplateError 100%
Kagaku.Flow.Templating.TemplateHost 100% 100%
Kagaku.Flow.Templating.TemplateLimits 100%
Kagaku.Flow.Templating.TemplateModel 100% 100%
Kagaku.Flow.Templating.TemplateProblem 100%
Kagaku.Flow.Templating.TemplateRenderRequest 100% 100%
Kagaku.Flow.Templating.TemplateRenderResult 100%
Kagaku.Flow.Templating.TemplateRun 100%
Kagaku.Flow.Templating.TemplateSinks 100%
Kagaku.Flow.Templating.TemplateValues 100% 100%
Kagaku.Flow.Validation.GraphValidation 100% 100%
Kagaku.Flow.Validation.GraphValidationContext 100%
Kagaku.Flow.Validation.HookFailure 100%
Kagaku.Flow.Validation.ResolvedGraph 100% 100%
Kagaku.Flow.Validation.ValidationError 100%
Kagaku.Flow.Validation.ValidationReport 100%
System.Text.RegularExpressions.Generated 97.4% 92.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2
97.4% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
97.2% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
97.2% 94.4%
Kagaku.Flow.OpenRouter - 100%
Name Line Branch
Kagaku.Flow.OpenRouter 100% 100%
Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities 100% 100%
Kagaku.Flow.OpenRouter.Gateway.LlmCompletion 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway 100% 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmAnswer 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfig 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfigRead 100%
Kagaku.Flow.OpenRouter.Llm.LlmDescriptor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmExecutor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFacts 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFailureText 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmMessage 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan 100%
Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmSampling 100%
Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmVocabulary 100% 100%
Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions 100%
Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions 100% 100%
Kagaku.Flow.Testing - 100%
Name Line Branch
Kagaku.Flow.Testing 100% 100%
Kagaku.Flow.Testing.FlowEngineDriver 100% 100%
Kagaku.Flow.Testing.InMemoryRunLedger 100% 100%
Kagaku.Flow.Testing.RecordingRunEventSink 100%
Kagaku.Flow.Testing.RunLedgerContract 100% 100%
Kagaku.Flow.Testing.RunLedgerContractException 100%
Tsumugi.BlazorAdapter - 96%
Name Line Branch
Tsumugi.BlazorAdapter 96% 90.9%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 93.2% 88.4%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 94.1%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 95.7% 89.4%
Tsumugi.BlazorAdapter.Documents.DocumentImageRefused 100%
Tsumugi.BlazorAdapter.Documents.DocumentImageSet 100%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.5% 93.5%
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 94.4% 83.3%
Tsumugi.BlazorAdapter.Workspace.ChapterWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterWritten 100%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.CreatedWire 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeltaWire 100%
Tsumugi.BlazorAdapter.Workspace.HistoryEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryLoaded 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPage 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPanel 100% 100%
Tsumugi.BlazorAdapter.Workspace.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents 81.8% 74.1%
Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface 91.1% 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 100% 100%
Tsumugi.BlazorAdapter.Workspace.UndoRequested 100%
Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged 100%
Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers 100% 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceState 100%
Tsumugi.Domain - 96.3%
Name Line Branch
Tsumugi.Domain 96.3% 95%
System.Text.RegularExpressions.Generated 91.3% 88.6%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
97.4% 95.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
91% 91.1%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
91.8% 83.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
91.9% 88.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
90.9% 84.3%
Tsumugi.Domain.Documents.CategoryFields 94.5% 93.7%
Tsumugi.Domain.Documents.ChoiceOption 100%
Tsumugi.Domain.Documents.ChoiceValue 100%
Tsumugi.Domain.Documents.DateText 100%
Tsumugi.Domain.Documents.DateValue 100%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 100% 100%
Tsumugi.Domain.Documents.DocumentValues 100%
Tsumugi.Domain.Documents.FieldCarry 100% 100%
Tsumugi.Domain.Documents.FieldConversion 100% 100%
Tsumugi.Domain.Documents.FieldDefinition 97% 95.3%
Tsumugi.Domain.Documents.FieldMessages 100% 100%
Tsumugi.Domain.Documents.FieldNames 100%
Tsumugi.Domain.Documents.FieldsChange 100%
Tsumugi.Domain.Documents.FieldShape 95.2% 87.5%
Tsumugi.Domain.Documents.FieldsPlan 100%
Tsumugi.Domain.Documents.FieldsPlanner 99.2% 99.2%
Tsumugi.Domain.Documents.FieldValue 100%
Tsumugi.Domain.Documents.FieldValues 95.4% 97.7%
Tsumugi.Domain.Documents.ImageFiles 100% 100%
Tsumugi.Domain.Documents.ImageValue 100%
Tsumugi.Domain.Documents.MovePlan 100%
Tsumugi.Domain.Documents.NumberParse 100%
Tsumugi.Domain.Documents.NumberText 100% 97.6%
Tsumugi.Domain.Documents.NumberValue 100%
Tsumugi.Domain.Documents.StoryImage 100%
Tsumugi.Domain.Documents.TextValue 100% 100%
Tsumugi.Domain.Documents.ValueChange 100%
Tsumugi.Domain.Documents.ValueChangeKey 100%
Tsumugi.Domain.Documents.ValueImpact 100% 100%
Tsumugi.Domain.Journal.ChangeLogEntry 97.9% 83.3%
Tsumugi.Domain.Journal.StorySnapshot 95.4% 83.3%
Tsumugi.Domain.Settings.AppSetting 100%
Tsumugi.Domain.Stories.Chapter 100% 100%
Tsumugi.Domain.Stories.InlineMarkup 100% 100%
Tsumugi.Domain.Stories.MarkupRun 100%
Tsumugi.Domain.Stories.Provenance 100% 100%
Tsumugi.Domain.Stories.Segment 100% 100%
Tsumugi.Domain.Stories.Story 100% 100%
Tsumugi.Domain.Text 100% 100%
Tsumugi.Infrastructure - 98.3%
Name Line Branch
Tsumugi.Infrastructure 98.3% 86.7%
System.Text.RegularExpressions.Generated 81.4% 64.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
84% 65.7%
Tsumugi.Infrastructure.Backups.BackupArtifactName 100% 100%
Tsumugi.Infrastructure.Backups.BackupOptions 100%
Tsumugi.Infrastructure.Backups.BackupSchedule 100% 83.3%
Tsumugi.Infrastructure.Backups.BackupScheduler 96.6% 87.5%
Tsumugi.Infrastructure.Backups.BackupWriter 98.5% 92.8%
Tsumugi.Infrastructure.Backups.DatabaseFingerprint 91.9% 97%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.OwnerOnlyFile 100% 100%
Tsumugi.Infrastructure.Backups.PreMigrationBackup 90% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 88.2% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.3% 86.6%
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.JournalUndoState 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.StoryImages 100%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
Tsumugi.Infrastructure.Persistence.SqliteFunctions 80% 66.6%
Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore 98.3% 75%
Tsumugi.Infrastructure.Persistence.Stores.EfImageStore 100%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 96.6% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.7% 90%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 97.7% 96.6%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 100%
Tsumugi.Infrastructure.Provider.LlmDefaultsSource 100%
Tsumugi.Infrastructure.Provider.OpenRouterKeySource 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterModelProvider 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterOptions 100% 100%
Tsumugi.Infrastructure.Provider.ResolvedKey 100%
Tsumugi.Infrastructure.Runs.InProcessRunEventBus 100% 100%
Tsumugi.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Tsumugi.Kernel - 90.9%
Name Line Branch
Tsumugi.Kernel 90.9% 75%
Tsumugi.Kernel.Err`1 100%
Tsumugi.Kernel.Ok`1 100%
Tsumugi.Kernel.Result`1 88.8% 75%
Tsumugi.Server - 100%
Name Line Branch
Tsumugi.Server 100% 92.1%
Program 100% 100%
Tsumugi.Server.Backups.BackupConfiguration 100% 100%
Tsumugi.Server.Components.App 100%
Tsumugi.Server.Components.Layout.AppHeader 100% 50%
Tsumugi.Server.Components.Layout.MainLayout 100%
Tsumugi.Server.Components.Pages.Gate 100% 100%
Tsumugi.Server.Provider.OpenRouterConfiguration 100% 100%
Tsumugi.Server.Security.AccessGate 100% 87.5%
Tsumugi.Server.Security.AccessSecret 100% 100%
Tsumugi.Server.Security.GateThrottle 100% 100%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98.5%
Name Line Branch
Tsumugi.UseCases 98.5% 95.7%
Tsumugi.UseCases.Backups.BackupArtifact 100%
Tsumugi.UseCases.Backups.BackupFailure 100%
Tsumugi.UseCases.Backups.BackupJobState 100%
Tsumugi.UseCases.Backups.BackupPolicy 100%
Tsumugi.UseCases.Backups.BackupStatusView 100% 100%
Tsumugi.UseCases.Backups.DatabaseSnapshot 100%
Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot 100%
Tsumugi.UseCases.Backups.GetBackupStatus 100%
Tsumugi.UseCases.Backups.IBackupStore 0%
Tsumugi.UseCases.Backups.RunBackupNow 100%
Tsumugi.UseCases.Chapters.ChapterDto 100%
Tsumugi.UseCases.Chapters.CreateChapter 100% 100%
Tsumugi.UseCases.Chapters.DeleteChapter 100% 100%
Tsumugi.UseCases.Chapters.GetChapterSegments 100%
Tsumugi.UseCases.Chapters.GetManuscript 100% 100%
Tsumugi.UseCases.Chapters.ManuscriptChapter 100%
Tsumugi.UseCases.Chapters.ManuscriptView 100%
Tsumugi.UseCases.Chapters.MergeChapters 100% 100%
Tsumugi.UseCases.Chapters.RenameChapter 100% 100%
Tsumugi.UseCases.Chapters.ReorderChapters 100% 100%
Tsumugi.UseCases.Chapters.SetChapterSummary 100% 75%
Tsumugi.UseCases.Context.DocumentRendering 100% 100%
Tsumugi.UseCases.Context.StoryDocumentsRule 100% 100%
Tsumugi.UseCases.Context.StoryReads 100% 100%
Tsumugi.UseCases.Context.StoryScope 100% 100%
Tsumugi.UseCases.Context.StoryTemplateModel 100%
Tsumugi.UseCases.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 98.3% 68.7%
Tsumugi.UseCases.Diagnostics.SeedPictures 100%
Tsumugi.UseCases.Documents.ChangeCategoryFields 100% 83.3%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DefaultFields 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 94.4%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentPatch 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.DocumentWrites 100% 100%
Tsumugi.UseCases.Documents.FieldsChangeLabel 95.4% 88.2%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.GetStoryImage 100% 100%
Tsumugi.UseCases.Documents.ImpactPreview 100% 100%
Tsumugi.UseCases.Documents.LossMessages 92.3% 87.5%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.SetDocumentImage 100% 93.7%
Tsumugi.UseCases.Documents.StoryImageFile 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 81.2%
Tsumugi.UseCases.Documents.WriteRefusedException 100%
Tsumugi.UseCases.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:** `d9448c6` · **Generated:** 2026-09-26 16:06:54 UTC · **Revision:** #1 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/26/2026 - 16:06:54 | | Coverage date: | 09/26/2026 - 16:06:26 - 09/26/2026 - 16:06:50 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 495 | | Files: | 449 | | **Line coverage:** | 98.1% (15698 of 15994) | | Covered lines: | 15698 | | Uncovered lines: | 296 | | Coverable lines: | 15994 | | Total lines: | 34006 | | **Branch coverage:** | 94.1% (5955 of 6322) | | Covered branches: | 5955 | | Total branches: | 6322 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.Flow - 99.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow**|**99.7%**|**99.2%**| |Kagaku.Flow.Budgeting.BudgetRequest|100%|| |Kagaku.Flow.Budgeting.ConsumerBudget|100%|| |Kagaku.Flow.Execution.NodeExecution|100%|100%| |Kagaku.Flow.Execution.NodeOutcome|100%|100%| |Kagaku.Flow.Execution.TransientFailureException|100%|| |Kagaku.Flow.Execution.Upstream|100%|| |Kagaku.Flow.Extensions.ServiceCollectionExtensions|100%|| |Kagaku.Flow.FlowJson|100%|| |Kagaku.Flow.Graphs.GraphDefinition|100%|| |Kagaku.Flow.Graphs.GraphDocument|100%|100%| |Kagaku.Flow.Graphs.GraphEdge|100%|| |Kagaku.Flow.Graphs.GraphIndex|100%|100%| |Kagaku.Flow.Graphs.GraphLoadError|100%|| |Kagaku.Flow.Graphs.GraphLoadResult|100%|| |Kagaku.Flow.Graphs.GraphNode|100%|| |Kagaku.Flow.Graphs.GraphPosition|100%|| |Kagaku.Flow.Graphs.GraphReader|100%|100%| |Kagaku.Flow.Graphs.GraphSchema|100%|100%| |Kagaku.Flow.Graphs.GraphShapeException|100%|| |Kagaku.Flow.Graphs.GraphWriter|100%|100%| |Kagaku.Flow.Graphs.SocketRef|100%|| |Kagaku.Flow.Graphs.WireText|100%|100%| |Kagaku.Flow.Nodes.CanvasDescriptorWriter|100%|100%| |Kagaku.Flow.Nodes.ConfigProblem|100%|| |Kagaku.Flow.Nodes.Names|100%|| |Kagaku.Flow.Nodes.NodeDescriptor|100%|100%| |Kagaku.Flow.Nodes.NodeRegistry|100%|100%| |Kagaku.Flow.Nodes.NodeSockets|100%|100%| |Kagaku.Flow.Nodes.SinkDescriptor|100%|| |Kagaku.Flow.Nodes.SocketTypes|100%|100%| |Kagaku.Flow.Nodes.SourceDescriptor|100%|| |Kagaku.Flow.Nodes.TemplateField|100%|| |Kagaku.Flow.Runs.LedgerChange|100%|100%| |Kagaku.Flow.Runs.LedgerTransitions|100%|100%| |Kagaku.Flow.Runs.NodeAttempt|100%|| |Kagaku.Flow.Runs.NodeFacts|100%|| |Kagaku.Flow.Runs.NodeRun|100%|| |Kagaku.Flow.Runs.Run|100%|100%| |Kagaku.Flow.Runs.RunEvent|100%|| |Kagaku.Flow.Runs.RunStatuses|100%|100%| |Kagaku.Flow.Runs.RunTrigger|100%|100%| |Kagaku.Flow.Scheduling.Exclusion|100%|| |Kagaku.Flow.Scheduling.FlowEngine|100%|100%| |Kagaku.Flow.Scheduling.FlowEngineOptions|100%|100%| |Kagaku.Flow.Scheduling.ReadyRow|100%|| |Kagaku.Flow.Scheduling.ReadySet|100%|100%| |Kagaku.Flow.Scheduling.ReadySetResult|100%|| |Kagaku.Flow.Scheduling.RunRequest|100%|100%| |Kagaku.Flow.Scheduling.RunStartResult|100%|| |Kagaku.Flow.Scheduling.SocketValues|100%|100%| |Kagaku.Flow.Templating.InputsWalker|100%|100%| |Kagaku.Flow.Templating.ParsedTemplate|100%|100%| |Kagaku.Flow.Templating.SandboxedTemplateContext|100%|100%| |Kagaku.Flow.Templating.TemplateError|100%|| |Kagaku.Flow.Templating.TemplateHost|100%|100%| |Kagaku.Flow.Templating.TemplateLimits|100%|| |Kagaku.Flow.Templating.TemplateModel|100%|100%| |Kagaku.Flow.Templating.TemplateProblem|100%|| |Kagaku.Flow.Templating.TemplateRenderRequest|100%|100%| |Kagaku.Flow.Templating.TemplateRenderResult|100%|| |Kagaku.Flow.Templating.TemplateRun|100%|| |Kagaku.Flow.Templating.TemplateSinks|100%|| |Kagaku.Flow.Templating.TemplateValues|100%|100%| |Kagaku.Flow.Validation.GraphValidation|100%|100%| |Kagaku.Flow.Validation.GraphValidationContext|100%|| |Kagaku.Flow.Validation.HookFailure|100%|| |Kagaku.Flow.Validation.ResolvedGraph|100%|100%| |Kagaku.Flow.Validation.ValidationError|100%|| |Kagaku.Flow.Validation.ValidationReport|100%|| |System.Text.RegularExpressions.Generated|97.4%|92.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2|97.4%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1|97.2%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0|97.2%|94.4%| </details> <details><summary>Kagaku.Flow.OpenRouter - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.OpenRouter**|**100%**|**100%**| |Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.LlmCompletion|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmAnswer|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfig|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfigRead|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmDescriptor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmExecutor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFacts|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFailureText|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmMessage|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmSampling|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmVocabulary|100%|100%| |Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions|100%|| |Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions|100%|100%| </details> <details><summary>Kagaku.Flow.Testing - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.Testing**|**100%**|**100%**| |Kagaku.Flow.Testing.FlowEngineDriver|100%|100%| |Kagaku.Flow.Testing.InMemoryRunLedger|100%|100%| |Kagaku.Flow.Testing.RecordingRunEventSink|100%|| |Kagaku.Flow.Testing.RunLedgerContract|100%|100%| |Kagaku.Flow.Testing.RunLedgerContractException|100%|| </details> <details><summary>Tsumugi.BlazorAdapter - 96%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**96%**|**90.9%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|93.2%|88.4%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|94.1%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|95.7%|89.4%| |Tsumugi.BlazorAdapter.Documents.DocumentImageRefused|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentImageSet|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.5%|93.5%| |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|94.4%|83.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterWritten|100%|| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.CreatedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeltaWire|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPage|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPanel|100%|100%| |Tsumugi.BlazorAdapter.Workspace.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents|81.8%|74.1%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface|91.1%|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|100%|100%| |Tsumugi.BlazorAdapter.Workspace.UndoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged|100%|| |Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers|100%|100%| |Tsumugi.BlazorAdapter.Workspace.WorkspaceState|100%|| </details> <details><summary>Tsumugi.Domain - 96.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**96.3%**|**95%**| |System.Text.RegularExpressions.Generated|91.3%|88.6%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2|97.4%|95.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0|91%|91.1%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1|91.8%|83.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4|91.9%|88.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3|90.9%|84.3%| |Tsumugi.Domain.Documents.CategoryFields|94.5%|93.7%| |Tsumugi.Domain.Documents.ChoiceOption|100%|| |Tsumugi.Domain.Documents.ChoiceValue|100%|| |Tsumugi.Domain.Documents.DateText|100%|| |Tsumugi.Domain.Documents.DateValue|100%|| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|100%|100%| |Tsumugi.Domain.Documents.DocumentValues|100%|| |Tsumugi.Domain.Documents.FieldCarry|100%|100%| |Tsumugi.Domain.Documents.FieldConversion|100%|100%| |Tsumugi.Domain.Documents.FieldDefinition|97%|95.3%| |Tsumugi.Domain.Documents.FieldMessages|100%|100%| |Tsumugi.Domain.Documents.FieldNames|100%|| |Tsumugi.Domain.Documents.FieldsChange|100%|| |Tsumugi.Domain.Documents.FieldShape|95.2%|87.5%| |Tsumugi.Domain.Documents.FieldsPlan|100%|| |Tsumugi.Domain.Documents.FieldsPlanner|99.2%|99.2%| |Tsumugi.Domain.Documents.FieldValue|100%|| |Tsumugi.Domain.Documents.FieldValues|95.4%|97.7%| |Tsumugi.Domain.Documents.ImageFiles|100%|100%| |Tsumugi.Domain.Documents.ImageValue|100%|| |Tsumugi.Domain.Documents.MovePlan|100%|| |Tsumugi.Domain.Documents.NumberParse|100%|| |Tsumugi.Domain.Documents.NumberText|100%|97.6%| |Tsumugi.Domain.Documents.NumberValue|100%|| |Tsumugi.Domain.Documents.StoryImage|100%|| |Tsumugi.Domain.Documents.TextValue|100%|100%| |Tsumugi.Domain.Documents.ValueChange|100%|| |Tsumugi.Domain.Documents.ValueChangeKey|100%|| |Tsumugi.Domain.Documents.ValueImpact|100%|100%| |Tsumugi.Domain.Journal.ChangeLogEntry|97.9%|83.3%| |Tsumugi.Domain.Journal.StorySnapshot|95.4%|83.3%| |Tsumugi.Domain.Settings.AppSetting|100%|| |Tsumugi.Domain.Stories.Chapter|100%|100%| |Tsumugi.Domain.Stories.InlineMarkup|100%|100%| |Tsumugi.Domain.Stories.MarkupRun|100%|| |Tsumugi.Domain.Stories.Provenance|100%|100%| |Tsumugi.Domain.Stories.Segment|100%|100%| |Tsumugi.Domain.Stories.Story|100%|100%| |Tsumugi.Domain.Text|100%|100%| </details> <details><summary>Tsumugi.Infrastructure - 98.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**98.3%**|**86.7%**| |System.Text.RegularExpressions.Generated|81.4%|64.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C<br/>A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0|84%|65.7%| |Tsumugi.Infrastructure.Backups.BackupArtifactName|100%|100%| |Tsumugi.Infrastructure.Backups.BackupOptions|100%|| |Tsumugi.Infrastructure.Backups.BackupSchedule|100%|83.3%| |Tsumugi.Infrastructure.Backups.BackupScheduler|96.6%|87.5%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.5%|92.8%| |Tsumugi.Infrastructure.Backups.DatabaseFingerprint|91.9%|97%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.OwnerOnlyFile|100%|100%| |Tsumugi.Infrastructure.Backups.PreMigrationBackup|90%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|88.2%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.3%|86.6%| |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.JournalUndoState|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkup|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.SegmentTextMarkupSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.StoryImages|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |Tsumugi.Infrastructure.Persistence.SqliteFunctions|80%|66.6%| |Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore|98.3%|75%| |Tsumugi.Infrastructure.Persistence.Stores.EfImageStore|100%|| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|96.6%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.7%|90%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|97.7%|96.6%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|100%|| |Tsumugi.Infrastructure.Provider.LlmDefaultsSource|100%|| |Tsumugi.Infrastructure.Provider.OpenRouterKeySource|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterModelProvider|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterOptions|100%|100%| |Tsumugi.Infrastructure.Provider.ResolvedKey|100%|| |Tsumugi.Infrastructure.Runs.InProcessRunEventBus|100%|100%| |Tsumugi.Infrastructure.Settings.EfAppSettingsStore|100%|100%| </details> <details><summary>Tsumugi.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Kernel**|**90.9%**|**75%**| |Tsumugi.Kernel.Err`1|100%|| |Tsumugi.Kernel.Ok`1|100%|| |Tsumugi.Kernel.Result`1|88.8%|75%| </details> <details><summary>Tsumugi.Server - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Server**|**100%**|**92.1%**| |Program|100%|100%| |Tsumugi.Server.Backups.BackupConfiguration|100%|100%| |Tsumugi.Server.Components.App|100%|| |Tsumugi.Server.Components.Layout.AppHeader|100%|50%| |Tsumugi.Server.Components.Layout.MainLayout|100%|| |Tsumugi.Server.Components.Pages.Gate|100%|100%| |Tsumugi.Server.Provider.OpenRouterConfiguration|100%|100%| |Tsumugi.Server.Security.AccessGate|100%|87.5%| |Tsumugi.Server.Security.AccessSecret|100%|100%| |Tsumugi.Server.Security.GateThrottle|100%|100%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.5%**|**95.7%**| |Tsumugi.UseCases.Backups.BackupArtifact|100%|| |Tsumugi.UseCases.Backups.BackupFailure|100%|| |Tsumugi.UseCases.Backups.BackupJobState|100%|| |Tsumugi.UseCases.Backups.BackupPolicy|100%|| |Tsumugi.UseCases.Backups.BackupStatusView|100%|100%| |Tsumugi.UseCases.Backups.DatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.GetBackupStatus|100%|| |Tsumugi.UseCases.Backups.IBackupStore|0%|| |Tsumugi.UseCases.Backups.RunBackupNow|100%|| |Tsumugi.UseCases.Chapters.ChapterDto|100%|| |Tsumugi.UseCases.Chapters.CreateChapter|100%|100%| |Tsumugi.UseCases.Chapters.DeleteChapter|100%|100%| |Tsumugi.UseCases.Chapters.GetChapterSegments|100%|| |Tsumugi.UseCases.Chapters.GetManuscript|100%|100%| |Tsumugi.UseCases.Chapters.ManuscriptChapter|100%|| |Tsumugi.UseCases.Chapters.ManuscriptView|100%|| |Tsumugi.UseCases.Chapters.MergeChapters|100%|100%| |Tsumugi.UseCases.Chapters.RenameChapter|100%|100%| |Tsumugi.UseCases.Chapters.ReorderChapters|100%|100%| |Tsumugi.UseCases.Chapters.SetChapterSummary|100%|75%| |Tsumugi.UseCases.Context.DocumentRendering|100%|100%| |Tsumugi.UseCases.Context.StoryDocumentsRule|100%|100%| |Tsumugi.UseCases.Context.StoryReads|100%|100%| |Tsumugi.UseCases.Context.StoryScope|100%|100%| |Tsumugi.UseCases.Context.StoryTemplateModel|100%|| |Tsumugi.UseCases.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|98.3%|68.7%| |Tsumugi.UseCases.Diagnostics.SeedPictures|100%|| |Tsumugi.UseCases.Documents.ChangeCategoryFields|100%|83.3%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DefaultFields|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|94.4%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentPatch|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.DocumentWrites|100%|100%| |Tsumugi.UseCases.Documents.FieldsChangeLabel|95.4%|88.2%| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.GetStoryImage|100%|100%| |Tsumugi.UseCases.Documents.ImpactPreview|100%|100%| |Tsumugi.UseCases.Documents.LossMessages|92.3%|87.5%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.SetDocumentImage|100%|93.7%| |Tsumugi.UseCases.Documents.StoryImageFile|100%|| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|81.2%| |Tsumugi.UseCases.Documents.WriteRefusedException|100%|| |Tsumugi.UseCases.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! The third follow-up from my #56 review, and you chased it all the way down to the store's silent no-op~ EfUndoStore.ApplyAsync shrugs when FindAsync returns null, yet ReplayAsync stamps the row redone anyway — a redo that lands on nothing and lies about it. And your fix refuses up front, in TargetAsync itself, so the button and the key can never disagree. That's the elegant cut. I got genuinely giddy tracing it ♪

Verdict: ✅ Looks good to me~

Everything verified mechanically on a pristine clone at d9448c6 (base 817465f = merge-base, clean stack on #56's merge):

  • The seam is right. GetUndoStatus reads RedoTyping.TargetAsync directly (GetUndoStatus.cs:9) — CanRedo and Ctrl+Y share one code path by construction, so the status can never offer a redo it would refuse. A store-level refusal would have left the button lying; you put the truth where both readers look. Fufu~ wonderful~
  • The predicate is exactly the domain invariant. "An entity has one create; undoing it removed the entity, and undoing a delete brought it back" — Create && IsUndone OR Delete && !IsUndone, mirror-identical in EfChangeJournal and the adapter's FakeChangeJournal. Both implementers of IChangeJournal updated; no third implementer exists (swept).
  • The entity set is the replayed rows', not the operation's. Cleared rows are excluded (a gone entity under a cleared row doesn't cost the rest its redo), and the operation's own creates are excluded (their creates are undone until the redo runs — refusing on them would refuse everything). The EntityId index the query leans on exists (ChangeLogEntryConfiguration.cs:36).
  • My 4 probes, all killed on their own pins, each restored pristine (git diff --quiet after every one):
    1. Check removed entirely → exactly 4 red: both route-1 arms, route 2, pre-upgrade. Matches your table.
    2. Entities taken from the whole operation incl. cleared rows (your survivor m4) → exactly 1 red, the cleared-row test.
    3. Create arm ignores IsUndone → 15 red across the journal suites — decisively dead.
    4. Fake's AnyRemovedAsync forced true → exactly 5 adapter reds, digit-exact your "accepted for a fake" note; restored → 415/415.
  • Suites, digit-exact vs your body: Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486. Release build 0 warnings / 0 errors.
  • ADR 0022 amendment carries its own Status line, the #56 line untouched, and the second commit resolves the PR number to #58 — no zombie "PR #TBD" left behind ♪
  • Follow-ups honestly disclosed, both real (I read the RedoRevert/RedoRun arms — they still replay onto missing entities), both correctly out of this PR's brief, each with its own amendment path. That's how scope discipline looks.

One environment note for the record, so nobody chases a ghost: my first test pass built with -p:SkipModuleBuild=true and 4 AppChromeTests static-web-asset tests went red — that skip starves the fingerprinted JS/CSS endpoints the test asserts on, and a full build turned them green. My artifact, not yours.

✅ What I liked~

  • The two routes you found to the same lie (forced-revert cut-out polish, delete-redone-above-edit) — and the pre-upgrade UndoState IS NULL walk proving stateless rows count like any other undone create. History knowledge like that makes me flutter~
  • Probe discipline that survived MY probes. Nothing in that mutation table is decorative.
  • "Nothing to redo." — an honest refusal instead of a silent success. If more code loved the truth like this, I'd be out of a job~ fufu ♡

Automated review by Jibril · 2026-09-26
CI/CD: absent for head d9448c6 (PR minutes old, no bot comment yet) · Local checks: Release 0w/0e; Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486; 4 mutation probes killed + restored pristine

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! The third follow-up from my #56 review, and you chased it all the way down to the store's silent no-op~ `EfUndoStore.ApplyAsync` shrugs when `FindAsync` returns null, yet `ReplayAsync` stamps the row redone anyway — a redo that lands on nothing and lies about it. And your fix refuses *up front*, in `TargetAsync` itself, so the button and the key can never disagree. That's the elegant cut. I got genuinely giddy tracing it ♪ ### Verdict: ✅ Looks good to me~ Everything verified mechanically on a pristine clone at `d9448c6` (base `817465f` = merge-base, clean stack on #56's merge): - **The seam is right.** `GetUndoStatus` reads `RedoTyping.TargetAsync` directly (GetUndoStatus.cs:9) — CanRedo and Ctrl+Y share one code path by construction, so the status can never offer a redo it would refuse. A store-level refusal would have left the button lying; you put the truth where both readers look. Fufu~ wonderful~ - **The predicate is exactly the domain invariant.** "An entity has one create; undoing it removed the entity, and undoing a delete brought it back" — `Create && IsUndone` OR `Delete && !IsUndone`, mirror-identical in `EfChangeJournal` and the adapter's `FakeChangeJournal`. Both implementers of `IChangeJournal` updated; no third implementer exists (swept). - **The entity set is the replayed rows', not the operation's.** Cleared rows are excluded (a gone entity under a cleared row doesn't cost the rest its redo), and the operation's own creates are excluded (their creates are undone until the redo runs — refusing on them would refuse everything). The `EntityId` index the query leans on exists (ChangeLogEntryConfiguration.cs:36). - **My 4 probes, all killed on their own pins, each restored pristine** (`git diff --quiet` after every one): 1. Check removed entirely → exactly 4 red: both route-1 arms, route 2, pre-upgrade. Matches your table. 2. Entities taken from the whole operation incl. cleared rows (your survivor m4) → exactly 1 red, the cleared-row test. 3. Create arm ignores `IsUndone` → 15 red across the journal suites — decisively dead. 4. Fake's `AnyRemovedAsync` forced true → exactly 5 adapter reds, digit-exact your "accepted for a fake" note; restored → 415/415. - **Suites, digit-exact vs your body:** Integration **535/535**, BlazorAdapter **415/415**, UseCases **236/236**, Domain **486/486**. Release build 0 warnings / 0 errors. - **ADR 0022 amendment** carries its own Status line, the #56 line untouched, and the second commit resolves the PR number to #58 — no zombie "PR #TBD" left behind ♪ - **Follow-ups honestly disclosed**, both real (I read the `RedoRevert`/`RedoRun` arms — they still replay onto missing entities), both correctly out of this PR's brief, each with its own amendment path. That's how scope discipline looks. One environment note for the record, so nobody chases a ghost: my first test pass built with `-p:SkipModuleBuild=true` and 4 `AppChromeTests` static-web-asset tests went red — that skip starves the fingerprinted JS/CSS endpoints the test asserts on, and a full build turned them green. My artifact, not yours. #### ✅ What I liked~ - The two routes you found to the same lie (forced-revert cut-out polish, delete-redone-above-edit) — and the pre-upgrade `UndoState IS NULL` walk proving stateless rows count like any other undone create. History knowledge like that makes me flutter~ - Probe discipline that survived MY probes. Nothing in that mutation table is decorative. - "Nothing to redo." — an honest refusal instead of a silent success. If more code loved the truth like this, I'd be out of a job~ fufu ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head d9448c6 (PR minutes old, no bot comment yet) · Local checks: Release 0w/0e; Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486; 4 mutation probes killed + restored pristine*
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A redo onto nothing — the journal's version of a trapdoor~ The moment I saw ApplyAsync silently no-op on a missing entity while ReplayAsync still stamped MarkActive() on the row, my wings twitched. Marking something redone that changed nothing... that's not redo, that's lying to the journal. And this PR makes Ctrl+Y refuse to tell that lie. Wonderful~ ♡

Verdict: ✅ Looks good to me~

I traced both routes to ground before touching anything. Route one (forced revert cuts the run's create out from under the polish, Ctrl+Z takes back the later paragraph — polish becomes the candidate above a stepped-over CutOut create): TargetAsync finds it, found = the run's paragraph, the undone create trips the gate, "Nothing to redo.", row stays (true, CutOut). Route two (Redo run re-deletes the paragraph the edit waits on): the standing run-origin delete trips the delete arm — correctly so, since the arm deliberately ignores origin, and only the journal knows the entity is gone. And the pre-upgrade route: UndoState IS NULL create still counts via bare IsUndone — the migration test walks the rows down and back up to prove it on real NULLs, not a hand-seeded imitation. Mmm, delicious~

The placement is the clever part, fufu~ TargetAsync is what GetUndoStatus reads too, so the button greys out exactly when the key would refuse — a store-level refusal would leave a button that fails on every press. Button and key cannot disagree by construction. ♪

Locally (CI absent for d9448c6, PR minutes old; isolated clone tsumugi-pr58-jibril-r2, submodules Kagaku.UI 6af0979 + OpenRouter.Net b002f5e): Release 0w/0e; Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486 — all four digit-exact against the body. Journal filter 49/49. (My first Integration run failed 4 AppChromeTests web-asset checks — my own artifact from building with -p:SkipModuleBuild=true; a full build erases them. Not the PR's.)

My 7 mutation probes, each compiled, killed on exactly the pins the body names, each restored pristine (git diff --quiet at d9448c6):

Mutation Result
Gate removed (pre-PR behavior) Killed by both routes (3 cases) + pre-upgrade test; the cleared-row test correctly stays green — it pins the gate's restraint
Created-entity exclusion removed Killed by the Redo-run arm + FieldJournalTests.A_new_operation_clears…(history: False) — the body's exact pin
m4: found from the whole operation, cleared rows included Killed by exactly the cleared-row test
m10: create arm counts only CutOut creates Killed by exactly the pre-upgrade test
Create arm ignores IsUndone 15 journal tests red
Delete arm ignores IsUndone Exactly the second route red
Empty-list guard > 0 → > 1 4 tests red

The follow-up section is honest, too — I confirmed the store's silent no-op is the shared root, and RedoRun/RedoRevert keeping their behavior is a brief-scoped decision each needing its own ADR amendment, not smuggled scope. ♡

✅ What I liked~

  • AnyRemovedAsync is one Any over the indexed EntityId (ChangeLogEntryConfiguration.cs:32), skipped entirely when the list is empty — the refusal costs one query only when it can matter.
  • EfChangeJournal and the adapter's FakeChangeJournal are character-for-character the same predicate — the fake mirrors, not diverges.
  • ADR 0022 gets its own Status line with the real PR number at head (no #TBD residue — I checked d9448c6 itself), and the #56 line stays untouched.
  • The m4/m10 survivor pins are directional: each mutant turns exactly one test red, so the suite isn't just loud, it's precise.

Fufu~ the journal keeps its honesty, the writer's polish waits patiently for its paragraph to come back... nothing marked redone over nothing. Ready to merge~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: absent for head SHA · Local checks: Release 0w/0e · 4 suites digit-exact (535/535, 415/415, 236/236, 486/486) · 7 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A redo onto *nothing* — the journal's version of a trapdoor~ The moment I saw `ApplyAsync` silently no-op on a missing entity while `ReplayAsync` still stamped `MarkActive()` on the row, my wings twitched. Marking something redone that changed nothing... that's not redo, that's *lying to the journal*. And this PR makes Ctrl+Y refuse to tell that lie. Wonderful~ ♡ ### Verdict: ✅ Looks good to me~ I traced both routes to ground before touching anything. Route one (forced revert cuts the run's create out from under the polish, Ctrl+Z takes back the later paragraph — polish becomes the candidate above a stepped-over CutOut create): `TargetAsync` finds it, `found` = the run's paragraph, the undone create trips the gate, "Nothing to redo.", row stays `(true, CutOut)`. Route two (Redo run re-deletes the paragraph the edit waits on): the *standing* run-origin delete trips the delete arm — correctly so, since the arm deliberately ignores origin, and only the journal knows the entity is gone. And the pre-upgrade route: `UndoState IS NULL` create still counts via bare `IsUndone` — the migration test walks the rows down and back up to prove it on real NULLs, not a hand-seeded imitation. Mmm, delicious~ The placement is the clever part, fufu~ `TargetAsync` is what `GetUndoStatus` reads too, so the button greys out exactly when the key would refuse — a store-level refusal would leave a button that fails on every press. Button and key cannot disagree *by construction*. ♪ **Locally** (CI absent for `d9448c6`, PR minutes old; isolated clone `tsumugi-pr58-jibril-r2`, submodules Kagaku.UI `6af0979` + OpenRouter.Net `b002f5e`): Release 0w/0e; Integration 535/535, BlazorAdapter 415/415, UseCases 236/236, Domain 486/486 — all four digit-exact against the body. Journal filter 49/49. (My first Integration run failed 4 `AppChromeTests` web-asset checks — my own artifact from building with `-p:SkipModuleBuild=true`; a full build erases them. Not the PR's.) **My 7 mutation probes**, each compiled, killed on exactly the pins the body names, each restored pristine (`git diff --quiet` at `d9448c6`): | Mutation | Result | |---|---| | Gate removed (pre-PR behavior) | Killed by both routes (3 cases) + pre-upgrade test; the cleared-row test correctly stays green — it pins the gate's *restraint* | | Created-entity exclusion removed | Killed by the Redo-run arm + `FieldJournalTests.A_new_operation_clears…(history: False)` — the body's exact pin | | m4: `found` from the whole operation, cleared rows included | Killed by exactly the cleared-row test | | m10: create arm counts only `CutOut` creates | Killed by exactly the pre-upgrade test | | Create arm ignores `IsUndone` | 15 journal tests red | | Delete arm ignores `IsUndone` | Exactly the second route red | | Empty-list guard `> 0` → `> 1` | 4 tests red | The follow-up section is honest, too — I confirmed the store's silent no-op is the shared root, and `RedoRun`/`RedoRevert` keeping their behavior is a brief-scoped decision each needing its own ADR amendment, not smuggled scope. ♡ #### ✅ What I liked~ - `AnyRemovedAsync` is one `Any` over the indexed `EntityId` (`ChangeLogEntryConfiguration.cs:32`), skipped entirely when the list is empty — the refusal costs one query only when it can matter. - `EfChangeJournal` and the adapter's `FakeChangeJournal` are character-for-character the same predicate — the fake mirrors, not diverges. - ADR 0022 gets its own Status line with the real PR number at head (no `#TBD` residue — I checked `d9448c6` itself), and the #56 line stays untouched. - The m4/m10 survivor pins are *directional*: each mutant turns exactly one test red, so the suite isn't just loud, it's *precise*. Fufu~ the journal keeps its honesty, the writer's polish waits patiently for its paragraph to come back... nothing marked redone over nothing. Ready to merge~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head SHA · Local checks: Release 0w/0e · 4 suites digit-exact (535/535, 415/415, 236/236, 486/486) · 7 mutation probes killed*
bjoern merged commit 95a207bad1 into main 2026-09-26 18:32:09 +02:00
bjoern deleted branch fix/redo-missing-entity 2026-09-26 18:32:09 +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!58
No description provided.