@gobing-ai/spur 0.4.7 → 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.
Files changed (145) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/pipeline-budgets.json +2 -2
  3. package/config/rules/boundary/config-loading-ownership.yaml +1 -0
  4. package/config/rules/boundary/sp-plugin-standalone.yaml +1 -1
  5. package/config/rules/boundary/sp-script-placement.yaml +1 -1
  6. package/config/rules/docs/sourced-api-claims.yaml +45 -7
  7. package/config/rules/strict/runtime-boundaries.yaml +40 -1
  8. package/config/rules/structure/protected-files.yaml +1 -1
  9. package/config/rules/surface/check-cli-surface.yaml +33 -0
  10. package/config/rules/typescript/no-debugger.yaml +3 -0
  11. package/config/workflow-candidates.json +2 -2
  12. package/config/workflows/feature-verification.yaml +6 -11
  13. package/config/workflows/history-anatomy.yaml +14 -28
  14. package/config/workflows/idea-pipeline.yaml +6 -19
  15. package/config/workflows/pr-review.yaml +9 -16
  16. package/config/workflows/task-pipeline.yaml +16 -23
  17. package/config/workflows/wrapup-pipeline.yaml +21 -63
  18. package/package.json +3 -3
  19. package/plugins/sp/README.md +70 -37
  20. package/plugins/sp/agents/super-planner.md +5 -5
  21. package/plugins/sp/agents/super-reviewer.md +2 -2
  22. package/plugins/sp/commands/dev-changelog.md +1 -1
  23. package/plugins/sp/commands/dev-daily.md +1 -1
  24. package/plugins/sp/commands/dev-pr-review.md +1 -1
  25. package/plugins/sp/commands/dev-review-session.md +1 -1
  26. package/plugins/sp/commands/dev-runall.md +4 -4
  27. package/plugins/sp/commands/dev-verify.md +4 -6
  28. package/plugins/sp/commands/dev-verifyall.md +4 -5
  29. package/plugins/sp/hooks/hooks.json +11 -1
  30. package/plugins/sp/lib/context-post-tool.ts +1 -1
  31. package/plugins/sp/lib/context-session-start.ts +1 -1
  32. package/plugins/sp/lib/context-session-stop.ts +1 -1
  33. package/plugins/sp/lib/destructive-policy.ts +65 -1
  34. package/plugins/sp/plugin.json +2 -5
  35. package/plugins/sp/{hooks → scripts/hooks}/agent-lifecycle.ts +1 -1
  36. package/plugins/sp/scripts/hooks/careful-guard.ts +94 -0
  37. package/plugins/sp/{hooks → scripts/hooks}/context-post-tool.ts +2 -2
  38. package/plugins/sp/{hooks → scripts/hooks}/context-session-start.ts +1 -1
  39. package/plugins/sp/{hooks → scripts/hooks}/context-session-stop.ts +1 -1
  40. package/plugins/sp/{hooks → scripts/hooks}/fleet-guest-stop.ts +6 -4
  41. package/plugins/sp/{hooks → scripts/hooks}/task-write-guard.ts +38 -21
  42. package/plugins/sp/skills/code-implementation/SKILL.md +1 -1
  43. package/plugins/sp/skills/code-verification/SKILL.md +8 -8
  44. package/plugins/sp/skills/code-verification/references/secu-review.md +4 -3
  45. package/plugins/sp/skills/code-verification/references/verdict-schema.md +9 -1
  46. package/plugins/sp/skills/daily-summary/SKILL.md +4 -5
  47. package/plugins/sp/skills/dogfood-testing/SKILL.md +9 -9
  48. package/plugins/sp/skills/dogfood-testing/references/report-template.md +1 -1
  49. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -2
  50. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  51. package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
  52. package/plugins/sp/skills/pr-reviewing/SKILL.md +14 -15
  53. package/plugins/sp/skills/session-review/SKILL.md +3 -3
  54. package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
  55. package/plugins/sp/skills/spur-check/SKILL.md +14 -13
  56. package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
  57. package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
  58. package/plugins/sp/skills/spur-cli/references/builder.md +27 -6
  59. package/plugins/sp/skills/spur-cli/references/features.md +6 -1
  60. package/plugins/sp/skills/spur-cli/references/history.md +3 -0
  61. package/plugins/sp/skills/spur-cli/references/self.md +5 -3
  62. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +3 -0
  63. package/plugins/sp/skills/spur-cli/references/tasks.md +13 -3
  64. package/plugins/sp/skills/spur-cli/references/workflows.md +36 -1
  65. package/plugins/sp/skills/spur-dev/SKILL.md +1 -1
  66. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +1 -1
  67. package/plugins/sp/skills/spur-dev/references/dev-operations.md +12 -12
  68. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +10 -11
  69. package/plugins/sp/skills/spur-dev/references/execution-batch.md +16 -17
  70. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +1 -1
  71. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +8 -11
  72. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +6 -8
  73. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
  74. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -40
  75. package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +24 -24
  76. package/plugins/sp/skills/spur-doctor/SKILL.md +5 -4
  77. package/spur.js +41901 -30598
  78. package/config/plugin-scripts.json +0 -116
  79. package/config/script-placement-baseline.json +0 -33
  80. package/plugins/sp/hooks/careful-guard.ts +0 -74
  81. package/plugins/sp/hooks/pi/guard-extension.ts +0 -304
  82. package/plugins/sp/lib/dogfood-pipeline.ts +0 -265
  83. package/plugins/sp/lib/dogfood-report.ts +0 -278
  84. package/plugins/sp/lib/history-anatomy.generated.d.mts +0 -112
  85. package/plugins/sp/lib/history-anatomy.generated.mjs +0 -691
  86. package/plugins/sp/lib/idea-handoff.generated.d.mts +0 -17
  87. package/plugins/sp/lib/idea-handoff.generated.mjs +0 -1446
  88. package/plugins/sp/lib/inline-run-app.ts +0 -68
  89. package/plugins/sp/lib/inline-run.generated.d.mts +0 -37
  90. package/plugins/sp/lib/inline-run.generated.mjs +0 -3103
  91. package/plugins/sp/lib/plan-projection.generated.d.mts +0 -197
  92. package/plugins/sp/lib/plan-projection.generated.mjs +0 -982
  93. package/plugins/sp/lib/quality-gate.generated.d.mts +0 -139
  94. package/plugins/sp/lib/quality-gate.generated.mjs +0 -30510
  95. package/plugins/sp/lib/residual-scan.generated.d.mts +0 -93
  96. package/plugins/sp/lib/residual-scan.generated.mjs +0 -383
  97. package/plugins/sp/lib/run-summary-core.ts +0 -225
  98. package/plugins/sp/lib/spur-bin.ts +0 -36
  99. package/plugins/sp/lib/step-profile.generated.d.mts +0 -71
  100. package/plugins/sp/lib/step-profile.generated.mjs +0 -174
  101. package/plugins/sp/lib/transcript.ts +0 -112
  102. package/plugins/sp/scripts/batch-plan.mjs +0 -1096
  103. package/plugins/sp/scripts/batch-plan.ts +0 -145
  104. package/plugins/sp/scripts/batch-preflight.mjs +0 -423
  105. package/plugins/sp/scripts/batch-preflight.ts +0 -270
  106. package/plugins/sp/scripts/commit-guard.mjs +0 -226
  107. package/plugins/sp/scripts/commit-guard.ts +0 -248
  108. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +0 -626
  109. package/plugins/sp/scripts/daily-summary/daily-summary.ts +0 -855
  110. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +0 -211
  111. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +0 -110
  112. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +0 -282
  113. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +0 -98
  114. package/plugins/sp/scripts/feature-verification-steps.mjs +0 -82
  115. package/plugins/sp/scripts/feature-verification-steps.ts +0 -164
  116. package/plugins/sp/scripts/history-anatomy-cache.mjs +0 -931
  117. package/plugins/sp/scripts/history-anatomy-cache.ts +0 -247
  118. package/plugins/sp/scripts/idea-handoff.mjs +0 -32
  119. package/plugins/sp/scripts/idea-handoff.ts +0 -47
  120. package/plugins/sp/scripts/inline-run-dispatch.mjs +0 -131
  121. package/plugins/sp/scripts/inline-run-dispatch.ts +0 -115
  122. package/plugins/sp/scripts/inline-run-setup.mjs +0 -746
  123. package/plugins/sp/scripts/inline-run-setup.ts +0 -198
  124. package/plugins/sp/scripts/persist-out-check.mjs +0 -217
  125. package/plugins/sp/scripts/persist-out-check.ts +0 -249
  126. package/plugins/sp/scripts/pr-reviewing.mjs +0 -712
  127. package/plugins/sp/scripts/pr-reviewing.ts +0 -952
  128. package/plugins/sp/scripts/quality-gate.mjs +0 -30491
  129. package/plugins/sp/scripts/quality-gate.ts +0 -80
  130. package/plugins/sp/scripts/residual-scan.mjs +0 -634
  131. package/plugins/sp/scripts/residual-scan.ts +0 -248
  132. package/plugins/sp/scripts/run-summary.mjs +0 -758
  133. package/plugins/sp/scripts/run-summary.ts +0 -107
  134. package/plugins/sp/scripts/script-root.mjs +0 -129
  135. package/plugins/sp/scripts/script-root.ts +0 -199
  136. package/plugins/sp/scripts/session-timeline.mjs +0 -359
  137. package/plugins/sp/scripts/session-timeline.ts +0 -190
  138. package/plugins/sp/scripts/task-diffstat.mjs +0 -181
  139. package/plugins/sp/scripts/task-diffstat.ts +0 -219
  140. package/plugins/sp/scripts/workflow-step-profile.mjs +0 -338
  141. package/plugins/sp/scripts/workflow-step-profile.ts +0 -165
  142. package/plugins/sp/scripts/wrapup-drift-probe.mjs +0 -190
  143. package/plugins/sp/scripts/wrapup-drift-probe.ts +0 -261
  144. package/plugins/sp/scripts/wrapup-steps.mjs +0 -627
  145. 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` (`plugins/sp/scripts/batch-preflight.ts`), consumed through
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
- node "$(superskill script path sp batch-plan.mjs)" order --tasks <tasks.json> [--concurrency <n>]
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 script implements Kahn's
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
- node "$(superskill script path sp batch-preflight.mjs)" \
272
- --wbs <wbs> --status <status> \
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.mjs` (ADR-130 glue over
293
- `packages/app/src/workflow/plan-projection.ts`), reached like `batch-preflight`:
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
- node "$(superskill script path sp batch-plan.mjs)" waves --tasks <tasks.json>
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
- node "$(superskill script path sp batch-plan.mjs)" task-children --letter <task-letter> --plan <plan.json>
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.mjs waves)
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" # 1129 R1: fingerprint before the first task writes; the close-out commit stages through it
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 = batch-preflight(wbs) # Step 2.6 — TABLE A STOP
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
- node "$(superskill script path sp batch-preflight.mjs)" --wbs <wbs> --status <status> --recovery
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)` in `plugins/sp/scripts/batch-preflight.ts`. Tables remain SSOT
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.mjs order` schedule;
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
- SETUP_SCRIPT=plugins/sp/scripts/inline-run-setup.ts; [ -f config/plugin-scripts.json -a -f "$SETUP_SCRIPT" ] || SETUP_SCRIPT="$(superskill script path sp inline-run-setup.mjs 2>/dev/null)"
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-run-setup.ts --persist-out` accepts `--from` and
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
- CHECK_SCRIPT=plugins/sp/scripts/persist-out-check.ts; [ -f config/plugin-scripts.json -a -f "$CHECK_SCRIPT" ] || CHECK_SCRIPT="$(superskill script path sp persist-out-check.mjs 2>/dev/null)"
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
- # 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)"
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
- # bun "$GUARD" stage --run "$RUN_ID" -- <resolved paths and regenerated bundles>
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-run-setup --persist-out --from <worktree> --task-file …
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 in `batch-preflight.ts`) **before** creating
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` (`plugins/sp/scripts/wrapup-steps.ts` → `spur feature check --strict --as done`
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
- bun "$GUARD" start --run "$RUN_ID" # <worktree>/.spur/run/$RUN_ID-tree-start.json = { head, dirty[] }
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
- 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)"
373
- bun "$GUARD" check --run "$RUN_ID" # 1129 R3: concurrent foreign writers; a non-empty list goes in the batch report
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: `quality-gate.ts status` reports `reuse: true` for
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-run-setup` persisted (`.spur/run/<run-id>-inline-setup.json`
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
- SETUP_SCRIPT=plugins/sp/scripts/inline-run-setup.ts; [ -f config/plugin-scripts.json -a -f "$SETUP_SCRIPT" ] || SETUP_SCRIPT="$(superskill script path sp inline-run-setup.mjs 2>/dev/null)";
102
- # 0960 R2: record the run's script-resolution identity beside the run row (the same file the
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
- 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)";
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
- The delegate uses the source app service when the SPUR_BIN chain identifies a checkout;
126
- otherwise it loads the generated application bundle shipped with the plugin. Both setup paths
127
- obtains the selected definition from the existing CLI `workflow show --format todo --json`
128
- projection and revalidates its schema/name/digest before preserving its source layer.
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
- Bun remains required for SQLite; the Node-runnable installed twin re-enters Bun on PATH.
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
- `plugins/sp/scripts/batch-preflight.ts` with the operation, status, filtered-set size, the
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
- bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
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 with `--action`.
414
+ labelled instead of presented as measured. `--estimated` is valid only on `inline action`.
424
415
 
425
- For a multi-action state, `--actions-file` may emit the measured boundaries together before leaving
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 `bun "$SETUP_SCRIPT" --fingerprint --task-file <task path>
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
- DISPATCH_SCRIPT=plugins/sp/scripts/inline-run-dispatch.ts; [ -f config/plugin-scripts.json -a -f "$DISPATCH_SCRIPT" ] || DISPATCH_SCRIPT="$(superskill script path sp inline-run-dispatch.mjs 2>/dev/null)"
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
- bun "$DISPATCH_SCRIPT" --attribution --run-id "$RUN_ID" --stage <state-id> \
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. the resolved `quality-gate` script in `light` mode (source-repo probe, else the installed twin) (biome, per-workspace typecheck, rule presets, related tests).
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
- 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)";
912
- bun "$GUARD" check --run "$RUN_ID"
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 `--close` returns `summaryFile`; print
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 `--close` when the operator asked for it. The window is the run row's `started_at` →
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
- - **`--decide --options-json <file>` takes one option object, never an array.** Shape:
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-diffstat.ts` reads `wbs` from the environment and writes an artifact.** Invoke it as
977
- `wbs=<wbs> node "$(superskill script path sp task-diffstat.mjs)"`; stdout stays empty, so assert success on
978
- `.spur/run/<wbs>-diffstat.json` and never on command output. Never the bare unguarded
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 existing run delegate (`$SETUP_SCRIPT`,
20
- `plugins/sp/scripts/inline-run-setup.ts`) — no new entry point, no second resolution chain:
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
- bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
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
- `--action`, `--actions-file` and `--node-enter` exit `1` with
47
- `{"ok":false,"code":"RUN_NOT_FOUND"}`, exactly like `--close`. **Never redirect these calls'
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
- bun "$SETUP_SCRIPT" --node-enter --run-id "$RUN_ID" --node <state-id> --project-root "$OWNING_TREE"
54
+ spur workflow inline node-enter --run-id "$RUN_ID" --node <state-id> --project-root "$OWNING_TREE"
55
55
  ```
56
56
 
57
- Then call `--action` **without** `--duration-ms` — the delegate computes
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 `--action` without `--duration-ms` and without a matching `--node-enter`
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 `--action` invocation per action. Write a JSON array
69
- (`[{node,kind,status,ok,durationMs,estimated?}, …]` — the `--action` fields, `estimated`
70
- optional and `false` when absent) to a temp file and pass it with `--actions-file`:
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
- bun "$SETUP_SCRIPT" --actions-file <actions.json> --run-id "$RUN_ID" --project-root "$OWNING_TREE"
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 `--action` (one `action_runs` row per entry);
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 `--action`: if a row's write fails mid-batch, the failure is recorded
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. `--actions-file` is exclusive with the
83
- other mode flags (`--action`, `--decide`, `--close`, …): mixing them is a usage error (exit 2),
84
- and a mixed call must be corrected, not silently split.
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
- bun "$SETUP_SCRIPT" --decide --run-id "$RUN_ID" --node <state-id> --options-json <options-file>
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 `--action`.
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
- bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind operator-wait \
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
- bun "$SETUP_SCRIPT" --close --run-id "$RUN_ID" --status <done|failed|paused> --project-root "$OWNING_TREE"
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 `--action` persistence
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 (`--close`) is bookkeeping, not
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-run-setup`,
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