refactor(errors): adopt reportable error terminology

This commit is contained in:
Onur Özkan committed 2026-08-23 00:49:25 +03:00
1 parent 21e9497915
commit 9fec2fa095
92 files changed
+270 -269

No files matched your search

+5 -5
View File
@@ -80,16 +80,16 @@ The build watches every fragment and generates one `message::kaptan` module;
fragments are never separately generated Rust modules. `kaptan-log` itself has
no MAVLink, platform, time, allocation, or filesystem dependency; its sole
configuration coupling is compile-time enum metadata for `LevelFilter`.
`kaptan-err-propagate` independently owns explicitly assigned typed-error identity,
function-boundary propagation, and a bounded nonblocking ingress; it has
`kaptan-err-reportable` independently owns explicitly assigned reportable-error
identity and a bounded nonblocking ingress; it has
no logging, MAVLink, platform, filesystem, or clock dependency. Event creation
is independent from sink filtering, allowing a future blackbox and MAVLink to
select different policies. The platform drains typed errors before its bounded
select different policies. The platform drains reportable errors before its bounded
critical and best-effort log queues and removes a pending record only after TX
admission. `KAPTAN_LOG` carries one conventional level plus one bounded text
field; `KAPTAN_ERROR` carries an explicitly assigned 16-bit ID and the bounded
`file:line` of the reporting boundary. Its
message kind already identifies a typed firmware error. Heartbeat and safety
`file:line` of the reporting point. Its
message kind already identifies a reportable firmware error. Heartbeat and safety
telemetry remain separate from diagnostics.
See [Configuration](configuration.md) for the deployment matrix and GCS transaction
+19 -19
View File
@@ -1,9 +1,9 @@
# Errors
Public Kaptan error enums derive the pure `KaptanError` implementation:
Public reportable Kaptan error enums derive `KaptanError`:
```rust
#[derive(Debug, kaptan_err_propagate::KaptanError)]
#[derive(Debug, kaptan_err_reportable::KaptanError)]
enum SensorError {
#[kaptan_error(id = 12345)]
TransferFault,
@@ -11,14 +11,14 @@ enum SensorError {
UnexpectedIdentity(u8),
}
#[kaptan_err_propagate::propagate]
#[kaptan_err_reportable::propagate]
fn service_sensor() -> Result<(), SensorError> {
read_sensor()?;
Ok(())
}
```
The derive implements `core::error::Error`, `Display`, and `ErrorReport`. It
The derive implements `core::error::Error`, `Display`, and `ReportableError`. It
requires a nonzero explicit ID on every variant and retains no type, variant,
or module string. `Display` renders the decimal ID. Renaming, moving, or
reordering a Rust variant therefore does not change its receiver contract.
@@ -26,11 +26,11 @@ Missing and same-enum duplicate IDs are rejected by the derive. Reusing an ID
across error enums generates the same reserved linker symbol and fails the
final firmware build.
`#[kaptan_err_propagate::propagate]` observes the ordinary `Result` produced
by one terminal diagnostic boundary. If an `Err` leaves that function, the attribute
makes one nonblocking admission attempt and returns the exact same `Err` to the
`#[kaptan_err_reportable::propagate]` turns an annotated function into a
reporting point. If a reportable `Err` leaves that function, the attribute makes
one nonblocking admission attempt and returns the exact same `Err` to the
caller. The record contains the final converted error ID and the compile-time
`file:line` of that annotated boundary. This is where the `Err` enters
`file:line` of that reporting point. This is where the `Err` enters
diagnostics, not necessarily the line where a deeper callee originally
constructed it. `?`, explicit returns, result aliases, and `From` conversion
retain their normal Rust behavior. An error handled inside the function is
@@ -46,35 +46,35 @@ renaming, moving, or reordering an existing variant keeps its assigned ID.
The example numbers above are illustrative and must be replaced with
unallocated catalog values when used in production code.
Only the terminal boundary is annotated. If nested functions are both
annotated, each boundary makes its own report attempt; the ingress does not
Only the intended reporting point is annotated. If nested functions are both
annotated, each function makes its own report attempt; the ingress does not
mark or mutate error values to deduplicate them. Expected validation,
backpressure, retry, and untrusted-input results remain unannotated. In
particular, transient SPI/I²C `Busy` and unavailable range measurements stay
inside their service retry/idle paths. In contrast, every logging
macro—including `kaptan_log::error!`—produces only
`KAPTAN_LOG`. Error propagation is not a replacement for safety state,
`KAPTAN_LOG`. Error reporting is not a replacement for safety state,
actuator inhibit, or typed configuration results.
`kaptan-err-propagate` owns error identity and its independent one-slot
ingress. A pending record contains only the compact ID and a static reference
to the propagation boundary's `file:line`. The MAVLink adapter copies that
`kaptan-err-reportable` owns reportable-error identity and its independent
one-slot ingress. A pending record contains only the compact ID and a static
reference to the reporting point's `file:line`. The MAVLink adapter copies that
location into its fixed field when constructing `KAPTAN_ERROR`. Producers never
encode or transmit MAVLink themselves. Admission is bounded and lossy if a
different typed error is already pending.
different reportable error is already pending.
## What the receiver sees
- Configuration writes receive authoritative structured failures through
`KAPTAN_CONFIG_RESULT`: operation, lifecycle state, field IDs, validation
rule, and protocol error code. A terminal persistence failure also reports
the storage-only `CommitTransactionError::Store` boundary once as
rule, and protocol error code. A reportable persistence failure also emits
the storage-only `CommitTransactionError::Store` ID once as
`KAPTAN_ERROR`; replaying the cached command result does not repeat the error
or the flash operation.
- Terminal typed `ErrorReport` faults reach the F722 MAVLink worker as a
- Reported `ReportableError` values reach the F722 MAVLink worker as a
`KAPTAN_ERROR`, subject to bounded transport admission. The payload is
`{ error_id, raised_at[96] }`. `raised_at` is a zero-padded UTF-8
`file:line` prefix for the annotated propagation boundary.
`file:line` prefix for the reporting point.
The message kind itself identifies an error; no level is duplicated in the
payload. Dynamic human-readable context belongs in `KAPTAN_LOG`, while
structured protocol failures remain in their owning response message.
+9 -9
View File
@@ -11,18 +11,18 @@ kaptan_log::trace!("prediction step complete");
```
All five macros emit `KAPTAN_LOG`; their level never selects a different wire
message. When a terminal typed firmware error escapes a reviewed
`#[kaptan_err_propagate::propagate]` function, it makes one bounded admission attempt
message. When a reportable firmware error escapes a reviewed
`#[kaptan_err_reportable::propagate]` function, it makes one bounded admission attempt
to the separate `KAPTAN_ERROR` ingress.
`kaptan-log` formats each event once into a fixed bounded buffer and never
sends MAVLink, allocates, blocks, changes flight state, or touches DMA. The
composition fans the event into each enabled sink; the sole MAVLink worker
drains its bounded sink queue. Ordinary log text uses one 160-byte bounded
record. Typed-error records contain the explicit ID and a static reference to
the annotated propagation boundary until the MAVLink adapter copies its
record. Reportable-error records contain the explicit ID and a static reference
to the reporting point until the MAVLink adapter copies its
`file:line` into the 96-byte `raised_at` field.
Logs and typed errors use independent fixed atomic
Logs and reportable errors use independent fixed atomic
ingresses; interrupt and worker producers make one nonblocking admission
attempt, and only the MAVLink worker encodes or transmits a retained event.
Panic and hard-fault paths still do not attempt live telemetry.
@@ -30,7 +30,7 @@ Panic and hard-fault paths still do not attempt live telemetry.
## Receiver contract
`definitions/kaptan/log.xml` and `definitions/kaptan/error.xml` separate
ordinary logs and typed errors:
ordinary logs and reportable errors:
```text
KAPTAN_LOG { level, flags, message_length, message[160] }
@@ -46,12 +46,12 @@ or the complete field when no zero is present.
`KAPTAN_LOG.level` accepts only Error (3), Warning (4), Info (6), and Debug
(7); Trace is encoded as Debug (7) plus the `TRACE` flag. Other MAVLink
severity numbers are not Kaptan log levels.
The `KAPTAN_ERROR` message kind already means a typed firmware error, so it has
The `KAPTAN_ERROR` message kind already means a reportable firmware error, so it has
no redundant level or flags field.
`error_id` is the stable nonzero catalog number explicitly assigned to the
Rust error variant. Renaming or reordering a variant does not change it.
`raised_at` identifies the annotated boundary where the `Err` entered
`raised_at` identifies the reporting point where the `Err` entered
diagnostics. Error details requiring
machine action stay in their owning protocol, notably `KAPTAN_CONFIG_RESULT`.
Delivery is bounded and lossy under link pressure; heartbeat and safety
@@ -65,7 +65,7 @@ event.
The single restart-only `mavlink.logging.level_filter` field uses the familiar
Off, Error, Warn, Info, Debug, and Trace choices. `Info`, for example, accepts
Error, Warn, and Info log events. `Off` suppresses `KAPTAN_LOG` on MAVLink
without suppressing typed `KAPTAN_ERROR` reports or events sent to another
without suppressing reportable `KAPTAN_ERROR` events or logs sent to another
sink. There is no separate enable flag and no MAVLink-specific set of extra
runtime log levels. F722 uses the validated filter recovered at boot, falling
back to its board factory when the journal is empty or invalid.
+2 -2
View File
@@ -50,8 +50,8 @@ log history.
The custom Kaptan definitions are aggregated by `definitions/kaptan.xml` from
`kaptan/config.xml`, `kaptan/log.xml`, and `kaptan/error.xml`.
`KAPTAN_LOG` is an outbound human-readable four-field record. `KAPTAN_ERROR`
is the separate bounded channel for typed firmware errors, carrying a stable
explicit ID plus the `file:line` of its propagation boundary, and needs no
is the separate bounded channel for reportable firmware errors, carrying a
stable explicit ID plus the `file:line` of its reporting point, and needs no
redundant level field. Configuration messages back the current target-described
web configurator and the future signed GCS. See
[Configuration](configuration.md), [Logs](logs.md), and [Errors](errors.md) for
+2 -2
View File
@@ -8,12 +8,12 @@ This page collects stable limits and points to the detailed contracts.
| F722 persistence | One bounded fixed scalar snapshot inside each slot of a power-loss-safe two-slot flash journal. |
| Config transaction | One owner-bound RAM transaction with typed scalar writes; commit is restart-required. |
| Config discovery | Correlated `KAPTAN_CONFIG_INFO_REQUEST` / `KAPTAN_CONFIG_INFO`, then exact-index descriptor/enum-option and field-value requests. |
| Diagnostics | `KAPTAN_LOG` (51020) for macro-produced level/text; `KAPTAN_ERROR` (51021) for a bounded typed `{ error_id, raised_at[96] }` firmware error. |
| Diagnostics | `KAPTAN_LOG` (51020) for macro-produced level/text; `KAPTAN_ERROR` (51021) for a bounded reportable `{ error_id, raised_at[96] }` firmware error. |
| F722 configuration | Target-described fields and board factory defaults; the current local transport is a directly wired unsigned UART with motor outputs physically inhibited. |
Read [Configuration](configuration.md) for the field/consumer matrix and GCS
transaction sequence, [Logs](logs.md) for receiver decoding and filtering, and
[Errors](errors.md) for error propagation and panic scope.
[Errors](errors.md) for reportable errors and panic scope.
## Verification