From 9031004df258baea59c4077ba7e54d8aaaf93183 Mon Sep 17 00:00:00 2001 From: Trecek Date: Sat, 27 Jun 2026 05:56:06 -0700 Subject: [PATCH 1/4] Remove phantom ingredient, dispatch section, and dead param Drop batch_dispatch from implementation.yaml, BATCH DISPATCH MODE section from fleet dispatcher prompt, and the now-dead max_issues_per_food_truck parameter from _build_fleet_dispatch_prompt and its ad-hoc call site. The campaign-side max_issues_per_food_truck references in _build_fleet_campaign_prompt and the campaign dispatch path are preserved. --- src/autoskillit/cli/_prompts_kitchen.py | 33 -------------- src/autoskillit/cli/fleet/_fleet_session.py | 1 - src/autoskillit/recipes/implementation.yaml | 5 --- tests/cli/test_fleet_session.py | 26 ----------- .../contracts/test_fleet_dispatch_bem_gate.py | 45 ------------------- 5 files changed, 110 deletions(-) diff --git a/src/autoskillit/cli/_prompts_kitchen.py b/src/autoskillit/cli/_prompts_kitchen.py index b103d843ce..b3584c85cc 100755 --- a/src/autoskillit/cli/_prompts_kitchen.py +++ b/src/autoskillit/cli/_prompts_kitchen.py @@ -95,7 +95,6 @@ def _build_open_kitchen_prompt( def _build_fleet_dispatch_prompt( mcp_prefix: str, recipe_table: str | None = None, - max_issues_per_food_truck: int = 3, max_total_issues: int = 12, max_concurrent_dispatches: int = 3, has_unguarded_filesystem_access: bool = False, @@ -265,38 +264,6 @@ def _build_fleet_dispatch_prompt( BEM already caps parallel group sizes via max_parallel (default 6 issues per group). -## BATCH DISPATCH MODE — OPTIONAL - -When dispatching the `implementation` recipe for multiple issues and the user has set the -`batch_dispatch` ingredient to `"true"`, use batched dispatch instead of per-issue dispatch: - -1. After BEM produces the dispatch_plan, for each parallel group (parallel: true): - a. Chunk the group's issues into sub-groups of up to {max_issues_per_food_truck} issues. - b. Dispatch each chunk as a SINGLE `implement-findings` food truck: - {mcp_prefix}dispatch_food_truck( - recipe="implement-findings", - task="Implement issues #X, #Y, #Z — parallel-safe per BEM group {{N}}", - ingredients={{{{ - "issue_urls": "", - "execution_map": "", - "base_branch": "", - }}}}, - dispatch_name="implement-g{{N}}-{{letter}}", - ) - c. Name chunks sequentially: `implement-g{{N}}-a`, `-b`, `-c` … - d. Issue ALL chunks for a parallel group in a single response (parallel tool calls). - The fleet semaphore gates actual concurrency — if FLEET_PARALLEL_REFUSED is returned, - wait for a running dispatch to complete and retry. - -2. Groups with only 1 issue or sequential groups (parallel: false): dispatch via the - `implementation` recipe as normal — one food truck per issue, not batched. - -3. When `batch_dispatch` is `"false"` (the default): use the standard per-issue dispatch - from Step 4 above — one `implementation` food truck per issue. Do NOT use implement-findings. - -4. The execution_map captured from bem-wrapper MUST be passed as an ingredient to each - implement-findings food truck so BEM is not re-run inside the food truck. - ## DISPATCHER DISCIPLINE You are a fleet dispatcher — NOT an executor. ALL recipe execution must be delegated \ diff --git a/src/autoskillit/cli/fleet/_fleet_session.py b/src/autoskillit/cli/fleet/_fleet_session.py index 8899ff439a..e2b85f558e 100644 --- a/src/autoskillit/cli/fleet/_fleet_session.py +++ b/src/autoskillit/cli/fleet/_fleet_session.py @@ -71,7 +71,6 @@ def _launch_fleet_session( prompt = _build_fleet_dispatch_prompt( mcp_prefix, recipe_table=recipe_table, - max_issues_per_food_truck=cfg.fleet.max_issues_per_food_truck, max_total_issues=cfg.fleet.max_total_issues, max_concurrent_dispatches=cfg.fleet.max_concurrent_dispatches, has_unguarded_filesystem_access=_backend_caps.has_unguarded_filesystem_access, diff --git a/src/autoskillit/recipes/implementation.yaml b/src/autoskillit/recipes/implementation.yaml index b47529a8a5..4aca92365c 100644 --- a/src/autoskillit/recipes/implementation.yaml +++ b/src/autoskillit/recipes/implementation.yaml @@ -46,11 +46,6 @@ ingredients: description: Automatically merge the PR after required checks pass — via merge queue when available, direct merge otherwise default: 'true' - batch_dispatch: - description: Pack multiple parallel-safe issues per food truck. When "true", the - fleet dispatcher batches parallel-safe issues (up to max_issues_per_food_truck) - into implement-findings food trucks with comma-separated issue_urls. - default: 'false' review_max_retries: description: Maximum number of review-resolve retry cycles before proceeding to CI diff --git a/tests/cli/test_fleet_session.py b/tests/cli/test_fleet_session.py index e0e4929a35..fc7fa5625c 100644 --- a/tests/cli/test_fleet_session.py +++ b/tests/cli/test_fleet_session.py @@ -811,32 +811,6 @@ async def test_build_fleet_campaign_prompt_accepts_prior_dispatch_id_parameter( class TestLaunchFleetSessionMaxIssuesPerFoodTruck: """Contract: _launch_fleet_session threads max_issues_per_food_truck to prompt builders.""" - def test_adhoc_dispatch_forwards_max_issues_per_food_truck( - self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path - ) -> None: - """Ad-hoc threads cfg.fleet.max_issues_per_food_truck to _build_fleet_dispatch_prompt.""" - captured: dict = {} - - def _fake_build(*args: object, **kwargs: object) -> str: - captured.update(kwargs) - return "fake-prompt" - - monkeypatch.setattr("autoskillit.cli._prompts._build_fleet_dispatch_prompt", _fake_build) - monkeypatch.setattr( - "autoskillit.cli.session._session_launch._run_interactive_session", - lambda *a, **kw: None, - ) - - config_dir = tmp_path / ".autoskillit" - config_dir.mkdir(exist_ok=True) - (config_dir / "config.yaml").write_text("fleet:\n max_issues_per_food_truck: 7\n") - monkeypatch.chdir(tmp_path) - - from autoskillit.cli.fleet._fleet_session import _launch_fleet_session - - _launch_fleet_session(None, None, None, None, fleet_mode="dispatch") - assert captured.get("max_issues_per_food_truck") == 7 - def test_campaign_dispatch_forwards_max_issues_per_food_truck( self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: diff --git a/tests/contracts/test_fleet_dispatch_bem_gate.py b/tests/contracts/test_fleet_dispatch_bem_gate.py index 1de942b221..a9c513bbbe 100644 --- a/tests/contracts/test_fleet_dispatch_bem_gate.py +++ b/tests/contracts/test_fleet_dispatch_bem_gate.py @@ -98,51 +98,6 @@ def test_fleet_prompt_bem_gate_has_never_block(fleet_prompt: str) -> None: ) -def test_fleet_prompt_contains_batch_dispatch_section(fleet_prompt: str) -> None: - """Fleet dispatcher prompt must contain batch dispatch mode section.""" - assert "BATCH DISPATCH" in fleet_prompt - - -def test_fleet_prompt_batch_section_references_implement_findings(fleet_prompt: str) -> None: - """Batch dispatch section must reference implement-findings recipe.""" - batch_section = fleet_prompt.split("BATCH DISPATCH")[1].split("## DISPATCHER")[0] - assert "implement-findings" in batch_section - - -def test_fleet_prompt_batch_section_references_execution_map(fleet_prompt: str) -> None: - """Batch dispatch section must instruct passing execution_map to implement-findings.""" - batch_section = fleet_prompt.split("BATCH DISPATCH")[1].split("## DISPATCHER")[0] - assert "execution_map" in batch_section - - -def test_fleet_prompt_batch_section_contains_max_issues_cap(fleet_prompt: str) -> None: - """Batch dispatch section must contain the max_issues_per_food_truck cap value.""" - batch_section = fleet_prompt.split("BATCH DISPATCH")[1].split("## DISPATCHER")[0] - assert "3" in batch_section - - -def test_fleet_prompt_batch_section_preserves_single_issue_fallback(fleet_prompt: str) -> None: - """Batch section must instruct fallback to implementation recipe for single-issue groups.""" - batch_section = fleet_prompt.split("BATCH DISPATCH")[1].split("## DISPATCHER")[0] - lower = batch_section.lower() - assert "single" in lower or "1 issue" in lower or "only 1" in lower - - -def test_implementation_recipe_has_batch_dispatch_ingredient() -> None: - """implementation.yaml must expose a visible batch_dispatch ingredient.""" - from autoskillit.core.io import load_yaml - from autoskillit.core.paths import pkg_root - - recipe_yaml = load_yaml(pkg_root() / "recipes" / "implementation.yaml") - ingredients = recipe_yaml["ingredients"] - assert "batch_dispatch" in ingredients, ( - "implementation.yaml must have batch_dispatch ingredient" - ) - bd = ingredients["batch_dispatch"] - assert bd.get("default") == "false", "batch_dispatch must default to 'false'" - assert bd.get("hidden") is not True, "batch_dispatch must be visible (not hidden)" - - def test_fleet_prompt_contains_gated_group_handling(fleet_prompt: str) -> None: assert "gated" in fleet_prompt.lower(), ( "Fleet dispatcher prompt must instruct handling of gated groups " From 7f5730acf33b56b8eba86e22914ad36540286be9 Mon Sep 17 00:00:00 2001 From: Trecek Date: Sat, 27 Jun 2026 05:57:17 -0700 Subject: [PATCH 2/4] chore: regenerate implementation.json after batch_dispatch removal --- src/autoskillit/recipes/implementation.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/autoskillit/recipes/implementation.json b/src/autoskillit/recipes/implementation.json index f0ef050836..c43325888a 100644 --- a/src/autoskillit/recipes/implementation.json +++ b/src/autoskillit/recipes/implementation.json @@ -55,10 +55,6 @@ "description": "Automatically merge the PR after required checks pass — via merge queue when available, direct merge otherwise", "default": "true" }, - "batch_dispatch": { - "description": "Pack multiple parallel-safe issues per food truck. When \"true\", the fleet dispatcher batches parallel-safe issues (up to max_issues_per_food_truck) into implement-findings food trucks with comma-separated issue_urls.", - "default": "false" - }, "review_max_retries": { "description": "Maximum number of review-resolve retry cycles before proceeding to CI", "default": "3" From 9bcafead04cf10ef9a895a5d4e338bfe7ec1995e Mon Sep 17 00:00:00 2001 From: Trecek Date: Sat, 27 Jun 2026 06:02:43 -0700 Subject: [PATCH 3/4] fix: update implementation diagram hash after batch_dispatch ingredient removal --- src/autoskillit/recipes/diagrams/implementation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/autoskillit/recipes/diagrams/implementation.md b/src/autoskillit/recipes/diagrams/implementation.md index 5417ad1358..b41bc5bc3a 100644 --- a/src/autoskillit/recipes/diagrams/implementation.md +++ b/src/autoskillit/recipes/diagrams/implementation.md @@ -1,4 +1,4 @@ - + # implementation From 11cf6bdf204d80f0f86c1f73aa7389a88f23794c Mon Sep 17 00:00:00 2001 From: Trecek Date: Sat, 27 Jun 2026 06:25:46 -0700 Subject: [PATCH 4/4] fix(review): update stale class docstring and add dispatch builder signature guard Update TestLaunchFleetSessionMaxIssuesPerFoodTruck docstring to reflect that only the campaign builder receives max_issues_per_food_truck (ad-hoc test was deleted in previous commit). Add negative-assertion test confirming _build_fleet_dispatch_prompt does not accept this parameter. --- tests/cli/test_fleet_session.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/cli/test_fleet_session.py b/tests/cli/test_fleet_session.py index fc7fa5625c..b20ef33d98 100644 --- a/tests/cli/test_fleet_session.py +++ b/tests/cli/test_fleet_session.py @@ -809,7 +809,7 @@ async def test_build_fleet_campaign_prompt_accepts_prior_dispatch_id_parameter( class TestLaunchFleetSessionMaxIssuesPerFoodTruck: - """Contract: _launch_fleet_session threads max_issues_per_food_truck to prompt builders.""" + """Contract: max_issues_per_food_truck flows to campaign builder only, not dispatch builder.""" def test_campaign_dispatch_forwards_max_issues_per_food_truck( self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path @@ -853,3 +853,10 @@ def _fake_build( fleet_mode="campaign", ) assert captured.get("max_issues_per_food_truck") == 7 + + def test_dispatch_prompt_does_not_accept_max_issues_per_food_truck(self) -> None: + """_build_fleet_dispatch_prompt must not expose max_issues_per_food_truck parameter.""" + from autoskillit.cli._prompts_kitchen import _build_fleet_dispatch_prompt + + sig = inspect.signature(_build_fleet_dispatch_prompt) + assert "max_issues_per_food_truck" not in sig.parameters