Files
jason.woltje 068d868a99 lead: commit rocko's untracked evidence (4471 files: queue-124 queue-129 queue-171 queue-178 queue-280 queue-31 queue-84 queue-85 queue-94)
Unclaimed files left in the canonical checkout. Inventory: canonical-cleanup-inventory.md (commit-as-evidence groups). detect-secrets scan clean on 2026-11-02: hits are sha256 pins, git object ids, test sentinels already in tracked tests and unit-file lines.
2026-11-02 15:05:15 -06:00

70 lines
4.0 KiB
Markdown

# Row 124: token accounting per run
Approved brief: docs/plans/2026-10-14_prd-1.2-build.md, Token accounting per run,
re-pinned by sage-0705; base 9098c33f7. REQ-LIMIT-2/3 counting foundation,
REQ-LIMIT-4, REQ-PLUG-1 and REQ-WEB-1. No enforcement or account discovery.
## Data flow
The runner brackets each actual harness invocation with usage.begin/usage.end.
These are private runner protocol verbs, not harness tools. The broker binds
business/run/instance/harness; the runtime derives filesystem roots and the
provider/model from the trusted launch record/model selection. Callers supply
only the delivered message id, never a host path or token count. The bus calls
all configured usage sources through packages/plugins' loader. Broker imports
remain free of host filesystem/plugin implementations, preserving client sandbox
import closure. The runtime injects an accounting adapter, like the project one.
A source's interfaceVersion remains 1. readTurn(context) returns a bounded
snapshot of assistant-message usage, or {status:'unknown',code}. The accounting
adapter takes a snapshot before and after each turn and records only new usage;
this excludes history when a thread resumes in a new run. Baselines and outcomes
are durable and retries of one run/message are idempotent. Missing begin,
failed/malformed source, missing end data, rewritten prior entries or no enabled
source means unknown, never a fabricated zero. Separate source records preserve
which source reported which counts. Totals sum reported records; unknown turns
are counted distinctly by run/message beside each grouping's totals.
## Hostile filesystem boundary
The transcript plug-in opens directories one component at a time using
O_DIRECTORY|O_NOFOLLOW and anchored /proc/self/fd paths on Linux. Final files
open O_NOFOLLOW|O_NONBLOCK, must be regular single-link files, and are checked
with fstat before/after bounded reads. Directory count, file count, total bytes,
line bytes and record count are bounded. Malformed/truncated JSONL, invalid UTF-8,
invalid/negative/noninteger counters, unsafe paths, source failures and overflow
return an unknown code. No transcript content or parse exception text is logged.
Every guard receives a targeted fixture and mutant.
Claude assistant entries use message.id and usage input_tokens/output_tokens/
cache_creation_input_tokens/cache_read_input_tokens. Pi message entries use id
and message.usage input/output/cacheWrite/cacheRead. Non-assistant valid JSON
lines do not count; repeated identical message IDs do not double count. The
reader returns only usage metadata. A session can edit its own transcript:
these counts are the stack's best reading, not proof.
## Persistence and views
Schema 3g→3h adds an append-only accounting table with per-source begin/end
records and explicit unknown status/reason. Prior evidence is untouched. Test
on a copied fixture DB built from base schema.sql, never the live store. Keep
future migration chaining and all schema-version assertions current.
usage is a business-scoped read, returning total and by-run/instance/provider/
model/account groups. Each total shows input/output/cacheWrite/cacheRead and
unknownTurns. account stays null. mosaic usage [--json] formats that view;
Settings adds its own Token usage section, separate from row 155's editor.
No enforcement, resets or organization edits ship; the packet gives the exact
plugins.usage-source change needed to enable transcript. Public landing waits
for Mos's go (decision 123), schema migration/re-pin is Mos's downtime window.
## Execution and evidence
Implement transcript fixtures first, then the bounded reader; migration and
accounting tests, broker/runtime/runner integration; CLI and Settings tests.
Run fixture-only single files while building. Ask Sage before any package suite,
browser test, mutant batch or gate. One mutant per acceptance/security check;
restore source and process groups on every exit. Prepare BUILD.md, migration
procedure, changed-paths, patch and both manifests. No source commit/push/live
read or action. Sage posts review after the claimant's no-token in-review move.