Skip to content

Fix executor QR: split broken combined modules into decompose+verify#20

Open
Sapd wants to merge 4 commits into
solatis:mainfrom
Sapd:fix/executor-qr-decompose-verify
Open

Fix executor QR: split broken combined modules into decompose+verify#20
Sapd wants to merge 4 commits into
solatis:mainfrom
Sapd:fix/executor-qr-decompose-verify

Conversation

@Sapd
Copy link
Copy Markdown

@Sapd Sapd commented Feb 10, 2026

(Ive written this PR using claude. I noticed that when executing a plan, it does not go through Quality review. Thats silent so easy to miss).

Problem

The executor orchestrator (skills/planner/orchestrator/executor.py) references QR modules that don't exist:

# executor.py lines 122, 160
"mode_script": "quality_reviewer/impl-code-qr.py",   # resolves to skills.planner.quality_reviewer.impl_code_qr
"mode_script": "quality_reviewer/impl-docs-qr.py",    # resolves to skills.planner.quality_reviewer.impl_docs_qr

Neither impl_code_qr.py nor impl_docs_qr.py exist. These were split into separate decompose/verify files at some point, matching the planner's pattern:

  • impl_code_qr_decompose.py + impl_code_qr_verify.py
  • impl_docs_qr_decompose.py + impl_docs_qr_verify.py

The planner orchestrator was updated to dispatch decompose and verify as separate steps (steps 4+5, 8+9, 12+13), but the executor was never updated. This means executor steps 4 and 7 always fail with ModuleNotFoundError.

The supporting infrastructure was already updated for the split:

  • constants.py: EXECUTOR_TOTAL_STEPS = 10, EXECUTOR_GATE_STEPS = {5, 9} (expects 10 steps, not 9)
  • phases.py: impl-code maps decompose=3, verify=4, gate=5; impl-docs maps decompose=7, verify=8, gate=9
  • qr/constants.py: routing entries exist for ("executor", "impl-code") → gate step 5

But executor.py still had the old 9-step layout with combined QR modules.

Fix

Rewrites executor.py from 9 to 10 steps, matching the existing phases.py/constants.py definitions:

Step Old New
1 Execution Planning Execution Planning (+ create state_dir)
2 Reconciliation Implementation (reconciliation folded in via flag)
3 Implementation Code QR Decompose → impl_code_qr_decompose
4 Code QR (broken) Code QR Verify → impl_code_qr_verify (parallel)
5 Code QR Gate Code QR Gate (pass→6, fail→2)
6 Documentation Documentation
7 Doc QR (broken) Doc QR Decompose → impl_docs_qr_decompose
8 Doc QR Gate Doc QR Verify → impl_docs_qr_verify (parallel)
9 Retrospective Doc QR Gate (pass→10, fail→6)
10 Retrospective

Key changes:

  • Add --state-dir CLI arg (created in step 1, passed through all steps)
  • Use get_phase_config() to resolve decompose/verify script paths from phases.py
  • Reuse planner's QR patterns: qr_file_exists skip, template_dispatch for parallel verify, build_gate_output for gates
  • Derive fix mode from QR state files (like planner does) instead of relying solely on --qr-fail flag

Test plan

  • All 10 steps produce valid output (--step 1 through --step 10)
  • Gate steps route correctly: pass→next phase, fail→work step with --state-dir
  • Fix mode works for both implementation (step 2) and documentation (step 6)
  • Decompose skip works when qr-{phase}.json already exists
  • State dir created automatically in step 1, required for steps 2+

The executor referenced non-existent quality_reviewer/impl-code-qr.py
and impl-docs-qr.py modules. These were split into separate
_decompose.py and _verify.py files (matching planner's pattern) but
the executor was never updated.

Changes:
- Rewrite executor from 9 to 10 steps (matching EXECUTOR_TOTAL_STEPS
  and phases.py step numbering)
- Split step 4 (Code QR) into: decompose (3) + verify (4) + gate (5)
- Split step 7 (Doc QR) into: decompose (7) + verify (8) + gate (9)
- Add --state-dir CLI arg (created in step 1, passed through all steps)
- Use phases.py config for script paths instead of hardcoded mode_script
- Reuse planner's QR patterns: qr_file_exists skip, parallel verify
  dispatch with template_dispatch, build_gate_output for gates
- Fold reconciliation into step 1 (--reconciliation-check flag)
@qodo-code-review
Copy link
Copy Markdown

Review Summary by Qodo

Fix executor QR: split broken combined modules into decompose+verify pattern

🐞 Bug fix ✨ Enhancement

Grey Divider

Walkthroughs

Description
• Rewrite executor from 9 to 10 steps, splitting QR modules into decompose/verify/gate pattern
• Replace broken combined QR modules with separate decompose and verify scripts
• Add --state-dir CLI argument created in step 1, passed through all steps
• Use get_phase_config() to resolve script paths from phases.py instead of hardcoded references
• Reuse planner's QR patterns: skip logic, parallel verify dispatch, gate routing
• Fold reconciliation into step 1 via --reconciliation-check flag
• Derive fix mode from QR state files instead of relying solely on --qr-fail flag
Diagram
flowchart LR
  A["Step 1: Planning<br/>+ state_dir setup"] --> B["Step 2: Implementation<br/>wave-aware dispatch"]
  B --> C["Step 3: Code QR<br/>Decompose"]
  C --> D["Step 4: Code QR<br/>Verify parallel"]
  D --> E["Step 5: Code QR<br/>Gate route"]
  E -->|pass| F["Step 6: Documentation<br/>TW dispatch"]
  E -->|fail| B
  F --> G["Step 7: Doc QR<br/>Decompose"]
  G --> H["Step 8: Doc QR<br/>Verify parallel"]
  H --> I["Step 9: Doc QR<br/>Gate route"]
  I -->|pass| J["Step 10: Retrospective"]
  I -->|fail| F
Loading

Grey Divider

File Changes

1. skills/scripts/skills/planner/orchestrator/executor.py 🐞 Bug fix +386/-456

Rewrite executor workflow to 10-step QR decompose/verify/gate pattern

• Rewrote workflow from 9 to 10 steps with QR decompose/verify/gate pattern
• Replaced hardcoded broken QR module references with get_phase_config() lookups
• Added --state-dir parameter created in step 1, passed through all steps
• Implemented parallel QR verification using template_dispatch() and item grouping
• Added QR decompose skip logic via qr_file_exists() check
• Implemented gate routing using build_gate_output() helper
• Folded reconciliation into step 1 via --reconciliation-check flag
• Added QR state file-based fix mode detection for steps 2 and 6

skills/scripts/skills/planner/orchestrator/executor.py


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented Feb 10, 2026

Code Review by Qodo

🐞 Bugs (5) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

✅ 1. state_dir exposed in errors 📘 Rule violation ⛨ Security
Description
The QR verify step returns an error message that includes the internal state_dir filesystem path,
which can leak implementation details to the user. This violates secure error handling expectations
for user-facing errors.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R266-269]

+    qr_state = load_qr_state(state_dir, phase)
+    if not qr_state or "items" not in qr_state:
+        body = f"Error: qr-{phase}.json not found or malformed in {state_dir}"
+        return format_step(body, title=title)
Evidence
The secure error handling rule requires user-facing errors not to expose internal implementation
details; the code includes state_dir directly in the returned error string.

Rule 4: Generic: Secure Error Handling
skills/scripts/skills/planner/orchestrator/executor.py[266-269]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
User-facing error output includes the internal filesystem path (`state_dir`), leaking implementation details.
## Issue Context
This orchestrator prints `format_step(...)` content to stdout, which is user-visible. Secure error handling requires keeping internal details (paths, stack traces) out of user-facing messages.
## Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[266-269]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Unquoted state_dir in commands 📘 Rule violation ⛨ Security
Description
The code interpolates state_dir directly into command strings without quoting/escaping, so paths
with spaces can break commands and user-controlled values can enable shell-injection if copy/pasted
or executed via a shell. This violates security-first input handling expectations for external
inputs.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R130-132]

+    next_cmd = f"python3 -m {MODULE_PATH} --step 2 --state-dir {state_dir}"

-    # Determine next command
-    if qr.passed and gate.pass_step is not None:
-        next_cmd = f"python3 -m {MODULE_PATH} --step {gate.pass_step}"
-    else:
-        next_iteration = qr.iteration + 1
-        next_cmd = f"python3 -m {MODULE_PATH} --step {gate.work_step} --qr-fail --qr-iteration {next_iteration}"
+    return format_step(body, next_cmd, title="Execution Planning")
Evidence
The input validation rule requires external inputs to be handled securely; here, the user-provided
--state-dir value is embedded into shell command text without any escaping/quoting.

Rule 6: Generic: Security-First Input Validation and Data Handling
skills/scripts/skills/planner/orchestrator/executor.py[504-505]
skills/scripts/skills/planner/orchestrator/executor.py[130-132]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`state_dir` is treated as an external input and is interpolated into command strings without quoting/escaping, risking command breakage and potential injection.
## Issue Context
Commands are produced as strings (for next-step commands and agent dispatch templates). If these strings are executed via a shell or copy/pasted, unquoted values can be interpreted as additional flags/commands.
## Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[130-132]
- skills/scripts/skills/planner/orchestrator/executor.py[204-205]
- skills/scripts/skills/planner/orchestrator/executor.py[238-238]
- skills/scripts/skills/planner/orchestrator/executor.py[306-307]
- skills/scripts/skills/planner/orchestrator/executor.py[341-345]
- skills/scripts/skills/planner/orchestrator/executor.py[396-409]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 3. Bad --qr-fail dispatch 🐞 Bug ✓ Correctness
Description
In fix mode, executor dispatches developer/TW router scripts with a bare --qr-fail flag, but those
scripts use mode_main, which defines --qr-fail as a string option requiring a value. This will
raise argparse errors and break the fix loop at runtime.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R152-154]

+        mode_script = get_mode_script_path("developer/exec_implement.py")
+        invoke_cmd = f"python3 -m {mode_script} --step 1 --state-dir {state_dir} --qr-fail --qr-iteration {qr.iteration}"
Evidence
Executor constructs fix-mode subagent commands with --qr-fail (no value). The invoked subagent
entrypoints use mode_main, where --qr-fail is declared as type=str, so a value is required;
passing it as a bare flag will fail argument parsing.

skills/scripts/skills/planner/orchestrator/executor.py[152-154]
skills/scripts/skills/planner/orchestrator/executor.py[396-400]
skills/scripts/skills/lib/workflow/cli.py[88-92]
skills/scripts/skills/planner/developer/exec_implement.py[88-98]
skills/scripts/skills/planner/technical_writer/exec_docs.py[88-98]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Executor fix-mode dispatch commands include a bare `--qr-fail`, but the invoked subagent scripts use `mode_main` which defines `--qr-fail` as a string option requiring a value. This causes argparse failures and breaks the fix loop.
### Issue Context
- Executor fix-mode dispatch uses `developer/exec_implement.py` and `technical_writer/exec_docs.py`.
- Those scripts are entered via `mode_main` which defines `--qr-fail` as `type=str`.
- The router scripts already decide fix vs execute via QR state inspection (`has_qr_failures`), so `--qr-fail` is unnecessary.
### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[152-154]
- skills/scripts/skills/planner/orchestrator/executor.py[396-400]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
4. Retry state not applied 🐞 Bug ✓ Correctness
Description
Executor derives LoopState.RETRY from QR state files only for steps 2 and 6, not for QR steps (3–5,
7–9). As a result, QR verify steps typically run as INITIAL even when failures exist, so iteration
increments and progressive de-escalation logic won’t execute as intended and workflows can get stuck
blocking on low-severity items.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R461-468]

+    # Derive fix mode from QR state files (like planner does)
+    phase_for_step = {2: "impl-code", 6: "impl-docs"}
+    if step in phase_for_step and state_dir and not qr_fail:
+        from skills.planner.shared.qr.utils import has_qr_failures
+        phase = phase_for_step[step]
+        if has_qr_failures(state_dir, phase):
+            qr = QRState(iteration=qr_iteration, state=LoopState.RETRY, status=status)
+
Evidence
Executor only checks has_qr_failures for step 2 and 6. However, QR verify increments iteration
only when qr.state == LoopState.RETRY. Without deriving RETRY for steps 4/8 (and iteration from
file), retries won’t be recognized and iteration-based severity narrowing won’t progress.

skills/scripts/skills/planner/orchestrator/executor.py[461-468]
skills/scripts/skills/planner/orchestrator/executor.py[271-273]
skills/scripts/skills/planner/shared/qr/constants.py[55-82]
skills/scripts/skills/planner/orchestrator/planner.py[589-603]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Executor only derives retry state from QR files for steps 2 and 6, so QR verify steps do not enter RETRY mode even when failures exist. This prevents iteration increments and breaks progressive severity de-escalation.
### Issue Context
Planner orchestrator derives phase/iteration/retry state from QR state files for every step handler with a phase. Executor should follow the same pattern for impl-code (steps 2–5) and impl-docs (steps 6–9).
### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[450-492]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. QR error marks complete 🐞 Bug ⛯ Reliability
Description
If qr-{phase}.json is missing/malformed, format_qr_verify calls format_step without a next command,
which causes the step renderer to output WORKFLOW COMPLETE. This can silently stop execution instead
of routing back to decompose or surfacing a recoverable error path.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R266-269]

+    qr_state = load_qr_state(state_dir, phase)
+    if not qr_state or "items" not in qr_state:
+        body = f"Error: qr-{phase}.json not found or malformed in {state_dir}"
+        return format_step(body, title=title)
Evidence
format_qr_verify returns format_step(body, title=...) on error. In format_step, when there is no
branching and no next_cmd, it prints a WORKFLOW COMPLETE footer. Therefore missing qr files can
incorrectly be treated as completion.

skills/scripts/skills/planner/orchestrator/executor.py[266-269]
skills/scripts/skills/lib/workflow/prompts/step.py[57-58]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When qr state is missing/malformed, executor returns a formatted step without a next command, and the step formatter treats this as workflow completion.
### Issue Context
This should be a recoverable error: users should be routed back to the decompose step (or given a command to regenerate qr-{phase}.json).
### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[266-269]
- skills/scripts/skills/lib/workflow/prompts/step.py[57-58]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

6. plan.json write lacks handling 📘 Rule violation ⛯ Reliability
Description
Step 1 creates a temp directory and writes plan.json without handling filesystem errors
(permissions/disk full), which can crash with an unhandled exception and provide poor diagnostics.
This violates robust error handling expectations for likely failure points.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R516-528]

+    # Create state_dir for step 1 if not provided
+    state_dir = args.state_dir
+    if args.step == 1 and not state_dir:
+        state_dir = tempfile.mkdtemp(prefix="executor-")
+        # Write minimal plan skeleton
+        plan_path = Path(state_dir) / "plan.json"
+        plan_path.write_text(json.dumps({
+            "schema_version": 2,
+            "overview": {"problem": "", "approach": ""},
+            "milestones": [],
+            "waves": [],
+        }, indent=2))
+
Evidence
The robust error handling rule requires identifying and handling failure points with actionable
context; direct filesystem writes can fail but are not wrapped with contextual handling.

Rule 3: Generic: Robust Error Handling and Edge Case Management
skills/scripts/skills/planner/orchestrator/executor.py[516-528]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Creating the state directory and writing `plan.json` can fail, but failures are not handled, leading to crashes and poor error context.
## Issue Context
This is part of the CLI flow for step 1; handling IO errors gracefully improves debuggability and avoids raw tracebacks.
## Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[516-528]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 7. Stale iteration after increment 🐞 Bug ✓ Correctness
Description
format_qr_verify increments iteration in qr-{phase}.json but continues filtering items using the
pre-increment iteration loaded earlier. This undermines the intended severity de-escalation behavior
across retries.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R271-276]

+    if qr.state == LoopState.RETRY:
+        increment_qr_iteration(state_dir, phase)
+
+    # Dispatch only items at blocking severity for current iteration
+    iteration = qr_state.get("iteration", 1)
+    items = query_items(qr_state, by_status("TODO", "FAIL"), by_blocking_severity(iteration))
Evidence
qr_state is loaded before increment_qr_iteration() runs. The subsequent `iteration =
qr_state.get('iteration', 1)` is therefore stale, while blocking severities explicitly depend on
iteration count.

skills/scripts/skills/planner/orchestrator/executor.py[266-276]
skills/scripts/skills/planner/shared/qr/utils.py[297-304]
skills/scripts/skills/planner/shared/qr/constants.py[55-82]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`format_qr_verify` increments iteration in the on-disk QR state file but uses a stale in-memory `qr_state` to determine the current iteration for severity filtering.
### Issue Context
Severity blocking thresholds depend on iteration count (progressive de-escalation). Filtering with the old iteration defeats this policy.
### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[266-276]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


✅ 8. plan.json skeleton incomplete 🐞 Bug ⛯ Reliability
Description
Executor auto-creates plan.json missing fields present in the v2 skeleton used elsewhere
(planning_context, invisible_knowledge). Downstream impl-docs QR guidance explicitly asks reviewers
to focus on invisible_knowledge, so missing fields reduce effectiveness and can break schema
expectations.
Code

skills/scripts/skills/planner/orchestrator/executor.py[R519-527]

+        state_dir = tempfile.mkdtemp(prefix="executor-")
+        # Write minimal plan skeleton
+        plan_path = Path(state_dir) / "plan.json"
+        plan_path.write_text(json.dumps({
+            "schema_version": 2,
+            "overview": {"problem": "", "approach": ""},
+            "milestones": [],
+            "waves": [],
+        }, indent=2))
Evidence
Executor writes a minimal plan.json with only overview/milestones/waves, while the planner’s v2
skeleton includes planning_context and invisible_knowledge. The impl-docs QR decompose step
instructs reviewers to examine the invisible_knowledge section, which won’t exist with the executor
skeleton unless manually added.

skills/scripts/skills/planner/orchestrator/executor.py[521-527]
skills/scripts/skills/planner/orchestrator/planner.py[131-147]
skills/scripts/skills/planner/quality_reviewer/impl_docs_qr_decompose.py[20-39]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Executor’s auto-generated plan.json skeleton omits fields that downstream QR guidance expects (notably `invisible_knowledge`) and diverges from the standard v2 skeleton used by the planner.
### Issue Context
Impl-docs QR explicitly reviews `invisible_knowledge`. Using a consistent skeleton reduces missing-field edge cases and keeps schema expectations aligned across workflows.
### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[519-527]
- skills/scripts/skills/planner/orchestrator/executor.py[69-118]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +266 to +269
qr_state = load_qr_state(state_dir, phase)
if not qr_state or "items" not in qr_state:
body = f"Error: qr-{phase}.json not found or malformed in {state_dir}"
return format_step(body, title=title)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. state_dir exposed in errors 📘 Rule violation ⛨ Security

The QR verify step returns an error message that includes the internal state_dir filesystem path,
which can leak implementation details to the user. This violates secure error handling expectations
for user-facing errors.
Agent Prompt
## Issue description
User-facing error output includes the internal filesystem path (`state_dir`), leaking implementation details.

## Issue Context
This orchestrator prints `format_step(...)` content to stdout, which is user-visible. Secure error handling requires keeping internal details (paths, stack traces) out of user-facing messages.

## Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[266-269]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +130 to +132
next_cmd = f"python3 -m {MODULE_PATH} --step 2 --state-dir {state_dir}"

# Determine next command
if qr.passed and gate.pass_step is not None:
next_cmd = f"python3 -m {MODULE_PATH} --step {gate.pass_step}"
else:
next_iteration = qr.iteration + 1
next_cmd = f"python3 -m {MODULE_PATH} --step {gate.work_step} --qr-fail --qr-iteration {next_iteration}"
return format_step(body, next_cmd, title="Execution Planning")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Unquoted state_dir in commands 📘 Rule violation ⛨ Security

The code interpolates state_dir directly into command strings without quoting/escaping, so paths
with spaces can break commands and user-controlled values can enable shell-injection if copy/pasted
or executed via a shell. This violates security-first input handling expectations for external
inputs.
Agent Prompt
## Issue description
`state_dir` is treated as an external input and is interpolated into command strings without quoting/escaping, risking command breakage and potential injection.

## Issue Context
Commands are produced as strings (for next-step commands and agent dispatch templates). If these strings are executed via a shell or copy/pasted, unquoted values can be interpreted as additional flags/commands.

## Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[130-132]
- skills/scripts/skills/planner/orchestrator/executor.py[204-205]
- skills/scripts/skills/planner/orchestrator/executor.py[238-238]
- skills/scripts/skills/planner/orchestrator/executor.py[306-307]
- skills/scripts/skills/planner/orchestrator/executor.py[341-345]
- skills/scripts/skills/planner/orchestrator/executor.py[396-409]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +152 to 154
mode_script = get_mode_script_path("developer/exec_implement.py")
invoke_cmd = f"python3 -m {mode_script} --step 1 --state-dir {state_dir} --qr-fail --qr-iteration {qr.iteration}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Bad --qr-fail dispatch 🐞 Bug ✓ Correctness

In fix mode, executor dispatches developer/TW router scripts with a bare --qr-fail flag, but those
scripts use mode_main, which defines --qr-fail as a string option requiring a value. This will
raise argparse errors and break the fix loop at runtime.
Agent Prompt
### Issue description
Executor fix-mode dispatch commands include a bare `--qr-fail`, but the invoked subagent scripts use `mode_main` which defines `--qr-fail` as a string option requiring a value. This causes argparse failures and breaks the fix loop.

### Issue Context
- Executor fix-mode dispatch uses `developer/exec_implement.py` and `technical_writer/exec_docs.py`.
- Those scripts are entered via `mode_main` which defines `--qr-fail` as `type=str`.
- The router scripts already decide fix vs execute via QR state inspection (`has_qr_failures`), so `--qr-fail` is unnecessary.

### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[152-154]
- skills/scripts/skills/planner/orchestrator/executor.py[396-400]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +461 to +468
# Derive fix mode from QR state files (like planner does)
phase_for_step = {2: "impl-code", 6: "impl-docs"}
if step in phase_for_step and state_dir and not qr_fail:
from skills.planner.shared.qr.utils import has_qr_failures
phase = phase_for_step[step]
if has_qr_failures(state_dir, phase):
qr = QRState(iteration=qr_iteration, state=LoopState.RETRY, status=status)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

4. Retry state not applied 🐞 Bug ✓ Correctness

Executor derives LoopState.RETRY from QR state files only for steps 2 and 6, not for QR steps (3–5,
7–9). As a result, QR verify steps typically run as INITIAL even when failures exist, so iteration
increments and progressive de-escalation logic won’t execute as intended and workflows can get stuck
blocking on low-severity items.
Agent Prompt
### Issue description
Executor only derives retry state from QR files for steps 2 and 6, so QR verify steps do not enter RETRY mode even when failures exist. This prevents iteration increments and breaks progressive severity de-escalation.

### Issue Context
Planner orchestrator derives phase/iteration/retry state from QR state files for every step handler with a phase. Executor should follow the same pattern for impl-code (steps 2–5) and impl-docs (steps 6–9).

### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[450-492]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +266 to +269
qr_state = load_qr_state(state_dir, phase)
if not qr_state or "items" not in qr_state:
body = f"Error: qr-{phase}.json not found or malformed in {state_dir}"
return format_step(body, title=title)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

5. Qr error marks complete 🐞 Bug ⛯ Reliability

If qr-{phase}.json is missing/malformed, format_qr_verify calls format_step without a next command,
which causes the step renderer to output WORKFLOW COMPLETE. This can silently stop execution instead
of routing back to decompose or surfacing a recoverable error path.
Agent Prompt
### Issue description
When qr state is missing/malformed, executor returns a formatted step without a next command, and the step formatter treats this as workflow completion.

### Issue Context
This should be a recoverable error: users should be routed back to the decompose step (or given a command to regenerate qr-{phase}.json).

### Fix Focus Areas
- skills/scripts/skills/planner/orchestrator/executor.py[266-269]
- skills/scripts/skills/lib/workflow/prompts/step.py[57-58]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sapd added 2 commits February 10, 2026 18:05
get_step_guidance() was missing module_path and **kwargs parameters
that mode_main() passes to all step guidance functions. This caused
a TypeError when the QR fix workflow was dispatched.
Sub-agents dispatched via Task tool don't always cd to the working
directory before running Python module commands, causing intermittent
"module not found" failures. Fix by inlining `cd {dir} &&` into the
command itself instead of relying on a separate "Working directory"
instruction that agents may ignore.
@ArtyT
Copy link
Copy Markdown

ArtyT commented Feb 11, 2026

Fixes for 4 review bugs

Addressed the 4 substantive bugs from the Qodo review. Here's the diff:

1. Remove bare --qr-fail from subagent dispatch (Bug #3)

mode_main defines --qr-fail as type=str (requires a value), but executor passed it as a bare flag — this would crash argparse. The router scripts already detect fix mode from QR state files via has_qr_failures(), so the flag is unnecessary.

-        invoke_cmd = f"python3 -m {mode_script} --step 1 --state-dir {state_dir} --qr-fail --qr-iteration {qr.iteration}"
+        invoke_cmd = f"python3 -m {mode_script} --step 1 --state-dir {state_dir}"

(Applied to both step 2 developer dispatch and step 6 TW dispatch)

2. Fix stale iteration after increment (Bug #7)

increment_qr_iteration() updates on disk but the code read iteration from the stale in-memory qr_state. Now uses the return value:

+    iteration = qr_state.get("iteration", 1)
     if qr.state == LoopState.RETRY:
-        increment_qr_iteration(state_dir, phase)
+        new_iter = increment_qr_iteration(state_dir, phase)
+        if new_iter is not None:
+            iteration = new_iter
 
     # Dispatch only items at blocking severity for current iteration
-    iteration = qr_state.get("iteration", 1)
     items = query_items(qr_state, by_status("TODO", "FAIL"), by_blocking_severity(iteration))

3. Fix QR error silently marking workflow complete (Bug #5)

Missing QR state file produced format_step(body, title=...) with no next_cmd, which prints "WORKFLOW COMPLETE". Now routes back to the decompose step:

     if not qr_state or "items" not in qr_state:
-        body = f"Error: qr-{phase}.json not found or malformed in {state_dir}"
-        return format_step(body, title=title)
+        decompose_step = step - 1
+        body = f"Error: qr-{phase}.json not found or malformed. Routing back to decompose step."
+        retry_cmd = f"python3 -m {MODULE_PATH} --step {decompose_step} --state-dir {state_dir}"
+        return format_step(body, retry_cmd, title=title)

4. Add missing fields to plan.json skeleton (Bug #8)

Executor skeleton was missing planning_context and invisible_knowledge that the planner's v2 skeleton includes (and that downstream impl_docs_qr_decompose references):

         plan_path.write_text(json.dumps({
             "schema_version": 2,
             "overview": {"problem": "", "approach": ""},
+            "planning_context": {
+                "decisions": [],
+                "rejected_alternatives": [],
+                "constraints": [],
+                "risks": [],
+            },
+            "invisible_knowledge": {
+                "system": "",
+                "invariants": [],
+                "tradeoffs": [],
+            },
             "milestones": [],
             "waves": [],
         }, indent=2))

Skipped (noise)

…on, skeleton fields

- Remove bare --qr-fail/--qr-iteration flags from subagent dispatch commands;
  sub-agents detect fix mode from QR state files via has_qr_failures()
- Use return value of increment_qr_iteration() instead of reading stale
  in-memory qr_state after disk update
- Route back to decompose step when QR state file is missing/malformed
  instead of silently marking workflow complete
- Add planning_context and invisible_knowledge to executor plan.json
  skeleton to match planner's v2 schema

Co-authored-by: Arty <24428965+ArtyT@users.noreply.github.com>
@solatis
Copy link
Copy Markdown
Owner

solatis commented Feb 13, 2026

Thanks, the planner skill is currently going through a bit of an overhaul, and is indeed broken -- let me see what I can do.

@Sapd
Copy link
Copy Markdown
Author

Sapd commented Feb 13, 2026

I also noticed that even with my changes, sometimes claude/the planner declares victory while QR steps are still open. A simple "check if you really did all steps" is enough to trigger it continuing. Not sure how this can be fixed.

@solatis
Copy link
Copy Markdown
Owner

solatis commented Feb 13, 2026

Yes, I think it's Claude that wants to stop early; it's effectively one of the limitations of Claude Code not being extensible enough to "force" a workflow.

I'm thinking of ways to avoid this; context also gets larger and larger with every QR iteration run.

@dusan-t
Copy link
Copy Markdown

dusan-t commented Feb 18, 2026

Do you have an opinion on whether it's better to use an earlier version of the workflow (e.g., one from mid-January) while you iron out the bugs in the planner skill, or if it's still worth using the current version despite the issues?

gcharang added a commit to playactai/claude-config that referenced this pull request Apr 16, 2026
Port the executor QR decompose/verify/gate rewrite from PR solatis#20 and go
beyond the merged branch by closing the three Qodo items ArtyT skipped
(unquoted state_dir, RETRY state for QR steps, plan.json write error
handling). Also repair broken tests that predated this change:
Workflow._params, ChoiceSet/Constant domain types, dead WORKFLOW
strings in QR verify modules, and a NameError in incoherence.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.

4 participants