NtsError.timeout constructor

const NtsError.timeout({
  1. required TimeoutPhase phase,
  2. TrustBackend? trustBackend,
})

Wall-clock budget elapsed inside one of the call's pre-NTP or NTP phases. The TimeoutPhase payload identifies which phase tripped the deadline so callers can choose the right remediation.

trustBackend is typed as nullable to keep the Rust KeFailure attribution contract honest at the FFI boundary, but in practice every Rust-authored phase fires after build_tls_config returned Ok and therefore carries the resolved backend. Rust perform_handshake calls build_tls_config before any DNS, connect, or TLS I/O begins, then attaches the resolved backend (via the per-call attribute closure) to every subsequent failure site — dnsSaturation and dnsTimeout from the bounded resolver, connect from the per-address TcpStream::connect_timeout loop, tls from the rustls handshake / write / flush window, keRecordIo from the chunked record-read loop, and the post-handshake UDP-leg ntp phase. The Android per-instance hybrid-fallback upgrade is reflected when the HybridVerifier's fallback counter incremented during the TLS write/flush window. The one exception is the Dart-authored TimeoutPhase.bridgeSaturation, which fires in the wrapper's bridge admission gate before any FFI dispatch and therefore always carries a null backend.

Implementation

const factory NtsError.timeout({
  required TimeoutPhase phase,
  TrustBackend? trustBackend,
}) = NtsErrorTimeout;