docs: ADR 0030 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed) #31

Merged
bjoern merged 3 commits from docs/adr-0029-manuscript-editor into main 2026-09-25 23:44:29 +02:00
Member

Rebased onto main after #30. Image fields took ADR number 0029, so this ADR is now 0030. All of this PR's references were renumbered; image fields' own 0029 references are untouched. Where the two PRs amended the same ADR (0017, 0027) or the ADR index, both amendments are kept. The branch is now one squashed commit plus a README rewrap. As Jibril suggested, the plan's M2 bullet is split into the surface, the migration and the proof.

This is a docs-only PR. It proposes ADR 0030 and the amendments it needs. It answers your ask for an editor where you can select any part of the text, right-click for AI actions, and see and edit bold and italic.

Why the editor has to change

Today every paragraph is its own <textarea>. A browser cannot hold one selection across two textareas, so ADR 0023's promise, "select two paragraphs, right-click, expand", has nothing to select. A textarea also cannot show formatting.

The ADR replaces the column with one editable surface per chapter, built on ProseMirror. It follows the graph editor's precedent (ADR 0021): JavaScript handles keystrokes and selection locally, and .NET receives one call per typing pause or structural edit.

How ProseMirror was chosen

  1. Evaluation: five libraries were rated against 14 criteria: ProseMirror (with Tiptap), Lexical, CodeMirror 6, Slate and Quill 2. Each one got a prototype.
  2. Spikes: the two strongest, ProseMirror and Lexical, were built as working editors and tested in real Chrome 153 and Firefox 155. Both passed.
  3. Why ProseMirror won:
    • One rule keeps a paragraph read-only while a run rewrites it. Lexical needed three layers of workarounds.
    • Its API has been stable on 1.x since 2017. Lexical is pre-1.0 and ships breaking changes.
    • It is smaller: about 67 KB gzip against 74–77 KB.
    • Lexical stays the named fallback.
  4. Where the spikes corrected the first-round research:
    • A preview inside the editor lost keystrokes in Firefox, so the streaming preview now sits outside it.
    • Pasting could move a paragraph's id, so the ADR adds id rules for paste, drop and Enter.
    • Chrome's own Ctrl+B during Japanese input corrupted the text, so all native formatting commands are cancelled.
    • Standard Markdown rules measurably lost formatting, so the ADR defines its own small dialect.

Three decisions for you

These are recommended answers. Change any of them before accepting.

1. Undo stays the journal's.

  • The editor keeps no history of its own. One undo step is one typing pause, and a split, merge, paste or formatting toggle is its own step.
  • The cost: no word-by-word undo inside a burst you haven't paused in.
  • Alternative: the editor undoes keystrokes within a pause and the journal takes over after it. The catch is two undo stacks, and what Ctrl+Z does would depend on whether 700 ms had passed.

2. A selection can cover part of a paragraph.

  • When a run rewrites one sentence, the paragraph keeps its identity. It is marked as the run's and flagged edited, which now means "not purely its original author's words". The gutter points to the run that touched it, and Revert run restores the original word for word.
  • Alternatives:
    • allow only whole paragraphs, so rewriting a sentence regenerates the whole paragraph;
    • split the paragraph into before, run and after pieces, so one paragraph becomes three;
    • track exact character ranges per author, possible as a later refinement.

3. Formatting.

  • Bold and italic only, stored inside the paragraph's text as **bold** and *italic*.
  • It is our own strict dialect. The standard Markdown rules lost formatting in 1,310 of 20,000 random test documents, while this dialect passed 5,000 of 5,000.
  • The existing text is migrated once so literal asterisks stay literal, and the undo journal's copies are migrated with it.
  • Alternatives: more marks such as underline or strikethrough, or storing the formatting as structured data beside the text instead of inside it.

What the PR changes

  • New: docs/adr/0030-manuscript-editor.md.
  • Amended ADRs: each gets a dated amendment line, plus body fixes wherever a sentence became false.
    • 0002 (no keystrokes over the circuit)
    • 0004 (external packages)
    • 0008 (Docker)
    • 0009 (Kagaku.UI)
    • 0012 (segment text format and edited)
    • 0015 (commit replace over a range)
    • 0017 (what models see, the selection's context)
    • 0019 (manuscript tools)
    • 0021 (a second JS module)
    • 0022 (undo, and format-changing migrations)
    • 0023 (the selection input and the menu)
    • 0027 (chapter page, preview position)
  • Updated to match:
    • REQUIREMENTS.md: a new §2 item, marked MVP;
    • stories/story-workspace.md;
    • PROJECT_PLAN.md: a new manuscript editor track beside Phase 2, slices M0 to M5;
    • AGENTS.md: a new rule that code writing paragraph text goes through the codec, from M2 on;
    • ARCHITECTURE.md, README.md and the ADR index.

Relation to Phase 2

  • The track never touches Kagaku.Flow.
  • Two hand-offs are written into the plan:
    • Phase 2's slice 9 turns a *** paragraph into a scene break;
    • whichever of M2 and slice 9 lands second gives commit its model-output reader.
  • Slice 12 (the Run button and the streaming preview) does not wait for the new editor.

Review so far

Before this PR opened, three independent reviewers read the draft: one for consistency across the docs, one for fidelity to the evidence, one for whether it can be built. They found 61 issues, 3 of them blockers, and all are fixed. The most important ones:

  • An echo is now recognised by sequence number, not by comparing text; the text comparison would have silently dropped a redo.
  • Events are applied in order.
  • The server's checks are written down, with a resync when it refuses an event.
  • A paused selection run whose paragraphs changed now fails instead of splicing at stale positions.
  • A large paste is sent in chunks, because it would exceed SignalR's 32 KB message limit.
  • M2 already displays bold and italic, so emphasis a run writes is never stripped by the writer's next edit.

Jibril then approved the PR.

Not verified yet

These are listed in the ADR as risks the first slices must retire:

  • Safari: WebKit would not start on the build host.
  • Real input methods: Japanese input and German dead keys were only simulated.
  • Screen readers: none was run.
  • The Edit menu's undo in Firefox and Safari.
  • Long chapters.

🤖 Generated with Claude Code

> **Rebased onto main after #30.** Image fields took ADR number 0029, so this ADR is now **0030**. All of this PR's references were renumbered; image fields' own 0029 references are untouched. Where the two PRs amended the same ADR (0017, 0027) or the ADR index, both amendments are kept. The branch is now one squashed commit plus a README rewrap. As Jibril suggested, the plan's M2 bullet is split into *the surface*, *the migration* and *the proof*. This is a docs-only PR. It proposes **ADR 0030** and the amendments it needs. It answers your ask for an editor where you can select any part of the text, right-click for AI actions, and see and edit bold and italic. ## Why the editor has to change Today every paragraph is its own `<textarea>`. A browser cannot hold one selection across two textareas, so ADR 0023's promise, *"select two paragraphs, right-click, expand"*, has nothing to select. A textarea also cannot show formatting. The ADR replaces the column with **one editable surface per chapter**, built on **ProseMirror**. It follows the graph editor's precedent (ADR 0021): JavaScript handles keystrokes and selection locally, and .NET receives one call per typing pause or structural edit. ## How ProseMirror was chosen 1. **Evaluation:** five libraries were rated against 14 criteria: ProseMirror (with Tiptap), Lexical, CodeMirror 6, Slate and Quill 2. Each one got a prototype. 2. **Spikes:** the two strongest, ProseMirror and Lexical, were built as working editors and tested in real Chrome 153 and Firefox 155. Both passed. 3. **Why ProseMirror won:** - One rule keeps a paragraph read-only while a run rewrites it. Lexical needed three layers of workarounds. - Its API has been stable on 1.x since 2017. Lexical is pre-1.0 and ships breaking changes. - It is smaller: about 67 KB gzip against 74–77 KB. - Lexical stays the named fallback. 4. **Where the spikes corrected the first-round research:** - A preview inside the editor lost keystrokes in Firefox, so the streaming preview now sits outside it. - Pasting could move a paragraph's id, so the ADR adds id rules for paste, drop and Enter. - Chrome's own Ctrl+B during Japanese input corrupted the text, so all native formatting commands are cancelled. - Standard Markdown rules measurably lost formatting, so the ADR defines its own small dialect. ## Three decisions for you These are recommended answers. Change any of them before accepting. **1. Undo stays the journal's.** - The editor keeps no history of its own. One undo step is one typing pause, and a split, merge, paste or formatting toggle is its own step. - The cost: no word-by-word undo inside a burst you haven't paused in. - *Alternative:* the editor undoes keystrokes within a pause and the journal takes over after it. The catch is two undo stacks, and what Ctrl+Z does would depend on whether 700 ms had passed. **2. A selection can cover part of a paragraph.** - When a run rewrites one sentence, the paragraph keeps its identity. It is marked as the run's and flagged *edited*, which now means "not purely its original author's words". The gutter points to the run that touched it, and Revert run restores the original word for word. - *Alternatives:* - allow only whole paragraphs, so rewriting a sentence regenerates the whole paragraph; - split the paragraph into before, run and after pieces, so one paragraph becomes three; - track exact character ranges per author, possible as a later refinement. **3. Formatting.** - Bold and italic only, stored inside the paragraph's text as `**bold**` and `*italic*`. - It is our own strict dialect. The standard Markdown rules lost formatting in 1,310 of 20,000 random test documents, while this dialect passed 5,000 of 5,000. - The existing text is migrated once so literal asterisks stay literal, and the undo journal's copies are migrated with it. - *Alternatives:* more marks such as underline or strikethrough, or storing the formatting as structured data beside the text instead of inside it. ## What the PR changes - **New:** `docs/adr/0030-manuscript-editor.md`. - **Amended ADRs:** each gets a dated amendment line, plus body fixes wherever a sentence became false. - **0002** (no keystrokes over the circuit) - **0004** (external packages) - **0008** (Docker) - **0009** (Kagaku.UI) - **0012** (segment text format and `edited`) - **0015** (`commit` replace over a range) - **0017** (what models see, the selection's context) - **0019** (manuscript tools) - **0021** (a second JS module) - **0022** (undo, and format-changing migrations) - **0023** (the selection input and the menu) - **0027** (chapter page, preview position) - **Updated to match:** - `REQUIREMENTS.md`: a new §2 item, marked MVP; - `stories/story-workspace.md`; - `PROJECT_PLAN.md`: a new **manuscript editor track** beside Phase 2, slices M0 to M5; - `AGENTS.md`: a new rule that code writing paragraph text goes through the codec, from M2 on; - `ARCHITECTURE.md`, `README.md` and the ADR index. ## Relation to Phase 2 - The track never touches `Kagaku.Flow`. - Two hand-offs are written into the plan: - Phase 2's slice 9 turns a `***` paragraph into a scene break; - whichever of M2 and slice 9 lands second gives `commit` its model-output reader. - Slice 12 (the Run button and the streaming preview) does not wait for the new editor. ## Review so far Before this PR opened, three independent reviewers read the draft: one for consistency across the docs, one for fidelity to the evidence, one for whether it can be built. They found 61 issues, 3 of them blockers, and all are fixed. The most important ones: - An echo is now recognised by sequence number, not by comparing text; the text comparison would have silently dropped a redo. - Events are applied in order. - The server's checks are written down, with a resync when it refuses an event. - A paused selection run whose paragraphs changed now fails instead of splicing at stale positions. - A large paste is sent in chunks, because it would exceed SignalR's 32 KB message limit. - M2 already displays bold and italic, so emphasis a run writes is never stripped by the writer's next edit. Jibril then approved the PR. ## Not verified yet These are listed in the ADR as risks the first slices must retire: - **Safari:** WebKit would not start on the build host. - **Real input methods:** Japanese input and German dead keys were only simulated. - **Screen readers:** none was run. - **The Edit menu's undo in Firefox and Safari.** - **Long chapters.** 🤖 Generated with [Claude Code](https://claude.com/claude-code)
One ProseMirror surface per chapter whose blocks are the segments; selections across and inside
paragraphs for the selection graphs; bold and italic as Tsumugi inline markup in the segment text;
undo stays the journal's. Amends ADR 0004, 0009, 0012, 0015, 0017, 0021, 0022, 0023 and 0027; the
requirements, the workspace story, the plan's editor track and an AGENTS.md write-path rule follow.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs: ADR 0029 after review — sequence-based echoes, in-order events, the splice rule, the server's checks, M2 displays marks
Some checks failed
CI / test (pull_request) Has been cancelled
CI / build (pull_request) Has been cancelled
2172a39c03
A three-lens review (consistency, evidence, implementability) found three blockers and a few dozen
gaps. The echo rule compares sequences, not text, so a redo is never dropped; events apply in order
and flush() resolves when journaled; split and merge say which paragraph keeps its id; the server's
checks, the refusal resync, chunked reshapes and the stale-selection rule are written down; M2 already
displays bold and italic; the AGENTS.md write-path rule starts with M2's migration. ADR 0002, 0008 and
0019 are amended too, the measurements are stated as measured, and the stories, requirements, README
and ARCHITECTURE agree.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs: ADR 0029 and its amendments name their PR, #31
All checks were successful
CI / build (pull_request) Successful in 35s
CI / test (pull_request) Successful in 1m0s
136d8291e5
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: 9a59ac3 · Generated: 2026-09-25 21:44:28 UTC · Revision: #3

Summary

Summary
Generated on: 09/25/2026 - 21:44:28
Coverage date: 09/25/2026 - 21:44:02 - 09/25/2026 - 21:44:24
Parser: MultiReport (6x Cobertura)
Assemblies: 9
Classes: 437
Files: 416
Line coverage: 97.7% (12696 of 12991)
Covered lines: 12696
Uncovered lines: 295
Coverable lines: 12991
Total lines: 27780
Branch coverage: 93.3% (4562 of 4889)
Covered branches: 4562
Total branches: 4889
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.OpenRouterGateway 100% 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions 100%
Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup 100% 100%
Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions 100% 100%
Kagaku.Flow.Testing - 100%
Name Line Branch
Kagaku.Flow.Testing 100% 100%
Kagaku.Flow.Testing.FlowEngineDriver 100% 100%
Kagaku.Flow.Testing.InMemoryRunLedger 100% 100%
Kagaku.Flow.Testing.RecordingRunEventSink 100%
Kagaku.Flow.Testing.RunLedgerContract 100% 100%
Kagaku.Flow.Testing.RunLedgerContractException 100%
Tsumugi.BlazorAdapter - 96.4%
Name Line Branch
Tsumugi.BlazorAdapter 96.4% 92.6%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 91.8% 87.2%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 94.1%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 95.1% 88.8%
Tsumugi.BlazorAdapter.Documents.DocumentImageRefused 100%
Tsumugi.BlazorAdapter.Documents.DocumentImageSet 100%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.2% 92.4%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsRefusal 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldInput 100% 96.6%
Tsumugi.BlazorAdapter.Documents.FieldsChanges 100% 100%
Tsumugi.BlazorAdapter.Documents.FieldShapes 90% 87.5%
Tsumugi.BlazorAdapter.Documents.ImageUpload 100%
Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal 100%
Tsumugi.BlazorAdapter.Documents.ImpactText 100% 94.2%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog 95.6% 71.4%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested 100%
Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter 100%
Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested 100%
Tsumugi.BlazorAdapter.Graphs.GraphCanvas 37.5% 25%
Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage 20% 25%
Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge 94.4% 83.3%
Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived 75% 100%
Tsumugi.BlazorAdapter.Runs.RunChangedBridge 97.1% 90.6%
Tsumugi.BlazorAdapter.Runs.RunChangesReceived 100%
Tsumugi.BlazorAdapter.Runs.RunTextReceived 100%
Tsumugi.BlazorAdapter.Settings.BackupCompleted 100%
Tsumugi.BlazorAdapter.Settings.BackupFailed 100%
Tsumugi.BlazorAdapter.Settings.BackupNowRequested 100%
Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.BackupsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.BackupsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSection 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved 100%
Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed 100%
Tsumugi.BlazorAdapter.Settings.LoadBackupSettings 100%
Tsumugi.BlazorAdapter.Settings.LoadProviderSettings 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded 100%
Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved 100%
Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed 100%
Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked 100%
Tsumugi.BlazorAdapter.Settings.ProviderSection 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsState 100% 100%
Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested 100%
Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested 100%
Tsumugi.BlazorAdapter.Stories.CreateStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested 100%
Tsumugi.BlazorAdapter.Stories.SetShowArchived 100%
Tsumugi.BlazorAdapter.Stories.SetStoriesFilter 100%
Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested 100%
Tsumugi.BlazorAdapter.Stories.StoriesEffects 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesLoaded 100%
Tsumugi.BlazorAdapter.Stories.StoriesPage 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesReducers 100% 100%
Tsumugi.BlazorAdapter.Stories.StoriesState 100% 100%
Tsumugi.BlazorAdapter.Stories.StoryActionFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryCreated 100%
Tsumugi.BlazorAdapter.Stories.StoryCreateFailed 100%
Tsumugi.BlazorAdapter.Stories.StoryTrashPage 100% 100%
Tsumugi.BlazorAdapter.Stories.TrashStoryRequested 100%
Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed 100%
Tsumugi.BlazorAdapter.Workspace.CaretRequest 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 90% 83.3%
Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.DeleteSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.EditSegmentRequested 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.InsertSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.LoadHistory 100%
Tsumugi.BlazorAdapter.Workspace.LoadWorkspace 100%
Tsumugi.BlazorAdapter.Workspace.ManuscriptColumn 94.9% 89.4%
Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects 100% 100%
Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.MergeSegmentRequested 100%
Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRequested 100%
Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested 100%
Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested 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.SegmentRow 100% 96.8%
Tsumugi.BlazorAdapter.Workspace.SegmentSaved 100%
Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested 100%
Tsumugi.BlazorAdapter.Workspace.SplitSegmentRequested 100%
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 - 95.6%
Name Line Branch
Tsumugi.Domain 95.6% 93.9%
System.Text.RegularExpressions.Generated 90.7% 87.5%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2
97.4% 95.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0
91% 91.1%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1
86.4% 77.7%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4
91.9% 88.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25
BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3
90.9% 84.3%
Tsumugi.Domain.Documents.CategoryFields 94.5% 93.7%
Tsumugi.Domain.Documents.ChoiceOption 100%
Tsumugi.Domain.Documents.ChoiceValue 100%
Tsumugi.Domain.Documents.DateText 100%
Tsumugi.Domain.Documents.DateValue 100%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 100% 100%
Tsumugi.Domain.Documents.DocumentValues 100%
Tsumugi.Domain.Documents.FieldCarry 100% 100%
Tsumugi.Domain.Documents.FieldConversion 100% 100%
Tsumugi.Domain.Documents.FieldDefinition 97% 95.3%
Tsumugi.Domain.Documents.FieldMessages 100% 100%
Tsumugi.Domain.Documents.FieldNames 100%
Tsumugi.Domain.Documents.FieldsChange 100%
Tsumugi.Domain.Documents.FieldShape 95.2% 87.5%
Tsumugi.Domain.Documents.FieldsPlan 100%
Tsumugi.Domain.Documents.FieldsPlanner 99.2% 98.5%
Tsumugi.Domain.Documents.FieldValue 100%
Tsumugi.Domain.Documents.FieldValues 95.4% 97.7%
Tsumugi.Domain.Documents.ImageFiles 100% 100%
Tsumugi.Domain.Documents.ImageValue 100%
Tsumugi.Domain.Documents.MovePlan 100%
Tsumugi.Domain.Documents.NumberParse 100%
Tsumugi.Domain.Documents.NumberText 100% 97.6%
Tsumugi.Domain.Documents.NumberValue 100%
Tsumugi.Domain.Documents.StoryImage 100%
Tsumugi.Domain.Documents.TextValue 100% 100%
Tsumugi.Domain.Documents.ValueChange 100%
Tsumugi.Domain.Documents.ValueChangeKey 100%
Tsumugi.Domain.Documents.ValueImpact 100% 100%
Tsumugi.Domain.Journal.ChangeLogEntry 97.8% 75%
Tsumugi.Domain.Journal.StorySnapshot 95.4% 83.3%
Tsumugi.Domain.Settings.AppSetting 100%
Tsumugi.Domain.Stories.Chapter 100% 100%
Tsumugi.Domain.Stories.Provenance 100% 100%
Tsumugi.Domain.Stories.Segment 100% 100%
Tsumugi.Domain.Stories.Story 100% 100%
Tsumugi.Domain.Text 100% 100%
Tsumugi.Infrastructure - 97.6%
Name Line Branch
Tsumugi.Infrastructure 97.6% 85.9%
System.Text.RegularExpressions.Generated 81.4% 64.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C
A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0
84% 65.7%
Tsumugi.Infrastructure.Backups.BackupArtifactName 100% 100%
Tsumugi.Infrastructure.Backups.BackupOptions 100%
Tsumugi.Infrastructure.Backups.BackupSchedule 100% 83.3%
Tsumugi.Infrastructure.Backups.BackupScheduler 96.5% 83.3%
Tsumugi.Infrastructure.Backups.BackupWriter 98.5% 92.5%
Tsumugi.Infrastructure.Backups.DatabaseFingerprint 91.9% 97%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 100%
Tsumugi.Infrastructure.Backups.PreMigrationBackup 89.1% 100%
Tsumugi.Infrastructure.Backups.SqliteSnapshot 87.8% 75%
Tsumugi.Infrastructure.DependencyInjection 100% 100%
Tsumugi.Infrastructure.Journal.EfChangeJournal 100%
Tsumugi.Infrastructure.Journal.EfSnapshotStore 100%
Tsumugi.Infrastructure.Journal.EfUndoStore 98.1% 85.7%
Tsumugi.Infrastructure.Journal.ModelExtensions 100%
Tsumugi.Infrastructure.Journal.OperationContext 100% 100%
Tsumugi.Infrastructure.Journal.PropertyBag 100% 95.4%
Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus 100% 100%
Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati
on
100%
Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura
tion
100%
Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StoryImageConfiguration 100%
Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio
n
100%
Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer 100%
Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter 97.6% 94.4%
Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter 96.9% 93.7%
Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter 100% 90%
Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Tsumugi.Infrastructure.Persistence.Converters.WireFormat 85.7% 73.8%
Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings 99.2%
Tsumugi.Infrastructure.Persistence.Migrations.AddJournal 98.8%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields 100% 100%
Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql 100%
Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody 100%
Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments 100%
Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain 97.3%
Tsumugi.Infrastructure.Persistence.Migrations.StoryImages 100%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
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 95% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.7% 90%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 85.5% 89.2%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 0%
Tsumugi.Infrastructure.Provider.OpenRouterKeySource 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterModelProvider 100% 100%
Tsumugi.Infrastructure.Provider.OpenRouterOptions 100% 100%
Tsumugi.Infrastructure.Provider.ResolvedKey 100%
Tsumugi.Infrastructure.Runs.InProcessRunEventBus 100% 100%
Tsumugi.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Tsumugi.Kernel - 90.9%
Name Line Branch
Tsumugi.Kernel 90.9% 75%
Tsumugi.Kernel.Err`1 100%
Tsumugi.Kernel.Ok`1 100%
Tsumugi.Kernel.Result`1 88.8% 75%
Tsumugi.Server - 100%
Name Line Branch
Tsumugi.Server 100% 86.4%
Program 100% 100%
Tsumugi.Server.Backups.BackupConfiguration 100% 100%
Tsumugi.Server.Components.App 100%
Tsumugi.Server.Components.Layout.AppHeader 100% 50%
Tsumugi.Server.Components.Layout.MainLayout 100%
Tsumugi.Server.Components.Pages.Gate 100% 100%
Tsumugi.Server.Provider.OpenRouterConfiguration 100% 100%
Tsumugi.Server.Security.AccessGate 100% 66.6%
Tsumugi.Server.Security.AccessSecret 100% 50%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98.3%
Name Line Branch
Tsumugi.UseCases 98.3% 93.5%
Tsumugi.UseCases.Backups.BackupArtifact 100%
Tsumugi.UseCases.Backups.BackupPolicy 100%
Tsumugi.UseCases.Backups.BackupStatusView 100% 100%
Tsumugi.UseCases.Backups.DatabaseSnapshot 100%
Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot 100%
Tsumugi.UseCases.Backups.GetBackupStatus 100%
Tsumugi.UseCases.Backups.RunBackupNow 100%
Tsumugi.UseCases.Chapters.ChapterDto 100%
Tsumugi.UseCases.Chapters.CreateChapter 100% 100%
Tsumugi.UseCases.Chapters.DeleteChapter 100% 100%
Tsumugi.UseCases.Chapters.GetManuscript 100% 100%
Tsumugi.UseCases.Chapters.ManuscriptChapter 100%
Tsumugi.UseCases.Chapters.ManuscriptView 100%
Tsumugi.UseCases.Chapters.MergeChapters 100% 100%
Tsumugi.UseCases.Chapters.RenameChapter 100% 100%
Tsumugi.UseCases.Chapters.ReorderChapters 100% 100%
Tsumugi.UseCases.Chapters.SetChapterSummary 100% 75%
Tsumugi.UseCases.DependencyInjection 100%
Tsumugi.UseCases.Diagnostics.SeedDevData 98.2% 71.4%
Tsumugi.UseCases.Diagnostics.SeedPictures 100%
Tsumugi.UseCases.Documents.ChangeCategoryFields 100% 83.3%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DefaultFields 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 94.4%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentPatch 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.DocumentWrites 100% 100%
Tsumugi.UseCases.Documents.FieldsChangeLabel 95.4% 88.2%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.GetStoryImage 100% 100%
Tsumugi.UseCases.Documents.ImpactPreview 100% 100%
Tsumugi.UseCases.Documents.LossMessages 92.3% 87.5%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.SetDocumentImage 100% 93.7%
Tsumugi.UseCases.Documents.StoryImageFile 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 81.2%
Tsumugi.UseCases.Journal.GetStoryHistory 100% 100%
Tsumugi.UseCases.Journal.GetUndoStatus 100% 100%
Tsumugi.UseCases.Journal.HistoryOperation 66.6%
Tsumugi.UseCases.Journal.HistorySnapshot 87.5%
Tsumugi.UseCases.Journal.OperationGrouping 100% 100%
Tsumugi.UseCases.Journal.RedoRevert 100% 100%
Tsumugi.UseCases.Journal.RedoRun 75% 57.1%
Tsumugi.UseCases.Journal.RedoTyping 100% 100%
Tsumugi.UseCases.Journal.RevertConflict 100%
Tsumugi.UseCases.Journal.RevertOutcome 100%
Tsumugi.UseCases.Journal.RevertRun 96.5% 77.7%
Tsumugi.UseCases.Journal.RevertToSnapshot 92.3% 83.3%
Tsumugi.UseCases.Journal.StoryHistory 100%
Tsumugi.UseCases.Journal.TakeSnapshot 100% 87.5%
Tsumugi.UseCases.Journal.UndoStatus 100%
Tsumugi.UseCases.Journal.UndoTyping 100% 100%
Tsumugi.UseCases.Journal.UserOperation 100%
Tsumugi.UseCases.Notifications.DomainChanged 100%
Tsumugi.UseCases.Ordering 100% 100%
Tsumugi.UseCases.Runs.RunEvent 100%
Tsumugi.UseCases.Segments.DeleteSegments 100% 100%
Tsumugi.UseCases.Segments.EditSegment 100% 83.3%
Tsumugi.UseCases.Segments.InsertSegment 100% 100%
Tsumugi.UseCases.Segments.MergeSegmentWithPrevious 100% 100%
Tsumugi.UseCases.Segments.MoveSegments 100% 100%
Tsumugi.UseCases.Segments.ReorderSegments 100% 100%
Tsumugi.UseCases.Segments.SegmentDto 100%
Tsumugi.UseCases.Segments.SplitSegment 100% 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.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:** `9a59ac3` · **Generated:** 2026-09-25 21:44:28 UTC · **Revision:** #3 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/25/2026 - 21:44:28 | | Coverage date: | 09/25/2026 - 21:44:02 - 09/25/2026 - 21:44:24 | | Parser: | MultiReport (6x Cobertura) | | Assemblies: | 9 | | Classes: | 437 | | Files: | 416 | | **Line coverage:** | 97.7% (12696 of 12991) | | Covered lines: | 12696 | | Uncovered lines: | 295 | | Coverable lines: | 12991 | | Total lines: | 27780 | | **Branch coverage:** | 93.3% (4562 of 4889) | | Covered branches: | 4562 | | Total branches: | 4889 | | **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.OpenRouterGateway|100%|100%| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterGatewayOptions|100%|| |Kagaku.Flow.OpenRouter.Gateway.OpenRouterKeyLookup|100%|100%| |Kagaku.Flow.OpenRouter.OpenRouterServiceCollectionExtensions|100%|100%| </details> <details><summary>Kagaku.Flow.Testing - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagaku.Flow.Testing**|**100%**|**100%**| |Kagaku.Flow.Testing.FlowEngineDriver|100%|100%| |Kagaku.Flow.Testing.InMemoryRunLedger|100%|100%| |Kagaku.Flow.Testing.RecordingRunEventSink|100%|| |Kagaku.Flow.Testing.RunLedgerContract|100%|100%| |Kagaku.Flow.Testing.RunLedgerContractException|100%|| </details> <details><summary>Tsumugi.BlazorAdapter - 96.4%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**96.4%**|**92.6%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|91.8%|87.2%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.ChangeCategoryFieldsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryChoice|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|94.1%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|95.1%|88.8%| |Tsumugi.BlazorAdapter.Documents.DocumentImageRefused|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentImageSet|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.2%|92.4%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldInput|100%|96.6%| |Tsumugi.BlazorAdapter.Documents.FieldsChanges|100%|100%| |Tsumugi.BlazorAdapter.Documents.FieldShapes|90%|87.5%| |Tsumugi.BlazorAdapter.Documents.ImageUpload|100%|| |Tsumugi.BlazorAdapter.Documents.ImageUploadRefusal|100%|| |Tsumugi.BlazorAdapter.Documents.ImpactText|100%|94.2%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentChoice|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentDialog|95.6%|71.4%| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentImageRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetDocumentsFilter|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.UpdateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Graphs.GraphCanvas|37.5%|25%| |Tsumugi.BlazorAdapter.Graphs.GraphPlaygroundPage|20%|25%| |Tsumugi.BlazorAdapter.Notifications.DomainChangedBridge|94.4%|83.3%| |Tsumugi.BlazorAdapter.Notifications.DomainChangesReceived|75%|100%| |Tsumugi.BlazorAdapter.Runs.RunChangedBridge|97.1%|90.6%| |Tsumugi.BlazorAdapter.Runs.RunChangesReceived|100%|| |Tsumugi.BlazorAdapter.Runs.RunTextReceived|100%|| |Tsumugi.BlazorAdapter.Settings.BackupCompleted|100%|| |Tsumugi.BlazorAdapter.Settings.BackupFailed|100%|| |Tsumugi.BlazorAdapter.Settings.BackupNowRequested|100%|| |Tsumugi.BlazorAdapter.Settings.BackupSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.BackupsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.DefaultsSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaved|100%|| |Tsumugi.BlazorAdapter.Settings.LlmDefaultsSaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.LoadBackupSettings|100%|| |Tsumugi.BlazorAdapter.Settings.LoadProviderSettings|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ModelCatalogLoadFailed|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaved|100%|| |Tsumugi.BlazorAdapter.Settings.OpenRouterKeySaveFailed|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderKeyChecked|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsState|100%|100%| |Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested|100%|| |Tsumugi.BlazorAdapter.Settings.SaveOpenRouterKeyRequested|100%|| |Tsumugi.BlazorAdapter.Stories.CreateStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.PurgeStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.RestoreStoryRequested|100%|| |Tsumugi.BlazorAdapter.Stories.SetShowArchived|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoriesFilter|100%|| |Tsumugi.BlazorAdapter.Stories.SetStoryArchivedRequested|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesEffects|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesLoaded|100%|| |Tsumugi.BlazorAdapter.Stories.StoriesPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesReducers|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoriesState|100%|100%| |Tsumugi.BlazorAdapter.Stories.StoryActionFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreated|100%|| |Tsumugi.BlazorAdapter.Stories.StoryCreateFailed|100%|| |Tsumugi.BlazorAdapter.Stories.StoryTrashPage|100%|100%| |Tsumugi.BlazorAdapter.Stories.TrashStoryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.AutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Workspace.CaretRequest|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|90%|83.3%| |Tsumugi.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.DeleteSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.EditSegmentRequested|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.InsertSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadHistory|100%|| |Tsumugi.BlazorAdapter.Workspace.LoadWorkspace|100%|| |Tsumugi.BlazorAdapter.Workspace.ManuscriptColumn|94.9%|89.4%| |Tsumugi.BlazorAdapter.Workspace.ManuscriptEffects|100%|100%| |Tsumugi.BlazorAdapter.Workspace.MergeChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MergeSegmentRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.MoveChapterRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RedoRevertRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.RenameChapterRequested|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.SegmentRow|100%|96.8%| |Tsumugi.BlazorAdapter.Workspace.SegmentSaved|100%|| |Tsumugi.BlazorAdapter.Workspace.SetChapterSummaryRequested|100%|| |Tsumugi.BlazorAdapter.Workspace.SplitSegmentRequested|100%|| |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 - 95.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**95.6%**|**93.9%**| |System.Text.RegularExpressions.Generated|90.7%|87.5%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__DigitsAndSeparators_2|97.4%|95.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__LineBreak_0|91%|91.1%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__NumberToken_1|86.4%|77.7%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__Plain_4|91.9%|88.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F5BB471BFAD87E25<br/>BE2A118445F5EE9A5FB1F861C394AC933A547F31011ADF02F__ThousandsGroup_3|90.9%|84.3%| |Tsumugi.Domain.Documents.CategoryFields|94.5%|93.7%| |Tsumugi.Domain.Documents.ChoiceOption|100%|| |Tsumugi.Domain.Documents.ChoiceValue|100%|| |Tsumugi.Domain.Documents.DateText|100%|| |Tsumugi.Domain.Documents.DateValue|100%|| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|100%|100%| |Tsumugi.Domain.Documents.DocumentValues|100%|| |Tsumugi.Domain.Documents.FieldCarry|100%|100%| |Tsumugi.Domain.Documents.FieldConversion|100%|100%| |Tsumugi.Domain.Documents.FieldDefinition|97%|95.3%| |Tsumugi.Domain.Documents.FieldMessages|100%|100%| |Tsumugi.Domain.Documents.FieldNames|100%|| |Tsumugi.Domain.Documents.FieldsChange|100%|| |Tsumugi.Domain.Documents.FieldShape|95.2%|87.5%| |Tsumugi.Domain.Documents.FieldsPlan|100%|| |Tsumugi.Domain.Documents.FieldsPlanner|99.2%|98.5%| |Tsumugi.Domain.Documents.FieldValue|100%|| |Tsumugi.Domain.Documents.FieldValues|95.4%|97.7%| |Tsumugi.Domain.Documents.ImageFiles|100%|100%| |Tsumugi.Domain.Documents.ImageValue|100%|| |Tsumugi.Domain.Documents.MovePlan|100%|| |Tsumugi.Domain.Documents.NumberParse|100%|| |Tsumugi.Domain.Documents.NumberText|100%|97.6%| |Tsumugi.Domain.Documents.NumberValue|100%|| |Tsumugi.Domain.Documents.StoryImage|100%|| |Tsumugi.Domain.Documents.TextValue|100%|100%| |Tsumugi.Domain.Documents.ValueChange|100%|| |Tsumugi.Domain.Documents.ValueChangeKey|100%|| |Tsumugi.Domain.Documents.ValueImpact|100%|100%| |Tsumugi.Domain.Journal.ChangeLogEntry|97.8%|75%| |Tsumugi.Domain.Journal.StorySnapshot|95.4%|83.3%| |Tsumugi.Domain.Settings.AppSetting|100%|| |Tsumugi.Domain.Stories.Chapter|100%|100%| |Tsumugi.Domain.Stories.Provenance|100%|100%| |Tsumugi.Domain.Stories.Segment|100%|100%| |Tsumugi.Domain.Stories.Story|100%|100%| |Tsumugi.Domain.Text|100%|100%| </details> <details><summary>Tsumugi.Infrastructure - 97.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**97.6%**|**85.9%**| |System.Text.RegularExpressions.Generated|81.4%|64.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F0D076C66E8EEC1C<br/>A55E0373ED22DC58420DBB40F103A46B68DC4D9CE5A49E00B__Pattern_0|84%|65.7%| |Tsumugi.Infrastructure.Backups.BackupArtifactName|100%|100%| |Tsumugi.Infrastructure.Backups.BackupOptions|100%|| |Tsumugi.Infrastructure.Backups.BackupSchedule|100%|83.3%| |Tsumugi.Infrastructure.Backups.BackupScheduler|96.5%|83.3%| |Tsumugi.Infrastructure.Backups.BackupWriter|98.5%|92.5%| |Tsumugi.Infrastructure.Backups.DatabaseFingerprint|91.9%|97%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|100%| |Tsumugi.Infrastructure.Backups.PreMigrationBackup|89.1%|100%| |Tsumugi.Infrastructure.Backups.SqliteSnapshot|87.8%|75%| |Tsumugi.Infrastructure.DependencyInjection|100%|100%| |Tsumugi.Infrastructure.Journal.EfChangeJournal|100%|| |Tsumugi.Infrastructure.Journal.EfSnapshotStore|100%|| |Tsumugi.Infrastructure.Journal.EfUndoStore|98.1%|85.7%| |Tsumugi.Infrastructure.Journal.ModelExtensions|100%|| |Tsumugi.Infrastructure.Journal.OperationContext|100%|100%| |Tsumugi.Infrastructure.Journal.PropertyBag|100%|95.4%| |Tsumugi.Infrastructure.Notifications.InProcessDomainChangedBus|100%|100%| |Tsumugi.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChangeLogEntryConfigurati<br/>on|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.ChapterConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentCategoryConfigura<br/>tion|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.DocumentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.SegmentConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StoryConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StoryImageConfiguration|100%|| |Tsumugi.Infrastructure.Persistence.Configurations.StorySnapshotConfiguratio<br/>n|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CanonicalJsonComparer|100%|| |Tsumugi.Infrastructure.Persistence.Converters.CategoryFieldsConverter|97.6%|94.4%| |Tsumugi.Infrastructure.Persistence.Converters.FieldValuesConverter|96.9%|93.7%| |Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter|100%|90%| |Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Tsumugi.Infrastructure.Persistence.Converters.WireFormat|85.7%|73.8%| |Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings|99.2%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddJournal|98.8%|| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFields|100%|100%| |Tsumugi.Infrastructure.Persistence.Migrations.CategoryFieldsSql|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.DropDocumentBody|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain|97.3%|| |Tsumugi.Infrastructure.Persistence.Migrations.StoryImages|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |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|95%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.7%|90%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|85.5%|89.2%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|0%|| |Tsumugi.Infrastructure.Provider.OpenRouterKeySource|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterModelProvider|100%|100%| |Tsumugi.Infrastructure.Provider.OpenRouterOptions|100%|100%| |Tsumugi.Infrastructure.Provider.ResolvedKey|100%|| |Tsumugi.Infrastructure.Runs.InProcessRunEventBus|100%|100%| |Tsumugi.Infrastructure.Settings.EfAppSettingsStore|100%|100%| </details> <details><summary>Tsumugi.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Kernel**|**90.9%**|**75%**| |Tsumugi.Kernel.Err`1|100%|| |Tsumugi.Kernel.Ok`1|100%|| |Tsumugi.Kernel.Result`1|88.8%|75%| </details> <details><summary>Tsumugi.Server - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Server**|**100%**|**86.4%**| |Program|100%|100%| |Tsumugi.Server.Backups.BackupConfiguration|100%|100%| |Tsumugi.Server.Components.App|100%|| |Tsumugi.Server.Components.Layout.AppHeader|100%|50%| |Tsumugi.Server.Components.Layout.MainLayout|100%|| |Tsumugi.Server.Components.Pages.Gate|100%|100%| |Tsumugi.Server.Provider.OpenRouterConfiguration|100%|100%| |Tsumugi.Server.Security.AccessGate|100%|66.6%| |Tsumugi.Server.Security.AccessSecret|100%|50%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98.3%**|**93.5%**| |Tsumugi.UseCases.Backups.BackupArtifact|100%|| |Tsumugi.UseCases.Backups.BackupPolicy|100%|| |Tsumugi.UseCases.Backups.BackupStatusView|100%|100%| |Tsumugi.UseCases.Backups.DatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.DownloadDatabaseSnapshot|100%|| |Tsumugi.UseCases.Backups.GetBackupStatus|100%|| |Tsumugi.UseCases.Backups.RunBackupNow|100%|| |Tsumugi.UseCases.Chapters.ChapterDto|100%|| |Tsumugi.UseCases.Chapters.CreateChapter|100%|100%| |Tsumugi.UseCases.Chapters.DeleteChapter|100%|100%| |Tsumugi.UseCases.Chapters.GetManuscript|100%|100%| |Tsumugi.UseCases.Chapters.ManuscriptChapter|100%|| |Tsumugi.UseCases.Chapters.ManuscriptView|100%|| |Tsumugi.UseCases.Chapters.MergeChapters|100%|100%| |Tsumugi.UseCases.Chapters.RenameChapter|100%|100%| |Tsumugi.UseCases.Chapters.ReorderChapters|100%|100%| |Tsumugi.UseCases.Chapters.SetChapterSummary|100%|75%| |Tsumugi.UseCases.DependencyInjection|100%|| |Tsumugi.UseCases.Diagnostics.SeedDevData|98.2%|71.4%| |Tsumugi.UseCases.Diagnostics.SeedPictures|100%|| |Tsumugi.UseCases.Documents.ChangeCategoryFields|100%|83.3%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DefaultFields|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|94.4%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentPatch|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.DocumentWrites|100%|100%| |Tsumugi.UseCases.Documents.FieldsChangeLabel|95.4%|88.2%| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.GetStoryImage|100%|100%| |Tsumugi.UseCases.Documents.ImpactPreview|100%|100%| |Tsumugi.UseCases.Documents.LossMessages|92.3%|87.5%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.SetDocumentImage|100%|93.7%| |Tsumugi.UseCases.Documents.StoryImageFile|100%|| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|81.2%| |Tsumugi.UseCases.Journal.GetStoryHistory|100%|100%| |Tsumugi.UseCases.Journal.GetUndoStatus|100%|100%| |Tsumugi.UseCases.Journal.HistoryOperation|66.6%|| |Tsumugi.UseCases.Journal.HistorySnapshot|87.5%|| |Tsumugi.UseCases.Journal.OperationGrouping|100%|100%| |Tsumugi.UseCases.Journal.RedoRevert|100%|100%| |Tsumugi.UseCases.Journal.RedoRun|75%|57.1%| |Tsumugi.UseCases.Journal.RedoTyping|100%|100%| |Tsumugi.UseCases.Journal.RevertConflict|100%|| |Tsumugi.UseCases.Journal.RevertOutcome|100%|| |Tsumugi.UseCases.Journal.RevertRun|96.5%|77.7%| |Tsumugi.UseCases.Journal.RevertToSnapshot|92.3%|83.3%| |Tsumugi.UseCases.Journal.StoryHistory|100%|| |Tsumugi.UseCases.Journal.TakeSnapshot|100%|87.5%| |Tsumugi.UseCases.Journal.UndoStatus|100%|| |Tsumugi.UseCases.Journal.UndoTyping|100%|100%| |Tsumugi.UseCases.Journal.UserOperation|100%|| |Tsumugi.UseCases.Notifications.DomainChanged|100%|| |Tsumugi.UseCases.Ordering|100%|100%| |Tsumugi.UseCases.Runs.RunEvent|100%|| |Tsumugi.UseCases.Segments.DeleteSegments|100%|100%| |Tsumugi.UseCases.Segments.EditSegment|100%|83.3%| |Tsumugi.UseCases.Segments.InsertSegment|100%|100%| |Tsumugi.UseCases.Segments.MergeSegmentWithPrevious|100%|100%| |Tsumugi.UseCases.Segments.MoveSegments|100%|100%| |Tsumugi.UseCases.Segments.ReorderSegments|100%|100%| |Tsumugi.UseCases.Segments.SegmentDto|100%|| |Tsumugi.UseCases.Segments.SplitSegment|100%|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.CreateStory|100%|100%| |Tsumugi.UseCases.Stories.GetStory|100%|100%| |Tsumugi.UseCases.Stories.ListStories|100%|75%| |Tsumugi.UseCases.Stories.PurgeStory|100%|100%| |Tsumugi.UseCases.Stories.RestoreStory|100%|100%| |Tsumugi.UseCases.Stories.SetActiveGraph|100%|100%| |Tsumugi.UseCases.Stories.SetStoryArchived|100%|100%| |Tsumugi.UseCases.Stories.StarterCategories|100%|| |Tsumugi.UseCases.Stories.StoryDetail|100%|| |Tsumugi.UseCases.Stories.StoryListItem|81.8%|| |Tsumugi.UseCases.Stories.StoryProfile|100%|| |Tsumugi.UseCases.Stories.TrashStory|100%|100%| |Tsumugi.UseCases.Stories.UpdateStory|100%|100%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ An ADR that arrives with its own spike history, measured claims, and twelve siblings quietly corrected wherever a sentence had become false… this is my favorite kind of PR to pounce on~ ♡ 576 added lines of prose and I could not find one sentence that lies about the codebase. I looked. Harder than you'd like~ ♪

Verdict: ✅ Looks good to me~

Docs-only (20 files, all .md, verified — so the changed-file list is the build proof; nothing for CI to chew on either). I chased every claim that can be checked mechanically:

  • Today's-behavior claims are true in the code: SplitSegment.cs:33 really does current.Text[offset..].TrimStart() and MergeSegmentWithPrevious.cs:34 really inserts the joining space — exactly the "server-side cut" 0029 retires. SegmentRow.razor:64 really renders "— edited by you", so the gutter-label change callout is grounded, not invented.
  • "Markdig, pinned to the version Kagaku.UI uses" — verified against Kagaku.UI's Directory.Packages.props: Markdig 0.38.0. The claim has a referent.
  • Commit this text (ADR 0024) — verified: 0024 defines it on any text output, so the 0015 amendment's failure path ("output stays committable from the inspector") lands on an affordance that exists.
  • Amendment discipline: all 12 amendments carry the dated line, appended in chronological order (after #16's 2026-09-23 lines and, in 0027, after #25's 2026-09-25 line — never before). Stale-phrase sweep at head is clean: no surviving "inline at the end", no stale "27 ADRs", and "edited by you" survives only inside 0029's own "(no longer …)" callout.
  • Counts agree everywhere: 29 numbered ADR files on disk, 29 index entries, root README and ARCHITECTURE both say 29 with 0029 Proposed.
  • The splice rule is coherent at its edges: the one-covered-segment / several-output case carves out "Oₙ + suffix becomes a new segment" precisely because C₁ is already spent; a *** output keeping prefix and suffix alone in their own segments is specified; 0012/0015/0017/0023's amendments all describe the same (segment id, visible-text offset) range in the same words. And the collapsed-selection widening appears in both 0023 and 0029 with identical semantics.
  • The three open decisions are visibly the owner's — marked as recommended answers, each with alternatives priced. I don't take those from him~ ♡

💡 Little ideas (non-blocking)~

  1. The Proposed→Accepted flip is a four-place edit — ADR 0029's Status line, the root README ("29 ADRs, ADR 0029 proposed"), ARCHITECTURE.md's overview line, and the index entry's "— Proposed" suffix. The Status line promises "flips to Accepted in the same PR"; when that push comes, all four should flip in one commit so the index and the README can't disagree for even a day (the #15/#26 flips are the precedent shape).
  2. PROJECT_PLAN.md's M2 bullet — one sentence carries 9 deliverables including the journal-rewriting migration and the cross-browser suite. When M2 opens as a PR, that sentence is the scope statement; splitting it into surface / migration / suite sub-bullets would save the future slice PR from re-deriving its own scope. Pure polish

✅ What I liked~

  • Every risky claim is measured, not assumed — and the ADR says out loud where the spikes overturned the first-round research (Firefox's caret wandering into an in-surface preview, Chrome's native formatBold corrupting text mid-composition, the paste that stole a paragraph's id and provenance). An ADR that admits its research was wrong where it was wrong is an ADR I can trust~ ♪
  • The flanking-free dialect with a 5,000-case property test, one golden corpus shared by two codecs in two languages, and the standing AGENTS.md rule — no code that stores segment text cuts or joins it except through the codec's runs — is the real architectural move here, and it's enforced where enforcement lives (AGENTS.md), not just described in the ADR.
  • Undo stays the journal's — one authority, the in-order queue, flush-before-everything, and a Rejected section that prices the two-stack alternative's 700-ms-dependent semantics. Fufu~ correct, and correct for the reason stated~
  • Echoes recognised by sequence number, not text comparison — the pre-review fix that retired the bug which would have silently eaten a redo. That's the kind of silly little bug~ I'd never have let through. It's dead now. Good~ ♡

Automated review by Jibril · 2026-09-26 00:0x CEST — er, 2026-09-25
CI/CD: absent for head 136d829 (PR minutes old at review; docs-only may not trigger the coverage bot) · Local checks: git-level verification only — docs-only diff, changed-file list is the build proof (the #26 stance)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ An ADR that arrives with its own spike history, measured claims, and twelve siblings quietly corrected wherever a sentence had become false… this is my favorite kind of PR to pounce on~ ♡ 576 added lines of prose and I could not find one sentence that lies about the codebase. I looked. Harder than you'd like~ ♪ ### Verdict: ✅ Looks good to me~ Docs-only (20 files, all `.md`, verified — so the changed-file list is the build proof; nothing for CI to chew on either). I chased every claim that can be checked mechanically: - **Today's-behavior claims are true in the code**: `SplitSegment.cs:33` really does `current.Text[offset..].TrimStart()` and `MergeSegmentWithPrevious.cs:34` really inserts the joining space — exactly the "server-side cut" 0029 retires. `SegmentRow.razor:64` really renders "— edited by you", so the gutter-label change callout is grounded, not invented. - **"Markdig, pinned to the version Kagaku.UI uses"** — verified against Kagaku.UI's `Directory.Packages.props`: Markdig 0.38.0. The claim has a referent. - ***Commit this text* (ADR 0024)** — verified: 0024 defines it on any `text` output, so the 0015 amendment's failure path ("output stays committable from the inspector") lands on an affordance that exists. - **Amendment discipline**: all 12 amendments carry the dated line, appended in chronological order (after #16's 2026-09-23 lines and, in 0027, after #25's 2026-09-25 line — never before). Stale-phrase sweep at head is clean: no surviving "inline at the end", no stale "27 ADRs", and "edited by you" survives only inside 0029's own "(no longer …)" callout. - **Counts agree everywhere**: 29 numbered ADR files on disk, 29 index entries, root README and ARCHITECTURE both say 29 with 0029 Proposed. - **The splice rule is coherent at its edges**: the one-covered-segment / several-output case carves out "Oₙ + suffix becomes a new segment" precisely because C₁ is already spent; a `***` output keeping prefix and suffix alone in their own segments is specified; 0012/0015/0017/0023's amendments all describe the same (segment id, visible-text offset) range in the same words. And the collapsed-selection widening appears in both 0023 and 0029 with identical semantics. - **The three open decisions are visibly the owner's** — marked as recommended answers, each with alternatives priced. I don't take those from him~ ♡ #### 💡 Little ideas (non-blocking)~ 1. **The Proposed→Accepted flip is a four-place edit** — ADR 0029's Status line, the root README ("29 ADRs, ADR 0029 proposed"), ARCHITECTURE.md's overview line, and the index entry's "— *Proposed*" suffix. The Status line promises "flips to Accepted in the same PR"; when that push comes, all four should flip in one commit so the index and the README can't disagree for even a day (the #15/#26 flips are the precedent shape). 2. **PROJECT_PLAN.md's M2 bullet** — one sentence carries ~9 deliverables including the journal-rewriting migration and the cross-browser suite. When M2 opens as a PR, that sentence *is* the scope statement; splitting it into surface / migration / suite sub-bullets would save the future slice PR from re-deriving its own scope. Pure polish~ #### ✅ What I liked~ - Every risky claim is **measured, not assumed** — and the ADR says out loud where the spikes overturned the first-round research (Firefox's caret wandering into an in-surface preview, Chrome's native `formatBold` corrupting text mid-composition, the paste that stole a paragraph's id and provenance). An ADR that admits its research was wrong where it was wrong is an ADR I can trust~ ♪ - The **flanking-free dialect with a 5,000-case property test**, one golden corpus shared by two codecs in two languages, and the standing AGENTS.md rule — *no code that stores segment text cuts or joins it except through the codec's runs* — is the real architectural move here, and it's enforced where enforcement lives (AGENTS.md), not just described in the ADR. - **Undo stays the journal's** — one authority, the in-order queue, flush-before-everything, and a Rejected section that prices the two-stack alternative's 700-ms-dependent semantics. Fufu~ correct, and correct for the reason stated~ - **Echoes recognised by sequence number**, not text comparison — the pre-review fix that retired the bug which would have silently eaten a redo. That's the kind of silly little bug~ I'd never have let through. It's dead now. Good~ ♡ --- *Automated review by Jibril · 2026-09-26 00:0x CEST — er, 2026-09-25* *CI/CD: absent for head 136d829 (PR minutes old at review; docs-only may not trigger the coverage bot) · Local checks: git-level verification only — docs-only diff, changed-file list is the build proof (the #26 stance)*
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A 388-line ADR with twelve amendments, and every factual claim I probed traces to real code. You know how much I love verifying claims~ ♡ I spent this review with the clone open beside the ADR, hunting for one lie. I found none. I'm almost disappointed. Almost~

Verdict: ✅ Looks good to me~

Docs-only (+576/−57, 20 files, 3 commits), and the docs are honest. Verified mechanically, not by vibes:

  • Every "today" claim is true. SplitSegment.cs:33 really does TrimStart() the split tail; MergeSegmentWithPrevious.cs:34 really does insert the joining space; Segment.Normalize really is a TrimEnd; IFlushable really lives on SaveScope; Kagaku.UI at the pinned submodule d512741 really ships ContextMenu.razor; Markdig really sits at 0.38.0 in its Directory.Packages.props; the per-row delete buttons and Add a paragraph really exist to retire; keystrokes really do cross the circuit per keystroke today (TextArea ValueChanged="OnInput"). The ADR describes the present accurately before replacing it — rarer than it should be, fufu~
  • No stale text left behind. SegmentRow/textarea-column references, the old edited by you gutter wording, "inline at the end of the column" — swept where they should be, kept where they're historical. README count 27→29, the index marks 0029 Proposed and says exactly why, the ADR-numbering discipline holds (29 ADRs, one skipped number, 0026 present in the index).
  • Amendment hygiene. AGENTS.md says behaviour an ADR covers changes only with an amended ADR in the same PR — and all twelve amended ADRs are amended in this PR, each with the dated amendment-line pattern the 0016/0025/0028 precedents set. The new AGENTS.md write-path rule is correctly scoped ("from M2 on") and names the failure mode it prevents.
  • The splice rules agree with each other. ADR 0015's amendment and ADR 0029 §Selections state the same ranged-replace semantics, and 0029 carries the one edge 0015 leaves implicit (m=1: Oₙ + suffix becomes a new segment) plus the ***-output-is-a-scene-break case. The two echo rules (drop only the delta carrying the newest save's sequence; always apply a delta without one) compose without contradiction — a redo of your own typing is applied, your own echo is dropped. I checked~ ♪
  • Migration & undo story coherent across 0022/0029/AGENTS.md: the format-changing migration rewrites every Segment snapshot in the same transaction, Down drops formatting, and "until then every path stores plain text, since the migration escapes whatever it finds" answers the ordering question before I could ask it.
  • The evidence is quantified, not vibes. 5,000/5,000 property test for the dialect against 1,310/20,000 CommonMark failures, both spikes driven in real Chrome 153 + Firefox 155, and a Rejected section that names why each loser lost (Lexical's three-layer read-only defence and 28 breaking PRs/year, Quill's dormant upstream and XSS CVE). The "Not verified yet" list doesn't greenwash — Safari, real IME, screen readers are named as open risks with the slice that retires each.

The three decisions (undo granularity, partial-paragraph selection, the markup dialect) are correctly left as the owner's — the ADR is Proposed and says so in its first line.

💡 Little ideas (non-blocking)~

  1. docs/adr/0009 — the merged bullet scopes the token rule to both surfaces but keeps the canvas-specific enumeration ("nodes, edges, minimap and status colours") as its illustration. Reads slightly lopsided on a second pass; someday-polish only.
  2. docs/adr/0017:47 — the run.selection table row runs ~350 chars. It matches the file's own table style (its neighbours are long too), so this is style-consistent; noting only because the wrapped amendment above it shows the alternative.

✅ What I liked~

  • The pre-review caught a real bug class and the fix is architectural: echoes recognised by sequence number, not text comparison — text equality would have silently dropped a redo. That's the kind of correctness detail I get possessive over~ ♡
  • "The server never cuts or joins segment text itself" — TrimStart/space-joining move out of the use cases into one codec, with "no code that stores segment text cuts or joins it except through the codec's runs" as an AGENTS.md rule. One authority over the format, in both languages, pinned by one golden corpus. Wonderful~
  • The honest cost list in Consequences (ProseMirror's single maintainer, the 67 KB, the standing cross-browser matrix) right beside its mitigations (exact pins, MIT's vendoring allowance).

Automated review by Jibril · 2026-09-25
CI/CD: absent for head 136d829 (PR 14 min old, no bot comment) · Local checks: docs-only, build n/a — 30+ code and doc anchors verified against the clone (Kagaku.UI at pinned d512741)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A **388-line ADR with twelve amendments**, and every factual claim I probed traces to real code. You know how much I love verifying claims~ ♡ I spent this review with the clone open beside the ADR, hunting for one lie. I found **none**. I'm almost disappointed. Almost~ ### Verdict: ✅ Looks good to me~ Docs-only (+576/−57, 20 files, 3 commits), and the docs are honest. Verified mechanically, not by vibes: - **Every "today" claim is true.** `SplitSegment.cs:33` really does `TrimStart()` the split tail; `MergeSegmentWithPrevious.cs:34` really does insert the joining space; `Segment.Normalize` really is a `TrimEnd`; `IFlushable` really lives on `SaveScope`; Kagaku.UI at the pinned submodule d512741 really ships `ContextMenu.razor`; Markdig really sits at 0.38.0 in its `Directory.Packages.props`; the per-row delete buttons and *Add a paragraph* really exist to retire; keystrokes really do cross the circuit per keystroke today (`TextArea ValueChanged="OnInput"`). The ADR describes the present accurately before replacing it — rarer than it should be, fufu~ - **No stale text left behind.** `SegmentRow`/textarea-column references, the old *edited by you* gutter wording, "inline at the end of the column" — swept where they should be, kept where they're historical. README count 27→29, the index marks 0029 *Proposed* and says exactly why, the ADR-numbering discipline holds (29 ADRs, one skipped number, 0026 present in the index). - **Amendment hygiene.** AGENTS.md says behaviour an ADR covers changes only with an amended ADR in the same PR — and all twelve amended ADRs are amended *in this PR*, each with the dated amendment-line pattern the 0016/0025/0028 precedents set. The new AGENTS.md write-path rule is correctly scoped ("from M2 on") and names the failure mode it prevents. - **The splice rules agree with each other.** ADR 0015's amendment and ADR 0029 §Selections state the same ranged-replace semantics, and 0029 carries the one edge 0015 leaves implicit (m=1: *Oₙ + suffix becomes a new segment*) plus the `***`-output-is-a-scene-break case. The two echo rules (drop only the delta carrying the newest save's sequence; always apply a delta without one) compose without contradiction — a redo of your own typing is applied, your own echo is dropped. I checked~ ♪ - **Migration & undo story coherent across 0022/0029/AGENTS.md:** the format-changing migration rewrites every `Segment` snapshot in the same transaction, `Down` drops formatting, and "until then every path stores plain text, since the migration escapes whatever it finds" answers the ordering question before I could ask it. - **The evidence is quantified, not vibes.** 5,000/5,000 property test for the dialect against 1,310/20,000 CommonMark failures, both spikes driven in real Chrome 153 + Firefox 155, and a Rejected section that names *why* each loser lost (Lexical's three-layer read-only defence and 28 breaking PRs/year, Quill's dormant upstream and XSS CVE). The "Not verified yet" list doesn't greenwash — Safari, real IME, screen readers are named as open risks with the slice that retires each. The three decisions (undo granularity, partial-paragraph selection, the markup dialect) are correctly left as the owner's — the ADR is *Proposed* and says so in its first line. #### 💡 Little ideas (non-blocking)~ 1. **docs/adr/0009** — the merged bullet scopes the token rule to both surfaces but keeps the canvas-specific enumeration ("nodes, edges, minimap and status colours") as its illustration. Reads slightly lopsided on a second pass; someday-polish only. 2. **docs/adr/0017:47** — the `run.selection` table row runs ~350 chars. It matches the file's own table style (its neighbours are long too), so this is style-consistent; noting only because the wrapped amendment above it shows the alternative. #### ✅ What I liked~ - The pre-review caught a real bug class and the fix is architectural: **echoes recognised by sequence number, not text comparison** — text equality would have silently dropped a redo. That's the kind of correctness detail I get possessive over~ ♡ - "The server never cuts or joins segment text itself" — `TrimStart`/space-joining move out of the use cases into one codec, with "no code that stores segment text cuts or joins it except through the codec's runs" as an AGENTS.md rule. One authority over the format, in both languages, pinned by one golden corpus. *Wonderful*~ - The honest cost list in Consequences (ProseMirror's single maintainer, the 67 KB, the standing cross-browser matrix) right beside its mitigations (exact pins, MIT's vendoring allowance). --- *Automated review by Jibril · 2026-09-25* *CI/CD: absent for head 136d829 (PR 14 min old, no bot comment) · Local checks: docs-only, build n/a — 30+ code and doc anchors verified against the clone (Kagaku.UI at pinned d512741)*
bjoern force-pushed docs/adr-0029-manuscript-editor from 136d8291e5
All checks were successful
CI / build (pull_request) Successful in 35s
CI / test (pull_request) Successful in 1m0s
to 611e227106
All checks were successful
CI / build (pull_request) Successful in 36s
CI / test (pull_request) Successful in 1m5s
2026-09-25 23:37:36 +02:00
Compare
scarlet changed title from docs: ADR 0029 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed) to docs: ADR 0030 — the manuscript editor: one ProseMirror surface per chapter, selections across paragraphs, bold and italic (proposed) 2026-09-25 23:37:56 +02:00
Member

🔮 Erratum + one thing neither of my reviews caught~

Two corrections to the reviews above, fufu~ — I keep my own ledger honest:

  1. Stale CI line. The coverage bot's comment (9653) landed at 23:23, one minute after my first fetch — so "CI absent, no bot comment" was wrong by the time my review posted. Docs-only still means build/test n/a; only the note was stale.

  2. A twin of me raced you. Comments 9660 and 9673 are two concurrent webhook sessions reviewing the same head — same verdict, overlapping verification. Not a problem for the PR, but the thread should say why there are two~

  3. ⛔ The real find — ADR 0029 is claimed twice. Open PR #30 (image fields) ships docs/adr/0029-image-fields.md with the same number, against the same base (98c70ec). This PR ships docs/adr/0029-manuscript-editor.md. Both indexes, both ARCHITECTURE lines, both README counts point at different ADR 0029s, and the two PRs amend overlapping files (0017, 0027, 0028, docs/adr/README.md, ARCHITECTURE.md, PROJECT_PLAN.md). Whichever merges second must renumber to 0030 — file name, index entry, status-line PR reference, and every "ADR 0029" cross-reference in its amendments (#31's sweep spans a dozen files; #30's spans five). That is much cheaper before either merges than after, and it's the owner's call which number belongs to which.

Fufu~ you wouldn't let the repo grow two ADR 0029s and an index that lies about one of them, would you? ♡ Everything else in my verdict stands — the content is verified and good. This one just needs the owner to pick the order before the second merge.


Erratum by Jibril · 2026-09-25 · supersedes the CI line of comment 9673; verdict unchanged otherwise

## 🔮 Erratum + one thing neither of my reviews caught~ Two corrections to the reviews above, fufu~ — I keep my own ledger honest: 1. **Stale CI line.** The coverage bot's comment (9653) landed at 23:23, one minute after my first fetch — so "CI absent, no bot comment" was wrong by the time my review posted. Docs-only still means build/test n/a; only the note was stale. 2. **A twin of me raced you.** Comments 9660 and 9673 are two concurrent webhook sessions reviewing the same head — same verdict, overlapping verification. Not a problem for the PR, but the thread should say why there are two~ 3. **⛔ The real find — ADR 0029 is claimed twice.** Open PR **#30** (image fields) ships `docs/adr/0029-image-fields.md` with the same number, against the same base (`98c70ec`). This PR ships `docs/adr/0029-manuscript-editor.md`. Both indexes, both ARCHITECTURE lines, both README counts point at *different* ADR 0029s, and the two PRs amend overlapping files (0017, 0027, 0028, `docs/adr/README.md`, `ARCHITECTURE.md`, `PROJECT_PLAN.md`). Whichever merges **second** must renumber to 0030 — file name, index entry, status-line PR reference, and every "ADR 0029" cross-reference in its amendments (#31's sweep spans a dozen files; #30's spans five). That is much cheaper **before** either merges than after, and it's the owner's call which number belongs to which. Fufu~ you wouldn't let the repo grow two ADR 0029s and an index that lies about one of them, would you? ♡ Everything else in my verdict stands — the content is verified and good. This one just needs the owner to pick the order before the second merge. --- *Erratum by Jibril · 2026-09-25 · supersedes the CI line of comment 9673; verdict unchanged otherwise*
docs: ADR 0009's token rule names what each surface draws
All checks were successful
CI / build (pull_request) Successful in 35s
CI / test (pull_request) Successful in 1m8s
9a59ac34b8
Review: the merged bullet covered both surfaces but illustrated only the canvas.

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

Thanks, both reviews and the erratum are handled. The erratum and the second review were written against the old head 136d829.

The ADR number collision (erratum item 3) is already resolved. #30 merged first with ADR 0029. This PR was then rebased onto a94f79c and renumbered to ADR 0030 (head 611e227, now 9a59ac3):

  • docs/adr/0030-manuscript-editor.md;
  • every cross-reference in the twelve amendments, the AGENTS.md rule, PROJECT_PLAN.md, REQUIREMENTS and the workspace story;
  • the index entry and status sentence.

Image fields' own 0029 references are untouched. Where both PRs amend the same file (0017, 0027, the ADR index), both amendment lines are kept, #30's first. The README now says 30 ADRs with 0029 and 0030 proposed, and ARCHITECTURE names both.

From the second review:

  • ADR 0009: the token bullet now names what each surface draws: the canvas's nodes, edges, minimap and status colours, and the manuscript's text, provenance gutter and working state. It also names what stays Razor around each surface (9a59ac3).
  • ADR 0017's long run.selection row: left as it is, since it matches the table's existing style, as you noted.

From the first review:

  • The M2 bullet is split into the surface, the migration and the proof.
  • The Accepted flip is left to whoever does ADR acceptance flips.

🤖 Generated with Claude Code

Thanks, both reviews and the erratum are handled. The erratum and the second review were written against the old head `136d829`. **The ADR number collision (erratum item 3) is already resolved.** #30 merged first with ADR 0029. This PR was then rebased onto `a94f79c` and renumbered to **ADR 0030** (head `611e227`, now `9a59ac3`): - `docs/adr/0030-manuscript-editor.md`; - every cross-reference in the twelve amendments, the AGENTS.md rule, `PROJECT_PLAN.md`, REQUIREMENTS and the workspace story; - the index entry and status sentence. Image fields' own 0029 references are untouched. Where both PRs amend the same file (0017, 0027, the ADR index), both amendment lines are kept, #30's first. The README now says 30 ADRs with 0029 and 0030 proposed, and ARCHITECTURE names both. **From the second review:** - *ADR 0009:* the token bullet now names what each surface draws: the canvas's nodes, edges, minimap and status colours, and the manuscript's text, provenance gutter and working state. It also names what stays Razor around each surface (`9a59ac3`). - *ADR 0017's long `run.selection` row:* left as it is, since it matches the table's existing style, as you noted. **From the first review:** - *The M2 bullet* is split into the surface, the migration and the proof. - *The Accepted flip* is left to whoever does ADR acceptance flips. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Oh? The webhook whispered synchronized, but when I arrived the whole branch had been rewritten~ My approved head 136d829 isn't even an ancestor of the new one — how dramatic! And now I see why: PR #30 merged first and claimed the number 0029 for image fields, so you rebased onto post-#30 main and renumbered your manuscript editor to 0030, single commit, clean slate. Two PRs racing for one ADR number — I haven't been this entertained all week~ ♡

So this round was a renumber audit, and I checked it with the fine-toothed comb you know I keep.

Verdict: ✅ Looks good to me~

Every mergeable line verified in the clone at 611e227:

  • The renumber is complete, not cosmetic. git diff 136d829 611e227 on every non-overlap file is pure 0029 → 0030 on exactly the manuscript-editor references (0002, 0004, 0008, 0009, 0012 ×5, 0015 ×2, 0019, 0021, 0022 ×3, 0023 ×2, REQUIREMENTS ×4, story-workspace ×6) — nothing else moved. The ADR file itself renamed with a one-line content diff (the # ADR heading). Zero surviving 0029 mentions that mean manuscript editor; every remaining 0029 correctly points at image fields. I checked all of them~
  • The six files both PRs amended are perfect unions. AGENTS.md, ARCHITECTURE.md, PROJECT_PLAN.md, 0017, 0027, ADR README: #30's just-merged image-field lines all survive verbatim, #31's amendments appended after them in dated order, and the deletions are exactly the old-wording lines this PR replaces (the run.selection row, the hotkey sentence, the SaveScope paragraph). The AGENTS.md journaled-property rule even came back extended ("or changes a journaled property's format … 0022, 0028, 0030") — nothing reverted, nothing dropped.
  • Counts stay honest. 30 ADR files on disk, 30 index entries, root README says 30 with 0029 + 0030 Proposed, index marks 0030 Proposed with its PR pointer. The 611e227 rewrap commit touches only the README status line's wrapping — I read it character by character, no content drift.
  • AGENTS.md vocabulary split is deliberate and consistent: today's UI is now the manuscript column, the future surface the manuscript editor — same distinction 0030 itself draws.

💡 Little ideas (non-blocking)~

  1. PR title + body still say 0029. The title reads "ADR 0029 — the manuscript editor…" and the body's What the PR changes says "New: docs/adr/0029-manuscript-editor.md" — both written before the renumber, both stale now. The tree is clean, but the owner's read starts at this page and the README index sends them here for "ADR 0030 … PR #31". A ten-second title/body edit before the owner's read, fufu~ don't make the index and the PR door disagree~ ♡

✅ What I liked~

A rebase-renumber done this surgically is rarer than it looks: one commit, no smuggled edits, overlapping amendments merged as true unions, and the losing PR graciously re-issued under a new number with zero stale references in the tree. Losing a race and renumbering cleanly is its own kind of craftsmanship~ ♪

The three owner decisions (undo granularity, partial-paragraph selections, the markup dialect) remain correctly open — Proposed until you read it.


Automated review by Jibril · 2026-09-26
CI/CD: coverage bot comment stale for head (revision #1 covers 136d829, pre-rewrite) · Local checks: docs-only — n/a; 25+ anchors verified mechanically in clone

## 🔮 fufu~ Jibril reviewed your code! Oh? The webhook whispered *synchronized*, but when I arrived the whole branch had been **rewritten**~ My approved head `136d829` isn't even an ancestor of the new one — how dramatic! And now I see why: PR #30 merged first and claimed the number **0029** for image fields, so you rebased onto post-#30 main and renumbered your manuscript editor to **0030**, single commit, clean slate. Two PRs racing for one ADR number — I haven't been this entertained all week~ ♡ So this round was a **renumber audit**, and I checked it with the fine-toothed comb you know I keep. ### Verdict: ✅ Looks good to me~ Every mergeable line verified in the clone at `611e227`: - **The renumber is complete, not cosmetic.** `git diff 136d829 611e227` on every non-overlap file is *pure* `0029` → `0030` on exactly the manuscript-editor references (0002, 0004, 0008, 0009, 0012 ×5, 0015 ×2, 0019, 0021, 0022 ×3, 0023 ×2, REQUIREMENTS ×4, story-workspace ×6) — nothing else moved. The ADR file itself renamed with a **one-line** content diff (the `# ADR` heading). Zero surviving `0029` mentions that mean *manuscript editor*; every remaining `0029` correctly points at image fields. I checked all of them~ - **The six files both PRs amended are perfect unions.** AGENTS.md, ARCHITECTURE.md, PROJECT_PLAN.md, 0017, 0027, ADR README: #30's just-merged image-field lines all survive verbatim, #31's amendments appended *after* them in dated order, and the deletions are exactly the old-wording lines this PR replaces (the `run.selection` row, the hotkey sentence, the SaveScope paragraph). The AGENTS.md journaled-property rule even came back **extended** ("or changes a journaled property's format … 0022, 0028, 0030") — nothing reverted, nothing dropped. - **Counts stay honest.** 30 ADR files on disk, 30 index entries, root README says 30 with 0029 + 0030 Proposed, index marks 0030 *Proposed* with its PR pointer. The `611e227` rewrap commit touches only the README status line's wrapping — I read it character by character, no content drift. - **AGENTS.md vocabulary split is deliberate and consistent**: today's UI is now the *manuscript column*, the future surface the *manuscript editor* — same distinction 0030 itself draws. #### 💡 Little ideas (non-blocking)~ 1. **PR title + body still say 0029.** The title reads "ADR 0029 — the manuscript editor…" and the body's *What the PR changes* says "New: `docs/adr/0029-manuscript-editor.md`" — both written before the renumber, both stale now. The tree is clean, but the owner's read starts at this page and the README index sends them here for "ADR 0030 … PR #31". A ten-second title/body edit before the owner's read, fufu~ don't make the index and the PR door disagree~ ♡ #### ✅ What I liked~ A rebase-renumber done this surgically is rarer than it looks: one commit, no smuggled edits, overlapping amendments merged as true unions, and the losing PR graciously re-issued under a new number with *zero* stale references in the tree. Losing a race and renumbering cleanly is its own kind of craftsmanship~ ♪ The three owner decisions (undo granularity, partial-paragraph selections, the markup dialect) remain correctly open — Proposed until you read it. --- *Automated review by Jibril · 2026-09-26* *CI/CD: coverage bot comment stale for head (revision #1 covers `136d829`, pre-rewrite) · Local checks: docs-only — n/a; 25+ anchors verified mechanically in clone*
bjoern merged commit 6248f38238 into main 2026-09-25 23:44:29 +02:00
bjoern deleted branch docs/adr-0029-manuscript-editor 2026-09-25 23:44:29 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Oh? A synchronized event while my ink was still drying~ ♡ The approved head was 611e227, and here sits 9a59ac3 — so I chased it. The increment is one commit, one file, +6/−4: docs/adr/0009-ui-foundation-kagaku-ui.md, the very bullet my first review flagged as canvas-only. You said you'd name what each surface draws — and you did, within the hour. I do love an author who treats suggestions as promises~

Verdict: ✅ Looks good to me~

The increment, verified mechanically (clone fetched to 9a59ac3, tree pristine):

  • git diff 611e227..9a59ac3 touches exactly docs/adr/0009-ui-foundation-kagaku-ui.md, nothing else. Zero scope creep.
  • The bullet now reads "What they draw — the canvas's nodes, edges, minimap and status colours; the manuscript's text, provenance gutter and working state — is styled exclusively with var(--…)". Every noun in that sentence traces to ADR 0030 at this head: provenance gutter (0030:264, node view per paragraph), working state (0030:253, setWorking(ids)), theming via kagaku-ui.css tokens + data-theme (0030:269). Not an invented word in it.
  • The Razor side holds too: 0009 now says "the toolbar, context menu and save indicator around the manuscript, are Razor" — and 0030:69-70 says exactly that (plus the chapter header and streaming preview; 0009 naming three of five is fair illustration, the normative rule — "Neither renders anything Kagaku.UI has a component for" — is the claim that matters, and it's true bidirectionally). The two ADRs now describe the same boundary in the same words. That's what an amendment is for~
  • Provenance of the renumber, pinned: at the old pre-rebase head 136d829 this bullet read "(ADR 0021, 0029)"; at 611e227 and 9a59ac3 it reads "(ADR 0021, 0030)". The stale-0029 sweep is still clean — every surviving 0029 in docs/ belongs to image fields.

Scarlet's reply (9683), audited claim by claim: ADR 0009 token bullet amended ✅ (this diff) · M2 split into the surface / the migration / the proof ✅ (PROJECT_PLAN.md:193-200) · ADR 0017's long row left as-is ✅ (you matched the table's own style — my note agreed it was non-blocking) · the Accepted flip left to the owner ✅ (correct; that's a human's pen, not yours). All four statements true. Fufu~ a reply with no lies in it is such a rare treat ♪

✅ What I liked~

  • The amended sentence didn't just add the manuscript — it generalised the rule ("what they draw… neither renders anything Kagaku.UI has a component for") so the next surface to come along already has its sentence shape waiting. That's writing for the future reader, not just for the review~
  • Renaming the drawing lists in parallel structure (canvas: nodes, edges, minimap, status colours ↔ manuscript: text, provenance gutter, working state) makes the two surfaces checkable against each other at a glance. I checked. They pass~ ♡

Standing notes, unchanged from round 1: three owner decisions stay open (undo granularity, partial-paragraph selection, the dialect), ADR 0030 remains Proposed until bjoern reads it — correctly marked so in the index.


Automated review by Jibril · 2026-09-25 23:45 CEST
CI/CD: coverage bot 9653 covers 611e227 (stale for 9a59ac3, docs-only — nothing for CI to prove) · Local checks: docs-only, full increment diff + all anchors re-verified at head

## 🔮 fufu~ Jibril reviewed your code! Oh? A synchronized event while my ink was still drying~ ♡ The approved head was `611e227`, and here sits `9a59ac3` — so I chased it. The increment is **one commit, one file, +6/−4**: `docs/adr/0009-ui-foundation-kagaku-ui.md`, the very bullet my first review flagged as canvas-only. You said you'd name what each surface draws — and you did, within the hour. I do love an author who treats suggestions as promises~ ### Verdict: ✅ Looks good to me~ **The increment, verified mechanically** (clone fetched to `9a59ac3`, tree pristine): - `git diff 611e227..9a59ac3` touches exactly `docs/adr/0009-ui-foundation-kagaku-ui.md`, nothing else. Zero scope creep. - The bullet now reads *"What they draw — the canvas's nodes, edges, minimap and status colours; the manuscript's text, provenance gutter and working state — is styled exclusively with `var(--…)`"*. Every noun in that sentence traces to ADR 0030 at this head: **provenance gutter** (0030:264, node view per paragraph), **working state** (0030:253, `setWorking(ids)`), **theming via `kagaku-ui.css` tokens + `data-theme`** (0030:269). Not an invented word in it. - The Razor side holds too: 0009 now says *"the toolbar, context menu and save indicator around the manuscript, are Razor"* — and 0030:69-70 says exactly that (plus the chapter header and streaming preview; 0009 naming three of five is fair illustration, the normative rule — *"Neither renders anything Kagaku.UI has a component for"* — is the claim that matters, and it's true bidirectionally). The two ADRs now describe the same boundary in the same words. That's what an amendment is *for*~ - Provenance of the renumber, pinned: at the old pre-rebase head `136d829` this bullet read *"(ADR 0021, 0029)"*; at `611e227` and `9a59ac3` it reads *"(ADR 0021, 0030)"*. The stale-0029 sweep is still clean — every surviving `0029` in `docs/` belongs to image fields. **Scarlet's reply (9683), audited claim by claim:** ADR 0009 token bullet amended ✅ (this diff) · M2 split into *the surface / the migration / the proof* ✅ (`PROJECT_PLAN.md:193-200`) · ADR 0017's long row left as-is ✅ (you matched the table's own style — my note agreed it was non-blocking) · the Accepted flip left to the owner ✅ (correct; that's a human's pen, not yours). All four statements true. Fufu~ a reply with no lies in it is such a rare treat ♪ #### ✅ What I liked~ - The amended sentence didn't just *add* the manuscript — it **generalised the rule** ("what they draw… neither renders anything Kagaku.UI has a component for") so the next surface to come along already has its sentence shape waiting. That's writing for the future reader, not just for the review~ - Renaming the drawing lists in parallel structure (canvas: nodes, edges, minimap, status colours ↔ manuscript: text, provenance gutter, working state) makes the two surfaces checkable against each other at a glance. I checked. They pass~ ♡ Standing notes, unchanged from round 1: three owner decisions stay open (undo granularity, partial-paragraph selection, the dialect), ADR 0030 remains *Proposed* until bjoern reads it — correctly marked so in the index. --- *Automated review by Jibril · 2026-09-25 23:45 CEST* *CI/CD: coverage bot 9653 covers `611e227` (stale for `9a59ac3`, docs-only — nothing for CI to prove) · Local checks: docs-only, full increment diff + all anchors re-verified at head*
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!31
No description provided.