Skip to content

fix(linux): prevent implicit game downgrades in the builder - #2406

Merged
hckrman101 merged 5 commits into
NotRexed:mainfrom
Arkex-ai:fix/linux-downgrade-protection
Nov 11, 2026
Merged

hckrman101 merged 5 commits into
NotRexed:mainfrom
Arkex-ai:fix/linux-downgrade-protection

Conversation

@Arkex-ai

@Arkex-ai Arkex-ai commented Nov 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

On Linux, the game-folder launcher could select an older installed Builder and offer to rebuild a newer game backwards, even offline. This keeps the recorded Builder associated with its game and prevents an implicit downgrade, while preserving confirmed version changes.

Fixes #2352. Claim. Scope coordinated with #2373; this does not redesign its launcher.

Technical changes

  • Prefer the game's recorded Builder; retain installed-Builder and direct-game fallbacks when it is unavailable. No candidate execution or extra interpreter needed to choose one.
  • Default to Play for a known older update target. Confirm older rebuilds at the common update entry, including DLSS changes and direct launcher updates.
  • Carry accepted downgrade consent once across an exact-version handoff, bound to the unchanged game version. A legacy fetched flag alone grants no consent.
  • Require the download list and fetched tools to match the selected target before rebuilding; report release-list lag instead of silently using another version.

Validation

Current tested head 04ea74bb, rebased onto main 34f05785. The worklist conflict preserves main’s damaged-file row and places this package’s row in score order. Focused version-admission tests pass again on Windows and Linux; Windows skips the POSIX executable-permission case, which passes on Linux. No fresh game rebuild or native Linux GUI run is claimed. Fresh hosted checks are separate exact-head evidence.

Earlier validation evidence and limits

Tested 2dcca138 on main 7759a6f3:

  • 14 focused methods pass on Linux; Windows passes the 13 handler/version methods and skips the POSIX-wrapper method. Tests execute the actual shell wrapper, version selector and complete production Tk handlers with authored UI/thread/download boundaries.
  • Original main fails the regression. 11 broken variants rejected on Linux / 10 on Windows, including lost or stale consent, wrong fetched tools, mismatched release lists and bypassed confirmation.
  • Full Linux: 374 passed / 0 failed / 23 skipped, versus exact base373/0/23.
  • Full Windows: 364 passed / 2 failed / 31 skipped, versus exact base363/2/31. The same recorder negative-control and NUP link-privilege failures remain; no new failure.
  • Existing updater30 and launch6 tests pass; shell syntax passes. The screenshot is the actual Tk launcher on Windows using authored version metadata.

No game files, real downloads or builds were used. Native Linux GUI rendering, a real AppImage upgrade and gameplay remain untested. Unknown hashes/differing nightlies retain the existing ordering policy; version labels are not commit-ancestry proof. Behavior and limits.

Tk launcher preview on Windows with authored game v2.2.0 and Builder v2.1.0 metadata

Current-head workflow Result
Game-free source regressions Passed
Linux AppImage Passed
PR title Passed
Windows builder Passed

Prefer the recorded Builder, keep default updates from selecting known older tools, and confirm older rebuilds at the common entry point.

Assisted-by: OpenAI Codex
Cover lagging lists, including lists that name the currently running older tools, before download or build handoff.

Assisted-by: OpenAI Codex
Record an isolated Tk preview using authored metadata and label the Windows rendering limit.

Assisted-by: OpenAI Codex
Bind one-use consent to the existing game and requested tools; old fetched flags alone cannot bypass confirmation.

Assisted-by: OpenAI Codex
@Arkex-ai
Arkex-ai force-pushed the fix/linux-downgrade-protection branch from 1649b1c to 04ea74b Compare November 11, 2026 19:46

@Joey-Magnus Joey-Magnus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does what #2352 needs, and the consent handling is tight. choose_mode no longer offers an older target as an update. older_ok now guards every rebuild entry point in begin_update, before any page change or download, so the DLSS-change rebuild and the game's own --update path are covered too. The --allow-downgrade-from handoff only counts when the game version, the requested tag and the running tools all match, and it's cleared after one use. The new manifest.tag != target check also closes the case where an API/list lag silently rebuilt a newer target with the running, older tools. CI is green on 04ea74bb, and test_linux_downgrade, test_linux_update, test_linux_update_skip and test_hookshot_launch pass locally. older_version returns False for anything release_key can't order (hashes, None), so nightlies and unversioned builds keep today's behaviour.

question builder/linux/hookshot-folder:30-33: flipping the order to prefer builder= fixes the "older installed Builder opens a newer game" case, but it makes the reverse case worse. Take a folder built from an AppImage that is still on disk (say ~/Applications/Hookshot-2.0.AppImage), while a newer Builder has since been installed under $XDG_DATA_HOME/hookshot/builder by another folder's update. Today that folder opens the newer installed Builder, which can rebuild it offline with the tools it already has. After this PR it opens the older AppImage. Offline, that one only knows its own version, so it shows Play. Online, it goes back through linux_update.install for a version that is already installed. The downgrade guard in choose_mode already stops the backwards rebuild whichever Builder opens, so would it be enough to pick the newer of the two? The installed one's tag is in $root/current and the recorded one built the game named by version=, so you can compare them without running either. A sort -V in the wrapper would do, and that keeps the no-interpreter property you wanted. If you'd rather keep the simple rule, please mention the offline trade-off in docs/linux-builder-version-selection.md.

minor: the new page and its 45 KB screenshot (docs/images/linux-builder-newer-game.png, a Windows rendering of the Linux Tk launcher with made-up versions) document one launcher behaviour. A short paragraph in the existing Linux section of docs/development.md or the readme, with the screenshot kept in the PR description, would be easier to keep current. Your call, not blocking.

@hckrman101
hckrman101 merged commit bd69992 into NotRexed:main Nov 11, 2026
14 checks passed
@Arkex-ai

Copy link
Copy Markdown
Contributor Author

Thanks for the review and merge. The reverse case is a real trade-off of the accepted recorded-Builder priority: an older AppImage can offer only Play offline even when a newer Builder is installed separately, and online it may fetch tools already installed there. Opening the installed Builder and selecting the game explicitly remains available; the downgrade guard still applies whichever Builder opens it.

I would keep a newest-candidate policy coordinated with #2373, with stable/pre-release/nightly and unorderable versions decided explicitly. This PR protects rebuild admission; it does not automatically choose the newest available Builder.

hckrman101 pushed a commit that referenced this pull request Nov 12, 2026
The worklist was behind the forum and the merges. Since v2.1.0, many fix
PRs have merged, several rows already shipped, and the most-reported
problems in Discord #bug-reporting had no row. This PR brings
`docs/worklist.md` back in line, following the rules in the worklist and
in `docs/workflow.md`.

## Method
- **Forum snapshot.** All 409 #bug-reporting posts as of Nov 11, ~11:10
PM ET (Nov 7-11). Each post is dated by its thread ID, so the submit
time is in ET.
- **How dates were used.**
- v2.1.0 was cut from `main` at about 8:32 PM ET on Nov 10 and published
at 9:29 PM ET. A PR merged before the cut counts as shipped; I checked
this with `git merge-base --is-ancestor <merge commit> v2.1.0`.
- A report sent before a fix shipped and not repeated after it counts as
fixed.
- A report sent after v2.1.0, or before a fix that merged later, counts
as still open or waiting for a release.
- **Score.** Severity x reach x confidence.
- Reach comes from workflow.md's 2026-11-10 reporter shares. Where the
affected subset is unknown, it is marked as an upper bound.
- Confidence is 0.7 only where the GitHub tracker has logs from several
commenters; otherwise it is 0.4.
- **Owners.** New rows have no owner. Existing owners are kept.

## Changes
- **Added 20 rows (18 Open, 2 Fixed-waiting).**
- Open: RAM/VRAM fill-up to OOM (#993, 5.6; 13 threads after v2.1.0),
shader preparation stalls (3.2), AMD Windows crashes (#996, 2.9),
CPU-bound fps in Castle Town and Hyrule Field (#995), invisible objects
and doors (#1002), build.py stopped on v2.1.0, cutscene audio desync,
shadow artifacts, coloured lighting, HDR black screen and flicker, frame
generation stutter, the block grid around lights and fog, the v2.1.0
update failing, AF outlines, wrong button glyphs, Steam Deck at 6 fps,
Linux AMD slower than Windows, and the FSR 4 tick not rebuilding.
- Fixed-waiting: the pick-up counter above 60 fps (#2006) and RADV
device lost after the intro (#2362).
- **Updated 6 rows.**
- The Link-jump row is now the "above a 60 fps cap" row (#1742),
covering the Scarecrow's Song softlock, Gohma and the item hanging above
Link's head. It goes from S2 to S1 and is re-scored from 1.2 to 3.5.
- New forum links or scores on the antivirus, Intel black screen (0.11
to 0.2, #999 has logs), fairy grotto, voices (#2506) and RX 580 (#2343)
rows.
- **Moved 10 rows to Fixed, waiting for a release.** #2545 (ground
garbling), #2451 (RTX 30 crash), #2286, #2275, #2449, #2096, #2406,
#2515, #1954 and #2367.
- **Deleted 8 rows** whose fix shipped in v2.1.0: #1792, #1922, #1819,
#1863, #1447, #1451, #1769-#1810 and the HDR10 overlay.

## Not done
- PRs listed as "candidate" fixes are matched by title and description
only. None is confirmed against the reports.
- Long forum threads were judged from their summaries.
- `tests/run_all.py` was not run (docs-only change).

Co-authored-by: Joey Magnus <joey.magnus@cxalloy.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Linux: the game folder's launcher opens an older installed builder, which offers to rebuild a newer game at its older version

3 participants