← Back

telltale

A terminal instrument for five coding-agent CLIs. Every reading is measured, and a reading it cannot measure is drawn absent, not zero.

Case study summary

telltale is a Go terminal program. It reads what five coding-agent CLIs leave on disk and draws one row per seat: context, spend, quota, liveness, sandbox posture. The interesting part is not the gauge. It is the refusal. A gauge that fills a gap with a plausible number is worse than no gauge, because a plausible number gets trusted. Most of the engineering here is the code that declines to render.

Measured zero draws a full empty track. Absent draws nothing. An invented reading is the failure. 0% MEASURED vendor said zero ABSENT no track, no number 47% INVENTED plausible, unmeasured

A measured zero and an absence are different claims, and the render has to keep them different. The third cell is the one the whole program exists to prevent.

Two kinds of number appear below. A plain figure was recounted from the repository by a script at build time, at the commit printed under Stack. A figure with a source reference beside it was measured once and recorded in the project’s design document, and this page cites that record rather than re-measuring it. A check in this site’s own test suite fails the build if either kind drifts from the file it was pulled into.

What it is

One static Go binary, no runtime dependency. It has two faces. A heads-up display draws every live agent session as one row. A dispatch room seats five of those agents side by side, sends them one brief, and shows the five answers as five columns. The room is the product and the gauges are the infrastructure, and that ranking is a recorded ruling in the project’s design document rather than a preference of mine.

Underneath, there are 7 vendor adapters. That is a larger number than the five seats on purpose: two of the vendors are watched by the display but are deliberately not seated in the room, and the design document says which and why. A sixth kind of row comes from a drop-file relay — a documented format any tool can write, so a program telltale ships no adapter for can still put a row on screen. That row is marked self-reported, because telltale did not measure it.

An agent-facing mode serves the same document over stdio. It binds no port and it writes nothing. Install is a direct archive, a scoop manifest exercised once, or a source build.

 fleet usage  quota is a reading against a limit; spend is a count with none  =========================================

 claude  quota relayed by the statusline - 2h ago
        5h             ########------------    42%  ~ 2h13m
        7d             #-------------------     6%  ~ 5d00h

 codex  quota read from its own store, this scan
        models         gpt-5.1-codex
        7d             ###############-----    79%  ~ 22h48m

 gemini  no quota reaches disk anywhere telltale can read
        models         gemini-3-pro
This is what a refusal looks like when it is rendered rather than argued. Two vendors have a quota reading and print it against its window; the third has none reaching disk at all, so the row says that in words and draws no gauge — the header states the distinction the view is built on. Lines 3–14 of internal/hud/testdata/golden/usage-ascii.txt at 38f262a, copied byte for byte from the test suite’s own output. The fixture is synthesized; the repository holds no real session content. Scrolls sideways on a narrow screen.

What the release does and does not prove. Two of the four archives are built, not run: no recorded run exists for the macOS ARM build or the Linux build. All macOS measurement is one Intel machine. No binary is signed, so checksum verification against the release’s own checksum file is the whole verification the release offers. The Windows reputation prompt is unmeasured. One package-manager manifest set is a draft and was never submitted.

Zero and absent are different states

Presence lives in two places, on purpose. Every optional field on a session is a pointer, so a missing reading is a nil rather than a sentinel number, and a rendered 0 therefore always means the vendor said zero. Above that sits a capability declaration per adapter: a vendor that can never supply a field declares it unsupported, and the column is dropped entirely rather than filled with dashes. A column of dashes for a vendor that could never fill it is itself a small claim about what was measured.

The strongest detail in the repository is how one of those declarations is documented. It is not asserted. The package documentation names the fields the survey looked for in a live corpus and records that the search returned no matches. An absence documented with the search that found nothing is a different claim from an absence nobody looked for.

The same rule is why there is no context percentage for some vendors. A percentage needs a per-model window as its denominator, and where the vendor does not expose one, any percentage would be arithmetic performed on a number I made up.

3 golden files, in three different packages, fail the build if a measured zero and an absence ever render the same. The rule is enforced by a stored render rather than by intent, because intent does not fail a build.

The rule: a gauge may state a number, or it may state nothing. It may not state a number it did not measure. An absence documented with the search that found nothing is a different claim from an absence nobody looked for. That difference is the whole product.

The badges claimed more than I had measured

Reversed. A badge with no evidence class

The row read like enforcement, and one seat had a mechanism

Each seat in the room carries a badge describing its sandbox posture. The first version of that row read as enforcement across four seats when exactly one of them had a measured mechanism behind it. Nobody wrote a false sentence. The badge simply did not say what kind of thing it was.

The fix was not a better badge. Every badge now names its evidence class, and there are three: enforced, where a live run measured the restriction holding; refuted, where a live run measured it failing; and unverified, where it was looked for and no result was obtained. A fourth class was retired, because “claimed” read like “enforced” and was not. The original error stays in the design document as the reason the rule exists.

One seat has moved in both directions, which is the only way to show the classes are real. It carried a weaker badge because at one tool version a read-only flag failed every process spawn, and it earned the stronger badge back only on a later re-probe that measured a live write denied with no file left on disk. I do not name the seat, and I do not publish a per-vendor verdict table. Which settings do not contain writes is a bypass instruction, and a negative finding measured once by one operator is not a fact about somebody’s product.

The same vocabulary covers the seats that were considered and not taken, so that “we looked and said no” never reads like “nobody looked”. Non-seated candidates are recorded with their evidence class, and one is recorded as installed, waitlisted, and explicitly not a rejection.

The lesson: a badge that does not name its evidence class is a rumour with a border. A reader supplies the strongest reading available, so the claim has to carry its own evidence class or it lies by default.

Five seats, one brief, and no winner

One brief is raced across every seat at once, each attempt in its own git worktree, and the attempts are compared by diff instead of by prose. Two mechanics exist only to stop a lying diff. The diff anchors on a recorded base commit and never on HEAD, and untracked files are staged first — so an attempt whose entire answer is a new file cannot read as “no changes”.

Each finisher carries a rank, a phase word, its own clock, and a commit receipt. A seat cut by hand keeps its receipt too. In the first race that seated all five, the first finish came in at 50s, two more finished within about twenty seconds of it, and two seats were given up by hand after roughly 11 minutes — both keeping their commits exactly as the finish-line design promised. Those two figures are cited from the design document’s section on the race, not re-measured here.

I withhold the seat names, and the reason is the point. One race is not a benchmark. Publishing a ranking off a single brief on a single machine would be a claim about five products that the measurement cannot support, and the standings inside the program refuse the same thing for the same reason.

A check grades an attempt from the real exit code and nothing else. Not from output, not from the diff, not from duration, and not from a model’s opinion. A command that could not run reads “check unavailable”, which is not a FAIL. The standings say adopted, never won, because the git refs can record that a branch merged and cannot record a rank, a phase, or that a seat was cut. An undecided race is reported beside the rate and never inside it, and the rate never prints without its count. Hand-cut receipts are refused outright, which makes the figure an undercount — and an undercount is the honest direction to be wrong in.

  arena record  ===================================================================================  telltale  5 races  
  read from the arena/ and adopt/ branches this repository still holds, t2 through t9: 3 decided by you, 2 nobody was   
  adopted from. A race whose branches were dropped is no longer in the record.                                          
The record states its own reach before it states a single result: what it read, how many races that was, how many a human decided, and that a race whose branches were dropped is simply gone from the record rather than counted as a loss. Lines 8–10 of internal/council/testdata/golden/arena-record-ascii.txt at 38f262a, copied byte for byte. The per-seat rows below this header are deliberately not reproduced here. Scrolls sideways on a narrow screen.

What has no live half yet. No live race has run under a check, and no real hybrid adopt has been armed. Both are built and both are unexercised.

Twice the instrument was the bug

Four corrections, and two of them are the same shape: the thing that was wrong was my own measuring equipment, and it failed by reporting nothing found.

Reversed. The regex answered the question it was asked

A sweep reported one key, and the record carried eleven

A pattern sweep behind one vendor’s cost row concluded that the vendor exposed a cost total and nothing else. The pattern was anchored on the substring cost and it was lowercase, so a key spelled with a capital letter in the middle matched neither half. It was structurally incapable of the question a reader takes that row to answer.

A live re-measure read eleven keys off the same turn record, where the sweep could match one key and reported one key. A session captured weeks earlier carried the identical key set, which settles it: this was never vendor drift. The counts were on disk before the adapter was written. Both figures are cited from the design document’s own correction block.

The same class of mistake landed a second time, when a pattern that swept file contents could never have matched a directory name.

The rule this bought: before a vendor is built here, re-read its records, not its struct. A record struct is an allowlist, so what it omits is a decision and not an absence. Both instrument bugs failed in the same direction: they reported nothing found, which is the one failure mode this product is least able to see in itself.

A green test over the wrong prompt

A live test stayed green while one seat was dead for a day

One seat’s command-line flag had been separated from its value, and that vendor’s parser refuses a brief that opens with three dashes. Every briefed turn died with an empty column. The live test stayed green the whole time, because it probed with a prompt that began with a letter.

The lesson: probe a vendor with a prompt shaped like a brief, not like a greeting. Every later probe is brief-fenced for that reason.

A guard that read a live process as health

A finished racer read as streaming for twenty-one minutes

A stale-exit guard attributed a live process to the wrong seat, so a racer that had already exited left its column reading 21 minutes after the fact: no diff, no commit, no rank, no receipt. Two earlier drives had written it off as the vendor quitting. It was not the vendor. The fix was attribution, and it was verified the same day — the column retired in 18 seconds. Both durations are cited from the design document’s measurement block.

The lesson: a debt that will not pay may be a broken feature rather than an unfinished errand.

Reversed. Pictures a human maintained

The README’s frames drifted, and one of them showed a number the code refuses to compute

The frames in the README were hand-drawn. They had drifted several ways at once, and one of the drifts was a cost line showing a derived figure that the codebase deliberately does not compute. A picture of a program that the program did not draw is a claim with nothing checking it.

They are now emitted by the test suite from the real render, and a test fails the build when they stop matching.

Why it governs this page too: a picture a human maintains is a claim with no gate on it. Every count on this page was re-read from the repository at build time, and the commit it was read at is printed under Stack.

What it refuses to render

Each of these was considered, argued, and declined, and each refusal is a file in the repository with the argument still attached.

The review keys are the same rule in a smaller place. Pressing one lands a quoted hunk in the live composer draft, and nothing else happens. The surveyed alternatives route a comment straight back to the agent; this room cannot do that honestly, because a race attempt is one-shot and finished by the time you are reading it. A person pressing a key stays the only thing that spends a quota, and a test asserts it by counting processes spawned and turns started rather than by checking the wording.

The gate that measured the capacity

The same habit that gates a model choice on this site was pointed at the build capacity itself. On a fixed date I wrote down six evidence axes and a close date, froze every change until the close, and let the axes decide. The month returned a step down, and it also returned a process finding I did not want: nothing ever wrote to the axes. I tell that one on the program page, because it is a program artifact and not a product feature. The capacity gate →

What this does not establish

Stack

Go, one static binary, no runtime dependency. No network listener is bound by default; the agent-facing mode serves the same document over stdio and binds no port. No telemetry, no price table, and no model call anywhere in the gauge path. Public repository: github.com/sanlee-ys/telltale.

The honesty rules are named tests, so a skeptic can grep rather than trust:

I do not print the permission-bypass flag name, the per-vendor sandbox settings, or a containment table. Naming them publishes a bypass instruction.

How it was built: I set the direction, the contracts, and the bar. Claude does most of the typing. The proof is the suite and the goldens, and a test entry point that panics rather than let a test spend money.

Counts and frames on this page were re-read from sanlee-ys/telltale at 38f262a on 2026-08-30. The suite holds 132 golden text renders and 1780 test functions at that commit. Each figure names the command that produced it, and a check in this site’s test suite fails the build if a rendered figure drifts from that record.

What it demonstrates

The rest of this record is a system I built with agents. This is the instrument I built to watch them. The honesty rule is one sentence — a gauge may not render a number nobody measured — and it is enforced by golden files rather than by intent, because intent does not fail a build. A list of features was refused outright, each because it would have required an invented number, and every refusal is a file you can read with the argument still attached. When my own instrument was the thing that was wrong, the correction went into the record next to the claim it broke, and both times the wrong answer arrived as an absence rather than as an error, which is the failure mode this product is least able to see in itself. Every sentence above resolves to a file you can open.