Skip to content

watcher: changes OpenSave makes itself are not new saves - #23

Open
ChakraFusion wants to merge 1 commit into
Liquid-co:mainfrom
ChakraFusion:pr/own-writes-not-saves
Open

ChakraFusion wants to merge 1 commit into
Liquid-co:mainfrom
ChakraFusion:pr/own-writes-not-saves

Conversation

@ChakraFusion

Copy link
Copy Markdown

Part of #21.

The bug

Every change a sync applies looks exactly like the game saving. This has two effects:

  • Snapshot floods. A peer deleting files one request at a time caused an auto-snapshot every couple of seconds. Each one held a save that was neither the old one nor the new one. They filled the retention budget and pushed out the snapshots that mattered.
  • Echo. OnChanged fired for pulled files, so the sync was sent straight back out to the peers.

The fix

A new small package, internal/owntouch, records the paths OpenSave itself touches:

  • pulled files (delta.PatchWriter);
  • the folders a pull creates;
  • a peer's deletions, and the files "keep theirs" removes;
  • the mtimes "keep mine" re-dates.

The watcher classifies each burst of events against it:

  • A burst made only of OpenSave's own changes moves the recorded hash and nothing else: no auto-snapshot and no OnChanged.
  • A file counts as OpenSave's only if nothing wrote it after the mark (its mtime is not later). Once OpenSave is done with a file (renamed into place, re-dated to the peer's time), it records the exact time and size it left the file with. From then on the file is OpenSave's only while both still match. A game saving right after a sync is therefore still the game's change, even within the 2 seconds a plain time comparison would have to allow.
  • A path found gone counts as OpenSave's only if OpenSave removed it (MarkRemoved). If the game or a person deletes a file OpenSave has just pulled, that deletion is theirs, and it is synced and snapshotted as such.
  • The rescan after new folders come under watch counts as OpenSave's own only when OpenSave created those folders, for example a pull of a save with subfolders.

Tests

  • owntouch_test.go:
    • a marked file and its folder count as ours, and a sibling doesn't;
    • a write after the mark is not ours;
    • a file deleted by someone else after OpenSave wrote it is not ours, while a file OpenSave removed is;
    • a same-size save written 20 ms after a finished pull is not ours.
  • watcher/owntouch_test.go: own changes and own new folders are not snapshotted, and a burst mixing own changes with the game's is.
  • go test ./... passes. CI on the fork (all jobs green): https://github.com/ChakraFusion/OpenSave/actions/runs/37174971888

🤖 Generated with Claude Code

New package internal/owntouch records the paths OpenSave itself writes,
removes, creates or re-dates: pulled files, a peer's deletions, the folders a
pull creates, the files "keep theirs" removes and the mtimes "keep mine"
touches. The watcher classifies every event by it: a burst made only of
OpenSave's own changes moves the recorded hash and nothing else - no
auto-snapshot, and no OnChanged sending the sync straight back out.

Before, every change a sync applied looked exactly like the game saving. A peer
deleting files one request at a time produced an auto-snapshot every couple of
seconds, each of a save that was neither the old one nor the new one; they
filled the retention budget and pushed out the snapshots that mattered.

- a file counts as OpenSave's only if nothing wrote it after the mark (its
  mtime is not later), so a game saving straight after a sync is still the
  game's change.
- once OpenSave is done with a file (renamed into place, re-dated to the
  peer's time) it records the time and size it left it with, and from then
  on the file is OpenSave's only while it has exactly those - a game saving
  within the two seconds the time comparison allows is still the game's.
- a path found gone counts as OpenSave's only if OpenSave removed it
  (MarkRemoved): a file it pulled and the game or a person then deleted is
  their change.
- the rescan after new folders come under watch is OpenSave's own when it
  created those folders (a pull of a save with subfolders), and someone
  else's otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 4, 2026

Copy link
Copy Markdown

@ChakraFusion is attempting to deploy a commit to the sivadaboi's projects Team on Vercel.

A member of the Team first needs to authorize it.

This branch has not been deployed

No deployments
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