Loading…
Code that is correct, tests that are green, and a product that is broken for somebody else. This is the category of problem nobody teaches, looked up rather than read in order.
Every case here is a real defect from this product's own history: the symptom, the wrong first guess and the fix are what actually happened. Nothing is invented: a war story that never occurred teaches a failure mode you will never meet.
Nothing looked wrong. Progress saved, XP went up, levels advanced. Then a single `curl` command with `{"xp": 999999}` in the body granted an arbitrary level, and a second hole was worse because it was quieter: the penalty for reading a worked solution was a flag the browser volunteered, so the honest client paid it and a modified one simply did not send it.
"Only our own front end calls this endpoint." It is true right up until someone opens the network tab, and it is not a security property: it is a description of yesterday's traffic.
The API accepted the *result* from the client instead of the *event*. The browser said "I finished this lesson and it was worth N points, and by the way I did not use the solution": three claims, all trusted. Two of them were the client reporting on its own performance, which is the category of statement a server can never accept.
Anything the client says about its own performance is a request, not a fact. The server should accept what happened and decide for itself what it was worth.
No symptom at all. A deliberate piece of work had stripped quiz answers and worked solutions out of the page payload, and a test asserted that no answer key could be found in it. The test passed. The suite was green for weeks.
There is nothing to find: the tests cover it. That is the trap: a green suite is evidence about the rule you wrote down, and says nothing about the rule you meant.
One field had been left in the payload on purpose, with a written justification: a hint "points at the idea rather than giving the code", and making it cost a round trip would stop people taking it. The reasoning was sound and the premise was never checked. Measuring it later: of 118 hints, 88 contained code and 15 were the reference solution written out. The exemption that had been argued for was shipping the answer.
A green test proves the rule you wrote, not the rule you meant. The dangerous defects live inside the exemptions you argued for.
Learners in Turkey studying late in the evening lost their daily streak, or saw it fail to advance. Nobody in UTC could reproduce it, and the streak code had a passing test.
An off-by-one in the streak arithmetic: that is where the logic looks fiddly, so that is where everyone reads first. The arithmetic was correct. Reading it again, more carefully, would have cost another afternoon.
`todayStr()` computed the current date in UTC. Turkey is UTC+3, so between 00:00 and 03:00 local time the server still considered it yesterday. A learner finishing a lesson at 00:30 was recorded against the previous day: the streak either failed to advance or counted a day it should not have.
The server's day is not the user's day, and a bug that only exists for three hours in one country will not be found by reading the code.
A learner wrote a loop with no exit and the browser tab froze: permanently. No error, no stack trace, no way to stop it. The only recovery was force-quitting the tab, which lost whatever they had typed.
A performance problem: the interpreter is slow, the machine is old, give it a moment. It never finishes, because there is nothing to wait for, but "wait a bit longer" is a very easy thing to keep believing.
The Python runtime ran on the browser's main thread, which is the same thread that draws the page and handles clicks. An endless loop there does not slow the page down; it stops the page existing. There was no timeout and no way to interrupt, because a busy main thread cannot run the code that would interrupt it.
Code you cannot stop is code you cannot ship. Decide where untrusted work runs before you decide what it does.
`tsc` started failing with `Duplicate identifier` errors in files nobody had written, inside a generated directory. Deleting the directory fixed it. Days later it came back. Another time the dev server melted down entirely, panicking with `Next.js package not found` a hundred and twenty times while the page reloaded in a loop.
A broken build cache, or a bad dependency install. Both are reasonable, both are the usual answer, and deleting the cache did appear to work, which is exactly what made it take three occurrences to see the real pattern.
The project lived under a folder that a cloud drive was syncing. When sync could not resolve a change it left a second copy beside the original, named `file 2.ts`. Inside the generated types directory those copies duplicated every generated declaration, so the compiler saw each identifier twice. The same mechanism produced copies of the SQLite write-ahead log, and, on one occasion, a conflict copy of a source file was committed to git, a stale duplicate of a module from before it was rewritten.
Your filesystem is a participant in your build, and anything with write access to the project directory is part of the toolchain whether you chose it or not.
A table was renamed. Running the schema push locally printed a stack trace and stopped. Nothing was applied, nothing was broken, and the same command in a pipeline would have hung until it timed out.
The migration tool is broken, or the schema is invalid. Neither was true: the tool was working exactly as designed, and the schema was fine.
A rename is ambiguous to a schema differ: it cannot tell "this table was renamed" from "this table was dropped and a different one created". So it asked which one it was: an interactive prompt, waiting on a terminal that in a pipeline is not there.
A tool that asks a question has no answer in a pipeline. Anything that can prompt must be run where a person is, or not at all.
A freshness check reported that 295 links in the Turkish content were missing their date stamp, while every English link was fine. A clean split down one locale, in content that had been written in both languages at the same time by the same process.
The Turkish content was written more carelessly. It is the obvious reading, it is faintly plausible, and acting on it means editing 295 lines that were never wrong.
The check was wrong. English marked dates as `(added 2026-08)` and Turkish as `(eklenme: 2026-08)`, with a colon. The pattern being searched for did not allow the colon, so it matched nothing in Turkish and everything in English. The same run also flagged two files for quoting a price without a caveat; one of them says prices are "per million tokens" and quotes no figure at all, and the other was talking about a token count.
Before you fix 295 things, verify the thing doing the counting. A check is code, and untested code is untested code wherever it lives.