From 35d25c13e889f8f74b33740a054f2703e5e9cce1 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:40:31 +0200 Subject: [PATCH] ADR 0119: a taken tunnel's predecessor is retired once the take is proven --- ...-a-taken-tunnels-predecessor-is-retired.md | 78 +++++++++++++++++++ 02-DECISIONS/README.md | 1 + 2 files changed, 79 insertions(+) create mode 100644 02-DECISIONS/0119-a-taken-tunnels-predecessor-is-retired.md diff --git a/02-DECISIONS/0119-a-taken-tunnels-predecessor-is-retired.md b/02-DECISIONS/0119-a-taken-tunnels-predecessor-is-retired.md new file mode 100644 index 0000000..89db5b1 --- /dev/null +++ b/02-DECISIONS/0119-a-taken-tunnels-predecessor-is-retired.md @@ -0,0 +1,78 @@ +--- +topic: the mesh +status: accepted +date: 2026-09-27 +deciders: jochen +reconstructed: false +extends: 0105-the-mesh-adopts-the-predecessors-tunnel-in-place.md +--- + +# 119. A taken tunnel's predecessor is retired once the take is proven + +## Context + +[ADR 0105](0105-the-mesh-adopts-the-predecessors-tunnel-in-place.md) has the private network take +over the tunnel it finds: the found unit stopped and disabled, never flushed, and **its +configuration left on disk, kept like any held file.** That was the right caution for the take +itself — if the mesh's interface failed to come up, the host starts the found unit again and the +peers never notice — and every apply since stops the found unit again should anyone start it. + +What it leaves is a predecessor that never finishes leaving. On every machine that has enrolled, +the tunnel is the mesh's and has been proven so — its interface up with the found key, the peers +handshaking, the machines resolving and reaching each other over it — and still the predecessor's +configuration sits where its unit reads it, held for a module that has long since replaced it. +The predecessor itself is being deprecated. A tunnel that can be started again by one command, with +a configuration nothing maintains any more, is not a rollback path; it is a second way onto the +network that nobody is watching. And the hold never ends, so every node report keeps listing it. + +## Considered Options + +**1. Keep it, as 0105 says.** Rejected: the caution it bought is spent once the take is proven, and +what remains is a live, unmaintained way back onto the network. + +**2. Delete it at the take.** Rejected: the take is exactly the moment the fallback is needed. If +the mesh's interface does not come up, the host must still be able to raise the found one. + +**3. Retire it once the take is proven.** Chosen. + +## Decision + +**Once the mesh's interface has proven it carries the tunnel, the found interface's configuration +is removed from where its unit reads it.** + +- **Proven means:** the tunnel's state is *taken* — the found unit down and disabled, the mesh's + interface up with the found key — and the mesh's interface has completed a handshake with at + least one peer. Not before: until then, a failed take still falls back to the found unit. +- **Retired means:** the configuration file the found unit reads is removed. Its original was + already kept, before anything happened to it + ([ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md)), and stays kept; that copy + is the record of what the predecessor was, and a person's way back if one is ever wanted. +- The found unit stays disabled. Without its configuration it cannot raise the interface, so the + every-apply stop that guarded against it becomes a check that finds nothing to do. +- **The hold ends.** What was held for the private network has been replaced; the node stops + reporting it. +- **The mesh never brings it back.** Undeclaring the private network does not restore the found + tunnel: the mesh stopped it, and nothing is started on the way out + (ADR 0118, in review). A machine whose + private network is unassigned has no tunnel until it is assigned again — which is what + unassigning it means. + +## Consequences + +- On every machine that took a tunnel, the predecessor's tunnel configuration disappears at the + first apply after the take is proven. Nothing a peer sees changes; the mesh's interface already + carries the same key, port, address and peers. +- A take that is never proven — no peer ever handshakes — keeps the found configuration, and the + node says so, so a broken take is visible rather than silently retired. +- Rolling back to the predecessor's tunnel becomes a deliberate act: copy the kept original back + and start its unit. The mesh does neither. +- 0105's "its configuration stays on disk, kept like any held file" holds until the take is proven, + and not after. + +## References + +- [ADR 0105](0105-the-mesh-adopts-the-predecessors-tunnel-in-place.md): the take, and why it keeps + the found configuration during it +- [ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md): kept originals +- ADR 0118 (in review): nothing is started on the way out +- mesh-host `internal/apply/takeover.go` diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index 67eb0fe..fdfdbbf 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -133,6 +133,7 @@ python3 00-META/checks/index.py fail if stale - **0105** — [The mesh adopts the predecessor's tunnel in place](0105-the-mesh-adopts-the-predecessors-tunnel-in-place.md) - **0106** — [The bus is NATS](0106-the-bus-is-nats.md) - **0116** — [The bus is built in five steps, and the protocol moves with it](0116-the-bus-is-built-in-five-steps.md) +- **0119** — [A taken tunnel's predecessor is retired once the take is proven](0119-a-taken-tunnels-predecessor-is-retired.md) ### Its tiers, from the bottom up