diff --git a/03-DESIGN/01-to-be/02-scenario-declaration.md b/03-DESIGN/01-to-be/02-scenario-declaration.md index 62e59b2..5789e4f 100644 --- a/03-DESIGN/01-to-be/02-scenario-declaration.md +++ b/03-DESIGN/01-to-be/02-scenario-declaration.md @@ -388,6 +388,115 @@ This is **not** the same as `machines[].inbound`, and conflating them loses a re A mesh node behind a `policy` deny cannot be reached even by a peer that knows exactly where it is — and that is a real topology, not a contrived one. +## Worked example — a whole mesh of the ordinary kind + +The shape research 004 identified: one machine with a routable address, one publicly named but +behind a household connection, one stationary machine on that network, one that roams. Written +out completely, with every field the model has. + +```yaml +scenario: the-ordinary-shape + +segments: + internet: + kind: public + cidr: [203.0.113.0/24, 2001:db8::/32] + mtu: 1500 + + home: # the household network + kind: private + cidr: [192.168.1.0/24, 2001:db8:1::/64] + mtu: 1492 # PPPoE on the uplink; 1500 if the line is not PPPoE + gateway: + to: internet + address: 203.0.113.50 # the address the ISP hands the household + nat: [v4] # v4 translated, v6 routed — the modern default + forwardable: true # the household router is ours to configure + mapping_ttl: 120s + + devices: # optional: a segmented network on the same router + kind: private + cidr: [192.168.30.0/24] + gateway: + to: internet + address: 203.0.113.50 # identical → the SAME gateway machine + nat: [v4] + forwardable: true + mapping_ttl: 120s + + elsewhere: # wherever the roaming machine happens to be + kind: private + cidr: [198.51.100.0/24] + mtu: 1400 + gateway: + to: internet + address: 203.0.113.80 + nat: [v4] + forwardable: false # someone else's network, or carrier-grade NAT + mapping_ttl: 30s + +policy: + - { from: devices, to: home, allow: false } + - { from: home, to: devices, allow: true } + +machines: + anchor: # routable, nothing in front of it + at: { segment: internet, address: [203.0.113.10, 2001:db8::10] } + inbound: allow + + home-server: # publicly named, behind the household connection + at: { segment: home, address: [192.168.1.135, 2001:db8:1::135] } + published: + - { port: 443, on: home } # v4 reaches it only through the forward + inbound: allow # and v6 reaches it directly, so this matters + + workstation: # on the household network, not published + at: { segment: home, address: [192.168.1.250, 2001:db8:1::250] } + inbound: deny + + laptop: # starts at home; moves during the run + at: { segment: home, address: [192.168.1.98, 2001:db8:1::98] } + inbound: deny + +place: + all: [host] + anchor: [substrate] + +snapshot: raised +``` + +### What the ISP modem is doing here + +**Nothing, if it is in bridge mode** — which is the ordinary arrangement when the household has +its own router. A bridged modem is a media converter: it changes the physical medium and leaves +the packets alone, so it creates no IP-level fact and appears nowhere above. + +Were it in router mode it would be a second gateway, `home` would sit behind it rather than +behind `internet` directly, and publishing would need a rule on both — the case the model +cannot yet express. + +### What is deliberately absent + +Nothing here mentions overlay addresses, which node is the hub, who peers with whom, any name, +or any certificate. Research 004 recorded all of those for this topology, and **a scenario must +not state them** ([ADR 0031](../../02-DECISIONS/0031-the-lab-provides-the-underlay.md)): they +are what the mesh does, and a scenario that supplied them would be certifying its own work. + +The absence is the point. Given the declaration above, whether a hub is elected, whether the +NATed machine's endpoint is learned, whether the roaming machine re-forms after moving — all of +it is observed. + +### Running it + +``` +move laptop → { segment: elsewhere, address: [198.51.100.23] } # it leaves the house +move laptop → detached # it sleeps +move laptop → { segment: home, address: [192.168.1.98, 2001:db8:1::98] } +``` + +One identity, four positions, one run. The `mapping_ttl: 30s` on `elsewhere` means a connection +held without refreshing dies while it is out — which is the point of putting a number there. + ## Is this general? — the axes a setup can vary along The question that matters is not *does this cover our mesh*, but **can it express any mesh**.