Prevent a game update from turning yesterday's progress into today's support ticket.
savegame-compat is a zero-dependency Node.js CLI and GitHub Action that runs
real, committed JSON save files through your actual migration chain. It checks
the schema after every step, verifies game-specific invariants, runs every
fixture twice to expose random or time-dependent migrations, and fails CI when
an old save no longer reaches the current format.
简体中文 · configuration · migration operations · repair guide · research
git clone https://github.com/KanadeK/savegame-compat.git
cd savegame-compat
npm ci
node bin/savegame-compat.js verify \
--config examples/skyfarer/savegame.config.json \
--json artifacts/report.json \
--html artifacts/report.htmlExpected result:
PASS Skyfarer: 3/3 fixtures compatible with save version 3
[ok] v1-veteran.json 1->3 2 steps
[ok] v2-early-access.json 2->3 1 step
[ok] v3-current.json 3->3 0 steps
Migration executions: 3; fixture versions: 1, 2, 3
That output is not mocked. The v1 fixture uses a declarative migration to move currency and reshape every inventory entry. The v2→v3 step runs a JavaScript migration that splits player and world state into new structures. Each intermediate result is validated before the next step starts.
- A removed or renamed field with no migration.
- A migration chain that skips a shipped save version.
- A migration that emits data invalid for an intermediate or current schema.
- Player IDs, progression, inventory counts, or economy rules lost in transit.
- Duplicate inventory identifiers after a reshape.
Date.now(),Math.random(), unordered input, or other nondeterministic output.- A "current" fixture that no longer matches the current schema.
- Missing fixtures for any configured save format version.
- Unsafe JSON Pointer and merge keys that could mutate object prototypes.
flowchart LR
A["Committed save fixtures<br>v1, v2, …, current"] --> B["Validate source schema"]
B --> C["Run the real migration step"]
C --> D["Validate intermediate schema"]
D --> E{"Current version?"}
E -- "No" --> C
E -- "Yes" --> F["Check game invariants"]
F --> G["Repeat and compare SHA-256"]
G --> H["Exit code + JSON/HTML report"]
The HTML report contains file names, routes, counts, failure codes, and hashes. It deliberately does not embed save contents, player names, IDs, or inventory values.
Install from the tagged GitHub source:
npm install --save-dev github:KanadeK/savegame-compat#v0.1.1
npx savegame-compat init
npx savegame-compat verifyinit creates a valid one-version project:
savegame.config.json
fixtures/v1.json
schemas/v1.schema.json
When the save format changes:
- Keep the old fixture unchanged.
- Add the new schema and at least one current fixture.
- Add one migration edge from the previous format.
- Increment
currentVersion. - Add invariants for values the schema cannot prove.
- Run
npx savegame-compat verify.
The Skyfarer example is a complete three-version reference.
{
"formatVersion": 1,
"project": "My Game",
"currentVersion": 3,
"versionPath": "/meta/saveFormat",
"fixturesDir": "fixtures",
"schemas": {
"1": "schemas/v1.schema.json",
"2": "schemas/v2.schema.json",
"3": "schemas/v3.schema.json"
},
"migrations": [
{ "from": 1, "to": 2, "file": "migrations/1-to-2.json" },
{ "from": 2, "to": 3, "file": "migrations/2-to-3.mjs" }
],
"invariants": [
{
"id": "player-id-survives",
"check": "preserved",
"before": "/player/id",
"after": "/profile/playerId",
"sourceVersions": [1, 2]
},
{
"id": "credits-never-negative",
"check": "gte",
"path": "/economy/credits",
"value": 0
}
]
}Declarative migrations support add, replace, remove, move, copy,
default, increment, multiply, coerce, map, merge, assert, and
recursive map-array. Complex migrations can export an up(save, context)
function from a trusted .mjs file. See migration operations.
name: Save compatibility
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
jobs:
saves:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: KanadeK/savegame-compat@v0.1.1
with:
config: savegame.config.json
- uses: actions/upload-artifact@v7
if: always()
with:
name: savegame-compat-report
path: artifacts/savegame-compat-report.*The Action needs no package installation and adds the compatibility summary to the workflow job summary.
| Command | Real behavior |
|---|---|
init [dir] |
Writes a valid starter config, schema, and fixture; refuses overwrite by default. |
verify |
Migrates every fixture twice, validates every step and invariant, checks version coverage. |
inspect save.json |
Validates the source save and prints the exact planned migration route. |
migrate save.json |
Writes a validated migrated copy; refuses to overwrite unless --force is explicit. |
--version |
Prints the package version. |
Run npx savegame-compat --help for all output and report options.
- Save files must be JSON objects. Compressed, encrypted, binary, or engine-native saves need a deterministic JSON export/import adapter.
- The built-in validator implements the documented
JSON Schema subset;
unsupported external
$refURLs are rejected instead of silently ignored. - JavaScript migration modules are repository code and run with the same local permissions as the CLI. Use declarative JSON migrations for untrusted input.
- Forward migrations are supported. Downgrades are deliberately rejected.
- No telemetry, network request, account, cloud service, or runtime dependency is used.
The release gate used by this repository is:
npm ci
npm run verifyIt runs formatting/syntax checks, 47 unit and integration tests, a healthy
three-generation migration, a deliberately broken fixture that must exit 1,
privacy assertions on the HTML report, a secret scan, deterministic release
packaging, checksum generation, and a clean install from the generated .tgz.
When a gate fails, do not rewrite an old fixture to make it pass. Use the failure-code repair guide, then rerun:
npx savegame-compat inspect fixtures/the-failing-save.json
npx savegame-compat migrate fixtures/the-failing-save.json --out /tmp/repaired.json
npx savegame-compat verify --json artifacts/report.json --html artifacts/report.html
npm run verify- Architecture
- Configuration and schema support
- Declarative and JavaScript migrations
- CI and release integration
- Failure repair guide
- Market and overlap research
- Security policy
- Contributing
MIT © KanadeK. See LICENSE.