@gobing-ai/spur 0.3.73 → 0.3.75
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/config.example.yaml +15 -4
- package/config/pipeline-budgets.json +4 -4
- package/config/rules/strict/runtime-boundaries.yaml +1 -1
- package/config/templates/AGENTS.md +5 -0
- package/config/templates/docs/99_PROJECT_CONSTITUTION.md +2 -0
- package/config/workflows/basic.yaml +5 -2
- package/config/workflows/docs-pipeline.yaml +117 -55
- package/config/workflows/feature-dev.yaml +185 -121
- package/config/workflows/feature-lifecycle.yaml +1 -0
- package/config/workflows/history-anatomy.yaml +8 -4
- package/config/workflows/idea-pipeline.yaml +123 -43
- package/config/workflows/pr-review.yaml +31 -8
- package/config/workflows/task-lifecycle.yaml +1 -0
- package/config/workflows/task-pipeline.yaml +965 -905
- package/config/workflows/wayfinder-resolution.yaml +124 -90
- package/config/workflows/wrapup-pipeline.yaml +304 -107
- package/package.json +1 -1
- package/plugins/sp/agents/expert-spur.md +7 -4
- package/plugins/sp/commands/dev-idea.md +1 -1
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/scripts/history-anatomy-cache.mjs +7 -1
- package/plugins/sp/scripts/history-anatomy-cache.ts +11 -2
- package/plugins/sp/scripts/pr-reviewing.mjs +5 -1
- package/plugins/sp/scripts/pr-reviewing.ts +7 -1
- package/plugins/sp/scripts/transition-shim-check.ts +6 -6
- package/plugins/sp/skills/pr-reviewing/SKILL.md +4 -1
- package/plugins/sp/skills/spur-cli/references/self.md +17 -3
- package/plugins/sp/skills/spur-cli/references/tasks.md +4 -2
- package/plugins/sp/skills/spur-cli/references/workflows/workflow-fit-and-tuning.md +5 -5
- package/plugins/sp/skills/spur-cli/references/workflows.md +4 -4
- package/plugins/sp/skills/spur-dev/SKILL.md +17 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +23 -8
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +3 -3
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +5 -3
- package/plugins/sp/skills/wayfinder/SKILL.md +1 -1
- package/spur.js +2999 -1010
- package/web/_astro/{BoardApp.BYCNkMOn.js → BoardApp.BOW1815F.js} +101 -100
- package/web/_astro/BoardApp.C4zimv1U.js +1 -0
- package/web/_astro/{TaskDetail.CgUreSP2.js → TaskDetail.CX6C7dSJ.js} +1 -1
- package/web/_astro/{arc.BySSh34M.js → arc.CwSvH1ji.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.DM46TS_h.js → architectureDiagram-3BPJPVTR.Dxne1RvP.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.tZhvNUHA.js → blockDiagram-GPEHLZMM.D9Fb14rC.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.PT4Or4Nf.js → c4Diagram-AAUBKEIU.DmvWSFvv.js} +1 -1
- package/web/_astro/channel.CQHdDVp9.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.J9r0_Bbe.js → chunk-2J33WTMH.BCCktIrE.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.hzyeIvhR.js → chunk-4BX2VUAB.BzCk9q27.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.B0rO7qVh.js → chunk-55IACEB6.CZXVgTk4.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.wE_Uk5D4.js → chunk-727SXJPM.CJL8UIpX.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.DqEEjQw7.js → chunk-AQP2D5EJ.Dz8MDEdw.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.CDoD9sBX.js → chunk-FMBD7UC4.CkQeYYUw.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.CtX5nF9P.js → chunk-ND2GUHAM.KiC1QgzH.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.CK_EwfaT.js → chunk-QZHKN3VN.AJ08mw2e.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.DLt5a8Lh.js → classDiagram-4FO5ZUOK.DRWRDKzK.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.DLt5a8Lh.js → classDiagram-v2-Q7XG4LA2.DRWRDKzK.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.CMCWP49h.js → cose-bilkent-S5V4N54A.CavydfLP.js} +1 -1
- package/web/_astro/{cynefin-OW5HDTMX.HyXw_vdS.js → cynefin-OW5HDTMX.D_7o_a0B.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BTuAzh01.js → dagre-BM42HDAG.LWk2dKgg.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.D9dr9wfT.js → diagram-2AECGRRQ.82lbq6aB.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.C4Rot0hj.js → diagram-5GNKFQAL.hyNL1pwY.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.B_TK5uWC.js → diagram-KO2AKTUF.BaLqVf-b.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.JkXKK7CO.js → diagram-LMA3HP47.DQJxj0oz.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.BzMN8Bd6.js → diagram-OG6HWLK6.DhlL8cG2.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DVZaWGUd.js → erDiagram-TEJ5UH35.HoTnXwkF.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.rjEiWUfR.js → flowDiagram-I6XJVG4X.DkFKlZIZ.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.C_EgAarK.js → ganttDiagram-6RSMTGT7.9qPfOTDb.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.B-QQSDsK.js → gitGraphDiagram-PVQCEYII.B4G18Dwc.js} +1 -1
- package/web/_astro/index.Dcr_8fiK.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.DlWesz7T.js → infoDiagram-5YYISTIA.e3KJkXAM.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.BUMZOawi.js → ishikawaDiagram-YF4QCWOH.CY3yddhD.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.CWfkxfjY.js → journeyDiagram-JHISSGLW.DaAKIO1t.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.B-YpMwXf.js → kanban-definition-UN3LZRKU.DGkDddtc.js} +1 -1
- package/web/_astro/{linear.D7uqzENp.js → linear.DnDPcpd1.js} +1 -1
- package/web/_astro/{mermaid.core.CxrNppBD.js → mermaid.core.1uBmxa9t.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.B4Qe7cM2.js → mindmap-definition-RKZ34NQL.XFJVayxw.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.Ds-5j2ro.js → pieDiagram-4H26LBE5.BXm2OgHh.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.tBd38uNC.js → quadrantDiagram-W4KKPZXB.DgB2p5fc.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.sFENkWl3.js → requirementDiagram-4Y6WPE33.jBR39bnS.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.BeB-Hk7C.js → sankeyDiagram-5OEKKPKP.N3u9OhE3.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.DnTeaSpx.js → sequenceDiagram-3UESZ5HK.CZhqZXNL.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.B-8Jt5EJ.js → stateDiagram-AJRCARHV.DlNu1VEa.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.Br7xoqMW.js → stateDiagram-v2-BHNVJYJU.BEqi8NQV.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.C-3WdOyi.js → timeline-definition-PNZ67QCA.BPcexclc.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.DCIs7Lc6.js → vennDiagram-CIIHVFJN.BZalxKGQ.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.rGAL-bbz.js → wardleyDiagram-YWT4CUSO.BqOljod9.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.hkfQKiRl.js → xychartDiagram-2RQKCTM6.tkO4ppN5.js} +1 -1
- package/web/index.html +2 -2
- package/config/corpus-baseline.json +0 -1805
- package/config/workflow-composition-baseline.json +0 -615
- package/web/_astro/BoardApp.E12MFjOS.js +0 -1
- package/web/_astro/channel.5cYKr5cs.js +0 -1
- package/web/_astro/index.B5MTfe7k.css +0 -1
|
@@ -46,8 +46,10 @@ CLI nouns for direct use, but they are not this corpus specialist's scope.
|
|
|
46
46
|
3. Run the noun's read/check/validate path before mutation where available.
|
|
47
47
|
4. Mutate only through `spur`; parse `--json` output when the verb advertises it.
|
|
48
48
|
5. Inspect each result before the next dependent operation; stop on structural or validation failure.
|
|
49
|
-
6. Run
|
|
50
|
-
`spur task check
|
|
49
|
+
6. Run affected-input checks after mutation (constitution T11): after task/feature batch writes,
|
|
50
|
+
run `spur task check <wbs>` / `spur feature check <id>` for each changed document and its
|
|
51
|
+
required linked evidence — not a corpus sweep. The explicit unsuppressed audit
|
|
52
|
+
(`spur task check --corpus --json`) is reserved for checker-policy changes (T10).
|
|
51
53
|
|
|
52
54
|
Workflow fit, mode selection, simplicity budgets, authoring, and tuning live in the workflow
|
|
53
55
|
references under `plugins/sp/skills/spur-cli/references/workflows/`; load them rather than copying
|
|
@@ -59,7 +61,7 @@ their runbook here.
|
|
|
59
61
|
|
|
60
62
|
- Use the source-local CLI when working in the Spur repository.
|
|
61
63
|
- Use `spur task update --section --from-file` for task section writes.
|
|
62
|
-
- Keep check-before/write/check-after evidence and the final scoped
|
|
64
|
+
- Keep check-before/write/check-after evidence and the final scoped validation result.
|
|
63
65
|
- Preserve declaration order and currently executing runs when changing workflows.
|
|
64
66
|
|
|
65
67
|
### Never
|
|
@@ -87,7 +89,8 @@ their runbook here.
|
|
|
87
89
|
### Gates
|
|
88
90
|
- pre-check: <result>
|
|
89
91
|
- post-check/validate: <result>
|
|
90
|
-
-
|
|
92
|
+
- scoped validation: <affected task/feature checks + linked evidence, or n/a; explicit T10
|
|
93
|
+
corpus audit only when checker policy changed>
|
|
91
94
|
```
|
|
92
95
|
|
|
93
96
|
## Platform Notes
|
|
@@ -46,4 +46,4 @@ vars as subsets of `--approve-taste` (`idea_approved` / `design_approved`). Pref
|
|
|
46
46
|
- `auto`/name: launch `spur workflow run idea-pipeline.yaml --async`, observe with one `workflow trace --follow`, and only report cancellation as stopped when `workflow cancel --json` returns `killed: true`.
|
|
47
47
|
- `Skill(skill="sp:spur-dev", args="idea $ARGUMENTS")`
|
|
48
48
|
- Stage contract (discovery → idea-eval → feature-create → AC → feature-check → system-design →
|
|
49
|
-
decompose → batch-create → handoff): `plugins/sp/skills/spur-dev/references/dev-operations.md` § idea.
|
|
49
|
+
decompose → batch-create → ready-prepare → handoff): `plugins/sp/skills/spur-dev/references/dev-operations.md` § idea.
|
package/plugins/sp/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.75",
|
|
4
4
|
"description": "Spur — a local-first harness engineering toolkit that wraps mainstream coding agents with constraint checking, workflow orchestration, and history analytics.",
|
|
5
5
|
"extensions": {
|
|
6
6
|
"pi": ["./hooks/pi/guard-extension.ts"]
|
|
@@ -198,6 +198,7 @@ function parseProvenance(reportMarkdown) {
|
|
|
198
198
|
contractDigest: String(obj.contractDigest ?? ""),
|
|
199
199
|
skillDigest: String(obj.skillDigest ?? ""),
|
|
200
200
|
workflowDigest: String(obj.workflowDigest ?? ""),
|
|
201
|
+
helperDigest: String(obj.helperDigest ?? ""),
|
|
201
202
|
coverage: coverage.map((c) => ({
|
|
202
203
|
source: String(c.source ?? ""),
|
|
203
204
|
status: String(c.status ?? ""),
|
|
@@ -244,6 +245,8 @@ function decideCache(cached, current, opts) {
|
|
|
244
245
|
reasons.push("logic-changed:skill");
|
|
245
246
|
if (cached.workflowDigest !== current.workflowDigest)
|
|
246
247
|
reasons.push("logic-changed:workflow");
|
|
248
|
+
if (cached.helperDigest !== current.helperDigest)
|
|
249
|
+
reasons.push("logic-changed:helper");
|
|
247
250
|
const currentSources = new Set(current.coverage.map((c) => c.source));
|
|
248
251
|
if (cached.coverage.some((c) => !currentSources.has(c.source)))
|
|
249
252
|
reasons.push("coverage-degraded");
|
|
@@ -473,6 +476,7 @@ function buildProvenance(opts) {
|
|
|
473
476
|
contractDigest: logicDigest(opts.contractFile),
|
|
474
477
|
skillDigest: logicDigest(opts.skillDir),
|
|
475
478
|
workflowDigest: logicDigest(opts.workflowFile),
|
|
479
|
+
helperDigest: logicDigest(opts.helperFile),
|
|
476
480
|
coverage,
|
|
477
481
|
runId: opts.runId,
|
|
478
482
|
currentArtifactPath: opts.artifact,
|
|
@@ -503,6 +507,7 @@ var YAML_KEYS = [
|
|
|
503
507
|
"contractDigest",
|
|
504
508
|
"skillDigest",
|
|
505
509
|
"workflowDigest",
|
|
510
|
+
"helperDigest",
|
|
506
511
|
"runId",
|
|
507
512
|
"currentArtifactPath",
|
|
508
513
|
"baselineArtifactPath",
|
|
@@ -595,7 +600,7 @@ function diffPorcelain(before, now, expects) {
|
|
|
595
600
|
return [...porcelainPaths(now)].filter((p) => !beforePaths.has(p) && !expects.has(p)).sort();
|
|
596
601
|
}
|
|
597
602
|
var VALID_COMMANDS = "digest, check, paths, assert-clean, probe, stamp, refresh, publish";
|
|
598
|
-
var PROBE_USAGE = "<script> probe --artifact <a.json> --target <report.md> [--baseline <b.json>] [--mode daily|ad-hoc] " + "[--date <YYYY-MM-DD>] [--recompute true] [--out <prov.json>] [--skill-dir <d>] [--contract <f>] [--workflow <f>]";
|
|
603
|
+
var PROBE_USAGE = "<script> probe --artifact <a.json> --target <report.md> [--baseline <b.json>] [--mode daily|ad-hoc] " + "[--date <YYYY-MM-DD>] [--recompute true] [--out <prov.json>] [--skill-dir <d>] [--contract <f>] [--workflow <f>] [--helper <f>]";
|
|
599
604
|
function parseFlags(args) {
|
|
600
605
|
const out = {};
|
|
601
606
|
for (let i = 0;i < args.length; i++) {
|
|
@@ -729,6 +734,7 @@ ${result.problems.map((p) => `- ${p}
|
|
|
729
734
|
skillDir: f["skill-dir"],
|
|
730
735
|
contractFile: f.contract,
|
|
731
736
|
workflowFile: f.workflow,
|
|
737
|
+
helperFile: f.helper,
|
|
732
738
|
contractVersion: f["contract-version"],
|
|
733
739
|
runId: f["run-id"],
|
|
734
740
|
spurVersion: f["spur-version"]
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* ADR-079 makes cache validity a *derived* fact, not a stored claim: a cached report is reusable
|
|
6
6
|
* only for its model-authored half, and only when a freshly derived semantic digest of the analyze
|
|
7
|
-
* artifact plus the contract/skill/workflow logic digests all match what the cache
|
|
7
|
+
* artifact plus the contract/skill/workflow/helper logic digests all match what the cache
|
|
8
|
+
* recorded (helper digest: task 0771 — the deterministic half is part of cache identity).
|
|
8
9
|
*
|
|
9
10
|
* This script performs deterministic file, hash, and schema work only — no finding, remediation,
|
|
10
11
|
* severity, or ranking logic (that is judgment, owned by the sp:history-anatomy skill). Jobs:
|
|
@@ -68,6 +69,8 @@ export interface CacheProvenance {
|
|
|
68
69
|
contractDigest: string;
|
|
69
70
|
skillDigest: string;
|
|
70
71
|
workflowDigest: string;
|
|
72
|
+
/** Digest of the executing helper twin itself (0771): a changed deterministic half invalidates. */
|
|
73
|
+
helperDigest: string;
|
|
71
74
|
coverage: Array<{ source: string; status: string; lastImportedAt: string | null }>;
|
|
72
75
|
// 0660 R7 audit fields. Recorded in the published frontmatter for provenance; deliberately
|
|
73
76
|
// NOT part of the invalidation matrix — a changed run id or executor is not stale evidence.
|
|
@@ -243,6 +246,7 @@ export function parseProvenance(reportMarkdown: string): CacheProvenance | null
|
|
|
243
246
|
contractDigest: String(obj.contractDigest ?? ''),
|
|
244
247
|
skillDigest: String(obj.skillDigest ?? ''),
|
|
245
248
|
workflowDigest: String(obj.workflowDigest ?? ''),
|
|
249
|
+
helperDigest: String(obj.helperDigest ?? ''),
|
|
246
250
|
coverage: coverage.map((c) => ({
|
|
247
251
|
source: String(c.source ?? ''),
|
|
248
252
|
status: String(c.status ?? ''),
|
|
@@ -300,6 +304,7 @@ export function decideCache(
|
|
|
300
304
|
if (cached.contractDigest !== current.contractDigest) reasons.push('logic-changed:contract');
|
|
301
305
|
if (cached.skillDigest !== current.skillDigest) reasons.push('logic-changed:skill');
|
|
302
306
|
if (cached.workflowDigest !== current.workflowDigest) reasons.push('logic-changed:workflow');
|
|
307
|
+
if (cached.helperDigest !== current.helperDigest) reasons.push('logic-changed:helper');
|
|
303
308
|
|
|
304
309
|
// Coverage cannot degrade: the cache must not claim broader coverage than the current
|
|
305
310
|
// analyze covers. If the cached report covered a source the current analyze no longer does,
|
|
@@ -601,6 +606,7 @@ export interface ProbeOptions {
|
|
|
601
606
|
skillDir?: string;
|
|
602
607
|
contractFile?: string;
|
|
603
608
|
workflowFile?: string;
|
|
609
|
+
helperFile?: string;
|
|
604
610
|
contractVersion?: string;
|
|
605
611
|
runId?: string;
|
|
606
612
|
spurVersion?: string;
|
|
@@ -660,6 +666,7 @@ export function buildProvenance(opts: ProbeOptions): CacheProvenance {
|
|
|
660
666
|
contractDigest: logicDigest(opts.contractFile),
|
|
661
667
|
skillDigest: logicDigest(opts.skillDir),
|
|
662
668
|
workflowDigest: logicDigest(opts.workflowFile),
|
|
669
|
+
helperDigest: logicDigest(opts.helperFile),
|
|
663
670
|
coverage,
|
|
664
671
|
runId: opts.runId,
|
|
665
672
|
currentArtifactPath: opts.artifact,
|
|
@@ -697,6 +704,7 @@ const YAML_KEYS: Array<keyof CacheProvenance> = [
|
|
|
697
704
|
'contractDigest',
|
|
698
705
|
'skillDigest',
|
|
699
706
|
'workflowDigest',
|
|
707
|
+
'helperDigest',
|
|
700
708
|
'runId',
|
|
701
709
|
'currentArtifactPath',
|
|
702
710
|
'baselineArtifactPath',
|
|
@@ -823,7 +831,7 @@ export function diffPorcelain(before: string, now: string, expects: Set<string>)
|
|
|
823
831
|
const VALID_COMMANDS = 'digest, check, paths, assert-clean, probe, stamp, refresh, publish';
|
|
824
832
|
const PROBE_USAGE =
|
|
825
833
|
'<script> probe --artifact <a.json> --target <report.md> [--baseline <b.json>] [--mode daily|ad-hoc] ' +
|
|
826
|
-
'[--date <YYYY-MM-DD>] [--recompute true] [--out <prov.json>] [--skill-dir <d>] [--contract <f>] [--workflow <f>]';
|
|
834
|
+
'[--date <YYYY-MM-DD>] [--recompute true] [--out <prov.json>] [--skill-dir <d>] [--contract <f>] [--workflow <f>] [--helper <f>]';
|
|
827
835
|
|
|
828
836
|
/** `--key value` / `--flag` → record. Bare flags become `"true"` so `--recompute` needs no value. */
|
|
829
837
|
function parseFlags(args: string[]): Record<string, string | undefined> {
|
|
@@ -956,6 +964,7 @@ export function runCacheCli(argv: string[]): CacheCliResult {
|
|
|
956
964
|
skillDir: f['skill-dir'],
|
|
957
965
|
contractFile: f.contract,
|
|
958
966
|
workflowFile: f.workflow,
|
|
967
|
+
helperFile: f.helper,
|
|
959
968
|
contractVersion: f['contract-version'],
|
|
960
969
|
runId: f['run-id'],
|
|
961
970
|
spurVersion: f['spur-version'],
|
|
@@ -325,7 +325,11 @@ function hasPendingRequest(comments, head, login) {
|
|
|
325
325
|
}
|
|
326
326
|
function requireExpectedHead(args, pr) {
|
|
327
327
|
const expected = args.flags.get("--head");
|
|
328
|
-
if (expected
|
|
328
|
+
if (!expected) {
|
|
329
|
+
writeStatus(args, "FAIL");
|
|
330
|
+
fail(args, "--head <sha> is required and must match the reviewed request HEAD", 2);
|
|
331
|
+
}
|
|
332
|
+
if (expected !== pr.headRefOid) {
|
|
329
333
|
writeStatus(args, "FAIL");
|
|
330
334
|
fail(args, `PR HEAD moved from ${expected.slice(0, 7)} to ${pr.headRefOid.slice(0, 7)} \u2014 request a new review`, 2);
|
|
331
335
|
}
|
|
@@ -519,8 +519,14 @@ function hasPendingRequest(comments: readonly GhIssueComment[], head: string, lo
|
|
|
519
519
|
}
|
|
520
520
|
|
|
521
521
|
function requireExpectedHead(args: ParsedArgs, pr: GhPr): void {
|
|
522
|
+
// 0771: head pinning only protects when the flag actually carries a SHA — an empty or
|
|
523
|
+
// missing --head must fail loud instead of silently reviewing whatever HEAD is current.
|
|
522
524
|
const expected = args.flags.get('--head');
|
|
523
|
-
if (expected
|
|
525
|
+
if (!expected) {
|
|
526
|
+
writeStatus(args, 'FAIL');
|
|
527
|
+
fail(args, '--head <sha> is required and must match the reviewed request HEAD', 2);
|
|
528
|
+
}
|
|
529
|
+
if (expected !== pr.headRefOid) {
|
|
524
530
|
writeStatus(args, 'FAIL');
|
|
525
531
|
fail(
|
|
526
532
|
args,
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
* so it is a grep target and a review signal, and a manifest entry in
|
|
9
9
|
* `config/transition-shims.json` records who owns it and when it can be removed.
|
|
10
10
|
*
|
|
11
|
-
* The gate is deliberately two-sided
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* The gate is deliberately two-sided: a marker with no manifest entry
|
|
12
|
+
* FAILS, and a manifest entry whose marker no longer appears in source
|
|
13
|
+
* FAILS. Without the second half the manifest would rot into a permanent
|
|
14
|
+
* suppression list — the exact invisible-debt pattern this gate exists to
|
|
15
|
+
* end.
|
|
16
16
|
*
|
|
17
17
|
* Marker convention (docs/04_DESIGN.md §2.5):
|
|
18
18
|
* // @transition-shim(<id>) — <one line on what this keeps working>
|
|
@@ -134,7 +134,7 @@ function scanMarkers(cwd: string, roots: string[]): Map<string, Set<string>> {
|
|
|
134
134
|
return found;
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
/** Load the manifest; a missing file degrades to no entries (
|
|
137
|
+
/** Load the manifest; a missing file degrades to no entries (fail-open). */
|
|
138
138
|
function loadManifest(path: string): { entries: ManifestEntry[]; raw: string | null } {
|
|
139
139
|
if (!existsSync(path)) return { entries: [], raw: null };
|
|
140
140
|
const raw = readFileSync(path, 'utf8');
|
|
@@ -164,12 +164,15 @@ superskill script contract.
|
|
|
164
164
|
8. **Collect** — `<script> collect --since "$requestedAt" --head "$requestHead" --json`. Normalize
|
|
165
165
|
only the requested HEAD and request window; then invoke `status` with the same bounds for
|
|
166
166
|
PR/base/CI/local state. Never turn an absent, stale, or moved-HEAD result into `clean`.
|
|
167
|
+
`--head` is mandatory on wait/collect/status (0771): an empty or missing pin fails loud
|
|
168
|
+
instead of silently reviewing whatever HEAD is current.
|
|
167
169
|
|
|
168
170
|
## Fix mode
|
|
169
171
|
|
|
170
172
|
Only in `fix` mode:
|
|
171
173
|
|
|
172
|
-
1. **Collect before editing.** Invoke direct `collect --json
|
|
174
|
+
1. **Collect before editing.** Invoke direct `collect --json --head "$(git rev-parse HEAD)"` plus
|
|
175
|
+
`status --json --head "$(git rev-parse HEAD)"` and require a
|
|
173
176
|
completed result for the current pushed HEAD. If the result is pending, stale, or unavailable,
|
|
174
177
|
report it and stop without source edits. If it is explicitly clean, report no fixes and stop.
|
|
175
178
|
2. **Validate each finding.** Open the referenced code; trace callers/callees; verify the problem
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: spur-cli-self
|
|
3
|
-
description: "spur-cli noun reference for `spur self`: self-management verbs — scaffold (`init`), schema migrations (`migrate`), local web server (`serve`), and status overview (`status`). Each verb mounts the same command builder as its legacy top-level noun, which remains a hidden alias over the identical command."
|
|
3
|
+
description: "spur-cli noun reference for `spur self`: self-management verbs — scaffold (`init`), database maintenance (`maintain`), schema migrations (`migrate`), local web server (`serve`), and status overview (`status`). Each verb mounts the same command builder as its legacy top-level noun, which remains a hidden alias over the identical command."
|
|
4
4
|
see_also:
|
|
5
5
|
- spur-cli
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# spur self - self-management verbs
|
|
9
9
|
|
|
10
|
-
`spur self` hosts the
|
|
11
|
-
that also remains registered as a legacy top-level **hidden alias** (`spur init`, `spur migrate`,
|
|
10
|
+
`spur self` hosts the self-management verbs. Each verb is the canonical path for a command
|
|
11
|
+
that also remains registered as a legacy top-level **hidden alias** (`spur init`, `spur maintain`, `spur migrate`,
|
|
12
12
|
`spur serve`, `spur status`) so existing scripts, workflow YAML, and habits keep working unchanged.
|
|
13
13
|
Both paths share the same command builder: identical flags, output, and exit codes. The legacy
|
|
14
14
|
top-level forms are omitted from `spur --help`, leaving `self` as the visible surface.
|
|
@@ -18,6 +18,7 @@ top-level forms are omitted from `spur --help`, leaving `self` as the visible su
|
|
|
18
18
|
| Verb | Purpose | Key flags |
|
|
19
19
|
| ---- | ------- | --------- |
|
|
20
20
|
| `init` | Scaffold a new Spur project in the current directory | `--name <name>` `--force` `--minimal` `--json` |
|
|
21
|
+
| `maintain` | Run database maintenance: PRAGMA optimize, WAL truncation, optional VACUUM | `--vacuum` `--json` |
|
|
21
22
|
| `migrate` | Apply CLI-owned schema migrations | `--json` |
|
|
22
23
|
| `serve` | Start the Spur web server (local fallback) | `--port <n>` `--host <addr>` `--no-open` `--cwd <path>` `--json` |
|
|
23
24
|
| `status [path]` | Show project and git status for a Spur project | `--json` |
|
|
@@ -43,6 +44,19 @@ Materializes the `.spur/` directory tree with config, docs, rules, and workflow
|
|
|
43
44
|
(Phase 1.5 / 1.6) run immediately after this verb completes — see **[init.md](init.md)** for the
|
|
44
45
|
probe protocol and rule-glob adaptation procedure.
|
|
45
46
|
|
|
47
|
+
## `self maintain` - run database maintenance
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
spur self maintain # run PRAGMA optimize + wal_checkpoint(TRUNCATE)
|
|
51
|
+
spur self maintain --vacuum # deep maintenance: VACUUM + optimize + checkpoint
|
|
52
|
+
spur self maintain --json # machine-readable
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Executes SQLite database maintenance operations on `.spur/spur.db`:
|
|
56
|
+
- `PRAGMA optimize;` to refresh query planner statistics in `sqlite_stat1`.
|
|
57
|
+
- `PRAGMA wal_checkpoint(TRUNCATE);` to checkpoint committed WAL frames and truncate WAL to 0 bytes.
|
|
58
|
+
- `--vacuum` runs `VACUUM;` first for page compaction and B-tree defragmentation (requires 2x free disk space).
|
|
59
|
+
|
|
46
60
|
## `self migrate` - apply CLI-owned schema migrations
|
|
47
61
|
|
|
48
62
|
```bash
|
|
@@ -51,7 +51,7 @@ re-reading or re-tokenizing the task.
|
|
|
51
51
|
| `batch-create` | Create many tasks from a validated JSON array | `--file <path>` `--folder` `--json` |
|
|
52
52
|
| `record <wbs>` | Write `Testing` from a verify verdict (deterministic); bare-`## Review` fallback only; optional Solution + transition | `--verdict-file <path>` `--solution-from-diff` `--transition <status>` `--folder` `--json` |
|
|
53
53
|
| `verdict <wbs>` | Derive PASS/PARTIAL/FAIL/UNKNOWN from verify answer text → verdict JSON; see [answer-file shape](tasks/verbs.md#answer-file-shape-what---from-answer-parses) | `--from-answer <path>` `--folder` `--json` |
|
|
54
|
-
| `check [wbs]` | Four-layer validation;
|
|
54
|
+
| `check [wbs]` | Four-layer validation; `--fix` repairs structure; `--corpus` is the explicit unsuppressed audit | `--strict` `--as <status>` `--strict-core` `--fix` `--folder` `--corpus` `--since <ref>` `--json` |
|
|
55
55
|
| `resolve <file-path>` | Map a file path to its owning task WBS | `--strict` `--folder` `--json` |
|
|
56
56
|
| `path <wbs>` | Map a WBS to its absolute task file path (inverse of `resolve`) | `--folder` `--json` |
|
|
57
57
|
| `run-link <wbs>` | Record pipeline run provenance link for task | `--source <src>` `--run-id <id>` `--json` |
|
|
@@ -187,7 +187,9 @@ spur task record 0040 --verdict-file .spur/run/0040-verdict.json --solution-from
|
|
|
187
187
|
- **`--solution-from-diff`** backfills `Solution` from `git diff -U0` hunk headers **only when the
|
|
188
188
|
Solution section is still bare** — a safety net, not an overwrite.
|
|
189
189
|
- **`--transition <status>`** optionally advances the lifecycle after writing (e.g. `testing`).
|
|
190
|
-
`
|
|
190
|
+
`--transition done` is a **guarded** completion path: it requires a PASS verdict, auto-walks
|
|
191
|
+
`wip → testing → done`, and auto-creates the pipeline run-link (0436 R4); a non-PASS verdict to
|
|
192
|
+
`done` errors instead of transitioning, and the normal done gates still apply (0108).
|
|
191
193
|
|
|
192
194
|
The verdict shape (`wbs`, `verdict`, `requirements[]`, `checks[]`) and the rendered tables are
|
|
193
195
|
documented in [tasks/verbs.md](tasks/verbs.md).
|
|
@@ -140,10 +140,10 @@ reports it. Do not invent a second threshold; author to the one that is frozen (
|
|
|
140
140
|
| Node count | Every node earns its transition round-trip | A node that always runs immediately after another, with no guard between them, is one node |
|
|
141
141
|
|
|
142
142
|
**When a node breaches the budget, do not reformat to dodge the measure.** Joining five lines with
|
|
143
|
-
`&&` moves the complexity, not the ownership. Pick
|
|
143
|
+
`&&` moves the complexity, not the ownership. Pick one of the four remaining owners from
|
|
144
144
|
`docs/design/workflow-shell-ownership.md`: public `spur` verb (consent-gated), application service,
|
|
145
|
-
least-privilege built-in action kind, workflow-relative external extension
|
|
146
|
-
stays-shell exception with
|
|
145
|
+
least-privilege built-in action kind, or workflow-relative external extension. (0775 retired the
|
|
146
|
+
recorded stays-shell exception along with the suppression snapshot.)
|
|
147
147
|
|
|
148
148
|
**Advisory posture is binding.** Composition findings never block a run, never change a `validate`
|
|
149
149
|
exit status, and are never a reason to hot-edit an executing pipeline. Surface them; fix on operator
|
|
@@ -193,8 +193,8 @@ Steps:
|
|
|
193
193
|
2. **Return each node's work to its owner** — judgment nodes to the command or skill they should
|
|
194
194
|
have been calling; a genuinely useful shell sequence to one script under its owning surface.
|
|
195
195
|
3. **Rewrite the entry surface as the procedure**, in the order the graph ran.
|
|
196
|
-
4. **Delete the YAML
|
|
197
|
-
|
|
196
|
+
4. **Delete the YAML** in the same change. (0775 retired the composition-baseline entries that
|
|
197
|
+
used to be deleted alongside it; the live definition is the only artifact left.)
|
|
198
198
|
5. **Record the demotion** and its trigger, so the next author does not re-promote it by reflex.
|
|
199
199
|
|
|
200
200
|
### optimize — refine an accepted workflow in place
|
|
@@ -231,10 +231,10 @@ agent prompts where a first-class surface would own it better?" — nothing more
|
|
|
231
231
|
raw prompt length only sets the reported severity (<200 low / ≤1000 medium / >1000 high).
|
|
232
232
|
|
|
233
233
|
**How to run it:** it is not a separate command — `spur workflow validate <file> --json` returns
|
|
234
|
-
`composition: {findings[]
|
|
235
|
-
with exit 0.
|
|
236
|
-
`
|
|
237
|
-
|
|
234
|
+
`composition: {findings[]}` on the valid path; human mode prints the advisory to stderr
|
|
235
|
+
with exit 0. Findings are derived from the workflow definition itself
|
|
236
|
+
(`extractResolvedWorkflowFacts`, guarded by `composition-baseline.test.ts`); 0775 retired the
|
|
237
|
+
suppression snapshot, so every finding is reported — none are suppressed.
|
|
238
238
|
|
|
239
239
|
**How to read it, and the fix path per defect class:**
|
|
240
240
|
|
|
@@ -153,6 +153,23 @@ CLI does.
|
|
|
153
153
|
|
|
154
154
|
## Gotchas
|
|
155
155
|
|
|
156
|
+
### Bounded execution and recovery (0777)
|
|
157
|
+
|
|
158
|
+
- During planning/refinement of corpus-scale work, record an execution budget, persisted-artifact
|
|
159
|
+
paths and requireDiff guidance in the task Design. For classification-only work, declare
|
|
160
|
+
`mutationPolicy: none`; its task/evidence change is the deliverable, not invented source edits.
|
|
161
|
+
Preserve partial artifacts at the budget boundary; resume only against the current task contract.
|
|
162
|
+
- Before accepting a child/watcher result, compare its run ID with the dispatched run ID and check
|
|
163
|
+
current trace state through Spur. If using a run log as evidence, require its mtime to be at least
|
|
164
|
+
the dispatch time. A mismatch or stale timestamp is not completion evidence. Do not scrape terminals.
|
|
165
|
+
Bound each watch invocation to 10 minutes or 20 polls, whichever comes first; persist the last
|
|
166
|
+
confirmed identity/state and report a checkpoint before continuing. A watcher timeout does not
|
|
167
|
+
cancel the owned run or authorize launching a replacement.
|
|
168
|
+
- Mark superseded scratch with `SUPERSEDED` and a pointer to the authoritative task Design. Never
|
|
169
|
+
let a scratch instruction override the live task, even when its old run is still readable.
|
|
170
|
+
- Checker-policy changes require one explicit unsuppressed audit (T10); ordinary corpus commit
|
|
171
|
+
prep checks affected documents and linked evidence (T11), not the corpus. No acceptance snapshots.
|
|
172
|
+
|
|
156
173
|
1. **Never skip a gate.** A clean `feature check` is the only proof the AC is valid; a
|
|
157
174
|
passing `batch-create` is the only proof the decomposition is well-formed. Skip either and
|
|
158
175
|
you ship corrupted corpus.
|
|
@@ -652,21 +652,35 @@ Field semantics (enforced by `parseCheckpointMetadata` / `checkpointStaleness`):
|
|
|
652
652
|
up once retention expires.
|
|
653
653
|
- `source_commit` pins repository HEAD at write time; drift staleness is reported, not hidden.
|
|
654
654
|
- `artifacts` lists referenced run files; a missing artifact makes the checkpoint stale.
|
|
655
|
-
|
|
656
|
-
|
|
655
|
+
|
|
656
|
+
**Writer cadence (0784 R4).** There is exactly one canonical writer: the `task-pipeline` done
|
|
657
|
+
state's terminal checkpoint (`status: done`, real HEAD, run id from `$__runId`, and `$wbs`-expanded
|
|
658
|
+
artifact paths). It is a plain `shell` step — checkpoints are working memory, not CLI-gated corpus.
|
|
659
|
+
The `feature-dev`, `wrapup-pipeline`, and `idea-pipeline` pipelines used to echo pseudo-checkpoints
|
|
660
|
+
("checkpoint: <workflow> done ...") that violated the canonical schema; those writers were removed
|
|
661
|
+
in 0784 — the persisted run row is the authoritative terminal record, and a non-canonical echo
|
|
662
|
+
cannot be resumed, routed, or reclaimed safely.
|
|
663
|
+
|
|
664
|
+
**Engine state vs checkpoint status (0784 R3).** The persisted run row's status is authoritative;
|
|
665
|
+
a checkpoint's `status` is an advisory projection written by consumers. On resume
|
|
666
|
+
(`workflow continue`), a checkpoint associated with the paused run must project a nonterminal
|
|
667
|
+
engine state — `pending`, `running`, or `approved` are accepted; `done`/`failed`/`cancelled`/
|
|
668
|
+
`skipped`, a missing status, or any unknown value refuse the resume with a named reason. The
|
|
669
|
+
engine owns no persisted `paused` checkpoint status.
|
|
657
670
|
|
|
658
671
|
**Write checkpoints after:**
|
|
659
672
|
|
|
660
|
-
-
|
|
661
|
-
-
|
|
662
|
-
|
|
663
|
-
- Every terminal state (`done`, `failed`, `cancelled`, `skipped`).
|
|
673
|
+
- Terminal task completion in `task-pipeline` (the canonical writer above).
|
|
674
|
+
- Any additional consumer-specific checkpoints you genuinely need for local resume; keep the
|
|
675
|
+
canonical schema — non-canonical files are ignored by routing and cleanup.
|
|
664
676
|
|
|
665
677
|
**Read checkpoints when:**
|
|
666
678
|
|
|
667
679
|
- `/sp:dev-run --continue` or `/sp:dev-runall --continue` is used.
|
|
668
680
|
- The operator asks to resume a task or feature.
|
|
669
|
-
- A workflow run is paused and later continued (`spur workflow continue <run-id>`).
|
|
681
|
+
- A workflow run is paused and later continued (`spur workflow continue <run-id>`). Resume
|
|
682
|
+
validates freshness in the run's recorded launch workdir (0784 R1/R3): artifacts resolve relative
|
|
683
|
+
to that workdir, and git HEAD is probed there — never in the ambient process cwd.
|
|
670
684
|
|
|
671
685
|
**Rules:**
|
|
672
686
|
|
|
@@ -678,7 +692,8 @@ Field semantics (enforced by `parseCheckpointMetadata` / `checkpointStaleness`):
|
|
|
678
692
|
- **Retention.** Terminal checkpoints older than `workflowLogRetentionDays` with no active run are
|
|
679
693
|
reclaimed by `spur workflow clean` (task 0711 R5–R8); non-terminal checkpoints are always kept.
|
|
680
694
|
- **Not a validated corpus.** Checkpoints are working memory. They are overwritten when a session
|
|
681
|
-
resumes and re-checkpoints. They are NOT authoritative task state — the task file
|
|
695
|
+
resumes and re-checkpoints. They are NOT authoritative task state — the task file and the
|
|
696
|
+
persisted run row are.
|
|
682
697
|
- **One file per session.** The `session_id` is `<date>-<wbs-or-feature>`. A resumed session
|
|
683
698
|
overwrites the same file.
|
|
684
699
|
- **Operator-readable.** The YAML frontmatter is machine-parseable; the body is free-form markdown
|
|
@@ -341,7 +341,7 @@ must not be changed without updating the backing skill.
|
|
|
341
341
|
- `--approve-taste` — with `--auto`, skip **all** remaining taste pauses this run (idea-eval + design-approval). Sets `idea_approved=true` and `design_approved=true`.
|
|
342
342
|
Aliases (prefer `--approve-taste`): `--idea-approved` → `idea_approved`; `--design-approved` → `design_approved`. There is **no** `--design` force flag.
|
|
343
343
|
- **Backing:** `idea-pipeline.yaml` through the inline driver for omitted/`inline`, or `spur workflow run idea-pipeline.yaml --async` for `auto`/name.
|
|
344
|
-
- **Behavior:** Builds vars from the table above and drives the idea pipeline. Flow: discovery → **idea-eval** (taste; reject → cancelled) → feature-create → ac-generate → feature-check → system-design (conditional) → design-approval (taste) → decompose → batch-create → handoff. STOPS at handoff — no task execution, no pipeline nesting. Headless runs use one `trace --follow`; cancellation is reported stopped only when `workflow cancel --json` returns `killed: true`.
|
|
344
|
+
- **Behavior:** Builds vars from the table above and drives the idea pipeline. Flow: discovery → **idea-eval** (taste; reject → cancelled) → feature-create → ac-generate → feature-check → system-design (conditional) → design-approval (taste) → decompose → batch-create (`--skip-ready`) → ready-prepare (ready checklist per created task + ready-evidence sidecar, 0788) → handoff. STOPS at handoff — no task execution, no pipeline nesting. Headless runs use one `trace --follow`; cancellation is reported stopped only when `workflow cancel --json` returns `killed: true`.
|
|
345
345
|
- **Delegation:** Host-session inline driver by default; explicit executor selection uses the async workflow worker.
|
|
346
346
|
- **Idea-evaluation gate:** After discovery, operator reviews `.spur/run/idea-eval-report.md` ([idea-evaluation.md](idea-evaluation.md)). Approve continues; reject/cancel → no feature. Under `--auto`, still pauses unless taste pre-cleared (`--approve-taste` / alias). Enhanced idea is a sidecar — `vars.idea` is not overwritten.
|
|
347
347
|
- **Design package (`--skip-design` only):**
|
|
@@ -887,9 +887,9 @@ time. Before launching a full `spur-check-new`:
|
|
|
887
887
|
`console.*`), spawn processes via `NodeProcessExecutor` (no `Bun.spawnSync`), get a
|
|
888
888
|
`runtime-boundaries` fs-io exemption for sync reads (mirrors `task.ts`), and a non-command helper
|
|
889
889
|
must not live in `apps/cli/src/commands/` (the noun scan treats every file there as a noun).
|
|
890
|
-
3. **Doc/TSDoc edits shift `file:line` anchors** cited by other tasks —
|
|
891
|
-
as `L4.anchor-subject-mismatch
|
|
892
|
-
|
|
890
|
+
3. **Doc/TSDoc edits shift `file:line` anchors** cited by other tasks — the per-task gate surfaces
|
|
891
|
+
them as `L4.anchor-subject-mismatch` (0775: the corpus sweep retired; run `spur task check <wbs>`
|
|
892
|
+
on touched tasks). Repoint the shifted citations (via `spur task update --section`)
|
|
893
893
|
|
|
894
894
|
## AC traceability
|
|
895
895
|
|
|
@@ -149,7 +149,10 @@ passed, so provenance denied first and Review L3 denied on the retry.
|
|
|
149
149
|
|
|
150
150
|
| # | Gate layer | Triggers denial when | Remediation |
|
|
151
151
|
|---|------------|----------------------|-------------|
|
|
152
|
-
| 1 | **Strict-core + verdict artifact** (`spur task check <wbs> --strict-core` + `done-transition-guard.ts`) | The strict-core check fails, or `.spur/run/<wbs>-verdict.json` is **missing** or has a non-PASS aggregate. **Missing artifact is a deny** (not a silent allow — closes the 0349 "done without verdict" class). The aggregate is recomputed from requirement/AC rows; the harsher of stored and computed wins. | Re-run `/sp:dev-verify <wbs>` until PASS (writes the artifact), or explicitly override with `spur task update <wbs> done --force-done --reason "<why>"`. Docs-only pipelines
|
|
152
|
+
| 1 | **Strict-core + verdict artifact** (`spur task check <wbs> --strict-core` + `done-transition-guard.ts`) | The strict-core check fails, or `.spur/run/<wbs>-verdict.json` is **missing** or has a non-PASS aggregate. **Missing artifact is a deny** (not a silent allow — closes the 0349 "done without verdict" class). The aggregate is recomputed from requirement/AC rows; the harsher of stored and computed wins. | Re-run `/sp:dev-verify <wbs>` until PASS (writes the artifact), or explicitly override with `spur task update <wbs> done --force-done --reason "<why>"`. Docs-only pipelines (`docs-pipeline.yaml`) meet the same layer: read-only measured verification
|
|
153
|
+
(answer file + `spur task verdict`) writes the standard `.spur/run/<wbs>-verdict.json` artifact
|
|
154
|
+
under proof-input digest bracketing; missing or non-PASS evidence is a refusal, never a synthetic
|
|
155
|
+
PASS stub. |
|
|
153
156
|
| 2 | **Provenance guard** (`lifecycle-adapter.ts`) | No pipeline-kind run link exists for `<wbs>`. | Run `/sp:dev-run <wbs>` through the full pipeline, use `/sp:dev-run <wbs> --mode implement --auto --next` for the explicit step chain, or record the audited bypass with `SPUR_PROVENANCE_OVERRIDE=1`. |
|
|
154
157
|
| 3 | **Review L3** (`task-check.ts`) | `### Review` is empty, placeholder-only, or lacks a populated P1–P4 findings table. | Run `/sp:dev-review <wbs>`; verify cannot write Review because of the Step 10 prohibition above. |
|
|
155
158
|
|
|
@@ -170,7 +173,7 @@ transition to `done`.
|
|
|
170
173
|
> The verify skill writes this shape automatically — operators only need it when hand-authoring
|
|
171
174
|
> an answer file or debugging an UNKNOWN verdict.
|
|
172
175
|
|
|
173
|
-
> **
|
|
176
|
+
> **Finding-rule discipline (ADR-108).** When checker policy changes, run focused tests and one explicit unsuppressed `bun run corpus-check` audit; record/reconcile essential failures without waivers (T10). Ordinary corpus commit prep checks changed tasks/features and their required linked evidence, not the corpus (T11). The baseline and regenerators remain deleted; tests are not a substitute for the explicit policy-change audit.
|
|
174
177
|
>
|
|
175
178
|
> **Transition-shim discipline (`transition-shim-check`, task 0541 / ADR-058).** Wired as an early step of `spur-check` / `spur-check-new` (second, after `link-check` and before `lint`) so a shim violation fails in ~0.3 s rather than after the test run. Two-sided against `config/transition-shims.json`: an `@transition-shim(<id>)` marker with no manifest entry fails as a **new unregistered shim**, **and** a listed entry whose marker is gone from source fails as a **stale entry**. Emptying the manifest is the definition of the agent-role transition being complete. A removal condition must be objectively checkable against the repository. Shapes: `docs/04_DESIGN.md` §2.5.
|
|
176
179
|
|
|
@@ -188,4 +191,3 @@ transition to `done`.
|
|
|
188
191
|
> failure is not yours. This costs seconds and mutates nothing — do **not** `git stash` to get a
|
|
189
192
|
> clean baseline on a shared working tree. Treat any failure that does *not* name a port/listen/`ps`
|
|
190
193
|
> cause as yours until proven otherwise; the count is a moving baseline, not a constant.
|
|
191
|
-
|
|
@@ -147,7 +147,7 @@ Invoked when a map already exists (operator provides the feature ID). A ticket i
|
|
|
147
147
|
— no task is claimed, and it does not consume the session's one ticket.
|
|
148
148
|
|
|
149
149
|
5. **Record the resolution.** Post the answer in the task body, then `spur task update <wbs> done`. Append one line to the map's **## Decisions so far**: `- [<WBS> <title>](path) — <one-line gist of the answer>`.
|
|
150
|
-
6. **Graduate fog into new tickets.** Any fog the answer has made specifiable becomes fresh child tasks (create-then-wire). Clear each graduated patch from **### Not yet specified** so it lives only as its new ticket. Doing half of this — deleting the fog without creating the ticket — destroys the only record the work was ever identified
|
|
150
|
+
6. **Graduate fog into new tickets.** Any fog the answer has made specifiable becomes fresh child tasks (create-then-wire). Clear each graduated patch from **### Not yet specified** so it lives only as its new ticket. Doing half of this — deleting the fog without creating the ticket — destroys the only record the work was ever identified; the `corpus.ungraduated-fog` sweep retired in 0775 — enforcement is review-time discipline.
|
|
151
151
|
7. **Rule out mis-scoped tickets.** If the answer reveals a ticket sits beyond the destination, close it and add one line to **### Out of scope** (the gist + why it's out of scope, linking the closed ticket). A scope boundary is not a step on the route — it stays out of **## Decisions so far**.
|
|
152
152
|
8. **Stop after ONE ticket.** Never resolve more than one per session.
|
|
153
153
|
|