301 duplicate IDs in the browser, 0 on the JVM: one real bug, end to end A developer found that a match-3 game engine generated duplicate gem IDs in the browser but not on the JVM, due to the code relying on System.nanoTime() which browsers clamp for security. The fix replaced the timestamp-based ID with a simple counter, and three new tests ensure the bug cannot recur. A reader named Ryan left the sharpest comment on my last post. The gist: it was jargon-heavy, kept restating "you have to test the AI's output" in new words, and read more like a pitch deck than a case study. He was right, and he pointed at the fix himself: walk through one real task. What changed, what caught the problem, what proof was required, where did a human step in. So here is one task, start to finish. Everything below is public and runnable. No withheld details, no diagrams of boxes with arrows. My match-3 game runs on a plain-Java rules engine. It runs two ways: on a JVM where the tests and CI live and in the browser, compiled to JavaScript by TeaVM https://teavm.org , so the same Java drives a real playable board. That second runtime is not just a demo. Running one piece of logic on two different machines gives me a free check: where the two disagree, one of them is wrong. I did not have to write down the right answer. I just had to notice a disagreement. Here is a task where that check earned its keep. I ported the engine to the browser. New demo-js module, TeaVM config, opaque integer handles in and JSON out so boards never actually cross into JavaScript. Mechanical work. The engine code barely moved. Except the port compiled a line I had never once looked at hard. This is how every gem got its ID: String id = row + "-" + col + "-" + System.nanoTime + "-" + RNG.nextInt 1000 ; Timestamp plus a random number. It had passed every test for months. The IDs are how the renderer tells one gem from another. Two gems with the same ID animate as a single gem. So I ran the same board generation on both runtimes and counted collisions over 128,000 gems. Same source code. Same inputs. Different answer. That is the entire signal. A machine counted it; I did not have to guess that something felt off. A number this specific still needs a human to say which side is wrong and why . That part was me. System.nanoTime looks unique but only leans on the clock being high-resolution enough that two calls land on different values. A JVM's timer is fine, so the flaw was invisible there. Browsers deliberately clamp their clock to about 100 microseconds a Spectre mitigation , so nanoTime barely advances between gems and RNG.nextInt 1000 collides on its own often enough to matter. Neither runtime was broken. The code was, for depending on clock resolution it was never promised. The browser was just honest about it. The fix is boring, which is the point: private static long idSeq = 0L; private static synchronized long nextId { return idSeq++; } -String id = row + "-" + col + "-" + System.nanoTime + "-" + RNG.nextInt 1000 ; +String id = row + "-" + col + "-" + nextId ; A counter is unique on every clock. The guarantee stops depending on the platform. The one rule I do not bend: a fix is not done because I say "fixed." It is done when a check that would catch the bug is sitting on disk and passing in CI. For this one, that meant three tests whose whole job is to fail if IDs ever lean on the clock again: @Test public void idsAreUniqueWithoutRelyingOnClockResolution { // Mint many gems as fast as possible: a clock-derived id would collide // here on any platform whose timer doesn't advance between calls. Set