Skip to content

cost.json per-run records capture only one side of the token ledger (input OR output = 0 per run), making totals and GRAPH_REPORT.md 'Token cost' misleading (v0.8.36) #3658

Description

@nihviid

Summary

graphifyy==0.8.36 records per-run token usage in graphify-out/cost.json with only one side of the ledger per run: a run books either input_tokens or output_tokens, never both (the other side is 0). The total_input_tokens / total_output_tokens sums over these one-sided records — and the - Token cost: N input · M output line report.py renders into GRAPH_REPORT.md — therefore understate real usage and mislead any human or CI gate that trusts them.

Environment

  • graphifyy version: 0.8.36 (exact pin in CI; latest at time of filing: 0.9.63 — unverified whether still affected)
  • OS: ubuntu-latest (GitHub Actions runner), Python 3.11
  • Command: graphify update <repo> --force invoked from CI after each merge to main

Minimal reproduction

Two consecutive graphify update runs on the same repository (CodeBus), from the committed graphify-out/cost.json:

{
  "runs": [
    {
      "date": "2026-06-09T20:34:51.846794+00:00",
      "input_tokens": 0,
      "output_tokens": 62833,
      "files": 44
    },
    {
      "date": "2026-06-12T06:46:50.591041+00:00",
      "input_tokens": 64786,
      "output_tokens": 0,
      "files": 168
    }
  ],
  "total_input_tokens": 64786,
  "total_output_tokens": 62833
}

Steps:

  1. pip install graphifyy==0.8.36
  2. Run graphify update <repo> --force against a corpus that requires LLM extraction (run A).
  3. Run graphify update <repo> --force again after repo changes (run B).
  4. Inspect graphify-out/cost.json and the - Token cost: line in graphify-out/GRAPH_REPORT.md.

Expected

Each run records both sides of its own usage (input_tokens > 0 and output_tokens > 0 for any run that performed LLM extraction), and totals are the sum of complete per-run records.

Actual

  • Run A recorded input_tokens: 0, output_tokens: 62833 — extraction of 44 files consumed input tokens; they were not captured.
  • Run B recorded input_tokens: 64786, output_tokens: 0 — extraction of 168 files produced output tokens; they were not captured.
  • GRAPH_REPORT.md (rendered from the latest run) claims - Token cost: 64,786 input · 0 output, i.e. "this build produced zero output tokens", which is impossible for a run that extracted 168 files.
  • The totals (64786 / 62833) are sums over one-sided records: each total comes entirely from a different run.

The pattern suggests the usage-capture path differs per backend/mode: one code path populates only output_tokens (e.g. an agent/CLI-backend result whose input_tokens placeholder is never overwritten), the other only input_tokens, and the merged/persisted record keeps the zeros instead of failing loudly or marking the side as unknown.

Impact

  • Any cost dashboard, budget gate, or human reading cost.json / GRAPH_REPORT.md silently under-accounts real token spend (one side is always 0 per run).
  • Downstream CI (ours: CodeBus graphify-on-merge.yml) publishes these numbers into an internal report; we now have to mark the accounting UNTRUSTED until fixed.

Related

Suggested fix direction

  1. In every backend's usage capture, treat a missing side as unknown, not 0, and refuse to persist a run record with an unknown side without flagging it (e.g. "input_tokens": null + a partial: true marker).
  2. Make report.py's - Token cost: line render partial/unknown records explicitly instead of printing a confident 0.
  3. Add a regression test asserting a two-run sequence where both runs did LLM work yields input_tokens > 0 && output_tokens > 0 in each run record.

Reported from CodeBus issue #271 (Bragi-GmbH/CodeBus). Full in-repo write-up: docs/graph/upstream-graphify-cost-json-bug.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions