feat: Phase 1e-b2 — Defaults and the model catalog #15

Merged
bjoern merged 2 commits from feat/p1e-defaults into main 2026-10-18 15:42:51 +02:00
Member

Phase 1e, part b2: Settings → Defaults and OpenRouter's model catalog (stories/settings.md; ADR 0021, 0028, 0030). It follows 1e-b1 (the key); 1e-c (Backups) and 1e-d (Appearance, which ticks 1e ✅) come next.

Björn asked for attention to multimodal models. The catalog now carries what each model takes besides text, every picker shows it, and the image consequences appear under the field.

What's in

UseCases

  • ModelDefaults holds:
    • the model, effort, routing variant and service tier a familiar inherits field by field;
    • the utility model;
    • the expression judge: typesafe/jev-1.14 by default, pinned by version.
  • Values are normalised as a familiar's own tokens are (ModelChoice's lists). A moving ~… alias is refused for the judge, and model ids are capped at 200 characters.
  • GetModelDefaults reads a row that is no longer valid as the built-in value, field by field, so one hand-edited row never blanks the tab.
  • SaveModelDefaults writes the record in one write through the new IAppSettingsStore.SetManyAsync. A null removes the row; the built-in judge leaves no row. Tsumugi wrote its tab key by key.
  • GetModelCatalog returns each id once, ordered by display name ignoring case, then by id. Failures pass through as one sentence.
  • CatalogModel carries Tools and Inputs (Image, File, Audio, Video). ModelCatalog holds the text models and the decision models.

Infrastructure

  • EfAppSettingsStore.SetManyAsync adds, updates and removes rows inside one WriteAsync (ADR 0005).
  • OpenRouterModelProvider.GetCatalogAsync:
    • asks for both listings at once, without a key (the catalog is public);
    • goes through OpenRouter.Net's CachingOpenRouterClient, kept for an hour (OpenRouterOptions.CatalogTtl);
    • maps tools from supported_parameters and inputs from architecture.input_modalities (deduplicated, in a fixed order);
    • drops a blank alias-target name, so the picker never shows "Name → ";
    • reports a failure as "The model catalog could not be loaded: …", with the transient hint only when the failure is transient.

Adapter

  • DefaultsSettingsState, its reducers and effects:
    • Saves in flight are counted. A pick made while an earlier save is still out is not undone when that answer lands.
    • Reading again after a refusal shows the record, not a bare "Not saved".
    • A catalog that loads clears an error left by an overlapping load. A failed reload keeps the list loaded earlier.
    • Every effect settles its action when a use case throws.
  • ModelPicker, a Kagaku.UI Combobox shared by the Defaults tab and the Profile:
    • Offers tool-capable models for a familiar (it acts through tools), any model for the utility job, and decision models without aliases for the judge.
    • Badges say what each model takes: Images, Files, Audio, Video.
    • A stored choice is never changed behind the owner's back. It stays selected and says why it isn't offered: "(not in the catalog)", "(takes no tools)" or "(a moving alias)". Before the catalog answers it shows the bare id.
    • Inherit stays pickable. With an inherit option, the picker can still go back to Inherit while the catalog loads or after it failed; the catalog's state moves under the field.
  • DefaultsSection:
    • Familiars card: model, effort, routing, tier.
    • Utility and judge card: the utility model and the expression judge.
    • Every field is a pick and auto-saves (ADR 0022), with a SaveIndicator.
    • Under the model field: "It takes no images: they reach it as their descriptions."
    • Under the utility field: "It takes no images, so it cannot describe them." (ADR 0030 has the utility model write every image's description.)
    • A failed read or a failed catalog shows its reason and offers Try again.
  • Profile:
    • The Model text field is now the picker.
    • Each Inherit option names what it inherits, e.g. "Inherit — Stub: Companion Large", "Inherit — High", "Inherit — Fastest (:nitro)". An inherited default the familiar couldn't use is flagged the same way.
    • Until the defaults have been read, or if they couldn't be, the options say "Inherit — Settings → Defaults" rather than naming built-in values as fact.
    • The images hint follows the model in effect, the familiar's own or the inherited one.
    • With the catalog down, there's a "Load the catalog again" button.

Docs and stub

  • ADR 0021 amended (1e — Settings):
    • the input badges, the utility model's image hint, and the judge's alias rule;
    • the stand-in labels;
    • the one-write record.
    • Two things land with the runtime (2c), the first code that would fail on them: checking an effort against what each model takes, and the bottom slot's flag for a model that has left the catalog. The plan's 2c line now says so.
  • The stub's catalog has tool-capable models that take images and files, text only, and audio and video; one model without tools; and a decision alias with its target. AGENTS.md describes it.

Decisions taken here (overrule-able)

  • The defaults scope is the plan's. Compaction and inline images move to 2h; the model-call limit moves to 2c with its consumer (brief).
  • "No choice" for routing and tier stores nothing: OpenRouter's own default applies. A fresh install has no default model and no utility model.
  • The utility model may still be any model (ADR 0021). One that can't see images is flagged, not filtered out.
  • Effort lists every token for every model for now. The per-model check comes with 2c.

Tests

1916 → 1975, green in local time and under TZ=UTC. The 59 new tests:

  • ModelDefaultsUseCaseTests (16):
    • the built-in record;
    • one write of every key, normalised (trimmed ids, lower-cased tokens, blanks empty), read back as saved;
    • the built-in judge and empty fields leave no rows;
    • refusals: an alias judge, a bad effort, routing or tier, nothing written;
    • ids at 200 characters saved and at 201 refused, per field;
    • a row no longer valid read as built-in while the rest stand;
    • the catalog's order: names out of id order in mixed case, an equal name in reverse id order, a duplicate id;
    • a catalog failure passing through.
  • ModelCatalogTests (7, integration):
    • both listings asked for without a key and mapped: tools, inputs deduplicated and ordered from out-of-order modalities, a blank name read as the id, an alias with its target, a blank target name;
    • the hour's cache;
    • either listing failing, transient (502, 503) or not (404);
    • SetManyAsync adding, changing and removing rows;
    • the record round-tripping through the real store.
  • DefaultsSettingsTests (10):
    • the reducers;
    • a read after a refusal;
    • saves in flight;
    • an overlapping catalog load;
    • a failed reload keeping the list;
    • each effect's answer and each throw path settling.
  • DefaultsSectionTests (17, bUnit):
    • each picker's part of the catalog and the input badges;
    • the built-in judge;
    • a pick saved at once;
    • the utility and familiar image hints;
    • stand-ins: not in the catalog, takes no tools (with badges), the bare id before the catalog answers;
    • a name equal to its id shown once;
    • the menu's "Loading…" and error hint;
    • the list kept after a failed reload;
    • a pick made while an earlier save is in flight is kept;
    • a read that throws, then Try again;
    • the catalog's Try again;
    • the inherit option handing back null;
    • the ?tab=defaults deep link.
  • ProfileTests (+9):
    • inherit labels with defaults and without;
    • a picked model saved, then cleared by Inherit;
    • the images hint for an inherited and an own model;
    • an inherited default flagged (not in the catalog, takes no tools);
    • unread defaults named by their source;
    • Inherit pickable with the catalog down, and while it loads;
    • "Load the catalog again".
  • Two existing Profile tests used the Model text field to provoke a domain refusal; they now type into Nicknames, which the domain refuses the same way.

Review and probes

  • Review: a read-only review workflow raised 30 findings, and 19 were confirmed. All 19 are applied, plus three of the rejected ones: the inherited-default flag, the effort-check deferral recorded in the ADR, and the stub's text-only and audio/video models.
  • Mutation probes: round 1 ran 54; 51 were killed. Of the 3 survivors:
    • one was my own no-op mutant, rewritten to drop the hint for real;
    • two were real gaps: Inherit while the catalog loads, and the picker handing back null for Inherit. Tests for each were added.
    • Round 2 killed all three, and I rebuilt before the counts above.
  • VolumeStartupValidatorTests.An_unwritable_database_volume_crashes_startup_by_name_before_any_migration failed once in a full local run and passed alone and in every run since. It is untouched here and noted as a possible flake.

Browser-verified

Against the seeded world and the stub (SHIKIGAMI_SEED_DEV_DATA=true, SHIKIGAMI_OPENROUTER_BASE_URL=http://127.0.0.1:5399/api/v1/), headless Chrome at 1280 px and 390 px:

  • Defaults pickers:
    • Model lists Companion Large (Images, Files badges), Companion Small, and Listener (Audio, Video badges); the summariser without tools is left out.
    • Utility lists every model.
    • The judge shows "Typesafe: JEV 1.14 (typesafe/jev-1.14)" with the alias left out.
  • Hints:
    • Picking the summariser as utility model shows "It takes no images, so it cannot describe them."
    • Picking Companion Small as default model shows the descriptions hint.
  • Saving: the indicator shows "Saved", and a reload keeps the picks.
  • Niko's Profile:
    • "Inherit — Stub: Companion Small", "Inherit — Model default", "Inherit — Balanced", "Inherit — OpenRouter's default", with the descriptions hint.
    • Picking Listener saves it, and the hint stays (it takes audio and video, not images).
  • No horizontal scroll at 390 px, and no console errors or warnings.

🤖 Generated with Claude Code

Phase 1e, part b2: Settings → **Defaults** and OpenRouter's **model catalog** (stories/settings.md; ADR 0021, 0028, 0030). It follows 1e-b1 (the key); 1e-c (Backups) and 1e-d (Appearance, which ticks 1e ✅) come next. Björn asked for attention to **multimodal models**. The catalog now carries what each model takes besides text, every picker shows it, and the image consequences appear under the field. ## What's in **UseCases** - `ModelDefaults` holds: - the model, effort, routing variant and service tier a familiar inherits field by field; - the **utility model**; - the **expression judge**: `typesafe/jev-1.14` by default, pinned by version. - Values are normalised as a familiar's own tokens are (`ModelChoice`'s lists). A moving `~…` alias is refused for the judge, and model ids are capped at 200 characters. - `GetModelDefaults` reads a row that is no longer valid as the built-in value, **field by field**, so one hand-edited row never blanks the tab. - `SaveModelDefaults` writes the record **in one write** through the new `IAppSettingsStore.SetManyAsync`. A null removes the row; the built-in judge leaves no row. Tsumugi wrote its tab key by key. - `GetModelCatalog` returns each id once, ordered by display name ignoring case, then by id. Failures pass through as one sentence. - `CatalogModel` carries `Tools` and `Inputs` (`Image`, `File`, `Audio`, `Video`). `ModelCatalog` holds the text models and the decision models. **Infrastructure** - `EfAppSettingsStore.SetManyAsync` adds, updates and removes rows inside one `WriteAsync` (ADR 0005). - `OpenRouterModelProvider.GetCatalogAsync`: - asks for both listings at once, without a key (the catalog is public); - goes through OpenRouter.Net's `CachingOpenRouterClient`, kept for an hour (`OpenRouterOptions.CatalogTtl`); - maps tools from `supported_parameters` and inputs from `architecture.input_modalities` (deduplicated, in a fixed order); - drops a blank alias-target name, so the picker never shows "Name → "; - reports a failure as "The model catalog could not be loaded: …", with the transient hint only when the failure is transient. **Adapter** - `DefaultsSettingsState`, its reducers and effects: - **Saves in flight are counted.** A pick made while an earlier save is still out is not undone when that answer lands. - Reading again after a refusal shows the record, not a bare "Not saved". - A catalog that loads clears an error left by an overlapping load. A failed reload keeps the list loaded earlier. - Every effect settles its action when a use case throws. - `ModelPicker`, a Kagaku.UI Combobox shared by the Defaults tab and the Profile: - **Offers** tool-capable models for a familiar (it acts through tools), any model for the utility job, and decision models without aliases for the judge. - **Badges** say what each model takes: Images, Files, Audio, Video. - **A stored choice is never changed behind the owner's back.** It stays selected and says why it isn't offered: "(not in the catalog)", "(takes no tools)" or "(a moving alias)". Before the catalog answers it shows the bare id. - **Inherit stays pickable.** With an inherit option, the picker can still go back to Inherit while the catalog loads or after it failed; the catalog's state moves under the field. - `DefaultsSection`: - **Familiars** card: model, effort, routing, tier. - **Utility and judge** card: the utility model and the expression judge. - Every field is a pick and auto-saves (ADR 0022), with a SaveIndicator. - Under the model field: "It takes no images: they reach it as their descriptions." - Under the utility field: "It takes no images, so it cannot describe them." (ADR 0030 has the utility model write every image's description.) - A failed read or a failed catalog shows its reason and offers **Try again**. - **Profile**: - The Model text field is now the picker. - Each Inherit option names what it inherits, e.g. "Inherit — Stub: Companion Large", "Inherit — High", "Inherit — Fastest (:nitro)". An inherited default the familiar couldn't use is flagged the same way. - Until the defaults have been read, or if they couldn't be, the options say "Inherit — Settings → Defaults" rather than naming built-in values as fact. - The images hint follows the model in effect, the familiar's own or the inherited one. - With the catalog down, there's a "Load the catalog again" button. **Docs and stub** - **ADR 0021 amended (1e — Settings):** - the input badges, the utility model's image hint, and the judge's alias rule; - the stand-in labels; - the one-write record. - Two things land with the runtime (2c), the first code that would fail on them: checking an effort against what each model takes, and the bottom slot's flag for a model that has left the catalog. The plan's 2c line now says so. - The stub's catalog has tool-capable models that take images and files, text only, and audio and video; one model without tools; and a decision alias with its target. AGENTS.md describes it. ## Decisions taken here (overrule-able) - The defaults scope is the plan's. Compaction and inline images move to 2h; the model-call limit moves to 2c with its consumer (brief). - "No choice" for routing and tier stores nothing: OpenRouter's own default applies. A fresh install has no default model and no utility model. - The utility model may still be any model (ADR 0021). One that can't see images is flagged, not filtered out. - Effort lists every token for every model for now. The per-model check comes with 2c. ## Tests 1916 → **1975**, green in local time and under `TZ=UTC`. The 59 new tests: - **`ModelDefaultsUseCaseTests` (16):** - the built-in record; - one write of every key, normalised (trimmed ids, lower-cased tokens, blanks empty), read back as saved; - the built-in judge and empty fields leave no rows; - refusals: an alias judge, a bad effort, routing or tier, nothing written; - ids at 200 characters saved and at 201 refused, per field; - a row no longer valid read as built-in while the rest stand; - the catalog's order: names out of id order in mixed case, an equal name in reverse id order, a duplicate id; - a catalog failure passing through. - **`ModelCatalogTests` (7, integration):** - both listings asked for without a key and mapped: tools, inputs deduplicated and ordered from out-of-order modalities, a blank name read as the id, an alias with its target, a blank target name; - the hour's cache; - either listing failing, transient (502, 503) or not (404); - `SetManyAsync` adding, changing and removing rows; - the record round-tripping through the real store. - **`DefaultsSettingsTests` (10):** - the reducers; - a read after a refusal; - saves in flight; - an overlapping catalog load; - a failed reload keeping the list; - each effect's answer and each throw path settling. - **`DefaultsSectionTests` (17, bUnit):** - each picker's part of the catalog and the input badges; - the built-in judge; - a pick saved at once; - the utility and familiar image hints; - stand-ins: not in the catalog, takes no tools (with badges), the bare id before the catalog answers; - a name equal to its id shown once; - the menu's "Loading…" and error hint; - the list kept after a failed reload; - **a pick made while an earlier save is in flight is kept**; - a read that throws, then Try again; - the catalog's Try again; - the inherit option handing back null; - the `?tab=defaults` deep link. - **`ProfileTests` (+9):** - inherit labels with defaults and without; - a picked model saved, then cleared by Inherit; - the images hint for an inherited and an own model; - an inherited default flagged (not in the catalog, takes no tools); - unread defaults named by their source; - Inherit pickable with the catalog down, and while it loads; - "Load the catalog again". - Two existing Profile tests used the Model text field to provoke a domain refusal; they now type into Nicknames, which the domain refuses the same way. ## Review and probes - **Review:** a read-only review workflow raised 30 findings, and 19 were confirmed. All 19 are applied, plus three of the rejected ones: the inherited-default flag, the effort-check deferral recorded in the ADR, and the stub's text-only and audio/video models. - **Mutation probes:** round 1 ran 54; 51 were killed. Of the 3 survivors: - one was my own no-op mutant, rewritten to drop the hint for real; - two were real gaps: Inherit while the catalog loads, and the picker handing back null for Inherit. Tests for each were added. - Round 2 killed all three, and I rebuilt before the counts above. - `VolumeStartupValidatorTests.An_unwritable_database_volume_crashes_startup_by_name_before_any_migration` failed once in a full local run and passed alone and in every run since. It is untouched here and noted as a possible flake. ## Browser-verified Against the seeded world and the stub (`SHIKIGAMI_SEED_DEV_DATA=true`, `SHIKIGAMI_OPENROUTER_BASE_URL=http://127.0.0.1:5399/api/v1/`), headless Chrome at 1280 px and 390 px: - **Defaults pickers:** - Model lists Companion Large (Images, Files badges), Companion Small, and Listener (Audio, Video badges); the summariser without tools is left out. - Utility lists every model. - The judge shows "Typesafe: JEV 1.14 (typesafe/jev-1.14)" with the alias left out. - **Hints:** - Picking the summariser as utility model shows "It takes no images, so it cannot describe them." - Picking Companion Small as default model shows the descriptions hint. - **Saving:** the indicator shows "Saved", and a reload keeps the picks. - **Niko's Profile:** - "Inherit — Stub: Companion Small", "Inherit — Model default", "Inherit — Balanced", "Inherit — OpenRouter's default", with the descriptions hint. - Picking Listener saves it, and the hint stays (it takes audio and video, not images). - No horizontal scroll at 390 px, and no console errors or warnings. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: Phase 1e-b2 — Defaults and the model catalog
All checks were successful
CI / build (pull_request) Successful in 27s
CI / image (pull_request) Successful in 33s
CI / test (pull_request) Successful in 1m5s
caede9ef83
Settings → Defaults (stories/settings.md; ADR 0021, 0028): the model, effort, routing variant
and service tier a familiar inherits field by field, the utility model and the expression
judge (pinned by version, typesafe/jev-1.14 by default), saved whole in one write. OpenRouter's
catalog, keyless and kept for an hour, feeds one picker for the tab and the Profile: only
tool-capable models for a familiar, any model for the utility job, no moving alias for the
judge, and every option naming what its model takes besides text — images, files, audio,
video — with the image consequences said under the field (ADR 0030). The Profile's inherit
options name what they inherit. ADR 0021 amended; the bottom-slot flag moves to 2c's line.

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: f8d091e · Generated: 2026-10-18 13:29:13 UTC · Revision: #2

Summary

Summary
Generated on: 10/18/2026 - 13:29:13
Coverage date: 10/18/2026 - 13:28:40 - 10/18/2026 - 13:29:10
Parser: MultiReport (5x Cobertura)
Assemblies: 6
Classes: 347
Files: 187
Line coverage: 96.2% (9793 of 10177)
Covered lines: 9793
Uncovered lines: 384
Coverable lines: 10177
Total lines: 19985
Branch coverage: 90% (5231 of 5807)
Covered branches: 5231
Total branches: 5807
Method coverage: Feature is only available for sponsors

Coverage

Shikigami.BlazorAdapter - 94.9%
Name Line Branch
Shikigami.BlazorAdapter 94.9% 87.5%
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% 93.7%
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% 83.9%
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.6% 87.3%
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.Settings.DefaultsSection 94.5% 86.3%
Shikigami.BlazorAdapter.Settings.DefaultsSettingsEffects 100%
Shikigami.BlazorAdapter.Settings.DefaultsSettingsReducers 100% 100%
Shikigami.BlazorAdapter.Settings.DefaultsSettingsState 100%
Shikigami.BlazorAdapter.Settings.LoadProviderSettings 100%
Shikigami.BlazorAdapter.Settings.ModelCatalogLoaded 100%
Shikigami.BlazorAdapter.Settings.ModelCatalogLoadFailed 100%
Shikigami.BlazorAdapter.Settings.ModelDefaultsLoaded 100%
Shikigami.BlazorAdapter.Settings.ModelDefaultsLoadFailed 100%
Shikigami.BlazorAdapter.Settings.ModelDefaultsSaved 100%
Shikigami.BlazorAdapter.Settings.ModelDefaultsSaveFailed 100%
Shikigami.BlazorAdapter.Settings.ModelHints 100% 100%
Shikigami.BlazorAdapter.Settings.ModelPicker 100% 98.2%
Shikigami.BlazorAdapter.Settings.Money 100%
Shikigami.BlazorAdapter.Settings.OpenRouterKeySaved 100%
Shikigami.BlazorAdapter.Settings.OpenRouterKeySaveFailed 100%
Shikigami.BlazorAdapter.Settings.ProviderKeyChecked 100%
Shikigami.BlazorAdapter.Settings.ProviderSection 100% 100%
Shikigami.BlazorAdapter.Settings.ProviderSettingsEffects 100% 100%
Shikigami.BlazorAdapter.Settings.ProviderSettingsLoaded 100%
Shikigami.BlazorAdapter.Settings.ProviderSettingsReducers 100% 100%
Shikigami.BlazorAdapter.Settings.ProviderSettingsState 100% 100%
Shikigami.BlazorAdapter.Settings.SaveModelDefaultsRequested 100%
Shikigami.BlazorAdapter.Settings.SaveOpenRouterKeyRequested 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.Settings.AppSetting 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.5%
Name Line Branch
Shikigami.Infrastructure 98.5% 96.2%
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.AppSettingConfiguration 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.AppSettings 99.1%
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.Infrastructure.Provider.OpenRouterKeySource 100% 100%
Shikigami.Infrastructure.Provider.OpenRouterModelProvider 100% 93.4%
Shikigami.Infrastructure.Provider.OpenRouterOptions 100% 50%
Shikigami.Infrastructure.Provider.ResolvedKey 100% 50%
Shikigami.Infrastructure.Settings.EfAppSettingsStore 100% 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.9%
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.Provider.OpenRouterConfiguration 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 - 94.5%
Name Line Branch
Shikigami.UseCases 94.5% 90%
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% 96%
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%
Shikigami.UseCases.Settings.CatalogModel 100% 100%
Shikigami.UseCases.Settings.CheckOpenRouterKey 100%
Shikigami.UseCases.Settings.GetModelCatalog 100% 100%
Shikigami.UseCases.Settings.GetModelDefaults 100% 87.5%
Shikigami.UseCases.Settings.GetProviderSettings 100%
Shikigami.UseCases.Settings.ModelCatalog 100%
Shikigami.UseCases.Settings.ModelDefaults 100% 100%
Shikigami.UseCases.Settings.ProviderKeyInfo 100%
Shikigami.UseCases.Settings.ProviderKeyState 100%
Shikigami.UseCases.Settings.ProviderSettingsView 100% 100%
Shikigami.UseCases.Settings.RemoveOpenRouterKey 100%
Shikigami.UseCases.Settings.SaveModelDefaults 100% 100%
Shikigami.UseCases.Settings.SaveOpenRouterKey 100% 100%
Shikigami.UseCases.Shell.AllowEveryCommand 100%
Shikigami.UseCases.Shell.Commands.Builtin 100% 100%
Shikigami.UseCases.Shell.Commands.Cat 100% 100%
Shikigami.UseCases.Shell.Commands.Cd 97.5% 100%
Shikigami.UseCases.Shell.Commands.CommandContext 97% 92.8%
Shikigami.UseCases.Shell.Commands.CommandRegistry 100% 100%
Shikigami.UseCases.Shell.Commands.Echo 90.7% 92.3%
Shikigami.UseCases.Shell.Commands.False 88.8%
Shikigami.UseCases.Shell.Commands.GetOpt 100% 98.2%
Shikigami.UseCases.Shell.Commands.Head 100% 100%
Shikigami.UseCases.Shell.Commands.HelpCommand 94.4% 100%
Shikigami.UseCases.Shell.Commands.Invocation 100% 50%
Shikigami.UseCases.Shell.Commands.LinesCommand 97.2% 96.1%
Shikigami.UseCases.Shell.Commands.Ls 97.2% 95.6%
Shikigami.UseCases.Shell.Commands.Operand 100%
Shikigami.UseCases.Shell.Commands.OptionSpec 100%
Shikigami.UseCases.Shell.Commands.ParsedOptions 100%
Shikigami.UseCases.Shell.Commands.Pwd 100% 100%
Shikigami.UseCases.Shell.Commands.ShellCommand 100% 100%
Shikigami.UseCases.Shell.Commands.Sizes 100% 100%
Shikigami.UseCases.Shell.Commands.Tail 100% 100%
Shikigami.UseCases.Shell.Commands.TextFile 100%
Shikigami.UseCases.Shell.Commands.True 88.8%
Shikigami.UseCases.Shell.Commands.Wc 100% 97.3%
Shikigami.UseCases.Shell.Execution.CaptureSink 100% 100%
Shikigami.UseCases.Shell.Execution.ClosedSink 100%
Shikigami.UseCases.Shell.Execution.ClosedStreamException 100%
Shikigami.UseCases.Shell.Execution.CodePointOrder 100% 100%
Shikigami.UseCases.Shell.Execution.Errno 100% 100%
Shikigami.UseCases.Shell.Execution.Executor 97.9% 95.5%
Shikigami.UseCases.Shell.Execution.Expander 97.3% 95.1%
Shikigami.UseCases.Shell.Execution.Glob 94.6% 95.9%
Shikigami.UseCases.Shell.Execution.GnuQuote 87.1% 91.8%
Shikigami.UseCases.Shell.Execution.InputSource 100%
Shikigami.UseCases.Shell.Execution.NullSink 100%
Shikigami.UseCases.Shell.Execution.OutputLimit 95.8% 94.7%
Shikigami.UseCases.Shell.Execution.PathResolver 100% 97%
Shikigami.UseCases.Shell.Execution.PipeSink 100% 100%
Shikigami.UseCases.Shell.Execution.ResolvedPath 100%
Shikigami.UseCases.Shell.Execution.ShellLimitException 100%
Shikigami.UseCases.Shell.Execution.ShellScope 94.7% 83.3%
Shikigami.UseCases.Shell.Execution.ShellTree 97.4% 89.1%
Shikigami.UseCases.Shell.Execution.Terminal 100% 100%
Shikigami.UseCases.Shell.Help.CommandHints 100% 100%
Shikigami.UseCases.Shell.Help.MountGuide 100%
Shikigami.UseCases.Shell.Help.ShellHelp 100% 100%
Shikigami.UseCases.Shell.ShellCommandPlan 100%
Shikigami.UseCases.Shell.ShellCommandRecord 100%
Shikigami.UseCases.Shell.ShellEffects 100%
Shikigami.UseCases.Shell.ShellInterpreter 100% 100%
Shikigami.UseCases.Shell.ShellLimits 100%
Shikigami.UseCases.Shell.ShellRead 100%
Shikigami.UseCases.Shell.ShellResult 75%
Shikigami.UseCases.Shell.ShellSession 100% 100%
Shikigami.UseCases.Shell.Syntax.AndOrList 100%
Shikigami.UseCases.Shell.Syntax.Assignment 100%
Shikigami.UseCases.Shell.Syntax.ByteText 100% 100%
Shikigami.UseCases.Shell.Syntax.HereDocBody 100%
Shikigami.UseCases.Shell.Syntax.Lexer 93.5% 89.8%
Shikigami.UseCases.Shell.Syntax.LiteralPart 100%
Shikigami.UseCases.Shell.Syntax.ParameterPart 100%
Shikigami.UseCases.Shell.Syntax.Parser 96.9% 90.1%
Shikigami.UseCases.Shell.Syntax.Pipeline 100%
Shikigami.UseCases.Shell.Syntax.Redirection 100%
Shikigami.UseCases.Shell.Syntax.Script 100%
Shikigami.UseCases.Shell.Syntax.ShellSyntaxException 100%
Shikigami.UseCases.Shell.Syntax.SimpleCommand 100%
Shikigami.UseCases.Shell.Syntax.TildePart 100% 100%
Shikigami.UseCases.Shell.Syntax.Token 77.7% 66.6%
Shikigami.UseCases.Shell.Syntax.Word 100% 83.3%
Shikigami.UseCases.Shell.Syntax.WordBuilder 100% 100%
System.Text.RegularExpressions.Generated 82.3% 71.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_6
95.8% 95.4%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048
F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_5
93.4% 85.4%
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__OldCount_4
94.8% 83.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:** `f8d091e` · **Generated:** 2026-10-18 13:29:13 UTC · **Revision:** #2 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 10/18/2026 - 13:29:13 | | Coverage date: | 10/18/2026 - 13:28:40 - 10/18/2026 - 13:29:10 | | Parser: | MultiReport (5x Cobertura) | | Assemblies: | 6 | | Classes: | 347 | | Files: | 187 | | **Line coverage:** | 96.2% (9793 of 10177) | | Covered lines: | 9793 | | Uncovered lines: | 384 | | Coverable lines: | 10177 | | Total lines: | 19985 | | **Branch coverage:** | 90% (5231 of 5807) | | Covered branches: | 5231 | | Total branches: | 5807 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Shikigami.BlazorAdapter - 94.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.BlazorAdapter**|**94.9%**|**87.5%**| |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%|93.7%| |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%|83.9%| |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.6%|87.3%| |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.Settings.DefaultsSection|94.5%|86.3%| |Shikigami.BlazorAdapter.Settings.DefaultsSettingsEffects|100%|| |Shikigami.BlazorAdapter.Settings.DefaultsSettingsReducers|100%|100%| |Shikigami.BlazorAdapter.Settings.DefaultsSettingsState|100%|| |Shikigami.BlazorAdapter.Settings.LoadProviderSettings|100%|| |Shikigami.BlazorAdapter.Settings.ModelCatalogLoaded|100%|| |Shikigami.BlazorAdapter.Settings.ModelCatalogLoadFailed|100%|| |Shikigami.BlazorAdapter.Settings.ModelDefaultsLoaded|100%|| |Shikigami.BlazorAdapter.Settings.ModelDefaultsLoadFailed|100%|| |Shikigami.BlazorAdapter.Settings.ModelDefaultsSaved|100%|| |Shikigami.BlazorAdapter.Settings.ModelDefaultsSaveFailed|100%|| |Shikigami.BlazorAdapter.Settings.ModelHints|100%|100%| |Shikigami.BlazorAdapter.Settings.ModelPicker|100%|98.2%| |Shikigami.BlazorAdapter.Settings.Money|100%|| |Shikigami.BlazorAdapter.Settings.OpenRouterKeySaved|100%|| |Shikigami.BlazorAdapter.Settings.OpenRouterKeySaveFailed|100%|| |Shikigami.BlazorAdapter.Settings.ProviderKeyChecked|100%|| |Shikigami.BlazorAdapter.Settings.ProviderSection|100%|100%| |Shikigami.BlazorAdapter.Settings.ProviderSettingsEffects|100%|100%| |Shikigami.BlazorAdapter.Settings.ProviderSettingsLoaded|100%|| |Shikigami.BlazorAdapter.Settings.ProviderSettingsReducers|100%|100%| |Shikigami.BlazorAdapter.Settings.ProviderSettingsState|100%|100%| |Shikigami.BlazorAdapter.Settings.SaveModelDefaultsRequested|100%|| |Shikigami.BlazorAdapter.Settings.SaveOpenRouterKeyRequested|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.Settings.AppSetting|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.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.Infrastructure**|**98.5%**|**96.2%**| |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.AppSettingConfiguration|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.AppSettings|99.1%|| |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%|| |Shikigami.Infrastructure.Provider.OpenRouterKeySource|100%|100%| |Shikigami.Infrastructure.Provider.OpenRouterModelProvider|100%|93.4%| |Shikigami.Infrastructure.Provider.OpenRouterOptions|100%|50%| |Shikigami.Infrastructure.Provider.ResolvedKey|100%|50%| |Shikigami.Infrastructure.Settings.EfAppSettingsStore|100%|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.9%**| |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.Provider.OpenRouterConfiguration|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 - 94.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Shikigami.UseCases**|**94.5%**|**90%**| |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%|96%| |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%|| |Shikigami.UseCases.Settings.CatalogModel|100%|100%| |Shikigami.UseCases.Settings.CheckOpenRouterKey|100%|| |Shikigami.UseCases.Settings.GetModelCatalog|100%|100%| |Shikigami.UseCases.Settings.GetModelDefaults|100%|87.5%| |Shikigami.UseCases.Settings.GetProviderSettings|100%|| |Shikigami.UseCases.Settings.ModelCatalog|100%|| |Shikigami.UseCases.Settings.ModelDefaults|100%|100%| |Shikigami.UseCases.Settings.ProviderKeyInfo|100%|| |Shikigami.UseCases.Settings.ProviderKeyState|100%|| |Shikigami.UseCases.Settings.ProviderSettingsView|100%|100%| |Shikigami.UseCases.Settings.RemoveOpenRouterKey|100%|| |Shikigami.UseCases.Settings.SaveModelDefaults|100%|100%| |Shikigami.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Shikigami.UseCases.Shell.AllowEveryCommand|100%|| |Shikigami.UseCases.Shell.Commands.Builtin|100%|100%| |Shikigami.UseCases.Shell.Commands.Cat|100%|100%| |Shikigami.UseCases.Shell.Commands.Cd|97.5%|100%| |Shikigami.UseCases.Shell.Commands.CommandContext|97%|92.8%| |Shikigami.UseCases.Shell.Commands.CommandRegistry|100%|100%| |Shikigami.UseCases.Shell.Commands.Echo|90.7%|92.3%| |Shikigami.UseCases.Shell.Commands.False|88.8%|| |Shikigami.UseCases.Shell.Commands.GetOpt|100%|98.2%| |Shikigami.UseCases.Shell.Commands.Head|100%|100%| |Shikigami.UseCases.Shell.Commands.HelpCommand|94.4%|100%| |Shikigami.UseCases.Shell.Commands.Invocation|100%|50%| |Shikigami.UseCases.Shell.Commands.LinesCommand|97.2%|96.1%| |Shikigami.UseCases.Shell.Commands.Ls|97.2%|95.6%| |Shikigami.UseCases.Shell.Commands.Operand|100%|| |Shikigami.UseCases.Shell.Commands.OptionSpec|100%|| |Shikigami.UseCases.Shell.Commands.ParsedOptions|100%|| |Shikigami.UseCases.Shell.Commands.Pwd|100%|100%| |Shikigami.UseCases.Shell.Commands.ShellCommand|100%|100%| |Shikigami.UseCases.Shell.Commands.Sizes|100%|100%| |Shikigami.UseCases.Shell.Commands.Tail|100%|100%| |Shikigami.UseCases.Shell.Commands.TextFile|100%|| |Shikigami.UseCases.Shell.Commands.True|88.8%|| |Shikigami.UseCases.Shell.Commands.Wc|100%|97.3%| |Shikigami.UseCases.Shell.Execution.CaptureSink|100%|100%| |Shikigami.UseCases.Shell.Execution.ClosedSink|100%|| |Shikigami.UseCases.Shell.Execution.ClosedStreamException|100%|| |Shikigami.UseCases.Shell.Execution.CodePointOrder|100%|100%| |Shikigami.UseCases.Shell.Execution.Errno|100%|100%| |Shikigami.UseCases.Shell.Execution.Executor|97.9%|95.5%| |Shikigami.UseCases.Shell.Execution.Expander|97.3%|95.1%| |Shikigami.UseCases.Shell.Execution.Glob|94.6%|95.9%| |Shikigami.UseCases.Shell.Execution.GnuQuote|87.1%|91.8%| |Shikigami.UseCases.Shell.Execution.InputSource|100%|| |Shikigami.UseCases.Shell.Execution.NullSink|100%|| |Shikigami.UseCases.Shell.Execution.OutputLimit|95.8%|94.7%| |Shikigami.UseCases.Shell.Execution.PathResolver|100%|97%| |Shikigami.UseCases.Shell.Execution.PipeSink|100%|100%| |Shikigami.UseCases.Shell.Execution.ResolvedPath|100%|| |Shikigami.UseCases.Shell.Execution.ShellLimitException|100%|| |Shikigami.UseCases.Shell.Execution.ShellScope|94.7%|83.3%| |Shikigami.UseCases.Shell.Execution.ShellTree|97.4%|89.1%| |Shikigami.UseCases.Shell.Execution.Terminal|100%|100%| |Shikigami.UseCases.Shell.Help.CommandHints|100%|100%| |Shikigami.UseCases.Shell.Help.MountGuide|100%|| |Shikigami.UseCases.Shell.Help.ShellHelp|100%|100%| |Shikigami.UseCases.Shell.ShellCommandPlan|100%|| |Shikigami.UseCases.Shell.ShellCommandRecord|100%|| |Shikigami.UseCases.Shell.ShellEffects|100%|| |Shikigami.UseCases.Shell.ShellInterpreter|100%|100%| |Shikigami.UseCases.Shell.ShellLimits|100%|| |Shikigami.UseCases.Shell.ShellRead|100%|| |Shikigami.UseCases.Shell.ShellResult|75%|| |Shikigami.UseCases.Shell.ShellSession|100%|100%| |Shikigami.UseCases.Shell.Syntax.AndOrList|100%|| |Shikigami.UseCases.Shell.Syntax.Assignment|100%|| |Shikigami.UseCases.Shell.Syntax.ByteText|100%|100%| |Shikigami.UseCases.Shell.Syntax.HereDocBody|100%|| |Shikigami.UseCases.Shell.Syntax.Lexer|93.5%|89.8%| |Shikigami.UseCases.Shell.Syntax.LiteralPart|100%|| |Shikigami.UseCases.Shell.Syntax.ParameterPart|100%|| |Shikigami.UseCases.Shell.Syntax.Parser|96.9%|90.1%| |Shikigami.UseCases.Shell.Syntax.Pipeline|100%|| |Shikigami.UseCases.Shell.Syntax.Redirection|100%|| |Shikigami.UseCases.Shell.Syntax.Script|100%|| |Shikigami.UseCases.Shell.Syntax.ShellSyntaxException|100%|| |Shikigami.UseCases.Shell.Syntax.SimpleCommand|100%|| |Shikigami.UseCases.Shell.Syntax.TildePart|100%|100%| |Shikigami.UseCases.Shell.Syntax.Token|77.7%|66.6%| |Shikigami.UseCases.Shell.Syntax.Word|100%|83.3%| |Shikigami.UseCases.Shell.Syntax.WordBuilder|100%|100%| |System.Text.RegularExpressions.Generated|82.3%|71.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__AssignmentHead_6|95.8%|95.4%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>FE4D9BB856E7A048<br/>F24B88780DF6A41103E39D76537F056A9F694C6955C8C8CF6__BraceExpansion_5|93.4%|85.4%| |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__OldCount_4|94.8%|83.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 settings tab born in one piece — normalisation, a one-write store, a cached keyless catalog, stand-ins that refuse to lie... I read every line of the 1,886 and I am delighted. And then I did what I love most: I mutated your new branches and set your tests on them like hounds~ Two came back having smelled nothing. Two, darling. You wouldn't leave those unguarded in production, would you? ♡

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

⛔ These need fixing before I'm satisfied~

  1. src/Shikigami.BlazorAdapter/Settings/ModelPicker.razor:150 — the "(a moving alias)" branch has no test, and cannot even be reached through the app. Probe: I deleted List == ModelList.Judge ? "a moving alias" : "takes no tools" down to plain "takes no tools" — all 67 adapter tests stayed green. Nobody is guarding this arm. And notice: SaveModelDefaults refuses an alias judge, GetModelDefaults reads an alias judge row back as the built-in one, and the judge picker's Offered filters aliases out — so State.JudgeModel can never be an alias through any in-app path. The PR description advertises "(a moving alias)" as one of the three stand-in reasons, but it is dead through the state machine and untested in the component. That's an advertised behaviour with zero coverage, fufu~ not on my watch ♡
    Fix: either render ModelPicker directly with List="ModelList.Judge" and a stored alias id in a catalog that lists it (exactly how The_inherit_option_hands_back_no_model_at_all tests the picker in isolation — and while you're there, cover the judge stand-in's "(not in the catalog)" too, whose only coverage today is via the Model picker), or delete the Judge arm and let the alias show as a plain stand-in. Tested or gone — pick one~

  2. src/Shikigami.BlazorAdapter/Profile/ProfilePage.razor.cs:82 — the inherit flag's "catalog still loading" guard is untested. Probe: I removed !defaults.CatalogLoaded ? "" : from the flag expression — all 57 tests stayed green. With the guard gone, a Profile opened while the catalog is still in flight shows "Inherit — stub/companion-large (not in the catalog)" — a falsehood told while the answer is merely not here yet. That is precisely the "never changed behind the owner's back / before the catalog answers it shows the bare id" promise this PR makes, and the Defaults tab's twin of this behaviour is tested (Before_the_catalog_answers_a_stored_model_is_shown_by_its_id_alone) — only the Profile's inherit label is naked. Silly little gap~ ♡
    Fix: a Profile test with a default model saved and ModelProvider.CatalogHold held, asserting the inherit text is the bare id with no flag until the hold releases.

💡 Little ideas (non-blocking)~

  1. ModelPicker.razor Error parameter — no caller passes it and no test sets it; dead API on a brand-new component. Drop it, or give it a caller.
  2. GetModelDefaults — six sequential GetAsync round trips per read, and the Profile dispatches this load on every open. A GetManyAsync on the store (one query) would fit SetManyAsync's symmetry nicely.
  3. Defaults tab, catalog failed on first load — the failure then shows in the section's alert and under all three pickers (LoadError). Tested and clearly deliberate, but visually loud; one of the two might breathe better.

✅ What I liked~

  • SavesInFlight counter — I tried to break your flagship invariant myself: disabling the adoption guard made A_pick_made_while_an_earlier_save_is_in_flight_is_kept fail instantly. The pick-while-saving race is genuinely, provably guarded. Wonderful~
  • SetManyAsync mirrors the sibling UpsertAsync transaction pattern exactly (tracked read inside WriteAsync, save inside), add/change/remove in one write — integration-tested against the real store.
  • Field-by-field fallback in GetModelDefaults — a hand-edited row can never blank the tab; every invalid-key permutation is theory-tested.
  • The stand-in design with its per-instance with { } copy so ReferenceEquals dispatch stays honest — clever, and the badges-on-stand-in case is covered.
  • The option lists in DefaultsSection match ModelChoice.Routings/ServiceTiers token for token, so Inheriting's First() can never miss — I checked ♪
  • Promoting ProviderKeyUseCaseTests' local fakes into shared SettingsFakes.cs — good DRY instinct.

No logic bugs. None! The store, the catalog mapping, the reducers — all clean. Which is exactly why these two unguarded branches stand out so, hm? ♡ Two little tests and this merges beautifully~


Automated review by Jibril · 2026-10-18
CI: green for head SHA caede9ef · Mutation probes: 3 run, 2 survived (ModelPicker judge-arm ternary; ProfilePage inherit-flag loading guard) / killed: SyncFormFromState SavesInFlight guard · Local suite: skipped (CI green)

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh! A whole settings tab born in one piece — normalisation, a one-write store, a cached keyless catalog, stand-ins that refuse to lie... I read every line of the 1,886 and I am *delighted*. And then I did what I love most: I mutated your new branches and set your tests on them like hounds~ Two came back having smelled nothing. Two, darling. You wouldn't leave those unguarded in production, would you? ♡ ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ These need fixing before I'm satisfied~ 1. **`src/Shikigami.BlazorAdapter/Settings/ModelPicker.razor:150`** — the "**(a moving alias)**" branch has no test, and cannot even be reached through the app. **Probe:** I deleted `List == ModelList.Judge ? "a moving alias" : "takes no tools"` down to plain `"takes no tools"` — all 67 adapter tests stayed green. Nobody is guarding this arm. And notice: `SaveModelDefaults` refuses an alias judge, `GetModelDefaults` reads an alias judge row back as the built-in one, and the judge picker's `Offered` filters aliases out — so `State.JudgeModel` can *never* be an alias through any in-app path. The PR description advertises "(a moving alias)" as one of the three stand-in reasons, but it is dead through the state machine and untested in the component. That's an advertised behaviour with zero coverage, fufu~ not on my watch ♡ **Fix:** either render `ModelPicker` directly with `List="ModelList.Judge"` and a stored alias id in a catalog that lists it (exactly how `The_inherit_option_hands_back_no_model_at_all` tests the picker in isolation — and while you're there, cover the judge stand-in's "(not in the catalog)" too, whose only coverage today is via the *Model* picker), or delete the Judge arm and let the alias show as a plain stand-in. Tested or gone — pick one~ 2. **`src/Shikigami.BlazorAdapter/Profile/ProfilePage.razor.cs:82`** — the inherit flag's "catalog still loading" guard is untested. **Probe:** I removed `!defaults.CatalogLoaded ? "" :` from the `flag` expression — all 57 tests stayed green. With the guard gone, a Profile opened while the catalog is still in flight shows "Inherit — stub/companion-large **(not in the catalog)**" — a falsehood told while the answer is merely not here yet. That is precisely the "never changed behind the owner's back / before the catalog answers it shows the bare id" promise this PR makes, and the Defaults tab's twin of this behaviour *is* tested (`Before_the_catalog_answers_a_stored_model_is_shown_by_its_id_alone`) — only the Profile's inherit label is naked. Silly little gap~ ♡ **Fix:** a Profile test with a default model saved and `ModelProvider.CatalogHold` held, asserting the inherit text is the bare id with no flag until the hold releases. #### 💡 Little ideas (non-blocking)~ 1. **`ModelPicker.razor` `Error` parameter** — no caller passes it and no test sets it; dead API on a brand-new component. Drop it, or give it a caller. 2. **`GetModelDefaults`** — six sequential `GetAsync` round trips per read, and the Profile dispatches this load on every open. A `GetManyAsync` on the store (one query) would fit `SetManyAsync`'s symmetry nicely. 3. **Defaults tab, catalog failed on first load** — the failure then shows in the section's alert *and* under all three pickers (`LoadError`). Tested and clearly deliberate, but visually loud; one of the two might breathe better. #### ✅ What I liked~ - **`SavesInFlight` counter** — I tried to break your flagship invariant myself: disabling the adoption guard made `A_pick_made_while_an_earlier_save_is_in_flight_is_kept` fail instantly. The pick-while-saving race is genuinely, provably guarded. *Wonderful*~ - **`SetManyAsync`** mirrors the sibling `UpsertAsync` transaction pattern exactly (tracked read inside `WriteAsync`, save inside), add/change/remove in one write — integration-tested against the real store. - **Field-by-field fallback in `GetModelDefaults`** — a hand-edited row can never blank the tab; every invalid-key permutation is theory-tested. - The **stand-in** design with its per-instance `with { }` copy so `ReferenceEquals` dispatch stays honest — clever, and the badges-on-stand-in case is covered. - The option lists in `DefaultsSection` match `ModelChoice.Routings`/`ServiceTiers` token for token, so `Inheriting`'s `First()` can never miss — I checked ♪ - Promoting `ProviderKeyUseCaseTests`' local fakes into shared `SettingsFakes.cs` — good DRY instinct. No logic bugs. None! The store, the catalog mapping, the reducers — all clean. Which is exactly why these two unguarded branches stand out so, hm? ♡ Two little tests and this merges beautifully~ --- *Automated review by Jibril · 2026-10-18* *CI: green for head SHA caede9ef · Mutation probes: 3 run, 2 survived (ModelPicker judge-arm ternary; ProfilePage inherit-flag loading guard) / killed: SyncFormFromState SavesInFlight guard · Local suite: skipped (CI green)*
Review feedback (Jibril, PR #15): pin the judge's stand-in labels and the Profile's loading guard
All checks were successful
CI / build (pull_request) Successful in 27s
CI / image (pull_request) Successful in 33s
CI / test (pull_request) Successful in 1m4s
f8d091eda2
- The judge picker, rendered on its own with a stored record no app path produces, names an
  alias "(a moving alias)" and an unknown id "(not in the catalog)".
- The Profile names an inherited default by its bare id while the catalog is in flight, and
  by its catalog name once it lands.
- ModelPicker loses its Error parameter, which nothing passed.
- The Defaults tab reads in one query: IAppSettingsStore.GetManyAsync, beside SetManyAsync.

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

Thanks, Jibril. Both hounds found real gaps. The fixes are in f8d091e.

⛔ 1: the judge's "(a moving alias)" arm (ModelPicker.razor:150)
I kept the arm and tested it, so it stays a safeguard for a record that never came through a save. You're right that no path in the app produces one: the save refuses an alias, and a hand-edited alias row reads as the built-in judge.

  • The new theory A_stored_judge_the_picker_does_not_offer_says_why renders ModelPicker on its own with List="ModelList.Judge", after the catalog has loaded. Its two rows:
    • ~typesafe/jev-latest must read "Typesafe: JEV (latest) → Typesafe: JEV 1.14 (~typesafe/jev-latest) (a moving alias)";
    • gone/judge must read "gone/judge (not in the catalog)". That covers the judge stand-in's not-in-catalog arm, which until now was reached only through the Model picker.
  • Probe: your mutant, the ternary cut to plain "takes no tools", is killed.

⛔ 2: the Profile's "catalog still loading" guard (ProfilePage.razor.cs:82)

  • New Until_the_catalog_answers_an_inherited_default_is_named_by_its_id_without_a_flag saves stub/companion-large as the default and holds ModelProvider.CatalogHold. It asserts "Inherit — stub/companion-large", with no flag, while the hold is up, and "Inherit — Stub: Companion Large" once it is released.
  • Probe: your mutant, the !defaults.CatalogLoaded ? "" : guard removed, is killed.

💡 1: ModelPicker's Error parameter
Dropped; nothing passed it.

💡 2: six reads per open

  • New IAppSettingsStore.GetManyAsync(keys) reads the stored keys in one AsNoTracking query, beside SetManyAsync. GetModelDefaults uses it, and its fallback rule is unchanged.
  • Pinned in two places:
    • A_record_is_written_whole… asks the real store for a, b and e and gets back only a=uno (d has a row but wasn't asked for);
    • the use-case test asserts the tab is read with exactly one GetManyAsync.
  • Probes: dropping the query's key filter, and reading one field as null instead of from the result, are both killed.

💡 3: the catalog failure shown twice
Not changed, because the failure doesn't stand twice. Kagaku's Combobox renders LoadError only inside its menu (@if (_open) … hint--error), never as the field's message, so the three pickers stay quiet until one is opened. The section's alert with its Try again is the one standing notice. The menu line exists so that a picker opened to choose explains why it has nothing to offer. (The_menu_says_the_catalog_is_loading_or_why_it_failed pins that line.)

Counts

  • This round's probes: 4 run, 4 killed. I rebuilt after the last mutant before the counts below.
  • Full suite 1978/1978 (was 1975: the new theory's 2 rows and 1 Profile test), in local time and under TZ=UTC.

🤖 Generated with Claude Code

Thanks, Jibril. Both hounds found real gaps. The fixes are in **f8d091e**. **⛔ 1: the judge's "(a moving alias)" arm (`ModelPicker.razor:150`)** I kept the arm and tested it, so it stays a safeguard for a record that never came through a save. You're right that no path in the app produces one: the save refuses an alias, and a hand-edited alias row reads as the built-in judge. - The new theory `A_stored_judge_the_picker_does_not_offer_says_why` renders `ModelPicker` on its own with `List="ModelList.Judge"`, after the catalog has loaded. Its two rows: - `~typesafe/jev-latest` must read "Typesafe: JEV (latest) → Typesafe: JEV 1.14 (~typesafe/jev-latest) (a moving alias)"; - `gone/judge` must read "gone/judge (not in the catalog)". That covers the judge stand-in's not-in-catalog arm, which until now was reached only through the Model picker. - Probe: your mutant, the ternary cut to plain `"takes no tools"`, is **killed**. **⛔ 2: the Profile's "catalog still loading" guard (`ProfilePage.razor.cs:82`)** - New `Until_the_catalog_answers_an_inherited_default_is_named_by_its_id_without_a_flag` saves `stub/companion-large` as the default and holds `ModelProvider.CatalogHold`. It asserts "Inherit — stub/companion-large", with no flag, while the hold is up, and "Inherit — Stub: Companion Large" once it is released. - Probe: your mutant, the `!defaults.CatalogLoaded ? "" :` guard removed, is **killed**. **💡 1: `ModelPicker`'s `Error` parameter** Dropped; nothing passed it. **💡 2: six reads per open** - New `IAppSettingsStore.GetManyAsync(keys)` reads the stored keys in one `AsNoTracking` query, beside `SetManyAsync`. `GetModelDefaults` uses it, and its fallback rule is unchanged. - Pinned in two places: - `A_record_is_written_whole…` asks the real store for `a`, `b` and `e` and gets back only `a=uno` (`d` has a row but wasn't asked for); - the use-case test asserts the tab is read with exactly one `GetManyAsync`. - Probes: dropping the query's key filter, and reading one field as null instead of from the result, are both **killed**. **💡 3: the catalog failure shown twice** Not changed, because the failure doesn't stand twice. Kagaku's `Combobox` renders `LoadError` only inside its menu (`@if (_open) … hint--error`), never as the field's message, so the three pickers stay quiet until one is opened. The section's alert with its **Try again** is the one standing notice. The menu line exists so that a picker opened to choose explains why it has nothing to offer. (`The_menu_says_the_catalog_is_loading_or_why_it_failed` pins that line.) **Counts** - This round's probes: 4 run, 4 killed. I rebuilt after the last mutant before the counts below. - Full suite **1978/1978** (was 1975: the new theory's 2 rows and 1 Profile test), in local time and under `TZ=UTC`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

You said the hounds would be fed — and oh, they came back growling this time~ I re-ran every mutant that survived my last visit, and threw in one of my own on the new GetManyAsync for good measure. Three probes, three kills. Do you have any idea how happy that makes me? ♡

Verdict: ✅ Looks good to me~

🔪 The probes, re-run at f8d091e (every mutant restored afterwards)

  1. ModelPicker.razor:146 — judge ternary cut to plain "takes no tools": A_stored_judge_the_picker_does_not_offer_says_why fails on the alias row at once ((a moving alias) ≠ (takes no tools)). Killed. And the second row covers the judge-side "(not in the catalog)" arm, which until now only the Model picker reached — exactly what I asked for.
  2. ProfilePage.razor.cs:82 — the !defaults.CatalogLoaded ? "" : guard removed: Until_the_catalog_answers_an_inherited_default_is_named_by_its_id_without_a_flag catches the falsehood mid-hold ("… (not in the catalog)" while the catalog is still in flight), the bare id stands until the answer lands, and the catalog name appears after release. Killed. The hold-then-release shape is precisely right.
  3. EfAppSettingsStore.GetManyAsync (new code, my own probe) — key filter neutered (s.Key.Length > 0 || …): the read-back returns d=four unasked and A_record_is_written_whole_adding_changing_and_removing_rows fails. Killed. One query, only the keys asked for, AsNoTracking like the sibling reads, ordinal comparer like SetManyAsync — and ManyReads == 1 pins the one-query promise from the use-case side. Lovely symmetry with SetManyAsync~

✅ What I liked~

  • Keeping the judge arm as a safeguard with a comment saying why ("No path in the app stores an alias judge…") — a defensive branch that documents its own reason for existing is my favourite kind ♪
  • GetManyAsync beside SetManyAsync — the store's read/write pair is symmetric again, and the Profile's every-open read is now one round trip, with both fakes mirroring the real semantics.
  • The Error parameter is gone and nothing mourns it — the build confirms no caller misses it.
  • The dual catalog-error display: your reasoning is sound — Kagaku's Combobox renders LoadError only inside the opened menu, the section's alert with its Try again is the one standing notice, and The_menu_says_the_catalog_is_loading_or_why_it_failed pins the menu line. Accepted~

No new findings. I read the full delta and every touched file: the map from six GetAsyncs to GetValueOrDefault is behaviour-identical, the judge fallback (?? builtIn.JudgeModel) survived the rewrite, and the new tests reuse the established render-the-section-first pattern rather than inventing one. Both of my blockers are resolved and provably guarded. This merges beautifully now~ ♡


Automated review by Jibril · 2026-10-18
CI: green for head SHA f8d091e · Mutation probes: 3 run, 0 survived / 3 killed (judge-arm ternary, Profile loading guard, GetManyAsync key filter) · Local suite: skipped (CI green)

## 🔮 fufu~ Jibril reviewed your code! You said the hounds would be fed — and oh, they came back *growling* this time~ I re-ran every mutant that survived my last visit, and threw in one of my own on the new `GetManyAsync` for good measure. Three probes, three kills. Do you have any idea how happy that makes me? ♡ ### Verdict: ✅ Looks good to me~ #### 🔪 The probes, re-run at f8d091e (every mutant restored afterwards) 1. **`ModelPicker.razor:146`** — judge ternary cut to plain `"takes no tools"`: `A_stored_judge_the_picker_does_not_offer_says_why` fails on the alias row at once (`(a moving alias)` ≠ `(takes no tools)`). **Killed.** And the second row covers the judge-side "(not in the catalog)" arm, which until now only the Model picker reached — exactly what I asked for. 2. **`ProfilePage.razor.cs:82`** — the `!defaults.CatalogLoaded ? "" :` guard removed: `Until_the_catalog_answers_an_inherited_default_is_named_by_its_id_without_a_flag` catches the falsehood mid-hold ("… (not in the catalog)" while the catalog is still in flight), the bare id stands until the answer lands, and the catalog name appears after release. **Killed.** The hold-then-release shape is precisely right. 3. **`EfAppSettingsStore.GetManyAsync`** *(new code, my own probe)* — key filter neutered (`s.Key.Length > 0 || …`): the read-back returns `d=four` unasked and `A_record_is_written_whole_adding_changing_and_removing_rows` fails. **Killed.** One query, only the keys asked for, `AsNoTracking` like the sibling reads, ordinal comparer like `SetManyAsync` — and `ManyReads == 1` pins the one-query promise from the use-case side. Lovely symmetry with `SetManyAsync`~ #### ✅ What I liked~ - Keeping the judge arm as a safeguard **with a comment saying why** ("No path in the app stores an alias judge…") — a defensive branch that documents its own reason for existing is my favourite kind ♪ - `GetManyAsync` beside `SetManyAsync` — the store's read/write pair is symmetric again, and the Profile's every-open read is now one round trip, with both fakes mirroring the real semantics. - The `Error` parameter is gone and nothing mourns it — the build confirms no caller misses it. - The dual catalog-error display: your reasoning is sound — Kagaku's `Combobox` renders `LoadError` only inside the opened menu, the section's alert with its **Try again** is the one standing notice, and `The_menu_says_the_catalog_is_loading_or_why_it_failed` pins the menu line. Accepted~ No new findings. I read the full delta and every touched file: the map from six `GetAsync`s to `GetValueOrDefault` is behaviour-identical, the judge fallback (`?? builtIn.JudgeModel`) survived the rewrite, and the new tests reuse the established render-the-section-first pattern rather than inventing one. Both of my blockers are resolved *and provably guarded*. This merges beautifully now~ ♡ --- *Automated review by Jibril · 2026-10-18* *CI: green for head SHA f8d091e · Mutation probes: 3 run, 0 survived / 3 killed (judge-arm ternary, Profile loading guard, GetManyAsync key filter) · Local suite: skipped (CI green)*
bjoern merged commit efe5f27f21 into main 2026-10-18 15:42:51 +02:00
bjoern deleted branch feat/p1e-defaults 2026-10-18 15:42:51 +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!15
No description provided.