fix: [#836] always emit tokens_input_total + document token semantics

Merged
AN
5mo ago
+295-8

What does this PR do?

Resolves the "Anthropic tokens_input=0 broken" false-positive from telemetry-2026-05-21 (54k Sonnet generations). The field was working as designed — full cache hits legitimately produce tokens_input=0 because tokens_input is normalized to mean uncached input tokens only across providers. The dashboard query needed the inclusive tokens_input_total field, but it was emitted conditionally and absent on non-cache-using providers — making queries return null and reinforcing the confusion.

Three changes:

  1. session/processor.ts — drop the conditional emit, always include tokens_input_total. ~12 bytes per event, negligible.
  2. telemetry/index.ts — tighten the schema from tokens_input_total?: number to tokens_input_total: number. The always-present contract now lives in the type system.
  3. telemetry/index.ts — add a doc-block above the generation event type explicitly documenting the cross-provider semantics. Single biggest documentation gap surfaced by the May 21 triage.

Type of change

  • Bug fix (non-breaking change which fixes an issue)

Issue for this PR

Closes #836

How did you verify your code works?

  • tsgo --noEmit: pass
  • bun test test/session/session-getusage.test.ts: 7 pass / 0 fail (new test file)
  • bun test test/session/session-getusage.test.ts test/session/compaction.test.ts test/altimate/training-import.test.ts: 41 pass / 0 fail
  • Marker check: pass — altimate_change markers applied
  • 7 new tests pin the cross-provider normalization invariant: tokens.input + tokens.cache.read + tokens.cache.write === tokens.inputTotal — across Anthropic-style (uncached) and OpenAI-style (inclusive) usage shapes

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes
  • Marker check passes
  • Linked to issue #836

Files changed (3):

  • packages/opencode/src/altimate/telemetry/index.ts — schema doc + tighten type
  • packages/opencode/src/session/processor.ts — always emit
  • packages/opencode/test/session/session-getusage.test.ts (new) — 7 invariant tests

Expected impact: Dashboard queries get tokens_input_total on every generation event without null-coalescing. The "Anthropic tokens_input=0 broken" finding disappears once dashboards switch to tokens_input_total for input volume queries. No behavior change for cost calculation.

P0 series progress (telemetry-2026-05-21):

  • #827 / #828: finops_* 100% failure
  • #830 / #831: project_scan 32% errors
  • #832 / #833: build agent 0% completion
  • #834 / #835: todowrite runaway
  • #836 / this PR: tokens_input semantics

Summary by cubic

Always emit tokens_input_total, clamp negative derived inputs to zero, and document cross‑provider token semantics so input volume queries are reliable and costs never go negative. Resolves #836.

  • Bug Fixes

    • Always emit tokens_input_total in session/processor.ts.
    • Tighten telemetry/index.ts to tokens_input_total: number and clarify cache_write semantics (Anthropic/Bedrock/Venice only; OpenAI/OpenRouter is a no‑op).
    • Clamp uncached input to 0 in session/index.ts to prevent negative cost when provider counts are inconsistent.
    • Add tests covering Anthropic/OpenAI, @ai-sdk/google-vertex/anthropic, Bedrock, and Venice; harden telemetry/processor tests to include tokens_input_total.
  • Migration

    • Update dashboards to use tokens_input_total for input volume.
    • No changes needed for cost calculations.

Summary by CodeRabbit

  • Improvements

    • Total input tokens are now always reported for generation events, improving telemetry consistency.
    • Adjusted input token counts are clamped at zero to prevent negative values and incorrect cost calculations.
    • Token accounting preserves the invariant: input + cache.read + cache.write == inputTotal.
  • Tests

    • Added comprehensive tests covering token normalization, cache accounting, edge cases and multi-provider scenarios.

Review Change Stack