Hand-written. ../harvested/error-handling.md is what the documents say; this is what the implementation found, and it wins.
Facts measured on .NET SDK 10.0.401 / runtime 10.0.12, Linux, so a later reader does not have to re-measure them.
- Moving
ServiceRequestExceptionunderIOExceptionchanges no classification: the retry classifier readsIRetryableErrorand the cause chain, never the SDK root.TRANSPORT-20says a transport failure "MUST be a subtype of the platformIOException" andXCUT-4that it be catchable as a generic I/O error; the port had rooted it inSdkExceptionbecause it chose one SDK root, which no requirement asks for (single inheritance was the only obstacle, design §10 entry 7, retired). The type keepsIRetryableErroritself, keeps the native exception asInnerException, stores the suppressed trail throughExceptionTrailand renders it inToStringthrough the rendererSdkExceptionshares, so a cycle across the two families still terminates. The cost is on callers:catch (SdkException)no longer catches a transport failure, and a negative check written as "is not anSdkExceptionthat is retryable" goes vacuous and must readIRetryableError(the conformance kit had eight such sites, P11-7;TransportExceptionTaxonomyTests). review ·docs/work/mvp/phase11/2026-10-19-phase11-deviation-reconciliation-design.md· high · sha:manual-p11-transport-is-ioexception