Define P2P session cancellation ownership

This commit is contained in:
vorotamoroz
2026-08-27 13:18:17 +00:00
parent 56444bb98b
commit 8e5b058eef
3 changed files with 84 additions and 28 deletions
@@ -331,6 +331,12 @@ initialisation, reset, lock, unlock, and resolution settle only after their
defined remote write succeeds; a Rebuilder must not continue after an ignored
mutation failure.
`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
Capability availability and operation results are separate. A supported
@@ -367,17 +373,22 @@ active -> retiring -> disposed -> replacement published
```
Acquisitions wait for the transition and receive only the replacement. A fenced
old handle cannot start work. Disposal stops Continuous activity, 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.
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 generic stop role is an idempotent request to stop a provider transfer after
transport work begins. It does not promise cancellation of readiness checks,
Security Seed acquisition, or external storage calls which do not consume a
cancellation signal. P2P declares this role `not-implemented` until its lower
level transfer and RPC work have a real stop path.
cancellation signal. P2P implements this role through its room-session owner:
the request aborts the current finite-operation scopes without closing the room
or disabling later transfers. Its RPC request, incoming `reqSync`, and
replication batch loop consume the same effective signal. An already-started
atomic database operation may settle before cancellation completes, but no new
batch is started afterwards.
`getNewReplicator()` is not a general temporary-instance API. Setup and settings
flows request narrow probes, such as connection, preferred-tweak, or isolated
@@ -426,7 +437,7 @@ support states.
| 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 | NI |
| Request to stop active transfer | S | S | S |
P2P unattended OneShot means a role exists which uses configured target names
without opening a dialogue. Peer-room, watch, acceptance, and broadcast roles
@@ -65,7 +65,8 @@ A **P2P room session** is one active room membership and every resource whose
validity depends on that membership:
- the Trystero room, RPC actions, and `RpcRoom`;
- its internal session epoch and cancellation signal;
- its internal session epoch, session controller, and finite-operation
registry;
- advertisement state and temporary peer decisions;
- peer-bound RPC clients and remote database proxies;
- connection, diagnostic, and platform-event subscriptions; and
@@ -147,11 +148,31 @@ dialogue. Persisted or automatic acceptance may authorise an unattended path;
it cannot create local interaction authority implicitly.
Every finite operation which needs a room obtains its own internal,
session-epoch-bound demand. Acquiring another demand does not open another
session. Releasing it never closes a session still required by AutoStart,
another finite operation, or another host consumer. Demand bookkeeping is
internal to the service and is not a general consumer contract; it cannot turn
a finite transfer into persistent transport policy.
session-epoch-bound demand and operation controller. The operation consumes an
effective signal composed from the room session, its operation controller, and
any narrower caller or incoming-RPC signal. The room-session owner, rather than
the adapter or UI consumer, owns every controller and operation settlement.
Acquiring another demand does not open another session. Releasing it never
closes a session still required by AutoStart, another finite operation, or
another host consumer. A request to stop active transfer aborts the registered
finite-operation controllers but does not abort the room-session controller;
the room remains usable and later transfers obtain fresh operation controllers.
Retiring the room session aborts its session controller, which cancels every
remaining child operation. Demand and controller bookkeeping is internal to the
service and is not a general consumer contract; it cannot turn a finite transfer
into persistent transport policy.
Cancellation is cooperative and does not roll back durable work. Pull,
requested push, and bidirectional synchronisation propagate the effective
signal through the initiating RPC, incoming `reqSync`, the reverse database RPC
calls, and the replication batch loop. An atomic PouchDB read or write which has
already begun may settle. If a batch write has begun, the operation processes
its successful writes and records the batch checkpoint only after every
required revision has settled successfully. Cancellation before the write does
not advance that checkpoint. The operation then reports a cancelled result and
does not start another batch. Session retirement awaits that settlement before
releasing RPC and room resources.
### Reconcile session settings atomically
@@ -173,19 +194,18 @@ client, or policy demand remains reachable after replacement.
Reconciliation is serialised with room lifecycle operations:
1. fence new session work;
2. allow already-started finite transfers to settle, because the current lower
level transfer may not yet have a real cancellation contract;
2. abort the old session's finite-operation scopes and await their cooperative
settlement;
3. close and leave the old room in transport-owned order;
4. open and validate the candidate session; and
5. publish the replacement only after it has opened successfully.
The service never exposes a partly initialised candidate or silently interrupts
a transfer without a cancellation contract. If bounded settlement or candidate
opening fails, reconciliation reports the failure and publishes no mixed old
and new session. A candidate-open failure leaves one observable disconnected
state with policy demands unsatisfied; it does not revive the fenced session or
start an unbounded retry loop. A later lifecycle trigger or explicit connect may
retry.
The service never exposes a partly initialised candidate or treats a cancellation
request as rollback. If bounded settlement or candidate opening fails,
reconciliation reports the failure and publishes no mixed old and new session.
A candidate-open failure leaves one observable disconnected state with policy
demands unsatisfied; it does not revive the fenced session or start an unbounded
retry loop. A later lifecycle trigger or explicit connect may retry.
### Order local database replacement across both owners
@@ -258,6 +278,15 @@ host must reject concurrent probing while the active service uses those
sockets. It must not pause or close active relay sockets as a side effect of a
short-lived check.
The probe owns the same kind of lifetime controller as a room session, and
`dispose()` aborts and settles its work before releasing its own room. This
makes probe retirement bounded, but it does not turn process-global Trystero
relay state into isolated state. Runtime acquisition therefore reuses or
observes a compatible active session where the probe requires no second room,
allows a separately owned logical room only when the effective relay binding is
compatible, and otherwise returns a blocked result. It does not silently retire
the active service to make an incompatible probe possible.
### Keep provider composition explicit
The stable P2P service can be composed even when P2P is not the selected main
@@ -116,10 +116,14 @@ Preserve RTC diagnostics through `P2PDiagnostics`, rather than retaining
`rawHost`. The compatibility facade may delegate during this stage, but new
consumers cannot receive it.
Separate active-adapter release, room-session leave, and the stop request. Keep
the P2P stop role `not-implemented` until a lower-level operation exists. Add
internal session-demand ownership for finite operations and policy-held
AutoStart without exposing that bookkeeping as a general consumer API.
Separate active-adapter release, room-session leave, and the stop request.
Implement the lower-level cooperative cancellation path before declaring the
P2P stop role supported: caller abort through RPC request cancellation,
incoming-handler signal propagation, signal-bound reverse database RPC calls,
and safe batch-boundary termination in `replicateShim`. Add room-session and
operation controllers beside internal session-demand ownership for finite
operations and policy-held AutoStart, without exposing that bookkeeping as a
general consumer API.
Add ownership regressions immediately before implementation:
@@ -132,7 +136,19 @@ Add ownership regressions immediately before implementation:
advertisements do not;
- local database replacement retires database-bound feeds and publication;
- repeated replacement does not retain platform-event subscriptions;
- policy-only change waits for an already-started finite transfer to settle;
- an active-transfer stop aborts finite operations without closing the room,
while a later operation can use the same room;
- room retirement aborts both locally initiated and incoming `reqSync` work,
waits for an already-started atomic database operation to settle, and starts
no later batch;
- RPC cancellation, timeout, peer departure, and room close abort a
cancellation-aware handler rather than only discarding its eventual result;
- the inbound request context exists before request admission begins, so a
cancellation received while admission waits cannot be lost;
- cancellation retains already-settled documents and checkpoints and reports
`cancelled`, rather than claiming rollback or completion;
- a per-document batch-write failure does not advance the replication
checkpoint past the failed revision;
- explicit disconnect suppresses AutoStart and relay reconnection until
explicit connect; and
- database replacement fences both active-provider and P2P work before