@gobing-ai/spur 0.3.94 → 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 (198) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/README.md +42 -0
  3. package/board/index.d.ts +38 -0
  4. package/config/plugin-scripts.json +3 -52
  5. package/config/rules/boundary/sp-script-placement.yaml +19 -0
  6. package/config/rules/strict/runtime-boundaries.yaml +5 -0
  7. package/config/rules/structure/test-location.yaml +2 -0
  8. package/config/rules/typescript/no-syscall-emulation-in-boundary-mock.yaml +1 -1
  9. package/config/rules/typescript/output-boundaries.yaml +15 -2
  10. package/config/script-placement-baseline.json +51 -0
  11. package/config/workflows/feature-verification.yaml +7 -4
  12. package/config/workflows/history-anatomy.yaml +23 -11
  13. package/config/workflows/idea-pipeline.yaml +87 -86
  14. package/config/workflows/pr-review.yaml +18 -9
  15. package/config/workflows/task-pipeline.yaml +84 -109
  16. package/config/workflows/wrapup-pipeline.yaml +173 -46
  17. package/package.json +15 -11
  18. package/plugins/sp/README.md +8 -10
  19. package/plugins/sp/agents/super-reviewer.md +43 -18
  20. package/plugins/sp/commands/dev-fixgha.md +83 -0
  21. package/plugins/sp/commands/dev-gitmsg.md +8 -6
  22. package/plugins/sp/commands/dev-gtd.md +2 -2
  23. package/plugins/sp/commands/dev-idea.md +22 -12
  24. package/plugins/sp/commands/dev-plan.md +8 -9
  25. package/plugins/sp/commands/dev-review.md +22 -13
  26. package/plugins/sp/commands/dev-verify.md +7 -4
  27. package/plugins/sp/commands/dev-verifyall.md +5 -4
  28. package/plugins/sp/commands/dev-wrap.md +1 -1
  29. package/plugins/sp/commands/spur-init.md +2 -2
  30. package/plugins/sp/hooks/context-post-tool.ts +2 -2
  31. package/plugins/sp/hooks/context-session-start.ts +2 -1
  32. package/plugins/sp/hooks/context-session-stop.ts +22 -14
  33. package/plugins/sp/hooks/pi/guard-extension.ts +109 -150
  34. package/plugins/sp/lib/history-anatomy.generated.d.mts +112 -0
  35. package/plugins/sp/lib/history-anatomy.generated.mjs +686 -0
  36. package/plugins/sp/lib/idea-handoff.generated.mjs +6 -5
  37. package/plugins/sp/lib/inline-run.generated.d.mts +13 -2
  38. package/plugins/sp/lib/inline-run.generated.mjs +33 -16
  39. package/plugins/sp/lib/quality-gate.generated.d.mts +104 -0
  40. package/plugins/sp/lib/quality-gate.generated.mjs +438 -0
  41. package/plugins/sp/lib/residual-scan.generated.d.mts +62 -0
  42. package/plugins/sp/lib/residual-scan.generated.mjs +210 -0
  43. package/plugins/sp/lib/spur-bin.ts +36 -0
  44. package/plugins/sp/lib/step-profile.generated.d.mts +71 -0
  45. package/plugins/sp/lib/step-profile.generated.mjs +174 -0
  46. package/plugins/sp/plugin.json +1 -1
  47. package/plugins/sp/references/roles.md +1 -1
  48. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +3 -3
  49. package/plugins/sp/scripts/daily-summary/daily-summary.ts +3 -3
  50. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +2 -0
  51. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +1 -0
  52. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +9 -7
  53. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +8 -7
  54. package/plugins/sp/scripts/feature-verification-steps.ts +6 -6
  55. package/plugins/sp/scripts/history-anatomy-cache.mjs +23 -22
  56. package/plugins/sp/scripts/history-anatomy-cache.ts +23 -928
  57. package/plugins/sp/scripts/inline-run-setup.mjs +90 -315
  58. package/plugins/sp/scripts/inline-run-setup.ts +109 -639
  59. package/plugins/sp/scripts/pr-reviewing.mjs +2 -0
  60. package/plugins/sp/scripts/pr-reviewing.ts +1 -0
  61. package/plugins/sp/scripts/quality-gate.mjs +38 -21
  62. package/plugins/sp/scripts/quality-gate.ts +20 -660
  63. package/plugins/sp/scripts/residual-scan.mjs +138 -159
  64. package/plugins/sp/scripts/residual-scan.ts +102 -499
  65. package/plugins/sp/scripts/script-root.mjs +129 -0
  66. package/plugins/sp/scripts/script-root.ts +199 -0
  67. package/plugins/sp/scripts/workflow-step-profile.mjs +27 -16
  68. package/plugins/sp/scripts/workflow-step-profile.ts +22 -314
  69. package/plugins/sp/scripts/wrapup-drift-probe.mjs +12 -3
  70. package/plugins/sp/scripts/wrapup-drift-probe.ts +6 -3
  71. package/plugins/sp/scripts/wrapup-steps.mjs +42 -40
  72. package/plugins/sp/scripts/wrapup-steps.ts +64 -46
  73. package/plugins/sp/skills/code-improvement/SKILL.md +5 -4
  74. package/plugins/sp/skills/code-verification/SKILL.md +46 -16
  75. package/plugins/sp/skills/code-verification/references/verdict-schema.md +13 -2
  76. package/plugins/sp/skills/functional-review/SKILL.md +8 -5
  77. package/plugins/sp/skills/functional-review/references/verdict-schema.md +1 -1
  78. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -1
  79. package/plugins/sp/skills/next-feature/references/handoff-routing.md +1 -1
  80. package/plugins/sp/skills/next-router/references/routing-table.md +2 -2
  81. package/plugins/sp/skills/spur-cli/SKILL.md +3 -3
  82. package/plugins/sp/skills/spur-cli/references/agent.md +10 -10
  83. package/plugins/sp/skills/spur-cli/references/features.md +17 -6
  84. package/plugins/sp/skills/spur-cli/references/init.md +17 -16
  85. package/plugins/sp/skills/spur-cli/references/self.md +3 -2
  86. package/plugins/sp/skills/spur-cli/references/serve.md +10 -10
  87. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +28 -5
  88. package/plugins/sp/skills/spur-cli/references/tasks.md +14 -8
  89. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -3
  90. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +11 -9
  91. package/plugins/sp/skills/spur-dev/references/decision-brief.md +1 -1
  92. package/plugins/sp/skills/spur-dev/references/dev-operations.md +86 -70
  93. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +3 -3
  94. package/plugins/sp/skills/spur-dev/references/execution-batch.md +107 -44
  95. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +5 -9
  96. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -3
  97. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +31 -21
  98. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +19 -19
  99. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +4 -3
  100. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +35 -6
  101. package/plugins/sp/skills/spur-doctor/SKILL.md +1 -1
  102. package/plugins/sp/skills/sys-architecture/SKILL.md +3 -2
  103. package/plugins/sp/tsconfig.json +8 -0
  104. package/spur.js +6638 -4775
  105. package/web/_astro/BoardApp.BIjMatT1.js +1 -0
  106. package/web/_astro/{BoardApp.FTEs3-N8.js → BoardApp.GvjIe9Z6.js} +150 -153
  107. package/web/_astro/TaskDetail.BZM3EAFx.js +1 -0
  108. package/web/_astro/_commonjsHelpers.CqkleIqs.js +1 -0
  109. package/web/_astro/{arc.uuAf51IT.js → arc.HkRiZnoI.js} +1 -1
  110. package/web/_astro/architectureDiagram-3BPJPVTR.BDdK-tgZ.js +36 -0
  111. package/web/_astro/{blockDiagram-GPEHLZMM.D1mGCq3p.js → blockDiagram-GPEHLZMM.CZ9kOBxx.js} +1 -1
  112. package/web/_astro/board-facade-react-dom-client.B2U5wMvk.js +1 -0
  113. package/web/_astro/board-facade-react-dom.Cd2MuMhF.js +1 -0
  114. package/web/_astro/board-facade-react-jsx-dev-runtime.B_L3JzfC.js +1 -0
  115. package/web/_astro/board-facade-react-jsx-runtime.BY2yfHRi.js +1 -0
  116. package/web/_astro/board-facade-react-router-dom.Dy5pjzOw.js +1 -0
  117. package/web/_astro/board-facade-react-router.DjjqU27_.js +1 -0
  118. package/web/_astro/board-facade-react.Dgf4GRyj.js +1 -0
  119. package/web/_astro/{c4Diagram-AAUBKEIU.CMsolcde.js → c4Diagram-AAUBKEIU.DXK9qeRD.js} +1 -1
  120. package/web/_astro/channel.DlhX2MEt.js +1 -0
  121. package/web/_astro/{chunk-2J33WTMH.CrGA3fik.js → chunk-2J33WTMH.BTD2WeX5.js} +1 -1
  122. package/web/_astro/{chunk-4BX2VUAB.DsLVVla0.js → chunk-4BX2VUAB.Ci6Qbcvk.js} +1 -1
  123. package/web/_astro/{chunk-55IACEB6.Dxc59Tfi.js → chunk-55IACEB6.yl3zsj7p.js} +1 -1
  124. package/web/_astro/{chunk-727SXJPM.CaEVE2Wy.js → chunk-727SXJPM.ClXZsfyR.js} +1 -1
  125. package/web/_astro/{chunk-AQP2D5EJ.BiJ4HXeI.js → chunk-AQP2D5EJ.BmKWZBcP.js} +1 -1
  126. package/web/_astro/{chunk-FMBD7UC4.Mxf1fru5.js → chunk-FMBD7UC4.By30fcb7.js} +1 -1
  127. package/web/_astro/chunk-JMJ3UQ3L.BQJEJHu4.js +34 -0
  128. package/web/_astro/{chunk-ND2GUHAM.pyOWQixH.js → chunk-ND2GUHAM.24NmrD-k.js} +1 -1
  129. package/web/_astro/{chunk-QZHKN3VN.BmEsg4vr.js → chunk-QZHKN3VN.BN4sKdcS.js} +1 -1
  130. package/web/_astro/chunk-YNUBSHFH.CxeAygfi.js +7 -0
  131. package/web/_astro/{classDiagram-4FO5ZUOK.BHhhMFTO.js → classDiagram-4FO5ZUOK.CJpoMPb5.js} +1 -1
  132. package/web/_astro/{classDiagram-v2-Q7XG4LA2.BHhhMFTO.js → classDiagram-v2-Q7XG4LA2.CJpoMPb5.js} +1 -1
  133. package/web/_astro/client.BhluLQqe.js +1 -0
  134. package/web/_astro/client.DBpSRLnx.js +9 -0
  135. package/web/_astro/cose-bilkent-S5V4N54A.BraxQ2Nt.js +1 -0
  136. package/web/_astro/{cynefin-OW5HDTMX.C2j1_lKL.js → cynefin-OW5HDTMX.gzoU73oL.js} +1 -1
  137. package/web/_astro/{dagre-BM42HDAG.hZ2NCTdT.js → dagre-BM42HDAG.wyDfWySU.js} +1 -1
  138. package/web/_astro/{diagram-2AECGRRQ.Bfw5_EzK.js → diagram-2AECGRRQ.h2_EbMxV.js} +1 -1
  139. package/web/_astro/{diagram-5GNKFQAL.Bt1V_Tmk.js → diagram-5GNKFQAL.Db6dcs89.js} +1 -1
  140. package/web/_astro/{diagram-KO2AKTUF.DEk-YFwp.js → diagram-KO2AKTUF.NVwzxu_U.js} +1 -1
  141. package/web/_astro/{diagram-LMA3HP47.CDjndtQm.js → diagram-LMA3HP47.B-eNgDQk.js} +1 -1
  142. package/web/_astro/{diagram-OG6HWLK6.cFnUHScG.js → diagram-OG6HWLK6.Bsa8ZRbJ.js} +1 -1
  143. package/web/_astro/{erDiagram-TEJ5UH35.DlhYp7NV.js → erDiagram-TEJ5UH35.BospRE5Q.js} +1 -1
  144. package/web/_astro/{flowDiagram-I6XJVG4X.DNTpsxfx.js → flowDiagram-I6XJVG4X.DMzvHwAA.js} +1 -1
  145. package/web/_astro/ganttDiagram-6RSMTGT7.Dmdxgd-M.js +292 -0
  146. package/web/_astro/{gitGraphDiagram-PVQCEYII.DkEqNI0P.js → gitGraphDiagram-PVQCEYII.CaqdO0rL.js} +1 -1
  147. package/web/_astro/index.5dn-Zm-2.js +1 -0
  148. package/web/_astro/index.C-IqPpW2.js +1 -0
  149. package/web/_astro/index.Cyc_GA4f.js +1 -0
  150. package/web/_astro/index.EoZlzLK-.css +1 -0
  151. package/web/_astro/index.tZfqwSut.js +1 -0
  152. package/web/_astro/{infoDiagram-5YYISTIA.CrjioCTG.js → infoDiagram-5YYISTIA.DDVD9Wn7.js} +1 -1
  153. package/web/_astro/{ishikawaDiagram-YF4QCWOH.BcK0CN8n.js → ishikawaDiagram-YF4QCWOH.EKyCUFsL.js} +1 -1
  154. package/web/_astro/{journeyDiagram-JHISSGLW.p0CbBDX1.js → journeyDiagram-JHISSGLW.By2-RkYB.js} +1 -1
  155. package/web/_astro/jsx-runtime.DWOiEOII.js +1 -0
  156. package/web/_astro/{kanban-definition-UN3LZRKU.puHIFt6J.js → kanban-definition-UN3LZRKU.ar-WmlyR.js} +1 -1
  157. package/web/_astro/{linear.Bb-3a1d7.js → linear.BnzMBgo_.js} +1 -1
  158. package/web/_astro/{mermaid.core.CJDgXOJs.js → mermaid.core.DSqeFu2Y.js} +4 -4
  159. package/web/_astro/{mindmap-definition-RKZ34NQL.BoAZEI9t.js → mindmap-definition-RKZ34NQL.1XcF8Wh2.js} +1 -1
  160. package/web/_astro/{pieDiagram-4H26LBE5.CJNSdqY7.js → pieDiagram-4H26LBE5.DnItHOdK.js} +1 -1
  161. package/web/_astro/{quadrantDiagram-W4KKPZXB.DtTy7_0Z.js → quadrantDiagram-W4KKPZXB.BQQyrnBt.js} +1 -1
  162. package/web/_astro/{requirementDiagram-4Y6WPE33.BNYV98Xg.js → requirementDiagram-4Y6WPE33.Dmzxun82.js} +1 -1
  163. package/web/_astro/{sankeyDiagram-5OEKKPKP.DRq9DGHp.js → sankeyDiagram-5OEKKPKP.BBIeRKYB.js} +1 -1
  164. package/web/_astro/{sequenceDiagram-3UESZ5HK.B7KdBFCm.js → sequenceDiagram-3UESZ5HK.CUNVdBBf.js} +1 -1
  165. package/web/_astro/{stateDiagram-AJRCARHV.CD62ZJ2H.js → stateDiagram-AJRCARHV.DlFf2sJm.js} +1 -1
  166. package/web/_astro/{stateDiagram-v2-BHNVJYJU.CeVk1TAj.js → stateDiagram-v2-BHNVJYJU.DXR7I1H5.js} +1 -1
  167. package/web/_astro/{timeline-definition-PNZ67QCA.C_ZPA5tT.js → timeline-definition-PNZ67QCA.BcO-GyX2.js} +1 -1
  168. package/web/_astro/{vennDiagram-CIIHVFJN.CrThO_FQ.js → vennDiagram-CIIHVFJN.ChCECmmW.js} +1 -1
  169. package/web/_astro/{wardleyDiagram-YWT4CUSO.DSZCA5nl.js → wardleyDiagram-YWT4CUSO.CRaT12mD.js} +1 -1
  170. package/web/_astro/{xychartDiagram-2RQKCTM6.KI7baTuk.js → xychartDiagram-2RQKCTM6.B3lsHVpj.js} +1 -1
  171. package/web/board-runtime.json +69 -0
  172. package/web/index.html +2 -2
  173. package/plugins/sp/lib/artifact-digest.generated.d.mts +0 -7
  174. package/plugins/sp/lib/artifact-digest.generated.mjs +0 -48
  175. package/plugins/sp/scripts/feature-sync-bounded.mjs +0 -298
  176. package/plugins/sp/scripts/feature-sync-bounded.ts +0 -479
  177. package/plugins/sp/scripts/idea-coverage-check.ts +0 -168
  178. package/plugins/sp/scripts/inline-pipeline-parity-check.ts +0 -298
  179. package/plugins/sp/scripts/record-feature-sync.mjs +0 -63
  180. package/plugins/sp/scripts/record-feature-sync.ts +0 -84
  181. package/plugins/sp/scripts/script-contract-check.ts +0 -377
  182. package/plugins/sp/scripts/stage-registry-adapter.ts +0 -1533
  183. package/plugins/sp/scripts/surface-drift-inventory.ts +0 -989
  184. package/plugins/sp/scripts/task-evidence-precheck.ts +0 -187
  185. package/plugins/sp/scripts/task-size-precheck.ts +0 -210
  186. package/plugins/sp/scripts/transition-shim-check.ts +0 -238
  187. package/plugins/sp/scripts/validate-commands.ts +0 -689
  188. package/plugins/sp/scripts/validate-flag-contracts.ts +0 -878
  189. package/plugins/sp/scripts/verify-answer-lint.ts +0 -547
  190. package/web/_astro/BoardApp.C02hAHPO.js +0 -1
  191. package/web/_astro/TaskDetail.C-GdsS-t.js +0 -1
  192. package/web/_astro/architectureDiagram-3BPJPVTR.CGe629A1.js +0 -36
  193. package/web/_astro/channel.fsgl7o5j.js +0 -1
  194. package/web/_astro/client.yhYJvxCU.js +0 -9
  195. package/web/_astro/cose-bilkent-S5V4N54A.2fH4YOlp.js +0 -1
  196. package/web/_astro/ganttDiagram-6RSMTGT7.DC_p36PI.js +0 -292
  197. package/web/_astro/index.De90oHcH.js +0 -1
  198. package/web/_astro/index.Hjbr15fG.css +0 -1
@@ -13,9 +13,10 @@
13
13
  # `test` is the project quality gate (shell + bounded /sp:dev-fixall), not
14
14
  # /sp:dev-unit (coverage gap-fill; router C3/C5).
15
15
  #
16
- # F96 residual sweep (0950): precheck captures the resume-safe base commit; verify
17
- # scans and folds residuals between the verdict and the proof bind (blocking leftovers
18
- # downgrade PASS → PARTIAL and take the existing remediation edge); done settles
16
+ # F96 residual sweep (0950, reordered 0983): precheck captures the resume-safe base
17
+ # commit; record scans and folds residuals AFTER `task record` flips the verdict-proven
18
+ # boxes (a post-record blocking leftover downgrades PASS → PARTIAL, fails the record →
19
+ # done guard closed, and re-records Testing before the failed edge); done settles
19
20
  # deferrals; failed renders the recovery report. No new state, edge, or model query.
20
21
  #
21
22
  # Vars (passed as a JSON object via `--vars`):
@@ -43,7 +44,7 @@ description: "Standard task pipeline: precheck → implement → quality-gate (t
43
44
  # any non-terminal state may transition to cancelled.
44
45
  # Guards:
45
46
  # wip → testing: spur task check <wbs>
46
- # testing → done: spur task check <wbs> --strict-core, then PASS-verdict provenance
47
+ # testing → done: spur task check <wbs> --as done, then PASS-verdict provenance
47
48
  # Invalid: todo → testing, todo → done, and wip → done.
48
49
  # Pipeline states below are orchestration states, not task statuses.
49
50
  iterationBound: 20
@@ -162,12 +163,6 @@ vars:
162
163
  # anchors directly in the /sp:dev-fixall input, so the fix agent starts AT the failing
163
164
  # file:line instead of re-deriving it from a fresh gate run (0482 R3).
164
165
  gateFindings: ""
165
- # Max R-items in ## Requirements before size precheck fails (R2, task 0454).
166
- # Override with `--vars '{"maxImplementReqs":"20"}'`.
167
- maxImplementReqs: "10"
168
- # Max checklist items under ## Plan before size precheck fails (R2, task 0454).
169
- # Override with `--vars '{"maxImplementPlanItems":"32"}'`.
170
- maxImplementPlanItems: "16"
171
166
  # Diff-scope guard on the implement hop (R1, task 0487). When the target task
172
167
  # body backticks at least one path, non-corpus changes outside those paths
173
168
  # fail the step by name. New files beside a declared file are allowed. Empty
@@ -187,38 +182,25 @@ states:
187
182
  Fast deterministic task readiness and size checks. Failures route to the
188
183
  `failed` terminal state (not a raw lifecycle abort mid-enter).
189
184
  onEnter:
190
- # (e) git-status hygiene advisory; never fails the run (0487 R6 / 0511 R1).
185
+ # 0960 R2: run-start script-resolution identity — record which tree this run
186
+ # resolved (source-repo vs installed) before any step executes. Never aborts.
191
187
  - kind: shell
192
188
  options:
193
189
  command: >-
194
- D=$(git status --porcelain -- . ':(exclude)docs/tasks*' ':(exclude)docs/features' 2>/dev/null); [ -z "$D" ] || printf 'precheck: WARNING - working tree has uncommitted non-corpus changes — commit or stash before starting a new task:\n%s\n' "$D"; C=$(git status --porcelain -- ':(glob)docs/tasks*/**' 2>/dev/null); [ -z "$C" ] || printf 'precheck: NOTE - task corpus has uncommitted changes — review before staging with this task:\n%s\n' "$C"; exit 0
195
- - kind: note
196
- options:
197
- # R4 task_run_links linkage (kind=pipeline) is written by a WorkflowService
198
- # hook at run start — see the 0062 follow-up note; there is no link-writing
199
- # CLI verb to call from a shell step, so it cannot live in pure YAML.
200
- message: "Pipeline start for task ${vars.wbs}."
201
- # (e) auto-profile feature reopen; exit 1 when reactivation fails (0723 R3).
202
- - kind: shell
203
- options:
204
- command: >-
205
- [ "$profile" = auto ] || exit 0; FID=$($spurBin task show $wbs --json 2>/dev/null | jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null); [ -z "$FID" ] || $spurBin feature sync "$FID" --force 2>/dev/null || $spurBin feature update "$FID" active 2>/dev/null || { echo "precheck: FAIL - feature reactivation $FID failed — feature sync + feature update both errored" >&2; exit 1; }; exit 0
206
- # (d) task-size-precheck.ts owns the check; shell only resolves it and fails closed (0454 R2 / 0723 R2).
207
- - kind: shell
208
- options:
209
- command: >-
210
- mkdir -p .spur/run; S=plugins/sp/scripts/task-size-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-size-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin" --max-reqs "$maxImplementReqs" --max-plan-items "$maxImplementPlanItems"; else echo "task-size-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-size.status"; fi; exit 0
211
- # (d) task-evidence-precheck.ts owns the check; shell only resolves it and fails closed (0726 R2).
190
+ 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
191
+ # (e) git-status hygiene advisory; never fails the run (0487 R6 / 0511 R1). 1007 R3:
192
+ # the F96 base-sha capture (0950) merged into this shell — original commands in order,
193
+ # then the one-time base commit capture; a resumed run keeps its original base so
194
+ # residual scans stay anchored to the same diff.
212
195
  - kind: shell
213
196
  options:
214
197
  command: >-
215
- mkdir -p .spur/run; S=plugins/sp/scripts/task-evidence-precheck.ts; [ -f "$S" ] || S="$(superskill script path sp task-evidence-precheck.ts 2>/dev/null)"; if [ -f "$S" ]; then bun "$S" "$wbs" --spur-bin "$spurBin"; else echo "task-evidence-precheck failed closed — checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'." >&2; echo "FAIL" > ".spur/run/$wbs-precheck-evidence.status"; fi; exit 0
216
- # (e) F96 R1 (0950): capture the run's base commit once — a resumed or re-entered run
217
- # keeps its original base so residual scans stay anchored to the same diff.
198
+ D=$(git status --porcelain -- . ':(exclude)docs/tasks*' ':(exclude)docs/features' 2>/dev/null); [ -z "$D" ] || printf 'precheck: WARNING - working tree has uncommitted non-corpus changes — commit or stash before starting a new task:\n%s\n' "$D"; C=$(git status --porcelain -- ':(glob)docs/tasks*/**' 2>/dev/null); [ -z "$C" ] || printf 'precheck: NOTE - task corpus has uncommitted changes — review before staging with this task:\n%s\n' "$C"; mkdir -p .spur/run; [ -f ".spur/run/$wbs-base.sha" ] || git rev-parse HEAD > ".spur/run/$wbs-base.sha"; exit 0
199
+ # (e) auto-profile feature reopen; exit 1 when reactivation fails (0723 R3).
218
200
  - kind: shell
219
201
  options:
220
202
  command: >-
221
- mkdir -p .spur/run; [ -f ".spur/run/$wbs-base.sha" ] || git rev-parse HEAD > ".spur/run/$wbs-base.sha"; exit 0
203
+ [ "$profile" = auto ] || exit 0; FID=$($spurBin task show $wbs --json 2>/dev/null | jq -r '.feature_id // .frontmatter.feature_id // empty' 2>/dev/null); [ -z "$FID" ] || $spurBin feature sync "$FID" --force 2>/dev/null || $spurBin feature update "$FID" active 2>/dev/null || { echo "precheck: FAIL - feature reactivation $FID failed — feature sync + feature update both errored" >&2; exit 1; }; exit 0
222
204
  # (e) route-reason lookup and routes log; proportional-routing tests locate it
223
205
  # (0759 R1/R5 run-scoped artifact; 0804 R8 run-id safety — one line, no in-scalar `#`).
224
206
  - kind: shell
@@ -432,7 +414,7 @@ states:
432
414
  - kind: shell
433
415
  options:
434
416
  command: >-
435
- mkdir -p .spur/run; if [ -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts run; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" run; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
417
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S" run; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
436
418
 
437
419
  - id: test-fix
438
420
  description: >
@@ -447,19 +429,15 @@ states:
447
429
  options:
448
430
  command: >-
449
431
  TASK_POLICY=$($spurBin task show "$wbs" --json | jq -er '.frontmatter.mutationPolicy // ([.content | scan("(?m)^mutationPolicy:[ \t]*([^ \r\n]+)[ \t]*$") | .[0]] | if length == 0 then "code" elif length == 1 then .[0] else "ambiguous" end)') || exit 1; [ "$mutationPolicy:$TASK_POLICY" = "code:code" ] || { echo "test-fix: mutation policy forbids automatic code repair (run=$mutationPolicy, task=$TASK_POLICY) — gate failure preserved, no agent dispatched" >&2; exit 1; }
450
- # (e) fixall attempt counter and verdict hand-off to the remediation log.
451
- - kind: shell
452
- options:
453
- command: >-
454
- mkdir -p .spur/run; A=".spur/run/$wbs-test-fix-attempt"; n=$(cat "$A" 2>/dev/null || echo 0); printf '%s\n' "$((n + 1))" > "$A"; [ ! -f ".spur/run/$wbs-verdict.json" ] || { echo '--- verify verdict (remediation input, task 0703 R4) ---'; cat ".spur/run/$wbs-verdict.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
455
- # (d) F96 R3 (0950): hand the residual list to the remediation loop — dev-fixall
456
- # treats residual items as fix targets and may defer P3/markers to
457
- # residual-deferrals.json (see dev-fixall.md). Fold already merged the anchors
458
- # into <wbs>-test-gate.findings; this carries the structured artifact too.
432
+ # (e) fixall attempt counter, verdict hand-off and residual artifact in one log
433
+ # append shell (1007 R3: the two appends merged — original commands in order, exit 0).
434
+ # (d) F96 R3 (0950): dev-fixall treats residual items as fix targets and may defer
435
+ # P3/markers to residual-deferrals.json (see dev-fixall.md); fold already merged the
436
+ # anchors into <wbs>-test-gate.findings, this carries the structured artifact too.
459
437
  - kind: shell
460
438
  options:
461
439
  command: >-
462
- [ ! -f ".spur/run/$wbs-residuals.json" ] || { echo '--- residual artifact (F96 fix targets; deferrals go to residual-deferrals.json, P3/markers only) ---'; cat ".spur/run/$wbs-residuals.json"; } >> ".spur/run/$wbs-test-gate.log"; exit 0
440
+ 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
463
441
  # R3 (0482): project the extracted gate anchors into a var so the dispatch input
464
442
  # can NAME the failing file:line, not merely point at a log. A vars template cannot
465
443
  # run a shell, so the read is an action, not an inline `$(cat ...)` substitution.
@@ -515,7 +493,7 @@ states:
515
493
  - kind: shell
516
494
  options:
517
495
  command: >-
518
- mkdir -p .spur/run; if [ -f plugins/sp/scripts/quality-gate.ts ]; then bun plugins/sp/scripts/quality-gate.ts recheck; elif Q="$(superskill script path sp quality-gate.mjs 2>/dev/null)" && [ -f "$Q" ]; then node "$Q" recheck; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
496
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/quality-gate.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/quality-gate.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S" recheck; else echo "quality gate failed closed — quality-gate script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf 'FAIL\n' > ".spur/run/$wbs-test-gate.status"; fi; exit 0
519
497
 
520
498
  - id: triage
521
499
  description: >-
@@ -535,7 +513,7 @@ states:
535
513
  - kind: shell
536
514
  options:
537
515
  command: >-
538
- mkdir -p .spur/run; if [ -f plugins/sp/scripts/task-diffstat.ts ]; then bun plugins/sp/scripts/task-diffstat.ts --spur-bin "$spurBin"; elif D="$(superskill script path sp task-diffstat.mjs 2>/dev/null)" && [ -f "$D" ]; then node "$D"; else echo "task-diffstat failed closed — task-diffstat script not found — run 'superskill install sp'" >&2; printf '{"files":0,"insertions":0,"deletions":0,"paths":[],"sensitive":true}\n' > ".spur/run/$wbs-diffstat.json"; fi; exit 0
516
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/task-diffstat.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/task-diffstat.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S" --spur-bin "$spurBin"; else echo "task-diffstat failed closed — task-diffstat script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; printf '{"files":0,"insertions":0,"deletions":0,"paths":[],"sensitive":true}\n' > ".spur/run/$wbs-diffstat.json"; fi; exit 0
539
517
  # (b)+(c) lane pre-guard BEFORE decide: a caller-set mode is projected verbatim (R2b);
540
518
  # a sensitive path or >400 changed lines pins safety (R2c) and the decide result below
541
519
  # is never consulted. A missing/malformed diffstat row (producer crashed or never ran,
@@ -561,18 +539,15 @@ states:
561
539
  - .spur/run/${vars.wbs}-diffstat.json
562
540
  - ${vars.taskSpecPath}
563
541
  resultFile: .spur/run/${vars.wbs}-triage.decision
564
- # (d) project the decision: low → fast lane; anything else (standard/high, degraded
565
- # default, missing row) leaves the mode empty → standard review path. A non-empty mode
566
- # file (caller-set or deterministic-high) is never overridden.
542
+ # (d) project the decision, then append the triage route reason (1007 R3: the
543
+ # mode-fallback shell merged into the memory-append shell — original commands in
544
+ # order, the non-empty mode file is still never overridden; the append keeps the
545
+ # failure signal of the original pair). low → fast lane; anything else (standard/high,
546
+ # degraded default, missing row) leaves the mode empty → standard review path.
567
547
  - kind: shell
568
548
  options:
569
549
  command: >-
570
- MF=".spur/run/$wbs-mode.txt"; [ -s "$MF" ] && exit 0; jq -r 'if .value == "low" then "fast" else empty end' ".spur/run/$wbs-triage.decision" 2>/dev/null > "$MF"; exit 0
571
- # R5: append the triage route reason in the shared routes-log format.
572
- - kind: shell
573
- options:
574
- command: >-
575
- m="$(cat ".spur/run/$wbs-mode.txt")"; RUN_ID="$__runId"; [ -n "$RUN_ID" ] || RUN_ID="pipeline-$wbs"; mkdir -p .spur/memory; printf '%s %s %s\n' "$RUN_ID" "$wbs" "$(jq -rn --arg m "$m" --arg c "$mode" 'if $c != "" then ($c + ":caller-set") else {"fast":"fast:triage low lane","safety":"safety:triage deterministic-high","":"safety:triage standard lane"}[$m] // "safety:triage unrecognized mode" end')" >> .spur/memory/task-pipeline-routes.log
550
+ MF=".spur/run/$wbs-mode.txt"; [ -s "$MF" ] || jq -r 'if .value == "low" then "fast" else empty end' ".spur/run/$wbs-triage.decision" 2>/dev/null > "$MF"; m="$(cat "$MF")"; RUN_ID="$__runId"; [ -n "$RUN_ID" ] || RUN_ID="pipeline-$wbs"; mkdir -p .spur/memory; printf '%s %s %s\n' "$RUN_ID" "$wbs" "$(jq -rn --arg m "$m" --arg c "$mode" 'if $c != "" then ($c + ":caller-set") else {"fast":"fast:triage low lane","safety":"safety:triage deterministic-high","":"safety:triage standard lane"}[$m] // "safety:triage unrecognized mode" end')" >> .spur/memory/task-pipeline-routes.log
576
551
  # (d) the resolved lane becomes the `mode` var for the triage → verify/review guards.
577
552
  - kind: file.read.into-var
578
553
  options:
@@ -615,7 +590,7 @@ states:
615
590
  # through the executor registry, and the runner enforces (pre-dispatch,
616
591
  # fail-closed) that a P0/P1 task's review resolves a DIFFERENT executor
617
592
  # spec than the implement stage recorded in __agentRouting_implement.
618
- input: /sp:dev-review ${vars.wbs} --auto
593
+ input: /sp:dev-review --tasks ${vars.wbs} --auto
619
594
  # The captured review answer is the run's dispatch evidence (0823 R1):
620
595
  # expectFile fails the step when no answer was captured. Quality stays with
621
596
  # the review proof digest and the verify verdict.
@@ -697,37 +672,11 @@ states:
697
672
  compareExecutorWith: implement
698
673
  timeoutMs: ${vars.stepTimeoutMs}
699
674
  expectFile: .spur/run/${vars.wbs}-verify-answer.txt
700
- # 0726 R3: hard lint gate over the verifier-owned answer — shape and
701
- # evidence-row identity, before the verdict derivation reads it.
702
- # Hard action: a malformed answer halts the sequence here instead of
703
- # poisoning the verdict parse downstream.
704
- # (d) verify-answer-lint.ts owns the answer lint; shell only resolves it.
705
- - kind: shell
706
- options:
707
- command: >-
708
- LINT_SCRIPT="plugins/sp/scripts/verify-answer-lint.ts";
709
- [ -f "$LINT_SCRIPT" ] ||
710
- LINT_SCRIPT="$(superskill script path sp verify-answer-lint.ts 2>/dev/null)";
711
- if [ -z "$LINT_SCRIPT" ] || [ ! -f "$LINT_SCRIPT" ]; then
712
- echo "verify-answer-lint: checker not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2;
713
- exit 1;
714
- fi;
715
- bun "$LINT_SCRIPT" "$wbs"
716
- --answer ".spur/run/$wbs-verify-answer.txt"
717
- --spur-bin "$spurBin"
675
+ # (d) `spur task verdict` owns the answer lint (task 1003 R2) — the shell below
676
+ # fails closed when the verifier's answer is malformed, before any verdict artifact.
718
677
  - kind: shell
719
678
  options:
720
679
  command: "$spurBin task verdict $wbs --from-answer .spur/run/$wbs-verify-answer.txt"
721
- # (d) F96 R2 (0950): residual-scan.ts owns the sweep; shell only resolves it.
722
- # ONE hard action (scan+fold): a scanner crash fails verify closed — the
723
- # verify→failed catch-all routes a missing/malformed verdict. Runs AFTER
724
- # `task verdict` and BEFORE the jq bind so a blocking residual turns PASS
725
- # into PARTIAL (fold rewrites the verdict artifact) and takes the existing
726
- # verify→test-fix edge while attempts remain.
727
- - kind: shell
728
- options:
729
- command: >-
730
- S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ ! -f "$S" ]; then echo "residual-scan failed closed — scanner not found in plugins/sp/scripts/ nor staged — run 'superskill install sp'" >&2; exit 1; fi; case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" scan "$wbs" --spur-bin "$spurBin" && "$RUNNER" "$S" fold "$wbs" --spur-bin "$spurBin"
731
680
  # (e) one jq mutation binds the verdict to the proof digest (0703 R3; runId 0730 §B.2 /
732
681
  # 0757 R4; definitionDigest 0759 R5; honest review stamp 0785 R4; soft action + hard guard).
733
682
  - kind: shell
@@ -743,9 +692,13 @@ states:
743
692
  `run.artifact` registration (0785 R3): the verify verdict is ledger-registered
744
693
  against a freshly captured proof digest — including review-completion marker
745
694
  evidence (0785 R4) — before any task record or status mutation. Post-record step
746
- conditionally syncs feature status via the bounded `feature-sync-bounded` wrapper
695
+ conditionally syncs feature status via `spur feature sync`
747
696
  (task 0411 retry-suppression) if `feature_id` is present, or appends an orphan
748
- link proposal to the run report if absent (task 0328 / ADR-0322).
697
+ link proposal to the run report if absent (task 0328 / ADR-0322). The post-record
698
+ residual sweep (0983) re-scans the task file after the verdict-proven box flips and
699
+ folds blocking leftovers into the verdict before `record → done`; a downgrade
700
+ re-records Testing from the final artifact so a failed task never keeps a stale
701
+ PASS narrative.
749
702
  onEnter:
750
703
  # 0785 R3: BOUND verify-verdict registration — FIRST action, before any task record or
751
704
  # status mutation, replacing the redundant proof.fingerprint compare (the action itself
@@ -771,7 +724,11 @@ states:
771
724
  options:
772
725
  id: task-record-transition
773
726
  executable: "${vars.spurBin}"
774
- args: ["task", "record", "${vars.wbs}", "--solution-from-diff", "--transition", "testing"]
727
+ # 0980: --no-lifecycle mirrors the wip/done hops — the pipeline run is
728
+ # already the lifecycle record, so a record-stage transition must not
729
+ # spawn a nested task-lifecycle run that outlives the pipeline as a
730
+ # `running` orphan. The target-aware check gate still runs (inline).
731
+ args: ["task", "record", "${vars.wbs}", "--solution-from-diff", "--transition", "testing", "--no-lifecycle"]
775
732
  retry:
776
733
  maxAttempts: 2
777
734
  delayMs: 2000
@@ -779,19 +736,40 @@ states:
779
736
  resultFile: .spur/run/${vars.__runId}-record-transition.status
780
737
  softFail: false
781
738
  timeoutMs: 120000
782
- # (d) feature-sync-bounded.ts owns the sync; shell adds the orphan note and fallbacks
783
- # (0411 retry-suppression; 0328 / ADR-0322). Best-effort `exit 0` — feature status sync is a
784
- # follow-up, not a completion gate; `record → done` runs `spur task check`.
785
- # 0931 R5: with deferFeatureSync "true" (parallel mode) the deferral note lands in the
786
- # task report and the sync is skipped entirely, so task branches never touch feature
787
- # corpus files; the batch orchestrator performs the deferred sync on the base ref.
788
- # The sync itself is owned by record-feature-sync.ts (ADR-115: the guard plus the old
789
- # inline chain cannot share one shell); resolution follows the standard in-repo-first,
790
- # superskill-staged fallback used by every pipeline checker.
739
+ # (d) Best-effort `exit 0` — feature status sync is a follow-up, not a completion gate;
740
+ # `record → done` runs `spur task check`. 0931 R5: with deferFeatureSync "true" (parallel
741
+ # mode) the deferral note lands in the task report and the sync is skipped entirely, so
742
+ # task branches never touch feature corpus files; the batch orchestrator performs the
743
+ # deferred sync on the base ref. 1004 R4: the sync is a bare `feature sync` — repeated-
744
+ # BLOCKED suppression (0411) now lives in the feature sync service itself, so the shell
745
+ # resolves feature_id via jq and delegates without a helper script.
791
746
  - kind: shell
792
747
  options:
793
748
  command: >-
794
- S=plugins/sp/scripts/record-feature-sync.ts; [ -f "$S" ] || S="$(superskill script path sp record-feature-sync.mjs 2>/dev/null)"; [ "$deferFeatureSync" = "true" ] && echo "feature sync deferred to batch integration" >> ".spur/run/$wbs-report.txt" || if [ -f "$S" ]; then bun "$S" --spur-bin "$spurBin"; else echo "feature sync skipped — record-feature-sync not found in plugins/sp/scripts/ nor staged" >> ".spur/run/$wbs-report.txt"; fi; exit 0
749
+ if [ "$deferFeatureSync" = "true" ]; then echo "feature sync deferred to batch integration" >> ".spur/run/$wbs-report.txt"; else FID="$($spurBin task show $wbs --json 2>/dev/null | jq -r '(.feature_id // .frontmatter.feature_id) // empty' 2>/dev/null)"; if [ -n "$FID" ]; then $spurBin feature sync "$FID" --json || echo "feature sync failed — re-run: $spurBin feature sync $FID" >> ".spur/run/$wbs-report.txt"; else echo "Orphan task $wbs — no feature_id linked — proposal: consider linking to a parent feature." >> ".spur/run/$wbs-report.txt"; fi; fi; exit 0
750
+ # (d) F96 (0983): residual-scan.ts owns the sweep; shell only resolves it. The
751
+ # scan moved here from verify: it must read the task file AFTER `task record`
752
+ # flipped the verdict-proven Requirement/AC boxes (0692), or a proven-but-unticked
753
+ # box folds every good run to PARTIAL and the done guard is unreachable (0967).
754
+ # Classification unchanged: any box still unchecked post-record (unproven R/AC,
755
+ # unfinished Plan) stays blocking and fails the record → done guard closed.
756
+ # ONE hard action (scan+fold): a scanner crash fails record closed.
757
+ - kind: shell
758
+ options:
759
+ command: >-
760
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/residual-scan.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/residual-scan.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ ! -f "$S" ]; then echo "residual-scan failed closed — scanner not found in plugins/sp/scripts/ nor staged — run 'superskill install sp --marketplace gobing-ai/spur'" >&2; exit 1; fi; "$RUNNER" "$S" scan "$wbs" --spur-bin "$spurBin" && "$RUNNER" "$S" fold "$wbs" --spur-bin "$spurBin"
761
+ # (e) F96 R5 (0983): a sweep downgrade must reach the task record — re-record from
762
+ # the FINAL (post-fold) artifact so Testing carries the downgraded verdict; a failed
763
+ # task must not retain a stale PASS Testing narrative. Soft (exit 0): the downgrade
764
+ # itself already fails the record → done guard; a re-record failure prints its
765
+ # re-run command and the failed state renders the recovery report.
766
+ # 0980: --no-lifecycle for the same orphan reason as the main record command —
767
+ # inert today (the task is already at testing, so this is a same-status no-op),
768
+ # but it keeps the no-nested-lifecycle invariant if the flow shifts.
769
+ - kind: shell
770
+ options:
771
+ command: >-
772
+ verdict="$(jq -r .verdict .spur/run/$wbs-verdict.json 2>/dev/null)"; if [ -n "$verdict" ] && [ "$verdict" != PASS ]; then $spurBin task record $wbs --solution-from-diff --transition testing --no-lifecycle || echo "post-downgrade re-record failed — re-run: $spurBin task record $wbs" >&2; fi; exit 0
795
773
 
796
774
  - id: done
797
775
  description: >
@@ -805,7 +783,7 @@ states:
805
783
  - kind: shell
806
784
  options:
807
785
  command: >-
808
- S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" settle "$wbs" --spur-bin "$spurBin" || echo "residual-settle failed — re-run: residual-scan settle $wbs" >&2; else echo "residual-scan not staged — settle skipped — re-run: residual-scan settle $wbs" >&2; fi; exit 0
786
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/residual-scan.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/residual-scan.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S" settle "$wbs" --spur-bin "$spurBin" || echo "residual-settle failed — re-run: residual-scan settle $wbs" >&2; else echo "residual-scan not staged — settle skipped — re-run: residual-scan settle $wbs" >&2; fi; exit 0
809
787
  # (c) command.gate owns the done transition with classified transient retry.
810
788
  - kind: command.gate
811
789
  options:
@@ -819,10 +797,9 @@ states:
819
797
  resultFile: .spur/run/${vars.__runId}-done-transition.status
820
798
  softFail: false
821
799
  timeoutMs: 120000
822
- - kind: note
823
- options:
824
- message: "Pipeline complete for task ${vars.wbs} (done gate cleared)."
825
800
  # (e) advisory terminal checkpoint, one printf (0711 R1–R3; binding corrected 0784 R4).
801
+ # 1007 R3: the former done note ("Pipeline complete ...") is dropped — the checkpoint
802
+ # below is the terminal record.
826
803
  - kind: shell
827
804
  options:
828
805
  command: >-
@@ -852,24 +829,22 @@ states:
852
829
  - kind: shell
853
830
  options:
854
831
  command: >-
855
- S=plugins/sp/scripts/residual-scan.ts; [ -f "$S" ] || S="$(superskill script path sp residual-scan.mjs 2>/dev/null)"; if [ -f "$S" ]; then case "$S" in *.mjs) RUNNER=node ;; *) RUNNER=bun ;; esac; "$RUNNER" "$S" report "$wbs" --spur-bin "$spurBin" || echo "residual-report failed — re-run: residual-scan report $wbs" >&2; else echo "residual-scan not staged — report skipped — re-run: residual-scan report $wbs" >&2; fi; exit 0
832
+ eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/residual-scan.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/residual-scan.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; if [ -f "$S" ]; then "$RUNNER" "$S" report "$wbs" --spur-bin "$spurBin" || echo "residual-report failed — re-run: residual-scan report $wbs" >&2; else echo "residual-scan not staged — report skipped — re-run: residual-scan report $wbs" >&2; fi; exit 0
856
833
 
857
834
  - id: cancelled
858
835
  description: Terminal — pipeline cancelled by operator at the approval gate (R1).
859
836
 
860
837
  transitions:
861
- # ── precheck: size PASS + task check → implement; else → failed ──
838
+ # ── precheck: task check --precheck (size + evidence + four-layer, 1002 R4) → implement; ──
839
+ # else → failed. The flag folds the two deleted precheck scripts into one fail-closed
840
+ # guard: any size/evidence/structural error exits 1 and the fallback edge terminates.
862
841
  - from: precheck
863
842
  to: implement
864
843
  description: Deterministic size, evidence, and task checks are green — begin implementation.
865
- # (warn) 5 commands: named size/evidence status reads + task check (legibility, 0874).
866
844
  guard:
867
845
  kind: shell
868
846
  options:
869
- command: >-
870
- size_status="$(cat .spur/run/$wbs-precheck-size.status 2>/dev/null)";
871
- evidence_status="$(cat .spur/run/$wbs-precheck-evidence.status 2>/dev/null)";
872
- test "$size_status" = PASS && test "$evidence_status" = PASS && $spurBin task check $wbs
847
+ command: '$spurBin task check $wbs --precheck'
873
848
  - from: precheck
874
849
  to: failed
875
850
  terminalReason: failed-check
@@ -1163,6 +1138,6 @@ transitions:
1163
1138
  - from: record
1164
1139
  to: failed
1165
1140
  terminalReason: failed-check
1166
- description: Task check failed or proof evidence missing/malformed/mismatched — block before done.
1141
+ description: Task check failed, a post-record residual downgrade, or proof evidence missing/malformed/mismatched — block before done.
1167
1142
  guard:
1168
1143
  kind: always