Skip to content

feat(worker,admin): pricing façade, run-record scan, and the pure cost fold - #76

Merged
edgehero merged 4 commits into
mainfrom
feat/pricing-and-fold
Aug 2, 2026
Merged

edgehero merged 4 commits into
mainfrom
feat/pricing-and-fold

Conversation

@edgehero

@edgehero edgehero commented Aug 1, 2026

Copy link
Copy Markdown
Owner

The data layer for #53's gaps 4 and 5 — aggregation and what-if re-pricing with no database, no new deps, and no second pricing table. Stacked on #73 (usage ledger) and #74 (subscriptions file); their commits appear here until they merge, after which this PR's diff collapses to its own three parts.

worker/src/pricing.mjs (exported ./pricing)

The admin's only road to pi-ai's rate tables — the budget/dayKey anti-drift idiom instead of a fourth exact pin and a second drift axis. reprice(quad, target) builds a fresh Usage with a zeroed cost skeleton on every call (pi-ai's calculateCost mutates its argument and TypeErrors without one — both pinned by test) and inherits pi-ai's tier selection and 1h premium. One judgment call, commented as such: cacheWrite1h forwards only to anthropic targets (clamped to cacheWrite), folded short for everyone else — the premium is an Anthropic billing rule; applying it elsewhere would invent cost. Catalog lookups are own-key hardened (the generated catalog genuinely resolves __proto__/toString through the prototype chain — found and pinned). Enumeration via the side-effect-free providers/all, never ./compat.

The test file doubles as the pinned-artifact pricing-surface guard: mutation contract, tier threshold key (input+cacheRead+cacheWrite), exact opus-4-6/codex rates, the 272k tier boundary, all-zero kimi/zai tables (correct data, not missing data), and the exact resolved version 0.80.7 — a pi-ai pin bump that reshapes pricing fails the build, not the screen.

scanRunRecords + admin/src/costs.mjs

scanRunRecords is listRuns' sibling without the 50-clamp — retention-bounded, hard-capped at 92 days even under keep-forever, explicitly not a query surface. costs.mjs is pure and fs-free (purity-regex-tested; dayKey is the one permitted worker coupling, so admin and worker cannot drift on UTC day boundaries) and is where facts meet opinions: classification happens at fold time and is never stored, so editing subscriptions.json retroactively reclassifies history — correctly.

The honesty rules, each pinned by a golden-fixture test:

  • every dollar is a typed {usd, class, floor, coverage} value; fmtCost (feat(admin): pure panel primitives for the costs surface — sparkline, typed cost formatting, line input, ASCII glyphs #75) is its only renderer;
  • a sum stays metered only when every addend is — one estimated addend demotes it visibly, with coverage;
  • plan-covered rows contribute $0 metered but carry their API-equivalent (reprice at the declared counterfactualModel) as an estimate — never $0.00, never free ($0 (unrated) for unmatched zero-rate runs);
  • floors propagate (unpriced/unresolved/metered:false/pre-Token accounting & optional token cap (unblocked by #21: pi 0.80.7 exposes per-turn usage) #25 records);
  • unknown-limit windows produce facts only (peak runs/tokens), never an invented burn-down;
  • verdicts: SAVING/LOSING for owned plans (API-equiv vs prorated price), WOULD_SAVE/WOULD_LOSE for hypothetical (vs actual metered spend), and NO_BASELINE whenever the comparison would be against nothing;
  • whatIfFlow seeds from the flow's own median quad (one 10× outlier must not move the estimate); with zero ledgered history, the OQ-002 $0.5–$5 band labeled unmeasured (OQ-002) — always a band, never a point;
  • ratesDrifted accuses only when both versions are present.

Specs (same PR)

Minted DES-COST-FOLD-BY-SCAN (Rejected, each with its reason: embedded analytics store; rollup/index files — a second source of truth that goes stale on every sweep, retry overwrite, and subscriptions edit; a redis cost series — TTL'd enforcement state is not history; storing the classification — a record written under one subscriptions file lies under the next) and INT-PRICING-EXPORT-CONTRACT. DES-RUN-HISTORY-FLAT-FILES-NO-DB unchanged, checked and leaned on.

Tests

Full suite 1546, 0 fail — 21 pricing-guard, 19 fold (purity regex first), 5 scan tests new. The COSTS view + /dispatch costs PR that composes this with #75's primitives follows.

…t fold (issue #53)

Closes gaps 4 and 5's data layer for issue #53: aggregation and
re-pricing, with no database, no new deps, and no second pricing table.

- worker/src/pricing.mjs (exported ./pricing): the admin's ONLY road
  to pi-ai's rate tables -- listPricedModels, getPricedModel (own-key
  hardened: the generated catalog resolves __proto__ lookups through
  the prototype chain), isZeroRated, piAiVersion (resolved package's
  version read from disk; pi-ai exports no ./package.json), and
  reprice(quad, target). reprice builds a fresh Usage with a zeroed
  cost skeleton every call -- calculateCost mutates its argument in
  place and TypeErrors without one, both pinned by test -- and makes
  exactly one judgment: cacheWrite1h forwards only to anthropic
  targets (clamped to cacheWrite), folded short for everyone else,
  because the 1h premium is an Anthropic billing rule and applying it
  elsewhere would invent cost. Enumeration via the side-effect-free
  providers/all, never ./compat. The test file doubles as the
  pinned-artifact pricing-surface guard: mutation contract, tier
  threshold key (input+cacheRead+cacheWrite), opus-4-6 and codex
  rates, the 272k tier boundary, all-zero kimi/zai tables, and the
  exact resolved version -- a pin bump fails the BUILD, not the screen.
- admin/src/read-model.mjs scanRunRecords: listRuns' sibling without
  the 50-clamp; retention-bounded, hard-capped at 92 days even under
  keep-forever; not a query surface.
- admin/src/costs.mjs (pure, fs-free, purity-regex-tested with dayKey
  as the one permitted worker coupling): the fold where FACTS meet
  OPINIONS. Classification (metered/plan/zero-rated/estimated/seeded/
  unknown) happens at fold time and is never stored, so editing
  subscriptions.json retroactively reclassifies history correctly.
  Every dollar is a typed {usd, class, floor, coverage} value; a sum
  stays metered only when every addend is; plan-covered rows carry
  their API-equivalent as an estimate, never $0.00; unknown-limit
  windows produce facts only, never burn-down; verdicts degrade to
  NO_BASELINE rather than compare against nothing; whatIfFlow seeds
  from the flow's own median quad, else the OQ-002 band labeled
  unmeasured -- always a band, never a point.

Specs minted in-PR: DES-COST-FOLD-BY-SCAN (Rejected: analytics store,
rollup/index files, a redis cost series, storing the classification)
and INT-PRICING-EXPORT-CONTRACT. DES-RUN-HISTORY-FLAT-FILES-NO-DB
unchanged, checked and leaned on.

Tests: full suite 1546, 0 fail (21 pricing-guard, 19 fold, 5 scan new).
Signed-off-by: Rob Boerman <robboerman@live.nl>
…a literal byte

The per-(provider,model) row key joined its pair with a LITERAL 0x00
byte in the source, which is semantically identical to the u0000
escape at runtime and completely different to every tool that reads
the file as text: file(1) classifies it as data, grep goes binary,
and a reviewer's diff shows an opaque blob. The runner's meter spells
the same separator as the six-character escape for exactly this
reason; now both sides do.

Signed-off-by: Rob Boerman <robboerman@live.nl>
# Conflicts:
#	specs/design.md
#	specs/interfaces.md
@edgehero
edgehero merged commit 2c20ac4 into main Aug 2, 2026
4 checks passed
@edgehero
edgehero deleted the feat/pricing-and-fold branch August 2, 2026 03:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant