diff --git a/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md b/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md index 82618f1..b940789 100644 --- a/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md +++ b/04-ISSUES/143-converging-does-not-retire-the-firewall-it-found/00-report.md @@ -2,8 +2,8 @@ status: located opened: 2026-09-29 located-in: - - mesh-controller internal/catalogue (a converged node's declaration) - - mesh-host internal/apply/opening.go + - mesh-host internal/apply/opening.go (retireFirewall) + - mesh-host internal/apply/apply.go (the condition it is called under) fixed-by: amended-design: --- @@ -31,9 +31,29 @@ 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. +*Corrected 2026-09-29, an hour later, from reading the host rather than the declaration.* **The first +account of this was wrong.** It said the declaration carries no resource that would disable the found +firewall, and that the sentence was printed by the command with nothing implementing it. The +declaration indeed carries no such resource — but the mechanism was never meant to be one. It is a +step in the host's own apply, `retireFirewall`, and it exists, is careful, and is strict: it refuses to +retire anything until it has read back from the machine that the mesh's own table is loaded, it records +the forward policies first so a half-done retirement can be retried, and it verifies ufw reports +inactive afterwards. + +What is established is narrower and stranger than "nothing implements it": + +- ufw was **active and enabled two minutes after the flip**, and the flip had reported the node + converged with 372 resources applied and nothing failed. +- The machine's own record now reads `disabled_by_mesh: true` — but it was written by a reconcile + *after* an operator disabled ufw by hand, roughly fifty minutes later. A reconcile found ufw already + inactive, asked it to be inactive, read that back, and recorded that the mesh had done it. +- So the step did not take effect at the flip, and the machine's record now says it did. + +The candidates are named rather than chosen, because the evidence does not separate them: the step is +called only when the apply had no failures, and a skipped step is silent; the mesh's table is loaded by +a service in the same apply, so whether it was loaded *at the moment the step asked* is an ordering +question; and the host's own detail lines do not reach the journal, so what it decided is not +recoverable after the fact. ## Why it matters beyond this instance @@ -69,5 +89,14 @@ harmless, but the mesh's belief about which firewall is in force has been wrong 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. +- Is there a check that a sentence the mesh prints corresponds to something that happened? This is the + second time in one session that a printed claim and the machine disagreed. +- **Why did the step not take effect?** It is called only when the apply had no failures, and being + skipped is silent. The mesh's table is loaded by a service in the same apply, so whether it was + loaded when the step asked is an ordering question — and ADR 0100 makes loading it first a + precondition rather than an expectation. +- **A step that records the mesh as having done what an operator did is worse than the omission.** The + record now says the mesh disabled ufw. Nothing distinguishes "we did this" from "we found it already + so". Should it? +- Why do the host's own detail lines not reach the journal? Everything it decided during the flip is + unrecoverable, which is why this account has candidates instead of a cause.