FlakyLifecycleSeam

class FlakyLifecycleSeam(delegate: Seam, scope: CoroutineScope) : Seam

A Seam wrapper that owns its own state and gates the contract on it, enabling lifecycle-flap scenarios in tests.

Unlike FaultySeam (which delegates state and injects per-frame faults), this wrapper can simulate a transport link that drops and recovers: Woven → Weaving → Woven (transient reconnect) or escalates to Torn (permanent failure).

Behaviour while SeamState.Weaving

  • peers collapses to {selfId} — this peer is momentarily alone.

  • broadcast is the contract's defined no-op (no other peers; returns immediately without throwing).

  • sendTo throws PeerNotConnected for any absent peer (as always).

  • Inbound frames from the delegate are dropped while weaving — they are not buffered and will not appear on incoming after recover.

Behaviour on recover

state → Woven, peers refills from the delegate, inbound delivery resumes.

Behaviour on tear

state → Torn(reason) (terminal), incoming completes, subsequent sends throw IllegalStateException.

Composition

Lifecycle wrapper outer, frame-fault inner: FlakyLifecycleSeam(FaultySeam(realSeam), scope). The lifecycle wrapper gates the consumer-facing contract on its own state; the inner FaultySeam applies frame-level faults to whatever flows while SeamState.Woven.

Determinism guarantee: all timing goes through kotlinx.coroutines.delay so kotlinx.coroutines.test.runTest controls virtual time. FlapSchedule jitter is seeded — same seed, same flap pattern.

Constructors

Link copied to clipboard
constructor(delegate: Seam, scope: CoroutineScope)

Properties

Link copied to clipboard
open override val incoming: Flow<Swatch>

Frames from delegate.incoming, filtered by this seam's lifecycle state.

Link copied to clipboard
open override val peers: StateFlow<Set<PeerId>>

Live set of peers currently connected. Includes selfId.

Link copied to clipboard
open val plies: StateFlow<Map<PlyId, SeamState>>

Per-ply lifecycle breakdown. Single-ply fabrics report a one-entry map keyed by PlyId.Sole. Invariant: state.value equals the rollup of plies.value.values under "any ply Woven ⇒ Woven".

Link copied to clipboard
open override val selfId: PeerId

This peer's own identifier.

Link copied to clipboard
open override val state: StateFlow<SeamState>

The fabric's lifecycle as observed by this peer.

Functions

Link copied to clipboard
suspend fun blip(weavingFor: Duration)

Suspend through weavingFor in SeamState.Weaving then return to SeamState.Woven — one atomic blip.

Link copied to clipboard
open suspend override fun broadcast(payload: ByteArray)

Send to all other peers. Suspends until accepted by the local transport.

Link copied to clipboard
open suspend override fun close(reason: CloseReason = CloseReason.Normal)

Disconnect from the session. Idempotent.

Link copied to clipboard
fun drive(schedule: FlapSchedule): Job

Launch a FlapSchedule loop in scope and return the running Job.

Link copied to clipboard

Transition Woven → Weaving. Held until recover or tear is called.

Link copied to clipboard
suspend fun flapThenTear(flaps: Int, weavingFor: Duration, reason: CloseReason = CloseReason.Unreachable)

Perform flaps blips (each SeamState.Weaving for weavingFor), then tear with reason. After this call completes the seam is terminal.

Link copied to clipboard
fun recover()

Transition Weaving → Woven. Inbound delivery and peers resume from the delegate.

Link copied to clipboard
open suspend override fun sendTo(peer: PeerId, payload: ByteArray)

Send to one peer. Suspends until accepted by the local transport.

Link copied to clipboard
fun tear(reason: CloseReason = CloseReason.Unreachable)

Transition to SeamState.Torn (terminal). incoming completes; subsequent sends throw IllegalStateException.