Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pico-node is node **firmware people build a real node with** β€” so radios (a Ni

## Where it stands today (2026-07-12, after the Fable wave)

`crates/ax25-node-core` builds `thumbv6m-none-eabi` `no_std`+`alloc`; the `ax25-node-fw` crate cross-compiles. Health on `main`: **717 core host tests** green, `clippy -D warnings` clean, the `no_std` build clean, both fw `--locked` gates green, and the parity drift-guard passing (0 gaps).
`crates/ax25-node-core` builds `thumbv6m-none-eabi` `no_std`+`alloc`; the `ax25-node-fw` crate cross-compiles. Health on `main`: **724 core host tests** green, `clippy -D warnings` clean, the `no_std` build clean, both fw `--locked` gates green, and the parity drift-guard passing (0 gaps).

> **The old June "current state" in this doc was stale.** A fresh recon (2026-07-12) found the tree far more complete than recorded β€” full detail in **[Delivered β€” 2026-07-12 Fable wave](#delivered--2026-07-12-fable-wave)**. In brief: NET/ROM L4 + NODES origination + INP3 were *already* built (not "read-only"); mod-128 was genuinely missing *at the wire codec* (now shipped); the radio stack was greenfield (now shipped); no shared golden vectors existed (now built).

Expand All @@ -33,27 +33,27 @@ A parallel implementation wave β€” recon fan-out β†’ 7 isolated git worktrees
| parity CI | cross-stack drift-guard: `scripts/parity-check.mjs` + vendored 50-item C# inventory + `parity-exceptions.json` + self-hosted `.github/workflows/parity.yml` | #53 |
| fw wiring | NODES obsolescence-sweep fix, origination + RX-observe on RF, `kiss_serial` pump+spawn, new Tait CCDI transport β€” **compile-validated only, no hardware run** (also repaired a fw-build break from #58's new enum variants) | #60 |

### Shipped β€” "land everything not explicitly deferred" pass (PRs #62–#63)
### Shipped β€” "land everything not explicitly deferred" pass (PRs #62–#65)

The In/Yes picks that had slipped to follow-up were then landed:

| Area | What shipped | PR |
|---|---|---|
| D Β· SDM | **SDM link** (`SdmTuningLink`) over the CCDI driver β€” receipt-tolerant default (returns on radio-accept; a delivered send with **no** over-air receipt is *not* an error β€” the TM8110 SDM auto-ack refractory finding), retry-on-reject, sequence dedupe | #62 |
| A Β· XID | **XID/MDL keystone** β€” XID info-field TLV codec (spec Fig 4.5–4.6 golden bytes), pre-session XID responder, peer-capability cache, **activates SREJ** (negotiated-SREJ link now emits SREJ β€” was dormant), `prefer_extended_connect` **default β†’ on** + DM-degrade regression, XID golden vectors | #63 |
| A Β· XID | **Initiator pre-connect XID probe** (`NegotiateSrejBeforeConnect`) β€” probe-out β†’ response-merge-connect / timeout-fallback / cache-hit-skip; completes the XID pick | #65 |

This retires the earlier "SREJ / v2.2 shipped but dormant" caveat: SREJ now activates on a negotiated link, and pico dials SABME-first by default. **717 core tests** on `main`; both fw `--locked` gates + drift-guard green.
This retires the earlier "SREJ / v2.2 shipped but dormant" caveat: SREJ now activates on a negotiated link, and pico dials SABME-first by default. **724 core tests** on `main`; both fw `--locked` gates + drift-guard green.

### 3-way parity mirror (cross-repo β€” merged)
`interop.yml` (packet.net **#605**) and `parity-check.mjs` + `ci.yml` (ax25-ts **#73**) gained a `--rust` leg so the mirror is a true 3-way gate β€” C# `Packet.*` βŠ† TS `@packet-net/ax25` βŠ† Rust pico-node, drift failing on whichever side introduces it. Reuses the live C# extraction (single source of truth) against pico-node's manifest/exceptions. **Both merged** (validated locally: three legs green, backward-compatible, and the Rust leg bites on injected drift).

### Decision reconciliations
- **INP3 (decided "Later, leave a seam")** β€” it turned out *fully built and byte-identical*. Retroactively cargo-gating it would **diverge from the C# reference** (which also ships it always-compiled, runtime-gated). Resolution: **left as-is β€” present, runtime-gated *off* by default**; the wire form degrades exactly to plain NET/ROM when disabled, which honours "leave a seam" without divergence.
- **`prefer_extended_connect`** shipped default-off in #56 (pending #48), then **flipped to default-on in #63** with a DM-refusing-peer degrade-to-mod-8 regression β€” pico now dials SABME-first, matching C# `PreferExtendedConnect`.
- **XID / MDL responder + `preConnectXid` cache** (decided In) shipped in #63; **SDM link** (decided Yes) shipped in #62. The one deferred sub-piece is the initiator XID probe (below).
- **XID / MDL responder + `preConnectXid` cache** (decided In) shipped in #63, and the **initiator pre-connect XID probe** in #65 β€” the XID pick is complete. **SDM link** (decided Yes) shipped in #62.

### Still open (follow-ups)
- **Initiator pre-connect XID *probe*** (`NegotiateSrejBeforeConnectAsync` β€” proactively send our XID *before* we dial, bounded-wait, merge). The XID *responder* + peer-capability cache landed (#63); the initiator half is an inherently async, fw-side multi-step flow left as a clean follow-on β€” the `mdl::apply_negotiated` merge + `capability.rs`/`connect_planned` dial seam are in place for it.
- **SDL version skew** β€” Rust `ax25sdl` 0.8.0 vs C# `Packet.Ax25.Sdl` 0.10.0, pico floats on `main`. Recorded in `parity-manifest.toml [sdl]`; pin to a matching `crate-v*` tag. Only bites SDL-*driven* session vectors, not pure codecs.
- **fw bench validation** β€” everything in #60 is compile-only; sweep timing, on-air NODES visibility, the `kiss_serial` pump under live NinoTNC traffic, and the Tait CCDI transact/demux all need the hardware-bringup session.
- **Optional NET/ROM parity** β€” L4 payload compression (needs a `no_std` deflate β€” a dependency decision) and NODESPACLEN per-port fragmentation; both default-off in C#, so interop is unaffected today.
Expand Down Expand Up @@ -82,7 +82,7 @@ This retires the earlier "SREJ / v2.2 shipped but dormant" caveat: SREJ now acti
| **mod-128 (extended) framing** β€” SABME/extended control octets | NONE (its own flagged follow-up) | πŸ”’ | In | In Β· βœ… #56 |
| **v2.2-preferred CONNECT** (SABME-first, SABM fallback) | check | πŸ”’ | In | In Β· βœ… #56 codec; **#63 flips default on** (SABME-first) + DM-degrade regression |
| **SREJ-to-BPQ interop** tweaks (the working-SREJ leg) | PARTIAL (has SREJ) | πŸ”’ | In | In Β· βœ… codec #56/#55; **activated via XID negotiation #63** (was dormant) |
| **Pre-session XID responder** + mod-8 interlinks + fast-probe fallback | NONE | πŸ”’ | In | In Β· βœ… **#63** responder + TLV codec + activation (initiator *probe* = residual) |
| **Pre-session XID responder** + mod-8 interlinks + fast-probe fallback | NONE | πŸ”’ | In | In Β· βœ… **#63** responder + TLV codec + activation; **#65** initiator probe (complete) |
| **Per-call preConnectXid / peer-capability cache** dial param | NONE | πŸ”’ | Decide | In Β· βœ… **#63** (peer-capability cache + dial seam) |
| **Carrier-sense (CSMA) seam** (`ICarrierSense` parity) | NONE | πŸ”’/πŸ”§ | In (needed for any keyed modem) | In Β· βœ… #56 (default always-clear) |
| **figc4.x quirks added after #47** (if any landed) | HAS #38–47 | πŸ”’ | In (audit) | In (audit) Β· βœ… #55 adds #48/#9/#13 β†’ 11/12 |
Expand Down
Loading