docs: define independent revision properties

This commit is contained in:
vorotamoroz
2026-08-19 06:25:00 +00:00
parent a0684c4b3a
commit f02470ec5c
13 changed files with 153 additions and 99 deletions
@@ -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