Skip to content

feat: price a run from a versioned rate table - #33

Merged
SurefireStudios merged 1 commit into
mainfrom
feat/pricing-table
Sep 9, 2026
Merged

SurefireStudios merged 1 commit into
mainfrom
feat/pricing-table

Conversation

@SurefireStudios

@SurefireStudios SurefireStudios commented Sep 9, 2026 •

Copy link
Copy Markdown
Owner

Refs #10. Covers the first two bullets; the per-run budget is deliberately left out, see below.

What was already here

More than the issue implies. packages/submission/src/pricing.ts already had a rate snapshot, an estimator that prices input and output separately, and ModelUsage.estimatedCostUsd already permitted a number. What was missing was a table keyed by model, and any way to tell later which rates produced a figure.

What this adds

  • PRICING_TABLE, keyed by the model id a manifest already records, so a lookup needs nothing else, with PRICING_TABLE_VERSION covering the table as a whole. A rate change bumps the version rather than editing an entry in place, so a later change cannot silently restate what an earlier run cost.
  • priceRun returns the cost and the version together, because they have to agree. A figure without the table that produced it cannot be checked later; a version without a figure says nothing.

A model the table does not price stays unpriced. My first attempt passed the looked-up rates with ?? undefined, which fell through to the estimator's default and would have priced an unknown model at Opus rates. That is exactly the failure the file's own doc comment warns about, so priceRun now returns null for both fields instead.

Two things I checked before touching anything

Pinned artifacts. The hashes in submission/reproduction-manifest.json are over canonical predictions, not run manifests, so populating a cost field does not invalidate the frozen evaluation. pnpm reproduce still reports PASSED (27 checks).

Historical manifests. Twelve tracked manifests carry modelUsage with exactly five keys, and ModelUsageSchema is .strict(). pricingTableVersion is therefore optional, so those still validate. They are records of what happened and are not rewritten; the field appears on runs made from here.

One move worth flagging

The rate table moved from @stateproof/submission into @stateproof/core. The runners that make the model calls needed it, and making agents depend on submission would have inverted the layering, since submission reports on agent runs. Core already owns the manifest schema whose fields this fills, so the fields and the only code that populates them now sit together. Submission re-exports the table, so its importers are unchanged and there is one table rather than two that can drift.

Tests

Ten in packages/core/test/pricing.test.ts, aimed at the property that matters rather than at arithmetic: a cost figure is never invented.

  • input and output priced at their own rates, since pricing both at the input rate is the mistake the split exists to prevent
  • an unpriced model, and a null model id
  • a missing, NaN or negative token count
  • a zero-token run priced as 0 rather than as unpriced
  • every table entry keyed by its own model id, so a lookup cannot return the wrong rates

The scoring-integrity guard asserted estimatedCostUsd was null because the feature did not exist. It now asserts the two fields agree, which is the real invariant. The report line that read "Cost in USD is deliberately null: no pricing rule has been implemented" was true and is now false, so it is replaced.

Full suite 547 passing across 31 files, pnpm typecheck clean.

Not in this PR

The optional per-run budget that stops compilation before it is exceeded. It touches compilation control flow and needs a decision about what happens mid-suite when the budget runs out, which is a product call rather than a mechanical one. Happy to take it as a follow-up once you have a view.

Note

Low Risk

Overview
This pull request adds a model-keyed PRICING_TABLE and supporting types to the core package, providing versioned input and output rates for pricing calculations. The submission pricing flow now applies these rates, reports input and output costs separately, and includes the pricing snapshot information used for a run. Runners and scoring logic propagate pricing metadata, while core exports, manifest schema fields, and pricing/scoring tests are updated to cover the new behavior. Per-run budget handling remains unchanged and is not included.

Written by Gitzilla for commit 6c3fccb. This will update automatically on new runs. Configure in the Gitzilla dashboard.

`estimatedCostUsd` was hardcoded null in every run manifest and the report
said so: "no pricing rule has been implemented". Most of the pieces were
already here — a rate snapshot, an estimator that prices input and output
separately, and a manifest field that already permitted a number.

What was missing was a table keyed by model and a way to tell later which
rates produced a figure. Both are now in `@stateproof/core`:

- `PRICING_TABLE`, keyed by the model id a manifest already records, with
  `PRICING_TABLE_VERSION` covering the table as a whole. A rate change
  bumps the version rather than editing an entry, so a later change cannot
  silently restate what an earlier run cost.
- `priceRun` returns the cost and the version together, because the two
  have to agree: a figure without the table that produced it cannot be
  checked, and a version without a figure says nothing.

A model the table does not price stays unpriced. Pricing it at another
model's rates would produce a number that looks measured and is not,
which is the failure the estimator was already written to avoid.

`ModelUsage` gains `pricingTableVersion`, optional so the twelve pinned
manifests written before the table existed still validate. Those are
records of what happened and are not rewritten; the field appears on runs
made from here.

The rate table moved from `@stateproof/submission` into core, beside the
manifest schema whose fields it fills, because the runners that make the
model calls cannot depend on the package that reports on them. Submission
re-exports it, so its importers are unchanged and there is one table
rather than two that can disagree.

Ten tests cover the paths that matter: input and output priced at their
own rates, an unpriced model, a missing token count, and a zero-token run
priced as zero rather than as unpriced. The scoring-integrity guard now
asserts the two fields agree instead of asserting the feature is absent.

Full suite 547 passing; `pnpm reproduce` still PASSED (27 checks).

Refs #10.
Copilot AI lite review requested due to automatic review settings September 9, 2026 16:49

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@SurefireStudios
SurefireStudios merged commit 0f0c5be into main Sep 9, 2026
6 checks passed
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.

2 participants