feat(trekexecute): couple the executor to the review gate, the plan approval and the step checks
Wave 2, order 6. /trekexecute now: - refuses a plan whose logged approval does not cover its current sha256 (K2, approval-log verify --kind plan), before step 1; - runs the step check (K9) and the step's optional Regression: (K10, new lib/verification/regression-check.mjs through the criteria runner) at step end, before the checkpoint; exit 2 is "not measured", never green; - runs the architecture rules (K5) and the plan-file sweep (K6) after the last step; a violation or a file outside the plan turns completed into partial; - reviews by itself in the closing run (Phase 7.2): run the thing, /simplify, /trekreview, verdict-gate; a BLOCK adds the review's remediation steps after the plan validator accepts them and the operator re-approves the plan, capped at TREKEXECUTE_MAX_REVIEW_ROUNDS (3); - makes the main-merge gate a lock on the verdict: BLOCK or undecided keeps the merge closed; when open, the executor merges and the guard's question is the one question (operator decision 2026-10-08). The --gates pause before the wave merge-back is gone for the same reason. The guard refuses a merge into main and a push in the permission mode that shows no prompts, since no one can be asked (operator decision 2026-10-09; two mode-read exemptions approved by the operator). progress.json gains optional coupling fields (Handover 5); the validator rejects the runner's exitCode in plan_verification.failed_criteria (C15). Pointer lines name the skills test-first and debugging (S2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
4ee711a6ac
commit
920fbd3c47
15 changed files with 1310 additions and 64 deletions
26
README.md
26
README.md
|
|
@ -319,6 +319,8 @@ Reads a plan from `/trekplan` and implements it with strict discipline. No guess
|
|||
|
||||
Per step: record the start point → **one fresh helper** (`step-implementer`) writes the step's test first, proves it red, locks it, then applies Changes exactly as written → the executor proves it by command: **red at the start point, green at the result** (`red-proof.mjs`), Verify (exit code is truth), manifest audit, and the **floor guard** on the diff (`test-integrity.mjs`: removed asserts, skipped or deleted tests, muted checks, stubs, loosened thresholds) → **one controller** reads the diff — never the helper's summary — and gives two verdicts, *spec* and *quality* → a script writes the step's **done line** only when the test command exits 0 (`done-line.mjs`) → Checkpoint commit. After all steps: independent Phase 7.5 manifest audit from git log + filesystem (ignoring agent bookkeeping); drift triggers Phase 7.6 bounded recovery. A plan with no passing run-the-thing criterion ends **not verified end to end**, never green.
|
||||
|
||||
A run starts only on a plan you approved **as it is now**: the approval log holds the plan's sha256, so a plan edited after its approval is refused before step 1. At step end the repo's own tools check the step's diff (the step check) and the step's `Regression:` suite must stay green. After the last step come the architecture rules and the sweep for files the plan does not name, and then **the review starts by itself**: `/simplify` → `/trekreview` → the verdict gate. A BLOCK keeps the merge into main closed.
|
||||
|
||||
### The step loop
|
||||
|
||||
| Part | What it does | Why |
|
||||
|
|
@ -329,6 +331,8 @@ Per step: record the start point → **one fresh helper** (`step-implementer`) w
|
|||
| Test lock | the helper locks its test files after the red proof (`test-lock.mjs`, when installed; otherwise "not-locked" is reported) | The code moves to meet the test, never the reverse |
|
||||
| Floor guard | `test-integrity.mjs` reads the diff for weakened tests; exit 2 ("could not run") is never green | Cheating the tests is caught by a command |
|
||||
| Controller | one general helper, two verdicts (spec, quality), re-checks only what a fix round changed | An independent judge of the diff |
|
||||
| Step check | `step-check.mjs` runs the repo's own formatters, linters and type checker on the step's diff; findings go to the controller, a repo without tools reads "not measured" | The stop for P7 is at step end |
|
||||
| Regression | the step's optional `Regression:` command (one allowlisted test runner) runs through the criteria runner before the checkpoint; red goes into the fix rounds | Verify proves the step; the regression proves nothing else broke |
|
||||
| Done line | `done-line.mjs` appends `DONE step N` only when the test command exits 0 | "Done" is an exit code |
|
||||
|
||||
The helper works in your working tree, not in a worktree of its own: measured 2026-10-06, a worktree-isolated subagent branches from the default branch rather than your `HEAD`, so it would not see the earlier steps (only the operator setting `worktree.baseRef: "head"` changes that).
|
||||
|
|
@ -337,6 +341,20 @@ The helper works in your working tree, not in a worktree of its own: measured 20
|
|||
|
||||
A run stops only on a **closed list**: something that cannot be undone · something security-sensitive · something outside the working copy (merge to main, push, publish) · a plan so broken that everything after it is guesswork. Everything else the executor decides itself and logs in the final report's **Decisions taken** table, each with what it costs if it is wrong.
|
||||
|
||||
### The review at the end — a gate (P11)
|
||||
|
||||
After the last step, and with nobody typing anything, the executor runs Cherny's order: **run the thing** (the plan's `## Verification`, its end-to-end criterion included) → **`/simplify`** (Claude Code's cleanup skill; edits outside the run's files are restored, and a cleanup that breaks the verification is reverted) → **`/trekreview`** (Claude Code's `/code-review` and `/security-review`, then Voyage's check against the brief) → **`verdict-gate.mjs`**.
|
||||
|
||||
| Verdict gate | Merge into main |
|
||||
|---|---|
|
||||
| 0 — ALLOW / WARN | open: the executor runs the merge, and the guard asks you before it runs |
|
||||
| 1 — BLOCK | closed. The review's BLOCKERs are added to the plan as new numbered steps, you approve the plan again, and the loop runs: build, check, review — at most 3 reviews, then it is yours |
|
||||
| 2 — could not decide | closed: a review that did not run in full is never green |
|
||||
|
||||
**One question per merge.** The guard asks before every merge into main and every push, in auto mode too, so the executor no longer asks "ready to merge?" itself (operator decision 2026-10-08). On the wave path the push and the merge of each session go in one call, so you are asked once per session.
|
||||
|
||||
Borrowed: the order from Cherny; the gate on a verdict in a file from Kiro; the bounded fix-and-review loop from Spec Kit; nothing dropped silently from Superpowers. Ideas only.
|
||||
|
||||
### Modes
|
||||
|
||||
| Mode | Usage | Behavior |
|
||||
|
|
@ -359,8 +377,8 @@ Voyage never starts a Claude Code session. When a plan has an `## Execution Stra
|
|||
2. **Creates git worktrees** — each session in the wave gets its own isolated worktree and branch (`trek/{slug}/session-{N}`)
|
||||
3. **Writes a session order per session** — the worktree to open, the steps, the done-condition, and a one-line starter (`/trekexecute --session N <plan>`) — then stops
|
||||
4. **You open each session yourself** in the directory its order names and give it the starter
|
||||
5. **Run the same `/trekexecute` command again** — it reads every session's progress file, merges the branches back sequentially with `--no-ff`, cleans up, and writes the next wave's orders
|
||||
6. After the last wave: master verification on the merged result; worktrees and branches are cleaned up unconditionally (even on failure)
|
||||
5. **Run the same `/trekexecute` command again** — it reads every session's progress file, merges the branches back sequentially with `--no-ff` (the guard asks you once per session: push and merge go in one call), cleans up, and writes the next wave's orders
|
||||
6. After the last wave: master verification on the merged result, then the review at the end; worktrees and branches are cleaned up unconditionally (even on failure)
|
||||
|
||||
```
|
||||
Wave 1 orders: Session 1 (worktree-1) + Session 2 (worktree-2) -- you run them, in parallel
|
||||
|
|
@ -392,7 +410,7 @@ The executor implements defense-in-depth security across three layers:
|
|||
|
||||
**Guards during the build.** All are command hooks; none runs a model.
|
||||
|
||||
- **Approval guard (P12)** — `pre-bash-executor.mjs` answers `ask` before a merge into `main`, a push, a tag or package publish, and destructive git (hard reset, forced clean, force-deleted branch, dropped stash, discarded changes, history rewrite). Claude Code shows the prompt labelled `[plugin:voyage]`, also in auto mode, and the prompt names the way forward. `post-approval-log.mjs` writes an approved merge or push to `main` (`merge`) and a tag or publish (`release`) to the approval log with a one-hour expiry. It logs exactly what the person was asked, and nothing in a permission mode that shows no prompts, where no one is asked; other pushes and destructive git are asked about but not logged. Claude Code's own notification for a waiting permission prompt is the alert; Voyage adds none.
|
||||
- **Approval guard (P12)** — `pre-bash-executor.mjs` answers `ask` before a merge into `main`, a push, a tag or package publish, and destructive git (hard reset, forced clean, force-deleted branch, dropped stash, discarded changes, history rewrite). Claude Code shows the prompt labelled `[plugin:voyage]`, also in auto mode, and the prompt names the way forward. `post-approval-log.mjs` writes an approved merge or push to `main` (`merge`) and a tag or publish (`release`) to the approval log with a one-hour expiry. It logs exactly what the person was asked, and nothing in a permission mode that shows no prompts, where no one is asked; other pushes and destructive git are asked about but not logged. Claude Code's own notification for a waiting permission prompt is the alert; Voyage adds none. `/trekexecute` relies on it: where the guard asks, the executor never asks the same thing again. In the permission mode where Claude Code shows no prompts there is no one to ask, so the guard refuses a merge into `main` and a push instead, and says to run it yourself (operator decision 2026-10-09).
|
||||
- **Plan gate (P3)** — `pre-plan-gate.mjs` runs Voyage's plan gate on the plan Claude Code's plan mode presents and sends an invalid Voyage plan back to planning; when the gate cannot run, the prompt says "not measured". An approved Voyage plan is logged with the hash of its text. A plan without `plan_version` passes untouched.
|
||||
- **Test lock (P9)** — while a step's test is locked (`lib/util/test-lock.mjs`), `pre-write-executor.mjs` refuses Write, Edit and NotebookEdit on it, and `stop-test-lock.mjs` refuses "done" in the session that took the lock until the executor unlocks it.
|
||||
- **Post-edit check (P7)** — `post-edit-check.mjs` runs the target repo's own formatter and linter on each edited file (check-only; a tool is never downloaded) and logs the result. `lib/verification/step-check.mjs` re-runs them on the diff at step end, adds the type checker, and fails the step on findings. A repo without tools, or a configured tool that is missing or crashes, reads "not measured", never green. The check is on only while Voyage executes a plan in that repo, or when the repo switches it on with `.claude/voyage-guards.json` = `{ "post_edit_check": true }`.
|
||||
|
|
@ -421,7 +439,7 @@ prompt-injection vector that the plugin's own hooks cannot fully mitigate
|
|||
### Unattended execution
|
||||
|
||||
`/trekexecute` runs without asking questions:
|
||||
- **No questions asked** — all recovery decisions come from the plan
|
||||
- **No questions asked** — all recovery decisions come from the plan. The exceptions are approvals: the plan's approval again after the review added steps, and the guard's question before a merge or push
|
||||
- **Progress file** — crash recovery via `{project_dir}/progress.json` (or `.trekexecute-progress-{slug}.json` for legacy plans)
|
||||
- **Scope fence enforcement** — never touches files outside the session's scope
|
||||
- **JSON summary** — machine-parseable `trekexecute_summary` block at the end of every run
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue