Rename a variable on a SaveGame class, change its type or move a struct member, and an old player’s save still loads, but the value is gone: the engine matches stored values by name and skips any it cannot place, with no error. Savekeeper reads the saves you kept from each shipped build against your current classes and tells you, per stored value, whether a player keeps it.
The editor and a packaged game do not load saves by the same rules. The editor follows CoreRedirects property redirects and Blueprint property GUIDs, so a renamed variable comes back in PIE. A packaged game loading with UGameplayStatics does neither: the engine applies both only when !RequiresCookedData() || IsSaveGame() (Class.cpp, lines 1621 to 1622 in 5.8), and LoadGameFromMemory never marks its archive a save game. So it judges each value three ways: editor, packaged with the stock loader, packaged with its own loader. That reading comes from the engine source; Savekeeper’s own tests run in the editor.
-run=Savekeeper -Capture=1.0.0 keeps a build’s .sav files under SaveFixtures. A plain -run=Savekeeper on each new build writes an HTML report and JUnit for CI, and exits 2 when a stored value is lost. For a renamed field it proposes the CoreRedirects line and proves it first: it rewrites the save with the line applied, loads it through the engine and checks the value is in the new field. -Apply writes proven lines to DefaultEngine.ini. Load Game from Slot (Savekeeper) applies your redirects to the stored bytes before the stock load, so packaged games keep renamed values.
It reads UGameplayStatics saves from UE 5.4 on; only saves written by 5.8 were run. Third party save plugins and custom Serialize overrides are not covered. Unreal Engine 5.8 on Windows. The code was written with AI tools. It costs 14.99 USD on itch: