portfolio-optimiser/docs/2026-09-09-p7-forankrede-identifikatorer.md
Kjell Tore Guttormsen 277bb95777 feat(validator,generate,run): an identifier a proposal builds on must be in the input, or the verdict falls [skip-docs]
P6 (økt 108) ended in ValidatedProposal (verdict 5fd6272e3725fe68) on two cost
codes -- M-04-01 / M-04-03 -- that appear in NO prompt of that run. Measured
here first, verbatim: validate_proposal(p, baseline=None) validates it; the same
proposal against any non-empty CostBaseline is rejected naming both codes.

So the hole was never "fabrication goes uncaught" -- _reconcile_against_baseline
exists and is right -- but that the falsifier is reached only through
`if baseline is not None`. The input always exists; the baseline does not.

New stage 0b (_ground_against_input), OUTSIDE the baseline branch, after stage 0
so an anchored run's message is byte-identical to before. ONE Rejection, the
validator's own type, naming EVERY ungrounded identifier "; "-joined in the
proposal's own order (økt 94's completeness reason).

The rule has NO pattern -- `code in grounding`, exact substring -- and that is a
measurement: over the delivered corpora (K2 1108 files / 2 005 561 chars, the
three N payloads 8 excerpts each) the identifier forms are heterogeneous, and a
pattern chosen to cover them would be a rule about shapes. Bare numerals are the
one inert class (46 394 occurrences / 2 117 distinct in K2); the rule fails OPEN
there, never closed.

Evidence is three non-model-authored sources: what run_project DELIVERED (the
rendered cut/pointer/chunks plus the base's context_files -- never files, which
would make the type: verdict layer evidence), the project's own cost lines, and
the baseline's codes when anchored. The rendered PROMPT is deliberately NOT
evidence, on two measurements: gen_context IS the debate output on the S2c path,
and from attempt 2 the prompt carries the previous Rejection.reason verbatim --
which for this stage QUOTES the identifier it just refused. Grounding in the
prompt would let the gate's own refusal disarm it on its second round.

Prose scanning was chosen against WITH THE NUMBERS: a typed gate catches 2/2
(P6) and 2/2 (S7c) -- 100% of what reached a verdict. What stays uncaught, said
plainly: an ungrounded identifier that lives only in agent/debate prose and never
becomes an affected_item code (2 of 4 P6, 2 of 4 S7c, 1 of 2 P4).

Iron Law: 9 red / 2 green before the rule existed. Ten mutations all red against
the whole suite, green control 1558 passed / 5 skipped (from 1543/5, superset,
0 removed), golden demo-transcript.stdout BYTE-UNCHANGED (shasum -a 1 of the
CONTENT = ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

Three existing fixtures changed, no gate weakened -- most of all
test_pre_amendment_bundle_runs_unchanged, which sent the SAME FABRICATED code and
asserted it validated: the økt-108 hole written down as an expectation.

No paid run. Order 20260909T113641Z-38938691-from-.claude.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 16:04:01 +02:00

223 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# P7 — en identifikator forslaget bygger på skal finnes ORDRETT i inputen, ellers faller dommen
**Ordre:** `20260909T113641Z-38938691-from-.claude` · **Økt 109** · 2026-09-09
**Kontroll før arbeidet:** 1543 passed / 5 skipped · `ruff check src tests` og `uv run mypy src` rene
**Kontroll etter:** **1558 passed / 5 skipped** (+15 node-ider, 0 fjernet)
**Golden `demo-transcript.stdout`:** `shasum -a 1` av INNHOLDET = `ea8c534773acdbe41ae68f2c55724d69aaf8be4f`, UENDRET
**Ingen betalt kjøring.** Alt i dette dokumentet er målt på eksisterende, gratis opptak. **NOK 0,00.**
## 0. Hva som ER målt, og hva som IKKE er det
**MÅLT:** at hullet finnes nøyaktig der PM sa (`validate_proposal(p, baseline=None)` på P6-forslaget
gir `ValidatedProposal`; samme forslag med en ikke-tom `CostBaseline` gir `Rejection` som navngir
BEGGE koder); hvilke identifikator-former de leverte korpusene faktisk bærer, med nevnere; hva en
typet gate og en prosa-gate ville fanget på hvert av de tre opptakene, med nevnere; og at den nye
regelen feller de fire fabrikkerte kodene mens kjent-positiven `Krav 3.3.1—13` står.
**IKKE MÅLT:** at regelen endrer utfallet i en LEVENDE kjøring. Ingen betalt kjøring er gjort, og
ingen er bestilt. De tre opptakene kommer fra ÉN modell og ETT deployment.
**DOMMEN:** hullet var ikke «fang fabrikasjon» — den koden finnes og er riktig — men at
forankringen var **koblet til om det tilfeldigvis fantes en kostnadsbaseline**. Inputen finnes
alltid; baselinen gjør ikke det. Regelen er derfor et EGET stadium (0b) som ikke ser på `baseline`
i det hele tatt.
---
## 1. Premissene, hver verifisert selv
| Premiss (PM målte 09.09) | Verifisert her med | Utfall |
|---|---|---|
| (i) HEAD `999846a`, `git ls-remote origin main` = `eb41374` → UPUSHET = 1 | `git log --oneline -1`, `git ls-remote origin main` | **BEKREFTET** |
| (ii) To utrackede: presentasjons-HTML (parallell økt) + `scratchpad/` | `git status --short` | **BEKREFTET.** Ingen tredje. Begge forblir utrackede |
| (iii) 1543 passed / 5 skipped, ruff + mypy rene, golden `ea8c534…` | `uv run pytest -q`, `ruff`, `mypy`, `shasum -a 1` | **BEKREFTET, alle fire** |
| (iv) `_reconcile_against_baseline` bak `if baseline is not None` | Kjørt PMs egen kontroll på P6-forslaget | **BEKREFTET ORDRETT.** `baseline=None``ValidatedProposal`; ikke-tom baseline → `Rejection: unknown cost code 'M-04-01' … 'M-04-03'` |
| (v) P6 `validated`/`5fd6272e3725fe68`/`approve`; S7c `rejected` på MAGNITUDE | Lest begge `*-outcome.json` + begge `*-proposal.json` | **BEKREFTET.** S7cs grunn er «claimed saving 1400000 exceeds P90 feasible 879107» — stage 4, ikke fabrikasjon |
| (vi) ugrunnede identifikatorer per opptak med PMs grove mønster | Re-målt, se § 3 | **BEKREFTET** (2/2 · 4/4 · 1/2), og mønsteret er erstattet — se § 2 |
| (vii) `Krav 3.3.1—13` i 6/6 prompter OG 6/6 svar, EM-DASH | Re-målt på `p4-n100-free-records.json` | **BEKREFTET.** Bindestrek-varianten: 0 i begge |
| (viii) sømmen er `generate.py` (`_fetch_parsed``validate_proposal`); fem kallsteder | Lest alle: `validator.py:292` (`self_repair`), `run.py:450` (mandat, ingen modell), `explore.py:1266` (`quick_validate`, rådgivende), `generate.py` | **BEKREFTET.** Regelen wires i `generate.py`; de tre andre er uendret, med grunn i § 6 |
---
## 2. Mønsteret, målt fra korpuset — og hvorfor regelen ikke har noe mønster
Målt over det som faktisk ble levert: K2-basen (`scratchpad/s7c/k2-bundle-s7c/`, **1 108 `.md`,
2 005 561 tegn**) og de tre N-payloadene (`scratchpad/nbundler-p2/payload-n{100,200,500}.json`,
**8 leverte utdrag hver**).
| Form | K2 (treff / unike) | N100 | N200 | N500 | Tas inn i regelen? |
|---|---|---|---|---|---|
| `Krav X.Y.Z—N` (em-dash) i KROPPEN | 0 / 0 | 0 | 0 | 0 | — se raden under |
| `Krav X.Y.Z—N` i `req_number` / `title` | — | 8/8 | 8/8 | 8/8 | **JA** (den bor i frontmatter, ikke i kroppen — derfor leser grunnlaget også `frontmatter`) |
| `UPPER-num` (`FOR-2005-04`, `HKFK-22`) | 499 / 23 | 0 | 0 | 0 | **JA** |
| Enkelt-bokstav-kode (`B-20-00-00`, `M-04-01`-formen) | 25 / 14 | 0 | 0 | 0 | **JA** |
| UUID | 0 / 0 | 0 | 71 / 71 | 0 | **JA** (høy entropi; ingen ekstra risiko) |
| `concept_id`-slugger | 1 108 stier | 8/8 | 8/8 | 8/8 | **JA** |
| Rene tall, 26 sifre | **46 394 / 2 117** | 153 / 37 | 132 / 80 | 19 / 14 | **JA i formen, men regelen er INERT der** — se under |
| Punktnummer (`3.3.4`) | 7 392 / 1 755 | 9 / 2 | 25 / 8 | 1 | samme |
**Konklusjonen målingen tvang fram: regelen har ikke noe mønster i det hele tatt.** Sjekken er
`code in grounding` — eksakt delstreng. Formene over er heterogene nok til at et mønster valgt for
å dekke dem ville vært en regel om FASONGER, ikke om forankring, og hver form jeg ikke kunne telle
ville blitt en gjetning. En mønsterløs regel kan ikke ta feil om en form korpuset bærer.
**Rene tall er den ene svakheten, og den er MÅLT, ikke antatt:** K2 bærer 46 394 forekomster av
tall over 2 117 distinkte verdier, så en ren-numerisk kode er nesten alltid «grunnet» ved et
sammentreff (P6 § 4(c) så nøyaktig dette med `1000`). Regelen feiler altså **ÅPENT** der, aldri
lukket — den kan ikke felle en ekte kode, den kan bare la en oppdiktet numerisk kode passere. Det er
den ærlige feilretningen for en gate som uttaler seg om en modells oppfinnelse, og den står som en
grense i § 6, ikke som en påstand om dekning.
---
## 3. Hva de to variantene ville fanget, per opptak, med nevnere
«Ugrunnet» = finnes i et SVAR, finnes ikke i NOEN prompt i samme opptak.
| Opptak | Variant A (typede `affected_items`) | Variant B (identifikator-formede tokens i svarets PROSA) |
|---|---|---|
| P6 `scratchpad/s7c/p6-Aopen-records.json` (5 records) | **2 av 2 ugrunnet**`M-04-01`, `M-04-03` | **4 av 4**`MER-001`, `MER-002`, `M-04-01`, `M-04-03` |
| S7c `scratchpad/s7c/Aopen-records.json` (11 records) | **2 av 2**`PRD-001`, `PRD-002` | **4 av 4**`MEETINGS-05`, `LOGGING-02`, `PRD-001`, `PRD-002` |
| P4 `scratchpad/nbundler-p2/p4-n100-free-records.json` (6 records) | **nevner 0** — opptaket har intet lagret forslag (fri kjøring) | **1 av 2**`CRS-01` ugrunnet, **`Krav 3.3.1—13` GRUNNET** (6/6 prompter) |
**VALGT: variant A. Prosa-skanningen er IKKE bygget.** Begrunnelsen er tallene over, ikke smak:
* variant A fanger **100 % av de identifikatorene som faktisk nådde en DOM** (2/2 og 2/2). Ordrens
tittel er «or the verdict falls», og de fire tokenene variant B legger til nådde aldri en dom:
`MER-001`/`MER-002` sto i en debatt-tur, og en debatt har ingen dom å felle;
* variant A trenger **intet mønster** (§ 2). Variant B kan ikke bygges uten ett, og hvert mønster
er en ny kilde til både falske positive og falske negative på et korpus jeg har tre opptak av;
* variant A er allerede den formen validatoren tar (en typet `SavingsProposal`), så den blir et
stadium ved siden av de andre i stedet for en ny inngang.
**HVA SOM DA FORBLIR UFANGET, ordrett:** en ugrunnet identifikator som KUN står i agent-/debatt-prosa
og aldri blir en `affected_item`-kode. Målt: **2 av 4 på P6** (`MER-001`, `MER-002`), **2 av 4 på
S7c** (`LOGGING-02`, `MEETINGS-05`), og **1 av 2 på P4** (`CRS-01`, i en fri kjøring uten forslag i
det hele tatt). Det samme står i STATEs NESTE.
---
## 4. Regelen
`validator._ground_against_input(proposal, grounding)`**stadium 0b**, ETTER stage 0 og FØR
løseren, og **utenfor** `if baseline is not None`. Returnerer ÉN `Rejection` (validatorens egen
type, aldri en ny domstype) som navngir **HVER** ugrunnet identifikator, `"; "`-joinet, i
FORSLAGETS egen rekkefølge — samme form og samme målte grunn som `_reconcile_against_baseline`
(økt 94: en melding som navngir bare den første leses som en instruks om å fikse den ene).
`_reconcile_against_baseline` er **URØRT**. 0b er plassert ETTER stage 0, så en forankret kjøring
der begge ville fyrt får byte-identisk samme melding som før: baselinens setning er den mer
handlingsbare (den navngir prosjektet og hvor mange koder det kjenner), og Steg 5 mater nettopp den
tilbake.
### 4.1 Beviset er tre kilder, og PROMPTEN er BEVISST IKKE en av dem
`generate._grounding_text(project, baseline, delivered)` komponerer på ÉTT sted:
1. **`delivered`** — hva KALLEREN kan bevise at kjøringen fikk. `run_project` fyller den fra den
leverte rendringen (pre-pass-kuttet / bundle-pekeren / vegstiens hentede chunks) PLUSS den
navigerte basens `context_files`**aldri `files`**, som er egenskapen som dropper
`type: verdict`-laget på hvert nivå (MAJOR-3 N2 / S7a-3). Å grunne et forslag i en tidligere DOM
ville rutet ExpeL-foldens eget materiale rundt sin egen gate;
2. **prosjektets EGNE kostlinjer.** Vegstiens estimat ER prosjektet. **MÅLT:**
`_project_from_bundle` bygger `cost_items=()`, så denne kilden bidrar med INGENTING på
bundle-stien og gaten forblir like skarp der fabrikasjonen ble målt;
3. **baselinens koder når kjøringen er forankret.** Stage 0 har allerede dømt hver kode som når 0b
som en EKTE linje; det svakere stadiet skal ikke overprøve det sterkere fordi et prosa-sammendrag
ikke gjentok koden.
**Den rendrede PROMPTEN er ikke bevis, og det er en MÅLING — ikke smak.** To av promptens deler er
modellens egne ord matet tilbake:
* på S2c-bundle-stien er `gen_context` **debatt-outputen**. Målt: en skriptet proposer som navngir
en kode i en debatt-tur grunner så sitt eget forslag i den turen (armen
`test_g_run_project_grounds_a_candidate_in_the_base_it_delivered` var RØD på nøyaktig dette før
prompten ble tatt ut av beviset);
* fra forsøk 2 bærer prompten forrige `Rejection.reason` ORDRETT (Steg 5) — og dette stadiets grunn
**siterer identifikatoren den nettopp nektet**. Med prompten som bevis ville gatens egen nekt
grunnet neste forsøk: **en falsifiserer som avvæpner seg selv på sin andre runde.** Gatet av
`test_h_the_refusal_does_not_ground_the_next_attempt_that_repeats_the_code`.
### 4.2 Sporet, og hva som ikke er rørt
`grounding` er VALGFRI på `validate_proposal` av samme grunn som `baseline` er det (`None` = pre-P7,
så hver eksisterende kaller, hver golden og demo-transkriptet er uendret), men den lukker et ANNET
hull: stage 0 fyrer bare når en baseline finnes, mens inputen finnes alltid.
---
## 5. Testene, kjent-positiven og mutasjonene
**Iron Law:** testfila ble skrevet FØRST og var **9 røde / 2 grønne** (de to grønne var kontrollene,
som korrekt skal passere pre-P7) før én linje av regelen fantes.
**Fixturene er SPORET, ikke lest fra `scratchpad/`.** Opptakene ligger utracket og finnes ikke i
`git archive HEAD`, så en test som leste dem ville passert her og felt handover-gaten.
`tests/fixtures/p7-grounding/` bærer de tre genererings-promptene ORDRETT (1 788 / 1 397 / 985
tegn) — hele inputen proposeren så på forsøket som produserte kandidaten. Ingen test skipper.
**Kjent-positiven, bindende:** `Krav 3.3.1—13` (EM-DASH, U+2014) står i N100-genererings-prompten og
flagges IKKE. **KONTROLLEN på samme opptak:** `CRS-01` — det ene identifikator-formede tokenet den
kjøringen produserte som ingen prompt bærer — FELLES. Uten den kontrollen ville en grønn
kjent-positiv ikke bevist noe.
### Mutasjonstabell — ti mutasjoner, ALLE RØDE mot HELE suiten
Grønn kontroll **1558 passed / 5 skipped**, golden BYTE-UENDRET, restaurert fra
`scratchpad/p7/mut-backup/` + `shasum -c` etter hver (aldri `git checkout`), ÉN per kjøring.
| # | Mutasjon | Røde |
|---|---|---|
| M1 | regelen finner aldri en violation | **10** |
| M2 | regelen flagger ALT (grunnet eller ei) | **72** — inkl. kjent-positiven og golden-transkriptet |
| M3 | grunnen navngir bare den FØRSTE violationen | **3** |
| M4 | stadiet legges bak `baseline is not None` (økt-108-hullet gjeninnført) | **9** |
| M5 | detach `grounding=` i `generate.py` | **3** |
| M6 | `run_project` erklærer ingen levert input | **33** — hvorav de fleste i tester eldre enn dette arbeidet |
| M7 | grunnlaget bygges fra `bundle.files` (verdict-laget blir bevis) | **1** — den armen ALENE |
| M8 | komponisten dropper baselinens koder | **1** |
| M9 | komponisten dropper prosjektets egne kostlinjer | **15** — alle i eldre tester; kilden har ingen egen arm i den nye fila, og det er dens vitne |
| M10 | den rendrede prompten blir bevis igjen (selv-avvæpningen) | **2** |
---
## 6. Honesty limits
* **Ingen betalt kjøring bekrefter at regelen endrer utfallet levende.** Alt her er målt offline på
tre gratis opptak fra ÉN modell og ETT deployment. En levende bekreftelse er en senere, separat
ordre.
* **Prosa-skanningen er valgt bort med tallene i § 3, ikke bygget.** Ufanget forblir: en ugrunnet
identifikator som kun står i agent-/debatt-prosa og aldri blir en `affected_item`-kode — målt
2 av 4 (P6), 2 av 4 (S7c), 1 av 2 (P4).
* **Rene og svært korte identifikatorer er regelen INERT mot** (§ 2, 46 394 forekomster / 2 117
distinkte i K2). Feilretningen er åpen, aldri en falsk nekt.
* **`assumptions`-nøkler sjekkes ikke.** En nøkkel som ikke navngir noe `affected_item` samples
aldri av Monte Carlo (`SavingsProposal._assumption_bands_enclose_unit_cost` sier det i de samme
ordene), så den kan ikke flytte dommen; en sjekk på den ville vært en gren intet opptak øver.
* **De tre andre `validate_proposal`-kallstedene er BEVISST urørt**, hvert med sin grunn:
`self_repair` er en ren hjelper uten input-tekst; `run.py:450` (`evaluate_mandate_candidates`)
bygger kandidaten FRA baselinen, så den kan strukturelt ikke fabrikkere (økt 82s M7-grense); og
`explore.py:1266` (`quick_validate`) er nivå 1, rådgivende, og når aldri provenance.
* **Den hostede flaten er urørt** — `grounding` er ikke i noen av hostings tre sett, så den
generiske 400-en svarer og Fase 4es to halvdeler står (MAJOR-4/S7bs eget valg gjentatt).
* **`--require-cost-baseline` er IKKE gjort til default** (F4 valgte den opt-in, D-3 låste bruken på
N-kjøringer). P7 gjør den mindre nødvendig, ikke overflødig.
* **Tre eksisterende fixturer ble endret, ingen gate svekket:** `test_structured_output_loadbearing`
gir sin syntetiske kontekst linja forslaget gjenforteller; `test_dimension_loadbearing`s
fremmed-dimensjon-arm bytter `SENTINEL-FOREIGN` mot en kode basen NAVNER (armen ville ellers ridd
på forankringen i stedet for på `admits` — den er nå SKARPERE); og
`test_s40_cost_baseline_loadbearing::test_pre_amendment_bundle_runs_unchanged` sendte den SAMME
FABRIKKERTE koden og påsto at den validerte — altså økt-108-hullet skrevet ned som en
FORVENTNING. Den bærer nå en kode basen navner og beviser dermed det den påstår (en uforankret
kjøring når fortsatt en dom) uten også å love at fabrikasjon klarerer.
---
## 7. Reproduksjon (gratis)
```
uv run pytest -q tests/test_identifier_grounding_loadbearing.py
```
Mønster- og variant-målingene i § 2 og § 3 kjøres med `scratchpad/p7/measure_forms.py` og
`scratchpad/p7/measure_variants.py` (utracket; de leser opptakene under `scratchpad/`).