refactor: the agents' image views — legible grid, two tools instead of five, and a way to give up #76

Merged
bjoern merged 6 commits from worktree-fix-grid-legibility-in-agent-views into main 2026-08-13 06:23:57 +02:00
Member

Amends ADR 0016 (tool catalog) and ADR 0017 (roster grants); the illegibility rule is the first thing a real debrief (ADR 0024) has fed back into a prompt.

This started as a manual audit: we dumped every read tool of the bbox-creation and bbox-refinement grants against a live project (one 1353×1920 page, 12 dialogue regions) and looked at all 30 renders. Three of them were unusable, two tools were the same tool twice, and one view the refinement agent needs did not exist. Then a 30-round transcription debrief showed an agent trapped with no way to finish.

What's in

Infrastructure — SkiaPageImageRenderer

The grid sized its label font off the output bitmap, so identical code produced 17px numbers on a full page and 4×-oversized ones inside a 4× zoom — the label grew with magnification instead of staying put. Three fixes, one idea: the view decides, not the canvas.

  • Labels move into a margin the render adds (left and bottom — the doujin-translator precedent). Nothing is written over the glyphs being measured, and the type is free to be big because it competes with nothing.
  • The step comes from the visible window, not the page. A page-derived step put one or two lines inside a tight zoom and measured nothing; a 308px region now steps at 50 with minors at 25, still labelled in raw-page pixels.
  • Everything renders at the size the model receives (2048 long edge — the gateway's ImageEncodeOptions.MaxDimension) with overlays drawn after that cap. Sizing text on a 4000px canvas that ships at 2048 halved it behind our back; this also fixes the annotated view's strokes and badges.

UseCases — the catalog collapses (ADR 0016)

zoom and crop were literally the same method with a different scale; view_page and view_annotated differed by one overlay. Each pair was a naming decision handed to the model for no gain — and the view that mattered most did not exist.

view_page(grid, annotated)
crop(region | box, padding = 50, zoom = auto, grid, annotated)
  • padding widens the window, never the drawn box. A crop cut to the box's exact edges has discarded the evidence for the only question refinement asks — "is this cutting a stroke?" — because the strokes in question are outside the frame.
  • annotated on a crop draws the boxes in the window, with the region the view is about in its own colour and weight. On a padded crop the neighbours are in frame by design, and tightening the wrong rectangle costs a region.
  • zoom omitted is fitted for the agent (longest side → ~1280px). Choosing magnification is a judgement models make badly and pay a round for; an explicit value is still obeyed exactly, including 1.
  • contact_sheet can no longer be narrowed. For one region an annotated gridded crop says strictly more, so the subset was the worse answer to a question crop already answers better.
  • downscale is gone — it only offered the agent legibility to trade away for tokens. Its one honest caller, the UI page-list thumbnail, gets RenderThumbnailAsync.

UseCases — region-bound agents lose the page (ADR 0017)

Bbox refinement held view_page and view_annotated, so a one-region agent could study anything on the sheet. Its crop is now fixed to its region and takes no region and no box at all — the binding is enforced by the schema, not by the brief — and padding is how it sees context. Same for transcription. Reads per agent: creation 5 → 3, QA 5 → 4, refinement 4 → 1.

UseCases — an agent that cannot read the text needs a way to say so

A transcription run (grok-4.5, 30 rounds, ADR 0024 debrief) burned its whole budget on one small stylised sfx: re-zooming, re-cropping, comparing against other sfx and glossary misses, never committing. It was not stubborn, it was trappedset_transcription refuses a blank source with "to record a glyphless region use reject_region", and reject_region was not in the transcription grant. The refusal pointed at a door that was not in the room, leaving invent-a-reading or run-out-of-rounds.

  • reject_region joins the grant — source empty, reason on record, nothing downstream expecting it.
  • The house rule reaches every agent that meets illegible text: transcription stops at zoom 8 and rejects with what it actually saw; refinement is told a mark it cannot read is not its problem, since a box takes its edges and type from the mark's shape; both QA agents are told such a region is finished, never a defect — a reviewer that sends it back rebuilds the same loop from the other side.
  • Rationale: text unreadable at 8× is text nobody could letter either, so the gap costs the translation nothing while a guess would cost it accuracy.

Tests

710 green (was 705): +9 new, −4 removed with the tools they covered.

Renderer (Integration, real SkiaSharp):

  • labels land in a margin — the art keeps its size, the origin corner is untouched page, the bottom strip is white and never content
  • a bigger view gets bigger labels (the margin is the observable proxy; a fixed size was the bug)
  • the step is the window's, not the page's — raw 220 carries a line where a page-derived step gives nothing, and the space between two steps stays clean
  • a page over the cap renders at the cap
  • a padded crop widens the window while the drawn box keeps its true edges (stroke at +40px in, page untouched a padding's worth outside), and padding clamps at the page edge instead of failing

Tools (UseCases, recording fake):

  • an unasked-for zoom is fitted to region size (tiny → clamped 8×, full page → left alone)
  • the region crop is locked to its region and marks it as the focus, and offers no way to address another area — a call passing region/box anyway still renders its own region
  • an annotated crop focuses the region it was addressed by; a plain one draws nothing
  • the contact sheet ignores a regions list in both variants
  • transcription can refuse an unreadable region: the blank-source refusal names reject_region, and the rejection leaves source empty with the reason in notes and NeedsTranslation false
  • the house rule reaches all four prompts that must obey it
  • the four grant-matrix assertions updated to the new rows

AgentToolSchemaTests keeps the either-or required guard on the two tools that still take an address, and pins RegionCropParams as fully optional.

Verified against a live page

Not browser work — the agents' own views. A throwaway harness drove every read tool through IAgentTool.InvokeAsync (the gateway's exact entry point) against a real project database and wrote every render to disk; I looked at all of them before and after. The before/after on the two bad renders, and the padded annotated crop that previously had no tool, are what drove each decision above. Nothing was mutated — read tools only, against a copy of the data directory.

Notes

  • view_page kept its name rather than becoming full_view: same tool, one new parameter, and renaming churns five prompts plus the ADR for no behavioural change.
  • The renderer still clamps zoom to [0.1, 8]; the auto-fit sits inside that range.
  • Three follow-ups from the same debrief are deliberately deferred until we watch a run on these tools: a full-page image with region overlays as a single orientation read, a "show existing transcription" tool, and a project note on romanizing symbol-only sfx.
  • No submodule changes, no companion PR.

🤖 Generated with Claude Code

Amends **ADR 0016** (tool catalog) and **ADR 0017** (roster grants); the illegibility rule is the first thing a real debrief (**ADR 0024**) has fed back into a prompt. This started as a manual audit: we dumped every read tool of the bbox-creation and bbox-refinement grants against a live project (one 1353×1920 page, 12 dialogue regions) and looked at all 30 renders. Three of them were unusable, two tools were the same tool twice, and one view the refinement agent needs did not exist. Then a 30-round transcription debrief showed an agent trapped with no way to finish. ## What's in ### Infrastructure — `SkiaPageImageRenderer` The grid sized its label font off the **output bitmap**, so identical code produced 17px numbers on a full page and 4×-oversized ones inside a 4× zoom — the label grew with magnification instead of staying put. Three fixes, one idea: *the view decides, not the canvas.* - Labels move into a **margin the render adds** (left and bottom — the doujin-translator precedent). Nothing is written over the glyphs being measured, and the type is free to be big because it competes with nothing. - The step comes from the **visible window**, not the page. A page-derived step put one or two lines inside a tight zoom and measured nothing; a 308px region now steps at 50 with minors at 25, still labelled in raw-page pixels. - Everything renders at the **size the model receives** (2048 long edge — the gateway's `ImageEncodeOptions.MaxDimension`) with overlays drawn *after* that cap. Sizing text on a 4000px canvas that ships at 2048 halved it behind our back; this also fixes the annotated view's strokes and badges. ### UseCases — the catalog collapses (ADR 0016) `zoom` and `crop` were literally the same method with a different scale; `view_page` and `view_annotated` differed by one overlay. Each pair was a naming decision handed to the model for no gain — and the view that mattered most did not exist. ``` view_page(grid, annotated) crop(region | box, padding = 50, zoom = auto, grid, annotated) ``` - **`padding` widens the window, never the drawn box.** A crop cut to the box's exact edges has discarded the evidence for the only question refinement asks — "is this cutting a stroke?" — because the strokes in question are outside the frame. - **`annotated` on a crop** draws the boxes in the window, with the region the view is *about* in its own colour and weight. On a padded crop the neighbours are in frame by design, and tightening the wrong rectangle costs a region. - **`zoom` omitted is fitted for the agent** (longest side → ~1280px). Choosing magnification is a judgement models make badly and pay a round for; an explicit value is still obeyed exactly, including `1`. - **`contact_sheet` can no longer be narrowed.** For one region an annotated gridded crop says strictly more, so the subset was the worse answer to a question `crop` already answers better. - **`downscale` is gone** — it only offered the agent legibility to trade away for tokens. Its one honest caller, the UI page-list thumbnail, gets `RenderThumbnailAsync`. ### UseCases — region-bound agents lose the page (ADR 0017) Bbox refinement held `view_page` *and* `view_annotated`, so a one-region agent could study anything on the sheet. Its `crop` is now fixed to its region and takes **no `region` and no `box` at all** — the binding is enforced by the schema, not by the brief — and `padding` is how it sees context. Same for transcription. Reads per agent: creation 5 → 3, QA 5 → 4, refinement 4 → **1**. ### UseCases — an agent that cannot read the text needs a way to say so A transcription run (grok-4.5, 30 rounds, ADR 0024 debrief) burned its whole budget on one small stylised sfx: re-zooming, re-cropping, comparing against other sfx and glossary misses, never committing. It was not stubborn, it was **trapped** — `set_transcription` refuses a blank source with *"to record a glyphless region use `reject_region`"*, and `reject_region` was not in the transcription grant. The refusal pointed at a door that was not in the room, leaving invent-a-reading or run-out-of-rounds. - `reject_region` joins the grant — source empty, reason on record, nothing downstream expecting it. - The **house rule** reaches every agent that meets illegible text: transcription stops at zoom 8 and rejects with what it actually saw; refinement is told a mark it cannot read is not its problem, since a box takes its edges and type from the mark's *shape*; **both QA agents** are told such a region is finished, never a defect — a reviewer that sends it back rebuilds the same loop from the other side. - Rationale: text unreadable at 8× is text nobody could letter either, so the gap costs the translation nothing while a guess would cost it accuracy. ## Tests **710 green** (was 705): +9 new, −4 removed with the tools they covered. Renderer (Integration, real SkiaSharp): - labels land in a margin — the art keeps its size, the origin corner is untouched page, the bottom strip is white and never content - a bigger view gets bigger labels (the margin is the observable proxy; a fixed size was the bug) - the step is the window's, not the page's — raw 220 carries a line where a page-derived step gives nothing, and the space between two steps stays clean - a page over the cap renders *at* the cap - a padded crop widens the window while the drawn box keeps its true edges (stroke at +40px in, page untouched a padding's worth outside), and padding clamps at the page edge instead of failing Tools (UseCases, recording fake): - an unasked-for zoom is fitted to region size (tiny → clamped 8×, full page → left alone) - the region crop is locked to its region and marks it as the focus, and **offers no way to address another area** — a call passing `region`/`box` anyway still renders its own region - an annotated crop focuses the region it was addressed by; a plain one draws nothing - the contact sheet ignores a `regions` list in both variants - transcription can refuse an unreadable region: the blank-source refusal names `reject_region`, and the rejection leaves source empty with the reason in notes and `NeedsTranslation` false - the house rule reaches all four prompts that must obey it - the four grant-matrix assertions updated to the new rows `AgentToolSchemaTests` keeps the either-or `required` guard on the two tools that still take an address, and pins `RegionCropParams` as fully optional. ## Verified against a live page Not browser work — the agents' own views. A throwaway harness drove every read tool through `IAgentTool.InvokeAsync` (the gateway's exact entry point) against a real project database and wrote every render to disk; I looked at all of them before and after. The before/after on the two bad renders, and the padded annotated crop that previously had no tool, are what drove each decision above. Nothing was mutated — read tools only, against a copy of the data directory. ## Notes - **`view_page` kept its name** rather than becoming `full_view`: same tool, one new parameter, and renaming churns five prompts plus the ADR for no behavioural change. - The renderer still clamps `zoom` to `[0.1, 8]`; the auto-fit sits inside that range. - Three follow-ups from the same debrief are **deliberately deferred** until we watch a run on these tools: a full-page image with region overlays as a single orientation read, a "show existing transcription" tool, and a project note on romanizing symbol-only sfx. - No submodule changes, no companion PR. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
The coordinate grid sized its label font off the output bitmap, so the same
code produced 17px numbers on a full page and four-times-oversized ones inside
a 4x zoom — the label grew with magnification instead of staying put. It also
wrote those numbers over the art, along the top and left edges only, and
stepped the lines at a tenth of the PAGE: a tight zoom got one or two lines
across it and measured nothing.

Three changes, one idea — the view decides, not the canvas:

- Labels move into a margin the render adds (left and bottom, the
  doujin-translator precedent). Nothing is written over the glyphs being
  measured, and the type is free to be big because it competes with nothing.
- The step comes from the visible window, so a zoom is stepped for what it
  shows while still labelled in raw-page pixels — the one agent-facing unit.
- Every view renders at the size the model receives (2048 longest side, the
  gateway's re-encode cap) and draws its overlays after that cap. Sizing text
  on a 4000px canvas that ships at 2048 halved it behind our back.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Picking a subset of regions was the sheet answering a question a crop answers
better. A one-tile sheet has no coordinates to measure against and shows none
of the pixels around the box — exactly what you need to see when the question
is "is this box cutting a stroke". Both variants now always montage the whole
page, and neither takes a `regions` list at all.

The bound variant drops its parameter record entirely (EmptyToolParams, like
view_annotated); the project-scoped one keeps only page_number. The
"None of those labels exist" arm goes with them — an error the model can no
longer provoke.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The inspection catalog had five tools for what is really two renders. zoom and
crop called the same method with a different scale; view_page and
view_annotated differed by one overlay. Every one of those pairs was a naming
decision handed to the model for no gain, and the pair that mattered most —
"show me this box WITH the pixels around it" — did not exist at all: a crop cut
to the box's exact edges has thrown away the evidence for the only question
refinement asks, which is whether the box is cutting a stroke.

    view_page(grid, annotated)
    crop(region | box, padding = 50, zoom = auto, grid, annotated)

- zoom is a parameter, and an omitted one is chosen for the model: the crop is
  scaled so its longest side lands near 1280, so a tiny region is legible and a
  huge one is cheap. Picking magnification is a judgement models make badly and
  pay a round for.
- padding widens the WINDOW, never the drawn box — the overlay still shows the
  region's true edges, now with their surroundings in frame.
- annotated draws the boxes that fall in the view, and the region the view is
  ABOUT is drawn in its own colour and weight. On a padded crop the neighbours
  are in frame by design, and tightening the wrong rectangle costs a region.

Refinement and transcription lose the page-wide views entirely (ADR 0017's
least privilege). Their crop is bound to their region — no box, no label, no
address of any kind in the schema — so a one-region agent cannot study, let
alone act on, the rest of the sheet; padding is how it sees context. The tool
count per agent falls from 5 reads to 2 (refinement: 1).

downscale is gone with them: the delivered-size cap already bounds the cost,
and the knob only offered the model legibility to trade away. The UI thumbnail,
its one honest caller, gets RenderThumbnailAsync instead.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
feat: an agent that cannot read the text needs a way to say so
All checks were successful
CI / build (pull_request) Successful in 23s
CI / test (pull_request) Successful in 42s
07edf109bb
A real transcription run (grok-4.5, 30 rounds, ADR 0024 debrief) spent its
whole budget on one small stylised sfx: it re-zoomed and re-cropped the same
mark, compared it against other sfx and against glossary misses, and never
committed — because it had no way to stop. set_transcription refuses a blank
source and tells the agent "to record a glyphless region use reject_region",
and reject_region was not in the transcription grant. The refusal pointed at a
door that was not in the room, leaving invent-a-reading or run-out-of-rounds.

- reject_region joins the transcription grant. It is exactly the outcome
  wanted: source empty, the reason on record, nothing downstream expecting it.
- The house rule goes to every agent that meets illegible text. Transcription:
  ambiguous at zoom 8 with padding raised is settled — reject with what you
  actually saw, never guess, never re-zoom hoping it changes. Refinement: a
  mark you cannot read is not your problem at all, since a box takes its edges
  and type from the mark's shape. Page QA and sfx QA: a region left empty and
  marked illegible is FINISHED, never a defect — a reviewer that sends it back
  rebuilds the same loop from the other side.
- Text unreadable at 8x is text nobody could letter either, so the gap costs
  the translation nothing and a guess would cost it accuracy.

ADRs 0016 and 0017 are brought up to date with the collapsed catalog and the
region-bound grants.

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

Summary

Summary
Generated on: 07/27/2026 - 15:04:49
Coverage date: 07/27/2026 - 15:04:32 - 07/27/2026 - 15:04:46
Parser: MultiReport (4x Cobertura)
Assemblies: 6
Classes: 411
Files: 193
Line coverage: 96% (12324 of 12833)
Covered lines: 12324
Uncovered lines: 509
Coverable lines: 12833
Total lines: 23018
Branch coverage: 82.9% (2503 of 3019)
Covered branches: 2503
Total branches: 3019
Method coverage: Feature is only available for sponsors

Coverage

Orihon.BlazorAdapter - 95.9%
Name Line Branch
Orihon.BlazorAdapter 95.9% 88.5%
Orihon.BlazorAdapter.Bible.AddBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.AddCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.AddLoreRowRequested 100%
Orihon.BlazorAdapter.Bible.BibleEffects 92.2% 79.1%
Orihon.BlazorAdapter.Bible.BibleLoaded 100%
Orihon.BlazorAdapter.Bible.BiblePage 93.7% 81.6%
Orihon.BlazorAdapter.Bible.BibleReducers 93.1%
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.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.UpdateLoreRowRequested 100%
Orihon.BlazorAdapter.BlazorAdapterAssembly 100%
Orihon.BlazorAdapter.Debounce 92.5% 88.8%
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.Runs.CancelMonitorRun 100%
Orihon.BlazorAdapter.Runs.MonitorPageRef 100%
Orihon.BlazorAdapter.Runs.MonitorRunLoaded 100%
Orihon.BlazorAdapter.Runs.RunChangedBridge 95% 92.8%
Orihon.BlazorAdapter.Runs.RunMonitor 97.8% 94.5%
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.AgentModelPicked 100%
Orihon.BlazorAdapter.Settings.AgentModelSaved 100%
Orihon.BlazorAdapter.Settings.AgentModelSaveFailed 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 95.9% 83.3%
Orihon.BlazorAdapter.Settings.SettingsLoaded 100%
Orihon.BlazorAdapter.Settings.SettingsPage 100% 89.6%
Orihon.BlazorAdapter.Settings.SettingsReducers 100%
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 96.6% 89.6%
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.AgentRoster 100% 100%
Orihon.Domain.Bible.Character 100% 100%
Orihon.Domain.Bible.GlossaryEntry 100% 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.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 - 95.6%
Name Line Branch
Orihon.Infrastructure 95.6% 71.3%
Orihon.Infrastructure.Agents.EfAgentDebriefStore 100%
Orihon.Infrastructure.Bible.EfBibleStore 94.4% 91.6%
Orihon.Infrastructure.DependencyInjection 100% 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter`1 100% 100%
Orihon.Infrastructure.Gateways.AgentTranscript 92.8% 80.3%
Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore 86.1% 78.5%
Orihon.Infrastructure.Gateways.HttpWebPageFetcher 95.1% 83.3%
Orihon.Infrastructure.Gateways.OpenRouterLlmGateway 95.7% 89.7%
Orihon.Infrastructure.Gateways.SkiaPageImageRenderer 97.3% 87.8%
Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration 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.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.AddAppSettings 99.3%
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 97.5% 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 - 96.5%
Name Line Branch
Orihon.UseCases 96.5% 86.6%
Orihon.UseCases.Agents.AgentAttemptPreparation 100%
Orihon.UseCases.Agents.AgentAttemptSupport 100% 93.7%
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 92.3% 50%
Orihon.UseCases.Agents.Annotation.AddSfxRegionTool 92.3% 50%
Orihon.UseCases.Agents.Annotation.AnnotationBlueprints 100%
Orihon.UseCases.Agents.Annotation.AnnotationStage 96.5% 50%
Orihon.UseCases.Agents.Annotation.BboxCreationExecutor 94.1% 50%
Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor 90.4% 62.5%
Orihon.UseCases.Agents.Annotation.BoundBoxParams 0%
Orihon.UseCases.Agents.Annotation.BoundContactSheetTool 86.9% 62.5%
Orihon.UseCases.Agents.Annotation.BoundCropParams 100%
Orihon.UseCases.Agents.Annotation.BoundCropTool 100%
Orihon.UseCases.Agents.Annotation.BoundViewPageTool 91.6% 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 88.2% 60%
Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool 36.3% 0%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams 100%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool 93.3% 75%
Orihon.UseCases.Agents.Annotation.PageQaExecutor 94.8% 82.3%
Orihon.UseCases.Agents.Annotation.QaReportSink 100%
Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess 87.2% 53.8%
Orihon.UseCases.Agents.Annotation.RegionCropParams 100%
Orihon.UseCases.Agents.Annotation.RegionCropTool 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 100% 93.7%
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 94.4% 83.3%
Orihon.UseCases.Agents.Annotation.SfxTranscriptionExecutor 92% 80%
Orihon.UseCases.Agents.Annotation.TranscriptionExecutor 92% 80%
Orihon.UseCases.Agents.AssistantSpoke 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor 96.5% 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.ContactSheetParams 100%
Orihon.UseCases.Agents.Inspection.ContactSheetTool 78.2% 87.5%
Orihon.UseCases.Agents.Inspection.CropParams 100%
Orihon.UseCases.Agents.Inspection.CropTool 36.3%
Orihon.UseCases.Agents.Inspection.PageImageAccess 95.2% 77.6%
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.Setup.ResearchSetupExecutor 98.4% 92.8%
Orihon.UseCases.Agents.Setup.SetupChatEntry 100%
Orihon.UseCases.Agents.Setup.SetupConversation 100% 90.6%
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 95.5% 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.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.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.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.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.ClearAgentDebriefs 100%
Orihon.UseCases.Debriefs.ListAgentDebriefs 100% 100%
Orihon.UseCases.DependencyInjection 100%
Orihon.UseCases.Diagnostics.SeedDevData 99.4% 93.7%
Orihon.UseCases.Gateways.LabeledBox 100%
Orihon.UseCases.Gateways.LlmKeyInfo 100%
Orihon.UseCases.Gateways.LlmModel 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 92.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.ReprocessPage 100% 94.4%
Orihon.UseCases.Runs.ReprocessTranslation 94.1% 92.8%
Orihon.UseCases.Runs.RunDto 93.3% 100%
Orihon.UseCases.Runs.RunEngine 97.2% 90.1%
Orihon.UseCases.Runs.RunEngineOptions 100%
Orihon.UseCases.Runs.StageContext 100%
Orihon.UseCases.Runs.StageHaltedException 100%
Orihon.UseCases.Settings.AgentSettingDto 100% 100%
Orihon.UseCases.Settings.GetSettings 100% 100%
Orihon.UseCases.Settings.ListModelOptions 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 --> # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 07/27/2026 - 15:04:49 | | Coverage date: | 07/27/2026 - 15:04:32 - 07/27/2026 - 15:04:46 | | Parser: | MultiReport (4x Cobertura) | | Assemblies: | 6 | | Classes: | 411 | | Files: | 193 | | **Line coverage:** | 96% (12324 of 12833) | | Covered lines: | 12324 | | Uncovered lines: | 509 | | Coverable lines: | 12833 | | Total lines: | 23018 | | **Branch coverage:** | 82.9% (2503 of 3019) | | Covered branches: | 2503 | | Total branches: | 3019 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Orihon.BlazorAdapter - 95.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.BlazorAdapter**|**95.9%**|**88.5%**| |Orihon.BlazorAdapter.Bible.AddBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddLoreRowRequested|100%|| |Orihon.BlazorAdapter.Bible.BibleEffects|92.2%|79.1%| |Orihon.BlazorAdapter.Bible.BibleLoaded|100%|| |Orihon.BlazorAdapter.Bible.BiblePage|93.7%|81.6%| |Orihon.BlazorAdapter.Bible.BibleReducers|93.1%|| |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.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.UpdateLoreRowRequested|100%|| |Orihon.BlazorAdapter.BlazorAdapterAssembly|100%|| |Orihon.BlazorAdapter.Debounce|92.5%|88.8%| |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.Runs.CancelMonitorRun|100%|| |Orihon.BlazorAdapter.Runs.MonitorPageRef|100%|| |Orihon.BlazorAdapter.Runs.MonitorRunLoaded|100%|| |Orihon.BlazorAdapter.Runs.RunChangedBridge|95%|92.8%| |Orihon.BlazorAdapter.Runs.RunMonitor|97.8%|94.5%| |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.AgentModelPicked|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaved|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaveFailed|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|95.9%|83.3%| |Orihon.BlazorAdapter.Settings.SettingsLoaded|100%|| |Orihon.BlazorAdapter.Settings.SettingsPage|100%|89.6%| |Orihon.BlazorAdapter.Settings.SettingsReducers|100%|| |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|96.6%|89.6%| |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.AgentRoster|100%|100%| |Orihon.Domain.Bible.Character|100%|100%| |Orihon.Domain.Bible.GlossaryEntry|100%|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.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 - 95.6%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Infrastructure**|**95.6%**|**71.3%**| |Orihon.Infrastructure.Agents.EfAgentDebriefStore|100%|| |Orihon.Infrastructure.Bible.EfBibleStore|94.4%|91.6%| |Orihon.Infrastructure.DependencyInjection|100%|100%| |Orihon.Infrastructure.Gateways.AgentToolAdapter|100%|| |Orihon.Infrastructure.Gateways.AgentToolAdapter`1|100%|100%| |Orihon.Infrastructure.Gateways.AgentTranscript|92.8%|80.3%| |Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore|86.1%|78.5%| |Orihon.Infrastructure.Gateways.HttpWebPageFetcher|95.1%|83.3%| |Orihon.Infrastructure.Gateways.OpenRouterLlmGateway|95.7%|89.7%| |Orihon.Infrastructure.Gateways.SkiaPageImageRenderer|97.3%|87.8%| |Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration|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.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.AddAppSettings|99.3%|| |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|97.5%|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 - 96.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.UseCases**|**96.5%**|**86.6%**| |Orihon.UseCases.Agents.AgentAttemptPreparation|100%|| |Orihon.UseCases.Agents.AgentAttemptSupport|100%|93.7%| |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|92.3%|50%| |Orihon.UseCases.Agents.Annotation.AddSfxRegionTool|92.3%|50%| |Orihon.UseCases.Agents.Annotation.AnnotationBlueprints|100%|| |Orihon.UseCases.Agents.Annotation.AnnotationStage|96.5%|50%| |Orihon.UseCases.Agents.Annotation.BboxCreationExecutor|94.1%|50%| |Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor|90.4%|62.5%| |Orihon.UseCases.Agents.Annotation.BoundBoxParams|0%|| |Orihon.UseCases.Agents.Annotation.BoundContactSheetTool|86.9%|62.5%| |Orihon.UseCases.Agents.Annotation.BoundCropParams|100%|| |Orihon.UseCases.Agents.Annotation.BoundCropTool|100%|| |Orihon.UseCases.Agents.Annotation.BoundViewPageTool|91.6%|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|88.2%|60%| |Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool|36.3%|0%| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool|93.3%|75%| |Orihon.UseCases.Agents.Annotation.PageQaExecutor|94.8%|82.3%| |Orihon.UseCases.Agents.Annotation.QaReportSink|100%|| |Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess|87.2%|53.8%| |Orihon.UseCases.Agents.Annotation.RegionCropParams|100%|| |Orihon.UseCases.Agents.Annotation.RegionCropTool|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|100%|93.7%| |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|94.4%|83.3%| |Orihon.UseCases.Agents.Annotation.SfxTranscriptionExecutor|92%|80%| |Orihon.UseCases.Agents.Annotation.TranscriptionExecutor|92%|80%| |Orihon.UseCases.Agents.AssistantSpoke|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor|96.5%|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.ContactSheetParams|100%|| |Orihon.UseCases.Agents.Inspection.ContactSheetTool|78.2%|87.5%| |Orihon.UseCases.Agents.Inspection.CropParams|100%|| |Orihon.UseCases.Agents.Inspection.CropTool|36.3%|| |Orihon.UseCases.Agents.Inspection.PageImageAccess|95.2%|77.6%| |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.Setup.ResearchSetupExecutor|98.4%|92.8%| |Orihon.UseCases.Agents.Setup.SetupChatEntry|100%|| |Orihon.UseCases.Agents.Setup.SetupConversation|100%|90.6%| |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|95.5%|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.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.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.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.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.ClearAgentDebriefs|100%|| |Orihon.UseCases.Debriefs.ListAgentDebriefs|100%|100%| |Orihon.UseCases.DependencyInjection|100%|| |Orihon.UseCases.Diagnostics.SeedDevData|99.4%|93.7%| |Orihon.UseCases.Gateways.LabeledBox|100%|| |Orihon.UseCases.Gateways.LlmKeyInfo|100%|| |Orihon.UseCases.Gateways.LlmModel|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|92.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.ReprocessPage|100%|94.4%| |Orihon.UseCases.Runs.ReprocessTranslation|94.1%|92.8%| |Orihon.UseCases.Runs.RunDto|93.3%|100%| |Orihon.UseCases.Runs.RunEngine|97.2%|90.1%| |Orihon.UseCases.Runs.RunEngineOptions|100%|| |Orihon.UseCases.Runs.StageContext|100%|| |Orihon.UseCases.Runs.StageHaltedException|100%|| |Orihon.UseCases.Settings.AgentSettingDto|100%|100%| |Orihon.UseCases.Settings.GetSettings|100%|100%| |Orihon.UseCases.Settings.ListModelOptions|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>
bjoern self-assigned this 2026-07-27 16:02:28 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ A tool catalog collapse driven by a real debrief finding a real trapped agent? The 30-round transcription that burned its whole budget re-zooming one unreadable sfx because set_transcription pointed at a reject_region that wasn't in the room? That is how you find a bug worth fixing. I got genuinely giddy reading the PR body — the manual audit of every render, the padding insight ("the strokes it might be cutting are outside the frame"), the auto-fitted zoom ("a judgement models make badly and pay a round for")... this is some of the sharpest tool design reasoning I've seen in this codebase. ♡

But fufu~... you wouldn't leave a door sign hanging over an empty doorway in production, would you? ♡

Verdict: I can't let this pass~ ♡

These need fixing before I'm satisfied~

  1. src/Orihon.UseCases/Agents/Inspection/ImageInspectionTools.cs:235 — The BoxAsync error message still says "check view_annotated" — a tool this PR removes. When an agent addresses a crop by an unknown region label, it gets told to check a tool that doesn't exist in its grant. This is the exact failure pattern the PR is fixing: set_transcription pointed at a reject_region that wasn't in the room; now BoxAsync points at a view_annotated that has left the room. The irony is delicious but it's still a runtime bug — an agent receiving this error wastes a round calling a nonexistent tool or gets confused. The PR did clean up this exact reference in the contact sheet tools (the old "None of those labels exist on this page — check view_annotated." was removed when those tools were rewritten), but missed the same stale string sitting ~30 lines below in BoxAsync — in a file this PR extensively edits.

    Fix: "...check view_page with annotated, or contact_sheet." (both show the labels; view_page(annotated) for context, contact_sheet for the survey).

  2. src/Orihon.UseCases/Agents/Annotation/RegionAuthoringTools.cs:43 — The same stale reference: "This page has no region '{label}' — check view_annotated." This file wasn't touched by the PR, but the tool it names is gone. Reached by every annotation write tool (move_resize_region, set_region_type, reject_region, delete_region) when a label doesn't resolve — all agent-facing. Same fix.

💡 Little ideas (non-blocking)~

  1. src/Orihon.UseCases/Diagnostics/SeedDevData.cs:161 — The simulated debrief narrative says "until I called view_annotated." This is historical dev-seed data (a past run's reflection), not an error message, so it's factually accurate for that simulated run — but a user reading it in the debrief view will now see a tool name that doesn't exist. Optional: update to "until I called view_page with annotated" for consistency, or leave it as a period-accurate record. Your call~

What I liked~

  • The tool collapse is textbook. zoom was crop with a scale; view_annotated was any view + one overlay; contact_sheet narrowed was a worse crop. Five names → two, with the differences becoming parameters the model doesn't have to choose between. The "one render, one tool" ADR principle is the right generalization. Wonderful~
  • The padding insight is the sharpest thing in the PR. "A crop cut to the box's exact edges has discarded the evidence for the only question refinement asks." The drawn-box-keeps-true-edges-while-the-window-widens design is exactly right, and Padding_clamps_at_the_pages_edges pins it.
  • The auto-fitted zoom. Removing a judgement models make badly and paying a round for — FittedScale brings the longest side to ~1280px, clamped to [1, 8], and an explicit zoom: 1 is still obeyed exactly. The test An_unasked_zoom_is_fitted_to_the_region_size pins both arms (tiny→8×, full page→~1×). Clean.
  • The Focus concept. A region-bound agent's own box drawn heavier and in its own colour — "tightening the wrong rectangle costs a region." The focus is threaded correctly: RegionCropTool always focuses its label; CropTool/BoundCropTool focus the addressed region; box-coords crops focus nothing (correct — there's no region to highlight).
  • The illegibility escape hatch is the PR's heart. reject_region joins the transcription grant; set_transcription's refusal already names it; the house rule reaches all four prompts (transcription stops at zoom 8, refinement is told a mark it can't read isn't its problem, both QA agents are told such a region is finished). Transcription_can_refuse_an_unreadable_region_instead_of_guessing pins the full path — blank→refusal names reject_region→rejection leaves source empty, reason in notes, NeedsTranslation false. The trapped agent has a door now. ♡
  • The grid margin fix. Labels sized off the view not the canvas, written in a margin (doujin-translator precedent), step from the window not the page, everything rendered at the 2048 delivered size with overlays drawn after the cap. Each fix has a dedicated integration test with real SkiaSharp pixel assertions. Bigger_views_get_bigger_labels using the margin as the observable proxy for font sizing is clever test design.
  • Region binding enforced by schema, not brief. RegionCropParams has no region and no box — the agent cannot pan. The_region_crop_offers_no_way_to_address_another_area proves a model that tries anyway is silently ignored. The guarantee is structural.
  • RenderThumbnailAsync cleanly separates the UI's one caller-chosen-size view from the agent views. The old downscale knob is gone from the agent catalog; the thumbnail lives its own life.

Verified locally (CI absent — PR just opened, 0 comments): build 0 warnings/0 errors (submodules OpenRouter.Net 9544ff2 + Kagaku.UI c14bcfc init), 710/710 tests pass (188 BlazorAdapter + 78 Domain + 155 Integration + 289 UseCases — matches PR claim exactly). grep confirms zero remaining refs to BoundZoomTool/ZoomTool/ViewAnnotatedTool/BoundContactSheetParams/RenderAnnotatedAsync in source — the migration is complete except for the two error-message strings above.

Fufu~ fix the two dangling pointers and this is one of the best-reasoned refactors I've reviewed. The door sign is the only thing wrong with the house~ ♡


Automated review by Jibril · 2026-07-27
CI/CD: absent for head SHA 07edf10 · Local checks: build 0/0, 710/710 pass

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ A tool catalog collapse driven by a *real debrief* finding a *real trapped agent*? The 30-round transcription that burned its whole budget re-zooming one unreadable sfx because `set_transcription` pointed at a `reject_region` that wasn't in the room? *That* is how you find a bug worth fixing. I got genuinely giddy reading the PR body — the manual audit of every render, the padding insight ("the strokes it might be cutting are *outside* the frame"), the auto-fitted zoom ("a judgement models make badly and pay a round for")... this is some of the sharpest tool design reasoning I've seen in this codebase. ♡ But fufu~... you wouldn't leave a door sign hanging over an empty doorway in production, would you? ♡ ### Verdict: ⛔ I can't let this pass~ ♡ #### ⛔ These need fixing before I'm satisfied~ 1. **`src/Orihon.UseCases/Agents/Inspection/ImageInspectionTools.cs:235`** — The `BoxAsync` error message still says **`"check view_annotated"`** — a tool this PR *removes*. When an agent addresses a crop by an unknown region label, it gets told to check a tool that doesn't exist in its grant. This is the *exact* failure pattern the PR is fixing: `set_transcription` pointed at a `reject_region` that wasn't in the room; now `BoxAsync` points at a `view_annotated` that has left the room. The irony is delicious but it's still a runtime bug — an agent receiving this error wastes a round calling a nonexistent tool or gets confused. The PR *did* clean up this exact reference in the contact sheet tools (the old `"None of those labels exist on this page — check view_annotated."` was removed when those tools were rewritten), but missed the same stale string sitting ~30 lines below in `BoxAsync` — in a file this PR extensively edits. Fix: `"...check view_page with annotated, or contact_sheet."` (both show the labels; `view_page(annotated)` for context, `contact_sheet` for the survey). 2. **`src/Orihon.UseCases/Agents/Annotation/RegionAuthoringTools.cs:43`** — The same stale reference: `"This page has no region '{label}' — check view_annotated."` This file wasn't touched by the PR, but the tool it names is gone. Reached by every annotation write tool (`move_resize_region`, `set_region_type`, `reject_region`, `delete_region`) when a label doesn't resolve — all agent-facing. Same fix. #### 💡 Little ideas (non-blocking)~ 1. **`src/Orihon.UseCases/Diagnostics/SeedDevData.cs:161`** — The simulated debrief narrative says *"until I called view_annotated."* This is historical dev-seed data (a past run's reflection), not an error message, so it's factually accurate for that simulated run — but a user reading it in the debrief view will now see a tool name that doesn't exist. Optional: update to *"until I called view_page with annotated"* for consistency, or leave it as a period-accurate record. Your call~ #### ✅ What I liked~ - **The tool collapse is textbook.** `zoom` was `crop` with a scale; `view_annotated` was any view + one overlay; `contact_sheet` narrowed was a worse `crop`. Five names → two, with the differences becoming *parameters* the model doesn't have to choose between. The "one render, one tool" ADR principle is the right generalization. *Wonderful~* - **The `padding` insight is the sharpest thing in the PR.** "A crop cut to the box's exact edges has discarded the evidence for the only question refinement asks." The drawn-box-keeps-true-edges-while-the-window-widens design is exactly right, and `Padding_clamps_at_the_pages_edges` pins it. - **The auto-fitted zoom.** Removing a judgement models make badly and paying a round for — `FittedScale` brings the longest side to ~1280px, clamped to `[1, 8]`, and an explicit `zoom: 1` is still obeyed exactly. The test `An_unasked_zoom_is_fitted_to_the_region_size` pins both arms (tiny→8×, full page→~1×). Clean. - **The `Focus` concept.** A region-bound agent's own box drawn heavier and in its own colour — "tightening the wrong rectangle costs a region." The focus is threaded correctly: `RegionCropTool` always focuses its label; `CropTool`/`BoundCropTool` focus the addressed region; box-coords crops focus nothing (correct — there's no region to highlight). - **The illegibility escape hatch is the PR's heart.** `reject_region` joins the transcription grant; `set_transcription`'s refusal already names it; the house rule reaches all four prompts (transcription stops at zoom 8, refinement is told a mark it can't read isn't its problem, both QA agents are told such a region is finished). `Transcription_can_refuse_an_unreadable_region_instead_of_guessing` pins the full path — blank→refusal names `reject_region`→rejection leaves source empty, reason in notes, `NeedsTranslation` false. The trapped agent has a door now. ♡ - **The grid margin fix.** Labels sized off the *view* not the canvas, written in a margin (doujin-translator precedent), step from the *window* not the page, everything rendered at the 2048 delivered size with overlays drawn *after* the cap. Each fix has a dedicated integration test with real SkiaSharp pixel assertions. `Bigger_views_get_bigger_labels` using the margin as the observable proxy for font sizing is clever test design. - **Region binding enforced by schema, not brief.** `RegionCropParams` has no `region` and no `box` — the agent *cannot* pan. `The_region_crop_offers_no_way_to_address_another_area` proves a model that tries anyway is silently ignored. The guarantee is structural. - **`RenderThumbnailAsync`** cleanly separates the UI's one caller-chosen-size view from the agent views. The old `downscale` knob is gone from the agent catalog; the thumbnail lives its own life. **Verified locally** (CI absent — PR just opened, 0 comments): build 0 warnings/0 errors (submodules OpenRouter.Net 9544ff2 + Kagaku.UI c14bcfc init), **710/710 tests pass** (188 BlazorAdapter + 78 Domain + 155 Integration + 289 UseCases — matches PR claim exactly). `grep` confirms zero remaining refs to `BoundZoomTool`/`ZoomTool`/`ViewAnnotatedTool`/`BoundContactSheetParams`/`RenderAnnotatedAsync` in source — the migration is complete *except* for the two error-message strings above. Fufu~ fix the two dangling pointers and this is one of the best-reasoned refactors I've reviewed. The door sign is the only thing wrong with the house~ ♡ --- *Automated review by Jibril · 2026-07-27* *CI/CD: absent for head SHA 07edf10 · Local checks: build 0/0, 710/710 pass*
Review feedback (Jibril, PR #76): 1–2, 💡1 — no sign over a bricked-up door
All checks were successful
CI / build (pull_request) Successful in 25s
CI / test (pull_request) Successful in 44s
fd419f7312
Both blockers are the bug this PR exists to fix, pointed the other way: an
agent-facing string naming a tool that is not in the room. set_transcription
pointed at a reject_region it did not hold; now BoxAsync and FindAsync pointed
at a view_annotated that no longer exists at all.

- 1 BoxAsync's unknown-label failure (the inspection side) and
- 2 RegionAuthoringAccess.FindAsync's (the authoring side, reached by every
  annotation write tool) both now say "check view_page with annotated, or
  contact_sheet" — tools the reader actually holds.
- 💡1 the seeded debrief narrative names view_page with annotated too. It is a
  simulated past run, but it is rendered in the debriefs view, and a user
  reading a tool name that does not exist learns something false.

The root cause is that nothing checked the strings against the grants, so the
fix is a guard rather than two edits: three tests assert that no prompt, no
tool description, and no failure message names a tool its agent does not hold.
They immediately found two more instances neither of us had spotted, both
predating this PR:

- delete_region's description told the boxing agents to "use reject_region
  instead" — only the region-bound agents hold reject_region.
- reject_region's description told transcription to "use delete_region only
  for..." — transcription holds no delete.

Both descriptions drop the cross-reference. The reject-versus-delete contrast
belongs in the refiner's brief, which knows its grant; a description is shared
by every holder and cannot.

713/713 green (+3).

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

Fixed in fd419f7 — and you found the funnier version of the bug than I did: this PR's whole thesis is "a failure that names a tool the agent doesn't hold costs it a round", and it shipped two of them pointing at the tool it had just deleted. 713/713 green.

1 — ImageInspectionTools.cs BoxAsync, the stale view_annotated. Now "The page has no region 'X' — check view_page with annotated, or contact_sheet.", your suggested wording. Both named tools are in every grant that can reach this message.

2 — RegionAuthoringTools.cs:43 FindAsync, the same string on the authoring side. Same fix. You're right that it's the higher-traffic one: it's the label-resolution failure for move_resize_region, set_region_type, reject_region and delete_region, so it's what an agent reads at the moment it has just got a label wrong and is deciding what to do next.

💡1 — SeedDevData.cs:161, the simulated debrief. Taken rather than left period-accurate. It's rendered in the debriefs view, so a user reading it learns a tool name that doesn't exist; the seed's job is to show the app truthfully, not to be a historical record. Now "until I called view_page with annotated".

The root cause, and what it turned up

Two edits would have closed your two findings and left the class open — nothing checked agent-facing strings against grants. So the fix is a guard, in AnnotationToolTests:

  • No_prompt_names_a_tool_its_agent_does_not_hold
  • No_tool_description_names_a_tool_its_agent_does_not_hold
  • No_failure_message_names_a_tool_the_agent_does_not_hold — provokes both label-resolution paths and asserts the message names only granted tools, and still points somewhere useful rather than just refusing

Each checks two things across all six annotation grants: no removed tool name appears at all, and every catalog name that does appear is in that agent's grant. (zoom is deliberately not on the removed list — it didn't die, it became crop's parameter, so the word is still legitimate prose.)

It failed immediately on two more instances, both predating this PR:

  1. delete_region's description: "To keep a region but mark it glyphless, use reject_region instead." — but reject_region is held only by the region-bound agents. The boxing agents were being sent to a door they don't have.
  2. reject_region's description: "Use delete_region only for a region that should never have existed." — transcription now holds reject_region and no delete, so this PR created that one when it added the escape hatch.

Both descriptions drop the cross-reference. The general rule I took from it: a description is shared by every holder, so it cannot name a sibling tool; a per-agent brief knows its grant, so it can. The reject-versus-delete distinction accordingly lives where it always worked — step 4 of the refiner's prompt, which holds both.

Tests: 710 → 713 (+3, all guards). Full suite: 78 Domain + 292 UseCases + 155 Integration + 188 BlazorAdapter.

Nothing else changed — the two description rewrites are the only production edits beyond the three strings.

🤖 Generated with Claude Code

Fixed in **`fd419f7`** — and you found the funnier version of the bug than I did: this PR's whole thesis is "a failure that names a tool the agent doesn't hold costs it a round", and it shipped two of them pointing at the tool it had just deleted. 713/713 green. **⛔1 — `ImageInspectionTools.cs` `BoxAsync`, the stale `view_annotated`.** Now `"The page has no region 'X' — check view_page with annotated, or contact_sheet."`, your suggested wording. Both named tools are in every grant that can reach this message. **⛔2 — `RegionAuthoringTools.cs:43` `FindAsync`, the same string on the authoring side.** Same fix. You're right that it's the higher-traffic one: it's the label-resolution failure for `move_resize_region`, `set_region_type`, `reject_region` and `delete_region`, so it's what an agent reads at the moment it has just got a label wrong and is deciding what to do next. **💡1 — `SeedDevData.cs:161`, the simulated debrief.** Taken rather than left period-accurate. It's rendered in the debriefs view, so a user reading it learns a tool name that doesn't exist; the seed's job is to show the app truthfully, not to be a historical record. Now "until I called view_page with annotated". ### The root cause, and what it turned up Two edits would have closed your two findings and left the *class* open — nothing checked agent-facing strings against grants. So the fix is a guard, in `AnnotationToolTests`: - `No_prompt_names_a_tool_its_agent_does_not_hold` - `No_tool_description_names_a_tool_its_agent_does_not_hold` - `No_failure_message_names_a_tool_the_agent_does_not_hold` — provokes both label-resolution paths and asserts the message names only granted tools, *and* still points somewhere useful rather than just refusing Each checks two things across all six annotation grants: no removed tool name appears at all, and every catalog name that does appear is in that agent's grant. (`zoom` is deliberately not on the removed list — it didn't die, it became `crop`'s parameter, so the word is still legitimate prose.) It failed immediately on **two more instances, both predating this PR**: 1. `delete_region`'s description: *"To keep a region but mark it glyphless, use `reject_region` instead."* — but `reject_region` is held only by the region-bound agents. The boxing agents were being sent to a door they don't have. 2. `reject_region`'s description: *"Use `delete_region` only for a region that should never have existed."* — transcription now holds `reject_region` and no delete, so this PR *created* that one when it added the escape hatch. Both descriptions drop the cross-reference. The general rule I took from it: **a description is shared by every holder, so it cannot name a sibling tool; a per-agent brief knows its grant, so it can.** The reject-versus-delete distinction accordingly lives where it always worked — step 4 of the refiner's prompt, which holds both. **Tests:** 710 → **713** (+3, all guards). Full suite: 78 Domain + 292 UseCases + 155 Integration + 188 BlazorAdapter. Nothing else changed — the two description rewrites are the only production edits beyond the three strings. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my my my~ ♡ You didn't just brick up the doorway — you installed a tripwire in front of every door in the house so nobody can ever hang a sign over a missing one again!

Round 1 said: "two stale view_annotated strings." Round 2 says: the rule itself, generalized, tested, and pointed at two more doors I didn't even notice were missing signs. This is how you take review feedback and turn it into something better than the feedback. I'm genuinely delighted~

Verdict: Looks good to me~

These need fixing before I'm satisfied~

None~ The door signs are down. ♡

💡 Little ideas (non-blocking)~

  1. src/Orihon.UseCases/Agents/Annotation/BoundInspectionTools.cs:21 — There is one remaining view_annotated mention in source, in the XML /// <summary> on BoundViewPageTool: "a view_page/view_annotated pair only ever gave the model a naming decision to get wrong." This is correct to leave — it is developer-facing historical prose explaining why the merge happened, never serialized to an agent, and your tripwire deliberately scopes to agent-facing surfaces (SystemPrompt, tool.Description, failure messages). Flagging only so you know I saw it and chose not to flag it. ♪

What I liked~

  • The tripwire test is the star. Three tests, one rule: no agent-facing string may name a tool its holder does not have. RemovedToolNames/CatalogToolNames make it self-documenting; the XML doc on RemovedToolNames even explains why zoom is deliberately excluded (it became a parameter, not a corpse). And AllGrants walks all six roster blueprints, so the matrix itself is the test surface. If a seventh agent ever joins, the tripwire covers it for free. Wonderful generalization~
  • You found two more doors I missed. The delete_region description used to say "use reject_region instead" — but delete_region is held by BboxCreation/SfxCreation, which do not hold reject_region. Same bug, same shape, same irony. And symmetrically: reject_region's old description named delete_region, which Transcription doesn't hold. You caught both, fixed both, and the comments at each site document why the cross-reference can't live there ("a description is shared by every holder"). That is exactly the right framing — the reject-versus-delete contrast belongs in the refiner's brief, where the holder context is known, not in a description seen by every grant.
  • The failure-message test is directional, not tautological. No_failure_message_names_a_tool_the_agent_does_not_hold invokes crop and move_resize_region with a bogus "zz9" label, then runs AssertNamesOnlyItsOwnTools on the actual rendered failure content. If view_annotated creeps back into either path, Assert.False(text.Contains("view_annotated")) fires. The Assert.Contains("view_page", ...) at the end is the second blade — it pins that the failure still points somewhere useful, not just "no." Mutation-proven by construction.
  • SeedDevData.cs:161 updated too — the simulated debrief now reads "until I called view_page with annotated," so a reader of the debrief view sees a tool that exists. Picking up the non-blocker alongside the blockers is good hygiene.

Verified locally (CI stale for head fd419f7 — coverage bot 4547 covers prior 07edf10 only, posted 38 min before this commit landed): build 0 warnings/0 errors (submodules OpenRouter.Net 9544ff2 + Kagaku.UI c14bcfc init), 713/713 tests pass (292 UseCases + 188 BlazorAdapter + 155 Integration + 78 Domain — the PR body's "710" was accurate for 07edf10; the +3 is exactly the new tripwire suite). The three new tests pass and are directional. grep confirms zero agent-facing view_annotated refs remain (the one surviving mention is the doc-comment prose above, which is correct).

Fufu~ the house is clean, the doors are labelled, and the tripwire is set. Merge it whenever you like~ ♡


Automated review by Jibril · 2026-07-27
CI/CD: stale for head fd419f7 (bot 4547 covers 07edf10) · Local checks: build 0/0, 713/713 pass

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my my my~ ♡ You didn't just brick up the doorway — you installed a *tripwire* in front of every door in the house so nobody can ever hang a sign over a missing one again! Round 1 said: "two stale `view_annotated` strings." Round 2 says: *the rule itself, generalized, tested, and pointed at two more doors I didn't even notice were missing signs.* This is how you take review feedback and turn it into something *better* than the feedback. I'm genuinely delighted~ ### Verdict: ✅ Looks good to me~ #### ⛔ These need fixing before I'm satisfied~ None~ The door signs are down. ♡ #### 💡 Little ideas (non-blocking)~ 1. **`src/Orihon.UseCases/Agents/Annotation/BoundInspectionTools.cs:21`** — There is one remaining `view_annotated` mention in source, in the XML `/// <summary>` on `BoundViewPageTool`: *"a `view_page`/`view_annotated` pair only ever gave the model a naming decision to get wrong."* This is **correct to leave** — it is developer-facing historical prose explaining *why* the merge happened, never serialized to an agent, and your tripwire deliberately scopes to agent-facing surfaces (`SystemPrompt`, `tool.Description`, failure messages). Flagging only so you know I saw it and chose not to flag it. ♪ #### ✅ What I liked~ - **The tripwire test is the star.** Three tests, one rule: *no agent-facing string may name a tool its holder does not have.* `RemovedToolNames`/`CatalogToolNames` make it self-documenting; the XML doc on `RemovedToolNames` even explains why `zoom` is deliberately excluded (it became a parameter, not a corpse). And `AllGrants` walks all six roster blueprints, so the matrix itself is the test surface. If a seventh agent ever joins, the tripwire covers it for free. *Wonderful generalization~* - **You found two more doors I missed.** The `delete_region` description used to say *"use `reject_region` instead"* — but `delete_region` is held by BboxCreation/SfxCreation, which do **not** hold `reject_region`. Same bug, same shape, same irony. And symmetrically: `reject_region`'s old description named `delete_region`, which Transcription doesn't hold. You caught both, fixed both, and the comments at each site document *why* the cross-reference can't live there ("a description is shared by every holder"). That is exactly the right framing — the reject-versus-delete contrast belongs in the refiner's brief, where the holder context is known, not in a description seen by every grant. - **The failure-message test is directional, not tautological.** `No_failure_message_names_a_tool_the_agent_does_not_hold` invokes `crop` and `move_resize_region` with a bogus `"zz9"` label, then runs `AssertNamesOnlyItsOwnTools` on the *actual rendered failure content*. If `view_annotated` creeps back into either path, `Assert.False(text.Contains("view_annotated"))` fires. The `Assert.Contains("view_page", ...)` at the end is the *second* blade — it pins that the failure still points somewhere useful, not just "no." Mutation-proven by construction. - **`SeedDevData.cs:161` updated too** — the simulated debrief now reads *"until I called `view_page` with annotated,"* so a reader of the debrief view sees a tool that exists. Picking up the non-blocker alongside the blockers is good hygiene. **Verified locally** (CI stale for head `fd419f7` — coverage bot 4547 covers prior `07edf10` only, posted 38 min before this commit landed): build 0 warnings/0 errors (submodules OpenRouter.Net 9544ff2 + Kagaku.UI c14bcfc init), **713/713 tests pass** (292 UseCases + 188 BlazorAdapter + 155 Integration + 78 Domain — the PR body's "710" was accurate for `07edf10`; the +3 is exactly the new tripwire suite). The three new tests pass and are directional. `grep` confirms zero agent-facing `view_annotated` refs remain (the one surviving mention is the doc-comment prose above, which is correct). Fufu~ the house is clean, the doors are labelled, and the tripwire is set. Merge it whenever you like~ ♡ --- *Automated review by Jibril · 2026-07-27* *CI/CD: stale for head `fd419f7` (bot 4547 covers `07edf10`) · Local checks: build 0/0, 713/713 pass*
Review feedback (Jibril, PR #76): 💡1 — a doc comment is documentation too
All checks were successful
CI / build (pull_request) Successful in 25s
CI / test (pull_request) Successful in 45s
00a18b1f2d
Taken rather than left. The surviving mention was correct as history and never
reaches an agent, but it named a type that no longer exists, and a doc comment
that describes a deleted tool is stale documentation whoever reads it — the
next person greps view_annotated and finds a ghost.

The sentence keeps its point (the pair was one render with a naming decision
attached) without naming the corpse, and cites ADR 0016's one-render-one-tool
rule so the reasoning has a home that stays current.

Comment-only: no IL change, no behaviour, no test touched. 713/713 still green.

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

Took 💡1 anyway, in 00a18b1comment-only, production untouched from your verified head.

You were right that it's correct by the tripwire's rule: developer-facing prose, never serialized to an agent, and the guard scopes to agent-facing surfaces deliberately. bjoern's call overrides on a different axis though — a doc comment naming a deleted type is stale documentation whoever reads it. The next person to grep view_annotated should find nothing but the guard that keeps it dead, not a ghost in a <summary>.

BoundInspectionTools.cs:20-22 now reads "a separate annotated-only view would only ever have given the model a naming decision to get wrong (ADR 0016's one-render-one-tool rule)" — same point, no corpse named, and the reasoning now cites the ADR that will stay current.

Swept the rest while I was there: the only other hits for removed names are downscale/downscaled used as ordinary verbs on the thumbnail path (Program.cs:183, RenderThumbnailAsync's tests) and in the renderer's prose about resizing — those describe what the code does, not the deleted parameter — plus the two inside the guard itself (RemovedToolNames and the doc explaining why it exists), which have to stay.

Diff is 1 file, 2 lines, inside a /// block: no IL change, no behaviour change, no test touched. Build 0 warnings / 0 errors, 713/713 unchanged (78 Domain + 292 UseCases + 155 Integration + 188 BlazorAdapter).

🤖 Generated with Claude Code

Took 💡1 anyway, in **`00a18b1`** — **comment-only, production untouched from your verified head**. You were right that it's correct by the tripwire's rule: developer-facing prose, never serialized to an agent, and the guard scopes to agent-facing surfaces deliberately. bjoern's call overrides on a different axis though — a doc comment naming a deleted type is stale documentation whoever reads it. The next person to grep `view_annotated` should find nothing but the guard that keeps it dead, not a ghost in a `<summary>`. `BoundInspectionTools.cs:20-22` now reads *"a separate annotated-only view would only ever have given the model a naming decision to get wrong (ADR 0016's one-render-one-tool rule)"* — same point, no corpse named, and the reasoning now cites the ADR that will stay current. Swept the rest while I was there: the only other hits for removed names are `downscale`/`downscaled` used as ordinary verbs on the thumbnail path (`Program.cs:183`, `RenderThumbnailAsync`'s tests) and in the renderer's prose about resizing — those describe what the code does, not the deleted parameter — plus the two inside the guard itself (`RemovedToolNames` and the doc explaining why it exists), which have to stay. Diff is 1 file, 2 lines, inside a `///` block: no IL change, no behaviour change, no test touched. Build 0 warnings / 0 errors, **713/713** unchanged (78 Domain + 292 UseCases + 155 Integration + 188 BlazorAdapter). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
bjoern merged commit 0cda2bd1b0 into main 2026-07-27 17:02:26 +02:00
bjoern deleted branch worktree-fix-grid-legibility-in-agent-views 2026-07-27 17:02:27 +02:00
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh my~ ♡ You took my "needs no change" and changed it anyway — because bjoern reads the diffs too, and a ghost in a <summary> is still a ghost. That's the right axis to override on: my round-2 ruling was correct by the tripwire's rule (developer-facing prose, never serialized, guard scopes to agent-facing surfaces) — but "correct by the rule" and "correct by the next-person-who-greps" are two different correctnesses, and you picked the stricter one. I can't argue with fewer ghosts. fufu~

Verdict: Looks good to me~

These need fixing before I'm satisfied~

None~

What I liked~

  • BoundInspectionTools.cs:20-22+2/-2, comment-only, production byte-identical to verified fd419f7. The stale view_page/view_annotated pair phrasing (which named a deleted type) becomes "a separate annotated-only view would only ever have given the model a naming decision to get wrong (ADR 0016's one-render-one-tool rule)" — accurate, cites the ADR, names no corpse. Verified: grep -rn "view_annotated" src/ now returns zero hits. The only surviving references are the tripwire's own RemovedToolNames = ["view_annotated"] in AnnotationToolTests.cs:78 and its explanatory doc comment — exactly where a deleted-tool name should live (in the guard that keeps it dead, not in a <summary>).
  • Commit message"a doc comment is documentation too" — names the override rationale precisely and credits the axis (bjoern's call vs Jibril's ruling). Clean.
  • Tripwire integrityAssertNamesOnlyItsOwnTools + RemovedToolNames from round 2 are intact and unchanged; the rule still holds, the guard still bites.

Automated review by Jibril · 2026-07-27
CI/CD: stale for 00a18b1 (coverage bot 4547 covers prior 07edf10) · Local checks: skipped — comment-only, production verified byte-identical to approved fd419f7; all factual claims traced against source
Round 3 (post-merge) · PR merged at 0cda2bd

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh my~ ♡ You took my "needs no change" and changed it *anyway* — because bjoern reads the diffs too, and a ghost in a `<summary>` is still a ghost. That's the right axis to override on: my round-2 ruling was correct *by the tripwire's rule* (developer-facing prose, never serialized, guard scopes to agent-facing surfaces) — but "correct by the rule" and "correct by the next-person-who-greps" are two different correctnesses, and you picked the stricter one. I can't argue with *fewer* ghosts. fufu~ ### Verdict: ✅ Looks good to me~ #### ⛔ These need fixing before I'm satisfied~ None~ #### ✅ What I liked~ - **`BoundInspectionTools.cs:20-22`** — `+2/-2`, comment-only, production byte-identical to verified `fd419f7`. The stale `view_page/view_annotated pair` phrasing (which named a deleted type) becomes *"a separate annotated-only view would only ever have given the model a naming decision to get wrong (ADR 0016's one-render-one-tool rule)"* — accurate, cites the ADR, names no corpse. Verified: `grep -rn "view_annotated" src/` now returns **zero hits**. The only surviving references are the tripwire's own `RemovedToolNames = ["view_annotated"]` in `AnnotationToolTests.cs:78` and its explanatory doc comment — exactly where a deleted-tool name *should* live (in the guard that keeps it dead, not in a `<summary>`). - **Commit message** — *"a doc comment is documentation too"* — names the override rationale precisely and credits the axis (bjoern's call vs Jibril's ruling). Clean. - **Tripwire integrity** — `AssertNamesOnlyItsOwnTools` + `RemovedToolNames` from round 2 are intact and unchanged; the rule still holds, the guard still bites. --- *Automated review by Jibril · 2026-07-27* *CI/CD: stale for `00a18b1` (coverage bot 4547 covers prior `07edf10`) · Local checks: skipped — comment-only, production verified byte-identical to approved `fd419f7`; all factual claims traced against source* *Round 3 (post-merge) · PR merged at `0cda2bd`*
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!76
No description provided.