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 |
| [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 |
| [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
@@ -21,7 +21,7 @@ typed access at the computed positions.
### 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:
```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-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)
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
read/write functions apply endianness when converting between bytes and
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
+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,
length-prefix reading for variable-length types.
- **[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.
## Design Decisions
@@ -5,7 +5,7 @@ last_updated: 2026-07-20
# 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,
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"]`).
The `TypeDef:Enum` custom keyword signals that the type is an enum for
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
@@ -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]`.
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
sequence of `(key, value)` pairs: `[count: u32][key_len: u32][key_bytes]
[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
ISO 8601). Stored as a length-prefixed UTF-8 string (strategy 1) or
fixed-size reservation (strategy 2 with `maxLength`). The engine does not
parse or validate the timestamp format beyond UTF-8 — the jsonschema
validator checks RFC 3339 conformance at the JSON level.
fixed-size reservation (strategy 2 with `maxLength`). The data-access
layer treats timestamps as opaque length-prefixed strings — it does not
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
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.
**`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.
- **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`:**
- The `TypeDef:Enum` custom keyword signals that the type is an enum for