auto-sync: 2026-06-07 23:50:01
This commit is contained in:
133
tasks/orchestrator/STATUS_MODEL_DEEP_ANALYSIS.md
Normal file
133
tasks/orchestrator/STATUS_MODEL_DEEP_ANALYSIS.md
Normal file
@@ -0,0 +1,133 @@
|
||||
# Глубокий аудит ядра орка под новую статусную модель
|
||||
|
||||
Дата: 2026-06-07 · Автор: Стрим · Уровень: ЯДРО (stage_engine/webhooks/plane_sync/stages)
|
||||
|
||||
## 0. Метод
|
||||
Прочитан реальный код прода: `src/stages.py`, `src/stage_engine.py`, `src/webhooks/plane.py`,
|
||||
`src/plane_sync.py`, `src/reconciler.py`. Ниже — что есть, какие зазоры с моделью, и что
|
||||
доработать. Каждый пункт — с привязкой к коду.
|
||||
|
||||
## 1. КРИТИЧЕСКОЕ различие: «стадия конвейера» ≠ «Plane-статус»
|
||||
Это два РАЗНЫХ слоя, их легко спутать и сломать.
|
||||
|
||||
### Слой A — STAGE_TRANSITIONS (`stages.py`) — машина СТАДИЙ (internal)
|
||||
```
|
||||
created → analysis → architecture → development → review → testing →
|
||||
deploy-staging → deploy → done
|
||||
```
|
||||
Каждая стадия: `{next, agent, qg}`. Это движок: какой агент запускается, какой QG-гейт
|
||||
проходится. **Здесь НЕТ Awaiting Deploy / Deploying / Monitoring** — это внутренние стадии,
|
||||
а наши новые статусы — отображение на доске Plane.
|
||||
|
||||
### Слой B — Plane-статусы (`plane_sync.py`) — ИНДИКАЦИЯ на доске
|
||||
`_STAGE_TO_STATE_KEY` маппит стадию → Plane-статус. Сейчас:
|
||||
- analysis → in_progress, deploy → in_progress (ПЕРЕГРУЗ), остальные → одноимённые.
|
||||
|
||||
### ⚠️ Вывод
|
||||
Новая модель меняет в основном **слой B (Plane-индикацию)** + точки, где Phase A/B/C ставят
|
||||
статусы вручную. **STAGE_TRANSITIONS трогать минимально** (риск регресса всего конвейера).
|
||||
Новые статусы — это переименования/добавления в маппинге + ручных set_issue_*.
|
||||
|
||||
## 2. Маппинг новой модели на стадии (что куда)
|
||||
| Стадия (слой A) | Сейчас Plane | НАДО (новая модель) | Как ставится |
|
||||
|---|---|---|---|
|
||||
| (человек жмёт старт) | In Progress | **To Analyse** (вход-триггер, переименование In Progress) | человек |
|
||||
| analysis | In Progress | **Analysis** (новый выходной) | орк при старте analyst |
|
||||
| analysis → approve-pending | In Review | In Review (без изменений) | `_handle_analysis_approved_flow` |
|
||||
| analysis → вопросы | Needs Input | Needs Input (уже есть!) | `set_issue_needs_input` (01-questions.md) |
|
||||
| architecture | Architecture | Architecture | stage_to_state |
|
||||
| development | Development | Development | stage_to_state |
|
||||
| review | Review | **Code-Review** (переименование) | stage_to_state |
|
||||
| testing | Testing | Testing | stage_to_state |
|
||||
| deploy-staging → Phase A | In Review | **Awaiting Deploy** | `_handle_self_deploy_phase_a` (стр 1012) |
|
||||
| deploy → Phase B старт | (In Progress) | **Deploying** | `_handle_self_deploy_phase_b` |
|
||||
| deploy → Phase C health-OK | Done | **Monitoring after Deploy** | deploy-finalizer |
|
||||
| post-deploy окно closed HEALTHY | (Done) | **Done** | post-deploy-monitor (ORCH-21) |
|
||||
| любой фейл деплоя/окна | Blocked | **Blocked** | set_issue_blocked |
|
||||
|
||||
## 3. Needs Input — ГЛАВНЫЙ запрос Славы. Что есть, чего нет.
|
||||
|
||||
### ✅ ЧТО УЖЕ РАБОТАЕТ (нашла в коде!)
|
||||
`_handle_analysis_approved_flow` (stage_engine.py ~502-549):
|
||||
- analyst пишет файл `docs/work-items/<WI>/01-questions.md` → орк видит его →
|
||||
`set_issue_needs_input(work_item_id)` + коммент «❓ Analyst нуждается в уточнении: ...».
|
||||
- **Возврат:** человек отвечает в Plane → переводит issue обратно в **In Progress** →
|
||||
`handle_status_start` видит существующий task + idle-агента → **relaunch analyst** (он
|
||||
читает свежие комменты). Механизм статус-driven.
|
||||
|
||||
### ❌ ЧЕГО НЕТ / зазоры
|
||||
1. **Needs Input ТОЛЬКО у analyst — ПОДТВЕРЖДЕНО ГРЕПОМ (Слава поправил).**
|
||||
`set_issue_needs_input` вызывается РОВНО в ОДНОМ месте во всём src/: `stage_engine.py:538`
|
||||
внутри `_handle_analysis_approved_flow`, у которой ЖЁСТКИЙ гард:
|
||||
`if not (agent == "analyst" and work_item_id): return`. Для любого НЕ-аналитика — просто return.
|
||||
`01-questions.md` захардкожен под analysis (префикс 01-), читается только там.
|
||||
=> architect/developer/reviewer/tester **ФИЗИЧЕСКИ НЕ МОГУТ** уйти в Needs Input. Механизма НЕТ.
|
||||
«И Т.Д.» = ПОСТРОИТЬ С НУЛЯ universal-механизм для всех стадий — ПОЛНОЦЕННАЯ фича (D6).
|
||||
2. **Возврат завязан на `In Progress`** (`handle_status_start`). Если переименуем In Progress
|
||||
→ To Analyse, **сломается возврат из Needs Input** (webhook слушает in_progress UUID).
|
||||
⚠️ ГРАБЛИ: либо возврат тоже на To Analyse, либо оставить отдельный «Resume»-триггер.
|
||||
3. **Нет матрицы разрешённых переходов** (вопрос Славы про «только доступные значения»).
|
||||
Plane не умеет (404 на transitions/). Нужен guard в `handle_issue_updated`.
|
||||
|
||||
## 4. Доработки ядра (полный список с приоритетом)
|
||||
|
||||
### P0 — без этого модель не работает
|
||||
- **D1.** `plane_sync.py`: добавить ключи/маппинг `to_analyse, analysis, code_review,
|
||||
awaiting_deploy, deploying, monitoring` в `_DEFAULT_STATES` + `_PLANE_NAME_TO_KEY` +
|
||||
обновить `_STAGE_TO_STATE_KEY` (analysis→analysis, review→code_review, deploy→deploying).
|
||||
Хелперы `set_issue_<status>`.
|
||||
- **D2.** `webhooks/plane.py` `handle_status_start`: триггер старта конвейера и возврата из
|
||||
Needs Input привязать к **To Analyse** (новый вход), НЕ к In Progress. Учесть fork
|
||||
«старт vs возврат» (как сейчас по active-job).
|
||||
- **D3.** Phase A (`_handle_self_deploy_phase_a`): `set_issue_in_review` → `set_issue_awaiting_deploy`.
|
||||
- **D4.** Phase B: при старте detached-деплоя ставить **Deploying**.
|
||||
- **D5.** Phase C / post-deploy: health-OK → **Monitoring after Deploy** (не Done); окно
|
||||
HEALTHY closed → **Done**; UNHEALTHY → **Blocked**.
|
||||
|
||||
### P1 — то, что Слава просит «и т.д.» (расширение Needs Input)
|
||||
- **D6 (ПОЛНОЦЕННАЯ ФИЧА, НЕ детект).** Universal «агент просит уточнение» для ВСЕХ стадий:
|
||||
(1) **договор сигнала**: агент пишет verdict-маркер `status: NEEDS_INPUT` в своём
|
||||
артефакте ИЛИ `NN-questions.md` — единый контракт для всех;
|
||||
(2) **детект для каждого агента** в advance_stage: сейчас ветка жёстко analyst-only
|
||||
(`if not (agent==analyst)`), надо вынести в общий pre-QG чек: NEEDS_INPUT →
|
||||
set_issue_needs_input + коммент + Telegram, НЕ запускать QG/advance;
|
||||
(3) **resume**: возврат relaunch'ит ТЕКУЩУЮ стадию. `handle_status_start` уже умеет
|
||||
relaunch по current_stage (переиспользуемо), НО триггерится только через In Progress —
|
||||
перепривязать на resume-триггер (D7).
|
||||
**Детект-сторона + контракт сигнала — ПОЛНОСТЬЮ НОВЫЕ.** + правка промптов всех агентов
|
||||
(научить писать NEEDS_INPUT когда застряли без ввода).
|
||||
- **D7.** Чёткий «Resume» semantics: из Needs Input/Blocked человек возвращает задачу — какой
|
||||
статус-триггер relaunch'ит текущую стадию? Предложение: отдельный вход **To Analyse**
|
||||
только для старта; для resume — возврат в статус ТЕКУЩЕЙ стадии ИЛИ спец-триггер. РЕШИТЬ.
|
||||
|
||||
### P2 — guard переходов (вопрос Славы про «только доступные»)
|
||||
- **D8.** `ALLOWED_TRANSITIONS` матрица (из нашей схемы) в коде. В `handle_issue_updated`:
|
||||
входящий человеческий переход проверяется по матрице {current_stage/status → allowed[]}.
|
||||
Недопустимый → revert статуса назад + коммент «Недопустимый переход. Разрешено: [...]».
|
||||
Это server-side state-machine вместо UI-ограничения (Plane его не умеет).
|
||||
|
||||
## 5. Грабли/риски (НЕ сломать прод)
|
||||
- **R1.** Переименование In Progress ломает 3 вещи: старт конвейера, возврат из Needs Input,
|
||||
и `_STAGE_TO_STATE_KEY[deploy]=in_progress`. Все три перепривязать атомарно.
|
||||
- **R2.** `reconciler.py` Guard 2 пропускает blocked/needs_input — при новых статусах
|
||||
проверить, что reconciler не «оживляет» Awaiting Deploy/Monitoring (это активные ожидания,
|
||||
не зависшие). Возможно добавить их в skip-список.
|
||||
- **R3.** fail-closed везде: нет статуса в проекте (enduro/fallback) → не падать, вести себя
|
||||
как раньше (как сделали в ORCH-59 AC-7).
|
||||
- **R4.** STAGE_TRANSITIONS НЕ менять (инвариант AC-9 из ORCH-59). Новые статусы — только
|
||||
индикация + ручные set_issue_*, не новые стадии конвейера.
|
||||
- **R5.** Идемпотентность: повторный webhook одного статуса → no-op (как Phase B marker).
|
||||
|
||||
## 6. Объём → 2 work item (предложение)
|
||||
- **WI-1 «Статусная модель + индикация»** (D1-D5): переименования/новые статусы, Phase A/B/C
|
||||
ставят правильные статусы, Monitoring-этап перед Done. Средний размер, хирургично.
|
||||
- **WI-2 «Needs Input для всех стадий + guard переходов»** (D6-D8): расширение clarification-
|
||||
механизма + server-side state-machine. Содержательный, можно отдельным PR после WI-1.
|
||||
+ Задача гигиены Plane (создать/переименовать статусы через API) — инфра-предусловие, делаю я.
|
||||
|
||||
## 7. Открытые решения Славе
|
||||
1. **Resume из Needs Input:** какой триггер relaunch'ит текущую стадию? (а) возврат в статус
|
||||
текущей стадии; (б) отдельный «Resume»-статус; (в) To Analyse только для analysis, для
|
||||
остальных — статус стадии. Влияет на D2/D7.
|
||||
2. **Один большой WI или два** (модель + needs-input/guard)?
|
||||
3. **Guard переходов сейчас или потом** (P2 можно отложить)?
|
||||
Reference in New Issue
Block a user