--- status: located opened: 2026-09-29 located-in: - mesh-controller internal/catalogue (a converged node's declaration) - mesh-host internal/apply/opening.go fixed-by: amended-design: --- # 143 — Converging a machine does not retire the firewall it found, and says it does ## What was observed The control-node was converged on 2026-09-29, the first machine with a found firewall to be flipped — the two converged before it had none. The preview said, and the flip repeated: ``` the found firewall (ufw) is disabled, never flushed: its configuration stays on disk ... sent: the host loads the mesh's filter and disables the firewall it found ``` The mesh then reported the node `converged`, 372 resources applied, nothing failed. Afterwards, on the machine: ``` systemctl is-enabled ufw -> enabled systemctl is-active ufw -> active ``` And the declaration that was sent carries no resource that would disable it. A converged node's declaration has no adoption block at all, and nothing in its 372 resources names the found firewall. The sentence is printed by the command; no resource implements it. ## Why it matters beyond this instance **It is a stated behaviour that does not happen, reported as success** — the fault this repository exists to catch, and [ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md) states it as part of what the flip *is*: "loads the mesh's derived filter in place of its refusal-only table, and retires the found firewall by disabling it, never by flushing". **It could only be found on the first machine that had one.** The two machines converged before this had no firewall to retire, so the step had never run, and nothing reported that it had not. That is the same shape as [issue 136](../136-a-module-may-name-a-program-the-machine-does-not-have/00-report.md): a step that is silent when it does nothing. **The machine is left doubly filtered, which is not what either firewall describes.** Every base chain at a hook runs and a drop in any is final, so the machine now enforces the *intersection* of the mesh's derived filter and a rule set left by the system being replaced. Nothing is broken by that today — measured from outside, mail, the proxy and git-over-ssh answer and the databases and admin interfaces are refused — but the machine's behaviour is described by neither of the two things claiming to describe it, and the stale set includes a rule for a broker that no longer exists. **And returning the node to adopted would be wrong in the other direction.** ADR 0100 says that restores the found firewall by enabling it again; enabling something that was never disabled is harmless, but the mesh's belief about which firewall is in force has been wrong in both modes. ## Open questions - Which side owns retiring it — a resource in the declaration, so it is applied and reported like everything else, or the flip as an act? A resource seems right: the flip is otherwise entirely expressed as one, and an act that only the command performs cannot be re-checked on a later reconcile. - What should a reconcile do if the found firewall is enabled again by hand, or by a package update? Convergence is a state, so presumably re-disable it and say so. - Should the preview say what it *will* do rather than what it does, until a step exists that does it? The wording was read as evidence twice in one session. - Is there a check that a sentence the mesh prints corresponds to a resource it sends? This is the second time today that a printed claim and a sent declaration disagreed.