← RFC

Backbone B1 — The First INFRA↔INFRA Adjacency (design)

Status: Implementation design for the next protocol milestone. Date: 2026-06-12. Implements: routing-spec.md §4 (backbone link-state) + §5 (coordinator claims), minimal slice. Hardware path: bench first (the Duo's two radios as two co-channel coordinators), then the real thing: mid-tower + top-tower nodes (top switches to the Loomwave fleet when its MeshCore data-gathering stint ends).

Goal

Two coordinators, each running a full secured cell, that discover each other, exchange link-state, and forward client traffic across cells — the first multi-cell Loomwave mesh. Everything so far is one cell; this is the architecture's defining claim on hardware.

Constraints

Design: same channel, half-frame stagger

Both cells share one channel (902.5 MHz / SF9). FRAME_T = 2000 ms is split:

|<------------------ 2000 ms ------------------>|
| A: BEACON | A slots | A CW || B: BEACON | B slots | B CW |
t0          ...        ...    t0+1000ms   ...      ...

Discovery and claims

  1. Scan-before-claim (boot): a coordinator listens SCAN_SF = 4 superframes before its first beacon. If it hears an existing coordinator's signed beacon, it TOFUs that coordinator (identity ADVERT exchange as today), adopts the half-frame offset, and records the adjacency. If it hears nothing, it anchors at its own t0 (it is "A").
  2. Coordinator-claim ADVERT (ADV_COORD_CLAIM = 0x02): sent in the peer's CW after TOFU. Body: cell_desc(3) ‖ member_count(1) ‖ reach_score(2) — the §5 election evidence in embryo (B1 doesn't elect; both stay coordinators; the frame exists so B2+ can).

LSA ADVERT (ADV_LSA = 0x03), signed, rate-capped at one per LSA_EVERY = 8 superframes, transmitted in the peer's CW. Body:

seq(2)  member_count(1)  members: count × addr24   adjacencies: count2 × (addr24 ‖ rssi_q(1))

Each coordinator thereby learns the peer's cell membership (the aggregated edge tier — members as a list at B1 scale; the spec's summarized form comes when counts demand it) and its adjacency list. Two nodes → trivial SPF (the route is "the peer"), but the frames, tables, and signatures are the real ones.

Cross-cell forwarding (the demo that matters)

Client X registered in B's cell sends sealed DATA with DST = a member of A's cell (or A itself):

  1. B receives X's DATA in X's slot, opens it (pairwise X↔B), sees DST not local and present in A's last LSA membership.
  2. B re-seals pairwise B↔A (B1 forwarding is hop-by-hop re-encryption — the relay owns the plaintext; true end-to-end across cells needs key distribution beyond B1) and transmits in A's CW with HOPLIM decremented (relay_step).
  3. A opens, delivers/logs: a frame crossed two cells over the backbone.

The reverse path (A-cell → B-cell) is symmetric. The tower drive-test rig then demonstrates: T114 in B's (top, above-canopy) cell, its position reports forwarded into A's (mid) drive log.

Failure behaviour

Milestones

Deliverable Where
B1.1 proto: ADV_COORD_CLAIM / ADV_LSA subtypes + bodies + tests code repo
B1.2 infrad: scan-before-claim, stagger anchor, claim/LSA exchange, neighbor table code repo
B1.3 Bench demo: Duo SX1262 = coordinator A, LR1121 = coordinator B, same channel; LSAs exchanged; T114 joins B; X-cell forward A↔B observed bench
B1.4 Tower demo: top node → Loomwave fleet; mid (A) + top (B); T114 drive with cross-cell forwarding field

Out of scope for B1 (B2+ backlog)

N>2 slot negotiation; coordinator election/demotion (claims carried but not acted on); cell summarization at scale; end-to-end sealing across cells; backhaul-transport adjacencies; spatial reuse between the cells.