# Telemetry Schema
As of v4.0.0, user telemetry schema is runtime state. `DataEndpoint` and
`DataType` are stable numeric IDs on the wire, but the library no longer
generates application-specific Rust enum variants or binding constants at
compile time.
The default registry contains only built-in internal entries:
- telemetry error endpoint/type
- reliable-control packet types
- discovery endpoint/types
- time-sync endpoint/types when the `timesync` feature is enabled
Applications add user endpoints and data types at runtime through APIs, JSON
seeding, or discovery schema sync.
## Runtime IDs and Names
`DataEndpoint(pub u32)` and `DataType(pub u32)` are transparent runtime IDs.
Use names for readability and only use raw IDs where you are assigning a wire
ID intentionally.
```rust
let radio = DataEndpoint::named("RADIO");
let gps = DataType::named("GPS_DATA");
let maybe_radio = DataEndpoint::try_named("RADIO");
let maybe_gps = DataType::try_named("GPS_DATA");
```
Definitions carry:
- numeric ID
- string name
- human-readable description
- endpoint link-local flag
- data type shape, allowed endpoints, reliability mode, queue priority, and E2E cryptography policy
Lookup/export APIs include:
- `endpoint_definition(...)`
- `endpoint_definition_by_name(...)`
- `data_type_definition(...)`
- `data_type_definition_by_name(...)`
- `known_endpoints()`
- `known_data_types()`
- `export_schema()`
## Registering Schema
Rust:
```rust
let radio = register_endpoint_id_with_description(
DataEndpoint(100),
"RADIO",
"Downlink radio",
false,
)?;
register_data_type_id_with_description(
DataType(100),
"GPS_DATA",
"Latitude, longitude, altitude",
MessageElement::Static(3, MessageDataType::Float32, MessageClass::Data),
&[radio],
ReliableMode::Ordered,
80,
)?;
```
Use `register_data_type_id_with_description_and_e2e_encryption(...)` when a type should prefer or
require E2E encrypted payloads.
Direct registration rejects conflicts:
- same endpoint ID/name with different endpoint metadata
- same data type ID/name with a different shape, endpoint set, reliability mode, priority, or E2E
policy
- data types referencing endpoints that do not exist
Endpoint handler registration also creates missing endpoints in `std` builds:
```rust
- `description` is preferred.
- Legacy `doc` is still accepted as an alias.
- Legacy `broadcast_mode = "Never"` is accepted and maps to link-local behavior.
- IPC JSON loaded through the IPC seed path is applied as link-local overlay data.
## Network Schema Sync
Discovery includes schema advertisements. When nodes connect, they can exchange
the current endpoint/type list and merge compatible definitions.
Merge behavior:
- new endpoint/type definitions are added
- equivalent definitions are kept
- ID/name conflicts are resolved deterministically so nodes converge on the same
winner
- data types with missing endpoint dependencies are skipped until those
endpoints are known
Direct local registration remains stricter than network merge. If local code
tries to register an existing data type with a different shape, registration
returns `BadArg`.
## Memory Budgeting
Runtime schema memory counts against the shared router/relay `MAX_QUEUE_BUDGET`.
That same budget also covers RX/TX queues, reliable replay/out-of-order state,
recent packet ID caches, and discovery topology.
If a received schema snapshot would exceed the budget, the merge is rejected and
the current registry is left unchanged.
## Payload Layouts
Schema shape still controls packet validation:
- **Static + numeric/bool**: payload size must equal `count * element_width`.
- **Dynamic + numeric/bool**: payload size must be a multiple of element width.
- **String**: dynamic UTF-8 bytes; trailing NULs are ignored for validation.
- **Binary**: raw bytes.
- **NoData**: zero-length payload.
For static `String` or `Binary` payloads, the configured limits are:
- `STATIC_STRING_LENGTH`
- `STATIC_HEX_LENGTH`
## Compatibility Checklist
For v4 deployments:
- Prefer named runtime lookup in application code: `DataEndpoint::named(...)` and
`DataType::named(...)`.
- Seed required endpoints/types at router startup if they must always exist.
- Let discovery sync optional or peer-defined schema over time.
- Treat data type shape changes as incompatible unless you intentionally create
a new type ID/name.
- Budget for schema memory if you expect many dynamic endpoints/types.