In the previous post, Change-as-Code was introduced as a discipline for managing system evolution. Applying it well requires a mental model of how systems actually evolve — and why “same state” often doesn’t mean “same system.”
State vs Path in Distributed Systems
State is a snapshot. It describes the system at a moment in time.
Path is history: the sequence of changes, their order, and the conditions under which they were applied.
Modern tooling inspects state with precision — versions, schemas, permissions. But state is a lossy representation — it collapses history, discarding order and context.
In distributed systems, those paths matter.
A schema added before a backfill behaves differently from one added after. A consumer that processed historical events behaves differently from one that joined later. A retention rule applied mid-stream is not equivalent to one applied from day one.
Two systems may both report schema version X. One evolved through A → B → X. The other jumped directly from A → X. On paper, they match. In practice, assumptions embedded in the data differ in ways no snapshot captures.
Consider two staging environments showing schema version 12. One was built fresh last week. The other has been running for months, accumulating data between migrations. Same schema. Different historical data shapes. Different edge cases.
Why Drift is inevitable in Distributed Systems
Drift is often treated as a mistake — a missed step or broken process.
More often, it’s the natural result of unmanaged evolution.
Distributed systems change continuously. Components observe and apply changes at different times. Some changes are partial. Others depend on runtime behavior.
When evolution isn’t modeled explicitly, paths diverge quietly and accumulate over time.
Nothing necessarily broke.
The system simply evolved.
Why rollback and replay are fragile
Rollback and replay assume history is known and reproducible.
That only holds if the evolution path was captured and verified.
If changes were implicit, conditional, or applied out of order, there is no reliable reference point. If historical behavior depended on context that was never recorded, replaying events under new rules produces different outcomes.
You can’t reliably rewind a system whose history was never made explicit.
The unavoidable implication
Once you see systems as paths rather than snapshots, certain requirements stop being optional.
Evolution must be ordered, not just applied. History must be inspectable, not inferred. Convergence must be verifiable, not assumed.
These are structural requirements once you understand that behavior emerges over time. Without them, you’re managing snapshots while the real system quietly diverges.
System evolution is a first-class architectural concern.
What comes next
If system behavior is shaped by the path it took, that path needs execution, ordering, and verification at runtime.
That’s the missing piece.
Next post: The missing execution layer in System evolution