@gobing-ai/spur 0.4.8 → 0.4.9
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/pipeline-budgets.json +2 -2
- package/config/rules/boundary/config-loading-ownership.yaml +1 -0
- package/config/rules/boundary/sp-plugin-standalone.yaml +1 -1
- package/config/rules/boundary/sp-script-placement.yaml +1 -1
- package/config/rules/docs/sourced-api-claims.yaml +45 -7
- package/config/rules/strict/runtime-boundaries.yaml +40 -1
- package/config/rules/structure/protected-files.yaml +1 -1
- package/config/rules/surface/check-cli-surface.yaml +33 -0
- package/config/rules/typescript/no-debugger.yaml +3 -0
- package/config/workflow-candidates.json +2 -2
- package/config/workflows/feature-verification.yaml +6 -11
- package/config/workflows/history-anatomy.yaml +14 -28
- package/config/workflows/idea-pipeline.yaml +6 -19
- package/config/workflows/pr-review.yaml +9 -16
- package/config/workflows/task-pipeline.yaml +16 -23
- package/config/workflows/wrapup-pipeline.yaml +21 -63
- package/package.json +3 -3
- package/plugins/sp/README.md +70 -37
- package/plugins/sp/agents/super-planner.md +5 -5
- package/plugins/sp/agents/super-reviewer.md +2 -2
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/commands/dev-daily.md +1 -1
- package/plugins/sp/commands/dev-pr-review.md +1 -1
- package/plugins/sp/commands/dev-review-session.md +1 -1
- package/plugins/sp/commands/dev-runall.md +4 -4
- package/plugins/sp/commands/dev-verify.md +4 -6
- package/plugins/sp/commands/dev-verifyall.md +4 -5
- package/plugins/sp/hooks/hooks.json +11 -1
- package/plugins/sp/lib/context-post-tool.ts +1 -1
- package/plugins/sp/lib/context-session-start.ts +1 -1
- package/plugins/sp/lib/context-session-stop.ts +1 -1
- package/plugins/sp/lib/destructive-policy.ts +65 -1
- package/plugins/sp/plugin.json +2 -5
- package/plugins/sp/{hooks → scripts/hooks}/agent-lifecycle.ts +1 -1
- package/plugins/sp/scripts/hooks/careful-guard.ts +94 -0
- package/plugins/sp/{hooks → scripts/hooks}/context-post-tool.ts +2 -2
- package/plugins/sp/{hooks → scripts/hooks}/context-session-start.ts +1 -1
- package/plugins/sp/{hooks → scripts/hooks}/context-session-stop.ts +1 -1
- package/plugins/sp/{hooks → scripts/hooks}/fleet-guest-stop.ts +6 -4
- package/plugins/sp/{hooks → scripts/hooks}/task-write-guard.ts +38 -21
- package/plugins/sp/skills/code-implementation/SKILL.md +1 -1
- package/plugins/sp/skills/code-verification/SKILL.md +8 -8
- package/plugins/sp/skills/code-verification/references/secu-review.md +4 -3
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +9 -1
- package/plugins/sp/skills/daily-summary/SKILL.md +4 -5
- package/plugins/sp/skills/dogfood-testing/SKILL.md +9 -9
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +1 -1
- package/plugins/sp/skills/history-anatomy/references/modes.md +2 -2
- package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
- package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
- package/plugins/sp/skills/pr-reviewing/SKILL.md +14 -15
- package/plugins/sp/skills/session-review/SKILL.md +3 -3
- package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
- package/plugins/sp/skills/spur-check/SKILL.md +14 -13
- package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
- package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
- package/plugins/sp/skills/spur-cli/references/builder.md +27 -6
- package/plugins/sp/skills/spur-cli/references/features.md +6 -1
- package/plugins/sp/skills/spur-cli/references/history.md +3 -0
- package/plugins/sp/skills/spur-cli/references/self.md +5 -3
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +3 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +13 -3
- package/plugins/sp/skills/spur-cli/references/workflows.md +36 -1
- package/plugins/sp/skills/spur-dev/SKILL.md +1 -1
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +1 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +12 -12
- package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +10 -11
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +16 -17
- package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +8 -11
- package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +6 -8
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -40
- package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +24 -24
- package/plugins/sp/skills/spur-doctor/SKILL.md +5 -4
- package/spur.js +41901 -30598
- package/config/plugin-scripts.json +0 -116
- package/config/script-placement-baseline.json +0 -33
- package/plugins/sp/hooks/careful-guard.ts +0 -74
- package/plugins/sp/hooks/pi/guard-extension.ts +0 -304
- package/plugins/sp/lib/dogfood-pipeline.ts +0 -265
- package/plugins/sp/lib/dogfood-report.ts +0 -278
- package/plugins/sp/lib/history-anatomy.generated.d.mts +0 -112
- package/plugins/sp/lib/history-anatomy.generated.mjs +0 -691
- package/plugins/sp/lib/idea-handoff.generated.d.mts +0 -17
- package/plugins/sp/lib/idea-handoff.generated.mjs +0 -1446
- package/plugins/sp/lib/inline-run-app.ts +0 -68
- package/plugins/sp/lib/inline-run.generated.d.mts +0 -37
- package/plugins/sp/lib/inline-run.generated.mjs +0 -3103
- package/plugins/sp/lib/plan-projection.generated.d.mts +0 -197
- package/plugins/sp/lib/plan-projection.generated.mjs +0 -982
- package/plugins/sp/lib/quality-gate.generated.d.mts +0 -139
- package/plugins/sp/lib/quality-gate.generated.mjs +0 -30510
- package/plugins/sp/lib/residual-scan.generated.d.mts +0 -93
- package/plugins/sp/lib/residual-scan.generated.mjs +0 -383
- package/plugins/sp/lib/run-summary-core.ts +0 -225
- package/plugins/sp/lib/spur-bin.ts +0 -36
- package/plugins/sp/lib/step-profile.generated.d.mts +0 -71
- package/plugins/sp/lib/step-profile.generated.mjs +0 -174
- package/plugins/sp/lib/transcript.ts +0 -112
- package/plugins/sp/scripts/batch-plan.mjs +0 -1096
- package/plugins/sp/scripts/batch-plan.ts +0 -145
- package/plugins/sp/scripts/batch-preflight.mjs +0 -423
- package/plugins/sp/scripts/batch-preflight.ts +0 -270
- package/plugins/sp/scripts/commit-guard.mjs +0 -226
- package/plugins/sp/scripts/commit-guard.ts +0 -248
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +0 -626
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +0 -855
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +0 -211
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +0 -110
- package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +0 -282
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +0 -98
- package/plugins/sp/scripts/feature-verification-steps.mjs +0 -82
- package/plugins/sp/scripts/feature-verification-steps.ts +0 -164
- package/plugins/sp/scripts/history-anatomy-cache.mjs +0 -931
- package/plugins/sp/scripts/history-anatomy-cache.ts +0 -247
- package/plugins/sp/scripts/idea-handoff.mjs +0 -32
- package/plugins/sp/scripts/idea-handoff.ts +0 -47
- package/plugins/sp/scripts/inline-run-dispatch.mjs +0 -131
- package/plugins/sp/scripts/inline-run-dispatch.ts +0 -115
- package/plugins/sp/scripts/inline-run-setup.mjs +0 -746
- package/plugins/sp/scripts/inline-run-setup.ts +0 -198
- package/plugins/sp/scripts/persist-out-check.mjs +0 -217
- package/plugins/sp/scripts/persist-out-check.ts +0 -249
- package/plugins/sp/scripts/pr-reviewing.mjs +0 -712
- package/plugins/sp/scripts/pr-reviewing.ts +0 -952
- package/plugins/sp/scripts/quality-gate.mjs +0 -30491
- package/plugins/sp/scripts/quality-gate.ts +0 -80
- package/plugins/sp/scripts/residual-scan.mjs +0 -634
- package/plugins/sp/scripts/residual-scan.ts +0 -248
- package/plugins/sp/scripts/run-summary.mjs +0 -758
- package/plugins/sp/scripts/run-summary.ts +0 -107
- package/plugins/sp/scripts/script-root.mjs +0 -129
- package/plugins/sp/scripts/script-root.ts +0 -199
- package/plugins/sp/scripts/session-timeline.mjs +0 -359
- package/plugins/sp/scripts/session-timeline.ts +0 -190
- package/plugins/sp/scripts/task-diffstat.mjs +0 -181
- package/plugins/sp/scripts/task-diffstat.ts +0 -219
- package/plugins/sp/scripts/workflow-step-profile.mjs +0 -338
- package/plugins/sp/scripts/workflow-step-profile.ts +0 -165
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +0 -190
- package/plugins/sp/scripts/wrapup-drift-probe.ts +0 -261
- package/plugins/sp/scripts/wrapup-steps.mjs +0 -627
- package/plugins/sp/scripts/wrapup-steps.ts +0 -891
|
@@ -104,7 +104,7 @@ bun run apps/cli/src/index.ts feature check <id> --strict --json
|
|
|
104
104
|
tasks, and the structured feature findings (the `--json` finding list) reported verbatim. This is
|
|
105
105
|
the same abort vocabulary as cycle / unknown selector (Step 4/Step 5). **Expected pre-run
|
|
106
106
|
states are classified in code, not here:** the non-aborting set lives in
|
|
107
|
-
`NON_ABORTING_PREFLIGHT_CODES` (`
|
|
107
|
+
`NON_ABORTING_PREFLIGHT_CODES` (`spur task preflight --classify-feature`), consumed through
|
|
108
108
|
`classifyFeaturePreflightFindings`, which splits the finding list into `aborting` and
|
|
109
109
|
`nonAborting` and reports `shouldAbort`. `L4.scenario-unverified` is the expected state of any
|
|
110
110
|
not-yet-run feature (its covering tasks have no PASS verdicts yet) and
|
|
@@ -211,12 +211,12 @@ as a JSON array of `{wbs, dependencies, files?}` (`dependencies` from `spur task
|
|
|
211
211
|
frontmatter; `files` = repo paths the task's Design/Plan names, omit when it names none) and run:
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
|
-
|
|
214
|
+
spur task batch-plan order --tasks <tasks.json> [--concurrency <n>]
|
|
215
215
|
# → {"order":[…],"waves":[[…],…],"cycle":null|[…],"overlaps":[…],"mode":"sequential|parallel","reason":"…"}
|
|
216
216
|
```
|
|
217
217
|
|
|
218
218
|
`order` is the execution plan; a non-null `cycle` is the abort below. `waves`, `overlaps`, `mode`
|
|
219
|
-
and `reason` feed `--mode auto` (§ 2.4a) and the batch report. The
|
|
219
|
+
and `reason` feed `--mode auto` (§ 2.4a) and the batch report. The verb implements Kahn's
|
|
220
220
|
algorithm (ADR-130 glue over `scheduleBatch` in `packages/app/src/workflow/plan-projection.ts`):
|
|
221
221
|
|
|
222
222
|
1. Seed the queue with zero-indegree nodes, **sorted WBS-ascending** (deterministic tie-break).
|
|
@@ -265,12 +265,12 @@ The ordered execution plan: a WBS-ascending-topological list of tasks to run, pl
|
|
|
265
265
|
### 2.6 Preflight — TABLE A STOP rows (task 0279 / next-router consumer)
|
|
266
266
|
|
|
267
267
|
**Before** each `spur workflow run` for a WBS still on the plan, re-check readiness with the pure
|
|
268
|
-
helper (preferred) or `sp:next-router` dry-run
|
|
268
|
+
helper (preferred) or `sp:next-router` dry-run. Status, dependencies and their statuses are read
|
|
269
|
+
from the task corpus; `--status` / `--deps` / `--dep-status` override those reads:
|
|
269
270
|
|
|
270
271
|
```bash
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
--deps <comma-deps> --dep-status <wbs:status,...> --json
|
|
272
|
+
spur task preflight <wbs> --json
|
|
273
|
+
spur task preflight <wbs> --status <status> --deps <comma-deps> --dep-status <wbs:status,...> --json
|
|
274
274
|
```
|
|
275
275
|
|
|
276
276
|
| Result | Batch action |
|
|
@@ -289,9 +289,8 @@ out-of-set deps; 2.6 is belt-and-braces for status STOP rows and a uniform repor
|
|
|
289
289
|
### 2.7 Visible batch plan (1105 R3)
|
|
290
290
|
|
|
291
291
|
The batch publishes a generated two-layer plan in the host's native todo list — letters first, digits
|
|
292
|
-
per task only at task start. Rows come from `batch-plan
|
|
293
|
-
`packages/app/src/workflow/plan-projection.ts`), reached like `
|
|
294
|
-
`node "$(superskill script path sp batch-plan.mjs)"`. The visible plan is a projection of the frozen
|
|
292
|
+
per task only at task start. Rows come from `spur task batch-plan` (a thin verb over
|
|
293
|
+
`packages/app/src/workflow/plan-projection.ts`), reached like `spur task preflight`. The visible plan is a projection of the frozen
|
|
295
294
|
plan, never a second plan: labels carry identity, updates happen at the boundaries below only, and no
|
|
296
295
|
per-task letter is ever hand-assigned.
|
|
297
296
|
|
|
@@ -302,7 +301,7 @@ per-task letter is ever hand-assigned.
|
|
|
302
301
|
JSON array of `{wbs, name}` and render the waves:
|
|
303
302
|
|
|
304
303
|
```bash
|
|
305
|
-
|
|
304
|
+
spur task batch-plan waves --tasks <tasks.json>
|
|
306
305
|
```
|
|
307
306
|
|
|
308
307
|
Publish wave 1's rows — one letter (B…Y) per task with no digit children, then `Z Batch report`;
|
|
@@ -311,7 +310,7 @@ per-task letter is ever hand-assigned.
|
|
|
311
310
|
`spur workflow show task-pipeline.yaml --no-logo --format todo --json` payload:
|
|
312
311
|
|
|
313
312
|
```bash
|
|
314
|
-
|
|
313
|
+
spur task batch-plan task-children --letter <task-letter> --plan <plan.json>
|
|
315
314
|
```
|
|
316
315
|
|
|
317
316
|
4. **When a task ends:** mark the task's letter (and its published digits) with the task's terminal
|
|
@@ -324,9 +323,9 @@ per-task letter is ever hand-assigned.
|
|
|
324
323
|
```
|
|
325
324
|
plan = resolve(--tasks) → freeze → order(deps) # may abort (cycle) or pre-block (unmet dep)
|
|
326
325
|
report = []
|
|
327
|
-
publish visible plan §2.7: A/Z rows now; one letter per task after this freeze (batch-plan
|
|
326
|
+
publish visible plan §2.7: A/Z rows now; one letter per task after this freeze (task batch-plan waves)
|
|
328
327
|
RUN_ID = WT-3 marker id under --worktree, else "batch-$(date -u +%Y%m%dT%H%M%SZ)" # fixed ONCE here; the close-out reuses it
|
|
329
|
-
commit-guard start --run "$RUN_ID"
|
|
328
|
+
spur workflow commit-guard start --run "$RUN_ID" # 1129 R1: fingerprint before the first task writes; the close-out commit stages through it
|
|
330
329
|
for wbs in plan: # default sequential mode
|
|
331
330
|
if any dependency of wbs failed earlier in THIS batch:
|
|
332
331
|
report += skipped(wbs, reason); continue # only relevant under --keep-going
|
|
@@ -334,7 +333,7 @@ for wbs in plan: # default sequential mode
|
|
|
334
333
|
if precheck fails on semantic findings:
|
|
335
334
|
if --auto: one /sp:dev-refineall --auto pass; still failing → report += skipped(wbs, findings); continue
|
|
336
335
|
else: HALT (unchanged non-auto behavior)
|
|
337
|
-
preflight =
|
|
336
|
+
preflight = spur task preflight <wbs> # Step 2.6 — TABLE A STOP
|
|
338
337
|
if preflight.action == skip:
|
|
339
338
|
report += preflight-skip(wbs, preflight); continue
|
|
340
339
|
visible plan (§2.7): letter in_progress + task-children digits at start; letter ← outcome at end
|
|
@@ -443,7 +442,7 @@ After a non-PASS terminal state (or when the task status is stuck at `wip`/`test
|
|
|
443
442
|
verdict), consult **one** recovery hop:
|
|
444
443
|
|
|
445
444
|
```bash
|
|
446
|
-
|
|
445
|
+
spur task preflight <wbs> --status <status> --recovery
|
|
447
446
|
# → e.g. /sp:dev-verify 0042 --auto --next
|
|
448
447
|
```
|
|
449
448
|
|
|
@@ -455,7 +454,7 @@ node "$(superskill script path sp batch-preflight.mjs)" --wbs <wbs> --status <st
|
|
|
455
454
|
| Multi-candidate | HITL stop — do not silent-pick (batch `--auto` does not break ties) |
|
|
456
455
|
| Forbidden | Replacing the whole batch with repeated `/sp:dev-next` (deep-merge) |
|
|
457
456
|
|
|
458
|
-
Helper: `recoveryHint(status, wbs)`
|
|
457
|
+
Helper: `recoveryHint(status, wbs)` behind `spur task preflight --recovery`. Tables remain SSOT
|
|
459
458
|
in next-router; this only maps status → primary TABLE A hop for recovery.
|
|
460
459
|
|
|
461
460
|
### 3.3c Feature-sync retry suppression (task 0411; 1004 R3)
|
|
@@ -47,7 +47,7 @@ emit batch report (per-task outcomes + preflight skips + recovery hints + batch
|
|
|
47
47
|
rebase over theirs. Omitting `--mode` stays sequential; this loop is entered only via
|
|
48
48
|
`--mode parallel` on `/sp:dev-runall`, directly or as a `--mode auto` resolution
|
|
49
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
|
|
50
|
+
- **Fan-out set.** Run order and eligibility come from the § 2.4 `spur task batch-plan order` schedule;
|
|
51
51
|
its file-overlap edges are in-set dependencies here, so overlapping tasks never run at once.
|
|
52
52
|
- **Workdir.** `spur workflow run` records the launch workdir (0784 R1), so launch with `cwd` = the
|
|
53
53
|
task worktree: resume and `.spur/run/` artifact paths resolve there. Read the verdict from
|
|
@@ -89,7 +89,7 @@ git merge-base --is-ancestor "$BATCH_TIP" "$LANDED_BASE_TIP" \
|
|
|
89
89
|
write_marker () { # $1 = merged | retained; read-modify-write: preserve WT-3 fields (id, command, selector, createdAt, adopted, adoptedAt); jq already assumed by WT-3/task-resolution flows
|
|
90
90
|
mkdir -p "$(dirname "$MARKER")"
|
|
91
91
|
if [ -f "$MARKER" ]; then
|
|
92
|
-
TMP_MARKER="$(mktemp)"
|
|
92
|
+
TMP_MARKER="$(mktemp "$MARKER.XXXXXX")" # sibling: atomic same-dir mv, no system temp dir
|
|
93
93
|
jq --arg s "$1" --arg m "$BATCH_TIP" '.status = $s | .mergeCommit = $m' "$MARKER" > "$TMP_MARKER" \
|
|
94
94
|
|| { echo "WT-4 halt: cannot rewrite marker $MARKER" >&2; rm -f "$TMP_MARKER"; exit 1; }
|
|
95
95
|
mv "$TMP_MARKER" "$MARKER"
|
|
@@ -116,8 +116,7 @@ WT_PATH="$(cd "../<worktree-dir>" && pwd)" # hoisted: needed by WT-4a AND WT-4
|
|
|
116
116
|
# automatically reconciles each forwarded terminal task's receiving lifecycle row in
|
|
117
117
|
# the invoking tree (finalizing any stale in-flight or interrupted row left from the
|
|
118
118
|
# task's creation), so a manual DB edit is never required:
|
|
119
|
-
|
|
120
|
-
bun "$SETUP_SCRIPT" --persist-out --from "$WT_PATH" "${TASK_FILE_ARGS[@]}" \
|
|
119
|
+
spur workflow inline persist-out --from "$WT_PATH" "${TASK_FILE_ARGS[@]}" \
|
|
121
120
|
|| { echo "halt: worktree run-record persist-out failed - worktree retained (WT-5)" >&2; write_marker retained; exit 1; }
|
|
122
121
|
#
|
|
123
122
|
# WT-4b — bounded CWD-holder cleanup (task 0720 R1). $WT_PATH above is the EXACT
|
|
@@ -156,10 +155,9 @@ fi # NO prune/remove/branch delete
|
|
|
156
155
|
# worktree while it still owns evidence absent from (or divergent from) the invoking tree —
|
|
157
156
|
# the D63 landing skipped persist-out and silently lost verdicts + receipts. WBSes ride the
|
|
158
157
|
# same TASK_FILE_ARGS resolved for WT-4a; run ids are a separate `--run-id <id>` per run and
|
|
159
|
-
# belong to THIS check only — `inline
|
|
158
|
+
# belong to THIS check only — `spur workflow inline persist-out` accepts `--from` and
|
|
160
159
|
# `--task-file` alone and exits 2 on `--run-id` (1089 driver note).
|
|
161
|
-
|
|
162
|
-
bun "$CHECK_SCRIPT" --from "$WT_PATH" "${TASK_FILE_ARGS[@]}" \
|
|
160
|
+
spur workflow inline persist-check --from "$WT_PATH" "${TASK_FILE_ARGS[@]}" \
|
|
163
161
|
|| { echo "WT-4 halt: worktree evidence would be abandoned - persist-out missing or stale (WT-5)" >&2; write_marker retained; exit 1; }
|
|
164
162
|
git worktree remove "../<worktree-dir>" \
|
|
165
163
|
|| { echo "WT-4 halt: worktree remove failed after landed merge $BATCH_TIP" >&2; write_marker retained; exit 1; }
|
|
@@ -235,7 +233,7 @@ WT_PATH="<resolved-worktree-path>" # reuse mode: the adopted tree's physical p
|
|
|
235
233
|
write_marker () { # $1 = merged | retained; read-modify-write: preserve WT-3 fields (id, command, selector, createdAt, adopted, adoptedAt); jq already assumed by WT-3/task-resolution flows
|
|
236
234
|
mkdir -p "$(dirname "$MARKER")"
|
|
237
235
|
if [ -f "$MARKER" ]; then
|
|
238
|
-
TMP_MARKER="$(mktemp)"
|
|
236
|
+
TMP_MARKER="$(mktemp "$MARKER.XXXXXX")" # sibling: atomic same-dir mv, no system temp dir
|
|
239
237
|
jq --arg s "$1" --arg m "$BATCH_TIP" '.status = $s | .mergeCommit = $m' "$MARKER" > "$TMP_MARKER" \
|
|
240
238
|
|| { echo "WT-4 halt: cannot rewrite marker $MARKER" >&2; rm -f "$TMP_MARKER"; exit 1; }
|
|
241
239
|
mv "$TMP_MARKER" "$MARKER"
|
|
@@ -423,15 +421,14 @@ git checkout <base-ref> && git merge --no-ff -m "<prepared message>" <branch>
|
|
|
423
421
|
# the batch's run id, the same one WT-3b's worktree fingerprint used — the two trees keep two
|
|
424
422
|
# artifacts under the same id):
|
|
425
423
|
# RUN_ID="<marker-id>" # the WT-3 marker's id
|
|
426
|
-
#
|
|
427
|
-
# bun "$GUARD" start --run "$RUN_ID"
|
|
424
|
+
# spur workflow commit-guard start --run "$RUN_ID"
|
|
428
425
|
# git checkout <base-ref> && git merge --no-commit <branch>
|
|
429
426
|
# 2. resolve source conflicts by hand; generated files are then regenerated with the project's
|
|
430
427
|
# generator, never hand-merged
|
|
431
428
|
# (this repo: bun run build:plugin-lib && bun run --filter @gobing-ai/spur build:bundle)
|
|
432
429
|
# 3. stage every resolved path and regenerated bundle through the guard — an unmerged or
|
|
433
430
|
# unstaged path makes step 5 abort, and a conflict-marked path exits 3 (resolve, then retry):
|
|
434
|
-
#
|
|
431
|
+
# spur workflow commit-guard stage --run "$RUN_ID" -- <resolved paths and regenerated bundles>
|
|
435
432
|
# Forbidden here as in every driver commit step: `git add -A` and `git add .`.
|
|
436
433
|
# 4. run qualityGateCmd once, after ALL conflicts are resolved
|
|
437
434
|
# 5. commit the merge with the prepared message file — CHECK THE PARENTS FIRST (step 5a)
|
|
@@ -446,7 +443,7 @@ git checkout <base-ref> && git merge --no-ff -m "<prepared message>" <branch>
|
|
|
446
443
|
# ancestry).
|
|
447
444
|
|
|
448
445
|
# 6. persist evidence out (WT-4a), then WT-4b/4c cleanup, and set the marker to merged
|
|
449
|
-
inline
|
|
446
|
+
spur workflow inline persist-out --from <worktree> --task-file …
|
|
450
447
|
```
|
|
451
448
|
|
|
452
449
|
The report reuses the [`--next` chain contract](flag-glossary.md#--next-chain-contract) halt-report
|
|
@@ -20,7 +20,7 @@ lifecycle for the sequential batch loop. `--mode parallel` has its own per-task
|
|
|
20
20
|
rejected there (parallel mode already isolates each task in its own worktree).
|
|
21
21
|
|
|
22
22
|
**Startup ordering (task 0814 R3).** Resolve the selector/status filter and run the quick
|
|
23
|
-
command-aware readiness (the `quickReadiness` contract
|
|
23
|
+
command-aware readiness (the `quickReadiness` contract behind `spur task preflight --operation`) **before** creating
|
|
24
24
|
or adopting the tree. The admission decision is what determines whether a tree should be cut at all;
|
|
25
25
|
all subsequent tools, agents, task/feature writes, and run artifacts use the confirmed execution
|
|
26
26
|
tree's cwd. A stale or empty selector, an unsupported mode, or an invalid target creates no tree and
|
|
@@ -209,7 +209,7 @@ the worktree directory before launching the loop.
|
|
|
209
209
|
|
|
210
210
|
`.spur/memory/evidence/` and `.spur/run/` are **untracked per-tree** planes, so a fresh worktree
|
|
211
211
|
starts with neither while the invoking tree holds every earlier task's verdict. Both
|
|
212
|
-
`preflightFeature` (`
|
|
212
|
+
`preflightFeature` (`spur task wrapup resolve` → `spur feature check --strict --as done`
|
|
213
213
|
with cwd = the worktree) and `runMetrics` resolve verdict artifacts relative to the tree they run
|
|
214
214
|
in, so without this step an already-`done` linked task reads as missing evidence
|
|
215
215
|
(`L4.evidence-not-recoverable`, `L4.scenario-unverified`) and its metrics row degrades to
|
|
@@ -346,14 +346,13 @@ fingerprints the invoking tree, which is also where its commit lands. The confli
|
|
|
346
346
|
fingerprints the invoking tree for the same reason (its own step 1b).
|
|
347
347
|
|
|
348
348
|
```bash
|
|
349
|
-
GUARD=plugins/sp/scripts/commit-guard.ts; [ -f config/plugin-scripts.json -a -f "$GUARD" ] || GUARD="$(superskill script path sp commit-guard.mjs 2>/dev/null)"
|
|
350
349
|
# Pinned subshell, same discipline as WT-3b: select the execution tree for this one call.
|
|
351
350
|
(
|
|
352
351
|
cd -- "../<worktree-dir>" || { echo "tree missing: expected ../<worktree-dir>" >&2; exit 1; }
|
|
353
352
|
[ "$(git branch --show-current)" = "$BRANCH" ] \
|
|
354
353
|
|| { echo "branch mismatch: expected $BRANCH, got $(git branch --show-current)" >&2; exit 1; }
|
|
355
354
|
RUN_ID="<marker-id>" # the WT-3 marker's id — the same id WT-3b's stage call uses
|
|
356
|
-
|
|
355
|
+
spur workflow commit-guard start --run "$RUN_ID" # <worktree>/.spur/run/$RUN_ID-tree-start.json = { head, dirty[] }
|
|
357
356
|
)
|
|
358
357
|
```
|
|
359
358
|
|
|
@@ -369,9 +368,8 @@ same call, verifies the WT-3 identity, and never relies on a persistent `cd` or
|
|
|
369
368
|
cd -- "../<worktree-dir>" || { echo "tree missing: expected ../<worktree-dir>" >&2; exit 1; }
|
|
370
369
|
[ "$(git branch --show-current)" = "$BRANCH" ] \
|
|
371
370
|
|| { echo "branch mismatch: expected $BRANCH, got $(git branch --show-current)" >&2; exit 1; }
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
bun "$GUARD" stage --run "$RUN_ID" -- <files-the-batch-wrote> \
|
|
371
|
+
spur workflow commit-guard check --run "$RUN_ID" # 1129 R3: concurrent foreign writers; a non-empty list goes in the batch report
|
|
372
|
+
spur workflow commit-guard stage --run "$RUN_ID" -- <files-the-batch-wrote> \
|
|
375
373
|
|| { echo "WT-3b halt: commit-guard refused a path (foreign, unmerged or conflict-marked); nothing committed" >&2; exit 1; }
|
|
376
374
|
git commit -m "<type>(<scope>): <command> <selector> batch writes"
|
|
377
375
|
)
|
|
@@ -379,7 +377,7 @@ same call, verifies the WT-3 identity, and never relies on a persistent `cd` or
|
|
|
379
377
|
|
|
380
378
|
> **Forbidden in every driver commit step:** `git add -A` and `git add .`. They stage whatever a
|
|
381
379
|
> concurrent writer happened to leave in the tree — the two incidents this guard exists for are
|
|
382
|
-
> `a94f9f431` and `36f274590` — so a driver stages only through `commit-guard stage`.
|
|
380
|
+
> `a94f9f431` and `36f274590` — so a driver stages only through `spur workflow commit-guard stage`.
|
|
383
381
|
|
|
384
382
|
> **`stage` takes files, never directories.** A directory argument is refused as `(unchanged since
|
|
385
383
|
> base)` and stages *nothing*, so a task whose diff lives in a moved tree must expand the changed
|
|
@@ -88,7 +88,7 @@ Entered before `task-pipeline.yaml` `review` state dispatches `sp:code-verificat
|
|
|
88
88
|
|
|
89
89
|
- [ ] The implementation matches the task's `## Plan` checklist (every checked item maps to a code/test/doc change).
|
|
90
90
|
- [ ] `git status` shows only changes traceable to this task's Plan (no drive-by edits).
|
|
91
|
-
- [ ] Check receipt current: `
|
|
91
|
+
- [ ] Check receipt current: `spur task gate <wbs> status` reports `reuse: true` for
|
|
92
92
|
`.spur/run/<wbs>-check-receipt.json` at the current digest; run `bun run spur-check` only
|
|
93
93
|
when it reports stale or missing (0940 — never re-run the full chain on a reusable receipt).
|
|
94
94
|
- [ ] New `biome-ignore` / `eslint-disable` suppressions: none, or each is justified inline.
|
|
@@ -21,7 +21,7 @@ the interpreter and trace instructions must match. Never hand-edit the installed
|
|
|
21
21
|
|
|
22
22
|
## Driver state checklist (re-read this after a compaction)
|
|
23
23
|
|
|
24
|
-
- **Run id** — the run row `inline
|
|
24
|
+
- **Run id** — the run row `spur workflow inline begin` persisted (`.spur/run/<run-id>-inline-setup.json`
|
|
25
25
|
sidecar, `.spur/memory/runs/<run-id>.md` + `.state.json`); never re-derive it from the transcript.
|
|
26
26
|
- **Markers under `.spur/run/`** — `<run-id>-inline-setup.json` (frozen invocation identity),
|
|
27
27
|
`<run-id>-tree-start.json` (commit-guard fingerprint), `<wbs>-verdict.json` (per-stage verdict),
|
|
@@ -98,14 +98,8 @@ fallback) — labels are display addresses only, never an execution key.
|
|
|
98
98
|
accept the inline run (0785 R3):
|
|
99
99
|
|
|
100
100
|
```bash
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
# pipelines' run-start action writes) so the inline path carries the same provenance.
|
|
104
|
-
RS=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$RS" ] || RS="$(superskill script path sp script-root.mjs 2>/dev/null)";
|
|
105
|
-
RUNNER=bun; case "$RS" in *.mjs) RUNNER=node ;; esac; [ -f "$RS" ] && "$RUNNER" "$RS" --run-id "$RUN_ID" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2
|
|
106
|
-
[ -n "$SETUP_SCRIPT" ] && [ -f "$SETUP_SCRIPT" ] && \
|
|
107
|
-
bun "$SETUP_SCRIPT" --run-id "$RUN_ID" --file <selected-pipeline-yaml> \
|
|
108
|
-
|| { echo "inline run setup failed closed — checker not found; run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 1; }
|
|
101
|
+
spur workflow inline begin --run-id "$RUN_ID" --file <selected-pipeline-yaml> \
|
|
102
|
+
|| { echo "inline run setup failed closed — see the spur workflow inline begin error above" >&2; exit 1; }
|
|
109
103
|
```
|
|
110
104
|
|
|
111
105
|
**Commit fingerprint (1129 R1).** Fingerprint the tree the task commit will land in — before the
|
|
@@ -118,21 +112,18 @@ fallback) — labels are display addresses only, never an execution key.
|
|
|
118
112
|
|
|
119
113
|
```bash
|
|
120
114
|
RUN_ID="<marker-id>" # the WT-3 marker's id (execution-batch.md), or the run id allocated at setup
|
|
121
|
-
|
|
122
|
-
bun "$GUARD" start --run "$RUN_ID" # <this tree>/.spur/run/$RUN_ID-tree-start.json = { head, dirty[] }
|
|
115
|
+
spur workflow commit-guard start --run "$RUN_ID" # <this tree>/.spur/run/$RUN_ID-tree-start.json = { head, dirty[] }
|
|
123
116
|
```
|
|
124
117
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Both paths create-or-attach the row,
|
|
118
|
+
`spur workflow inline begin` (the installed CLI transport; the plugin requires spur) obtains the
|
|
119
|
+
selected definition from the CLI's `workflow show --format todo --json` projection — through
|
|
120
|
+
`--spur-bin`/`SPUR_BIN` when set, else the running spur — and revalidates its
|
|
121
|
+
schema/name/digest before preserving its source layer. It create-or-attaches the row,
|
|
130
122
|
and writes the run-record state `.spur/memory/runs/<run-id>.state.json` plus the `.md` run-start
|
|
131
123
|
header (task 0927; a legacy pre-0927 run keeps its `<run-id>-inline-setup.json` sidecar).
|
|
132
124
|
Seed `__runId` and `__definitionDigest`
|
|
133
125
|
from that state so proof capture and bound registration verify against the persisted identity.
|
|
134
|
-
|
|
135
|
-
A non-zero exit (missing runtime/bundle, invalid projection, missing row identity, changed definition) stops the run —
|
|
126
|
+
A non-zero exit (invalid projection, missing row identity, changed definition) stops the run —
|
|
136
127
|
never continue unbound and never fabricate a PASS. (The delegate persists the authoritative
|
|
137
128
|
RUN row only — the 0808 inline record is the registration-equivalent convention below, not a
|
|
138
129
|
setup-time artifact-ledger insert.)
|
|
@@ -173,7 +164,7 @@ fallback) — labels are display addresses only, never an execution key.
|
|
|
173
164
|
Publishing executes nothing, so it safely precedes readiness and isolation, which keep their
|
|
174
165
|
existing order below.
|
|
175
166
|
6. **Quick deterministic readiness (R2), before isolation.** Evaluate `quickReadiness` from
|
|
176
|
-
`
|
|
167
|
+
`spur task preflight <wbs> --operation <op>` with the operation, status, filtered-set size, the
|
|
177
168
|
matrix-selected required/present sections, and content-policy findings. Record the outcome
|
|
178
169
|
(runnable / needs-refinement / blocked / skipped / invalid) in the run log. Admission decision
|
|
179
170
|
only — no model, no full tests/lint, no live-data probe, no feature mutation, no corpus-wide
|
|
@@ -414,15 +405,15 @@ After each executed action settles, record its boundary before the next action,
|
|
|
414
405
|
or terminal close. Measure its actual duration and preserve its declared failure policy:
|
|
415
406
|
|
|
416
407
|
```bash
|
|
417
|
-
|
|
408
|
+
spur workflow inline action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
|
|
418
409
|
--status <done|failed> --ok <true|false> --duration-ms <measured-ms> [--estimated]
|
|
419
410
|
```
|
|
420
411
|
|
|
421
412
|
`--duration-ms` is the wall clock measured around the action. Pass `--estimated` when you did
|
|
422
413
|
**not** time it — for example a duration reconstructed after a subagent returned — so the row is
|
|
423
|
-
labelled instead of presented as measured. `--estimated` is valid only
|
|
414
|
+
labelled instead of presented as measured. `--estimated` is valid only on `inline action`.
|
|
424
415
|
|
|
425
|
-
For a multi-action state,
|
|
416
|
+
For a multi-action state, `spur workflow inline actions --file <json>` may emit the measured boundaries together before leaving
|
|
426
417
|
that state. Follow [Structured trace emission](#structured-trace-emission-adr-117-task-0868) for the
|
|
427
418
|
payload, delegated `decide` emission and best-effort failure handling. Never retry a failed batch
|
|
428
419
|
or backfill at close; a zero-row done close fails with `NO_ACTION_ROWS`.
|
|
@@ -488,7 +479,7 @@ Action semantics come from the YAML and the workflow action contract:
|
|
|
488
479
|
state mutates the task, the host validates the same refusal conditions inline — the declared
|
|
489
480
|
artifact exists at the resolved path and is canonical-valid for the run's wbs (for
|
|
490
481
|
`verify-verdict`: verdict `PASS`), `proofBinding: current` is honored against a freshly captured
|
|
491
|
-
proof digest — capture it with `
|
|
482
|
+
proof digest — capture it with `spur workflow inline fingerprint --task-file <task path>
|
|
492
483
|
[--feature-file <feature path>]`, the same entry point used at Run setup, which prints the engine
|
|
493
484
|
`sha256:<hex>` digest. Run it inside a per-call pin subshell for the confirmed execution tree
|
|
494
485
|
(the cwd feeds the git-tree half of the digest)
|
|
@@ -560,8 +551,7 @@ run collapses into one serial host worker with no executor diversity. So classif
|
|
|
560
551
|
failure before falling back:
|
|
561
552
|
|
|
562
553
|
```bash
|
|
563
|
-
|
|
564
|
-
bun "$DISPATCH_SCRIPT" --dispatch-failure --run-id "$RUN_ID" --stage <state-id> --decision <escalate|stop> \
|
|
554
|
+
spur workflow inline dispatch-failure --run-id "$RUN_ID" --stage <state-id> --decision <escalate|stop> \
|
|
565
555
|
--text-file <bounded failure record> [--executor <name>] [--agent <a>] [--model <m>]
|
|
566
556
|
```
|
|
567
557
|
|
|
@@ -586,7 +576,7 @@ record the executor identity the stage will use, so a later classified exhaustio
|
|
|
586
576
|
to a rung configuration can disable:
|
|
587
577
|
|
|
588
578
|
```bash
|
|
589
|
-
|
|
579
|
+
spur workflow inline attribution --run-id "$RUN_ID" --stage <state-id> \
|
|
590
580
|
[--executor <name>] [--agent <name>] [--model <m>] # omit --executor for the no-attribution marker
|
|
591
581
|
```
|
|
592
582
|
|
|
@@ -662,6 +652,12 @@ boundary, and a delegate left to re-derive them re-derives them against its own
|
|
|
662
652
|
when a plugin script was touched, and the paired-script parity test when `package.json` changed —
|
|
663
653
|
so an env-var-hygiene violation, a stale generated twin, or a half-updated paired chain is
|
|
664
654
|
named by the stage rather than discovered by the pipeline `test` hop.
|
|
655
|
+
**That pre-check is returned evidence, not a background step:** the stage reports its output (or
|
|
656
|
+
`precheck: not-run` with the reason), and a stage that returns neither the output nor the
|
|
657
|
+
not-run line is recorded `done` with a `precheck-missing` marker beside the `probe-missing` one.
|
|
658
|
+
Measured cost of skipping it (2026-10-16, task 1215): one full quality-gate run plus a
|
|
659
|
+
`test-fix` → `test-recheck` cycle on a `process.env` in a new test that the pre-check preset
|
|
660
|
+
flags in seconds.
|
|
665
661
|
**A stage that returns neither probe evidence nor the not-applicable line is not silently
|
|
666
662
|
complete (task 1135 R2): the driver records the stage `done` with a `probe-missing` marker in
|
|
667
663
|
the run log and carries the same marker into that task's batch-report row.**
|
|
@@ -765,7 +761,7 @@ host-owned gate sat between the stages, or when the platform cannot address comp
|
|
|
765
761
|
|
|
766
762
|
**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:
|
|
767
763
|
1. the **changed-path matrix** (`code-implementation/SKILL.md` § Changed-path targeted checks) over the paths they touched;
|
|
768
|
-
2.
|
|
764
|
+
2. `spur task gate <wbs> light` (biome, per-workspace typecheck, rule presets, related tests).
|
|
769
765
|
Neither step takes the full gate. The pipeline's `test` and `test-recheck` hops remain the only full gate. Carry
|
|
770
766
|
`--gate-log <path>` through to the child **verbatim**: never paraphrase it into "re-run the named
|
|
771
767
|
gate command". That paraphrase is not cosmetic — it sent a worker into a full gate run instead of
|
|
@@ -864,7 +860,7 @@ documented beside `DEFAULT_EXCLUDE_GLOBS` in `proof-input-fingerprint.ts`).
|
|
|
864
860
|
Order matters for the `testing → done` hop: the sections must not be hand-written **before** the
|
|
865
861
|
verdict artifact exists (tasks 0617, 0619 — the clobbering spiral).
|
|
866
862
|
|
|
867
|
-
1. **Write the verdict artifact first.** `spur task record --solution-from-diff --transition testing`
|
|
863
|
+
1. **Write the verdict artifact first.** `spur task record <wbs> --solution-from-diff --transition testing --no-lifecycle`
|
|
868
864
|
reads `.spur/run/<wbs>-verdict.json` (default attempt output) on every invocation and atomically retains the recorded verdict under `.spur/memory/evidence/`. A missing or malformed artifact
|
|
869
865
|
yields **UNKNOWN**: bare Testing receives a "No requirements recorded" stub, while already-authored
|
|
870
866
|
Testing is preserved. `--solution-from-diff` backfills only a bare Solution. The clobbering above is
|
|
@@ -878,7 +874,7 @@ verdict artifact exists (tasks 0617, 0619 — the clobbering spiral).
|
|
|
878
874
|
# Both calls are per-call pinned (task 1058): the record hop selects the execution tree inside
|
|
879
875
|
# the same tool call — never through a cwd a previous call happened to leave behind.
|
|
880
876
|
spur task update <wbs> wip --no-lifecycle
|
|
881
|
-
spur task record <wbs> --solution-from-diff --transition testing
|
|
877
|
+
spur task record <wbs> --solution-from-diff --transition testing --no-lifecycle
|
|
882
878
|
```
|
|
883
879
|
|
|
884
880
|
The engine now preserves an already-authored Testing when the verdict is UNKNOWN (task-service
|
|
@@ -908,16 +904,15 @@ verdict artifact exists (tasks 0617, 0619 — the clobbering spiral).
|
|
|
908
904
|
conflict markers — both mean "resolve it, do not commit":
|
|
909
905
|
|
|
910
906
|
```bash
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
bun "$GUARD" stage --run "$RUN_ID" -- <files this run wrote> \
|
|
907
|
+
spur workflow commit-guard check --run "$RUN_ID"
|
|
908
|
+
spur workflow commit-guard stage --run "$RUN_ID" -- <files this run wrote> \
|
|
914
909
|
|| { echo "record halt: commit-guard refused a path (foreign, unmerged or conflict-marked); nothing committed" >&2; exit 1; }
|
|
915
910
|
git commit -m "<type>(<scope>): <wbs> <summary>"
|
|
916
911
|
```
|
|
917
912
|
|
|
918
|
-
5. **Print the run's execution summary (1146).** The terminal
|
|
913
|
+
5. **Print the run's execution summary (1146).** The terminal `spur workflow inline close` returns `summaryFile`; print
|
|
919
914
|
that file's contents verbatim under an `### Execution summary` heading, and pass `--no-summary`
|
|
920
|
-
through to
|
|
915
|
+
through to `inline close` when the operator asked for it. The window is the run row's `started_at` →
|
|
921
916
|
close time — the driver records no `SINCE` and assembles no measurement of its own
|
|
922
917
|
(structured-trace-emission.md § the close step owns the contract).
|
|
923
918
|
|
|
@@ -967,17 +962,15 @@ were both violated once on 2026-10-10, aborting the run's own verification):
|
|
|
967
962
|
|
|
968
963
|
Each item below cost a driver cycle to discover. They are contracts, not tips.
|
|
969
964
|
|
|
970
|
-
-
|
|
965
|
+
- **`spur workflow inline decide --options-json <file>` takes one option object, never an array.** Shape:
|
|
971
966
|
`{id, decision, params?, evidence? | instructions?, resultFile}`; `evidence` and `instructions` are
|
|
972
967
|
mutually exclusive (`CatalogDecideOptionsSchema`). A JSON array parses as neither dialect and
|
|
973
968
|
surfaces as `decide: invalid options — Invalid input` with no field detail. `resultFile` resolves
|
|
974
969
|
against the confirmed tree's cwd, so pass a worktree-relative path such as
|
|
975
970
|
`.spur/run/<wbs>-triage.decision`.
|
|
976
|
-
- **`task
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
source-repo path form — the script-contract check forbids it on a shipped surface because it
|
|
980
|
-
shadows the installed twin in a consumer.
|
|
971
|
+
- **`spur task diffstat <wbs>` writes an artifact, not output.** stdout stays empty, so assert
|
|
972
|
+
success on `.spur/run/<wbs>-diffstat.json` and never on command output; a missing or malformed
|
|
973
|
+
run base still exits 0 with `sensitive: true` (fail safe).
|
|
981
974
|
- **The verify answer grammar is exact.** One `Verdict:` line, then
|
|
982
975
|
`### Per-Requirement Traceability` (`| Req | Status | Evidence |`) and
|
|
983
976
|
`### Acceptance Criteria Verification` (`| AC | Status | Evidence Type | Evidence |`). Requirement
|
|
@@ -16,14 +16,14 @@ implementation. The shared writer is `WorkflowActionTraceWriter`
|
|
|
16
16
|
around `DbWorkflowPersistenceAdapter`, so the two surfaces call one emission path and one run-row
|
|
17
17
|
closure path and cannot drift.
|
|
18
18
|
|
|
19
|
-
The driver reaches it through the
|
|
20
|
-
|
|
19
|
+
The driver reaches it through the installed CLI transport `spur workflow inline <op>` (the same
|
|
20
|
+
command that began the run) — no second entry point, no second resolution chain:
|
|
21
21
|
|
|
22
22
|
- **Every executed action** — after the action settles, whether it ran host-inline or via a native
|
|
23
23
|
subagent — append its provenance line as before, then record the boundary:
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
spur workflow inline action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
|
|
27
27
|
--status <done|failed> --ok <true|false> [--duration-ms <measured-ms>] [--estimated] \
|
|
28
28
|
--project-root "$OWNING_TREE"
|
|
29
29
|
```
|
|
@@ -43,45 +43,45 @@ deliberate, so when the driver runs inside a `--worktree` (or any other executio
|
|
|
43
43
|
lives in the **invoking** tree's `.spur/spur.db` while the action commands run in the execution
|
|
44
44
|
tree. `--project-root` is the invoking tree recorded by the WT-3 marker; without it the row is read
|
|
45
45
|
from the cwd tree. A run-row miss is a **correctness failure**, not a best-effort emission failure:
|
|
46
|
-
|
|
47
|
-
`{"ok":false,"code":"RUN_NOT_FOUND"}`, exactly like
|
|
46
|
+
`inline action`, `inline actions` and `inline node-enter` exit `1` with
|
|
47
|
+
`{"ok":false,"code":"RUN_NOT_FOUND"}`, exactly like `inline close`. **Never redirect these calls'
|
|
48
48
|
stdout/stderr to `/dev/null`** — the suppressed-RUN_NOT_FOUND run of task 1132 lost 93 action rows
|
|
49
49
|
to exactly that redirect. Capture the output or let it stream; a failure must be visible.
|
|
50
50
|
|
|
51
51
|
**Durations: measured beats reported (task 1136 R4).** Stamp the enter time before the action runs:
|
|
52
52
|
|
|
53
53
|
```bash
|
|
54
|
-
|
|
54
|
+
spur workflow inline node-enter --run-id "$RUN_ID" --node <state-id> --project-root "$OWNING_TREE"
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
Then call
|
|
57
|
+
Then call `inline action` **without** `--duration-ms` — the delegate computes
|
|
58
58
|
`duration = now − enter` and stamps `provenance: measured` into `action_runs.result_json`. A
|
|
59
59
|
caller-supplied `--duration-ms` stays valid but is recorded `provenance: host-reported` (with
|
|
60
60
|
`--estimated` marking a value reconstructed after the fact); every other inline row is
|
|
61
61
|
`host-reported` too, and the projection exposes `provenance` per attempt so the Board can label a
|
|
62
62
|
reported duration instead of presenting it as measured. A row whose computed start would precede
|
|
63
63
|
`runs.started_at` is **rejected** (exit `1`) — a timestamp before the run began is a broken clock,
|
|
64
|
-
not evidence. Calling
|
|
64
|
+
not evidence. Calling `inline action` without `--duration-ms` and without a matching `inline node-enter`
|
|
65
65
|
exits `1` with `code:"ACTION_DURATION_UNAVAILABLE"`; it never silently drops the row.
|
|
66
66
|
|
|
67
67
|
- **A state with several actions (1007 R5)** — emit the whole state's boundaries in one call
|
|
68
|
-
instead of one
|
|
69
|
-
(`[{node,kind,status,ok,durationMs,estimated?}, …]` — the
|
|
70
|
-
optional and `false` when absent) to a temp file and pass it with
|
|
68
|
+
instead of one `inline action` invocation per action. Write a JSON array
|
|
69
|
+
(`[{node,kind,status,ok,durationMs,estimated?}, …]` — the `inline action` fields, `estimated`
|
|
70
|
+
optional and `false` when absent) to a temp file and pass it with `spur workflow inline actions --file`:
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
|
|
73
|
+
spur workflow inline actions --file <actions.json> --run-id "$RUN_ID" --project-root "$OWNING_TREE"
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
Every row is recorded through the same writer as
|
|
76
|
+
Every row is recorded through the same writer as `inline action` (one `action_runs` row per entry);
|
|
77
77
|
the batch is validated in full before the first write, so an invalid row or unreadable file
|
|
78
78
|
exits `1` with `{"ok":false}` and leaves **no** partial rows — fix the batch and re-emit. On
|
|
79
79
|
success it prints `{"ok":true,"runId":…,"recorded":<n>}` and exits `0`. Row emission stays
|
|
80
|
-
best-effort exactly like
|
|
80
|
+
best-effort exactly like `inline action`: if a row's write fails mid-batch, the failure is recorded
|
|
81
81
|
to the run record and the call reports `{"ok":false,…,"error":…}` but still exits `0` — the run
|
|
82
|
-
continues; never retry the batch or backfill by hand.
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
continues; never retry the batch or backfill by hand. Each op takes only its own flags: an
|
|
83
|
+
unknown flag (say `--status` on `inline actions`) is a usage error (exit 2), and such a call
|
|
84
|
+
must be corrected, not silently split.
|
|
85
85
|
|
|
86
86
|
- **A `decide` action (0941)** — the driver never executes the DecisionMaker itself; it delegates
|
|
87
87
|
to the same app runner the engine registers, which writes the resultFile row (schemaVersion 1)
|
|
@@ -89,7 +89,7 @@ to exactly that redirect. Capture the output or let it stream; a failure must be
|
|
|
89
89
|
through the same writer as every other action:
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
|
|
92
|
+
spur workflow inline decide --run-id "$RUN_ID" --node <state-id> --options-json <options-file>
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
The options JSON mirrors the YAML `decide` options (`id`, `method: choice|noul`, `question`,
|
|
@@ -102,14 +102,14 @@ to exactly that redirect. Capture the output or let it stream; a failure must be
|
|
|
102
102
|
`decide node=<id> value=<v> source=<s> reason=<r>` to the run log, so a declared-default
|
|
103
103
|
fallback is never read as a model decision. Only an invalid options
|
|
104
104
|
schema exits `1` (fail closed), and usage errors exit `2`. The `action_runs` trace row is
|
|
105
|
-
best-effort exactly like
|
|
105
|
+
best-effort exactly like `inline action`.
|
|
106
106
|
|
|
107
107
|
- **An operator pause is its own row (task 1136 R5)** — while the driver waits on a `hitl.confirm`
|
|
108
108
|
or `hitl.input`, emit the wait as its own boundary instead of charging it to the neighbouring
|
|
109
109
|
node:
|
|
110
110
|
|
|
111
111
|
```bash
|
|
112
|
-
|
|
112
|
+
spur workflow inline action --run-id "$RUN_ID" --node <state-id> --kind operator-wait \
|
|
113
113
|
--status done --ok true --duration-ms <waited-ms> --project-root "$OWNING_TREE"
|
|
114
114
|
```
|
|
115
115
|
|
|
@@ -121,7 +121,7 @@ to exactly that redirect. Capture the output or let it stream; a failure must be
|
|
|
121
121
|
stale:
|
|
122
122
|
|
|
123
123
|
```bash
|
|
124
|
-
|
|
124
|
+
spur workflow inline close --run-id "$RUN_ID" --status <done|failed|paused> --project-root "$OWNING_TREE"
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
The close also produces the execution summary (1146 R1): its stdout carries
|
|
@@ -152,21 +152,21 @@ to exactly that redirect. Capture the output or let it stream; a failure must be
|
|
|
152
152
|
close with zero rows stays a clean `0` (a halt before the first boundary legitimately records
|
|
153
153
|
nothing), and any `done` close with `actionRows ≥ 1` exits `0`.
|
|
154
154
|
|
|
155
|
-
**Best-effort at the action boundary only (ADR-117, task 1136 R1/R2).** An
|
|
155
|
+
**Best-effort at the action boundary only (ADR-117, task 1136 R1/R2).** An `inline action` persistence
|
|
156
156
|
failure is recorded — the delegate appends a `trace-emission-failed` line to
|
|
157
157
|
`.spur/memory/runs/<run-id>.md` and prints `{"ok":false}` on stdout — and the run continues to its
|
|
158
158
|
declared terminal state; the delegate exits `0` for that outcome and the driver must never treat an
|
|
159
159
|
emission failure as a run failure, retry it in a loop, or substitute a hand-written row. The
|
|
160
160
|
exception is the **run row itself**: a missing run row, a duration that cannot be measured, or a
|
|
161
161
|
start time before `runs.started_at` are correctness failures and exit `1`
|
|
162
|
-
(`RUN_NOT_FOUND`, `ACTION_DURATION_UNAVAILABLE`). The run-row closure (
|
|
162
|
+
(`RUN_NOT_FOUND`, `ACTION_DURATION_UNAVAILABLE`). The run-row closure (`inline close`) is bookkeeping, not
|
|
163
163
|
trace emission, and is **not** best-effort either: a missing run row or a persistence failure exits
|
|
164
164
|
`1` with `{"ok":false}` and a named error (a missing row also carries `code:"RUN_NOT_FOUND"`),
|
|
165
165
|
because a silently `running` row is exactly the stale state `spur workflow clean` reaps as `failed`.
|
|
166
166
|
Exit `2` means the invocation itself was malformed (missing `--node`/`--kind`/`--status`/`--ok`, a
|
|
167
167
|
miscased `--ok`, or a malformed `--duration-ms`) and must be corrected, not ignored.
|
|
168
168
|
|
|
169
|
-
**Never suppress this output.** The driver reference forbids redirecting `inline
|
|
169
|
+
**Never suppress this output.** The driver reference forbids redirecting `spur workflow inline`,
|
|
170
170
|
`quality-gate` and `persist-out*` stdout/stderr to `/dev/null`; a static pin fails any reference
|
|
171
171
|
snippet that does. Suppressing a `RUN_NOT_FOUND` is how task 1132's 93 action rows disappeared.
|
|
172
172
|
|