Fix #2601: drop "One PR" opener from planner prompts; align both paths on slice-DAG - #2607
Conversation
…s on slice-DAG Both planner prompts in orchestrator/routes/pipelines.py opened with a **CRITICAL CONSTRAINT — One Issue = One Workflow = One PR** opener that directly contradicted the slice-DAG decomposition framing added to the refine-phase prompt in #2597. An operator who selected a multi-slice option during refine would see the planner emit a single-PR plan and the upstream HITL decision became a dead letter. - Concurrent task_planner (role_value path) keeps the existing ## Slice-DAG guidance (#2137) section; drop the contradictory opener and the "do NOT propose multiple PRs" line at the end of the YAML guidance. Reframe the slice packaging note around the slice-DAG section rather than against pr_plan. - Sequential phase=="plan" path (currently only reached via tests, but silently misfires if ever re-routed) gets the same opener removed and a compact mirror of the slice-DAG block appended, so the two paths stay aligned. - Add TestPlannerPromptSliceDagFraming: negative-regression assertions that the opener does not return, plus presence checks for slice-DAG framing on both planner paths. Fixes #2601
There was a problem hiding this comment.
Review
Reviewed the diff (orchestrator/routes/pipelines.py and orchestrator/tests/test_pipeline_prompts.py), traced both planner code paths, verified the test class, and grepped for residual "One PR" framing across the repo.
The core change — dropping the CRITICAL CONSTRAINT — One Issue = One Workflow = One PR opener from both planner prompts and reframing the pr_plan-rejection line around the slice-DAG section — is correct. Production routing for phase="plan" goes through _build_agent_prompt(role_value="task_planner") (the only non-test call site, routes/pipelines.py:12583, is gated to ("coder", "refiner") so the _build_phase_prompt(phase="plan") branch is genuinely test-only); the PR claim about reachability is accurate. The negative-regression tests are well-targeted and pass locally (pytest orchestrator/tests/test_pipeline_prompts.py → 382 passed).
No blocking issues. A few non-blocking observations:
Non-blocking
1. YAML example still shows phases:, but the slice-DAG block tells the planner to prefer slices:. This was already present on the concurrent path before this PR and is now mirrored to the sequential path:
pipelines.py:11150(sequential) andpipelines.py:13111(concurrent) both renderphases:in the canonical YAML example.pipelines.py:11190–11192and13210–13213then sayprefer the canonical \`slices:`` key`.
The agent will copy what it sees in the YAML example — i.e., phases: — so the slices: directive at the end is essentially ornamental until the example switches. Functionally fine because the parser accepts both (shared/egg_contracts/plan_parser.py:442–489), but the prompt teaches the wrong-but-accepted key. Worth a follow-up: switch the YAML examples in both planner paths to slices: (and probably mirror the change in shared/egg_contracts/plan_parser.py:265/420/832-area docstrings).
2. shared/egg_contracts/plan_parser.py:458–469 still asserts "Each issue must produce exactly one PR" in its pr_plan rejection warnings. That phrasing contradicts the slice-DAG architecture this PR is aligning the planners to (slice = PR, so one issue can produce N PRs). The PR doesn't modify the parser — and the parser's intent (use slices:/phases: instead of pr_plan) is still correct — but the user-visible warning text would be more accurate as something like "Use the slices: key to express a slice DAG; pr_plan is not a supported decomposition format." Could be folded into the follow-up above.
3. Sequential planner's slice-DAG block is a compact mirror — drops the worked serialized_chain_order YAML example and the Jaccard fallback heuristic that the concurrent path carries (pipelines.py:13236–13263). Because the sequential path is test-only this asymmetry is harmless today, but if someone ever re-routes that path the planner will know that serialized_chain_order exists without seeing how to populate it. Not worth blocking on; flagging so the asymmetry is a deliberate choice rather than a forgotten copy-paste.
4. Test coverage is presence-based on both planner paths, which is the right minimum for a "remove this phrase, keep that phrase" change. End-to-end "operator picks a multi-slice option → planner emits a multi-slice plan" lives in the integration test domain and isn't blocking for this PR's scope. The class docstring is clear about being a negative-regression suite, which matches what the tests do.
— Authored by egg
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
…ce-DAG framing - pipelines.py: switch the canonical `# yaml-tasks` example from `phases:` to `slices:` in both planner prompts. The slice-DAG block in the same prompt directs the agent to prefer `slices:`, so the example was teaching the wrong-but-accepted key. - pipelines.py: mirror the full slice-DAG block to the sequential planner path — the worked `serialized_chain_order` example and the Jaccard fallback heuristic now appear on both paths. The sequential path is test-only today, but the asymmetry was a forgotten copy-paste rather than a deliberate omission. - plan_parser.py: drop the "Each issue must produce exactly one PR" framing from the two `pr_plan`-rejection warnings; reword to direct authors at `slices:` for decomposition and the singular `pr:` for per-PR metadata. - plan_parser.py: update three docstring examples to use `slices:` (noting `phases:` is still accepted as a backward-compat alias). - test_pipeline_prompts.py: add three regression tests locking in (a) both planner YAML examples use `slices:` not `phases:` and (b) the sequential path now carries the worked example + Jaccard tokens that the concurrent path already had. Refs review feedback on #2607.
Review feedback dispositionsThanks for the thorough trace. Per-item: 1. YAML example uses 2. 3. Sequential planner's slice-DAG block dropped the worked example + Jaccard fallback — 4. Test coverage is presence-based — — Authored by egg |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Re-review
Reviewed the delta (commit f096e54) and confirmed all three actionable items from my previous review on 75376cf are properly fixed in production code, not just superficially. Traced the new code paths, diffed the two planner blocks, and ran both the new regression class (7/7 pass) and the existing pr_plan-warning suite (4/4 pass) locally.
Previous feedback dispositions verified
1. YAML example key swap — fixed correctly.
pipelines.py:11150(sequential) andpipelines.py:13141(concurrent) both now renderslices:instead ofphases:, and the example placeholders are renamedSlice Name/What this slice achievesso the canonical example is internally consistent with the slice-DAG directive a few paragraphs below it.test_sequential_plan_yaml_example_uses_slices_key/test_concurrent_planner_yaml_example_uses_slices_keylock in"\nslices:\n" in promptAND"\nphases:\n" not in prompt. The latter assertion is robust: the slice-DAG block still mentions`phases:`(backticked) as a legacy alias, but that does not match a bare line.
2. Parser warning rewording — fixed and back-compat preserved.
plan_parser.py:463–481drops the "Each issue must produce exactly one PR" framing from bothpr_plan-rejection warnings and reframes them around "useslices:for decomposition, singularpr:for per-PR metadata."- The existing assertions in
tests/shared/egg_contracts/test_plan_parser.py:1011–1086("pr_plan","not supported","without 'slices' or 'phases'") all still match the new messages — I ran them and 4/4 pass. The new context strings ("The 'pr_plan' format is not supported; use 'slices'") are an improvement. - Three docstrings (
:265,:420,:832) now showslices:with an explicit "phases:is also accepted for backward compatibility" note. Backward-compat aliasing inparse_phases_from_yamlat:451–499is unchanged.
3. Sequential path slice-DAG block mirror — fixed cleanly.
pipelines.py:11203–11237now carries the full workedserialized_chain_orderexample block and Jaccard fallback heuristic that the concurrent path had at13258–13293. I diffed the two and the only differences are line-wrap word boundaries (Python string concatenation; same rendered output) and the path-name/trailer (plan_pathvsdraft_path, sequential adds"Commit and push the draft when done.", concurrent appends_build_role_restrictions_section()) — all pre-existing structural differences unrelated to the slice-DAG block.test_sequential_plan_carries_worked_example_and_jaccardlocks in three needles (Worked example,Jaccard,files_affected); grep confirms all three appear on the sequential path now (:11210,:11236,:11236).
4. Test coverage scope disagreement — accepted. Negative-regression presence checks are correct minimum for a "remove this phrase, keep that phrase" change; end-to-end "operator picks multi-slice option → planner emits multi-slice plan" belongs in integration-test scope, not this PR's surface.
No new blocking issues
- Two prompt paths are now structurally aligned; the asymmetry the previous review flagged is gone.
- Worked example uses
slice-Nreferences independencies:/serialized_chain_order:against numericid: 1/2/3slice IDs.to_contract_sliceatplan_parser.py:130–185normalisesslice-Ndeps toslice-N(andphase-Nlegacy →slice-N) before contract emission, so this shape parses correctly. The example is also fragmentary (no parentslices:key) by design — it illustrates only the DAG pattern, while the full structure lives in the canonical example earlier in the prompt. - All three new tests pass via
pytest orchestrator/tests/test_pipeline_prompts.py::TestPlannerPromptSliceDagFraming -v(7/7).
Approving — the previous non-blocking suggestions are now fully addressed and the PR is internally consistent end-to-end.
— Authored by egg
|
egg review completed. View run logs 3 previous review(s) hidden. |
Summary
orchestrator/routes/pipelines.pyopened with**CRITICAL CONSTRAINT — One Issue = One Workflow = One PR**, directly contradicting the slice-DAG decomposition framing added to the refine-phase prompt in Fix #2584: frame refiner work-decomposition decisions on slice-DAG, not PR count #2597. A refine-phase multi-slice HITL decision became a dead letter at plan time.task_plannerpath: drop the contradicting opener and thedo NOT propose multiple PRsline; the existing## Slice-DAG guidance (#2137)block remains the single voice on slice packaging.phase == "plan"path: drop the same opener and append a compact mirror of the slice-DAG block so the two planner paths stay aligned (the sequential path is currently only reached via tests, but silently misfires if ever re-routed).TestPlannerPromptSliceDagFramingcovering both paths — negative-regression on the removed opener plus positive presence checks for the slice-DAG framing tokens.Fixes #2601.
Test plan
.venv/bin/pytest orchestrator/tests/test_pipeline_prompts.py -k TestPlannerPromptSliceDagFraming— 4 new tests pass.make test(changeset-aware) — 2732 passed, 0 failures, 7:43.make lint— clean (existing soft-cap warnings only, untouched files).