Issues 111 and 112: the resolver was told the wrong set of names, twice over #98
+52
@@ -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=/<a routed name>.internal/<the hub>
|
||||
address=/<the node>.internal/<the hub>
|
||||
address=/<another routed name>.internal/<the hub>
|
||||
```
|
||||
|
||||
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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user