portfolio-optimiser/tests/test_anchored_reserve_loadbearing.py
Kjell Tore Guttormsen 02ddc6735f feat(simulation): GO — demoen kjører levert VEGLYS-bundle, forankret på deres tall [skip-docs]
P3 a-c lukket. Pullen hentet commons 002f000+27cdce9: kriterium 8 grønt (nav-goldens
byte-uendret, målt både med git diff og shasum) og suiten uendret 785 — ingen abort.

Retningen på tallene er SNUDD (P3 b): manus-registerets kostlinjer er skrevet FRA
shared/examples/veglys-fv-soer/cost-baseline.json, ikke ved siden av den, og
baseline_from_scripted_candidate brukes ikke på denne stien — main() leser levert fil.
Overdrivelsen 2100000 er valgt utenfor commons' tall-inventar: målt fraværende fra
bundelen og over målt P90 1769915 (deres anslag var ~1770000). 600000/900000 ville
klarert gaten og aldri utløst Steg 5.

Målingen felte en defekt reserven skjulte: :g slår over i eksponentform ved 7. signifikante
siffer, så levert baseline printet 4.38615e+06. Reservens 300000 har seks siffer og nådde
aldri overgangen. _num erstatter :g begge steder.

Load-bearing MÅLT mot hele suiten, fem mutasjoner alle røde + grønn kontroll:
detach main-wiringen · reverter _num til :g · drift registeret ETT siffer (4386151 —
innenfor 5 %-toleransen, fanget av ingenting i 792 tester bortsett fra den nye) ·
sett flip_key til et token som finnes i bundelen · detach forankringen på bundle-stien.

785 -> 793 passed / 4 skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BUjfw4eJdwwnqHSXhfcY6i
2026-08-09 21:27:43 +02:00

188 lines
9.6 KiB
Python

"""P4 pkt. 0 — the demo's RESERVE bundle must anchor the deterministic gate to real cost lines.
The gap (egnethetsreview Funn 1, corrected by objection I1): the validator CAN reconcile a proposal
against the project's actual cost lines (S4.0, stage 0), but only when the knowledge base ships a
``cost-baseline.json``. No bundle under ``shared/examples/`` has that file — so in the demo the
validator reasoned only about numbers the proposal itself supplied, and an internally consistent
hallucination would clear the gate on stage.
The reserve cannot receive the file IN ``shared/``: the subtree is pull-only and demo criterion 8
requires the commons-owned goldens byte-unchanged. But that is a PLACEMENT constraint, not an
impossibility — the demo already runs on a COPY of the bundle, so a copy-and-extend variant gives an
anchored run without touching commons.
**Direction of derivation, and why it matters.** Here the baseline is derived FROM the scripted
register: the reserve's numbers are synthetic, so the script is the only ground truth available.
On GO day the direction reverses (plan P3 b) — the register's numbers are written FROM the
delivered ``cost-baseline.json``. Deriving in code, not by hand, is what stops the two from drifting
apart; drift is precisely the failure the 10 % test below models.
**The 10 % test** is the answer to "you generated the ground truth from the answer, so of course it
passes": deviate the baseline beyond the 5 % tolerance and the same, unchanged script must be
FORKASTET at stage 0 — before the solver — while the undeviated run is FORESLÅTT.
"""
from __future__ import annotations
import json
import subprocess
import sys
import pytest
from portfolio_optimiser import okf
from portfolio_optimiser.ir import CostBaseline, CostBaselineLine
from portfolio_optimiser.simulation import (
ScriptedCandidate,
_default_bundle_dir,
baseline_from_scripted_candidate,
materialize_anchored_bundle,
simulate_learning_loop,
)
from portfolio_optimiser.validator import Rejection, ValidatedProposal
def _deviated(baseline: CostBaseline, factor: float) -> CostBaseline:
"""The same baseline with every quantity scaled — the delivered numbers disagreeing with the
script's by ``factor``, which is exactly the GO-day risk this models."""
return CostBaseline(
project_id=baseline.project_id,
items={
code: CostBaselineLine(quantity=line.quantity * factor, unit_cost=line.unit_cost)
for code, line in baseline.items.items()
},
)
async def test_the_anchored_reserve_runs_the_whole_demo(tmp_path) -> None:
"""CONTROL: with the baseline derived from the script, the anchored reserve behaves exactly as
the demo narrates — hypothesis #1 falsified by the P90 stage, the corrected one validated.
This is the control that gives the 10 % test its meaning: a gate that rejects everything proves
nothing. It also pins WHICH stage rejects hypothesis #1 — if stage 0 started rejecting it, demo
criterion 2 would still show a REJECTED and a VALIDATED line while silently demonstrating a
different mechanism."""
bundle = materialize_anchored_bundle(tmp_path / "forankret")
result = await simulate_learning_loop(str(bundle), str(tmp_path))
assert isinstance(result.run_a.outcome, ValidatedProposal)
assert isinstance(result.run_b.outcome, ValidatedProposal)
assert result.run_a.refinements, "no falsification was fed back — Step 5 is not being shown"
assert "exceeds P90 feasible" in result.run_a.refinements[0].reason, (
"hypothesis #1 was rejected by some other stage than the P90 one the demo narrates"
)
async def test_a_deviating_baseline_forkaster_the_demo_run_before_the_solver(tmp_path) -> None:
"""LOAD-BEARING (the 10 % test): when the project's declared cost lines deviate by 10 % from
the numbers the script asserts, the run is FORKASTET at stage 0 — with the reconciliation
reason, not the P90 one.
Goes RED the moment the demo stops being anchored: without the ``cost-baseline.json`` in the
bundle the run path passes ``baseline=None``, stage 0 is skipped, and this same deviating
number changes nothing at all (the run ends FORESLÅTT, as ``test_..._runs_the_whole_demo``
above shows). The script is byte-identical in both tests — only the declared baseline moves."""
baseline = _deviated(baseline_from_scripted_candidate(_only_candidate()), 1.10)
bundle = materialize_anchored_bundle(tmp_path / "forankret", baseline=baseline)
result = await simulate_learning_loop(str(bundle), str(tmp_path))
outcome = result.run_a.outcome
assert isinstance(outcome, Rejection), (
"a proposal 10 % away from the project's declared cost lines was NOT rejected — the "
"deterministic gate is not anchored to the baseline"
)
assert "outside the 5.0% tolerance" in outcome.reason
assert "ENERGI-TOTAL-EL" in outcome.reason
assert "P90" not in outcome.reason, (
"rejected by the solver stage, not by the reconciliation stage 0 that must run BEFORE it"
)
def test_the_reserve_itself_ships_no_baseline(tmp_path) -> None:
"""The materializer must ADD something the reserve genuinely lacks — and must leave the
commons-owned bundle alone (criterion 8: the goldens stay byte-unchanged)."""
reserve = _default_bundle_dir()
assert okf.load_optional_cost_baseline(str(reserve)) is None, (
"the shared reserve now ships a cost baseline — the copy-and-extend variant is obsolete "
"and this whole seam should be re-measured"
)
bundle = materialize_anchored_bundle(tmp_path / "forankret")
assert okf.load_optional_cost_baseline(str(bundle)) is not None, (
"the materialized bundle is not readable by okf's own loader — the filename has drifted"
)
assert okf.load_optional_cost_baseline(str(reserve)) is None
def test_the_baseline_is_derived_from_the_scripted_register() -> None:
"""The baseline is DERIVED from the script's own cost lines, never typed alongside them: a
hand-written copy is a second source of the same numbers, and two sources drift."""
candidate = _only_candidate()
derived = baseline_from_scripted_candidate(candidate)
for reply in (candidate.overclaimed, candidate.corrected):
for item in json.loads(reply)["affected_items"]:
line = derived.items[item["code"]]
assert (line.quantity, line.unit_cost) == (item["quantity"], item["unit_cost"])
assert derived.project_id == candidate.project_id
def test_a_candidate_whose_two_replies_disagree_is_refused() -> None:
"""Validation, never repair. The two scripted replies must state the SAME cost lines: were they
to differ, hypothesis #1 would be rejected by stage 0 instead of by P90, and the demo's
REJECTED line would silently come from another mechanism than the one it narrates."""
candidate = _only_candidate()
skewed = ScriptedCandidate(
project_id=candidate.project_id,
overclaimed=candidate.overclaimed.replace("300000", "310000"),
corrected=candidate.corrected,
flip_key=candidate.flip_key,
)
with pytest.raises(ValueError):
baseline_from_scripted_candidate(skewed)
def test_the_demo_entry_point_runs_the_anchored_delivered_bundle() -> None:
"""LOAD-BEARING on the CALL SITE: the thing the operator actually runs on stage must be the
anchored variant — and since P3 (GO), the anchor is the DELIVERED bundle's own shipped
``cost-baseline.json``, not the script-derived reserve one. Goes RED if ``main`` is pointed back
at either the plain reserve or the anchored reserve.
The declared baseline is printed because an anchoring nobody can see is an anchoring nobody can
check: every other line of the demo is byte-identical whether the gate is anchored or not.
**The first form of this test was vacuous, and the mutation caught it.** It asserted
``"kostbaseline erklært" in stdout`` — but the un-anchored branch read "ingen kostbaseline
erklært", which CONTAINS that substring; and ``"ENERGI-TOTAL-EL" in stdout`` holds either way,
because the Step-2 line prints the proposal's own cost lines. Both survived the mutation. The
assertions below name the whole declared line and rule the other branch out explicitly.
The magnitude is asserted in FULL (``4386150``, not ``4.38615e+06``): ``:g`` switched to exponent
notation at the 7th significant digit, which the reserve's six-digit ``300000`` never reached —
so the delivered content exposed the formatting defect on its first run, and this assert is what
keeps it exposed."""
proc = subprocess.run(
[sys.executable, "-m", "portfolio_optimiser.simulation"],
capture_output=True,
text=True,
check=False,
)
assert proc.returncode == 0, proc.stderr
assert "kostbaseline erklært (ENERGI-VEGLYS-EL 4386150 x 1)" in proc.stdout, (
"the demo is not anchored on the DELIVERED cost baseline — either it ran a bundle without "
"one (the gate then reasons only about the proposal's own numbers), or it fell back to the "
"script-derived reserve baseline"
)
assert "validatorens stage 0 avstemmer" in proc.stdout
assert "uten kostbaseline" not in proc.stdout
assert "e+06" not in proc.stdout, "a cost magnitude regressed to exponent notation"
assert "tallene er syntetiske" not in proc.stdout, (
"the reserve's honesty sentence is on stage, so the run is NOT on delivered content"
)
def _only_candidate() -> ScriptedCandidate:
from portfolio_optimiser.simulation import _CANDIDATES, _PROJECT_ID
(candidate,) = [c for c in _CANDIDATES if c.project_id == _PROJECT_ID]
return candidate