Skip to content

Commit 6baab76

Browse files
authored
🤖 fix: improve orchestrator dependency sequencing (#2054)
## Summary Tighten the Orchestrator built-in agent guidance so it reliably sequences dependent `exec` subtasks and only parallelizes patches that can apply + verify independently. ## Background We occasionally spawn a second `exec` task whose implementation/verification depends on outputs from the first task. Since child workspaces snapshot at spawn time and `exec` agents are instructed not to expand scope, the dependent task can become blocked or forced into scope expansion. ## Implementation - Add a required dependency analysis checklist (inputs/outputs + independence criteria) before batching. - Extend the Orchestrator → Exec task brief template with a **Dependencies / assumptions** section. - Replace the vague sequential fallback with an explicit step-by-step protocol (await → apply patch → then spawn dependent). - Include a concrete example dependency chain (schema download → generation). ## Validation - `make static-check` --- <details> <summary>📋 Implementation Plan</summary> # Improve Orchestrator dependency reasoning (task decomposition + sequencing) ## Context / Why The Orchestrator agent (`src/node/builtinAgents/orchestrator.md`) currently encourages batching “independent” subtasks in parallel, with a brief sequential fallback note. In practice it sometimes spawns a second `exec` task whose work/verification *depends on artifacts produced by the first task* (e.g., new schema download targets/files). Because `exec` sub-agents are instructed **not to expand scope**, the dependent task can become impossible to complete cleanly without either: - violating its scope constraints, or - producing a patch that can’t be verified/applied independently. Goal: update the Orchestrator prompt so it reliably (1) detects dependency chains, (2) sequences prerequisite tasks *and integrates their patches* before spawning dependents, and (3) only parallelizes truly mergeable/standalone tasks. ## Evidence (repo facts consulted) - `src/node/builtinAgents/orchestrator.md` - “Patch integration loop (default)” recommends batching independent subtasks and running them with `run_in_background: true`. - “Sequential fallback” is currently a single bullet: “If subtasks depend on one another, do them in order and apply patches between them.” - `src/node/builtinAgents/exec.md` - Child `exec` agents: “Take a single narrowly scoped task… Do not expand scope.” - `src/node/services/tools/task.ts` + `src/common/utils/tools/toolDefinitions.ts` - `task` has only `run_in_background` for sequencing; there is no first-class `dependsOn` DAG concept. - Explore reports (authoritative for referenced files): - Orchestrator prompt location + dependency wording + task spawn logic. - Task/workspace types show parent/child nesting but no dependency graph field; sequencing is done via `run_in_background:false` or `task_await`. ## Recommended approach (A): prompt-only improvements (fast + low risk) **Net LoC estimate (product code):** ~+60 / -10 (mostly `src/node/builtinAgents/orchestrator.md`). ### Implementation details #### 1) Strengthen Orchestrator rules for dependency analysis before batching **File:** `src/node/builtinAgents/orchestrator.md` Add an explicit “Dependency analysis (required)” section *above* “Patch integration loop (default)”. Make it checklist-style to reduce ambiguity. Key rules to add: - **Define subtask IO:** For each candidate subtask, identify: - **Outputs**: files/targets/artifacts the patch introduces/renames (including generated artifacts). - **Inputs**: files/targets/artifacts the task needs to exist to implement *or verify* its work. - **Independence test (must pass to parallelize):** Two tasks may run concurrently only if: 1) each patch can be applied *by itself* on current HEAD (no missing symbols/files), and 2) each task can run its own acceptance/verification commands without needing another pending patch, and 3) they don’t both touch the same “high-conflict” files (same Makefile, same generator entrypoint, etc.). - **If unsure, default to sequential or merge the tasks.** Parallelism is an optimization; correctness is the requirement. Suggested prompt snippet (shape only; adjust wording to match file tone): ```md Dependency analysis (required before spawning `exec` tasks): - For each candidate subtask, write: - Outputs: … - Inputs/prereqs (including for verification): … - A subtask is “independent” only if its patch can land + verify on current HEAD without any other pending patch. - If task B depends on outputs from task A: - Do not spawn B until A has completed and A’s patch is applied in the parent workspace. - If the dependency chain is tight (download → generate → wire-up), prefer a single `exec` task instead of splitting. ``` #### 2) Make “Sequential fallback” operational (concrete steps) Replace the current one-line “Sequential fallback” with an explicit protocol: ```md Sequential protocol (when any dependency exists): 1. Spawn the prerequisite `exec` task with `run_in_background: false` (or spawn, then immediately `task_await`). 2. Apply its patch (dry-run then real). 3. Only after the patch is applied, spawn the dependent `exec` task. 4. Repeat until the chain is complete. ``` Rationale: queued/background tasks inherit the repo snapshot at spawn time; spawning dependents too early makes them work from the wrong base and pushes them toward scope expansion. #### 3) Update the Orchestrator → Exec task brief template to include dependencies/assumptions In `src/node/builtinAgents/orchestrator.md`, extend the template with a dedicated section: ```md - Dependencies / assumptions: - Assumes <prereq patch or file> is already merged into the parent workspace. - If this is not true, stop and report back; do not expand scope to “fix” prerequisites. ``` This gives child agents an explicit “escape hatch” aligned with `exec.md` (report blockers rather than guessing/expanding scope). #### 4) Add a short concrete example tied to the failure mode Add a 6–10 line example showing why “schema download” must precede “generator uses schema files”. Keep it generic, but concrete enough that the model recognizes the pattern. Example (paraphrased): - Task A outputs new schema download targets/files. - Task B reads those files and runs generation/verification. - Therefore: A must be completed + applied before spawning B. ## Optional follow-up (B): first-class task dependencies in code (stronger enforcement) **Net LoC estimate (product code):** ~+250–450. Only do this if prompt-only changes aren’t sufficient. ### Idea Add an explicit dependency field (e.g., `dependsOnWorkspaceIds: string[]`) to the workspace/task schema and teach `TaskService` to avoid starting tasks until prerequisites are `reported`. ### Caveat (important) Because child workspaces are created at `taskService.create()` time, “dependency-aware queueing” alone may still start tasks from the wrong repo snapshot if prerequisites land later. To fully solve this, dependency enforcement likely needs to: - **Delay creating the child workspace/worktree until dependencies are satisfied**, or - create the workspace but rebase/pull from parent just before starting. ### Likely touchpoints - `src/common/orpc/schemas/project.ts`: extend workspace/task schema. - `src/common/utils/tools/toolDefinitions.ts`: optional `dependsOn` param to `task` tool. - `src/node/services/taskService.ts`: enforce dependency readiness when starting queued tasks. - UI: optionally surface “Blocked by …” in `WorkspaceListItem`. <details> <summary>Why not jump straight to code-level dependencies?</summary> Prompt-only updates are low-risk and align with the current tool model (`run_in_background:false` + patch-apply between steps). A code-level DAG is more correct long-term, but it’s easy to implement *part* of it (queueing) while still leaving the core problem (repo snapshot correctness) unsolved. </details> </details> --- _Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `xhigh` • Cost: `$1.83`_ <!-- mux-attribution: model=openai:gpt-5.2 thinking=xhigh costs=1.83 --> --------- Signed-off-by: Thomas Kosiewski <[email protected]>
1 parent 490ba38 commit 6baab76

File tree

3 files changed

+67
-9
lines changed

3 files changed

+67
-9
lines changed

docs/agents/index.mdx

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,9 @@ Delegation guide:
406406
- Deliverables: commits + verification commands to run
407407
- Constraints:
408408
- Do not expand scope.
409-
- Explore as needed (spawn `explore` tasks to fill in missing repo context before editing; skip if starting points + acceptance are already clear).
409+
- Prefer `explore` tasks for repo investigation (paths/symbols/tests/patterns) to preserve your context window for implementation.
410+
Trust Explore reports as authoritative; do not re-verify unless ambiguous/contradictory.
411+
If starting points + acceptance are already clear, skip initial explore and only explore when blocked.
410412
- Create one or more git commits before `agent_report`.
411413

412414
Recommended Orchestrator → Exec task brief template:
@@ -418,15 +420,37 @@ Recommended Orchestrator → Exec task brief template:
418420
- Scope: <what to change>
419421
- Non-goals: <explicitly out of scope>
420422
- Starting points: <paths / symbols / callsites>
423+
- Dependencies / assumptions:
424+
- Assumes: <prereq patch(es) already applied in parent workspace, or required files/targets already exist>
425+
- If unmet: stop and report back; do not expand scope to create prerequisites.
421426
- Acceptance: <bullets / checks>
422427
- Deliverables:
423428
- Commits: <what to commit>
424429
- Verification: <commands to run>
425430
- Constraints:
426431
- Do not expand scope.
427-
- Explore as needed (spawn `explore` tasks to fill in missing repo context before editing; skip if starting points + acceptance are already clear).
432+
- Prefer `explore` tasks for repo investigation (paths/symbols/tests/patterns) to preserve your context window for implementation.
433+
Trust Explore reports as authoritative; do not re-verify unless ambiguous/contradictory.
434+
If starting points + acceptance are already clear, skip initial explore and only explore when blocked.
428435
- Create one or more git commits before `agent_report`.
429436

437+
Dependency analysis (required before spawning `exec` tasks):
438+
439+
- For each candidate subtask, write:
440+
- Outputs: files/targets/artifacts introduced/renamed/generated
441+
- Inputs / prerequisites (including for verification): what must already exist
442+
- A subtask is "independent" only if its patch can be applied + verified on the current parent workspace HEAD, without any other pending patch.
443+
- Default to sequential if unsure. Parallelism is an optimization; correctness is the requirement.
444+
- If task B depends on outputs from task A:
445+
- Do not spawn B until A has completed and A's patch is applied in the parent workspace.
446+
- If the dependency chain is tight (download → generate → wire-up), prefer one `exec` task rather than splitting.
447+
448+
Example dependency chain (schema download → generation):
449+
450+
- Task A outputs: a new download target + new schema files.
451+
- Task B inputs: those schema files; verifies by running generation.
452+
- Therefore: run Task A (await + apply patch) before spawning Task B.
453+
430454
Patch integration loop (default):
431455

432456
1. Identify a batch of independent subtasks.
@@ -441,9 +465,14 @@ Patch integration loop (default):
441465
- PASS: summary-only (no long logs).
442466
- FAIL: include the failing command + key error lines; then delegate a fix to `exec` and re-verify.
443467

444-
Sequential fallback:
468+
Sequential protocol (when any dependency exists):
469+
470+
1. Spawn the prerequisite `exec` task with `run_in_background: false` (or spawn, then immediately `task_await`).
471+
2. Dry-run apply its patch; then apply for real.
472+
3. Only after the patch is applied, spawn the dependent `exec` task.
473+
4. Repeat until the dependency chain is complete.
445474

446-
- If subtasks depend on one another, do them in order and apply patches between them.
475+
Note: child workspaces are created at spawn time. Spawning dependents too early means they work from the wrong repo snapshot and get forced into scope expansion.
447476

448477
Keep context minimal:
449478

src/node/builtinAgents/orchestrator.md

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ Delegation guide:
5252
- Deliverables: commits + verification commands to run
5353
- Constraints:
5454
- Do not expand scope.
55-
- Explore as needed (spawn `explore` tasks to fill in missing repo context before editing; skip if starting points + acceptance are already clear).
55+
- Prefer `explore` tasks for repo investigation (paths/symbols/tests/patterns) to preserve your context window for implementation.
56+
Trust Explore reports as authoritative; do not re-verify unless ambiguous/contradictory.
57+
If starting points + acceptance are already clear, skip initial explore and only explore when blocked.
5658
- Create one or more git commits before `agent_report`.
5759

5860
Recommended Orchestrator → Exec task brief template:
@@ -64,15 +66,37 @@ Recommended Orchestrator → Exec task brief template:
6466
- Scope: <what to change>
6567
- Non-goals: <explicitly out of scope>
6668
- Starting points: <paths / symbols / callsites>
69+
- Dependencies / assumptions:
70+
- Assumes: <prereq patch(es) already applied in parent workspace, or required files/targets already exist>
71+
- If unmet: stop and report back; do not expand scope to create prerequisites.
6772
- Acceptance: <bullets / checks>
6873
- Deliverables:
6974
- Commits: <what to commit>
7075
- Verification: <commands to run>
7176
- Constraints:
7277
- Do not expand scope.
73-
- Explore as needed (spawn `explore` tasks to fill in missing repo context before editing; skip if starting points + acceptance are already clear).
78+
- Prefer `explore` tasks for repo investigation (paths/symbols/tests/patterns) to preserve your context window for implementation.
79+
Trust Explore reports as authoritative; do not re-verify unless ambiguous/contradictory.
80+
If starting points + acceptance are already clear, skip initial explore and only explore when blocked.
7481
- Create one or more git commits before `agent_report`.
7582

83+
Dependency analysis (required before spawning `exec` tasks):
84+
85+
- For each candidate subtask, write:
86+
- Outputs: files/targets/artifacts introduced/renamed/generated
87+
- Inputs / prerequisites (including for verification): what must already exist
88+
- A subtask is "independent" only if its patch can be applied + verified on the current parent workspace HEAD, without any other pending patch.
89+
- Default to sequential if unsure. Parallelism is an optimization; correctness is the requirement.
90+
- If task B depends on outputs from task A:
91+
- Do not spawn B until A has completed and A's patch is applied in the parent workspace.
92+
- If the dependency chain is tight (download → generate → wire-up), prefer one `exec` task rather than splitting.
93+
94+
Example dependency chain (schema download → generation):
95+
96+
- Task A outputs: a new download target + new schema files.
97+
- Task B inputs: those schema files; verifies by running generation.
98+
- Therefore: run Task A (await + apply patch) before spawning Task B.
99+
76100
Patch integration loop (default):
77101

78102
1. Identify a batch of independent subtasks.
@@ -87,9 +111,14 @@ Patch integration loop (default):
87111
- PASS: summary-only (no long logs).
88112
- FAIL: include the failing command + key error lines; then delegate a fix to `exec` and re-verify.
89113

90-
Sequential fallback:
114+
Sequential protocol (when any dependency exists):
115+
116+
1. Spawn the prerequisite `exec` task with `run_in_background: false` (or spawn, then immediately `task_await`).
117+
2. Dry-run apply its patch; then apply for real.
118+
3. Only after the patch is applied, spawn the dependent `exec` task.
119+
4. Repeat until the dependency chain is complete.
91120

92-
- If subtasks depend on one another, do them in order and apply patches between them.
121+
Note: child workspaces are created at spawn time. Spawning dependents too early means they work from the wrong repo snapshot and get forced into scope expansion.
93122

94123
Keep context minimal:
95124

0 commit comments

Comments
 (0)