feat(s36): deterministic integer-ore estimate scaling with model x effort

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0145ZKPLMVeqM47z2jxxokym
This commit is contained in:
Kjell Tore Guttormsen 2026-07-15 09:59:55 +02:00
commit eb889a7f0e
3 changed files with 99 additions and 0 deletions

View file

@ -102,3 +102,51 @@ def _price_ore_per_1k(model: str, pricing: PricingContract) -> int | None:
if entry is None:
raise ValueError(f"missing price for {model}")
return entry.ore_per_1k_tokens
# Effort is a costsim-LOCAL what-if scenario knob (integer percent multipliers on the token ceiling).
# HONESTY (målbilde §1): the runtime does NOT consume an effort setting today — there is no
# `effort`/`ChatOptions` counterpart in the model-map or run path — so this is an explicit scenario
# dimension for the what-if, never a measured runtime input.
EFFORT_FACTORS: dict[str, int] = {"low": 70, "standard": 100, "high": 140}
# The hard per-run token ceiling. A run cannot exceed it (mirrors run.py's default budget cap), so it
# IS the honest per-run upper bound — rounds are NOT multiplied in (that double-counts the cap).
_DEFAULT_MAX_TOKENS = 100_000
def estimate_run_ore(
model: str, effort: str, pricing: PricingContract, max_tokens: int = _DEFAULT_MAX_TOKENS
) -> int | None:
"""Deterministic INTEGER-øre upper-bound estimate for ONE run of ``model`` at ``effort``.
``max_tokens`` is the hard per-run ceiling the honest per-run upper bound (rounds are not
multiplied in that double-counts the cap). ``effort`` scales it by a scenario factor (see
``EFFORT_FACTORS``). Returns ``None`` when ``model`` is an unpriced placeholder. Pure integer
math (float NOK is banned ``ledger.py``); marked as an estimate (øvre grense), not a
prediction."""
if effort not in EFFORT_FACTORS:
raise ValueError(f"unknown effort {effort!r}; known: {sorted(EFFORT_FACTORS)}")
rate = _price_ore_per_1k(model, pricing)
if rate is None:
return None
scaled_tokens = max_tokens * EFFORT_FACTORS[effort] // 100
return scaled_tokens * rate // 1000
def estimate_portfolio_ore(
model: str,
effort: str,
pricing: PricingContract,
*,
n_projects: int,
max_tokens: int = _DEFAULT_MAX_TOKENS,
) -> int | None:
"""Deterministic portfolio upper bound = ``n_projects × estimate_run_ore``. ``None`` if the
model is an unpriced placeholder. Fail-fast on a negative project count."""
if n_projects < 0:
raise ValueError(f"n_projects must be >= 0, got {n_projects}")
per_run = estimate_run_ore(model, effort, pricing, max_tokens)
if per_run is None:
return None
return n_projects * per_run