From 99d430a0c29299b046474f3bdb920459c058d6bf Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 10 Apr 2026 11:21:00 +0000 Subject: [PATCH] fix: bug: architect has no path for approved PRs awaiting initial design questions (#570) Implementation: - Added detect_approved_pending_questions() function to identify approved PRs that have no ## Design forks section and no Q1:, Q2: comments yet. - Modified response processing block to handle three session modes: 1. questions_phase: Resume session for processing Q&A answers 2. start_questions: Fresh session to post initial design questions 3. pitch: Original behavior for new pitch generation - Added build_architect_prompt_for_mode() function to generate appropriate prompts for each session mode. - When an approved PR is detected, the agent posts initial design questions (Q1:, Q2:, etc.) and adds the ## Design forks section, transitioning the PR into the existing questions phase. This fixes the issue where approved architect PRs would sit indefinitely because the agent had no path to start the design conversation. --- architect/AGENTS.md | 6 +- architect/architect-run.sh | 179 ++++++++++++++++++++++++++++++++++-- formulas/run-architect.toml | 13 +++ 3 files changed, 186 insertions(+), 12 deletions(-) diff --git a/architect/AGENTS.md b/architect/AGENTS.md index 74847b9..f5fddf4 100644 --- a/architect/AGENTS.md +++ b/architect/AGENTS.md @@ -51,9 +51,11 @@ Bash in `architect-run.sh` handles state detection and orchestration: ``` New vision issue → pitch PR (model generates pitch, bash creates PR) ↓ -ACCEPT review → research + questions (model, session saved to $SID_FILE) +APPROVED review → start design questions (model posts Q1:, adds Design forks section) ↓ -Answers received → sub-issue filing (model, session resumed via --resume) +Answers received → continue Q&A (model processes answers, posts follow-ups) + ↓ +All forks resolved → sub-issue filing (model files implementation issues) ↓ REJECT review → close PR + journal (model processes rejection, bash merges PR) ``` diff --git a/architect/architect-run.sh b/architect/architect-run.sh index 8455b74..b2ddf3c 100755 --- a/architect/architect-run.sh +++ b/architect/architect-run.sh @@ -129,7 +129,88 @@ ${PROMPT_FOOTER} _PROMPT_EOF_ } -PROMPT=$(build_architect_prompt) +# ── Build prompt for specific session mode ─────────────────────────────── +# Args: session_mode (pitch / questions_phase / start_questions) +# Returns: prompt text via stdout +build_architect_prompt_for_mode() { + local session_mode="$1" + + case "$session_mode" in + "start_questions") + cat <<_PROMPT_EOF_ +You are the architect agent for ${FORGE_REPO}. Work through the formula below. + +Your role: strategic decomposition of vision issues into development sprints. +Propose sprints via PRs on the ops repo, converse with humans through PR comments, +and file sub-issues after design forks are resolved. + +## CURRENT STATE: Approved PR awaiting initial design questions + +A sprint pitch PR has been approved by the human (via APPROVED review), but the +design conversation has not yet started. Your task is to: + +1. Read the approved sprint pitch from the PR body +2. Identify the key design decisions that need human input +3. Post initial design questions (Q1:, Q2:, etc.) as comments on the PR +4. Add a `## Design forks` section to the PR body documenting the design decisions +5. File sub-issues for each design fork path if applicable + +This is NOT a pitch phase — the pitch is already approved. This is the START +of the design Q&A phase. + +## Project context +${CONTEXT_BLOCK} +${GRAPH_SECTION} +${SCRATCH_CONTEXT} +$(formula_lessons_block) +## Formula +${FORMULA_CONTENT} + +${SCRATCH_INSTRUCTION} +${PROMPT_FOOTER} +_PROMPT_EOF_ + ;; + "questions_phase") + cat <<_PROMPT_EOF_ +You are the architect agent for ${FORGE_REPO}. Work through the formula below. + +Your role: strategic decomposition of vision issues into development sprints. +Propose sprints via PRs on the ops repo, converse with humans through PR comments, +and file sub-issues after design forks are resolved. + +## CURRENT STATE: Design Q&A in progress + +A sprint pitch PR is in the questions phase: +- The PR has a `## Design forks` section +- Initial questions (Q1:, Q2:, etc.) have been posted +- Humans may have posted answers or follow-up questions + +Your task is to: +1. Read the existing questions and the PR body +2. Read human answers from PR comments +3. Parse the answers and determine next steps +4. Post follow-up questions if needed (Q3:, Q4:, etc.) +5. If all design forks are resolved, file sub-issues for each path +6. Update the `## Design forks` section as you progress + +## Project context +${CONTEXT_BLOCK} +${GRAPH_SECTION} +${SCRATCH_CONTEXT} +$(formula_lessons_block) +## Formula +${FORMULA_CONTENT} + +${SCRATCH_INSTRUCTION} +${PROMPT_FOOTER} +_PROMPT_EOF_ + ;; + "pitch"|*) + # Default: pitch new sprints (original behavior) + build_architect_prompt + ;; + esac +} # ── Create worktree ────────────────────────────────────────────────────── formula_worktree_setup "$WORKTREE" @@ -184,6 +265,71 @@ detect_questions_phase() { return 0 } +# ── Detect if PR is approved and awaiting initial design questions ──────── +# A PR is in this state when: +# - It's an open architect PR on ops repo +# - It has an APPROVED review (from human acceptance) +# - It has NO `## Design forks` section yet +# - It has NO Q1:, Q2:, etc. comments yet +# This means the human accepted the pitch and we need to start the design +# conversation by posting initial questions and adding the Design forks section. +detect_approved_pending_questions() { + local pr_number="" + local pr_body="" + + # Get open architect PRs on ops repo + local ops_repo="${OPS_REPO_ROOT:-/home/agent/data/ops}" + if [ ! -d "${ops_repo}/.git" ]; then + return 1 + fi + + # Use Forgejo API to find open architect PRs + local response + response=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_API}/repos/${FORGE_OPS_REPO}/pulls?state=open" 2>/dev/null) || return 1 + + # Check each open PR for architect markers + pr_number=$(printf '%s' "$response" | jq -r '.[] | select(.title | contains("architect:")) | .number' 2>/dev/null | head -1) || return 1 + + if [ -z "$pr_number" ]; then + return 1 + fi + + # Fetch PR body + pr_body=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_API}/repos/${FORGE_OPS_REPO}/pulls/${pr_number}" 2>/dev/null | jq -r '.body // empty') || return 1 + + # Check for APPROVED review + local reviews + reviews=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_API}/repos/${FORGE_OPS_REPO}/pulls/${pr_number}/reviews" 2>/dev/null) || return 1 + + if ! printf '%s' "$reviews" | jq -e '.[] | select(.state == "APPROVED")' >/dev/null 2>&1; then + return 1 + fi + + # Check that PR does NOT have `## Design forks` section yet + # (we're in the "start questions" phase, not "process answers" phase) + if printf '%s' "$pr_body" | grep -q "## Design forks"; then + # Has design forks section — this is either in questions phase or past it + return 1 + fi + + # Check that PR has NO question comments yet (Q1:, Q2:, etc.) + local comments + comments=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_API}/repos/${FORGE_OPS_REPO}/issues/${pr_number}/comments" 2>/dev/null) || return 1 + + if printf '%s' "$comments" | jq -r '.[].body // empty' | grep -qE 'Q[0-9]+:'; then + # Has question comments — this is either in questions phase or past it + return 1 + fi + + # PR is approved and awaiting initial design questions + log "Detected PR #${pr_number} approved and awaiting initial design questions" + return 0 +} + # ── Sub-issue existence check ──────────────────────────────────────────── # Check if a vision issue already has sub-issues filed from it. # Returns 0 if sub-issues exist and are open, 1 otherwise. @@ -717,19 +863,32 @@ if [ "${has_responses_to_process:-false}" = "true" ]; then # Run agent only if there are responses to process if [ "$needs_agent" = "true" ]; then - # Determine whether to resume session + # Determine session handling based on PR state RESUME_ARGS=() - if detect_questions_phase && [ -f "$SID_FILE" ]; then - RESUME_SESSION=$(cat "$SID_FILE") - RESUME_ARGS=(--resume "$RESUME_SESSION") - log "Resuming session from questions phase run: ${RESUME_SESSION:0:12}..." - elif ! detect_questions_phase; then + SESSION_MODE="fresh" + + if detect_questions_phase; then + # PR is in questions-awaiting-answers phase — resume from that session + if [ -f "$SID_FILE" ]; then + RESUME_SESSION=$(cat "$SID_FILE") + RESUME_ARGS=(--resume "$RESUME_SESSION") + SESSION_MODE="questions_phase" + log "PR in questions-awaiting-answers phase — resuming session: ${RESUME_SESSION:0:12}..." + else + log "PR in questions phase but no session file — starting fresh session" + fi + elif detect_approved_pending_questions; then + # PR is approved but awaiting initial design questions — start fresh with special prompt + SESSION_MODE="start_questions" + log "PR approved and awaiting initial design questions — starting fresh session" + else log "PR not in questions phase — starting fresh session" - elif [ ! -f "$SID_FILE" ]; then - log "No session ID found for questions phase — starting fresh session" fi - agent_run "${RESUME_ARGS[@]}" --worktree "$WORKTREE" "$PROMPT" + # Build prompt with appropriate mode + PROMPT_FOR_MODE=$(build_architect_prompt_for_mode "$SESSION_MODE") + + agent_run "${RESUME_ARGS[@]}" --worktree "$WORKTREE" "$PROMPT_FOR_MODE" log "agent_run complete" fi fi diff --git a/formulas/run-architect.toml b/formulas/run-architect.toml index 39458c6..0efb6df 100644 --- a/formulas/run-architect.toml +++ b/formulas/run-architect.toml @@ -169,6 +169,19 @@ description = """ IMPORTANT: PR creation is handled by bash (architect-run.sh) during the pitch step. This step is for documentation only — the actual PR creation happens in research_pitch. +## Approved PR → Initial design questions (issue #570) + +When a sprint pitch PR receives an APPROVED review but has no `## Design forks` +section and no Q1:, Q2: comments yet, the architect enters a new state: + +1. detect_approved_pending_questions() identifies this state +2. A fresh agent session starts with a special prompt +3. The agent reads the approved pitch, posts initial design questions (Q1:, Q2:, etc.) +4. The agent adds a `## Design forks` section to the PR body +5. The PR transitions into the questions phase, where the existing Q&A loop takes over + +This ensures approved PRs don't sit indefinitely without design conversation. + Architecture: - Bash creates PRs during stateless pitch generation (step 2) - Model has no role in PR creation — no Forgejo API access