D7 mirror candidate (p) `to_ore`, measured offline with the mutation harness. `to_ore` does not exist here (0 of 80 .py files in src+tests; positive control: `unit_cost` found in 19). Our money axis is the accumulated USD spend, and its conversion is the rounding to six decimals — present in FOUR literal copies with no named source (run.py:159, run_s10.py:110 and :130, costsim.py:125) while the share rounding one file over DOES have one (`_SHARE_DIGITS`). The sibling's drift form is present. Three of the four copies are never executed: replacing the whole expression with `999.0` left all 984 green at each. Their green under a detach was never evidence about the rounding — it was "not measured" (ansikt 4 on the apparatus). The default branch WAS pinned; the value branch was not. The one path that decides with the cost — the C3.5 pre-call USD belt — is a permanent no-op: `max_cost_usd` is set in 0 of 27 src modules (positive control: `max_budget_usd_per_call` is found by the same scan). The gate is built; no path hands it a cap. Seven mutations, all VALUE-PROVED with collateral controls green in both runs. No src change: folding the copies is a refactor, wiring the run-total cap is a feature. The tests pin today's boundary so neither lands silently. 984 -> 997 (strict superset, 0 lost node ids). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
261 lines
14 KiB
Python
261 lines
14 KiB
Python
"""Kø-(p) LOAD-BEARING: the USD cost conversion — one rule, four copies, three of them never run.
|
|
|
|
The sibling's ``to_ore`` entered the mirror queue because a money conversion had DRIFTED into
|
|
two copies under two rules, and the two copies met on the two sides of one goal comparison.
|
|
The mirrored claim is therefore not "do we have the function" but: **is our money conversion
|
|
one rule, and is that rule load-bearing where it decides something?**
|
|
|
|
Measured 2026-09-13. ``to_ore`` does not exist here (0 hits across 80 ``.py`` files in
|
|
``src``+``tests``; positive control: the same query finds ``unit_cost`` in 19). Our money axis
|
|
is not NOK->øre but the accumulated USD spend, ``total_cost_usd``, and its conversion is the
|
|
rounding to six decimals. That rounding exists in FOUR literal copies with no named source —
|
|
``run.py``'s ``_client_cost_usd``, ``run_s10.py``'s two persistence call sites, and
|
|
``costsim.py``'s per-cell estimate — while the sibling rule one file over (share rounding in
|
|
``valuereport.py``) DOES have a named source, ``_SHARE_DIGITS``. The sibling's drift form is
|
|
present here.
|
|
|
|
What the harness then showed is sharper than "pinned only at the edge". Replacing the WHOLE
|
|
rounding expression with the constant ``999.0`` left all 984 tests green at three of the four
|
|
sites (``run.py``:159, ``run_s10.py``:110 and :130) — those branches are never executed with a
|
|
cost at all, so their green under a detach was never evidence about the rounding (økt 39,
|
|
Verifiseringsloven ansikt 4 applied to the measuring apparatus). Only ``costsim.py`` was
|
|
covered. The default branch WAS pinned (``getattr(..., None)`` -> ``0.0`` is red in
|
|
``test_run_entrance``) — the key was pinned in its name and free in its value (økt 41).
|
|
|
|
And the one path that DECIDES with the cost, the C3.5 pre-call USD belt, is a permanent no-op:
|
|
``max_cost_usd`` is set in 0 of 27 ``src`` files (positive control: ``max_budget_usd_per_call``,
|
|
which IS wired, is found by the same scan). All four ``BudgetMeter(...)`` constructions in
|
|
``src`` take the default ``None``, so ``guard_before_call`` returns before it ever compares.
|
|
The gate is built; no path hands it a cap.
|
|
|
|
This file pins today's boundary. It makes NO ``src`` change: wiring a run-total USD cap into the
|
|
entrance is a feature with a CLI flag and a contract field (and the README/``--help`` parity
|
|
guard behind it), not a fix to a measured defect, and the per-call SDK cap
|
|
(``max_budget_usd_per_call``) already bounds live spend. What the tests forbid is the change
|
|
landing SILENTLY — and the rounding rule growing a fifth copy, or drifting to a different digit
|
|
count, without anyone noticing.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import ast
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Callable, Iterator
|
|
|
|
import pytest
|
|
from _scripted import ScriptedClient, reply
|
|
|
|
from portfolio_optimiser_claude.budget import BudgetExceeded, BudgetMeter
|
|
from portfolio_optimiser_claude.contracts import Contracts, TerminationContract
|
|
from portfolio_optimiser_claude.ir import load_validator_input
|
|
from portfolio_optimiser_claude.loop import ModelClient, ModelReply, _guarded_complete
|
|
from portfolio_optimiser_claude.run import main
|
|
|
|
BUNDLE = Path(__file__).resolve().parents[1] / "shared" / "examples" / "bygg-energi-mikro"
|
|
SRC = Path(__file__).resolve().parents[1] / "src" / "portfolio_optimiser_claude"
|
|
|
|
# A spend with MORE precision than the rule keeps: the rounded value and the raw value are
|
|
# different numbers, so a test that reads the persisted figure can tell which one was written.
|
|
_RAW_SPEND = 0.1234567891
|
|
_ROUNDED_SPEND = 0.123457 # round(_RAW_SPEND, 6)
|
|
|
|
# A spend that sits strictly between the cap and its own rounding: raw > cap (the belt must
|
|
# stop) but round(raw, 6) == cap (a belt reading the ROUNDED figure would let the call through).
|
|
_CAP_USD = 0.1
|
|
_OVERSPEND_RAW = 0.10000004
|
|
|
|
|
|
class CostingScriptedClient(ScriptedClient):
|
|
"""A scripted stand-in that DOES account USD — the fixture the rule reads.
|
|
|
|
``ScriptedClient`` carries no ``total_cost_usd`` at all, which is why every existing run-path
|
|
test exercises only the honest-null branch of ``_client_cost_usd``. Honesty rule (§1): this
|
|
is still a scripted stand-in, not a model; the cost is a fixture value, not a provider
|
|
figure.
|
|
"""
|
|
|
|
def __init__(self, replies: list[ModelReply], *, total_cost_usd: float) -> None:
|
|
super().__init__(replies=replies)
|
|
self.total_cost_usd = total_cost_usd
|
|
|
|
|
|
def _costing_factory(
|
|
replies: list[ModelReply], *, total_cost_usd: float
|
|
) -> Callable[[Contracts, float], ModelClient]:
|
|
def factory(contracts: Contracts, max_budget_usd_per_call: float) -> ModelClient:
|
|
return CostingScriptedClient(list(replies), total_cost_usd=total_cost_usd)
|
|
|
|
return factory
|
|
|
|
|
|
def _completed_run_replies() -> list[ModelReply]:
|
|
return [
|
|
reply("debate reasoning"),
|
|
reply("VERDICT: APPROVE"),
|
|
reply(json.dumps(load_validator_input(BUNDLE).model_dump())),
|
|
]
|
|
|
|
|
|
def _usage_after_run(tmp_path: Path, *, total_cost_usd: float) -> dict[str, object]:
|
|
out = tmp_path / "out"
|
|
code = main(
|
|
["--bundle", str(BUNDLE), "--out", str(out)],
|
|
client_factory=_costing_factory(_completed_run_replies(), total_cost_usd=total_cost_usd),
|
|
)
|
|
assert code == 0, "the fixture must reach the completed-run persistence branch"
|
|
payload: dict[str, object] = json.loads((out / "usage.json").read_text("utf-8"))
|
|
return payload
|
|
|
|
|
|
class TestTheRoundingRuleIsActuallyApplied:
|
|
"""The value branch of ``_client_cost_usd`` — never executed by the suite before this file.
|
|
|
|
Each assertion is its own test: a red test proves only its FIRST assert, and "the figure is
|
|
rounded" and "the figure is not the raw value" are two claims about two different mutations.
|
|
"""
|
|
|
|
def test_persisted_cost_is_quantized_to_six_decimals(self, tmp_path: Path) -> None:
|
|
usage = _usage_after_run(tmp_path, total_cost_usd=_RAW_SPEND)
|
|
assert usage["cost_usd"] == _ROUNDED_SPEND
|
|
|
|
def test_persisted_cost_is_not_the_raw_accumulated_spend(self, tmp_path: Path) -> None:
|
|
# The discriminating half: a detached rounding persists the raw float, which passes the
|
|
# test above only if that test is written as an approximate comparison. It is not.
|
|
usage = _usage_after_run(tmp_path, total_cost_usd=_RAW_SPEND)
|
|
assert usage["cost_usd"] != _RAW_SPEND
|
|
|
|
def test_the_value_branch_is_reached_at_all(self, tmp_path: Path) -> None:
|
|
# Positive control on the apparatus (ansikt 4): before this file, replacing the whole
|
|
# expression with a constant left all 984 green, because the branch never ran with a
|
|
# cost. This pins that a costing client now reaches it — without it, the two tests above
|
|
# could pass vacuously on a None.
|
|
usage = _usage_after_run(tmp_path, total_cost_usd=_RAW_SPEND)
|
|
assert usage["cost_usd"] is not None
|
|
|
|
|
|
class TestTheBeltDecidesOnTheRawSpend:
|
|
"""What the code COMPUTES WITH is not what it PERSISTS — and the gate must read the raw one.
|
|
|
|
Rounding before a comparison moves the threshold: a run that has crossed its cap by less
|
|
than half a micro-dollar would read as not-crossed. The sibling's defect was exactly this
|
|
shape — two sides of one money comparison computed under two rules.
|
|
"""
|
|
|
|
def _meter(self) -> BudgetMeter:
|
|
return BudgetMeter(
|
|
TerminationContract(max_rounds=1000, max_tokens=10_000), max_cost_usd=_CAP_USD
|
|
)
|
|
|
|
def test_the_belt_stops_on_a_spend_its_own_rounding_would_hide(self) -> None:
|
|
client = CostingScriptedClient([reply("never reached")], total_cost_usd=_OVERSPEND_RAW)
|
|
with pytest.raises(BudgetExceeded) as caught:
|
|
_guarded_complete(client, "prompt", role="proposer", meter=self._meter())
|
|
assert caught.value.kind == "cost_usd"
|
|
|
|
def test_the_stop_event_carries_the_raw_spend_not_the_rounded_one(self) -> None:
|
|
# The structured stop is the artifact's own record of what the gate saw (§8). If the
|
|
# belt ever reads a rounded figure, this is the number that changes.
|
|
client = CostingScriptedClient([reply("never reached")], total_cost_usd=_OVERSPEND_RAW)
|
|
with pytest.raises(BudgetExceeded) as caught:
|
|
_guarded_complete(client, "prompt", role="proposer", meter=self._meter())
|
|
assert caught.value.observed == _OVERSPEND_RAW
|
|
|
|
def test_control_the_rounded_spend_would_not_have_stopped(self) -> None:
|
|
# The positive control that makes the two tests above evidence rather than coincidence:
|
|
# the SAME meter does not stop on round(_OVERSPEND_RAW, 6). Without this, a belt that
|
|
# stopped on everything would satisfy them.
|
|
meter = self._meter()
|
|
meter.guard_before_call(round(_OVERSPEND_RAW, 6)) # no raise
|
|
assert round(_OVERSPEND_RAW, 6) == _CAP_USD
|
|
|
|
|
|
def _literal_round_digit_calls() -> Iterator[tuple[str, int, int]]:
|
|
"""Every ``round(x, <int literal>)`` in ``src``, as (module, lineno, digits).
|
|
|
|
A rounding whose digit count is a NAME (``_SHARE_DIGITS``) is a rule with one source and is
|
|
deliberately not collected here — that is the shape this file says the money rule lacks.
|
|
"""
|
|
for path in sorted(SRC.glob("*.py")):
|
|
tree = ast.parse(path.read_text("utf-8"))
|
|
for node in ast.walk(tree):
|
|
if not isinstance(node, ast.Call) or not isinstance(node.func, ast.Name):
|
|
continue
|
|
if node.func.id != "round" or len(node.args) != 2:
|
|
continue
|
|
digits = node.args[1]
|
|
if isinstance(digits, ast.Constant) and isinstance(digits.value, int):
|
|
yield (path.name, node.lineno, digits.value)
|
|
|
|
|
|
class TestTheMoneyRuleHasNotDrifted:
|
|
"""The copy count IS the finding: four literal copies, no named source (the sibling's form).
|
|
|
|
The sibling closed its version with ``assert run_mod.to_ore is ledger_mod.to_ore``. We have
|
|
no function to compare, so the equivalent guard is over the call sites themselves.
|
|
"""
|
|
|
|
def test_the_scan_finds_the_known_literal_roundings(self) -> None:
|
|
# Positive control FIRST (before any negative): the scanner CAN find what it looks for,
|
|
# and the denominator is the whole package, not a file.
|
|
modules = sorted({name for name, _, _ in _literal_round_digit_calls()})
|
|
assert len(list(SRC.glob("*.py"))) == 27, "denominator: src modules scanned"
|
|
assert modules == ["costsim.py", "run.py", "run_s10.py"]
|
|
|
|
def test_every_literal_usd_rounding_uses_six_digits(self) -> None:
|
|
digits = {d for _, _, d in _literal_round_digit_calls()}
|
|
assert digits == {6}, "one digit count across every copy — a second value IS the drift"
|
|
|
|
def test_there_are_exactly_four_copies_of_the_rule(self) -> None:
|
|
# Red when a fifth copy appears (drift) and red when one is folded into a named source
|
|
# (the fix) — either way the finding above stops being true and must be re-measured.
|
|
assert len(list(_literal_round_digit_calls())) == 4
|
|
|
|
def test_the_share_rule_by_contrast_has_a_named_source(self) -> None:
|
|
# The contrast is the point: one file over, the same package already knows how to give a
|
|
# rounding one source. The money rule is the one that does not.
|
|
valuereport = (SRC / "valuereport.py").read_text("utf-8")
|
|
assert "_SHARE_DIGITS" in valuereport
|
|
assert "round(" in valuereport
|
|
assert not [n for n, _, _ in _literal_round_digit_calls() if n == "valuereport.py"]
|
|
|
|
|
|
def _call_keywords_in_src() -> Iterator[tuple[str, str]]:
|
|
"""Every keyword argument NAME used in a call anywhere in ``src``, as (module, keyword)."""
|
|
for path in sorted(SRC.glob("*.py")):
|
|
tree = ast.parse(path.read_text("utf-8"))
|
|
for node in ast.walk(tree):
|
|
if isinstance(node, ast.Call):
|
|
for kw in node.keywords:
|
|
if kw.arg is not None:
|
|
yield (path.name, kw.arg)
|
|
|
|
|
|
class TestTheRunTotalUsdCapIsWiredNowhere:
|
|
"""RATCHET on a measured absence — the gate exists and no path gives it a cap.
|
|
|
|
``guard_before_call`` returns immediately when ``max_cost_usd is None``, and every
|
|
``BudgetMeter(...)`` in ``src`` takes that default. The belt is therefore a no-op outside its
|
|
own unit test. This is not asserted as desirable; it is pinned so that wiring it — a real
|
|
change to what bounds a live run — cannot land silently while the documented finding still
|
|
claims otherwise.
|
|
"""
|
|
|
|
def test_the_keyword_scan_finds_a_cap_that_IS_wired(self) -> None:
|
|
# Positive control before the negative (økt 29): the scan can find a USD cap keyword, so
|
|
# the null below is a measurement and not a broken query.
|
|
wired = {
|
|
module for module, kw in _call_keywords_in_src() if kw == "max_budget_usd_per_call"
|
|
}
|
|
assert wired, "the per-call SDK cap must be found by this scan"
|
|
|
|
def test_no_src_path_configures_the_run_total_usd_cap(self) -> None:
|
|
configured = [module for module, kw in _call_keywords_in_src() if kw == "max_cost_usd"]
|
|
assert configured == [], "denominator: 27 src modules; the belt is a no-op on every path"
|
|
|
|
def test_a_meter_without_a_cap_never_stops_however_large_the_spend(self) -> None:
|
|
# What the absence above MEANS, executed rather than inferred: the default meter — the
|
|
# one every src path builds — passes a spend far above any plausible run budget.
|
|
meter = BudgetMeter(TerminationContract(max_rounds=1000, max_tokens=10_000))
|
|
meter.guard_before_call(9_999_999.0) # no raise: the belt is off
|
|
assert meter.rounds_used == 0
|