Files
orchestrator/docs/architecture/adr/adr-0034-lessons-journal.md
claude-bot 21a47e85d3
All checks were successful
CI / test (push) Successful in 56s
CI / test (pull_request) Successful in 55s
fix(lessons): resolve land-race with ORCH-100 — renumber ADR 0033→0034
Merge-gate auto_rebase_onto_main bounced this branch back: ORCH-100 landed
in main first and claimed global ADR number adr-0033 (adr-0033-sidecar-watchdog),
while this branch had created adr-0033-lessons-journal. Resolved the genuine
land race:

- rebased feature/ORCH-098-fnd onto current origin/main (linear history)
- resolved docs/architecture/README.md component-list conflict — both the
  Lessons-journal and Sidecar-watchdog bullets now coexist
- renamed docs/architecture/adr/adr-0033-lessons-journal.md →
  adr-0034-lessons-journal.md (next free global ADR number) + fixed the
  in-file header
- updated all cross-references (CLAUDE.md, README.md, work-item ADR-001,
  12-review.md) 0033→0034 for the lessons journal; ORCH-100's adr-0033
  (sidecar) left intact
- recovered the ORCH-098 CHANGELOG entry silently dropped by the rebase
  auto-merge (now above ORCH-100, ADR ref corrected to 0034)

No code semantics changed; src/** auto-merged cleanly (ORCH-100 did not
touch src/**). ruff: n/a locally (CI). pytest tests/ -q: 1630 passed.

Refs: ORCH-098
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 10:44:34 +03:00

93 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
work_item: ORCH-098
stage: architecture
author_agent: architect
status: proposed
created_at: 2026-06-10
model_used: claude-opus-4-8
---
# adr-0034: Машинный журнал уроков — таблица `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`.