mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(tasks): CEO-reject of a coordination root routes to pending, not needs_revision
A CEO reject sent the root to NEEDS_REVISION, but that status is developer-claim-only — a coordination/integration root (project_id NULL + product_id set) has no developer, so the Main PM that owns it could not re-claim, escalated to the Board, and the task deadlocked in blocked with no forward state. ceo_reject now detects the coordination root and routes it to PENDING (the Main PM's claim source) with the claim cleared, via the audited admin_set_status override (awaiting_ceo_approval->pending has no in-band transition). Non-coordination tasks keep the normal needs_revision->developer path. Test pending (test DB was down mid-incident).
This commit is contained in:
+22
-6
@@ -3970,7 +3970,13 @@ class TaskService(BaseService):
|
|||||||
else rejection_entry
|
else rejection_entry
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate transition with CEO role requirement
|
# A coordination/integration root (no repo of its own, carries a
|
||||||
|
# product) has no developer to revise it — NEEDS_REVISION is
|
||||||
|
# developer-claim-only, so it would deadlock the Main PM that owns the
|
||||||
|
# root. Such a root is routed to PENDING below instead; every other task
|
||||||
|
# takes the normal NEEDS_REVISION path back toward its developer.
|
||||||
|
is_coordination_root = task.project_id is None and task.product_id is not None
|
||||||
|
if not is_coordination_root:
|
||||||
self._validate_and_set_status(task, TaskStatus.NEEDS_REVISION, "ceo")
|
self._validate_and_set_status(task, TaskStatus.NEEDS_REVISION, "ceo")
|
||||||
|
|
||||||
# Surface the CEO's required changes through the task journal — the one
|
# Surface the CEO's required changes through the task journal — the one
|
||||||
@@ -3986,16 +3992,26 @@ class TaskService(BaseService):
|
|||||||
|
|
||||||
# Route the rejected task to whoever should drive the rework.
|
# Route the rejected task to whoever should drive the rework.
|
||||||
reassigned_to: str | None
|
reassigned_to: str | None
|
||||||
if task.project_id is None and task.product_id is not None:
|
if is_coordination_root:
|
||||||
# Coordination/integration root: the Main PM delegates the rework — a
|
# Coordination/integration root: the Main PM re-plans and
|
||||||
# board/dev role cannot drive a coordination task.
|
# re-delegates the rework — a board/dev role cannot drive it. Land it
|
||||||
|
# in PENDING (the Main PM's claim source), claim cleared, so it
|
||||||
|
# re-enters plan→delegate. awaiting_ceo_approval→pending has no
|
||||||
|
# in-band transition, so use the audited privileged override.
|
||||||
main_pm_id = UUID(AGENT_UUIDS["main-pm"])
|
main_pm_id = UUID(AGENT_UUIDS["main-pm"])
|
||||||
task.team = Team.MAIN_PM
|
task.team = Team.MAIN_PM
|
||||||
task.assigned_to = cast("Any", main_pm_id)
|
task.assigned_to = cast("Any", main_pm_id)
|
||||||
task.claimed_by = cast("Any", main_pm_id)
|
task.claimed_by = None
|
||||||
reassigned_to = str(main_pm_id)
|
reassigned_to = str(main_pm_id)
|
||||||
|
await self.session.flush()
|
||||||
|
await self.admin_set_status(
|
||||||
|
task_id,
|
||||||
|
TaskStatus.PENDING,
|
||||||
|
actor_role="ceo",
|
||||||
|
actor_id=AGENT_UUIDS["ceo"],
|
||||||
|
)
|
||||||
self.log.info(
|
self.log.info(
|
||||||
"Coordination task rejected by CEO - routed to Main PM",
|
"Coordination task rejected by CEO - routed to Main PM (pending)",
|
||||||
task_id=str(task_id),
|
task_id=str(task_id),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user