Files
ruvnet--RuView/v2
ruv 23fd8ac371 feat(sensing-server): consume ADR-110 §A0.12 sync packets, store per-node
Iter 15 — converts the iter 14 SyncPacket decoder from "shipped" to
"consumed" by wiring it into the sensing-server UDP receive loop.

Wiring:
- Cargo.toml gains wifi-densepose-hardware = path = "../wifi-densepose-hardware"
  to pull in the SyncPacket decoder + SYNC_PACKET_MAGIC dispatch constant.
- NodeState gains two new fields:
    latest_sync:    Option<SyncPacket>           — the parsed packet
    latest_sync_at: Option<std::time::Instant>   — staleness clock
- udp_receiver_task now magic-dispatches every incoming datagram against
  SYNC_PACKET_MAGIC (0xC511A110) before falling through to the existing
  ADR-039 vitals / ADR-040 WASM / ADR-018 CSI parsers. Same Option-returning
  pattern as the other parsers, so future packet types slot in cleanly.

When a sync packet arrives:
  * write-lock state, lookup-or-create NodeState by node_id
  * stash the SyncPacket + Instant::now() on the node
  * debug-log node, leader/valid/smoothed flags, sequence, offset_us
  * continue (don't fall through — we know it's not a CSI frame)

Downstream multistatic CSI fusion now has a documented landing pad: any
CSI frame with byte 19 bit 4 set looks up the matching NodeState, applies
ns.latest_sync.epoch_us + (now_local - ns.latest_sync.local_us) to get a
mesh-aligned timestamp. Implementation of that fusion math is the next
ADR-029/030 layer (wifi-densepose-signal).

Verification:
- cargo check -p wifi-densepose-sensing-server --no-default-features → green
- cargo test -p wifi-densepose-hardware sync_packet → 7/7 pass, 122 filtered
- Zero behavioral change for nodes that don't emit sync packets — the
  dispatch only fires on magic match.

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-05-23 13:11:35 -04:00
..