feat(saves): scrubbed saves in the repository, and oot_saves.py is now longshot_saves.py #543

Merged
HumanBean merged 1 commit from HumanBean/Longshot:feat/repo-saves into main 2026-11-14 22:56:09 +00:00
Owner

Why

Test runs and the Test Farm need the same starting points on every PC, and today a scenario can only start from the title screen or someone's own save. This proposes a narrow exception to "no saves": a few scrubbed saves in the repository. It also renames the save tool so its name drops the game's initials.

What changed

  • saves: scripts/longshot_saves.py, renamed from scripts/oot_saves.py, with tests/test_oot_saves.py renamed tests/test_longshot_saves.py. The docs, issue template and longshot_ctl.py follow. The backup folder keeps the name oot-save-backups, so players' existing backups and the launcher's stay together.
  • saves: longshot_saves.py scrub SRC --slot NN --out assets/saves/<name>:
    • copies one slot as slot_00 (progress.sav, caption.sav);
    • replaces caption.sav's JPEG with a plain mid-grey JPEG of the same size (543x306) and fixes the length field;
    • resets the save date (six hashed fields in the header, each found by its key exactly once) to 2026-01-01 00:00:00;
    • refuses any layout it doesn't fully understand, and prints every change.
  • saves: longshot_saves.py check-repo-saves checks:
    • the layout, with no links and no other files;
    • size caps;
    • a grey picture and a reset date;
    • a README per save;
    • that there is no account.sav, option.sav or _profile.
  • control: longshot_ctl.py launch GAME --repo-save NAME copies a repo save's slot into the run (same safety checks as --save); longshot_ctl.py saves --repo lists the repo saves.
  • assets: assets/saves/README.md (the rules). It holds no saves yet.
  • CONTRIBUTING.md: in "The rule with no exceptions", only the saves bullet changes. It now allows scrubbed saves under assets/saves/ (one slot, grey picture, reset date, passing check-repo-saves, made fresh for the farm, added through a pull request two maintainers approve). account.sav, option.sav, longshot_options.ini, longshot_env.txt and the rest of user/ stay banned.
  • .gitignore: *.sav everywhere except assets/saves/, so a real save can't be committed by accident.
  • docs: docs/saves-script.md, docs/control.md, docs/saves.md, docs/development.md.

Flags and settings

None.

Measurements

No performance change. What was checked on the real game is under Testing.

main: 7ff5256e (2026-11-14)
this PR: feat/repo-saves @ ba5e144e

main @ 7ff5256e this PR @ ba5e144e
a scrubbed slot alone (no account.sav/option.sav) loads into play n/a (no scrub) yes: title, Load, Hyrule Castle
Load screen picture / date the save's own plain grey / 1/1/2026 12:00 a.m.

Testing

Tested:

  • tests/test_longshot_saves.py (63 tests) and tests/test_longshot_ctl.py (44 tests) pass. They use made-up saves only.
  • libjpeg (djpeg), PIL and ImageMagick decode the grey JPEG cleanly.
  • Real game, on the AMD lab PC (RX 580, RADV, Linux), with main @ 839e85ff's build, headless, driven through the control bridge:
    1. A real save's Load screen shows its picture, date and time, place, hearts and "Autosave", and no player name.
    2. That slot, scrubbed and placed alone in an empty data folder, loads to gameplay in Hyrule Castle. The game then writes its own account.sav and option.sav.
    3. Its Load screen shows a grey picture and 1/1/2026 12:00 a.m.
  • All 12 caption.sav files on hand (Longshot and Hookshot) have the layout scrub expects. That layout is how host/control.c reads it.

Not tested:

  • No repo save exists yet: the first one should be made fresh for the farm. This PR adds the tools and the rule only.
  • Windows: launch --repo-save is Linux only, like --save.

Needs other testers:

  • Any PC: make the first farm save (a new file, played to a useful spot), scrub it and check it loads. Test request to open once this is agreed.

Screenshots

The Load screen with a scrubbed save, "main @ 839e85ff, scrubbed slot", can be attached on request. It's a grey picture box next to "1/1/2026 12:00 a.m., Hyrule Castle".

Risk and rollback

It changes the project's game-data rule, which the team needs to agree on before merging. Nothing in the game changes. Reverting the commit removes the tooling and restores the rule, and the rename can be reverted the same way.

Reviewer notes

  • The policy text in CONTRIBUTING.md first.
  • scripts/longshot_saves.py: scrub and check-repo-saves, which refuse anything they don't fully understand.
  • Beanstalk (the Test Farm, MagicBeanDev/Beanstalk#3) plans can use these with start = "save:<name>".

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). Run before the rebase, with the same failures as main (test_bake_portability, test_program_cache_cleanup, test_program_cache_one_variant, test_vram_budget_row, test_walk_key (a C link error, no C changed), and the socket tests in the sandbox).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not applicable (no performance change).
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.
## Why Test runs and the Test Farm need the same starting points on every PC, and today a scenario can only start from the title screen or someone's own save. This proposes a narrow exception to "no saves": a few scrubbed saves in the repository. It also renames the save tool so its name drops the game's initials. ## What changed - **saves:** `scripts/longshot_saves.py`, renamed from `scripts/oot_saves.py`, with `tests/test_oot_saves.py` renamed `tests/test_longshot_saves.py`. The docs, issue template and `longshot_ctl.py` follow. The backup folder keeps the name `oot-save-backups`, so players' existing backups and the launcher's stay together. - **saves:** `longshot_saves.py scrub SRC --slot NN --out assets/saves/<name>`: - copies one slot as `slot_00` (`progress.sav`, `caption.sav`); - replaces `caption.sav`'s JPEG with a plain mid-grey JPEG of the same size (543x306) and fixes the length field; - resets the save date (six hashed fields in the header, each found by its key exactly once) to 2026-01-01 00:00:00; - refuses any layout it doesn't fully understand, and prints every change. - **saves:** `longshot_saves.py check-repo-saves` checks: - the layout, with no links and no other files; - size caps; - a grey picture and a reset date; - a README per save; - that there is no `account.sav`, `option.sav` or `_profile`. - **control:** `longshot_ctl.py launch GAME --repo-save NAME` copies a repo save's slot into the run (same safety checks as `--save`); `longshot_ctl.py saves --repo` lists the repo saves. - **assets:** `assets/saves/README.md` (the rules). It holds no saves yet. - **CONTRIBUTING.md:** in "The rule with no exceptions", only the saves bullet changes. It now allows scrubbed saves under `assets/saves/` (one slot, grey picture, reset date, passing `check-repo-saves`, made fresh for the farm, added through a pull request two maintainers approve). `account.sav`, `option.sav`, `longshot_options.ini`, `longshot_env.txt` and the rest of `user/` stay banned. - **.gitignore:** `*.sav` everywhere except `assets/saves/`, so a real save can't be committed by accident. - **docs:** `docs/saves-script.md`, `docs/control.md`, `docs/saves.md`, `docs/development.md`. ## Flags and settings None. ## Measurements No performance change. What was checked on the real game is under Testing. main: 7ff5256e (2026-11-14) this PR: feat/repo-saves @ ba5e144e | | main @ 7ff5256e | this PR @ ba5e144e | |---|---|---| | a scrubbed slot alone (no account.sav/option.sav) loads into play | n/a (no scrub) | yes: title, Load, Hyrule Castle | | Load screen picture / date | the save's own | plain grey / 1/1/2026 12:00 a.m. | ## Testing **Tested:** - `tests/test_longshot_saves.py` (63 tests) and `tests/test_longshot_ctl.py` (44 tests) pass. They use made-up saves only. - libjpeg (djpeg), PIL and ImageMagick decode the grey JPEG cleanly. - Real game, on the AMD lab PC (RX 580, RADV, Linux), with `main` @ 839e85ff's build, headless, driven through the control bridge: 1. A real save's Load screen shows its picture, date and time, place, hearts and "Autosave", and **no player name**. 2. That slot, scrubbed and placed **alone** in an empty data folder, loads to gameplay in Hyrule Castle. The game then writes its own `account.sav` and `option.sav`. 3. Its Load screen shows a **grey picture and 1/1/2026 12:00 a.m.** - All 12 `caption.sav` files on hand (Longshot and Hookshot) have the layout `scrub` expects. That layout is how `host/control.c` reads it. **Not tested:** - No repo save exists yet: the first one should be made fresh for the farm. This PR adds the tools and the rule only. - Windows: `launch --repo-save` is Linux only, like `--save`. **Needs other testers:** - Any PC: make the first farm save (a new file, played to a useful spot), scrub it and check it loads. Test request to open once this is agreed. ## Screenshots The Load screen with a scrubbed save, "main @ 839e85ff, scrubbed slot", can be attached on request. It's a grey picture box next to "1/1/2026 12:00 a.m., Hyrule Castle". ## Risk and rollback It changes the project's game-data rule, which the team needs to agree on before merging. Nothing in the game changes. Reverting the commit removes the tooling and restores the rule, and the rename can be reverted the same way. ## Reviewer notes - The policy text in CONTRIBUTING.md first. - `scripts/longshot_saves.py`: `scrub` and `check-repo-saves`, which refuse anything they don't fully understand. - Beanstalk (the Test Farm, MagicBeanDev/Beanstalk#3) plans can use these with `start = "save:<name>"`. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main`. - [x] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). Run before the rebase, with the same failures as main (test_bake_portability, test_program_cache_cleanup, test_program_cache_one_variant, test_vram_budget_row, test_walk_key (a C link error, no C changed), and the socket tests in the sandbox). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. Not applicable (no performance change). - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated.
feat(saves): scrubbed saves in the repository, and oot_saves.py is now longshot_saves.py
Some checks failed
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Has been skipped
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Has been skipped
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Has been skipped
Third-party parts / The same as upstream (pull_request) Has been skipped
CI / Conventional Commit title (pull_request) Successful in 5s
CI / Workflow lint (actionlint) (pull_request) Successful in 6s
Third-party parts / As their notes say (pull_request) Successful in 9s
PR description / Description follows the template (pull_request_target) Failing after 6s
ba5e144edc
A few saves in the repository give the Test Farm, the tests and everyone
the same starting points. Each is one slot (progress.sav, caption.sav),
scrubbed by scripts/longshot_saves.py scrub: the file-select picture is
plain grey and the save date is reset to 2026-01-01 00:00. The game shows
no player name and makes account.sav and option.sav itself, so those are
never shipped. check-repo-saves enforces it; longshot_ctl.py launch
--repo-save NAME loads one. CONTRIBUTING.md: the narrow exception to the
no-saves rule, added through a pull request two maintainers approve.

scripts/oot_saves.py is renamed scripts/longshot_saves.py (and its test);
the backup folder keeps its name so existing backups stay together.

Assisted-by: Claude Code
Co-Authored-By: Claude Opus 5.5 <[email protected]>
HumanBean changed title from WIP: feat(saves): scrubbed saves in the repository, and oot_saves.py is now longshot_saves.py to feat(saves): scrubbed saves in the repository, and oot_saves.py is now longshot_saves.py 2026-11-14 22:55:47 +00:00
HumanBean deleted branch feat/repo-saves 2026-11-14 22:56:09 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!543
No description provided.