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
//! **The version preface** (yog's `docs/REMOTE.md` §3): *"each end writes one
//! frame, `{"protocol": <integer>}`, before it reads the peer's."* Both write
//! before either reads, so neither waits on the other and there is no ordering
//! rule to remember.
//!
//! **This is why thrall exists as a separate program and it is not decoration.**
//! Until the four-component split one crate shipped both ends of every
//! connection and the wire could not skew. A foot is installed on a box the
//! engine's operator may not administer, upgraded on that box's own schedule —
//! so the day the two disagree about what a frame means is a day that will
//! arrive, and it must arrive as a sentence rather than as a gesture answered
//! wrongly.
//!
//! **thrall writes and confirms; it never admits.** A foot dials and is never
//! dialled, so there is exactly one half of the exchange here. The engine's
//! half — refusing a peer in band on the connection it opened — is the
//! server's, and a foot that carried it would be a foot that listens.
//!
//! **A mismatch is fail-closed and the refusal names both versions**, which is
//! REMOTE §3's requirement rather than a nicety: the sentence *is* the upgrade
//! prompt, so it must name a number an operator can act on. There is no
//! negotiation, no version list and no compat shim — negotiation is the
//! mechanism that makes every later version carry every earlier one's shape
//! forever, and the operator who installed both ends can upgrade the older one.
//!
//! **And a preface that ARRIVED is told apart from one that never did**
//! (bl-5d62). REMOTE §3 collapses them on the *engine's* side, and rightly: a
//! peer of the wrong version and a peer that hung up mid-preface are both peers
//! it cannot serve, so one sentence answers both. A foot is deciding a
//! different question — whether dialling again could help — and there the two
//! part. A frame this end read and could not agree with is a fact about the two
//! *binaries*: it will say the same thing on every dial until somebody installs
//! a new one, so it is [`Failure::Skew`] and it ends the channel. A preface that
//! never came is an engine restarting, a socket dying, a box waking up — the
//! wire, [`Failure::Wire`], and dialled again. The SENTENCE stays one sentence
//! either way; what differs is only what this foot does next.
//!
//! Under the old reading a foot that met a version bump wrote a line into its
//! operator's journal every minute forever, and one that met a restarting
//! engine was indistinguishable from it.
use ;
use ;
use ;
/// The protocol this build speaks.
///
/// **A new verb is not a bump.** A `Query`, an `Action` or a reply kind the
/// peer has not heard of already refuses in band, naming it (REMOTE §3's strict
/// decode) — the boundary correcting itself, not two protocols meeting. The
/// integer moves when the *existing* shape changes meaning: the framing, the
/// envelope, or what a spelling already in use is taken to say.
///
/// **The number is the engine's and there is nothing here to version.** It must
/// read whatever yog's own repo-root `PROTOCOL` file reads, so it is stated a
/// second time — as a literal copied from that file — in `crate::corpus`, which
/// is what the suite's stand-in engine dials at. The two agreeing is a test
/// (`corpus::tests`) rather than a tautology, and that is the whole of the
/// defence: while the stand-in wrote its preface from *this* constant, both
/// ends of every test agreed by construction and the pin sat five versions
/// behind a live engine with the suite green (bl-e0f0).
///
/// **Most bumps are not a foot's business, and it can still not dial across a
/// single one of them.** Of everything past 2, exactly one touched this crate's
/// own surface — 8 (yog bl-66d4), the required `wrote` on `reply/advertised`.
/// 3 through 7 and 9 through 18 moved seat-facing shapes this crate never
/// decodes, 10 moved no field at all (`attention` became follow-class), and 17
/// and 18 each moved a VALUE rather than a field — a new `signals` word, then a
/// fourth `framing` word — that the shape ledger cannot see. The
/// preface is one integer compared for equality, so the version states the
/// engine's *build* and never which frames this end happens to read — which is
/// why this constant has now drifted seven times (bl-e0f0, bl-f88f, bl-dc5f,
/// bl-605f, bl-44b4, bl-272d, bl-dc8a) with the suite
/// green: nothing on this side of the socket can see the far end move, and a
/// real dial is the only thing that meets the skew. bl-dc8a is the first moved
/// while the engine's number was still UNPUBLISHED, which is the order yog
/// `docs/REMOTE.md` §3 asks for: a consumer's `main` carries the number, then
/// the engine publishes, then the consumer does.
///
/// **It is not declared here.** The repo-root `PROTOCOL` file states it, one
/// line, and `build.rs` compiles that into the constant re-exported below
/// (bl-c618) — the same shape yog and every other consumer now carry. Bump it
/// by editing that line; nothing under `src` says the number. It is a file
/// because the release gates that read it are other repositories FETCHING one
/// path out of a tree they do not build, and a Rust path is not a stable
/// address for that: yog's own split of `src/wire/hello.rs` left the old path
/// re-exporting, which a build cannot notice and a regex reads as no
/// declaration, and it broke every gate in the suite at once.
pub use PROTOCOL;
/// The generated constant, and nothing else: `build.rs` writes it from the
/// repo-root `PROTOCOL` file on every build the file has moved.
/// The preface's one key, and the whole of its shape.
const KEY: &str = "protocol";
/// What a peer that stated no version is called in the sentence. An unversioned
/// build, a frame that is not an object, a frame without the key and a peer
/// that hung up mid-preface are one case on purpose: none of them can be
/// served, and four sentences for one outcome is four sentences.
const UNSTATED: &str = "no version";
/// Write this build's preface. Called before this end reads, which is what
/// makes the exchange deadlock-free without an ordering rule.
/// Read the engine's preface and refuse a mismatch — as the one `Err(String)`
/// every other thing that can go wrong with this transport already arrives as,
/// so nothing above here carries a case for it.
/// **The peer's preface frame, if one came at all.** `None` is the wire: a read
/// that failed, or a stream that ended where a frame belongs. Anything this
/// end managed to read is a frame the peer deliberately wrote, whatever it
/// says.
/// The refusal: both versions, and what to do about it.