architect(ET): auto-commit from architect run_id=574
This commit is contained in:
92
docs/architecture/adr/adr-0033-lessons-journal.md
Normal file
92
docs/architecture/adr/adr-0033-lessons-journal.md
Normal file
@@ -0,0 +1,92 @@
|
||||
---
|
||||
work_item: ORCH-098
|
||||
stage: architecture
|
||||
author_agent: architect
|
||||
status: proposed
|
||||
created_at: 2026-06-10
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# adr-0033: Машинный журнал уроков — таблица `lessons` + observer-leaf (ORCH-098)
|
||||
|
||||
## Статус
|
||||
Proposed
|
||||
|
||||
## Контекст
|
||||
|
||||
Оркестратор автономно ведёт задачи по конвейеру (ORCH-54), но **развивается** вручную: инциденты →
|
||||
уроки → задачи. Уроки живут свободным текстом в `memory/` — не машиночитаемы: нельзя считать
|
||||
паттерны, приоритизировать, предлагать улучшения. ORCH-098 — шаг 1 эпика саморазвития (домен 0
|
||||
«Фундамент», F2): «топливо» петли самообучения 8A. Нужна **структурированная таблица отклонений
|
||||
конвейера**, на которой позже встанут ретроспективщик (E2), приоритизатор RICE (E3) и Стрим.
|
||||
|
||||
Нормативное требование Славы (10.06): схема ДОЛЖНА **сразу** нести поля **атрибуции** урока
|
||||
(`platform`/`project`/`both`/`unknown` + целевой репо + домен улучшения), иначе позже придётся
|
||||
переделывать схему на живой общей прод-БД.
|
||||
|
||||
**Кросс-каттинговость** (почему сквозной ADR): новый компонент `src/lessons.py` + аддитивная
|
||||
таблица на **общей прод-БД** (self-hosting, разделяемой с enduro-trails) + врезки автозаписи в
|
||||
несколько горячих choke-point'ов (`stage_engine`/`merge_gate`/`launcher`) + новый раздел контракта
|
||||
`GET /queue`. Фундамент для будущих задач-потребителей → регистрируется глобально.
|
||||
|
||||
## Решение
|
||||
|
||||
Журнал уроков — **observer (наблюдатель), НЕ Quality Gate**. Аддитивная таблица + чистый leaf,
|
||||
по образцу `serial_gate`/`coverage_gate`/`metrics`/`bug_fast_track`.
|
||||
|
||||
1. **Таблица `lessons`** (`db.init_db()`, `CREATE TABLE IF NOT EXISTS` + 3 индекса, идемпотентно,
|
||||
restart-safe) — поля контекста (`work_item_id`/`task_id`/`stage`/`agent`/`repo`), анализа
|
||||
(`root_cause`/`suggestion`), статуса (`status`/`related_task`), **атрибуции сразу и нуллабельно**
|
||||
(`attribution`/`target_repo`/`target_domain`) + `source`/`detail`. Без `enum`-констрейнтов
|
||||
(слаги forward-compatible). Будущие колонки — `_ensure_column`.
|
||||
|
||||
2. **Leaf `src/lessons.py`** (never-raise, импортирует только `config`+`db`): `record()` / `get()` /
|
||||
`update()` / `snapshot()`. **Расхождение с гейт-шаблоном: журнал НЕ скоупится по репо** — он
|
||||
observer-only и не *действует* ни на один репо; единственный регулятор — глобальный kill-switch
|
||||
`lessons_enabled`. Запись урока про enduro ценна и **не затрагивает** пайплайн enduro (чистая
|
||||
память орка); репо-разрез — на выборке (`repo`-колонка/фильтр).
|
||||
|
||||
3. **Автозапись 4 типов** (`source="auto"`, best-effort, дедуп в окне; `transient_retry` — только на
|
||||
исчерпании бюджета ретраев): `gate_failure` (`stage_engine._handle_qg_failure_rollbacks`),
|
||||
`merge_hold` (`merge_gate._handle_merge_verify` HOLD), `transient_retry` (merge-retry/launcher
|
||||
transient budget-exhaustion), `deploy_degraded` (post-deploy `DEGRADED → set_repo_freeze`, урок
|
||||
слоя-3 «деплой OK / прод сломан», ET-8). Каждая врезка — одиночный вызов в защитном `try/except`.
|
||||
|
||||
4. **Эндпоинты** `GET /lessons` (read-only, фильтры), `POST /lessons` (ручная запись,
|
||||
`source="manual"`), `POST /lessons/{id}` (update — доклассификация `unknown`), + read-only ключ
|
||||
`"lessons": snapshot()` в `GET /queue`. При выключенном флаге → `{"enabled": false}`.
|
||||
|
||||
**Инвариант (нерушимый):** `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключи
|
||||
(`verdict:`/`result:`/`staging_status:`/`deploy_status:`/`security_status:`/`coverage_status:`) /
|
||||
схемы существующих таблиц — **байт-в-байт не тронуты**. Журнал не влияет на продвижение по стадиям.
|
||||
|
||||
## Композиция с существующими механизмами
|
||||
- **Self-hosting (общая БД):** аддитивная таблица; enduro не затронут (NFR-3).
|
||||
- **serial-gate (ORCH-088) / post-deploy (ORCH-021):** детектор `deploy_degraded` врезан рядом с
|
||||
`set_repo_freeze`, не меняя freeze-логику.
|
||||
- **merge-gate (ORCH-043/071/093):** `merge_hold`/`transient_retry` читают исход актора, не меняя
|
||||
классификатор/ретрай.
|
||||
- **metrics (ORCH-099):** журнал — историческая память петли (best-effort запись), `/metrics` —
|
||||
realtime-сырьё для sidecar; разные роли, оба observer-only.
|
||||
|
||||
## Условность и откат
|
||||
- Флаг `lessons_enabled` (env `ORCH_LESSONS_ENABLED`, дефолт `True`; kill-switch) +
|
||||
`lessons_dedup_window_s` / `lessons_query_limit_default`. `False` → полная инертность, нулевая
|
||||
регрессия, конвейер байт-в-байт прежний.
|
||||
- **never-raise** на всех публичных функциях и врезках (NFR-1) — сбой журнала не роняет конвейер.
|
||||
- Откат — флаг в `false` (мгновенно) или revert диффа; таблица не касается существующих.
|
||||
|
||||
## Последствия
|
||||
- **+** Машиночитаемые уроки — фундамент E2/E3/Стрим; атрибуция forward-proof (без передела живой БД).
|
||||
- **+** Нулевая регрессия; проверенный additive-observer-leaf шаблон → низкий риск; enduro изолирован.
|
||||
- **−** Рост таблицы (митигейшн: лёгкие строки + дедуп + budget-exhaustion; ретенция — будущее).
|
||||
- **−** Дедуп-запрос в `record()` (один indexed-SELECT, только `auto`).
|
||||
|
||||
## Ссылки
|
||||
- Локальный ADR: `docs/work-items/ORCH-098/06-adr/ADR-001-lessons-journal.md`
|
||||
- BRD/TRZ/AC: `docs/work-items/ORCH-098/01-brd.md`, `02-trz.md`, `03-acceptance-criteria.md`
|
||||
- Data/Infra/Risks: `docs/work-items/ORCH-098/08-data-requirements.md`, `07-infra-requirements.md`,
|
||||
`10-tech-risks.md`
|
||||
- Эпик: `docs/epics/self-evolution.md` (домен 0 «Фундамент», F2; петля 8A)
|
||||
- Сверено по коду: `src/serial_gate.py`, `src/coverage_gate.py`, `src/db.py`, `src/stage_engine.py`,
|
||||
`src/merge_gate.py`, `src/agents/launcher.py`, `src/main.py`, `src/qg/checks.py`.
|
||||
Reference in New Issue
Block a user