portfolio-optimiser/tests/test_prepass_render_loadbearing.py
Kjell Tore Guttormsen 76b939b3b8 feat(prepass): --prepass-seed makes the cut a starting point, and K2 says it costs
Q5 = B, bygget som MAALT OPSJON. --prepass-payload gir DEBATTEN et deklarert
kutt og trekker de fire navigatoerverktoeyene; --prepass-seed gir UTFORSKNINGEN
det samme kuttet som utgangspunkt og BEHOLDER verktoeyene.

Nekten M32/F4 staar ORDRETT. B er et nytt flagg, aldri en loesning av den, og
hjemmelen er konsumkontraktens SS 2.2: en skill maa ikke lese «outside what the
payload delivers or explicitly names as reachable». Andre ledd er hele arm B, og
PrepassDeclaration.rest_reachable er det som gjoer de to lesningene skillbare i
ettertid -- paakrevd uten default av cost_baseline_anchoreds grunn, fordi begge
defaults ville loeyet om hvilken arm som leste kuttet.

Soemmene:
  admit_payload er EN opptaks-gate (form -> montert base -> tom-leveranse-nekt)
    delt av begge doerer; to kopier ville latt en doer slippe inn det den andre
    nekter.
  render_seed deler header, regel->ANTALL-foldingen og DATA-blokkene med
    render_context. Det eneste som skiller dem er avsnittet som sier hva
    leseren kan gjoere videre.
  explore(seed_context=...) legger kuttet i TASK-MELDINGEN, aldri i prompt:
    _finish bygger Mandate.objective av prompt, og en kommisjon med 22 335
    tokens utdrag i objektivet er uleselig for den som skrev den. Tom streng gir
    en byte-identisk task-melding.
  trace_payload(prepass=...) skriver deklarasjonen fra en finally. MAALT baerende
    -- den seedede kjoeringen som doede paa en Azure-400 etterlot likevel kuttet
    deklarert.
  Fem nekter ved navn. --checkpoint-dir baerer en beslutning: en gjenopptatt
    etappe kjoerer i en prosess som aldri saa payloaden og ville overskrevet den
    parkerte etappens deklarasjon med prepass: null.
  --dimension-config er BEVISST ikke nektet (arm A nekter den): maalt bygger
    utforskningen navigator_tools(bundle_dirs) UTEN dimensjon, saa aa skope
    seedet ville nektet tekst den samme loekka kan aapne et oeyeblikk senere.

MAALT PAA K2 MED LEVENDE MODELL, og maalingen taler MOT aa gjoere B til default:
like-for-like gratis 4 317 -> 227 675 o200k (x 52,7), og betalt er manageren
x 21 paa samme antall prompter. Viktigere enn prisen: den USEEDETE kontrollen
hentet prisskjemaet i fire steg (del-ii-bilag-7-prisskjema/prissammenstilling-
sheet-1.md), mens BEGGE seedede armer lot vaere -- den ene med null verktoeykall
fordi manageren rutet til hypotesisereren i alle tre runder, den andre ved aa
gjette stier ut av kuttets egne konsept-navn og mynte en base-id som ikke finnes.
Erkjennelsen kom (manageren skrev i hver runde at utdragene ikke rakk),
handlingen ikke. Ingen av de 40 svarene brukte ett eneste av kontraktens fem
literaler. NOK 2,78 av taket 5, 0 x 429. Anbefaling skrevet, beslutning ikke
tatt -- den er operatoerens.

Load-bearing maalt: 26 armer, 16 mutasjoner alle roede mot HELE suiten, groenn
kontroll 1493 passed / 5 skipped (fra 1467/5; +26 node-ider, 0 fjernet), golden
demo-transcript.stdout byte-uendret (shasum -a 1 av innholdet =
ea8c534773acdbe41ae68f2c55724d69aaf8be4f).

To armer var GROENNE AV FEIL GRUNN og ble rettet, ikke droppet: tool_calls alene
kan ikke skille «et verktoey ble kalt» fra «basen var aapen», fordi recorderen
appender FOER call_next; og id-enighets-armen maalte den stale digesten i stedet
for id-gaten. Sonden var dessuten feil foer koden var det -- foerste
diskriminator var norsk, og verktoeysvar serialiseres med \uXXXX-escapes.

Avvik, uttalt: implementasjonen ble skrevet FOER testfila. Roedmaalingen er gjort
etterpaa ved aa reversere src/ til HEAD (16 av 24 armer roede), deretter
restaurert med shasum-verifikasjon. Beviset er ekte, rekkefoelgen var ikke.

Rapportert, ikke fikset: ChatClientException (Azure 400, «No tool call found for
function call output») etter tre quick_validate-nekter paa rad -- den ligger
utenfor main()s nekt-tuppel og forlater CLI-en som traceback.

Azure-konfigurasjonen er uendret; endepunktet utledes inline fra az og er aldri
lagret i fil. Ruff + mypy rene.

Maaling: docs/2026-09-07-prepass-mater-q5b-k2.md
Ordre: 20260907T234344Z-9062321009-from-.claude

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

227 lines
10 KiB
Python

"""Load-bearing gate for what a declared cut LOOKS LIKE in the prompt (order 20260907T080223Z).
Two things are gated here, and they pull in opposite directions:
- The rendering must carry enough that the debate can reason and DECLARE — the delivered text,
the three denominators, and the rules that dropped everything else.
- It must stay bounded. Measured on a 629-concept corpus, the whole payload is 41 097 o200k
tokens and its withheld list alone is 34 451; the debate's task message rides in three calls,
so a rendering that carried the payload verbatim would cost ~123 000 against a run cap of
100 000 that has already fired live.
The ceiling therefore lives HERE and not in `prepass.py` — `_CATALOGUE_EXCERPT_CHARS`' own rule:
a bound imported from the implementation moves with it, and widening it is exactly the regression
this file exists to catch.
"""
from __future__ import annotations
import hashlib
import json
import shutil
from pathlib import Path
from typing import Any
from portfolio_optimiser import prepass
FIXTURE = Path(__file__).parent / "fixtures" / "prepass" / "bygg-energi-mikro-fixture.payload.json"
SHIPPED_BASE = Path(__file__).parent.parent / "shared" / "examples" / "bygg-energi-mikro"
#: What the rendering may add ON TOP of the delivered text, in CHARACTERS.
#:
#: **The OVERHEAD is bounded, not the total, and that is the whole point.** The delivered text is
#: already bounded by the producer's own budget gate (SS 7.3, re-checked by `check_payload_shape`),
#: so an absolute ceiling would either refuse a legitimately large cut or be so loose it caught
#: nothing. What po must guarantee is the shape of the cost: O(delivered text) + O(1), never
#: O(corpus) — which is exactly what regresses if the 621-entry withheld list creeps back in.
#:
#: Characters, not tokens, for MAJOR-3's reason: `tiktoken` is not a dependency of this package,
#: and a gate that skips when an optional package is missing is a gate that can be silently
#: absent. Measured 2026-09-07 with a validated instrument, the byte/token ratio is not one
#: number — 2,50 for a withheld list, 2,90 for ordinary Norwegian concept prose, 17,90 for a
#: padded spreadsheet render — so converting a token budget into this bound would import an
#: arithmetic that does not hold across the corpus.
#:
#: The bound lives HERE and never in `prepass.py`: `_CATALOGUE_EXCERPT_CHARS`' rule, because a
#: bound imported from the implementation moves with it, and widening it is the regression.
_CEILING_OVERHEAD_CHARS = 2_000
_DELIVERED_SENTINEL = "SENTINEL-LEVERT-UTDRAG"
_WITHHELD_SENTINEL = "SENTINEL-TILBAKEHOLDT-KONSEPT"
def _raw() -> dict[str, Any]:
return json.loads(FIXTURE.read_text(encoding="utf-8"))
def _marked_base(tmp_path: Path) -> tuple[str, prepass.PrepassPayload]:
"""A base where a DELIVERED concept and a WITHHELD one each carry their own sentinel.
Two sentinels, not one: with a single marker the "the withheld text never reaches the prompt"
assertion could be satisfied by a rendering that carries nothing at all, and the "the
delivered text does reach it" assertion by one that carries everything.
"""
root = tmp_path / "marked"
shutil.copytree(SHIPPED_BASE, root)
index = root / "index.md"
lines = index.read_text(encoding="utf-8").split("\n")
lines.insert(1, "bundle_id: bygg-energi-mikro-fixture")
index.write_text("\n".join(lines), encoding="utf-8")
raw = _raw()
delivered = raw["excerpts"][0]
withheld_id = raw["withheld"][0]["concept_id"]
for concept_id, sentinel in (
(delivered["concept_id"], _DELIVERED_SENTINEL),
(withheld_id, _WITHHELD_SENTINEL),
):
path = root / (concept_id + ".md")
path.write_text(path.read_text(encoding="utf-8") + f"\n\n{sentinel}\n", encoding="utf-8")
delivered["sha256"] = hashlib.sha256(
(root / (delivered["concept_id"] + ".md")).read_bytes()
).hexdigest()
delivered["text"] = prepass.concept_text(root / (delivered["concept_id"] + ".md"))
delivered["text_sha256"] = hashlib.sha256(delivered["text"].encode("utf-8")).hexdigest()
return str(root), prepass.PrepassPayload.model_validate(raw)
# --- what the rendering carries -------------------------------------------------------------
def test_the_rendering_carries_the_delivered_text(tmp_path: Path) -> None:
_, payload = _marked_base(tmp_path)
assert _DELIVERED_SENTINEL in prepass.render_context(payload)
def test_the_rendering_carries_nothing_from_a_withheld_concept(tmp_path: Path) -> None:
"""The half that matters. A withheld concept was withheld deliberately (SS 2.2)."""
_, payload = _marked_base(tmp_path)
assert _WITHHELD_SENTINEL not in prepass.render_context(payload)
def test_the_withheld_sentinel_really_is_in_the_base(tmp_path: Path) -> None:
"""The causality control for the arm above: without it, that assertion is satisfied by a
sentinel that was never written anywhere."""
bundle_dir, payload = _marked_base(tmp_path)
withheld_id = payload.withheld[0].concept_id
body = (Path(bundle_dir) / (withheld_id + ".md")).read_text(encoding="utf-8")
assert _WITHHELD_SENTINEL in body
def test_the_rendering_names_the_withheld_rules_and_never_the_withheld_ids() -> None:
"""Rule -> COUNT. A rule name is a fact a reader can act on; a list of ids they cannot open
is cost without information, and on a real corpus it is 34 451 tokens of it."""
payload = prepass.load_prepass_payload(str(FIXTURE))
rendering = prepass.render_context(payload)
# The HEADER — everything po itself authors, before the first delivered document. A whole-
# rendering substring assert would be red for the wrong reason the moment a delivered concept
# happens to CITE a withheld one, which in a cross-linked base is ordinary (measured: it does).
header = rendering.split("--- BEGIN DATA")[0]
assert "verdict_layer_excluded" in header
for entry in payload.withheld:
assert entry.concept_id not in header
def test_the_rendering_carries_the_three_denominators_and_the_question() -> None:
payload = prepass.load_prepass_payload(str(FIXTURE))
rendering = prepass.render_context(payload)
for number in (
payload.denominators.considered,
payload.denominators.withheld,
payload.denominators.delivered,
):
assert str(number) in rendering
assert payload.question in rendering
assert payload.bundle.bundle_id in rendering
def test_the_rendering_says_a_delivered_excerpt_is_not_an_answer() -> None:
"""Measured live on a 629-concept corpus: a question the base cannot answer still returns
eight excerpts. A rendering that presented them as "what the base says about this" would be
handing the debate a confident guess wearing a denominator."""
rendering = prepass.render_context(prepass.load_prepass_payload(str(FIXTURE)))
assert "[sourced-not-sufficient]" in rendering
# --- the bound ------------------------------------------------------------------------------
def _overhead(payload: prepass.PrepassPayload) -> int:
"""What the rendering costs beyond the delivered text itself."""
return len(prepass.render_context(payload)) - sum(len(e.text) for e in payload.excerpts)
def test_the_rendering_adds_only_a_bounded_overhead_to_the_delivered_text() -> None:
payload = prepass.load_prepass_payload(str(FIXTURE))
assert _overhead(payload) <= _CEILING_OVERHEAD_CHARS, _overhead(payload)
def test_the_overhead_stays_bounded_when_the_corpus_is_large() -> None:
"""The arm that makes the bound mean something.
The checked-in fixture withholds ONE concept, so a rendering that dumped every withheld id
would pass the arm above on it. This one synthesises the corpus-scale case — 620 withheld
concepts, K2's own order of magnitude — and requires the overhead to be UNCHANGED in order of
magnitude, which only a rule -> count rendering can do.
"""
raw = _raw()
raw["withheld"] = [
{
"concept_id": f"del-ii/{n:03d}/et-ganske-langt-konseptnavn-som-i-et-ekte-korpus",
"rule": "no_lexical_match",
}
for n in range(620)
] + raw["withheld"]
raw["denominators"]["withheld"] = len(raw["withheld"])
raw["denominators"]["considered"] = len(raw["withheld"]) + raw["denominators"]["delivered"]
payload = prepass.PrepassPayload.model_validate(raw)
prepass.check_payload_shape(payload)
assert _overhead(payload) <= _CEILING_OVERHEAD_CHARS, _overhead(payload)
def test_the_withheld_list_alone_is_far_over_the_overhead_ceiling() -> None:
"""The flat control: without it, the arm above could be green because the synthetic list is
somehow cheap rather than because the rendering summarises it."""
withheld = [
{
"concept_id": f"del-ii/{n:03d}/et-ganske-langt-konseptnavn-som-i-et-ekte-korpus",
"rule": "no_lexical_match",
}
for n in range(620)
]
assert len(json.dumps(withheld, ensure_ascii=False)) > 5 * _CEILING_OVERHEAD_CHARS
# --- the declaration -------------------------------------------------------------------------
def test_the_declaration_reports_the_payloads_own_denominators() -> None:
"""Never a recount off the navigated bundle: the pre-pass counts the verdict layer and
`Bundle.context_files` does not, so two numbers for one fact would be kø-(p)."""
payload = prepass.load_prepass_payload(str(FIXTURE))
declaration = prepass.declaration_of(payload, rest_reachable=False)
assert declaration.considered == payload.denominators.considered == 5
assert declaration.withheld == payload.denominators.withheld == 1
assert declaration.delivered == payload.denominators.delivered == 4
assert declaration.ref == payload.bundle.ref
assert declaration.question == payload.question
def test_the_declaration_counts_the_withheld_rules_without_naming_the_concepts() -> None:
payload = prepass.load_prepass_payload(str(FIXTURE))
declaration = prepass.declaration_of(payload, rest_reachable=False)
assert declaration.withheld_rules == (("verdict_layer_excluded", 1),)
assert sum(count for _, count in declaration.withheld_rules) == declaration.withheld
def test_the_declaration_payload_is_a_plain_mapping() -> None:
"""The outbox stays framework-free (`explore.trace_payload`'s rule)."""
declaration = prepass.declaration_of(
prepass.load_prepass_payload(str(FIXTURE)), rest_reachable=False
)
body = prepass.declaration_payload(declaration)
assert json.loads(json.dumps(body))["withheld_rules"] == [
{"rule": "verdict_layer_excluded", "count": 1}
]