A save file that scrambled its own handwriting
When we built saving and loading, we wanted a tripwire. The idea was small and stubborn: take a freshly written save of fixed, known contents, reduce its bytes to a single fingerprint number, and from then on compare against that number every time.
If the on-disk shape of a save ever changed when we didn’t mean it to — a field quietly added, a value formatted differently, a line ending shifting under us — the fingerprint would move, and the change would light up in testing instead of slipping past us to a player. Save the same world, get the same bytes, get the same number. That was the whole contract.
The first time we ran it, the number refused to hold still.
The same world, in a different hand
Two saves of the exact same data produced two different fingerprints. That should be impossible. Identical contents in, identical bytes out — there’s nowhere for a difference to come from. So either our data wasn’t as identical as we thought, or something was writing the file differently each time for reasons that had nothing to do with the world.
A couple of throwaway probes — written, run once, deleted — localized it inside a few minutes. The culprit was the engine’s own file writer. Our save is a human-readable text file, not an opaque blob, and when the engine writes out a resource that contains nested sub-pieces, it labels each internal sub-piece with a short, randomly generated tag. Those tags are pure internal bookkeeping — the engine’s way of referring to one piece from another — and they are regenerated every time the file is written. Same world, freshly relabeled. The file was, in a very literal sense, scrambling its own handwriting: the same words set down in a slightly different penmanship each time.

Once we knew where to look, the rest of the file was reassuring. Every byte that meant something was rock-steady. The field values were stable. The dictionary keys came out in the same alphabetical order every time. The indentation matched. The line endings matched. Even the order things were declared in held constant. Of all the bytes in the save, the random internal tags were the only surface that moved — and they were the only ones that carried no meaning whatsoever.
What was nudging the randomness
There was one more thread to pull, because the drift wasn’t even constant. Two saves taken back to back, with nothing between them, came out byte-for-byte identical. The tags only shifted once a load happened between two saves.
That pinned it exactly. Each load nudges the engine’s random-tag generator forward a step, so the next save draws its tags from a slightly advanced position and labels everything afresh. With no load in between, the generator sat still and the tags repeated. Read a world back in, then save it again, and the penmanship changed — not because the world had, but because the act of reading it had quietly advanced the one thing those tags are drawn from.
The save wasn’t unstable. It was writing the same world in a different hand each time, and only after we’d read it once.
Chasing the purpose, not the wording
It would have been easy to declare the tripwire broken and weaken it — loosen the comparison, ignore the mismatch, move on. But the tripwire wasn’t wrong about what it saw; it was reacting to a part of the file that was never a useful signal. The honest fix was to keep the check’s purpose intact while teaching it to ignore the noise.
So before we fingerprint a save, we rewrite those random internal tags into stable placeholder names — first one, second one, and so on, in order of appearance — and take the fingerprint of that tag-normalized copy instead. The placeholders are deterministic by position, so a given world always normalizes to exactly the same text, and the fingerprint of that text holds still. Run after run, and across separate launches of the game, the number is now stable.
Crucially, normalizing the tags doesn’t blind the tripwire to anything we actually care about. The things that should move the fingerprint still move it. Add a field, remove one, rename one, change its type — the fingerprint shifts. Let an engine update change how a value is formatted, or a line-ending convention drift — the fingerprint shifts. The only thing we taught it to overlook is the one thing that was never information: the churn of randomly generated internal labels. A precise tripwire instead of a jumpy one.
Pulling on the same save-and-load thread turned up two more ways a load could quietly hand back the wrong world — a reload served from a stale in-memory copy, and a field gone silent at its default carrying an old value forward — but those belong to the world that loaded last week’s weather, not here; this post stays with the handwriting.
One hand for the whole world
There’s a quieter epilogue. As more of the world started being saved — first plants, then the first creatures — the normalize-then-fingerprint logic had been copy-pasted into several places, and copies like that drift apart the moment one is touched and the others aren’t. So we pulled it into a single shared routine that every check now runs through. One way to clean a save up before fingerprinting it, one way to read its true shape — so two checks can never disagree about what a world’s fingerprint is.
This was its own narrow problem, distinct from the rest of the save story. Keeping an old world loadable as the format grows is the forward-only upgrade ladder; holding the whole simulation to byte-for-byte reproducibility from a seed is deterministic chaos. This one was simpler and more particular: telling a real change apart from meaningless churn. The fingerprint had to react to everything that mattered and nothing that didn’t — and the only thing standing between those two was a save file that kept rewriting its own handwriting, in a hand we eventually learned to read past.
The engine can scramble the handwriting all it likes. The world it records always reads back true.



