Skip to content

t1319: Extract auto-pickup decision logic to AI module#2228

Closed
marcusquinn wants to merge 1 commit intomainfrom
feature/t1319
Closed

t1319: Extract auto-pickup decision logic to AI module#2228
marcusquinn wants to merge 1 commit intomainfrom
feature/t1319

Conversation

@marcusquinn
Copy link
Owner

@marcusquinn marcusquinn commented Feb 24, 2026

Summary

Migrates ~460 lines of inline dispatch gating, blocked-by chain checking, and task selection decisions from cmd_auto_pickup() in cron.sh to a new ai-pickup-decisions.sh module.

Architecture

GATHER (shell) → JUDGE (AI) → RETURN (shell) with deterministic fallback.

What moved to AI (ai-pickup-decisions.sh):

  • Dispatch gating decisions (should this task be picked up?)
  • Priority/ordering among eligible tasks
  • Blocker tag interpretation (which -needed tags block?)
  • Subtask inheritance decisions
  • Batch grouping strategy

What stays in shell:

  • TODO.md parsing (grep for candidates) — data gathering
  • DB queries (task status, cross-repo checks) — data gathering
  • is_task_blocked() / _check_and_skip_if_blocked() — data queries
  • _is_cross_repo_misregistration() — data query
  • cmd_add / cmd_batch execution — side effects
  • dispatch_decomposition_worker() — execution
  • Scheduler install/uninstall (cmd_cron, cmd_watch) — unchanged

Feature flag

AI_PICKUP_DECISIONS_ENABLED (default: true). Set to false for deterministic-only mode.

Model

sonnet — fast and cheap enough for structured classification tasks.

Files Changed

File Change
.agents/scripts/supervisor/ai-pickup-decisions.sh NEW — AI pickup decision module
.agents/scripts/supervisor/cron.sh cmd_auto_pickup() reduced to thin wrapper
.agents/scripts/supervisor-helper.sh Source new module
.agents/aidevops/supervisor-module-map.md Updated module map

Verification

  • ShellCheck: zero violations on all modified .sh files
  • All 4 original strategies preserved (tagged, dispatch queue, plan decomposition, subtask inheritance)
  • Strategy 5 (batch cleanup) preserved as pure shell
  • Auto-batch logic preserved as pure shell
  • Deterministic fallback replicates exact original behavior

Ref #2215

Summary by CodeRabbit

  • New Features

    • Enhanced auto-pickup command with AI-driven task selection that evaluates candidates across multiple discovery strategies with intelligent decision-making and deterministic fallback when AI is unavailable.
  • Refactor

    • Restructured auto-pickup implementation by delegating decision logic to external module for improved modularity.
  • Chores

    • Updated auto-pickup command documentation.

Migrates ~460 lines of inline dispatch gating, blocked-by chain checking,
and task selection decisions from cmd_auto_pickup() in cron.sh to a new
ai-pickup-decisions.sh module.

Architecture: GATHER (shell) → JUDGE (AI) → RETURN (shell)
- Shell gathers candidate tasks from TODO.md (4 strategies preserved)
- Shell gathers DB state, blocker info, metadata
- AI receives structured context and decides which tasks to pick up
- Shell executes the pickup actions (cmd_add, cmd_batch, decomposition)
- Falls back to deterministic logic if AI is unavailable

What stays in shell: TODO.md parsing, DB queries, is_task_blocked(),
_is_cross_repo_misregistration(), cmd_add/cmd_batch execution,
dispatch_decomposition_worker(), scheduler install/uninstall.

What moves to AI: dispatch gating decisions, priority/ordering,
blocker tag interpretation, subtask inheritance decisions, batch strategy.

Feature flag: AI_PICKUP_DECISIONS_ENABLED (default: true)
Model: sonnet (fast, cheap enough for structured classification)
@marcusquinn marcusquinn marked this pull request as ready for review February 24, 2026 18:06
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 24, 2026

Walkthrough

This PR introduces an AI-driven auto-pickup decision pipeline by creating a new ai-pickup-decisions.sh module implementing a GATHER→JUDGE→EXECUTE workflow with deterministic fallback, sourcing this module in supervisor-helper.sh, refactoring cmd_auto_pickup in cron.sh to delegate to ai_auto_pickup, and updating documentation accordingly.

Changes

Cohort / File(s) Summary
Documentation Update
.agents/aidevops/supervisor-module-map.md
Updated description of cmd_auto_pickup to reflect delegation to ai_auto_pickup(t1319) instead of inline TODO.md scanning.
Module Loading
.agents/scripts/supervisor-helper.sh
Added sourcing of the new ai-pickup-decisions.sh module to extend supervisor capabilities.
AI Pickup Decisions Module
.agents/scripts/supervisor/ai-pickup-decisions.sh
New comprehensive module implementing AI-driven task pickup with GATHER (candidate collection from TODO.md, PLANS.md, dispatch queue), JUDGE (AI evaluation with deterministic fallback), and EXECUTE (decision application with inheritance and decomposition) phases. Includes configuration flags, audit logging, and robust error handling.
Command Refactoring
.agents/scripts/supervisor/cron.sh
Replaced inline multi-strategy filtering logic (446 lines) in cmd_auto_pickup with delegation to ai_auto_pickup, moving decision complexity to the new dedicated module while retaining scheduler and dispatch responsibilities.

Sequence Diagram(s)

sequenceDiagram
    participant Scheduler as Scheduler
    participant cmd_auto_pickup as cmd_auto_pickup
    participant ai_auto_pickup as ai_auto_pickup
    participant Gatherer as GATHER Phase
    participant Judge as JUDGE Phase
    participant Executor as EXECUTE Phase
    participant AI as AI Engine
    participant DB as Database
    participant Fallback as Deterministic<br/>Fallback

    Scheduler->>cmd_auto_pickup: trigger auto-pickup
    cmd_auto_pickup->>ai_auto_pickup: delegate with repo path
    
    ai_auto_pickup->>Gatherer: scan TODO.md & strategies
    Gatherer->>Gatherer: collect from auto-dispatch tags
    Gatherer->>Gatherer: collect from dispatch queue
    Gatherer->>Gatherer: collect from PLANS.md decomposition
    Gatherer->>DB: fetch blocker info & state
    Gatherer-->>ai_auto_pickup: return candidate JSON

    ai_auto_pickup->>Judge: evaluate candidates
    Judge->>AI: prompt AI with decision rules
    alt AI Available & Parse Success
        AI-->>Judge: return JSON decisions
        Judge->>Judge: strip ANSI, extract array
    else AI Unavailable or Parse Fails
        Judge->>Fallback: recreate inline logic
        Fallback->>DB: check assignee, blockers, status
        Fallback-->>Judge: return deterministic decisions
    end
    Judge-->>ai_auto_pickup: finalized decisions

    ai_auto_pickup->>Executor: apply decisions
    Executor->>Executor: process pickup (inherit model if needed)
    Executor->>Executor: process skip
    Executor->>Executor: process decompose
    Executor->>DB: update task state & log decisions
    Executor-->>ai_auto_pickup: execution complete
    
    ai_auto_pickup-->>cmd_auto_pickup: return status
    cmd_auto_pickup-->>Scheduler: exit status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🤖 The Pickup Choreography

Where tasks once gathered by human hand,
Now AI judges with logic grand—
GATHER, JUDGE, and EXECUTE dance,
With fallback steps for every chance. ✨
Auto-pickup blooms, decisions flow free!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: extracting auto-pickup decision logic into a new AI module, which aligns with the primary refactoring across all modified files.
Docstring Coverage ✅ Passed Docstring coverage is 93.33% 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/t1319

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

❤️ Share

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

@gemini-code-assist
Copy link

Summary of Changes

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

This pull request significantly refactors the task auto-pickup mechanism by migrating its complex decision-making logic to a dedicated AI module. This change aims to enhance the flexibility and intelligence of task selection, allowing for more nuanced prioritization and gating, while ensuring system stability through a configurable AI enablement and a comprehensive deterministic fallback that mirrors the original behavior.

Highlights

  • AI-driven Auto-Pickup: The core logic for cmd_auto_pickup has been extracted from cron.sh into a new ai-pickup-decisions.sh module, enabling AI to make task selection decisions.
  • Modular Architecture: Implemented a GATHER (shell) → JUDGE (AI) → RETURN (shell) architecture, separating data gathering, AI decision-making, and action execution for improved clarity and maintainability.
  • Configurable AI: Introduced a feature flag (AI_PICKUP_DECISIONS_ENABLED) to enable or disable AI decision-making, with a default to the sonnet model, and a robust deterministic fallback for reliability.
  • Preserved Functionality: All original auto-pickup strategies (tagged, dispatch queue, plan decomposition, subtask inheritance) and batching logic are preserved, either handled by the AI or through the deterministic fallback.
Changelog
  • .agents/aidevops/supervisor-module-map.md
    • Updated the description for cmd_auto_pickup to reflect its new delegation to the AI module.
  • .agents/scripts/supervisor-helper.sh
    • Added a source command to include the new ai-pickup-decisions.sh module.
  • .agents/scripts/supervisor/ai-pickup-decisions.sh
    • Introduced a new shell script containing the AI-powered logic for task auto-pickup.
    • Implemented functions for gathering candidate task data, building AI prompts, calling AI models, and parsing AI responses.
    • Included a comprehensive deterministic fallback mechanism that replicates the original cmd_auto_pickup logic.
    • Defined feature flags and logging for AI decision auditing.
  • .agents/scripts/supervisor/cron.sh
    • Refactored the cmd_auto_pickup function into a thin wrapper that delegates its core decision logic to the new ai_auto_pickup function in ai-pickup-decisions.sh.
    • Removed approximately 460 lines of inline decision-making code.
Activity
  • No human activity (comments, reviews, approvals) has been recorded on this pull request yet.
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.

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 successfully refactors the cmd_auto_pickup logic into a new, well-structured AI module, ai-pickup-decisions.sh. This significantly cleans up cron.sh and centralizes the decision-making process. The new module follows a clear GATHER -> JUDGE -> EXECUTE pattern with a deterministic fallback, which is a robust design. The code is generally well-documented. My main feedback concerns the repeated use of 2>/dev/null to suppress errors, which can hide important debugging information and violates established repository rules. I've provided specific suggestions to improve error handling and logging.

Comment on lines +120 to +124
ai_result=$(portable_timeout "$timeout_secs" opencode run \
-m "$ai_model" \
--format default \
--title "pickup-${title_suffix}-$$" \
"$prompt" 2>/dev/null || echo "")

Choose a reason for hiding this comment

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

high

Suppressing stderr with 2>/dev/null for the opencode command call hides critical debugging information. If the AI call fails due to authentication issues, network problems, or invalid arguments, the error messages are lost, making it difficult to diagnose problems. The script only checks for an empty result, which is not enough to understand the root cause of a failure. It's better to let stderr be visible for logging and debugging purposes, especially for external API calls. The same applies to the claude call on lines 129-132.

Suggested change
ai_result=$(portable_timeout "$timeout_secs" opencode run \
-m "$ai_model" \
--format default \
--title "pickup-${title_suffix}-$$" \
"$prompt" 2>/dev/null || echo "")
ai_result=$(portable_timeout "$timeout_secs" opencode run \
-m "$ai_model" \
--format default \
--title "pickup-${title_suffix}-$$" \
"$prompt" 2>>"$SUPERVISOR_LOG" || echo "")
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.


# Portable timeout alias — uses portable_timeout from _common.sh when sourced,
# or defines a local fallback for standalone execution.
if ! declare -f portable_timeout &>/dev/null; then

Choose a reason for hiding this comment

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

medium

The use of &>/dev/null to suppress output from declare -f is overly broad. The declare -f command only outputs to stdout, so redirecting stderr is unnecessary and can hide potential syntax errors in the command itself.

Suggested change
if ! declare -f portable_timeout &>/dev/null; then
if ! declare -f portable_timeout >/dev/null; then
References
  1. In shell scripts, avoid blanket suppression of errors with '2>/dev/null'. For 'declare -f', redirecting only stdout ('>/dev/null') is sufficient as it does not output to stderr, allowing potential syntax errors to remain visible.


# Try 1: Direct parse as array
local parsed
if parsed=$(printf '%s' "$response" | jq '.' 2>/dev/null) && [[ -n "$parsed" ]]; then

Choose a reason for hiding this comment

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

medium

Suppressing stderr from jq with 2>/dev/null can hide important errors. If jq is not installed, or if there's a syntax error in the filter, the failure will be silent. While the if statement handles a failed parse, the reason for the failure is lost, making debugging harder. It's better to allow stderr to be visible for logging. This pattern is repeated throughout the script.

Suggested change
if parsed=$(printf '%s' "$response" | jq '.' 2>/dev/null) && [[ -n "$parsed" ]]; then
if parsed=$(printf '%s' "$response" | jq '.' 2>>"$SUPERVISOR_LOG") && [[ -n "$parsed" ]]; then
References
  1. In shell scripts with 'set -e' enabled, use '|| true' to prevent the script from exiting when a command like 'jq' fails on an optional lookup. Do not suppress stderr with '2>/dev/null' so that actual syntax or system errors remain visible for debugging.

local decision="$1"
local context="${2:-}"

mkdir -p "$AI_PICKUP_DECISIONS_LOG_DIR" 2>/dev/null || true

Choose a reason for hiding this comment

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

medium

Suppressing stderr from mkdir with 2>/dev/null can mask underlying filesystem issues, such as permission errors. If the log directory cannot be created, it's better to see the error message to diagnose the problem.

Suggested change
mkdir -p "$AI_PICKUP_DECISIONS_LOG_DIR" 2>/dev/null || true
mkdir -p "$AI_PICKUP_DECISIONS_LOG_DIR" 2>>"$SUPERVISOR_LOG" || true
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.

auto_base_concurrency=2
fi
local auto_batch_id
auto_batch_id=$(cmd_batch "$auto_batch_name" --concurrency "$auto_base_concurrency" --tasks "$task_csv" 2>/dev/null)

Choose a reason for hiding this comment

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

medium

Suppressing stderr from cmd_batch with 2>/dev/null hides potential errors during batch creation. If cmd_batch fails, the script will silently continue without creating the batch, and the reason for the failure will be lost. It's better to log these errors for debugging.

Suggested change
auto_batch_id=$(cmd_batch "$auto_batch_name" --concurrency "$auto_base_concurrency" --tasks "$task_csv" 2>/dev/null)
auto_batch_id=$(cmd_batch "$auto_batch_name" --concurrency "$auto_base_concurrency" --tasks "$task_csv" 2>>"$SUPERVISOR_LOG")
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.

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

🤖 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/ai-pickup-decisions.sh:
- Around line 689-752: In _execute_pickup_decisions validate each AI decision
against the provided candidates and re-apply hard gates before executing: for
each task_id (from decisions) ensure it exists in candidates (use jq to select
by .task_id) and if not, log_warn and skip; fetch the candidate entry and
enforce non-negotiable gates (reject if assignee is non-empty, merged == true,
db_status indicates closed, blockers present, or tags include "needed" or other
blocking tags) by turning the decision into skip and logging the gate that
blocked it; if a candidate contains tag "plan_decomposition" force decision to
"decompose"; validate inherit_model exists on the candidate before passing it to
cmd_add (otherwise ignore model_arg); only allow executing pickup/decompose/skip
after these checks and log when decisions are altered due to validation.

ℹ️ 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 777b7f3 and 4e6e99d.

📒 Files selected for processing (4)
  • .agents/aidevops/supervisor-module-map.md
  • .agents/scripts/supervisor-helper.sh
  • .agents/scripts/supervisor/ai-pickup-decisions.sh
  • .agents/scripts/supervisor/cron.sh

Comment on lines +689 to +752
_execute_pickup_decisions() {
local decisions="$1"
local candidates="$2"
local repo="$3"
local todo_file="$4"

local picked_up=0
local decision_count
decision_count=$(printf '%s' "$decisions" | jq 'length' 2>/dev/null || echo "0")

local i=0
while [[ "$i" -lt "$decision_count" ]]; do
local task_id decision reason inherit_model
task_id=$(printf '%s' "$decisions" | jq -r ".[$i].task_id" 2>/dev/null || echo "")
decision=$(printf '%s' "$decisions" | jq -r ".[$i].decision" 2>/dev/null || echo "")
reason=$(printf '%s' "$decisions" | jq -r ".[$i].reason // \"\"" 2>/dev/null || echo "")
inherit_model=$(printf '%s' "$decisions" | jq -r ".[$i].inherit_model // \"\"" 2>/dev/null || echo "")

i=$((i + 1))

[[ -z "$task_id" || -z "$decision" ]] && continue

case "$decision" in
pickup)
local model_arg=""
if [[ -n "$inherit_model" && "$inherit_model" != "null" ]]; then
model_arg="--model $inherit_model"
log_info " $task_id: inheriting model:$inherit_model from parent"
fi

# shellcheck disable=SC2086
if cmd_add "$task_id" --repo "$repo" $model_arg; then
picked_up=$((picked_up + 1))
log_success " Auto-picked: $task_id ($reason)"
fi
;;
decompose)
# Look up plan_anchor from candidates
local plan_anchor
plan_anchor=$(printf '%s' "$candidates" | jq -r \
--arg id "$task_id" \
'[.[] | select(.task_id == $id)] | .[0].plan_anchor // ""' 2>/dev/null || echo "")

if cmd_add "$task_id" --repo "$repo"; then
picked_up=$((picked_up + 1))
log_success " Auto-picked: $task_id (#plan task for decomposition)"

if [[ -n "$plan_anchor" ]]; then
log_info " Dispatching decomposition worker for $task_id..."
dispatch_decomposition_worker "$task_id" "$plan_anchor" "$repo"
else
log_warn " $task_id: decompose decision but no plan_anchor found"
fi
fi
;;
skip)
if [[ -n "$reason" && "$reason" != "null" ]]; then
log_info " $task_id: skipped — $reason"
fi
;;
*)
log_warn " $task_id: unknown decision '$decision' — skipping"
;;
esac
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

Enforce hard gates + candidate validation before executing AI decisions.

AI output is untrusted; as written, a hallucinated task_id or a hard‑gate violation can be executed. Validate decisions against the candidate set and re‑apply non‑negotiable gates (assignee/merged/db_status/blockers/needed tags). Also force plan_decomposition → decompose for safety.

🔒️ Proposed safeguard for AI decisions
@@
-		[[ -z "$task_id" || -z "$decision" ]] && continue
+		[[ -z "$task_id" || -z "$decision" ]] && continue
+
+		# Validate AI output against candidate set + hard gates
+		local candidate
+		candidate=$(printf '%s' "$candidates" | jq -r --arg id "$task_id" '.[] | select(.task_id == $id)' 2>/dev/null)
+		if [[ -z "$candidate" || "$candidate" == "null" ]]; then
+			log_warn "  $task_id: AI returned unknown task_id — skipping"
+			continue
+		fi
+
+		local has_assignee has_merged_pr db_status unresolved_blockers needed_tags source
+		has_assignee=$(printf '%s' "$candidate" | jq -r '.has_assignee' 2>/dev/null || echo "")
+		has_merged_pr=$(printf '%s' "$candidate" | jq -r '.has_merged_pr' 2>/dev/null || echo "")
+		db_status=$(printf '%s' "$candidate" | jq -r '.db_status' 2>/dev/null || echo "")
+		unresolved_blockers=$(printf '%s' "$candidate" | jq -r '.unresolved_blockers' 2>/dev/null || echo "")
+		needed_tags=$(printf '%s' "$candidate" | jq -r '.needed_tags' 2>/dev/null || echo "")
+		source=$(printf '%s' "$candidate" | jq -r '.source' 2>/dev/null || echo "")
+
+		if [[ "$has_assignee" == "true" || "$has_merged_pr" == "true" || -n "$unresolved_blockers" || -n "$needed_tags" || ( -n "$db_status" && "$db_status" != "none" ) ]]; then
+			log_info "  $task_id: hard gate matched — skipping AI decision"
+			continue
+		fi
+		if [[ "$source" == "plan_decomposition" && "$decision" != "decompose" ]]; then
+			log_info "  $task_id: forcing decompose for plan task"
+			decision="decompose"
+		fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/scripts/supervisor/ai-pickup-decisions.sh around lines 689 - 752, In
_execute_pickup_decisions validate each AI decision against the provided
candidates and re-apply hard gates before executing: for each task_id (from
decisions) ensure it exists in candidates (use jq to select by .task_id) and if
not, log_warn and skip; fetch the candidate entry and enforce non-negotiable
gates (reject if assignee is non-empty, merged == true, db_status indicates
closed, blockers present, or tags include "needed" or other blocking tags) by
turning the decision into skip and logging the gate that blocked it; if a
candidate contains tag "plan_decomposition" force decision to "decompose";
validate inherit_model exists on the candidate before passing it to cmd_add
(otherwise ignore model_arg); only allow executing pickup/decompose/skip after
these checks and log when decisions are altered due to validation.

@marcusquinn
Copy link
Owner Author

Superseded — this work was completed manually in a different PR.

@marcusquinn marcusquinn deleted the feature/t1319 branch February 24, 2026 18:29
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