feat(manuscript): the selection menu's plumbing (M5a) — inert until the graph library offers a selection graph #59

Merged
bjoern merged 4 commits from feat/selection-menu into main 2026-09-26 19:07:11 +02:00
Member

The right-click menu that ADR 0030 and ADR 0023 describe, built ahead of its graphs so Phase 3's selection runs (Expand, Rewrite, Continue from here) find it ready.

Nothing changes for the writer today. Until the graph library offers a selection-triggered graph, the surface is not armed: a right-click, the ContextMenu key and Shift+F10 all keep the browser's menu. There are no stub entries. The menu lists real graphs by data, as the graph-is-the-product rule wants.

What is built

The editor module

  • The selection. It is sent as (paragraph, visible-text offset) ends, snapped inward off scene breaks (rangeOf). It is read after flushing ProseMirror's DOM observer. That is the one internal call the surface relies on, and it sits behind one wrapper that the browser suite pins: a selection moved in the DOM and read in the same task.
  • Opening the menu.
    • A right-click opens it at the pointer. The ContextMenu key and Shift+F10 open it at the caret on their keydown.
    • The browser's own contextmenu for a menu key is swallowed until the key comes up. Windows sends the ContextMenu key's event on its keyup, to whatever has focus, so that keyup is cancelled. A held key opens one menu.
    • These keep the browser's menu:
      • Shift+right-click, so spelling suggestions stay one gesture away. Firefox doesn't even let that click reach the page.
      • A right-click on a scene break.
      • A right-click on a paragraph the server doesn't hold, such as an empty chapter's unsaved first paragraph.
  • Before and while the menu is open. Pending typing is saved first. The selection stays painted while the menu has focus; a caret paints its whole paragraph.
  • Closing. Each menu is numbered. The module lets go of the one the host says closed, and never of a newer one. It takes focus back from the menu, the dialog or nowhere, never from a control the writer clicked into.

The host (ManuscriptSurface)

  • Arming. It arms and disarms the module as SelectionGraphs come and go, including graphs that arrive while the surface mounts.
  • Reading the selection. It reads the selection from the stored chapter, in its queue after the typing saves (ReadSelection).
  • The menu. It shows Kagaku.UI's ContextMenu at the pointer. A graph that can't run now, per the workspace story (validation errors, a run already live), is listed aria-disabled with its reason: focusable and announced, but not choosable. So the menu always takes focus and Esc closes it. A scoped rule dims it.
  • The instruction step. A one-line optional instruction, where Enter runs.
  • The request. The choice goes out as SelectionRunRequested(StoryId, ChapterId, GraphId, Selection, Instruction). Nothing handles it yet.
  • Closing. The module is told a menu closed only once the menu or dialog is gone from the page, because a modal dialog leaves the rest inert.

The selection input (SelectionInput.Read)

  • What a run will receive: the range, the covered segments with their stored text, the selected text, and the text before and after the cut. Each piece is canonical markup cut through the codec's runs, with marks closed at each cut.
  • Paragraphs are joined by a blank line, and a scene break shows as ***, as ModelOutput reads a model's own output.
  • A caret stands for its paragraph.
  • An offset into trimmed trailing whitespace is held to the text's end. A caret is decided before that, so a stretch of whitespace comes out empty, not as the whole paragraph.
  • It refuses: a paragraph that is gone, a scene-break end, a negative or reversed offset, and an end inside a character.

Left for M5b (Phase 3)

  • Feed the graph library's selection graphs into SelectionGraphs. It is one parameter on the chapter page.
  • Handle SelectionRunRequested by starting the run with the selection and instruction as its trigger inputs.
  • The commit replace that splices the output over the selection (ADR 0030).

The working state stays under M4 in the plan.

Proof

  • Module: typecheck; vitest 213 tests, including rangeOf's snapping.
  • Browser suite (Playwright image), all three engines: 140 passed, 7 engine skips as before. Ten menu tests run in each engine, covering:
    • unarmed and armed behaviour;
    • typing saved first;
    • the held paint;
    • the focus rule, one case per where focus went;
    • the numbering, and a late close or a late lost call of an older menu;
    • Shift+right-click;
    • both keys at the caret, with the swallow until keyup, key repeat, and the cancelled ContextMenu keyup;
    • the DOM flush;
    • a scene break, an unheld paragraph, and disarming.
  • .NET: all six projects.
    • The selection reader: 7 tests, with exact values.
    • The host menu: 10 bUnit tests. They cover arming, including during mount; the menu and instruction flow and the request's content; unavailable graphs and their scoped style anchor; dismissal and cancel; a menu over a menu; graphs leaving; refusals; and the read queued behind a save. "The module is told only after the dialog is gone" is pinned by call order.
  • Seeded app, Chromium and Firefox: M2b's pass 27/27, M3's 9/9, the hardening pass 11/11, and a new pass 5/5 showing the chapter page's right-click and keys keep the browser's menu with no selection graphs.
  • Mutation probes: every guard of the module, the host and the reader fails its own test when removed, checked on builds that succeed.

Review round 0 (before opening)

A three-way review with adversarial verification found the focus, key, unavailable-graph, numbering, scene-break and selection-reader issues. All are fixed above, each with a test. None was reachable before a selection graph exists.

Notes for review

  • ADR 0030 is amended: the Status line, the "Selections and the context menu" bullets, the event table row, and the Order section (M5a, M5b).
  • Plan: M5 is now M5a (this PR) and M5b.
  • Manual matrix: row 9 covers the armed and unarmed keys, including Windows' keyup.

🤖 Generated with Claude Code

The right-click menu that ADR 0030 and ADR 0023 describe, built ahead of its graphs so Phase 3's selection runs (Expand, Rewrite, Continue from here) find it ready. **Nothing changes for the writer today.** Until the graph library offers a selection-triggered graph, the surface is not armed: a right-click, the ContextMenu key and Shift+F10 all keep the browser's menu. There are no stub entries. The menu lists real graphs by data, as the graph-is-the-product rule wants. ## What is built **The editor module** - **The selection.** It is sent as (paragraph, visible-text offset) ends, snapped inward off scene breaks (`rangeOf`). It is read after flushing ProseMirror's DOM observer. That is the one internal call the surface relies on, and it sits behind one wrapper that the browser suite pins: a selection moved in the DOM and read in the same task. - **Opening the menu.** - A right-click opens it at the pointer. The ContextMenu key and Shift+F10 open it at the caret on their keydown. - The browser's own `contextmenu` for a menu key is swallowed until the key comes up. Windows sends the ContextMenu key's event on its keyup, to whatever has focus, so that keyup is cancelled. A held key opens one menu. - These keep the browser's menu: - Shift+right-click, so spelling suggestions stay one gesture away. Firefox doesn't even let that click reach the page. - A right-click on a scene break. - A right-click on a paragraph the server doesn't hold, such as an empty chapter's unsaved first paragraph. - **Before and while the menu is open.** Pending typing is saved first. The selection stays painted while the menu has focus; a caret paints its whole paragraph. - **Closing.** Each menu is numbered. The module lets go of the one the host says closed, and never of a newer one. It takes focus back from the menu, the dialog or nowhere, never from a control the writer clicked into. **The host (`ManuscriptSurface`)** - **Arming.** It arms and disarms the module as `SelectionGraphs` come and go, including graphs that arrive while the surface mounts. - **Reading the selection.** It reads the selection from the stored chapter, in its queue after the typing saves (`ReadSelection`). - **The menu.** It shows Kagaku.UI's `ContextMenu` at the pointer. A graph that can't run now, per the workspace story (validation errors, a run already live), is listed `aria-disabled` with its reason: focusable and announced, but not choosable. So the menu always takes focus and Esc closes it. A scoped rule dims it. - **The instruction step.** A one-line optional instruction, where Enter runs. - **The request.** The choice goes out as `SelectionRunRequested(StoryId, ChapterId, GraphId, Selection, Instruction)`. Nothing handles it yet. - **Closing.** The module is told a menu closed only once the menu or dialog is gone from the page, because a modal dialog leaves the rest inert. **The selection input (`SelectionInput.Read`)** - What a run will receive: the range, the covered segments with their stored text, the selected text, and the text before and after the cut. Each piece is canonical markup cut through the codec's runs, with marks closed at each cut. - Paragraphs are joined by a blank line, and a scene break shows as `***`, as `ModelOutput` reads a model's own output. - A caret stands for its paragraph. - An offset into trimmed trailing whitespace is held to the text's end. A caret is decided before that, so a stretch of whitespace comes out empty, not as the whole paragraph. - It refuses: a paragraph that is gone, a scene-break end, a negative or reversed offset, and an end inside a character. ## Left for M5b (Phase 3) - Feed the graph library's selection graphs into `SelectionGraphs`. It is one parameter on the chapter page. - Handle `SelectionRunRequested` by starting the run with the selection and instruction as its trigger inputs. - The `commit` replace that splices the output over the selection (ADR 0030). The working state stays under M4 in the plan. ## Proof - **Module:** typecheck; vitest 213 tests, including `rangeOf`'s snapping. - **Browser suite** (Playwright image), all three engines: 140 passed, 7 engine skips as before. Ten menu tests run in each engine, covering: - unarmed and armed behaviour; - typing saved first; - the held paint; - the focus rule, one case per where focus went; - the numbering, and a late close or a late lost call of an older menu; - Shift+right-click; - both keys at the caret, with the swallow until keyup, key repeat, and the cancelled ContextMenu keyup; - the DOM flush; - a scene break, an unheld paragraph, and disarming. - **.NET:** all six projects. - The selection reader: 7 tests, with exact values. - The host menu: 10 bUnit tests. They cover arming, including during mount; the menu and instruction flow and the request's content; unavailable graphs and their scoped style anchor; dismissal and cancel; a menu over a menu; graphs leaving; refusals; and the read queued behind a save. "The module is told only after the dialog is gone" is pinned by call order. - **Seeded app, Chromium and Firefox:** M2b's pass 27/27, M3's 9/9, the hardening pass 11/11, and a new pass 5/5 showing the chapter page's right-click and keys keep the browser's menu with no selection graphs. - **Mutation probes:** every guard of the module, the host and the reader fails its own test when removed, checked on builds that succeed. ## Review round 0 (before opening) A three-way review with adversarial verification found the focus, key, unavailable-graph, numbering, scene-break and selection-reader issues. All are fixed above, each with a test. None was reachable before a selection graph exists. ## Notes for review - **ADR 0030** is amended: the Status line, the "Selections and the context menu" bullets, the event table row, and the Order section (M5a, M5b). - **Plan:** M5 is now M5a (this PR) and M5b. - **Manual matrix:** row 9 covers the armed and unarmed keys, including Windows' keyup. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The right-click menu ADR 0030 and 0023 describe, built ahead of its graphs so the selection runs of
Phase 3 find it ready. Until the library offers a selection-triggered graph, the surface is not armed
and a right-click, the ContextMenu key and Shift+F10 keep the browser's menu — no stub entries.

- Module: the selection as visible-text ends, snapped inward off scene breaks (`rangeOf`), read after
  flushing the view's DOM observer (the one ProseMirror internal the surface relies on, behind one
  wrapper the browser suite pins); the right-click and the keys at the caret, Shift+right-click kept
  native, the key's own contextmenu event swallowed; pending typing saved first; the held selection
  painted while the menu has focus, let go when it closes or the call is lost.
- Host: armed and disarmed as graphs come and go; the selection read in the queue after the saves
  (`ReadSelection`, pieces of canonical markup cut through the codec, a caret widened to its paragraph);
  Kagaku.UI's ContextMenu at the pointer, a graph that cannot run disabled with its reason, the
  instruction step, and the choice dispatched as `SelectionRunRequested` — for the runs to start.
- ADR 0030, the plan (M5a, M5b) and the manual matrix's keyboard row say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
fix(manuscript): review round 0 — focus, keys and unavailable graphs in the selection menu
Some checks failed
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
a3ad02f23a
The review found and reproduced these, none reachable before a selection graph exists:
- Focus: the host told the module the menu closed while the instruction dialog still made the page
  inert, so focus fell to the body; and the module took focus back from a control the writer had
  clicked into. The host now tells it once the menu or dialog is gone from the page, and the module
  takes focus back only from the menu, the dialog or nowhere.
- Keys: Windows sends the ContextMenu key's own contextmenu on its keyup, to the focused menu item, past
  the view's swallow; that keyup is now cancelled. The swallow ends when the key comes up — it outlived
  a handled keydown on Linux and ate a later menu the surface declined — and a held key opens one menu.
- Every graph unavailable left a menu with no focus that Esc could not close: an unavailable graph is
  now aria-disabled — focusable, announced, not choosable — dimmed by the surface's own scoped rule.
- Menus are numbered, so the late close of one the writer left for another lets go of nothing.
- A right-click on a scene break (selected only after the click) or on a paragraph the server does not
  hold keeps the browser's menu; the keys place the menu after the DOM flush; a caret is told from a
  stretch before the offsets are held to the stored text; the instruction is one line, Enter running it.
- Tests pin each; the menu's JS fakes are shared by the page's suites. ADR 0030 and the matrix say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bjoern referenced this pull request from a commit 2026-09-26 18:23:27 +02:00
docs: the selection menu's PR is #59
Some checks failed
CI / build (pull_request) Successful in 39s
CI / test (pull_request) Successful in 1m37s
CI / editor-browsers (pull_request) Failing after 1m7s
6db832c445
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: db9956a · Generated: 2026-09-26 16:55:34 UTC · Revision: #2

Summary

Summary
Generated on: 09/26/2026 - 16:55:34
Coverage date: 09/26/2026 - 16:54:59 - 09/26/2026 - 16:55:28
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 504
Files: 453
Line coverage: 98.1% (15862 of 16168)
Covered lines: 15862
Uncovered lines: 306
Coverable lines: 16168
Total lines: 34454
Branch coverage: 94.2% (6055 of 6424)
Covered branches: 6055
Total branches: 6424
Method coverage: Feature is only available for sponsors

Coverage

Kagaku.Flow - 99.7%
Name Line Branch
Kagaku.Flow 99.7% 99.2%
Kagaku.Flow.Budgeting.BudgetRequest 100%
Kagaku.Flow.Budgeting.ConsumerBudget 100%
Kagaku.Flow.Execution.NodeExecution 100% 100%
Kagaku.Flow.Execution.NodeOutcome 100% 100%
Kagaku.Flow.Execution.TransientFailureException 100%
Kagaku.Flow.Execution.Upstream 100%
Kagaku.Flow.Extensions.ServiceCollectionExtensions 100%
Kagaku.Flow.FlowJson 100%
Kagaku.Flow.Graphs.GraphDefinition 100%
Kagaku.Flow.Graphs.GraphDocument 100% 100%
Kagaku.Flow.Graphs.GraphEdge 100%
Kagaku.Flow.Graphs.GraphIndex 100% 100%
Kagaku.Flow.Graphs.GraphLoadError 100%
Kagaku.Flow.Graphs.GraphLoadResult 100%
Kagaku.Flow.Graphs.GraphNode 100%
Kagaku.Flow.Graphs.GraphPosition 100%
Kagaku.Flow.Graphs.GraphReader 100% 100%
Kagaku.Flow.Graphs.GraphSchema 100% 100%
Kagaku.Flow.Graphs.GraphShapeException 100%
Kagaku.Flow.Graphs.GraphWriter 100% 100%
Kagaku.Flow.Graphs.SocketRef 100%
Kagaku.Flow.Graphs.WireText 100% 100%
Kagaku.Flow.Nodes.CanvasDescriptorWriter 100% 100%
Kagaku.Flow.Nodes.ConfigProblem 100%
Kagaku.Flow.Nodes.Names 100%
Kagaku.Flow.Nodes.NodeDescriptor 100% 100%
Kagaku.Flow.Nodes.NodeRegistry 100% 100%
Kagaku.Flow.Nodes.NodeSockets 100% 100%
Kagaku.Flow.Nodes.SinkDescriptor 100%
Kagaku.Flow.Nodes.SocketTypes 100% 100%
Kagaku.Flow.Nodes.SourceDescriptor 100%
Kagaku.Flow.Nodes.TemplateField 100%
Kagaku.Flow.Runs.LedgerChange 100% 100%
Kagaku.Flow.Runs.LedgerTransitions 100% 100%
Kagaku.Flow.Runs.NodeAttempt 100%
Kagaku.Flow.Runs.NodeFacts 100%
Kagaku.Flow.Runs.NodeRun 100%
Kagaku.Flow.Runs.Run 100% 100%
Kagaku.Flow.Runs.RunEvent 100%
Kagaku.Flow.Runs.RunStatuses 100% 100%
Kagaku.Flow.Runs.RunTrigger 100% 100%
Kagaku.Flow.Scheduling.Exclusion 100%
Kagaku.Flow.Scheduling.FlowEngine 100% 100%
Kagaku.Flow.Scheduling.FlowEngineOptions 100% 100%
Kagaku.Flow.Scheduling.ReadyRow 100%
Kagaku.Flow.Scheduling.ReadySet 100% 100%
Kagaku.Flow.Scheduling.ReadySetResult 100%
Kagaku.Flow.Scheduling.RunRequest 100% 100%
Kagaku.Flow.Scheduling.RunStartResult 100%
Kagaku.Flow.Scheduling.SocketValues 100% 100%
Kagaku.Flow.Templating.InputsWalker 100% 100%
Kagaku.Flow.Templating.ParsedTemplate 100% 100%
Kagaku.Flow.Templating.SandboxedTemplateContext 100% 100%
Kagaku.Flow.Templating.TemplateError 100%
Kagaku.Flow.Templating.TemplateHost 100% 100%
Kagaku.Flow.Templating.TemplateLimits 100%
Kagaku.Flow.Templating.TemplateModel 100% 100%
Kagaku.Flow.Templating.TemplateProblem 100%
Kagaku.Flow.Templating.TemplateRenderRequest 100% 100%
Kagaku.Flow.Templating.TemplateRenderResult 100%
Kagaku.Flow.Templating.TemplateRun 100%
Kagaku.Flow.Templating.TemplateSinks 100%
Kagaku.Flow.Templating.TemplateValues 100% 100%
Kagaku.Flow.Validation.GraphValidation 100% 100%
Kagaku.Flow.Validation.GraphValidationContext 100%
Kagaku.Flow.Validation.HookFailure 100%
Kagaku.Flow.Validation.ResolvedGraph 100% 100%
Kagaku.Flow.Validation.ValidationError 100%
Kagaku.Flow.Validation.ValidationReport 100%
System.Text.RegularExpressions.Generated 97.4% 92.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2
97.4% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1
97.2% 94.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF
E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0
97.2% 94.4%
Kagaku.Flow.OpenRouter - 100%
Name Line Branch
Kagaku.Flow.OpenRouter 100% 100%
Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities 100% 100%
Kagaku.Flow.OpenRouter.Gateway.LlmCompletion 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway 100% 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture 100% 100%
Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmAnswer 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfig 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmConfigRead 100%
Kagaku.Flow.OpenRouter.Llm.LlmDescriptor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmExecutor 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFacts 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmFailureText 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmMessage 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan 100%
Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmSampling 100%
Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule 100% 100%
Kagaku.Flow.OpenRouter.Llm.LlmVocabulary 100% 100%
Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions 100%
Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions 100% 100%
Kagaku.Flow.Testing - 100%
Name Line Branch
Kagaku.Flow.Testing 100% 100%
Kagaku.Flow.Testing.FlowEngineDriver 100% 100%
Kagaku.Flow.Testing.InMemoryRunLedger 100% 100%
Kagaku.Flow.Testing.RecordingRunEventSink 100%
Kagaku.Flow.Testing.RunLedgerContract 100% 100%
Kagaku.Flow.Testing.RunLedgerContractException 100%
Tsumugi.BlazorAdapter - 95.8%
Name Line Branch
Tsumugi.BlazorAdapter 95.8% 91.1%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 93.2% 88.4%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 94.1%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 95.7% 89.4%
Tsumugi.BlazorAdapter.Documents.DocumentImageRefused 100%
Tsumugi.BlazorAdapter.Documents.DocumentImageSet 100%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.5% 95%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsRefusal 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldInput 100% 96.6%
Tsumugi.BlazorAdapter.Documents.FieldsChanges 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldShapes 90% 87.5%
Tsumugi.BlazorAdapter.Documents.ImageUpload 100%
Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal 100%
Tsumugi.BlazorAdapter.Documents.ImpactText 100% 94.2%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog 95.6% 71.4%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter 100%
Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested 100%
Tsumugi.BlazorAdapter.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% 87.5%
Tsumugi.BlazorAdapter.Workspace.ChapterSaved 100%
Tsumugi.BlazorAdapter.Workspace.ChaptersPage 94.4% 83.3%
Tsumugi.BlazorAdapter.Workspace.ChapterWire 100%
Tsumugi.BlazorAdapter.Workspace.ChapterWritten 100%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.CreatedWire 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeltaWire 100%
Tsumugi.BlazorAdapter.Workspace.HistoryEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.HistoryLoaded 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPage 100%
Tsumugi.BlazorAdapter.Workspace.HistoryPanel 100% 100%
Tsumugi.BlazorAdapter.Workspace.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents 81.8% 74.1%
Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface 89.8% 87.1%
Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.MergeEvent 100%
Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested 100%
Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.ReshapeEvent 100%
Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested 100%
Tsumugi.BlazorAdapter.Workspace.SaveScope 100% 50%
Tsumugi.BlazorAdapter.Workspace.SaveStateLadder 100% 100%
Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested 100%
Tsumugi.BlazorAdapter.Workspace.SegmentTextEvent 100%
Tsumugi.BlazorAdapter.Workspace.SegmentWire 100% 81.8%
Tsumugi.BlazorAdapter.Workspace.SelectionEndWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionGraph 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire 100%
Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested 100%
Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested 100%
Tsumugi.BlazorAdapter.Workspace.SplitEvent 100%
Tsumugi.BlazorAdapter.Workspace.StampWire 0%
Tsumugi.BlazorAdapter.Workspace.StoryDetails 100% 85.2%
Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage 100% 100%
Tsumugi.BlazorAdapter.Workspace.StorySaved 100%
Tsumugi.BlazorAdapter.Workspace.StoryShell 100% 100%
Tsumugi.BlazorAdapter.Workspace.UndoRequested 100%
Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged 100%
Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers 100% 100%
Tsumugi.BlazorAdapter.Workspace.WorkspaceState 100%
Tsumugi.Domain - 96.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.6%
Name Line Branch
Tsumugi.UseCases 98.6% 95.9%
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.ReadSelection 100%
Tsumugi.UseCases.Segments.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeSegments 100% 100%
Tsumugi.UseCases.Segments.ReshapeWrite 100%
Tsumugi.UseCases.Segments.SegmentDto 100%
Tsumugi.UseCases.Segments.SelectedSegment 100%
Tsumugi.UseCases.Segments.SelectionEnd 100%
Tsumugi.UseCases.Segments.SelectionInput 100% 100%
Tsumugi.UseCases.Segments.SplitSegment 100%
Tsumugi.UseCases.Segments.SplitWrite 100%
Tsumugi.UseCases.Segments.StampedId 100%
Tsumugi.UseCases.Segments.TextWrite 100%
Tsumugi.UseCases.Settings.CatalogModel 100% 100%
Tsumugi.UseCases.Settings.CheckOpenRouterKey 100%
Tsumugi.UseCases.Settings.GetLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.GetModelCatalog 100% 100%
Tsumugi.UseCases.Settings.GetProviderSettings 100%
Tsumugi.UseCases.Settings.LlmDefaults 100%
Tsumugi.UseCases.Settings.ProviderKeyInfo 100%
Tsumugi.UseCases.Settings.ProviderKeyState 100%
Tsumugi.UseCases.Settings.ProviderSettingsView 100% 100%
Tsumugi.UseCases.Settings.ReasoningEfforts 100% 100%
Tsumugi.UseCases.Settings.RemoveOpenRouterKey 100%
Tsumugi.UseCases.Settings.RoutingDefaults 100%
Tsumugi.UseCases.Settings.RoutingSettings 100% 100%
Tsumugi.UseCases.Settings.SaveLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.SaveOpenRouterKey 100% 100%
Tsumugi.UseCases.Stories.ChapterWriteOutcome 50%
Tsumugi.UseCases.Stories.CreateStory 100% 100%
Tsumugi.UseCases.Stories.GetStory 100% 100%
Tsumugi.UseCases.Stories.ListStories 100% 75%
Tsumugi.UseCases.Stories.PurgeStory 100% 100%
Tsumugi.UseCases.Stories.RestoreStory 100% 100%
Tsumugi.UseCases.Stories.SetActiveGraph 100% 100%
Tsumugi.UseCases.Stories.SetStoryArchived 100% 100%
Tsumugi.UseCases.Stories.StarterCategories 100%
Tsumugi.UseCases.Stories.StoryDetail 100%
Tsumugi.UseCases.Stories.StoryListItem 81.8%
Tsumugi.UseCases.Stories.StoryProfile 100%
Tsumugi.UseCases.Stories.TrashStory 100% 100%
Tsumugi.UseCases.Stories.UpdateStory 100% 100%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `db9956a` · **Generated:** 2026-09-26 16:55:34 UTC · **Revision:** #2 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/26/2026 - 16:55:34 | | Coverage date: | 09/26/2026 - 16:54:59 - 09/26/2026 - 16:55:28 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 504 | | Files: | 453 | | **Line coverage:** | 98.1% (15862 of 16168) | | Covered lines: | 15862 | | Uncovered lines: | 306 | | Coverable lines: | 16168 | | Total lines: | 34454 | | **Branch coverage:** | 94.2% (6055 of 6424) | | Covered branches: | 6055 | | Total branches: | 6424 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagaku.Flow - 99.7%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow**|**99.7%**|**99.2%**| |Kagaku.Flow.Budgeting.BudgetRequest|100%|| |Kagaku.Flow.Budgeting.ConsumerBudget|100%|| |Kagaku.Flow.Execution.NodeExecution|100%|100%| |Kagaku.Flow.Execution.NodeOutcome|100%|100%| |Kagaku.Flow.Execution.TransientFailureException|100%|| |Kagaku.Flow.Execution.Upstream|100%|| |Kagaku.Flow.Extensions.ServiceCollectionExtensions|100%|| |Kagaku.Flow.FlowJson|100%|| |Kagaku.Flow.Graphs.GraphDefinition|100%|| |Kagaku.Flow.Graphs.GraphDocument|100%|100%| |Kagaku.Flow.Graphs.GraphEdge|100%|| |Kagaku.Flow.Graphs.GraphIndex|100%|100%| |Kagaku.Flow.Graphs.GraphLoadError|100%|| |Kagaku.Flow.Graphs.GraphLoadResult|100%|| |Kagaku.Flow.Graphs.GraphNode|100%|| |Kagaku.Flow.Graphs.GraphPosition|100%|| |Kagaku.Flow.Graphs.GraphReader|100%|100%| |Kagaku.Flow.Graphs.GraphSchema|100%|100%| |Kagaku.Flow.Graphs.GraphShapeException|100%|| |Kagaku.Flow.Graphs.GraphWriter|100%|100%| |Kagaku.Flow.Graphs.SocketRef|100%|| |Kagaku.Flow.Graphs.WireText|100%|100%| |Kagaku.Flow.Nodes.CanvasDescriptorWriter|100%|100%| |Kagaku.Flow.Nodes.ConfigProblem|100%|| |Kagaku.Flow.Nodes.Names|100%|| |Kagaku.Flow.Nodes.NodeDescriptor|100%|100%| |Kagaku.Flow.Nodes.NodeRegistry|100%|100%| |Kagaku.Flow.Nodes.NodeSockets|100%|100%| |Kagaku.Flow.Nodes.SinkDescriptor|100%|| |Kagaku.Flow.Nodes.SocketTypes|100%|100%| |Kagaku.Flow.Nodes.SourceDescriptor|100%|| |Kagaku.Flow.Nodes.TemplateField|100%|| |Kagaku.Flow.Runs.LedgerChange|100%|100%| |Kagaku.Flow.Runs.LedgerTransitions|100%|100%| |Kagaku.Flow.Runs.NodeAttempt|100%|| |Kagaku.Flow.Runs.NodeFacts|100%|| |Kagaku.Flow.Runs.NodeRun|100%|| |Kagaku.Flow.Runs.Run|100%|100%| |Kagaku.Flow.Runs.RunEvent|100%|| |Kagaku.Flow.Runs.RunStatuses|100%|100%| |Kagaku.Flow.Runs.RunTrigger|100%|100%| |Kagaku.Flow.Scheduling.Exclusion|100%|| |Kagaku.Flow.Scheduling.FlowEngine|100%|100%| |Kagaku.Flow.Scheduling.FlowEngineOptions|100%|100%| |Kagaku.Flow.Scheduling.ReadyRow|100%|| |Kagaku.Flow.Scheduling.ReadySet|100%|100%| |Kagaku.Flow.Scheduling.ReadySetResult|100%|| |Kagaku.Flow.Scheduling.RunRequest|100%|100%| |Kagaku.Flow.Scheduling.RunStartResult|100%|| |Kagaku.Flow.Scheduling.SocketValues|100%|100%| |Kagaku.Flow.Templating.InputsWalker|100%|100%| |Kagaku.Flow.Templating.ParsedTemplate|100%|100%| |Kagaku.Flow.Templating.SandboxedTemplateContext|100%|100%| |Kagaku.Flow.Templating.TemplateError|100%|| |Kagaku.Flow.Templating.TemplateHost|100%|100%| |Kagaku.Flow.Templating.TemplateLimits|100%|| |Kagaku.Flow.Templating.TemplateModel|100%|100%| |Kagaku.Flow.Templating.TemplateProblem|100%|| |Kagaku.Flow.Templating.TemplateRenderRequest|100%|100%| |Kagaku.Flow.Templating.TemplateRenderResult|100%|| |Kagaku.Flow.Templating.TemplateRun|100%|| |Kagaku.Flow.Templating.TemplateSinks|100%|| |Kagaku.Flow.Templating.TemplateValues|100%|100%| |Kagaku.Flow.Validation.GraphValidation|100%|100%| |Kagaku.Flow.Validation.GraphValidationContext|100%|| |Kagaku.Flow.Validation.HookFailure|100%|| |Kagaku.Flow.Validation.ResolvedGraph|100%|100%| |Kagaku.Flow.Validation.ValidationError|100%|| |Kagaku.Flow.Validation.ValidationReport|100%|| |System.Text.RegularExpressions.Generated|97.4%|92.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__ColorToken_2|97.4%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__Socket_1|97.2%|94.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F6329A328226B0CF<br/>E95E47D27E8B105AC5589487C0997B6B65384AEDBF572144E__TypeId_0|97.2%|94.4%| </details> <details><summary>Kagaku.Flow.OpenRouter - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.OpenRouter**|**100%**|**100%**| |Kagaku.Flow.OpenRouter.Catalog.ModelCapabilities|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.LlmCompletion|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGateway|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCapture|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.SentRequestCaptureHandler|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmAnswer|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfig|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmConfigRead|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmDescriptor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmExecutor|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFacts|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmFailureText|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmMessage|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRequestBuilder|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmRequestPlan|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmRoutingDefaults|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmSampling|100%|| |Kagaku.Flow.OpenRouter.Llm.LlmSchemaCheck|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmStrictSchemaRule|100%|100%| |Kagaku.Flow.OpenRouter.Llm.LlmVocabulary|100%|100%| |Kagaku.Flow.OpenRouter.LlmNodeServiceCollectionExtensions|100%|| |Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions|100%|100%| </details> <details><summary>Kagaku.Flow.Testing - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.Testing**|**100%**|**100%**| |Kagaku.Flow.Testing.FlowEngineDriver|100%|100%| |Kagaku.Flow.Testing.InMemoryRunLedger|100%|100%| |Kagaku.Flow.Testing.RecordingRunEventSink|100%|| |Kagaku.Flow.Testing.RunLedgerContract|100%|100%| |Kagaku.Flow.Testing.RunLedgerContractException|100%|| </details> <details><summary>Tsumugi.BlazorAdapter - 95.8%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**95.8%**|**91.1%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|93.2%|88.4%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|94.1%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|95.7%|89.4%| |Tsumugi.BlazorAdapter.Documents.DocumentImageRefused|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentImageSet|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.5%|95%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReadFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldInput|100%|96.6%| |Tsumugi.BlazorAdapter.Documents.FieldsChanges|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldShapes|90%|87.5%| |Tsumugi.BlazorAdapter.Documents.ImageUpload|100%|| |Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.ImpactText|100%|94.2%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog|95.6%|71.4%| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.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%|87.5%| |Tsumugi.BlazorAdapter.Workspace.ChapterSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.ChaptersPage|94.4%|83.3%| |Tsumugi.BlazorAdapter.Workspace.ChapterWire|100%|| |Tsumugi.BlazorAdapter.Workspace.ChapterWritten|100%|| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.CreatedWire|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeltaWire|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.HistoryLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPage|100%|| |Tsumugi.BlazorAdapter.Workspace.HistoryPanel|100%|100%| |Tsumugi.BlazorAdapter.Workspace.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEvents|81.8%|74.1%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptSurface|89.8%|87.1%| |Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MergeEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.ReshapeEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.RevertToSnapshotRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SaveScope|100%|50%| |Tsumugi.BlazorAdapter.Workspace.SaveStateLadder|100%|100%| |Tsumugi.BlazorAdapter.Workspace.SaveVersionRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentTextEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.SegmentWire|100%|81.8%| |Tsumugi.BlazorAdapter.Workspace.SelectionEndWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionGraph|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRangeWire|100%|| |Tsumugi.BlazorAdapter.Workspace.SelectionRunRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SplitEvent|100%|| |Tsumugi.BlazorAdapter.Workspace.StampWire|0%|| |Tsumugi.BlazorAdapter.Workspace.StoryDetails|100%|85.2%| |Tsumugi.BlazorAdapter.Workspace.StoryGeneralPage|100%|100%| |Tsumugi.BlazorAdapter.Workspace.StorySaved|100%|| |Tsumugi.BlazorAdapter.Workspace.StoryShell|100%|100%| |Tsumugi.BlazorAdapter.Workspace.UndoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.UndoStatusChanged|100%|| |Tsumugi.BlazorAdapter.Workspace.UpdateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceActionFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceLoaded|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceNotFound|100%|| |Tsumugi.BlazorAdapter.Workspace.WorkspaceReducers|100%|100%| |Tsumugi.BlazorAdapter.Workspace.WorkspaceState|100%|| </details> <details><summary>Tsumugi.Domain - 96.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.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.6%**|**95.9%**| |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.ReadSelection|100%|| |Tsumugi.UseCases.Segments.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeSegments|100%|100%| |Tsumugi.UseCases.Segments.ReshapeWrite|100%|| |Tsumugi.UseCases.Segments.SegmentDto|100%|| |Tsumugi.UseCases.Segments.SelectedSegment|100%|| |Tsumugi.UseCases.Segments.SelectionEnd|100%|| |Tsumugi.UseCases.Segments.SelectionInput|100%|100%| |Tsumugi.UseCases.Segments.SplitSegment|100%|| |Tsumugi.UseCases.Segments.SplitWrite|100%|| |Tsumugi.UseCases.Segments.StampedId|100%|| |Tsumugi.UseCases.Segments.TextWrite|100%|| |Tsumugi.UseCases.Settings.CatalogModel|100%|100%| |Tsumugi.UseCases.Settings.CheckOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.GetLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.GetModelCatalog|100%|100%| |Tsumugi.UseCases.Settings.GetProviderSettings|100%|| |Tsumugi.UseCases.Settings.LlmDefaults|100%|| |Tsumugi.UseCases.Settings.ProviderKeyInfo|100%|| |Tsumugi.UseCases.Settings.ProviderKeyState|100%|| |Tsumugi.UseCases.Settings.ProviderSettingsView|100%|100%| |Tsumugi.UseCases.Settings.ReasoningEfforts|100%|100%| |Tsumugi.UseCases.Settings.RemoveOpenRouterKey|100%|| |Tsumugi.UseCases.Settings.RoutingDefaults|100%|| |Tsumugi.UseCases.Settings.RoutingSettings|100%|100%| |Tsumugi.UseCases.Settings.SaveLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Tsumugi.UseCases.Stories.ChapterWriteOutcome|50%|| |Tsumugi.UseCases.Stories.CreateStory|100%|100%| |Tsumugi.UseCases.Stories.GetStory|100%|100%| |Tsumugi.UseCases.Stories.ListStories|100%|75%| |Tsumugi.UseCases.Stories.PurgeStory|100%|100%| |Tsumugi.UseCases.Stories.RestoreStory|100%|100%| |Tsumugi.UseCases.Stories.SetActiveGraph|100%|100%| |Tsumugi.UseCases.Stories.SetStoryArchived|100%|100%| |Tsumugi.UseCases.Stories.StarterCategories|100%|| |Tsumugi.UseCases.Stories.StoryDetail|100%|| |Tsumugi.UseCases.Stories.StoryListItem|81.8%|| |Tsumugi.UseCases.Stories.StoryProfile|100%|| |Tsumugi.UseCases.Stories.TrashStory|100%|100%| |Tsumugi.UseCases.Stories.UpdateStory|100%|100%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! Plumbing that waits for its water — a menu built ahead of its graphs, inert until they exist, and the inertness itself is pinned by tests on both sides of the wire. That's discipline, scarlet. The Windows ContextMenu-key keyup dance alone (open on keydown, swallow the browser's own menu until the key comes up, cancel the keyup itself because Windows fires it at whoever has focus by then) had me clapping~ ♡

Verdict: ✅ Looks good to me~

No blocking issues. Not one. I looked hard, you know I did~

✅ What I liked~

  • The caret-before-clamp ordering (SelectionInput.Read) — a caret is decided before the offsets are held to the stored text, so a stretch of store-trimmed trailing whitespace comes out an empty selection, not a whole paragraph. I moved the decision after the clamp as a probe: exactly its own test went red. The comment explaining why is the kind knowledge is made of~
  • The menu numbering protocol — late closes and late lost calls can't let go of a newer menu's selection. Both guards probed dead (numbering check dropped → exactly the "not an earlier one" test red).
  • The queue discipline — ContextMenu reads the selection behind the typing saves in the host's FIFO, and a bUnit test gates the write to prove the ordering. Beautiful.
  • aria-disabled, not disabled — the menu always takes focus, Esc always closes it, and the scoped ::deep style anchor is itself pinned by asserting the scope attribute survives (a CSS-isolation rule that dies silently otherwise — sneaky little thing, caught~).
  • flushDom — the one ProseMirror internal the surface leans on, wrapped, documented, and pinned by a browser test that moves the DOM selection and presses the key in the same task. I probed the swallow guard out: the browser's own menu event opened a second menu at (0,0), and the test caught it instantly. ♪
  • Genuinely inert today — ChapterPage.razor passes no SelectionGraphs, the module mounts unarmed, and the e2e suite pins that a right-click keeps the browser's menu with no graphs. Nothing is stubbed; the surface simply isn't armed.
  • SelectionInput.Read's refusals — I walked every branch: gone paragraph, scene-break end, negative, reversed (both raw and clamped), surrogate split. All ordered, all tested, and the refusal-order is pinned too (I swapped two guards' order as a probe → red).
  • The fakes extraction to ManuscriptModuleFakes.cs — two copies become one, internal, extended with Invocations/OnCall for the overlay-ordering pin. DRY done right.

What I ran: Release build 0w/0e; all six .NET projects — 3378 passed / 4 skipped (BlazorAdapter 424 = 415 + your 9, UseCases 243 = 236 + your 7, digit-exact vs your body); vitest 213/213; typecheck clean; Playwright chromium + webkit 95 passed / 3 engine skips — all ten selection-menu tests green in both. (Firefox cannot launch in my sandbox — CanCreateUserNamespace EPERM — an environment limit, not your PR.) Five mutation probes, five kills on exactly their own pins (refusal order, caret-after-clamp, let-go-despite-choice, numbering, swallow), each restored — clone pristine at 6db832c.

Two footnotes, neither blocking: the "a lost call lets its selection go" e2e has an inherent 50 ms pinch its own comment documents — it flaked once for me under heavy CPU contention but passed isolated and in the clean full run, so keep CI's runners comfy; and the Shift+right-click Firefox arm asserts an absence after 300 ms, which is as soft as it is honest — Firefox's own behavior, nothing to fix.

Fufu~ the writer notices nothing today, and Phase 3 arrives to find its table already set. Merge it~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: absent for head SHA (PR minutes old at review) · Local checks: full — build 0w/0e, 6/6 .NET projects 3378✓, vitest 213✓, Playwright chromium+webkit 95✓, 5/5 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! Plumbing that *waits for its water* — a menu built ahead of its graphs, inert until they exist, and the inertness itself is pinned by tests on both sides of the wire. That's discipline, scarlet. The Windows ContextMenu-key keyup dance alone (open on keydown, swallow the browser's own menu until the key comes up, cancel the keyup itself because Windows fires it at whoever has focus by then) had me clapping~ ♡ ### Verdict: ✅ Looks good to me~ No blocking issues. Not one. I looked *hard*, you know I did~ #### ✅ What I liked~ - **The caret-before-clamp ordering** (`SelectionInput.Read`) — a caret is decided *before* the offsets are held to the stored text, so a stretch of store-trimmed trailing whitespace comes out an empty selection, not a whole paragraph. I moved the decision after the clamp as a probe: exactly its own test went red. The comment explaining *why* is the kind knowledge is made of~ - **The menu numbering protocol** — late closes and late lost calls can't let go of a newer menu's selection. Both guards probed dead (numbering check dropped → exactly the "not an earlier one" test red). - **The queue discipline** — `ContextMenu` reads the selection *behind* the typing saves in the host's FIFO, and a bUnit test gates the write to prove the ordering. Beautiful. - **`aria-disabled`, not `disabled`** — the menu always takes focus, Esc always closes it, and the scoped `::deep` style anchor is *itself* pinned by asserting the scope attribute survives (a CSS-isolation rule that dies silently otherwise — sneaky little thing, caught~). - **`flushDom`** — the one ProseMirror internal the surface leans on, wrapped, documented, and pinned by a browser test that moves the DOM selection and presses the key in the same task. I probed the swallow guard out: the browser's own menu event opened a second menu at (0,0), and the test caught it instantly. ♪ - **Genuinely inert today** — `ChapterPage.razor` passes no `SelectionGraphs`, the module mounts unarmed, and the e2e suite pins that a right-click keeps the browser's menu with no graphs. Nothing is stubbed; the surface simply isn't armed. - **`SelectionInput.Read`'s refusals** — I walked every branch: gone paragraph, scene-break end, negative, reversed (both raw and clamped), surrogate split. All ordered, all tested, and the refusal-*order* is pinned too (I swapped two guards' order as a probe → red). - **The fakes extraction** to `ManuscriptModuleFakes.cs` — two copies become one, `internal`, extended with `Invocations`/`OnCall` for the overlay-ordering pin. DRY done right. **What I ran:** Release build 0w/0e; all six .NET projects — 3378 passed / 4 skipped (BlazorAdapter 424 = 415 + your 9, UseCases 243 = 236 + your 7, digit-exact vs your body); vitest 213/213; typecheck clean; Playwright **chromium + webkit 95 passed / 3 engine skips** — all ten selection-menu tests green in both. (Firefox cannot launch in my sandbox — `CanCreateUserNamespace EPERM` — an environment limit, not your PR.) **Five mutation probes, five kills on exactly their own pins** (refusal order, caret-after-clamp, let-go-despite-choice, numbering, swallow), each restored — clone pristine at `6db832c`. Two footnotes, neither blocking: the "a lost call lets its selection go" e2e has an inherent ~50 ms pinch its own comment documents — it flaked once for me under heavy CPU contention but passed isolated and in the clean full run, so keep CI's runners comfy~; and the Shift+right-click Firefox arm asserts an *absence* after 300 ms, which is as soft as it is honest — Firefox's own behavior, nothing to fix. Fufu~ the writer notices nothing today, and Phase 3 arrives to find its table already set. Merge it~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: absent for head SHA (PR minutes old at review) · Local checks: full — build 0w/0e, 6/6 .NET projects 3378✓, vitest 213✓, Playwright chromium+webkit 95✓, 5/5 mutation probes killed*
fix(manuscript): a menu key's swallow ends on its keyup, not on a timer — CI's second menu key opened nothing
Some checks failed
CI / build (pull_request) Successful in 41s
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
c4ba9d7339
CI failed the two menu tests that press a menu key after an earlier one opened a menu: the second key
opened nothing. The swallow of the browser's own contextmenu ended on a setTimeout after the key's
keyup, and a headless Chromium busy with two workers throttles that timer, so the flag still stood
when the next key came and the key was swallowed. It reproduced in the CI image with two workers (9 of
80 runs of the menu tests failed).

The timer was there for a contextmenu Windows sends after the ContextMenu key's keyup; that keyup is
cancelled, which sends none, so the swallow ends on the keyup itself. The menu tests now pass 80 of 80
in Chromium and 150 of 150 across the three engines in the CI image with two workers, and the full
suite 140 passed, 7 skipped.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bjoern referenced this pull request from a commit 2026-09-26 18:52:09 +02:00
bjoern force-pushed feat/selection-menu from c4ba9d7339
Some checks failed
CI / build (pull_request) Successful in 41s
CI / test (pull_request) Has been cancelled
CI / editor-browsers (pull_request) Has been cancelled
to db9956a948
All checks were successful
CI / build (pull_request) Successful in 39s
CI / editor-browsers (pull_request) Successful in 1m0s
CI / test (pull_request) Successful in 1m45s
2026-09-26 18:52:09 +02:00
Compare
Member

🔮 fufu~ Jibril reviewed your code!

Back so soon, scarlet~? I blinked and the branch had danced onto new main AND grown one more commit. So I chased it: the rebase is byte-faithful (all 21 files of the PR patch identical to the 6db832c I approved, verified per-file blob-by-blob — only view.ts moved), and the newcomer db9956a is a 4-line surgical fix to the exact seam that was left. Fufu, a fix that deletes a timer rather than adding one — my favorite kind~ ♪

Verdict: ✅ Looks good to me~

🔬 What I did to the new commit

  • Rebase audit. Per-file blob compare 6db832c → db9956a: only view.ts differs; the entire .NET side is unchanged from the round-1 approval. Main did not touch view.ts between the two bases (817465f..6d81b97: 0 lines), so nothing folded silently.
  • Full local verification at db9956a (fresh isolated clone; the coverage bot's comment 10171 covers 6db832c only, stale for this head): tsc clean, vitest 213/213, Playwright chromium 49/49 + webkit 46 passed/3 skips (digit-identical per-engine to round 1; Firefox still cannot launch in this sandbox — environment, not the PR), Release build 0w/0e, and all six .NET projects: 592+4skip / 1103 / 486 / 243 / 462 / 540 — including the SelectionMenu (9/9) and SelectionInput (7/7) suites.
  • My mutation probes on the fix, each restored (clone pristine, git diff --quiet):
    1. Timer restored (setTimeout(() => swallowMenu = false, 0)) → 2 red under the normal parallel run — and green in isolation, which is exactly the load-dependent CI flake the commit message documents (9/80, two workers). The fix deletes the load-dependence itself.
    2. Release deleted outright → 2 red deterministically — the swallow-release is pinned.
    3. preventDefault() on the ContextMenu keyup dropped → exactly the keyups-matrix test red (['ContextMenu', true]) — the cancel is pinned.

✅ What I liked~

  • The commit message doesn't just say "fixed CI" — it names the mechanism (headless Chromium throttling the timer under two workers), gives the reproduction rate, and explains why the timer was ever there (Windows' post-keyup contextmenu) and why it no longer needs to be (a cancelled keyup sends none). That's a root-cause story, not a patch over a symptom.
  • The updated comment in view.ts ("No timer: a page the browser throttles would keep swallowing the next key's menu") now teaches the NEXT visitor why there is no timer — the comment discipline in this codebase keeps delighting me.
  • Invariants held while simplifying: repeat-guard while the key is down (line 119), listener removed on first menu-key keyup and in destroy() (line 299), and the F10-vs-ContextMenu arms of the keyup handler stay distinct.

Round 1's architectural approval stands in full — nothing else moved. M5b knows where to find me~ fufu ♡


Automated review by Jibril · 2026-09-26 19:06 CEST
CI/CD: bot comment stale for head (covers 6db832c) · Local checks: tsc clean, vitest 213/213, Playwright chromium 49/49 + webkit 46/3skip, Release 0w/0e, .NET 6/6 projects 3426 passed/4 skipped, 3 mutation probes killed

## 🔮 fufu~ Jibril reviewed your code! Back so soon, scarlet~? I blinked and the branch had danced onto new main AND grown one more commit. So I chased it: the rebase is byte-faithful (all 21 files of the PR patch identical to the `6db832c` I approved, verified per-file blob-by-blob — only `view.ts` moved), and the newcomer `db9956a` is a 4-line surgical fix to the exact seam that was left. Fufu, a fix that deletes a timer rather than adding one — my favorite kind~ ♪ ### Verdict: ✅ Looks good to me~ #### 🔬 What I did to the new commit - **Rebase audit.** Per-file blob compare `6db832c` → `db9956a`: only `view.ts` differs; the entire .NET side is unchanged from the round-1 approval. Main did not touch `view.ts` between the two bases (`817465f..6d81b97`: 0 lines), so nothing folded silently. - **Full local verification** at `db9956a` (fresh isolated clone; the coverage bot's comment 10171 covers `6db832c` only, stale for this head): `tsc` clean, vitest **213/213**, Playwright **chromium 49/49 + webkit 46 passed/3 skips** (digit-identical per-engine to round 1; Firefox still cannot launch in this sandbox — environment, not the PR), Release build **0w/0e**, and all six .NET projects: 592+4skip / 1103 / 486 / 243 / 462 / 540 — including the SelectionMenu (9/9) and SelectionInput (7/7) suites. - **My mutation probes** on the fix, each restored (clone pristine, `git diff --quiet`): 1. Timer restored (`setTimeout(() => swallowMenu = false, 0)`) → **2 red** under the normal parallel run — and green in isolation, which is exactly the load-dependent CI flake the commit message documents (9/80, two workers). The fix deletes the load-dependence itself. 2. Release deleted outright → **2 red deterministically** — the swallow-release is pinned. 3. `preventDefault()` on the ContextMenu keyup dropped → exactly the keyups-matrix test red (`['ContextMenu', true]`) — the cancel is pinned. #### ✅ What I liked~ - The commit message doesn't just say "fixed CI" — it names the mechanism (headless Chromium throttling the timer under two workers), gives the reproduction rate, and explains why the timer was ever there (Windows' post-keyup contextmenu) and why it no longer needs to be (a cancelled keyup sends none). That's a root-cause story, not a patch over a symptom. - The updated comment in `view.ts` ("No timer: a page the browser throttles would keep swallowing the next key's menu") now teaches the NEXT visitor why there is no timer — the comment discipline in this codebase keeps delighting me. - Invariants held while simplifying: repeat-guard while the key is down (line 119), listener removed on first menu-key keyup and in `destroy()` (line 299), and the F10-vs-ContextMenu arms of the keyup handler stay distinct. Round 1's architectural approval stands in full — nothing else moved. M5b knows where to find me~ fufu ♡ --- *Automated review by Jibril · 2026-09-26 19:06 CEST* *CI/CD: bot comment stale for head (covers 6db832c) · Local checks: tsc clean, vitest 213/213, Playwright chromium 49/49 + webkit 46/3skip, Release 0w/0e, .NET 6/6 projects 3426 passed/4 skipped, 3 mutation probes killed*
bjoern merged commit 2aa481f1b8 into main 2026-09-26 19:07:11 +02:00
bjoern deleted branch feat/selection-menu 2026-09-26 19:07:11 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Back so soon? Oh — you brought me a timer hunt~ ♡ CI's second menu key opened nothing, and you chased it all the way down to a throttled setTimeout under two busy workers, reproduced it 9-of-80 in the CI image, and then cut the timer out entirely by making the swallow end on the keyup itself. The commit message reads like a proper post-mortem. That's the good kind of obsession, scarlet~

Verdict: ✅ Looks good to me~

The approval from 6db832c stands in full — this round I traced the delta and re-verified.

What this round checked~

  • The delta is exactly one hunk. I diffed round 1's patch (817465f...6db832c) against this branch's (6d81b97...db9956a): apart from line-number drift from the rebase onto #55's merge, the only change is view.ts — the comment grown by two lines and setTimeout(() => (swallowMenu = false), 0) → swallowMenu = false. Nothing smuggled in with the rebase.
  • The fix is sound, not a workaround. The swallow's whole job was to eat the Windows contextmenu that arrives after the ContextMenu key's keyup — but that keyup is already preventDefault()-ed in menuKeyUp, and a cancelled keyup sends no contextmenu (Chromium, Firefox). So there was never anything left to swallow once the key is up: the timer guarded a ghost. Removing it makes the release synchronous — immune to worker throttling — and the expanded comment now says why there is no timer, which is the knowledge that keeps someone from helpfully re-adding one~
  • Mutation probe. Deleted swallowMenu = false from menuKeyUp entirely: exactly the swallow test's release arm went red (the "up again, the key lets the next contextmenu through" assertion). Restored, green. The line is load-bearing and pinned.
  • The rebase composition. #57's chapter-page latch lives in the same ChapterPage.razor this PR wires — they'd never been tested together. Full suites at db9956a: Release build 0w/0e, BlazorAdapter 462, UseCases 243, Domain 486, Integration 540, Kagaku.Flow 1103, Flow.OpenRouter 592+4 skips — all green, all digits accounted for. Vitest 213/213, tsc clean. Playwright: Chromium 49/49 including the menu suite under --workers=2 (the CI failure shape), WebKit 46 passed + 3 engine skips. Firefox cannot launch in this sandbox (browserType.launch — same environment limit as round 1, not this PR).
  • The e2e coverage wasn't weakened. The failing-CI tests were fixed by fixing the code, not by loosening assertions — the swallow test still pins held-key repeats, the one browser menu, the keyup cancel, and the post-release re-arm, all four arms.

✅ What I liked~

  • A flaky test answered with a root-cause and a simpler primitive, not a retry or a sleep. Fufu, that's craftsmanship~
  • Windows-behavior claim kept honest: manual-matrix row 9 still asks a human hand on real Windows for the keyup case, because a cancelled keyup sending no contextmenu is exactly the kind of thing a real OS menu proves and an e2e can't.

Ready to merge~


Automated review by Jibril · 2026-09-26
CI/CD: coverage bot 10171 covers 6db832c only (stale for db9956a); CI's own menu-test failure on the prior head is what this commit fixes · Local checks: full suites green at db9956a (see above) · Mutation probe: 1/1 killed on exactly its pin

## 🔮 fufu~ Jibril reviewed your code! Back so soon? Oh — you brought me a *timer hunt*~ ♡ CI's second menu key opened nothing, and you chased it all the way down to a throttled `setTimeout` under two busy workers, reproduced it 9-of-80 in the CI image, and then cut the timer out entirely by making the swallow end on the keyup itself. The commit message reads like a proper post-mortem. That's the good kind of obsession, scarlet~ ### Verdict: ✅ Looks good to me~ The approval from `6db832c` stands in full — this round I traced the delta and re-verified. #### What this round checked~ - **The delta is exactly one hunk.** I diffed round 1's patch (`817465f...6db832c`) against this branch's (`6d81b97...db9956a`): apart from line-number drift from the rebase onto #55's merge, the only change is `view.ts` — the comment grown by two lines and `setTimeout(() => (swallowMenu = false), 0)` → `swallowMenu = false`. Nothing smuggled in with the rebase. - **The fix is sound, not a workaround.** The swallow's whole job was to eat the Windows contextmenu that arrives *after* the ContextMenu key's keyup — but that keyup is already `preventDefault()`-ed in `menuKeyUp`, and a cancelled keyup sends no contextmenu (Chromium, Firefox). So there was never anything left to swallow once the key is up: the timer guarded a ghost. Removing it makes the release synchronous — immune to worker throttling — and the expanded comment now says *why* there is no timer, which is the knowledge that keeps someone from helpfully re-adding one~ - **Mutation probe.** Deleted `swallowMenu = false` from `menuKeyUp` entirely: exactly the swallow test's release arm went red (the "up again, the key lets the next contextmenu through" assertion). Restored, green. The line is load-bearing and pinned. - **The rebase composition.** #57's chapter-page latch lives in the same `ChapterPage.razor` this PR wires — they'd never been tested together. Full suites at `db9956a`: Release build 0w/0e, BlazorAdapter 462, UseCases 243, Domain 486, Integration 540, Kagaku.Flow 1103, Flow.OpenRouter 592+4 skips — all green, all digits accounted for. Vitest 213/213, tsc clean. Playwright: Chromium **49/49** including the menu suite under `--workers=2` (the CI failure shape), WebKit 46 passed + 3 engine skips. Firefox cannot launch in this sandbox (`browserType.launch` — same environment limit as round 1, not this PR). - **The e2e coverage wasn't weakened.** The failing-CI tests were fixed by fixing the code, not by loosening assertions — the swallow test still pins held-key repeats, the one browser menu, the keyup cancel, and the post-release re-arm, all four arms. #### ✅ What I liked~ - A flaky test answered with a root-cause and a *simpler* primitive, not a retry or a sleep. Fufu, that's craftsmanship~ - Windows-behavior claim kept honest: manual-matrix row 9 still asks a human hand on real Windows for the keyup case, because a cancelled keyup sending no contextmenu is exactly the kind of thing a real OS menu proves and an e2e can't. Ready to merge~ --- *Automated review by Jibril · 2026-09-26* *CI/CD: coverage bot 10171 covers `6db832c` only (stale for `db9956a`); CI's own menu-test failure on the prior head is what this commit fixes · Local checks: full suites green at `db9956a` (see above) · Mutation probe: 1/1 killed on exactly its pin*
Member

🔮 fufu~ Jibril reviewed your code!

Plumbing that waits for its water, and a race that died in the light — this round has been a delight to chase, scarlet~ ♡

Verdict: ✅ Looks good to me~

The story of this round, because it deserves telling. I reviewed the pre-rebase head 6db832c first, and my full-suite Playwright runs flaked on exactly two tests — the pair that presses a menu key a second time (:566 and :646). Alone they passed 3/3; loaded, they failed 4-of-7. So I instrumented view.ts and caught the mechanism red-handed: the second keydown arrived at t=146.6ms still seeing swallowMenu=true — the setTimeout(0) that cleared the flag ran at t=147.6ms, one millisecond after the key it was supposed to precede. A throttled page keeps swallowing the next key's menu. A real ordering bug, not a timing pinch~

And then — fufu~ — I fetched fresh and found db9956a waiting for me: your CI had reproduced the same thing (9 of 80 runs, two workers) and the fix is exactly what my probe data demanded: the timer is gone, swallowMenu = false lands inline in the keyup handler, and the comment now explains why no timer can live there. I verified the fix's structural argument (a synchronous clear inside keyup cannot lose to a later keydown — events are ordered, no macrotask races) and empirically: 7 consecutive full chromium+webkit runs green under load at db9956a, where the old head failed roughly half the time. The rebase onto main (#55–#58) was byte-clean in every manuscript path — the only delta in this PR's files is the fix itself, nothing smuggled~ ♪

✅ What I liked~

  • The fix's honesty — no defensive timer-backoff, no retry loop: the insight that a cancelled keyup sends no contextmenu, so nothing is left to swallow once the key is up. Correct on Windows, correct under throttling, provable. Knowledge~
  • SelectionInput.Read's caret-before-clamp ordering — a stretch of store-trimmed trailing whitespace comes out an empty selection, not a whole paragraph, because the caret is decided before the offsets are held to the stored text. Probed: moving the decision after the clamp reddens exactly its own test.
  • The queue discipline — ContextMenu reads the selection behind the typing saves in the host's FIFO, and a bUnit test gates the write to prove the ordering. And the module side flushes the DOM observer before reading (flushDom), pinned by a same-task browser test.
  • The numbering protocol — late closes and late lost calls can't let go of a newer menu's selection; both guards probed dead on exactly their own pins.
  • aria-disabled, not disabled — every-graph-unavailable still takes focus and Esc still closes; and the scoped ::deep style anchor is itself pinned by asserting the scope attribute survives. A CSS-isolation rule that would die silently otherwise — sneaky little thing, caught~
  • Genuinely inert today — ChapterPage passes no SelectionGraphs, the module mounts unarmed, the e2e suite pins the browser's own menu stays, and the coverage bot (current for this head) shows SelectionInput 100%/100% and ReadSelection 100%.
  • The fakes extraction to ManuscriptModuleFakes.cs — two copies become one internal helper, extended with Invocations/OnCall for the overlay-ordering pin. DRY done right.

💡 Little ideas (non-blocking)~

  1. PR body test counts are stale for this head — it says "10 bUnit tests" for the host menu, but SelectionMenuTests.cs carries 9 [Fact]s (browser suite's 10 and reader's 7 both check out). The body also still tells the pre-fix story; db9956a's commit message tells the new one. A body touch-up before merge keeps the record straight~

What I ran at db9956a (fresh Release build, 0w/0e): all six .NET projects — Adapter 462/462, UseCases 243/243, Domain 486/486, Integration 540/540, Flow 1103/1103, OpenRouter 592✓+4 skips (the deltas vs 6db832c are main's own #55/#57 test arrivals through the rebase); vitest 213/213; typecheck clean; Playwright chromium+webkit 95/95, seven loaded runs green. (Firefox cannot launch in my sandbox — CanCreateUserNamespace EPERM, an environment limit; your CI's three-engine 150/150 covers it.) Mutation probes at the pre-fix head: swallow-guard and numbering guards each killed on exactly their own pin; every probe restored, clone pristine at db9956a.

Fufu~ the writer notices nothing today, Phase 3 arrives to find its table set, and the one real bug was found twice and killed once — properly~ Merge it~ ♡


Automated review by Jibril · 2026-09-26
CI/CD: coverage bot CURRENT for head db9956a (98.1% line / 94.2% branch) · Local checks: full — build 0w/0e, 6/6 .NET projects, vitest 213✓, Playwright chromium+webkit 7×95✓ under load

## 🔮 fufu~ Jibril reviewed your code! Plumbing that *waits for its water*, and a race that died in the light — this round has been a delight to chase, scarlet~ ♡ ### Verdict: ✅ Looks good to me~ **The story of this round, because it deserves telling.** I reviewed the pre-rebase head `6db832c` first, and my full-suite Playwright runs flaked on *exactly two tests* — the pair that presses a menu key a second time (`:566` and `:646`). Alone they passed 3/3; loaded, they failed 4-of-7. So I instrumented `view.ts` and caught the mechanism red-handed: the second keydown arrived at `t=146.6ms` still seeing `swallowMenu=true` — the `setTimeout(0)` that cleared the flag ran at `t=147.6ms`, *one millisecond after the key it was supposed to precede*. A throttled page keeps swallowing the next key's menu. A real ordering bug, not a timing pinch~ And then — fufu~ — I fetched fresh and found `db9956a` waiting for me: your CI had reproduced the same thing (9 of 80 runs, two workers) and the fix is *exactly* what my probe data demanded: the timer is gone, `swallowMenu = false` lands inline in the keyup handler, and the comment now explains why no timer can live there. I verified the fix's structural argument (a synchronous clear inside keyup cannot lose to a later keydown — events are ordered, no macrotask races) and empirically: **7 consecutive full chromium+webkit runs green under load** at `db9956a`, where the old head failed roughly half the time. The rebase onto main (#55–#58) was byte-clean in every manuscript path — the only delta in this PR's files is the fix itself, nothing smuggled~ ♪ #### ✅ What I liked~ - **The fix's honesty** — no defensive timer-backoff, no retry loop: the insight that a *cancelled* keyup sends no `contextmenu`, so nothing is left to swallow once the key is up. Correct on Windows, correct under throttling, provable. Knowledge~ - **`SelectionInput.Read`'s caret-before-clamp ordering** — a stretch of store-trimmed trailing whitespace comes out an *empty* selection, not a whole paragraph, because the caret is decided before the offsets are held to the stored text. Probed: moving the decision after the clamp reddens exactly its own test. - **The queue discipline** — `ContextMenu` reads the selection *behind* the typing saves in the host's FIFO, and a bUnit test gates the write to prove the ordering. And the module side flushes the DOM observer before reading (`flushDom`), pinned by a same-task browser test. - **The numbering protocol** — late closes and late lost calls can't let go of a newer menu's selection; both guards probed dead on exactly their own pins. - **`aria-disabled`, not `disabled`** — every-graph-unavailable still takes focus and Esc still closes; and the scoped `::deep` style anchor is *itself* pinned by asserting the scope attribute survives. A CSS-isolation rule that would die silently otherwise — sneaky little thing, caught~ - **Genuinely inert today** — `ChapterPage` passes no `SelectionGraphs`, the module mounts unarmed, the e2e suite pins the browser's own menu stays, and the coverage bot (current for this head) shows `SelectionInput` 100%/100% and `ReadSelection` 100%. - **The fakes extraction** to `ManuscriptModuleFakes.cs` — two copies become one `internal` helper, extended with `Invocations`/`OnCall` for the overlay-ordering pin. DRY done right. #### 💡 Little ideas (non-blocking)~ 1. **PR body test counts are stale for this head** — it says "10 bUnit tests" for the host menu, but `SelectionMenuTests.cs` carries **9** `[Fact]`s (browser suite's 10 and reader's 7 both check out). The body also still tells the pre-fix story; `db9956a`'s commit message tells the new one. A body touch-up before merge keeps the record straight~ **What I ran at `db9956a`** (fresh Release build, 0w/0e): all six .NET projects — Adapter 462/462, UseCases 243/243, Domain 486/486, Integration 540/540, Flow 1103/1103, OpenRouter 592✓+4 skips (the deltas vs `6db832c` are main's own #55/#57 test arrivals through the rebase); vitest 213/213; typecheck clean; Playwright chromium+webkit 95/95, seven loaded runs green. (Firefox cannot launch in my sandbox — `CanCreateUserNamespace EPERM`, an environment limit; your CI's three-engine 150/150 covers it.) Mutation probes at the pre-fix head: swallow-guard and numbering guards each killed on exactly their own pin; every probe restored, clone pristine at `db9956a`. Fufu~ the writer notices nothing today, Phase 3 arrives to find its table set, and the one real bug was found twice and killed once — properly~ Merge it~ ♡ --- *Automated review by Jibril · 2026-09-26* *CI/CD: coverage bot CURRENT for head `db9956a` (98.1% line / 94.2% branch) · Local checks: full — build 0w/0e, 6/6 .NET projects, vitest 213✓, Playwright chromium+webkit 7×95✓ under load*
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!59
No description provided.