From a855ed2ae5e9e72aec2c13752d7e8679a78774b2 Mon Sep 17 00:00:00 2001 From: Johannes Millan Date: Wed, 15 Jul 2026 16:56:47 +0200 Subject: [PATCH] docs(sync): note force-upload as another immutable-snapshot orphan source (#9040) Document that _uploadSnapshotSplit (USE_LOCAL / recovery) leaves the previous compaction's immutable snapshot unreferenced, so it joins the crash-window case as an inert residual leak. Both are reclaimed by the same documented listFiles-prune backstop. Comment-only. --- .../file-based-sync-adapter.service.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/app/op-log/sync-providers/file-based/file-based-sync-adapter.service.ts b/src/app/op-log/sync-providers/file-based/file-based-sync-adapter.service.ts index 13d23176aa..4a96123321 100644 --- a/src/app/op-log/sync-providers/file-based/file-based-sync-adapter.service.ts +++ b/src/app/op-log/sync-providers/file-based/file-based-sync-adapter.service.ts @@ -1471,11 +1471,18 @@ export class FileBasedSyncAdapterService { * just wrote, which is now an orphan no committed ops file references (the * concurrent-compaction case that would otherwise leak). * - * Residual: a crash between the snapshot write and either commit or this cleanup - * still leaks (rare crash window). Upgrade path if it ever matters — an - * opportunistic `listFiles` prune of `STATE_GEN_FILE_PREFIX` files with a stale - * syncVersion (listFiles is optional on the provider interface, so it must stay - * capability-gated). + * Residual leaks these two call sites do NOT cover (all inert — orphaned + * snapshots only waste remote space, never affect correctness): + * - a crash between the snapshot write and either commit or this cleanup; + * - a force-upload (`_uploadSnapshotSplit`: USE_LOCAL / recovery), which resets + * to a fixed `sync-state.json` with a `snapshotRef` carrying no `file`, so the + * previous compaction's immutable snapshot is left unreferenced and the next + * compaction's predecessor-delete (which reads `snapshotRef.file`) can't find + * it. + * Upgrade path if these ever matter — an opportunistic `listFiles` prune that + * deletes every `STATE_GEN_FILE_PREFIX` file except the one the current ops file + * references (listFiles is optional on the provider interface, so it must stay + * capability-gated). That single prune reclaims all of the above. */ private async _removeGenStateFile( provider: FileSyncProvider,