Twice in one file, a statement about a machine that read as reasoned and was wrong — and the module's unit tests all passed while the daemon could not start. That is what a unit test is: it confirms the assertion was made, never that it is true of any machine. 003 in prose rather than in a manifest key.
3.2 KiB
status, opened, located-in, fixed-by, amended-design
| status | opened | located-in | fixed-by | amended-design | |
|---|---|---|---|---|---|
| resolved | 2026-08-31 |
|
mesh-control — the resolver module's claims about machines are checked on a machine |
019 — A comment asserting a fact about a machine, which nothing checked
Symptom
The resolver module carried two statements about the machine it runs on. Both read as reasoned, both were in prose beside the setting they justified, and both were wrong:
| it said | the machine said |
|---|---|
127.0.0.54 is free — "not .53, that is systemd-resolved's" |
systemd-resolved holds both; .54 is its proxy stub. dnsmasq could not create the socket and never started |
it takes only 127.0.0.55 |
listening on a loopback address takes the rest of loopback with it, 127.0.0.1 included |
A third statement in the same file was true and incomplete in a way that mattered as much: the
config read /etc/resolv.conf for upstreams without saying so, and the module that points a
machine at the mesh writes this resolver's own address into that file. So its upstream was
itself. Its receive queue filled with 15KB of queries and every lookup on the machine hung.
Why this matters
The module had unit tests, and they all passed. They checked that it names an address, that it reads what the mesh writes, that it restarts when that changes, and that the two asking modules point where it answers. Every one of those was true while the daemon could not start at all.
That is not a gap in those tests. It is what a unit test is: it confirms the assertion was made, never that it is true of any machine. Only a machine knows which of its addresses are spare, or what a daemon does with a file when it starts.
This is 04-ISSUES/003 in prose rather
than in a manifest key. There, five manifests carried a scope: that read as a restriction and
restricted nothing. Here, a comment read as a reasoned choice of address and chose a taken one. In
both cases an unenforced rule is indistinguishable from a wrong one, and costs more, because
people believe it — and a comment is the least enforced rule there is.
It cost three full lab cycles, at fifteen minutes each, because each one revealed exactly one of the three faults.
What was done
The wrong statements are corrected, and the correction says what it now knows rather than
asserting a new comfort. .55 is written down as a convention, not a reservation: if a future
systemd takes it, one line changes. What the module takes is what its claim already said — the
machine's DNS port — rather than a promise about one address.
The unit tests hold what a machine has told us. They assert the module does not take .53,
.54 or 127.0.0.1, and that it does not read resolv.conf for upstreams. A unit test cannot
discover those facts; it can refuse to forget them.
And the order changed. A module that asserts something about machines is proven on a machine before its assertions are believed — the lab test written first, not last. Written here because the cost of the old order is measurable: three cycles, forty-five minutes, for a module whose mesh-side half was correct from the start.