docs: описать транзакционный guard и взаимное исключение операций

- docs/07: полный порядок staged apply, инвариант снятия guard, объяснение
  почему окно 45 секунд не обязано покрывать smoke и почему guard не трогает
  nftables.service, семантическая проверка эффективного firewall;
- docs/11: разделы A5e/A5f для новых unit-тестов и серверные сценарии D1e
  (guard доходит до дедлайна), D1f (конкурентные операции), D1g (успешная
  операция не оставляет следов транзакции); матрица и acceptance criteria
  дополнены;
- docs/12: разбор отказов "уже выполняется другая операция" и
  firewall_guard_fired;
- docs/13: строки журнала guard в таблице recovery, новый раздел 8a про замок
  операций;
- docs/14 и purge-v0.sh: очистка /run/hy2xs, замка операций и candidate-файлов
  firewall — /run это tmpfs, но очистка не имеет права требовать перезагрузки;
- README: защита от потери доступа при смене firewall и раздел "Одна операция
  за раз";
- CHANGELOG: шестой проход.
This commit is contained in:
2026-08-31 01:31:15 +05:00
parent 50ec4d9717
commit 39139e95f7
8 changed files with 532 additions and 11 deletions
+19 -1
View File
@@ -87,6 +87,20 @@ PATHS=(
/usr/local/lib/hy2xs
/usr/local/h-ui
/usr/local/bin/hy2xs-orchestrator
# Артефакты незавершённой операции в /run. Каталог отката хранит прежние
# nftables.conf и hy2xs.nft вместе с маркером срабатывания guard, а замок
# операций способен пережить убитый `kill -9` процесс оркестратора и не даст
# запуститься следующей установке. /run — tmpfs, и перезагрузка убрала бы оба,
# но очистка не имеет права требовать перезагрузки.
/run/hy2xs
/run/lock/hy2xs-orchestrator.lock
)
# Candidate-файлы firewall: остаются на диске, если операция упала между
# проверкой `nft -c` и подстановкой в production-путь.
CANDIDATES=(
/etc/nftables.conf.candidate
/etc/nftables.d/hy2xs.nft.candidate
)
NFT_FRAGMENT=/etc/nftables.d/hy2xs.nft
@@ -119,7 +133,7 @@ show_plan() {
log "будут удалены пути:"
local path
for path in "${UNIT_FILES[@]}" "${PATHS[@]}" "$NFT_FRAGMENT"; do
for path in "${UNIT_FILES[@]}" "${PATHS[@]}" "${CANDIDATES[@]}" "$NFT_FRAGMENT"; do
if [ -e "$path" ]; then
printf ' - %s (существует)\n' "$path"
else
@@ -167,6 +181,10 @@ remove_paths() {
rm -rf "$path"
done
for path in "${CANDIDATES[@]}"; do
rm -f "$path"
done
rm -f /usr/local/bin/hysteria
}