From e275c35fa88a0c6ae2ecd64fbae4cab46f657db7 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 12 Apr 2026 04:41:12 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20bug:=20architect=20close-vision=20lifecy?= =?UTF-8?q?cle=20matches=20unrelated=20sub-issues=20=E2=80=94=20spams=20fa?= =?UTF-8?q?lse=20completion=20comments=20(#735)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- architect/architect-run.sh | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/architect/architect-run.sh b/architect/architect-run.sh index d51960c..9e0045d 100755 --- a/architect/architect-run.sh +++ b/architect/architect-run.sh @@ -441,6 +441,7 @@ get_vision_subissues() { fi # Method 2: Find issues referenced in merged sprint PR bodies + # Only consider PRs whose title or body references this specific vision issue local prs_json prs_json=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ "${FORGE_API_BASE}/repos/${FORGE_OPS_REPO}/pulls?state=closed&limit=100" 2>/dev/null) || true @@ -449,8 +450,7 @@ get_vision_subissues() { while IFS= read -r pr_num; do [ -z "$pr_num" ] && continue - # Check if PR is merged and references the vision issue - local pr_details pr_body + local pr_details pr_body pr_title pr_details=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ "${FORGE_API_BASE}/repos/${FORGE_OPS_REPO}/pulls/${pr_num}" 2>/dev/null) || continue @@ -461,11 +461,19 @@ get_vision_subissues() { continue fi + pr_title=$(printf '%s' "$pr_details" | jq -r '.title // ""') || continue pr_body=$(printf '%s' "$pr_details" | jq -r '.body // ""') || continue - # Extract all issue numbers from PR body + # Only process PRs that reference this specific vision issue + if ! printf '%s\n%s' "$pr_title" "$pr_body" | grep -qE "#${vision_issue}([^0-9]|$)"; then + continue + fi + + # Extract issue numbers from PR body, excluding the vision issue itself while IFS= read -r ref_issue; do [ -z "$ref_issue" ] && continue + # Skip the vision issue itself + [ "$ref_issue" = "$vision_issue" ] && continue # Skip if already in list local found=false for existing in "${subissues[@]+"${subissues[@]}"}"; do @@ -518,6 +526,17 @@ all_subissues_closed() { # Args: vision_issue_number close_vision_issue() { local vision_issue="$1" + + # Idempotency guard: check if a completion comment already exists + local existing_comments + existing_comments=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_API}/issues/${vision_issue}/comments" 2>/dev/null) || existing_comments="[]" + + if printf '%s' "$existing_comments" | jq -e '[.[] | select(.body | contains("Vision Issue Completed"))] | length > 0' >/dev/null 2>&1; then + log "Vision issue #${vision_issue} already has a completion comment — skipping" + return 0 + fi + local subissues subissues=$(get_vision_subissues "$vision_issue")