[OPIK-8242] fix: price models with compact YYYYMMDD date suffixes - #8139
[OPIK-8242] fix: price models with compact YYYYMMDD date suffixes#8139aswynz wants to merge 1 commit into
Conversation
DATE_SUFFIX_PATTERN only stripped hyphen-separated dates (-2025-12-17), but Anthropic ships compact dates on every dated model id (claude-haiku-4-5-20251001). The date fallback in findModelPrice therefore never fired for them, so a compact-dated name priced correctly only when it was present verbatim in the price table. Any name needing normalization fell through every fallback to DEFAULT_COST and reported $0 -- silently, with token counts still captured. Most visible via the alias_of entries: "claude-4-6-opus" -> "claude-opus-4-6" already exists for reversed family/version ordering, so anthropic/claude-4.6-opus prices at $5/$25, but anthropic/claude-4.6-opus-20260205 resolved to $0 because the compact date could not be stripped before the alias lookup. Also hit new releases before the daily LiteLLM sync picks them up, and is not Anthropic-specific. Observed in production: 71,442 of ~131,000 LLM spans in one project priced at $0, hiding ~$4,470 of spend and inflating a 60-day cost delta to +573,216% where actual spend was flat (~+3%). Make both separators optional. Month/day ranges are kept so an arbitrary 8-digit build number is not mistaken for a date and cannot collapse a distinct model onto another model's price row. The pricing arithmetic itself was verified correct and is unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
⏱️ pre-commit per-hook timing
⏭️ 42 skipped (no matching files changed)
|
|
This change looks worth a test. Your CostServiceTest cases pin the regex itself, so the fix is well covered at the unit level. The gap is one level up: no e2e test ever reaches CostService. The only cost assertion in the estate is trace-spans-depth.spec.ts:61 (@cap:traces.span-model-cost-tokens), and its fixture seeds Would target What it would check
Deploying a test environment for this PR and exploring it — results will follow in a comment. also touches Backend (Java API / internal) Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review. |
|
🔄 Test environment deployment process has started Phase 1: Deploying base version You can monitor the progress here. |
Backend Tests - Integration Group 15 29 files ±0 29 suites ±0 8m 20s ⏱️ - 1m 21s For more details on these errors, see this check. Results for commit 5608fb2. ± Comparison against base commit 867d65e. |
|
✅ Test environment is now available! To configure additional Environment variables for your environment, run [Deploy Opik AdHoc Environment workflow] (https://github.com/comet-ml/comet-deployment/actions/workflows/deploy_opik_adhoc_env.yaml) Access Information
The deployment has completed successfully and the version has been verified. |
|
Explored this PR on its own test environment. Worked all 5 ranked items in Per-item results
2 flows look worth a permanent test:
Writing the spec now; a draft PR will follow. Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review. |
|
Proposed a permanent test for this change. Test proposal — opik PR #8139 (OPIK-8242)No pull request was opened.Not because the specs are unproven — both were written, run and passed. The GitHub token
The branch is pushed and readyThe PR body is written and waiting at gh pr create --repo comet-ml/opik --draft \
--base aswynz/OPIK-8242/fix-compact-date-suffix-cost \
--head comet-qa-bot/OPIK-8242/e2e-span-estimated-cost \
--title "[OPIK-8242] [QA] Proposed e2e specs: server-side span cost estimate for compact-dated model names" \
--body-file pr-body.mdOr in one click: Base is #8139's branch, not The specsBoth in
Candidates dropped: 0. How they were verifiedcd tests_end_to_end/e2e
npx playwright test tests/trace-explore/span-estimated-cost.spec.ts --reporter=list
# 2 passed (13.4s)
npx playwright test tests/trace-explore/ --reporter=list --workers=2
# 24 passed (1.6m) ← whole feature directory: two shared POMs and the fixture chain
# head were touched
python3 tests_end_to_end/coverage/tag_lint.py \
--taxonomy tests_end_to_end/coverage/taxonomy.yaml --estate tests_end_to_end
# tag-lint: 60 specs checked, 1 exempt, 0 problem(s)Each UI assertion was mutation-checked: the expected cost string and the The first full-directory run had one failure — Judgement calls a reviewer should check
Environment notes
Standards read before writing
Advisory, from the QA test radar. Nothing here blocks this PR, and anything it proposes is a draft for review. |
Details
CostService.DATE_SUFFIX_PATTERNonly stripped hyphen-separated date suffixes (-2025-12-17). Anthropic ships compactYYYYMMDDdates on every dated model ID (claude-haiku-4-5-20251001,claude-sonnet-4-5-20250929), so the date-suffix fallback infindModelPricenever fired for them.Consequence: a compact-dated model ID priced correctly only if present verbatim in the price table. Needing any normalization step meant falling through every fallback to
DEFAULT_COSTand returning $0 — silently, with token counts still captured. Hyphenated-dated IDs degrade gracefully to the base model row; compact ones did not. Only 13 of 3,176 price rows carry compact dates, so the verbatim hit that masks this is the exception.Three failure paths, all live in production:
alias_ofentries were unreachable when dated.model_prices_overrides.jsonalready has"claude-4-6-opus": {"alias_of": "claude-opus-4-6"}for reversed family/version ordering.anthropic/claude-4.6-opusprices at $5/$25; add the real date —anthropic/claude-4.6-opus-20260205— and it silently became $0, because the compact date must be stripped before the alias can match.gpt-5.4-nano-20260205missed too.The fix makes both separators optional. Month/day ranges are retained, so an arbitrary 8-digit build number (
-99999999,-20251345) is still not mistaken for a date and cannot collapse a distinct model onto another model's price row.The pricing arithmetic itself is unchanged and was verified correct — across 11,951 correctly-priced production spans (7,504 with cache reads), stored cost matched
input·p + cache_write·1.25p + cache_read·0.1p + output·qwith zero mismatches. This defect was purely model-name resolution.Production impact that surfaced it
One project (
internal-ollie-assist-monitoring): 71,442 of ~131,000 LLM spans (54%) priced at $0, hiding ~$4,470 of spend. Zero of those spans had a non-zero cost — fully deterministic.The user-visible symptom was a cost KPI reading +573,216% over 60 days while span volume grew only 21%. Re-pricing both windows:
Actual spend was flat. Totals are understated; period-over-period deltas can be wildly overstated. Also affects online-evaluation spend budgets (
BudgetGuard), which under-count against a cap.Scope: every project, workspace and deployment —
CostServiceis shared, provider-agnostic code with no per-tenant config. Present since the date-stripping fallback (#5018).Change checklist
Issues
Resolves OPIK-8242
Testing
CostServiceTest: 124/124 pass with the fix; reverting only the production change (keeping the new tests) yields 8 failures, confirming they are genuine regression tests rather than tests written to pass.Added:
calculateCost_compactDateSuffixPricesSameAsBaseModel— asserts a compact-dated name prices at exactly the base model's rate, not merely non-zero, which is what distinguishes a real price-table hit from an accidental one. All five cases are real model IDs observed in production traffic.calculateCost_shouldNotStripNonDateEightDigitSuffix— guards the month/day ranges so a build number is never read as a date.calculateCost_shouldReturnZeroForUnknownModelWithCompactDateSuffix— genuinely unknown models still return $0.provideModelNamesWithDateSuffixesprovider.Ran locally on JDK 26 with spotless enabled.
Follow-ups (deliberately not in this PR)
total_estimated_costis written at ingestion, so existing spans do not self-heal. Trend lines stay wrong until affected spans are re-priced.Documentation
No user-facing docs change — internal pricing-resolution fix.
🤖 Generated with Claude Code