@gobing-ai/spur 0.4.9 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/config/rules/README.md +1 -1
- package/config/rules/boundary/env-var-hygiene.yaml +0 -1
- package/config/rules/boundary/sp-script-placement.yaml +3 -3
- package/config/rules/docs/sourced-api-claims.yaml +23 -96
- package/config/workflows/feature-verification.yaml +1 -9
- package/config/workflows/pr-review.yaml +72 -224
- package/config/workflows/task-pipeline.yaml +2 -2
- package/package.json +1 -1
- package/plugins/sp/agents/expert-spur.md +0 -1
- package/plugins/sp/commands/dev-changelog.md +1 -1
- package/plugins/sp/commands/dev-pr-review.md +27 -17
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/skills/brainstorm/SKILL.md +12 -11
- package/plugins/sp/skills/brainstorm/agents/openai.yaml +1 -1
- package/plugins/sp/skills/brainstorm/examples/ideation-example.md +0 -4
- package/plugins/sp/skills/brainstorm/metadata.openclaw +1 -1
- package/plugins/sp/skills/brainstorm/references/workflows.md +4 -14
- package/plugins/sp/skills/code-verification/references/secu-review.md +7 -4
- package/plugins/sp/skills/history-anatomy/references/operations.md +3 -4
- package/plugins/sp/skills/history-anatomy/references/report-contract.md +2 -3
- package/plugins/sp/skills/issue-finding/SKILL.md +1 -1
- package/plugins/sp/skills/parallel-execution/SKILL.md +1 -1
- package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +9 -10
- package/plugins/sp/skills/pr-reviewing/SKILL.md +157 -210
- package/plugins/sp/skills/reverse-engineering/SKILL.md +4 -6
- package/plugins/sp/skills/session-review/SKILL.md +10 -26
- package/plugins/sp/skills/source-driven-development/SKILL.md +35 -31
- package/plugins/sp/skills/spur-cli/SKILL.md +1 -1
- package/plugins/sp/skills/spur-cli/references/agent.md +5 -2
- package/plugins/sp/skills/spur-cli/references/builder.md +86 -13
- package/plugins/sp/skills/spur-cli/references/features.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +1 -1
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +5 -6
- package/plugins/sp/skills/spur-dev/references/execution-worktree-landing.md +1 -1
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +3 -2
- package/spur.js +1280 -417
- package/web/_astro/{BoardApp.CaNvQBD_.js → BoardApp.B5rTVNd_.js} +1 -1
- package/web/_astro/{BoardApp.C5jnkkKP.js → BoardApp.BMprmPRc.js} +141 -141
- package/web/_astro/{TaskDetail.DGKndhI8.js → TaskDetail.Ddsur8qd.js} +1 -1
- package/web/_astro/{arc.DHrwdg3G.js → arc.DLqVVBxP.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.pvKpK1s5.js → architectureDiagram-3BPJPVTR.C-Pk3uAi.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.BQmRcZsS.js → blockDiagram-GPEHLZMM.BRO1i_Nm.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.CCLjHeH1.js → c4Diagram-AAUBKEIU.BU_cWu6e.js} +1 -1
- package/web/_astro/channel.Bs3Illhy.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.DL6Yuoma.js → chunk-2J33WTMH.D2VXiQ2t.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.CzlyEI7l.js → chunk-4BX2VUAB.BcHT772J.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.B60EWxp1.js → chunk-55IACEB6.DhDtICmo.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.c7v_fRLo.js → chunk-727SXJPM.BoKHp7gV.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.8BxLWdDc.js → chunk-AQP2D5EJ.Chu4JRpE.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.DmKuxGFT.js → chunk-FMBD7UC4.wHdwKPlq.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.1Zwd4mqV.js → chunk-ND2GUHAM.ffN-M1JB.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.BvYLu-A1.js → chunk-QZHKN3VN.FRubwg4S.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.CEqRt0WU.js → classDiagram-4FO5ZUOK.c22tQsc_.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.CEqRt0WU.js → classDiagram-v2-Q7XG4LA2.c22tQsc_.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.C7JiUdj2.js → cose-bilkent-S5V4N54A.B9c6fiSj.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.B6mZ-1be.js → cynefin-OW5HDTMX.DrZsrUHl.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BuryfDy6.js → dagre-BM42HDAG.DG1U4b3y.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.dao39YQM.js → diagram-2AECGRRQ.CH15b-K3.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.lnGZe4At.js → diagram-5GNKFQAL.BH1j7twR.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.uWfhzEfT.js → diagram-KO2AKTUF.q2zCkbAj.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.ppq8-198.js → diagram-LMA3HP47.BLaaZnHV.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CKSCqDt5.js → diagram-OG6HWLK6.BcpRdQwI.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.sFSf2yBN.js → erDiagram-TEJ5UH35.D7KBlqfM.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.BJQjKLbz.js → flowDiagram-I6XJVG4X.D_gmuRqg.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DAHKNj2N.js → ganttDiagram-6RSMTGT7.DzgWYniD.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.BlmzcW_O.js → gitGraphDiagram-PVQCEYII.576i3hm3.js} +1 -1
- package/web/_astro/index.DiC1a6lh.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DGhjaqsi.js → infoDiagram-5YYISTIA.DMCclBiz.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.gKIpgt6F.js → ishikawaDiagram-YF4QCWOH.9Kyca4SH.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.DG3tmP0R.js → journeyDiagram-JHISSGLW.chbdG-8q.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.CgHDSxkR.js → kanban-definition-UN3LZRKU.Bds54-e0.js} +1 -1
- package/web/_astro/{linear.BuGEpcuM.js → linear.D5ND9GN_.js} +1 -1
- package/web/_astro/{mermaid.core.DBVqkWBp.js → mermaid.core.D9N_PGbj.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.D-kOcji9.js → mindmap-definition-RKZ34NQL.t0xop5vp.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.BvGPwtZt.js → pieDiagram-4H26LBE5.DqgKh6hM.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.BKb_9FV6.js → quadrantDiagram-W4KKPZXB.DeuHVi2t.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.Cx0fvD8v.js → requirementDiagram-4Y6WPE33.BdYFSG4W.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.fatULi0W.js → sankeyDiagram-5OEKKPKP.k1LPPETJ.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.ChHyKqco.js → sequenceDiagram-3UESZ5HK.DdyfpzoG.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.BdUpKWyj.js → stateDiagram-AJRCARHV.DSEI8il0.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.fmJxqIm5.js → stateDiagram-v2-BHNVJYJU.CoMnQRKo.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.BayDn5-V.js → timeline-definition-PNZ67QCA.DM1AHNm-.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.Bm2Aggwa.js → vennDiagram-CIIHVFJN.C-cJmVtl.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.DI75O-uG.js → wardleyDiagram-YWT4CUSO.D0xMzKPb.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DL90E7Q7.js → xychartDiagram-2RQKCTM6.BH5xJcEq.js} +1 -1
- package/web/index.html +2 -2
- package/web/_astro/channel.C7wG9RxA.js +0 -1
- package/web/_astro/index.BCY1JJHd.css +0 -1
package/config/rules/README.md
CHANGED
|
@@ -17,7 +17,7 @@ install or to ts-libs.
|
|
|
17
17
|
| `surface` | `surface/` | CLI surface consistency (registerXxxCommand wiring, --json serialization) |
|
|
18
18
|
| `migration` | `migration/` | Transitional helpers for the regex → `rg` evaluator move (`rg-dialect`) |
|
|
19
19
|
| `ui` | `ui/` | Web UI seam boundaries (import seam, daisyUI class leak) |
|
|
20
|
-
| `docs` | `docs/` | Sourced API/library claims in markdown — citation anchor
|
|
20
|
+
| `docs` | `docs/` | Sourced API/library claims in markdown — same-line citation anchor (no confidence level, ADR-138). Advisory (`info`), and deliberately **not** in a preset: see the file header for its calibration audit. |
|
|
21
21
|
|
|
22
22
|
## Presets
|
|
23
23
|
|
|
@@ -13,7 +13,6 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
|
13
13
|
# gateway — because `superskill install` bundles them on targets with no
|
|
14
14
|
# node_modules, where any `@gobing-ai/*` import fails ("Bundle failed", task
|
|
15
15
|
# 0669). It mirrors the upstream semantics and is the one exempt file.
|
|
16
|
-
# The `superskill script convert` `.mjs` twins remain self-contained by inlining.
|
|
17
16
|
# - `apps/web` uses `import.meta.env` (Vite browser plane) — not process env, never matches.
|
|
18
17
|
# - Which variables exist and who consumes them is documented in `.env.example`.
|
|
19
18
|
# (The former per-var lease table moved there; the rule now enforces the funnel,
|
|
@@ -2,11 +2,11 @@ $schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
|
2
2
|
# [boundary] ADR-130 script placement contract (task 1000). Runs the fast
|
|
3
3
|
# --placement-only mode of the relocated script-contract-check on every
|
|
4
4
|
# recommended-pre-check; SKIPs outside the Spur source repo (same pattern as
|
|
5
|
-
# strict/rule-files-structural.yaml SKIP on missing yq). The full
|
|
6
|
-
# stays in spur-check-feature.
|
|
5
|
+
# strict/rule-files-structural.yaml SKIP on missing yq). The full hook-only
|
|
6
|
+
# layout check (`bun run script-contract-check`) stays in spur-check-feature.
|
|
7
7
|
rules:
|
|
8
8
|
- id: sp-script-placement
|
|
9
|
-
description: "
|
|
9
|
+
description: "plugins/sp and scripts/commands must honor the ADR-130 placement contract (hook entry budget, no DB driver or corpus parsing in plugin scripts/hooks/lib, no raw DB driver in scripts/commands, no noun clash, ADR-129 hook layout); any finding fails, no baseline."
|
|
10
10
|
severity: error
|
|
11
11
|
evaluator:
|
|
12
12
|
type: exit-code
|
|
@@ -1,51 +1,18 @@
|
|
|
1
1
|
$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
2
|
-
# Sourced-claims rules (docs corpus) — API/library
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# measured fact from model memory. The deterministic scan is line-level and
|
|
7
|
-
# heuristic — code fences and command examples can legitimately carry bare
|
|
8
|
-
# versions, so severity is info (advisory visibility; the recommended-pre-check
|
|
9
|
-
# gate runs --fail-on warning, so this rule surfaces findings for review without
|
|
10
|
-
# reddening gates — changed-file enforcement happens in SECUA review).
|
|
2
|
+
# Sourced-claims rules (docs corpus) — an external API/library claim in markdown
|
|
3
|
+
# (a bare x.y.z version, or "deprecated since / added in / removed in <v>") must carry
|
|
4
|
+
# a same-line citation anchor: an http(s) URL or a repo path:line. Contract owned by
|
|
5
|
+
# sp-source-driven-development; changed-file enforcement is SECUA review.
|
|
11
6
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# (`docs/00_ADR.md:5` → `version: 1.69.0`), a section number in a heading
|
|
18
|
-
# (`docs/04_DESIGN.md:116` → `### 1.0.1 Shared option registry`) and a
|
|
19
|
-
# `§`-numbered cross-reference (`docs/00_ADR.md:1118` → `§1.2.1`). All three are
|
|
20
|
-
# excluded by the pattern below — the first two on the line's shape, the third on
|
|
21
|
-
# the token itself. The remaining source was a stale exclude list that stopped at
|
|
22
|
-
# `docs/tasks4/` while the active corpus folder is `docs/tasks5/`, which alone
|
|
23
|
-
# produced 226 findings; it is now one `docs/tasks*/**` glob. 593 → 330 after those
|
|
24
|
-
# two fixes, then 277 once the `§` shape was excluded too — the residual are
|
|
25
|
-
# version-pinned package claims that genuinely lack a same-line anchor, and they
|
|
26
|
-
# stay visible rather than suppressed.
|
|
7
|
+
# Severity is info and the category is deliberately NOT in any preset: the scan is
|
|
8
|
+
# line-level, fires inside code fences, and its residual is a review surface, not a
|
|
9
|
+
# gate (2026-10-12 audit: 593 → 277 findings after the shape/`§`/excludes fixes; the
|
|
10
|
+
# 2026-10-16 widening admitted only verbs whose shape vouches for a version).
|
|
11
|
+
# Re-measure with `spur rule run --file … --json` before widening the vocabulary.
|
|
27
12
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# (code-verification secu-review checklist). These rules are its deterministic
|
|
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`,
|
|
39
|
-
# and the category is deliberately NOT in `recommended-pre-check` — it surfaces
|
|
40
|
-
# findings for review without reddening gates. The 2026-10-12 audit below settled
|
|
41
|
-
# the promotion question: the residual findings stay a review-surface concern
|
|
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.
|
|
13
|
+
# Citation only — no HIGH/MEDIUM/LOW level rule (ADR-138, task 1221): a model can
|
|
14
|
+
# write HIGH as easily as a claim, so the level verified nothing. The anchor is the
|
|
15
|
+
# evidence; do not reintroduce a level half.
|
|
49
16
|
include:
|
|
50
17
|
- "docs/**/*.md"
|
|
51
18
|
- "plugins/sp/skills/**/references/**/*.md"
|
|
@@ -58,6 +25,11 @@ exclude:
|
|
|
58
25
|
# fallback strips the `*` down to `docs/tasks/` — which is why that form
|
|
59
26
|
# silently excluded nothing (measured 2026-10-12).
|
|
60
27
|
- "docs/tasks*/**"
|
|
28
|
+
# Dated working records — see the "Historical-record excludes" note above.
|
|
29
|
+
- "docs/report*/**"
|
|
30
|
+
- "docs/dogfood/**"
|
|
31
|
+
- "docs/plans/**"
|
|
32
|
+
- "docs/analysis/**"
|
|
61
33
|
- "drizzle/**"
|
|
62
34
|
- "**/node_modules/**"
|
|
63
35
|
rules:
|
|
@@ -66,8 +38,8 @@ rules:
|
|
|
66
38
|
A markdown line asserting a version string (x.y.z) without a citation
|
|
67
39
|
anchor on the same line — http(s) URL or repo path reference like
|
|
68
40
|
packages/app/src/foo.ts:123 — is unverifyable. Add the anchor, or drop
|
|
69
|
-
the version if it is not load-bearing
|
|
70
|
-
|
|
41
|
+
the version if it is not load-bearing; contract in
|
|
42
|
+
sp-source-driven-development.
|
|
71
43
|
severity: info
|
|
72
44
|
evaluator:
|
|
73
45
|
type: regex
|
|
@@ -87,57 +59,12 @@ rules:
|
|
|
87
59
|
- id: cited-api-claims
|
|
88
60
|
description: >
|
|
89
61
|
A markdown line making a time- or version-anchored external API claim
|
|
90
|
-
("deprecated since 1.2", "introduced in v3", "
|
|
91
|
-
|
|
92
|
-
source
|
|
93
|
-
contract in sp-source-driven-development.
|
|
94
|
-
severity: info
|
|
95
|
-
evaluator:
|
|
96
|
-
type: regex
|
|
97
|
-
config:
|
|
98
|
-
mode: forbid
|
|
99
|
-
pattern: "^(?!.*(?:https?://|(?:[\\w.-]+/)+[\\w.-]+:\\d+)).*\\b(?:deprecated (?:since|in|as of)|introduced in|added in|available since|stable since)\\b"
|
|
100
|
-
- id: cited-api-claims-confidence
|
|
101
|
-
description: >
|
|
102
|
-
A markdown line making a time- or version-anchored external API claim
|
|
103
|
-
("deprecated since 1.2", "introduced in v3", "available since 0.9") must
|
|
104
|
-
also state its confidence level — HIGH, MEDIUM or LOW — so a reader can
|
|
105
|
-
tell a checked fact from model memory; contract in
|
|
106
|
-
sp-source-driven-development. Pairs with `cited-api-claims`, which covers
|
|
107
|
-
the citation half: a line missing both halves reports once per rule,
|
|
108
|
-
deliberately, because each missing half is its own defect.
|
|
109
|
-
severity: info
|
|
110
|
-
evaluator:
|
|
111
|
-
type: regex
|
|
112
|
-
config:
|
|
113
|
-
mode: forbid
|
|
114
|
-
# Fires on a claim line carrying no uppercase level token. The verbs match
|
|
115
|
-
# `cited-api-claims` exactly, so the two rules never disagree about which
|
|
116
|
-
# lines are claims.
|
|
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.
|
|
62
|
+
("deprecated since 1.2", "introduced in v3", "removed in 0.9") must carry
|
|
63
|
+
a citation anchor on the same line — URL or repo path:line; contract in
|
|
64
|
+
sp-source-driven-development.
|
|
133
65
|
severity: info
|
|
134
66
|
evaluator:
|
|
135
67
|
type: regex
|
|
136
68
|
config:
|
|
137
69
|
mode: forbid
|
|
138
|
-
|
|
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"
|
|
70
|
+
pattern: "^(?!.*(?:https?://|(?:[\\w.-]+/)+[\\w.-]+:\\d+)).*\\b(?:deprecated (?:since|in|as of)|introduced in|added in|available since|stable since|removed (?:in|since) [vV]?\\d|(?:since|as of) (?:[vV]\\d+\\.\\d+(?:\\.\\d+)?|\\d+\\.\\d+\\.\\d+))\\b"
|
|
@@ -52,14 +52,6 @@ vars:
|
|
|
52
52
|
featureId: "X"
|
|
53
53
|
spurBin: "spur"
|
|
54
54
|
verificationCmd: "bun run spur-check-feature"
|
|
55
|
-
# Operator-declared confidence level; empty derives it from the pass (HIGH when the selected
|
|
56
|
-
# definition's own command exited 0 with an unchanged proof-input digest, MEDIUM under a caller
|
|
57
|
-
# `--cmd` override, LOW otherwise). The completion boundary refuses a PASS carrying no level or
|
|
58
|
-
# LOW unless the receipt records the acknowledgement below.
|
|
59
|
-
confidence: ""
|
|
60
|
-
# Operator acknowledgement of a LOW level. It rides the receipt, so the transition reads it from
|
|
61
|
-
# the evidence rather than from whatever flags a later command happens to pass.
|
|
62
|
-
ackLowConfidence: "false"
|
|
63
55
|
__runId: ""
|
|
64
56
|
|
|
65
57
|
states:
|
|
@@ -73,7 +65,7 @@ states:
|
|
|
73
65
|
- kind: shell
|
|
74
66
|
options:
|
|
75
67
|
command: >-
|
|
76
|
-
mkdir -p .spur/run;
|
|
68
|
+
mkdir -p .spur/run; $spurBin feature verify "$featureId" --run-id "$__runId" --no-logo || printf 'FAIL feature-verification failed closed — spur feature verify exited nonzero\n' > ".spur/run/$__runId-feature-verification.status"; exit 0
|
|
77
69
|
|
|
78
70
|
- id: done
|
|
79
71
|
description: Terminal — repo-wide checks passed and the receipt is bound.
|
|
@@ -3,13 +3,14 @@
|
|
|
3
3
|
# (initialState / states[].id / onEnter / top-level transitions), same family as
|
|
4
4
|
# basic.yaml / task-pipeline.yaml. Seeded into projects by `spur init` (scaffold manifest).
|
|
5
5
|
#
|
|
6
|
-
# Shape:
|
|
6
|
+
# Shape: check → precheck → open → review → done
|
|
7
7
|
# (soft probes everywhere: red gates route to `failed`/`pending` via transitions,
|
|
8
8
|
# never a raw lifecycle abort — same reliability contract as basic.yaml)
|
|
9
9
|
#
|
|
10
|
-
# This YAML is the SSOT for the review spine's state order and guards. Every state shells
|
|
11
|
-
#
|
|
12
|
-
#
|
|
10
|
+
# This YAML is the SSOT for the review spine's state order and guards. Every state shells out to
|
|
11
|
+
# the four flat `spur builder pr-<verb>` verbs (task 1219); the op sequencing
|
|
12
|
+
# (preflight→hygiene, push→ensure, request→wait→collect) lives in `runPrVerb`, not in this file's
|
|
13
|
+
# shell, and no gh/git logic lives in this file. All model-bearing work — finding triage, `fix`
|
|
13
14
|
# mode — stays in the sp:pr-reviewing skill and never enters this machine.
|
|
14
15
|
#
|
|
15
16
|
# Non-negotiable: the external review goes through the GitHub PR + an `@codex review`
|
|
@@ -21,7 +22,7 @@
|
|
|
21
22
|
# submit: request and stop at `pending` (no wait)
|
|
22
23
|
# rerun: request with --force even when HEAD is already reviewed
|
|
23
24
|
# baseBranch — base for a newly created PR (default: existing PR base, else repo default)
|
|
24
|
-
# focus — extra review focus appended to the @codex request
|
|
25
|
+
# focus — extra review focus appended to the @codex review request
|
|
25
26
|
# noWait — "true" returns pending right after the request instead of polling
|
|
26
27
|
# waitTimeoutSec — poll budget for Codex output (default 600)
|
|
27
28
|
# waitIntervalSec — poll interval (default 30; do not poll aggressively)
|
|
@@ -34,9 +35,9 @@
|
|
|
34
35
|
version: "1"
|
|
35
36
|
name: pr-review
|
|
36
37
|
kind: state-machine
|
|
37
|
-
description: GitHub Codex PR-review spine —
|
|
38
|
+
description: GitHub Codex PR-review spine — check → precheck → open → review
|
|
38
39
|
iterationBound: 16
|
|
39
|
-
initialState:
|
|
40
|
+
initialState: check
|
|
40
41
|
terminalStates:
|
|
41
42
|
- done
|
|
42
43
|
- pending
|
|
@@ -53,50 +54,27 @@ vars:
|
|
|
53
54
|
spurBin: "spur"
|
|
54
55
|
preReviewCmd: ""
|
|
55
56
|
__runId: ""
|
|
56
|
-
# Runtime-set by file.read.into-var (0771): the request record's requestedAt|head,
|
|
57
|
-
# extracted once by `request` and read per state — no repeated JSON parsing in shell.
|
|
58
|
-
prSince: ""
|
|
59
|
-
prHead: ""
|
|
60
57
|
|
|
61
58
|
states:
|
|
62
|
-
- id:
|
|
59
|
+
- id: check
|
|
63
60
|
description: >
|
|
64
|
-
Soft probe: git/gh/repo checks
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Writes PASS|FAIL to .spur/run/${vars.__runId}-pr-
|
|
61
|
+
Soft probe: preflight (git/gh/repo checks, detached HEAD, dirty tree, base-branch refusal —
|
|
62
|
+
refused before any push can publish it) followed by the hygiene scan of base...HEAD
|
|
63
|
+
(secrets/.env/conflict markers BLOCK; debug residue WARNs). A preflight failure stops before
|
|
64
|
+
hygiene. Writes PASS|WARN|BLOCK|FAIL to .spur/run/${vars.__runId}-pr-check.status; always
|
|
65
|
+
exit 0, so a red gate routes through the transitions below.
|
|
68
66
|
onEnter:
|
|
69
|
-
# script-root retired for this workflow: actions call `$spurBin builder pr
|
|
67
|
+
# script-root retired for this workflow: actions call `$spurBin builder pr-<verb>` directly.
|
|
70
68
|
- kind: shell
|
|
71
69
|
options:
|
|
72
|
-
# (e) 0825:
|
|
73
|
-
#
|
|
70
|
+
# (e) 0825: 7 lines — preflight+hygiene and their status fallback must land together
|
|
71
|
+
# (one verb now owns the whole probe; a split would half-probe the submission gate).
|
|
74
72
|
command: >-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if [ "$rc" -eq 0 ]; then printf 'PASS\n' > "$STATUS_FILE"; else printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
81
|
-
exit 0
|
|
82
|
-
|
|
83
|
-
- id: hygiene
|
|
84
|
-
description: >
|
|
85
|
-
Submission sanity scan of base...HEAD: secrets/.env/conflict markers BLOCK the run;
|
|
86
|
-
debug residue only WARNs. Not a replacement for the independent Codex review.
|
|
87
|
-
onEnter:
|
|
88
|
-
- kind: shell
|
|
89
|
-
options:
|
|
90
|
-
# (e) 0825: 9 lines — hygiene verdict + json capture land together; the status-file
|
|
91
|
-
# fallback keeps a silent driver from passing the gate.
|
|
92
|
-
command: >-
|
|
93
|
-
|
|
94
|
-
STATUS_FILE=".spur/run/$__runId-pr-hygiene.status" &&
|
|
95
|
-
set +e &&
|
|
96
|
-
$spurBin builder pr hygiene --base "$baseBranch" --json
|
|
97
|
-
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-hygiene.json";
|
|
98
|
-
rc=$?; set -e &&
|
|
99
|
-
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
73
|
+
STATUS_FILE=".spur/run/$__runId-pr-check.status";
|
|
74
|
+
mkdir -p .spur/run;
|
|
75
|
+
$spurBin builder pr-check --base "$baseBranch" --json --status-file "$STATUS_FILE"
|
|
76
|
+
> ".spur/run/$__runId-pr-check.json";
|
|
77
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi;
|
|
100
78
|
exit 0
|
|
101
79
|
|
|
102
80
|
- id: precheck
|
|
@@ -111,141 +89,78 @@ states:
|
|
|
111
89
|
command: >-
|
|
112
90
|
mkdir -p .spur/run; if [ -z "$preReviewCmd" ]; then R=SKIP; elif sh -c "$preReviewCmd"; then R=PASS; else R=FAIL; fi; printf '%s\n' "$R" > ".spur/run/$__runId-pr-precheck.status"
|
|
113
91
|
|
|
114
|
-
- id:
|
|
92
|
+
- id: open
|
|
115
93
|
description: >
|
|
116
|
-
Publish the branch (normal push only, never force; sets upstream when missing)
|
|
117
|
-
|
|
94
|
+
Publish the branch (normal push only, never force; sets upstream when missing) and reuse or
|
|
95
|
+
create its PR — a rejected push stops before any PR work. Writes FOUND|CREATED|FAIL to
|
|
96
|
+
.spur/run/${vars.__runId}-pr-open.status and the composed record (push + pr) to
|
|
97
|
+
.spur/run/${vars.__runId}-pr-open.json.
|
|
118
98
|
onEnter:
|
|
119
99
|
- kind: shell
|
|
120
100
|
options:
|
|
121
|
-
# (e) 0825:
|
|
122
|
-
#
|
|
101
|
+
# (e) 0825: 7 lines — publish + PR dedupe are one verb now; the status fallback keeps a
|
|
102
|
+
# silent driver from passing the gate.
|
|
123
103
|
command: >-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
> "
|
|
129
|
-
rc=$?; set -e &&
|
|
130
|
-
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
104
|
+
STATUS_FILE=".spur/run/$__runId-pr-open.status";
|
|
105
|
+
mkdir -p .spur/run;
|
|
106
|
+
$spurBin builder pr-open --base "$baseBranch" --json --status-file "$STATUS_FILE"
|
|
107
|
+
> ".spur/run/$__runId-pr-open.json";
|
|
108
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi;
|
|
131
109
|
exit 0
|
|
132
110
|
|
|
133
|
-
- id:
|
|
134
|
-
description: Find or create the GitHub PR for the current branch — never a duplicate.
|
|
135
|
-
onEnter:
|
|
136
|
-
- kind: shell
|
|
137
|
-
options:
|
|
138
|
-
# (e) 0825: 9 lines — PR dedupe lookup captures its record for the downstream
|
|
139
|
-
# review link; ensure + capture must not race.
|
|
140
|
-
command: >-
|
|
141
|
-
mkdir -p .spur/run &&
|
|
142
|
-
STATUS_FILE=".spur/run/$__runId-pr-ensure.status" &&
|
|
143
|
-
set +e &&
|
|
144
|
-
$spurBin builder pr ensure-pr --base "$baseBranch" --json
|
|
145
|
-
--status-file "$STATUS_FILE" > ".spur/run/$__runId-pr.json";
|
|
146
|
-
rc=$?; set -e &&
|
|
147
|
-
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
148
|
-
exit 0
|
|
149
|
-
|
|
150
|
-
- id: request
|
|
151
|
-
description: >
|
|
152
|
-
Post the `@codex review` request (per-HEAD dedupe unless mode=rerun forces).
|
|
153
|
-
Records the request under .spur/run/${vars.__runId}-pr-request.json.
|
|
154
|
-
onEnter:
|
|
155
|
-
- kind: shell
|
|
156
|
-
options:
|
|
157
|
-
# (e) 0825: 10 lines — the write-then-read split is the file-var transport feeding
|
|
158
|
-
# wait/collect and must stay one action (same record, same run scope).
|
|
159
|
-
command: >-
|
|
160
|
-
F="$([ "$mode" = rerun ] && echo --force)"; $spurBin builder pr request --focus "$focus" $F --json --status-file ".spur/run/$__runId-pr-request.status" > ".spur/run/$__runId-pr-request.json"; [ -f ".spur/run/$__runId-pr-request.status" ] || echo FAIL > ".spur/run/$__runId-pr-request.status"; jq -e . ".spur/run/$__runId-pr-request.json" >/dev/null 2>&1 && jq -r '.requestedAt // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-since.txt" && jq -r '.head // ""' ".spur/run/$__runId-pr-request.json" > ".spur/run/$__runId-pr-head.txt"; exit 0
|
|
161
|
-
|
|
162
|
-
- id: wait
|
|
111
|
+
- id: review
|
|
163
112
|
description: >
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
113
|
+
Request, wait for and collect the `@codex review` result on the current pushed HEAD
|
|
114
|
+
(per-HEAD dedupe unless mode=rerun; mode=submit or noWait=true stop at PENDING). Writes
|
|
115
|
+
CLEAN|FINDINGS|PENDING|FAIL to .spur/run/${vars.__runId}-pr-review.status — a wait timeout
|
|
116
|
+
is PENDING, never a failure — plus the composed findings record and the composite status.
|
|
168
117
|
onEnter:
|
|
169
|
-
- kind: file.read.into-var
|
|
170
|
-
options:
|
|
171
|
-
path: .spur/run/${vars.__runId}-pr-since.txt
|
|
172
|
-
var: prSince
|
|
173
|
-
- kind: file.read.into-var
|
|
174
|
-
options:
|
|
175
|
-
path: .spur/run/${vars.__runId}-pr-head.txt
|
|
176
|
-
var: prHead
|
|
177
118
|
- kind: shell
|
|
178
119
|
options:
|
|
179
|
-
# (e) 0825:
|
|
180
|
-
#
|
|
120
|
+
# (e) 0825: 10 lines — request/wait/collect are one verb now, so their result lands
|
|
121
|
+
# atomically; the status fallback covers a crashed driver. `mode=submit` or `noWait=true`
|
|
122
|
+
# pass --no-wait and `mode=rerun` passes --force, each as its own space-separated word
|
|
123
|
+
# (two substitutions, never concatenated). `/bin/sh -c` carries no `-e`, so a failed
|
|
124
|
+
# substitution is ignored.
|
|
181
125
|
command: >-
|
|
182
|
-
|
|
183
|
-
STATUS_FILE=".spur/run/$__runId-pr-
|
|
184
|
-
|
|
185
|
-
$spurBin builder pr
|
|
186
|
-
--json --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-
|
|
187
|
-
|
|
188
|
-
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi &&
|
|
126
|
+
O="$([ "$mode" = submit ] || [ "$noWait" = "true" ] && echo --no-wait) $([ "$mode" = rerun ] && echo --force)";
|
|
127
|
+
STATUS_FILE=".spur/run/$__runId-pr-review.status";
|
|
128
|
+
mkdir -p .spur/run;
|
|
129
|
+
$spurBin builder pr-review --focus "$focus" $O --timeout "$waitTimeoutSec" --interval "$waitIntervalSec"
|
|
130
|
+
--json --status-file "$STATUS_FILE" > ".spur/run/$__runId-pr-findings.json";
|
|
131
|
+
if [ ! -f "$STATUS_FILE" ]; then printf 'FAIL\n' > "$STATUS_FILE"; fi;
|
|
189
132
|
exit 0
|
|
190
|
-
|
|
191
|
-
- id: collect
|
|
192
|
-
description: >-
|
|
193
|
-
Normalize the latest current-HEAD Codex result and record composite PR/CI status.
|
|
194
|
-
Request record read via file.read.into-var vars (0771, see wait).
|
|
195
|
-
onEnter:
|
|
196
|
-
- kind: file.read.into-var
|
|
197
|
-
options:
|
|
198
|
-
path: .spur/run/${vars.__runId}-pr-since.txt
|
|
199
|
-
var: prSince
|
|
200
|
-
- kind: file.read.into-var
|
|
201
|
-
options:
|
|
202
|
-
path: .spur/run/${vars.__runId}-pr-head.txt
|
|
203
|
-
var: prHead
|
|
204
133
|
- kind: shell
|
|
205
134
|
options:
|
|
206
|
-
#
|
|
207
|
-
#
|
|
135
|
+
# The report reads the same composite PR/CI/Codex artifact as before (read-only, so a
|
|
136
|
+
# failed probe records its own error object instead of failing the collected run).
|
|
208
137
|
command: >-
|
|
209
|
-
|
|
138
|
+
$spurBin builder pr-status --json > ".spur/run/$__runId-pr-status.json" || true
|
|
210
139
|
|
|
211
140
|
- id: done
|
|
212
141
|
description: Terminal — review collected; findings artifact at .spur/run/${vars.__runId}-pr-findings.json
|
|
213
142
|
- id: pending
|
|
214
|
-
description: Terminal — review requested (or timed out) but not yet collected; run /sp:dev-pr-review
|
|
143
|
+
description: Terminal — review requested (or timed out) but not yet collected; run /sp:dev-pr-review status later
|
|
215
144
|
- id: failed
|
|
216
145
|
description: Terminal — a gate went red; the stage .status/.json artifacts under .spur/run name the blocker
|
|
217
146
|
|
|
218
147
|
transitions:
|
|
219
|
-
- from:
|
|
220
|
-
to: hygiene
|
|
221
|
-
description: Repo, gh auth, and clean tree verified
|
|
222
|
-
guard:
|
|
223
|
-
kind: shell
|
|
224
|
-
options:
|
|
225
|
-
command: 'test "$(cat .spur/run/$__runId-pr-preflight.status 2>/dev/null)" = PASS'
|
|
226
|
-
- from: preflight
|
|
227
|
-
to: failed
|
|
228
|
-
terminalReason: failed-check
|
|
229
|
-
description: Preflight red (detached HEAD, dirty tree, gh auth, no GitHub remote, or the current branch being the base branch) — stop before any publishing
|
|
230
|
-
guard:
|
|
231
|
-
kind: always
|
|
232
|
-
|
|
233
|
-
- from: hygiene
|
|
148
|
+
- from: check
|
|
234
149
|
to: precheck
|
|
235
150
|
description: Clean or warn-only — warnings ride along to the report
|
|
236
151
|
guard:
|
|
237
152
|
kind: shell
|
|
238
153
|
options:
|
|
239
|
-
command: 'grep -qE "^(PASS|WARN)$" .spur/run/$__runId-pr-
|
|
240
|
-
- from:
|
|
154
|
+
command: 'grep -qE "^(PASS|WARN)$" .spur/run/$__runId-pr-check.status 2>/dev/null'
|
|
155
|
+
- from: check
|
|
241
156
|
to: failed
|
|
242
157
|
terminalReason: failed-check
|
|
243
|
-
description: BLOCK (secrets/.env/conflict markers) or probe failure —
|
|
158
|
+
description: BLOCK (secrets/.env/conflict markers), a preflight failure (detached HEAD, dirty tree, gh auth, no GitHub remote, or the current branch being the base branch), or a probe failure — stop before any publishing
|
|
244
159
|
guard:
|
|
245
160
|
kind: always
|
|
246
161
|
|
|
247
162
|
- from: precheck
|
|
248
|
-
to:
|
|
163
|
+
to: open
|
|
249
164
|
description: Project fast check passed or was skipped
|
|
250
165
|
guard:
|
|
251
166
|
kind: shell
|
|
@@ -258,104 +173,37 @@ transitions:
|
|
|
258
173
|
guard:
|
|
259
174
|
kind: always
|
|
260
175
|
|
|
261
|
-
- from:
|
|
262
|
-
to:
|
|
263
|
-
description: Branch published
|
|
264
|
-
guard:
|
|
265
|
-
kind: shell
|
|
266
|
-
options:
|
|
267
|
-
command: 'grep -qE "^(PUSHED|UP_TO_DATE)$" .spur/run/$__runId-pr-push.status 2>/dev/null'
|
|
268
|
-
- from: push
|
|
269
|
-
to: failed
|
|
270
|
-
terminalReason: failed-check
|
|
271
|
-
description: Push rejected (e.g. non-fast-forward) — report; never force-push as a workaround
|
|
272
|
-
guard:
|
|
273
|
-
kind: always
|
|
274
|
-
|
|
275
|
-
- from: ensure-pr
|
|
276
|
-
to: request
|
|
277
|
-
description: PR found or created
|
|
278
|
-
guard:
|
|
279
|
-
kind: shell
|
|
280
|
-
options:
|
|
281
|
-
command: 'grep -qE "^(FOUND|CREATED)$" .spur/run/$__runId-pr-ensure.status 2>/dev/null'
|
|
282
|
-
- from: ensure-pr
|
|
283
|
-
to: failed
|
|
284
|
-
terminalReason: failed-check
|
|
285
|
-
description: No reviewable delta or PR creation failed — report the actual git/GitHub state
|
|
286
|
-
guard:
|
|
287
|
-
kind: always
|
|
288
|
-
|
|
289
|
-
# Declaration order matters: ALREADY_REVIEWED routes straight to collect (full mode dedupe);
|
|
290
|
-
# submit/noWait stop at pending; everything else waits.
|
|
291
|
-
- from: request
|
|
292
|
-
to: collect
|
|
293
|
-
description: Current HEAD already carries a Codex review — collect instead of duplicating
|
|
294
|
-
guard:
|
|
295
|
-
kind: shell
|
|
296
|
-
options:
|
|
297
|
-
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = ALREADY_REVIEWED'
|
|
298
|
-
- from: request
|
|
299
|
-
to: pending
|
|
300
|
-
description: Request already in flight, or mode=submit/--no-wait after posting — return pending
|
|
301
|
-
guard:
|
|
302
|
-
kind: shell
|
|
303
|
-
options:
|
|
304
|
-
# (e) 0825: 4-predicate guard — ALREADY_REQUESTED/REQUESTED pair state is the
|
|
305
|
-
# fallback route when the review driver stalls (mode/noWait honored).
|
|
306
|
-
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = ALREADY_REQUESTED || { test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = REQUESTED && { test "$mode" = "submit" || test "$noWait" = "true"; }; }'
|
|
307
|
-
- from: request
|
|
308
|
-
to: wait
|
|
309
|
-
description: Request posted — poll for the result
|
|
310
|
-
guard:
|
|
311
|
-
kind: shell
|
|
312
|
-
options:
|
|
313
|
-
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = REQUESTED'
|
|
314
|
-
- from: request
|
|
315
|
-
to: failed
|
|
316
|
-
terminalReason: failed-check
|
|
317
|
-
description: Request failed (no PR, gh error) — report the preserved error
|
|
318
|
-
guard:
|
|
319
|
-
kind: always
|
|
320
|
-
|
|
321
|
-
- from: wait
|
|
322
|
-
to: collect
|
|
323
|
-
description: Codex findings or an explicit clean result on the current HEAD found
|
|
324
|
-
guard:
|
|
325
|
-
kind: shell
|
|
326
|
-
options:
|
|
327
|
-
command: 'grep -qE "^(FOUND|CLEAN)$" .spur/run/$__runId-pr-wait.status 2>/dev/null'
|
|
328
|
-
- from: wait
|
|
329
|
-
to: pending
|
|
330
|
-
description: Poll budget exhausted — pending, not failed
|
|
176
|
+
- from: open
|
|
177
|
+
to: review
|
|
178
|
+
description: Branch published and PR found or created
|
|
331
179
|
guard:
|
|
332
180
|
kind: shell
|
|
333
181
|
options:
|
|
334
|
-
command: '
|
|
335
|
-
- from:
|
|
182
|
+
command: 'grep -qE "^(FOUND|CREATED)$" .spur/run/$__runId-pr-open.status 2>/dev/null'
|
|
183
|
+
- from: open
|
|
336
184
|
to: failed
|
|
337
185
|
terminalReason: failed-check
|
|
338
|
-
description:
|
|
186
|
+
description: Push rejected (e.g. non-fast-forward — report; never force-push as a workaround) or no reviewable delta or PR creation failed
|
|
339
187
|
guard:
|
|
340
188
|
kind: always
|
|
341
189
|
|
|
342
|
-
- from:
|
|
190
|
+
- from: review
|
|
343
191
|
to: done
|
|
344
192
|
description: Current-HEAD review collected (CLEAN/FINDINGS)
|
|
345
193
|
guard:
|
|
346
194
|
kind: shell
|
|
347
195
|
options:
|
|
348
|
-
command: 'grep -qE "^(FINDINGS|CLEAN)$" .spur/run/$__runId-pr-
|
|
349
|
-
- from:
|
|
196
|
+
command: 'grep -qE "^(FINDINGS|CLEAN)$" .spur/run/$__runId-pr-review.status 2>/dev/null'
|
|
197
|
+
- from: review
|
|
350
198
|
to: pending
|
|
351
|
-
description:
|
|
199
|
+
description: Request in flight, mode=submit/noWait, or a wait timeout — pending, not failed (collect later)
|
|
352
200
|
guard:
|
|
353
201
|
kind: shell
|
|
354
202
|
options:
|
|
355
|
-
command: 'test "$(cat .spur/run/$__runId-pr-
|
|
356
|
-
- from:
|
|
203
|
+
command: 'test "$(cat .spur/run/$__runId-pr-review.status 2>/dev/null)" = PENDING'
|
|
204
|
+
- from: review
|
|
357
205
|
to: failed
|
|
358
206
|
terminalReason: failed-check
|
|
359
|
-
description:
|
|
207
|
+
description: Review probe itself failed (no PR, gh error, moved HEAD)
|
|
360
208
|
guard:
|
|
361
209
|
kind: always
|