Compare commits

...
Author SHA1 Message Date
jochen b740ce9321 Connectivity: walk the five contexts through the network layers, so a reader can see which layer each one acts at and read a failure from the bottom up
mesh/delivery ready: it delivers once merged
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
2026-10-10 14:12:48 +02:00
+110 -1
View File
@@ -22,8 +22,10 @@ code:
- mesh-host internal/apply (the service that reflects a rule set; a whole file handed to its new owner) - mesh-host internal/apply (the service that reflects a rule set; a whole file handed to its new owner)
- mesh-controller cmd/mesh-controller/nodes.go (a token issued for a machine's tunnel key, ADR 0169) - mesh-controller cmd/mesh-controller/nodes.go (a token issued for a machine's tunnel key, ADR 0169)
- mesh-host cmd/mesh-host/join_tunnel.go (a machine joins through the tunnel, ADR 0169) - mesh-host cmd/mesh-host/join_tunnel.go (a machine joins through the tunnel, ADR 0169)
updated: 2026-10-08 updated: 2026-10-09
decisions: decisions:
- 02-DECISIONS/0241-a-machine-says-how-its-network-is-and-an-outside-writer-of-a-mesh-file-is-a-finding.md
- 02-DECISIONS/0117-a-machines-uplink-is-a-seat.md
- 02-DECISIONS/0247-a-machine-with-a-vpn-client-routes-names-by-domain-through-a-resolver-of-its-own.md - 02-DECISIONS/0247-a-machine-with-a-vpn-client-routes-names-by-domain-through-a-resolver-of-its-own.md
- 02-DECISIONS/0226-the-private-network-is-assigned-by-its-own-name-and-the-proxy-names-its-public-issuer.md - 02-DECISIONS/0226-the-private-network-is-assigned-by-its-own-name-and-the-proxy-names-its-public-issuer.md
- 02-DECISIONS/0223-the-mesh-has-two-resolvers-and-a-machine-lists-only-them.md - 02-DECISIONS/0223-the-mesh-has-two-resolvers-and-a-machine-lists-only-them.md
@@ -1105,6 +1107,113 @@ against today's behaviour, where both are always composed; an unrouted endpoint
named; an assignment naming an endpoint the module does not declare refused where it is said; and a named; an assignment naming an endpoint the module does not declare refused where it is said; and a
silent assignment rendering byte-identically to today. silent assignment rendering byte-identically to today.
## The five through the network layers
*2026-10-09. A reading aid: it decides nothing and states no rule. Each claim names the section or the
record that decided it.*
The OSI model is the standard seven-layer picture of a network: every layer wraps what the layer above
hands it, and the receiving side unwraps in reverse. The five contexts of this document act at
different layers, and seeing which explains why they fail independently. A resolver that stopped
answering leaves the private network working, and a tunnel that cannot handshake leaves every name
resolving to an address nothing can reach.
| Layer | What it carries | Where the mesh acts there |
|---|---|---|
| 7 Application | the message itself | the bus ([ADR 0106](../../02-DECISIONS/0106-the-bus-is-nats.md)); resolution (§2); exposure, where the proxy chooses a route by the name a request asks for (§3) |
| 6 Presentation | how what is said is encoded and encrypted | certificates (§5): TLS, which is usually drawn between 4 and 7 and placed here by the book |
| 5 Session | a conversation kept open | a node's link to the bus, opened once and reopened after the machine sleeps |
| 4 Transport | ports, TCP and UDP | filtering (§4), which opens a port to a source; the private network itself travels as UDP |
| 3 Network | addresses and the path between them | the private network (§1): every node's address, the peer graph, the hub relaying |
| 2 Data link | frames on one network segment | the machine's own uplink ([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)), on the underlay |
| 1 Physical | cable, fibre, radio | nothing of the mesh's |
### Two networks, one inside the other
**The private network is a layer 3 network carried at layer 4 of the underlay.** A packet for another
node's private address is encrypted whole and becomes the payload of a UDP datagram addressed to a
peer's underlay address. Every hop on the underlay reads only the outer envelope, up to its layer 3,
and never sees inside.
```
underlay │ L1 radio │ L2 frame │ L3 to the hub's public address │ L4 UDP │ ▓▓ encrypted ▓▓ │
│
decrypted at the hub │
┌────────────────────────────────────────────────┘
▼
private network │ L3 to a private address │ L4 TCP │ L5–L7 a message on the bus │
```
### The shape the layers are drawn on
The shape is §1's: a hub, direct peering between nodes at the same site, and a roaming node that goes
through the hub only. In a small mesh one node is both the anchor and the hub, and holds the bus.
```
┌──────────────────────────────────────────┐
│ hub and anchor — reachable from outside │
│ holds the bus │
└─────▲──────────────────▲─────────────▲───┘
│ │ │
│ each tunnel is dialled out by the node below it
│ │ │
┌─────┴─────┐ ┌──────┴──────┐ ┌────┴────────┐
│ laptop │ │ home-server │ │ home-server │
│ no site: │ └──────▲──────┘ └──────▲──────┘
│ hub only │ └──── direct ───┘
└───────────┘ same site, peered
```
**Every arrow points at the hub.** A node with no public address still has a tunnel, because it dials
out and the hub answers; only the hub's tunnel must be dialable, at a stable address
([ADR 0169](../../02-DECISIONS/0169-a-machine-joins-through-the-tunnel-and-the-bus-is-never-public.md)).
### One tool call, from the laptop to a home-server
The laptop wraps the call one layer at a time:
| Layer | On the laptop |
|---|---|
| 7 | a message on the bus naming the tool and its arguments |
| 6 | the message encoded for the wire |
| 5 | the laptop's link to the bus, already open |
| 4 | TCP to the bus at its private address |
| 3 | a packet from the laptop's private address to the bus's |
| 3 inside 4 | the tunnel: that packet encrypted, in a UDP datagram to the hub's public address |
| 2 | a frame to the gateway of whatever network the laptop is on |
| 1 | radio |
**At the hub the outer envelope comes off** — frame, packet, datagram — and the tunnel decrypts what was
inside. The inner packet is addressed to the bus, which is on this node, so the hub keeps unwrapping up
to layer 7. The bus finds the home-server's subscription and sends the message down the home-server's
own link, which that node opened earlier through its own tunnel. Neither spoke ever accepted a
connection; both dialled the hub.
**How far the hub unwraps depends on what the packet is for.** A packet addressed to a home-server's
private address, not to the bus, is opened only to layer 3: the hub relays it, encrypted again for the
home-server's tunnel. That is the whole of the glossary's *a hub relays for nodes that cannot reach
each other directly*. Two home-servers at one site skip the hub: their tunnel crosses the home network
at layer 2, and nothing of theirs reaches the hub at all.
**Why a roaming node has one path is a layer 3 fact.** A more specific route to an endpoint that is
gone takes the packets and drops them; it does not fall back (§1). A laptop that moves between networks
therefore has exactly one route, the hub's.
### Reading a failure by layer
The machine's own network checks
([ADR 0241](../../02-DECISIONS/0241-a-machine-says-how-its-network-is-and-an-outside-writer-of-a-mesh-file-is-a-finding.md))
each look at one layer:
| Check | Layer | Failing alone means |
|---|---|---|
| **route** — a default route | 3, underlay | the machine has no way out; nothing above can work |
| **tunnel** — a handshake with the hub within five minutes | 3 carried at 4 | the underlay works and the private network does not: a key, the hub's address, or a filter on the way |
| **bus** — the link is open | 5 to 7 | the private network works and the bus, or the node's account on it, does not |
| **resolv-conf** and **names** | 7 | addresses work and names do not, as when a VPN client rewrites the machine's resolver file |
Read them from the bottom. A layer that fails explains every failure above it, and never one below it.
## What this removes ## What this removes
The list is worth having in one place, because it is most of the argument: The list is worth having in one place, because it is most of the argument: