Skip to content

fix(claude): forward the billed dollar receipt off the result line - #159

Merged
drewstone merged 1 commit into
mainfrom
fix/claude-cost-receipt
Aug 14, 2026
Merged

fix(claude): forward the billed dollar receipt off the result line#159
drewstone merged 1 commit into
mainfrom
fix/claude-cost-receipt

Conversation

@drewstone

Copy link
Copy Markdown
Owner

Problem

ClaudeStreamResult declares total_cost_usd (src/backends/claude.ts:74), but the terminal yield sent only { finish_reason, usage, internal_session_id }. total_cost_usd is a sibling of usage, not a member, so the one genuinely provider-billed number the bridge receives never left the backend.

Measured consequence downstream: across 292 fleet runs, spentTotal.usd > 0 on zero runs. The dollar channel is dead, and this is one of the two reasons.

Change

Forward the figure through the lane the bridge already uses for a known cost (src/usage.ts:59-67, src/streaming/sse.ts:108-121):

Case What travels
total_cost_usd present, finite, >= 0 cost, cost_known: true, cost_provenance: provider-receipt, cost_scope: total
absent cost_known: false, no amount
negative / NaN / Infinity cost_known: false, no amount

cost_scope: total is correct because Anthropic's figure covers the whole claude -p invocation, including every internal model call the harness made.

It is a real provider receipt, so it goes in the receipt lane, not the estimate lane. The catalog-estimate lane is untouched: Pi keeps costKnown: false by contract (src/backends/types.ts:138) because neither Pi nor the proxy reports billed dollars.

A run reporting no figure sends no dollar amount at all. A zero would read as a measured free turn.

Proof

New tests/claude-cost-receipt.test.ts (5 tests). 4 of the 5 fail without the source change — verified by stashing src/backends/claude.ts and re-running:

- "cost": 0.0412,
- "cost_known": true,
- "cost_provenance": "provider-receipt",
- "cost_scope": "total",
+ "cost_known": false,

 Test Files  1 failed (1)
      Tests  4 failed | 1 passed (5)

The 5th (catalog estimate stays out of the receipt lane) passes both before and after — it is the regression guard for the lane this change must not touch.

Full suite, after:

 Test Files  45 passed | 1 skipped (46)
      Tests  815 passed | 8 skipped (823)
   Duration  8.72s

pnpm typecheck clean.

tests/pi-backend.test.ts gains an explicit guard that no Pi delta carries cost_known: true or a cost amount.

Docs

Two README bullets: the two-lane dollar contract, and what the claude harness now reports.

The claude backend declared `total_cost_usd` on `ClaudeStreamResult` but
yielded only `usage`. The figure is a sibling of `usage`, not a member, so
the one genuinely provider-billed number the bridge receives never left the
backend and every claude turn reached the caller with no dollar cost.

Forward it through the lane the bridge already uses for a known cost:
`cost` with `cost_known: true` and `provider-receipt` provenance, at
`cost_scope: total` because the figure covers the whole `claude -p`
invocation. A run that reports no figure keeps `cost_known: false` and sends
no amount. A negative or non-finite figure is refused rather than billed.

The catalog-estimate lane is untouched. Pi reports `cost_known: false` by
contract because neither Pi nor the proxy reports billed dollars.
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