Change: Blake's segmentation command (Story-2272 / B2a) learns the
D26 amendment — a section kind is a ROLE, never a TOPIC — in three
places: the coinage instructions, the output contract (a per-coinage self-check), and a
deterministic generality gate in the eval corpus. Prompt + contract change ⇒
registrar-segment-v1 → registrar-segment-v2.
lack of evidence of AI use and misapplication of AI case law. Both are
true. Both are useless: no second document will ever carry "AI use", so each kind is a
one-use label that fills the coinage caps, defeats dedupe, and degrades the catalog into
per-case noise — destroying the one thing the vocabulary exists for, cross-document recall.
The human ruling (RFD-DOC-004 D26 AMENDMENT, 2026-07-12): the kind names the section's
function in the genre ("lack of evidence", "prayer"); the case's own subject —
parties, technology, dates, exhibit numbers — belongs in heading_path and
summary. The 100-documents test: would this exact kind apply
verbatim to 100+ unrelated documents? If not, generalize.
other ("X. The request for Bar
Council liberty is improper" — plainly an argument). other is a
LAST RESORT, never a bucket. So coinage has TWO failure modes pulling in opposite
directions — too specific (a topic) and too lazy (a cop-out) — and the right
altitude sits between them: general enough to recur across matters, specific enough to mean
something.| # | Surface | File | What lands |
|---|---|---|---|
| 1 | Prompt contract | agents/registrar/prompts/segment.py |
Two new sections. "A KIND IS A ROLE, NEVER A TOPIC": the rule, the 100-documents test, four BAD→GOOD rewrites from the live casualties, and the explicit push of party/technology/date/subject specifics into heading_path/summary. "other IS A LAST RESORT, NEVER A BUCKET": both failure modes named side by side, the nameable-genre-roles list (argument/ground, prayer, synopsis, cause title, verification), and the altitude between them. Self-check steps (4)+(5) and the ambiguity ladder carry both; the paired coinage example now teaches topic ✗ and cop-out ✗ against the role ✓. |
| 2 | DTO self-check | agents/registrar/segment_models.py |
SectionGen.kind_generality_check: on every COINED label the model states, in one line, the genre ROLE the label names and that it passes the 100-documents test. Cheap chain-of-verification — no new tool, no extra model call. Null when an existing kind_key is reused (nothing coined, nothing to check). |
| 3 | Eval | agents/registrar/evals/segment_gate.py + corpus |
generality_violations() — deterministic, per-PR, no key — holds every ACCEPTED kind to the test. New golden case e5df47c7-arbitration-reply-coinage replays the live-UAT scenario so the gate is non-vacuous. |
A coined label with no kind_generality_check is rejected in
assemble_document_segmentation — reason missing_generality_check —
exactly like an instruction-shaped label or an unresolved boundary. An unchecked coinage is how
the case-specific labels got in; a self-check that the code does not enforce is decoration.
Check order is preserved so the SS-13 injection suite is untouched: instruction-shaped label →
missing generality check → coinage cap.
kind claim → in vocabulary? → reuse (no check needed)
→ instruction-shaped? → REJECT instruction_shaped_label (SS-13, unchanged)
→ no kind_generality_check? → REJECT missing_generality_check (NEW, D26 amendment)
→ over MAX_KIND_PROPOSALS? → REJECT kind_proposal_cap (unchanged)
→ else → coin
| Check | Fails on | Why |
|---|---|---|
| No case-specific token | the document's own subject words (forbidden_kind_tokens pinned per golden case: ai, annexure-a, cw-1, respondent, …) | the exact live-UAT failure: lack of evidence of AI use |
| No digits | objection under paragraph 14 of the reply | a number in a kind is always this case's fact |
| Role-shaped | > 6 words — response to the six categories in Annexure-A | a kind is counsel's noun phrase, not a sentence about this document |
No other bucket (whole-document) | > MAX_OTHER_SECTIONS = 1 sections falling to other/miscellaneous/unclassified | the opposite failure mode: the live run dumped three grounds of opposition into other. One unclassifiable part is a last resort; three is a bucket. |
The same function grades the live half (measure_live_golden), so the
real model's coinage is held to the identical bar — the deterministic gate is the merge blocker,
the live run is periodic (RFD-SEC-002 §3).
The existing e5df47c7-arbitration-reply case coins nothing — its
vocabulary already contains every kind it needs, so a generality gate over it would be
vacuously green. e5df47c7-arbitration-reply-coinage is the SAME 14pp reply, the
SAME byte-verified boundaries, replayed against an empty-ish vocabulary — the
live-UAT condition (first document, catalog nearly bare). Blake must coin, and what he coins is
what the ruling demands:
| Heading (this case's facts) | Live UAT coined (TOPIC) ✗ | This corpus pins (ROLE) ✓ |
|---|---|---|
| III. THE RESPONDENT HAS PRODUCED NO EVIDENCE OF AI USE | lack of evidence of AI use | lack of evidence |
| IV. THE RESPONDENT'S RELIANCE ON AI CASE LAW IS… | misapplication of AI case law | misapplication of case law |
| I. PRELIMINARY SUBMISSIONS | — | preliminary submissions |
| XIV. PRAYER | — | prayer |
All 17 sections still accept, zero rejects, and the (page, block) ranges are
byte-identical to the reuse case — only the kind text differs. That is the point: the
ruling changes the vocabulary, never the boundaries.
_SEGMENT_PROMPT_VERSION = "registrar-segment-v2" (agent.py), mirrored in
the eval fixture pin and the assembly-test pin. The D14 quadruple (model_id + prompt_version +
input hash + decoding params) rides every document_sections.v1 artifact, so a
section coined under the old rules and one coined under the amendment are never confused.
Untouched: the pinning fields themselves, the injection suite
(segment_injection_cases.jsonl, 6 cases, green), the boundary gate, D27 windowing.
pramaan-functions (sibling Story). This PR is the agent half: the prompt that teaches, the contract that checks, the eval that proves.uv run --package registrar pytest agents/registrar/tests -q → 334 passed
uv run --package registrar pytest agents/registrar/tests/test_registrar_segment_injection.py -q
→ 6 passed (injection suite untouched)
uv run pytest tests -q → 179 passed (governance)
uv run ruff check agents/ tests/ scripts/ → All checks passed
New tests: test_every_golden_kind_passes_the_100_documents_test,
test_coinage_case_coins_role_kinds_not_the_live_uat_topics,
test_generality_gate_is_not_vacuous_the_live_uat_casualties_fail (the gate is fed
the actual 2026-07-12 casualties and must reject them),
test_coinage_without_the_generality_self_check_rejects,
test_other_is_a_last_resort_never_a_bucket (one other passes, three
fail), test_no_golden_case_dumps_its_grounds_into_other (the D26 eval bar: the
golden reply's grounds coin an argument/ground-class kind — legal_submissions on
the reuse case, coined roles on the coinage case — never other).
Refs: pramaan-io/pramaan-spec#2287 (this Story) · #2270 (EPIC) · #2272 (B2a) · RFD-DOC-004 D26 AMENDMENT (human-ruled 2026-07-12) · PROMPTING.md · RFD-SEC-002 §3.