diff --git a/04-ISSUES/111-the-resolver-is-told-names-the-mesh-serves-not-only-machines/00-report.md b/04-ISSUES/111-the-resolver-is-told-names-the-mesh-serves-not-only-machines/00-report.md new file mode 100644 index 0000000..0adfa36 --- /dev/null +++ b/04-ISSUES/111-the-resolver-is-told-names-the-mesh-serves-not-only-machines/00-report.md @@ -0,0 +1,52 @@ +--- +status: resolved +opened: 2026-09-24 +located-in: [mesh-controller cmd/mesh-controller/plan.go, mesh-controller internal/catalogue/facts.go] +fixed-by: mesh-controller — tell the resolver the machines, not the names the mesh merely serves +amended-design: +--- + +# 111 — The resolver is told every name the mesh serves, not only the machines + +## What was observed + +Composing the resolver's first assignment on the control-node, 2026-09-24, and reading the plan +before pushing it. The file the mesh would have handed the resolver: + +``` +local=/internal/ +address=/.internal/ +address=/.internal/ +address=/.internal/ +``` + +Two of the three are not machines. They are names the mesh was **told to serve** — a module's public +name, resolved mesh-wide so that a container reaching it finds the proxy serving it +([ADR 0066](../../02-DECISIONS/0066-public-routing-is-name-agnostic.md)) — with the +mesh's own suffix appended to each, producing a name nobody will ever ask for. + +The control plane hands a resolution one map of names, and it holds both kinds. A container's hosts +file wants all of it. The resolver's zones want only the machines, and the difference matters +because of the line above them: told that the mesh's suffix is its own, the resolver answers +authoritatively for everything under it and forwards none of it. So the invented names sit beside +the real ones looking exactly as real, and a fourth is absent — +[issue 112](../112-adopting-a-tunnel-gives-the-mesh-addresses-without-names/00-report.md). + +Nothing was pushed. The module was unassigned and the machine left as it was. + +## Why it matters beyond this instance + +The two sets are not the same and the mesh had one word for both. Every fact the mesh computes about +"the names" now has to say which it means, and the one that leaks is the one that is authoritative: +a resolver that answers for a name it invented cannot be asked again. + +It is also a near miss of the kind worth writing down. The conversion was reviewed, its own tests +passed, and the fault was invisible in them because they were written with a map of machines — the +shape the composer's own comment assumed. It appeared the first time the composer met a live mesh +that also serves routed names, and only because the plan was read before it was pushed. + +## What it is now + +The control plane carries the two sets separately — every name it serves, and the machines — and +each fact is handed the one it is true of. The hosts file keeps every name; the resolver's zones take +the machines. A test pins both halves together, so neither can drift into the other again. diff --git a/04-ISSUES/112-adopting-a-tunnel-gives-the-mesh-addresses-without-names/00-report.md b/04-ISSUES/112-adopting-a-tunnel-gives-the-mesh-addresses-without-names/00-report.md new file mode 100644 index 0000000..92285c4 --- /dev/null +++ b/04-ISSUES/112-adopting-a-tunnel-gives-the-mesh-addresses-without-names/00-report.md @@ -0,0 +1,51 @@ +--- +status: open +opened: 2026-09-24 +located-in: [] +fixed-by: +amended-design: +--- + +# 112 — Adopting a tunnel gives the mesh the peers' addresses but not their names + +## What was observed + +On the control-node, 2026-09-24, reading what the resolver would answer before it was assigned. + +The predecessor's resolver answers for **four** machines — the hub and the three that reach it over +the tunnel. The mesh's would have answered for **one**: itself. The other three are *carried peers* +of the tunnel the hub took over +([ADR 0105](../../02-DECISIONS/0105-the-mesh-adopts-the-predecessors-tunnel-in-place.md)) — the mesh +holds an address for each, and keeps it, and has no name for any of them, because a name comes from +enrolling and they have not enrolled. + +Taking the resolver in that state replaces a file that resolves four machines with one that resolves +one, and — because the resolver is told the mesh's suffix is its own and forwards nothing under it — +the other three stop resolving rather than falling through. Everything on the machine that reaches +another by name breaks at once: the predecessor's own agents, its pipeline, anything an operator +typed. + +## Why it matters beyond this instance + +Adoption was designed so that what the mesh does not know yet, it leaves alone. The tunnel is the +first place the mesh takes over something whose *content is knowledge the predecessor has* — three +machines exist, and these are their names — and it takes the addresses without the names. Nothing +says so; the mesh reads as complete. + +This is an ordering rule the migration did not have: **a name the predecessor answers for must keep +resolving until the machine behind it is a node.** It applies to the resolver first and to anything +else derived from "the machines the mesh knows" while the mesh knows fewer than the machine does. + +## Open questions + +- Should a carried peer be nameable — the operator saying which machine a carried address is, before + it enrols — so the resolver can answer for it in the meantime? The mesh would be recording a name + it cannot verify. +- Or should the resolver simply not be taken until every carried peer has enrolled, stated as a + refusal rather than a note in a runbook? +- Or should the mesh's resolver, while any peer is carried, forward the suffix it cannot answer to + the resolver it replaced — which is the adapter shape + ([ADR 0104](../../02-DECISIONS/0104-a-provision-may-be-answered-by-an-adapter-to-the-predecessor.md)) + applied to names instead of routes? +- What checks it? Nothing compares what the predecessor's resolver answers with what the mesh's + would.