🌐 US-Proxy
class="logged-out env-production page-responsive" style="word-wrap: break-word;" >
Skip to content

feat(coderd): accumulate user daily AI spend on token usage - #26741

Merged
ssncferreira merged 3 commits into
mainfrom
ssncf/ai-spend-on-token-usage
Jul 2, 2026
Merged

feat(coderd): accumulate user daily AI spend on token usage#26741
ssncferreira merged 3 commits into
mainfrom
ssncf/ai-spend-on-token-usage

Conversation

@ssncferreira

@ssncferreira ssncferreira commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

Adds post-response spend accumulation to RecordTokenUsage.

Changes

  • Wrap the token usage insert and daily spend increment in a single transaction.
  • Skip the spend update when the user is unbudgeted, the model is unpriced, or the computed cost is non-positive.

Depends on #26562

Closes https://linear.app/codercom/issue/AIGOV-427/add-post-response-spend-accumulation

Note

Initially generated by Claude Opus 4.7, modified and reviewed by @ssncferreira

ssncferreira commented Jun 26, 2026

Copy link
Copy Markdown
Contributor Author

@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from cc3228d to 314d33b Compare June 26, 2026 10:47
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch from bb18cf7 to b2c90c2 Compare June 26, 2026 10:47
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch 2 times, most recently from c39f028 to 8b7c712 Compare June 26, 2026 15:02
@linear-code

linear-code Bot commented Jun 26, 2026

Copy link
Copy Markdown

AIGOV-427

@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from 8b7c712 to 111133e Compare June 26, 2026 15:27
@ssncferreira

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Chat: Review posted | View chat
Requested: 2026-06-26 15:32 UTC by @ssncferreira
Spend: $22.66 / $100.00

Review history
  • R1 (2026-06-26): 13 reviewers, 1 Nit, 2 Note, 1 P2, 3 P3, COMMENT. Review

deep-review v0.9.0 | Round 1 | b2c90c2..111133e

Last posted: Round 1, 7 findings (1 P2, 3 P3, 1 Nit, 2 Note), COMMENT. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P3 Open aibridgedserver.go:792 calendarUTCDay duplicates dbtime.StartOfDay R1 Netero Yes
CRF-2 Nit Open aibridgedserver.go:305 Bare error return breaks wrapping convention R1 Netero Yes
CRF-3 P2 Open aibridgedserver.go:311 Doc comment promises unconditional spend accumulation R1 Gon P2, Leorio P3 Yes
CRF-4 P3 Open aibridgedserver.go:338 Debug log omits initiator_id R1 Leorio Yes
CRF-5 Nit Dropped by orchestrator (subsumed by CRF-1) aibridgedserver.go:791 Doc comment restates calendarUTCDay body R1 Gon No
CRF-6 P3 Open aibridgedserver.go:350 Day comment bloated R1 Gon Yes
CRF-7 Note Open aibridgedserver.go:337 Skip condition silently drops negative cost R1 Kite Yes
CRF-8 Note Open aibridgedserver_test.go:1180 Test comment bloat pattern R1 Gon Yes

Round log

Round 1

Panel. Netero first pass clean (P3 + Nit). Panel: Bisky, Chopper, Ging-Go, Gon, Hisoka, Kite, Komugi, Leorio, Mafu-san, Mafuuu, Meruem, Pariston, Knov (wildcard). 1 P2, 3 P3, 2 Nit, 2 Note. 1 dropped (CRF-5 subsumed by CRF-1). Reviewed against b2c90c2..111133e.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Clean design. The transaction wrapping is correct (both writes use tx, not s.store), the skip condition covers all four budget-by-price states, and the test matrix exercises every branch, both happy-path resolution strategies (group lookup + user override), and both error paths. The integration test verifies the full write path through dbauthz and reads the spend row back from a real database. 80% test density, 60 production LOC, no scope drift.

As Pariston put it: "I tried to build a case against this change and could not."

Severity count: 1 P2, 3 P3, 2 Nit, 2 Note.

The P2 is the doc comment on recordTokenUsageAndSpend claiming unconditional accumulation when the function conditionally skips. The remaining findings are comment quality, a missing log field, and a minor code duplication.

🤖 This review was automatically generated with Coder Agents.

Comment thread coderd/aibridgedserver/aibridgedserver.go Outdated
Comment thread coderd/aibridgedserver/aibridgedserver.go
Comment thread coderd/aibridgedserver/aibridgedserver.go
Comment thread coderd/aibridgedserver/aibridgedserver.go Outdated
Comment thread coderd/aibridgedserver/aibridgedserver.go Outdated
Comment thread coderd/aibridgedserver/aibridgedserver.go
@@ -1176,71 +1178,16 @@ func TestRecordTokenUsage(t *testing.T) {
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Note [CRF-8] Test comment bloat is a pattern in this PR. 14 of 17 test comments restate the test name (// Budget resolves via group lookup, model is priced. on a test named "with effective group and cost"), the mock expectation (// Spend update is skipped because cost is NULL. on IncrementUserAIDailySpend.Times(0)), or use more words than needed. The test names are already descriptive and the assertions are clear. Comments that add the skip-reason (which branch of the guard) are the valuable ones; the rest could be trimmed or removed. (Gon)

🤖

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I find these comments relevant, and they helped me when restructuring the tests to make sure all cases are covered. But happy to remove them if they are not useful for others 🙂

@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from 111133e to e769e76 Compare June 29, 2026 12:40
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch from b2c90c2 to 38c650b Compare June 29, 2026 12:40
EffectiveGroupID: cost.effectiveGroupID.UUID,
// Day is derived from the record usage request CreatedAt
// so it matches the token usage row's created_at column.
Day: dbtime.StartOfDay(createdAt.UTC()),

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Initially, I was using a new clock for Day, but then realized the request's CreatedAt already carries the time the token usage was created on the aibridge side. To keep the database consistent and the spend Day deterministic from the aibridge_token_usages table (source of truth), I switched to deriving it from CreatedAt. This handles the edge case where token usage is created on the aibridge side on day X, but the request reaches coderd after midnight, so time.Now() would return day X+1. Let me know if you see any issues.

@ssncferreira
ssncferreira marked this pull request as ready for review June 29, 2026 12:44
Comment thread coderd/aibridgedserver/aibridgedserver.go
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from e769e76 to ce79640 Compare June 29, 2026 13:31
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from 2fbae8e to ec306e5 Compare June 29, 2026 14:20
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch 2 times, most recently from 888ac85 to dee171f Compare June 30, 2026 14:16
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from ec306e5 to f1c6469 Compare June 30, 2026 14:16
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch from dee171f to 6e8896d Compare July 1, 2026 12:09
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from f1c6469 to 13eb001 Compare July 1, 2026 12:09
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch from 6e8896d to 41ad5f2 Compare July 2, 2026 14:51
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from 13eb001 to dbb6f44 Compare July 2, 2026 14:51
@ssncferreira
ssncferreira force-pushed the ssncf/ai-user-daily-spend branch from 41ad5f2 to ae35c71 Compare July 2, 2026 14:58
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from dbb6f44 to 04e366f Compare July 2, 2026 14:58

ssncferreira commented Jul 2, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Jul 2, 3:29 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 2, 3:31 PM UTC: Graphite rebased this pull request as part of a merge.
  • Jul 2, 3:42 PM UTC: @ssncferreira merged this pull request with Graphite.

@ssncferreira
ssncferreira changed the base branch from ssncf/ai-user-daily-spend to graphite-base/26741 July 2, 2026 15:29
@ssncferreira
ssncferreira changed the base branch from graphite-base/26741 to main July 2, 2026 15:29
@ssncferreira
ssncferreira force-pushed the ssncf/ai-spend-on-token-usage branch from 04e366f to 4aa77ba Compare July 2, 2026 15:30
@ssncferreira
ssncferreira merged commit be9c95c into main Jul 2, 2026
29 of 30 checks passed
@ssncferreira
ssncferreira deleted the ssncf/ai-spend-on-token-usage branch July 2, 2026 15:42
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 2, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants