Problem
usage_events table is created on store init (internal/memory/store.go:171-187) and the RecordUsageEvent / RecordExecutionUsage writers exist in internal/memory/metering.go, but no production code calls them:
$ grep -rn "RecordUsageEvent\|RecordExecutionUsage" internal/ cmd/ --include="*.go" | grep -v "_test.go\|metering.go"
# (no results)
Result: SELECT COUNT(*) FROM usage_events → 0 rows, ever. The billing/metering pipeline is dead code.
All cost data still lives in executions.estimated_cost_usd (legacy single-row-per-execution model), which:
- Doesn't separate task vs. token vs. compute vs. api_call event types (the whole reason
usage_events was designed)
- Has no
user_id (multi-tenancy can't aggregate per-user spend)
- Has no
metadata field for per-event context (cache hit ratio, model variant, etc.)
Suggested fix
In internal/executor/dispatcher.go worker loop (around line 669, where SaveExecutionMetrics is called):
if result != nil && result.TokensTotal > 0 {
if err := w.store.RecordExecutionUsage(exec.ID, exec.UserID, exec.ProjectPath, result); err != nil {
w.log.Error("Failed to record usage event", slog.Any("error", err))
}
}
RecordExecutionUsage already exists at metering.go:130-187 and emits 3 events per execution (task, token, compute). It just needs a caller.
Why it matters
- Multi-user / team mode (per
team_members, teams tables) needs per-user cost rollups. usage_events.user_id is the designed pivot.
- Future budget enforcement / billing export depends on this table.
- We currently can't answer "how much did GLM vs. Claude cost us this week" without parsing
executions.metadata.
Verification
After fix: run any task, then SELECT * FROM usage_events ORDER BY timestamp DESC LIMIT 5 should show 3 rows per execution (task + token + compute event types).
Scope
Small: ~1 call site in dispatcher + plumb UserID through Execution struct if missing. Tests already exist in metering_test.go.
Refs
internal/memory/metering.go:110,130-187
internal/memory/store.go:171-187
internal/executor/dispatcher.go:669
Problem
usage_eventstable is created on store init (internal/memory/store.go:171-187) and theRecordUsageEvent/RecordExecutionUsagewriters exist ininternal/memory/metering.go, but no production code calls them:Result:
SELECT COUNT(*) FROM usage_events→ 0 rows, ever. The billing/metering pipeline is dead code.All cost data still lives in
executions.estimated_cost_usd(legacy single-row-per-execution model), which:usage_eventswas designed)user_id(multi-tenancy can't aggregate per-user spend)metadatafield for per-event context (cache hit ratio, model variant, etc.)Suggested fix
In
internal/executor/dispatcher.goworker loop (around line 669, whereSaveExecutionMetricsis called):RecordExecutionUsagealready exists atmetering.go:130-187and emits 3 events per execution (task, token, compute). It just needs a caller.Why it matters
team_members,teamstables) needs per-user cost rollups.usage_events.user_idis the designed pivot.executions.metadata.Verification
After fix: run any task, then
SELECT * FROM usage_events ORDER BY timestamp DESC LIMIT 5should show 3 rows per execution (task + token + compute event types).Scope
Small: ~1 call site in dispatcher + plumb
UserIDthroughExecutionstruct if missing. Tests already exist inmetering_test.go.Refs
internal/memory/metering.go:110,130-187internal/memory/store.go:171-187internal/executor/dispatcher.go:669