feat(p19): a direction must NAME the requirement that binds it, and have READ it

Two paid rounds scored 0 of 26 fasit concepts opened -- the same number twice.
P18 closed the navigation side (a listing is a window, an invented path is
refused by name) and it did not move, which makes it a ROLE question: nothing
in the loop ever asked the model to say what requirement binds the direction it
committed to, so opening one was never on the critical path to an answer.

A PREMISE OF THE ORDER WAS FELLED BEFORE ANYTHING WAS BUILT ON IT. A1 places
the demand in _INSTRUCTIONS[HYPOTHESISER_ROLE] alone. Measured: the stress
command sends --mandate and NOT --explore, the two are refused together by
name, and none of the nine round-1/2 outboxes holds a {run_id}-exploration.json
-- the hypothesiser never runs in a stress round, so A3 would have been
unreachable in exactly the paid runs this order commissions.

A2's own sentence resolves it: the refusal goes to the model "som en tur den
kan rette (samme mekanisme som quick_validate's nekt), ikke som en raise" --
and quick_validate IS a tool. declare_requirement therefore lives in
navigator_tools, held by BOTH roles that navigate (the exploration, and since
S2c the debate). It EXISTS only when the caller offers both sinks, which keeps
every pre-P19 call site byte-identical; one sink without the other is refused
at construction. 'opened' is the SAME list ExplorationToolRecorder fills, so
the refusal reads the run's own read trace.

The marked hypothesis carries 'requirement' as a REQUIRED key: omitted is a
hard error, explicit null is legal and needs 'why_none', a half-named one is
refused. A minted approach carries it; a seed never acquires one. The proposer
prompt names it only when the field exists, and the judge counts a hit against
THIS approach's fasit concepts, never against the base.

Load-bearing measured (12 arms), four mutations all red against the whole
suite, green control 1711/5 and demo-transcript.stdout byte-unchanged.
A-iii's predicted signature was FALSIFIED: the golden stays green because the
demo runs without a mandate, so _build_messages' approach branch is never
taken there. A-iv was GREEN first -- the repo's vacuous-gate class, 24th time:
the arm drove _attributable while the hit is computed at the call site.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-15 01:21:47 +02:00
commit c84e8bf6f1
22 changed files with 903 additions and 35 deletions

View file

@ -2598,6 +2598,49 @@ Python ≥3.10. MAF (`agent-framework-core` 1.16.0, `-orchestrations` 1.1.1 —
(ignorer scopet) → 1 rød, den nye armen ALENE. **Isolert målt på ekte data:** re-dømming av runde 1
med den nye dommeren tar kontrakt-sorasen fra `named=3` til `named=1`, og den ene som står igjen
er `named_in_measure` — modellens egne ord.
- **En retning må NAVNGI kravet som binder den, og ha LEST det — og ordrens egen plassering var
strukturelt inert (P19 DEL A, 15.09):** to betalte runder på rad ga **0 av 26** fasit-konsepter
åpnet (P16 § 3, P18 § 1). P18 lukket navigasjonssiden (vindu + navngitt nekt for oppfunnet sti) og
tallet rørte seg ikke — dét er hva som gjør det til en ROLLE-sak: ingenting i sløyfa ba noensinne
modellen si hvilket krav i korpuset som binder retningen den forpliktet seg til, så å åpne ett var
aldri på kritisk sti til et svar. **PREMISSET FELT FØR NOE BLE BYGGET PÅ DET:** ordrens A1 legger
kravet i `_INSTRUCTIONS[HYPOTHESISER_ROLE]` ALENE, men stresskommandoen (P18 D1, gjentatt ordrett i
P19 E1) sender `--mandate` og IKKE `--explore`, de to er nektet sammen ved navn, og **ingen av de
ni runde-1/2-utboksene har en `{run_id}-exploration.json`** — hypotesisereren kjører aldri i en
stressrunde, så A3 («kravet når forslaget») ville vært unåbar i nøyaktig de betalte kjøringene
ordren bestiller. **A2s egen setning er dét som løser det:** nekten skal gå til modellen «som en
tur den kan rette (samme mekanisme som `quick_validate`s nekt), ikke som en `raise`» — og
`quick_validate` ER et verktøy. `declare_requirement` bor derfor i `navigator_tools`, altså hos
BEGGE roller som navigerer (utforskningen, og siden S2c debatten). **Verktøyet FINNES kun når
kalleren gir begge sinkene** (`opened` + `requirements`), og dét er hva som holder hvert
pre-P19-kallsted byte-identisk; én sink uten den andre NEKTES ved konstruksjon, fordi en logg som
ikke ser hva som ble åpnet ville akseptert enhver erklæring (vakuøs-gate-klassen, uttalt på
forhånd). `opened` er den SAMME lista `ExplorationToolRecorder` fyller (alias, aldri kopi —
`_drive`-regelen), så nekten leser kjøringens EGEN lesetrace. `RequirementNotRead` er en
`ValueError` (`BundlePathNotFound`-presedensen). **HYPOTESE-LINJA: `requirement` er en PÅKREVD
nøkkel** — utelatt er en hard feil av samme klasse som en uleselig merket linje, eksplisitt `null`
er lovlig og krever `why_none` (basen uten krav er et FUNN; en ubegrunnet null er en stillhet), og
et halvnavngitt krav nektes (validering, ALDRI reparasjon). Et MYNTET forslag bærer feltet, et FRØ
får det ALDRI (§ C.6 dør 1 er en bevaringsregel). **A3:** linja `Binding requirement: <ref>
(<path>)` finnes i `_build_messages` kun når feltet finnes, så hver prompt skrevet før i dag er
byte-identisk. **A4:** dommerens `requirement_hit` måles mot DENNE approachens fasit-konsepter,
aldri mot basen, og `requirement_source` (`approach` | `run` | `absent`) sier hvilken av de to
stedene den kom fra — debatten erklærer ÉN gang per kjøring og kan derfor ikke tilskrives én
approach alene. Load-bearing MÅLT (`tests/test_binding_requirement_loadbearing.py`, 12 armer),
**fire mutasjoner alle røde mot HELE suiten** + grønn kontroll **1710/5** (fra 1699/5, supersett,
0 fjernet) og golden `demo-transcript.stdout` BYTE-UENDRET (`shasum -a 1` av INNHOLDET =
`ea8c534773acdbe41ae68f2c55724d69aaf8be4f`): A-i feltet valgfritt igjen (1) · A-ii nekten sjekker
ikke mot åpnede stier (1) · A-iii A3-linja fyrer ubetinget (1) · A-iv dommeren teller mot hele
basen (1). **ÉN AV ORDRENS SPÅDDE SIGNATURER BLE FALSIFISERT AV MÅLINGEN:** A-iii skulle gjøre
GOLDEN rød — den er byte-uendret, fordi demoen kjører UTEN mandat og `_build_messages`' approach-
gren derfor aldri tas på golden-stien; vitnet er byte-identitets-halvdelen av arm (g).
**OG ÉN MUTASJON FALSIFISERTE TESTEN FØRST (repoets vakuøs-gate-klasse, TJUEFJERDE gang):** A-iv
sto GRØNN mot HELE suiten, fordi arm (h) drev `_attributable` mens treffet regnes ut på KALLSTEDET
i `score_context_set`; armen driver nå hele dommeren mot en erklæring som ER i basen men IKKE er
fasitens, med en positiv kontroll. **Ærlighets-grenser, uttalt:** ingen LEVENDE modell har kalt
verktøyet (structured-output-grensens klasse); debattens erklæring er RUN-nivå, så en approach
uten eget krav tilskrives kjøringens erklæringer og raden SIER at den gjør det; og feltet når
ikke `ProvenanceStamp` (stempelet beskriver gaten som dømte ÉN kandidat).
- **STATE.md er local-only** (gitignored). Voyage session-state er efemert; STATE.md er kanonisk kontinuitet.
- Prosess: Voyage-plugin (`/trekbrief → /trekplan → /trekexecute → /trekreview`) per større fase.