Skip to content

Orchestrator: route open questions back to originator before approval (#11)#15

Merged
Joncallim merged 1 commit into
mainfrom
feat/issue-11-open-questions
Jun 22, 2026
Merged

Orchestrator: route open questions back to originator before approval (#11)#15
Joncallim merged 1 commit into
mainfrom
feat/issue-11-open-questions

Conversation

@Joncallim

Copy link
Copy Markdown
Owner

Closes #11.

What

Open questions raised by the architect are now sent back to the task originator and resolved before the plan can be approved.

  • Structured questions — the architect appends an open_questions_json fenced block; web/worker/open-questions.ts parses it (tolerant of malformed JSON), and questions are persisted to a new task_questions table (migration 0005).
  • New awaiting_answers state — a plan with unanswered questions moves the task to awaiting_answers instead of awaiting_approval (web/worker/orchestrator.ts, web/worker/task-state.ts).
  • Answer + re-plan loopPOST /api/tasks/[id]/questions records answers and enqueues a forge:answers job; the worker (AnswersQueueprocessAnsweredQuestions) re-runs the architect with the answers in context, then moves to awaiting_approval (or back to awaiting_answers if new questions arise).
  • UI — the task page renders a QuestionsPanel (wired to initial load + the SSE questions:created/questions:answered events) with answer inputs and resolved Q&A history; Approve stays gated until questions are resolved.

Finishing work done on top of the WIP

The background subagent completed the backend/worker/migration and the QuestionsPanel component but stopped before wiring it up. This PR:

  • wired QuestionsPanel into the page (consume questions from useTaskStream, load initial questions from the task GET, render + onAnswered refresh);
  • fixed a type error (QueueName was missing 'answers');
  • added unit tests for the parser and guard tests for the questions route.

Verification

  • npx tsc --noEmit
  • npx eslint .
  • npx vitest run → 76 passed ✓
  • Migration 0005_add_task_questions.sql verified consistent with the Drizzle schema (columns, FKs, indexes). db:migrate not run here (no DB in this environment).

Integration note

This branch and the already-merged item #5 (Approve / Change plan / Restart + prompt display) both touch web/app/dashboard/tasks/[id]/page.tsx; the merge was reconciled here so both feature sets coexist.

🤖 Generated with Claude Code

- Architect emits a machine-parseable open_questions_json block; parsed and
  persisted to a new task_questions table (migration 0005).
- New awaiting_answers lifecycle state: tasks with open questions wait for the
  originator instead of going straight to awaiting_approval.
- POST /api/tasks/:id/questions records answers and enqueues a forge:answers
  re-plan job; the worker re-runs the architect with answers in context and then
  moves to awaiting_approval (or back to awaiting_answers on new questions).
- Task page renders a QuestionsPanel (wired to initial load + SSE) and gates
  Approve until questions are resolved; integrates with the Approve/Change
  plan/Restart actions.
- Fix: extend worker QueueName with 'answers'. Add unit tests for the parser and
  guard tests for the questions route.

Closes #11

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 824c58419d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

await updateTaskStatus(taskId, openQuestionCount > 0 ? 'awaiting_answers' : 'awaiting_approval')
} catch (err) {
const message = errorMessage(err)
await updateTaskStatus(taskId, 'failed', message)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve retryable status for answer re-plans

When runArchitect throws during an answered-question re-plan, this catch always marks the task failed before rethrowing. The answers queue in runtime.ts will schedule a retry when attempts remain, but the retried job immediately exits at the task.status !== 'awaiting_answers' guard above because the task is now failed, so transient provider/network errors after answers are submitted are never actually retried. Keep the task retryable, e.g. restore awaiting_answers for non-final attempts or pass final-attempt state into this path.

Useful? React with 👍 / 👎.

// previous round should not linger.
await db.delete(taskQuestions).where(eq(taskQuestions.taskId, taskId))

if (questions.length === 0) return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Notify clients when questions are cleared

When the follow-up architect run resolves all answered questions, this branch deletes the existing task_questions rows and returns without publishing any empty questions update. Clients that already received the previous questions:created event, or get it replayed from SSE history, keep rendering that stale question set because useTaskStream only clears questions when it receives a replacement event; the UI only matches the database after a full reload without replay. Publish a questions:created event with questions: [] after clearing the rows.

Useful? React with 👍 / 👎.

@Joncallim Joncallim merged commit 78fde9a into main Jun 22, 2026
2 checks passed
@Joncallim Joncallim deleted the feat/issue-11-open-questions branch June 22, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Orchestrator: route open questions back to task originator before approval

1 participant