feat(prepass): one renderer and one artefact carry the declaration out of the run [skip-docs]

[skip-docs]: CLI-flagget og README-blokka kommer i neste commit.

`prepass_notice` er ENESTE renderer, tar den ALT OPPLOESTE deklarasjonen (aldri en
payload-sti -- en renderer som leste fila paa nytt ville vaert en andre oppløsning fri
til aa vaere uenig med kjoeringen den beskriver), og returnerer `None` uten payload.
Omisjonen er entydig her paa en maate `proposal_review_notice`s bevisst ikke er: en
kjoering sier ingenting om et kutt fordi operatoeren ikke ga noe, og det finnes
noeyaktig EN maate aa gi et paa. Golden-transkriptet er det uavhengige, eksisterende
vitnet for den halvdelen. To kallsteder: dry-run og full kjoering.

`outbox.write_prepass` skriver `{run_id}-prepass.json` IFF et payload ble gitt --
`write_proposal_reviews`-regelen, og her gjoer den en andre jobb: siden et payload
TREKKER navigatoerverktoeyene er `{run_id}-debate.json`s `tool_calls` tom ved
konstruksjon paa denne stien, og DEN fila skrives ubetinget nettopp fordi et tomt spor
ER S2c-regresjonen. Uten dette artefaktet ved siden av ville "trukket med vilje" og
"regrert" lest likt. TILSTEDEVAERELSEN er det som skiller dem, og en egen arm
observerer BEGGE filene paa SAMME kjoering.

Skrevet fra `finally` (`write_parse_failures`-presedensen) ved et DIREKTE kall, ikke
via `_write_or_report`: den helperens paakrevde `in_flight` bindes foerst inne i
genererings-blokka, og `None` der ville latt en `OSError` fortrenge en `BudgetExceeded`
i luften -- noeyaktig defekten helperen finnes for. En egen arm driver et budsjettstopp
midt i debatten og krever at deklarasjonen likevel ligger der.

Regel -> ANTALL i baade rendereren og artefaktet; en arm beviser at 20 tilbakeholdte
konsept-ider naar HVERKEN stdout eller artefaktet mens antallet gjoer det.

1446 passed / 5 skipped (fra 1440/5, +6, 0 fjernet). ruff + mypy rene. Golden
`shasum -a 1` av INNHOLDET = ea8c534773acdbe41ae68f2c55724d69aaf8be4f, BYTE-UENDRET.

Co-Authored-By: Claude <claude-opus-5>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-07 11:17:38 +02:00
commit d3476d55ee
3 changed files with 154 additions and 0 deletions

View file

@ -219,6 +219,31 @@ def write_debate_tools(
return path
def write_prepass(
outbox_dir: str,
run_id: str,
*,
declaration: Mapping[str, Any],
) -> Path:
"""Write ``{run_id}-prepass.json`` — the CUT this run was given (order 20260907T080223Z).
Written IFF a payload was supplied, including when the cut withheld nothing
``write_proposal_reviews``' rule, and here it does a second job. Since a payload WITHDRAWS the
navigator tools, ``{run_id}-debate.json``'s ``tool_calls`` is empty by construction on this
path; and that file is written unconditionally precisely because an empty trace IS the S2c
regression (a debate that navigated nothing looks exactly like a cheap one). Without this
artefact beside it, "withdrawn by design" and "regressed" would read identically. Its PRESENCE
is what tells them apart.
Takes an already-rendered plain mapping (``prepass.declaration_payload``) so the RAW output
layer stays framework-free ``write_exploration``'s rule, same reason."""
directory = Path(outbox_dir)
directory.mkdir(parents=True, exist_ok=True)
path = directory / f"{run_id}-prepass.json"
path.write_text(_dump({"run_id": run_id, "prepass": dict(declaration)}), encoding="utf-8")
return path
def write_plan_review(
outbox_dir: str,
run_id: str,

View file

@ -838,6 +838,36 @@ def unkeyed_verdicts_notice(unkeyed: int) -> str | None:
)
def prepass_notice(declaration: prepass.PrepassDeclaration | None) -> str | None:
"""Render the CUT this run was given, or ``None`` when it was given none.
ONE renderer, N callsites (-(p)), taking the ALREADY-RESOLVED declaration rather than a
payload path: a renderer that re-read the file would be a second resolution free to disagree
with the run it describes.
``None`` without a payload omission, never an empty row (``mandate.announce``'s rule, which
``cost_baseline_notice`` and ``skipped_links_notice`` both follow). Here the omission is
unambiguous in a way ``proposal_review_notice``'s deliberately is not: a run says nothing about
a cut because the operator supplied no payload, and there is exactly one way to supply one. The
golden transcript is an independent, pre-existing witness for that half a renderer that
always returned a line would print in the demo and go red there.
The withheld concepts appear as rule -> COUNT, never as ids: the same rule the rendering
follows, for the same measured reason (34 451 o200k tokens of ids on a real corpus), and
because an operator reading a run summary wants to know WHAT was dropped and HOW MUCH, not
which. The full list is in the payload the operator already holds."""
if declaration is None:
return None
rules = ", ".join(f"{rule} ({count})" for rule, count in declaration.withheld_rules)
return (
f" Knowledge base: a DECLARED CUT was used — {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}; "
f"cut computed for: {declaration.question}"
)
def skipped_links_notice(skipped: tuple[okf.SkippedLink, ...]) -> str | None:
"""Render what the run could NOT read, or ``None`` when every cross-link was followed.
@ -1182,6 +1212,18 @@ async def run_project(
# the S2c regression itself, so it must be readable rather than inferred from an absence.
if outbox_dir is not None:
assert run_id is not None # narrowed by the step-0 guard (no wall-clock default)
if prepass_declaration is not None:
# BEFORE the debate trace, and by a DIRECT call rather than ``_write_or_report``:
# that helper's required ``in_flight`` is bound only inside the generation block
# below, and passing ``None`` here would let an OSError displace an in-flight
# ``BudgetExceeded`` — the very defect it exists to prevent. Written from the
# ``finally`` so a budget stop mid-debate still leaves the declaration, and built
# from the SAME object ``RunResult.prepass`` carries, never a second load.
outbox.write_prepass(
outbox_dir,
run_id,
declaration=prepass.declaration_payload(prepass_declaration),
)
outbox.write_debate_tools(
outbox_dir, run_id, tool_calls=tool_call_payload(debate_tool_calls)
)
@ -3498,6 +3540,9 @@ def main(argv: list[str] | None = None) -> int:
# of its own now OPENS, so the disagreement has to be said out loud or nothing ever reports
# that the run's artefacts name something other than the path the operator typed.
id_notice = bundle_id_notice(report.bundle_id_source)
cut_notice = prepass_notice(report.prepass)
if cut_notice is not None:
print(cut_notice)
if id_notice is not None:
print(id_notice)
return 0
@ -3575,6 +3620,11 @@ def main(argv: list[str] | None = None) -> int:
id_notice = bundle_id_notice(result.provenance.bundle_id_source)
if id_notice is not None:
print(id_notice)
# The CUT this run was given, read off the run's OWN declaration rather than off argv, for
# the reason above: stdout and ``{run_id}-prepass.json`` are built from the same object.
cut_notice = prepass_notice(result.prepass)
if cut_notice is not None:
print(cut_notice)
# Full run only, and structurally so: the fold happens BELOW the ``--live-dry-run`` cut, so a
# dry run has nothing to report here (contrast the three notices above, all resolved above it).
fold_notice = unkeyed_verdicts_notice(result.unkeyed_verdicts)