1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//! **Why an exchange produced no answer** — and the one thing this end can say
//! about what the far end did with the request.
//!
//! yog's `docs/REMOTE.md` §3 rules the recovery: *"A lost reply leaves an act IN
//! DOUBT, and the recovery is a read — never a resend … a client whose act
//! earned a transport error instead of a reply paints the failure and consults
//! the world, which is the durable record … Asks are the opposite case and
//! re-ask freely."*
//!
//! Acting on that needs one fact a bare `Err(String)` cannot carry: **did the
//! request cross?** The two answers have opposite remedies — do it again, or do
//! nothing and look — so a seat that collapsed them would give one of them
//! wrong. That is the same division [`crate::ui::Notice`] already draws three
//! ways for three remedies, taken one layer down where the fact is known.
//!
//! **The seam is [`crate::channel::Channel::dial`]**, and it is the seam the
//! transport already had: everything `dial` refuses happened before the far end
//! could adjudicate anything, and what it hands back is — in its own words — *"a
//! socket with a request on it and no answer yet read"*. So the classification
//! is structural rather than a reading of a message, exactly as
//! `Channel::wrote` reads a typed `rustls::Error` rather than its wording.
//!
//! **A read does not care and must not be made to.** Both arms are one sentence
//! to the asker and the follow lane, which is what [`Reach::said`] is for: a
//! standing question is answered in place and asking twice is asking once, so
//! the classification is spent by the poster and by nobody else.
/// What a transport failure says about the request that earned it.