---
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`).
