Quantum Bugs Escaped the Sandbox Again
The bugs that only exist while you are not looking
Edge-case gremlins haunt production environments, and the language we use about them is revealing. We say a bug is "impossible", that logs are "spectral", that a failure "only happens during the executive demo". All of that is the vocabulary of the supernatural, and it is a fairly precise description of what it feels like to debug something you cannot reproduce.
None of it is supernatural. It is under-observed, which is a different and more tractable problem.
Why the bug disappears under the debugger
The classic heisenbug vanishes the moment you attach a debugger, add logging, or run it in a slower environment. This is not the bug being coy. It is the bug being a race, and the observation changing the timing enough to lose the race reliably instead of winning it occasionally.
A data race needs two things to manifest: two operations that conflict, and an interleaving where they overlap. The conflict is a permanent property of the code — it is there whether or not it ever bites. The interleaving is a probabilistic property of the runtime, and almost anything perturbs it. Attaching a debugger inserts delays. Adding a log line inserts I/O and often a lock. Running under a sanitiser slows everything by a large factor and, crucially, slows it unevenly.
So the fact that a bug goes away under observation is not evidence that it is mysterious. It is fairly strong evidence about what kind of bug it is. "It disappears when I add logging" should update you sharply toward concurrency and away from logic, and that is genuinely useful information extracted from a failed reproduction attempt.
Non-determinism has a small number of sources
It feels infinite when you are inside it. It is not. In ordinary server software, run-to-run variation comes from a short list: thread and goroutine scheduling; wall-clock time and timezone; anything seeded from a random source; iteration order over hash-based collections; network ordering and latency; filesystem ordering; uninitialised memory; and the environment itself — a different kernel, a different container image, a different CPU feature set.
Writing that list down is most of the technique, because it converts an open-ended hunt into an enumeration. For each entry: is it present in this code path, and could it plausibly produce this symptom? Hash iteration order explains a test that fails one time in twenty on a map with a few keys. It does not explain a failure that correlates with time of day. Time of day explains a failure that appears at a boundary — midnight, a month end, a daylight-saving transition — and points immediately at date handling rather than at anything concurrent.
Most "impossible" bugs become ordinary the moment they are matched to a source of non-determinism, because each source suggests its own instrument.
Catching one without watching it
The core difficulty is that the act of looking changes the timing. The way around it is to record rather than observe — to arrange for evidence to be captured as a side effect of normal execution, so that nothing is added at the moment of failure.
In practice this means shifting from interactive debugging to always-on instrumentation with enough context to reconstruct the sequence afterwards. Structured events carrying the identifiers that let you correlate them. Traces that survive process boundaries. A ring buffer of recent activity that gets flushed when an error fires, so the expensive detail exists only in memory until the moment it turns out to matter.
That last pattern is worth more than it costs. The reason detailed logging is normally off is volume, and the reason it is needed is failure — and failure is rare. Buffering verbose detail in memory and persisting it only when something goes wrong resolves that tension almost completely, at the cost of some memory and the discipline to define what "goes wrong" means.
Tooling that finds the conflict, not the interleaving
The strongest move available is to stop hunting for the bad interleaving and hunt for the conflict instead. Race detectors do exactly this: rather than waiting for two operations to actually overlap, they track which memory is accessed under which locks and flag conflicting access patterns even on runs where the race did not manifest.
This inverts the economics. Instead of needing the unlucky one-in-ten-thousand run, you need any run that exercises both code paths — and that you can arrange. The cost is a substantial slowdown, which is why these tools live in test suites and staging rather than in production, and why the useful discipline is making sure your test suite actually exercises the concurrent paths rather than merely importing them.
Fuzzing and property-based testing attack the same problem from the other end, generating the input diversity that hand-written tests never have. Neither finds everything. Both find things that no amount of staring at the code does, because the thing you are looking for is by definition the case you did not think of.
The demo effect
Failures do genuinely cluster around demos, and there is no mysticism in it. Demos run on freshly provisioned environments, with cold caches, empty databases, and a login that has never been used before. They are performed by someone following an unusual path at an unusual pace, often on a network they do not normally use, while a screen recorder consumes resources.
That is not a normal request. It is close to the worst-case combination of cold start, first-run, and untested sequence — which is exactly the region of the input space that ordinary usage never explores and no test covers, because tests run against a warmed-up fixture.
The lesson is not that the universe has opinions about your career. It is that first-run behaviour is a real and under-tested code path, and the demo is simply the one time anybody exercises it under observation. If cold start is where your failures live, it is worth visiting on purpose rather than only by accident, in front of an audience.