No description
  • C# 88.8%
  • HTML 9.2%
  • CSS 1.8%
  • Dockerfile 0.1%
Find a file
scarlet 70cc3a6c8f
All checks were successful
CI / build (push) Successful in 27s
Build and Push Docker Image / build-and-push (push) Successful in 1m2s
CI / test (push) Successful in 58s
fix: a container is judged against its own text, not against the page (#131)
bjoern sent a page where the fill takes "too much of everything, even at threshold 1". He was right, and the rule I shipped in #130 does not catch it. This replaces the tell.

## What the page actually does

A balloon whose outline opens onto the page's left margin. Rendered with the real gateways at `LeastTolerance` — the tightest threshold there is:

```
p12r9 (a balloon):     1% of page, spread  1.23x   accepted
p12r4 (the margin):   11% of page, spread 10.05x   refused
```

The margin fill runs the **full height of the sheet** and reaches back through the margin into **two further balloons** that touch the same panel edge. One seed, one connected white region.

Tolerance cannot help: the margin and the balloon's inside are the *same white*, so there is no threshold that parts them. The fill is right about colour and wrong about what it is describing.

## Share is the wrong measure, in both directions

**It misses this.** A strip the height of a page is 11% of its area — under `RunawayShare` (25), so #130 waves it through.

**And it refuses real containers.** `jagged-shout-clipped` — a fixture in our own regression suite — is **37%** of its image. #130 would refuse it. The same balloon on a full page is 1%. A share depends on how much page surrounds the container, which is not a property of the container.

## The measure that works

`spread` — the larger of the container's two dimensions over the region's own box. A container holds this text, so it is a small multiple of it, and that does not change with how much page there is.

Measured across every container I have known-good numbers for — five regression fixtures and five balloons off two real pages:

| container | share | spread |
|---|---:|---:|
| starburst-with-heart-glyphs | 2% | 0.29x |
| round-balloons-on-art | 6% | 0.89x |
| raw2 balloon | 1% | 1.23x |
| raw balloon ×5 | 0–3% | 1.45–1.96x |
| jagged-shout-clipped | **37%** | 1.49x |
| white-boxes-on-white-page | 6% | 1.58x |
| **the margin leak** | **11%** | **10.05x** |

Widest good container **1.96x**; the leak **10x**. `LooseSpread = 4` sits between them with room on both sides — it leaves every known-good container alone by a factor of two and still catches the leak by a factor of two.

The larger dimension rather than the area, because a leak is usually long in one direction only: this one is barely wider than it started and ten times taller, which an area would average away.

## What's in

- **`ContainerFit.Spread`** — nullable, since a request without a `MustCover` box has nothing to be a multiple of.
- **`LooksLikeRunaway`** uses spread where it exists, and falls back to share where it does not. Every production caller passes the region's box, so the fallback is for direct-gateway use.
- **The refusal and the workspace hint now say what is wrong** — "came out 10 times the size of this region's own box" rather than a percentage — and name the case tolerance cannot fix, so an agent does not sit there lowering a number that will never help.
- **ADR 0012** records why share was demoted, with the numbers.

## Tests — 1284/1284 green

Domain 150, UseCases 575, Integration 280, BlazorAdapter 279. Build 0 warnings / 0 errors.

New (+7), both directions on the fixture the suite already carries:

- **`A_fill_that_reaches_the_page_margin_is_loose_however_small_its_share`** ×2 seeds — at `LeastTolerance`, asserting the fill *is* loose, spread > 10, **and that its share never reaches the old line**. That last assertion is the point: it fails if anyone reintroduces a share-based rule.
- **`A_real_container_is_a_small_multiple_of_its_own_text`** ×5 — every seed the panel suite already trusts, asserting spread stays under *half* the limit.

No new fixture: `whole-page-with-gutters.jpg` reproduces the leak exactly (spread 19.93x at its own margin), so the regression is pinned on an image already in the tree rather than another 848 KB.

## Notes

- **This supersedes #130's share threshold in practice.** `RunawayShare` stays for the no-box case rather than being deleted, and the note in #130 about legitimately large containers being blocked is now moot — that was the `jagged-shout` false positive, and spread does not have it.
- Unchanged: the editor's threshold control, both-ways guidance, and the floating rule from #130 all still apply. This only replaces *how a bad fill is recognised*.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: schattenan <schattenan@kagaku.eu>
Reviewed-on: #131
Co-authored-by: scarlet <scarlet@kagaku.eu>
Co-committed-by: scarlet <scarlet@kagaku.eu>
2026-07-31 08:15:21 +02:00
.claude/skills/pr-review-loop Skill: while waiting on a review round, the branch sits still 2026-07-25 16:36:11 +02:00
.config chore: the meta and deploy files track the Kagura conventions 2026-07-23 19:14:22 +02:00
.github ci: stamp coverage comment with commit SHA + revision number (#78) 2026-07-27 18:18:33 +02:00
deploy fix: visible page uploads — icons, live progress, and a circuit that survives them 2026-07-24 23:40:20 +02:00
docs fix: a container is judged against its own text, not against the page (#131) 2026-07-31 08:15:21 +02:00
external fix: the provider's handle on its thought reaches the next round (#121) 2026-07-30 13:43:14 +02:00
src fix: a container is judged against its own text, not against the page (#131) 2026-07-31 08:15:21 +02:00
tests fix: a container is judged against its own text, not against the page (#131) 2026-07-31 08:15:21 +02:00
.dockerignore chore: the meta and deploy files track the Kagura conventions 2026-07-23 19:14:22 +02:00
.gitattributes chore: the meta and deploy files track the Kagura conventions 2026-07-23 19:14:22 +02:00
.gitignore docs: capture the PR review loop with Jibril as a repo skill 2026-07-25 16:36:11 +02:00
.gitmodules chore: the repository skeleton stands up 2026-07-23 19:02:00 +02:00
AGENTS.md feat: how many agents run at once is the user's number, not ours (#125) 2026-07-30 18:19:45 +02:00
CLAUDE.md chore: the repository skeleton stands up 2026-07-23 19:02:00 +02:00
Directory.Build.props chore: the repository skeleton stands up 2026-07-23 19:02:00 +02:00
Directory.Packages.props test: pin the bridge's teardown guards with a deterministic clock 2026-07-25 12:13:10 +02:00
Orihon.slnx feat: translation domain model and the bible entities 2026-07-24 17:02:49 +02:00
README.md chore: the repository skeleton stands up 2026-07-23 19:02:00 +02:00

Orihon

A single-user, self-hosted doujinshi translation harness — a Blazor Server app that drives translation through a heavy-handed, inspectable AI workflow graph.

Status: repository skeleton. Structure, submodules, central package management, CI and the container build are in place. The architecture (ADRs) and user stories are written next, before feature code.

Prerequisites

  • .NET SDK 10.0+
  • Access to the vendored submodules on git.kagaku.eu (TeamAI org)

Getting started

# Clone WITH submodules (OpenRouter.Net, Kagaku.UI live under external/)
git clone --recurse-submodules <orihon-url>
# Already cloned without them?
git submodule update --init --recursive

dotnet build   Orihon.slnx --configuration Release
dotnet test    Orihon.slnx --configuration Release
dotnet run   --project src/Orihon.Server   # http://localhost:5000, /health

Layout

Project Responsibility
src/Orihon.Kernel Technical primitives (Result<T>). References nothing.
src/Orihon.Domain Entities and value objects. Pure — no I/O, no framework attributes.
src/Orihon.UseCases Application layer: use cases and the ports they depend on.
src/Orihon.Infrastructure Driven adapters. The only project that sees the vendored clients.
src/Orihon.BlazorAdapter Primary UI adapter (Razor Class Library).
src/Orihon.Server ASP.NET host + composition root.
tests/* Unit, integration and component test projects.
external/* Vendored libraries as git submodules (OpenRouter.Net, Kagaku.UI).

Dependency direction: Kernel → Domain → UseCases → {Infrastructure, BlazorAdapter} → Server, enforced by the project-reference graph.

Conventions

  • .slnx solution format; Directory.Build.props + Directory.Packages.props (central package management).
  • net10.0, nullable + implicit usings on, warnings-as-errors, deterministic, invariant globalization.
  • Versioning via MinVer (v-prefixed tags).
  • CI on Forgejo Actions (.github/workflows/); container image published to git.kagaku.eu/teamai/orihon.