Skip to content

Fix Orchestrator Anti-Patterns Identified by run_cmd Pattern Mining#285

Closed
Trecek wants to merge 12 commits intomainfrom
fix-orchestrator-anti-patterns-identified-by-run-cmd-pattern/238
Closed

Fix Orchestrator Anti-Patterns Identified by run_cmd Pattern Mining#285
Trecek wants to merge 12 commits intomainfrom
fix-orchestrator-anti-patterns-identified-by-run-cmd-pattern/238

Conversation

@Trecek
Copy link
Collaborator

@Trecek Trecek commented Mar 10, 2026

Summary

Pattern mining of 736 run_cmd invocations across 47 orchestrator sessions identified five
behavioral anti-patterns where the orchestrator bypasses the recipe routing discipline. This
plan fixes all five:

  1. AP1 — CI Investigation Spiral (22 occurrences): Create a diagnose-ci skill so the
    orchestrator has a proper run_skill channel for CI log investigation. Update recipes to
    insert a diagnose_ci step before resolve_ci on CI failure paths.

  2. AP2 — Push-Per-Merge (8 wasted pushes): Switch push_integration_branch in
    pr-merge-pipeline.yaml from run_cmd to the push_to_remote MCP tool (the same tool
    all other push steps use), and add an explicit kitchen rule forbidding intermediate pushes
    inside the merge loop.

  3. AP3 — Branch Checkout Retries (12 redundant attempts): Add base_branch_name
    parameter to the create_unique_branch MCP tool. Replace the create_branch run_cmd
    bash script in all recipes with two cleaner steps: compute_branch (name-only run_cmd)

    • create_branch (create_unique_branch MCP tool). The atomic MCP call eliminates the
      gap where the orchestrator inserts extra git fetch + checkout -b commands.
  4. AP4 — Multi-Issue Boilerplate (80-command sessions): Add a batch-implementation.yaml
    recipe skeleton that runs shared setup (clone, base_sha) once and loops per-issue for the
    branch+implement+push steps. Full loop implementation is deferred pending write_telemetry_files
    from issue feat: new MCP tools for high-frequency run_cmd patterns (pattern mining 2026-03-08) #237; this plan delivers the recipe structure and the shared-setup savings.

  5. AP5 — Unnamed Step Commands (88.3%): Add step_name to every run_cmd step in all
    bundled recipes that currently lacks one. Target: ≤20% unnamed commands.

Architecture Impact

Process Flow Diagram

%%{init: {'flowchart': {'nodeSpacing': 45, 'rankSpacing': 55, 'curve': 'basis'}}}%%
flowchart TB
    %% CLASS DEFINITIONS %%
    classDef cli fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;
    classDef stateNode fill:#004d40,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef handler fill:#e65100,stroke:#ffb74d,stroke-width:2px,color:#fff;
    classDef phase fill:#6a1b9a,stroke:#ba68c8,stroke-width:2px,color:#fff;
    classDef newComponent fill:#2e7d32,stroke:#81c784,stroke-width:2px,color:#fff;
    classDef output fill:#00695c,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef detector fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#fff;
    classDef terminal fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;

    %% TERMINALS %%
    START([START])
    DONE([DONE])
    ESCALATE([ESCALATE])

    subgraph AP3 ["AP3 Fix: Branch Creation (implementation, audit-and-fix, remediation)"]
        direction TB
        COMPUTE["● compute_branch<br/>━━━━━━━━━━<br/>run_cmd: name only<br/>slug/issue → proposed_branch<br/>no git operations"]
        CUB["★ create_branch<br/>━━━━━━━━━━<br/>create_unique_branch tool<br/>base_branch_name=proposed_branch<br/>atomic: ls-remote + checkout -b"]
        PUSH_MT["push_merge_target<br/>━━━━━━━━━━<br/>push_to_remote MCP"]
    end

    subgraph IMPL ["Core Loop (implement → test → merge)"]
        direction LR
        PLAN["plan / implement<br/>━━━━━━━━━━<br/>run_skill sessions"]
        TEST{"test passes?"}
        FIX["fix<br/>━━━━━━━━━━<br/>resolve-failures"]
        MERGE["merge<br/>━━━━━━━━━━<br/>merge_worktree MCP"]
    end

    subgraph AP1 ["AP1 Fix: CI Failure Path (implementation, audit-and-fix, remediation)"]
        direction TB
        PUSH_PR["push / open_pr / review_pr<br/>━━━━━━━━━━<br/>upstream push + GitHub PR"]
        CI_WATCH{"● ci_watch<br/>━━━━━━━━━━<br/>wait_for_ci"}
        DIAG_CI["★ diagnose_ci<br/>━━━━━━━━━━<br/>run_skill: /autoskillit:diagnose-ci<br/>gh logs → failure_type, is_fixable<br/>writes temp/diagnose-ci/diagnosis_*.md"]
        RES_CI["● resolve_ci<br/>━━━━━━━━━━<br/>resolve-failures + diagnosis_path<br/>retries: 2"]
        RE_PUSH["re_push<br/>━━━━━━━━━━<br/>push_to_remote MCP"]
    end

    subgraph AP2 ["AP2 Fix: PR Merge Pipeline Push (pr-merge-pipeline)"]
        direction TB
        MERGE_LOOP["merge_pr loop<br/>━━━━━━━━━━<br/>sequential PR merges<br/>no intermediate pushes"]
        PUSH_INT["● push_integration_branch<br/>━━━━━━━━━━<br/>push_to_remote MCP tool<br/>(was: run_cmd git push)"]
        CI_WATCH_PR{"● ci_watch_pr<br/>━━━━━━━━━━<br/>wait_for_ci: integration branch"}
        DIAG_CI_PR["★ diagnose_ci_pr<br/>━━━━━━━━━━<br/>run_skill: /autoskillit:diagnose-ci<br/>observability only — no auto-retry"]
    end

    %% FLOW: Branch Creation %%
    START --> COMPUTE
    COMPUTE -->|"proposed_branch captured"| CUB
    CUB -->|"merge_target captured"| PUSH_MT
    PUSH_MT --> PLAN

    %% FLOW: Core Loop %%
    PLAN --> TEST
    TEST -->|"pass"| MERGE
    TEST -->|"fail"| FIX
    FIX --> TEST
    MERGE -->|"success"| PUSH_PR

    %% FLOW: CI failure path %%
    PUSH_PR --> CI_WATCH
    CI_WATCH -->|"success"| DONE
    CI_WATCH -->|"failure"| DIAG_CI
    DIAG_CI -->|"diagnosis_path → resolve_ci<br/>(success OR failure)"| RES_CI
    RES_CI -->|"success"| RE_PUSH
    RES_CI -->|"exhausted / failure"| ESCALATE
    RE_PUSH -->|"loop back"| CI_WATCH

    %% FLOW: PR merge pipeline (parallel flow) %%
    MERGE_LOOP -->|"all PRs merged"| PUSH_INT
    PUSH_INT --> CI_WATCH_PR
    CI_WATCH_PR -->|"success"| DONE
    CI_WATCH_PR -->|"failure"| DIAG_CI_PR
    DIAG_CI_PR -->|"always → cleanup_failure"| ESCALATE

    %% CLASS ASSIGNMENTS %%
    class START,DONE,ESCALATE terminal;
    class COMPUTE,MERGE,PUSH_MT,RE_PUSH,PUSH_PR,PLAN,MERGE_LOOP handler;
    class CUB,DIAG_CI,DIAG_CI_PR,PUSH_INT newComponent;
    class RES_CI phase;
    class CI_WATCH,CI_WATCH_PR stateNode;
    class TEST detector;
Loading

Error/Resilience Diagram

%%{init: {'flowchart': {'nodeSpacing': 45, 'rankSpacing': 55, 'curve': 'basis'}}}%%
flowchart TB
    %% CLASS DEFINITIONS %%
    classDef terminal fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;
    classDef stateNode fill:#004d40,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef handler fill:#e65100,stroke:#ffb74d,stroke-width:2px,color:#fff;
    classDef phase fill:#6a1b9a,stroke:#ba68c8,stroke-width:2px,color:#fff;
    classDef newComponent fill:#2e7d32,stroke:#81c784,stroke-width:2px,color:#fff;
    classDef output fill:#00695c,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef detector fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#fff;
    classDef gap fill:#ff6f00,stroke:#ffa726,stroke-width:2px,color:#000;

    T_SUCCESS([CI PASSED])
    T_ESCALATE([ESCALATED])
    T_CLEANUP([CLEANUP FAILURE])

    subgraph AP3_RES ["AP3: Branch Collision Guard (create_unique_branch)"]
        direction LR
        LS_REMOTE["● ls-remote check<br/>━━━━━━━━━━<br/>refs/heads/{proposed_branch}"]
        SUFFIX{"collision?"}
        CHECKOUT["git checkout -b<br/>━━━━━━━━━━<br/>atomic branch creation"]
        SUFFIX_N["append suffix<br/>━━━━━━━━━━<br/>-2, -3, ... -100"]
    end

    subgraph AP1_IMPL ["AP1: CI Failure Recovery (implementation / audit-and-fix / remediation)"]
        direction TB
        CI_WATCH{"● ci_watch<br/>━━━━━━━━━━<br/>wait_for_ci<br/>success | failure"}
        DIAG_CI["★ diagnose_ci<br/>━━━━━━━━━━<br/>/autoskillit:diagnose-ci<br/>classifies: test|lint|build<br/>writes diagnosis_*.md<br/>captures: diagnosis_path"]
        RES_CI["● resolve_ci<br/>━━━━━━━━━━<br/>resolve-failures + diagnosis_path<br/>retries: 2"]
        RE_PUSH["re_push<br/>━━━━━━━━━━<br/>push_to_remote MCP<br/>re-triggers CI watch loop"]
    end

    subgraph AP1_PR ["AP1: Integration CI Observability (pr-merge-pipeline)"]
        direction TB
        CI_WATCH_PR{"● ci_watch_pr<br/>━━━━━━━━━━<br/>wait_for_ci: integration branch"}
        DIAG_CI_PR["★ diagnose_ci_pr<br/>━━━━━━━━━━<br/>/autoskillit:diagnose-ci<br/>observability only<br/>NO automated remediation"]
    end

    subgraph TEST_LOOP ["Test-Fix Loop (all recipes)"]
        direction LR
        TEST_GATE{"test passes?<br/>━━━━━━━━━━<br/>task test-check"}
        FIX["fix<br/>━━━━━━━━━━<br/>resolve-failures<br/>no hard retry limit"]
    end

    LS_REMOTE --> SUFFIX
    SUFFIX -->|"no collision"| CHECKOUT
    SUFFIX -->|"collision"| SUFFIX_N
    SUFFIX_N -->|"retry ls-remote"| SUFFIX
    CHECKOUT --> TEST_GATE

    TEST_GATE -->|"pass"| CI_WATCH
    TEST_GATE -->|"fail"| FIX
    FIX -->|"retry"| TEST_GATE

    CI_WATCH -->|"success"| T_SUCCESS
    CI_WATCH -->|"failure"| DIAG_CI
    DIAG_CI -->|"success OR failure"| RES_CI
    RES_CI -->|"resolved"| RE_PUSH
    RES_CI -->|"exhausted (retry 2)"| T_ESCALATE
    RE_PUSH -->|"re-triggers CI loop"| CI_WATCH

    CI_WATCH_PR -->|"success"| T_SUCCESS
    CI_WATCH_PR -->|"failure"| DIAG_CI_PR
    DIAG_CI_PR -->|"always (no auto-retry)"| T_CLEANUP

    class T_SUCCESS,T_ESCALATE,T_CLEANUP terminal;
    class LS_REMOTE,RE_PUSH,FIX handler;
    class CHECKOUT output;
    class SUFFIX_N phase;
    class DIAG_CI,DIAG_CI_PR newComponent;
    class RES_CI phase;
    class SUFFIX,CI_WATCH,CI_WATCH_PR,TEST_GATE detector;
Loading

Closes #238

Implementation Plan

Plan file: /home/talon/projects/autoskillit-runs/impl-20260309-163144-711104/temp/make-plan/orchestrator_anti_patterns_fix_plan_2026-03-09_120000.md

Token Usage Summary

Token Usage Summary

Step input output cache_create cache_read
plan 5,385 206,073 565,097 7,786,890
verify 229 117,284 463,772 7,676,097
implement 12,168 439,202 1,182,612 73,253,502
fix 320 158,164 467,166 23,403,907
audit_impl 528 99,514 389,958 2,613,670
open_pr 104 52,902 189,905 4,079,028
review_pr 10,284 216,697 565,519 7,468,841
resolve_review 387 136,019 448,381 20,173,933
Total 60,783 1,738,007 5,316,054 161,843,046

Step Timing Summary

Step Timing Summary

Step Duration Invocations
clone 1s 1
capture_base_sha 0s 1
set_merge_target 0s 1
create_branch 1s 1
push_merge_target 1s 1
plan 5m 17s 1
verify 4m 37s 1
implement 8m 54s 1
fix 5m 47s 1
test 1m 34s 2
merge 1m 30s 1
audit_impl 3m 2s 1
push 1s 1
Total 31m 5s

🤖 Generated with Claude Code via AutoSkillit

Trecek and others added 11 commits March 9, 2026 16:59
- tests/recipe/test_anti_pattern_guards.py: new file with AP1-AP5 guards
- tests/workspace/test_skills.py: add diagnose-ci to BUNDLED_SKILLS and test_diagnose_ci_skill_is_resolvable
- tests/server/test_tools_git.py: add test for base_branch_name parameter on create_unique_branch
New bundled skill that fetches CI logs via gh CLI, classifies the
failure type (test/lint/build/type_check/env/unknown), and writes a
structured diagnosis report to temp/diagnose-ci/. Orchestrators route
to this skill on ci_watch failure before resolve-failures.
When base_branch_name is provided, it is used directly as the base name
instead of composing from slug+issue_number. The ls-remote collision
check and -2/-3 suffix logic apply regardless of which path is taken.

Also makes slug and remote optional (default "" and "origin") so the
new base_branch_name path can be the sole entry point without requiring
callers to pass empty slug and issue_number.
AP5: Add step_name to capture_base_sha and set_merge_target run_cmd steps
AP3: Replace create_branch bash script with compute_branch (run_cmd, name only)
     + create_branch (create_unique_branch MCP tool); update claim_issue routing
AP1: Add diagnose_ci step between ci_watch failure and resolve_ci; update
     ci_watch.on_failure and resolve_ci.skill_command to include diagnosis_path
Same changes as implementation.yaml: step_name on capture_base_sha and
set_merge_target, compute_branch + create_unique_branch for AP3,
diagnose_ci step for AP1.
…P1/AP2/AP5

AP5: Add step_name to all unnamed run_cmd steps in both recipes
AP2: Switch push_integration_branch from run_cmd to push_to_remote MCP tool;
     add kitchen rule forbidding intermediate pushes inside the merge loop
AP1: Add diagnose_ci_pr step; change ci_watch_pr.on_failure to diagnose_ci_pr
…AP3/AP5

AP5: Add step_name to set_merge_target run_cmd steps
AP3: Replace create_branch bash script with compute_branch + create_unique_branch
     MCP tool; update claim_issue routing to compute_branch
AP1: Add diagnose_ci step; change ci_watch.on_failure to diagnose_ci;
     update resolve_ci.skill_command to include diagnosis_path
Add diagnose-ci to the Bundled AutoSkillit Skills section of write-recipe/SKILL.md
and to the skills directory listing in CLAUDE.md.
New recipe that shares clone/base_sha/set_merge_target setup once across
all issues, then loops per-issue for get_issue_title → claim_issue →
compute_branch → create_branch → implement → push → open_pr_step.

Full loop state accumulation deferred to after write_telemetry_files (#237) lands.
This delivers the shared-setup structure and reduces setup overhead from O(n) to O(1).
Auto-fix ruff format issues in test files; shorten test docstring
in test_tools_git.py to satisfy E501 line length limit.
- Fix create_unique_branch parameter order (restore slug/issue_number/remote/cwd
  to match legacy call signature; add base_branch_name as addl optional param)
- Fix batch-implementation.yaml YAML syntax error (quote summary with colons)
- Add current_issue_url/current_issue_task as ingredients; replace context.
  references with inputs. to satisfy skip-when-false-undeclared rule
- Remove dead base_sha capture; fix issue_title dead-output in batch recipe
- Add capture_list/glob note to implement step for multipart-plan compliance
- Fix unbounded-cycle errors via cleanup_failure exits in get_issue_title/
  claim_issue/release_issue_failure
- Add diagnose-ci to skill_contracts.yaml with outputs contract
- Fix diagnose_ci_pr: add capture + on_result to satisfy implicit-handoff
  and dead-output rules simultaneously
- Update test_bundled_recipes.py: check compute_branch.cmd instead of
  create_branch.cmd; update ci_watch on_failure assertions to diagnose_ci
- Update test_issue_url_pipeline.py: check compute_branch.cmd for slug fallback;
  update claim_issue routing assertion to compute_branch
- Update test_pr_merge_pipeline.py: update ci_watch_pr routing to diagnose_ci_pr

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Collaborator Author

@Trecek Trecek left a comment

Choose a reason for hiding this comment

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

AutoSkillit Review Findings

Verdict: changes_requested

9 actionable findings (clear fixes available) + 1 decision finding (requires human judgment).

src/autoskillit/recipes/batch-implementation.yaml

Line Severity Dimension Message
383 warning bugs create_branch runs inside the batch loop against the same shared clone. After the first issue's feature branch is created, subsequent iterations branch from the current HEAD (the prior feature branch) rather than base_branch. There is no git checkout base_branch between iterations, so branches stack on each other.
402 warning bugs The 'implement' step invokes /autoskillit:make-plan (planning only), but on_success routes to open_pr_step which opens a PR — implying working code is present. A TODO comment acknowledges this, but opening a PR after make-plan with no actual implementation step will produce empty PRs. Should this step use implement-worktree-no-merge instead? ⚠️ requires_decision
454 warning bugs next_or_done_issue uses ${{ result.next }} == more_issues but action: route calls no tool and no prior step produces a next field. The routing condition is permanently unsatisfiable — the pipeline always routes to confirm_cleanup and never loops back to get_issue_title.

src/autoskillit/recipes/pr-merge-pipeline.yaml

Line Severity Dimension Message
880 warning cohesion Step is named 'diagnose_ci_pr' here but 'diagnose_ci' in all other recipes (implementation.yaml, implementation-groups.yaml, audit-and-fix.yaml, remediation.yaml). The '_pr' suffix breaks cross-recipe naming symmetry without adding structural distinction.
888 warning cohesion diagnose_ci_pr uses 'on_result' with a single unconditional route to 'cleanup_failure', while all sibling diagnose_ci steps use 'on_success'/'on_failure' routing. The asymmetric routing pattern diverges from the established convention for this step type across every other recipe.

src/autoskillit/server/tools_git.py

Line Severity Dimension Message
1099 warning defense create_unique_branch has no validation guard: if base_branch_name is None and slug is also empty (both are defaults), base_name becomes '' or '-{issue_number}' — both invalid git branch names. Add a defensive check that raises an error when neither base_branch_name nor slug is provided.
1103 warning defense base_branch_name is typed str

tests/recipe/test_anti_pattern_guards.py

Line Severity Dimension Message
1381 warning tests test_implementation_groups_ci_failure_routes_to_diagnose_ci asserts only ci_watch.on_failure == 'diagnose_ci' and step existence, but its sister test for implementation.yaml also asserts diag.tool == 'run_skill' and 'diagnosis_path' in diag.capture. The weaker assertions here mean a misconfigured diagnose_ci step (wrong tool or missing capture) would pass undetected for implementation-groups.
1409 warning tests test_pr_merge_pipeline_has_no_loop_push_kitchen_rule uses fragile prose substring matching ('NEVER push inside the' or 'no intermediate push') on a joined rule string. Any rewording (e.g. 'NEVER push within the') silently breaks the guard. Prefer asserting a stable structural property instead.

tests/server/test_tools_git.py

Line Severity Dimension Message
1649 warning tests The generator expression passed to next() has no default, so if no subprocess call contains 'ls-remote' in its args, next() raises a bare StopIteration with no diagnostic message. Add next(..., None) and assert the result for a readable failure.

… quality

- batch-implementation: add checkout_base step before create_branch to
  prevent feature branches stacking on prior iteration's HEAD
- batch-implementation: fix unsatisfiable routing in next_or_done_issue
  (result.next never set); use inputs.current_issue_url instead
- pr-merge-pipeline: rename diagnose_ci_pr → diagnose_ci for cross-recipe
  naming symmetry; replace unconditional on_result with on_success/on_failure
- pr-merge-pipeline: add dead-output exemption in _analysis.py for
  diagnosis_path observability captures (parallel to cleanup_succeeded)
- tools_git.create_unique_branch: guard against empty base_branch_name
  (truthy check instead of is not None); error when neither base_branch_name
  nor slug is provided
- test_anti_pattern_guards: strengthen implementation-groups diagnose_ci
  assertions (add tool and capture checks); replace fragile prose matching
  in loop-push test with structural push_to_remote step set assertion
- test_tools_git: add default to next() call to produce readable failure

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Trecek
Copy link
Collaborator Author

Trecek commented Mar 10, 2026

Collapsed into integration PR #288 (#288)

@Trecek Trecek closed this Mar 10, 2026
Trecek added a commit that referenced this pull request Mar 10, 2026
## Integration Summary

Collapsed 4 PRs into `pr-batch/pr-merge-20260309-184208` targeting
`main`.

## Merged PRs

| # | Title | Complexity | Additions | Deletions | Overlaps |
|---|-------|-----------|-----------|-----------|---------|
| #281 | Track MCP Tool Response Token Counts in Diagnostic Logging |
simple | +616 | -12 | — |
| #280 | Rectify: Recipe Diagram Renderer — Graph Model Unification —
PART A ONLY | needs_check | +727 | -152 | #281 |
| #285 | Fix Orchestrator Anti-Patterns Identified by run_cmd Pattern
Mining | needs_check | +909 | -181 | #281, #280 |
| #284 | Phase 3 — Registration Consolidation and chefs-hat CLI |
needs_check | +608 | -333 | #281, #285 |

## Architecture Impact

### Development Diagram

```mermaid
%%{init: {'flowchart': {'nodeSpacing': 50, 'rankSpacing': 60, 'curve': 'basis'}}}%%
flowchart TB
    %% CLASS DEFINITIONS %%
    classDef cli fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;
    classDef stateNode fill:#004d40,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef handler fill:#e65100,stroke:#ffb74d,stroke-width:2px,color:#fff;
    classDef phase fill:#6a1b9a,stroke:#ba68c8,stroke-width:2px,color:#fff;
    classDef newComponent fill:#2e7d32,stroke:#81c784,stroke-width:2px,color:#fff;
    classDef output fill:#00695c,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef detector fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#fff;

    subgraph Structure ["PROJECT STRUCTURE"]
        direction LR
        SRC["src/autoskillit/<br/>━━━━━━━━━━<br/>101 source files<br/>9 sub-packages"]
        TESTS["tests/<br/>━━━━━━━━━━<br/>160 test files<br/>arch/cli/recipe/server..."]
    end

    subgraph Build ["● BUILD TOOLING"]
        direction LR
        PYPROJECT["● pyproject.toml<br/>━━━━━━━━━━<br/>hatchling backend<br/>uv package manager<br/>Python >=3.11"]
        TASKFILE["Taskfile.yml<br/>━━━━━━━━━━<br/>test-all / test-check<br/>install-worktree"]
        UVLOCK["● uv.lock<br/>━━━━━━━━━━<br/>Pinned dependencies<br/>10 runtime + 7 dev"]
    end

    subgraph Quality ["CODE QUALITY GATES (pre-commit)"]
        direction LR
        FORMAT["ruff-format<br/>━━━━━━━━━━<br/>Auto-format<br/>line-length=99"]
        LINT["ruff check<br/>━━━━━━━━━━<br/>E/F/I/UP/TID251<br/>banned: logging.getLogger"]
        TYPES["mypy<br/>━━━━━━━━━━<br/>src/ --ignore-missing-imports<br/>layer contracts enforced"]
        SECRETS["gitleaks<br/>━━━━━━━━━━<br/>Secret scanning<br/>v8.30.0"]
        NOCONFIGS["no-generated-configs<br/>━━━━━━━━━━<br/>Blocks hooks.json<br/>settings.json diagrams/"]
    end

    subgraph Testing ["TEST FRAMEWORK"]
        direction LR
        PYTEST["pytest + asyncio<br/>━━━━━━━━━━<br/>asyncio_mode=auto<br/>timeout=60s"]
        XDIST["pytest-xdist<br/>━━━━━━━━━━<br/>-n 4 parallel workers<br/>safe parallel execution"]
        IMPORTLINTER["import-linter<br/>━━━━━━━━━━<br/>6 layer contracts<br/>L0→L1→L2→L3"]
    end

    subgraph NewPipeline ["★ NEW PIPELINE COMPONENT"]
        MCPRESP["★ mcp_response.py<br/>━━━━━━━━━━<br/>DefaultMcpResponseLog<br/>per-tool response tracking"]
    end

    subgraph EntryPoints ["ENTRY POINTS"]
        direction LR
        CLI["● autoskillit<br/>━━━━━━━━━━<br/>● app.py (serve/init/config)<br/>● _doctor.py / _marketplace.py"]
        CHEFHAT["★ chefs-hat<br/>━━━━━━━━━━<br/>★ _chefs_hat.py<br/>Ephemeral skill session launcher"]
    end

    %% FLOW %%
    SRC --> PYPROJECT
    TESTS --> PYPROJECT
    PYPROJECT --> UVLOCK
    PYPROJECT --> TASKFILE

    PYPROJECT --> FORMAT
    FORMAT --> LINT
    LINT --> TYPES
    TYPES --> SECRETS
    SECRETS --> NOCONFIGS

    NOCONFIGS --> PYTEST
    PYTEST --> XDIST
    PYTEST --> IMPORTLINTER

    SRC --> NewPipeline
    NewPipeline --> MCPRESP

    PYPROJECT --> CLI
    PYPROJECT --> CHEFHAT

    %% CLASS ASSIGNMENTS %%
    class SRC,TESTS cli;
    class PYPROJECT,TASKFILE,UVLOCK phase;
    class FORMAT,LINT,TYPES,SECRETS,NOCONFIGS detector;
    class PYTEST,XDIST,IMPORTLINTER handler;
    class MCPRESP newComponent;
    class CLI output;
    class CHEFHAT newComponent;
```

### Data Lineage Diagram

```mermaid
%%{init: {'flowchart': {'nodeSpacing': 50, 'rankSpacing': 60, 'curve': 'basis'}}}%%
flowchart LR
    %% CLASS DEFINITIONS %%
    classDef cli fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;
    classDef stateNode fill:#004d40,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef handler fill:#e65100,stroke:#ffb74d,stroke-width:2px,color:#fff;
    classDef phase fill:#6a1b9a,stroke:#ba68c8,stroke-width:2px,color:#fff;
    classDef newComponent fill:#2e7d32,stroke:#81c784,stroke-width:2px,color:#fff;
    classDef output fill:#00695c,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef integration fill:#c62828,stroke:#ef9a9a,stroke-width:2px,color:#fff;
    classDef detector fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#fff;

    subgraph MCPFlow ["★ MCP RESPONSE TRACKING FLOW (PR #281)"]
        direction LR
        TOOL["● MCP Tool Handlers<br/>━━━━━━━━━━<br/>tools_*.py<br/>returns: str | dict"]
        DECORATOR["★ track_response_size<br/>━━━━━━━━━━<br/>● server/helpers.py<br/>json.dumps → UTF-8 encode<br/>bytes // 4 = tokens"]
        RESPLOG["★ DefaultMcpResponseLog<br/>━━━━━━━━━━<br/>★ pipeline/mcp_response.py<br/>McpResponseEntry per tool<br/>invocation_count, bytes, tokens"]
        THRESHOLD["● config/settings.py<br/>━━━━━━━━━━<br/>alert_threshold_tokens<br/>● defaults.yaml"]
    end

    subgraph TokenSummary ["● TOKEN SUMMARY AGGREGATION"]
        direction TB
        TOKLOG["TokenLog<br/>━━━━━━━━━━<br/>pipeline/tokens.py<br/>per-step token counts"]
        GETSUMMARY["● get_token_summary<br/>━━━━━━━━━━<br/>● tools_status.py<br/>merges token + ★ mcp_responses"]
    end

    subgraph TelemetryOut ["TELEMETRY ARTIFACTS (write-only)"]
        direction TB
        TOKMD["token_summary.md<br/>━━━━━━━━━━<br/>Markdown table<br/>per-step tokens"]
        TIMEMD["timing_summary.md<br/>━━━━━━━━━━<br/>Markdown table<br/>per-step timing"]
        MCPJSON["★ mcp_response_metrics.json<br/>━━━━━━━━━━<br/>JSON per-tool response stats<br/>bytes + estimated tokens"]
    end

    subgraph RecipeFlow ["● RECIPE DIAGRAM FLOW (PR #280)"]
        direction LR
        YAML["Recipe YAML<br/>━━━━━━━━━━<br/>recipes/*.yaml<br/>step definitions"]
        LOADER["load_recipe()<br/>━━━━━━━━━━<br/>recipe/io.py<br/>→ Recipe dataclass"]
        GRAPH["● build_recipe_graph()<br/>━━━━━━━━━━<br/>● recipe/_analysis.py<br/>→ igraph.Graph<br/>vertex/edge attrs"]
        LAYOUT["● _compute_layout()<br/>━━━━━━━━━━<br/>● recipe/diagrams.py<br/>FOR EACH cycle detect<br/>back-edge flags"]
        DIAGRAMMD["● recipes/diagrams/{stem}.md<br/>━━━━━━━━━━<br/>● v6 format diagram<br/>SHA-256 hash embedded"]
    end

    subgraph ValidationFlow ["● ANTI-PATTERN VALIDATION FLOW (PR #285)"]
        direction LR
        YAML2["Recipe YAML<br/>━━━━━━━━━━<br/>recipes/*.yaml"]
        CONTRACTS["● skill_contracts.yaml<br/>━━━━━━━━━━<br/>Skill tool contracts<br/>● recipe/"]
        ANALYSIS["● analyze_dataflow()<br/>━━━━━━━━━━<br/>● recipe/_analysis.py<br/>BFS passes: dead outputs<br/>implicit handoffs, ref invalidations"]
        REPORT["DataFlowReport<br/>━━━━━━━━━━<br/>recipe/schema.py<br/>warnings: list[DataFlowWarning]<br/>DEAD_OUTPUT / IMPLICIT_HANDOFF<br/>REF_INVALIDATED"]
        SEMRULES["Semantic Rules<br/>━━━━━━━━━━<br/>recipe/rules_*.py<br/>ValidationContext<br/>→ RuleFindings"]
    end

    %% MCP TRACKING FLOW %%
    TOOL -->|"return value"| DECORATOR
    THRESHOLD -->|"alert_threshold_tokens"| DECORATOR
    DECORATOR -->|"record(tool_name, bytes, tokens)"| RESPLOG
    RESPLOG -->|"get_report()"| GETSUMMARY
    TOKLOG -->|"get_report()"| GETSUMMARY
    GETSUMMARY -.->|"write-only"| TOKMD
    GETSUMMARY -.->|"write-only"| TIMEMD
    GETSUMMARY -.->|"★ write-only"| MCPJSON

    %% RECIPE DIAGRAM FLOW %%
    YAML -->|"parse YAML"| LOADER
    LOADER -->|"Recipe dataclass"| GRAPH
    GRAPH -->|"igraph.Graph"| LAYOUT
    LAYOUT -.->|"atomic write"| DIAGRAMMD

    %% VALIDATION FLOW %%
    YAML2 -->|"parse"| LOADER
    CONTRACTS -->|"read"| ANALYSIS
    LOADER -->|"Recipe dataclass"| ANALYSIS
    ANALYSIS -->|"DataFlowReport"| REPORT
    REPORT -->|"ValidationContext"| SEMRULES

    %% CLASS ASSIGNMENTS %%
    class TOOL,YAML,YAML2 cli;
    class DECORATOR newComponent;
    class RESPLOG newComponent;
    class THRESHOLD phase;
    class TOKLOG stateNode;
    class GETSUMMARY handler;
    class TOKMD,TIMEMD output;
    class MCPJSON newComponent;
    class LOADER phase;
    class GRAPH handler;
    class LAYOUT handler;
    class DIAGRAMMD output;
    class CONTRACTS stateNode;
    class ANALYSIS handler;
    class REPORT stateNode;
    class SEMRULES detector;
```

### Module Dependency Diagram

```mermaid
%%{init: {'flowchart': {'nodeSpacing': 50, 'rankSpacing': 70, 'curve': 'basis'}}}%%
graph TB
    %% CLASS DEFINITIONS %%
    classDef cli fill:#1a237e,stroke:#7986cb,stroke-width:2px,color:#fff;
    classDef phase fill:#6a1b9a,stroke:#ba68c8,stroke-width:2px,color:#fff;
    classDef handler fill:#e65100,stroke:#ffb74d,stroke-width:2px,color:#fff;
    classDef stateNode fill:#004d40,stroke:#4db6ac,stroke-width:2px,color:#fff;
    classDef newComponent fill:#2e7d32,stroke:#81c784,stroke-width:2px,color:#fff;
    classDef integration fill:#c62828,stroke:#ef9a9a,stroke-width:2px,color:#fff;
    classDef detector fill:#b71c1c,stroke:#ef5350,stroke-width:2px,color:#fff;

    subgraph L3 ["L3 — APPLICATION (cli/ + server/)"]
        direction LR
        CLIAPP["● cli/app.py<br/>━━━━━━━━━━<br/>serve/init/config/doctor<br/>skills/recipes/workspace"]
        CHEFHAT["★ cli/_chefs_hat.py<br/>━━━━━━━━━━<br/>chefs-hat command<br/>ephemeral skill session"]
        CLIDOC["● cli/_doctor.py<br/>● cli/_init_helpers.py<br/>● cli/_marketplace.py<br/>━━━━━━━━━━<br/>CLI sub-commands"]
        SRVHELPER["● server/helpers.py<br/>━━━━━━━━━━<br/>★ track_response_size<br/>wraps all tool handlers"]
        SRVTOOLS["● server/tools_*.py<br/>━━━━━━━━━━<br/>36 MCP tool handlers<br/>all decorated by helpers"]
    end

    subgraph L2 ["L2 — DOMAIN (recipe/ + migration/)"]
        direction LR
        ANALYSIS["● recipe/_analysis.py<br/>━━━━━━━━━━<br/>build_recipe_graph()<br/>analyze_dataflow()<br/>igraph.Graph model"]
        DIAGRAMS["● recipe/diagrams.py<br/>━━━━━━━━━━<br/>_compute_layout()<br/>v6 format + SHA-256"]
        RULES["● recipe/rules_*.py<br/>━━━━━━━━━━<br/>semantic rules<br/>anti-pattern guards"]
        CONTRACTS["● recipe/skill_contracts.yaml<br/>━━━━━━━━━━<br/>tool contract data<br/>read by _analysis.py"]
    end

    subgraph L1 ["L1 — SERVICES (pipeline/ + config/ + execution/ + workspace/)"]
        direction LR
        MCPRESP["★ pipeline/mcp_response.py<br/>━━━━━━━━━━<br/>McpResponseEntry<br/>DefaultMcpResponseLog<br/>per-tool byte/token tracking"]
        CTX["● pipeline/context.py<br/>━━━━━━━━━━<br/>ToolContext DI container<br/>● +response_log field"]
        CFGSETTINGS["● config/settings.py<br/>━━━━━━━━━━<br/>AutomationConfig<br/>● +mcp_response section"]
        CFGYAML["● config/defaults.yaml<br/>━━━━━━━━━━<br/>● alert_threshold_tokens<br/>● alert_on_threshold"]
    end

    subgraph L0 ["L0 — FOUNDATION (core/)"]
        direction LR
        CORETYPES["● core/types.py<br/>━━━━━━━━━━<br/>StrEnums, protocols<br/>constants"]
        COREINIT["● core/__init__.py<br/>━━━━━━━━━━<br/>Re-exports public surface"]
    end

    subgraph External ["EXTERNAL PACKAGES"]
        direction LR
        IGRAPH["igraph<br/>━━━━━━━━━━<br/>Graph model<br/>subcomponent() for cycles"]
        FASTMCP["fastmcp<br/>━━━━━━━━━━<br/>MCP server framework<br/>tool registration"]
        CYCLOPTS["cyclopts<br/>━━━━━━━━━━<br/>CLI framework<br/>★ chefs-hat entry"]
        STRUCTLOG["structlog<br/>━━━━━━━━━━<br/>Structured logging"]
    end

    %% L3 → L2 dependencies %%
    SRVTOOLS -->|"imports schema, validator"| ANALYSIS
    SRVTOOLS -->|"imports diagrams"| DIAGRAMS
    CLIAPP -->|"imports recipe io"| ANALYSIS

    %% L3 → L1 dependencies %%
    SRVHELPER -->|"★ imports DefaultMcpResponseLog"| MCPRESP
    SRVHELPER -->|"imports ToolContext"| CTX
    SRVTOOLS -->|"imports ToolContext"| CTX
    CLIAPP -->|"imports config"| CFGSETTINGS
    CHEFHAT -->|"imports core paths"| COREINIT

    %% L2 → L1 dependencies %%
    ANALYSIS -->|"imports DataFlowWarning"| CORETYPES
    DIAGRAMS -->|"imports load_recipe"| ANALYSIS

    %% L2 → External %%
    ANALYSIS -->|"igraph.Graph"| IGRAPH

    %% L1 → L1 dependencies %%
    CTX -->|"★ holds response_log"| MCPRESP
    CTX -->|"reads threshold from"| CFGSETTINGS
    CFGSETTINGS -->|"reads defaults"| CFGYAML

    %% L1 → L0 dependencies %%
    MCPRESP -->|"imports StrEnum"| CORETYPES
    CTX -->|"imports protocols"| CORETYPES
    COREINIT -->|"re-exports"| CORETYPES

    %% L3 → External %%
    SRVTOOLS -->|"FastMCP tools"| FASTMCP
    CLIAPP -->|"CLI commands"| CYCLOPTS
    CHEFHAT -->|"★ CLI command"| CYCLOPTS

    %% CLASS ASSIGNMENTS %%
    class CLIAPP,CLIDOC cli;
    class CHEFHAT newComponent;
    class SRVHELPER handler;
    class SRVTOOLS handler;
    class ANALYSIS phase;
    class DIAGRAMS phase;
    class RULES detector;
    class CONTRACTS stateNode;
    class MCPRESP newComponent;
    class CTX stateNode;
    class CFGSETTINGS phase;
    class CFGYAML stateNode;
    class CORETYPES stateNode;
    class COREINIT stateNode;
    class IGRAPH,FASTMCP,CYCLOPTS,STRUCTLOG integration;
```

Closes #223
Closes #229
Closes #238
Closes #270

🤖 Generated with [Claude Code](https://claude.com/claude-code) via
AutoSkillit

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@Trecek Trecek deleted the fix-orchestrator-anti-patterns-identified-by-run-cmd-pattern/238 branch March 10, 2026 02:12
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.

fix: orchestrator anti-patterns identified by run_cmd pattern mining

1 participant