auto-sync: 2026-06-05 14:30:02

This commit is contained in:
Stream
2026-06-05 14:30:02 +03:00
parent b59f0224e2
commit 286e633e6a
2 changed files with 110 additions and 1 deletions

View File

@@ -418,7 +418,8 @@ Dev (session orch9_docs_canon) отработал, я проверила не с
- **БЛОКЕР 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 ГОТОВ → ПРОВЕРЕНО МНОЙ лично (PR #33):** diff только plane_sync.py+webhooks/plane.py+tests, 342 passed (+23), резолвинг живой (ET→b873d9eb/3020bbb7, ORCH→e331bfb3/795cc32f, UUID разные), enduro не сломан. get_project_states(project_id)+кэш+fallback _DEFAULT_STATES. ЖДЁТ МЕРЖА PR #33. После мержа → ребилд прода → проверка в контейнере → ORCH-16 старт.
- Полные карты UUID обоих проектов — в ТЗ (сняты с прода). ORCH-37 заведена (гигиена статусов Plane, Backlog, id 9ccc5490). 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`, мелкая, наполнена. Первая самодоработка-прогрев.

View File

@@ -0,0 +1,108 @@
# Dev Report: ORCH-10 — per-project Plane state resolution
Дата: 2026-06-05
Статус: DONE
## Задача
Устранить блокер запуска ORCH-задач: `src/plane_sync.py` хардкодил глобальный `PLANE_STATES` с UUID статусов только enduro-проекта. Webhook-сравнение `new_state == PLANE_STATES["in_progress"]` совпадало только с ET UUID `b873d9eb`, ORCH UUID `e331bfb3` игнорировался — pipeline никогда не стартовал для ORCH-задач.
## Сделано
- [x] Создана ветка `feature/ORCH-10-per-project-states` из `origin/main`
- [x] Прочитан и изучен существующий код `src/plane_sync.py`, `src/webhooks/plane.py`, `src/projects.py`
- [x] Реализован `get_project_states(project_id)` — динамический резолвинг UUID по проекту через Plane API
- [x] Добавлен `_DEFAULT_STATES` (= прежний `PLANE_STATES`), `PLANE_STATES` оставлен как alias
- [x] Добавлен кэш `_STATES_CACHE` per project_id и функция `reload_project_states()`
- [x] Добавлен `stage_to_state(stage, project_id)` через `get_project_states`
- [x] `update_issue_state()` переключён на `stage_to_state()` вместо `STAGE_TO_STATE` dict
- [x] Все `set_issue_*()` функции резолвят UUID через `get_project_states(project_id)`
- [x] `webhooks/plane.py::handle_issue_updated()` — сравнение через `get_project_states(project_id)` вместо глобального `PLANE_STATES`
- [x] `webhooks/plane.py::start_pipeline()` QG-0 blocked path — `get_project_states(plane_project_id)["blocked"]`
- [x] Написаны 23 новых теста в `tests/test_orch10_states.py`
- [x] `pytest tests/ -q` — 342 passed (было 319, +23)
- [x] Коммит: `fix(plane): resolve issue states per-project instead of hardcoded enduro UUIDs (ORCH-10)`
- [x] Push ветки и создание PR #33
## Изменённые файлы
| Файл | Что изменено |
|------|-------------|
| `src/plane_sync.py` | `_DEFAULT_STATES` + `PLANE_STATES` alias; `_STATES_CACHE`; `get_project_states()`; `reload_project_states()`; `_PLANE_NAME_TO_KEY`; `_STAGE_TO_STATE_KEY`; `stage_to_state()`; `update_issue_state()``stage_to_state()`; все `set_issue_*()` через `get_project_states()` |
| `src/webhooks/plane.py` | `handle_issue_updated()`: `proj_states = get_project_states(project_id)`, сравнение per-project; `start_pipeline()` QG-0: `get_project_states(plane_project_id)["blocked"]` |
| `tests/test_orch10_states.py` | 23 новых теста (NEW FILE) |
## Результат
### pytest
```
342 passed, 4 warnings in 9.66s
```
Было 319, стало 342 (+23 ORCH-10 теста). Ни один существующий тест не сломан.
### git diff --name-status origin/main..feature/ORCH-10-per-project-states
```
M src/plane_sync.py
M src/webhooks/plane.py
A tests/test_orch10_states.py
```
Только разрешённые файлы. `qg/checks.py`, launcher, queue — не тронуты.
### PR
**#33** — https://git.mva154.duckdns.org/admin/orchestrator/pulls/33
Ветка: `feature/ORCH-10-per-project-states``main`. Мержить НЕ нужно (Стрим смержит вручную после ревью).
## Проверка всех критериев ТЗ
1. **pytest tests/ -q** — ✅ 342 passed (было 319)
2. **get_project_states(ET) → ET-UUID; get_project_states(ORCH) → ORCH-UUID** — ✅
- `test_get_project_states_enduro`: все 14 ET UUID совпадают
- `test_get_project_states_orchestrator`: все 14 ORCH UUID совпадают
- `test_get_project_states_et_in_progress_uuid`: ET `in_progress` = `b873d9eb-993c-48cd-97ac-99a9b1623967`
- `test_get_project_states_orch_in_progress_uuid`: ORCH `in_progress` = `e331bfb3-e17e-4699-ba48-4abb89c21b7b`
3. **webhook in_progress распознаётся для обоих проектов** — ✅
- `test_webhook_in_progress_et_starts_pipeline`: ET `b873d9eb``handle_status_start` called
- `test_webhook_in_progress_orch_starts_pipeline`: ORCH `e331bfb3``handle_status_start` called
- `test_webhook_et_in_progress_not_confused_with_orch`: ET UUID в ORCH-проекте НЕ триггерит
4. **Fallback при недоступном API → _DEFAULT_STATES** — ✅
- `test_get_project_states_api_error_fallback`: Exception → `_DEFAULT_STATES`
- `test_get_project_states_non_200_fallback`: HTTP 500 → `_DEFAULT_STATES`
- `test_get_project_states_empty_response_fallback`: пустой results → `_DEFAULT_STATES`
- `test_get_project_states_none_project_id_fallback`: None → `_DEFAULT_STATES` без API-вызова
5. **git diff --name-status** — ✅ только `plane_sync.py`, `webhooks/plane.py`, `tests/`
## Архитектура резолвинга/кэша
```
get_project_states(project_id: str) -> dict[str, str]
├── if project_id in _STATES_CACHE -> return cached
├── GET /api/v1/workspaces/{WORKSPACE}/projects/{project_id}/states/
│ ├── success → map by _PLANE_NAME_TO_KEY, fill missing from _DEFAULT_STATES
│ │ → _STATES_CACHE[project_id] = resolved; return resolved
│ └── failure → log warning; return _DEFAULT_STATES (ET values, safe fallback)
└── None project_id → _DEFAULT_STATES immediately
stage_to_state(stage, project_id) -> str | None
└── _STAGE_TO_STATE_KEY[stage] -> logical key
└── get_project_states(project_id)[key] -> UUID
```
**Кэш**: `_STATES_CACHE: dict[str, dict[str,str]]` — per project_id, не протухает (процесс перезапускает). `reload_project_states(project_id=None)` — для тестов и ручного сброса.
**Backward compat**: `PLANE_STATES` = `_DEFAULT_STATES` (alias). `STAGE_TO_STATE` оставлен как статический dict на ET-значениях (для тестов). `update_issue_state()` теперь вызывает `stage_to_state()` вместо него.
## Проблемы и решения
**Проблема**: `$()` в bash-heredoc-е SSH интерпретировался шеллом → bash command substitution error.
**Решение**: файлы передавались через `base64 | ssh 'base64 -d > file'` — без heredoc.
**Проблема**: `git commit -m` с Python-кодом в строке вызывал bash syntax error.
**Решение**: многострочный `-m` отдельной строкой через SSH; bash-парсер затронул только переменные типа `$()` — commit прошёл корректно.
## Следующий шаг
Отправить на ревью → Стрим мержит PR #33 → ребилд docker-образа → ручная проверка на проде.