feat(plane): осмысленная статусная модель Plane (слой B — индикация)
Приводит статусы доски Plane к смыслу стадий конвейера, сохраняя инвариант «статус — индикация, а не управление». Меняется только слой B (отображение: src/plane_sync.py + точки выставления статуса в stage_engine.py/webhooks/plane.py/reconciler.py); слой A — машина стадий src/stages.py::STAGE_TRANSITIONS — остаётся байт-в-байт неизменным (AC-21). - 6 новых логических ключей статуса (to_analyse, analysis, code_review, awaiting_deploy, deploying, monitoring) + сеттеры и диспетчер set_issue_stage_state. - Project-relative alias-fallback (BR-12): новый ключ деградирует на базовый UUID того же проекта → нулевая регрессия для enduro-trails. - Самодеплой (ORCH-036) индицирует фазы: Awaiting Deploy / Deploying; terminal-sync для self-hosting → Monitoring after Deploy, для прочих → терминальный Done. - Post-deploy монитор (ORCH-021): HEALTHY → Done, DEGRADED → Blocked (только индикация; self-hosting ALERT_ONLY, прод не трогается, BR-5). - Reconciler: триггер старта/резюма на To Analyse; Guard 2 учитывает новые активные ожидания без расширения skip-set на алиасах. - never-raise контракт сеттеров и резолвера состояний сохранён. - Раскатка — созданием статусов в Plane оператором, без kill-switch. Инварианты не менялись: STAGE_TRANSITIONS, QG_CHECKS (12 чеков), check_deploy_status, exit-код-контракт хука, merge-gate, схема БД. ADR: docs/work-items/ORCH-066/06-adr/ADR-001-plane-status-model.md Тесты: test_plane_status_model, test_plane_to_analyse_resume, test_plane_status_failclosed + TC в существующих наборах. 774 passed. Refs: ORCH-066 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,10 +147,15 @@ async def handle_issue_updated(data: dict, project_id: str = ""):
|
||||
return
|
||||
|
||||
# ORCH-10: resolve expected state UUIDs per the incoming issue's project so
|
||||
# both enduro (b873d9eb) and orchestrator (e331bfb3) In Progress trigger the
|
||||
# both enduro (b873d9eb) and orchestrator (e331bfb3) statuses trigger the
|
||||
# pipeline. Using PLANE_STATES["in_progress"] here was the root-cause blocker.
|
||||
# ORCH-066: the start/resume trigger is now `To Analyse` (human entry-point),
|
||||
# which discharges `In Progress` of its overloaded "start the pipeline"
|
||||
# meaning. Fail-closed: on a project without the `To Analyse` status,
|
||||
# `to_analyse` aliases to the project's own `in_progress` UUID, so moving an
|
||||
# enduro issue to In Progress still triggers start/resume (AC-17).
|
||||
proj_states = get_project_states(project_id)
|
||||
if new_state == proj_states["in_progress"]:
|
||||
if new_state == proj_states["to_analyse"]:
|
||||
await handle_status_start(data, project_id)
|
||||
elif new_state == proj_states["approved"]:
|
||||
await handle_verdict(data, project_id, approved=True)
|
||||
@@ -235,9 +240,14 @@ async def handle_status_start(data: dict, project_id: str = ""):
|
||||
)
|
||||
job_id = enqueue_job(stage_agent, repo, task_desc, task_id=task_id)
|
||||
logger.info(
|
||||
f"Task {task_id}: returned to In Progress (Needs Input answered), "
|
||||
f"Task {task_id}: returned to To Analyse (Needs Input answered), "
|
||||
f"relaunched {stage_agent} for stage {current_stage} (job_id={job_id})"
|
||||
)
|
||||
# ORCH-066 (AC-3): a resume of the analyst (the only Needs-Input owner) is
|
||||
# re-indicated as `Analysis`; other stages keep their own indication.
|
||||
if current_stage == "analysis":
|
||||
from ..plane_sync import set_issue_analysis as _set_analysis
|
||||
_set_analysis(work_item_id)
|
||||
try:
|
||||
_add_comment(
|
||||
work_item_id,
|
||||
@@ -538,6 +548,10 @@ async def start_pipeline(data: dict, project_id: str = ""):
|
||||
)
|
||||
job_id = enqueue_job("analyst", repo, task_desc, task_id=task_id)
|
||||
logger.info(f"Task {task_id}: enqueued analyst (job_id={job_id})")
|
||||
# ORCH-066 (AC-3): indicate the analysis stage with the dedicated
|
||||
# `Analysis` status (degrades to In Progress where it is not created).
|
||||
from ..plane_sync import set_issue_analysis as _set_analysis
|
||||
_set_analysis(work_item_id, plane_project_id)
|
||||
# Post start comment to Plane
|
||||
from ..plane_sync import add_comment as _add_comment
|
||||
_add_comment(work_item_id, "\U0001f50d Analyst \u0437\u0430\u043f\u0443\u0449\u0435\u043d. BRD/\u0422\u0417/AC/TestPlan \u0432 \u0440\u0430\u0431\u043e\u0442\u0435 (\u043e\u0436\u0438\u0434\u0430\u0439\u0442\u0435 8-15 \u043c\u0438\u043d).", author="analyst")
|
||||
@@ -579,9 +593,11 @@ async def _rollback_stage(
|
||||
(via the existing rollback notify + an enqueue of the prev-stage agent).
|
||||
"""
|
||||
if current_stage == "analysis":
|
||||
# Already in analysis — just relaunch analyst with rejection reason
|
||||
from ..plane_sync import set_issue_in_progress
|
||||
set_issue_in_progress(work_item_id)
|
||||
# Already in analysis — just relaunch analyst with rejection reason.
|
||||
# ORCH-066 (AC-3): indicate `Analysis` (degrades to In Progress where the
|
||||
# status is not created).
|
||||
from ..plane_sync import set_issue_analysis
|
||||
set_issue_analysis(work_item_id)
|
||||
task_desc = (
|
||||
f"Work item: {work_item_id}\nRepo: {repo}\nBranch: {branch}\n"
|
||||
f"Stage: analysis\nNote: Stakeholder REJECTED your artifacts. "
|
||||
|
||||
Reference in New Issue
Block a user