Skip to content

0.4.0 — a number is worth what its counting method is worth

The last release said that a claim is worth what its enforcement is worth. This one is what happened when that sentence was turned on the document itself: five of its figures were wrong, all five in the same way, and the check that should have caught the last of them had been passing for weeks over data in which the defect could not appear.

construct cost summed the usage of every line in an agent's journal. The journal writes one line per content block of a response — thinking, text, tool call — and repeats that response's usage on each of them, so a run's recorded cost grew with how many blocks its answers happened to be split into. Everything this project measured, published and decided with was about 2.4 times its true size. Its test passed throughout, because its fixtures wrote journal lines with no request identifier, so the double counting had nothing to double.

What it fixes

construct cost deduplicates by request identifier: one response counted once however many lines carry it, two responses counted twice, and a line the runtime recorded without an identifier still counted, so the fallback is deliberate rather than accidental. If you have been reading its numbers, they were too large by roughly that factor and they are not any more.

Every figure the defect produced has been re-derived from the run it names and corrected where it was published — the 0.3.0 release note and the reasoning-budget guide both carry the correction with the counting method stated, rather than a silent swap of digits. The comparisons those documents make are unaffected. The same bias ran through every figure, so what the numbers were used to argue — that the entry into the repository dominates the price, that it grows with the repository rather than the task, that the reasoning class predicts the cost poorly — stands exactly as written. What was wrong was every absolute number.

Decision 0008, which set retryLimit to 0, is amended rather than reopened. Its conclusion survives; the ratio underneath it does not. Splitting five architect entries at their first structured-output call measures the exploration a new entry pays at 385k to 1.48M and one more attempt inside an entry already paid for at 57k to 100k — five to twenty to one, where the note had claimed a thousand to one from a subtraction of two different runs.

What it adds

A run whose design step ran out now names the way out of it. The result carries a recovery field and /implement relays it verbatim: re-run the task one class lower with the design written into the brief. That is not advice but the measured route — three of the three occasions it has been tried on this repository produced the design the architect had failed to return, at almost no cost, because the person already had the design in their head when they wrote the brief.

The message also says why the run does not simply try again, because a route offered without that reads as a missing feature: a second agent entry pays for the exploration all over again, against one more attempt inside an entry already bought. retryLimit stays 0, and now the reason travels with the failure instead of living only in a decision record.

Alongside it, decision 0014 names a class this project kept meeting: a check answers honestly about the set it was shown, and says nothing about what fell out of it. Two mechanisms hold two halves of it, and neither holds the whole. tests/every-source-has-a-reader.test.ts reconciles the source tree against both of its readers — no file may be ignored by git and by eslint at once — which closes the half where a file vanishes from a checker. It does nothing for the half where the file is visible, the test runs, it passes and it proves nothing; that half is closed by proving every new check by mutation before trusting it. What neither reaches stays at review, and the record says so.

That rule earned itself immediately. The first version of the reconciliation test was written against git ls-files and stayed green when the real defect was reintroduced, because an already-committed file reads as tracked whatever the ignore rules say. Without the mutation step this release would have shipped a second empty check as the cure for the first.

What it does not fix, and what is now known not to be the cause

The design step still fails, and why is still unknown. On this repository, four of nine architect entries returned nothing. That number is worse than it looks: two more returned decision: "test", constraints: ["a"], files: ["a"], which the schema accepted because it constrains shape and never content, so the run went on and handed the implementer Acceptance criteria: - a. Six of nine produced no usable design and only four of the six were visible as failures. That is not fixed in this release — the shipped schema still accepts a placeholder — and it is the first thing to look at next.

What a day of measurement did settle is a list of explanations that are no longer available:

  • Not the length of the answer. An 18,525-byte spec was accepted on the first attempt; the smallest payload the runtime is known to have refused was 3,436 bytes.
  • Not a fence or prose wrapped around the object. Every recorded payload begins at {.
  • Not a raw control character in the long prose field. decision is complete and correctly escaped in all seven refusals where it can be read.
  • Not the field the refusals appear to break in. They all break in the one after decision because the journal keeps 2,048 characters and decision is shorter than that — the boundary is the log's, not the model's.
  • Not running out of room. Every recorded completion stopped with tool_use, never max_tokens, across seventeen of them.
  • Not a property of the task. Both briefs that once produced nothing and a placeholder returned real designs when re-run.
  • Not permanent degradation under retry. The answer shrinks across refused attempts and then recovers; an empty tool call is a transient, not a floor.

What remains unread is the part that would name the cause: the bytes at which a payload became invalid, which the journal discards past 2,048 characters. Ten refused payloads are frozen in this repository with a note saying exactly which of their properties are evidence and which are artefacts of the logger, and a harness exists that would capture a whole one. It has not been run, and this note does not claim the next release will have the answer.

Names are a tribute to Cyberpunk 2077. Not affiliated with CD Projekt Red.