go-learn/prestart-litany.md
sab.code.lab 1c85091186 chore: восстановление репозитория из снапшота v0.3.1
Прежняя git-история утрачена при переносе проекта на машину владельца
(снапшот без .git). Хэши коммитов в docs/reports/* относятся к утраченной
истории.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-07 09:34:02 +02:00

86 KiB
Raw Permalink Blame History

Литания перед стартом нового проекта

Как применять: положи этот файл в корень нового проекта и дай 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. Каркас и финал развёртывания

Развернуть каркас из разделов IV по итогам триажа. Финал: показать пользователю 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 <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.
  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, гейты, ревью диффов, интеграцию. Нижняя граница: правку 13 строк не делегировать — оверхед дороже. Нет подходящего агента — остановиться и спросить, не выдумывать. Определения агентов модель-нейтральны: модель и 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 → стек поднимается с другими именами БД/юзера. → один источник дефолтов. (АПЕКС)

Данные и логика

  1. gotcha-journal-bypass Мутация в обход журнала. Ручное списание меняло остаток напрямую — журнал слеп, аудит дыряв. → ЕДИНАЯ точка применения эффекта, все пути через неё. (BAZA)
  2. gotcha-pair-asymmetry Асимметрия парных операций. Создание покрывало 2 метода оплаты, отмена — 1: проводка-сирота, отчёт врал. → create+cancel парой, тест на цикл create→cancel→след чист. (BAZA)
  3. gotcha-increment-race Гонки на инкрементах. Два параллельных движения читают один остаток → lost update. → блокировка (select_for_update) внутри транзакции на любых счётчиках с первого дня + конкурентный тест. Где лочить нельзя (ISR, UI) — один назначенный писатель (I.17). (BAZA)
  4. gotcha-placeholder-data Плейсхолдер, притворяющийся данными. Черновые значения без пометки уезжают как «проверенные». → помечать (?, TODO владельцу); гейт перед прод — плейсхолдеров не осталось. (EventPlan)
  5. gotcha-number-null Number(null) === 0 [React/формы]. Трансформ на маунте: null FK → 0 → «выбрана» несуществующая запись. → null-безопасные setValueAs. (BAZA)
  6. gotcha-green-modules-dead-system Модули зелёные — система мертва. 74 честных юнит-теста, архитектура по гайдлайнам — а ключевая функция ядра не вызывается нигде, автосейва не существует (ноль вызовов), софтлок за 12 минут. → orphan-check «кто вызывает» по каждой публичной функции ядра; интеграционный тест полного цикла; для накопительных доменов — headless-прогон N шагов с проверкой, что метрики двигаются. (Ad-Tycoon, независимое ревью)
  7. gotcha-orphan-config Конфиг-поле без потребителя. Поля загружаются, валидируются — и никем не читаются; рядом код с хардкодом, расходящимся с конфигом в 100 раз. → вынес в конфиг = есть потребитель и тест, что читается именно оно; валидация при старте; единицы сходятся. (Ad-Tycoon)
  8. gotcha-gitignored-dependency Зависимость от артефакта вне git. Детект платформы завязан на плагин из каталога в .gitignore — работает только на машине разработки, в чистом клоне и CI ломается молча. → гейт «чистый клон собирается и стартует». (Ad-Tycoon)

Версии и контракты

  1. gotcha-version-sot Несколько «источников истины» версии. pyproject vs настройки vs package.json расползаются. → SoT-файлы письменно, остальное не считается. (BAZA)
  2. gotcha-version-symmetry Автовыравнивание версий «для симметрии». PATCH независим — ровнять = фейковые релизы. → бамп только изменившегося. (BAZA)
  3. gotcha-lexicographic-semver Лексикографическое сравнение версий. "0.10.0" < "0.9.0" строками — стреляет в OTA, когда MINOR доходит до 10. → сравнение только semver-парсером. И вторая линия: guard от даунгрейда на стороне клиентаstrcmp(...)!=0 означало «ставлю всё, что отличается»; серверная монотонность фида — единая точка отказа, способная забрикать флот одной ошибочной публикацией; намеренный откат — «старый код под более высокой версией». (АПЕКС, ADR-023)
  4. gotcha-feature-test-debt Тестовый долг фичи. Фича изменила ответ эндпоинта, тесты не тронули — красный набор всплыл через неделю у чужой сессии. → тесты контракта в том же коммите, полный прогон перед push. (BAZA)
  5. gotcha-tsc-no-b tsc без -b не проверяет project references [TS]. Локально зелёный, сборка на сервере падает. → tsc -b --noEmit при composite/references. (АПЕКС)

Windows и кодировки [Windows]

  1. gotcha-gitattributes Переносы строк без .gitattributes. autocrlf → LF↔CRLF-дрейф, в Linux-контейнере ломаются скрипты с CRLF. → * text=auto eol=lf с ПЕРВОГО коммита. (EventPlan: 80+ предупреждений)
  2. 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).
  3. gotcha-windows-bindmount Windows bind-mount врёт. Задержка синхронизации → контейнер видит старый файл. → docker cp или --no-cache при сборке фронта. (BAZA)
  4. gotcha-case-insensitive-headers HTTPClient.h vs HttpClient.h — две библиотеки, различающиеся регистром имени, конфликтуют на регистронезависимой ФС. (АПЕКС)

Инфраструктура [инфра/прод]

  1. gotcha-shared-proxy Общий реверс-прокси: глобальные объекты и Host. Одноимённые map/upstream → «duplicate map»; proxy_pass по IP без Host $host → 400 от whitelist. → имена глобальных объектов уникальны per-vhost; Host всегда. (BAZA)
  2. gotcha-fail2ban-self Авто-защиты банят свою автоматизацию. fail2ban целевой системы банит настройщика после 2 SSH-коннектов (ssh-copy-id = 2 = бан). → свой IP в доверенные ДО работ. (BAZA: NAS)
  3. gotcha-pipefail Пайп без set -o pipefail → код возврата от последней команды: упавший pg_dump + живой gzip = пустой архив и «успех». Зелёный статус над битым дампом хуже отсутствия бэкапа. (мониторинг)
  4. gotcha-tls-bare-ip Запрос по голому IP при сертификате на домен провалит TLS-проверку — в инструкциях и конфигах всегда домен. (АПЕКС)
  5. gotcha-crypto-defaults Дефолты криптоутилит небезопасны. htpasswd по умолчанию bcrypt cost 5 (32 раунда) — задавать стоимость явно (-C 12). (мониторинг)
  6. gotcha-https-redirect-proxy HTTPS-редирект за SSL-прокси хостинга = бесконечный редирект: RewriteCond %{HTTPS} off не видит прокси. → редиректы — средствами панели/прокси; за прокси о схеме судят по X-Forwarded-Proto. (лендинг; родня gotcha-shared-proxy — за прокси реальность не та, что видит приложение)
  7. gotcha-robots-secret Секретный путь в robots.txt. Строка Disallow сама выдаёт путь любому, кто откроет robots. → секретные пути не упоминать нигде публично. (лендинг)
  8. gotcha-double-cron Два механизма расписания (/etc/cron.d/* и crontab -e) → задача дважды за ночь. → SoT расписания — один файл, создаётся setup-скриптом. (АПЕКС)
  9. gotcha-nginx-details Мелочи nginx: expires + add_header Cache-Control вместе = дублирующийся заголовок; на Debian пользователь www-data, не nginx. (АПЕКС)

Процесс

  1. gotcha-docs-drift Документация отстаёт молча. Месяц без сведения = 35 файлов лжи и день работы 10 субагентов. → ритуал закрытия сессии (III.4), каждый раз. (BAZA)
  2. gotcha-god-files God-файлы съедают контекст и дисциплину. serializers на 940 строк, страница на 1290. → делить при росте, карта крупных файлов с автопроверкой (III.1), точечное чтение. (BAZA)
  3. gotcha-phantom-tails Фантомные хвосты плана. «Незакрытые» пункты roadmap давно сделаны — сессия готова повторить работу. → статусы по факту кода, сверка перед реализацией (III.5). (BAZA: 2 из 4)
  4. gotcha-silent-later Молчаливое «потом». Каждое «потом допишем» без записи исчезает. → всё отложенное — письменно (план, ADR-компромисс, реестр долгов, memory) в момент откладывания. (BAZA)
  5. gotcha-ci-wrong-branch CI слушает не ту ветку. Workflows на master, работа месяц шла в dev — гейты тихо перестали существовать. → сменил ветвенную модель → в тот же коммит триггеры CI/хуков/автоматики. (BAZA d9804c2)
  6. gotcha-hook-shell-blind Хук слеп к реальному шеллу. Matcher Bash, работа идёт в PowerShell — защита существует и не работает. → покрытие хука по всем шеллам, проверяется скриптом целостности. (АПЕКС)
  7. gotcha-renumbered-parent Перенумерация родительского документа тихо ломает все производные ссылки. → ссылаться слагом; при реструктуризации — прогнать ссылки в производных. (EventPlan: ссылки на литанию били в пустоту через 2 часа)
  8. gotcha-two-agent-configs Две конфигурации агента. Проект вёлся двумя инструментами, конфигурация дважды мигрировала и рассинхронизировалась. → одна инструменто-нейтральная точка входа; чужие каталоги удаляются тем же коммитом. (Ad-Tycoon ADR-010)
  9. gotcha-automated-prompt Системные инъекции неотличимы от пользователя. Автоуведомление фоновой задачи пришло как «промпт пользователя» и снимало экстренную остановку. → механика, реагирующая на «пользователь написал», обязана фильтровать автоматику. (office-dashboard v0.13.2)
  10. gotcha-llm-stale-configs Конфиги по памяти модели. Синтаксис быстро меняющихся сервисов, выдуманный по памяти, не совпадает с текущей версией (HS+auth: Authentik 2026.x убрал Redis). → сверка с актуальной официальной докой; версии пинуются и записываются ДО генерации.
  11. gotcha-modal-drag-close Модалка закрывается при drag-выделении текста [React] (mouseup ловится на бэкдропе). → закрытие по клику, начатому и завершённому на бэкдропе. (АПЕКС)
  12. gotcha-404-swallows-detail Глобальный 404-хендлер глотает содержательные detail роутеров. → хендлер пропускает существующий detail. (АПЕКС)

Финал: литания прочитана, профиль определён, триаж проведён, каркас развёрнут и отревьюен — можно начинать. Новые грабли проекта — в живой раздел docs/architecture.md#Грабли проекта (копия литании read-only), обобщаемое — периодически в мастер-литанию: она живёт, пока её кормят инцидентами.