Iter 29 — extends the iter 23 WebSocket NodeSyncSnapshot publication
with an HTTP surface so non-streaming clients (curl scripts, Home
Assistant REST sensors, Prometheus exporters, automation rule probes)
can poll mesh state without holding a WebSocket connection.
GET /api/v1/nodes/:id/sync
200 → Json(NodeSyncSnapshot) when latest_sync is present
404 → {"error": "unknown_node" | "no_sync", "node_id": N}
— "no_sync" includes a `hint` pointing operators at the
"no mesh peer or not v0.6.9+" diagnostic.
GET /api/v1/mesh
200 → { "nodes": { "<id>": NodeSyncSnapshot, ... }, "total": N }
Nodes without a recent sync are omitted; an empty `nodes` object
means no mesh peers reachable.
Both handlers reuse the iter 23 NodeSyncSnapshot struct (same JSON
shape as the WebSocket broadcast — clients get one schema, two
delivery modes). The Path<u8> extractor returns 404 on overflow
automatically (axum), so /api/v1/nodes/256/sync gives a clean error.
cargo check -p wifi-densepose-sensing-server --no-default-features → green.
Curl quick-start (added to operator playbook material in a follow-up):
curl http://localhost:3000/api/v1/mesh # full fleet
curl http://localhost:3000/api/v1/nodes/9/sync # one node
Co-Authored-By: claude-flow <ruv@ruv.net>