diff --git a/memory/2026-06-05.md b/memory/2026-06-05.md index b404f36..ecdf3ad 100644 --- a/memory/2026-06-05.md +++ b/memory/2026-06-05.md @@ -413,6 +413,20 @@ Dev (session orch9_docs_canon) отработал, я проверила не с - Архив доставки: `temp/orch_docs_canon.tgz` → slin `/tmp/orch_docs_canon.tgz` - Отчёт Dev: `tasks/orchestrator/reports/dev-2026-06-05-orch9-docs-canon.md` +### ЗАПУСК САМОДОРАБОТКИ — ревью готовности (05.06, Слава: «Старт», таска ORCH-16): +- **БЛОКЕР 1 УСТРАНЁН:** прод-образ отставал (checks.py без is_self_hosting_repo). Ребилд из main `5ecd1c4` (ОК Славы). Постпроверка: checks.py=main `3f9fe07`, is_self_hosting_repo(enduro)=False/(orchestrator)=True, staging-gate enduro=пропуск, 6 ET-задач на месте, 319 passed. Прод синхронен. (Тесты НЕ в образе — Dockerfile COPY только src/+data/, гонять из /repos/orchestrator или CI.) +- **БЛОКЕР 2 = ORCH-10 (в работе):** plane_sync.py хардкодит PLANE_STATES = UUID СТАТУСОВ ТОЛЬКО ENDURO. ORCH-проект имел 5 базовых статусов, нет стадийных. Слава: «сделать в ORCH такую же статусную модель как в ET, недостающие добавить». + - **СДЕЛАЛА:** создала 9 недостающих статусов в ORCH-проекте через Plane API (Architecture/Development/Review/Testing/Approved/Rejected/Needs Input/In Review/Blocked) — теперь 14 шт, идентично ET по составу. UUID НОВЫЕ (свои у ORCH). + - **Dev запущен** (orch10_states, session 305f824d): ТЗ `DEV_TASK_ORCH10_PER_PROJECT_STATES.md` — динамический резолвинг статусов по project_id (get_project_states + кэш + fallback _DEFAULT_STATES). КРИТИЧНО: webhook-сравнение in_progress резолвить по проекту (иначе ORCH-задача не стартует). Ветка feature/ORCH-10-per-project-states. + - Полные карты UUID обоих проектов — в ТЗ (сняты с прода). ORCH-16 ОСТАЛАСЬ в Backlog (мой PATCH state упал 400 — и хорошо, конвейер НЕ запущен). В описание ORCH-16 дописаны ответы на 2 вопроса (текст+ссылка+1-строка вердикт; один коммент на агента). +- **ПОРЯДОК:** ORCH-10 (Dev) → ребилд прода → проверка резолвинга лично → ТОГДА ORCH-16 Backlog→In Progress (старт конвейера). +- ORCH-16 = «Единообразные коммент-артефакты в Plane» id `2b80c58c-2a83-4ab0-aa69-b7f5d2f8c345`, мелкая, наполнена. Первая самодоработка-прогрев. + +### КЛЮЧЕВЫЕ PLANE state-id (оба проекта): +- **ORCH** in_progress `e331bfb3-e17e-4699-ba48-4abb89c21b7b`, backlog `2d5d42ff-...`, done `3738cd3c-...`. Стадийные: architecture `795cc32f`, development `f5ed4705`, review `2026f3d9`, testing `81c5cd78`, approved `63f2c8fe`, rejected `4c769e90`, needs_input `99978b3f`, in_review `c52e99b9`, blocked `505f01a6`. +- **ET** in_progress `b873d9eb-...` (остальные — в ТЗ ORCH-10 и plane_sync.py PLANE_STATES). +- ORCH-проект plane_id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`, ET plane_id `7a79f0a9-5278-49cd-9007-9a338f238f9c`. + ### ФАКТЫ ОРКА (золотой источник, для будущих сессий): - НЕТ Makefile, НЕТ budget.yaml (в отличие от enduro). Тесты: `pytest tests/ -q` (из .gitea/workflows/ci.yml). CI = Gitea Actions. - Прод 8500, staging 8501 (изолированная БД ./data/staging, profile staging, только sandbox-проект). External: https://openclaw.mva154.duckdns.org/orchestrator/. Webhook: .../orchestrator/webhook/gitea (+ /webhook/plane). diff --git a/tasks/orchestrator/DEV_TASK_ORCH10_PER_PROJECT_STATES.md b/tasks/orchestrator/DEV_TASK_ORCH10_PER_PROJECT_STATES.md new file mode 100644 index 0000000..f2ce3a0 --- /dev/null +++ b/tasks/orchestrator/DEV_TASK_ORCH10_PER_PROJECT_STATES.md @@ -0,0 +1,103 @@ +# DEV TASK — ORCH-10: per-project резолвинг Plane-статусов + +**Проект:** orchestrator | **Сервер:** slin@82.22.50.71 (pw motoZ@yaz2010) | **Репо:** /home/slin/repos/orchestrator +**Ветка:** `feature/ORCH-10-per-project-states` из свежего origin/main (`git fetch && git checkout main && git pull --ff-only && git checkout -b feature/ORCH-10-per-project-states`). +**PR push в main ЗАПРЕЩЁН, НЕ мержить.** Коммит в ветку + PR в Gitea. + +## ПРОБЛЕМА (корень) +`src/plane_sync.py` хардкодит `PLANE_STATES` — UUID статусов ТОЛЬКО enduro-проекта (`7a79f0a9`). В коде уже стоит `TODO(ORCH-10): these UUIDs are PER-PROJECT ... do NOT hardcode globally`. При онбординге orchestrator-проекта (`8da6aa25`) синхронизация статусов на доске ломается: орк пытается выставить ET-шный UUID в ORCH-проект → статус не найден. + +**Статусы в обоих проектах УЖЕ созданы и идентичны по составу (14 шт), но UUID разные.** Нужен резолвинг по project_id. + +## ГОТОВЫЕ ДАННЫЕ (не выдумывай — это снято с прода Стрим) + +### enduro-trails (project_id `7a79f0a9-5278-49cd-9007-9a338f238f9c`): +``` +backlog 113b24f6-cce8-4be9-9a22-a359b9cf0122 +todo 2c7d3df3-9eb9-419b-92b7-d7d560bcdd10 +in_progress b873d9eb-993c-48cd-97ac-99a9b1623967 +architecture 3020bbb7-6122-4663-930c-0315ba8dfa3d +development 9920609b-f140-4e46-ab95-89acda8412c8 +review ba0d802c-5218-41d4-ab43-978b0ea123ed +testing 7855d807-b1bf-42ef-8dae-6cde0df92d02 +approved a519a341-dada-4a91-8910-7604f82b79c5 +rejected ba958f3c-5db5-461d-8f82-89425e413b97 +done 381a2833-3c4e-4be5-bd0f-be84cb946ad8 +cancelled b1cae7f9-961d-4889-a179-f3acea697d17 +needs_input babf08a3-ff4d-41f3-a821-5491aa29a8ac +in_review 38fb1f64-aa1e-48a3-92e0-0b109679046b +blocked 6c4543f9-ac47-4ef7-ae0f-070020dc9920 +``` + +### orchestrator (project_id `8da6aa25-a60e-44d6-a1e2-d8ae59aa7d6a`): +``` +backlog 2d5d42ff-e94d-4209-a664-8020c28c2a95 +todo b5d3f512-4870-460f-bf6b-4ea560f00a6f +in_progress e331bfb3-e17e-4699-ba48-4abb89c21b7b +architecture 795cc32f-5f5a-4244-be7b-9acffc92c7c0 +development f5ed4705-5029-470d-89a9-54c3f0d211ee +review 2026f3d9-0f43-4054-ab5f-3f9bae3308b8 +testing 81c5cd78-2993-4f2c-9e8c-2f52db3e5623 +approved 63f2c8fe-dcda-4ace-952f-dd88bd0118ff +rejected 4c769e90-bf80-4a52-b97a-e1c84904bfc3 +done 3738cd3c-7610-4907-ba5e-26b9a248d9c0 +cancelled 59d1d210-8e3a-4a83-930a-cbc5dbf6ad85 +needs_input 99978b3f-72fe-46e3-8b9b-25ba02899fa0 +in_review c52e99b9-31ae-4b31-be3f-9773eea7a747 +blocked 505f01a6-a12f-4121-aaa7-9c5dd009acc4 +``` + +## РЕШЕНИЕ (архитектура — согласовано) +**Динамический резолвинг статусов по project_id через Plane API + кэш**, с fallback на статический дефолт (текущие ET-значения = safe default). + +### R1. Функция резолвинга +В `src/plane_sync.py` ввести: +```python +def get_project_states(project_id: str) -> dict[str, str]: + """Резолвит {логическое_имя -> state_id} для конкретного project_id. + Источник правды — Plane API GET /projects//states/. + Маппит Plane-имена статусов (по полю name) на логические ключи + (backlog/todo/in_progress/architecture/development/review/testing/ + approved/rejected/done/cancelled/needs_input/in_review). + Кэшируется per project_id (модульный dict, lazy). Если API недоступен — + fallback на статический _DEFAULT_STATES (текущие ET-значения). + """ +``` +- Маппинг Plane-name → логический ключ: `{"Backlog":"backlog","Todo":"todo","In Progress":"in_progress","Architecture":"architecture","Development":"development","Review":"review","Testing":"testing","Approved":"approved","Rejected":"rejected","Done":"done","Cancelled":"cancelled","Needs Input":"needs_input","In Review":"in_review","Blocked":"blocked"}`. +- Кэш: `_STATES_CACHE: dict[str, dict[str,str]]` per project_id. Функция `reload_project_states(project_id=None)` для сброса (по аналогии с `reload_projects`). +- `_DEFAULT_STATES` = текущий `PLANE_STATES` dict (ET-значения) — fallback при сбое API. + +### R2. Заменить хардкод-обращения PLANE_STATES[...] на резолвинг по проекту +Во ВСЕХ местах, где сейчас `PLANE_STATES["..."]` используется для записи статуса в КОНКРЕТНУЮ задачу — резолвить по project_id этой задачи. Точки (из грепа): +- `STAGE_TO_STATE` (строки 128-137) — сейчас статический dict на PLANE_STATES. Сделать функцией `stage_to_state(stage, project_id)` ИЛИ резолвить внутри `update_issue_state`/`set_issue_stage_state`. +- `update_issue_state` (285), `set_issue_stage_state` (362), `_set_issue_state_direct` (377) — уже принимают `project_id`; использовать его для резолвинга. +- `set_issue_needs_input`(333), `set_issue_in_review`(338), `set_issue_blocked`(343), `set_issue_done`(354), `set_issue_in_progress`(359) — резолвить по project_id. +- `STAGE_VISIBILITY_STATE`(117) + использование в `set_issue_stage_state`(371-374). + +### R3. Webhook-сравнения (src/webhooks/plane.py 140-152) +`if new_state == PLANE_STATES["in_progress"]` / approved / rejected — это СРАВНЕНИЕ входящего state с известными. Тут project_id известен из payload (`data.project` или резолв через registry по plane_project_id). Резолвить ожидаемые state-id ПО ПРОЕКТУ задачи: +- `in_progress` старт пайплайна, `approved`/`rejected` — вердикт-переходы. +- ⚠️ КРИТИЧНО: сравнение должно работать для ОБОИХ проектов. Сейчас сравнивает только с ET-UUID → для ORCH-задачи переход в In Progress (ORCH-UUID `e331bfb3`) НЕ распознаётся как старт! Это БЛОКЕР запуска ORCH-задач. Резолвить expected in_progress по project_id входящей задачи. + +### R4. project_id — откуда брать +В реестре `src/projects.py` есть `get_project_by_repo`/`get_project_by_plane_id`. project_id Plane = `ProjectConfig.plane_project_id`. Задача знает свой repo (tasks.repo) → резолв project_id через registry. Если в функции уже передаётся project_id — использовать его; если нет — резолвить через repo задачи. + +## ⛔ OFF-LIMITS / ГРАБЛИ +- НЕ менять QG-логику (`src/qg/checks.py`), очередь, launcher. +- НЕ ломать enduro: при project_id=enduro резолвинг ДОЛЖЕН давать те же UUID, что сейчас (тесты это проверят). +- НЕ создавать/удалять статусы в Plane (они УЖЕ созданы Стрим — только читать через API). +- PLANE_STATES оставить как `_DEFAULT_STATES` (fallback) — НЕ удалять, на него опираются тесты и аварийный режим. +- Кэш не должен протухать в пределах процесса, но `reload_project_states` для тестов/ручного сброса. +- Plane API base — тот же, что использует существующий код (`PLANE_BASE`, `WORKSPACE`, токен) — переиспользовать, не хардкодить URL. +- Санитайзер SSH-heredoc: `$(...)` экранировать. Запуск Python в проде: base64→docker cp→exec. + +## ПРОВЕРКА (пруф в отчёт) +1. `pytest tests/ -q` — все проходят (был 319; не ронять, добавить тесты на резолвинг). +2. Новый тест: `get_project_states(ET)` даёт ET-UUID; `get_project_states(ORCH)` даёт ORCH-UUID (значения из таблиц выше). +3. Новый тест: webhook in_progress распознаётся для ОБОИХ проектов (ORCH `e331bfb3` И ET `b873d9eb` → старт). +4. Fallback: при недоступном API `get_project_states` возвращает `_DEFAULT_STATES`. +5. `git diff --name-status origin/main..ветка` — затронуты только plane_sync.py, webhooks/plane.py (+ возможно stage_engine.py), tests/. НЕ qg/checks.py, НЕ launcher, НЕ queue. +6. Ручная проверка на проде НЕ требуется от тебя — Стрим проверит лично после ребилда. + +## РЕЗУЛЬТАТ +Отчёт → `tasks/orchestrator/reports/dev-2026-06-05-orch10-states.md`. Коммит: `fix(plane): resolve issue states per-project instead of hardcoded enduro UUIDs (ORCH-10)`. Верни: список файлов diff, новые тесты, результат pytest, номер PR, краткое описание подхода к резолвингу/кэшу.