<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roy Tong</title>
    <description>The latest articles on DEV Community by Roy Tong (@roytong).</description>
    <link>https://dev.to/roytong</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4118697%2F14d08eb4-2784-4071-beaf-5f510e5e6d2e.png</url>
      <title>DEV Community: Roy Tong</title>
      <link>https://dev.to/roytong</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/roytong"/>
    <language>en</language>
    <item>
      <title>We audited 110 AI usage tools for metering bugs — 45+ reproduced, every finding linkable</title>
      <dc:creator>Roy Tong</dc:creator>
      <pubDate>Wed, 14 Oct 2026 03:43:29 +0000</pubDate>
      <link>https://dev.to/roytong/we-audited-110-aiai-usage-tools-for-metering-bugs-45-reproduced-every-finding-linkable-4bo1</link>
      <guid>https://dev.to/roytong/we-audited-110-aiai-usage-tools-for-metering-bugs-45-reproduced-every-finding-linkable-4bo1</guid>
      <description>&lt;p&gt;Outcome-based pricing won the pricing page. Per-resolution AI support, usage-billed agents, API metering by the call — the industry has decided that software is billed by what it does. One question got a lot quieter than it deserves: &lt;strong&gt;who verifies the billed number?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We kept running into the same class of silent accounting errors while metering AI agent usage — retries billed as new operations, duplicate records after crashes, cache hits priced as fresh tokens. So we did the boring thing: we audited. 110 AI usage tools so far, each with the tool's own parser on synthetic fixtures, every bug reproduced against a pinned commit, every fix re-verified after it landed upstream (25 merged so far). The full index is public — every entry has exactly one status, one date, one link:&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://roy-tong.github.io/AgentMeasure/claims.html" rel="noopener noreferrer"&gt;https://roy-tong.github.io/AgentMeasure/claims.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The five shapes that keep showing up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Retries billed as new operations.&lt;/strong&gt; A runtime retry chain — 429, timeout, then success — is one logical operation with three executions. If the meter counts executions, the customer pays 3×. We reproduced this shape across runtimes; it is the single most common finding, and dashboards stay green the whole time because every individual record is "correct."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Duplicate records after a crash or resume.&lt;/strong&gt; Re-emitted lines after a crash look like new usage. Byte-identical duplicates inside session files showed up in more tools than we expected. The fix is boring — dedupe on record id before counting anything — which is exactly why it doesn't get done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Cache hits priced as fresh tokens.&lt;/strong&gt; Where a tool reports cache accounting, cached-read tokens sometimes ride the same field as fresh tokens, priced identically. At cache-hit rates typical for agent workloads, that's not a rounding error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Attempt grain reported as operation grain.&lt;/strong&gt; "Median steps per operation: 2.5" computed over successful attempts reads very different from 4.0 computed over total consumption including retries. Both numbers are defensible; only one matches what the bill should say. The metric's grain is the claim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Absent zero.&lt;/strong&gt; A boolean "consumed" field reused for "not set" turns 9,107 referenced observations into a confident zero. Missing evidence formatted as data is the nastiest one, because it looks like a result.&lt;/p&gt;

&lt;h2&gt;
  
  
  UNPROVABLE is a result, not an error
&lt;/h2&gt;

&lt;p&gt;The audit's vocabulary has five states and two of them are "we can't say": &lt;strong&gt;Verified Mismatch / Fixed · Re-verified / Conformance Pass / UNPROVABLE / Not-a-bug&lt;/strong&gt;. If the export lacks the field that decides a metric, the finding is UNPROVABLE — stated out loud, not filled with a zero. Most metering disputes we've seen are not dishonesty; they're someone's UNPROVABLE rendered as a confident number.&lt;/p&gt;

&lt;p&gt;That discipline is also why the audit is reproducible: every claim binds to a fixture you can run. &lt;code&gt;pip install agentmeasure&lt;/code&gt; gives you the checker (&lt;code&gt;agentmeasure check&lt;/code&gt;) which scans your own Codex / Claude Code session logs locally — duplicate records, retry chains, token anomalies, thirty seconds, nothing uploaded, no account. New in v0.7.0 (2026-10-14): Windows CI coverage and machine-checkable sanitized summaries (&lt;code&gt;agentmeasure share&lt;/code&gt; exports aggregate counts only — previews first, exports after you look).&lt;/p&gt;

&lt;h2&gt;
  
  
  What we do when a finding needs a human
&lt;/h2&gt;

&lt;p&gt;The tools are and stay free. When your own check flags something and you want to know what it means in your setup — bug or intended semantics, why, what to do next — that's a human diagnosis, and that's the paid part: a $10 anomaly diagnosis and a $20 metering QA check, email application, fixed scope, refund terms on the page (&lt;a href="https://roy-tong.github.io/AgentMeasure/services.html" rel="noopener noreferrer"&gt;https://roy-tong.github.io/AgentMeasure/services.html&lt;/a&gt;). "No finding" is a valid deliverable and is priced in.&lt;/p&gt;

&lt;h2&gt;
  
  
  The community part matters more than the bugs
&lt;/h2&gt;

&lt;p&gt;This cycle merged three external PRs — an SSE conformance vector, a Freshdesk field mapping, an Intercom walkthrough — plus the first availability-certification vector contributed via PR. &lt;code&gt;agentmeasure conformance --new-vector &amp;lt;name&amp;gt;&lt;/code&gt; scaffolds a CI-valid external vector in one command: if you meter an MCP server or an agent API, you can pin your own semantics and let CI catch regressions when you change retry logic or pricing.&lt;/p&gt;

&lt;p&gt;Numbers as of 2026-10-14: 110 tools audited · 45+ reproduced metering bugs · 25 upstream fixes merged · 477 tests green. Every one of those claims links from the index above — that's the whole point.&lt;/p&gt;

&lt;p&gt;If you run usage-billed agents, run the check before your next invoice. If you build the tools, file a vector. If you find a bug, the index has room.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>opensource</category>
      <category>testing</category>
    </item>
    <item>
      <title>We audited 110 AI usage tools. Here is where the numbers go wrong.</title>
      <dc:creator>Roy Tong</dc:creator>
      <pubDate>Tue, 22 Sep 2026 23:12:53 +0000</pubDate>
      <link>https://dev.to/roytong/we-audited-110-ai-usage-tools-here-is-where-the-numbers-go-wrong-5d8h</link>
      <guid>https://dev.to/roytong/we-audited-110-ai-usage-tools-here-is-where-the-numbers-go-wrong-5d8h</guid>
      <description>&lt;p&gt;AI products are moving from flat subscriptions to usage-based and outcome-based billing: per-resolution support agents, premium request quotas, per-token gateway billing. Every one of those numbers is produced by a meter, and the meter is usually the vendor's own. We spent the last month auditing the open-source side of that world — 110 tools that count tokens, track costs, or enforce budgets — and this post is the field report.&lt;/p&gt;

&lt;p&gt;The short version: &lt;strong&gt;45+ verified bugs, five recurring families, 23 fixes already merged upstream&lt;/strong&gt; (including langfuse at 34k stars and codeburn at 11k). An independent auditor reproduced our entire conformance suite and confirmed one cache-accounting path that under-reports usage by roughly 99%. Every claim below links to a reproducible check.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five bug families
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Stale pricing tables.&lt;/strong&gt; The most common real bug, and the most boring: pricing tables that lack the current generation of models. In one batch of seven tools, five shipped outdated or missing rate rows. The tool computes confidently from numbers that stopped being true months ago — and every downstream total inherits the error.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Provider-wrong cache multipliers.&lt;/strong&gt; Cache reads and writes are billed at different multipliers per provider. A common shortcut hardcodes one provider's ratios and applies them to everyone. We found a tool applying Anthropic's cache-read discount to OpenAI models, underestimating cache reads by 5x. The billing math is wrong in a way that looks plausible on every individual line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Retry double-counting in stream aggregation.&lt;/strong&gt; When a streaming request is retried byte-identical, some aggregators count both attempts. In one public corpus of 604 re-emitted events — 46% of the corpus — the bytes were identical, and naive aggregation doubled them. Conversely, tools that deduplicate too aggressively miss genuine retried work. Both directions lose money for someone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Absent treated as zero.&lt;/strong&gt; When a usage field is missing, &lt;code&gt;or 0&lt;/code&gt; turns "unknown" into "free". It reads like defensive coding and behaves like a discount nobody authorized. The fix is semantic, not syntactic: absent must stay absent, and rollups must be allowed to say UNPROVABLE instead of zero.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Window boundary errors.&lt;/strong&gt; Quota windows anchored to wall-clock time with fixtures pinned to absolute dates — the tool passes tests for 30 days and then fails everywhere at once. We know this one intimately because our own CI did it to us.&lt;/p&gt;

&lt;h2&gt;
  
  
  An independent reproduction
&lt;/h2&gt;

&lt;p&gt;The part we are proudest of is not our numbers — it is that an external auditor, working separately, reproduced our full conformance suite (236 checks) and then contributed his own quantified audit of a commercial provider's cache accounting: four code paths failing, usage under-reported by 98.9% and 95.1% on the affected paths, pinned to an exact commit. That report is now in our evidence tree with named credit. A third party spending real effort to check your work is worth more than any testimonial.&lt;/p&gt;

&lt;h2&gt;
  
  
  What merged upstream
&lt;/h2&gt;

&lt;p&gt;23 fixes across the ecosystem carry the audit's fingerprints — pricing table updates, cache multipliers corrected per provider, retry-collapse guards with regression fixtures, absent-vs-zero semantics made explicit. None of these were adversarial finds. Every one started as a thread where the maintainer was already discussing the problem, which is the only place we work.&lt;/p&gt;

&lt;h2&gt;
  
  
  What vendors should publish
&lt;/h2&gt;

&lt;p&gt;We checked 20 commercial vendors for one thing: a published process for what happens when the meter is wrong — a dispute path, a correction policy, anything. None had one. When the vendor runs the meter, grades its own homework, and publishes no correction process, "trust us" is the whole control framework. Two minimum standards would change that: a named dispute path, and machine-checkable billing disclosures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify your own bill in ten minutes
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/roy-tong/AgentMeasure" rel="noopener noreferrer"&gt;conformance pack&lt;/a&gt; is open source (MIT). Export your usage data, run the checker locally — nothing leaves your machine — and it separates logical operations from physical attempts, cache reads from cache writes, and absent from zero, with every verdict traceable to a named rule. If a number on your invoice survives an independent recount, you can defend it. If it doesn't, now you have the receipt.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;The full audit report with per-tool findings: &lt;a href="https://github.com/roy-tong/AgentMeasure/blob/main/campaigns/audit-report-2026-09.md" rel="noopener noreferrer"&gt;campaigns/audit-report-2026-09.md&lt;/a&gt;. The settlement spec behind the checker: &lt;a href="https://github.com/roy-tong/AgentMeasure/blob/main/standard/SETTLEMENT.md" rel="noopener noreferrer"&gt;AMS-1&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>observability</category>
    </item>
    <item>
      <title>I audited 110 AI usage/cost tools and filed 45+ verified billing bugs. Here's what they get wrong.</title>
      <dc:creator>Roy Tong</dc:creator>
      <pubDate>Thu, 10 Sep 2026 06:47:09 +0000</pubDate>
      <link>https://dev.to/roytong/i-audited-110-ai-usagecost-tools-and-filed-45-verified-billing-bugs-heres-what-they-get-wrong-38m3</link>
      <guid>https://dev.to/roytong/i-audited-110-ai-usagecost-tools-and-filed-45-verified-billing-bugs-heres-what-they-get-wrong-38m3</guid>
      <description>&lt;h1&gt;
  
  
  I audited 110 AI usage/cost tools and filed 45+ verified billing bugs
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; If a tool tells you what your AI coding agents cost, there is a real chance it is wrong in a systematic direction. I audited ~110 repositories across the Claude Code / Codex / gateway / eval / observability ecosystems and filed 65+ evidence-backed findings; &lt;strong&gt;10 have already been merged or accepted by maintainers&lt;/strong&gt;, several with public credit. The majority of audited tools passed clean — including some of the largest (promptfoo, Portkey's model data, TokenTracker) — so this is not "everything is broken"; it is five specific, findable bug classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/roy-tong/AgentMeasure/blob/main/campaigns/audit-report-2026-09.md" rel="noopener noreferrer"&gt;Full report with every finding linked&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The five classes that keep appearing
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. One assistant message ≠ one line (10 confirmed tools)
&lt;/h3&gt;

&lt;p&gt;Claude Code writes &lt;strong&gt;one JSONL line per content block&lt;/strong&gt; of an assistant message, and every line carries the same &lt;code&gt;message.id&lt;/code&gt; and the same &lt;code&gt;message.usage&lt;/code&gt;. Sum per line and a message with text + two tool calls is billed 3×. Real overcounts we measured: 2×–5×.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/zhangferry/tokendash/pull/37" rel="noopener noreferrer"&gt;tokendash #37&lt;/a&gt; (49★, merged): 3-block message → 3× tokens and cost&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Genuifx/ccem/issues/12" rel="noopener noreferrer"&gt;ccem #12&lt;/a&gt;: same shape, first-wins variant undercounts instead&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ipeterpetrus/samewrite/issues/1" rel="noopener noreferrer"&gt;samewrite #1&lt;/a&gt;: a &lt;em&gt;research project's&lt;/em&gt; headline numbers rested on it&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Re-emitted events (5 tools)
&lt;/h3&gt;

&lt;p&gt;Codex re-emits &lt;code&gt;token_count&lt;/code&gt; events with identical totals after compaction, settings changes, and rate-limit refreshes. Naive per-event accumulation double-counts. Measured on real corpora: +0.5% to +15% per session file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/extrei/token-vision/issues/1" rel="noopener noreferrer"&gt;token-vision #1&lt;/a&gt;: one real rollout, +14.97%&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/stealthsrc/tokenscope/pull/6" rel="noopener noreferrer"&gt;tokenscope #6&lt;/a&gt; (merged), &lt;a href="https://github.com/avihut/coding-agent-usage-tracker/pull/1" rel="noopener noreferrer"&gt;coding-agent-usage-tracker #1&lt;/a&gt; (merged)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Cache-pricing semantics (9 tools)
&lt;/h3&gt;

&lt;p&gt;Anthropic's &lt;code&gt;input_tokens&lt;/code&gt; &lt;strong&gt;excludes&lt;/strong&gt; cache tokens; OpenAI's includes them. 5-minute cache writes cost 1.25× input, 1-hour writes 2×, reads 0.1×. Tools that apply one convention to both providers clamp input to $0, double-charge cache, or price 1h writes as 1.25×.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/jarrodwatts/claude-hud/pull/758" rel="noopener noreferrer"&gt;claude-hud #758&lt;/a&gt; (27.9k★): 1h writes at 1.25× — 37.5% understated on that component&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/modelbus/one-api-pro/issues/13" rel="noopener noreferrer"&gt;one-api-pro #13&lt;/a&gt;: streaming &lt;code&gt;+=&lt;/code&gt; double-counts input (+50.7% with no cache) &lt;strong&gt;and&lt;/strong&gt; the billing formula re-subtracts cache&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Price-table drift (7 tools, including the source)
&lt;/h3&gt;

&lt;p&gt;Embedded price snapshots diverge from published rates by 1.2×–5× — including in vendored copies of &lt;strong&gt;LiteLLM's price file&lt;/strong&gt;, the industry's source of record (&lt;a href="https://github.com/BerriAI/litellm/issues/40360" rel="noopener noreferrer"&gt;litellm #40360&lt;/a&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Resume/fork history loss (4 tools)
&lt;/h3&gt;

&lt;p&gt;Codex resume writes a new rollout file whose &lt;code&gt;session_meta.id&lt;/code&gt; is the &lt;em&gt;original&lt;/em&gt; session id. Stores that replace-per-session wipe everything before the resume; fork re-plays the parent prefix and double-counts it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/Kud0o/ai-usage-inspector/issues/1" rel="noopener noreferrer"&gt;ai-usage-inspector #1&lt;/a&gt;: 86% of a session's tokens vanish (real pair measured)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/ra3orblade/swarm/issues/145" rel="noopener noreferrer"&gt;swarm #145&lt;/a&gt; → &lt;a href="https://github.com/ra3orblade/swarm/pull/146" rel="noopener noreferrer"&gt;fixed in #146&lt;/a&gt; with maintainer credit: &lt;em&gt;"reported and diagnosed by @roy-tong, who also supplied the patch this follows"&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why you should care even if you don't use these tools
&lt;/h2&gt;

&lt;p&gt;Your billing dashboards, your FinOps exports, and every "how much did this agent cost" number downstream inherit these errors. The bugs are findable with &lt;strong&gt;synthetic fixtures in minutes&lt;/strong&gt; — most tools' own tests never model these shapes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit your own tool in 10 minutes
&lt;/h2&gt;

&lt;p&gt;The fixture corpus is open data — plain JSONL + expected totals, no runtime:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone &lt;span class="nt"&gt;--depth&lt;/span&gt; 1 https://github.com/roy-tong/AgentMeasure
python3 conformance/pack/agentmeasure selftest   &lt;span class="c"&gt;# see the expected-totals style&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full method and per-class pointers: &lt;a href="https://github.com/roy-tong/AgentMeasure/blob/main/campaigns/tool-authors.md" rel="noopener noreferrer"&gt;tool-authors.md&lt;/a&gt;.&lt;br&gt;
Full case list: &lt;a href="https://github.com/roy-tong/AgentMeasure/blob/main/campaigns/measurement-casebook.md" rel="noopener noreferrer"&gt;measurement-casebook.md&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honesty notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Counts are of &lt;em&gt;filings with pinned evidence&lt;/em&gt;, as of 2026-09-10; merges happen as maintainers get to them (10 accepted so far).&lt;/li&gt;
&lt;li&gt;Most audited repos passed. We name the clean ones because that matters.&lt;/li&gt;
&lt;li&gt;All reproductions are synthetic; no private logs anywhere.&lt;/li&gt;
&lt;li&gt;This audit was performed with the methods and fixtures of &lt;a href="https://github.com/roy-tong/AgentMeasure" rel="noopener noreferrer"&gt;AgentMeasure&lt;/a&gt; — that is the demo. No audited project endorses it.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>codex</category>
    </item>
  </channel>
</rss>
