analyst(ET): auto-commit from analyst run_id=777
All checks were successful
CI / test (push) Successful in 1m13s
All checks were successful
CI / test (push) Successful in 1m13s
This commit is contained in:
171
docs/work-items/ORCH-120/01-brd.md
Normal file
171
docs/work-items/ORCH-120/01-brd.md
Normal file
@@ -0,0 +1,171 @@
|
||||
---
|
||||
work_item: ORCH-120
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
escalate: full-cycle
|
||||
---
|
||||
|
||||
# 01 — BRD (бизнес-требования): ORCH-120 — Открытые вопросы аналитика должны переводить задачу в Needs Input
|
||||
|
||||
Work Item: **ORCH-120** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
> ⚠️ **Эскалация в полный цикл (`escalate: full-cycle`).** Это формально баг (метка `BUG:` в
|
||||
> заголовке), но фикс требует архитектурных решений (правило приоритета веток в
|
||||
> `_handle_analysis_approved_flow`, интеграция с осью «пауза» ORCH-124, семантика устаревания
|
||||
> `01-questions.md`, стандартизация нового pipeline-артефакта) — нужен ADR. Поэтому выпущен
|
||||
> **полный** analysis-пакет (01/02/03/04), а не облегчённый bug-shaped. Оператор снимает багфикс-трек
|
||||
> командой `POST /bug-fast-track/escalate?work_item=ORCH-120`, после чего задача идёт через стадию
|
||||
> `architecture` (ADR-001 D5 ORCH-019). Открытые проектные вопросы для архитектора — §6 (DQ-1…DQ-4).
|
||||
|
||||
## 1. Бизнес-контекст и проблема
|
||||
|
||||
При запуске конвейера аналитик (`analyst`) получает бизнес-запрос и **обязан** выпустить 4 файла
|
||||
(`01-brd` / `02-trz` / `03-acceptance-criteria` / `04-test-plan.yaml`), иначе exit-гейт стадии
|
||||
`analysis` не пройдёт. Если бизнес-запрос неоднозначен или неполон (классический пример — тело
|
||||
запроса `Description: TBD`), у аналитика **нет рабочего канала** запросить уточнения у заказчика: он
|
||||
вынужден **домысливать** требования и всё равно сдать 4 файла. Сфабрикованный пакет уходит в
|
||||
`In Review` / `architecture` — то есть весь конвейер строит решение поверх выдуманных требований.
|
||||
|
||||
**Парадокс:** механизм «вопросы → Needs Input» в движке **уже есть, но мёртв**. Код
|
||||
`src/stage_engine.py::_handle_analysis_approved_flow` (стр. 769–786) читает файл
|
||||
`docs/work-items/<wid>/01-questions.md` и при его наличии вызывает `set_issue_needs_input(...)` +
|
||||
комментарий в Plane + Telegram. Однако:
|
||||
|
||||
1. **Контракт не доведён до аналитика.** Промпт `.openclaw/agents/analyst.md` **нигде** не упоминает
|
||||
`01-questions.md`: ни в `<deliverables>`, ни в `<task>`. Скелета `docs/_templates/01-questions.md`
|
||||
нет, в манифесте `docs/_standards/PIPELINE_DOCS.md` артефакт не описан. Аналитик физически не
|
||||
знает, что у него есть канал «задать блокирующий вопрос», поэтому домысливает.
|
||||
2. **Ошибка приоритета веток.** В `_handle_analysis_approved_flow` ветка `files_ok` (все 4 файла на
|
||||
месте — `check_analysis_complete`) проверяется **первой** и делает `return` (стр. 711–767). Ветка
|
||||
`01-questions.md` (стр. 769) достижима, только если 4 файла НЕ полны. Значит, если аналитик сдал и
|
||||
неполный/заглушечный пакет, и `01-questions.md` — движок уйдёт в `In Review`, проигнорировав
|
||||
блокирующие вопросы. «Есть вопросы» должно иметь приоритет над «файлы на месте».
|
||||
3. **Needs-Input блокирует serial-gate репо.** Задача в Needs Input остаётся в стадии `analysis`
|
||||
(Plane-статус — слой B индикации, ORCH-066, **не** меняет `tasks.stage`) и при этом
|
||||
`paused_at IS NULL`. По правилу serial-gate (ORCH-088) такая «активная» задача держит FIFO репо
|
||||
закрытым: пока заказчик не ответит (часы/дни), ни одна следующая задача `orchestrator` не войдёт в
|
||||
`analysis`. ORCH-124 ввёл ортогональную ось «пауза» (`tasks.paused_at` + `POST /serial-gate/pause|
|
||||
resume`) ровно для случая «приостановлено, но не блокирует» — Needs-Input обязан её использовать.
|
||||
4. **Нет гигиены устаревшего `01-questions.md`.** После ответа заказчика `handle_status_start`
|
||||
перезапускает аналитика (`src/webhooks/plane.py:317–381`). Если перезапущенный аналитик теперь
|
||||
выпускает полный валидный пакет, старый `01-questions.md` остаётся в ветке. Без правила
|
||||
«устаревания» он либо игнорируется (если `files_ok` побеждает), либо вечно перезапускает Needs
|
||||
Input (если вопросы получат приоритет). Нужно явное правило supersede.
|
||||
|
||||
Корень — **разрыв контракта между промптом аналитика и движком** плюс **3 смежных дефекта потока**
|
||||
(приоритет, блокировка очереди, устаревание). ORCH-120 закрывает их как единый «правильный поток
|
||||
Needs Input».
|
||||
|
||||
**Связь с предшественниками (контекст резюма из бэклога):** задача разморожена после корневых
|
||||
фиксов **ORCH-124** (ось «пауза без блокировки» — необходимый фундамент для требования BR-3) и
|
||||
**ORCH-126** (queued-job не застревает со stale `run_id`/`pid` — гарантирует, что перезапущенный
|
||||
после ответа аналитик-job реально заберётся из очереди). Оба — предусловия, а не объём ORCH-120.
|
||||
|
||||
## 2. Объём (scope)
|
||||
|
||||
### В объёме
|
||||
- **Контракт промпта аналитика:** `.openclaw/agents/analyst.md` явно документирует канал
|
||||
«блокирующие открытые вопросы → пиши `01-questions.md`, НЕ фабрикуй 4 deliverables», с форматом и
|
||||
правилом поведения на перезапуске (прочитать ответы, снять устаревшие вопросы).
|
||||
- **Канон артефакта:** скелет `docs/_templates/01-questions.md` + строка в манифесте
|
||||
`docs/_standards/PIPELINE_DOCS.md` (артефакт-сигнал Needs Input; **не** machine-verdict-док, гейтом
|
||||
не парсится).
|
||||
- **Приоритет веток в движке:** в `_handle_analysis_approved_flow` блокирующие открытые вопросы
|
||||
получают корректный приоритет → задача с вопросами надёжно достигает Needs Input.
|
||||
- **Неблокирование serial-gate:** переход в Needs Input не держит FIFO репо закрытым неопределённо
|
||||
долго (интеграция с осью «пауза» ORCH-124).
|
||||
- **Гигиена устаревания:** перезапущенный аналитик, выпустивший полный валидный пакет без свежих
|
||||
вопросов, приводит к `In Review`, а не к повторному Needs Input.
|
||||
- **Корректность resume-петли:** ответ заказчика → перезапуск аналитика → снятие паузы (unpark), job
|
||||
забирается из очереди.
|
||||
- **Обязательный регресс-тест** (красный до фикса, зелёный после) + анти-дрейф структурные тесты.
|
||||
|
||||
### Вне объёма
|
||||
- **Расширение владения Needs Input на других агентов.** ORCH-066 BR-10 фиксирует: Needs Input —
|
||||
только у аналитика. Механизм не расширяется на architect/developer/reviewer/tester/deployer.
|
||||
- **Новые QG-проверки и новые рёбра `STAGE_TRANSITIONS`.** Поток вопросов — pre-gate-ветка движка,
|
||||
не Quality Gate. `check_analysis_complete`/`check_analysis_approved` — байт-в-байт.
|
||||
- **Изменение семантики самого гейта `analysis`** (4 файла по-прежнему обязательны для прохождения
|
||||
exit-гейта `analysis → architecture`).
|
||||
- **Авто-ответ на вопросы / LLM-триаж ответов заказчика.** Ответы читает человек/аналитик, а не
|
||||
отдельный автомат.
|
||||
- **Машинерия багфикс-трека (ORCH-019)** и любые изменения вне аналитической стадии.
|
||||
|
||||
## 3. Заинтересованные стороны
|
||||
- **Заказчик / оператор (Слава)** — получает осмысленный запрос уточнений вместо выдуманных
|
||||
требований; отвечает в Plane и возвращает задачу в работу.
|
||||
- **Конвейер `orchestrator` (self-hosting)** — перестаёт строить решения поверх домыслов; serial-gate
|
||||
репо не клинит на задаче, ждущей человека.
|
||||
- **Аналитик-агент** — получает легитимный канал «не знаю — спрошу» вместо принуждения к фабрикации.
|
||||
- **Другие проекты на общем инстансе (enduro-trails)** — не затронуты (нулевая регрессия при
|
||||
отсутствии `01-questions.md` и вне self-hosting-области).
|
||||
|
||||
## 4. Бизнес-требования (BR)
|
||||
- **BR-1** — Аналитик, столкнувшийся с **блокирующей** неоднозначностью бизнес-запроса, ОБЯЗАН иметь
|
||||
документированный канал запроса уточнений (`01-questions.md`) и НЕ должен фабриковать 4 deliverables
|
||||
«лишь бы пройти гейт». Промпт `.openclaw/agents/analyst.md` описывает этот канал.
|
||||
- **BR-2** — Наличие блокирующих открытых вопросов переводит задачу в Plane-статус **Needs Input** и
|
||||
**останавливает** продвижение по конвейеру (не `In Review`, не `architecture`), даже если на диске
|
||||
присутствуют частичные/заглушечные deliverables. Приоритет «вопросы» > «файлы на месте».
|
||||
- **BR-3** — Задача в Needs Input **не блокирует** per-repo serial-gate FIFO неопределённо долго:
|
||||
следующая задача `orchestrator` может войти в `analysis`, пока первая ждёт ответа человека.
|
||||
- **BR-4** — После ответа заказчика (возврат issue в рабочий статус) аналитик перезапускается, читает
|
||||
ответы и выпускает пакет. Если пакет полон и валиден и свежих блокирующих вопросов нет → задача
|
||||
переходит в `In Review` (устаревший `01-questions.md` не должен повторно ронять её в Needs Input).
|
||||
- **BR-5** — Поведение **обратимо и выборочно**: при отсутствии `01-questions.md` и выключенных
|
||||
под-флагах поток Needs Input/паузы — байт-в-байт как до ORCH-120 (нулевая регрессия для enduro и
|
||||
для штатной задачи без вопросов).
|
||||
- **BR-6** — `01-questions.md` стандартизирован как pipeline-артефакт (скелет в `docs/_templates/` +
|
||||
строка манифеста `PIPELINE_DOCS.md`): он сигнальный, **не** machine-verdict (гейтом не парсится).
|
||||
|
||||
## 5. Нефункциональные требования (NFR)
|
||||
- **NFR-1 (never-raise / fail-safe)** — Любая ошибка новой логики (чтение файла, park-вызов,
|
||||
определение приоритета) НЕ роняет `advance_stage`/launcher и деградирует к безопасному прежнему
|
||||
поведению (как существующие leaf'ы `serial_gate`/`labels`/`cancel`).
|
||||
- **NFR-2 (обратная совместимость)** — Стадии, кроме `analysis`, и Needs-Input-владение (ORCH-066) —
|
||||
не трогаются. `STAGE_TRANSITIONS` / `QG_CHECKS` / `check_*` / machine-verdict-ключи / семантика
|
||||
exit-гейта `analysis` — байт-в-байт.
|
||||
- **NFR-3 (инварианты serial-gate)** — Интеграция с паузой не регрессирует ORCH-088 (анти-stale-base:
|
||||
отложенный срез ветки) и ORCH-124 (терминал `{done,cancelled}` и оси `task_deps`/`freeze` —
|
||||
не читают `paused_at`; пауза их не обходит).
|
||||
- **NFR-4 (self-hosting-безопасность)** — Поток только меняет Plane-статус/паузу/комментарий и читает
|
||||
worktree: не деплоит, не рестартит прод-контейнер, не пушит в `main`, не трогает detached-процессы.
|
||||
- **NFR-5 (наблюдаемость)** — Переход в Needs Input и park/unpark логируются структурно; состояние
|
||||
паузы видно в блоке `serial_gate` `GET /queue` (ORCH-124 уже отдаёт `paused`).
|
||||
|
||||
## 6. Допущения и ограничения
|
||||
- **Допущение:** механизм чтения `01-questions.md` и `set_issue_needs_input` рабочие — задача в
|
||||
основном **активирует и достраивает** существующий путь, а не строит его с нуля.
|
||||
- **Допущение:** промпт `cat`-ается из worktree в момент запуска (ORCH-077 loading-model) → новый
|
||||
контракт аналитика вступает в силу на следующем worktree от `main` без прод-рестарта.
|
||||
- **Ограничение:** Plane-статус **Needs Input** должен существовать на доске проекта (ключ
|
||||
`needs_input` уже в `plane_sync._DEFAULT_STATES`) — инфра-предусловие выполнено для ORCH.
|
||||
- **Открытые проектные вопросы для архитектора (решить в `06-adr/`, НЕ в analysis):**
|
||||
- **DQ-1** — Парковать задачу при Needs Input **автоматически** (`db.set_task_paused` в момент
|
||||
перехода) или оставить park **операторским** (`POST /serial-gate/pause`)? Trade-off:
|
||||
авто-park снимает риск стопора очереди (BR-3), но связывает индикацию (слой B) с осью планировщика.
|
||||
- **DQ-2** — Механизм устаревания `01-questions.md` (BR-4): удалять файл при выпуске полного пакета /
|
||||
приоритет по «вопросы свежее deliverables» (mtime/commit) / явный маркер «answered». Любой выбор
|
||||
обязан быть детерминированным и не зависеть от сетевого Plane.
|
||||
- **DQ-3** — Точное правило приоритета в `_handle_analysis_approved_flow`: проверять
|
||||
`01-questions.md` ДО `files_ok`, либо ввести предикат «вопросы активны» с учётом DQ-2.
|
||||
- **DQ-4** — Коллизия номера `01-questions.md` с `01-brd.md`. Движок читает именно `01-questions.md`
|
||||
(`stage_engine.py:771`) — менять путь = код-изменение; стандарт документирует фактический путь.
|
||||
- **Ограничение по флагам:** новое поведение (приоритет вопросов / авто-park) — под kill-switch с
|
||||
безопасным дефолтом, чтобы откат был байт-в-байт (BR-5).
|
||||
|
||||
## 7. Критерии успеха
|
||||
Аналитик при блокирующей неоднозначности пишет `01-questions.md`, задача надёжно переходит в Needs
|
||||
Input, **не** блокирует serial-gate репо, после ответа заказчика возобновляется и выпускает корректный
|
||||
пакет; при отсутствии вопросов — поведение прежнее. Детальные PASS/FAIL — `03-acceptance-criteria.md`.
|
||||
|
||||
## 8. Риски
|
||||
- Связывание индикации (Plane-статус) с осью планировщика (пауза) при авто-park (DQ-1) — риск
|
||||
непреднамеренного park; смягчение — kill-switch + явный лог.
|
||||
- Устаревший `01-questions.md` зацикливает Needs Input (DQ-2) — смягчение детерминированным
|
||||
supersede-правилом + регресс-тест BR-4.
|
||||
- Регресс serial-gate (ORCH-088/124) при неаккуратной интеграции паузы — смягчение тестами NFR-3.
|
||||
Детали и оценка — `10-tech-risks.md` (заполняет архитектор).
|
||||
111
docs/work-items/ORCH-120/02-trz.md
Normal file
111
docs/work-items/ORCH-120/02-trz.md
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
work_item: ORCH-120
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 02 — ТЗ (TRZ): ORCH-120 — Открытые вопросы аналитика → Needs Input
|
||||
|
||||
Work Item: **ORCH-120** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
> ТЗ описывает **конкретные изменения к реализации**, выведенные из BRD и фактического кода.
|
||||
> Архитектурное обоснование (выбор механизма приоритета, авто-park vs operator-park, способ
|
||||
> устаревания `01-questions.md`) — задача архитектора (`06-adr/`). Открытые проектные вопросы —
|
||||
> BRD §6 (DQ-1…DQ-4).
|
||||
|
||||
## 1. Сводка изменения
|
||||
|
||||
Активировать и достроить уже существующий, но мёртвый путь «аналитик задаёт блокирующие вопросы →
|
||||
задача в Needs Input». Четыре связанных изменения: (1) **контракт промпта** аналитика +
|
||||
**канон артефакта** `01-questions.md`; (2) **приоритет** ветки вопросов над веткой «файлы готовы» в
|
||||
`_handle_analysis_approved_flow`; (3) **неблокирование serial-gate** через ось «пауза» ORCH-124;
|
||||
(4) **гигиена устаревания** `01-questions.md` на resume-петле. `STAGE_TRANSITIONS`, реестр `QG_CHECKS`,
|
||||
семантика и имена `check_*`, machine-verdict-ключи, схема существующих таблиц — **не меняются**.
|
||||
|
||||
## 2. Задействованные модули / пути
|
||||
|
||||
| Путь | Действие |
|
||||
|------|----------|
|
||||
| `.openclaw/agents/analyst.md` | **изменить** — добавить контракт «блокирующие вопросы → `01-questions.md`, не фабриковать deliverables» (в `<task>` + `<deliverables>` + поведение на resume); сохранить канон 52d (5 секций, 6 полей frontmatter). |
|
||||
| `docs/_templates/01-questions.md` | **создать** — скелет артефакта открытых вопросов (формат: контекст / список блокирующих вопросов с вариантами / что разблокирует анализ). |
|
||||
| `docs/_standards/PIPELINE_DOCS.md` | **изменить** — строка манифеста §2 для `01-questions.md` (владелец `analyst`, категория `when-applicable`, стадия `analysis`, «механизм: ветка Needs Input в `_handle_analysis_approved_flow`», machine-key — «нет, сигнальный»). |
|
||||
| `src/stage_engine.py` | **изменить** — `_handle_analysis_approved_flow`: правило приоритета (вопросы активны → Needs Input до/вместо `files_ok`, см. DQ-3); опц. вызов park (DQ-1); гигиена устаревания (DQ-2). Всё never-raise. |
|
||||
| `src/webhooks/plane.py` | **изменить (точечно)** — `handle_status_start` (analysis-resume ветка, стр. 317–381): при перезапуске аналитика снять паузу (`clear_task_paused`/`POST` эквивалент), чтобы re-enqueued job был claimable. |
|
||||
| `src/db.py` | **переиспользовать** — `set_task_paused` / `clear_task_paused` / `is_task_paused` (ORCH-124, уже есть; новых колонок НЕ вводить). |
|
||||
| `src/serial_gate.py` | **не менять кодом** — ось «пауза» уже исключает `paused_at NOT NULL` (ORCH-124); ORCH-120 лишь корректно её триггерит. |
|
||||
| `src/config.py` | **изменить** — добавить kill-switch(и) нового поведения (напр. `analyst_questions_gate_enabled`, опц. `analyst_needs_input_autopause_enabled`), env `ORCH_*`, безопасные дефолты. |
|
||||
| `src/main.py` | **возможно** — наблюдаемость в блоке `GET /queue` (если потребуется доп. поле); pause/resume эндпоинты ORCH-124 переиспользуются как есть. |
|
||||
|
||||
> Точный набор правок в `src/**` финализирует архитектор (DQ-1…DQ-3). TRZ фиксирует **наблюдаемый
|
||||
> контракт**, а не конкретную реализацию ветвления.
|
||||
|
||||
## 3. Функциональные требования
|
||||
|
||||
### FR-1 — Контракт промпта аналитика (BR-1, BR-6)
|
||||
`.openclaw/agents/analyst.md` явно описывает: при **блокирующей** неоднозначности бизнес-запроса
|
||||
аналитик пишет `docs/work-items/<plane-id>/01-questions.md` (через Write tool) со списком конкретных
|
||||
блокирующих вопросов и **не** выпускает сфабрикованные 4 deliverables. Указывается поведение на
|
||||
перезапуске: прочитать свежие комментарии-ответы в Plane, снять/не переписывать устаревшие вопросы,
|
||||
выпустить полный пакет. Промпт остаётся в каноне 52d (5 секций, 6 полей schema, без `model:`).
|
||||
|
||||
### FR-2 — Приоритет «вопросы активны» (BR-2)
|
||||
В `_handle_analysis_approved_flow` наличие **активных** блокирующих вопросов (`01-questions.md`,
|
||||
с учётом supersede-правила DQ-2) ведёт к `set_issue_needs_input(...)` + комментарий + Telegram +
|
||||
`result.note = "analysis-needs-input"` **независимо** от того, присутствуют ли на диске 4 файла.
|
||||
Сейчас ветка `files_ok` (стр. 711) делает `return` до проверки вопросов (стр. 769) — порядок/предикат
|
||||
исправляется так, что вопросы имеют приоритет. Happy-path (нет вопросов, 4 файла) → `In Review`
|
||||
(`analysis-in-review`) без изменений.
|
||||
|
||||
### FR-3 — Неблокирование serial-gate (BR-3, NFR-3)
|
||||
Переход в Needs Input приводит к тому, что задача **исключается** из «активного» предиката serial-gate
|
||||
(ORCH-088), чтобы следующая задача `orchestrator` могла войти в `analysis`. Механизм — ось «пауза»
|
||||
ORCH-124: `paused_at NOT NULL` уже исключается в `build_claim_clause`/`repo_has_active_task`/
|
||||
`_per_repo_snapshot`. Авто-park vs operator-park — DQ-1. Терминал `{done,cancelled}` и оси
|
||||
`task_deps`/`freeze` не читают `paused_at` — пауза их не обходит (инвариант ORCH-124 цел).
|
||||
|
||||
### FR-4 — Resume + unpark (BR-4)
|
||||
`handle_status_start` (analysis-ветка) при перезапуске аналитика после ответа заказчика снимает паузу
|
||||
(`clear_task_paused`), чтобы re-enqueued analyst-job был claimable (совместно с фиксом ORCH-126 о
|
||||
stale `run_id`/`pid`). Существующий relaunch-guard ORCH-090 (relaunch только для `analysis`) — не
|
||||
ослабляется.
|
||||
|
||||
### FR-5 — Гигиена устаревания `01-questions.md` (BR-4)
|
||||
Перезапущенный аналитик, выпустивший полный валидный пакет (4 файла) **без свежих** блокирующих
|
||||
вопросов, приводит к `In Review`, а не к повторному Needs Input. Реализация supersede — DQ-2
|
||||
(детерминированно, offline, без сетевого Plane).
|
||||
|
||||
### FR-6 — Обратимость / kill-switch (BR-5)
|
||||
Новое поведение под kill-switch с безопасным дефолтом: при отсутствии `01-questions.md` и выключенном
|
||||
под-флаге поток Needs Input/паузы — **байт-в-байт** как до ORCH-120. Скоуп — self-hosting
|
||||
(`orchestrator`); enduro не затронут.
|
||||
|
||||
## 4. Изменения API
|
||||
**Нет новых эндпоинтов.** Переиспользуются существующие `POST /serial-gate/pause` и
|
||||
`POST /serial-gate/resume` (ORCH-124, `src/main.py:396/442`) как операторский путь park/unpark (если
|
||||
архитектор выберет operator-park, DQ-1). При авто-park вызывается `db.set_task_paused` напрямую из
|
||||
движка. Блок `serial_gate` в `GET /queue` уже отдаёт `paused` — возможно дополнение полем-причиной.
|
||||
|
||||
## 5. Изменения схемы БД
|
||||
**Нет.** Колонка `tasks.paused_at` уже введена ORCH-124 (`src/db.py:160`, `_ensure_column`). Новых
|
||||
таблиц/колонок/индексов ORCH-120 не вводит.
|
||||
|
||||
## 6. Требования к новым/изменённым QG checks
|
||||
**Нет.** `01-questions.md` — сигнальный артефакт, **не** machine-verdict-док; гейтом не парсится.
|
||||
`check_analysis_complete` / `check_analysis_approved` / `_parse_*` — байт-в-байт. Поток вопросов
|
||||
остаётся pre-gate-веткой движка (`_handle_analysis_approved_flow`), как и был.
|
||||
|
||||
## 7. Совместимость / регресс
|
||||
- **Обратная совместимость:** при отсутствии `01-questions.md` ветвление `_handle_analysis_approved_flow`
|
||||
и serial-gate работают как прежде (NFR-2). Стадии ≠ `analysis` — не трогаются.
|
||||
- **Kill-switch:** новое поведение (приоритет вопросов / авто-park) выключаемо → откат байт-в-байт
|
||||
(FR-6/BR-5). Область — self-hosting `orchestrator`.
|
||||
- **Инварианты:** ORCH-066 (Needs Input только у аналитика) — не расширяется; ORCH-088/124 (анти-stale-base,
|
||||
терминал/freeze/deps оси) — не регрессируют (NFR-3); never-raise (NFR-1); self-hosting-безопасность
|
||||
(NFR-4: без прод-рестарта/`main`-push).
|
||||
- **Полный регресс** `pytest tests/` остаётся зелёным; обязательный новый регресс-тест (TC-01) красный
|
||||
до фикса и зелёный после.
|
||||
- **Трассировка маркеров (ORCH-078):** правки в `_handle_analysis_approved_flow`/`serial_gate`/
|
||||
`plane.py` сверяются с ADR ORCH-066 / ORCH-088 / ORCH-124 перед изменением (не сломать инварианты).
|
||||
142
docs/work-items/ORCH-120/03-acceptance-criteria.md
Normal file
142
docs/work-items/ORCH-120/03-acceptance-criteria.md
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
work_item: ORCH-120
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
---
|
||||
|
||||
# 03 — Критерии приёмки (Acceptance Criteria): ORCH-120 — Открытые вопросы аналитика → Needs Input
|
||||
|
||||
Work Item: **ORCH-120** · Repo: **orchestrator** · Стадия: analysis
|
||||
|
||||
Формат: каждый критерий имеет **PASS** (что должно быть истинно для приёмки) и **FAIL** (что
|
||||
считается провалом). Reviewer проверяет их буквально по файлам репозитория и тестам.
|
||||
|
||||
---
|
||||
|
||||
## AC-1 — Приоритет вопросов над «файлы готовы» (регресс, обязательный)
|
||||
|
||||
**Условие:** `_handle_analysis_approved_flow` вызывается после аналитика, в worktree присутствуют
|
||||
ОДНОВРЕМЕННО все 4 файла (`01-brd`/`02-trz`/`03-acceptance-criteria`/`04-test-plan.yaml`) И
|
||||
`01-questions.md` с активными блокирующими вопросами.
|
||||
- **PASS:** вызывается `set_issue_needs_input(work_item_id)`, `result.note == "analysis-needs-input"`,
|
||||
`set_issue_in_review` НЕ вызывается, задача НЕ продвигается на `architecture`.
|
||||
- **FAIL:** задача уходит в `In Review` / `architecture` (текущее ошибочное поведение — ветка
|
||||
`files_ok` побеждает).
|
||||
|
||||
---
|
||||
|
||||
## AC-2 — Только вопросы, без deliverables (сохранение существующего поведения)
|
||||
|
||||
**Условие:** `01-questions.md` присутствует, 4 файла отсутствуют.
|
||||
- **PASS:** `set_issue_needs_input` вызван, `result.note == "analysis-needs-input"`, текст вопросов
|
||||
передан в Plane-комментарий и Telegram.
|
||||
- **FAIL:** задача не переходит в Needs Input или падает с исключением.
|
||||
|
||||
---
|
||||
|
||||
## AC-3 — Happy-path без регресса
|
||||
|
||||
**Условие:** `01-questions.md` отсутствует, все 4 файла на месте.
|
||||
- **PASS:** `set_issue_in_review` вызван, `result.note == "analysis-in-review"`, запрошен статус
|
||||
`Approved` (поведение байт-в-байт как до ORCH-120, включая autoApprove-ветку ORCH-089).
|
||||
- **FAIL:** задача ошибочно уходит в Needs Input либо happy-path-комментарий/статус изменился.
|
||||
|
||||
---
|
||||
|
||||
## AC-4 — Needs Input не блокирует serial-gate репо
|
||||
|
||||
**Условие:** задача A `orchestrator` в `analysis` переведена в Needs Input по `01-questions.md`;
|
||||
существует более поздняя задача B того же репо.
|
||||
- **PASS:** A исключена из «активного» предиката serial-gate (через `paused_at NOT NULL`, ось
|
||||
ORCH-124); B может войти в `analysis` (claim analyst-job B не блокируется задачей A).
|
||||
- **FAIL:** A продолжает держать FIFO репо закрытым (`repo_has_active_task` возвращает True из-за A),
|
||||
B не может стартовать, пока заказчик не ответит.
|
||||
|
||||
---
|
||||
|
||||
## AC-5 — Resume снимает паузу и перезапускает аналитика
|
||||
|
||||
**Условие:** заказчик ответил и вернул issue в рабочий статус (In Progress / To Analyse) на стадии
|
||||
`analysis`; активного job нет.
|
||||
- **PASS:** `handle_status_start` снимает паузу (`paused_at` → NULL) и enqueue'ит analyst-job; job
|
||||
забирается из очереди (не застревает со stale `run_id`/`pid`, ср. ORCH-126); relaunch-guard ORCH-090
|
||||
(только `analysis`) соблюдён.
|
||||
- **FAIL:** задача остаётся paused (job не claimable) ИЛИ перезапуск происходит на не-`analysis` стадии
|
||||
(нарушение ORCH-090).
|
||||
|
||||
---
|
||||
|
||||
## AC-6 — Гигиена устаревшего `01-questions.md`
|
||||
|
||||
**Условие:** перезапущенный аналитик выпустил полный валидный пакет (4 файла) без свежих блокирующих
|
||||
вопросов; устаревший `01-questions.md` от прошлого прогона мог остаться.
|
||||
- **PASS:** задача переходит в `In Review` (`analysis-in-review`), а НЕ повторно в Needs Input;
|
||||
supersede-правило (DQ-2) применено детерминированно и offline.
|
||||
- **FAIL:** устаревший `01-questions.md` повторно роняет задачу в Needs Input (бесконечная петля).
|
||||
|
||||
---
|
||||
|
||||
## AC-7 — Контракт промпта аналитика (анти-дрейф)
|
||||
|
||||
**Условие:** содержимое `.openclaw/agents/analyst.md`.
|
||||
- **PASS:** промпт документирует канал `01-questions.md` (блокирующие вопросы → Needs Input, не
|
||||
фабриковать deliverables) И сохраняет канон 52d (5 XML-секций, 6 полей frontmatter-схемы, без
|
||||
`model:`); `tests/test_agent_prompts_canon.py` зелёный, добавлен assert наличия контракта вопросов.
|
||||
- **FAIL:** канал не документирован, либо нарушен канон 52d, либо тест канона красный.
|
||||
|
||||
---
|
||||
|
||||
## AC-8 — Канон артефакта `01-questions.md`
|
||||
|
||||
**Условие:** наличие скелета и записи в манифесте.
|
||||
- **PASS:** `docs/_templates/01-questions.md` существует; `docs/_standards/PIPELINE_DOCS.md` содержит
|
||||
строку манифеста для `01-questions.md` (владелец `analyst`, категория `when-applicable`, механизм
|
||||
«ветка Needs Input», не machine-verdict).
|
||||
- **FAIL:** скелет или строка манифеста отсутствуют.
|
||||
|
||||
---
|
||||
|
||||
## AC-9 — Обратимость / нулевая регрессия
|
||||
|
||||
**Условие:** kill-switch нового поведения выключен ИЛИ репо вне self-hosting-области (enduro-trails).
|
||||
- **PASS:** ветвление `_handle_analysis_approved_flow` и serial-gate работают **байт-в-байт** как до
|
||||
ORCH-120; `STAGE_TRANSITIONS`/`QG_CHECKS`/`check_*`/machine-verdict/схема БД не изменены.
|
||||
- **FAIL:** обнаружено отличие поведения при выключенном флаге / для enduro.
|
||||
|
||||
---
|
||||
|
||||
## AC-10 — never-raise / self-hosting-безопасность
|
||||
|
||||
**Условие:** сбой новой логики (ошибка чтения файла, park-вызова, определения приоритета).
|
||||
- **PASS:** `advance_stage`/launcher не падает, деградирует к безопасному прежнему поведению + WARNING;
|
||||
поток не деплоит, не рестартит прод-контейнер, не пушит в `main`.
|
||||
- **FAIL:** исключение всплывает наружу / встаёт конвейер / затронут прод/`main`.
|
||||
|
||||
---
|
||||
|
||||
## AC-11 — Полный регресс зелёный
|
||||
|
||||
**Условие:** `pytest tests/ -q`.
|
||||
- **PASS:** вся сюита зелёная; новый обязательный регресс-тест (AC-1 / TC-01) красный на коде до фикса
|
||||
и зелёный после.
|
||||
- **FAIL:** любой тест красный, либо регресс-тест проходит и на дофиксовом коде (не доказывает баг).
|
||||
|
||||
---
|
||||
|
||||
## Сводная матрица AC ↔ FR/BR
|
||||
| AC | Покрывает |
|
||||
|----|-----------|
|
||||
| AC-1 | BR-2 / FR-2 (регресс) |
|
||||
| AC-2 | BR-2 / FR-2 |
|
||||
| AC-3 | BR-5 / FR-2 |
|
||||
| AC-4 | BR-3 / FR-3 |
|
||||
| AC-5 | BR-4 / FR-4 |
|
||||
| AC-6 | BR-4 / FR-5 |
|
||||
| AC-7 | BR-1 / BR-6 / FR-1 |
|
||||
| AC-8 | BR-6 / FR-1 |
|
||||
| AC-9 | BR-5 / FR-6 / NFR-2 |
|
||||
| AC-10 | NFR-1 / NFR-4 |
|
||||
| AC-11 | NFR-2 |
|
||||
88
docs/work-items/ORCH-120/04-test-plan.yaml
Normal file
88
docs/work-items/ORCH-120/04-test-plan.yaml
Normal file
@@ -0,0 +1,88 @@
|
||||
work_item: ORCH-120
|
||||
stage: analysis
|
||||
author_agent: analyst
|
||||
status: ready-for-review
|
||||
created_at: 2026-06-17
|
||||
model_used: claude-opus-4-8
|
||||
title: "Аналитик: открытые вопросы → Needs Input (приоритет, неблокирование serial-gate, resume)"
|
||||
framework: pytest
|
||||
scope: >
|
||||
Покрывает поток «блокирующие открытые вопросы аналитика → Needs Input»:
|
||||
приоритет ветки вопросов над «файлы готовы» (_handle_analysis_approved_flow),
|
||||
неблокирование per-repo serial-gate (ось паузы ORCH-124), resume+unpark,
|
||||
гигиена устаревшего 01-questions.md, контракт промпта и канон артефакта,
|
||||
never-raise и нулевая регрессия. Вне покрытия: расширение Needs Input на
|
||||
других агентов, новые QG/рёбра STAGE_TRANSITIONS, авто-ответ на вопросы.
|
||||
notes: >
|
||||
TC-01 — ОБЯЗАТЕЛЬНЫЙ регресс-тест: красный на коде ДО фикса (ветка files_ok
|
||||
побеждает → In Review), зелёный ПОСЛЕ. Тесты движка прогоняют
|
||||
_handle_analysis_approved_flow напрямую (launcher-путь), мокая plane_sync-
|
||||
сеттеры и используя временный worktree (паттерн tests/test_analyst_status_only_regression.py
|
||||
и tests/test_auto_approve_brd.py). Полный регресс pytest tests/ остаётся зелёным.
|
||||
|
||||
tests:
|
||||
- id: TC-01
|
||||
type: unit
|
||||
description: "РЕГРЕСС: 4 файла + активный 01-questions.md одновременно -> set_issue_needs_input вызван, note=='analysis-needs-input', set_issue_in_review НЕ вызван (приоритет вопросов, AC-1). Красный до фикса."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-02
|
||||
type: unit
|
||||
description: "01-questions.md есть, 4 файлов нет -> Needs Input, текст вопросов в Plane-комментарии и Telegram (AC-2, сохранение существующего поведения)."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-03
|
||||
type: unit
|
||||
description: "Happy-path: нет 01-questions.md, 4 файла на месте -> set_issue_in_review, note=='analysis-in-review', запрос статуса Approved (AC-3, нет регресса)."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-04
|
||||
type: integration
|
||||
description: "Задача A в analysis переведена в Needs Input (paused_at NOT NULL) -> serial_gate исключает её из активного предиката; задача B того же репо может войти в analysis (AC-4, неблокирование FIFO)."
|
||||
module: tests/test_orch120_serial_gate_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-05
|
||||
type: integration
|
||||
description: "Resume: возврат issue в рабочий статус на analysis при отсутствии активного job -> handle_status_start снимает паузу (paused_at->NULL) и enqueue'ит analyst-job; relaunch-guard ORCH-090 (только analysis) соблюдён (AC-5)."
|
||||
module: tests/test_orch120_resume_unpark.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-06
|
||||
type: unit
|
||||
description: "Гигиена устаревания: перезапущенный аналитик выпустил полный валидный пакет без свежих вопросов -> In Review, НЕ повторный Needs Input; supersede-правило детерминировано и offline (AC-6)."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-07
|
||||
type: unit
|
||||
description: "Анти-дрейф промпта: .openclaw/agents/analyst.md документирует канал 01-questions.md (блокирующие вопросы -> Needs Input, не фабриковать deliverables) и сохраняет канон 52d (5 секций, 6 полей, без model:) (AC-7)."
|
||||
module: tests/test_agent_prompts_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-08
|
||||
type: unit
|
||||
description: "Канон артефакта: docs/_templates/01-questions.md существует и docs/_standards/PIPELINE_DOCS.md содержит строку манифеста для 01-questions.md (владелец analyst, when-applicable, не machine-verdict) (AC-8)."
|
||||
module: tests/test_orch120_questions_artifact_canon.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-09
|
||||
type: unit
|
||||
description: "never-raise: сбой новой логики (ошибка чтения 01-questions.md / park-вызова) не роняет advance_stage, деградирует к безопасному прежнему поведению + WARNING (AC-10)."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-10
|
||||
type: unit
|
||||
description: "Обратимость: kill-switch выключен ИЛИ репо вне self-hosting (enduro-trails) -> ветвление _handle_analysis_approved_flow и serial-gate байт-в-байт как до ORCH-120 (AC-9)."
|
||||
module: tests/test_orch120_analyst_needs_input.py
|
||||
expected: PASS
|
||||
|
||||
- id: TC-11
|
||||
type: integration
|
||||
description: "Полный регресс pytest tests/ зелёный; STAGE_TRANSITIONS/QG_CHECKS/check_* снапшот не изменён (AC-11, NFR-2)."
|
||||
module: tests/test_stage_transitions_snapshot.py
|
||||
expected: PASS
|
||||
Reference in New Issue
Block a user