feat(visibility): en uforankret kjoering sier det - felt + linje (ORDRE 20260821T092039Z)

Maalt oekt 48: en bundle-kjoering uten cost-baseline.json gikk rc 0 uten et ord, og
`grep baseline provenance.py outbox.py` ga null treff - hverken stdout, stempelet eller
utboksen bar at validatorens steg 0 ble hoppet over.

To tenner, begge smaa, og begge fra kjoeringens ENE oppslag av baselinen (koe-(p)):

1. ProvenanceStamp.cost_baseline_anchored - PAAKREVD bool uten default. Begge defaults
   lyver: True lar en glemsom konstruktoer paastaa en ankring som ikke skjedde, False
   underrapporterer en ekte. Naar utboksen gratis (write_proposal dumper hele stempelet).
   DryRunReport baerer det samme - en dry-run stopper foer noe stempel finnes.
2. run.cost_baseline_notice(anchored) - ENESTE renderer, tar den alt opploeste booleanen,
   returnerer None naar kjoeringen ER forankret (omisjon, aldri en tom rad). Printes paa
   tre flater: --live-dry-run, full enkeltkjoering, og per prosjekt i portefoeljemodus.

IKKE foldet inn i mandate.announce, og det er en MAALING: den fyrer kun med --mandate, saa
nettopp de bare bundle-dry-runsene defekten ble maalt paa ville fortsatt sagt ingenting -
og den renderes foer run_project, altsaa foer noen har opploest baselinen.

Ankeringen forblir VALGFRI (en pre-amendment-base kjoerer uendret) - dette er synlighet,
ikke en ny nekt. Golden-transkriptet er byte-uendret: demoen kjoerer en base som HAR fila.

Load-bearing MAALT (tests/test_baseline_visibility_loadbearing.py, 11 tester), seks
mutasjoner alle roede mot HELE suiten + groenn kontroll 885/5: konstant stamp-wiring
(3 roede) - konstant dry-run-wiring (1) - detach dry-run-printen (1) - renderer returnerer
alltid linja (2, inkl. den forankrede kontrollen) - detach full-run-printen (1) - detach
portefoelje-printen (1). Portefoelje-armen er DEFENSIV og uttalt (ingen referanse-prosjekt
setter bundle_dir; budget_stop-presedensen, crafted PortfolioResult).

Det paakrevde feltet tvang fem eksisterende test-konstruktoerer til aa ta stilling.

Dokumentene som beskrev den gamle stillheten er rettet: kunnskapsbase-for-en-kjoring.md
S4.1 (tabellraden re-maalt live), S6 og S7; README «How it is set up»; CLAUDE.md S4.0-raden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DA6HAF8HFQxGYC2h6ypRQe
This commit is contained in:
Kjell Tore Guttormsen 2026-08-21 12:21:48 +02:00
commit 156312c32e
11 changed files with 481 additions and 17 deletions

View file

@ -57,6 +57,20 @@ class ProvenanceStamp(BaseModel):
role: str
validator_decision: Literal["validated", "rejected"]
token_usage: int
#: Was the deterministic gate ANCHORED to the project's own cost lines? ``True`` means
#: ``validate_proposal`` ran its stage-0 reconciliation (every ``affected_item`` checked against
#: a real ``CostBaseline`` line, within tolerance, BEFORE the solver); ``False`` means the
#: bundle shipped no ``cost-baseline.json``, so that stage was SKIPPED and the gate reasoned
#: only about numbers the proposal itself supplied. Anchoring stays OPTIONAL (a pre-amendment
#: bundle is legitimately un-anchored) — this field does not gate anything, it makes the skip
#: legible. A STRUCTURED field rather than prose, for the reason ``BudgetExceeded`` carries
#: ``kind``/``limit``/``observed`` as fields (kø-(y)): "was the falsifier anchored" is an
#: operative question that must be readable by machine.
#:
#: REQUIRED, with no default, because both defaults lie: ``True`` would let a constructor that
#: forgot claim an anchoring that never happened, and ``False`` would under-claim a real one.
#: A binary fact about a falsifier has no honest default.
cost_baseline_anchored: bool
#: External service calls the run made (B4). EMPTY is a positive statement — "nothing outside
#: this process was contacted" — not an absent field, which is why it is always serialized.
external_calls: list[ExternalCall] = Field(default_factory=list)

View file

@ -172,6 +172,11 @@ class DryRunReport:
max_rounds: int
max_tokens: int
top_k: int
#: Whether a REAL run of this configuration would have its deterministic gate anchored to the
#: project's own cost lines (see ``ProvenanceStamp.cost_baseline_anchored``). Carried here too
#: because a dry run stops before any proposal exists, so there is no stamp to read it off —
#: and this surface is precisely where the un-anchored case was measured to be silent.
cost_baseline_anchored: bool
@dataclass(frozen=True)
@ -423,6 +428,38 @@ def _default_factory(profile: Profile | str) -> Callable[[str], BaseChatClient]:
return factory
#: The one line a run prints about its own anchoring. Rendered ONLY when the run is un-anchored:
#: an anchored run has nothing to warn about, and ``mandate.announce``'s rule is that a line for
#: something the run does not have is OMITTED rather than rendered empty.
_UNANCHORED_NOTICE = (
" Cost baseline: NONE in the bundle — this run is un-anchored: the validator's stage 0 "
"(reconciling each proposed cost line against the project's own) is SKIPPED"
)
def cost_baseline_notice(anchored: bool) -> str | None:
"""Render the un-anchored notice, or ``None`` when the run IS anchored.
ONE renderer with N callsites, never N copies of the wording (-(p)) and it takes the
already-resolved BOOLEAN rather than a bundle path, so the printed line and the machine-readable
``ProvenanceStamp.cost_baseline_anchored`` can never disagree: both descend from the single
``okf.load_optional_cost_baseline`` call inside ``run_project``. A renderer that re-read the
bundle would be a second resolution of the same rule, free to drift from the run it describes.
**Not folded into ``mandate.announce``, and that is a measurement rather than a preference:**
``announce`` is printed only when ``--mandate`` is given, so the runs this notice exists for
the bare bundle dry-runs that exit 0 in silence would still say nothing. It also renders
BEFORE ``run_project`` is called, i.e. before anyone has resolved the baseline; putting the line
there would have required ``main`` to open the bundle itself.
English, like every other line this CLI prints; the Norwegian explanation of what an un-anchored
run means belongs in ``docs/kunnskapsbase-for-en-kjoring.md``, next to the domain expert.
Tense-neutral on purpose ("is SKIPPED"): the same string serves ``--live-dry-run`` (where the
run has not happened) and a completed run (where it has)."""
return None if anchored else _UNANCHORED_NOTICE
async def run_project(
project_id: str,
profile: Profile | str = Profile.LOCAL,
@ -585,6 +622,7 @@ async def run_project(
max_rounds=max_rounds,
max_tokens=max_tokens,
top_k=top_k,
cost_baseline_anchored=baseline is not None,
)
# The MCP lifecycle (Trekk B2): entered HERE, after the dry-run cut above, so a dry run never
# opens a connection — its promise to stop before the first call covers egress too. Constructed
@ -710,6 +748,11 @@ async def run_project(
"validated" if isinstance(validator_outcome, ValidatedProposal) else "rejected"
),
token_usage=meter.tokens,
# Whether stage 0 of the deterministic gate had a baseline to reconcile against. Read off
# the SAME ``baseline`` the validator was handed, so the record cannot describe a different
# anchoring than the one that ran. The road path is anchored by construction (the reference
# project's own cost_items ARE the baseline); a bundle is anchored iff it ships the file.
cost_baseline_anchored=baseline is not None,
# B4: which external service the debate actually called. Read AFTER the debate, so it is a
# record rather than an intention. The honesty limit lives on ``ExternalCall`` itself: this
# is the call and its source, not a verified rendering of the service's answer.
@ -1684,6 +1727,14 @@ def main(argv: list[str] | None = None) -> int:
return 1
for r in portfolio_result.runs:
print(f"{type(r.outcome).__name__}: verdict id={r.verdict.id}")
# Per project, because anchoring is a per-project fact. DEFENSIVE and currently
# unreachable from this branch — measured, and said out loud for the same reason the
# ``budget_stop`` arm below is: no reference project sets ``bundle_dir``, so every
# portfolio run today takes the road path and is anchored by construction. The test
# that covers it drives a crafted ``PortfolioResult``, and says so.
run_notice = cost_baseline_notice(r.provenance.cost_baseline_anchored)
if run_notice is not None:
print(run_notice)
# One settlement per project: the mandate applies to each project in the pass, so
# each project answers for it separately. Empty without a mandate.
project_settlement = settle(r.coverage)
@ -1776,6 +1827,12 @@ def main(argv: list[str] | None = None) -> int:
f"max_tokens={report.max_tokens}, top_k={report.top_k}) — "
"ingen modellkall gjort (stoppet før første debate.run)"
)
# The measured silence this closes: a bundle without ``cost-baseline.json`` used to dry-run
# to rc 0 with nothing said about the gate's stage 0 being skipped. Printed AFTER the line
# it qualifies, and only when there is something to say.
notice = cost_baseline_notice(report.cost_baseline_anchored)
if notice is not None:
print(notice)
return 0
try:
@ -1813,6 +1870,11 @@ def main(argv: list[str] | None = None) -> int:
return 1
kind = type(result.outcome).__name__
print(f"{args.project_id}: {kind} (verdict id={result.verdict.id}, decision={args.decision})")
# Same notice, same renderer, read off the run's OWN stamp — so stdout and the outbox artefact
# cannot disagree about whether the gate was anchored.
notice = cost_baseline_notice(result.provenance.cost_baseline_anchored)
if notice is not None:
print(notice)
# The settlement against the commission (Trekk A4). Empty without a mandate, so an
# un-commissioned run prints exactly what it printed before.
settlement = settle(result.coverage)