Skip to content

fix: make game transfers recoverable and safer - #300

Merged
fraa2a merged 5 commits into
mainfrom
fix/game-transfer-recovery
Nov 6, 2026
Merged

fraa2a merged 5 commits into
mainfrom
fix/game-transfer-recovery

Conversation

@fraa2a

@fraa2a fraa2a commented Nov 6, 2026 •

Copy link
Copy Markdown
Owner

What changed?

Four game transfer fixes from the review, one commit each:

  • H8, game blocked after a committed transfer: once a transfer is committed the new location is authoritative. If the old copy can't be fully deleted, the transfer still completes, the pending record is cleared (launch, uninstall and transfer are unblocked) and the user gets a warning naming the leftover folder to delete manually. The log entry omits the path. Games already stuck this way are unblocked too.
  • Stuck in copied with no temporary copy: recovery rolls back to the source when the temp copy and the destination are gone and the source is still owned (marker plus executable present).
  • Nested games: the overlap check from uninstall is shared as game_uninstall::overlaps_other_game (uninstall behaviour unchanged) and applied to both transfer source and destination.
  • Destination validation: transfer_game takes a libraryId and only accepts a registered library, instead of an arbitrary path from the webview. Frontend callers already had the id.

Intentionally left: if the destination can't be shown to be ours (e.g. drive unplugged), the transfer stays pending, because deleting the source then would be unsafe.

Validation

  • cargo test 966 passed, cargo clippy --all-targets -D warnings and cargo fmt --check clean.
  • npm run check, npm run lint, npm run test:feedback, npm run test:acl pass.
  • New tests: committed_transfer_unblocks_despite_leftover_source, leftover_source_is_reported, copied_transfer_without_copy_rolls_back, nested_game_paths_are_refused; frontend test checks the library id is sent.
  • Manual transfer test in the running app.
  • No unrelated changes.

UI changes

New warning when the old copy can't be deleted after a transfer.


Generated by Claude Code

Once a transfer is committed the destination is authoritative. A failed
or refused removal of the old copy now finishes the transfer, deletes the
journal row and reports the leftover folder as a warning, instead of
blocking launch, uninstall and further transfers forever.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGbCKVdcUfJfjZ93bYY9p3
A transfer recorded as copied always tried to commit, so a missing
temporary copy (deleted, or its drive unplugged) blocked the game forever.
Recovery now rolls back to the source when neither the copy nor the
destination exists and the source is still owned and intact.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGbCKVdcUfJfjZ93bYY9p3
Transfer only refused a source that held another game's executable, so a
game imported inside another game's folder could be moved out of it.
Uninstall's overlap check (installation root, Steam path and executable,
both directions) is now shared and applied to the transfer source and
destination.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGbCKVdcUfJfjZ93bYY9p3
transfer_game took a destination path from the webview and only checked
that it was an absolute existing directory. It now takes a library id and
resolves it with game_library::library_root, so games can only move into
registered libraries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGbCKVdcUfJfjZ93bYY9p3
Paths that do not exist yet were compared uncanonicalized against
canonical ones, so Windows short temp paths never matched.
@fraa2a
fraa2a merged commit d2be726 into main Nov 6, 2026
7 checks passed
@fraa2a
fraa2a deleted the fix/game-transfer-recovery branch November 6, 2026 17:35
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.

2 participants