portfolio-optimiser/tests/test_cost_baseline_flag_loadbearing.py
Kjell Tore Guttormsen 7b4f85d77c feat(p21): the PROJECT carries the price, so a run against a road normal can be anchored
Four paid stress rounds ran entirely UN-ANCHORED, all of them, because the one file
loader reads cost-baseline.json out of the BUNDLE and no vegnormal ships one: N100,
N200, N500 and R761 are knowledge, and knowledge carries requirements, never amounts.
The validator's stage 0 -- the one stage that tells an invented cost line from a line
this project actually buys -- was skipped in every single run, so "validated" could not
mean what it says. P20 G1/G2 measured real R761 process numbers (12.11 three times on
Soraasen, 1.1.1 on Lindaas) validating with amounts nobody had anywhere.

--cost-baseline FILE is PM decision (e), taken over the three alternatives P20 wrote
down. A LOADED object, never a path (prepass_payload's rule): the CLI owns the file and
loads it ONCE, so the notice, the stamp and every base of an --across-bundle pass all
descend from one read. ONE parse, two doors -- load_cost_baseline delegates to
load_cost_baseline_file -- while safe_resolve stays on the bundle door alone, because a
project's own schedule is legitimately outside every base. No tolerant twin: this path
exists only because an operator NAMED a file.

DEL B: five anchored context sets, a1-a3 with their line and a4 with none, so stage 0 is
what catches the falsification arm. THE ORDER'S OWN ARM (h) WAS FELLED BY MEASUREMENT:
"no baseline code is a requirement number the base declares" is measured 0 of 4 on the
project-coded sets and 5 of 5 on kontrakt-sorasen -- which is what R761 Prosesskoden IS,
a bill of quantities priced BY process code. The complement keeps both, and the order's
own mutation still bites.

DEL B3: the judge reports anchored (off the run's own stamp), priced per row, and WHICH
falsifier caught the falsification arm.

Load-bearing MEASURED, five mutations all red against the WHOLE suite, green control
1850/5 (from 1809/5, superset, 0 removed), golden byte-unchanged:
A3(i) the flag is read but the baseline is unused (3 red) . A3(ii) only the first base
gets it (1) . A3(iii) report_forbidden drops it (1) . B2(i) a4 gets a line (1, arm (g)
alone) . B2(ii) a code swapped to 12.11 (2, arms (f) and (h)).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 10:49:10 +02:00

396 lines
16 KiB
Python

"""P21 DEL A - the PROJECT carries the price, so a run against a road normal can be anchored.
**The measurement this closes.** Four paid stress rounds (P16/P18/P19/P17b/P20) ran ENTIRELY
un-anchored. The cause is one line: the only file loader reads ``cost-baseline.json`` out of the
BUNDLE directory (``okf.load_optional_cost_baseline``), and no vegnormal ships one — N100, N200,
N500 and R761 are knowledge, and knowledge carries requirements, never amounts. The validator's
stage 0 — the one stage that can tell an invented cost line from a line this project actually buys
— was therefore skipped in every single one, and ``validated`` could not mean what it says: P20
G1/G2 measured real R761 process numbers (``12.11`` three times on Søråsen, ``1.1.1`` on Lindås)
validating with amounts nobody had anywhere.
``--cost-baseline FILE`` is PM decision (e), taken over three alternatives P20 wrote down: (a)
refusing every requirement-shaped code un-anchored would make the one realistic context set
unmeasurable, (b) ``--require-cost-baseline`` as a default would leave no stress test at all, and
(c) K2's priced schedule is refused by MAJOR-4's own stated limit. (e) puts the price where it
belongs — with the project — and stage 0 judges again.
Arms: (a) the library seam anchors * (b) control: without it the same base is un-anchored *
(c) it is the SAME baseline the validator is handed, so stage 0 really judges * (d) two sources for
one baseline are refused at the library seam * (e) the free trip anchors too * (f) a missing file
and (g) a malformed one are refused with ``load_cost_baseline``'s own error classes * (h)(i)(j)(k)
four CLI refusals BY NAME, each with an rc-0 control on an argv that would otherwise be accepted *
(l) the CLI wiring, measured on the stamp * (m) the notice * (n) EVERY base of an ``--across-bundle``
pass gets the SAME schedule.
"""
from __future__ import annotations
import json
import shutil
from pathlib import Path
from typing import Any
import pytest
from pydantic import ValidationError
from portfolio_optimiser import okf, run
from portfolio_optimiser.ir import CostBaseline, CostBaselineLine
from portfolio_optimiser.simulation import ScriptedChatClient
from portfolio_optimiser.validator import Rejection, validate_proposal
_EXAMPLES = Path(__file__).resolve().parents[1] / "shared" / "examples"
#: A base that ships NO ``cost-baseline.json`` — the whole class this flag exists for.
_UNPRICED_SOURCE = _EXAMPLES / "bygg-energi-mikro"
_IR_PROJECTION = {
"project_id": "P-KNOWLEDGE",
"measure": "PLACEHOLDER - authored by this test to satisfy the bundle contract",
"affected_items": [{"code": "KNOW-1", "quantity": 10, "unit_cost": 100.0}],
"claimed_saving_nok": 500.0,
}
def _runnable(tmp_path: Path, *, name: str = "base") -> str:
root = tmp_path / name
shutil.copytree(_UNPRICED_SOURCE, root)
(root / "validator-input.json").write_text(json.dumps(_IR_PROJECTION), encoding="utf-8")
assert not (root / "cost-baseline.json").exists(), "the fixture must be UNPRICED"
return str(root)
def _schedule(tmp_path: Path, *, name: str = "cost-baseline.json", **codes: float) -> str:
"""The PROJECT's own price schedule, written OUTSIDE every knowledge base — which is the whole
point: ``safe_resolve`` guards the bundle door, and a project's schedule is legitimately not in
a bundle."""
path = tmp_path / name
path.write_text(
json.dumps(
{
"project_id": "P-KNOWLEDGE",
"items": {
code: {"quantity": 10.0, "unit_cost": unit} for code, unit in codes.items()
},
}
),
encoding="utf-8",
)
return str(path)
def _scripted(sink: list[str] | None = None) -> Any:
return lambda role: ScriptedChatClient(sink=sink, role=role, default_reply="ok")
# --- (a)/(b)/(c)/(d)/(e) the library seam ---------------------------------------------------------
async def test_a_project_schedule_anchors_a_base_that_ships_none(tmp_path: Path) -> None:
bundle_dir = _runnable(tmp_path)
baseline = okf.load_cost_baseline_file(_schedule(tmp_path, RIGG=1000.0))
report = await run.run_project(
"P-KNOWLEDGE",
"local",
docs_dir=bundle_dir,
bundle_dir=bundle_dir,
cost_baseline=baseline,
live_dry_run=True,
)
assert isinstance(report, run.DryRunReport)
assert report.cost_baseline_anchored is True
async def test_control_without_the_schedule_the_same_base_is_unanchored(tmp_path: Path) -> None:
"""The discriminator for the arm above: the SAME base, the flag removed. Without this, "it is
anchored" could be a property of the fixture rather than of the file."""
bundle_dir = _runnable(tmp_path)
report = await run.run_project(
"P-KNOWLEDGE", "local", docs_dir=bundle_dir, bundle_dir=bundle_dir, live_dry_run=True
)
assert isinstance(report, run.DryRunReport)
assert report.cost_baseline_anchored is False
def test_the_supplied_schedule_is_what_stage_0_judges_against() -> None:
"""The stamp says anchored; this says the anchoring DOES something.
An implementation that read the file, stamped ``True`` and handed the validator ``None`` would
pass every other arm here — the mutation the order names as (i). Stage 0 either refuses a code
the project does not buy or it does not, and that is the only thing worth having.
"""
baseline = CostBaseline(
project_id="P-KNOWLEDGE",
items={"RIGG": CostBaselineLine(quantity=10.0, unit_cost=1000.0)},
)
from portfolio_optimiser.ir import AffectedItem, SavingsProposal
invented = SavingsProposal(
project_id="P-KNOWLEDGE",
measure="m",
affected_items=[AffectedItem(code="INDEKS-01", quantity=10.0, unit_cost=1000.0)],
claimed_saving_nok=100.0,
)
outcome = validate_proposal(invented, baseline=baseline)
assert isinstance(outcome, Rejection)
assert "cost baseline" in outcome.reason
# The control: the SAME magnitudes on a code the project DOES buy are not refused by stage 0.
real = SavingsProposal(
project_id="P-KNOWLEDGE",
measure="m",
affected_items=[AffectedItem(code="RIGG", quantity=10.0, unit_cost=1000.0)],
claimed_saving_nok=100.0,
)
second = validate_proposal(real, baseline=baseline)
assert not (isinstance(second, Rejection) and "cost baseline" in second.reason)
async def test_two_sources_for_one_baseline_are_refused_at_the_library_seam(
tmp_path: Path,
) -> None:
"""(d) Checked in ``run_project`` and not only in the CLI: the library takes the same two
arguments, and a library caller must not reach a state the CLI refuses by name."""
bundle_dir = _runnable(tmp_path)
baseline = okf.load_cost_baseline_file(_schedule(tmp_path, RIGG=1000.0))
with pytest.raises(ValueError, match="two sources for one baseline"):
await run.run_project(
"P-KNOWLEDGE",
"local",
docs_dir=bundle_dir,
bundle_dir=bundle_dir,
cost_baseline=baseline,
derive_cost_baseline=True,
live_dry_run=True,
)
async def test_it_satisfies_the_anchoring_requirement(tmp_path: Path) -> None:
"""(e) ``--require-cost-baseline`` is the guarantee; this is one of the two ways to meet it."""
bundle_dir = _runnable(tmp_path)
baseline = okf.load_cost_baseline_file(_schedule(tmp_path, RIGG=1000.0))
report = await run.run_project(
"P-KNOWLEDGE",
"local",
docs_dir=bundle_dir,
bundle_dir=bundle_dir,
cost_baseline=baseline,
require_cost_baseline=True,
live_dry_run=True,
)
assert isinstance(report, run.DryRunReport)
assert report.cost_baseline_anchored is True
# --- (f)/(g) the loader's error classes -----------------------------------------------------------
def test_a_missing_schedule_is_refused(tmp_path: Path) -> None:
with pytest.raises(FileNotFoundError):
okf.load_cost_baseline_file(str(tmp_path / "nope.json"))
def test_a_malformed_schedule_is_refused(tmp_path: Path) -> None:
"""``load_cost_baseline``'s own classes, and there is no tolerant twin: this path exists only
because an operator NAMED a file, so degrading its absence would answer an explicit order with
a silently un-anchored run."""
bad = tmp_path / "bad.json"
bad.write_text('{"project_id": "P", "items": {"X": {"quantity": -1, "unit_cost": 0}}}', "utf-8")
with pytest.raises(ValidationError):
okf.load_cost_baseline_file(str(bad))
def test_the_bundle_loader_still_parses_through_the_same_seam(tmp_path: Path) -> None:
"""ONE parse, two doors (kø-(p)). What differs is the RESOLUTION: ``safe_resolve`` stays on the
bundle door alone, because a project's own schedule is legitimately outside every base."""
base = tmp_path / "b"
base.mkdir()
(base / "cost-baseline.json").write_text(
json.dumps({"project_id": "P", "items": {"X": {"quantity": 1, "unit_cost": 2}}}), "utf-8"
)
assert okf.load_cost_baseline(str(base)).items["X"].unit_cost == 2.0
# --- (h)/(i)/(j)/(k) four CLI refusals, each with an rc-0 control ----------------------------------
def test_cli_requires_a_knowledge_base(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
"""(h) On the road path the baseline IS ``Project.cost_items``, so a file there is a second
source for one fact with nothing to break the tie (``--require-cost-baseline``'s reason)."""
rc = run.main(["P1", "--docs-dir", "docs", "--cost-baseline", _schedule(tmp_path, RIGG=1000.0)])
assert rc == 1
assert "--cost-baseline" in capsys.readouterr().err
def test_cli_refuses_two_sources_by_name(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
"""(i) BY NAME so the operator hears WHICH two flags conflict, rather than a traceback."""
bundle_dir = _runnable(tmp_path)
schedule = _schedule(tmp_path, RIGG=1000.0)
assert (
run.main(
[
"P-KNOWLEDGE",
"--bundle-dir",
bundle_dir,
"--cost-baseline",
schedule,
"--live-dry-run",
]
)
== 0
), "the control argv must be ACCEPTED"
capsys.readouterr()
rc = run.main(
[
"P-KNOWLEDGE",
"--bundle-dir",
bundle_dir,
"--cost-baseline",
schedule,
"--derive-cost-baseline",
"--live-dry-run",
]
)
assert rc == 1
err = capsys.readouterr().err
assert "--cost-baseline" in err and "--derive-cost-baseline" in err
def test_cli_is_refused_in_portfolio_mode(
tmp_path: Path, capsys: pytest.CaptureFixture[str]
) -> None:
"""(j) A portfolio pass keys on PROJECTS, each already anchored by its own ``cost_items``, so
ONE file could be right for at most one row out of N. BY NAME, its neighbours' reason."""
rc = run.main(["--portfolio", "--cost-baseline", _schedule(tmp_path, RIGG=1000.0)])
assert rc == 1
assert "--portfolio" in capsys.readouterr().err
def test_cli_is_refused_in_report_mode(tmp_path: Path, capsys: pytest.CaptureFixture[str]) -> None:
"""(k) Report mode returns ABOVE every dispatch, so an omission from the allowlist is a SILENT
DROP — the file would be accepted, nothing anchored, exit 0 (the F4 gap)."""
ledger = tmp_path / "ledger.json"
ledger.write_text("[]", encoding="utf-8")
assert run.main(["--report", "--ledger", str(ledger)]) == 0, "the control argv must be ACCEPTED"
capsys.readouterr()
rc = run.main(
["--report", "--ledger", str(ledger), "--cost-baseline", _schedule(tmp_path, RIGG=1000.0)]
)
assert rc == 1
assert "mode-exclusive" in capsys.readouterr().err
# --- (l)/(m) the CLI wiring and the notice --------------------------------------------------------
def test_cli_wiring_anchors_the_dry_run_and_says_so(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
"""(l)+(m) The flag must REACH ``run_project``, and the operator must be able to see that it
did on the FREE trip. rc 0 alone proves neither, so the discriminators are the two lines: the
un-anchored warning is GONE and the positive line names the file and the count."""
monkeypatch.delenv("PORTFOLIO_MODEL_MAP", raising=False)
bundle_dir = _runnable(tmp_path)
argv = ["P-KNOWLEDGE", "--bundle-dir", bundle_dir, "--live-dry-run"]
assert run.main(argv) == 0
before = capsys.readouterr().out
assert "Cost baseline: NONE in the bundle" in before
assert "Cost baseline: 2 lines from" not in before
schedule = _schedule(tmp_path, RIGG=1000.0, ASFALT=250.0)
assert run.main([*argv, "--cost-baseline", schedule]) == 0
after = capsys.readouterr().out
assert "Cost baseline: NONE in the bundle" not in after
assert f"Cost baseline: 2 lines from {schedule}" in after
def test_the_notice_is_omitted_when_nobody_named_a_file() -> None:
"""Omission where it is unambiguous — there is exactly one way to supply a schedule, so
silence means nobody did (``cost_baseline_notice``'s rule, kept)."""
assert run.cost_baseline_source_notice(None, 0) is None
assert run.cost_baseline_source_notice("x.json", 1) == (
" Cost baseline: 1 line from x.json — the validator's stage 0 reconciles every proposed "
"cost line against this project's own schedule"
)
# --- (n) every base of a multi-base pass ----------------------------------------------------------
async def test_every_base_of_an_across_bundle_pass_gets_the_same_schedule(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""(n) ONE project has ONE price schedule, so it anchors EVERY base.
The order's mutation (ii) is "only the first base gets it", and the assert is therefore per
BASE: a recorder that stopped at the first call would pass on exactly that mutation — the
vacuous-gate class this repo keeps measuring. Both calls are recorded and both must carry the
SAME object, because two reads of one file is already one resolution too many (kø-(p)).
"""
from portfolio_optimiser.mandate import Approach, Mandate
first = _runnable(tmp_path, name="one")
second = _runnable(tmp_path, name="two")
baseline = okf.load_cost_baseline_file(_schedule(tmp_path, RIGG=1000.0))
calls: list[dict[str, Any]] = []
async def _recorder(project_id: str, profile: Any = "local", **kwargs: Any) -> Any:
calls.append({"project_id": project_id, **kwargs})
class _Stub:
coverage: tuple[Any, ...] = ()
provenance = None
return _Stub()
monkeypatch.setattr(run, "run_project", _recorder)
mandate = Mandate(
objective="o",
success_criteria="s",
approaches=[
Approach(
id="a1",
label="one",
affected_codes=["RIGG"],
claimed_saving_nok=1.0,
bundle_id="one",
),
Approach(
id="a2",
label="two",
affected_codes=["RIGG"],
claimed_saving_nok=1.0,
bundle_id="two",
),
],
)
await run.run_mandate_across_bundles(mandate, [first, second], "local", cost_baseline=baseline)
assert len(calls) == 2, f"the dispatch ran {len(calls)} base(s), not two"
assert [c["bundle_dir"] for c in calls] == [first, second]
assert [c.get("cost_baseline") for c in calls] == [baseline, baseline], (
"a base was dispatched without the project's own schedule"
)
# The control: without the flag, no base is handed one — so the arm above measures the flag
# rather than a default.
calls.clear()
await run.run_mandate_across_bundles(mandate, [first, second], "local")
assert [c.get("cost_baseline") for c in calls] == [None, None]