-
Notifications
You must be signed in to change notification settings - Fork 5
feat(supervisor): eager orphaned PR scan after worker evaluation (t216) #917
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Caution Review failedThe pull request is closed. WalkthroughAdded a new per-task eager orphan-PR scanner Changes
Sequence Diagram(s)sequenceDiagram
participant Pulse as cmd_pulse
participant Eval as Task Evaluator
participant Scanner as scan_orphaned_pr_for_task
participant PRRepo as PR Repository
participant DB as Task Database
Pulse->>Eval: Evaluate task(task_id)
Eval-->>Pulse: Outcome (not complete)
Pulse->>Scanner: scan_orphaned_pr_for_task(task_id)
Scanner->>PRRepo: Fetch open/merged PRs for repo
PRRepo-->>Scanner: PR list
Scanner->>Scanner: Match PR by task ID (title/branch)
alt PR Found & Valid
Scanner->>DB: Link PR -> task row
Scanner->>DB: Update task row & transition to complete
Scanner-->>Pulse: Linked & completed
Pulse->>Pulse: Update outcome to complete (short-circuit)
else PR Not Found
Scanner-->>Pulse: No match
Pulse->>Pulse: Continue processing
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Tue Feb 10 04:57:49 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.agents/scripts/supervisor-helper.sh:
- Around line 6065-6187: The eager orphaned-PR scan (scan_orphaned_pr_for_task)
links PRs while tasks can still be in status evaluating, but the case in
scan_orphaned_pr_for_task only transitions failed|blocked|retrying to complete;
update that case to also treat evaluating as eligible for automatic transition
to complete (i.e., add evaluating to the first case pattern that logs and calls
cmd_transition/update_todo_on_complete/send_task_notification/store_success_pattern),
or alternatively ensure cmd_pulse moves the task out of evaluating before
calling scan_orphaned_pr_for_task so the existing case will apply.
| ####################################### | ||
| # Eager orphaned PR scan for a single task (t216). | ||
| # | ||
| # Called immediately after worker evaluation when the outcome is | ||
| # retry/failed/blocked and no PR was linked. Unlike scan_orphaned_prs() | ||
| # which is a throttled batch sweep (Phase 6), this does a targeted | ||
| # single-task lookup — one repo, one API call — with no throttle. | ||
| # | ||
| # This catches the common case where a worker created a PR but exited | ||
| # without the FULL_LOOP_COMPLETE signal, and evaluate_worker()'s | ||
| # fallback PR detection missed it (API timeout, non-standard branch, etc.). | ||
| # | ||
| # $1: task_id | ||
| # | ||
| # Returns 0 on success. Sets pr_url in DB and transitions task to | ||
| # complete if a matching PR is found. | ||
| ####################################### | ||
| scan_orphaned_pr_for_task() { | ||
| local task_id="$1" | ||
|
|
||
| ensure_db | ||
|
|
||
| local escaped_id | ||
| escaped_id=$(sql_escape "$task_id") | ||
|
|
||
| # Get task details | ||
| local task_row | ||
| task_row=$(db -separator '|' "$SUPERVISOR_DB" " | ||
| SELECT status, repo, branch, pr_url FROM tasks | ||
| WHERE id = '$escaped_id'; | ||
| " 2>/dev/null || echo "") | ||
|
|
||
| if [[ -z "$task_row" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| local tstatus trepo tbranch tpr_url | ||
| IFS='|' read -r tstatus trepo tbranch tpr_url <<< "$task_row" | ||
|
|
||
| # Skip if PR already linked (not orphaned) | ||
| if [[ -n "$tpr_url" && "$tpr_url" != "no_pr" && "$tpr_url" != "task_only" && "$tpr_url" != "task_obsolete" && "$tpr_url" != "" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| # Need a repo to scan | ||
| if [[ -z "$trepo" || ! -d "$trepo" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| local repo_slug | ||
| repo_slug=$(detect_repo_slug "$trepo" 2>/dev/null || echo "") | ||
| if [[ -z "$repo_slug" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| # Fetch open PRs for this repo (single API call) | ||
| local pr_list | ||
| pr_list=$(gh pr list --repo "$repo_slug" --state open --limit 100 \ | ||
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | ||
|
|
||
| # Also check recently merged PRs | ||
| local merged_pr_list | ||
| merged_pr_list=$(gh pr list --repo "$repo_slug" --state merged --limit 50 \ | ||
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | ||
|
|
||
| # Combine open and merged PR lists | ||
| local all_prs | ||
| if [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" && -n "$pr_list" && "$pr_list" != "[]" ]]; then | ||
| all_prs=$(echo "$pr_list" "$merged_pr_list" | jq -s 'add' 2>/dev/null || echo "$pr_list") | ||
| elif [[ -n "$pr_list" && "$pr_list" != "[]" ]]; then | ||
| all_prs="$pr_list" | ||
| elif [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" ]]; then | ||
| all_prs="$merged_pr_list" | ||
| else | ||
| return 0 | ||
| fi | ||
|
|
||
| # Match PRs to this task by task ID in title or branch name | ||
| local matched_pr_url | ||
| matched_pr_url=$(echo "$all_prs" | jq -r --arg tid "$task_id" ' | ||
| .[] | select( | ||
| (.title | test("\\b" + $tid + "\\b"; "i")) or | ||
| (.headRefName | test("\\b" + $tid + "\\b"; "i")) | ||
| ) | .url | ||
| ' 2>/dev/null | head -1 || echo "") | ||
|
|
||
| if [[ -z "$matched_pr_url" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| # Validate the PR belongs to this task | ||
| local validated_url | ||
| validated_url=$(validate_pr_belongs_to_task "$task_id" "$repo_slug" "$matched_pr_url") || validated_url="" | ||
|
|
||
| if [[ -z "$validated_url" ]]; then | ||
| return 0 | ||
| fi | ||
|
|
||
| # Link the PR to the task | ||
| db "$SUPERVISOR_DB" "UPDATE tasks SET pr_url = '$(sql_escape "$validated_url")' WHERE id = '$escaped_id';" 2>/dev/null || true | ||
|
|
||
| # Transition eligible tasks to complete | ||
| case "$tstatus" in | ||
| failed|blocked|retrying) | ||
| log_info " Eager scan: ORPHANED PR found for $task_id ($tstatus -> complete): $validated_url" | ||
| cmd_transition "$task_id" "complete" --pr-url "$validated_url" 2>>"$SUPERVISOR_LOG" || true | ||
| # Run post-completion hooks | ||
| update_todo_on_complete "$task_id" 2>>"$SUPERVISOR_LOG" || true | ||
| send_task_notification "$task_id" "complete" "orphaned_pr_linked:$validated_url" 2>>"$SUPERVISOR_LOG" || true | ||
| local tid_desc | ||
| tid_desc=$(db "$SUPERVISOR_DB" "SELECT description FROM tasks WHERE id = '$escaped_id';" 2>/dev/null || echo "") | ||
| store_success_pattern "$task_id" "orphaned_pr_linked_eager" "$tid_desc" 2>>"$SUPERVISOR_LOG" || true | ||
| ;; | ||
| complete) | ||
| log_info " Eager scan: Linked orphaned PR to completed task $task_id: $validated_url" | ||
| ;; | ||
| *) | ||
| log_info " Eager scan: Linked orphaned PR to $task_id ($tstatus): $validated_url" | ||
| ;; | ||
| esac | ||
|
|
||
| return 0 | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eager scan won’t complete tasks still in evaluating state.
In cmd_pulse, the eager scan runs immediately after evaluate_worker() while the task is still evaluating. Your case statement only transitions failed|blocked|retrying, so a найден PR just gets linked, then the task can still be marked retry/failed/blocked. Since pr_url is now set, the Phase 6 sweep won’t correct it. Please include evaluating as an eligible transition (or explicitly transition before scan).
🔧 Suggested fix
- case "$tstatus" in
- failed|blocked|retrying)
+ case "$tstatus" in
+ failed|blocked|retrying|evaluating)
log_info " Eager scan: ORPHANED PR found for $task_id ($tstatus -> complete): $validated_url"
cmd_transition "$task_id" "complete" --pr-url "$validated_url" 2>>"$SUPERVISOR_LOG" || true📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ####################################### | |
| # Eager orphaned PR scan for a single task (t216). | |
| # | |
| # Called immediately after worker evaluation when the outcome is | |
| # retry/failed/blocked and no PR was linked. Unlike scan_orphaned_prs() | |
| # which is a throttled batch sweep (Phase 6), this does a targeted | |
| # single-task lookup — one repo, one API call — with no throttle. | |
| # | |
| # This catches the common case where a worker created a PR but exited | |
| # without the FULL_LOOP_COMPLETE signal, and evaluate_worker()'s | |
| # fallback PR detection missed it (API timeout, non-standard branch, etc.). | |
| # | |
| # $1: task_id | |
| # | |
| # Returns 0 on success. Sets pr_url in DB and transitions task to | |
| # complete if a matching PR is found. | |
| ####################################### | |
| scan_orphaned_pr_for_task() { | |
| local task_id="$1" | |
| ensure_db | |
| local escaped_id | |
| escaped_id=$(sql_escape "$task_id") | |
| # Get task details | |
| local task_row | |
| task_row=$(db -separator '|' "$SUPERVISOR_DB" " | |
| SELECT status, repo, branch, pr_url FROM tasks | |
| WHERE id = '$escaped_id'; | |
| " 2>/dev/null || echo "") | |
| if [[ -z "$task_row" ]]; then | |
| return 0 | |
| fi | |
| local tstatus trepo tbranch tpr_url | |
| IFS='|' read -r tstatus trepo tbranch tpr_url <<< "$task_row" | |
| # Skip if PR already linked (not orphaned) | |
| if [[ -n "$tpr_url" && "$tpr_url" != "no_pr" && "$tpr_url" != "task_only" && "$tpr_url" != "task_obsolete" && "$tpr_url" != "" ]]; then | |
| return 0 | |
| fi | |
| # Need a repo to scan | |
| if [[ -z "$trepo" || ! -d "$trepo" ]]; then | |
| return 0 | |
| fi | |
| local repo_slug | |
| repo_slug=$(detect_repo_slug "$trepo" 2>/dev/null || echo "") | |
| if [[ -z "$repo_slug" ]]; then | |
| return 0 | |
| fi | |
| # Fetch open PRs for this repo (single API call) | |
| local pr_list | |
| pr_list=$(gh pr list --repo "$repo_slug" --state open --limit 100 \ | |
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | |
| # Also check recently merged PRs | |
| local merged_pr_list | |
| merged_pr_list=$(gh pr list --repo "$repo_slug" --state merged --limit 50 \ | |
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | |
| # Combine open and merged PR lists | |
| local all_prs | |
| if [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" && -n "$pr_list" && "$pr_list" != "[]" ]]; then | |
| all_prs=$(echo "$pr_list" "$merged_pr_list" | jq -s 'add' 2>/dev/null || echo "$pr_list") | |
| elif [[ -n "$pr_list" && "$pr_list" != "[]" ]]; then | |
| all_prs="$pr_list" | |
| elif [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" ]]; then | |
| all_prs="$merged_pr_list" | |
| else | |
| return 0 | |
| fi | |
| # Match PRs to this task by task ID in title or branch name | |
| local matched_pr_url | |
| matched_pr_url=$(echo "$all_prs" | jq -r --arg tid "$task_id" ' | |
| .[] | select( | |
| (.title | test("\\b" + $tid + "\\b"; "i")) or | |
| (.headRefName | test("\\b" + $tid + "\\b"; "i")) | |
| ) | .url | |
| ' 2>/dev/null | head -1 || echo "") | |
| if [[ -z "$matched_pr_url" ]]; then | |
| return 0 | |
| fi | |
| # Validate the PR belongs to this task | |
| local validated_url | |
| validated_url=$(validate_pr_belongs_to_task "$task_id" "$repo_slug" "$matched_pr_url") || validated_url="" | |
| if [[ -z "$validated_url" ]]; then | |
| return 0 | |
| fi | |
| # Link the PR to the task | |
| db "$SUPERVISOR_DB" "UPDATE tasks SET pr_url = '$(sql_escape "$validated_url")' WHERE id = '$escaped_id';" 2>/dev/null || true | |
| # Transition eligible tasks to complete | |
| case "$tstatus" in | |
| failed|blocked|retrying) | |
| log_info " Eager scan: ORPHANED PR found for $task_id ($tstatus -> complete): $validated_url" | |
| cmd_transition "$task_id" "complete" --pr-url "$validated_url" 2>>"$SUPERVISOR_LOG" || true | |
| # Run post-completion hooks | |
| update_todo_on_complete "$task_id" 2>>"$SUPERVISOR_LOG" || true | |
| send_task_notification "$task_id" "complete" "orphaned_pr_linked:$validated_url" 2>>"$SUPERVISOR_LOG" || true | |
| local tid_desc | |
| tid_desc=$(db "$SUPERVISOR_DB" "SELECT description FROM tasks WHERE id = '$escaped_id';" 2>/dev/null || echo "") | |
| store_success_pattern "$task_id" "orphaned_pr_linked_eager" "$tid_desc" 2>>"$SUPERVISOR_LOG" || true | |
| ;; | |
| complete) | |
| log_info " Eager scan: Linked orphaned PR to completed task $task_id: $validated_url" | |
| ;; | |
| *) | |
| log_info " Eager scan: Linked orphaned PR to $task_id ($tstatus): $validated_url" | |
| ;; | |
| esac | |
| return 0 | |
| } | |
| ####################################### | |
| # Eager orphaned PR scan for a single task (t216). | |
| # | |
| # Called immediately after worker evaluation when the outcome is | |
| # retry/failed/blocked and no PR was linked. Unlike scan_orphaned_prs() | |
| # which is a throttled batch sweep (Phase 6), this does a targeted | |
| # single-task lookup — one repo, one API call — with no throttle. | |
| # | |
| # This catches the common case where a worker created a PR but exited | |
| # without the FULL_LOOP_COMPLETE signal, and evaluate_worker()'s | |
| # fallback PR detection missed it (API timeout, non-standard branch, etc.). | |
| # | |
| # $1: task_id | |
| # | |
| # Returns 0 on success. Sets pr_url in DB and transitions task to | |
| # complete if a matching PR is found. | |
| ####################################### | |
| scan_orphaned_pr_for_task() { | |
| local task_id="$1" | |
| ensure_db | |
| local escaped_id | |
| escaped_id=$(sql_escape "$task_id") | |
| # Get task details | |
| local task_row | |
| task_row=$(db -separator '|' "$SUPERVISOR_DB" " | |
| SELECT status, repo, branch, pr_url FROM tasks | |
| WHERE id = '$escaped_id'; | |
| " 2>/dev/null || echo "") | |
| if [[ -z "$task_row" ]]; then | |
| return 0 | |
| fi | |
| local tstatus trepo tbranch tpr_url | |
| IFS='|' read -r tstatus trepo tbranch tpr_url <<< "$task_row" | |
| # Skip if PR already linked (not orphaned) | |
| if [[ -n "$tpr_url" && "$tpr_url" != "no_pr" && "$tpr_url" != "task_only" && "$tpr_url" != "task_obsolete" && "$tpr_url" != "" ]]; then | |
| return 0 | |
| fi | |
| # Need a repo to scan | |
| if [[ -z "$trepo" || ! -d "$trepo" ]]; then | |
| return 0 | |
| fi | |
| local repo_slug | |
| repo_slug=$(detect_repo_slug "$trepo" 2>/dev/null || echo "") | |
| if [[ -z "$repo_slug" ]]; then | |
| return 0 | |
| fi | |
| # Fetch open PRs for this repo (single API call) | |
| local pr_list | |
| pr_list=$(gh pr list --repo "$repo_slug" --state open --limit 100 \ | |
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | |
| # Also check recently merged PRs | |
| local merged_pr_list | |
| merged_pr_list=$(gh pr list --repo "$repo_slug" --state merged --limit 50 \ | |
| --json number,title,headRefName,url 2>>"$SUPERVISOR_LOG" || echo "") | |
| # Combine open and merged PR lists | |
| local all_prs | |
| if [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" && -n "$pr_list" && "$pr_list" != "[]" ]]; then | |
| all_prs=$(echo "$pr_list" "$merged_pr_list" | jq -s 'add' 2>/dev/null || echo "$pr_list") | |
| elif [[ -n "$pr_list" && "$pr_list" != "[]" ]]; then | |
| all_prs="$pr_list" | |
| elif [[ -n "$merged_pr_list" && "$merged_pr_list" != "[]" ]]; then | |
| all_prs="$merged_pr_list" | |
| else | |
| return 0 | |
| fi | |
| # Match PRs to this task by task ID in title or branch name | |
| local matched_pr_url | |
| matched_pr_url=$(echo "$all_prs" | jq -r --arg tid "$task_id" ' | |
| .[] | select( | |
| (.title | test("\\b" + $tid + "\\b"; "i")) or | |
| (.headRefName | test("\\b" + $tid + "\\b"; "i")) | |
| ) | .url | |
| ' 2>/dev/null | head -1 || echo "") | |
| if [[ -z "$matched_pr_url" ]]; then | |
| return 0 | |
| fi | |
| # Validate the PR belongs to this task | |
| local validated_url | |
| validated_url=$(validate_pr_belongs_to_task "$task_id" "$repo_slug" "$matched_pr_url") || validated_url="" | |
| if [[ -z "$validated_url" ]]; then | |
| return 0 | |
| fi | |
| # Link the PR to the task | |
| db "$SUPERVISOR_DB" "UPDATE tasks SET pr_url = '$(sql_escape "$validated_url")' WHERE id = '$escaped_id';" 2>/dev/null || true | |
| # Transition eligible tasks to complete | |
| case "$tstatus" in | |
| failed|blocked|retrying|evaluating) | |
| log_info " Eager scan: ORPHANED PR found for $task_id ($tstatus -> complete): $validated_url" | |
| cmd_transition "$task_id" "complete" --pr-url "$validated_url" 2>>"$SUPERVISOR_LOG" || true | |
| # Run post-completion hooks | |
| update_todo_on_complete "$task_id" 2>>"$SUPERVISOR_LOG" || true | |
| send_task_notification "$task_id" "complete" "orphaned_pr_linked:$validated_url" 2>>"$SUPERVISOR_LOG" || true | |
| local tid_desc | |
| tid_desc=$(db "$SUPERVISOR_DB" "SELECT description FROM tasks WHERE id = '$escaped_id';" 2>/dev/null || echo "") | |
| store_success_pattern "$task_id" "orphaned_pr_linked_eager" "$tid_desc" 2>>"$SUPERVISOR_LOG" || true | |
| ;; | |
| complete) | |
| log_info " Eager scan: Linked orphaned PR to completed task $task_id: $validated_url" | |
| ;; | |
| *) | |
| log_info " Eager scan: Linked orphaned PR to $task_id ($tstatus): $validated_url" | |
| ;; | |
| esac | |
| return 0 | |
| } |
🤖 Prompt for AI Agents
In @.agents/scripts/supervisor-helper.sh around lines 6065 - 6187, The eager
orphaned-PR scan (scan_orphaned_pr_for_task) links PRs while tasks can still be
in status evaluating, but the case in scan_orphaned_pr_for_task only transitions
failed|blocked|retrying to complete; update that case to also treat evaluating
as eligible for automatic transition to complete (i.e., add evaluating to the
first case pattern that logs and calls
cmd_transition/update_todo_on_complete/send_task_notification/store_success_pattern),
or alternatively ensure cmd_pulse moves the task out of evaluating before
calling scan_orphaned_pr_for_task so the existing case will apply.
Bot review dismissed - all CI checks pass
Add scan_orphaned_pr_for_task() — a targeted single-task orphaned PR scanner that runs immediately after evaluate_worker() returns a non-complete outcome in Phase 1 of cmd_pulse(). Previously, orphaned PR detection only ran in Phase 6 as a throttled batch sweep (every 10 minutes). Workers that created PRs but exited without FULL_LOOP_COMPLETE would sit in retry/failed/blocked state until the next Phase 6 run passed the throttle check. Now the flow is: 1. evaluate_worker() returns retry/failed/blocked 2. scan_orphaned_pr_for_task() immediately checks GitHub for a PR matching the task ID in title or branch name 3. If found, transitions the task to complete (skipping retry/fail) 4. Phase 6 broad sweep remains as a safety net for edge cases The eager scan makes 1-2 gh API calls per evaluated task (open + merged PRs), which is acceptable since it only fires when a worker finishes — not on every pulse for every task.
17a9bda to
bc6151f
Compare
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Tue Feb 10 12:39:45 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
|



Summary
scan_orphaned_pr_for_task()— a targeted single-task orphaned PR scanner that runs immediately afterevaluate_worker()returns a non-complete outcome in Phase 1 ofcmd_pulse()scan_orphaned_prs()) remains as a safety net for edge cases (Phase 4b DB orphans, pre-existing failed tasks)Changes
New function:
scan_orphaned_pr_for_task()validate_pr_belongs_to_task()before linkingorphaned_pr_linked_eagersuccess pattern for trackingPhase 1 integration
evaluate_worker()returns a non-complete outcome, immediately callsscan_orphaned_pr_for_task()continuePhase 6 updates
Testing
bash -nsyntax check passestbranch, matching existing pattern inscan_orphaned_prs())Summary by CodeRabbit
New Features
Chores