diff --git a/docs/re/structures/savegame-format.md b/docs/re/structures/savegame-format.md index 9c0c434..1877e47 100644 --- a/docs/re/structures/savegame-format.md +++ b/docs/re/structures/savegame-format.md @@ -631,3 +631,41 @@ in 12 words**, not 135. Worth stating because the inflated figure looked plausible: half the file changing between saves is exactly what one would expect if saves were dense state, and nothing about it invites a second look. + + +## ✅ Refinement: every difference is in the HEADER; the slot region is identical + +**Same day, one iteration later.** Splitting the same comparison at the +documented slot-table boundary (`save+136`) sharpens the result considerably and +corrects the framing above: + +| region | words | pointer-shaped | **differ between same-state saves** | +|---|---|---|---| +| header, `< 0x88` | 34 | 12 | **12 — all of them** | +| slot table, `≥ 0x88` | 35 | 6 | **0** | + +**The slot region is byte-identical between the two saves.** Every one of the 12 +differing words lives in the header. That is a stronger and more useful statement +than the pointer framing, and it means **the documented slot fields on this page +are untouched by the churn** — they are stable state, and a diff of the slot +region is meaningful in a way that a diff of the whole file is not. + +### ⚠️ And my "pointer-shaped" heuristic has false positives + +The slot region contains **6 words in the pointer value range that do not +change** — `0x73777174`, `0x770F8877`, `0xBC2B75EF`, `0x8187F76B`, +`0x7BE9C030`, `0x829F6B88`. A pointer captured from a moving heap would not sit +still across two runs, so these are data whose values merely land in +`0x70–0x8F`/`0xB0–0xBF`. + +So the value-range test alone **does not identify a pointer** — a third of the +words it flags here are not pointers. What identifies one is the *combination* +of pointer-shaped **and** varying across runs, ideally with a shared constant +delta as three of the header words have (`0x101080`). The previous section's +"26 % of the file is heap addresses" overstates it on that basis; the defensible +figure is the 8 header words that are both pointer-shaped and moving. + +I am leaving the earlier section in place with this correction after it, because +the mistake is instructive: a value-range classifier on 32-bit words will always +have a false-positive rate, and quoting its raw count as a fact about the format +is the error. \ No newline at end of file