50ec4d9717
Инварианты, добавленные двумя предыдущими коммитами, обязаны жить в сборке, а не в намерении. - скан заглушённых ошибок отката расширен на остановку rollback guard: именно этот диапазон он не покрывал, поэтому `systemctl stop ... || true` прожил дольше всех остальных `|| true` в откате. Заодно покрыт rollbackFirewallNow целиком — правая граница null означает "до конца файла"; - скрипт автоотката проверяется как текст: маркер срабатывания первым действием, отсутствие маскировки, накопление rc, отказ трогать nftables.service; - снятие guard обязано проверять маркер с обеих сторон остановки и подтверждаться ActiveState, а не кодом возврата systemctl; - сработавший guard обязан иметь собственный тип ошибки и собственную причину отказа, и классифицироваться по типу, а не по тексту; - smoke обязан сверять эффективный firewall, а не только разбирать файл, и делать это read-only раннерами: та же проверка выполняется в doctor; - порядок стадий отката firewall проверяется явно: ExecStop у nftables.service делает `nft flush ruleset`, поэтому восстановление состояния сервиса обязано идти до применения ruleset; - политика замка операций: кто берёт, кто не берёт, снятие в finally и по SIGINT/SIGTERM/SIGHUP, безопасное переиспользование замка мёртвого держателя; - формула ключа операции обязана существовать в одном файле.