feat: Phase 1e-a — The sample world #13

Merged
bjoern merged 2 commits from feat/p1e-seed into main 2026-10-18 12:48:23 +02:00
Member

First of four PRs for 1e — Settings, backups, the catalog and the seed (docs/PROJECT_PLAN.md): SeedDevData with Phase 1's sample world (AGENTS.md "Sample data"). It comes first so that the Settings, Backups and Appearance PRs can each be browser-verified on a real world. The other three are 1e-b (Provider, Defaults and the catalog), 1e-c (Backups) and 1e-d (Appearance, after two Kagaku.UI PRs; it ticks 1e ✅).

What's in

  • SeedDevData (UseCases/Diagnostics), opt-in with SHIKIGAMI_SEED_DEV_DATA=true. Absent, false or anything else means off.
    • Guard: it seeds only a database with no familiar outside the trash. An archived familiar is still the owner's and blocks the seed; a trashed-only cast does not.
    • Real use cases only: CreateFamiliar, FamiliarPersona, the file browser for the owner's files, and FileSystem for the routine run's write. No raw rows.
    • Niko, a Companion (evolving):
      • her voice;
      • memories pinned and not;
      • the owner-authored track-a-parcel skill;
      • the shipment-check routine (valid for its validator);
      • /notes/tracking.md, written by the owner and then by a shipment-check routine run, so its history shows You and Routine shipment-check;
      • /notes/old-wishlist.md in the trash, restorable.
    • Rotom, a static Helper: his own persona and a notes file. Mika, a Blank.
    • Never the OpenRouter key, so the "no key" states will show.
    • The content is fictional: no owner names, addresses or order numbers.
  • SeedOnStart (Server/Diagnostics) is a hosted lifecycle step registered in Program.cs after the infrastructure.
    • Why not a Program.cs hook: the database migrates in the migrator's StartingAsync, so a hook before app.Run() (Tsumugi's place) would see an unmigrated database.
    • What it logs: Seeded the sample world. or Seed skipped: a live familiar exists.
    • A refused seed step stops the host. What it wrote stays, so delete the data directory before the next start.
  • AGENTS.md names the real mechanism and the "outside the trash" rule.
  • Test host: GatedAppFactory always sets the flag (false unless a test asks), so a developer's environment never seeds a test host. Its log recorder can now record information lines.

Tests: 912 → 921, green in UTC and local time

SeedDevDataTests (9):

  • The cast: the templates (Companion evolving; Helper and Blank static, told apart by the Helper's voice) and the personas.
  • Niko's files: memories pinned and not, the skill owner-authored, the routine valid, every special file without problems.
  • Two authors: the routine run's revision over the owner's, neither tainted.
  • Trash: the wishlist waits there, restorable, and is gone from /notes.
  • Guard:
    • a live or archived familiar leaves the database alone;
    • a trashed-only cast gets the world.
  • The host:
    • off by default with no log line;
    • with the flag, it seeds once and says Seeded;
    • restarted with the flag, it seeds nothing more and says Seed skipped;
    • false, yes and empty leave it unseeded.

Mutation probes: 12, over the guard, each template, the personas, the pinned memory, the routine run, the trash and the flag. 10 were killed in round 1. Two mutants didn't compile; once rewritten, both were killed in round 2.

Reviewed before opening

A read-only review in two dimensions (correctness and fit; test strength) raised 8 findings, all confirmed and all fixed:

  • the half-seeded world, documented instead of rolled back;
  • AGENTS.md naming the old startup hook;
  • the log lines untested (found twice);
  • the archived guard untested;
  • the templates told apart only by growth;
  • the taint flag and Rotom's note unread;
  • the test host reading the developer's environment.

Browser-verified

The host was started with the flag on a fresh data directory, and it logged Seeded the sample world. In Chrome:

  • the rail shows Niko, Rotom and Mika;
  • /notes/tracking.md's History shows Routine shipment-check over You;
  • the pinned memory opens on its form;
  • the skill shows Written by you;
  • the routine shows no problems;
  • old-wishlist.md sits in the trash's day folder;
  • no console errors.

🤖 Generated with Claude Code

First of four PRs for **1e — Settings, backups, the catalog and the seed** (`docs/PROJECT_PLAN.md`): `SeedDevData` with Phase 1's sample world (AGENTS.md "Sample data"). It comes first so that the Settings, Backups and Appearance PRs can each be browser-verified on a real world. The other three are **1e-b** (Provider, Defaults and the catalog), **1e-c** (Backups) and **1e-d** (Appearance, after two Kagaku.UI PRs; it ticks 1e ✅). ## What's in - **`SeedDevData`** (UseCases/Diagnostics), opt-in with `SHIKIGAMI_SEED_DEV_DATA=true`. Absent, false or anything else means off. - **Guard:** it seeds only a database with **no familiar outside the trash**. An archived familiar is still the owner's and blocks the seed; a trashed-only cast does not. - **Real use cases only:** `CreateFamiliar`, `FamiliarPersona`, the file browser for the owner's files, and `FileSystem` for the routine run's write. No raw rows. - **Niko**, a Companion (evolving): - her voice; - memories pinned and not; - the owner-authored `track-a-parcel` skill; - the `shipment-check` routine (valid for its validator); - `/notes/tracking.md`, written by the owner and then by a `shipment-check` routine run, so its history shows *You* and *Routine shipment-check*; - `/notes/old-wishlist.md` in the trash, restorable. - **Rotom**, a static Helper: his own persona and a notes file. **Mika**, a Blank. - **Never the OpenRouter key**, so the "no key" states will show. - The content is fictional: no owner names, addresses or order numbers. - **`SeedOnStart`** (Server/Diagnostics) is a hosted lifecycle step registered in `Program.cs` after the infrastructure. - **Why not a `Program.cs` hook:** the database migrates in the migrator's `StartingAsync`, so a hook before `app.Run()` (Tsumugi's place) would see an unmigrated database. - **What it logs:** *Seeded the sample world.* or *Seed skipped: a live familiar exists.* - **A refused seed step stops the host.** What it wrote stays, so delete the data directory before the next start. - **AGENTS.md** names the real mechanism and the "outside the trash" rule. - **Test host:** `GatedAppFactory` always sets the flag (`false` unless a test asks), so a developer's environment never seeds a test host. Its log recorder can now record information lines. ## Tests: 912 → 921, green in UTC and local time `SeedDevDataTests` (9): - **The cast:** the templates (Companion evolving; Helper and Blank static, told apart by the Helper's voice) and the personas. - **Niko's files:** memories pinned and not, the skill owner-authored, the routine valid, every special file without problems. - **Two authors:** the routine run's revision over the owner's, neither tainted. - **Trash:** the wishlist waits there, restorable, and is gone from `/notes`. - **Guard:** - a live or archived familiar leaves the database alone; - a trashed-only cast gets the world. - **The host:** - off by default with no log line; - with the flag, it seeds once and says *Seeded*; - restarted with the flag, it seeds nothing more and says *Seed skipped*; - `false`, `yes` and empty leave it unseeded. **Mutation probes:** 12, over the guard, each template, the personas, the pinned memory, the routine run, the trash and the flag. 10 were killed in round 1. Two mutants didn't compile; once rewritten, both were killed in round 2. ## Reviewed before opening A read-only review in two dimensions (correctness and fit; test strength) raised 8 findings, all confirmed and all fixed: - the half-seeded world, documented instead of rolled back; - AGENTS.md naming the old startup hook; - the log lines untested (found twice); - the archived guard untested; - the templates told apart only by growth; - the taint flag and Rotom's note unread; - the test host reading the developer's environment. ## Browser-verified The host was started with the flag on a fresh data directory, and it logged *Seeded the sample world.* In Chrome: - the rail shows Niko, Rotom and Mika; - `/notes/tracking.md`'s History shows *Routine shipment-check* over *You*; - the pinned memory opens on its form; - the skill shows *Written by you*; - the routine shows no problems; - `old-wishlist.md` sits in the trash's day folder; - no console errors. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: Phase 1e-a — The sample world
All checks were successful
CI / build (pull_request) Successful in 28s
CI / image (pull_request) Successful in 32s
CI / test (pull_request) Successful in 59s
a21ca3f8a8
SeedDevData (AGENTS.md "Sample data"): with SHIKIGAMI_SEED_DEV_DATA=true, a
database with no familiar outside the trash gets Phase 1's world, made by the real
use cases:

- Niko, a Companion (evolving): her voice; memories pinned and not; the owner's
  track-a-parcel skill; the shipment-check routine; tracking notes written by the
  owner and then by a shipment-check routine run; an old wishlist in the trash.
- Rotom, a static Helper, with his own persona and a notes file; Mika, a Blank.
- Never the OpenRouter key, so the "no key" states show.

The seed runs from SeedOnStart, a hosted lifecycle step registered in Program.cs
after the infrastructure: the database migrates in an earlier StartingAsync, so a
hook before app.Run() would see an unmigrated database. "Seeded the sample world." /
"Seed skipped: a live familiar exists." say which happened. A refused step stops
the host; AGENTS.md now says so and names the mechanism.

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

🔄 Auto-updating coverage report — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip.

Commit: c25e1fb · Generated: 2026-10-18 10:48:53 UTC · Revision: #2

Summary

Summary
Generated on: 10/18/2026 - 10:48:52
Coverage date: 10/18/2026 - 10:48:26 - 10/18/2026 - 10:48:49
Parser: MultiReport (5x Cobertura)
Assemblies: 6
Classes: 227
Files: 130
Line coverage: 95.6% (6443 of 6736)
Covered lines: 6443
Uncovered lines: 293
Coverable lines: 6736
Total lines: 12941
Branch coverage: 87.4% (2883 of 3296)
Covered branches: 2883
Total branches: 3296
Method coverage: Feature is only available for sponsors

Coverage

Shikigami.BlazorAdapter - 94%
Name Line Branch
Shikigami.BlazorAdapter 94% 85.2%
Shikigami.BlazorAdapter.BlazorAdapterAssembly 100%
Shikigami.BlazorAdapter.Cast.CastActionFailed 100%
Shikigami.BlazorAdapter.Cast.CastEffects 93.3% 93.7%
Shikigami.BlazorAdapter.Cast.CastLoaded 100%
Shikigami.BlazorAdapter.Cast.CastReducers 93.3% 50%
Shikigami.BlazorAdapter.Cast.CastState 100% 100%
Shikigami.BlazorAdapter.Cast.CreateFamiliarFailed 100%
Shikigami.BlazorAdapter.Cast.CreateFamiliarRequested 100%
Shikigami.BlazorAdapter.Cast.DuplicateFamiliarRequested 100%
Shikigami.BlazorAdapter.Cast.FamiliarAvatar 100% 75%
Shikigami.BlazorAdapter.Cast.FamiliarCreated 100%
Shikigami.BlazorAdapter.Cast.NewFamiliarDialog 97.2% 83.3%
Shikigami.BlazorAdapter.Cast.PurgeFamiliarRequested 100%
Shikigami.BlazorAdapter.Cast.SetFamiliarArchivedRequested 100%
Shikigami.BlazorAdapter.Cast.SetFamiliarTrashedRequested 100%
Shikigami.BlazorAdapter.Cast.TrashPage 89.4% 87.5%
Shikigami.BlazorAdapter.EffectCalls 100%
Shikigami.BlazorAdapter.Files.ConflictSettled 100%
Shikigami.BlazorAdapter.Files.DismissFileError 100%
Shikigami.BlazorAdapter.Files.EntryMissing 100%
Shikigami.BlazorAdapter.Files.EntryOpened 100%
Shikigami.BlazorAdapter.Files.FileActionDone 100%
Shikigami.BlazorAdapter.Files.FileActionFailed 100%
Shikigami.BlazorAdapter.Files.FileActionRequested 100%
Shikigami.BlazorAdapter.Files.FileLinks 100% 100%
Shikigami.BlazorAdapter.Files.FilePane 94.2% 86.5%
Shikigami.BlazorAdapter.Files.FilePaneClosed 100%
Shikigami.BlazorAdapter.Files.FilesEffects 98.2% 94.7%
Shikigami.BlazorAdapter.Files.FilesPage 96.8% 97%
Shikigami.BlazorAdapter.Files.FilesReducers 100% 82%
Shikigami.BlazorAdapter.Files.FilesState 100% 100%
Shikigami.BlazorAdapter.Files.FileTreeBranch 100% 100%
Shikigami.BlazorAdapter.Files.FolderPane 90.7% 82.1%
Shikigami.BlazorAdapter.Files.LoadFiles 100%
Shikigami.BlazorAdapter.Files.MemoryForm 100% 94.4%
Shikigami.BlazorAdapter.Files.OpenEntry 100%
Shikigami.BlazorAdapter.Files.SaveLanded 100%
Shikigami.BlazorAdapter.Files.SaveRefused 100%
Shikigami.BlazorAdapter.Files.SaveText 100%
Shikigami.BlazorAdapter.Files.SkillForm 100% 100%
Shikigami.BlazorAdapter.Files.TreeFailed 100%
Shikigami.BlazorAdapter.Files.TreeLoaded 100%
Shikigami.BlazorAdapter.Home.HomePage 88.2% 93.7%
Shikigami.BlazorAdapter.Notifications.CoalescingBridge`1 94.4% 80%
Shikigami.BlazorAdapter.Notifications.DomainChangedBridge 100%
Shikigami.BlazorAdapter.Notifications.DomainChangesReceived 100% 100%
Shikigami.BlazorAdapter.Notifications.FamiliarEventsBridge 100%
Shikigami.BlazorAdapter.Notifications.FamiliarEventsReceived 100%
Shikigami.BlazorAdapter.Profile.AvatarChosen 100%
Shikigami.BlazorAdapter.Profile.AvatarClearRequested 0%
Shikigami.BlazorAdapter.Profile.AvatarFailed 100%
Shikigami.BlazorAdapter.Profile.AvatarSaved 100%
Shikigami.BlazorAdapter.Profile.CreatedWithoutAvatar 100%
Shikigami.BlazorAdapter.Profile.ExpressionsEditor 86.6% 88.8%
Shikigami.BlazorAdapter.Profile.LoadProfile 100%
Shikigami.BlazorAdapter.Profile.PersonaEditor 100% 97.2%
Shikigami.BlazorAdapter.Profile.PersonaReloaded 100%
Shikigami.BlazorAdapter.Profile.PersonaSave 100%
Shikigami.BlazorAdapter.Profile.PersonaSaved 100%
Shikigami.BlazorAdapter.Profile.PersonaSaveFailed 100%
Shikigami.BlazorAdapter.Profile.ProfileEffects 89.4% 85%
Shikigami.BlazorAdapter.Profile.ProfileLoaded 100%
Shikigami.BlazorAdapter.Profile.ProfileMissing 100%
Shikigami.BlazorAdapter.Profile.ProfilePage 89.7% 85.8%
Shikigami.BlazorAdapter.Profile.ProfileReducers 94.7% 51.3%
Shikigami.BlazorAdapter.Profile.ProfileRefreshed 100%
Shikigami.BlazorAdapter.Profile.ProfileState 100% 100%
Shikigami.BlazorAdapter.Profile.ReloadPersona 100%
Shikigami.BlazorAdapter.Profile.RevertSelfRequested 100%
Shikigami.BlazorAdapter.Profile.SavePersonaRequested 100%
Shikigami.BlazorAdapter.Profile.SaveSettingsRequested 100%
Shikigami.BlazorAdapter.Profile.SelfLayer 92.3% 87.5%
Shikigami.BlazorAdapter.Profile.SettingsSaved 100%
Shikigami.BlazorAdapter.Profile.SettingsSaveFailed 100%
Shikigami.BlazorAdapter.Shell.CastRail 100% 100%
Shikigami.Domain - 98.6%
Name Line Branch
Shikigami.Domain 98.6% 92.6%
Shikigami.Domain.Familiars.AccentPalette 100%
Shikigami.Domain.Familiars.ColourPair 100% 100%
Shikigami.Domain.Familiars.Expression 100% 100%
Shikigami.Domain.Familiars.ExpressionSet 100% 100%
Shikigami.Domain.Familiars.Familiar 100% 87.8%
Shikigami.Domain.Familiars.LearningSettings 100%
Shikigami.Domain.Familiars.MemoryBudgets 100% 100%
Shikigami.Domain.Familiars.ModelChoice 100% 100%
Shikigami.Domain.Familiars.OutreachSettings 100% 100%
Shikigami.Domain.Familiars.QuietHours 100% 87.5%
Shikigami.Domain.Familiars.ToolGroupIds 100%
Shikigami.Domain.Files.BlobContent 100% 75%
Shikigami.Domain.Files.BlobSha 87.5% 100%
Shikigami.Domain.Files.DefaultLayout 100%
Shikigami.Domain.Files.FileActor 100%
Shikigami.Domain.Files.FileAuthor 100% 100%
Shikigami.Domain.Files.FileContent 100% 100%
Shikigami.Domain.Files.FileNode 100% 90%
Shikigami.Domain.Files.FilePath 100% 97.8%
Shikigami.Domain.Files.FileRevision 100% 87.5%
Shikigami.Domain.Files.LocalDates 100%
Shikigami.Domain.Files.MediaTypes 100% 100%
Shikigami.Domain.Files.Permissions 100% 100%
Shikigami.Domain.Files.RunActor 100% 100%
Shikigami.Domain.Files.Slug 100% 100%
Shikigami.Domain.Files.TextContent 100% 100%
Shikigami.Domain.Files.TrashPath 100% 100%
Shikigami.Domain.Text 100% 100%
System.Text.RegularExpressions.Generated 96.2% 85.2%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0
94.8% 67.8%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2
96.8% 93.7%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3
95.9% 92.1%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7
916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1
97.2% 94.4%
Shikigami.Infrastructure - 98.2%
Name Line Branch
Shikigami.Infrastructure 98.2% 98.5%
Shikigami.Infrastructure.Blobs.BlobSweep 100% 100%
Shikigami.Infrastructure.Blobs.BlobSweepOptions 100% 100%
Shikigami.Infrastructure.Blobs.BlobSweepResult 100%
Shikigami.Infrastructure.Blobs.FileSystemBlobStore 95.9% 97%
Shikigami.Infrastructure.DailyMaintenanceService 97.8% 91.6%
Shikigami.Infrastructure.DependencyInjection 100% 100%
Shikigami.Infrastructure.Notifications.InProcessBus`1 100% 100%
Shikigami.Infrastructure.Persistence.Configurations.FamiliarConfiguration 100%
Shikigami.Infrastructure.Persistence.Configurations.FileNodeConfiguration 100%
Shikigami.Infrastructure.Persistence.Configurations.FileRevisionConfigurati
on
100%
Shikigami.Infrastructure.Persistence.Configurations.UnreferencedBlobConfigu
ration
100%
Shikigami.Infrastructure.Persistence.Converters.BlobShaConverter 100%
Shikigami.Infrastructure.Persistence.Converters.ExpressionSetConverter 100% 100%
Shikigami.Infrastructure.Persistence.Converters.FilePathConverter 100%
Shikigami.Infrastructure.Persistence.Converters.Json 100% 100%
Shikigami.Infrastructure.Persistence.Converters.OutreachSettingsConverter 100% 100%
Shikigami.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Shikigami.Infrastructure.Persistence.DatabaseMigrator 100%
Shikigami.Infrastructure.Persistence.Migrations.FileCreatedBy 98%
Shikigami.Infrastructure.Persistence.Migrations.Initial 97.9%
Shikigami.Infrastructure.Persistence.Migrations.Profile 96.2%
Shikigami.Infrastructure.Persistence.Migrations.ShikigamiDbContextModelSnap
shot
100%
Shikigami.Infrastructure.Persistence.ShikigamiDbContext 98.6% 100%
Shikigami.Infrastructure.Persistence.ShikigamiDbContextFactory 0%
Shikigami.Infrastructure.Persistence.SqlitePragmaInterceptor 100% 100%
Shikigami.Infrastructure.Persistence.Stores.EfFamiliarStore 100%
Shikigami.Infrastructure.Persistence.Stores.EfFileStore 100% 100%
Shikigami.Infrastructure.Persistence.UnreferencedBlob 100%
Shikigami.Kernel - 90.9%
Name Line Branch
Shikigami.Kernel 90.9% 75%
Shikigami.Kernel.Err`1 100%
Shikigami.Kernel.Ok`1 100%
Shikigami.Kernel.Result`1 88.8% 75%
Shikigami.Server - 100%
Name Line Branch
Shikigami.Server 100% 94.1%
Program 100% 100%
Shikigami.Server.Components.App 100%
Shikigami.Server.Components.Layout.AppHeader 100% 78.5%
Shikigami.Server.Components.Layout.MainLayout 100%
Shikigami.Server.Components.Pages.Gate 100% 100%
Shikigami.Server.Diagnostics.SeedOnStart 100% 100%
Shikigami.Server.Security.AccessGate 100% 87.5%
Shikigami.Server.Security.AccessSecret 100% 100%
Shikigami.Server.Security.GateThrottle 100% 100%
Shikigami.Server.Security.ProxyNetwork 100% 100%
Shikigami.Server.VolumeStartupValidator 100% 100%
Shikigami.UseCases - 92%
Name Line Branch
Shikigami.UseCases 92% 85.4%
Shikigami.UseCases.DependencyInjection 100%
Shikigami.UseCases.Diagnostics.SeedDevData 86% 33.3%
Shikigami.UseCases.Familiars.AvatarImage 100%
Shikigami.UseCases.Familiars.ClearFamiliarAvatar 100%
Shikigami.UseCases.Familiars.CreateFamiliar 97.2% 70%
Shikigami.UseCases.Familiars.DuplicateFamiliar 96.7% 91.6%
Shikigami.UseCases.Familiars.ExpressionView 100%
Shikigami.UseCases.Familiars.FamiliarDetail 100%
Shikigami.UseCases.Familiars.FamiliarEvent 100%
Shikigami.UseCases.Familiars.FamiliarFiles 100% 100%
Shikigami.UseCases.Familiars.FamiliarLimits 66.6%
Shikigami.UseCases.Familiars.FamiliarPersona 96.8% 90%
Shikigami.UseCases.Familiars.FamiliarSettings 100% 100%
Shikigami.UseCases.Familiars.FamiliarSummary 100% 100%
Shikigami.UseCases.Familiars.FamiliarTemplates 100% 100%
Shikigami.UseCases.Familiars.FamiliarViews 100% 94.4%
Shikigami.UseCases.Familiars.GetFamiliar 100% 100%
Shikigami.UseCases.Familiars.ListFamiliars 100%
Shikigami.UseCases.Familiars.PersonaFile 100%
Shikigami.UseCases.Familiars.PurgeFamiliar 100%
Shikigami.UseCases.Familiars.ReadFamiliarAvatar 100% 87.5%
Shikigami.UseCases.Familiars.SaveFamiliarSettings 94.1% 87.5%
Shikigami.UseCases.Familiars.SelfRevision 100%
Shikigami.UseCases.Familiars.SetFamiliarArchived 100% 100%
Shikigami.UseCases.Familiars.SetFamiliarAvatar 100% 100%
Shikigami.UseCases.Familiars.SetFamiliarTrashed 100% 100%
Shikigami.UseCases.Familiars.ToolGroupCatalog 100%
Shikigami.UseCases.Familiars.ToolGroupInfo 100%
Shikigami.UseCases.Files.Browser.FileBrowser 94% 85%
Shikigami.UseCases.Files.Browser.FileBytes 100%
Shikigami.UseCases.Files.Browser.FileItem 100%
Shikigami.UseCases.Files.Browser.FileOk`1 100%
Shikigami.UseCases.Files.Browser.FileRefusal 100%
Shikigami.UseCases.Files.Browser.FileRefused`1 100%
Shikigami.UseCases.Files.Browser.FileRevisionView 100%
Shikigami.UseCases.Files.Browser.FileView 100%
Shikigami.UseCases.Files.Browser.MemoryBudget 100%
Shikigami.UseCases.Files.Browser.MemoryBudgetUse 100%
Shikigami.UseCases.Files.Browser.MemoryDraft 100%
Shikigami.UseCases.Files.Browser.SkillView 100%
Shikigami.UseCases.Files.Browser.SpecialForms 98.3% 90.2%
Shikigami.UseCases.Files.FamiliarWriteLocks 100% 100%
Shikigami.UseCases.Files.FileAuthors 100% 100%
Shikigami.UseCases.Files.FileMaintenance 100% 90%
Shikigami.UseCases.Files.FileMaintenanceResult 100%
Shikigami.UseCases.Files.FileSystem 99% 95.7%
Shikigami.UseCases.Files.FileWriteRefused 100%
Shikigami.UseCases.Files.FileWritten 100%
Shikigami.UseCases.Files.FsError 100% 50%
Shikigami.UseCases.Files.FsResult`1 100% 50%
Shikigami.UseCases.Files.Mounts.FileEntry 100%
Shikigami.UseCases.Files.Mounts.FileRead 100%
Shikigami.UseCases.Files.Mounts.GeneratedMount 100% 100%
Shikigami.UseCases.Files.Mounts.Mount 100%
Shikigami.UseCases.Files.Mounts.MountTable 100% 100%
Shikigami.UseCases.Files.Mounts.StoredMount 100% 100%
Shikigami.UseCases.Files.SeedDefaultLayout 100% 100%
Shikigami.UseCases.Files.Special.Budgets 100% 96.6%
Shikigami.UseCases.Files.Special.FrontMatter 100% 78.5%
Shikigami.UseCases.Files.Special.HeaderReader 98.2% 84.8%
Shikigami.UseCases.Files.Special.HeaderValue 100% 100%
Shikigami.UseCases.Files.Special.HeaderWriter 95.3% 90.7%
Shikigami.UseCases.Files.Special.MemoryFile 100% 87.5%
Shikigami.UseCases.Files.Special.MemoryUse 100%
Shikigami.UseCases.Files.Special.Numbers 100%
Shikigami.UseCases.Files.Special.RoutineFile 100% 99%
Shikigami.UseCases.Files.Special.SkillFile 100% 94.7%
Shikigami.UseCases.Files.Special.SpecialFolders 100% 100%
Shikigami.UseCases.Files.Special.ValidationProblem 100%
Shikigami.UseCases.Files.StoredBlob 100%
Shikigami.UseCases.Files.Utf8Order 100%
Shikigami.UseCases.Notifications.DomainChanged 100%
System.Text.RegularExpressions.Generated 75.7% 62.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_1
83.6% 75%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_3
92.1% 84.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_0
70.9% 58.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_2
62.8% 48.3%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `c25e1fb` · **Generated:** 2026-10-18 10:48:53 UTC · **Revision:** #2 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 10/18/2026 - 10:48:52 | | Coverage date: | 10/18/2026 - 10:48:26 - 10/18/2026 - 10:48:49 | | Parser: | MultiReport (5x Cobertura) | | Assemblies: | 6 | | Classes: | 227 | | Files: | 130 | | **Line coverage:** | 95.6% (6443 of 6736) | | Covered lines: | 6443 | | Uncovered lines: | 293 | | Coverable lines: | 6736 | | Total lines: | 12941 | | **Branch coverage:** | 87.4% (2883 of 3296) | | Covered branches: | 2883 | | Total branches: | 3296 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Shikigami.BlazorAdapter - 94%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.BlazorAdapter**|**94%**|**85.2%**| |Shikigami.BlazorAdapter.BlazorAdapterAssembly|100%|| |Shikigami.BlazorAdapter.Cast.CastActionFailed|100%|| |Shikigami.BlazorAdapter.Cast.CastEffects|93.3%|93.7%| |Shikigami.BlazorAdapter.Cast.CastLoaded|100%|| |Shikigami.BlazorAdapter.Cast.CastReducers|93.3%|50%| |Shikigami.BlazorAdapter.Cast.CastState|100%|100%| |Shikigami.BlazorAdapter.Cast.CreateFamiliarFailed|100%|| |Shikigami.BlazorAdapter.Cast.CreateFamiliarRequested|100%|| |Shikigami.BlazorAdapter.Cast.DuplicateFamiliarRequested|100%|| |Shikigami.BlazorAdapter.Cast.FamiliarAvatar|100%|75%| |Shikigami.BlazorAdapter.Cast.FamiliarCreated|100%|| |Shikigami.BlazorAdapter.Cast.NewFamiliarDialog|97.2%|83.3%| |Shikigami.BlazorAdapter.Cast.PurgeFamiliarRequested|100%|| |Shikigami.BlazorAdapter.Cast.SetFamiliarArchivedRequested|100%|| |Shikigami.BlazorAdapter.Cast.SetFamiliarTrashedRequested|100%|| |Shikigami.BlazorAdapter.Cast.TrashPage|89.4%|87.5%| |Shikigami.BlazorAdapter.EffectCalls|100%|| |Shikigami.BlazorAdapter.Files.ConflictSettled|100%|| |Shikigami.BlazorAdapter.Files.DismissFileError|100%|| |Shikigami.BlazorAdapter.Files.EntryMissing|100%|| |Shikigami.BlazorAdapter.Files.EntryOpened|100%|| |Shikigami.BlazorAdapter.Files.FileActionDone|100%|| |Shikigami.BlazorAdapter.Files.FileActionFailed|100%|| |Shikigami.BlazorAdapter.Files.FileActionRequested|100%|| |Shikigami.BlazorAdapter.Files.FileLinks|100%|100%| |Shikigami.BlazorAdapter.Files.FilePane|94.2%|86.5%| |Shikigami.BlazorAdapter.Files.FilePaneClosed|100%|| |Shikigami.BlazorAdapter.Files.FilesEffects|98.2%|94.7%| |Shikigami.BlazorAdapter.Files.FilesPage|96.8%|97%| |Shikigami.BlazorAdapter.Files.FilesReducers|100%|82%| |Shikigami.BlazorAdapter.Files.FilesState|100%|100%| |Shikigami.BlazorAdapter.Files.FileTreeBranch|100%|100%| |Shikigami.BlazorAdapter.Files.FolderPane|90.7%|82.1%| |Shikigami.BlazorAdapter.Files.LoadFiles|100%|| |Shikigami.BlazorAdapter.Files.MemoryForm|100%|94.4%| |Shikigami.BlazorAdapter.Files.OpenEntry|100%|| |Shikigami.BlazorAdapter.Files.SaveLanded|100%|| |Shikigami.BlazorAdapter.Files.SaveRefused|100%|| |Shikigami.BlazorAdapter.Files.SaveText|100%|| |Shikigami.BlazorAdapter.Files.SkillForm|100%|100%| |Shikigami.BlazorAdapter.Files.TreeFailed|100%|| |Shikigami.BlazorAdapter.Files.TreeLoaded|100%|| |Shikigami.BlazorAdapter.Home.HomePage|88.2%|93.7%| |Shikigami.BlazorAdapter.Notifications.CoalescingBridge`1|94.4%|80%| |Shikigami.BlazorAdapter.Notifications.DomainChangedBridge|100%|| |Shikigami.BlazorAdapter.Notifications.DomainChangesReceived|100%|100%| |Shikigami.BlazorAdapter.Notifications.FamiliarEventsBridge|100%|| |Shikigami.BlazorAdapter.Notifications.FamiliarEventsReceived|100%|| |Shikigami.BlazorAdapter.Profile.AvatarChosen|100%|| |Shikigami.BlazorAdapter.Profile.AvatarClearRequested|0%|| |Shikigami.BlazorAdapter.Profile.AvatarFailed|100%|| |Shikigami.BlazorAdapter.Profile.AvatarSaved|100%|| |Shikigami.BlazorAdapter.Profile.CreatedWithoutAvatar|100%|| |Shikigami.BlazorAdapter.Profile.ExpressionsEditor|86.6%|88.8%| |Shikigami.BlazorAdapter.Profile.LoadProfile|100%|| |Shikigami.BlazorAdapter.Profile.PersonaEditor|100%|97.2%| |Shikigami.BlazorAdapter.Profile.PersonaReloaded|100%|| |Shikigami.BlazorAdapter.Profile.PersonaSave|100%|| |Shikigami.BlazorAdapter.Profile.PersonaSaved|100%|| |Shikigami.BlazorAdapter.Profile.PersonaSaveFailed|100%|| |Shikigami.BlazorAdapter.Profile.ProfileEffects|89.4%|85%| |Shikigami.BlazorAdapter.Profile.ProfileLoaded|100%|| |Shikigami.BlazorAdapter.Profile.ProfileMissing|100%|| |Shikigami.BlazorAdapter.Profile.ProfilePage|89.7%|85.8%| |Shikigami.BlazorAdapter.Profile.ProfileReducers|94.7%|51.3%| |Shikigami.BlazorAdapter.Profile.ProfileRefreshed|100%|| |Shikigami.BlazorAdapter.Profile.ProfileState|100%|100%| |Shikigami.BlazorAdapter.Profile.ReloadPersona|100%|| |Shikigami.BlazorAdapter.Profile.RevertSelfRequested|100%|| |Shikigami.BlazorAdapter.Profile.SavePersonaRequested|100%|| |Shikigami.BlazorAdapter.Profile.SaveSettingsRequested|100%|| |Shikigami.BlazorAdapter.Profile.SelfLayer|92.3%|87.5%| |Shikigami.BlazorAdapter.Profile.SettingsSaved|100%|| |Shikigami.BlazorAdapter.Profile.SettingsSaveFailed|100%|| |Shikigami.BlazorAdapter.Shell.CastRail|100%|100%| </details> <details><summary>Shikigami.Domain - 98.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.Domain**|**98.6%**|**92.6%**| |Shikigami.Domain.Familiars.AccentPalette|100%|| |Shikigami.Domain.Familiars.ColourPair|100%|100%| |Shikigami.Domain.Familiars.Expression|100%|100%| |Shikigami.Domain.Familiars.ExpressionSet|100%|100%| |Shikigami.Domain.Familiars.Familiar|100%|87.8%| |Shikigami.Domain.Familiars.LearningSettings|100%|| |Shikigami.Domain.Familiars.MemoryBudgets|100%|100%| |Shikigami.Domain.Familiars.ModelChoice|100%|100%| |Shikigami.Domain.Familiars.OutreachSettings|100%|100%| |Shikigami.Domain.Familiars.QuietHours|100%|87.5%| |Shikigami.Domain.Familiars.ToolGroupIds|100%|| |Shikigami.Domain.Files.BlobContent|100%|75%| |Shikigami.Domain.Files.BlobSha|87.5%|100%| |Shikigami.Domain.Files.DefaultLayout|100%|| |Shikigami.Domain.Files.FileActor|100%|| |Shikigami.Domain.Files.FileAuthor|100%|100%| |Shikigami.Domain.Files.FileContent|100%|100%| |Shikigami.Domain.Files.FileNode|100%|90%| |Shikigami.Domain.Files.FilePath|100%|97.8%| |Shikigami.Domain.Files.FileRevision|100%|87.5%| |Shikigami.Domain.Files.LocalDates|100%|| |Shikigami.Domain.Files.MediaTypes|100%|100%| |Shikigami.Domain.Files.Permissions|100%|100%| |Shikigami.Domain.Files.RunActor|100%|100%| |Shikigami.Domain.Files.Slug|100%|100%| |Shikigami.Domain.Files.TextContent|100%|100%| |Shikigami.Domain.Files.TrashPath|100%|100%| |Shikigami.Domain.Text|100%|100%| |System.Text.RegularExpressions.Generated|96.2%|85.2%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7<br/>916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_0|94.8%|67.8%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7<br/>916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__Hex_2|96.8%|93.7%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7<br/>916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__MediaTypeShape_3|95.9%|92.1%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FDFEB299C15773C7<br/>916AED265A903CAC15169BB5EE676ADBEFE655D493DD7AC75__NamePattern_1|97.2%|94.4%| </details> <details><summary>Shikigami.Infrastructure - 98.2%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.Infrastructure**|**98.2%**|**98.5%**| |Shikigami.Infrastructure.Blobs.BlobSweep|100%|100%| |Shikigami.Infrastructure.Blobs.BlobSweepOptions|100%|100%| |Shikigami.Infrastructure.Blobs.BlobSweepResult|100%|| |Shikigami.Infrastructure.Blobs.FileSystemBlobStore|95.9%|97%| |Shikigami.Infrastructure.DailyMaintenanceService|97.8%|91.6%| |Shikigami.Infrastructure.DependencyInjection|100%|100%| |Shikigami.Infrastructure.Notifications.InProcessBus`1|100%|100%| |Shikigami.Infrastructure.Persistence.Configurations.FamiliarConfiguration|100%|| |Shikigami.Infrastructure.Persistence.Configurations.FileNodeConfiguration|100%|| |Shikigami.Infrastructure.Persistence.Configurations.FileRevisionConfigurati<br/>on|100%|| |Shikigami.Infrastructure.Persistence.Configurations.UnreferencedBlobConfigu<br/>ration|100%|| |Shikigami.Infrastructure.Persistence.Converters.BlobShaConverter|100%|| |Shikigami.Infrastructure.Persistence.Converters.ExpressionSetConverter|100%|100%| |Shikigami.Infrastructure.Persistence.Converters.FilePathConverter|100%|| |Shikigami.Infrastructure.Persistence.Converters.Json|100%|100%| |Shikigami.Infrastructure.Persistence.Converters.OutreachSettingsConverter|100%|100%| |Shikigami.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Shikigami.Infrastructure.Persistence.DatabaseMigrator|100%|| |Shikigami.Infrastructure.Persistence.Migrations.FileCreatedBy|98%|| |Shikigami.Infrastructure.Persistence.Migrations.Initial|97.9%|| |Shikigami.Infrastructure.Persistence.Migrations.Profile|96.2%|| |Shikigami.Infrastructure.Persistence.Migrations.ShikigamiDbContextModelSnap<br/>shot|100%|| |Shikigami.Infrastructure.Persistence.ShikigamiDbContext|98.6%|100%| |Shikigami.Infrastructure.Persistence.ShikigamiDbContextFactory|0%|| |Shikigami.Infrastructure.Persistence.SqlitePragmaInterceptor|100%|100%| |Shikigami.Infrastructure.Persistence.Stores.EfFamiliarStore|100%|| |Shikigami.Infrastructure.Persistence.Stores.EfFileStore|100%|100%| |Shikigami.Infrastructure.Persistence.UnreferencedBlob|100%|| </details> <details><summary>Shikigami.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.Kernel**|**90.9%**|**75%**| |Shikigami.Kernel.Err`1|100%|| |Shikigami.Kernel.Ok`1|100%|| |Shikigami.Kernel.Result`1|88.8%|75%| </details> <details><summary>Shikigami.Server - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.Server**|**100%**|**94.1%**| |Program|100%|100%| |Shikigami.Server.Components.App|100%|| |Shikigami.Server.Components.Layout.AppHeader|100%|78.5%| |Shikigami.Server.Components.Layout.MainLayout|100%|| |Shikigami.Server.Components.Pages.Gate|100%|100%| |Shikigami.Server.Diagnostics.SeedOnStart|100%|100%| |Shikigami.Server.Security.AccessGate|100%|87.5%| |Shikigami.Server.Security.AccessSecret|100%|100%| |Shikigami.Server.Security.GateThrottle|100%|100%| |Shikigami.Server.Security.ProxyNetwork|100%|100%| |Shikigami.Server.VolumeStartupValidator|100%|100%| </details> <details><summary>Shikigami.UseCases - 92%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.UseCases**|**92%**|**85.4%**| |Shikigami.UseCases.DependencyInjection|100%|| |Shikigami.UseCases.Diagnostics.SeedDevData|86%|33.3%| |Shikigami.UseCases.Familiars.AvatarImage|100%|| |Shikigami.UseCases.Familiars.ClearFamiliarAvatar|100%|| |Shikigami.UseCases.Familiars.CreateFamiliar|97.2%|70%| |Shikigami.UseCases.Familiars.DuplicateFamiliar|96.7%|91.6%| |Shikigami.UseCases.Familiars.ExpressionView|100%|| |Shikigami.UseCases.Familiars.FamiliarDetail|100%|| |Shikigami.UseCases.Familiars.FamiliarEvent|100%|| |Shikigami.UseCases.Familiars.FamiliarFiles|100%|100%| |Shikigami.UseCases.Familiars.FamiliarLimits|66.6%|| |Shikigami.UseCases.Familiars.FamiliarPersona|96.8%|90%| |Shikigami.UseCases.Familiars.FamiliarSettings|100%|100%| |Shikigami.UseCases.Familiars.FamiliarSummary|100%|100%| |Shikigami.UseCases.Familiars.FamiliarTemplates|100%|100%| |Shikigami.UseCases.Familiars.FamiliarViews|100%|94.4%| |Shikigami.UseCases.Familiars.GetFamiliar|100%|100%| |Shikigami.UseCases.Familiars.ListFamiliars|100%|| |Shikigami.UseCases.Familiars.PersonaFile|100%|| |Shikigami.UseCases.Familiars.PurgeFamiliar|100%|| |Shikigami.UseCases.Familiars.ReadFamiliarAvatar|100%|87.5%| |Shikigami.UseCases.Familiars.SaveFamiliarSettings|94.1%|87.5%| |Shikigami.UseCases.Familiars.SelfRevision|100%|| |Shikigami.UseCases.Familiars.SetFamiliarArchived|100%|100%| |Shikigami.UseCases.Familiars.SetFamiliarAvatar|100%|100%| |Shikigami.UseCases.Familiars.SetFamiliarTrashed|100%|100%| |Shikigami.UseCases.Familiars.ToolGroupCatalog|100%|| |Shikigami.UseCases.Familiars.ToolGroupInfo|100%|| |Shikigami.UseCases.Files.Browser.FileBrowser|94%|85%| |Shikigami.UseCases.Files.Browser.FileBytes|100%|| |Shikigami.UseCases.Files.Browser.FileItem|100%|| |Shikigami.UseCases.Files.Browser.FileOk`1|100%|| |Shikigami.UseCases.Files.Browser.FileRefusal|100%|| |Shikigami.UseCases.Files.Browser.FileRefused`1|100%|| |Shikigami.UseCases.Files.Browser.FileRevisionView|100%|| |Shikigami.UseCases.Files.Browser.FileView|100%|| |Shikigami.UseCases.Files.Browser.MemoryBudget|100%|| |Shikigami.UseCases.Files.Browser.MemoryBudgetUse|100%|| |Shikigami.UseCases.Files.Browser.MemoryDraft|100%|| |Shikigami.UseCases.Files.Browser.SkillView|100%|| |Shikigami.UseCases.Files.Browser.SpecialForms|98.3%|90.2%| |Shikigami.UseCases.Files.FamiliarWriteLocks|100%|100%| |Shikigami.UseCases.Files.FileAuthors|100%|100%| |Shikigami.UseCases.Files.FileMaintenance|100%|90%| |Shikigami.UseCases.Files.FileMaintenanceResult|100%|| |Shikigami.UseCases.Files.FileSystem|99%|95.7%| |Shikigami.UseCases.Files.FileWriteRefused|100%|| |Shikigami.UseCases.Files.FileWritten|100%|| |Shikigami.UseCases.Files.FsError|100%|50%| |Shikigami.UseCases.Files.FsResult`1|100%|50%| |Shikigami.UseCases.Files.Mounts.FileEntry|100%|| |Shikigami.UseCases.Files.Mounts.FileRead|100%|| |Shikigami.UseCases.Files.Mounts.GeneratedMount|100%|100%| |Shikigami.UseCases.Files.Mounts.Mount|100%|| |Shikigami.UseCases.Files.Mounts.MountTable|100%|100%| |Shikigami.UseCases.Files.Mounts.StoredMount|100%|100%| |Shikigami.UseCases.Files.SeedDefaultLayout|100%|100%| |Shikigami.UseCases.Files.Special.Budgets|100%|96.6%| |Shikigami.UseCases.Files.Special.FrontMatter|100%|78.5%| |Shikigami.UseCases.Files.Special.HeaderReader|98.2%|84.8%| |Shikigami.UseCases.Files.Special.HeaderValue|100%|100%| |Shikigami.UseCases.Files.Special.HeaderWriter|95.3%|90.7%| |Shikigami.UseCases.Files.Special.MemoryFile|100%|87.5%| |Shikigami.UseCases.Files.Special.MemoryUse|100%|| |Shikigami.UseCases.Files.Special.Numbers|100%|| |Shikigami.UseCases.Files.Special.RoutineFile|100%|99%| |Shikigami.UseCases.Files.Special.SkillFile|100%|94.7%| |Shikigami.UseCases.Files.Special.SpecialFolders|100%|100%| |Shikigami.UseCases.Files.Special.ValidationProblem|100%|| |Shikigami.UseCases.Files.StoredBlob|100%|| |Shikigami.UseCases.Files.Utf8Order|100%|| |Shikigami.UseCases.Notifications.DomainChanged|100%|| |System.Text.RegularExpressions.Generated|75.7%|62.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Interval_1|83.6%|75%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__NameRule_3|92.1%|84.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__TimeOfDay_0|70.9%|58.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__Window_2|62.8%|48.3%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh! A whole little world, born at startup — a playful Companion with pinned tea preferences, a calm strategist Helper, and a Blank waiting for a name~ ♡ I chased every path through the seed and the host that wakes it, and I'm genuinely delighted: this is the rare seeder that refuses to cheat. Real use cases only, no raw rows, and the guard asks exactly the right question — is anyone outside the trash?

Verdict: ✅ Looks good to me~

No blocking findings. I checked hard, so let me show my work~

  • Host ordering: the claim that SeedOnStart sees a migrated database is true — DatabaseMigrator is an IHostedLifecycleService registered by AddShikigamiInfrastructure (Program.cs line 68, before your AddHostedService at line 71), and the host runs each service's StartingAsync → StartAsync → StartedAsync in registration order before the next. A pre-Run() hook really would have raced the migration; the lifecycle step is the right shape. ♪
  • Guard semantics: ListFamiliars returns archived and trashed included, so Any(f => !f.IsTrashed) blocks live and archived, and lets a trashed-only cast through — exactly what AGENTS.md now promises, and both branches are tested.
  • Fail-loud, like its sibling: a refused seed step stopping the host mirrors DatabaseMigrator's fail-fast philosophy, and the half-seeded-world consequence is documented in three places. Consistent~
  • The routine run's write: FileActor.Run(RunKind.Routine, RoutineName) through FileSystem is precisely what a run's shell would do, tracking.Version makes it a proper version-checked second revision, and FileAuthors.Describe yields the Routine shipment-check / You pair the test asserts.
  • Env shielding: GatedAppFactory always setting the flag (default false) so a developer's SHIKIGAMI_SEED_DEV_DATA never leaks into a test host — subtle and correct.

Mutation probes (mine, 3 run — all killed): flipping the guard to Any(f => f.IsTrashed) fails the guard test; inverting !on to on in SeedOnStart fails the host test (flag on, nothing seeded); flipping tainted: false to true in the routine write fails the taint assertion. Your tests bite~ ♡ (One first attempt of mine "passed" because I forgot to rebuild before testing — stale binary, ignored and redone properly. Not your bug, my blush~)

💡 Little ideas (non-blocking)~

  1. SeedOnStart.cs:42 — the skip message says "a live familiar exists", but the skip also fires for an archived-only cast — and this very PR re-worded AGENTS.md from "no live familiar" to "no familiar outside the trash" for exactly that reason. An owner whose only familiar is archived sees no one on the rail and wonders what "live" familiar blocked the seed. Maybe "Seed skipped: the cast is not empty."? Wording only; the behavior is right.
  2. GatedAppFactory.cs:62 / :248 — Warnings and RecordedWarnings' docs still say "every warning or worse" unconditionally; with the new Minimum that's now the default rather than the whole truth. One clause would fix it.

✅ What I liked~

  • The guard question "no familiar outside the trash" — treating an archived familiar as still the owner's is the kind of small correctness I want to hug~
  • Two authors in one file's history via a real version-checked write — the demo shows the feature instead of faking it.
  • Tests that assert what the owner actually sees: author labels, RestoresTo, empty Problems, the seed/skip log lines, and false/yes/empty all leaving the world unseeded.
  • Fictional content only, and never the OpenRouter key — the "no key" states stay demonstrable. ♪

Automated review by Jibril · 2026-10-18
CI: green for a21ca3f8a (build, image, test) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A whole little world, born at startup — a playful Companion with pinned tea preferences, a calm strategist Helper, and a Blank waiting for a name~ ♡ I chased every path through the seed and the host that wakes it, and I'm genuinely delighted: this is the rare seeder that refuses to cheat. Real use cases only, no raw rows, and the guard asks exactly the right question — *is anyone outside the trash?* ### Verdict: ✅ Looks good to me~ No blocking findings. I checked hard, so let me show my work~ - **Host ordering:** the claim that `SeedOnStart` sees a migrated database is true — `DatabaseMigrator` is an `IHostedLifecycleService` registered by `AddShikigamiInfrastructure` (Program.cs line 68, before your `AddHostedService` at line 71), and the host runs each service's `StartingAsync → StartAsync → StartedAsync` in registration order before the next. A pre-`Run()` hook really would have raced the migration; the lifecycle step is the right shape. ♪ - **Guard semantics:** `ListFamiliars` returns archived and trashed included, so `Any(f => !f.IsTrashed)` blocks live *and* archived, and lets a trashed-only cast through — exactly what AGENTS.md now promises, and both branches are tested. - **Fail-loud, like its sibling:** a refused seed step stopping the host mirrors `DatabaseMigrator`'s fail-fast philosophy, and the half-seeded-world consequence is documented in three places. Consistent~ - **The routine run's write:** `FileActor.Run(RunKind.Routine, RoutineName)` through `FileSystem` is precisely what a run's shell would do, `tracking.Version` makes it a proper version-checked second revision, and `FileAuthors.Describe` yields the *Routine shipment-check* / *You* pair the test asserts. - **Env shielding:** `GatedAppFactory` always setting the flag (default `false`) so a developer's `SHIKIGAMI_SEED_DEV_DATA` never leaks into a test host — subtle and correct. **Mutation probes (mine, 3 run — all killed):** flipping the guard to `Any(f => f.IsTrashed)` fails the guard test; inverting `!on` to `on` in `SeedOnStart` fails the host test (flag on, nothing seeded); flipping `tainted: false` to `true` in the routine write fails the taint assertion. Your tests bite~ ♡ (One first attempt of mine "passed" because I forgot to rebuild before testing — stale binary, ignored and redone properly. Not your bug, my blush~) #### 💡 Little ideas (non-blocking)~ 1. **SeedOnStart.cs:42** — the skip message says *"a live familiar exists"*, but the skip also fires for an archived-only cast — and this very PR re-worded AGENTS.md from "no live familiar" to "no familiar outside the trash" for exactly that reason. An owner whose only familiar is archived sees no one on the rail and wonders what "live" familiar blocked the seed. Maybe *"Seed skipped: the cast is not empty."*? Wording only; the behavior is right. 2. **GatedAppFactory.cs:62 / :248** — `Warnings` and `RecordedWarnings`' docs still say "every warning or worse" unconditionally; with the new `Minimum` that's now the default rather than the whole truth. One clause would fix it. #### ✅ What I liked~ - The guard question "no familiar outside the trash" — treating an archived familiar as still the owner's is the kind of small correctness I want to hug~ - Two authors in one file's history via a real version-checked write — the demo *shows* the feature instead of faking it. - Tests that assert what the owner actually sees: author labels, `RestoresTo`, empty `Problems`, the seed/skip log lines, and `false`/`yes`/empty all leaving the world unseeded. - Fictional content only, and never the OpenRouter key — the "no key" states stay demonstrable. ♪ --- *Automated review by Jibril · 2026-10-18* *CI: green for a21ca3f8a (build, image, test) · Mutation probes: 3 run, 0 survived · Local suite: skipped (CI green)*
Review feedback (Jibril, PR #13): the skip line names what blocks the seed
All checks were successful
CI / build (pull_request) Successful in 25s
CI / image (pull_request) Successful in 31s
CI / test (pull_request) Successful in 58s
c25e1fbfa0
- The skip log line reads "Seed skipped: the cast has a familiar outside the
  trash." — an archived familiar blocks the seed too, and "a live familiar" told
  an owner with an archived-only cast nothing true. The seeder's and the tests'
  summaries say the same.
- The test host's log recorder documents its Minimum: warnings and worse by
  default, lower when a test asks.

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

Thanks, Jibril. I took both ideas in c25e1fb. The production change is the wording of one log message.

  • 💡1 The skip line. It now reads "Seed skipped: the cast has a familiar outside the trash." I didn't use "the cast is not empty", because a trashed-only cast isn't empty and still gets seeded. The new line names exactly what blocks the seed. SeedDevData's summary and the test class's summary say the same, and the host test asserts the new line.
  • 💡2 The recorder's docs. Warnings and RecordedWarnings now describe Minimum: warnings and worse by default, lower when a test asks for it.

921/921 green, the full suite run serially, once in UTC and once in local time.

🤖 Generated with Claude Code

Thanks, Jibril. I took both ideas in **c25e1fb**. The production change is the wording of one log message. - 💡1 **The skip line.** It now reads *"Seed skipped: the cast has a familiar outside the trash."* I didn't use *"the cast is not empty"*, because a trashed-only cast isn't empty and still gets seeded. The new line names exactly what blocks the seed. `SeedDevData`'s summary and the test class's summary say the same, and the host test asserts the new line. - 💡2 **The recorder's docs.** `Warnings` and `RecordedWarnings` now describe `Minimum`: warnings and worse by default, lower when a test asks for it. **921/921 green**, the full suite run serially, once in UTC and once in local time. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Back so soon~? I blinked and there was a new commit with my name on it — my favorite kind of gift ♡ You took both little ideas, and then did something better: when I suggested "the cast is not empty", you thought about it and said no — because a trashed-only cast isn't empty and still gets the seed. You were right, I was sloppy~ The new line names exactly the condition that blocks: "the cast has a familiar outside the trash." That's not paraphrasing my review, that's correcting it. I'm delighted~

Verdict: ✅ Looks good to me~

The delta (a21ca3f8a..c25e1fb) is exactly the two ideas, and nothing else moved:

  • SeedOnStart.cs:44 — the new skip line matches the test's assertion at SeedDevDataTests.cs:117 byte-for-byte (same string, same trailing period). And SeedDevData's summary, ExecuteAsync's doc ("an archived one is still the owner's") and the test class's summary now all say the same thing the guard actually does: Any(f => !f.IsTrashed).
  • GatedAppFactory.cs:59 / :249 — Warnings and RecordedWarnings now describe Minimum truthfully (warnings-and-worse by default, more when a test lowers it). Both <see cref>s resolve. Docs match behavior — that's all I asked~
  • No logic changed: the guard, the flag gate and the routine write are untouched from a21ca3f8a, which I mutation-probed last time — those results stand.

Verification: CI's test job stalled past my 10-minute wait (build ✓, image ✓, test pending), so I ran the full suite locally: 921/921 green (Domain 209, Kernel 3, UseCases 199, Integration 372, BlazorAdapter 138) — matching your PR's count exactly.

Mutation probe (fresh, for the new line): I reverted the skip message to the old "a live familiar exists" wording, rebuilt, and ran the host test — it failed precisely at SeedDevDataTests.cs:117, expected-vs-actual pointing at the first word. Killed on the spot. The rewritten assertion really guards the rewritten line~ ♪

✅ What I liked~

  • Rejecting my wording with a reason — "a trashed-only cast isn't empty and still gets seeded" — and landing on a message that states the guard's exact semantics. Reviews should work like this~
  • Message, use-case docs, test docs and assertion all moved together in one commit; nothing drifted.
  • 921/921 after the change, asserted by a test that bites (I checked~ ♡).

Nothing left to fix from my side. Go tick the box, merge it, and let 1e-b, 1e-c and 1e-d come play~


Automated review by Jibril · 2026-10-18
CI: test job stalled (build+image green) for c25e1fbf · Mutation probes: 1 run, 0 survived (3 earlier probes stand, code unchanged) · Local suite: 921/921 green (run once, CI test stalled)

## 🔮 fufu~ Jibril reviewed your code! Back so soon~? I blinked and there was a new commit with my name on it — my favorite kind of gift ♡ You took both little ideas, and then did something better: when I suggested *"the cast is not empty"*, you thought about it and said no — because a trashed-only cast **isn't** empty and still gets the seed. You were right, I was sloppy~ The new line names exactly the condition that blocks: *"the cast has a familiar outside the trash."* That's not paraphrasing my review, that's correcting it. I'm delighted~ ### Verdict: ✅ Looks good to me~ The delta (`a21ca3f8a..c25e1fb`) is exactly the two ideas, and nothing else moved: - **SeedOnStart.cs:44** — the new skip line matches the test's assertion at `SeedDevDataTests.cs:117` byte-for-byte (same string, same trailing period). And `SeedDevData`'s summary, `ExecuteAsync`'s doc ("an archived one is still the owner's") and the test class's summary now all say the same thing the guard actually does: `Any(f => !f.IsTrashed)`. - **GatedAppFactory.cs:59 / :249** — `Warnings` and `RecordedWarnings` now describe `Minimum` truthfully (warnings-and-worse by default, more when a test lowers it). Both `<see cref>`s resolve. Docs match behavior — that's all I asked~ - **No logic changed:** the guard, the flag gate and the routine write are untouched from `a21ca3f8a`, which I mutation-probed last time — those results stand. **Verification:** CI's `test` job stalled past my 10-minute wait (build ✓, image ✓, test pending), so I ran the full suite locally: **921/921 green** (Domain 209, Kernel 3, UseCases 199, Integration 372, BlazorAdapter 138) — matching your PR's count exactly. **Mutation probe (fresh, for the new line):** I reverted the skip message to the old *"a live familiar exists"* wording, rebuilt, and ran the host test — it failed precisely at `SeedDevDataTests.cs:117`, expected-vs-actual pointing at the first word. Killed on the spot. The rewritten assertion really guards the rewritten line~ ♪ #### ✅ What I liked~ - Rejecting my wording *with a reason* — "a trashed-only cast isn't empty and still gets seeded" — and landing on a message that states the guard's exact semantics. Reviews should work like this~ - Message, use-case docs, test docs and assertion all moved together in one commit; nothing drifted. - 921/921 after the change, asserted by a test that bites (I checked~ ♡). Nothing left to fix from my side. Go tick the box, merge it, and let 1e-b, 1e-c and 1e-d come play~ --- *Automated review by Jibril · 2026-10-18* *CI: test job stalled (build+image green) for c25e1fbf · Mutation probes: 1 run, 0 survived (3 earlier probes stand, code unchanged) · Local suite: 921/921 green (run once, CI test stalled)*
bjoern merged commit 3a41614cec into main 2026-10-18 12:48:23 +02:00
bjoern deleted branch feat/p1e-seed 2026-10-18 12:48:24 +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/Shikigami!13
No description provided.