mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-16 14:22:32 +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:
|
These operations do not share one support boundary:
|
||||||
|
|
||||||
- CouchDB supports unattended OneShot Sync, Continuous replication, central
|
- CouchDB supports unattended OneShot Sync, Continuous replication,
|
||||||
remote administration, and CouchDB-specific inspection and maintenance.
|
central-remote administration, and CouchDB-specific inspection and
|
||||||
|
maintenance.
|
||||||
- Object Storage supports finite journal synchronisation, central reset and
|
- Object Storage supports finite journal synchronisation, central reset and
|
||||||
lock Metadata, full upload and download, and storage-size inspection. It has
|
lock Metadata, full upload and download, and storage-size inspection. It has
|
||||||
no continuous changes feed, CouchDB Chunk source, CouchDB integrity
|
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:
|
Each provider definition supplies:
|
||||||
|
|
||||||
- canonical kind and diagnostic name;
|
- canonical kind and diagnostic name;
|
||||||
- complete support metadata for the current catalogue;
|
|
||||||
- active Replicator construction;
|
- active Replicator construction;
|
||||||
- provider configuration identity and an explicit same-kind rebind-or-replace
|
- a configuration predicate and private configuration identity;
|
||||||
policy;
|
- explicit user-initiated and unattended OneShot runners;
|
||||||
- flow-specific probe and initial-transfer dependency factories; and
|
- readiness requirements, an explicit Continuous support decision, and a
|
||||||
- provider-specific entry points required by existing current flows.
|
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
|
The host composes CouchDB and Object Storage definitions directly. A module is
|
||||||
retained only when it owns separate state or behaviour; a factory-registration-
|
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
|
kind; it never infers CouchDB by truthiness or by a negative test such as
|
||||||
'neither Object Storage nor P2P'.
|
'neither Object Storage nor P2P'.
|
||||||
|
|
||||||
If a provider caches effective connection settings, its declared rebind or
|
The private configuration identity covers every effective setting which binds
|
||||||
replacement policy keeps the active adapter current after a same-kind profile
|
the active adapter. The active publication is retained only while both the
|
||||||
change. Reconciliation is serialised with active work and leaves no old
|
provider and identity are unchanged. Every changed identity follows the same
|
||||||
credentials, Security Seed state, journal checkpoint, adapter cache, or
|
serialised replacement transition; there is no same-instance rebind branch.
|
||||||
diagnostic connection reachable from the reconciled handle.
|
|
||||||
|
|
||||||
### 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
|
The active object implements only the lifecycle and transport primitives which
|
||||||
current catalogue. An active Replicator exposes only the narrow roles marked as
|
are real for CouchDB, Object Storage Journal, and P2P:
|
||||||
supported by its definition. This gives compile-time completeness without a
|
|
||||||
giant runtime facade or a collection of Boolean flags.
|
|
||||||
|
|
||||||
The generic catalogue covers user-initiated and unattended OneShot Sync,
|
```typescript
|
||||||
ordinary long-lived Continuous replication, full upload and download, central
|
interface ReplicatorInstance {
|
||||||
reset and lock administration, preferred-tweak Metadata read and write,
|
initializeDatabaseForReplication(): Promise<boolean>;
|
||||||
on-demand remote Chunk reads, remote storage status, compromised-Chunk
|
openReplication(
|
||||||
inspection, central Security Seed, and a request to stop active transfer.
|
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 runners compose the differences in interaction authority, readiness,
|
||||||
Provider initialisation remains flow-specific: CouchDB may create a database,
|
typed settlement, explicit Continuous support or inapplicability, and P2P room
|
||||||
whereas Object Storage prepares its Security Seed and does not provision a
|
demand. Short-lived connection, preferred-tweak, Security Seed, and
|
||||||
bucket. Provider-specific CouchDB maintenance, Object Storage journal
|
synchronisation-information operations remain caller-owned resources. Central
|
||||||
checkpoint maintenance, and P2P room operations are narrowed facets, not
|
administration remains one optional cohesive runner. None of those differences
|
||||||
generic feature tests. P2P facets are defined in Part 2.
|
widens `ReplicatorInstance`.
|
||||||
|
|
||||||
Local node identity initialisation is a database and Replicator lifecycle
|
The LiveSync central-remote administration composition shares only local-identity
|
||||||
concern, not a remote capability. Replication statistics remain a
|
preparation, mutation ordering, milestone interpretation, and result
|
||||||
`ReplicatorService` telemetry sink.
|
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
|
### Make unattended work explicit and truthful
|
||||||
|
|
||||||
@@ -375,7 +404,11 @@ type ReplicationOutcome =
|
|||||||
| typeof REPLICATION_CANCELLED
|
| typeof REPLICATION_CANCELLED
|
||||||
| { readonly status: "blocked"; readonly reason: ReplicationBlockReason }
|
| { readonly status: "blocked"; readonly reason: ReplicationBlockReason }
|
||||||
| { readonly status: "partial"; readonly detail: PartialReplicationDetail }
|
| { 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,
|
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
|
defined remote write succeeds; a Rebuilder must not continue after an ignored
|
||||||
mutation failure.
|
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
|
`cancelled` means that the requested finite operation did not reach its normal
|
||||||
completion boundary. It does not promise rollback. A provider may retain
|
completion boundary. It does not promise rollback. A provider may retain
|
||||||
documents and checkpoints from batches which had already settled before the
|
documents and checkpoints from batches which had already settled before the
|
||||||
cancellation signal was observed, and a later operation resumes from that
|
cancellation signal was observed, and a later operation resumes from that
|
||||||
durable state.
|
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
|
Capability availability and operation results are separate. A supported
|
||||||
operation may fail, while an inapplicable operation must not be called or
|
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
|
Keep uncertainty where it changes a safety decision. In particular, an Object
|
||||||
result:
|
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
|
This principle does not require one generic `RemoteObservation<T>` type or an
|
||||||
type RemoteObservation<T> =
|
active-read catalogue. Existing provider-specific inspection and maintenance
|
||||||
| { readonly kind: "observed"; readonly value: T }
|
methods may retain their current compatibility surface until their real
|
||||||
| { readonly kind: "unavailable"; readonly error?: unknown };
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
### Give active ownership and probes explicit boundaries
|
### Give active ownership and probes explicit boundaries
|
||||||
|
|
||||||
`ReplicatorService` is the sole owner of the active Replicator. Replacement is
|
`ReplicatorService` is the sole owner of the active Replicator. Replacement and
|
||||||
an atomic transition under its transition lock:
|
disposal use one explicit quiescing transition under its transition lock:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
active -> retiring -> disposed -> replacement published
|
active -> quiescing -> closed -> replacement published
|
||||||
```
|
```
|
||||||
|
|
||||||
Acquisitions wait for the transition and receive only the replacement. A fenced
|
The transition removes the old publication from `current`, rejects later
|
||||||
old handle cannot start work. Disposal stops Continuous activity, requests
|
admission, requests the provider's supported transfer cancellation, and drains
|
||||||
cancellation of work which supports it, awaits work which cannot be cancelled,
|
work which was already admitted. Only then does it close the old Replicator and
|
||||||
and settles or reports every operation owned by the active adapter before
|
publish another active context. Acquisitions ordered after the
|
||||||
publication. If bounded retirement cannot settle, replacement fails visibly
|
transition receive only the replacement. A cancellation failure does not
|
||||||
and no new handle is published; the old handle is disposed when late work
|
permit the physical close boundary to be skipped. If admitted work cannot
|
||||||
settles.
|
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
|
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,
|
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
|
to the probe itself and cannot silently read active settings. A probe cannot
|
||||||
replace the active Replicator or the P2P service.
|
replace the active Replicator or the P2P service.
|
||||||
|
|
||||||
Streaming Fetch receives an owned CouchDB HTTP configuration and
|
Streaming Fetch receives an owned Security Seed resource bound to its settings
|
||||||
`RemoteSecuritySeed` supplier directly. The supplier is bound to the selected
|
snapshot. The current compatibility implementation may construct an
|
||||||
configuration identity, invalidates cached seed state on reconciliation, and
|
unpublished Replicator internally, but the resource owns and disposes it and
|
||||||
is disposed by the initial-transfer flow. It does not construct a temporary
|
cannot replace the active publication.
|
||||||
full Replicator.
|
|
||||||
|
|
||||||
### Keep initialisation workflows explicit
|
### Keep initialisation workflows explicit
|
||||||
|
|
||||||
- CouchDB and Object Storage first-device rebuilds reset and lock their central
|
- Fetch, Rebuild, overwrite, and first-device setup remain application
|
||||||
remote, then perform the established convergence upload.
|
workflows. Their direction, reset, lock, peer selection, local-database work,
|
||||||
- A P2P first-device rebuild prepares the local database without pretending to
|
and convergence passes are not one Replicator capability.
|
||||||
reset, lock, or upload to a central remote.
|
- CouchDB and Object Storage use their established workflow-local directional
|
||||||
- CouchDB and Object Storage Fetch use their central full-download flow.
|
adapters and central administration where required.
|
||||||
- A P2P additional-device Fetch selects a peer and performs one full download.
|
- A P2P first device prepares only its local state. An additional P2P device
|
||||||
- CouchDB Streaming Fetch remains the separate initial-transfer service above.
|
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
|
The `EVENT_DATABASE_REBUILT` continuation remains separately authorised and
|
||||||
concrete class. Its `EVENT_DATABASE_REBUILT` continuation is separately
|
does not imply `syncOnStart` or P2P AutoStart. Complete Rebuilder and
|
||||||
authorised and does not imply `syncOnStart` or P2P AutoStart.
|
maintenance-facade migration is a later bounded change rather than a condition
|
||||||
|
for the active Replicator core.
|
||||||
|
|
||||||
## Target capability matrix for current providers
|
## 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
|
Configuration and reachability are request preconditions or outcomes, not
|
||||||
support states.
|
support states.
|
||||||
|
|
||||||
| Generic role | CouchDB | Object Storage | P2P |
|
| Active provider role | CouchDB | Object Storage | P2P |
|
||||||
| --------------------------------------- | ------- | -------------- | --- |
|
| -------------------------------------- | ------- | -------------- | --- |
|
||||||
| User-initiated OneShot Sync | S | S | S |
|
| User-initiated OneShot Sync | S | S | S |
|
||||||
| Unattended OneShot Sync without UI | S | S | S |
|
| Unattended OneShot Sync without UI | S | S | S |
|
||||||
| Ordinary long-lived Continuous session | S | NA | NA |
|
| Ordinary long-lived Continuous session | S | NA | NA |
|
||||||
| Full upload to a central remote | S | S | NA |
|
| Request to stop active transfer | S | S | S |
|
||||||
| Full download | S | S | S |
|
|
||||||
| Central remote reset | S | S | NA |
|
Every provider definition records the Continuous row explicitly. CouchDB
|
||||||
| Central remote lock and resolution | S | S | NA |
|
supplies its runner, while Object Storage and P2P declare the role not
|
||||||
| Preferred-tweak Metadata read and write | S | S | NA |
|
applicable; omission is not a fourth support state.
|
||||||
| On-demand remote Chunk source | S | NA | NA |
|
|
||||||
| Remote storage status | S | S | NA |
|
The current definition also declares the finite resources and the one optional
|
||||||
| Compromised-Chunk inspection | S | NA | NA |
|
central facility which have real consumers:
|
||||||
| Central-remote Security Seed | S | S | NA |
|
|
||||||
| Request to stop active transfer | S | S | S |
|
| 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
|
P2P unattended OneShot means a role exists which uses configured target names
|
||||||
without opening a dialogue. Peer-room, watch, acceptance, and broadcast roles
|
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)
|
- [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)
|
- [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 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
|
Proposed. The stages below are an implementation and verification order, not
|
||||||
independently releasable states. Commonlib and Self-hosted LiveSync must not
|
independently releasable states. Commonlib and Self-hosted LiveSync must not
|
||||||
publish temporary support boundaries described by an incomplete stage. A
|
publish temporary support boundaries described by an incomplete stage. A
|
||||||
release follows only after the target matrix, ownership boundaries, and all
|
release follows only after the target matrix, ownership boundaries, and the
|
||||||
production-consumer migrations in Parts 1 and 2 are complete.
|
contracted production-consumer migrations in Parts 1 and 2 are complete.
|
||||||
|
|
||||||
## Migration rules
|
## 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
|
## Stage 5: separate active construction and flow-specific probes
|
||||||
|
|
||||||
Make active creation a private, exhaustive `ReplicatorService` operation with
|
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
|
before restricting `getNewReplicator()`: CouchDB connection and passphrase
|
||||||
checks, Object Storage connection and preferred-tweak trials, isolated P2P
|
checks, Object Storage connection and preferred-tweak trials, isolated P2P
|
||||||
Setup, CLI commands, and other host compositions. Prove that every probe leaves
|
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
|
configuration-identity, cache-invalidation, and probe-disposal tests before
|
||||||
making active construction private.
|
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
|
The provider-defined active-construction path is now private to
|
||||||
retrieval, migration inspection, maintenance, and abort commands. Central
|
`ReplicatorService`. The public `getNewReplicator` handler remains as a
|
||||||
mutations settle truthfully before Rebuilder continuation. Compromised-Chunk
|
compatibility surface, but current Self-hosted LiveSync production code no
|
||||||
inspection uses `observed` or `unavailable`; an offline check is never zero.
|
longer calls it. Its removal belongs to Stage 7 after any external compatibility
|
||||||
Object Storage and P2P no longer supply dummy integrity counts, remote Chunk
|
decision has been made.
|
||||||
results, or Security Seeds through the compatibility facade.
|
|
||||||
|
|
||||||
Move local node identity initialisation out of the provider facade. Add
|
The current host composition has migrated CouchDB and Object Storage connection
|
||||||
idempotent asynchronous disposal and settlement tests, same-kind profile
|
checks, passphrase inspection, preferred-tweak reads, CLI remote status and
|
||||||
rebind-or-replace tests, and bounded activity around the host-owned garbage-
|
administration, isolated P2P Setup, and Streaming Fetch Security Seed access to
|
||||||
collection workflow's CouchDB OneShots. Each consumer migration removes the
|
owned resources or focused services. Active replacement is serialised, context
|
||||||
corresponding generic `remoteType` or `instanceof` feature branch and adds a
|
acquisition waits for a queued replacement, late candidates are fenced, and
|
||||||
focused test.
|
short-lived resources are disposed.
|
||||||
|
|
||||||
Transport-specific settings may continue to display provider kind. Provider
|
This position completes the Stage 5 construction and probe boundary. It is not
|
||||||
identity is valid for labels and provider-specific configuration; it is not a
|
itself a release decision: the active-publication and truthful-attempt work in
|
||||||
generic feature test.
|
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
|
Replace the active dependency on `LiveSyncAbstractReplicator` with the small
|
||||||
on `LiveSyncAbstractReplicator`. Retain or remove compatibility exports at the
|
`ReplicatorInstance` contract. Retain a publication only while its provider and
|
||||||
next Commonlib compatibility boundary. Do not retain dummy methods only because
|
private configuration identity are unchanged. Every changed identity fences
|
||||||
the former abstract base declared them.
|
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
|
## Verification
|
||||||
|
|
||||||
@@ -260,21 +425,29 @@ the former abstract base declared them.
|
|||||||
Cover:
|
Cover:
|
||||||
|
|
||||||
- exhaustive host-composed definitions for CouchDB, Object Storage, and P2P;
|
- 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
|
- user-initiated, unattended, blocked, partial, cancelled, and failed OneShot
|
||||||
outcomes;
|
outcomes;
|
||||||
- truthful Object Storage stop or transfer failure and headless P2P outcomes;
|
- truthful Object Storage stop or transfer failure and headless P2P outcomes;
|
||||||
- observed and unavailable compromised-Chunk results, including offline;
|
- active, quiescing, disposed, and replacement-published states, including
|
||||||
- active, retiring, disposed, and replacement-published states, including
|
rejection of new work during retirement, acquisition waiting, and late
|
||||||
rejection of new work during retirement and late settlement;
|
candidate settlement;
|
||||||
- same-kind rebind or replacement, configuration-identity invalidation,
|
- unchanged-identity retention, changed-identity replacement, idempotent
|
||||||
idempotent asynchronous disposal, and settlement ordering;
|
reservation release, and close ordering;
|
||||||
- probes which cannot replace the active Replicator or P2P service and dispose
|
- probes which cannot replace the active Replicator or P2P service and dispose
|
||||||
owned resources;
|
owned resources;
|
||||||
- the deliberately narrow active-transfer stop request, including work it
|
- the deliberately narrow active-transfer stop request, including work it
|
||||||
does not claim to cancel;
|
does not claim to cancel;
|
||||||
- central full-transfer and remote-administration boundaries; and
|
- CouchDB compatibility and transfer using the same owned OneShot connection;
|
||||||
- provider-specific P2P, CouchDB, and journal facets.
|
- 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
|
### Self-hosted LiveSync unit tests
|
||||||
|
|
||||||
@@ -302,6 +475,10 @@ Cover:
|
|||||||
- counterpart RPC authorisation and broadcast progress preserving no-dialogue
|
- counterpart RPC authorisation and broadcast progress preserving no-dialogue
|
||||||
authority;
|
authority;
|
||||||
- Setup and settings validation through probes;
|
- 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;
|
- first-device and additional-device initialisation for each current provider;
|
||||||
- P2P as the main remote and as an adjunct transport; and
|
- P2P as the main remote and as an adjunct transport; and
|
||||||
- CLI, WebApp, and WebPeer composition against the same contracts, including
|
- 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
|
without an unexpected selection dialogue or transport replacement. P2P
|
||||||
validation also covers an accepted configured peer advertising after room open,
|
validation also covers an accepted configured peer advertising after room open,
|
||||||
a watched peer whose remote side broadcasts, and suspension before a delayed
|
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
|
No temporary stage is a release candidate. Release readiness requires the
|
||||||
target capability matrix, production-consumer migration, focused downstream
|
target capability matrix, the contracted core and in-scope consumer migration,
|
||||||
checks with the exact packed Commonlib artefact, and the real-runtime checks
|
focused downstream checks with the exact packed Commonlib artefact, and the
|
||||||
appropriate to the changed boundary.
|
real-runtime checks appropriate to the changed boundary. Complete legacy-facade
|
||||||
|
retirement remains a separately reviewed compatibility change.
|
||||||
|
|
||||||
## References
|
## References
|
||||||
|
|
||||||
@@ -330,3 +510,4 @@ appropriate to the changed boundary.
|
|||||||
- [P2P Transport Compatibility Controls](2026_08_p2p_transport_compatibility.md)
|
- [P2P Transport Compatibility Controls](2026_08_p2p_transport_compatibility.md)
|
||||||
- [Bounded Remote Activity](2026_07_bounded_remote_activity.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 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