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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
//! **The version preface** (REMOTE §3, bl-a670): the first frame each end
//! writes on a connection, carrying the one fact it states about itself.
//!
//! Until the four-component split (REMOTE §12) one crate shipped both ends of
//! every connection, so the wire could not skew and needed no version. Four
//! separately installed components can skew, so it carries one.
//!
//! **Three properties, each a refusal of something easier.**
//!
//! - **Both ends state, and either end may refuse.** Each writes its preface
//! before it reads the peer's, so neither waits on the other and a mismatch
//! is nameable from whichever side notices first. An engine refusing a seat
//! and a seat refusing an engine are one rule with one sentence, not two
//! halves that can disagree.
//! - **No negotiation.** No version list, no capability probe, no compat shim:
//! a mismatch is fail-closed and the sentence — which names *both* versions —
//! is the upgrade prompt. Negotiation is the mechanism that makes every later
//! version carry every earlier one's shape forever, and it buys nothing here
//! because the operator installs both ends.
//! - **The request frame is untouched.** The preface rides *beside* the gesture
//! envelope, never inside it, so the frame the wire carries stays byte for
//! byte the frame the `gestures/` inbox carries (REMOTE §3: the wire adds
//! nothing to the boundary) and the codec gains no field.
//!
//! **Two keys since bl-e598 made the number a MAJOR, and only one of them is
//! adjudicated** (REMOTE §3.2). `protocol` is the major, and the refusal above
//! is still strict equality on it. `edition` beside it is the corpus this
//! build was generated from — the newest stamp in `corpus/shapes.json`,
//! compiled in by `build.rs` as [`EDITION`] — and it decides nothing: an
//! addition ships without a bump, so two ends of one major routinely differ
//! here and are meant to. What it buys is that the difference is *sayable*. A
//! seat that vendors the ledger reads the engine's edition and knows which of
//! two things an absent field is: a fact the engine chose not to state, or a
//! field this engine cannot spell at all — which it then renders as exactly
//! that, rather than as the reassuring default. A peer that states no edition
//! is read as speaking the [`FLOOR`], because every engine of this major
//! writes every path stamped at or below it; that is the right reading of
//! every build that predates the key.
//!
//! **ALPN was the alternative, and it cannot say this.** rustls will refuse a
//! handshake whose application protocol does not match, at no cost and with no
//! frame — but that refusal is a TLS alert, so neither end learns the other's
//! version and an operator reads a transport error where a sentence belongs.
//! Naming both versions is the requirement, so the preface is in band.
//!
//! **It costs no round trip.** Each end writes its preface and only then reads
//! the peer's, and the seat writes its request in the same breath as its
//! preface — so the check travels with bytes that were already going, and the
//! only connection it stops is one that was going to be refused anyway.
use ;
use ;
use frame;
/// The wire version this build speaks, and the changelog of every bump —
/// its own file at §12's cap (bl-94a5), because the number is one line and
/// the reasoning behind each move of it is the rest: `hello` is the preface
/// EXCHANGE, `version` is what the preface states and why it ever changed.
/// Since bl-9ced it also holds the newest version yog has PUBLISHED, which no
/// preface ever states — the corpus ledger's gate is its one reader.
pub use ;
/// The preface's first key: the MAJOR, and the whole of what is decided on.
const KEY: &str = "protocol";
/// Its second: the corpus **edition** this build was generated from (REMOTE
/// §3.2, bl-1be7). It is stated and never adjudicated — an edition can only
/// ever differ *within* an agreed major, which is the point of the split, so a
/// peer is admitted or refused on [`KEY`] alone and the edition is what it is
/// then allowed to say about itself.
const EDITION_KEY: &str = "edition";
/// What a peer that stated no version is called in the sentence. An
/// unversioned build, a peer that hung up mid-preface and noise are one case
/// on purpose: none of them can be served, and telling them apart would be
/// three sentences for one outcome.
const UNSTATED: &str = "no version";
/// Write this build's preface. Called before either end reads, which is what
/// makes the exchange deadlock-free without an ordering rule to remember.
pub
/// What the peer stated about itself: the major, and the edition beside it.
/// Read one preface frame.
/// Whether what the peer stated is this build's own protocol.
/// The refusal, said the same way at both ends: both versions, and what to do
/// about it. It is the upgrade prompt, so it names the remedy rather than
/// leaving an operator to infer one from a number.
/// **The engine's half**: state, read, and either admit the peer or refuse it
/// in band on the connection it opened.
///
/// `None` is the whole of the refusal — the caller drops the connection and
/// never decodes a frame of another protocol, so no gesture of a version this
/// build does not speak is ever adjudicated. A refusal that could not be
/// written (a peer already gone) changes nothing: the answer is the same.
///
/// An admitted peer is handed back **its edition** (REMOTE §3.2), which the
/// caller keeps on the connection's presence entry. The decision itself is
/// still [`KEY`] alone: an edition never refuses anybody, because the whole
/// point of splitting it off the major is that a difference in it is one two
/// ends are meant to survive.
pub
/// **The seat's half**: read the engine's preface and refuse a mismatch to the
/// caller, as one `Err(String)`.
///
/// `cfg(test)` since bl-7942: no seat ships in this crate any more, and the one
/// client left in the tree is the suite's own
/// ([`test_support::wire::Seat`](crate::test_support::wire)), which has to
/// speak the whole protocol or it would prove the listener against a dialect.
/// The *rule* it implements is still the server's — [`stated`] writes the same
/// preface — so it belongs beside it rather than in the harness.
pub