Repository navigation
Seven money-affecting fixes are unreleased; v0.7.33 still bills by the old arithmetic #437
Description
The gap
The newest release is tag v0.7.33 (commit 9a83181). main is 24 commits ahead of it, and seven of those change what a request costs or what prices the catalogue can express. A deployer running v0.7.33 today is billed by the arithmetic that shipped before any of them.
This is filed so the gap is visible next to the fixes, not to ask for a tag: .github/workflows/docker-publish.yml fires on a tag and the release decision is the maintainer's.
Verified against the repository, not assumed:
git merge-base --is-ancestor 357ab01 v0.7.33 # -> false (not released)
git merge-base --is-ancestor 41ca047 v0.7.33 # -> false
git merge-base --is-ancestor a49f130 v0.7.33 # -> false
git rev-list --count v0.7.33..main # -> 24
What a v0.7.33 deployer is charged today
| Unreleased commit | PR | Effect on a v0.7.33 deployment |
Direction |
|---|---|---|---|
ada9043 |
#412 | Weekends and configured holidays are billed at the peak rate | overcharges |
eadfb9f |
#413 | Four catalogue prices are wrong, one of them a cache-hit price written as 0 |
undercharges |
496a723 |
#416 | Tiered prices and a cache-write price cannot be expressed in config.toml at all |
cannot express |
544cf86 |
#417 | A long input is settled at the first (lowest) tier regardless of its length | undercharges |
357ab01 |
#433 | Cache-write (cache-creation) tokens are billed at zero, so the platform absorbs that cost | undercharges |
41ca047 |
#434 | The admin model editor cannot set cache_write_input_per_m, so an operator on this tag cannot even opt in |
cannot express |
a49f130 |
#436 | Streaming Anthropic responses report input_tokens net of the cache-read subtraction, so uncached input is undercounted |
undercharges |
Two further unreleased commits change the catalogue roster rather than the arithmetic — 983111c (#414, the four international vendors become selectable) and b7d19ea (#415, current-generation models). Until they ship, an operator on v0.7.33 cannot list those vendors or models.
A worked example of the widest one
#436, at the catalogue prices for claude-sonnet-5.5 ($2.00 input / $0.10 cache-read / $10.00 output per million). A streamed call reporting input=2,000, cache_read=60,000, output=1,000:
- correctly settled: $0.020000
- as
v0.7.33settles it: $0.016000 — the uncached segment clamps to zero, because the cache-read amount is subtracted from aninput_tokensthat never included it
That is 0.0288 points, roughly 20% of the call, and the gap widens with the cached share. #433 compounds it on the same call: the cache-creation segment is billed at zero.
Scope note
Stated so this issue is not read as broader than it is:
- It does not ask for a release, a version bump or a tag.
- It does not cover
devorprod: what those environments run is a deployment decision tracked outside this repository. - Nothing here is a defect in
main— every item listed is fixed onmainand unreleased. The defect is the distance betweenv0.7.33andmain.
Activity
argszero commentedon Oct 25, 2026
#439 merged (
db0160f) — one more unreleased change, and this one blocks a deployer who does nothing.This is a note, not a request to cut a release; the call on when to release is yours.
fix(config): reject keys the schema does not declarechanges startup behaviour, not pricing: any key the schema does not declare is now a fatal load error that names the key. A correctly configured deployment parses to exactly the same values as before — but a config carrying a stray or stale key, which used to be silently ignored, now refuses to start.Measured against a real config file, not fixtures, using the binary built from the merged tree (
db0160f):data/config.toml) — 382 lines, seeded 13 models, started and served on0.0.0.0:8080. It carries no undeclared key, so it needs no action.cache_write_input_per_mmforcache_write_input_per_m) — exit 1,unknown field ... expected one of provider, model, currency, input_per_m, cache_hit_input_per_m, output_per_m, peak_input_per_m, peak_cache_hit_input_per_m, peak_output_per_m, cache_write_input_per_m, tiers, context_length, max_output, vision. Before fix(config): reject keys the schema does not declare #439 that config loaded and settled cache-write tokens at0.0.So the upgrade note in #439 is immediate rather than theoretical for anyone whose config drifted from
config/config.example.toml: diff the config against the example before upgrading, and anything in the diff that the example no longer declares is a key that was being ignored until now.argszero commentedon Oct 25, 2026
Question (wire or delete): four fields are declared, accepted, and read by nothing.
src/config.rsstill carries four#[allow(dead_code)]fields on the merged tree (db0160f):Points.display_name/Points.symbol—config.rs:389,config.rs:392, commented "display name (UI only)" and "symbol (UI only)"Provider.name/Provider.country—config.rs:404,config.rs:406Nothing reads them, so the "UI only" part of those comments describes an intent rather than today's behaviour. #439 sharpened the consequence without changing it: because all four are declared,
deny_unknown_fieldsaccepts them — unlike a typo — so an operator who setsdisplay_nameorcountryinconfig.tomlgets a config that loads cleanly and displays nothing. Declared-and-ignored is the quieter half of the defect #438 named, and it is the half a startup check cannot catch.Two ways out, and I do not think a round of mine should pick between them:
display_name/symbolto the points label in the UI,name/countryto the provider list.If the answer is "not now", that is a fine answer too — I will leave them alone rather than refactor around an undecided contract.
argszero commentedon Oct 25, 2026
Latent, not live: the cache-write price cannot follow a tier boundary.
Two readings at
db0160f, recording a boundary the code documents rather than a defect:ModelTier(src/config.rs:451-461) carries exactly four fields —from_tokens,input_per_m,cache_hit_input_per_m,output_per_m. No cache-write. Both price paths return a triple (select_tier,effective_prices), and the cache-write price is read from the model-level price at both settle sites (src/gateway.rs:251,:265).cache_write_input_per_m. The single occurrence inconfig/config.example.tomlis the doc comment at line 351; there are zero assignments across all 24[[models]]blocks — including the four that carry tiers (gemini-3.1-pro,grok-4.6,grok-4.7,minimax-m3).So the documented boundary holds today, and it holds only because nothing is priced there. If a cache-write price is ever published for a model that has tiers, and the vendor's cache-write price tracks input length the way input and output do, then a request above a tier boundary bills input, cache-hit and output at the upper tier while cache-write stays at the single model-level figure — the base price applied where the vendor charges the higher one, with the platform absorbing the difference on exactly the long-context requests vendors charge most for.
Latent today, not a live bill defect: every shipped cache-write price is at its
0default, so the mispriced term is multiplied by zero and no stored row is wrong. Adding cache-write prices to the catalogue would be a pricing decision (it raises real bills), not a code fix, and it is not mine to make. Recording the condition only, so that whoever publishes those prices knows the per-tier slot does not exist yet.