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

@ -860,8 +860,17 @@ def prepass_notice(declaration: prepass.PrepassDeclaration | None) -> str | None
if declaration is None:
return None
rules = ", ".join(f"{rule} ({count})" for rule, count in declaration.withheld_rules)
# ONE renderer, two arms — because the number of concepts delivered says nothing at all about
# whether the run could still open the rest, and an operator reading a summary that reported
# "8 of 630" without that would draw the wrong conclusion in exactly one of the two cases.
role = (
"a DECLARED CUT SEEDED the exploration (the rest of the base stayed reachable with the "
"navigation tools)"
if declaration.rest_reachable
else "a DECLARED CUT was used"
)
return (
f" Knowledge base: a DECLARED CUT was used — {declaration.delivered} of "
f" Knowledge base: {role}{declaration.delivered} of "
f"{declaration.considered} concept(s) delivered, {declaration.withheld} withheld"
f"{' by rule: ' + rules if rules else ''}. "
f"Base {declaration.bundle_id} at ref {declaration.ref}; "
@ -1059,27 +1068,19 @@ async def run_project(
prepass_declaration: prepass.PrepassDeclaration | None = None
debate_tools: list[Any]
if prepass_payload is not None:
prepass.check_payload_shape(prepass_payload)
prepass.verify_against_bundle(
# ONE admission gate, shared with the exploration's seeding door: shape, then the
# mounted base, then the empty-delivery refusal. Two copies of what makes a payload
# admissible would let one door accept what the other refuses (kø-(p)).
prepass.admit_payload(
prepass_payload,
bundle_dir=bundle_dir,
resolved_id=resolved,
dimension=dimension_id,
)
if not prepass_payload.excerpts:
# Measured: ``delivered == 0`` is reachable only when every concept failed to
# match (the producer REFUSES the other empty case, where concepts matched and the
# budget admitted none). So this is evidence of ABSENCE for this question at this
# ref, and saying it is better than two silent alternatives: an empty prompt, or
# falling through to the citation guard below, whose message names ``docs_dir`` —
# ``None`` on this path. SS 7.3's own posture: the skill stops and says so.
raise prepass.PrepassRefused(
f"the pre-pass delivered 0 of {prepass_payload.denominators.considered} "
f"concepts for the question {prepass_payload.question!r} at ref "
f"{prepass_payload.bundle.ref}; an empty cut is evidence that this knowledge "
"base does not answer that question, not something to run a debate over"
)
prepass_declaration = prepass.declaration_of(prepass_payload)
# ``rest_reachable=False`` is the FACT this arm establishes four lines below by
# emptying ``debate_tools`` — stated, never defaulted, because the other arm keeps
# them and a declaration that could not tell the two apart would describe neither.
prepass_declaration = prepass.declaration_of(prepass_payload, rest_reachable=False)
context = prepass.render_context(prepass_payload)
# Citations over the DELIVERED concepts alone: a stamp citing the whole corpus for a
# proposal that saw eight documents re-creates the undeclared claim this seam removes.
@ -2395,6 +2396,22 @@ def main(argv: list[str] | None = None) -> int:
"--bundle-dir; refused with --portfolio, --report, --proposals-from-mandate, "
"--dimension-config and --explore.",
)
parser.add_argument(
"--prepass-seed",
default=None,
metavar="FILE",
help="The OTHER arm of the same door (Q5=B): hand the EXPLORATION a declared cut as its "
"STARTING POINT and KEEP the four navigator tools. FILE is one contract-conformant OKF "
"consumption pre-pass payload (okf-consumption/1), admitted by exactly the checks "
"--prepass-payload applies — identity, sha256, the delivered text re-derived from the "
"mounted document, the verdict layer — before a single model call. The difference is what "
"happens next: the cut and its three denominators join the exploration's task message, "
"and the loop may still open anything else in the base (contract SS 2.2 permits what the "
"payload 'explicitly names as reachable'). The cut is printed and recorded in "
"{run_id}-exploration.json, which says rest_reachable so a reader can tell a seeded run "
"from a bounded one. REQUIRES --explore; refused with --prepass-payload (two opposite "
"arms of one decision), --portfolio, --report and --checkpoint-dir.",
)
parser.add_argument(
"--proposal-review",
action="store_true",
@ -2655,6 +2672,9 @@ def main(argv: list[str] | None = None) -> int:
# ABOVE every dispatch, so an omission here is a silent DROP — the operator would be
# told nothing and the declared cut would simply never happen.
"--prepass-payload": args.prepass_payload is not None,
# And the seeding arm, listed for the identical reason: report mode returns above the
# exploration dispatch too, so an omission here is a silent DROP and not a refusal.
"--prepass-seed": args.prepass_seed is not None,
# The three U12 flags, listed for exactly that reason: report mode returns before the
# resume dispatch, so an omission here is a silent drop, not a refusal.
"--checkpoint-dir": args.checkpoint_dir is not None,
@ -2744,6 +2764,10 @@ def main(argv: list[str] | None = None) -> int:
# operator who wrote --portfolio --prepass-payload has to hear which of the two is
# wrong, and an arm asserting on the shared token could not tell the two apart.
"--prepass-payload": args.prepass_payload,
# The seeding arm sits on the same side and by NAME for the same reason: it requires
# --explore, which this mode also refuses, so falling through would tell an operator
# who wrote --portfolio --prepass-seed to add a second flag --portfolio refuses too.
"--prepass-seed": args.prepass_seed,
# And the asynchronous half of the same door, on the same side of the partition and by
# NAME for the same reason.
"--checkpoint-dir": args.checkpoint_dir,
@ -2794,6 +2818,49 @@ def main(argv: list[str] | None = None) -> int:
)
return 1
# The SEEDING arm's three refusals, placed ABOVE the replacing arm's block on purpose: given
# both flags, the block below would answer with "--prepass-payload and --explore cannot be
# combined", which names neither of the two flags the operator actually put in conflict. At
# FUNCTION level, never nested under another flag's branch, for the F4 reason its neighbours
# are: under one, a bare combination falls through to a dispatch that drops the flag silently.
if not args.portfolio and args.prepass_seed is not None:
if args.prepass_payload is not None:
# TWO OPPOSITE ARMS OF ONE DECISION, and merging them is not defined: one WITHDRAWS
# the navigator tools because the cut replaces the base, the other KEEPS them because
# the cut is where to start. A run holding both would have to silently pick, and the
# picked one would be a policy nobody wrote down.
print(
"run refused: --prepass-payload and --prepass-seed are two opposite arms of one "
"decision (the first REPLACES the knowledge base with the cut and withdraws the "
"navigation tools; the second uses the cut as a STARTING POINT and keeps them). "
"Choose which one this run is",
file=sys.stderr,
)
return 1
if args.explore is None:
# The ``--explore-config`` case verbatim: a seed for a loop that never runs would be
# loaded, verified, paid for in I/O and then dropped.
print(
"run refused: --prepass-seed requires --explore (the cut seeds an EXPLORATION's "
"starting point; without one there is no loop to seed, and the debate's own arm "
"is --prepass-payload)",
file=sys.stderr,
)
return 1
if args.checkpoint_dir is not None:
# A parked leg writes {run_id}-exploration.json from its ``finally`` WITH the
# declaration; the resumed leg runs in a process that never saw the payload and
# OVERWRITES the same file with ``prepass: null``. A declaration that evaporates
# halfway is worse than one refused, and it would do so silently — so this is refused
# rather than left to erase itself.
print(
"run refused: --prepass-seed and --checkpoint-dir cannot be combined (the resumed "
"leg runs in a process that never saw the payload, and its own artefact would "
"overwrite the parked leg's declaration of the cut with nothing)",
file=sys.stderr,
)
return 1
# The pre-pass door's four remaining refusals, at FUNCTION level and never nested under
# another flag's branch: under one, a bare combination would fall straight through to a
# dispatch that drops the payload in silence (the F4 class).
@ -3214,6 +3281,16 @@ def main(argv: list[str] | None = None) -> int:
print(f"run refused: {exc}", file=sys.stderr)
return 1
# The seeding arm's payload, loaded here and by the SAME loader: one reader of one file
# format, never a second (kø-(p)). What differs between the two arms starts after admission.
prepass_seed: prepass.PrepassPayload | None = None
if args.prepass_seed is not None:
try:
prepass_seed = load_prepass_payload(args.prepass_seed)
except (FileNotFoundError, ValidationError, ValueError) as exc:
print(f"run refused: {exc}", file=sys.stderr)
return 1
# The egress config, loaded fail-fast alongside the commission. Degrading a broken one to "no
# external services" would make the announcement describe a run nobody configured, and a
# partially-parsed one could contact a subset nobody chose.
@ -3316,6 +3393,41 @@ def main(argv: list[str] | None = None) -> int:
else PlanReviewDecision.revise(answer.feedback),
)
# The seeding arm's admission, HOISTED above the try/finally below for the økt-57 reason the
# resume loads are hoisted: this is a refusal, and a refusal must not first overwrite
# {run_id}-exploration.json with an empty trace. It also has to happen before the first model
# call — at the exit code, a refusal after the spend looks exactly like one before it.
seed_declaration: prepass.PrepassDeclaration | None = None
seed_context = ""
if prepass_seed is not None:
assert args.bundle_dir is not None # guarded: --prepass-seed -> --explore -> --bundle-dir
try:
# This door OPENS a base, so it carries that gate itself rather than trusting the
# tool-side one to fire later (S7a-3: every opening door gets its own, and its own
# mutation). A base whose concepts name two corpora cannot be the one a cut is OF.
okf.assert_declared_ids_agree(okf.navigate_bundle(args.bundle_dir))
prepass.admit_payload(
prepass_seed,
bundle_dir=args.bundle_dir,
resolved_id=okf.reconcile_bundle_id(args.bundle_dir),
# NOT scoped, and that is measured rather than overlooked: the exploration builds
# ``navigator_tools(bundle_dirs)`` with no dimension at all, so scoping the seed
# would refuse text the very same loop can open with ``read_file`` a moment later.
# The DEBATE downstream stays scoped exactly as it is today.
dimension=None,
)
except (FileNotFoundError, ValidationError, ValueError) as exc:
print(f"run refused: {exc}", file=sys.stderr)
return 1
seed_declaration = prepass.declaration_of(prepass_seed, rest_reachable=True)
seed_context = prepass.render_seed(prepass_seed)
# Printed HERE, before the loop it seeds, rather than after: the announcement contract is
# that a commission is declared before the work it commissions, and a run whose budget is
# exhausted mid-exploration must still have said what it started from.
cut_notice = prepass_notice(seed_declaration)
assert cut_notice is not None # a declaration always renders; ``None`` means no cut
print(cut_notice)
if args.explore is not None or resumed is not None:
exploration_trace = ExplorationTrace()
exploration: ExplorationResult | None = None
@ -3356,6 +3468,9 @@ def main(argv: list[str] | None = None) -> int:
plan_reviewer=terminal_plan_reviewer() if args.plan_review else None,
# The U12 door. Mutually exclusive with the one above, refused at the top.
checkpoint_dir=args.checkpoint_dir,
# Q5=B. Empty unless --prepass-seed was given, and an empty string leaves
# the task message byte-identical to what every run built before today.
seed_context=seed_context,
)
)
except PlanReviewParked as parked_exc:
@ -3387,6 +3502,13 @@ def main(argv: list[str] | None = None) -> int:
stop=exploration.stop if exploration is not None else None,
completed=exploration is not None,
mandate=exploration.mandate if exploration is not None else None,
# From the SAME object the notice was rendered from, never a second load:
# stdout and the artefact must describe one cut, not two (kø-(p)).
prepass=(
prepass.declaration_payload(seed_declaration)
if seed_declaration is not None
else None
),
),
)
if budget_now is not None: