# Architecture Kaptan separates immutable board configuration from platform-owned runtime resources and portable flight logic. ```text board declaration │ ▼ F722 platform / RTIC application ──► data channel ──► MAVLink telemetry │ ├── physical sensor drivers └── startup motor-pin inhibition Portable flight libraries (not connected to physical actuators) FlightEndpoint ──► Navigation / control / phases / safety │ └── caller-owned synchronous output sink ``` Each F722 board combines `F722UserConfig` with an immutable hardware manifest. The manifest selects the IMU route, driver settings, mount, serial inventory, status LED, optional I²C sensor, motor pins and service frequency. User settings select UART roles, baud and MAVLink settings. Motor pins are inhibited at startup. `F722ImmutableConfig` retains the IMU route type through initialization and interrupt acknowledgement. The sealed `Mpu6000Spi1` and `Icm42688Spi3` routes select IMU wiring and backend independently of serial inventory and LED wiring. Each board declares one `PortCatalog::DESCRIPTORS` array. Both `Ports` and `SerialInventory::new(&Catalog::DESCRIPTORS)` use it for stable UART/field identities, supported roles, baud allowlists and resource claims. Validation produces a boot-only `PortPlan`. The same const `N` sizes I/O and protocol storage: five UARTs on each current board. Absent UARTs have no slots. A declared UART set to Disabled retains its slot but initializes no peripheral or pins. USB is fixed normal MAVLink outside that inventory, separate from ROM DFU. Each MAVLink `Link` has its own scheduler, encoder and receive framing, with a separate transport queue. A shared collector snapshots sensor mailboxes for all links. See [MAVLink](mavlink.md) for scheduling and transport behavior. `kaptan-flight-runtime::FlightEndpoint` runs Quad-X control and `kaptan-navigation::Navigation` without allocation. Callers supply observations, independently captured receipt/processing time, clock ticks and a synchronous output sink. Transport and wire encoding stay outside the core. The board images do not yet construct a flight endpoint. See [Safety boundary](safety-boundary.md#shared-runtime-commit-contract) for epochs, request sequencing and the output commit contract. `FlightEndpoint::supervise` checks actual time, cached health and phase/stream deadlines without advancing navigation, integrating control or consuming a control release. It can inhibit and publish outcomes, but cannot renew enabled output. Callers must service the endpoint with actual time even when input stops. The core owns control release and deadline decisions. Within `FlightEndpoint`, fusion, current prediction and initialization completion run only when the 100-Hz control service is due. Early `tick` calls supervise cached evidence without advancing navigation. Ingress admission and its diagnostics remain immediate, but receiving or queuing fresh observations alone does not renew capabilities. The actual control gap is checked before a due navigation update can refresh evidence. `Navigation` initializes from a stationary window of IMU, fixed-reference local position/velocity, magnetic, pressure and range observations. It derives attitude and a fixed launch origin from sensors, with explicit calibration/reference identities. Its shared 16-state error covariance covers position, velocity, attitude error, gyro bias, accelerometer bias and barometric datum. Bounded delayed fusion and current prediction preserve observation timing and capability evidence. The navigation `sensor-snapshots` feature enables driver snapshot conversion. The same flight estimator is available on host and embedded targets. Navigation owns the 25-m/s² free-flight acceleration bound checked by complete-profile validation. See [Configuration](configuration.md#flight-configuration) for required installation data and the supported vehicle model. Configuration and diagnostics use separate paths: ```text FILE_CONTROL / FILE_DATA │ ▼ kaptan-file-mavlink ──► virtual FileProvider │ KCFG importer/exporter │ ConfigManager ──► private store kaptan-log / kaptan-err-reportable │ ▼ kaptan-diagnostics-mavlink ──► per-link encoder / bounded TX ``` The Kaptan-native file dialect owns bounded transfers and retries across links. Its provider maps saved, active and factory-reset endpoints to streaming KCFG v3 and the generic configuration lifecycle. `ConfigManager` owns boot-active values, known committed values or unknown durable state, and the factory candidate. F722 supplies its UART-disabled setup fallback through `recover_with`. Readable invalid settings remain inspectable for USB repair. Saving or factory reset never changes active consumers until reboot. Target-owned stores use private persistence formats. F722 alternates compact `KCSP` snapshots between two erase sectors, retaining only the old and replacement records across the commit boundary. That format is not exposed as KCFG. Motor allocation/mixer topology remains compiled vehicle capability data. ## I/O ownership Sensor handoff uses owned `LatestMailbox` storage split into exactly one non-cloneable producer and one non-cloneable consumer. Publishing replaces an unread value, and taking removes it at most once. Each operation copies or takes an `Option` inside the platform critical section. No callback, allocation, retry or wait occurs inside that section. Storage stays borrowed while endpoints are in use, and moving, dropping or forgetting an endpoint holds no lock. The backend must exclude every participating context, using Cortex-M single-core exclusion on F722 and the `critical-section/std` backend for host threads. UART TX and RX are interrupt-driven, without UART DMA. Each I/O owner retains the peripheral, TX queue and a 512-byte RX buffer with a typed `Timestamp` per byte captured at IRQ receipt. The worker takes at most 16 bytes per UART per turn under a short lock. Protocol parsing, scheduling and persistence run outside UART locks. Overflow or a hardware RX fault discards the damaged backlog and resets the decoder before later bytes. These bounds do not establish a measured latency guarantee. `kaptan-tx::TransmitQueue` owns bounded admission and one logically active frame. Pending admission cannot replace that active frame. The queue itself is movable and does not promise DMA address stability. UART byte writes and USB endpoint writes borrow or copy its bytes synchronously. MAVLink owns encoding, while platform I/O owners handle transmission. USB uses the repository-patched Synopsys driver. Runtime register waits allow higher-priority interrupts and stop after 5 ms or 1,080,000 polls per wait. These are fault limits, not measured execution times. A fault holds USB in peripheral reset until restart and discards its queued data. Brief critical sections protect USB ownership and endpoint buffers. Boot initialization still runs under RTIC's startup interrupt mask. SPI1 and SPI3 DMA each use a once-claimed static pair of 32-byte TX/RX buffers. `start_transfer` copies in, so hardware retains no caller slice. Completion copies out only after checking stream disable, SPI quiescence, transfer counts and faults. Failure to establish shutdown or drain RX quarantines the storage and prevents reuse. Moving, dropping or forgetting the owner never releases that claim. The F722 implementation relies on DMA-accessible SRAM, disabled D-cache and device barriers. Physical SPI shutdown, timing and fault behavior still require hardware validation. ## Monotonic time TIM2 is the canonical F722 clock. The configured 108-MHz timer input and PSC=107 produce a free-running 32-bit counter at 1 MHz with ARR=`u32::MAX`. All readers and the CC1 service IRQ extend one shared `u64` microsecond epoch inside the same critical section. A consumer may remain silent across wraps if other readers or IRQ service keep extending that epoch. Combined observations must be strictly less than 2^32 microseconds apart, about 71.58 minutes, including interrupt blackouts and debugger halts. NMI and fault handlers must not access this clock. CC1 schedules the current 100-Hz service at epoch-aligned 10-ms deadlines. Delayed service skips missed periods in constant work and emits at most one notification per IRQ. Rearming uses two bounded attempts before pending a recovery invocation. Callbacks and notifications run after clock exclusion ends. TIM2 is not reset for each service tick, and no update IRQ or timer DMA is used. Its IRQ is enabled only at the successful end of initialization. Ordinary WFI retains the timer clock. Deep sleep, STOP/Standby, clock-tree changes, counter reset/regression and debugger halts spanning a full wrap are unsupported and require platform reset. Uptime must leave one service period before `u64` microsecond overflow. DWT is used only for the CPU-running SRAM flash-poll timeout at 216 MHz, not sensor timestamps or service deadlines. These contracts do not establish measured oscillator accuracy, IRQ latency, jitter or worst-case timing. ## Diagnostics `kaptan-log` has no MAVLink, platform, time, allocation or filesystem dependency. Its configuration coupling is compile-time enum metadata for `LevelFilter`. `kaptan-err-reportable` independently owns explicit error identities and a bounded nonblocking ingress, without logging, transport or clock dependencies. Event creation is independent from sink filtering. The worker drains reportable errors before logs and offers each diagnostic to all MAVLink links. Heartbeat and sensor publications use separate scheduling. See [Configuration](configuration.md) for KCFG and the file-transfer contract, [Logs](logs.md) for the receiver contract, and [Errors](errors.md) for derived-error and failure-reporting scope. ## Ownership rules - A peripheral owner is local to the platform runtime. - Portable crates use typed units and validated values rather than raw wire or timer representations. - `SafetySupervisor::evaluate_and_commit` checks current evidence at the synchronous enabled-output boundary. No transferable permit escapes it. - Rejected numerical updates do not partially commit computational candidates. Fault latches, inhibition and ingress replay watermarks follow their explicit failure contracts rather than rolling back authority or replay history.