Generations alone could not order a repair against copies held by
instances. Deleting dropped the watermark, so a stale instance could
skip downloading the new baseline. An import could land on the same
generation as an upload that never reached the controller, and the
instance would then keep its own copy.
Imports and deletes now bump a per-player epoch, which the controller
returns on acquire and checks on upload. Instances throw away a copy
from an earlier epoch, and deleted players keep their generation and
epoch in player_sync_deleted.json. A restarted download also takes the
new generation instead of the outdated one.
Generations in player data must now be non-negative integers, so an
invalid import is refused before it reaches the datastore.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
InstanceDetailsGetRequest needs core.instance.get, which the
player-sync list and show commands are not documented to require.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Factorio's table_to_json writes an empty inventory as {"i":{}}, which
made the summary throw for show and the web drawer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov flagged ctl.ts at 21% patch coverage. Run each command
through a fake control link with canned responses and check what it
prints and sends.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Admins had no way to look at or fix the player data the controller
stores when a sync went wrong. The web page now lists every stored
entry with its generation, size and the instance holding the lock, and
opens a drawer per player with an inventory summary, JSON export and
import, delete and lock release. The same operations are exposed as
clusterioctl player-sync commands.
Import bumps the generation past the stored one so instances holding an
older copy download the new data on the next join. Import and delete
are refused while an instance holds the lock, since its upload on leave
would undo the change. A new player_sync.inventory.modify permission
gates the write operations.
Closes#1003
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>