textmachine/platform/docs/ENGINEERING_STANDARDS.md

9.4 KiB
Raw Blame History

Стандарты разработки и критерии приёмки платформы

Ратифицировано оркестратором №14 по решению владельца 04.08: платформа считает токены пользователей и держит их логины — «ошибки недопустимы»; качество и отказоустойчивость выше скорости фич. Каждый промт платформенной сессии обязан ссылаться на этот документ; отступление = пинг, не тихая девиация.

1. Рамка

  • Несущие пути — auth/сессии/CSRF, всё денежное (usage, лимиты, биллинг), ингест/супервизия движка, миграции. Изменение несущего пути = «тяжёлый» класс: полный цикл приёмки §3, без исключений.
  • Сторонние тулы прежде самописного (решение владельца 04.08): проверенные библиотеки предпочитаются своему коду везде, КРОМЕ похода в ядро переводов (tmctl зовётся процессом, обвязка своя) и мест, где stdlib и есть индустриальный стандарт (net/http, database/sql-слой через pgx). Новая зависимость — строка в STACK_DECISIONS.md с датой релиза и «зачем», ратифицирует оркестратор.
  • Канон-инварианты зоны без изменений: D39.84 (никаких денежных сумм на проводе/UI/INFO-логах) · D39.85 (шов: NDJSON → апсерт (engine_run_id, seq) → SSE из Postgres; живой SQLite движка не читать) · ПТ-34 (noindex/no-store на всём) · языко-агностичность.

2. Базовые стандарты (проверяются каждой приёмкой)

Безопасность — базовая линия OWASP ASVS 5.0.0, целевой L2 (главы, релевантные зоне: V6 аутентификация · V7 сессии · V10 OAuth/OIDC) + OWASP API Security Top 10 2023 (API1 BOLA = проверка владения книгой на каждом /v0-маршруте; API4 = класс PD-2). Что берём и чего не берём из инструментов — PLATFORM_DIRECTION.md §3. Конкретика:

  • Сессии: одна серверная, opaque-токен ≥256 бит из crypto/rand, в БД только хеш, немедленный отзыв, два срока (idle скользит, absolute нет). Плейнтекст-токен не персистится, не логируется и живёт в памяти только окно обработки запроса (решение владельца 04.08).
  • Секреты — только из окружения/секрет-менеджера; в репо и в логи не попадают НИ на каком уровне.
  • Ввод: только параметризованные запросы; каждый body-принимающий хендлер несёт http.MaxBytesReader и дедлайн (гейт PD-2 регистра); закрытые словари валидируются на входе И констрейнтами БД.
  • Ответы: problem+json; внутренности и оракулы (unknown-vs-expired токен) на провод не текут; заголовки ПТ-34+nosniff+no-referrer — мидлварью на всё, не дисциплиной хендлера.
  • govulncheck (make vuln) — перед каждым лендингом; красный = блокер лендинга.

Отказоустойчивость:

  • Ингест идемпотентен ((engine_run_id, seq), high-water mark в одной транзакции с эффектом); at-least-once — норма, дубль — не ошибка.
  • Graceful shutdown с реальным дренажем; пул с лимитами; транзиентные ошибки БД — ретраи с джиттером; миграции идемпотентны, down-путь существует и гоняется тестом.
  • Отказ зависимости — деградация с диагностикой, не тишина: проглоченная ошибка без лога и без комментария-обоснования = дефект (класс PD-5/PD-16).

Наблюдаемость — базовая линия практики именования Prometheus (базовые единицы: секунды и байты; _total у счётчиков; единица в имени, не в лейбле) + четыре золотых сигнала SRE на вопрос «что мерить» (внесено P5 по ратифицированному направлению PD-115: у оси появился внешний эталон, а не только собственная проза зоны). Конкретика:

  • структурные логи (route-pattern, не сырой путь — id пользователя/книги в логи не текут), X-Request-Id на каждом ответе, ошибки видимы на своём уровне;
  • метрики отдаются в формате Prometheus на ОТДЕЛЬНОМ слушателе (STACK_DECISIONS §24); лейбл несёт паттерн маршрута, никогда путь — иначе это и неограниченная кардинальность, и библиотека пользователя в индексе оператора;
  • Money-числа — только в приватных таблицах, ни в логах, ни в ответах, ни в метриках (кроме P-5-статуса процентами);
  • ⚠ оси ops (релиз/откат, ёмкость, восстановление) и конфигурация внешнего эталона по-прежнему не имеют — PD-115 открыт ими.

Контракт-первичность: поверхность = docs/architecture/14-api-contract/openapi.yaml; расхождение кода со спекой = дефект чей-то один: либо спека правится через ратификацию, либо код. Генерация типов/стабов из спеки (oapi-codegen — кандидат, ратификация при P1) предпочтительнее ручного дрифта.

3. Критерии приёмки сессии (Definition of Done)

  1. make check зелёный офлайн; скипы названы вслух. ⚠ «Скипов ноль» требует ТРЁХ условий, а не одного (испр. 22.08 — прежняя редакция называла только DSN и позволяла объявить приёмку выполненной с молча пропущенной третью батареи): TM_PLATFORM_TEST_DSN (схема) · TM_PLATFORM_TEST_ENGINE_BIN + TM_PLATFORM_TEST_BOOK_TEMPLATE (живой рендер конфигурации) · ДОСТИЖИМЫЙ пользовательский менеджер systemd (internal/runner, systemdOrSkip — на хосте без logind-сессии три теста скипаются и «скипов 0» недостижимо в принципе, PD-374). Условие, которое на этом хосте не выполнено, сессия НАЗЫВАЕТ вместе с числом скипов — «зелёная батарея» без него не значит ничего. Порядок подъёма PG без root — STACK_DECISIONS.md.
  2. Каждый деливерабл проверен ИСПОЛНЕНИЕМ (сервер поднят и опрошен, миграции применены дважды, констрейнты сработали поимённо, супервизор гонял настоящий процесс) — не чтением.
  3. Заявленное в отчёте свойство несущего пути ОБЯЗАНО быть запинено тестом, который ловит мутацию этого свойства; сессия сама называет в отчёте, какой тест что пинит. Приёмка оркестратора сажает СВОИ мутации (урок P0: «в БД только хеш» было истинно, но не запинено — посадка выжила).
  4. Адверсариальная самопроверка (author≠reviewer) до сдачи; найденное — в отчёт, не молча.
  5. Новые находки — строками в DEFECT_REGISTER.md тем же деревом; закрытие дефекта — коммит + пинящий тест.
  6. Дерево не коммитится сессией — лендит оркестратор после адверсариальной приёмки (для несущих путей — с воркфлоу-верификаторами и посадками).