Document the implemented Replicator architecture

- mark capability and lifecycle ADRs as accepted
- add lifecycle, fencing, and provider-extension guidance
- split project terminology into a dedicated glossary
This commit is contained in:
vorotamoroz
2026-09-03 06:42:34 +00:00
parent d00c5ecc56
commit 2461d37ead
12 changed files with 855 additions and 174 deletions
+21 -7
View File
@@ -1,9 +1,23 @@
---
date: 2026-09-03
commonlib-version: "0.1.21"
self-hosted-livesync-version: "1.0.24"
status: accepted
---
# Architectural Decision Record: P2P Room and Transport Lifecycle
## Status
Accepted — implemented and verified through Commonlib owner tests, the Compose transport suite, and the real-Obsidian setup workflow.
The stable P2P service and room-session owner accepted in
[Replicator Capabilities and Lifecycle Orchestration — Part 2](2026_08_replicator_capabilities_02_p2p_service_lifecycle.md)
supersede only this record's replaceable LiveSync P2P Replicator and ownership
of the replaceable result returned by the `serviceFeature`. This record remains
authoritative for serialised room operations, `room.leave()`, Trystero-owned
physical peers, and relay reconnection.
## Context
Self-hosted LiveSync uses Trystero's Nostr strategy for P2P discovery, signalling, and WebRTC transport. Three related resources have different owners and lifetimes:
@@ -12,7 +26,7 @@ Self-hosted LiveSync uses Trystero's Nostr strategy for P2P discovery, signallin
- Trystero owns the underlying WebRTC peers and may share one physical peer across more than one room; and
- Trystero's Nostr relay manager owns WebSocket clients shared by relay URL.
Closing every `RTCPeerConnection` returned by `room.getPeers()` bypasses Trystero's shared-peer manager. The manager may then retain a stale shared peer and prevent a replacement LiveSync replicator from discovering the same remote peer again.
Closing every `RTCPeerConnection` returned by `room.getPeers()` bypasses Trystero's shared-peer manager. The manager may then retain a stale shared peer and prevent a replacement LiveSync Replicator from discovering the same remote peer again.
Room departure and physical transport destruction are not equivalent. `room.leave()` sends the room-leave action, removes that room's actions and callbacks, and detaches its shared-peer binding. Trystero may retain a healthy physical WebRTC peer for later reuse after the last room binding has gone. The retained peer cannot carry actions for the room which has been left.
@@ -40,7 +54,7 @@ The explicit disconnect operation therefore has the following contract:
This operation is a logical LiveSync disconnection and a physical signalling-server disconnection. It does not promise that every browser-owned WebRTC object has been destroyed synchronously.
An explicit connect resumes relay reconnection before opening a new room. Settings application and database lifecycle replacement close the current LiveSync replicator, discard it, construct a new instance from the current settings, and open that current instance when the configured policy requires it. Commands, event handlers, and panes resolve the current service-feature result at the point of use rather than retaining an obsolete replicator.
An explicit connect resumes relay reconnection before opening a new room. Settings application and database lifecycle replacement close the current LiveSync Replicator, discard it, construct a new instance from the current settings, and open that current instance when the configured policy requires it. Commands, event handlers, and panes resolve the focused views returned by the current P2P `serviceFeature` at the point of use rather than retaining an obsolete Replicator.
Lifecycle operations on one `LiveSyncTrysteroReplicator` are serialised. A close requested while an open is in progress must leave no orphan room serving, and repeated opens must not create parallel rooms. No fixed delay is inserted between close and open: readiness is determined by the actual lifecycle operation and peer discovery.
@@ -50,7 +64,7 @@ P2P setup follows the transport's actual ownership model. Initialising the first
## Ownership
Commonlib owns the LiveSync-specific P2P service, RPC, command, and lifecycle composition. Trystero owns WebRTC peer creation, sharing, reuse, stale detection, and destruction, as well as relay-client reconstruction. The Self-hosted LiveSync host owns the current Commonlib service-feature result and supplies the platform services used by its current replicator.
Commonlib owns the LiveSync-specific P2P service, RPC, command, and lifecycle composition. Trystero owns WebRTC peer creation, sharing, reuse, stale detection, and destruction, as well as relay-client reconstruction. The Self-hosted LiveSync host owns the focused views returned by the current Commonlib P2P `serviceFeature` and supplies the platform services used by its current Replicator.
Self-hosted LiveSync does not add a separate root Trystero dependency. Tests which must observe relay sockets resolve the exact Trystero generation owned by the locked Commonlib package, avoiding two independent transport singletons in one process.
@@ -58,7 +72,7 @@ Self-hosted LiveSync does not add a separate root Trystero dependency. Tests whi
### Close every value returned by `room.getPeers()`
This bypasses Trystero's shared-peer manager and can prevent a replacement replicator from rediscovering the same peer.
This bypasses Trystero's shared-peer manager and can prevent a replacement Replicator from rediscovering the same peer.
### Add a fixed close-to-open delay
@@ -76,15 +90,15 @@ This interferes with Trystero's shared relay clients. The public pause and resum
Commonlib unit tests prove that normal P2P host closure calls `room.leave()` without directly closing Trystero-owned peer connections. Additional package tests cover the action API, replaceable peer-event subscriptions, multiple RPC transport disposers, serialised open and close operations, initialisation of the first device without a central remote, and Fetch running once for an additional device.
Self-hosted LiveSync unit tests prove that settings and database replacement leave panes on the current replicator, and that an explicit P2P rebuild bypasses the policy intended for ordinary replication.
Self-hosted LiveSync unit tests prove that settings and database replacement leave panes on the current Replicator, and that an explicit P2P rebuild bypasses the policy intended for ordinary replication.
The canonical Compose P2P suite uses a real local Nostr relay and WebRTC implementation. It covers ordinary two-peer synchronisation, replacement of the active LiveSync replicator followed by discovery and transfer with the same peer, and explicit relay disconnection followed by paused and resumed reconnection. The lifecycle scenario is exposed only through a Docker test build and an injected CLI command runner; it is not part of the public CLI command surface.
The canonical Compose P2P suite uses a real local Nostr relay and WebRTC implementation. It covers ordinary two-peer synchronisation, replacement of the active LiveSync Replicator followed by discovery and transfer with the same peer, and explicit relay disconnection followed by paused and resumed reconnection. The lifecycle scenario is exposed only through a Docker test build and an injected CLI command runner; it is not part of the public CLI command surface.
The real-Obsidian P2P Setup URI workflow creates the first device, generates the second-device URI from it, accepts each peer visibly, and verifies a two-way note round-trip through a local relay. A separate focused pane test covers the principal connection control and teardown without requiring a remote peer. Transport replacement and relay-socket lifecycle remain owned by the package and Compose tests rather than being duplicated in Obsidian.
## Consequences
- Replacing a P2P replicator no longer leaves host views or commands bound to an obsolete instance.
- Replacing a P2P Replicator no longer leaves host views or commands bound to an obsolete instance.
- Explicit signalling-server disconnection has a testable socket-level meaning without claiming immediate destruction of idle WebRTC objects.
- Settings which change the relay, room, passphrase, or TURN configuration can replace the whole LiveSync room safely.
- Trystero may reuse healthy peers across room lifecycles, reducing unnecessary renegotiation.
@@ -1,8 +1,8 @@
---
date: 2026-08-27
commonlib-version: "0.1.20"
self-hosted-livesync-version: "1.0.21"
status: proposed
date: 2026-09-02
commonlib-version: "0.1.21"
self-hosted-livesync-version: "1.0.23"
status: accepted
series: replicator-capabilities-and-lifecycle
part: 1 of 3
---
@@ -15,15 +15,20 @@ then [Part 3: migration plan and verification](2026_08_replicator_capabilities_0
## Status
Proposed. This record defines the provider, capability, lifecycle, interaction,
Accepted and implemented in Commonlib 0.1.21 and Self-hosted LiveSync 1.0.23.
This record defines the provider, capability, lifecycle, interaction,
ownership, and probe boundaries required by current Self-hosted LiveSync
consumers. It is the generic part of the series; the P2P-specific ownership
rules live in Part 2, and implementation sequencing lives in Part 3.
rules live in Part 2, and the completed implementation sequence lives in Part
3. The current structure is summarised in the
[Replicator architecture](../design_docs/replicator_architecture.md) design
document.
The accepted P2P room and transport lifecycle record remains authoritative for
the current P2P implementation until Stage 3 in Part 3 is complete. The
supersession boundary for that record is stated in Part 2 and is not repeated
here.
Stage 3 in Part 3 is complete. The stable P2P service and room-session owner in
Part 2 supersede the replaceable LiveSync P2P Replicator ownership described by
the earlier P2P room and transport lifecycle record. That accepted record
remains authoritative for its retained Trystero room, physical-peer, and relay
ownership decisions.
## Context
@@ -235,12 +240,14 @@ supplies an exhaustive definition table for that set. The current catalogue is
CouchDB, Object Storage, and P2P; it is not a public third-party registration
API.
CouchDB is part of every current host composition. Object Storage and P2P are
compile-time composition choices and may be included or omitted without
changing the generic scheduling feature. Adding another current provider
requires a Commonlib kind and support declaration, host composition,
Setup/profile schema handling, and provider-specific tests. It does not require
a runtime plug-in registry or behaviour for unknown provider kinds.
Every current `LiveSyncBaseCore` host composes CouchDB and Object Storage.
`WebPeerRuntime` is a separate P2P-only host composition, and P2P remains a
compile-time feature choice for the other hosts. A host can include or omit a
provider without changing the generic scheduling feature. Adding another
current provider requires a Commonlib kind and support declaration, host
composition, Setup/profile schema handling, and provider-specific tests. It
does not require a runtime plug-in registry or behaviour for unknown provider
kinds.
Each provider definition supplies:
@@ -777,6 +784,7 @@ when every caller proves it to be the operation's identity.
## References
- [Project glossary](../glossary.md#developer-and-design-terms)
- [Part 2: P2P service and session lifecycle](2026_08_replicator_capabilities_02_p2p_service_lifecycle.md)
- [Part 3: migration plan and verification](2026_08_replicator_capabilities_03_migration_plan.md)
- [Bounded Remote Activity](2026_07_bounded_remote_activity.md)
@@ -1,8 +1,8 @@
---
date: 2026-08-27
commonlib-version: "0.1.20"
self-hosted-livesync-version: "1.0.21"
status: proposed
date: 2026-09-02
commonlib-version: "0.1.21"
self-hosted-livesync-version: "1.0.23"
status: accepted
series: replicator-capabilities-and-lifecycle
part: 2 of 3
---
@@ -14,20 +14,24 @@ first, then continue with [Part 3: migration plan and verification](2026_08_repl
## Status
Proposed. This record defines the P2P service owner, room-session boundary,
narrow contract views, automation demands, replacement fencing, and trigger
Accepted and implemented in Commonlib 0.1.21 and Self-hosted LiveSync 1.0.23.
This record defines the P2P service owner, room-session boundary, narrow
contract views, automation demands, replacement fencing, and trigger
semantics. Generic provider and capability rules are owned by Part 1; the
implementation and verification order is owned by Part 3.
completed implementation and verification order is recorded in Part 3.
The implemented state is recorded separately in Commonlib's
`docs/p2p-transport-lifecycle.md` design document. It supersedes the
replaceable LiveSync P2P Replicator and current-result ownership described by
[P2P transport lifecycle](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/p2p-transport-lifecycle.md)
design document and summarised with the generic provider lifecycle in the
[Replicator architecture](../design_docs/replicator_architecture.md) design
document. It supersedes the replaceable LiveSync P2P Replicator and ownership
of the replaceable result returned by the `serviceFeature`, as described by
the accepted [P2P Room and Transport Lifecycle](2026_07_p2p_transport_lifecycle.md)
record. The accepted record's decisions about serialised room operations,
record.
The accepted record's decisions about serialised room operations,
`room.leave()`, Trystero-owned physical peers, and relay reconnection remain in
force. This ADR remains the decision and migration target; the Commonlib
design document records the names and ownership boundaries which actually
landed.
force. This ADR records the product decision; the Commonlib design document
records the implemented names and ownership boundaries.
## Scope and context
@@ -397,6 +401,7 @@ and does not publish a second P2P lifecycle owner.
## References
- [Project glossary](../glossary.md#developer-and-design-terms)
- [Part 1: core contract](2026_08_replicator_capabilities_01_core_contract.md)
- [Part 3: migration plan and verification](2026_08_replicator_capabilities_03_migration_plan.md)
- [P2P Room and Transport Lifecycle](2026_07_p2p_transport_lifecycle.md)
@@ -1,8 +1,8 @@
---
date: 2026-08-27
commonlib-version: "0.1.20"
self-hosted-livesync-version: "1.0.21"
status: proposed
date: 2026-09-02
commonlib-version: "0.1.21"
self-hosted-livesync-version: "1.0.23"
status: accepted
series: replicator-capabilities-and-lifecycle
part: 3 of 3
---
@@ -16,11 +16,14 @@ another runtime contract.
## Status
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 the
contracted production-consumer migrations in Parts 1 and 2 are complete.
Accepted and implemented in Commonlib 0.1.21 and Self-hosted LiveSync 1.0.23.
The stages below record the implementation and verification order; they were
not independently releasable states. The target matrix, ownership boundaries,
and contracted production-consumer migrations in Parts 1 and 2 are complete.
Items which Stage 7 explicitly defers remain separate compatibility work rather
than incomplete stages. The current result is summarised in the
[Replicator architecture](../design_docs/replicator_architecture.md) design
document.
## Migration rules
@@ -103,11 +106,11 @@ until every remaining demand has settled. The LiveSync feature-binding test
must not rely on the current registration order of equal-priority resume
handlers.
Until Stage 4 supplies target-aware unattended P2P, each host composition
declares generic `P2P_SyncOnReplication` as `not-implemented`. Its automatic
request settles without UI with an explicit blocked result. Existing AutoSync,
AutoWatch, and accepted incoming-request paths continue with the Stage 2 gate.
This is a temporary migration state, not the target matrix in Part 1.
Before Stage 4 supplied target-aware unattended P2P, each host composition
declared generic `P2P_SyncOnReplication` as `not-implemented`. Its automatic
request settled without UI with an explicit blocked result. Existing AutoSync,
AutoWatch, and accepted incoming-request paths continued with the Stage 2 gate.
This was a temporary migration state, not the target matrix in Part 1.
Apply and test the CLI scheduling precedence defined in Part 1, so the daemon
and scheduling context cannot schedule duplicate initial or recurring work.
@@ -178,10 +181,11 @@ Add ownership regressions immediately before implementation:
publishing the new database identity, while a failed candidate leaves one
observable disconnected state without reviving the fenced session.
When this stage lands, add a supersession note to the accepted P2P lifecycle
record and update `devs.md` from the replaceable concrete Replicator getter to
the stable contract views. Preserve the accepted Trystero peer and relay
ownership rules rather than rewriting their historical verification.
Completion of this stage added a bounded supersession note to the accepted P2P
lifecycle record and updated `devs.md` from the replaceable concrete Replicator
getter to the stable contract views. The accepted Trystero peer and relay
ownership rules remain in force rather than being rewritten as part of this
migration.
## Stage 4: add target-aware unattended P2P orchestration
@@ -203,14 +207,17 @@ shared-pane synchronisation.
Keep the detailed wait, session-demand, de-duplication, and session-epoch state
machine in Part 2 rather than expanding the generic provider contract. If
implementation evidence requires a refinement, amend Part 2 before completing
this stage. After Stage 3 is complete, Part 2 supersedes the
replaceable-Replicator and current-result ownership portions of the accepted
July 2026 record; its Trystero peer and relay decisions remain unchanged.
this stage. With Stage 3 complete, Part 2 supersedes the portions of the
accepted July 2026 record concerning the replaceable Replicator and ownership
of the replaceable result returned by the `serviceFeature`. Its Trystero peer
and relay decisions remain unchanged.
Commonlib's `docs/p2p-transport-lifecycle.md` design document records the
implemented Stage 3 and Stage 4 ownership, demand, automation, replacement,
and shutdown behaviour. This document remains the migration and verification
sequence rather than a second description of the implemented state.
Commonlib's
[P2P transport lifecycle](https://github.com/vrtmrz/livesync-commonlib/blob/main/docs/p2p-transport-lifecycle.md)
design document records the implemented Stage 3 and Stage 4 ownership, demand,
automation, replacement, and shutdown behaviour. This document remains the
migration and verification sequence rather than a second description of the
implemented state.
## Stage 5: separate active construction and flow-specific probes
@@ -231,8 +238,8 @@ making active construction private.
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.
longer calls it. Stage 7 reviewed its possible removal and deferred it pending
an external compatibility decision.
The current host composition has migrated CouchDB and Object Storage connection
checks, passphrase inspection, preferred-tweak reads, CLI remote status and
@@ -246,10 +253,11 @@ against the active relay binding held by the stable P2P service. The Stage 7
review identified and completed that remaining owner boundary; it did not
reopen the active-construction contract.
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.
This position completed the Stage 5 construction and probe boundary. At that
intermediate point it was not itself a release decision: Stage 6 still had to
complete the active-publication lifecycle and return an exact outcome for each
attempt. Complete retirement of the compatibility facade was not a prerequisite
for issue 1140.
## Stage 6: harden the active lifecycle and exact attempt outcome
@@ -342,8 +350,8 @@ publication.
The first implementation regressions cover:
- replacement waiting for an admitted exact-context task while ignoring an
unrelated bounded activity;
- replacement waiting for a task admitted against the exact publication 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
@@ -711,6 +719,7 @@ retirement remains a separately reviewed compatibility change.
## References
- [Project glossary](../glossary.md#developer-and-design-terms)
- [Part 1: core contract](2026_08_replicator_capabilities_01_core_contract.md)
- [Part 2: P2P service and session lifecycle](2026_08_replicator_capabilities_02_p2p_service_lifecycle.md)
- [P2P Room and Transport Lifecycle](2026_07_p2p_transport_lifecycle.md)