@gobing-ai/spur 0.3.92 → 0.3.94
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/pipeline-budgets.json +0 -7
- package/config/plugin-scripts.json +10 -0
- package/config/rules/boundary/test-subpath-boundary.yaml +48 -0
- package/config/rules/strict/runtime-boundaries.yaml +2 -1
- package/config/rules/structure/protected-files.yaml +4 -0
- package/config/templates/AGENTS.md +4 -0
- package/config/templates/docs/02_ROADMAP.md +2 -0
- package/config/templates/docs/03_ARCHITECTURE.md +3 -1
- package/config/templates/docs/04_DESIGN.md +2 -0
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +10 -2
- package/config/workflow-candidates.json +72 -1
- package/config/workflows/feature-verification.yaml +1 -0
- package/config/workflows/history-anatomy.yaml +2 -0
- package/config/workflows/idea-pipeline.yaml +67 -18
- package/config/workflows/pr-review.yaml +8 -0
- package/config/workflows/task-pipeline.yaml +171 -39
- package/config/workflows/wayfinder-resolution.yaml +5 -0
- package/config/workflows/wrapup-pipeline.yaml +55 -14
- package/package.json +9 -9
- package/plugins/sp/README.md +8 -3
- package/plugins/sp/commands/dev-review-session.md +4 -4
- package/plugins/sp/commands/dev-review.md +16 -5
- package/plugins/sp/commands/dev-run.md +2 -2
- package/plugins/sp/commands/dev-runall.md +2 -2
- package/plugins/sp/hooks/pi/guard-extension.ts +17 -36
- package/plugins/sp/lib/idea-handoff.generated.mjs +8 -4
- package/plugins/sp/lib/inline-run.generated.d.mts +3 -0
- package/plugins/sp/lib/inline-run.generated.mjs +48 -19
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/inline-pipeline-parity-check.ts +1 -1
- package/plugins/sp/scripts/inline-run-setup.mjs +117 -7
- package/plugins/sp/scripts/inline-run-setup.ts +211 -7
- package/plugins/sp/scripts/quality-gate.mjs +255 -6
- package/plugins/sp/scripts/quality-gate.ts +425 -9
- package/plugins/sp/scripts/residual-scan.mjs +13 -5
- package/plugins/sp/scripts/residual-scan.ts +34 -7
- package/plugins/sp/scripts/task-diffstat.mjs +156 -0
- package/plugins/sp/scripts/task-diffstat.ts +229 -0
- package/plugins/sp/scripts/wrapup-drift-probe.mjs +181 -0
- package/plugins/sp/scripts/wrapup-drift-probe.ts +258 -0
- package/plugins/sp/scripts/wrapup-steps.mjs +60 -1
- package/plugins/sp/scripts/wrapup-steps.ts +89 -4
- package/plugins/sp/skills/brainstorm/SKILL.md +2 -0
- package/plugins/sp/skills/brainstorm/references/workflows.md +17 -2
- package/plugins/sp/skills/code-verification/SKILL.md +2 -2
- package/plugins/sp/skills/code-verification/references/secu-review.md +3 -2
- package/plugins/sp/skills/session-review/SKILL.md +11 -9
- package/plugins/sp/skills/spur-check/SKILL.md +112 -0
- package/plugins/sp/skills/spur-dev/SKILL.md +2 -1
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +14 -2
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +8 -2
- package/plugins/sp/skills/spur-dev/references/document-authoring.md +85 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +46 -18
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +24 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +3 -2
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +34 -2
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +5 -5
- package/plugins/sp/skills/spur-dev/templates/design.md +31 -0
- package/plugins/sp/skills/spur-dev/templates/plan.md +32 -0
- package/plugins/sp/skills/spur-doctor/SKILL.md +60 -14
- package/schemas/state-machine-workflow.schema.json +4 -0
- package/spur.js +19577 -19822
- package/web/_astro/BoardApp.C02hAHPO.js +1 -0
- package/web/_astro/{BoardApp.CerSBgis.js → BoardApp.FTEs3-N8.js} +107 -105
- package/web/_astro/{TaskDetail.DCqiC-OZ.js → TaskDetail.C-GdsS-t.js} +1 -1
- package/web/_astro/arc.uuAf51IT.js +1 -0
- package/web/_astro/{architectureDiagram-3BPJPVTR.DM_vp_hO.js → architectureDiagram-3BPJPVTR.CGe629A1.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.DXVIiv0p.js → blockDiagram-GPEHLZMM.D1mGCq3p.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.BbF_zCxW.js → c4Diagram-AAUBKEIU.CMsolcde.js} +1 -1
- package/web/_astro/channel.fsgl7o5j.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.CAgQHpPC.js → chunk-2J33WTMH.CrGA3fik.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.BN-5tpw4.js → chunk-4BX2VUAB.DsLVVla0.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.CnPkEEr0.js → chunk-55IACEB6.Dxc59Tfi.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.BQzQeMVm.js → chunk-727SXJPM.CaEVE2Wy.js} +4 -4
- package/web/_astro/{chunk-AQP2D5EJ.B6xNyDnL.js → chunk-AQP2D5EJ.BiJ4HXeI.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.C7f9Ih78.js → chunk-FMBD7UC4.Mxf1fru5.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CNV1dFXT.js → chunk-ND2GUHAM.pyOWQixH.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.Cudn2TkJ.js → chunk-QZHKN3VN.BmEsg4vr.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.D1NwP50q.js → classDiagram-4FO5ZUOK.BHhhMFTO.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.D1NwP50q.js → classDiagram-v2-Q7XG4LA2.BHhhMFTO.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.B1wSL-Xb.js → cose-bilkent-S5V4N54A.2fH4YOlp.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.BmK52w8G.js → cynefin-OW5HDTMX.C2j1_lKL.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.Bfy5CTDT.js → dagre-BM42HDAG.hZ2NCTdT.js} +2 -2
- package/web/_astro/diagram-2AECGRRQ.Bfw5_EzK.js +43 -0
- package/web/_astro/diagram-5GNKFQAL.Bt1V_Tmk.js +10 -0
- package/web/_astro/{diagram-KO2AKTUF.CW_vMJ4z.js → diagram-KO2AKTUF.DEk-YFwp.js} +3 -3
- package/web/_astro/{diagram-LMA3HP47.B_8ZGF67.js → diagram-LMA3HP47.CDjndtQm.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BppnHsdS.js → diagram-OG6HWLK6.cFnUHScG.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.BEuHXcjJ.js → erDiagram-TEJ5UH35.DlhYp7NV.js} +5 -5
- package/web/_astro/{flowDiagram-I6XJVG4X.CH-UlnGr.js → flowDiagram-I6XJVG4X.DNTpsxfx.js} +4 -4
- package/web/_astro/{ganttDiagram-6RSMTGT7.BO81S85v.js → ganttDiagram-6RSMTGT7.DC_p36PI.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.XnPxPPZN.js → gitGraphDiagram-PVQCEYII.DkEqNI0P.js} +1 -1
- package/web/_astro/{infoDiagram-5YYISTIA.JyjYRu_T.js → infoDiagram-5YYISTIA.CrjioCTG.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BBRBF-Fo.js → ishikawaDiagram-YF4QCWOH.BcK0CN8n.js} +5 -5
- package/web/_astro/{journeyDiagram-JHISSGLW.C_iymSyp.js → journeyDiagram-JHISSGLW.p0CbBDX1.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.DdfW-Oqt.js → kanban-definition-UN3LZRKU.puHIFt6J.js} +7 -7
- package/web/_astro/{linear.C2_IkbZT.js → linear.Bb-3a1d7.js} +1 -1
- package/web/_astro/mermaid.core.CJDgXOJs.js +301 -0
- package/web/_astro/{mindmap-definition-RKZ34NQL.DAZIxQSK.js → mindmap-definition-RKZ34NQL.BoAZEI9t.js} +2 -2
- package/web/_astro/{pieDiagram-4H26LBE5.CN8sIhKM.js → pieDiagram-4H26LBE5.CJNSdqY7.js} +3 -3
- package/web/_astro/{quadrantDiagram-W4KKPZXB.3dGcX5GP.js → quadrantDiagram-W4KKPZXB.DtTy7_0Z.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.BV2y4dd6.js → requirementDiagram-4Y6WPE33.BNYV98Xg.js} +3 -3
- package/web/_astro/{sankeyDiagram-5OEKKPKP.Cqo15Tvo.js → sankeyDiagram-5OEKKPKP.DRq9DGHp.js} +4 -4
- package/web/_astro/{sequenceDiagram-3UESZ5HK.CROCPMJB.js → sequenceDiagram-3UESZ5HK.B7KdBFCm.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.RfXZrkFE.js → stateDiagram-AJRCARHV.CD62ZJ2H.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.CPXmbBs9.js → stateDiagram-v2-BHNVJYJU.CeVk1TAj.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DdgKTiO8.js → timeline-definition-PNZ67QCA.C_ZPA5tT.js} +3 -3
- package/web/_astro/{vennDiagram-CIIHVFJN.CPNVSHF1.js → vennDiagram-CIIHVFJN.CrThO_FQ.js} +5 -5
- package/web/_astro/{wardleyDiagram-YWT4CUSO.CQhA0Jyr.js → wardleyDiagram-YWT4CUSO.DSZCA5nl.js} +3 -3
- package/web/_astro/{xychartDiagram-2RQKCTM6.n61BWyy4.js → xychartDiagram-2RQKCTM6.KI7baTuk.js} +1 -1
- package/web/index.html +1 -1
- package/config/workflows/decision-routing-example.yaml +0 -134
- package/web/_astro/BoardApp.eoTz0pZs.js +0 -1
- package/web/_astro/arc.CPwg6Rw0.js +0 -1
- package/web/_astro/channel.MYZLKNwy.js +0 -1
- package/web/_astro/diagram-2AECGRRQ.DhNnvUvX.js +0 -43
- package/web/_astro/diagram-5GNKFQAL.lTX5KwnS.js +0 -10
- package/web/_astro/mermaid.core.GAOYeSR0.js +0 -303
|
@@ -48,13 +48,6 @@
|
|
|
48
48
|
"tokenCostUsd": null,
|
|
49
49
|
"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.",
|
|
50
50
|
"decision": null
|
|
51
|
-
},
|
|
52
|
-
"decision-routing-example": {
|
|
53
|
-
"modelQueries": 0,
|
|
54
|
-
"wallClockMs": null,
|
|
55
|
-
"tokenCostUsd": null,
|
|
56
|
-
"source": "Coverage entry (0911): authoring example (config/workflows/decision-routing-example.yaml) enumerating `decision:` modes. Measured 0 model queries — the producer is a shell action, so the example runs with no provider (live count via loadQueryCounts, 2026-09-20). Not a pipeline humans run; wall-clock and cost unenforced, never 0.",
|
|
57
|
-
"decision": null
|
|
58
51
|
}
|
|
59
52
|
}
|
|
60
53
|
}
|
|
@@ -36,6 +36,11 @@
|
|
|
36
36
|
"contract": "standard",
|
|
37
37
|
"twin": "idea-handoff.mjs"
|
|
38
38
|
},
|
|
39
|
+
{
|
|
40
|
+
"rel": "wrapup-drift-probe.ts",
|
|
41
|
+
"contract": "standard",
|
|
42
|
+
"twin": "wrapup-drift-probe.mjs"
|
|
43
|
+
},
|
|
39
44
|
{
|
|
40
45
|
"rel": "wrapup-steps.ts",
|
|
41
46
|
"contract": "standard",
|
|
@@ -96,6 +101,11 @@
|
|
|
96
101
|
"rel": "surface-drift-inventory.ts",
|
|
97
102
|
"contract": "repo-only"
|
|
98
103
|
},
|
|
104
|
+
{
|
|
105
|
+
"rel": "task-diffstat.ts",
|
|
106
|
+
"contract": "standard",
|
|
107
|
+
"twin": "task-diffstat.mjs"
|
|
108
|
+
},
|
|
99
109
|
{
|
|
100
110
|
"rel": "task-evidence-precheck.ts",
|
|
101
111
|
"contract": "repo-only"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
$schema: "@gobing-ai/spur/schemas/rule-file.schema.json"
|
|
2
|
+
# Test-only subpath boundary — @gobing-ai/spur-app/testing and the app's testing/
|
|
3
|
+
# module are for tests and the mock itself, never production sources (task 0975 R3).
|
|
4
|
+
#
|
|
5
|
+
# WHY: `@gobing-ai/spur-app/testing` (packages/app/src/testing/history-board-mock.ts)
|
|
6
|
+
# is a test-only mock subpath (E82). A production import couples shipped code to a
|
|
7
|
+
# fake, and it crept toward the server transport before 0961 severed the seam. The
|
|
8
|
+
# evaluator's glob matcher is segment-aware with `*`/`**` only (no brace groups), so
|
|
9
|
+
# the ts/tsx globs would need separate entries — the repo carries .ts sources only,
|
|
10
|
+
# matching the dao-boundary precedent.
|
|
11
|
+
#
|
|
12
|
+
# Scope covers src trees only: `<workspace>/tests/**` directories stay outside, and
|
|
13
|
+
# `packages/app/src/testing/**` (the mock's own home) is exempted explicitly.
|
|
14
|
+
rules:
|
|
15
|
+
- id: no-testing-subpath-import
|
|
16
|
+
description: >
|
|
17
|
+
Production sources must not import the @gobing-ai/spur-app/testing subpath
|
|
18
|
+
(history-board mock, E82/0961). Tests under <workspace>/tests/** and the
|
|
19
|
+
packages/app/src/testing/** module itself are exempt.
|
|
20
|
+
severity: error
|
|
21
|
+
evaluator:
|
|
22
|
+
type: forbidden-import
|
|
23
|
+
config:
|
|
24
|
+
forbidden:
|
|
25
|
+
- specifier: "@gobing-ai/spur-app/testing"
|
|
26
|
+
scope:
|
|
27
|
+
include:
|
|
28
|
+
- "apps/**/src/**/*.ts"
|
|
29
|
+
- "packages/**/src/**/*.ts"
|
|
30
|
+
exclude:
|
|
31
|
+
- "packages/app/src/testing/**"
|
|
32
|
+
|
|
33
|
+
- id: no-relative-testing-module-import
|
|
34
|
+
description: >
|
|
35
|
+
packages/app production sources must not reach the testing/ module through
|
|
36
|
+
relative imports (from './testing/…' or '../…/testing…'). The testing/**
|
|
37
|
+
module itself and workspace tests/ directories are exempt.
|
|
38
|
+
severity: error
|
|
39
|
+
evaluator:
|
|
40
|
+
type: forbidden-import
|
|
41
|
+
config:
|
|
42
|
+
forbidden:
|
|
43
|
+
- pattern: "(?:from\\s+|import\\(\\s*)['\"](\\.\\.?/)+(?:[^'\"]*/)?testing(?:/|['\"])"
|
|
44
|
+
scope:
|
|
45
|
+
include:
|
|
46
|
+
- "packages/app/src/**/*.ts"
|
|
47
|
+
exclude:
|
|
48
|
+
- "packages/app/src/testing/**"
|
|
@@ -73,6 +73,7 @@ rules:
|
|
|
73
73
|
|
|
74
74
|
# Synchronous template & workflow resolvers:
|
|
75
75
|
- "apps/cli/src/commands/task.ts" # sync loadTemplateContent/Bodies callbacks
|
|
76
|
-
- "packages/app/src/services/workflow-service.ts" #
|
|
76
|
+
- "packages/app/src/services/workflow-service.ts" # run-log/checkpoint reclamation realpath confinement (:988, :1014)
|
|
77
|
+
- "packages/app/src/workflow/run-record.ts" # confined sync run-record reads: realpath + fstat byte-window (moved from workflow-service.ts, 0962)
|
|
77
78
|
- "apps/cli/src/release-ops.ts" # sync manifest/workspace reads + Bun.write rewrites inside the git release flow (task 0617); mirrors task.ts sync-template exemption
|
|
78
79
|
- "apps/cli/src/version-carriers.ts" # sync manifest reads + Bun.write rewrites for registered release carriers (task 0854); mirrors release-ops.ts sync exemption
|
|
@@ -37,6 +37,10 @@ rules:
|
|
|
37
37
|
# this rule's include scope — scanning generated copies only adds noise
|
|
38
38
|
# (e.g. `id: task-implement-transition` trips the sk- token shape).
|
|
39
39
|
- "apps/cli/config/"
|
|
40
|
+
# `apps/cli/plugins/` is the same kind of gitignored build:bundle output — a staged
|
|
41
|
+
# npm copy of `plugins/`, itself outside the include scope. Minified generated libs
|
|
42
|
+
# there trip the api-key shape (0976: HEAD's inline-run.generated.mjs fires too).
|
|
43
|
+
- "apps/cli/plugins/"
|
|
40
44
|
|
|
41
45
|
- id: no-unsafe-git-commands
|
|
42
46
|
description: "Unsafe git commands (force-push, hard reset) can overwrite history or cause data loss (AGENTS.md CRITICAL safety)."
|
|
@@ -95,6 +95,10 @@ It owns document responsibilities and maintenance; `00` owns architectural choic
|
|
|
95
95
|
`01` product scope, and root `DESIGN.md` UI/UX. Use **`sp:doc-evolve`** for drift,
|
|
96
96
|
sync and contract checks. Follow host/operator precedence.
|
|
97
97
|
|
|
98
|
+
For new `docs/plans/` working records and `docs/design/` non-UI satellites, use the
|
|
99
|
+
`sp:spur-dev` plan/design templates and document-authoring reference. Preserve legacy files' history
|
|
100
|
+
and headings when revising them; `sp:spur-doctor` can propose safe upgrades.
|
|
101
|
+
|
|
98
102
|
### Doc map
|
|
99
103
|
|
|
100
104
|
| File | Owns | Update when |
|
|
@@ -16,6 +16,8 @@ sync: [T5, T6]
|
|
|
16
16
|
|
|
17
17
|
Phase goals, order, dependencies and exits only. Detailed feature state belongs in the
|
|
18
18
|
feature tool's index; task progress belongs in task records (constitution §6.3).
|
|
19
|
+
Detailed proposals and investigations may live in dated `docs/plans/` working records;
|
|
20
|
+
link accepted phase changes here without copying the plan.
|
|
19
21
|
|
|
20
22
|
## Phase 0 — Foundation
|
|
21
23
|
|
|
@@ -31,4 +31,6 @@ _(Describe the primary data path: input → processing → output. Name the seam
|
|
|
31
31
|
<!--
|
|
32
32
|
Describes the CURRENT architecture only. Future/accepted designs go in sections explicitly
|
|
33
33
|
titled "(accepted design — ADR-NNN; not yet built)". Keep command/schema detail in 04 satellites and task delivery receipts in task records.
|
|
34
|
-
|
|
34
|
+
Use the `sp:spur-dev` design template for a new non-UI satellite; link it instead of copying its
|
|
35
|
+
contract here.
|
|
36
|
+
-->
|
|
@@ -16,6 +16,8 @@ sync: [T3, T9]
|
|
|
16
16
|
|
|
17
17
|
Non-UI contract index (constitution §6.5). Keep signatures, schemas, defaults, errors
|
|
18
18
|
and boundary behavior in the owning `docs/design/<slug>.md` satellite.
|
|
19
|
+
Start a new satellite from the `sp:spur-dev` design template; distinguish proposed from current
|
|
20
|
+
behavior and preserve existing headings when revising one.
|
|
19
21
|
|
|
20
22
|
## UI/UX boundary & DESIGN.md
|
|
21
23
|
|
|
@@ -3,7 +3,7 @@ name: Project Constitution
|
|
|
3
3
|
doc: 99_PROJECT_CONSTITUTION
|
|
4
4
|
owns: PROCESS — how the key files are maintained
|
|
5
5
|
authority: authoritative-on-process
|
|
6
|
-
version: 1.
|
|
6
|
+
version: 1.8.0
|
|
7
7
|
created_at: {{init-date}}
|
|
8
8
|
updated_at: {{init-date}}
|
|
9
9
|
edit_rules: 99 §6.8
|
|
@@ -70,11 +70,15 @@ size, approval, task count, or completion alone does not qualify it for an ADR (
|
|
|
70
70
|
### 4.2 Working layers (outside the authority chain)
|
|
71
71
|
|
|
72
72
|
- Dated `docs/plans/` and `docs/reports/` files hold proposals, investigations, audits and evidence.
|
|
73
|
-
They record work; accepted conclusions take effect only in their proper owner.
|
|
73
|
+
They record work; accepted conclusions take effect only in their proper owner. New plan files use
|
|
74
|
+
ordinary Markdown with concise frontmatter and purpose, evidence, recommendation, and follow-up
|
|
75
|
+
as applicable; the `sp:spur-dev` plan template is a starting point, not a rigid schema.
|
|
74
76
|
- Configured task folders hold requirements, implementation plans, results and verification,
|
|
75
77
|
maintained through the task tool. Resolve their paths through that tool.
|
|
76
78
|
- Existing project context or learning storage holds reusable lessons (§8).
|
|
77
79
|
- `docs/design/` and `docs/features/` are governed detail layers (§4.5), not scratch storage.
|
|
80
|
+
New non-UI design satellites use the `sp:spur-dev` design template; revisions preserve existing
|
|
81
|
+
meaning and references.
|
|
78
82
|
|
|
79
83
|
Preserve historical evidence and its dates. It may be linked for provenance, but current
|
|
80
84
|
contracts must be understandable without treating an old plan or report as governing policy.
|
|
@@ -90,6 +94,8 @@ Use `authoritative` for `00`, `authoritative-on-scope` for `01`,
|
|
|
90
94
|
`owns` must match §4.1 in meaning. Bump the minor version for substantive edits and refresh
|
|
91
95
|
`updated_at` when content changes. Do not touch unrelated documents just to update a date.
|
|
92
96
|
Keep one metadata block. Root entry/UI files may use their established native format.
|
|
97
|
+
Plans and design satellites use lighter frontmatter for identity, truthful status and dates;
|
|
98
|
+
legacy files without it remain valid and readable. Do not infer historical status from a template.
|
|
93
99
|
|
|
94
100
|
### 4.4 AGENTS.md synchronization
|
|
95
101
|
|
|
@@ -194,6 +200,8 @@ Keep the index short. Satellites own non-UI signatures, schemas, defaults, error
|
|
|
194
200
|
and boundary behavior. Verify against registrations/contracts; prefer generated artifacts to
|
|
195
201
|
manual copies. UI rules belong in root `DESIGN.md`; architectural rationale belongs in `00`/`03`.
|
|
196
202
|
Separate proposed from current behavior. A completed task adds no delivery receipt here.
|
|
203
|
+
Use the design template to structure new satellites around boundaries, contracts, invariants and
|
|
204
|
+
compatibility. Preserve stable headings and historical claims when revising old ones.
|
|
197
205
|
|
|
198
206
|
### 6.6 `docs/05_FEATURES.md` + `docs/features/<feature-id>_<slug>.md`
|
|
199
207
|
|
|
@@ -1,7 +1,72 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"note": "Workflow graph-change promotion candidates (task 0873, feature D62; ADR-076 amendment). A candidate is shadow-run against recorded real-run inputs and is promoted into the canonical definition or deleted by its named deadline — never left as a standing parallel <name>2.yaml. `verdict` is null while pending and is filled by `bun scripts/spur-dev.ts promotion evaluate <id>`; `promotion check` (spur-check-feature) fails any candidate still present past its deadline, any unreferenced parallel definition in config/workflows/, and (0877 R8) any retired definition with real (non-dry) terminal runs lacking a recorded decision in `retirements[]`.",
|
|
4
|
-
"candidates": [
|
|
4
|
+
"candidates": [
|
|
5
|
+
{
|
|
6
|
+
"id": "task-pipeline-triage-lanes",
|
|
7
|
+
"canonical": "task-pipeline",
|
|
8
|
+
"deadline": "2026-11-24",
|
|
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).",
|
|
11
|
+
"measurement": {
|
|
12
|
+
"workflow": "task-pipeline"
|
|
13
|
+
},
|
|
14
|
+
"delta": {
|
|
15
|
+
"agentRunCount": 0,
|
|
16
|
+
"baselineAgentRunCount": 0,
|
|
17
|
+
"note": "Structural graph agent.run count unchanged (no new model state); fast-lane runs save the existing review agent.run (1 fewer on triage-low diffs), retryable classification can save fixall fix hops. baselineAgentRunCount = 0938 task-pipeline agentRunCountMedian."
|
|
18
|
+
},
|
|
19
|
+
"verdict": null
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "check-dedup-task-pipeline",
|
|
23
|
+
"canonical": "task-pipeline",
|
|
24
|
+
"deadline": "2026-11-24",
|
|
25
|
+
"createdAt": "2026-09-25",
|
|
26
|
+
"rationale": "0940 (feature D64): the comprehensive check runs once at the quality boundary — no-progress rechecks skip the full gate to the probe path (check.skipped-no-progress) and review confirms the check receipt (check.reused) instead of re-running tests/lint. 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; per-state rows cover only `record` (visits=0) — no test-recheck/review state-level wall deltas exist yet, so the benefit is projected as wall time (full-gate vs probe cost on no-progress loops, plus removed review-stage re-runs), not agent.run count. Measured-benefit status: projected from 0938, NOT shadow-run-confirmed; `promotion evaluate` runs post-merge against recorded runs. If it does not beat the baseline, it is reverted (ADR-076).",
|
|
27
|
+
"measurement": {
|
|
28
|
+
"workflow": "task-pipeline"
|
|
29
|
+
},
|
|
30
|
+
"delta": {
|
|
31
|
+
"agentRunCount": 0,
|
|
32
|
+
"baselineAgentRunCount": 0,
|
|
33
|
+
"note": "No agent.run delta by design: check dedup removes full-gate wall time on no-progress rechecks and model-stage re-runs, not model hops. baselineAgentRunCount = 0938 task-pipeline agentRunCountMedian."
|
|
34
|
+
},
|
|
35
|
+
"verdict": null
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "wrapup-drift-probe",
|
|
39
|
+
"canonical": "wrapup-pipeline",
|
|
40
|
+
"deadline": "2026-11-24",
|
|
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).",
|
|
43
|
+
"measurement": {
|
|
44
|
+
"workflow": "wrapup-pipeline"
|
|
45
|
+
},
|
|
46
|
+
"delta": {
|
|
47
|
+
"agentRunCount": 0,
|
|
48
|
+
"baselineAgentRunCount": 1,
|
|
49
|
+
"note": "Clean wrap skips the single doc-sync agent.run (1 -> 0 for those wraps). baselineAgentRunCount = 1 structural doc-sync agent.run per wrapup run (wrapup-pipeline declares one model query — config/pipeline-budgets.json); the 0938 snapshot records 0 wrapup runs (agentRunCountMedian null), so no measured median exists yet."
|
|
50
|
+
},
|
|
51
|
+
"verdict": null
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"id": "idea-pipeline-guard-legibility",
|
|
55
|
+
"canonical": "idea-pipeline",
|
|
56
|
+
"deadline": "2026-11-24",
|
|
57
|
+
"createdAt": "2026-09-25",
|
|
58
|
+
"rationale": "0945 (feature D64): the four idea-pipeline route guards (ac-generate/feature-check → system-design|decompose) read derived fact files (.spur/run/<runId>-idea-design-route.txt, <runId>-idea-ac-ready.status) written by one deterministic shell action at the end of both ac-generate and feature-check onEnter, instead of re-deriving design×needs_design and dual status reads inline — guards drop from 4-5 logical commands with (warn) markers to 3 predicates with no warn (ADR-115), and routing is proven identical by the executed truth-table test (idea-pipeline-routing.test.ts: the frozen pre-refactor guards are the oracle across profile × __hitlAnswer × design × needs_design × ac × coverage, 3456 cells, plus the guard-parity fixture refreshed per the 0874→0887 protocol). Projected basis: 0938 terminal-reason coverage for idea-pipeline is 100% classified for new runs (all nine failure-state edges declare terminalReason under 0937), so route outcomes stay measurable per terminalReason; this is projected from structure, NOT shadow-run-confirmed — promotion evaluate fills the verdict post-merge, and a losing candidate reverts (ADR-076).",
|
|
59
|
+
"measurement": {
|
|
60
|
+
"workflow": "idea-pipeline"
|
|
61
|
+
},
|
|
62
|
+
"verdict": null,
|
|
63
|
+
"delta": {
|
|
64
|
+
"agentRunCount": 6,
|
|
65
|
+
"baselineAgentRunCount": 6,
|
|
66
|
+
"note": "No agent.run delta by design: legibility derives the route facts in shell, model hops are unchanged (composition baseline modelQueries=6 in config/pipeline-budgets.json holds). baselineAgentRunCount = 0938 idea-pipeline agentRunCountMedian."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
],
|
|
5
70
|
"retirements": [
|
|
6
71
|
{
|
|
7
72
|
"name": "planning-pipeline",
|
|
@@ -14,6 +79,12 @@
|
|
|
14
79
|
"recordedBy": "ADR-076 (commit 017ac7a30)",
|
|
15
80
|
"date": "2026-08-20",
|
|
16
81
|
"rationale": "Standing parallel definition deleted with the D5-N fixture promotion bar; 5 real terminal runs retained in history."
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "decision-routing-example",
|
|
85
|
+
"recordedBy": "0946 (D64)",
|
|
86
|
+
"date": "2026-09-25",
|
|
87
|
+
"rationale": "Example-only authoring sample (0911 D7, retained-as-example 0921) retired per the mechanical catalogue rule (D64 design §10): zero real runs in the 0938 window (2026-06-01, run-record plane) and no live caller — only the plugin README catalogue row, a 0-query budget coverage entry and design/help doc mentions. YAML deleted; README row, budget entry and doc mentions removed; the decision-policy regression fixture moved to packages/app/tests/services/fixtures/decision-routing-example.yaml (workflow-service.test.ts decision-policy block). Its exit also dropped `hitl.select` from the live action union, so the inline-pipeline-parity-check DOCUMENTED set and driver mirror dropped it (parity contract). No run history deleted; 0 real terminal runs retained in history."
|
|
17
88
|
}
|
|
18
89
|
]
|
|
19
90
|
}
|
|
@@ -74,6 +74,7 @@ transitions:
|
|
|
74
74
|
command: 'test "$(cat .spur/run/$__runId-feature-verification.status 2>/dev/null)" = PASS'
|
|
75
75
|
- from: verify
|
|
76
76
|
to: failed
|
|
77
|
+
terminalReason: failed-check
|
|
77
78
|
description: Repo-wide checks failed (or the evidence is missing/corrupt) — stop at failed.
|
|
78
79
|
guard:
|
|
79
80
|
kind: always
|
|
@@ -391,6 +391,7 @@ transitions:
|
|
|
391
391
|
command: 'grep -q "^PASS$" .spur/run/$__runId-structure-gate.txt 2>/dev/null'
|
|
392
392
|
- from: structure-gate
|
|
393
393
|
to: failed
|
|
394
|
+
terminalReason: retry-exhausted
|
|
394
395
|
description: Structure gate FAIL with the correction cap exhausted — never publish a malformed candidate.
|
|
395
396
|
guard:
|
|
396
397
|
kind: shell
|
|
@@ -418,6 +419,7 @@ transitions:
|
|
|
418
419
|
command: '! tail -n 1 .spur/run/$__runId-validation.txt 2>/dev/null | grep -qx "Verdict: PASS" && test "$(cat .spur/run/$__runId-correction-count 2>/dev/null || echo 0)" -lt 2'
|
|
419
420
|
- from: validate
|
|
420
421
|
to: failed
|
|
422
|
+
terminalReason: retry-exhausted
|
|
421
423
|
description: Validation FAIL with the correction cap exhausted — terminate without publishing.
|
|
422
424
|
guard:
|
|
423
425
|
kind: always
|
|
@@ -262,6 +262,23 @@ states:
|
|
|
262
262
|
printf 'FAIL run=%s checker not found — run superskill install sp\n' "$__runId" | tee ".spur/run/$__runId-idea-coverage.reason" >&2;
|
|
263
263
|
printf 'FAIL\n' > ".spur/run/$__runId-idea-coverage.status";
|
|
264
264
|
fi
|
|
265
|
+
# 0945 R2: derive the route facts ONCE at this boundary (0769 pattern) — guards read these
|
|
266
|
+
# named files instead of re-deriving design×needs_design inline. The same command is
|
|
267
|
+
# duplicated in feature-check's onEnter (YAML has no include); byte-equality is
|
|
268
|
+
# test-pinned (idea-pipeline-routing.test.ts). Missing/corrupt needs-design JSON fails
|
|
269
|
+
# safe to `design`; readiness is PASS only when both recorded checks are PASS.
|
|
270
|
+
# (warn) 7 commands: two three-way `test && printf || printf` derivations over captured
|
|
271
|
+
# signal files (ADR-115); no model hop, no CLI re-run.
|
|
272
|
+
- kind: shell
|
|
273
|
+
options:
|
|
274
|
+
command: >-
|
|
275
|
+
mkdir -p .spur/run &&
|
|
276
|
+
{ test "$design" = skip -o "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false &&
|
|
277
|
+
printf 'skip\n' > .spur/run/$__runId-idea-design-route.txt ||
|
|
278
|
+
printf 'design\n' > .spur/run/$__runId-idea-design-route.txt; } &&
|
|
279
|
+
{ test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS -a "$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" = PASS &&
|
|
280
|
+
printf 'PASS\n' > .spur/run/$__runId-idea-ac-ready.status ||
|
|
281
|
+
printf 'FAIL\n' > .spur/run/$__runId-idea-ac-ready.status; }
|
|
265
282
|
|
|
266
283
|
- id: feature-check
|
|
267
284
|
description: >
|
|
@@ -286,6 +303,19 @@ states:
|
|
|
286
303
|
prompt: "Feature check for ${vars.featureId}. Review the AC and confirm to proceed? Requirement coverage status: $(cat .spur/run/${vars.__runId}-idea-coverage.status 2>/dev/null || echo unknown) — reason: $(cat .spur/run/${vars.__runId}-idea-coverage.reason 2>/dev/null || echo n/a) (.spur/run/${vars.__runId}-idea-coverage.status[.reason]). (Failures route back to ac-generate for revision, capped at 3 retries.)"
|
|
287
304
|
decision:
|
|
288
305
|
mode: never
|
|
306
|
+
# 0945 R2: same writer as ac-generate's onEnter (byte-equal, test-pinned) — refreshes the
|
|
307
|
+
# derived route facts after the interactive gate so both entries into this boundary read
|
|
308
|
+
# consistent files; hitl.confirm only sets $__hitlAnswer.
|
|
309
|
+
- kind: shell
|
|
310
|
+
options:
|
|
311
|
+
command: >-
|
|
312
|
+
mkdir -p .spur/run &&
|
|
313
|
+
{ test "$design" = skip -o "$design" = auto -a "$(jq -r .needs_design .spur/run/$__runId-idea-needs-design.json 2>/dev/null)" = false &&
|
|
314
|
+
printf 'skip\n' > .spur/run/$__runId-idea-design-route.txt ||
|
|
315
|
+
printf 'design\n' > .spur/run/$__runId-idea-design-route.txt; } &&
|
|
316
|
+
{ test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS -a "$(cat .spur/run/$__runId-idea-coverage.status 2>/dev/null)" = PASS &&
|
|
317
|
+
printf 'PASS\n' > .spur/run/$__runId-idea-ac-ready.status ||
|
|
318
|
+
printf 'FAIL\n' > .spur/run/$__runId-idea-ac-ready.status; }
|
|
289
319
|
|
|
290
320
|
- id: system-design
|
|
291
321
|
description: >
|
|
@@ -567,6 +597,7 @@ transitions:
|
|
|
567
597
|
command: 'test "$(cat .spur/run/$__runId-idea-precheck-doctor.status 2>/dev/null)" = PASS'
|
|
568
598
|
- from: start
|
|
569
599
|
to: failed
|
|
600
|
+
terminalReason: failed-check
|
|
570
601
|
description: Agent doctor FAIL — stop before discovery.
|
|
571
602
|
guard:
|
|
572
603
|
kind: always
|
|
@@ -606,6 +637,7 @@ transitions:
|
|
|
606
637
|
command: 'test "$__hitlAnswer" = yes'
|
|
607
638
|
- from: idea-eval
|
|
608
639
|
to: cancelled
|
|
640
|
+
terminalReason: cancelled
|
|
609
641
|
description: Idea evaluation rejected or cancelled — no feature created.
|
|
610
642
|
guard:
|
|
611
643
|
kind: shell
|
|
@@ -621,9 +653,11 @@ transitions:
|
|
|
621
653
|
|
|
622
654
|
# ── ac-generate: auto-skip (profile=auto) OR enter feature-check HITL gate (interactive) ──
|
|
623
655
|
# Declaration order: auto-skip guards tried FIRST (same pattern as task-pipeline review→verify
|
|
624
|
-
# and design-gen→handoff). Under profile=auto, the
|
|
625
|
-
# recorded
|
|
626
|
-
#
|
|
656
|
+
# and design-gen→handoff). Under profile=auto, the derived route facts — the ready file (both
|
|
657
|
+
# recorded checks PASS, 0887 R4) and the design route file (0945 R2 writer at the end of both
|
|
658
|
+
# ac-generate and feature-check onEnter) — route directly to the appropriate next state:
|
|
659
|
+
# guards never re-run the CLI or the checker and never re-derive the signals (task 0769).
|
|
660
|
+
# Under interactive, the
|
|
627
661
|
# always fallback enters the feature-check state whose onEnter hitl.confirm pauses for
|
|
628
662
|
# operator confirmation (coverage is surfaced in that prompt; the operator's answer governs).
|
|
629
663
|
#
|
|
@@ -631,25 +665,29 @@ transitions:
|
|
|
631
665
|
- from: ac-generate
|
|
632
666
|
to: system-design
|
|
633
667
|
description: "profile=auto, check passed, requirements covered, design route — run system design."
|
|
634
|
-
#
|
|
635
|
-
#
|
|
668
|
+
# 0945 R3: three predicates over derived facts — the ready file folds both recorded check
|
|
669
|
+
# statuses (PASS only when ac-check AND coverage are PASS), the route file folds
|
|
670
|
+
# design×needs_design (fail-safe design); nothing re-runs, nothing re-derives (0769).
|
|
636
671
|
guard:
|
|
637
672
|
kind: shell
|
|
638
673
|
options:
|
|
639
674
|
command: >-
|
|
640
|
-
|
|
641
|
-
test "$
|
|
675
|
+
test "$profile" = auto &&
|
|
676
|
+
test "$(cat .spur/run/$__runId-idea-ac-ready.status 2>/dev/null)" = PASS &&
|
|
677
|
+
test "$(cat .spur/run/$__runId-idea-design-route.txt 2>/dev/null)" = design
|
|
642
678
|
# Auto-skip 2: pass + coverage + skip-design route → decompose
|
|
643
679
|
- from: ac-generate
|
|
644
680
|
to: decompose
|
|
645
681
|
description: "profile=auto, check passed, requirements covered, skip-design route — go directly to decompose."
|
|
646
|
-
#
|
|
647
|
-
#
|
|
648
|
-
# signal file authoritative for both routes (0769).
|
|
682
|
+
# 0945 R3: mirror of the design-route guard over the same derived facts with route=skip;
|
|
683
|
+
# one captured signal file per fact keeps both routes symmetric (0769).
|
|
649
684
|
guard:
|
|
650
685
|
kind: shell
|
|
651
686
|
options:
|
|
652
|
-
command:
|
|
687
|
+
command: >-
|
|
688
|
+
test "$profile" = auto &&
|
|
689
|
+
test "$(cat .spur/run/$__runId-idea-ac-ready.status 2>/dev/null)" = PASS &&
|
|
690
|
+
test "$(cat .spur/run/$__runId-idea-design-route.txt 2>/dev/null)" = skip
|
|
653
691
|
# Auto-skip 3: check or coverage failed, retry < 3 → loop back to ac-generate (self-loop)
|
|
654
692
|
- from: ac-generate
|
|
655
693
|
to: ac-generate
|
|
@@ -666,6 +704,7 @@ transitions:
|
|
|
666
704
|
# Auto-skip 4: check or coverage failed, retry cap reached → escalate to failed
|
|
667
705
|
- from: ac-generate
|
|
668
706
|
to: failed
|
|
707
|
+
terminalReason: retry-exhausted
|
|
669
708
|
description: "profile=auto, check or coverage failed after 3 retries — escalate to failed."
|
|
670
709
|
# (warn) 5 commands: mirror of the retry guard with cap>=3; keeping escalation and retry as one
|
|
671
710
|
# test-chain pair makes the cap boundary auditable in the diff (0769).
|
|
@@ -687,23 +726,27 @@ transitions:
|
|
|
687
726
|
- from: feature-check
|
|
688
727
|
to: system-design
|
|
689
728
|
description: Feature check passed, design route — run system design.
|
|
690
|
-
#
|
|
691
|
-
#
|
|
729
|
+
# 0945 R3: three predicates over derived facts — the recorded ac-check status stays the
|
|
730
|
+
# conjunct here (parity: the operator's answer governs the interactive gate, 0887), the
|
|
731
|
+
# route file folds design×needs_design (fail-safe design); nothing re-runs (0769).
|
|
692
732
|
guard:
|
|
693
733
|
kind: shell
|
|
694
734
|
options:
|
|
695
735
|
command: >-
|
|
696
|
-
|
|
697
|
-
test "$
|
|
736
|
+
test "$__hitlAnswer" = yes &&
|
|
737
|
+
test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS &&
|
|
738
|
+
test "$(cat .spur/run/$__runId-idea-design-route.txt 2>/dev/null)" = design
|
|
698
739
|
- from: feature-check
|
|
699
740
|
to: decompose
|
|
700
741
|
description: Feature check passed, skip-design route — go directly to decompose.
|
|
701
|
-
#
|
|
702
|
-
# design=auto/needs_design=false pair (0769).
|
|
742
|
+
# 0945 R3: mirror of the design-route guard over the same derived facts with route=skip.
|
|
703
743
|
guard:
|
|
704
744
|
kind: shell
|
|
705
745
|
options:
|
|
706
|
-
command:
|
|
746
|
+
command: >-
|
|
747
|
+
test "$__hitlAnswer" = yes &&
|
|
748
|
+
test "$(cat .spur/run/$__runId-idea-ac-check.status 2>/dev/null)" = PASS &&
|
|
749
|
+
test "$(cat .spur/run/$__runId-idea-design-route.txt 2>/dev/null)" = skip
|
|
707
750
|
- from: feature-check
|
|
708
751
|
to: ac-generate
|
|
709
752
|
description: "Feature check failed — revise AC (retry cap: 3)."
|
|
@@ -717,6 +760,7 @@ transitions:
|
|
|
717
760
|
(test "$__hitlAnswer" = no || test "$ac_status" != PASS) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -lt 3
|
|
718
761
|
- from: feature-check
|
|
719
762
|
to: failed
|
|
763
|
+
terminalReason: retry-exhausted
|
|
720
764
|
description: Feature check failed after 3 retries — escalate to failed.
|
|
721
765
|
# (warn) 5 commands (named status capture + 4 conditions): mirror of the revise guard with cap>=3 (0769).
|
|
722
766
|
guard:
|
|
@@ -727,6 +771,7 @@ transitions:
|
|
|
727
771
|
(test "$__hitlAnswer" = no || test "$ac_status" != PASS) && test "$(cat .spur/run/$__runId-idea-ac-retry-count 2>/dev/null || echo 0)" -ge 3
|
|
728
772
|
- from: feature-check
|
|
729
773
|
to: cancelled
|
|
774
|
+
terminalReason: cancelled
|
|
730
775
|
description: Operator cancelled the feature-check gate.
|
|
731
776
|
guard:
|
|
732
777
|
kind: shell
|
|
@@ -772,6 +817,7 @@ transitions:
|
|
|
772
817
|
command: 'test "$__hitlAnswer" = no && test "$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0)" -le 1'
|
|
773
818
|
- from: design-approval
|
|
774
819
|
to: failed
|
|
820
|
+
terminalReason: retry-exhausted
|
|
775
821
|
description: "Design rejected after 1 revise - design-approval gate exhausted (R7 0433)."
|
|
776
822
|
guard:
|
|
777
823
|
kind: shell
|
|
@@ -779,6 +825,7 @@ transitions:
|
|
|
779
825
|
command: 'test "$__hitlAnswer" = no && test "$(cat .spur/run/$__runId-idea-design-reject-count 2>/dev/null || echo 0)" -gt 1'
|
|
780
826
|
- from: design-approval
|
|
781
827
|
to: cancelled
|
|
828
|
+
terminalReason: cancelled
|
|
782
829
|
description: Operator cancelled design approval.
|
|
783
830
|
guard:
|
|
784
831
|
kind: shell
|
|
@@ -816,6 +863,7 @@ transitions:
|
|
|
816
863
|
command: 'test "$__hitlAnswer" = no'
|
|
817
864
|
- from: batch-create
|
|
818
865
|
to: cancelled
|
|
866
|
+
terminalReason: cancelled
|
|
819
867
|
description: Operator cancelled batch creation.
|
|
820
868
|
guard:
|
|
821
869
|
kind: shell
|
|
@@ -845,6 +893,7 @@ transitions:
|
|
|
845
893
|
command: 'test -f .spur/run/$__runId-idea-batch-create.failed && test "$(cat .spur/run/$__runId-idea-decompose-retry-count 2>/dev/null || echo 0)" -lt 3'
|
|
846
894
|
- from: batch-create-run
|
|
847
895
|
to: failed
|
|
896
|
+
terminalReason: retry-exhausted
|
|
848
897
|
description: Batch-create failed after 3 retries — escalate to failed.
|
|
849
898
|
guard:
|
|
850
899
|
kind: shell
|
|
@@ -223,6 +223,7 @@ transitions:
|
|
|
223
223
|
command: 'test "$(cat .spur/run/$__runId-pr-preflight.status 2>/dev/null)" = PASS'
|
|
224
224
|
- from: preflight
|
|
225
225
|
to: failed
|
|
226
|
+
terminalReason: failed-check
|
|
226
227
|
description: Preflight red (detached HEAD, dirty tree, gh auth, no GitHub remote, or the current branch being the base branch) — stop before any publishing
|
|
227
228
|
guard:
|
|
228
229
|
kind: always
|
|
@@ -236,6 +237,7 @@ transitions:
|
|
|
236
237
|
command: 'grep -qE "^(PASS|WARN)$" .spur/run/$__runId-pr-hygiene.status 2>/dev/null'
|
|
237
238
|
- from: hygiene
|
|
238
239
|
to: failed
|
|
240
|
+
terminalReason: failed-check
|
|
239
241
|
description: BLOCK (secrets/.env/conflict markers) or probe failure — never submit a tainted diff
|
|
240
242
|
guard:
|
|
241
243
|
kind: always
|
|
@@ -249,6 +251,7 @@ transitions:
|
|
|
249
251
|
command: 'grep -qE "^(PASS|SKIP)$" .spur/run/$__runId-pr-precheck.status 2>/dev/null'
|
|
250
252
|
- from: precheck
|
|
251
253
|
to: failed
|
|
254
|
+
terminalReason: failed-check
|
|
252
255
|
description: Project checks red — do not spend a review request on code that fails its own gate
|
|
253
256
|
guard:
|
|
254
257
|
kind: always
|
|
@@ -262,6 +265,7 @@ transitions:
|
|
|
262
265
|
command: 'grep -qE "^(PUSHED|UP_TO_DATE)$" .spur/run/$__runId-pr-push.status 2>/dev/null'
|
|
263
266
|
- from: push
|
|
264
267
|
to: failed
|
|
268
|
+
terminalReason: failed-check
|
|
265
269
|
description: Push rejected (e.g. non-fast-forward) — report; never force-push as a workaround
|
|
266
270
|
guard:
|
|
267
271
|
kind: always
|
|
@@ -275,6 +279,7 @@ transitions:
|
|
|
275
279
|
command: 'grep -qE "^(FOUND|CREATED)$" .spur/run/$__runId-pr-ensure.status 2>/dev/null'
|
|
276
280
|
- from: ensure-pr
|
|
277
281
|
to: failed
|
|
282
|
+
terminalReason: failed-check
|
|
278
283
|
description: No reviewable delta or PR creation failed — report the actual git/GitHub state
|
|
279
284
|
guard:
|
|
280
285
|
kind: always
|
|
@@ -306,6 +311,7 @@ transitions:
|
|
|
306
311
|
command: 'test "$(cat .spur/run/$__runId-pr-request.status 2>/dev/null)" = REQUESTED'
|
|
307
312
|
- from: request
|
|
308
313
|
to: failed
|
|
314
|
+
terminalReason: failed-check
|
|
309
315
|
description: Request failed (no PR, gh error) — report the preserved error
|
|
310
316
|
guard:
|
|
311
317
|
kind: always
|
|
@@ -326,6 +332,7 @@ transitions:
|
|
|
326
332
|
command: 'test "$(cat .spur/run/$__runId-pr-wait.status 2>/dev/null)" = TIMEOUT'
|
|
327
333
|
- from: wait
|
|
328
334
|
to: failed
|
|
335
|
+
terminalReason: failed-check
|
|
329
336
|
description: Poll probe itself failed
|
|
330
337
|
guard:
|
|
331
338
|
kind: always
|
|
@@ -346,6 +353,7 @@ transitions:
|
|
|
346
353
|
command: 'test "$(cat .spur/run/$__runId-pr-collect.status 2>/dev/null)" = PENDING'
|
|
347
354
|
- from: collect
|
|
348
355
|
to: failed
|
|
356
|
+
terminalReason: failed-check
|
|
349
357
|
description: Collect probe failed
|
|
350
358
|
guard:
|
|
351
359
|
kind: always
|