Skip to content

Preserve exact archive UIDs in inventory backups - #15

Closed
rrblack wants to merge 1 commit into
dougchansan:mainfrom
rrblack:fix/exact-inventory-uid
Closed

rrblack wants to merge 1 commit into
dougchansan:mainfrom
rrblack:fix/exact-inventory-uid

Conversation

@rrblack

@rrblack rrblack commented Nov 7, 2026 •

Copy link
Copy Markdown

pull-inventory could record the wrong archive as a successful backup:

  • A nonzero-UID Account row whose open is refused (0xe02, the running app's own save) fell back to the common uid-0 save of the same title. The child printed "done:", and the locked user's row was marked done while holding the common save.
  • An all-zero UID was dropped from the child arguments, so the child enumerated the console's users and could back up a user's save for the common-save row.

Passing the uid alone is not enough, because plan() still adds the common and per-user fallbacks.

save-pull-root gains --exact: one open with the given uid (zeros allowed), space, type and rank/index/static id, no account enumeration and no fallback. pull-inventory always passes the row's uid with --exact, and marks a row done only when the child's manifest names the same program, uid, space, type, rank and index with no failed files. Done rows from earlier runs are re-checked the same way. A mismatched row goes back to pending, and its folder is renamed to .unverified- so the earlier files are kept. Manual save-pull-root discovery and sweeps are unchanged without --exact.

tests/test_pull_inventory_exact.cjs runs the real parent and child against a fake engine run directory. On the previous code it fails for the locked-user, zero-UID, one-open-per-row and stale-record cases.

pull-inventory could record the wrong archive as a successful backup:

- A nonzero-UID Account row whose open is refused (0xe02, the running
  app's own save) fell back to the common uid-0 save of the same title.
  The child printed "done:", and the locked user's row was marked done
  while holding the common save.
- An all-zero UID was dropped from the child arguments, so the child
  enumerated the console's users and could back up a user's save for
  the common-save row.

Passing the uid alone is not enough, because plan() still adds the
common and per-user fallbacks.

save-pull-root gains --exact: one open with the given uid (zeros
allowed), space, type and rank/index/static id, no account enumeration
and no fallback. pull-inventory always passes the row's uid with
--exact, and marks a row done only when the child's manifest names the
same program, uid, space, type, rank and index with no failed files.
Done rows from earlier runs are re-checked the same way. A mismatched
row goes back to pending, and its folder is renamed to
<folder>.unverified-<time> so the earlier files are kept. Manual
save-pull-root discovery and sweeps are unchanged without --exact.

tests/test_pull_inventory_exact.cjs runs the real parent and child
against a fake engine run directory. On the previous code it fails for
the locked-user, zero-UID, one-open-per-row and stale-record cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MxLKZQf6sapdg8rKhHumLg
@rrblack rrblack closed this Nov 7, 2026
@rrblack
rrblack deleted the fix/exact-inventory-uid branch November 7, 2026 10:38
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.

1 participant