Прежняя git-история утрачена при переносе проекта на машину владельца (снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной истории. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 KiB
Литания перед стартом нового проекта
Как применять: положи этот файл в корень нового проекта и дай 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
- git с первого файла +
.gitattributes(* text=auto eol=lf) и.gitignore— ДО первогоgit add. Никаких копий-папок и зипов как версий. - Секрет-гигиена — включая документацию, примеры команд и рабочий каталог: секреты вне git всё равно попадают в бэкапы диска, скриншоты и контекст агента, получившего доступ к папке (recovery-коды открытым текстом в корне папки проектов).
- Опасные действия письменно; на боевом — только команды, выполняет человек.
- Бэкап перед перезаписью боевого файла (ротация N копий).
- Версия и дата на артефакте: подвал сайта, штамп «версии на момент составления»
в доке,
v1.0 · датав README. - Плейсхолдеры помечены (
?, TODO владельцу) и сверяются перед выкладкой. - Мини-ритуал закрытия: обновить дату, строка «что сделали», всё отложенное — письменно в момент откладывания.
- Развилки — через AskUserQuestion, очевидные дефолты — принять и озвучить.
- Один 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. Архитектура — принципы, проверенные боем
- Модульность: один модуль/приложение = одна бизнес-область. Cross-module общение — только события или явные сервис-вызовы через абстракции; прямой импорт внутренностей чужого домена запрещён. Каждый новый модуль в момент создания попадает в Module Map (III.1).
- Сервисный слой: контроллер/view/handler = parse → call service → respond, ноль логики. Модель = структура данных. Вся бизнес-логика в сервисах; при росте делить на подмодули СРАЗУ (реэкспорт сохраняет внешний контракт), не ждать god-файла.
- Статусы = конечный автомат: защищённое поле + именованные переходы с source/target/permission + side-effects внутри перехода. Прямое присваивание статуса запрещено — это обход прав, аудита и эффектов.
- Аудит-след обязателен: каждая транзакция создаёт запись в журнале через единую точку применения эффекта. Мутация в обход журнала — критическая ошибка. Контракт логирования — таблицей «событие → что логировать» с именованным логгером, иначе «аудит обязателен» выполняется на глаз (BAZA CLAUDE.md).
- Soft delete для доменов с документами/деньгами, двухуровневый: документы/деньги =
is_active + deleted_at; справочники = толькоis_active. Физический delete запрещён; связи на audit-модели — PROTECT. - Деньги = Decimal (12,2) или целые минорные единицы. Float рядом с money-полями — блокирующая ошибка. Общий принцип: число без объявленной единицы — баг, ждущий повода; единицы измерения и система координат — часть контракта, объявляются письменно один раз (EventPlan: «единицы — миллиметры», СК от самой длинной стены). Есть стандартный формат обмена для домена (GeoJSON, iCal, ISO-коды) — брать его, не изобретать: бесплатные валидаторы и общий язык со всеми слоями.
- Миграции схемы append-only: существующие не редактировать; каждая data-миграция обратима; большие таблицы — expand → backfill → contract. Механика раннера (glob vs реестр, порядок применения, идемпотентность) — в README рядом с миграциями, иначе каждая сессия изобретает своё (АПЕКС). У грабли «дрейф миграций» записан не только запрет, но и рецепт восстановления (BAZA: 5 шагов через MigrationLoader).
- Внешние вызовы: только асинхронно (очередь), идемпотентные ключи, retry с backoff, верификация вебхуков, audit-лог каждого вызова. Внешняя платформа/SDK (маркетплейс, магазин, игровая площадка, платёжка) — за адаптером с двумя реализациями: боевой и Local-заглушкой; вход в приложение — в try/catch с фолбэком; требования модерации — чеклистом ДО релиза (Ad-Tycoon: PlatformAdapter, «вечный чёрный экран» без фолбэка). Недоступные из твоей инфраструктуры внешние сервисы — письменно списком, иначе агент раз за разом предлагает нерабочее (АПЕКС: Telegram на RU-VPS, protomaps).
- Парные операции симметричны с рождения: если есть create-эффект — в том же
коммите пишется cancel-эффект и ТЕСТ на пару (
gotcha-pair-asymmetry). - Без хардкода — в меру. Значение, которое может измениться, повториться или
зависеть от окружения/клиента — в константу/конфиг/env/данные. Самоочевидные
единичные значения не выносить. Доменные параметры — редактируемые данные
(сид + переопределение на сущность), не константы; вычислительное ядро принимает их
параметром и остаётся чистым (EventPlan ADR-0003). То же — матрица прав и
фиче-флаги: данные в БД, редактируемые без релиза (BAZA). Параметры, зависящие
от экземпляра (калибровки, коэффициенты per-device/per-tenant) — хранятся при
экземпляре, не в коде
[железо](АПЕКС: NVS, калибровка минимум в 3 точках). Настроечная константа (таймаут, батч, буфер) — с единицей, формулой следствия и направлением компромисса, иначе следующая сессия крутит её вслепую (VOX: DMA-буферы «4 мс; меньше → щелчки; больше → латентность»). - Contract First для многослойных контрактов. Контракт, потребляемый несколькими
артефактами — таблица слоёв в CLAUDE.md, изменение обновляет ВСЕ слои одним
коммитом. Wire-протокол версионируется отдельно от приложений — два разных SoT,
с письменной матрицей «что бампает протокол» (optional-поле → minor, required/
переименование → major, багфикс payload не бампает) (АПЕКС versioning.md).
Порядок выката — часть контракта: сервер раньше клиента, новые поля optional
(expand→contract для провода). Совместимость — декларация клиента
(
api_version_minв манифесте, клиент сам блокируется), а не блокировка сервером: отклонение данных по версии создаёт слепые зоны ровно у проблемных клиентов (АПЕКС ADR-016). Агент, меняющий контракт, обязан спросить: «нужно ли обновить остальные слои?» Удалил поле из контракта — докажи grep'ом, что его никто не читает (АПЕКС: orphan-читатели top-levelversion). - Docker-first (если проект контейнерный): ничего не запускается на хосте; базовый
compose + явные именованные override-файлы; healthchecks на всех сервисах; non-root;
секреты только env. Осознанное отклонение — строка в реестре долгов «принято
осознанно» + явный запрет альтернативной команды («никогда
docker compose build frontend») — запрет важнее правила: именно его агент нарушит по инерции (АПЕКС). - 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). - Персистентное состояние вне транзакционной БД (сейв, localStorage, NVS, файл
конфига, кэш) — та же дисциплина, что схема БД:
version+ контрольная сумма + атомарная запись (temp + rename; два слота пинг-понгом на flash) + миграция при загрузке + roundtrip-тест; битое состояние не роняет приложение — старт с чистого / дефолтов с указанием места поломки (REC dimmer EEPROM-блоб; мониторинг mktemp+mv; tray-monitor; Ad-Tycoon:// TODO: restore staff— купленное исчезало). - Права — на уровне выборки, не UI: выдача фильтруется по пользователю в самом запросе (IDOR), permission-классы объявлены явно на каждом эндпоинте (BAZA). Пагинация на всех list-эндпоинтах, явный ordering (недетерминированный порядок ломает пагинацию), запрет N+1.
- Retention фиксируется раньше механизма: для каждой таблицы, растущей от активности (телеметрия, логи, события, аудит) — «сколько храним» решено письменно, компенсирующий контроль (индекс, мониторинг объёма) — сразу (АПЕКС ADR-019). Класс данных, запрещённый к отправке во внешние сервисы включая облачные AI, — объявлен письменно ДО первой интеграции (АПЕКС: 152-ФЗ → только локальная модель).
- Один назначенный писатель — там, где блокировать нельзя (ISR, UI-поток, горячий
путь): ресурс пишет ровно один владелец, обмен через двойной буфер/очередь; это
парный паттерн к «блокировка на счётчиках» (
gotcha-increment-race) (REC dimmer: CCR пишет только ISR TIM6). Эксклюзивный ресурс (COM-порт, файл-лок, сокет) освобождается явно до передачи следующему; поток без фреймов — дренаж запоздалых ответов и фильтрация незапрошенного[железо](АПЕКС release process). - Не создавай второй канал доставки для того, без чего не работает первый: конфиг, ключ, сертификат, схема — если их доставка идёт другим путём, чем код, отказ доставки убивает возможность починки (АПЕКС ADR-022: CA вшиты в прошивку — битая отдельная партиция значила бы мёртвый TLS = мёртвый OTA = физическая перепрошивка).
- Файлы: бинарники не в БД — хранится путь; превью асинхронно; статику/медиа отдаёт прокси мимо приложения, приватное — через X-Accel-Redirect/аналог (BAZA). Каждый подписчик события — с уникальным идентификатором подписки (dispatch_uid): двойное подключение = двойные эффекты, почти не диагностируется (BAZA).
- Автономный/демо/offline-режим — как обычный источник данных, а не ветка
ifво всём тракте: подделывается вход, не тракт (REC dimmer: STATIC-кадр — обычный валидный сигнал для FSM, пайплайн без спецслучаев).
II. Код и гейты
- Гейты с ПЕРВОГО коммита: форматтер + импорт-сорт + линтер + типы в pre-commit и
CI. Для нового кода — 0 warnings сразу; для унаследованного долга — рэтчет
warn→error с зафиксированным потолком и планом, не разовая зачистка (BAZA ADR-051).
Гейты двух уровней: hard блокирует, soft предупреждает (АПЕКС). Поведение при
провале — письменно: остановиться, показать упавший гейт + полный stderr, не чинить
молча; обход по команде —
NOTE: committed with failing <gate>в тело коммита. Обоснованный пропуск гейта — с условием возврата («тесты — план 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. - Правило, проверяемое машиной — хук, а не абзац. Каждый инвариант литании,
выразимый регуляркой/AST, дублируется PreToolUse-хуком в момент формулировки —
иначе живёт до первой спешки (BAZA: 12 блокирующих — float у денег, физический
delete, правка миграции, секреты, DEBUG в prod…). Блокирующие и напоминающие хуки —
два разных класса; Stop-хук — для напоминаний о ритуалах. Обязательные спутники
хука: список исключений (migrations/, node_modules/, собственные литералы паттернов),
тесты на сам хук, быстрый путь выхода (оверхед на каждый tool call). Покрытие
хука проверяется по всем шеллам, которыми реально пользуется агент
(
gotcha-hook-shell-blind). - Каждый слой каркаса проверяй сразу, не в конце: после каждого слоя — прогон гейтов. Ошибки ловятся дёшево у источника (EventPlan).
- Тулчейн и системные зависимости проверяй фактически ДО написания конфигов: запусти и убедись, не предполагай. Версии пинуй; что тянет либа — в ADR/Dockerfile в момент выбора (EventPlan: corepack pnpm; Shapely→GEOS, weasyprint→pango).
- Типы обязательны на всех функциях. Функции ≤40 строк без явного обоснования.
- Тесты зеркалят структуру, фабрики, AAA. Тест = полная жизненная цепочка, не
изолированный вызов. Каждый багфикс приносит тест. Интеграционные — на реальной БД,
мок только для внешних сервисов. Фича, меняющая контракт, обновляет свои тесты в том
же коммите (
gotcha-feature-test-debt). Для вычислительного ядра цепочка — не то: там инварианты алгоритма в docstring как контракт + property-based тесты, автор инварианта и автор теста — разные агенты (EventPlan: hypothesis). Цифра покрытия — только с конфигурацией замера («69% с greenlet, без него фиктивные 56%»); расхождение тестовой и прод-СУБД — задокументированное ограничение, не умолчание (АПЕКС). - Тесты wiring — отдельный класс от тестов логики. Юнит-тест, импортирующий объект
напрямую, не проверяет, что система его находит: любая регистрация «по конвенции»
(задачи, сигналы, плагины, роуты) требует теста «всё, на что ссылается конфиг,
реально зарегистрировано» (
gotcha-silent-unregistered). Orphan-check: публичная функция ядра без единого вызывающего — баг интеграции или мёртвый код (gotcha-green-modules-dead-system). Конфиг-поле без потребителя — ложь в диффе; конфиг валидируется при старте (fail fast), единицы измерения совпадают с кодом (Ad-Tycoon: в конфиге 2, в коде хардкод 0.02 — расхождение в 100 раз). - Тест без боевой среды — спроектирован, не случаен. Ядро не импортирует ни строчки среды исполнения И ни строчки вендорского 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).
- Фоновые задачи (если есть очередь): никакой бизнес-логики в таске — таска вызывает сервис; queue, time_limit, retry с backoff, идемпотентность; передавать id, не объекты.
- Фронтенд (если есть): 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, запросы) — проверяются при добавлении тяжёлого, не «когда станет медленно». - 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). - Лицензионный гейт: политика лицензий стороннего кода письменно (для закрытого продукта — только пермиссивные); новый компонент — сначала строка в THIRD_PARTY_LICENSES.md, потом в сборку (REC dimmer).
III. Бумажная работа (карта + документация + версии)
Развернуть с первого дня — «потом» не наступает (gotcha-docs-drift).
- Карта навигации: Module Map в CLAUDE.md (строка на модуль: путь — назначение — ключевые сущности) + navigation-док (дерево каталогов; таблица сущностей — генерируется grep'ом, не по памяти; «задача → где искать»). Список крупных файлов — не как список, а как порог (параметр) + команда генерации + дата сверки + автопроверка в обе стороны («перерос, но не в списке» и «в списке, но похудел») (АПЕКС check-integrity). Правило контекст-экономии первым пунктом workflow; большие файлы — поиск → чтение диапазона; правило передавать субагентам.
- Документация — один индекс и один гейт. Два независимых дерева = двойная цена синхронизации (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, таблица модулей (число = факт!), старт.
- ADR: нетривиальное решение (≥2 реальных альтернатив) → Контекст / Альтернативы / Решение / Причины / Компромисс (обязателен). Существующие ADR не редактируются. «Почему не X» — рядом с решением, особенно где ошибка необратима (Pulse generator: таблица отвергнутых MOSFET с причинами). Ключ связывания систем — решение с организационным следствием, и оно пишется в Компромисс (HS+auth: маппинг по email ⇒ «почты сотрудников нельзя переиспользовать» — правило для отдела кадров).
- Ритуал закрытия сессии (скилл с триггер-фразой): «закрываем сессию» → дифф
сессии (
git log+git status) → свести затронутые зоны (модуль → дока + карта; процесс → правило; решение → ADR; бамп → changelog; закрытый долг → реестр) → отдельныйdocs(sync)-коммит. Если сводить нечего — сказать это явно, не молчать (иначе ритуал незаметно отмирает) (АПЕКС). Канонические имена/URL при сведении сверяются grep'ом с кодом — SoT имени всегда код (BAZA:/healthzчислился/api/health/в пяти доках). После docs-сессии — короткий список реально исполняемых изменений (АПЕКС post-rules-refactor). Штамп ≠ гарантия актуальности. - Статусы в планах — по факту кода, в обе стороны. Фантомные хвосты: пункт числится
открытым, а код давно есть — перед реализацией «незакрытого» сверка с кодом (BAZA:
2 из 4 хвостов). Сводки и индексы правятся атомарно с деталью. Реестр
«Критические долги» — в НАЧАЛЕ roadmap (не в подвале): приоритет, слой, условие
закрытия; закрытие — двухфазно: коммит-фикс, затем коммит-пометка с точным SHA
первого (смешивать нельзя — SHA фикса ещё не существует в момент правки таблицы)
(АПЕКС). Чек-лист
[x]— только если формулировка однозначно совпадает с диффом; буллеты закрытых релизов — неизменяемая история. План фазы — в репозитории, не в памяти агента, с блоком «Ключевые решения (не пере-решать)» со ссылками на ADR — прививка от пере-обсуждения решённого (АПЕКС 0.7.0-execution-plan). Опционально — HTML-дашборд прогресса с блоком DATA, собираемым из git, обновляется в ритуале закрытия (Dashboard/BAZA). - Версии: 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
- Модель ветвления объявляется письменно в ADR — trunk-based или dev/master, по
числу людей и наличию ревью, а не по привычке (АПЕКС живёт trunk-based, ADR-024;
BAZA — dev/master). Для dev/master: master = стабильный прод, merge только бампом;
режим стабилизации — dev держится потоком фиксов, фичи во временных
feature/*, постоянную третью ветку не заводить (BAZA ADR-068). - Делегирование: нетривиальное — субагентам с явным именованием; 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.
- Опасные команды — список письменно в 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). - Не переспрашивай и не угадывай: решение с очевидным дефолтом — прими, озвучь, двигайся. Развилку, меняющую архитектуру/данные/UX — AskUserQuestion до кода. Несколько вопросов — одним заходом.
- TodoWrite на всё многошаговое; планы — в
docs/plans/, не в корне. Двухфазность: фикс отдельным коммитом, roadmap/доки — отдельным (причину см. III.5). - Бюджет CLAUDE.md: там только то, что нужно КАЖДУЮ сессию — постоянная статья
расхода контекста. Ритуалы — скиллы с триггер-фразами; правила — файлы с
globsпо зонам кода (грузятся по файлу) (оба боевых проекта пришли независимо: АПЕКС 279→149 строк, BAZA rules→skills)..claudeignoreна шумные каталоги — с обратным правилом: ничто, на что ссылаются правила или память, не скрыто (указатели в невидимое) (АПЕКС). Гигиена памяти: индекс обязателен (нет в MEMORY.md = невидимо при recall), лимит размера (большой файл = документ, в docs/), память ≠ хранилище документов. У метаданных проекта — свой прогоняемый чек (битые ссылки CLAUDE.md, захардкоженные счётчики, таблица крупных файлов, покрытие хуков): их дрейф не роняет ни один тест (АПЕКС check-integrity.ps1). Одна точка входа для агента, инструменто-нейтральная: смена инструмента = миграция содержимого, чужие каталоги удаляются тем же коммитом (gotcha-two-agent-configs). - Систематически нарушаемое правило — дефект системы, а не людей. Гайд не покрывает реальную потребность — расширь систему и задокументируй, а не копи исключения (BAZA: один класс кнопки закрыл годы техдолга). Осознанное исключение пишется в самом правиле — с границей применимости (BAZA viewsets-only). Заморозка направления фиксируется в правиле явно («i18n ЗАМОРОЖЕН: … не трогать»), иначе очередная сессия «доводит до ума» замороженный слой (BAZA). Правило, невыполнимое по построению («не портировать вручную» между двумя деревьями одного кода) — сигнал менять структуру, не дисциплину: одномоментный перенос, старое read-only (АПЕКС ADR-020).
- Гигиена сессии: следить за автокомпактом — ссылки на docs/ позволяют перечитать
первоисточник после сжатия контекста; сессия ушла не туда — дешевле поправить
CLAUDE.md и начать новую, чем выправлять (REC dimmer). Конфиги быстро меняющихся
сторонних сервисов — по актуальной официальной документации, не по памяти модели;
версии сверяются ДО генерации конфигов (
gotcha-llm-stale-configs). - Протокол отладки (именованный ритуал с триггер-фразой): снаружи внутрь (UI → сеть → бэкенд → БД); не чинить первую найденную причину — проверить, нет ли слоёв под ней; подтвердить фикс фактически до объявления победы; пойманное — в memory/грабли (BAZA tyranid-hunt).
V. Прод, эксплуатация, наблюдаемость
- Боевые серверы — только команды, никакого «я сделаю сам». На прод/VPS агент не выполняет НИЧЕГО самостоятельно. Он выдаёт готовые команды блоком, выполняет человек. Одно письменное подтверждение = одно действие; «да» из прошлого раза не переносится. (АПЕКС)
- Деплой-чеклист письменно и всегда целиком: build ВСЕХ артефактов («изменения не
появились» = собрал не всё — артефактов деплоя больше одного, перечисли ВСЕ и способ
сборки каждого,
gotcha-partial-build) → перезапуск ВСЕХ производных контейнеров → прокси → статусы → логи воркеров → smoke-тест. Частичные варианты — флаги одного скрипта (--backend/--frontend), не отдельные инструкции (АПЕКС). - Деплой — один канонический скрипт с проверками внутри (BAZA deploy.sh): отказ
при грязном дереве/чужой ветке; список пересоздаваемых сервисов вычисляется из
compose, не хардкодится (новый воркер попадает в деплой сам); бэкап — при
непустом плане миграций; ожидание healthy по inspect с таймаутом, не «на глаз»;
smoke = версия из health-эндпоинта, не 200 OK; при провале health-gate скрипт
печатает точную команду отката. Точка отката для проекта с миграциями — пара
(коммит, дамп), образа
:prevнедостаточно: откат кода через миграционный рубеж без отката БД падает на отсутствующих колонках. Rollback — отдельный парный скрипт: подтверждение словом, страховочный дамп текущего состояния ДО восстановления,--code-ref, финальная сверка схемы с кодом (BAZA rollback.sh). Фронт-статика: новая сборка рядом (dist_new) → атомарный swap, старая = точка отката (АПЕКС). - Секрет-гигиена, три слоя раздельно: код / состояние / секреты.
.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). - Канонические пути и имена — письменно в момент создания: путь на сервере, имена
контейнеров, бакетов (АПЕКС: /opt/signe/ vs «угаданный» /opt/signe-server/).
Плюс реестр занятого: порты/адреса/имена проверяются на конфликт с соседями,
включая вендорские дефолты (REC dimmer: дефолтный IP ноды = дефолт диммера;
Grafana 3001 из-за forgejo). Порядок старта зависимостей (VPN раньше docker) — либо
в юните (
After=), либо задокументирован как штатный симптом (мониторинг). - Наблюдаемость (при проде — обязательна): внешний наблюдатель — всё, что
запущено на самом сервере, не видит отказ самого сервера (АПЕКС). 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) и перечислением того, что утечёт (мониторинг). - Бэкап не существует, пока не проверено восстановление. Дамп — вне тома с
данными; проверка целостности (
--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 файл утерян безвозвратно). - Приёмка и необратимость. Приёмочный чек-лист — парный артефакт спеки, и он
диктует наблюдаемость: сначала «как проверяем», из этого — какую диагностику
обязан отдавать продукт (счётчики, uptime, версия на самом устройстве) (REC
dimmer). Ворота этапа: неизвестность закрывается ДО необратимых/дорогих работ;
условные этапы не проектируются заранее; фазовый гейт — измеримый пользовательский
результат с правом остановить продукт («загрузил → план ≤3 мин против 2 ч; нет
„вау“ → пересматриваем») (EventPlan roadmap); ценность раньше «умной» части —
ML/распознавание после подтверждения тупого варианта. Отказные сценарии
обновления — часть приёмки: битый файл → отказ по CRC, питание в момент записи →
грузится старое; «что деградирует во время обновления» записано (REC dimmer).
В пайплайне с необратимыми шагами guard выполняется до первого необратимого
(АПЕКС: compat-check до записи identity). Запас по предельным параметрам вместо
защиты, когда отказ необратим («полевик умрёт раньше любой защиты»). Критерий
приёмки чисто-архитектурного рефакторинга — байт-идентичный наблюдаемый выход
до/после, иначе это не рефакторинг (АПЕКС ADR-021). Debug-функциональность
физически отсутствует в релизном артефакте (
#ifdef/сборка), а не «выключена настройкой»: debug-роуты, mock-режимы, фейковый логин (АПЕКС). - Профиль «публичный релиз» — отдельный от своего прода: как только артефакт уходит в чужой магазин/Marketplace/публичный домен — LICENSE + поле в манифесте, README-витрина со скриншотами, CHANGELOG, иконка, локализация пользовательских доков (внутренние — на одном языке, и это записано), чеклист модерации ДО релиза (claude-office-dashboard).
- Межпроектные контракты: значения, которые один проект ВЫДАЁТ, а другой
ПОТРЕБЛЯЕТ — таблицей с явным эмитентом и потребителем, «совпадают байт в байт»,
включая trailing slash и порт (HS+auth: OIDC). Перечислить ВСЕ пары «кто → кому
ходит»: браузер ≠ контейнер, оба должны достучаться — поломки живут в паре, о
которой не подумали. Общий эталон проверяется первым при «не работает»: земля
для сигналов, NTP для токенов (clock skew валит exp/iat), кодировка для текста,
таймзона для дат — и записывается в предусловия (Pulse generator + HS+auth,
независимо).
[железо]Однократные ручные предусловия среды («выпаять флеш», modprobe модуля, драйвер) — письменный чек-лист, не проза. Комплект артефактов железного проекта: pinout · схема подключения · BOM · порядок сборки · приёмка (три проекта пришли независимо); SoT по «ногам» — документ, в коде ровно один заголовок (pins.h), его отражающий; при противоречии прав документ (REC dimmer).
VI. Литания против граблей
Каждая — реальный инцидент; чти их, дабы не повторить. Теги — к какому стеку/профилю применима; при триаже неприменимые группы отсекай целиком. Ссылайся слагом, не номером.
Контейнеры и деплой [Docker]
gotcha-migration-driftДрейф миграций[+Django]. makemigrations в контейнере без bind-mount → файл живёт в слое образа, БД помнит, git нет; rebuild — файл исчез. Потеряно 18 файлов. → makemigrations ТОЛЬКО через dev-override с bind-mount; после —git status; CI-гейт «чистый migrate с нуля». Рецепт восстановления — записан (I.7). (BAZA)gotcha-stale-workersВоркеры на старом образе[+очередь].up -d appне трогает worker/beat/asgi — очередь выполняет старый код, симптомов не даёт. → деплой-чеклист V.2 целиком; список сервисов вычисляется из compose. (BAZA)gotcha-proxy-cacheПрокси кэширует upstream. После пересборки — 502 или старый фронт. → лечить причину конфигом:resolver 127.0.0.11 valid=10s+ переменные upstream в каждом location — после этого рестарт nginx не нужен; ритуал рестарта — подстраховка, знай, что он маскирует незакрытую причину. (BAZA, вылечено 3ae5995)gotcha-partial-buildАртефактов деплоя больше одного. Пересборка бэкенда не деплоит фронт (в контейнере он или нет — неважно); «изменения не появились» — почти всегда это. → перечисли ВСЕ артефакты и способ сборки каждого. (BAZA, АПЕКС)gotcha-pidfilePidfile в контейнере.docker restartсохраняет ФС → осиротевший pidfile → вечный рестарт, периодика молча стоит. → pidfile в one-process-контейнере не нужен никогда. Парная: healthcheck, проверявший pidfile, стал вечно-ложным после лечения — устранив причину, пройди по проверкам, которые на неё опирались (gotcha-proxy-healthcheck). (BAZA)gotcha-interval-scheduleИнтервальные расписания сбрасываются рестартом планировщика → суточная задача «каждые 24ч» не срабатывает никогда. → crontab-выражения для суточных/еженедельных. (BAZA)gotcha-silent-unregisteredРасписание ≠ реестр[+очередь]. Задача, не попавшая в реестр воркера (autodiscover не видит подпакет), отбрасывается МОЛЧА — beat шлёт, воркер отвечает «unregistered», симптом — тишина. Юнит-тесты, импортирующие задачу напрямую, бага не видят. → тест «расписание ⊆ реестр» + проверка в деплой-скрипте; у планировщика нет громкого режима отказа — создай его. (BAZA, прод)gotcha-dev-prod-settingsDev-стек на prod-настройках. Забытый override → prod-whitelist хостов → 400 на локальном домене. → явные именованные override-файлы и одна задокументированная команда запуска dev-стека. (BAZA)gotcha-exec-bitПрава/окружение контейнера ≠ хоста[+Windows]. Скрипт без +x, том с чужим uid → Permission denied. → скрипты звать черезsh <путь>; явные права томов; проверка после первого up. (BAZA)gotcha-rootowned-bindmountBind-mount на несуществующий путь — docker создаст каталог от root, задача не от root писать не сможет. → создавать каталоги заранее в скрипте. (мониторинг)gotcha-docker-bypasses-ufwГраницу доступа определяет bind-адрес, не фаервол. Docker пишет правила в nat в ОБХОД ufw —ufw deny 9090порт не закроет. → bind на tailnet/localhost; публичный bind — осознанное решение. (мониторинг)gotcha-container-oomКонтейнерный лимит памяти без внутреннего лимита процесса → OOM-kill вместо деградации. → лимит процесса ниже лимита контейнера. (АПЕКС)gotcha-env-special-charsСпецсимволы#$!%&в пароле ломают парсер .env/compose → контейнер в вечном Restarting. (АПЕКС)gotcha-compose-env-driftДефолты в compose разошлись с .env.example → стек поднимается с другими именами БД/юзера. → один источник дефолтов. (АПЕКС)
Данные и логика
gotcha-journal-bypassМутация в обход журнала. Ручное списание меняло остаток напрямую — журнал слеп, аудит дыряв. → ЕДИНАЯ точка применения эффекта, все пути через неё. (BAZA)gotcha-pair-asymmetryАсимметрия парных операций. Создание покрывало 2 метода оплаты, отмена — 1: проводка-сирота, отчёт врал. → create+cancel парой, тест на цикл create→cancel→след чист. (BAZA)gotcha-increment-raceГонки на инкрементах. Два параллельных движения читают один остаток → lost update. → блокировка (select_for_update) внутри транзакции на любых счётчиках с первого дня + конкурентный тест. Где лочить нельзя (ISR, UI) — один назначенный писатель (I.17). (BAZA)gotcha-placeholder-dataПлейсхолдер, притворяющийся данными. Черновые значения без пометки уезжают как «проверенные». → помечать (?, TODO владельцу); гейт перед прод — плейсхолдеров не осталось. (EventPlan)gotcha-number-nullNumber(null) === 0[React/формы]. Трансформ на маунте: null FK → 0 → «выбрана» несуществующая запись. → null-безопасные setValueAs. (BAZA)gotcha-green-modules-dead-systemМодули зелёные — система мертва. 74 честных юнит-теста, архитектура по гайдлайнам — а ключевая функция ядра не вызывается нигде, автосейва не существует (ноль вызовов), софтлок за 12 минут. → orphan-check «кто вызывает» по каждой публичной функции ядра; интеграционный тест полного цикла; для накопительных доменов — headless-прогон N шагов с проверкой, что метрики двигаются. (Ad-Tycoon, независимое ревью)gotcha-orphan-configКонфиг-поле без потребителя. Поля загружаются, валидируются — и никем не читаются; рядом код с хардкодом, расходящимся с конфигом в 100 раз. → вынес в конфиг = есть потребитель и тест, что читается именно оно; валидация при старте; единицы сходятся. (Ad-Tycoon)gotcha-gitignored-dependencyЗависимость от артефакта вне git. Детект платформы завязан на плагин из каталога в .gitignore — работает только на машине разработки, в чистом клоне и CI ломается молча. → гейт «чистый клон собирается и стартует». (Ad-Tycoon)
Версии и контракты
gotcha-version-sotНесколько «источников истины» версии. pyproject vs настройки vs package.json расползаются. → SoT-файлы письменно, остальное не считается. (BAZA)gotcha-version-symmetryАвтовыравнивание версий «для симметрии». PATCH независим — ровнять = фейковые релизы. → бамп только изменившегося. (BAZA)gotcha-lexicographic-semverЛексикографическое сравнение версий."0.10.0" < "0.9.0"строками — стреляет в OTA, когда MINOR доходит до 10. → сравнение только semver-парсером. И вторая линия: guard от даунгрейда на стороне клиента —strcmp(...)!=0означало «ставлю всё, что отличается»; серверная монотонность фида — единая точка отказа, способная забрикать флот одной ошибочной публикацией; намеренный откат — «старый код под более высокой версией». (АПЕКС, ADR-023)gotcha-feature-test-debtТестовый долг фичи. Фича изменила ответ эндпоинта, тесты не тронули — красный набор всплыл через неделю у чужой сессии. → тесты контракта в том же коммите, полный прогон перед push. (BAZA)gotcha-tsc-no-btscбез-bне проверяет project references[TS]. Локально зелёный, сборка на сервере падает. →tsc -b --noEmitпри composite/references. (АПЕКС)
Windows и кодировки [Windows]
gotcha-gitattributesПереносы строк без.gitattributes. autocrlf → LF↔CRLF-дрейф, в Linux-контейнере ломаются скрипты с CRLF. →* text=auto eol=lfс ПЕРВОГО коммита. (EventPlan: 80+ предупреждений)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).gotcha-windows-bindmountWindows bind-mount врёт. Задержка синхронизации → контейнер видит старый файл. → docker cp или --no-cache при сборке фронта. (BAZA)gotcha-case-insensitive-headersHTTPClient.hvsHttpClient.h— две библиотеки, различающиеся регистром имени, конфликтуют на регистронезависимой ФС. (АПЕКС)
Инфраструктура [инфра/прод]
gotcha-shared-proxyОбщий реверс-прокси: глобальные объекты и Host. Одноимённыеmap/upstream→ «duplicate map»; proxy_pass по IP безHost $host→ 400 от whitelist. → имена глобальных объектов уникальны per-vhost; Host всегда. (BAZA)gotcha-fail2ban-selfАвто-защиты банят свою автоматизацию. fail2ban целевой системы банит настройщика после 2 SSH-коннектов (ssh-copy-id = 2 = бан). → свой IP в доверенные ДО работ. (BAZA: NAS)gotcha-pipefailПайп безset -o pipefail→ код возврата от последней команды: упавший pg_dump + живой gzip = пустой архив и «успех». Зелёный статус над битым дампом хуже отсутствия бэкапа. (мониторинг)gotcha-tls-bare-ipЗапрос по голому IP при сертификате на домен провалит TLS-проверку — в инструкциях и конфигах всегда домен. (АПЕКС)gotcha-crypto-defaultsДефолты криптоутилит небезопасны. htpasswd по умолчанию bcrypt cost 5 (32 раунда) — задавать стоимость явно (-C 12). (мониторинг)gotcha-https-redirect-proxyHTTPS-редирект за SSL-прокси хостинга = бесконечный редирект:RewriteCond %{HTTPS} offне видит прокси. → редиректы — средствами панели/прокси; за прокси о схеме судят поX-Forwarded-Proto. (лендинг; родняgotcha-shared-proxy— за прокси реальность не та, что видит приложение)gotcha-robots-secretСекретный путь в robots.txt. СтрокаDisallowсама выдаёт путь любому, кто откроет robots. → секретные пути не упоминать нигде публично. (лендинг)gotcha-double-cronДва механизма расписания (/etc/cron.d/*иcrontab -e) → задача дважды за ночь. → SoT расписания — один файл, создаётся setup-скриптом. (АПЕКС)gotcha-nginx-detailsМелочи nginx:expires+add_header Cache-Controlвместе = дублирующийся заголовок; на Debian пользовательwww-data, неnginx. (АПЕКС)
Процесс
gotcha-docs-driftДокументация отстаёт молча. Месяц без сведения = 35 файлов лжи и день работы 10 субагентов. → ритуал закрытия сессии (III.4), каждый раз. (BAZA)gotcha-god-filesGod-файлы съедают контекст и дисциплину. serializers на 940 строк, страница на 1290. → делить при росте, карта крупных файлов с автопроверкой (III.1), точечное чтение. (BAZA)gotcha-phantom-tailsФантомные хвосты плана. «Незакрытые» пункты roadmap давно сделаны — сессия готова повторить работу. → статусы по факту кода, сверка перед реализацией (III.5). (BAZA: 2 из 4)gotcha-silent-laterМолчаливое «потом». Каждое «потом допишем» без записи исчезает. → всё отложенное — письменно (план, ADR-компромисс, реестр долгов, memory) в момент откладывания. (BAZA)gotcha-ci-wrong-branchCI слушает не ту ветку. Workflows на master, работа месяц шла в dev — гейты тихо перестали существовать. → сменил ветвенную модель → в тот же коммит триггеры CI/хуков/автоматики. (BAZA d9804c2)gotcha-hook-shell-blindХук слеп к реальному шеллу. MatcherBash, работа идёт в PowerShell — защита существует и не работает. → покрытие хука по всем шеллам, проверяется скриптом целостности. (АПЕКС)gotcha-renumbered-parentПеренумерация родительского документа тихо ломает все производные ссылки. → ссылаться слагом; при реструктуризации — прогнать ссылки в производных. (EventPlan: ссылки на литанию били в пустоту через 2 часа)gotcha-two-agent-configsДве конфигурации агента. Проект вёлся двумя инструментами, конфигурация дважды мигрировала и рассинхронизировалась. → одна инструменто-нейтральная точка входа; чужие каталоги удаляются тем же коммитом. (Ad-Tycoon ADR-010)gotcha-automated-promptСистемные инъекции неотличимы от пользователя. Автоуведомление фоновой задачи пришло как «промпт пользователя» и снимало экстренную остановку. → механика, реагирующая на «пользователь написал», обязана фильтровать автоматику. (office-dashboard v0.13.2)gotcha-llm-stale-configsКонфиги по памяти модели. Синтаксис быстро меняющихся сервисов, выдуманный по памяти, не совпадает с текущей версией (HS+auth: Authentik 2026.x убрал Redis). → сверка с актуальной официальной докой; версии пинуются и записываются ДО генерации.gotcha-modal-drag-closeМодалка закрывается при drag-выделении текста[React](mouseup ловится на бэкдропе). → закрытие по клику, начатому и завершённому на бэкдропе. (АПЕКС)gotcha-404-swallows-detailГлобальный 404-хендлер глотает содержательныеdetailроутеров. → хендлер пропускает существующий detail. (АПЕКС)
Финал: литания прочитана, профиль определён, триаж проведён, каркас развёрнут и
отревьюен — можно начинать. Новые грабли проекта — в живой раздел
docs/architecture.md#Грабли проекта (копия литании read-only), обобщаемое —
периодически в мастер-литанию: она живёт, пока её кормят инцидентами.