Symptom
Every Pi/OMP historian run shows input: 0 / output: 0 in the dashboard — including healthy 30–90s completed runs — while OpenCode-harness runs show real counts. From the shared DB:
opencode historian: 1506 nonzero rows, 47.9M input / 1.6M output tokens recorded
pi + omp historian: 345 rows, all 0/0 — every row, ever
Work demonstrably happened (durations, compartments produced); only the metering is blind.
Cause chain (verified live against 0.41.4 + omp 18.1.11)
- omp emits usage. Live probe
omp --print --mode json --no-session: message_end / turn_end / agent_end all carry message.usage = {input: 20153, output: 17, cacheRead: 241, cacheWrite: 0, totalTokens, reasoningTokens, cost} — structurally checked, not substring-matched.
- The plugin never captures it.
spawnPiHistorianRun builds {agentResponses, toolCalls, assistantTexts, ...} from the child stream with no usage plumbing, and the 0.41.4 bundle contains zero writes of usage into subagent_invocations on the Pi path (61 invocation hits, all unrelated graph terms).
- No backfill path either. Session-entry-based
computePiWorkMetrics reads message.usage from persisted entries — but historian children run with --no-session (ephemeral), so there are no entries to sum.
Net: the data exists in the child event stream, the expected shape ({input, output, cacheRead}) even matches the existing extractPiUsage-style extractor — it is simply never transferred into the invocation row.
Suggested fix
Capture message.usage from the child turn_end/agent_end events in spawnPiHistorianRun (or the finalize step) and persist input/output/cacheRead/cacheWrite on the invocation row, same as the OpenCode lane does from its runner callback.
Symptom
Every Pi/OMP historian run shows
input: 0 / output: 0in the dashboard — including healthy 30–90s completed runs — while OpenCode-harness runs show real counts. From the shared DB:opencodehistorian: 1506 nonzero rows, 47.9M input / 1.6M output tokens recordedpi+omphistorian: 345 rows, all 0/0 — every row, everWork demonstrably happened (durations, compartments produced); only the metering is blind.
Cause chain (verified live against 0.41.4 + omp 18.1.11)
omp --print --mode json --no-session:message_end/turn_end/agent_endall carrymessage.usage = {input: 20153, output: 17, cacheRead: 241, cacheWrite: 0, totalTokens, reasoningTokens, cost}— structurally checked, not substring-matched.spawnPiHistorianRunbuilds{agentResponses, toolCalls, assistantTexts, ...}from the child stream with no usage plumbing, and the 0.41.4 bundle contains zero writes of usage intosubagent_invocationson the Pi path (61invocationhits, all unrelated graph terms).computePiWorkMetricsreadsmessage.usagefrom persisted entries — but historian children run with--no-session(ephemeral), so there are no entries to sum.Net: the data exists in the child event stream, the expected shape (
{input, output, cacheRead}) even matches the existingextractPiUsage-style extractor — it is simply never transferred into the invocation row.Suggested fix
Capture
message.usagefrom the childturn_end/agent_endevents inspawnPiHistorianRun(or the finalize step) and persistinput/output/cacheRead/cacheWriteon the invocation row, same as the OpenCode lane does from its runner callback.