Reproduced the same defect class on T3 0.0.36 with a non-OpenRouter OpenCode setup, so this doesn't look OpenRouter-specific.
Root cause (read out of the 0.0.36 server bundle): OpenCode uses its own SDK-based provider adapter, and its handleSubscribedEvent branch for case "message.updated" tracks role/text but discards event.properties.info.tokens — the AssistantMessage.tokens ({ input, output, reasoning, cache: { read, write } }, plus providerID/modelID) that the OpenCode SDK already delivers on every assistant message update. So the adapter never emits thread.token-usage.updated, and the existing thread.token-usage.updated -> context-window.updated pipeline (which Claude and Codex both feed) never sees an OpenCode reading. Same class as #8382, but a different code path: #8382 is the shared ACP usage_update gap, while 0.0.36 OpenCode goes through this SDK adapter.
Fix validated locally: emit the snapshot from message.updated (assistant role + tokens present) through the adapter's existing event idiom, using OpenCode's own canonical semantics from the latest assistant message — usedTokens = input + cache.read + cache.write, totalProcessedTokens = input + output + reasoning + cache.read + cache.write, maxTokens from live provider.list() model metadata (model.limit.context). No historic summation; a later smaller (post-compaction) snapshot supersedes.
Live-validated in the composer: pre-fix, OpenCode threads (including one with 7 completed turns) had zero context-window.updated rows; post-fix, turns emit them and the meter populates and keeps updating, e.g. {"usedTokens":199101,"inputTokens":2252,"cachedInputTokens":196849,"outputTokens":305,"reasoningOutputTokens":70,"totalProcessedTokens":199476,"maxTokens":1048576} with usedTokens == input + cache.read holding on every snapshot (54/54 checked), and maxTokens matching the model's real context window. The reporter is right that running opencode directly shows a working indicator — that indicator reads exactly these AssistantMessage.tokens, which T3 was dropping. Covered with regression tests for the snapshot semantics, the memoized/in-flight-deduped metadata lookup (transient failures emit without a denominator and retry), compaction (latest-wins, never summed), and interrupt-safety (abort never erases the last valid snapshot).