mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-27 13:57:07 +00:00
docs: define independent revision properties
This commit is contained in:
@@ -6,6 +6,10 @@ Accepted for a limited implementation.
|
||||
|
||||
## Problem and scope
|
||||
|
||||
This document uses the independent revision properties defined under
|
||||
[Revision](../terms.md#revision) and the general state model in
|
||||
[Conflict resolution and revision provenance](../specs_conflict_resolution.md).
|
||||
|
||||
Document History can reconstruct an available historical revision from its
|
||||
Chunks and write that content to the Vault through **Back to this revision**.
|
||||
The current action writes directly through the storage adapter. It does not
|
||||
@@ -13,8 +17,9 @@ create a new Metadata revision, clear a logical deletion through a successor,
|
||||
or record which database revision produced the restored Vault file.
|
||||
|
||||
This leaves a logically deleted Metadata document at `deleted: true` after the
|
||||
file has returned to the Vault. A later ordinary Vault save may create a live
|
||||
successor, but restoration must not depend on an unrelated later file event.
|
||||
file has returned to the Vault. A later ordinary Vault save may create a
|
||||
non-deleted successor, but restoration must not depend on an unrelated later
|
||||
file event.
|
||||
|
||||
The same action does not inspect or preserve revision-tree intent explicitly
|
||||
when conflicts exist. Document History currently displays the ancestry of the
|
||||
@@ -22,9 +27,9 @@ PouchDB winner. It does not display the complete revision tree or the ancestry
|
||||
of every conflict leaf.
|
||||
|
||||
This design covers restoration of one readable historical revision of a normal
|
||||
Vault file. It creates a new live revision, reflects that exact revision to the
|
||||
Vault, and leaves every other live conflict branch available for the existing
|
||||
conflict workflow.
|
||||
Vault file. It creates a new non-deleted successor revision, reflects that exact
|
||||
revision to the Vault, and leaves every other conflict branch available for the
|
||||
existing conflict workflow.
|
||||
|
||||
## Evidence
|
||||
|
||||
@@ -43,16 +48,16 @@ restoration step.
|
||||
## Revision-tree decision
|
||||
|
||||
The selected historical revision is the content source. It is not necessarily
|
||||
a live leaf and is not used as the parent of the new write.
|
||||
a current leaf and is not used as the parent of the new write.
|
||||
|
||||
At the time of the restoration operation, LiveSync reads the current PouchDB
|
||||
winner. The new revision is written as a child of that exact live revision and
|
||||
contains the selected historical content with no logical-deletion marker.
|
||||
winner. The new revision is written as a child of that exact winner revision
|
||||
and contains the selected historical content with no logical-deletion marker.
|
||||
|
||||
For an unconflicted logical deletion:
|
||||
|
||||
```text
|
||||
A -- D (deleted winner) -- R (restored live successor)
|
||||
A -- D (logically deleted winner) -- R (non-deleted restored successor)
|
||||
```
|
||||
|
||||
For an existing conflict:
|
||||
@@ -60,20 +65,20 @@ For an existing conflict:
|
||||
```text
|
||||
A -- W (winner) -- R (restored successor)
|
||||
\
|
||||
C (existing conflict remains live)
|
||||
C (existing conflict remains current)
|
||||
```
|
||||
|
||||
Advancing the winner branch is the ordinary meaning of reverting its content.
|
||||
The previous winner remains in revision history, while every other live leaf
|
||||
remains available for conflict resolution. Restoration does not manufacture an
|
||||
additional independent branch merely to retain the previous winner as another
|
||||
live conflict.
|
||||
The previous winner remains in revision history, while every other conflict
|
||||
leaf remains available for conflict resolution. Restoration does not
|
||||
manufacture an additional independent branch merely to retain the previous
|
||||
winner as another current conflict.
|
||||
|
||||
The existing **Inspect conflicts and file/database differences** workflow owns
|
||||
subsequent comparison and resolution of the restored revision and the remaining
|
||||
live leaves. Document History supplies content which may no longer be a live
|
||||
leaf; the Inspector operates on the live tree after that content has been
|
||||
restored. Neither interface replaces the other.
|
||||
conflict leaves. Document History supplies content which may no longer be a
|
||||
current leaf; the Inspector operates on the current revision tree after that
|
||||
content has been restored. Neither interface replaces the other.
|
||||
|
||||
## Persistence and reflection order
|
||||
|
||||
@@ -82,16 +87,18 @@ Restoration performs these steps in order:
|
||||
1. read and reconstruct the exact selected historical revision;
|
||||
2. read the current winner and use its exact revision as the write base;
|
||||
3. create Chunks and conditionally write a new non-deleted Metadata revision
|
||||
containing the selected content below that live base;
|
||||
containing the selected content below that exact winner;
|
||||
4. obtain the exact created revision from the database write;
|
||||
5. reflect that exact revision to the Vault; and
|
||||
6. record the reflected revision as the device-local file provenance.
|
||||
|
||||
The database write precedes Vault reflection. If the database write fails, the
|
||||
Vault remains unchanged. If the new revision is stored but Vault reflection
|
||||
fails, the live restored revision remains recoverable and the operation reports
|
||||
that the database restoration completed without successful reflection. It does
|
||||
not remove the new revision in an attempted rollback.
|
||||
fails, the restored revision remains in database history and the operation
|
||||
reports that persistence completed without successful reflection. It does not
|
||||
remove the new revision in an attempted rollback. Concurrent database activity
|
||||
may subsequently change whether that stored revision is a current leaf or the
|
||||
winner.
|
||||
|
||||
The new Metadata keeps the current document's creation time, records the
|
||||
restoration as a new modification, and derives its size and type from the
|
||||
@@ -99,6 +106,20 @@ reconstructed bytes. Reusing the historical modification time would make an
|
||||
explicit present-day restoration appear older than concurrent changes and
|
||||
would interact poorly with modification-time policies.
|
||||
|
||||
### Restoration state transition
|
||||
|
||||
The selected historical revision `H` supplies content, the winner `W` supplies
|
||||
the conditional write base, and `R` is the non-deleted restored revision. These
|
||||
are operation roles; winner, Vault-matching, and displayed remain independent
|
||||
properties.
|
||||
|
||||
| Stage | Content source | Winner | Vault relationship |
|
||||
| ---------------------------- | -------------- | -------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| Before restoration | `H` | current winner `W` | unchanged |
|
||||
| After the conditional write | `H` | `R` immediately after writing | Vault state and displayed provenance remain unchanged |
|
||||
| After exact Vault reflection | `H` | normally `R`; concurrent activity may differ | `R` is Vault-matching and displayed |
|
||||
| After a reflection failure | `H` | depends on subsequent database activity | Vault state and displayed provenance remain unchanged; `R` is stored |
|
||||
|
||||
## Conflicts and concurrent changes
|
||||
|
||||
Existing conflict leaves are never deleted by restoration. When conflicts
|
||||
@@ -109,10 +130,10 @@ other versions.
|
||||
|
||||
Document History does not perform a separate comparison with the winner which
|
||||
was current when the dialogue opened. The conditional exact-base write uses an
|
||||
ordinary PouchDB new edit. If that base is no longer a writable live leaf,
|
||||
ordinary PouchDB new edit. If that base is no longer a writable current leaf,
|
||||
PouchDB rejects the write and the dialogue reports that the revision tree
|
||||
changed and the operation should be retried. If the base remains live while
|
||||
another conflict leaf appears, the write may succeed and both branches remain
|
||||
changed and the operation should be retried. If the base remains current while
|
||||
another conflict leaf appears, the write may succeed and both leaves remain
|
||||
available.
|
||||
|
||||
Commonlib's existing `storeWithBaseRevision` operation cannot provide this
|
||||
@@ -120,8 +141,8 @@ condition. Its force-write behaviour intentionally uses `new_edits: false` so
|
||||
that conflict-preservation workflows can create a branch from a supplied
|
||||
ancestor. The restoration path therefore uses a separate
|
||||
`storeWithLiveBaseRevision` operation. That operation writes below the supplied
|
||||
leaf with ordinary PouchDB revision checking and never falls back to the force
|
||||
path.
|
||||
current leaf with ordinary PouchDB revision checking and never falls back to
|
||||
the force path.
|
||||
|
||||
The action must not silently fall back to an unbased write after an exact-base
|
||||
failure.
|
||||
@@ -130,9 +151,10 @@ failure.
|
||||
|
||||
The current slider continues to represent the available ancestry of the
|
||||
PouchDB winner. Building a complete branch-aware history viewer would require
|
||||
loading the ancestry of every live leaf, joining shared ancestors, representing
|
||||
missing or compacted revisions, and adding an explicit branch-selection
|
||||
interface. That work is not required to restore the history currently shown.
|
||||
loading the ancestry of every current leaf, joining shared ancestors,
|
||||
representing missing or compacted revisions, and adding an explicit
|
||||
branch-selection interface. That work is not required to restore the history
|
||||
currently shown.
|
||||
|
||||
When the document has conflicts, the dialogue may state that restoration will
|
||||
create a new revision on the winner branch which is current when the action
|
||||
@@ -152,9 +174,9 @@ Commonlib owns:
|
||||
|
||||
- Chunk creation and Metadata persistence;
|
||||
- `storeWithLiveBaseRevision`, which writes content as a normal child of an
|
||||
exact live revision and returns the created revision;
|
||||
exact current leaf and returns the created revision;
|
||||
- rejecting an unavailable or stale base revision;
|
||||
- reflecting an exact live revision to storage; and
|
||||
- reflecting an exact current leaf revision to storage; and
|
||||
- recording device-local file-reflection provenance.
|
||||
|
||||
The implementation retains `storeWithBaseRevision` for the conflict workflows
|
||||
@@ -180,13 +202,13 @@ Focused tests cover:
|
||||
- restoring readable content as a non-deleted child of a deleted winner;
|
||||
- returning and reflecting the exact created revision;
|
||||
- retaining every existing conflict leaf while advancing the winner branch;
|
||||
- refusing an exact-base write when the base is no longer live;
|
||||
- refusing an exact-base write when the base is no longer a current leaf;
|
||||
- retaining the existing force-write behaviour for callers which deliberately
|
||||
create a conflict branch;
|
||||
- leaving the Vault unchanged when database persistence fails; and
|
||||
- retaining the stored live revision when subsequent Vault reflection fails.
|
||||
- retaining the stored revision when subsequent Vault reflection fails.
|
||||
|
||||
The real-Obsidian regression exercise removes the additional normal Vault save
|
||||
from the earlier reproduction. **Back to this revision** must itself produce a
|
||||
new live database revision, restore the exact content to the Vault, and reopen
|
||||
Document History at that successor.
|
||||
new non-deleted successor revision, restore the exact content to the Vault, and
|
||||
reopen Document History at that successor.
|
||||
|
||||
@@ -94,7 +94,7 @@ separately; there is no batch repair.
|
||||
A one-entry repair is offered only when all of these checks pass:
|
||||
|
||||
- the mismatch is within the normal-file namespace;
|
||||
- the source is the current live revision and has no conflicts;
|
||||
- the source is the current winner and has no conflict leaves;
|
||||
- the recorded path is valid and selected by current synchronisation policy;
|
||||
- one case-normalised path maps to one source under the active filename setting;
|
||||
- only one mismatched source expects the target ID; and
|
||||
|
||||
Reference in New Issue
Block a user