oxedyne/fe2o3/fe2o3_ore/format.jdat
38.5 KiB, 137 runs
created by r1870400018:35247, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | { |
| 2 | "about": "The on-disk and on-the-wire names this crate fixes, and the tests that freeze them. This file is the authority for the version constants, the wire codes, the kind bytes and the golden byte tests; format_change_contract.md carries the reasoning and points here for the facts. tests/format_registry.rs reads it and reddens when the code and this file disagree, which is why the facts live here rather than in a document nothing can check.", |
| 3 | |
| 4 | "files": [ |
| 5 | { |
| 6 | "path": "src/segment.rs", |
| 7 | "role": "the segment container, its version, and the kind byte on every record", |
| 8 | "exempt": [] |
| 9 | }, |
| 10 | { |
| 11 | "path": "src/op.rs", |
| 12 | "role": "the operation vocabulary and the values inside an operation", |
| 13 | "exempt": [] |
| 14 | }, |
| 15 | { |
| 16 | "path": "src/sync/msg.rs", |
| 17 | "role": "the sync message frame", |
| 18 | "exempt": [] |
| 19 | } |
| 20 | ], |
| 21 | |
| 22 | "constants": [ |
| 23 | { |
| 24 | "name": "segment::MAGIC", |
| 25 | "file": "src/segment.rs", |
| 26 | "line": (u64|83), |
| 27 | "value": "ORESEG", |
| 28 | "axis": "frame", |
| 29 | "holds": "the six bytes a reader matches before it believes the file is a segment at all" |
| 30 | }, |
| 31 | { |
| 32 | "name": "segment::VERSION", |
| 33 | "file": "src/segment.rs", |
| 34 | "line": (u64|110), |
| 35 | "value": (u8|6), |
| 36 | "axis": "vocabulary", |
| 37 | "holds": "which operation codes a segment written now may carry, stamped at byte 6 of every segment" |
| 38 | }, |
| 39 | { |
| 40 | "name": "segment::VERSION_MIN", |
| 41 | "file": "src/segment.rs", |
| 42 | "line": (u64|129), |
| 43 | "value": (u8|2), |
| 44 | "axis": "vocabulary", |
| 45 | "holds": "the oldest segment this crate reads; it stays where it is because every version since has been a strict superset of it" |
| 46 | }, |
| 47 | { |
| 48 | "name": "segment::KIND_BARE", |
| 49 | "file": "src/segment.rs", |
| 50 | "line": (u64|160), |
| 51 | "value": (u8|1), |
| 52 | "axis": "container", |
| 53 | "holds": "a record carrying an unsigned, unencrypted operation" |
| 54 | }, |
| 55 | { |
| 56 | "name": "segment::KIND_SEALED", |
| 57 | "file": "src/segment.rs", |
| 58 | "line": (u64|162), |
| 59 | "value": (u8|2), |
| 60 | "axis": "container", |
| 61 | "holds": "a record carrying a signed envelope" |
| 62 | }, |
| 63 | { |
| 64 | "name": "segment::KIND_VEILED", |
| 65 | "file": "src/segment.rs", |
| 66 | "line": (u64|172), |
| 67 | "value": (u8|3), |
| 68 | "axis": "container", |
| 69 | "holds": "a record whose header is in clear and whose body is ciphertext; it cost no version bump, which is the precedent every later container change is read against" |
| 70 | }, |
| 71 | { |
| 72 | "name": "segment::KIND_PACKED", |
| 73 | "file": "src/segment.rs", |
| 74 | "line": (u64|194), |
| 75 | "value": (u8|4), |
| 76 | "axis": "container", |
| 77 | "holds": "a record carrying a run of records deflated together; like the veil it cost no version bump, and what is inside it is the plain framing unchanged, so a packed segment yields the same records with the same digests as the plain one it was made from" |
| 78 | }, |
| 79 | { |
| 80 | "name": "segment::PACKED_MAX", |
| 81 | "file": "src/segment.rs", |
| 82 | "line": (u64|202), |
| 83 | "value": (u64|67108864), |
| 84 | "axis": "container", |
| 85 | "holds": "the most a packed run may inflate to; a compressed frame is an instruction to allocate and it arrives from wherever the segment did, so one that reaches this is refused rather than obeyed" |
| 86 | }, |
| 87 | { |
| 88 | "name": "op::CODE_FILE_CREATE", |
| 89 | "file": "src/op.rs", |
| 90 | "line": (u64|110), |
| 91 | "value": (u8|1), |
| 92 | "axis": "vocabulary", |
| 93 | "holds": "a file comes into being" |
| 94 | }, |
| 95 | { |
| 96 | "name": "op::CODE_FILE_DELETE", |
| 97 | "file": "src/op.rs", |
| 98 | "line": (u64|111), |
| 99 | "value": (u8|2), |
| 100 | "axis": "vocabulary", |
| 101 | "holds": "a file stops being" |
| 102 | }, |
| 103 | { |
| 104 | "name": "op::CODE_FILE_RENAME", |
| 105 | "file": "src/op.rs", |
| 106 | "line": (u64|112), |
| 107 | "value": (u8|3), |
| 108 | "axis": "vocabulary", |
| 109 | "holds": "a file takes another path" |
| 110 | }, |
| 111 | { |
| 112 | "name": "op::CODE_MARK", |
| 113 | "file": "src/op.rs", |
| 114 | "line": (u64|113), |
| 115 | "value": (u8|4), |
| 116 | "axis": "vocabulary", |
| 117 | "holds": "a name given to a point, two elements and nothing more; every mark ever signed is spelled this way and none of them may move" |
| 118 | }, |
| 119 | { |
| 120 | "name": "op::CODE_SPLICE", |
| 121 | "file": "src/op.rs", |
| 122 | "line": (u64|114), |
| 123 | "value": (u8|5), |
| 124 | "axis": "vocabulary", |
| 125 | "holds": "an edit to a file's contents" |
| 126 | }, |
| 127 | { |
| 128 | "name": "op::CODE_MOVE", |
| 129 | "file": "src/op.rs", |
| 130 | "line": (u64|115), |
| 131 | "value": (u8|6), |
| 132 | "axis": "vocabulary", |
| 133 | "holds": "a run of atoms taken from one place to another" |
| 134 | }, |
| 135 | { |
| 136 | "name": "op::CODE_NOTE", |
| 137 | "file": "src/op.rs", |
| 138 | "line": (u64|116), |
| 139 | "value": (u8|7), |
| 140 | "axis": "vocabulary", |
| 141 | "holds": "something said about the history rather than done to it; the top of the version 2 vocabulary" |
| 142 | }, |
| 143 | { |
| 144 | "name": "op::CODE_FILE_MODE", |
| 145 | "file": "src/op.rs", |
| 146 | "line": (u64|117), |
| 147 | "value": (u8|8), |
| 148 | "axis": "vocabulary", |
| 149 | "holds": "a file's mode changes; the top of the version 3 vocabulary" |
| 150 | }, |
| 151 | { |
| 152 | "name": "op::CODE_MARK_TIMED", |
| 153 | "file": "src/op.rs", |
| 154 | "line": (u64|118), |
| 155 | "value": (u8|9), |
| 156 | "axis": "vocabulary", |
| 157 | "holds": "the second spelling of a mark, for one carrying a body, a time, or both" |
| 158 | }, |
| 159 | { |
| 160 | "name": "op::CODE_PROPOSAL", |
| 161 | "file": "src/op.rs", |
| 162 | "line": (u64|119), |
| 163 | "value": (u8|10), |
| 164 | "axis": "vocabulary", |
| 165 | "holds": "what is being asked for" |
| 166 | }, |
| 167 | { |
| 168 | "name": "op::CODE_SAID", |
| 169 | "file": "src/op.rs", |
| 170 | "line": (u64|120), |
| 171 | "value": (u8|11), |
| 172 | "axis": "vocabulary", |
| 173 | "holds": "one remark in a proposal's discussion" |
| 174 | }, |
| 175 | { |
| 176 | "name": "op::CODE_SETTLED", |
| 177 | "file": "src/op.rs", |
| 178 | "line": (u64|121), |
| 179 | "value": (u8|12), |
| 180 | "axis": "vocabulary", |
| 181 | "holds": "what became of a proposal" |
| 182 | }, |
| 183 | { |
| 184 | "name": "op::CODE_REVERTS", |
| 185 | "file": "src/op.rs", |
| 186 | "line": (u64|122), |
| 187 | "value": (u8|13), |
| 188 | "axis": "vocabulary", |
| 189 | "holds": "what a set of operations undoes; the top of the version 4 vocabulary" |
| 190 | }, |
| 191 | { |
| 192 | "name": "op::CODE_AMENDED", |
| 193 | "file": "src/op.rs", |
| 194 | "line": (u64|123), |
| 195 | "value": (u8|14), |
| 196 | "axis": "vocabulary", |
| 197 | "holds": "a proposal restated by the voice that opened it; the top of the version 5 vocabulary" |
| 198 | }, |
| 199 | { |
| 200 | "name": "op::CODE_FORGET", |
| 201 | "file": "src/op.rs", |
| 202 | "line": (u64|124), |
| 203 | "value": (u8|15), |
| 204 | "axis": "vocabulary", |
| 205 | "holds": "earlier operations losing their content and keeping their shape; the act recorded so that every replica forgets the same things" |
| 206 | }, |
| 207 | { |
| 208 | "name": "op::CODE_FORGOTTEN", |
| 209 | "file": "src/op.rs", |
| 210 | "line": (u64|125), |
| 211 | "value": (u8|16), |
| 212 | "axis": "vocabulary", |
| 213 | "holds": "what stands under a forgotten operation's own header once its bytes are gone: its shape, written by a repack and vouched for by the Forget that names it; the top of the version 6 vocabulary" |
| 214 | }, |
| 215 | { |
| 216 | "name": "op::MODE_NORMAL", |
| 217 | "file": "src/op.rs", |
| 218 | "line": (u64|281), |
| 219 | "value": (u8|0), |
| 220 | "axis": "field", |
| 221 | "holds": "the mode a file has unless something says otherwise" |
| 222 | }, |
| 223 | { |
| 224 | "name": "op::MODE_EXECUTABLE", |
| 225 | "file": "src/op.rs", |
| 226 | "line": (u64|282), |
| 227 | "value": (u8|1), |
| 228 | "axis": "field", |
| 229 | "holds": "the mode a FileMode operation carries for an executable" |
| 230 | }, |
| 231 | { |
| 232 | "name": "op::MODE_SYMLINK", |
| 233 | "file": "src/op.rs", |
| 234 | "line": (u64|283), |
| 235 | "value": (u8|2), |
| 236 | "axis": "field", |
| 237 | "holds": "the mode a FileMode operation carries for a symbolic link" |
| 238 | }, |
| 239 | { |
| 240 | "name": "op::SETTLED_OPEN", |
| 241 | "file": "src/op.rs", |
| 242 | "line": (u64|287), |
| 243 | "value": (u8|0), |
| 244 | "axis": "field", |
| 245 | "holds": "a proposal nobody has settled" |
| 246 | }, |
| 247 | { |
| 248 | "name": "op::SETTLED_ACCEPTED", |
| 249 | "file": "src/op.rs", |
| 250 | "line": (u64|288), |
| 251 | "value": (u8|1), |
| 252 | "axis": "field", |
| 253 | "holds": "a proposal taken up" |
| 254 | }, |
| 255 | { |
| 256 | "name": "op::SETTLED_DECLINED", |
| 257 | "file": "src/op.rs", |
| 258 | "line": (u64|289), |
| 259 | "value": (u8|2), |
| 260 | "axis": "field", |
| 261 | "holds": "a proposal turned down" |
| 262 | }, |
| 263 | { |
| 264 | "name": "op::SETTLED_DONE", |
| 265 | "file": "src/op.rs", |
| 266 | "line": (u64|290), |
| 267 | "value": (u8|3), |
| 268 | "axis": "field", |
| 269 | "holds": "a proposal carried out" |
| 270 | }, |
| 271 | { |
| 272 | "name": "op::AUTO_MARK_PREFIX", |
| 273 | "file": "src/op.rs", |
| 274 | "line": (u64|136), |
| 275 | "value": "@", |
| 276 | "axis": "convention", |
| 277 | "holds": "the character an automatic mark's name begins with, and which a person's mark may not; it separates the marks a person named from the ones a command wrote" |
| 278 | }, |
| 279 | { |
| 280 | "name": "op::AUTHOR_TRAILER", |
| 281 | "file": "src/op.rs", |
| 282 | "line": (u64|196), |
| 283 | "value": "Ore-Author: ", |
| 284 | "axis": "convention", |
| 285 | "holds": "the commit-message trailer the git exporter writes and the git importer reads; a mismatch loses attribution silently in both directions" |
| 286 | }, |
| 287 | { |
| 288 | "name": "sync::msg::MAGIC", |
| 289 | "file": "src/sync/msg.rs", |
| 290 | "line": (u64|29), |
| 291 | "value": "ORESYN", |
| 292 | "axis": "frame", |
| 293 | "holds": "the six bytes every sync message begins with" |
| 294 | }, |
| 295 | { |
| 296 | "name": "sync::msg::VERSION", |
| 297 | "file": "src/sync/msg.rs", |
| 298 | "line": (u64|63), |
| 299 | "value": (u8|4), |
| 300 | "axis": "vocabulary", |
| 301 | "holds": "the newest set of message kinds a peer may send, stamped only on a message that needs it. It does not move when the OPERATION vocabulary does, so an old relay accepts the frame and then fails inside Entry::from_dat, after the handshake said it was compatible; it moved to 2 for sync::msg::KIND_PART, to 3 for sync::msg::KIND_FORGOTTEN and to 4 for sync::msg::KIND_RESUME, where the refusal lands at the header instead" |
| 302 | }, |
| 303 | { |
| 304 | "name": "sync::msg::VERSION_MIN", |
| 305 | "file": "src/sync/msg.rs", |
| 306 | "line": (u64|73), |
| 307 | "value": (u8|1), |
| 308 | "axis": "vocabulary", |
| 309 | "holds": "the oldest message version this crate reads, and the version stamped on every message a version 1 peer could itself have sent; it stays at 1 because versions 2, 3 and 4 each added a kind above the existing ones and moved nothing else" |
| 310 | }, |
| 311 | { |
| 312 | "name": "sync::msg::KIND_HELLO", |
| 313 | "file": "src/sync/msg.rs", |
| 314 | "line": (u64|76), |
| 315 | "value": (u8|1), |
| 316 | "axis": "vocabulary", |
| 317 | "holds": "a peer opening a session" |
| 318 | }, |
| 319 | { |
| 320 | "name": "sync::msg::KIND_SKETCH", |
| 321 | "file": "src/sync/msg.rs", |
| 322 | "line": (u64|77), |
| 323 | "value": (u8|2), |
| 324 | "axis": "vocabulary", |
| 325 | "holds": "a peer offering what it holds" |
| 326 | }, |
| 327 | { |
| 328 | "name": "sync::msg::KIND_SEND", |
| 329 | "file": "src/sync/msg.rs", |
| 330 | "line": (u64|78), |
| 331 | "value": (u8|3), |
| 332 | "axis": "vocabulary", |
| 333 | "holds": "a peer handing entries over" |
| 334 | }, |
| 335 | { |
| 336 | "name": "sync::msg::KIND_DONE", |
| 337 | "file": "src/sync/msg.rs", |
| 338 | "line": (u64|79), |
| 339 | "value": (u8|4), |
| 340 | "axis": "vocabulary", |
| 341 | "holds": "a peer closing a session; the top of the version 1 vocabulary" |
| 342 | }, |
| 343 | { |
| 344 | "name": "sync::msg::KIND_PART", |
| 345 | "file": "src/sync/msg.rs", |
| 346 | "line": (u64|80), |
| 347 | "value": (u8|5), |
| 348 | "axis": "vocabulary", |
| 349 | "holds": "one piece of an operation the carrier cannot take whole; the top of the version 2 vocabulary. A piece is not an operation: nothing places it, nothing signs it, and no segment may carry it, which is why it is a message kind and not an entry kind beside segment::KIND_PACKED" |
| 350 | }, |
| 351 | { |
| 352 | "name": "sync::msg::KIND_FORGOTTEN", |
| 353 | "file": "src/sync/msg.rs", |
| 354 | "line": (u64|81), |
| 355 | "value": (u8|6), |
| 356 | "axis": "vocabulary", |
| 357 | "holds": "records to be written in place of the operations a Forget names, so that a carrier's copy of a history stops holding their bytes; the top of the version 3 vocabulary. It is not an offer and no session absorbs it: every identifier it carries is one the receiver already holds, and what changes is the form it is held in. The SENDER builds the stubs in every case, because a carrier of a veiled repository can read neither the forget nor the record it names" |
| 358 | }, |
| 359 | { |
| 360 | "name": "sync::msg::KIND_RESUME", |
| 361 | "file": "src/sync/msg.rs", |
| 362 | "line": (u64|82), |
| 363 | "value": (u8|7), |
| 364 | "axis": "vocabulary", |
| 365 | "holds": "how far into what the receiver last owed the speaker the speaker was carried; the top of the version 4 vocabulary. It names an operation and not a count, because an owed set is recomputed every session and a log's append order is not, and it rides BESIDE an opening rather than inside one so that the four original kinds are still spelled exactly as they were. Without it a bounded frontier walk against a peer whose head the carrier does not hold sends the same prefix every session, for ever" |
| 366 | }, |
| 367 | { |
| 368 | "name": "sync::msg::PART_MAX", |
| 369 | "file": "src/sync/msg.rs", |
| 370 | "line": (u64|93), |
| 371 | "value": (u64|67108864), |
| 372 | "axis": "vocabulary", |
| 373 | "holds": "the most an operation may come to when its pieces are put back together. A declared piece count is never sized from, only the bytes that actually arrived are counted, so this is a policy ceiling and not a guard against an allocation a peer could ask for" |
| 374 | } |
| 375 | ], |
| 376 | |
| 377 | "versions": [ |
| 378 | { |
| 379 | "version": (u8|2), |
| 380 | "highest_code": "op::CODE_NOTE", |
| 381 | "note": "frozen with the note at the top; the oldest version this crate reads" |
| 382 | }, |
| 383 | { |
| 384 | "version": (u8|3), |
| 385 | "highest_code": "op::CODE_FILE_MODE", |
| 386 | "note": "one code added above the version 2 vocabulary and nothing else; the framing did not move a byte" |
| 387 | }, |
| 388 | { |
| 389 | "version": (u8|4), |
| 390 | "highest_code": "op::CODE_REVERTS", |
| 391 | "note": "five codes added at once, for the mark's second spelling and the proposal operations" |
| 392 | }, |
| 393 | { |
| 394 | "version": (u8|5), |
| 395 | "highest_code": "op::CODE_AMENDED", |
| 396 | "note": "one code added above the version 4 vocabulary and nothing else, so that a proposal's author can state it again without the opening operation being touched" |
| 397 | }, |
| 398 | { |
| 399 | "version": (u8|6), |
| 400 | "highest_code": "op::CODE_FORGOTTEN", |
| 401 | "note": "two codes added above the version 5 vocabulary: a Forget, which names earlier operations and the shape each keeps, and a Forgotten, which a repack writes in a forgotten operation's place. History is the author's data; what the log keeps for good is that it forgot" |
| 402 | } |
| 403 | ], |
| 404 | |
| 405 | "goldens": [ |
| 406 | { |
| 407 | "name": "the_segment_bytes_are_frozen", |
| 408 | "file": "src/segment.rs", |
| 409 | "magic": "segment::MAGIC", |
| 410 | "holds": "a one record segment carrying a mark with neither a body nor a time; the fixed point for the framing and for the mark spelling every signature in every repository depends on", |
| 411 | "pins": [ |
| 412 | { "at": (u64|6), "is": "segment::VERSION" }, |
| 413 | { "at": (u64|9), "is": "segment::KIND_BARE" }, |
| 414 | { "at": (u64|66), "is": "op::CODE_MARK" } |
| 415 | ] |
| 416 | }, |
| 417 | { |
| 418 | "name": "the_file_mode_bytes_are_frozen", |
| 419 | "file": "src/segment.rs", |
| 420 | "magic": "segment::MAGIC", |
| 421 | "holds": "the operation the version 3 bump exists for, in the encoding it was added in; it is spelled the same in version 4, which is why a store full of them needs no migration", |
| 422 | "pins": [ |
| 423 | { "at": (u64|6), "is": "segment::VERSION" }, |
| 424 | { "at": (u64|8), "is": "segment::KIND_BARE" }, |
| 425 | { "at": (u64|43), "is": "op::CODE_FILE_MODE" }, |
| 426 | { "at": (u64|66), "is": "op::MODE_EXECUTABLE" } |
| 427 | ] |
| 428 | }, |
| 429 | { |
| 430 | "name": "the_veiled_bytes_are_frozen", |
| 431 | "file": "src/segment.rs", |
| 432 | "magic": "segment::MAGIC", |
| 433 | "holds": "the veiled framing under the identity encrypter, and the fact that the entry a veil is put around is the entry that was signed, byte for byte", |
| 434 | "pins": [ |
| 435 | { "at": (u64|6), "is": "segment::VERSION" }, |
| 436 | { "at": (u64|8), "is": "segment::KIND_VEILED" }, |
| 437 | { "at": (u64|74), "is": "segment::KIND_BARE" }, |
| 438 | { "at": (u64|130), "is": "op::CODE_MARK" } |
| 439 | ] |
| 440 | }, |
| 441 | { |
| 442 | "name": "the_message_bytes_are_frozen", |
| 443 | "file": "src/sync/msg.rs", |
| 444 | "magic": "sync::msg::MAGIC", |
| 445 | "holds": "a send message carrying one bare entry; it has no segment header, so the operation vocabulary rising does not move a byte of it, and the message vocabulary rising does not either -- a message is stamped with the version it needs, so this one still says 1", |
| 446 | "pins": [ |
| 447 | { "at": (u64|6), "is": "sync::msg::VERSION_MIN" }, |
| 448 | { "at": (u64|11), "is": "sync::msg::KIND_SEND" }, |
| 449 | { "at": (u64|19), "is": "segment::KIND_BARE" }, |
| 450 | { "at": (u64|75), "is": "op::CODE_MARK" } |
| 451 | ] |
| 452 | }, |
| 453 | { |
| 454 | "name": "the_part_bytes_are_frozen", |
| 455 | "file": "src/sync/msg.rs", |
| 456 | "magic": "sync::msg::MAGIC", |
| 457 | "holds": "the first of the two pieces a small bare entry is cut into. What it freezes beyond the framing is that the payload is a PREFIX OF THE ENTRY'S OWN BYTES and not a re-encoding of it, which is the whole of why a signature survives being cut up: the bytes put back together are the bytes that were signed. Its version byte stopped being sync::msg::VERSION when that moved to 3: a message is stamped with the version it NEEDS, so a part still says 2 and an older peer reads every part it could read before", |
| 458 | "pins": [ |
| 459 | { "at": (u64|6), "is": "sync::msg::version_for(KIND_PART)" }, |
| 460 | { "at": (u64|11), "is": "sync::msg::KIND_PART" }, |
| 461 | { "at": (u64|67), "is": "segment::KIND_BARE" } |
| 462 | ] |
| 463 | }, |
| 464 | { |
| 465 | "name": "the_forgotten_bytes_are_frozen", |
| 466 | "file": "src/sync/msg.rs", |
| 467 | "magic": "sync::msg::MAGIC", |
| 468 | "holds": "a replacement message carrying one bare record in a forgotten operation's place. Two builds that disagree about this are two builds that disagree about which record a carrier writes over which, and the one that has it wrong destroys a history rather than failing to read one. Byte 80 is the Placing code, 0 for a void, which is the shape a forgotten mark or note keeps; byte 79 is the U8 tag in front of it", |
| 469 | "pins": [ |
| 470 | { "at": (u64|6), "is": "sync::msg::version_for(KIND_FORGOTTEN)" }, |
| 471 | { "at": (u64|11), "is": "sync::msg::KIND_FORGOTTEN" }, |
| 472 | { "at": (u64|19), "is": "segment::KIND_BARE" }, |
| 473 | { "at": (u64|75), "is": "op::CODE_FORGOTTEN" } |
| 474 | ] |
| 475 | }, |
| 476 | { |
| 477 | "name": "the_resume_bytes_are_frozen", |
| 478 | "file": "src/sync/msg.rs", |
| 479 | "magic": "sync::msg::MAGIC", |
| 480 | "holds": "a cursor, which is one identifier and the framing around it. What it freezes is that a cursor carries nothing else -- no count, no set, no claim about what was sent -- and that a peer built before it meets the refusal at the header, by version, rather than reading past a kind it does not know", |
| 481 | "pins": [ |
| 482 | { "at": (u64|6), "is": "sync::msg::VERSION" }, |
| 483 | { "at": (u64|11), "is": "sync::msg::KIND_RESUME" } |
| 484 | ] |
| 485 | } |
| 486 | ], |
| 487 | |
| 488 | "removed": [ |
| 489 | { |
| 490 | "name": "snapshot::VERSION", |
| 491 | "file": "src/snapshot.rs", |
| 492 | "gone": "12026-08-21", |
| 493 | "commit": "2e956a4", |
| 494 | "why": "the snapshot format was taken out once a render was measured linear rather than quadratic. The row is kept because the contract's own table went on naming this constant, at a line in a file that had been deleted, for four days" |
| 495 | }, |
| 496 | { |
| 497 | "name": "the_snapshot_bytes_are_frozen", |
| 498 | "file": "src/snapshot.rs", |
| 499 | "gone": "12026-08-21", |
| 500 | "commit": "2e956a4", |
| 501 | "why": "the golden test went with the format it froze. The contract's table went on listing it, which is the same failure twice in one document" |
| 502 | } |
| 503 | ], |
| 504 | |
| 505 | "open": [ |
| 506 | { |
| 507 | "question": "how a wrap stops being served, so that removing somebody from a veiled repository means something", |
| 508 | "asked": "12026-08-22", |
| 509 | "note": "key_distribution.md", |
| 510 | "why": "the wraps route takes a deposit and keeps one wrap per address, so a wrap can be replaced and cannot yet be taken away. Revocation is forward only whatever is built -- a departed member keeps whatever they already copied, and no scheme changes that -- so what is open is only the mechanism: a deposit that is authoritative over the whole list would let any pusher wipe everybody else's wraps, and a removal of one named address needs a name for the act and a rule about who may do it. Both are shared names, and the tool that mints a fresh content key on the other side of it has to say in words that operations already veiled under the old key stay readable to whoever held it", |
| 511 | "guard": ["WRAP_REVOKE", "revoke_wrap", "DROP_WRAP", "wraps_delete", "revoked", "revoke", "withdraw"] |
| 512 | } |
| 513 | ], |
| 514 | |
| 515 | "settled": [ |
| 516 | { |
| 517 | "question": "which key receives a wrapped content key, and what says that the key belongs to a replica", |
| 518 | "answer": "a SEPARATE X25519 key, the veil key, published by a binding over the tag ORE-VEIL-1 and signed by the replica's Ed25519 key. The tool spells the tag ore_store::veilkey::VEIL_BIND_TAG and names the scheme X25519 in the file's own scheme field, shaped on Ed25519 in .ore/key and AES-256-GCM in .ore/veil. Reusing the Ed25519 replica identity was possible and was refused: the two are the same curve in two coordinate systems and ed25519-dalek ships the conversion, but that library argues against this exact reuse in its own documentation, citing eprint 2021/509. The binding cannot certify itself the way ORE-BIND-1 does, because an X25519 key cannot sign. It is signed by the replica's Ed25519 key, whose own binding is self-certified, so a reader checks a chain of two links and a carrier can forge neither: a fabricated veil key fails the Ed25519 signature over it, and a fabricated Ed25519 binding fails its own", |
| 519 | "answered": "12026-08-22", |
| 520 | "note": "key_distribution.md", |
| 521 | "names": [], |
| 522 | "refused": ["ORE-WRAP-1", "ORE-KEM-1", "ORE-VEILKEY-1", "ORE-X25519-1", "VEILKEY_TAG", "WRAP_TAG", "Curve25519", "ECDH"] |
| 523 | }, |
| 524 | { |
| 525 | "question": "where a replica's veil key lives, and what that file is called", |
| 526 | "answer": "one word, veilkey, in the .ore directory beside the signing key and the content key, written under the same mode 0600; ore_store::veilkey::VEIL_KEY_FILE, format version 1. Its fields are the signing key file's -- format, scheme, replica, public, secret -- because it is the same kind of thing said about a different scheme, and a second spelling of the same five fields would be a seam for nothing. One word rather than veil-key or veil_key so that no reader takes it for a variant of the content key .ore/veil, which is a different key of a different kind for a different job. A veil key is per REPLICA and not per person, decided by the owner on 12026-08-22: a wrap is eighty bytes so three machines cost nothing, and a secret then lives on exactly one machine, so losing a laptop revokes exactly one thing instead of forcing a re-key. The cost accepted with it is that a relay's idea of who may read a repository is a list of replicas and not a list of people", |
| 527 | "answered": "12026-08-22", |
| 528 | "note": "key_distribution.md", |
| 529 | "names": [], |
| 530 | "refused": ["veilkeys", "wrapkey", "VEILKEY_FILE", "AGREE_FILE"] |
| 531 | }, |
| 532 | { |
| 533 | "question": "where the wraps and the veil bindings sit on a relay, and on which route they cross", |
| 534 | "answer": "two files beside acl in the hosted repository's own directory, veils for the bindings and wraps for the wraps, both served and taken at a route of their own, .../wraps. Not inside the repository: .ore is the one directory capture refuses by name, so the history cannot carry the key that opens it. Not inside acl: a wrap is not an authorisation, and folding it in would drag key material through every access check that has no use for it. Not on the keys route: the bindings there populate the trust set that decides provenance, a veil binding decides nothing about provenance, and leaving that route's bytes alone keeps a relay built before this able to answer a client built after it. THE RELAY SERVES WRAPS TO ANYBODY WHO MAY PULL, AND THAT IS NOT A LEAK -- a wrap is useless without the member's secret, which is why it may travel through the party it is being kept from", |
| 535 | "answered": "12026-08-22", |
| 536 | "note": "key_distribution.md", |
| 537 | "names": [], |
| 538 | "refused": ["WRAP_FILE", "VEIL_RECORD_FILE", "wrapped_keys", "keybox"] |
| 539 | }, |
| 540 | { |
| 541 | "question": "what one wrap says about itself", |
| 542 | "answer": "three fields and nothing else: to, the veil public key the wrap is addressed to; eph, the ephemeral X25519 public key minted for this wrap alone; and wrapped, the content key encrypted under the key those two agree on. No replica number and no person's name, because the address is the key: membership is a set of replicas, and if a human readable list is ever wanted it joins through the voice record rather than by putting a name in here. The sender's key is ephemeral rather than static so that a member's leaked secret does not open every wrap ever made to them; be exact about what that buys, since it protects the WRAP and not the REPOSITORY -- every wrap an attacker can still fetch from the relay is still opened by that secret", |
| 543 | "answered": "12026-08-22", |
| 544 | "note": "key_distribution.md", |
| 545 | "names": [], |
| 546 | "refused": ["recipient", "ephemeral", "sealed_to", "wrapped_key", "eph_pk"] |
| 547 | }, |
| 548 | { |
| 549 | "question": "how a carrier's copy of a history stops holding what a forget took", |
| 550 | "answered": "12026-09-15", |
| 551 | "answer": "the PUSHER sends the sealed stubs, as sync::msg::KIND_FORGOTTEN, and the carrier writes each in place of the record it names. It is a message kind above the existing ones and sync::msg::VERSION moved to 3 for it, by the rule sync::msg::highest_kind states. Two alternatives were refused. Letting the carrier build the stubs itself works for a plain repository and cannot work at all for a veiled one -- the carrier reads neither the forget nor the record it names -- so it would have been one path for plain histories and no path for private ones. Putting the records in a Send was refused because a session absorbs a send, and absorbing one of these places nothing: every identifier in it is one the receiver already holds, and a carrier acting on a send would be rewriting its store from what it was told to take in. A carrier sent a forget WITHOUT the stubs appends it and keeps its bytes until a later push carries them, which is what an older pusher does and is not refused", |
| 552 | "names": ["sync::msg::KIND_FORGOTTEN", "sync::msg::VERSION"], |
| 553 | "refused": ["KIND_STUB", "KIND_STUBS", "KIND_REPLACE", "KIND_REPLACEMENT"], |
| 554 | "note": "format_change_contract.md, \"Settled about forget\"" |
| 555 | }, |
| 556 | { |
| 557 | "question": "how an operation larger than the carrier's request limit crosses at all", |
| 558 | "answer": "its ENCODED BYTES are cut into pieces and put back together at the far end, as sync::msg::KIND_PART. Three alternatives were refused on their merits. Raising the server's limit fixes one operation and leaves the next, and the owner refused it for exactly that reason. Splitting the OPERATION -- one large Splice becoming several -- changes what was signed and cannot touch an operation already in a log. Compressing it moves the threshold rather than removing it, and segment::KIND_PACKED already does that where it belongs. Cutting the bytes leaves the operation exactly as it was, which is the only one of the four that keeps the per-operation signature intact", |
| 559 | "answered": "12026-08-22", |
| 560 | "note": "relay_transport.md", |
| 561 | "names": ["sync::msg::KIND_PART"], |
| 562 | "refused": ["KIND_CHUNK", "KIND_FRAGMENT", "KIND_SLICE", "KIND_PIECE"] |
| 563 | }, |
| 564 | { |
| 565 | "question": "which axis a piece sits on: a message kind, or an entry kind on the container axis beside segment::KIND_PACKED", |
| 566 | "answer": "a MESSAGE kind, and the message version moved for it. The KIND_PACKED precedent does not transfer, and the reason it does not is the reason it was taken: a kind byte was right there because a SEGMENT stamps one version over many records, so a bump would condemn every plain record beside the new one. A message stamps its own version in its own bytes, so a bump condemns nothing it does not have to. Two further reasons. A piece is not a record -- it has no digest, no header of its own and may never reach a segment -- so an entry kind would be a form Store::append had to grow a refusal for, which is a form in the wrong crate. And the refusal lands better: a message kind is refused at the header, before a decode and naming both versions, where an entry kind is refused inside Entry::from_dat, after the handshake has already said the frame was compatible", |
| 567 | "answered": "12026-08-22", |
| 568 | "note": "relay_transport.md", |
| 569 | "names": ["sync::msg::KIND_PART", "sync::msg::VERSION"], |
| 570 | "refused": ["KIND_PARTED", "KIND_SPLIT", "KIND_PIECES"] |
| 571 | }, |
| 572 | { |
| 573 | "question": "whether sync::msg::VERSION moves, and what an old peer meets when it does", |
| 574 | "answer": "yes, 1 to 2, with sync::msg::VERSION_MIN introduced at 1 and a message stamped with THE VERSION IT NEEDS rather than the version its writer was built at. Every message a version 1 peer could have sent is spelled and stamped exactly as it was, so the_message_bytes_are_frozen does not move a byte and its pin at index 6 moves from VERSION to VERSION_MIN. An old peer meets a version 2 message at the header and refuses by name, saying both versions; sync::msg::highest_kind makes the superset promise true of the bytes and not merely of the intention, so a part stamped as version 1 is refused too", |
| 575 | "answered": "12026-08-22", |
| 576 | "note": "relay_transport.md", |
| 577 | "names": ["sync::msg::VERSION", "sync::msg::VERSION_MIN"], |
| 578 | "refused": ["MSG_VERSION", "ORESYN_VERSION", "VERSION_PART"] |
| 579 | }, |
| 580 | { |
| 581 | "question": "what a piece says about itself, and what puts a run of them back together", |
| 582 | "answer": "id, seq, total and bytes, and sync::msg::Parts. The identifier is carried in clear beside the pieces and compared against the header inside the reassembled entry, for the reason a veiled entry carries its header twice: a carrier that cut an operation up is a carrier that could have relabelled the pieces, and the record inside is the signed one. Parts holds ONE run and nothing durable: a run begins at piece zero and a piece zero discards whatever the attempt before it left, so a push that died halfway completes on a rerun rather than doubling, and the operation -- never absorbed -- is offered again of its own accord. That is resume-is-rerun unchanged", |
| 583 | "answered": "12026-08-22", |
| 584 | "note": "relay_transport.md", |
| 585 | "names": [], |
| 586 | "refused": ["Reassembler", "Assembler", "PartBuffer", "chunk_no", "nparts", "piece_count"] |
| 587 | }, |
| 588 | { |
| 589 | "question": "what bounds an operation put back together out of pieces", |
| 590 | "answer": "sync::msg::PART_MAX, sixty-four mebibytes, the same as segment::PACKED_MAX and the relay's frame limit. It is a POLICY ceiling and not a guard against an allocation a peer could ask for: a declared piece count is never sized from, and the bytes counted are the bytes that arrived, so a peer wanting to make a carrier hold a gigabyte has to send one. The number is the largest single operation whose arrival costs no more than opening the repository it belongs to already costs, an operation of n bytes being held about three times over while it is taken in", |
| 591 | "answered": "12026-08-22", |
| 592 | "note": "relay_transport.md", |
| 593 | "names": ["sync::msg::PART_MAX"], |
| 594 | "refused": ["PART_LIMIT", "MAX_PART", "REASSEMBLY_MAX"] |
| 595 | }, |
| 596 | { |
| 597 | "question": "the spelling of the flag that says a segment is compressed", |
| 598 | "answer": "segment::KIND_PACKED, byte 4. It says a run was PACKED rather than naming the algorithm, because the algorithm is revisable by a repack and a name like DEFLATED would not be", |
| 599 | "answered": "12026-08-21", |
| 600 | "note": "segment_compression.md", |
| 601 | "names": ["segment::KIND_PACKED"], |
| 602 | "refused": ["KIND_COMPRESSED", "COMPRESSED", "COMPRESSION", "compressed", "compression"] |
| 603 | }, |
| 604 | { |
| 605 | "question": "which axis the flag sits on: a header field, a kind byte, or the version", |
| 606 | "answer": "a kind byte, on the container axis, exactly as the veil was. The KIND_VEILED doc argues it in its own words -- the kind byte says so in the record where it is rather than in a header that would condemn every plain record beside it -- and a header field could not have been free anyway, since entries begin immediately after the header and a new field would make an old reader parse it as the start of an entry", |
| 607 | "answered": "12026-08-21", |
| 608 | "note": "segment_compression.md", |
| 609 | "names": ["segment::KIND_PACKED"], |
| 610 | "refused": ["COMPRESS_AXIS"] |
| 611 | }, |
| 612 | { |
| 613 | "question": "which compression algorithm, named on the wire or implied by the version", |
| 614 | "answer": "deflate, through flate2, implied by the kind and named nowhere on the wire. It resolves to miniz_oxide, which is pure Rust and builds for wasm32; zstd binds C. At the megabyte frames this format uses, zstd's advantage is 2.9 points rather than the 4.5 it shows over a whole segment, because its long range matching is most of what a frame that size neutralises", |
| 615 | "answered": "12026-08-21", |
| 616 | "note": "segment_compression.md", |
| 617 | "names": [], |
| 618 | "refused": ["ALGO_ZSTD", "ALGO_DEFLATE", "COMPRESS_ALGO", "zstd"] |
| 619 | }, |
| 620 | { |
| 621 | "question": "whether the compression level is recorded in the segment", |
| 622 | "answer": "no. Deflate carries what it needs to inflate, so a reader never asks; recording it would invite a test to freeze it, and freezing it would freeze a dependency version and call it a format. For the same reason there is no golden byte test over a packed payload: the framing around a run is asserted structurally by the_packed_framing_is_fixed, and what a compressor made of the records is not a fact about Ore", |
| 623 | "answered": "12026-08-21", |
| 624 | "note": "segment_compression.md", |
| 625 | "names": [], |
| 626 | "refused": ["COMPRESS_LEVEL", "LEVEL_DEFAULT"] |
| 627 | }, |
| 628 | { |
| 629 | "question": "whether segment::VERSION rises for compression", |
| 630 | "answer": "no, it stays at 4. The rule the vocabulary grows by is about operation codes and compression adds none, so a packed segment declares the version its operations need and the two segment golden tests do not move a byte", |
| 631 | "answered": "12026-08-21", |
| 632 | "note": "segment_compression.md", |
| 633 | "names": ["segment::VERSION"], |
| 634 | "refused": [] |
| 635 | } |
| 636 | ] |
| 637 | } |