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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//! **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 the seat 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 seat is installed on the
//! operator's own laptop or phone and upgraded on that device's schedule,
//! while the engine it dials is upgraded on the server's — 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.
//!
//! **The seat writes and confirms; it never admits.** A seat 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 seat that carried it would be a seat 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.
use ;
use json;
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.
///
/// **2 was yog bl-77be's bump**, and it was the second clause of that rule
/// rather than the first: four shapes grew an optional field
/// (`request/advertise` and `reply/clients` gained a tool's `subject_cwd`
/// consent, `request/invoke` and `reply/invocations` gained the subject's
/// `cwd`), and — the part no ledger can see — REMOTE §5.5 changed what a
/// follow frame's `text`/`thinking` are taken to say, from the whole
/// accumulated answer to what landed since the previous frame. The spelling
/// did not move; the meaning did, which is exactly what this integer is for.
///
/// **3 and 4 are two bumps of one unreleased cycle** (REMOTE §9.10, §9.11),
/// and the pair is why this integer is not a count of releases. 3 gave
/// `reply/conversations`' row, the §6 queue row and the `agent` answer a
/// `failure` clause — why the conversation's latest model call failed — and 4
/// gave the queue row a `flag` object beside a new `flagged` signal token.
/// Each is a gained field, which §3's rule bumps whether or not a reader needs
/// it; the ledger's granularity is per bump and not per release, so a shape
/// touched twice in one cycle costs two integers. Neither number was ever
/// spoken by a peer.
///
/// **This seat consumes exactly one of the four fields** (bl-d774), which is
/// DESIGN §4.9's rule holding rather than a shortfall: `failure` reaches
/// [`crate::reply::convs::ConvRow`] because the conversation list is the pane
/// that paints the row it hangs on, and the `agent`, `attention` and queue
/// shapes stay in the corpus ledger under `unreadable/` because no pane here
/// reads them. A field is carried by the release that paints it.
///
/// **5 is the first clause of the rule and the one this seat cannot check**
/// (REMOTE §9.12, upstream bl-e654; bl-e6ee here). `reply/governing` lost
/// `branch`, gained `follows` and `diverged_lineages`, and — the half no
/// signature can see — its `oid` **changed meaning under the same key**: it
/// named the `config/*` ancestor an agent's branch forked off, a commit that
/// never moved, and now names the commit control reads at each step boundary,
/// the followed lineage's head. The doctrine inverted with it, from
/// fork-is-the-freeze to follow-the-tip.
///
/// **Nothing here decodes `governing`**, so this seat paid the integer and no
/// field, and that is the whole of what it owed: the shape falls to
/// [`crate::reply::read`]'s unknown-kind arm and its fixture asserts exactly
/// that from `corpus/unreadable/`. The trap is recorded here rather than
/// nowhere, because it is aimed at whoever lands the pane: a reader that took
/// `oid` for the fork commit would paint a plausible number that has been
/// wrong since this bump, and it is the one kind of drift a corpus replay
/// cannot catch — the bytes are well-formed and the field is spelled the same.
///
/// **6 is a bump this seat paid for one row and not for the two ops beside
/// it** (REMOTE §9.13, upstream bl-23bd; bl-675e here). `reply/providers`'
/// rows gained `effort` and `priority`, two required booleans saying which
/// tuning knobs that provider row actually takes — a capability stated as a
/// column of the row it is about, rather than as a second answer a seat would
/// have to join back. The `/effort` and `/priority` **ops** that landed with
/// them moved nothing: a new op is a new spelling in an existing vocabulary,
/// and a peer that has not heard of one refuses it in band by name, which is
/// the first paragraph of this comment rather than an exception to it.
///
/// Nothing here paints providers either, so this is the second consecutive
/// integer bought without a field — see [`crate::reply`] for why that is the
/// arrangement working. The request half is not free of obligation, though:
/// the two new ops carry a top-level `workspace` and `src/verbs/tests/corpus`
/// asserts this seat routes every vocabulary frame by the slot upstream's own
/// signature says it carries, which is where a miss would be silent.
///
/// **7 is the first bump this end reads a field out of** (REMOTE §9.14,
/// upstream bl-8758; bl-38d4 here). Every `reply/help` row gained `surface`,
/// classing the op `control` — every seat owes it a discoverable interactable
/// — or `machine`, spoken by programs and owed nothing. It is wire-visible
/// because it rides a reply this seat vendors, and it is load-bearing here:
/// the field IS the roster the interface-parity gate judges this window
/// against (`crate::snapshot::parity`, yog's `docs/PARITY.md` §2). The bump
/// also carried the `roles` shape, which nothing here paints yet and which
/// therefore landed in the corpus ledger — `corpus/README.md` on why that
/// directory is the record rather than an oversight.
///
/// **8 is a bump for a shape this seat does not speak either half of**
/// (REMOTE §5.1, upstream bl-66d4; bl-2604 here). `reply/advertised` gained
/// **`wrote`**, a required boolean saying whether the engine stored the
/// presented tool set or found it identical to what it held and wrote nothing.
/// It is required rather than optional-absent-reads-false on purpose:
/// absent would decode as *"nothing was restored"* — the reassuring answer —
/// on exactly the build too old to tell.
///
/// **The fact is a foot's, not a seat's.** `advertise` is the tool host's
/// gesture, and a `true` on any re-presentation after the first is that host
/// learning some other connection bearing its certificate blanked its set
/// while it was executing and holding no parked read. A seat presents no set,
/// so this end has no gesture to receive the receipt for and nothing to say
/// about it: the fixture stays in `corpus/unreadable/`, the shape keeps
/// falling to [`crate::reply::read`]'s unknown-kind arm, and the pane that
/// would paint a tool host's state does not exist here yet (bl-e53c). Third
/// consecutive integer bought without a field, and — like the two before it —
/// the corpus refresh is the whole of what the re-vendor moved: one signature,
/// one fixture, nothing else in forty-seven shapes.
///
/// **13 crosses five bumps at once, and only one of them is a break**
/// (bl-249b here; yog's own `src/wire/hello.rs` carries the ledger and REMOTE
/// §9.16-§9.18 the reasoning). The released engine moved five integers while
/// this build sat at 8, and the shape of the arrears is the point: four of the
/// five *gained* something, and a gain reaches a decoder that reads named
/// fields as nothing at all. What has to be paid is the one loss.
///
/// - **9** — `reply/steps` **LOST** `auth_failed`, and `reply/transcript`
/// gained the `wounded` entry beside it. This is the break: the field was
/// read here with [`super::super::reply::fields::flag`], which is required,
/// so at 13 every steps reply refuses on a key the engine no longer writes.
/// REMOTE §9.16 names the replacement outright — *"a seat that read
/// `auth_failed` reads `wound == \"refused\"` instead"* — and this build
/// already decodes `wound` and `auth_row`, so the affordance is re-pointed at
/// the vocabulary it was always one arm of, and no reading is lost.
/// - **10** — no field moved anywhere. `attention` became follow-class: the
/// same ask and the same reply shape, but a *sequence*. It is the one class
/// of change a field-signature ledger cannot see, and it is exactly why the
/// preface is strict equality rather than a signature comparison.
/// - **11** — `reply/ops` gained `failed`, `exit_label` and `standing`.
/// - **12** — every queue row gained `says`, and `reply/acknowledged` arrived
/// spelling rows the same way.
/// - **13** — `reply/config` gained `settings`, the file's own schema applied
/// to the bytes answered beside it.
///
/// **The ledger absorbs the rest, which is the arrangement working rather than
/// a debt.** `ops` and `config` are already `corpus/unreadable/` files here, so
/// their gains cost a refresh and nothing else; `acknowledged` and `login` are
/// new shapes and land there the same way; and the `wounded` entry falls to
/// [`crate::reply::transcript::EntryKind::Unknown`], which is total by design.
/// Four new ops are classed `control` — `login`, `login-tail`, `pin`, `unpin`
/// — so `parity.toml` gains four lines rather than the gate reddening, each
/// citing the ball that will delete it.
pub const PROTOCOL: u32 = 13;
/// 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
/// terminator where a preface belongs are one case on purpose: none of them can
/// be served, and four sentences for one outcome is four sentences.
///
/// **A peer this end could not read at all is no longer among them** (bl-3969).
/// It was, and the collapse was right about the sentence and wrong about the
/// recovery: the other four are a peer speaking, so nothing crossed, where an
/// unreadable preface is a broken connection with this end's request already on
/// it. See [`confirm`] — the sentence is still one per outcome; there are now
/// two outcomes.
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 [`Reach`] every
/// other thing that can go wrong with this transport already arrives as, so
/// nothing above here carries a case for it.
///
/// **The classification splits where the four collapsed cases do not.** A peer
/// that STATED something — another version, a frame that is not an object, a
/// frame without the key, a terminator where a preface belongs — refused this
/// end before adjudicating anything (REMOTE §3: a request of a version this
/// build does not speak *"is never adjudicated"*), so nothing crossed and one
/// sentence still serves all four. A preface this end could not READ is the
/// fifth case and is not about a version at all: the request went out in the
/// same breath as this end's preface, so the connection broke with the gesture
/// already at the far end and an act on it is IN DOUBT (REMOTE §3, bl-3969). It
/// says so in the transport's own words rather than borrowing a sentence about
/// a number nobody stated.
/// The refusal: both versions, and what to do about it.