Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .agents/skills/map-efficient/efficient-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ python3 .map/scripts/map_orchestrator.py advance_wave
Do not mix wave APIs with the sequential `get_next_step` cursor for the same
wave unless the orchestrator response explicitly tells you to fall back.

When `worktree.isolation` is enabled and a wave runs in parallel (≥2 disjoint
subtasks), give each subtask its own worktree and accept the whole wave
atomically after all pass Monitor — never merge them one at a time (the first
merge advances HEAD and the next trips `BASE_DIVERGED`):

```bash
python3 .map/scripts/map_step_runner.py merge_wave_worktrees "$ST_A" "$ST_B"
```

It runs the post-wave gate inside the transaction and rolls the whole wave back
to base on any conflict or gate failure (worktrees kept for retry). On a single
subtask's Monitor failure, `discard_subtask_worktree` that subtask and retry it
before calling `merge_wave_worktrees`.

## TDD Mode

`--tdd` inserts `TEST_WRITER` and `TEST_FAIL_GATE` before `ACTOR`.
Expand Down
2 changes: 1 addition & 1 deletion .claude/skills/map-efficient/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ Every Monitor failure must create a durable `code-review-N.md` with exact issue,

### Per-Wave Gates (after all subtasks in wave pass Monitor)

Run build first, then tests, then linter. If build fails, skip tests/lint and reopen the owning subtask. Run the FULL test suite (not a `-k` subset) whenever any subtask in the wave tripped the cross-subtask regression gate (`recommended_gate == "full_suite"`) — a parallel wave that edits a shared file is the highest-risk case for a regression no single subtask's scoped run can see.
Run build first, then tests, then linter. If build fails, skip tests/lint and reopen the owning subtask. Run the FULL test suite (not a `-k` subset) whenever any subtask in the wave tripped the cross-subtask regression gate (`recommended_gate == "full_suite"`) — a parallel wave that edits a shared file is the highest-risk case for a regression no single subtask's scoped run can see. **Worktree isolation, parallel wave:** when `worktree.isolation` is on and the wave has ≥2 isolated subtasks, accept the whole wave atomically with `merge_wave_worktrees` (never one at a time — the first merge trips `BASE_DIVERGED`); it runs this post-wave gate inside the transaction and rolls the wave back on failure — see [efficient-reference.md](efficient-reference.md#worktree-isolation).

## Step 2a: Validate Step Completion

Expand Down
39 changes: 38 additions & 1 deletion .claude/skills/map-efficient/efficient-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ including clean passes — must carry concrete evidence references.

## Wave Execution

Sequential is default. Parallel execution is allowed only when a wave has satisfied dependencies, low risk, and disjoint new-file writes, or when the user explicitly requests it. Use `get_wave_step`, `validate_wave_step`, and `advance_wave`; do not mix wave APIs with the single-current-subtask API.
Sequential is default. Parallel execution is allowed only when a wave has satisfied dependencies, low risk, and disjoint new-file writes, or when the user explicitly requests it. Use `get_wave_step`, `validate_wave_step`, and `advance_wave`; do not mix wave APIs with the single-current-subtask API. When `worktree.isolation` is on and a wave runs in parallel, each subtask gets its own worktree and the wave is accepted atomically via `merge_wave_worktrees` — see [Parallel waves](#worktree-isolation) under Worktree isolation.

## Predictor Recovery

Expand Down Expand Up @@ -551,6 +551,43 @@ python3 .map/scripts/map_step_runner.py discard_subtask_worktree "$SUBTASK_ID" -
The retry creates a fresh worktree off the current HEAD. Inspect state any time
with `worktree_isolation_status`.

### Parallel waves (≥2 worktree-isolated subtasks) — #284 Phase 2

When `get_wave_step` returns `mode:"parallel"` (a wave with ≥2 disjoint-file
subtasks) AND isolation is enabled, give EACH subtask its own worktree and
dispatch the Actors concurrently (separate Task agents, each pinned to its own
`$WT_PATH`). Do NOT merge them one at a time: every worktree was cut off the same
HEAD, so the first `merge_subtask_worktree` advances the working branch and the
next trips `BASE_DIVERGED`. Accept the whole wave atomically instead — only after
EVERY subtask in the wave has passed Monitor (+ Evaluator):

```bash
python3 .map/scripts/map_step_runner.py merge_wave_worktrees "$ST_A" "$ST_B" "$ST_C"
```

The coordinator (council-reviewed, conv `c29d6fa9`): derives the wave base from
the sidecar; refuses EXTERNAL HEAD movement but allows the sibling divergence each
in-wave squash-merge creates; runs each worktree's pre-merge `verification_checks`,
then squash-merges every accepted worktree by frozen SHA in sorted id order (one
runner commit per subtask), then runs the post-wave full gate **inside the same
transaction**. It is **all-or-nothing**: any textual conflict, commit failure, or
post-wave-gate failure rolls the WHOLE wave back to the base (`reset --hard` +
`clean -fd`, never `git merge --abort` — squash leaves no `MERGE_HEAD`) and leaves
every worktree intact for retry. Pass each subtask's `merged_sha` from the result
to `record_subtask_result --commit-sha`. This **replaces** the separate Per-Wave
Gate when isolation is on — the post-wave gate runs inside `merge_wave_worktrees`.

Failure `kind`s (working branch untouched / rolled back to base, worktrees kept):
`WAVE_MERGE_CONFLICT` (with `attribution` naming the subtasks that touched each
conflicted file — fix `affected_files` or re-decompose), `WAVE_VERIFY_FAILED`
(post-wave gate red), `EXTERNAL_HEAD_MOVED` (a commit landed outside the wave —
recreate the worktrees off the new HEAD), `WAVE_BASE_MISMATCH`, `DIRTY_TARGET`,
`MERGE_IN_PROGRESS`, plus the per-worktree preflight `kind`s (`VERIFY_FAILED`,
`BULK_DELETION`, … with `phase:"preflight"`). On any Monitor `valid=false` for a
single wave subtask, `discard_subtask_worktree` THAT subtask and retry it; call
`merge_wave_worktrees` only once the whole wave is green. The `overlaps` field is
advisory telemetry (actual changed-file intersections), not a gate.

## Troubleshooting

- Blueprint validation fails: fix the decomposer output before Actor starts.
Expand Down
Loading
Loading