fix(cost): repair the cost pipeline — pricing table, transcript dedupe, path source - #17
Merged
Merged
Conversation
…e, path source The cost pipeline was wrong in both directions: 1. Stale pricing table: no entries for Opus 4.8 / Sonnet 5 / Fable 5, so computeCost() silently returned $0 for every current-model session and CostCeiling/budget policies failed open. Opus 4.7/4.6 were priced at the pre-4.5 $15/$75 tier instead of the actual $5/$25 — a 3x overestimate. Table refreshed and verified against published rates 2026-07-11; BEDROCK_PRICING now spreads ANTHROPIC_PRICING so new models can never price at $0 on one backend only. 2. Per-line double count: Claude Code writes one transcript line per content block, each repeating the same message.id with identical usage. Summing per line inflated cost 2-7x. readSessionUsage now counts each message.id once (id-less lines still counted individually). 3. Wrong transcript path for non-slash-encoded cwds: hooks now prefer the transcript_path field Claude Code sends in every hook payload; the reconstruction fallback encodes [^a-zA-Z0-9] -> "-" to match Claude Code's real project-dir encoding. Unknown models are no longer silent: they surface on SessionUsage.unknownModels and the hook warns on stderr that their spend is invisible to cost policies. Verified end-to-end against a live Fable 5 transcript: previously $0.00, now $14.42 with dedupe applied. Note: historical run costs in existing databases were computed with the old table and the double count; this change does not backfill them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
iaj6
added a commit
that referenced
this pull request
Jul 12, 2026
…24) Doc/config drift flagged by the July audit: - CLAUDE.md was the stalest file in the repo and actively misled agent sessions: claimed 6 policy types incl. a nonexistent RequiredApproval (actual: 8, with guard/check modes), "eight tables" (actual: 16 — the whole auth/webhook/audit/budget layer was missing), no mention of the auth model, login/doctor/user/admin/cleanup commands, or the transcript cost pipeline. Also marks the jobs/locks/dispatch layer as vestigial and documents the stale-dist gotcha for web tests. - CHANGELOG now covers the June audit sweep (PRs #1-#16) and the July revival audit (PRs #17-#23); previously it stopped before both. - `agentops serve` printed "The API is currently unauthenticated" when binding beyond localhost — false since the auth layer shipped. The warning now says what's true: auth is required, but traffic is plain HTTP, so use the caddy profile beyond a trusted LAN. - Litestream sidecar mounted the DB read-only, which breaks replication outright (litestream needs the checkpoint lock + sidecar files). Now rw, with a comment explaining why. The S3-compatible endpoint comment now says explicitly that setting AGENTOPS_S3_ENDPOINT alone does nothing while the config line stays commented. - scripts/demo-seed.mjs (previously untracked) is committed, now gated behind --yes since it wipes runs/events/policy_results/run_metrics. - packages/cli/src/build-info.ts is generated on every build, so the working tree was permanently dirty. Gitignored; the generator now also runs as pretest so fresh clones can run cli tests before a build. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The July revival audit found the cost pipeline — the flagship feature — broken in three independent ways. This PR fixes all three.
1. Stale pricing table → current models silently priced at $0
ANTHROPIC_PRICINGtopped out at Opus 4.7 / Sonnet 4.6, andcomputeCost()returned0for unknown models — so every Opus 4.8 / Sonnet 5 / Fable 5 session read $0.00 and CostCeiling/budget policies failed open. Opus 4.7/4.6 were also priced at the pre-4.5 $15/$75 tier (actual: $5/$25 — 3× over).BEDROCK_PRICINGnow spreadsANTHROPIC_PRICING, so a newly added model can never price at $0 on one backend only.SessionUsage.unknownModels, and hooks warn on stderr that this spend is invisible to cost policies.2. Transcript double-count (2–7× inflation)
Claude Code writes one transcript line per content block, each repeating the same
message.idwith identicalusage. Summing per line multiplied real cost by blocks-per-message (verified on a live transcript: 47 usage lines, 16 unique messages, one id repeated 7×).readSessionUsagenow counts eachmessage.idonce; id-less lines (older formats) are still counted individually.3. Wrong transcript path for non-slash characters
transcriptPathonly replaced/when encoding the cwd, so any project dir containing./_/space resolved to a nonexistent path and read $0. Hooks now prefer thetranscript_pathfield Claude Code already sends in every hook payload (newreadHookUsagehelper collapses the four duplicated call sites); the reconstruction fallback encodes[^a-zA-Z0-9]→-to match Claude Code's real encoding.Verification
Caveat
Historical run costs in existing databases were computed with the old table + double count (old Opus runs ~3×·dupes over; Fable/Opus 4.8 runs $0). This PR does not backfill them.
🤖 Generated with Claude Code