@gobing-ai/spur 0.4.1 → 0.4.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/config.global.yaml +4 -2
- package/config/templates/AGENTS.md +1 -1
- package/config/workflows/wrapup-pipeline.yaml +1 -1
- package/package.json +10 -10
- package/plugins/sp/README.md +1 -2
- package/plugins/sp/agents/super-planner.md +5 -6
- package/plugins/sp/commands/dev-review-session.md +2 -1
- package/plugins/sp/commands/dev-runall.md +18 -9
- package/plugins/sp/hooks/context-owner.ts +56 -0
- package/plugins/sp/hooks/context-post-tool.ts +23 -0
- package/plugins/sp/hooks/context-session-start.ts +49 -27
- package/plugins/sp/hooks/context-session-stop.ts +131 -30
- package/plugins/sp/hooks/pi/guard-extension.ts +21 -8
- package/plugins/sp/lib/idea-handoff.generated.mjs +4 -2
- package/plugins/sp/lib/inline-run.generated.mjs +47 -30
- package/plugins/sp/lib/plan-projection.generated.d.mts +19 -0
- package/plugins/sp/lib/plan-projection.generated.mjs +113 -0
- package/plugins/sp/lib/quality-gate.generated.d.mts +0 -12
- package/plugins/sp/lib/quality-gate.generated.mjs +48 -230
- package/plugins/sp/lib/transcript.ts +49 -21
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +1 -1
- package/plugins/sp/scripts/batch-plan.mjs +154 -1
- package/plugins/sp/scripts/batch-plan.ts +48 -3
- package/plugins/sp/scripts/inline-run-setup.mjs +24 -13
- package/plugins/sp/scripts/pr-reviewing.mjs +19 -5
- package/plugins/sp/scripts/pr-reviewing.ts +34 -9
- package/plugins/sp/scripts/quality-gate.mjs +25 -207
- package/plugins/sp/scripts/run-summary.mjs +24 -13
- package/plugins/sp/scripts/session-timeline.mjs +26 -25
- package/plugins/sp/scripts/session-timeline.ts +4 -18
- package/plugins/sp/scripts/task-diffstat.mjs +32 -29
- package/plugins/sp/scripts/task-diffstat.ts +34 -34
- package/plugins/sp/skills/indexed-context/SKILL.md +14 -7
- package/plugins/sp/skills/parallel-execution/SKILL.md +2 -2
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +1 -1
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +2 -2
- package/plugins/sp/skills/pr-reviewing/SKILL.md +7 -3
- package/plugins/sp/skills/session-review/SKILL.md +5 -3
- package/plugins/sp/skills/spur-cli/references/decision.md +9 -2
- package/plugins/sp/skills/spur-cli/references/projects.md +7 -5
- package/plugins/sp/skills/spur-dev/SKILL.md +2 -0
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +27 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -3
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +5 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +43 -4
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +4 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +13 -11
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +8 -13
- package/spur.js +14261 -2846
- package/web/_astro/{BoardApp.D66k_s_T.js → BoardApp.B3GQZvj8.js} +1 -1
- package/web/_astro/{BoardApp.D6sjAJr_.js → BoardApp.BT7L2kSb.js} +192 -192
- package/web/_astro/TaskDetail.Cxov1_N_.js +1 -0
- package/web/_astro/{arc._BUadrdH.js → arc.vaT7tPOB.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Dh7xS1Pp.js → architectureDiagram-3BPJPVTR.DRMmTjkN.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DFDVpfXm.js → blockDiagram-GPEHLZMM.cla0LO_q.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.V7_3_glh.js → c4Diagram-AAUBKEIU.D4YAIBKn.js} +1 -1
- package/web/_astro/channel.D4nG9YLf.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.De1yx7Jz.js → chunk-2J33WTMH.BrSJbMRZ.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BDhHFuxx.js → chunk-4BX2VUAB.CuLMgKF5.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.DDLkWnmC.js → chunk-55IACEB6.zkvgu54F.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.CwfiLnA7.js → chunk-727SXJPM.DxWkACh8.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.CtGDmUnM.js → chunk-AQP2D5EJ.42XrmIlH.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.BOLjpw73.js → chunk-FMBD7UC4.Bao2wMK9.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.BDhQls6O.js → chunk-ND2GUHAM.BhydojD1.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.76qBynDF.js → chunk-QZHKN3VN.CmZ82g-H.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.N0mpPHT0.js → classDiagram-4FO5ZUOK.Blr83Gt_.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.N0mpPHT0.js → classDiagram-v2-Q7XG4LA2.Blr83Gt_.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CKknFfjB.js → cose-bilkent-S5V4N54A.qmfv0SPn.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.Cw3ZWBAh.js → cynefin-OW5HDTMX.BtELhXPR.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.D3yIKCRD.js → dagre-BM42HDAG.AWmaAvXo.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.D51dO83Z.js → diagram-2AECGRRQ.DdH34KDi.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Bb-FViDj.js → diagram-5GNKFQAL.BmNPix1k.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.D3mN8S6x.js → diagram-KO2AKTUF.BNQd_Ppo.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.dMMyPcbJ.js → diagram-LMA3HP47.BAPgDi0e.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.AzbvzY4C.js → diagram-OG6HWLK6.DZ4zyLdC.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BR5I4OZb.js → erDiagram-TEJ5UH35.Q1TySMmw.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.DFqvhGkn.js → flowDiagram-I6XJVG4X.BXhFBicG.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.ByJbhH6J.js → ganttDiagram-6RSMTGT7.vHSgcuo2.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.CInHjQR3.js → gitGraphDiagram-PVQCEYII.Bi1f73C7.js} +1 -1
- package/web/_astro/{index.COh_kBxN.css → index.BhSwN8yY.css} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.Cm0dGVjJ.js → infoDiagram-5YYISTIA.DPvXZEWm.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.C3nOP6Sj.js → ishikawaDiagram-YF4QCWOH.Cz829fsV.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.4IvLa2MW.js → journeyDiagram-JHISSGLW.enRnB9Me.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DS87Cl-k.js → kanban-definition-UN3LZRKU.DnTNk6d2.js} +1 -1
- package/web/_astro/{linear.MzmRrNER.js → linear.BzGnBwNL.js} +1 -1
- package/web/_astro/{mermaid.core.fK-WNswS.js → mermaid.core.CSbTpIVz.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.BqipOHhY.js → mindmap-definition-RKZ34NQL.DGJDy8zT.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.0nBiPqFG.js → pieDiagram-4H26LBE5.HSPdi5_8.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.Szj7Zpx5.js → quadrantDiagram-W4KKPZXB.6Gv8mz2Y.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.D4UR6TWo.js → requirementDiagram-4Y6WPE33.CnBCtFwa.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.DAE7BdOs.js → sankeyDiagram-5OEKKPKP.5M8VWAu8.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BP9ZVq25.js → sequenceDiagram-3UESZ5HK.DN41XN-U.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BQW7mIxk.js → stateDiagram-AJRCARHV.ErOO3W8j.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.PbK4nDih.js → stateDiagram-v2-BHNVJYJU.B_ZHICM-.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.Ci_GvUpo.js → timeline-definition-PNZ67QCA.CWdosr07.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DNw1Y5qx.js → vennDiagram-CIIHVFJN.BHzYjNV5.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CwlkaaNe.js → wardleyDiagram-YWT4CUSO.h8x4IwPX.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.MI6ZuiH_.js → xychartDiagram-2RQKCTM6.RTapW2X8.js} +1 -1
- package/web/index.html +2 -2
- package/plugins/sp/commands/dev-parallel.md +0 -37
- package/web/_astro/TaskDetail.BynLnMNc.js +0 -1
- package/web/_astro/channel.DZVfto-r.js +0 -1
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
* `precheck`, F96 R1) and the current working tree, then writes:
|
|
8
8
|
* `.spur/run/<wbs>-diffstat.json` `{ files, insertions, deletions, paths[], sensitive }`
|
|
9
9
|
*
|
|
10
|
-
* Counts come from `git diff --numstat <base>` (tracked changes; binary rows count the
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* if a miscount
|
|
10
|
+
* Counts come from `git diff --numstat -z <base>` (tracked changes; binary rows count the path
|
|
11
|
+
* but no lines; NUL records carry RAW paths, so a non-ASCII or newline-bearing path reaches the
|
|
12
|
+
* sensitive matchers intact) plus untracked files (`git ls-files --others --exclude-standard -z`,
|
|
13
|
+
* newline-counted — # ponytail: untracked line counts are a newline scan, numstat-grade binary
|
|
14
|
+
* detection is unnecessary here; switch to `--numstat --no-index` if a miscount flips a lane).
|
|
15
15
|
*
|
|
16
16
|
* `sensitive` is true when ANY changed path matches the exported SENSITIVE list (0943 R2c);
|
|
17
17
|
* the workflow's pre-decide guard maps sensitive (or >400 changed lines) to the safety lane
|
|
@@ -85,7 +85,7 @@ function globToRegex(glob: string): RegExp {
|
|
|
85
85
|
.replaceAll('*', '[^/]*')
|
|
86
86
|
.replaceAll('\u0000', '(?:.*/)?')
|
|
87
87
|
.replaceAll('\u0001', '.*');
|
|
88
|
-
return new RegExp(`^${escaped}
|
|
88
|
+
return new RegExp(`^${escaped}$`, 's');
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
const SENSITIVE_MATCHERS: Array<{ label: string; test: (path: string) => boolean }> = [
|
|
@@ -125,26 +125,10 @@ function countNewlines(path: string, cwd?: string): number {
|
|
|
125
125
|
return lines;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*/
|
|
133
|
-
export function expandDiffPath(raw: string): string[] {
|
|
134
|
-
const arrow = raw.indexOf(' => ');
|
|
135
|
-
if (arrow === -1) return [raw];
|
|
136
|
-
const open = raw.indexOf('{');
|
|
137
|
-
const close = raw.lastIndexOf('}');
|
|
138
|
-
if (open !== -1 && close > open && open < arrow && arrow < close) {
|
|
139
|
-
const inner = raw.slice(open + 1, close);
|
|
140
|
-
const innerArrow = inner.indexOf(' => ');
|
|
141
|
-
if (innerArrow !== -1) {
|
|
142
|
-
const head = raw.slice(0, open);
|
|
143
|
-
const tail = raw.slice(close + 1);
|
|
144
|
-
return [head + inner.slice(0, innerArrow) + tail, head + inner.slice(innerArrow + 4) + tail];
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return [raw.slice(0, arrow), raw.slice(arrow + 4)];
|
|
128
|
+
function addCounts(add: string, del: string): [number, number] | null {
|
|
129
|
+
for (const count of [add, del]) if (count !== '-' && !/^\d+$/.test(count)) return null;
|
|
130
|
+
const [a, d] = [add === '-' ? 0 : Number(add), del === '-' ? 0 : Number(del)];
|
|
131
|
+
return Number.isSafeInteger(a) && Number.isSafeInteger(d) ? [a, d] : null;
|
|
148
132
|
}
|
|
149
133
|
|
|
150
134
|
/**
|
|
@@ -190,18 +174,34 @@ export function runDiffstat(
|
|
|
190
174
|
}
|
|
191
175
|
if (!/^[0-9a-f]{7,40}$/i.test(base)) return failSafe('run base .spur/run/<wbs>-base.sha missing or malformed');
|
|
192
176
|
|
|
193
|
-
const numstat = git(['diff', '--numstat', base]);
|
|
177
|
+
const numstat = git(['diff', '--numstat', '-z', base]);
|
|
194
178
|
if (numstat.status !== 0) return failSafe(`git diff --numstat failed (status=${numstat.status})`);
|
|
179
|
+
if (numstat.stdout.length > 0 && !numstat.stdout.endsWith('\u0000'))
|
|
180
|
+
return failSafe('git diff --numstat -z output is not NUL-terminated (malformed framing)');
|
|
195
181
|
const paths = new Set<string>();
|
|
196
182
|
let insertions = 0;
|
|
197
183
|
let deletions = 0;
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (
|
|
204
|
-
|
|
184
|
+
const records = numstat.stdout.split('\u0000').slice(0, -1); // drop the terminating NUL tail
|
|
185
|
+
for (let i = 0; i < records.length; i++) {
|
|
186
|
+
const header = records[i] ?? '';
|
|
187
|
+
const first = header.indexOf('\t'); // first two tabs only
|
|
188
|
+
const second = header.indexOf('\t', first + 1); // a raw path may itself hold more tabs
|
|
189
|
+
if (first < 1 || second < first + 2) return failSafe('git diff --numstat -z record is missing counts or path');
|
|
190
|
+
const counts = addCounts(header.slice(0, first), header.slice(first + 1, second));
|
|
191
|
+
if (counts === null) return failSafe('git diff --numstat -z record has a malformed count');
|
|
192
|
+
insertions += counts[0];
|
|
193
|
+
deletions += counts[1]; // once per count header, never once per rename half
|
|
194
|
+
const path = header.slice(second + 1);
|
|
195
|
+
if (path !== '') {
|
|
196
|
+
paths.add(path);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
// An empty path field is Git's rename/copy form: the next two records are old and new.
|
|
200
|
+
const oldPath = records[++i];
|
|
201
|
+
const newPath = records[++i];
|
|
202
|
+
if (!oldPath || !newPath) return failSafe('git diff --numstat -z rename record has incomplete paths');
|
|
203
|
+
paths.add(oldPath);
|
|
204
|
+
paths.add(newPath);
|
|
205
205
|
}
|
|
206
206
|
const others = git(['ls-files', '--others', '--exclude-standard', '-z']);
|
|
207
207
|
if (others.status !== 0) return failSafe(`git ls-files failed (status=${others.status})`);
|
|
@@ -144,14 +144,21 @@ an explicit allowlist entry.
|
|
|
144
144
|
env dumps. Token estimates for Bash/Grep/Glob use response size **after a 4 KiB cap** and secret
|
|
145
145
|
scrub; omit `tokens` when unknown (never `0`).
|
|
146
146
|
|
|
147
|
+
**Session lifecycle:** `.spur/context/.session.json` is a private pointer to the in-flight session.
|
|
148
|
+
It records the creating host's owner identity (`{host, sessionId}` — Claude's hook `session_id`, Pi's
|
|
149
|
+
session-manager id) and only that owner's `SessionEnd` / `session_shutdown` may write the rollup and
|
|
150
|
+
remove the pointer. A nested run reuses the parent's ledger for tool recording but cannot finalize
|
|
151
|
+
or delete it; an ownerless (legacy) pointer is never finalized and expires under the existing
|
|
152
|
+
idle-start window instead.
|
|
153
|
+
|
|
147
154
|
```jsonl
|
|
148
|
-
{"ts":"2026-07-09T14:23:01Z","session":"session-2026-07-09-
|
|
149
|
-
{"ts":"2026-07-09T14:23:15Z","session":"session-2026-07-09-
|
|
150
|
-
{"ts":"2026-07-09T14:24:00Z","session":"session-2026-07-09-
|
|
151
|
-
{"ts":"2026-07-12T15:00:00Z","session":"session-2026-07-12-
|
|
152
|
-
{"ts":"2026-07-12T15:00:01Z","session":"session-2026-07-12-
|
|
153
|
-
{"ts":"2026-07-12T15:00:02Z","session":"session-2026-07-12-
|
|
154
|
-
{"ts":"2026-07-09T14:30:00Z","session":"session-2026-07-09-
|
|
155
|
+
{"ts":"2026-07-09T14:23:01Z","session":"session-2026-07-09-142318-a1b2c3d4","type":"session_start"}
|
|
156
|
+
{"ts":"2026-07-09T14:23:15Z","session":"session-2026-07-09-142318-a1b2c3d4","type":"read","file":"src/dao.ts","tokens":648}
|
|
157
|
+
{"ts":"2026-07-09T14:24:00Z","session":"session-2026-07-09-142318-a1b2c3d4","type":"write","file":"src/dao.ts","tokens":222,"action":"edit"}
|
|
158
|
+
{"ts":"2026-07-12T15:00:00Z","session":"session-2026-07-12-150007-e5f6a7b8","type":"bash","summary":"ls -la","tokens":12}
|
|
159
|
+
{"ts":"2026-07-12T15:00:01Z","session":"session-2026-07-12-150007-e5f6a7b8","type":"grep","summary":"/TODO/ src"}
|
|
160
|
+
{"ts":"2026-07-12T15:00:02Z","session":"session-2026-07-12-150007-e5f6a7b8","type":"glob","summary":"**/*.test.ts"}
|
|
161
|
+
{"ts":"2026-07-09T14:30:00Z","session":"session-2026-07-09-142318-a1b2c3d4","type":"session_end","totals":{"reads":5,"writes":19,"tokens":2783}}
|
|
155
162
|
```
|
|
156
163
|
|
|
157
164
|
**Never edit `token-ledger.jsonl` by hand.** It feeds the Board **Observability → Tool Using** tab.
|
|
@@ -104,7 +104,7 @@ was meant to avoid. Let the reviewer reach its own conclusion.
|
|
|
104
104
|
|
|
105
105
|
- **`sp:spur-dev`** owns task selection and lifecycle. When a batch contains independent tasks, the spine consults this skill for the fan-out pattern.
|
|
106
106
|
- **`sp:super-planner`** is the orchestrator that executes the fan-out. Its parallel mode (documented in its agent definition) applies the patterns from this skill.
|
|
107
|
-
- **`/sp:dev-parallel`** is the
|
|
107
|
+
- **`/sp:dev-runall --mode parallel|auto`** is the task-batch entry point; its `batch-plan.mjs order` schedule applies this skill's dependency and file-overlap rows deterministically.
|
|
108
108
|
|
|
109
109
|
## When to use
|
|
110
110
|
|
|
@@ -135,7 +135,7 @@ Do **not** use this skill for:
|
|
|
135
135
|
|
|
136
136
|
- **`sp:spur-dev`** — the orchestration spine that consults this skill for fan-out decisions.
|
|
137
137
|
- **`sp:super-planner`** — the batch orchestrator that executes fan-out patterns.
|
|
138
|
-
- **`/sp:dev-parallel`** — the slash command entry point for parallel
|
|
138
|
+
- **`/sp:dev-runall --mode parallel|auto`** — the slash command entry point for parallel task batches.
|
|
139
139
|
|
|
140
140
|
## Platform Notes
|
|
141
141
|
|
|
@@ -70,7 +70,7 @@ own axis.
|
|
|
70
70
|
Surface choice and model choice stay separate axes, but the invocation surface is where the
|
|
71
71
|
cheap-model hint is applied. On hosts whose native subagent invocation accepts a per-call model
|
|
72
72
|
override (Claude Code: the Agent tool's `model` parameter), dispatch read-only fan-out workers —
|
|
73
|
-
|
|
73
|
+
N-way investigation and competency-lens review's read-only lenses — with the host's
|
|
74
74
|
cheapest capable model. The rule is owned by
|
|
75
75
|
[fan-out-patterns.md § Cheap-model hint for read-only fan-out](fan-out-patterns.md#cheap-model-hint-for-read-only-fan-out)
|
|
76
76
|
and carries two prohibitions and one exemption: invocation-side only, **never** a subagent
|
|
@@ -134,13 +134,13 @@ blocker** — never a permission-probing subsystem:
|
|
|
134
134
|
[Keep a durable progress ledger](../SKILL.md#keep-a-durable-progress-ledger)).
|
|
135
135
|
|
|
136
136
|
Read-only investigation fan-out avoids the write-permission class by construction:
|
|
137
|
-
|
|
137
|
+
N-way investigation and competency-lens review's read-only lenses dispatch
|
|
138
138
|
**read-only worker shapes** — search/read tools only, with no write surface declared.
|
|
139
139
|
|
|
140
140
|
## Cheap-model hint for read-only fan-out
|
|
141
141
|
|
|
142
142
|
On hosts whose native subagent invocation accepts a per-call model override (Claude Code: the Agent
|
|
143
|
-
tool's `model` parameter), dispatch read-only fan-out workers —
|
|
143
|
+
tool's `model` parameter), dispatch read-only fan-out workers — N-way investigation
|
|
144
144
|
and competency-lens review's read-only lenses — with the host's cheapest capable model. The rule is
|
|
145
145
|
invocation-side, with two prohibitions and one exemption:
|
|
146
146
|
|
|
@@ -112,9 +112,13 @@ unrelated uncommitted changes make safe editing or committing ambiguous.
|
|
|
112
112
|
**Current-HEAD invariant.** Treat the PR's pushed `headRefOid` as the review identity. After every
|
|
113
113
|
preflight, push, commit, and request, record the returned HEAD and require `wait`, `collect`, and
|
|
114
114
|
the report to match that exact HEAD. A result for an older commit is stale; a result absent for the
|
|
115
|
-
current HEAD is pending, not clean.
|
|
116
|
-
|
|
117
|
-
|
|
115
|
+
current HEAD is pending, not clean. `wait` re-asserts this at two points, not one: at the start of
|
|
116
|
+
every poll, and again immediately before it emits FOUND/CLEAN/TIMEOUT — a head that moved while the
|
|
117
|
+
review was being fetched, or between polls, fails the wait (exit 2) instead of accepting an old-head
|
|
118
|
+
result. The pinned identity is the PR number AND the expected head, so a different PR appearing on
|
|
119
|
+
the branch is also a failure, never a silent retarget. Reject uncorrelated issue/conversation
|
|
120
|
+
comments rather than using them to manufacture a current-HEAD result. In `fix` mode, discard the old
|
|
121
|
+
result after the fix commit and judge only the forced re-review for the new pushed HEAD.
|
|
118
122
|
|
|
119
123
|
**Reviewer authority.** Codex is an independent reviewer, not an authority. For every finding that
|
|
120
124
|
may lead to a code change: inspect the referenced code, verify reachability and intended behavior,
|
|
@@ -101,9 +101,11 @@ issues with its evidence. Notes stay report-only.
|
|
|
101
101
|
refresh it with `superskill install sp` before reporting numbers; report `n/a` until then.
|
|
102
102
|
The transcript resolves from `--transcript`, else `CLAUDE_CODE_SESSION_ID`, else `PI_SESSION_FILE`
|
|
103
103
|
(the pi host sets it and no Claude session id); with none of them the measurement reports
|
|
104
|
-
`available:false` with a reason and the table renders `n/a` instead of guessing. A
|
|
105
|
-
|
|
106
|
-
segment
|
|
104
|
+
`available:false` with a reason and the table renders `n/a` instead of guessing. A pi
|
|
105
|
+
`<skill name="…">` wrapper row is the OPERATOR'S own `/skill` invocation, not an injected body:
|
|
106
|
+
it opens a segment rendered `/<name> <args>` (or `/<name>` when no arguments follow the closing
|
|
107
|
+
tag), and the wrapper body never appears in the prompt excerpt. Only the operator's prompts
|
|
108
|
+
segment the session.
|
|
107
109
|
2. **Inventory outcomes.** List requested outcomes and classify each as completed, partial, blocked,
|
|
108
110
|
or not attempted. Collapse repeated attempts into one outcome.
|
|
109
111
|
3. **Classify issues.** For every material issue, distinguish resolved, open, or attempted. Record
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spur-cli-decision
|
|
3
|
-
description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers. Backed by @gobing-ai/ts-ai-decision 0.5.
|
|
3
|
+
description: "spur-cli noun reference: operate `spur decision` as the read/serve surface over the decision catalog - list registered decisions, show one served contract (parameters, criteria vocabulary, effective maker), run a decision to a served outcome (never writes a workflow resultFile), and status the catalog layers. Backed by @gobing-ai/ts-ai-decision 0.5.22 hub; offline by default via the built-in `typesafe` maker. Introduced by task 1093."
|
|
4
4
|
see_also:
|
|
5
5
|
- spur-cli
|
|
6
6
|
---
|
|
@@ -79,6 +79,13 @@ exist there). The final `catalog-default` maker is the hub built-in `typesafe`
|
|
|
79
79
|
without a configured backend still produce deterministic closed-vocabulary outcomes, which is why
|
|
80
80
|
`run` is usable in tests and scripts with no model access.
|
|
81
81
|
|
|
82
|
+
**Available makers:** the three upstream built-ins (`typesafe`, `fm-local`, `laya-local`) plus
|
|
83
|
+
Spur's hosted `clef` (Cloudflare Workers AI via `@gobing-ai/ts-decision-clef`). `clef` registers
|
|
84
|
+
only when both `CLOUDFLARE_ACCOUNT_ID` and `CLOUDFLARE_AUTH_TOKEN` are set in the environment;
|
|
85
|
+
without them it is absent from `registeredMakers`, so naming it in config or `--maker` is a config
|
|
86
|
+
error, never a silent fallback. Its model defaults to `clef-flash` (a catalog `model` selects
|
|
87
|
+
`clef`).
|
|
88
|
+
|
|
82
89
|
## Examples
|
|
83
90
|
|
|
84
91
|
```bash
|
|
@@ -93,6 +100,6 @@ spur decision status --json | jq '.loadErrors' # audit catalog health
|
|
|
93
100
|
## References
|
|
94
101
|
|
|
95
102
|
- Design: `docs/design/decision-catalog.md` (§2 catalog authoring, §3.4 CLI surface)
|
|
96
|
-
- Hub: `@gobing-ai/ts-ai-decision` 0.5.
|
|
103
|
+
- Hub: `@gobing-ai/ts-ai-decision` 0.5.22 (`DecisionService`, catalog schema, maker registry)
|
|
97
104
|
- App service: `packages/app/src/decision/decision-service.ts`
|
|
98
105
|
- Shipped catalogs: `config/decisions/*.yaml`
|
|
@@ -22,7 +22,7 @@ shapes live in `apps/cli/src/commands/projects.ts`.
|
|
|
22
22
|
| `clean` | Purge missing project folders and terminate lingering processes (alias: `refresh`) | `--no-terminate-processes` `--json` |
|
|
23
23
|
| `list` | List entries with live running status | `--json` `--fleet` |
|
|
24
24
|
| `start <target>` | Start or reuse a detached project server | `--port <n>` `--json` |
|
|
25
|
-
| `stop <target>` |
|
|
25
|
+
| `stop <target>` | Ownership-verified stop of the listener and clear its recorded port | `--json` |
|
|
26
26
|
|
|
27
27
|
Every verb also advertises `--json-envelope`; use the facade's machine-output contract. Success is
|
|
28
28
|
exit `0`; validation, registry, spawn, health, or lookup failure is exit `1`.
|
|
@@ -36,8 +36,8 @@ exit `0`; validation, registry, spawn, health, or lookup failure is exit `1`.
|
|
|
36
36
|
- `add` requires an existing path, resolves a relative path from the current working directory, and
|
|
37
37
|
defaults the display name to its basename. It upserts; it does not start a server. The current
|
|
38
38
|
source does not enforce a `.spur/` marker or directory type.
|
|
39
|
-
- `list` automatically heals tilde paths, verifies project directories exist on disk (purging missing entries and terminating lingering processes), and heals stale entries to `port: 0` before reporting `running`.
|
|
40
|
-
- `clean` (alias `refresh`) explicitly purges non-existent project directories from `projects.json`, probes live ports for removed entries, and
|
|
39
|
+
- `list` automatically heals tilde paths, verifies project directories exist on disk (purging missing entries and terminating only ownership-verified lingering processes), and heals stale entries to `port: 0` before reporting `running`.
|
|
40
|
+
- `clean` (alias `refresh`) explicitly purges non-existent project directories from `projects.json`, probes live ports for removed entries, and terminates orphaned listeners only after ownership verification (SIGTERM with bounded wait and SIGKILL escalation, each signal gated on `service:spur` identity plus exact project path and a stable PID; foreign or unverified listeners are never signaled). Supports `--no-terminate-processes` to skip process kills.
|
|
41
41
|
- `list --fleet` (0835/0858) additionally resolves each project's `agent.fleet` section from that
|
|
42
42
|
project's `.spur/config.yaml` under the existing verb (no new noun). Per project it prints one line
|
|
43
43
|
per member: instance id (the spec id / mailbox identity), `role`, resolved `executor`,
|
|
@@ -76,8 +76,10 @@ port is returned idempotently; otherwise the service allocates a port (3000–39
|
|
|
76
76
|
set), spawns `spur serve --host 127.0.0.1 --no-open` detached in the project root, waits for the port,
|
|
77
77
|
then persists it.
|
|
78
78
|
|
|
79
|
-
`stop`
|
|
80
|
-
|
|
79
|
+
`stop` signals only a listener that proves `service:spur` identity plus the exact registered project
|
|
80
|
+
path with a stable rediscovered PID; it refuses foreign or unverified listeners with exit 1 and
|
|
81
|
+
preserves the port, treats an absent listener as idempotent success, and excludes the CLI and its
|
|
82
|
+
parent. It is not a persistent supervisor contract.
|
|
81
83
|
`remove` only removes the registry entry; stop a running project first when process cleanup matters.
|
|
82
84
|
|
|
83
85
|
Raw JSON success payloads are verb-specific (`project`, `projects`, `removed`, `stopped`, or start
|
|
@@ -110,6 +110,8 @@ Read this `SKILL.md` plus your mode's files below before the first dispatch; eve
|
|
|
110
110
|
- --worktree: `references/execution-batch.md`, `references/execution-worktree-setup.md`
|
|
111
111
|
- --mode parallel: `references/execution-batch.md`, `references/execution-parallel-isolation.md`
|
|
112
112
|
|
|
113
|
+
`--mode auto` reads as sequential-inline until § 2.4a resolves it.
|
|
114
|
+
|
|
113
115
|
Byte budgets for these sums live in `plugins/sp/tests/bootstrap-budget.test.ts`
|
|
114
116
|
(`BOOTSTRAP_BUDGETS_BYTES`, task 1128); the test fails the build when a mode's bootstrap grows.
|
|
115
117
|
|
|
@@ -88,6 +88,33 @@ DD-06 permissive start: treat only the core tier as must-ship initially; promote
|
|
|
88
88
|
prove important in a later iteration. (When tiered gating lands in `spur feature check`, these tags
|
|
89
89
|
become the gate input — the CLI stays the validator; this guide stays the convention.)
|
|
90
90
|
|
|
91
|
+
### Home-node tier (structural, exempt from the orphan sweep)
|
|
92
|
+
|
|
93
|
+
A **home node** carries one structural or placement scenario that states *where the work lives*
|
|
94
|
+
(e.g. "work on the kk workflow-run ledger has a home node"). No task can cover that statement — it
|
|
95
|
+
describes planning placement, not behaviour — so tag it `@home-node` to remove it from the
|
|
96
|
+
feature-side DD-09 orphan sweep (`L4.uncovered-feature-scenario`):
|
|
97
|
+
|
|
98
|
+
```gherkin
|
|
99
|
+
@home-node
|
|
100
|
+
Scenario: R1 — Work on the kk workflow run ledger has a home node
|
|
101
|
+
Given a change that targets the kk workflow run ledger workflow
|
|
102
|
+
When the change is planned as a feature
|
|
103
|
+
Then it is feature G7 or a child feature of G7
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Rules:
|
|
107
|
+
|
|
108
|
+
- **Scenario-level tag only.** A `Feature:`-level `@home-node` exempts nothing; the tag is read per
|
|
109
|
+
scenario.
|
|
110
|
+
- **Exempts the orphan sweep only.** Scenario satisfaction (0340), verdict-row matching, and the
|
|
111
|
+
known-issues ratchet are unchanged — a tagged scenario a task actually covers is classified
|
|
112
|
+
exactly as before.
|
|
113
|
+
- **Never a hiding place.** Use it only for a scenario no task can own. A deliberately uncoverable
|
|
114
|
+
*capability* scenario belongs to `@core`/`@edge` and must stay in the sweep: tagging it
|
|
115
|
+
`@home-node` hides a real gap. Wording is never the signal.
|
|
116
|
+
- A feature with **no linked task** is still flagged as `L4.orphan-scenarios`, tagged or not.
|
|
117
|
+
|
|
91
118
|
## Scenario-title stability
|
|
92
119
|
|
|
93
120
|
The scenario title is the **identity key** for traceability. When a task references a
|
|
@@ -23,7 +23,7 @@ The `Skill()` commands back onto six skills: `sp:spur-dev` (planning + execution
|
|
|
23
23
|
`sp:code-verification` (SECUA review + traceability), `sp:parallel-execution` (fan-out / parallel batch),
|
|
24
24
|
and `sp:brainstorm` (structured ideation). The `runall` operation (#13) is `sp:spur-dev`'s batch entry — it delegates the driver loop to the
|
|
25
25
|
`sp:super-planner` agent (the batch orchestrator) per [execution-batch.md](execution-batch.md).
|
|
26
|
-
`dev-parallel` (
|
|
26
|
+
Parallel task batches are `dev-runall --mode parallel|auto` (`dev-parallel` retired 2026-10-10). `dev-brainstorm` carries the two artifact exits — `--task` (one task) and `--feature` (validated
|
|
27
27
|
feature with BDD AC; the front-half entry that hands off to `dev-plan`). The 4 `inline` commands
|
|
28
28
|
cover git tooling and operational utilities that have no natural skill home — creating a skill for
|
|
29
29
|
each would be scope creep for one-liner procedures.
|
|
@@ -86,8 +86,7 @@ each would be scope creep for one-liner procedures.
|
|
|
86
86
|
| 11b | job-resume | `dev-job-resume` | `Skill()` | `sp:spur-dev` (`job-resume`) | `--file <path>` |
|
|
87
87
|
| 12 | brainstorm | `dev-brainstorm` | `Skill()` | `sp:brainstorm` (`dev-brainstorm`) | `<topic> [--depth <basic\|detailed\|comprehensive>] [--options <n>] [--agent <inline\|auto\|name>] [--skip-discovery] [--task [<feature-id>]] [--feature [<parent-id>]] [--next]` |
|
|
88
88
|
| 12a | find-way | `dev-find-way` | `Skill()` | `sp:wayfinder` (worktree-isolated) | `<idea> \| <feature-id> [<wbs>] [--agent <inline\|auto\|name>] [--auto] [--worktree [<name>]] [--wrap]` |
|
|
89
|
-
| 13 | runall | `dev-runall` | `Skill()` → agent | `sp:spur-dev` (`runall`) → `sp:super-planner` | `--tasks <selector> [--feature <id>] [--mode <sequential\|parallel>] [--keep-going] [--auto] [--agent <inline\|auto\|name>] [--json] [--wrap] [--next] [--continue] [--worktree [<name>]] [--no-summary] [--defer-gate]` |
|
|
90
|
-
| 13a | parallel | `dev-parallel` | `Skill()` | `sp:parallel-execution` | `--tasks <selector> [--feature <id>] [--mode <fan-out\|review-panel\|investigation>] [--agent <inline\|auto\|name>] [--json] [--defer-gate]` |
|
|
89
|
+
| 13 | runall | `dev-runall` | `Skill()` → agent | `sp:spur-dev` (`runall`) → `sp:super-planner` | `--tasks <selector> [--feature <id>] [--mode <sequential\|parallel\|auto>] [--concurrency <n>] [--keep-going] [--auto] [--agent <inline\|auto\|name>] [--json] [--wrap] [--next] [--continue] [--worktree [<name>]] [--no-summary] [--defer-gate]` |
|
|
91
90
|
| 14 | wrap | `dev-wrap` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `<wbs> [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
|
|
92
91
|
| 15 | wrapall | `dev-wrapall` | `Skill()` | `spur workflow run` (wrapup-pipeline) | `[--since <iso>] [--feature <id>] [--status <s>] [--agent <inline\|auto\|name>] [--auto] [--merge] [--dry-run]` |
|
|
93
92
|
| 16 | idea | `dev-idea` | `Skill()` | inline driver (`idea-pipeline`) or async workflow | `"<idea>" \| --from-file <path> [--skip-design] [--agent <inline\|auto\|name>] [--auto]` |
|
|
@@ -178,6 +178,11 @@ the wrap's refusal of non-done tasks remains the hard invariant.
|
|
|
178
178
|
|
|
179
179
|
**Close-out commit (1129 R2/R5).** In sequential mode the wrap's writes (learnings, metrics,
|
|
180
180
|
doc-sync) land in the invoking tree and are committed as ONE close-out commit after the wrap exits.
|
|
181
|
+
**Under `--worktree` they land in the EXECUTION tree instead** and ride the branch as its own commit
|
|
182
|
+
on `$BRANCH`: Step 6 runs before WT-4, so a close-out commit on the base ref would advance it and
|
|
183
|
+
make the batch's own FF-merge impossible (the fresh base tip would no longer be an ancestor of the
|
|
184
|
+
batch tip — the step that makes the close-out the report's own contradiction). The close-out commit
|
|
185
|
+
is never a point on the base ref.
|
|
181
186
|
Stage them through the guard — never a free-form `git add` — so a concurrent writer's file cannot
|
|
182
187
|
ride into the close-out commit (incident `36f274590`). `$RUN_ID` is the id Step 3 fixed before
|
|
183
188
|
`commit-guard start` (execution-batch.md § Step 3); an unset id makes the guard exit 1 — fail closed:
|
|
@@ -204,7 +204,18 @@ For each dependency edge to a task **outside** the frozen set, resolve its curre
|
|
|
204
204
|
|
|
205
205
|
### 2.4 Topological sort
|
|
206
206
|
|
|
207
|
-
|
|
207
|
+
Do not hand-run the sort — compute it. Write the remaining in-set, non-blocked tasks to a temp file
|
|
208
|
+
as a JSON array of `{wbs, dependencies, files?}` (`dependencies` from `spur task show <wbs> --json`
|
|
209
|
+
frontmatter; `files` = repo paths the task's Design/Plan names, omit when it names none) and run:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
node "$(superskill script path sp batch-plan.mjs)" order --tasks <tasks.json> [--concurrency <n>]
|
|
213
|
+
# → {"order":[…],"waves":[[…],…],"cycle":null|[…],"overlaps":[…],"mode":"sequential|parallel","reason":"…"}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`order` is the execution plan; a non-null `cycle` is the abort below. `waves`, `overlaps`, `mode`
|
|
217
|
+
and `reason` feed `--mode auto` (§ 2.4a) and the batch report. The script implements Kahn's
|
|
218
|
+
algorithm (ADR-130 glue over `scheduleBatch` in `packages/app/src/workflow/plan-projection.ts`):
|
|
208
219
|
|
|
209
220
|
1. Seed the queue with zero-indegree nodes, **sorted WBS-ascending** (deterministic tie-break).
|
|
210
221
|
2. Repeatedly dequeue the lowest-WBS zero-indegree node, emit it, decrement its successors'
|
|
@@ -214,7 +225,35 @@ Topological-sort the remaining in-set, non-blocked tasks using Kahn's algorithm:
|
|
|
214
225
|
**Cycle handling (R2.3):** a cycle aborts the **entire batch** before any task runs. Reconstruct a
|
|
215
226
|
representative cycle path via DFS over the remaining unsorted nodes and report it (e.g.
|
|
216
227
|
`0040 → 0042 → 0040`). Do not run any task in a cyclic batch — running a prefix would partially
|
|
217
|
-
execute work whose ordering is undefined.
|
|
228
|
+
execute work whose ordering is undefined. The script reports it as `cycle` (e.g.
|
|
229
|
+
`["0040","0042","0040"]`) with an empty `order`.
|
|
230
|
+
|
|
231
|
+
**File overlap.** Two tasks that declare the same file get a serialization edge oriented by their
|
|
232
|
+
dependency order (`overlaps[]` records each), so overlap never creates a cycle and never puts
|
|
233
|
+
overlapping tasks in the same wave (`sp:parallel-execution` row 3). It only matters under parallel
|
|
234
|
+
execution; sequential order stays a valid topological order either way.
|
|
235
|
+
|
|
236
|
+
### 2.4a `--mode auto` resolution
|
|
237
|
+
|
|
238
|
+
`--mode auto` is decided **once, here, by the active orchestrator** (the host session, or
|
|
239
|
+
`sp:super-planner` when an explicit executor is set), after freeze, Step 2.3 blocking and
|
|
240
|
+
the § 2.4 schedule, and before any task runs:
|
|
241
|
+
|
|
242
|
+
| Condition (first match wins) | Resolved mode |
|
|
243
|
+
| --- | --- |
|
|
244
|
+
| `--worktree` present | `sequential` (parallel rejects `--worktree`) |
|
|
245
|
+
| `--agent inline` explicitly passed | `sequential` (inline is the host-session driver) |
|
|
246
|
+
| script `mode` is `sequential` (fewer than 2 tasks, `--concurrency 1`, or every wave holds one task) | `sequential` |
|
|
247
|
+
| script `mode` is `parallel` | `parallel` |
|
|
248
|
+
|
|
249
|
+
- **Sequential resolution** continues the Step 3 loop with the frozen `order` (host-inline, or
|
|
250
|
+
subprocess per task under an explicit executor).
|
|
251
|
+
- **Parallel resolution** hands off to the explicit/parallel path as
|
|
252
|
+
`runall --tasks <order as comma WBS list> --mode parallel` plus the operator's other flags. The
|
|
253
|
+
explicit list carries the frozen membership, so the feature preflight (Step 1) is not re-run.
|
|
254
|
+
- `--defer-gate` survives only a parallel resolution; a sequential one drops it.
|
|
255
|
+
- The batch report records `mode: auto → <resolved>` with the script's `reason`, the widest wave,
|
|
256
|
+
and any `overlaps`.
|
|
218
257
|
|
|
219
258
|
### 2.5 Result
|
|
220
259
|
|
|
@@ -321,8 +360,8 @@ emit batch report (per-task outcome + preflight skips + recovery hints + autoRep
|
|
|
321
360
|
```
|
|
322
361
|
|
|
323
362
|
Parallel mode keeps the same lifecycle but swaps the inner loop for the per-task-worktree fan-out
|
|
324
|
-
specified in [§ Parallel isolation](#parallel-isolation---mode-parallel):
|
|
325
|
-
non-overlapping
|
|
363
|
+
specified in [§ Parallel isolation](#parallel-isolation---mode-parallel): take the zero-edge,
|
|
364
|
+
non-overlapping frontier from the § 2.4 schedule's waves; **preflight each** selected task; run each ready task's `task-pipeline.yaml`
|
|
326
365
|
invocation in its own create-mode worktree; integrate by rebase + `--ff-only` as tasks finish;
|
|
327
366
|
recovery stays **sequential** (one WBS). If any decision-framework check fails, serialize and
|
|
328
367
|
record the reason.
|
|
@@ -45,7 +45,10 @@ emit batch report (per-task outcomes + preflight skips + recovery hints + batch
|
|
|
45
45
|
- **Eligibility (R2).** A task becomes eligible only when all of its in-set dependencies are
|
|
46
46
|
**integrated** onto the base ref — pipeline-terminal is not enough, because its branch must
|
|
47
47
|
rebase over theirs. Omitting `--mode` stays sequential; this loop is entered only via
|
|
48
|
-
`--mode parallel` on `/sp:dev-runall
|
|
48
|
+
`--mode parallel` on `/sp:dev-runall`, directly or as a `--mode auto` resolution
|
|
49
|
+
([execution-batch.md § 2.4a](execution-batch.md#24a---mode-auto-resolution)).
|
|
50
|
+
- **Fan-out set.** Run order and eligibility come from the § 2.4 `batch-plan.mjs order` schedule;
|
|
51
|
+
its file-overlap edges are in-set dependencies here, so overlapping tasks never run at once.
|
|
49
52
|
- **Workdir.** `spur workflow run` records the launch workdir (0784 R1), so launch with `cwd` = the
|
|
50
53
|
task worktree: resume and `.spur/run/` artifact paths resolve there. Read the verdict from
|
|
51
54
|
`$WT/.spur/run/<wbs>-verdict.json` before integration; WT-4a persists it into the invoking tree.
|
|
@@ -148,7 +148,7 @@ halt-on-first-failure. Never silently retried; the failure is still reported.
|
|
|
148
148
|
|
|
149
149
|
### `--defer-gate` — opt-in parallel-batch gate policy (task 1111 / H15)
|
|
150
150
|
|
|
151
|
-
**Applies to:** `/sp-dev-runall --mode parallel`,
|
|
151
|
+
**Applies to:** `/sp-dev-runall --mode parallel`, and `--mode auto` when it resolves to parallel.
|
|
152
152
|
**Default:** off — every task pipeline runs its own FULL project gate inside its worktree.
|
|
153
153
|
|
|
154
154
|
With `--defer-gate`, each task's `test` / `test-recheck` hop runs the **light tier** (changed-scope
|
|
@@ -167,9 +167,10 @@ Two properties are load-bearing and are asserted structurally:
|
|
|
167
167
|
project gate; the per-task token is `DEFERRED`, and the `test → triage` /
|
|
168
168
|
`test-recheck → triage` guards accept it only while `deferQualityGate = "true"`.
|
|
169
169
|
|
|
170
|
-
`--defer-gate`
|
|
171
|
-
worktrees to the one place the integrated tree exists.
|
|
172
|
-
|
|
170
|
+
`--defer-gate` with `--mode sequential` (or omitted `--mode`) is rejected — the flag exists to move
|
|
171
|
+
one full gate from N worktrees to the one place the integrated tree exists. Under `--mode auto` it
|
|
172
|
+
applies only if the batch resolves to parallel; a sequential resolution drops it with a report note.
|
|
173
|
+
Sequential and inline batches never set the var. ADR-124 carries the dated clarification.
|
|
173
174
|
|
|
174
175
|
**Anchor:** `#flag-defer-gate`.
|
|
175
176
|
|
|
@@ -177,11 +178,11 @@ var. ADR-124 carries the dated clarification.
|
|
|
177
178
|
|
|
178
179
|
**Anchor:** `#flag-concurrency`.
|
|
179
180
|
|
|
180
|
-
`dev-runall` under `--mode parallel` (task 0931): at most `<n>` task pipelines run at once
|
|
181
|
+
`dev-runall` under `--mode parallel` (task 0931), or `--mode auto` resolved to parallel: at most `<n>` task pipelines run at once
|
|
181
182
|
(default 2, `n ≥ 1`). A dependent task starts only after every in-set dependency has been
|
|
182
183
|
**integrated** onto the base ref — see
|
|
183
184
|
[execution-batch.md § Parallel isolation](execution-batch.md#parallel-isolation---mode-parallel).
|
|
184
|
-
Ignored in sequential mode. Each worker is one more concurrent quality gate; raise it only when
|
|
185
|
+
Ignored in sequential mode; `--concurrency 1` pins `--mode auto` to sequential. Each worker is one more concurrent quality gate; raise it only when
|
|
185
186
|
the host has the CPU for it.
|
|
186
187
|
|
|
187
188
|
### `--continue` — resume an interrupted batch from checkpoint
|
|
@@ -271,12 +272,12 @@ is the contract; divergence between `--dry-run` and the real run is a bug.
|
|
|
271
272
|
|
|
272
273
|
**Anchor:** `#flag-tasks`.
|
|
273
274
|
|
|
274
|
-
Batch operation (`dev-
|
|
275
|
+
Batch operation (`dev-refineall`, `dev-review`, `dev-runall`, `dev-verifyall`). An
|
|
275
276
|
explicit selector — WBS list, status pseudo-list (`todo`, `wip`), `feature:<id>`, or `ready` —
|
|
276
277
|
resolving to the set the batch runs over. On `dev-review` the selector is restricted to the
|
|
277
278
|
review-safe forms: comma WBS list and `feature:<id>` — status pseudo-lists and `ready` are
|
|
278
|
-
rejected (they select work to do, not work to review). Required on `dev-
|
|
279
|
-
|
|
279
|
+
rejected (they select work to do, not work to review). Required on `dev-runall` and
|
|
280
|
+
`dev-verifyall`, where `--feature` is an optional restrictor. On `dev-refineall` it is instead
|
|
280
281
|
one of a required pair — supply exactly one of `--feature` or `--tasks`.
|
|
281
282
|
|
|
282
283
|
### `--mode <kind>` — select an execution mode
|
|
@@ -284,8 +285,9 @@ one of a required pair — supply exactly one of `--feature` or `--tasks`.
|
|
|
284
285
|
**Anchor:** `#flag-mode`.
|
|
285
286
|
|
|
286
287
|
Select an execution mode: `full|implement` on `dev-run` (full pipeline vs implement-only),
|
|
287
|
-
`sequential|parallel` on `dev-runall` (serial
|
|
288
|
-
|
|
288
|
+
`sequential|parallel|auto` on `dev-runall` (serial, fanned-out independent subset, or chosen from the
|
|
289
|
+
frozen batch's dependency waves — see [execution-batch.md § 2.4](execution-batch.md#24-topological-sort)),
|
|
290
|
+
the reconstruction depth
|
|
289
291
|
`briefing|structure|architecture|design|full` on `dev-reverse`, and `daily|ad-hoc` on
|
|
290
292
|
`dev-find-issue` (the history-anatomy report mode). Mode selection is explicit and orthogonal
|
|
291
293
|
to `--next`.
|
|
@@ -86,7 +86,9 @@ fallback) — labels are display addresses only, never an execution key.
|
|
|
86
86
|
1. Resolve the command inputs, `--auto`, and any explicit `--vars` — **without reading the selected
|
|
87
87
|
YAML yet**. An explicit non-inline executor selection chooses the subprocess workflow path.
|
|
88
88
|
2. Allocate a collision-resistant inline run id (`uuidgen`, with a timestamp/pid fallback), create
|
|
89
|
-
`.spur/run/`
|
|
89
|
+
`.spur/run/` and the run's scratch subdirectory `.spur/run/<run-id>/` for attempt staging (action
|
|
90
|
+
batches, captured stage output, temporary status/answer files) plus `.spur/memory/runs/` for
|
|
91
|
+
retained records, and use the two-file run record (task 0927) — append lines to
|
|
90
92
|
`.spur/memory/runs/<run-id>.md` and read machine state from `.spur/memory/runs/<run-id>.state.json`.
|
|
91
93
|
The run id lives in those two files and the persisted run row — never stage it in an ad-hoc
|
|
92
94
|
`*.env` file: the `no-env-files` gate rule flags any `.env` name, so run-scoped staging files
|
|
@@ -606,7 +608,7 @@ prompt the host cannot see is invisible until join. Record one run-log line per
|
|
|
606
608
|
stage <id> permission precheck: ok | <missing capability>
|
|
607
609
|
```
|
|
608
610
|
|
|
609
|
-
Read-only investigation fan-out (
|
|
611
|
+
Read-only investigation fan-out (N-way investigation) dispatches read-only
|
|
610
612
|
worker shapes by construction — see the [pre-dispatch permission
|
|
611
613
|
rule](../../parallel-execution/references/fan-out-patterns.md).
|
|
612
614
|
|
|
@@ -761,21 +763,14 @@ grading its own work defeats the stage. A continuation stage also dispatches fre
|
|
|
761
763
|
same-task subagent exists (the earlier stage ran host-inline or below the dispatch floor), when a
|
|
762
764
|
host-owned gate sat between the stages, or when the platform cannot address completed subagents.
|
|
763
765
|
|
|
764
|
-
**Implement and test-fix workers never run the full gate (task
|
|
765
|
-
takes a host-wide lock (`SPUR_GATE_LOCK_DIR`, default `~/.config/spur/run/full-gate.lock`):
|
|
766
|
-
concurrent full-gate runs serialize, and a manual `spur-check` (wrapped via
|
|
767
|
-
`scripts/commands/gate-lock.ts`) holds the same lock. A dispatched **implement** or `test-fix` child
|
|
768
|
-
that re-ran the full gate would queue behind every other gate on the host and burn its dispatch
|
|
769
|
-
timeout waiting instead of working. Workers use the light tier as their iteration check (task 1142 R3) in exact order:
|
|
766
|
+
**Implement and test-fix workers never run the full gate (task 1142 R3).** Workers use the light tier as their iteration check (task 1142 R3) in exact order:
|
|
770
767
|
1. the **changed-path matrix** (`code-implementation/SKILL.md` § Changed-path targeted checks) over the paths they touched;
|
|
771
768
|
2. the resolved `quality-gate` script in `light` mode (source-repo probe, else the installed twin) (biome, per-workspace typecheck, rule presets, related tests).
|
|
772
769
|
Neither step takes the full-gate lock. The pipeline's `test` and `test-recheck` hops remain the only full gate. Carry
|
|
773
770
|
`--gate-log <path>` through to the child **verbatim**: never paraphrase it into "re-run the named
|
|
774
|
-
gate command". That paraphrase is not cosmetic — it
|
|
775
|
-
|
|
776
|
-
stage
|
|
777
|
-
holder, so a queued worker's effective budget is dispatch timeout minus observed lock queue wait,
|
|
778
|
-
not the timeout alone.
|
|
771
|
+
gate command". That paraphrase is not cosmetic — it sent a worker into a full gate run instead of
|
|
772
|
+
targeted iteration checks. The pipeline's next `test` (recheck)
|
|
773
|
+
stage delivers the deciding verdict.
|
|
779
774
|
|
|
780
775
|
**Null or timed-out dispatch (task 1134 R9).** The dispatch bound stays the existing YAML
|
|
781
776
|
`timeoutMs` (`implementTimeoutMs` / `stepTimeoutMs`), passed to the host dispatch as today — R9 adds
|