@gobing-ai/spur 0.3.95 → 0.3.96

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 (155) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/plugin-scripts.json +0 -54
  3. package/config/rules/boundary/sp-script-placement.yaml +19 -0
  4. package/config/rules/strict/runtime-boundaries.yaml +5 -0
  5. package/config/rules/structure/test-location.yaml +2 -0
  6. package/config/rules/typescript/no-syscall-emulation-in-boundary-mock.yaml +1 -1
  7. package/config/rules/typescript/output-boundaries.yaml +15 -2
  8. package/config/script-placement-baseline.json +51 -0
  9. package/config/workflows/feature-verification.yaml +1 -1
  10. package/config/workflows/history-anatomy.yaml +23 -11
  11. package/config/workflows/idea-pipeline.yaml +80 -85
  12. package/config/workflows/pr-review.yaml +18 -9
  13. package/config/workflows/task-pipeline.yaml +42 -95
  14. package/config/workflows/wrapup-pipeline.yaml +89 -37
  15. package/package.json +1 -1
  16. package/plugins/sp/README.md +8 -10
  17. package/plugins/sp/agents/super-reviewer.md +43 -18
  18. package/plugins/sp/commands/dev-fixgha.md +83 -0
  19. package/plugins/sp/commands/dev-gitmsg.md +8 -6
  20. package/plugins/sp/commands/dev-gtd.md +2 -2
  21. package/plugins/sp/commands/dev-idea.md +22 -12
  22. package/plugins/sp/commands/dev-plan.md +8 -9
  23. package/plugins/sp/commands/dev-review.md +22 -13
  24. package/plugins/sp/commands/dev-verifyall.md +1 -1
  25. package/plugins/sp/commands/spur-init.md +2 -2
  26. package/plugins/sp/lib/history-anatomy.generated.d.mts +112 -0
  27. package/plugins/sp/lib/history-anatomy.generated.mjs +686 -0
  28. package/plugins/sp/lib/idea-handoff.generated.mjs +5 -4
  29. package/plugins/sp/lib/inline-run.generated.d.mts +11 -0
  30. package/plugins/sp/lib/inline-run.generated.mjs +25 -8
  31. package/plugins/sp/lib/quality-gate.generated.d.mts +104 -0
  32. package/plugins/sp/lib/quality-gate.generated.mjs +438 -0
  33. package/plugins/sp/lib/residual-scan.generated.d.mts +62 -0
  34. package/plugins/sp/lib/residual-scan.generated.mjs +210 -0
  35. package/plugins/sp/lib/spur-bin.ts +36 -0
  36. package/plugins/sp/lib/step-profile.generated.d.mts +71 -0
  37. package/plugins/sp/lib/step-profile.generated.mjs +174 -0
  38. package/plugins/sp/plugin.json +1 -1
  39. package/plugins/sp/references/roles.md +1 -1
  40. package/plugins/sp/scripts/history-anatomy-cache.mjs +20 -19
  41. package/plugins/sp/scripts/history-anatomy-cache.ts +23 -928
  42. package/plugins/sp/scripts/inline-run-setup.mjs +85 -320
  43. package/plugins/sp/scripts/inline-run-setup.ts +104 -667
  44. package/plugins/sp/scripts/quality-gate.mjs +34 -19
  45. package/plugins/sp/scripts/quality-gate.ts +12 -658
  46. package/plugins/sp/scripts/residual-scan.mjs +135 -156
  47. package/plugins/sp/scripts/residual-scan.ts +102 -499
  48. package/plugins/sp/scripts/script-root.mjs +5 -1
  49. package/plugins/sp/scripts/script-root.ts +5 -1
  50. package/plugins/sp/scripts/workflow-step-profile.mjs +25 -17
  51. package/plugins/sp/scripts/workflow-step-profile.ts +21 -315
  52. package/plugins/sp/scripts/wrapup-drift-probe.mjs +8 -2
  53. package/plugins/sp/scripts/wrapup-drift-probe.ts +3 -2
  54. package/plugins/sp/scripts/wrapup-steps.mjs +10 -32
  55. package/plugins/sp/scripts/wrapup-steps.ts +8 -36
  56. package/plugins/sp/skills/code-improvement/SKILL.md +5 -4
  57. package/plugins/sp/skills/code-verification/SKILL.md +34 -9
  58. package/plugins/sp/skills/code-verification/references/verdict-schema.md +3 -3
  59. package/plugins/sp/skills/functional-review/SKILL.md +7 -4
  60. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  61. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -1
  62. package/plugins/sp/skills/next-feature/references/handoff-routing.md +1 -1
  63. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  64. package/plugins/sp/skills/spur-cli/SKILL.md +3 -3
  65. package/plugins/sp/skills/spur-cli/references/agent.md +10 -10
  66. package/plugins/sp/skills/spur-cli/references/features.md +17 -6
  67. package/plugins/sp/skills/spur-cli/references/init.md +17 -16
  68. package/plugins/sp/skills/spur-cli/references/self.md +3 -2
  69. package/plugins/sp/skills/spur-cli/references/serve.md +10 -10
  70. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +21 -6
  71. package/plugins/sp/skills/spur-cli/references/tasks.md +14 -8
  72. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -3
  73. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +11 -9
  74. package/plugins/sp/skills/spur-dev/references/decision-brief.md +1 -1
  75. package/plugins/sp/skills/spur-dev/references/dev-operations.md +86 -70
  76. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +3 -3
  77. package/plugins/sp/skills/spur-dev/references/execution-batch.md +77 -34
  78. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +5 -9
  79. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -3
  80. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +31 -21
  81. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +19 -19
  82. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +4 -3
  83. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +29 -3
  84. package/plugins/sp/skills/spur-doctor/SKILL.md +1 -1
  85. package/plugins/sp/skills/sys-architecture/SKILL.md +3 -2
  86. package/spur.js +1495 -369
  87. package/web/_astro/{BoardApp.Cpxntzad.js → BoardApp.BIjMatT1.js} +1 -1
  88. package/web/_astro/{BoardApp.BxJuwD7I.js → BoardApp.GvjIe9Z6.js} +42 -42
  89. package/web/_astro/{TaskDetail.C5bW4WGV.js → TaskDetail.BZM3EAFx.js} +1 -1
  90. package/web/_astro/{arc.CyjRvNMY.js → arc.HkRiZnoI.js} +1 -1
  91. package/web/_astro/{architectureDiagram-3BPJPVTR.B4lWRzJA.js → architectureDiagram-3BPJPVTR.BDdK-tgZ.js} +1 -1
  92. package/web/_astro/{blockDiagram-GPEHLZMM.Be38USQ2.js → blockDiagram-GPEHLZMM.CZ9kOBxx.js} +1 -1
  93. package/web/_astro/{c4Diagram-AAUBKEIU.DT9Fj5Qx.js → c4Diagram-AAUBKEIU.DXK9qeRD.js} +1 -1
  94. package/web/_astro/channel.DlhX2MEt.js +1 -0
  95. package/web/_astro/{chunk-2J33WTMH.SeSBWLg5.js → chunk-2J33WTMH.BTD2WeX5.js} +1 -1
  96. package/web/_astro/{chunk-4BX2VUAB.DoO4VE14.js → chunk-4BX2VUAB.Ci6Qbcvk.js} +1 -1
  97. package/web/_astro/{chunk-55IACEB6.DrmTFA53.js → chunk-55IACEB6.yl3zsj7p.js} +1 -1
  98. package/web/_astro/{chunk-727SXJPM.Bi-TUb_V.js → chunk-727SXJPM.ClXZsfyR.js} +1 -1
  99. package/web/_astro/{chunk-AQP2D5EJ.B-xp8Uhi.js → chunk-AQP2D5EJ.BmKWZBcP.js} +1 -1
  100. package/web/_astro/{chunk-FMBD7UC4.DGWrDnUU.js → chunk-FMBD7UC4.By30fcb7.js} +1 -1
  101. package/web/_astro/{chunk-ND2GUHAM._BagvPDy.js → chunk-ND2GUHAM.24NmrD-k.js} +1 -1
  102. package/web/_astro/{chunk-QZHKN3VN.VOboYWQ0.js → chunk-QZHKN3VN.BN4sKdcS.js} +1 -1
  103. package/web/_astro/{classDiagram-4FO5ZUOK.D_apfHS7.js → classDiagram-4FO5ZUOK.CJpoMPb5.js} +1 -1
  104. package/web/_astro/{classDiagram-v2-Q7XG4LA2.D_apfHS7.js → classDiagram-v2-Q7XG4LA2.CJpoMPb5.js} +1 -1
  105. package/web/_astro/{cose-bilkent-S5V4N54A.DNLU_L-x.js → cose-bilkent-S5V4N54A.BraxQ2Nt.js} +1 -1
  106. package/web/_astro/{cynefin-OW5HDTMX.D8borhV-.js → cynefin-OW5HDTMX.gzoU73oL.js} +1 -1
  107. package/web/_astro/{dagre-BM42HDAG.Uc0lvjcV.js → dagre-BM42HDAG.wyDfWySU.js} +1 -1
  108. package/web/_astro/{diagram-2AECGRRQ.DDIxtDBo.js → diagram-2AECGRRQ.h2_EbMxV.js} +1 -1
  109. package/web/_astro/{diagram-5GNKFQAL.DVoDnD3H.js → diagram-5GNKFQAL.Db6dcs89.js} +1 -1
  110. package/web/_astro/{diagram-KO2AKTUF.CRubTJ-0.js → diagram-KO2AKTUF.NVwzxu_U.js} +1 -1
  111. package/web/_astro/{diagram-LMA3HP47.m9SeYcXQ.js → diagram-LMA3HP47.B-eNgDQk.js} +1 -1
  112. package/web/_astro/{diagram-OG6HWLK6.C6s2ZjV5.js → diagram-OG6HWLK6.Bsa8ZRbJ.js} +1 -1
  113. package/web/_astro/{erDiagram-TEJ5UH35.nSzr5KTj.js → erDiagram-TEJ5UH35.BospRE5Q.js} +1 -1
  114. package/web/_astro/{flowDiagram-I6XJVG4X.DrZcys16.js → flowDiagram-I6XJVG4X.DMzvHwAA.js} +1 -1
  115. package/web/_astro/{ganttDiagram-6RSMTGT7.Do4M1b-K.js → ganttDiagram-6RSMTGT7.Dmdxgd-M.js} +1 -1
  116. package/web/_astro/{gitGraphDiagram-PVQCEYII.BWc9oJ4l.js → gitGraphDiagram-PVQCEYII.CaqdO0rL.js} +1 -1
  117. package/web/_astro/index.EoZlzLK-.css +1 -0
  118. package/web/_astro/{infoDiagram-5YYISTIA.BIdOctFk.js → infoDiagram-5YYISTIA.DDVD9Wn7.js} +1 -1
  119. package/web/_astro/{ishikawaDiagram-YF4QCWOH.CV5SuG2t.js → ishikawaDiagram-YF4QCWOH.EKyCUFsL.js} +1 -1
  120. package/web/_astro/{journeyDiagram-JHISSGLW.CxE-rEJ-.js → journeyDiagram-JHISSGLW.By2-RkYB.js} +1 -1
  121. package/web/_astro/{kanban-definition-UN3LZRKU.BPRdKWs_.js → kanban-definition-UN3LZRKU.ar-WmlyR.js} +1 -1
  122. package/web/_astro/{linear.zRsuuDTE.js → linear.BnzMBgo_.js} +1 -1
  123. package/web/_astro/{mermaid.core.jAJTcMKc.js → mermaid.core.DSqeFu2Y.js} +4 -4
  124. package/web/_astro/{mindmap-definition-RKZ34NQL.BffJxfCr.js → mindmap-definition-RKZ34NQL.1XcF8Wh2.js} +1 -1
  125. package/web/_astro/{pieDiagram-4H26LBE5.CacwWaE3.js → pieDiagram-4H26LBE5.DnItHOdK.js} +1 -1
  126. package/web/_astro/{quadrantDiagram-W4KKPZXB.hXELD06-.js → quadrantDiagram-W4KKPZXB.BQQyrnBt.js} +1 -1
  127. package/web/_astro/{requirementDiagram-4Y6WPE33.DdEbPcqT.js → requirementDiagram-4Y6WPE33.Dmzxun82.js} +1 -1
  128. package/web/_astro/{sankeyDiagram-5OEKKPKP.DgaDocKv.js → sankeyDiagram-5OEKKPKP.BBIeRKYB.js} +1 -1
  129. package/web/_astro/{sequenceDiagram-3UESZ5HK.B0KScnAu.js → sequenceDiagram-3UESZ5HK.CUNVdBBf.js} +1 -1
  130. package/web/_astro/{stateDiagram-AJRCARHV.CV9M_WNc.js → stateDiagram-AJRCARHV.DlFf2sJm.js} +1 -1
  131. package/web/_astro/{stateDiagram-v2-BHNVJYJU.BOAo74Et.js → stateDiagram-v2-BHNVJYJU.DXR7I1H5.js} +1 -1
  132. package/web/_astro/{timeline-definition-PNZ67QCA.CqqepUMe.js → timeline-definition-PNZ67QCA.BcO-GyX2.js} +1 -1
  133. package/web/_astro/{vennDiagram-CIIHVFJN.DDqe4dOG.js → vennDiagram-CIIHVFJN.ChCECmmW.js} +1 -1
  134. package/web/_astro/{wardleyDiagram-YWT4CUSO.B3R9OPdO.js → wardleyDiagram-YWT4CUSO.CRaT12mD.js} +1 -1
  135. package/web/_astro/{xychartDiagram-2RQKCTM6.B3SvgXpQ.js → xychartDiagram-2RQKCTM6.B3lsHVpj.js} +1 -1
  136. package/web/index.html +2 -2
  137. package/plugins/sp/lib/artifact-digest.generated.d.mts +0 -7
  138. package/plugins/sp/lib/artifact-digest.generated.mjs +0 -48
  139. package/plugins/sp/scripts/feature-sync-bounded.mjs +0 -301
  140. package/plugins/sp/scripts/feature-sync-bounded.ts +0 -481
  141. package/plugins/sp/scripts/idea-coverage-check.ts +0 -168
  142. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +0 -298
  143. package/plugins/sp/scripts/record-feature-sync.mjs +0 -63
  144. package/plugins/sp/scripts/record-feature-sync.ts +0 -84
  145. package/plugins/sp/scripts/script-contract-check.ts +0 -506
  146. package/plugins/sp/scripts/stage-registry-adapter.ts +0 -1533
  147. package/plugins/sp/scripts/surface-drift-inventory.ts +0 -989
  148. package/plugins/sp/scripts/task-evidence-precheck.ts +0 -189
  149. package/plugins/sp/scripts/task-size-precheck.ts +0 -212
  150. package/plugins/sp/scripts/transition-shim-check.ts +0 -238
  151. package/plugins/sp/scripts/validate-commands.ts +0 -689
  152. package/plugins/sp/scripts/validate-flag-contracts.ts +0 -890
  153. package/plugins/sp/scripts/verify-answer-lint.ts +0 -549
  154. package/web/_astro/channel.CI6N_tCg.js +0 -1
  155. package/web/_astro/index.CENnIEqT.css +0 -1
@@ -9,9 +9,9 @@
9
9
  #
10
10
  # Shape: start -> discovery -> idea-eval -> feature-create -> ac-generate -> feature-check
11
11
  # -> system-design (conditional: needs_design signal)
12
- # -> design-approval (taste HITL gate; not auto-clicked by --auto)
12
+ # -> design-approval (taste HITL gate; bypassed only when design_approved=true + design check PASS)
13
13
  # -> decompose -> batch-create -> handoff-finalize -> handoff
14
- # (idea-eval rejection -> cancelled)
14
+ # (idea-eval rejection, or auto + `drop` recommendation -> cancelled)
15
15
  # (feature-check failure routes back to ac-generate; batch-create failure to decompose).
16
16
  #
17
17
  # Evidence instead of ceremony (task 0769): the feature check is MEASURED exactly once at
@@ -27,11 +27,11 @@
27
27
  # design — "auto" (default, signal-driven) or "skip" (--skip-design). No force path.
28
28
  # Unified: skip also means omit per-task Design in batch-create (scaffold only;
29
29
  # refine fills later). Default: decompose must author batch item `design`.
30
- # design_approved — "true" when taste pre-cleared (CLI --approve-taste or alias --design-approved);
31
- # lets profile=auto route around the design-approval taste gate (default "false")
32
- # idea_approved — "true" when taste pre-cleared (CLI --approve-taste or alias --idea-approved);
33
- # lets profile=auto route around the idea-eval taste gate (default "false")
34
- # CLI --approve-taste sets both design_approved and idea_approved to true.
30
+ # design_approved — "true" lets profile=auto route around the design-approval taste gate when
31
+ # the recorded design check PASSes (default "false")
32
+ # idea_approved — "true" lets profile=auto accept the idea-eval report's recommendation
33
+ # (proceed/reshape → continue, drop → cancelled; missing → pause) (default "false")
34
+ # CLI --auto on dev-idea / dev-plan sets profile=auto AND both pre-clear vars to true.
35
35
  # spurBin — PATH-independent spur invocation (overridden by CLI at run start)
36
36
  # agent — agent for agent.run steps (default: auto → `agent.default` in config)
37
37
  #
@@ -137,15 +137,24 @@ states:
137
137
  session: fresh
138
138
  expectFile: .spur/run/${vars.__runId}-idea-eval-report.md
139
139
  timeoutMs: ${vars.stepTimeoutMs}
140
+ # Derive the eval recommendation ONCE (0769 pattern): the first non-blank line under
141
+ # `## Recommendation` → proceed | reshape | drop | unknown. The --auto guards out of
142
+ # discovery / idea-eval read this file; `unknown` routes to the idea-eval pause.
143
+ - kind: shell
144
+ options:
145
+ command: >-
146
+ awk '/^## Recommendation/{f=1;next} f&&NF{r=tolower($0);exit}
147
+ END{print (match(r,/^[*_ ]*(proceed|reshape|drop)/) ? substr(r,RSTART,RLENGTH) : "unknown")}'
148
+ ".spur/run/$__runId-idea-eval-report.md" | tr -d '*_ ' > ".spur/run/$__runId-idea-recommendation.txt"
140
149
 
141
150
  - id: idea-eval
142
151
  description: >
143
152
  HITL taste gate. Discovery has produced the idea-evaluation report
144
153
  (.spur/run/${vars.__runId}-idea-eval-report.md) with urgency/necessity scores, premises,
145
154
  pros/cons, and a recommendation. The operator reviews and approves or
146
- rejects. This gate is NOT auto-clicked by --auto (taste gate, like
147
- design-approval). Only routes around when vars.idea_approved=true
148
- (explicit prior approval).
155
+ rejects. Routed around only when profile=auto AND vars.idea_approved=true
156
+ (CLI --auto) AND the report's recommendation is proceed/reshape; a drop
157
+ recommendation cancels, a missing one still pauses here.
149
158
  pause: true
150
159
  onEnter:
151
160
  - kind: hitl.confirm
@@ -181,16 +190,15 @@ states:
181
190
  options:
182
191
  path: .spur/run/${vars.__runId}-idea-feature-id.txt
183
192
  var: featureId
193
+ # 1007 R2: one shell persists both sections — the Goal and Scope updates share the
194
+ # artifact precondition, so the two update shells merged (original commands in order,
195
+ # same && fail-fast semantics).
184
196
  - kind: shell
185
197
  options:
186
198
  command: >-
187
199
  mkdir -p .spur/run &&
188
200
  test -s .spur/run/$__runId-idea-goal.md &&
189
- $spurBin feature update "$featureId" --section Goal --from-file .spur/run/$__runId-idea-goal.md
190
- - kind: shell
191
- options:
192
- command: >-
193
- mkdir -p .spur/run &&
201
+ $spurBin feature update "$featureId" --section Goal --from-file .spur/run/$__runId-idea-goal.md &&
194
202
  test -s .spur/run/$__runId-idea-scope.md &&
195
203
  $spurBin feature update "$featureId" --section Scope --from-file .spur/run/$__runId-idea-scope.md
196
204
 
@@ -206,9 +214,10 @@ states:
206
214
  check records FAIL and routes through the capped retry loop via guards that consume the
207
215
  recorded result — it never fails the run (the engine's default onError policy is `fail`,
208
216
  so an in-action check failure would kill the run before the retry edges are evaluated).
209
- Requirement coverage is MEASURED alongside it by the soft idea-coverage-check shell
210
- (0887 R4): the recorded coverage status conjuncts into the profile=auto ac-generate
211
- guards below so uncovered inventory items route through the same capped retry loop.
217
+ Requirement coverage is MEASURED by the same gate (1004 R2): the `idea-ac-check` args
218
+ carry `--inventory .spur/run/${vars.__runId}-idea-eval-report.md`, so uncovered
219
+ inventory items record FAIL on `idea-ac-check.status` and route through the same capped
220
+ retry loop via the guards below.
212
221
  onEnter:
213
222
  - kind: shell
214
223
  options:
@@ -246,33 +255,16 @@ states:
246
255
  options:
247
256
  id: idea-ac-check
248
257
  executable: "${vars.spurBin}"
249
- args: ["feature", "check", "${vars.featureId}"]
258
+ args: ["feature", "check", "${vars.featureId}", "--inventory", ".spur/run/${vars.__runId}-idea-eval-report.md"]
250
259
  resultFile: .spur/run/${vars.__runId}-idea-ac-check.status
251
260
  softFail: true
252
261
  timeoutMs: 120000
253
- # 0887 R4: requirement-inventory ↔ AC coverage, measured once at the same author/revise
254
- # boundary. Soft shell (exit 0 always): the checker writes the PASS/FAIL status itself and
255
- # the guards below consume the recorded result — never re-run the checker (0769 pattern).
256
- # Repo-checkout path first, then the superskill-staged twin (handoff-finalize resolution
257
- # shape); neither present fails closed to FAIL so readiness degrades visibly instead of
258
- # silently skipping coverage.
259
- - kind: shell
260
- options:
261
- command: >-
262
- mkdir -p .spur/run &&
263
- S=plugins/sp/scripts/idea-coverage-check.ts;
264
- [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp idea-coverage-check.ts 2>/dev/null)";
265
- if [ -n "$S" ] && [ -f "$S" ]; then
266
- bun "$S" --run-id "$__runId" --report ".spur/run/$__runId-idea-eval-report.md" --ac ".spur/run/$__runId-idea-ac-content.md" || printf 'FAIL run=%s checker exited nonzero (bun missing or checker crash)\n' "$__runId" > ".spur/run/$__runId-idea-coverage.reason";
267
- else
268
- printf 'FAIL run=%s checker not found — run superskill install sp --marketplace gobing-ai/spur\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
269
- printf 'FAIL\n' > ".spur/run/$__runId-idea-coverage.status";
270
- fi
271
262
  # 0945 R2: derive the route facts ONCE at this boundary (0769 pattern) — guards read these
272
263
  # named files instead of re-deriving design×needs_design inline. The same command is
273
264
  # duplicated in feature-check's onEnter (YAML has no include); byte-equality is
274
265
  # test-pinned (idea-pipeline-routing.test.ts). Missing/corrupt needs-design JSON fails
275
- # safe to `design`; readiness is PASS only when both recorded checks are PASS.
266
+ # safe to `design`; readiness is PASS only when the recorded check is PASS (1004 R2:
267
+ # coverage folds into idea-ac-check via --inventory).
276
268
  # (warn) 7 commands: two three-way `test && printf || printf` derivations over captured
277
269
  # signal files (ADR-115); no model hop, no CLI re-run.
278
270
  - kind: shell
@@ -282,7 +274,7 @@ states:
282
274
  { test "$design" = skip -o "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false &&
283
275
  printf 'skip\n' > .spur/run/$__runId-idea-design-route.txt ||
284
276
  printf 'design\n' > .spur/run/$__runId-idea-design-route.txt; } &&
285
- { test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS -a "$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" = PASS &&
277
+ { test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS &&
286
278
  printf 'PASS\n' > .spur/run/$__runId-idea-ac-ready.status ||
287
279
  printf 'FAIL\n' > .spur/run/$__runId-idea-ac-ready.status; }
288
280
 
@@ -299,29 +291,19 @@ states:
299
291
  the transition guards route directly from ac-generate to the appropriate next
300
292
  state, so this state is only entered in interactive mode. On failure, the retry
301
293
  cap routes back to ac-generate (≤3 retries) or escalates to failed.
302
- Requirement coverage (.spur/run/${vars.__runId}-idea-coverage.status, 0887 R4) is part of
303
- the recorded results this gate surfaces: a FAIL there means some inventory items have no
304
- covering scenario — answer no to route back to ac-generate for revision if needed.
294
+ Requirement coverage (1004 R2) folds into the recorded `idea-ac-check` result via the
295
+ gate's `--inventory` flag: a FAIL there can mean some inventory items have no covering
296
+ scenario — answer no to route back to ac-generate for revision if needed.
305
297
  pause: true
306
298
  onEnter:
307
299
  - kind: hitl.confirm
308
300
  options:
309
- prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? Requirement coverage status: $(cat .spur/run/${vars.__runId}-idea-coverage.status 2>/dev/null || echo unknown) — reason: $(cat .spur/run/${vars.__runId}-idea-coverage.reason 2>/dev/null || echo n/a) (.spur/run/${vars.__runId}-idea-coverage.status[.reason]). (Failures route back to ac-generate for revision, capped at 3 retries.)"
301
+ prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? Recorded check status: $(cat .spur/run/${vars.__runId}-idea-ac-check.status 2>/dev/null || echo unknown) (.spur/run/${vars.__runId}-idea-ac-check.status — includes inventory-coverage findings, 1004 R2). (Failures route back to ac-generate for revision, capped at 3 retries.)"
310
302
  decision:
311
303
  mode: never
312
- # 0945 R2: same writer as ac-generate's onEnter (byte-equal, test-pinned) — refreshes the
313
- # derived route facts after the interactive gate so both entries into this boundary read
314
- # consistent files; hitl.confirm only sets $__hitlAnswer.
315
- - kind: shell
316
- options:
317
- command: >-
318
- mkdir -p .spur/run &&
319
- { test "$design" = skip -o "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false &&
320
- printf 'skip\n' > .spur/run/$__runId-idea-design-route.txt ||
321
- printf 'design\n' > .spur/run/$__runId-idea-design-route.txt; } &&
322
- { test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS -a "$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" = PASS &&
323
- printf 'PASS\n' > .spur/run/$__runId-idea-ac-ready.status ||
324
- printf 'FAIL\n' > .spur/run/$__runId-idea-ac-ready.status; }
304
+ # 1007 R2: the former post-confirm route-writer duplicate is deleted — ac-generate's
305
+ # writer is the single writer (0945 R2 pin updated); its inputs (design var, needs-design
306
+ # JSON, recorded ac-check status) cannot change across hitl.confirm.
325
307
 
326
308
  - id: system-design
327
309
  description: >
@@ -376,9 +358,8 @@ states:
376
358
  - id: design-approval
377
359
  description: >
378
360
  HITL taste gate. The operator reviews the system design and approves or
379
- rejects it. This gate is NOT auto-clicked by --auto (Auto-Decision Principle
380
- #5: taste-decision -> surface to human). Only routes around when
381
- vars.design_approved=true (explicit prior approval).
361
+ rejects it. Routed around only when profile=auto AND vars.design_approved=true
362
+ (CLI --auto) AND the recorded design check PASSes; a FAIL still pauses here.
382
363
 
383
364
  R7 (0433): a headless `no` persisted by DefaultHitlResponder would loop
384
365
  design-approval -> system-design -> design-approval, burning unbounded
@@ -559,10 +540,8 @@ states:
559
540
  - kind: shell
560
541
  options:
561
542
  command: >-
562
- if [ -f packages/app/src/workflow/idea-handoff-cli.ts ]; then
563
- bun packages/app/src/workflow/idea-handoff-cli.ts;
564
- elif H="$(superskill script path sp idea-handoff.mjs 2>/dev/null)" && [ -f "$H" ]; then
565
- node "$H";
543
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/idea-handoff.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/idea-handoff.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then
544
+ "$RUNNER" "$S";
566
545
  else
567
546
  echo "idea handoff failed closed — idea-handoff script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
568
547
  exit 1;
@@ -575,9 +554,8 @@ states:
575
554
  next command (ready-depth refineall when any task is unready, else auto
576
555
  runall). No task execution — the pipeline stops here.
577
556
  onEnter:
578
- - kind: note
579
- options:
580
- message: "Idea pipeline handoff. Feature: ${vars.featureId}. See .spur/run/${vars.__runId}-idea-handoff.md for the created task list and recommended next command."
557
+ # 1007 R2: the handoff note is deleted — the run.artifact below carries the handoff
558
+ # (same path, the recommended-next-command report).
581
559
  - kind: run.artifact
582
560
  options:
583
561
  path: .spur/run/${vars.__runId}-idea-handoff.md
@@ -608,17 +586,32 @@ transitions:
608
586
  guard:
609
587
  kind: always
610
588
 
611
- # ── discovery: auto-skip (profile=auto + idea_approved) OR enter idea-eval taste gate ──
612
- # Declaration order: auto-skip FIRST (same pattern as system-design → design-approval).
613
- # Without this edge, discovery always enters idea-eval (pause: true), rendering the prompt
589
+ # ── discovery: auto-accept the eval recommendation (profile=auto + idea_approved) OR enter idea-eval ──
590
+ # Declaration order: auto edges FIRST (same pattern as system-design → design-approval).
591
+ # Without them, discovery always enters idea-eval (pause: true), rendering the prompt
614
592
  # and persisting an avoidable pause before the in-state auto-skip guard can fire (0366 R4/R5).
593
+ # --auto accepts the recommendation derived at the end of discovery (-idea-recommendation.txt):
594
+ # drop → cancelled, proceed/reshape → feature-create; unknown/missing falls through to the
595
+ # idea-eval pause (fail-safe: never auto-create a feature without an explicit proceed).
596
+ - from: discovery
597
+ to: cancelled
598
+ terminalReason: cancelled
599
+ description: profile=auto AND idea_approved=true AND eval recommends drop — accept it, no feature.
600
+ guard:
601
+ kind: shell
602
+ options:
603
+ command: >-
604
+ test "$profile" = auto && test "$idea_approved" = true &&
605
+ grep -qx drop .spur/run/$__runId-idea-recommendation.txt
615
606
  - from: discovery
616
607
  to: feature-create
617
- description: profile=auto AND idea_approved=true — skip idea-eval taste gate entirely.
608
+ description: profile=auto AND idea_approved=true AND eval recommends proceed/reshape — skip idea-eval taste gate.
618
609
  guard:
619
610
  kind: shell
620
611
  options:
621
- command: 'test "$profile" = auto && test "$idea_approved" = true'
612
+ command: >-
613
+ test "$profile" = auto && test "$idea_approved" = true &&
614
+ grep -qxE 'proceed|reshape' .spur/run/$__runId-idea-recommendation.txt
622
615
  - from: discovery
623
616
  to: idea-eval
624
617
  description: Discovery complete — gate on idea evaluation taste decision.
@@ -629,11 +622,13 @@ transitions:
629
622
  # Declaration order: auto-skip FIRST (same pattern as system-design → design-approval).
630
623
  - from: idea-eval
631
624
  to: feature-create
632
- description: profile=auto AND idea_approved=true — skip idea-eval taste gate.
625
+ description: profile=auto AND idea_approved=true AND eval recommends proceed/reshape — skip idea-eval taste gate.
633
626
  guard:
634
627
  kind: shell
635
628
  options:
636
- command: 'test "$profile" = auto && test "$idea_approved" = true'
629
+ command: >-
630
+ test "$profile" = auto && test "$idea_approved" = true &&
631
+ grep -qxE 'proceed|reshape' .spur/run/$__runId-idea-recommendation.txt
637
632
  - from: idea-eval
638
633
  to: feature-create
639
634
  description: Idea evaluation approved — create or select a feature.
@@ -694,32 +689,32 @@ transitions:
694
689
  test "$profile" = auto &&
695
690
  test "$(cat .spur/run/$__runId-idea-ac-ready.status 2>/dev/null)" = PASS &&
696
691
  test "$(cat .spur/run/$__runId-idea-design-route.txt 2>/dev/null)" = skip
697
- # Auto-skip 3: check or coverage failed, retry < 3 → loop back to ac-generate (self-loop)
692
+ # Auto-skip 3: check failed (incl. inventory coverage), retry < 3 → loop back to ac-generate (self-loop)
698
693
  - from: ac-generate
699
694
  to: ac-generate
700
- description: "profile=auto, check or coverage failed, retry cap not reached — re-run ac-generate."
701
- # (warn) 5 commands: one persistent multi-assignment line captures both statuses and the retry count
702
- # (with its 0 fallback); the failed-check pair stays verbatim and the profile gate folds into the retry
703
- # test via `test -a`; the retry loop is the smallest honest formulation of cap<3 routing (0769).
695
+ description: "profile=auto, check failed (incl. inventory coverage), retry cap not reached — re-run ac-generate."
696
+ # (warn) 4 commands: one persistent multi-assignment line captures the check status and the retry
697
+ # count (with its 0 fallback); the profile gate folds into the retry test via `test -a`; the retry
698
+ # loop is the smallest honest formulation of cap<3 routing (0769).
704
699
  guard:
705
700
  kind: shell
706
701
  options:
707
702
  command: >-
708
- ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" cov_status="$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
709
- { test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -lt 3
710
- # Auto-skip 4: check or coverage failed, retry cap reached → escalate to failed
703
+ ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
704
+ test "$ac_status" != PASS && test "$profile" = auto -a "$retry" -lt 3
705
+ # Auto-skip 4: check failed (incl. inventory coverage), retry cap reached → escalate to failed
711
706
  - from: ac-generate
712
707
  to: failed
713
708
  terminalReason: retry-exhausted
714
- description: "profile=auto, check or coverage failed after 3 retries — escalate to failed."
715
- # (warn) 5 commands: mirror of the retry guard with cap>=3; keeping escalation and retry as one
709
+ description: "profile=auto, check failed (incl. inventory coverage) after 3 retries — escalate to failed."
710
+ # (warn) 4 commands: mirror of the retry guard with cap>=3; keeping escalation and retry as one
716
711
  # test-chain pair makes the cap boundary auditable in the diff (0769).
717
712
  guard:
718
713
  kind: shell
719
714
  options:
720
715
  command: >-
721
- ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" cov_status="$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
722
- { test "$ac_status" != PASS || test "$cov_status" != PASS; } && test "$profile" = auto -a "$retry" -ge 3
716
+ ac_status="$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" retry="$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)";
717
+ test "$ac_status" != PASS && test "$profile" = auto -a "$retry" -ge 3
723
718
  # Interactive fallback: enter feature-check HITL gate
724
719
  - from: ac-generate
725
720
  to: feature-check
@@ -50,6 +50,7 @@ vars:
50
50
  noWait: "false"
51
51
  waitTimeoutSec: "600"
52
52
  waitIntervalSec: "30"
53
+ spurBin: "spur"
53
54
  preReviewCmd: ""
54
55
  __runId: ""
55
56
  # Runtime-set by file.read.into-var (0771): the request record's requestedAt|head,
@@ -65,15 +66,23 @@ states:
65
66
  before any push can publish it).
66
67
  Writes PASS|FAIL to .spur/run/${vars.__runId}-pr-preflight.status; always exit 0.
67
68
  onEnter:
69
+ # 1007 R8: run-start script-resolution identity (same command as feature-verification
70
+ # verify's first action) — records which tree this run resolved (source-repo vs
71
+ # installed) into .spur/run/$__runId-script-root.json; later plugin-script actions
72
+ # resolve through it (1007 R4 snippet). Never aborts.
73
+ - kind: shell
74
+ options:
75
+ command: >-
76
+ S=plugins/sp/scripts/script-root.ts; [ -f config/plugin-scripts.json -a -f "$S" ] || S="$(superskill script path sp script-root.mjs 2>/dev/null)"; RUNNER=bun; case "$S" in *.mjs) RUNNER=node ;; esac; [ -f "$S" ] && "$RUNNER" "$S" --run-id "$__runId" --spur-bin "$spurBin" || echo "script-root failed closed — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 0
68
77
  - kind: shell
69
78
  options:
70
79
  # (e) 0825: 10 lines — detached-HEAD/dirty/gh-auth/base-refusal probes must record
71
80
  # before any push can publish; split would let a half-probed run continue.
72
81
  command: >-
73
- mkdir -p .spur/run &&
82
+
74
83
  STATUS_FILE=".spur/run/$__runId-pr-preflight.status" &&
75
84
  set +e &&
76
- bun "$(superskill script path sp pr-reviewing.ts)" preflight --base "$baseBranch" --json > ".spur/run/$__runId-pr-context.json";
85
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" preflight --base "$baseBranch" --json > ".spur/run/$__runId-pr-context.json";
77
86
  rc=$?; set -e &&
78
87
  if [ "$rc" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi &&
79
88
  exit 0
@@ -88,10 +97,10 @@ states:
88
97
  # (e) 0825: 9 lines — hygiene verdict + json capture land together; the status-file
89
98
  # fallback keeps a silent driver from passing the gate.
90
99
  command: >-
91
- mkdir -p .spur/run &&
100
+
92
101
  STATUS_FILE=".spur/run/$__runId-pr-hygiene.status" &&
93
102
  set +e &&
94
- bun "$(superskill script path sp pr-reviewing.ts)" hygiene --base "$baseBranch" --json
103
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" hygiene --base "$baseBranch" --json
95
104
  --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-hygiene.json";
96
105
  rc=$?; set -e &&
97
106
  if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
@@ -122,7 +131,7 @@ states:
122
131
  mkdir -p .spur/run &&
123
132
  STATUS_FILE=".spur/run/$__runId-pr-push.status" &&
124
133
  set +e &&
125
- bun "$(superskill script path sp pr-reviewing.ts)" push --json --status-file "$STATUS_FILE"
134
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" push --json --status-file "$STATUS_FILE"
126
135
  > ".spur/run/$__runId-pr-push.json";
127
136
  rc=$?; set -e &&
128
137
  if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
@@ -139,7 +148,7 @@ states:
139
148
  mkdir -p .spur/run &&
140
149
  STATUS_FILE=".spur/run/$__runId-pr-ensure.status" &&
141
150
  set +e &&
142
- bun "$(superskill script path sp pr-reviewing.ts)" ensure-pr --base "$baseBranch" --json
151
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" ensure-pr --base "$baseBranch" --json
143
152
  --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr.json";
144
153
  rc=$?; set -e &&
145
154
  if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
@@ -155,7 +164,7 @@ states:
155
164
  # (e) 0825: 10 lines — the write-then-read split is the file-var transport feeding
156
165
  # wait/collect and must stay one action (same record, same run scope).
157
166
  command: >-
158
- mkdir -p .spur/run; case "$mode" in rerun) F=--force ;; *) F= ;; esac; bun "$(superskill script path sp pr-reviewing.ts)" request --focus "$focus" $F --json --status-file ".spur/run/$__runId-pr-request.status" > ".spur/run/$__runId-pr-request.json"; [ -f ".spur/run/$__runId-pr-request.status" ] || printf 'FAIL\n' > ".spur/run/$__runId-pr-request.status"; jq -e . ".spur/run/$__runId-pr-request.json" > /dev/null 2>&1 && jq -r '.requestedAt // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-since.txt" && jq -r '.head // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-head.txt"; exit 0
167
+ F="$([ "$mode" = rerun ] && echo --force)"; eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" request --focus "$focus" $F --json --status-file ".spur/run/$__runId-pr-request.status" > ".spur/run/$__runId-pr-request.json"; [ -f ".spur/run/$__runId-pr-request.status" ] || echo FAIL > ".spur/run/$__runId-pr-request.status"; jq -e . ".spur/run/$__runId-pr-request.json" >/dev/null 2>&1 && jq -r '.requestedAt // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-since.txt" && jq -r '.head // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-head.txt"; exit 0
159
168
 
160
169
  - id: wait
161
170
  description: >
@@ -180,7 +189,7 @@ states:
180
189
  mkdir -p .spur/run &&
181
190
  STATUS_FILE=".spur/run/$__runId-pr-wait.status" &&
182
191
  set +e &&
183
- bun "$(superskill script path sp pr-reviewing.ts)" wait --since "$prSince" --head "$prHead" --timeout "$waitTimeoutSec" --interval "$waitIntervalSec"
192
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" wait --since "$prSince" --head "$prHead" --timeout "$waitTimeoutSec" --interval "$waitIntervalSec"
184
193
  --json --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-wait.json";
185
194
  rc=$?; set -e &&
186
195
  if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
@@ -204,7 +213,7 @@ states:
204
213
  # (e) 0825: 9 lines — collect + status must run against the same since/head pair
205
214
  # before the composite status is decided (same 0771 record contract).
206
215
  command: >-
207
- mkdir -p .spur/run; bun "$(superskill script path sp pr-reviewing.ts)" collect --since "$prSince" --head "$prHead" --json --status-file ".spur/run/$__runId-pr-collect.status" > ".spur/run/$__runId-pr-findings.json"; c=$?; bun "$(superskill script path sp pr-reviewing.ts)" status --since "$prSince" --head "$prHead" --json > ".spur/run/$__runId-pr-status.json" && [ "$c" -eq 0 ] && [ -f ".spur/run/$__runId-pr-collect.status" ] || printf 'FAIL\n' > ".spur/run/$__runId-pr-collect.status"; cat ".spur/run/$__runId-pr-findings.json" 2>/dev/null; exit 0
216
+ mkdir -p .spur/run; eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/pr-reviewing.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/pr-reviewing.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" collect --since "$prSince" --head "$prHead" --json --status-file ".spur/run/$__runId-pr-collect.status" > ".spur/run/$__runId-pr-findings.json"; c=$?; "$RUNNER" "$S" status --since "$prSince" --head "$prHead" --json > ".spur/run/$__runId-pr-status.json" && [ "$c" -eq 0 ] && [ -f ".spur/run/$__runId-pr-collect.status" ] || printf 'FAIL\n' > ".spur/run/$__runId-pr-collect.status"; cat ".spur/run/$__runId-pr-findings.json" 2>/dev/null; exit 0
208
217
 
209
218
  - id: done
210
219
  description: Terminal — review collected; findings artifact at .spur/run/${vars.__runId}-pr-findings.json