docs: U4-kallstedene som invariant + --explore paa den publiserte flaten (ORDRE 20260823T204216Z)

CLAUDE.md: ny invariant «Utforskningens KALLSTEDER» - det kaller-eide sporet og
hvorfor formen er tvunget av en maaling og ikke valgt, tredelingen av hostings
whitelist og den NEGATIVE halvdelen Fase 4e-beviset trengte, de to nektene som baerer
en beslutning (to kilder til ett mandat; enable_plan_review nektet FOER explore()
fordi ExplorationError er en RuntimeError), demo-scenarioets vakuitets-vakt, seksten
maalte mutasjoner, og den ene som falsifiserte testen foerst. Linja «--explore i
run.py ... er IKKE bygget (oekt 57)» er fjernet - den er ikke sann lenger.

README: --explore/--explore-config i single-project-partisjonen, med bundene som maa
oppgis og hvorfor ingen av dem har en default, nekten mot --mandate og doera som
faktisk betjener fagpersonens egne hypoteser, samt {run_id}-exploration.json og det
hostede explore_prompt.

998 passed / 5 skipped. Golden-transkriptet byte-uendret.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YRZhBJcxqTcqWyMW6hBttx
This commit is contained in:
Kjell Tore Guttormsen 2026-08-25 09:43:46 +02:00
commit 2d44c5e224
2 changed files with 85 additions and 3 deletions

View file

@ -834,8 +834,61 @@ Python ≥3.10. MAF (`agent-framework-core` 1.9.0). Pakkehåndtering: `uv`. To b
stedet for målt; `quick_validate`-dommene hypotesiseren så bor ikke i `ExplorationResult`, de er nivå stedet for målt; `quick_validate`-dommene hypotesiseren så bor ikke i `ExplorationResult`, de er nivå
1 og hører hjemme i `{run_id}-exploration.json` som CLI-wiringen skriver; utforskningsrollene løses 1 og hører hjemme i `{run_id}-exploration.json` som CLI-wiringen skriver; utforskningsrollene løses
via `resolve_model`s `default`-fallback til en operatør mapper dem eksplisitt; at en LEVENDE modell via `resolve_model`s `default`-fallback til en operatør mapper dem eksplisitt; at en LEVENDE modell
kaller verktøyene er ikke bevist offline (samme klasse som structured-output-grensen). `--explore` i kaller verktøyene er ikke bevist offline (samme klasse som structured-output-grensen).
`run.py`, `explore_prompt` i `hosting.py` og sim-scenarioet er IKKE bygget (økt 57). - **Utforskningens KALLSTEDER: sporet er kaller-eid, og whitelisten ble en TREDELING (økt 57):**
`--explore "<prompt>" --explore-config FILE` i `run.py`, `explore_prompt` + `explore_contract`
den hostede flaten, og `simulate_exploration` som et TREDJE sim-scenario — alle opt-in, alle over
den uendrede sløyfa. **`ExplorationTrace` er en KALLER-EID akkumulator (funn-1-sinken, ett lag
opp), og formen er tvunget av en måling, ikke valgt:** `explore()` raiser `BudgetExceeded`
rundetaket og tokentaket fyrer fra middleware midt i løpet — på BEGGE stier konstrueres aldri et
`ExplorationResult`, mens § C.2 krever at artefaktet er lesbart «uansett hvilken vakt som fyrte».
Steg-5-regelen («returverdi, ALDRI en out-parameter») styrer en verdi som NÅR kalleren; her gjør
den ikke det, og å kopiere regelen blindt ville gjenoppbygd defekten den ble skrevet mot.
`ExplorationResult.ledger_log`/`.plan_reviews` BYGGES FRA akkumulatoren (`tuple(trace.ledger)`),
aldri ved siden av — to beholdere om ett faktum er kø-(p). `{run_id}-exploration.json` skrives fra
en **`finally`** (`write_parse_failures`-presedensen) via `explore.trace_payload``outbox`s
plain-mapping-skriver (RAW-laget forblir MAF-fritt); **`completed` er et EGET påkrevd felt**, fordi
en `stop: null` som betyr BÅDE «avsluttet normalt» og «vi fikk aldri vite» er stillheten
`cost_baseline_anchored` ble påkrevd for å lukke. **Åtte CLI-nekter, alle ved navn**, hvorav to
bærer en beslutning: (i) `--explore` + `--mandate` er TO KILDER TIL ETT MANDAT og NEKTES, aldri
slås sammen — `explore()` tar objective fra prompten og hardkoder `allow_own_proposals=True`, så
komposisjon ville stille overskrevet tre felt operatøren skrev selv; nekten NAVNGIR
biblioteksdøra (`seed_approaches`), fordi § C.6 dør 1 er et ekte behov flaten ikke betjener.
(ii) `enable_plan_review=true` nektes på BEGGE flater FØR `explore()` kalles, og det er en
TYPE-måling: `ExplorationError` er en `RuntimeError` og ligger utenfor `main()`s
`(ValueError, FileNotFoundError, ValidationError)`-tuppel og utenfor hostings 400-arm, så å
overlate den til sløyfa ville gitt traceback på CLI-en og 500 — krasj-kanalen — på HTTP.
(`TracingConfigError` er derimot en `ValueError`; 400-armen dekket den alt.) Etter nektene er hver
konfig-formet `ExplorationError` UNÅBAR fra begge inngangene ved konstruksjon; det som fortsatt kan
slippe ut (uleselig merket hypotese, uttømt budsjett) er RUN-en som feiler, ikke kalleren som tar
feil. **Hostings whitelist er nå `_REQUIRED` / `_OPTIONAL` / `_CONSUMED`:** utforskningsfeltene er
IKKE `run_project`-parametre, så Fase 4e-beviset fikk en NEGATIV halvdel — hvert videresendt felt
MÅ finnes i `inspect.signature(run_project)`, hvert konsumert felt MÅ ikke; uten den ville et felt
som glir fra konsumert til videresendt vært nøyaktig driften 4e finnes for. **Demo-scenarioet er
nåbart ved NAVN og bare der** (`main()` kaller det ikke, og at golden-transkriptet er byte-uendret
etter at det ble lagt til ER målingen av det), med en **vakuitets-vakt**: en label kunnskapsbasen
ALLEREDE oppgir refuseres, fordi den ville nådd hypotese-prompten som ordinær kontekst enten
utforskningen kjørte eller ei — `simulate_learning_loop`s to-markør-vakt i demo-form. Manager-
manuset nøkles på PROMPT-STADIET, ikke prosjekt-ID-en, og det er ikke et unntak fra
`scripted_proposer`-regelen: manageren får FEM ulike spørsmål og prosjekt-ID-en er konstant over
alle fem. Load-bearing MÅLT (`tests/test_explore_callsites_loadbearing.py`, 23 tester), seksten
mutasjoner alle røde mot HELE suiten + grønn kontroll 998/5: detach sink-appenden (1) · andre liste
for rundene (4) · detach `--mandate`-nekten (1) · detach `--explore-config`-nekten (1) · skriv
artefaktet kun ved fullført kjøring (1) · detach CLI-ens `mandate=` (1) · slipp
`enable_plan_review` gjennom, CLI (1) · detach `--bundle-dir`-kravet, CLI (1) · detach
`--live-dry-run`-nekten (1) · fjern `--explore` fra portefølje-partisjonen (1) · videresend de
konsumerte feltene (2) · detach hostings `mandate=` (1) · detach `enable_plan_review`-nekten,
hosting (1) · detach `bundle_dir`-kravet, hosting (1) · detach sim-scenarioets `mandate=` (1) ·
detach vakuitets-vakten (1). **ÉN MUTASJON FALSIFISERTE TESTEN FØRST (repoets vakuøs-gate-klasse,
syvende gang):** portefølje-testen asserterte kun at meldingen nevnte `--explore`, og sto GRØNN
uten partisjonen — kjøringen falt da gjennom til «`--explore` requires `--bundle-dir`», som nevner
`--explore` også. To nekter som deler en delstreng er «assert aldri på ordlyd to grener deler»,
fanget av sin egen mutasjon; testen navngir nå `--portfolio`. **Ærlighets-grenser, uttalt:**
multi-base (`Approach.bundle_id`, § C.7) er FORTSATT ikke bygget — `run_project` tar én
`bundle_dir`; utforskningens egne modellkall er UANNONSERTE (annonseringens kontrakt er at en
KOMMISJON erklæres før arbeidet den bestiller, og før `explore()` returnerer finnes ingen —
`exploration_notice` dekker gapet i det sløyfa er ferdig); `BudgetExceeded` ut av `--explore`
tracebacker som den gjør for debatten i dag.
- **STATE.md er local-only** (gitignored). Voyage session-state er efemert; STATE.md er kanonisk kontinuitet. - **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. - Prosess: Voyage-plugin (`/trekbrief → /trekplan → /trekexecute → /trekreview`) per større fase.

View file

@ -394,7 +394,9 @@ when the seam is detached, so the loop cannot silently degrade into theater.
`--semantic-retrieval`, `--decision`/`--rationale`, `--live-dry-run`, and `--semantic-retrieval`, `--decision`/`--rationale`, `--live-dry-run`, and
`--scripted-replies <file>` (the offline whole-loop door — see `--scripted-replies <file>` (the offline whole-loop door — see
[Walk the whole chain offline](#walk-the-whole-chain-offline); mutually exclusive with [Walk the whole chain offline](#walk-the-whole-chain-offline); mutually exclusive with
`--live-dry-run`, which stops before the first model call rather than answering it). `--live-dry-run`, which stops before the first model call rather than answering it), and
`--explore "<prompt>" --explore-config <file>` (opt-in: run an exploration first and let it
shape the mandate this run evaluates — see below).
- **Portfolio**`--portfolio`, plus optional `--goals`, `--ledger`, `--dimension-config`, - **Portfolio**`--portfolio`, plus optional `--goals`, `--ledger`, `--dimension-config`,
`--semantic-retrieval`; it stops early and prints a `goal reached: …` line when the `--semantic-retrieval`; it stops early and prints a `goal reached: …` line when the
accumulated ledger meets a goal. accumulated ledger meets a goal.
@ -414,6 +416,33 @@ when the seam is detached, so the loop cannot silently degrade into theater.
uv run python -m portfolio_optimiser.run --report --ledger ledger.json uv run python -m portfolio_optimiser.run --report --ledger ledger.json
``` ```
`--explore` (U4) is **opt-in** and sits *over* the eight-step loop, never inside it. Given a
prompt and a knowledge base, a Magentic manager decides what to read and which cost-saving
directions are worth testing; what leaves that freedom is a **mandate**, and every number in it
is still gated by the same blocking deterministic validator. The exploration writes nothing —
no outbox artefact, no wiki entry, no verdict.
```bash
uv run python -m portfolio_optimiser.run FV42-GSV-E1 --docs-dir <docs> --bundle-dir <bundle> \
--explore "Find the cheapest saving worth testing here" --explore-config exploration.json
```
`--explore-config` states the bounds, and **every field is required**`max_rounds`,
`max_tokens`, `max_stall_count`, `max_reset_count`, `max_plan_revisions`, `enable_plan_review`.
None of them has a default, because an omitted cap falls back to an *unbounded* loop rather than
a conservative one. `enable_plan_review` must be `false` on this surface: the plan review is
synchronous and there is no reviewer at a CLI to answer it (the library API takes one).
`--explore` is refused together with `--mandate` — they are two sources of one mandate, and
merging would silently overwrite what you wrote. To seed an exploration with a domain expert's
own hypotheses, use `explore(..., seed_approaches=[Approach(...)])`; seeds are always preserved
and always come first, including when the loop stops early. With `--outbox-dir`/`--run-id` the
run also writes `{run_id}-exploration.json`: the per-round ledger, the plan reviews and the
in-loop advisory verdicts, written even when a cap cut the exploration short.
The hosted surface takes the same door as `explore_prompt` + `explore_contract` on
`POST /invocations`.
`--semantic-retrieval` (S3.1) is an **opt-in** ranking change, **off by default**. Off, prior `--semantic-retrieval` (S3.1) is an **opt-in** ranking change, **off by default**. Off, prior
verdicts are ranked exactly as before: a structural score over the affected cost-code set, verdicts are ranked exactly as before: a structural score over the affected cost-code set,
measure type and magnitude bucket, with surface text deliberately excluded. On, that score is measure type and magnitude bucket, with surface text deliberately excluded. On, that score is