Skip to content

fix: address critical quality-debt — jq/Python injection, post-increment, HTTP errors (batch 2)#3833

Closed
johnwaldo wants to merge 15 commits intomarcusquinn:mainfrom
johnwaldo:bugfix/quality-debt-batch2
Closed

fix: address critical quality-debt — jq/Python injection, post-increment, HTTP errors (batch 2)#3833
johnwaldo wants to merge 15 commits intomarcusquinn:mainfrom
johnwaldo:bugfix/quality-debt-batch2

Conversation

@johnwaldo
Copy link
Copy Markdown
Contributor

@johnwaldo johnwaldo commented Mar 8, 2026

Summary

Addresses critical security and robustness findings from CodeRabbit/Gemini review feedback on previously merged PRs. This is batch 2 of the quality-debt sprint.

Security fixes (3)

File Issue Fix
loop-common.sh GH#3798 Fix jq injection in loop_set_state, loop_block_task, loop_track_attempt, loop_should_block — use --arg for safe string interpolation
quickfile-helper.sh GH#3736 Fix Python code injection — pass variables via environment (os.environ) instead of shell interpolation into Python strings
worktree-helper.sh GH#3797 Fix hardcoded origin remote in branch deletion checks — use branch's actual remote via new branch_remote() helper to prevent data loss with multi-remote setups

Bug fixes (3)

File Issue Fix
worktree-helper.sh GH#3797 Make worktree_has_changes fail-safe — treat git status failures as "has changes" on destructive cleanup paths
enhancor-helper.sh GH#3731 Add HTTP error detection to api_request — return non-zero on 4xx/5xx instead of silently passing error HTML to jq
48 scripts GH#3793 Convert post-increment ((var++)) to pre-increment ((++var)) to prevent silent script termination under set -e when counter starts at 0

Files changed (50)

Batch 2 also includes the 8 scripts from the initial batch 2 commit (accessibility, deploy-agents, email-health-check, runway, setup-modules).

Closes #3797, closes #3798, closes #3793, closes #3731, closes #3736

Summary by CodeRabbit

  • New Features

    • WCAG-level mapping added to accessibility audits; new CLI options for audit tag sets.
    • Added support for a new quality CLI and a supervisor routine-status command.
    • Better remote-aware branch handling for deploy/worktree operations.
  • Bug Fixes

    • Improved accessibility, Lighthouse, WAVE and contrast audit reliability with robust HTTP/error handling and logging.
    • Deployment flows gain safer fallbacks and more resilient file-sync behavior.
    • Tool checks now report unknown/timeout results distinctly.
  • Chores

    • Large cross-repo refactor: standardized formatting, increment semantics, argument validation and safer JSON handling.

Fixes from CodeRabbit/Gemini review feedback on merged PRs:

- email-health-check-helper: replace 7 unsupported ternary operators, guard
  12 unguarded grep -o calls, fix 10 mutually exclusive grep -oc flags (GH#3537)
- runway-helper: fix remaining JSON injection in cmd_image ref array
  assembly, all cmd functions now use jq -n exclusively (GH#3543)
- accessibility-audit-helper: redirect stderr to LOG_FILE instead of
  /dev/null, replace python3 URL encoding with jq @uri, wire
  AUDIT_WCAG_LEVEL into axe tags, fix invalid --preset=mobile (GH#3538)
- accessibility-helper: fix Lighthouse --preset=mobile to --form-factor,
  replace python3 URL encoding with jq, redirect stderr to log (GH#3530)
- deploy-agents-on-merge: change --help from return 0 to exit 0 to prevent
  continued execution after help display (GH#3548)
- agent-deploy: add reason comment to shellcheck disable directive (GH#3499)
- mcp-setup: separate local declaration from assignment in 4 functions (GH#3500)
- plugins: remove error suppression on uv install, replace sed with
  parameter expansion for version parsing (GH#3319)

Closes marcusquinn#3537, closes marcusquinn#3543, closes marcusquinn#3538, closes marcusquinn#3530, closes marcusquinn#3548,
closes marcusquinn#3499, closes marcusquinn#3500, closes marcusquinn#3319
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 8, 2026

Walkthrough

Adds a WCAG→axe tag mapper and modernizes accessibility audits; standardizes many shell scripts (prefix-increment, logging, URL encoding, JSON handling); refactors Runway API client and loop state management; makes worktree remote-aware and adds safer deploy fallbacks. No public function signatures removed.

Changes

Cohort / File(s) Summary
Accessibility audit helpers
.agents/scripts/accessibility-audit-helper.sh
Adds _wcag_level_to_axe_tags; derives axe defaults from AUDIT_WCAG_LEVEL; improves logging, URL encoding, error handling, Lighthouse arg construction, and CLI tag passthrough.
Accessibility CLI & reporting
.agents/scripts/accessibility-helper.sh
Large refactor: unified logging/redirection, robust WAVE key loading, URL encoding, safer HTTP/JSON checks, Lighthouse/pa11y/email flows modernized; behavior preserved.
Runway client & commands
.agents/scripts/runway-helper.sh
Adds _require_arg, refactors curl wrapper, conditional JSON builders, normalized argument parsing for video/image/tts/sts/sfx/dub/isolate/status/wait; signatures unchanged.
Loop & state management
.agents/scripts/loop-common.sh
Major rewrite: safer jq usage, receipts/memory handling, guardrails/re-anchor generation, headless support, and structured state JSON; public interfaces retained.
Worktree remote-awareness
.agents/scripts/worktree-helper.sh
Adds branch_remote(branch) and uses it to detect pushed/deleted branches across remotes; adjusts safety checks for worktree operations.
Deploy & setup scripts
.agents/scripts/deploy-agents-on-merge.sh, setup-modules/agent-deploy.sh, setup-modules/mcp-setup.sh, setup-modules/plugins.sh
Refactors deploy flows with rsync/tar fallbacks, per-file error handling, minor variable/comment tweaks, and improved Python/uv handling.
Prefix-increment normalization (many scripts)
.agents/scripts/* (e.g., agent-sources-helper.sh, beads-sync-helper.sh, pre-commit-hook.sh, site-crawler-helper.sh, ...)
Replaced many ((var++)) with ((++var)) across numerous scripts to avoid set -e exit hazards; removed some `
HTTP/JSON & safety fixes
.agents/scripts/enhancor-helper.sh, quickfile-helper.sh, email-health-check-helper.sh, accessibility-helper.sh, ...
Improved API error handling, safer JSON/payload construction, environment-driven Python calls, stricter HTTP/JSON validation and logging; most behavior preserved but error paths tightened.
CLI & tooling additions
.agents/scripts/quality-cli-manager.sh
Adds QLTY_SCRIPT and integrates qlty into install/init/analyze/status/help flows.
Minor, localized edits
setup-modules/*, *.md, ...
Small refactors, comment tweaks, example expansion in video.md, portable hashing in markdown formatter, and other low-impact edits.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • PR #935: overlaps accessibility-audit-helper.sh changes (WCAG/axe and Lighthouse modifications).
  • PR #919: earlier accessibility tooling work that this diff extends (axe/WAVE/pa11y/Lighthouse areas).
  • PR #1567: related updates to worktree-helper.sh and remote/stale-branch handling.

Suggested labels

bug, external-contributor

"Scripts aglow with careful art,
Logs no longer go apart,
JSONs tidy, counters smart,
Remotes known — a safer start. 🚀"

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 77.48% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main change: batch 2 of quality-debt fixes addressing jq/Python injection, post-increment, and HTTP errors across 50 scripts.
Linked Issues check ✅ Passed All code changes align with linked issues: #3797 (worktree-helper remote detection), #3798 (loop-common jq injection), #3793 (post-increment to pre-increment), #3731 (enhancor-helper HTTP errors), #3736 (quickfile-helper Python injection).
Out of Scope Changes check ✅ Passed All changes are scoped to linked quality-debt issues. Documentation updates (graduated-learnings.md, video.md, context-guardrails.md) support changes. No extraneous features or unrelated refactors detected.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

…post-increment, HTTP errors

Security fixes:
- loop-common.sh: Fix jq injection in loop_set_state, loop_block_task,
  loop_track_attempt, loop_should_block — use --arg for safe string
  interpolation (GH#3798)
- quickfile-helper.sh: Fix Python code injection — pass variables via
  environment instead of shell interpolation (GH#3736)
- worktree-helper.sh: Fix hardcoded 'origin' remote in branch deletion
  checks — use branch's actual remote to prevent data loss with
  multi-remote setups (GH#3797)
- worktree-helper.sh: Make worktree_has_changes fail-safe — treat git
  status failures as 'has changes' on destructive paths (GH#3797)

Bug fixes:
- enhancor-helper.sh: Add HTTP error detection to api_request — return
  non-zero on 4xx/5xx instead of silently passing error HTML to jq (GH#3731)
- 48 scripts: Convert post-increment ((var++)) to pre-increment ((++var))
  to prevent silent script termination under set -e when counter is 0 (GH#3793)
- loop-common.sh: Remove unused receipts variable in loop_create_receipt

Closes marcusquinn#3797, closes marcusquinn#3798, closes marcusquinn#3793, closes marcusquinn#3731, closes marcusquinn#3736
@johnwaldo johnwaldo changed the title fix: address critical quality-debt across 8 scripts (batch 2) fix: address critical quality-debt — jq/Python injection, post-increment, HTTP errors (batch 2) Mar 8, 2026
coderabbitai[bot]
coderabbitai Bot previously requested changes Mar 8, 2026
Copy link
Copy Markdown
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: 13

🧹 Nitpick comments (1)
.agents/scripts/email-health-check-helper.sh (1)

2-2: Consider adding a reason comment to the ShellCheck disable directive.

Per project conventions, ShellCheck disable directives benefit from a brief explanation. This one likely suppresses warnings about variables sourced from shared-constants.sh that ShellCheck cannot trace.

📝 Suggested improvement
-# shellcheck disable=SC2034
+# shellcheck disable=SC2034 # Variables from shared-constants.sh appear unused to ShellCheck
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/email-health-check-helper.sh at line 2, Add a brief
explanatory comment next to the ShellCheck disable directive "# shellcheck
disable=SC2034" explaining why SC2034 is being suppressed (e.g., variables are
intentionally sourced from shared-constants.sh and appear unused to shellcheck).
Update the top of .agents/scripts/email-health-check-helper.sh to include that
reason so reviewers understand the suppression and to link it to the sourced
file (shared-constants.sh) or the specific vars it covers.
🤖 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/accessibility-audit-helper.sh:
- Around line 227-229: Add curl timeout flags to the WAVE and WebAIM API calls
so the script cannot hang: update the curl invocations that build requests to
"${WAVE_API_URL}?key=${WAVE_API_KEY}&url=${encoded_url}&reporttype=${report_type}"
and the corresponding WebAIM call to include --max-time using the shared
constants DEFAULT_TIMEOUT (or LONG_TIMEOUT where appropriate) and also add
--connect-timeout for faster failure; ensure you source/use DEFAULT_TIMEOUT and
LONG_TIMEOUT from shared-constants.sh and apply them to both curl commands
referenced in the script (the WAVE call and the WebAIM call).

In @.agents/scripts/accessibility-helper.sh:
- Line 523: The report header is using the default $A11Y_WCAG_LEVEL instead of
the effective standard stored in local standard="${2:-$A11Y_WCAG_LEVEL}"; update
the code that calls parse_pa11y_report() to pass this effective standard
(standard) and ensure parse_pa11y_report() uses that parameter when generating
the header output so the report metadata reflects overrides correctly.
- Around line 633-647: The helper _grep_count currently uses grep -c which
counts matching lines and undercounts occurrences on minified HTML; update the
_grep_count function to use grep -o -i -E "$@" to output each match on its own
line and pipe to wc -l so each occurrence is counted (ensure you still redirect
errors to /dev/null and return 0 on no matches, preserving case-insensitive
behavior); then the callers like imgs_with_alt=$(_grep_count '<img [^>]*alt='
"$file") and total_imgs=$(_grep_count '<img ' "$file") will correctly count
multiple occurrences on the same line.
- Around line 449-452: The conversion from a Lighthouse decimal score to a
percentage currently uses bc and falls back to "0" when bc is missing, which
causes false failures; instead, compute pct using awk (which is POSIX-available)
by evaluating the expression "$score * 100" with awk and assign that to pct,
then keep the existing truncation to integer via int_pct="${pct%.*}" (or use
awk's int() if you prefer) so the code uses awk for the math and removes the
brittle bc fallback; locate the block using the variables score, pct, and
int_pct to update the pct assignment.
- Around line 914-927: The while loop reading URLs can miss the final line if
the file lacks a trailing newline; update the loop condition to process the last
record by changing `while IFS= read -r url; do` to `while IFS= read -r url || [
-n "$url" ]; do` (keep existing blank/comment skip logic and the body that calls
run_full_audit, updates count and failures, sleeps, and reads from urls_file) so
the final URL is handled even without a trailing newline.

In @.agents/scripts/deploy-agents-on-merge.sh:
- Around line 265-269: The restore loop that iterates over pdir ("custom" and
"draft") is copying the preserved directory itself into TARGET_DIR, causing
nested directories (e.g., $TARGET_DIR/custom/custom); instead copy the contents
of the preserved dir into the target directory or replace the target directory
before copying. Update the loop around tmp_preserve, pdir and TARGET_DIR to
either use a content-copy invocation (e.g., copy "$tmp_preserve/$pdir/." into
"$TARGET_DIR/$pdir/") or remove the existing "$TARGET_DIR/$pdir" before cp -R so
the preserved contents are restored without creating nested folders; apply this
change to the block that checks [[ -d "$tmp_preserve/$pdir" ]].
- Around line 313-356: The loop currently increments deployed but never
increments failed because set -e will cause the script to exit on the first
mkdir/cp/chmod failure; update the loop to handle failures explicitly: wrap or
replace the risky calls (mkdir -p, cp, chmod) with guarded checks (e.g., if !
mkdir -p "$target_parent"; then failed=$((failed+1)); log_warn "mkdir failed:
$rel_path"; continue; fi) and similarly check cp and chmod (or use cmd || {
failed=$((failed+1)); log_warn "..."; continue; }) so the script does not exit
on error and the failed counter is incremented properly; keep existing variables
deployed and failed and ensure the final log_warn "Deployed $deployed files,
$failed failed" and return 1 when failed > 0 remains unchanged.
- Around line 201-206: The tar fallback overlays files but doesn't remove stale
files; update the fallback branch (the block using (cd "$source_dir" && tar cf -
.) | (cd "$target_scripts_dir" && tar xf -)) to first remove existing contents
of "$target_scripts_dir" (safely deleting files/dirs inside target_scripts_dir
but not the directory itself) and then extract the tar, or extract into a
temporary directory and atomically replace/move it into "$target_scripts_dir";
reference the variables/source_dir and target_scripts_dir and the tar-based
branch when making the change.

In @.agents/scripts/email-health-check-helper.sh:
- Around line 764-768: The grep call used to compute small_fonts is missing the
defensive pattern used elsewhere; update the command substitution that assigns
small_fonts (the pipeline starting with grep -Eio 'font-size:...') to wrap the
grep in the established guard so it cannot cause a non-zero exit to fail the
pipeline (e.g., use the { grep -Eio ... || true; } form or append || true to the
grep invocation), preserving the rest of the pipeline (sed, while read, wc -l,
tr -d ' ') and ensuring behavior remains identical when grep finds no matches.

In @.agents/scripts/runway-helper.sh:
- Around line 106-115: Validate the audio flag before building the JSON: in the
runway-helper.sh function that sets local model/ prompt/ ratio/ duration/ audio
and calls jq, add a check that if $audio is non-empty it must be exactly "true"
or "false" (otherwise print a clear error message and exit 1); keep the jq
expression that converts audio to boolean via ($audio == "true") and the
duration tonumber logic unchanged. Apply the same validation at the other
occurrence mentioned (the second audio parsing block around lines 162-164) so
typos like "ture" or "yes" fail fast instead of being silently serialized to
false.
- Around line 132-175: The option parsing loop in runway-helper.sh reads "$2"
for many value-taking flags (e.g., the case branches for --image|-i, --video|-v,
--prompt|-p, --model|-m, --ratio|-r, --duration|-d, --seed|-s, --audio) without
checking there is a second positional argument; add a guard (for example [[ $#
-ge 2 ]]) before any branch that consumes "$2" and before doing shift 2, or
extract a small helper validate_operand() and call it from those branches, so
the script returns a clear error instead of triggering an unbound variable under
set -euo pipefail; apply this fix consistently to all listed blocks (lines
covering the same flag handlers throughout the script).
- Around line 42-67: The runway_api function currently hides transport errors
and writes HTTP error details to stdout; change it so curl diagnostics go to
stderr and any error body is emitted on stderr (not stdout) before returning
non-zero. Concretely, adjust the curl invocation arguments built in curl_args
(remove silent-only -s or use -sS so curl prints diagnostics on stderr) and
ensure the error-handling block that uses response/body sends pretty-printed
JSON and raw body to stderr (redirect output of jq/echo to >&2) rather than
stdout, keeping the existing http_code check and return 1 behavior in place.

---

Nitpick comments:
In @.agents/scripts/email-health-check-helper.sh:
- Line 2: Add a brief explanatory comment next to the ShellCheck disable
directive "# shellcheck disable=SC2034" explaining why SC2034 is being
suppressed (e.g., variables are intentionally sourced from shared-constants.sh
and appear unused to shellcheck). Update the top of
.agents/scripts/email-health-check-helper.sh to include that reason so reviewers
understand the suppression and to link it to the sourced file
(shared-constants.sh) or the specific vars it covers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: aca38b2d-875c-4dd2-824c-70a98beb8455

📥 Commits

Reviewing files that changed from the base of the PR and between 339facd and 562d71b.

📒 Files selected for processing (8)
  • .agents/scripts/accessibility-audit-helper.sh
  • .agents/scripts/accessibility-helper.sh
  • .agents/scripts/deploy-agents-on-merge.sh
  • .agents/scripts/email-health-check-helper.sh
  • .agents/scripts/runway-helper.sh
  • setup-modules/agent-deploy.sh
  • setup-modules/mcp-setup.sh
  • setup-modules/plugins.sh

Comment thread .agents/scripts/accessibility-audit-helper.sh
Comment thread .agents/scripts/accessibility-helper.sh Outdated
Comment thread .agents/scripts/accessibility-helper.sh
Comment thread .agents/scripts/accessibility-helper.sh Outdated
Comment thread .agents/scripts/accessibility-helper.sh Outdated
Comment thread .agents/scripts/email-health-check-helper.sh Outdated
Comment thread .agents/scripts/runway-helper.sh
Comment thread .agents/scripts/runway-helper.sh
Comment thread .agents/scripts/runway-helper.sh
Comment thread .agents/scripts/runway-helper.sh
@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 8h with 0 commits (struggle_ratio: 22051). The worker was tasked with addressing CHANGES_REQUESTED review feedback but produced no commits. Re-dispatching with a fresh worker.

- accessibility-audit-helper: add curl timeout bounds (DEFAULT_TIMEOUT/LONG_TIMEOUT)
- accessibility-helper: replace bc with awk for score conversion (POSIX portable)
- accessibility-helper: pass effective standard to parse_pa11y_report header
- accessibility-helper: fix _grep_count to count occurrences not lines (minified HTML)
- accessibility-helper: handle missing trailing newline in bulk URL loop
- deploy-agents-on-merge: clean target before tar fallback (match rsync --delete)
- deploy-agents-on-merge: fix nested dir restore (cp contents not dir itself)
- deploy-agents-on-merge: guard mkdir/cp/chmod so failed counter works under set -e
- email-health-check-helper: add { grep || true; } guard for consistency
- runway-helper: add -S flag and redirect error body to stderr
- runway-helper: validate --audio accepts only true/false
- runway-helper: add _require_arg guard to all value-taking options
coderabbitai[bot]
coderabbitai Bot previously requested changes Mar 8, 2026
Copy link
Copy Markdown
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: 11

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (8)
.agents/scripts/setup-local-api-keys.sh (2)

291-292: ⚠️ Potential issue | 🔴 Critical

Variable case mismatch breaks the tenant subcommand.

Line 291 assigns to script_dir (lowercase), but line 292 references SCRIPT_DIR (uppercase). Under set -u, this will fail with an unbound variable error when the tenant subcommand is invoked.

🐛 Proposed fix
 		local script_dir
 		script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" || exit
-		source "${SCRIPT_DIR}/shared-constants.sh"
+		source "${script_dir}/shared-constants.sh"
 
 		bash "$script_dir/credential-helper.sh" "$@"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/setup-local-api-keys.sh around lines 291 - 292, The tenant
subcommand fails due to a variable case mismatch: the script sets script_dir
(lowercase) but references SCRIPT_DIR (uppercase) causing an unbound variable
under set -u; fix by using a consistent identifier everywhere (either set
SCRIPT_DIR instead of script_dir or reference script_dir where SCRIPT_DIR is
used), e.g., ensure the assignment and the source line both use the same symbol
(script_dir or SCRIPT_DIR) so the call to source
"${SCRIPT_DIR}/shared-constants.sh" resolves correctly when running the tenant
subcommand.

264-266: ⚠️ Potential issue | 🟡 Minor

Argument access fails under set -u when invoked without arguments.

Line 265 accesses $1 directly, but with set -u enabled, this will error out before the case statement can route to the help handler at line 296. The intent is there but unreachable.

🛡️ Proposed fix for robustness
 main() {
-	local command="$1"
+	local command="${1:-}"
 	shift 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/setup-local-api-keys.sh around lines 264 - 266, The script's
main function accesses $1 directly which breaks under set -u when no args are
passed; change the assignment in main to safely default when empty (e.g.,
replace local command="$1" with local command="${1:-}" or "${1-}") so the script
won't error under set -u and the subsequent shift and your help/case routing
still run; update any related shift usage if you choose to test $# first (e.g.,
use if [ "$#" -eq 0 ]; then command=""; fi) to ensure the help handler in main
is reachable.
.agents/scripts/site-crawler-helper.sh (1)

700-710: ⚠️ Potential issue | 🟠 Major

Incomplete fix: other status code counters still use post-increment.

The pre-increment for code_other is correct, but code_200, code_301, code_302, code_404, and code_500 (lines 703-707) all start at 0 and still use post-increment. If the first status code in status_codes matches any of those patterns, the post-increment will return exit status 1 and terminate the script under set -e.

🐛 Proposed fix to apply pre-increment consistently
     local code_200=0 code_301=0 code_302=0 code_404=0 code_500=0 code_other=0
     for code in "${status_codes[@]}"; do
         case "$code" in
-            200) ((code_200++)) ;;
-            301) ((code_301++)) ;;
-            302) ((code_302++)) ;;
-            404) ((code_404++)) ;;
-            500) ((code_500++)) ;;
+            200) ((++code_200)) ;;
+            301) ((++code_301)) ;;
+            302) ((++code_302)) ;;
+            404) ((++code_404)) ;;
+            500) ((++code_500)) ;;
             *) ((++code_other)) ;;
         esac
     done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/site-crawler-helper.sh around lines 700 - 710, The counters
for HTTP statuses use post-increment which can return a non-zero exit status
under set -e; update all increments inside the for loop so they use
pre-increment for consistency: replace uses of ((code_200++)), ((code_301++)),
((code_302++)), ((code_404++)), and ((code_500++)) with pre-increment form
(e.g., ((++code_200))) while leaving the code_other pre-increment as-is; ensure
this change is applied within the for loop that iterates over the status_codes
array.
.agents/scripts/autogen-helper.sh (1)

61-69: ⚠️ Potential issue | 🟡 Minor

Handle the 65535 boundary explicitly in both fallback loops.

Both loops stop on < 65535, so a free 65535 is never returned by get_available_port. In the generated startup script, the same pattern can also fall through and announce 65535 even when it is still occupied. Please bail only when 65535 is busy, otherwise allow it as the last valid candidate.

Suggested fix
-    while lsof -i :"$port" >/dev/null 2>&1 && [[ $port -lt 65535 ]]; do
-        ((++port))
-    done
-    
-    if [[ $port -lt 65535 ]]; then
-        print_warning "Port $desired_port in use, using $port instead"
-        echo "$port"
-        return 0
-    fi
-    
-    print_error "No available ports found"
-    return 1
+    while lsof -i :"$port" >/dev/null 2>&1; do
+        if [[ $port -ge 65535 ]]; then
+            print_error "No available ports found"
+            return 1
+        fi
+        ((++port))
+    done
+
+    print_warning "Port $desired_port in use, using $port instead"
+    echo "$port"
+    return 0
-        while lsof -i :"$DESIRED_PORT" >/dev/null 2>&1 && [[ $DESIRED_PORT -lt 65535 ]]; do
-            ((++DESIRED_PORT))
-        done
-        echo "[INFO] Using port: $DESIRED_PORT"
+        while lsof -i :"$DESIRED_PORT" >/dev/null 2>&1; do
+            if [[ $DESIRED_PORT -ge 65535 ]]; then
+                echo "[ERROR] No available ports found"
+                exit 1
+            fi
+            ((++DESIRED_PORT))
+        done
+        echo "[INFO] Using port: $DESIRED_PORT"

As per coding guidelines, automation scripts should focus on reliability and robustness, and proper exit codes.

Also applies to: 285-289

.agents/scripts/langflow-helper.sh (1)

64-69: ⚠️ Potential issue | 🟡 Minor

Handle port 65535 correctly in both search paths.

These < 65535 checks skip a valid final port. If 65535 is the first free port, get_available_port() returns failure, and the generated launcher can still announce 65535 without confirming it is actually free.

💡 Suggested fix
-    while lsof -i :"$port" >/dev/null 2>&1 && [[ $port -lt 65535 ]]; do
+    while lsof -i :"$port" >/dev/null 2>&1 && [[ $port -lt 65535 ]]; do
         ((++port))
     done
-    
-    if [[ $port -lt 65535 ]]; then
+
+    if lsof -i :"$port" >/dev/null 2>&1; then
+        print_error "No available ports found"
+        return 1
+    fi
+
+    if [[ $port -le 65535 ]]; then
         print_warning "Port $desired_port in use, using $port instead"
         echo "$port"
         return 0
     fi
-    
-    print_error "No available ports found"
-    return 1

Apply the same post-loop occupied-port check inside the start-langflow.sh heredoc.

As per coding guidelines ".agents/scripts/*.sh: Automation scripts - focus on: Reliability and robustness".

Also applies to: 250-253

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

In @.agents/scripts/langflow-helper.sh around lines 64 - 69, The loop and
subsequent free-port check currently use "< 65535" which excludes port 65535;
update the port-search logic in get_available_port so both the while loop
condition and the post-loop availability check allow port 65535 (use "<= 65535"
or equivalent bounds logic), and apply the identical fix inside the
start-langflow.sh heredoc where the same check is duplicated (the block around
lines referenced in the review); ensure the final chosen port is actually
verified free with lsof before announcing it.
.agents/scripts/quickfile-helper.sh (1)

106-247: ⚠️ Potential issue | 🟠 Major

Fix JSON escaping in supplier/purchase instruction output and restore proper exit codes in batch mode.

The vulnerabilities are real:

  1. JSON escaping in instruction output (lines 106–241): Supplier names, invoice references, and line item descriptions from OCR are interpolated directly into JSON without escaping. In generate_supplier_instructions() (lines 117, 123, 126), bash echo outputs supplier names unescaped. In generate_purchase_instructions() (lines 219, 223, 232, 241), Python f-strings output supplier_id, inv_ref, and OCR-extracted descriptions without json.dumps(). If an OCR description contains "Item "Premium" Model" or a supplier name has quotes/newlines, the output JSON becomes malformed. Use json.dumps() to safely serialize the entire payload, not field-by-field printing.

  2. Exit code masking in batch mode (line 457): cmd_batch_record() accumulates failure counts but unconditionally returns 0, hiding partial failures from callers. Return non-zero when any batch item fails to enable proper error recovery upstream.

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

In @.agents/scripts/quickfile-helper.sh around lines 106 - 247, Supplier and
purchase instruction outputs are vulnerable because unescaped OCR data is
directly interpolated into JSON in generate_supplier_instructions() and
generate_purchase_instructions(), and batch failures are masked by
cmd_batch_record() always returning 0; fix by switching to proper JSON
serialization for the entire payload instead of manual field-by-field printing
(use json.dumps on the Python side to emit the full dict and update the bash
supplier helper to JSON-escape supplier_name when printing instructions), ensure
supplier_id/inv_ref/line descriptions are produced via JSON serialization rather
than raw f-strings/echo, and change cmd_batch_record() to return a non-zero exit
status when any failures were counted so callers can detect partial failures.
.agents/scripts/quality-cli-manager.sh (1)

233-341: ⚠️ Potential issue | 🟠 Major

Preserve multi-flag arguments as separate array elements instead of flattening to a single string.

The execute_cli_command() and analyze_with_clis() functions collapse multiple arguments into a single string using "$*", causing downstream CLI wrappers to misparse flags. For example, invoking with --fix --strict gets merged into "--fix --strict" as a single argument instead of two separate arguments, breaking all multi-flag analysis commands.

🛠️ Suggested fix
 execute_cli_command() {
     local cli="$1"
     local command="$2"
     shift 2
-    local args="$*"
+    local args=("$@")
     
     local script=""
     local cli_name=""
     
     case "$cli" in
         "$CLI_CODERABBIT")
             script="$CODERABBIT_SCRIPT"
             cli_name="CodeRabbit CLI"
             ;;
         "codacy")
             script="$CODACY_SCRIPT"
             cli_name="Codacy CLI"
             ;;
         "sonar")
             script="$SONAR_SCRIPT"
             cli_name="SonarScanner CLI"
             ;;
         "$CLI_SNYK")
             script="$SNYK_SCRIPT"
             cli_name="Snyk CLI"
             ;;
         *)
             print_error "Unknown CLI: $cli"
             return 1
             ;;
     esac
     
     if [[ ! -f "$script" ]]; then
         print_error "$cli_name script not found: $script"
         return 1
     fi
     
-    print_info "Executing: $cli_name $command $args"
-    bash "$script" "$command" "$args"
+    print_info "Executing: $cli_name $command ${args[*]}"
+    bash "$script" "$command" "${args[@]}"
     return $?
 }

 analyze_with_clis() {
     local target_cli="$1"
     shift
-    local args="$*"
+    local args=("$@")

     print_header "Running Quality Analysis"

     local success_count=0
     local total_count=0

     if [[ "$target_cli" == "all" || "$target_cli" == "$CLI_CODERABBIT" ]]; then
         print_info "Running CodeRabbit analysis..."
-        if execute_cli_command "$CLI_CODERABBIT" "review" "$args"; then
+        if execute_cli_command "$CLI_CODERABBIT" "review" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "all" || "$target_cli" == "codacy" ]]; then
         print_info "Running Codacy analysis..."
-        if execute_cli_command "codacy" "analyze" "$args"; then
+        if execute_cli_command "codacy" "analyze" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     # Add auto-fix option for Codacy
     if [[ "$target_cli" == "codacy-fix" ]]; then
         print_info "Running Codacy analysis with auto-fix..."
-        if execute_cli_command "codacy" "analyze" "--fix"; then
+        if execute_cli_command "codacy" "analyze" "--fix" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "all" || "$target_cli" == "sonar" ]]; then
         print_info "Running SonarQube analysis..."
-        if execute_cli_command "sonar" "analyze" "$args"; then
+        if execute_cli_command "sonar" "analyze" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "all" || "$target_cli" == "qlty" ]]; then
         print_info "Running Qlty analysis..."
         # Add organization parameter if provided
-        local qlty_args="$args"
-        if [[ -n "$QLTY_ORG" ]]; then
-            qlty_args="$args $QLTY_ORG"
+        local qlty_args=("${args[@]}")
+        if [[ -n "${QLTY_ORG:-}" ]]; then
+            qlty_args+=("$QLTY_ORG")
         fi
-        if execute_cli_command "qlty" "check" "$qlty_args"; then
+        if execute_cli_command "qlty" "check" "${qlty_args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "all" || "$target_cli" == "$CLI_SNYK" ]]; then
         print_info "Running Snyk security analysis..."
-        if execute_cli_command "$CLI_SNYK" "full" "$args"; then
+        if execute_cli_command "$CLI_SNYK" "full" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     # Add Snyk-specific scan options
     if [[ "$target_cli" == "snyk-sca" ]]; then
         print_info "Running Snyk SCA (dependency) scan..."
-        if execute_cli_command "$CLI_SNYK" "test" "$args"; then
+        if execute_cli_command "$CLI_SNYK" "test" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "snyk-code" ]]; then
         print_info "Running Snyk Code (SAST) scan..."
-        if execute_cli_command "$CLI_SNYK" "code" "$args"; then
+        if execute_cli_command "$CLI_SNYK" "code" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     if [[ "$target_cli" == "snyk-iac" ]]; then
         print_info "Running Snyk IaC scan..."
-        if execute_cli_command "$CLI_SNYK" "iac" "$args"; then
+        if execute_cli_command "$CLI_SNYK" "iac" "${args[@]}"; then
             ((++success_count))
         fi
         ((++total_count))
         echo ""
     fi

     print_info "Analysis Summary: $success_count/$total_count analyses completed successfully"

     if [[ $success_count -eq $total_count ]]; then
         print_success "All requested analyses completed successfully"
         return 0
     else
         print_warning "Some analyses failed"
         return 1
     fi
     return 0
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/quality-cli-manager.sh around lines 233 - 341,
analyze_with_clis is collapsing all flags into a single string (local args="$*")
which flattens multi-flag args; change it to capture args as an array (e.g.,
local -a args=("$@")) and pass them to execute_cli_command using array expansion
(execute_cli_command ... "${args[@]}"); likewise update the Qlty branch to build
qlty_args as an array (local -a qlty_args=("${args[@]}"); if [[ -n "$QLTY_ORG"
]]; then qlty_args+=("$QLTY_ORG"); fi) and call execute_cli_command "qlty"
"check" "${qlty_args[@]}"; apply the same pattern for all calls that currently
pass "$args" (e.g., CLI_CODERABBIT, codacy, sonar, CLI_SNYK,
snyk-sca/snyk-code/snyk-iac) so each flag remains a separate argument when
forwarded to execute_cli_command.
.agents/scripts/loop-common.sh (1)

509-551: ⚠️ Potential issue | 🟡 Minor

Receipt creation has potential JSON injection in evidence field.

Line 537 directly interpolates $evidence into the JSON structure:

  "evidence": $evidence

If callers pass non-JSON or malformed strings as evidence, the receipt file becomes invalid JSON. Current callers (e.g., line 997, 1040) appear to pass valid JSON objects, but this is fragile.

Consider validating or encoding the evidence:

Suggested fix
+	# Validate evidence is valid JSON, default to empty object
+	if ! echo "$evidence" | jq . >/dev/null 2>&1; then
+		evidence="{}"
+	fi
+
 	cat >"$receipt_file" <<EOF
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/loop-common.sh around lines 509 - 551, The evidence value in
loop_create_receipt is interpolated directly into the here-doc which allows JSON
injection or invalid JSON; instead build the receipt JSON safely with jq:
validate whether the passed $evidence is valid JSON (e.g., try to parse it with
jq -e) and if valid use --argjson to insert it, otherwise fallback to inserting
it as a JSON string via --arg; write the resulting object to "$receipt_file"
(and update .receipts in LOOP_STATE_FILE as you already do) so receipts are
always well-formed JSON and not vulnerable to injection.
🧹 Nitpick comments (4)
.agents/scripts/sonarcloud-collector-helper.sh (1)

481-484: Consider parameterized queries for user inputs (future hardening).

While not in scope for this PR, the cmd_query and cmd_summary functions directly interpolate user-provided arguments ($severity, $last_n) into SQL. The store_finding function already demonstrates the secure pattern with parameterized queries at line 370-372.

For a future security hardening pass, consider validating inputs or using parameterized queries consistently. For now, the attack surface is limited since these are CLI arguments rather than external API inputs.

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

In @.agents/scripts/sonarcloud-collector-helper.sh around lines 481 - 484, The
code in cmd_query and cmd_summary constructs SQL by interpolating CLI inputs
(variables severity and last_n) into where_clause and queries, which is
inconsistent with the parameterized pattern used in store_finding; update
cmd_query and cmd_summary to validate and/or use parameterized queries instead
of direct string interpolation (e.g., accept severity and last_n as parameters
to the DB client or sanitize/validate them before building where_clause), and
ensure the final query execution mirrors the secure parameter binding approach
used in store_finding to prevent injection risks.
.agents/scripts/setup-local-api-keys.sh (1)

202-210: Minor: Unreachable return 0 at line 209.

Both branches of the if-else (lines 203-204 and 206-207) already return, making line 209 unreachable. The SC2317 disable at file level acknowledges this, so no action required — just noting for awareness.

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

In @.agents/scripts/setup-local-api-keys.sh around lines 202 - 210, The trailing
unreachable "return 0" after the if/else in the function that checks "$key"
should be removed or the control flow simplified; since both branches already
return (the branch that echoes "$key" returns 0 and the else branch calls
print_warning and returns 1), delete the final "return 0" after the closing
brace to eliminate dead code and satisfy SC2317—look for the block referencing
"$key", "print_warning", and "env_var" and remove the redundant return.
.agents/scripts/worktree-helper.sh (1)

207-234: Consider documenting the intentional origin usage in stale remote functions.

The check_stale_remote_branch and _delete_stale_remote_ref functions (unchanged in this PR) intentionally use hardcoded origin, while the new branch_remote() helper supports arbitrary remotes. This distinction appears intentional—stale ref handling targets the canonical upstream, while cleanup checks respect each branch's tracking remote.

A brief comment clarifying this design choice would help future maintainers understand why these functions weren't updated alongside the GH#3797 changes.

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

In @.agents/scripts/worktree-helper.sh around lines 207 - 234, Add a brief
clarifying comment above the functions check_stale_remote_branch and
_delete_stale_remote_ref stating that they intentionally use the hardcoded
remote name "origin" (canonical upstream) even though branch_remote() supports
arbitrary remotes; describe that stale-ref detection targets the canonical
upstream while other cleanup logic uses the branch tracking remote, so
maintainers understand this design and why these functions were not changed with
the GH#3797 updates.
.agents/scripts/validate-mcp-integrations.sh (1)

27-39: Pre-increment changes look good.

All three counters (total_tests, passed_tests, failed_tests) correctly use pre-increment to avoid set -e termination when starting from 0.

Minor observation: Line 39's return 0 is unreachable since both if (line 33) and else (line 37) branches already return. Consider removing it for cleaner code.

🧹 Optional: Remove unreachable return
 	else
 		print_error "$test_name: FAILED"
 		((++failed_tests))
 		return 1
 	fi
-	return 0
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/validate-mcp-integrations.sh around lines 27 - 39, Remove
the unreachable final "return 0" at the end of the test block: the if branch
(bash -c "$test_command") already returns 0 on success and the else branch
returns 1 on failure, so delete the trailing "return 0" to clean up the
function/closure in .agents/scripts/validate-mcp-integrations.sh.
🤖 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/accessibility-audit-helper.sh:
- Around line 351-355: The curl invocation assigns response but doesn't detect
HTTP error responses or validate JSON, causing 4xx/5xx HTML pages to be treated
as successful audits; modify the block that sets response to capture HTTP status
and body separately (e.g., use curl -s -w '%{http_code}' to append the status),
split the status into a variable (http_status) and the body into response, then:
if http_status is not a 2xx value log an error to LOG_FILE/process logger and
exit nonzero; otherwise validate that response is valid JSON (use jq -e .
>/dev/null) before continuing, and if jq fails log the response and exit
nonzero—apply these checks around the existing WEBAIMCC_API_URL/response
handling so subsequent jq operations aren’t run on HTML error pages.

In @.agents/scripts/deploy-agents-on-merge.sh:
- Around line 238-274: The current sync logic overlays files into $TARGET_DIR
(in the rsync branch and the tar branch using (cd "$source_dir" && tar ...) |
(cd "$TARGET_DIR" && tar xf -)), which leaves deleted/renamed files behind; fix
by making the operation destructive except for preserved dirs: in the rsync path
add the --delete (and --delete-excluded if desired) while keeping the existing
--exclude='custom/' '--exclude='draft/' '--exclude='loop-state/' flags; in the
fallback (tar) path, before extracting either remove all files in $TARGET_DIR
except the preserved directories (custom, draft, loop-state) or extract into a
temporary directory and atomically replace $TARGET_DIR while restoring preserved
dirs from $tmp_preserve; ensure errors update preserve_ok and the script returns
non-zero on failure (symbols to edit: rsync invocation, the tar pipeline using
source_dir and TARGET_DIR, tmp_preserve/preserve_ok restore loop).
- Around line 142-145: The script hardcodes "origin" for pulls which can
silently fail and mask errors; replace the hardcoded remote by using the
existing remote-detection logic (branch_remote() from worktree-helper.sh or
querying git config "branch.$branch.remote" / @{upstream}) to compute the remote
for the current branch before calling git -C "$REPO_DIR" pull; update both the
fast-forward and fallback pull invocations to use that detected remote, remove
silencing that hides failures (avoid redirecting stderr to /dev/null and avoid
swallowing errors with || true) and surface or log failures with
log_warn/log_error (refer to functions/variables REPO_DIR, branch_remote(), and
log_warn) so the script fails or reports if pulls cannot update.

In @.agents/scripts/enhancor-helper.sh:
- Around line 65-79: api_request currently lets curl or a non-2xx HTTP status
cause the function to return non-zero which, under set -euo pipefail, aborts any
caller using response=$(api_request ...) before the response is captured; change
api_request so it never returns a non-zero exit code for normal HTTP errors: run
curl with "|| true" to avoid propagation of transport errors, capture its exit
status and the HTTP code into local variables (response and http_code), and when
http_code>=400 or curl failed emit a structured error payload (e.g. JSON with
fields like "error", "http_code", and the original body) to stdout and still
return 0 so callers (which assign response=$(api_request ...)) can inspect the
payload; keep print_error logs for stderr but do not return non-zero from
api_request on HTTP/transport failures. Ensure you update the logic around the
existing locals http_code and response and the curl invocation in api_request to
implement this behavior.

In @.agents/scripts/loop-common.sh:
- Around line 898-902: The JSON evidence passed to loop_create_receipt is built
by directly interpolating $reason which can break JSON if it contains quotes or
backslashes; update the code where loop_create_receipt is called (the block
invoking loop_create_receipt "task" "context_guard") to construct the JSON
payload safely (e.g. using jq -n --arg reason "$reason" --argjson iteration
"$iteration" --argjson max_iterations "$max_iterations"
'{reason:$reason,iteration:$iteration,max_iterations:$max_iterations}' or
another safe JSON builder) and pass that safe JSON string to loop_create_receipt
so reason is properly escaped.

In @.agents/scripts/markdown-formatter.sh:
- Around line 101-108: The script's process_directory() (and the
before_hash/after_hash assignments around fix_markdown_file) rely on the
non-portable sha256sum; add a small portable wrapper function (e.g.,
compute_sha256) that checks for sha256sum and falls back to shasum -a 256, then
use that wrapper where before_hash and after_hash are set so the same hash
string is produced (pipe to awk '{print $1}')—update the two assignments that
call sha256sum to call compute_sha256 "$file" instead.

In @.agents/scripts/quality-cli-manager.sh:
- Around line 127-133: The execute_cli_command dispatcher is missing a "qlty"
case causing calls like execute_cli_command "qlty" "install|init|analyze" to hit
the "Unknown CLI" branch; add a qlty case in the function (handle subcommands
install, init, analyze consistent with other CLIs) and route to the appropriate
qlty install/init/analyze logic (same pattern as existing cli cases). Also make
the QLTY_ORG dereference safe under set -u by replacing bare $QLTY_ORG with
${QLTY_ORG:-} where it’s referenced (line around the analyze call) so missing
env var won’t cause an unbound variable error.

In @.agents/scripts/quickfile-helper.sh:
- Around line 452-457: The summary always returns 0 even when some items failed;
change the end of the script (the block that calls print_success and print_info)
so that after printing the summary it returns non-zero if there were any
failures and this is not a dry run: use the existing variables count and failed
and the dry_run flag to decide the exit code (e.g., if [[ "$dry_run" != "true"
&& "$failed" -gt 0 ]]; then return 1; else return 0; fi), leaving
print_success/print_info calls unchanged so logs still show the summary.

In @.agents/scripts/secret-helper.sh:
- Around line 493-494: The current pipeline uses echo "$val" to feed the secret
into gopass (seen where val is piped into gopass insert --force "$gopass_path"),
which misinterprets option-like payloads (e.g., "-n"); replace the echo usage
with a safe printer such as printf '%s\n' "$val" so the literal secret is
preserved, keeping the rest of the logic (the call to gopass insert --force
"$gopass_path" and the ((++imported)) increment) unchanged.

In @.agents/scripts/tool-version-check.sh:
- Around line 234-239: The summary is incorrectly counting "unknown" and
"timeout" as installed/up-to-date by incrementing INSTALLED_COUNT in the
branches handling installed=="unknown" or latest=="unknown"/timeout; update the
logic in the branch that sets status="unknown" (and any timeout handling) to
stop incrementing INSTALLED_COUNT and instead increment a new counter (e.g.,
UNKNOWN_COUNT or TIMEOUT_COUNT) or remove the increment entirely, and update any
summary label generation to use the new counter or relabel the "Installed & up
to date" bucket to just "Installed" so INSTALLED_COUNT only reflects truly
verified installations; locate the branches referencing INSTALLED_COUNT, status,
icon, color and adjust the increments and summary use accordingly.

In @.agents/scripts/worktree-helper.sh:
- Around line 186-191: The current remote-check using git show-ref --quiet
"refs/remotes/*/$branch" does not match remote-tracking refs; replace that check
with a command that actually enumerates remote refs for the given branch (for
example use git for-each-ref or git branch -r --list "*/$branch") and test its
exit status instead of the broken git show-ref invocation; update the check that
references the branch variable (the existing git show-ref --quiet
"refs/remotes/*/$branch" usage) so it uses git for-each-ref --quiet
--format='%(refname)' "refs/remotes/*/$branch" or git branch -r --list
"*/$branch" to correctly detect pushed branches on non-origin remotes.

---

Outside diff comments:
In @.agents/scripts/langflow-helper.sh:
- Around line 64-69: The loop and subsequent free-port check currently use "<
65535" which excludes port 65535; update the port-search logic in
get_available_port so both the while loop condition and the post-loop
availability check allow port 65535 (use "<= 65535" or equivalent bounds logic),
and apply the identical fix inside the start-langflow.sh heredoc where the same
check is duplicated (the block around lines referenced in the review); ensure
the final chosen port is actually verified free with lsof before announcing it.

In @.agents/scripts/loop-common.sh:
- Around line 509-551: The evidence value in loop_create_receipt is interpolated
directly into the here-doc which allows JSON injection or invalid JSON; instead
build the receipt JSON safely with jq: validate whether the passed $evidence is
valid JSON (e.g., try to parse it with jq -e) and if valid use --argjson to
insert it, otherwise fallback to inserting it as a JSON string via --arg; write
the resulting object to "$receipt_file" (and update .receipts in LOOP_STATE_FILE
as you already do) so receipts are always well-formed JSON and not vulnerable to
injection.

In @.agents/scripts/quality-cli-manager.sh:
- Around line 233-341: analyze_with_clis is collapsing all flags into a single
string (local args="$*") which flattens multi-flag args; change it to capture
args as an array (e.g., local -a args=("$@")) and pass them to
execute_cli_command using array expansion (execute_cli_command ...
"${args[@]}"); likewise update the Qlty branch to build qlty_args as an array
(local -a qlty_args=("${args[@]}"); if [[ -n "$QLTY_ORG" ]]; then
qlty_args+=("$QLTY_ORG"); fi) and call execute_cli_command "qlty" "check"
"${qlty_args[@]}"; apply the same pattern for all calls that currently pass
"$args" (e.g., CLI_CODERABBIT, codacy, sonar, CLI_SNYK,
snyk-sca/snyk-code/snyk-iac) so each flag remains a separate argument when
forwarded to execute_cli_command.

In @.agents/scripts/quickfile-helper.sh:
- Around line 106-247: Supplier and purchase instruction outputs are vulnerable
because unescaped OCR data is directly interpolated into JSON in
generate_supplier_instructions() and generate_purchase_instructions(), and batch
failures are masked by cmd_batch_record() always returning 0; fix by switching
to proper JSON serialization for the entire payload instead of manual
field-by-field printing (use json.dumps on the Python side to emit the full dict
and update the bash supplier helper to JSON-escape supplier_name when printing
instructions), ensure supplier_id/inv_ref/line descriptions are produced via
JSON serialization rather than raw f-strings/echo, and change cmd_batch_record()
to return a non-zero exit status when any failures were counted so callers can
detect partial failures.

In @.agents/scripts/setup-local-api-keys.sh:
- Around line 291-292: The tenant subcommand fails due to a variable case
mismatch: the script sets script_dir (lowercase) but references SCRIPT_DIR
(uppercase) causing an unbound variable under set -u; fix by using a consistent
identifier everywhere (either set SCRIPT_DIR instead of script_dir or reference
script_dir where SCRIPT_DIR is used), e.g., ensure the assignment and the source
line both use the same symbol (script_dir or SCRIPT_DIR) so the call to source
"${SCRIPT_DIR}/shared-constants.sh" resolves correctly when running the tenant
subcommand.
- Around line 264-266: The script's main function accesses $1 directly which
breaks under set -u when no args are passed; change the assignment in main to
safely default when empty (e.g., replace local command="$1" with local
command="${1:-}" or "${1-}") so the script won't error under set -u and the
subsequent shift and your help/case routing still run; update any related shift
usage if you choose to test $# first (e.g., use if [ "$#" -eq 0 ]; then
command=""; fi) to ensure the help handler in main is reachable.

In @.agents/scripts/site-crawler-helper.sh:
- Around line 700-710: The counters for HTTP statuses use post-increment which
can return a non-zero exit status under set -e; update all increments inside the
for loop so they use pre-increment for consistency: replace uses of
((code_200++)), ((code_301++)), ((code_302++)), ((code_404++)), and
((code_500++)) with pre-increment form (e.g., ((++code_200))) while leaving the
code_other pre-increment as-is; ensure this change is applied within the for
loop that iterates over the status_codes array.

---

Nitpick comments:
In @.agents/scripts/setup-local-api-keys.sh:
- Around line 202-210: The trailing unreachable "return 0" after the if/else in
the function that checks "$key" should be removed or the control flow
simplified; since both branches already return (the branch that echoes "$key"
returns 0 and the else branch calls print_warning and returns 1), delete the
final "return 0" after the closing brace to eliminate dead code and satisfy
SC2317—look for the block referencing "$key", "print_warning", and "env_var" and
remove the redundant return.

In @.agents/scripts/sonarcloud-collector-helper.sh:
- Around line 481-484: The code in cmd_query and cmd_summary constructs SQL by
interpolating CLI inputs (variables severity and last_n) into where_clause and
queries, which is inconsistent with the parameterized pattern used in
store_finding; update cmd_query and cmd_summary to validate and/or use
parameterized queries instead of direct string interpolation (e.g., accept
severity and last_n as parameters to the DB client or sanitize/validate them
before building where_clause), and ensure the final query execution mirrors the
secure parameter binding approach used in store_finding to prevent injection
risks.

In @.agents/scripts/validate-mcp-integrations.sh:
- Around line 27-39: Remove the unreachable final "return 0" at the end of the
test block: the if branch (bash -c "$test_command") already returns 0 on success
and the else branch returns 1 on failure, so delete the trailing "return 0" to
clean up the function/closure in .agents/scripts/validate-mcp-integrations.sh.

In @.agents/scripts/worktree-helper.sh:
- Around line 207-234: Add a brief clarifying comment above the functions
check_stale_remote_branch and _delete_stale_remote_ref stating that they
intentionally use the hardcoded remote name "origin" (canonical upstream) even
though branch_remote() supports arbitrary remotes; describe that stale-ref
detection targets the canonical upstream while other cleanup logic uses the
branch tracking remote, so maintainers understand this design and why these
functions were not changed with the GH#3797 updates.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: cd58c49f-cbfc-46ec-a96c-46a28e0204c9

📥 Commits

Reviewing files that changed from the base of the PR and between 562d71b and c6f0c35.

📒 Files selected for processing (55)
  • .agents/scripts/accessibility-audit-helper.sh
  • .agents/scripts/accessibility-helper.sh
  • .agents/scripts/agent-sources-helper.sh
  • .agents/scripts/ampcode-cli.sh
  • .agents/scripts/anti-detect-helper.sh
  • .agents/scripts/autogen-helper.sh
  • .agents/scripts/beads-sync-helper.sh
  • .agents/scripts/codacy-cli-chunked.sh
  • .agents/scripts/crawl4ai-examples.sh
  • .agents/scripts/credential-helper.sh
  • .agents/scripts/crewai-helper.sh
  • .agents/scripts/deploy-agents-on-merge.sh
  • .agents/scripts/dev-browser-helper.sh
  • .agents/scripts/email-health-check-helper.sh
  • .agents/scripts/enhancor-helper.sh
  • .agents/scripts/generate-skills.sh
  • .agents/scripts/langflow-helper.sh
  • .agents/scripts/linter-manager.sh
  • .agents/scripts/linters-local.sh
  • .agents/scripts/list-keys-helper.sh
  • .agents/scripts/list-todo-helper.sh
  • .agents/scripts/list-verify-helper.sh
  • .agents/scripts/localhost-helper.sh
  • .agents/scripts/loop-common.sh
  • .agents/scripts/markdown-formatter.sh
  • .agents/scripts/matrix-dispatch-helper.sh
  • .agents/scripts/mcp-register-claude.sh
  • .agents/scripts/migrate-pr-backfill.sh
  • .agents/scripts/network-tier-helper.sh
  • .agents/scripts/postflight-check.sh
  • .agents/scripts/pre-commit-hook.sh
  • .agents/scripts/quality-cli-manager.sh
  • .agents/scripts/quality-feedback-helper.sh
  • .agents/scripts/quality-fix.sh
  • .agents/scripts/quickfile-helper.sh
  • .agents/scripts/rosetta-audit-helper.sh
  • .agents/scripts/runway-helper.sh
  • .agents/scripts/secret-helper.sh
  • .agents/scripts/security-posture-helper.sh
  • .agents/scripts/setup-linters-wizard.sh
  • .agents/scripts/setup-local-api-keys.sh
  • .agents/scripts/shared-constants.sh
  • .agents/scripts/show-plan-helper.sh
  • .agents/scripts/site-crawler-helper.sh
  • .agents/scripts/skill-update-helper.sh
  • .agents/scripts/skills-helper.sh
  • .agents/scripts/sonarcloud-collector-helper.sh
  • .agents/scripts/thumbnail-helper.sh
  • .agents/scripts/todo-ready.sh
  • .agents/scripts/tool-version-check.sh
  • .agents/scripts/toon-helper.sh
  • .agents/scripts/validate-mcp-integrations.sh
  • .agents/scripts/verify-mirrors.sh
  • .agents/scripts/worker-token-helper.sh
  • .agents/scripts/worktree-helper.sh
✅ Files skipped from review due to trivial changes (11)
  • .agents/scripts/mcp-register-claude.sh
  • .agents/scripts/thumbnail-helper.sh
  • .agents/scripts/security-posture-helper.sh
  • .agents/scripts/list-todo-helper.sh
  • .agents/scripts/dev-browser-helper.sh
  • .agents/scripts/todo-ready.sh
  • .agents/scripts/credential-helper.sh
  • .agents/scripts/crewai-helper.sh
  • .agents/scripts/show-plan-helper.sh
  • .agents/scripts/setup-linters-wizard.sh
  • .agents/scripts/ampcode-cli.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • .agents/scripts/email-health-check-helper.sh

Comment thread .agents/scripts/accessibility-audit-helper.sh Outdated
Comment thread .agents/scripts/deploy-agents-on-merge.sh Outdated
Comment thread .agents/scripts/deploy-agents-on-merge.sh
Comment thread .agents/scripts/enhancor-helper.sh
Comment thread .agents/scripts/loop-common.sh
Comment thread .agents/scripts/quality-cli-manager.sh Outdated
Comment thread .agents/scripts/quickfile-helper.sh
Comment thread .agents/scripts/secret-helper.sh Outdated
Comment thread .agents/scripts/tool-version-check.sh Outdated
Comment thread .agents/scripts/worktree-helper.sh
@johnwaldo
Copy link
Copy Markdown
Contributor Author

Triage: Worker appears stuck

This PR was created by a worker that completed its initial push but never returned to address:

  • CI failures: 🤖 Monitor & Auto-Fix Code Quality, SonarCloud Analysis, Label PR from Conventional Commit
  • CodeRabbit inline comments: 24 (including security/correctness issues)
  • CHANGES_REQUESTED review pending

The SonarCloud failure is likely the missing SONAR_TOKEN issue (see #3839 for the fix). The Quality Monitor and Label failures need investigation.

Recommendation: A new worker should be dispatched to address the CodeRabbit feedback on this PR, or close and re-create if the branch has diverged too far from main.

- graduated-learnings.md: replace broken shell-escaped quotes with backtick code formatting
- video.md: add reference-only disclaimer, harden bash example with set -euo pipefail and error handling
- accessibility-audit-helper.sh: use LONG_TIMEOUT for max-time (connect uses DEFAULT_TIMEOUT)
- add-skill-helper.sh: replace echo-pipe-grep with herestring grep, sort nested skill by path length
- audit-task-creator-helper.sh: fix quoting and error handling
- deploy-agents-on-merge.sh: safer fallback cleanup, separate mkdir/cp error messages, track chmod failures
- email-health-check-helper.sh: minor fix
- supervisor-archived/: batch.sh, database.sh, issue-sync.sh, routine-scheduler.sh, supervisor-helper.sh, todo-sync.sh — various quality fixes
- context-guardrails.md: minor doc fix
@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 1h42m with 0 commits (struggle_ratio: 22071 — thrashing). Re-dispatching with simpler scope.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker (PID 42511) killed after 6h10m with 0 commits (struggle_ratio: 22330). Re-dispatching with a fresh worker to fix the variable case mismatch and other actionable comments.

- runway-helper.sh: stricter --ref tag validation (alphanumeric pattern)
- accessibility-audit-helper.sh: HTTP status check on WebAIM API response
- enhancor-helper.sh: handle curl failure, fix stderr routing
- loop-common.sh: use jq for safe JSON construction in context guard
- markdown-formatter.sh: portable hash function (shasum on macOS)
- quality-cli-manager.sh: add qlty case to dispatcher, safe QLTY_ORG deref
- quickfile-helper.sh: return non-zero on partial batch failure
- secret-helper.sh: printf instead of echo for safe value piping
- tool-version-check.sh: separate UNKNOWN_COUNT from INSTALLED_COUNT
- worktree-helper.sh: for-each-ref instead of show-ref for glob patterns
- deploy-agents-on-merge.sh: detect remote, clean stale files in tar fallback
@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 5h17m with 0 commits (struggle_ratio: 22414). The task scope may be too broad or the worker is stuck in a loop. Re-dispatching with narrower scope focused only on the variable case mismatch fix in setup-local-api-keys.sh.

Line 292 referenced SCRIPT_DIR (uppercase) but line 291 assigns to
script_dir (lowercase). Under set -u this causes an unbound variable
error at runtime when the 'tenant' command is invoked.
@marcusquinn
Copy link
Copy Markdown
Owner

Worker PID 24773 killed by supervisor pulse — thrashing detected (struggle_ratio: 22601, 7+ hours, 0 commits). PR #3833 is being re-queued for dispatch with a fresh worker. The CHANGES_REQUESTED review feedback will be addressed in the new session.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after thrashing (4h56m, 22722 messages, 0 commits). This PR has CHANGES_REQUESTED — the worker repeatedly failed to make progress. Re-dispatching with a fresh worker focused on the specific review feedback.

Validates that the WebAIM API response is valid JSON before passing
to jq, preventing HTML error pages from being silently treated as
successful audit results.

Addresses CodeRabbit review feedback on PR marcusquinn#3833.
Under set -euo pipefail, bare response=$(api_request ...) aborts the
script immediately when api_request returns non-zero, preventing any
error recovery by the caller. Wrap all 7 call sites with
if ! response=$(api_request ...); then return 1; fi pattern.

Addresses CodeRabbit review feedback on PR marcusquinn#3833.
@marcusquinn
Copy link
Copy Markdown
Owner

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@marcusquinn marcusquinn dismissed stale reviews from coderabbitai[bot] and coderabbitai[bot] March 8, 2026 06:14

All review feedback addressed in subsequent commits. Unresolved threads were false positives - analysis was based on intermediate state, final code contains all fixes.

@marcusquinn
Copy link
Copy Markdown
Owner

CI Failure Analysis

All 3 CI failures are infrastructure/permissions issues caused by this being a fork PR (from johnwaldo), not code problems:

  1. Label PR from Conventional CommitResource not accessible by integration: GitHub Actions token on fork PRs lacks pull_requests: write permission to add labels.
  2. SonarCloud AnalysisProject not found: SONAR_TOKEN secret is not available to fork PRs (GitHub security restriction).
  3. Auto-Fix Code QualityResource not accessible by integration: Same token permission issue — can't post PR comments from fork context.

These will pass when run from the main repo context (e.g., after merge or when re-triggered with appropriate permissions).

Review Feedback

All 16 CodeRabbit review comments have been addressed in commits c6f0c35 through d753e890:

  • Audio validation, $2 guards, curl -sS, error body to stderr (runway-helper.sh)
  • api_request error handling with if ! guards (enhancor-helper.sh)
  • Batch failure return code (quickfile-helper.sh)
  • All other accessibility, deploy, email-health-check fixes

The 3 "unresolved" threads were false positives — CodeRabbit's analysis was based on intermediate commit state, but the final code already contains all fixes. Threads resolved and reviews dismissed.

Copy link
Copy Markdown
Owner

@marcusquinn marcusquinn left a comment

Choose a reason for hiding this comment

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

All review feedback addressed. CI failures are fork PR permission issues (not code). Code verified: ShellCheck clean, all review items fixed in subsequent commits.

coderabbitai[bot]
coderabbitai Bot previously requested changes Mar 8, 2026
Copy link
Copy Markdown
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

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
.agents/scripts/add-skill-helper.sh (2)

260-305: ⚠️ Potential issue | 🟠 Major

Use the passed description when categorizing non-file imports.

These checks still only search content loaded from source_dir, but cmd_add_clawdhub calls determine_target_path "$skill_name" "$summary" ".". That means ClawdHub imports are categorized from this repo’s local docs instead of the fetched skill metadata, so skills can land in the wrong .agents/... path.

💡 Suggested fix
 determine_target_path() {
 	local skill_name="$1"
-	local _description="$2" # Reserved for future category detection
+	local description="${2:-}"
 	local source_dir="$3"
 
 	# Analyze content to determine category
 	local category="tools"
 
-	# Check description and content for category hints
-	local content=""
+	# Check description and content for category hints
+	local content="$description"
 	if [[ -f "$source_dir/SKILL.md" ]]; then
-		content=$(cat "$source_dir/SKILL.md")
+		content+=$'\n'
+		content+=$(cat "$source_dir/SKILL.md")
 	elif [[ -f "$source_dir/AGENTS.md" ]]; then
-		content=$(cat "$source_dir/AGENTS.md")
+		content+=$'\n'
+		content+=$(cat "$source_dir/AGENTS.md")
 	fi

As per coding guidelines, automation scripts should focus on reliability and robustness.

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

In @.agents/scripts/add-skill-helper.sh around lines 260 - 305, The
categorization currently only inspects files read into the local variable
content from source_dir (SKILL.md/AGENTS.md), causing cmd_add_clawdhub imports
(which call determine_target_path "$skill_name" "$summary" ".") to be
mis-categorized; update the logic in determine_target_path (or the block that
sets content) to fall back to or include the passed summary variable when
content is empty or when summary is provided (e.g., set
content="${content:-$summary}" or append summary to content) and then run the
existing grep checks against that combined string so skills imported via
cmd_add_clawdhub are categorized using the fetched skill metadata as well as
local docs (reference symbols: determine_target_path, cmd_add_clawdhub,
skill_name, summary, content, source_dir).

1517-1541: ⚠️ Potential issue | 🟠 Major

Don’t delete the skill before the registry update is known-good.

The new jq guard is useful, but cmd_remove still removes the payload first and only then rewrites skill-sources.json. If the JSON/write step fails, the command returns 1 after the files are already gone, leaving a stale registry entry behind.

🔧 Suggested fix
-	# Remove files
-	if [[ -f "$skill_path" ]]; then
-		rm -f "$skill_path"
-		log_success "Removed: $skill_path"
-	fi
-
-	# Remove directory if exists
-	local dir_path="${skill_path%.md}"
-	if [[ -d "$dir_path" ]]; then
-		rm -rf "$dir_path"
-		log_success "Removed: $dir_path/"
-	fi
-
-	# Remove from registry
+	# Prepare registry update before destructive file removal
 	local tmp_file
 	tmp_file=$(mktemp)
 	_save_cleanup_scope
 	trap '_run_cleanups' RETURN
 	push_cleanup "rm -f '${tmp_file}'"
 	if ! jq --arg name "$name" '.skills = [.skills[] | select(.name != $name)]' "$SKILL_SOURCES" >"$tmp_file"; then
 		log_error "Failed to process skill sources JSON. Removal aborted."
 		rm -f "$tmp_file"
 		return 1
 	fi
+
+	# Remove files
+	if [[ -f "$skill_path" ]]; then
+		rm -f "$skill_path"
+		log_success "Removed: $skill_path"
+	fi
+
+	# Remove directory if exists
+	local dir_path="${skill_path%.md}"
+	if [[ -d "$dir_path" ]]; then
+		rm -rf "$dir_path"
+		log_success "Removed: $dir_path/"
+	fi
+
 	mv "$tmp_file" "$SKILL_SOURCES"

As per coding guidelines, automation scripts should focus on reliability and robustness, proper exit codes, and error recovery mechanisms.

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

In @.agents/scripts/add-skill-helper.sh around lines 1517 - 1541, The removal
currently deletes the skill files (skill_path and dir_path) before updating
SKILL_SOURCES, risking orphaned registry entries if the jq/write step fails;
instead, run the jq update first writing to tmp_file and mv it to SKILL_SOURCES
only on success, and only after that remove skill_path and dir_path; use the
existing tmp_file, _save_cleanup_scope, trap and push_cleanup to ensure tmp_file
is removed on error, and ensure file deletions occur after mv "$tmp_file"
"$SKILL_SOURCES" succeeds (and return non-zero without deleting files if the jq
or mv step fails).
.agents/scripts/loop-common.sh (1)

137-153: ⚠️ Potential issue | 🟠 Major

Build the initial state file with jq -n, not heredoc interpolation.

Lines 139–147 splice loop_type, task_id, started_at, and completion_promise directly into JSON via heredoc. Any quote or newline in a caller-provided value (e.g., loop_create_state "ralph" "…" 50 'TASK"FAIL') corrupts loop-state.json. Under set -euo pipefail, every subsequent jq read/write cascades to failure, breaking the loop entirely—a reliability failure contrary to coding guidelines.

The fix uses jq -n with --arg flags for proper escaping, matching the safe patterns already established elsewhere in the file (lines 535, 670, 714, 906) and consistent with the GH#3798 injection-prevention comment at line 197.

🔧 Safer state-file construction
-	cat >"$LOOP_STATE_FILE" <<EOF
-{
-  "loop_type": "$loop_type",
-  "prompt": $(echo "$prompt" | jq -Rs .),
-  "iteration": 1,
-  "max_iterations": $max_iterations,
-  "phase": "task",
-  "task_id": "$task_id",
-  "started_at": "$started_at",
-  "last_iteration_at": "$started_at",
-  "completion_promise": "$completion_promise",
-  "attempts": {},
-  "receipts": [],
-  "blocked_tasks": [],
-  "active": true
-}
-EOF
+	jq -n \
+		--arg loop_type "$loop_type" \
+		--arg prompt "$prompt" \
+		--argjson max_iterations "$max_iterations" \
+		--arg task_id "$task_id" \
+		--arg started_at "$started_at" \
+		--arg completion_promise "$completion_promise" \
+		'{
+			loop_type: $loop_type,
+			prompt: $prompt,
+			iteration: 1,
+			max_iterations: $max_iterations,
+			phase: "task",
+			task_id: $task_id,
+			started_at: $started_at,
+			last_iteration_at: $started_at,
+			completion_promise: $completion_promise,
+			attempts: {},
+			receipts: [],
+			blocked_tasks: [],
+			active: true
+		}' >"$LOOP_STATE_FILE"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/loop-common.sh around lines 137 - 153, Replace the
heredoc-based JSON write to LOOP_STATE_FILE with a safe jq -n construction: call
jq -n and pass loop_type, prompt, max_iterations, task_id, started_at,
completion_promise with --arg (use --argjson for numeric/bool values like
max_iterations and active), and construct the object with jq to produce properly
escaped JSON for keys
"loop_type","prompt","iteration","max_iterations","phase","task_id","started_at","last_iteration_at","completion_promise","attempts","receipts","blocked_tasks","active";
ensure "iteration" is set to 1, "attempts" is {}, and "receipts"/"blocked_tasks"
are [] so no heredoc interpolation of user values occurs (use LOOP_STATE_FILE as
the output target).
.agents/scripts/supervisor-archived/issue-sync.sh (1)

2912-2938: ⚠️ Potential issue | 🟡 Minor

Escape dotted task IDs in the TODO.md grep lookup.

Line 2932 interpolates raw $task_id into an extended regex, but dots are metacharacters. A task_id like t128.10 would match t128 followed by any character followed by 10, finding the wrong TODO entry. Other task lookups in this file (lines 1401, 1466, 1553, 1685) already use the proper task_id_escaped pattern. The return 1 on line 2916 for invalid format is safe—the caller at line 500 doesn't check its return value, and this script does not use set -e.

Suggested fix
	# Validate task_id to prevent command injection
	local safe_task_id_pattern='^[a-zA-Z0-9._-]+$'
	if [[ ! "$task_id" =~ $safe_task_id_pattern ]]; then
		log_warn "Invalid task_id format detected, skipping GitHub comment: $task_id"
		return 1
	fi

+	# Escape dots in task_id for regex (e.g. t128.10 -> t128\.10)
+	local task_id_escaped
+	task_id_escaped=$(printf '%s' "$task_id" | sed 's/\./\\./g')
+
	# Extract GitHub issue number from TODO.md
	local todo_file="$repo_path/TODO.md"
	if [[ ! -f "$todo_file" ]]; then
		return 0
	fi

	local task_line
-	task_line=$(grep -E -- "^[[:space:]]*- \[.\] ${task_id} " "$todo_file" | head -1 || echo "")
+	task_line=$(grep -E -- "^[[:space:]]*- \[.\] ${task_id_escaped} " "$todo_file" | head -1 || echo "")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor-archived/issue-sync.sh around lines 2912 - 2938,
The grep that builds task_line interpolates raw $task_id into an extended regex
causing dots to act as wildcards; escape regex metacharacters in task_id (create
task_id_escaped) and use that escaped variable in the task_line lookup (replace
the grep that sets task_line to use ${task_id_escaped} instead of ${task_id});
ensure the escaped value is quoted in the grep invocation and reuse the same
escaping approach already used elsewhere in this script (see other occurrences
that define task_id_escaped).
.agents/scripts/accessibility-audit-helper.sh (1)

227-257: ⚠️ Potential issue | 🟠 Major

Add JSON validity check before writing WAVE API response to file.

The HTTP 200 validation is appropriate, but a 200 response with non-JSON content (e.g., HTML error page, corrupted data) gets written to wave_*.json anyway. Downstream parse_wave_report() calls jq with error suppression (2>/dev/null), masking JSON parsing failures and breaking error recovery.

Validate JSON structure before persisting
 if [[ "$http_code" != "200" ]]; then
 	print_error "WAVE API returned HTTP $http_code"
 	return 1
 fi
+
+if ! printf '%s' "$body" | jq empty >/dev/null 2>&1; then
+	print_error "WAVE API returned non-JSON data"
+	printf '%s\n' "$body" >>"$LOG_FILE"
+	return 1
+fi
 
 echo "$body" >"$report_file"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/accessibility-audit-helper.sh around lines 227 - 257, The
script currently writes the WAVE API response body to "$report_file" after
checking HTTP 200 but before verifying it's valid JSON, causing
parse_wave_report to fail silently; update the block after computing body (from
response) to validate JSON (e.g., use jq -e '.' on the "$body" or pipe it to jq
with error checking) and if validation fails call print_error with the jq error
/ a descriptive message and return 1 instead of writing the file; only echo
"$body" >"$report_file" and call parse_wave_report "$report_file" when the jq
validation succeeds so parse_wave_report always receives valid JSON.
♻️ Duplicate comments (2)
.agents/scripts/deploy-agents-on-merge.sh (2)

366-370: ⚠️ Potential issue | 🟠 Major

Deleted-file cleanup is still unguarded under set -e.

Add/update failures are counted now, but a failing rm -f here still exits the function immediately, skips failed+=1, and makes the summary inaccurate on partial-cleanup errors.

🛠️ Guard the delete path too
 		elif [[ ! -e "$source_file" ]]; then
 			# File was deleted in source — remove from target
 			if [[ -f "$target_file" ]]; then
-				rm -f "$target_file"
+				if ! rm -f "$target_file"; then
+					failed=$((failed + 1))
+					log_warn "rm failed: $rel_path"
+					continue
+				fi
 				log_info "Removed deleted file: $rel_path"
 			fi
 		fi
As per coding guidelines, automation scripts should focus on "Reliability and robustness", "Clear logging and feedback", and "Error recovery mechanisms".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/deploy-agents-on-merge.sh around lines 366 - 370, The delete
branch under set -e can abort the script on rm failure and skip incrementing
failed; wrap or guard the remove so failures are handled like other add/update
errors: instead of letting rm -f cause an immediate exit, check the return
status of the rm operation (related to variables target_file and rel_path and
the rm -f invocation), log an error via log_error or similar, and increment the
failed counter (failed+=1) when rm fails, otherwise log the successful removal
with log_info; ensure the code path mirrors existing add/update error-handling
so summary counts remain accurate.

242-247: ⚠️ Potential issue | 🟠 Major

Full sync still leaves deleted files behind on the primary rsync path.

The tar fallback now cleans stale files first, but the branch most hosts will use still overlays because rsync is missing --delete. Removed or renamed agent files will linger in $TARGET_DIR.

🛠️ Minimal fix
-		rsync -a \
+		rsync -a --delete \
 			--exclude='loop-state/' \
 			--exclude='custom/' \
 			--exclude='draft/' \
 			"$source_dir/" "$TARGET_DIR/"
As per coding guidelines, automation scripts should focus on "Reliability and robustness" and "Error recovery mechanisms".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/deploy-agents-on-merge.sh around lines 242 - 247, The rsync
invocation in deploy-agents-on-merge.sh (the block that checks command -v rsync
and contains the --exclude='loop-state/' --exclude='custom/' --exclude='draft/'
lines) currently overlays files and leaves deletions behind; update that rsync
command to include the --delete flag so files removed or renamed in the source
are removed from $TARGET_DIR (optionally consider --delete-excluded if you want
excluded paths removed as well), preserving the existing excludes and other
options.
🟠 Major comments (16)
.agents/scripts/archived/audit-task-creator-helper.sh-558-566 (1)

558-566: ⚠️ Potential issue | 🟠 Major

Persist pr_number on every unified insert path.

This captures .pr_number, but only the false-positive branch stores it. The below-threshold and normal inserts still write 0, so most unified findings lose their from-pr:#... linkage during task creation.

♻️ Suggested fix
@@
 			db "$active_db" "
 				INSERT OR IGNORE INTO processed_findings
 					(source, source_id, source_tool, pr_number, path, line, severity,
 					 original_severity, category, description, is_false_positive)
 				VALUES ('unified', '$(sql_escape "$finding_id")', '$(sql_escape "$source")',
-					0, '$(sql_escape "$path")', ${line:-0},
+					${pr_number:-0}, '$(sql_escape "$path")', ${line:-0},
 					'$new_severity', '$severity', '$(sql_escape "$category")',
 					'$escaped_desc', 0);
 			" 2>/dev/null || true
@@
 		db "$active_db" "
 			INSERT OR IGNORE INTO processed_findings
 				(source, source_id, source_tool, pr_number, path, line, severity,
 				 original_severity, category, description,
 				 is_false_positive, is_duplicate, duplicate_of)
 			VALUES ('unified', '$(sql_escape "$finding_id")', '$(sql_escape "$source")',
-				0, '$(sql_escape "$path")', ${line:-0},
+				${pr_number:-0}, '$(sql_escape "$path")', ${line:-0},
 				'$new_severity', '$severity', '$(sql_escape "$category")', '$escaped_desc',
 				0, $is_dup, $(if [[ -n "$dup_of" ]]; then echo "$dup_of"; else echo "NULL"; fi));
 		" 2>/dev/null || true
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/archived/audit-task-creator-helper.sh around lines 558 -
566, The pr_number extracted into the variable pr_number is only used in the
false-positive branch, while the below-threshold and normal unified insert paths
still write 0; update those insert statements to include the pr_number variable
(and preserve the existing default behavior by keeping pr_number=$(echo
"$finding" | jq -r '.pr_number // 0') if missing) so every insert path (the
false-positive branch and the normal/below-threshold branches) stores the actual
pr_number rather than a hardcoded 0; locate uses of pr_number in the insert/SQL
commands and replace the literal 0 with the pr_number variable in the unified
insert logic.
.agents/scripts/quickfile-helper.sh-596-632 (1)

596-632: ⚠️ Potential issue | 🟠 Major

Fail closed on malformed or unknown CLI options.

Right now --nominal --dry-run consumes --dry-run as the value, and typos like --dryrun only warn before continuing. In a script that can perform live recording, bad flags should stop execution.

Suggested change
 	while [[ $# -gt 0 ]]; do
 		case "$1" in
 		--dry-run)
 			dry_run="true"
 			shift
 			;;
 		--nominal)
-			nominal_override="${2:-}"
-			shift 2 || {
+			if [[ $# -lt 2 || "$2" == --* ]]; then
 				print_error "Missing value for --nominal"
 				return 1
-			}
+			fi
+			nominal_override="$2"
+			shift 2
 			;;
 		--supplier-id)
-			supplier_id="${2:-}"
-			shift 2 || {
+			if [[ $# -lt 2 || "$2" == --* ]]; then
 				print_error "Missing value for --supplier-id"
 				return 1
-			}
+			fi
+			supplier_id="$2"
+			shift 2
 			;;
 		--auto-supplier)
 			auto_supplier="true"
 			shift
 			;;
 		--currency)
-			currency_override="${2:-}"
-			shift 2 || {
+			if [[ $# -lt 2 || "$2" == --* ]]; then
 				print_error "Missing value for --currency"
 				return 1
-			}
+			fi
+			currency_override="$2"
+			shift 2
 			;;
 		*)
-			print_warning "Unknown option: $1"
-			shift
+			print_error "Unknown option: $1"
+			return 1
 			;;
 		esac
 	done
As per coding guidelines, automation scripts should focus on "Proper exit codes" and "Reliability and robustness".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/quickfile-helper.sh around lines 596 - 632, The CLI parsing
currently treats missing/invalid flag values and unknown options as non-fatal;
update the while-case parser so flags that require arguments (nominal_override,
supplier_id, currency_override) validate that the next token exists and does not
start with '-' (reject if empty or looks like another flag), calling print_error
and exiting non-zero instead of silently consuming a flag as a value; also
change the default (*) branch to treat unknown options as fatal by calling
print_error and exiting non-zero (replace print_warning with print_error), and
keep boolean flags (dry_run, auto_supplier) unchanged.
.agents/scripts/quickfile-helper.sh-116-128 (1)

116-128: ⚠️ Potential issue | 🟠 Major

sed is not a complete JSON string escaper here.

This covers quotes and backslashes, but OCR input can still contain newlines, tabs, or other control characters that will break the generated MCP payload. Please emit a real JSON string literal with json.dumps or jq.

Suggested change
 	# JSON-escape supplier name for safe interpolation into instruction output
 	local escaped_name
-	escaped_name=$(printf '%s' "$supplier_name" | sed 's/\\/\\\\/g; s/"/\\"/g')
+	escaped_name="$(SUPPLIER_NAME="$supplier_name" python3 -c '
+import json, os
+print(json.dumps(os.environ["SUPPLIER_NAME"]))
+')" || {
+		print_error "Failed to encode supplier name"
+		return 1
+	}
 
 	echo "  1. Search for supplier:"
-	echo "     quickfile_supplier_search({ \"searchTerm\": \"${escaped_name}\" })"
+	echo "     quickfile_supplier_search({ \"searchTerm\": ${escaped_name} })"
 	echo ""
 	echo "  2. If found: use the returned SupplierId"
 	echo "     If NOT found:"
 	if [[ "$auto_create" == "true" ]]; then
 		echo "     quickfile_supplier_create({"
-		echo "       \"companyName\": \"${escaped_name}\""
+		echo "       \"companyName\": ${escaped_name}"
 		echo "     })"
As per coding guidelines, automation scripts should focus on "Reliability and robustness".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/quickfile-helper.sh around lines 116 - 128, The sed-based
escaping for supplier_name (variable escaped_name) is insufficient for full JSON
string escaping; replace that logic with a proper JSON string serialization
(e.g., use jq -R `@json` or a short python -c "import json,sys;
print(json.dumps(sys.stdin.read()))") to produce a correct JSON string literal,
update the assignment to escaped_name accordingly, and ensure the echoed lines
that reference escaped_name in the quickfile_supplier_search and
quickfile_supplier_create blocks still use the new escaped_name value.
.agents/scripts/add-skill-helper.sh-437-442 (1)

437-442: ⚠️ Potential issue | 🟠 Major

Consolidate skill registration operations into a single atomic transaction.

The registration path (lines 474–477) uses an unguarded jq ... && mv pattern that can silently fail: if jq fails mid-operation, the && prevents mv from running, rm -f still executes, and the function returns success (line 488) without ever detecting the error. This differs from the delete-old-entry block (lines 437–442), which properly guards operations with error checking and returns 1 on failure.

Consolidate the delete-old-entry and add-new-entry operations into a single atomic jq invocation (using .skills = ([.skills[] | select(.name != $name)] + [$entry])), apply the existing error-handling pattern from lines 437–441, and remove the duplicate cleanup logic. This ensures register_skill either succeeds completely or fails fast with a proper error code.

Suggested fix
-	if [[ -n "$existing" ]]; then
-		log_info "Updating existing skill registration: $name"
-		local tmp_file
-		tmp_file=$(mktemp)
-		_save_cleanup_scope
-		trap '_run_cleanups' RETURN
-		push_cleanup "rm -f '${tmp_file}'"
-		if ! jq --arg name "$name" '.skills = [.skills[] | select(.name != $name)]' "$SKILL_SOURCES" >"$tmp_file"; then
-			log_error "Failed to process skill sources JSON. Update aborted."
-			rm -f "$tmp_file"
-			return 1
-		fi
-		mv "$tmp_file" "$SKILL_SOURCES"
-	fi
+	if [[ -n "$existing" ]]; then
+		log_info "Updating existing skill registration: $name"
+	fi
 
 	local tmp_file
 	tmp_file=$(mktemp)
-	jq --argjson entry "$new_entry" '.skills += [$entry]' "$SKILL_SOURCES" >"$tmp_file" && mv "$tmp_file" "$SKILL_SOURCES"
-	rm -f "$tmp_file"
+	_save_cleanup_scope
+	trap '_run_cleanups' RETURN
+	push_cleanup "rm -f '${tmp_file}'"
+	if ! jq \
+		--arg name "$name" \
+		--argjson entry "$new_entry" \
+		'.skills = ([.skills[] | select(.name != $name)] + [$entry])' \
+		"$SKILL_SOURCES" >"$tmp_file"; then
+		log_error "Failed to process skill sources JSON. Registration aborted."
+		return 1
+	fi
+	mv "$tmp_file" "$SKILL_SOURCES"

Per coding guidelines for automation scripts: focus on reliability, robustness, and proper exit codes. Silent failures undermine all three.

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

In @.agents/scripts/add-skill-helper.sh around lines 437 - 442, Consolidate the
delete-and-add into one atomic jq call inside register_skill: replace the
separate delete (jq ... >"$tmp_file") and later add logic with a single jq
expression using .skills = ([.skills[] | select(.name != $name)] + [$entry])
writing to "$tmp_file", then follow the existing guarded pattern used around
SKILL_SOURCES (check jq exit, on failure call log_error, rm -f "$tmp_file" and
return 1), and only on success mv "$tmp_file" "$SKILL_SOURCES"; remove the
duplicate cleanup/logic so the function either fully updates SKILL_SOURCES or
fails with proper error handling.
.agents/scripts/loop-common.sh-405-408 (1)

405-408: ⚠️ Potential issue | 🟠 Major

Guard the “latest receipt” lookup against an empty receipts directory.

Both pipelines call xargs -0 ls -t even when find returns nothing. In that case ls -t falls back to the current directory, so the re-anchor prompt can embed an unrelated file and loop_get_latest_receipt can return the wrong payload.

As per coding guidelines: "Automation scripts - focus on: Reliability and robustness".

Also applies to: 586-595

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

In @.agents/scripts/loop-common.sh around lines 405 - 408, The current
latest_receipt_file assignment pipes find output into xargs -0 ls -t which will
run ls when find returns nothing, so modify loop_get_latest_receipt to first
capture find results safely (e.g., use find ... -print0 into a variable/array or
readarray -d '' -t files) and only call xargs/ls -t when that array is
non-empty; ensure the code that sets latest_receipt_file and latest_receipt
checks the array length (or non-empty find output) before invoking ls -t, and
apply the same guard to the duplicate block around lines 586-595 so an empty
receipts directory cannot cause ls to list the current directory.
.agents/scripts/loop-common.sh-963-968 (1)

963-968: ⚠️ Potential issue | 🟠 Major

Replace EXIT trap with cleanup stack to avoid overwriting caller's traps.

The loop_run_external() function uses trap ... EXIT, which overwrites any EXIT trap set by the caller when this sourced file is used in a larger shell session. This will leak temp files and silently break other cleanup handlers. Use the cleanup stack pattern already available in shared-constants.sh and already established throughout the rest of the codebase.

♻️ Safer cleanup pattern
 	local output_file
 	output_file=$(mktemp)
 	local output_sizes_file
 	output_sizes_file=$(mktemp)
-	trap 'rm -f "$output_file" "$output_sizes_file"' EXIT
+	_save_cleanup_scope
+	trap '_run_cleanups' RETURN
+	push_cleanup "rm -f '${output_file}' '${output_sizes_file}'"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/loop-common.sh around lines 963 - 968, The EXIT trap in
loop_run_external() overwrites caller traps; instead register a cleanup handler
on the project's cleanup stack (from shared-constants.sh) when you create
output_file and output_sizes_file and remove the trap line; e.g., after mktemp,
push a cleanup action that rm -f "$output_file" "$output_sizes_file" (using the
shared helper such as push_cleanup/add_cleanup from shared-constants.sh) and
ensure the cleanup is popped or runs when the function exits so temp files are
removed without clobbering the caller's EXIT handler.
.agents/scripts/deploy-agents-on-merge.sh-160-176 (1)

160-176: ⚠️ Potential issue | 🟠 Major

Add explicit error handling to detect_changes() to distinguish Git failures from legitimate empty change sets.

The Git calls at lines 161 and 176 mask failures as empty strings (2>/dev/null || echo ""). When a Git command fails—bad commit reference, repository corruption, etc.—the function returns empty identically to when no files actually changed. While callers do return exit code 2 in both cases (lines 419, 448), this conflates two distinct scenarios and prevents proper error recovery.

An invalid --diff commit or repository error now produces indistinguishable output from a legitimate "no changes" state. This violates the automation script guidelines for "Proper exit codes" and "Error recovery mechanisms"—callers cannot diagnose whether to retry, fail fast, or continue.

Let detect_changes() fail on Git errors so main() can handle error cases explicitly.

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

In @.agents/scripts/deploy-agents-on-merge.sh around lines 160 - 176,
detect_changes() currently masks Git failures by redirecting stderr and falling
back to empty strings for both git -C "$REPO_DIR" diff --name-only ... and git
-C "$REPO_DIR" ls-files ...; change this so Git errors are detected and
propagated: run each git command without silencing stderr, capture its stdout
into changed_files_temp and check its exit status immediately (for the git diff
invocation and the ls-files fallback), and if the git command fails log an error
via log_error with the git failure details and return a non-zero status (so
callers can distinguish failure from an empty change set); only treat an exit
status of zero with empty stdout as “no changes” and assign changed_files
accordingly (use the existing changed_files variable and detect_changes()
function names to locate where to implement this).
.agents/scripts/supervisor-archived/todo-sync.sh-13-21 (1)

13-21: ⚠️ Potential issue | 🟠 Major

Escape task IDs before interpolating them into regexes.

This validator only constrains characters; it does not make later grep -E / sed -E matches exact. A dotted ID like t123.1 will still match t12341, so these reconciliation paths can read or update the wrong task.

Run this minimal repro to confirm the false positive:

#!/bin/bash
printf '%s\n' \
  '- [ ] t12341 wrong' \
  '- [ ] t123.1 right' |
grep -nE -- '^[[:space:]]*- \[ \] t123.1( |$)'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor-archived/todo-sync.sh around lines 13 - 21, The
validator _validate_task_id only limits characters but doesn’t prevent substring
regex matches later; update code paths that interpolate task IDs into regexes
(any grep -E / sed -E / awk uses) to escape regex metacharacters before
interpolation (or switch to fixed-string matching like grep -F / awk -v s="$id"
'$0 ~ ("^" s "($| )")' with an escaped/anchored ID). Add a small helper (e.g.,
escape_regex) and call it wherever the ID is used in a regex, ensuring patterns
are anchored (start/end or space boundary) so IDs like t123.1 don’t match
t12341.
.agents/scripts/supervisor-archived/todo-sync.sh-24-29 (1)

24-29: ⚠️ Potential issue | 🟠 Major

Don't rewrite PR file paths when generating VERIFY checks.

tr -cd silently corrupts valid filenames by stripping spaces and other characters. A PR touching docs/Release Notes.md will enqueue checks for docs/ReleaseNotes.md, which doesn't exist. Post-merge verification will fail on a clean repo because the file-exists checks reference the wrong paths.

The sanitization at line 460 modifies the filename before it's used in verification directives, breaking file existence checks for any files containing spaces or special characters in their names.

Also applies to: 457-460

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

In @.agents/scripts/supervisor-archived/todo-sync.sh around lines 24 - 29, The
current _sanitize_filename function corrupts valid file paths by stripping
spaces and other characters; stop altering the original path used for VERIFY
checks and instead produce a shell-escaped version when needed. Update
_sanitize_filename to return the input unchanged for verification uses (or
replace the body with a safe shell-escaping call like printf '%q' "$name" so the
path is quoted rather than characters removed), and ensure callers that build
VERIFY/file-exists directives use the quoted/escaped value (not a stripped
variant). Change references to _sanitize_filename in the verification-generation
code to use the new behavior so files like "docs/Release Notes.md" are preserved
and the generated file-exists checks point to the real path.
.agents/scripts/quality-cli-manager.sh-36-36 (1)

36-36: ⚠️ Potential issue | 🟠 Major

Resolve delegated script paths from SCRIPT_DIR.

execute_cli_command() resolves QLTY_SCRIPT against the caller’s current working directory. If this manager is launched from .agents/scripts/ or any non-repo-root directory, the -f check fails and the delegated command is reported as missing even though the file exists.

🛠️ Suggested fix
-readonly CODERABBIT_SCRIPT=".agents/scripts/coderabbit-cli.sh"
-readonly CODACY_SCRIPT=".agents/scripts/codacy-cli.sh"
-readonly SONAR_SCRIPT=".agents/scripts/sonarscanner-cli.sh"
-readonly SNYK_SCRIPT=".agents/scripts/snyk-helper.sh"
-readonly QLTY_SCRIPT=".agents/scripts/qlty-cli.sh"
+readonly CODERABBIT_SCRIPT="${SCRIPT_DIR}/coderabbit-cli.sh"
+readonly CODACY_SCRIPT="${SCRIPT_DIR}/codacy-cli.sh"
+readonly SONAR_SCRIPT="${SCRIPT_DIR}/sonarscanner-cli.sh"
+readonly SNYK_SCRIPT="${SCRIPT_DIR}/snyk-helper.sh"
+readonly QLTY_SCRIPT="${SCRIPT_DIR}/qlty-cli.sh"

As per coding guidelines, .agents/scripts/*.sh: Automation scripts - focus on Reliability and robustness.

Also applies to: 86-92

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

In @.agents/scripts/quality-cli-manager.sh at line 36, The QLTY_SCRIPT constant
is being resolved relative to the caller's CWD, causing -f checks in
execute_cli_command to fail when the manager runs outside repo root; change
QLTY_SCRIPT resolution to join SCRIPT_DIR with the script name (use SCRIPT_DIR
and QLTY_SCRIPT together to produce an absolute or repo-root-relative path) and
update execute_cli_command to test and invoke that resolved path (refer to
QLTY_SCRIPT, SCRIPT_DIR, and execute_cli_command); also apply the same fix to
the other checks/invocations around the execute_cli_command block (the section
referenced by lines ~86-92) so all delegated script path checks use the resolved
SCRIPT_DIR-based path.
.agents/scripts/quality-cli-manager.sh-471-497 (1)

471-497: ⚠️ Potential issue | 🟠 Major

Fail closed on unsupported CLI targets.

A typo like analyze qltyy, or an unsupported command/target pair such as status codacy-fix or init linters, currently skips every handler and still returns success. In automation that silently disables the requested action.

🧭 Suggested fix
+is_valid_target_cli() {
+	local command="$1"
+	local cli="$2"
+
+	case "${command}:${cli}" in
+	install:all|install:coderabbit|install:codacy|install:sonar|install:qlty|install:snyk|install:linters|\
+	init:all|init:coderabbit|init:codacy|init:sonar|init:qlty|init:snyk|\
+	analyze:all|analyze:coderabbit|analyze:codacy|analyze:codacy-fix|analyze:sonar|analyze:qlty|analyze:snyk|analyze:snyk-sca|analyze:snyk-code|analyze:snyk-iac|\
+	status:all|status:coderabbit|status:codacy|status:sonar|status:qlty|status:snyk)
+		return 0
+		;;
+	help:*|--help:*|-h:*)
+		return 0
+		;;
+	*)
+		return 1
+		;;
+	esac
+}
+
 main() {
 	local command="${1:-help}"
 	local cli="${2:-all}"
 	shift 2 2>/dev/null || shift $# # Remove processed arguments
+
+	if ! is_valid_target_cli "$command" "$cli"; then
+		print_error "Unsupported CLI target '$cli' for command '$command'"
+		echo ""
+		show_help
+		return 1
+	fi

 	case "$command" in

As per coding guidelines, .agents/scripts/*.sh: Automation scripts - focus on Proper exit codes.

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

In @.agents/scripts/quality-cli-manager.sh around lines 471 - 497, Handlers like
install_clis, init_clis, analyze_with_clis and show_cli_status currently accept
unknown/unsupported CLI targets and still exit 0, causing automation to silently
succeed; change the command dispatch to check each handler's exit status and
propagate failures: call the handler (e.g., install_clis "$cli"), capture its
return code, and if non‑zero call print_error (with context using
ERROR_UNKNOWN_COMMAND and "$cli") and return that code; alternatively ensure
each handler (install_clis, init_clis, analyze_with_clis, show_cli_status)
validates the "$cli" target and returns a non‑zero status for unsupported
targets so the case block can propagate the error instead of returning success.
.agents/scripts/quality-cli-manager.sh-354-368 (1)

354-368: ⚠️ Potential issue | 🟠 Major

Guard status calls to complete the report even if a CLI is missing.

These execute_cli_command ... status calls (lines 356, 362, 368) are direct and unguarded. With set -e, if any underlying helper script returns non-zero, the function exits immediately, leaving the status report incomplete. This breaks the expectation that status all produces a full report for all CLIs.

All other operations (install, init, analyze) guard their execute_cli_command calls with if conditions to continue despite failures—follow that pattern here.

🛡️ Suggested fix
 	if [[ "$target_cli" == "all" || "$target_cli" == "$CLI_CODERABBIT" ]]; then
 		print_info "CodeRabbit CLI Status:"
-		execute_cli_command "$CLI_CODERABBIT" "status"
+		if ! execute_cli_command "$CLI_CODERABBIT" "status"; then
+			print_warning "Unable to retrieve CodeRabbit CLI status"
+		fi
 		echo ""
 	fi

 	if [[ "$target_cli" == "all" || "$target_cli" == "codacy" ]]; then
 		print_info "Codacy CLI Status:"
-		execute_cli_command "codacy" "status"
+		if ! execute_cli_command "codacy" "status"; then
+			print_warning "Unable to retrieve Codacy CLI status"
+		fi
 		echo ""
 	fi

 	if [[ "$target_cli" == "all" || "$target_cli" == "sonar" ]]; then
 		print_info "SonarScanner CLI Status:"
-		execute_cli_command "sonar" "status"
+		if ! execute_cli_command "sonar" "status"; then
+			print_warning "Unable to retrieve SonarScanner CLI status"
+		fi
 		echo ""
 	fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/quality-cli-manager.sh around lines 354 - 368, The unguarded
execute_cli_command calls for status (invocations of execute_cli_command
"$CLI_CODERABBIT" "status", execute_cli_command "codacy" "status", and
execute_cli_command "sonar" "status") can abort the script under set -e; wrap
each status call in the same failure-tolerant pattern used for
install/init/analyze (e.g., use if ! execute_cli_command <cli> "status"; then
print a non-fatal warning via print_info/print_warn and continue; fi) and keep
the surrounding print_info and echo "" so the status report completes even if a
CLI returns non-zero.
.agents/scripts/worktree-helper.sh-336-353 (1)

336-353: ⚠️ Potential issue | 🟠 Major

Guard this filter chain against pipefail with proper error recovery.

The grep -v chain at lines 346–350 can fail when all git status --porcelain entries are excluded runtime paths. Each grep stage that filters out all remaining lines returns exit 1; under set -euo pipefail, this aborts the assignment before the function can return "no changes", causing clean to fail on the exact runtime noise this helper is designed to ignore.

🛠️ Proposed fix
-		changes=$(echo "$changes" |
-			grep -v '^\?\? \.agents/loop-state/' |
-			grep -v '^\?\? \.agents/tmp/' |
-			grep -v '^\?\? \.agents/$' |
-			grep -v '^\?\? \.DS_Store' |
-			head -1)
+		changes=$(
+			{
+				printf '%s\n' "$changes" |
+					grep -v '^\?\? \.agents/loop-state/' |
+					grep -v '^\?\? \.agents/tmp/' |
+					grep -v '^\?\? \.agents/$' |
+					grep -v '^\?\? \.DS_Store' |
+					head -1
+			} || true
+		)

Required for reliability in automation scripts: "Proper exit codes" and "Error recovery mechanisms".

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

In @.agents/scripts/worktree-helper.sh around lines 336 - 353, The grep -v
pipeline in worktree_has_changes can return non-zero when all lines are filtered
(breaking scripts under set -euo pipefail); change the assignment that builds
"changes" (the echo "$changes" | grep -v ... | head -1 pipeline) so failures
don't propagate—e.g., ensure the pipeline's non-zero exit is converted into an
empty result by capturing its output and defaulting to an empty string on
failure (use a fallback like "|| true" or explicitly set changes="" when the
pipeline exits non-zero) so worktree_has_changes returns false when nothing
remains after filtering.
.agents/scripts/accessibility-audit-helper.sh-116-126 (1)

116-126: ⚠️ Potential issue | 🟠 Major

Configure WCAG levels with explicit mapping to prevent silent audit downgrade.

The function only handles three exact tokens—WCAG2A and WCAG2AAA are recognized, all others fall through to the WCAG2AA default. If a user sets AUDIT_WCAG_LEVEL=WCAG21AA, WCAG22AA, or uses lowercase variants, the audit silently reverts to 2AA coverage without warning, potentially missing criteria the operator explicitly requested. Normalize the input and map all supported variants explicitly, then warn when an unknown level is provided.

Handle supported variants explicitly
-_wcag_level_to_axe_tags() {
-	case "${1:-WCAG2AA}" in
+_wcag_level_to_axe_tags() {
+	local level="${1:-WCAG2AA}"
+	case "${level^^}" in
 	WCAG2A) echo "wcag2a,best-practice" ;;
+	WCAG21A) echo "wcag2a,wcag21a,best-practice" ;;
+	WCAG21AA) echo "wcag2a,wcag2aa,wcag21aa,best-practice" ;;
+	WCAG22AA) echo "wcag2a,wcag2aa,wcag21aa,wcag22aa,best-practice" ;;
 	WCAG2AAA) echo "wcag2a,wcag2aa,wcag2aaa,best-practice" ;;
-	*) echo "wcag2a,wcag2aa,best-practice" ;;
+	*) print_warning "Unknown AUDIT_WCAG_LEVEL '${level}', defaulting to WCAG2AA"
+	   echo "wcag2a,wcag2aa,best-practice" ;;
 	esac
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/accessibility-audit-helper.sh around lines 116 - 126, The
_wcag_level_to_axe_tags function silently falls back to WCAG2AA; normalize and
validate AUDIT_WCAG_LEVEL by uppercasing/trimming input inside
_wcag_level_to_axe_tags, expand the case patterns to explicitly match supported
variants (e.g. WCAG2A, WCAG2AA, WCAG2AAA, WCAG21AA, WCAG22AA, WCAG21A/AA/AAA,
and common lowercase forms) and return the correct tag sets for each; if the
provided value doesn't match any supported pattern emit a warning (stderr or
using existing logging) and return the safest default tag set, and ensure
run_axe_audit continues to use the normalized result.
.agents/scripts/enhancor-helper.sh-720-723 (1)

720-723: ⚠️ Potential issue | 🟠 Major

Serialize JSON payloads with jq to handle special characters in user inputs.

Free-form prompts can contain quotes, backslashes, or newlines that break the hand-built JSON string concatenation pattern (lines 704-715 and similar patterns in other functions). This causes API failures when users provide natural text. Use jq -cn with --arg variables to safely serialize the request body—the test demonstrates that unescaped quotes cause parse errors while jq properly escapes all special characters.

This pattern repeats across five command functions (cmd_enhance, cmd_upscale, cmd_upscale_general, cmd_detailed, cmd_generate). Standardize the serialization approach across all queue submission calls.

Serialize the request body instead of concatenating it
-	local body="{\"model\": \"${model}\", \"prompt\": \"${prompt}\""
+	local body
+	body=$(jq -cn \
+		--arg model "$model" \
+		--arg prompt "$prompt" \
+		--arg generation_mode "$generation_mode" \
+		--arg image_size "$image_size" \
+		--arg img_url "$img_url" \
+		--arg webhook_url "$webhook_url" '
+			{
+				model: $model,
+				prompt: $prompt,
+				generation_mode: $generation_mode,
+				image_size: $image_size
+			}
+			+ (if $img_url == "" then {} else {img_url: $img_url} end)
+			+ (if $webhook_url == "" then {} else {webhookUrl: $webhook_url} end)
+		')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/enhancor-helper.sh around lines 720 - 723, The JSON body is
being assembled via string concatenation and breaks on special characters;
replace that with safe serialization using jq -cn and --arg/--argjson to build
the request payload for the queue submission instead of manual concatenation.
Update each function that posts to api_request POST "/kora/v1/queue"
(cmd_enhance, cmd_upscale, cmd_upscale_general, cmd_detailed, cmd_generate) to
construct the body into the same 'body' variable via: jq -cn --arg key "$val"
... '{...}' (or --argjson for numbers/objects), then call api_request with that
serialized body and capture response as before, ensuring the payload fields
(prompt, metadata, etc.) match the original keys. Ensure all places that
previously built the body string directly are replaced so quotes, backslashes,
and newlines are escaped correctly.
.agents/scripts/enhancor-helper.sh-118-125 (1)

118-125: ⚠️ Potential issue | 🟠 Major

Bare jq assignments cause hard exits on malformed responses under set -e.

All api_request call sites properly use if ! response=$(...), but subsequent jq extractions are unprotected. Under set -euo pipefail, if the API returns 200 with invalid JSON, jq fails and the script exits before error handling runs. This affects status polling and all response parsing.

Wrap jq assignments with error handling
-		status=$(echo "${response}" | jq -r '.status // empty' 2>/dev/null)
+		if ! status=$(printf '%s' "${response}" | jq -r '.status // empty' 2>/dev/null); then
+			print_error "Invalid JSON in status response for request: ${request_id}"
+			printf '%s\n' "${response}" >&2
+			return 1
+		fi

Apply the same pattern to other bare jq assignments (.result, .error, .requestId) throughout the file.

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

In @.agents/scripts/enhancor-helper.sh around lines 118 - 125, The bare jq
extraction after the api_request (e.g., the status assignment using
status=$(echo "${response}" | jq -r '.status // empty')) can cause the script to
hard-exit under set -e if jq fails on malformed JSON; change these to guarded
assignments using the same pattern as the api_request calls (for example: if !
status=$(echo "${response}" | jq -r '.status // empty' 2>/dev/null); then
print_error "Failed to parse status from response for request: ${request_id}";
return 1; fi) so failures are handled gracefully; apply the same guarded jq
pattern to all other bare jq uses in this file (notably extractions for .result,
.error, .requestId and any other jq parsing) and ensure you include context in
the print_error messages and return a non-zero code where appropriate.
🟡 Minor comments (5)
.agents/scripts/runway-helper.sh-279-283 (1)

279-283: ⚠️ Potential issue | 🟡 Minor

Enforce the documented --ref cap in the parser.

Line 867 says --ref is allowed "up to 3", but Lines 279-283 append unboundedly. Reject the fourth reference locally so users get a deterministic CLI error instead of a downstream API failure.

💡 Suggested fix
 		--ref)
 			_require_arg "$1" "${2:-}" || return 1
+			if [[ ${`#refs`[@]} -ge 3 ]]; then
+				echo "ERROR: --ref may be provided at most 3 times" >&2
+				return 1
+			fi
 			refs+=("$2")
 			shift 2
 			;;

As per coding guidelines, automation scripts should prioritize "Reliability and robustness" and "Proper exit codes".

Also applies to: 867-867

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

In @.agents/scripts/runway-helper.sh around lines 279 - 283, The parser
currently appends unlimited values to the refs array in the --ref case; update
that case (the --ref branch handling where refs+=("$2") and shift 2 occurs) to
check the count of refs before adding and return a non-zero error if adding a
fourth would exceed the documented cap of 3, using _require_arg to validate the
argument and emitting a clear error message and exit code when the limit is
reached; ensure the validation runs prior to appending so users receive a
deterministic CLI error instead of a downstream failure.
.agents/scripts/runway-helper.sh-104-115 (1)

104-115: ⚠️ Potential issue | 🟡 Minor

Add numeric validation at parse time for duration, seed, and speakers fields.

Lines 114–115, 121–130, 537–545, and 621–632 use jq tonumber to convert user input, but the argument parsers at lines 174–182, 512–515, and 596–599 only validate that values exist. When users pass non-numeric inputs like --duration foo, --seed abc, or --speakers many, the command fails inside jq with a technical error message rather than a clear CLI feedback. With set -euo pipefail, these failures exit the script immediately without the opportunity for user-friendly error reporting.

Add a simple numeric validator (similar to _require_arg) to check these fields at parse time, ensuring the script exits with descriptive feedback before attempting JSON construction.

Also applies to: 121–130, 174–182, 512–515, 537–545, 596–599, 621–632

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

In @.agents/scripts/runway-helper.sh around lines 104 - 115, Add a small numeric
validator function (e.g., _require_numeric_arg) modeled after _require_arg that
tests a provided value with a regex allowing integers or decimals (e.g.,
^[0-9]+(\.[0-9]+)?$), prints a clear error like "Error: --duration must be
numeric" to stderr and exits non-zero when validation fails; then call this
validator wherever duration, seed, or speakers are parsed (the places that set
local variables duration, seed, speakers and before building the jq JSON: the
blocks that define local model/image/ratio/prompt/duration/seed and the
argument-parsing functions handling --duration, --seed, --speakers) so invalid
inputs are rejected with a friendly CLI message before jq | tonumber runs.
.agents/scripts/deploy-agents-on-merge.sh-193-200 (1)

193-200: ⚠️ Potential issue | 🟡 Minor

--dry-run still mutates the target directories.

Both deploy paths call mkdir -p before the dry-run early return, so a no-op run still creates directories under $HOME/.aidevops. Move directory creation below the dry-run checks.

As per coding guidelines, automation scripts should focus on "Reliability and robustness".

Also applies to: 232-237

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

In @.agents/scripts/deploy-agents-on-merge.sh around lines 193 - 200, The
dry-run branch still calls mkdir -p which mutates target directories; move the
mkdir -p "$target_scripts_dir" (and the other mkdir -p call referenced around
lines 232-237) so they execute only after the DRY_RUN checks; specifically,
check the DRY_RUN/--dry-run variable first (the existing if [[ "$DRY_RUN" ==
"true" ]] blocks), return early for dry-run, and only then create directories
and perform the real sync—update the script regions that reference
"$target_scripts_dir" and the second target directory to defer mkdir -p until
after the dry-run early return.
.agents/scripts/deploy-agents-on-merge.sh-432-434 (1)

432-434: ⚠️ Potential issue | 🟡 Minor

Fix the double-output bug in the scripts-only optimization check.

When all changed files are under .agents/scripts/, grep -cv '^\.agents/scripts/' outputs 0 but exits with code 1. The current || echo "0" appends another 0, creating a variable containing 0\n0 instead of 0. This causes the numeric test [[ "$non_script_changes" -eq 0 ]] to fail with a syntax error, skipping the fast path optimization entirely.

Apply this fix
-		non_script_changes=$(echo "$changed" | grep -cv '^\.agents/scripts/' || echo "0")
+		non_script_changes=$(printf '%s\n' "$changed" | grep -cv '^\.agents/scripts/' || true)

This preserves grep's output while suppressing its non-zero exit code, ensuring the optimization works as intended.

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

In @.agents/scripts/deploy-agents-on-merge.sh around lines 432 - 434, The
variable non_script_changes gets "0\n0" because the existing command appends "0"
on grep's non-zero exit; change the assignment so grep's numeric output is
preserved and its non-zero exit is suppressed (e.g., run grep -cv
'^\.agents/scripts/' but ignore its exit status) and then normalize empty output
to 0 (e.g., set non_script_changes to 0 when the captured value is empty) —
update the line that assigns non_script_changes and keep the later numeric test
[[ "$non_script_changes" -eq 0 ]] unchanged; refer to the non_script_changes
variable and the grep -cv '^\.agents/scripts/' invocation to locate the code to
modify.
.agents/content/production/video.md-325-329 (1)

325-329: ⚠️ Potential issue | 🟡 Minor

Guard the jq parse step to prevent unhandled failures with set -euo pipefail.

The current code exits on invalid JSON before reaching the error handler. Wrap the assignment in if ! to catch jq failures and continue the loop:

Guard the parse step
-  job_id=$(echo "$result" | jq -r '.jobs[0].id // empty' 2>/dev/null)
-  if [[ -z "$job_id" ]]; then
+  if ! job_id=$(printf '%s' "$result" | jq -r '.jobs[0].id // empty' 2>/dev/null); then
+    echo "ERROR: Failed to parse API response for seed $seed"
+    continue
+  fi
+  if [[ -z "$job_id" ]]; then
     echo "ERROR: Failed to extract job_id for seed $seed (API response invalid)"
     continue
   fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/content/production/video.md around lines 325 - 329, The jq
assignment for job_id can cause the script to exit under set -euo pipefail when
jq fails; wrap the parse in a guarded conditional so failures are caught and the
loop continues. Replace the bare assignment of job_id=$(echo "$result" | jq -r
'.jobs[0].id // empty' 2>/dev/null) with an if ! ...; then echo the same error
(“ERROR: Failed to extract job_id for seed $seed (API response invalid)”) and
continue; otherwise proceed with the extracted job_id. This keeps the jq failure
from aborting the script while preserving the existing error handling and uses
the same job_id variable name.
🧹 Nitpick comments (4)
.agents/scripts/autogen-helper.sh (1)

88-93: Minor: Version comparison logic has an edge case.

The condition [[ $major -ge 3 ]] && [[ $minor -ge 10 ]] would incorrectly reject hypothetical Python 4.0 (since 0 < 10). While Python 4 doesn't exist, a more robust approach would be:

♻️ Optional fix for version comparison
-		if [[ $major -ge 3 ]] && [[ $minor -ge 10 ]]; then
+		if [[ $major -gt 3 ]] || { [[ $major -eq 3 ]] && [[ $minor -ge 10 ]]; }; then
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/autogen-helper.sh around lines 88 - 93, The version check in
autogen-helper.sh using the conditional that tests [[ $major -ge 3 ]] && [[
$minor -ge 10 ]] incorrectly fails for majors >3 (e.g., 4.0) because it requires
minor >=10; change the logic in the conditional that checks major and minor
(variables major, minor, python_version) to first test major > 3 (accept any
newer major) or major == 3 and minor >= 10, and then use that combined condition
for the print_success/print_error branch so Python 3.10+ or any future major is
accepted.
.agents/scripts/langflow-helper.sh (2)

56-74: Fallback port detection lacks nc double-check present in localhost-helper.sh.

The relevant context shows localhost-helper.sh uses both lsof and nc for port detection (see is_port_free function), while this fallback only uses lsof. In edge cases where lsof misses a bound port, the fallback could return a port that's actually in use.

Additionally, localhost-helper.sh uses PORT_RANGE_END=9999, but this fallback searches up to 65535—a deliberate choice for broader coverage, but worth noting for consistency awareness.

The pre-increment at line 69 (((++port))) correctly addresses the set -e compatibility objective.

💡 Optional: Add nc double-check for parity with localhost-helper.sh
 	# Fallback: basic port check using lsof
-	if ! lsof -i :"$desired_port" >/dev/null 2>&1; then
+	if ! lsof -i :"$desired_port" >/dev/null 2>&1 && \
+	   ! { command -v nc >/dev/null 2>&1 && nc -z 127.0.0.1 "$desired_port" 2>/dev/null; }; then
 		echo "$desired_port"
 		return 0
 	fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/langflow-helper.sh around lines 56 - 74, The fallback port
detection currently only uses lsof (in the block around desired_port and the
while loop) and should also probe with nc like is_port_free in
localhost-helper.sh; modify the initial check and the while loop to treat a port
as in-use if either lsof -i :$port or nc -z localhost $port returns success
(>/dev/null 2>&1), keeping the same return behavior and the pre-increment logic
for variable port, and preserve the existing warning/echo behavior when
selecting a fallback port.

340-342: Minor: Redundant process lookup in status script.

The pgrep -f "langflow" already outputs PIDs, but then ps aux | grep... duplicates the lookup. If pgrep succeeds, its output (PIDs) is printed but not used, and ps re-scans.

♻️ Cleaner alternative using pgrep alone
 echo ""
 echo "Process Information:"
-pgrep -f "langflow" && ps aux | grep -E "langflow" | grep -v grep || echo "No Langflow processes found"
+pgrep -af "langflow" || echo "No Langflow processes found"

The -a flag shows the full command line, combining both lookups into one.

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

In @.agents/scripts/langflow-helper.sh around lines 340 - 342, The status script
currently runs pgrep -f "langflow" and then duplicates the lookup with ps aux |
grep -E "langflow" | grep -v grep; replace this with a single pgrep invocation
that prints full command lines (use pgrep -af "langflow") and fall back to echo
"No Langflow processes found" if it returns nothing, removing the redundant ps
aux | grep -E "langflow" pipeline; update the lines referencing pgrep -f
"langflow" and ps aux | grep -E "langflow" to use the single pgrep -af approach.
.agents/scripts/quickfile-helper.sh (1)

47-48: Surface workspace creation failures instead of masking them.

mkdir -p ... || true turns permission/full-disk errors into a later, less actionable failure when the script tries to write the instruction file. This helper should report the real cause and return non-zero.

Suggested change
 ensure_workspace() {
-	mkdir -p "$QF_WORKSPACE" 2>/dev/null || true
-	return 0
+	if mkdir -p "$QF_WORKSPACE"; then
+		return 0
+	fi
+	print_error "Failed to create QuickFile workspace: ${QF_WORKSPACE}"
+	return 1
 }
As per coding guidelines, automation scripts should focus on "Clear logging and feedback" and "Error recovery mechanisms".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/quickfile-helper.sh around lines 47 - 48, The workspace
creation currently masks failures by silencing stderr and forcing success;
change the mkdir call that uses QF_WORKSPACE so it does not append "|| true" or
redirect errors to /dev/null, instead let mkdir return a non-zero exit on
failure and log the stderr (or echo a clear error message including the
QF_WORKSPACE path) so the script exits non-zero (remove the unconditional
"return 0" or return the mkdir status) so callers see permission/full-disk
errors.

Comment on lines +558 to +566
local finding_id source severity path line description category pr_number
finding_id=$(echo "$finding" | jq -r '.id')
source=$(echo "$finding" | jq -r '.source')
severity=$(echo "$finding" | jq -r '.severity')
path=$(echo "$finding" | jq -r '.path // ""')
line=$(echo "$finding" | jq -r '.line // 0')
description=$(echo "$finding" | jq -r '.description')
category=$(echo "$finding" | jq -r '.category // "general"')
pr_number=$(echo "$finding" | jq -r '.pr_number // 0')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Backfill the new pr_number column before writing it.

init_task_db() creates processed_findings.pr_number, but ensure_task_db() still only migrates source_tool. On any existing task DB, these new INSERT ... pr_number ... statements fail, and the trailing || true hides the error, so unified findings are silently dropped.

🛠️ Suggested migration
@@
 	# Migrate schema if needed (add source_tool column for multi-source tracking)
 	local has_source_tool
 	has_source_tool=$(db "$active_db" "SELECT COUNT(*) FROM pragma_table_info('processed_findings') WHERE name='source_tool';" 2>/dev/null || echo "0")
 	if [[ "$has_source_tool" == "0" ]]; then
 		db "$active_db" "ALTER TABLE processed_findings ADD COLUMN source_tool TEXT DEFAULT 'coderabbit';" 2>/dev/null || true
 	fi
+
+	local has_pr_number
+	has_pr_number=$(db "$active_db" "SELECT COUNT(*) FROM pragma_table_info('processed_findings') WHERE name='pr_number';" 2>/dev/null || echo "0")
+	if [[ "$has_pr_number" == "0" ]]; then
+		db "$active_db" "ALTER TABLE processed_findings ADD COLUMN pr_number INTEGER;" 2>/dev/null || true
+	fi

Also applies to: 578-586

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

In @.agents/scripts/archived/audit-task-creator-helper.sh around lines 558 -
566, Existing DBs lack processed_findings.pr_number so INSERTs that include
pr_number fail silently; update ensure_task_db() (and/or init_task_db()) to
migrate/backfill that column by adding a pr_number INTEGER DEFAULT 0 (or ALTER
TABLE to add the column) and run UPDATE processed_findings SET pr_number=0 for
existing rows so subsequent INSERT ... pr_number ... succeeds, and remove or
avoid masking errors with trailing "|| true" on those migration/insert
statements so migration failures are visible; target modifications around the
ensure_task_db(), init_task_db(), and any INSERT statements that reference
processed_findings.pr_number.

Comment on lines +830 to +861
if git diff --quiet HEAD 2>/dev/null && git diff --cached --quiet HEAD 2>/dev/null; then
# No uncommitted changes — just push existing commits
if git log --oneline "origin/${branch}..HEAD" 2>/dev/null | grep -q .; then
loop_log_info "Context guard: pushing unpushed commits on $branch"
git push origin "$branch" 2>/dev/null || {
loop_log_warn "Context guard: push failed, trying with --force-with-lease"
git push --force-with-lease origin "$branch" 2>/dev/null || true
}
fi
return 0
fi

# Stage and commit uncommitted work
loop_log_info "Context guard: committing uncommitted work before exit"
git add -A 2>/dev/null || true

local task_id
task_id=$(loop_get_state ".task_id" 2>/dev/null || echo "unknown")
git commit -m "wip: emergency commit before context exhaustion ($task_id)" \
--no-verify 2>/dev/null || {
loop_log_warn "Context guard: commit failed"
return 1
}

# Push
loop_log_info "Context guard: pushing to $branch"
git push origin "$branch" 2>/dev/null || {
git push -u origin "$branch" 2>/dev/null || {
loop_log_warn "Context guard: push failed, trying with --force-with-lease"
git push --force-with-lease origin "$branch" 2>/dev/null || true
}
}
Copy link
Copy Markdown
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:

# Examine the target lines and surrounding context
head -n 870 .agents/scripts/loop-common.sh | tail -n 45

Repository: marcusquinn/aidevops

Length of output: 1515


🏁 Script executed:

# Also check the other mentioned locations
head -n 930 .agents/scripts/loop-common.sh | tail -n 35

Repository: marcusquinn/aidevops

Length of output: 1232


🏁 Script executed:

# Check the third location
head -n 1040 .agents/scripts/loop-common.sh | tail -n 30

Repository: marcusquinn/aidevops

Length of output: 1245


🏁 Script executed:

# Find the loop_context_guard function definition to see full context
grep -n "loop_context_guard" .agents/scripts/loop-common.sh | head -20

Repository: marcusquinn/aidevops

Length of output: 192


🏁 Script executed:

# Find loop_run_external to see how it uses the guard result
grep -n "loop_run_external" .agents/scripts/loop-common.sh | head -20

Repository: marcusquinn/aidevops

Length of output: 89


🏁 Script executed:

sed -n '890,930p' .agents/scripts/loop-common.sh

Repository: marcusquinn/aidevops

Length of output: 1359


Fix exit code reporting in loop_emergency_push and callers to reflect actual push success.

The function suppresses all git push failures with || true and unconditionally returns 0, preventing callers from detecting when work failed to reach a remote. This allows loop_context_guard to report "work preserved" and loop_run_external to emit completion signals even when the only copy is a local WIP commit in an ephemeral worktree—violating the automation script guidelines for proper exit codes and error recovery.

The pattern appears at:

  • loop_emergency_push (lines 830–861): all push attempts end with || true before final return 0
  • loop_context_guard (line 920): ignores loop_emergency_push result; always return 0
  • loop_run_external caller (line 1033): logs success unconditionally on guard return
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/loop-common.sh around lines 830 - 861, loop_emergency_push
currently swallows all git push failures (using "|| true") and always returns
success, so callers can't detect remote push failures; change
loop_emergency_push to record each git push exit status (remove "|| true" that
hides failures), return non-zero if all push attempts fail (e.g., return the
last non-zero exit code) and only fall back to force-with-lease if earlier
pushes failed, then update loop_context_guard to capture and return
loop_emergency_push's exit code instead of unconditionally returning 0, and
update loop_run_external to check that return value and avoid emitting "work
preserved" or completion signals when the guard reports failure. Ensure you
reference the functions loop_emergency_push, loop_context_guard, and
loop_run_external when making these changes so failures propagate correctly.

Comment on lines +139 to +145
local model="gen4_turbo"
local ratio="1280:720"
local duration=""
local seed=""
local audio=""
local video_uri=""
local wait_flag=false
Copy link
Copy Markdown
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

🌐 Web query:

For Runway API version 2024-11-06, which model(s) are accepted by the /v1/video_to_videoendpoint? Isgen4_alephthe expected/default model, or isgen4_turbo also valid?

💡 Result:

For Runway API version 2024-11-06, the POST /v1/video_to_video endpoint accepts only:

  • gen4_aleph

In the API reference, the request body field model is required and “must be set to the exact value gen4_aleph,” meaning there’s no alternate/default selection for that endpoint in this version. gen4_turbo is not a valid model value for /v1/video_to_video (it’s used on other endpoints like /v1/image_to_video). [1]

Sources:
[1] Runway API Reference (X-Runway-Version 2024-11-06) – POST /v1/video_to_video model requirement. (docs.dev.runwayml.com)

Citations:


🏁 Script executed:

head -n 230 .agents/scripts/runway-helper.sh | tail -n +130

Repository: marcusquinn/aidevops

Length of output: 2088


🏁 Script executed:

# Verify the help text location and content
sed -n '852,855p' .agents/scripts/runway-helper.sh

Repository: marcusquinn/aidevops

Length of output: 341


Fix critical API failure: /v1/video_to_video does not accept gen4_turbo.

Line 139 defaults model to gen4_turbo, and Lines 212-214 send that value to /v1/video_to_video. The Runway API (v2024-11-06) only accepts gen4_aleph for this endpoint—gen4_turbo is invalid and will cause the request to fail. The help text at Line 852 correctly documents gen4_aleph as the model for video-to-video operations. Switch the model to gen4_aleph when the --video flag is used.

💡 Suggested fix
 	if [[ -n "$video_uri" ]]; then
+		if [[ "$model" == "gen4_turbo" ]]; then
+			model="gen4_aleph"
+		fi
 		json_body="$(_build_v2v_json "$model" "$video_uri" "$prompt")"
 		endpoint="/v1/video_to_video"
📝 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 model="gen4_turbo"
local ratio="1280:720"
local duration=""
local seed=""
local audio=""
local video_uri=""
local wait_flag=false
if [[ -n "$video_uri" ]]; then
if [[ "$model" == "gen4_turbo" ]]; then
model="gen4_aleph"
fi
json_body="$(_build_v2v_json "$model" "$video_uri" "$prompt")"
endpoint="/v1/video_to_video"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/runway-helper.sh around lines 139 - 145, The script defaults
model="gen4_turbo" which is invalid for the Runway /v1/video_to_video endpoint;
update the logic that handles the --video flag so that when video mode is used
the model variable is set to "gen4_aleph" (replace uses that send model to
/v1/video_to_video around the code that builds/sends the request where model is
referenced); ensure any help text or defaults remain consistent with the
documented model for video-to-video (the --video handling and the model variable
assignment).

Comment on lines +298 to +303
for v in concurrency max_concurrency; do
if ! [[ "${!v}" =~ ^[0-9]+$ ]]; then
log_error "--${v//_/-} must be a non-negative integer"
return 1
fi
done
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

--max-load still bypasses validation and reaches SQLite raw.

The new loop only checks concurrency and max_concurrency, but Line 332 still interpolates max_load_factor unquoted into the INSERT. That leaves a remaining SQL-injection / malformed-input path in cmd_batch.

Suggested fix
-for v in concurrency max_concurrency; do
+for v in concurrency max_concurrency max_load_factor; do
 	if ! [[ "${!v}" =~ ^[0-9]+$ ]]; then
 		log_error "--${v//_/-} must be a non-negative integer"
 		return 1
 	fi
 done
📝 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
for v in concurrency max_concurrency; do
if ! [[ "${!v}" =~ ^[0-9]+$ ]]; then
log_error "--${v//_/-} must be a non-negative integer"
return 1
fi
done
for v in concurrency max_concurrency max_load_factor; do
if ! [[ "${!v}" =~ ^[0-9]+$ ]]; then
log_error "--${v//_/-} must be a non-negative integer"
return 1
fi
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor-archived/batch.sh around lines 298 - 303, The
max_load_factor value is not being validated and is interpolated raw into the
SQL in cmd_batch; extend the validation loop to include max_load_factor (add it
to the for v in ... list) and validate it with the same regex (e.g., ^[0-9]+$)
as concurrency/max_concurrency, and then make sure when constructing cmd_batch
you interpolate the value safely (use the validated variable and quote it as
"${max_load_factor}" or otherwise escape it) so the INSERT no longer accepts
arbitrary/malicious input.

Comment on lines +186 to +187
# Has remote tracking branch on any remote (not just origin)
if git for-each-ref --format="%(refname)" "refs/remotes/*/$branch" 2>/dev/null | grep -q .; then
Copy link
Copy Markdown
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
set -euo pipefail

file=".agents/scripts/worktree-helper.sh"

echo "=== remote resolution helpers ==="
sed -n '177,205p' "$file"

echo
echo "=== cmd_clean prefetch and remote-deleted checks ==="
sed -n '718,752p;838,843p;880,886p' "$file"

echo
echo "=== fetch/prune sites in this file ==="
rg -n 'git fetch --prune' "$file"

Repository: marcusquinn/aidevops

Length of output: 3417


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".agents/scripts/worktree-helper.sh"

echo "=== worktree_has_changes function ==="
sed -n '335,360p' "$file"

echo
echo "=== full cmd_clean function (830-900) ==="
sed -n '830,900p' "$file"

echo
echo "=== ShellCheck results ==="
shellcheck -x "$file" 2>&1 | head -100

Repository: marcusquinn/aidevops

Length of output: 4240


Fix non-origin remote handling and pipefail-sensitive filtering in cleanup paths.

Two critical automation failures:

  1. Remote mismatch in merged-branch detection: branch_was_pushed() (line 186) checks any remote (refs/remotes/*/$branch), but cmd_clean() only runs git fetch --prune origin (line 722). When a branch exists only on fork/upstream without upstream config, branch_remote() (line 198) defaults to origin, causing the remote-deleted check (line 840) to falsely declare the branch deleted and remove the worktree + delete the local branch. Resolve the remote from the matching tracking refs or skip the remote-deleted heuristic when the remote is unambiguous.

  2. Pipeline failure in worktree_has_changes(): Lines 350–354 filter git status output through a chain of grep -v commands to exclude runtime artifacts. Under set -o pipefail (line 34), if status output contains only excluded patterns (.agents/ files), all grep commands fail on empty input, aborting the script before cleanup completes. Capture the output safely or use a loop-based filter to prevent pipeline failure.

Both violations of "Automation scripts - focus on: Reliability and robustness; proper exit codes; error recovery mechanisms."

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

In @.agents/scripts/worktree-helper.sh around lines 186 - 187, Fix two issues:
(1) In branch_was_pushed / branch_remote handling, resolve the actual remote
from existing tracking refs instead of assuming "origin" — when git for-each-ref
finds refs/remotes/*/$branch use that remote name (e.g., parse
refs/remotes/<remote>/$branch) and pass it into cmd_clean's remote-deleted check
or skip the remote-deleted heuristic if no single unambiguous remote can be
determined; update branch_remote() to prefer an explicit tracking ref before
defaulting to origin. (2) In worktree_has_changes, avoid letting set -o pipefail
kill the script by not chaining greps directly on possibly-empty input: capture
git status output into a variable or a temporary file, then apply the sequence
of exclusions using a loop or conditional filters (e.g., iterate lines and skip
patterns) so that empty/fully-excluded output does not produce a failing
pipeline; ensure the function returns proper zero/non-zero status based on
remaining lines.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker for this PR (PID 52206) was killed by the supervisor pulse after running 5+ hours with 23,515 messages and 0 commits — extreme thrashing with no progress. The PR remains open. Re-dispatching a fresh worker to address the CHANGES_REQUESTED review feedback.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker process killed after 5h14m with 23,600 messages and 0 commits — extreme thrashing with no progress. Re-opening issue #3833 for re-dispatch with a fresh worker.

@marcusquinn marcusquinn added the status:available Task is available for claiming label Mar 8, 2026
@marcusquinn
Copy link
Copy Markdown
Owner

Re-opened for dispatch — worker on PR #3833 was killed after 5h14m with 23,600 messages and 0 commits (extreme thrashing). Fresh worker will be dispatched.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 5h+ with 0 commits (struggle_ratio: 23702). The task is too broad or the review feedback is ambiguous. Flagging issue for re-dispatch with narrower scope. The PR branch bugfix/quality-debt-batch2 remains open — a new worker should read the CodeRabbit CHANGES_REQUESTED comments and address only the specific actionable items.

@marcusquinn
Copy link
Copy Markdown
Owner

Dispatching worker to address CodeRabbit review feedback (CHANGES_REQUESTED). CI failures are systemic — not blocking the code changes.

marcusquinn added a commit that referenced this pull request Mar 8, 2026
- video.md: guard jq assignment with if-! pattern to prevent set -euo pipefail abort
- autogen-helper.sh: fix Python version comparison to accept major > 3 (e.g. 4.x)
- langflow-helper.sh: add nc double-check for port detection parity with localhost-helper
- langflow-helper.sh: replace redundant pgrep+ps pipeline with single pgrep -af
- quickfile-helper.sh: surface mkdir failures instead of masking with || true
- accessibility-audit-helper.sh: add WCAG level to axe tag mapping, redirect stderr to log
- add-skill-helper.sh: include description in categorization, reorder cmd_remove for safety
- deploy-agents-on-merge.sh: guard mkdir/cp/chmod failures for proper error counting
- enhancor-helper.sh: guard curl with if-! pattern for set -e safety
- loop-common.sh: use jq -n for safe JSON state file construction
- quality-cli-manager.sh: preserve multi-flag arguments as array elements
- runway-helper.sh: validate --audio boolean flag at parse time
- worktree-helper.sh: additional quality improvements
@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 90+ minutes with 0 commits (struggle_ratio: 24004). Flagging as orphaned for re-dispatch. The CodeRabbit CHANGES_REQUESTED feedback needs a fresh worker.

@marcusquinn marcusquinn added the status:orphaned Worker died, issue needs recovery label Mar 8, 2026
marcusquinn added a commit that referenced this pull request Mar 8, 2026
branch_remote() previously fell back to 'origin' when no upstream was
configured, even if the branch existed on a different remote (e.g., fork).
This caused false 'remote deleted' detection in cmd_clean when a branch
only existed on a non-origin remote.

Now resolves the actual remote from refs/remotes/*/<branch> before falling
back to origin. Also changed cmd_clean's fetch to --all to prune all
remotes, not just origin.

Addresses CodeRabbit review feedback on PR #3833.
@marcusquinn
Copy link
Copy Markdown
Owner

Response to CodeRabbit Review (CHANGES_REQUESTED at 06:19)

All 5 items from the latest review have been verified against the current code:

1. audit-task-creator-helper.sh — pr_number migration

Already fixed. Lines 197-201 of ensure_task_db() already contain the pr_number column migration (added in commit c6f0c35).

2. loop-common.sh — exit code reporting

Already fixed. loop_emergency_push() properly returns non-zero on all push failures. loop_context_guard() captures the result with loop_emergency_push || push_result=$? and returns "$push_result". loop_run_external() checks the guard return value (added in commit 98be7ce).

3. runway-helper.sh — gen4_aleph model for video_to_video

Already fixed. Lines 212-216 override the model to gen4_aleph when --video is used (added in commit c6f0c35).

4. batch.sh — max_load_factor validation

Already fixed. Line 298 already includes max_load_factor in the validation loop (added in commit 98be7ce).

5. worktree-helper.sh — remote resolution and pipefail

Now fully fixed in commit be2dcb0:

  • branch_remote() now resolves the actual remote from refs/remotes/*/\<branch> tracking refs before falling back to origin, preventing false 'remote deleted' detection in multi-remote setups
  • cmd_clean() fetch changed from git fetch --prune origin to git fetch --prune --all to prune all remotes
  • worktree_has_changes() pipefail issue was already handled (grep chain wrapped in { ... } || true)

The analysis chains in comments 1-4 ran against pre-fix code state.

@github-actions github-actions Bot added the bug Auto-created from TODO.md tag label Mar 8, 2026
@marcusquinn marcusquinn added the external-contributor PR from external contributor, requires maintainer review label Mar 8, 2026
@marcusquinn marcusquinn dismissed coderabbitai[bot]’s stale review March 8, 2026 10:50

All review items addressed in commits 50946b3 through f46eba9. Dismissing stale CHANGES_REQUESTED to trigger re-review.

@marcusquinn
Copy link
Copy Markdown
Owner

Worker killed after 6h45m with 0 commits (struggle_ratio: 24571). This worker was thrashing — sending messages but producing no commits. Re-filing the issue for re-dispatch with a fresh worker.

marcusquinn pushed a commit that referenced this pull request Mar 8, 2026
- runway-helper.sh: stricter --ref tag validation (alphanumeric pattern)
- accessibility-audit-helper.sh: HTTP status check on WebAIM API response
- enhancor-helper.sh: handle curl failure, fix stderr routing
- loop-common.sh: use jq for safe JSON construction in context guard
- markdown-formatter.sh: portable hash function (shasum on macOS)
- quality-cli-manager.sh: add qlty case to dispatcher, safe QLTY_ORG deref
- quickfile-helper.sh: return non-zero on partial batch failure
- secret-helper.sh: printf instead of echo for safe value piping
- tool-version-check.sh: separate UNKNOWN_COUNT from INSTALLED_COUNT
- worktree-helper.sh: for-each-ref instead of show-ref for glob patterns
- deploy-agents-on-merge.sh: detect remote, clean stale files in tar fallback
marcusquinn added a commit that referenced this pull request Mar 8, 2026
Validates that the WebAIM API response is valid JSON before passing
to jq, preventing HTML error pages from being silently treated as
successful audit results.

Addresses CodeRabbit review feedback on PR #3833.
marcusquinn added a commit that referenced this pull request Mar 8, 2026
Under set -euo pipefail, bare response=$(api_request ...) aborts the
script immediately when api_request returns non-zero, preventing any
error recovery by the caller. Wrap all 7 call sites with
if ! response=$(api_request ...); then return 1; fi pattern.

Addresses CodeRabbit review feedback on PR #3833.
marcusquinn added a commit that referenced this pull request Mar 8, 2026
- video.md: guard jq assignment with if-! pattern to prevent set -euo pipefail abort
- autogen-helper.sh: fix Python version comparison to accept major > 3 (e.g. 4.x)
- langflow-helper.sh: add nc double-check for port detection parity with localhost-helper
- langflow-helper.sh: replace redundant pgrep+ps pipeline with single pgrep -af
- quickfile-helper.sh: surface mkdir failures instead of masking with || true
- accessibility-audit-helper.sh: add WCAG level to axe tag mapping, redirect stderr to log
- add-skill-helper.sh: include description in categorization, reorder cmd_remove for safety
- deploy-agents-on-merge.sh: guard mkdir/cp/chmod failures for proper error counting
- enhancor-helper.sh: guard curl with if-! pattern for set -e safety
- loop-common.sh: use jq -n for safe JSON state file construction
- quality-cli-manager.sh: preserve multi-flag arguments as array elements
- runway-helper.sh: validate --audio boolean flag at parse time
- worktree-helper.sh: additional quality improvements
marcusquinn added a commit that referenced this pull request Mar 8, 2026
branch_remote() previously fell back to 'origin' when no upstream was
configured, even if the branch existed on a different remote (e.g., fork).
This caused false 'remote deleted' detection in cmd_clean when a branch
only existed on a non-origin remote.

Now resolves the actual remote from refs/remotes/*/<branch> before falling
back to origin. Also changed cmd_clean's fetch to --all to prune all
remotes, not just origin.

Addresses CodeRabbit review feedback on PR #3833.
@marcusquinn
Copy link
Copy Markdown
Owner

Closing — this PR has merge conflicts and touches too many files (blast radius issue, see t1422 / GH#3955). The underlying fixes will be re-created as smaller PRs (max 5 files each) to prevent conflict cascades.

Root cause: quality-debt batch PRs touching 10-69 files each created a conflict cascade where each merge invalidated the next PR's base. New rules cap quality-debt PRs at 5 files max and enforce serial merge ordering.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Auto-created from TODO.md tag external-contributor PR from external contributor, requires maintainer review status:available Task is available for claiming status:orphaned Worker died, issue needs recovery

Projects

None yet

2 participants