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
188 lines
9.6 KiB
Python
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
|