Skip to content

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Feb 8, 2026

Summary

  • Fix create_task_worktree() stdout leak where git branch -D output ("Deleted branch ...") polluted the function's return value when captured via $(...), causing dispatch to fail with invalid worktree paths
  • Add defensive validation in cmd_dispatch() that checks the returned worktree path is a real directory before proceeding
  • Add 3 regression tests in test-supervisor-state-machine.sh (Section 7: Worktree Path Integrity) verifying clean single-line output

Root Cause

When a stale branch needed cleanup, git branch -D "$branch_name" 2>/dev/null suppressed stderr but not stdout. The output Deleted branch feature/tXXX (was abc1234). was prepended to the worktree path, causing cd to fail in the nohup dispatch — resulting in 7-byte logs containing only EXIT:1.

Changes

File Change
.agents/scripts/supervisor-helper.sh 2>/dev/null&>/dev/null on 4 git cleanup commands in create_task_worktree()
.agents/scripts/supervisor-helper.sh Added [[ ! -d "$worktree_path" ]] guard after create_task_worktree() returns in cmd_dispatch()
tests/test-supervisor-state-machine.sh Added Section 7 with 3 assertions: single-line output, valid directory, no "Deleted branch" pollution

Testing

All 78 tests pass (77 pass, 1 pre-existing skip, 0 failures):

=== Worktree Path Integrity ===
  PASS create_task_worktree returns exactly 1 line (no stdout pollution)
  PASS create_task_worktree returns a valid directory path
  PASS create_task_worktree output is free of 'Deleted branch' pollution

Unblocks t169 and t173 which both failed with Max retries exceeded during re-prompt due to this bug.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed stdout leakage in worktree management commands, ensuring clean return values and preventing output pollution.
    • Added validation checks to verify worktree directory paths exist before processing.
  • Tests

    • Introduced comprehensive regression tests for worktree path integrity, validating output cleanliness and proper directory validation without Git output pollution.

git branch -D outputs 'Deleted branch ...' to stdout, which pollutes the
return value when captured via $(...). This caused dispatch to fail with
invalid worktree paths (7-byte logs containing only EXIT:1).

Changes:
- Change 2>/dev/null to &>/dev/null on git cleanup commands in
  create_task_worktree() to suppress both stdout and stderr
- Add worktree path validation guard in cmd_dispatch() that checks
  the returned path is a real directory before proceeding
- Add regression test (3 assertions) in test-supervisor-state-machine.sh
  verifying clean single-line output from create_task_worktree
@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 addresses a critical bug where git command output was inadvertently captured as part of a function's return value, leading to invalid worktree paths and subsequent task dispatch failures. The changes ensure that all git commands used for cleanup properly suppress their output, and a new validation step is introduced to robustly check the integrity of worktree paths before use, significantly improving the reliability of task dispatch.

Highlights

  • Stdout Leak Fix: Resolved an issue in create_task_worktree() where git branch -D output polluted the function's return value, causing dispatch failures. This was achieved by redirecting both stdout and stderr to /dev/null for relevant git commands.
  • Defensive Validation: Implemented a new validation step in cmd_dispatch() to ensure that the worktree path returned by create_task_worktree() is a valid directory, preventing further processing with corrupted paths.
  • Regression Tests: Added three new regression tests in test-supervisor-state-machine.sh to verify that create_task_worktree() returns a clean, single-line, valid directory path free of stdout pollution.
Changelog
  • .agents/scripts/supervisor-helper.sh
    • Modified four git cleanup commands within create_task_worktree() to use &>/dev/null instead of 2>/dev/null to suppress both stdout and stderr.
    • Added a new conditional check in cmd_dispatch() to validate if the $worktree_path is a valid directory, logging an error and failing the task if it's not.
  • tests/test-supervisor-state-machine.sh
    • Introduced a new 'Worktree Path Integrity' section (Section 7) with three new tests.
    • Added a test to confirm create_task_worktree returns exactly one line of output.
    • Added a test to verify the output of create_task_worktree is a valid directory path.
    • Added a test to ensure the output of create_task_worktree does not contain 'Deleted branch' pollution.
Activity
  • The pull request fixes issues t169 and t173, which were experiencing 'Max retries exceeded during re-prompt' due to the identified bug.
  • All 78 tests pass, including the 3 new regression tests, confirming the fix and preventing future regressions.
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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 8, 2026

Walkthrough

This PR fixes stdout leakage in the supervisor script by silencing Git and worktree command outputs in create_task_worktree, and adds validation in cmd_dispatch to verify the derived worktree path exists. A regression test suite validates clean output without pollution.

Changes

Cohort / File(s) Summary
Stdout Suppression & Path Validation
.agents/scripts/supervisor-helper.sh
Redirected stdout to /dev/null for worktree removal, pruning, and branch deletion operations in create_task_worktree to prevent leakage into return values. Added validation in cmd_dispatch to ensure the worktree path exists as a directory before dispatch, with early failure logging if invalid.
Regression Tests
tests/test-supervisor-state-machine.sh
New "Worktree Path Integrity" test section validates that create_task_worktree returns single-line directory paths without stdout pollution (e.g., "Deleted branch" leak). Tests verify path validity, directory existence, and cleanup.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

💨 Silence the chatter, keep output clean,
Worktrees shine brighter without the in-between,
Paths validated, no leaks in sight,
A-grade automation, pristine and tight! 🎯

🚥 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 summarizes the main change: suppressing stdout pollution in create_task_worktree, with relevant issue references (t169, t173).
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ 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 bugfix/worktree-stdout-leak

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.

@github-actions
Copy link

github-actions bot commented Feb 8, 2026

🔍 Code Quality Report

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

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

�[0;34m[INFO]�[0m Recent monitoring activity:
Sun Feb 8 18:41:15 UTC 2026: Code review monitoring started
Sun Feb 8 18:41:15 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 37

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 37
  • VULNERABILITIES: 0

Generated on: Sun Feb 8 18:41:18 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 8, 2026

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: 2

🤖 Fix all issues with AI agents
In `@tests/test-supervisor-state-machine.sh`:
- Around line 1029-1036: The test falsely passes when worktree_output is empty
because echo "" | wc -l yields 1; add an explicit empty-output guard before the
line_count check: test if worktree_output is empty (using the worktree_output
variable) and fail immediately with a clear message if so, otherwise compute
line_count as before and assert it equals 1; reference create_task_worktree,
worktree_output, and line_count so you update the existing condition that
currently does the wc -l check.
- Around line 1022-1027: After sourcing SUPERVISOR_SCRIPT and invoking cmd_init
(which calls ensure_db), add an explicit database validation step: verify the
SUPERVISOR_DB file exists and that a simple query can be executed against it
(e.g., a SELECT 1) to ensure ensure_db actually succeeded before calling
create_task_worktree; also stop silencing source's stderr/stdout or assert
cmd_init/ensure_db exit codes so failures are detected (references:
SUPERVISOR_SCRIPT, cmd_init, ensure_db, SUPERVISOR_DB, create_task_worktree,
TEST_DIR, WORKTREE_TEST_REPO).
🧹 Nitpick comments (3)
.agents/scripts/supervisor-helper.sh (1)

2683-2690: Preserve stderr for cleanup failures while silencing stdout.

&>/dev/null hides useful error output. To keep return-value cleanliness while retaining diagnostics, redirect stdout only and send stderr to the supervisor log.

🔧 Suggested change
-            git -C "$repo" worktree remove "$worktree_path" --force &>/dev/null || rm -rf "$worktree_path"
-            git -C "$repo" worktree prune &>/dev/null || true
+            git -C "$repo" worktree remove "$worktree_path" --force >/dev/null 2>>"$SUPERVISOR_LOG" || rm -rf "$worktree_path"
+            git -C "$repo" worktree prune >/dev/null 2>>"$SUPERVISOR_LOG" || true
@@
-        git -C "$repo" branch -D "$branch_name" &>/dev/null || true
+        git -C "$repo" branch -D "$branch_name" >/dev/null 2>>"$SUPERVISOR_LOG" || true
@@
-        git -C "$repo" push origin --delete "$branch_name" &>/dev/null || true
+        git -C "$repo" push origin --delete "$branch_name" >/dev/null 2>>"$SUPERVISOR_LOG" || true

As per coding guidelines, automation scripts should emphasize clear logging and feedback.

tests/test-supervisor-state-machine.sh (2)

995-997: Section numbering is out of order.

"SECTION 7" is placed after Sections 14b and the Evaluate Worker section. This will confuse anyone reading the test output or scanning the file. Consider renaming to SECTION 15 (or the next available number) to maintain sequential ordering.

🔢 Proposed fix
-# SECTION 7: Worktree Path Integrity
+# SECTION 15: Worktree Path Integrity

1006-1006: Trap override silently drops any traps registered between line 59 and here.

This replaces the original trap 'rm -rf "$TEST_DIR"' EXIT from line 59. It works today, but if a future section inserts another trap between lines 59 and 1006, it will be silently discarded. A more resilient pattern appends to the existing trap.

🛡️ Safer trap chaining
-trap 'rm -rf "$WORKTREE_TEST_DIR"; rm -rf "$TEST_DIR"' EXIT
+trap 'rm -rf "$WORKTREE_TEST_DIR" "$TEST_DIR"' EXIT

Even better, consider using a cleanup function that accumulates directories, or simply add $WORKTREE_TEST_DIR to the same rm -rf as the original trap at line 59 so there's a single trap definition.

Comment on lines +1022 to +1027
worktree_output=$(bash -c "
export AIDEVOPS_SUPERVISOR_DIR='$TEST_DIR'
set -- init
source '$SUPERVISOR_SCRIPT' >/dev/null
create_task_worktree 'wt-test-001' '$WORKTREE_TEST_REPO' true
" 2>/dev/null)
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
# Find the supervisor-related scripts
fd -type f -name "*supervisor*" | head -20

Repository: marcusquinn/aidevops

Length of output: 234


🏁 Script executed:

# Read the test file around the flagged lines
wc -l tests/test-supervisor-state-machine.sh

Repository: marcusquinn/aidevops

Length of output: 107


🏁 Script executed:

#!/bin/bash
# Find supervisor-related scripts correctly
find . -name "*supervisor*" -type f

Repository: marcusquinn/aidevops

Length of output: 185


🏁 Script executed:

# Read test file around the flagged lines with context
sed -n '1015,1035p' tests/test-supervisor-state-machine.sh

Repository: marcusquinn/aidevops

Length of output: 1104


🏁 Script executed:

#!/bin/bash
# Read supervisor-helper.sh to understand the dispatch mechanism
wc -l ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 107


🏁 Script executed:

# Find the main function and entry point pattern
rg -n 'main\s*"\$@"' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 78


🏁 Script executed:

# Find cmd_init function
rg -n 'cmd_init' ./.agents/scripts/supervisor-helper.sh | head -20

Repository: marcusquinn/aidevops

Length of output: 116


🏁 Script executed:

#!/bin/bash
# Read the main function dispatch logic
sed -n '8200,8240p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 1368


🏁 Script executed:

# Read cmd_init function
sed -n '906,950p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 1341


🏁 Script executed:

# Find the main function definition
rg -n '^main\s*\(' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 77


🏁 Script executed:

#!/bin/bash
# Find log_success and log_info definitions
rg -n 'log_success|log_info' ./.agents/scripts/supervisor-helper.sh | head -5

Repository: marcusquinn/aidevops

Length of output: 372


🏁 Script executed:

# Find ensure_db definition
rg -n 'ensure_db\s*\(' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 81


🏁 Script executed:

# Find create_task_worktree definition
rg -n 'create_task_worktree\s*\(' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 93


🏁 Script executed:

#!/bin/bash
# Read ensure_db to check error handling
sed -n '594,630p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 2391


🏁 Script executed:

# Read create_task_worktree function
sed -n '2619,2680p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 2987


🏁 Script executed:

# Check if there's error handling in cmd_init after ensure_db
sed -n '906,920p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 487


🏁 Script executed:

#!/bin/bash
# Check if ensure_db has any set -e or error handling
sed -n '594,670p' ./.agents/scripts/supervisor-helper.sh | grep -E 'set -e|return [1-9]|exit [1-9]||| *return'

Repository: marcusquinn/aidevops

Length of output: 3970


🏁 Script executed:

# Check if cmd_init checks ensure_db return value
sed -n '906,920p' ./.agents/scripts/supervisor-helper.sh | grep -E 'ensure_db.*\$?||| *true|&& *return'

Repository: marcusquinn/aidevops

Length of output: 487


🏁 Script executed:

# Verify main dispatch pattern - check if set -- modifies what main receives
rg -n 'show_usage' ./.agents/scripts/supervisor-helper.sh -B2 -A2 | head -30

Repository: marcusquinn/aidevops

Length of output: 467


🏁 Script executed:

#!/bin/bash
# Check if cmd_init relies on ensure_db succeeding
# Look for any error handling pattern in cmd_init
sed -n '906,920p' ./.agents/scripts/supervisor-helper.sh

Repository: marcusquinn/aidevops

Length of output: 487


🏁 Script executed:

# Check if create_task_worktree depends on DB state or just function definitions
sed -n '2619,2650p' ./.agents/scripts/supervisor-helper.sh | head -40

Repository: marcusquinn/aidevops

Length of output: 1510


🏁 Script executed:

# Verify what happens in test after create_task_worktree - does it validate DB state?
sed -n '1022,1045p' tests/test-supervisor-state-machine.sh

Repository: marcusquinn/aidevops

Length of output: 968


Error suppression masks whether cmd_init / database initialization actually succeeded — test can pass even if DB is non-functional.

The set -- init workaround is necessary and already well-documented in the preceding comment. However, the actual risk is deeper: cmd_init calls ensure_db without checking its return code (line 906 of supervisor-helper.sh), and both stdout and stderr from sourcing are redirected away. If ensure_db fails silently (e.g., DB initialization fails but doesn't exit), cmd_init continues and returns 0.

More importantly, create_task_worktree operates only on git state (worktrees/branches), not the database — so the test can pass and return a valid directory path even if the supervisor database was never initialized. This test validates that function definitions load and create_task_worktree returns no extraneous stdout, but provides no assurance the supervisor DB is actually ready when the function runs.

Consider adding an explicit DB validation step (e.g., verify $SUPERVISOR_DB exists and can execute a simple query) before or after calling create_task_worktree to catch silent initialization failures.

🤖 Prompt for AI Agents
In `@tests/test-supervisor-state-machine.sh` around lines 1022 - 1027, After
sourcing SUPERVISOR_SCRIPT and invoking cmd_init (which calls ensure_db), add an
explicit database validation step: verify the SUPERVISOR_DB file exists and that
a simple query can be executed against it (e.g., a SELECT 1) to ensure ensure_db
actually succeeded before calling create_task_worktree; also stop silencing
source's stderr/stdout or assert cmd_init/ensure_db exit codes so failures are
detected (references: SUPERVISOR_SCRIPT, cmd_init, ensure_db, SUPERVISOR_DB,
create_task_worktree, TEST_DIR, WORKTREE_TEST_REPO).

Comment on lines +1029 to +1036
# Count lines — should be exactly 1 (the path)
line_count=$(echo "$worktree_output" | wc -l | tr -d ' ')
if [[ "$line_count" -eq 1 ]]; then
pass "create_task_worktree returns exactly 1 line (no stdout pollution)"
else
fail "create_task_worktree returned $line_count lines (stdout pollution detected)" \
"Output: $(echo "$worktree_output" | head -3)"
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

Empty output passes the "exactly 1 line" check — false-positive risk.

If create_task_worktree produces no output (empty string), echo "" | wc -l still returns 1, so this assertion would incorrectly PASS. The directory check on line 1039 would catch the failure downstream, but the first test gives a misleading result. Guard against this explicitly.

🐛 Proposed fix
+# Guard: empty output is an immediate failure
+if [[ -z "$worktree_output" ]]; then
+    fail "create_task_worktree returned empty output"
+else
 # Count lines — should be exactly 1 (the path)
 line_count=$(echo "$worktree_output" | wc -l | tr -d ' ')
 if [[ "$line_count" -eq 1 ]]; then
     pass "create_task_worktree returns exactly 1 line (no stdout pollution)"
 else
     fail "create_task_worktree returned $line_count lines (stdout pollution detected)" \
         "Output: $(echo "$worktree_output" | head -3)"
 fi
+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
# Count lines — should be exactly 1 (the path)
line_count=$(echo "$worktree_output" | wc -l | tr -d ' ')
if [[ "$line_count" -eq 1 ]]; then
pass "create_task_worktree returns exactly 1 line (no stdout pollution)"
else
fail "create_task_worktree returned $line_count lines (stdout pollution detected)" \
"Output: $(echo "$worktree_output" | head -3)"
fi
# Guard: empty output is an immediate failure
if [[ -z "$worktree_output" ]]; then
fail "create_task_worktree returned empty output"
else
# Count lines — should be exactly 1 (the path)
line_count=$(echo "$worktree_output" | wc -l | tr -d ' ')
if [[ "$line_count" -eq 1 ]]; then
pass "create_task_worktree returns exactly 1 line (no stdout pollution)"
else
fail "create_task_worktree returned $line_count lines (stdout pollution detected)" \
"Output: $(echo "$worktree_output" | head -3)"
fi
fi
🤖 Prompt for AI Agents
In `@tests/test-supervisor-state-machine.sh` around lines 1029 - 1036, The test
falsely passes when worktree_output is empty because echo "" | wc -l yields 1;
add an explicit empty-output guard before the line_count check: test if
worktree_output is empty (using the worktree_output variable) and fail
immediately with a clear message if so, otherwise compute line_count as before
and assert it equals 1; reference create_task_worktree, worktree_output, and
line_count so you update the existing condition that currently does the wc -l
check.

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

The pull request effectively addresses the stdout pollution issue in create_task_worktree() by redirecting both stdout and stderr of git commands to /dev/null. The addition of a defensive validation check in cmd_dispatch() further enhances the robustness of the system by ensuring that the worktree path is a valid directory. The new regression tests in test-supervisor-state-machine.sh provide excellent coverage for the fix, verifying single-line output, valid directory paths, and the absence of "Deleted branch" pollution. This is a solid fix that improves the reliability and correctness of the supervisor's worktree management.

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