You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+19Lines changed: 19 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,25 @@ All notable changes to **superpowers-v (Compound V)** are documented here.
4
4
5
5
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses semantic versioning.
6
6
7
+
## [2.6.4] — 2026-07-10
8
+
9
+
### Fixed — Compound V's own audit trail could be silently deleted, and `/v:status` could mislead
10
+
11
+
Two real incidents **noticed by Oscar Salcedo**, which a requested Codex cross-model hunt for
12
+
"similar/adjacent bugs" grew into a full sweep of the same bug class across the orchestrator:
13
+
14
+
-**Data loss: an uncommitted run directory vanishes on worktree cleanup.**`docs/superpowers/execution/<run-id>/**` is documented as "the committed run substrate" (`execution-manifest.md`) — but nothing in the pipeline actually committed it. `superpowers:finishing-a-development-branch`'s cleanup step runs `git worktree remove` on **both** its Merge and Discard paths, which **silently deletes any uncommitted files** in that worktree — taking Compound V's own audit trail with it. After a restart, `/v:status` would then honestly (but confusingly) report "no orchestrator runs" for a repo that demonstrably had one.
15
+
-**Misleading status message for non-Compound-V work.** When a repo had real prior work done via plain Superpowers `subagent-driven-development` (evidenced by `.superpowers/sdd/` task-brief/report/review artifacts) rather than Compound V's own manifest-driven dispatch, `/v:status`'s "no orchestrator runs" message read as "nothing happened here" — it had no visibility into that different, upstream-owned execution path. **Fixed with a cheap presence-check** (not a parse — that directory's format belongs to the base Superpowers plugin, not Compound V) that disambiguates the message without trying to understand or summarize its contents.
16
+
17
+
**The commit-discipline fix, after four rounds of Codex review, landed nine explicit commit points across the pipeline** (each closing a path where state could be written but never survive a worktree cleanup):
18
+
1.`/v:orchestrate` — commits `manifest.yaml` + the initial `state.json` right after materializing them.
19
+
2.`parallel-dispatcher` Step 7 — commits the run directory + memory/scorecard files in one shot **before** handing off to `finishing-a-development-branch` (the one point that can trigger the destructive cleanup). **Round 1 of review caught a bug in this very fix**: `state.json`'s phase was flipped to `MERGED`*after* the commit, so the committed record permanently lagged one phase behind reality — fixed by writing `MERGED` first, then committing everything together.
20
+
3–7. `commands/v-epic.md` — a **separate, epic-level `epic-state.json`** (the epic's *only* resume mechanism, one level up from any single feature's run directory) was never committed anywhere. Five commit points added: after init, at every checkpoint (the default `MAX_FEATURES=1` stopping point after *every* feature), at epic-complete, at epic-blocked, and — caught in round 3 — after crash-reconcile (the `--status failed` "abandon and stop" path is terminal and doesn't otherwise pass through the checkpoint's commit).
21
+
8.`commands/v-resume.md` — its own completion path didn't reference committing the recovered run substrate; a resume completing this way could re-lose the very state it just recovered.
22
+
9.`commands/v-collect.md` — standalone use (re-checking an already-dispatched run without re-dispatching) rewrote `results/*.json` + `state.json` with no commit step at all.
23
+
24
+
`state-machine.md` documents the general "written to disk ≠ durable" principle tying it all together. Docs-only; no code changed. **Codex cross-model verification, four rounds:** round 1 found the `MERGED`-ordering bug plus the v-epic/v-resume/v-collect gaps; round 2 (broad hunt) confirmed the fix and found nothing new to add; round 3 caught the crash-reconcile gap; round 4 (narrow re-check) confirmed all nine commit points present, correctly scoped, and non-contradictory.
25
+
7
26
## [2.6.3] — 2026-07-10
8
27
9
28
### Changed — Codex defaults bumped to the GPT-5.6 family (Sol/Terra/Luna)
Copy file name to clipboardExpand all lines: agents/parallel-dispatcher.md
+26-1Lines changed: 26 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -231,7 +231,9 @@ After every task is approved and every worktree job has merged back, dispatch ON
231
231
- Cross-task integration works (Task 0's types are used correctly by parallel tasks) and the build is green
232
232
- The composite change matches the spec + all three audits' constraints **and the manifest's feature-level `acceptance_criteria`** (the AC-gate for the run)
233
233
234
-
On PASS, advance `state.json` to `MERGED` and hand off to `superpowers:finishing-a-development-branch`.
234
+
On PASS, proceed to Step 6 (post-run memory), then Step 7 (commit + `MERGED` + hand off). Do
235
+
**not** advance `state.json` to `MERGED` yet — per [`state-machine.md`](../skills/compound-v/state-machine.md),
236
+
`MERGED` means the run's substrate is actually merged and handed off, not just reviewed.
Copy file name to clipboardExpand all lines: commands/v-collect.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,7 +39,7 @@ The run-dir layout and per-job `status` semantics are in [`skills/compound-v/sta
39
39
-**INTEGRATION** — cross-job seams build, and the composite change satisfies the feature-level `acceptance_criteria`.
40
40
DONE is gated on all three. Unresolvable reviewer ISSUES ⇒ HALT (do not merge).
41
41
42
-
5.**Update state + report.** Write `state.json` after each transition (`COLLECTED` → `REVIEWED`). Report: per-job scope verdict, the three review-pass outcomes, and whether the run is clear to merge. If clear, point at the merge step (worktree diffs apply into the main tree, then `superpowers:finishing-a-development-branch`). If BLOCKED, point at [`/v:resume {{args}}`](v-resume.md).
42
+
5.**Update state + report.** Write `state.json` after each transition (`COLLECTED` → `REVIEWED`). **Commit what this command rewrote** — `state.json` and the refreshed `results/*.json` — the same commit discipline as [`parallel-dispatcher`](../agents/parallel-dispatcher.md)'s Step 7: uncommitted files in a worktree are silently deleted by `finishing-a-development-branch`'s cleanup step, and `/v:collect` is explicitly usable **standalone** (re-checking an already-dispatched run), so don't assume a later step will commit on your behalf. Report: per-job scope verdict, the three review-pass outcomes, and whether the run is clear to merge. If clear, point at the merge step (worktree diffs apply into the main tree, then `superpowers:finishing-a-development-branch`). If BLOCKED, point at [`/v:resume {{args}}`](v-resume.md).
`--require-specs` **refuses to start unless every feature has an existing `spec_path`** — the deterministic enforcement that no feature enters the autonomous loop without an approved spec. It also validates ids/refs/cycles/dups. A non-zero exit ⇒ fix and re-init; never hand-edit the state.
27
+
- **Commit the epic-level files right after init**: `features.json` and the freshly-created `epic-state.json` are new, uncommitted files — `git add docs/superpowers/execution/epics/<epic-id>/features.json docs/superpowers/execution/epics/<epic-id>/epic-state.json && git commit -m "chore(v-epic): init epic <epic-id>"`. (Per-feature spec files are committed by `superpowers:brainstorming` itself when each spec is approved, in step 2 — no separate action needed for those.)
27
28
28
29
4. **The autonomous loop** (bounded by `MAX_FEATURES`). Repeat until no feature is runnable **or this invocation's budget is spent**:
29
30
- **Ask for the next runnable feature:**
@@ -52,14 +53,14 @@ The epic model, run-dir layout, the final integration review, and the honesty bo
then **stop the loop** and go to step 6 (the epic is now blocked but resumable).
55
-
5. **Checkpoint (human-in-the-loop cadence).** Count each completed feature against `MAX_FEATURES`. When this invocation's budget is spent, **STOP and report** `python3 scripts/compound-v-epic-state.py --stats --state <epic-state.json>` (done / remaining) so the human reviews the accumulated diff and re-runs `/v:epic` to continue. This is a *driver-enforced cadence*, not a token ceiling; with the default `MAX_FEATURES=1` the epic checkpoints after **every** feature.
56
+
5. **Checkpoint (human-in-the-loop cadence).** Count each completed feature against `MAX_FEATURES`. When this invocation's budget is spent: **first commit `epic-state.json`** — `git add docs/superpowers/execution/epics/<epic-id>/epic-state.json && git commit -m "chore(v-epic): checkpoint <epic-id> (<N> features done)"` — **then STOP and report** `python3 scripts/compound-v-epic-state.py --stats --state <epic-state.json>` (done / remaining) so the human reviews the accumulated diff and re-runs `/v:epic` to continue. **The commit is not optional**: each feature's own v1.0 run already commits *that feature's* run directory (parallel-dispatcher's Step 7), but epic-state.json itself (which `run_id`/`status` each feature is at — the epic's *only* resume mechanism) lives one level up and is never covered by that. A checkpoint is exactly the moment control returns to a human who might close the session or clean up the worktree — an uncommitted `epic-state.json` at that instant means a later `/v:epic <epic-id>` has no record of what's done, and a `finishing-a-development-branch` cleanup can erase it outright. This is a *driver-enforced cadence*, not a token ceiling; with the default `MAX_FEATURES=1` the epic checkpoints (and commits) after **every** feature.
56
57
- **If `feature` is null**, branch on `reason` (step 5/6).
57
58
58
-
5. **Epic complete** (`reason == "epic complete"`). All features are `done`. Run a **final cross-feature integration review**: the *whole accumulated diff* on the branch against the **epic's** acceptance criteria — not the per-feature ACs (those already passed in each feature's own review), but the cross-feature contracts: do the features compose, do shared boundaries line up, is the product coherent end-to-end. On PASS, hand to `superpowers:finishing-a-development-branch` (merge / PR / cleanup options). On ISSUES, surface them and stay resumable.
59
+
5. **Epic complete** (`reason == "epic complete"`). All features are `done`. Run a **final cross-feature integration review**: the *whole accumulated diff* on the branch against the **epic's** acceptance criteria — not the per-feature ACs (those already passed in each feature's own review), but the cross-feature contracts: do the features compose, do shared boundaries line up, is the product coherent end-to-end. On PASS, **commit `epic-state.json` (same as the checkpoint step, if it isn't already)**, then hand to `superpowers:finishing-a-development-branch` (merge / PR / cleanup options) — never hand off with an uncommitted `epic-state.json`. On ISSUES, surface them and stay resumable.
59
60
60
-
6. **Epic blocked** (`reason` starts with `epic blocked` — a feature `failed` or an unmet dependency). **Stop and surface it.** Print `compound-v-epic-state.py --summary --state <epic-state.json>` so the user sees exactly which feature failed and what it blocks. The epic stays **resumable**: after the user fixes the failed feature (or its spec/partition), retry it (`--update --feature <id> --status pending`) and re-run `/v:epic <epic-id>` (or the same brief) — step 3 detects the existing `epic-state.json` and continues; only `pending` features run, the `done` ones are skipped.
61
+
6. **Epic blocked** (`reason` starts with `epic blocked` — a feature `failed` or an unmet dependency). **Commit `epic-state.json` (same as the checkpoint step, if it isn't already), then stop and surface it.** Print `compound-v-epic-state.py --summary --state <epic-state.json>` so the user sees exactly which feature failed and what it blocks. The epic stays **resumable** — but only if the `failed` status actually made it into git before anyone touches the worktree. After the user fixes the failed feature (or its spec/partition), retry it (`--update --feature <id> --status pending`) and re-run `/v:epic <epic-id>` (or the same brief) — step 3 detects the existing `epic-state.json` and continues; only `pending` features run, the `done` ones are skipped.
61
62
62
-
**Epic needs reconcile** (`reason` starts with `epic needs reconcile` — a feature is still `running`). Because epic mode is **sequential**, `--next` is only ever called between features, so a `running` feature on resume means that feature's run **crashed mid-pipeline**. Do not route around it. **Reconcile by resuming first — don't discard half-built work:** the crashed feature ran a *normal v1.0 run* with its own crash-resume, so run **[`/v:resume <run-id>`](v-resume.md)** to re-dispatch only that run's incomplete jobs; if it completes, mark the feature **`--status done`**. **If the feature's `run_id` is null** (the crash happened before the run-id was recorded — see step 4.1 — or it is an old state), there is nothing to resume → restart it with **`--status pending`**. Only if a resumed run cannot be recovered, fall back to **`--status pending`** (full restart from the spec) or **`--status failed`** (abandon and stop). Never leave a feature `running` across a resume — the epic will not advance until the stale run is reconciled.
63
+
**Epic needs reconcile** (`reason` starts with `epic needs reconcile` — a feature is still `running`). Because epic mode is **sequential**, `--next` is only ever called between features, so a `running` feature on resume means that feature's run **crashed mid-pipeline**. Do not route around it. **Reconcile by resuming first — don't discard half-built work:** the crashed feature ran a *normal v1.0 run* with its own crash-resume, so run **[`/v:resume <run-id>`](v-resume.md)** to re-dispatch only that run's incomplete jobs; if it completes, mark the feature **`--status done`**. **If the feature's `run_id` is null** (the crash happened before the run-id was recorded — see step 4.1 — or it is an old state), there is nothing to resume → restart it with **`--status pending`**. Only if a resumed run cannot be recovered, fall back to **`--status pending`** (full restart from the spec) or **`--status failed`** (abandon and stop). Never leave a feature `running` across a resume — the epic will not advance until the stale run is reconciled. **Whichever status this settles on, commit `epic-state.json` right after** (`git add docs/superpowers/execution/epics/<epic-id>/epic-state.json && git commit -m "chore(v-epic): reconcile <feature-id> -> <status>"`) — the `--status failed` ("abandon and stop") path in particular is terminal and does not otherwise pass through the checkpoint step's commit.
63
64
64
65
7. **Report.** Print the epic summary (`--summary`), the per-feature run-ids, and the next step: the integration review + `finishing-a-development-branch` on complete, or the blocking feature + the resume hint on blocked.
Copy file name to clipboardExpand all lines: commands/v-orchestrate.md
+8-1Lines changed: 8 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,7 +32,14 @@ The manifest schema and rules are defined in [`skills/compound-v/execution-manif
32
32
```
33
33
It enforces the invariants (disjoint `write_allowed`, `codex ⇒ worktree`, `reviewers ⇒ opus`, shared-in-Task-0). If it exits non-zero, **fix the manifest** and re-run — do not hand a manifest the validator rejects to dispatch.
34
34
35
-
8.**Report.** Print the run-id, the run-dir path, the job count by backend/model, and the next step: `/v:dispatch <run-id>` to execute, or edit `manifest.yaml` first. Point the user at [`/v:status {{args}}`](v-status.md) to inspect.
35
+
8.**Commit the run directory.**`docs/superpowers/execution/<run-id>/{manifest.yaml,state.json}` are new files on disk, not yet in git — a plain **write** is not durable. Stage and commit them now:
git commit -m "chore(v-orchestrate): materialize run <run-id>"
39
+
```
40
+
This is not optional. If this run is happening inside a git worktree, an *uncommitted* run directory is silently deleted by `git worktree remove` — the cleanup step in `superpowers:finishing-a-development-branch` — the very moment the branch is merged or discarded, taking Compound V's own audit trail with it. See [`state-machine.md`](../skills/compound-v/state-machine.md)'s note on this.
41
+
42
+
9.**Report.** Print the run-id, the run-dir path, the job count by backend/model, and the next step: `/v:dispatch <run-id>` to execute, or edit `manifest.yaml` first. Point the user at [`/v:status {{args}}`](v-status.md) to inspect.
Copy file name to clipboardExpand all lines: commands/v-resume.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -29,7 +29,7 @@ Resume is **Engine-A-owned**: it does not rely on Workflows (whose resume is sam
29
29
- For a Codex worktree job with a recorded `session_id`, the codex adapter may use `codex exec resume <session_id>` instead of a cold start. Either way, the **scope gate re-runs** on return.
30
30
- Update each job's `status` and write `state.json` after every transition.
31
31
32
-
6.**Continue the pipeline** from the reconciled phase: re-collect results, run the scope gate on every job, then the three-pass Review Gate (AC-gated), then merge worktree diffs on PASS. Already-`done` jobs are not re-run.
32
+
6.**Continue the pipeline** from the reconciled phase: re-collect results, run the scope gate on every job, then the three-pass Review Gate (AC-gated), then merge worktree diffs on PASS. Already-`done` jobs are not re-run.**On reaching `MERGED`, commit the run substrate exactly as [`parallel-dispatcher`](../agents/parallel-dispatcher.md)'s Step 7 does** — `state.json` (phase written as `MERGED` first, then committed together with the rest), `results/*.json`, and the memory/scorecard files if this resume refreshed them — **before** handing off to `superpowers:finishing-a-development-branch`. This matters *especially* on the resume path: the whole point of resuming is recovering from a crash or interruption, so leaving the just-recovered state uncommitted means a subsequent worktree cleanup can silently erase the very state resume just fixed.
33
33
34
34
7.**Report.** Which jobs were skipped (already landed), which were re-dispatched, which stayed **blocked behind an open breaker** (and the exact unblock action — top up credits or re-auth via `/v:init`), and the resulting `phase`. Point the user at [`/v:status {{args}}`](v-status.md) to inspect.
0 commit comments