feat(expressions): inpaint the face region per emotion through the queue (ADR 0029/0030) #98

Merged
bjoern merged 2 commits from feat/expression-generation into main 2026-08-13 06:23:58 +02:00
Member

Slice 3b — the finale of the expression tier (ADR 0029/0030, outfit-expressions story): each adopted emotion generates by inpainting the outfit sprite's face region, one queue job per card. This completes the arc started with the emotion library (#92), the RegionSelector (#94), and the adoption grid (#95).

The generation path

  • InpaintSource joins the vendor-neutral generation spec (image + mask + 0..1 strength, default 1.0). SpriteRequestMapper renders it onto the NovelAI request and swaps in the paired inpainting model (GetInpaintingModel() — an internal pairing, never a user-facing model choice, per the gateway's own note).
  • RegionMaskRasterizer — the stored normalized region rasterized at generation time into a white-on-black grayscale PNG at the source sprite's exact dimensions (ADR 0030: the rectangle is the source of truth; no mask files persisted; rounded edges fold into the image). SixLabors.ImageSharp becomes an explicit reference — the same binary the vendored NovelAI client already ships, so nothing new lands in the app.
  • ExpressionImageGenerator mirrors its generator siblings exactly: preconditions in a throwaway scope (outfit sprite, face region, character gender, adopted emotion — each refused with its own message before anything enqueues), the job on the worker in a fresh scope. The prompt is the outfit's effective set with the emotion's tags appended inside the character group, then the style reference (ADR 0027) and character defaults (ADR 0028) — the inpainted face stays consistent with the sprite it sits on, and the emotion steers only what the mask exposes.
  • The sprite lands in the expression's own subfolder (…/outfits/{id}/expressions/{id}/), the row records it with the suppressed-journal save every generated-image reference uses, and a new gated expressions/{id}/sprite endpoint serves the cards.
  • IEmotionStore.FindAdoptedAsync extends the ADR 0029 boundary rule from names to tags: an adopted emotion keeps generating after its library delete — deletion only takes it off the pickers.

UI

  • Per-card generate/regenerate and a Generate all that fans out one GenerateExpression per idle card — N individually visible, individually cancellable queue jobs, never a mega-batch (ADR 0010).
  • Card spinner overlays (several can run at once as the queue works through), failures name their emotion ("“Happy”: Unauthorized"), and the buttons gate with reasons: no sprite → pointer to the Outfit tab, no region → pointer to the section above, no token → pointer to settings. A stale region warns (in the face-region section) but does not block, per the story.
  • Fixed en route: switching outfits reset the slice to defaults, silently wiping the learned TokenAvailable back to true — the capability is app-level and now carries across the reset (pinned by a reducer test). Found live in the browser before any test caught it.

Tests

  • 3 mask-rasterizer (pixel-checked white/black regions, overflow folding), 2 mapper inpaint (payload + model swap, and the no-inpaint control), 9 generator end-to-end over real SQLite + filesystem (the mask decoded and pixel-checked against the real region, prompt composition order, the deleted-emotion rule, journal asymmetry, folder coexistence, wrong-pairing 404), 5 effects tests, 4 bUnit grid tests (gating, per-card + generate-all through the engine, cache-busted card src).
  • Full suite: 1183 green.

Browser-verified at zero NovelAI spend

The gates named each missing input in turn as it was supplied (sprite → region → gender → token). With an invalid token, the job passed preconditions, the mask rasterized against the real drawn region, the card spun while the queue ran, the real NovelAI API rejected it, and "“Happy”: Unauthorized" landed on the card with the spinner cleared — the entire pipeline short of a paid image. Both themes; all dev-data changes reverted afterwards. A first real generation needs a valid token and costs one Anlas-priced image per expression.

🤖 Generated with Claude Code

Slice 3b — the finale of the expression tier (ADR 0029/0030, outfit-expressions story): each adopted emotion generates by **inpainting the outfit sprite's face region**, one queue job per card. This completes the arc started with the emotion library (#92), the RegionSelector (#94), and the adoption grid (#95). ## The generation path - **`InpaintSource`** joins the vendor-neutral generation spec (image + mask + 0..1 strength, default 1.0). `SpriteRequestMapper` renders it onto the NovelAI request and **swaps in the paired inpainting model** (`GetInpaintingModel()` — an internal pairing, never a user-facing model choice, per the gateway's own note). - **`RegionMaskRasterizer`** — the stored normalized region rasterized *at generation time* into a white-on-black grayscale PNG at the source sprite's exact dimensions (ADR 0030: the rectangle is the source of truth; no mask files persisted; rounded edges fold into the image). `SixLabors.ImageSharp` becomes an explicit reference — the same binary the vendored NovelAI client already ships, so nothing new lands in the app. - **`ExpressionImageGenerator`** mirrors its generator siblings exactly: preconditions in a throwaway scope (outfit sprite, face region, character gender, adopted emotion — each refused with its own message before anything enqueues), the job on the worker in a fresh scope. The prompt is the **outfit's effective set with the emotion's tags appended** inside the character group, then the style reference (ADR 0027) and character defaults (ADR 0028) — the inpainted face stays consistent with the sprite it sits on, and the emotion steers only what the mask exposes. - The sprite lands in the expression's own subfolder (`…/outfits/{id}/expressions/{id}/`), the row records it with the **suppressed-journal** save every generated-image reference uses, and a new gated `expressions/{id}/sprite` endpoint serves the cards. - **`IEmotionStore.FindAdoptedAsync`** extends the ADR 0029 boundary rule from names to tags: an adopted emotion keeps *generating* after its library delete — deletion only takes it off the pickers. ## UI - Per-card **generate/regenerate** and a **Generate all** that fans out one `GenerateExpression` per idle card — N individually visible, individually cancellable queue jobs, never a mega-batch (ADR 0010). - Card **spinner overlays** (several can run at once as the queue works through), failures **name their emotion** ("“Happy”: Unauthorized"), and the buttons gate with reasons: no sprite → pointer to the Outfit tab, no region → pointer to the section above, no token → pointer to settings. A stale region warns (in the face-region section) but does not block, per the story. - **Fixed en route:** switching outfits reset the slice to defaults, silently wiping the learned `TokenAvailable` back to `true` — the capability is app-level and now carries across the reset (pinned by a reducer test). Found live in the browser before any test caught it. ## Tests - 3 mask-rasterizer (pixel-checked white/black regions, overflow folding), 2 mapper inpaint (payload + model swap, and the no-inpaint control), **9 generator end-to-end** over real SQLite + filesystem (the mask decoded and pixel-checked against the real region, prompt composition order, the deleted-emotion rule, journal asymmetry, folder coexistence, wrong-pairing 404), 5 effects tests, 4 bUnit grid tests (gating, per-card + generate-all through the engine, cache-busted card src). - Full suite: **1183 green**. ## Browser-verified at zero NovelAI spend The gates named each missing input in turn as it was supplied (sprite → region → gender → token). With an **invalid token**, the job passed preconditions, the mask rasterized against the real drawn region, the card spun while the queue ran, the real NovelAI API rejected it, and *"“Happy”: Unauthorized"* landed on the card with the spinner cleared — the entire pipeline short of a paid image. Both themes; all dev-data changes reverted afterwards. A first real generation needs a valid token and costs one Anlas-priced image per expression. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(expressions): inpaint the face region per emotion through the queue (ADR 0029/0030)
All checks were successful
CI / build (pull_request) Successful in 22s
CI / test (pull_request) Successful in 51s
c80164c903
Slice 3b — the expression tier's finale. Each adopted emotion generates
by inpainting the outfit sprite's face region, one queue job per card:

- UseCases: InpaintSource on the generation spec (image + mask + 0..1
  strength); IExpressionImageGenerator port; OpenExpressionSprite for
  the gated card image endpoint; IExpressionStore.SetImageAsync
  (suppressed journal, like every generated-image reference); and
  IEmotionStore.FindAdoptedAsync — an adopted emotion keeps generating
  after its library delete (ADR 0029's boundary rule, now on the tags
  too, not just the name).
- Infrastructure: RegionMaskRasterizer — the stored normalized region
  rasterized at generation time into a white-on-black PNG at the source
  sprite's exact dimensions (ADR 0030: the rectangle is the truth, no
  mask files persisted; ImageSharp made an explicit reference, same
  binary the vendored client already ships). SpriteRequestMapper maps
  the inpaint source and swaps in the paired inpainting model.
  ExpressionImageGenerator mirrors its siblings: preconditions up front
  (sprite, region, gender, adopted emotion), the job in a fresh worker
  scope — prompt = outfit effective set + emotion tags appended, then
  style reference and character defaults (ADR 0027/0028); the sprite
  lands in the expression's own subfolder. New expressions/{id}/sprite
  endpoint.
- UI: per-card generate/regenerate + a Generate all that fans out one
  job per idle card (individually visible and cancellable in the
  queue); card spinner overlays; failures name their emotion; gating
  with reasons (sprite, region, token). Fixed en route: the outfit-
  switch reducer reset wiped the learned TokenAvailable back to its
  optimistic default — the capability is app-level and now carries
  across (pinned by a reducer test).
- Tests: 3 mask rasterizer, 2 mapper inpaint, 9 generator end-to-end
  (incl. the mask decoded and checked pixel-wise, the deleted-emotion
  rule, and the journal asymmetry), 5 effects, 4 bUnit grid tests.
  Full suite: 1183 green.

Browser-verified at zero NovelAI spend: gates name each missing input
in turn; with an invalid token the job enqueues, the card spins, the
real API rejects it, and "Happy": Unauthorized lands on the card with
the spinner cleared. Both themes; dev data reverted.

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

Summary

Summary
Generated on: 07/12/2026 - 14:01:35
Coverage date: 07/12/2026 - 14:01:13 - 07/12/2026 - 14:01:32
Parser: MultiReport (4x Cobertura)
Assemblies: 7
Classes: 609
Files: 405
Line coverage: 96.2% (20645 of 21443)
Covered lines: 20645
Uncovered lines: 798
Coverable lines: 21443
Total lines: 37434
Branch coverage: 83.3% (2854 of 3424)
Covered branches: 2854
Total branches: 3424
Method coverage: Feature is only available for sponsors

Coverage

Kagura.BlazorAdapter - 90.2%
Name Line Branch
Kagura.BlazorAdapter 90.2% 80.7%
Kagura.BlazorAdapter.BlazorAdapterAssembly 100%
Kagura.BlazorAdapter.Connections.AddLinkModal 91.4% 81.5%
Kagura.BlazorAdapter.Connections.ConnectionsEffects 95.4% 80%
Kagura.BlazorAdapter.Connections.ConnectionsFailed 100%
Kagura.BlazorAdapter.Connections.ConnectionsLoaded 100%
Kagura.BlazorAdapter.Connections.ConnectionsPanel 100% 95%
Kagura.BlazorAdapter.Connections.ConnectionsReducers 100% 75%
Kagura.BlazorAdapter.Connections.ConnectionsState 90%
Kagura.BlazorAdapter.Connections.KindIcon 100%
Kagura.BlazorAdapter.Connections.LinkRequested 100%
Kagura.BlazorAdapter.Connections.LinkTargetsFound 100%
Kagura.BlazorAdapter.Connections.LoadConnections 100%
Kagura.BlazorAdapter.Connections.NodeKindIcons 100%
Kagura.BlazorAdapter.Connections.RemoveLinkRequested 100%
Kagura.BlazorAdapter.Connections.SearchLinkTargets 100%
Kagura.BlazorAdapter.Design 0% 0%
Kagura.BlazorAdapter.EditorComponentsDemo 0%
Kagura.BlazorAdapter.FileUploadDemo 0%
Kagura.BlazorAdapter.Generation.ActivityQueueBridge 87.5% 50%
Kagura.BlazorAdapter.Generation.CancelActivityRequested 100%
Kagura.BlazorAdapter.Generation.GenerationQueueEffects 100%
Kagura.BlazorAdapter.Generation.GenerationQueueLoaded 100%
Kagura.BlazorAdapter.Generation.GenerationQueuePage 100% 100%
Kagura.BlazorAdapter.Generation.GenerationQueueReducers 100%
Kagura.BlazorAdapter.Generation.GenerationQueueState 100%
Kagura.BlazorAdapter.Generation.GenerationStatusBar 100% 95.4%
Kagura.BlazorAdapter.Generation.RemoveActivityRequested 100%
Kagura.BlazorAdapter.History.DiffValue 100% 87.5%
Kagura.BlazorAdapter.History.DocumentHistoryEffects 90% 68.7%
Kagura.BlazorAdapter.History.DocumentHistoryFailed 100%
Kagura.BlazorAdapter.History.DocumentHistoryLoaded 100%
Kagura.BlazorAdapter.History.DocumentHistoryPanel 79.3% 75%
Kagura.BlazorAdapter.History.DocumentHistoryReducers 95% 83.3%
Kagura.BlazorAdapter.History.DocumentHistoryState 100%
Kagura.BlazorAdapter.History.LoadDocumentHistory 100%
Kagura.BlazorAdapter.History.RevertCompleted 100%
Kagura.BlazorAdapter.History.RevertRequested 100%
Kagura.BlazorAdapter.History.RevisionDiffLoaded 100%
Kagura.BlazorAdapter.History.SelectRevision 100%
Kagura.BlazorAdapter.KnowledgeBase.AdoptEmotionsRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.BaseSpriteFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.BaseSpriteGenerated 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterBaseSprite 95.2% 88.8%
Kagura.BlazorAdapter.KnowledgeBase.CharacterCreated 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterDeleted 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorEffects 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorNotFound 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorPage 91.3% 81.8%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorReducers 100% 92.8%
Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorState 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterOperationFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterOutfits 94.2% 83.3%
Kagura.BlazorAdapter.KnowledgeBase.CharacterSaved 100%
Kagura.BlazorAdapter.KnowledgeBase.CharactersEffects 94.1% 75%
Kagura.BlazorAdapter.KnowledgeBase.CharactersLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.CharactersPage 94.7% 90%
Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteEffects 83.3% 100%
Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteReducers 100% 75%
Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteState 100%
Kagura.BlazorAdapter.KnowledgeBase.CharactersReducers 100% 87.5%
Kagura.BlazorAdapter.KnowledgeBase.CharactersState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateCharacterFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.CreateCharacterRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateLocationFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.CreateLocationRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateLocationVariantRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateLoreFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.CreateLoreRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateOutfitRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateRelationshipRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.CreateTimelineEventRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteCharacterRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteLocationRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteLocationVariantRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteLoreRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteOutfitRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteRelationshipRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.DeleteTimelineEventRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionCapabilityChecked 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionGenerated 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionGenerationFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionRemoved 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionsEffects 87.7% 66.6%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionsFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionsLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionsReducers 85.7% 43.7%
Kagura.BlazorAdapter.KnowledgeBase.ExpressionsState 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateAllExpressions 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateBaseSprite 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateExpression 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateLocationBackground 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateLocationVariantImage 100%
Kagura.BlazorAdapter.KnowledgeBase.GenerateOutfitSprite 100%
Kagura.BlazorAdapter.KnowledgeBase.LabeledEntryMapping 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadCharacter 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadCharacters 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadExpressions 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLocation 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLocationHierarchy 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLocations 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLocationVariant 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLocationVariants 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLore 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadLoreEntry 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadOutfit 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadOutfits 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadRelationshipCast 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadRelationships 100%
Kagura.BlazorAdapter.KnowledgeBase.LoadTimeline 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackground 95.2% 88.8%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundCapabilityChecked 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundEffects 83.3% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundGenerated 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundReducers 100% 75%
Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundState 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationCreated 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationDeleted 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorEffects 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorNotFound 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorPage 87.8% 70.8%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorReducers 86.9% 71.4%
Kagura.BlazorAdapter.KnowledgeBase.LocationEditorState 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyEffects 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyReducers 100% 75%
Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationOperationFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationSaved 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationsEffects 94.1% 75%
Kagura.BlazorAdapter.KnowledgeBase.LocationsLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationsPage 94.7% 95%
Kagura.BlazorAdapter.KnowledgeBase.LocationsReducers 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationsState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorEffects 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorNotFound 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorPage 88.1% 70%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorReducers 100% 93.7%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorSaved 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImage 96.2% 90.9%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageCapabilityChecked 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageEffects 83.3% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageGenerated 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageReducers 100% 75%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageState 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariants 94.2% 79.1%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsEffects 96.4% 83.3%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsReducers 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsState 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreCategories 100% 50%
Kagura.BlazorAdapter.KnowledgeBase.LoreCreated 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreDeleted 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorEffects 96.6% 87.5%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorNotFound 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorPage 90.8% 75%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorReducers 86.9% 71.4%
Kagura.BlazorAdapter.KnowledgeBase.LoreEditorState 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreEffects 94.1% 75%
Kagura.BlazorAdapter.KnowledgeBase.LoreLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreOperationFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.LorePage 80% 78.5%
Kagura.BlazorAdapter.KnowledgeBase.LoreReducers 90.9% 87.5%
Kagura.BlazorAdapter.KnowledgeBase.LoreSaved 100%
Kagura.BlazorAdapter.KnowledgeBase.LoreState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.NewTimelineEvent 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorEffects 96.4% 87.5%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorNotFound 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorPage 88.1% 70%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorReducers 100% 93.7%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorSaved 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitExpressions 94.9% 90.9%
Kagura.BlazorAdapter.KnowledgeBase.OutfitFaceRegion 86.6% 72%
Kagura.BlazorAdapter.KnowledgeBase.OutfitsEffects 96.4% 83.3%
Kagura.BlazorAdapter.KnowledgeBase.OutfitsFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitsLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSprite 95.4% 88.8%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteCapabilityChecked 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteEffects 83.3% 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteFailed 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteGenerated 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteReducers 100% 75%
Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteState 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitsReducers 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.OutfitsState 100%
Kagura.BlazorAdapter.KnowledgeBase.ParentCandidatesFound 100%
Kagura.BlazorAdapter.KnowledgeBase.ParentPickerModal 84.6% 89.2%
Kagura.BlazorAdapter.KnowledgeBase.PositioningPanel 100% 95.4%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipCard 75.6% 60.7%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipCastLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipList 97.3% 88.4%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipModal 94.1% 94.7%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsEffects 92.8% 77.7%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsPage 92.8% 87.5%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsReducers 94.7% 75%
Kagura.BlazorAdapter.KnowledgeBase.RelationshipsState 100% 100%
Kagura.BlazorAdapter.KnowledgeBase.RemoveExpressionRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.ReorderTimelineEventRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveCharacterRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveFaceRegionRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveLocationRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveLocationVariantRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveLoreRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SaveOutfitRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SearchParentCandidates 100%
Kagura.BlazorAdapter.KnowledgeBase.SetCharactersFilter 100%
Kagura.BlazorAdapter.KnowledgeBase.SetLocationsFilter 100%
Kagura.BlazorAdapter.KnowledgeBase.SetLoreCategory 100%
Kagura.BlazorAdapter.KnowledgeBase.SetLoreFilter 100%
Kagura.BlazorAdapter.KnowledgeBase.SetParentRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.SetRelationshipsFilter 100%
Kagura.BlazorAdapter.KnowledgeBase.SpriteCapabilityChecked 100%
Kagura.BlazorAdapter.KnowledgeBase.TimelineEffects 93.5% 70%
Kagura.BlazorAdapter.KnowledgeBase.TimelineEventCard 92.5% 80%
Kagura.BlazorAdapter.KnowledgeBase.TimelineEventEdit 100%
Kagura.BlazorAdapter.KnowledgeBase.TimelineFailed 0%
Kagura.BlazorAdapter.KnowledgeBase.TimelineLoaded 100%
Kagura.BlazorAdapter.KnowledgeBase.TimelinePage 95.8% 90%
Kagura.BlazorAdapter.KnowledgeBase.TimelineReducers 91.6% 75%
Kagura.BlazorAdapter.KnowledgeBase.TimelineSection 96.6% 91.6%
Kagura.BlazorAdapter.KnowledgeBase.TimelineState 100%
Kagura.BlazorAdapter.KnowledgeBase.UpdateRelationshipRequested 100%
Kagura.BlazorAdapter.KnowledgeBase.UpdateTimelineEventRequested 100%
Kagura.BlazorAdapter.Notifications.DomainChangedBridge 88.8% 58.3%
Kagura.BlazorAdapter.Notifications.DomainChangesReceived 100% 100%
Kagura.BlazorAdapter.OverlayDemo 0% 0%
Kagura.BlazorAdapter.Projects.ClearStyleReferenceRequested 100%
Kagura.BlazorAdapter.Projects.CreateProjectRequested 100%
Kagura.BlazorAdapter.Projects.DeleteProjectRequested 100%
Kagura.BlazorAdapter.Projects.LoadWorkspace 100%
Kagura.BlazorAdapter.Projects.ProjectCreated 100%
Kagura.BlazorAdapter.Projects.ProjectCreateFailed 100%
Kagura.BlazorAdapter.Projects.ProjectDeleted 100%
Kagura.BlazorAdapter.Projects.ProjectSaved 100%
Kagura.BlazorAdapter.Projects.ProjectSaveFailed 100%
Kagura.BlazorAdapter.Projects.ProjectsEffects 100% 100%
Kagura.BlazorAdapter.Projects.ProjectsLoaded 100%
Kagura.BlazorAdapter.Projects.ProjectsPage 94.7% 100%
Kagura.BlazorAdapter.Projects.ProjectsReducers 100% 100%
Kagura.BlazorAdapter.Projects.ProjectsState 100% 100%
Kagura.BlazorAdapter.Projects.ProjectWorkspacePage 96.2% 96.1%
Kagura.BlazorAdapter.Projects.SaveProjectRequested 100%
Kagura.BlazorAdapter.Projects.SetProjectsFilter 100%
Kagura.BlazorAdapter.Projects.SetStyleReferenceRequested 100%
Kagura.BlazorAdapter.Projects.StyleReferenceChanged 100%
Kagura.BlazorAdapter.Projects.StyleReferenceFailed 100%
Kagura.BlazorAdapter.Projects.WorkspaceCrumb 100%
Kagura.BlazorAdapter.Projects.WorkspaceEffects 97.7% 90.9%
Kagura.BlazorAdapter.Projects.WorkspaceLoaded 100%
Kagura.BlazorAdapter.Projects.WorkspaceReducers 100%
Kagura.BlazorAdapter.Projects.WorkspaceSectionPage 100% 66.6%
Kagura.BlazorAdapter.Projects.WorkspaceShell 100% 94.4%
Kagura.BlazorAdapter.Projects.WorkspaceState 100%
Kagura.BlazorAdapter.QuicklinkDemo 0%
Kagura.BlazorAdapter.SelectDemo 0%
Kagura.BlazorAdapter.Settings.CreateEmotionRequested 100%
Kagura.BlazorAdapter.Settings.DeleteEmotionRequested 100%
Kagura.BlazorAdapter.Settings.EmotionCreated 100%
Kagura.BlazorAdapter.Settings.EmotionLibraryEffects 71.4% 37.5%
Kagura.BlazorAdapter.Settings.EmotionLibraryFailed 0%
Kagura.BlazorAdapter.Settings.EmotionLibraryLoaded 100%
Kagura.BlazorAdapter.Settings.EmotionLibraryReducers 96.5% 50%
Kagura.BlazorAdapter.Settings.EmotionLibrarySection 90.1% 80.7%
Kagura.BlazorAdapter.Settings.EmotionLibraryState 100%
Kagura.BlazorAdapter.Settings.NovelAiSettingsEffects 68.8% 50%
Kagura.BlazorAdapter.Settings.NovelAiSettingsFailed 100%
Kagura.BlazorAdapter.Settings.NovelAiSettingsLoaded 100%
Kagura.BlazorAdapter.Settings.NovelAiSettingsReducers 90.9% 25%
Kagura.BlazorAdapter.Settings.NovelAiSettingsSection 94.1% 91.6%
Kagura.BlazorAdapter.Settings.NovelAiSettingsState 100%
Kagura.BlazorAdapter.Settings.NovelAiTokenChecked 100%
Kagura.BlazorAdapter.Settings.SaveDefaultTagsRequested 100%
Kagura.BlazorAdapter.Settings.SaveEmotionRequested 100%
Kagura.BlazorAdapter.Settings.SaveNovelAiModelRequested 100%
Kagura.BlazorAdapter.Settings.SaveNovelAiTokenRequested 100%
Kagura.BlazorAdapter.Settings.SelectEmotion 100%
Kagura.BlazorAdapter.Settings.TokenVerdict 100%
Kagura.BlazorAdapter.SliderDemo 0% 0%
Kagura.BlazorAdapter.Tags.ForgetTagAuthoringInstance 100%
Kagura.BlazorAdapter.Tags.PromptTagEditing 100% 76.3%
Kagura.BlazorAdapter.Tags.RequestSuggestions 100%
Kagura.BlazorAdapter.Tags.SearchTags 100%
Kagura.BlazorAdapter.Tags.SuggestionsReceived 100%
Kagura.BlazorAdapter.Tags.TagAuthoring 95.5% 78.5%
Kagura.BlazorAdapter.Tags.TagAuthoringEffects 100% 100%
Kagura.BlazorAdapter.Tags.TagAuthoringInstance 100%
Kagura.BlazorAdapter.Tags.TagAuthoringPage 0%
Kagura.BlazorAdapter.Tags.TagAuthoringReducers 100% 100%
Kagura.BlazorAdapter.Tags.TagAuthoringState 100% 100%
Kagura.BlazorAdapter.Tags.TagDatabaseChecked 100%
Kagura.BlazorAdapter.Tags.TagsSearched 100%
Kagura.BlazorAdapter.ToggleGroupDemo 0% 0%
Kagura.Domain - 94.1%
Name Line Branch
Kagura.Domain 94.1% 85.8%
Kagura.Domain.Graph.Entry 100% 100%
Kagura.Domain.Graph.Link 100% 100%
Kagura.Domain.Graph.LinkRole 100% 100%
Kagura.Domain.Graph.LinkRoles 100%
Kagura.Domain.Graph.StructuralRef 100% 100%
Kagura.Domain.Graph.StructuralRefs 100% 50%
Kagura.Domain.Journal.ChangeLogEntry 100%
Kagura.Domain.KnowledgeBase.Character 91.6% 100%
Kagura.Domain.KnowledgeBase.CharacterProfile 100%
Kagura.Domain.KnowledgeBase.Emotion 87.8% 66.6%
Kagura.Domain.KnowledgeBase.EmotionProfile 50%
Kagura.Domain.KnowledgeBase.Expression 87%
Kagura.Domain.KnowledgeBase.ImageRegion 90% 100%
Kagura.Domain.KnowledgeBase.LabeledEntry 100%
Kagura.Domain.KnowledgeBase.Location 86.9% 100%
Kagura.Domain.KnowledgeBase.LocationProfile 100%
Kagura.Domain.KnowledgeBase.LocationVariant 91.3% 66.6%
Kagura.Domain.KnowledgeBase.LocationVariantProfile 100%
Kagura.Domain.KnowledgeBase.LoreEntry 100%
Kagura.Domain.KnowledgeBase.LoreProfile 100%
Kagura.Domain.KnowledgeBase.Outfit 92.7% 80%
Kagura.Domain.KnowledgeBase.OutfitProfile 100%
Kagura.Domain.KnowledgeBase.PromptTag 42.8% 100%
Kagura.Domain.KnowledgeBase.Relationship 91.8% 100%
Kagura.Domain.KnowledgeBase.RelationshipProfile 100%
Kagura.Domain.KnowledgeBase.RelationshipSecret 100% 75%
Kagura.Domain.KnowledgeBase.TimelineEvent 100% 100%
Kagura.Domain.Projects.Project 100% 100%
Kagura.Domain.Projects.Slug 100% 100%
Kagura.Domain.Settings.AppSetting 100%
System.Text.RegularExpressions.Generated 90.2% 72.2%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE06CC341D340484
D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0
89.4% 75%
Kagura.Infrastructure - 98.2%
Name Line Branch
Kagura.Infrastructure 98.2% 84.9%
Kagura.Infrastructure.DependencyInjection 100% 100%
Kagura.Infrastructure.Diagnostics.SqliteDatabaseSnapshotStore 100% 100%
Kagura.Infrastructure.Emotions.EfEmotionStore 92.3% 75%
Kagura.Infrastructure.Emotions.EmotionSeeder 100% 100%
Kagura.Infrastructure.Generation.ActivityQueue 99.3% 97.5%
Kagura.Infrastructure.Generation.ActivityQueueWorker 100%
Kagura.Infrastructure.Graph.EfGraphStore 94.5% 75%
Kagura.Infrastructure.Journal.EfChangeJournal 100%
Kagura.Infrastructure.Journal.EfDocumentReverter 95% 91.6%
Kagura.Infrastructure.Journal.EfUndoStore 98.4% 90.9%
Kagura.Infrastructure.Journal.OperationContext 100% 100%
Kagura.Infrastructure.Journal.SnapshotApplier 95% 90%
Kagura.Infrastructure.KnowledgeBase.CharacterImageGenerator 97.5% 77.7%
Kagura.Infrastructure.KnowledgeBase.EfCharacterStore 96.9% 83.3%
Kagura.Infrastructure.KnowledgeBase.EfExpressionStore 96.1% 75%
Kagura.Infrastructure.KnowledgeBase.EfLocationStore 96.9% 87.5%
Kagura.Infrastructure.KnowledgeBase.EfLocationVariantStore 96.9% 83.3%
Kagura.Infrastructure.KnowledgeBase.EfLoreStore 100% 100%
Kagura.Infrastructure.KnowledgeBase.EfOutfitStore 95% 75%
Kagura.Infrastructure.KnowledgeBase.EfRelationshipStore 93% 66.6%
Kagura.Infrastructure.KnowledgeBase.EfTimelineStore 93.9% 75%
Kagura.Infrastructure.KnowledgeBase.ExpressionImageGenerator 93.5% 80.5%
Kagura.Infrastructure.KnowledgeBase.LocationImageGenerator 97.4% 75%
Kagura.Infrastructure.KnowledgeBase.LocationVariantImageGenerator 95.2% 75%
Kagura.Infrastructure.KnowledgeBase.OutfitImageGenerator 95.8% 80%
Kagura.Infrastructure.KnowledgeBase.RegionMaskRasterizer 100% 100%
Kagura.Infrastructure.KnowledgeBase.SpriteEnrichment 100% 100%
Kagura.Infrastructure.Notifications.InProcessDomainChangedBus 100% 100%
Kagura.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.ChangeLogEntryConfiguratio
n
100%
Kagura.Infrastructure.Persistence.Configurations.CharacterConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.EmotionConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.EntryConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.ExpressionConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.JsonColumnMapper 100%
Kagura.Infrastructure.Persistence.Configurations.LinkConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.LocationConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.LocationVariantConfigurati
on
100%
Kagura.Infrastructure.Persistence.Configurations.LoreEntryConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.OutfitConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.ProjectConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.RelationshipConfiguration 100%
Kagura.Infrastructure.Persistence.Configurations.TimelineEventConfiguration 100%
Kagura.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Kagura.Infrastructure.Persistence.KaguraDbContext 86% 88%
Kagura.Infrastructure.Persistence.KaguraDbContextFactory 0%
Kagura.Infrastructure.Persistence.Migrations.AddAppSettings 99.3%
Kagura.Infrastructure.Persistence.Migrations.AddChangeLogUndoFlag 96.8%
Kagura.Infrastructure.Persistence.Migrations.AddCharacterBaseAppearance 98.4%
Kagura.Infrastructure.Persistence.Migrations.AddCharacterBaseImage 99%
Kagura.Infrastructure.Persistence.Migrations.AddCharacterProfile 92.9%
Kagura.Infrastructure.Persistence.Migrations.AddCharacters 98.7%
Kagura.Infrastructure.Persistence.Migrations.AddEmotions 99.4%
Kagura.Infrastructure.Persistence.Migrations.AddExpressions 99.5%
Kagura.Infrastructure.Persistence.Migrations.AddGraphEntryAndLink 97.7%
Kagura.Infrastructure.Persistence.Migrations.AddLocationBaseImage 99.1%
Kagura.Infrastructure.Persistence.Migrations.AddLocationBaseTags 99.1%
Kagura.Infrastructure.Persistence.Migrations.AddLocationHierarchy 96.6%
Kagura.Infrastructure.Persistence.Migrations.AddLocations 98.9%
Kagura.Infrastructure.Persistence.Migrations.AddLocationVariantImage 99.3%
Kagura.Infrastructure.Persistence.Migrations.AddLocationVariants 99.4%
Kagura.Infrastructure.Persistence.Migrations.AddLocationVariantTags 98.8%
Kagura.Infrastructure.Persistence.Migrations.AddLoreEntries 99%
Kagura.Infrastructure.Persistence.Migrations.AddLoreEntryTables 97.8%
Kagura.Infrastructure.Persistence.Migrations.AddOutfitClothingTags 99.1%
Kagura.Infrastructure.Persistence.Migrations.AddOutfitDisabledInheritedTags 99.1%
Kagura.Infrastructure.Persistence.Migrations.AddOutfitFaceRegion 98.7%
Kagura.Infrastructure.Persistence.Migrations.AddOutfitImage 99.1%
Kagura.Infrastructure.Persistence.Migrations.AddOutfits 99.4%
Kagura.Infrastructure.Persistence.Migrations.AddProjectDescription 98.1%
Kagura.Infrastructure.Persistence.Migrations.AddProjectStyleReference 99%
Kagura.Infrastructure.Persistence.Migrations.AddRelationships 99.2%
Kagura.Infrastructure.Persistence.Migrations.AddSoftDeleteAndChangeLog 90.3%
Kagura.Infrastructure.Persistence.Migrations.AddTimelineEvents 99.2%
Kagura.Infrastructure.Persistence.Migrations.InitialCreate 94.4%
Kagura.Infrastructure.Persistence.Migrations.KaguraDbContextModelSnapshot 100%
Kagura.Infrastructure.Projects.EfProjectStore 97.2% 87.5%
Kagura.Infrastructure.Projects.FileSystemProjectAssetStore 90.6% 60%
Kagura.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Kagura.Infrastructure.Settings.NovelAiGateway 76.4% 50%
Kagura.Infrastructure.Settings.SpriteRequestMapper 100% 100%
Kagura.Infrastructure.Tags.SqliteTagSearch 97.9% 87.9%
Kagura.Infrastructure.Tags.TagDatabaseOptions 100%
Kagura.Kernel - 90%
Name Line Branch
Kagura.Kernel 90% 75%
Kagura.Kernel.Err`1 100%
Kagura.Kernel.Ok`1 100%
Kagura.Kernel.Result`1 87.5% 75%
Kagura.Server - 89.2%
Name Line Branch
Kagura.Server 89.2% 80.9%
Kagura.Server.Components.App 100%
Kagura.Server.Components.Layout.MainLayout 100%
Kagura.Server.Components.Pages.Error 100% 50%
Kagura.Server.Components.Pages.Gate 100% 100%
Kagura.Server.Security.AccessGate 100% 83.3%
Kagura.Server.Security.AccessSecret 100% 100%
Program 83.4% 85.7%
Kagura.UI - 96.3%
Name Line Branch
Kagura.UI 96.3% 90.8%
Kagura.UI.Badge 100% 100%
Kagura.UI.Breadcrumb 100%
Kagura.UI.BreadcrumbItem 100% 100%
Kagura.UI.Button 100% 100%
Kagura.UI.Card 100% 100%
Kagura.UI.ConfirmDialog 100%
Kagura.UI.CssClassExtensions 100%
Kagura.UI.DebouncedSearchField 100% 88.8%
Kagura.UI.DocumentTitle 76.9% 100%
Kagura.UI.EmptyState 100% 100%
Kagura.UI.Field 100% 100%
Kagura.UI.FileUpload 100% 91.6%
Kagura.UI.Icon 100% 100%
Kagura.UI.IconCatalog 100%
Kagura.UI.InlineAlert 91.6% 87.5%
Kagura.UI.InputFieldBase 94.2% 87.5%
Kagura.UI.LabeledEntriesTable 96.7% 66.6%
Kagura.UI.LabeledEntry 100%
Kagura.UI.MaskedSecretField 95.2% 83.3%
Kagura.UI.Menu 90% 75%
Kagura.UI.MenuItem 100% 100%
Kagura.UI.Modal 87.1% 90%
Kagura.UI.NavGroup 100% 100%
Kagura.UI.NavItem 100% 100%
Kagura.UI.NavList 100%
Kagura.UI.PreviewImage 100% 100%
Kagura.UI.QuicklinkNav 85.2% 95.8%
Kagura.UI.QuicklinkSection 100%
Kagura.UI.RegionRect 90% 60%
Kagura.UI.RegionSelector 92.6% 88.7%
Kagura.UI.RelativeTime 100% 93.7%
Kagura.UI.SaveIndicator 100% 100%
Kagura.UI.Select`1 96.1% 95.8%
Kagura.UI.SelectOption`1 100%
Kagura.UI.Separator 100%
Kagura.UI.Slider 100% 91.6%
Kagura.UI.StatusDot 100%
Kagura.UI.Tab 100%
Kagura.UI.Table`1 100% 92.3%
Kagura.UI.TableColumn`1 100%
Kagura.UI.Tabs 95.8% 86.2%
Kagura.UI.TextArea 100% 100%
Kagura.UI.TextField 100%
Kagura.UI.ThemeSwitcher 100% 100%
Kagura.UI.ToggleButtonGroup`1 100% 100%
Kagura.UI.ToggleOption`1 100%
Kagura.UseCases - 96.2%
Name Line Branch
Kagura.UseCases 96.2% 83.9%
Kagura.UseCases.DependencyInjection 100%
Kagura.UseCases.Diagnostics.DatabaseSnapshot 100%
Kagura.UseCases.Diagnostics.DownloadDatabase 100%
Kagura.UseCases.Emotions.CreateEmotion 100% 66.6%
Kagura.UseCases.Emotions.DeleteEmotion 100% 100%
Kagura.UseCases.Emotions.EmotionDto 91.6%
Kagura.UseCases.Emotions.ListEmotions 100%
Kagura.UseCases.Emotions.UpdateEmotion 100% 50%
Kagura.UseCases.Generation.Activity`1 100% 50%
Kagura.UseCases.Generation.ActivityChanged 100%
Kagura.UseCases.Generation.ActivityOutcome 100%
Kagura.UseCases.Generation.ActivityProgress 100%
Kagura.UseCases.Generation.ActivityView 83.3%
Kagura.UseCases.Generation.GeneratedImage 100%
Kagura.UseCases.Generation.Img2ImgSource 100%
Kagura.UseCases.Generation.InpaintSource 100%
Kagura.UseCases.Generation.JobResult`1 100%
Kagura.UseCases.Generation.SpriteGenerationSpec 100%
Kagura.UseCases.Graph.EdgeGroup 100%
Kagura.UseCases.Graph.FindLinkTargets 100%
Kagura.UseCases.Graph.GetNodeGraph 97.5% 78.5%
Kagura.UseCases.Graph.GraphEdgeView 87.5%
Kagura.UseCases.Graph.LinkNodes 100% 100%
Kagura.UseCases.Graph.NodeGraphView 100%
Kagura.UseCases.Graph.NodeSummary 100%
Kagura.UseCases.Graph.RemoveLink 100% 100%
Kagura.UseCases.Graph.RestoreLink 100% 100%
Kagura.UseCases.Graph.StructuralEdge 100%
Kagura.UseCases.Journal.ChangeRecordView 57.1%
Kagura.UseCases.Journal.DocumentRevision 100%
Kagura.UseCases.Journal.FieldChange 100%
Kagura.UseCases.Journal.GetDocumentHistory 100%
Kagura.UseCases.Journal.GetEntityHistory 100%
Kagura.UseCases.Journal.GetRevisionDiff 100% 50%
Kagura.UseCases.Journal.GetUndoStatus 100%
Kagura.UseCases.Journal.Redo 100% 100%
Kagura.UseCases.Journal.RevertDocument 100% 100%
Kagura.UseCases.Journal.RevertOutcome 100%
Kagura.UseCases.Journal.RevisionCoalescer 100% 100%
Kagura.UseCases.Journal.RevisionDiff 80% 50%
Kagura.UseCases.Journal.RevisionDiffBuilder 98.4% 86.5%
Kagura.UseCases.Journal.RowChange 100%
Kagura.UseCases.Journal.Undo 100% 100%
Kagura.UseCases.Journal.UndoOutcome 100%
Kagura.UseCases.Journal.UndoStatus 100%
Kagura.UseCases.KnowledgeBase.AdoptEmotions 100% 100%
Kagura.UseCases.KnowledgeBase.CharacterDto 97.2%
Kagura.UseCases.KnowledgeBase.CharacterSpriteContent 100%
Kagura.UseCases.KnowledgeBase.CreateCharacter 100%
Kagura.UseCases.KnowledgeBase.CreateLocation 100%
Kagura.UseCases.KnowledgeBase.CreateLocationVariant 100% 75%
Kagura.UseCases.KnowledgeBase.CreateLore 100%
Kagura.UseCases.KnowledgeBase.CreateOutfit 100% 75%
Kagura.UseCases.KnowledgeBase.CreateRelationship 93.3% 80%
Kagura.UseCases.KnowledgeBase.CreateTimelineEvent 100%
Kagura.UseCases.KnowledgeBase.DeleteCharacter 100% 100%
Kagura.UseCases.KnowledgeBase.DeleteLocation 100% 100%
Kagura.UseCases.KnowledgeBase.DeleteLocationVariant 100% 100%
Kagura.UseCases.KnowledgeBase.DeleteLore 100% 100%
Kagura.UseCases.KnowledgeBase.DeleteOutfit 100% 100%
Kagura.UseCases.KnowledgeBase.DeleteRelationship 100% 50%
Kagura.UseCases.KnowledgeBase.DeleteTimelineEvent 100% 50%
Kagura.UseCases.KnowledgeBase.ExpressionView 100%
Kagura.UseCases.KnowledgeBase.FindParentCandidates 100% 50%
Kagura.UseCases.KnowledgeBase.GetCharacter 100% 100%
Kagura.UseCases.KnowledgeBase.GetLocation 100% 100%
Kagura.UseCases.KnowledgeBase.GetLocationHierarchy 100%
Kagura.UseCases.KnowledgeBase.GetLocationVariant 100% 58.3%
Kagura.UseCases.KnowledgeBase.GetLore 100% 100%
Kagura.UseCases.KnowledgeBase.GetOutfit 100% 100%
Kagura.UseCases.KnowledgeBase.GetRelationshipsForCharacter 100%
Kagura.UseCases.KnowledgeBase.ListCharacters 100%
Kagura.UseCases.KnowledgeBase.ListExpressions 100% 100%
Kagura.UseCases.KnowledgeBase.ListLocations 100%
Kagura.UseCases.KnowledgeBase.ListLocationVariants 100%
Kagura.UseCases.KnowledgeBase.ListLore 100%
Kagura.UseCases.KnowledgeBase.ListOutfits 100%
Kagura.UseCases.KnowledgeBase.ListRelationships 100%
Kagura.UseCases.KnowledgeBase.ListTimeline 100%
Kagura.UseCases.KnowledgeBase.LocationDto 80%
Kagura.UseCases.KnowledgeBase.LocationHierarchyView 100%
Kagura.UseCases.KnowledgeBase.LocationVariantDto 90.4%
Kagura.UseCases.KnowledgeBase.LocationVariantEditorView 100%
Kagura.UseCases.KnowledgeBase.LoreDto 85.7%
Kagura.UseCases.KnowledgeBase.OpenCharacterBaseSprite 88.8% 70%
Kagura.UseCases.KnowledgeBase.OpenExpressionSprite 92.3% 68.7%
Kagura.UseCases.KnowledgeBase.OpenLocationBackground 88.8% 70%
Kagura.UseCases.KnowledgeBase.OpenLocationVariant 90.9% 75%
Kagura.UseCases.KnowledgeBase.OpenOutfitSprite 90.9% 75%
Kagura.UseCases.KnowledgeBase.OutfitDto 92%
Kagura.UseCases.KnowledgeBase.OutfitEditorView 100%
Kagura.UseCases.KnowledgeBase.RelationshipDto 88%
Kagura.UseCases.KnowledgeBase.RelationshipEndpoint 100%
Kagura.UseCases.KnowledgeBase.RemoveExpression 100% 100%
Kagura.UseCases.KnowledgeBase.ReorderTimelineEvent 94.1% 87.5%
Kagura.UseCases.KnowledgeBase.SetLocationParent 90.4% 81.2%
Kagura.UseCases.KnowledgeBase.SetOutfitFaceRegion 100% 75%
Kagura.UseCases.KnowledgeBase.TimelineEventDto 88.8%
Kagura.UseCases.KnowledgeBase.UpdateCharacter 100% 100%
Kagura.UseCases.KnowledgeBase.UpdateLocation 100% 100%
Kagura.UseCases.KnowledgeBase.UpdateLocationVariant 100% 100%
Kagura.UseCases.KnowledgeBase.UpdateLore 100% 100%
Kagura.UseCases.KnowledgeBase.UpdateOutfit 100% 100%
Kagura.UseCases.KnowledgeBase.UpdateRelationship 100% 50%
Kagura.UseCases.KnowledgeBase.UpdateTimelineEvent 100% 50%
Kagura.UseCases.Notifications.DomainChanged 100%
Kagura.UseCases.Projects.ClearProjectStyleReference 100% 100%
Kagura.UseCases.Projects.CreateProject 100% 100%
Kagura.UseCases.Projects.DeleteProject 100% 100%
Kagura.UseCases.Projects.GetProject 100% 100%
Kagura.UseCases.Projects.ListProjects 100%
Kagura.UseCases.Projects.OpenProjectStyleReference 100% 83.3%
Kagura.UseCases.Projects.ProjectDto 100%
Kagura.UseCases.Projects.SetProjectStyleReference 100% 100%
Kagura.UseCases.Projects.StyleReferenceContent 100%
Kagura.UseCases.Projects.UpdateProject 100% 100%
Kagura.UseCases.Settings.CheckNovelAiToken 100% 100%
Kagura.UseCases.Settings.GenerationDefaultTagsJson 100% 100%
Kagura.UseCases.Settings.GetNovelAiSettings 100%
Kagura.UseCases.Settings.NovelAiModelOption 100%
Kagura.UseCases.Settings.NovelAiSettingsView 100%
Kagura.UseCases.Settings.SaveGenerationDefaultTags 100%
Kagura.UseCases.Settings.SaveNovelAiModel 100%
Kagura.UseCases.Settings.SaveNovelAiToken 100% 100%
Kagura.UseCases.Settings.SettingKeys 83.3% 75%
Kagura.UseCases.Tags.SimilarTag 100%
Kagura.UseCases.Tags.TagCategoryCount 100%
Kagura.UseCases.Tags.TagDetails 54.5%
Kagura.UseCases.Tags.TagResolution 100%
Kagura.UseCases.Tags.TagSearchFilter 100%
Kagura.UseCases.Tags.TagSuggestion 71.4%
Kagura.UseCases.Tags.TagSummary 83.3%
<!-- coverage-comment --> # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 07/12/2026 - 14:01:35 | | Coverage date: | 07/12/2026 - 14:01:13 - 07/12/2026 - 14:01:32 | | Parser: | MultiReport (4x Cobertura) | | Assemblies: | 7 | | Classes: | 609 | | Files: | 405 | | **Line coverage:** | 96.2% (20645 of 21443) | | Covered lines: | 20645 | | Uncovered lines: | 798 | | Coverable lines: | 21443 | | Total lines: | 37434 | | **Branch coverage:** | 83.3% (2854 of 3424) | | Covered branches: | 2854 | | Total branches: | 3424 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Kagura.BlazorAdapter - 90.2%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.BlazorAdapter**|**90.2%**|**80.7%**| |Kagura.BlazorAdapter.BlazorAdapterAssembly|100%|| |Kagura.BlazorAdapter.Connections.AddLinkModal|91.4%|81.5%| |Kagura.BlazorAdapter.Connections.ConnectionsEffects|95.4%|80%| |Kagura.BlazorAdapter.Connections.ConnectionsFailed|100%|| |Kagura.BlazorAdapter.Connections.ConnectionsLoaded|100%|| |Kagura.BlazorAdapter.Connections.ConnectionsPanel|100%|95%| |Kagura.BlazorAdapter.Connections.ConnectionsReducers|100%|75%| |Kagura.BlazorAdapter.Connections.ConnectionsState|90%|| |Kagura.BlazorAdapter.Connections.KindIcon|100%|| |Kagura.BlazorAdapter.Connections.LinkRequested|100%|| |Kagura.BlazorAdapter.Connections.LinkTargetsFound|100%|| |Kagura.BlazorAdapter.Connections.LoadConnections|100%|| |Kagura.BlazorAdapter.Connections.NodeKindIcons|100%|| |Kagura.BlazorAdapter.Connections.RemoveLinkRequested|100%|| |Kagura.BlazorAdapter.Connections.SearchLinkTargets|100%|| |Kagura.BlazorAdapter.Design|0%|0%| |Kagura.BlazorAdapter.EditorComponentsDemo|0%|| |Kagura.BlazorAdapter.FileUploadDemo|0%|| |Kagura.BlazorAdapter.Generation.ActivityQueueBridge|87.5%|50%| |Kagura.BlazorAdapter.Generation.CancelActivityRequested|100%|| |Kagura.BlazorAdapter.Generation.GenerationQueueEffects|100%|| |Kagura.BlazorAdapter.Generation.GenerationQueueLoaded|100%|| |Kagura.BlazorAdapter.Generation.GenerationQueuePage|100%|100%| |Kagura.BlazorAdapter.Generation.GenerationQueueReducers|100%|| |Kagura.BlazorAdapter.Generation.GenerationQueueState|100%|| |Kagura.BlazorAdapter.Generation.GenerationStatusBar|100%|95.4%| |Kagura.BlazorAdapter.Generation.RemoveActivityRequested|100%|| |Kagura.BlazorAdapter.History.DiffValue|100%|87.5%| |Kagura.BlazorAdapter.History.DocumentHistoryEffects|90%|68.7%| |Kagura.BlazorAdapter.History.DocumentHistoryFailed|100%|| |Kagura.BlazorAdapter.History.DocumentHistoryLoaded|100%|| |Kagura.BlazorAdapter.History.DocumentHistoryPanel|79.3%|75%| |Kagura.BlazorAdapter.History.DocumentHistoryReducers|95%|83.3%| |Kagura.BlazorAdapter.History.DocumentHistoryState|100%|| |Kagura.BlazorAdapter.History.LoadDocumentHistory|100%|| |Kagura.BlazorAdapter.History.RevertCompleted|100%|| |Kagura.BlazorAdapter.History.RevertRequested|100%|| |Kagura.BlazorAdapter.History.RevisionDiffLoaded|100%|| |Kagura.BlazorAdapter.History.SelectRevision|100%|| |Kagura.BlazorAdapter.KnowledgeBase.AdoptEmotionsRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.BaseSpriteFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.BaseSpriteGenerated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterBaseSprite|95.2%|88.8%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterCreated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterDeleted|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorEffects|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorNotFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorPage|91.3%|81.8%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorReducers|100%|92.8%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterEditorState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterOperationFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharacterOutfits|94.2%|83.3%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterSaved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharactersEffects|94.1%|75%| |Kagura.BlazorAdapter.KnowledgeBase.CharactersLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharactersPage|94.7%|90%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteEffects|83.3%|100%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteReducers|100%|75%| |Kagura.BlazorAdapter.KnowledgeBase.CharacterSpriteState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CharactersReducers|100%|87.5%| |Kagura.BlazorAdapter.KnowledgeBase.CharactersState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.CreateCharacterFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateCharacterRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateLocationFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateLocationRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateLocationVariantRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateLoreFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateLoreRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateOutfitRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateRelationshipRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.CreateTimelineEventRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteCharacterRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteLocationRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteLocationVariantRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteLoreRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteOutfitRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteRelationshipRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.DeleteTimelineEventRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionCapabilityChecked|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionGenerated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionGenerationFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionRemoved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionsEffects|87.7%|66.6%| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionsFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionsLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionsReducers|85.7%|43.7%| |Kagura.BlazorAdapter.KnowledgeBase.ExpressionsState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateAllExpressions|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateBaseSprite|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateExpression|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateLocationBackground|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateLocationVariantImage|100%|| |Kagura.BlazorAdapter.KnowledgeBase.GenerateOutfitSprite|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LabeledEntryMapping|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadCharacter|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadCharacters|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadExpressions|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLocation|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLocationHierarchy|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLocations|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLocationVariant|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLocationVariants|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLore|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadLoreEntry|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadOutfit|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadOutfits|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadRelationshipCast|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadRelationships|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoadTimeline|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackground|95.2%|88.8%| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundCapabilityChecked|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundEffects|83.3%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundGenerated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundReducers|100%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LocationBackgroundState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationCreated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationDeleted|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorEffects|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorNotFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorPage|87.8%|70.8%| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorReducers|86.9%|71.4%| |Kagura.BlazorAdapter.KnowledgeBase.LocationEditorState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyEffects|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyReducers|100%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LocationHierarchyState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationOperationFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationSaved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationsEffects|94.1%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LocationsLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationsPage|94.7%|95%| |Kagura.BlazorAdapter.KnowledgeBase.LocationsReducers|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationsState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorEffects|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorNotFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorPage|88.1%|70%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorReducers|100%|93.7%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorSaved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantEditorState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImage|96.2%|90.9%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageCapabilityChecked|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageEffects|83.3%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageGenerated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageReducers|100%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantImageState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariants|94.2%|79.1%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsEffects|96.4%|83.3%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsReducers|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.LocationVariantsState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreCategories|100%|50%| |Kagura.BlazorAdapter.KnowledgeBase.LoreCreated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreDeleted|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorEffects|96.6%|87.5%| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorNotFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorPage|90.8%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorReducers|86.9%|71.4%| |Kagura.BlazorAdapter.KnowledgeBase.LoreEditorState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreEffects|94.1%|75%| |Kagura.BlazorAdapter.KnowledgeBase.LoreLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreOperationFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LorePage|80%|78.5%| |Kagura.BlazorAdapter.KnowledgeBase.LoreReducers|90.9%|87.5%| |Kagura.BlazorAdapter.KnowledgeBase.LoreSaved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.LoreState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.NewTimelineEvent|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorEffects|96.4%|87.5%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorNotFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorPage|88.1%|70%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorReducers|100%|93.7%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorSaved|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitEditorState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitExpressions|94.9%|90.9%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitFaceRegion|86.6%|72%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitsEffects|96.4%|83.3%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitsFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitsLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSprite|95.4%|88.8%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteCapabilityChecked|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteEffects|83.3%|100%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteFailed|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteGenerated|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteReducers|100%|75%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitSpriteState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.OutfitsReducers|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.OutfitsState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ParentCandidatesFound|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ParentPickerModal|84.6%|89.2%| |Kagura.BlazorAdapter.KnowledgeBase.PositioningPanel|100%|95.4%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipCard|75.6%|60.7%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipCastLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipList|97.3%|88.4%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipModal|94.1%|94.7%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsEffects|92.8%|77.7%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsPage|92.8%|87.5%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsReducers|94.7%|75%| |Kagura.BlazorAdapter.KnowledgeBase.RelationshipsState|100%|100%| |Kagura.BlazorAdapter.KnowledgeBase.RemoveExpressionRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.ReorderTimelineEventRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveCharacterRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveFaceRegionRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveLocationRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveLocationVariantRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveLoreRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SaveOutfitRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SearchParentCandidates|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetCharactersFilter|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetLocationsFilter|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetLoreCategory|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetLoreFilter|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetParentRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SetRelationshipsFilter|100%|| |Kagura.BlazorAdapter.KnowledgeBase.SpriteCapabilityChecked|100%|| |Kagura.BlazorAdapter.KnowledgeBase.TimelineEffects|93.5%|70%| |Kagura.BlazorAdapter.KnowledgeBase.TimelineEventCard|92.5%|80%| |Kagura.BlazorAdapter.KnowledgeBase.TimelineEventEdit|100%|| |Kagura.BlazorAdapter.KnowledgeBase.TimelineFailed|0%|| |Kagura.BlazorAdapter.KnowledgeBase.TimelineLoaded|100%|| |Kagura.BlazorAdapter.KnowledgeBase.TimelinePage|95.8%|90%| |Kagura.BlazorAdapter.KnowledgeBase.TimelineReducers|91.6%|75%| |Kagura.BlazorAdapter.KnowledgeBase.TimelineSection|96.6%|91.6%| |Kagura.BlazorAdapter.KnowledgeBase.TimelineState|100%|| |Kagura.BlazorAdapter.KnowledgeBase.UpdateRelationshipRequested|100%|| |Kagura.BlazorAdapter.KnowledgeBase.UpdateTimelineEventRequested|100%|| |Kagura.BlazorAdapter.Notifications.DomainChangedBridge|88.8%|58.3%| |Kagura.BlazorAdapter.Notifications.DomainChangesReceived|100%|100%| |Kagura.BlazorAdapter.OverlayDemo|0%|0%| |Kagura.BlazorAdapter.Projects.ClearStyleReferenceRequested|100%|| |Kagura.BlazorAdapter.Projects.CreateProjectRequested|100%|| |Kagura.BlazorAdapter.Projects.DeleteProjectRequested|100%|| |Kagura.BlazorAdapter.Projects.LoadWorkspace|100%|| |Kagura.BlazorAdapter.Projects.ProjectCreated|100%|| |Kagura.BlazorAdapter.Projects.ProjectCreateFailed|100%|| |Kagura.BlazorAdapter.Projects.ProjectDeleted|100%|| |Kagura.BlazorAdapter.Projects.ProjectSaved|100%|| |Kagura.BlazorAdapter.Projects.ProjectSaveFailed|100%|| |Kagura.BlazorAdapter.Projects.ProjectsEffects|100%|100%| |Kagura.BlazorAdapter.Projects.ProjectsLoaded|100%|| |Kagura.BlazorAdapter.Projects.ProjectsPage|94.7%|100%| |Kagura.BlazorAdapter.Projects.ProjectsReducers|100%|100%| |Kagura.BlazorAdapter.Projects.ProjectsState|100%|100%| |Kagura.BlazorAdapter.Projects.ProjectWorkspacePage|96.2%|96.1%| |Kagura.BlazorAdapter.Projects.SaveProjectRequested|100%|| |Kagura.BlazorAdapter.Projects.SetProjectsFilter|100%|| |Kagura.BlazorAdapter.Projects.SetStyleReferenceRequested|100%|| |Kagura.BlazorAdapter.Projects.StyleReferenceChanged|100%|| |Kagura.BlazorAdapter.Projects.StyleReferenceFailed|100%|| |Kagura.BlazorAdapter.Projects.WorkspaceCrumb|100%|| |Kagura.BlazorAdapter.Projects.WorkspaceEffects|97.7%|90.9%| |Kagura.BlazorAdapter.Projects.WorkspaceLoaded|100%|| |Kagura.BlazorAdapter.Projects.WorkspaceReducers|100%|| |Kagura.BlazorAdapter.Projects.WorkspaceSectionPage|100%|66.6%| |Kagura.BlazorAdapter.Projects.WorkspaceShell|100%|94.4%| |Kagura.BlazorAdapter.Projects.WorkspaceState|100%|| |Kagura.BlazorAdapter.QuicklinkDemo|0%|| |Kagura.BlazorAdapter.SelectDemo|0%|| |Kagura.BlazorAdapter.Settings.CreateEmotionRequested|100%|| |Kagura.BlazorAdapter.Settings.DeleteEmotionRequested|100%|| |Kagura.BlazorAdapter.Settings.EmotionCreated|100%|| |Kagura.BlazorAdapter.Settings.EmotionLibraryEffects|71.4%|37.5%| |Kagura.BlazorAdapter.Settings.EmotionLibraryFailed|0%|| |Kagura.BlazorAdapter.Settings.EmotionLibraryLoaded|100%|| |Kagura.BlazorAdapter.Settings.EmotionLibraryReducers|96.5%|50%| |Kagura.BlazorAdapter.Settings.EmotionLibrarySection|90.1%|80.7%| |Kagura.BlazorAdapter.Settings.EmotionLibraryState|100%|| |Kagura.BlazorAdapter.Settings.NovelAiSettingsEffects|68.8%|50%| |Kagura.BlazorAdapter.Settings.NovelAiSettingsFailed|100%|| |Kagura.BlazorAdapter.Settings.NovelAiSettingsLoaded|100%|| |Kagura.BlazorAdapter.Settings.NovelAiSettingsReducers|90.9%|25%| |Kagura.BlazorAdapter.Settings.NovelAiSettingsSection|94.1%|91.6%| |Kagura.BlazorAdapter.Settings.NovelAiSettingsState|100%|| |Kagura.BlazorAdapter.Settings.NovelAiTokenChecked|100%|| |Kagura.BlazorAdapter.Settings.SaveDefaultTagsRequested|100%|| |Kagura.BlazorAdapter.Settings.SaveEmotionRequested|100%|| |Kagura.BlazorAdapter.Settings.SaveNovelAiModelRequested|100%|| |Kagura.BlazorAdapter.Settings.SaveNovelAiTokenRequested|100%|| |Kagura.BlazorAdapter.Settings.SelectEmotion|100%|| |Kagura.BlazorAdapter.Settings.TokenVerdict|100%|| |Kagura.BlazorAdapter.SliderDemo|0%|0%| |Kagura.BlazorAdapter.Tags.ForgetTagAuthoringInstance|100%|| |Kagura.BlazorAdapter.Tags.PromptTagEditing|100%|76.3%| |Kagura.BlazorAdapter.Tags.RequestSuggestions|100%|| |Kagura.BlazorAdapter.Tags.SearchTags|100%|| |Kagura.BlazorAdapter.Tags.SuggestionsReceived|100%|| |Kagura.BlazorAdapter.Tags.TagAuthoring|95.5%|78.5%| |Kagura.BlazorAdapter.Tags.TagAuthoringEffects|100%|100%| |Kagura.BlazorAdapter.Tags.TagAuthoringInstance|100%|| |Kagura.BlazorAdapter.Tags.TagAuthoringPage|0%|| |Kagura.BlazorAdapter.Tags.TagAuthoringReducers|100%|100%| |Kagura.BlazorAdapter.Tags.TagAuthoringState|100%|100%| |Kagura.BlazorAdapter.Tags.TagDatabaseChecked|100%|| |Kagura.BlazorAdapter.Tags.TagsSearched|100%|| |Kagura.BlazorAdapter.ToggleGroupDemo|0%|0%| </details> <details><summary>Kagura.Domain - 94.1%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.Domain**|**94.1%**|**85.8%**| |Kagura.Domain.Graph.Entry|100%|100%| |Kagura.Domain.Graph.Link|100%|100%| |Kagura.Domain.Graph.LinkRole|100%|100%| |Kagura.Domain.Graph.LinkRoles|100%|| |Kagura.Domain.Graph.StructuralRef|100%|100%| |Kagura.Domain.Graph.StructuralRefs|100%|50%| |Kagura.Domain.Journal.ChangeLogEntry|100%|| |Kagura.Domain.KnowledgeBase.Character|91.6%|100%| |Kagura.Domain.KnowledgeBase.CharacterProfile|100%|| |Kagura.Domain.KnowledgeBase.Emotion|87.8%|66.6%| |Kagura.Domain.KnowledgeBase.EmotionProfile|50%|| |Kagura.Domain.KnowledgeBase.Expression|87%|| |Kagura.Domain.KnowledgeBase.ImageRegion|90%|100%| |Kagura.Domain.KnowledgeBase.LabeledEntry|100%|| |Kagura.Domain.KnowledgeBase.Location|86.9%|100%| |Kagura.Domain.KnowledgeBase.LocationProfile|100%|| |Kagura.Domain.KnowledgeBase.LocationVariant|91.3%|66.6%| |Kagura.Domain.KnowledgeBase.LocationVariantProfile|100%|| |Kagura.Domain.KnowledgeBase.LoreEntry|100%|| |Kagura.Domain.KnowledgeBase.LoreProfile|100%|| |Kagura.Domain.KnowledgeBase.Outfit|92.7%|80%| |Kagura.Domain.KnowledgeBase.OutfitProfile|100%|| |Kagura.Domain.KnowledgeBase.PromptTag|42.8%|100%| |Kagura.Domain.KnowledgeBase.Relationship|91.8%|100%| |Kagura.Domain.KnowledgeBase.RelationshipProfile|100%|| |Kagura.Domain.KnowledgeBase.RelationshipSecret|100%|75%| |Kagura.Domain.KnowledgeBase.TimelineEvent|100%|100%| |Kagura.Domain.Projects.Project|100%|100%| |Kagura.Domain.Projects.Slug|100%|100%| |Kagura.Domain.Settings.AppSetting|100%|| |System.Text.RegularExpressions.Generated|90.2%|72.2%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE06CC341D340484<br/>D04ADFED3A21D401C2764A1D17367E35BEB556CBB3B4B0B74__NonSlugChars_0|89.4%|75%| </details> <details><summary>Kagura.Infrastructure - 98.2%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.Infrastructure**|**98.2%**|**84.9%**| |Kagura.Infrastructure.DependencyInjection|100%|100%| |Kagura.Infrastructure.Diagnostics.SqliteDatabaseSnapshotStore|100%|100%| |Kagura.Infrastructure.Emotions.EfEmotionStore|92.3%|75%| |Kagura.Infrastructure.Emotions.EmotionSeeder|100%|100%| |Kagura.Infrastructure.Generation.ActivityQueue|99.3%|97.5%| |Kagura.Infrastructure.Generation.ActivityQueueWorker|100%|| |Kagura.Infrastructure.Graph.EfGraphStore|94.5%|75%| |Kagura.Infrastructure.Journal.EfChangeJournal|100%|| |Kagura.Infrastructure.Journal.EfDocumentReverter|95%|91.6%| |Kagura.Infrastructure.Journal.EfUndoStore|98.4%|90.9%| |Kagura.Infrastructure.Journal.OperationContext|100%|100%| |Kagura.Infrastructure.Journal.SnapshotApplier|95%|90%| |Kagura.Infrastructure.KnowledgeBase.CharacterImageGenerator|97.5%|77.7%| |Kagura.Infrastructure.KnowledgeBase.EfCharacterStore|96.9%|83.3%| |Kagura.Infrastructure.KnowledgeBase.EfExpressionStore|96.1%|75%| |Kagura.Infrastructure.KnowledgeBase.EfLocationStore|96.9%|87.5%| |Kagura.Infrastructure.KnowledgeBase.EfLocationVariantStore|96.9%|83.3%| |Kagura.Infrastructure.KnowledgeBase.EfLoreStore|100%|100%| |Kagura.Infrastructure.KnowledgeBase.EfOutfitStore|95%|75%| |Kagura.Infrastructure.KnowledgeBase.EfRelationshipStore|93%|66.6%| |Kagura.Infrastructure.KnowledgeBase.EfTimelineStore|93.9%|75%| |Kagura.Infrastructure.KnowledgeBase.ExpressionImageGenerator|93.5%|80.5%| |Kagura.Infrastructure.KnowledgeBase.LocationImageGenerator|97.4%|75%| |Kagura.Infrastructure.KnowledgeBase.LocationVariantImageGenerator|95.2%|75%| |Kagura.Infrastructure.KnowledgeBase.OutfitImageGenerator|95.8%|80%| |Kagura.Infrastructure.KnowledgeBase.RegionMaskRasterizer|100%|100%| |Kagura.Infrastructure.KnowledgeBase.SpriteEnrichment|100%|100%| |Kagura.Infrastructure.Notifications.InProcessDomainChangedBus|100%|100%| |Kagura.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.ChangeLogEntryConfiguratio<br/>n|100%|| |Kagura.Infrastructure.Persistence.Configurations.CharacterConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.EmotionConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.EntryConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.ExpressionConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.JsonColumnMapper|100%|| |Kagura.Infrastructure.Persistence.Configurations.LinkConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.LocationConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.LocationVariantConfigurati<br/>on|100%|| |Kagura.Infrastructure.Persistence.Configurations.LoreEntryConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.OutfitConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.ProjectConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.RelationshipConfiguration|100%|| |Kagura.Infrastructure.Persistence.Configurations.TimelineEventConfiguration|100%|| |Kagura.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Kagura.Infrastructure.Persistence.KaguraDbContext|86%|88%| |Kagura.Infrastructure.Persistence.KaguraDbContextFactory|0%|| |Kagura.Infrastructure.Persistence.Migrations.AddAppSettings|99.3%|| |Kagura.Infrastructure.Persistence.Migrations.AddChangeLogUndoFlag|96.8%|| |Kagura.Infrastructure.Persistence.Migrations.AddCharacterBaseAppearance|98.4%|| |Kagura.Infrastructure.Persistence.Migrations.AddCharacterBaseImage|99%|| |Kagura.Infrastructure.Persistence.Migrations.AddCharacterProfile|92.9%|| |Kagura.Infrastructure.Persistence.Migrations.AddCharacters|98.7%|| |Kagura.Infrastructure.Persistence.Migrations.AddEmotions|99.4%|| |Kagura.Infrastructure.Persistence.Migrations.AddExpressions|99.5%|| |Kagura.Infrastructure.Persistence.Migrations.AddGraphEntryAndLink|97.7%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationBaseImage|99.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationBaseTags|99.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationHierarchy|96.6%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocations|98.9%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationVariantImage|99.3%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationVariants|99.4%|| |Kagura.Infrastructure.Persistence.Migrations.AddLocationVariantTags|98.8%|| |Kagura.Infrastructure.Persistence.Migrations.AddLoreEntries|99%|| |Kagura.Infrastructure.Persistence.Migrations.AddLoreEntryTables|97.8%|| |Kagura.Infrastructure.Persistence.Migrations.AddOutfitClothingTags|99.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddOutfitDisabledInheritedTags|99.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddOutfitFaceRegion|98.7%|| |Kagura.Infrastructure.Persistence.Migrations.AddOutfitImage|99.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddOutfits|99.4%|| |Kagura.Infrastructure.Persistence.Migrations.AddProjectDescription|98.1%|| |Kagura.Infrastructure.Persistence.Migrations.AddProjectStyleReference|99%|| |Kagura.Infrastructure.Persistence.Migrations.AddRelationships|99.2%|| |Kagura.Infrastructure.Persistence.Migrations.AddSoftDeleteAndChangeLog|90.3%|| |Kagura.Infrastructure.Persistence.Migrations.AddTimelineEvents|99.2%|| |Kagura.Infrastructure.Persistence.Migrations.InitialCreate|94.4%|| |Kagura.Infrastructure.Persistence.Migrations.KaguraDbContextModelSnapshot|100%|| |Kagura.Infrastructure.Projects.EfProjectStore|97.2%|87.5%| |Kagura.Infrastructure.Projects.FileSystemProjectAssetStore|90.6%|60%| |Kagura.Infrastructure.Settings.EfAppSettingsStore|100%|100%| |Kagura.Infrastructure.Settings.NovelAiGateway|76.4%|50%| |Kagura.Infrastructure.Settings.SpriteRequestMapper|100%|100%| |Kagura.Infrastructure.Tags.SqliteTagSearch|97.9%|87.9%| |Kagura.Infrastructure.Tags.TagDatabaseOptions|100%|| </details> <details><summary>Kagura.Kernel - 90%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.Kernel**|**90%**|**75%**| |Kagura.Kernel.Err`1|100%|| |Kagura.Kernel.Ok`1|100%|| |Kagura.Kernel.Result`1|87.5%|75%| </details> <details><summary>Kagura.Server - 89.2%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.Server**|**89.2%**|**80.9%**| |Kagura.Server.Components.App|100%|| |Kagura.Server.Components.Layout.MainLayout|100%|| |Kagura.Server.Components.Pages.Error|100%|50%| |Kagura.Server.Components.Pages.Gate|100%|100%| |Kagura.Server.Security.AccessGate|100%|83.3%| |Kagura.Server.Security.AccessSecret|100%|100%| |Program|83.4%|85.7%| </details> <details><summary>Kagura.UI - 96.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.UI**|**96.3%**|**90.8%**| |Kagura.UI.Badge|100%|100%| |Kagura.UI.Breadcrumb|100%|| |Kagura.UI.BreadcrumbItem|100%|100%| |Kagura.UI.Button|100%|100%| |Kagura.UI.Card|100%|100%| |Kagura.UI.ConfirmDialog|100%|| |Kagura.UI.CssClassExtensions|100%|| |Kagura.UI.DebouncedSearchField|100%|88.8%| |Kagura.UI.DocumentTitle|76.9%|100%| |Kagura.UI.EmptyState|100%|100%| |Kagura.UI.Field|100%|100%| |Kagura.UI.FileUpload|100%|91.6%| |Kagura.UI.Icon|100%|100%| |Kagura.UI.IconCatalog|100%|| |Kagura.UI.InlineAlert|91.6%|87.5%| |Kagura.UI.InputFieldBase|94.2%|87.5%| |Kagura.UI.LabeledEntriesTable|96.7%|66.6%| |Kagura.UI.LabeledEntry|100%|| |Kagura.UI.MaskedSecretField|95.2%|83.3%| |Kagura.UI.Menu|90%|75%| |Kagura.UI.MenuItem|100%|100%| |Kagura.UI.Modal|87.1%|90%| |Kagura.UI.NavGroup|100%|100%| |Kagura.UI.NavItem|100%|100%| |Kagura.UI.NavList|100%|| |Kagura.UI.PreviewImage|100%|100%| |Kagura.UI.QuicklinkNav|85.2%|95.8%| |Kagura.UI.QuicklinkSection|100%|| |Kagura.UI.RegionRect|90%|60%| |Kagura.UI.RegionSelector|92.6%|88.7%| |Kagura.UI.RelativeTime|100%|93.7%| |Kagura.UI.SaveIndicator|100%|100%| |Kagura.UI.Select`1|96.1%|95.8%| |Kagura.UI.SelectOption`1|100%|| |Kagura.UI.Separator|100%|| |Kagura.UI.Slider|100%|91.6%| |Kagura.UI.StatusDot|100%|| |Kagura.UI.Tab|100%|| |Kagura.UI.Table`1|100%|92.3%| |Kagura.UI.TableColumn`1|100%|| |Kagura.UI.Tabs|95.8%|86.2%| |Kagura.UI.TextArea|100%|100%| |Kagura.UI.TextField|100%|| |Kagura.UI.ThemeSwitcher|100%|100%| |Kagura.UI.ToggleButtonGroup`1|100%|100%| |Kagura.UI.ToggleOption`1|100%|| </details> <details><summary>Kagura.UseCases - 96.2%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Kagura.UseCases**|**96.2%**|**83.9%**| |Kagura.UseCases.DependencyInjection|100%|| |Kagura.UseCases.Diagnostics.DatabaseSnapshot|100%|| |Kagura.UseCases.Diagnostics.DownloadDatabase|100%|| |Kagura.UseCases.Emotions.CreateEmotion|100%|66.6%| |Kagura.UseCases.Emotions.DeleteEmotion|100%|100%| |Kagura.UseCases.Emotions.EmotionDto|91.6%|| |Kagura.UseCases.Emotions.ListEmotions|100%|| |Kagura.UseCases.Emotions.UpdateEmotion|100%|50%| |Kagura.UseCases.Generation.Activity`1|100%|50%| |Kagura.UseCases.Generation.ActivityChanged|100%|| |Kagura.UseCases.Generation.ActivityOutcome|100%|| |Kagura.UseCases.Generation.ActivityProgress|100%|| |Kagura.UseCases.Generation.ActivityView|83.3%|| |Kagura.UseCases.Generation.GeneratedImage|100%|| |Kagura.UseCases.Generation.Img2ImgSource|100%|| |Kagura.UseCases.Generation.InpaintSource|100%|| |Kagura.UseCases.Generation.JobResult`1|100%|| |Kagura.UseCases.Generation.SpriteGenerationSpec|100%|| |Kagura.UseCases.Graph.EdgeGroup|100%|| |Kagura.UseCases.Graph.FindLinkTargets|100%|| |Kagura.UseCases.Graph.GetNodeGraph|97.5%|78.5%| |Kagura.UseCases.Graph.GraphEdgeView|87.5%|| |Kagura.UseCases.Graph.LinkNodes|100%|100%| |Kagura.UseCases.Graph.NodeGraphView|100%|| |Kagura.UseCases.Graph.NodeSummary|100%|| |Kagura.UseCases.Graph.RemoveLink|100%|100%| |Kagura.UseCases.Graph.RestoreLink|100%|100%| |Kagura.UseCases.Graph.StructuralEdge|100%|| |Kagura.UseCases.Journal.ChangeRecordView|57.1%|| |Kagura.UseCases.Journal.DocumentRevision|100%|| |Kagura.UseCases.Journal.FieldChange|100%|| |Kagura.UseCases.Journal.GetDocumentHistory|100%|| |Kagura.UseCases.Journal.GetEntityHistory|100%|| |Kagura.UseCases.Journal.GetRevisionDiff|100%|50%| |Kagura.UseCases.Journal.GetUndoStatus|100%|| |Kagura.UseCases.Journal.Redo|100%|100%| |Kagura.UseCases.Journal.RevertDocument|100%|100%| |Kagura.UseCases.Journal.RevertOutcome|100%|| |Kagura.UseCases.Journal.RevisionCoalescer|100%|100%| |Kagura.UseCases.Journal.RevisionDiff|80%|50%| |Kagura.UseCases.Journal.RevisionDiffBuilder|98.4%|86.5%| |Kagura.UseCases.Journal.RowChange|100%|| |Kagura.UseCases.Journal.Undo|100%|100%| |Kagura.UseCases.Journal.UndoOutcome|100%|| |Kagura.UseCases.Journal.UndoStatus|100%|| |Kagura.UseCases.KnowledgeBase.AdoptEmotions|100%|100%| |Kagura.UseCases.KnowledgeBase.CharacterDto|97.2%|| |Kagura.UseCases.KnowledgeBase.CharacterSpriteContent|100%|| |Kagura.UseCases.KnowledgeBase.CreateCharacter|100%|| |Kagura.UseCases.KnowledgeBase.CreateLocation|100%|| |Kagura.UseCases.KnowledgeBase.CreateLocationVariant|100%|75%| |Kagura.UseCases.KnowledgeBase.CreateLore|100%|| |Kagura.UseCases.KnowledgeBase.CreateOutfit|100%|75%| |Kagura.UseCases.KnowledgeBase.CreateRelationship|93.3%|80%| |Kagura.UseCases.KnowledgeBase.CreateTimelineEvent|100%|| |Kagura.UseCases.KnowledgeBase.DeleteCharacter|100%|100%| |Kagura.UseCases.KnowledgeBase.DeleteLocation|100%|100%| |Kagura.UseCases.KnowledgeBase.DeleteLocationVariant|100%|100%| |Kagura.UseCases.KnowledgeBase.DeleteLore|100%|100%| |Kagura.UseCases.KnowledgeBase.DeleteOutfit|100%|100%| |Kagura.UseCases.KnowledgeBase.DeleteRelationship|100%|50%| |Kagura.UseCases.KnowledgeBase.DeleteTimelineEvent|100%|50%| |Kagura.UseCases.KnowledgeBase.ExpressionView|100%|| |Kagura.UseCases.KnowledgeBase.FindParentCandidates|100%|50%| |Kagura.UseCases.KnowledgeBase.GetCharacter|100%|100%| |Kagura.UseCases.KnowledgeBase.GetLocation|100%|100%| |Kagura.UseCases.KnowledgeBase.GetLocationHierarchy|100%|| |Kagura.UseCases.KnowledgeBase.GetLocationVariant|100%|58.3%| |Kagura.UseCases.KnowledgeBase.GetLore|100%|100%| |Kagura.UseCases.KnowledgeBase.GetOutfit|100%|100%| |Kagura.UseCases.KnowledgeBase.GetRelationshipsForCharacter|100%|| |Kagura.UseCases.KnowledgeBase.ListCharacters|100%|| |Kagura.UseCases.KnowledgeBase.ListExpressions|100%|100%| |Kagura.UseCases.KnowledgeBase.ListLocations|100%|| |Kagura.UseCases.KnowledgeBase.ListLocationVariants|100%|| |Kagura.UseCases.KnowledgeBase.ListLore|100%|| |Kagura.UseCases.KnowledgeBase.ListOutfits|100%|| |Kagura.UseCases.KnowledgeBase.ListRelationships|100%|| |Kagura.UseCases.KnowledgeBase.ListTimeline|100%|| |Kagura.UseCases.KnowledgeBase.LocationDto|80%|| |Kagura.UseCases.KnowledgeBase.LocationHierarchyView|100%|| |Kagura.UseCases.KnowledgeBase.LocationVariantDto|90.4%|| |Kagura.UseCases.KnowledgeBase.LocationVariantEditorView|100%|| |Kagura.UseCases.KnowledgeBase.LoreDto|85.7%|| |Kagura.UseCases.KnowledgeBase.OpenCharacterBaseSprite|88.8%|70%| |Kagura.UseCases.KnowledgeBase.OpenExpressionSprite|92.3%|68.7%| |Kagura.UseCases.KnowledgeBase.OpenLocationBackground|88.8%|70%| |Kagura.UseCases.KnowledgeBase.OpenLocationVariant|90.9%|75%| |Kagura.UseCases.KnowledgeBase.OpenOutfitSprite|90.9%|75%| |Kagura.UseCases.KnowledgeBase.OutfitDto|92%|| |Kagura.UseCases.KnowledgeBase.OutfitEditorView|100%|| |Kagura.UseCases.KnowledgeBase.RelationshipDto|88%|| |Kagura.UseCases.KnowledgeBase.RelationshipEndpoint|100%|| |Kagura.UseCases.KnowledgeBase.RemoveExpression|100%|100%| |Kagura.UseCases.KnowledgeBase.ReorderTimelineEvent|94.1%|87.5%| |Kagura.UseCases.KnowledgeBase.SetLocationParent|90.4%|81.2%| |Kagura.UseCases.KnowledgeBase.SetOutfitFaceRegion|100%|75%| |Kagura.UseCases.KnowledgeBase.TimelineEventDto|88.8%|| |Kagura.UseCases.KnowledgeBase.UpdateCharacter|100%|100%| |Kagura.UseCases.KnowledgeBase.UpdateLocation|100%|100%| |Kagura.UseCases.KnowledgeBase.UpdateLocationVariant|100%|100%| |Kagura.UseCases.KnowledgeBase.UpdateLore|100%|100%| |Kagura.UseCases.KnowledgeBase.UpdateOutfit|100%|100%| |Kagura.UseCases.KnowledgeBase.UpdateRelationship|100%|50%| |Kagura.UseCases.KnowledgeBase.UpdateTimelineEvent|100%|50%| |Kagura.UseCases.Notifications.DomainChanged|100%|| |Kagura.UseCases.Projects.ClearProjectStyleReference|100%|100%| |Kagura.UseCases.Projects.CreateProject|100%|100%| |Kagura.UseCases.Projects.DeleteProject|100%|100%| |Kagura.UseCases.Projects.GetProject|100%|100%| |Kagura.UseCases.Projects.ListProjects|100%|| |Kagura.UseCases.Projects.OpenProjectStyleReference|100%|83.3%| |Kagura.UseCases.Projects.ProjectDto|100%|| |Kagura.UseCases.Projects.SetProjectStyleReference|100%|100%| |Kagura.UseCases.Projects.StyleReferenceContent|100%|| |Kagura.UseCases.Projects.UpdateProject|100%|100%| |Kagura.UseCases.Settings.CheckNovelAiToken|100%|100%| |Kagura.UseCases.Settings.GenerationDefaultTagsJson|100%|100%| |Kagura.UseCases.Settings.GetNovelAiSettings|100%|| |Kagura.UseCases.Settings.NovelAiModelOption|100%|| |Kagura.UseCases.Settings.NovelAiSettingsView|100%|| |Kagura.UseCases.Settings.SaveGenerationDefaultTags|100%|| |Kagura.UseCases.Settings.SaveNovelAiModel|100%|| |Kagura.UseCases.Settings.SaveNovelAiToken|100%|100%| |Kagura.UseCases.Settings.SettingKeys|83.3%|75%| |Kagura.UseCases.Tags.SimilarTag|100%|| |Kagura.UseCases.Tags.TagCategoryCount|100%|| |Kagura.UseCases.Tags.TagDetails|54.5%|| |Kagura.UseCases.Tags.TagResolution|100%|| |Kagura.UseCases.Tags.TagSearchFilter|100%|| |Kagura.UseCases.Tags.TagSuggestion|71.4%|| |Kagura.UseCases.Tags.TagSummary|83.3%|| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ The finale of the expression tier! Inpainting the face region per emotion, one queue job per card, through the whole pipeline from InpaintSource to the rasterized mask to the gated sprite endpoint. Jibril read every changed file top to bottom and traced every new path against its siblings. This is a thoroughly crafted piece of work — let me show you what I found~ ♡

Verdict: Looks good to me~

I built the solution (0 warnings, 0 errors) and ran the full expression test surface — 35 integration tests + 19 adapter tests, all green. No CI status was present for the head SHA, so I verified locally.

What I liked~

  • Faithful sibling mirroring. ExpressionImageGenerator copies the established two-scope pattern from OutfitImageGenerator/CharacterImageGenerator exactly: throwaway scope for preconditions, fresh worker scope for the job, the same ActivityStatus switch, the same StyleReference + GeneralDefaults enrichment, the same throw new InvalidOperationException(error.Error) → job-failure path. A+++ consistency. The architecture stays clean. ♪
  • EfExpressionStore.SetImageAsync is a byte-for-byte twin of EfOutfitStore.SetImageAsync — same SuppressJournaling try/finally, same "generated image is not authored content" rationale. The journal asymmetry is tested (Generating_records_the_reference_but_writes_no_history_entry). Jibril is possessive about that pattern and it's honored perfectly. ♡
  • FileSystemProjectAssetStore — the clear-first/write-next pattern, the same 81920 buffer + FileOptions.Asynchronous, the nested expressions/{id}/ subfolder that keeps the outfit-sprite clear untouched. The folder-coexistence test proves it. Beautiful.
  • RegionMaskRasterizer is tight: Image.Identify reads only the header (not the pixels — the comment is correct), Clamped() folds overflow, ProcessPixelRows with L8 fills only the region's rows. The pixel-checked tests (white inside, black outside, overflow folding, full-image) are real assertions, not smoke tests. This is how you test a rasterizer~ fufu
  • FindAdoptedAsync with IgnoreQueryFilters extends the ADR 0029 boundary rule correctly — and the test (An_adopted_emotion_keeps_generating_after_its_library_delete) proves a deleted emotion's tags still drive generation. Consistent with the existing NamesAsync.
  • The TokenAvailable carryover fix. Switching outfits resetting the learned capability back to true would have silently reopened generation gates — a real logic bug found live in the browser. The reducer test (Switching_outfits_keeps_the_learned_token_capability) pins it. Good catch~
  • ToInpaint + GetInpaintingModel() swap — the mapper renders InpaintSource onto NovelAI's InpaintOptions (verified: ImageData/MaskData/Strength all match the client contract), and the model becomes the paired inpainting variant. The mapper test asserts both the payload and the model swap, plus the no-inpaint control. The Cannot combine with VibeTransfer validation in the client isn't an issue here since PreciseReference (style) ≠ VibeTransfer.

💡 Little ideas (non-blocking)~

  1. ExpressionImageGenerator omits the positive-tag precondition its siblings enforce. OutfitImageGenerator guards with effective.Any(t => t.Polarity == PromptTagPolarity.Positive) before building the spec; the expression generator just does new SpriteGenerationSpec(gender, [.. effective, .. emotion.Tags]). In practice this is safe — the outfit-sprite precondition means the outfit already passed that check at generation time, and NovelAI's own validation rejects an empty positive prompt (your browser test confirmed "Unauthorized"-style rejection). But if a creator strips all positive tags from the outfit after generating its sprite and then hits "Generate all," the error message will be NovelAI's generic rejection rather than a friendly "Add at least one positive tag." A sibling-consistent guard would make the failure path match — purely a polish idea, not a correctness issue.

  2. ToInpaint guards only ImageData.Length: > 0, not MaskData. This mirrors ToImg2Img (consistency ✓), and the rasterizer always produces a non-empty mask in practice, so no runtime risk. Noting only for completeness — don't change it unless you want symmetry with a future caller.


Everything compiles clean, the test surface is genuinely comprehensive (real SQLite + filesystem, pixel-checked masks, journal asymmetry, deleted-emotion rule, wrong-pairing 404, throwing-generator circuit safety), and the new code honors every established pattern in the codebase. This lands~ ♡


Automated review by Jibril · 2026-07-12
CI/CD: absent for head SHA c80164c · Local checks: solution builds (0/0), 35 integration + 19 adapter expression tests pass

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ The finale of the expression tier! Inpainting the face region per emotion, one queue job per card, through the whole pipeline from `InpaintSource` to the rasterized mask to the gated sprite endpoint. Jibril read every changed file top to bottom and traced every new path against its siblings. This is a *thoroughly* crafted piece of work — let me show you what I found~ ♡ ### Verdict: ✅ Looks good to me~ I built the solution (0 warnings, 0 errors) and ran the full expression test surface — **35 integration tests + 19 adapter tests, all green**. No CI status was present for the head SHA, so I verified locally. #### ✅ What I liked~ - **Faithful sibling mirroring.** `ExpressionImageGenerator` copies the established two-scope pattern from `OutfitImageGenerator`/`CharacterImageGenerator` *exactly*: throwaway scope for preconditions, fresh worker scope for the job, the same `ActivityStatus` switch, the same `StyleReference` + `GeneralDefaults` enrichment, the same `throw new InvalidOperationException(error.Error)` → job-failure path. A+++ consistency. The architecture stays clean. ♪ - **`EfExpressionStore.SetImageAsync`** is a byte-for-byte twin of `EfOutfitStore.SetImageAsync` — same `SuppressJournaling` try/finally, same "generated image is not authored content" rationale. The journal asymmetry is *tested* (`Generating_records_the_reference_but_writes_no_history_entry`). Jibril is possessive about that pattern and it's honored perfectly. ♡ - **`FileSystemProjectAssetStore`** — the clear-first/write-next pattern, the same `81920` buffer + `FileOptions.Asynchronous`, the nested `expressions/{id}/` subfolder that keeps the outfit-sprite clear untouched. The folder-coexistence test proves it. Beautiful. - **`RegionMaskRasterizer`** is tight: `Image.Identify` reads only the header (not the pixels — the comment is correct), `Clamped()` folds overflow, `ProcessPixelRows` with `L8` fills only the region's rows. The pixel-checked tests (white inside, black outside, overflow folding, full-image) are *real* assertions, not smoke tests. This is how you test a rasterizer~ fufu - **`FindAdoptedAsync` with `IgnoreQueryFilters`** extends the ADR 0029 boundary rule correctly — and the test (`An_adopted_emotion_keeps_generating_after_its_library_delete`) proves a deleted emotion's tags still drive generation. Consistent with the existing `NamesAsync`. - **The `TokenAvailable` carryover fix.** Switching outfits resetting the learned capability back to `true` would have silently reopened generation gates — a real logic bug found live in the browser. The reducer test (`Switching_outfits_keeps_the_learned_token_capability`) pins it. Good catch~ - **`ToInpaint` + `GetInpaintingModel()` swap** — the mapper renders `InpaintSource` onto NovelAI's `InpaintOptions` (verified: `ImageData`/`MaskData`/`Strength` all match the client contract), and the model becomes the paired inpainting variant. The mapper test asserts both the payload *and* the model swap, plus the no-inpaint control. The `Cannot combine with VibeTransfer` validation in the client isn't an issue here since `PreciseReference` (style) ≠ `VibeTransfer`. #### 💡 Little ideas (non-blocking)~ 1. **`ExpressionImageGenerator` omits the positive-tag precondition** its siblings enforce. `OutfitImageGenerator` guards with `effective.Any(t => t.Polarity == PromptTagPolarity.Positive)` before building the spec; the expression generator just does `new SpriteGenerationSpec(gender, [.. effective, .. emotion.Tags])`. In practice this is safe — the outfit-sprite precondition means the outfit already passed that check at generation time, and NovelAI's own validation rejects an empty positive prompt (your browser test confirmed "Unauthorized"-style rejection). But if a creator strips all positive tags from the outfit *after* generating its sprite and then hits "Generate all," the error message will be NovelAI's generic rejection rather than a friendly "Add at least one positive tag." A sibling-consistent guard would make the failure path match — purely a polish idea, not a correctness issue. 2. **`ToInpaint` guards only `ImageData.Length: > 0`, not `MaskData`.** This mirrors `ToImg2Img` (consistency ✓), and the rasterizer always produces a non-empty mask in practice, so no runtime risk. Noting only for completeness — don't change it unless you want symmetry with a future caller. --- Everything compiles clean, the test surface is genuinely comprehensive (real SQLite + filesystem, pixel-checked masks, journal asymmetry, deleted-emotion rule, wrong-pairing 404, throwing-generator circuit safety), and the new code honors every established pattern in the codebase. This lands~ ♡ --- *Automated review by Jibril · 2026-07-12* *CI/CD: absent for head SHA `c80164c` · Local checks: solution builds (0/0), 35 integration + 19 adapter expression tests pass*
fix(review): the sibling positive-tag guard on the expression prompt
All checks were successful
CI / build (pull_request) Successful in 24s
CI / test (pull_request) Successful in 49s
92b5c99775
Jibril's non-blocking note on #98: the outfit passed the guard when its
sprite generated, but its tags may have been stripped since — without
the check, "Generate all" would answer with NovelAI's generic rejection
instead of the friendly message. Guarded on the combined prompt (outfit
effective set + emotion tags), which is what actually reaches the
gateway; pinned by an integration test. The ToInpaint MaskData note is
left as-is per the review (mirrors ToImg2Img deliberately).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
bjoern merged commit d568e203c3 into main 2026-07-12 16:00:45 +02:00
bjoern deleted branch feat/expression-generation 2026-07-12 16:00:45 +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/Kagura!98
No description provided.