Skip to content

Commit 6f18de7

Browse files
copeusclaude
andcommitted
release: v3.2.0 — the triage gate is on by default, and the claim that kept it off was wrong
The Stop triage gate shipped OFF, justified in our own audit table with: "turning it on blocks turn-end in every session of every install, including sessions that never touched Compound V." A live probe disproved both halves. no .claude/compound-v.json -> silent (most installs) config present, no uncovered change -> silent docs/superpowers/**, hook's store -> exempt uncovered code changes -> fires ONCE per session, marker before block any timeout/unreadable/git error -> fails open, whole rule bounded at ~800 ms The real population is a repository that deliberately initialised Compound V, once per session, with code changes no triage record covers — exactly the failure this plugin exists to catch. The complaint that started the 3.0 line was an agent skipping the pipeline; leaving the one mechanism that catches it switched off was not caution, it was mechanism-with-no-caller wearing a config key. That is the SECOND published limitation in two releases that did not survive being checked (3.1.2 was the clamp). Both were written from reading one function instead of the path around it, and both were corrected only because something made me look. The flip then introduced a bug of its own. jq's `//` is the ALTERNATIVE operator: it yields the RHS for null AND for false, so `.enforcement.triage_gate // true` turns an explicit `false` back into `true` and the opt-out documented in the gate's own block message would silently not work. Caught by its own test on the first run — the opt-out test was written before the flip was believed. Now an explicit `== false` comparison, boolean or string. Consequence pinned rather than discovered: the triage rule runs first, so a project with pipeline_bypass:true and no triage_gate key now sees the triage wording instead of the bypass wording. Deliberate — /v:triage IS the first step of the correction the bypass rule asks for — and `"triage_gate": false` restores the old message. Opt out with {"enforcement": {"triage_gate": false}}. Documented in README, /v:init and the block message. pipeline_bypass unchanged and still off. tests/test-epic-goal-stop.sh: 88 -> 98 checks. Eleven of twelve unused-native rows now close fully; agentType remains at its designed end state, and triage keeps a small honest ⚠ — UserPromptSubmit still carries a reminder and enforcement lands one turn later at Stop. The gate makes skipping expensive, not impossible. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 774f858 commit 6f18de7

8 files changed

Lines changed: 173 additions & 36 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{
1010
"name": "superpowers-v",
1111
"description": "Compound V for Superpowers: triple parallel pre-flight (code archaeology + domain-expert + Context7 library validator), disjoint partitioning, manifest-driven multi-backend dispatch (Claude + Codex + Antigravity + Cursor), git-diff scope enforcement, crash-resumable runs, adaptive tier-based routing, epic mode, research-grounded brainstorming (gated pre-brainstorm recon + batched elicitation), V-memory local-first semantic+lexical recall over docs/superpowers (opt-in pure-python embeddings + a deterministic recall→action bridge), and batched parallel dispatch (Opus default, narrow Sonnet exception)",
12-
"version": "3.1.2",
12+
"version": "3.2.0",
1313
"source": "./",
1414
"author": {
1515
"name": "Oleg",

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "superpowers-v",
33
"description": "Compound V for Superpowers: triple parallel pre-flight (code archaeology + domain-expert advisor + library/doc validator via Context7), disjoint file partitioning, manifest-driven multi-backend dispatch (Claude + headless Codex + Antigravity + Cursor workers), git-diff scope enforcement, crash-resumable runs, adaptive tier-based routing, epic mode for multi-feature builds, V-memory local-first semantic+lexical recall over docs/superpowers (opt-in pure-python embeddings + a deterministic recall\u2192action bridge), and batched parallel dispatch (Opus default, Sonnet for narrow junior-task carve-out), plus /v:onboard — a project-onboarding command that builds a citation-verified knowledge base + AGENTS.md/CLAUDE.md bridge behind a human gate. Auto-intercepts four transitions: pre-brainstorm recon \u2192 brainstorming \u2192 writing-plans \u2192 execution.",
4-
"version": "3.1.2",
4+
"version": "3.2.0",
55
"author": {
66
"name": "Oleg",
77
"email": "copeus@gmail.com"

CHANGELOG.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,44 @@ All notable changes to **superpowers-v (Compound V)** are documented here.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project uses semantic versioning.
66

7+
## [3.2.0] - 2026-09-02
8+
9+
### Changed — the triage gate is ON by default, and the claim that kept it off was wrong
10+
11+
This is a behaviour change, and it exists because a limitation this project published about itself did not survive being checked. **Twice in two releases now.**
12+
13+
The `Stop` triage gate shipped off under `enforcement.triage_gate`, and the audit table justified that with: *"turning it on by default blocks turn-end in every session of every install, including for sessions that never touched Compound V."* A live probe on 2026-09-02 disproved both halves:
14+
15+
| State | Behaviour |
16+
|---|---|
17+
| no `.claude/compound-v.json` | **silent** — a project that never ran `/v:init` is untouched, which is most installs |
18+
| config present, no uncovered change | silent |
19+
| `docs/superpowers/**`, the hook's own store | exempt |
20+
| uncovered code changes | fires **once per session**, marker written *before* the block, so it cannot loop |
21+
| any timeout / unreadable record / git error | **fails open**, whole rule bounded at ~800 ms |
22+
23+
The real population is *a repository that deliberately initialised Compound V, once per session, with code changes no triage record covers*. That is exactly the failure this plugin exists to catch — the complaint that started the 3.0 line was an agent skipping the pipeline — and leaving the one mechanism that catches it switched off was not caution. It was the mechanism-with-no-caller defect wearing a config key.
24+
25+
**Opt out with `"enforcement": {"triage_gate": false}`** in `.claude/compound-v.json`. Documented in the README, in `/v:init`, and in the block message itself. `pipeline_bypass` is unchanged and still off.
26+
27+
### Fixed — the flip introduced a bug that would have made the opt-out a lie
28+
29+
`jq`'s `//` is the **alternative** operator: it yields the right-hand side when the left is `null` **or `false`**. So the obvious `.enforcement.triage_gate // true` turns an explicit `"triage_gate": false` back into `true`, and the opt-out documented in the gate's own block message would silently not work.
30+
31+
Caught by its own test on the first run of the flip — the opt-out test was written before the flip was believed. The value is now read with an explicit `== false` comparison, and both the boolean and the string form turn it off.
32+
33+
### Changed — the triage gate now shadows the bypass rule, deliberately
34+
35+
Both rules say *"you changed code without X"*, and only one response per `Stop` event is permitted. The more specific diagnosis goes first: `/v:triage` **is** the first step of the correction the bypass rule asks for. So a project with `pipeline_bypass: true` and no `triage_gate` key now sees the triage wording instead of the bypass wording. Setting `"triage_gate": false` restores the old message. Pinned by three tests so it can never become an accident.
36+
37+
`tests/test-epic-goal-stop.sh`: 88 → **98 checks**, including the opt-out, the shadowing, and the four live-probed states.
38+
39+
### Where the native-mechanism audit stands now
40+
41+
Eleven of the twelve "native mechanism exists, we were not using it" rows close fully. The remaining one is `agentType`, at its designed end state and explained in the table.
42+
43+
Triage-at-prompt-arrival keeps a small, honest ⚠: `UserPromptSubmit` still carries a *reminder*, and the enforcement lands one turn later at `Stop`. Between those two points nothing stops work beginning without triage. The gate makes that expensive, not impossible — and no wording here should be read as saying otherwise.
44+
745
## [3.1.2] - 2026-09-02
846

947
### Fixed — a caveat this project published about itself was wrong

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ That's it.
128128
- **Epic mode is bounded by default** — it stops after each feature for a human checkpoint. It is *not* a fire-and-forget overnight build unless you raise the budget.
129129
- **Marathon mode (opt-in) is still not fire-and-forget-overnight.** It removes the per-feature checkpoint and adds an arbiter panel + blocker ledger + global breakers so it can run further unattended in one sitting — but on its own it does not self-revive after a hard death. If the session dies, you re-run `/v:epic <epic-id>` yourself; it resumes from the last committed state.
130130
- **Auto-Resurrection (opt-in, v2.11) is a bounded catch-up, not an always-on service.** With `epic.autonomy.watch` on, a scheduler wakes roughly every 30 minutes and resumes a genuinely-dead marathon epic for you, up to a resume cap. It pauses or misses fires while the session is busy/unavailable, only catches up once per app open/wake on the on-disk tier, and needs both a quota reset and a still-authenticated session to survive quota exhaustion. A machine that is truly off is not covered; that needs remote infrastructure, which this does not ship.
131+
- **The triage gate is ON by default (3.2.0), and here is how to turn it off.** Once per session, in a repo that has a `.claude/compound-v.json`, if the working tree carries code changes that no triage record covers, the `Stop` hook holds the turn open and asks for `/v:triage`. It is exempt on `docs/superpowers/**`, it fires at most once per session, it is bounded at ~800 ms and fails open on any timeout or error, and a project that never ran `/v:init` never sees it. To opt out:
132+
133+
```json
134+
{ "enforcement": { "triage_gate": false } }
135+
```
136+
137+
in `.claude/compound-v.json`. An explicit `false` is the only value that turns it off. It is **advisory** — the runtime discards a `Stop` block when a turn ends via a tool result or a loop tick, and `CLAUDE_CODE_STOP_HOOK_BLOCK_CAP` (default 8) lets the harness override it outright. It raises the cost of skipping the pipeline; it cannot make skipping impossible.
131138
- No daemon, no server, no MCP service, no made-up cost numbers. Everything is small, readable scripts.
132139

133140
---

commands/v-init.md

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ was, in those two fields).
544544
}
545545
},
546546
"review": { "cross_model": false },
547-
"enforcement": { "pipeline_bypass": false, "triage_gate": false },
547+
"enforcement": { "pipeline_bypass": false, "triage_gate": true },
548548
"brainstorm": {
549549
"deep_research": "ask",
550550
"batch_elicitation": true
@@ -633,15 +633,24 @@ identically to `balanced`. Only `cost-aware.claude.standard` differs: `sonnet`,
633633
fixed pair: each reader owns exactly one key and reads it fail-closed-to-OFF
634634
(`jq -r '.enforcement.<key> // false'`), so a key that is absent, misspelled, malformed or unknown
635635
to this version is simply OFF and a future release adds a gate by adding a key — never by changing
636-
the shape. Seed the block above verbatim; seed a **`false`** for every gate the installed version
637-
documents, and leave keys you do not recognize untouched when re-running `/v:init` over an existing
638-
config. Shipped gates: **`pipeline_bypass`** (v2.18 — tracked source changed this session with no
639-
run record and no accepted fast-path record; corrects toward the pipeline or its sanctioned
640-
Pre-Evaluation shortcut) and **`triage_gate`** (v3.0 — non-exempt files changed with no committed
641-
triage record covering that diff). **`/v:init` writes them OFF and never offers to turn one on.**
642-
Enabling a gate is a deliberate human edit of this file, because a false positive costs a blocked
643-
turn in every session of everyone who shares this repo, and both rules are **advisory and
644-
best-effort by construction**: each blocks at most once while its own temp-dir marker survives, and
636+
the shape. Seed the block above verbatim and leave keys you do not recognize untouched when
637+
re-running `/v:init` over an existing config. Shipped gates: **`pipeline_bypass`** (v2.18 — tracked
638+
source changed this session with no run record and no accepted fast-path record; corrects toward
639+
the pipeline or its sanctioned Pre-Evaluation shortcut) and **`triage_gate`** (v3.0 — non-exempt
640+
files changed with no committed triage record covering that diff).
641+
642+
**`triage_gate` is ON by default as of 3.2.0; `pipeline_bypass` is still OFF.** The two are not
643+
symmetrical. `triage_gate` asks for the *first* step of the correction (`/v:triage`), it is exempt
644+
on `docs/superpowers/**`, and a project with no `.claude/compound-v.json` never sees it at all —
645+
so its population is exactly "a repo that deliberately initialised Compound V, once per session,
646+
with uncovered code changes". It shipped OFF on a blast-radius claim this project made about
647+
itself and never checked; a live probe on 2026-09-02 disproved the claim, and leaving the one
648+
mechanism that catches a skipped pipeline switched off was the mechanism-with-no-caller defect
649+
wearing a config key.
650+
651+
**Opt out with `"triage_gate": false`** — an explicit boolean `false` (or the string `"false"`),
652+
which is the ONLY value that turns it off. Enabling `pipeline_bypass` is still a deliberate human
653+
edit. Both rules are **advisory and best-effort by construction**: each blocks at most once while its own temp-dir marker survives, and
645654
the runtime silently discards a `Stop` block when a turn ends via a tool result, an MCP end-turn or
646655
a loop tick. They raise the cost of skipping the pipeline; they cannot make skipping impossible, so
647656
do not describe them to the user as enforcement that cannot be bypassed. The armed **epic goal**

0 commit comments

Comments
 (0)