The previous one-sentence §8.3 was wrong about scope: it said KISS hosts
treat the 1-byte header as opaque pass-through, which is misleading —
the byte lives between RNodes on the LoRa air-frame, not on the KISS
channel. Hosts (RNS, Sideband, etc.) never see it. Any alternative
implementation that talks LoRa to an RNode must construct/parse it
bit-exactly, or its TX is invisible and its RX mistakes the header for
the first payload byte.
New text covers:
- Header byte layout: bit 7..4 random seq nibble, bit 0 FLAG_SPLIT,
SEQ_UNSET=0xFF sentinel (Framing.h:105-108).
- TX rules: header = random(256) & 0xF0 | (FLAG_SPLIT iff
payload > 254). Both halves of a split share the same byte byte-
for-byte. Split at 255 bytes total per LoRa frame; max reassembled
payload 508. (RNode_Firmware.ino:716-742; Config.h:59-61.)
- RX state machine: at most one buffered first-half keyed by seq
nibble; four cases for inbound frames (RNode_Firmware.ino:359-446).
- Reassembly timeout: upstream firmware has none (relies on
subsequent traffic to evict). The clean-room repeater adds a 500ms
defensive timeout (reticulum-lora-repeater/src/Radio.cpp:189-194)
— implementation-private, not part of the wire spec.
- Sequence-collision ceiling: 4 random bits = 1/16 collision per
overlapping split-packet pair from the same sender. Don't burst.
- Note that a "header rotates between transmissions" memory of this
protocol is a fading recall of the per-TX random seq nibble — there
is no retransmit-driven byte rotation or rechunk. LoRa TX is
fire-and-forget; higher-layer retransmit just re-runs the TX path
and gets a fresh random seq.
todo.md gets an entry for tools/verify_rnode_split.py to lock the
new §8.3 in with a runtime test.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
119 lines
6.2 KiB
Markdown
119 lines
6.2 KiB
Markdown
# TODO
|
|
|
|
Outstanding work for the spec repo.
|
|
|
|
## Outreach
|
|
|
|
- [ ] **File a community-documentation issue on `markqvist/Reticulum`.**
|
|
Link this repo as a community-maintained byte-level spec. Ask
|
|
whether the maintainer would like to bless / link from the
|
|
official Reticulum manual. Frame it as a complement to (not a
|
|
replacement for) the existing operator-focused docs.
|
|
|
|
## Test infrastructure
|
|
|
|
- [x] **Bootstrap `test-vectors/identities.json`** — Alice + Bob
|
|
identities populated against RNS 1.2.0. Regenerator at
|
|
`tools/regen_identities.py`.
|
|
- [ ] **Bootstrap remaining test-vectors files** (`announces.json`,
|
|
`lxmf.json`, `links.json`) with the existing vectors from
|
|
`reticulum-mobile-app/reference/test-vectors.json`. Convert to
|
|
the proposed JSON format documented in `test-vectors/README.md`,
|
|
adding the regenerator scripts so future contributors can
|
|
verify vectors against newer upstream RNS releases.
|
|
|
|
- [ ] **Write the priority verifier scripts** listed in
|
|
`tools/README.md`, in this order (highest interop value first):
|
|
1. [x] `verify_destination_hash.py` — pure-function check, no RNS state needed
|
|
2. [x] `verify_packet_header.py` — bit layout + HEADER_1/HEADER_2 round-trip + originator HEADER_1→HEADER_2 conversion
|
|
3. [ ] `verify_announce_roundtrip.py` — closes the SPEC.md §4 gap (partial coverage in `verify_announce_app_data.py`)
|
|
4. [ ] `verify_token_crypto.py` — closes SPEC.md §3 gap
|
|
5. [ ] `verify_lxmf_opportunistic.py` — closes SPEC.md §5 gap
|
|
6. [ ] `verify_link_handshake.py` — closes SPEC.md §6 gap
|
|
7. [x] `verify_path_request.py` — closes SPEC.md §7.1, §7.2 gaps
|
|
8. [ ] `verify_msgpack_quirk.py` — closes SPEC.md §9.3 gap
|
|
|
|
Each verifier should remove its corresponding `⚠️ UNVERIFIED` /
|
|
`🔮 SPECULATION` callout in `SPEC.md` (per `agent.md` §1).
|
|
|
|
## Open `⚠️ UNVERIFIED` items in SPEC.md
|
|
|
|
These need either a runtime test or a stronger upstream source citation
|
|
to remove their markers:
|
|
|
|
- [x] **§2.3 Originator HEADER_1 → HEADER_2 conversion.** Verified
|
|
against RNS 1.2.0 by `tools/verify_packet_header.py`, which
|
|
seeds `Transport.path_table` with a multi-hop entry and confirms
|
|
the converted wire bytes via stubbed `Transport.transmit`.
|
|
Citation updated to `RNS/Transport.py:1074-1083`.
|
|
|
|
- [x] **§4.3 The 3-element `[name, stamp_cost, [capabilities]]`
|
|
app_data variant.** Verified against LXMF 0.9.6 by
|
|
`tools/verify_announce_app_data.py`. Finding: in this LXMF
|
|
version the producer emits a 2-element form only (the
|
|
`supported_functionality` line at `LXMF/LXMRouter.py:999` is
|
|
dead code); the parser is prepared for a 3-element form via
|
|
`compression_support_from_app_data`. SPEC.md §4.3 updated to
|
|
describe the actual current behavior.
|
|
|
|
- [x] **§7.1 path? always precedes LXMF DATA.** Verified against
|
|
LXMF 0.9.6 by `tools/verify_path_request.py`. Finding: the
|
|
preamble fires only when `not has_path()` AND method is
|
|
OPPORTUNISTIC; the retry path can fire a second `request_path`
|
|
after `MAX_PATHLESS_TRIES` (`LXMRouter.py:2571+`). SPEC.md §7.1
|
|
rewritten accordingly. Also fixed a documentation bug in §1.2
|
|
(path-request name_hash column).
|
|
|
|
- [x] **§7.4 Ratchet ring count default = 8.** False — actual upstream
|
|
default is `Destination.RATCHET_COUNT = 512` at
|
|
`RNS/Destination.py:85` in RNS 1.2.0, with
|
|
`RATCHET_INTERVAL = 30*60` (line 90) and
|
|
`RATCHET_EXPIRY = 60*60*24*30` (`RNS/Identity.py:69`).
|
|
SPEC.md §7.4 corrected.
|
|
|
|
## Open `⚠️` items needing a runtime verifier
|
|
|
|
- [ ] **`tools/verify_rnode_split.py` to lock in §8.3.** The RNode
|
|
air-frame split-packet protocol is now documented in SPEC.md §8.3
|
|
against direct citations in `markqvist/RNode_Firmware/Framing.h`,
|
|
`Config.h`, `Utilities.h`, and `RNode_Firmware.ino`, plus the
|
|
clean-room reimplementation in `thatSFguy/reticulum-lora-repeater/src/Radio.cpp`.
|
|
A runtime verifier would: build a 300-byte synthetic Reticulum
|
|
packet, run it through a Python implementation of the TX-side
|
|
header rules, and confirm the byte-level frames match what
|
|
`RNode_Firmware.ino:716-742` would emit (header byte high nibble
|
|
random + low-nibble FLAG_SPLIT bit, both frames sharing the same
|
|
header, split point at 255 bytes total per LoRa frame). RX-side
|
|
verifier should drive the state-table at SPEC.md §8.3 and confirm
|
|
the four reassembly cases.
|
|
|
|
- [ ] **Lock in the §6.2 / §6.3 corrections with `verify_link_handshake.py`.**
|
|
The wire-byte order of the LRPROOF body (`signature || responder_X25519_pub || signalling`,
|
|
not `link_id || responder_X25519_pub || signature || signalling`) and
|
|
the `link_id` derivation offsets (`N=2` for HEADER_1, `N=18` for HEADER_2,
|
|
not 18/34) were corrected against direct upstream source citations
|
|
(`RNS/Link.py:376`, `RNS/Packet.py:354-361`) in `SPEC.md` §6.2/§6.3
|
|
while writing `flows/send-link-lxmf.md`. They are source-cited but
|
|
not yet exercised by a runtime verifier. Add `tools/verify_link_handshake.py`
|
|
that drives an upstream LINKREQUEST → LRPROOF → ACTIVE handshake and
|
|
asserts byte-level layouts + `link_id` invariance under HEADER_1↔HEADER_2.
|
|
|
|
## Spec polishing (lower priority)
|
|
|
|
- [ ] **Split `SPEC.md` into per-layer files** as the document grows
|
|
past ~1500 lines. Suggested layout per `README.md`:
|
|
`00-overview.md`, `01-packet-header.md`, `02-identity.md`,
|
|
`03-announce.md`, `04-token-crypto.md`, `05-lxmf.md`,
|
|
`06-link.md`, `07-resource.md`, `08-transport.md`,
|
|
`09-paths-and-discovery.md`, `10-implementation-gotchas.md`.
|
|
|
|
- [ ] **Add a "last-verified-against-rns" line** to SPEC.md
|
|
frontmatter (per `agent.md` §7) so readers know which RNS
|
|
version the spec was tested against.
|
|
|
|
- [ ] **Document the Reticulum Resource fragmentation protocol** —
|
|
currently absent from SPEC.md but needed for multi-packet LXMF
|
|
over Link (NomadNet pages > 1 MTU, large file transfers).
|
|
|
|
- [ ] **Document the Propagation `/get` pull protocol** for offline
|
|
message retrieval. Used by Sideband when peers are out of range.
|