Kuba Opoczka Signature verifier Auditable CV
Notes  /  25 July 2026

Three bugs an AI wrote that didn't crash.

I shipped a browser extension built with AI coding agents. An independent review pass over the finished code found three real defects. None of them threw an exception. None of them failed a test. All three had already shipped. What they have in common turned out to be the useful part.

First, the uninteresting caveat: I'm early career and self-taught, and I direct AI agents to write most of my code. That's not a confession, it's the setup; the whole point of what follows is what happens after the agent hands you something that looks finished.

A crash is a gift. It tells you where to look. Every bug below did the opposite: the function was called, it returned a plausible value, and execution continued. If you were watching the console you saw nothing at all.

01

A one-token error that silently truncated every long list

Recursion invariant · fix was 4 characters

The extension walks React's internal Fiber tree to find components. A tree walk carries a depth counter with a cap, so a pathological tree can't hang the page. Standard.

// what the agent wrote
walk(fiber.child,   depth + 1, out);
walk(fiber.sibling, depth + 1, out);

// what it should have been
walk(fiber.child,   depth + 1, out);
walk(fiber.sibling, depth,     out);

Children are one level deeper. Siblings are not. Incrementing depth on sibling traversal means depth stops measuring depth and starts counting everything. So a flat list of forty items reads as forty levels deep and hits a cap meant for pathological nesting.

A forty-item list is not an edge case. It's a table, a dropdown, a feed: the single most common shape in a React app. The walker returned successfully every time, with the tail of your component tree quietly missing.

Why no test caught it My fixtures were small. Every test tree had a handful of siblings, so every test passed. The bug only exists at a scale I hadn't thought to write a fixture for. It produced no error at that scale either, just a shorter list than reality.
02

Assigning to a global that another extension already owns

Shared namespace · failure depends on load order

React exposes a hook on window.__REACT_DEVTOOLS_GLOBAL_HOOK__. It's how React DevTools works. It's also how my extension needed to work.

// what the agent wrote
window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = { /* mine */ };

// what it should have been: extend what is already there
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__ || { /* mine */ };

Assignment, not extension. If the real React DevTools loaded first, I destroyed it. If it loaded second, it destroyed me. And injection order between two extensions in the page's main world is not guaranteed, so the behaviour isn't just broken; it's nondeterministic.

Consider who my users are: developers debugging React. Practically all of them have React DevTools installed. I had written a tool whose most likely observable effect was breaking a more important tool they already relied on, on some machines, some of the time.

Why no test caught it Nothing was wrong with my code in isolation, and in isolation is exactly how it was tested. The bug lives in the interaction with software that wasn't present in my test environment. There was no assertion to write, because the missing thing was another extension.
03

A licence check that validated instead of activating

Third-party API semantics · both endpoints return success

The paid tier used licence keys with a limit on how many machines one key may activate. The billing provider offers /licenses/validate and /licenses/activate. The agent called validate.

POST /v1/licenses/validate   // "is this key real?"  → yes
POST /v1/licenses/activate   // "register this machine" → yes, and counts it

Both return success for a valid key. Both look correct in a happy-path test. But only activate registers an instance, and the activation limit is enforced against instances. Calling validate alone meant no instance was ever registered, so the limit was never enforced.

One key would have worked on unlimited machines. The feature I believed I had shipped existed only as an intention. Nothing in the code, the response, or the logs would have told me.

Why no test caught it My test asserted what the code did, not what the business rule required. A mocked validate returns valid: true and the test goes green. Verifying this needed something no unit test contains: reading the provider's documentation and knowing what the limit was supposed to mean.

The pattern is the point

Three bugs, three different subsystems, one shape. Each sat exactly where my code met an assumption I didn't own: React's tree contract, another extension's namespace, a payment provider's semantics. Inside my own boundaries the agent's code was fine. At the seams it produced something that ran perfectly and meant the wrong thing.

That makes sense when you think about how these models work. They produce what is plausible. Plausible and correct overlap almost completely in the middle of a function, and come apart at the edges, where correctness is defined by a system somewhere else. And at exactly those edges there is no local signal: no exception, no failing assertion, nothing red.

A crash tells you where to look. These three told me nothing at all. They just ran.

What actually caught them

Not cleverness, and not re-reading the code. In every case what caught the bug was something outside the code that already knew what right looked like:

An independent review pass that hadn't been told the code was finished. A realistic fixture: a list long enough to matter. The actual documentation for someone else's API. And on a different project, the strongest one available: a second, independent implementation of the same specification, run against the first until they agreed byte for byte.

That last one is the technique I'd defend hardest. If you write the same spec twice by different routes and both outputs match on the awkward cases, you've learned something no amount of staring at one implementation can tell you. You can watch it working here: a page that verifies a real email signature with two independent implementations checking each other, and lets you break it on purpose.

The uncomfortable version

It's tempting to end with "so review AI output carefully," which is true and useless. The sharper version: the speed is real, and so is the failure mode, and they're the same property. These models are fast because they generate what usually comes next. That is also precisely why they're confident at the seams, where "usually" is wrong.

So the work moved. It isn't typing any more, and it isn't prompting either. Prompting is easy and everyone can do it. The work is deciding what correct means, and building the thing that can tell you when you don't have it. Tests, review passes, second implementations, negative cases that prove your checker can actually fail.

I ship faster than I could have written this by hand. I also assume, now, that anything an agent hands me is confidently wrong somewhere I can't see, and that finding out is my job rather than the model's. Both of those are true at once, and holding both is the actual skill.

The three fixes above are in this public repository if you want to read them rather than take my word for it. That is rather the theme.