@gobing-ai/spur 0.3.99 → 0.4.0

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 (106) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/config.global.yaml +17 -0
  3. package/config/decisions/task-pipeline.yaml +55 -0
  4. package/config/plugin-scripts.json +10 -0
  5. package/config/rules/boundary/sp-runtime-path.yaml +2 -0
  6. package/config/rules/quality/coverage-gate.yaml +5 -3
  7. package/config/rules/strict/runtime-boundaries.yaml +11 -0
  8. package/config/rules/structure/protected-files.yaml +3 -0
  9. package/config/workflows/task-pipeline.yaml +178 -18
  10. package/package.json +9 -9
  11. package/plugins/sp/README.md +14 -1
  12. package/plugins/sp/agents/super-reviewer.md +25 -11
  13. package/plugins/sp/commands/dev-changelog.md +5 -4
  14. package/plugins/sp/commands/dev-review-session.md +12 -7
  15. package/plugins/sp/commands/dev-run.md +5 -2
  16. package/plugins/sp/commands/dev-runall.md +5 -2
  17. package/plugins/sp/hooks/agent-lifecycle.ts +155 -0
  18. package/plugins/sp/hooks/fleet-guest-stop.ts +180 -0
  19. package/plugins/sp/hooks/hooks.json +45 -1
  20. package/plugins/sp/hooks/pi/guard-extension.ts +21 -0
  21. package/plugins/sp/lib/history-anatomy.generated.mjs +5 -0
  22. package/plugins/sp/lib/idea-handoff.generated.mjs +34 -9
  23. package/plugins/sp/lib/inline-run.generated.d.mts +1 -0
  24. package/plugins/sp/lib/inline-run.generated.mjs +49 -19
  25. package/plugins/sp/lib/transcript.ts +160 -0
  26. package/plugins/sp/plugin.json +1 -1
  27. package/plugins/sp/scripts/history-anatomy-cache.mjs +5 -0
  28. package/plugins/sp/scripts/inline-run-setup.mjs +21 -20
  29. package/plugins/sp/scripts/inline-run-setup.ts +25 -31
  30. package/plugins/sp/scripts/residual-scan.mjs +2 -7
  31. package/plugins/sp/scripts/residual-scan.ts +7 -8
  32. package/plugins/sp/scripts/run-summary.mjs +286 -0
  33. package/plugins/sp/scripts/run-summary.ts +241 -0
  34. package/plugins/sp/scripts/session-timeline.mjs +234 -0
  35. package/plugins/sp/scripts/session-timeline.ts +152 -0
  36. package/plugins/sp/skills/code-verification/SKILL.md +5 -0
  37. package/plugins/sp/skills/fleet-join/SKILL.md +63 -0
  38. package/plugins/sp/skills/session-review/SKILL.md +46 -24
  39. package/plugins/sp/skills/spur-cli/SKILL.md +1 -0
  40. package/plugins/sp/skills/spur-cli/references/agent.md +108 -6
  41. package/plugins/sp/skills/spur-cli/references/decision.md +97 -0
  42. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +22 -0
  43. package/plugins/sp/skills/spur-composer/SKILL.md +27 -1
  44. package/plugins/sp/skills/spur-dev/references/dev-operations.md +28 -16
  45. package/plugins/sp/skills/spur-dev/references/execution-batch.md +64 -7
  46. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +14 -0
  47. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +16 -4
  48. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +32 -7
  49. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +6 -0
  50. package/schemas/decision-catalog.schema.json +226 -0
  51. package/schemas/spur-config.schema.json +25 -0
  52. package/spur.js +7440 -2424
  53. package/web/_astro/BoardApp.Bzr4OXrW.js +324 -0
  54. package/web/_astro/{BoardApp.i4eh_fHA.js → BoardApp.VeoxxLBy.js} +1 -1
  55. package/web/_astro/{TaskDetail.C5Cu8LdB.js → TaskDetail.LAyR_Pvn.js} +1 -1
  56. package/web/_astro/{arc.Bu5XpBEz.js → arc.f4e0OYLg.js} +1 -1
  57. package/web/_astro/{architectureDiagram-3BPJPVTR.9vHQTvhF.js → architectureDiagram-3BPJPVTR.SSIvxi-Z.js} +1 -1
  58. package/web/_astro/{blockDiagram-GPEHLZMM.Cn2Xl7D6.js → blockDiagram-GPEHLZMM.DSXIHOFf.js} +1 -1
  59. package/web/_astro/{c4Diagram-AAUBKEIU.7o0P_QDo.js → c4Diagram-AAUBKEIU.DG9Ubu85.js} +1 -1
  60. package/web/_astro/channel.CUFdtWhm.js +1 -0
  61. package/web/_astro/{chunk-2J33WTMH.C3zZFsNt.js → chunk-2J33WTMH.C7QU88Qh.js} +1 -1
  62. package/web/_astro/{chunk-4BX2VUAB.CNy_M7fO.js → chunk-4BX2VUAB.26Z94xBj.js} +1 -1
  63. package/web/_astro/{chunk-55IACEB6.2TiPnLBL.js → chunk-55IACEB6.DYRiBkqw.js} +1 -1
  64. package/web/_astro/{chunk-727SXJPM.5CGSyKAp.js → chunk-727SXJPM.D5Vfv5pe.js} +1 -1
  65. package/web/_astro/{chunk-AQP2D5EJ.w-ZIgfsK.js → chunk-AQP2D5EJ.DXHV47bN.js} +1 -1
  66. package/web/_astro/{chunk-FMBD7UC4.BkcEyhKa.js → chunk-FMBD7UC4.D1suAfOs.js} +1 -1
  67. package/web/_astro/{chunk-ND2GUHAM.mxKKbBG4.js → chunk-ND2GUHAM.D6BmdHEY.js} +1 -1
  68. package/web/_astro/{chunk-QZHKN3VN.cyA0z9aT.js → chunk-QZHKN3VN.rnPU-Ak-.js} +1 -1
  69. package/web/_astro/{classDiagram-4FO5ZUOK.CqtUzwhX.js → classDiagram-4FO5ZUOK.CvEfXIo1.js} +1 -1
  70. package/web/_astro/{classDiagram-v2-Q7XG4LA2.CqtUzwhX.js → classDiagram-v2-Q7XG4LA2.CvEfXIo1.js} +1 -1
  71. package/web/_astro/{cose-bilkent-S5V4N54A.BExPTopI.js → cose-bilkent-S5V4N54A.DkMisLSm.js} +1 -1
  72. package/web/_astro/{cynefin-OW5HDTMX.Bq2i10Cn.js → cynefin-OW5HDTMX.C77Q-pF6.js} +1 -1
  73. package/web/_astro/{dagre-BM42HDAG.By_HsOuv.js → dagre-BM42HDAG.YaV8ce27.js} +1 -1
  74. package/web/_astro/{diagram-2AECGRRQ.BtU0b7hz.js → diagram-2AECGRRQ.CUyGEKge.js} +1 -1
  75. package/web/_astro/{diagram-5GNKFQAL.D00ztMdT.js → diagram-5GNKFQAL.CRgd8dgj.js} +1 -1
  76. package/web/_astro/{diagram-KO2AKTUF.DMVJWaUN.js → diagram-KO2AKTUF.Bmzys9hq.js} +1 -1
  77. package/web/_astro/{diagram-LMA3HP47.Cxqrjg5-.js → diagram-LMA3HP47.BvmJY4Lw.js} +1 -1
  78. package/web/_astro/{diagram-OG6HWLK6.2lz_1B5h.js → diagram-OG6HWLK6.0hEhD30d.js} +1 -1
  79. package/web/_astro/{erDiagram-TEJ5UH35.BVQEuJ3T.js → erDiagram-TEJ5UH35.Bjt8lrnm.js} +1 -1
  80. package/web/_astro/{flowDiagram-I6XJVG4X.Qlyo90ky.js → flowDiagram-I6XJVG4X.CJZTjRDV.js} +1 -1
  81. package/web/_astro/{ganttDiagram-6RSMTGT7.DRwb8HHZ.js → ganttDiagram-6RSMTGT7._VqoVafc.js} +1 -1
  82. package/web/_astro/{gitGraphDiagram-PVQCEYII.YfoPthfS.js → gitGraphDiagram-PVQCEYII.CEDb7tVo.js} +1 -1
  83. package/web/_astro/index.Dg_3bOaJ.css +1 -0
  84. package/web/_astro/{infoDiagram-5YYISTIA.DvFREck1.js → infoDiagram-5YYISTIA.CgwifPpK.js} +1 -1
  85. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BzCj9Q0-.js → ishikawaDiagram-YF4QCWOH.B99wx2J1.js} +1 -1
  86. package/web/_astro/{journeyDiagram-JHISSGLW.BDMT_AFb.js → journeyDiagram-JHISSGLW.2hRwJbEo.js} +1 -1
  87. package/web/_astro/{kanban-definition-UN3LZRKU.D6Fh3gj9.js → kanban-definition-UN3LZRKU.BahJkKNC.js} +1 -1
  88. package/web/_astro/{linear.Dxw00fGQ.js → linear.DguUUe6V.js} +1 -1
  89. package/web/_astro/{mermaid.core.CsoxUWa0.js → mermaid.core.CvgfmqVr.js} +4 -4
  90. package/web/_astro/{mindmap-definition-RKZ34NQL.CN8oeHLu.js → mindmap-definition-RKZ34NQL.B3qEA3x9.js} +1 -1
  91. package/web/_astro/{pieDiagram-4H26LBE5.C7ADqQ_7.js → pieDiagram-4H26LBE5.FlWA-_ru.js} +1 -1
  92. package/web/_astro/{quadrantDiagram-W4KKPZXB.Cw9lKyHP.js → quadrantDiagram-W4KKPZXB.9bVn35X7.js} +1 -1
  93. package/web/_astro/{requirementDiagram-4Y6WPE33.B1ni-z4q.js → requirementDiagram-4Y6WPE33.ChykIhct.js} +1 -1
  94. package/web/_astro/{sankeyDiagram-5OEKKPKP.BhexdjVr.js → sankeyDiagram-5OEKKPKP.Z2Y3hkYb.js} +1 -1
  95. package/web/_astro/{sequenceDiagram-3UESZ5HK.C3Rm7dpQ.js → sequenceDiagram-3UESZ5HK.J7JsHWDt.js} +1 -1
  96. package/web/_astro/{stateDiagram-AJRCARHV.CkuMt27u.js → stateDiagram-AJRCARHV.DAPbiCSS.js} +1 -1
  97. package/web/_astro/{stateDiagram-v2-BHNVJYJU.Dc_aazUA.js → stateDiagram-v2-BHNVJYJU.D2jvSi0q.js} +1 -1
  98. package/web/_astro/{timeline-definition-PNZ67QCA.ja7sUFhH.js → timeline-definition-PNZ67QCA.psW2ci29.js} +1 -1
  99. package/web/_astro/{vennDiagram-CIIHVFJN.BxIshX_K.js → vennDiagram-CIIHVFJN.DlILYVmg.js} +1 -1
  100. package/web/_astro/{wardleyDiagram-YWT4CUSO.DfHlC0sh.js → wardleyDiagram-YWT4CUSO.xNWwLJnn.js} +1 -1
  101. package/web/_astro/{xychartDiagram-2RQKCTM6.DSnhHwCh.js → xychartDiagram-2RQKCTM6.EU_BuH7V.js} +1 -1
  102. package/web/board-runtime.json +1 -1
  103. package/web/index.html +2 -2
  104. package/web/_astro/BoardApp.BVp-LYi6.js +0 -322
  105. package/web/_astro/channel.6IFIKBhu.js +0 -1
  106. package/web/_astro/index.CbNz17Sx.css +0 -1
@@ -7,7 +7,7 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "sp",
10
- "version": "0.3.99",
10
+ "version": "0.4.0",
11
11
  "source": "./plugins/sp"
12
12
  }
13
13
  ]
@@ -149,3 +149,20 @@ agent:
149
149
  # extra workflow folders by concatenating them here (loader merge):
150
150
  workflows:
151
151
  paths: []
152
+
153
+ # Decision catalogs (feature P / ADR-134): the project layer is always
154
+ # `<cwd>/.spur/decisions` and the shared layer is the installed package's own
155
+ # `config/decisions`, so no config entry is needed to discover the shipped
156
+ # catalogs. `paths` registers extra catalog folders (absolute or
157
+ # project-relative); the first layer wins per file basename (ADR-113 style).
158
+ # `maker` selects the default DecisionMaker for every decision point, and
159
+ # `makers` overrides it per decision id. Built-in makers: typesafe, fm-local,
160
+ # laya-local (laya-local needs Apple Silicon). An unregistered name is a config
161
+ # error, never a silent fallback. Inspect the effective choice with
162
+ # `spur decision status`. `init` never overwrites this file — until you add the
163
+ # keys, the shipped catalog's maker applies (see `status`).
164
+ decisions:
165
+ paths: []
166
+ maker: typesafe
167
+ # makers:
168
+ # task-triage: laya-local
@@ -0,0 +1,55 @@
1
+ $schema: "@gobing-ai/spur/schemas/decision-catalog.schema.json"
2
+ # Decision catalogs for the task pipeline (feature P / task 1092, ADR-134).
3
+ #
4
+ # These entries mirror the inline decide actions that ship in
5
+ # config/workflows/task-pipeline.yaml today — same questions, choices and
6
+ # fallbacks — so their reliability can be measured with `spur decision run`
7
+ # before feature P1 migrates the workflow actions onto them (design §3.5).
8
+ # No workflow references this catalog yet.
9
+ #
10
+ # Resolution: this file ships in the shared layer (the installed package's
11
+ # config/decisions/). A project can override it per basename through
12
+ # .spur/decisions/ or decisions.paths (first layer wins, ADR-113 style).
13
+ version: 1
14
+
15
+ defaults:
16
+ # ADR-125 value, kept over the upstream 0.7 default.
17
+ minConfidence: 0.8
18
+
19
+ decisions:
20
+ task-triage:
21
+ type: choice
22
+ description: Which verification lane does a green-gate diff deserve?
23
+ parameters:
24
+ wbs:
25
+ type: string
26
+ description: Task WBS the diff belongs to.
27
+ criteria:
28
+ low: Small, contained diff — the fast lane is enough.
29
+ standard: Ordinary diff — the standard verification lane applies.
30
+ high: Broad or risky diff — verify with high caution.
31
+ fallback: standard
32
+
33
+ failure-class:
34
+ type: choice
35
+ description: Is a failed quality gate fixable by the repair agent, or should the run stop?
36
+ parameters:
37
+ wbs:
38
+ type: string
39
+ description: Task WBS whose gate failed.
40
+ criteria:
41
+ fix: The failure looks fixable — send it to the repair agent.
42
+ stop: The failure is not mechanically fixable — stop the run for the operator.
43
+ fallback: fix
44
+
45
+ review-failure-class:
46
+ type: choice
47
+ description: Is a non-PASS review fixable by the repair agent, or should the run stop?
48
+ parameters:
49
+ wbs:
50
+ type: string
51
+ description: Task WBS whose review did not certify PASS.
52
+ criteria:
53
+ fix: The findings look fixable — send them to the repair agent.
54
+ stop: The findings are not mechanically fixable — stop the run for the operator.
55
+ fallback: fix
@@ -76,11 +76,21 @@
76
76
  "contract": "standard",
77
77
  "twin": "residual-scan.mjs"
78
78
  },
79
+ {
80
+ "rel": "run-summary.ts",
81
+ "contract": "standard",
82
+ "twin": "run-summary.mjs"
83
+ },
79
84
  {
80
85
  "rel": "script-root.ts",
81
86
  "contract": "standard",
82
87
  "twin": "script-root.mjs"
83
88
  },
89
+ {
90
+ "rel": "session-timeline.ts",
91
+ "contract": "standard",
92
+ "twin": "session-timeline.mjs"
93
+ },
84
94
  {
85
95
  "rel": "task-diffstat.ts",
86
96
  "contract": "standard",
@@ -24,6 +24,8 @@ exclude:
24
24
  # legitimately contains `config/...` documentation / self-references — not
25
25
  # runtime paths.
26
26
  - "apps/cli/config/**"
27
+ # Desktop stage copies the same generated build-time asset payload beside each binary.
28
+ - "apps/desktop/resources/**"
27
29
  rules:
28
30
  - id: sp-runtime-path
29
31
  description: >
@@ -2,9 +2,11 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
2
2
  # Coverage gate — per-file line coverage meets threshold from Bun's lcov output.
3
3
  # Absorbed from ts-libs/.spur/rules/quality/coverage-gate.yaml, re-scoped to
4
4
  # Spur's monorepo layout:
5
- # - lcovPath kept at .coverage/lcov.info (Spur's `bun run test:coverage` —
6
- # what `bun run check` and the `*:full` chains run — writes coverage there
7
- # via --coverage-dir=.coverage; plain `bun run test` skips coverage)
5
+ # - lcovPath kept at .coverage/lcov.info (Spur's `bun run test:coverage`
6
+ # writes it via --coverage-dir=.coverage, and `bunfig.toml
7
+ # [test] coverage = true` means a plain `bun run test` writes the same
8
+ # artifact — so a TARGETED `bun test <file>` overwrites it with a partial
9
+ # tracefile, and this rule then judges that partial data)
8
10
  # - include expanded to apps/** + packages/** (Spur tests cover both;
9
11
  # ts-libs only covers packages/**)
10
12
  # - threshold kept at 90 matching bunfig.toml coverageThreshold
@@ -32,6 +32,10 @@ rules:
32
32
  - "**/tests/**"
33
33
  - "**/*.test.ts"
34
34
 
35
+ # Electron Node adapter: ts-runtime's streaming handle uses Bun.spawn.
36
+ # Owns the detached process-group handle needed for startup cancellation and quit.
37
+ - "apps/desktop/src/server-process.ts"
38
+
35
39
  # Low-level system primitives:
36
40
  - "packages/app/src/services/quality-gate.ts" # gate runs `sh -c` with stdout+stderr merged onto ONE fd; ProcessExecutor captures streams separately and cannot reproduce the stream-order contract (task 1006 R1; mirrors the history-anatomy bundling exemptions)
37
41
 
@@ -60,16 +64,23 @@ rules:
60
64
  - "packages/app/src/services/token-ledger-service.ts" # FD byte-window log tailing
61
65
  - "packages/app/src/services/token-ledger-watcher.ts" # node:fs watch() live watcher
62
66
  - "packages/app/src/services/project-registry.ts" # atomic projects.json persistence
67
+ - "packages/app/src/services/project-server-owner.ts" # atomic mkdir lifetime claim + unique-marker stale recovery; FileSystem has no exclusive mkdir primitive (1082)
63
68
  - "packages/app/src/services/slash-commands-service.ts" # synchronous ~/.config/spur/slash_commands.json persistence (mirrors project-registry.ts)
64
69
  - "packages/app/src/services/agent-usage-producer.ts" # atomic agent-usage snapshot write (tmp + rename, mirrors project-registry.ts; task 0892 R1)
65
70
  - "packages/app/src/services/history-service.ts" # versioned analyze artifact + bounded-errors sidecar + latest.json symlink pointer (task 0474); ts-runtime FileSystem seam has no symlink, so the pointer uses node:fs directly (mirrors project-registry.ts persistence exemption)
66
71
  - "packages/app/src/services/history-anatomy.ts" # deterministic history-anatomy cache core (task 1005 R2): fsync'd tmp+rename atomic publish, readdir digest scans and sync report reads must stay byte-stable; bundled standalone for the bare-node plugin twin (mirrors agent-usage-producer.ts / history-service.ts exemptions)
67
72
  - "packages/app/src/observability/workflow-run-log-sink.ts" # sync FD append for mid-run tail-able all-in-one run log (task 0426 / feature D2); append() is sync from the observability bus
73
+ - "packages/app/src/observability/agent-run-log.ts" # same primitive as the sink above for the per-run agent stream (task 1076 R1, ADR-132); append() is sync from the agent service's own onOutput hook, and the byte cap needs the FD position it tracks
68
74
  - "apps/cli/src/commands/workflow.ts" # FD byte-window tail of the mid-run run log for `workflow trace --follow` streaming (task 0428 / feature D2); readSync at offset over the observability sink's FDs
69
75
  - "apps/web/src/modules/discover.ts" # Vite/Astro module scanner fallback under bun test
70
76
  - "packages/app/src/services/quality-gate.ts" # gate artifacts (log/findings/receipt) written directly; merged-fd gate log and fsync-free atomic writes must stay byte-stable; bundled standalone for the bare-node plugin twin (task 1006 R1; mirrors history-anatomy.ts)
71
77
  - "packages/app/src/services/run-storage.ts" # durable-evidence migration core (task 1025 R4): atomic tmp+rename byte copies with digest reread and atomic manifest publish must stay byte-stable (mirrors agent-usage-producer.ts / project-registry.ts exemptions)
72
78
 
79
+ # Electron Node adapters cannot load Bun runtime implementations; keep the
80
+ # synchronous existence/directory probes injected for unit testing (desktop contract).
81
+ - "apps/desktop/src/layout.ts"
82
+ - "apps/desktop/src/server-process.ts"
83
+
73
84
  # Synchronous bootstrap & path resolution:
74
85
  - "packages/config/src/bundled-config.ts" # sync bundledConfigRoot() directory walk
75
86
  - "packages/config/src/loader.ts" # sync resolveConfigFile() / schema specifier lookup
@@ -37,6 +37,9 @@ rules:
37
37
  # this rule's include scope — scanning generated copies only adds noise
38
38
  # (e.g. `id: task-implement-transition` trips the sk- token shape).
39
39
  - "apps/cli/config/"
40
+ # Desktop ships the same generated config payload beside each compiled binary.
41
+ # Its source remains outside this source-code rule, just like the CLI bundle.
42
+ - "apps/desktop/resources/"
40
43
  # `apps/cli/plugins/` is the same kind of gitignored build:bundle output — a staged
41
44
  # npm copy of `plugins/`, itself outside the include scope. Minified generated libs
42
45
  # there trip the api-key shape (0976: HEAD's inline-run.generated.mjs fires too).
@@ -19,6 +19,21 @@
19
19
  # done guard closed, and re-records Testing before the failed edge); done settles
20
20
  # deferrals; failed renders the recovery report. No new state, edge, or model query.
21
21
  #
22
+ # Confidence gate (session finding after 1088, task 1068 follow-up): the verify answer has
23
+ # carried a `Confidence: HIGH|MEDIUM|LOW` line since 1068, and nothing read it — a PASS at
24
+ # LOW confidence certified exactly like HIGH. The verify stamp now records a `confidence`
25
+ # check row, and BOTH completion guards (verify → record, record → done) refuse a LOW (or
26
+ # absent) level unless the run was launched with `--vars '{"ackLowConfidence":"true"}'`.
27
+ # The acknowledgement is an operator decision, not a model one: it is the only way to
28
+ # certify a verdict the verifier itself would not stand behind.
29
+ #
30
+ # Review-failure routing (session finding after 1088): `review` had no outgoing edge for a
31
+ # FAIL verdict, so a failing review could only be remediated by driving the graph by hand
32
+ # (re-entering `test` and hand-emitting rows). The review stage now derives
33
+ # `.spur/run/<wbs>-review.status` from its own answer file (fail-closed to FAIL), and a FAIL
34
+ # routes through `review-fail-triage` — the review-side twin of `test-fail-triage` (0943) —
35
+ # into the SAME bounded fix budget, so remediation stays on-graph and bounded.
36
+ #
22
37
  # Vars (passed as a JSON object via `--vars`):
23
38
  # wbs — task WBS (required)
24
39
  # profile — "auto" skips HITL approve (R4)
@@ -36,7 +51,19 @@ kind: state-machine
36
51
  name: task-pipeline
37
52
  # 0772 R2: explicit identity tag. Set only after the proof failure-path tests
38
53
  # passed; the engine treats unversioned external definitions as supported.
39
- version: "3"
54
+ # v4 (session finding after 1088): the completion gate reads the verifier's confidence level and
55
+ # the graph routes a non-PASS review into bounded remediation — both are contract changes, so the
56
+ # identity moves with them.
57
+ # v5 (task 1077's inline run, 2026-10-06): the verify verdict action is explicitly `onError:
58
+ # continue`. `task verdict` exits non-zero on any non-PASS verdict BY DESIGN (1003 R2) — that is
59
+ # data for the verify guards, not a state failure. Under the engine's default 'fail' policy
60
+ # (`resolveOnErrorPolicy: action ?? workflowDefault ?? runOption ?? 'fail'`) the state sequence
61
+ # halted on that exit code and `lifecycle.fail('verify')` finalized the run before any transition
62
+ # guard was evaluated, which made the declared `verify → test-fix` "repairable non-PASS" lane
63
+ # UNREACHABLE: a non-PASS verify could only end the run failed. `test-fix` also gained the
64
+ # review-lane evidence projection (see its onEnter) so the repair hop is not fed an empty findings
65
+ # list when the failing hop was `review-fail-triage` rather than the quality gate.
66
+ version: "5"
40
67
  description: "Standard task pipeline: precheck → implement → quality-gate (test/fix/recheck) → review → approve → verify → record → done"
41
68
  # Task entity lifecycle (owned by task-lifecycle.yaml):
42
69
  # normal: backlog → todo → wip → testing → done
@@ -149,6 +176,14 @@ vars:
149
176
  # Escalation counter: .spur/run/<wbs>-escalation-count. Default 2 = two answered
150
177
  # questions; a third pause routes to failed with a report note.
151
178
  maxEscalations: "2"
179
+ # Operator acknowledgement of a LOW-confidence certification (session finding after 1088).
180
+ # The verify answer's `Confidence:` line is captured into the verdict artifact; a LOW (or
181
+ # absent) level fails the completion guards unless this is "true", because a PASS the
182
+ # verifier would not stand behind is an operator risk decision, not a mechanical one.
183
+ # Set per run: `--vars '{"ackLowConfidence":"true"}'` (and export it on the inline path).
184
+ # Deliberately NOT settable from the task file or the verifier's own answer: the point is
185
+ # that a second party, not the producer, accepts the residual uncertainty.
186
+ ackLowConfidence: ""
152
187
  # Runtime-written, 0933: the escalate hop's file.read.into-var fills this from
153
188
  # .spur/run/<wbs>-question.md; the hitl.input prompt below references it. Declared
154
189
  # here (empty) so the static var-reference validator sees the template source.
@@ -438,6 +473,17 @@ states:
438
473
  options:
439
474
  command: >-
440
475
  printf '%s\n' "$(( $(cat ".spur/run/$wbs-test-fix-attempt" 2>/dev/null || echo 0) + 1 ))" > ".spur/run/$wbs-test-fix-attempt"; [ -f ".spur/run/$wbs-verdict.json" ] && echo '--- verify verdict (remediation input, task 0703 R4) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$wbs-verdict.json" >> ".spur/run/$wbs-test-gate.log"; [ -f ".spur/run/$wbs-residuals.json" ] && echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$wbs-residuals.json" >> ".spur/run/$wbs-test-gate.log"; exit 0
476
+ # Review-lane input (v5, task 1077 run): `review-fail-triage` routes a non-PASS review
477
+ # into this same bounded repair hop, but it stages no review evidence — the fixer then
478
+ # received a GREEN gate log and an empty findings list, so the review finding it exists
479
+ # to repair was invisible to it. Project the reviewer's answer into the same log the
480
+ # other lanes use, and only on the review lane (the decision file exists only after
481
+ # `review-fail-triage`). Own action, not an append to the one above: ADR-115's 800-char
482
+ # shell cap is already 602 chars there.
483
+ - kind: shell
484
+ options:
485
+ command: >-
486
+ [ -f ".spur/run/$wbs-review-failure-class.decision" ] && [ -f ".spur/run/$__runId-review-answer.txt" ] && echo '--- review verdict (remediation input, review lane) ---' >> ".spur/run/$wbs-test-gate.log" && cat ".spur/run/$__runId-review-answer.txt" >> ".spur/run/$wbs-test-gate.log"; exit 0
441
487
  # R3 (0482): project the extracted gate anchors into a var so the dispatch input
442
488
  # can NAME the failing file:line, not merely point at a log. A vars template cannot
443
489
  # run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
@@ -611,10 +657,43 @@ states:
611
657
  # verify stamp marks review `completed` only when this marker equals the current digest;
612
658
  # otherwise `skipped` (an honest downgrade, never a fake completed), and the bound
613
659
  # `record` registration refuses a skipped review.
660
+ # Session finding after 1088: the review VERDICT is read straight out of the reviewer's
661
+ # own answer file by the review → * guards below, so this stage needs no extra artifact
662
+ # and no extra action (ADR-115 legibility cap).
614
663
  - kind: shell
615
664
  options:
616
665
  command: 'mkdir -p .spur/run; printf "%s" "$proofDigest" > ".spur/run/$__runId-review-proof.digest"; exit 0'
617
666
 
667
+ # ── review-fail-triage (session finding after 1088) ────────────────────────
668
+ # A review that reports FAIL used to have no outgoing edge: the graph could not see the
669
+ # verdict and nothing consumed it, so remediating a failing review meant driving the
670
+ # states by hand. This state is the review-side twin of `test-fail-triage` (0943 R3):
671
+ # the deterministic classifier routes the failure into the SAME bounded fix budget
672
+ # (`.spur/run/<wbs>-test-fix-attempt` against `qualityGateMaxFixAttempts`), and the fix
673
+ # re-enters quality → review → verify on a freshly captured digest. The `decide` action
674
+ # itself always runs (the engine has no onEnter conditionals); with
675
+ # `workflow.decideDecisionMaker` off it degrades to its declared default.
676
+ - id: review-fail-triage
677
+ description: >-
678
+ Deterministic router for a review that did NOT certify PASS (session finding after 1088).
679
+ `decide review-failure-class` reads the reviewer's answer and the task spec and routes:
680
+ fix → the shared test-fix hop, stop → failed with terminalReason failed-check. A
681
+ missing/corrupt decision fails closed to failed-check.
682
+ onEnter:
683
+ - kind: decide
684
+ options:
685
+ id: review-failure-class
686
+ method: choice
687
+ question: >-
688
+ The review did not certify PASS (FAIL or PARTIAL). Is the finding fixable by the
689
+ repair agent, or should the run stop here for the operator?
690
+ choices: [fix, stop]
691
+ default: fix
692
+ evidence:
693
+ - .spur/run/${vars.__runId}-review-answer.txt
694
+ - ${vars.taskSpecPath}
695
+ resultFile: .spur/run/${vars.wbs}-review-failure-class.decision
696
+
618
697
  - id: approve
619
698
  description: >
620
699
  Human-in-the-loop approval gate. Under `profile=auto` this state is never entered
@@ -675,8 +754,26 @@ states:
675
754
  # (d) `spur task verdict` owns the answer lint (task 1003 R2) — the shell below
676
755
  # fails closed when the verifier's answer is malformed, before any verdict artifact.
677
756
  - kind: shell
757
+ # `task verdict` exits 1 on a non-PASS verdict by design (1003 R2). The `continue`
758
+ # policy keeps that exit code as recorded evidence (the action row is still `failed`)
759
+ # while letting the state finish its remaining actions and reach the guards below;
760
+ # without it the default 'fail' policy halts the run here and `verify → test-fix`
761
+ # (the declared bounded remediation lane) can never fire (v5, task 1077 run).
762
+ onError: continue
678
763
  options:
679
764
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
765
+ # Session finding after 1088: the verifier's confidence level becomes a `confidence` check
766
+ # row (warn unless HIGH) and a gate-log line, so the level the completion guards enforce is
767
+ # visible in the artifact and the log — not only in the answer file. This is its own action
768
+ # because the proof-binding stamp below must stay the state's LAST action AND under the
769
+ # ADR-115 800-char shell cap.
770
+ - kind: shell
771
+ options:
772
+ command: >-
773
+ V=".spur/run/$wbs-verdict.json"; [ -f "$V" ] || exit 0;
774
+ jq --arg ack "$ackLowConfidence" '. + {checks: ((.checks // []) | map(select(.name != "confidence"))) + [{name: "confidence", status: (if (.confidence // "LOW") == "HIGH" then "pass" else "warn" end), evidence: ((.confidence // "LOW (absent from artifact)") + (if $ack == "true" then " (operator-acknowledged)" else "" end))}]}' "$V" > "$V.tmp" && mv "$V.tmp" "$V";
775
+ printf 'confidence: %s (ack=%s)\n' "$(jq -r '.confidence // "LOW (absent)"' "$V")" "$ackLowConfidence" >> ".spur/run/$wbs-test-gate.log";
776
+ exit 0
680
777
  # (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
681
778
  # 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
682
779
  - kind: shell
@@ -1018,21 +1115,73 @@ transitions:
1018
1115
  description: Failure-class decision missing/corrupt — stop at failed.
1019
1116
  guard:
1020
1117
  kind: always
1021
- # ── review → approve, OR skip the HITL gate entirely when profile=auto (R4) ──
1022
- # Declaration order matters: the auto-skip guard is tried FIRST, so under
1023
- # profile=auto the run routes straight to verify and never ENTERS approve
1024
- # (whose onEnter hitl.confirm would otherwise block). Otherwise fall through
1025
- # to approve for the human gate.
1118
+ # ── review-failure routing (session finding after 1088): the review-side twin of the
1119
+ # failure-class router above — stop first, then the shared attempt cap, then the fix lane,
1120
+ # then the fail-closed defense. The counter is the SAME one the quality-gate loop uses, so a
1121
+ # review FAIL cannot buy extra attempts and the iteration bound stays finite.
1122
+ - from: review-fail-triage
1123
+ to: failed
1124
+ terminalReason: failed-check
1125
+ description: Review failure class stop — the run terminates at failed, never bypassed.
1126
+ guard:
1127
+ kind: shell
1128
+ options:
1129
+ command: >-
1130
+ jq -e '.value == "stop"' ".spur/run/$wbs-review-failure-class.decision" >/dev/null 2>&1
1131
+ - from: review-fail-triage
1132
+ to: failed
1133
+ terminalReason: retry-exhausted
1134
+ description: Attempt cap reached — qualityGateMaxFixAttempts bounds the review repair lane.
1135
+ guard:
1136
+ kind: shell
1137
+ options:
1138
+ command: >-
1139
+ fix_attempts="$(cat .spur/run/$wbs-test-fix-attempt 2>/dev/null || echo 0)";
1140
+ test "$fix_attempts" -ge "$qualityGateMaxFixAttempts"
1141
+ - from: review-fail-triage
1142
+ to: test-fix
1143
+ description: Review failure class fix and under the cap — the shared bounded repair hop.
1144
+ guard:
1145
+ kind: shell
1146
+ options:
1147
+ command: >-
1148
+ jq -e '.value == "fix"' ".spur/run/$wbs-review-failure-class.decision" >/dev/null 2>&1
1149
+ # Defense: missing/corrupt review-failure decision — fail closed instead of silently repairing.
1150
+ - from: review-fail-triage
1151
+ to: failed
1152
+ terminalReason: failed-check
1153
+ description: Review-failure decision missing/corrupt — stop at failed.
1154
+ guard:
1155
+ kind: always
1156
+ # ── review routing: FAIL → bounded remediation; PASS → approve or the auto-skip (R4) ──
1157
+ # Declaration order matters and is FAIL-CLOSED: the two PASS edges each demand the reviewer's
1158
+ # own `Verdict: PASS` line, and the catch-all sends EVERYTHING ELSE (FAIL, a missing answer, an
1159
+ # unparseable one) into `review-fail-triage`. Before this, a FAIL review had no outgoing edge at
1160
+ # all — the graph could not see the verdict, so remediation meant driving states by hand
1161
+ # (session finding after 1088). The reviewer writes `Verdict: PASS|FAIL` in its answer; both
1162
+ # plain and bold forms are accepted. Under `profile=auto` the approve gate is skipped, so the
1163
+ # PASS+auto edge is tried first and the interactive PASS edge second.
1026
1164
  - from: review
1027
1165
  to: verify
1028
- description: profile=auto — skip the human approval gate, go straight to verify.
1166
+ description: profile=auto and the review certified PASS — skip the human approval gate.
1029
1167
  guard:
1030
1168
  kind: shell
1031
1169
  options:
1032
- command: 'test "$profile" = auto'
1170
+ command: >-
1171
+ test "$profile" = auto &&
1172
+ grep -qiE '^[[:space:]]*\**Verdict:\** *PASS' ".spur/run/$__runId-review-answer.txt"
1033
1173
  - from: review
1034
1174
  to: approve
1035
- description: Review done — gate on human approval.
1175
+ description: Review certified PASS — gate on human approval before verification.
1176
+ guard:
1177
+ kind: shell
1178
+ options:
1179
+ command: grep -qiE '^[[:space:]]*\**Verdict:\** *PASS' ".spur/run/$__runId-review-answer.txt"
1180
+ - from: review
1181
+ to: review-fail-triage
1182
+ description: >-
1183
+ No PASS in the reviewer's answer (FAIL, PARTIAL, missing, or unparseable — fail closed) —
1184
+ classify the failure and route it into the bounded repair hop instead of dead-ending the run.
1036
1185
  guard:
1037
1186
  kind: always
1038
1187
 
@@ -1069,19 +1218,23 @@ transitions:
1069
1218
  # The verify step emits .spur/run/<wbs>-verdict.json with a required proof block (task 0703 R3/R5).
1070
1219
  # Only `verdict: PASS` PLUS a proof block whose digest — top level and every named stage — equals
1071
1220
  # the captured `proofDigest` clears the gate to `record`; any non-PASS, a missing file, malformed
1072
- # JSON, or missing/mismatched proof evidence does not. Declaration order: PASS+proof guard FIRST,
1221
+ # JSON, or missing/mismatched proof evidence does not. The verifier's confidence level is part of
1222
+ # that certification (session finding after 1088): a PASS the verifier itself marked LOW — or left
1223
+ # unstated — clears the gate only when the operator accepted it with
1224
+ # `--vars '{"ackLowConfidence":"true"}'`. Declaration order: PASS+proof guard FIRST,
1073
1225
  # then the bounded remediation route (R4), then the always catch-all so a PASS verdict with a
1074
1226
  # missing/malformed proof block still terminates at `failed` instead of hanging the state.
1075
1227
  - from: verify
1076
1228
  to: record
1077
- description: Verification verdict is PASS and its proof block names the captured digest on every stage — record results and proceed to done.
1229
+ description: Verification verdict is PASS, its proof block names the captured digest on every stage, and any LOW confidence was operator-acknowledged — record results and proceed to done.
1078
1230
  guard:
1079
1231
  # (one jq -e predicate) PASS verdict; proof, quality-gate, review and verification digests
1080
- # equal to proofDigest; review completed; matching run id and definition digest (0703 R5, 0785 R4).
1232
+ # equal to proofDigest; review completed; matching run id and definition digest (0703 R5, 0785 R4);
1233
+ # confidence HIGH/MEDIUM, or LOW/absent with the operator's ack (session finding after 1088).
1081
1234
  kind: shell
1082
1235
  options:
1083
1236
  command: >-
1084
- jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" '
1237
+ jq -e --arg d "$proofDigest" --arg r "$__runId" --arg dd "$__definitionDigest" --arg ack "$ackLowConfidence" '
1085
1238
  .verdict == "PASS"
1086
1239
  and (.proof.digest // "") == $d
1087
1240
  and (.proof.stages.qualityGate.digest // "") == $d
@@ -1090,6 +1243,7 @@ transitions:
1090
1243
  and (.proof.stages.verification.digest // "") == $d
1091
1244
  and (.proof.runId // "") == $r
1092
1245
  and (.proof.definitionDigest // "") == $dd
1246
+ and ((.confidence // "LOW") != "LOW" or $ack == "true")
1093
1247
  ' ".spur/run/$wbs-verdict.json" >/dev/null 2>&1
1094
1248
  - from: verify
1095
1249
  to: test-fix
@@ -1117,11 +1271,12 @@ transitions:
1117
1271
  # ── done gate: record → done/failed gated on `spur task check` (ADR-026 amendment 2026-06-23)
1118
1272
  # PLUS the proof-block re-assertion (task 0703 R5): the verdict artifact must still be PASS and
1119
1273
  # still name the captured digest — a forged or mutated completion artifact fails closed here.
1274
+ # PLUS the confidence re-assertion (session finding after 1088): the same ack rule as verify →
1275
+ # record, re-read from the artifact so a mutation between the two boundaries cannot slip through.
1120
1276
  # Declaration order: pass guard first.
1121
1277
  - from: record
1122
1278
  to: done
1123
- description: Task check passed and the verdict proof block still names the captured digest — certify done.
1124
- # (warn) 5 commands: named verdict + proof digest reads after the task check (legibility, 0874).
1279
+ description: Task check passed, the verdict proof block still names the captured digest, and any LOW confidence was acknowledged — certify done.
1125
1280
  guard:
1126
1281
  kind: shell
1127
1282
  options:
@@ -1130,11 +1285,16 @@ transitions:
1130
1285
  # the CLI's own target-aware `--no-lifecycle` backstop (F92 R3). No `#`
1131
1286
  # comments inside the folded scalar: `>-` joins same-indent lines into
1132
1287
  # one shell line.
1288
+ # Two logical commands, deliberately (ADR-115): the `task check` projection plus
1289
+ # ONE jq predicate re-asserting the whole completion contract — PASS verdict, the
1290
+ # captured proof digest, and the confidence rule (session finding after 1088).
1133
1291
  command: >-
1134
1292
  $spurBin task check $wbs --as done &&
1135
- verdict="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)" &&
1136
- proof_digest="$(jq -r '.proof.digest // ""' .spur/run/$wbs-verdict.json 2>/dev/null)" &&
1137
- test "$verdict" = PASS && test "$proof_digest" = "$proofDigest"
1293
+ jq -e --arg p "$proofDigest" --arg ack "$ackLowConfidence" '
1294
+ .verdict == "PASS"
1295
+ and ((.proof.digest // "") == $p)
1296
+ and ((.confidence // "LOW") != "LOW" or $ack == "true")
1297
+ ' ".spur/run/$wbs-verdict.json" >/dev/null 2>&1
1138
1298
  - from: record
1139
1299
  to: failed
1140
1300
  terminalReason: failed-check
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobing-ai/spur",
3
- "version": "0.3.99",
3
+ "version": "0.4.0",
4
4
  "description": "Spur CLI — local-first harness for mainstream coding agents: constraint checking, workflow orchestration, agent health, and history analytics. Bun-native; exposes the `spur` command.",
5
5
  "keywords": [
6
6
  "spur",
@@ -57,14 +57,14 @@
57
57
  },
58
58
  "devDependencies": {
59
59
  "@commander-js/extra-typings": "^14.0.0",
60
- "@gobing-ai/ts-db": "^0.5.12",
61
- "@gobing-ai/ts-ai-runner": "^0.5.12",
62
- "@gobing-ai/ts-dual-workflow-engine": "^0.5.12",
63
- "@gobing-ai/ts-infra": "^0.5.12",
64
- "@gobing-ai/ts-llm-jsonl-importer": "^0.5.12",
65
- "@gobing-ai/ts-rule-engine": "^0.5.12",
66
- "@gobing-ai/ts-runtime": "^0.5.12",
67
- "@gobing-ai/ts-utils": "^0.5.12",
60
+ "@gobing-ai/ts-db": "^0.5.16",
61
+ "@gobing-ai/ts-ai-runner": "^0.5.16",
62
+ "@gobing-ai/ts-dual-workflow-engine": "^0.5.16",
63
+ "@gobing-ai/ts-infra": "^0.5.16",
64
+ "@gobing-ai/ts-llm-jsonl-importer": "^0.5.16",
65
+ "@gobing-ai/ts-rule-engine": "^0.5.16",
66
+ "@gobing-ai/ts-runtime": "^0.5.16",
67
+ "@gobing-ai/ts-utils": "^0.5.16",
68
68
  "@types/bun": "1.3.14",
69
69
  "@types/figlet": "^1.7.0",
70
70
  "@types/node-notifier": "8.0.5",
@@ -273,6 +273,7 @@ plugins/sp/
273
273
  ├── commands/ # Slash-command wrappers — the SSOT (hand-editable thin wrappers; see Commands below)
274
274
  ├── agents/ # 4 specialist subagents (expert-spur, super-coder, super-planner, super-reviewer)
275
275
  ├── hooks/ # hooks.json + task-write-guard.{ts,test.ts} + context-{session-start,post-tool,session-stop}.ts
276
+ │ # + agent-lifecycle.{ts,test.ts} + fleet-guest-stop.{ts,test.ts} (fleet member/guest hooks)
276
277
  │ # + careful-guard.{ts,test.ts} + context-hooks.test.ts + token-estimate.test.ts
277
278
  │ # + shared policy modules: agent-hint.ts, destructive-policy.{ts,test.ts}, task-file-policy.{ts,test.ts}
278
279
  │ # + pi/guard-extension.{ts,test.ts} (plugin.json `extensions.pi` entry point)
@@ -342,6 +343,7 @@ surface or run one workflow. All skills target the same five core platforms: `cl
342
343
  | `reverse-engineering` | 1.1 | Codebase analysis / HLD generation / audit — depth-driven reverse engineering with orthogonal mode, focus, and format controls; backs `/sp:dev-reverse` |
343
344
  | `issue-finding` | 2.0 | Session-log forensics — multi-source discovery, bottleneck ranking, optional topic focus, CLI-gated fix task generation; **legacy path** — superseded by `history-anatomy` for indexed reporting; backs no current command; directly invocable as sp:issue-finding |
344
345
  | `conflict-finding` | 1.0 | Authority-aware semantic audit — four-pillar (source/task/feature/authority) conflict discovery, claim-specific authority resolution, reproducible evidence, confirmed owner-routed remediation; backs `/sp:dev-find-conflict` |
346
+ | `fleet-join` | 1.0 | Guest fleet occupancy — join as a live guest occupant, loop `spur agent wait --inbox` to pull work, reply through `spur message reply`, then leave; G73 (task 1081) |
345
347
  | `next-feature` | 1.0 | Prompt-first feature frontier prioritizer — sync-first precondition, B3 actionability gate (cited, never restated), tiered rubric over measured signals, D1–D4 defect proposals conforming to the restructure map schema; backs `/sp:dev-find-next` |
346
348
  | `pr-reviewing` | 1.0 | GitHub Codex PR review — PR prepare/reuse, `@codex review` request with per-HEAD dedupe, bounded polling, findings normalization, validated fix + re-review; spine SSOT `pr-review.yaml` + `scripts/pr-reviewing.ts`; backs `/sp:dev-pr-review` |
347
349
  | `indexed-context` | 1.0 | Cross-agent project context — anatomy/learnings/pitfalls/buglog/memory in `.spur/context/`; hook-tracked token-ledger; graceful degradation on agents without hooks |
@@ -473,13 +475,16 @@ the agent provides an isolated context window.
473
475
  #### 4. Hooks (`hooks/`)
474
476
 
475
477
  Event-driven enforcement that runs automatically without user invocation. `hooks.json` registers
476
- four handlers:
478
+ six handlers across seven events:
477
479
 
478
480
  | Event | Matcher | Handler | Timeout |
479
481
  | -------------- | ------------------------------------- | ---------------------------------------------- | ------- |
480
482
  | `PreToolUse` | `Write\|Edit` | `superskill hook run sp task-write-guard` | 10s |
481
483
  | `PostToolUse` | `Bash\|Grep\|Glob\|Read\|Write\|Edit` | `superskill hook run sp context-post-tool` | 10s |
482
484
  | `SessionStart` | — | `superskill hook run sp context-session-start` | 15s |
485
+ | `SessionStart`, `UserPromptSubmit`, `Stop` | — | `superskill hook run sp agent-lifecycle` | 5s |
486
+ | `Notification` | `permission_prompt` | `superskill hook run sp agent-lifecycle` | 5s |
487
+ | `Stop` | — | `superskill hook run sp fleet-guest-stop` | 10s |
483
488
  | `SessionEnd` | — | `superskill hook run sp context-session-stop` | 15s |
484
489
 
485
490
  **Write guard.** The `PreToolUse` hook fires on every `Write`/`Edit` tool call and checks whether
@@ -493,6 +498,11 @@ estimates the token cost of each matched tool call and appends it to `.spur/cont
493
498
  (with redaction of sensitive argument fields), `context-session-start` seeds the indexed-context
494
499
  hint on first launch, and `context-session-stop` closes out the session record.
495
500
 
501
+ **Fleet hooks (1080/1081).** `agent-lifecycle` reports member state in the background via
502
+ `spur agent report --state working|idle|blocked` (a permission prompt is `blocked`) — only when
503
+ `SPUR_SPEC_ID` is set, so outside a fleet it makes no call. `fleet-guest-stop` delivers pending
504
+ inbox work to a session joined as a fleet guest at turn end; any other session passes through.
505
+
496
506
  **Available but unwired:** `careful-guard.ts` ships in `hooks/` (with tests) as an opt-in
497
507
  `PreToolUse` guard that asks before destructive shell commands (`rm -rf`, `DROP TABLE`,
498
508
  `git push --force`, …) — it is **not** registered in `hooks.json`. Fail-open by contract; escape
@@ -511,6 +521,7 @@ hold `SKILL.md` and prompt-side companions only.
511
521
  | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
512
522
  | `hooks/task-write-guard.ts` | Compatibility shim for older installs that still execute the script path directly. Forwards stdin to the stable PATH command `superskill hook run sp task-write-guard`, mirrors parseable PreToolUse decisions, and fails open if the runtime is unavailable. Performs no source-tree CLI lookup. |
513
523
  | `hooks/context-*.ts` | Runtime for the three registered context hooks (session-start, post-tool, session-stop) — token-cost estimation + ledger append for `sp:indexed-context` |
524
+ | `hooks/{agent-lifecycle,fleet-guest-stop}.ts` | Fleet hooks (1080/1081): member lifecycle reports via `spur agent report`; turn-end inbox delivery to joined guests |
514
525
  | `hooks/careful-guard.ts` | Opt-in destructive-command guard (unwired — see Hooks above) |
515
526
  | `scripts/batch-preflight.ts` | Pure TABLE A STOP evaluation for `super-planner` — skip doomed pipeline launches without spawning a Skill subprocess; recovery hints map stuck statuses to a single `/sp:dev-*` hop |
516
527
  | `scripts/workflow-step-profile.ts` | Thin glue over the generated lib bundle (`lib/step-profile.generated.mjs` from `packages/app/src/workflow/step-profile.ts`) — read-only step profile from `spur workflow trace`: per node and action-kind durations, idle gaps, session mode and `cacheHit` coverage, plus the ADR-115 cache-window flags `sp:spur-doctor` turns into workflow-optimization proposals |
@@ -518,6 +529,8 @@ hold `SKILL.md` and prompt-side companions only.
518
529
  | `scripts/dogfood-testing/validate-report.ts` | Pure `validateReport(md)` — footer-mandatory + 7-check finalize-or-abort contract with stable error codes |
519
530
  | `scripts/daily-summary/{daily-summary,logger}.ts` | ccusage + git-history orchestration helpers for `sp:daily-summary` |
520
531
  | `scripts/task-diffstat.ts` | 0943 triage-lane diffstat producer — numstat + untracked scan vs the run base; writes `<wbs>-diffstat.json` with the sensitive-path flag; fails safe (sensitive) |
532
+ | `scripts/run-summary.ts` | Measured execution summary `/sp:dev-run` / `/sp:dev-runall` print by default (`--no-summary` skips) — windows the host transcript by `spur workflow progress` attempt timestamps; per stage/run time, wait, tool calls, total / non-cached tokens; `n/a` for subprocess windows |
533
+ | `scripts/session-timeline.ts` | Measured Time/Wait/Token evidence for `sp:session-review` — reads the active Claude Code transcript read-only, one segment per operator prompt, usage deduplicated by message id, tokens split total / non-cached; `{available:false}` exit 0 when no transcript |
521
534
  | `scripts/commands/validate-flag-contracts.ts` | Mechanical consistency gate — compares flag claims across command files, flag-glossary, cross-cutting, dev-operations, and ADR; reports disagreements |
522
535
  | `*.test.ts` | Unit suites — in `hooks/` for guards, in `tests/<skill>/` per ADR-031 pairing |
523
536