diff --git a/docs/archive/README.md b/docs/archive/README.md index 0ae9a1a..fb320d6 100644 --- a/docs/archive/README.md +++ b/docs/archive/README.md @@ -1,4 +1,4 @@ -# Archive — Akroasis Docs +# Archive - Akroasis Docs Completed or superseded documentation preserved for historical reference. diff --git a/docs/archive/STANDARDS.md b/docs/archive/STANDARDS.md index dca0fc0..5ed5ef8 100644 --- a/docs/archive/STANDARDS.md +++ b/docs/archive/STANDARDS.md @@ -51,5 +51,5 @@ Add `#[allow(clippy::expect_used, clippy::unwrap_used)]` to `#[cfg(test)]` modul - Unit tests live in the same file, inside `#[cfg(test)] mod tests { ... }`. - Integration tests live under `tests/` in the crate root. - Test names describe what is being verified: `fn valid_coordinates_accepted()`. -- Use `assert!`, `assert_eq!`, `assert_ne!` — do not write custom assertion logic unless necessary. +- Use `assert!`, `assert_eq!`, `assert_ne!` - do not write custom assertion logic unless necessary. - Doc-tests (`cargo test --workspace --doc`) must also pass. diff --git a/research/P2-R1-meshtastic-rust-integration.md b/research/P2-R1-meshtastic-rust-integration.md index 4461bea..723370e 100644 --- a/research/P2-R1-meshtastic-rust-integration.md +++ b/research/P2-R1-meshtastic-rust-integration.md @@ -527,7 +527,7 @@ pub(crate) fn decrypt( The `ChannelSettings.psk` field holds raw PSK bytes. Three cases: -**Default channel key** (`psk == [0x01]`): expand to the well-known 16-byte default key. Verify the exact bytes against the pinned firmware tag's `Default.h` constant `DEFAULT_PSK` — do not hardcode from memory. +**Default channel key** (`psk == [0x01]`): expand to the well-known 16-byte default key. Verify the exact bytes against the pinned firmware tag's `Default.h` constant `DEFAULT_PSK` - do not hardcode from memory. ```rust /// Meshtastic default channel key, expanded from PSK byte 0x01. @@ -568,7 +568,7 @@ pub(crate) enum Psk { ### 3.7 Multi-Channel Decryption -For broadcasts on an unknown channel, try each registered channel's PSK. A successful decrypt produces parseable protobuf; an invalid decode means the wrong key. This is a heuristic — AES-CTR has no authentication tag. A valid `Data::decode` is necessary but not sufficient; in practice, false positives are rare. +For broadcasts on an unknown channel, try each registered channel's PSK. A successful decrypt produces parseable protobuf; an invalid decode means the wrong key. This is a heuristic - AES-CTR has no authentication tag. A valid `Data::decode` is necessary but not sufficient; in practice, false positives are rare. ```rust pub(crate) fn decrypt_any_channel( @@ -812,8 +812,8 @@ States: Disconnected Connecting Handshaking Ready Error | `Ready` | `FromRadio` received | `Ready` | process, reset stale timer | | `Ready` | stale timer fires (300 s) | `Error` | log stale | | `Ready` | OS error on read/write | `Error` | log | -| `Error` | cleanup complete | `Disconnected` | — | -| `Disconnected` | backoff elapsed | `Connecting` | — | +| `Error` | cleanup complete | `Disconnected` | - | +| `Disconnected` | backoff elapsed | `Connecting` | - | **Handshake sub-states:** @@ -999,9 +999,9 @@ File header: reserved[2] = 0x0000 Record: - timestamp_us[8] u64 LE — microseconds since Unix epoch + timestamp_us[8] u64 LE - microseconds since Unix epoch direction[1] 0x00 = device→host, 0x01 = host→device - length[2] u16 LE — raw frame bytes (header + payload) + length[2] u16 LE - raw frame bytes (header + payload) data[length] raw bytes as they appeared on the wire ``` diff --git a/research/P2-R2-mesh-topology-routing.md b/research/P2-R2-mesh-topology-routing.md index 88d11f6..1dff2b9 100644 --- a/research/P2-R2-mesh-topology-routing.md +++ b/research/P2-R2-mesh-topology-routing.md @@ -1,6 +1,6 @@ # P2-R2: Mesh Topology and Routing -**Phase:** 2 — Kerykeion +**Phase:** 2 - Kerykeion **Block:** P2-03, P2-04 **Depends on:** P2-R1 (Meshtastic routing mechanics), P2-R27 (DTN patterns) @@ -19,7 +19,7 @@ | Maintenance | Active, widely used | Slow | N/A | | `no_std` path | No (not needed) | No | Possible | -`graphlib` is a thin wrapper with a sparser API. A custom adjacency list is warranted only if the graph structure is specialized (it is not here — this is a sparse, small, weighted digraph). `petgraph` covers the use case and does not require writing traversal algorithms. +`graphlib` is a thin wrapper with a sparser API. A custom adjacency list is warranted only if the graph structure is specialized (it is not here - this is a sparse, small, weighted digraph). `petgraph` covers the use case and does not require writing traversal algorithms. **Concrete types:** @@ -186,7 +186,7 @@ Every packet the server receives carries: - `hop_start`: hops remaining when the packet left the originator - `hop_limit`: hops remaining when the server received the packet -From these: `hops_traversed = hop_start - hop_limit`. If `relay_node` is non-zero, we know the final hop is `relay_node → server_connected_node` with SNR `rx_snr`. Add that directed edge to the graph immediately — no traceroute required. +From these: `hops_traversed = hop_start - hop_limit`. If `relay_node` is non-zero, we know the final hop is `relay_node → server_connected_node` with SNR `rx_snr`. Add that directed edge to the graph immediately - no traceroute required. ### 3.2 Update Frequency @@ -269,9 +269,9 @@ Thresholds: | Score | Classification | |-------|---------------| -| 0–15 | Good — direct or short path with strong SNR | -| 16–35 | Degraded — long path or weak links | -| 36–60 | Poor — marginally usable; prefer store-and-forward | +| 0–15 | Good - direct or short path with strong SNR | +| 16–35 | Degraded - long path or weak links | +| 36–60 | Poor - marginally usable; prefer store-and-forward | | 61+ | Effectively disconnected | ### 4.4 Multi-Path Tracking @@ -434,7 +434,7 @@ The engine checks gateway health every 30 seconds (cheap in-memory scan, no mesh ### 6.5 Bridge Architecture -The gateway is an RF-to-internet bridge. kerykeion does not speak directly to the internet from the gateway node's perspective — it routes a Meshtastic packet to the gateway, which then forwards it outbound via MQTT or a direct API call. The return path is symmetric. +The gateway is an RF-to-internet bridge. kerykeion does not speak directly to the internet from the gateway node's perspective - it routes a Meshtastic packet to the gateway, which then forwards it outbound via MQTT or a direct API call. The return path is symmetric. **Outbound (server → internet):** @@ -511,7 +511,7 @@ This information informs PACE planning: a sub-mesh may have internal mesh commun ### 8.1 What opsis Needs -opsis (ratatui TUI) renders the mesh topology. It needs a serializable snapshot that decouples the topology engine from the rendering layer — ratatui runs in the terminal event loop, not the async mesh loop. +opsis (ratatui TUI) renders the mesh topology. It needs a serializable snapshot that decouples the topology engine from the rendering layer - ratatui runs in the terminal event loop, not the async mesh loop. ```rust /// Snapshot of the mesh topology, suitable for rendering without locking the graph. @@ -677,7 +677,7 @@ pub enum MessageFailureReason { } ``` -These signals flow into the `GeoSignal` broadcast channel and are consumed by semaino (aggregation) and opsis (display). No signal is emitted without a corresponding state change in the graph — events are not re-emitted on polling, only on transition. +These signals flow into the `GeoSignal` broadcast channel and are consumed by semaino (aggregation) and opsis (display). No signal is emitted without a corresponding state change in the graph - events are not re-emitted on polling, only on transition. --- @@ -685,7 +685,7 @@ These signals flow into the `GeoSignal` broadcast channel and are consumed by se ### 10.1 Assumptions -- LoRa SF10, BW125 kHz, CR 4/5 — typical Meshtastic default for longer range +- LoRa SF10, BW125 kHz, CR 4/5 - typical Meshtastic default for longer range - Effective data rate: ~980 bps (SF10 BW125) - Duty cycle limit: 1% per LoRa regulatory requirement (EU); US has no duty cycle limit but we budget conservatively - 7 nodes total; 4 have regular activity (2 T-Deck Plus personal carry, RAK gateway, WisBlock) @@ -729,7 +729,7 @@ If the firmware reports `channel_utilization > 20%`: If `channel_utilization > 30%`: - Suspend Default-priority S&F messages. -- Emit `ChannelCongestion` signal (new `MeshDetail` variant, not defined above — add when implementing congestion handling). +- Emit `ChannelCongestion` signal (new `MeshDetail` variant, not defined above - add when implementing congestion handling). This keeps kerykeion from amplifying congestion loops. diff --git a/research/P2-R3-mesh-networking-crates.md b/research/P2-R3-mesh-networking-crates.md index 459fa8b..3f26c16 100644 --- a/research/P2-R3-mesh-networking-crates.md +++ b/research/P2-R3-mesh-networking-crates.md @@ -1,7 +1,7 @@ # P2-R3: Mesh networking crates for kerykeion **Date:** 2026-03-18 -**Scope:** Rust crate selection for kerykeion — the clean-room Meshtastic stack within Akroasis. Covers serial, BLE, protobuf, crypto, graph, discovery, and test infrastructure. Excludes the official `meshtastic` crate (0.1.8, GPL-3.0) per project constraints. +**Scope:** Rust crate selection for kerykeion - the clean-room Meshtastic stack within Akroasis. Covers serial, BLE, protobuf, crypto, graph, discovery, and test infrastructure. Excludes the official `meshtastic` crate (0.1.8, GPL-3.0) per project constraints. kerykeion (from Greek keryx, the herald's staff carried by Hermes) handles the physical-to-application boundary: receiving LoRa packets from Meshtastic radio hardware, decrypting and decoding them, and presenting structured mesh topology to the rest of Akroasis. @@ -42,7 +42,7 @@ kerykeion (from Greek keryx, the herald's staff carried by Hermes) handles the p Use `tokio-serial 5.4.5` with `tokio-util 0.7.18` codec framing. -`tokio-serial` wraps `serialport 4.9.0` (the established synchronous serial library) with a Tokio async layer using `mio-serial` under the hood. Linux support for CP2102, CH340, and CH9102 USB serial chipsets is OS-driver level — all three present as `/dev/ttyUSBn` on Linux and work without special crate handling. Baud rate configuration, hardware flow control (RTS/CTS, DTR/DSR), and 8N1 framing are all supported through `serialport::SerialPortBuilder`. +`tokio-serial` wraps `serialport 4.9.0` (the established synchronous serial library) with a Tokio async layer using `mio-serial` under the hood. Linux support for CP2102, CH340, and CH9102 USB serial chipsets is OS-driver level - all three present as `/dev/ttyUSBn` on Linux and work without special crate handling. Baud rate configuration, hardware flow control (RTS/CTS, DTR/DSR), and 8N1 framing are all supported through `serialport::SerialPortBuilder`. `serialport` uses MPL-2.0. This is file-level copyleft: modifications to `serialport`'s own source files must be shared, but code that calls it is not affected. AGPL-3.0 is compatible with this. @@ -172,7 +172,7 @@ pub(crate) async fn open_radio( Use `btleplug 0.12.0`. -Both `btleplug` and `bluer` use D-Bus to talk to BlueZ on Linux — neither is truly free of system daemon coupling. The choice comes down to API ergonomics and cross-platform future. +Both `btleplug` and `bluer` use D-Bus to talk to BlueZ on Linux - neither is truly free of system daemon coupling. The choice comes down to API ergonomics and cross-platform future. `btleplug` provides a `Central` trait for scanning and a `Peripheral` trait for GATT operations. Characteristic discovery, read/write, and notification subscribe all have clean async interfaces. The triple license (MIT/Apache-2.0/BSD-3-Clause) causes no AGPL complications. The 2026-03-09 update date confirms active maintenance. @@ -386,7 +386,7 @@ bytes 12..15 : extraNonce as u32, little-endian (0 for normal packets) This is a 128-bit nonce used as the initial counter value. The intended layout uses a u64 packet ID (not u32). -**Firmware bug (confirmed in `CryptoEngine.cpp`):** The `extraNonce` branch writes to offset `sizeof(uint32_t)` (offset 4) instead of `sizeof(uint64_t) + sizeof(uint32_t)` (offset 12). When `extraNonce != 0`, it overwrites bytes 4–7 (the high word of `packetId`) rather than bytes 12–15. This is a latent firmware defect. For normal mesh packets `extraNonce` is always 0, so this bug is harmless in practice — the nonce layout above is correct for all packets kerykeion will receive. +**Firmware bug (confirmed in `CryptoEngine.cpp`):** The `extraNonce` branch writes to offset `sizeof(uint32_t)` (offset 4) instead of `sizeof(uint64_t) + sizeof(uint32_t)` (offset 12). When `extraNonce != 0`, it overwrites bytes 4–7 (the high word of `packetId`) rather than bytes 12–15. This is a latent firmware defect. For normal mesh packets `extraNonce` is always 0, so this bug is harmless in practice - the nonce layout above is correct for all packets kerykeion will receive. ### CTR variant selection