mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-30 15:27:06 +00:00
Reconcile the Replicator capability design
This commit is contained in:
@@ -35,8 +35,9 @@ remote status, integrity inspection, and connected-device inspection.
|
||||
|
||||
These operations do not share one support boundary:
|
||||
|
||||
- CouchDB supports unattended OneShot Sync, Continuous replication, central
|
||||
remote administration, and CouchDB-specific inspection and maintenance.
|
||||
- CouchDB supports unattended OneShot Sync, Continuous replication,
|
||||
central-remote administration, and CouchDB-specific inspection and
|
||||
maintenance.
|
||||
- Object Storage supports finite journal synchronisation, central reset and
|
||||
lock Metadata, full upload and download, and storage-size inspection. It has
|
||||
no continuous changes feed, CouchDB Chunk source, CouchDB integrity
|
||||
@@ -244,12 +245,13 @@ a runtime plug-in registry or behaviour for unknown provider kinds.
|
||||
Each provider definition supplies:
|
||||
|
||||
- canonical kind and diagnostic name;
|
||||
- complete support metadata for the current catalogue;
|
||||
- active Replicator construction;
|
||||
- provider configuration identity and an explicit same-kind rebind-or-replace
|
||||
policy;
|
||||
- flow-specific probe and initial-transfer dependency factories; and
|
||||
- provider-specific entry points required by existing current flows.
|
||||
- a configuration predicate and private configuration identity;
|
||||
- explicit user-initiated and unattended OneShot runners;
|
||||
- readiness requirements, an explicit Continuous support decision, and a
|
||||
transfer-stop runner;
|
||||
- the exhaustive current remote-resource catalogue; and
|
||||
- an optional cohesive central-remote administration runner.
|
||||
|
||||
The host composes CouchDB and Object Storage definitions directly. A module is
|
||||
retained only when it owns separate state or behaviour; a factory-registration-
|
||||
@@ -280,35 +282,62 @@ persistence/profile boundary. Capability selection then uses that canonical
|
||||
kind; it never infers CouchDB by truthiness or by a negative test such as
|
||||
'neither Object Storage nor P2P'.
|
||||
|
||||
If a provider caches effective connection settings, its declared rebind or
|
||||
replacement policy keeps the active adapter current after a same-kind profile
|
||||
change. Reconciliation is serialised with active work and leaves no old
|
||||
credentials, Security Seed state, journal checkpoint, adapter cache, or
|
||||
diagnostic connection reachable from the reconciled handle.
|
||||
The private configuration identity covers every effective setting which binds
|
||||
the active adapter. The active publication is retained only while both the
|
||||
provider and identity are unchanged. Every changed identity follows the same
|
||||
serialised replacement transition; there is no same-instance rebind branch.
|
||||
|
||||
### Separate exhaustive support metadata from narrow runtime roles
|
||||
### Keep the active contract small and compose the differing roles
|
||||
|
||||
Every provider definition contains a required support record over the complete
|
||||
current catalogue. An active Replicator exposes only the narrow roles marked as
|
||||
supported by its definition. This gives compile-time completeness without a
|
||||
giant runtime facade or a collection of Boolean flags.
|
||||
The active object implements only the lifecycle and transport primitives which
|
||||
are real for CouchDB, Object Storage Journal, and P2P:
|
||||
|
||||
The generic catalogue covers user-initiated and unattended OneShot Sync,
|
||||
ordinary long-lived Continuous replication, full upload and download, central
|
||||
reset and lock administration, preferred-tweak Metadata read and write,
|
||||
on-demand remote Chunk reads, remote storage status, compromised-Chunk
|
||||
inspection, central Security Seed, and a request to stop active transfer.
|
||||
```typescript
|
||||
interface ReplicatorInstance {
|
||||
initializeDatabaseForReplication(): Promise<boolean>;
|
||||
openReplication(
|
||||
setting: RemoteDBSettings,
|
||||
keepAlive: boolean,
|
||||
showResult: boolean,
|
||||
ignoreCleanLock: boolean
|
||||
): Promise<void | boolean>;
|
||||
terminateSync(): void | Promise<void>;
|
||||
closeReplication(): void | Promise<void>;
|
||||
}
|
||||
```
|
||||
|
||||
Full upload/download, reset/lock, and Metadata read/write remain separate roles.
|
||||
Provider initialisation remains flow-specific: CouchDB may create a database,
|
||||
whereas Object Storage prepares its Security Seed and does not provision a
|
||||
bucket. Provider-specific CouchDB maintenance, Object Storage journal
|
||||
checkpoint maintenance, and P2P room operations are narrowed facets, not
|
||||
generic feature tests. P2P facets are defined in Part 2.
|
||||
Provider runners compose the differences in interaction authority, readiness,
|
||||
typed settlement, explicit Continuous support or inapplicability, and P2P room
|
||||
demand. Short-lived connection, preferred-tweak, Security Seed, and
|
||||
synchronisation-information operations remain caller-owned resources. Central
|
||||
administration remains one optional cohesive runner. None of those differences
|
||||
widens `ReplicatorInstance`.
|
||||
|
||||
Local node identity initialisation is a database and Replicator lifecycle
|
||||
concern, not a remote capability. Replication statistics remain a
|
||||
`ReplicatorService` telemetry sink.
|
||||
The LiveSync central-remote administration composition shares only local-identity
|
||||
preparation, mutation ordering, milestone interpretation, and result
|
||||
settlement. Its CouchDB and Object Storage adapters retain their own milestone
|
||||
readers and connection or client ownership. The fixed provider definition has
|
||||
already selected the adapter, so those readers validate only the additional
|
||||
operations which they use; they do not rediscover capability support through a
|
||||
concrete-class `instanceof` test.
|
||||
|
||||
The central OneShot adapters likewise require only the local structural
|
||||
`openOneShotReplicationWithOutcome()` operation. Concrete constructors remain
|
||||
at the host-composition boundary, but constructor identity is not a capability
|
||||
test. A structurally incomplete active instance settles as a failed outcome
|
||||
rather than falling back to the legacy `openReplication()` operation.
|
||||
|
||||
Directional Fetch and Rebuild, Streaming Fetch, CouchDB on-demand Chunk reads,
|
||||
remote-size inspection, compromised-Chunk inspection, Garbage Collection,
|
||||
compaction, and journal checkpoint maintenance are workflow or
|
||||
provider-specific concerns. They do not become exhaustive provider
|
||||
capabilities merely because an application flow branches by topology.
|
||||
|
||||
Local node identity initialisation remains at the established Replicator and
|
||||
local-database initialisation boundary for this change. A later physical
|
||||
database-lifetime review may move it only after establishing a concrete owner
|
||||
and migration benefit. Replication statistics remain a `ReplicatorService`
|
||||
telemetry sink.
|
||||
|
||||
### Make unattended work explicit and truthful
|
||||
|
||||
@@ -375,7 +404,11 @@ type ReplicationOutcome =
|
||||
| typeof REPLICATION_CANCELLED
|
||||
| { readonly status: "blocked"; readonly reason: ReplicationBlockReason }
|
||||
| { readonly status: "partial"; readonly detail: PartialReplicationDetail }
|
||||
| { readonly status: "failed"; readonly error: unknown };
|
||||
| {
|
||||
readonly status: "failed";
|
||||
readonly error: unknown;
|
||||
readonly recoveryHint?: CentralCompatibilityRecoveryHint;
|
||||
};
|
||||
```
|
||||
|
||||
Completed and cancelled values are shared singletons or literals. Blocked,
|
||||
@@ -384,54 +417,108 @@ initialisation, reset, lock, unlock, and resolution settle only after their
|
||||
defined remote write succeeds; a Rebuilder must not continue after an ignored
|
||||
mutation failure.
|
||||
|
||||
CouchDB and Object Storage Journal record one immutable central-compatibility
|
||||
decision inside the finite attempt which owns the connection or borrowed
|
||||
client. Only a rejection from that exact attempt becomes a recovery hint. A
|
||||
transport failure before assessment, or after an accepted assessment, cannot
|
||||
reuse mutable mismatch or lock state from an earlier attempt. P2P produces no
|
||||
central-compatibility decision. The recovery field is already specific to this
|
||||
contract, so its value carries the stable rejection reason and any preferred
|
||||
tweak value without a redundant kind discriminator.
|
||||
|
||||
`cancelled` means that the requested finite operation did not reach its normal
|
||||
completion boundary. It does not promise rollback. A provider may retain
|
||||
documents and checkpoints from batches which had already settled before the
|
||||
cancellation signal was observed, and a later operation resumes from that
|
||||
durable state.
|
||||
|
||||
### Distinguish observation from an identity result only when required
|
||||
### Preserve uncertainty at the boundary which owns the decision
|
||||
|
||||
Capability availability and operation results are separate. A supported
|
||||
operation may fail, while an inapplicable operation must not be called or
|
||||
reported as a network attempt.
|
||||
reported as a network attempt. A workflow which legitimately has no step for
|
||||
its topology may complete that branch without claiming that a provider ran an
|
||||
operation.
|
||||
|
||||
For an observation where an empty value changes a safety decision, use a tagged
|
||||
result:
|
||||
Keep uncertainty where it changes a safety decision. In particular, an Object
|
||||
Storage read distinguishes `available`, `not-found`, and `unavailable` before a
|
||||
caller decides whether creation is permitted. Only explicit `not-found` may
|
||||
create Journal synchronisation parameters; an unavailable read cannot be
|
||||
converted to a missing value or a new Security Seed.
|
||||
|
||||
```typescript
|
||||
type RemoteObservation<T> =
|
||||
| { readonly kind: "observed"; readonly value: T }
|
||||
| { readonly kind: "unavailable"; readonly error?: unknown };
|
||||
```
|
||||
|
||||
Compromised-Chunk inspection is the current example. `observed: 0` proves that
|
||||
the supported inspection found no matching entries; `unavailable` says that it
|
||||
did not complete, including while offline. A caller must handle every result
|
||||
before declaring the remote clean.
|
||||
|
||||
Do not wrap every result. When an empty array is the safe, documented identity
|
||||
for every current caller, retain it. High-frequency Chunk, document,
|
||||
changes-feed, and queue paths keep arrays, iterators, and scalars unless a
|
||||
measurement and a safety distinction justify a tag. No wrapper is added per
|
||||
Chunk, document, changes-feed row, or queue item.
|
||||
This principle does not require one generic `RemoteObservation<T>` type or an
|
||||
active-read catalogue. Existing provider-specific inspection and maintenance
|
||||
methods may retain their current compatibility surface until their real
|
||||
consumers are migrated. When a later bounded migration needs to distinguish an
|
||||
observed zero or empty result from an unavailable inspection, that consumer
|
||||
owns the smallest explicit result type required by the decision.
|
||||
|
||||
### Give active ownership and probes explicit boundaries
|
||||
|
||||
`ReplicatorService` is the sole owner of the active Replicator. Replacement is
|
||||
an atomic transition under its transition lock:
|
||||
`ReplicatorService` is the sole owner of the active Replicator. Replacement and
|
||||
disposal use one explicit quiescing transition under its transition lock:
|
||||
|
||||
```text
|
||||
active -> retiring -> disposed -> replacement published
|
||||
active -> quiescing -> closed -> replacement published
|
||||
```
|
||||
|
||||
Acquisitions wait for the transition and receive only the replacement. A fenced
|
||||
old handle cannot start work. Disposal stops Continuous activity, requests
|
||||
cancellation of work which supports it, awaits work which cannot be cancelled,
|
||||
and settles or reports every operation owned by the active adapter before
|
||||
publication. If bounded retirement cannot settle, replacement fails visibly
|
||||
and no new handle is published; the old handle is disposed when late work
|
||||
settles.
|
||||
The transition removes the old publication from `current`, rejects later
|
||||
admission, requests the provider's supported transfer cancellation, and drains
|
||||
work which was already admitted. Only then does it close the old Replicator and
|
||||
publish another active context. Acquisitions ordered after the
|
||||
transition receive only the replacement. A cancellation failure does not
|
||||
permit the physical close boundary to be skipped. If admitted work cannot
|
||||
settle, no replacement is published. If physical close fails, the quiescing
|
||||
publication remains fenced so a later transition can retry that close before
|
||||
constructing a replacement.
|
||||
|
||||
The publication object itself is the private generation identity; no separate
|
||||
generation number or public lease is required. Its reservation count is not the
|
||||
service-wide bounded-activity count or finite-replication count: those counts
|
||||
remain status and quiescence signals and can include trials, local work, and an
|
||||
outer Rebuilder flow which itself initiates a lifecycle transition. A switch
|
||||
which waited for either global count could therefore wait for the operation
|
||||
which is awaiting that same switch.
|
||||
|
||||
Production consumers cannot synchronously inspect an unreserved active
|
||||
context. They must acquire it or run work inside the admitted callback boundary.
|
||||
The synchronous `inspectActiveReplicatorContext()` view is protected and exists
|
||||
only for lifecycle diagnostics and focused tests.
|
||||
|
||||
The minimum consumer surface is a callback boundary,
|
||||
`runWithActiveReplicatorContext(callback)`, rather than an exposed lease or
|
||||
release token. Admission is ordered with lifecycle transitions, the callback
|
||||
receives one exact context, and private release runs in `finally` without
|
||||
entering the transition queue.
|
||||
|
||||
The callback must not initiate or await settings realisation, database reset or
|
||||
replacement, active Replicator retirement, or another operation which queues
|
||||
the same lifecycle transition. Such recovery or reconfiguration is staged
|
||||
after the reserved dispatch settles. A process-wide re-entrancy flag would
|
||||
both reject unrelated asynchronous work and miss re-entry after an `await`, so
|
||||
the contract is documented and tested at the owning workflows rather than
|
||||
claimed as a reliable runtime detector.
|
||||
|
||||
Failure presentation and recovery start only after the finite reservation has
|
||||
settled. A later remote mutation re-enters through the callback boundary and
|
||||
requires reference equality with the failed context. It cannot apply the
|
||||
decision produced by one publication to its replacement.
|
||||
|
||||
An edited-settings trial is different: it owns an independent Replicator and
|
||||
connection, never borrows the active publication, and disposes both resources.
|
||||
|
||||
Application suspension is a reversible host pause, not an ownership
|
||||
transition. `ReplicatorService` orders the provider's transfer-stop request but
|
||||
retains the active publication, accepts later work, and does not drain or close
|
||||
the Replicator. Provider-specific transport lifecycle, including P2P room and
|
||||
relay handling, remains independently owned.
|
||||
|
||||
Plug-in unload is terminal and reuses the same quiescing retirement as disposal;
|
||||
it does not add another public state or unload capability. The lifecycle handler
|
||||
fences admission, requests transfer cancellation, drains admitted work, and
|
||||
closes the Replicator before `ControlService` closes the local database. This
|
||||
ordering matters even when disabling the plug-in leaves the JavaScript process
|
||||
alive.
|
||||
|
||||
The generic stop role is an idempotent request to stop a provider transfer after
|
||||
transport work begins. It does not promise cancellation of readiness checks,
|
||||
@@ -450,25 +537,28 @@ resource with idempotent asynchronous `dispose()`. Trial settings are passed
|
||||
to the probe itself and cannot silently read active settings. A probe cannot
|
||||
replace the active Replicator or the P2P service.
|
||||
|
||||
Streaming Fetch receives an owned CouchDB HTTP configuration and
|
||||
`RemoteSecuritySeed` supplier directly. The supplier is bound to the selected
|
||||
configuration identity, invalidates cached seed state on reconciliation, and
|
||||
is disposed by the initial-transfer flow. It does not construct a temporary
|
||||
full Replicator.
|
||||
Streaming Fetch receives an owned Security Seed resource bound to its settings
|
||||
snapshot. The current compatibility implementation may construct an
|
||||
unpublished Replicator internally, but the resource owns and disposes it and
|
||||
cannot replace the active publication.
|
||||
|
||||
### Keep initialisation workflows explicit
|
||||
|
||||
- CouchDB and Object Storage first-device rebuilds reset and lock their central
|
||||
remote, then perform the established convergence upload.
|
||||
- A P2P first-device rebuild prepares the local database without pretending to
|
||||
reset, lock, or upload to a central remote.
|
||||
- CouchDB and Object Storage Fetch use their central full-download flow.
|
||||
- A P2P additional-device Fetch selects a peer and performs one full download.
|
||||
- CouchDB Streaming Fetch remains the separate initial-transfer service above.
|
||||
- Fetch, Rebuild, overwrite, and first-device setup remain application
|
||||
workflows. Their direction, reset, lock, peer selection, local-database work,
|
||||
and convergence passes are not one Replicator capability.
|
||||
- CouchDB and Object Storage use their established workflow-local directional
|
||||
adapters and central administration where required.
|
||||
- A P2P first device prepares only its local state. An additional P2P device
|
||||
selects a peer and uses the real finite download path; P2P does not emulate a
|
||||
central reset, lock, milestone, or upload.
|
||||
- CouchDB Streaming Fetch remains a separate initial-transfer service and uses
|
||||
only its owned Security Seed dependency.
|
||||
|
||||
The Rebuilder requests capabilities and does not cast a generic Replicator to a
|
||||
concrete class. Its `EVENT_DATABASE_REBUILT` continuation is separately
|
||||
authorised and does not imply `syncOnStart` or P2P AutoStart.
|
||||
The `EVENT_DATABASE_REBUILT` continuation remains separately authorised and
|
||||
does not imply `syncOnStart` or P2P AutoStart. Complete Rebuilder and
|
||||
maintenance-facade migration is a later bounded change rather than a condition
|
||||
for the active Replicator core.
|
||||
|
||||
## Target capability matrix for current providers
|
||||
|
||||
@@ -476,21 +566,47 @@ authorised and does not imply `syncOnStart` or P2P AutoStart.
|
||||
Configuration and reachability are request preconditions or outcomes, not
|
||||
support states.
|
||||
|
||||
| Generic role | CouchDB | Object Storage | P2P |
|
||||
| --------------------------------------- | ------- | -------------- | --- |
|
||||
| User-initiated OneShot Sync | S | S | S |
|
||||
| Unattended OneShot Sync without UI | S | S | S |
|
||||
| Ordinary long-lived Continuous session | S | NA | NA |
|
||||
| Full upload to a central remote | S | S | NA |
|
||||
| Full download | S | S | S |
|
||||
| Central remote reset | S | S | NA |
|
||||
| Central remote lock and resolution | S | S | NA |
|
||||
| Preferred-tweak Metadata read and write | S | S | NA |
|
||||
| On-demand remote Chunk source | S | NA | NA |
|
||||
| Remote storage status | S | S | NA |
|
||||
| Compromised-Chunk inspection | S | NA | NA |
|
||||
| Central-remote Security Seed | S | S | NA |
|
||||
| Request to stop active transfer | S | S | S |
|
||||
| Active provider role | CouchDB | Object Storage | P2P |
|
||||
| -------------------------------------- | ------- | -------------- | --- |
|
||||
| User-initiated OneShot Sync | S | S | S |
|
||||
| Unattended OneShot Sync without UI | S | S | S |
|
||||
| Ordinary long-lived Continuous session | S | NA | NA |
|
||||
| Request to stop active transfer | S | S | S |
|
||||
|
||||
Every provider definition records the Continuous row explicitly. CouchDB
|
||||
supplies its runner, while Object Storage and P2P declare the role not
|
||||
applicable; omission is not a fourth support state.
|
||||
|
||||
The current definition also declares the finite resources and the one optional
|
||||
central facility which have real consumers:
|
||||
|
||||
| Provider-owned facility | CouchDB | Object Storage | P2P |
|
||||
| --------------------------------------------- | ------- | -------------- | ------ |
|
||||
| Connection probe | S | S | NA |
|
||||
| Preferred-tweak probe | S | S | NA |
|
||||
| Security Seed resource | S | S | NA |
|
||||
| Synchronisation-information resource | S | NA | NA |
|
||||
| Cohesive central-remote administration runner | S | S | absent |
|
||||
|
||||
`remoteResources` is exhaustive over its four stable machine keys, so adding a
|
||||
resource requires an explicit decision from every composed provider. The
|
||||
central-remote administration field is optional because there is no corresponding
|
||||
P2P facility. Actions within that runner are the current central protocol, not
|
||||
an exhaustive capability table imposed on every Replicator.
|
||||
|
||||
The public contract is named `CentralRemoteAdministration*` because every
|
||||
current action, observation, failure, and postcondition belongs to that central
|
||||
milestone protocol. Established CLI command names remain unchanged.
|
||||
|
||||
The following concerns deliberately stay outside this capability matrix:
|
||||
|
||||
| Concern | Current owner |
|
||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
||||
| Directional Fetch and Rebuild | Application workflow over provider-specific adapters |
|
||||
| Streaming Fetch | CouchDB initial-transfer workflow plus an owned Security Seed resource |
|
||||
| On-demand remote Chunks and compromised-Chunk inspection | CouchDB compatibility or maintenance consumers |
|
||||
| Remote size, Garbage Collection, compaction, and device registry | Provider-specific inspection and maintenance flows |
|
||||
| P2P room, relay, peer selection, admission, watch, and broadcast | Stable P2P service and room-session owner in Part 2 |
|
||||
|
||||
P2P unattended OneShot means a role exists which uses configured target names
|
||||
without opening a dialogue. Peer-room, watch, acceptance, and broadcast roles
|
||||
@@ -578,3 +694,4 @@ only when every caller proves it to be the operation's identity.
|
||||
- [CouchDB Remote Connection Ownership](2026_08_couchdb_remote_connection_ownership.md)
|
||||
- [Package the Common Library Behind Explicit Host Boundaries](2026_07_common_library_package_boundary.md)
|
||||
- [Self-hosted LiveSync issue 1140](https://github.com/vrtmrz/obsidian-livesync/issues/1140)
|
||||
- [Self-hosted LiveSync issue 1147](https://github.com/vrtmrz/obsidian-livesync/issues/1147)
|
||||
|
||||
@@ -19,8 +19,8 @@ another runtime contract.
|
||||
Proposed. The stages below are an implementation and verification order, not
|
||||
independently releasable states. Commonlib and Self-hosted LiveSync must not
|
||||
publish temporary support boundaries described by an incomplete stage. A
|
||||
release follows only after the target matrix, ownership boundaries, and all
|
||||
production-consumer migrations in Parts 1 and 2 are complete.
|
||||
release follows only after the target matrix, ownership boundaries, and the
|
||||
contracted production-consumer migrations in Parts 1 and 2 are complete.
|
||||
|
||||
## Migration rules
|
||||
|
||||
@@ -215,7 +215,7 @@ sequence rather than a second description of the implemented state.
|
||||
## Stage 5: separate active construction and flow-specific probes
|
||||
|
||||
Make active creation a private, exhaustive `ReplicatorService` operation with
|
||||
an explicit same-kind rebind-or-replace policy. Migrate every non-active caller
|
||||
one configuration identity and replacement policy. Migrate every non-active caller
|
||||
before restricting `getNewReplicator()`: CouchDB connection and passphrase
|
||||
checks, Object Storage connection and preferred-tweak trials, isolated P2P
|
||||
Setup, CLI commands, and other host compositions. Prove that every probe leaves
|
||||
@@ -226,32 +226,197 @@ defined in Part 1. Add replacement-fence, late-settlement,
|
||||
configuration-identity, cache-invalidation, and probe-disposal tests before
|
||||
making active construction private.
|
||||
|
||||
## Stage 6: migrate safety-sensitive and provider-specific consumers
|
||||
### Implementation position after Stage 5
|
||||
|
||||
Migrate Setup, Rebuilder, tweak review, remote-size inspection, on-demand Chunk
|
||||
retrieval, migration inspection, maintenance, and abort commands. Central
|
||||
mutations settle truthfully before Rebuilder continuation. Compromised-Chunk
|
||||
inspection uses `observed` or `unavailable`; an offline check is never zero.
|
||||
Object Storage and P2P no longer supply dummy integrity counts, remote Chunk
|
||||
results, or Security Seeds through the compatibility facade.
|
||||
The provider-defined active-construction path is now private to
|
||||
`ReplicatorService`. The public `getNewReplicator` handler remains as a
|
||||
compatibility surface, but current Self-hosted LiveSync production code no
|
||||
longer calls it. Its removal belongs to Stage 7 after any external compatibility
|
||||
decision has been made.
|
||||
|
||||
Move local node identity initialisation out of the provider facade. Add
|
||||
idempotent asynchronous disposal and settlement tests, same-kind profile
|
||||
rebind-or-replace tests, and bounded activity around the host-owned garbage-
|
||||
collection workflow's CouchDB OneShots. Each consumer migration removes the
|
||||
corresponding generic `remoteType` or `instanceof` feature branch and adds a
|
||||
focused test.
|
||||
The current host composition has migrated CouchDB and Object Storage connection
|
||||
checks, passphrase inspection, preferred-tweak reads, CLI remote status and
|
||||
administration, isolated P2P Setup, and Streaming Fetch Security Seed access to
|
||||
owned resources or focused services. Active replacement is serialised, context
|
||||
acquisition waits for a queued replacement, late candidates are fenced, and
|
||||
short-lived resources are disposed.
|
||||
|
||||
Transport-specific settings may continue to display provider kind. Provider
|
||||
identity is valid for labels and provider-specific configuration; it is not a
|
||||
generic feature test.
|
||||
This position completes the Stage 5 construction and probe boundary. It is not
|
||||
itself a release decision: the active-publication and truthful-attempt work in
|
||||
Stage 6 remains required. Complete retirement of the compatibility facade is
|
||||
not a prerequisite for issue 1140.
|
||||
|
||||
## Stage 7: retire the giant compatibility facade
|
||||
## Stage 6: harden the active lifecycle and exact attempt outcome
|
||||
|
||||
After every current consumer has migrated, stop requiring unsupported methods
|
||||
on `LiveSyncAbstractReplicator`. Retain or remove compatibility exports at the
|
||||
next Commonlib compatibility boundary. Do not retain dummy methods only because
|
||||
the former abstract base declared them.
|
||||
Replace the active dependency on `LiveSyncAbstractReplicator` with the small
|
||||
`ReplicatorInstance` contract. Retain a publication only while its provider and
|
||||
private configuration identity are unchanged. Every changed identity fences
|
||||
new admission, requests supported transfer cancellation, drains admitted work,
|
||||
closes the old instance, and only then constructs and publishes a replacement.
|
||||
|
||||
Reserve the exact publication around typed finite dispatch and the currently
|
||||
required workflow-local directional attempts. Release before recovery or a
|
||||
dialogue. CouchDB and Journal record an immutable compatibility decision inside
|
||||
the attempt which owns the connection or borrowed client, and a later mutation
|
||||
must re-admit that failed context. Retry and Continuous paths reassess on each
|
||||
new CouchDB connection without adding another logical connection.
|
||||
|
||||
Preserve Journal storage read states through `getSyncParameters()`. Only an
|
||||
explicit `not-found` result permits `SyncParamsHandler` to create and upload new
|
||||
synchronisation parameters. An unavailable read becomes a fetch failure and
|
||||
must not regenerate the shared Security Seed. This fixes issue 1147 within the
|
||||
owned-observation boundary rather than adding another Replicator capability.
|
||||
|
||||
### Contracted Stage 6 implementation position
|
||||
|
||||
The retained implementation is deliberately smaller than the earlier complete
|
||||
consumer-migration proposal:
|
||||
|
||||
- `ReplicatorInstance` contains only initialisation, `openReplication`,
|
||||
transfer termination, and close;
|
||||
- provider definitions retain user-initiated and unattended OneShot runners,
|
||||
an explicit Continuous support decision, readiness, transfer stop, the four
|
||||
owned remote resources, and one optional cohesive central-remote administration
|
||||
runner;
|
||||
- every changed configuration identity replaces the active instance; there is
|
||||
no same-instance rebind policy;
|
||||
- typed finite dispatch reserves the exact readiness-tested publication and
|
||||
releases it before failure recovery;
|
||||
- CouchDB and Journal carry only a rejected attempt-local compatibility
|
||||
decision into the failure outcome, so a transport failure cannot reuse old
|
||||
mutable fields;
|
||||
- mismatch updates, unlock, and cleaned-remote reconciliation re-admit the
|
||||
failed publication before remote mutation;
|
||||
- P2P uses a narrow non-owning active adapter, takes the same typed finite path,
|
||||
supports its real download workflow, and exposes no central facility;
|
||||
- ordinary central preparation and Streaming Fetch use owned Security Seed
|
||||
resources which dispose their unpublished compatibility instances;
|
||||
- CLI synchronisation diagnoses lock and clean rejection from the exact outcome
|
||||
while preserving the existing success and failure return policy; and
|
||||
- Journal unavailable sync-parameter reads cannot enter the create-and-upload
|
||||
branch required only by explicit absence.
|
||||
|
||||
The active path no longer depends on the giant facade. Existing maintenance,
|
||||
remote-size, on-demand Chunk, migration-inspection, and compatibility consumers
|
||||
may still use focused structural checks or the legacy facade. Their complete
|
||||
migration, local-node-identity redesign, generic milestone extraction, and
|
||||
in-process local-database reset redesign are deferred unless a separate bounded
|
||||
change proves that they are required.
|
||||
|
||||
Each production correction has a focused regression. The verification section
|
||||
distinguishes local source and packed-consumer evidence from registry,
|
||||
real-runtime, and release validation.
|
||||
|
||||
### Active-publication quiescing boundary
|
||||
|
||||
Commonlib implements the publication-scoped callback reservation defined in
|
||||
Part 1 for finite provider dispatch, central-remote administration, exact
|
||||
recovery mutation, and the workflow-local directional attempts which use the
|
||||
active instance. Invocation queues its admission decision in the same order as
|
||||
replacement and disposal. The publication object is its private generation
|
||||
identity. Once admitted, release is idempotent, private, and independent of
|
||||
that queue so quiescing cannot prevent the operation which allows its own drain
|
||||
to settle.
|
||||
|
||||
Every switch follows the same order: fence admission, request supported
|
||||
transfer cancellation, drain admitted callbacks, close, then publish another
|
||||
context. An unchanged provider and configuration identity keeps the existing
|
||||
publication.
|
||||
|
||||
The first implementation regressions cover:
|
||||
|
||||
- replacement waiting for an admitted exact-context task while ignoring an
|
||||
unrelated bounded activity;
|
||||
- context acquisition waiting for a queued replacement rather than returning a
|
||||
stale or intermediate publication;
|
||||
- rejecting central-remote administration releasing its reservation before
|
||||
replacement continues;
|
||||
- finite failure recovery starting only after publication release;
|
||||
- directional workflow retry releasing and then re-admitting the same context;
|
||||
and
|
||||
- terminal unload draining admitted work before Replicator and local-database
|
||||
close, while reversible suspension retains the publication.
|
||||
|
||||
Keep readiness, failure presentation, dialogue, independently owned trial
|
||||
resources, P2P room-session demand, and Continuous replication outside this
|
||||
reservation. The callback TSDoc forbids awaiting a lifecycle transition which
|
||||
would wait for the same admission to settle.
|
||||
|
||||
## Stage 7: perform a bounded structural review
|
||||
|
||||
Confirm that the contracted core is minimum and robust before a commit or
|
||||
release decision. The active path must stay independent of
|
||||
`LiveSyncAbstractReplicator`, but complete migration of every compatibility
|
||||
consumer is separate work. Remove a dummy or abstract requirement only when
|
||||
its current callers have a truthful alternative; do not turn facade retirement
|
||||
into a condition for issue 1140.
|
||||
|
||||
The retained compatibility surface includes the broad
|
||||
`LiveSyncBaseCore.replicator` view and concrete central adapters required by
|
||||
maintenance and migration code. It is explicitly a partial compatibility view,
|
||||
not the active provider contract. P2P's active adapter does not inherit it.
|
||||
|
||||
CouchDB and Object Storage Journal both have a real central milestone document,
|
||||
but that fact alone does not justify a generic store. Extract a focused contract
|
||||
only when a second current caller demonstrates the same ownership and mutation
|
||||
semantics. P2P has no central milestone document and must not receive a stub or
|
||||
synthetic implementation.
|
||||
|
||||
The final structural review retains the following minimum boundaries:
|
||||
|
||||
- central provider definitions remain outside `LiveSyncBaseCore`; its thin
|
||||
registration method remains as the construction-order composition boundary;
|
||||
- P2P registration remains with the feature which owns the stable P2P service;
|
||||
- `ReplicatorService` and `ReplicationService` remain cohesive services. Their
|
||||
complex state and policy already reside in `ActiveReplicatorState`,
|
||||
`TypedReplicationCoordinator`, the readiness evaluator,
|
||||
`RemoteResourceResolver`, and `CentralRemoteAdministrationCoordinator`, so
|
||||
another split would not improve the current test seams;
|
||||
- every provider explicitly declares Continuous support or inapplicability;
|
||||
- `IReplicatorService` exposes only acquired or admitted active-context access.
|
||||
A protected synchronous inspector remains for focused lifecycle tests;
|
||||
- central-compatibility statuses, recorders, and projection helpers remain
|
||||
package-internal. Only stable rejection reason codes and public recovery
|
||||
value types remain package-index exports; and
|
||||
- redundant recovery-kind data, unused active-state identity matching, and the
|
||||
externally visible legacy administration lookup helper are removed.
|
||||
|
||||
LiveSync implements its optional central-remote administration facility through one
|
||||
shared protocol executor and provider-specific milestone readers. Provider
|
||||
composition selects the reader; a reader validates only the structural
|
||||
operations required for its CouchDB connection or Journal client before any
|
||||
remote mutation. It does not impose concrete-class identity on the generic
|
||||
runner contract.
|
||||
|
||||
The unpublished public contract, provider field, coordinator, and service
|
||||
operation use the `CentralRemoteAdministration*` name because their complete
|
||||
protocol is central-milestone-specific. The central OneShot adapters use a
|
||||
separate local structural operation instead of concrete-class identity. Stable
|
||||
capability-kind comparisons use `CAPABILITY_SUPPORT_KINDS`, and unavailable
|
||||
capabilities settle once without a redundant post-narrowing check.
|
||||
|
||||
Provider-specific configuration identities remain explicit projections of the
|
||||
settings which bind each adapter. They are not replaced with a generic identity
|
||||
builder: the current URL normalisation and setting lists are clearer at the
|
||||
provider boundary, and changing the shared header parser is separate work.
|
||||
|
||||
The review records, but does not prejudge, whether maintained Rebuild and Fetch
|
||||
workflows still require an in-process local-database reset. Prefer a Flag File and restart
|
||||
boundary if it can preserve user intent, CLI behaviour, failure recovery, and
|
||||
the maintained test workflows without losing a supported continuation path.
|
||||
Until that evidence exists, retain the current reset contract and its explicit
|
||||
Replicator-retirement ordering rather than assuming that every workflow has
|
||||
already moved to a restart.
|
||||
|
||||
It also records consumers which retain `LiveSyncLocalDB`, its physical PouchDB
|
||||
handle, or its managers. If broad retention still leaks ownership after the
|
||||
consumer migrations, keep the physical handle and teardown authority in
|
||||
`LiveSyncLocalDB`, and expose only the smallest read-only view or
|
||||
generation-bound operation contract required by each consumer. Do not cache a
|
||||
detached handle snapshot across reset. Preserve the current single active
|
||||
database contract, and add another abstraction only where the inventory shows
|
||||
a concrete lifetime or testability benefit. These recorded questions do not
|
||||
widen Stage 6 or make an anticipatory database abstraction part of this change.
|
||||
|
||||
## Verification
|
||||
|
||||
@@ -260,21 +425,29 @@ the former abstract base declared them.
|
||||
Cover:
|
||||
|
||||
- exhaustive host-composed definitions for CouchDB, Object Storage, and P2P;
|
||||
- complete support declarations and matching runtime roles;
|
||||
- the four-method active `ReplicatorInstance` contract and provider-owned
|
||||
runtime roles;
|
||||
- user-initiated, unattended, blocked, partial, cancelled, and failed OneShot
|
||||
outcomes;
|
||||
- truthful Object Storage stop or transfer failure and headless P2P outcomes;
|
||||
- observed and unavailable compromised-Chunk results, including offline;
|
||||
- active, retiring, disposed, and replacement-published states, including
|
||||
rejection of new work during retirement and late settlement;
|
||||
- same-kind rebind or replacement, configuration-identity invalidation,
|
||||
idempotent asynchronous disposal, and settlement ordering;
|
||||
- active, quiescing, disposed, and replacement-published states, including
|
||||
rejection of new work during retirement, acquisition waiting, and late
|
||||
candidate settlement;
|
||||
- unchanged-identity retention, changed-identity replacement, idempotent
|
||||
reservation release, and close ordering;
|
||||
- probes which cannot replace the active Replicator or P2P service and dispose
|
||||
owned resources;
|
||||
- the deliberately narrow active-transfer stop request, including work it
|
||||
does not claim to cancel;
|
||||
- central full-transfer and remote-administration boundaries; and
|
||||
- provider-specific P2P, CouchDB, and journal facets.
|
||||
- CouchDB compatibility and transfer using the same owned OneShot connection;
|
||||
- Journal compatibility and transfer using one settings-bound borrowed client;
|
||||
- attempt-local accepted, rejected, and not-assessed decisions, including retry
|
||||
and Continuous reassessment on newly opened CouchDB connections;
|
||||
- Journal synchronisation-parameter reads distinguishing explicit absence from
|
||||
unavailability and never writing after the latter;
|
||||
- cohesive central administration and its truthful mutation settlement; and
|
||||
- the narrow non-owning P2P active adapter, including download without a
|
||||
synthetic upload or central facility.
|
||||
|
||||
### Self-hosted LiveSync unit tests
|
||||
|
||||
@@ -302,6 +475,10 @@ Cover:
|
||||
- counterpart RPC authorisation and broadcast progress preserving no-dialogue
|
||||
authority;
|
||||
- Setup and settings validation through probes;
|
||||
- exact failed-context mismatch, unlock, and cleaned-remote recovery, including
|
||||
rejection after active replacement;
|
||||
- CLI lock diagnostics from the exact finite outcome rather than mutable fields
|
||||
on a later active Replicator;
|
||||
- first-device and additional-device initialisation for each current provider;
|
||||
- P2P as the main remote and as an adjunct transport; and
|
||||
- CLI, WebApp, and WebPeer composition against the same contracts, including
|
||||
@@ -315,12 +492,15 @@ waiting for the periodic interval, ordinary CouchDB start-up, and P2P start-up
|
||||
without an unexpected selection dialogue or transport replacement. P2P
|
||||
validation also covers an accepted configured peer advertising after room open,
|
||||
a watched peer whose remote side broadcasts, and suspension before a delayed
|
||||
AutoStart callback.
|
||||
AutoStart callback. Object Storage validation must also confirm that a
|
||||
temporarily unavailable synchronisation-parameter read does not upload a new
|
||||
Security Seed.
|
||||
|
||||
No temporary stage is a release candidate. Release readiness requires the
|
||||
target capability matrix, production-consumer migration, focused downstream
|
||||
checks with the exact packed Commonlib artefact, and the real-runtime checks
|
||||
appropriate to the changed boundary.
|
||||
target capability matrix, the contracted core and in-scope consumer migration,
|
||||
focused downstream checks with the exact packed Commonlib artefact, and the
|
||||
real-runtime checks appropriate to the changed boundary. Complete legacy-facade
|
||||
retirement remains a separately reviewed compatibility change.
|
||||
|
||||
## References
|
||||
|
||||
@@ -330,3 +510,4 @@ appropriate to the changed boundary.
|
||||
- [P2P Transport Compatibility Controls](2026_08_p2p_transport_compatibility.md)
|
||||
- [Bounded Remote Activity](2026_07_bounded_remote_activity.md)
|
||||
- [Self-hosted LiveSync issue 1140](https://github.com/vrtmrz/obsidian-livesync/issues/1140)
|
||||
- [Self-hosted LiveSync issue 1147](https://github.com/vrtmrz/obsidian-livesync/issues/1147)
|
||||
|
||||
Reference in New Issue
Block a user