feat(build): the lift key hashes only the environment that changes the lifted C #2874

Open
github-sync wants to merge 1 commit from github/pr/2874 into main
Owner

@jordanella opened this pull request on GitHub · 2026-11-12 18:08 UTC · original

A switch left set in the shell made the next build translate the whole game again (about 5 minutes on Windows): the lift key took every A64_, OOT_ and RX_ variable, including RX_VK_* renderer switches and RX_RELEASE, which the lift never reads. The same game in another work or game folder did too, since the folders' paths (OOT_WORK, OOT_EXEFS, ...) were in the key. This is the dev-loop proposal's A2 (#2636), with hckrman101's review point that the paths kept two checkouts of one tree from sharing a lift.

Change

nx2/make_game.py, lift_key: it hashes only the variables lift_reads_env() names:

  • In the key: A64_* and SUYU_RECOMP_* (the emitter's own switches, which weren't in the key at all before), and RX_TARGET.
  • Not in the key:
    • the paths (LIFT_PATH_ENV: OOT_WORK, OOT_EXEFS, OOT_ROMFS, OOT_DUMP, A64_HOT_FUNCS), since what the lift reads through them is hashed by its contents already;
    • the compile's own variables (COMPILE_ONLY_ENV);
    • and LIFT_ENV_NOT_OUTPUT: variables the lift's sources read that change nothing it writes (how many processes, where the compiler is), each with why.

The key's form changes, so the first build after this translates once.

Measured

Windows 11, Ryzen 9 3900X: after that first lift, a build with RX_VK_NO_PROGRAM_CACHE=1 in the shell skipped the lift (15 s), where main translated again.

In the game

Every build I ran in the game today carried this make_game.py. The latest: Windows 11, RTX 3080 (NVIDIA 621.14), from a save, headless through the control bridge: in play in Kokiri Forest, 28-31 fps, nothing in the log about a lost device or a crash. The change decides only whether the lift runs; the C it writes is the same.

Testing

  • tests/test_lift_cache.py, new cases:
    • the same game and inputs in other folders give the same key;
    • RX_RELEASE, an RX_VK_ switch and RX_MARCH leave it unchanged, while SUYU_RECOMP_STRICT, RX_TARGET and an A64_ switch change it;
    • every variable the lift's sources read is in the key, a path, or in LIFT_ENV_NOT_OUTPUT with a reason, so a new one can't slip through.
  • Every check that reads the changed files (54), through run_all.py, rebased on today's main, on Windows: 53 pass; test_linux_update fails the same way on main here.
  • Not tested: Linux. Nothing here is platform-specific.

See #2636 (A2).

🤖 Generated with Claude Code

> [@jordanella](https://github.com/jordanella) opened this pull request on GitHub · 2026-11-12 18:08 UTC · [original](https://github.com/NotRexed/Hookshot/pull/2874) A switch left set in the shell made the next build translate the whole game again (about 5 minutes on Windows): the lift key took every `A64_`, `OOT_` and `RX_` variable, including `RX_VK_*` renderer switches and `RX_RELEASE`, which the lift never reads. The same game in another work or game folder did too, since the folders' paths (`OOT_WORK`, `OOT_EXEFS`, ...) were in the key. This is the dev-loop proposal's A2 (#2636), with hckrman101's review point that the paths kept two checkouts of one tree from sharing a lift. ## Change `nx2/make_game.py`, `lift_key`: it hashes only the variables `lift_reads_env()` names: - **In the key:** `A64_*` and `SUYU_RECOMP_*` (the emitter's own switches, which weren't in the key at all before), and `RX_TARGET`. - **Not in the key:** - the paths (`LIFT_PATH_ENV`: `OOT_WORK`, `OOT_EXEFS`, `OOT_ROMFS`, `OOT_DUMP`, `A64_HOT_FUNCS`), since what the lift reads through them is hashed by its contents already; - the compile's own variables (`COMPILE_ONLY_ENV`); - and `LIFT_ENV_NOT_OUTPUT`: variables the lift's sources read that change nothing it writes (how many processes, where the compiler is), each with why. The key's form changes, so the first build after this translates once. ## Measured Windows 11, Ryzen 9 3900X: after that first lift, a build with `RX_VK_NO_PROGRAM_CACHE=1` in the shell skipped the lift (15 s), where `main` translated again. ## In the game Every build I ran in the game today carried this `make_game.py`. The latest: Windows 11, RTX 3080 (NVIDIA 621.14), from a save, headless through the control bridge: in play in Kokiri Forest, 28-31 fps, nothing in the log about a lost device or a crash. The change decides only whether the lift runs; the C it writes is the same. ## Testing - **`tests/test_lift_cache.py`, new cases:** - the same game and inputs in other folders give the same key; - `RX_RELEASE`, an `RX_VK_` switch and `RX_MARCH` leave it unchanged, while `SUYU_RECOMP_STRICT`, `RX_TARGET` and an `A64_` switch change it; - every variable the lift's sources read is in the key, a path, or in `LIFT_ENV_NOT_OUTPUT` with a reason, so a new one can't slip through. - **Every check that reads the changed files (54), through `run_all.py`, rebased on today's `main`, on Windows:** 53 pass; `test_linux_update` fails the same way on `main` here. - **Not tested:** Linux. Nothing here is platform-specific. See #2636 (A2). 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- github-sync:item:2874 -->
The key took every A64_, OOT_ and RX_ variable, so an RX_VK_ switch left set in the shell, or RX_RELEASE, which the lift
does not read, translated the game again (~5 minutes on Windows), and so did the same game in another work or game
folder: OOT_WORK, OOT_EXEFS, OOT_ROMFS, OOT_DUMP and A64_HOT_FUNCS are paths, and what the lift reads through them is
hashed by its contents already. The emitter's own SUYU_RECOMP_ switches were not in the key at all. This is the dev-loop
proposal's A2 (#2636), with hckrman101's point that the paths keep two checkouts of one tree from sharing a lift.

lift_key now hashes the variables lift_reads_env() names: A64_ and SUYU_RECOMP_, and RX_TARGET, but not the paths
(LIFT_PATH_ENV) nor the compile's own (COMPILE_ONLY_ENV). tests/test_lift_cache.py checks that the same game and inputs in
other folders give the same key, that RX_RELEASE, an RX_VK_ switch and RX_MARCH leave it and SUYU_RECOMP_STRICT, RX_TARGET
and an A64_ switch change it, and that every variable the lift's sources read is in the key, a path, or in
LIFT_ENV_NOT_OUTPUT with why it changes nothing. The key's form changes, so the first build after this translates once.

Measured on Windows: after that first lift, a build with RX_VK_NO_PROGRAM_CACHE=1 in the shell skipped the lift (15 s).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Commenting is not possible because the repository is archived.
No description provided.