BudgetExceeded carries kind/limit/observed as ONE structured stop event, but only
`observed` was undefended. Measured against the whole suite before writing anything:
four of five raise sites (TokenMeter.charge, tick_round, and BOTH arms of exhausted())
could report any value at all without a single one of 621 tests noticing. Only
PortfolioMeter.check was covered.
What hid it: spikes/_harness.py carries its OWN copy of BudgetExceeded/TokenMeter, so
the spike suite's `observed` assert never touched the shipped module — the production
tick_round had no direct test whatsoever.
exhausted() is the only site that CHOOSES a ledger (the S3.4 pre-call guard), so a
refusal naming portfolio_tokens while reporting the run's own spend would misdirect
every reader of it. Both arms are pinned with observed != limit on purpose: at
exactly-exhausted the two coincide, and a test written there would pass on an
implementation that echoed the cap back as the spend.
No defect in the values themselves (unlike kø-x and kø-p) — the triple was coherent at
all five sites; the gap was purely coverage.
Load-bearing MEASURED: nine mutations, all red — five observed mutations (including the
control) and four echo mutations. 621 -> 623 tests.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LW749xcXQmVEgdipB6KNm4
PortfolioBudget + PortfolioMeter carry ONE token ledger over a whole portfolio
pass -- and, seeded from a persisted spend file, across passes -- while the
per-run Budget/TokenMeter pair is untouched. Three enforcement points, each
doing a different job:
- startup: a remainder that cannot fund one run raises BudgetRefused before
anything loads (a pass that can afford zero projects is a caller mistake,
not a result);
- wave assembly: an unfundable project is NEVER STARTED and the pass stops
structurally (budget_stop + stopped_early, completed runs preserved).
Because every member of a wave is funded against the SAME pre-wave
remainder, admission RESERVES each member's requirement -- otherwise a wave
of k over-commits the cap by up to k runs;
- pre-call: BudgetMiddleware refuses a call the remainder cannot pay for
instead of making it. The post-charge check stays: real usage is only
knowable after the response, so the guard stops the NEXT call, never the
one in flight.
budget_stop is its own field rather than a widened stop_reason -- a goal-stop
is success, this is resource exhaustion, and fusing them would make "we
stopped" unreadable. PortfolioMeter splits record/check so tokens the provider
already billed reach the ledger even when the same charge breaks the run's own
cap. read_spend raises on corrupt content (our own accounting state, unlike
the tolerant RAW inbox layer); write_spend takes a REQUIRED stamp with no
wall-clock default, mirroring promote_verdict.
Load-bearing MEASURED, not asserted -- 6 mutations, all red: detach the wave
check; detach the pre-call guard; detach the wave reservation; check the run
cap before crediting the global ledger; detach the startup refusal; make
read_spend tolerant. Files restored from shasum-verified copies after each.
Two findings worth keeping: the pre-call guard MASKS a detached wave check if
the test asserts on overspend (spend stays under the cap either way), so the
load-bearing assertion had to become failures == () plus never-started; and
the token arithmetic is probed (32 tokens/run at tokens=8), not guessed.
537 -> 553 tests, ruff + mypy green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015EaxFnaDAbMQkmTeX4u7sd