integ: merge ORCH-066 plane status model

# Conflicts:
#	CHANGELOG.md
#	docs/architecture/README.md
#	src/plane_sync.py
#	src/webhooks/plane.py
This commit is contained in:
stream
2026-06-08 06:34:37 +00:00
31 changed files with 2195 additions and 38 deletions

View File

@@ -147,15 +147,21 @@ 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)
# ORCH-059: the dedicated "Confirm Deploy" status is the prod-deploy trigger.
# fail-closed via .get — environments without the status (enduro / API
# fallback) resolve to None, so the branch simply never activates (no KeyError,
# no blind deploy). Checked before `approved` so the two gestures never alias.
confirm_state = proj_states.get("confirm_deploy")
if new_state == proj_states["in_progress"]:
# ORCH-066: start/resume trigger is `To Analyse` (human entry-point).
if new_state == proj_states["to_analyse"]:
await handle_status_start(data, project_id)
elif confirm_state and new_state == confirm_state:
await handle_confirm_deploy(data, project_id)
@@ -281,9 +287,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,
@@ -584,6 +595,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")
@@ -625,9 +640,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. "