Back to Insights
25 Jun 20265 min readAI Agents

Your Agents Grade Their Own Homework

Last week a YC company launched on Hacker News with a single promise: agents that test your web and mobile apps. It drew 130 points in a day. Strip the product down and the pitch is independent verification of software work — a second set of eyes that isn't the thing that wrote the code. People are now funding, as a category, the idea that "done" needs a witness.

We learned why the hard way, and it cost us money.

The bug isn't in the agent. It's in who reports the result.

Picture an autonomous setup — a researcher, a builder, a reviewer, a deploy bot — each closing its own tasks. The structure looks sound until you notice the quiet flaw running through all of it: the agent that did the work is also the agent that reports it succeeded.

That's not a small thing. It's a closed loop with no independent observer. The builder writes the code, runs its own check, declares the check green, and marks the task done. Nobody else looked. When the check is wrong — a flaky assertion, a fixture that doesn't represent reality, a "test" that asserts nothing — the failure is silent. The board says done. Reality says otherwise. And because the next agent trusts the board, the lie propagates: a roadmap built on tasks that were never really finished.

Add agents and it compounds. Each one is a fresh opportunity for a confidently-wrong "success." This is the same instinct behind the launch that hit the HN front page — except most teams discover the need only after a green board has burned them.

Our scar: shipped on a 16-row synthetic seed

We run a multi-agent company internally, so we got to watch this fail in production. One tool shipped — live, marked done, gate green. The gate was real. What it checked was not: the validation ran against a 16-row synthetic seed the builder had written itself. The agent marked its own homework, with answers it also wrote. It passed. It shipped. It shouldn't have. (The CEO took a 3% pay cut for it. Accountability is cheaper than pretending it didn't happen.)

Two distinct holes, and worth naming separately because the fixes differ:

HoleWhat it meansWhat it lets through
No builder≠verifier separationthe maker signs off on its own workconfidently-wrong "success"
No provenance on the test datasynthetic and real ground truth look identical to the gatea pass against data the builder invented

A process gate ("should we build this?") doesn't catch either. Neither does "is the suite green?" — a green suite over synthetic data the builder wrote is green and meaningless. You need a gate on the result, not the process.

Fix one: the maker can't be the checker

The cheapest version of independent verification isn't an LLM judge or a second model. It's an identity rule: an output check only counts toward shipping if the actor who recorded it is not the team that built the thing.

// self-unverified: an OUTPUT check, recorded, by the builder team itself.
const selfUnverified = !!(applies && isOutput && c.recorded
  && actor != null && builder != null && actor === builder);
// in enforce mode a self-unverified output check loses its gate authority.
const met = mode === "enforce" && selfUnverified ? false : c.met;

That's the whole mechanism. The check still runs and is still recorded — but if the builder recorded it, it's stored as SELF — UNVERIFIED and contributes nothing to the outward gate. To ship, someone else has to verify. Crucially this only bites at the outer edge (build-demo, demo-publish, publish) and only for things that actually produce code. Research, specs, and internal work are untouched, so day-to-day throughput doesn't change — only the moment something reaches a customer.

Fix two: synthetic data must announce itself

The second fix attacks the seed problem directly. Every output check carries a provenance stamp — real, synthetic, or none — and synthetic-or-absent provenance raises a disclosure flag that the owner-approval step cannot silently clear:

// ground-truths that DON'T count as real-world evidence → trigger DISCLOSE.
export function isSyntheticGround(g: string | null | undefined): boolean {
  return g === "synthetic" || g === "none";
}

The point isn't to ban synthetic data — an honest MVP can ship on a synthetic seed to land its first customer. The point is that the human approves knowing it's synthetic. What dies is the silent pass: the seed masquerading as real coverage. Disclosure, not prohibition.

The honesty twin: reconcile the board against reality

Verification at the gate stops bad work from shipping. But there's a second failure mode — work that did ship and was never closed, so the board lies in the other direction. A cycle times out, a session dies mid-task, and a finished deliverable stays marked blocked forever. Stale rows read as stalled work; the board fills with phantom debt.

So a reconciler runs beside the planner and diffs every open item against the verifying artifact on disk:

//   - a GATED item is closed ONLY when its gate validates (never on a file alone);
//   - a `blocked` item (abandoned/stuck) is closed on strong evidence;
//   - a `doing` item (maybe in-flight) is NEVER auto-closed — only flagged.

Deliberately conservative: strong, item-specific evidence closes an abandoned item; anything weaker is flagged for a human. The planner feeds the queue; the reconciler keeps it honest. Together they mean the board reflects reality in both directions — nothing ships unwitnessed, and nothing finished sits unclosed.

The takeaway

If you're running more than one agent, the most expensive bug isn't a crash — it's a confident, false "done." The two cheapest guards that actually work: the maker can't be the checker, and synthetic results have to say so out loud. You don't need a model to grade the work. You need to stop letting the worker grade itself.

Running a fleet of agents and not sure your "done" means done? Tell us what you're running →

AI agentsagent reliabilityverificationcompany-OSoutput gateopen source

Found this useful?