From 382df76bb694cb36af317cc34fe08785214f6c21 Mon Sep 17 00:00:00 2001 From: Stream Date: Wed, 3 Jun 2026 18:20:10 +0300 Subject: [PATCH] auto-sync: 2026-06-03 18:20:01 --- .../reports/dev-2026-06-03-pipeline-ux.md | 91 ++++++++++++++----- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/tasks/orchestrator/reports/dev-2026-06-03-pipeline-ux.md b/tasks/orchestrator/reports/dev-2026-06-03-pipeline-ux.md index 6f226e0..a2da012 100644 --- a/tasks/orchestrator/reports/dev-2026-06-03-pipeline-ux.md +++ b/tasks/orchestrator/reports/dev-2026-06-03-pipeline-ux.md @@ -1,16 +1,16 @@ # Dev Report: Конвейер UX (4 фичи) Дата: 2026-06-03 -Статус: IN PROGRESS +Статус: DONE (PR открыт, НЕ мержён, НЕ задеплоен) ## Задача -Реализовать 4 UX-фичи оркестратора в ветке feature/pipeline-ux: +4 UX-фичи оркестратора в ветке `feature/pipeline-ux`: 1. Старт по статусу (In Progress), не по created -2. Вердикт-статусы Approved/Rejected (вариант B), комменты оставить рабочими +2. Вердикт-статусы Approved/Rejected (вариант B), комменты остаются рабочими 3. Видимость стадий на доске (6 новых UUID статусов) -4. Расход токенов по агентам (claude --output-format json, agent_runs +cols, комменты) +4. Расход токенов по агентам ## Реальный формат Plane webhook на смену статуса -Из таблицы `events` (event id=160), РЕАЛЬНЫЙ payload: +Поймал в таблице `events` (event id=160, 28 issue-событий, есть action=updated): ```json { "event": "issue", @@ -18,9 +18,8 @@ "data": { "id": "", "state": {"id": "", "name": "In Progress", "group": "started"}, - "project": "7a79f0a9-...", - "sequence_id": 2, - ... + "project": "7a79f0a9-5278-49cd-9007-9a338f238f9c", + "sequence_id": 2 }, "activity": { "field": "state", @@ -30,20 +29,68 @@ } } ``` -**Ключ:** `event="issue"`, `action="updated"`, `activity.field == "state"`, новый статус в `data.state.id` (== `activity.new_value`). +**Ключ:** `event="issue"`, `action="updated"`, новый статус в **`data.state.id`** (== `activity.new_value`). +Также поддержан вариант `data.state` как голая строка-UUID и алиас `work_item.updated`. -## Сделано -- [x] Изучил кодовую базу, baseline 166 passed / 9 pre-existing 401 -- [x] Поймал реальный payload смены статуса (28 issue-событий, есть action=updated) -- [ ] Фича 1 -- [ ] Фича 2 -- [ ] Фича 3 -- [ ] Фича 4 -- [ ] Тесты -- [ ] Push + PR +## Таблица: фича → файлы/функции +| Фича | Файлы | Ключевые функции | +|------|-------|------------------| +| 1. Старт по статусу | `src/webhooks/plane.py` | `plane_webhook` (dispatch `issue/updated`), `handle_issue_updated`, `handle_status_start`, `start_pipeline` (вынесено из `handle_work_item_created`), `_qg0_errors`; `handle_work_item_created` → только soft-лог | +| 2. Вердикт-статусы | `src/webhooks/plane.py`, `src/plane_sync.py` | `handle_verdict` (Approved→`_try_advance_stage`, Rejected→`_rollback_stage`), `_rollback_stage` (общий с `:rejected:`-коммент-веткой); UUID `approved`/`rejected` в `PLANE_STATES` | +| 3. Видимость стадий | `src/plane_sync.py` | `PLANE_STATES` +6 UUID, `STAGE_VISIBILITY_STATE`, `STAGE_TO_STATE` (arch/dev/review/testing → свои статусы), `set_issue_stage_state` | +| 4. Токены | `src/agents/launcher.py`, `src/db.py`, `src/usage.py` (новый) | `--output-format json` в claude-cmd; ALTER agent_runs (+input/output/cache_read/cost_usd, идемпотентно); `_monitor_agent` парсит usage; `_post_usage_comments`; `usage.py`: `parse_usage_from_text/log`, `record_usage`, `usage_comment`, `task_summary_comment` | -## Изменённые файлы -(заполняется по ходу) +## Идемпотентность / защита handle_comment (Фича 1) +`handle_status_start` проверяет `get_task_by_plane_id(plane_id)` — если задача уже есть, лог + return (НЕ дублит, НЕ перезапускает analyst). Поэтому `set_issue_in_progress` из `handle_comment` (approve/ответы) не триггерит повторный старт — задача к тому моменту уже в БД. -## Следующий шаг -Реализация фич. +## Token usage — формат коммента (вариант A) +Под именем агента (через `add_comment(author=role)`): +``` +💻 Developer готов · 45.2k in / 12.1k out · $0.21 +``` +Сводка Deployer на done (вариант B, SUM по agent_runs GROUP BY agent): +``` +📊 Итого по задаче: 1.5k токенов вход / 300 выход · $0.15 +• Developer: 1.0k in / 200 out · $0.10 +• Tester: 500 in / 100 out · $0.05 +``` + +## Боевой usage-парс (CLI 2.1.142, реальный вывод) +Запустил `claude --print --output-format json "Say hi"` в контейнере, прогнал `parse_usage_from_log`: +``` +PARSED: {'input_tokens': 6, 'output_tokens': 15, 'cache_read_tokens': 18500, 'cost_usd': 0.0560175} +AGENT COMMENT: 💻 Developer готов · 6 in / 15 out · $0.06 +``` +Реальные поля JSON: `total_cost_usd`, `usage.input_tokens`, `usage.output_tokens`, `usage.cache_read_input_tokens` — подтверждены вживую. + +## Тесты +Baseline: 166 passed, 9 pre-existing 401 (test_webhooks.py). +**Итог: 190 passed, 9 failed (те же 9 baseline, не тронуты).** +Новые (+24): +- `tests/test_status_trigger.py` — created не стартует; In Progress стартует analyst; повтор идемпотентен +- `tests/test_verdict_status.py` — Approved→advance, Rejected→rollback; комменты `:approved:`/`:rejected:` живы +- `tests/test_stage_visibility.py` — UUID в PLANE_STATES; set_issue_stage_state ставит верный UUID; analysis/deploy no-op; Needs Input/In Review/Blocked приоритетны +- `tests/test_usage.py` — парс реального CLI-JSON (в т.ч. с текстом перед JSON); NULL при битом JSON; запись; формат токенов k/M; сводка по задаче + +Изменены существующие тесты под новый триггер (created→issue/updated In Progress): +`tests/test_m6_sequence.py`, `tests/test_plane_webhook.py`, `tests/test_webhook_dedup.py`. + +## Git +- Ветка `feature/pipeline-ux` из свежего main (e9fd305). +- 4 коммита (Conventional Commits): + - `a4668c0` feat(plane): stage visibility on board + verdict status UUIDs + - `09b1c5e` feat(webhook): start pipeline on In Progress status (not on create) + - `38a741d` feat(webhook): verdict via Approved/Rejected statuses (variant B) + - `9a702a0` feat(metrics): per-agent token/cost accounting +- **Remote проверен** (ORCH-7 грабля): `git log origin/main..origin/feature/pipeline-ux` показывает все 4 коммита. +- **PR #10** → main: https://git.mva154.duckdns.org/admin/orchestrator/pulls/10 + +## Ограничения соблюдены +- БД Plane / nginx / openclaw.json / deploy-хук / HMAC / очередь / get_next_work_item_id / M-6 / per-agent authorship — НЕ тронуты (используются). +- ORCH-6 резолв проектов НЕ переделан; оставлен TODO(ORCH-10) в PLANE_STATES (статусы per-project). +- НЕ деплоил, НЕ мержил — мерж за Стримом после живой проверки. +- `.env.bak-*` (стрэй-бэкап) НЕ закоммичен. + +## Замечание для Стрима (живая проверка) +- Rejected-вердикт (и `:rejected:` коммент) теперь **перезапускает агента предыдущей стадии** (через `STAGE_AUTHORS[prev_stage]`) — это унифицировано для обоих механизмов (раньше коммент-ветка для non-analysis только откатывала без перезапуска). Так выполнено требование ТЗ «откат + перезапуск агента». +- Стадийные статусы видны на доске только в проекте enduro (UUID per-project). При онбординге новых проектов — ORCH-10.