@gobing-ai/spur 0.3.65 → 0.3.66
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/workflows/history-anatomy.yaml +5 -4
- package/package.json +1 -1
- package/plugins/sp/commands/dev-review-session.md +11 -6
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +4 -0
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +4 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +1 -1
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +3 -2
- package/plugins/sp/skills/dogfood-testing/SKILL.md +11 -11
- package/plugins/sp/skills/session-review/SKILL.md +39 -6
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +7 -1
- package/plugins/sp/skills/spur-dev/SKILL.md +5 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +2 -2
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +71 -15
- package/spur.js +333 -121
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
# spurBin — PATH-independent spur invocation (overridden by CLI at run start)
|
|
45
45
|
# __runId — run-scoped id for explicit artifact paths (allocated in start)
|
|
46
46
|
# stepTimeoutMs — agent.run budget for enrich/validate
|
|
47
|
-
# correctionCount — bounded correction loop counter file path bits (name resolved in correct)
|
|
48
47
|
|
|
49
48
|
"$schema": "@gobing-ai/spur/schemas/state-machine-workflow.schema.json"
|
|
50
49
|
kind: state-machine
|
|
@@ -73,7 +72,6 @@ vars:
|
|
|
73
72
|
spurBin: "spur"
|
|
74
73
|
__runId: ""
|
|
75
74
|
stepTimeoutMs: "1800000"
|
|
76
|
-
correctionCount: "0"
|
|
77
75
|
workflowFile: "config/workflows/history-anatomy.yaml"
|
|
78
76
|
contractVersion: "1"
|
|
79
77
|
reportDir: "docs/report"
|
|
@@ -231,8 +229,11 @@ states:
|
|
|
231
229
|
- id: correct
|
|
232
230
|
description: >
|
|
233
231
|
A two-pass correction budget (0690). onEnter increments the counter; retry edges guard on
|
|
234
|
-
the run-scoped correction-count file
|
|
235
|
-
|
|
232
|
+
the run-scoped correction-count file
|
|
233
|
+
`.spur/run/$__runId-correction-count` < 2 (the live bound — the
|
|
234
|
+
former `vars.correctionCount` declared-but-unread var was removed,
|
|
235
|
+
0702 R3), and a failure after the second repair takes the -> failed
|
|
236
|
+
edge. The
|
|
236
237
|
counter is shared by the structure-gate and validate FAIL edges, so a structure repair can
|
|
237
238
|
still be followed by one validation-driven repair. The
|
|
238
239
|
model half re-authors the candidate in place from the gate findings and validation notes —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gobing-ai/spur",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.66",
|
|
4
4
|
"description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spur",
|
|
@@ -1,22 +1,25 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Review the active coding-agent session immediately: summarize outcomes, distinguish resolved and open issues with evidence, and propose bounded improvements. Triggers: review this session, session wrap-up, immediate retrospective, what happened, what was resolved"
|
|
2
|
+
description: "Review the active coding-agent session immediately: summarize outcomes, distinguish resolved and open issues with evidence, and propose bounded improvements. With --triage: apply pure-doc / one-to-two-line fixes inline, then file remaining findings as one new task. Triggers: review this session, session wrap-up, immediate retrospective, what happened, what was resolved, triage findings"
|
|
3
3
|
role: reviewer
|
|
4
|
-
argument-hint: "[<focus>]"
|
|
4
|
+
argument-hint: "[<focus>] [--triage]"
|
|
5
5
|
allowed-tools: ["Bash", "Read", "Grep", "Glob", "Skill"]
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Dev Review Session
|
|
9
9
|
|
|
10
|
-
Wraps the **sp:session-review** skill for a lightweight
|
|
11
|
-
|
|
12
|
-
session context is preserved
|
|
13
|
-
applies
|
|
10
|
+
Wraps the **sp:session-review** skill for a lightweight review of the active host session. By
|
|
11
|
+
default it is report-only: current conversation plus read-only repository evidence, run inline so
|
|
12
|
+
the session context is preserved — no workflow launch, history import, task creation, or
|
|
13
|
+
remediation. With `--triage`, it first triages the findings, then applies direct fixes (pure
|
|
14
|
+
documentation work and one-to-two-line fixes) inline and files everything remaining as exactly one
|
|
15
|
+
new task for further fixing.
|
|
14
16
|
|
|
15
17
|
## Argument Flags
|
|
16
18
|
|
|
17
19
|
| Flag | Description | Default |
|
|
18
20
|
| --- | --- | --- |
|
|
19
21
|
| `[<focus>]` | Optional question or operation to emphasize without excluding material session outcomes. | full active session |
|
|
22
|
+
| `--triage` | After the report: bucket findings → apply pure-doc / 1–2-line fixes inline → create one task for the remainder. | off (report-only) |
|
|
20
23
|
|
|
21
24
|
For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag-glossary.md).
|
|
22
25
|
|
|
@@ -25,6 +28,8 @@ For shared semantics, see the [flag glossary](../skills/spur-dev/references/flag
|
|
|
25
28
|
```
|
|
26
29
|
/sp:dev-review-session
|
|
27
30
|
/sp:dev-review-session "why the verification loop repeated"
|
|
31
|
+
/sp:dev-review-session --triage
|
|
32
|
+
/sp:dev-review-session "F95 findings" --triage
|
|
28
33
|
```
|
|
29
34
|
|
|
30
35
|
## Implementation
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.66",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -18,7 +18,7 @@ function countLedgerDataRows(markdown) {
|
|
|
18
18
|
const nextHeading = after.search(/^### /m);
|
|
19
19
|
const body = nextHeading === -1 ? after : after.slice(0, nextHeading);
|
|
20
20
|
const rows = body.split(`
|
|
21
|
-
`).filter((line) => line.trim().startsWith("|")).filter((line) => !/^\|[\s:|-]+\|?\s*$/.test(line.trim())).filter((line) => !/^\|\s
|
|
21
|
+
`).filter((line) => line.trim().startsWith("|")).filter((line) => !/^\|[\s:|-]+\|?\s*$/.test(line.trim())).filter((line) => !/^\|\s*`?drift:/.test(line.trim()));
|
|
22
22
|
return Math.max(rows.length - 1, 0);
|
|
23
23
|
}
|
|
24
24
|
function declaredExecutedSteps(markdown) {
|
|
@@ -37,8 +37,9 @@ function countLedgerDataRows(markdown: string): number | null {
|
|
|
37
37
|
.filter((line) => line.trim().startsWith('|'))
|
|
38
38
|
.filter((line) => !/^\|[\s:|-]+\|?\s*$/.test(line.trim()))
|
|
39
39
|
// drift:external rows are documentary (task 0296) — included in the table but
|
|
40
|
-
// subtracted from the executed-step count, per the @1.2 cardinality contract
|
|
41
|
-
|
|
40
|
+
// subtracted from the executed-step count, per the @1.2 cardinality contract;
|
|
41
|
+
// the prescribed code-span form (`drift:external`) matches too (task 0701 R5b).
|
|
42
|
+
.filter((line) => !/^\|\s*`?drift:/.test(line.trim()));
|
|
42
43
|
// Minus the header row; what remains are data rows.
|
|
43
44
|
return Math.max(rows.length - 1, 0);
|
|
44
45
|
}
|
|
@@ -408,22 +408,22 @@ no fix applications and a clean tree at finalize needs no drift row.
|
|
|
408
408
|
|
|
409
409
|
### What drift is — and is not
|
|
410
410
|
|
|
411
|
-
**Drift** = a tracked file changes that neither the driver nor
|
|
412
|
-
**Explained** set = files named in ledger `Fix Applied` cells (driver fixes) plus
|
|
413
|
-
|
|
414
|
-
|
|
411
|
+
**Drift** = a tracked file changes that neither the driver nor a testee ledger row names.
|
|
412
|
+
**Explained** set = files named in ledger `Fix Applied` cells (driver fixes) plus testee writes the
|
|
413
|
+
driver recorded in the ledger. Anything else new or modified in `git status --porcelain` since
|
|
414
|
+
baseline is drift.
|
|
415
415
|
|
|
416
416
|
### On detecting drift
|
|
417
417
|
|
|
418
418
|
- Append a **warning ledger row** tagged `drift:external` in the Step column: paths in `Fix Applied`,
|
|
419
|
-
`Outcome: drift`, `Basis: <fingerprint diff>`. Do NOT mark the step PASSED/FIXED
|
|
420
|
-
drift; the row records the drift, it does not change a step's outcome.
|
|
419
|
+
`Outcome: drift`, `Basis: <fingerprint diff>`. Do NOT mark the step PASSED/FIXED because of
|
|
420
|
+
drift; the row records the drift, it does not change a step's outcome. Write the Step cell as
|
|
421
|
+
the code span `` `drift:external` `` — the validator drops it from the data-row count (0701 R5b).
|
|
421
422
|
- Emit a **mandatory report finding** under §6 Findings — `P2 — workspace drift detected during
|
|
422
|
-
run; attribution to external writer` — naming the drifted paths and the snapshot delta. The
|
|
423
|
-
|
|
424
|
-
- The driver **never** claims drifted files as its own or the testee's work
|
|
425
|
-
`Fix Applied` cites only
|
|
426
|
-
separately.
|
|
423
|
+
run; attribution to external writer` — naming the drifted paths and the snapshot delta. The
|
|
424
|
+
report states the run's evidence is degraded, not voided.
|
|
425
|
+
- The driver **never** claims drifted files as its own or the testee's work: a fix row's
|
|
426
|
+
`Fix Applied` cites only what the driver changed; drift rows cite drifted paths separately.
|
|
427
427
|
|
|
428
428
|
### Worktree advisory (mutating dogfoods)
|
|
429
429
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: session-review
|
|
3
|
-
description: "Review the active coding-agent session
|
|
3
|
+
description: "Review the active coding-agent session: separate resolved from open issues with evidence, propose bounded improvements. With --triage, apply pure-doc / 1–2-line fixes inline and file the rest as one task. Triggers: review this session, wrap-up, triage findings."
|
|
4
4
|
license: Apache-2.0
|
|
5
|
-
version: 1.
|
|
5
|
+
version: 1.1.0
|
|
6
6
|
metadata:
|
|
7
7
|
author: spur
|
|
8
8
|
platforms: "claude-code,codex,openclaw,opencode,antigravity,pi"
|
|
@@ -31,6 +31,7 @@ cross-agent windows, recurrence, trends, or quantitative performance forensics.
|
|
|
31
31
|
| Argument | Description | Default |
|
|
32
32
|
| --- | --- | --- |
|
|
33
33
|
| `[focus]` | Question or operation to emphasize. It changes ordering, not evidence collection. | full active session |
|
|
34
|
+
| `--triage` | Opt into bounded remediation after the report: apply direct fixes (pure docs / one-to-two-line fixes) inline, then file all remaining actionable findings as exactly one new task via the CLI-gated corpus surface. | off (report-only) |
|
|
34
35
|
|
|
35
36
|
## Evidence boundary
|
|
36
37
|
|
|
@@ -46,6 +47,28 @@ cross-agent windows, recurrence, trends, or quantitative performance forensics.
|
|
|
46
47
|
- State `not available` when compaction or missing output removed evidence. Never reconstruct it from
|
|
47
48
|
memory or claim a verification that did not run.
|
|
48
49
|
|
|
50
|
+
## Triage mode (`--triage`)
|
|
51
|
+
|
|
52
|
+
Report-only stays the default. With `--triage`, run the same evidence pass, then remediate in
|
|
53
|
+
three buckets — never skip triage and start fixing from the raw findings list.
|
|
54
|
+
|
|
55
|
+
1. **Triage every finding into exactly one bucket:**
|
|
56
|
+
- **Direct fix** — pure documentation work, or a one-to-two-line fix with obvious, local,
|
|
57
|
+
low-risk scope. Read the root cause first; a "one-liner" that needs design or touches a
|
|
58
|
+
shared write path is not direct.
|
|
59
|
+
- **Task** — real, actionable, and not already owned by an existing task. Deferred
|
|
60
|
+
requirements recorded inside their own task files are pointers, not duplicates.
|
|
61
|
+
- **Note** — pre-existing, environmental, or ownerless observations; report only.
|
|
62
|
+
2. **Apply direct fixes inline** — smallest surgical diff, project style, and re-verify each
|
|
63
|
+
with the targeted check (lint / test / the exact command that exhibited the issue).
|
|
64
|
+
3. **Create exactly one task** for the Task bucket through the CLI-gated corpus surface
|
|
65
|
+
(`spur task create`, then `spur task update <wbs> --section <s> --from-file` per section).
|
|
66
|
+
One task, not one per finding: each finding keeps its evidence, a suggested fix direction,
|
|
67
|
+
and an AC where verifiable. Exclude what direct fixes already resolved — say so in the task
|
|
68
|
+
Background instead.
|
|
69
|
+
4. **Report** — add a Triage section: applied fixes (path + one-line what + verification) and
|
|
70
|
+
the created task WBS. The Resolved/Open tables keep their evidence rules unchanged.
|
|
71
|
+
|
|
49
72
|
## Protocol
|
|
50
73
|
|
|
51
74
|
1. **Resolve scope.** Review the active session from the operator's initiating request through the
|
|
@@ -86,6 +109,14 @@ session. Do not list ordinary implementation steps as issues.
|
|
|
86
109
|
For each supported proposal, name its owner surface, expected impact, verification method, and
|
|
87
110
|
reversibility. Proposals remain report-only: apply no change and create no task.
|
|
88
111
|
|
|
112
|
+
### Triage (only when `--triage` was passed)
|
|
113
|
+
|
|
114
|
+
| Applied fix / created task | Bucket | What + verification |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
|
|
117
|
+
One row per applied fix and one per created task (with its WBS). Omit the section entirely when
|
|
118
|
+
`--triage` was not passed.
|
|
119
|
+
|
|
89
120
|
### Next actions
|
|
90
121
|
|
|
91
122
|
List only actions needed to finish partial scope, confirm a hypothesis, or preserve a demonstrated
|
|
@@ -94,10 +125,12 @@ improvement. Use `None` when the session is complete and no follow-up is justifi
|
|
|
94
125
|
## Boundaries
|
|
95
126
|
|
|
96
127
|
- Stay in the active host session. Do not delegate; a fresh context loses the evidence being reviewed.
|
|
97
|
-
- Do not launch a workflow, import history,
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
128
|
+
- Do not launch a workflow, import history, append indexed-context memory, perform baseline
|
|
129
|
+
comparison or recurrence classification, or emit a twelve-section forensic report; those belong
|
|
130
|
+
to imported-history analysis.
|
|
131
|
+
- Report-only by default: do not create or update corpus items or edit files. The single exception
|
|
132
|
+
is `--triage` mode, which permits exactly two mutation classes — direct fixes from the triage
|
|
133
|
+
bucket, and the one triage task. Anything beyond that stays a proposal.
|
|
101
134
|
- Do not turn a single low-impact observation into a new policy. Report it as a candidate until it
|
|
102
135
|
recurs or demonstrates a high-impact contract violation.
|
|
103
136
|
|
|
@@ -54,7 +54,9 @@ frontmatter scalar.
|
|
|
54
54
|
cancelled`. Two transitions run a target-aware `check` guard (§7.5): `wip→testing` →
|
|
55
55
|
`spur task check <wbs> --as testing`; `testing→done` → `spur task check <wbs> --as done`
|
|
56
56
|
(F92 R3 — each evaluates the transition target, so `testing→done` checks the `done` row).
|
|
57
|
-
A failing gate blocks the transition.
|
|
57
|
+
A failing gate blocks the transition. The `wip→testing` guard additionally requires a Solution
|
|
58
|
+
section citing concrete `file:line` evidence — a missing/unsubstantiated Solution is rejected with
|
|
59
|
+
`[invalid-solution]`.
|
|
58
60
|
- **`--no-lifecycle`**: suppress lifecycle workflow *run record* creation (use inside pipeline runs
|
|
59
61
|
to avoid orphaned nested lifecycle runs). **It is not a guard bypass** — the `wip→testing` and
|
|
60
62
|
`testing→done` `check` gates above still run; the CLI evaluates them inline when the FSM guard
|
|
@@ -230,6 +232,10 @@ only the exact corpus path, with no basename-WBS fallback. Returns exit `1` if n
|
|
|
230
232
|
|
|
231
233
|
## `verdict <wbs>`
|
|
232
234
|
|
|
235
|
+
There is **no `verify` verb**. The verify leg is three steps: the agent writes its structured
|
|
236
|
+
evidence write-up to `.spur/run/<wbs>-verify-answer.txt`, then `spur task verdict <wbs>` derives
|
|
237
|
+
the verdict artifact, then `spur task record <wbs>` lands it into the task.
|
|
238
|
+
|
|
233
239
|
Derive a PASS / PARTIAL / FAIL / UNKNOWN verdict from a verify-step answer text file (the agent's
|
|
234
240
|
structured evidence write-up). Replaces the pipeline's verify→record transition's previous grep/shell
|
|
235
241
|
ladder (0108; ADR-022). On a readable answer, emits `.spur/run/<wbs>-verdict.json` (mkdir-p the
|
|
@@ -234,6 +234,11 @@ or `args="refine <wbs>"` for task refinement, or `args="refineall --feature <id>
|
|
|
234
234
|
batch refine under a feature (add `--depth ready` for implement-ready freeze). Use `spur agent run`
|
|
235
235
|
for isolated LLM invocations within pipeline steps.
|
|
236
236
|
|
|
237
|
+
**Argument parsing.** Split `$ARGUMENTS` into target + flags before dispatching. Unknown flags are
|
|
238
|
+
not silently dropped: note them in the plan line, or stop (rule imported from `next-router`,
|
|
239
|
+
task 0701 R3 — e.g. `--worktree` on `dev-refine` is undeclared, so it must be surfaced, never
|
|
240
|
+
discarded).
|
|
241
|
+
|
|
237
242
|
### Codex / OpenClaw / OpenCode / Antigravity
|
|
238
243
|
|
|
239
244
|
Run `spur` CLI via the Bash tool; parse `--json` output. Invoke this skill directly for
|
|
@@ -236,7 +236,7 @@ must not be changed without updating the backing skill.
|
|
|
236
236
|
- **Purpose:** Batch-refine a set of tasks (or all refine-eligible tasks under a feature) — resolve a set, topo-sort by dependencies, run per-task `refine`, emit a summary report. Planning-half counterpart of `verifyall` / `runall` for the just-in-time spec-completion gate. With `--depth ready`, batch **implement-ready** freeze before multi-agent implement or runall.
|
|
237
237
|
- **Inputs:**
|
|
238
238
|
- `--feature <id>` **or** `--tasks <selector>` (required — at least one). `--feature` is sugar for `--tasks feature:<id>` (shared selector grammar: explicit WBS list, `feature:<id>`, `ready`, status pseudo-list — [execution-batch.md](execution-batch.md) Step 1). If both are present, `--tasks` wins (one-line note in the report).
|
|
239
|
-
- Shared refine flags (passed through to each per-task refine): `--focus <mode>`, `--description <text>`, `--depth <standard|ready>`, `--agent <inline|auto|name>`, `--auto
|
|
239
|
+
- Shared refine flags (passed through to each per-task refine): `--focus <mode>`, `--description <text>`, `--depth <standard|ready>`, `--agent <inline|auto|name>`, `--auto`.
|
|
240
240
|
- Batch-only flags: `--keep-going` (continue independents after a failure; default halt), `--status <s>` (filter resolved membership; default **`backlog,todo`** — planning-side fill candidates), `--json` (machine-readable batch report).
|
|
241
241
|
- **Backing:** `sp:spur-dev` skill, `refineall` operation (orchestrates; per-task body is the single-task `refine` operation — never a second refine implementation).
|
|
242
242
|
- **Behavior:**
|
|
@@ -248,7 +248,7 @@ must not be changed without updating the backing skill.
|
|
|
248
248
|
6. Emit a batch report (markdown or `--json`) that records `depth` once at the header.
|
|
249
249
|
- **Per-task outcome vocabulary:** `refined` (synthesis wrote sections) | `SKIP` (already meets the active depth bar under `--auto`) | `failed` | `skipped` (dep failed under `--keep-going`) | `not-attempted` (halted) | `blocked` (unmet out-of-set dep).
|
|
250
250
|
- **Batch verdict:** `clean` (all attempted tasks `refined` or `SKIP`) | `halted` (a failure stopped the batch) | `aborted` (cycle / unknown selector / empty set after filter).
|
|
251
|
-
- **`--next`
|
|
251
|
+
- **`--next` is not accepted** (dropped by feature H8, 2026-07-31 — see `plugins/sp/commands/dev-refineall.md` for the removal record). Chain execution explicitly: refineall, then `/sp:dev-runall --feature <id>`.
|
|
252
252
|
- **`--auto` recommendation:** Batch refine without `--auto` requires per-task interactive Q&A and does not scale. Default operator path: `/sp:dev-refineall --feature <id> --auto`. For implement handoffs: `/sp:dev-refineall --feature <id> --auto --depth ready`.
|
|
253
253
|
- **Delegation:** `Skill(skill="sp:spur-dev", args="refineall $ARGUMENTS")` → per task `Skill(skill="sp:spur-dev", args="refine <wbs> $SHARED_FLAGS")` (shared flags include `--depth` when set).
|
|
254
254
|
|
|
@@ -61,6 +61,7 @@ function normalizeArgs(raw: Args): Args {
|
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
**Normalization rules (performed by the command layer before the skill sees $ARGUMENTS, or by the batch resolver):**
|
|
64
|
+
|
|
64
65
|
- If `--feature FOO` is present and `--tasks` is absent, treat the effective selector as `feature:FOO`.
|
|
65
66
|
- If both are present, `--tasks` wins (with a one-line note in the batch report).
|
|
66
67
|
|
|
@@ -101,7 +102,7 @@ bun run apps/cli/src/index.ts feature check <id> --strict --json
|
|
|
101
102
|
kickoff** — the driver never re-queries `spur task list` to recompute membership mid-batch (R2.1).
|
|
102
103
|
|
|
103
104
|
| Selector form | Regex / match | Resolution |
|
|
104
|
-
|
|
105
|
+
| --- | --- | --- |
|
|
105
106
|
| Explicit WBS list | `^[0-9, ]+$` | Split on comma; validate each token is a 4-digit WBS; collect the explicit set. (R1.1) |
|
|
106
107
|
| `feature:<id>` (via `--tasks` or `--feature <id>`) | literal `feature:` prefix or `--feature` flag | `spur task list --feature <id> --json`; collect `wbs` from each row. The `--feature` flag is sugar that becomes `--tasks feature:<id>` at the command layer. (R1.3) |
|
|
107
108
|
| `ready` | literal `ready` | Resolve the union of `spur task list --status todo --json` + `spur task list --status backlog --json`, drop tasks with open children (R1.5, umbrella-parent exclusion below), then keep only tasks whose every `dependencies[]` entry resolves to `status == done` (via `spur task show <dep> --json | jq '{wbs, status, dependencies, feature_id}'` — R5 metadata-only). Report each excluded task with its unmet dependency. (R1.4) |
|
|
@@ -185,7 +186,7 @@ node "$(superskill script path sp batch-preflight.mjs)" \
|
|
|
185
186
|
```
|
|
186
187
|
|
|
187
188
|
| Result | Batch action |
|
|
188
|
-
|
|
189
|
+
| -------- | ---------------- |
|
|
189
190
|
| `action: run` | Launch `task-pipeline.yaml` for this WBS (happy path **unchanged**) |
|
|
190
191
|
| `action: skip` code **A2** | Do not launch; report `preflight-skip` + unmet deps (mirrors TABLE A2) |
|
|
191
192
|
| `action: skip` code **A7** | Do not launch; report blocked (handover is operator-side) |
|
|
@@ -253,7 +254,7 @@ Only two flags cross the orchestrator→pipeline boundary; both are merged into
|
|
|
253
254
|
`--vars` JSON:
|
|
254
255
|
|
|
255
256
|
| Flag | Effect on per-task `--vars` |
|
|
256
|
-
|
|
257
|
+
| --- | --- |
|
|
257
258
|
| `--auto` | sets `"profile":"auto"` (skips the HITL approve gate). Omitting it forwards nothing, so the pipeline uses its default profile (standard — HITL pause surfaces to the operator). (R4.2) |
|
|
258
259
|
| `--agent <value>` | omit/`inline` in interactive sequential mode selects the host driver and is not forwarded. `auto` or a name sets **both** `"agent":"<value>"` and `"implementAgent":"<value>"` so every workflow `agent.run` step — including implement — spawns that executor. Headless omit/inline falls through the executor precedence chain. To pin ONLY implement, pass `--vars '{"implementAgent":"..."}'` separately; that explicit var selects the subprocess path. (R4.3, tasks 0483/0503) |
|
|
259
260
|
|
|
@@ -283,7 +284,7 @@ node "$(superskill script path sp batch-preflight.mjs)" --wbs <wbs> --status <st
|
|
|
283
284
|
```
|
|
284
285
|
|
|
285
286
|
| Rule | Detail |
|
|
286
|
-
|
|
287
|
+
| ------ | -------- |
|
|
287
288
|
| Budget | **≤ 1** recovery consult per WBS per batch — never loop until done |
|
|
288
289
|
| Default | Print the exact child command in the batch report |
|
|
289
290
|
| `--auto` batch | May dispatch the child **once** when cardinality is 1 and the hop is a single lifecycle command |
|
|
@@ -295,7 +296,6 @@ in next-router; this only maps status → primary TABLE A hop for recovery.
|
|
|
295
296
|
|
|
296
297
|
### 3.3c Bounded feature-sync retry suppression (task 0411)
|
|
297
298
|
|
|
298
|
-
|
|
299
299
|
During a batch, the per-task `record` step and the wrap-up `feature-transition` step each invoke
|
|
300
300
|
feature status sync. When a feature is L4-gate-blocked (e.g. not all linked tasks are `done`), the
|
|
301
301
|
identical blocked proposal repeats on every call with no intervening input change — in the H9
|
|
@@ -413,6 +413,14 @@ The per-task outcome vocabulary: `done` | `failed` | `blocked` | `skipped` | `no
|
|
|
413
413
|
The batch verdict: `clean` (all attempted tasks `done`) | `halted` (a failure stopped the batch) |
|
|
414
414
|
`aborted` (cycle or selector error before any run).
|
|
415
415
|
|
|
416
|
+
**Zero-task rule (task 0701 R7b).** A selector that resolves to an **empty set after the status
|
|
417
|
+
filter** is an `aborted` verdict (`aborted (empty set after filter)`), matching dev-operations.md
|
|
418
|
+
§5a. Under `--worktree`, **WT-2 is skipped entirely**: no worktree is cut and no WT-3 marker is
|
|
419
|
+
written for a batch with nothing to run. The early-exit report carries zero per-task rows,
|
|
420
|
+
`Steps: 0 derived, 0 executed`, and the `aborted` verdict; no WT-3b commit step and no WT-4/WT-5
|
|
421
|
+
terminal action runs. A contract test pins this
|
|
422
|
+
(`plugins/sp/tests/dogfood-testing/execution-batch-contract.test.ts`).
|
|
423
|
+
|
|
416
424
|
## Worktree isolation (`--worktree [<name>]`)
|
|
417
425
|
|
|
418
426
|
When a batch command (`dev-runall`, `dev-refineall`, `dev-verifyall`) is invoked with
|
|
@@ -487,7 +495,12 @@ Create one worktree on a new branch cut from the current HEAD's ref (the **base
|
|
|
487
495
|
BASE_REF=$(git rev-parse --abbrev-ref HEAD)
|
|
488
496
|
BASE_SHA=$(git rev-parse HEAD)
|
|
489
497
|
BRANCH="sp/<command>-<selector-slug>-<short-id>" # e.g. sp/runall-h1-a3f2
|
|
490
|
-
git worktree add
|
|
498
|
+
# `git worktree add -b` creates the branch BEFORE the directory, so a failed create leaves a
|
|
499
|
+
# dangling branch and the natural retry dies on "a branch named ... already exists"
|
|
500
|
+
# (task 0701 R2b). Wrap the create: on failure, delete the branch — or derive a fresh
|
|
501
|
+
# short-id per attempt — before surfacing the error.
|
|
502
|
+
git worktree add "../<repo>-<command>-<selector-slug>-<short-id>" -b "$BRANCH" "$BASE_REF" \
|
|
503
|
+
|| { git branch -D "$BRANCH"; false; }
|
|
491
504
|
```
|
|
492
505
|
|
|
493
506
|
Branch and directory names are derived (command + selector slug + short id); the create path never
|
|
@@ -497,10 +510,15 @@ not resolve is an error, not a create).
|
|
|
497
510
|
A fresh worktree has no `node_modules` (gitignored), so the first `bun test` or
|
|
498
511
|
typecheck fails on the first workspace import. Install before any task work:
|
|
499
512
|
|
|
500
|
-
cd "../<worktree-dir>" && bun install --frozen-lockfile
|
|
513
|
+
cd "../<worktree-dir>" && bun install --frozen-lockfile --ignore-scripts
|
|
501
514
|
|
|
502
515
|
`--frozen-lockfile` pins the worktree to `bun.lock` rather than re-resolving,
|
|
503
|
-
so the worktree's dependency tree matches the base ref's.
|
|
516
|
+
so the worktree's dependency tree matches the base ref's. `--ignore-scripts` is required, not
|
|
517
|
+
stylistic (task 0701 R2a): worktrees share the main tree's `.git`, and this repo's `prepare`
|
|
518
|
+
script is `lefthook install` (`package.json`) — a bare install rewrites the operator's
|
|
519
|
+
main-repo hooks from inside the "isolated" tree. Scripts are skipped only at this call site;
|
|
520
|
+
a normal clone keeps `prepare`. The worktree still gets a usable dependency tree — the install
|
|
521
|
+
exists so the first `bun test` resolves workspace imports.
|
|
504
522
|
|
|
505
523
|
#### Reuse mode (`--worktree <name>`)
|
|
506
524
|
|
|
@@ -510,8 +528,8 @@ invoking tree's current HEAD ref (not the worktree's branch) and `BASE_SHA` is
|
|
|
510
528
|
`git merge-base <BASE_REF> <BRANCH>` — so WT-4's FF-merge lands the worktree's accumulated commits
|
|
511
529
|
onto the invoking tree's base ref, exactly as create mode does.
|
|
512
530
|
|
|
513
|
-
`bun install --frozen-lockfile` runs **only when `node_modules` is absent** in
|
|
514
|
-
worktree. A warm reused tree does not re-pay the install; a cold one (hand-made, or a retained tree
|
|
531
|
+
`bun install --frozen-lockfile --ignore-scripts` runs **only when `node_modules` is absent** in
|
|
532
|
+
the resolved worktree (same `--ignore-scripts` rationale as create mode — task 0701 R2a). A warm reused tree does not re-pay the install; a cold one (hand-made, or a retained tree
|
|
515
533
|
whose deps were removed) installs exactly once before the first task. This is the R3 conditional
|
|
516
534
|
install rule (source: task 0481) — create mode always installs because a fresh tree is always cold.
|
|
517
535
|
|
|
@@ -570,7 +588,9 @@ verb) whose path argument you control.
|
|
|
570
588
|
|
|
571
589
|
Worktree identity lives on disk under `.spur/run/`, not only in the orchestrator's memory, so a
|
|
572
590
|
session that dies mid-batch is recoverable. Write the marker at creation and update it at the
|
|
573
|
-
terminal transition (merged / retained).
|
|
591
|
+
terminal transition (merged / retained). The marker is written to the **invoking** tree's
|
|
592
|
+
`.spur/run/` (task 0701 R2c) — the tree where the driver process started, not the worktree's own
|
|
593
|
+
`.spur/run/` — so WT-6's resume scan finds it regardless of where the operator stands. Schema:
|
|
574
594
|
|
|
575
595
|
```json
|
|
576
596
|
{
|
|
@@ -617,6 +637,22 @@ Reuse mode resolves the marker by the resolved worktree's `path` (not by `comman
|
|
|
617
637
|
(AGENTS.md one-writer-per-tree; task 0487 R5). Overridable with `--force` (the operator can tell
|
|
618
638
|
a crashed-session marker from a live-session one; the harness cannot).
|
|
619
639
|
|
|
640
|
+
### WT-3b — Commit the batch's writes on `$BRANCH` (task 0701 R1)
|
|
641
|
+
|
|
642
|
+
Before any terminal action, commit the batch's corpus writes **on `$BRANCH`, inside the
|
|
643
|
+
worktree** — including the generated task files under `docs/tasks*/` and the kanban index:
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
cd "../<worktree-dir>"
|
|
647
|
+
git add <files-the-batch-wrote>
|
|
648
|
+
git commit -m "<type>(<scope>): <command> <selector> batch writes"
|
|
649
|
+
cd - >/dev/null
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
The FF-only git merge carries only commits — uncommitted writes in the worktree would be left
|
|
653
|
+
behind by the merge and then destroyed by create mode's `git worktree remove`. WT-3b exists so
|
|
654
|
+
that can never happen.
|
|
655
|
+
|
|
620
656
|
### WT-4 — Success path (R4)
|
|
621
657
|
|
|
622
658
|
When the batch completes with **no failed task**, fast-forward-merge the worktree branch onto the
|
|
@@ -629,6 +665,11 @@ only what it created*):
|
|
|
629
665
|
# Run these from the main tree (not inside the worktree) - you merge the worktree branch
|
|
630
666
|
# back onto the base ref there:
|
|
631
667
|
git checkout "$BASE_REF"
|
|
668
|
+
# Guard (task 0701 R1): a zero-commit branch makes the FF-only git merge exit 0
|
|
669
|
+
# ("Already up to date") while merging nothing — the two lines below would then delete
|
|
670
|
+
# the worktree holding the only copy of the batch's writes. Refuse instead:
|
|
671
|
+
[ "$(git rev-list --count "$BASE_SHA..$BRANCH")" -gt 0 ] \
|
|
672
|
+
|| { echo "halt: branch carries no commits - nothing to merge" >&2; false; } # -> WT-5
|
|
632
673
|
git merge --ff-only "$BRANCH" # FF-only: never rebase, merge-commit, or resolve conflicts
|
|
633
674
|
# if FF succeeded:
|
|
634
675
|
git worktree remove "../<worktree-dir>"
|
|
@@ -636,6 +677,9 @@ git branch -d "$BRANCH"
|
|
|
636
677
|
# update marker: status = "merged"
|
|
637
678
|
```
|
|
638
679
|
|
|
680
|
+
On the zero-commit guard firing, fall through to **WT-5** with the halt cause *"branch carries no
|
|
681
|
+
commits — nothing to merge"*: the worktree and branch are retained, never removed (task 0701 R1).
|
|
682
|
+
|
|
639
683
|
#### Reuse mode — merge, retain
|
|
640
684
|
|
|
641
685
|
The FF-merge runs identically (same `git checkout "$BASE_REF" && git merge --ff-only "$BRANCH"`),
|
|
@@ -667,12 +711,23 @@ risk losing work); WT-5 retains the worktree and branch whenever FF is impossibl
|
|
|
667
711
|
Reuse mode is **narrower** than the carve-out (it merges but does not delete the branch), so the
|
|
668
712
|
carve-out text needs no widening.
|
|
669
713
|
|
|
714
|
+
**Lifecycle-DB disposition (task 0701 R2d).** The worktree has its own `.spur` lifecycle DB, and
|
|
715
|
+
WT-4/WT-5 remove or retain that tree — the DB state does **not** travel with the merge. The
|
|
716
|
+
**committed task file is authoritative**: after a green merge the branch's task files read
|
|
717
|
+
`done`/`testing` while the invoking tree's DB still reports the pre-batch statuses. Re-sync
|
|
718
|
+
explicitly by replaying the recorded terminal transitions in the invoking tree (`spur task update
|
|
719
|
+
<wbs> <status>` per task, then `spur task record <wbs>`), or treat the batch report's per-task
|
|
720
|
+
table as the source of truth. This is a deliberate choice over auto-migrating DB state: the DB is
|
|
721
|
+
per-tree by design and the committed corpus files are the durable record.
|
|
722
|
+
|
|
670
723
|
### WT-5 — Failure path: retain and report (R5)
|
|
671
724
|
|
|
672
725
|
On any per-task failure, batch halt, HITL pause that ends the run, or non-FF merge from WT-4, the
|
|
673
726
|
worktree directory and branch are left **intact**. No destructive automation on this path under any
|
|
674
727
|
flag combination (`--auto`, `--force`, `--keep-going` — all leave the worktree in place). Update the
|
|
675
|
-
marker: `status = "retained"`.
|
|
728
|
+
marker: `status = "retained"`. The worktree's own `.spur` lifecycle DB is retained with the tree,
|
|
729
|
+
so nothing is lost on this path (see the WT-4 lifecycle-DB disposition for the merged case —
|
|
730
|
+
task 0701 R2d). Emit a retention report in the existing halt-report shape:
|
|
676
731
|
|
|
677
732
|
```
|
|
678
733
|
## Worktree retained — <command> <selector>
|
|
@@ -706,7 +761,8 @@ its WT-3 marker rather than creating a second one. Marker lookup tries two paths
|
|
|
706
761
|
This path covers the common resume shapes: the operator remembers the name used last time, or
|
|
707
762
|
passes the path (tier-1 match).
|
|
708
763
|
2. **Command+selector fallback (bare `--worktree` or absent flag)** — scan
|
|
709
|
-
`.spur/run/worktree-*.json`
|
|
764
|
+
`.spur/run/worktree-*.json` **in the invoking tree** (where WT-3 wrote the marker —
|
|
765
|
+
task 0701 R2c) for a marker whose `command` + `selector` match the current
|
|
710
766
|
invocation and whose `status` is `active` or `retained`. Create-mode runs that did not name their
|
|
711
767
|
tree resolve here.
|
|
712
768
|
3. **Found by either path** → `cd` into the marker's `path`, skip WT-1/WT-2 (no new worktree), and
|
|
@@ -769,7 +825,7 @@ time. Before launching a full `spur-check-new`:
|
|
|
769
825
|
## AC traceability
|
|
770
826
|
|
|
771
827
|
| AC | Where satisfied |
|
|
772
|
-
|
|
828
|
+
| --- | --- |
|
|
773
829
|
| R1.1–R1.4 (selector grammar) | Step 1 — selector resolution table |
|
|
774
830
|
| R1.5 (umbrella-parent exclusion) | Step 1 — "Umbrella-parent exclusion" paragraph |
|
|
775
831
|
| R2.1 (freeze at kickoff) | Step 2.1 |
|
|
@@ -793,6 +849,7 @@ time. Before launching a full `spur-check-new`:
|
|
|
793
849
|
When a batch contains tasks with **zero dependency edges between them** and **no file-overlap conflicts**, the orchestrator can fan them out in parallel instead of running them sequentially. This is an **orchestrator-level optimization** — the per-task pipeline (`task-pipeline.yaml`) is unchanged; only the execution order differs.
|
|
794
850
|
|
|
795
851
|
**Decision framework:** `sp:parallel-execution` owns the full fan-out decision logic and patterns. Consult its [fan-out-patterns.md](../../parallel-execution/references/fan-out-patterns.md) before parallelizing. The orchestrator's responsibility is:
|
|
852
|
+
|
|
796
853
|
1. Identify the independent subset from the topo-sorted batch (tasks with no edges to each other).
|
|
797
854
|
2. Check for file-overlap conflicts (two tasks touching the same `file:line` range must serialize).
|
|
798
855
|
3. Verify token budget supports N-way fan-out.
|
|
@@ -803,7 +860,6 @@ When a batch contains tasks with **zero dependency edges between them** and **no
|
|
|
803
860
|
|
|
804
861
|
**See also:** `sp:parallel-execution` skill, `sp:super-planner` agent (parallel mode), `/sp:dev-parallel` command.
|
|
805
862
|
|
|
806
|
-
|
|
807
863
|
## Subagent execution disciplines
|
|
808
864
|
|
|
809
865
|
Parallel fan-out and any subagent dispatch obey the four disciplines owned by
|