Skip to content

Resolve OpenAI model ids to the most specific pricing key - #8

Merged
nitrimandylis merged 1 commit into
mainfrom
fix-openai-model-resolution
Aug 8, 2026
Merged

Resolve OpenAI model ids to the most specific pricing key#8
nitrimandylis merged 1 commit into
mainfrom
fix-openai-model-resolution

Conversation

@nitrimandylis

Copy link
Copy Markdown
Owner

prOpenAI resolves a model id by substring against MP_OPENAI, walking the
table in insertion order. Several keys are prefixes of others, so the prefix
always answered first and every -mini variant priced as its full-size parent.

id resolved to priced at should be
gpt-4o-mini GPT-4o $2.50 / $10 $0.15 / $0.60
o1-mini o1 $15 / $60 $3 / $12
o3-mini o3 $2 / $8 $1.10 / $4.40
gpt-4-32k GPT-4 $30 / $60 $60 / $120

The fuzzy-match block below the loop had the right order but was unreachable
for all of these. Fix is to try the longest key first. The block is reduced to
the one alias that is not itself a table key (gpt-3.5).

Why this was more than mispricing

costMiniDowngrade prices its remedy through prOpenAI("gpt-4o-mini"). On a
GPT-4o row that returned the row's own cost, so savings came to zero and
addFinding's sav > 0.5 floor dropped the finding without a trace.

"Model Downgrade → GPT-4o-mini" could not fire on a GPT-4o row at all
the commonest OpenAI workload there is. It only ever appeared on rows pricier
than GPT-4o (o1, gpt-4, gpt-4-turbo), understating those by ~19%.

A textbook candidate, 60M in / 3M out over 40k requests at 75 avg output
tokens, $180/mo:

before:  Batch API Migration $90 | RAG Optimization $60 | High-Impact $18
         Model Downgrade → GPT-4o-mini:  ABSENT

after:   Model Downgrade → GPT-4o-mini $169.20 | Batch API Migration $10.80

Both demo personas use expensive models, which is why six months of demo runs
never showed it.

Fallout, and what it forced

Rule 3 gained two deferrals. Correctly priced, mini is ~94% cheaper, so
rule 3 outbids every other finding for the greedy per-row savings cap and
starves them. It now stands down on rows other rules own:

  • RAG territory (ratio > 12 && inp > 10M, rule 2's gate, already used by
    rule 8 for the same reason). A row pulling 28:1 input has a retrieval
    problem, not a model problem.
  • avg input ≥ 10k tok, which was already a confidence signal here and has to
    be a gate at real pricing. A request carrying 15k tokens of context is not
    a simple classification task; rule 8 owns it.

Without these, the enterprise demo lost both RAG Optimization and Prompt
Optimization to a mini downgrade that ate the headroom.

The startup demo persona was authored against the inflated prices. Its two
mini projects came to $2/mo once corrected, below every rule's threshold, so
the persona produced zero findings and the demo rendered an empty report.
Volumes re-sized against real mini pricing, keeping the one deliberate caching
finding the persona exists to show.

Two costing fixtures moved to mini rows. Rule 0 needs inp > 5M, and at
that volume a GPT-4o row now always attracts a mini downgrade (rule 1 when
ao < 200, rule 3 otherwise) which takes the cap headroom first and clamps
the rule under test. Rules 1 and 3 both skip mini rows, so that is the only
way to isolate them. The caching fixture also dropped its arbitrary
cost: 60, which paired a billed figure with $2.70 of tokens and pushed the
saving under the $0.50 floor.

Verification

npm run type-check    ✓
npm run lint          ✓  0 errors (1 pre-existing warning in calibration.sweep.test.ts, also on main)
npm run format:check  ✓
npm test              ✓  117 passed | 1 skipped

npm run calibrate re-baselined, both engines clean, no overconfidence flags:

verdict: high-confidence (≥0.65) persistence 99.6% vs rest 98.5%

Model Downgrade → GPT-4o-mini     300        0.90  100%

That category tracked 60 findings before and 300 now, which is the bug's
footprint measured from the other side.

Tests

src/__tests__/openai-pricing.test.ts, 14 cases: every affected id pins its
label and both rates; dated and suffixed ids resolve the same; the unknown-
model fallback still lands on GPT-4o; and a general property test asserting
that wherever one table key contains another, the longer one wins, so a future
table entry cannot silently reintroduce this. Plus two end-to-end regressions:
the mini downgrade firing on a GPT-4o row and pricing at mini rates, and rule
3 ceding to RAG bloat and prompt bloat rather than starving them.

Note on #7

Cut from main, so it does not conflict with #7. Merging this changes the
sample output quoted in that PR: its Haiku line reads
Haiku 4.5 $43.49 → GPT-4o $120.80 (+178%) because the mapping target
gpt-4o-mini was resolving to GPT-4o. With this fix it becomes a large
negative delta, which is what that comparison was always meant to show.
Whichever lands second wants a rebase and a refreshed sample.

prOpenAI walked MP_OPENAI in insertion order with a substring test, and
several keys are prefixes of others. Every "-mini" variant matched its
full-size parent: gpt-4o-mini priced at GPT-4o's $2.50/$10 instead of
$0.15/$0.60, plus o1-mini, o3-mini and gpt-4-32k. Longest key wins now.

The mispricing did more than inflate numbers. costMiniDowngrade prices the
remedy via prOpenAI("gpt-4o-mini"), so on a GPT-4o row it returned the row's
own cost, savings came to zero, and addFinding's $0.50 floor dropped the
finding. "Model Downgrade -> GPT-4o-mini" could not fire on a GPT-4o row at
all — the commonest OpenAI workload. A $180/mo row with 75 avg output tokens
now reports the $169.20/mo saving it always had.

Correcting the price makes mini ~94% cheaper, so rule 3 outbid every other
finding for the per-row savings cap and starved them. It now defers on rows
other rules own: RAG territory (rule 2's gate, already used by rule 8) and
avg input >= 10k tok, which was previously only a confidence signal.

The startup demo persona was authored against the inflated prices; its two
mini projects came to $2/mo once corrected and produced no findings at all.
Volumes re-sized against real pricing, keeping the one deliberate caching
finding. Two costing fixtures moved to mini rows: rule 0 and the batch rules
cannot be isolated on a GPT-4o row now that a mini downgrade always fires
alongside and takes the headroom first.

Calibration re-baselined, both engines clean: high-confidence persistence
99.6% vs 98.5% for the rest. Model Downgrade -> GPT-4o-mini now tracks 300
findings instead of 60, at 0.90 confidence and 100% persistence.
@vercel

vercel Bot commented Aug 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
tokenpilot Ready Ready Preview Aug 8, 2026 5:41pm

@nitrimandylis
nitrimandylis marked this pull request as ready for review August 8, 2026 17:48
@nitrimandylis
nitrimandylis merged commit 844f57e into main Aug 8, 2026
3 checks passed
@nitrimandylis
nitrimandylis deleted the fix-openai-model-resolution branch August 8, 2026 17:51
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