Expand description
Transport-agnostic client participant state and sealed effects.
The client aggregate owns correlation, detach replay, and the durability barrier for one outstanding operation. The authorized round-3 order is commit-seal, persist the committed resume record, then release executable authority; pending has no durable form.
§LP-CLIENT-GOAL API-shape rationale
The Phase 1 brief requires authority-safe shapes rather than caller-owned state parts. The resulting public shape is deliberate:
- Replay and reconnect transitions consume and return the root aggregate so their facts are persisted atomically; standalone state-part recomposition is not representable.
ReconnectAggregatehas no public constructor because fresh detached reconnect state would separate permit identity from participant facts.recover_reconnect_permitexists because an unissued committed cold record must release its permit once without making permits cloneable.- Only the commit seal exposes a durable record; pending has no encoder. The
authorized round-3 order is commit-seal, persist committed
LPCR, release. - The retained name
crate::outcome::ReconnectDelayResultcarries an event, never a delay: the brief explicitly supersedes timer scheduling. - A different retained detach is refused while live, but terminal or attach-superseded replay yields only to an exact newer-generation detach.
- Terminalized-detach fixture construction remains
cfg(test)only; wire authority construction is not weakened in production. - Detach recording is atomic with
record_operation, so no public raw envelope-to-replay mint or second caller-owned persistence step exists. DetachTransportFateis closed to response unavailability because this protocol crate owns no socket, runtime, or transport handle.DetachReplayOutcomeis exhaustive so a generic server value cannot be relabeled by a caller as one of the three terminal detach outcomes.- Reconnect fresh-event producers are separate typed functions rather than a generic event-injection seam, limiting minting to the brief’s classes.
recover_expected_operationis the one-use post-restore counterpart to the pending-to-commit barrier; detach recovery also marks replay in flight.- Replay inspection returns
Noneonly for its named Empty state; terminal payloads remain lossless and distinct. - There is no speculative persistence format. A pending-window crash means the operation did not happen and restart may record it again.
RecordAdmissionresponses are always ambiguous because wire identity is insufficient;ObserverRecoverycompares its echoed list. As the M7 companion rule, both tokenless classes resolve as typed abandoned on every restore and are never re-released. A later sealed-transport-context SDK leg may add outbound attempt tokens and lift this restriction.- A crash or restore that destroys live authority mints a serialized,
take-once
LostAuthorityTestimonywith no public constructor (LP-CLIENT-GOALpiece 4, r2, 2026-07-18). Every public fate or recovery entry point consumes either a live one-use correlation, a one-use sealed attempt authority, or the pending serialized testimony; no publicly constructible process-fate value exists, so a fate that consumes neither is unrepresentable at the API surface. - Detached bindings retain the attach secret because the complete client record must remain capable of a later credential attach after restart.
- Expected recovery and replay-start atomically share one detach issuance bit, guaranteeing one first-send authority in either call order.
- Both pending atoms use the retain-in-bytes encode shape (
LP-CLIENT-GOALpiece 2, r2, 2026-07-18): encoding an aggregate that holds a pending testimony or abandonment emits bytes that carry the atom, so encode-without-take loses nothing and no checkpoint window is refused. The refuse-while-pending shape was rejected because piece 4 requires the testimony to round-trip losslessly through the aggregate encoding. - Re-recording the retained detach envelope requires replay-status
compatibility with a fresh first send: only
Parkedadmits; superseded, Leave-superseded, terminal, and in-flight statuses refuse with typedClientOperationRecordRefusalReason::DetachReplayIncompatible(r2, 2026-07-18), closing the round-4 door that revived expected-detach authority over an inactive replay.
§Exhaustive constructible-state audit
Every state accepted by restore or reachable through a public apply path is listed here. The exhaustive conservation property test mechanically covers the live authority and typed consumption columns across 610 applied paths from a 4-operation × 11-action alphabet through depth 7, attempting every action at every step: 1041 attempts end in the crate’s typed refusal and 1748 are unrepresentable because the consumed one-use value does not exist at the type level. Every row below is either reachable-and-tested or refused-by-construction with the refusing type named.
| Owned state | Restore/apply acceptance | Live authority | Typed consumption / exit |
|---|---|---|---|
Binding Unbound | new, restore | 0 | enrollment/attach → Bound; identity-bound requests refuse |
Binding Bound | enrollment/attach, restore | 0 | detach result → Detached; Leave/Retired → Left |
Binding Detached | detach result, restore | 0 | exact-secret attach → Bound; Leave/Retired → Left |
Binding Left | correlated Leave/Retired, restore | 0 | permanent; inbound/outbound return AlreadyDead |
Expected None | new, abort, consumed outcome/fate, restore | 0 | one record_operation admission |
| Tokenless expected, live process only | record/commit/release | 0 or 1 | exact response remains conservative; fate consumes; every restore converts it into the durable TokenlessAfterCrash abandonment atom below |
| Token-bearing non-detach, unissued | committed LPCR, restore | 0 | recover_expected_operation issues once |
| Token-bearing non-detach, issued | release/recovery, restore | 1 live, or serialized testimony after restore | correlated outcome/fate consumes the live correlation; restore mints the take-once testimony consumed only by resolve_lost_operation_authority |
Expected detach + replay Parked | commit, live fate, testimony resolution, restore only when exact and unissued | 0 | recovery or replay start issues exactly one effect |
Expected detach + replay InFlight | release/start, restore only when exact and issued | 1 live, or serialized testimony after restore | correlated outcome/fate consumes the live correlation; restore mints the take-once testimony whose resolve_lost_operation_authority resolution parks exact-token replay |
Expected detach + replay Empty, Superseded, LeaveSuperseded, or terminal | never accepted, unreachable by construction | 0 | refused at restore by ClientResumeRestoreError::ExpectedDetachActiveReplayMismatch and in live code by ClientOperationRecordRefusalReason::DetachReplayIncompatible, which closes the only door that could re-couple an expected detach to an inactive replay |
| Active replay without exact expected detach | never accepted | 0 | typed ActiveReplayExpectedDetachMismatch restore refusal |
Replay Empty | new, abort, restore without expected detach | 0 | admitted detach records Parked atomically |
Replay Superseded | authority-consuming matching attach, restore | 0 | old generation terminal; exact newer generation may replace; same-envelope re-record refused by construction (DetachReplayIncompatible) |
Replay LeaveSuperseded | authority-consuming matching durable Leave, restore | 0 | proves only that matching Leave/retirement superseded replay; public apply_leave_durable does not change binding to Left; same-envelope re-record refused by construction (DetachReplayIncompatible) |
| Replay terminal (three exact payload arms) | authority-consuming exact outcome, restore | 0 | lossless terminal; exact newer-generation detach may replace; same-envelope re-record refused by construction (DetachReplayIncompatible) |
| Restored-loss testimony, operation slot | minted only by validated restore of an issued token-bearing operation; carried losslessly by encode/decode | counts as the destroyed authority | consumed exactly once by resolve_lost_operation_authority; coupling refusals in both directions: a serialized atom without its issued state (or with the wrong kind) is refused by construction by ClientResumeRestoreError::LostAuthorityTestimonyMismatch, and every live consumption of the testified state is refused reachable-and-tested by the typed LostAuthorityPending reasons on decide_correlated_inbound, record_expected_operation_fate, transport_fate, apply_attach, apply_leave_durable, and apply_detach_outcome |
| Restored-loss testimony, reconnect slot | minted only by validated restore of an issued permit or in-progress attempt; carried losslessly by encode/decode | counts as the destroyed authority | consumed exactly once by resolve_lost_reconnect_authority; coupling refusals in both directions: a serialized atom without its matching machine state is refused by construction by ClientResumeRestoreError::LostAuthorityTestimonyMismatch, and prior-process handles are refused reachable-and-tested by ReconnectAttemptRefusalReason::LostAuthorityPending and ReconnectAttemptFateRefusalReason::LostAuthorityPending |
Pending TokenlessAfterCrash abandonment | minted by restore of a tokenless expected operation; carried losslessly by encode/decode with its issued flag | was_issued marks a destroyed authority | taken exactly once by ClientParticipantAggregate::take_restored_operation_abandonment; a second take observes nothing; coupling refusals in both directions: a serialized abandonment beside a tokenless expected operation is refused by construction by ClientResumeRestoreError::PendingAbandonmentConflict, and tokenless admission while pending is refused reachable-and-tested by ClientOperationRecordRefusalReason::AbandonmentPending |
Reconnect Parked | new/failure/loss resolution, restore | 0 | typed fresh event → permit |
| Reconnect permit unissued | committed restore testimony | 0 | one recover_reconnect_permit issue |
| Reconnect permit issued | event/recovery, restore | 1 live, or serialized testimony after restore | held permit → attempt; restore mints the take-once testimony consumed only by resolve_lost_reconnect_authority |
| Reconnect attempt | permit redemption, restore | 1 live, or serialized testimony after restore | held fate → Online/Parked; restore mints the take-once testimony consumed only by resolve_lost_reconnect_authority |
Reconnect Online | successful fate, restore | 0 | later typed fresh event → permit |
Structs§
- Client
Continuous Operation - Continuous acknowledgement that bypasses the write-ahead slot.
- Client
Correlated Inbound Refusal - Refused body-omitting response with the exact local correlation retained.
- Client
Inbound Applied - Applied inbound value and resulting aggregate.
- Client
Inbound Refusal - Refused inbound value paired with the unchanged aggregate.
- Client
Operation Commit - Committed operation decision that still seals aggregate and execution authority.
- Client
Operation Record Refusal - Unchanged aggregate and request refused before persistence.
- Client
Participant Aggregate - Non-cloneable client participant state shell.
- Client
Pending Operation Record - Pending decision whose successor and executable parts remain unreachable.
- Client
Response Correlation - Non-cloneable local correlation for responses that omit request body identity.
- Client
Resume Record - Private-field, inert, canonical client persistence record.
- Detach
Replay Applied - Applied detach replay transition.
- Detach
Replay Refusal - Refused detach replay transition with unchanged aggregate and input.
- Detach
Transport Attempt - Sealed effect authorizing one transport send of the exact detach.
- Expected
Participant Operation - Sealed, non-cloneable authority to execute exactly the committed operation.
- Lost
Authority Testimony - Serialized, take-once testimony that live process-local authority was
destroyed by crash or restore (
LP-CLIENT-GOALpiece 4, r2, 2026-07-18). - Reconnect
Aggregate - Non-cloneable reconnect producer and single-attempt state shell.
- Reconnect
Attempt Permit - Sealed, non-cloneable authority for one real connection attempt.
- Reconnect
InProgress Attempt - Sealed in-progress authority held while the binding opens a real connection.
- Reconnect
Permit Refusal - Fresh-event refusal with unchanged aggregate and retained event.
- Restored
Expected Operation Abandonment - Typed restore resolution for an operation that cannot safely be re-issued.
- SdkDetach
Replay Aggregate - Non-cloneable owner of the exact detach replay envelope and lifecycle.
Enums§
- Apply
Attach Decision - Decision for applying a matching newer attach to replay.
- Apply
Detach Outcome Decision - Decision for terminalizing detach replay.
- Apply
Leave Decision - Decision for applying a durable Leave to replay.
- Client
Binding Status - Coarse client binding state without exposing credential-bearing state parts.
- Client
Correlated Inbound Decision - Inbound decision for response classes whose wire envelopes omit request identity.
- Client
Inbound Decision - Exhaustive inbound correlation decision.
- Client
Inbound Refusal Reason - Closed refusal classes for inbound semantic values.
- Client
Operation Record Decision - Complete write-ahead admission decision.
- Client
Operation Record Refusal Reason - Reason an operation could not enter the write-ahead slot.
- Client
Resume Record Decode Error - Typed canonical client-record decode failure.
- Client
Resume Record Encode Error - Failure while creating a canonical record from live client state.
- Client
Resume Record Section - Section whose tag or nested canonical frame was invalid.
- Client
Resume Restore Error - Validated cold-restore invariant failure.
- Detach
Replay Outcome - Typed terminal detach outcome accepted by replay.
- Detach
Replay Refusal Reason - Reason a detach replay input was refused unchanged.
- Detach
Replay Status - Closed, lossless detach replay status vocabulary.
- Detach
Replay Terminal - Typed terminal detach replay outcomes retained without projection.
- Detach
Transport Attempt Decision - Decision for starting a detach transport attempt.
- Detach
Transport Fate - Typed transport fate for an outstanding detach send.
- Detach
Transport Fate Decision - Decision for returning an in-flight detach to parked replay.
- Established
Connection Transport Fate - Established-connection transport fate authorizing one reconnect attempt.
- Expected
Operation Fate Decision - Complete typed fate decision for an issued non-detach operation.
- Expected
Operation Fate Refusal Reason - Reason an expected-operation transport fate was refused.
- Expected
Operation Transport Fate - Typed transport fate for an issued non-detach operation awaiting a response.
- Explicit
Reconnect Action - Explicit caller action authorizing one reconnect attempt.
- Lost
Authority Kind - Closed description of which live process-local authority was destroyed.
- Lost
Authority Resolution Refusal Reason - Reason a lost-authority resolution was refused.
- Lost
Operation Authority Decision - Complete decision for resolving a restored operation-authority loss.
- Lost
Reconnect Authority Decision - Complete decision for resolving restored reconnect-authority loss.
- Proved
Online Transition - Proved online transition authorizing one reconnect attempt.
- Reconnect
Attempt Decision - Complete permit redemption decision.
- Reconnect
Attempt Fate - Typed fate of one real connection attempt.
- Reconnect
Attempt Fate Decision - Complete attempt-fate decision.
- Reconnect
Attempt Fate Refusal Reason - Reason an attempt fate was refused.
- Reconnect
Attempt Refusal Reason - Reason a permit redemption was refused unchanged.
- Reconnect
Fresh Event - Closed fresh-event classes that may mint one reconnect permit.
- Reconnect
Permit Decision - Complete fresh-event permit decision.
- Reconnect
Permit Refusal Reason - Reason a fresh event did not mint another permit.
- Recovered
Expected Operation Decision - Decision for releasing a committed cold-restored operation exactly once.
- Recovered
Reconnect Permit Decision - Decision for releasing a validated cold-restored permit exactly once.
- Restored
Expected Operation Abandonment Reason - Why a persisted expected operation was deliberately not re-released.
Functions§
- apply_
attach - Applies attach supersession without treating attach as transport fate.
- apply_
detach_ outcome - Validates a typed detach outcome against the retained exact request.
- apply_
leave_ durable - Applies durable Leave supersession.
- decide_
correlated_ inbound - Attempts correlation while retaining the process-local handle on refusal.
- decide_
inbound - Correlates and applies one server value inside the client aggregate.
- record_
attempt_ fate - Records typed success or failure for one in-progress real attempt.
- record_
expected_ operation_ fate - Records transport loss for the exact issued non-detach operation.
- record_
explicit_ reconnect - Records explicit caller action and mints at most one permit.
- record_
online_ transition - Records a proved online transition and mints at most one permit.
- record_
operation - Records one operation behind the client durability barrier.
- record_
transport_ fate - Records established-connection transport fate and mints at most one permit.
- recover_
expected_ operation - Releases an unissued operation from a validated committed cold restore.
- recover_
reconnect_ permit - Releases an unissued permit created only by a committed cold record.
- redeem_
attempt - Redeems one fresh permit into one in-progress real connection attempt.
- resolve_
lost_ operation_ authority - Consumes the pending operation-domain lost-authority testimony exactly once.
- resolve_
lost_ reconnect_ authority - Consumes the pending reconnect-domain lost-authority testimony exactly once.
- transport_
attempt_ started - Moves a parked detach to in-flight and releases its exact send effect.
- transport_
fate - Consumes the outstanding send authority with typed transport fate.