Repository navigation
Feature request: Allow atomic placement of offered games with AutoSync disabled #40
Description
Update — draft implementation
A draft pull request is open: #43
It is not merged. Maintainer review of the API split below is explicitly welcome.
The original request is unchanged and is kept further down. The draft does not implement it as a plain autoSync column write, because that flag only stops this device from starting a sync. A paired device that already knows the game id can still request the manifest and move files. Pause does not survive a daemon restart.
What the draft adds, all opt-in
Ordinary placement and tracking are unchanged when the new fields are omitted.
POST /api/offered-games/{id}/place and POST /api/games accept "autoSync": false or "provisioningHold": true. Either one records the game and a provisioning hold in the same transaction. While the hold is set, that game is excluded from inbound and outbound transfer. A failed hold read is not treated as "not held".
An explicit id is accepted only on held creation, so another machine can be given the same id locally. That does not create the game on the remote peer by itself.
Named save locations can be configured while the hold is in place. A held primary path cannot be changed to a symlink.
Difference from the request below
The original note asked to enable sync later through the existing game-setting API. The draft does not do that.
PATCH of autoSync cannot clear the hold. The unblock is:
POST /api/games/{id}/release-provisioning- An empty body clears the hold and turns AutoSync on. Release itself does not call
SyncGame. A later reconcile or reconnect can transfer. {"autoSync": false}clears the hold and leaves local AutoSync off. An explicit sync can still run.
Warning
Staged release is not a peer lock. After the hold is cleared, an unheld peer can still request the save even if this device's AutoSync is off. Peers that must not exchange bytes have to stay held.
A stock or older daemon on the same database does not understand the hold. It was observed to serve a held manifest (HTTP 200). Do not downgrade a data directory that has provisioning holds. A stock client talking to a patched held server was refused for the tested manifest and delete requests. That is not general mixed-version safety.
An already tracked game cannot be converted into a hold. That is intentional.
Suggested acceptance criteria, against the draft
- Placing or tracking without the new fields keeps current behaviour. Covered by tests in feat: allow atomic, opt-in game provisioning holds #43.
-
autoSync: falseorprovisioningHold: truecreates the game and the hold together, before any sync. - While held, reconcile, restart, direct sync, and inbound manifest/delete do not move that game's saves.
- Named save locations can be configured before release.
- Enabling sync later uses
release-provisioning, notPATCH autoSync. This is a deliberate difference from the request below. Maintainer preference is still open. - Empty-body release turns AutoSync on.
{"autoSync": false}does not, and does not stop an unheld peer from requesting the save. - Offer identity, offer clearing, and existing path/security checks are preserved.
- Downgrade safety is not met. Old binaries do not enforce the new table.
Summary
Would it be possible to extend the existing offered-game placement API to optionally create a tracked game with AutoSync disabled from the outset, rather than enabling synchronization during creation and requiring a second operation to disable it?
This would be particularly useful for headless OpenSave installations, NAS devices, home servers, and third-party applications that manage game-save provisioning programmatically.
Current Behaviour
OpenSave already provides a useful mechanism for handling games received from paired devices when the local save directory is unknown:
opensave offersopensave offers place <gameId> <folder>POST /api/offered-games/{gameId}/place
However, the placement endpoint calls Daemon.TrackGame(), which currently sets AutoSync = true during game creation.
For automated provisioning, this introduces a race condition:
- An application detects an offered game from a paired device.
- It creates a suitable local storage directory.
- It accepts the offer through OpenSave's placement API.
- OpenSave creates the tracked game with AutoSync enabled.
- The application attempts to disable AutoSync while configuring additional save locations, verifying identity, or performing other setup.
Between steps 4 and 5, synchronization may already have started.
This makes it difficult to safely automate provisioning on an already-paired headless device.
Proposed Solution
Extend the existing offered-game placement endpoint to accept an optional autoSync property.
Example request:
POST /api/offered-games/example-game/place
Content-Type: application/json
{
"path": "/srv/opensave/games/example-game/main",
"autoSync": false
}Expected Behaviour
- When
autoSyncis omitted, preserve the existing behaviour for backward compatibility. - When
autoSync: falseis supplied, create the tracked game with synchronization disabled atomically. - Ensure no initial peer sync, watcher-triggered sync, or other automatic transfer can begin before the disabled state is established.
- Preserve the existing game ID, offered-game lifecycle, path validation, and security protections.
- Allow synchronization to be enabled later through the existing game-setting API or CLI.
The important requirement is that this must be atomic within the tracking lifecycle. Creating the game with AutoSync enabled and immediately issuing a separate request to disable it would not eliminate the race.
Example Use Case
Consider an always-on Linux server running OpenSave as a persistent synchronization and backup peer.
A gaming PC tracks a new game, and the server receives an offered-game notification.
A local management application needs to:
- Allocate a dedicated storage directory.
- Accept the offered game with AutoSync initially disabled.
- Configure additional named save locations, if required.
- Verify the local storage layout and game identity.
- Explicitly enable AutoSync once provisioning is complete.
Currently, step 2 can initiate synchronization before the remaining setup has finished.
An atomic disabled-on-creation option would allow this workflow without modifying OpenSave's database, stopping the daemon, or introducing a separate server mode.
Scope and Backward Compatibility
Ideally, this would be a small, backward-compatible extension.
In scope:
- An optional
autoSyncparameter on the existing placement endpoint. - Support for initializing the tracked game with AutoSync disabled before any synchronization can begin.
- Preservation of existing behaviour when the parameter is omitted.
- Regression tests covering disabled-on-creation behaviour.
Out of scope:
- New networking protocols.
- Changes to the P2P synchronization algorithm.
- Dedicated server or NAS modes.
- Automatic directory allocation.
- Changes to conflict resolution or snapshot formats.
- Changes to existing security or authentication rules.
Question for Maintainers
Would you be open to a narrowly scoped PR implementing this?
Draft #43 is that attempt, with the hold/release split described at the top. Feedback on whether release should instead be the existing settings API is welcome.
Activity
[-]Feature request: Automatically place incoming games into a managed folder on headless devices[/-][+]Feature request: Allow atomic placement of offered games with AutoSync disabled[/+]Omar-VF commentedon Oct 11, 2026
Thanks for the careful design. It's a useful idea for headless setups, but it adds a check across many sync paths, so we're parking it for now while we land the data-loss fixes. We'll come back to it; please keep it open.