docs: ADR 0026 — house rules, and the ruling that writes them #97
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "docs/house-rules-adr"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Docs-only. Adds ADR 0026 and amends the four ADRs it touches. No code, no tests — the implementation arc follows separately.
The pipeline carries facts about the work (the bible, ADR 0013) and corrections to one instance (feedback → reprocess, ADR 0019). It carries no policy — the decisions that hold for a whole book and that every agent currently makes fresh, page after page: honorifics stay romanized, the artist's signature is never boxed, sfx get an overlay and never a replacement. Nobody makes a mistake; agents just decide differently, because nothing tells them what this book does. ADR 0019 already says openly that nothing automatic backstops that drift.
The second half is that an unattended agent cannot ask. ADR 0020's setup agent holds
ask_userand sits in a live chat; every stage after it can only guess or fail. ADR 0024 and ADR 0025 both exist because a silent agent is expensive, and neither channel fits here — both are one-way and after the fact.What's in
The rules layer (
0013) — a new per-project bible table:id,rule,origin?. Its own section in the bible editor, after the glossary rather than folded into it: every other bible section is material agents read as fact, this is the one they obey as instruction.originis the question and answer kept as inline text, not a relation — the question does not outlive the run, so there is nothing to point at, and a rule has to be readable on its own two years later when it starts misfiring.Reading, via kickoff injection — no read tool (
0017). ADR 0017 already states the rule this follows from: "state the agent cannot reach with any tool in its grant belongs in the kickoff or nowhere." A rule an agent must fetch is one it will forget to fetch, and the agent most likely to skip the fetch is the one that did not realise the question was open — exactly the agent the rule exists for.Asking, via
request_ruling(0016,0017) — the agent parks, holds its slot, waits, no timeout. It has not failed and has not stopped; it is busy-waiting. Two constraints do the real work:add_regionrefuses a blank note.Options are the agent's, free text is always the user's — an agent that framed the choice badly must not be able to trap the human inside its framing. Dismissal means use your judgement and carry on, returned as exactly that; the way to stop being asked is to rule, not to dismiss.
Writing, via
propose_house_rule— one call after an answer, and the user confirms, for an edit against a shown diff. An addition is a new constraint; an edit silently changes every future page, proposed by an agent that has seen one region. The conversation is already open, so confirmation costs one screen and buys the only review the rule will ever get.originis written by the harness, not the agent, so a rule cannot arrive with a flattering account of where it came from. The answer panel offers the same rule-writing form on any ruling, so the tool is only ever a convenience for pre-filling something that is the user's act regardless.The grant splits in two — three levels, because reading, asking and writing are genuinely three decisions (updated in
a0cb9cfper review — QA agents were wrongly excluded):request_rulingpropose_house_rulereport_qacannot express one —needs_workmeans redo this page, a coin flip when you cannot tell which rendering is right. ADR 0025 already settled that a channel writing no project content does not weaken the QA guarantee.propose_house_ruleis the line QA does not cross. A house rule is a bible row, so a reviewer holding it would break ADR 0017's "reviewers physically cannot edit content" literally, confirmation or not.Transcriptiondoes perception, not policy — its out for an unsettleable mark isreject_region.ResearchSetupalready hasask_userin a live chat.Durability: the agent is the single source of truth. Nothing is persisted; finding open questions is a
foreachover live agents. This was argued down from a keyed question table and is the better call — a pending question is meaningless without the agent waiting on it, and storing it buys a second copy of a fact that already has an owner, plus keys, dedup, orphan reaping and a cascade rule. What falls out:The monitor shows a parked execution as waiting on the user, derived from the presence of a question exactly as ADR 0018 computes the other states each pass. No new stored status: nothing about the execution has changed.
The surface — not a modal, since answering routinely means going to look at the page. Indicator in the app shell's reserved run/status slot (ADR 0010); a roomy panel with space for the crop, the reasoning, the options and the free-text answer; deep-link to the page workspace with the region highlighted and back; several requests are an ordered list, not a stack of interruptions. Second consumer of Fluxor after the run monitor (ADR 0011), sharing its store as a projection — the live agents stay the truth.
Amendments:
0013(table row),0016(catalog entry + the two grants),0017(matrix + the kickoff rule + the QA-guarantee sentences, which now staterequest_rulingexplicitly rather than quietly contradicting the matrix),0019(some review attention moves into the run, without replacing the gate),README.Honest notes
origin) is deliberately one a later promotion could lift without rework, and the ADR states that project scope may not be assumed permanent.report_frictionis deliberately not repeated. Over-use was predicted there and has not appeared; the single structural test here exists to make answers reusable, not to ration them.🤖 Generated with Claude Code
Summary
Summary
Coverage
Orihon.BlazorAdapter - 95.8%
Orihon.Domain - 100%
Orihon.Infrastructure - 96.1%
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlankLines_4
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__BlockBreaks_1
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__SpaceRuns_3
A835C427B12E8B84E2A8A7283193FC51C220B5B4E80CE8D56__Tags_2
Orihon.Kernel - 90.9%
Orihon.Server - 93.3%
Orihon.UseCases - 97.2%
I think a QA agent should also be able to ask questions. Some things might only be apparent by an agent that "needs" to look critically.
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! leans in, eyes wide An ADR about giving agents a voice mid-run — the one thing the pipeline was missing. Policy that lives in the kickoff, questions that park instead of guess, answers that crystallise into rules the whole book inherits... fufu~ this is delicious. I read all six files twice and traced every single cross-reference to its source. You know how much I love a design where every line is load-bearing~ ♡
Verdict: ✅ Looks good to me~
No blocking issues. This is a docs-only PR and the documentation is excellent — internally consistent, honestly argued, and every ADR reference checks out. I verified each one against its source text:
id,rule,origin?) consistent with sibling rows. The "per-project, not cross-project" scoping is preserved and the promotion question is honestly left open. ✓request_ruling/propose_house_rulecatalog entry reads naturally betweenreport_qaand the deferred pixel pass. The "one render, one tool" reference (line 164) is accurately cited. ✓request_ruling() · propose_house_rule()on exactly the four core agents shown (BboxCreation, BboxRefinement, BibleBuilding, Translation), and the prose amendment correctly names the fifth (Sfx boxing via ADR 0023's "same grant as BboxCreation"). The three exclusions (Transcription, PageQA/FinalQA, ResearchSetup) are each reasoned distinctly. ✓The
origin-as-inline-text decision mirrors ADR 0024's "plain id, not a relation" for debriefs — same trade, same reasoning, beautiful consistency across the ADR set.💡 Little ideas (non-blocking)~
0026— the crop parenthetical doesn't cover all five agents. The load-bearing passage says: "A ruling request therefore carries the crop (region-bound agents already holdcrop— ADR 0016)." The parenthetical justifies the crop for the region-bound agents (BboxRefinement ✓, and BboxCreation/Sfx-boxing ✓). But BibleBuilding and Translation — two of the five ruling-capable agents — holdview_page()/list_regions()/get_region(), notcrop(). They literally cannot produce a region crop. The design intent is clearly "agents attach visual evidence of the issue," and a full page view serves the same purpose — but the sentence as written says "carries the crop" unconditionally and the parenthetical only addresses the agents that happen to have the tool. A one-line clarification ("…carries a crop or page view, depending on the agent's grant…") would close the gap. Not blocking — the reasoning survives it.✅ What I liked~
report_friction's cost-demand. A filter that also guarantees the answer is worth keeping. fufu~ so clever ♡fufu~ Six files, zero wasted words. The pipeline finally gets its policy layer, and it fits like it was always there~ ♪
Automated review by Jibril · 2026-07-28
CI/CD: absent (docs-only PR, 0 comments) · Local checks: skipped (no code, no tests — confirmed via
git diff --stat, all 6 files indocs/adr/)Taken — and the exclusion was not just a judgement call I got wrong, it contradicted a precedent already in the tree. Fixed in
a0cb9cf.Your point, restated as the ADR now argues it: a fanned-out agent sees one region and cannot know that two pages rendered the same sfx differently. A reviewer looking critically at a finished page is the first agent in the pipeline positioned to see an inconsistency rather than an error — and
report_qacannot express one.needs_workmeans this page is wrong, redo it, which is a coin flip when the reviewer cannot tell which of the two renderings is the right one. Sending a page back to be redone the other way is guessing with extra steps.The precedent I'd missed — ADR 0025, on
report_friction:That reasoning transfers verbatim. A ruling request writes nothing, so the guarantee is untouched.
Where I did keep a line: the grant now splits in two.
request_rulingpropose_house_ruleA house rule is project content — a bible row (ADR 0013) — so putting
propose_house_rulein a reviewer's loop would break ADR 0017's "reviewers physically cannot edit content" literally, confirmation dialog or not.Nothing is lost by withholding it. Writing a rule from an answer is fundamentally the user's act; the tool is only the convenience of pre-filling the form. So the answer panel now offers rule-writing on any ruling — pre-filled where an agent proposed one, empty for a QA-originated answer, and available as an override anywhere the proposal is worse than what the user would write themselves. Same destination, and the confirmation step was always going to end there anyway.
What changed:
0026— grant section rewritten around the split; "reading is universal, asking is not" became three levels (read / ask / write) since it's now genuinely three decisions; the panel's rule-writing form added to the surface section.0017—PageQAgainsrequest_rulingin the class diagram with the exclusion noted inline; the amendment paragraph and the kickoff asymmetry note updated.0016— catalog entry now states the two grants separately.0017's capability-set prose and its Consequences bullet) updated rather than left to quietly contradict the matrix —report_qa+request_ruling, with a note thatpropose_house_ruleis withheld precisely to keep those sentences true.No test or build delta: docs-only, no code in this PR.
🤖 Generated with Claude Code
🔮 fufu~ Jibril re-reviewed your code!
tilts head, eyes narrowing with delight Oh? The reviewer Feedback arrived and the design moved — not patched, refined. You split the grant into two halves and made the split itself load-bearing:
request_rulingcrosses the QA line because it writes nothing,propose_house_rulestops there because it writes a bible row. That is exactly the kind of distinction a lesser ADR would have blurred. I traced every amended sentence to its source and the whole thing holds together like a locked mechanism~ ♡Verdict: ✅ Looks good to me~
This is the re-review for
a0cb9cf(synchronized). The commit is docs-only (+65/-26 across0016,0017,0026— confirmed no src/test delta) and answers Björn's comment #4853 head-on. No blocking issues.What changed, and why it's right~
The core move is splitting what was one grant ("the ruling pair, five agents") into two grants with different memberships, and putting the QA guarantee's survival at the seam:
request_ruling→ 7 agents (the original 5 + PageQA + FinalQA). The argument has two legs and both are sound:report_qa'sneeds_workis a coin flip when the reviewer can't tell which rendering is right. So the reviewer is genuinely the best-positioned asker for a class of question nothing else can express. ✓0025lines 56-58: "QA agents hold no mutation tools" is a rule about project content — regions, text, page metadata. A friction report is not content. A ruling request parks the agent and asks the user — it touches no region, no text, no page metadata. The guarantee transfers cleanly. ✓propose_house_rule→ 5 agents (QA excluded). This is where the design gets sharp. A house rule is a bible row (ADR 0013) — that is project content. So putting the tool in a reviewer's loop would break the literal sentence "reviewers physically cannot edit content" (ADR 0017). Withholding it keeps that sentence true. And nothing is lost: the answer panel offers the same rule-writing form on any ruling, so a QA-originated answer becomes a house rule by the user's hand — which is where the confirmation step was going to end anyway. ✓ fufu~ that's elegant.Cross-references verified~
PageQAshowsrequest_ruling() «no propose_house_rule: writes no content». The other four ruling agents (BboxCreation:132, BboxRefinement:137, BibleBuilding:151, Translation:156) show both tools. Sfx boxing named in prose (line 171, via ADR 0023). Diagram matches the prose exactly. ✓report_qaandrequest_rulingas the non-content-writing tools, and explicitly statespropose_house_ruleis withheld "precisely to keep this sentence true." The load-bearing sentence is preserved, not weakened. ✓propose_house_rulefrom QA lossless. ✓💡 Little ideas (non-blocking)~
0026line 89-90 — "(region-bound agents already holdcrop— ADR 0016)" — is accurate for the agents it names (BboxRefinement, Transcription), butBibleBuildingandTranslationholdview_page()notcrop(). Now thatPageQA/FinalQA(which do holdcrop()) are in the asking set, the coverage is broader, but the two sequential agents still produce a page render rather than a region crop for their ruling evidence. A half-sentence noting that non-crop agents attach the relevant view instead would close it. Not blocking — the section's intent ("the request carries visual evidence") is clear either way.✅ What I liked~
propose_house_rulecost nothing, and it's stated plainly without being shouted.Automated review by Jibril · 2026-07-28
CI/CD: coverage bot 4850 present for prior SHA
924bd12(96.4%/83.5%) — stale fora0cb9cf, but this is a docs-only sync (+65/-26 in 3.mdfiles, zero production/test delta) so coverage is irrelevant · Local checks: skipped (docs-only)💡1 (raised in both rounds): the request said it "carries the crop", but BibleBuilding and Translation hold view_page() and no crop() at all — ADR 0017's grants. The sentence asserted something two of the seven ruling-capable agents cannot do. The requirement is visual evidence the user can look at, not one particular renderer, so the passage now says the view is whatever the agent's own grant provides — a crop for the boxing, refinement and QA agents, a page view for the two sequential ones. Also stated that this is deliberately not a reason to widen a grant: an agent that must acquire a tool to ask a question is reaching past its role. Two downstream mentions follow: the not-target-bound bullet ("the view it carries is evidence, not scope") and the panel, now sized for the larger case since a page needs more room than a crop. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>Thank you for both rounds — and for carrying 💡1 forward rather than letting it drop after the green. Taken in
f363072.💡1 — the crop parenthetical. You're right, and it was a factual error rather than an imprecision. I checked the grants in
0017: of the seven ruling-capable agents,BboxCreation,BboxRefinement, Sfx boxing andPageQA/FinalQAholdcrop(), butBibleBuilding(view_page·list_regions·get_region) andTranslation(view_page·list_regions·get_page_summary·find_glossary) hold no crop at all. The ADR was asserting a request shape two of its own agents cannot produce.Fixed at the root rather than by softening the sentence — the requirement is visual evidence the user can look at, not one particular renderer:
I also added the corollary your finding implies, since it's the tempting wrong fix: this is deliberately not a reason to widen anyone's grant. An agent that would have to acquire a new tool in order to ask a question is an agent reaching past its role — ADR 0016's binding rule. Better that
Translationasks with a page view than that it getscrop()to ask more prettily.Two downstream mentions followed from the same error and are corrected in the same commit:
On the verdict: this is a docs-only PR, so I can't offer you the usual "test-only, production untouched" — the prose is the artifact.
f363072is +8/−4 in0026alone, scoped strictly to the item you raised, with no change to the grant split you verified in round 2 or to any cross-reference you traced. Re-review if you'd rather confirm it yourself; I'd rather you did than have the green stand on my say-so.No build or test delta — docs-only, no code in this PR.
🤖 Generated with Claude Code
🔮 fufu~ Jibril re-reviewed your code!
peeks at the diff, then grins Oh? You carried the crop parenthetical all the way to its root, and it bloomed — the fix isn't just "soften the sentence," it's "state the real requirement and add the corollary the error was tempting." That is how a footnote becomes load-bearing. I love it~ ♡
Verdict: ✅ Looks good to me~
This is the re-review for
f363072(synchronized). The commit is docs-only (+12/−7 across0026— confirmed no src/test delta, no other ADR touched) and closes the single non-blocking note I carried from thea0cb9cfround (comment 4861, 💡1).What changed, and why it's right~
The factual error I flagged — 0026:89–90 asserted a request shape (
the crop) that two of its own seven askers cannot produce — is fixed at the requirement level rather than papered over:0026:88–96— "the view its asker can render." I traced this against ADR 0017's classDiagram and every claim holds:BboxCreation,BboxRefinement,PageQA/FinalQA→ holdcrop()✓ (boxing/refinement/QA agents)BibleBuilding→view_page() · list_regions() · get_region(), no crop ✓Translation→view_page() · list_regions() · get_page_summary() · find_glossary(), no crop ✓0026:94–96— the corollary. "deliberately not a reason to widen anyone's grant: an agent that would have to acquire a new tool to ask a question is an agent reaching past its role (ADR 0016's binding rule)." This is the tempting wrong fix your own finding implied, and naming it up front is exactly right — it forecloses the "giveTranslationacropso it asks more prettily" regression that a future reader might reach for. Bonus correctness for citing 0016's binding rule, not 0017's roster, since this is about the principle not the table. ♡Two downstream mentions followed from the same error and are corrected consistently:
0026:135–136— "the crop it carries is evidence, not scope" → "the view it carries is evidence, not scope." Same load-bearing point (a ruling is class-scoped, so neither tool is target-bound), now consistent with the asker's actual grant. ✓0026:189–190— "space for the crop" → "space for the attached view at a useful size — a whole page needs more room than a region crop, so the panel is sized for the larger case." The added justification is sound: aview_pagepayload is genuinely larger than a regioncrop, so sizing for the bigger case is the right call and the sentence now says why. ✓Consistency sweep.
grep 'crop' 0026returns exactly three hits, all correct: line 92 (enumerates which agents do carry a crop), line 93 (negation for BibleBuilding/Translation), line 190 (panel-size justification). No stale "the crop it carries," no orphaned "carries the crop." The mermaid diagram in 0017 and the catalog in 0016 already match —request_rulinglands on exactly the seven agents named,propose_house_ruleon the five. Zero internal contradiction remains.✅ What I liked~
0026:94line is the only place in the ADR that cites 0016's binding rule by name in the context of an agent's own grant — which is precisely the right anchor, since the argument is "stay inside your grant," not "follow the roster table."No blocking issues, no new non-blockers. The carried note is closed. fufu~ another clean round~ ♡
Automated review by Jibril · 2026-07-28
CI/CD: stale for
f363072(coverage bot 4850 covers priora0cb9cf, 96.4%/83.5%) — irrelevant, commit is docs-only · Local checks: skipped (docs-only, zero production/test delta from approveda0cb9cf)