Skip to content

feat(server): account for token usage per dispatch (#346 DI-33) - #354

Merged
m2ux merged 1 commit into
mainfrom
feat/di33-per-dispatch-usage
Jul 30, 2026
Merged

feat(server): account for token usage per dispatch (#346 DI-33)#354
m2ux merged 1 commit into
mainfrom
feat/di33-per-dispatch-usage

Conversation

@m2ux

@m2ux m2ux commented Jul 30, 2026

Copy link
Copy Markdown
Owner

The engine half of DI-33 from #346.

The defect

next_activity recorded an activity_usage event keyed to the activity a transition exits. So a dispatch not followed by a transition never reached the ledger:

  • a resume after a checkpoint yield
  • a re-dispatch after a timeout
  • an out-of-band dispatch
  • an abandoned session
  • the terminal activity, which nothing exits

The review run that surfaced this reported 2,751,188 tokens against an actual 4,130,657 across 33 dispatches — a third of the run missing, including the pass that produced both Critical findings its verdict rested on.

The change

Cost belongs to a dispatch, not to a graph edge.

record_usage { session_index, activity, usage } writes one event per dispatch, and next_activity no longer takes usage at all. One write path, so there is no double-count to guard against and no attribution question to answer.

That also retires usageWarning, which fired when usage rode an entry transition that exits nothing. The case only existed because an edge was being asked to carry a dispatch's cost — remove the premise and the warning has nothing to warn about.

The activity_usage event type is unchanged, so projectUsage and the inspect_session usage view needed no edit. That projection already documented one entry per pass and left summing to the caller, which is exactly the shape per-dispatch accounting wants — only the write side was missing.

Absence stays distinguishable from zero: omit the call when the harness surfaces nothing, since a worker cannot self-measure.

This is a breaking change to next_activity

An optional parameter is removed. Nothing in the repo passes it after this change, and the orchestrator contract that told callers to pass it is updated in #351. Pre-1.0, and pre-merge, is the moment to do this rather than carry two paths.

Worth flagging honestly: I first assessed the parameter as having no dependents. Three tests did — a dedicated next_activity usage accounting (#324 B1) suite, including a deliberately-designed test for the entry-transition warning. So this removes a considered, tested design, not an oversight. I still think it is right, because that warning is itself evidence the transition model was awkward, but it deserves a reviewer's eye rather than being presented as a tidy-up.

Tests

The #324 B1 suite encoded transition attribution, so it moves onto record_usage rather than living alongside it. Two cases added:

  • a dispatch the graph never transitions away from — the case the old model structurally could not reach
  • two dispatches of one activity stay separate rows — a merged total is precisely what hid the shortfall

The entry-transition warning test is dropped, because the case no longer exists.

Merge order

#354#351#352.

#351 updates dispatch-activity's account-every-dispatch rule to call record_usage, so this must land first or that rule names a tool the server does not have. (An earlier revision of this description said "merges in any order" — that was written before the definitions follow-up existed.)

Verification

17/17 guards, 745 tests. The site's tool-group drift guard caught record_usage being ungrouped — it sits under Trace, whose note now covers cost accounting, and site/api/tools.html is regenerated.

A closing sweep checked the changeover for residue: usageWarning is gone entirely, usageSchema has exactly its declaration and one use, and five pieces of prose that still described cost as belonging to a transition — or defined the new call by what the old one no longer does — were rewritten to state the new model directly.

Refs #346

🤖 Generated with Claude Code

@m2ux
m2ux force-pushed the feat/di33-per-dispatch-usage branch 2 times, most recently from f4928d7 to 490b28f Compare July 30, 2026 06:29
@m2ux m2ux changed the title feat(server): record_usage, so the token ledger can see every dispatch (#346 DI-33) feat(server): move usage accounting off the transition and onto the dispatch (#346 DI-33) Jul 30, 2026
`next_activity` recorded an `activity_usage` event keyed to the activity a
transition EXITS, so any dispatch not followed by a transition never reached the
ledger: a resume after a checkpoint yield, a re-dispatch after a timeout, an
out-of-band dispatch, an abandoned session, and the terminal activity, which
nothing exits. The review run that surfaced this reported 2,751,188 tokens against
an actual 4,130,657 across 33 dispatches.

Cost belongs to a dispatch, not to a graph edge. `record_usage { session_index,
activity, usage }` writes one event per dispatch, and `next_activity` no longer
takes `usage` at all — one write path, so there is no double-count to warn about
and no attribution question to answer. The `usageWarning` that fired when usage
rode an entry transition goes with it: that case only existed because an edge was
being asked to carry a dispatch's cost.

The event type is unchanged, so projectUsage and the inspect_session usage view
need no edit — that projection already documented one entry per exit and left
summing to the caller, which is the shape per-dispatch accounting wants.

Absence stays distinguishable from zero: omit the call when the harness surfaces
nothing, since a worker cannot self-measure.

Tests: the #324 B1 suite encoded transition attribution, including the entry-edge
warning, so it moves onto record_usage rather than being kept alongside. Added
cover for the case the old model could not reach — a dispatch the graph never
transitions away from — and for two dispatches of one activity staying separate
rows, since a merged total is what hid the shortfall. The entry-edge warning test
is dropped: the case no longer exists.

The site's tool-group drift guard caught record_usage being ungrouped; it sits
under Trace, whose note now covers cost accounting.

Refs #346

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@m2ux
m2ux force-pushed the feat/di33-per-dispatch-usage branch from 490b28f to 3bf6560 Compare July 30, 2026 06:44
@m2ux m2ux changed the title feat(server): move usage accounting off the transition and onto the dispatch (#346 DI-33) feat(server): account for token usage per dispatch (#346 DI-33) Jul 30, 2026
@m2ux
m2ux merged commit 6ae1f59 into main Jul 30, 2026
4 checks passed
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