TeardownFault
What a FaultySeam's teardown should do — a different axis from FaultProfile, which describes what happens to frames.
Before #2501 FaultySeam.close was an unconditional passthrough to the delegate, so the one component in the tree whose job is to make a transport misbehave could not make a teardown slow, suspend, or fail. Every obligation that only becomes falsifiable when close misbehaves — Room.leave's idempotency and its no-minted-cancellation obligation (#1826), reached through SeamRoom.leave's seam.close(...) — was therefore unreachable rather than merely unwritten.
Why a separate knob rather than a FaultProfile arm
FaultProfile's model is per-frame evaluation carrying a Direction. A teardown has neither a frame nor a direction, so a teardown arm would be three dead branches in FaultState's outbound / inbound / inbound-delay evaluators plus a teardown-extraction walker alongside inboundDelay for FaultProfile.Composite — conflating two axes to reuse one sealed hierarchy.
Honouring FaultProfile.DelayAll inside close was the other option and is worse: it silently changes teardown at every existing FaultySeam call site, and a delay can only make a close slow, never fail, so the minted-cancellation obligation would still have no failure to classify.
Orthogonal and defaulting to None means no existing call site changes behaviour at all, and slow and failing teardowns compose freely with any frame profile.
Determinism: Slow suspends through kotlinx.coroutines.delay, so kotlinx.coroutines.test.runTest controls it in virtual time — no wall clock is consumed.