# Литания перед стартом нового проекта > **Как применять:** положи этот файл в корень нового проекта и дай Claude Code вместе > с первой задачей: «Прочитай prestart-litany.md, определи профиль проекта, разверни > описанную систему триажем под этот проект, затем приступай к задаче: …». > > **Источники:** BAZA.CRM (ERP, 22 модуля, Django+React+Celery, боевой прод), EventPlan > (геометрический SaaS, FastAPI+React), АПЕКС-М (IoT: FastAPI+React+ESP32, боевой VPS) — > плюс аудит всех 17 проектов рабочей папки от 2026-07-26 (Ad-Tycoon, REC dimmer, > мониторинг, HS+auth, лендинги и др. — см. litany-audit-2026-07-26.md). Каждая грабля > в разделе VI оплачена реальным инцидентом — источник указан в скобках. > > **Устройство:** ядро сформулировано стек-нейтрально; конкретика стека — в примерах > *курсивом* и тегах `[Docker]` `[React]` `[Windows]` `[железо]`… Неприменимое к твоему > профилю и стеку отсекается триажем (раздел 0), а не игнорируется молча. > > **Ссылки на литанию — только слагом** (`` `gotcha-…` `` у граблей, названием пункта у > правил), никогда номером: перенумерация родительского документа тихо ломает все > производные правила *(EventPlan: ссылки «V.15», «VI.10» из rules/ и ADR-0004 били в > пустоту уже через 2 часа после финальной правки литании)*. --- ## 0. Развёртывание (порядок строгий) ### 0.1. Профиль проекта — первый вопрос, до триажа | Профиль | Признаки | Примеры | |---|---|---| | **D — документ** | Артефакт = один документ, кода нет | инструкция, руководство | | **S — статика** | Один экран/лендинг, нет БД и пользователей; правит не-программист | лендинг, брендбук | | **A — одиночный артефакт** | Скетч, скрипт, утилита; один файл-проект | генератор, трей-клиент | | **M — продукт без своего прода** | Код, тесты, релизы — но нет своего сервера/БД/денег | игра, расширение, десктоп | | **XL — полное ядро** | Прод, БД, деньги, пользователи, контейнеры, железо в поле | ERP, SaaS, IoT-платформа | Без профилей мелкие проекты выпадают из процесса целиком, а не частично: 6 из 17 проектов папки жили вообще без git, один версионировался зипами `(4)…(8).zip`. ### 0.2. Минимальное ядро — действует ВСЕГДА, даже для D и S 1. **git с первого файла** + `.gitattributes` (`* text=auto eol=lf`) и `.gitignore` — ДО первого `git add`. Никаких копий-папок и зипов как версий. 2. **Секрет-гигиена** — включая документацию, примеры команд и **рабочий каталог**: секреты вне git всё равно попадают в бэкапы диска, скриншоты и контекст агента, получившего доступ к папке *(recovery-коды открытым текстом в корне папки проектов)*. 3. **Опасные действия письменно**; на боевом — только команды, выполняет человек. 4. **Бэкап перед перезаписью боевого файла** (ротация N копий). 5. **Версия и дата на артефакте**: подвал сайта, штамп «версии на момент составления» в доке, `v1.0 · дата` в README. 6. **Плейсхолдеры помечены** (`?`, TODO владельцу) и сверяются перед выкладкой. 7. **Мини-ритуал закрытия**: обновить дату, строка «что сделали», всё отложенное — письменно в момент откладывания. 8. **Развилки — через AskUserQuestion**, очевидные дефолты — принять и озвучить. 9. **Один ADR** даже в S — на 5 строк, но с обязательным «Компромиссом». ### 0.3. Профильные добавки (сверх ядра) - **D:** SoT — исходник (HTML/markdown), PDF — производный артефакт, пересобирается вместе с ним; раздел «версии ПО на момент составления»; нумерация до третьего уровня (чтобы ссылаться на шаг в переписке); визуальные классы опасности (danger/warn/ok) вместо прозы; владелец и дата пересмотра. - **S:** контент отделён от кода **одним файлом** («правишь это, остальное не трогай»); индексация закрыта по умолчанию (`Disallow: /` + noindex), открытие — сознательный акт по чеклисту (robots, аналитика, schema.org, PageSpeed, Вебмастер/Search Console, privacy-policy не заглушка); deny-list «что не выкладывать на прод» (локальный редактор, дизайн-канвас); бюджет веса страницы и картинок; документ передачи не-разработчику (варианты правки по возрастанию сложности, лимиты хостинга). - **A:** один README-витрина: что это · пины/константы **одной таблицей** · как собрать · troubleshooting «симптом → причина»; все физические/средовые константы в одном месте файла; способ проверить **без** железа/боевого стека + одна строка «чего он не проверяет». - **M:** + чистое ядро и детерминизм (II), версионирование локального состояния (I), адаптер платформы (I), CI-матрица ОС (II), профиль публичного релиза (V), роли (IV). - **XL:** литания целиком. ### 0.4. Триаж Для D/S/A — «профиль + список отклонений» ≤10 строк в README. Для M/XL — полный, каждый пункт → **IN / DEFERRED / OUT** с причиной, итог — одним ADR. Формат вердиктов (проверен дважды: EventPlan ADR-0004, АПЕКС ADR-024): | Пункт | Вердикт | Причина / условие | |---|---|---| | … | IN / DEFERRED / OUT | … | + обязательный раздел «Компромиссы — что осознанно потеряли». DEFERRED — только с условием активации («появятся формы → схемная валидация»), не «потом». Осознанный legacy-путь получает зеркальное — **условие снятия** («удалить, когда ни одного устройства с plaintext-токеном»), иначе он вечен. Мёртвое правило убивает доверие ко всем правилам. ### 0.5. Стартовый бриф и вопросы **Вопросы одним заходом** (AskUserQuestion): стек и версии тулчейна, число артефактов версии, есть ли фронтенд / воркеры / прод / железо, ОС разработчика. Бриф проекта пишется по шаблону, проверенному дважды *(HS+auth PROJECT_BRIEF, REC dimmer bootstrap)*: принципы-обязательства → **«Чего НЕ делать»** (явные запреты) → этапы с подтверждением человека → «что нужно на выходе» → финал **«ничего не пиши в файлы, пока не согласуем; вопросы без ответа в документах — задай списком, не делай допущений»**. Полезный парный документ — памятка человеку «как ставить задачу»: шаблон [ЗОНА][ДЕЙСТВИЕ], формат баг-репорта, «чего НЕ указывать — уже в CLAUDE.md» *(АПЕКС how_to_ask.md)*. ### 0.6. Каркас и финал развёртывания Развернуть каркас из разделов I–V по итогам триажа. Финал: показать пользователю Module Map и список созданных правил на ревью → отдельный коммит каркаса → только затем первая боевая задача. ### 0.7. Обратный поток граблей Копия литании в проекте — read-only архив, её не редактируют. Новые грабли проекта пишутся в живой раздел `docs/architecture.md#Грабли проекта` с источником; раз в несколько сессий обобщаемое мигрирует в мастер-литанию *(Самолётики: финал «дописывай в VI» оказался невыполним — копия заморожена, дописывать было некуда)*. Раздел VI — постоянный чеклист на всю жизнь проекта, не одноразовое чтение. Всё общение и документация — на русском. Идентификаторы кода, пути API, хэши и версии не переводить — по ним ищут в коде; жаргон — с оригиналом в скобках при первом упоминании *(BAZA d64605c)*. ## I. Архитектура — принципы, проверенные боем 1. **Модульность:** один модуль/приложение = одна бизнес-область. Cross-module общение — только события или явные сервис-вызовы через абстракции; прямой импорт внутренностей чужого домена запрещён. Каждый новый модуль в момент создания попадает в Module Map (III.1). 2. **Сервисный слой:** контроллер/view/handler = parse → call service → respond, ноль логики. Модель = структура данных. Вся бизнес-логика в сервисах; при росте делить на подмодули СРАЗУ (реэкспорт сохраняет внешний контракт), не ждать god-файла. 3. **Статусы = конечный автомат:** защищённое поле + именованные переходы с source/target/permission + side-effects внутри перехода. Прямое присваивание статуса запрещено — это обход прав, аудита и эффектов. 4. **Аудит-след обязателен:** каждая транзакция создаёт запись в журнале через **единую точку применения эффекта**. Мутация в обход журнала — критическая ошибка. Контракт логирования — таблицей «событие → что логировать» с именованным логгером, иначе «аудит обязателен» выполняется на глаз *(BAZA CLAUDE.md)*. 5. **Soft delete** для доменов с документами/деньгами, двухуровневый: документы/деньги = `is_active + deleted_at`; справочники = только `is_active`. Физический delete запрещён; связи на audit-модели — PROTECT. 6. **Деньги = Decimal** (12,2) или целые минорные единицы. Float рядом с money-полями — блокирующая ошибка. Общий принцип: **число без объявленной единицы — баг, ждущий повода**; единицы измерения и система координат — часть контракта, объявляются письменно один раз *(EventPlan: «единицы — миллиметры», СК от самой длинной стены)*. Есть стандартный формат обмена для домена (GeoJSON, iCal, ISO-коды) — брать его, не изобретать: бесплатные валидаторы и общий язык со всеми слоями. 7. **Миграции схемы append-only:** существующие не редактировать; каждая data-миграция обратима; большие таблицы — expand → backfill → contract. Механика раннера (glob vs реестр, порядок применения, идемпотентность) — в README рядом с миграциями, иначе каждая сессия изобретает своё *(АПЕКС)*. У грабли «дрейф миграций» записан не только запрет, но и рецепт восстановления *(BAZA: 5 шагов через MigrationLoader)*. 8. **Внешние вызовы:** только асинхронно (очередь), идемпотентные ключи, retry с backoff, верификация вебхуков, audit-лог каждого вызова. Внешняя платформа/SDK (маркетплейс, магазин, игровая площадка, платёжка) — за адаптером с **двумя реализациями: боевой и Local-заглушкой**; вход в приложение — в try/catch с фолбэком; требования модерации — чеклистом ДО релиза *(Ad-Tycoon: PlatformAdapter, «вечный чёрный экран» без фолбэка)*. Недоступные из твоей инфраструктуры внешние сервисы — письменно списком, иначе агент раз за разом предлагает нерабочее *(АПЕКС: Telegram на RU-VPS, protomaps)*. 9. **Парные операции симметричны с рождения:** если есть create-эффект — в том же коммите пишется cancel-эффект и ТЕСТ на пару (`gotcha-pair-asymmetry`). 10. **Без хардкода — в меру.** Значение, которое может измениться, повториться или зависеть от окружения/клиента — в константу/конфиг/env/данные. Самоочевидные единичные значения не выносить. **Доменные параметры** — редактируемые данные (сид + переопределение на сущность), не константы; вычислительное ядро принимает их параметром и остаётся чистым *(EventPlan ADR-0003)*. То же — **матрица прав и фиче-флаги**: данные в БД, редактируемые без релиза *(BAZA)*. Параметры, зависящие от экземпляра (калибровки, коэффициенты per-device/per-tenant) — хранятся при экземпляре, не в коде `[железо]` *(АПЕКС: NVS, калибровка минимум в 3 точках)*. Настроечная константа (таймаут, батч, буфер) — с единицей, формулой следствия и направлением компромисса, иначе следующая сессия крутит её вслепую *(VOX: DMA-буферы «4 мс; меньше → щелчки; больше → латентность»)*. 11. **Contract First для многослойных контрактов.** Контракт, потребляемый несколькими артефактами — таблица слоёв в CLAUDE.md, изменение обновляет ВСЕ слои одним коммитом. Wire-протокол версионируется отдельно от приложений — два разных SoT, с письменной матрицей «что бампает протокол» (optional-поле → minor, required/ переименование → major, багфикс payload не бампает) *(АПЕКС versioning.md)*. **Порядок выката — часть контракта:** сервер раньше клиента, новые поля optional (expand→contract для провода). Совместимость — **декларация клиента** (`api_version_min` в манифесте, клиент сам блокируется), а не блокировка сервером: отклонение данных по версии создаёт слепые зоны ровно у проблемных клиентов *(АПЕКС ADR-016)*. Агент, меняющий контракт, обязан спросить: «нужно ли обновить остальные слои?» Удалил поле из контракта — докажи grep'ом, что его никто не читает *(АПЕКС: orphan-читатели top-level `version`)*. 12. **Docker-first** (если проект контейнерный): ничего не запускается на хосте; базовый compose + явные именованные override-файлы; healthchecks на всех сервисах; non-root; секреты только env. Осознанное отклонение — строка в реестре долгов «принято осознанно» + **явный запрет альтернативной команды** («никогда `docker compose build frontend`») — запрет важнее правила: именно его агент нарушит по инерции *(АПЕКС)*. 13. **Fail-safe: неопределённое состояние = безопасное.** Заглушки нереализованных модулей отказывают в безопасную сторону (недописанный чек прав — запрещает, недописанный лимит — блокирует, фича-флаг по умолчанию выключен); где отказ физически опасен — второй барьер вне кода `[железо]` *(REC dimmer: аппаратная подтяжка — ресет/прошивка/Hi-Z = ключи закрыты без участия кода)*. **Деградация вместо отключения**, и «плохие данные» ≠ «нет данных»: политики разные, обе спроектированы явно; **нет данных — не гадать** *(REC dimmer: отказ датчика → вентилятор на максимум, лимиты НЕ применяются)*. Отсутствие показателя ≠ ноль: прочерк, а не 0 *(tray-monitor; мониторинг: `absent()` — отдельный алерт)*. Fail-open/fail-closed выбирается **на каждую точку отдельно, по длительности окна риска** *(АПЕКС ADR-017: HTTP fail-open — окно один запрос; WS fail-closed — канал жил бы часами)*; код ошибки, который UI трактует как команду, не получает второго, инфраструктурного смысла. Отказ канала связи ≠ отказ узла — различие моделируется в протоколе, эскалация зависит от того, что известно *(АПЕКС ADR-011)*. 14. **Персистентное состояние вне транзакционной БД** (сейв, localStorage, NVS, файл конфига, кэш) — та же дисциплина, что схема БД: `version` + контрольная сумма + **атомарная запись** (temp + rename; два слота пинг-понгом на flash) + миграция при загрузке + roundtrip-тест; битое состояние не роняет приложение — старт с чистого / дефолтов с указанием места поломки *(REC dimmer EEPROM-блоб; мониторинг mktemp+mv; tray-monitor; Ad-Tycoon: `// TODO: restore staff` — купленное исчезало)*. 15. **Права — на уровне выборки, не UI:** выдача фильтруется по пользователю в самом запросе (IDOR), permission-классы объявлены явно на каждом эндпоинте *(BAZA)*. Пагинация на всех list-эндпоинтах, явный ordering (недетерминированный порядок ломает пагинацию), запрет N+1. 16. **Retention фиксируется раньше механизма:** для каждой таблицы, растущей от активности (телеметрия, логи, события, аудит) — «сколько храним» решено письменно, компенсирующий контроль (индекс, мониторинг объёма) — сразу *(АПЕКС ADR-019)*. Класс данных, запрещённый к отправке во внешние сервисы **включая облачные AI**, — объявлен письменно ДО первой интеграции *(АПЕКС: 152-ФЗ → только локальная модель)*. 17. **Один назначенный писатель** — там, где блокировать нельзя (ISR, UI-поток, горячий путь): ресурс пишет ровно один владелец, обмен через двойной буфер/очередь; это парный паттерн к «блокировка на счётчиках» (`gotcha-increment-race`) *(REC dimmer: CCR пишет только ISR TIM6)*. Эксклюзивный ресурс (COM-порт, файл-лок, сокет) освобождается явно до передачи следующему; поток без фреймов — дренаж запоздалых ответов и фильтрация незапрошенного `[железо]` *(АПЕКС release process)*. 18. **Не создавай второй канал доставки для того, без чего не работает первый:** конфиг, ключ, сертификат, схема — если их доставка идёт другим путём, чем код, отказ доставки убивает возможность починки *(АПЕКС ADR-022: CA вшиты в прошивку — битая отдельная партиция значила бы мёртвый TLS = мёртвый OTA = физическая перепрошивка)*. 19. **Файлы:** бинарники не в БД — хранится путь; превью асинхронно; статику/медиа отдаёт прокси мимо приложения, приватное — через X-Accel-Redirect/аналог *(BAZA)*. Каждый подписчик события — с уникальным идентификатором подписки (dispatch_uid): двойное подключение = двойные эффекты, почти не диагностируется *(BAZA)*. 20. **Автономный/демо/offline-режим — как обычный источник данных, а не ветка `if` во всём тракте:** подделывается вход, не тракт *(REC dimmer: STATIC-кадр — обычный валидный сигнал для FSM, пайплайн без спецслучаев)*. ## II. Код и гейты 1. **Гейты с ПЕРВОГО коммита:** форматтер + импорт-сорт + линтер + типы в pre-commit и CI. Для нового кода — 0 warnings сразу; для унаследованного долга — **рэтчет** warn→error с зафиксированным потолком и планом, не разовая зачистка *(BAZA ADR-051)*. Гейты двух уровней: **hard блокирует, soft предупреждает** *(АПЕКС)*. Поведение при провале — письменно: остановиться, показать упавший гейт + полный stderr, не чинить молча; обход по команде — `NOTE: committed with failing ` в тело коммита. Обоснованный пропуск гейта — с условием возврата («тесты — план 0.8.0»), иначе «нулевая терпимость» обходится тихо. Неиспользуемая disable-директива = ошибка. Ложное срабатывание любого сканера гасится **самым узким скоупом** (allow по пути), не глобальным игнором класса правила *(BAZA trivy)*. Локальный гейт и CI — один инструмент одной версии. Форматтеры не трогают append-only артефакты (глобальный exclude на миграции — правило нарушает автоформат, а не человек) *(BAZA 2026-07-21)*. *Инструменты по стеку: Python — black/isort/ruff/mypy; TS — eslint + `tsc -b --noEmit`.* 2. **Правило, проверяемое машиной — хук, а не абзац.** Каждый инвариант литании, выразимый регуляркой/AST, дублируется PreToolUse-хуком в момент формулировки — иначе живёт до первой спешки *(BAZA: 12 блокирующих — float у денег, физический delete, правка миграции, секреты, DEBUG в prod…)*. Блокирующие и напоминающие хуки — два разных класса; Stop-хук — для напоминаний о ритуалах. Обязательные спутники хука: список исключений (migrations/, node_modules/, собственные литералы паттернов), тесты на сам хук, быстрый путь выхода (оверхед на каждый tool call). Покрытие хука проверяется по **всем шеллам**, которыми реально пользуется агент (`gotcha-hook-shell-blind`). 3. **Каждый слой каркаса проверяй сразу, не в конце:** после каждого слоя — прогон гейтов. Ошибки ловятся дёшево у источника *(EventPlan)*. 4. **Тулчейн и системные зависимости проверяй фактически ДО написания конфигов:** запусти и убедись, не предполагай. Версии пинуй; что тянет либа — в ADR/Dockerfile в момент выбора *(EventPlan: corepack pnpm; Shapely→GEOS, weasyprint→pango)*. 5. **Типы обязательны** на всех функциях. **Функции ≤40 строк** без явного обоснования. 6. **Тесты зеркалят структуру**, фабрики, AAA. Тест = полная жизненная цепочка, не изолированный вызов. Каждый багфикс приносит тест. Интеграционные — на реальной БД, мок только для внешних сервисов. Фича, меняющая контракт, обновляет свои тесты в том же коммите (`gotcha-feature-test-debt`). Для вычислительного ядра цепочка — не то: там **инварианты алгоритма в docstring** как контракт + property-based тесты, автор инварианта и автор теста — разные агенты *(EventPlan: hypothesis)*. Цифра покрытия — только с конфигурацией замера («69% с greenlet, без него фиктивные 56%»); расхождение тестовой и прод-СУБД — задокументированное ограничение, не умолчание *(АПЕКС)*. 7. **Тесты wiring — отдельный класс от тестов логики.** Юнит-тест, импортирующий объект напрямую, не проверяет, что система его находит: любая регистрация «по конвенции» (задачи, сигналы, плагины, роуты) требует теста «всё, на что ссылается конфиг, реально зарегистрировано» (`gotcha-silent-unregistered`). **Orphan-check:** публичная функция ядра без единого вызывающего — баг интеграции или мёртвый код (`gotcha-green-modules-dead-system`). Конфиг-поле без потребителя — ложь в диффе; конфиг валидируется при старте (fail fast), единицы измерения совпадают с кодом *(Ad-Tycoon: в конфиге 2, в коде хардкод 0.02 — расхождение в 100 раз)*. 8. **Тест без боевой среды — спроектирован, не случаен.** Ядро не импортирует ни строчки среды исполнения И ни строчки вендорского SDK — это две разные оси изоляции, обе проверяются **сборкой** (второй target «на хосте»), а не дисциплиной *(REC dimmer: core/ не видит hal/; АПЕКС ADR-021: изоляция окупается тестируемостью даже без миграции; VOX: dsp.h собирается на ПК)*. Внутри ядра запрещены Date.now() / Math.random(): часы и seeded RNG инжектируются — детерминизм = воспроизводимые тесты *(Ad-Tycoon)*. Матрица средств тестирования — с честным «чего НЕ покрывает ни один» *(VOX: Wokwi vs WAV-стенд)*. Мок-режим — полноценный режим приложения со сценарием по расписанию, включая негативные состояния *(tray-monitor: три сервера со сдвинутыми фазами, один намеренно без датчика)*. Симулятор внешней системы — первоклассный артефакт со своими правилами: те же схемы, что у прод-кода (не копипаст полей), seed, префикс SIM_/флаг is_simulated, assert «не прод» *(АПЕКС)*. Для доменов с накопительной динамикой — headless-прогон N шагов ботом с проверкой, что метрики двигаются *(Ad-Tycoon: «7 дней, seed 42» показал экономический тупик)*. Смоук-сценарий на то, что уже ломалось — для слоёв, не берущихся юнит-тестами (GUI, трей, жизненный цикл процесса) *(tray-monitor)*. 9. **Фоновые задачи** (если есть очередь): никакой бизнес-логики в таске — таска вызывает сервис; queue, time_limit, retry с backoff, идемпотентность; передавать id, не объекты. 10. **Фронтенд** (если есть): strict-типизация без `any`; единый api-клиент (auth + refresh + interceptor в одном месте); server state отдельно от клиентского *(у нас react-query + zustand)*; формы со схемной валидацией *(RHF + zod)*; дизайн-система классов вместо inline-стилей; error boundary на каждый маршрут **с key**; скачивание защищённых файлов — только через api-клиент (blob); единый паттерн деталей сущностей. **Строки UI — в один ресурс с первого дня**, даже в одноязычном проекте: ретрофит i18n дороже в разы, а правки текстов не должны требовать правки кода *(Ad-Tycoon: файл есть, UI захардкожен — местами показывались ключи)*. **Бюджеты числами** (размер сборки, TTI, запросы) — проверяются при добавлении тяжёлого, не «когда станет медленно». 11. **CI — это не только гейты:** CI слушает **рабочую** ветку — сменил ветвенную модель → в тот же коммит триггеры CI/хуков (`gotcha-ci-wrong-branch`); для кроссплатформенного артефакта — матрица `ubuntu + windows` (автоматически ловит всю группу Windows-граблей); CI **собирает** релизный артефакт (ловит зависимость от файла вне git); гейт «чистый клон собирается и стартует»; supply-chain в базовом наборе (audit зависимостей, скан образа, встроенный `check --deploy` фреймворка — бесплатный гейт, который никто не включает); coverage-порог *(BAZA)*. Свой CI-раннер не селить рядом с боевыми сервисами — 1600 тестов = OOM соседям *(BAZA)*. Прод-образ намеренно без dev-тулинга; ожидаемое «падение pytest на проде» — задокументированная фича, не поломка *(BAZA)*. 12. **Лицензионный гейт:** политика лицензий стороннего кода письменно (для закрытого продукта — только пермиссивные); новый компонент — сначала строка в THIRD_PARTY_LICENSES.md, потом в сборку *(REC dimmer)*. ## III. Бумажная работа (карта + документация + версии) Развернуть с первого дня — «потом» не наступает (`gotcha-docs-drift`). 1. **Карта навигации:** Module Map в CLAUDE.md (строка на модуль: путь — назначение — ключевые сущности) + navigation-док (дерево каталогов; таблица сущностей — генерируется grep'ом, не по памяти; «задача → где искать»). Список крупных файлов — не как список, а как **порог (параметр) + команда генерации + дата сверки + автопроверка в обе стороны** («перерос, но не в списке» и «в списке, но похудел») *(АПЕКС check-integrity)*. Правило контекст-экономии первым пунктом workflow; большие файлы — поиск → чтение диапазона; правило передавать субагентам. 2. **Документация — один индекс и один гейт.** Два независимых дерева = двойная цена синхронизации *(BAZA проходила)*. Артефакт, потребляемый кодом (changelog в UI, схема в сборке), законно живёт в коде — но обязан быть в таблице маршрутизации ритуала закрытия. Формат — под проект и потребителя, выбор зафиксировать. **Документация проходит гейт как код**: strict-сборка доков (битые ссылки, файлы вне nav) — дерево без гейта гниёт по ссылкам быстрее, чем по содержанию *(АПЕКС: mkdocs --strict)*. Состав дерева: index, architecture, api-reference, decisions (ADR), versioning, onboarding, runbook (+production-runbook при проде), по-модульные доки; штамп «Обновлено: дата | версия». **Runbook — в формате «Симптом → Диагностика → Фикс»**, не описание системы *(×4 проекта независимо)*. Второй потребитель — человек вне разработки (сборщик, заказчик): его версия **генерируется** из основной, не пишется дважды *(VOX: md→html конвертер «открыть двойным щелчком»)*. README = витрина: версия + badge, таблица модулей (число = факт!), старт. 3. **ADR:** нетривиальное решение (≥2 реальных альтернатив) → Контекст / Альтернативы / Решение / Причины / **Компромисс** (обязателен). Существующие ADR не редактируются. «Почему не X» — рядом с решением, особенно где ошибка необратима *(Pulse generator: таблица отвергнутых MOSFET с причинами)*. Ключ связывания систем — решение с **организационным следствием**, и оно пишется в Компромисс *(HS+auth: маппинг по email ⇒ «почты сотрудников нельзя переиспользовать» — правило для отдела кадров)*. 4. **Ритуал закрытия сессии** (скилл с триггер-фразой): «закрываем сессию» → дифф сессии (`git log` + `git status`) → свести затронутые зоны (модуль → дока + карта; процесс → правило; решение → ADR; бамп → changelog; закрытый долг → реестр) → отдельный `docs(sync)`-коммит. **Если сводить нечего — сказать это явно, не молчать** (иначе ритуал незаметно отмирает) *(АПЕКС)*. Канонические имена/URL при сведении сверяются grep'ом с кодом — SoT имени всегда код *(BAZA: `/healthz` числился `/api/health/` в пяти доках)*. После docs-сессии — короткий список реально исполняемых изменений *(АПЕКС post-rules-refactor)*. Штамп ≠ гарантия актуальности. 5. **Статусы в планах — по факту кода, в обе стороны.** Фантомные хвосты: пункт числится открытым, а код давно есть — перед реализацией «незакрытого» сверка с кодом *(BAZA: 2 из 4 хвостов)*. Сводки и индексы правятся **атомарно** с деталью. **Реестр «Критические долги» — в НАЧАЛЕ roadmap** (не в подвале): приоритет, слой, условие закрытия; закрытие — двухфазно: коммит-фикс, затем коммит-пометка с точным SHA первого (смешивать нельзя — SHA фикса ещё не существует в момент правки таблицы) *(АПЕКС)*. Чек-лист `[x]` — только если формулировка однозначно совпадает с диффом; буллеты закрытых релизов — неизменяемая история. **План фазы — в репозитории, не в памяти агента**, с блоком «Ключевые решения (не пере-решать)» со ссылками на ADR — прививка от пере-обсуждения решённого *(АПЕКС 0.7.0-execution-plan)*. Опционально — HTML-дашборд прогресса с блоком DATA, собираемым из git, обновляется в ритуале закрытия *(Dashboard/BAZA)*. 6. **Версии:** SemVer; письменно объявленный SoT-файл на каждый артефакт; версия **наблюдаема на самом артефакте** (health-эндпоинт, UI «Что нового», экран About устройства). MAJOR.MINOR синхронны только для платформенной пары; прошивки/утилиты/ протокол — независимы; при >2 артефактах — **матрица совместимости в changelog минорного релиза** *(АПЕКС)*. Канал релиза (dev/beta/rc) — pre-release suffix SemVer, не отдельная колонка: парсер сам сравнит `0.1.0-debug.1 < 0.1.0-rc.1 < 0.1.0`; префикс артефакта — только в UI/тегах, не в коде *(АПЕКС)*. Changelog — только заметное пользователю, не коммит-лог; запись в changelog обязательна — без неё бамп запрещён. Бамп ТОЛЬКО по явной команде; ритуал «готовимся к бампу»: git log с прошлого бампа → атомарные сценарии ручной проверки, **сгенерированные по диффу, не по памяти** (файл чеклиста в .gitignore) → прогон по одному через AskUserQuestion (на ✗ — стоп) → полный тест-прогон → два зелёных дают право бампать. Сокращённый гейт для PATCH рассматривался и письменно отвергнут — «рождаются вторые патчи в тот же день» *(BAZA ADR-068)*. Тег ставится локально; **push тега — отдельное «да», каждый раз** *(АПЕКС)*. ## IV. Организация работы с Claude 1. **Модель ветвления объявляется письменно в ADR** — trunk-based или dev/master, по числу людей и наличию ревью, а не по привычке *(АПЕКС живёт trunk-based, ADR-024; BAZA — dev/master)*. Для dev/master: master = стабильный прод, merge только бампом; режим стабилизации — dev держится потоком фиксов, фичи во временных `feature/*`, постоянную третью ветку не заводить *(BAZA ADR-068)*. 2. **Делегирование:** нетривиальное — субагентам с явным именованием; main loop оставляет себе git, гейты, ревью диффов, интеграцию. **Нижняя граница:** правку 1–3 строк не делегировать — оверхед дороже. **Нет подходящего агента — остановиться и спросить, не выдумывать.** Определения агентов модель-нейтральны: модель и effort — во frontmatter, в прозе имён моделей нет (протухают за недели) *(АПЕКС ea13116; контрпример — «Opus 4.8» в CLAUDE.md EventPlan)*. Дорогой агент-архитектор вызывается по письменному списку **обязательных** триггеров — и только по ним. Субагенты не порождают субагентов: лиды возвращают план делегирования текстом, исполнителей запускает main loop. Три проверенных архетипа — субагент как **бюджет контекста**: reviewer-хранитель пронумерованных инвариантов («не переписывай сам»; «чем грозит»), test-runner на дешёвой модели («только вердикт и текст упавших»), doc-scout («файл:строка + цитата, не пересказывай») *(REC dimmer)*. Шкала оркестрации по размеру: роли в одном файле → именованные субагенты → генерируемая студия. Независимых — параллельно, одним сообщением. Субагентам передавать правило контекст-экономии и запрет на commit/push. 3. **Опасные команды** — список письменно в CLAUDE.md с первого дня: rm -rf, reset --hard, down -v, DROP, force-push, `git clean -f`, `git checkout --` с потерей правок, `docker system prune`, `volume rm`, `dd`, `mkfs`, `pkill -9`, erase-flash, любые действия на прод. Выполнение — только после письменного подтверждения, одно «да» = один вызов. **Текст без хука — декларация:** список дублируется блокирующим хуком, покрытие хука — по всем шеллам (II.2). Письменно же — известные escape-вектора ask-gate: `cd x && git push`, `sh -c`, `eval`, pipe через `xargs` — договорённость не использовать, распространена на субагентов *(BAZA)*. Опасны они не только потерей данных, но и потерей **улик**: сначала понять причину, потом чистить *(АПЕКС runbook)*. 4. **Не переспрашивай и не угадывай:** решение с очевидным дефолтом — прими, озвучь, двигайся. Развилку, меняющую архитектуру/данные/UX — AskUserQuestion **до** кода. Несколько вопросов — одним заходом. 5. **TodoWrite** на всё многошаговое; планы — в `docs/plans/`, не в корне. Двухфазность: фикс отдельным коммитом, roadmap/доки — отдельным (причину см. III.5). 6. **Бюджет CLAUDE.md:** там только то, что нужно КАЖДУЮ сессию — постоянная статья расхода контекста. Ритуалы — **скиллы** с триггер-фразами; правила — файлы с `globs` по зонам кода (грузятся по файлу) *(оба боевых проекта пришли независимо: АПЕКС 279→149 строк, BAZA rules→skills)*. `.claudeignore` на шумные каталоги — с обратным правилом: ничто, на что ссылаются правила или память, не скрыто (указатели в невидимое) *(АПЕКС)*. Гигиена памяти: индекс обязателен (нет в MEMORY.md = невидимо при recall), лимит размера (большой файл = документ, в docs/), память ≠ хранилище документов. **У метаданных проекта — свой прогоняемый чек** (битые ссылки CLAUDE.md, захардкоженные счётчики, таблица крупных файлов, покрытие хуков): их дрейф не роняет ни один тест *(АПЕКС check-integrity.ps1)*. Одна точка входа для агента, инструменто-нейтральная: смена инструмента = миграция содержимого, чужие каталоги удаляются тем же коммитом (`gotcha-two-agent-configs`). 7. **Систематически нарушаемое правило — дефект системы, а не людей.** Гайд не покрывает реальную потребность — расширь систему и задокументируй, а не копи исключения *(BAZA: один класс кнопки закрыл годы техдолга)*. Осознанное исключение пишется **в самом правиле** — с границей применимости *(BAZA viewsets-only)*. Заморозка направления фиксируется в правиле явно («i18n ЗАМОРОЖЕН: … не трогать»), иначе очередная сессия «доводит до ума» замороженный слой *(BAZA)*. Правило, невыполнимое по построению («не портировать вручную» между двумя деревьями одного кода) — сигнал менять структуру, не дисциплину: одномоментный перенос, старое read-only *(АПЕКС ADR-020)*. 8. **Гигиена сессии:** следить за автокомпактом — ссылки на docs/ позволяют перечитать первоисточник после сжатия контекста; сессия ушла не туда — дешевле поправить CLAUDE.md и начать новую, чем выправлять *(REC dimmer)*. Конфиги быстро меняющихся сторонних сервисов — по актуальной официальной документации, не по памяти модели; версии сверяются ДО генерации конфигов (`gotcha-llm-stale-configs`). 9. **Протокол отладки** (именованный ритуал с триггер-фразой): снаружи внутрь (UI → сеть → бэкенд → БД); **не чинить первую найденную причину** — проверить, нет ли слоёв под ней; подтвердить фикс фактически до объявления победы; пойманное — в memory/грабли *(BAZA tyranid-hunt)*. ## V. Прод, эксплуатация, наблюдаемость 1. **Боевые серверы — только команды, никакого «я сделаю сам».** На прод/VPS агент не выполняет НИЧЕГО самостоятельно. Он выдаёт готовые команды блоком, выполняет человек. Одно письменное подтверждение = одно действие; «да» из прошлого раза не переносится. *(АПЕКС)* 2. **Деплой-чеклист письменно и всегда целиком:** build ВСЕХ артефактов («изменения не появились» = собрал не всё — артефактов деплоя больше одного, перечисли ВСЕ и способ сборки каждого, `gotcha-partial-build`) → перезапуск ВСЕХ производных контейнеров → прокси → статусы → логи воркеров → smoke-тест. Частичные варианты — **флаги одного скрипта** (`--backend`/`--frontend`), не отдельные инструкции *(АПЕКС)*. 3. **Деплой — один канонический скрипт с проверками внутри** *(BAZA deploy.sh)*: отказ при грязном дереве/чужой ветке; список пересоздаваемых сервисов **вычисляется из compose**, не хардкодится (новый воркер попадает в деплой сам); бэкап — при непустом плане миграций; ожидание healthy по inspect с таймаутом, не «на глаз»; smoke = версия из health-эндпоинта, не 200 OK; при провале health-gate скрипт **печатает точную команду отката**. **Точка отката для проекта с миграциями — пара (коммит, дамп)**, образа `:prev` недостаточно: откат кода через миграционный рубеж без отката БД падает на отсутствующих колонках. Rollback — отдельный парный скрипт: подтверждение словом, страховочный дамп текущего состояния ДО восстановления, `--code-ref`, финальная сверка схемы с кодом *(BAZA rollback.sh)*. Фронт-статика: новая сборка рядом (`dist_new`) → атомарный swap, старая = точка отката *(АПЕКС)*. 4. **Секрет-гигиена, три слоя раздельно: код / состояние / секреты.** `.env` в `.gitignore`, `.env.example` с плейсхолдерами и маркерами `[SECRET] → менеджер`; шифрованные секреты (SOPS+age) коммитятся намеренно, ключ вне репо; учётки внешних SaaS — в парольном менеджере, не в `.env` *(HS+auth)*. Клиентские секреты — платформенный механизм (DPAPI/keychain) + письменно «от чего это НЕ защищает» *(tray-monitor)*. **Секрет в URL = секрет в access-логе и Referer** — маскирование в логах приложения + `access_log off` на эндпоинте *(АПЕКС: JWT в query WS)*. Предупреждать о риске ДО команды, которая выведет секрет в терминал/историю. Утечка = ротация в ту же сессию *(BAZA: PAT)*. 5. **Канонические пути и имена — письменно в момент создания:** путь на сервере, имена контейнеров, бакетов *(АПЕКС: /opt/signe/ vs «угаданный» /opt/signe-server/)*. Плюс **реестр занятого**: порты/адреса/имена проверяются на конфликт с соседями, включая вендорские дефолты *(REC dimmer: дефолтный IP ноды = дефолт диммера; Grafana 3001 из-за forgejo)*. Порядок старта зависимостей (VPN раньше docker) — либо в юните (`After=`), либо задокументирован как штатный симптом *(мониторинг)*. 6. **Наблюдаемость** (при проде — обязательна): **внешний наблюдатель** — всё, что запущено на самом сервере, не видит отказ самого сервера *(АПЕКС)*. Health-эндпоинт как liveness («200 degraded») → мониторинг по ключевому слову `"status":"ok"`, не по коду ответа; публичный health не утекает текст исключений. **Dead man's switch на всю периодику** (бэкап, отчёты, синк): «должно было запуститься и не запустилось» — отдельный класс отказов, cron сам о себе не сообщит; сигналы «упал» / «успех устарел» / «успехов не было ни разу» / «метрики вообще нет» слепы по отдельности — нужны все *(мониторинг: BackupNeverSucceeded не видит BackupTooOld)*; ping только на успех, grace с запасом, таймзона сверяется, не предполагается. Структурированные логи + сквозной request_id — с первого дня, задним числом невозможно *(АПЕКС)*. Пороги живут на сервере; клиент отображает решения, не принимает их; цвета клиента = правила стека («жёлтая цифра значит то же, что жёлтая иконка») *(tray-monitor)*. Healthcheck проверяет живой процесс, а не прокси-артефакт (файл/лог/таймстамп); устранив причину — пройди по проверкам, которые на неё опирались (`gotcha-proxy-healthcheck`). Предохранители в скриптах: опасная конфигурация не стартует, обход — только явным флагом с говорящим именем (`ALLOW_PUBLIC_UNAUTHENTICATED=1`) и перечислением того, что утечёт *(мониторинг)*. 7. **Бэкап не существует, пока не проверено восстановление.** Дамп — вне тома с данными; проверка целостности (`--verify`); retention письменно (daily/weekly/ monthly); **один SoT расписания** (`gotcha-double-cron`); процедура restore написана; **поимённый список критических артефактов с ценой пропуска каждого** *(HS+auth: noise.private_key — иначе перерегистрация всех узлов)*. Проверка на **bootstrap paradox**: пройди по зависимостям процедуры восстановления — нет ли тех, что сами восстанавливаются этой процедурой *(HS+auth: бэкап на NAS, доступном через ту же mesh-сеть; REC dimmer: «сбить IP с панели → починить с панели» — пункт приёмки)*. Внешнее хранилище/LFS считается рабочим только после скачивания объекта с чистой машины *(Ad-Tycoon: LFS отдавал 404, 31 файл утерян безвозвратно)*. 8. **Приёмка и необратимость.** Приёмочный чек-лист — парный артефакт спеки, и он **диктует наблюдаемость**: сначала «как проверяем», из этого — какую диагностику обязан отдавать продукт (счётчики, uptime, версия на самом устройстве) *(REC dimmer)*. **Ворота этапа:** неизвестность закрывается ДО необратимых/дорогих работ; условные этапы не проектируются заранее; фазовый гейт — измеримый пользовательский результат с правом остановить продукт («загрузил → план ≤3 мин против 2 ч; нет „вау“ → пересматриваем») *(EventPlan roadmap)*; ценность раньше «умной» части — ML/распознавание после подтверждения тупого варианта. Отказные сценарии обновления — часть приёмки: битый файл → отказ по CRC, питание в момент записи → грузится старое; «что деградирует во время обновления» записано *(REC dimmer)*. В пайплайне с необратимыми шагами guard выполняется **до первого необратимого** *(АПЕКС: compat-check до записи identity)*. Запас по предельным параметрам вместо защиты, когда отказ необратим («полевик умрёт раньше любой защиты»). Критерий приёмки чисто-архитектурного рефакторинга — **байт-идентичный наблюдаемый выход** до/после, иначе это не рефакторинг *(АПЕКС ADR-021)*. Debug-функциональность физически отсутствует в релизном артефакте (`#ifdef`/сборка), а не «выключена настройкой»: debug-роуты, mock-режимы, фейковый логин *(АПЕКС)*. 9. **Профиль «публичный релиз»** — отдельный от своего прода: как только артефакт уходит в чужой магазин/Marketplace/публичный домен — LICENSE + поле в манифесте, README-витрина со скриншотами, CHANGELOG, иконка, локализация пользовательских доков (внутренние — на одном языке, и это записано), чеклист модерации ДО релиза *(claude-office-dashboard)*. 10. **Межпроектные контракты:** значения, которые один проект ВЫДАЁТ, а другой ПОТРЕБЛЯЕТ — таблицей с явным эмитентом и потребителем, «совпадают байт в байт», включая trailing slash и порт *(HS+auth: OIDC)*. Перечислить ВСЕ пары «кто → кому ходит»: браузер ≠ контейнер, оба должны достучаться — поломки живут в паре, о которой не подумали. **Общий эталон проверяется первым** при «не работает»: земля для сигналов, NTP для токенов (clock skew валит exp/iat), кодировка для текста, таймзона для дат — и записывается в предусловия *(Pulse generator + HS+auth, независимо)*. `[железо]` Однократные ручные предусловия среды («выпаять флеш», modprobe модуля, драйвер) — письменный чек-лист, не проза. Комплект артефактов железного проекта: pinout · схема подключения · BOM · порядок сборки · приёмка (три проекта пришли независимо); **SoT по «ногам» — документ**, в коде ровно один заголовок (pins.h), его отражающий; при противоречии прав документ *(REC dimmer)*. ## VI. Литания против граблей > Каждая — реальный инцидент; чти их, дабы не повторить. Теги — к какому стеку/профилю > применима; при триаже неприменимые группы отсекай целиком. Ссылайся слагом, не номером. ### Контейнеры и деплой `[Docker]` 1. `gotcha-migration-drift` **Дрейф миграций** `[+Django]`. makemigrations в контейнере без bind-mount → файл живёт в слое образа, БД помнит, git нет; rebuild — файл исчез. Потеряно 18 файлов. → makemigrations ТОЛЬКО через dev-override с bind-mount; после — `git status`; CI-гейт «чистый migrate с нуля». Рецепт восстановления — записан (I.7). *(BAZA)* 2. `gotcha-stale-workers` **Воркеры на старом образе** `[+очередь]`. `up -d app` не трогает worker/beat/asgi — очередь выполняет старый код, симптомов не даёт. → деплой-чеклист V.2 целиком; список сервисов вычисляется из compose. *(BAZA)* 3. `gotcha-proxy-cache` **Прокси кэширует upstream.** После пересборки — 502 или старый фронт. → лечить причину конфигом: `resolver 127.0.0.11 valid=10s` + переменные upstream в каждом location — после этого рестарт nginx не нужен; ритуал рестарта — подстраховка, знай, что он маскирует незакрытую причину. *(BAZA, вылечено 3ae5995)* 4. `gotcha-partial-build` **Артефактов деплоя больше одного.** Пересборка бэкенда не деплоит фронт (в контейнере он или нет — неважно); «изменения не появились» — почти всегда это. → перечисли ВСЕ артефакты и способ сборки каждого. *(BAZA, АПЕКС)* 5. `gotcha-pidfile` **Pidfile в контейнере.** `docker restart` сохраняет ФС → осиротевший pidfile → вечный рестарт, периодика молча стоит. → pidfile в one-process-контейнере не нужен никогда. Парная: healthcheck, проверявший pidfile, стал вечно-ложным после лечения — устранив причину, пройди по проверкам, которые на неё опирались (`gotcha-proxy-healthcheck`). *(BAZA)* 6. `gotcha-interval-schedule` **Интервальные расписания сбрасываются рестартом** планировщика → суточная задача «каждые 24ч» не срабатывает никогда. → crontab-выражения для суточных/еженедельных. *(BAZA)* 7. `gotcha-silent-unregistered` **Расписание ≠ реестр** `[+очередь]`. Задача, не попавшая в реестр воркера (autodiscover не видит подпакет), отбрасывается МОЛЧА — beat шлёт, воркер отвечает «unregistered», симптом — тишина. Юнит-тесты, импортирующие задачу напрямую, бага не видят. → тест «расписание ⊆ реестр» + проверка в деплой-скрипте; у планировщика нет громкого режима отказа — создай его. *(BAZA, прод)* 8. `gotcha-dev-prod-settings` **Dev-стек на prod-настройках.** Забытый override → prod-whitelist хостов → 400 на локальном домене. → явные именованные override-файлы и одна задокументированная команда запуска dev-стека. *(BAZA)* 9. `gotcha-exec-bit` **Права/окружение контейнера ≠ хоста** `[+Windows]`. Скрипт без +x, том с чужим uid → Permission denied. → скрипты звать через `sh <путь>`; явные права томов; проверка после первого up. *(BAZA)* 10. `gotcha-rootowned-bindmount` **Bind-mount на несуществующий путь** — docker создаст каталог от root, задача не от root писать не сможет. → создавать каталоги заранее в скрипте. *(мониторинг)* 11. `gotcha-docker-bypasses-ufw` **Границу доступа определяет bind-адрес, не фаервол.** Docker пишет правила в nat в ОБХОД ufw — `ufw deny 9090` порт не закроет. → bind на tailnet/localhost; публичный bind — осознанное решение. *(мониторинг)* 12. `gotcha-container-oom` **Контейнерный лимит памяти без внутреннего лимита процесса** → OOM-kill вместо деградации. → лимит процесса ниже лимита контейнера. *(АПЕКС)* 13. `gotcha-env-special-chars` **Спецсимволы `#$!%&` в пароле** ломают парсер .env/compose → контейнер в вечном Restarting. *(АПЕКС)* 14. `gotcha-compose-env-drift` **Дефолты в compose разошлись с .env.example** → стек поднимается с другими именами БД/юзера. → один источник дефолтов. *(АПЕКС)* ### Данные и логика 15. `gotcha-journal-bypass` **Мутация в обход журнала.** Ручное списание меняло остаток напрямую — журнал слеп, аудит дыряв. → ЕДИНАЯ точка применения эффекта, все пути через неё. *(BAZA)* 16. `gotcha-pair-asymmetry` **Асимметрия парных операций.** Создание покрывало 2 метода оплаты, отмена — 1: проводка-сирота, отчёт врал. → create+cancel парой, тест на цикл create→cancel→след чист. *(BAZA)* 17. `gotcha-increment-race` **Гонки на инкрементах.** Два параллельных движения читают один остаток → lost update. → блокировка (select_for_update) внутри транзакции на любых счётчиках с первого дня + конкурентный тест. Где лочить нельзя (ISR, UI) — один назначенный писатель (I.17). *(BAZA)* 18. `gotcha-placeholder-data` **Плейсхолдер, притворяющийся данными.** Черновые значения без пометки уезжают как «проверенные». → помечать (`?`, TODO владельцу); гейт перед прод — плейсхолдеров не осталось. *(EventPlan)* 19. `gotcha-number-null` **Number(null) === 0** `[React/формы]`. Трансформ на маунте: null FK → 0 → «выбрана» несуществующая запись. → null-безопасные setValueAs. *(BAZA)* 20. `gotcha-green-modules-dead-system` **Модули зелёные — система мертва.** 74 честных юнит-теста, архитектура по гайдлайнам — а ключевая функция ядра не вызывается нигде, автосейва не существует (ноль вызовов), софтлок за 12 минут. → orphan-check «кто вызывает» по каждой публичной функции ядра; интеграционный тест полного цикла; для накопительных доменов — headless-прогон N шагов с проверкой, что метрики двигаются. *(Ad-Tycoon, независимое ревью)* 21. `gotcha-orphan-config` **Конфиг-поле без потребителя.** Поля загружаются, валидируются — и никем не читаются; рядом код с хардкодом, расходящимся с конфигом в 100 раз. → вынес в конфиг = есть потребитель и тест, что читается именно оно; валидация при старте; единицы сходятся. *(Ad-Tycoon)* 22. `gotcha-gitignored-dependency` **Зависимость от артефакта вне git.** Детект платформы завязан на плагин из каталога в .gitignore — работает только на машине разработки, в чистом клоне и CI ломается молча. → гейт «чистый клон собирается и стартует». *(Ad-Tycoon)* ### Версии и контракты 23. `gotcha-version-sot` **Несколько «источников истины» версии.** pyproject vs настройки vs package.json расползаются. → SoT-файлы письменно, остальное не считается. *(BAZA)* 24. `gotcha-version-symmetry` **Автовыравнивание версий «для симметрии».** PATCH независим — ровнять = фейковые релизы. → бамп только изменившегося. *(BAZA)* 25. `gotcha-lexicographic-semver` **Лексикографическое сравнение версий.** `"0.10.0" < "0.9.0"` строками — стреляет в OTA, когда MINOR доходит до 10. → сравнение только semver-парсером. И вторая линия: **guard от даунгрейда на стороне клиента** — `strcmp(...)!=0` означало «ставлю всё, что отличается»; серверная монотонность фида — единая точка отказа, способная забрикать флот одной ошибочной публикацией; намеренный откат — «старый код под более высокой версией». *(АПЕКС, ADR-023)* 26. `gotcha-feature-test-debt` **Тестовый долг фичи.** Фича изменила ответ эндпоинта, тесты не тронули — красный набор всплыл через неделю у чужой сессии. → тесты контракта в том же коммите, полный прогон перед push. *(BAZA)* 27. `gotcha-tsc-no-b` **`tsc` без `-b` не проверяет project references** `[TS]`. Локально зелёный, сборка на сервере падает. → `tsc -b --noEmit` при composite/references. *(АПЕКС)* ### Windows и кодировки `[Windows]` 28. `gotcha-gitattributes` **Переносы строк без `.gitattributes`.** autocrlf → LF↔CRLF-дрейф, в Linux-контейнере ломаются скрипты с CRLF. → `* text=auto eol=lf` с ПЕРВОГО коммита. *(EventPlan: 80+ предупреждений)* 29. `gotcha-non-ascii-toolchain` **Не-ASCII там, где системная кодировка.** Три канала: (а) файлы, которые парсит тулчейн — только ASCII *(АПЕКС: PlatformIO упал на кириллице в partitions_apex.csv — cp1251)*; (б) **stdout вспомогательных скриптов** на Windows — cp1251, `UnicodeEncodeError` на любом спецсимволе → `PYTHONIOENCODING=utf-8` или ASCII-вывод *(воспроизведено дважды при аудите)*; (в) **stdin хуков** читать как UTF-8 байты явно — иначе кириллица-мохито *(office-dashboard 2c047ee)*. 30. `gotcha-windows-bindmount` **Windows bind-mount врёт.** Задержка синхронизации → контейнер видит старый файл. → docker cp или --no-cache при сборке фронта. *(BAZA)* 31. `gotcha-case-insensitive-headers` **`HTTPClient.h` vs `HttpClient.h`** — две библиотеки, различающиеся регистром имени, конфликтуют на регистронезависимой ФС. *(АПЕКС)* ### Инфраструктура `[инфра/прод]` 32. `gotcha-shared-proxy` **Общий реверс-прокси: глобальные объекты и Host.** Одноимённые `map`/`upstream` → «duplicate map»; proxy_pass по IP без `Host $host` → 400 от whitelist. → имена глобальных объектов уникальны per-vhost; Host всегда. *(BAZA)* 33. `gotcha-fail2ban-self` **Авто-защиты банят свою автоматизацию.** fail2ban целевой системы банит настройщика после 2 SSH-коннектов (ssh-copy-id = 2 = бан). → свой IP в доверенные ДО работ. *(BAZA: NAS)* 34. `gotcha-pipefail` **Пайп без `set -o pipefail`** → код возврата от последней команды: упавший pg_dump + живой gzip = пустой архив и «успех». Зелёный статус над битым дампом хуже отсутствия бэкапа. *(мониторинг)* 35. `gotcha-tls-bare-ip` **Запрос по голому IP при сертификате на домен** провалит TLS-проверку — в инструкциях и конфигах всегда домен. *(АПЕКС)* 36. `gotcha-crypto-defaults` **Дефолты криптоутилит небезопасны.** htpasswd по умолчанию bcrypt cost 5 (32 раунда) — задавать стоимость явно (`-C 12`). *(мониторинг)* 37. `gotcha-https-redirect-proxy` **HTTPS-редирект за SSL-прокси хостинга** = бесконечный редирект: `RewriteCond %{HTTPS} off` не видит прокси. → редиректы — средствами панели/прокси; за прокси о схеме судят по `X-Forwarded-Proto`. *(лендинг; родня `gotcha-shared-proxy` — за прокси реальность не та, что видит приложение)* 38. `gotcha-robots-secret` **Секретный путь в robots.txt.** Строка `Disallow` сама выдаёт путь любому, кто откроет robots. → секретные пути не упоминать нигде публично. *(лендинг)* 39. `gotcha-double-cron` **Два механизма расписания** (`/etc/cron.d/*` и `crontab -e`) → задача дважды за ночь. → SoT расписания — один файл, создаётся setup-скриптом. *(АПЕКС)* 40. `gotcha-nginx-details` **Мелочи nginx:** `expires` + `add_header Cache-Control` вместе = дублирующийся заголовок; на Debian пользователь `www-data`, не `nginx`. *(АПЕКС)* ### Процесс 41. `gotcha-docs-drift` **Документация отстаёт молча.** Месяц без сведения = 35 файлов лжи и день работы 10 субагентов. → ритуал закрытия сессии (III.4), каждый раз. *(BAZA)* 42. `gotcha-god-files` **God-файлы съедают контекст и дисциплину.** serializers на 940 строк, страница на 1290. → делить при росте, карта крупных файлов с автопроверкой (III.1), точечное чтение. *(BAZA)* 43. `gotcha-phantom-tails` **Фантомные хвосты плана.** «Незакрытые» пункты roadmap давно сделаны — сессия готова повторить работу. → статусы по факту кода, сверка перед реализацией (III.5). *(BAZA: 2 из 4)* 44. `gotcha-silent-later` **Молчаливое «потом».** Каждое «потом допишем» без записи исчезает. → всё отложенное — письменно (план, ADR-компромисс, реестр долгов, memory) в момент откладывания. *(BAZA)* 45. `gotcha-ci-wrong-branch` **CI слушает не ту ветку.** Workflows на master, работа месяц шла в dev — гейты тихо перестали существовать. → сменил ветвенную модель → в тот же коммит триггеры CI/хуков/автоматики. *(BAZA d9804c2)* 46. `gotcha-hook-shell-blind` **Хук слеп к реальному шеллу.** Matcher `Bash`, работа идёт в PowerShell — защита существует и не работает. → покрытие хука по всем шеллам, проверяется скриптом целостности. *(АПЕКС)* 47. `gotcha-renumbered-parent` **Перенумерация родительского документа** тихо ломает все производные ссылки. → ссылаться слагом; при реструктуризации — прогнать ссылки в производных. *(EventPlan: ссылки на литанию били в пустоту через 2 часа)* 48. `gotcha-two-agent-configs` **Две конфигурации агента.** Проект вёлся двумя инструментами, конфигурация дважды мигрировала и рассинхронизировалась. → одна инструменто-нейтральная точка входа; чужие каталоги удаляются тем же коммитом. *(Ad-Tycoon ADR-010)* 49. `gotcha-automated-prompt` **Системные инъекции неотличимы от пользователя.** Автоуведомление фоновой задачи пришло как «промпт пользователя» и снимало экстренную остановку. → механика, реагирующая на «пользователь написал», обязана фильтровать автоматику. *(office-dashboard v0.13.2)* 50. `gotcha-llm-stale-configs` **Конфиги по памяти модели.** Синтаксис быстро меняющихся сервисов, выдуманный по памяти, не совпадает с текущей версией *(HS+auth: Authentik 2026.x убрал Redis)*. → сверка с актуальной официальной докой; версии пинуются и записываются ДО генерации. 51. `gotcha-modal-drag-close` **Модалка закрывается при drag-выделении текста** `[React]` (mouseup ловится на бэкдропе). → закрытие по клику, начатому и завершённому на бэкдропе. *(АПЕКС)* 52. `gotcha-404-swallows-detail` **Глобальный 404-хендлер глотает содержательные `detail` роутеров.** → хендлер пропускает существующий detail. *(АПЕКС)* --- **Финал:** литания прочитана, профиль определён, триаж проведён, каркас развёрнут и отревьюен — можно начинать. Новые грабли проекта — в живой раздел `docs/architecture.md#Грабли проекта` (копия литании read-only), обобщаемое — периодически в мастер-литанию: она живёт, пока её кормят инцидентами.