Run a fleet of coding agents and every fact you hold about the work arrives the same way: an agent wrote it down. The claim that the tests pass, the tick in the done column, the status page you skim over coffee — all of it authored by the same processes that did the work. Our own tracking tree currently carries 38 streams and 1,162 units of work, 366 of them closed. No human has read most of that, and no human is going to. The two classical answers are trust — take the reports at face value — or supervision — read everything, which caps the fleet at the speed of one reader. Both make the same mistake: they treat the report as the thing to evaluate.

Assay is the third answer, and it rests on one sentence: you don't need to trust the agents; you need their work to be checkable — and that's a property you can install. The whole operating model fits in three words: derived, linted, re-verified. Status is never collected from what agents say about their work. It is compiled from artifacts they are required to write in a checkable form, linted for internal consistency, and spot-re-verified by an identity that did not do the work. Everything below is those three words unpacked — four load-bearing parts, the loop that runs them, and the part most introductions skip: what the mechanism does not claim.

a brief is a contract, not a report

The unit of work is a brief: one markdown file, one scope, one definition of done, executable by one agent without reading the rest of the plan. Its frontmatter records four risk answers, and the review gate is derived from them rather than chosen:

gate: model
          risk: {regulatory: no, customer: no, irreversible: no, sensitive-data: no}

Any yes forces gate: human — closing that brief later requires a sign-off naming a person; a model's approval does not count. The gate is a conclusion, not an opinion: a reviewer audits the four answers, not the verdict.

The part that makes a brief checkable is its Verify table: literal commands with expected output, written for a stranger. One row from a real brief in our tree — the one that moved the board generator itself onto a pinned, hash-verified release binary:

# Command Expect
3 grep -rn "go run ./tools/statusgen" .github/workflows/ | wc -l 0

Anyone can run that. Nobody needs to have done the work, remember the context, or believe the author. The template's own rule is blunt about why: a row with no literal command and no expected exit or output "is a hope, not a check." That brief is the worked example for the rest of this article.

an implementer never grades its own exam

A brief moves through five states:

todo → in-progress → implemented → verified → done

The load-bearing rule is where the implementer stops: at implemented, having run the Verify table and logged its own results. In the lifecycle doc's words, an implementer verifying their own work "is the narrator grading their own exam." verified requires a non-implementer to re-run the table on merged main and log a dated result under their own identity. And merging does not verify: a merged brief sits in a visible awaiting queue until someone independent runs the checks.

The log those runs land in is append-only. Each run writes one witness row per Verify row: the command as authored, the exit code, a hash of the output, the date, and the runner's identity pinned to the tree SHA it ran against — with a +dirty suffix when the working tree was modified. Runs append and never overwrite: a green re-run must never erase a red one — that would edit the recorded basis of a past sign-off.

Our worked example carries two such runs: a verifier with no part in the implementation ran all five rows on 2026-07-23 and passed them. On 2026-08-13 a different verifier identity re-ran the table against current main — the pinned release had moved from v0.1.0 to v0.8.1 — re-hashed the served binary against the committed pin, and recorded a second pass, marking two rows it could not execute in isolation as corroborated rather than passed. Both runs sit on the log, dated and attributed. That is what checkable buys: not a promise the work is good, but a record a third party can re-derive.

the registers remember what the sessions forget

Agent sessions end. The fleet's memory is a pair of append-only registers, one file per entry, because a silent edit erases the record of why a decision was made. INTAKE is the front door for raw ideas; FINDINGS holds knowledge that invalidates existing work. When a finding lands, every brief it names is flagged stale and pulled from the schedule until it resolves. Retraction flips the entry's disposition and explains — a tombstone, never a deletion.

One design detail carries the system's whole posture. Filing a finding is unverified input — anyone, human or agent, can write a paragraph — so an unacknowledged finding can flag work but cannot force an in-flight brief backwards. Only a coordinator's on-record acknowledgment arms that. The documented reason: without the gate, filing a paragraph could knock a rival brief out of the queue. The registers assume their own writers may be wrong or adversarial, and meter them accordingly.

the board is compiled, not collected

statusgen is the derivation engine. The board — STATUS.md at the repo root — is generated from the stream tables, the registers, and the evidence logs, and it has exactly one writer: main's CI, which regenerates it on every push. Branches never commit it; pull-request CI runs the same generator in lint mode and blocks any diff that touches the board. Status is a build artifact: reproducible from its sources, and pointless to hand-edit — the next push rebuilds it.

The same pass computes the work queue. From the board as of this writing:

Next-up: 20 of 671 eligible — 651 held back (span-of-control cap 20). Overflow is itself an alarm: clear WIP before pulling more.

and the after-merge queue:

Awaiting verification / review (25 desk-actionable of 39 total — 38 at implemented, 1 verified awaiting review)

Eligibility is not a guess. A brief with an unresolved finding is excluded; a brief with an open branch on the remote is excluded as already claimed. When the claim check cannot reach the remote, the board does not pretend: it stamps a DEGRADED banner naming the cause and labels the queue an unfiltered superset. Every instrument in the tree answers in three states — checked-clean, checked-failed, could-not-check — and could-not-check never renders as a pass. An instrument that could not look does not get to answer.

four desks and a merge button

The loop that runs all this is a pipeline of four standing roles, each in its own session: an intake desk converts everything inbound — issues, ideas, raw requests — into tracked exits; a worker desk keeps a pool of implementers full, each in its own worktree behind a draft pull request; a review desk drives each PR through review and flips it ready; a verify desk drains the awaiting queue by re-running Verify tables on merged main. A coordinator desk arbitrates across streams and keeps the registers honest, and one act belongs to none of them: the human merges. Always.

The separation is the same one the lifecycle encodes: the dispatcher does not review, the implementer does not verify, and nothing merges itself. Each desk's output is another desk's input, in a form the next desk can check.

bring your own agents

Today's agentic-coding tools cluster on the two poles from the opening. Autonomous coding agents lean trust: the agent's own report is the record. Assistant-and-review-bot loops lean supervision — and where the checker is the same model that wrote the code, it inherits the same blind spots. Assay is neither a coding agent nor a smarter reviewer. It is the legibility-and-gating layer underneath whichever agents you run — status derived rather than reported, re-verified by a different identity, separated across accountable roles, appended rather than overwritten — and nothing in it cares which model wrote the code.

It wraps what you already run rather than replacing it. Bring your own agents, on any model or harness; keep your CI, your forge, and your review bots. The briefs, registers, lifecycle, and board sit on stock tooling around them and make their output checkable. And it composes with both poles: to a trust-leaning autonomous agent it adds the independent check the agent lacks; to a supervision-leaning loop it is what lets one reviewer cover a fleet instead of one pull request at a time.

what the gate does not give you

Here is the claim at its honest strength, from the methodology's own documentation: the board is "derived from agent-authored artifacts with consistency linting," not measured from ground truth. The generator parses markdown written by the same agents whose work it reports. It checks the internal consistency of those documents — missing evidence, malformed gates, cells that claim more than their witness supports — and it is backstopped by adversarial spot-verification. It does not independently observe that the code does what a brief says. The strong form of the claim — status is measured, never self-reported — is false, and the docs say so: the sensors are agent-writable.

The evidence log states its own limit: a witness is evidence, not an attestation — whoever controls the process controls the environment it reads. Its value is where it lands — in a pull request diff, next to the tree SHA it names, where a second identity can re-run the command and compare.

So what you actually get is attribution, not enforcement. Drift, missing evidence, and records that contradict each other become machine-visible, dated, and attributable to an identity. A single identity that authors both the work and its record can still lie; separated desk identities, independent re-verification, and append-only logs narrow that gap without closing it. The house rule is to claim the weaker, true thing, and this article is bound by it too.

checkable is a property you can install

None of this requires our tooling. The property comes from four decisions, all available on a stock forge and a scripting language:

  1. Make each unit of work a file carrying an executable verification contract — literal commands, expected output, runnable by a stranger.
  2. Derive your status surface from those files with a consistency linter. Give it one writer, and lint every branch.
  3. Split implementer from verifier across identities, and make evidence an append-only log of dated, attributed runs.
  4. Record risk answers in the work item, derive the gate from them, and route any yes to a human.

Our generator and desks are the worked example of those decisions, not a prerequisite. Install the property and the learning follows: you don't need to trust the agents — you need their work to be checkable. Derived, linted, re-verified.

What happens when the checking instruments themselves drift — a leak-sweep canary registered but never planted — is its own story, told in "Who assays the assayer."

Explainer video

No video for this article yet. An explainer script ships in the bundle (SCRIPT.md); a video link can be back-filled into the metadata later.