# Clock Skew And ID Ordering
Clock skew breaks the assumption that timestamps from different machines are directly comparable.
## The Problem
If IDs are generated as:
```text
timestamp | machine_id | sequence
```
and one machine's clock is ahead, it can emit a larger ID before another machine emits an older timestamp.
```mermaid
sequenceDiagram
participant A as Server A clock=10:00:01
participant B as Server B clock=10:00:03
A->>A: emits ID timestamp 10:00:01
B->>B: emits ID timestamp 10:00:03
A->>A: emits ID timestamp 10:00:02
```
Numeric order no longer equals true event order.
## Concrete Failure
Consider a profile service using "largest Snowflake ID wins" to choose the latest update. Server B is three seconds ahead and writes an old email address after reading stale input. Server A then writes the correct email address with a lower timestamp. If the merge rule trusts ID order, the stale write wins.
The bug is not duplicate IDs. The bug is treating approximate time as causality. Time-sortable IDs are good cursors, but they are weak conflict detectors.
## Causes
- NTP sync intervals,
- CPU scheduling pauses,
- virtualization pauses,
- clock adjustments,
- leap-second handling,
- hardware clock drift,
- overloaded machines,
- time moving backward after correction.
## Design Consequence
Time-sortable IDs are usually good enough for:
- pagination,
- rough ordering,
- logs,
- human debugging,
- feed continuation.
They are not enough for:
- financial conflict resolution,
- "last writer wins" correctness,
- distributed locking,
- legal/audit ordering,
- serializable transaction order.
## Safer Alternatives
For correctness-sensitive ordering, use:
- database commit order,
- monotonically increasing sequence from one authority,
- consensus log index,
- version number on the record,
- compare-and-swap,
- fencing token,
- vector/lamport clocks where causality is the requirement.
## Mitigation Table
| Need | Safer Mechanism |
|---|---|
| prevent stale overwrite | version column or compare-and-swap |
| order writes to one record | database transaction or per-record sequence |
| order events in a stream | broker offset or consensus log index |
| detect causality between replicas | vector clock or explicit version vector |
| lease ownership | fencing token checked by the resource |
## Operational Checks
Monitor clock drift per host and alert before drift reaches the ID generator's tolerance. Record generator worker ID, wall-clock timestamp, and receive timestamp in logs so ordering incidents can be reconstructed.
In tests, simulate backward clock jumps, paused processes, and hosts returning from sleep. The generator should either wait, fail closed, or use a documented logical fallback. Silent generation after rollback is the dangerous behavior.
## Rule
Do not treat wall-clock time as a total order across machines. Treat it as an approximate timestamp unless the system has explicitly engineered stronger guarantees.