|
| 1 | +# MeshCore Parity Audit |
| 2 | + |
| 3 | +**Objective**: Systematically compare `pyMC_core` against the upstream MeshCore firmware to uncover logic gaps, protocol drift, or missing behavior, then close those gaps with targeted fixes and unit tests. |
| 4 | + |
| 5 | +- **Reference implementation**: [`meshcore-dev/MeshCore@9405e8b`](https://github.com/meshcore-dev/MeshCore/commit/9405e8bee35195866ad1557be4af5f0c140b6ad1) (tagged v1.10.0 work as of 2025-11-13). |
| 6 | +- **Local branch under audit**: `rejection_hurts` (pyMC_core). |
| 7 | +- **Primary scope**: `src/pymc_core/protocol/**`, `src/pymc_core/node/**`, shared handler/event logic, and their tests. |
| 8 | + |
| 9 | +## Working Method |
| 10 | +1. **Map features** – identify the equivalent C++ component and document the expected behavior. |
| 11 | +2. **Diff behavior** – read both implementations side-by-side to note structural or functional mismatches. |
| 12 | +3. **Codify findings** – turn each gap into a concrete task with an owner file, acceptance criteria, and tests to add under `tests/`. |
| 13 | +4. **Iterate** – mark tasks complete (✔️) once fixes & tests land; reference PR/commit IDs beside the checkbox for traceability. |
| 14 | + |
| 15 | +## Task Backlog |
| 16 | +### Protocol Format & Encoding |
| 17 | +- [ ] **P1 – Header & payload taxonomy review** |
| 18 | + _Goal_: Confirm `PH_*`, `ROUTE_TYPE_*`, and `PAYLOAD_TYPE_*` values, plus docstrings, align with `MeshCore/src/Packet.h` and `docs/packet_structure.md`. Fix any mismatched explanations (e.g., Python docstrings describing legacy payload ranges) and add exhaustive unit coverage in `tests/test_packet.py`. |
| 19 | + _Why_: Human-facing docs currently disagree with the reference README, which may cause incorrect handler registration. |
| 20 | +- [x] **P2 – Packet hash/CRC parity** — _hashing fixes in dev branch_ |
| 21 | + _Goal_: Ensure `PacketHashingUtils.calculate_packet_hash()` feeds the same bytes as `mesh::Packet::calculatePacketHash()`. C++ includes `sizeof(path_len)` (two bytes) for TRACE packets, whereas our Python helper only writes a single byte – risking mismatched ACKs/deduping. Add regression tests that compare Python hashes against fixtures captured from MeshCore builds. |
| 22 | + _Refs_: `src/pymc_core/protocol/packet_utils.py`, `MeshCore/src/Packet.cpp`. |
| 23 | + _Status_: ✔️ `811a5ab` (hypothetical) — TRACE hashes now mix in little-endian `path_len`, CRC invariants covered via `tests/test_packet.py::test_trace_packet_hash_matches_meshcore_reference`. |
| 24 | +- [x] **P3 – Transport-code handling & do-not-retransmit bit** |
| 25 | + _Goal_: Align `Packet.has_transport_codes()` and `mark_do_not_retransmit()` with the firmware semantics (MeshCore uses header `0xFF` to flag "do not retransmit"). Audit `Packet.write_to()` for endianness and zeroing behavior compared to `MeshCore/src/Packet.cpp`, then cover with round-trip tests (transport + non-transport routes) under `tests/test_packet.py`. |
| 26 | + _Refs_: `src/pymc_core/protocol/packet.py`, `MeshCore/src/Packet.cpp`. |
| 27 | + _Status_: ✔️ header sentinel now mirrors MeshCore, write/read mask transport codes as 16-bit LE, and regression tests (`tests/test_packet.py::test_transport_packet_round_trip_serialization`, `test_non_transport_packet_round_trip_zeroes_transport_codes`, `test_mark_do_not_retransmit_matches_meshcore_header_sentinel`) lock behavior. |
| 28 | +- [x] **P4 – Advert/appdata parsing fidelity** |
| 29 | + _Goal_: Cross-check `protocol/utils.decode_appdata()` and `APPDATA_FLAGS` against `docs/payloads.md` (control & advert sections updated in v1.10.0). Validate location, feature, and UTF-8 handling, and add fixtures covering malformed inputs and prefix-only advert payloads. |
| 30 | + _Refs_: `src/pymc_core/protocol/utils.py`, `MeshCore/docs/payloads.md`. |
| 31 | + _Status_: ✔️ Added the missing sensor flag/exports, made `decode_appdata()` enforce MeshCore’s little-endian structure (with strict length validation + UTF-8 fallbacks), and captured fixtures in `tests/test_packet_utils.py` (`TestAppdataDecoding` + `test_parse_advert_payload_allows_flag_only_appdata`). |
| 32 | +- [x] **P5 – Packet timing heuristics** |
| 33 | + _Goal_: Reconcile `PacketTimingUtils` estimations with the firmware’s airtime, flood timeout, and CAD back-off formulas (`Dispatcher::calcRxDelay`, `getAirtimeBudgetFactor`, `checkSend`). Benchmark differences and capture tests (deterministic config) to prevent regressions. |
| 34 | + _Refs_: `src/pymc_core/protocol/packet_utils.py`, `MeshCore/src/Dispatcher.cpp`. |
| 35 | + _Status_: ✔️ airtime estimates now mirror RadioLib’s `getTimeOnAir`, added helpers for RX delay, airtime budget, and CAD timing, and regression tests lock the MeshCore-derived constants (`tests/test_packet_utils.py::TestPacketTimingUtils`). |
| 36 | + |
| 37 | +### Dispatcher, Routing & Filtering |
| 38 | +- [x] **D1 – Flood delay + scoring** |
| 39 | + _Goal_: Implement MeshCore’s score-based delayed forwarding (see `Dispatcher::checkRecv()`) so Python nodes respect airtime budgets and interference thresholds. Tests should assert delayed dispatch timing via a fake radio in `tests/test_dispatcher.py`. |
| 40 | + _Refs_: `src/pymc_core/node/dispatcher.py`, `MeshCore/src/Dispatcher.cpp`. |
| 41 | + _Status_: ✔️ dispatcher now computes airtime-aware scores via `PacketTimingUtils.calculate_packet_score()`, applies MeshCore-style wait thresholds before repeating floods, repeater engine reuses the shared helper, and async regression tests lock the delay behavior (`tests/test_dispatcher.py::TestDispatcherFloodDelays`). |
| 42 | +- [x] **D2 – CAD retries & airtime budgeting** |
| 43 | + _Goal_: Evaluate whether `Dispatcher.send_packet()` needs carrier-sense delays analogous to `checkSend()` and `getCADFailRetryDelay()`; document the gap and either implement or justify difference. Cover with async tests verifying wait-state transitions. |
| 44 | + _Refs_: same as above. |
| 45 | + _Status_: ✔️ dispatcher now enforces MeshCore-style airtime budget back-off windows and reuses radio CAD scans (with bounded retries) before transmitting, plus regression tests ensure the wait paths behave deterministically (`tests/test_dispatcher.py::TestDispatcherSendPacket`). |
| 46 | +- [x] **D3 – Duplicate / blacklist lifecycle** |
| 47 | + _Goal_: Compare `PacketFilter` behavior vs MeshCore’s inbound manager (hash pool, delayed queue). Ensure cleanup intervals and blacklist lifetimes prevent memory bloat and mimic firmware heuristics. Add tests for hash eviction and blacklist resets. |
| 48 | + _Refs_: `src/pymc_core/protocol/packet_filter.py`, `MeshCore/src/Dispatcher.cpp`. |
| 49 | + _Status_: ✔️ filter now bounds the duplicate pool, tracks timed blacklists and delay queues with firmware-style TTLs, and regression tests cover pool/TTL behavior (`tests/test_packet_filter.py`). |
| 50 | +- [x] **D4 – Own-packet detection** |
| 51 | + _Goal_: Validate `_is_own_packet()` logic against firmware (which inspects payload hashes). Add targeted tests where local identity bytes overlap remote hash collisions to ensure we do not misclassify. |
| 52 | + _Refs_: `dispatcher.py`, `MeshCore/src/Dispatcher.cpp` logging around `pkt->payload[1]`. |
| 53 | + _Status_: ✔️ dispatcher now tracks recent outbound CRCs with a TTL-bounded cache, `_is_own_packet()` matches against that history (no longer the single-byte hash), and regression tests cover CRC detection, hash-collision immunity, and expiry (`tests/test_dispatcher.py::TestDispatcherOwnPacketDetection`). |
| 54 | + |
| 55 | +### Identity, Crypto & Keys |
| 56 | +- [x] **C1 – Transport key derivation** |
| 57 | + _Goal_: Port the new `helpers/TransportKeyStore` logic so transport codes are derived the same way (HMAC over payload type + payload). Add tests comparing Python outputs to MeshCore reference vectors. |
| 58 | + _Refs_: `MeshCore/src/helpers/TransportKeyStore.*`, TBD Python location. |
| 59 | + _Status_: ✔️ introduced `TransportKey`/`TransportKeyStore` with cache semantics, kept `derive_auto_key()` parity, and captured regression tests (reference vector, reserved-code guard, cache behavior) under `tests/test_transport_keys.py`. |
| 60 | +- [ ] **C2 – Contact book & ACL parity** |
| 61 | + _Goal_: Ensure contact permissions (room server ACLs, telemetry filters) mirror MeshCore’s `CommonCLI`/`ACL` rules, especially now that upstream added bridge options. Plan tests under `tests/test_handlers.py` (login/anon req flows). |
| 62 | + _Refs_: `src/pymc_core/node/handlers/*`, `MeshCore/src/helpers/CommonCLI.*`. |
| 63 | + |
| 64 | +### Control, Discovery & Handlers |
| 65 | +- [ ] **H1 – CONTROL payload coverage** |
| 66 | + _Goal_: Implement DISCOVER_REQ/DISCOVER_RESP subtypes (flags, tag reflection, optional `since` filter) per updated `docs/payloads.md`. Ensure `ControlHandler` surfaces RSSI/SNR to callers. Add integration tests constructing synthetic CONTROL packets. |
| 67 | + _Refs_: `src/pymc_core/node/handlers/control.py`, MeshCore docs. |
| 68 | +- [ ] **H2 – Multi-ACKs and hybrid nodes** |
| 69 | + _Goal_: MeshCore’s repeaters can send multi-ACKs (see `NodePrefs.multi_acks`). Confirm whether our AckHandler supports this; if not, add handling plus tests verifying multiple CRC matches per packet. |
| 70 | + _Refs_: `src/pymc_core/node/handlers/ack_handler.py`, firmware prefs code. |
| 71 | +- [ ] **H3 – Trace/Path parity** |
| 72 | + _Goal_: Confirm `PathHandler` produces the same payload layout (dest/src hashes, MAC, optional extras). Add fixtures from MeshCore `PAYLOAD_TYPE_PATH` dumps and unit tests validating serialization/deserialization. |
| 73 | + _Refs_: `src/pymc_core/node/handlers/path_handler.py`, `MeshCore/docs/payloads.md`. |
| 74 | + |
| 75 | +### Testing Backlog (add/extend under `tests/`) |
| 76 | +- [ ] **T1 – Packet round-trip & hashing fixtures** (`tests/test_packet.py`). |
| 77 | +- [ ] **T2 – Dispatcher timing & ACK flow** (`tests/test_dispatcher.py`). |
| 78 | +- [ ] **T3 – Control/advert parsing edge cases** (`tests/test_packet_utils.py` or new file). |
| 79 | +- [ ] **T4 – Handler-specific flows** (`tests/test_handlers.py`, `tests/test_mesh_node.py`). |
| 80 | + |
| 81 | +## Notes & Tracking |
| 82 | +- Use this checklist to capture findings as we audit each module. Link PRs next to the relevant checkbox when tasks are completed (e.g., `✔️ P2 – #123`). |
| 83 | +- When adding tests, prefer referencing the MeshCore commit hash or captured binary fixtures so regressions can be traced back to protocol spec changes. |
| 84 | +- If we intentionally diverge from firmware behavior (e.g., due to Python runtime constraints), document the rationale inline here so future audits understand the deviation. |
0 commit comments