Поиск с флагом -q прекращает чтение на первом совпадении и закрывает свой конец
канала. Продюсер, которому осталось что писать, получает SIGPIPE и завершается
кодом 141, а `set -o pipefail` делает 141 статусом всей конструкции:
совпадение НАЙДЕНО -> продюсер оборван -> статус 141 -> «не найдено»
Для утвердительных проверок это ложный FAIL. Для отрицательных — «такой
конструкции в коде нет» — ложный PASS: запрещённая конструкция найдена, а гейт
зелёный. Отрицательными проверками закреплена половина инвариантов приёмки,
включая запрет обхода тестов и запрет `pnpm audit --prod`.
Порог резкий: пока вывод продюсера помещается в буфер канала (64 KiB на Linux),
он не блокируется и успевает завершиться раньше, чем потребитель начнёт читать.
Замер, 60 прогонов на размер: до 60 KiB — 0 отказов, ровно на 64 KiB — 58/60,
от 96 KiB — 60/60. То есть проверка выглядит исправной ровно до первого
источника крупнее буфера, а такие файлы в репозитории уже есть.
- 56 мест переведены на here-string: `grep -q PATTERN <<<"$content"`;
- продюсеры-команды (ss|awk, dpkg-query, /proc/cpuinfo, systemctl
list-unit-files) сначала читаются в переменную;
- введён code_has: десять отрицательных сканов держались на `|| true` внутри
code_without_comments, гасившем 141, — то есть на побочном эффекте
подавления ошибок, а не на заявленном свойстве;
- несуществующий путь в скане больше не означает успех: `2>/dev/null || true`
превращал опечатку в пустой вывод, а пустой вывод для проверки «этого в коде
нет» — это PASS. Проверка явная, а не через set -e: в контексте `! code_has`
bash отключает errexit на весь вызов;
- возврат пайплайна запрещён отдельной приёмкой.
HY2XS baseline docs
Этот набор документов фиксирует актуальную baseline-модель HY2XS под следующие ограничения:
- серверный транспорт: ванильная Hysteria2
- UI: HY2XS admin, штатный компонент проекта, поставляется вместе с пакетом
- target OS: только чистый Debian 13
- оркестратор: install-only, только первичная установка и базовая настройка
- стек оркестратора: Bun + TypeScript
- target-side build: запрещён
- standalone update / rollback / uninstall subcommands: вне scope
- сборка и упаковка: отдельный локальный build layer
- post-install state:
/etc/hysteria/post-install.env - установка: только на чистый хост, миграция с 0.x не поддерживается
- контракт версий продукта/платформы/toolchain: корневой
versions.env - клиентский delivery/access layer: вне baseline этого пакета docs
Главная архитектурная схема
В этой редакции зафиксированы два слоя:
-
Builder layer — работает на отдельном Debian 13 amd64 build host. Он собирает итоговый пакет, собирает HY2XS admin, компилирует Bun/TypeScript оркестратор в install-артефакт, упаковывает шаблоны, unit-файлы и примеры конфигов.
-
Runtime / target layer — работает на чистом Debian 13. Здесь нет сборщика. Здесь запускается только итоговый install package / orchestrator, который:
- ставит системные зависимости
- разворачивает встроенный HY2XS admin
- забирает закреплённую в пакете Hysteria2 из официального upstream и сверяет её по SHA-256 и версии
- создаёт конфиги, systemd unit-файлы и
post-install.env - выполняет базовую настройку сервера
Версия Hysteria2 выбирается на builder layer: последняя стабильная разрешается при сборке и замораживается в metadata пакета. Target layer никогда не обращается к moving latest.
Базовые правила
- Hysteria2 не вендорится и не собирается как часть HY2XS.
- HY2XS admin — штатный компонент проекта и поставляется вместе с пакетом.
- Оркестратор пишется на Bun + TypeScript.
- На target нет
npm/pnpm/yarn/bun install/ transpile step. - На target нет standalone логики update / rollback / uninstall.
- В install/reconfigure есть bounded rollback для failure-сценариев firewall/systemd/config/smoke. Rollback опирается на то, что операция реально успела применить: сервисы, которые она не разворачивала, не останавливаются никогда.
- Установка двухфазная: PHASE 0 — read only, PHASE 1 — mutation.
До успешного clean-host preflight на сервере не изменяется ни один
persistent path. У мутирующей фазы ровно один владелец — оркестратор:
install.shпроверяет и передаёт управление, не изменяя ничего сам. Очистка предыдущей установки — отдельная явная операция оператора, см. 14-legacy-cleanup.md. - Выдача доступа пользователям, Telegram-бот, billing, backend профилей и похожие контуры не входят в этот baseline.
Состав документов
- 01-architecture-baseline.md
- 02-build-layer-and-package.md
- 03-server-hysteria2.md
- 04-admin-panel.md
- 05-client-and-access-scope.md
- 06-speed-limits-and-congestion.md
- 07-systemd-and-firewall.md
- 08-orchestrator-spec.md
- 09-post-install-env.md
- 10-access-layer-out-of-scope.md
- 11-testing-and-acceptance.md
- 12-operations-and-troubleshooting.md
- 13-production-runbook.md
- 14-legacy-cleanup.md
История изменений проекта — в CHANGELOG.md.
Жёсткие рамки baseline
Не делаем:
- upgrade manager
- rollback manager
- uninstall
- reconcile engine
- target-side build pipeline
- Docker baseline
- multi-node
- port hopping
- Telegram-бот
- backend выдачи remote profiles
- «умную» миграцию сломанных старых инсталляций
Одной фразой
Правильная baseline-модель теперь такая:
Локальный builder разрешает последнюю стабильную Hysteria2, проверяет её на совместимость с конфигом HY2XS и собирает install package с HY2XS admin и Bun/TypeScript оркестратором; серверный install-only orchestrator ставит этот пакет на чистый Debian 13, скачивает ровно закреплённую Hysteria2, разворачивает HY2XS admin, создаёт systemd + nftables + post-install env и подготавливает рабочее серверное окружение.