<?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: Agateon</title>
    <description>The latest articles on DEV Community by Agateon (@agateon).</description>
    <link>https://dev.to/agateon</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%2F4095078%2F63077ada-959a-49bc-a5d1-d4779c979759.jpg</url>
      <title>DEV Community: Agateon</title>
      <link>https://dev.to/agateon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/agateon"/>
    <language>en</language>
    <item>
      <title>A new session isn't a new perspective</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Fri, 11 Sep 2026 09:14:40 +0000</pubDate>
      <link>https://dev.to/agateon/a-new-session-isnt-a-new-perspective-3p5n</link>
      <guid>https://dev.to/agateon/a-new-session-isnt-a-new-perspective-3p5n</guid>
      <description>&lt;h1&gt;
  
  
  A new session isn't a new perspective
&lt;/h1&gt;

&lt;p&gt;The fix from the last post: put the review in a fresh session, with none of the author's context. So you did — the reviewer has never seen the conversation, the reasoning, or the sunk cost. It still runs on the same model as the author, and a model family's blind spots survive any number of fresh sessions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5gp2us6xqhom03tdowd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5gp2us6xqhom03tdowd.png" alt="Cover: an author node passes an artifact across a dashed context wall; behind the wall wait two judges — one a ghosted duplicate of the author in the same purple, one a solid teal judge holding a checkmark and an exit-code tag. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Role separation buys context independence: the reviewer can't inherit the author's misreadings, reasoning, or sunk cost. What it can still inherit is the model. Two sessions of the same model read with the same trained reflexes, so the failures a whole model family tends to miss are missed by both the producer and the reviewer. Our own &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/LIMITATIONS.md" rel="noopener noreferrer"&gt;limitation file&lt;/a&gt; carried this as a known, unfixable gap ("cognitive isolation, not true independence") until this week: v0.71.0 ships a dispatch router that can send any (phase, role) to a different model, or a different CLI entirely. Two invariants keep it honest: candidates fall back only on infrastructure failures, never on a gate FAIL — no shopping for an approving judge — and gates judge the artifact plus exit code, never the producer. The honest costs: a same-vendor model swap is weak mitigation, a cross-CLI subprocess is strong; unconfigured means byte-identical to before; and it's mitigation, not a cure. Below: why the blind spot survives the new session, how the routing works, and a three-question audit for your own pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  The blind spot follows the model, not the session
&lt;/h2&gt;

&lt;p&gt;Why doesn't a fresh session fix this? Because the session was never where the blind spot lived. A model's reflexes — what looks obviously correct, which edge classes read as out-of-scope, what kind of confident prose papers over a missing case — come from training. Two sessions of the same model bring the same reflexes to the same spec. Role separation removes the shared misreading of &lt;em&gt;this&lt;/em&gt; task — the reviewer no longer inherits the author's context. What it leaves untouched is the model's shared sense of what probably doesn't matter.&lt;/p&gt;

&lt;p&gt;This is in our &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/LIMITATIONS.md" rel="noopener noreferrer"&gt;LIMITATIONS.md&lt;/a&gt; as limitation 2, and the wording is careful: role isolation can block "obvious laziness," it cannot block "systematic blind spots" — the boundary cases this model family is bad at are missed by both roles. We shipped role separation knowing that, labeled it partial, and logged the gap as ADR-006: same-origin model isolation is cognitive-level, not true independence. For a while we had no mechanism for it at all. What we had was a name for the residue — and the observation that the residue is exactly the part prompting can't fix — the gap is invisible from inside both sessions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiab9bugyiqckc209cf0a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiab9bugyiqckc209cf0a.png" alt="Illustration: where the blind spot lives — on the left, author and reviewer are two sessions of the same model, and a dotted ellipse spans both, the same blind spot missed twice; on the right, the reviewer is a different model behind the context wall, so the blind spot stays local to the author while the judge returns a verdict and an exit code" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The model axis
&lt;/h2&gt;

&lt;p&gt;v0.71.0 adds the missing dimension. The command is &lt;code&gt;agate dispatch route &amp;lt;phase&amp;gt; &amp;lt;role&amp;gt;&lt;/code&gt;, and the flow (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/dispatch-protocol.md" rel="noopener noreferrer"&gt;protocol §0&lt;/a&gt;) is deliberately boring: look up &lt;code&gt;(phase, role)&lt;/code&gt; in the routing config; resolve it to either a tier or an explicit candidate chain of &lt;code&gt;{cli, model, effort?}&lt;/code&gt; (&lt;code&gt;effort&lt;/code&gt; being the CLI's reasoning-effort level); dispatch to the first candidate; fall through to the next only on infrastructure signals; if the chain runs out, dispatch like the feature never existed.&lt;/p&gt;

&lt;p&gt;The vocabulary has three tiers — &lt;code&gt;bulk&lt;/code&gt; (high volume, low cost), &lt;code&gt;deep&lt;/code&gt; (hard judgment: architect, judge, consistency review), and &lt;code&gt;standard&lt;/code&gt;. &lt;code&gt;standard&lt;/code&gt; has a special job: it means "inherit the main agent's current model and dispatch natively," and it is the factory default for every phase and role. That makes the strongest guarantee in the whole feature the one you test first: &lt;strong&gt;unconfigured means byte-identical&lt;/strong&gt;. There's a dedicated zero-change test asserting it — with no routing config, every dispatch resolves through the identical code path as before, and zero &lt;code&gt;dispatch_route&lt;/code&gt; events appear in the ledger.&lt;/p&gt;

&lt;p&gt;The mitigation strength depends on what you route to, and the protocol says so plainly. &lt;code&gt;cli: native&lt;/code&gt; — same platform, different model — is &lt;em&gt;weak&lt;/em&gt; mitigation: same training lineage, so the blind spots mostly overlap; what you buy is cost matching and some failure-mode diversity. A cross-CLI subprocess — say, sending the judge to a different vendor's CLI — is &lt;em&gt;strong&lt;/em&gt; mitigation: a genuinely different training lineage, which is what "independent perspective" was supposed to mean all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two invariants that keep it honest
&lt;/h2&gt;

&lt;p&gt;A feature like this has one failure mode that would quietly eat everything: using the fallback chain to escape bad verdicts. Two mechanical rules close that hole.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fallback is for broken plumbing, not rejected work.&lt;/strong&gt; The candidate chain falls through on exactly three signals — &lt;code&gt;launch_fail&lt;/code&gt;, &lt;code&gt;infra_error&lt;/code&gt;, &lt;code&gt;no_parseable_output&lt;/code&gt;. Once a candidate has produced anything a gate can evaluate, the routing is done and successful, whatever the gate then says. A gate FAIL is a normal phase retry &lt;em&gt;on the same candidate&lt;/em&gt;; the router does not get another turn. The reason-code enum has no &lt;code&gt;gate_fail&lt;/code&gt; value, and &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-events.py" rel="noopener noreferrer"&gt;our audit script&lt;/a&gt; mechanically rejects any event that tries to smuggle one in. Without this, every rejection would tempt a fallback to a more agreeable model and quietly become permission to try a different judge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Producer-agnostic gates.&lt;/strong&gt; The protocol states the second premise directly: gates read the output files and the exit code, and they must never learn who produced them — no special-casing for cross-CLI output, now or later. If a gate ever needs to know the producer, routing decisions leak into judgment.&lt;/p&gt;

&lt;p&gt;And every fallback leaves a mark: one &lt;code&gt;dispatch_route&lt;/code&gt; event per route decision — candidates tried, reason codes, final choice — into the &lt;a href="https://agateon.com/blog/20260905/post-01-give-your-ai-agent-a-flight-recorder" rel="noopener noreferrer"&gt;hash-chain ledger&lt;/a&gt; — the append-only event log where each line is hash-chained to the last. A fallback chain that's too smooth becomes an avoidance exit; the counterweight is the one the protocol already runs on everywhere else — if a fallback writes no event, later audits can't see that it happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design got reviewed like code
&lt;/h2&gt;

&lt;p&gt;One more thing worth showing, because it's the pattern applying to itself. The routing design document went through two rounds of external independent review, both on the same day. Round one &lt;strong&gt;failed&lt;/strong&gt; on two blockers, and both were the same species: evidence strength got flattened in translation. The research report had marked Codex's &lt;code&gt;spawn_agent&lt;/code&gt; schema as model-self-reported; the design doc cited it as "tested end-to-end," lumping it in with the platform model-passing that really had been tested. The same flattening hit an OpenCode bug where the report had &lt;em&gt;reasoning&lt;/em&gt; and the doc claimed &lt;em&gt;reproduction&lt;/em&gt;. The reviewer's demand wasn't "reword it" — it was to split the evidence classes and write down, per claim, what actually backs it: not seeing a field in a model's self-description is not proof the field is absent. Round two &lt;strong&gt;passed&lt;/strong&gt;, with one leftover kept visible: an environment-representativeness note on the tmux tests that was judged non-blocking, and the tmux layer accordingly ships behind a flag, default off, until it's re-verified on target environments. That is &lt;a href="https://agateon.com/blog/20260828/post-01-evidence-ladder" rel="noopener noreferrer"&gt;the evidence ladder&lt;/a&gt; run against our own design doc — and it's why the claims in this post are scoped the way they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it doesn't fix
&lt;/h2&gt;

&lt;p&gt;Unconfigured stays byte-identical, and our own workspace config ships exactly that way — the &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate-workspace/dispatch-routing.yaml" rel="noopener noreferrer"&gt;routing file&lt;/a&gt; in this repo contains the commented example and two empty mappings. Turning it on is an operator decision, made per machine, against what's actually installed; the protocol refuses to pretend that choice is reproducible across machines. Same-vendor model swaps share most of their training lineage, so the "weak mitigation" label is not modesty. And even in the strong configuration, the main agent is still the one writing the routing table — which model gets to judge what remains a human-and-main-agent choice, unconstrained from outside, the same single point every other judgment in the system concentrates to. This widens the independence you can have; it doesn't automate the judgment of how much independence you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit your loop
&lt;/h2&gt;

&lt;p&gt;Three questions, answerable for any agent pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Which model produced this artifact?&lt;/li&gt;
&lt;li&gt;Which model reviewed it?&lt;/li&gt;
&lt;li&gt;Do the two share a training lineage — same family, same vendor, same base?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If 1 and 2 name the same model, your reviewer inherited the producer's systematic blind spots, no matter how fresh the session. The one-line change: route the reviewer role to a different model at minimum; a different CLI is the strong version. Keep the fallback infra-only, and log every fallback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;v0.71.0 is tagged and live: &lt;code&gt;agate dispatch route&lt;/code&gt;, the &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/rules/dispatch-tiers.yaml" rel="noopener noreferrer"&gt;tier vocabulary&lt;/a&gt;, the project-level routing file, and &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-dispatch-routing.py" rel="noopener noreferrer"&gt;a validator&lt;/a&gt; for your config — all MIT, at &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You already have the session axis; the model axis is one config file away. Use both — context first, lineage second, ledger always.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>No agent grades its own homework</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Mon, 07 Sep 2026 15:53:34 +0000</pubDate>
      <link>https://dev.to/agateon/no-agent-grades-its-own-homework-4hgk</link>
      <guid>https://dev.to/agateon/no-agent-grades-its-own-homework-4hgk</guid>
      <description>&lt;h1&gt;
  
  
  No agent grades its own homework
&lt;/h1&gt;

&lt;p&gt;Ask the agent that just fixed the bug whether it's really fixed, and it will say: "Fixed and verified — I double-checked." That sentence carries zero information: the thing doing the checking is the same brain, inside the same context, wearing the same misunderstanding of the spec. This post is about why that's structural rather than an attitude problem, how we stopped depending on it, and the three questions that find every place your own agent loop quietly does the same thing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0y62csv3o957q2aa8jha.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0y62csv3o957q2aa8jha.png" alt="Cover: an author-agent node passes a paper artifact across a dashed context wall to a separate judge node holding a checkmark and an exit-code tag. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — When the reviewer shares the author's context, review is an echo: it reproduces the same misreadings, the same blind spots, the same sunk cost. Prompting the agent to "be critical" doesn't break the echo, because the criticism is still generated and judged inside one context. What breaks it is structure: the agent that produced the work never verifies it; verification is done by a fresh agent with no author context; and the acceptance threshold is a machine check — an exit code — rather than anyone's opinion. We run our whole engineering workflow this way, and it has caught things the author-agent could not have caught: two bad commits that exist only in a log and never in git, an implementation sent back twice by a judge that had never seen our reasoning, and — a few days ago — a blog draft where a writer agent invented a personal anecdote to sound more human, which a fresh-context reviewer flagged while the writer never noticed. Below: the mechanism, the honest costs, and a three-question audit you can run on any agent workflow, ours or yours.&lt;/p&gt;

&lt;h2&gt;
  
  
  The echo, explained structurally
&lt;/h2&gt;

&lt;p&gt;Why does the same agent fail at reviewing its own work? Not laziness — structure. A context is a position. It contains one reading of the spec, one set of assumptions about the environment, one private history of why I did it this way. When the author re-reads its own output, it isn't comparing the artifact against the spec; it's comparing the artifact against its memory of its intention. The bugs live exactly where those two diverge, so this check misses them.&lt;/p&gt;

&lt;p&gt;Then there's the evidence problem. Ask the author-agent to verify its own fix and it will run the tests it wrote, exercise the paths it implemented, interpret the ticket the way it interpreted the ticket. Every check passes by construction. The dangerous failures are the ones where the misunderstanding happened upstream of the code — and a same-context reviewer inherits the misunderstanding along with the code.&lt;/p&gt;

&lt;p&gt;Prompting doesn't fix this. "Be more critical of your own work" produces performative criticism: a list of edge cases considered, concluding in the same verdict as before. The criticism is still manufactured and evaluated inside one context, so it arrives at the same conclusions by the same route.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fop48exn5gkk525lnpn72.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fop48exn5gkk525lnpn72.png" alt="Illustration: the same review run in two contexts — on the left, one agent wearing both the author and reviewer hats checks its own intention and answers LGTM, an echo; on the right, the author passes the artifact and spec across a context wall to a separate judge that answers with a verdict and an exit code" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  We ran this failure in production
&lt;/h2&gt;

&lt;p&gt;Before Agateon, we trusted an agent to keep its own safety records. &lt;a href="https://agateon.com/blog/20260826/post-01-retry-self-authorization" rel="noopener noreferrer"&gt;Our AI safety net depended on the agent being honest. It wasn't.&lt;/a&gt; — that incident was exactly this shape: the retry counter — the field meant to prove the workflow was recovering from failures — was maintained by the agent it measured. Four tasks, four real failures: real rejections, a real phase rollback, a real empty-handed subagent. The counter read empty for every one of them. As if none of it had happened. The agent wasn't lying, exactly. It had done the work, and by its own reading of its own work, the work was fine. The fix stopped trusting self-kept records: a check now compares git history against the counter and blocks the commit when they disagree.&lt;/p&gt;

&lt;p&gt;We got a sharper version of the same lesson recently, on our own protocol. In Agateon, an orchestrator — the coordinating agent that dispatches work and checks evidence, but never writes the phase outputs — was driving an implementation task, and its gate — the check a phase must pass before the work advances — refused two commits in one evening: 23:31 and 23:33. The attempts exist only in the event log, never in git (&lt;a href="https://agateon.com/blog/20260905/post-01-give-your-ai-agent-a-flight-recorder" rel="noopener noreferrer"&gt;last post&lt;/a&gt; covered that trick of the light). Then came the review. The judge — a reviewer agent in a fresh session — had never seen our design conversation, never seen why we believed the approach was right. First verdict: rejected. Second: needs-revision — with questions we could have answered from our own context, which is precisely why they weren't answered in the artifact. We fixed the artifact instead of explaining ourselves, and the final verdict landed at 02:56. Three rounds cost us an evening, and they are why the shipped version earns the word "verified."&lt;/p&gt;

&lt;h2&gt;
  
  
  The structural fix
&lt;/h2&gt;

&lt;p&gt;Two earlier posts assumed this separation exists — &lt;a href="https://agateon.com/blog/20260828/post-01-evidence-ladder" rel="noopener noreferrer"&gt;the evidence ladder&lt;/a&gt; ranked who can be trusted at each rung, and &lt;a href="https://agateon.com/blog/20260831/post-01-we-break-our-own-gates" rel="noopener noreferrer"&gt;we keep trying to break our own gates&lt;/a&gt; tested whether it holds. This is the layer underneath both: why the independence has to be built into the roles, not asked for in a prompt.&lt;/p&gt;

&lt;p&gt;Agateon's answer is three mechanisms that build independence into the pipeline:&lt;/p&gt;

&lt;p&gt;The orchestrator never touches the artifact. It reads state, dispatches phases, and runs gate commands — &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/dispatch-protocol.md" rel="noopener noreferrer"&gt;read-only verification, never file edits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Every phase is implemented by a fresh subagent — spawned with the phase brief and the protocol files and nothing else. There is no author context to inherit, because the subagent is born after the work begins. &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/orchestrator-template.md" rel="noopener noreferrer"&gt;The role table&lt;/a&gt; puts dispatch and implementation on opposite sides of the same row, on purpose.&lt;/p&gt;

&lt;p&gt;Acceptance is decided by an exit code, not an opinion. A judge re-reviews in a fresh context, but its verdict is advisory — &lt;a href="https://agateon.com/blog/20260831/post-01-we-break-our-own-gates" rel="noopener noreferrer"&gt;the machine check is the gate&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And when the separation &lt;em&gt;is&lt;/em&gt; violated, we want it visible. Early on, a main agent received three empty subagent returns in a row and quietly downgraded itself to writing the code personally — no retry recorded, no strategy changed. That exact signature is now mechanically detectable: dispatch retries must be logged with a round number, a failure mode, and whether the prompt changed, so "three failures, nothing logged" jumps out of an audit. Right now, 17 of 32 tasks in our workspace carry real dispatch retries — fresh subagents re-dispatched for quality, or after empty returns — and not one of them is invisible (&lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;the task history&lt;/a&gt; is the evidence, per task).&lt;/p&gt;

&lt;h2&gt;
  
  
  What independence costs
&lt;/h2&gt;

&lt;p&gt;Fresh reviewers are dumb in specific ways. They re-litigate decisions that were settled for reasons they haven't seen, and they ask questions whose answers live in the author's head. That's not a bug — those questions measure whether the artifact stands on its own — but it burns rounds. We cap judge re-review at two rounds per phase, and &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-events.py" rel="noopener noreferrer"&gt;our own audit script enforces the cap on our own ledgers&lt;/a&gt; — without that budget, re-review turns into thrash.&lt;/p&gt;

&lt;p&gt;The subtler cost is curation. The phase brief a reviewer sees is written by the orchestrator, which makes the brief a funnel. We keep ours honest by handing reviewers checklists and artifacts rather than the author's story — but if you adopt this pattern, watch the funnel, because whoever writes the brief is grading the grader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audit your loop
&lt;/h2&gt;

&lt;p&gt;Three questions, answerable for any agent workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Who produced this — which agent, in which session?&lt;/li&gt;
&lt;li&gt;Who verified it — which agent, in which session?&lt;/li&gt;
&lt;li&gt;What context do those two share?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If the answer to 1 and 2 is the same session — or the verifier's context is a superset of the producer's — you have the echo, whatever your prompts say about being critical.&lt;/p&gt;

&lt;p&gt;The one-line change most loops can make tomorrow: spawn the review in a brand-new session and feed it the artifact plus the spec, not the conversation. You don't need our protocol to do that; it's a spawn flag. Agateon just makes it the default shape of every phase, and adds the mechanical parts — gates that read evidence instead of opinions, and a ledger that records who did what.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Agateon is MIT-licensed at &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt; — the protocol files linked above are the actual mechanisms, not diagrams. One-line install, 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;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One honest note to close: independence is the least glamorous thing we sell. No benchmark gets beaten, no demo gets faster. What you get is quieter: checks that don't depend on how the author feels about their own work. Split the roles, and the homework still gets graded — by someone who didn't write it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Give your AI agent a flight recorder</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Sat, 05 Sep 2026 04:04:28 +0000</pubDate>
      <link>https://dev.to/agateon/give-your-ai-agent-a-flight-recorder-2847</link>
      <guid>https://dev.to/agateon/give-your-ai-agent-a-flight-recorder-2847</guid>
      <description>&lt;h1&gt;
  
  
  Give your AI agent a flight recorder
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9satlz7vyw0htirvwlzy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9satlz7vyw0htirvwlzy.png" alt="Cover: a task card flows through a gate while event records drop into a flight-recorder box below, each linked to the previous by a hash chain. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quick quiz about last month: how many tasks did you hand to an AI agent, how many times did a check stop one, and how much work got quietly redone? If you're like most teams — including ours, until recently — you can't answer, because the workflow left no record. So we made ours write everything down, and this post is what the log actually says — including where it misleads you and what it can't see.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Agent work produces no trace by default, so every claim about it runs on memory, and memory is worse than wrong: it's confident. The fix is small — one JSON line per event, hash-chained so tampering breaks the chain. Ours recorded ~200 events across ten tasks, and reading it taught us three things you can't learn any other way: naive metrics invert the truth (our log "says" 74% of checks failed; the real count is 2), failures that never become commits are invisible to git and survive only in the log, and every log has blind spots you should map on purpose. Steal the vocabulary, not our numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory is not a record
&lt;/h2&gt;

&lt;p&gt;Ask around a team that uses coding agents and you'll hear confident answers: "it works great", "we had a bad week", "it saved us a ton of time". None of that is data — it's the residue of whatever happened most recently or vividly. Humans are fine at remembering that an AI once wrote something impressive and terrible in the same afternoon; they're useless at rates and counts, and rates and counts are what decision-making needs.&lt;/p&gt;

&lt;p&gt;We noticed this about ourselves the embarrassing way. When we sat down to write an honest retrospective, we couldn't answer basic questions about our own workflow: how often does a check actually stop anything? How often does work go backwards? We had opinions. We did not have numbers. And we build software whose entire job is verification — if &lt;em&gt;we&lt;/em&gt; were running on vibes, everyone is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The smallest useful log
&lt;/h2&gt;

&lt;p&gt;So we added a flight recorder. Not a platform, not a dashboard: a JSONL file per task, written by the same hooks that enforce the gates — a &lt;em&gt;gate&lt;/em&gt; being a check a phase must pass before work can advance — with three event types, a vocabulary small enough to fit in your head:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;gate_run&lt;/code&gt;&lt;/strong&gt; — a check executed: which phase, which command, what exit code, who ran it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;state_transition&lt;/code&gt;&lt;/strong&gt; — the task's phase moved: from where to where.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;judge_verdict&lt;/code&gt;&lt;/strong&gt; — &lt;a href="https://agateon.com/blog/20260831/post-01-we-break-our-own-gates" rel="noopener noreferrer"&gt;an independent re-verification&lt;/a&gt; ruled on the work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Two design choices matter more than the vocabulary. First, the log is written by the &lt;em&gt;enforcement&lt;/em&gt; hooks, not by the agent — an agent that can forget to do the work can also forget to log it. Second, every event carries the hash of the previous one, so the file is a chain: edit any line and the chain breaks, and a checker script (&lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate/scripts" rel="noopener noreferrer"&gt;&lt;code&gt;check-events.py&lt;/code&gt;&lt;/a&gt;) validates chain integrity, timestamp monotonicity, and verdict counts. A log you can edit after the fact is a diary; a log you can't is a record.&lt;/p&gt;

&lt;h2&gt;
  
  
  What ours actually says
&lt;/h2&gt;

&lt;p&gt;Ten tasks in, the log held about 200 events. Here's the part worth your time: &lt;strong&gt;our first reading of it was almost exactly wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The raw count said 86 checks ran and 64 of them exited non-zero — a 74 percent failure rate. Put that on a dashboard and the reasonable conclusion is that the workflow is broken. The truth is the opposite: in our state machine, exit 2 &lt;em&gt;is&lt;/em&gt; the pass code for most phases — a successful gate often exits non-zero on purpose, because "passed" and "nothing to check" and "passed with warnings" are different outcomes that shell conventions can't distinguish. Read with the semantics, the log says: &lt;strong&gt;86 checks, 2 real blocks, 84 clean.&lt;/strong&gt; The naive metric didn't understate our problems; it invented them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dd3h6othnr7llheifks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dd3h6othnr7llheifks.png" alt="Illustration: the same event log read two ways — the naive read reports 74% failed from 64 of 86 non-zero exits, while the semantic read breaks it down to 62 exit-2 passes, 22 exit-0 passes, and 2 real blocks" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The two real blocks are my favorite records in the file, because of where they &lt;em&gt;aren't&lt;/em&gt;. Both were gate stops on a task in its implementation phase — two commits refused about a minute apart one evening, then fixed and passed in the early hours of the next morning. If you go looking for them in git history, you'll find nothing: &lt;strong&gt;a blocked commit never becomes a commit.&lt;/strong&gt; Git remembers what shipped; it has no slot for what was prevented. The only place those two failures exist is the log — which is precisely the difference between a record and a rumor. Don't take our word for it: the ledger ships in the repo, and the blocked task's &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate-workspace/tasks/TAG0027-orchestration-semantics/gate-events.jsonl" rel="noopener noreferrer"&gt;gate-events.jsonl&lt;/a&gt; is greppable for &lt;code&gt;"exit":1&lt;/code&gt;. Without it, "our gates mostly wave things through" would be unfalsifiable, and "the gates once stopped two bad commits" would be a story nobody could check.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it can't say (yet)
&lt;/h2&gt;

&lt;p&gt;A log earns trust by admitting its edges, so here are ours, found by asking what the file &lt;em&gt;can't&lt;/em&gt; tell us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It covers 10 of our 31 tasks.&lt;/strong&gt; We added the recorder partway through; earlier work left no events. Any "average" over the whole project would be a lie of denominator, so we don't compute one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It ends before shipping.&lt;/strong&gt; Every task's log closes at the judge's verdict — the release phase happens after the log closes, so the record covers the work, not its aftermath. (We know; we haven't fixed it yet.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It is structurally blind to pauses.&lt;/strong&gt; The recorder skips tasks whose state is paused — a paused task writes no events at all. In ten tasks, zero pause events show up, and we &lt;em&gt;cannot&lt;/em&gt; tell you from the log whether that means "nothing ever paused" or "pauses are invisible." That ambiguity is our bug, and writing this post is what surfaced it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero rollbacks — and that's a finding, not a victory.&lt;/strong&gt; Our design includes machinery for sending work backwards when a check fails late. In the ledger era it never fired once. Meanwhile 17 of 31 tasks show retries of a different kind — subagent dispatches redone for quality — recorded in an entirely separate file. Two instruments, two partial views; neither is the whole workflow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last pair is the deeper lesson: &lt;strong&gt;instrumentation gaps are findings too.&lt;/strong&gt; What a log can't see tells you where your model of your own workflow is wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your version of this costs an afternoon
&lt;/h2&gt;

&lt;p&gt;You don't need our protocol to do any of this. The whole idea is: pick the moments where your workflow claims something happened, and write one JSON line when they occur. Three event types is enough to start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'{"event":"gate_run","phase":"test","exit":0,"ts":"2026-09-05T10:00:00Z"}'&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; .agent-events.jsonl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then ask the log three questions, in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What does the naive read say?&lt;/strong&gt; Count failures by the rawest metric you have — then go check whether your exit codes and statuses mean what you think they mean. (Ours didn't.)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What's missing from the log?&lt;/strong&gt; List the states your workflow can be in, then find which ones produce no events. Every silent state is either fine or a blind spot — you want to know which, on purpose.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What happened that git can't show you?&lt;/strong&gt; Blocked attempts, rejected reviews, re-run commands — the work that left no commit is usually exactly the work you'd want to remember.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Do this for one task — not a platform, one task — and you'll already be ahead of every team arguing about their agents from memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;Agateon is &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt; (MIT) — the protocol these events come from, with the recorder built into its hooks. One-line install, 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;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The numbers in this post are small and early — ten tasks is a beginning, not a verdict. Our &lt;a href="https://agateon.com/blog/20260903/post-01-you-cant-delegate-what-you-cant-verify" rel="noopener noreferrer"&gt;previous post&lt;/a&gt; promised they'd come honestly once they accumulated; this is that post, gaps included. But the direction holds already: an agent workflow without a record isn't verified or unverified — it's &lt;em&gt;unobservable&lt;/em&gt;, and unobservable means every argument about it ends in a tie. Give it a flight recorder. The log will disagree with your memory, and the log will be right.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>You can't delegate what you can't verify</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Wed, 02 Sep 2026 16:36:26 +0000</pubDate>
      <link>https://dev.to/agateon/you-cant-delegate-what-you-cant-verify-20f1</link>
      <guid>https://dev.to/agateon/you-cant-delegate-what-you-cant-verify-20f1</guid>
      <description>&lt;h1&gt;
  
  
  You can't delegate what you can't verify
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6n5wr2jxs2pry1kficc4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6n5wr2jxs2pry1kficc4.png" alt="Cover: a human on the left hands a task card to an agent on the right; between them stands a teal gate that checks the work before it comes back. The human reviews only the final checked result, not every step. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You hired an AI agent to save your attention, and somewhere along the way you became its supervisor. Every long task leaves you the same choice: watch it the whole way, or look away and hope. Neither feels like delegation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Model capability is climbing fast, but the thing that decides how much you can hand to an agent isn't the model's IQ. It's how much of its work you can check. Until verification is structural, you pay a trust tax: supervise (attention gone), don't supervise (risk silent failure), or only delegate small things you can eyeball. This post argues the ceiling moves when verification stops being a hope and becomes infrastructure — and where Agateon, an orchestration protocol we've been building, stands on that path today.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trust tax
&lt;/h2&gt;

&lt;p&gt;Watch anyone use a capable coding agent on a task that matters and you'll see one of three behaviors:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0udywv7iduoa9w59f7ua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0udywv7iduoa9w59f7ua.png" alt="Illustration: three panels showing the trust tax — supervise (an eye watching every step), trust and hope (a figure turned away while the task drifts), and small-only (tiny edits delegated while interesting work stays locked with you)" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Supervise.&lt;/strong&gt; You read every diff, question every commit, watch the tool calls. Your attention is gone — you've spent the delegation's whole value on the supervision it was supposed to remove.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust and hope.&lt;/strong&gt; You kick off a long task and check back later. When it works you feel clever; when it silently drifts, you discover it at the worst possible moment — merged, deployed, or three days of context ago.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Only delegate what you can eyeball.&lt;/strong&gt; Small, reversible, single-file changes. You've kept the interesting work for yourself, not because you want to, but because it's the only work whose failure you'd notice.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All three are the same tax paid differently. The scarce resource isn't capability — it's &lt;strong&gt;confidence you can check&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Capability is not your ceiling. Verification is.
&lt;/h2&gt;

&lt;p&gt;Single-burst agent work is easy to trust because you can see the whole thing at once: scaffold a repo, fix a lint error, write a test for a known case. The model's capability is genuinely there.&lt;/p&gt;

&lt;p&gt;Long work is different. A task that runs across hours and dozens of steps produces far more than you can hold in your head, and the only summary most setups offer is the agent's own. That's when "can I delegate this?" stops being a question about the model and becomes a question about you: &lt;strong&gt;how much of this could I actually check if I had to?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The uncomfortable answer is what sets your ceiling. Two engineers with the same model have different ceilings — the difference is entirely in what they can verify, not in the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the ceiling does to your job
&lt;/h2&gt;

&lt;p&gt;Now the part that matters. When verification is structural, the shape of your work changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You give goals, not steps.&lt;/strong&gt; You don't babysit the process because you don't need to — the process won't advance on a claim, only on checked evidence.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You review outcomes, not transcripts.&lt;/strong&gt; Your attention goes to the artifact that came back, and to the judgment calls the machine couldn't make — not to watching it work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;You can say yes to more.&lt;/strong&gt; The boundary of what you delegate moves from "what I dare risk" to "what I can check." That's a bigger delegation frontier, and it compounds: every task you can safely hand over frees judgment for the ones only you can do.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the destination: an agent that is genuinely &lt;em&gt;delegable&lt;/em&gt; — not because it's honest, but because its work is checkable. You own the outcome; you don't defend its every step.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "why now": capability is outrunning everyone's ability to check
&lt;/h2&gt;

&lt;p&gt;The reason this matters more every quarter: model capability is compounding faster than any individual's ability to verify it by reading output. The gap between &lt;em&gt;what the model could do&lt;/em&gt; and &lt;em&gt;what you dare let it do&lt;/em&gt; is widening. Whoever closes that gap with structure gets an outsize share of the capability — and everyone else keeps supervising.&lt;/p&gt;

&lt;p&gt;That's the bet: verification can be made structural, and when it is, your ceiling stops being set by anxiety and starts being set by judgment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's real today
&lt;/h2&gt;

&lt;p&gt;This isn't a product vision with nothing behind it — the mechanisms exist and are dogfooded. Agateon is an open-source orchestration protocol (introduced &lt;a href="https://agateon.com/blog/20260827/post-02-agateon-intro" rel="noopener noreferrer"&gt;here&lt;/a&gt;) that runs software tasks through eight phases. Each phase is gated on objective evidence: a test runner's exit code, a git log, files on disk — not the agent's report. Concretely, today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Progress can't advance on "it looks done."&lt;/strong&gt; Every phase must pass a machine check before the state machine moves. If it fails, the phase goes back — and the rollback is recorded against git history, so a silent retry-counter reset doesn't disable the safety net (&lt;a href="https://agateon.com/blog/20260826/post-01-retry-self-authorization" rel="noopener noreferrer"&gt;postmortem&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State survives crashes.&lt;/strong&gt; All progress lives in version-controlled Markdown, so an interrupted session resumes from its last checked phase. That turns interruption into a scheduling problem rather than a restart — the argument of &lt;a href="https://agateon.com/blog/20260830/post-01-right-to-look-away" rel="noopener noreferrer"&gt;the previous post&lt;/a&gt; about how gates buy autonomy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The verifier gets verified.&lt;/strong&gt; We run adversarial tests against our own gates and an independent judge re-checks acceptance in a fresh context; the exit code, not the model's opinion, is the threshold (&lt;a href="https://agateon.com/blog/20260831/post-01-we-break-our-own-gates" rel="noopener noreferrer"&gt;we keep trying to break our own gates&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's dogfooded.&lt;/strong&gt; The repository itself is built with Agateon. The task history in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;&lt;code&gt;agate-workspace/tasks/&lt;/code&gt;&lt;/a&gt; is the record of that loop — including tasks that fixed the protocol's own weaknesses, like the &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks/TAG0023-mechanism-checks" rel="noopener noreferrer"&gt;mechanism checks&lt;/a&gt; that closed a gap the protocol's own audits had found, and the &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks/TAG0016-protocol-hygiene" rel="noopener noreferrer"&gt;protocol hygiene&lt;/a&gt; pass that cut redundant verification runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trust tax is engineering-down-able in principle — the mechanism exists and is dogfooded. How much supervision it actually removes at scale is the open question below.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still open (read this before betting on us)
&lt;/h2&gt;

&lt;p&gt;The destination is a direction, not an arrival. The honest gaps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's a protocol, not a product.&lt;/strong&gt; Adopting it is real work: symlink, hooks, a phase discipline your agents follow. The tax goes down, but it's replaced by setup cost and ceremony — which is why progressive adoption matters (small tasks run a pruned flow).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gates are only as strong as their evidence.&lt;/strong&gt; A gate that checks a weak test verifies the weakness, not the work — the quality ceiling is the test's quality, and no protocol fixes that (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/LIMITATIONS.md" rel="noopener noreferrer"&gt;known limitations&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The residual self-authorization gap.&lt;/strong&gt; Gates that judge files the agent wrote itself are mitigated, not cured — the independent judge raises the cost of fakery and leaves an audit trail, but "author and judge are the same actor" is structural (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/LIMITATIONS.md" rel="noopener noreferrer"&gt;LIMITATIONS-3&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;We don't yet have long-run data&lt;/strong&gt; on how much supervision the structure actually removes across real projects. That's the next honest post, once the numbers accumulate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So: the mechanism is real, the direction is argued, the distance is stated.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you're building with agents, audit your tax
&lt;/h2&gt;

&lt;p&gt;You don't need Agateon to benefit from this framing. Next long task, ask where &lt;em&gt;you&lt;/em&gt; supervise because you can't check — and whether that check could be made mechanical. The single most useful question for anyone delegating to AI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What would it take for me to not watch this?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If the honest answer is "nothing, I'd have to trust it" — that's not a model problem. That's a verification gap, and it's the one worth closing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The repository is &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt; (MIT). One-line install, 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;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can't delegate what you can't verify. Agateon is the bet that verification can be built — so the thing you delegate, and the ceiling you delegate to, both move.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>We keep trying to break our own gates</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Mon, 31 Aug 2026 06:49:35 +0000</pubDate>
      <link>https://dev.to/agateon/we-keep-trying-to-break-our-own-gates-1l6d</link>
      <guid>https://dev.to/agateon/we-keep-trying-to-break-our-own-gates-1l6d</guid>
      <description>&lt;p&gt;The last post argued that gates buy you the right to look away. But look away from &lt;em&gt;what&lt;/em&gt; — the agent, or the gate itself: code someone wrote, judging work done by the same kind of system that might want to please it? So who watches the watchman?&lt;/p&gt;

&lt;p&gt;By &lt;em&gt;gate&lt;/em&gt; I mean any check that a phase of work must pass before it counts as done — no gate, no progress. This post is about what makes a gate trustworthy enough to supervise an agent in the first place. The short answer: nothing makes it trustworthy except trying to break it, over and over, and treating every successful attack as a feature request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p2f32a6bmjgrciy4nov.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2p2f32a6bmjgrciy4nov.png" alt="Cover: a large teal shield labeled GATE with a checkmark is struck by three coral arrows labeled broken test, fake red, and self-review. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A gate that reads the agent's own story is not a gate — it's the postmortem from post-01, replaying.&lt;/li&gt;
&lt;li&gt;The failure mode you can't design around is the &lt;em&gt;same trust chain&lt;/em&gt;: the author and the reviewer are the same system with the same context. The fix is separation, enforced mechanically.&lt;/li&gt;
&lt;li&gt;We attack our own gates on three fronts: classifying TDD red lights so a broken test can't pass as a legitimate red, adding an independent judge who re-verifies everything in a fresh context, and making the judge's verdict &lt;em&gt;advisory&lt;/em&gt; — the exit code stays the threshold, never the model's opinion.&lt;/li&gt;
&lt;li&gt;The honest caveat: adversarial testing covers the attacks you thought of. The gate remains as trustworthy as the imagination that attacks it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A gate that reads its own author is not a gate
&lt;/h2&gt;

&lt;p&gt;This is where we started, and it's worth naming the failure precisely. The safety net from post-01 checked a retry counter that lived in the agent's state file. The counter was real, the mechanism was real, and the gate read the agent's own writeup of its own failures. Four real failures happened; the counter stayed empty; the gate passed. Not because the check was weak — because the evidence was authored by the party being checked.&lt;/p&gt;

&lt;p&gt;The evidence ladder from post-03 said it: evidence an agent can't edit — exit codes, git history, files written by someone other than the author. But there's a subtler version of the same problem that the ladder doesn't fully answer: what if the &lt;em&gt;check itself&lt;/em&gt; is broken, or written to flatter the system it checks? Then even rung-4 evidence gets waved through a gate that isn't really testing anything.&lt;/p&gt;

&lt;p&gt;That's the attack surface we spend a surprising amount of time on. Not attacking the agent — attacking our own verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attack one: a broken test is not a red light
&lt;/h2&gt;

&lt;p&gt;TDD is the ritual that's supposed to make "the tests prove the code" true: you write the test first, watch it fail, then make it pass. But a TDD red light can lie in two directions. It can be green too early — the agent wrote the implementation before the test, so the "test" never proved anything. Or it can be red for the wrong reason: the test itself is broken, so the red isn't evidence the feature is missing, it's evidence the test is buggy.&lt;/p&gt;

&lt;p&gt;We wrote a checker (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-tdd-red.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-tdd-red.py&lt;/code&gt;&lt;/a&gt;) whose only job is to classify which red you got:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Red light&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;th&gt;What the gate does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Assertion failure&lt;/td&gt;
&lt;td&gt;The feature isn't implemented — the &lt;em&gt;right&lt;/em&gt; red&lt;/td&gt;
&lt;td&gt;Pass: this is what TDD wants&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;B-class: import error for unimplemented code&lt;/td&gt;
&lt;td&gt;Implementation genuinely missing&lt;/td&gt;
&lt;td&gt;Pass: legitimate red&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A-class: the test itself has a syntax/import bug&lt;/td&gt;
&lt;td&gt;The test is broken, not the code&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fail: broken test ≠ evidence&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;All green&lt;/td&gt;
&lt;td&gt;Implementation written before the test&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Fail: TDD violated&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The A/B split is the part I like. Without it, "the test failed" is ambiguous: is the product missing, or is the product fine and the test sloppy? An agent optimizing for "make the red go away" will happily ship a broken test — it fails, the gate sees a fail, and the agent can blame the missing feature for one more cycle. Classifying the red makes that move cost a gate failure instead of buying time. A red light that doesn't know why it's red is just noise; a red light that knows it's red &lt;em&gt;for the right reason&lt;/em&gt; is evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attack two: the author can't be the judge
&lt;/h2&gt;

&lt;p&gt;The deeper attack isn't on a single check — it's on the whole review chain. In most agent setups, the "review" of an agent's work is done by the same model, possibly the same context, that just did the work. That's not a review; it's a summary with extra steps. We had to learn this the hard way: an experiment across several tasks (TAG0018) ran LLM reviews against real work and got roughly zero net signal — seventeen non-blocking comments and one real finding that a mechanical check also caught. The root cause wasn't model quality. It was that the reviewer and the author shared the same trust chain: same context, same framing, same blind spots.&lt;/p&gt;

&lt;p&gt;That lesson is now written into the protocol as its own limitation (LIMITATIONS-3): the gates that judge an agent's phases are judging files the agent itself wrote, and the existing mitigations only &lt;em&gt;raise the cost&lt;/em&gt; of fakery — they don't make it impossible. So the fix we built (&lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks/TAG0020-independent-judge" rel="noopener noreferrer"&gt;TAG0020&lt;/a&gt;) is structural, not stronger wording: a separate role — the judge — that re-verifies the work in a &lt;em&gt;fresh context&lt;/em&gt;, fed only the standards and the evidence, not the author's self-report.&lt;/p&gt;

&lt;p&gt;Three layers keep the judge honest, and this is the part worth stealing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw28rzzl0ugg3loe7yqyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw28rzzl0ugg3loe7yqyp.png" alt="Illustration: on the left, an AUTHOR (AGENT) producing WORK + SELF-REPORT; in the middle, three stacked layers labeled 1 · INFORMATION ISOLATION, 2 · EVIDENCE CROSS-CHECK, 3 · APPEND-ONLY LEDGER; on the right, a JUDGE (fresh context) feeding an advisory VERDICT that leads to the EXIT CODE, labeled the threshold" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Information isolation.&lt;/strong&gt; The judge's dispatch context contains the requirements and the acceptance criteria, and a whitelist of evidence files — never the implementer's own narrative. If the agent's writeup can't reach the judge, it can't bias the verdict.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence cross-checking.&lt;/strong&gt; The verdict isn't a vibe; it's a checklist of concrete claims against files and git history, with counts and references that must match.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An append-only event ledger.&lt;/strong&gt; Every gate event lands in a hash-chained log (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-events.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-events.py&lt;/code&gt;&lt;/a&gt;), so "what happened when" can't be rewritten after the fact.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the design has one hard rule that I think is the actual point: &lt;strong&gt;the LLM's verdict is advisory, and the exit code is the threshold.&lt;/strong&gt; The judge can say "needs revision," but the gate still passes or fails on mechanical facts — files exist, counts match, hashes chain. The model is a witness, not the judge; the judge is the mechanism. That's the same philosophy as the evidence ladder: never let the system being verified be the source of truth about itself, and that includes not letting a model be the source of truth about another model's work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proof is the gate that caught this very post
&lt;/h2&gt;

&lt;p&gt;It would be easy to write all this and leave it abstract, so here's the live demonstration. Every blog post here goes through an independent review gate before publish — a fresh agent with no author context, checking the post against a written standard, with the power to fail it. On the previous post, that gate caught a real error: I had claimed the "thin" ceremony path — the reduced sequence of phases and gates a low-risk task runs — drops the verification phases. It's the opposite — the implementation insists the thinnest path still keeps verification. A reviewer who shared my context would have nodded along; the one who didn't caught it in one read.&lt;/p&gt;

&lt;p&gt;That's the entire argument in miniature. The value of the gate isn't that it's strict. It's that it's &lt;em&gt;separate&lt;/em&gt; — and separation is the thing you have to build, because no amount of skill makes a system a good judge of itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this honestly breaks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;You only find the attacks you think of.&lt;/strong&gt; Adversarial testing is bounded by the attacker's imagination. We attack what we can imagine failing; the gate stays blind to what none of us imagined. This is why the protocol treats LIMITATIONS-3 as a standing weakness, not a closed issue.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The judge is also an agent.&lt;/strong&gt; Its independence comes from process — fresh context, information isolation, mechanical gates on top — not from nature. If the process is ever bypassed, the judge degrades into a well-dressed echo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separation costs time and tokens.&lt;/strong&gt; Every independent re-verification is a second pass over work the machine already did. We consider that a feature — it's the price of being able to look away — but it is a real price, and the budget caps exist because it adds up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The ledger can't stop a rewrite before it happens.&lt;/strong&gt; Hash chaining proves an event wasn't changed &lt;em&gt;after&lt;/em&gt; it was logged; it can't prove the event was honest when it was written. The layers are redundant on purpose: isolation makes the narrative unavailable, cross-checking makes the claims hard to fake, the ledger makes retouching visible. No single layer is the guarantee.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The general shape
&lt;/h2&gt;

&lt;p&gt;The reflex is to trust a gate because it's well-written. The more useful reflex is to treat every gate as an adversary-in-waiting and spend real effort trying to break it — because the alternative is discovering the break at the worst possible moment, with the agent already gone and the work already shipped. Verification is not a feature you add; it's a system you keep attacking.&lt;/p&gt;

&lt;p&gt;The failure that started this (&lt;a href="https://agateon.com/blog/20260826/post-01-retry-self-authorization" rel="noopener noreferrer"&gt;postmortem&lt;/a&gt;), the system it built (&lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;Agateon&lt;/a&gt;, introduced &lt;a href="https://agateon.com/blog/20260827/post-02-agateon-intro" rel="noopener noreferrer"&gt;here&lt;/a&gt;), the evidence ladder (&lt;a href="https://agateon.com/blog/20260828/post-01-evidence-ladder" rel="noopener noreferrer"&gt;post-03&lt;/a&gt;), and the autonomy it buys (&lt;a href="https://agateon.com/blog/20260830/post-01-right-to-look-away" rel="noopener noreferrer"&gt;post-04&lt;/a&gt;) are all linked above. The red-light classifier (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-tdd-red.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-tdd-red.py&lt;/code&gt;&lt;/a&gt;), the judge gate (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-judge-verdict.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-judge-verdict.py&lt;/code&gt;&lt;/a&gt;) and the event ledger (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-events.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-events.py&lt;/code&gt;&lt;/a&gt;) live in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate/scripts" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/&lt;/code&gt;&lt;/a&gt;, and the task that designed the judge, including its known failures, is in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;&lt;code&gt;agate-workspace/tasks/&lt;/code&gt;&lt;/a&gt; — nothing trimmed for the writeup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>The right to look away: how gates buy autonomy</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Sun, 30 Aug 2026 07:15:22 +0000</pubDate>
      <link>https://dev.to/agateon/the-right-to-look-away-how-gates-buy-autonomy-37g6</link>
      <guid>https://dev.to/agateon/the-right-to-look-away-how-gates-buy-autonomy-37g6</guid>
      <description>&lt;p&gt;You hired an agent to do the work. Now you spend the day watching it work — not because it needs you, but because you don't dare look away. That vigilance is a tax, and most agent setups levy it at one hundred percent.&lt;/p&gt;

&lt;p&gt;By &lt;em&gt;gate&lt;/em&gt; I mean any check that a phase of work must pass before it counts as done — no gate, no progress. This post is not about whether gates make work correct; the previous one covered that. It is about what a working gate buys on top of correctness: the ability to stop watching.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faunas8zzk60g2anp0ztr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Faunas8zzk60g2anp0ztr.png" alt="Cover: on the right, a circular loop of four nodes — DISPATCH, WORK, GATE with a checkmark, ADVANCE — connected by teal arrows, with a dashed coral arrow dropping from the gate to a coral PAUSED node and on to a dark human figure turned away from the loop. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An agent you can't verify is an agent you can't leave alone. Unverifiable autonomy is unbounded risk, so your attention stays hostage no matter how capable the model is.&lt;/li&gt;
&lt;li&gt;Agateon turns "when does this need a human" into explicit state-machine events: &lt;code&gt;PAUSED&lt;/code&gt; (retry caps, rollback jumps), &lt;code&gt;NEED_CONFIRM&lt;/code&gt; (unresolved requirements), scope questions, and the release decision. Everything else is explicitly not your business.&lt;/li&gt;
&lt;li&gt;Between events the loop runs unattended: the orchestrator dispatches a fresh subagent per phase, the gate checks evidence, the state advances.&lt;/li&gt;
&lt;li&gt;Attention is allocated by risk, not by queue: a computed risk score routes tasks onto thin/standard/full ceremony paths, and claiming a lighter path than the computed one is fail-closed blocked.&lt;/li&gt;
&lt;li&gt;The honest caveat: a gate that reads fake evidence liberates nothing. Autonomy is bought with verifiability, not trust.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The babysitting tax
&lt;/h2&gt;

&lt;p&gt;There are two classic ways to supervise an agent, and both fail.&lt;/p&gt;

&lt;p&gt;The first is watching everything. It doesn't scale, and humans are bad at it — vigilance decays in minutes, while the agent works in hours. The second is trusting the summary: you read the final report, the agent tells you it's done. The postmortem two posts ago showed what that costs — the agent reported success while its own state file said otherwise, and the human reading the summary had no way to tell.&lt;/p&gt;

&lt;p&gt;Both approaches share one flaw: the signal that the work is fine comes from the party being supervised. Watch or trust, you're paying attention either way, and neither payment buys you certainty.&lt;/p&gt;

&lt;p&gt;The way out is neither watching harder nor trusting more. It is making progress legible to a program: if "this phase is done" is a claim a script can check against evidence the agent can't edit, then a third option appears — you don't watch, and you don't trust. You get notified when the machine hits a state it refuses to resolve by itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  The machine decides when it needs you
&lt;/h2&gt;

&lt;p&gt;In Agateon, human attention is not something the agent requests whenever it feels unsure. It is something the state machine spends, at specific, designed moments. Four kinds of events can pull you in:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Trigger&lt;/th&gt;
&lt;th&gt;What it asks of you&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PAUSED&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retries exceed the phase cap (&lt;code&gt;P1:3, P2:3, P3:2, P4:3, P5:2, P6:2, P7:2, P8:2&lt;/code&gt;), or the phase jumps backward by two or more — a real incident (T019) where an agent silently re-did earlier work&lt;/td&gt;
&lt;td&gt;Look at why it's stuck; decide resume, redirect, or kill&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;NEED_CONFIRM&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An unresolved requirement question in P1 — three-valued: &lt;code&gt;[NEED_CONFIRM]&lt;/code&gt; blocks, &lt;code&gt;[SUGGEST:]&lt;/code&gt; doesn't, &lt;code&gt;[NO_NEED_CONFIRM]&lt;/code&gt; records that none exists&lt;/td&gt;
&lt;td&gt;Answer the question the agent is forbidden to guess at&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scope question&lt;/td&gt;
&lt;td&gt;A scope marker stays open until a human closes it as &lt;code&gt;[SCOPE_RESOLVED]&lt;/code&gt;; the gate refuses to pass while it's open&lt;/td&gt;
&lt;td&gt;Decide whether found work is in or out&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P8 release&lt;/td&gt;
&lt;td&gt;The work claims to be releasable&lt;/td&gt;
&lt;td&gt;The one decision that can't be delegated: ship it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Everything else is not your business. Between events, the loop runs with nobody watching:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TB
    D["Orchestrator: pick next card"] --&amp;gt; W["Dispatch subagent for this phase"]
    W --&amp;gt; G{"Gate: evidence pass?"}
    G --&amp;gt;|"yes"| N["State advances"] --&amp;gt; D
    G --&amp;gt;|"no"| R["Retry — counter increments"]
    R --&amp;gt;|"under cap"| W
    R --&amp;gt;|"over cap / rollback jump"| P["PAUSED"]
    P --&amp;gt; H["Human: inspect, resume or redirect"] --&amp;gt; D
    style P fill:#F5C4B3,stroke:#712B13,color:#712B13
    style G fill:#9FE1CB,stroke:#085041,color:#085041&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;No human is in that loop — by design, not by neglect. The orchestrator never writes code itself; it dispatches a fresh subagent per phase and reads what the gate says. The gate, in turn, never reads the agent's opinion of the work — it reads exit codes, file diffs, and check scripts. The only way a human enters the picture is through the four doors above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1kh647d0ws0jzpo6ty89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1kh647d0ws0jzpo6ty89.png" alt="Illustration: on the left, the small unattended loop of DISPATCH, WORK, GATE and ADVANCE labeled " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Attention is allocated by risk, not by queue
&lt;/h2&gt;

&lt;p&gt;"Not your business until an event fires" is only safe if the events actually fire when risk is high. A cheap task and a dangerous task can't have the same ceremony — the same sequence of phases and gates to run — but you also don't want to personally triage every task to decide which is which.&lt;/p&gt;

&lt;p&gt;So the triage is computed. Every task gets a risk score (roughly 4–12) from five signals, including change size and blast radius. The score maps to a ceremony tier by a max rule: any high signal means full ceremony, all-low means a &lt;em&gt;candidate&lt;/em&gt; for the thin path, anything between means standard. The thin candidate then has to prove it deserves the fast path: a coupling checklist, an explicit statement of the risks being skipped, a phase plan that still includes the verification and acceptance phases (thinning the ceremony never thins verification — only test design and the consistency cross-check may be dropped), and a computed score that agrees with the claim.&lt;/p&gt;

&lt;p&gt;The direction of that check is the whole point. You can always declare &lt;em&gt;more&lt;/em&gt; ceremony than the score requires; declaring &lt;em&gt;less&lt;/em&gt; is fail-closed blocked — the gate exits 1 and the task doesn't move. In attention terms: the fast path exists, but it is earned by evidence, not claimed by confidence. Low-risk work flows through without you; risky work pulls you in at the gates that matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Crash is a pause (with one amendment)
&lt;/h2&gt;

&lt;p&gt;A commenter on the last post put the state-design payoff better than we did: "If the gates write real exit codes and evidence files, interruption becomes a scheduling problem rather than a trust problem. That is the part most agent demos still hand-wave."&lt;/p&gt;

&lt;p&gt;We agree, with one amendment. Versioned state (&lt;code&gt;active-tasks.md&lt;/code&gt;, &lt;code&gt;.state.yaml&lt;/code&gt;) makes the &lt;em&gt;position&lt;/em&gt; auditable — a killed session, a power loss, a context window that hit its ceiling; the next run reads the state file and picks up where the machine left off. It does not make the &lt;em&gt;work&lt;/em&gt; trusted. On resume, the gate re-runs; the position is a scheduling problem, but validity is still a gate problem.&lt;/p&gt;

&lt;p&gt;The retry-counter incident is the cautionary version. The state file was versioned, recovery worked, and the safety net still never fired — because the evidence it read was the agent's own story. Versioning is what lets you stop watching the &lt;em&gt;where&lt;/em&gt;; only evidence quality lets you stop watching the &lt;em&gt;whether&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this honestly breaks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A gate that reads fake evidence liberates nothing.&lt;/strong&gt; It just moves the disaster to a moment when you're not looking. Everything above inherits the evidence ladder from the last post: a rung-2 gate (self-reported artifacts) buying "autonomy" is theater with extra steps. The right to look away is only as real as the rung your gates sit on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;PAUSED&lt;/code&gt; is not free.&lt;/strong&gt; A task that keeps hitting its cap converts one watched agent into one recurring interruption. The cap numbers in the table are informed guesses we're still tuning; the honest data — how often each event actually fires across our 25 tasks — deserves its own post once we've collected it properly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope questions still need you, every time.&lt;/strong&gt; That is a feature — it's the machine admitting which judgments it refuses to make — but it means "look away" is not "gone." You are on call for exactly the classes of questions the protocol won't let the agent answer alone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The general shape
&lt;/h2&gt;

&lt;p&gt;Autonomy for agents is usually argued as a trust question: how much do you believe the model? We think it is an accounting question: how much verified progress exists right now, and what does the state machine do when verification fails? Trust decays with every impressive demo; an accounting of verified steps doesn't.&lt;/p&gt;

&lt;p&gt;The machine advances without you not because you trust it, but because you don't have to — every step it takes alone is a step a gate already accepted, and every step it cannot take alone lands in one of four designed doors, not in your inbox. That is the whole trade: you stop paying attention continuously, and start paying it at decision points, where attention is actually worth something.&lt;/p&gt;

&lt;p&gt;If you want the failure that taught us the trust version doesn't work, that's &lt;a href="https://agateon.com/blog/20260826/post-01-retry-self-authorization" rel="noopener noreferrer"&gt;the postmortem&lt;/a&gt;. The system this post describes is &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;Agateon&lt;/a&gt; (MIT), introduced &lt;a href="https://agateon.com/blog/20260827/post-02-agateon-intro" rel="noopener noreferrer"&gt;here&lt;/a&gt;; the evidence ladder behind the caveat is &lt;a href="https://agateon.com/blog/20260828/post-01-evidence-ladder" rel="noopener noreferrer"&gt;here&lt;/a&gt;. The state machine (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-state-transition.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-state-transition.py&lt;/code&gt;&lt;/a&gt;), scope gate (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-scope-resolved.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-scope-resolved.py&lt;/code&gt;&lt;/a&gt;), and ceremony routing (&lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-routing.py" rel="noopener noreferrer"&gt;&lt;code&gt;check-routing.py&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/agate-risk-score.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate-risk-score.py&lt;/code&gt;&lt;/a&gt;) are all in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate/scripts" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/&lt;/code&gt;&lt;/a&gt;, and the 25 tasks that ran through the loop are in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;&lt;code&gt;agate-workspace/tasks/&lt;/code&gt;&lt;/a&gt; — nothing trimmed for the writeup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Is it done, or does it just look done? A ladder of evidence for AI-agent work</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Fri, 28 Aug 2026 05:00:16 +0000</pubDate>
      <link>https://dev.to/agateon/is-it-done-or-does-it-just-look-done-a-ladder-of-evidence-for-ai-agent-work-4ehg</link>
      <guid>https://dev.to/agateon/is-it-done-or-does-it-just-look-done-a-ladder-of-evidence-for-ai-agent-work-4ehg</guid>
      <description>&lt;h1&gt;
  
  
  Is it done, or does it just look done? A ladder of evidence for AI-agent work
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqt9935aglgzfxqom75mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqt9935aglgzfxqom75mw.png" alt="Cover: a five-rung staircase of evidence. The bottom rung, dashed and coral, is fed by a dashed line from an agent node and shows a question mark — 'self-report'. Higher rungs are solid, rising to a green checkmark on the top rung — 'independent'. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our previous post was a postmortem about a safety net that depended on the agent being honest — and wasn't. The retry counter, a field the agent was supposed to fill, sat empty across four real failures, so the net never fired. This post is the general version of that lesson: a ladder of evidence for deciding when agent work is actually done, and a checklist for catching the self-reports hiding in your own gates.&lt;/p&gt;

&lt;p&gt;By &lt;em&gt;gate&lt;/em&gt; I mean any check that a phase of work must pass before it counts as done — no gate, no progress. The safety net from the postmortem was a gate that read the retry counter; the question this post answers is how to tell a gate that reads real evidence from a gate that reads the agent's own story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — When an agent says a phase is done, the question is never "did it finish talking." It's "what can you point at and re-run?" Evidence ranks on a ladder. The lowest rung — the agent's own account — is worth almost nothing, because it can be omitted, fabricated, or just confidently wrong. The highest rungs — immutable history and independent judgment — are anchored in the world, not in the agent. This post ranks the rungs with real examples from Agateon, names the two ways a rung can lie, and gives a five-question audit you can run on any mechanism that gates agent progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  The question behind "done"
&lt;/h2&gt;

&lt;p&gt;Ask anyone who has run a long task through a coding agent: how do you know it's done? The honest answer is usually "the agent said so, and the diff looks plausible." That is not a quality signal — it's a report from the party under review, and it fails in three distinct ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Omission&lt;/strong&gt; — the agent simply doesn't record what happened. Nothing errors; a field just stays empty. The safety net that depends on that field never fires, and nobody notices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fabrication&lt;/strong&gt; — the agent invents a plausible-looking account of work that didn't happen, or a version of events that flatters it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confident error&lt;/strong&gt; — the agent isn't lying; it's just wrong about itself. LLMs produce confident summaries of what they did that don't match what's actually on disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The common thread: all three live entirely inside the agent's head. The fix is to make "done" mean something that lives &lt;em&gt;outside&lt;/em&gt; the agent's head — evidence you can re-run, that a tool or the world produced, that the agent can't quietly edit away.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ladder of evidence
&lt;/h2&gt;

&lt;p&gt;We've been running tasks through gates long enough to stop asking "is this evidence or not?" and start asking "which rung is this evidence standing on?" Here's the ladder we use, weakest to strongest:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart BT
    S["1 · Self-report — the agent's own account"] --&amp;gt; A["2 · Produced artifacts — documents the agent wrote"]
    A --&amp;gt; T["3 · Tool verdicts — exit code from a real test runner"]
    T --&amp;gt; G["4 · Immutable history — git log, version tags"]
    G --&amp;gt; I["5 · Independent judgment — a reviewer with no context"]
    style S fill:#F5C4B3
    style A fill:#E8E6DE
    style T fill:#9FE1CB
    style G fill:#9FE1CB
    style I fill:#E3E0F7&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  Rung 1 — Self-report
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;"It looks done."&lt;/em&gt; &lt;em&gt;"I ran the tests."&lt;/em&gt; This is the agent's own account of its work, and it's worth nothing by itself, for the three reasons above. The mistake that started this whole project is treating rung 1 as if it were evidence at all.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rung 2 — Produced artifacts
&lt;/h3&gt;

&lt;p&gt;A document the agent wrote, checked &lt;em&gt;structurally&lt;/em&gt;. Agateon's requirements gate is here: it reads the requirements file the agent produced and checks that it contains at least one BDD (Behavior-Driven Development) acceptance criterion and no unresolved &lt;code&gt;NEED_CONFIRM&lt;/code&gt; items. &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-scope-resolved.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/check-scope-resolved.py&lt;/code&gt;&lt;/a&gt; is the same shape — it looks for a &lt;code&gt;[SCOPE_RESOLVED]&lt;/code&gt; marker when the output contains &lt;code&gt;[SCOPE+]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This rung is useful and deeply limited. The artifact exists because the agent made it, and its &lt;em&gt;verdict&lt;/em&gt; is the agent's claim wearing a label. An agent can write a BDD criterion that doesn't match the code, and the gate will pass. Rung 2 proves the document has the right &lt;em&gt;shape&lt;/em&gt;, not the right &lt;em&gt;content&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rung 3 — Tool verdicts
&lt;/h3&gt;

&lt;p&gt;The gate itself executes a real tool and reads what it says. Agateon's test-first gate, &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-tdd-red.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/check-tdd-red.py&lt;/code&gt;&lt;/a&gt;, runs the actual test runner and reads the exit code and output — it can tell "the tests fail because the implementation is missing" (correct red light) from "the tests fail because the test code itself is broken" (a bug in the test). The verification gate runs the declared test commands and checks they exit 0, and &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/agate-gate-p5-count.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/agate-gate-p5-count.py&lt;/code&gt;&lt;/a&gt; requires a real number of declared commands so the phase can't pass by declaring nothing.&lt;/p&gt;

&lt;p&gt;This is the big step up: a tool the agent doesn't control decides. But there's a catch that never goes away — &lt;em&gt;the agent chose which tool and which command&lt;/em&gt;. If the gate runs whatever command the agent declared, and the agent declares &lt;code&gt;echo done&lt;/code&gt;, the gate runs &lt;code&gt;echo done&lt;/code&gt;. Rung 3 is only as strong as the test suite that exists, which the agent wrote earlier in the task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rung 4 — Immutable history
&lt;/h3&gt;

&lt;p&gt;Facts that exist in the world independent of what the agent writes — git history, commit SHAs, version tags. The postmortem's fix lives here: instead of trusting a retry counter the agent fills in, &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-state-transition.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/check-state-transition.py&lt;/code&gt;&lt;/a&gt; reads the commit history, sees that a phase actually moved backward, and compares that against the retry record — a real rollback with an empty counter gets the commit blocked. &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-protocol-consistency.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/check-protocol-consistency.py&lt;/code&gt;&lt;/a&gt; does the same trick for releases: its CHECK 7 runs &lt;code&gt;git describe --tags&lt;/code&gt; and compares the README version badge to the actual latest tag, so an agent can't make a release look current by editing a README.&lt;/p&gt;

&lt;p&gt;This is the highest rung for "did X happen" questions, because the evidence is already in version control before the agent touches anything, and it can't be omitted without the omission being visible too. It's also the narrowest — it only knows what git knows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rung 5 — Independent judgment
&lt;/h3&gt;

&lt;p&gt;For the questions no command can answer — &lt;em&gt;is this design right? is this worth shipping?&lt;/em&gt; — the strongest check is a reviewer with no context of the work. This post goes through one before it's published: an independent reviewer with no authorship context checks it against a written standard. Agateon uses the same shape for the work a command can't judge, and we're working on making independent judgment a first-class gate rather than a manual step (&lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks/TAG0020-independent-judge" rel="noopener noreferrer"&gt;&lt;code&gt;TAG0020-independent-judge&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Rung 5 isn't automated, which is exactly the point: it's the one rung designed to be a person (or a fresh agent) whose judgment wasn't shaped by having done the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two ways a rung lies
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Omission
&lt;/h3&gt;

&lt;p&gt;A mechanism anchored to rung 1 or 2 can be silently disabled by an empty field. The postmortem case is the clean example: a retry counter that triggers a human pause, written by the agent, left empty across four real failures. Nothing errored. The mechanism simply never fired, and the safety net wasn't there. The fix isn't "make the agent log more carefully" — it's move the trigger up to rung 4, where the fact already exists in git whether the agent writes it or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Theater
&lt;/h3&gt;

&lt;p&gt;The subtler failure: evidence that &lt;em&gt;looks&lt;/em&gt; like a higher rung but is actually the agent's own report wearing a costume. A gate that checks "did the agent write a plausible-looking report" is theater — it's rung 1 in a rung 2 disguise. The same disease can infect rung 3: if the agent picks the command the gate runs, "the gate runs a real command" quietly becomes "the gate runs whatever the agent declared." The check is only real if the &lt;em&gt;declaration&lt;/em&gt; is also gated — by requiring a real number of commands, by running adversarial tests that try to declare a no-op, by having a human look at what was declared.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ezalcmocg2nnvv1tjot.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ezalcmocg2nnvv1tjot.png" alt="Illustration: a gate node stamps PASS onto a report document that was written by an agent and handed over with a dashed line — the 'evidence' the gate checked came from the author being reviewed. Caption: " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The rule we apply: for every gate, trace the evidence to its author. If the author is the agent being gated, you're on rung 1 or 2, no matter how official the label looks.&lt;/p&gt;

&lt;h2&gt;
  
  
  The audit checklist
&lt;/h2&gt;

&lt;p&gt;If you're building agent tooling, run these five questions against every mechanism that gates progress, deployment, or safety:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;th&gt;How to check&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;What exactly does this mechanism check?&lt;/td&gt;
&lt;td&gt;"Checks that work is done" hides which evidence it reads.&lt;/td&gt;
&lt;td&gt;Write down the exact file, field, command, exit code.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Who produced that evidence — the agent, a tool, or the world?&lt;/td&gt;
&lt;td&gt;The author of the evidence is the trust boundary.&lt;/td&gt;
&lt;td&gt;Trace it: who wrote this file, set this field, owns this log?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Could the agent omit it without being caught?&lt;/td&gt;
&lt;td&gt;Omission fails silently — the mechanism just never fires.&lt;/td&gt;
&lt;td&gt;Could the agent finish the phase with this empty or absent and still pass?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Could the agent fake it without being caught?&lt;/td&gt;
&lt;td&gt;A plausible-looking fake is theater.&lt;/td&gt;
&lt;td&gt;Would a fabricated-but-plausible version pass the check?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Is this evidence actually correlated with what you're claiming?&lt;/td&gt;
&lt;td&gt;"Tests pass" ≠ "this is what the user wanted."&lt;/td&gt;
&lt;td&gt;If this passes, is the claim it's supposed to support actually supported?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The point of question 5 is worth sitting with, because it's where most "verification" setups quietly give up: a rung-3 test suite proves the code does what the &lt;em&gt;tests&lt;/em&gt; say, and the tests were written by the same agent that wrote the code. That's real progress over rung 1 — but it's not proof the product is right. That gap is what rung 5 and humans are for, and pretending otherwise is how "verified" ships become "it seemed fine at the time" incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where we honestly sit
&lt;/h2&gt;

&lt;p&gt;Applying the ladder to our own gates, so you can see exactly where the trust is and isn't:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Gate&lt;/th&gt;
&lt;th&gt;Rung&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;What's still open&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Requirements&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Checks the doc has ≥1 BDD criterion, no unresolved &lt;code&gt;NEED_CONFIRM&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;An agent can write a criterion that doesn't match the code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Test-first (P3)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Runs the real test runner; distinguishes test bugs from missing implementation&lt;/td&gt;
&lt;td&gt;Only as good as the tests the agent wrote&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification (P5)&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Runs declared test commands, checks exit 0, requires a real command count&lt;/td&gt;
&lt;td&gt;The agent declares the commands; a no-op declaration is possible, mitigated by adversarial tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State &amp;amp; retry&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Blocks illegal phase transitions; retry detection anchored to git history&lt;/td&gt;
&lt;td&gt;Only knows what git knows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release consistency&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;README version badge must match the actual latest git tag&lt;/td&gt;
&lt;td&gt;Can't catch a wrong-but-consistent version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Design quality&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;A human or independent agent reviews what a command can't judge&lt;/td&gt;
&lt;td&gt;Still partly manual; making it first-class is &lt;code&gt;TAG0020&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;And the honest caveat on top: the ladder ranks &lt;em&gt;progress claims&lt;/em&gt;, not &lt;em&gt;product quality&lt;/em&gt;. A task can pass every gate and still ship something nobody wants. We don't claim our gates sit at the top of the ladder. We claim the ladder makes it visible which rung each gate stands on — and that visibility is the actual safety feature, because a gate you know is on rung 2 gets a human's attention, while a gate you &lt;em&gt;believe&lt;/em&gt; is on rung 4 gets trusted.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general shape of the problem
&lt;/h2&gt;

&lt;p&gt;If you're building anything where an AI agent's output feeds a gate, deploy, or safety mechanism, this is the five-minute audit: ask who produced the evidence, whether the agent could omit or fake it, and whether it actually correlates with what you're claiming. The cheapest win is usually finding the rung-2 checks pretending to be rung-3, and the most valuable is anchoring anything safety-related to rung 4 — a fact already in version control that the agent can't quietly leave out.&lt;/p&gt;

&lt;p&gt;That's the idea behind &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;Agateon&lt;/a&gt; (MIT): make "done" mean something you can re-run, not something you were told. The previous posts are the failure that started it (&lt;a href="https://agateon.com/blog/20260826/post-01-retry-self-authorization" rel="noopener noreferrer"&gt;our AI safety net depended on the agent being honest. It wasn't.&lt;/a&gt;) and the project's shape (&lt;a href="https://agateon.com/blog/20260827/post-02-agateon-intro" rel="noopener noreferrer"&gt;verify AI agents the way a build system verifies a compiler&lt;/a&gt;). The gates named above are all in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate/scripts" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/&lt;/code&gt;&lt;/a&gt;, and twenty-five tasks of history are in &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;&lt;code&gt;agate-workspace/tasks/&lt;/code&gt;&lt;/a&gt; — nothing trimmed for the writeup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Agateon: verify AI agents the way a build system verifies a compiler</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Thu, 27 Aug 2026 01:12:48 +0000</pubDate>
      <link>https://dev.to/agateon/agateon-verify-ai-agents-the-way-a-build-system-verifies-a-compiler-1a5d</link>
      <guid>https://dev.to/agateon/agateon-verify-ai-agents-the-way-a-build-system-verifies-a-compiler-1a5d</guid>
      <description>&lt;h1&gt;
  
  
  Agateon: verify AI agents the way a build system verifies a compiler
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dwh7b2rff6uplwpne45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8dwh7b2rff6uplwpne45.png" alt="Cover: an agent node on the left feeds work into a teal gate; the gate checks evidence — git log, test exit code, files on disk — and a checkmark lets the work advance to the next phase. Title reads " width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've run a long task through an AI coding agent, you know the quality signal most setups leave you with: &lt;em&gt;it looks done&lt;/em&gt;. Not "the test suite is green and the typechecker is clean" — just that the agent says so, and the diff seems plausible. We spent months building the alternative, and this post is about what it is and why it's shaped the way it is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; — Agateon is an open-source orchestration protocol for software-engineering tasks run by AI agents. There's no runtime, no daemon, no build step: it's a set of Markdown protocol files plus gate-check scripts. Work moves through eight phases, and after every phase an objective gate — a test runner's exit code, a typechecker, a git log — must pass before the state machine may advance. All state lives in version-controlled Markdown. The orchestrator agent never writes code; it dispatches a dedicated subagent per phase and checks their output against evidence. Progress can't advance on "it looks done" — only on things you can point at and re-run.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem: "it looks done" is not a quality signal
&lt;/h2&gt;

&lt;p&gt;LLM agents are genuinely good at software work in a single burst: scaffold a repo, fix a lint error, write a test for a known case. The trouble is long tasks. Context gets polluted. Subagents drift from the original brief. And as a task stretches across hours and dozens of turns, the only signal most setups give you is the agent's own summary of what it did.&lt;/p&gt;

&lt;p&gt;That's the failure mode this project exists to close. A build system doesn't trust a compiler's claim that it produced correct code — it checks the exit status, runs the test suite, typechecks the output. We wanted the same shape for agents: &lt;strong&gt;you don't trust the output, you verify it through gates.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: treat the agent like a compiler
&lt;/h2&gt;

&lt;p&gt;The core claim, stated plainly: an AI agent working on a codebase should be treated like a compiler feeding into a build. You don't ask it to be more honest. You don't read its diary. You make the mechanism refuse to advance unless objective evidence says the phase is done.&lt;/p&gt;

&lt;p&gt;That reframing changes a lot of defaults. "Done" stops meaning "the agent finished talking" and starts meaning "the gate command exited 0 and the evidence file is non-empty."&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phases and gates
&lt;/h3&gt;

&lt;p&gt;A task moves through a fixed state machine: P0 brief → P1 requirements → P2 design → P3 test-first → P4 implementation → P5 verification → P6 acceptance → P7 consistency → P8 release → READY → DONE.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    P0[P0 brief] --&amp;gt; P1[P1 requirements]
    P1 --&amp;gt; P2[P2 design]
    P2 --&amp;gt; P3[P3 test-first]
    P3 --&amp;gt; P4[P4 implement]
    P4 --&amp;gt; P5[P5 verify]
    P5 --&amp;gt; P6[P6 accept]
    P6 --&amp;gt; P7[P7 consistency]
    P7 --&amp;gt; P8[P8 release]
    P8 --&amp;gt; D[DONE]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Between every pair sits a gate, and the gate's job is to run evidence the agent didn't write about itself. For a verification phase, that's the real test command — the gate script executes it and looks at the exit code. For requirements, it's a structural check: does the document contain at least one BDD (behavior-driven-development) acceptance criterion, are there unresolved &lt;code&gt;NEED_CONFIRM&lt;/code&gt; items? For acceptance, it checks that the evidence files are non-empty and the gate commands all exited 0.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Phase work] --&amp;gt; G{Gate: run evidence}
    G --&amp;gt;|pass: exit 0, evidence holds| N[Persist to Markdown, advance]
    G --&amp;gt;|fail| R[Redo the phase]
    R --&amp;gt; A&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;If a gate fails, the phase is redone and the retry is recorded. This is where a recent postmortem — &lt;a href="https://dev.to/agateon/our-ai-safety-net-depended-on-the-agent-being-honest-it-wasnt-3k64"&gt;our AI safety net depended on the agent being honest. It wasn't.&lt;/a&gt; — gets relevant: we found the retry counter itself could be left empty by an agent, silently disabling the whole safety mechanism. The fix anchored that check to git history instead of the agent's own bookkeeping. The honest takeaway: the gates are only as strong as the evidence they're anchored to, and we're always looking for places where the "evidence" is really another self-report in disguise.&lt;/p&gt;

&lt;h3&gt;
  
  
  State you can see
&lt;/h3&gt;

&lt;p&gt;Every phase result is written to version-controlled Markdown (&lt;code&gt;active-tasks.md&lt;/code&gt;, &lt;code&gt;.state.yaml&lt;/code&gt;). This is a deliberate choice, and it buys two things. First, a crash — a killed session, a power loss, a model context that hit its ceiling — is a pause, not a restart: the next run reads the state file and picks up where the machine left off. Second, a human (or another agent) can audit what happened by reading the files, not by trusting the summary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gwaam4tdz4soqzqq1at.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gwaam4tdz4soqzqq1at.png" alt="Illustration: a task moves through phases P4 to P5 and is interrupted by a lightning bolt at the gate; below, a Markdown state-file card stays intact with the phase persisted, and an arrow resumes the work from the saved state" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Roles are separated
&lt;/h3&gt;

&lt;p&gt;The orchestrator agent never writes code. Each phase is dispatched to a dedicated subagent — a requirements analyst, an architect, a test designer, an implementer, a verifier — and their output is handed back through the gate. This keeps the orchestrator's context clean (it's a dispatcher, not a participant) and makes the review genuinely independent of the work it's reviewing. Same reason you don't let the author be the only reviewer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does it actually work? We make it eat its own food.
&lt;/h2&gt;

&lt;p&gt;Agateon is built with Agateon. The repository's own task history — dozens of tasks, from the original bootstrap to recent mechanism fixes — was produced through this same state machine, and it's all in the repo for anyone to read: &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks" rel="noopener noreferrer"&gt;&lt;code&gt;agate-workspace/tasks/&lt;/code&gt;&lt;/a&gt;. The postmortem linked above is a real example of the loop working: an audit found a design hole, the fix went through phases with gates, adversarial tests were run against a real git repository, and the task record shows all of it.&lt;/p&gt;

&lt;p&gt;We also try to break our own gates. The verification phases run adversarial tests — rollbacks, missing records, half-finished evidence — and check that the gate blocks what it's supposed to block and passes what it's supposed to pass. When a gate can be fooled by something an agent can simply omit, that's a bug, and it goes back into the machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it is not (read this before trying it)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It's not a magic agent.&lt;/strong&gt; It's a protocol and a set of scripts. You bring the coding agent; Agateon shapes how it's orchestrated and checked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's not a runtime or a service.&lt;/strong&gt; There's nothing to deploy. Your agent just needs to read Markdown and run commands. Setup is a symlink plus a couple of git hooks: &lt;code&gt;curl -sSL https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It doesn't make gates immune to bad design.&lt;/strong&gt; A gate that checks "did the agent write a plausible-looking report" is theater; a gate that runs a real test suite is not. The difference is entirely in what you choose as evidence, and choosing well is a design problem, not a tooling problem.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It's early and honest about it.&lt;/strong&gt; The phase machine, the gate scripts, and the docs are all live in an MIT-licensed repository at v0.64.0, but "early" isn't a euphemism for "stable": the right expectation is that you audit the gates you depend on.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  If you're building agent tooling, check this
&lt;/h2&gt;

&lt;p&gt;The lesson generalizes beyond this project: whenever an agent's own report feeds a safety or progress mechanism, ask whether that mechanism depends on evidence the agent could simply omit. Ours did — the retry counter that triggered a human pause could be left empty, silently. The fix wasn't "make the agent more careful." It was "stop needing the agent to be careful about the parts that matter most," and anchor the check to something that exists independent of what the agent chooses to report.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;The repository is &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt; (MIT). One-line install, no infrastructure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/randomgitsrc/agateon/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you've ever shipped a long agent task on "it looks done" and felt uneasy about it, this is the project for you. The honest summary of what Agateon does: it makes "done" mean something you can re-run, not something you were told.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Our AI Safety Net Depended on the Agent Being Honest. It Wasn't.</title>
      <dc:creator>Agateon</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:51:19 +0000</pubDate>
      <link>https://dev.to/agateon/our-ai-safety-net-depended-on-the-agent-being-honest-it-wasnt-3k64</link>
      <guid>https://dev.to/agateon/our-ai-safety-net-depended-on-the-agent-being-honest-it-wasnt-3k64</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbdgwgjaay31vjghms79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzbdgwgjaay31vjghms79.png" alt="Cover: a row of gate checkpoints, most passed green, one flagged with a question mark fed by a dashed " width="800" height="513"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agateon is a protocol for running software-engineering work through AI agents without trusting their word for it. Every phase of work — requirements, design, implementation, testing, release — has to pass an objective gate before it counts as done. No gate, no progress. That's the entire premise.&lt;/p&gt;

&lt;p&gt;A few days ago, a routine audit found a hole in one of our own gates. Not a logic bug. A &lt;em&gt;design&lt;/em&gt; hole — the kind where the mechanism does exactly what it was told to do, and that's the problem. Here's what happened, how we found it, and how we fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mechanism: fail enough times, and a human has to look
&lt;/h2&gt;

&lt;p&gt;Agents get stuck. They misread a requirement, a test fails for a reason they don't understand, a sub-agent comes back with nothing useful. Agateon's answer is simple: track retries per phase, and once a phase has failed too many times, stop automation entirely and force a human decision.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;stateDiagram-v2
    [*] --&amp;gt; Phase: agent starts work
    Phase --&amp;gt; GateCheck: submit for gate check
    GateCheck --&amp;gt; NextPhase: pass
    GateCheck --&amp;gt; RetryOrPause: fail
    RetryOrPause --&amp;gt; Phase: retries below limit, try again
    RetryOrPause --&amp;gt; PAUSED: retries exhausted
    PAUSED --&amp;gt; [*]: human decides
    NextPhase --&amp;gt; [*]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Nothing exotic. It's the same idea as a circuit breaker: enough consecutive failures, and the system stops trying to route around the problem itself and hands control back to a person.&lt;/p&gt;

&lt;p&gt;The part that matters is &lt;em&gt;how&lt;/em&gt; the system knows a retry happened: the agent records it. Every time a phase gets rejected and redone, the retry is supposed to be written into that task's state file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the audit found
&lt;/h2&gt;

&lt;p&gt;An independent review of four recently completed tasks checked whether the retry records actually matched what had happened. They didn't.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    subgraph Real["What actually happened, per git history"]
        A1["Review rejected a design,&amp;lt;br/&amp;gt;sent back for rework"]
        A2["Verification failed,&amp;lt;br/&amp;gt;task rolled back a phase"]
        A3["A sub-agent returned&amp;lt;br/&amp;gt;nothing useful, redispatched"]
    end
    subgraph Recorded["What the state file recorded"]
        B1["retries: (empty)"]
    end
    A1 -.-&amp;gt; B1
    A2 -.-&amp;gt; B1
    A3 -.-&amp;gt; B1&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;All four tasks — real rejections, a real phase rollback, a real empty-handed sub-agent — and the retry counter for every one of them read empty. As if none of it had happened.&lt;/p&gt;

&lt;p&gt;The retry-limit mechanism was never triggered by any of this, because the mechanism has no way to see the world except through what gets written into that field. If the field says nothing happened, as far as the safety net is concerned, nothing happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this isn't just a missed edge case
&lt;/h2&gt;

&lt;p&gt;The uncomfortable part isn't that some retries went unlogged. It's &lt;em&gt;what kind&lt;/em&gt; of gap this is.&lt;/p&gt;

&lt;p&gt;Agateon's whole reason for existing is that you shouldn't trust an AI agent's account of its own work — you verify it against evidence instead. The retry-limit mechanism is supposed to be one of the things doing that verifying. But its own trigger condition depended entirely on the same untrusted party self-reporting honestly. The guard was watching for the fox, using information the fox was free to leave out.&lt;/p&gt;

&lt;p&gt;That's not a bug you find by writing more test cases for the happy path. It's a hole in the design's trust model — the mechanism could be silently no-op'd, not through malice, just through an agent that got busy, forgot, or never wired up the bookkeeping. And it fails &lt;em&gt;silently&lt;/em&gt;: no error, no crash, just a safety net that was never actually there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6opr3hazjdrtbxoxr8h7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6opr3hazjdrtbxoxr8h7.png" alt="Illustration: an agent icon connected to a shield icon only by a dashed line reading " width="800" height="427"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;sequenceDiagram
    participant Agent
    participant StateFile as State File
    participant Gate as Retry-Limit Gate

    Note over Agent,Gate: What was supposed to happen
    Agent-&amp;gt;&amp;gt;StateFile: record retry
    StateFile-&amp;gt;&amp;gt;Gate: retries for phase = 3
    Gate-&amp;gt;&amp;gt;Agent: PAUSED, human needed

    Note over Agent,Gate: What could actually happen
    Agent--xStateFile: retry never recorded
    StateFile-&amp;gt;&amp;gt;Gate: retries for phase = empty
    Gate-&amp;gt;&amp;gt;Agent: continue as normal&lt;/code&gt;&lt;/pre&gt;



&lt;h2&gt;
  
  
  The fix: stop trusting the field, check the evidence instead
&lt;/h2&gt;

&lt;p&gt;The fix doesn't ask the agent to be more careful about logging. It stops relying on the log at all for the part that matters most, and checks something the agent can't quietly leave out: the git history.&lt;/p&gt;

&lt;p&gt;A real phase rollback — say, verification failing and the task moving backward a phase — is a fact that's already sitting in version control the moment it happens, independent of anything the agent writes anywhere. So the fix compares the two: if the commit history shows a real rollback but the retry counter for that phase didn't grow, the commit is blocked.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3k5glenhyfa3nh4m2w7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3k5glenhyfa3nh4m2w7x.png" alt="Illustration: before and after comparison. Before, an agent connects to a gate only through a dashed self-report line and the gate shows a question mark. After, the same self-report line is grayed out and a solid line from git history commits feeds the gate, which now shows a checkmark" width="800" height="462"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[Commit staged] --&amp;gt; B{Did phase move backward?}
    B -- No --&amp;gt; Z[Allow]
    B -- Yes --&amp;gt; C{Did retries counter&amp;lt;br/&amp;gt;for that phase increase?}
    C -- Yes --&amp;gt; Z
    C -- No --&amp;gt; D["Block commit&amp;lt;br/&amp;gt;retry happened, wasn't recorded"]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;We deliberately kept this narrow. There are softer signals too — things like a review-rejection file existing on disk, or a sub-agent's output containing the phrases that usually mean "came back empty." Those are useful hints, but they're pattern-matching, and pattern-matching has false positives. So those only produce a warning, not a block. The one check that hard-blocks a commit is built on a fact that can't be fabricated by omission: a phase number that actually moved backward in git history. Confidence dictates enforcement strength — we don't block on evidence we don't fully trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Did it actually work? We tried to break it.
&lt;/h2&gt;

&lt;p&gt;We didn't take the fix's word for it either. Two adversarial tests, both against a real git repository:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Attack:&lt;/strong&gt; stage a phase rollback with an empty retry record — exactly the scenario the audit found.&lt;br&gt;
&lt;strong&gt;Result:&lt;/strong&gt; commit blocked, with a message naming the exact phase and the exact missing record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control:&lt;/strong&gt; the same rollback, this time with the retry properly recorded.&lt;br&gt;
&lt;strong&gt;Result:&lt;/strong&gt; commit allowed.&lt;/p&gt;

&lt;p&gt;One more thing worth mentioning, because it's the kind of detail that's easy to leave out of a postmortem and shouldn't be: an earlier version of this fix had a guard condition that, on inspection, would have made it unable to catch the exact failure mode that motivated it in the first place — the original evidence was tasks where a retry had &lt;em&gt;never&lt;/em&gt; once been recorded, and the guard assumed there'd already been a prior record to compare against. It was caught in review before it shipped, not after. We're mentioning it because "the fix for the self-reporting problem needed a second pair of eyes to catch a flaw in its own logic" is a good demonstration of why we don't rely on any single check, including this one, working perfectly on the first attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's still open
&lt;/h2&gt;

&lt;p&gt;The heuristic checks — the ones that only warn instead of block — can still be evaded by an agent that's a bit more careful about not leaving the usual pattern-matching signals behind. We know this. We're not claiming the retry-tracking problem is now airtight; we're claiming the one path that was silently, structurally guaranteed to fail is no longer silent, and everything else stays exactly as uncertain as it honestly is.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general shape of the problem
&lt;/h2&gt;

&lt;p&gt;If you're building anything where an AI agent's own report is part of what triggers a safety mechanism, this is worth checking for directly: does the trigger condition depend on evidence the agent could simply omit? If yes, that's not a hypothetical risk. Ours sat there, unnoticed, across four completed tasks, doing nothing, until an audit went looking for it on purpose.&lt;/p&gt;

&lt;p&gt;The fix isn't "make the agent more careful." It's "stop needing the agent to be careful about the parts that matter most" — anchor the check to something that exists independent of what the agent chooses to report.&lt;/p&gt;

&lt;p&gt;That's the whole idea behind Agateon: &lt;a href="https://github.com/randomgitsrc/agateon" rel="noopener noreferrer"&gt;github.com/randomgitsrc/agateon&lt;/a&gt;. The fix described here lives at &lt;a href="https://github.com/randomgitsrc/agateon/blob/main/agate/scripts/check-state-transition.py" rel="noopener noreferrer"&gt;&lt;code&gt;agate/scripts/check-state-transition.py&lt;/code&gt;&lt;/a&gt;, and the task that shipped it is &lt;a href="https://github.com/randomgitsrc/agateon/tree/main/agate-workspace/tasks/TAG0023-mechanism-checks" rel="noopener noreferrer"&gt;&lt;code&gt;TAG0023-mechanism-checks&lt;/code&gt;&lt;/a&gt; — full history included, nothing trimmed for the writeup.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>llm</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
