From 0fd24cd79e971f685125f89c5858b9fcc306d296 Mon Sep 17 00:00:00 2001 From: vorotamoroz Date: Sat, 17 Oct 2026 14:21:38 +0000 Subject: [PATCH] Align recovery and path identity documentation with Commonlib 0.1.42 --- docs/adr/2026_10_unicode_path_identity.md | 2 ++ docs/design_docs/tweak_compatibility.md | 28 +++++++++++++----- docs/design_docs/unicode_path_identity.md | 35 +++++++++-------------- docs/recovery.md | 16 +++++++++++ docs/settings.md | 4 ++- docs/specs_conflict_resolution.md | 33 ++++++++++++++------- docs/troubleshooting.md | 8 ++++-- 7 files changed, 84 insertions(+), 42 deletions(-) diff --git a/docs/adr/2026_10_unicode_path_identity.md b/docs/adr/2026_10_unicode_path_identity.md index eb503b50..839ea986 100644 --- a/docs/adr/2026_10_unicode_path_identity.md +++ b/docs/adr/2026_10_unicode_path_identity.md @@ -131,5 +131,7 @@ are detected. - [Unicode path identity design](../design_docs/unicode_path_identity.md) - [Setting details](../settings.md#unicode-path-identity) +- [User migration procedure](../recovery.md#migrate-to-unicode-nfc-path-identity) +- [Device-local file provenance](../specs_conflict_resolution.md#device-local-file-provenance) - [Commonlib Unicode path identity contract](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/unicode-path-identity.md) - [Project glossary](../glossary.md) diff --git a/docs/design_docs/tweak_compatibility.md b/docs/design_docs/tweak_compatibility.md index 965e5f3b..be7dda44 100644 --- a/docs/design_docs/tweak_compatibility.md +++ b/docs/design_docs/tweak_compatibility.md @@ -1,15 +1,16 @@ --- -date: 2026-09-08 -commonlib-version: "0.1.24" -self-hosted-livesync-version: "1.0.27" +date: 2026-10-17 +commonlib-version: "0.1.42" +self-hosted-livesync-version: "1.0.37" status: unreleased --- # Tweak compatibility and recovery -This document describes the integration of Commonlib 0.1.24 with -Self-hosted LiveSync 1.0.27. Commonlib owns the interpretation of synchronisation -settings; LiveSync owns the dialogues and operations which consume that result. +This document describes the compatibility and recovery contract, including +unreleased changes after Self-hosted LiveSync 1.0.37 using Commonlib 0.1.42. +Commonlib owns the interpretation of synchronisation settings; LiveSync owns +the dialogues and operations which consume that result. ## Shared assessment @@ -25,11 +26,16 @@ document IDs. An explicitly enabled value is therefore different from either an explicitly disabled value or a missing value. Settings whose historical missing value has not been established remain unadvertised; the evaluator does not invent defaults or turn every falsy value into an absent value. +`pathNormalizationVersion` is another explicit compatibility rule: missing and +`0` select legacy identity, while `1` requires coordinated reconstruction. +The [Unicode path identity design](unicode_path_identity.md) defines its +admission checks and supported transports. The central replication gate, mismatch dialogues, and RedFlag Fetch preparation consume the same effective differences. The P2P transport retains its separate policy: ordinary representation differences warn without rejecting transfer, -while its existing passphrase and peer checks still apply. Sharing assessment +while its existing passphrase and peer checks still apply. NFC path identity +is outside that warning-only policy: P2P refuses version `1`. Sharing assessment does not make the central replication policy appropriate for every transport. ## Host responsibilities @@ -100,3 +106,11 @@ replication, explicit Fetch, and replication after restart. A unit test which mocks Fetch does not establish those behaviours, and a corrected mismatch dialogue alone does not establish the cause of a reported persistent automatic synchronisation failure. + +The `tweak-compatibility` real-Obsidian scenario covers automatic and manual +adoption, stale target rejection, and adoption which activates either E2EE or +Property Encryption. Those prerequisite changes must retain the adopted +effective Metadata encryption value through Fetch, restart, and two-way file +transfer. See the [test guide](../../test/e2e-obsidian/README.md) for the scenario +and explicit artefact selection. The cause of an earlier saved chunk-size +change is separate from these recovery guarantees. diff --git a/docs/design_docs/unicode_path_identity.md b/docs/design_docs/unicode_path_identity.md index 7c3fd9f8..4a9f4210 100644 --- a/docs/design_docs/unicode_path_identity.md +++ b/docs/design_docs/unicode_path_identity.md @@ -16,7 +16,7 @@ the [Unicode path identity ADR](../adr/2026_10_unicode_path_identity.md). Commonlib's [consumer contract](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/unicode-path-identity.md) defines the shared package boundary. -This records an unreleased change to Self-hosted LiveSync `1.0.37`, using the +This records an unreleased change after Self-hosted LiveSync `1.0.37`, using the published Commonlib `0.1.42` package as an exact dependency. ## Scope @@ -128,26 +128,12 @@ has been successfully reserved; cancellation or failed reservation leaves it pending. A `remoteOnly` operation cannot apply a pending identity change, and the settings-only fallback is not offered. -Migration uses this ordered procedure: - -1. Update every CLI and Obsidian client which will use the database. Stop - synchronisation and editing on all devices, and keep a complete backup. -2. Select the Vault whose complete file set is authoritative. Resolve any - collision reported by Rebuild before continuing. -3. Select version `1` on that source. In Obsidian, choose **Overwrite Server - Data with This Device's Files**; the new mode becomes active only when the - Rebuild reservation succeeds. In the CLI, use settings with - `pathNormalizationVersion: 1` and run `rebuild` with `--force - --write-settings`. Both local and remote databases are reconstructed from - the specified physical Vault. -4. Select version `1` on each remaining client. In Obsidian, choose **Reset - Synchronisation on This Device**; the new mode becomes active only when the - Fetch reservation succeeds. In the CLI, use settings with - `pathNormalizationVersion: 1` and run `fetch` with `--force - --write-settings`. Each operation replaces that client's local database - from the rebuilt remote. -5. Confirm that every participating client is using version `1`, then resume - synchronisation. +The [user migration procedure](../recovery.md#migrate-to-unicode-nfc-path-identity) +owns the operational sequence: updated and stopped clients, a complete backed-up +authoritative Vault, source Rebuild, then Fetch on each remaining client. The +source operation reconstructs both databases; a receiving client's Fetch +replaces only its local database. The [CLI guide](../../src/apps/cli/README.md) +provides the equivalent `rebuild` and `fetch` commands. The CLI checks `--force` before core start-up so an omitted confirmation cannot trigger database access or destructive preparation. Neither `--force` nor a @@ -171,7 +157,11 @@ The path identity is also used by two existing resume mechanisms: keys with NFC in mode `1` for reads, writes, deletes, raw snapshot lookup, and untracked revision recording. Mode `0` retains the old keys. Rebuild and Fetch use the existing local-state reconstruction and replacement lifecycle; - no new persistent field or in-place key migration is introduced. + no NFC-specific persistent field or in-place key migration is introduced. + Commonlib 0.1.42 separately adds content hashes to the same records. The + [file-provenance contract](../specs_conflict_resolution.md#device-local-file-provenance) + defines that content evidence; changing a path key neither changes file + bytes nor supplies missing revision ancestry. - **Fast Fetch checkpoints:** the path version participates in checkpoint identity so an interrupted transfer cannot resume using a different path-to-ID rule. Existing checkpoint persistence and retry handling remain @@ -259,5 +249,6 @@ This design does not: - [Unicode path identity ADR](../adr/2026_10_unicode_path_identity.md) - [Setting details](../settings.md#unicode-path-identity) +- [User migration procedure](../recovery.md#migrate-to-unicode-nfc-path-identity) - [Commonlib Unicode path identity contract](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/unicode-path-identity.md) - [Metadata and Chunks glossary](../glossary.md#user-facing-and-operational-terms) diff --git a/docs/recovery.md b/docs/recovery.md index d9083b82..de9c5c17 100644 --- a/docs/recovery.md +++ b/docs/recovery.md @@ -18,6 +18,22 @@ Use the least destructive operation which matches the evidence: Do not switch transport, enable P2P, or run Garbage Collection as a substitute for diagnosing a stopped CouchDB or Object Storage setup. +## Migrate to Unicode NFC path identity + +Use this coordinated migration when CLI and Obsidian clients share a CouchDB database and composed and decomposed Unicode spellings should identify the same path. Version `0` remains the default and preserves legacy identity. Version `1` is supported with CouchDB only; it is unsupported with Object Storage and P2P. + +This migration reconstructs the databases from one authoritative Vault. It does not rewrite document IDs in place or rename files. + +1. Update every participating CLI and Obsidian client to a version which supports Unicode NFC path identity. Back up a complete authoritative Vault and the CouchDB database. Stop synchronisation and editing on every device until the migration is complete. +2. Choose the complete Vault which contains the intended files. Review any composed and decomposed names which would map to the same path identity, and resolve them before reconstruction. If Rebuild or Fetch reports an ambiguous path or Metadata ID, stop and resolve that collision before retrying; LiveSync does not choose or merge the files for you. +3. On the source client, select **Unicode NFC path identity** (`pathNormalizationVersion: 1`). In Obsidian, choose **Overwrite Server Data with This Device's Files**. In the CLI, set the same value in its settings and run `rebuild` with `--force --write-settings`. +4. On each remaining client, select **Unicode NFC path identity** (`pathNormalizationVersion: 1`) before fetching. In Obsidian, choose **Reset Synchronisation on This Device**. In the CLI, set the same value in its settings and run `fetch` with `--force --write-settings`. +5. Confirm that every client uses version `1` and that the expected files are present before resuming synchronisation. Do not reconnect a version `0` client to the migrated database. + +The Inspector's **Repair this Metadata document ID** action repairs one local entry; it is not a bulk migration tool. Use the Rebuild and Fetch procedure above for path identity changes. + +This procedure does not establish native macOS or iOS filesystem behaviour. Obsidian's collision checks use the paths exposed by its Vault APIs; see [Unicode path identity](settings.md#unicode-path-identity) for that visibility limit. + ## Suspend before diagnosis Close Obsidian completely, then create an empty file or directory named `redflag.md` at the root of the Vault. On the next start, LiveSync enters its emergency suspension state before ordinary database, file-watching, and synchronisation work continues. diff --git a/docs/settings.md b/docs/settings.md index 519ff707..ab3fc26e 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -1012,6 +1012,8 @@ Requires restart of Obsidian Setting key: deleteMetadataOfDeletedFiles +For an unconflicted file, disabling this setting records a logical deletion in the Metadata document; enabling it removes that document through a PouchDB tombstone instead. Both behaviours propagate file deletions and the source side of a rename. Before removing a Vault file, LiveSync revalidates the current winning revision; if this final check observes a concurrent restoration, it keeps the restored file. This setting changes how the deletion is represented; file content remains stored separately in Chunks. Deletion during an unresolved conflict follows the separate [displayed-branch rules](specs_conflict_resolution.md#operations-while-a-conflict-exists). + #### Delete old metadata of deleted files on start-up Setting key: automaticallyDeleteMetadataOfDeletedFiles @@ -1056,7 +1058,7 @@ Setting key: pathNormalizationVersion Version `0` preserves legacy file identity and is the default for existing and new settings. Version `1` uses Unicode NFC when deriving document IDs, so equivalent composed and decomposed paths identify the same file across the CLI and Obsidian. Existing physical file names are retained. This mode currently supports CouchDB only. -Before enabling version `1`, update every participating client, stop synchronisation, and back up a complete authoritative Vault. Rebuild both databases from that Vault, then select version `1` and Fetch on each remaining device. Changing this setting without reconstruction is refused when it would mix database identities. Do not resume an older client against the migrated remote. +Version `1` requires a coordinated migration: set it on the source client before Rebuild, then set it on each remaining client before Fetch. Changing the setting alone does not migrate existing Metadata. Follow [Migrate to Unicode NFC path identity](recovery.md#migrate-to-unicode-nfc-path-identity) for the complete procedure. Do not resume a version `0` client against the migrated remote. The selected value stays pending through ordinary settings saves and reloads. It becomes active only when the Rebuild or Fetch operation is successfully reserved; cancellation leaves it pending. diff --git a/docs/specs_conflict_resolution.md b/docs/specs_conflict_resolution.md index 8f62b992..aabf5807 100644 --- a/docs/specs_conflict_resolution.md +++ b/docs/specs_conflict_resolution.md @@ -38,15 +38,17 @@ At most one revision is the winner, more than one revision can be Vault-matching - Automatic text and structured-data merge uses the nearest `available` revision ID which is present in both leaf histories. - Missing or compacted history stops conservative automatic merge instead of guessing a base. -- A Vault file which still matches its exact recorded revision is unchanged. An ordinary save does not append those stale bytes to a newer database revision; a newer, unconflicted database result is reflected through the existing file-reflection path. +- A Vault file which still matches its exact recorded content is unchanged. The comparison uses the readable recorded revision or its saved SHA-256 hash and byte length, including after that revision has been pruned. An ordinary save does not append those stale bytes to a newer database revision; a newer, unconflicted database result is reflected through the existing file-reflection path. - A file which differs from its readable recorded revision is an edit of that revision, even if its bytes match another historical revision. Saving and incoming overwrite protection use the same rule. -- Without a readable recorded revision, current non-deleted leaves are checked for duplicate content. If none matches, the file is preserved as a fresh independent root under the same document ID. Its unknown ancestry cannot supply a three-way merge base. +- Without a readable recorded revision or matching saved content evidence, current non-deleted leaves are checked for duplicate content. If none matches, the file is preserved as a fresh independent root under the same document ID. Its unknown ancestry cannot supply a three-way merge base. - File bytes, rather than path, size, modification time, or revision generation, determine whether content is known. - Three or more current versions are reviewed one pair at a time in a deterministic order, with each completed pair committed before the next pair is read. - Each device records the exact revision most recently reflected in each Vault file. An ordinary edit extends that displayed branch even before a conflict exists. Conflict-time deletion and case-only rename retain their separate displayed-branch contracts. - A cross-path rename stores the target before logically deleting only the displayed source branch. -The recorded revision can belong to a deleted losing branch. If its readable body still matches the Vault, the propagated resolution can be reflected without recreating the conflict. A historical byte match without that record does not establish that the file is unchanged: it may be an intentional revert. Existing Vaults can lack records, so an upgrade, reset, or unavailable old body can expose additional conflicts requiring review. +The recorded revision can belong to a deleted losing branch. If its readable body or saved content evidence still matches the Vault, the propagated resolution can be reflected without recreating the conflict. A historical byte match without that record does not establish that the file is unchanged: it may be an intentional revert. Existing Vaults can lack records or contain legacy records without content evidence, so an upgrade, reset, or unavailable old body can still expose conflicts requiring review. Content evidence neither reconstructs a missing merge base nor resolves conflicts which have already been created. + +Ordinary deletion reflection accepts both logical deletion Metadata and PouchDB tombstones produced when `deleteMetadataOfDeletedFiles` is enabled. Commonlib revalidates the winning deletion before removing the Vault file. A restoration observed during that final check prevents deletion and allows the restored revision to be reflected. This does not change the separate conflict-time deletion rules below. The explicit **Always overwrite with a newer file** option retains its existing modification-time policy. An independent branch prevents an inferred three-way merge; it does not disable the user's selected conflict-resolution option. Metadata and Chunks retain their existing format, and matching chunks can be shared between branches. @@ -59,10 +61,11 @@ The explicit **Always overwrite with a newer file** option retains its existing | One side deletes content which the other leaves unchanged | Preserve the deletion. | | One side deletes content which the other modifies | Ask the user. | | A receiving file matches its exact readable recorded revision | Apply the propagated database result under the existing conflict policy. | +| A receiving file matches its recorded SHA-256 hash and byte length | Apply the propagated result under the same policy even if the recorded revision has been pruned. | | A receiving file differs from its readable recorded revision | Preserve the edit as a child of that exact revision. | | Provenance is unknown and no current non-deleted leaf matches the file | Preserve a fresh independent branch for conflict resolution. | | Provenance is unknown and current non-deleted leaves already hold the file bytes | Avoid duplicate storage; infer provenance only for a unique match. | -| A required body or shared ancestor is missing or compacted | Ask the user. | +| A body or shared ancestor required for merging is missing or compacted | Ask the user. | | Binary contents differ | Prefer an explicit user selection; semantic merge is unavailable. | The compatibility implementation currently selects the newer modification time for differing binary conflicts even when the general **Always overwrite with a newer file** option is disabled. This is existing behaviour, not a new 1.0 guarantee. Changing it to explicit selection only is a separate compatibility decision. @@ -140,10 +143,16 @@ Consequently, choosing **Not now** or closing Obsidian cannot undo a completed p LiveSync composes Commonlib's injected `FileReflectionProvenance` with its local key-value database. Each device stores: ```text -path -> { revision, observedStorageMtime? } +path -> { revision, observedStorageMtime?, contentHash?, contentSize? } ``` -`revision` identifies the exact database revision most recently saved from or reflected in this device's Vault. It is the base for subsequent local edits, rather than a certificate that the current file still contains those bytes. `observedStorageMtime` is the raw local modification time of the saved snapshot or the file observed after reflection. It is not rounded, combined with another device's value, or used as proof of branch identity. No content hash is persisted. +`revision` identifies the exact database revision most recently saved from or reflected in this device's Vault. It is the base for subsequent local edits, rather than a certificate that the current file still contains those bytes. `observedStorageMtime` is the raw local modification time of the saved snapshot or the file observed after reflection. It is not rounded, combined with another device's value, or used as proof of branch identity. + +Commonlib 0.1.42 adds optional `contentHash` and `contentSize` fields for the exact immutable content successfully saved or reflected. The hash uses `sha256:`; the size is the byte length. LiveSync persists these fields in its existing `file-reflection-provenance-v1` store. They are device-local evidence, not replicated Metadata, a replacement revision ID, or a way to reconstruct missing ancestry. Matching evidence can establish unchanged content, but cannot attach a genuine edit to an unavailable base. + +Legacy records remain readable. An equal-time scan can add evidence when the recorded revision is still the conflict-free current revision and its bytes match storage. An ordinary unchanged save can also upgrade its verified current record. Hashing is followed by the required storage and provenance revalidation; an unreadable or unrelated revision cannot be certified from the current file. Unsupported evidence or a hashing failure retains the existing revision-based comparison and conservative fallback. + +Commonlib owns the [content-hash decision and compatibility contract](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/file-reflection-content-hash.md). It serialises hashing before reading the Blob to bound simultaneous whole-file buffers, and reuses results only for the same immutable Blob. Whole-file allocation remains necessary. LiveSync's [Review Harness](../devs.md#file-content-hash-performance-measurements) compares that production helper with xxHash64; it does not select the production algorithm. The record changes after a successful database-to-Vault reflection or Vault-to-database write. An equal-time scan may also fill a missing record while the current database revision uniquely matches the file's bytes and no conflict leaf exists. It rereads storage and the current database revision before recording; it does not change file bytes or create a database revision. Ordinary file reads do not change the record. An existing recorded revision remains authoritative even if the user edits the file to bytes which equal another branch; otherwise content equality could silently move the edit to a branch which was not displayed. @@ -153,7 +162,9 @@ The common lock does not stop Obsidian edits, external filesystem writes, or rep LiveSync creates the namespaced store handle during service composition, before the key-value database is open. The sequential `onSettingLoaded` lifecycle opens that database before Vault scanning, watching, or replication starts. Store operations do not wait for implicit readiness: a lifecycle violation fails promptly, avoiding an indefinite or self-referential initialisation wait. Local database reset is a transient unavailable boundary, after which scanning reconstructs derived state. -For ordinary saves and incoming reflection, a missing or unreadable recorded base permits reconstruction only from exactly one matching current non-deleted leaf. Matching several current leaves avoids duplicate storage but does not identify a displayed branch. No current match creates an independent branch, even when an older ancestor has the same bytes. Deletion and rename retain their existing provenance-recovery contracts. +For ordinary saves and incoming reflection, a missing or unreadable recorded base without matching saved content evidence permits reconstruction only from exactly one matching current non-deleted leaf. Matching several current leaves avoids duplicate storage but does not identify a displayed branch. No current match creates an independent branch, even when an older ancestor has the same bytes. Deletion and rename retain their existing provenance-recovery contracts. + +Provenance keys follow the selected [Unicode path identity](design_docs/unicode_path_identity.md#state-which-follows-the-selected-identity). In NFC mode, equivalent path spellings address the same record; the content evidence continues to describe file bytes, independently of that path spelling. ## Operations while a conflict exists @@ -240,7 +251,7 @@ If the user renames `draft.md` to `published.md`, LiveSync stores `published.md` ### A remote resolution reaches a device which still shows the losing content -Android may resolve a conflict and continue editing while Mac still shows the losing revision. When Mac receives the resolved tree, LiveSync compares Mac's bytes with the exact revision recorded for its Vault. If that body remains readable and matches, it can apply Android's resolution without asking Mac to resolve the same unchanged conflict again. +Android may resolve a conflict and continue editing while Mac still shows the losing revision. When Mac receives the resolved tree, LiveSync compares Mac's bytes with the exact revision recorded for its Vault or its saved content evidence. If they match, it can apply Android's resolution without asking Mac to resolve the same unchanged conflict again, including when the recorded revision has been pruned. If the user edited the file on Mac before the resolution arrived, the bytes no longer match that historical revision. LiveSync preserves the Mac edit as an unsynchronised conflict instead of overwriting it. @@ -277,9 +288,11 @@ Do not: ## Verification -LiveSync also exercises three and four independently editing devices through real CouchDB, using the installed Commonlib package and the CLI conflict-resolution command dispatcher. These tests check unchanged losing files before and after resolution, genuine edits on a losing branch, missing provenance, compacted bases, independent-root deduplication, and propagation of the selected result. See the [multiple-device regression procedure and coverage boundaries](../test/README.md#multiple-device-conflict-regression-tests). +LiveSync also exercises three and four independently editing devices through real CouchDB, using the installed Commonlib package and the CLI conflict-resolution command dispatcher. The compaction cases distinguish unchanged files with saved content evidence, legacy records without it, and genuine edits which retain the same byte length and modification time. Repeated saves must create no duplicate revisions, and the selected result must propagate to every replica. See the [multiple-device regression procedure and coverage boundaries](../test/README.md#multiple-device-conflict-regression-tests). -Commonlib owns the real-PouchDB and injected-boundary tests for revision ancestry, content preservation, provenance, independent branches, and repeated file events. LiveSync owns persistent host composition and actual Obsidian restart coverage. The focused `test:e2e:obsidian:stale-file-restart` scenario advances the local DB while old Vault bytes remain, persists pending file events, and restarts the same isolated profile. It requires an unchanged recorded file to reflect the DB without a new revision, an unknown file to remain on an independent branch alongside the DB content, and repeated processing after provenance loss to leave those branches unchanged. It also removes the record for a file whose bytes still match the current database revision, checks that start-up restores the record without a new database revision, and then checks that a later incoming revision reflects without a conflict. It uses real local storage and startup processing; transport replication and mobile lifecycle coverage are separate. +Commonlib owns the real-PouchDB and injected-boundary tests for revision ancestry, content preservation, provenance, independent branches, and repeated file events. LiveSync owns persistent host composition and actual Obsidian restart coverage. The focused `test:e2e:obsidian:stale-file-restart` scenario prunes a recorded revision while its old Vault bytes remain, persists the content evidence and pending file event, and restarts the same isolated profile. The unchanged file must reflect the newer content without a database write. Other fixtures check independent preservation of unknown content, deduplication after provenance loss, reconstruction of a missing record from the current revision, and verified upgrade of a legacy record. It uses real local storage and start-up processing; transport replication and mobile lifecycle coverage are separate. + +`E2E_OBSIDIAN_ONLY_METADATA_DELETION=true` selects two-Vault creation, update, deletion, and rename checks with `deleteMetadataOfDeletedFiles` disabled and enabled. It also delivers a real CouchDB restoration during the final deletion check, requiring the receiving file bytes and restored winning revision to remain, with no deletion event. LiveSync's optional real-Obsidian two-Vault checks have two scopes. `E2E_OBSIDIAN_INCLUDE_MARKDOWN_CONFLICT=true` resolves and edits a Markdown conflict, propagates it to a Vault which still displays the deleted losing content, and requires one current result to remain. `E2E_OBSIDIAN_INCLUDE_CONFLICT_OPERATIONS=true` edits, deletes, case-renames, and cross-path-renames files while conflicts remain active; it verifies the parent revision of each resulting branch, replicates those exact trees, and confirms that the other conflict branches remain intact. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 388c55a3..b4a2decc 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -51,7 +51,9 @@ If the remote is healthy but one device's local database is not, use [Reset Sync If the log says `Preserved unsynchronised local changes as a conflict`, keep both versions available until you have checked their contents. The message means that LiveSync could not prove that the Vault file was unchanged; it does not establish that you edited the file. Use **Inspect conflicts and file/database differences** in Hatch to review the current branches before selecting a version. -At start-up, LiveSync can restore a missing device-local revision record when the file still exactly matches the current local database revision. If a newer revision has already arrived, that match may no longer exist. LiveSync then preserves the old file for review because it cannot distinguish an unchanged copy from an intentional edit back to older content. A new release cannot resolve a conflict which was already created merely by recognising a historical content match. If the problem recurs, include the first relevant log entries, plug-in versions on both devices, and a redacted full report with the issue steps. +At start-up, LiveSync can restore a missing device-local revision record when the file exactly matches the conflict-free current local database revision. For a saved record, it compares the Vault file with that exact revision when the revision body is readable. It also saves a device-local content hash and byte length. Evidence saved before pruning lets LiveSync recognise an unchanged Vault file even after its recorded revision has been pruned. + +If the recorded body is unavailable and no matching content evidence exists, LiveSync cannot prove that the file is unchanged and preserves it for review. Genuine edits and files with unknown origins remain protected; content evidence does not recreate missing revision history. A conflict which was already recorded is not automatically removed or resolved. Use **Inspect conflicts and file/database differences** to review its current branches. If the problem recurs, include the first relevant log entries, plug-in versions on both devices, and a redacted full report with the issue steps. ## Synchronisation is paused for compatibility review @@ -96,7 +98,9 @@ Current releases automatically align compatible settings which control how new c A missing legacy file-name case setting means case-insensitive handling. It matches an explicit disabled setting and does not require a rebuild for that difference. An explicitly enabled setting can use different document IDs and still requires a compatibility decision against either value. Other configuration differences shown in the dialogue must still be resolved. -If the mismatch names **Encrypt internal file Properties**, update every device before accepting that preference. It affects subsequent Metadata writes for Hidden File Sync and Customisation Sync; it does not automatically protect existing Metadata. A manual remote Rebuild is strongly recommended if you need to protect existing paths, times, sizes, and Chunk references. +The saved **Encrypt internal file Properties** preference is effective only for CouchDB when E2EE V2 and **Property Encryption** are also enabled. An inactive preference difference alone does not change Metadata behaviour or require a Rebuild. Applying settings retains that preference only when doing so leaves the adopted effective encryption settings unchanged. + +When active, this option affects subsequent Metadata writes for Hidden File Sync and Customisation Sync; it does not automatically protect existing Metadata. To protect existing paths, times, sizes, and Chunk references, update every device and manually Rebuild the remote database. The `Sync now` command keeps routine replication progress quiet so that it is convenient to assign to a keyboard shortcut; assign one in Obsidian if that suits your workflow. A quiet command may still open this dialogue when a mismatch or another decision requires your attention.