fix(build): гейт классификации reconfigure описывал прежнюю архитектуру

Проверка требовала литеральное `classifyReconfigureFailure(ownership)`, тогда
как у функции давно два параметра. Второй появился вместе с типизированным
распознаванием сработавшего guard: по владению он неотличим от обычного отказа
smoke — тронут firewall, перезапущены сервисы, — но чинить надо другое, потому
что сервер уже вернулся на ПРЕЖНИЙ firewall.

То есть гейт утверждал не тот контракт, который назван в его же заголовке, и
падал на коде, который этот контракт соблюдает. Поведенческие тесты при этом
были и остаются зелёными: «текст ошибки на классификацию не влияет» и
«сработавший guard опознаётся по типу ошибки».

Проверка приведена к фактической форме, заголовок — к фактической архитектуре.
`error instanceof FirewallGuardFiredError` намеренно не дублируется: тот же
инвариант проверяется ниже, в «a fired guard forbids the durable commit», и для
install, и для reconfigure.

Заодно прогнаны ВСЕ гейты приёмки по текущему дереву, а не только упавший:
116 положительных литеральных проверок, 36 bun-блоков с текстовыми
инвариантами и все отрицательные сканы. Кроме этого одного — расхождений нет.
This commit is contained in:
2026-09-01 04:56:33 +05:00
parent d32811b804
commit a1f0db22c2
+17 -3
View File
@@ -1282,11 +1282,25 @@ run_single_owner_acceptance() {
}
' || fail "acceptance: production-запись обязана объявлять владельца файла"
log_step "Acceptance: reconfigure classifies by ownership, not by message text"
log_step "Acceptance: reconfigure classifies by ownership and typed guard state, not by message text"
# Обычные операционные отказы классифицируются по ВЛАДЕНИЮ. Исключение ровно
# одно, и оно типизированное: сработавший guard по владению неотличим от
# обычного отказа smoke — тронут firewall, перезапущены сервисы, — но чинить
# надо другое, потому что сервер уже вернулся на ПРЕЖНИЙ firewall. Поэтому он
# опознаётся по типу ошибки и никогда по её тексту.
#
# Гейт требовал литеральное `classifyReconfigureFailure(ownership)` и потому
# утверждал не тот контракт, который назван в его же заголовке: второй
# параметр появился вместе с типизированным распознаванием guard, и с этого
# момента проверка описывала предыдущую версию архитектуры.
#
# `error instanceof FirewallGuardFiredError` здесь намеренно НЕ дублируется:
# тот же инвариант проверяется ниже, в «a fired guard forbids the durable
# commit», и для install, и для reconfigure. Один инвариант — один гейт.
! grep -qF '.test(message)' orchestrator/src/commands/reconfigure.ts \
|| fail "acceptance: reconfigure must not classify failures by matching the error text"
grep -q 'classifyReconfigureFailure(ownership)' orchestrator/src/commands/reconfigure.ts \
|| fail "acceptance: reconfigure failure classification must be ownership-driven"
grep -q 'classifyReconfigureFailure(ownership, error)' orchestrator/src/commands/reconfigure.ts \
|| fail "acceptance: reconfigure failure classification must use ownership and the typed operation error"
}
# Каналы утечки секретов: Config API и журналы.