Skip to content

fix: register blocked tasks in DB during auto-pickup#2239

Merged
marcusquinn merged 1 commit intomainfrom
feature/auto-pickup-register-blocked
Feb 24, 2026
Merged

fix: register blocked tasks in DB during auto-pickup#2239
marcusquinn merged 1 commit intomainfrom
feature/auto-pickup-register-blocked

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Feb 24, 2026

Summary

  • Problem: cmd_auto_pickup() skipped blocked tasks entirely — tasks with blocked-by: dependencies or -needed tags were never registered in the supervisor DB, making them invisible until a subsequent auto-pickup run after blockers resolved
  • Fix: Add _register_blocked_task() helper that creates tasks via cmd_add and immediately sets status='blocked' with the blocker reason in the error field
  • Lifecycle completion: Update auto_unblock_resolved_tasks() in todo-sync.sh to transition DB status from blockedqueued when all blockers resolve, enabling immediate dispatch

Changes

cron.sh

  • New _register_blocked_task() function: registers task in DB as blocked (handles both new and existing tasks)
  • Strategy 1 (#auto-dispatch tagged): register blocked tasks instead of continue
  • Strategy 2 (Dispatch Queue section): register blocked tasks instead of continue
  • Strategy 4 (subtask scanning): register blocked tasks instead of continue
  • -needed blocker tags also registered as blocked (Strategies 1 & 2)

todo-sync.sh

  • auto_unblock_resolved_tasks(): when all blockers resolve, also transition DB status from blocked to queued (previously only removed blocked-by: from TODO.md)

Impact

Blocked tasks (e.g., a managed private repo t003.2-t003.5, t009.2-t009.4) will now be registered in the DB immediately on first scan. When their blockers complete, auto_unblock_resolved_tasks transitions them to queued and dispatch picks them up in the same pulse — no waiting for the next auto-pickup cycle.

Summary by CodeRabbit

Release Notes

  • Chores
    • Improved internal task management to track blocked tasks and automatically resume processing once blockers are resolved.

Previously, cmd_auto_pickup() skipped blocked tasks entirely (blocked-by:
dependencies and -needed tags), making them invisible to the supervisor.
Tasks with unresolved blockers were never registered in the DB, so the
supervisor couldn't dispatch them when blockers resolved — they had to
wait for a subsequent auto-pickup run.

Changes:
- Add _register_blocked_task() helper in cron.sh that creates a task via
  cmd_add and immediately sets status='blocked' with blocker reason
- At all 3 strategy locations in cmd_auto_pickup(), register blocked
  tasks in DB instead of skipping (strategies 1, 2, and 4)
- Also register -needed blocker tag tasks as blocked (strategies 1, 2)
- Update auto_unblock_resolved_tasks() in todo-sync.sh to transition
  DB status from 'blocked' to 'queued' when all blockers resolve

This creates a complete lifecycle: blocked tasks are registered on first
scan, then auto-dispatched the instant their blockers complete.
@gemini-code-assist
Copy link

Summary of Changes

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

This pull request significantly improves the handling of blocked tasks within the supervisor system. By ensuring that tasks with dependencies or specific blocking tags are registered in the database immediately, even when blocked, the system gains better visibility and responsiveness. Once blockers are resolved, these tasks are automatically transitioned to a 'queued' state, allowing for their prompt dispatch and eliminating delays previously caused by waiting for subsequent auto-pickup runs.

Highlights

  • Problem Addressed: Previously, cmd_auto_pickup() in cron.sh skipped tasks with blocked-by: dependencies or -needed tags, preventing them from being registered in the supervisor database until their blockers were resolved.
  • New Functionality: A new helper function, _register_blocked_task(), was added to cron.sh. This function registers blocked tasks in the supervisor database by creating them via cmd_add (if not already tracked) and immediately setting their status to 'blocked' with the blocker reason in the error field.
  • Enhanced Task Lifecycle: The auto_unblock_resolved_tasks() function in todo-sync.sh was updated to transition the database status of tasks from 'blocked' to 'queued' once all their blockers are resolved. This ensures immediate dispatch without waiting for the next auto-pickup cycle.
  • Integration with Auto-Pickup Strategies: The cmd_auto_pickup() function in cron.sh was modified across multiple strategies (auto-dispatch tagged, Dispatch Queue section, subtask scanning) to utilize _register_blocked_task() for tasks that are blocked by dependencies or -needed tags, ensuring they are registered in the DB instead of being skipped.
Changelog
  • .agents/scripts/supervisor/cron.sh
    • Added a new shell function _register_blocked_task to manage the registration and status update of blocked tasks in the supervisor database.
    • Modified cmd_auto_pickup to call _register_blocked_task when encountering tasks blocked by blocked-by: dependencies, ensuring they are registered instead of skipped.
    • Modified cmd_auto_pickup to call _register_blocked_task for tasks identified with -needed blocker tags.
    • Modified cmd_auto_pickup to call _register_blocked_task for blocked subtasks during subtask scanning.
  • .agents/scripts/supervisor/todo-sync.sh
    • Updated auto_unblock_resolved_tasks to transition the database status of unblocked tasks from 'blocked' to 'queued', facilitating immediate dispatch.
Using Gemini Code Assist

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

Invoking Gemini

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

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

Customization

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

Limitations & Feedback

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

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

Footnotes

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Walkthrough

These changes add database-backed visibility for blocked tasks in the supervisor system. Instead of implicitly skipping tasks with unresolved blockers, they are now explicitly registered in the supervisor database as blocked with detailed blocker reasons. When blockers resolve, tasks automatically transition to queued state in the database, enabling immediate dispatch.

Changes

Cohort / File(s) Summary
Task Blocking Registration
.agents/scripts/supervisor/cron.sh
Introduces _register_blocked_task() helper function to ensure blocked tasks are persisted in supervisor DB with blocker_reason recorded. Integrates this function across cmd_auto_pickup, human-action-required blocker branches, Dispatch Queue section, and Strategy 1/2/3/4 flows, replacing previous implicit skipping with explicit DB-backed blocking.
Task Unblocking Automation
.agents/scripts/supervisor/todo-sync.sh
Enhances auto_unblock_resolved_tasks() to check supervisor DB when blockers are resolved. Updates DB status from blocked to queued, clears error field, and records timestamp transition when SUPERVISOR_DB is set.

Sequence Diagram

sequenceDiagram
    participant Cron as Cron Script
    participant DB as Supervisor DB
    participant TODO as TODO.md
    
    rect rgba(100, 150, 200, 0.5)
    Note over Cron,DB: Task Blocking Phase
    Cron->>Cron: Detect unresolved blocker
    Cron->>DB: Check if task exists in DB
    alt Task exists & non-terminal
        DB-->>Cron: Task found
        Cron->>DB: UPDATE status=blocked, error=blocker_reason
    else Task not in DB
        DB-->>Cron: Task not found
        Cron->>DB: INSERT task with status=blocked
    end
    end
    
    rect rgba(200, 150, 100, 0.5)
    Note over Cron,TODO: Task Unblocking Phase
    Cron->>TODO: Detect blocker resolved
    Cron->>TODO: Remove blocked-by marker
    Cron->>DB: Query task status
    alt Status is blocked
        DB-->>Cron: blocked
        Cron->>DB: UPDATE status=queued, clear error, update timestamp
        DB-->>Cron: Transition logged
    end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • marcusquinn/aidevops#2015 — Modifies supervisor todo-sync auto_unblock_resolved_tasks flow and DB state management for queued transitions.
  • marcusquinn/aidevops#1551 — Reads supervisor DB blocked reason field to post GitHub comments; directly complementary to blocker_reason recording in this PR.
  • marcusquinn/aidevops#1616 — Originally introduced blocked-by checks and skipping in cron.sh cmd_auto_pickup; these changes update those same code paths to register tasks in DB instead.

Poem

🔗 Tasks once hidden in the skip,
Now bloom in DB, never slip,
Blockers melt, they autorise,
From blocked to queued—no manual tries! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: registering blocked tasks in the database during auto-pickup, which is the core fix described in the PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/auto-pickup-register-blocked

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

🔍 Code Quality Report

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

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

�[0;34m[INFO]�[0m Recent monitoring activity:
Tue Feb 24 21:16:54 UTC 2026: Code review monitoring started
Tue Feb 24 21:16:54 UTC 2026: SonarCloud - Bugs: 0, Vulnerabilities: 0, Code Smells: 58

📈 Current Quality Metrics

  • BUGS: 0
  • CODE SMELLS: 58
  • VULNERABILITIES: 0

Generated on: Tue Feb 24 21:16:57 UTC 2026


Generated by AI DevOps Framework Code Review Monitoring

@sonarqubecloud
Copy link

Copy link

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

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable fix for handling blocked tasks in cmd_auto_pickup(). Instead of skipping them, they are now registered in the supervisor database with a 'blocked' status. This ensures they are visible and can be dispatched immediately once their blockers are resolved. The changes in cron.sh and todo-sync.sh are logical and well-implemented to achieve this. My review focuses on improving error handling and consistency. Specifically, I've suggested removing stderr suppression (2>/dev/null) in several places to align with repository guidelines, which will make debugging easier. I also pointed out an inconsistency in a new function's return logic compared to its documentation and suggested a fix.

Comment on lines +470 to +498
_register_blocked_task() {
local task_id="$1"
local repo="$2"
local blocker_reason="$3"

# Check if already in supervisor DB
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)

if [[ -n "$existing" ]]; then
# Already tracked — update to blocked if not in a terminal state
if [[ "$existing" == "complete" || "$existing" == "cancelled" || "$existing" == "verified" ]]; then
return 0
fi
if [[ "$existing" != "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: updated to blocked (was: $existing, blocked by: $blocker_reason)"
fi
return 0
fi

# Not in DB — add it first, then mark blocked
if cmd_add "$task_id" --repo "$repo"; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: registered as blocked (blocked by: $blocker_reason)"
fi

return 0
}

Choose a reason for hiding this comment

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

medium

This new function has a couple of areas for improvement:

  1. Incorrect failure handling: The function documentation at line 468 states it returns 1 on failure, but the current implementation always returns 0. If cmd_add fails, the function silently continues and returns success, which can hide problems and makes the function's behavior inconsistent with its documentation.
  2. Error suppression: The db calls use 2>/dev/null to suppress stderr. According to the repository's general rules, this should be avoided to ensure that underlying issues like database corruption or syntax errors are visible for debugging. The || true is sufficient to prevent script exit with set -e.

The suggested change below addresses both points by correctly handling the failure of cmd_add and removing the stderr suppression.

_register_blocked_task() {
	local task_id="$1"
	local repo="$2"
	local blocker_reason="$3"

	# Check if already in supervisor DB
	local existing
	existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" || true)

	if [[ -n "$existing" ]]; then
		# Already tracked — update to blocked if not in a terminal state
		if [[ "$existing" == "complete" || "$existing" == "cancelled" || "$existing" == "verified" ]]; then
			return 0
		fi
		if [[ "$existing" != "blocked" ]]; then
			db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" || true
			log_info "  $task_id: updated to blocked (was: $existing, blocked by: $blocker_reason)"
		fi
		return 0
	fi

	# Not in DB — add it first, then mark blocked
	if ! cmd_add "$task_id" --repo "$repo"; then
		log_error "  $task_id: failed to add to supervisor DB."
		return 1
	fi

	db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" || true
	log_info "  $task_id: registered as blocked (blocked by: $blocker_reason)"

	return 0
}
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

Comment on lines +1263 to +1271
# Transition DB status from blocked to queued so dispatch picks it up
if [[ -n "${SUPERVISOR_DB:-}" && -f "${SUPERVISOR_DB}" ]]; then
local db_status
db_status=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")' LIMIT 1;" 2>/dev/null || echo "")
if [[ "$db_status" == "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='queued', error=NULL, updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " auto-unblock: $task_id — DB status transitioned from blocked to queued"
fi
fi

Choose a reason for hiding this comment

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

medium

The db calls on lines 1266 and 1268 use 2>/dev/null to suppress stderr. According to the repository's general rules, this should be avoided to ensure that underlying issues like database corruption or syntax errors are visible for debugging. The || echo "" and || true constructs are sufficient to handle expected failures without exiting the script.

Suggested change
# Transition DB status from blocked to queued so dispatch picks it up
if [[ -n "${SUPERVISOR_DB:-}" && -f "${SUPERVISOR_DB}" ]]; then
local db_status
db_status=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")' LIMIT 1;" 2>/dev/null || echo "")
if [[ "$db_status" == "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='queued', error=NULL, updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " auto-unblock: $task_id — DB status transitioned from blocked to queued"
fi
fi
# Transition DB status from blocked to queued so dispatch picks it up
if [[ -n "${SUPERVISOR_DB:-}" && -f "${SUPERVISOR_DB}" ]]; then
local db_status
db_status=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")' LIMIT 1;" || echo "")
if [[ "$db_status" == "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='queued', error=NULL, updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" || true
log_info " auto-unblock: $task_id — DB status transitioned from blocked to queued"
fi
fi
References
  1. Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.

@marcusquinn marcusquinn merged commit 12bd3ec into main Feb 24, 2026
13 of 14 checks passed
@marcusquinn marcusquinn deleted the feature/auto-pickup-register-blocked branch February 24, 2026 21:19
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
.agents/scripts/supervisor/cron.sh (1)

710-725: ⚠️ Potential issue | 🟠 Major

Address ShellCheck warnings in cron.sh before merging.

ShellCheck found 4 info-level violations (SC2016) in .agents/scripts/supervisor/cron.sh at lines 1199–1203. These echo statements use single quotes where expressions should expand; use double quotes instead:

Line 1199: echo "  children=$(pgrep -P $$ 2>/dev/null || true)"
Line 1200: echo "  if [[ -n "$children" ]]; then"
Line 1201: echo "    kill -TERM $children 2>/dev/null || true"
Line 1203: echo "    kill -9 $children 2>/dev/null || true"

.agents/scripts/supervisor/todo-sync.sh passes ShellCheck cleanly.

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

In @.agents/scripts/supervisor/cron.sh around lines 710 - 725, ShellCheck
flagged SC2016: several echo statements emit literal dollar-sign expressions
because they use single quotes; locate the echo lines that print the shell
snippet (the ones emitting children=$(pgrep -P $$ ...), the if [[ -n "$children"
]] line, and the kill lines) and change their quotes to double quotes so
variables expand (e.g., echo "  children=$(pgrep -P $$ 2>/dev/null || true)"),
making sure to escape any inner double quotes or dollar signs as needed; re-run
ShellCheck to confirm the SC2016 warnings are resolved.
🧹 Nitpick comments (1)
.agents/scripts/supervisor/todo-sync.sh (1)

1263-1271: Prefer a state-log-aware transition for blocked → queued.

Direct SQL updates bypass state_log/transition hooks used elsewhere. Consider using cmd_transition or at least inserting a state_log entry for audit consistency.

📝 Suggested state_log addition
 				if [[ "$db_status" == "blocked" ]]; then
-					db "$SUPERVISOR_DB" "UPDATE tasks SET status='queued', error=NULL, updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
+					local escaped_task_id
+					escaped_task_id=$(sql_escape "$task_id")
+					db "$SUPERVISOR_DB" "UPDATE tasks SET status='queued', error=NULL, updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='${escaped_task_id}';" 2>/dev/null || true
+					db "$SUPERVISOR_DB" "INSERT INTO state_log (task_id, from_state, to_state, timestamp, reason)
+						VALUES ('${escaped_task_id}', 'blocked', 'queued',
+							strftime('%Y-%m-%dT%H:%M:%SZ','now'),
+							'auto_unblock_resolved_tasks: blockers resolved');" 2>/dev/null || true
 					log_info "  auto-unblock: $task_id — DB status transitioned from blocked to queued"
 				fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor/todo-sync.sh around lines 1263 - 1271, The
current auto-unblock block uses a direct SQL UPDATE via db "$SUPERVISOR_DB"
which bypasses the application's state transition hooks and state_log/audit;
replace the raw UPDATE with the existing transition mechanism (call
cmd_transition or the helper that records state_log entries) so transitions for
task_id go through the same code path that appends to state_log and triggers
hooks, or if cmd_transition is not available here, after the UPDATE insert a
state_log row for task_id documenting the blocked→queued change and include
error=NULL and updated_at timestamp; locate the block around db "$SUPERVISOR_DB"
"SELECT status..." and the UPDATE invocation and switch to calling
cmd_transition (or adding the state_log insert) and ensure sql_escape "$task_id"
is used for the id and any command failures are handled similarly to the current
2>/dev/null || true behavior.
🤖 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/supervisor/cron.sh:
- Around line 454-498: In _register_blocked_task, blocker_reason is interpolated
directly into SQL UPDATE statements (the two db calls that set error='Blocked
by: ${blocker_reason}'), allowing quotes or injection; escape the full error
string via sql_escape before embedding it in the SQL (e.g., compute an
escaped_error or call sql_escape on "Blocked by: ${blocker_reason}" and use that
in both UPDATE queries) so both UPDATEs use the escaped value.

---

Outside diff comments:
In @.agents/scripts/supervisor/cron.sh:
- Around line 710-725: ShellCheck flagged SC2016: several echo statements emit
literal dollar-sign expressions because they use single quotes; locate the echo
lines that print the shell snippet (the ones emitting children=$(pgrep -P $$
...), the if [[ -n "$children" ]] line, and the kill lines) and change their
quotes to double quotes so variables expand (e.g., echo "  children=$(pgrep -P
$$ 2>/dev/null || true)"), making sure to escape any inner double quotes or
dollar signs as needed; re-run ShellCheck to confirm the SC2016 warnings are
resolved.

---

Nitpick comments:
In @.agents/scripts/supervisor/todo-sync.sh:
- Around line 1263-1271: The current auto-unblock block uses a direct SQL UPDATE
via db "$SUPERVISOR_DB" which bypasses the application's state transition hooks
and state_log/audit; replace the raw UPDATE with the existing transition
mechanism (call cmd_transition or the helper that records state_log entries) so
transitions for task_id go through the same code path that appends to state_log
and triggers hooks, or if cmd_transition is not available here, after the UPDATE
insert a state_log row for task_id documenting the blocked→queued change and
include error=NULL and updated_at timestamp; locate the block around db
"$SUPERVISOR_DB" "SELECT status..." and the UPDATE invocation and switch to
calling cmd_transition (or adding the state_log insert) and ensure sql_escape
"$task_id" is used for the id and any command failures are handled similarly to
the current 2>/dev/null || true behavior.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2144545 and 3a54f55.

📒 Files selected for processing (2)
  • .agents/scripts/supervisor/cron.sh
  • .agents/scripts/supervisor/todo-sync.sh

Comment on lines +454 to +498
#######################################
# Register a task as blocked in the supervisor DB.
# Creates the task via cmd_add if not already tracked, then
# sets status='blocked' with the blocker reason in the error field.
#
# This ensures blocked tasks are visible to the supervisor and
# will be dispatched immediately when auto_unblock_resolved_tasks
# transitions them to 'queued'.
#
# Args:
# $1 - task_id (e.g. t003.2)
# $2 - repo path
# $3 - blocker reason (e.g. "t003.1" or "hosting-needed")
#
# Returns: 0 on success, 1 on failure
#######################################
_register_blocked_task() {
local task_id="$1"
local repo="$2"
local blocker_reason="$3"

# Check if already in supervisor DB
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)

if [[ -n "$existing" ]]; then
# Already tracked — update to blocked if not in a terminal state
if [[ "$existing" == "complete" || "$existing" == "cancelled" || "$existing" == "verified" ]]; then
return 0
fi
if [[ "$existing" != "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: updated to blocked (was: $existing, blocked by: $blocker_reason)"
fi
return 0
fi

# Not in DB — add it first, then mark blocked
if cmd_add "$task_id" --repo "$repo"; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: registered as blocked (blocked by: $blocker_reason)"
fi

return 0
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Escape blocker_reason before SQL updates.

blocker_reason flows from TODO.md into SQL string literals. Since the regex allows any non‑space chars, a single quote can break the query or be abused. Please escape the full error string before persisting it.

🔧 Proposed fix
 _register_blocked_task() {
 	local task_id="$1"
 	local repo="$2"
 	local blocker_reason="$3"
+	local escaped_error
+	escaped_error=$(sql_escape "Blocked by: ${blocker_reason}")
@@
-			db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
+			db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='${escaped_error}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
@@
-		db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
+		db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='${escaped_error}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#######################################
# Register a task as blocked in the supervisor DB.
# Creates the task via cmd_add if not already tracked, then
# sets status='blocked' with the blocker reason in the error field.
#
# This ensures blocked tasks are visible to the supervisor and
# will be dispatched immediately when auto_unblock_resolved_tasks
# transitions them to 'queued'.
#
# Args:
# $1 - task_id (e.g. t003.2)
# $2 - repo path
# $3 - blocker reason (e.g. "t003.1" or "hosting-needed")
#
# Returns: 0 on success, 1 on failure
#######################################
_register_blocked_task() {
local task_id="$1"
local repo="$2"
local blocker_reason="$3"
# Check if already in supervisor DB
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)
if [[ -n "$existing" ]]; then
# Already tracked — update to blocked if not in a terminal state
if [[ "$existing" == "complete" || "$existing" == "cancelled" || "$existing" == "verified" ]]; then
return 0
fi
if [[ "$existing" != "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: updated to blocked (was: $existing, blocked by: $blocker_reason)"
fi
return 0
fi
# Not in DB — add it first, then mark blocked
if cmd_add "$task_id" --repo "$repo"; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='Blocked by: ${blocker_reason}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: registered as blocked (blocked by: $blocker_reason)"
fi
return 0
}
#######################################
# Register a task as blocked in the supervisor DB.
# Creates the task via cmd_add if not already tracked, then
# sets status='blocked' with the blocker reason in the error field.
#
# This ensures blocked tasks are visible to the supervisor and
# will be dispatched immediately when auto_unblock_resolved_tasks
# transitions them to 'queued'.
#
# Args:
# $1 - task_id (e.g. t003.2)
# $2 - repo path
# $3 - blocker reason (e.g. "t003.1" or "hosting-needed")
#
# Returns: 0 on success, 1 on failure
#######################################
_register_blocked_task() {
local task_id="$1"
local repo="$2"
local blocker_reason="$3"
local escaped_error
escaped_error=$(sql_escape "Blocked by: ${blocker_reason}")
# Check if already in supervisor DB
local existing
existing=$(db "$SUPERVISOR_DB" "SELECT status FROM tasks WHERE id = '$(sql_escape "$task_id")';" 2>/dev/null || true)
if [[ -n "$existing" ]]; then
# Already tracked — update to blocked if not in a terminal state
if [[ "$existing" == "complete" || "$existing" == "cancelled" || "$existing" == "verified" ]]; then
return 0
fi
if [[ "$existing" != "blocked" ]]; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='${escaped_error}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: updated to blocked (was: $existing, blocked by: $blocker_reason)"
fi
return 0
fi
# Not in DB — add it first, then mark blocked
if cmd_add "$task_id" --repo "$repo"; then
db "$SUPERVISOR_DB" "UPDATE tasks SET status='blocked', error='${escaped_error}', updated_at=strftime('%Y-%m-%dT%H:%M:%SZ','now') WHERE id='$(sql_escape "$task_id")';" 2>/dev/null || true
log_info " $task_id: registered as blocked (blocked by: $blocker_reason)"
fi
return 0
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor/cron.sh around lines 454 - 498, In
_register_blocked_task, blocker_reason is interpolated directly into SQL UPDATE
statements (the two db calls that set error='Blocked by: ${blocker_reason}'),
allowing quotes or injection; escape the full error string via sql_escape before
embedding it in the SQL (e.g., compute an escaped_error or call sql_escape on
"Blocked by: ${blocker_reason}" and use that in both UPDATE queries) so both
UPDATEs use the escaped value.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant