From 3a54f556dfde0429aff1425030a39b3d13b0154d Mon Sep 17 00:00:00 2001 From: marcusquinn <6428977+marcusquinn@users.noreply.github.com> Date: Tue, 24 Feb 2026 21:16:03 +0000 Subject: [PATCH] fix: register blocked tasks in DB during auto-pickup instead of skipping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- .agents/scripts/supervisor/cron.sh | 64 ++++++++++++++++++++++++- .agents/scripts/supervisor/todo-sync.sh | 10 ++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/.agents/scripts/supervisor/cron.sh b/.agents/scripts/supervisor/cron.sh index 49937cc25..6c484654e 100755 --- a/.agents/scripts/supervisor/cron.sh +++ b/.agents/scripts/supervisor/cron.sh @@ -451,6 +451,52 @@ _check_and_skip_if_blocked() { return 1 } +####################################### +# 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 +} + ####################################### # t1239: Cross-repo misregistration guard for auto-pickup. # Returns 0 (skip) if the task_id is already registered in the DB @@ -560,8 +606,15 @@ cmd_auto_pickup() { continue fi + # Register blocked tasks in DB instead of skipping entirely. + # This makes blocked tasks visible to the supervisor so they + # can be dispatched immediately when blockers resolve. + # Skip tasks with unresolved blocked-by dependencies (t1085.4) if _check_and_skip_if_blocked "$line" "$task_id" "$todo_file"; then + local unresolved + unresolved=$(is_task_blocked "$line" "$todo_file" || true) + _register_blocked_task "$task_id" "$repo" "$unresolved" continue fi @@ -570,6 +623,7 @@ cmd_auto_pickup() { local blocker_tag blocker_tag=$(echo "$line" | grep -oE '(account|hosting|login|api-key|clarification|resources|payment|approval|decision|design|content|dns|domain|testing)-needed' | head -1) log_info " $task_id: blocked by $blocker_tag (human action required) — skipping auto-pickup" + _register_blocked_task "$task_id" "$repo" "$blocker_tag" continue fi @@ -653,8 +707,12 @@ cmd_auto_pickup() { continue fi + # Register blocked tasks in DB instead of skipping entirely. # Skip tasks with unresolved blocked-by dependencies (t1085.4) if _check_and_skip_if_blocked "$line" "$task_id" "$todo_file"; then + local unresolved + unresolved=$(is_task_blocked "$line" "$todo_file" || true) + _register_blocked_task "$task_id" "$repo" "$unresolved" continue fi @@ -663,6 +721,7 @@ cmd_auto_pickup() { local blocker_tag blocker_tag=$(echo "$line" | grep -oE '(account|hosting|login|api-key|clarification|resources|payment|approval|decision|design|content|dns|domain|testing)-needed' | head -1) log_info " $task_id: blocked by $blocker_tag (human action required) — skipping auto-pickup" + _register_blocked_task "$task_id" "$repo" "$blocker_tag" continue fi @@ -816,8 +875,11 @@ cmd_auto_pickup() { continue fi - # Skip tasks with unresolved blocked-by dependencies + # Register blocked subtasks in DB instead of skipping entirely if _check_and_skip_if_blocked "$sub_line" "$sub_id" "$todo_file"; then + local unresolved + unresolved=$(is_task_blocked "$sub_line" "$todo_file" || true) + _register_blocked_task "$sub_id" "$repo" "$unresolved" continue fi diff --git a/.agents/scripts/supervisor/todo-sync.sh b/.agents/scripts/supervisor/todo-sync.sh index 55c253eea..bacc69aad 100755 --- a/.agents/scripts/supervisor/todo-sync.sh +++ b/.agents/scripts/supervisor/todo-sync.sh @@ -1260,6 +1260,16 @@ auto_unblock_resolved_tasks() { sed_inplace "${line_num}s/[[:space:]]*$//" "$todo_file" 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;" 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 + unblocked_count=$((unblocked_count + 1)) if [[ -n "$unblocked_ids" ]]; then unblocked_ids="${unblocked_ids}, ${task_id}"