dd5be47ef7
Both owned tables were torn down before the replacement was applied, so a failure in between left the host with neither. Host firewall: apply_host_firewall ran `nft delete table` as its own command and only then piped the new ruleset to `nft -f -`. Any failure in that second step - a syntax error, a transient netlink error, the process dying - left the host with no INPUT policy and no allow rules at all. That is fail-open on the host firewall, reached by a single failed command. The code comment even claimed a rejected batch could not take the existing rules down, which stopped being true the moment the delete moved out of the batch. Anti-torrent was worse: delete, then four separate commands to rebuild table, counter, chain and rule. A failure partway through left a half-built table - a table and counter with no chain, or a chain with no rule - which the inspector reports as drift but which provides no protection in the meantime. Both now emit delete and rebuild as a single `nft -f` script. nft applies a script atomically, so a rejected ruleset leaves the previous one exactly as it was. The delete line is only included when the table actually exists, because `delete table` on a missing table aborts the whole transaction - table_exists in nft.rs answers that, treating a not-found error as absent and any other error as a real failure. Rendering the anti-torrent table as a script also collapses four command invocations and their argument-array plumbing into one string, and removes run_step, which had no other user. Four tests: for each table, that the script omits the delete when nothing is there and that delete precedes the rebuild in the same script when it is; plus that the anti-torrent script creates every object the inspector later requires, checked element by element rather than through the listing-format contract matcher. Not changed, deliberately: tc has no equivalent transaction, so the traffic module keeps its rebuild-on-drift model. Losing shaping briefly is not comparable to losing the host firewall. cargo test --workspace: 183 + 4 passed. clippy -D warnings clean.