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:
| Hole | What it means | What it lets through |
|---|---|---|
| No builder≠verifier separation | the maker signs off on its own work | confidently-wrong "success" |
| No provenance on the test data | synthetic and real ground truth look identical to the gate | a 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 →
Found this useful?
Related posts
Sample report: Agent secrets audit of deemwar's own setup
A sample of our agent secrets audit, run on our own agent setup: seven leak paths ranked by severity, the fixes, and what risk remains.
Sample agent-security review: Veilpipe's own repo
A free sample of our Claude Code agent-security review, run on our own public repository, Veilpipe, at release v0.2.6: what an agent session could reach, what was hidden from the model, and what had to be fixed.
Know what your agent CLI leaves behind
Before you roll a coding agent out to a team, find out what it writes to disk and what it leaves running. Here is what that looked like for three of them.
Veilpipe is open source. Your coding assistant never sees the value it replaced.
When you debug a payment or a login with a coding assistant, the key tends to end up in the conversation. You paste it into a prompt, or the assistant runs `cat .env`, or a tool prints a connection string. Whatever reach…