wicked-garden 12.53.0 → 12.53.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.53.0"}], "version": "12.53.0"}
1
+ {"name": "wicked-garden", "owner": {"name": "Mike Parcewski"}, "plugins": [{"name": "wicked-garden", "source": "./", "description": "Your coding agent already plans and swarms \u2014 Wicked Garden is the curated toolkit for what it can't: proof-not-claims gates, code links grep can't see, deterministic refactor, cross-session memory, multi-model second opinions (fallback seats labelled). Don't fight the harness; fill its gaps. The gate needs wicked-vault (a self-contained infra peer, installed directly) and re-derives through garden's built-in engine; estate/bus are opt-in layers (wicked-testing and wicked-brain are retired \u2014 QE ships in-catalog as the qe domain, memory lives in wicked-estate).", "version": "12.53.2"}], "version": "12.53.2"}
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.53.0",
3
+ "version": "12.53.2",
4
4
  "description": "Your coding agent's harness already plans and swarms; Wicked Garden is the curated toolkit for what it can't do alone. Proof, not claims \u2014 gates re-derive 'done' through the internal loom engine (fail-closed, independently attested via wicked-vault), so a self-asserted pass can't lie its way green. Relationships grep can't see \u2014 the wicked-estate code graph + injected bus/dispatch/capability/archetype edges power blast-radius & lineage. Plus deterministic multi-file refactor (wicked-patch), cross-session memory + knowledge (the mem domain over wicked-estate), multi-model second opinions (fallback seats labelled) (jam:council), portable expertise as on-demand skill-refs, and evidence-gated testing (the in-catalog qe domain). It reads the shape of your work to apply the right rigor \u2014 steering, not a pipeline \u2014 then gets out of the way. The compiler stamps a self-contained evidence gate into any repo that runs with no wicked-garden installed. Don't fight the harness; fill its gaps. The evidence gate requires wicked-vault, a self-contained infra peer wicked-garden installs directly; wicked-bus is an opt-in layer \u2014 install what you'll use, the toolkit works without the rest.",
5
5
  "wicked_vault_version": "^0.5.0",
6
6
  "wicked_ledger_version": "^0.6.0",
package/CHANGELOG.md CHANGED
@@ -2,6 +2,17 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [12.53.2] — 2026-10-11
6
+
7
+ ### Fixed
8
+ - **qe accept runs in one turn inside a governed unit (PR #1291, #1290).** With `WICKED_RUN_ID` set, `wicked-garden-qe` accept runs writer → executor → reviewer inline in one turn, with no sub-agent dispatch, and ends only on the recorded verdict. A claude QE seat no longer ends its turn on the writer's test plan.
9
+
10
+ ## [12.53.1] — 2026-10-11
11
+
12
+ ### Fixed
13
+ - **One wicked-ledger resolver, `$WICKED_LEDGER_PKG_DIR` first (PR #1284, crew#951).** `wicked-garden-qe` accept, the gate and the campaign scoreboard resolve wicked-ledger through one resolver that honours `$WICKED_LEDGER_PKG_DIR` first (wicked-crew 0.9.7 sets it for a governed run), so a governed QE unit records its verdict without the repository installing wicked-ledger.
14
+ - **Learn: the author computes claim ids (PR #1288, E2E F-LEARN-1);** synthesize leaves them.
15
+
5
16
  ## [12.53.0] — 2026-10-11
6
17
 
7
18
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wicked-garden",
3
- "version": "12.53.0",
3
+ "version": "12.53.2",
4
4
  "type": "module",
5
5
  "description": "Curated toolkit for what AI coding agents can't do alone: evidence-gated work, codegraph relationships, deterministic multi-file refactor, multi-model second opinions, and cross-session memory. Installs as a Claude Code plugin.",
6
6
  "keywords": [
@@ -93,6 +93,7 @@
93
93
  import { existsSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
94
94
  import { join, dirname, resolve, isAbsolute } from "node:path";
95
95
  import { pathToFileURL } from "node:url";
96
+ import { resolveLedgerModule } from "./ledger-pkg.mjs";
96
97
  import { parseArgs } from "node:util";
97
98
 
98
99
  import {
@@ -168,54 +169,9 @@ export function resolveLedgerRootLocal(repoRoot, env = process.env) {
168
169
  return current;
169
170
  }
170
171
 
171
- // --- wicked-ledger resolution (target-repo-anchored, like gate.mjs) ----------
172
-
173
- function esmEntryForPackageDir(pkgDir) {
174
- const pj = join(pkgDir, "package.json");
175
- if (!existsSync(pj)) return null;
176
- const pkg = readJsonSafe(pj);
177
- if (!pkg) return null;
178
- const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
179
- const rel =
180
- (dot && typeof dot === "object" && (dot.import || dot.default)) ||
181
- (typeof dot === "string" ? dot : null) ||
182
- pkg.module ||
183
- pkg.main ||
184
- "index.js";
185
- return join(pkgDir, rel);
186
- }
172
+ // --- wicked-ledger resolution: the shared resolver (./ledger-pkg.mjs) -----------
187
173
 
188
- export async function resolveLedgerModule(repoRoot, env = process.env) {
189
- // 1. explicit override (tests, TH-6 wiring, unpublished-floor installs)
190
- if (env.WICKED_LEDGER_PKG_DIR) {
191
- const entry = esmEntryForPackageDir(env.WICKED_LEDGER_PKG_DIR);
192
- if (entry && existsSync(entry)) return await import(pathToFileURL(entry).href);
193
- return null;
194
- }
195
- // 2. bare import (global / hoisted install)
196
- try {
197
- return await import("wicked-ledger");
198
- } catch {
199
- /* fall through */
200
- }
201
- // 3. walk up from the target repo root
202
- let dir = resolve(repoRoot);
203
- for (let i = 0; i < 10; i++) {
204
- const cand = join(dir, "node_modules", "wicked-ledger");
205
- const entry = esmEntryForPackageDir(cand);
206
- if (entry && existsSync(entry)) {
207
- try {
208
- return await import(pathToFileURL(entry).href);
209
- } catch {
210
- return null;
211
- }
212
- }
213
- const parent = dirname(dir);
214
- if (parent === dir) break;
215
- dir = parent;
216
- }
217
- return null;
218
- }
174
+ export { resolveLedgerModule } from "./ledger-pkg.mjs";
219
175
 
220
176
  // --- evidence extraction ------------------------------------------------------
221
177
 
@@ -83,50 +83,15 @@ import { existsSync, readdirSync, readFileSync } from "node:fs";
83
83
  import { join, dirname, isAbsolute } from "node:path";
84
84
  import { spawnSync } from "node:child_process";
85
85
  import { createHash } from "node:crypto";
86
- import { createRequire } from "node:module";
87
86
  import { pathToFileURL } from "node:url";
88
87
  import { parseArgs } from "node:util";
89
88
 
90
89
  import { buildExclusionsClause } from "./flake-policy.mjs";
91
90
  import { resolveVaultModule, applyVaultIntegrity, VaultEvidenceError } from "./vault-evidence.mjs";
92
91
  import { crewRunStamp } from "./crew-run.mjs";
92
+ import { resolveLedgerModule } from "./ledger-pkg.mjs";
93
93
 
94
- // --- wicked-ledger resolution (cwd-anchored; mirrors wicked-vault's bus.mjs) ---
95
-
96
- function esmEntryForPackage(resolvedFile) {
97
- let dir = dirname(resolvedFile);
98
- for (let i = 0; i < 10; i++) {
99
- const pj = join(dir, "package.json");
100
- if (existsSync(pj)) {
101
- let pkg;
102
- try { pkg = JSON.parse(readFileSync(pj, "utf8")); } catch { return null; }
103
- const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
104
- const rel =
105
- (dot && typeof dot === "object" && (dot.import || dot.default)) ||
106
- (typeof dot === "string" ? dot : null) ||
107
- pkg.module || pkg.main || "index.js";
108
- return join(dir, rel);
109
- }
110
- const parent = dirname(dir);
111
- if (parent === dir) break;
112
- dir = parent;
113
- }
114
- return null;
115
- }
116
-
117
- async function resolveLedgerModule(cwd) {
118
- try {
119
- return await import("wicked-ledger");
120
- } catch { /* fall through */ }
121
- try {
122
- const require = createRequire(join(cwd, "__qe_gate_anchor__.js"));
123
- const located = require.resolve("wicked-ledger");
124
- const esm = esmEntryForPackage(located) || located;
125
- return await import(pathToFileURL(esm).href);
126
- } catch {
127
- return null;
128
- }
129
- }
94
+ // --- wicked-ledger resolution: the shared resolver (./ledger-pkg.mjs, $WICKED_LEDGER_PKG_DIR first) ---
130
95
 
131
96
  /**
132
97
  * Resolve the ledger root the gate writes to (TH-6). MUST mirror the TH-2
@@ -357,7 +322,7 @@ export async function runGate({ projectId, runId, verdict, verdictSummary, ratio
357
322
  process.stderr.write(
358
323
  JSON.stringify({
359
324
  error: "LEDGER_UNRESOLVABLE",
360
- detail: "wicked-ledger is not resolvable from this repo — npm i --no-save wicked-ledger",
325
+ detail: "wicked-ledger is not resolvable — set WICKED_LEDGER_PKG_DIR (a governed crew run sets it) or npm i --no-save wicked-ledger",
361
326
  }) + "\n"
362
327
  );
363
328
  process.exit(3);
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The ONE wicked-ledger resolver of garden's QE pipeline (accept, the gate, the campaign
3
+ * scoreboard). wicked-ledger is resolved for the TARGET repo — the plugin ships no node_modules —
4
+ * in this order:
5
+ *
6
+ * 1. `$WICKED_LEDGER_PKG_DIR` — an explicit package dir. wicked-crew exports its OWN bundled
7
+ * wicked-ledger here (wicked-crew#951), so a governed run's QE unit records its verdict with
8
+ * the very package crew's acceptance check reads it with, and needs no install in the
9
+ * worktree (a fenced governed seat cannot `npm i`, and an install would change the tree).
10
+ * Set but unusable ⇒ `null` (an explicit pin never falls back to a different package).
11
+ * 2. a bare `import("wicked-ledger")` (a global / hoisted install);
12
+ * 3. a walk up from the target repo for `node_modules/wicked-ledger`.
13
+ *
14
+ * `null` when none resolves; callers say so (never a silent no-op).
15
+ */
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { dirname, join, resolve } from "node:path";
18
+ import { pathToFileURL } from "node:url";
19
+
20
+ export const LEDGER_PKG_ENV = "WICKED_LEDGER_PKG_DIR";
21
+
22
+ /** The ESM entry file of a package dir (its `exports["."]` import/default, else module/main). */
23
+ export function esmEntryForPackageDir(pkgDir) {
24
+ const pj = join(pkgDir, "package.json");
25
+ if (!existsSync(pj)) return null;
26
+ let pkg;
27
+ try {
28
+ pkg = JSON.parse(readFileSync(pj, "utf8"));
29
+ } catch {
30
+ return null;
31
+ }
32
+ const dot = pkg.exports && pkg.exports["."] !== undefined ? pkg.exports["."] : pkg.exports;
33
+ const rel =
34
+ (dot && typeof dot === "object" && (dot.import || dot.default)) ||
35
+ (typeof dot === "string" ? dot : null) ||
36
+ pkg.module ||
37
+ pkg.main ||
38
+ "index.js";
39
+ return join(pkgDir, rel);
40
+ }
41
+
42
+ /** The resolved wicked-ledger module for `repoRoot`, or `null`. */
43
+ export async function resolveLedgerModule(repoRoot = process.cwd(), env = process.env) {
44
+ const pinned = env[LEDGER_PKG_ENV]?.trim();
45
+ if (pinned) {
46
+ const entry = esmEntryForPackageDir(pinned);
47
+ if (!entry || !existsSync(entry)) return null;
48
+ try {
49
+ return await import(pathToFileURL(entry).href);
50
+ } catch {
51
+ return null;
52
+ }
53
+ }
54
+ try {
55
+ return await import("wicked-ledger");
56
+ } catch {
57
+ /* fall through */
58
+ }
59
+ let dir = resolve(repoRoot);
60
+ for (let i = 0; i < 10; i++) {
61
+ const entry = esmEntryForPackageDir(join(dir, "node_modules", "wicked-ledger"));
62
+ if (entry && existsSync(entry)) {
63
+ try {
64
+ return await import(pathToFileURL(entry).href);
65
+ } catch {
66
+ return null;
67
+ }
68
+ }
69
+ const parent = dirname(dir);
70
+ if (parent === dir) break;
71
+ dir = parent;
72
+ }
73
+ return null;
74
+ }
@@ -43,9 +43,9 @@ Relative paths in this skill are relative to the directory that contains this SK
43
43
  |---|---|---|---|
44
44
  | `scope` | neutral | nothing | Name the slug (kebab-case, at most 64 characters), the kind (`topic` or `event`), 3 to 7 questions to answer, what is out of scope, and the source policy: primary sources first (specs, official docs, release notes, the project's own site), dated reporting for events. Read `.wicked/knowledge/<slug>/` if it exists: then this run is a **refresh** (see refs/refresh.md). |
45
45
  | `research` | neutral | nothing | Fetch sources with your web tools (or `curl -sL`). For each source, record the URL, title, published date when the page states one, and `observed_at` = now in UTC. Draft candidate claims, each tied to the sources that support it. No network: write `research: no web access` and stop; never answer from memory as if it were sourced. |
46
- | `synthesize` | neutral | nothing | Turn the candidates into the claims ledger (refs/claims.md): one atomic, checkable statement per claim, deduplicated, ids from `claim_id`. Keep only claims that would help a fresh session in 3 months. On a refresh, output the diff against the existing ledger. |
46
+ | `synthesize` | neutral | nothing | Turn the candidates into the claims ledger (refs/claims.md): one atomic, checkable statement per claim, deduplicated. Leave new claim ids to the author (a neutral seat may not run scripts); on a refresh keep each existing id. Keep only claims that would help a fresh session in 3 months. On a refresh, output the diff against the existing ledger. |
47
47
  | `walkthrough` | neutral | nothing | Teach it in the run thread: a 5-line summary, a worked example, what changed (on a refresh), the open questions, and 3 to 5 check questions. The operator answers, asks or corrects by sending the step back; answer each point, re-teach what was unclear, and mark which corrections you verified against a source. |
48
- | `author` | creator | `.wicked/knowledge/<slug>/`, skills | Write the files (refs/claims.md), then run the check below and paste its JSON and exit code. |
48
+ | `author` | creator | `.wicked/knowledge/<slug>/`, skills | Compute each new claim's id (`wicked-garden run scripts/learn/check.py --claim-id "<text>"`), write the files (refs/claims.md), then run the check below and paste its JSON and exit code. |
49
49
  | `review` | evaluator | nothing | Re-run the check yourself; re-fetch and spot-check at least 3 claims (every retirement, too); judge the durability test; last line `VERDICT: PASS` or `VERDICT: FAIL`. |
50
50
  | `check` | any | nothing | `wicked-garden run scripts/learn/check.py --repo . [--slug <slug>]` |
51
51
  | `index` | human or daemon only | estate knowledge | `wicked-garden run scripts/learn/index.py --repo <default-branch checkout>` after the PR merged. It refuses inside a governed run. |
@@ -87,6 +87,24 @@ invocation.)
87
87
  - `--phase review` — review existing evidence
88
88
  - `--json` — emit JSON envelope
89
89
 
90
+ ## Governed unit (`WICKED_RUN_ID` set): one turn, inline
91
+
92
+ A governed wicked-crew unit (`WICKED_RUN_ID` is set) is ONE headless turn: whatever you print
93
+ last is the unit's reply, and the engine reads its `VERDICT:` line. So, on every seat:
94
+
95
+ - Run writer → executor → reviewer **inline, in this one turn**. Carry out each hand-off below
96
+ yourself: open the worker skill (Skill tool, or its SKILL.md from your catalog), do its steps,
97
+ and come back here. Do not dispatch an `Agent` / `Task` sub-agent or a fork. A headless unit has
98
+ none, and a forked result returns to nobody.
99
+ - A worker's output (test plan, evidence report) is an **intermediate artifact**: save it under
100
+ `{EVIDENCE_DIR}` (`test-plan.md`, `evidence.json`) and continue to the next phase. Never end
101
+ your reply on it.
102
+ - Never end the turn before step 6 has written the verdict row and your reply's last line is
103
+ `VERDICT: PASS` or `VERDICT: FAIL`. If a step fails, still finish: record FAIL with
104
+ `reason: inconclusive — <why>` and print that verdict line.
105
+ - Reviewer isolation is evidence-only dispatch here: judge from the scenario, plan and evidence
106
+ files, never from what you saw while executing.
107
+
90
108
  ## Instructions
91
109
 
92
110
  ### Preflight: Validate Input
@@ -123,7 +141,15 @@ the run's canonical UUID. This serves three goals at once:
123
141
  // Resolve the ledger root (wicked-ledger >= 0.6.0): WICKED_QE_LEDGER_DIR when set — inside a
124
142
  // governed wicked-crew run, the run's own ledger OUTSIDE the worktree (crew#951) — else dual-read
125
143
  // (Phase 6c): '.wicked-qe', or a legacy '.wicked-testing' root written before the rename. <!-- historical -->
126
- import { createDomainStore, resolveLedgerRoot } from 'wicked-ledger';
144
+ // wicked-ledger through the ONE resolver ($WICKED_LEDGER_PKG_DIR — set by a governed crew run —,
145
+ // else an install the target repo resolves); see § wicked-ledger resolution.
146
+ import { pathToFileURL } from 'node:url';
147
+ import { join as joinPath } from 'node:path';
148
+ // {WT_LIB} is a native path (Windows too): import it as a file URL, never a bare string.
149
+ const { resolveLedgerModule } = await import(pathToFileURL(joinPath(String.raw`{WT_LIB}`, 'ledger-pkg.mjs')).href);
150
+ const ledger = await resolveLedgerModule(process.cwd());
151
+ if (!ledger) throw new Error("wicked-ledger is not resolvable: set WICKED_LEDGER_PKG_DIR or npm i --no-save wicked-ledger");
152
+ const { createDomainStore, resolveLedgerRoot } = ledger;
127
153
  import { join } from 'node:path';
128
154
  const LEDGER_ROOT = resolveLedgerRoot(process.cwd());
129
155
  const store = createDomainStore({ root: LEDGER_ROOT });
@@ -162,9 +188,9 @@ repo under audit, etc.) could otherwise inject instruction-looking prose
162
188
  writer's instruction turn. The writer has `allowed-tools: Read` so it can
163
189
  open the scenario itself.
164
190
 
165
- Hand off to the `wicked-garden-qe-acceptance-test-writer` worker skill (it runs in an isolated context):
191
+ Hand off to the `wicked-garden-qe-acceptance-test-writer` worker skill (an isolated context where the host forks one; inline in a governed unit):
166
192
 
167
- **Hand-off** — open the `wicked-garden-qe-acceptance-test-writer` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
193
+ **Hand-off** — open the `wicked-garden-qe-acceptance-test-writer` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog; either way carry it out inline in this turn (no sub-agent), then continue here.
168
194
 
169
195
  ```markdown
170
196
  Generate an evidence-gated test plan for the acceptance scenario
@@ -187,20 +213,23 @@ at the path below.
187
213
  6. Map every success criterion to specific assertions.
188
214
  7. Flag any specification mismatches you discover.
189
215
 
190
- Return the complete test plan in the standard format.
216
+ Produce the complete test plan in the standard format. It is an intermediate
217
+ artifact of `qe accept`: hand it back and continue (garden#1290).
191
218
 
192
219
  ```
193
220
 
194
- If `--phase write`, stop here.
221
+ Save the plan to `{EVIDENCE_DIR}/test-plan.md` (the reviewer reads it from there).
222
+
223
+ If `--phase write`, stop here. Otherwise continue to step 3 in this same turn.
195
224
 
196
225
  ### 3. Phase: Execute (Evidence Collection)
197
226
 
198
227
  The run record was already created in step 0 so the evidence dir could derive
199
228
  from its UUID. Here we dispatch the executor against that dir.
200
229
 
201
- Hand off to the `wicked-garden-qe-acceptance-test-executor` worker skill (it runs in an isolated context):
230
+ Hand off to the `wicked-garden-qe-acceptance-test-executor` worker skill (an isolated context where the host forks one; inline in a governed unit):
202
231
 
203
- **Hand-off** — open the `wicked-garden-qe-acceptance-test-executor` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
232
+ **Hand-off** — open the `wicked-garden-qe-acceptance-test-executor` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog; either way carry it out inline in this turn (no sub-agent), then continue here.
204
233
 
205
234
  ```markdown
206
235
  Execute this test plan and collect evidence artifacts.
@@ -219,13 +248,14 @@ Execute this test plan and collect evidence artifacts.
219
248
  5. Continue to next step even if current step fails
220
249
  6. Record timestamps for every step
221
250
 
222
- Return the complete evidence report.
251
+ Produce the complete evidence report. It is an intermediate artifact of
252
+ `qe accept`: hand it back and continue (garden#1290).
223
253
 
224
254
  ```
225
255
 
226
256
  Update run status in DomainStore after execution.
227
257
 
228
- If `--phase execute`, stop here.
258
+ If `--phase execute`, stop here. Otherwise continue to step 4 in this same turn.
229
259
 
230
260
  ### 4. Phase: Pre-Review Cold Context (Optional, pre-dispatch validated)
231
261
 
@@ -271,7 +301,7 @@ if (result.rejected) {
271
301
 
272
302
  Example safe query:
273
303
 
274
- **Hand-off** — open the `wicked-garden-mem` skill and run its `recall` action with `<scenario-category> test rules` as the query; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
304
+ **Hand-off** — open the `wicked-garden-mem` skill and run its `recall` action with `<scenario-category> test rules` as the query; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog; either way carry it out inline in this turn (no sub-agent), then continue here.
275
305
 
276
306
  If the knowledge layer is absent, skip this phase entirely — no `context.md` is
277
307
  written and the reviewer still has everything it needs (scenario + plan +
@@ -283,7 +313,7 @@ evidence).
283
313
  It does NOT receive the executor's conversation, reasoning, or stdout/stderr directly.
284
314
  Pass paths, not content, where possible.
285
315
 
286
- **Hand-off** — open the `wicked-garden-qe-acceptance-test-reviewer` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog and carry it out inline, then continue here.
316
+ **Hand-off** — open the `wicked-garden-qe-acceptance-test-reviewer` skill with the brief below as the argument; on Claude Code this is the Skill tool, on any other seat open the named skill from your catalog; either way carry it out inline in this turn (no sub-agent), then continue here.
287
317
 
288
318
  ```markdown
289
319
  Review the evidence against the test plan assertions.
@@ -306,9 +336,11 @@ flag as CONTEXT_CONTAMINATION and return `VERDICT: FAIL` with
306
336
  2. Read the test plan file at the path above
307
337
  3. Read evidence files from the evidence directory (including context.md if present)
308
338
  4. Evaluate each assertion against evidence
309
- 5. End with one plain-text line `VERDICT: PASS` or `VERDICT: FAIL` as the LAST
310
- line of your reply (never quote another VERDICT line); missing evidence or
311
- CONTEXT_CONTAMINATION is FAIL with `reason: inconclusive — <why>`
339
+ 5. End the review with one plain-text line `VERDICT: PASS` or `VERDICT: FAIL`
340
+ (never quote another VERDICT line); missing evidence or
341
+ CONTEXT_CONTAMINATION is FAIL with `reason: inconclusive — <why>`. Hand the
342
+ review back: `qe accept` still writes the verdict (step 6) and prints that
343
+ line last (garden#1290)
312
344
  6. For any EQUIVALENT_TO_BASELINE assertion, also return the equivalence facet
313
345
  { baseline_ref, baseline_sha, method, diff_count, tolerance, matched } so the
314
346
  orchestrator can persist it on the verdict (see `verdict.equivalence`).
@@ -394,7 +426,7 @@ const verdictRecord = store.create('verdicts', {
394
426
  });
395
427
 
396
428
  // 3. Materialize the public manifest at the contract path
397
- import { buildManifest, emitBusEvent } from 'wicked-ledger';
429
+ const { buildManifest, emitBusEvent } = ledger; // the same resolved wicked-ledger as step 0
398
430
  import { readFileSync } from 'node:fs';
399
431
  const pkgVersion = JSON.parse(readFileSync('package.json','utf8')).version;
400
432
  const runAfter = store.get('runs', run.id);
@@ -424,6 +456,9 @@ emitBusEvent('wicked.test.evidence.captured', {
424
456
 
425
457
  ### 7. Output
426
458
 
459
+ The reply's LAST line is the reviewer's `VERDICT: PASS` or `VERDICT: FAIL`, printed
460
+ only after step 6 wrote the verdict row. This is what ends the turn.
461
+
427
462
  **Without `--json`** — Present the full verdict:
428
463
 
429
464
  ```markdown
@@ -475,7 +510,13 @@ WT_LIB="$(wicked-garden path scripts/qe/lib)"
475
510
  ## wicked-ledger resolution
476
511
 
477
512
  `wicked-ledger` (npm) is the QE data layer — DomainStore, oracle queries, and
478
- manifest building. Import-style snippets above must run where the package
479
- resolves: the target project's `node_modules` (`npm i --no-save wicked-ledger`)
480
- or any directory with it installed. The pinned range lives in
481
- `.claude-plugin/plugin.json` → `wicked_ledger_version`.
513
+ manifest building. The snippets above load it through `{WT_LIB}/ledger-pkg.mjs`,
514
+ the one resolver the gate shares:
515
+
516
+ 1. `$WICKED_LEDGER_PKG_DIR`. Inside a governed wicked-crew run it is set to crew's
517
+ own wicked-ledger, the package crew's acceptance check reads the verdict with.
518
+ Do not `npm i` in a governed run: a fenced seat is refused the install, and it
519
+ would change the tree under review.
520
+ 2. otherwise, an install the target repo resolves (`npm i --no-save wicked-ledger`).
521
+
522
+ The pinned range lives in `.claude-plugin/plugin.json` → `wicked_ledger_version`.
@@ -133,6 +133,11 @@ python3 -c "import json,sys; sys.stdout.write(json.dumps({...}))" 2>/dev/null \
133
133
 
134
134
  ### 6. Compile Evidence Report
135
135
 
136
+ **Opened from `qe accept`** (garden#1290): your evidence report is an intermediate artifact of that
137
+ pipeline, not the end of the turn. Hand it back and the pipeline continues to the reviewer in the
138
+ same turn. Never end the turn on it, above all in a governed unit (`WICKED_RUN_ID` set), where your
139
+ last output is the unit's reply.
140
+
136
141
  Return a text evidence report with all captured data:
137
142
 
138
143
  ```markdown
@@ -180,6 +180,9 @@ Review any specification notes from the test plan writer. Factor these into your
180
180
  ```markdown
181
181
  ## Overall Verdict
182
182
 
183
+ **Opened from `qe accept`** (garden#1290): hand this review back and continue. `qe accept` writes the
184
+ verdict row (its step 6) and then prints the `VERDICT:` line last; that, not this review, ends the turn.
185
+
183
186
  ### Status: {PASS | FAIL | PARTIAL | INCONCLUSIVE}
184
187
 
185
188
  ### Summary
@@ -26,6 +26,11 @@ Your test plans are designed so that:
26
26
 
27
27
  You do NOT execute tests. You do NOT grade results. You produce test plans.
28
28
 
29
+ **Opened from `qe accept`** (garden#1290): your test plan is an intermediate artifact of that
30
+ pipeline, not the end of the turn. Hand it back and the pipeline continues to the executor in the
31
+ same turn. Never end the turn on it, above all in a governed unit (`WICKED_RUN_ID` set), where your
32
+ last output is the unit's reply.
33
+
29
34
  ## Why You Can Query Brain
30
35
 
31
36
  You have `Skill` access so you can query the knowledge layer (wicked-estate,