Skip to content

t1146: Add batch-cleanup mode to reduce worktree/PR overhead for chore tasks#1770

Merged
marcusquinn merged 2 commits intomainfrom
feature/t1146
Feb 18, 2026
Merged

t1146: Add batch-cleanup mode to reduce worktree/PR overhead for chore tasks#1770
marcusquinn merged 2 commits intomainfrom
feature/t1146

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Feb 18, 2026

Adds batch-cleanup mode to the supervisor to reduce worktree/PR overhead for simple chore tasks.

Problem

Each TODO.md cleanup task (mark cancelled, fix duplicate, fix typo) currently creates its own worktree and PR. For N simple text edits, this costs N*(worktree setup + PR creation + CI run + merge) when a single commit would suffice.

Solution

  • batch-cleanup-helper.sh: New script that scans for eligible tasks and dispatches a single worker to handle all of them in one PR
  • Strategy 5 in cmd_auto_pickup: Integrates batch-cleanup into the supervisor pulse cycle — triggers automatically when >=2 eligible tasks are found
  • supervisor-helper.sh batch-cleanup: New command for manual invocation

Eligibility Criteria

  • Tagged #chore in TODO.md
  • Estimated <=15m (~5m, ~10m, ~15m)
  • Status: pending ([ ] checkbox)
  • No unresolved blocked-by: dependencies
  • No assignee: or started: fields (unclaimed)

Expected Savings

  • N chore tasks: N*(worktree + PR + CI + merge) → 1*(worktree + PR + CI + merge)
  • ~80% token reduction for cleanup batches of 5+ tasks (observed: 5 separate tasks for what should be 1 commit)

Quality

  • ShellCheck: zero violations on all modified files
  • Syntax: bash -n passes on all files
  • Integration: Strategy 5 is non-fatal (failures logged, pulse continues)

Ref #1722

Summary by CodeRabbit

  • New Features
    • Batch cleanup automation for chore tasks automatically identifies and groups multiple eligible small tasks into a single PR for concurrent processing, reducing individual workflow overhead.
    • Intelligent task batching uses size and dependency analysis to organize routine maintenance work, streamlining chore handling while maintaining task integrity.

… tasks (t1146)

Groups #chore tasks with ~<=15m estimates into a single dispatch instead of
N separate worktrees and PRs. Reduces overhead by ~80% for cleanup batches.

Changes:
- Add batch-cleanup-helper.sh: scans for eligible tasks, dispatches single worker
- Add Strategy 5 to cmd_auto_pickup in cron.sh: triggers batch-cleanup during pulse
- Add 'batch-cleanup' command to supervisor-helper.sh router and usage docs

Eligibility criteria: #chore tag + ~<=15m estimate + unclaimed + unblocked
Trigger: >=2 eligible tasks found during auto-pickup pulse
Savings: N*(worktree+PR+CI+merge) → 1*(worktree+PR+CI+merge)
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Walkthrough

This PR introduces a comprehensive batch-cleanup system that scans TODO.md for eligible chore tasks, validates dependencies and estimates, and dispatches them as grouped batches. Integration points are added to the supervisor CLI and auto-pickup scheduler.

Changes

Cohort / File(s) Summary
Batch Cleanup Core
.agents/scripts/batch-cleanup-helper.sh
New script implementing task eligibility scanning with estimate/dependency parsing, batch worker dispatch via AI CLI, and supervisor database interaction. Includes helpers for estimate conversion, dependency validation, and CLI subcommands (scan, dispatch, status).
Supervisor CLI Integration
.agents/scripts/supervisor-helper.sh
Added batch-cleanup subcommand case branch that delegates to batch-cleanup-helper.sh with argument pass-through; updated usage text to document the new subcommand and its eligibility criteria.
Supervisor Auto-Pickup
.agents/scripts/supervisor/cron.sh
Added Strategy 5 in cmd_auto_pickup to invoke batch-cleanup scanner, count eligible tasks, and conditionally dispatch batch worker if minimum threshold (2 tasks) is met.

Sequence Diagram(s)

sequenceDiagram
    participant Cron as Cron Scheduler
    participant Supervisor as supervisor-helper.sh
    participant Scanner as batch-cleanup-helper.sh<br/>(scan)
    participant TODO as TODO.md
    participant Dispatcher as batch-cleanup-helper.sh<br/>(dispatch)
    participant AiCli as resolve_ai_cli<br/>(AI Worker)
    participant Db as Supervisor DB

    Cron->>Supervisor: cmd_auto_pickup
    Supervisor->>Scanner: batch-cleanup scan
    Scanner->>TODO: Read & parse `#chore` tasks
    TODO-->>Scanner: Task list with estimates
    Scanner->>Scanner: Validate eligibility<br/>(estimate ≤ 15m, no assignee/started,<br/>dependencies unblocked)
    Scanner->>Db: Check task status
    Db-->>Scanner: Eligible task IDs
    Scanner-->>Supervisor: Task count & IDs
    
    alt Eligible Tasks ≥ 2
        Supervisor->>Dispatcher: batch-cleanup dispatch
        Dispatcher->>Dispatcher: Build worker prompt<br/>with task descriptions
        Dispatcher->>AiCli: Execute batch with task CSV
        AiCli->>AiCli: Apply all changes<br/>in single batch
        AiCli->>Db: Update supervisor DB
        AiCli-->>Dispatcher: Return status & summary
        Dispatcher-->>Supervisor: BATCH_CLEANUP_COMPLETE
    else Fewer Than 2 Tasks
        Supervisor-->>Cron: No dispatch needed
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • Issue #1722: Directly implements batch cleanup/batch-task-creation feature for simple #chore tasks to reduce PR/CI/merge overhead, matching the same system objectives.

Possibly related PRs

  • PR #1616: Both modify supervisor auto-pickup flow (cron.sh) and supervisor CLI architecture; #1616 adds blocked-by gating while this PR adds batch-cleanup strategy/dispatch.
  • PR #378: Both extend supervisor-helper.sh main() dispatcher with new subcommands; #378 adds reprompt/evaluate while this PR adds batch-cleanup delegation.
  • PR #377: This PR's batch-cleanup-helper relies on supervisor dispatch primitives (resolve_ai_cli, worktree handling) established in #377.

Poem

🧹 A thousand chores await their fate,
Bundled tight to automate—
Dependencies align just right,
One batch worker, one PR tight!
Let the cleanup script compile,
Turning tedium to style! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: introducing batch-cleanup mode to consolidate chore tasks and reduce overhead.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/t1146

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @marcusquinn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new batch-cleanup mode designed to optimize the handling of small, routine chore tasks. By consolidating multiple eligible tasks into a single worktree and pull request, it aims to drastically cut down on the repetitive overhead associated with individual task processing, thereby improving overall efficiency and resource utilization within the supervisor system.

Highlights

  • New Batch Cleanup Mode: Introduced a new batch-cleanup-helper.sh script to group multiple simple chore tasks into a single dispatch, significantly reducing overhead.
  • Automated Integration: Integrated batch cleanup as 'Strategy 5' into the supervisor's cmd_auto_pickup function, allowing automatic triggering when two or more eligible chore tasks are detected.
  • Manual Invocation: Added a new supervisor-helper.sh batch-cleanup command for manual scanning, dispatching, and status checking of batch cleanup operations.
  • Eligibility Criteria: Defined specific criteria for tasks to be eligible for batch cleanup: #chore tag, estimated time <=15m, pending status, no unresolved blocked-by dependencies, and no assignee or started fields.
  • Efficiency Gains: Expected to reduce the overhead for N chore tasks from N individual worktrees/PRs/CI runs/merges to a single one, leading to an estimated ~80% token reduction for cleanup batches.
Changelog
  • .agents/scripts/batch-cleanup-helper.sh
    • Added a new executable script to manage the batch cleanup process for chore tasks.
    • Implemented functions for parsing task estimates, checking dependency resolution, and dispatching a worker for grouped tasks.
    • Defined the core logic for identifying eligible tasks based on tags, estimates, status, and assignment.
    • Provided commands for scanning, dispatching, and monitoring the status of batch cleanup operations.
  • .agents/scripts/supervisor-helper.sh
    • Updated the script's usage documentation to include the new batch-cleanup command and its sub-commands.
    • Added a new entry in the auto-pickup strategies documentation for 'Strategy 5: Batch-cleanup', detailing its purpose and benefits.
    • Integrated the batch-cleanup command into the main command-line interface, delegating execution to the new helper script.
  • .agents/scripts/supervisor/cron.sh
    • Implemented 'Strategy 5' within the cmd_auto_pickup function to automatically detect and initiate batch cleanup for eligible chore tasks.
    • Configured the strategy to only trigger a batch dispatch when a minimum of two eligible tasks are found and no existing batch cleanup worker is active.
Activity
  • No human activity has occurred on this pull request since its creation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 24 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Wed Feb 18 18:51:59 UTC 2026: Code review monitoring started
Wed Feb 18 18:51:59 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 24

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 24
  • VULNERABILITIES: 0

Generated on: Wed Feb 18 18:52:01 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces an excellent optimization for handling simple chore tasks by batching them into a single worktree and pull request. The new batch-cleanup-helper.sh script is well-structured and the integration into the supervisor's auto-pickup logic is clean. My review focuses on improving the shell scripting quality within the new helper script, suggesting more efficient alternatives to some command pipelines and ensuring strict adherence to the repository's style guide, particularly regarding error stream handling. These changes will enhance performance and maintainability.


# Extract blocked-by: field
local blocked_by
blocked_by=$(echo "$task_line" | grep -oE 'blocked-by:[^ ]+' | sed 's/blocked-by://' || true)

Choose a reason for hiding this comment

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

medium

This command pipeline uses echo, grep, and sed to extract the blocked-by value, creating three separate processes. This can be made more efficient by using a single sed command to perform the extraction.

Suggested change
blocked_by=$(echo "$task_line" | grep -oE 'blocked-by:[^ ]+' | sed 's/blocked-by://' || true)
blocked_by=$(echo "$task_line" | sed -nE 's/.*blocked-by:([^ ]+).*/\1/p')


# Check if dependency is complete ([x]) in TODO.md
local dep_line
dep_line=$(grep -E "^[[:space:]]*- \[x\] ${dep} " "$todo_file" 2>/dev/null | head -1 || true)

Choose a reason for hiding this comment

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

medium

The style guide (line 50) prohibits blanket suppression of stderr with 2>/dev/null. To adhere to the guide and improve debuggability, please redirect stderr to the supervisor log file.

Suggested change
dep_line=$(grep -E "^[[:space:]]*- \[x\] ${dep} " "$todo_file" 2>/dev/null | head -1 || true)
dep_line=$(grep -E "^[[:space:]]*- \[x\] ${dep} " "$todo_file" 2>>"$SUPERVISOR_LOG" | head -1 || true)
References
  1. Line 50: 2>/dev/null is acceptable ONLY when redirecting to log files, not blanket suppression. This comment points out a violation where stderr is suppressed instead of being logged. (link)


# Find all pending #chore tasks
local chore_tasks
chore_tasks=$(grep -E '^[[:space:]]*- \[ \] (t[0-9]+(\.[0-9]+)*) .*#chore' "$todo_file" 2>/dev/null || true)

Choose a reason for hiding this comment

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

medium

The style guide (line 50) prohibits blanket suppression of stderr with 2>/dev/null. To adhere to the guide and improve debuggability, please redirect stderr to the supervisor log file.

Suggested change
chore_tasks=$(grep -E '^[[:space:]]*- \[ \] (t[0-9]+(\.[0-9]+)*) .*#chore' "$todo_file" 2>/dev/null || true)
chore_tasks=$(grep -E '^[[:space:]]*- \[ \] (t[0-9]+(\.[0-9]+)*) .*#chore' "$todo_file" 2>>"$SUPERVISOR_LOG" || true)
References
  1. Line 50: 2>/dev/null is acceptable ONLY when redirecting to log files, not blanket suppression. This comment points out a violation where stderr is suppressed instead of being logged. (link)

[[ -z "$line" ]] && continue

local task_id
task_id=$(echo "$line" | grep -oE 't[0-9]+(\.[0-9]+)*' | head -1)

Choose a reason for hiding this comment

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

medium

This command pipeline uses echo, grep, and head to extract the task ID. This can be done more efficiently within bash itself using a regular expression match, avoiding the overhead of creating multiple subprocesses.

Suggested change
task_id=$(echo "$line" | grep -oE 't[0-9]+(\.[0-9]+)*' | head -1)
task_id=$([[ "$line" =~ (t[0-9]+(\.[0-9]+)*) ]] && echo "${BASH_REMATCH[1]}")


# Check estimate — must be <=15m
local estimate
estimate=$(echo "$line" | grep -oE '~[0-9]+(\.[0-9]+)?[mh]' | head -1 || true)

Choose a reason for hiding this comment

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

medium

This command pipeline uses echo, grep, and head to extract the estimate. This can be done more efficiently within bash itself using a regular expression match, avoiding the overhead of creating multiple subprocesses.

Suggested change
estimate=$(echo "$line" | grep -oE '~[0-9]+(\.[0-9]+)?[mh]' | head -1 || true)
estimate=$([[ "$line" =~ (~[0-9]+(\.[0-9]+)?[mh]) ]] && echo "${BASH_REMATCH[1]}")

local task_id
for task_id in "${task_ids[@]}"; do
local task_line
task_line=$(grep -E "^[[:space:]]*- \[ \] ${task_id} " "$todo_file" 2>/dev/null | head -1 || true)

Choose a reason for hiding this comment

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

medium

The style guide (line 50) prohibits blanket suppression of stderr with 2>/dev/null. To adhere to the guide and improve debuggability, please redirect stderr to the supervisor log file.

Suggested change
task_line=$(grep -E "^[[:space:]]*- \[ \] ${task_id} " "$todo_file" 2>/dev/null | head -1 || true)
task_line=$(grep -E "^[[:space:]]*- \[ \] ${task_id} " "$todo_file" 2>>"$SUPERVISOR_LOG" | head -1 || true)
References
  1. Line 50: 2>/dev/null is acceptable ONLY when redirecting to log files, not blanket suppression. This comment points out a violation where stderr is suppressed instead of being logged. (link)

…1146)

The dispatch command calls resolve_ai_cli() which is defined in
supervisor/dispatch.sh, but batch-cleanup-helper.sh only sourced
_common.sh and shared-constants.sh. This would cause a runtime
failure when attempting to dispatch a batch-cleanup worker.

Verified: scan, status, help, and dispatch --dry-run all work correctly.
@github-actions
Copy link

🔍 Code Quality Report

�[0;35m[MONITOR]�[0m Code Review Monitoring Report

�[0;34m[INFO]�[0m Latest Quality Status:
SonarCloud: 0 bugs, 0 vulnerabilities, 24 code smells

�[0;34m[INFO]�[0m Recent monitoring activity:
Wed Feb 18 18:59:09 UTC 2026: Code review monitoring started
Wed Feb 18 18:59:09 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 24

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 24
  • VULNERABILITIES: 0

Generated on: Wed Feb 18 18:59:12 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@sonarqubecloud
Copy link

@marcusquinn marcusquinn merged commit bfa4937 into main Feb 18, 2026
10 of 11 checks passed
@marcusquinn marcusquinn deleted the feature/t1146 branch February 18, 2026 19:02
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/scripts/batch-cleanup-helper.sh:
- Around line 74-80: The fractional-hour handling uses "frac * 6" which treats
the fraction as a single decimal digit and breaks for multi-digit fractions;
update the branch that matches "$estimate" to compute minutes correctly by
interpreting the fractional string as a proper decimal (e.g., build "0.$frac" or
compute frac/(10^len) ) and then calculate total minutes as hours*60 +
decimal_fraction*60 using a reliable tool (awk or bc) or integer math with the
fraction length; adjust the echo to output that computed minutes and keep the
same match on BASH_REMATCH to locate the code.
- Around line 355-366: The worker is launched with nohup using dispatch_cmd and
inherits the caller CWD so file references in worker_prompt (e.g., TODO.md,
todo/) will fail under cron; update the dispatch to cd into the repository
before launching the worker (either prepend a "cd '${repo}' &&" to the
dispatched command or generate a small wrapper script like
dispatch_decomposition_worker in cron.sh that does an explicit cd then exec the
ai_cli command), ensuring the code that builds dispatch_cmd (and the nohup
invocation) runs from the repo and still writes the worker PID to
BATCH_CLEANUP_PID_FILE.
- Around line 190-198: The existing check using the SUPERVISOR_DB/db/sql_escape
lookup mistakenly allows tasks with status "complete" to pass through; change
the conditional around the variable existing (result of db ... SELECT status
...) so that it treats "complete" as a skipped/post-completion state (e.g. test
for [[ -n "$existing" && ( "$existing" == "cancelled" || "$existing" ==
"complete" ) ]] and then log_info "  $task_id: already tracked in supervisor
(status: $existing) — skipping" and continue). Update the condition in
batch-cleanup-helper.sh where existing is set to ensure complete tasks are
skipped.
- Around line 91-120: The cron job fails because cron.sh calls an undefined
is_task_blocked(); copy the dependency-check logic from is_task_unblocked() in
batch-cleanup-helper.sh into supervisor/_common.sh as a single shared function
named is_task_blocked() (invert the boolean semantics so it returns 0 when the
task IS blocked and 1 when unblocked), ensure it extracts the blocked-by: field,
splits commas, trims spaces, and checks for completed "[x]" entries in TODO.md
the same way, then update cron.sh and batch-cleanup-helper.sh to source
supervisor/_common.sh and replace their local is_task_unblocked()/calls with the
new is_task_blocked() implementation.

In @.agents/scripts/supervisor/cron.sh:
- Around line 554-555: Fix the path resolution for the batch-cleanup helper:
change how batch_cleanup_helper is built so it uses
"${SCRIPT_DIR}/batch-cleanup-helper.sh" (not
"${SCRIPT_DIR}/../batch-cleanup-helper.sh") so the -x check for
batch_cleanup_helper succeeds in the cron context; also add an error log when
the helper is not found/ not executable (matching the behavior used in
supervisor-helper.sh) so the Strategy 5 block doesn't silently fail. Reference:
variable SCRIPT_DIR, variable batch_cleanup_helper and the Strategy 5 block in
cron.sh.

Comment on lines +74 to +80
if [[ "$estimate" =~ ^([0-9]+)\.([0-9]+)h$ ]]; then
local hours="${BASH_REMATCH[1]}"
local frac="${BASH_REMATCH[2]}"
# Convert fractional hours: 0.5h = 30m, 1.5h = 90m
echo $((hours * 60 + frac * 6))
return 0
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fractional hour parsing is incorrect for multi-digit decimals.

frac * 6 assumes a single-digit tenths value (e.g., ~0.5h5 * 6 = 30). Multi-digit fractions break: ~0.25h yields 25 * 6 = 150m instead of 15m, and ~0.75h yields 450m instead of 45m.

In practice, batch-cleanup targets ≤15m tasks so fractional hours are unlikely to appear, but the function advertises general support in its docstring (line 53).

Proposed fix using proper decimal arithmetic
 	if [[ "$estimate" =~ ^([0-9]+)\.([0-9]+)h$ ]]; then
 		local hours="${BASH_REMATCH[1]}"
 		local frac="${BASH_REMATCH[2]}"
-		# Convert fractional hours: 0.5h = 30m, 1.5h = 90m
-		echo $((hours * 60 + frac * 6))
+		# Convert fractional hours using awk for correct decimal handling
+		# e.g., 0.25h = 15m, 0.5h = 30m, 1.5h = 90m
+		awk "BEGIN { printf \"%d\", ${hours}.${frac} * 60 }"
 		return 0
 	fi
📝 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.

Suggested change
if [[ "$estimate" =~ ^([0-9]+)\.([0-9]+)h$ ]]; then
local hours="${BASH_REMATCH[1]}"
local frac="${BASH_REMATCH[2]}"
# Convert fractional hours: 0.5h = 30m, 1.5h = 90m
echo $((hours * 60 + frac * 6))
return 0
fi
if [[ "$estimate" =~ ^([0-9]+)\.([0-9]+)h$ ]]; then
local hours="${BASH_REMATCH[1]}"
local frac="${BASH_REMATCH[2]}"
# Convert fractional hours using awk for correct decimal handling
# e.g., 0.25h = 15m, 0.5h = 30m, 1.5h = 90m
awk "BEGIN { printf \"%d\", ${hours}.${frac} * 60 }"
return 0
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/batch-cleanup-helper.sh around lines 74 - 80, The
fractional-hour handling uses "frac * 6" which treats the fraction as a single
decimal digit and breaks for multi-digit fractions; update the branch that
matches "$estimate" to compute minutes correctly by interpreting the fractional
string as a proper decimal (e.g., build "0.$frac" or compute frac/(10^len) ) and
then calculate total minutes as hours*60 + decimal_fraction*60 using a reliable
tool (awk or bc) or integer math with the fraction length; adjust the echo to
output that computed minutes and keep the same match on BASH_REMATCH to locate
the code.

Comment on lines +91 to +120
is_task_unblocked() {
local task_line="$1"
local todo_file="$2"

# Extract blocked-by: field
local blocked_by
blocked_by=$(echo "$task_line" | grep -oE 'blocked-by:[^ ]+' | sed 's/blocked-by://' || true)

if [[ -z "$blocked_by" ]]; then
return 0 # No dependencies — unblocked
fi

# Check each dependency
local dep
IFS=',' read -ra deps <<<"$blocked_by"
for dep in "${deps[@]}"; do
dep="${dep// /}"
[[ -z "$dep" ]] && continue

# Check if dependency is complete ([x]) in TODO.md
local dep_line
dep_line=$(grep -E "^[[:space:]]*- \[x\] ${dep} " "$todo_file" 2>/dev/null | head -1 || true)
if [[ -z "$dep_line" ]]; then
# Dependency not complete — task is blocked
return 1
fi
done

return 0 # All dependencies resolved
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find is_task_blocked definition and context
rg -n 'is_task_blocked' --type=sh -C3 | head -100

Repository: marcusquinn/aidevops

Length of output: 559


🏁 Script executed:

# Find _check_and_skip_if_blocked definition
rg -n '_check_and_skip_if_blocked' --type=sh -C3 | head -100

Repository: marcusquinn/aidevops

Length of output: 2072


🏁 Script executed:

# Check what scripts source what
fd '\.sh$' -x grep -l 'source\|^\.' {} \; | head -20

Repository: marcusquinn/aidevops

Length of output: 663


🏁 Script executed:

# Get a summary of all script files and their sourcing patterns
fd '\.sh$' | sort

Repository: marcusquinn/aidevops

Length of output: 11714


🏁 Script executed:

# Find where is_task_blocked is defined
rg -n '^is_task_blocked\s*\(' --type=sh -A 20

Repository: marcusquinn/aidevops

Length of output: 46


🏁 Script executed:

# Check what batch-cleanup-helper.sh sources
head -50 .agents/scripts/batch-cleanup-helper.sh

Repository: marcusquinn/aidevops

Length of output: 2006


🏁 Script executed:

# Check supervisor/_common.sh for task blocking logic
cat -n .agents/scripts/supervisor/_common.sh | head -100

Repository: marcusquinn/aidevops

Length of output: 3560


🏁 Script executed:

# Broader search for is_task_blocked - check if it's defined anywhere
rg -n 'is_task_blocked' --type=sh

Repository: marcusquinn/aidevops

Length of output: 172


🏁 Script executed:

# Check supervisor/dispatch.sh since batch-cleanup-helper sources it
cat -n .agents/scripts/supervisor/dispatch.sh | head -80

Repository: marcusquinn/aidevops

Length of output: 3116


🏁 Script executed:

# Check cron.sh around line 233 for is_task_blocked definition or context
sed -n '1,250p' .agents/scripts/supervisor/cron.sh | tail -100

Repository: marcusquinn/aidevops

Length of output: 2580


🏁 Script executed:

# Search for any function definition starting with is_ or _check
rg -n '^\s*(is_|_check)' --type=sh .agents/scripts/supervisor/ | head -40

Repository: marcusquinn/aidevops

Length of output: 1525


🏁 Script executed:

# Get the full cron.sh to understand its structure
wc -l .agents/scripts/supervisor/cron.sh

Repository: marcusquinn/aidevops

Length of output: 102


🏁 Script executed:

# Verify the exact context at cron.sh line 233
sed -n '220,240p' .agents/scripts/supervisor/cron.sh

Repository: marcusquinn/aidevops

Length of output: 670


🏁 Script executed:

# Check if is_task_blocked appears anywhere as an alias or indirect call
rg -n 'is_task_blocked|declare.*is_task_blocked' --type=sh

Repository: marcusquinn/aidevops

Length of output: 172


🏁 Script executed:

# Get the complete is_task_unblocked from batch-cleanup-helper for comparison
sed -n '91,120p' .agents/scripts/batch-cleanup-helper.sh

Repository: marcusquinn/aidevops

Length of output: 816


Extract and share blocked-by dependency check — cron.sh currently fails at runtime.

The function is_task_blocked() called at cron.sh:233 is undefined and will cause a runtime error. Meanwhile, batch-cleanup-helper.sh implements a working version: is_task_unblocked() (lines 91-120).

Extract this logic to supervisor/_common.sh as a shared is_task_blocked() function (inverting the return semantics to match cron.sh's expectation), then use it in both cron.sh and batch-cleanup-helper.sh to eliminate the duplication and fix the broken reference.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/batch-cleanup-helper.sh around lines 91 - 120, The cron job
fails because cron.sh calls an undefined is_task_blocked(); copy the
dependency-check logic from is_task_unblocked() in batch-cleanup-helper.sh into
supervisor/_common.sh as a single shared function named is_task_blocked()
(invert the boolean semantics so it returns 0 when the task IS blocked and 1
when unblocked), ensure it extracts the blocked-by: field, splits commas, trims
spaces, and checks for completed "[x]" entries in TODO.md the same way, then
update cron.sh and batch-cleanup-helper.sh to source supervisor/_common.sh and
replace their local is_task_unblocked()/calls with the new is_task_blocked()
implementation.

Comment on lines +190 to +198
# Check if already tracked in supervisor DB
if [[ -f "$SUPERVISOR_DB" ]]; then
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)
if [[ -n "$existing" && "$existing" != "cancelled" && "$existing" != "complete" ]]; then
log_info " $task_id: already tracked in supervisor (status: $existing) — skipping"
continue
fi
fi
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Completed tasks are not skipped — risks duplicate dispatch.

The condition on line 194 allows tasks in complete state to pass through as eligible. A complete task already has a worker that finished (and likely created a PR). Re-dispatching it in a batch creates duplicate work.

Compare with Strategy 1 in cron.sh (line 308) where complete tasks are explicitly skipped.

Proposed fix: also skip post-completion lifecycle states
-			if [[ -n "$existing" && "$existing" != "cancelled" && "$existing" != "complete" ]]; then
+			if [[ -n "$existing" && "$existing" != "cancelled" ]]; then
 				log_info "  $task_id: already tracked in supervisor (status: $existing) — skipping"
 				continue
 			fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/batch-cleanup-helper.sh around lines 190 - 198, The existing
check using the SUPERVISOR_DB/db/sql_escape lookup mistakenly allows tasks with
status "complete" to pass through; change the conditional around the variable
existing (result of db ... SELECT status ...) so that it treats "complete" as a
skipped/post-completion state (e.g. test for [[ -n "$existing" && ( "$existing"
== "cancelled" || "$existing" == "complete" ) ]] and then log_info "  $task_id:
already tracked in supervisor (status: $existing) — skipping" and continue).
Update the condition in batch-cleanup-helper.sh where existing is set to ensure
complete tasks are skipped.

Comment on lines +355 to +366
# Dispatch headless worker
local dispatch_cmd=("$ai_cli" run --format json)

# Add model flag if supported
if [[ "$ai_cli" == "opencode" ]]; then
dispatch_cmd+=(--model "anthropic/claude-sonnet-4-6")
fi

nohup "${dispatch_cmd[@]}" "$worker_prompt" \
>"$log_file" 2>&1 &
local worker_pid=$!
echo "$worker_pid" >"$BATCH_CLEANUP_PID_FILE"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Worker launched without cd to repo — will fail in cron context.

The nohup dispatch (line 363) inherits the caller's cwd. When triggered from cron or the supervisor pulse, this is likely $HOME, not the repository. The worker prompt references TODO.md and todo/ which won't be found.

Compare with dispatch_decomposition_worker in cron.sh which explicitly generates cd '${repo}' in its dispatch script (line 797).

Proposed fix: cd to repo before launching worker
 	# Dispatch headless worker
-	local dispatch_cmd=("$ai_cli" run --format json)
+	# Ensure worker runs in the target repository
+	cd "$repo" || {
+		log_error "Failed to cd to repo: $repo"
+		return 1
+	}
+
+	local dispatch_cmd=("$ai_cli" run --format json)

Alternatively, follow the pattern from dispatch_decomposition_worker and generate a wrapper script that includes an explicit cd.

📝 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.

Suggested change
# Dispatch headless worker
local dispatch_cmd=("$ai_cli" run --format json)
# Add model flag if supported
if [[ "$ai_cli" == "opencode" ]]; then
dispatch_cmd+=(--model "anthropic/claude-sonnet-4-6")
fi
nohup "${dispatch_cmd[@]}" "$worker_prompt" \
>"$log_file" 2>&1 &
local worker_pid=$!
echo "$worker_pid" >"$BATCH_CLEANUP_PID_FILE"
# Dispatch headless worker
# Ensure worker runs in the target repository
cd "$repo" || {
log_error "Failed to cd to repo: $repo"
return 1
}
local dispatch_cmd=("$ai_cli" run --format json)
# Add model flag if supported
if [[ "$ai_cli" == "opencode" ]]; then
dispatch_cmd+=(--model "anthropic/claude-sonnet-4-6")
fi
nohup "${dispatch_cmd[@]}" "$worker_prompt" \
>"$log_file" 2>&1 &
local worker_pid=$!
echo "$worker_pid" >"$BATCH_CLEANUP_PID_FILE"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/batch-cleanup-helper.sh around lines 355 - 366, The worker
is launched with nohup using dispatch_cmd and inherits the caller CWD so file
references in worker_prompt (e.g., TODO.md, todo/) will fail under cron; update
the dispatch to cd into the repository before launching the worker (either
prepend a "cd '${repo}' &&" to the dispatched command or generate a small
wrapper script like dispatch_decomposition_worker in cron.sh that does an
explicit cd then exec the ai_cli command), ensuring the code that builds
dispatch_cmd (and the nohup invocation) runs from the repo and still writes the
worker PID to BATCH_CLEANUP_PID_FILE.

Comment on lines +554 to +555
local batch_cleanup_helper="${SCRIPT_DIR}/../batch-cleanup-helper.sh"
if [[ -x "$batch_cleanup_helper" ]]; then
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify the directory structure and where SCRIPT_DIR resolves
echo "=== Looking for batch-cleanup-helper.sh ==="
fd -t f 'batch-cleanup-helper.sh'

echo ""
echo "=== SCRIPT_DIR definition in supervisor-helper.sh ==="
rg -n 'SCRIPT_DIR=' .agents/scripts/supervisor-helper.sh | head -5

echo ""
echo "=== Path used in cron.sh (lines around 554) ==="
sed -n '550,560p' .agents/scripts/supervisor/cron.sh

echo ""
echo "=== All batch-cleanup-helper references in supervisor-helper.sh ==="
rg -n 'batch.*cleanup.*helper' .agents/scripts/supervisor-helper.sh

echo ""
echo "=== All batch-cleanup-helper references in cron.sh ==="
rg -n 'batch.*cleanup.*helper' .agents/scripts/supervisor/cron.sh

Repository: marcusquinn/aidevops

Length of output: 1657


Path resolution bug — Strategy 5 will never execute in cron context.

SCRIPT_DIR is set to .agents/scripts/ in supervisor-helper.sh line 167. The path ${SCRIPT_DIR}/../batch-cleanup-helper.sh resolves to .agents/batch-cleanup-helper.sh, but the helper actually lives at .agents/scripts/batch-cleanup-helper.sh.

Compare with the correct path in supervisor-helper.sh line 702: ${SCRIPT_DIR}/batch-cleanup-helper.sh (without ../). The -x check silently fails, making the entire Strategy 5 block dead code.

Proposed fix
-	local batch_cleanup_helper="${SCRIPT_DIR}/../batch-cleanup-helper.sh"
+	local batch_cleanup_helper="${SCRIPT_DIR}/batch-cleanup-helper.sh"
	if [[ -x "$batch_cleanup_helper" ]]; then

Additionally, add error logging when the helper isn't found (consistent with supervisor-helper.sh line 704):

	if [[ -x "$batch_cleanup_helper" ]]; then
+	else
+		log_warn "batch-cleanup-helper.sh not found or not executable at $batch_cleanup_helper"
	fi
📝 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.

Suggested change
local batch_cleanup_helper="${SCRIPT_DIR}/../batch-cleanup-helper.sh"
if [[ -x "$batch_cleanup_helper" ]]; then
local batch_cleanup_helper="${SCRIPT_DIR}/batch-cleanup-helper.sh"
if [[ -x "$batch_cleanup_helper" ]]; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor/cron.sh around lines 554 - 555, Fix the path
resolution for the batch-cleanup helper: change how batch_cleanup_helper is
built so it uses "${SCRIPT_DIR}/batch-cleanup-helper.sh" (not
"${SCRIPT_DIR}/../batch-cleanup-helper.sh") so the -x check for
batch_cleanup_helper succeeds in the cron context; also add an error log when
the helper is not found/ not executable (matching the behavior used in
supervisor-helper.sh) so the Strategy 5 block doesn't silently fail. Reference:
variable SCRIPT_DIR, variable batch_cleanup_helper and the Strategy 5 block in
cron.sh.

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.

1 participant