Code that assumes sequential execution, stable state, or consistent timing will fail the moment concurrency, scale, or latency proves the assumption wrong.
Two operations assume exclusive access to shared state without synchronization
If a system checks a condition and then acts on it without holding a lock or using an atomic operation — if code that works on small data fails on large data — if behavior changes under load — the system is temporally coupled to assumptions about sequencing, scale, or speed.
Every system that operates across time — concurrent threads, distributed nodes, growing datasets, eventual consistency — contains temporal assumptions. The more distributed the system, the more assumptions it makes about time, and the more ways those assumptions can fail.
Both are temporal coupling failures — one at the microsecond scale (threads), one at the data-growth scale (migrations)
Year
1997–present
Context
The web brought concurrency to application developers who had never thought about it. A desktop application had one user. A web application had thousands — simultaneously. Every shared resource — a bank balance, a seat on a flight, an item in inventory — became a race. Two requests arrive at the same time. Both read the balance. Both see $500. Both withdraw $400. Both succeed. The account now holds -$300.
Who Built This
Application developers who learned to write sequential code and were asked to write concurrent code. The languages — Java, C++, C# — provided threading primitives. The tutorials showed how to start a thread. They rarely showed what happens when two threads collide.
Threat Model at Time
Functional correctness. Does the right answer come back? Testing ran one request at a time. One request at a time always produced the right answer. The bug only appeared under load — and load testing rarely ran the same operation concurrently against the same resource.
Why It Made Sense
Sequential code is easy to reason about. Step A, then Step B, then Step C. The mental model is linear. When concurrency is introduced, the developer still thinks linearly — "check the balance, then deduct" — without recognizing that another thread is executing the same sequence on the same data at the same instant.
This pattern has been found in applications built by talented developers at respected organizations across every decade of software history. Its presence in a codebase is not a reflection of the developer who wrote it — it is a reflection of what that developer was taught, what tools they had, and the path that was easiest given what they were taught. The goal is not to find fault. The goal is to find the pattern — before it finds you.
Katie's Law: The developers were not wrong. The shortcut was not wrong. The context changed and the shortcut didn't.