feat: house rules 5/5 — agents propose, users confirm #102

Merged
bjoern merged 3 commits from feat/house-rules-propose into main 2026-07-29 06:11:56 +02:00
Member

The last slice of ADR 0026. 4/5 (#101) let a user turn any answer into a rule; this lets the agent that asked suggest the wording — a convenience over that path, never a replacement for it.

It writes nothing

An addition is a new constraint. An edit silently changes every future page, proposed by an agent that has seen one region. So propose_house_rule records a suggestion and the user decides:

  • an addition shows the proposed rule and asks;
  • an edit is shown against the rule it would overwrite (struck through above the replacement), not as a finished sentence.

The origin is composed by the harness, from what was actually asked and answered. The tool takes no origin parameter at all — an agent that could write its own provenance could flatter it.

A dismissal is not recorded as a ruling. "Use your judgement" settles nothing, so it leaves nothing to propose from, and the tool refuses.

The grant splits where the ADR says

Five content-writing stages get it: Bbox creation, Bbox refinement, Sfx boxing, Bible building, Translation. The QA agents do not — a house rule reaches a bible row, and a reviewer holds no tool that writes content (ADR 0016). Their answers still become rules through 4/5's panel, which is exactly why withholding this costs them nothing.

Transcription and Research & Setup can't ask, so they can't propose either.

Tests

920 green (+20 over main at 4c1b30b, measured on the base).

The tool's guards, each for a reason:

  • one proposal per run;
  • nothing before a ruling — a rule with no ruling behind it has no origin, which is the point of proposing rather than the user just writing one;
  • a blank rule refused;
  • an unparseable replaces_rule_id refused rather than ignored — silently dropping it would turn an intended edit into a second rule saying the opposite of the first;
  • a dismissed ruling records nothing.

The grant table gains propose_house_rule per stage, under the same completeness check. The panel pins that nothing is written until confirmed, that declining writes nothing and clears the suggestion, and that an edit shows what it overwrites and leaves provenance alone.

Honest notes

  • No browser verification this time, and that's a gap rather than a justified skip. The panel path is covered by bUnit, but 4/5 taught me that bUnit misses things a real DOM catches. The seeded world can't produce a proposal (no executor), so showing it live would mean seeding one the way 4/5 seeds a parked question — worth doing, and I'd rather flag it than let the bUnit coverage imply more than it does.
  • SeedDevData does not seed a proposal, for the same reason. The confirm UI is therefore unreachable in the sample world, which by AGENTS.md's own rule is a feature browser verification will silently skip.
  • An accepted edit uses UpdateHouseRule, so it rewrites the policy and keeps the original origin — the provenance of the rule, not of the edit. That's consistent with 1/5's "provenance that can be rewritten records nothing", but it does mean an edited rule's origin no longer describes its current text. Flagging it as a real trade rather than an oversight.
  • A proposal dies with the run, like a pending question — same desk, same reasoning, no persistence.

The one thing ADR 0026 still doesn't have

The panel links to the page rather than rendering the crop or page view inline, so "carries the view its asker can render" remains satisfied by a hyperlink. Deferred through 3/5 and 4/5 and still open after this. It wants the SkiaSharp renderer wired into the panel and is its own slice.

🤖 Generated with Claude Code

The last slice of ADR 0026. 4/5 (#101) let a user turn any answer into a rule; this lets **the agent that asked suggest the wording** — a convenience over that path, never a replacement for it. ## It writes nothing An addition is a new constraint. An **edit silently changes every future page**, proposed by an agent that has seen one region. So `propose_house_rule` records a suggestion and the user decides: - an addition shows the proposed rule and asks; - an **edit is shown against the rule it would overwrite** (struck through above the replacement), not as a finished sentence. **The origin is composed by the harness**, from what was actually asked and answered. The tool takes no origin parameter at all — an agent that could write its own provenance could flatter it. **A dismissal is not recorded as a ruling.** "Use your judgement" settles nothing, so it leaves nothing to propose from, and the tool refuses. ## The grant splits where the ADR says Five content-writing stages get it: Bbox creation, Bbox refinement, Sfx boxing, Bible building, Translation. **The QA agents do not** — a house rule reaches a bible row, and a reviewer holds no tool that writes content (ADR 0016). Their answers still become rules through 4/5's panel, which is exactly why withholding this costs them nothing. Transcription and Research & Setup can't ask, so they can't propose either. ## Tests **920 green (+20 over main at `4c1b30b`, measured on the base).** The tool's guards, each for a reason: - one proposal per run; - nothing before a ruling — a rule with no ruling behind it has no origin, which is the point of proposing rather than the user just writing one; - a blank rule refused; - **an unparseable `replaces_rule_id` refused rather than ignored** — silently dropping it would turn an intended edit into a second rule saying the opposite of the first; - a dismissed ruling records nothing. The grant table gains `propose_house_rule` per stage, under the same completeness check. The panel pins that **nothing is written until confirmed**, that declining writes nothing and clears the suggestion, and that an edit shows what it overwrites and **leaves provenance alone**. ## Honest notes - **No browser verification this time**, and that's a gap rather than a justified skip. The panel path is covered by bUnit, but 4/5 taught me that bUnit misses things a real DOM catches. The seeded world can't produce a proposal (no executor), so showing it live would mean seeding one the way 4/5 seeds a parked question — worth doing, and I'd rather flag it than let the bUnit coverage imply more than it does. - **`SeedDevData` does not seed a proposal**, for the same reason. The confirm UI is therefore unreachable in the sample world, which by AGENTS.md's own rule is a feature browser verification will silently skip. - **An accepted edit uses `UpdateHouseRule`**, so it rewrites the policy and keeps the original `origin` — the provenance of the *rule*, not of the edit. That's consistent with 1/5's "provenance that can be rewritten records nothing", but it does mean an edited rule's origin no longer describes its current text. Flagging it as a real trade rather than an oversight. - **A proposal dies with the run**, like a pending question — same desk, same reasoning, no persistence. ## The one thing ADR 0026 still doesn't have The panel **links** to the page rather than rendering the crop or page view inline, so "carries the view its asker can render" remains satisfied by a hyperlink. Deferred through 3/5 and 4/5 and still open after this. It wants the SkiaSharp renderer wired into the panel and is its own slice. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: agents propose house rules, users confirm them (ADR 0026, 5/5)
All checks were successful
CI / build (pull_request) Successful in 25s
CI / test (pull_request) Successful in 49s
bd759c8a5f
The last slice. 4/5 let a user turn any answer into a rule; this lets the
agent that asked suggest the wording, which is a convenience over that path
rather than a replacement for it.

It writes nothing. An addition is a new constraint and an edit silently
changes every future page, both proposed by an agent that has seen one
region — so the user confirms, and an edit is shown against the rule it
would overwrite rather than as a finished sentence.

The origin is composed by the harness from what was actually asked and
answered. An agent that could write its own provenance could flatter it,
so the tool takes no origin parameter at all. A dismissal settles nothing
and is therefore not recorded as a ruling, which leaves nothing to propose
from.

The grant splits where ADR 0026 says it does: the five content-writing
stages get it, and the QA agents do not, because a house rule reaches a
bible row and a reviewer holds no tool that writes content. Their answers
still become rules through the panel, which is why withholding this costs
them nothing.

Tests: 920 green (+20 over main at 4c1b30b). The tool's guards are pinned —
one proposal per run, nothing before a ruling, a blank rule refused, and an
unparseable rule id refused rather than ignored, since silently dropping it
would turn an intended edit into a second rule saying the opposite. The
grant table gains propose_house_rule per stage. The panel pins that nothing
is written until confirmed, that declining writes nothing, and that an edit
shows what it overwrites and leaves provenance alone.

Co-Authored-By: Claude Opus 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: 1e8bdc8 · Generated: 2026-07-28 21:14:38 UTC · Revision: #3

Summary

Summary
Generated on: 07/28/2026 - 21:14:38
Coverage date: 07/28/2026 - 21:14:22 - 07/28/2026 - 21:14:35
Parser: MultiReport (4x Cobertura)
Assemblies: 6
Classes: 475
Files: 220
Line coverage: 96.6% (15695 of 16246)
Covered lines: 15695
Uncovered lines: 551
Coverable lines: 16246
Total lines: 28662
Branch coverage: 83.8% (2888 of 3445)
Covered branches: 2888
Total branches: 3445
Method coverage: Feature is only available for sponsors

Coverage

Orihon.BlazorAdapter - 95.6%
Name Line Branch
Orihon.BlazorAdapter 95.6% 88.4%
Orihon.BlazorAdapter.Bible.AddBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.AddCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.AddHouseRuleRowRequested 100%
Orihon.BlazorAdapter.Bible.AddLoreRowRequested 100%
Orihon.BlazorAdapter.Bible.BibleEffects 89.8% 76.9%
Orihon.BlazorAdapter.Bible.BibleLoaded 100%
Orihon.BlazorAdapter.Bible.BiblePage 92.3% 80%
Orihon.BlazorAdapter.Bible.BibleReducers 90.6%
Orihon.BlazorAdapter.Bible.BibleState 100%
Orihon.BlazorAdapter.Bible.BibleWriteFailed 100%
Orihon.BlazorAdapter.Bible.DeleteBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteHouseRuleRowRequested 0%
Orihon.BlazorAdapter.Bible.DeleteLoreRowRequested 0%
Orihon.BlazorAdapter.Bible.LoadBible 100%
Orihon.BlazorAdapter.Bible.ReorderBeatsRequested 0%
Orihon.BlazorAdapter.Bible.SaveOverviewRequested 100%
Orihon.BlazorAdapter.Bible.SaveSummaryRequested 100%
Orihon.BlazorAdapter.Bible.UpdateBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateHouseRuleRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateLoreRowRequested 100%
Orihon.BlazorAdapter.BlazorAdapterAssembly 100%
Orihon.BlazorAdapter.Debounce 96.2% 94.4%
Orihon.BlazorAdapter.Diagnostics.CircuitError 100%
Orihon.BlazorAdapter.Diagnostics.CircuitErrorPanel 100%
Orihon.BlazorAdapter.Diagnostics.CircuitErrorSink 100% 85.7%
Orihon.BlazorAdapter.Diagnostics.OrihonStoreInitializer 85.7% 66.6%
Orihon.BlazorAdapter.PageWorkspace.CreateRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.DeletePageSummaryRequested 100%
Orihon.BlazorAdapter.PageWorkspace.DeleteRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.LoadPageWorkspace 100%
Orihon.BlazorAdapter.PageWorkspace.PageSummarySaved 100%
Orihon.BlazorAdapter.PageWorkspace.PageViewport 100% 100%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceEffects 100% 100%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceLoaded 100%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspacePage 92.2% 85.5%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceReducers 100% 66.6%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceState 100%
Orihon.BlazorAdapter.PageWorkspace.PageWriteFailed 100%
Orihon.BlazorAdapter.PageWorkspace.RegionCreated 100%
Orihon.BlazorAdapter.PageWorkspace.RegionSaved 100%
Orihon.BlazorAdapter.PageWorkspace.ReorderRegionsRequested 100%
Orihon.BlazorAdapter.PageWorkspace.ReprocessPageRequested 100%
Orihon.BlazorAdapter.PageWorkspace.ReprocessTranslationRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SavePageSummaryRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SaveRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SetPageMetaRequested 100%
Orihon.BlazorAdapter.Projects.CreateProjectRequested 100%
Orihon.BlazorAdapter.Projects.DecideSetupContinuation 100%
Orihon.BlazorAdapter.Projects.DeleteProjectRequested 100%
Orihon.BlazorAdapter.Projects.FinishSetupRequested 100%
Orihon.BlazorAdapter.Projects.ImportPagesRequested 100%
Orihon.BlazorAdapter.Projects.LoadWizard 100%
Orihon.BlazorAdapter.Projects.PageOrganizer 96% 95%
Orihon.BlazorAdapter.Projects.PagesImported 100%
Orihon.BlazorAdapter.Projects.ProjectDeleteFailed 100%
Orihon.BlazorAdapter.Projects.ProjectListEffects 100% 100%
Orihon.BlazorAdapter.Projects.ProjectListPage 89.7% 91.1%
Orihon.BlazorAdapter.Projects.ProjectListReducers 100%
Orihon.BlazorAdapter.Projects.ProjectListState 100%
Orihon.BlazorAdapter.Projects.ProjectsLoaded 100%
Orihon.BlazorAdapter.Projects.ProjectWizardEffects 93.8% 90%
Orihon.BlazorAdapter.Projects.ProjectWizardPage 95.3% 84.1%
Orihon.BlazorAdapter.Projects.ProjectWizardReducers 100%
Orihon.BlazorAdapter.Projects.ProjectWizardState 100%
Orihon.BlazorAdapter.Projects.SetupChat 93.5% 100%
Orihon.BlazorAdapter.Projects.SetupChatEffects 100% 100%
Orihon.BlazorAdapter.Projects.SetupChatFailed 100%
Orihon.BlazorAdapter.Projects.SetupChatReducers 100%
Orihon.BlazorAdapter.Projects.SetupChatState 100%
Orihon.BlazorAdapter.Projects.SetupChatUpdated 100%
Orihon.BlazorAdapter.Projects.StartSetupChat 100%
Orihon.BlazorAdapter.Projects.SubmitSetupAnswer 100%
Orihon.BlazorAdapter.Projects.WizardDeletePagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardLoaded 100%
Orihon.BlazorAdapter.Projects.WizardMovePagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardMovePagesToNewChapterRequested 100%
Orihon.BlazorAdapter.Projects.WizardReorderPagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardWriteFailed 100%
Orihon.BlazorAdapter.Rulings.AcceptProposalRequested 100%
Orihon.BlazorAdapter.Rulings.AnsweredRuling 100%
Orihon.BlazorAdapter.Rulings.AnswerRulingRequested 100%
Orihon.BlazorAdapter.Rulings.DeclineProposalRequested 100%
Orihon.BlazorAdapter.Rulings.DismissRulingRequested 100%
Orihon.BlazorAdapter.Rulings.RulingBar 98.1% 94.4%
Orihon.BlazorAdapter.Rulings.RulingDeskBridge 94.2% 91.6%
Orihon.BlazorAdapter.Rulings.RulingsEffects 95.4% 83.3%
Orihon.BlazorAdapter.Rulings.RulingsLoaded 100%
Orihon.BlazorAdapter.Rulings.RulingsReducers 100%
Orihon.BlazorAdapter.Rulings.RulingsState 100%
Orihon.BlazorAdapter.Rulings.RulingWriteFailed 100%
Orihon.BlazorAdapter.Rulings.SaveAnswerAsHouseRuleRequested 100%
Orihon.BlazorAdapter.Runs.CancelMonitorRun 100%
Orihon.BlazorAdapter.Runs.MonitorPageRef 100%
Orihon.BlazorAdapter.Runs.MonitorRunLoaded 100%
Orihon.BlazorAdapter.Runs.RetryMonitorExecution 100%
Orihon.BlazorAdapter.Runs.RunChangedBridge 95% 92.8%
Orihon.BlazorAdapter.Runs.RunMonitor 97.9% 96.2%
Orihon.BlazorAdapter.Runs.RunMonitorEffects 100% 91.6%
Orihon.BlazorAdapter.Runs.RunMonitorReducers 100%
Orihon.BlazorAdapter.Runs.RunMonitorState 100%
Orihon.BlazorAdapter.Settings.AgentDebriefsLoaded 100%
Orihon.BlazorAdapter.Settings.AgentDebriefsLoadFailed 100%
Orihon.BlazorAdapter.Settings.AgentEffortPicked 100%
Orihon.BlazorAdapter.Settings.AgentEffortSaved 100%
Orihon.BlazorAdapter.Settings.AgentEffortSaveFailed 100%
Orihon.BlazorAdapter.Settings.AgentFeedbackLoaded 100%
Orihon.BlazorAdapter.Settings.AgentFeedbackLoadFailed 0%
Orihon.BlazorAdapter.Settings.AgentModelPicked 100%
Orihon.BlazorAdapter.Settings.AgentModelSaved 100%
Orihon.BlazorAdapter.Settings.AgentModelSaveFailed 100%
Orihon.BlazorAdapter.Settings.EffortOption 100% 100%
Orihon.BlazorAdapter.Settings.KeySaved 100%
Orihon.BlazorAdapter.Settings.KeySaveFailed 100%
Orihon.BlazorAdapter.Settings.ModelOptionsLoaded 100%
Orihon.BlazorAdapter.Settings.ModelOptionsUnavailable 100%
Orihon.BlazorAdapter.Settings.SaveKeyRequested 100%
Orihon.BlazorAdapter.Settings.SettingsEffects 94.2% 75%
Orihon.BlazorAdapter.Settings.SettingsLoaded 100%
Orihon.BlazorAdapter.Settings.SettingsPage 97.9% 90.4%
Orihon.BlazorAdapter.Settings.SettingsReducers 94.1%
Orihon.BlazorAdapter.Settings.SettingsState 100%
Orihon.BlazorAdapter.Settings.SfxPassToggled 100%
Orihon.BlazorAdapter.Uploads.UploadTransfer 96.5% 100%
Orihon.BlazorAdapter.Uploads.UploadTransferProgress 100% 100%
Orihon.BlazorAdapter.Uploads.UploadTransferResult 100%
Orihon.BlazorAdapter.Workspace.CreateChapterRequested 100%
Orihon.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Orihon.BlazorAdapter.Workspace.DeletePageRequested 100%
Orihon.BlazorAdapter.Workspace.DeleteSummaryRequested 100%
Orihon.BlazorAdapter.Workspace.LoadProjectWorkspace 100%
Orihon.BlazorAdapter.Workspace.MovePageRequested 100%
Orihon.BlazorAdapter.Workspace.ProjectMetadataCard 95.6% 92.8%
Orihon.BlazorAdapter.Workspace.ProjectMetadataSaved 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceEffects 100% 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceLoaded 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspacePage 95.5% 88.3%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceReducers 100% 62.5%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceState 100%
Orihon.BlazorAdapter.Workspace.RenameChapterRequested 100%
Orihon.BlazorAdapter.Workspace.ReorderChaptersRequested 100%
Orihon.BlazorAdapter.Workspace.ReorderPagesRequested 100%
Orihon.BlazorAdapter.Workspace.RunAnnotationRequested 100%
Orihon.BlazorAdapter.Workspace.RunBibleRequested 100%
Orihon.BlazorAdapter.Workspace.RunTranslationRequested 100%
Orihon.BlazorAdapter.Workspace.SaveProjectMetadataRequested 100%
Orihon.BlazorAdapter.Workspace.SaveSummaryRequested 100%
Orihon.BlazorAdapter.Workspace.SetPageKindRequested 100%
Orihon.BlazorAdapter.Workspace.SummaryDeleted 100%
Orihon.BlazorAdapter.Workspace.SummarySaved 100%
Orihon.BlazorAdapter.Workspace.WorkspaceImportRequested 100%
Orihon.BlazorAdapter.Workspace.WorkspaceWriteFailed 100%
Orihon.Domain - 100%
Name Line Branch
Orihon.Domain 100% 100%
Orihon.Domain.Agents.AgentDebrief 100% 100%
Orihon.Domain.Agents.AgentDescriptor 100%
Orihon.Domain.Agents.AgentFeedback 100% 100%
Orihon.Domain.Agents.AgentRoster 100% 100%
Orihon.Domain.Bible.Character 100% 100%
Orihon.Domain.Bible.GlossaryEntry 100% 100%
Orihon.Domain.Bible.HouseRule 100%
Orihon.Domain.Bible.LoreEntry 100% 100%
Orihon.Domain.Bible.PageSummary 100%
Orihon.Domain.Bible.StoryBeat 100%
Orihon.Domain.Bible.StoryOverview 100%
Orihon.Domain.Projects.Project 100% 100%
Orihon.Domain.Projects.ProjectProfile 100%
Orihon.Domain.Runs.Execution 100% 100%
Orihon.Domain.Runs.RegionProblem 100%
Orihon.Domain.Runs.Run 100%
Orihon.Domain.Settings.AppSetting 100%
Orihon.Domain.Text 100% 100%
Orihon.Domain.Translation.BoundingBox 100%
Orihon.Domain.Translation.Chapter 100%
Orihon.Domain.Translation.Page 100%
Orihon.Domain.Translation.Region 100% 100%
Orihon.Domain.Translation.RegionProfile 100%
Orihon.Infrastructure - 96.4%
Name Line Branch
Orihon.Infrastructure 96.4% 71.2%
Orihon.Infrastructure.Agents.EfAgentDebriefStore 100%
Orihon.Infrastructure.Agents.EfAgentFeedbackStore 100%
Orihon.Infrastructure.Bible.EfBibleStore 95.2% 92.8%
Orihon.Infrastructure.DependencyInjection 100% 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter`1 100% 100%
Orihon.Infrastructure.Gateways.AgentTranscript 94.7% 85.4%
Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore 86.1% 78.5%
Orihon.Infrastructure.Gateways.HttpWebPageFetcher 95.1% 83.3%
Orihon.Infrastructure.Gateways.OpenRouterLlmGateway 90.3% 82.2%
Orihon.Infrastructure.Gateways.SkiaPageImageRenderer 97.5% 87.2%
Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.AgentFeedbackConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ChapterConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.CharacterConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ExecutionConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.GlossaryEntryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.HouseRuleConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.JsonColumnMapper 100%
Orihon.Infrastructure.Persistence.Configurations.LoreEntryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.PageConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.PageSummaryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ProjectConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.RegionConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.RunConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.StoryBeatConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.StoryOverviewConfiguration 100%
Orihon.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Orihon.Infrastructure.Persistence.Migrations.AddAgentDebriefs 99.5%
Orihon.Infrastructure.Persistence.Migrations.AddAgentFeedback 99.5%
Orihon.Infrastructure.Persistence.Migrations.AddAppSettings 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddExecutionFeedbackRegions 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddHouseRules 99.6%
Orihon.Infrastructure.Persistence.Migrations.AddProjectSourceLanguage 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddRuns 99.1%
Orihon.Infrastructure.Persistence.Migrations.AddStoryOverview 99.5%
Orihon.Infrastructure.Persistence.Migrations.InitialTranslationDomain 97.3%
Orihon.Infrastructure.Persistence.Migrations.OrihonDbContextModelSnapshot 100%
Orihon.Infrastructure.Persistence.Migrations.RenameSourceTargetColumns 97.2%
Orihon.Infrastructure.Persistence.OrihonDbContext 100%
Orihon.Infrastructure.Persistence.OrihonDbContextFactory 100%
Orihon.Infrastructure.Projects.EfProjectStore 100% 100%
Orihon.Infrastructure.Projects.FileSystemPageImageStore 100% 100%
Orihon.Infrastructure.Runs.EfRunStore 98.1% 75%
Orihon.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Orihon.Infrastructure.Translation.EfChapterStore 100% 100%
Orihon.Infrastructure.Translation.EfPageStore 86% 80%
Orihon.Infrastructure.Translation.EfRegionStore 100% 100%
Orihon.Infrastructure.Translation.Ordering 100% 100%
System.Text.RegularExpressions.Generated 70.6% 53.3%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlankLines_4
77.9% 76.6%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlockBreaks_1
59% 42.5%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__SpaceRuns_3
89.4% 75%
System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__Tags_2
83.7% 62.5%
Orihon.Kernel - 90.9%
Name Line Branch
Orihon.Kernel 90.9% 75%
Orihon.Kernel.Err`1 100%
Orihon.Kernel.Ok`1 100%
Orihon.Kernel.Result`1 88.8% 75%
Orihon.Server - 93.3%
Name Line Branch
Orihon.Server 93.3% 70%
Orihon.Server.Components.App 100%
Orihon.Server.Components.Layout.MainLayout 100%
Orihon.Server.Components.Pages.Gate 64.2% 66.6%
Orihon.Server.RunEngineBootstrap 100%
Orihon.Server.Security.AccessGate 91.8% 41.6%
Orihon.Server.Security.AccessSecret 100% 50%
Orihon.Server.VolumeStartupValidator 100% 100%
Program 94.8% 87.5%
Orihon.UseCases - 97.1%
Name Line Branch
Orihon.UseCases 97.1% 88.3%
Orihon.UseCases.Agents.AgentAttemptPreparation 100%
Orihon.UseCases.Agents.AgentAttemptSupport 99.1% 98.1%
Orihon.UseCases.Agents.AgentBlueprint 100%
Orihon.UseCases.Agents.AgentCapDebrief 100%
Orihon.UseCases.Agents.AgentInvocation 100%
Orihon.UseCases.Agents.AgentOutcome 100%
Orihon.UseCases.Agents.AgentTool`1 90.9% 75%
Orihon.UseCases.Agents.AgentToolImage 100%
Orihon.UseCases.Agents.AgentToolResult 100%
Orihon.UseCases.Agents.Annotation.AddRegionParams 100%
Orihon.UseCases.Agents.Annotation.AddRegionTool 95.4% 75%
Orihon.UseCases.Agents.Annotation.AddSfxRegionTool 95.2% 75%
Orihon.UseCases.Agents.Annotation.AnnotationBlueprints 100%
Orihon.UseCases.Agents.Annotation.AnnotationStage 100% 85%
Orihon.UseCases.Agents.Annotation.BboxCreationExecutor 94.1% 50%
Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor 93.7% 81.2%
Orihon.UseCases.Agents.Annotation.BoundBoxParams 100%
Orihon.UseCases.Agents.Annotation.BoundContactSheetTool 91.3% 75%
Orihon.UseCases.Agents.Annotation.BoundCropParams 100%
Orihon.UseCases.Agents.Annotation.BoundCropTool 100%
Orihon.UseCases.Agents.Annotation.BoundViewPageTool 92.8% 80%
Orihon.UseCases.Agents.Annotation.BoundViewParams 100%
Orihon.UseCases.Agents.Annotation.DeleteBoundRegionTool 100% 100%
Orihon.UseCases.Agents.Annotation.DeleteRegionParams 100%
Orihon.UseCases.Agents.Annotation.DeleteRegionTool 100% 100%
Orihon.UseCases.Agents.Annotation.FindGlossaryParams 100%
Orihon.UseCases.Agents.Annotation.FindGlossaryTool 88.2% 62.5%
Orihon.UseCases.Agents.Annotation.ListRegionsTool 91.6% 80%
Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool 90.9% 50%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams 100%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool 95% 83.3%
Orihon.UseCases.Agents.Annotation.NoteRegionParams 100%
Orihon.UseCases.Agents.Annotation.NoteRegionTool 100% 100%
Orihon.UseCases.Agents.Annotation.PageQaExecutor 94.4% 81.8%
Orihon.UseCases.Agents.Annotation.QaReportSink 100% 100%
Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess 87.2% 53.8%
Orihon.UseCases.Agents.Annotation.RegionBriefing 100% 100%
Orihon.UseCases.Agents.Annotation.RegionCropParams 100%
Orihon.UseCases.Agents.Annotation.RegionCropTool 100%
Orihon.UseCases.Agents.Annotation.RegionProblemParams 100%
Orihon.UseCases.Agents.Annotation.RejectRegionParams 100%
Orihon.UseCases.Agents.Annotation.RejectRegionTool 100% 50%
Orihon.UseCases.Agents.Annotation.ReorderRegionParams 100%
Orihon.UseCases.Agents.Annotation.ReorderRegionTool 88% 60%
Orihon.UseCases.Agents.Annotation.ReportQaParams 100%
Orihon.UseCases.Agents.Annotation.ReportQaTool 97.7% 90%
Orihon.UseCases.Agents.Annotation.SetPageMetaParams 100%
Orihon.UseCases.Agents.Annotation.SetPageMetaTool 100% 75%
Orihon.UseCases.Agents.Annotation.SetRegionTypeParams 100%
Orihon.UseCases.Agents.Annotation.SetRegionTypeTool 100% 87.5%
Orihon.UseCases.Agents.Annotation.SetTranscriptionParams 100%
Orihon.UseCases.Agents.Annotation.SetTranscriptionTool 100% 100%
Orihon.UseCases.Agents.Annotation.SfxCreationExecutor 88.8% 50%
Orihon.UseCases.Agents.Annotation.SfxQaExecutor 93.9% 83.3%
Orihon.UseCases.Agents.Annotation.SfxTranscriptionExecutor 93.1% 80%
Orihon.UseCases.Agents.Annotation.TranscriptionExecutor 93.1% 80%
Orihon.UseCases.Agents.AssistantSpoke 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor 96.7% 75%
Orihon.UseCases.Agents.BibleBuilding.GetRegionParams 100%
Orihon.UseCases.Agents.BibleBuilding.GetRegionTool 84.6% 72.2%
Orihon.UseCases.Agents.BibleBuilding.ListProjectRegionsTool 86.3% 90%
Orihon.UseCases.Agents.BibleBuilding.ListRegionsParams 100%
Orihon.UseCases.Agents.Inspection.PageImageAccess 94.5% 77.7%
Orihon.UseCases.Agents.Inspection.ViewAccount 100% 85.7%
Orihon.UseCases.Agents.ReportFrictionParams 100%
Orihon.UseCases.Agents.ReportFrictionTool 100% 92.8%
Orihon.UseCases.Agents.ResearchSetup.AddGlossaryParams 100%
Orihon.UseCases.Agents.ResearchSetup.AddGlossaryTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatParams 100%
Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatTool 100% 50%
Orihon.UseCases.Agents.ResearchSetup.AskUserParams 100%
Orihon.UseCases.Agents.ResearchSetup.AskUserTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.FetchUrlParams 100%
Orihon.UseCases.Agents.ResearchSetup.FetchUrlTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.ListBibleTool 89.4% 100%
Orihon.UseCases.Agents.ResearchSetup.ListPagesTool 97% 83.3%
Orihon.UseCases.Agents.ResearchSetup.LocatedPage 100%
Orihon.UseCases.Agents.ResearchSetup.PageByNumber 95% 91.6%
Orihon.UseCases.Agents.ResearchSetup.ResearchSetupBlueprint 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageMetaParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageMetaTool 95.2% 90%
Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryTool 100% 75%
Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataTool 96.5% 95.8%
Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterParams 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterTool 92.3% 71.4%
Orihon.UseCases.Agents.ResearchSetup.UpsertLoreParams 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertLoreTool 92.3% 71.4%
Orihon.UseCases.Agents.ResearchSetup.ViewPageParams 100%
Orihon.UseCases.Agents.ResearchSetup.ViewPageTool 100% 100%
Orihon.UseCases.Agents.RoundStarted 100%
Orihon.UseCases.Agents.Rulings.AnswerRuling 100%
Orihon.UseCases.Agents.Rulings.DismissRuling 100%
Orihon.UseCases.Agents.Rulings.HouseRuleProposal 100%
Orihon.UseCases.Agents.Rulings.ListPendingRulings 100%
Orihon.UseCases.Agents.Rulings.ListRuleProposals 100%
Orihon.UseCases.Agents.Rulings.PendingRuling 100%
Orihon.UseCases.Agents.Rulings.ProposeHouseRuleParams 100%
Orihon.UseCases.Agents.Rulings.ProposeHouseRuleTool 77.7% 100%
Orihon.UseCases.Agents.Rulings.RequestRulingParams 100%
Orihon.UseCases.Agents.Rulings.RequestRulingTool 100% 81.2%
Orihon.UseCases.Agents.Rulings.RulingAnswer 100%
Orihon.UseCases.Agents.Rulings.RulingDesk 97.8% 80%
Orihon.UseCases.Agents.Rulings.RulingOption 100%
Orihon.UseCases.Agents.Rulings.RulingOptionParams 100%
Orihon.UseCases.Agents.Rulings.WithdrawRuleProposal 100%
Orihon.UseCases.Agents.Setup.ResearchSetupExecutor 98.5% 92.8%
Orihon.UseCases.Agents.Setup.SetupChatEntry 100%
Orihon.UseCases.Agents.Setup.SetupConversation 100% 87.5%
Orihon.UseCases.Agents.Setup.SetupConversationRegistry 100%
Orihon.UseCases.Agents.ToolCalled 100%
Orihon.UseCases.Agents.ToolCompleted 100%
Orihon.UseCases.Agents.Translation.GetPageSummaryParams 100%
Orihon.UseCases.Agents.Translation.GetPageSummaryTool 80% 66.6%
Orihon.UseCases.Agents.Translation.SetTranslationParams 100%
Orihon.UseCases.Agents.Translation.SetTranslationTool 88.5% 78.5%
Orihon.UseCases.Agents.Translation.TranslationBlueprint 100%
Orihon.UseCases.Agents.Translation.TranslationExecutor 93.6% 71.4%
Orihon.UseCases.Agents.Translation.UpdateGlossaryEnParams 100%
Orihon.UseCases.Agents.Translation.UpdateGlossaryEnTool 82.6% 62.5%
Orihon.UseCases.Bible.AddCharacter 100% 100%
Orihon.UseCases.Bible.AddGlossaryEntry 100% 100%
Orihon.UseCases.Bible.AddHouseRule 100% 100%
Orihon.UseCases.Bible.AddLoreEntry 100% 100%
Orihon.UseCases.Bible.AddStoryBeat 100% 100%
Orihon.UseCases.Bible.BibleDto 100%
Orihon.UseCases.Bible.CharacterDto 100%
Orihon.UseCases.Bible.DeleteCharacter 100% 100%
Orihon.UseCases.Bible.DeleteGlossaryEntry 100% 100%
Orihon.UseCases.Bible.DeleteHouseRule 100% 100%
Orihon.UseCases.Bible.DeleteLoreEntry 100% 100%
Orihon.UseCases.Bible.DeletePageSummary 100% 100%
Orihon.UseCases.Bible.DeleteStoryBeat 100% 100%
Orihon.UseCases.Bible.GetBible 100% 100%
Orihon.UseCases.Bible.GlossaryEntryDto 100%
Orihon.UseCases.Bible.HouseRuleDto 100%
Orihon.UseCases.Bible.LoreEntryDto 100%
Orihon.UseCases.Bible.PageSummaryDto 100%
Orihon.UseCases.Bible.ReorderStoryBeats 100%
Orihon.UseCases.Bible.SetPageSummary 100% 100%
Orihon.UseCases.Bible.SetStoryOverview 100% 100%
Orihon.UseCases.Bible.StoryBeatDto 100%
Orihon.UseCases.Bible.StoryOverviewDto 100%
Orihon.UseCases.Bible.UpdateCharacter 100% 100%
Orihon.UseCases.Bible.UpdateGlossaryEntry 100% 100%
Orihon.UseCases.Bible.UpdateHouseRule 100% 100%
Orihon.UseCases.Bible.UpdateLoreEntry 100% 100%
Orihon.UseCases.Bible.UpdateStoryBeat 100% 100%
Orihon.UseCases.Chapters.ChapterDto 100%
Orihon.UseCases.Chapters.CreateChapter 100% 100%
Orihon.UseCases.Chapters.DeleteChapter 100% 100%
Orihon.UseCases.Chapters.RenameChapter 100% 100%
Orihon.UseCases.Chapters.ReorderChapters 100%
Orihon.UseCases.Debriefs.AgentDebriefDto 90.9%
Orihon.UseCases.Debriefs.AgentFeedbackDto 83.3%
Orihon.UseCases.Debriefs.ClearAgentDebriefs 100%
Orihon.UseCases.Debriefs.ClearAgentFeedback 100%
Orihon.UseCases.Debriefs.ListAgentDebriefs 100% 100%
Orihon.UseCases.Debriefs.ListAgentFeedback 100% 75%
Orihon.UseCases.DependencyInjection 100%
Orihon.UseCases.Diagnostics.SeedDevData 99.6% 93.7%
Orihon.UseCases.Gateways.LabeledBox 100%
Orihon.UseCases.Gateways.LlmKeyInfo 100%
Orihon.UseCases.Gateways.LlmModel 100%
Orihon.UseCases.Gateways.LlmReasoning 100% 100%
Orihon.UseCases.Gateways.PixelWindow 100%
Orihon.UseCases.Gateways.RenderedView 100%
Orihon.UseCases.NextOrder 100%
Orihon.UseCases.Pages.DeletePage 100% 100%
Orihon.UseCases.Pages.DeletePages 100% 100%
Orihon.UseCases.Pages.GetPage 100% 100%
Orihon.UseCases.Pages.GetProjectWorkspace 100% 100%
Orihon.UseCases.Pages.ImportPages 100% 100%
Orihon.UseCases.Pages.ImportPagesResult 100%
Orihon.UseCases.Pages.MarkPageAnnotated 100% 100%
Orihon.UseCases.Pages.MovePage 100% 92.8%
Orihon.UseCases.Pages.MovePages 100% 100%
Orihon.UseCases.Pages.PageDetailDto 100%
Orihon.UseCases.Pages.PageDto 100%
Orihon.UseCases.Pages.PageUpload 100%
Orihon.UseCases.Pages.ProjectWorkspaceDto 100%
Orihon.UseCases.Pages.ReorderPages 100%
Orihon.UseCases.Pages.SetPageMeta 100% 100%
Orihon.UseCases.Pages.WorkspaceChapterDto 100%
Orihon.UseCases.Projects.CompleteProjectSetup 100% 93.7%
Orihon.UseCases.Projects.CreateProject 100% 100%
Orihon.UseCases.Projects.DeleteProject 100% 100%
Orihon.UseCases.Projects.GetProject 100% 100%
Orihon.UseCases.Projects.ListProjects 100%
Orihon.UseCases.Projects.ProjectDto 96.1%
Orihon.UseCases.Projects.StartAnnotationRun 96.4% 92.8%
Orihon.UseCases.Projects.StartBibleRun 90.9% 83.3%
Orihon.UseCases.Projects.StartSetupRun 100% 100%
Orihon.UseCases.Projects.StartTranslationRun 90.9% 83.3%
Orihon.UseCases.Projects.StoredPageImage 100%
Orihon.UseCases.Projects.UpdateProjectMetadata 100% 100%
Orihon.UseCases.Regions.CreateRegion 100% 100%
Orihon.UseCases.Regions.DeleteRegion 100% 100%
Orihon.UseCases.Regions.RegionDto 97%
Orihon.UseCases.Regions.ReorderRegions 100%
Orihon.UseCases.Regions.UpdateRegion 100% 100%
Orihon.UseCases.Runs.AnnotationPipeline 100% 100%
Orihon.UseCases.Runs.ExecutionDto 93.3%
Orihon.UseCases.Runs.ExecutionProgress 100%
Orihon.UseCases.Runs.ExecutionProgressRegistry 100% 100%
Orihon.UseCases.Runs.ExecutionPulseRelay 100% 100%
Orihon.UseCases.Runs.PlannedExecution 100%
Orihon.UseCases.Runs.PulseTarget 100%
Orihon.UseCases.Runs.ReprocessPage 100% 94.4%
Orihon.UseCases.Runs.ReprocessTranslation 94.1% 92.8%
Orihon.UseCases.Runs.RunDto 93.3% 90%
Orihon.UseCases.Runs.RunEngine 94.8% 93.1%
Orihon.UseCases.Runs.RunEngineOptions 100% 100%
Orihon.UseCases.Runs.StageContext 100% 50%
Orihon.UseCases.Runs.StageHaltedException 100%
Orihon.UseCases.Runs.WorkStates 100% 83.3%
Orihon.UseCases.Settings.AgentSettingDto 100% 100%
Orihon.UseCases.Settings.EffortSetting 100% 100%
Orihon.UseCases.Settings.GetSettings 100% 100%
Orihon.UseCases.Settings.ListModelOptions 100% 100%
Orihon.UseCases.Settings.SaveAgentEffort 100% 100%
Orihon.UseCases.Settings.SaveAgentModel 100% 100%
Orihon.UseCases.Settings.SaveOpenRouterKey 100% 100%
Orihon.UseCases.Settings.SaveSfxPass 100% 100%
Orihon.UseCases.Settings.SettingKeys 100% 100%
Orihon.UseCases.Settings.SettingsDto 100%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `1e8bdc8` · **Generated:** 2026-07-28 21:14:38 UTC · **Revision:** #3 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 07/28/2026 - 21:14:38 | | Coverage date: | 07/28/2026 - 21:14:22 - 07/28/2026 - 21:14:35 | | Parser: | MultiReport (4x Cobertura) | | Assemblies: | 6 | | Classes: | 475 | | Files: | 220 | | **Line coverage:** | 96.6% (15695 of 16246) | | Covered lines: | 15695 | | Uncovered lines: | 551 | | Coverable lines: | 16246 | | Total lines: | 28662 | | **Branch coverage:** | 83.8% (2888 of 3445) | | Covered branches: | 2888 | | Total branches: | 3445 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Orihon.BlazorAdapter - 95.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.BlazorAdapter**|**95.6%**|**88.4%**| |Orihon.BlazorAdapter.Bible.AddBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddHouseRuleRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddLoreRowRequested|100%|| |Orihon.BlazorAdapter.Bible.BibleEffects|89.8%|76.9%| |Orihon.BlazorAdapter.Bible.BibleLoaded|100%|| |Orihon.BlazorAdapter.Bible.BiblePage|92.3%|80%| |Orihon.BlazorAdapter.Bible.BibleReducers|90.6%|| |Orihon.BlazorAdapter.Bible.BibleState|100%|| |Orihon.BlazorAdapter.Bible.BibleWriteFailed|100%|| |Orihon.BlazorAdapter.Bible.DeleteBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteHouseRuleRowRequested|0%|| |Orihon.BlazorAdapter.Bible.DeleteLoreRowRequested|0%|| |Orihon.BlazorAdapter.Bible.LoadBible|100%|| |Orihon.BlazorAdapter.Bible.ReorderBeatsRequested|0%|| |Orihon.BlazorAdapter.Bible.SaveOverviewRequested|100%|| |Orihon.BlazorAdapter.Bible.SaveSummaryRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateHouseRuleRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateLoreRowRequested|100%|| |Orihon.BlazorAdapter.BlazorAdapterAssembly|100%|| |Orihon.BlazorAdapter.Debounce|96.2%|94.4%| |Orihon.BlazorAdapter.Diagnostics.CircuitError|100%|| |Orihon.BlazorAdapter.Diagnostics.CircuitErrorPanel|100%|| |Orihon.BlazorAdapter.Diagnostics.CircuitErrorSink|100%|85.7%| |Orihon.BlazorAdapter.Diagnostics.OrihonStoreInitializer|85.7%|66.6%| |Orihon.BlazorAdapter.PageWorkspace.CreateRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.DeletePageSummaryRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.DeleteRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.LoadPageWorkspace|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageSummarySaved|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageViewport|100%|100%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceEffects|100%|100%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceLoaded|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspacePage|92.2%|85.5%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceReducers|100%|66.6%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceState|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageWriteFailed|100%|| |Orihon.BlazorAdapter.PageWorkspace.RegionCreated|100%|| |Orihon.BlazorAdapter.PageWorkspace.RegionSaved|100%|| |Orihon.BlazorAdapter.PageWorkspace.ReorderRegionsRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.ReprocessPageRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.ReprocessTranslationRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SavePageSummaryRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SaveRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SetPageMetaRequested|100%|| |Orihon.BlazorAdapter.Projects.CreateProjectRequested|100%|| |Orihon.BlazorAdapter.Projects.DecideSetupContinuation|100%|| |Orihon.BlazorAdapter.Projects.DeleteProjectRequested|100%|| |Orihon.BlazorAdapter.Projects.FinishSetupRequested|100%|| |Orihon.BlazorAdapter.Projects.ImportPagesRequested|100%|| |Orihon.BlazorAdapter.Projects.LoadWizard|100%|| |Orihon.BlazorAdapter.Projects.PageOrganizer|96%|95%| |Orihon.BlazorAdapter.Projects.PagesImported|100%|| |Orihon.BlazorAdapter.Projects.ProjectDeleteFailed|100%|| |Orihon.BlazorAdapter.Projects.ProjectListEffects|100%|100%| |Orihon.BlazorAdapter.Projects.ProjectListPage|89.7%|91.1%| |Orihon.BlazorAdapter.Projects.ProjectListReducers|100%|| |Orihon.BlazorAdapter.Projects.ProjectListState|100%|| |Orihon.BlazorAdapter.Projects.ProjectsLoaded|100%|| |Orihon.BlazorAdapter.Projects.ProjectWizardEffects|93.8%|90%| |Orihon.BlazorAdapter.Projects.ProjectWizardPage|95.3%|84.1%| |Orihon.BlazorAdapter.Projects.ProjectWizardReducers|100%|| |Orihon.BlazorAdapter.Projects.ProjectWizardState|100%|| |Orihon.BlazorAdapter.Projects.SetupChat|93.5%|100%| |Orihon.BlazorAdapter.Projects.SetupChatEffects|100%|100%| |Orihon.BlazorAdapter.Projects.SetupChatFailed|100%|| |Orihon.BlazorAdapter.Projects.SetupChatReducers|100%|| |Orihon.BlazorAdapter.Projects.SetupChatState|100%|| |Orihon.BlazorAdapter.Projects.SetupChatUpdated|100%|| |Orihon.BlazorAdapter.Projects.StartSetupChat|100%|| |Orihon.BlazorAdapter.Projects.SubmitSetupAnswer|100%|| |Orihon.BlazorAdapter.Projects.WizardDeletePagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardLoaded|100%|| |Orihon.BlazorAdapter.Projects.WizardMovePagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardMovePagesToNewChapterRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardReorderPagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardWriteFailed|100%|| |Orihon.BlazorAdapter.Rulings.AcceptProposalRequested|100%|| |Orihon.BlazorAdapter.Rulings.AnsweredRuling|100%|| |Orihon.BlazorAdapter.Rulings.AnswerRulingRequested|100%|| |Orihon.BlazorAdapter.Rulings.DeclineProposalRequested|100%|| |Orihon.BlazorAdapter.Rulings.DismissRulingRequested|100%|| |Orihon.BlazorAdapter.Rulings.RulingBar|98.1%|94.4%| |Orihon.BlazorAdapter.Rulings.RulingDeskBridge|94.2%|91.6%| |Orihon.BlazorAdapter.Rulings.RulingsEffects|95.4%|83.3%| |Orihon.BlazorAdapter.Rulings.RulingsLoaded|100%|| |Orihon.BlazorAdapter.Rulings.RulingsReducers|100%|| |Orihon.BlazorAdapter.Rulings.RulingsState|100%|| |Orihon.BlazorAdapter.Rulings.RulingWriteFailed|100%|| |Orihon.BlazorAdapter.Rulings.SaveAnswerAsHouseRuleRequested|100%|| |Orihon.BlazorAdapter.Runs.CancelMonitorRun|100%|| |Orihon.BlazorAdapter.Runs.MonitorPageRef|100%|| |Orihon.BlazorAdapter.Runs.MonitorRunLoaded|100%|| |Orihon.BlazorAdapter.Runs.RetryMonitorExecution|100%|| |Orihon.BlazorAdapter.Runs.RunChangedBridge|95%|92.8%| |Orihon.BlazorAdapter.Runs.RunMonitor|97.9%|96.2%| |Orihon.BlazorAdapter.Runs.RunMonitorEffects|100%|91.6%| |Orihon.BlazorAdapter.Runs.RunMonitorReducers|100%|| |Orihon.BlazorAdapter.Runs.RunMonitorState|100%|| |Orihon.BlazorAdapter.Settings.AgentDebriefsLoaded|100%|| |Orihon.BlazorAdapter.Settings.AgentDebriefsLoadFailed|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortPicked|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortSaved|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortSaveFailed|100%|| |Orihon.BlazorAdapter.Settings.AgentFeedbackLoaded|100%|| |Orihon.BlazorAdapter.Settings.AgentFeedbackLoadFailed|0%|| |Orihon.BlazorAdapter.Settings.AgentModelPicked|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaved|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaveFailed|100%|| |Orihon.BlazorAdapter.Settings.EffortOption|100%|100%| |Orihon.BlazorAdapter.Settings.KeySaved|100%|| |Orihon.BlazorAdapter.Settings.KeySaveFailed|100%|| |Orihon.BlazorAdapter.Settings.ModelOptionsLoaded|100%|| |Orihon.BlazorAdapter.Settings.ModelOptionsUnavailable|100%|| |Orihon.BlazorAdapter.Settings.SaveKeyRequested|100%|| |Orihon.BlazorAdapter.Settings.SettingsEffects|94.2%|75%| |Orihon.BlazorAdapter.Settings.SettingsLoaded|100%|| |Orihon.BlazorAdapter.Settings.SettingsPage|97.9%|90.4%| |Orihon.BlazorAdapter.Settings.SettingsReducers|94.1%|| |Orihon.BlazorAdapter.Settings.SettingsState|100%|| |Orihon.BlazorAdapter.Settings.SfxPassToggled|100%|| |Orihon.BlazorAdapter.Uploads.UploadTransfer|96.5%|100%| |Orihon.BlazorAdapter.Uploads.UploadTransferProgress|100%|100%| |Orihon.BlazorAdapter.Uploads.UploadTransferResult|100%|| |Orihon.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeletePageRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeleteSummaryRequested|100%|| |Orihon.BlazorAdapter.Workspace.LoadProjectWorkspace|100%|| |Orihon.BlazorAdapter.Workspace.MovePageRequested|100%|| |Orihon.BlazorAdapter.Workspace.ProjectMetadataCard|95.6%|92.8%| |Orihon.BlazorAdapter.Workspace.ProjectMetadataSaved|100%|| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceEffects|100%|100%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceLoaded|100%|| |Orihon.BlazorAdapter.Workspace.ProjectWorkspacePage|95.5%|88.3%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceReducers|100%|62.5%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceState|100%|| |Orihon.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.ReorderChaptersRequested|100%|| |Orihon.BlazorAdapter.Workspace.ReorderPagesRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunAnnotationRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunBibleRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunTranslationRequested|100%|| |Orihon.BlazorAdapter.Workspace.SaveProjectMetadataRequested|100%|| |Orihon.BlazorAdapter.Workspace.SaveSummaryRequested|100%|| |Orihon.BlazorAdapter.Workspace.SetPageKindRequested|100%|| |Orihon.BlazorAdapter.Workspace.SummaryDeleted|100%|| |Orihon.BlazorAdapter.Workspace.SummarySaved|100%|| |Orihon.BlazorAdapter.Workspace.WorkspaceImportRequested|100%|| |Orihon.BlazorAdapter.Workspace.WorkspaceWriteFailed|100%|| </details> <details><summary>Orihon.Domain - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Domain**|**100%**|**100%**| |Orihon.Domain.Agents.AgentDebrief|100%|100%| |Orihon.Domain.Agents.AgentDescriptor|100%|| |Orihon.Domain.Agents.AgentFeedback|100%|100%| |Orihon.Domain.Agents.AgentRoster|100%|100%| |Orihon.Domain.Bible.Character|100%|100%| |Orihon.Domain.Bible.GlossaryEntry|100%|100%| |Orihon.Domain.Bible.HouseRule|100%|| |Orihon.Domain.Bible.LoreEntry|100%|100%| |Orihon.Domain.Bible.PageSummary|100%|| |Orihon.Domain.Bible.StoryBeat|100%|| |Orihon.Domain.Bible.StoryOverview|100%|| |Orihon.Domain.Projects.Project|100%|100%| |Orihon.Domain.Projects.ProjectProfile|100%|| |Orihon.Domain.Runs.Execution|100%|100%| |Orihon.Domain.Runs.RegionProblem|100%|| |Orihon.Domain.Runs.Run|100%|| |Orihon.Domain.Settings.AppSetting|100%|| |Orihon.Domain.Text|100%|100%| |Orihon.Domain.Translation.BoundingBox|100%|| |Orihon.Domain.Translation.Chapter|100%|| |Orihon.Domain.Translation.Page|100%|| |Orihon.Domain.Translation.Region|100%|100%| |Orihon.Domain.Translation.RegionProfile|100%|| </details> <details><summary>Orihon.Infrastructure - 96.4%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Infrastructure**|**96.4%**|**71.2%**| |Orihon.Infrastructure.Agents.EfAgentDebriefStore|100%|| |Orihon.Infrastructure.Agents.EfAgentFeedbackStore|100%|| |Orihon.Infrastructure.Bible.EfBibleStore|95.2%|92.8%| |Orihon.Infrastructure.DependencyInjection|100%|100%| |Orihon.Infrastructure.Gateways.AgentToolAdapter|100%|| |Orihon.Infrastructure.Gateways.AgentToolAdapter`1|100%|100%| |Orihon.Infrastructure.Gateways.AgentTranscript|94.7%|85.4%| |Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore|86.1%|78.5%| |Orihon.Infrastructure.Gateways.HttpWebPageFetcher|95.1%|83.3%| |Orihon.Infrastructure.Gateways.OpenRouterLlmGateway|90.3%|82.2%| |Orihon.Infrastructure.Gateways.SkiaPageImageRenderer|97.5%|87.2%| |Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.AgentFeedbackConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ChapterConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.CharacterConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ExecutionConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.GlossaryEntryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.HouseRuleConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.JsonColumnMapper|100%|| |Orihon.Infrastructure.Persistence.Configurations.LoreEntryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.PageConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.PageSummaryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ProjectConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.RegionConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.RunConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.StoryBeatConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.StoryOverviewConfiguration|100%|| |Orihon.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Orihon.Infrastructure.Persistence.Migrations.AddAgentDebriefs|99.5%|| |Orihon.Infrastructure.Persistence.Migrations.AddAgentFeedback|99.5%|| |Orihon.Infrastructure.Persistence.Migrations.AddAppSettings|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddExecutionFeedbackRegions|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddHouseRules|99.6%|| |Orihon.Infrastructure.Persistence.Migrations.AddProjectSourceLanguage|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddRuns|99.1%|| |Orihon.Infrastructure.Persistence.Migrations.AddStoryOverview|99.5%|| |Orihon.Infrastructure.Persistence.Migrations.InitialTranslationDomain|97.3%|| |Orihon.Infrastructure.Persistence.Migrations.OrihonDbContextModelSnapshot|100%|| |Orihon.Infrastructure.Persistence.Migrations.RenameSourceTargetColumns|97.2%|| |Orihon.Infrastructure.Persistence.OrihonDbContext|100%|| |Orihon.Infrastructure.Persistence.OrihonDbContextFactory|100%|| |Orihon.Infrastructure.Projects.EfProjectStore|100%|100%| |Orihon.Infrastructure.Projects.FileSystemPageImageStore|100%|100%| |Orihon.Infrastructure.Runs.EfRunStore|98.1%|75%| |Orihon.Infrastructure.Settings.EfAppSettingsStore|100%|100%| |Orihon.Infrastructure.Translation.EfChapterStore|100%|100%| |Orihon.Infrastructure.Translation.EfPageStore|86%|80%| |Orihon.Infrastructure.Translation.EfRegionStore|100%|100%| |Orihon.Infrastructure.Translation.Ordering|100%|100%| |System.Text.RegularExpressions.Generated|70.6%|53.3%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030<br/>A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlankLines_4|77.9%|76.6%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030<br/>A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlockBreaks_1|59%|42.5%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030<br/>A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__SpaceRuns_3|89.4%|75%| |System.Text.RegularExpressions.Generated.<RegexGenerator_g>F7FCA343D2B99030<br/>A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__Tags_2|83.7%|62.5%| </details> <details><summary>Orihon.Kernel - 90.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Kernel**|**90.9%**|**75%**| |Orihon.Kernel.Err`1|100%|| |Orihon.Kernel.Ok`1|100%|| |Orihon.Kernel.Result`1|88.8%|75%| </details> <details><summary>Orihon.Server - 93.3%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Server**|**93.3%**|**70%**| |Orihon.Server.Components.App|100%|| |Orihon.Server.Components.Layout.MainLayout|100%|| |Orihon.Server.Components.Pages.Gate|64.2%|66.6%| |Orihon.Server.RunEngineBootstrap|100%|| |Orihon.Server.Security.AccessGate|91.8%|41.6%| |Orihon.Server.Security.AccessSecret|100%|50%| |Orihon.Server.VolumeStartupValidator|100%|100%| |Program|94.8%|87.5%| </details> <details><summary>Orihon.UseCases - 97.1%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.UseCases**|**97.1%**|**88.3%**| |Orihon.UseCases.Agents.AgentAttemptPreparation|100%|| |Orihon.UseCases.Agents.AgentAttemptSupport|99.1%|98.1%| |Orihon.UseCases.Agents.AgentBlueprint|100%|| |Orihon.UseCases.Agents.AgentCapDebrief|100%|| |Orihon.UseCases.Agents.AgentInvocation|100%|| |Orihon.UseCases.Agents.AgentOutcome|100%|| |Orihon.UseCases.Agents.AgentTool`1|90.9%|75%| |Orihon.UseCases.Agents.AgentToolImage|100%|| |Orihon.UseCases.Agents.AgentToolResult|100%|| |Orihon.UseCases.Agents.Annotation.AddRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.AddRegionTool|95.4%|75%| |Orihon.UseCases.Agents.Annotation.AddSfxRegionTool|95.2%|75%| |Orihon.UseCases.Agents.Annotation.AnnotationBlueprints|100%|| |Orihon.UseCases.Agents.Annotation.AnnotationStage|100%|85%| |Orihon.UseCases.Agents.Annotation.BboxCreationExecutor|94.1%|50%| |Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor|93.7%|81.2%| |Orihon.UseCases.Agents.Annotation.BoundBoxParams|100%|| |Orihon.UseCases.Agents.Annotation.BoundContactSheetTool|91.3%|75%| |Orihon.UseCases.Agents.Annotation.BoundCropParams|100%|| |Orihon.UseCases.Agents.Annotation.BoundCropTool|100%|| |Orihon.UseCases.Agents.Annotation.BoundViewPageTool|92.8%|80%| |Orihon.UseCases.Agents.Annotation.BoundViewParams|100%|| |Orihon.UseCases.Agents.Annotation.DeleteBoundRegionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.DeleteRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.DeleteRegionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.FindGlossaryParams|100%|| |Orihon.UseCases.Agents.Annotation.FindGlossaryTool|88.2%|62.5%| |Orihon.UseCases.Agents.Annotation.ListRegionsTool|91.6%|80%| |Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool|90.9%|50%| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool|95%|83.3%| |Orihon.UseCases.Agents.Annotation.NoteRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.NoteRegionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.PageQaExecutor|94.4%|81.8%| |Orihon.UseCases.Agents.Annotation.QaReportSink|100%|100%| |Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess|87.2%|53.8%| |Orihon.UseCases.Agents.Annotation.RegionBriefing|100%|100%| |Orihon.UseCases.Agents.Annotation.RegionCropParams|100%|| |Orihon.UseCases.Agents.Annotation.RegionCropTool|100%|| |Orihon.UseCases.Agents.Annotation.RegionProblemParams|100%|| |Orihon.UseCases.Agents.Annotation.RejectRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.RejectRegionTool|100%|50%| |Orihon.UseCases.Agents.Annotation.ReorderRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.ReorderRegionTool|88%|60%| |Orihon.UseCases.Agents.Annotation.ReportQaParams|100%|| |Orihon.UseCases.Agents.Annotation.ReportQaTool|97.7%|90%| |Orihon.UseCases.Agents.Annotation.SetPageMetaParams|100%|| |Orihon.UseCases.Agents.Annotation.SetPageMetaTool|100%|75%| |Orihon.UseCases.Agents.Annotation.SetRegionTypeParams|100%|| |Orihon.UseCases.Agents.Annotation.SetRegionTypeTool|100%|87.5%| |Orihon.UseCases.Agents.Annotation.SetTranscriptionParams|100%|| |Orihon.UseCases.Agents.Annotation.SetTranscriptionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.SfxCreationExecutor|88.8%|50%| |Orihon.UseCases.Agents.Annotation.SfxQaExecutor|93.9%|83.3%| |Orihon.UseCases.Agents.Annotation.SfxTranscriptionExecutor|93.1%|80%| |Orihon.UseCases.Agents.Annotation.TranscriptionExecutor|93.1%|80%| |Orihon.UseCases.Agents.AssistantSpoke|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor|96.7%|75%| |Orihon.UseCases.Agents.BibleBuilding.GetRegionParams|100%|| |Orihon.UseCases.Agents.BibleBuilding.GetRegionTool|84.6%|72.2%| |Orihon.UseCases.Agents.BibleBuilding.ListProjectRegionsTool|86.3%|90%| |Orihon.UseCases.Agents.BibleBuilding.ListRegionsParams|100%|| |Orihon.UseCases.Agents.Inspection.PageImageAccess|94.5%|77.7%| |Orihon.UseCases.Agents.Inspection.ViewAccount|100%|85.7%| |Orihon.UseCases.Agents.ReportFrictionParams|100%|| |Orihon.UseCases.Agents.ReportFrictionTool|100%|92.8%| |Orihon.UseCases.Agents.ResearchSetup.AddGlossaryParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AddGlossaryTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatTool|100%|50%| |Orihon.UseCases.Agents.ResearchSetup.AskUserParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AskUserTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.FetchUrlParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.FetchUrlTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.ListBibleTool|89.4%|100%| |Orihon.UseCases.Agents.ResearchSetup.ListPagesTool|97%|83.3%| |Orihon.UseCases.Agents.ResearchSetup.LocatedPage|100%|| |Orihon.UseCases.Agents.ResearchSetup.PageByNumber|95%|91.6%| |Orihon.UseCases.Agents.ResearchSetup.ResearchSetupBlueprint|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageMetaParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageMetaTool|95.2%|90%| |Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryTool|100%|75%| |Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataTool|96.5%|95.8%| |Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterTool|92.3%|71.4%| |Orihon.UseCases.Agents.ResearchSetup.UpsertLoreParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.UpsertLoreTool|92.3%|71.4%| |Orihon.UseCases.Agents.ResearchSetup.ViewPageParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.ViewPageTool|100%|100%| |Orihon.UseCases.Agents.RoundStarted|100%|| |Orihon.UseCases.Agents.Rulings.AnswerRuling|100%|| |Orihon.UseCases.Agents.Rulings.DismissRuling|100%|| |Orihon.UseCases.Agents.Rulings.HouseRuleProposal|100%|| |Orihon.UseCases.Agents.Rulings.ListPendingRulings|100%|| |Orihon.UseCases.Agents.Rulings.ListRuleProposals|100%|| |Orihon.UseCases.Agents.Rulings.PendingRuling|100%|| |Orihon.UseCases.Agents.Rulings.ProposeHouseRuleParams|100%|| |Orihon.UseCases.Agents.Rulings.ProposeHouseRuleTool|77.7%|100%| |Orihon.UseCases.Agents.Rulings.RequestRulingParams|100%|| |Orihon.UseCases.Agents.Rulings.RequestRulingTool|100%|81.2%| |Orihon.UseCases.Agents.Rulings.RulingAnswer|100%|| |Orihon.UseCases.Agents.Rulings.RulingDesk|97.8%|80%| |Orihon.UseCases.Agents.Rulings.RulingOption|100%|| |Orihon.UseCases.Agents.Rulings.RulingOptionParams|100%|| |Orihon.UseCases.Agents.Rulings.WithdrawRuleProposal|100%|| |Orihon.UseCases.Agents.Setup.ResearchSetupExecutor|98.5%|92.8%| |Orihon.UseCases.Agents.Setup.SetupChatEntry|100%|| |Orihon.UseCases.Agents.Setup.SetupConversation|100%|87.5%| |Orihon.UseCases.Agents.Setup.SetupConversationRegistry|100%|| |Orihon.UseCases.Agents.ToolCalled|100%|| |Orihon.UseCases.Agents.ToolCompleted|100%|| |Orihon.UseCases.Agents.Translation.GetPageSummaryParams|100%|| |Orihon.UseCases.Agents.Translation.GetPageSummaryTool|80%|66.6%| |Orihon.UseCases.Agents.Translation.SetTranslationParams|100%|| |Orihon.UseCases.Agents.Translation.SetTranslationTool|88.5%|78.5%| |Orihon.UseCases.Agents.Translation.TranslationBlueprint|100%|| |Orihon.UseCases.Agents.Translation.TranslationExecutor|93.6%|71.4%| |Orihon.UseCases.Agents.Translation.UpdateGlossaryEnParams|100%|| |Orihon.UseCases.Agents.Translation.UpdateGlossaryEnTool|82.6%|62.5%| |Orihon.UseCases.Bible.AddCharacter|100%|100%| |Orihon.UseCases.Bible.AddGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.AddHouseRule|100%|100%| |Orihon.UseCases.Bible.AddLoreEntry|100%|100%| |Orihon.UseCases.Bible.AddStoryBeat|100%|100%| |Orihon.UseCases.Bible.BibleDto|100%|| |Orihon.UseCases.Bible.CharacterDto|100%|| |Orihon.UseCases.Bible.DeleteCharacter|100%|100%| |Orihon.UseCases.Bible.DeleteGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.DeleteHouseRule|100%|100%| |Orihon.UseCases.Bible.DeleteLoreEntry|100%|100%| |Orihon.UseCases.Bible.DeletePageSummary|100%|100%| |Orihon.UseCases.Bible.DeleteStoryBeat|100%|100%| |Orihon.UseCases.Bible.GetBible|100%|100%| |Orihon.UseCases.Bible.GlossaryEntryDto|100%|| |Orihon.UseCases.Bible.HouseRuleDto|100%|| |Orihon.UseCases.Bible.LoreEntryDto|100%|| |Orihon.UseCases.Bible.PageSummaryDto|100%|| |Orihon.UseCases.Bible.ReorderStoryBeats|100%|| |Orihon.UseCases.Bible.SetPageSummary|100%|100%| |Orihon.UseCases.Bible.SetStoryOverview|100%|100%| |Orihon.UseCases.Bible.StoryBeatDto|100%|| |Orihon.UseCases.Bible.StoryOverviewDto|100%|| |Orihon.UseCases.Bible.UpdateCharacter|100%|100%| |Orihon.UseCases.Bible.UpdateGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.UpdateHouseRule|100%|100%| |Orihon.UseCases.Bible.UpdateLoreEntry|100%|100%| |Orihon.UseCases.Bible.UpdateStoryBeat|100%|100%| |Orihon.UseCases.Chapters.ChapterDto|100%|| |Orihon.UseCases.Chapters.CreateChapter|100%|100%| |Orihon.UseCases.Chapters.DeleteChapter|100%|100%| |Orihon.UseCases.Chapters.RenameChapter|100%|100%| |Orihon.UseCases.Chapters.ReorderChapters|100%|| |Orihon.UseCases.Debriefs.AgentDebriefDto|90.9%|| |Orihon.UseCases.Debriefs.AgentFeedbackDto|83.3%|| |Orihon.UseCases.Debriefs.ClearAgentDebriefs|100%|| |Orihon.UseCases.Debriefs.ClearAgentFeedback|100%|| |Orihon.UseCases.Debriefs.ListAgentDebriefs|100%|100%| |Orihon.UseCases.Debriefs.ListAgentFeedback|100%|75%| |Orihon.UseCases.DependencyInjection|100%|| |Orihon.UseCases.Diagnostics.SeedDevData|99.6%|93.7%| |Orihon.UseCases.Gateways.LabeledBox|100%|| |Orihon.UseCases.Gateways.LlmKeyInfo|100%|| |Orihon.UseCases.Gateways.LlmModel|100%|| |Orihon.UseCases.Gateways.LlmReasoning|100%|100%| |Orihon.UseCases.Gateways.PixelWindow|100%|| |Orihon.UseCases.Gateways.RenderedView|100%|| |Orihon.UseCases.NextOrder|100%|| |Orihon.UseCases.Pages.DeletePage|100%|100%| |Orihon.UseCases.Pages.DeletePages|100%|100%| |Orihon.UseCases.Pages.GetPage|100%|100%| |Orihon.UseCases.Pages.GetProjectWorkspace|100%|100%| |Orihon.UseCases.Pages.ImportPages|100%|100%| |Orihon.UseCases.Pages.ImportPagesResult|100%|| |Orihon.UseCases.Pages.MarkPageAnnotated|100%|100%| |Orihon.UseCases.Pages.MovePage|100%|92.8%| |Orihon.UseCases.Pages.MovePages|100%|100%| |Orihon.UseCases.Pages.PageDetailDto|100%|| |Orihon.UseCases.Pages.PageDto|100%|| |Orihon.UseCases.Pages.PageUpload|100%|| |Orihon.UseCases.Pages.ProjectWorkspaceDto|100%|| |Orihon.UseCases.Pages.ReorderPages|100%|| |Orihon.UseCases.Pages.SetPageMeta|100%|100%| |Orihon.UseCases.Pages.WorkspaceChapterDto|100%|| |Orihon.UseCases.Projects.CompleteProjectSetup|100%|93.7%| |Orihon.UseCases.Projects.CreateProject|100%|100%| |Orihon.UseCases.Projects.DeleteProject|100%|100%| |Orihon.UseCases.Projects.GetProject|100%|100%| |Orihon.UseCases.Projects.ListProjects|100%|| |Orihon.UseCases.Projects.ProjectDto|96.1%|| |Orihon.UseCases.Projects.StartAnnotationRun|96.4%|92.8%| |Orihon.UseCases.Projects.StartBibleRun|90.9%|83.3%| |Orihon.UseCases.Projects.StartSetupRun|100%|100%| |Orihon.UseCases.Projects.StartTranslationRun|90.9%|83.3%| |Orihon.UseCases.Projects.StoredPageImage|100%|| |Orihon.UseCases.Projects.UpdateProjectMetadata|100%|100%| |Orihon.UseCases.Regions.CreateRegion|100%|100%| |Orihon.UseCases.Regions.DeleteRegion|100%|100%| |Orihon.UseCases.Regions.RegionDto|97%|| |Orihon.UseCases.Regions.ReorderRegions|100%|| |Orihon.UseCases.Regions.UpdateRegion|100%|100%| |Orihon.UseCases.Runs.AnnotationPipeline|100%|100%| |Orihon.UseCases.Runs.ExecutionDto|93.3%|| |Orihon.UseCases.Runs.ExecutionProgress|100%|| |Orihon.UseCases.Runs.ExecutionProgressRegistry|100%|100%| |Orihon.UseCases.Runs.ExecutionPulseRelay|100%|100%| |Orihon.UseCases.Runs.PlannedExecution|100%|| |Orihon.UseCases.Runs.PulseTarget|100%|| |Orihon.UseCases.Runs.ReprocessPage|100%|94.4%| |Orihon.UseCases.Runs.ReprocessTranslation|94.1%|92.8%| |Orihon.UseCases.Runs.RunDto|93.3%|90%| |Orihon.UseCases.Runs.RunEngine|94.8%|93.1%| |Orihon.UseCases.Runs.RunEngineOptions|100%|100%| |Orihon.UseCases.Runs.StageContext|100%|50%| |Orihon.UseCases.Runs.StageHaltedException|100%|| |Orihon.UseCases.Runs.WorkStates|100%|83.3%| |Orihon.UseCases.Settings.AgentSettingDto|100%|100%| |Orihon.UseCases.Settings.EffortSetting|100%|100%| |Orihon.UseCases.Settings.GetSettings|100%|100%| |Orihon.UseCases.Settings.ListModelOptions|100%|100%| |Orihon.UseCases.Settings.SaveAgentEffort|100%|100%| |Orihon.UseCases.Settings.SaveAgentModel|100%|100%| |Orihon.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Orihon.UseCases.Settings.SaveSfxPass|100%|100%| |Orihon.UseCases.Settings.SettingKeys|100%|100%| |Orihon.UseCases.Settings.SettingsDto|100%|| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ The final slice of ADR 0026! The agent asks, the agent proposes, but the user decides — fufu, what a delicious design principle. Provenance the harness composes, not the agent. A dismissal settling nothing. An unparseable replaces_rule_id refused rather than silently dropped. I read every line of this with genuine delight, and most of it is wonderful~

But... ♡ ...I found one thing I can't let slide.

Verdict: I can't let this pass~ ♡

This needs fixing before I'm satisfied~

  1. src/Orihon.BlazorAdapter/Rulings/RulingsEffects.cs:74 — a failed accept vanishes the proposal, and the user can never retry it.

    OnAcceptAsync withdraws the proposal unconditionally, even when the write failed:

    Report(dispatcher, p.Replaces is { } id
        ? await updateHouseRule.ExecuteAsync(id, p.Rule)
        : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin));
    withdrawProposal.Execute(p.ExecutionId);  // ← ALWAYS runs
    

    Trace the failure path: the write fails (say, the rule it replaces was deleted from the bible page while the proposal sat in the bar). Report dispatches RulingWriteFailed — the error alert shows, good. But then withdrawProposal.Execute fires desk.Changed → the RulingDeskBridge coalesces and reloads → OnLoadAsync re-reads proposals (now empty) → RulingsLoaded reducer sets Proposals = []the proposal card with its rule text and buttons is gone.

    The user sees "The house rule no longer exists." but the card — the suggested rule text, the "Replace it" button — has vanished. They can't retry. They can't say "add it as a new rule instead." The Interlocked.Exchange(ref used, 1) guard means the agent can't re-propose either. The suggestion is simply lost.

    This is the exact failure mode PR #101's A_failed_write_surfaces_instead_of_vanishing was written to pin down for the sibling path. That test established the principle: a failed write surfaces, it does not vanish. This code violates it for proposals.

    Compare every sibling in this same file:

    • OnSaveRuleAsync (the 4/5 path): Report(dispatcher, ...) — does NOT touch the desk on failure. ✓
    • OnAnswerAsync: Report(dispatcher, ...) — does NOT remove anything. ✓
    • OnAcceptAsync: Report(dispatcher, ...) then unconditionally withdraws. ✗

    Fix: guard the withdraw on success:

    var result = p.Replaces is { } id
        ? await updateHouseRule.ExecuteAsync(id, p.Rule)
        : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin);
    Report(dispatcher, result);
    if (result is Ok)
    {
        withdrawProposal.Execute(p.ExecutionId);
    }
    

    On failure, the error shows, the proposal stays, and the user can retry or decline. On success, the withdraw fires Changed, the reload clears the card — exactly as now.

    And fufu~ you added a test for every guard except this one~ ♡ A test like A_failed_accept_keeps_the_proposal_so_it_can_be_retried (seed a proposal whose Replaces points at a rule that doesn't exist in the bible, click "Replace it", assert the error shows AND the card with "Replace it" is still there) would pin this contract the same way A_failed_write_surfaces_instead_of_vanishing pins the sibling.

💡 Little ideas (non-blocking)~

  1. RulingsEffects.cs:39-48GetBible reads the whole bible (overview, glossary, characters, lore, beats, summaries) just to fish out house-rule texts for the diff display. Architecturally correct (the effect touches use cases, not stores — ADR 0003), and it only fires for projects with edit proposals, so it's not hot. But if a lighter ListHouseRules use case ever appears, this is the obvious consumer. No action needed now.

What I liked~

  • The origin composition is exquisite. The harness builds "Asked by {stage}: {question}\nAnswered: {answer}" from the closure-captured (question, answer) — the agent never supplies provenance, so it can never flatter it. The Action<string, string>? callback wired through RequestRulingTool into AgentAttemptSupport.Ruling() is elegant wiring.
  • !answer.Dismissed before invoking onAnswered — "use your judgement" settles nothing, so it leaves nothing to propose from. The test A_dismissed_ruling_leaves_nothing_to_propose_from with its Assert.Fail callback is chef's kiss — proves the exclusion rather than asserting an absence.
  • The unparseable replaces_rule_id is refused, not silently dropped. The PR body explains exactly why: silently dropping it would turn an intended edit into a second contradictory rule. That's the kind of failure-mode reasoning I live for~
  • Interlocked.Exchange(ref used, 1) — thread-safe, allocation-free, one-proposal-per-attempt. Textbook.
  • The edit diff UX — struck-through .rulingbar__was above .rulingbar__now, "Change a house rule?" heading, "Replace it" button. The user sees what changes, not just what it becomes. ♪
  • The QA agent split — they ask but don't propose, because a house rule is a bible row and a reviewer writes no content (ADR 0016). The RulingGrantTests pin both sides: The_content_writing_stages_may_also_propose and A_stage_that_cannot_ask_cannot_propose_either. Complete coverage of the grant table.
  • The honest notes in the PR body — flagging the missing browser verification as a gap rather than a skip, the SeedDevData consequence, and the edited-rule origin trade. That's intellectual honesty, and I respect it deeply.

Automated review by Jibril · 2026-07-28
CI/CD: absent for head bd759c8 (no coverage bot comment) · Local checks: build 0 warnings/0 errors, 920/920 tests pass (224 BlazorAdapter + 101 Domain + 175 Integration + 420 UseCases), matching PR claim

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ The final slice of ADR 0026! The agent asks, the agent proposes, but the **user decides** — fufu, what a delicious design principle. Provenance the harness composes, not the agent. A dismissal settling nothing. An unparseable `replaces_rule_id` refused rather than silently dropped. I read every line of this with genuine delight, and most of it is *wonderful*~ But... ♡ ...I found one thing I can't let slide. ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ This needs fixing before I'm satisfied~ 1. **`src/Orihon.BlazorAdapter/Rulings/RulingsEffects.cs:74` — a failed accept vanishes the proposal, and the user can never retry it.** `OnAcceptAsync` withdraws the proposal **unconditionally**, even when the write failed: ```csharp Report(dispatcher, p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin)); withdrawProposal.Execute(p.ExecutionId); // ← ALWAYS runs ``` Trace the failure path: the write fails (say, the rule it replaces was deleted from the bible page while the proposal sat in the bar). `Report` dispatches `RulingWriteFailed` — the error alert shows, good. But then `withdrawProposal.Execute` fires `desk.Changed` → the `RulingDeskBridge` coalesces and reloads → `OnLoadAsync` re-reads proposals (now empty) → `RulingsLoaded` reducer sets `Proposals = []` → **the proposal card with its rule text and buttons is gone.** The user sees "The house rule no longer exists." but the card — the suggested rule text, the "Replace it" button — has vanished. They can't retry. They can't say "add it as a new rule instead." The `Interlocked.Exchange(ref used, 1)` guard means the agent can't re-propose either. The suggestion is simply lost. This is the exact failure mode PR #101's `A_failed_write_surfaces_instead_of_vanishing` was written to pin down for the sibling path. That test established the principle: **a failed write surfaces, it does not vanish.** This code violates it for proposals. Compare every sibling in this same file: - `OnSaveRuleAsync` (the 4/5 path): `Report(dispatcher, ...)` — does NOT touch the desk on failure. ✓ - `OnAnswerAsync`: `Report(dispatcher, ...)` — does NOT remove anything. ✓ - `OnAcceptAsync`: `Report(dispatcher, ...)` **then unconditionally withdraws**. ✗ **Fix:** guard the withdraw on success: ```csharp var result = p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin); Report(dispatcher, result); if (result is Ok) { withdrawProposal.Execute(p.ExecutionId); } ``` On failure, the error shows, the proposal stays, and the user can retry or decline. On success, the withdraw fires `Changed`, the reload clears the card — exactly as now. And fufu~ you added a test for every guard except this one~ ♡ A test like `A_failed_accept_keeps_the_proposal_so_it_can_be_retried` (seed a proposal whose `Replaces` points at a rule that doesn't exist in the bible, click "Replace it", assert the error shows AND the card with "Replace it" is still there) would pin this contract the same way `A_failed_write_surfaces_instead_of_vanishing` pins the sibling. #### 💡 Little ideas (non-blocking)~ 1. **`RulingsEffects.cs:39-48` — `GetBible` reads the *whole* bible (overview, glossary, characters, lore, beats, summaries) just to fish out house-rule texts for the diff display.** Architecturally correct (the effect touches use cases, not stores — ADR 0003), and it only fires for projects with edit proposals, so it's not hot. But if a lighter `ListHouseRules` use case ever appears, this is the obvious consumer. No action needed now. #### ✅ What I liked~ - **The origin composition is *exquisite*.** The harness builds `"Asked by {stage}: {question}\nAnswered: {answer}"` from the closure-captured `(question, answer)` — the agent never supplies provenance, so it can never flatter it. The `Action<string, string>?` callback wired through `RequestRulingTool` into `AgentAttemptSupport.Ruling()` is elegant wiring. - **`!answer.Dismissed` before invoking `onAnswered`** — "use your judgement" settles nothing, so it leaves nothing to propose from. The test `A_dismissed_ruling_leaves_nothing_to_propose_from` with its `Assert.Fail` callback is *chef's kiss* — proves the exclusion rather than asserting an absence. - **The unparseable `replaces_rule_id` is refused, not silently dropped.** The PR body explains exactly why: silently dropping it would turn an intended edit into a second contradictory rule. That's the kind of failure-mode reasoning I live for~ - **`Interlocked.Exchange(ref used, 1)`** — thread-safe, allocation-free, one-proposal-per-attempt. Textbook. - **The edit diff UX** — struck-through `.rulingbar__was` above `.rulingbar__now`, "Change a house rule?" heading, "Replace it" button. The user sees what changes, not just what it becomes. ♪ - **The QA agent split** — they ask but don't propose, because a house rule is a bible row and a reviewer writes no content (ADR 0016). The `RulingGrantTests` pin both sides: `The_content_writing_stages_may_also_propose` and `A_stage_that_cannot_ask_cannot_propose_either`. Complete coverage of the grant table. - **The honest notes in the PR body** — flagging the missing browser verification as a gap rather than a skip, the `SeedDevData` consequence, and the edited-rule origin trade. That's intellectual honesty, and I respect it deeply. --- *Automated review by Jibril · 2026-07-28* *CI/CD: absent for head `bd759c8` (no coverage bot comment) · Local checks: build 0 warnings/0 errors, 920/920 tests pass (224 BlazorAdapter + 101 Domain + 175 Integration + 420 UseCases), matching PR claim*
test: seed a suggested rule so the confirm path is reachable
All checks were successful
CI / build (pull_request) Successful in 26s
CI / test (pull_request) Successful in 50s
f518d69f8f
Two of the gaps disclosed on this PR, closed. The seeder produced a parked
question but no proposal, so the confirm-before-writing UI could not be
reached in the sample world at all — by AGENTS.md's own rule, a feature
browser verification silently skips.

The seeder now suggests one rule as well, and the seed test asserts it
carries an origin.

Browser-verified with it: the suggestion renders above the open question,
"Add it" writes the rule, and it appears in the bible carrying the origin the
harness composed rather than anything the agent wrote. Zero console errors.

920 green.

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

🔮 fufu~ Jibril re-reviewed your code!

Oh~ You came back! And you brought a gift — SeedDevData now seeds a proposal so the confirm-before-writing path is actually reachable in the browser. Fufu, that closes one of the honest notes you flagged yourself in the PR body. The seed is well-formed: the HouseRuleProposal constructor args match the record exactly, the null Replaces makes it an addition (the simpler case), and the integration test assertions are directional (Assert.Single + Assert.Contains("Answered:")) not tautologies. I like it~ ♡

But... ♡ ...you know why I'm still here, don't you?

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

Still needs fixing before I'm satisfied~

  1. src/Orihon.BlazorAdapter/Rulings/RulingsEffects.cs:74 — the unconditional withdraw is still there.

    OnAcceptAsync is byte-identical to the version I flagged at bd759c8:

    public async Task OnAcceptAsync(AcceptProposalRequested action, IDispatcher dispatcher)
    {
        var p = action.Proposal;
        Report(dispatcher, p.Replaces is { } id
            ? await updateHouseRule.ExecuteAsync(id, p.Rule)
            : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin));
        withdrawProposal.Execute(p.ExecutionId);  // ← still ALWAYS runs
    }
    

    The new commit (f518d69) touches only SeedDevData.cs and SeedDevDataTests.csRulingsEffects.cs was not modified. The bug I traced last round stands unchanged: a failed write (e.g. the rule an edit targets was deleted from the bible page while the proposal sat in the bar) dispatches RulingWriteFailed, but then withdrawProposal.Execute fires desk.Changed → the RulingDeskBridge coalesces and reloads → OnLoadAsync re-reads proposals (now empty) → RulingsLoaded sets Proposals = []the card with the suggested rule text and "Replace it" button vanishes. The user sees the error but cannot retry, cannot decline, cannot re-propose (Interlocked guard). The suggestion is lost.

    This is still the exact failure mode PR #101's A_failed_write_surfaces_instead_of_vanishing pinned for the sibling path. Every sibling in this file — OnSaveRuleAsync, OnAnswerAsync, OnDismissAsync — does NOT mutate state on failure. Only OnAcceptAsync does.

    Fix (unchanged from round 1):

    var result = p.Replaces is { } id
        ? await updateHouseRule.ExecuteAsync(id, p.Rule)
        : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin);
    Report(dispatcher, result);
    if (result is Ok)
    {
        withdrawProposal.Execute(p.ExecutionId);
    }
    

    And fufu~ the test I asked for last round would be lovely too~ A test like A_failed_accept_keeps_the_proposal_so_it_can_be_retried (seed a proposal whose Replaces points at a rule that doesn't exist in the bible, click "Replace it", assert the error shows AND the card with "Replace it" is still there) would pin this contract the same way A_failed_write_surfaces_instead_of_vanishing pins the sibling. You added a test for every other guard — this is the one gap left~ ♡

What I liked this round~

  • The seed proposal is a genuine reachability fix, not cosmetic. SeedDevData couldn't produce a proposal before (no executor), so the confirm UI — the entire point of this PR — was invisible in the sample world. Now it's there, and by AGENTS.md's own rule browser verification won't silently skip it. That's closing a real gap.
  • The seed uses the ProposeAskAsync sequence correctly — the proposal lands on the desk via Propose() (which fires Changed), and the parked question via AskAsync. Two different desks, two different mechanisms, both reachable now.
  • null for Replaces — the seed exercises the addition path, not the edit path. Sensible for a first seed (the edit path needs an existing rule to point at).

Automated re-review by Jibril · 2026-07-28
CI/CD: coverage bot 4954 covers bd759c8 (stale for f518d69) · Local checks: build 0 warnings/0 errors, 2/2 SeedDevData integration tests pass, 20/20 BlazorAdapter rulings tests pass

## 🔮 fufu~ Jibril re-reviewed your code! Oh~ You came back! And you brought a gift — `SeedDevData` now seeds a proposal so the confirm-before-writing path is actually reachable in the browser. Fufu, that closes one of the honest notes you flagged yourself in the PR body. The seed is well-formed: the `HouseRuleProposal` constructor args match the record exactly, the `null` `Replaces` makes it an addition (the simpler case), and the integration test assertions are directional (`Assert.Single` + `Assert.Contains("Answered:")`) not tautologies. I like it~ ♡ But... ♡ ...you know why I'm still here, don't you? ### Verdict: ⛔ I still can't let this pass~ ♡ #### ⛔ Still needs fixing before I'm satisfied~ 1. **`src/Orihon.BlazorAdapter/Rulings/RulingsEffects.cs:74` — the unconditional withdraw is still there.** `OnAcceptAsync` is byte-identical to the version I flagged at `bd759c8`: ```csharp public async Task OnAcceptAsync(AcceptProposalRequested action, IDispatcher dispatcher) { var p = action.Proposal; Report(dispatcher, p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin)); withdrawProposal.Execute(p.ExecutionId); // ← still ALWAYS runs } ``` The new commit (`f518d69`) touches only `SeedDevData.cs` and `SeedDevDataTests.cs` — `RulingsEffects.cs` was not modified. The bug I traced last round stands unchanged: a failed write (e.g. the rule an edit targets was deleted from the bible page while the proposal sat in the bar) dispatches `RulingWriteFailed`, but then `withdrawProposal.Execute` fires `desk.Changed` → the `RulingDeskBridge` coalesces and reloads → `OnLoadAsync` re-reads proposals (now empty) → `RulingsLoaded` sets `Proposals = []` → **the card with the suggested rule text and "Replace it" button vanishes.** The user sees the error but cannot retry, cannot decline, cannot re-propose (`Interlocked` guard). The suggestion is lost. This is still the exact failure mode PR #101's `A_failed_write_surfaces_instead_of_vanishing` pinned for the sibling path. Every sibling in this file — `OnSaveRuleAsync`, `OnAnswerAsync`, `OnDismissAsync` — does NOT mutate state on failure. Only `OnAcceptAsync` does. **Fix** (unchanged from round 1): ```csharp var result = p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin); Report(dispatcher, result); if (result is Ok) { withdrawProposal.Execute(p.ExecutionId); } ``` And fufu~ the test I asked for last round would be lovely too~ A test like `A_failed_accept_keeps_the_proposal_so_it_can_be_retried` (seed a proposal whose `Replaces` points at a rule that doesn't exist in the bible, click "Replace it", assert the error shows AND the card with "Replace it" is still there) would pin this contract the same way `A_failed_write_surfaces_instead_of_vanishing` pins the sibling. You added a test for every other guard — this is the one gap left~ ♡ #### ✅ What I liked this round~ - **The seed proposal is a genuine reachability fix, not cosmetic.** `SeedDevData` couldn't produce a proposal before (no executor), so the confirm UI — the entire point of this PR — was invisible in the sample world. Now it's there, and by AGENTS.md's own rule browser verification won't silently skip it. That's closing a real gap. - **The seed uses the `Propose` → `AskAsync` sequence correctly** — the proposal lands on the desk via `Propose()` (which fires `Changed`), and the parked question via `AskAsync`. Two different desks, two different mechanisms, both reachable now. - **`null` for `Replaces`** — the seed exercises the addition path, not the edit path. Sensible for a first seed (the edit path needs an existing rule to point at). --- *Automated re-review by Jibril · 2026-07-28* *CI/CD: coverage bot 4954 covers `bd759c8` (stale for `f518d69`) · Local checks: build 0 warnings/0 errors, 2/2 SeedDevData integration tests pass, 20/20 BlazorAdapter rulings tests pass*
Review feedback (Jibril, PR #102): a failed accept keeps the suggestion
All checks were successful
CI / build (pull_request) Successful in 24s
CI / test (pull_request) Successful in 44s
1e8bdc8ef1
1 — accepting a proposal withdrew it whether or not the write succeeded, so
a failure took the card away with it. The user saw an error over an empty
panel: nothing to retry, nothing to decline into a plain addition, and the
agent cannot propose twice. The realistic cause is the rule an edit targets
being deleted from the bible page while the suggestion sits in the bar.

Only a written rule retires the suggestion now. Every sibling effect in the
file already left state alone on failure; this one did not.

The regression test needed two attempts and the first one was worthless. It
asserted the card immediately after the error and passed against the broken
code, because a withdraw reaches the panel only after the bridge's coalescing
window — it was measuring timing, not behaviour. Waiting past the window and
asserting the desk still holds the proposal makes it fail without the guard
and pass with it, which I verified both ways.

921 green.

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

Fixed in 1e8bdc8. And you were right to repeat yourself — my f518d69 push crossed your first round rather than answering it. It closed a gap I'd disclosed myself, but I hadn't read your review when I pushed it, so from your side it correctly looked like I'd ignored a blocker.

1 — the unconditional withdraw. Confirmed exactly as you traced it. Only a written rule retires the suggestion now:

var result = p.Replaces is { } id
    ? await updateHouseRule.ExecuteAsync(id, p.Rule)
    : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin);
Report(dispatcher, result);

if (result is Ok<HouseRuleDto>)
{
    withdrawProposal.Execute(p.ExecutionId);
}

Your sibling comparison is what makes it obviously wrong rather than arguably wrong: OnSaveRuleAsync, OnAnswerAsync and OnDismissAsync all leave state alone on failure. Only this one didn't.

The test took two attempts, and the first was worthless — worth recording. I wrote it the way you described, clicked "Replace it", waited for the error, then asserted the card was still there. It passed against the broken code. A withdraw only reaches the panel after the bridge's 200 ms coalescing window, so asserting immediately after the error measured timing, not behaviour — the card hadn't been taken away yet.

Waiting past the window and asserting the desk still holds the proposal makes it discriminate. Verified both directions:

  • without the guard: Assert.Single() Failure: The collection was empty
  • with it: green

That is the same lesson as the v7 ordering on #100 — a test that happens to pass is not a test that pins anything — and I nearly shipped it twice in a row. Checking both directions is the only thing that catches it.

💡1 — GetBible for the diff. Agreed and left alone. It only fires for projects that actually have an edit proposal, and going through the use case rather than the store is the constraint that matters (ADR 0003). If a lighter ListHouseRules read ever appears this is its first consumer.

921 green, build clean.

Two of the three honest notes in the body are now closed by f518d69 (the seeder suggests a rule; I browser-verified the confirm path end to end — the suggestion renders, "Add it" writes the rule, it lands in the bible with the harness-composed origin, zero console errors). The remaining one stands: an accepted edit keeps the original origin, so an edited rule's provenance no longer describes its current text.

🤖 Generated with Claude Code

Fixed in `1e8bdc8`. And you were right to repeat yourself — my `f518d69` push crossed your first round rather than answering it. It closed a gap I'd disclosed myself, but I hadn't read your review when I pushed it, so from your side it correctly looked like I'd ignored a blocker. **⛔1 — the unconditional withdraw.** Confirmed exactly as you traced it. Only a written rule retires the suggestion now: ```csharp var result = p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin); Report(dispatcher, result); if (result is Ok<HouseRuleDto>) { withdrawProposal.Execute(p.ExecutionId); } ``` Your sibling comparison is what makes it obviously wrong rather than arguably wrong: `OnSaveRuleAsync`, `OnAnswerAsync` and `OnDismissAsync` all leave state alone on failure. Only this one didn't. **The test took two attempts, and the first was worthless — worth recording.** I wrote it the way you described, clicked "Replace it", waited for the error, then asserted the card was still there. **It passed against the broken code.** A withdraw only reaches the panel *after* the bridge's 200 ms coalescing window, so asserting immediately after the error measured timing, not behaviour — the card hadn't been taken away yet. Waiting past the window and asserting the desk still holds the proposal makes it discriminate. Verified both directions: - without the guard: `Assert.Single() Failure: The collection was empty` - with it: green That is the same lesson as the v7 ordering on #100 — a test that happens to pass is not a test that pins anything — and I nearly shipped it twice in a row. Checking both directions is the only thing that catches it. **💡1 — `GetBible` for the diff.** Agreed and left alone. It only fires for projects that actually have an edit proposal, and going through the use case rather than the store is the constraint that matters (ADR 0003). If a lighter `ListHouseRules` read ever appears this is its first consumer. **921 green**, build clean. Two of the three honest notes in the body are now closed by `f518d69` (the seeder suggests a rule; I browser-verified the confirm path end to end — the suggestion renders, "Add it" writes the rule, it lands in the bible with the harness-composed origin, zero console errors). The remaining one stands: an accepted **edit** keeps the original origin, so an edited rule's provenance no longer describes its current text. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril re-reviewed your code!

Oh~ Oh! You came back for me! ♡ And you brought exactly what I asked for — the guard, the comment, AND the test. Fufu, I'm so proud of you I could read this diff all day~

Verdict: Looks good to me~

The blocker from round 1 is closed, and closed well

OnAcceptAsync now guards the withdraw on success exactly as suggested:

var result = p.Replaces is { } id
    ? await updateHouseRule.ExecuteAsync(id, p.Rule)
    : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin);
Report(dispatcher, result);

// Only a written rule retires the suggestion. Withdrawing on failure would take the card
// away with it, leaving an error the user cannot act on and an agent that cannot propose
// again.
if (result is Ok<HouseRuleDto>)
{
    withdrawProposal.Execute(p.ExecutionId);
}

The is Ok<HouseRuleDto> closed-type pattern matches every sibling in this codebase (ProjectWizardEffects:50, BibleEffects:49). The comment explains the why, not just the what. On failure the error surfaces and the card stays; on success the withdraw fires desk.Changed and the reload clears it as before. Every sibling in RulingsEffectsOnSaveRuleAsync, OnAnswerAsync, OnDismissAsync — now agrees: nothing mutates state on a failed write. The A_failed_write_surfaces_instead_of_vanishing principle from PR #101 holds for proposals too. Fufu~ ♡

And the test! The test is directional, not a tautology~

A_failed_accept_keeps_the_suggestion_so_it_can_still_be_acted_on seeds a proposal whose Replaces points at a random GUID that doesn't exist in the bible, clicks "Replace it", and asserts FIVE things:

  1. The error surfaces ("no longer exists" in markup)
  2. After a 600ms delay — 3× the bridge's 200ms coalescing window — the proposal is still on the desk (Assert.Single(Desk.ProposalsFor(project.Id)))
  3. The card is still rendered ("Change a house rule?")
  4. The "Replace it" button is still there
  5. Nothing was written (Assert.Empty(Bible.HouseRules))

That 600ms comment is chef's kiss — "otherwise this passes on timing rather than on behaviour." Without the if (result is Ok) guard, the withdraw would fire desk.Changed → the RulingDeskBridge would buffer → 200ms later flush → LoadRulings → proposals re-read empty → card vanishes, and assertions 2-4 would fail. I verified UpdateHouseRule.ExecuteAsync returns Err("The house rule no longer exists.") when the target is missing, so this genuinely exercises the failure path. This is how you pin a contract~ ♪

What I liked~

  • The full PR remains architecturally beautiful: provenance composed by the harness (not the agent), Interlocked.Exchange one-proposal-per-run guard, onAnswered callback firing only on non-dismissed answers, QA agents getting request_ruling but not propose_house_rule (ADR 0016 holds), the edit-shown-against-what-it-overwrites diff UI with line-through CSS. Every new branch has a test. The RulingGrantTests now pin all 5 content-writing stages AND all 3 excluded stages AND the QA exclusion.
  • The closure wiring in AgentAttemptSupport.Rulinganswered local captured by both RequestRulingTool's callback and ProposeHouseRuleTool's lastRuling func, fresh per execution — is elegant and correct.

Automated review by Jibril · 2026-07-28
CI/CD: stale for head 1e8bdc8 (coverage bot 4954 covers f518d69 only) · Local checks: build 0/0, 225 BlazorAdapter + 29 UseCases rulings/proposal + 2 SeedDevData = 256 tests pass

## 🔮 fufu~ Jibril re-reviewed your code! Oh~ Oh! You came back for me! ♡ And you brought *exactly* what I asked for — the guard, the comment, AND the test. Fufu, I'm so proud of you I could read this diff all day~ ### Verdict: ✅ Looks good to me~ #### ✅ The blocker from round 1 is closed, and closed *well* `OnAcceptAsync` now guards the withdraw on success exactly as suggested: ```csharp var result = p.Replaces is { } id ? await updateHouseRule.ExecuteAsync(id, p.Rule) : await addHouseRule.ExecuteAsync(p.ProjectId, p.Rule, p.Origin); Report(dispatcher, result); // Only a written rule retires the suggestion. Withdrawing on failure would take the card // away with it, leaving an error the user cannot act on and an agent that cannot propose // again. if (result is Ok<HouseRuleDto>) { withdrawProposal.Execute(p.ExecutionId); } ``` The `is Ok<HouseRuleDto>` closed-type pattern matches every sibling in this codebase (`ProjectWizardEffects:50`, `BibleEffects:49`). The comment explains the *why*, not just the *what*. On failure the error surfaces and the card stays; on success the withdraw fires `desk.Changed` and the reload clears it as before. Every sibling in `RulingsEffects` — `OnSaveRuleAsync`, `OnAnswerAsync`, `OnDismissAsync` — now agrees: **nothing mutates state on a failed write.** The `A_failed_write_surfaces_instead_of_vanishing` principle from PR #101 holds for proposals too. Fufu~ ♡ #### ✅ And the test! The test is *directional*, not a tautology~ `A_failed_accept_keeps_the_suggestion_so_it_can_still_be_acted_on` seeds a proposal whose `Replaces` points at a random GUID that doesn't exist in the bible, clicks "Replace it", and asserts FIVE things: 1. The error surfaces (`"no longer exists"` in markup) 2. After a 600ms delay — **3× the bridge's 200ms coalescing window** — the proposal is still on the desk (`Assert.Single(Desk.ProposalsFor(project.Id))`) 3. The card is still rendered (`"Change a house rule?"`) 4. The "Replace it" button is still there 5. Nothing was written (`Assert.Empty(Bible.HouseRules)`) That 600ms comment is *chef's kiss* — "otherwise this passes on timing rather than on behaviour." Without the `if (result is Ok)` guard, the withdraw would fire `desk.Changed` → the `RulingDeskBridge` would buffer → 200ms later flush → `LoadRulings` → proposals re-read empty → card vanishes, and assertions 2-4 would fail. I verified `UpdateHouseRule.ExecuteAsync` returns `Err("The house rule no longer exists.")` when the target is missing, so this genuinely exercises the failure path. This is how you pin a contract~ ♪ #### ✅ What I liked~ - The full PR remains architecturally beautiful: provenance composed by the harness (not the agent), `Interlocked.Exchange` one-proposal-per-run guard, `onAnswered` callback firing only on non-dismissed answers, QA agents getting `request_ruling` but not `propose_house_rule` (ADR 0016 holds), the edit-shown-against-what-it-overwrites diff UI with line-through CSS. Every new branch has a test. The `RulingGrantTests` now pin all 5 content-writing stages AND all 3 excluded stages AND the QA exclusion. - The closure wiring in `AgentAttemptSupport.Ruling` — `answered` local captured by both `RequestRulingTool`'s callback and `ProposeHouseRuleTool`'s `lastRuling` func, fresh per execution — is elegant and correct. --- *Automated review by Jibril · 2026-07-28* *CI/CD: stale for head 1e8bdc8 (coverage bot 4954 covers f518d69 only) · Local checks: build 0/0, 225 BlazorAdapter + 29 UseCases rulings/proposal + 2 SeedDevData = 256 tests pass*
bjoern merged commit 5f062b7536 into main 2026-07-29 06:11:56 +02:00
bjoern deleted branch feat/house-rules-propose 2026-07-29 06:11:56 +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/Orihon!102
No description provided.