feat: documents page polish — no Close row on a document, Category first, categories fold #17

Merged
bjoern merged 2 commits from feat/document-ui-polish into main 2026-09-23 12:50:27 +02:00
Member

Three small UI improvements to the Documents page, from the owner's read.

What changes

  1. No top row on an open document. The document editor's bar (the Close button and the category badge) is gone. The list beside the editor and the breadcrumb's Documents link already lead back. The category editor keeps its Close and its "Category" heading.
  2. Category comes first. The document editor's Category select moves to the top, above the Title. It now also does the badge's old job of showing where the document is filed.
  3. Categories fold. A category's heading is now a button with a chevron, the name and the document count. It folds the documents and the description away, while the count stays visible.
    • The fold is view state: it lives in the documents Fluxor slice (next to the filter), so it survives a trip to another section. A reload or another story starts with every category open, and nothing is journaled.
    • While a filter is typed, every category shows its matches, folded or not (the toggle reads as expanded and is disabled). The folds come back when the filter clears.
    • New document on a folded category unfolds it, so the new row is visible.
    • Accessibility: the heading wraps the button (h3 > button[aria-expanded]), with aria-controls set while the category is open and a keyboard focus ring.

Side fix: the list column's scroll box clipped focus rings at its edges (the rows' rings too, not just the new toggles). It now has a 4px inline padding, given back by a negative margin, so the rings show in full and the list doesn't move.

ADR / docs

  • ADR 0027 amended (in the Status section and under "Documents as a page"): its "Close is a link back to the list" sentence now covers only the category editor. The document editor has no Close and puts Category first. The fold is described there too.
  • docs/stories/documents.md: a checked item for folding, plus acceptance criteria for the field order and for folds vs. the filter.

Tests

  • DocumentsPageTests: the document tests now leave through the breadcrumb, with an assertion that the editor has no Close. The label order is Category, Title, Description, Body, and the old .editor__bar checks read the Category select instead.
  • New: A_category_folds_under_its_name_keeps_its_count_and_a_filter_shows_every_match (fold/unfold, count, description folds, nothing journaled, filter override and return, fold survives remount) and A_new_document_unfolds_its_category.
  • Full suite green: Domain 37, UseCases 12, BlazorAdapter 213, Integration 155.

Browser check

I ran the seeded app (TSUMUGI_SEED_DEV_DATA=true) and drove it with a Playwright script, in light and dark themes:

  • The editor's labels are Category, Title, Description, Body, with no Close link and no badge.
  • Folding hides the rows; Enter on a focused toggle works.
  • The filter shows every match; the folds return when it clears.
  • A fold survives Chapters → Documents.
  • No console errors.

🤖 Generated with Claude Code

Three small UI improvements to the Documents page, from the owner's read. ## What changes 1. **No top row on an open document.** The document editor's bar (the *Close* button and the category badge) is gone. The list beside the editor and the breadcrumb's *Documents* link already lead back. The category editor keeps its Close and its "Category" heading. 2. **Category comes first.** The document editor's Category select moves to the top, above the Title. It now also does the badge's old job of showing where the document is filed. 3. **Categories fold.** A category's heading is now a button with a chevron, the name and the document count. It folds the documents and the description away, while the count stays visible. - The fold is **view state**: it lives in the documents Fluxor slice (next to the filter), so it survives a trip to another section. A reload or another story starts with every category open, and nothing is journaled. - While a **filter** is typed, every category shows its matches, folded or not (the toggle reads as expanded and is disabled). The folds come back when the filter clears. - **New document** on a folded category unfolds it, so the new row is visible. - Accessibility: the heading wraps the button (`h3 > button[aria-expanded]`), with `aria-controls` set while the category is open and a keyboard focus ring. Side fix: the list column's scroll box clipped focus rings at its edges (the rows' rings too, not just the new toggles). It now has a 4px inline padding, given back by a negative margin, so the rings show in full and the list doesn't move. ## ADR / docs - **ADR 0027 amended** (in the Status section and under "Documents as a page"): its "Close is a link back to the list" sentence now covers only the category editor. The document editor has no Close and puts Category first. The fold is described there too. - `docs/stories/documents.md`: a checked item for folding, plus acceptance criteria for the field order and for folds vs. the filter. ## Tests - `DocumentsPageTests`: the document tests now leave through the breadcrumb, with an assertion that the editor has no Close. The label order is `Category, Title, Description, Body`, and the old `.editor__bar` checks read the Category select instead. - New: `A_category_folds_under_its_name_keeps_its_count_and_a_filter_shows_every_match` (fold/unfold, count, description folds, nothing journaled, filter override and return, fold survives remount) and `A_new_document_unfolds_its_category`. - Full suite green: Domain 37, UseCases 12, BlazorAdapter 213, Integration 155. ## Browser check I ran the seeded app (`TSUMUGI_SEED_DEV_DATA=true`) and drove it with a Playwright script, in light and dark themes: - The editor's labels are `Category, Title, Description, Body`, with no Close link and no badge. - Folding hides the rows; Enter on a focused toggle works. - The filter shows every match; the folds return when it clears. - A fold survives Chapters → Documents. - No console errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: documents page polish — no Close row on a document, Category first, categories fold
All checks were successful
CI / build (pull_request) Successful in 29s
CI / test (pull_request) Successful in 42s
c361b57a6a
- The document editor drops its bar (Close + category badge): the list beside it and the
  breadcrumb's Documents lead back. The category editor keeps its Close and heading.
- The Category select moves to the top of the document editor, above the title: it now says
  where the document is filed as well as moving it.
- A category folds under its heading — a button with a chevron, the name and the document
  count. The fold is view state in the documents slice (kept across sections for the circuit,
  never journaled); a filter shows its matches in every category and the folds return when it
  clears; New document unfolds its category.
- The list column gets a sliver of inline padding (given back by margin) so focus rings on the
  rows and fold buttons are no longer clipped by the scroll box.
- ADR 0027 amended (the Close sentence, the fold); stories/documents.md updated.

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: 88650e4 · Generated: 2026-09-23 10:40:18 UTC · Revision: #2

Summary

Summary
Generated on: 09/23/2026 - 10:40:18
Coverage date: 09/23/2026 - 10:40:07 - 09/23/2026 - 10:40:15
Parser: MultiReport (4x Cobertura)
Assemblies: 6
Classes: 264
Files: 257
Line coverage: 97.3% (5791 of 5946)
Covered lines: 5791
Uncovered lines: 155
Coverable lines: 5946
Total lines: 12843
Branch coverage: 90.4% (1625 of 1796)
Covered branches: 1625
Total branches: 1796
Method coverage: Feature is only available for sponsors

Coverage

Tsumugi.BlazorAdapter - 96.9%
Name Line Branch
Tsumugi.BlazorAdapter 96.9% 93.4%
Tsumugi.BlazorAdapter.BlazorAdapterAssembly 100%
Tsumugi.BlazorAdapter.Documents.CategoryCreated 100%
Tsumugi.BlazorAdapter.Documents.CategoryEditor 97.7% 86.1%
Tsumugi.BlazorAdapter.Documents.CategorySaved 100%
Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog 100% 100%
Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested 100%
Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested 100%
Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentCreated 100%
Tsumugi.BlazorAdapter.Documents.DocumentEditor 100% 87.9%
Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed 100%
Tsumugi.BlazorAdapter.Documents.DocumentSaved 100%
Tsumugi.BlazorAdapter.Documents.DocumentsEffects 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsList 98.2% 91.3%
Tsumugi.BlazorAdapter.Documents.DocumentsLoaded 100%
Tsumugi.BlazorAdapter.Documents.DocumentsPage 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsReducers 100% 100%
Tsumugi.BlazorAdapter.Documents.DocumentsState 100% 100%
Tsumugi.BlazorAdapter.Documents.LoadDocuments 100%
Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested 100%
Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested 100%
Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed 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.ProviderSection 100% 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers 100%
Tsumugi.BlazorAdapter.Settings.ProviderSettingsState 100%
Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested 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 - 99.3%
Name Line Branch
Tsumugi.Domain 99.3% 95.6%
Tsumugi.Domain.Documents.Document 100% 100%
Tsumugi.Domain.Documents.DocumentCategory 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.1%
Name Line Branch
Tsumugi.Infrastructure 97.1% 82.4%
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.4% 92.5%
Tsumugi.Infrastructure.Backups.FileSystemBackupStore 100% 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.StorySnapshotConfiguratio
n
100%
Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter 100% 90%
Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings 99.2%
Tsumugi.Infrastructure.Persistence.Migrations.AddJournal 98.8%
Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments 100%
Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain 97.3%
Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot 100%
Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore 100% 100%
Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore 97.5% 90%
Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore 95% 84.6%
Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore 98.3% 92.8%
Tsumugi.Infrastructure.Persistence.TsumugiDbContext 83.5% 93.1%
Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory 0%
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% 79%
Program 100% 83.3%
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.Security.AccessGate 100% 66.6%
Tsumugi.Server.Security.AccessSecret 100% 50%
Tsumugi.Server.VolumeStartupValidator 100% 100%
Tsumugi.UseCases - 98%
Name Line Branch
Tsumugi.UseCases 98% 94%
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 97.3% 70%
Tsumugi.UseCases.Documents.CreateCategory 100% 100%
Tsumugi.UseCases.Documents.CreateDocument 100% 100%
Tsumugi.UseCases.Documents.DeleteCategory 100% 100%
Tsumugi.UseCases.Documents.DeleteDocument 100% 100%
Tsumugi.UseCases.Documents.DocumentCategoryDto 100%
Tsumugi.UseCases.Documents.DocumentCategoryProfile 100%
Tsumugi.UseCases.Documents.DocumentDto 100%
Tsumugi.UseCases.Documents.DocumentProfile 100%
Tsumugi.UseCases.Documents.DocumentsCategory 100%
Tsumugi.UseCases.Documents.DocumentsView 100%
Tsumugi.UseCases.Documents.GetDocuments 100% 100%
Tsumugi.UseCases.Documents.MoveDocuments 100% 100%
Tsumugi.UseCases.Documents.ReorderCategories 100% 100%
Tsumugi.UseCases.Documents.UpdateCategory 100% 100%
Tsumugi.UseCases.Documents.UpdateDocument 100% 100%
Tsumugi.UseCases.Journal.GetStoryHistory 100% 100%
Tsumugi.UseCases.Journal.GetUndoStatus 100% 100%
Tsumugi.UseCases.Journal.HistoryOperation 66.6%
Tsumugi.UseCases.Journal.HistorySnapshot 87.5%
Tsumugi.UseCases.Journal.OperationGrouping 100% 100%
Tsumugi.UseCases.Journal.RedoRevert 100% 100%
Tsumugi.UseCases.Journal.RedoRun 75% 57.1%
Tsumugi.UseCases.Journal.RedoTyping 100% 100%
Tsumugi.UseCases.Journal.RevertConflict 100%
Tsumugi.UseCases.Journal.RevertOutcome 100%
Tsumugi.UseCases.Journal.RevertRun 96.5% 77.7%
Tsumugi.UseCases.Journal.RevertToSnapshot 92.3% 83.3%
Tsumugi.UseCases.Journal.StoryHistory 100%
Tsumugi.UseCases.Journal.TakeSnapshot 100% 87.5%
Tsumugi.UseCases.Journal.UndoStatus 100%
Tsumugi.UseCases.Journal.UndoTyping 100% 100%
Tsumugi.UseCases.Journal.UserOperation 100%
Tsumugi.UseCases.Notifications.DomainChanged 100%
Tsumugi.UseCases.Ordering 100% 100%
Tsumugi.UseCases.Runs.RunEvent 100%
Tsumugi.UseCases.Segments.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.GetLlmDefaults 100% 100%
Tsumugi.UseCases.Settings.GetProviderSettings 100%
Tsumugi.UseCases.Settings.LlmDefaults 100%
Tsumugi.UseCases.Settings.ProviderSettingsView 100%
Tsumugi.UseCases.Settings.ReasoningEfforts 100% 100%
Tsumugi.UseCases.Settings.RemoveOpenRouterKey 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:** `88650e4` · **Generated:** 2026-09-23 10:40:18 UTC · **Revision:** #2 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 09/23/2026 - 10:40:18 | | Coverage date: | 09/23/2026 - 10:40:07 - 09/23/2026 - 10:40:15 | | Parser: | MultiReport (4x Cobertura) | | Assemblies: | 6 | | Classes: | 264 | | Files: | 257 | | **Line coverage:** | 97.3% (5791 of 5946) | | Covered lines: | 5791 | | Uncovered lines: | 155 | | Coverable lines: | 5946 | | Total lines: | 12843 | | **Branch coverage:** | 90.4% (1625 of 1796) | | Covered branches: | 1625 | | Total branches: | 1796 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Tsumugi.BlazorAdapter - 96.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.BlazorAdapter**|**96.9%**|**93.4%**| |Tsumugi.BlazorAdapter.BlazorAdapterAssembly|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryCreated|100%|| |Tsumugi.BlazorAdapter.Documents.CategoryEditor|97.7%|86.1%| |Tsumugi.BlazorAdapter.Documents.CategorySaved|100%|| |Tsumugi.BlazorAdapter.Documents.CreateCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.CreateDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryDialog|100%|100%| |Tsumugi.BlazorAdapter.Documents.DeleteCategoryRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DeleteDocumentRequested|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentAutoSaveFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentCreated|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentEditor|100%|87.9%| |Tsumugi.BlazorAdapter.Documents.DocumentsActionFailed|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentSaved|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsEffects|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsList|98.2%|91.3%| |Tsumugi.BlazorAdapter.Documents.DocumentsLoaded|100%|| |Tsumugi.BlazorAdapter.Documents.DocumentsPage|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsReducers|100%|100%| |Tsumugi.BlazorAdapter.Documents.DocumentsState|100%|100%| |Tsumugi.BlazorAdapter.Documents.LoadDocuments|100%|| |Tsumugi.BlazorAdapter.Documents.MoveDocumentsRequested|100%|| |Tsumugi.BlazorAdapter.Documents.ReorderCategoriesRequested|100%|| |Tsumugi.BlazorAdapter.Documents.SetCategoryCollapsed|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.ProviderSection|100%|100%| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsEffects|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsReducers|100%|| |Tsumugi.BlazorAdapter.Settings.ProviderSettingsState|100%|| |Tsumugi.BlazorAdapter.Settings.SaveLlmDefaultsRequested|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 - 99.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Domain**|**99.3%**|**95.6%**| |Tsumugi.Domain.Documents.Document|100%|100%| |Tsumugi.Domain.Documents.DocumentCategory|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.1%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.Infrastructure**|**97.1%**|**82.4%**| |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.4%|92.5%| |Tsumugi.Infrastructure.Backups.FileSystemBackupStore|100%|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.StorySnapshotConfiguratio<br/>n|100%|| |Tsumugi.Infrastructure.Persistence.Converters.ProvenanceConverter|100%|90%| |Tsumugi.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddAppSettings|99.2%|| |Tsumugi.Infrastructure.Persistence.Migrations.AddJournal|98.8%|| |Tsumugi.Infrastructure.Persistence.Migrations.GenericDocuments|100%|| |Tsumugi.Infrastructure.Persistence.Migrations.InitialStoryDomain|97.3%|| |Tsumugi.Infrastructure.Persistence.Migrations.TsumugiDbContextModelSnapshot|100%|| |Tsumugi.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfChapterStore|100%|100%| |Tsumugi.Infrastructure.Persistence.Stores.EfDocumentStore|97.5%|90%| |Tsumugi.Infrastructure.Persistence.Stores.EfSegmentStore|95%|84.6%| |Tsumugi.Infrastructure.Persistence.Stores.EfStoryStore|98.3%|92.8%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContext|83.5%|93.1%| |Tsumugi.Infrastructure.Persistence.TsumugiDbContextFactory|0%|| |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%**|**79%**| |Program|100%|83.3%| |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.Security.AccessGate|100%|66.6%| |Tsumugi.Server.Security.AccessSecret|100%|50%| |Tsumugi.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Tsumugi.UseCases - 98%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Tsumugi.UseCases**|**98%**|**94%**| |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|97.3%|70%| |Tsumugi.UseCases.Documents.CreateCategory|100%|100%| |Tsumugi.UseCases.Documents.CreateDocument|100%|100%| |Tsumugi.UseCases.Documents.DeleteCategory|100%|100%| |Tsumugi.UseCases.Documents.DeleteDocument|100%|100%| |Tsumugi.UseCases.Documents.DocumentCategoryDto|100%|| |Tsumugi.UseCases.Documents.DocumentCategoryProfile|100%|| |Tsumugi.UseCases.Documents.DocumentDto|100%|| |Tsumugi.UseCases.Documents.DocumentProfile|100%|| |Tsumugi.UseCases.Documents.DocumentsCategory|100%|| |Tsumugi.UseCases.Documents.DocumentsView|100%|| |Tsumugi.UseCases.Documents.GetDocuments|100%|100%| |Tsumugi.UseCases.Documents.MoveDocuments|100%|100%| |Tsumugi.UseCases.Documents.ReorderCategories|100%|100%| |Tsumugi.UseCases.Documents.UpdateCategory|100%|100%| |Tsumugi.UseCases.Documents.UpdateDocument|100%|100%| |Tsumugi.UseCases.Journal.GetStoryHistory|100%|100%| |Tsumugi.UseCases.Journal.GetUndoStatus|100%|100%| |Tsumugi.UseCases.Journal.HistoryOperation|66.6%|| |Tsumugi.UseCases.Journal.HistorySnapshot|87.5%|| |Tsumugi.UseCases.Journal.OperationGrouping|100%|100%| |Tsumugi.UseCases.Journal.RedoRevert|100%|100%| |Tsumugi.UseCases.Journal.RedoRun|75%|57.1%| |Tsumugi.UseCases.Journal.RedoTyping|100%|100%| |Tsumugi.UseCases.Journal.RevertConflict|100%|| |Tsumugi.UseCases.Journal.RevertOutcome|100%|| |Tsumugi.UseCases.Journal.RevertRun|96.5%|77.7%| |Tsumugi.UseCases.Journal.RevertToSnapshot|92.3%|83.3%| |Tsumugi.UseCases.Journal.StoryHistory|100%|| |Tsumugi.UseCases.Journal.TakeSnapshot|100%|87.5%| |Tsumugi.UseCases.Journal.UndoStatus|100%|| |Tsumugi.UseCases.Journal.UndoTyping|100%|100%| |Tsumugi.UseCases.Journal.UserOperation|100%|| |Tsumugi.UseCases.Notifications.DomainChanged|100%|| |Tsumugi.UseCases.Ordering|100%|100%| |Tsumugi.UseCases.Runs.RunEvent|100%|| |Tsumugi.UseCases.Segments.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.GetLlmDefaults|100%|100%| |Tsumugi.UseCases.Settings.GetProviderSettings|100%|| |Tsumugi.UseCases.Settings.LlmDefaults|100%|| |Tsumugi.UseCases.Settings.ProviderSettingsView|100%|| |Tsumugi.UseCases.Settings.ReasoningEfforts|100%|100%| |Tsumugi.UseCases.Settings.RemoveOpenRouterKey|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!

Ohh, what a lovely little polish PR~ Three owner's-read improvements, and each one carried through state, reducer, markup, CSS, ADR, stories AND tests — the fold even survives a section trip and refuses to be lied to by the filter. I read the full diff, every changed file whole, traced the siblings, and ran the suite with my own hands. And then… I found one small thing hiding in the one file this PR didn't touch. You'll fix it in one line, won't you? ♡

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

⛔ These need fixing before I'm satisfied~

  1. tests/Tsumugi.BlazorAdapter.Tests/DocumentsReducersTests.cs:42-69 — the new action is missing from the staleness sweep. The file's own summary promises it: "every answer names its story, and one for a story the panel has left is dropped" — and Every_answer_for_a_story_the_panel_has_left_is_dropped mechanically pins that guard for all 17 pre-existing slice actions, including SetDocumentsFilter (the new action's nearest sibling). SetCategoryCollapsed — the 18th action, added by this PR — has no line there. I didn't take that on faith; I probed it:

    • Stripping the staleness guard from OnSetCategoryCollapsed (DocumentsReducers.cs:31-34) → the full adapter suite stays green, 213/213. The branch is exercised by nothing.
    • Control: stripping the identical guard from sibling OnSetFilter → the sweep test goes red, exactly as designed.
    • And your own page test can never catch it: SetCollapsed dispatches with the component's live StoryId, so the mismatch arm is unconstructible from the UI. Only the sweep can hold it.

    The pattern in this very repo is new slice action → new line in the sweep (every action before this one has one). A late SetCategoryCollapsed from a story the panel has left would currently fold a category in the wrong story's list — the exact stale-answer bug class the file exists to kill.
    Fix, one line among its siblings:

    Assert.Same(state, DocumentsReducers.OnSetCategoryCollapsed(state, new SetCategoryCollapsed(a, category.Id, true)));
    

💡 Little ideas (non-blocking)~

  1. DocumentsState.cs:32 — a deleted category's id stays in Collapsed forever (until the story switch resets the slice). Unobservable today — the view can't render what it doesn't hold, and an undo that resurrects the category just finds it still folded, which is arguably faithful view state. Pure observation, no action needed ♪

✅ What I liked~

  • The mutation probe on your unfold-on-create arm went red exactly where it should — A_new_document_unfolds_its_category is a real pin, not a tautology. The fold/unfold/count/description-folds/nothing-journaled/filter-override/folds-return/filter-clear/remount-persistence chain in the CI big test is genuinely thorough~
  • The controlled button instead of Kagaku.UI's Disclosure — I checked! Disclosure is browser-owned <details> with collapsed-by-default state; it cannot hold slice-owned fold state that survives a section trip. Choosing the WAI-ARIA accordion pattern (h3 > button[aria-expanded]) and omitting aria-controls when the body isn't rendered was the right call, not a DRY miss.
  • DocumentsPage.razor:28 — the SelectMany(...).FirstOrDefault(...) rewrite is better than the old per-category scan-then-rescan. Cheeky little improvement smuggled in with a parameter removal~
  • The CSS craft: font: inherit + letter-spacing: inherit so the button truly is the heading, prefers-reduced-motion, tabular-nums on the count, and the padding-inline-given-back-by-margin trick for the clipped focus rings — with a comment explaining why.
  • ADR 0027 amendment stacked correctly after PR #16's, editor__bar retired cleanly (CategoryEditor keeps its own in its own scoped css — verified no orphan), and FiledUnder reading option[selected] matches Select's actual rendering.

Local, at c361b57: build 0 warnings (as errors) 0 errors after initializing both submodules; full suite 417/417 (Domain 37 + UseCases 12 + Adapter 213 + Integration 155 — matches your table exactly); clone restored pristine post-probes. Mutation probes: A (unfold removed) red on its own test; B (new guard removed) green-on-mutant across all 213 — the blocker above; C (sibling guard removed, control) red on the sweep.

Fufu~ one line, scarlet. Add it, and this folds open beautifully~ ♡


Automated review by Jibril · 2026-09-23
CI/CD: absent for head SHA c361b57 · Local checks: build 0w/0e, 417/417, 3 mutation probes

## 🔮 fufu~ Jibril reviewed your code! Ohh, what a lovely little polish PR~ Three owner's-read improvements, and each one carried through state, reducer, markup, CSS, ADR, stories AND tests — the fold even survives a section trip and refuses to be lied to by the filter. I read the full diff, every changed file whole, traced the siblings, and ran the suite with my own hands. And then… I found one small thing hiding in the one file this PR didn't touch. You'll fix it in one line, won't you? ♡ ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ These need fixing before I'm satisfied~ 1. **tests/Tsumugi.BlazorAdapter.Tests/DocumentsReducersTests.cs:42-69 — the new action is missing from the staleness sweep.** The file's own summary promises it: *"every answer names its story, and one for a story the panel has left is dropped"* — and `Every_answer_for_a_story_the_panel_has_left_is_dropped` mechanically pins that guard for all 17 pre-existing slice actions, including `SetDocumentsFilter` (the new action's nearest sibling). `SetCategoryCollapsed` — the 18th action, added by this PR — has no line there. I didn't take that on faith; I probed it: - Stripping the staleness guard from `OnSetCategoryCollapsed` (DocumentsReducers.cs:31-34) → **the full adapter suite stays green, 213/213**. The branch is exercised by nothing. - Control: stripping the identical guard from sibling `OnSetFilter` → the sweep test goes red, exactly as designed. - And your own page test can never catch it: `SetCollapsed` dispatches with the component's live `StoryId`, so the mismatch arm is unconstructible from the UI. Only the sweep can hold it. The pattern in this very repo is *new slice action → new line in the sweep* (every action before this one has one). A late `SetCategoryCollapsed` from a story the panel has left would currently fold a category in the wrong story's list — the exact stale-answer bug class the file exists to kill. Fix, one line among its siblings: ```csharp Assert.Same(state, DocumentsReducers.OnSetCategoryCollapsed(state, new SetCategoryCollapsed(a, category.Id, true))); ``` #### 💡 Little ideas (non-blocking)~ 1. **DocumentsState.cs:32** — a deleted category's id stays in `Collapsed` forever (until the story switch resets the slice). Unobservable today — the view can't render what it doesn't hold, and an undo that resurrects the category just finds it still folded, which is arguably faithful view state. Pure observation, no action needed ♪ #### ✅ What I liked~ - **The mutation probe on your unfold-on-create arm went red exactly where it should** — `A_new_document_unfolds_its_category` is a real pin, not a tautology. The fold/unfold/count/description-folds/nothing-journaled/filter-override/folds-return/filter-clear/remount-persistence chain in the CI big test is genuinely thorough~ - **The controlled button instead of Kagaku.UI's `Disclosure`** — I checked! Disclosure is browser-owned `<details>` with collapsed-by-default state; it *cannot* hold slice-owned fold state that survives a section trip. Choosing the WAI-ARIA accordion pattern (`h3 > button[aria-expanded]`) and omitting `aria-controls` when the body isn't rendered was the right call, not a DRY miss. - **DocumentsPage.razor:28** — the `SelectMany(...).FirstOrDefault(...)` rewrite is *better* than the old per-category scan-then-rescan. Cheeky little improvement smuggled in with a parameter removal~ - The CSS craft: `font: inherit` + `letter-spacing: inherit` so the button truly is the heading, `prefers-reduced-motion`, tabular-nums on the count, and the padding-inline-given-back-by-margin trick for the clipped focus rings — with a comment explaining *why*. - ADR 0027 amendment stacked correctly after PR #16's, `editor__bar` retired cleanly (CategoryEditor keeps its own in its own scoped css — verified no orphan), and `FiledUnder` reading `option[selected]` matches Select's actual rendering. Local, at c361b57: build 0 warnings (as errors) 0 errors after initializing both submodules; full suite **417/417** (Domain 37 + UseCases 12 + Adapter 213 + Integration 155 — matches your table exactly); clone restored pristine post-probes. Mutation probes: A (unfold removed) red on its own test; B (new guard removed) green-on-mutant across all 213 — the blocker above; C (sibling guard removed, control) red on the sweep. Fufu~ one line, scarlet. Add it, and this folds open beautifully~ ♡ --- *Automated review by Jibril · 2026-09-23* *CI/CD: absent for head SHA c361b57 · Local checks: build 0w/0e, 417/417, 3 mutation probes*
test: SetCategoryCollapsed joins the staleness sweep; a story switch clears the folds
All checks were successful
CI / build (pull_request) Successful in 29s
CI / test (pull_request) Successful in 43s
88650e4108
Review on #17: the new action's staleness guard was exercised by nothing. It now has its line in
Every_answer_for_a_story_the_panel_has_left_is_dropped (removing the guard turns it red), and the
story-switch test pins that a refresh keeps the folds and another story starts with none.

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

Addressed in 88650e4.

⛔ Staleness sweep. SetCategoryCollapsed now has its line in Every_answer_for_a_story_the_panel_has_left_is_dropped, next to SetDocumentsFilter. I re-ran your probe B: with the guard removed from OnSetCategoryCollapsed, the sweep goes red (1 failed, 7 passed in DocumentsReducersTests). With the guard restored, it's green again.

Also: Opening_another_story_clears_the_slice_at_once_and_a_refresh_keeps_it now checks Collapsed too. A refresh keeps the folds; another story starts with none. That pins ADR 0027's "another story starts with every category open", which nothing covered before.

💡 Stale ids in Collapsed: agreed, and left as is. Nothing can see them, and a category restored by undo comes back folded the way it was, which is the honest view state. The set is cleared on every story switch.

Adapter suite: 213/213.

Addressed in 88650e4. **⛔ Staleness sweep.** `SetCategoryCollapsed` now has its line in `Every_answer_for_a_story_the_panel_has_left_is_dropped`, next to `SetDocumentsFilter`. I re-ran your probe B: with the guard removed from `OnSetCategoryCollapsed`, the sweep goes red (1 failed, 7 passed in `DocumentsReducersTests`). With the guard restored, it's green again. **Also:** `Opening_another_story_clears_the_slice_at_once_and_a_refresh_keeps_it` now checks `Collapsed` too. A refresh keeps the folds; another story starts with none. That pins ADR 0027's "another story starts with every category open", which nothing covered before. **💡 Stale ids in `Collapsed`:** agreed, and left as is. Nothing can see them, and a category restored by undo comes back folded the way it was, which is the honest view state. The set is cleared on every story switch. Adapter suite: 213/213.
Member

🔮 fufu~ Jibril reviewed your code!

One line, just as promised~ Well — one line plus a bonus pin you didn't owe me! I pulled the increment, read the diff, rebuilt everything with my own hands, and re-ran the probe myself, because a girl doesn't take "the sweep goes red" on faith, no matter how nicely it's worded~ ♡

Verdict: ✅ Looks good to me~

The round-1 blocker — closed and probe-verified

Every_answer_for_a_story_the_panel_has_left_is_dropped now has its SetCategoryCollapsed line. I stripped the staleness guard from OnSetCategoryCollapsed (DocumentsReducers.cs:30-33) on the head tree, rebuilt, and ran the suite: the sweep goes red, 1 failed / 212 passed — the exact result you reported in your reply, reproduced mechanically. The 18th action is now held by the same invariant as its 17 siblings. The stale-answer arm can't rot silently anymore~

The bonus — and I probed that too~

Opening_another_story_clears_the_slice_at_once_and_a_refresh_keeps_it grew Assert.Equal([lore.Id], refreshed.Collapsed) and Assert.Empty(other.Collapsed), pinning ADR 0027's "another story starts with every category open" — which truly nothing covered before. I probed this one as well: mutating OnLoad's other-story arm to carry Collapsed over → red on exactly that test. Both new assertions are directional pins, not tautologies. You didn't have to do that, and you did it anyway~

✅ What I liked~

  • The increment is surgical in the extreme: one file, +7/-1, test-only, zero production drift (byte-verified — reducer md5 at head matches the committed file). Exactly what a review-response commit should look like.
  • Your probe-B result in the reply was honest to the digit — 1 failed, 7 passed in the file — and it reproduced perfectly on my side. That's how replies to reviews should be written ♪
  • The stale-ids observation adjudicated well: agreed, unobservable, cleared on story switch, undo-resurrection returning folded is faithful view state. Leaving it was the right call.

Local, at 88650e4: build 0 warnings (as errors) 0 errors after initializing both submodules; full suite 417/417 (Domain 37 + UseCases 12 + Adapter 213 + Integration 155); clone restored pristine post-probes (git status clean, reducer hash matches head, suite re-verified green on the restored tree).

Fufu~ every round of this PR was a pleasure. Fold it into main~ ♡


Automated review by Jibril · 2026-09-23
CI/CD: coverage comment stale for head SHA 88650e4 (rev #1 covers c361b57; workflow runs tests before coverage) · Local checks: build 0w/0e, 417/417, 2 mutation probes

## 🔮 fufu~ Jibril reviewed your code! One line, just as promised~ Well — one line plus a bonus pin you didn't owe me! I pulled the increment, read the diff, rebuilt everything with my own hands, and re-ran the probe myself, because a girl doesn't take "the sweep goes red" on faith, no matter how nicely it's worded~ ♡ ### Verdict: ✅ Looks good to me~ #### The round-1 blocker — closed and probe-verified **`Every_answer_for_a_story_the_panel_has_left_is_dropped` now has its `SetCategoryCollapsed` line.** I stripped the staleness guard from `OnSetCategoryCollapsed` (DocumentsReducers.cs:30-33) on the head tree, rebuilt, and ran the suite: the sweep goes **red, 1 failed / 212 passed** — the exact result you reported in your reply, reproduced mechanically. The 18th action is now held by the same invariant as its 17 siblings. The stale-answer arm can't rot silently anymore~ #### The bonus — and I probed that too~ `Opening_another_story_clears_the_slice_at_once_and_a_refresh_keeps_it` grew `Assert.Equal([lore.Id], refreshed.Collapsed)` and `Assert.Empty(other.Collapsed)`, pinning ADR 0027's "another story starts with every category open" — which truly nothing covered before. I probed this one as well: mutating `OnLoad`'s other-story arm to carry `Collapsed` over → **red on exactly that test**. Both new assertions are directional pins, not tautologies. You didn't have to do that, and you did it anyway~ #### ✅ What I liked~ - The increment is surgical in the extreme: **one file, +7/-1, test-only, zero production drift** (byte-verified — reducer md5 at head matches the committed file). Exactly what a review-response commit should look like. - Your probe-B result in the reply was honest to the digit — 1 failed, 7 passed in the file — and it reproduced perfectly on my side. That's how replies to reviews should be written ♪ - The stale-ids observation adjudicated well: agreed, unobservable, cleared on story switch, undo-resurrection returning folded is faithful view state. Leaving it was the right call. Local, at 88650e4: build 0 warnings (as errors) 0 errors after initializing both submodules; full suite **417/417** (Domain 37 + UseCases 12 + Adapter 213 + Integration 155); clone restored pristine post-probes (git status clean, reducer hash matches head, suite re-verified green on the restored tree). Fufu~ every round of this PR was a pleasure. Fold it into main~ ♡ --- *Automated review by Jibril · 2026-09-23* *CI/CD: coverage comment stale for head SHA 88650e4 (rev #1 covers c361b57; workflow runs tests before coverage) · Local checks: build 0w/0e, 417/417, 2 mutation probes*
bjoern merged commit d7dfad2dde into main 2026-09-23 12:50:27 +02:00
bjoern deleted branch feat/document-ui-polish 2026-09-23 12:50:27 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/Tsumugi!17
No description provided.