Skip to content

v1.27.0 ·

The bill was never the thinking

The problem

Measured on this repo's 53 transcripts before writing anything:

usage-bearing lines (what AIDLC counts):  17,292
unique message.id values:                  9,357
lines with no message.id:                      0
repeats whose usage object DIFFERS:            0
over-count factor:                         1.848
message-id groups that are non-contiguous:     0

Two facts from that run drive the design and are stated here so the design does not have to assume them:

  1. Repeats are pure duplication, not incremental updates. 7,935 repeat lines, zero with a differing usage object. So the correct operation is collapse, not sum.
  2. Every group is contiguous. 0 of 9,358 groups had another response's line interleaved. So a per-group cursor that advances to the group's last line stays monotone across the file.

Other providers were checked rather than assumed: codex.ts emits one segment per token_count event using last_token_usage, and kiro.ts one per usage_summary turn summary. Neither writes one line per content block, so neither carries this defect.

How it could be solved

Two roadmap items arrived on the same day out of one measurement pass over 20,920 ledger records and 54 transcripts, and the first question was whether to build them together or in sequence.

Sequence them: fix the meter, ship it, then cap the context. The clean answer, and the one the dependency graph asked for — the second item literally declared depends_on the first. Two small releases, each verifiable on its own.

Fold them into one instance. What actually shipped, and the reason is that the second item's success criteria are measurements. Every number that would demonstrate the context cap worked — average context per phase, cost per completed instance — was being read through a meter that over-reported by 1.85x. Landing the cap first would have shipped a saving nobody could verify; landing the meter fix alone would have corrected a gauge and saved nothing. They are two halves of one claim, not two features.

The third option, the one deliberately not taken: routing testing, deployment and maintenance to a cheaper model. On the same token volume that simulates at 39% against the context cap's 31%, and 57% combined — a bigger lever than the one that shipped. It needs per-phase model support that does not exist, so it is named in the item's own "out of scope" section specifically so the two would not be conflated when someone later asks why the cheaper option was skipped. It was not skipped; it was not available.

Within the meter fix, one narrower choice is worth recording because the measurement decided it rather than taste. Repeated usage records could be summed or collapsed, and the two differ by a factor of nearly two. Collapsing is only correct if the repeats are byte-identical — so that got measured before it got chosen: 7,935 repeat lines across 53 transcripts, zero with a differing usage object. Summing would have reproduced the exact defect being removed.

And on correcting history, the option rejected was the tempting one. 14,212 ledger entries have no transcript left to re-read, and the over-count factor for the period that can be measured is known. Multiplying the unreadable entries by that factor would have produced a tidier number and a much better-looking correction. It would also have made an estimate indistinguishable from a measurement, which is precisely the defect under repair. Those entries are left byte-identical and reported as unknown instead, which is why the correction lands at 1.362x rather than the 1.937x the analysis predicted.

How AIDLC solves it

Two things shipped, and only one of them is a feature.

The meter fix is the correction. The claude-code cost provider counted usage once per transcript line, and Claude Code writes one line per content block, repeating the response's usage object on every one. A reply that thought out loud and then called two tools was charged three times. Measured across this repository's 53 transcripts: 17,292 usage-bearing lines against 9,357 real API responses, an over-count of 1.848x.

The direction turned out to matter more than the size. Duplication scales with the number of content blocks, so it scales with parallel tool use — and calling two tools in one reply is genuinely cheaper than two sequential replies, because it avoids an entire re-read of the conversation prefix. The meter was reporting the single most effective optimization available as a cost increase. Usage is now grouped by response id and repeated records are collapsed rather than summed, which is only safe because the repeats are byte-identical, which was measured rather than assumed.

The reports changed with it. The token total had been summing fresh input and output only, ignoring cache traffic entirely — hiding 95 percent of the volume and 91 percent of the cost, which made any cost-per-million-tokens figure anyone computed wrong by two orders of magnitude. Cache tokens now count, so the reported total rises about 26-fold. And the cost report finally names the driver instead of only the total: what share of spend went on re-reading the prefix, the average context size per response, and the cost per response. A bare dollar figure gives a reader nothing to act on.

The feature is the context budget, and it exists because of what the corrected meter shows. Ninety-one percent of what this lifecycle costs is cache traffic — paying, turn after turn, to carry a conversation that only grows. Average context per unit of work runs from 80,000 tokens in ideation to 395,000 in deployment to 791,000 in maintenance. Deployment is the most expensive phase in the lifecycle, ahead of implementation, and not because it does more work: because it runs last and inherits everything before it. The one phase that reliably starts in its own session does comparable work at 76,000.

So a phase boundary is a free context reset, and nothing anywhere said to take it. Now the framework overview carries a single statement of that rule, each phase skill names exactly what to re-read when it starts fresh and restates none of the rule itself, and a new command reports what the current session is carrying against a budget defaulting to 150,000 tokens. It reads the transcript rather than the cost ledger, because the question gets asked at a phase boundary — precisely the moment the ledger has nothing recent to say.

It is a report and never a gate. That is a deliberate refusal rather than an omission. This project has shipped eleven features and seven bugfixes, and five of the six traceable bugfixes came from features built to watch the lifecycle, each of which added a gate every future piece of work then had to pass. A budget that blocks a transition would be the seventh. Its whole force is that somebody reads it out at the right moment.

Two smaller things came along. Historical ledgers can now be corrected — planned, printed, and deliberately not applied, because applying it moves every cost figure already published here, including the pair this project's own guidance is built on. And aidlc discover stopped destroying hand-written context documents, which is why this repository's architecture document had remained a directory-name scan describing a four-package workspace as "docs and scripts": improving it was pointless while nothing kept the improvement.

There is an honest loose end. The command was run against the very session that built it, and reported 198,000 tokens rising to 306,000 — over budget throughout, in the work that produced the budget. Either the threshold is too tight for a change of this size, or the rule needs the fresh session it recommends and this session never took one. The next three pieces of work decide that, and the failure condition was written down in advance: if starting fresh spends back more than a third of the saving on re-reading, the threshold moves rather than the claim being declared true.