Skip to main content

Safety

Sync policy​

SyncPolicy enforces runtime exclusions. A guard is held until fetch or push returns; a conflicting acquisition fails with AlreadyRunning.

Procedures started concurrentlySame remoteDifferent remotes
Fetch + fetchDeniedDenied
Fetch + pushDeniedAllowed
Push + pushDeniedAllowed
Confirmation + fetch or pushDeniedAllowed

A standalone confirmation takes the same per-remote slot as fetch and push, so it cannot run while one of them is working on that remote. Push preparation takes no slot at all: it reads local files only and contacts no remote.

Existing resource restrictions​

RestrictionProtectsEffect
Local operation-log mutexoperations.logSerializes one synchronous operation-log access at a time. The guard is released before an await.
Per-remote media-inventory mutexremotes/{remote_id}/state/media/media_list.jsonSerializes synchronous inventory read-modify-write work. It is never held across a network await, including the folder listings of a confirmation.
In-memory operation-state RwLockReconstructed in-memory stateMultiple readers may coexist; rebuilding installs state under the exclusive write lock.
Remote compaction lock fileoperations/LOCK.opOnly the client that created the lock with put_if_absent may compact. A client that cannot create it skips compaction. A stale lock requires manual removal.

Access boundaries​

To restrict remote-storage access, fetch receives only StorageRead, while push receives StorageReadWrite.

Local-state subdirectory access is not strictly enforced. However, path builders are separated by domain, so each caller receives a focused handle for the part of local state it needs.

The safety assessments below apply to concurrent work within one Library instance.

In-memory state​

ResourceFetch implementation inputPush implementation inputLocal-edit implementation inputSafe?
Reconstructed in-memory stateOperation-state RwLock (through Library)Operation-state RwLock (through Library)Operation-state RwLock (through Library)Safe RwLock

Remote storage​

ResourceFetch implementation inputPush implementation inputLocal-edit implementation inputSafe?
Remote storageStorageReadStorageReadWriteNot usedSafe Only one sync operation per remote

Local state​

ResourceFetch implementation inputPush implementation inputConfirmation inputOn-demand media download inputLocal-edit implementation inputSafe?
local_state/library/LocalStateLibraryDirNot usedNot usedNot usedNot usedSafe Only one fetch per library
remotes/{remote_id}/state/operations/RemoteLastKnownStateDirRemoteLastKnownStateDirNot usedNot usedNot usedSafe Only one sync operation per remote
remotes/{remote_id}/state/compact_op_id_merged_to_local.jsonRemoteCompactOpIdMergedToLocalNot usedNot usedNot usedNot usedSafe Fetch-exclusive; corruption intentionally fails fetch
remotes/{remote_id}/state/media/media_list.jsonRemoteMediaListRemoteMediaListRemoteMediaListNot usedNot usedSafe Per-remote inventory mutex plus atomic writes
local_state/media/Not usedLocalStateMediaDirNot usedLocalStateMediaDir (through Library)LocalStateMediaDir (through Library)Safe Atomic write; immutable file with a 1-to-1 filename/content relation
operations.logLocalOpsReadWriteLockLocalOpsReadWriteLock (through Library)Not usedNot usedLocalOpsReadWriteLock (through Library)Safe Mutex

Remote media inventory​

The sibling path accessors enforce ownership within the shared state/ parent: RemoteLastKnownStateDir owns only the remote's last-known operation state, RemoteCompactOpIdMergedToLocal owns only the merge marker, and RemoteMediaList owns only the media inventory.

media_list.json is a positive-only inventory: an entry confirms a media's data blob, its thumbnail, or both, independently of each other. A blob is confirmed by media availability confirmation, which runs inside fetch, inside push, and on its own when a user asks for it, or by push after a successful ensure-present upload. An unconfirmed blob means unconfirmed, not absent from the remote.

The inventory is not authority over lifecycle. Planning first selects IDs from current resolved CRDT state: trashed media remains eligible for confirmation and upload, while a hard-deleted ID is not eligible even if an old inventory entry positively remembers it. After a durable MediaDeletion is pushed, Push deletes that target remote's data and thumbnail objects and removes the positive inventory entry. This ordering prevents physical reclamation from making a still-live item unavailable.

Push preparation is the main reader. It resolves where each blob the target is missing can be read from, using nothing but these inventories and the local media cache, which is why an incomplete inventory shows up as an unresolved media rather than as a wrong upload.

Downloading a blob on demand to display it is not a writer. It proves only that the blob was readable at that moment, and the confirmation step of the next sync with that remote establishes the same fact, so the download path leaves the inventory alone.

Confirmation is optional bookkeeping, so an inventory write failure cannot prevent a validated operation fetch. Both writers use a per-remote non-async mutex, held only for synchronous local load-modify-save work and never across list, get, or put_if_absent awaits. Atomic file replacement prevents partial JSON contents; the mutex prevents lost concurrent updates.

compact_op_id_merged_to_local.json is written only by fetch. The global fetch slot makes it fetch-exclusive within a Library instance, and corruption of this merge marker intentionally fails fetch.