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>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-08 04:02:09 +02:00
commit 76b939b3b8
9 changed files with 1474 additions and 42 deletions

View file

@ -434,7 +434,12 @@ def tool_call_payload(calls: Sequence[ToolCall]) -> list[dict[str, Any]]:
def trace_payload(
trace: ExplorationTrace, *, stop: str | None, completed: bool, mandate: Mandate | None
trace: ExplorationTrace,
*,
stop: str | None,
completed: bool,
mandate: Mandate | None,
prepass: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
"""The ONE rendering of a trace into plain data for ``outbox.write_exploration``.
@ -454,10 +459,18 @@ def trace_payload(
a park), which is exactly what ``completed=False`` already says. Collapsing that into an
empty list would make "the loop formed no approaches" and "the loop never got that far"
unreadable from each other.
``prepass`` is the declared cut this exploration was SEEDED with (``--prepass-seed``), already
rendered by ``prepass.declaration_payload`` so this module and the outbox both stay free of
that dependency. It DEFAULTS to ``None``, unlike ``completed`` and ``mandate`` above: absence
here is an honest positive statement no cut was given which is ``Bundle.skipped``'s empty
tuple rather than ``cost_baseline_anchored``'s required boolean, and it is the same decision
``RunResult.prepass`` already made one surface over.
"""
return {
"completed": completed,
"stop": stop,
"prepass": dict(prepass) if prepass is not None else None,
"tokens_spent": trace.tokens_spent,
"approaches": [
{
@ -1516,6 +1529,7 @@ async def explore(
success_criteria: str = "",
trace: ExplorationTrace | None = None,
checkpoint_dir: str | None = None,
seed_context: str = "",
) -> ExplorationResult:
"""Explore the knowledge bases and return the ``Mandate`` the pipeline should evaluate.
@ -1554,6 +1568,20 @@ async def explore(
``trace`` is the caller's accumulator and is the ONLY way to see what a run that RAISED
produced: both budget channels destroy the ``ExplorationResult`` before it exists. When it is
omitted a private one is used, so the returned result is unchanged for every existing caller.
``seed_context`` is material the CALLER has already verified and wants the loop to START from
today, one contract-conformant OKF pre-pass cut (``--prepass-seed``). It joins the TASK
MESSAGE and deliberately NOT ``objective``: the objective is what a person commissioned and
what ``Mandate.announce`` prints back to them, so folding ten thousand tokens of excerpts into
it would make the commission unreadable and would put the cut's text into every artefact that
quotes the objective. Empty by default, and an empty string leaves the task message
byte-identical to what it has always been which is what makes "without the flag, nothing
changed" a property rather than a promise.
**This is a starting point, never a boundary.** The navigator tools are built exactly as they
are without it, because an exploration that could not read past its seed would be the OTHER
arm (``--prepass-payload``, where the cut REPLACES the base and the tools are withdrawn), and
building both behaviours behind one name is how a flag stops meaning anything.
"""
if plan_reviewer is not None and checkpoint_dir is not None:
raise ExplorationError(
@ -1614,7 +1642,10 @@ async def explore(
# With no provider installed this is a no-op tracer and every event is discarded, which is
# exactly what "tracing is off" has meant since U14.
with exploration_tracer().start_as_current_span(EXPLORATION_SPAN) as span:
result = await workflow.run(prompt)
# The seed rides in the TASK MESSAGE, never in ``prompt`` itself: ``_finish`` below builds
# the mandate's ``objective`` from ``prompt``, and a commission whose objective carried the
# whole cut would be unreadable to the person who wrote it.
result = await workflow.run(f"{prompt}\n\n{seed_context}" if seed_context else prompt)
stop, _ = await _drive(
workflow,
result,