7.0 KiB
date, commonlib-version, self-hosted-livesync-version, status
| date | commonlib-version | self-hosted-livesync-version | status |
|---|---|---|---|
| 2026-10-17 | 0.1.42 | 1.0.37 | unreleased |
Architectural Decision Record: Unicode Path Identity for CouchDB
Status
Accepted on 2026-10-17. The feature remains unreleased. Local validation evidence and platform limits are recorded in the design document.
Context
Self-hosted LiveSync derives normal-file Metadata document IDs from Vault paths.
Unicode permits visually identical text to use different code-point sequences.
For example, é can be represented as one precomposed character or as e
followed by a combining acute accent. Filesystems and applications can expose
these forms differently. Without a shared canonical form, two clients can
derive different document IDs for the same logical path, or fail to resolve an
existing document when another client reports an equivalent spelling.
Changing only a lookup performed when receiving a document is insufficient. New documents, edits, deletions, local provenance, and resumable Fetch checkpoints must all use the same path identity. Applying the change to a populated database in place would also leave old document IDs and revision histories behind. Distinct files or Metadata documents can collapse to one identity under NFC, so automatic selection or merging could lose user data.
The Metadata path and file content have separate roles: Metadata stores file properties and references to Chunks, while Chunks store the content. A path identity change must not require physical files to be renamed or content to be rewritten in Metadata.
Decision
Add the opt-in pathNormalizationVersion setting. An absent value and 0
retain the existing path-to-ID behaviour. Version 1 applies Unicode
Normalization Form C (NFC) to the logical path used for Metadata IDs and path
comparison keys. Existing case handling remains an independent rule; CLI path
resolution uses NFC equivalence regardless of the handleFilenameCaseSensitive
setting. NFC changes logical identity only: it does not rewrite the stored
Metadata.path, rename a physical file, or change Chunk IDs or content. It is
independent of idDerivationVersion and does not require encryption.
When the CLI resolves a path, it uses the actual spelling of each existing
file and directory. A missing component is created under the actual resolved
parent using the spelling received for that component. Obsidian resolves paths
through its TFile and Vault APIs. Its collision checks are limited to the
paths those APIs expose and do not promise to find raw physical aliases hidden
by the Obsidian index.
The initial support boundary is CLI and Obsidian clients using CouchDB.
Journal and P2P reject version 1; Direct file access refuses a remote which
declares the NFC feature. Other host adapters are not supported for version 1
until they provide equivalent path resolution and ambiguity handling within
their supported storage listing.
Version 1 is represented by the required nfc-path-identity-v1 feature in
the existing generation-13 database version document. Every client must agree
on the path identity before it can write Metadata. A mode 0 client cannot
join a database requiring this feature. An existing database without the
feature cannot acquire it through an ordinary Metadata write while it already
contains Metadata. These admission checks remain active when ordinary
configuration-mismatch warnings are disabled.
pathNormalizationVersion is a required Tweak even when encryption is
disabled. It does not replace or modify idDerivationVersion.
The supported migration is reconstruction, not an in-place ID rewrite:
- Update every participating client and stop synchronisation.
- Select a complete, authoritative Vault and resolve NFC-equivalent files or Metadata documents which would produce the same ID.
- Set version
1on the source client and Rebuild both databases from that Vault. - Set version
1on each remaining client and Fetch the rebuilt remote. - Resume synchronisation only after every client has the same path identity.
In Obsidian, the setting remains pending through ordinary settings saves, the
settings-only Apply fallback, and reload. It becomes active only when the
existing Rebuild or Fetch operation is successfully reserved. A remoteOnly
operation cannot apply a pending identity change, and the settings-only
fallback is not offered. The Setup URI shares
pathNormalizationVersion so a new client receives the intended value;
importing that value does not replace the required Rebuild or Fetch operation.
The CLI exposes explicit rebuild and fetch commands. Both require
--force before application start-up because they replace local or remote
database state. --force confirms the requested operation; it does not bypass
identity checks, collision preflight, compatibility checks, or required human
remediation. The commands use the existing Commonlib Rebuilder; this change
does not introduce a second migration engine.
The migration procedure also uses --write-settings to retain the selected
local database and settings across subsequent CLI invocations. Collision
preflight uses the supported host listing and local Metadata. It refuses
ambiguous file or parent-directory candidates before database reconstruction;
it does not claim to detect physical aliases which a host does not expose.
Alternatives considered
- Use NFC by default: rejected because existing clients and databases must retain their current IDs until their owners deliberately migrate them.
- Normalise only lookups: rejected because new Metadata writes and deletes could continue using legacy IDs and create duplicate documents.
- Change
idDerivationVersion: rejected because it controls cryptographic ID derivation, not Unicode canonicalisation, and must remain meaningful when encryption is disabled. - Rename files to NFC: rejected because the decision concerns logical identity, while physical spelling belongs to the Vault and its filesystem.
- Rewrite remote IDs automatically or merge collisions: rejected because changing document IDs cannot preserve CouchDB revision ancestry, and the system cannot choose safely between distinct file histories.
Consequences
Legacy mode remains unchanged, and NFC identity requires a coordinated,
destructive Rebuild and Fetch. An ambiguity found in the supported storage
listing or local Metadata stops reconstruction before either database is
reset; the user must resolve the names or synchronisation scope. The check is
bounded by each host's listing contract: Obsidian uses its TFile and Vault
APIs and does not scan the physical Vault for aliases hidden by that index.
No claim is made that raw physical aliases outside a host's supported listing
are detected.