fix(typedef): resolve spec inconsistencies from sanity check

- Remove TEnum 'always LE' exception (no POC basis, contradicts ADR-097).
  TEnum now follows schema endianness like all other fixed-size types.
- Document TEnum design change: u32 index is a deliberate deviation from
  TypeBox's string enum for binary efficiency.
- Document TBytes as alknet-typedef addition (not in TypeBox typedef.ts).
- Fix kind count inconsistency: all docs now consistently say 17 kinds.
- Fix TTimestamp validation contradiction: clarify data-access layer vs
  jsonschema validator responsibility.
- Add TEnum read/write coverage to data-access.md.
- Add TEnum endianness cross-reference to layout-engine.md.
- Clarify TBytes binary-vs-JSON representation in validation.md.
This commit is contained in:
deepseek-v4-pro committed 2026-07-21 07:44:58 +00:00
1 parent a941d86c3a
commit c6ab00d141
6 files changed
+58 -11

No files matched your search

+1 -1
View File
@@ -18,7 +18,7 @@ format definition; the engine is generic.
| [schema-layer.md](schema-layer.md) | draft | The 17 `TypeDef:*` kinds, jsonschema custom keyword integration, TypeBox interop, schema annotations | | [schema-layer.md](schema-layer.md) | draft | The 17 `TypeDef:*` kinds, jsonschema custom keyword integration, TypeBox interop, schema annotations |
| [layout-engine.md](layout-engine.md) | draft | Offset computation, the two layout modes (packed sequential vs aligned static), alignment, endianness, variable-length handling | | [layout-engine.md](layout-engine.md) | draft | Offset computation, the two layout modes (packed sequential vs aligned static), alignment, endianness, variable-length handling |
| [data-access.md](data-access.md) | draft | Read/write functions, TUnion dispatch, field paths, zero-copy access, length-prefix reading | | [data-access.md](data-access.md) | draft | Read/write functions, TUnion dispatch, field paths, zero-copy access, length-prefix reading |
| [validation.md](validation.md) | draft | Custom keyword validators for all 16 `TypeDef:*` kinds, `TypedefError`, load-time vs access-time validation, `TypedefEngine` | | [validation.md](validation.md) | draft | Custom keyword validators for all 17 `TypeDef:*` kinds, `TypedefError`, load-time vs access-time validation, `TypedefEngine` |
## Applicable ADRs ## Applicable ADRs
@@ -21,7 +21,7 @@ typed access at the computed positions.
### Fixed-size types ### Fixed-size types
Fixed-size types (`TFloat32`, `TInt32`, `TUint8`, etc.) are accessed via Fixed-size types (`TFloat32`, `TInt32`, `TUint8`, `TEnum`, etc.) are accessed via
zero-copy pointer casts: zero-copy pointer casts:
```rust ```rust
@@ -48,6 +48,28 @@ The engine applies endianness at access time based on the schema's
`"endian"` annotation (ADR-097). The offset computation is `"endian"` annotation (ADR-097). The offset computation is
endian-agnostic. endian-agnostic.
### TEnum access
`TEnum` is a fixed-size type (4 bytes, `u32` index). Read/write follows
the same pattern as other fixed-size types — the engine reads/writes a
`u32` at the field's computed offset, applying the schema's endianness:
```rust
fn read_enum(buffer: &[u8], offset: usize, endian: Endian) -> u32 {
let bytes: [u8; 4] = buffer[offset..offset+4].try_into().unwrap();
match endian {
Endian::Little => u32::from_le_bytes(bytes),
Endian::Big => u32::from_be_bytes(bytes),
}
}
```
The consumer maps the `u32` index back to the enum's string values using
the schema's `"enum"` array (index 0 → first value, index 1 → second
value, etc.). The engine does not perform this mapping — it operates on
the raw `u32` index. The jsonschema validator checks that the index
corresponds to a valid enum value at the JSON level.
### Variable-length types (inline length-prefixing) ### Variable-length types (inline length-prefixing)
For variable-length types with inline length-prefixing (the default): For variable-length types with inline length-prefixing (the default):
@@ -207,7 +207,8 @@ Endianness is per-schema (ADR-097). The offset computation is
endian-agnostic — it computes byte positions, not byte values. The endian-agnostic — it computes byte positions, not byte values. The
read/write functions apply endianness when converting between bytes and read/write functions apply endianness when converting between bytes and
typed values. The engine reads the `"endian"` annotation from the schema typed values. The engine reads the `"endian"` annotation from the schema
and byte-swaps accordingly. and byte-swaps accordingly. All fixed-size types — including `TEnum`
(u32 index) — follow the schema's endianness.
## Mode Selection ## Mode Selection
+1 -1
View File
@@ -163,7 +163,7 @@ These boundaries are decided in [ADR-095](../../decisions/095-alknet-typedef-pur
dispatch, field paths, zero-copy access for fixed-size types, dispatch, field paths, zero-copy access for fixed-size types,
length-prefix reading for variable-length types. length-prefix reading for variable-length types.
- **[validation.md](validation.md)** — custom keyword validators for all - **[validation.md](validation.md)** — custom keyword validators for all
16 `TypeDef:*` kinds, `TypedefError`, load-time vs access-time 17 `TypeDef:*` kinds, `TypedefError`, load-time vs access-time
validation, `TypedefEngine` as the compiled form of a schema. validation, `TypedefEngine` as the compiled form of a schema.
## Design Decisions ## Design Decisions
@@ -5,7 +5,7 @@ last_updated: 2026-07-20
# alknet-typedef — Schema Layer # alknet-typedef — Schema Layer
The schema layer: the 16 `TypeDef:*` custom type kinds, their mapping to The schema layer: the 17 `TypeDef:*` custom type kinds, their mapping to
Rust types and byte sizes, the `jsonschema` custom keyword integration, Rust types and byte sizes, the `jsonschema` custom keyword integration,
TypeBox interop, and the concrete JSON shapes for schema-level annotations. TypeBox interop, and the concrete JSON shapes for schema-level annotations.
@@ -53,8 +53,17 @@ second is index 1, etc. The enum's values are declared via the standard
JSON Schema `"enum"` keyword (e.g., `"enum": ["read", "write", "execute"]`). JSON Schema `"enum"` keyword (e.g., `"enum": ["read", "write", "execute"]`).
The `TypeDef:Enum` custom keyword signals that the type is an enum for The `TypeDef:Enum` custom keyword signals that the type is an enum for
layout purposes; the built-in `enum` keyword provides the value list. layout purposes; the built-in `enum` keyword provides the value list.
The `u32` index is always little-endian (enum indices are not protocol
data — they are internal to the schema). See [ADR-097](../../decisions/097-schema-annotations.md). **Design note:** TypeBox's `TEnum` is a string enum (variable-length). The
typedef engine uses a `u32` index instead — a deliberate deviation from
TypeBox fidelity in favor of binary efficiency. Most enums have a small
number of variants (e.g., the call protocol's 5 event types); a `u32`
index is compact, fixed-size, and sufficient for any realistic enum. The
JSON representation (for validation) remains a string; the binary
representation is the `u32` index.
The `u32` index follows the schema's endianness annotation (ADR-097), like
all other fixed-size types. In little-endian mode the index is
`u32::from_le_bytes`; in big-endian mode it is `u32::from_be_bytes`.
### Variable-length types ### Variable-length types
@@ -115,6 +124,14 @@ consistent byte order for both field values and length prefixes.
**`TBytes`:** Raw bytes — no UTF-8 constraint. The payload is `&[u8]`. **`TBytes`:** Raw bytes — no UTF-8 constraint. The payload is `&[u8]`.
Otherwise identical to `TString` in layout (same three strategies). Otherwise identical to `TString` in layout (same three strategies).
**Design note:** `TypeDef:Bytes` is an alknet-typedef addition — it does
not exist in TypeBox's `typedef.ts` (which defines 16 kinds). It is
included because raw byte arrays are a common binary protocol primitive
(SFTP data payloads, channels payloads, tensor data) and are semantically
distinct from UTF-8 strings. In the binary representation, TBytes is raw
bytes with no encoding (not base64, not hex). In the JSON representation
(for validation), TBytes is a string (JSON has no native byte type).
**`TRecord`:** A string-keyed map. Binary layout is a count-prefixed **`TRecord`:** A string-keyed map. Binary layout is a count-prefixed
sequence of `(key, value)` pairs: `[count: u32][key_len: u32][key_bytes] sequence of `(key, value)` pairs: `[count: u32][key_len: u32][key_bytes]
[value_len: u32][value_bytes]...`. The count is the number of entries. [value_len: u32][value_bytes]...`. The count is the number of entries.
@@ -126,9 +143,11 @@ entire record is reserved at `maxLength` bytes (zero-padded).
**`TTimestamp`:** An RFC 3339 timestamp string (the internet profile of **`TTimestamp`:** An RFC 3339 timestamp string (the internet profile of
ISO 8601). Stored as a length-prefixed UTF-8 string (strategy 1) or ISO 8601). Stored as a length-prefixed UTF-8 string (strategy 1) or
fixed-size reservation (strategy 2 with `maxLength`). The engine does not fixed-size reservation (strategy 2 with `maxLength`). The data-access
parse or validate the timestamp format beyond UTF-8 — the jsonschema layer treats timestamps as opaque length-prefixed strings — it does not
validator checks RFC 3339 conformance at the JSON level. parse or validate the timestamp format. The jsonschema custom keyword
validator checks RFC 3339 conformance at the JSON level (see
[validation.md](validation.md)).
`TArray` is variable-length when the element type is variable-length or `TArray` is variable-length when the element type is variable-length or
when the count is not known at schema time. For fixed-size element arrays when the count is not known at schema time. For fixed-size element arrays
@@ -104,8 +104,13 @@ type constraints; `jsonschema` handles all structural validation.
must not exceed it. must not exceed it.
**`TypeDef:Bytes`:** **`TypeDef:Bytes`:**
- Value must be a string (JSON represents binary data as a string). - Value must be a string (JSON represents binary data as a string — JSON
has no native byte type).
- If `maxLength` is specified, the byte length must not exceed it. - If `maxLength` is specified, the byte length must not exceed it.
- **Binary representation:** In the binary layout, `TBytes` is raw bytes
with no encoding (not base64, not hex). The JSON representation (for
validation) uses a string; the binary representation (for data access)
uses `&[u8]` directly.
**`TypeDef:Enum`:** **`TypeDef:Enum`:**
- The `TypeDef:Enum` custom keyword signals that the type is an enum for - The `TypeDef:Enum` custom keyword signals that the type is an enum for