@gobing-ai/spur 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/config/pipeline-budgets.json +2 -2
  3. package/config/rules/boundary/config-loading-ownership.yaml +1 -0
  4. package/config/rules/boundary/sp-plugin-standalone.yaml +1 -1
  5. package/config/rules/boundary/sp-script-placement.yaml +1 -1
  6. package/config/rules/docs/sourced-api-claims.yaml +45 -7
  7. package/config/rules/strict/runtime-boundaries.yaml +40 -1
  8. package/config/rules/structure/protected-files.yaml +1 -1
  9. package/config/rules/surface/check-cli-surface.yaml +33 -0
  10. package/config/rules/typescript/no-debugger.yaml +3 -0
  11. package/config/workflow-candidates.json +2 -2
  12. package/config/workflows/feature-verification.yaml +6 -11
  13. package/config/workflows/history-anatomy.yaml +14 -28
  14. package/config/workflows/idea-pipeline.yaml +6 -19
  15. package/config/workflows/pr-review.yaml +9 -16
  16. package/config/workflows/task-pipeline.yaml +16 -23
  17. package/config/workflows/wrapup-pipeline.yaml +21 -63
  18. package/package.json +3 -3
  19. package/plugins/sp/README.md +70 -37
  20. package/plugins/sp/agents/super-planner.md +5 -5
  21. package/plugins/sp/agents/super-reviewer.md +2 -2
  22. package/plugins/sp/commands/dev-changelog.md +1 -1
  23. package/plugins/sp/commands/dev-daily.md +1 -1
  24. package/plugins/sp/commands/dev-pr-review.md +1 -1
  25. package/plugins/sp/commands/dev-review-session.md +1 -1
  26. package/plugins/sp/commands/dev-runall.md +4 -4
  27. package/plugins/sp/commands/dev-verify.md +4 -6
  28. package/plugins/sp/commands/dev-verifyall.md +4 -5
  29. package/plugins/sp/hooks/hooks.json +11 -1
  30. package/plugins/sp/lib/context-post-tool.ts +1 -1
  31. package/plugins/sp/lib/context-session-start.ts +1 -1
  32. package/plugins/sp/lib/context-session-stop.ts +1 -1
  33. package/plugins/sp/lib/destructive-policy.ts +65 -1
  34. package/plugins/sp/plugin.json +2 -5
  35. package/plugins/sp/{hooks → scripts/hooks}/agent-lifecycle.ts +1 -1
  36. package/plugins/sp/scripts/hooks/careful-guard.ts +94 -0
  37. package/plugins/sp/{hooks → scripts/hooks}/context-post-tool.ts +2 -2
  38. package/plugins/sp/{hooks → scripts/hooks}/context-session-start.ts +1 -1
  39. package/plugins/sp/{hooks → scripts/hooks}/context-session-stop.ts +1 -1
  40. package/plugins/sp/{hooks → scripts/hooks}/fleet-guest-stop.ts +6 -4
  41. package/plugins/sp/{hooks → scripts/hooks}/task-write-guard.ts +38 -21
  42. package/plugins/sp/skills/code-implementation/SKILL.md +1 -1
  43. package/plugins/sp/skills/code-verification/SKILL.md +8 -8
  44. package/plugins/sp/skills/code-verification/references/secu-review.md +4 -3
  45. package/plugins/sp/skills/code-verification/references/verdict-schema.md +9 -1
  46. package/plugins/sp/skills/daily-summary/SKILL.md +4 -5
  47. package/plugins/sp/skills/dogfood-testing/SKILL.md +9 -9
  48. package/plugins/sp/skills/dogfood-testing/references/report-template.md +1 -1
  49. package/plugins/sp/skills/history-anatomy/references/modes.md +2 -2
  50. package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
  51. package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
  52. package/plugins/sp/skills/pr-reviewing/SKILL.md +14 -15
  53. package/plugins/sp/skills/session-review/SKILL.md +3 -3
  54. package/plugins/sp/skills/source-driven-development/SKILL.md +7 -4
  55. package/plugins/sp/skills/spur-check/SKILL.md +14 -13
  56. package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
  57. package/plugins/sp/skills/spur-cli/references/agent.md +12 -0
  58. package/plugins/sp/skills/spur-cli/references/builder.md +27 -6
  59. package/plugins/sp/skills/spur-cli/references/features.md +6 -1
  60. package/plugins/sp/skills/spur-cli/references/history.md +3 -0
  61. package/plugins/sp/skills/spur-cli/references/self.md +5 -3
  62. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +3 -0
  63. package/plugins/sp/skills/spur-cli/references/tasks.md +13 -3
  64. package/plugins/sp/skills/spur-cli/references/workflows.md +36 -1
  65. package/plugins/sp/skills/spur-dev/SKILL.md +1 -1
  66. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +1 -1
  67. package/plugins/sp/skills/spur-dev/references/dev-operations.md +12 -12
  68. package/plugins/sp/skills/spur-dev/references/execution-batch-report.md +10 -11
  69. package/plugins/sp/skills/spur-dev/references/execution-batch.md +16 -17
  70. package/plugins/sp/skills/spur-dev/references/execution-parallel-isolation.md +1 -1
  71. package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +8 -11
  72. package/plugins/sp/skills/spur-dev/references/execution-worktree-setup.md +6 -8
  73. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
  74. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +33 -40
  75. package/plugins/sp/skills/spur-dev/references/structured-trace-emission.md +24 -24
  76. package/plugins/sp/skills/spur-doctor/SKILL.md +5 -4
  77. package/spur.js +41901 -30598
  78. package/config/plugin-scripts.json +0 -116
  79. package/config/script-placement-baseline.json +0 -33
  80. package/plugins/sp/hooks/careful-guard.ts +0 -74
  81. package/plugins/sp/hooks/pi/guard-extension.ts +0 -304
  82. package/plugins/sp/lib/dogfood-pipeline.ts +0 -265
  83. package/plugins/sp/lib/dogfood-report.ts +0 -278
  84. package/plugins/sp/lib/history-anatomy.generated.d.mts +0 -112
  85. package/plugins/sp/lib/history-anatomy.generated.mjs +0 -691
  86. package/plugins/sp/lib/idea-handoff.generated.d.mts +0 -17
  87. package/plugins/sp/lib/idea-handoff.generated.mjs +0 -1446
  88. package/plugins/sp/lib/inline-run-app.ts +0 -68
  89. package/plugins/sp/lib/inline-run.generated.d.mts +0 -37
  90. package/plugins/sp/lib/inline-run.generated.mjs +0 -3103
  91. package/plugins/sp/lib/plan-projection.generated.d.mts +0 -197
  92. package/plugins/sp/lib/plan-projection.generated.mjs +0 -982
  93. package/plugins/sp/lib/quality-gate.generated.d.mts +0 -139
  94. package/plugins/sp/lib/quality-gate.generated.mjs +0 -30510
  95. package/plugins/sp/lib/residual-scan.generated.d.mts +0 -93
  96. package/plugins/sp/lib/residual-scan.generated.mjs +0 -383
  97. package/plugins/sp/lib/run-summary-core.ts +0 -225
  98. package/plugins/sp/lib/spur-bin.ts +0 -36
  99. package/plugins/sp/lib/step-profile.generated.d.mts +0 -71
  100. package/plugins/sp/lib/step-profile.generated.mjs +0 -174
  101. package/plugins/sp/lib/transcript.ts +0 -112
  102. package/plugins/sp/scripts/batch-plan.mjs +0 -1096
  103. package/plugins/sp/scripts/batch-plan.ts +0 -145
  104. package/plugins/sp/scripts/batch-preflight.mjs +0 -423
  105. package/plugins/sp/scripts/batch-preflight.ts +0 -270
  106. package/plugins/sp/scripts/commit-guard.mjs +0 -226
  107. package/plugins/sp/scripts/commit-guard.ts +0 -248
  108. package/plugins/sp/scripts/daily-summary/daily-summary.mjs +0 -626
  109. package/plugins/sp/scripts/daily-summary/daily-summary.ts +0 -855
  110. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.mjs +0 -211
  111. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +0 -110
  112. package/plugins/sp/scripts/dogfood-testing/validate-report.mjs +0 -282
  113. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +0 -98
  114. package/plugins/sp/scripts/feature-verification-steps.mjs +0 -82
  115. package/plugins/sp/scripts/feature-verification-steps.ts +0 -164
  116. package/plugins/sp/scripts/history-anatomy-cache.mjs +0 -931
  117. package/plugins/sp/scripts/history-anatomy-cache.ts +0 -247
  118. package/plugins/sp/scripts/idea-handoff.mjs +0 -32
  119. package/plugins/sp/scripts/idea-handoff.ts +0 -47
  120. package/plugins/sp/scripts/inline-run-dispatch.mjs +0 -131
  121. package/plugins/sp/scripts/inline-run-dispatch.ts +0 -115
  122. package/plugins/sp/scripts/inline-run-setup.mjs +0 -746
  123. package/plugins/sp/scripts/inline-run-setup.ts +0 -198
  124. package/plugins/sp/scripts/persist-out-check.mjs +0 -217
  125. package/plugins/sp/scripts/persist-out-check.ts +0 -249
  126. package/plugins/sp/scripts/pr-reviewing.mjs +0 -712
  127. package/plugins/sp/scripts/pr-reviewing.ts +0 -952
  128. package/plugins/sp/scripts/quality-gate.mjs +0 -30491
  129. package/plugins/sp/scripts/quality-gate.ts +0 -80
  130. package/plugins/sp/scripts/residual-scan.mjs +0 -634
  131. package/plugins/sp/scripts/residual-scan.ts +0 -248
  132. package/plugins/sp/scripts/run-summary.mjs +0 -758
  133. package/plugins/sp/scripts/run-summary.ts +0 -107
  134. package/plugins/sp/scripts/script-root.mjs +0 -129
  135. package/plugins/sp/scripts/script-root.ts +0 -199
  136. package/plugins/sp/scripts/session-timeline.mjs +0 -359
  137. package/plugins/sp/scripts/session-timeline.ts +0 -190
  138. package/plugins/sp/scripts/task-diffstat.mjs +0 -181
  139. package/plugins/sp/scripts/task-diffstat.ts +0 -219
  140. package/plugins/sp/scripts/workflow-step-profile.mjs +0 -338
  141. package/plugins/sp/scripts/workflow-step-profile.ts +0 -165
  142. package/plugins/sp/scripts/wrapup-drift-probe.mjs +0 -190
  143. package/plugins/sp/scripts/wrapup-drift-probe.ts +0 -261
  144. package/plugins/sp/scripts/wrapup-steps.mjs +0 -627
  145. package/plugins/sp/scripts/wrapup-steps.ts +0 -891
@@ -7,7 +7,7 @@
7
7
  "plugins": [
8
8
  {
9
9
  "name": "sp",
10
- "version": "0.4.7",
10
+ "version": "0.4.9",
11
11
  "source": "./plugins/sp"
12
12
  }
13
13
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "generatedAt": "2026-08-20T00:00:00.000Z",
4
- "note": "Per-pipeline model-query + wall-clock cost budgets (task 0607 R3). modelQueries anchors the live workflow definitions' query lists — the SSOT, extracted by extractResolvedWorkflowFacts and guarded by composition-baseline.test.ts (0775 retired the snapshot this file previously anchored to). wallClockMs is a gross-regression ceiling anchored to measured real-run data (R5): the gate compares the median-of-sane terminal-run wall-clock against it. A null budget is unenforced until measured — never treated as 0. Raising a numeric budget requires a fresh recorded decision in the same commit (config/pipeline-budgets.json vs git HEAD); the check-pipeline-budgets gate fails a silent raise by name.",
4
+ "note": "Per-pipeline model-query + wall-clock cost budgets (task 0607 R3). modelQueries anchors the live workflow definitions' query lists — the SSOT, extracted by extractResolvedWorkflowFacts and guarded by composition-baseline.test.ts (0775 retired the snapshot this file previously anchored to). wallClockMs is a gross-regression ceiling anchored to measured real-run data (R5): the gate compares the median-of-sane terminal-run wall-clock against it. A null budget is unenforced until measured — never treated as 0. Raising a numeric budget requires a fresh recorded decision in the same commit (config/pipeline-budgets.json vs git HEAD); the `spur workflow cost --budget` gate fails a silent raise by name.",
5
5
  "budgets": {
6
6
  "task-pipeline": {
7
7
  "modelQueries": 4,
@@ -39,7 +39,7 @@
39
39
  "modelQueries": 3,
40
40
  "wallClockMs": null,
41
41
  "tokenCostUsd": null,
42
- "source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0. 0920 recount 2026-09-23: 4 -> 3 — the resolve-scope model hop was removed; scope/window validation is deterministic in the history-anatomy-cache paths command.",
42
+ "source": "Coverage entry (0826 R2): the live definition's model-query count (extractResolvedWorkflowFacts, 2026-09-11). No real-run measurement yet: wall-clock and cost are unenforced until measured, never 0. 0920 recount 2026-09-23: 4 -> 3 — the resolve-scope model hop was removed; scope/window validation is deterministic in the `spur history anatomy paths` op (history-anatomy-cache before script-absorption PR-6).",
43
43
  "decision": null
44
44
  },
45
45
  "wayfinder-resolution": {
@@ -67,6 +67,7 @@ rules:
67
67
  exclude:
68
68
  - "packages/config/src/**"
69
69
  - "apps/cli/src/index.ts"
70
+ - "apps/cli/src/workflow-transport.ts" # boot-free composition root of `spur workflow inline|commit-guard` (PR-4)
70
71
  - "apps/server/src/serve.ts"
71
72
  - "apps/server/src/context.ts"
72
73
  - "**/tests/**"
@@ -12,7 +12,7 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
12
12
  # - plugins/sp/hooks/**, plugins/sp/scripts/**, plugins/sp/lib/** may value-import
13
13
  # only `node:*` builtins and relative paths (vendored helpers live in plugins/sp/lib/).
14
14
  # - `import type` / `export type` from any package is fine — erased before bundling
15
- # (e.g. inline-run-setup.ts's type-only import from @gobing-ai/app).
15
+ # (a type-only import from @gobing-ai/app is safe).
16
16
  # - This rule is the author-time tripwire over DIRECT imports; the transitive closure
17
17
  # and the real `superskill install` path are checked by `bun run plugin-smoke`, and
18
18
  # script-contract-check Rule 5 (manifest-aware) fails the spur-check gate.
@@ -6,7 +6,7 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
6
6
  # stays in spur-check-feature.
7
7
  rules:
8
8
  - id: sp-script-placement
9
- description: "Plugins/sp scripts must honor the ADR-130 placement contract (glue budget, no db imports, no corpus parsing, no noun clash); baseline config/script-placement-baseline.json can only shrink."
9
+ description: "Plugins/sp scripts must honor the ADR-130 placement contract (glue budget, no db imports, no corpus parsing, no noun clash, ADR-129 hook layout); any finding fails (task 1213 retired the baseline ledger)."
10
10
  severity: error
11
11
  evaluator:
12
12
  type: exit-code
@@ -29,12 +29,23 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
29
29
  # citation (URL or path:line) AND a confidence level (HIGH/MEDIUM/LOW) — is
30
30
  # owned by the sp-source-driven-development skill and verified in SECUA review
31
31
  # (code-verification secu-review checklist). These rules are its deterministic
32
- # backstop: the two `cited-*` rules cover the citation half, and
33
- # `cited-api-claims-confidence` covers the level half. All are severity `info`,
32
+ # backstop: the three `cited-*` rules cover the citation half, and
33
+ # `cited-api-claims-confidence` covers the level half.
34
+ # `cited-high-confidence` covers the HONESTY half — the level is a claim like
35
+ # any other, so the one level that asserts "verified this session" must show the
36
+ # source it was verified against. MEDIUM (recalled, plausibly stale) and LOW
37
+ # (memory only) require no anchor by contract and are deliberately not flagged.
38
+ # All are severity `info`,
34
39
  # and the category is deliberately NOT in `recommended-pre-check` — it surfaces
35
40
  # findings for review without reddening gates. The 2026-10-12 audit below settled
36
41
  # the promotion question: the residual findings stay a review-surface concern
37
42
  # (SECUA checklist), not a gate one — do not add `- docs` to that preset.
43
+ #
44
+ # Fenced-code behavior (measured 2026-10-16, `spur rule run --file … --json` over a
45
+ # probe doc): code fences are NOT skipped by the regex evaluator — every rule here
46
+ # fires on a matching line inside a fence. The earlier note claiming fenced lines
47
+ # were "out of regex reach" was wrong; fence noise is one more reason these stay
48
+ # `info` and ad hoc rather than gated.
38
49
  include:
39
50
  - "docs/**/*.md"
40
51
  - "plugins/sp/skills/**/references/**/*.md"
@@ -66,11 +77,12 @@ rules:
66
77
  # contains a semver-ish token. Lookarounds exclude IPs (127.0.0.1),
67
78
  # longer dotted numerics, a heading's section number (`### 1.0.1 Title`),
68
79
  # a document-version metadata line (`version: 1.69.0`) and a `§`-numbered
69
- # section reference (`§7.3.1`) — none of which is an external claim;
70
- # fenced-code lines are out of regex reach — that residual noise is why
71
- # this is info, not warning. The `§` guard sits on the token itself, not on
72
- # the line, so a line carrying both a section reference and a real version
73
- # still fires on the version.
80
+ # section reference (`§7.3.1`) — none of which is an external claim.
81
+ # Fenced code and command examples can legitimately carry bare versions and
82
+ # are NOT skipped by the evaluator (measured 2026-10-16) — that residual
83
+ # noise, with the above, is why this is info, not warning. The `§` guard sits
84
+ # on the token itself, not on the line, so a line carrying both a section
85
+ # reference and a real version still fires on the version.
74
86
  pattern: "^(?!.*(?:https?://|(?:[\\w.-]+/)+[\\w.-]+:\\d+))(?!\\s*#{1,6}\\s+\\d+\\.\\d+\\.\\d+)(?!\\s*[\\w-]+:\\s*\\d+\\.\\d+\\.\\d+\\s*$).*(?<![\\d.§])\\d+\\.\\d+\\.\\d+(?!\\.\\d)"
75
87
  - id: cited-api-claims
76
88
  description: >
@@ -103,3 +115,29 @@ rules:
103
115
  # `cited-api-claims` exactly, so the two rules never disagree about which
104
116
  # lines are claims.
105
117
  pattern: "^(?!.*\\b(?:HIGH|MEDIUM|LOW)\\b).*\\b(?:deprecated (?:since|in|as of)|introduced in|added in|available since|stable since)\\b"
118
+ - id: cited-high-confidence
119
+ description: >
120
+ A line stating HIGH confidence about an external API/library claim must
121
+ carry a source citation anchor on the same line — URL or repo path:line.
122
+ The claim contract (sp-source-driven-development) defines HIGH as
123
+ "verified against the pinned version's docs/source THIS SESSION", so an
124
+ uncited HIGH is the one level that cannot be honest: MEDIUM is recalled and
125
+ plausibly stale, LOW is memory only, and both are explicitly allowed
126
+ without a source (LOW must never be presented as fact — that stays a review
127
+ judgment, not a regex). Scoped to the same claim verbs as
128
+ `cited-api-claims`, so the two rules agree on which lines are claims: a
129
+ decision record's own `Confidence:` grade (the brainstorm family) is a
130
+ different contract and is deliberately out of scope. Pairs with
131
+ `cited-api-claims-confidence`, which catches a claim line carrying no level
132
+ at all.
133
+ severity: info
134
+ evaluator:
135
+ type: regex
136
+ config:
137
+ mode: forbid
138
+ # Fires when a claim line names HIGH but carries no anchor. The anchor
139
+ # vocabulary is identical to its siblings (URL or `path:line`), so one
140
+ # line cannot read as cited for one rule and uncited for another. The level
141
+ # is asserted with a lookahead so either prose order matches — `(HIGH)` after
142
+ # the claim (the usual form) and `HIGH — <claim>` both count.
143
+ pattern: "^(?!.*(?:https?://|(?:[\\w.-]+/)+[\\w.-]+:\\d+))(?=.*\\bHIGH\\b).*\\b(?:deprecated (?:since|in|as of)|introduced in|added in|available since|stable since)\\b"
@@ -37,6 +37,13 @@ rules:
37
37
  - "apps/desktop/src/server-process.ts"
38
38
 
39
39
  # Low-level system primitives:
40
+ # `spur builder pr` spine (script-absorption PR-7, moved from plugins/sp/scripts/pr-reviewing.ts):
41
+ # every git/gh call goes through ONE synchronous, test-injectable CommandRunner seam
42
+ # (`setCommandRunner`); the spine is synchronous end to end (wait polls with a sync sleep).
43
+ # The ts-runtime sync executors cannot stand in: NodeSyncProcessExecutor maps a spawn
44
+ # failure (gh/git missing) to a bare exit 1 and drops the reason the spine reports, and
45
+ # both strip the final newline. Output bytes are pinned by the PR-7 golden.
46
+ - "packages/app/src/services/pr-review/index.ts"
40
47
  - "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)
41
48
  # The feature-verification pass runs one long command with stdout+stderr merged onto the
42
49
  # run's single log fd and a 4 h ceiling (the frozen contract from task 0915: `safe argv
@@ -44,6 +51,13 @@ rules:
44
51
  # and exposes no timeout, so it cannot reproduce either half (task 1176 R2; same class as
45
52
  # the quality-gate exemption above).
46
53
  - "packages/app/src/workflow/feature-verification-run.ts"
54
+ # `spur task wrapup` steps (script-absorption PR-5, plan §3.4), pinned to the retired plugin
55
+ # scripts' golden output by apps/cli/tests/script-absorption-pr5-parity.test.ts. The feature gate
56
+ # (`sh -c`) and `task resolve` run with stdio/stderr INHERITED so their output streams into the
57
+ # workflow run log in order, and every step is synchronous; ProcessExecutor captures the streams
58
+ # separately and cannot inherit them (same class as the quality-gate exemption above).
59
+ - "packages/app/src/workflow/wrapup/steps.ts"
60
+ - "packages/app/src/workflow/wrapup/drift-probe.ts" # sync nested `spur task show` reads beside steps.ts (same exemption)
47
61
 
48
62
  - id: no-direct-fs-io
49
63
  description: "Prefer ts-runtime's FileSystem seam for fs IO."
@@ -66,6 +80,15 @@ rules:
66
80
 
67
81
  # Low-level system primitives (O_EXCL locks, FD byte-tailing, FS watcher, atomic registry, Vite glob fallback):
68
82
  - "packages/domain/src/planning/locks.ts" # POSIX atomic O_EXCL file locks
83
+ # Script-absorption PR-6: synchronous op modules whose file bytes are pinned by the
84
+ # PR-6 golden (apps/cli/tests/script-absorption-pr6). They keep the retired scripts'
85
+ # sync node:fs reads/writes (atomic publish rename, porcelain baselines, env/report
86
+ # writes, transcript and progress reads, the daily summary file + latest.json pointer);
87
+ # the async FileSystem seam would turn every op async and reorder their output.
88
+ - "packages/app/src/services/history-anatomy-cli.ts"
89
+ - "packages/app/src/services/session-timeline.ts"
90
+ - "packages/app/src/workflow/run-summary-cli.ts"
91
+ - "packages/app/src/services/daily-summary.ts"
69
92
  - "packages/domain/src/retention.ts" # recursive backup-dir reclamation + mtime stat (task 0622 R8); ts-runtime FileSystem seam has no recursive dir remove
70
93
  - "packages/app/src/services/token-ledger-service.ts" # FD byte-window log tailing
71
94
  - "packages/app/src/services/token-ledger-watcher.ts" # node:fs watch() live watcher
@@ -78,11 +101,27 @@ rules:
78
101
  - "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)
79
102
  - "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
80
103
  - "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
104
+ # Inline-driver transports (script-absorption PR-4, `spur workflow inline|commit-guard`): moved
105
+ # verbatim from the plugin scripts with their golden output pinned; synchronous probes and
106
+ # atomic tmp+rename snapshot writes inside one short-lived CLI process.
107
+ - "packages/app/src/workflow/commit-guard.ts" # .spur/run/<run>-tree-start.json atomic snapshot + target conflict-marker reads
108
+ - "packages/app/src/workflow/persist-check.ts" # recursive evidence-tree listing + byte comparison of both trees
109
+ - "packages/app/src/workflow/run-summary-render.ts" # close-step .spur/run/<run>-summary.{md,json} write (1146 R1)
110
+ - "packages/app/src/workflow/transcript.ts" # read-only host-transcript resolution (existsSync/readdirSync)
81
111
  # commands/workflow.ts was split per verb (commands/workflow/<verb>.ts); the FD tail lives in trace.ts.
82
112
  - "apps/cli/src/commands/workflow/trace.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
83
113
  - "apps/web/src/modules/discover.ts" # Vite/Astro module scanner fallback under bun test
84
- - "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)
114
+ - "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 (task 1006 R1; `spur task gate` since script-absorption PR-3; mirrors history-anatomy.ts)
115
+ - "packages/app/src/workflow/wrapup/steps.ts" # `spur task wrapup` steps (script-absorption PR-5): sync status/metrics appends and run-artifact writes byte-pinned to the retired plugin scripts' golden output (apps/cli/tests/script-absorption-pr5-parity.test.ts); the FileSystem seam is async and has no append
116
+ - "packages/app/src/workflow/wrapup/drift-probe.ts" # drift-probe step beside steps.ts (same exemption)
117
+ # Script-absorption PR-3: the residual sweep and triage diffstat glue moved here from the retired
118
+ # plugin scripts (`spur task residual` / `spur task diffstat`). Same class as quality-gate.ts:
119
+ # synchronous `wx`/tmp+rename artifact writes, mtime-ordered verdict copies, and an fstat(1)
120
+ # dev/ino identity check (1067 R3) that the async FileSystem seam cannot express.
121
+ - "packages/app/src/services/residual-scan-run.ts"
122
+ - "packages/app/src/workflow/task-diffstat.ts"
85
123
  - "packages/app/src/workflow/feature-verification-run.ts" # the pass opens the run's single merged log fd (`openSync(path,'a')`) and mkdirs the run dir beside the receipt writer, exactly as the plugin entry did before the move; the fd cannot be expressed through the FileSystem seam (task 1176 R2; same class as the quality-gate exemption above)
124
+ - "packages/app/src/services/pr-review/index.ts" # `spur builder pr` (PR-7): sync --status-file verdict writes and the AGENTS.md review-rules probe inside the synchronous spine (same exemption as its process seam above)
86
125
  - "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)
87
126
  - "packages/app/src/services/durable-plane-ignore.ts" # .git/info/exclude append moved verbatim out of run-storage.ts to break an import cycle (same exemption)
88
127
 
@@ -42,7 +42,7 @@ rules:
42
42
  - "apps/desktop/resources/"
43
43
  # `apps/cli/plugins/` is the same kind of gitignored build:bundle output — a staged
44
44
  # npm copy of `plugins/`, itself outside the include scope. Minified generated libs
45
- # there trip the api-key shape (0976: HEAD's inline-run.generated.mjs fires too).
45
+ # there tripped the api-key shape (0976; the generated libs were retired by script-absorption PR-6).
46
46
  - "apps/cli/plugins/"
47
47
 
48
48
  - id: no-unsafe-git-commands
@@ -28,6 +28,8 @@ rules:
28
28
  exclude:
29
29
  # Per-noun shared.ts holds helpers used by 2+ verbs; it registers nothing.
30
30
  - "apps/cli/src/commands/*/shared.ts"
31
+ # Byte-exact stdout/stderr writer for the absorbed pipeline steps (script-absorption PR-5); registers nothing.
32
+ - "apps/cli/src/commands/task/step-output.ts"
31
33
  evaluator:
32
34
  type: rg
33
35
  config:
@@ -51,6 +53,37 @@ rules:
51
53
  - "apps/cli/src/commands/agent/loop.ts"
52
54
  - "apps/cli/src/commands/agent/start.ts"
53
55
  - "apps/cli/src/commands/agent/stop.ts"
56
+ # Absorbed pipeline steps (script-absorption PR-5): the app operation renders the golden-pinned
57
+ # text/JSON (planning-preflight.ts JSON.stringify for `task preflight --json`, batch-plan.ts for
58
+ # `task batch-plan`); wrapup, feature verify/handoff declare no --json. step-output.ts writes bytes.
59
+ - "apps/cli/src/commands/task/batch-plan.ts"
60
+ - "apps/cli/src/commands/task/preflight.ts"
61
+ - "apps/cli/src/commands/task/step-output.ts"
62
+ - "apps/cli/src/commands/task/wrapup.ts"
63
+ - "apps/cli/src/commands/feature/handoff.ts"
64
+ - "apps/cli/src/commands/feature/verify.ts"
65
+ # commit-guard declares no --json: its {staged, foreign} / {foreign} lines are rendered by
66
+ # @gobing-ai/spur-app/commit-guard (byte-identical to the retired script, PR-4 golden).
67
+ - "apps/cli/src/commands/workflow/commit-guard.ts"
68
+ # Pipeline-internal task verbs (script-absorption PR-3) declare no --json: their contract is
69
+ # the .spur/run artifact they write (gate status/receipt, residuals.json, diffstat.json) and
70
+ # the exit code; the gate's own status line is serialized by the app service.
71
+ - "apps/cli/src/commands/task/gate.ts"
72
+ - "apps/cli/src/commands/task/residual.ts"
73
+ - "apps/cli/src/commands/task/diffstat.ts"
74
+ # Absorbed measurement/report verbs (script-absorption PR-6): the app module serializes the
75
+ # golden-pinned JSON (step-profile-cli for `workflow profile --json`, run-summary-cli for
76
+ # `workflow summary`, session-timeline for `history timeline`, history-anatomy-cli for the
77
+ # anatomy ops); `history summary` writes Markdown and declares no --json.
78
+ - "apps/cli/src/commands/workflow/profile.ts"
79
+ - "apps/cli/src/commands/workflow/summary.ts"
80
+ - "apps/cli/src/commands/history/anatomy.ts"
81
+ - "apps/cli/src/commands/history/timeline.ts"
82
+ - "apps/cli/src/commands/history/summary.ts"
83
+ # Absorbed dogfood / PR-review spines (script-absorption PR-7): --json is rendered by
84
+ # @gobing-ai/spur-app/dogfood and @gobing-ai/spur-app/pr-review (JSON.stringify), not the CLI envelope.
85
+ - "apps/cli/src/commands/agent/dogfood.ts"
86
+ - "apps/cli/src/commands/builder/pr.ts"
54
87
  evaluator:
55
88
  type: rg
56
89
  config:
@@ -14,6 +14,9 @@ include:
14
14
  - "scripts/**/*.ts"
15
15
  exclude:
16
16
  - "**/tests/**"
17
+ # The PR-review hygiene scanner matches the word in diff text (a /\bdebugger\b/ WARN pattern);
18
+ # it holds no statement. Biome noDebugger still guards the file (script-absorption PR-7).
19
+ - "packages/app/src/services/pr-review/index.ts"
17
20
  rules:
18
21
  - id: no-debugger-statement
19
22
  description: >
@@ -7,7 +7,7 @@
7
7
  "canonical": "task-pipeline",
8
8
  "deadline": "2026-11-24",
9
9
  "createdAt": "2026-09-25",
10
- "rationale": "0943 (feature D64): task-pipeline work routes by triage lane and failure class instead of static graphs. Between a green gate and the review/verify fork a deterministic `triage` state writes the diffstat (plugins/sp/scripts/task-diffstat.ts, numstat + untracked scan against the precheck-anchored run base), honors a caller-set mode verbatim (never overridden), pins the safety lane on sensitive paths (drizzle/, packages/config/, server auth basenames, *secret*, .github/, plugins/sp/hooks/, *.sql) or >400 changed lines with NO model call, otherwise consults `decide task-triage` (low → fast lane skips review; standard/high → review), and appends the route reason to .spur/memory/task-pipeline-routes.log (R5). On a red gate, `decide failure-class` routes retryable → test-recheck (attempt counted, qualityGateMaxFixAttempts still bounds), fix → test-fix, stop → failed(failed-check); missing/corrupt decision fails closed. Projected basis: the 0938 baseline (docs/reports/2026-09-workflow-cost-baseline.md) measured task-pipeline wall median 7983s over 1 real terminal run with agent.run median 0; the fast lane saves the review agent.run + wall on triage-low diffs, and retryable classification saves fixall hops (and their gate re-runs) on transient failures. Measurement gap honestly named: with workflow.decideDecisionMaker off (R4) triage degrades to standard lanes (diffstat-guard-sensitive/large still forced safety — pure shell, no model), so benefit only materializes with the flag on; per-lane route counts are observable post-merge in .spur/memory/task-pipeline-routes.log. Measured-benefit status: projected from 0938, NOT shadow-run-confirmed — plan step 5 (recorded-input shadow runs) is DEFERRED out of the 0943 session and tracked by this candidate's deadline; `promotion evaluate` runs post-merge. If it does not beat the baseline, it is reverted (ADR-076).",
10
+ "rationale": "0943 (feature D64): task-pipeline work routes by triage lane and failure class instead of static graphs. Between a green gate and the review/verify fork a deterministic `triage` state writes the diffstat (`spur task diffstat`, formerly plugins/sp/scripts/task-diffstat.ts; numstat + untracked scan against the precheck-anchored run base), honors a caller-set mode verbatim (never overridden), pins the safety lane on sensitive paths (drizzle/, packages/config/, server auth basenames, *secret*, .github/, plugins/sp/hooks/, *.sql) or >400 changed lines with NO model call, otherwise consults `decide task-triage` (low → fast lane skips review; standard/high → review), and appends the route reason to .spur/memory/task-pipeline-routes.log (R5). On a red gate, `decide failure-class` routes retryable → test-recheck (attempt counted, qualityGateMaxFixAttempts still bounds), fix → test-fix, stop → failed(failed-check); missing/corrupt decision fails closed. Projected basis: the 0938 baseline (docs/reports/2026-09-workflow-cost-baseline.md) measured task-pipeline wall median 7983s over 1 real terminal run with agent.run median 0; the fast lane saves the review agent.run + wall on triage-low diffs, and retryable classification saves fixall hops (and their gate re-runs) on transient failures. Measurement gap honestly named: with workflow.decideDecisionMaker off (R4) triage degrades to standard lanes (diffstat-guard-sensitive/large still forced safety — pure shell, no model), so benefit only materializes with the flag on; per-lane route counts are observable post-merge in .spur/memory/task-pipeline-routes.log. Measured-benefit status: projected from 0938, NOT shadow-run-confirmed — plan step 5 (recorded-input shadow runs) is DEFERRED out of the 0943 session and tracked by this candidate's deadline; `promotion evaluate` runs post-merge. If it does not beat the baseline, it is reverted (ADR-076).",
11
11
  "measurement": {
12
12
  "workflow": "task-pipeline"
13
13
  },
@@ -39,7 +39,7 @@
39
39
  "canonical": "wrapup-pipeline",
40
40
  "deadline": "2026-11-24",
41
41
  "createdAt": "2026-09-25",
42
- "rationale": "0944 (feature D64): a deterministic probe (plugins/sp/scripts/wrapup-drift-probe.ts) runs only when the caller leaves wrapup mode empty and projects mode=fast when no changed path matches a doc-owned surface (AGENTS.md doc map + docs/99_PROJECT_CONSTITUTION.md ownership table) and every task's Solution change map parsed — clean wraps then skip doc-sync via the existing fast edge (fast:drift-probe-clean), any doubt stays on the safety path. Projected basis: doc-sync costs exactly 1 agent.run per wrapup (wrapup-pipeline declares one model query; 0938 baseline docs/reports/2026-09-workflow-cost-baseline.json has 0 recorded wrapup runs — agentRunCountMedian null — so the 1 is structural, never a measured median). Measurement gap honestly named: skipping doc-sync also skips learnings capture (0607 R2 merge), so clean wraps lose per-task learnings rows; measured post-promotion by comparing .spur/memory/wrapup-routes.log fast:drift-probe-clean counts against captured <runId>-wrapup-learnings.md files. For 0946 (measurement-only confirmation): the 0938 snapshot carries per-state rows in states[] but history-anatomy has zero of them (0 recorded runs — only task-pipeline/record exists), and cache hit/miss disposition lives in the history-anatomy provenance stamp (0659/0660, history-anatomy-cache.ts), not in real-run-cost.ts; terminalReasonMix exists per workflow but history-anatomy's is empty. Measured-benefit status: projected from structure + 0938, NOT shadow-run-confirmed; `promotion evaluate` runs post-merge. If it does not beat the baseline, it is reverted (ADR-076).",
42
+ "rationale": "0944 (feature D64): a deterministic probe (`spur task wrapup drift-probe`, packages/app/src/workflow/wrapup/drift-probe.ts since script-absorption PR-5) runs only when the caller leaves wrapup mode empty and projects mode=fast when no changed path matches a doc-owned surface (AGENTS.md doc map + docs/99_PROJECT_CONSTITUTION.md ownership table) and every task's Solution change map parsed — clean wraps then skip doc-sync via the existing fast edge (fast:drift-probe-clean), any doubt stays on the safety path. Projected basis: doc-sync costs exactly 1 agent.run per wrapup (wrapup-pipeline declares one model query; 0938 baseline docs/reports/2026-09-workflow-cost-baseline.json has 0 recorded wrapup runs — agentRunCountMedian null — so the 1 is structural, never a measured median). Measurement gap honestly named: skipping doc-sync also skips learnings capture (0607 R2 merge), so clean wraps lose per-task learnings rows; measured post-promotion by comparing .spur/memory/wrapup-routes.log fast:drift-probe-clean counts against captured <runId>-wrapup-learnings.md files. For 0946 (measurement-only confirmation): the 0938 snapshot carries per-state rows in states[] but history-anatomy has zero of them (0 recorded runs — only task-pipeline/record exists), and cache hit/miss disposition lives in the history-anatomy provenance stamp (0659/0660, `spur history anatomy`, formerly history-anatomy-cache.ts), not in real-run-cost.ts; terminalReasonMix exists per workflow but history-anatomy's is empty. Measured-benefit status: projected from structure + 0938, NOT shadow-run-confirmed; `promotion evaluate` runs post-merge. If it does not beat the baseline, it is reverted (ADR-076).",
43
43
  "measurement": {
44
44
  "workflow": "wrapup-pipeline"
45
45
  },
@@ -21,8 +21,9 @@
21
21
  # shipped entry no longer provides, and the entry path. Reinstalling or upgrading the
22
22
  # plugin cannot supply a retired export — only the two remedies above can.
23
23
  #
24
- # Shape: verify -> done | failed. The onEnter step runs the standard script
25
- # `feature-verification-steps.ts` (no public CLI verb, D63 task 0915): it
24
+ # Shape: verify -> done | failed. The onEnter step runs `spur feature verify`
25
+ # (D63 task 0915; script-absorption PR-5 retired the feature-verification-steps
26
+ # plugin script): it
26
27
  # resolves this very definition for the verifier identity (name, source path,
27
28
  # layer, definition digest), records the RUNNING receipt (run-scoped +
28
29
  # feature-latest copies), registers the run-scoped receipt as a run artifact,
@@ -64,21 +65,15 @@ vars:
64
65
  states:
65
66
  - id: verify
66
67
  description: >
67
- Run the repo-wide check set via the standard verification script, which
68
+ Run the repo-wide check set via `spur feature verify`, which
68
69
  records the bound evidence receipt (verifier identity, checked-input
69
70
  digest, run identity) and the coarse status file, always exit 0 so the
70
71
  transition guard routes missing/corrupt/FAIL to `failed`.
71
72
  onEnter:
72
- # 0960 R2: run-start script-resolution identity — record which tree this run
73
- # resolved (source-repo vs installed) before the verification step runs. Never aborts.
74
73
  - kind: shell
75
74
  options:
76
75
  command: >-
77
- 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
78
- - kind: shell
79
- options:
80
- command: >-
81
- mkdir -p .spur/run; eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/feature-verification-steps.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/feature-verification-steps.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; ACK=""; [ "$ackLowConfidence" = "true" ] && ACK="--ack-low-confidence"; [ -f "$S" ] && "$RUNNER" "$S" verify --feature-id "$featureId" --run-id "$__runId" --spur-bin "$spurBin" --confidence "$confidence" $ACK || printf 'FAIL feature-verification failed closed — script not found — run superskill install sp --marketplace gobing-ai/spur\n' > ".spur/run/$__runId-feature-verification.status"; exit 0
76
+ mkdir -p .spur/run; ACK=""; [ "$ackLowConfidence" = "true" ] && ACK="--ack-low-confidence"; $spurBin feature verify "$featureId" --run-id "$__runId" --confidence "$confidence" $ACK --no-logo || printf 'FAIL feature-verification failed closed — spur feature verify exited nonzero\n' > ".spur/run/$__runId-feature-verification.status"; exit 0
82
77
 
83
78
  - id: done
84
79
  description: Terminal — repo-wide checks passed and the receipt is bound.
@@ -89,7 +84,7 @@ states:
89
84
  transitions:
90
85
  - from: verify
91
86
  to: done
92
- description: Repo-wide checks passed — the script completed the receipt with PASS.
87
+ description: Repo-wide checks passed — `spur feature verify` completed the receipt with PASS.
93
88
  guard:
94
89
  kind: shell
95
90
  options:
@@ -4,7 +4,7 @@
4
4
  # Orchestration is configuration (ADR-022): a state machine over the existing dual-workflow
5
5
  # engine. The YAML owns ONLY the cache branch, deterministic stage ordering, executor dispatch,
6
6
  # bounded correction, and atomic publication sequencing. The deterministic cache/digest/
7
- # structure/publish work is 0659's dependency-free helper script; the judgment (mode validity,
7
+ # structure/publish work is `spur history anatomy <op>` (0659's helper, absorbed by script-absorption PR-6); the judgment (mode validity,
8
8
  # what counts as evidence, the report contract, enrich/validate rubrics) is 0658's skill. Per
9
9
  # ADR-069 R1, cache-decide / digest / structure-check / publish must NOT be inline shell — every
10
10
  # shell action here is glue length (a single helper invocation), because each of those programs
@@ -100,16 +100,6 @@ states:
100
100
  # reclamation path (unlike the run-record pair and legacy `.log` files, which
101
101
  # `spur workflow clean --logs` owns). It is deliberately NOT a run record and is
102
102
  # exempt from the catalog record-name sweep (see run-record-catalog.test.ts).
103
-
104
-
105
- # 1007 R8: run-start script-resolution identity (same command as feature-verification
106
- # verify's first action), placed AFTER the id allocation above — the snippet reads
107
- # .spur/run/$__runId-script-root.json, so it needs the allocated id. Later
108
- # plugin-script actions resolve through it (1007 R4 snippet). Never aborts.
109
- - kind: shell
110
- options:
111
- command: >-
112
- 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
113
103
  - id: resolve-paths
114
104
  description: >
115
105
  Resolve the helper, the skill/contract logic paths, and the publication target once, into a
@@ -118,11 +108,11 @@ states:
118
108
  onEnter:
119
109
  - kind: shell
120
110
  options:
121
- # Path arithmetic lives in the helper (ADR-069 R1); the shell only locates it. Avoid
111
+ # Path arithmetic lives in `spur history anatomy paths` (ADR-069 R1; script-absorption
112
+ # PR-6 — HA_HELPER is the running spur, HA_SKILL the resolved skill dir). Avoid
122
113
  # `${...}` here — that syntax collides with the engine's own template interpolation.
123
114
  command: >-
124
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
125
- "$RUNNER" "$S" paths --helper "$S" --report-dir "$reportDir" --date "$date"
115
+ $spurBin history anatomy paths --report-dir "$reportDir" --date "$date"
126
116
  --output "$output" --mode "$mode" --since "$since" --until "$until"
127
117
  --focus "$focus" --recompute "$recompute" --run-id "$__runId"
128
118
  --out .spur/run/$__runId-paths.txt
@@ -155,13 +145,12 @@ states:
155
145
  - kind: shell
156
146
  options:
157
147
  command: >-
158
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
159
148
  . .spur/run/$__runId-paths.txt;
160
- "$RUNNER" "$S" probe --artifact .spur/run/$__runId-history-anatomy-current.json
149
+ $spurBin history anatomy probe --artifact .spur/run/$__runId-history-anatomy-current.json
161
150
  --baseline .spur/run/$__runId-history-anatomy-baseline.json --target "$HA_TARGET"
162
151
  --mode "$mode" --date "$HA_DATE" --recompute "$recompute" --executor "$agent"
163
152
  --skill-dir "$HA_SKILL" --contract "$HA_SKILL/references/report-contract.md"
164
- --workflow "$workflowFile" --helper "$S" --contract-version "$contractVersion" --run-id "$__runId"
153
+ --workflow "$workflowFile" --helper "$HA_HELPER" --contract-version "$contractVersion" --run-id "$__runId"
165
154
  --out .spur/run/$__runId-provenance.json
166
155
  > .spur/run/$__runId-cache-disposition.txt
167
156
 
@@ -198,7 +187,7 @@ states:
198
187
  - kind: shell
199
188
  options:
200
189
  command: >-
201
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" assert-clean --baseline .spur/run/$__runId-baseline-enrich.txt --expect .spur/run/$__runId-candidate.md
190
+ $spurBin history anatomy assert-clean --baseline .spur/run/$__runId-baseline-enrich.txt --expect .spur/run/$__runId-candidate.md
202
191
 
203
192
  - id: structure-gate
204
193
  description: >
@@ -209,7 +198,7 @@ states:
209
198
  - kind: shell
210
199
  options:
211
200
  command: >-
212
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" check \
201
+ $spurBin history anatomy check \
213
202
  .spur/run/$__runId-candidate.md > .spur/run/$__runId-structure-gate.txt 2>&1 || true
214
203
 
215
204
  - id: validate
@@ -267,7 +256,7 @@ states:
267
256
  command: >-
268
257
  f=.spur/run/$__runId-validation.txt;
269
258
  if [ -f "$f" ] && [ "$(grep -cx 'Verdict: FAIL' "$f")" = 0 ] && ! tail -n 1 "$f" | grep -qx 'Verdict: PASS'; then
270
- d=$("$spurBin" decision run anatomy-validation-verdict --evidence "$f" --json || true);
259
+ d=$($spurBin decision run anatomy-validation-verdict --evidence "$f" --json || true);
271
260
  v=$(printf '%s' "$d" | jq -r 'if (.source // .data.source) == "model" and (.value // .data.value) == "PASS" then "PASS" else "FAIL" end' 2>/dev/null);
272
261
  [ "$v" = "PASS" ] || v="FAIL";
273
262
  printf 'Verdict: %s\n' "$v" >> "$f";
@@ -275,7 +264,7 @@ states:
275
264
  - kind: shell
276
265
  options:
277
266
  command: >-
278
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" assert-clean --baseline .spur/run/$__runId-baseline-validate.txt --expect .spur/run/$__runId-validation.txt
267
+ $spurBin history anatomy assert-clean --baseline .spur/run/$__runId-baseline-validate.txt --expect .spur/run/$__runId-validation.txt
279
268
 
280
269
  - id: correct
281
270
  description: >
@@ -312,7 +301,7 @@ states:
312
301
  - kind: shell
313
302
  options:
314
303
  command: >-
315
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)"; "$RUNNER" "$S" assert-clean --baseline .spur/run/$__runId-baseline-correct.txt --expect .spur/run/$__runId-candidate.md
304
+ $spurBin history anatomy assert-clean --baseline .spur/run/$__runId-baseline-correct.txt --expect .spur/run/$__runId-candidate.md
316
305
 
317
306
  - id: refresh-provenance
318
307
  description: >
@@ -324,9 +313,8 @@ states:
324
313
  - kind: shell
325
314
  options:
326
315
  command: >-
327
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
328
316
  . .spur/run/$__runId-paths.txt;
329
- "$RUNNER" "$S" refresh --report "$HA_TARGET"
317
+ $spurBin history anatomy refresh --report "$HA_TARGET"
330
318
  --out .spur/run/$__runId-publishable.md --disposition hit
331
319
 
332
320
  - id: stamp
@@ -339,9 +327,8 @@ states:
339
327
  - kind: shell
340
328
  options:
341
329
  command: >-
342
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
343
330
  . .spur/run/$__runId-paths.txt;
344
- "$RUNNER" "$S" stamp --candidate .spur/run/$__runId-candidate.md
331
+ $spurBin history anatomy stamp --candidate .spur/run/$__runId-candidate.md
345
332
  --provenance .spur/run/$__runId-provenance.json
346
333
  --out .spur/run/$__runId-publishable.md
347
334
 
@@ -354,10 +341,9 @@ states:
354
341
  - kind: shell
355
342
  options:
356
343
  command: >-
357
- eval "$(jq -r 'if .mode=="source-repo" then "S="+@sh"\(.dir)/history-anatomy-cache.ts"+" RUNNER=bun" elif .mode=="installed" then "S="+@sh"\(.dir)/history-anatomy-cache.mjs"+" RUNNER=node" else empty end' ".spur/run/$__runId-script-root.json" 2>/dev/null)";
358
344
  . .spur/run/$__runId-paths.txt;
359
345
  mkdir -p "$(dirname "$HA_TARGET")";
360
- "$RUNNER" "$S" publish .spur/run/$__runId-publishable.md "$HA_TARGET"
346
+ $spurBin history anatomy publish .spur/run/$__runId-publishable.md "$HA_TARGET"
361
347
 
362
348
  - id: published
363
349
  description: Terminal — report published atomically after a passing validation.
@@ -88,12 +88,6 @@ states:
88
88
  handoff — no task execution. Soft agent doctor (status file) so doctor red
89
89
  routes to `failed` via transitions instead of a raw lifecycle abort.
90
90
  onEnter:
91
- # 0960 R2: run-start script-resolution identity — record which tree this run
92
- # resolved (source-repo vs installed) before any step executes. Never aborts.
93
- - kind: shell
94
- options:
95
- command: >-
96
- 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
97
91
  - kind: note
98
92
  options:
99
93
  message: "Idea pipeline start for idea: ${vars.idea}"
@@ -606,21 +600,14 @@ states:
606
600
  A mapping or CLI error fails the run before terminal handoff; an unready
607
601
  task is a successful planning outcome recorded as a refineall recommendation.
608
602
  onEnter:
609
- # (d) idea-handoff owns finalization (0824): the bundled finalizeIdeaHandoff
610
- # capability runs from the monorepo checkout first; seeded projects (no
611
- # packages/, no plugins/) resolve the registered idea-handoff.mjs twin under
612
- # bare node; neither present fails closed (exit 1) instead of silently
613
- # skipping finalization. The zip/deps/refresh/check/report contract itself is
614
- # pinned by finalizeIdeaHandoff unit tests, not by this file.
603
+ # (d) `spur feature handoff` owns finalization (0824; script-absorption PR-5
604
+ # retired the idea-handoff plugin script and its bundle). A nonzero exit fails
605
+ # the run (fail closed) instead of silently skipping finalization. The
606
+ # zip/deps/refresh/check/report contract itself is pinned by
607
+ # finalizeIdeaHandoff unit tests, not by this file.
615
608
  - kind: shell
616
609
  options:
617
- command: >-
618
- 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
619
- "$RUNNER" "$S";
620
- else
621
- echo "idea handoff failed closed — idea-handoff script not found — run 'superskill install sp --marketplace gobing-ai/spur'" >&2;
622
- exit 1;
623
- fi
610
+ command: '$spurBin feature handoff "$featureId" --run-id "$__runId" --no-logo'
624
611
  - id: handoff
625
612
  description: >
626
613
  Terminal — idea pipeline complete. Ordering applied, roster refreshed, and