fix(execute): clear the wave record only on the main-merge gate's confirm (green)

1. Step 6 cleared the orders dir before Phase 8's main-merge gate asked,
   so a declined gate lost the merged-waves record and the next run
   prepared wave 1 again on merged code. The clear now sits only under
   the gate's "On confirm" (wave path, next-wave none, Step 4 passed);
   Step 6 and a declined gate keep the record, so a re-run goes
   next-wave none -> Step 4 -> back to the gate.
2. The gate's Decline row and Recovery surface now say what holds on the
   wave path: the waves are already merged on the current branch,
   nothing is finalized, the record is kept, and re-running the same
   command (not --resume, which Phase 2.5 runs as a single session)
   re-runs master verification and returns to the gate. The branch name
   is trek/{slug}/session-N; the push-before-cleanup note now holds only
   where the push succeeded. The single-session --resume line stays.
3. The report footer adds the multi-session way to continue.
4. wave.json stores the branch the wave was prepared on (write
   --branch); Step 3's status call passes the current branch and stops,
   touching nothing, when the main checkout is on another branch.

npm test: 1277 tests, 1275 pass, 0 fail, 2 skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-10-02 16:24:33 +02:00
commit d70e3d2af7
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
2 changed files with 72 additions and 45 deletions

View file

@ -620,9 +620,10 @@ Record `REPO_ROOT`, `PLAN_REL`, `SESSION_DIR`, `WORKTREE_DIR`, `ORDERS_DIR`,
A number is `W`: continue to Step 1. `none` means earlier runs merged every
wave: go to Step 4. The record it reads, `$ORDERS_DIR/merged-waves.json`
(plan path + sha256 of the plan's content), is written by Step 3 after each
merged wave, survives Step 5, and is cleared by Step 6 only when every wave is
merged and Step 4 passed, so a re-run after a later wave failed never prepares
an already-merged wave again.
merged wave, survives Step 5, and is cleared only on confirm at Phase 8's
main-merge gate, when every wave is merged and Step 4 passed, so a re-run
after a later wave failed (or after a declined gate) never prepares an
already-merged wave again.
If `next-wave` exits 1, the record belongs to another plan or another version
of this one (`{slug}` is the plan's file name, so plans can share
`$SESSION_DIR`). Stop, touch nothing, and tell the user exactly what its
@ -735,16 +736,17 @@ Source: brief Constraint 2.
### Step 2 — Write the session orders for wave W, then stop
```bash
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" write --plan "$PLAN_REL" --wave "{W}" --session-dir "$SESSION_DIR")
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" write --plan "$PLAN_REL" --wave "{W}" --session-dir "$SESSION_DIR" --branch "$ORIGINAL_BRANCH")
```
`$PLAN_REL` is relative to the main checkout (Step 0; the tool refuses an
absolute path): each session resolves it inside its own worktree, which has the
same repo content from HEAD. The tool writes `$ORDERS_DIR/wave-{W}-session-{N}.md`
per session (naming its worktree, directory and progress file) and
`$ORDERS_DIR/wave.json` (`status: awaiting-sessions`, the plan path and the
sha256 of its content), and prints, per session, the directory to open and the
starter line (`/trekexecute --session {N} $PLAN_REL`). A session's per-session `cwd:`
`$ORDERS_DIR/wave.json` (`status: awaiting-sessions`, the plan path, the
sha256 of its content and the branch the wave is prepared on), and prints, per
session, the directory to open and the starter line
(`/trekexecute --session {N} $PLAN_REL`). A session's per-session `cwd:`
field in the Execution Strategy moves the directory it opens in to that
subdirectory of its worktree (plugin-in-monorepo layouts, brief Constraint 1,
Option B); default `.` is the worktree root.
@ -764,12 +766,15 @@ the orders are the hand-over.
### Step 3 — Collect wave W (a later run)
```bash
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" status --plan "$PLAN_REL" --wave "{W}" --session-dir "$SESSION_DIR")
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" status --plan "$PLAN_REL" --wave "{W}" --session-dir "$SESSION_DIR" --branch "$ORIGINAL_BRANCH")
```
If it exits 1, `wave.json` was written for another plan or another version of
this one: stop and report its message, touching nothing. Re-run with the plan
(version) that wrote the wave, or abandon the wave (the way out below).
If it exits 1, stop and report its message, touching nothing (`wave.json`
stays). Either `wave.json` was written for another plan or another version of
this one — re-run with the plan (version) that wrote the wave, or abandon the
wave (the way out below) — or the main checkout is on another branch than the
wave was prepared on (Step 0's `ORIGINAL_BRANCH` of that run): the user
switches back to that branch and re-runs, so the wave never merges elsewhere.
The JSON names each session's progress file (the file `--session N` writes,
Phase 3), its raw `status`, and its `state`, exactly one of:
@ -915,7 +920,8 @@ it never forces: `git worktree remove` without force refuses a worktree with
modified or untracked files, `git branch -d` refuses an unmerged branch, and
whatever git refuses is kept and reported, never retried with force. From
`$ORDERS_DIR` it deletes only `wave.json`: the orders, the archived progress
copies and the merged-waves record stay until Step 6 clears them.
copies and the merged-waves record stay until the main-merge gate's confirm
(Phase 8) clears them.
```bash
cd "$REPO_ROOT" || exit 1
@ -956,16 +962,11 @@ Read every archived copy, `$ORDERS_DIR/wave-*-session-*.progress.json`, into an
aggregated report — never the worktree copies, which Steps 3 and 5 remove with
their worktrees (earlier waves' in earlier runs).
Then clear the orders directory — orders, archived copies and the merged-waves
record — only when `next-wave` said `none` (every wave merged) AND
Step 4 passed, so a later plan with the same `{slug}` starts clean:
```bash
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" clear --session-dir "$SESSION_DIR")
```
On any other outcome keep it: the next run resumes at the lowest wave not yet
merged (Step 0), or re-runs Step 4 when every wave is merged. Jump to Phase 8.
Keep the orders directory here, whatever the outcome. Only Phase 8's
main-merge gate clears it, on confirm, when `next-wave` said `none` (every wave
merged) and Step 4 passed. Until then the next run resumes at the lowest wave
not yet merged (Step 0), or re-runs Step 4 and returns to the gate when every
wave is merged. Jump to Phase 8.
### --session N mode
@ -1644,7 +1645,7 @@ and finalize the run?"
| Option | Action |
|--------|--------|
| **Confirm — main-merge** | Emit `main-merge-approved`, proceed to write progress + state files. |
| **Decline — hold for review** | Emit `main-merge-declined`. Wave commits remain on their session branches for inspection. The run is recorded as `partial`. |
| **Decline — hold for review** | Emit `main-merge-declined`. Nothing is finalized: the run is recorded as `partial`. The commits stay where they are for review — on the multi-session wave path the waves are already merged on the current branch, and the merged-waves record is kept. |
This pause is **always on**, regardless of `gates_mode`. The `--gates` flag
re-enables earlier per-wave pauses; this gate is the one boundary that
@ -1658,6 +1659,15 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/stats/event-emit.mjs \
--payload "{\"plan\":\"${PLAN_PATH}\"}"
```
On the multi-session wave path (Phase 2.6), and only when `next-wave` said
`none` (every wave merged) and Step 4 passed, also clear the plan's orders
directory — orders, archived progress copies and the merged-waves record — so a
later plan with the same `{slug}` starts clean. This is the one place it is
cleared:
```bash
(cd "$REPO_ROOT" && node "$VOYAGE_ROOT/lib/util/session-orders.mjs" clear --session-dir "$SESSION_DIR")
```
On decline:
```bash
node ${CLAUDE_PLUGIN_ROOT}/lib/stats/event-emit.mjs \
@ -1665,12 +1675,20 @@ node ${CLAUDE_PLUGIN_ROOT}/lib/stats/event-emit.mjs \
--payload "{\"plan\":\"${PLAN_PATH}\",\"reason\":\"${reason}\"}"
```
**Recovery surface:** if declined, `--resume re-enters at the gate` —
re-running `/trekexecute --resume --project <dir>` jumps directly
back to the main-merge gate AskUserQuestion (skipping completed waves).
The wave session branches are preserved for inspection (Hard Rule 19's
push-before-cleanup ensures they survive on the remote even if local
cleanup ran). To inspect: `git log trekplan/<slug>/session-N` per wave.
On decline, nothing is cleared: the merged-waves record is kept.
**Recovery surface:** on the single-session path, if declined,
`--resume re-enters at the gate` — re-running
`/trekexecute --resume --project <dir>` skips the completed steps and returns
to the main-merge gate AskUserQuestion. On the multi-session wave path,
re-run the same `/trekexecute` command instead, not `--resume` (Phase 2.5 runs
a `--resume` as a single session): the waves are already merged on the current
branch, the kept merged-waves record makes Step 0's `next-wave` say `none`,
master verification (Step 4) runs again, and the run returns to this gate. The
session branches (`trek/{slug}/session-N`) are merged and deleted unless
Step 3 or 5 kept them; Step 3 pushed each one before merging it (Hard Rule 19),
so where that push succeeded it also survives on the remote. Inspect the
integrated result with `git log` on the current branch.
### Progress + state-file writes
@ -1786,7 +1804,8 @@ Attempts: {N}
{Numbered list of unexecuted steps}
To resume: /trekexecute --resume {path}
To resume (single session): /trekexecute --resume {path}
To continue (multi-session waves): re-run the same /trekexecute command (not --resume)
```
**Result vocabulary (v1.7, strict):**
@ -1832,10 +1851,11 @@ The `trekexecute_summary` key makes it grep-able in a session's output.
**Multi-session path (Phase 2.6).** Per-session results come from Step 6's
aggregate of the archived copies `$ORDERS_DIR/wave-*-session-*.progress.json`.
The report lists every worktree and `trek/{slug}/*` branch Steps 3 and 5 kept,
with what the user can do (Step 5). If Step 6 kept the orders directory (not
every wave merged, or Step 4 did not pass), say so: the next run resumes at the
lowest wave not yet merged, and the `clear` command in Step 0 starts the plan
over from its first wave instead.
with what the user can do (Step 5). If the orders directory was kept (not every
wave merged, Step 4 did not pass, or the gate was declined), say so: the next
run resumes at the lowest wave not yet merged, or re-runs Step 4 and returns to
the gate, and the `clear` command in Step 0 starts the plan over from its first
wave instead.
## Phase 9 — Stats tracking