feat(board): gate CEO Approve & Start on board-review completion

A board/coordination task stays pending throughout board review — that
pending state is what hands it to Main PM on approval — so the CEO's
Approve & Start button was live from the instant the task was created,
before the Product Owner and Head of Marketing had reviewed anything.
That let the CEO approve before the board finished.

Persist a board_review_complete flag the orchestrator sets once BOTH
board reviewers are done, and gate the button on it (the task stays
pending). The same handoff emits the formal CEO notification, so the
CEO gets an actionable signal instead of buried channel chatter.

- alembic 021: add tasks.board_review_complete (default false)
- TaskService.mark_board_review_complete: set the flag without leaving pending
- orchestrator: flag the task + notify CEO once both reviewers go idle
- panel: Approve & Start requires board_review_complete
This commit is contained in:
Renn F
2026-06-03 08:06:41 +02:00
parent 056ff41293
commit ceb4eec6ca
10 changed files with 181 additions and 69 deletions
@@ -364,16 +364,20 @@ export default function TaskDetailPage({ params }: TaskDetailPageProps) {
{/* CEO gate #1: Approve & Start a board-reviewed coordination task.
This is the handoff for a board/fan-out task (a product, no repo of its
own) that the Board has reviewed and is waiting on the CEO to hand to
Main PM. The server's approve_and_start requires the task to still be
PENDING (it re-targets to Main PM without a status change), so we gate
on PENDING — NOT awaiting_ceo_approval, which is the unrelated
end-of-work CEO gate handled by the ceo-approve flow. We also require a
coordination task (no project_id, has product_id) so the button only
shows on the board's fan-out handoffs, not on every board-team task. */}
Main PM. The server's approve_and_start keeps the task PENDING (it
re-targets to Main PM without a status change — that pending state is
what drives Main PM dispatch), so we gate on PENDING here, NOT on
awaiting_ceo_approval (the unrelated end-of-work ceo-approve flow).
The button must not appear until the board has actually finished
reviewing, so we also require board_review_complete — the flag the
orchestrator sets once BOTH the PO and Head of Marketing are done. The
coordination predicate (no project_id, has product_id) keeps the
button to the board's fan-out handoffs, not every board-team task. */}
{task.status === TaskStatus.PENDING &&
task.team === Team.BOARD &&
!task.project_id &&
!!task.product_id && (
!!task.product_id &&
task.board_review_complete === true && (
<div className="flex justify-end">
<ApproveAndStartButton task={task} />
</div>
+3
View File
@@ -280,6 +280,9 @@ export interface Task {
// PR Tracking (parallel execution in awaiting_documentation)
docs_complete: boolean;
pr_created: boolean;
// True once PO + Head of Marketing have both reviewed a pending board task.
// Gates the CEO's Approve & Start button (the task stays pending throughout).
board_review_complete?: boolean;
pm_approvals: Record<string, boolean>;
// Planning
plan: TaskPlan | null;