--- work_item: ORCH-098 stage: analysis author_agent: analyst status: ready-for-review created_at: 2026-06-10 model_used: claude-opus-4-8 --- # 01 — BRD (бизнес-требования): ORCH-098 — FND: машинный журнал уроков (структурированная база отклонений) Work Item: **ORCH-098** · Repo: **orchestrator** · Стадия: analysis ## 1. Бизнес-контекст и проблема Оркестратор уже автономно проводит задачи через конвейер (ORCH-54), но **развивает** платформу по-прежнему вручную связка Слава+Стрим: ловим инциденты → формулируем уроки → заводим задачи. Уроки сегодня живут **свободным текстом** в `memory/` — они не машиночитаемы, по ним нельзя считать паттерны, нельзя приоритизировать, нельзя автоматически предлагать улучшения. ORCH-098 — шаг 1 эпика саморазвития (`docs/epics/self-evolution.md`, **домен 0 «Фундамент», F2**, ORCH-8). Это **«топливо» вертикали-двигателя** (петля самообучения 8A): формализовать свободный текст в **машинную структурированную таблицу отклонений конвейера**. Каждый урок — запись с полями для машинного анализа паттернов. Журнал — фундамент, на котором позже встанут ретроспективщик (E2), приоритизатор RICE (E3) и Стрим как потребители. **Установленные факты-источники сигналов («уроков»)** — из памяти орка (инциденты 06–09.06) и §8A эпика: - Провал гейта (BLOCKED / FAILED / REQUEST_CHANGES). - **Ручное вмешательство человека — самый ценный сигнал** (каждый ручной пинок = дыра автономности). - Ретраи, откаты деплоя, таймауты агентов. - Ложные срабатывания гейтов (исторический пример: substring `PASS` в `check_tests_passed`). - «Деплой SUCCESS, а прод не работает» (урок ET-8); транзиенты (Gitea `405`, Anthropic `Overloaded`). **Решение Славы 10.06 (ОБЯЗАТЕЛЬНО учесть на этапе схемы):** схема журнала ДОЛЖНА **с самого начала** нести поля для будущей **АТРИБУЦИИ** урока (иначе потом переделывать схему на живой общей прод-БД). Атрибуция (`platform-level` / `project-level` / `both` / `unknown`), целевой проект и целевой домен улучшения — это §8A эпика «platform-level vs project-level». При автозаписи поля атрибуции могут быть пустыми/`unknown` (классификацию позже ставит ретроспективщик/Стрим), но **колонки в схеме должны существовать сразу** — аддитивные, нуллабельные. **Связь со слоями наблюдения (§2 эпика):** деградация продукта (слой 3, урок ET-8) — один из типов урока; журнал должен уметь его хранить с атрибуцией `platform`/`project`. ## 2. Объём (scope) ### В объёме - Аддитивная идемпотентная таблица БД `lessons` для структурированных уроков со всеми полями контекста, анализа, статуса **и атрибуции** (колонки атрибуции — сразу, нуллабельные). - Leaf-модуль `src/lessons.py` (never-raise, kill-switch) + helper записи урока. - **Автозапись** ≥2–3 типов отклонений из кода через best-effort точки врезки в `stage_engine.py` / `merge_gate.py` / `launcher.py` (провал гейта/откат, HOLD, транзиент-ретрай). - **Read-only выборка** уроков (HTTP-эндпоинт + блок в `GET /queue`) — для будущего ретроспективщика и Стрим. - **Ручная запись** урока (HTTP-эндпоинт / helper) — Стрим/оператор кладёт урок руками. - Доки (CLAUDE.md / architecture README / ADR) + `CHANGELOG.md`. ### Вне объёма - **Анализ паттернов / ретроспективщик (E2)** — отдельная задача-потребитель журнала. - **Приоритизатор RICE (E3)** — отдельная задача. - **Автоматическая классификация атрибуции** — её ставит ретроспективщик/человек позже; здесь — только колонки и возможность проставить значение руками/через update. - **Банк идей (D4 / идеатор, E5)** — отдельный реестр, НЕ путать с журналом уроков. - **Слой-3 детекция здоровья продукта** (мониторинг задеплоенного приложения) — отдельная D4/D5-способность; журнал лишь умеет **хранить** такой урок, когда детектор появится. - Изменение `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключей / любых существующих таблиц. - Миграция исторических уроков из `memory/` (ручной разовый импорт — вне объёма). ## 3. Заинтересованные стороны - **Заказчик:** Слава (требование атрибуции 10.06 — нормативно). - **Прямой потребитель (будущее):** агент-ретроспективщик E2, приоритизатор E3, Стрим (ручной разбор). - **Затрагивается:** self-hosting прод-инстанс orchestrator (общая БД и очередь с enduro-trails) — enduro **не должен быть затронут** (аддитивность, never-raise). - **Принимает результат:** reviewer/tester конвейера + Слава. ## 4. Бизнес-требования (BR) - **BR-1 — Структурированная таблица уроков.** Аддитивная, идемпотентная (`CREATE TABLE IF NOT EXISTS`) таблица `lessons` на общей прод-БД с полями: тип отклонения; контекст (work_item/task/стадия/агент/repo); корневая причина (если известна); предложенное улучшение (если есть); статус (`new`/`in_progress`/`closed`/`linked`) + связанная задача; timestamp. - **BR-2 — Поля атрибуции с самого начала.** Схема несёт **сразу** нуллабельные колонки: `attribution` (`platform`/`project`/`both`/`unknown`), `target_repo` (кого касается: `orchestrator`/`enduro-trails`/др.), `target_domain` (домен улучшения: `reliability`/`quality`/`economy`/`features`/`scale`). При автозаписи допустимо пусто/`unknown`. - **BR-3 — Автозапись ≥2–3 типов отклонений.** Из кода, best-effort, в детерминированных choke-point: (а) провал гейта / откат на `development` (reviewer REQUEST_CHANGES, tester FAIL, staging/deploy FAILED), (б) HOLD merge-актора / regression-guard HOLD, (в) транзиент-ретрай (Gitea-merge `405`/`5xx`, Anthropic `Overloaded`/agent-timeout requeue). Дополнительно желательно (г) post-deploy `DEGRADED` (урок «деплой OK / прод сломан», слой-3, ET-8) с атрибуцией. - **BR-4 — Read-only выборка.** HTTP-эндпоинт `GET /lessons` (фильтры: тип/статус/repo/work_item, лимит) + read-only блок `lessons` в `GET /queue` (сводка). Только чтение. - **BR-5 — Ручная запись.** HTTP-эндпоинт `POST /lessons` (+ публичный helper) — оператор/Стрим кладёт урок руками, в т.ч. с проставленной атрибуцией. - **BR-6 — Обновление урока.** Возможность сменить статус / проставить атрибуцию / привязать задачу после создания (helper/эндпоинт `POST /lessons/{id}` или поля в `POST /lessons`) — чтобы ретроспективщик/человек позже классифицировал автозаписанный `unknown`. ## 5. Нефункциональные требования (NFR) - **NFR-1 — never-raise (критично, self-hosting).** Сбой записи/чтения урока **никогда** не роняет и не тормозит конвейер. Любая ошибка детектора/записи → лог WARNING + продолжение основного потока. Журнал — наблюдатель, не участник пайплайна. - **NFR-2 — Kill-switch.** Флаг `lessons_enabled` (env `ORCH_LESSONS_ENABLED`). `False` → автозапись и эндпоинты инертны (нулевая регрессия, поведение конвейера байт-в-байт прежнее). - **NFR-3 — Аддитивность / изоляция enduro.** Только новая таблица + новый leaf + новые эндпоинты + тонкие врезки. `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключи / схема существующих таблиц — **байт-в-байт не тронуты**. Общая БД: enduro-trails не затронут. - **NFR-4 — Restart-safe / идемпотентность таблицы.** `CREATE TABLE IF NOT EXISTS` + `_ensure_column` (паттерн `repo_freeze`/`coverage_baseline`) — безопасно на живой БД, повторный старт без эффекта. - **NFR-5 — Лёгкость.** Запись — один `INSERT`, чтение — простые `SELECT` (общий хост впритык: RAM 171Mi free, диск 92%). Никаких фоновых потоков/сканов. - **NFR-6 — Схема-forward-proof.** Колонки атрибуции добавлены сразу (BR-2), чтобы не переделывать схему на живой БД, когда появится ретроспективщик. - **NFR-7 — Self-hosting безопасность.** Модуль только пишет/читает БД и отдаёт JSON — не деплоит, не рестартит прод, не трогает `main`, не порождает процессы/сеть. ## 6. Допущения и ограничения - Журнал уроков — **исключение** из правила «наблюдатель отделён от наблюдаемого» (§2 эпика): это историческая память петли, не realtime-мониторинг → допустимо в БД орка; запись best-effort. - Точки автозаписи привязаны к существующим choke-point: `stage_engine._handle_qg_failure_rollbacks` (откаты), `merge_gate` (HOLD/transient-классификатор ORCH-093), `launcher` (timeout/requeue транзиентов). Архитектор уточняет точный набор и сигнатуры врезок. - Набор значений `lesson_type` / `attribution` / `target_domain` — конвенция (строковые слаги), не enum-констрейнт БД (forward-compatible; новый тип не требует миграции). - Общая прод-БД с enduro: любое поле repo-scoped, фильтрация на уровне выборки. ## 7. Критерии успеха Таблица `lessons` создаётся идемпотентно на старте; автозаписаны ≥2–3 типа отклонений из реального прогона; `GET /lessons` и `POST /lessons` работают; атрибутивные колонки присутствуют и проставляемы; kill-switch выключает всё без регрессии; `pytest tests/ -q` зелёный; доки+CHANGELOG обновлены. Детальные PASS/FAIL — `03-acceptance-criteria.md`. ## 8. Риски - Врезка детектора в горячий путь конвейера → риск регрессии при сбое записи. Митигация: NFR-1 never-raise + kill-switch. - Рост таблицы со временем (автозапись на каждом откате/ретрае). Митигация: лёгкие строки; будущая ретенция — вне объёма, отметить в `10-tech-risks.md` (архитектор). - Недооформленная схема атрибуции → переделка на живой БД. Митигация: BR-2/NFR-6 (колонки сразу). - Детали и архитектурные развилки (точные точки врезки, индексы, дедуп автозаписей) — задача архитектора (`06-adr/`, `10-tech-risks.md`).