@gobing-ai/spur 0.3.85 → 0.3.86
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 +0 -25
- package/config/plugin-scripts.json +0 -5
- package/config/rules/boundary/env-var-hygiene.yaml +41 -0
- package/config/transition-shims.json +1 -1
- package/config/workflow-candidates.json +41 -0
- package/config/workflows/feature-lifecycle.yaml +4 -2
- package/config/workflows/feature-verification.yaml +70 -0
- package/config/workflows/idea-pipeline.yaml +24 -12
- package/config/workflows/task-pipeline.yaml +43 -12
- package/config/workflows/wrapup-pipeline.yaml +70 -7
- package/package.json +9 -9
- package/plugins/sp/README.md +0 -3
- package/plugins/sp/hooks/agent-hint.ts +5 -4
- package/plugins/sp/hooks/careful-guard.ts +3 -1
- package/plugins/sp/hooks/context-post-tool.ts +2 -1
- package/plugins/sp/hooks/context-session-start.ts +4 -3
- package/plugins/sp/hooks/context-session-stop.ts +2 -1
- package/plugins/sp/hooks/pi/guard-extension.ts +4 -3
- package/plugins/sp/hooks/task-write-guard.ts +4 -3
- package/plugins/sp/lib/idea-handoff.generated.mjs +260 -260
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/daily-summary/daily-summary.mjs +13 -4
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +6 -4
- package/plugins/sp/scripts/feature-sync-bounded.mjs +10 -2
- package/plugins/sp/scripts/feature-sync-bounded.ts +2 -1
- package/plugins/sp/scripts/idea-handoff.mjs +6 -1
- package/plugins/sp/scripts/idea-handoff.ts +4 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +1 -1
- package/plugins/sp/scripts/inline-run-setup.ts +185 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +8 -1
- package/plugins/sp/scripts/pr-reviewing.ts +2 -1
- package/plugins/sp/scripts/quality-gate.mjs +8 -1
- package/plugins/sp/scripts/quality-gate.ts +2 -1
- package/plugins/sp/scripts/surface-drift-inventory.ts +1 -4
- package/plugins/sp/scripts/task-evidence-precheck.ts +2 -1
- package/plugins/sp/scripts/task-size-precheck.ts +6 -4
- package/plugins/sp/scripts/verify-answer-lint.ts +2 -1
- package/plugins/sp/scripts/workflow-step-profile.mjs +10 -2
- package/plugins/sp/scripts/workflow-step-profile.ts +2 -1
- package/plugins/sp/scripts/wrapup-steps.mjs +8 -1
- package/plugins/sp/scripts/wrapup-steps.ts +2 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +8 -7
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +4 -5
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +2 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +59 -1
- package/schemas/state-machine-workflow.schema.json +5 -0
- package/schemas/transition-flow-workflow.schema.json +5 -0
- package/spur.js +20988 -20652
- package/web/_astro/BoardApp.CJiqp5pS.js +1 -0
- package/web/_astro/{BoardApp.yW425dRZ.js → BoardApp.yBBcFXWP.js} +4 -4
- package/web/_astro/{TaskDetail.CGwJAinW.js → TaskDetail.DqFJbRFc.js} +1 -1
- package/web/_astro/{arc.B-qNXzSO.js → arc.DL-BpHoi.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.Bdg-xiji.js → architectureDiagram-3BPJPVTR.9IdQYyDq.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DFArg3Kp.js → blockDiagram-GPEHLZMM.BKsFCqTl.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BkOLcjyx.js → c4Diagram-AAUBKEIU.DhwI0dh1.js} +1 -1
- package/web/_astro/channel.CX5453qQ.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.DN3c20V4.js → chunk-2J33WTMH.B3QVmQ9S.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.B64K0Ttd.js → chunk-4BX2VUAB.DBSuqs9F.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.C-AJvNwa.js → chunk-55IACEB6.BSYTWAYD.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.DMkr46uS.js → chunk-727SXJPM.cWVuxXfS.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.4_WGbI64.js → chunk-AQP2D5EJ.DpU_Ob3d.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.cbFW_lVE.js → chunk-FMBD7UC4.BykFkyji.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CDW_-2O1.js → chunk-ND2GUHAM.DwgHlMdY.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BoYOt_yg.js → chunk-QZHKN3VN.CusXUGWM.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.BNT6XpHQ.js → classDiagram-4FO5ZUOK.fx0ObzkN.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.BNT6XpHQ.js → classDiagram-v2-Q7XG4LA2.fx0ObzkN.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CI1DQxR3.js → cose-bilkent-S5V4N54A.Z4HgOlsd.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.A8ARH61p.js → cynefin-OW5HDTMX.B5dIZHJu.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.u28ZmqwR.js → dagre-BM42HDAG.DT70Q_Yw.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.Dx8JcrGc.js → diagram-2AECGRRQ.DqHA3XBF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.BXJUG9GY.js → diagram-5GNKFQAL.BmCem957.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.BtlMuWqW.js → diagram-KO2AKTUF.sn0-hrE0.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.C4T7qaAy.js → diagram-LMA3HP47.BSHe9tVc.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.D5HECE10.js → diagram-OG6HWLK6.DHIc-86k.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.B_hMR3yw.js → erDiagram-TEJ5UH35.Bxayrs7v.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BAmpcYl3.js → flowDiagram-I6XJVG4X.BkzoE_5I.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DV1bSWK-.js → ganttDiagram-6RSMTGT7.okT6CvTo.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.DxYKkKrJ.js → gitGraphDiagram-PVQCEYII.CJuYbhC7.js} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.BAWY2xMb.js → infoDiagram-5YYISTIA.RqLy7nBo.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.CZssRn6V.js → ishikawaDiagram-YF4QCWOH.BwIcoagw.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.C--muARd.js → journeyDiagram-JHISSGLW.UB1VbWtH.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.D_QCK4et.js → kanban-definition-UN3LZRKU.AaxMKpTk.js} +1 -1
- package/web/_astro/{linear.DzrmTtZ0.js → linear.Nv_xOUjP.js} +1 -1
- package/web/_astro/{mermaid.core.Da03W3iu.js → mermaid.core.Bc4LqQgX.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.6cy-8hR_.js → mindmap-definition-RKZ34NQL.oKUvU_qi.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C5rS1pdU.js → pieDiagram-4H26LBE5.DQk0oo03.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.w56GZZ6Q.js → quadrantDiagram-W4KKPZXB.BdDjESDa.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.CipX3Pwu.js → requirementDiagram-4Y6WPE33.C2u9hUeH.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.C0VVzgJm.js → sankeyDiagram-5OEKKPKP.CDEoiJST.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.BX2dUUbF.js → sequenceDiagram-3UESZ5HK.D_hT_GAT.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.ypCdgODQ.js → stateDiagram-AJRCARHV.DI8RYG0b.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.In0baEtg.js → stateDiagram-v2-BHNVJYJU.Bkxz4DnP.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.CJN4Vkvl.js → timeline-definition-PNZ67QCA.DSY-kH3-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.Cf8KkIPY.js → vennDiagram-CIIHVFJN.CpaDtuGr.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DCZBo9xw.js → wardleyDiagram-YWT4CUSO.DujQWvo8.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.Cm4v_MiJ.js → xychartDiagram-2RQKCTM6.DcM5Y4b9.js} +1 -1
- package/web/index.html +1 -1
- package/config/workflows/basic.yaml +0 -146
- package/config/workflows/docs-pipeline.yaml +0 -350
- package/config/workflows/feature-dev.yaml +0 -288
- package/plugins/sp/scripts/feature-dev-precheck.mjs +0 -146
- package/plugins/sp/scripts/feature-dev-precheck.ts +0 -238
- package/web/_astro/BoardApp.CHenHFia.js +0 -1
- package/web/_astro/channel.CbDHK5UQ.js +0 -1
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
import { spawnSync } from "child_process";
|
|
6
6
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
7
7
|
import { join } from "path";
|
|
8
|
+
|
|
9
|
+
// ../ts-libs/packages/utils/dist/env.js
|
|
10
|
+
function getEnvVars() {
|
|
11
|
+
return process.env;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// plugins/sp/scripts/wrapup-steps.ts
|
|
8
15
|
function jqPick(...values) {
|
|
9
16
|
for (const value of values) {
|
|
10
17
|
if (value !== null && value !== undefined && value !== false)
|
|
@@ -319,7 +326,7 @@ function runFeatureTransition(env, options = {}) {
|
|
|
319
326
|
return { status: syncStatus, statusFile: relStatusFile, exitCode: 0 };
|
|
320
327
|
}
|
|
321
328
|
var WRAPUP_STEPS_USAGE = "usage: wrapup-steps.ts <resolve|metrics|feature-transition> (env: __runId, tasks, feature, featureGateCmd, spurBin)";
|
|
322
|
-
function main(argv, env =
|
|
329
|
+
function main(argv, env = getEnvVars(), options = {}) {
|
|
323
330
|
const sub = argv[0];
|
|
324
331
|
if (sub === "resolve")
|
|
325
332
|
return resolveTasks(env, options).exitCode;
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
import { spawnSync } from 'node:child_process';
|
|
32
32
|
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
33
33
|
import { join } from 'node:path';
|
|
34
|
+
import { getEnvVars } from '@gobing-ai/ts-utils';
|
|
34
35
|
|
|
35
36
|
export interface WrapupStepsEnv {
|
|
36
37
|
__runId?: string;
|
|
@@ -449,7 +450,7 @@ export function runFeatureTransition(env: WrapupStepsEnv, options: WrapupStepsOp
|
|
|
449
450
|
export const WRAPUP_STEPS_USAGE =
|
|
450
451
|
'usage: wrapup-steps.ts <resolve|metrics|feature-transition> (env: __runId, tasks, feature, featureGateCmd, spurBin)';
|
|
451
452
|
|
|
452
|
-
export function main(argv: string[], env: WrapupStepsEnv =
|
|
453
|
+
export function main(argv: string[], env: WrapupStepsEnv = getEnvVars(), options: WrapupStepsOptions = {}): number {
|
|
453
454
|
const sub = argv[0];
|
|
454
455
|
if (sub === 'resolve') return resolveTasks(env, options).exitCode;
|
|
455
456
|
if (sub === 'metrics') {
|
|
@@ -62,7 +62,7 @@ ordered guards, and may loop back on itself (e.g. implement → check → fix
|
|
|
62
62
|
| Node typing | none (states are untyped) | `type: action\|gate\|parallel\|decision` |
|
|
63
63
|
| Required keys | `name, initialState, states, transitions` | `kind, name, initialNode, nodes, edges` |
|
|
64
64
|
| `kind` field | optional (defaults to state-machine) | **required** — `kind: transition-flow` |
|
|
65
|
-
| Canonical example | implement→check→fix loop (`
|
|
65
|
+
| Canonical example | implement→check→fix loop (`task-pipeline.yaml` — quality-gate hop with bounded fixall) | read→validate→transform→write pipeline |
|
|
66
66
|
|
|
67
67
|
**Heuristic:** loops / retries / one-active-state → **state-machine**; pipeline / fan-out / action-per-node → **transition-flow**.
|
|
68
68
|
|
|
@@ -95,7 +95,7 @@ Use this skill to:
|
|
|
95
95
|
|
|
96
96
|
The skill's logic divides by **whether the LLM adds value**:
|
|
97
97
|
|
|
98
|
-
- **Direct CLI** (`validate`, `run`, `list`, `trace`, `continue`, `cancel`, `clean`) — deterministic,
|
|
98
|
+
- **Direct CLI** (`validate`, `run`, `list`, `trace`, `progress`, `continue`, `cancel`, `clean`) — deterministic,
|
|
99
99
|
single-verb commands. Run them straight. A slash-command wrapper would only forward flags and add
|
|
100
100
|
drift; **there is no command for these — use the CLI**. The skill still drives them in natural
|
|
101
101
|
language (interpreting a failed validate, reading a run trace).
|
|
@@ -113,6 +113,7 @@ The skill's logic divides by **whether the LLM adds value**:
|
|
|
113
113
|
| `clean` | `spur workflow clean` (CLI) | `[--older-than <min>] [--force] [--logs] [--dry-run]` | Bulk-finalize stale `running`/`pending` runs as failed **and** reclaim retained run logs older than `workflow.logRetentionDays` (30d default) |
|
|
114
114
|
| `list` | `spur workflow list` (CLI) | — | Available workflow **YAML definition files** (not run records) |
|
|
115
115
|
| `trace` | `spur workflow trace` (CLI) | `[run-id] [--workflow <n>] [--status <s>] [--since <iso>] [--last <n>] [--follow] [--poll <ms>] [--output]` | Run history list or per-run timeline |
|
|
116
|
+
| `progress` | `spur workflow progress` (CLI) | `<run-id>` | The `projectWorkflowProgress` projection for that run — current state, per-action attempts, candidate next transitions, diagnostics. Read-only; the verb renders, `packages/app` derives. Unknown run id exits 1 with `Run <id> not found.` |
|
|
116
117
|
| `add` | agent procedure | `"<nl-description>" [--kind <state-machine\|transition-flow>] [--file <path>]` | **Mode chosen (confirmed)** → first reconciled against existing workflows (extend an existing flow rather than duplicate) → YAML authored in real schema shape → **validated AND dry-run** (reaches the expected terminal state) → [add](workflows/operations.md#add) |
|
|
117
118
|
| `refine` | agent procedure | `<workflow-file> [--intent "<goal>"] [--dry-run]` | Smallest change meeting the intent, re-validated and re-dry-run; `--dry-run` emits a diff only → [refine](workflows/operations.md#refine) |
|
|
118
119
|
|
|
@@ -262,6 +263,7 @@ spur workflow cancel <run-id> [--json]
|
|
|
262
263
|
spur workflow clean [--older-than <minutes>] [--force] [--logs] [--dry-run] [--json]
|
|
263
264
|
spur workflow list [--json]
|
|
264
265
|
spur workflow trace [run-id] [--workflow <name>] [--status <s>] [--since <iso>] [--last <n>] [--follow] [--poll <ms>] [--output] [--json]
|
|
266
|
+
spur workflow progress <run-id> [--json]
|
|
265
267
|
```
|
|
266
268
|
|
|
267
269
|
### `show` - project a definition
|
|
@@ -359,7 +361,7 @@ the workflow's actions (`shell`, custom runners) do that; this skill builds and
|
|
|
359
361
|
(transition-flow) wins. Order the specific case before the fallback. Simple shell checks can use
|
|
360
362
|
`action-ok` before an unconditional retry edge; multi-condition gates prefer a **soft status-file
|
|
361
363
|
probe** (always exit 0) with ordered shell guards for PASS / FAIL / exhausted (see
|
|
362
|
-
`
|
|
364
|
+
`task-pipeline.yaml`'s quality-gate hop).
|
|
363
365
|
4. **`env.allow` is an allowlist.** `${env.X}` resolves only if `X` is listed under `env.allow`;
|
|
364
366
|
otherwise it resolves empty. A workflow that "loses" an environment value usually forgot to allow it.
|
|
365
367
|
5. **Extensions are fail-closed.** The CLI loads YAML-declared extension modules itself
|
|
@@ -400,10 +402,9 @@ the workflow's actions (`shell`, custom runners) do that; this skill builds and
|
|
|
400
402
|
custom action/guard runners, the trust-gated extension loader, and CLI-vs-library capability gaps.
|
|
401
403
|
- `@gobing-ai/ts-dual-workflow-engine` README — authoritative library reference (both drivers,
|
|
402
404
|
RunLifecycle, persistence, the full event map, every built-in capability).
|
|
403
|
-
- `
|
|
404
|
-
(status-file branching
|
|
405
|
-
|
|
406
|
-
verify, record) when you need the complete reliability pattern set.
|
|
405
|
+
- `task-pipeline.yaml` — the canonical state-machine implement→soft-check→fixall loop and
|
|
406
|
+
full production pipeline (status-file branching, `qualityGateMaxFixAttempts`, quality gate,
|
|
407
|
+
HITL, verify, record); copy real shapes from here.
|
|
407
408
|
|
|
408
409
|
## Platform Notes
|
|
409
410
|
|
|
@@ -573,8 +573,6 @@ invariants that keep the pipeline set coherent as new ones are added.
|
|
|
573
573
|
| `idea-pipeline.yaml` | Ideation + planning (vague idea or known slug → feature + AC + task batch) | `/sp:dev-idea`, `/sp:dev-plan` | `handoff`, `cancelled` |
|
|
574
574
|
| `task-pipeline.yaml` | Execution (one task → done) | `/sp:dev-run` | `done`, `failed` |
|
|
575
575
|
| `wrapup-pipeline.yaml` | Wrap-up (completed tasks → learning + metrics + doc-sync) | `/sp:dev-wrap`, `/sp:dev-wrapall` | `done`, `skipped` |
|
|
576
|
-
| `feature-dev.yaml` | Umbrella (brainstorm → plan → execute → feature-verify) | `/sp:dev-runall --feature <id>` (or `--tasks feature:<id>`) | `done`, `failed` |
|
|
577
|
-
| `basic.yaml` | Simple (generic implement/check/fix loop) | direct `spur workflow run` | `done`, `failed` |
|
|
578
576
|
| `feature-lifecycle.yaml` | Feature status FSM (entity lifecycle, not a phase pipeline) | `spur feature update` | `done`, `cancelled` |
|
|
579
577
|
| `task-lifecycle.yaml` | Task status FSM (entity lifecycle, not a phase pipeline) | `spur task update` | `done`, `cancelled` |
|
|
580
578
|
|
|
@@ -587,8 +585,9 @@ not replace them.
|
|
|
587
585
|
A pipeline may invoke another workflow through a command wrapper or `spur workflow run` **only at a
|
|
588
586
|
phase boundary** — it must NOT inline another pipeline's state graph. Concretely:
|
|
589
587
|
|
|
590
|
-
-
|
|
591
|
-
|
|
588
|
+
- The feature-level batch entry (`/sp:dev-runall --feature <id>`) dispatches `task-pipeline.yaml`
|
|
589
|
+
per task through the CLI command wrapper, not by inlining the task graph (feature roster →
|
|
590
|
+
execution boundary).
|
|
592
591
|
- `idea-pipeline.yaml`'s `handoff` state may output a command for the operator to run
|
|
593
592
|
`task-pipeline.yaml` (phase boundary: ideation → execution).
|
|
594
593
|
- `task-pipeline.yaml`'s `implement` state must NOT contain a nested state machine for
|
|
@@ -692,7 +691,7 @@ Field semantics (enforced by `parseCheckpointMetadata` / `checkpointStaleness`):
|
|
|
692
691
|
**Writer cadence (0784 R4).** There is exactly one canonical writer: the `task-pipeline` done
|
|
693
692
|
state's terminal checkpoint (`status: done`, real HEAD, run id from `$__runId`, and `$wbs`-expanded
|
|
694
693
|
artifact paths). It is a plain `shell` step — checkpoints are working memory, not CLI-gated corpus.
|
|
695
|
-
The `
|
|
694
|
+
The `wrapup-pipeline`, and `idea-pipeline` pipelines (plus the since-retired `feature-dev`) used to echo pseudo-checkpoints
|
|
696
695
|
("checkpoint: <workflow> done ...") that violated the canonical schema; those writers were removed
|
|
697
696
|
in 0784 — the persisted run row is the authoritative terminal record, and a non-canonical echo
|
|
698
697
|
cannot be resumed, routed, or reclaimed safely.
|
|
@@ -105,7 +105,7 @@ gate will reject the task without it). Use the normal `--section --from-file` co
|
|
|
105
105
|
**4. Force-done with an honest reason.**
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
|
|
108
|
+
spur task update <wbs> done --force-done --provenance-bypass \
|
|
109
109
|
--reason "<step> agent.run timed out at <N>s; recovered manually: lint clean, <suite> pass, sections authored by hand"
|
|
110
110
|
```
|
|
111
111
|
|
|
@@ -149,11 +149,11 @@ passed, so provenance denied first and Review L3 denied on the retry.
|
|
|
149
149
|
|
|
150
150
|
| # | Gate layer | Triggers denial when | Remediation |
|
|
151
151
|
|---|------------|----------------------|-------------|
|
|
152
|
-
| 1 | **Strict-core + verdict artifact** (`spur task check <wbs> --strict-core` + `done-transition-guard.ts`) | The strict-core check fails, or `.spur/run/<wbs>-verdict.json` is **missing** or has a non-PASS aggregate. **Missing artifact is a deny** (not a silent allow — closes the 0349 "done without verdict" class). The aggregate is recomputed from requirement/AC rows; the harsher of stored and computed wins. | Re-run `/sp:dev-verify <wbs>` until PASS (writes the artifact), or explicitly override with `spur task update <wbs> done --force-done --reason "<why>"`. Docs-only
|
|
152
|
+
| 1 | **Strict-core + verdict artifact** (`spur task check <wbs> --strict-core` + `done-transition-guard.ts`) | The strict-core check fails, or `.spur/run/<wbs>-verdict.json` is **missing** or has a non-PASS aggregate. **Missing artifact is a deny** (not a silent allow — closes the 0349 "done without verdict" class). The aggregate is recomputed from requirement/AC rows; the harsher of stored and computed wins. | Re-run `/sp:dev-verify <wbs>` until PASS (writes the artifact), or explicitly override with `spur task update <wbs> done --force-done --reason "<why>"`. Docs-only procedures meet the same layer: read-only measured verification
|
|
153
153
|
(answer file + `spur task verdict`) writes the standard `.spur/run/<wbs>-verdict.json` artifact
|
|
154
154
|
under proof-input digest bracketing; missing or non-PASS evidence is a refusal, never a synthetic
|
|
155
155
|
PASS stub. |
|
|
156
|
-
| 2 | **Provenance guard** (`lifecycle-adapter.ts`) | No pipeline-kind run link exists for `<wbs>`. | Run `/sp:dev-run <wbs>` through the full pipeline, use `/sp:dev-run <wbs> --mode implement --auto --next` for the explicit step chain, or record the audited bypass with `
|
|
156
|
+
| 2 | **Provenance guard** (`lifecycle-adapter.ts`) | No pipeline-kind run link exists for `<wbs>`. | Run `/sp:dev-run <wbs>` through the full pipeline, use `/sp:dev-run <wbs> --mode implement --auto --next` for the explicit step chain, or record the audited bypass with `--provenance-bypass` on `spur task update`. |
|
|
157
157
|
| 3 | **Review L3** (`task-check.ts`) | `### Review` is empty, placeholder-only, or lacks a populated P1–P4 findings table. | Run `/sp:dev-review <wbs>`; verify cannot write Review because of the Step 10 prohibition above. |
|
|
158
158
|
|
|
159
159
|
When the verdict is **PARTIAL/FAIL**, or any gate layer fails: stop as review-pending — surface
|
|
@@ -25,7 +25,11 @@ implements it; remove the entry when the corresponding kind is dropped from the
|
|
|
25
25
|
|
|
26
26
|
**Actions:** `shell` · `note` · `doctor.probe` · `file.read.into-var` · `hitl.confirm` · `agent.run` · `proof.fingerprint` · `run.artifact` · `command.gate`
|
|
27
27
|
|
|
28
|
-
**Guards (transitions):** `always` · `shell`
|
|
28
|
+
**Guards (transitions):** `always` · `shell` · `action-ok` · `contract-violation`
|
|
29
|
+
|
|
30
|
+
- `action-ok` — pass iff the prior action on this state/node succeeded (engine builtin).
|
|
31
|
+
- `contract-violation` — pass iff the prior `agent.run` result is a named contract violation
|
|
32
|
+
(`data.outcome === 'contract-violation'`, ADR-118); the report carries `contract` and `observed`.
|
|
29
33
|
|
|
30
34
|
## What this driver is
|
|
31
35
|
|
|
@@ -398,6 +402,60 @@ keep their exact content after the stamp prefix. This normalization is contractu
|
|
|
398
402
|
**bare local-clock stamps are prohibited** — a hand-appended `[stage 12:31]` form mixes timezones
|
|
399
403
|
in one file and makes the run unauditable (task 0726 mixed both forms).
|
|
400
404
|
|
|
405
|
+
## Structured trace emission (ADR-117, task 0868)
|
|
406
|
+
|
|
407
|
+
`.spur/run/<run-id>.log` is a human convenience, **not the record of truth**. A run's
|
|
408
|
+
observability is a property of the run, so the inline driver owes the same structured trace the
|
|
409
|
+
engine subprocess writes — and it owes it through the **same writer**, never a parallel
|
|
410
|
+
implementation. The shared writer is `WorkflowActionTraceWriter`
|
|
411
|
+
(`packages/app/src/workflow/action-trace.ts`): the same decorator the engine composition installs
|
|
412
|
+
around `DbWorkflowPersistenceAdapter`, so the two surfaces call one emission path and one run-row
|
|
413
|
+
closure path and cannot drift.
|
|
414
|
+
|
|
415
|
+
The driver reaches it through the existing run delegate (`$SETUP_SCRIPT`,
|
|
416
|
+
`plugins/sp/scripts/inline-run-setup.ts`) — no new entry point, no second resolution chain:
|
|
417
|
+
|
|
418
|
+
- **Every executed action** — after the action settles, whether it ran host-inline or via a native
|
|
419
|
+
subagent — append its provenance line as before, then record the boundary:
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
bun "$SETUP_SCRIPT" --action --run-id "$RUN_ID" --node <state-id> --kind <action-kind> \
|
|
423
|
+
--status <done|failed> --ok <true|false> --duration-ms <measured-ms>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`<state-id>` is the current YAML state id (the `node`), `<action-kind>` the YAML action kind
|
|
427
|
+
(`agent.run`, `shell`, `note`, `doctor.probe`, …). `--status` is `done` when the action settled
|
|
428
|
+
under its declared error policy and `failed` otherwise; `--duration-ms` is the wall clock the
|
|
429
|
+
driver measured around the action. This writes the `action_runs` row (node, kind, status, `ok`,
|
|
430
|
+
`duration_ms`, `run_id`) the engine would have written, so the run's rows are queryable by run id
|
|
431
|
+
(`spur workflow progress <run-id>`, `ActionRunDao`) without reading the text log.
|
|
432
|
+
|
|
433
|
+
- **At the run's declared terminal state** — before the driver reports the run complete, close the
|
|
434
|
+
row so a successful inline run is never left non-terminal for `spur workflow clean` to reap as
|
|
435
|
+
stale:
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
bun "$SETUP_SCRIPT" --close --run-id "$RUN_ID" --status <done|failed|paused>
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
`--status` is the declared terminal state's verdict, not a guess: a run that reached a terminal
|
|
442
|
+
state is `done`; a run halted by a failing action under its error policy is `failed`.
|
|
443
|
+
|
|
444
|
+
**Best-effort at the action boundary only (ADR-117).** An `--action` persistence failure is
|
|
445
|
+
recorded — the delegate appends a `trace-emission-failed` line to `.spur/run/<run-id>.log` and
|
|
446
|
+
prints `{"ok":false}` on stdout — and the run continues to its declared terminal state; the
|
|
447
|
+
delegate exits `0` for that outcome and the driver must never treat an emission failure as a run
|
|
448
|
+
failure, retry it in a loop, or substitute a hand-written row. The run-row closure (`--close`) is
|
|
449
|
+
bookkeeping, not trace emission, and is **not** best-effort: a missing run row or a persistence
|
|
450
|
+
failure exits `1` with `{"ok":false}` and a named error (a missing row also carries
|
|
451
|
+
`code:"RUN_NOT_FOUND"`), because a silently `running` row is exactly the stale state
|
|
452
|
+
`spur workflow clean` reaps as `failed`. Exit `2` means the invocation itself was malformed
|
|
453
|
+
(missing `--node`/`--kind`/`--status`/`--ok`, a miscased `--ok`, a missing or malformed
|
|
454
|
+
`--duration-ms`, or an unsafe run id) and must be corrected, not ignored.
|
|
455
|
+
|
|
456
|
+
Emission is not optional and not deferred: an inline run that skips it reintroduces the
|
|
457
|
+
1,011-untraced-runs gap ADR-117 exists to close.
|
|
458
|
+
|
|
401
459
|
Transition guards are not advisory. Execute the declared guard exactly, in order, with the same
|
|
402
460
|
resolved variables and artifacts. `--no-lifecycle` remains bookkeeping only; the YAML's task checks,
|
|
403
461
|
verdict gate, record step, and done guard all remain authoritative.
|
|
@@ -161,6 +161,11 @@
|
|
|
161
161
|
"options": {
|
|
162
162
|
"type": "object",
|
|
163
163
|
"additionalProperties": true
|
|
164
|
+
},
|
|
165
|
+
"onError": {
|
|
166
|
+
"type": "string",
|
|
167
|
+
"enum": ["fail", "continue"],
|
|
168
|
+
"description": "Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so transition guards can route the outcome."
|
|
164
169
|
}
|
|
165
170
|
}
|
|
166
171
|
},
|
|
@@ -140,6 +140,11 @@
|
|
|
140
140
|
"options": {
|
|
141
141
|
"type": "object",
|
|
142
142
|
"additionalProperties": true
|
|
143
|
+
},
|
|
144
|
+
"onError": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": ["fail", "continue"],
|
|
147
|
+
"description": "Per-action error handling policy: 'fail' halts the run; 'continue' logs the failure and proceeds so edge conditions can route the outcome."
|
|
143
148
|
}
|
|
144
149
|
}
|
|
145
150
|
},
|