Skip to content

Comments

fix: resolve $0.00 session costs in tapes deck#133

Merged
bdougie merged 2 commits intomainfrom
fix/session-cost-calculation
Feb 25, 2026
Merged

fix: resolve $0.00 session costs in tapes deck#133
bdougie merged 2 commits intomainfrom
fix/session-cost-calculation

Conversation

@bdougie
Copy link
Contributor

@bdougie bdougie commented Feb 23, 2026

Summary

  • Cost calculation fallback: Track last-seen model in sessionFromNodes loop and use it when response nodes have empty model fields. This fixes the root cause : 2042 of 2048 of my response nodes since Feb 19 had empty models, causing cost calculation to skip them entirely.
  • Missing pricing: Add claude-haiku-4.6 to DefaultPricing() so sessions using it get costed correctly.
  • Streaming model fallback: In enqueueStreamedResponse, fall back to the request model when the reconstructed response has an empty model, preventing future empty-model nodes.

Test plan

  • New Ginkgo tests for empty-model fallback (last-seen model used, no-model-yet skipped)
  • New pricing tests for claude-haiku-4.6 resolution (exact and date-suffixed)
  • All 125 deck tests pass
  • All 55 proxy tests pass (including Anthropic streaming model capture)
  • go build ./... succeeds

Continue Tasks: ✅ 1 no changes — View all

Response nodes since ~Feb 19 have empty model fields, causing cost
calculation to skip them. This adds a last-seen model fallback in
sessionFromNodes, adds claude-haiku-4.6 to the pricing table, and
falls back to the request model in streaming responses.
Copy link
Contributor

@oppegard oppegard left a comment

Choose a reason for hiding this comment

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

I'm not really familiar with much of the codebase yet, so let me know if this is a non-issue.

Codex found this issue:

Apply empty-model fallback in detail costing
buildSessionSummaryFromNodes now reuses the previous model when n.Model is empty, but buildSessionMessages still calls costForNode, which returns zero cost for empty-model nodes. In sessions with streamed responses missing Model, the summary and overview totals will now include those costs while per-message and grouped-message totals remain at zero, producing inconsistent cost reporting for the same session (summary vs detail view).

I had it write a simple failing test to show the inconsistency. I ran code coverage on the deck package as well, and it appears we don't have any tests exercising buildSessionMessages() in query.go.

It("keeps summary and message totals consistent", func() {
		pricing := DefaultPricing()
		q := &Query{pricing: pricing}

		nodes := []*ent.Node{
			{ID: "node-1", Role: "user", Model: "claude-opus-4-6-20260219"},
			{
				ID:               "node-2",
				Role:             "assistant",
				Model:            "",
				CompletionTokens: intPtr(500000),
			},
		}

		summary, _, _, err := q.buildSessionSummaryFromNodes(nodes)
		Expect(err).NotTo(HaveOccurred())

		messages, _ := q.buildSessionMessages(nodes)
		messageTotal := 0.0
		for _, msg := range messages {
			messageTotal += msg.TotalCost
		}

		Expect(summary.TotalCost).To(BeNumerically("~", messageTotal, 1e-12))
	})

Copy link
Contributor Author

@bdougie bdougie left a comment

Choose a reason for hiding this comment

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

Good catch — this is a real inconsistency. buildSessionMessages was calling costForNode which bails on empty models, while buildSessionSummaryFromNodes had the last-seen model fallback. Summary says "$X" but per-message detail sums to "$0" for those nodes.

Fixed in the latest push:

  • Renamed costForNodecostForModel (accepts a model string directly)
  • Added the same lastModel tracking to buildSessionMessages
  • Resolved model is now set on SessionMessage.Model too, so the detail view shows the correct model
  • Added your consistency test (summary.TotalCost ≈ Σ message.TotalCost) — 126 deck tests and 55 proxy tests pass

@bdougie bdougie requested a review from oppegard February 25, 2026 01:03
@bdougie bdougie merged commit 847f7e9 into main Feb 25, 2026
12 checks passed
@bdougie bdougie deleted the fix/session-cost-calculation branch February 25, 2026 16:50
@continue
Copy link

continue bot commented Feb 25, 2026

No docs update needed. This PR fixes an internal bug in session cost calculation where response nodes with empty model fields were being skipped. The changes are:

  1. Cost calculation fallback: Uses last-seen model when response nodes have empty model fields
  2. Missing pricing: Adds claude-haiku-4.6 to the internal pricing table
  3. Streaming model fallback: Falls back to request model when reconstructed response has empty model

These are all internal implementation fixes that don't change any user-facing configuration, commands, or documented behavior. The cost display in tapes deck will now show accurate costs instead of $0.00 for affected sessions, but no documentation changes are required since cost calculation was already a documented/expected feature.

PR #133 was merged: fix: resolve $0.00 session costs in tapes deck
PR URL: #133
Merged by: bdougie

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