Skip to content

fix: track save revisions with SaveDataId and CommitId - #9

Open
Margok1987 wants to merge 5 commits into
prodeveloper0:mainfrom
Margok1987:fix/save-revision-change-detection
Open

fix: track save revisions with SaveDataId and CommitId#9
Margok1987 wants to merge 5 commits into
prodeveloper0:mainfrom
Margok1987:fix/save-revision-change-detection

Conversation

@Margok1987

Copy link
Copy Markdown

Summary

Replace the automatic-backup change detector's mounted-file st_mtime heuristic with Horizon save metadata:

  • identify each state entry by AccountUid + TitleID
  • track SaveDataId + CommitId from FsSaveDataInfo / FsSaveDataExtraData
  • keep a versioned .syncstate-v2
  • fail open: missing, ambiguous or unreadable metadata/state means BACKUP, never silent skip
  • capture the pre-upload revision and only advance sync state if the post-upload revision still matches

The server protocol, restore path, account selection and background-service control flow are unchanged.

Why

On real Switch hardware the current detector repeatedly observed mounted save files with st_mtime == 0.

The existing implementation treats a zero timestamp as changed, so an unchanged save is uploaded again on every check.

Hardware A/B/C measurements on two independent account/title saves showed:

  • mounted-file mtime: 0 in all samples
  • SaveDataId: stable across unchanged and changed saves
  • CommitId: stable across immediate unchanged A/B samples
  • CommitId: changed after an actual in-game save B/C

This provides a Horizon-native revision token without depending on POSIX timestamps from the mounted save filesystem.

State semantics

.syncstate-v2 stores one entry per account/title:

<uid0><uid1>:<titleID> <saveDataId> <commitId>

The legacy .syncstate is not trusted or migrated. The first run after upgrading therefore intentionally creates one fresh baseline backup per account/title.

State is only an optimization. Any metadata failure, missing or ambiguous record, corrupt state, or state-write failure leaves the title eligible for another backup.

Upload race handling

For every selected title the client captures the revision that caused it to be considered changed.

After archive + upload it reads the revision again:

  • PRE == POST -> record the synced revision
  • PRE/POST unavailable -> leave state unchanged
  • PRE != POST -> do not advance state and fail the round so the background service retries
  • upload failure -> do not advance state

This prevents a save committed during an upload from being incorrectly marked as already backed up.

Validation

Host-side tests covered:

  • missing state -> backup
  • first push -> state written
  • immediate unchanged -> skipped
  • CommitId change -> backup, then skipped
  • SaveDataId change -> backup, then skipped
  • same TitleID under two AccountUids -> independent state
  • reader failure -> fail-open backup
  • ExtraData failure -> fail-open backup
  • duplicate matches -> fail-open backup
  • PRE/POST race -> state not advanced
  • stable retry -> success then skip

Result: ALL_TESTS_PASS.

Hardware-tested source snapshot:

  • commit: 7cbd4af97938fff5a4cf4f85a3ec3106c3451108
  • GitHub Actions run: 32810647480
  • NRO SHA-256: 4baa0046e2dace86be0a569889307b25cbc99575817c932c5aab48e6458a6335
  • sysmodule SHA-256: 90101793e334267d600b7c9c1087e6d213186e19980123b0b78af1b6c678cda1

Hardware acceptance confirmed:

  • changed save -> uploaded
  • immediate unchanged manual push -> no new revision / no upload
  • unattended background service -> changed save uploaded automatically
  • unchanged saves for the other local accounts -> skipped
  • failed upload did not advance state; a later background round retried successfully
  • allAccounts=1 functioned
  • profile separation functioned
  • no restore operation was involved

The current PR head only removes the temporary candidate-build workflow after that test. The production source files are unchanged from the hardware-tested snapshot.

Scope

Changed production files only:

  • client/source/sync.cpp
  • client/source/sync.hpp

No server/database/API changes. No restore behavior changes.

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