@packet-schema/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/collect-refs.d.ts +4 -0
  2. package/dist/collect-refs.d.ts.map +1 -0
  3. package/dist/collect-refs.js +76 -0
  4. package/dist/collect-refs.js.map +1 -0
  5. package/dist/constraint.d.ts +66 -0
  6. package/dist/constraint.d.ts.map +1 -0
  7. package/dist/constraint.js +286 -0
  8. package/dist/constraint.js.map +1 -0
  9. package/dist/expr.d.ts +32 -0
  10. package/dist/expr.d.ts.map +1 -0
  11. package/dist/expr.js +190 -0
  12. package/dist/expr.js.map +1 -0
  13. package/dist/index.d.ts +17 -0
  14. package/dist/index.d.ts.map +1 -0
  15. package/dist/index.js +19 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/layout.d.ts +7 -0
  18. package/dist/layout.d.ts.map +1 -0
  19. package/dist/layout.js +217 -0
  20. package/dist/layout.js.map +1 -0
  21. package/dist/normalize.d.ts +37 -0
  22. package/dist/normalize.d.ts.map +1 -0
  23. package/dist/normalize.js +857 -0
  24. package/dist/normalize.js.map +1 -0
  25. package/dist/types.d.ts +538 -0
  26. package/dist/types.d.ts.map +1 -0
  27. package/dist/types.js +27 -0
  28. package/dist/types.js.map +1 -0
  29. package/dist/utils.d.ts +3 -0
  30. package/dist/utils.d.ts.map +1 -0
  31. package/dist/utils.js +4 -0
  32. package/dist/utils.js.map +1 -0
  33. package/dist/validate.d.ts +8 -0
  34. package/dist/validate.d.ts.map +1 -0
  35. package/dist/validate.js +1222 -0
  36. package/dist/validate.js.map +1 -0
  37. package/dist/values.d.ts +31 -0
  38. package/dist/values.d.ts.map +1 -0
  39. package/dist/values.js +73 -0
  40. package/dist/values.js.map +1 -0
  41. package/dist/yaml.d.ts +11 -0
  42. package/dist/yaml.d.ts.map +1 -0
  43. package/dist/yaml.js +145 -0
  44. package/dist/yaml.js.map +1 -0
  45. package/package.json +35 -0
  46. package/schemas/psdl-0.5.yaml +1223 -0
@@ -0,0 +1,1223 @@
1
+ $schema: https://json-schema.org/draft/2020-12/schema
2
+ $id: https://packet-schema.dev/schemas/psdl-0.5.yaml
3
+ title: PSDL 0.5
4
+ description: |-
5
+ Packet Schema Definition Language 0.5 — canonical YAML schema for a single
6
+ packet definition file. The top-level document IS the Packet object.
7
+
8
+ Authoring shorthands (bare integer → ExprLit, bare field-id string →
9
+ ExprRef) are normalized to full object form by the parser before
10
+ JSON Schema validation. The schema validates the normalized form only.
11
+
12
+ # ──────────────────────────────────────────────────────────────────────
13
+ # Packet (top-level)
14
+ # ──────────────────────────────────────────────────────────────────────
15
+ type: object
16
+ required: [name, body]
17
+ unevaluatedProperties: false
18
+ $comment: |-
19
+ Some PSDL rules are intentionally validator-layer-only and cannot be encoded
20
+ in JSON Schema: imported-name visibility (§1.3), §11.4 lint warnings
21
+ (version-absent, recursive-def constraint skip, checksumParams on a named
22
+ CRC), and the placement restriction forbidding `virtual` fields inside
23
+ defs/NamedStruct bodies (§11.1). See the ImportEntry note for the import
24
+ examples.
25
+ properties:
26
+ version:
27
+ type: string
28
+ pattern: '^\d+\.\d+$'
29
+ description: |-
30
+ PSDL version string (e.g. "0.5"). Strongly recommended.
31
+ See §15 for version compatibility rules.
32
+ name:
33
+ type: string
34
+ minLength: 1
35
+ description: Unique packet identifier (globally unique within a packet set).
36
+ abbrev:
37
+ type: string
38
+ description: |-
39
+ Protocol filter name used by codegen (e.g. Wireshark).
40
+ Defaults to `name` if absent.
41
+ rowBits:
42
+ type: integer
43
+ minimum: 1
44
+ description: "Deprecated: use rendererHints.rowBits. Accepted for pre-0.5 compatibility."
45
+ body:
46
+ type: array
47
+ items:
48
+ $ref: '#/$defs/Container'
49
+ constraints:
50
+ type: array
51
+ items:
52
+ $ref: '#/$defs/Constraint'
53
+ byteOrder:
54
+ type: string
55
+ enum: [BE, LE]
56
+ description: Default byte order for all multi-byte integer fields.
57
+ description:
58
+ type: string
59
+ rendererHints:
60
+ $ref: '#/$defs/RendererHints'
61
+ meta:
62
+ $ref: '#/$defs/PacketMeta'
63
+ defs:
64
+ type: object
65
+ description: Named Struct definitions available for reuse via `ref` containers.
66
+ additionalProperties:
67
+ $ref: '#/$defs/NamedStruct'
68
+ imports:
69
+ type: array
70
+ description: |-
71
+ Cross-file def imports. Makes defs from other PSDL files available
72
+ under a namespace prefix. See §1.2.
73
+ items:
74
+ $ref: '#/$defs/ImportEntry'
75
+
76
+ $defs:
77
+
78
+ # ────────────────────────────────────────────────────────────────────
79
+ # Cross-file imports
80
+ # ────────────────────────────────────────────────────────────────────
81
+ ImportEntry:
82
+ type: object
83
+ required: [source, as]
84
+ additionalProperties: false
85
+ description: |-
86
+ Imports defs from another PSDL file under a local namespace prefix.
87
+ NOTE: JSON Schema cannot enforce the following constraints; they MUST be
88
+ enforced by the validator layer:
89
+ - All `as` values in the imports array must be unique (duplicate as
90
+ prefix is a validation error per §1.2 and §11.1).
91
+ - Circular import chains (A imports B imports A) are a validation error.
92
+ See §1.2 for the full import rules.
93
+ properties:
94
+ source:
95
+ type: string
96
+ minLength: 1
97
+ description: |-
98
+ Opaque path / package reference. Resolution is tool-layer concern
99
+ (filesystem path, npm package, URL).
100
+ as:
101
+ type: string
102
+ pattern: '^[a-zA-Z][a-zA-Z0-9_]*$'
103
+ description: |-
104
+ Namespace prefix used to reference imported defs.
105
+ Must match [a-zA-Z][a-zA-Z0-9_]* (see §1.2).
106
+
107
+ # ────────────────────────────────────────────────────────────────────
108
+ # Packet metadata
109
+ # ────────────────────────────────────────────────────────────────────
110
+ PacketMeta:
111
+ type: object
112
+ additionalProperties: false
113
+ description: RFC, alias, and classification metadata for tooling (codegen, Chrome extension, LSP, catalog).
114
+ properties:
115
+ rfc:
116
+ $ref: '#/$defs/RfcRef'
117
+ description: RFC provenance (bare number, or {defined, updates}).
118
+ section:
119
+ type: string
120
+ description: RFC section reference (e.g. "3.1").
121
+ aliases:
122
+ type: array
123
+ items: { type: string }
124
+ description: Alternative names for this packet type.
125
+ tags:
126
+ type: array
127
+ items: { type: string }
128
+ description: >-
129
+ Free-form classification tags for catalog grouping/search (§1.1).
130
+ Multi-axis; the vocabulary is governed by the catalog layer, not the
131
+ schema (open strings, like aliases — unlike the closed field `category`).
132
+ family:
133
+ type: string
134
+ description: Optional single grouping key for a family of related packet types (e.g. "bgp") (§1.1).
135
+
136
+ # ────────────────────────────────────────────────────────────────────
137
+ # Normative levels and RFC provenance
138
+ # ────────────────────────────────────────────────────────────────────
139
+ NormativeLevel:
140
+ type: string
141
+ enum: [must, should, may]
142
+ description: |-
143
+ RFC 2119 normative strength. Absent is treated as "must" for constraints
144
+ and as "may" for value-dictionary and enum-variant entries (§9.1, §5.3).
145
+
146
+ RfcRef:
147
+ description: |-
148
+ RFC provenance. Either a bare RFC number (legacy 0.5 form) or an object
149
+ recording the defining RFC plus the chain of updating RFCs (§5.4).
150
+ oneOf:
151
+ - type: integer
152
+ - type: object
153
+ required: [defined]
154
+ additionalProperties: false
155
+ properties:
156
+ defined: { type: integer, description: RFC that originally defined this field. }
157
+ updates:
158
+ type: array
159
+ description: |-
160
+ RFCs that later updated this field's layout or semantics. Each
161
+ entry is either a bare RFC number (no section) or an object
162
+ { rfc (required), section? } naming the section of that updating
163
+ RFC (§5.4). The defining RFC's own section is carried by the
164
+ sibling meta.section.
165
+ items:
166
+ oneOf:
167
+ - type: integer
168
+ - type: object
169
+ required: [rfc]
170
+ additionalProperties: false
171
+ properties:
172
+ rfc: { type: integer, description: An updating RFC number. }
173
+ section: { type: string, description: 'Section of that updating RFC (e.g. "3").' }
174
+
175
+ # ────────────────────────────────────────────────────────────────────
176
+ # Per-field / per-group RFC metadata
177
+ # ────────────────────────────────────────────────────────────────────
178
+ FieldMeta:
179
+ type: object
180
+ additionalProperties: false
181
+ description: Per-field or per-group RFC annotation used by Chrome extension and LSP.
182
+ properties:
183
+ rfc:
184
+ $ref: '#/$defs/RfcRef'
185
+ description: RFC provenance (bare number, or {defined, updates}).
186
+ section:
187
+ type: string
188
+ description: RFC section reference for this specific field.
189
+
190
+ # ────────────────────────────────────────────────────────────────────
191
+ # Renderer hints
192
+ # ────────────────────────────────────────────────────────────────────
193
+ RendererHints:
194
+ type: object
195
+ additionalProperties: false
196
+ description: |-
197
+ Display-only metadata. A packet without rowBits is a valid PSDL
198
+ document; renderers should fall back to 32 if absent.
199
+ properties:
200
+ rowBits:
201
+ type: integer
202
+ minimum: 1
203
+ description: Number of bits per row in the wire diagram.
204
+ sections:
205
+ type: array
206
+ description: |-
207
+ Visual section labels for the wire diagram. Display-only;
208
+ no effect on wire layout or expression scoping.
209
+ items:
210
+ $ref: '#/$defs/RendererSection'
211
+
212
+ RendererSection:
213
+ type: object
214
+ required: [id, label, fields]
215
+ additionalProperties: false
216
+ description: A labelled visual region in the wire diagram renderer.
217
+ properties:
218
+ id:
219
+ type: string
220
+ minLength: 1
221
+ description: Unique identifier for this section.
222
+ label:
223
+ type: string
224
+ minLength: 1
225
+ description: Human-readable section header.
226
+ fields:
227
+ type: array
228
+ items: { type: string }
229
+ description: |-
230
+ Ordered list of field ids or group ids belonging to this section.
231
+
232
+ # ────────────────────────────────────────────────────────────────────
233
+ # Checksum algorithm parameters
234
+ # ────────────────────────────────────────────────────────────────────
235
+ ChecksumParams:
236
+ type: object
237
+ additionalProperties: false
238
+ description: |-
239
+ CRC algorithm parameters for codegen. Allows full specification of
240
+ arbitrary CRC variants without a custom algorithm name string.
241
+ Only valid on a field whose checksumAlgorithm uses the CRC parameter
242
+ model; pairing it with a named non-CRC algorithm (internet, adler32)
243
+ is a validation error (§8, §11.1).
244
+ properties:
245
+ polynomial:
246
+ oneOf:
247
+ - { type: integer, minimum: 0 }
248
+ - { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
249
+ description: |-
250
+ Generator polynomial (normal / non-reflected form). A bare integer is
251
+ accepted for values ≤ 2^53−1; values needing more than 53 bits (e.g.
252
+ NVMe CRC-64/ECMA-182 polynomial 0xAD93D23594C935A9) MUST be written as
253
+ a 0x hex string so the full 64-bit precision survives. Note: the
254
+ schema accepts any non-negative integer, but the validator rejects a
255
+ bare integer above 2^53−1 (write it as a hex string instead) — schema
256
+ acceptance is not validity here (§8 Integer precision, §11.1).
257
+ initValue:
258
+ oneOf:
259
+ - { type: integer, minimum: 0 }
260
+ - { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
261
+ description: |-
262
+ Initial CRC register value. Same precision rule as polynomial: use a
263
+ 0x hex string for values above 2^53−1.
264
+ finalXOR:
265
+ oneOf:
266
+ - { type: integer, minimum: 0 }
267
+ - { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
268
+ description: |-
269
+ Value XORed with the final CRC result. Same precision rule as
270
+ polynomial: use a 0x hex string for values above 2^53−1.
271
+ inputReflect:
272
+ type: boolean
273
+ description: Reflect each input byte before processing.
274
+ outputReflect:
275
+ type: boolean
276
+ description: Reflect the final CRC before applying finalXOR.
277
+ width:
278
+ type: integer
279
+ minimum: 1
280
+ maximum: 64
281
+ description: |-
282
+ CRC width in bits (1–64). Optional; when absent the width equals the
283
+ checksum value field's declared bit width. Required when the field's
284
+ type has no single declared bit width (e.g. bytes), §8.
285
+
286
+ # ────────────────────────────────────────────────────────────────────
287
+ # Expressions
288
+ # ────────────────────────────────────────────────────────────────────
289
+ Expr:
290
+ description: |-
291
+ Pure, serialisable arithmetic / comparison expression.
292
+ Authoring shorthands:
293
+ bare integer N → { kind: lit, value: N }
294
+ bare string "f" → { kind: ref, field: "f" } (if matches field-id pattern)
295
+ These are normalized to full objects before schema validation.
296
+ oneOf:
297
+ - $ref: '#/$defs/ExprLit'
298
+ - $ref: '#/$defs/ExprRef'
299
+ - $ref: '#/$defs/ExprOp'
300
+ - $ref: '#/$defs/ExprCond'
301
+ - $ref: '#/$defs/ExprPeek'
302
+ - $ref: '#/$defs/ExprLookup'
303
+ - $ref: '#/$defs/ExprWireSize'
304
+ - $ref: '#/$defs/ExprPrevIter'
305
+ - $ref: '#/$defs/ExprRemaining'
306
+ - $ref: '#/$defs/ExprEnclosingBits'
307
+ - $ref: '#/$defs/ExprEnclosingField'
308
+
309
+ ExprLit:
310
+ type: object
311
+ required: [kind, value]
312
+ additionalProperties: false
313
+ properties:
314
+ kind: { const: lit }
315
+ value: { type: integer }
316
+
317
+ ExprRef:
318
+ type: object
319
+ required: [kind, field]
320
+ additionalProperties: false
321
+ description: |-
322
+ Value of a named field by id. If field is a repeat container's id (not a
323
+ leaf field), the expression evaluates to that repeat's completed iteration
324
+ count (the env[repeat.id] value mandated by §10.7 for both eos and
325
+ fixed-count repeats), not bytes; for the wire-byte footprint use wireSize.
326
+ See §4.
327
+ properties:
328
+ kind: { const: ref }
329
+ field: { type: string, minLength: 1 }
330
+
331
+ ExprOp:
332
+ type: object
333
+ required: [kind, op, a, b]
334
+ additionalProperties: false
335
+ properties:
336
+ kind: { const: op }
337
+ op:
338
+ type: string
339
+ enum:
340
+ - "+" # addition
341
+ - "-" # subtraction
342
+ - "*" # multiplication
343
+ - "/" # integer division (truncated toward zero)
344
+ - "%" # remainder
345
+ - "<<" # left shift (32-bit)
346
+ - ">>" # arithmetic right shift (32-bit)
347
+ - "==" # equal → 0 or 1
348
+ - "!=" # not equal → 0 or 1
349
+ - "<" # less than → 0 or 1
350
+ - "<=" # less or equal → 0 or 1
351
+ - ">" # greater than → 0 or 1
352
+ - ">=" # greater/equal → 0 or 1
353
+ - "&" # bitwise AND (32-bit)
354
+ - "|" # bitwise OR (32-bit)
355
+ - "^" # bitwise XOR (32-bit)
356
+ a: { $ref: '#/$defs/Expr' }
357
+ b: { $ref: '#/$defs/Expr' }
358
+
359
+ ExprCond:
360
+ type: object
361
+ required: [kind, test, t, f]
362
+ additionalProperties: false
363
+ description: Ternary — evaluates t if test ≠ 0, otherwise f.
364
+ properties:
365
+ kind: { const: cond }
366
+ test: { $ref: '#/$defs/Expr' }
367
+ t: { $ref: '#/$defs/Expr' }
368
+ f: { $ref: '#/$defs/Expr' }
369
+
370
+ ExprPeek:
371
+ type: object
372
+ required: [kind, bits]
373
+ additionalProperties: false
374
+ description: |-
375
+ Read-ahead in the bit stream without consuming. Valid only in
376
+ switch.on, optional.when, and repeat.count (including until).
377
+ See §10.6 for parse-position semantics per context.
378
+ properties:
379
+ kind: { const: peek }
380
+ bits:
381
+ type: integer
382
+ minimum: 1
383
+ maximum: 64
384
+ description: 'Number of bits to read ahead; an integer in 1–64 (§4, §11.1).'
385
+ offset: { $ref: '#/$defs/Expr' }
386
+
387
+ ExprLookup:
388
+ type: object
389
+ required: [kind, key, table]
390
+ additionalProperties: false
391
+ description: |-
392
+ Discrete table lookup. Maps an integer key to an integer value.
393
+ If the key is absent from the table, the result is 0.
394
+ Useful for non-linear encodings such as CAN FD DLC-to-byte-count.
395
+ properties:
396
+ kind: { const: lookup }
397
+ key: { $ref: '#/$defs/Expr' }
398
+ table:
399
+ type: object
400
+ description: |-
401
+ Map from non-negative decimal integer key (as string) to integer
402
+ result value. Keys must match ^(0|[1-9][0-9]*)$ — negative keys,
403
+ hex literals, and non-numeric keys are a validation error (§4, §11.1).
404
+ propertyNames:
405
+ type: string
406
+ pattern: '^(0|[1-9][0-9]*)$'
407
+ additionalProperties: { type: integer }
408
+
409
+ ExprWireSize:
410
+ type: object
411
+ required: [kind, target]
412
+ additionalProperties: false
413
+ description: |-
414
+ Total bytes consumed on the wire by a named container or field
415
+ (`target`), including all recursively nested content for containers.
416
+ For a leaf field this is the field's wire footprint (bits/8 for
417
+ fixed-width types; the encoded size for varint/berLength). May appear in
418
+ constraints, in a Field.computedFrom hint, and in body expressions when
419
+ the target precedes the expression in document order (same
420
+ forward-reference rule as ref). Absent target yields 0. In
421
+ constraints/computedFrom it is evaluated bottom-up after recursive
422
+ encoding for length back-propagation (§4).
423
+ properties:
424
+ kind: { const: wireSize }
425
+ target:
426
+ type: string
427
+ minLength: 1
428
+ description: Id of the named container or field whose wire byte size is returned.
429
+
430
+ ExprPrevIter:
431
+ type: object
432
+ required: [kind, field]
433
+ additionalProperties: false
434
+ description: |-
435
+ Value of a named field from the most recently completed iteration of the
436
+ immediately enclosing repeat. Valid only inside repeat.count.until
437
+ (§4, §10.4). On the first iteration yields the field's seeded value
438
+ (§10.2) or 0.
439
+ properties:
440
+ kind: { const: prevIter }
441
+ field:
442
+ type: string
443
+ minLength: 1
444
+ description: Id of the field whose previous-iteration value is returned.
445
+
446
+ ExprRemaining:
447
+ type: object
448
+ required: [kind]
449
+ additionalProperties: false
450
+ description: |-
451
+ Bytes remaining in the immediately enclosing scope-providing container
452
+ (bounded scope, encrypted.plaintext, or top-level body) at the point of
453
+ evaluation: (scope byte budget) − (bytes already consumed). Replaces the
454
+ former per-scope byte-budget primitives (see §4).
455
+ Valid in bytes.n and other body expressions
456
+ (including inside cond) — last-data-consuming position, mid-scope, or in
457
+ a cond. For end-anchored fields, size the preceding data field
458
+ remaining - <constByteCount> and place the fixed-width end fields after
459
+ it (§5). Using it outside a scope-providing container is a validation
460
+ error (§4). Used inside an encrypted.plaintext whose encrypted container
461
+ omits wireBits, the plaintext budget is undefined and remaining there is
462
+ a validation error (§5 Encrypted, §11.1).
463
+ properties:
464
+ kind: { const: remaining }
465
+
466
+ ExprEnclosingBits:
467
+ type: object
468
+ required: [kind]
469
+ additionalProperties: false
470
+ description: |-
471
+ Absolute bit budget of the nearest scope-providing container that carries
472
+ one: inside an encrypted.plaintext it equals the enclosing encrypted
473
+ container's wireBits expression (evaluated during parse, subject to the
474
+ normal forward-reference rule); at the top-level body it is the externally
475
+ decoder-injected total packet bit count (a constant available before
476
+ parsing, exempt from forward-reference). (A bounded scope's budget is
477
+ authored in bytes, so it does not provide enclosingBits.) Bit-precision
478
+ counterpart of `remaining`; merges the former per-scope bit-budget
479
+ primitives into one form (see §4). Authors write
480
+ enclosingBits / 8 for a byte boundary. Using it outside an encrypted.plaintext struct or the top-level
481
+ body is a validation error; at the top-level body it requires the decoder
482
+ to inject the total packet size (otherwise a runtime error); inside an
483
+ encrypted.plaintext whose encrypted container omits wireBits the budget is
484
+ undefined (validation error, §11.1). §4, §10.1.
485
+ properties:
486
+ kind: { const: enclosingBits }
487
+
488
+ ExprEnclosingField:
489
+ type: object
490
+ required: [kind, field]
491
+ additionalProperties: false
492
+ description: |-
493
+ Value of a named field from the immediately enclosing protocol layer's
494
+ parsed state (cross-layer access, §7). Valid in constraints only; using
495
+ it in a body expression is a validation error. If no enclosing layer is
496
+ present the expression yields 0 (same as an absent-field reference).
497
+ properties:
498
+ kind: { const: enclosingField }
499
+ field:
500
+ type: string
501
+ minLength: 1
502
+ description: Id of the field in the enclosing layer's PSDL document.
503
+
504
+ # ────────────────────────────────────────────────────────────────────
505
+ # Wire types
506
+ # ────────────────────────────────────────────────────────────────────
507
+ Type:
508
+ oneOf:
509
+ - $ref: '#/$defs/TypeInt'
510
+ - $ref: '#/$defs/TypeBits'
511
+ - $ref: '#/$defs/TypeBytes'
512
+ - $ref: '#/$defs/TypeEnum'
513
+ - $ref: '#/$defs/TypeVarint'
514
+ - $ref: '#/$defs/TypeBerLength'
515
+
516
+ TypeInt:
517
+ type: object
518
+ required: [kind, bits]
519
+ additionalProperties: false
520
+ description: Fixed-width integer.
521
+ properties:
522
+ kind: { const: int }
523
+ bits: { type: integer, minimum: 1 }
524
+ signed: { type: boolean }
525
+
526
+ TypeBits:
527
+ type: object
528
+ required: [kind, n]
529
+ additionalProperties: false
530
+ description: |-
531
+ Raw bit field (no numeric semantics). A bits field that is a whole number
532
+ of bytes wide (n a multiple of 8, > 8) and begins on a byte boundary
533
+ follows the packet-level byteOrder for its multi-byte read; any other
534
+ width, or a field beginning/ending mid-byte, is a raw MSB-first bit run
535
+ with no byte-order swap (§12).
536
+ properties:
537
+ kind: { const: bits }
538
+ n: { type: integer, minimum: 1 }
539
+
540
+ TypeBytes:
541
+ type: object
542
+ required: [kind, n]
543
+ additionalProperties: false
544
+ description: |-
545
+ Variable-length byte array; length given by an expression (in bytes) or by
546
+ a `delimiter` form (§3). To consume all remaining bytes of the
547
+ enclosing scope-providing container use n: { kind: remaining } (§4). For
548
+ end-anchored fields, size this field n: remaining - <constByteCount> and
549
+ place the fixed-width end fields after it (§5).
550
+ properties:
551
+ kind: { const: bytes }
552
+ n:
553
+ oneOf:
554
+ - $ref: '#/$defs/Expr'
555
+ - $ref: '#/$defs/BytesDelimited'
556
+
557
+ BytesDelimited:
558
+ type: object
559
+ required: [delimiter]
560
+ additionalProperties: false
561
+ description: |-
562
+ Delimiter-terminated byte length (§3). The field spans from the current
563
+ parse position up to and including the first complete occurrence of the
564
+ delimiter byte sequence; the delimiter is always consumed and is part of
565
+ the field's wire footprint. Length is decoder-determined and forward-only.
566
+ Unrelated to the repeat.count.until after-iteration predicate (§5).
567
+ properties:
568
+ delimiter:
569
+ type: array
570
+ minItems: 1
571
+ items: { type: integer, minimum: 0, maximum: 255 }
572
+ description: Non-empty list of delimiter byte values (each 0–255), e.g. [13, 10] for CRLF or [0] for NUL.
573
+
574
+ ValueEntry:
575
+ type: object
576
+ additionalProperties: false
577
+ description: |-
578
+ Open value-dictionary entry (§5.3). Annotates one discrete value or an
579
+ inclusive range with meaning, normative strength, and provenance. Purely
580
+ annotational: does not close the value space and carries no wire semantics.
581
+ properties:
582
+ value:
583
+ type: integer
584
+ description: Single value. Mutually exclusive with `range`/`pattern`.
585
+ range:
586
+ type: array
587
+ minItems: 2
588
+ maxItems: 2
589
+ items: { type: integer }
590
+ description: Inclusive [min, max] (min ≤ max enforced by the validator). Mutually exclusive with `value`/`pattern`.
591
+ pattern:
592
+ type: string
593
+ pattern: '^[01xX]+$'
594
+ description: >-
595
+ Ternary bit-pattern predicate (0/1/x; uppercase X is accepted as a
596
+ synonym for x), read like a binary literal (rightmost char = bit 0).
597
+ Matches when every non-x bit equals the observed bit, e.g. "xxxx11"
598
+ for the DSCP experimental pool. Mutually exclusive with
599
+ `value`/`range`.
600
+ name: { type: string, description: Short machine-style symbol (e.g. "EF"). }
601
+ label: { type: string, description: Human-readable label. }
602
+ doc: { type: string }
603
+ level: { $ref: '#/$defs/NormativeLevel' }
604
+ meta: { $ref: '#/$defs/FieldMeta' }
605
+ oneOf:
606
+ - required: [value]
607
+ - required: [range]
608
+ - required: [pattern]
609
+
610
+ Subfield:
611
+ type: object
612
+ required: [id, name, mask]
613
+ additionalProperties: false
614
+ description: |-
615
+ Mask-addressed bit subfield over a parent int / byte-aligned bits field
616
+ (§12). The subfield decodes a slice of the parent's byte-order-resolved
617
+ integer value (value bit 0 = LSB). Display/annotation only — no wire bits,
618
+ no parse semantics. The mask must fit the parent's declared width (a
619
+ validator-layer check). Render-position placement is not guaranteed by 0.5.
620
+ properties:
621
+ id:
622
+ type: string
623
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
624
+ name:
625
+ type: string
626
+ mask:
627
+ oneOf:
628
+ - { type: integer, minimum: 0 }
629
+ - { type: string, pattern: '^0x[0-9A-Fa-f]+$' }
630
+ description: |-
631
+ Bit mask over the parent's decoded value (bit 0 = LSB). A bare integer
632
+ for ≤ 2^53−1; a 0x hex string for wider masks (D9 precedent), decoded
633
+ at full 64-bit precision.
634
+ doc: { type: string }
635
+ values: { type: array, items: { $ref: '#/$defs/ValueEntry' } }
636
+ level: { $ref: '#/$defs/NormativeLevel' }
637
+ category: { $ref: '#/$defs/CategoryToken' }
638
+ meta: { $ref: '#/$defs/FieldMeta' }
639
+
640
+ EnumVariant:
641
+ description: |-
642
+ Enum variant label. Either a plain string or an object with label, doc,
643
+ level (absent ≡ may, §9.1), and meta (§5.4).
644
+ oneOf:
645
+ - type: string
646
+ - type: object
647
+ required: [label]
648
+ additionalProperties: false
649
+ properties:
650
+ label: { type: string }
651
+ doc: { type: string }
652
+ level: { $ref: '#/$defs/NormativeLevel' }
653
+ meta: { $ref: '#/$defs/FieldMeta' }
654
+
655
+ TypeEnum:
656
+ type: object
657
+ required: [kind, bits, variants]
658
+ additionalProperties: false
659
+ description: Named enumeration; keys are numeric values.
660
+ properties:
661
+ kind: { const: enum }
662
+ bits: { type: integer, minimum: 1 }
663
+ variants:
664
+ type: object
665
+ propertyNames: { pattern: '^(0|[1-9][0-9]*)$' }
666
+ additionalProperties:
667
+ $ref: '#/$defs/EnumVariant'
668
+
669
+ TypeVarint:
670
+ type: object
671
+ required: [kind, encoding]
672
+ additionalProperties: false
673
+ description: |-
674
+ Variable-length integer. `encoding` names the scheme; predefined values
675
+ are quic, protobuf, cbor, ea-terminated, leb128. Arbitrary strings are
676
+ accepted for custom encodings (codec is responsible for implementing them).
677
+ properties:
678
+ kind: { const: varint }
679
+ encoding:
680
+ type: string
681
+ minLength: 1
682
+ $comment: |-
683
+ Predefined well-known values: quic, protobuf, cbor, ea-terminated,
684
+ leb128. Arbitrary strings are accepted for custom encodings. Linting
685
+ tools SHOULD warn when the value is non-empty but does not match any
686
+ of the five predefined values (likely a typo, e.g. "quite" for "quic").
687
+
688
+ TypeBerLength:
689
+ type: object
690
+ required: [kind]
691
+ additionalProperties: false
692
+ description: |-
693
+ BER-encoded length field (1–N bytes, self-describing). maxBytes caps the
694
+ maximum encoded length (1–5, default 5). Declaring maxBytes > 5 is a
695
+ validation error. Receiving a wire-encoded length exceeding maxBytes is
696
+ a runtime error.
697
+ properties:
698
+ kind: { const: berLength }
699
+ maxBytes:
700
+ type: integer
701
+ minimum: 1
702
+ maximum: 5
703
+ description: Maximum allowed BER encoded length in bytes (default 5).
704
+
705
+ # ────────────────────────────────────────────────────────────────────
706
+ # Category tokens
707
+ # ────────────────────────────────────────────────────────────────────
708
+ CategoryToken:
709
+ type: string
710
+ enum:
711
+ - addressing # source / destination address
712
+ - identifier # version, type, protocol number
713
+ - length # length / size field
714
+ - type # type / kind discriminator
715
+ - flags # boolean flag bits
716
+ - reserved # must-be-zero / future use
717
+ - checksum # integrity check value
718
+ - variable # payload or generic variable data
719
+ - payload-marker # marks the start of upper-layer payload
720
+
721
+ # ────────────────────────────────────────────────────────────────────
722
+ # Container hierarchy
723
+ # ────────────────────────────────────────────────────────────────────
724
+ Container:
725
+ description: |-
726
+ Any node that can appear in a packet body, def body, group, repeat
727
+ element, switch arm, bounded scope, or encrypted.plaintext field list.
728
+ A single uniform container union applies in every position (the former
729
+ Container/ContainerNoTrailer split existed only to gate trailer
730
+ placement, which has been removed in favour of ordinary end-anchored
731
+ fields, §5). Member order follows the §5 narrative.
732
+ Discriminated by `kind`; Field may omit `kind` (defaults to "field").
733
+ oneOf:
734
+ - $ref: '#/$defs/Field'
735
+ - $ref: '#/$defs/Virtual'
736
+ - $ref: '#/$defs/Group'
737
+ - $ref: '#/$defs/Optional'
738
+ - $ref: '#/$defs/Repeat'
739
+ - $ref: '#/$defs/Switch'
740
+ - $ref: '#/$defs/AlignContainer'
741
+ - $ref: '#/$defs/BoundedContainer'
742
+ - $ref: '#/$defs/Encrypted'
743
+ - $ref: '#/$defs/RefContainer'
744
+
745
+ Field:
746
+ type: object
747
+ required: [id, name, type]
748
+ additionalProperties: false
749
+ description: |-
750
+ A single wire field. `kind` may be omitted (defaults to "field").
751
+ Field `id` must match [a-zA-Z][a-zA-Z0-9_-]* and must not contain ".".
752
+ properties:
753
+ kind:
754
+ type: string
755
+ enum: [field]
756
+ id:
757
+ type: string
758
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
759
+ description: |-
760
+ Stable identifier used in expressions and cross-references.
761
+ Must not contain "." (reserved as the ref-expansion separator).
762
+ name:
763
+ type: string
764
+ description: Human-readable label.
765
+ type:
766
+ $ref: '#/$defs/Type'
767
+ doc:
768
+ type: string
769
+ meta:
770
+ $ref: '#/$defs/FieldMeta'
771
+ category:
772
+ $ref: '#/$defs/CategoryToken'
773
+ defaultValue:
774
+ type: integer
775
+ description: |-
776
+ Seed value injected into the env before parsing. Honoured for
777
+ fields inside defs as well as top-level fields. If const is also
778
+ set, const takes priority for env seeding.
779
+ byteOrder:
780
+ type: string
781
+ enum: [BE, LE]
782
+ description: |-
783
+ Per-field byte order override. Only affects int and enum types.
784
+ next:
785
+ type: object
786
+ description: |-
787
+ Protocol-linking map: field value → next-layer packet name.
788
+ Values SHOULD match the `name` or `meta.aliases` of the target
789
+ packet. The special key "_" is the catch-all default.
790
+ additionalProperties:
791
+ type: string
792
+ checksumAlgorithm:
793
+ type: string
794
+ description: |-
795
+ Algorithm for computing this checksum. Well-known values:
796
+ internet, crc32, crc32c, crc16, adler32. Arbitrary strings
797
+ accepted for custom algorithms (codec is responsible). A field
798
+ carrying checksumAlgorithm is computed and filled by the codec on
799
+ serialize after the covered fields are encoded (the authored/wire
800
+ value is ignored for output), analogous to the computedFrom contract
801
+ for length fields (§8, §4).
802
+ checksumCovers:
803
+ type: array
804
+ description: |-
805
+ Ordered list of field ids fed into the checksum computation.
806
+ Supports dotted paths (e.g. "src.oct0"), ref-container ids
807
+ (e.g. "src" → expands to all leaf fields of that ref in order), and
808
+ repeat-container ids (e.g. "chunks" → expands to the concatenated
809
+ wire bytes of every iteration in parse order, including any inner
810
+ align padding consumed within each iteration). When a checksum field
811
+ appears inside a repeat element, ids in its checksumCovers resolve
812
+ within the current iteration's scope (the repeat-indexed "#N"
813
+ instance), exactly as ref does (§10.4) — enabling per-block CRCs
814
+ (e.g. DNP3). See §8.
815
+ items:
816
+ type: string
817
+ checksumPseudoHeader:
818
+ type: string
819
+ enum: [ipv4, ipv6]
820
+ description: |-
821
+ Well-known pseudo-header prepended before checksumCovers when
822
+ computing the checksum. Used for TCP/UDP over IP.
823
+ checksumParams:
824
+ $ref: '#/$defs/ChecksumParams'
825
+ const:
826
+ type: integer
827
+ description: |-
828
+ Fixed value this field must carry. A mismatch is a runtime error.
829
+ Takes priority over defaultValue for env seeding; seeds the env
830
+ even when defaultValue is absent.
831
+ display:
832
+ type: string
833
+ enum: [dec, hex, oct, bin, ascii, utf8, addr]
834
+ description: |-
835
+ Display hint for renderers and Wireshark codegen. For numeric fields
836
+ a base (dec/hex/oct/bin, default dec); for bytes fields a rendering
837
+ (ascii/utf8/addr, default hex). No effect on wire encoding (§14).
838
+ values:
839
+ type: array
840
+ items: { $ref: '#/$defs/ValueEntry' }
841
+ description: |-
842
+ Open value dictionary for this field's discrete values (§5.3).
843
+ Annotational only; does not close the value space.
844
+ subfields:
845
+ type: array
846
+ items: { $ref: '#/$defs/Subfield' }
847
+ description: |-
848
+ Mask-addressed bit subfields over this int / byte-aligned bits field
849
+ (§12). Display/annotation only; value bit 0 = LSB of the decoded
850
+ value. The int-or-byte-aligned-bits restriction and the mask-fits-width
851
+ rule are validator-layer checks (§11.1).
852
+ computedFrom:
853
+ $ref: '#/$defs/ExprWireSize'
854
+ description: |-
855
+ Serializer hint only (does not affect parsing). Must be a wireSize
856
+ expression; instructs the codec to compute and fill this length
857
+ field bottom-up after recursive encoding is complete (§4, §6).
858
+ Using any other expression is a validation error.
859
+ allOf:
860
+ # §8/§11.1: checksumParams may only refine a CRC parameter model. Using it
861
+ # with a named non-CRC algorithm (internet, adler32) is a validation error —
862
+ # these algorithms have fixed internal parameters incompatible with the CRC set.
863
+ - if:
864
+ properties:
865
+ checksumAlgorithm:
866
+ enum: [internet, adler32]
867
+ required: [checksumAlgorithm]
868
+ then:
869
+ not:
870
+ required: [checksumParams]
871
+
872
+ Virtual:
873
+ type: object
874
+ required: [kind, id, expr]
875
+ additionalProperties: false
876
+ description: |-
877
+ Computed auxiliary field that consumes zero wire bytes. Its expr is
878
+ evaluated at parse time using the same forward-reference rules as body
879
+ expressions; its id is added to the env for subsequent expressions,
880
+ constraints, and checksumCovers (§5 Virtual field). Forbidden inside
881
+ defs/NamedStruct bodies (§11.1) — that placement restriction is enforced
882
+ by the validator layer, not this schema.
883
+ properties:
884
+ kind: { const: virtual }
885
+ id:
886
+ type: string
887
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
888
+ description: Identifier added to the env and usable in subsequent expressions.
889
+ expr: { $ref: '#/$defs/Expr' }
890
+ name: { type: string }
891
+ doc: { type: string }
892
+
893
+ Optional:
894
+ type: object
895
+ required: [kind, when, container]
896
+ additionalProperties: false
897
+ description: |-
898
+ Conditionally includes a container. `when` evaluated as boolean
899
+ (0 = absent, non-zero = present). Nesting Optional inside Optional
900
+ is allowed; inner `when` is evaluated only if the outer is present
901
+ (short-circuit semantics). See §10.8.
902
+ properties:
903
+ kind: { const: optional }
904
+ id:
905
+ type: string
906
+ description: |-
907
+ Optional identifier for the optional container. Used by §13
908
+ rendererHints.sections and wireSize (§4). Note wireSize on an
909
+ absent optional's inner field yields 0; target the inner field id,
910
+ not the optional container id.
911
+ when: { $ref: '#/$defs/Expr' }
912
+ container: { $ref: '#/$defs/Container' }
913
+ doc:
914
+ type: string
915
+ description: Description for LSP hover documentation.
916
+ meta:
917
+ $ref: '#/$defs/FieldMeta'
918
+ description: |-
919
+ Per-region RFC annotation { rfc?, section? } enabling LSP hover and
920
+ per-region RFC deep-linking for this optional container (§5).
921
+ Available through the source AST only (§5.4): the optional is
922
+ transparent in the flat normalized model.
923
+
924
+ Struct:
925
+ type: object
926
+ required: [id, fields]
927
+ additionalProperties: false
928
+ description: |-
929
+ Named list of containers; used in Repeat.element, Switch.cases arms,
930
+ and Encrypted.plaintext. Does not carry the recursive property — only
931
+ NamedStruct (used exclusively in defs) may be recursive.
932
+ properties:
933
+ id:
934
+ type: string
935
+ minLength: 1
936
+ doc:
937
+ type: string
938
+ description: Description for LSP hover and tooling documentation.
939
+ meta:
940
+ $ref: '#/$defs/FieldMeta'
941
+ description: |-
942
+ Per-region RFC annotation { rfc?, section? } for the inline struct
943
+ used as a Switch arm or Repeat element, enabling LSP hover and
944
+ per-region RFC deep-linking (§5). Available through the source AST
945
+ only (§5.4): the inline struct is transparent in the flat
946
+ normalized model.
947
+ fields:
948
+ type: array
949
+ items:
950
+ $ref: '#/$defs/Container'
951
+
952
+ NamedStruct:
953
+ type: object
954
+ required: [id, fields]
955
+ additionalProperties: false
956
+ description: |-
957
+ Struct type used exclusively as defs map values. Extends Struct with
958
+ the recursive property, which is meaningless (and therefore forbidden)
959
+ on anonymous inline structs used in Repeat.element, Switch.cases, or
960
+ Encrypted.plaintext.
961
+ properties:
962
+ id:
963
+ type: string
964
+ minLength: 1
965
+ doc:
966
+ type: string
967
+ description: Description for LSP hover and tooling documentation.
968
+ meta:
969
+ $ref: '#/$defs/FieldMeta'
970
+ description: |-
971
+ RFC annotation { rfc?, section? } for the def as a whole (§5.4, §6).
972
+ Documentation-grade provenance available through the source AST
973
+ only: a ref expansion is transparent and emits no container field,
974
+ so this meta does not appear in the normalized/layout output.
975
+ recursive:
976
+ type: boolean
977
+ description: |-
978
+ When true, this struct may contain ref containers pointing to
979
+ itself (direct) or to other recursive: true structs (indirect).
980
+ The decoder is responsible for depth limiting. Disables the
981
+ circular-reference validation check for this struct.
982
+ fields:
983
+ type: array
984
+ items:
985
+ $ref: '#/$defs/Container'
986
+
987
+ Group:
988
+ type: object
989
+ required: [kind, id, name, children]
990
+ additionalProperties: false
991
+ description: |-
992
+ Logical grouping of adjacent fields. Groups collapse to a single row
993
+ in the wire diagram and expose sub-field detail on hover.
994
+ properties:
995
+ kind: { const: group }
996
+ id: { type: string, minLength: 1 }
997
+ name: { type: string }
998
+ doc:
999
+ type: string
1000
+ description: Description for LSP hover documentation.
1001
+ meta:
1002
+ $ref: '#/$defs/FieldMeta'
1003
+ category: { $ref: '#/$defs/CategoryToken' }
1004
+ children:
1005
+ type: array
1006
+ items:
1007
+ $ref: '#/$defs/Container'
1008
+
1009
+ RepeatCount:
1010
+ description: |-
1011
+ Repetition specifier: a numeric expression, the string "eos"
1012
+ (repeat until the boundary of the nearest enclosing scope-providing
1013
+ container — a bounded scope, an encrypted.plaintext struct, or the
1014
+ top-level body, §5), or an until-condition object.
1015
+ oneOf:
1016
+ - $ref: '#/$defs/Expr'
1017
+ - type: string
1018
+ const: eos
1019
+ - type: object
1020
+ required: [until]
1021
+ additionalProperties: false
1022
+ properties:
1023
+ until: { $ref: '#/$defs/Expr' }
1024
+
1025
+ Repeat:
1026
+ type: object
1027
+ required: [kind, id, element, count]
1028
+ additionalProperties: false
1029
+ description: |-
1030
+ Repeats a Struct a given number of times. The decoder injects the
1031
+ completed iteration count into env[repeat.id] before normalization — for
1032
+ count: eos repeats (where it is detected at parse time) and for
1033
+ fixed-count repeats (where it trivially equals the count expression),
1034
+ §10.7. A ref whose field is this repeat's id therefore evaluates to that
1035
+ iteration count (§4).
1036
+ properties:
1037
+ kind: { const: repeat }
1038
+ id: { type: string, minLength: 1 }
1039
+ name: { type: string }
1040
+ element: { $ref: '#/$defs/Struct' }
1041
+ count: { $ref: '#/$defs/RepeatCount' }
1042
+ category: { $ref: '#/$defs/CategoryToken' }
1043
+ doc: { type: string }
1044
+
1045
+ Switch:
1046
+ type: object
1047
+ required: [kind, id, on, cases]
1048
+ additionalProperties: false
1049
+ description: |-
1050
+ Selects one Struct arm based on a discriminator expression.
1051
+ Case key formats: exact decimal "6", range "0-127", list "6,17,58",
1052
+ or catch-all "_". Keys are matched in order: exact → list → range → "_".
1053
+ The "_" key must appear inside the cases map (no separate default property).
1054
+ properties:
1055
+ kind: { const: switch }
1056
+ id: { type: string, minLength: 1 }
1057
+ name: { type: string }
1058
+ on: { $ref: '#/$defs/Expr' }
1059
+ cases:
1060
+ type: object
1061
+ description: |-
1062
+ Keys: decimal "6", range "0-127", list "6,17,58", or "_" (catch-all).
1063
+ Evaluation order: exact → list → range → "_".
1064
+ additionalProperties:
1065
+ $ref: '#/$defs/Struct'
1066
+ doc: { type: string }
1067
+
1068
+ Encrypted:
1069
+ type: object
1070
+ required: [kind, id, plaintext]
1071
+ additionalProperties: false
1072
+ description: |-
1073
+ Marks a region as encrypted. In wire view the region appears as an
1074
+ opaque block; in semantic view plaintext fields are shown. Inside
1075
+ plaintext the remaining and enclosingBits expressions are available, but
1076
+ only when wireBits is present: wireBits is the plaintext byte/bit budget,
1077
+ so if it is absent the plaintext budget is undefined and
1078
+ remaining/enclosingBits inside it are validation errors (§5, §11.1).
1079
+ properties:
1080
+ kind: { const: encrypted }
1081
+ id: { type: string, minLength: 1 }
1082
+ name: { type: string }
1083
+ plaintext: { $ref: '#/$defs/Struct' }
1084
+ wireBits: { $ref: '#/$defs/Expr' }
1085
+ contextNote:
1086
+ type: string
1087
+ minLength: 1
1088
+ description: Human-readable note shown in the encrypted-region tooltip.
1089
+ headerProtected:
1090
+ type: array
1091
+ description: |-
1092
+ Field ids that are header-protected by the cipher: either inside this
1093
+ plaintext, or a plaintext-external header field declared earlier in
1094
+ this body (§5). Annotation only. The same-body resolution is a
1095
+ validator-layer check (JSON Schema cannot express it).
1096
+ items: { type: string }
1097
+ category: { $ref: '#/$defs/CategoryToken' }
1098
+ doc: { type: string }
1099
+ meta:
1100
+ $ref: '#/$defs/FieldMeta'
1101
+ description: RFC provenance for the encrypted region (§5.4).
1102
+
1103
+ RefContainer:
1104
+ type: object
1105
+ required: [kind, ref, id]
1106
+ additionalProperties: false
1107
+ description: |-
1108
+ Inlines a named Struct from `defs` (or imported defs). Expanded field
1109
+ ids are prefixed with `{id}.` (e.g. ref id "src" + field "oct0" →
1110
+ "src.oct0"). Inside a repeat, expanded ids become "{ref.id}.{field.id}#N".
1111
+ The ref target must exist in defs or an imported namespace.
1112
+ Non-recursive circular references are a validation error.
1113
+ A ref is a transparent expansion (inherits surrounding scope).
1114
+ properties:
1115
+ kind: { const: ref }
1116
+ ref:
1117
+ type: string
1118
+ minLength: 1
1119
+ description: |-
1120
+ Key into the packet-level `defs` map, or a namespaced import
1121
+ reference (e.g. "addr.ipv4Addr").
1122
+ id:
1123
+ type: string
1124
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
1125
+ name: { type: string }
1126
+
1127
+ AlignContainer:
1128
+ type: object
1129
+ required: [kind, to]
1130
+ additionalProperties: false
1131
+ description: |-
1132
+ Consumes zero or more bytes to align the current parse position to a
1133
+ given bit boundary, measured from the absolute wire/packet origin. `to`
1134
+ must be a positive integer power of 2 and a multiple of 8. If a preceding
1135
+ sub-byte bits field left the cursor mid-byte, align first rounds up to the
1136
+ next whole byte, then advances to the `to` boundary (§5). Inside a bounded
1137
+ scope, padding bytes are charged against the scope byte budget; an align
1138
+ whose padding exceeds the remaining budget is a runtime error (§5). At the
1139
+ top-level body (or any scope), if the computed padding would run past the
1140
+ injected end-of-data the align consumes only the bytes actually available
1141
+ and does not error (it caps at the scope/packet end) — covering SCTP
1142
+ last-chunk optional padding (RFC 4960 §3.2), §5.
1143
+ Alignment padding bytes are excluded from any enclosing checksum coverage
1144
+ unless this container's `id` is explicitly listed in checksumCovers. `to`
1145
+ not a positive power of 2 that is a multiple of 8 is a validation error.
1146
+ properties:
1147
+ kind: { const: align }
1148
+ to:
1149
+ type: integer
1150
+ minimum: 1
1151
+ description: |-
1152
+ Alignment target in bits. Must be a positive integer power of 2 and
1153
+ a multiple of 8 (e.g. 8, 16, 32, 64). Validator MUST reject values
1154
+ that are not a power of 2 or not a multiple of 8.
1155
+ fill:
1156
+ type: integer
1157
+ minimum: 0
1158
+ maximum: 255
1159
+ description: |-
1160
+ Byte value used to fill padding bytes during serialization. When
1161
+ present, decoders also validate that incoming padding bytes equal
1162
+ this value (mismatch is a validation warning, §11.3). Range 0–255;
1163
+ values outside this range are a validation error. When absent,
1164
+ the fill value is encoder/decoder-defined. Example use: SCTP and
1165
+ Diameter mandate zero-fill padding (fill: 0).
1166
+ id:
1167
+ type: string
1168
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
1169
+ description: Optional identifier if the padding bytes need to be referenced.
1170
+ doc: { type: string }
1171
+
1172
+ BoundedContainer:
1173
+ type: object
1174
+ required: [kind, id, bytes, fields]
1175
+ additionalProperties: false
1176
+ description: |-
1177
+ Constrains parsing of its contents to a declared byte count. Creates a
1178
+ sub-stream cursor so that count:eos repeats terminate at the scope boundary.
1179
+ Inside a bounded scope, n: { kind: remaining } on a bytes field consumes
1180
+ all remaining bytes in this scope. Bounded scopes may be nested. A
1181
+ count: eos repeat more generally terminates at the boundary of its nearest
1182
+ enclosing scope-providing container — a bounded scope, an
1183
+ encrypted.plaintext struct (its wireBits budget), or the top-level body —
1184
+ not only a bounded scope (same scope-provider list as remaining/
1185
+ enclosingBits, §4, §5).
1186
+ properties:
1187
+ kind: { const: bounded }
1188
+ id:
1189
+ type: string
1190
+ pattern: '^[a-zA-Z][a-zA-Z0-9_-]*$'
1191
+ description: Scope identifier.
1192
+ bytes:
1193
+ $ref: '#/$defs/Expr'
1194
+ description: Expression giving the byte count of this scope.
1195
+ fields:
1196
+ type: array
1197
+ items:
1198
+ $ref: '#/$defs/Container'
1199
+ description: Ordered list of containers parsed within the scope.
1200
+ name: { type: string }
1201
+ doc: { type: string }
1202
+ meta:
1203
+ $ref: '#/$defs/FieldMeta'
1204
+ description: RFC provenance for the bounded region (§5.4).
1205
+
1206
+ # ────────────────────────────────────────────────────────────────────
1207
+ # Constraints
1208
+ # ────────────────────────────────────────────────────────────────────
1209
+ Constraint:
1210
+ type: object
1211
+ required: [lhs, rhs]
1212
+ additionalProperties: false
1213
+ description: |-
1214
+ Equality constraint between two expressions. Evaluated independently
1215
+ of body parsing; may reference any field regardless of document position.
1216
+ Back-propagation is fixpoint-iterated: the solver reruns until no new
1217
+ fields are resolved in a pass. Only single-unknown linear expressions
1218
+ can be auto-solved; multi-unknown / non-linear are validation-only.
1219
+ properties:
1220
+ lhs: { $ref: '#/$defs/Expr' }
1221
+ rhs: { $ref: '#/$defs/Expr' }
1222
+ doc: { type: string }
1223
+ level: { $ref: '#/$defs/NormativeLevel' }