docs: document multi-repo registry + ORCH-6 bugfix and incident
ORCH-6: ARCHITECTURE.md gets a project-registry section; README explains how to add a project via ORCH_PROJECTS_JSON; BUGFIXES_2026-06-03.md records the fix and links the 2026-06-02 webhook autorun incident.
This commit is contained in:
@@ -9,9 +9,39 @@ Orchestrator — event-driven FastAPI сервис, который управл
|
||||
### 1. Webhook Receivers
|
||||
|
||||
#### Plane Webhook (`src/webhooks/plane.py`)
|
||||
- Принимает `work_item.created` — создаёт задачу в DB, запускает analyst
|
||||
- **Фильтр по проекту (ORCH-6):** извлекает `data.project` (Plane project uuid) и игнорирует событие, если проект не в реестре (`known_plane_project_ids()`) → ответ `{"status":"ignored","reason":"unknown project"}`. Это предотвращает инцидент 2026-06-02 (webhook на весь workspace без фильтра).
|
||||
- Принимает `work_item.created` — резолвит repo/prefix/Plane-проект из реестра по `project`, создаёт задачу в DB, запускает analyst
|
||||
- Принимает `work_item.updated` — синхронизация статусов
|
||||
|
||||
#### Реестр проектов (`src/projects.py`, multi-repo, ORCH-6)
|
||||
Маппинг **Plane project id → (repo, work_item_prefix, name)**. Позволяет одному
|
||||
оркестратору обслуживать несколько репозиториев, не путая их.
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class ProjectConfig:
|
||||
plane_project_id: str # uuid Plane-проекта (ключ реестра)
|
||||
repo: str # имя gitea-репо (= папка в /repos)
|
||||
work_item_prefix: str # ET / ORCH
|
||||
name: str # человекочитаемое
|
||||
```
|
||||
|
||||
Резолверы:
|
||||
- `get_project_by_plane_id(uuid) -> ProjectConfig | None` — для фильтра/резолва в plane-webhook.
|
||||
- `get_project_by_repo(repo) -> ProjectConfig | None` — когда известен только repo (gitea-webhook, plane_sync).
|
||||
- `known_plane_project_ids() -> set[str]` — множество разрешённых проектов (фильтр).
|
||||
|
||||
**Источник конфигурации:** env `ORCH_PROJECTS_JSON` (JSON-массив `ProjectConfig`).
|
||||
Если пусто/битый JSON — используется встроенный дефолт-реестр (enduro-trails + orchestrator),
|
||||
чтобы система работала из коробки. Парсинг устойчив: битые записи пропускаются,
|
||||
полностью невалидный JSON → fallback на дефолт.
|
||||
|
||||
Следствия multi-repo:
|
||||
- **repo per project:** `repo = get_project_by_plane_id(project_id).repo` вместо хардкода `default_repo`.
|
||||
- **prefix per project:** `get_next_work_item_id(repo, prefix)` нумерует независимо — `ORCH-001` vs `ET-010` (`src/db.py`).
|
||||
- **plane_sync в правильный проект:** state/comment пишутся в Plane-проект самой задачи (резолв по repo через `get_project_by_repo`), а не в единственный хардкоженный `PROJECT_ID` (обратная совместимость сохранена дефолтом на enduro).
|
||||
- **gitea-webhook:** push в repo вне реестра → `ignored` (не триггерит конвейер).
|
||||
|
||||
#### Gitea Webhook (`src/webhooks/gitea.py`)
|
||||
- **push** — проверяет наличие артефактов (docs/, src/), продвигает стадию
|
||||
- **pull_request\*** (wildcard) — обрабатывает review approved/rejected, PR merge
|
||||
|
||||
Reference in New Issue
Block a user