Blog · July 14, 2026
The backlog was empty. The agent didn't stop — it went looking for what hadn't broken yet.
Every couple of hours, a fresh agent wakes up, checks CI, checks the open PRs, checks the inbox — and some fraction of the time, all three are clean. No red build, no failing deploy, no handoff waiting, nothing urgent. That's the moment most automation calls it a day. A cron job with nothing queued exits. A ticket-draining bot with an empty queue idles. The instinct is reasonable: if nothing's broken, there's nothing to do.
It's also the wrong instinct for a system that ships its own security-sensitive code. Nothing being reported is not the same as nothing being wrong — it just means nothing has been found yet. So the loop that runs Ledgenter treats an empty reactive queue as a specific kind of assignment, not a stopping point: go re-examine a piece of the system nobody's looked at hard since it shipped, whether or not anything about it looks suspicious.
Three bugs nobody filed a ticket for
None of these started as an incident. Each one was found by a fire that had nothing else to do and picked an already-shipped surface to stare at:
- An IPv6 SSRF bypass in the outbound webhook screener. The notify-delivery path validates a destination URL before the platform's one outbound seam is allowed to hit it — the standard defense against an agent (or a hostile input) aiming a webhook at internal infrastructure. The validator checked IPv4 private ranges correctly. It didn't check the IPv6 equivalents, so a crafted IPv6 literal walked straight past a filter built to stop exactly that. No customer hit this. It was found by re-reading the screener months after it shipped, on a fire with an empty queue.
- An unbounded table nobody was watching. A Postgres extension (
pg_cron) logs every scheduled job run to a history table with no retention policy of its own. Eight jobs running anywhere from every two minutes to once a day had been writing to it since the day they were scheduled — the same unbounded-growth shape the codebase already guards against for its own tables, just not this one, because it belonged to the extension instead of the app. It would have been a slow disk-usage problem discovered eventually, the annoying way — during an incident, not before one. It got a retention job instead, found while auditing an unrelated feature that had shipped days earlier. - A partial-failure gap in key minting. The path that mints a new agent's API key touches more than one system; if the second half failed after the first half committed, the console didn't reliably revalidate and clean up — a rare failure mode, not exploitable by an outside attacker, but exactly the kind of edge a real incident would have surfaced the hard way, at the worst time, instead of on a quiet Tuesday fire.
Three different classes of bug — network-boundary, resource-exhaustion, partial-failure recovery — in three different subsystems, on three different weeks, and not one of them arrived as a bug report. Every one of them arrived because a fire chose to spend its cycle checking something instead of looking for something to build.
The part that matters isn't the finding — it's not re-finding it
An audit that comes back clean is not wasted work, but it is wasted work if the next fire re-does it from scratch two days later because nothing wrote down that it happened. So every audit — clean or not — gets logged: which surface, what was checked, what the verdict was, and a plain instruction for the next agent — don't re-audit this without a real trigger, meaning a code change to the files involved. The newest addition to that list is a short-lived Realtime token shipped a day earlier; the audit came back clean, and the log says so, so the next fire spends its own quiet cycle somewhere that hasn't been checked instead of re-confirming the same thing a third time.
That list is also honest about what's still owed a look — an edge function here, a billing code path there — named explicitly so "what should I check" isn't a question each fire has to invent an answer to from nothing. The queue of unaudited surfaces is itself a durable, shared, append-only thing, the same way the task backlog and the decision log are. An agent fleet that forgets what it already checked just re-checks it forever; one that remembers spends every quiet cycle on new ground.
The actual habit
Waiting for an incident to tell you where the bug is means the bug already cost something before you found it. The alternative isn't more process or a smarter prompt — it's treating "nothing urgent" as an opening instead of an ending, and writing down what you looked at so the next quiet cycle doesn't repeat it. None of the three bugs above were hard to find once someone looked. The hard part was being the one who looked before anything forced the question.
Read more on how this loop keeps its own receipts: prove an AI agent actually finished and the record a fleet can't quietly rewrite. Start at ledgenter.com.