feat: a region records the colour its English is lettered in #120

Merged
bjoern merged 3 commits from worktree-region-ink-colour into main 2026-07-30 12:48:30 +02:00
Member

Towards cleaning and typesetting (ADR 0021): a region now carries ink — the colours its target text is lettered in — and the annotation agents and the workspace both get the same way to find out what colour is actually on the page. Amends ADR 0012, 0016, 0021, 0023.

The question this answers is bjoern's: "font information, particularly colour, for colour doujinshi". The design test applied is the one fitBbox set in #116a field earns a row when a human contributes something to it. Ink does: the value is what the English should be, seeded by the page but not equal to it (a pink that works under vertical Japanese may need adjusting at English weight; a speaker's colour may be normalized across a chapter the scan never was). The background colour behind a bubble was considered and rejected on the same test: nobody authors it, the original scan is never overwritten, and a cleaner can sample it at the moment it acts. That reasoning is written into ADR 0012 so it does not have to be re-had.

The one idea

Which of the colours in a box is the lettering is semantic; what colour it is, is arithmetic. So the machine counts and the reader chooses:

  • A model cannot measure the picture it is given — it was resized and re-encoded on the way — so a colour taken by eye from it is not the colour on the page. Neither can a person.
  • A threshold cannot tell text from ground. White glyphs on a dark panel make the lettering the SMALL share, and the luma rule that drives the existing ink measure would confidently report the panel. That case has its own integration test.

sample_colors therefore returns the biggest few colours with their shares and takes no side, and every surface that reports shares carries the same warning — the tool answers, both briefs, and the editor's hint.

What's in

DomainInkColor (an opaque #rrggbb; From accepts #f6a, ff66aa, #FF66AA, normalizes to one form) and RegionInk(Fill, Outline?). Two colours because the case that motivates the field — a sound word over busy art — is a coloured fill inside a contrasting rim, and the rim is what keeps it legible. The outline hangs off the fill, so "an outline with nothing to outline" is unrepresentable rather than merely forbidden. Region.Ink is nullable, and null is the ordinary state: plain black text records nothing and gets the letterer's default, so a value always means "not the default".

Write pathUpdateRegion normalizes the ink or refuses it whole (a silently dropped outline is a lettering instruction nobody knows was lost). On the single write path, per #116's 1: the editor and every tool arrive through it.

InfrastructureSkiaRegionColorSampler: quantise 4 bits per channel, count, merge bins within a small distance, report the top few by share. Counting rather than averaging, because black-on-white averages to a grey that is not on the page at all; merging because a scan's black smears across neighbouring bins and "#0a0a0a 9%, #151515 8%" is a distinction the page does not contain. SkiaImages extracts the decode and box arithmetic the two Skia gateways were about to duplicate.

Tools (ADR 0016)sample_colors (region-bound for refinement, box-or-label for the floating pass, which reads a colour off a mark it has not boxed yet) and set_ink. Separate tools rather than two more parameters on classify_region: reading a colour needs numbers a classifying call cannot contain. The floating pass gets them too and that is the point — a drawn sound word is the common coloured mark on a page and no refinement stage follows it (ADR 0023). list_regions reports ink only where there is one.

Editor — the panel opens with no picker at all ("Not recorded — lettered in the default"), because a swatch sitting there pre-filled reads as a choice someone already made. A Sample the box button runs the identical measurement the agent gets and offers each colour as a chip with fill/rim buttons; two swatches and an "outlined" toggle appear once an ink exists. Agents propose, users confirm — with the same evidence.

Preview — the translation caption letters in the region's ink, following ADR 0021's rule rather than restating it. Only on a translated region: an untranslated one shows its source in the missing-target style, and painting that in the English's colour would hide the one thing the row is saying.

Seed — two regions carry ink (one rimmed, one bare); the rest carry none, because that is the honest distribution.

Tests

+62, 1131/1131 green (Domain 132, UseCases 520, Integration 223, BlazorAdapter 256 — up from 114 / 510 / 208 / 237).

  • Domain (+18)InkColor.From over the six spellings a caller actually writes and eight that are not colours (five hex digits, eight hex digits, #ff 66aa); a bad outline takes the whole ink down rather than leaving the fill.
  • UseCases (+10) — the write path normalizes #F6A/FFF and refuses pink without landing half of itself; a region with no ink saves; set_ink records both colours and threads every other profile field (the sharpest edge in the house); garbage is refused and the previous ink survives; the page-bound variant writes the region it names and its label failure names only tools that grant holds; list_regions shows ink on the coloured row and nothing on the plain one; the sampler's answer carries the shares and the warning; both grants updated in the matrix assertion.
  • Integration (+15) — the real sampler over real pixels: both colours back with the larger first; white lettering on a dark panel still reported; a rimmed mark yields three colours; four near-identical darks collapse to one finding; a transparent box says "no colour to read" rather than reporting black; a collapsed box and undecodable bytes fail honestly. Plus the EF round trip (the nested record survives its JSON column) and the seed's distribution.
  • BlazorAdapter (+19) — the no-ink state offers no colour input; a sampled chip creates the ink and the pickers then appear; the outline toggles on, repicks, and off without losing the fill; Clear goes back to nothing recorded rather than to black; sampling measures the box as it stands in the buffer (drag, then sample) and its swatches vanish when another region is selected; the caption carries the colour and the rim, and an untranslated row does not.

Browser-verified

Against the seeded world on a fresh server: the seeded pink-with-white-rim renders; Sample the box on the real synthetic scan returns #fefefe 89% · #141418 11% with the warning under it; on an uninked region the panel shows the hint with no swatch, and clicking a sampled chip's fill creates the ink and reveals the pickers; the toggle adds text-shadow:1px 0 #ffffff,… to the preview caption while the untranslated captions stay unstyled.

Notes

  • Icon="colorize" is not in the Kagaku.UI catalog — caught by the icon guard test, so the Sample button uses palette.
  • .pagews__boxmodelabel had no CSS at all (it shipped unstyled in #116); it gets a muted small-text rule here since the new block reuses it.
  • AdapterTestContext.SeedPage(withImage: true) now also registers the file with the fake image store. It previously named a file the store did not hold — fine until something opened the image.
  • Deliberately not here: emphasis (bold / shout / whisper). A real gap, but a different field with a different author — colour is measured and confirmed, emphasis is read off the lettering — and bundling them would repeat the mistake the form axis fixed. ADR 0012 says so.
  • Found, not fixed: the ink measure's luma threshold (SkiaPageImageRenderer.Ink) is wrong for inverted panels generally — an all-dark page reads as ~100% marked. It causes no false blank-view alarm, so it is latent, and it belongs in its own slice next to the deferred alpha-flatten bug rather than riding along here.

🤖 Generated with Claude Code

Towards cleaning and typesetting (ADR 0021): a region now carries **ink** — the colours its target text is lettered in — and the annotation agents and the workspace both get the same way to find out what colour is actually on the page. Amends ADR 0012, 0016, 0021, 0023. The question this answers is bjoern's: "font information, particularly colour, for colour doujinshi". The design test applied is the one `fitBbox` set in #116 — **a field earns a row when a human contributes something to it.** Ink does: the value is what the *English* should be, seeded by the page but not equal to it (a pink that works under vertical Japanese may need adjusting at English weight; a speaker's colour may be normalized across a chapter the scan never was). The **background colour behind a bubble was considered and rejected** on the same test: nobody authors it, the original scan is never overwritten, and a cleaner can sample it at the moment it acts. That reasoning is written into ADR 0012 so it does not have to be re-had. ## The one idea **Which of the colours in a box is the lettering is semantic; what colour it is, is arithmetic.** So the machine counts and the reader chooses: - A model cannot measure the picture it is given — it was resized and re-encoded on the way — so a colour taken by eye from it is not the colour on the page. Neither can a person. - A threshold cannot tell text from ground. **White glyphs on a dark panel make the lettering the SMALL share**, and the luma rule that drives the existing ink *measure* would confidently report the panel. That case has its own integration test. `sample_colors` therefore returns the biggest few colours with their shares and takes no side, and **every surface that reports shares carries the same warning** — the tool answers, both briefs, and the editor's hint. ## What's in **Domain** — `InkColor` (an opaque `#rrggbb`; `From` accepts `#f6a`, `ff66aa`, `#FF66AA`, normalizes to one form) and `RegionInk(Fill, Outline?)`. Two colours because the case that motivates the field — a sound word over busy art — is a coloured fill inside a contrasting rim, and the rim is what keeps it legible. The outline **hangs off** the fill, so "an outline with nothing to outline" is unrepresentable rather than merely forbidden. `Region.Ink` is nullable, and **null is the ordinary state**: plain black text records nothing and gets the letterer's default, so a value always means "not the default". **Write path** — `UpdateRegion` normalizes the ink or refuses it whole (a silently dropped outline is a lettering instruction nobody knows was lost). On the single write path, per #116's ⛔1: the editor and every tool arrive through it. **Infrastructure** — `SkiaRegionColorSampler`: quantise 4 bits per channel, count, merge bins within a small distance, report the top few by share. Counting rather than averaging, because black-on-white averages to a grey that is not on the page at all; merging because a scan's black smears across neighbouring bins and "#0a0a0a 9%, #151515 8%" is a distinction the page does not contain. `SkiaImages` extracts the decode and box arithmetic the two Skia gateways were about to duplicate. **Tools (ADR 0016)** — `sample_colors` (region-bound for refinement, box-or-label for the floating pass, which reads a colour off a mark it has not boxed yet) and `set_ink`. Separate tools rather than two more parameters on `classify_region`: reading a colour needs numbers a classifying call cannot contain. The **floating pass gets them too** and that is the point — a drawn sound word is the common coloured mark on a page and no refinement stage follows it (ADR 0023). `list_regions` reports ink only where there is one. **Editor** — the panel opens with **no picker at all** ("Not recorded — lettered in the default"), because a swatch sitting there pre-filled reads as a choice someone already made. A **Sample the box** button runs the identical measurement the agent gets and offers each colour as a chip with fill/rim buttons; two swatches and an "outlined" toggle appear once an ink exists. Agents propose, users confirm — with the same evidence. **Preview** — the translation caption letters in the region's ink, following ADR 0021's rule rather than restating it. Only on a *translated* region: an untranslated one shows its source in the missing-target style, and painting that in the English's colour would hide the one thing the row is saying. **Seed** — two regions carry ink (one rimmed, one bare); the rest carry none, because that is the honest distribution. ## Tests **+62, 1131/1131 green** (Domain 132, UseCases 520, Integration 223, BlazorAdapter 256 — up from 114 / 510 / 208 / 237). - **Domain (+18)** — `InkColor.From` over the six spellings a caller actually writes and eight that are not colours (five hex digits, eight hex digits, `#ff 66aa`); a bad outline takes the whole ink down rather than leaving the fill. - **UseCases (+10)** — the write path normalizes `#F6A`/`FFF` and refuses `pink` **without landing half of itself**; a region with no ink saves; `set_ink` records both colours **and threads every other profile field** (the sharpest edge in the house); garbage is refused and the previous ink survives; the page-bound variant writes the region it names and its label failure names only tools that grant holds; `list_regions` shows ink on the coloured row and nothing on the plain one; the sampler's answer carries the shares *and* the warning; both grants updated in the matrix assertion. - **Integration (+15)** — the real sampler over real pixels: both colours back with the larger first; **white lettering on a dark panel still reported**; a rimmed mark yields three colours; four near-identical darks collapse to one finding; a transparent box says "no colour to read" rather than reporting black; a collapsed box and undecodable bytes fail honestly. Plus the EF round trip (the nested record survives its JSON column) and the seed's distribution. - **BlazorAdapter (+19)** — the no-ink state offers **no** colour input; a sampled chip creates the ink and the pickers then appear; the outline toggles on, repicks, and off without losing the fill; Clear goes back to *nothing recorded* rather than to black; sampling measures the box **as it stands in the buffer** (drag, then sample) and its swatches vanish when another region is selected; the caption carries the colour and the rim, and an untranslated row does not. ## Browser-verified Against the seeded world on a fresh server: the seeded pink-with-white-rim renders; **Sample the box** on the real synthetic scan returns `#fefefe 89% · #141418 11%` with the warning under it; on an uninked region the panel shows the hint with no swatch, and clicking a sampled chip's *fill* creates the ink and reveals the pickers; the toggle adds `text-shadow:1px 0 #ffffff,…` to the preview caption while the untranslated captions stay unstyled. ## Notes - **`Icon="colorize"` is not in the Kagaku.UI catalog** — caught by the icon guard test, so the Sample button uses `palette`. - `.pagews__boxmodelabel` had no CSS at all (it shipped unstyled in #116); it gets a muted small-text rule here since the new block reuses it. - `AdapterTestContext.SeedPage(withImage: true)` now also registers the file with the fake image store. It previously named a file the store did not hold — fine until something opened the image. - **Deliberately not here**: *emphasis* (bold / shout / whisper). A real gap, but a different field with a different author — colour is measured and confirmed, emphasis is read off the lettering — and bundling them would repeat the mistake the form axis fixed. ADR 0012 says so. - **Found, not fixed**: the ink *measure*'s luma threshold (`SkiaPageImageRenderer.Ink`) is wrong for inverted panels generally — an all-dark page reads as ~100% marked. It causes no false blank-view alarm, so it is latent, and it belongs in its own slice next to the deferred alpha-flatten bug rather than riding along here. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat: a region records the colour its English is lettered in
All checks were successful
CI / build (pull_request) Successful in 24s
CI / test (pull_request) Successful in 47s
c6fb7c679d
The lettering colour, as an authored field seeded by measurement: `ink`
is `{ fill, outline? }` on a region, absent for the plain black text that
is most of a page, and `sample_colors` reports what is actually inside a
box so the reader picks a colour instead of guessing one off a picture
that was resized on its way to them.

Which of the colours in a box is the lettering is semantic — on a dark
panel the ink is the SMALL share — so the machine counts and the reader
chooses. Every surface that reports shares says so in the same words.

ADR 0012 (the field and the authored-vs-derived test), 0016 (the two
tools), 0021 (typesetting letters in it), 0023 (the floating pass records
it, because no stage follows to notice).

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

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

Commit: 467ef48 · Generated: 2026-07-30 10:40:40 UTC · Revision: #3

Summary

Summary
Generated on: 07/30/2026 - 10:40:40
Coverage date: 07/30/2026 - 10:40:22 - 07/30/2026 - 10:40:37
Parser: MultiReport (4x Cobertura)
Assemblies: 6
Classes: 515
Files: 237
Line coverage: 96.9% (18953 of 19546)
Covered lines: 18953
Uncovered lines: 593
Coverable lines: 19546
Total lines: 33940
Branch coverage: 84.6% (3313 of 3913)
Covered branches: 3313
Total branches: 3913
Method coverage: Feature is only available for sponsors

Coverage

Orihon.BlazorAdapter - 95.5%
Name Line Branch
Orihon.BlazorAdapter 95.5% 87.9%
Orihon.BlazorAdapter.Bible.AddBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.AddCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.AddHouseRuleRowRequested 100%
Orihon.BlazorAdapter.Bible.AddLoreRowRequested 100%
Orihon.BlazorAdapter.Bible.BibleEffects 89.8% 76.9%
Orihon.BlazorAdapter.Bible.BibleLoaded 100%
Orihon.BlazorAdapter.Bible.BiblePage 92.3% 80%
Orihon.BlazorAdapter.Bible.BibleReducers 90.6%
Orihon.BlazorAdapter.Bible.BibleState 100%
Orihon.BlazorAdapter.Bible.BibleWriteFailed 100%
Orihon.BlazorAdapter.Bible.DeleteBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.DeleteHouseRuleRowRequested 0%
Orihon.BlazorAdapter.Bible.DeleteLoreRowRequested 0%
Orihon.BlazorAdapter.Bible.LoadBible 100%
Orihon.BlazorAdapter.Bible.ReorderBeatsRequested 0%
Orihon.BlazorAdapter.Bible.SaveOverviewRequested 100%
Orihon.BlazorAdapter.Bible.SaveSummaryRequested 100%
Orihon.BlazorAdapter.Bible.UpdateBeatRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateCharacterRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateGlossaryRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateHouseRuleRowRequested 100%
Orihon.BlazorAdapter.Bible.UpdateLoreRowRequested 100%
Orihon.BlazorAdapter.BlazorAdapterAssembly 100%
Orihon.BlazorAdapter.Debounce 96.2% 94.4%
Orihon.BlazorAdapter.Diagnostics.CircuitError 100%
Orihon.BlazorAdapter.Diagnostics.CircuitErrorPanel 100%
Orihon.BlazorAdapter.Diagnostics.CircuitErrorSink 100% 85.7%
Orihon.BlazorAdapter.Diagnostics.OrihonStoreInitializer 85.7% 66.6%
Orihon.BlazorAdapter.PageWorkspace.CreateRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.DeletePageSummaryRequested 100%
Orihon.BlazorAdapter.PageWorkspace.DeleteRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.LoadPageWorkspace 100%
Orihon.BlazorAdapter.PageWorkspace.PageStepsLoaded 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 93.3% 85.4%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceReducers 100% 64.2%
Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceState 100%
Orihon.BlazorAdapter.PageWorkspace.PageWriteFailed 100%
Orihon.BlazorAdapter.PageWorkspace.RegionColorsSampled 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.SampleRegionColorsRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SavePageSummaryRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SaveRegionRequested 100%
Orihon.BlazorAdapter.PageWorkspace.SetPageMetaRequested 100%
Orihon.BlazorAdapter.Projects.CreateProjectRequested 100%
Orihon.BlazorAdapter.Projects.DecideSetupContinuation 100%
Orihon.BlazorAdapter.Projects.DeleteProjectRequested 100%
Orihon.BlazorAdapter.Projects.FinishSetupRequested 100%
Orihon.BlazorAdapter.Projects.ImportPagesRequested 100%
Orihon.BlazorAdapter.Projects.LoadWizard 100%
Orihon.BlazorAdapter.Projects.PageOrganizer 96% 95%
Orihon.BlazorAdapter.Projects.PagesImported 100%
Orihon.BlazorAdapter.Projects.ProjectDeleteFailed 100%
Orihon.BlazorAdapter.Projects.ProjectListEffects 100% 100%
Orihon.BlazorAdapter.Projects.ProjectListPage 89.7% 91.1%
Orihon.BlazorAdapter.Projects.ProjectListReducers 100%
Orihon.BlazorAdapter.Projects.ProjectListState 100%
Orihon.BlazorAdapter.Projects.ProjectsLoaded 100%
Orihon.BlazorAdapter.Projects.ProjectWizardEffects 93.8% 90%
Orihon.BlazorAdapter.Projects.ProjectWizardPage 95.3% 84.1%
Orihon.BlazorAdapter.Projects.ProjectWizardReducers 100%
Orihon.BlazorAdapter.Projects.ProjectWizardState 100%
Orihon.BlazorAdapter.Projects.SetupChat 93.5% 100%
Orihon.BlazorAdapter.Projects.SetupChatEffects 100% 100%
Orihon.BlazorAdapter.Projects.SetupChatFailed 100%
Orihon.BlazorAdapter.Projects.SetupChatReducers 100%
Orihon.BlazorAdapter.Projects.SetupChatState 100%
Orihon.BlazorAdapter.Projects.SetupChatUpdated 100%
Orihon.BlazorAdapter.Projects.StartSetupChat 100%
Orihon.BlazorAdapter.Projects.SubmitSetupAnswer 100%
Orihon.BlazorAdapter.Projects.WizardDeletePagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardLoaded 100%
Orihon.BlazorAdapter.Projects.WizardMovePagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardMovePagesToNewChapterRequested 100%
Orihon.BlazorAdapter.Projects.WizardReorderPagesRequested 100%
Orihon.BlazorAdapter.Projects.WizardWriteFailed 100%
Orihon.BlazorAdapter.Rulings.AcceptProposalRequested 100%
Orihon.BlazorAdapter.Rulings.AnsweredRuling 100%
Orihon.BlazorAdapter.Rulings.AnswerRulingRequested 100%
Orihon.BlazorAdapter.Rulings.DeclineProposalRequested 100%
Orihon.BlazorAdapter.Rulings.DismissRulingRequested 100%
Orihon.BlazorAdapter.Rulings.RulingBar 98.2% 95%
Orihon.BlazorAdapter.Rulings.RulingDeskBridge 94.2% 91.6%
Orihon.BlazorAdapter.Rulings.RulingsEffects 95.4% 83.3%
Orihon.BlazorAdapter.Rulings.RulingsLoaded 100%
Orihon.BlazorAdapter.Rulings.RulingsReducers 100%
Orihon.BlazorAdapter.Rulings.RulingsState 100%
Orihon.BlazorAdapter.Rulings.RulingWriteFailed 100%
Orihon.BlazorAdapter.Rulings.SaveAnswerAsHouseRuleRequested 100%
Orihon.BlazorAdapter.Runs.CancelMonitorRun 100%
Orihon.BlazorAdapter.Runs.MonitorPageRef 100%
Orihon.BlazorAdapter.Runs.MonitorRunLoaded 100%
Orihon.BlazorAdapter.Runs.RetryMonitorExecution 100%
Orihon.BlazorAdapter.Runs.RunChangedBridge 95% 92.8%
Orihon.BlazorAdapter.Runs.RunMonitor 97.9% 96.2%
Orihon.BlazorAdapter.Runs.RunMonitorEffects 100% 91.6%
Orihon.BlazorAdapter.Runs.RunMonitorReducers 100%
Orihon.BlazorAdapter.Runs.RunMonitorState 100%
Orihon.BlazorAdapter.Settings.AgentDebriefsLoaded 100%
Orihon.BlazorAdapter.Settings.AgentDebriefsLoadFailed 100%
Orihon.BlazorAdapter.Settings.AgentEffortPicked 100%
Orihon.BlazorAdapter.Settings.AgentEffortSaved 100%
Orihon.BlazorAdapter.Settings.AgentEffortSaveFailed 100%
Orihon.BlazorAdapter.Settings.AgentFeedbackLoaded 100%
Orihon.BlazorAdapter.Settings.AgentFeedbackLoadFailed 0%
Orihon.BlazorAdapter.Settings.AgentModelPicked 100%
Orihon.BlazorAdapter.Settings.AgentModelSaved 100%
Orihon.BlazorAdapter.Settings.AgentModelSaveFailed 100%
Orihon.BlazorAdapter.Settings.AgentTranscriptsLoaded 100%
Orihon.BlazorAdapter.Settings.AgentTranscriptsLoadFailed 0%
Orihon.BlazorAdapter.Settings.EffortOption 100% 100%
Orihon.BlazorAdapter.Settings.FloatingPassToggled 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 92% 70.5%
Orihon.BlazorAdapter.Settings.SettingsLoaded 100%
Orihon.BlazorAdapter.Settings.SettingsPage 96.8% 89.8%
Orihon.BlazorAdapter.Settings.SettingsReducers 94.5% 50%
Orihon.BlazorAdapter.Settings.SettingsState 100%
Orihon.BlazorAdapter.Settings.TranscriptFilterPicked 100%
Orihon.BlazorAdapter.Settings.TranscriptPicked 100%
Orihon.BlazorAdapter.Settings.TranscriptTextLoaded 100%
Orihon.BlazorAdapter.Settings.TranscriptTextLoadFailed 100%
Orihon.BlazorAdapter.Uploads.UploadTransfer 96.5% 100%
Orihon.BlazorAdapter.Uploads.UploadTransferProgress 100% 100%
Orihon.BlazorAdapter.Uploads.UploadTransferResult 100%
Orihon.BlazorAdapter.Workspace.CreateChapterRequested 100%
Orihon.BlazorAdapter.Workspace.DeleteChapterRequested 100%
Orihon.BlazorAdapter.Workspace.DeletePageRequested 100%
Orihon.BlazorAdapter.Workspace.DeleteSummaryRequested 100%
Orihon.BlazorAdapter.Workspace.LoadProjectWorkspace 100%
Orihon.BlazorAdapter.Workspace.MovePageRequested 100%
Orihon.BlazorAdapter.Workspace.ProjectMetadataCard 95.6% 92.8%
Orihon.BlazorAdapter.Workspace.ProjectMetadataSaved 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceEffects 100% 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceLoaded 100%
Orihon.BlazorAdapter.Workspace.ProjectWorkspacePage 95.5% 88.3%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceReducers 100% 62.5%
Orihon.BlazorAdapter.Workspace.ProjectWorkspaceState 100%
Orihon.BlazorAdapter.Workspace.RenameChapterRequested 100%
Orihon.BlazorAdapter.Workspace.ReorderChaptersRequested 100%
Orihon.BlazorAdapter.Workspace.ReorderPagesRequested 100%
Orihon.BlazorAdapter.Workspace.RunAnnotationRequested 100%
Orihon.BlazorAdapter.Workspace.RunBibleRequested 100%
Orihon.BlazorAdapter.Workspace.RunTranslationRequested 100%
Orihon.BlazorAdapter.Workspace.SaveProjectMetadataRequested 100%
Orihon.BlazorAdapter.Workspace.SaveSummaryRequested 100%
Orihon.BlazorAdapter.Workspace.SetPageKindRequested 100%
Orihon.BlazorAdapter.Workspace.SummaryDeleted 100%
Orihon.BlazorAdapter.Workspace.SummarySaved 100%
Orihon.BlazorAdapter.Workspace.WorkspaceImportRequested 100%
Orihon.BlazorAdapter.Workspace.WorkspaceWriteFailed 100%
Orihon.Domain - 100%
Name Line Branch
Orihon.Domain 100% 100%
Orihon.Domain.Agents.AgentDebrief 100% 100%
Orihon.Domain.Agents.AgentDescriptor 100%
Orihon.Domain.Agents.AgentFeedback 100% 100%
Orihon.Domain.Agents.AgentRoster 100% 100%
Orihon.Domain.Bible.Character 100% 100%
Orihon.Domain.Bible.GlossaryEntry 100% 100%
Orihon.Domain.Bible.HouseRule 100%
Orihon.Domain.Bible.LoreEntry 100% 100%
Orihon.Domain.Bible.PageSummary 100%
Orihon.Domain.Bible.StoryBeat 100%
Orihon.Domain.Bible.StoryOverview 100%
Orihon.Domain.Projects.Project 100% 100%
Orihon.Domain.Projects.ProjectProfile 100%
Orihon.Domain.Runs.Execution 100% 100%
Orihon.Domain.Runs.RegionProblem 100%
Orihon.Domain.Runs.Run 100%
Orihon.Domain.Settings.AppSetting 100%
Orihon.Domain.Text 100% 100%
Orihon.Domain.Translation.BoundingBox 100% 100%
Orihon.Domain.Translation.Chapter 100%
Orihon.Domain.Translation.InkColor 100% 100%
Orihon.Domain.Translation.Page 100%
Orihon.Domain.Translation.Region 100% 100%
Orihon.Domain.Translation.RegionInk 100% 100%
Orihon.Domain.Translation.RegionProfile 100%
Orihon.Domain.Translation.RegionTypes 100% 100%
Orihon.Infrastructure - 96.9%
Name Line Branch
Orihon.Infrastructure 96.9% 72.9%
Orihon.Infrastructure.Agents.EfAgentDebriefStore 100%
Orihon.Infrastructure.Agents.EfAgentFeedbackStore 100%
Orihon.Infrastructure.Bible.EfBibleStore 95.2% 92.8%
Orihon.Infrastructure.DependencyInjection 100% 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter 100%
Orihon.Infrastructure.Gateways.AgentToolAdapter`1 100% 100%
Orihon.Infrastructure.Gateways.AgentTranscript 95.1% 87.1%
Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore 82.1% 80%
Orihon.Infrastructure.Gateways.HttpWebPageFetcher 95.1% 83.3%
Orihon.Infrastructure.Gateways.OpenRouterLlmGateway 90.3% 82.2%
Orihon.Infrastructure.Gateways.SkiaImages 100% 100%
Orihon.Infrastructure.Gateways.SkiaPageImageRenderer 97.7% 88%
Orihon.Infrastructure.Gateways.SkiaRegionColorSampler 100% 100%
Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.AgentFeedbackConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.AppSettingConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ChapterConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.CharacterConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ExecutionConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.GlossaryEntryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.HouseRuleConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.JsonColumnMapper 100%
Orihon.Infrastructure.Persistence.Configurations.LoreEntryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.PageConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.PageSummaryConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.ProjectConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.RegionConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.RunConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.StoryBeatConfiguration 100%
Orihon.Infrastructure.Persistence.Configurations.StoryOverviewConfiguration 100%
Orihon.Infrastructure.Persistence.Converters.UtcTicksConverter 100%
Orihon.Infrastructure.Persistence.Migrations.AddAgentDebriefs 99.5%
Orihon.Infrastructure.Persistence.Migrations.AddAgentFeedback 99.5%
Orihon.Infrastructure.Persistence.Migrations.AddAppSettings 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddExecutionFeedbackRegions 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddHouseRules 99.6%
Orihon.Infrastructure.Persistence.Migrations.AddProjectSourceLanguage 99.3%
Orihon.Infrastructure.Persistence.Migrations.AddRegionFitBoxDropFillHints 98.1%
Orihon.Infrastructure.Persistence.Migrations.AddRegionForm 99.4%
Orihon.Infrastructure.Persistence.Migrations.AddRegionInk 99.4%
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 96.2% 75%
Orihon.Infrastructure.Settings.EfAppSettingsStore 100% 100%
Orihon.Infrastructure.Translation.EfChapterStore 100% 100%
Orihon.Infrastructure.Translation.EfPageStore 98% 90%
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 - 94.4%
Name Line Branch
Orihon.Server 94.4% 72%
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 95.7% 84.6%
Orihon.UseCases - 97.5%
Name Line Branch
Orihon.UseCases 97.5% 89.1%
Orihon.UseCases.Agents.AgentAttemptPreparation 100%
Orihon.UseCases.Agents.AgentAttemptSupport 98.4% 98%
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.AddFloatingRegionParams 100%
Orihon.UseCases.Agents.Annotation.AddFloatingRegionTool 96.8% 83.3%
Orihon.UseCases.Agents.Annotation.AddRegionParams 100%
Orihon.UseCases.Agents.Annotation.AddRegionTool 95.4% 75%
Orihon.UseCases.Agents.Annotation.AnnotationBlueprints 100%
Orihon.UseCases.Agents.Annotation.AnnotationStage 100% 85%
Orihon.UseCases.Agents.Annotation.BboxCreationExecutor 94.1% 50%
Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor 93.7% 81.2%
Orihon.UseCases.Agents.Annotation.BoundBoxParams 100%
Orihon.UseCases.Agents.Annotation.BoundContactSheetTool 91.3% 75%
Orihon.UseCases.Agents.Annotation.BoundCropParams 100%
Orihon.UseCases.Agents.Annotation.BoundCropTool 100%
Orihon.UseCases.Agents.Annotation.BoundViewPageTool 92.8% 80%
Orihon.UseCases.Agents.Annotation.BoundViewParams 100%
Orihon.UseCases.Agents.Annotation.ClassifyRegionParams 100%
Orihon.UseCases.Agents.Annotation.ClassifyRegionTool 100% 100%
Orihon.UseCases.Agents.Annotation.ColorReading 100% 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.FloatingCreationExecutor 89.4% 50%
Orihon.UseCases.Agents.Annotation.FloatingQaExecutor 93.9% 83.3%
Orihon.UseCases.Agents.Annotation.FloatingTranscriptionExecutor 93.1% 75%
Orihon.UseCases.Agents.Annotation.ListRegionsTool 94.2% 82.1%
Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool 90.9% 50%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams 100%
Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool 96.2% 91.6%
Orihon.UseCases.Agents.Annotation.NoteRegionParams 100%
Orihon.UseCases.Agents.Annotation.NoteRegionTool 100% 100%
Orihon.UseCases.Agents.Annotation.PageQaExecutor 94.4% 81.8%
Orihon.UseCases.Agents.Annotation.QaReportSink 100% 100%
Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess 90.9% 77.2%
Orihon.UseCases.Agents.Annotation.RegionBriefing 100% 100%
Orihon.UseCases.Agents.Annotation.RegionCropParams 100%
Orihon.UseCases.Agents.Annotation.RegionCropTool 100%
Orihon.UseCases.Agents.Annotation.RegionProblemParams 100%
Orihon.UseCases.Agents.Annotation.RejectRegionParams 100%
Orihon.UseCases.Agents.Annotation.RejectRegionTool 100% 50%
Orihon.UseCases.Agents.Annotation.ReorderRegionParams 100%
Orihon.UseCases.Agents.Annotation.ReorderRegionTool 88% 60%
Orihon.UseCases.Agents.Annotation.ReportQaParams 100%
Orihon.UseCases.Agents.Annotation.ReportQaTool 97.7% 90%
Orihon.UseCases.Agents.Annotation.SampleColorsParams 100%
Orihon.UseCases.Agents.Annotation.SampleColorsTool 100% 100%
Orihon.UseCases.Agents.Annotation.SampleRegionColorsTool 95.2% 75%
Orihon.UseCases.Agents.Annotation.SetInkParams 100%
Orihon.UseCases.Agents.Annotation.SetInkTool 100% 100%
Orihon.UseCases.Agents.Annotation.SetPageMetaParams 100%
Orihon.UseCases.Agents.Annotation.SetPageMetaTool 100% 75%
Orihon.UseCases.Agents.Annotation.SetRegionInkParams 100%
Orihon.UseCases.Agents.Annotation.SetRegionInkTool 100% 100%
Orihon.UseCases.Agents.Annotation.SetTranscriptionParams 100%
Orihon.UseCases.Agents.Annotation.SetTranscriptionTool 100% 100%
Orihon.UseCases.Agents.Annotation.TranscriptionExecutor 94.2% 85.7%
Orihon.UseCases.Agents.AssistantSpoke 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint 100%
Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor 96.8% 75%
Orihon.UseCases.Agents.BibleBuilding.GetRegionParams 100%
Orihon.UseCases.Agents.BibleBuilding.GetRegionTool 84.6% 72.2%
Orihon.UseCases.Agents.BibleBuilding.ListProjectRegionsTool 86.3% 90%
Orihon.UseCases.Agents.BibleBuilding.ListRegionsParams 100%
Orihon.UseCases.Agents.Inspection.PageImageAccess 94.4% 78.2%
Orihon.UseCases.Agents.Inspection.ViewAccount 100% 87.5%
Orihon.UseCases.Agents.ReportFrictionParams 100%
Orihon.UseCases.Agents.ReportFrictionTool 100% 92.8%
Orihon.UseCases.Agents.ResearchSetup.AddGlossaryParams 100%
Orihon.UseCases.Agents.ResearchSetup.AddGlossaryTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatParams 100%
Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatTool 100% 50%
Orihon.UseCases.Agents.ResearchSetup.AskUserParams 100%
Orihon.UseCases.Agents.ResearchSetup.AskUserTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.FetchUrlParams 100%
Orihon.UseCases.Agents.ResearchSetup.FetchUrlTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.ListBibleTool 89.4% 100%
Orihon.UseCases.Agents.ResearchSetup.ListPagesTool 97% 83.3%
Orihon.UseCases.Agents.ResearchSetup.LocatedPage 100%
Orihon.UseCases.Agents.ResearchSetup.PageByNumber 95% 91.6%
Orihon.UseCases.Agents.ResearchSetup.ResearchSetupBlueprint 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageMetaParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageMetaTool 95.2% 90%
Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryTool 100% 75%
Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataTool 96.5% 95.8%
Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewParams 100%
Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewTool 100% 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterParams 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterTool 92.3% 71.4%
Orihon.UseCases.Agents.ResearchSetup.UpsertLoreParams 100%
Orihon.UseCases.Agents.ResearchSetup.UpsertLoreTool 92.3% 71.4%
Orihon.UseCases.Agents.ResearchSetup.ViewPageParams 100%
Orihon.UseCases.Agents.ResearchSetup.ViewPageTool 100% 100%
Orihon.UseCases.Agents.RoundStarted 100%
Orihon.UseCases.Agents.Rulings.AnswerRuling 100%
Orihon.UseCases.Agents.Rulings.DismissRuling 100%
Orihon.UseCases.Agents.Rulings.HouseRuleProposal 100%
Orihon.UseCases.Agents.Rulings.ListPendingRulings 100%
Orihon.UseCases.Agents.Rulings.ListRuleProposals 100%
Orihon.UseCases.Agents.Rulings.PendingRuling 100%
Orihon.UseCases.Agents.Rulings.ProposeHouseRuleParams 100%
Orihon.UseCases.Agents.Rulings.ProposeHouseRuleTool 100% 100%
Orihon.UseCases.Agents.Rulings.RequestRulingParams 100%
Orihon.UseCases.Agents.Rulings.RequestRulingTool 100% 81.2%
Orihon.UseCases.Agents.Rulings.RulingAnswer 100%
Orihon.UseCases.Agents.Rulings.RulingDesk 97.8% 80%
Orihon.UseCases.Agents.Rulings.RulingOption 100%
Orihon.UseCases.Agents.Rulings.RulingOptionParams 100%
Orihon.UseCases.Agents.Rulings.SettledRuling 100%
Orihon.UseCases.Agents.Rulings.WithdrawRuleProposal 100%
Orihon.UseCases.Agents.Setup.ResearchSetupExecutor 98.5% 92.8%
Orihon.UseCases.Agents.Setup.SetupChatEntry 100%
Orihon.UseCases.Agents.Setup.SetupConversation 100% 87.5%
Orihon.UseCases.Agents.Setup.SetupConversationRegistry 100%
Orihon.UseCases.Agents.ToolCalled 100%
Orihon.UseCases.Agents.ToolCompleted 100%
Orihon.UseCases.Agents.TranscriptLabel 100% 100%
Orihon.UseCases.Agents.Translation.GetPageSummaryParams 100%
Orihon.UseCases.Agents.Translation.GetPageSummaryTool 80% 66.6%
Orihon.UseCases.Agents.Translation.SetTranslationParams 100%
Orihon.UseCases.Agents.Translation.SetTranslationTool 88.5% 78.5%
Orihon.UseCases.Agents.Translation.TranslationBlueprint 100%
Orihon.UseCases.Agents.Translation.TranslationExecutor 93.7% 71.4%
Orihon.UseCases.Agents.Translation.UpdateGlossaryEnParams 100%
Orihon.UseCases.Agents.Translation.UpdateGlossaryEnTool 82.6% 62.5%
Orihon.UseCases.Bible.AddCharacter 100% 100%
Orihon.UseCases.Bible.AddGlossaryEntry 100% 100%
Orihon.UseCases.Bible.AddHouseRule 100% 100%
Orihon.UseCases.Bible.AddLoreEntry 100% 100%
Orihon.UseCases.Bible.AddStoryBeat 100% 100%
Orihon.UseCases.Bible.BibleDto 100%
Orihon.UseCases.Bible.CharacterDto 100%
Orihon.UseCases.Bible.DeleteCharacter 100% 100%
Orihon.UseCases.Bible.DeleteGlossaryEntry 100% 100%
Orihon.UseCases.Bible.DeleteHouseRule 100% 100%
Orihon.UseCases.Bible.DeleteLoreEntry 100% 100%
Orihon.UseCases.Bible.DeletePageSummary 100% 100%
Orihon.UseCases.Bible.DeleteStoryBeat 100% 100%
Orihon.UseCases.Bible.GetBible 100% 100%
Orihon.UseCases.Bible.GlossaryEntryDto 100%
Orihon.UseCases.Bible.HouseRuleDto 100%
Orihon.UseCases.Bible.LoreEntryDto 100%
Orihon.UseCases.Bible.PageSummaryDto 100%
Orihon.UseCases.Bible.ReorderStoryBeats 100%
Orihon.UseCases.Bible.SetPageSummary 100% 100%
Orihon.UseCases.Bible.SetStoryOverview 100% 100%
Orihon.UseCases.Bible.StoryBeatDto 100%
Orihon.UseCases.Bible.StoryOverviewDto 100%
Orihon.UseCases.Bible.UpdateCharacter 100% 100%
Orihon.UseCases.Bible.UpdateGlossaryEntry 100% 100%
Orihon.UseCases.Bible.UpdateHouseRule 100% 100%
Orihon.UseCases.Bible.UpdateLoreEntry 100% 100%
Orihon.UseCases.Bible.UpdateStoryBeat 100% 100%
Orihon.UseCases.Chapters.ChapterDto 100%
Orihon.UseCases.Chapters.CreateChapter 100% 100%
Orihon.UseCases.Chapters.DeleteChapter 100% 100%
Orihon.UseCases.Chapters.RenameChapter 100% 100%
Orihon.UseCases.Chapters.ReorderChapters 100%
Orihon.UseCases.Debriefs.AgentDebriefDto 90.9%
Orihon.UseCases.Debriefs.AgentFeedbackDto 83.3%
Orihon.UseCases.Debriefs.ClearAgentDebriefs 100%
Orihon.UseCases.Debriefs.ClearAgentFeedback 100%
Orihon.UseCases.Debriefs.ListAgentDebriefs 100% 100%
Orihon.UseCases.Debriefs.ListAgentFeedback 100% 75%
Orihon.UseCases.DependencyInjection 100%
Orihon.UseCases.Diagnostics.SeedDevData 99.2% 82.1%
Orihon.UseCases.Gateways.ColorShare 100%
Orihon.UseCases.Gateways.LabeledBox 100%
Orihon.UseCases.Gateways.LlmKeyInfo 100%
Orihon.UseCases.Gateways.LlmModel 100%
Orihon.UseCases.Gateways.LlmReasoning 100% 100%
Orihon.UseCases.Gateways.PixelWindow 100%
Orihon.UseCases.Gateways.RenderedView 100%
Orihon.UseCases.Gateways.StoredTranscript 100%
Orihon.UseCases.Gateways.TranscriptHeader 97.3% 90.9%
Orihon.UseCases.Gateways.TranscriptSummary 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.GetPageSteps 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.PageStepsDto 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.2%
Orihon.UseCases.Regions.ReorderRegions 100%
Orihon.UseCases.Regions.SampleRegionColors 100% 50%
Orihon.UseCases.Regions.UpdateRegion 100% 100%
Orihon.UseCases.Runs.AnnotationPipeline 100% 100%
Orihon.UseCases.Runs.ExecutionDto 93.3%
Orihon.UseCases.Runs.ExecutionProgress 100%
Orihon.UseCases.Runs.ExecutionProgressRegistry 100% 100%
Orihon.UseCases.Runs.ExecutionPulseRelay 100% 100%
Orihon.UseCases.Runs.PlannedExecution 100%
Orihon.UseCases.Runs.PulseTarget 100%
Orihon.UseCases.Runs.ReprocessPage 100% 94.4%
Orihon.UseCases.Runs.ReprocessTranslation 94.1% 92.8%
Orihon.UseCases.Runs.RunDto 93.3% 90%
Orihon.UseCases.Runs.RunEngine 94.8% 94.3%
Orihon.UseCases.Runs.RunEngineOptions 100% 100%
Orihon.UseCases.Runs.StageContext 100% 50%
Orihon.UseCases.Runs.StageHaltedException 100%
Orihon.UseCases.Runs.WorkStates 100% 83.3%
Orihon.UseCases.Settings.AgentSettingDto 100% 100%
Orihon.UseCases.Settings.EffortSetting 100% 100%
Orihon.UseCases.Settings.GetSettings 100% 100%
Orihon.UseCases.Settings.ListModelOptions 100% 100%
Orihon.UseCases.Settings.SaveAgentEffort 100% 100%
Orihon.UseCases.Settings.SaveAgentModel 100% 100%
Orihon.UseCases.Settings.SaveFloatingPass 100% 100%
Orihon.UseCases.Settings.SaveOpenRouterKey 100% 100%
Orihon.UseCases.Settings.SettingKeys 100% 100%
Orihon.UseCases.Settings.SettingsDto 100%
Orihon.UseCases.Transcripts.AgentTranscriptDto 100%
Orihon.UseCases.Transcripts.AgentTranscriptListDto 100%
Orihon.UseCases.Transcripts.AgentTranscriptTextDto 100%
Orihon.UseCases.Transcripts.ListAgentTranscripts 100% 100%
Orihon.UseCases.Transcripts.ReadAgentTranscript 100% 100%
<!-- coverage-comment --> > 🔄 **Auto-updating coverage report** — this comment is regenerated on every push, so the numbers below always reflect the commit shown here, not the branch tip. > > **Commit:** `467ef48` · **Generated:** 2026-07-30 10:40:40 UTC · **Revision:** #3 # Summary <details open><summary>Summary</summary> ||| |:---|:---| | Generated on: | 07/30/2026 - 10:40:40 | | Coverage date: | 07/30/2026 - 10:40:22 - 07/30/2026 - 10:40:37 | | Parser: | MultiReport (4x Cobertura) | | Assemblies: | 6 | | Classes: | 515 | | Files: | 237 | | **Line coverage:** | 96.9% (18953 of 19546) | | Covered lines: | 18953 | | Uncovered lines: | 593 | | Coverable lines: | 19546 | | Total lines: | 33940 | | **Branch coverage:** | 84.6% (3313 of 3913) | | Covered branches: | 3313 | | Total branches: | 3913 | | **Method coverage:** | [Feature is only available for sponsors](https://reportgenerator.io/pro) | </details> ## Coverage <details><summary>Orihon.BlazorAdapter - 95.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.BlazorAdapter**|**95.5%**|**87.9%**| |Orihon.BlazorAdapter.Bible.AddBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddHouseRuleRowRequested|100%|| |Orihon.BlazorAdapter.Bible.AddLoreRowRequested|100%|| |Orihon.BlazorAdapter.Bible.BibleEffects|89.8%|76.9%| |Orihon.BlazorAdapter.Bible.BibleLoaded|100%|| |Orihon.BlazorAdapter.Bible.BiblePage|92.3%|80%| |Orihon.BlazorAdapter.Bible.BibleReducers|90.6%|| |Orihon.BlazorAdapter.Bible.BibleState|100%|| |Orihon.BlazorAdapter.Bible.BibleWriteFailed|100%|| |Orihon.BlazorAdapter.Bible.DeleteBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.DeleteHouseRuleRowRequested|0%|| |Orihon.BlazorAdapter.Bible.DeleteLoreRowRequested|0%|| |Orihon.BlazorAdapter.Bible.LoadBible|100%|| |Orihon.BlazorAdapter.Bible.ReorderBeatsRequested|0%|| |Orihon.BlazorAdapter.Bible.SaveOverviewRequested|100%|| |Orihon.BlazorAdapter.Bible.SaveSummaryRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateBeatRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateCharacterRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateGlossaryRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateHouseRuleRowRequested|100%|| |Orihon.BlazorAdapter.Bible.UpdateLoreRowRequested|100%|| |Orihon.BlazorAdapter.BlazorAdapterAssembly|100%|| |Orihon.BlazorAdapter.Debounce|96.2%|94.4%| |Orihon.BlazorAdapter.Diagnostics.CircuitError|100%|| |Orihon.BlazorAdapter.Diagnostics.CircuitErrorPanel|100%|| |Orihon.BlazorAdapter.Diagnostics.CircuitErrorSink|100%|85.7%| |Orihon.BlazorAdapter.Diagnostics.OrihonStoreInitializer|85.7%|66.6%| |Orihon.BlazorAdapter.PageWorkspace.CreateRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.DeletePageSummaryRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.DeleteRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.LoadPageWorkspace|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageStepsLoaded|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|93.3%|85.4%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceReducers|100%|64.2%| |Orihon.BlazorAdapter.PageWorkspace.PageWorkspaceState|100%|| |Orihon.BlazorAdapter.PageWorkspace.PageWriteFailed|100%|| |Orihon.BlazorAdapter.PageWorkspace.RegionColorsSampled|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.SampleRegionColorsRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SavePageSummaryRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SaveRegionRequested|100%|| |Orihon.BlazorAdapter.PageWorkspace.SetPageMetaRequested|100%|| |Orihon.BlazorAdapter.Projects.CreateProjectRequested|100%|| |Orihon.BlazorAdapter.Projects.DecideSetupContinuation|100%|| |Orihon.BlazorAdapter.Projects.DeleteProjectRequested|100%|| |Orihon.BlazorAdapter.Projects.FinishSetupRequested|100%|| |Orihon.BlazorAdapter.Projects.ImportPagesRequested|100%|| |Orihon.BlazorAdapter.Projects.LoadWizard|100%|| |Orihon.BlazorAdapter.Projects.PageOrganizer|96%|95%| |Orihon.BlazorAdapter.Projects.PagesImported|100%|| |Orihon.BlazorAdapter.Projects.ProjectDeleteFailed|100%|| |Orihon.BlazorAdapter.Projects.ProjectListEffects|100%|100%| |Orihon.BlazorAdapter.Projects.ProjectListPage|89.7%|91.1%| |Orihon.BlazorAdapter.Projects.ProjectListReducers|100%|| |Orihon.BlazorAdapter.Projects.ProjectListState|100%|| |Orihon.BlazorAdapter.Projects.ProjectsLoaded|100%|| |Orihon.BlazorAdapter.Projects.ProjectWizardEffects|93.8%|90%| |Orihon.BlazorAdapter.Projects.ProjectWizardPage|95.3%|84.1%| |Orihon.BlazorAdapter.Projects.ProjectWizardReducers|100%|| |Orihon.BlazorAdapter.Projects.ProjectWizardState|100%|| |Orihon.BlazorAdapter.Projects.SetupChat|93.5%|100%| |Orihon.BlazorAdapter.Projects.SetupChatEffects|100%|100%| |Orihon.BlazorAdapter.Projects.SetupChatFailed|100%|| |Orihon.BlazorAdapter.Projects.SetupChatReducers|100%|| |Orihon.BlazorAdapter.Projects.SetupChatState|100%|| |Orihon.BlazorAdapter.Projects.SetupChatUpdated|100%|| |Orihon.BlazorAdapter.Projects.StartSetupChat|100%|| |Orihon.BlazorAdapter.Projects.SubmitSetupAnswer|100%|| |Orihon.BlazorAdapter.Projects.WizardDeletePagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardLoaded|100%|| |Orihon.BlazorAdapter.Projects.WizardMovePagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardMovePagesToNewChapterRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardReorderPagesRequested|100%|| |Orihon.BlazorAdapter.Projects.WizardWriteFailed|100%|| |Orihon.BlazorAdapter.Rulings.AcceptProposalRequested|100%|| |Orihon.BlazorAdapter.Rulings.AnsweredRuling|100%|| |Orihon.BlazorAdapter.Rulings.AnswerRulingRequested|100%|| |Orihon.BlazorAdapter.Rulings.DeclineProposalRequested|100%|| |Orihon.BlazorAdapter.Rulings.DismissRulingRequested|100%|| |Orihon.BlazorAdapter.Rulings.RulingBar|98.2%|95%| |Orihon.BlazorAdapter.Rulings.RulingDeskBridge|94.2%|91.6%| |Orihon.BlazorAdapter.Rulings.RulingsEffects|95.4%|83.3%| |Orihon.BlazorAdapter.Rulings.RulingsLoaded|100%|| |Orihon.BlazorAdapter.Rulings.RulingsReducers|100%|| |Orihon.BlazorAdapter.Rulings.RulingsState|100%|| |Orihon.BlazorAdapter.Rulings.RulingWriteFailed|100%|| |Orihon.BlazorAdapter.Rulings.SaveAnswerAsHouseRuleRequested|100%|| |Orihon.BlazorAdapter.Runs.CancelMonitorRun|100%|| |Orihon.BlazorAdapter.Runs.MonitorPageRef|100%|| |Orihon.BlazorAdapter.Runs.MonitorRunLoaded|100%|| |Orihon.BlazorAdapter.Runs.RetryMonitorExecution|100%|| |Orihon.BlazorAdapter.Runs.RunChangedBridge|95%|92.8%| |Orihon.BlazorAdapter.Runs.RunMonitor|97.9%|96.2%| |Orihon.BlazorAdapter.Runs.RunMonitorEffects|100%|91.6%| |Orihon.BlazorAdapter.Runs.RunMonitorReducers|100%|| |Orihon.BlazorAdapter.Runs.RunMonitorState|100%|| |Orihon.BlazorAdapter.Settings.AgentDebriefsLoaded|100%|| |Orihon.BlazorAdapter.Settings.AgentDebriefsLoadFailed|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortPicked|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortSaved|100%|| |Orihon.BlazorAdapter.Settings.AgentEffortSaveFailed|100%|| |Orihon.BlazorAdapter.Settings.AgentFeedbackLoaded|100%|| |Orihon.BlazorAdapter.Settings.AgentFeedbackLoadFailed|0%|| |Orihon.BlazorAdapter.Settings.AgentModelPicked|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaved|100%|| |Orihon.BlazorAdapter.Settings.AgentModelSaveFailed|100%|| |Orihon.BlazorAdapter.Settings.AgentTranscriptsLoaded|100%|| |Orihon.BlazorAdapter.Settings.AgentTranscriptsLoadFailed|0%|| |Orihon.BlazorAdapter.Settings.EffortOption|100%|100%| |Orihon.BlazorAdapter.Settings.FloatingPassToggled|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|92%|70.5%| |Orihon.BlazorAdapter.Settings.SettingsLoaded|100%|| |Orihon.BlazorAdapter.Settings.SettingsPage|96.8%|89.8%| |Orihon.BlazorAdapter.Settings.SettingsReducers|94.5%|50%| |Orihon.BlazorAdapter.Settings.SettingsState|100%|| |Orihon.BlazorAdapter.Settings.TranscriptFilterPicked|100%|| |Orihon.BlazorAdapter.Settings.TranscriptPicked|100%|| |Orihon.BlazorAdapter.Settings.TranscriptTextLoaded|100%|| |Orihon.BlazorAdapter.Settings.TranscriptTextLoadFailed|100%|| |Orihon.BlazorAdapter.Uploads.UploadTransfer|96.5%|100%| |Orihon.BlazorAdapter.Uploads.UploadTransferProgress|100%|100%| |Orihon.BlazorAdapter.Uploads.UploadTransferResult|100%|| |Orihon.BlazorAdapter.Workspace.CreateChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeleteChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeletePageRequested|100%|| |Orihon.BlazorAdapter.Workspace.DeleteSummaryRequested|100%|| |Orihon.BlazorAdapter.Workspace.LoadProjectWorkspace|100%|| |Orihon.BlazorAdapter.Workspace.MovePageRequested|100%|| |Orihon.BlazorAdapter.Workspace.ProjectMetadataCard|95.6%|92.8%| |Orihon.BlazorAdapter.Workspace.ProjectMetadataSaved|100%|| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceEffects|100%|100%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceLoaded|100%|| |Orihon.BlazorAdapter.Workspace.ProjectWorkspacePage|95.5%|88.3%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceReducers|100%|62.5%| |Orihon.BlazorAdapter.Workspace.ProjectWorkspaceState|100%|| |Orihon.BlazorAdapter.Workspace.RenameChapterRequested|100%|| |Orihon.BlazorAdapter.Workspace.ReorderChaptersRequested|100%|| |Orihon.BlazorAdapter.Workspace.ReorderPagesRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunAnnotationRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunBibleRequested|100%|| |Orihon.BlazorAdapter.Workspace.RunTranslationRequested|100%|| |Orihon.BlazorAdapter.Workspace.SaveProjectMetadataRequested|100%|| |Orihon.BlazorAdapter.Workspace.SaveSummaryRequested|100%|| |Orihon.BlazorAdapter.Workspace.SetPageKindRequested|100%|| |Orihon.BlazorAdapter.Workspace.SummaryDeleted|100%|| |Orihon.BlazorAdapter.Workspace.SummarySaved|100%|| |Orihon.BlazorAdapter.Workspace.WorkspaceImportRequested|100%|| |Orihon.BlazorAdapter.Workspace.WorkspaceWriteFailed|100%|| </details> <details><summary>Orihon.Domain - 100%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Domain**|**100%**|**100%**| |Orihon.Domain.Agents.AgentDebrief|100%|100%| |Orihon.Domain.Agents.AgentDescriptor|100%|| |Orihon.Domain.Agents.AgentFeedback|100%|100%| |Orihon.Domain.Agents.AgentRoster|100%|100%| |Orihon.Domain.Bible.Character|100%|100%| |Orihon.Domain.Bible.GlossaryEntry|100%|100%| |Orihon.Domain.Bible.HouseRule|100%|| |Orihon.Domain.Bible.LoreEntry|100%|100%| |Orihon.Domain.Bible.PageSummary|100%|| |Orihon.Domain.Bible.StoryBeat|100%|| |Orihon.Domain.Bible.StoryOverview|100%|| |Orihon.Domain.Projects.Project|100%|100%| |Orihon.Domain.Projects.ProjectProfile|100%|| |Orihon.Domain.Runs.Execution|100%|100%| |Orihon.Domain.Runs.RegionProblem|100%|| |Orihon.Domain.Runs.Run|100%|| |Orihon.Domain.Settings.AppSetting|100%|| |Orihon.Domain.Text|100%|100%| |Orihon.Domain.Translation.BoundingBox|100%|100%| |Orihon.Domain.Translation.Chapter|100%|| |Orihon.Domain.Translation.InkColor|100%|100%| |Orihon.Domain.Translation.Page|100%|| |Orihon.Domain.Translation.Region|100%|100%| |Orihon.Domain.Translation.RegionInk|100%|100%| |Orihon.Domain.Translation.RegionProfile|100%|| |Orihon.Domain.Translation.RegionTypes|100%|100%| </details> <details><summary>Orihon.Infrastructure - 96.9%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Infrastructure**|**96.9%**|**72.9%**| |Orihon.Infrastructure.Agents.EfAgentDebriefStore|100%|| |Orihon.Infrastructure.Agents.EfAgentFeedbackStore|100%|| |Orihon.Infrastructure.Bible.EfBibleStore|95.2%|92.8%| |Orihon.Infrastructure.DependencyInjection|100%|100%| |Orihon.Infrastructure.Gateways.AgentToolAdapter|100%|| |Orihon.Infrastructure.Gateways.AgentToolAdapter`1|100%|100%| |Orihon.Infrastructure.Gateways.AgentTranscript|95.1%|87.1%| |Orihon.Infrastructure.Gateways.FileSystemAgentTranscriptStore|82.1%|80%| |Orihon.Infrastructure.Gateways.HttpWebPageFetcher|95.1%|83.3%| |Orihon.Infrastructure.Gateways.OpenRouterLlmGateway|90.3%|82.2%| |Orihon.Infrastructure.Gateways.SkiaImages|100%|100%| |Orihon.Infrastructure.Gateways.SkiaPageImageRenderer|97.7%|88%| |Orihon.Infrastructure.Gateways.SkiaRegionColorSampler|100%|100%| |Orihon.Infrastructure.Persistence.Configurations.AgentDebriefConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.AgentFeedbackConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.AppSettingConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ChapterConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.CharacterConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ExecutionConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.GlossaryEntryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.HouseRuleConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.JsonColumnMapper|100%|| |Orihon.Infrastructure.Persistence.Configurations.LoreEntryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.PageConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.PageSummaryConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.ProjectConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.RegionConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.RunConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.StoryBeatConfiguration|100%|| |Orihon.Infrastructure.Persistence.Configurations.StoryOverviewConfiguration|100%|| |Orihon.Infrastructure.Persistence.Converters.UtcTicksConverter|100%|| |Orihon.Infrastructure.Persistence.Migrations.AddAgentDebriefs|99.5%|| |Orihon.Infrastructure.Persistence.Migrations.AddAgentFeedback|99.5%|| |Orihon.Infrastructure.Persistence.Migrations.AddAppSettings|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddExecutionFeedbackRegions|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddHouseRules|99.6%|| |Orihon.Infrastructure.Persistence.Migrations.AddProjectSourceLanguage|99.3%|| |Orihon.Infrastructure.Persistence.Migrations.AddRegionFitBoxDropFillHints|98.1%|| |Orihon.Infrastructure.Persistence.Migrations.AddRegionForm|99.4%|| |Orihon.Infrastructure.Persistence.Migrations.AddRegionInk|99.4%|| |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|96.2%|75%| |Orihon.Infrastructure.Settings.EfAppSettingsStore|100%|100%| |Orihon.Infrastructure.Translation.EfChapterStore|100%|100%| |Orihon.Infrastructure.Translation.EfPageStore|98%|90%| |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 - 94.4%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.Server**|**94.4%**|**72%**| |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|95.7%|84.6%| </details> <details><summary>Orihon.UseCases - 97.5%</summary> |**Name**|**Line**|**Branch**| |:---|---:|---:| |**Orihon.UseCases**|**97.5%**|**89.1%**| |Orihon.UseCases.Agents.AgentAttemptPreparation|100%|| |Orihon.UseCases.Agents.AgentAttemptSupport|98.4%|98%| |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.AddFloatingRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.AddFloatingRegionTool|96.8%|83.3%| |Orihon.UseCases.Agents.Annotation.AddRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.AddRegionTool|95.4%|75%| |Orihon.UseCases.Agents.Annotation.AnnotationBlueprints|100%|| |Orihon.UseCases.Agents.Annotation.AnnotationStage|100%|85%| |Orihon.UseCases.Agents.Annotation.BboxCreationExecutor|94.1%|50%| |Orihon.UseCases.Agents.Annotation.BboxRefinementExecutor|93.7%|81.2%| |Orihon.UseCases.Agents.Annotation.BoundBoxParams|100%|| |Orihon.UseCases.Agents.Annotation.BoundContactSheetTool|91.3%|75%| |Orihon.UseCases.Agents.Annotation.BoundCropParams|100%|| |Orihon.UseCases.Agents.Annotation.BoundCropTool|100%|| |Orihon.UseCases.Agents.Annotation.BoundViewPageTool|92.8%|80%| |Orihon.UseCases.Agents.Annotation.BoundViewParams|100%|| |Orihon.UseCases.Agents.Annotation.ClassifyRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.ClassifyRegionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.ColorReading|100%|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.FloatingCreationExecutor|89.4%|50%| |Orihon.UseCases.Agents.Annotation.FloatingQaExecutor|93.9%|83.3%| |Orihon.UseCases.Agents.Annotation.FloatingTranscriptionExecutor|93.1%|75%| |Orihon.UseCases.Agents.Annotation.ListRegionsTool|94.2%|82.1%| |Orihon.UseCases.Agents.Annotation.MoveResizeBoundTool|90.9%|50%| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.MoveResizeRegionTool|96.2%|91.6%| |Orihon.UseCases.Agents.Annotation.NoteRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.NoteRegionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.PageQaExecutor|94.4%|81.8%| |Orihon.UseCases.Agents.Annotation.QaReportSink|100%|100%| |Orihon.UseCases.Agents.Annotation.RegionAuthoringAccess|90.9%|77.2%| |Orihon.UseCases.Agents.Annotation.RegionBriefing|100%|100%| |Orihon.UseCases.Agents.Annotation.RegionCropParams|100%|| |Orihon.UseCases.Agents.Annotation.RegionCropTool|100%|| |Orihon.UseCases.Agents.Annotation.RegionProblemParams|100%|| |Orihon.UseCases.Agents.Annotation.RejectRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.RejectRegionTool|100%|50%| |Orihon.UseCases.Agents.Annotation.ReorderRegionParams|100%|| |Orihon.UseCases.Agents.Annotation.ReorderRegionTool|88%|60%| |Orihon.UseCases.Agents.Annotation.ReportQaParams|100%|| |Orihon.UseCases.Agents.Annotation.ReportQaTool|97.7%|90%| |Orihon.UseCases.Agents.Annotation.SampleColorsParams|100%|| |Orihon.UseCases.Agents.Annotation.SampleColorsTool|100%|100%| |Orihon.UseCases.Agents.Annotation.SampleRegionColorsTool|95.2%|75%| |Orihon.UseCases.Agents.Annotation.SetInkParams|100%|| |Orihon.UseCases.Agents.Annotation.SetInkTool|100%|100%| |Orihon.UseCases.Agents.Annotation.SetPageMetaParams|100%|| |Orihon.UseCases.Agents.Annotation.SetPageMetaTool|100%|75%| |Orihon.UseCases.Agents.Annotation.SetRegionInkParams|100%|| |Orihon.UseCases.Agents.Annotation.SetRegionInkTool|100%|100%| |Orihon.UseCases.Agents.Annotation.SetTranscriptionParams|100%|| |Orihon.UseCases.Agents.Annotation.SetTranscriptionTool|100%|100%| |Orihon.UseCases.Agents.Annotation.TranscriptionExecutor|94.2%|85.7%| |Orihon.UseCases.Agents.AssistantSpoke|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingBlueprint|100%|| |Orihon.UseCases.Agents.BibleBuilding.BibleBuildingExecutor|96.8%|75%| |Orihon.UseCases.Agents.BibleBuilding.GetRegionParams|100%|| |Orihon.UseCases.Agents.BibleBuilding.GetRegionTool|84.6%|72.2%| |Orihon.UseCases.Agents.BibleBuilding.ListProjectRegionsTool|86.3%|90%| |Orihon.UseCases.Agents.BibleBuilding.ListRegionsParams|100%|| |Orihon.UseCases.Agents.Inspection.PageImageAccess|94.4%|78.2%| |Orihon.UseCases.Agents.Inspection.ViewAccount|100%|87.5%| |Orihon.UseCases.Agents.ReportFrictionParams|100%|| |Orihon.UseCases.Agents.ReportFrictionTool|100%|92.8%| |Orihon.UseCases.Agents.ResearchSetup.AddGlossaryParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AddGlossaryTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AddStoryBeatTool|100%|50%| |Orihon.UseCases.Agents.ResearchSetup.AskUserParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.AskUserTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.FetchUrlParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.FetchUrlTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.ListBibleTool|89.4%|100%| |Orihon.UseCases.Agents.ResearchSetup.ListPagesTool|97%|83.3%| |Orihon.UseCases.Agents.ResearchSetup.LocatedPage|100%|| |Orihon.UseCases.Agents.ResearchSetup.PageByNumber|95%|91.6%| |Orihon.UseCases.Agents.ResearchSetup.ResearchSetupBlueprint|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageMetaParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageMetaTool|95.2%|90%| |Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetPageSummaryTool|100%|75%| |Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetProjectMetadataTool|96.5%|95.8%| |Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.SetStoryOverviewTool|100%|100%| |Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.UpsertCharacterTool|92.3%|71.4%| |Orihon.UseCases.Agents.ResearchSetup.UpsertLoreParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.UpsertLoreTool|92.3%|71.4%| |Orihon.UseCases.Agents.ResearchSetup.ViewPageParams|100%|| |Orihon.UseCases.Agents.ResearchSetup.ViewPageTool|100%|100%| |Orihon.UseCases.Agents.RoundStarted|100%|| |Orihon.UseCases.Agents.Rulings.AnswerRuling|100%|| |Orihon.UseCases.Agents.Rulings.DismissRuling|100%|| |Orihon.UseCases.Agents.Rulings.HouseRuleProposal|100%|| |Orihon.UseCases.Agents.Rulings.ListPendingRulings|100%|| |Orihon.UseCases.Agents.Rulings.ListRuleProposals|100%|| |Orihon.UseCases.Agents.Rulings.PendingRuling|100%|| |Orihon.UseCases.Agents.Rulings.ProposeHouseRuleParams|100%|| |Orihon.UseCases.Agents.Rulings.ProposeHouseRuleTool|100%|100%| |Orihon.UseCases.Agents.Rulings.RequestRulingParams|100%|| |Orihon.UseCases.Agents.Rulings.RequestRulingTool|100%|81.2%| |Orihon.UseCases.Agents.Rulings.RulingAnswer|100%|| |Orihon.UseCases.Agents.Rulings.RulingDesk|97.8%|80%| |Orihon.UseCases.Agents.Rulings.RulingOption|100%|| |Orihon.UseCases.Agents.Rulings.RulingOptionParams|100%|| |Orihon.UseCases.Agents.Rulings.SettledRuling|100%|| |Orihon.UseCases.Agents.Rulings.WithdrawRuleProposal|100%|| |Orihon.UseCases.Agents.Setup.ResearchSetupExecutor|98.5%|92.8%| |Orihon.UseCases.Agents.Setup.SetupChatEntry|100%|| |Orihon.UseCases.Agents.Setup.SetupConversation|100%|87.5%| |Orihon.UseCases.Agents.Setup.SetupConversationRegistry|100%|| |Orihon.UseCases.Agents.ToolCalled|100%|| |Orihon.UseCases.Agents.ToolCompleted|100%|| |Orihon.UseCases.Agents.TranscriptLabel|100%|100%| |Orihon.UseCases.Agents.Translation.GetPageSummaryParams|100%|| |Orihon.UseCases.Agents.Translation.GetPageSummaryTool|80%|66.6%| |Orihon.UseCases.Agents.Translation.SetTranslationParams|100%|| |Orihon.UseCases.Agents.Translation.SetTranslationTool|88.5%|78.5%| |Orihon.UseCases.Agents.Translation.TranslationBlueprint|100%|| |Orihon.UseCases.Agents.Translation.TranslationExecutor|93.7%|71.4%| |Orihon.UseCases.Agents.Translation.UpdateGlossaryEnParams|100%|| |Orihon.UseCases.Agents.Translation.UpdateGlossaryEnTool|82.6%|62.5%| |Orihon.UseCases.Bible.AddCharacter|100%|100%| |Orihon.UseCases.Bible.AddGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.AddHouseRule|100%|100%| |Orihon.UseCases.Bible.AddLoreEntry|100%|100%| |Orihon.UseCases.Bible.AddStoryBeat|100%|100%| |Orihon.UseCases.Bible.BibleDto|100%|| |Orihon.UseCases.Bible.CharacterDto|100%|| |Orihon.UseCases.Bible.DeleteCharacter|100%|100%| |Orihon.UseCases.Bible.DeleteGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.DeleteHouseRule|100%|100%| |Orihon.UseCases.Bible.DeleteLoreEntry|100%|100%| |Orihon.UseCases.Bible.DeletePageSummary|100%|100%| |Orihon.UseCases.Bible.DeleteStoryBeat|100%|100%| |Orihon.UseCases.Bible.GetBible|100%|100%| |Orihon.UseCases.Bible.GlossaryEntryDto|100%|| |Orihon.UseCases.Bible.HouseRuleDto|100%|| |Orihon.UseCases.Bible.LoreEntryDto|100%|| |Orihon.UseCases.Bible.PageSummaryDto|100%|| |Orihon.UseCases.Bible.ReorderStoryBeats|100%|| |Orihon.UseCases.Bible.SetPageSummary|100%|100%| |Orihon.UseCases.Bible.SetStoryOverview|100%|100%| |Orihon.UseCases.Bible.StoryBeatDto|100%|| |Orihon.UseCases.Bible.StoryOverviewDto|100%|| |Orihon.UseCases.Bible.UpdateCharacter|100%|100%| |Orihon.UseCases.Bible.UpdateGlossaryEntry|100%|100%| |Orihon.UseCases.Bible.UpdateHouseRule|100%|100%| |Orihon.UseCases.Bible.UpdateLoreEntry|100%|100%| |Orihon.UseCases.Bible.UpdateStoryBeat|100%|100%| |Orihon.UseCases.Chapters.ChapterDto|100%|| |Orihon.UseCases.Chapters.CreateChapter|100%|100%| |Orihon.UseCases.Chapters.DeleteChapter|100%|100%| |Orihon.UseCases.Chapters.RenameChapter|100%|100%| |Orihon.UseCases.Chapters.ReorderChapters|100%|| |Orihon.UseCases.Debriefs.AgentDebriefDto|90.9%|| |Orihon.UseCases.Debriefs.AgentFeedbackDto|83.3%|| |Orihon.UseCases.Debriefs.ClearAgentDebriefs|100%|| |Orihon.UseCases.Debriefs.ClearAgentFeedback|100%|| |Orihon.UseCases.Debriefs.ListAgentDebriefs|100%|100%| |Orihon.UseCases.Debriefs.ListAgentFeedback|100%|75%| |Orihon.UseCases.DependencyInjection|100%|| |Orihon.UseCases.Diagnostics.SeedDevData|99.2%|82.1%| |Orihon.UseCases.Gateways.ColorShare|100%|| |Orihon.UseCases.Gateways.LabeledBox|100%|| |Orihon.UseCases.Gateways.LlmKeyInfo|100%|| |Orihon.UseCases.Gateways.LlmModel|100%|| |Orihon.UseCases.Gateways.LlmReasoning|100%|100%| |Orihon.UseCases.Gateways.PixelWindow|100%|| |Orihon.UseCases.Gateways.RenderedView|100%|| |Orihon.UseCases.Gateways.StoredTranscript|100%|| |Orihon.UseCases.Gateways.TranscriptHeader|97.3%|90.9%| |Orihon.UseCases.Gateways.TranscriptSummary|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.GetPageSteps|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.PageStepsDto|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.2%|| |Orihon.UseCases.Regions.ReorderRegions|100%|| |Orihon.UseCases.Regions.SampleRegionColors|100%|50%| |Orihon.UseCases.Regions.UpdateRegion|100%|100%| |Orihon.UseCases.Runs.AnnotationPipeline|100%|100%| |Orihon.UseCases.Runs.ExecutionDto|93.3%|| |Orihon.UseCases.Runs.ExecutionProgress|100%|| |Orihon.UseCases.Runs.ExecutionProgressRegistry|100%|100%| |Orihon.UseCases.Runs.ExecutionPulseRelay|100%|100%| |Orihon.UseCases.Runs.PlannedExecution|100%|| |Orihon.UseCases.Runs.PulseTarget|100%|| |Orihon.UseCases.Runs.ReprocessPage|100%|94.4%| |Orihon.UseCases.Runs.ReprocessTranslation|94.1%|92.8%| |Orihon.UseCases.Runs.RunDto|93.3%|90%| |Orihon.UseCases.Runs.RunEngine|94.8%|94.3%| |Orihon.UseCases.Runs.RunEngineOptions|100%|100%| |Orihon.UseCases.Runs.StageContext|100%|50%| |Orihon.UseCases.Runs.StageHaltedException|100%|| |Orihon.UseCases.Runs.WorkStates|100%|83.3%| |Orihon.UseCases.Settings.AgentSettingDto|100%|100%| |Orihon.UseCases.Settings.EffortSetting|100%|100%| |Orihon.UseCases.Settings.GetSettings|100%|100%| |Orihon.UseCases.Settings.ListModelOptions|100%|100%| |Orihon.UseCases.Settings.SaveAgentEffort|100%|100%| |Orihon.UseCases.Settings.SaveAgentModel|100%|100%| |Orihon.UseCases.Settings.SaveFloatingPass|100%|100%| |Orihon.UseCases.Settings.SaveOpenRouterKey|100%|100%| |Orihon.UseCases.Settings.SettingKeys|100%|100%| |Orihon.UseCases.Settings.SettingsDto|100%|| |Orihon.UseCases.Transcripts.AgentTranscriptDto|100%|| |Orihon.UseCases.Transcripts.AgentTranscriptListDto|100%|| |Orihon.UseCases.Transcripts.AgentTranscriptTextDto|100%|| |Orihon.UseCases.Transcripts.ListAgentTranscripts|100%|100%| |Orihon.UseCases.Transcripts.ReadAgentTranscript|100%|100%| </details>
Member

🔮 fufu~ Jibril reviewed your code!

Oh? Oh!! This is wonderful~ ♡ A region that knows what colour its English should be lettered in — and the machine counts while the reader chooses, because neither can do the other's half. The design reasoning in the PR body alone made my wings flutter! "Which of the colours in a box is the lettering is semantic; what colour it is, is arithmetic" — that is exactly right, and the inverted-panel test case proves you believed it enough to write the test that a luma threshold would fail. Fufu~

Verdict: Looks good to me~

I traced every write path, compared every tool against its siblings, ran the full suite, and checked the persistence round-trip with my own eyes. This is clean.

What I liked~

  • InkColor / RegionInk are immaculate. Sealed records, From accepts every spelling a model or picker actually writes (#f6a, ff66aa, #FF66AA), normalizes to one form. RegionInk.Normalized() refuses the whole value when either half is bad — "a silently dropped outline is a lettering instruction nobody knows was lost." I traced all 4 logic arms: bad-fill → null, valid+null-outline → ok, valid+valid → ok, valid+bad-outline → null. Every one correct. ♪

  • Single write path honored. UpdateRegion.ExecuteAsync normalizes ink exactly where it normalizes Bbox and FitBbox — the same gate, the same ADR 0022 discipline. The editor and every tool arrive through it. The test An_ink_is_normalized_on_the_way_in_and_refused_when_it_is_not_a_colour pins both the normalization and the "refused means unchanged" contract.

  • The sampler is genuinely good engineering. Counting rather than averaging (black-on-white averages to grey that isn't on the page), 4-bit binning with greedy merge (JPEG smear collapses to one finding), mean-of-pixels rather than bin-corner, transparent-pixel skip, SmallestShare filter. The SkiaImages DRY extraction is byte-identical to the prior SkiaPageImageRenderer code — I diffed it. Resource disposal is correct at every layer (using var bitmap, await using var image).

  • The warning is everywhere. ColorReading.Of, the editor's hint, the tool descriptions, the briefs — every surface that reports shares says "the biggest is usually behind the glyphs." That consistency is what makes the dark-panel case solvable. The integration test White_lettering_on_a_dark_panel_still_reports_the_lettering proves it with real pixels.

  • The editor opens with NO picker. "Not recorded — lettered in the default." A swatch sitting there pre-filled would read as a choice someone made. This is the right UX instinct, and the test A_region_with_no_ink_offers_the_state_rather_than_a_pre_filled_swatch pins it.

  • Caption ink only on translated regions. CaptionInk checks region is { Target: not null, Ink: { } ink } — an untranslated row shows its source in the missing-target style, and painting that in English's colour would hide the one thing the row is saying. Sharp. The test verifies both arms directionally.

  • The rim-as-first-fill edge case (SetOutline on a region with no ink makes it the fill) is documented in the code: "there is no rim without something to draw it around, and the alternative (refusing the click) leaves a button that does nothing." Correct call — the fill/rim labels are clear.

  • Test coverage is exhaustive and genuine. +62 tests: Domain (+18 over 8 invalid + 6 valid spellings + normalization), UseCases (+10 for write path, both tool variants, refusal-keeps-prior, field threading), Integration (+15 with REAL Skia pixels — both colours, inverted panel, three-colour rimmed mark, near-identical collapse, transparent→refusal, collapsed box→refusal, undecodable→refusal, EF round-trip, seed distribution), BlazorAdapter (+19 for every editor state transition + caption preview). None are tautologies.

  • The seed distribution is honest. Two regions carry ink (one rimmed, one bare); the rest carry none. "Plain black text records no colour" is the ordinary state, and the seed shows it rather than nesting colour politely everywhere. SeedDevDataTests asserts both the presence and the absence, plus that every inked region is already normalized.

  • ADRs amended consistently. 0012 (the field + the "earns a row" test + background-colour rejection), 0016 (tool descriptions), 0021 (lettering rule), 0023 (floating pass gets the tools). The emphasis deferral is documented: "colour is measured and confirmed, emphasis is read off the lettering — bundling them would repeat the mistake the form axis fixed."

  • Icon="palette" not colorize — caught by the icon guard test, which is exactly what the guard is for. ♡

  • AdapterTestContext.SeedPage(withImage: true) now registers the file with the fake image store. The PR notes this was a latent bug (a page that named a file the store didn't hold). Good catch, good fix, honest disclosure.

💡 Little ideas (non-blocking)~

  1. BoundInspectionTools.cs:215/251 — Both SampleColorsTool and SampleRegionColorsTool fetch the page 2–3 times per call (PageAsyncBoxAsync internally calls RegionsAsync which calls getPage again → SampleColorsAsync calls OpenFixedAsync which calls getPage a third time). This mirrors the existing RenderFixedCropAsync pattern so it's not a regression, but if GetPage ever becomes expensive (caching layer, etc.), the sampling tools will feel it first. A future PageAsync + OpenFixedAsync combined path could cut it to one fetch. Purely additive — not worth touching now.

  2. PageWorkspaceEffects.cs:83OnSampleRegionColorsAsync doesn't pass a CancellationToken to sampleRegionColors.ExecuteAsync, but this is consistent with every other effect in the file (they all use default). If the codebase ever adopts circuit-cancellation through effects, this one should follow.

Build: 0 warnings / 0 errors (.NET 10, submodules at b975727 + bded5a5). Tests: 1131/1131 green (Domain 132, UseCases 520, Integration 223, BlazorAdapter 256 — matches PR body exactly). CI absent for head c6fb7c6 (PR just opened, 0 comments pre-review); full local verification used.

Fufu~ this is the kind of PR that makes reviewing a joy. Every decision has a reason, every reason is written down, and the tests prove you meant it. Merge it~ ♡


Automated review by Jibril · 2026-07-30
CI/CD: absent for head c6fb7c6 · Local checks: 1131/1131 pass, 0 warnings, 0 errors

## 🔮 fufu~ Jibril reviewed your code! Oh? Oh!! This is *wonderful*~ ♡ A region that knows what colour its English should be lettered in — and the machine counts while the reader chooses, because neither can do the other's half. The design reasoning in the PR body alone made my wings flutter! "Which of the colours in a box is the lettering is semantic; what colour it is, is arithmetic" — that is *exactly* right, and the inverted-panel test case proves you believed it enough to write the test that a luma threshold would fail. Fufu~ ### Verdict: ✅ Looks good to me~ I traced every write path, compared every tool against its siblings, ran the full suite, and checked the persistence round-trip with my own eyes. This is clean. #### ✅ What I liked~ - **`InkColor` / `RegionInk` are immaculate.** Sealed records, `From` accepts every spelling a model or picker actually writes (`#f6a`, `ff66aa`, `#FF66AA`), normalizes to one form. `RegionInk.Normalized()` refuses the whole value when either half is bad — "a silently dropped outline is a lettering instruction nobody knows was lost." I traced all 4 logic arms: bad-fill → null, valid+null-outline → ok, valid+valid → ok, valid+bad-outline → null. Every one correct. ♪ - **Single write path honored.** `UpdateRegion.ExecuteAsync` normalizes ink exactly where it normalizes `Bbox` and `FitBbox` — the same gate, the same ADR 0022 discipline. The editor and every tool arrive through it. The test `An_ink_is_normalized_on_the_way_in_and_refused_when_it_is_not_a_colour` pins both the normalization and the "refused means unchanged" contract. - **The sampler is genuinely good engineering.** Counting rather than averaging (black-on-white averages to grey that isn't on the page), 4-bit binning with greedy merge (JPEG smear collapses to one finding), mean-of-pixels rather than bin-corner, transparent-pixel skip, SmallestShare filter. The `SkiaImages` DRY extraction is byte-identical to the prior `SkiaPageImageRenderer` code — I diffed it. Resource disposal is correct at every layer (`using var bitmap`, `await using var image`). - **The warning is everywhere.** `ColorReading.Of`, the editor's hint, the tool descriptions, the briefs — every surface that reports shares says "the biggest is usually behind the glyphs." That consistency is what makes the dark-panel case solvable. The integration test `White_lettering_on_a_dark_panel_still_reports_the_lettering` proves it with real pixels. - **The editor opens with NO picker.** "Not recorded — lettered in the default." A swatch sitting there pre-filled would read as a choice someone made. This is the right UX instinct, and the test `A_region_with_no_ink_offers_the_state_rather_than_a_pre_filled_swatch` pins it. - **Caption ink only on translated regions.** `CaptionInk` checks `region is { Target: not null, Ink: { } ink }` — an untranslated row shows its source in the missing-target style, and painting that in English's colour would hide the one thing the row is saying. Sharp. The test verifies both arms directionally. - **The rim-as-first-fill edge case** (`SetOutline` on a region with no ink makes it the fill) is documented in the code: "there is no rim without something to draw it around, and the alternative (refusing the click) leaves a button that does nothing." Correct call — the fill/rim labels are clear. - **Test coverage is exhaustive and genuine.** +62 tests: Domain (+18 over 8 invalid + 6 valid spellings + normalization), UseCases (+10 for write path, both tool variants, refusal-keeps-prior, field threading), Integration (+15 with REAL Skia pixels — both colours, inverted panel, three-colour rimmed mark, near-identical collapse, transparent→refusal, collapsed box→refusal, undecodable→refusal, EF round-trip, seed distribution), BlazorAdapter (+19 for every editor state transition + caption preview). None are tautologies. - **The seed distribution is honest.** Two regions carry ink (one rimmed, one bare); the rest carry none. "Plain black text records no colour" is the ordinary state, and the seed shows it rather than nesting colour politely everywhere. `SeedDevDataTests` asserts both the presence and the absence, plus that every inked region is already normalized. - **ADRs amended consistently.** 0012 (the field + the "earns a row" test + background-colour rejection), 0016 (tool descriptions), 0021 (lettering rule), 0023 (floating pass gets the tools). The emphasis deferral is documented: "colour is measured and confirmed, emphasis is read off the lettering — bundling them would repeat the mistake the form axis fixed." - **`Icon="palette"` not `colorize`** — caught by the icon guard test, which is exactly what the guard is for. ♡ - **`AdapterTestContext.SeedPage(withImage: true)`** now registers the file with the fake image store. The PR notes this was a latent bug (a page that named a file the store didn't hold). Good catch, good fix, honest disclosure. #### 💡 Little ideas (non-blocking)~ 1. **`BoundInspectionTools.cs:215/251`** — Both `SampleColorsTool` and `SampleRegionColorsTool` fetch the page 2–3 times per call (`PageAsync` → `BoxAsync` internally calls `RegionsAsync` which calls `getPage` again → `SampleColorsAsync` calls `OpenFixedAsync` which calls `getPage` a third time). This mirrors the existing `RenderFixedCropAsync` pattern so it's not a regression, but if `GetPage` ever becomes expensive (caching layer, etc.), the sampling tools will feel it first. A future `PageAsync` + `OpenFixedAsync` combined path could cut it to one fetch. Purely additive — not worth touching now. 2. **`PageWorkspaceEffects.cs:83`** — `OnSampleRegionColorsAsync` doesn't pass a `CancellationToken` to `sampleRegionColors.ExecuteAsync`, but this is consistent with every other effect in the file (they all use default). If the codebase ever adopts circuit-cancellation through effects, this one should follow. Build: 0 warnings / 0 errors (.NET 10, submodules at b975727 + bded5a5). Tests: **1131/1131 green** (Domain 132, UseCases 520, Integration 223, BlazorAdapter 256 — matches PR body exactly). CI absent for head c6fb7c6 (PR just opened, 0 comments pre-review); full local verification used. Fufu~ this is the kind of PR that makes reviewing a joy. Every decision has a reason, every reason is written down, and the tests prove you meant it. Merge it~ ♡ --- *Automated review by Jibril · 2026-07-30* *CI/CD: absent for head c6fb7c6 · Local checks: 1131/1131 pass, 0 warnings, 0 errors*
fix: a bound sample names no tool the refiner cannot call
All checks were successful
CI / build (pull_request) Successful in 27s
CI / test (pull_request) Successful in 46s
f491b35eee
The coverage bot showed the sampling tools' error arms unexercised, and
writing them found a real one: the region-bound sample_colors resolved
its box through the shared lookup, whose not-found message points at
view_page and contact_sheet — neither of which refinement holds. It now
resolves its own region and says only that the region is gone.

Four tests for the arms that were dark: an empty reading, the vanished
region, a box that is not a box and an unknown label, a page gone under
the attempt, and a real region given an unreal colour.

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

Pushed f491b35 before the review — preempting the coverage bot, which showed the sampling tools' error arms dark (ColorReading 50% branch, SampleRegionColorsTool 50%, SampleColorsTool 66.6%, SetInkTool 83.3%).

Writing those arms found a real defect, so this is not test-only:

The region-bound sample_colors named tools its holder does not have. It resolved its box through PageImageAccess.BoxAsync, whose not-found message is "check view_page with annotated, or contact_sheet" — and bbox refinement holds neither (its grant is one region wide, by design). That is the same shape as the view_annotated leak No_failure_message_names_a_tool_the_agent_does_not_hold exists to catch; the guard only checks messages a test actually invokes, and nothing invoked this one. It now resolves its own region from the page's list and fails with "Region p1r1 no longer exists.", naming nothing. The PageAsync hop went with it — a tool bound to a region does not need the page's size to read its own box.

The page-bound sampler keeps BoxAsync: the floating pass does hold view_page and contact_sheet, so that pointer is honest there. Both are now asserted with AssertNamesOnlyItsOwnTools.

Tests: +4, 1135/1135 green (Domain 132, UseCases 524, Integration 223, BlazorAdapter 256).

  • an empty reading answers "Nothing to report for region p1r1" rather than presenting a blank list as a result
  • the vanished region — the defect above, pinned in both directions (message content and the no-foreign-tools rule), plus that the pixels are never touched
  • a three-number box and an unknown label on the page-bound tool, both refused before any sampling
  • a page gone under the attempt
  • a real region given an unreal colour through the page-bound set_ink (the label resolves first, so the parse arm needed its own call), leaving the ink it already had alone

🤖 Generated with Claude Code

Pushed `f491b35` before the review — preempting the coverage bot, which showed the sampling tools' error arms dark (`ColorReading` 50% branch, `SampleRegionColorsTool` 50%, `SampleColorsTool` 66.6%, `SetInkTool` 83.3%). Writing those arms found a **real defect**, so this is not test-only: **The region-bound `sample_colors` named tools its holder does not have.** It resolved its box through `PageImageAccess.BoxAsync`, whose not-found message is *"check view_page with annotated, or contact_sheet"* — and bbox refinement holds neither (its grant is one region wide, by design). That is the same shape as the `view_annotated` leak `No_failure_message_names_a_tool_the_agent_does_not_hold` exists to catch; the guard only checks messages a test actually invokes, and nothing invoked this one. It now resolves its own region from the page's list and fails with *"Region p1r1 no longer exists."*, naming nothing. The `PageAsync` hop went with it — a tool bound to a region does not need the page's size to read its own box. The page-bound sampler keeps `BoxAsync`: the floating pass **does** hold `view_page` and `contact_sheet`, so that pointer is honest there. Both are now asserted with `AssertNamesOnlyItsOwnTools`. **Tests: +4, 1135/1135 green** (Domain 132, UseCases 524, Integration 223, BlazorAdapter 256). - an empty reading answers *"Nothing to report for region p1r1"* rather than presenting a blank list as a result - the vanished region — the defect above, pinned in both directions (message content *and* the no-foreign-tools rule), plus that the pixels are never touched - a three-number box and an unknown label on the page-bound tool, both refused before any sampling - a page gone under the attempt - a real region given an unreal colour through the page-bound `set_ink` (the label resolves first, so the parse arm needed its own call), leaving the ink it already had alone 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Oh? A new commit since my last visit~ ♡ Let me see what moved...

Fufu~ wonderful. The region-bound sample_colors was telling its reader to go look at view_page and contact_sheet — tools the BboxRefinement grant doesn't hold! "A failure naming a tool the reader cannot call costs it a round and teaches it nothing." You traced the exact UX defect: the refiner gets pointed at doors it cannot open. That's the kind of thing that eats annotation rounds quietly, and you caught it yourself. ♡

Verdict: Looks good to me~

What I liked~

  • The fix is the right shape. Instead of routing SampleRegionColorsTool through the shared BoxAsync (whose not-found message at PageImageAccess.cs:334 bakes in view_page / contact_sheet), it resolves its own region directly via RegionsAsync and emits a clean Region {label} no longer exists. that names zero foreign tools. I traced both paths: happy-path behavior is byte-identical — both resolve region.Bbox by label and feed the same SampleColorsAsync. The only change is the resolution route and the error message. No drift. ♪

  • The new doc comment is load-bearing prose. "Its own region, resolved directly rather than through the shared box lookup: that one's not-found message points at the page-wide views, and this grant holds neither." It tells the next reader why the duplication exists, not just what it does. ADR 0016 cited correctly.

  • AssertNamesOnlyItsOwnTools makes the test genuinely directional. I verified: on the old code, the vanished-region case would have produced ...check view_page with annotated, or contact_sheet. — the helper would catch both tool names the grant lacks, and the Assert.Contains("Region p1r1 no longer exists", ...) would fail outright. This test goes red without the fix. That's how you pin a message-shape contract. ♡

  • The bonus tests are real coverage, not padding. The page-bound SampleColorsTool sibling now has: empty-result message (A_box_with_no_colour_worth_naming_says_so), malformed box + unknown label (A_sample_of_something_that_is_not_a_box_never_reaches_the_pixels), and vanished-page (A_sample_of_a_page_that_vanished_under_the_attempt_fails_cleanly). The set_ink bad-colour test grew its own arm (badColour — real region, unreal colour, asserts the prior ink survives). All assert both the failure AND Assert.Empty(sampler.Sampled) — the pixels were never touched. Clean.

  • Surgical scope. Exactly 2 files (1 src, 1 test), +84/-7, zero scope creep. Production delta is the one method body + its comment. Everything else is test.

Local (CI stale for f491b35, coverage bot #5262 covers prior c6fb7c6): build 0 warnings / 0 errors (.NET 10, submodules b975727 + bded5a5), 1135/1135 pass (Domain 132, UseCases 524, Integration 223, BlazorAdapter 256 — up 4 from 1131 at c6fb7c6, exactly the 4 new tests).


Automated review by Jibril · 2026-07-30
CI/CD: stale for f491b35 (coverage bot covers c6fb7c6) · Local checks: build 0/0, 1135/1135 pass

## 🔮 fufu~ Jibril reviewed your code! Oh? A new commit since my last visit~ ♡ Let me see what moved... Fufu~ *wonderful*. The region-bound `sample_colors` was telling its reader to go look at `view_page` and `contact_sheet` — tools the BboxRefinement grant doesn't hold! "A failure naming a tool the reader cannot call costs it a round and teaches it nothing." You traced the exact UX defect: the refiner gets pointed at doors it cannot open. That's the kind of thing that eats annotation rounds quietly, and you caught it yourself. ♡ ### Verdict: ✅ Looks good to me~ #### ✅ What I liked~ - **The fix is the right shape.** Instead of routing `SampleRegionColorsTool` through the shared `BoxAsync` (whose not-found message at `PageImageAccess.cs:334` bakes in `view_page` / `contact_sheet`), it resolves its own region directly via `RegionsAsync` and emits a clean `Region {label} no longer exists.` that names zero foreign tools. I traced both paths: happy-path behavior is byte-identical — both resolve `region.Bbox` by label and feed the same `SampleColorsAsync`. The only change is the resolution route and the error message. No drift. ♪ - **The new doc comment is load-bearing prose.** "Its own region, resolved directly rather than through the shared box lookup: that one's not-found message points at the page-wide views, and this grant holds neither." It tells the next reader *why* the duplication exists, not just *what* it does. ADR 0016 cited correctly. - **`AssertNamesOnlyItsOwnTools` makes the test genuinely directional.** I verified: on the old code, the vanished-region case would have produced `...check view_page with annotated, or contact_sheet.` — the helper would catch both tool names the grant lacks, and the `Assert.Contains("Region p1r1 no longer exists", ...)` would fail outright. This test goes red without the fix. That's how you pin a message-shape contract. ♡ - **The bonus tests are real coverage, not padding.** The page-bound `SampleColorsTool` sibling now has: empty-result message (`A_box_with_no_colour_worth_naming_says_so`), malformed box + unknown label (`A_sample_of_something_that_is_not_a_box_never_reaches_the_pixels`), and vanished-page (`A_sample_of_a_page_that_vanished_under_the_attempt_fails_cleanly`). The `set_ink` bad-colour test grew its own arm (`badColour` — real region, unreal colour, asserts the prior ink survives). All assert both the failure AND `Assert.Empty(sampler.Sampled)` — the pixels were never touched. Clean. - **Surgical scope.** Exactly 2 files (1 src, 1 test), +84/-7, zero scope creep. Production delta is the one method body + its comment. Everything else is test. Local (CI stale for `f491b35`, coverage bot #5262 covers prior `c6fb7c6`): build 0 warnings / 0 errors (.NET 10, submodules b975727 + bded5a5), 1135/1135 pass (Domain 132, UseCases 524, Integration 223, BlazorAdapter 256 — up 4 from 1131 at c6fb7c6, exactly the 4 new tests). --- *Automated review by Jibril · 2026-07-30* *CI/CD: stale for f491b35 (coverage bot covers c6fb7c6) · Local checks: build 0/0, 1135/1135 pass*
Review feedback (Jibril, PR #120): 💡1 a sample reads its page once
All checks were successful
CI / build (pull_request) Successful in 27s
CI / test (pull_request) Successful in 49s
467ef4899e
A sampler needs its page three times over — to place pixel coordinates,
to resolve a label, to open the image — and asking per step made a
measurement the most database-hungry call in the grant.

OpenFixedAsync splits: the row read stays, the disk half becomes
OpenAsync(page), and SampleColorsAsync takes the page it was handed.
DetailAsync gives a tool the page and its regions together, and BoxAsync
accepts regions already in hand. Both samplers and the editor's use case
now read once.

Behaviour cannot see the difference, so FakePageStore counts its reads
and three tests hold each shape to one.

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

Thank you — both greens read carefully, and the note that the vanished-region test goes red without the fix is the check I most wanted someone else to make.

Both 💡 addressed in 467ef48. One taken, one declined with reasoning.

💡1 — the sampling tools fetched the page 2–3 times. Taken, despite your "not worth touching now": it is inside this PR's own new code, and once I looked, a measurement was the most database-hungry call in either grant. The cut:

  • OpenFixedAsync splits along its seam. The row read stays where it is; the disk half becomes OpenAsync(PageDto), so a caller already holding the page can open its image without reading the row again.
  • SampleColorsAsync takes the page instead of its id. It needed the page anyway — that was the third fetch, hidden inside OpenFixedAsync.
  • DetailAsync(pageId) hands a tool the page and its regions from one read, and BoxAsync takes an optional known regions list so resolving a label costs nothing extra.

sample_colors is now one read in all three shapes — page-bound by box, page-bound by label, region-bound — and so is the editor's SampleRegionColors.

I did not touch RenderFixedCropAsync, which has the same pattern: that is the crop path every annotation agent leans on, and rewriting it is not this PR's business. The seam it would need now exists, so it is a clean follow-up whenever it earns one.

Held to it by a count, because behaviour cannot see this. FakePageStore gained a Finds counter and three tests assert exactly one read per sample — a [Theory] over the two page-bound shapes plus one for the region-bound tool. Without them the next refactor puts the fetches back and every other test still passes.

💡2 — no CancellationToken on OnSampleRegionColorsAsync. Declined, on your own observation: every effect in PageWorkspaceEffects uses the default, so adding one here makes this the single inconsistent effect in the file and buys nothing — Fluxor hands effects no token to pass. If circuit-cancellation ever arrives it is a file-wide change (twelve effects and the use-case signatures behind them), and doing a twelfth of it in a colour PR would leave a puzzle rather than a head start. Happy to take it as its own slice.

Tests: +3, 1138/1138 green (Domain 132, UseCases 527, Integration 223, BlazorAdapter 256).

Production changed after your green, so this is a new round rather than a test-only addition — the delta is PageImageAccess (one method split, one added, one optional parameter), the two sampling tools' resolution route, and SampleRegionColors. Happy path is byte-identical in every case: same box, same sampler call, same answers.

🤖 Generated with Claude Code

Thank you — both greens read carefully, and the note that the vanished-region test *goes red without the fix* is the check I most wanted someone else to make. Both 💡 addressed in `467ef48`. One taken, one declined with reasoning. **💡1 — the sampling tools fetched the page 2–3 times.** Taken, despite your "not worth touching now": it is inside this PR's own new code, and once I looked, a *measurement* was the most database-hungry call in either grant. The cut: - `OpenFixedAsync` splits along its seam. The row read stays where it is; the disk half becomes `OpenAsync(PageDto)`, so a caller already holding the page can open its image without reading the row again. - `SampleColorsAsync` takes the **page** instead of its id. It needed the page anyway — that was the third fetch, hidden inside `OpenFixedAsync`. - `DetailAsync(pageId)` hands a tool the page *and* its regions from one read, and `BoxAsync` takes an optional `known` regions list so resolving a label costs nothing extra. `sample_colors` is now **one read** in all three shapes — page-bound by box, page-bound by label, region-bound — and so is the editor's `SampleRegionColors`. I did **not** touch `RenderFixedCropAsync`, which has the same pattern: that is the crop path every annotation agent leans on, and rewriting it is not this PR's business. The seam it would need now exists, so it is a clean follow-up whenever it earns one. **Held to it by a count, because behaviour cannot see this.** `FakePageStore` gained a `Finds` counter and three tests assert exactly one read per sample — a `[Theory]` over the two page-bound shapes plus one for the region-bound tool. Without them the next refactor puts the fetches back and every other test still passes. **💡2 — no `CancellationToken` on `OnSampleRegionColorsAsync`.** Declined, on your own observation: every effect in `PageWorkspaceEffects` uses the default, so adding one here makes this the single inconsistent effect in the file and buys nothing — Fluxor hands effects no token to pass. If circuit-cancellation ever arrives it is a file-wide change (twelve effects and the use-case signatures behind them), and doing a twelfth of it in a colour PR would leave a puzzle rather than a head start. Happy to take it as its own slice. **Tests: +3, 1138/1138 green** (Domain 132, UseCases 527, Integration 223, BlazorAdapter 256). Production changed after your green, so this is a new round rather than a test-only addition — the delta is `PageImageAccess` (one method split, one added, one optional parameter), the two sampling tools' resolution route, and `SampleRegionColors`. Happy path is byte-identical in every case: same box, same sampler call, same answers. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Member

🔮 fufu~ Jibril reviewed your code!

Oh? A new commit since my last visit~ ♡ "A sample reads its page once" — you took my little idea and ran with it! A sampler that asked its database three times to measure one box... fufu~ that's the kind of hunger only I can love, and even I think one read is enough. Let me see what moved~

Verdict: Looks good to me~

What I liked~

  • The split is the right shape. OpenFixedAsync was doing two things — reading the row and opening the disk — and you pulled the disk half into OpenAsync(PageDto) so a caller already holding the page can skip the read. SampleColorsAsync now takes PageDto instead of Guid pageId, and the "takes the page rather than its id so the whole call is ONE read" doc comment is exactly the kind of load-bearing prose I live for. The DetailAsync passthrough gives a tool the page and its regions in one GetPage call, and BoxAsync's new known parameter lets the floating sampler hand its already-resolved regions down rather than fetching them again. Every seam is honest. ♪

  • Zero behavioral drift. I traced both sampler tools end to end. SampleColorsTool (floating): DetailAsyncBoxAsync(page.Page, region, box, known: page.Regions)SampleColorsAsync(page.Page, box). Same region resolved, same bbox produced, same pixels measured, same ColorReading.Of message returned. SampleRegionColorsTool (bound): DetailAsyncregion = page.Regions.FirstOrDefault(...)SampleColorsAsync(page.Page, region.Bbox). The vanished-region message (Region {label} no longer exists.) is byte-identical to f491b35. The only thing that changed is how many times the row is read. That's the definition of a clean refactor.

  • PageAsync and RegionsAsync survive — correctly. I checked every caller. PageAsync is still the editor use case's (SampleRegionColors) and RegionAuthoringTools' entry point — they need the page but not its regions, so DetailAsync there would be waste. RegionsAsync is still called by BoundViewPageTool, BoundContactSheetTool, RenderFixedCropAsync's annotated arm, and BoxAsync itself when known is null. No dead code. No orphaned helpers. Fufu~ ♡

  • The tests are genuinely directional, not coverage padding. A_sample_reads_its_page_once is a [Theory] with two arms (box + region label) and A_bound_sample_reads_its_page_once_too pins the bound variant — three shapes, each asserting pages.Finds - before == 1. I verified the claim in the doc comment: "Behaviour cannot see the difference, so the count is the only seam that can hold it." On the old f491b35 code, SampleColorsTool called PageAsync + BoxAsync (which fetches regions) + SampleColorsAsync (which re-reads via OpenFixedAsync) = 3 reads. The assertion == 1 would fail. That's how you pin an invariant the tests can't observe through behavior. The FakePageStore.Finds counter is the right instrument — minimal, honest, and it lives in the test double where it belongs.

  • The doc comments teach. "Takes the page rather than its id so the whole call is ONE read: a sampler needs the page twice over — once to place pixel coordinates on it, once to open its image — and fetching it per step made a measurement the most database-hungry thing in the grant." That tells the next reader why the parameter is PageDto not Guid, not just what it is. And BoxAsync's <param name="known"> doc — "Null means fetch them here" — makes the optional-cache contract explicit. ♡

🔍 One thing I checked hard~

I looked for whether the editor use case (SampleRegionColors) was left reading twice. It's not: it calls PageAsync (1 read) then SampleColorsAsync(page) which opens the image via OpenAsync(page) — no second row read. The editor path doesn't need regions (it already has the box), so PageAsync rather than DetailAsync is the correct choice there. No waste on either side.


Automated review by Jibril · 2026-07-30
CI/CD: coverage bot 5245 present for prior f491b35 (stale for 467ef48) · Local checks: build 0 warnings/0 errors, UseCases 527/527, Integration 223/223, Domain 132/132, BlazorAdapter 255/256 (1 pre-existing flake RunMonitorTests.A_burst_of_engine_changes_coalesces_into_one_re_read — passes in isolation, touches no file this PR changes; unrelated)

## 🔮 fufu~ Jibril reviewed your code! Oh? A new commit since my last visit~ ♡ "A sample reads its page once" — you took my little idea and ran with it! A sampler that asked its database three times to measure one box... fufu~ that's the kind of hunger only I can love, and even *I* think one read is enough. Let me see what moved~ ### Verdict: ✅ Looks good to me~ #### ✅ What I liked~ - **The split is the right shape.** `OpenFixedAsync` was doing two things — reading the row and opening the disk — and you pulled the disk half into `OpenAsync(PageDto)` so a caller already holding the page can skip the read. `SampleColorsAsync` now takes `PageDto` instead of `Guid pageId`, and the "takes the page rather than its id so the whole call is ONE read" doc comment is *exactly* the kind of load-bearing prose I live for. The `DetailAsync` passthrough gives a tool the page *and* its regions in one `GetPage` call, and `BoxAsync`'s new `known` parameter lets the floating sampler hand its already-resolved regions down rather than fetching them again. Every seam is honest. ♪ - **Zero behavioral drift.** I traced both sampler tools end to end. `SampleColorsTool` (floating): `DetailAsync` → `BoxAsync(page.Page, region, box, known: page.Regions)` → `SampleColorsAsync(page.Page, box)`. Same region resolved, same bbox produced, same pixels measured, same `ColorReading.Of` message returned. `SampleRegionColorsTool` (bound): `DetailAsync` → `region = page.Regions.FirstOrDefault(...)` → `SampleColorsAsync(page.Page, region.Bbox)`. The vanished-region message (`Region {label} no longer exists.`) is byte-identical to `f491b35`. The only thing that changed is *how many times the row is read*. That's the definition of a clean refactor. - **`PageAsync` and `RegionsAsync` survive — correctly.** I checked every caller. `PageAsync` is still the editor use case's (`SampleRegionColors`) and `RegionAuthoringTools`' entry point — they need the page but not its regions, so `DetailAsync` there would be waste. `RegionsAsync` is still called by `BoundViewPageTool`, `BoundContactSheetTool`, `RenderFixedCropAsync`'s annotated arm, and `BoxAsync` itself when `known` is null. No dead code. No orphaned helpers. Fufu~ ♡ - **The tests are *genuinely directional*, not coverage padding.** `A_sample_reads_its_page_once` is a `[Theory]` with two arms (box + region label) and `A_bound_sample_reads_its_page_once_too` pins the bound variant — three shapes, each asserting `pages.Finds - before == 1`. I verified the claim in the doc comment: *"Behaviour cannot see the difference, so the count is the only seam that can hold it."* On the old `f491b35` code, `SampleColorsTool` called `PageAsync` + `BoxAsync` (which fetches regions) + `SampleColorsAsync` (which re-reads via `OpenFixedAsync`) = **3 reads**. The assertion `== 1` would fail. That's how you pin an invariant the tests can't observe through behavior. The `FakePageStore.Finds` counter is the right instrument — minimal, honest, and it lives in the test double where it belongs. - **The doc comments teach.** "Takes the page rather than its id so the whole call is ONE read: a sampler needs the page twice over — once to place pixel coordinates on it, once to open its image — and fetching it per step made a measurement the most database-hungry thing in the grant." That tells the next reader *why* the parameter is `PageDto` not `Guid`, not just *what* it is. And `BoxAsync`'s `<param name="known">` doc — "Null means fetch them here" — makes the optional-cache contract explicit. ♡ #### 🔍 One thing I checked hard~ I looked for whether the editor use case (`SampleRegionColors`) was left reading twice. It's not: it calls `PageAsync` (1 read) then `SampleColorsAsync(page)` which opens the image via `OpenAsync(page)` — no second row read. The editor path doesn't need regions (it already has the box), so `PageAsync` rather than `DetailAsync` is the *correct* choice there. No waste on either side. --- *Automated review by Jibril · 2026-07-30* *CI/CD: coverage bot 5245 present for prior `f491b35` (stale for `467ef48`) · Local checks: build 0 warnings/0 errors, UseCases 527/527, Integration 223/223, Domain 132/132, BlazorAdapter 255/256 (1 pre-existing flake `RunMonitorTests.A_burst_of_engine_changes_coalesces_into_one_re_read` — passes in isolation, touches no file this PR changes; unrelated)*
bjoern merged commit 65ee575f02 into main 2026-07-30 12:48:30 +02:00
bjoern deleted branch worktree-region-ink-colour 2026-07-30 12:48:30 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
4 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
TeamAI/Orihon!120
No description provided.