feat(server): account for token usage per dispatch (#346 DI-33) - #354
Merged
Conversation
m2ux
force-pushed
the
feat/di33-per-dispatch-usage
branch
2 times, most recently
from
July 30, 2026 06:29
f4928d7 to
490b28f
Compare
`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
force-pushed
the
feat/di33-per-dispatch-usage
branch
from
July 30, 2026 06:44
490b28f to
3bf6560
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The engine half of DI-33 from #346.
The defect
next_activityrecorded anactivity_usageevent keyed to the activity a transition exits. So a dispatch not followed by a transition never reached the ledger: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, andnext_activityno longer takesusageat 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_usageevent type is unchanged, soprojectUsageand theinspect_sessionusage 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_activityAn 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 B1suite encoded transition attribution, so it moves ontorecord_usagerather than living alongside it. Two cases added:The entry-transition warning test is dropped, because the case no longer exists.
Merge order
#354 → #351 → #352.
#351 updates
dispatch-activity'saccount-every-dispatchrule to callrecord_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_usagebeing ungrouped — it sits under Trace, whose note now covers cost accounting, andsite/api/tools.htmlis regenerated.A closing sweep checked the changeover for residue:
usageWarningis gone entirely,usageSchemahas 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