feat(billing): agent-side spend records who was paid
Judge spend gained provider, model and mission on 2026-09-14; agent spend — the larger half — did not. The runtime's `done` frame has always carried `model` and `provider` beside the two token counts, and `topology_exec` read only the counts, summed them, and charged the sum as output with no record of which provider served the turn. `TurnOutcome` and `StepRecord` carry a `Spend` now (input/output split, provider, model), the worker passes it through `cm_billing::charge` along with the mission id, and the chat runtime records the model it requested — that loop drives one provider with no chain, so requested is answered. A bare model name is recorded without a guessed family. `StepRecord.spend` is `serde(default)` so journaled checkpoints from before this field still load, and `tokens` stays as the total every reader keys on. `charge` moved from `query!` to `query`: the macro pins the statement to offline metadata that a schema change then has to regenerate against a live database, for columns that are nullable text and uuid. The done-frame test now asserts the split and the provider survive, not just the sum. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01WZb5A2kfVfjpdwSochkuHz
This commit is contained in:
co-authored by
Claude Opus 5
parent
736b6a9a82
commit
483de9f88a
@@ -62,7 +62,7 @@ async fn charges_span_lots_oldest_first_and_record_usage() {
|
||||
.unwrap();
|
||||
|
||||
// 2500 tokens → 3 credits: drains the first lot (2) then one more.
|
||||
let deducted = charge(&pool, ws.id, agent.id, Some(run_id), 1500, 1000)
|
||||
let deducted = charge(&pool, ws.id, agent.id, Some(run_id), 1500, 1000, None, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(deducted, 3);
|
||||
@@ -96,7 +96,7 @@ async fn an_empty_workspace_records_usage_but_clamps_at_zero() {
|
||||
.unwrap();
|
||||
|
||||
// Owes 5, only 1 available: deducts 1, balance hits zero, never negative.
|
||||
let deducted = charge(&pool, ws.id, agent.id, Some(run_id), 4000, 500)
|
||||
let deducted = charge(&pool, ws.id, agent.id, Some(run_id), 4000, 500, None, None, None)
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(deducted, 1);
|
||||
|
||||
Reference in New Issue
Block a user