@gobing-ai/spur 0.3.60 → 0.3.62
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 +2 -2
- package/config/config.global.yaml +68 -57
- package/config/corpus-baseline.json +505 -57
- package/config/plugin-scripts.json +2 -2
- package/config/rules/boundary/config-loading-ownership.yaml +21 -0
- package/config/workflow-composition-baseline.json +1 -1
- package/config/workflows/history-anatomy.yaml +366 -0
- package/config/workflows/wayfinder-resolution.yaml +4 -6
- package/package.json +1 -1
- package/plugins/README.md +5 -4
- package/plugins/sp/README.md +22 -9
- package/plugins/sp/agents/super-planner.md +1 -1
- package/plugins/sp/commands/dev-find-issue.md +25 -46
- package/plugins/sp/commands/dev-pr-review.md +1 -1
- package/plugins/sp/commands/dev-run.md +22 -3
- package/plugins/sp/commands/dev-wrap.md +2 -2
- package/plugins/sp/commands/dev-wrapall.md +2 -2
- package/plugins/sp/lib/artifact-digest.generated.d.mts +7 -0
- package/plugins/sp/lib/artifact-digest.generated.mjs +48 -0
- package/plugins/sp/plugin.json +1 -1
- package/plugins/sp/references/roles.md +17 -14
- package/plugins/sp/scripts/history-anatomy-cache.mjs +669 -0
- package/plugins/sp/scripts/history-anatomy-cache.ts +818 -0
- package/plugins/sp/scripts/surface-drift-inventory.ts +51 -17
- package/plugins/sp/scripts/validate-commands.ts +11 -4
- package/plugins/sp/skills/code-verification/SKILL.md +1 -1
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +1 -1
- package/plugins/sp/skills/history-anatomy/SKILL.md +67 -0
- package/plugins/sp/skills/history-anatomy/references/modes.md +82 -0
- package/plugins/sp/skills/history-anatomy/references/operations.md +67 -0
- package/plugins/sp/skills/history-anatomy/references/report-contract.md +133 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +1 -1
- package/plugins/sp/skills/next-router/references/routing-table.md +1 -1
- package/plugins/sp/skills/pr-reviewing/SKILL.md +2 -2
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +1 -1
- package/plugins/sp/skills/spur-cli/references/init.md +1 -1
- package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +1 -1
- package/plugins/sp/skills/spur-cli/references/workflows.md +4 -4
- package/plugins/sp/skills/spur-dev/SKILL.md +4 -4
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +4 -4
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +11 -11
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +1 -1
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +17 -4
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +8 -1
- package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +3 -2
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +25 -13
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +1 -1
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +5 -2
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +2 -2
- package/schemas/spur-config.schema.json +1 -1
- package/spur.js +1278 -890
- package/web/_astro/BoardApp.Z9jMwI9G.js +1 -0
- package/web/_astro/BoardApp.rkWGVwwK.js +178 -0
- package/web/_astro/{TaskDetail.B0l1uzsB.js → TaskDetail.B7ODt_bA.js} +1 -1
- package/web/_astro/{arc.DPruHC3P.js → arc.C5QRz6AQ.js} +1 -1
- package/web/_astro/{architectureDiagram-3BPJPVTR.CuOqAck6.js → architectureDiagram-3BPJPVTR.CHptn8gZ.js} +1 -1
- package/web/_astro/{blockDiagram-GPEHLZMM.Cxb7HDIA.js → blockDiagram-GPEHLZMM.b1nEDkDw.js} +1 -1
- package/web/_astro/{c4Diagram-AAUBKEIU.Dw7wa-0S.js → c4Diagram-AAUBKEIU.BWj8S_Qq.js} +1 -1
- package/web/_astro/channel.BJtn6CGV.js +1 -0
- package/web/_astro/{chunk-2J33WTMH.MECQitzo.js → chunk-2J33WTMH.q0BBuE1n.js} +1 -1
- package/web/_astro/{chunk-4BX2VUAB.p3ofhIGE.js → chunk-4BX2VUAB.DP2KDkAU.js} +1 -1
- package/web/_astro/{chunk-55IACEB6.BmQGsPZP.js → chunk-55IACEB6.CkCId72p.js} +1 -1
- package/web/_astro/{chunk-727SXJPM.CwrK23OA.js → chunk-727SXJPM.oHWzxMot.js} +1 -1
- package/web/_astro/{chunk-AQP2D5EJ.CUKI_QXp.js → chunk-AQP2D5EJ.DkkgxfMP.js} +1 -1
- package/web/_astro/{chunk-FMBD7UC4.7AtDgShM.js → chunk-FMBD7UC4.lmFJDvRK.js} +1 -1
- package/web/_astro/{chunk-ND2GUHAM.f_YJbTs3.js → chunk-ND2GUHAM.52jt0eHK.js} +1 -1
- package/web/_astro/{chunk-QZHKN3VN.0q7V3gEg.js → chunk-QZHKN3VN.Cg8KEFoD.js} +1 -1
- package/web/_astro/{classDiagram-4FO5ZUOK.C_hG3HMK.js → classDiagram-4FO5ZUOK.BuOUhxcD.js} +1 -1
- package/web/_astro/{classDiagram-v2-Q7XG4LA2.C_hG3HMK.js → classDiagram-v2-Q7XG4LA2.BuOUhxcD.js} +1 -1
- package/web/_astro/{cose-bilkent-S5V4N54A.vsaaaEMy.js → cose-bilkent-S5V4N54A.BRUU8E_0.js} +1 -1
- package/web/_astro/{dagre-BM42HDAG.BN7XFqQ4.js → dagre-BM42HDAG.GDbfFYVV.js} +1 -1
- package/web/_astro/{diagram-2AECGRRQ.ED6AfryZ.js → diagram-2AECGRRQ.CvIDBeJF.js} +1 -1
- package/web/_astro/{diagram-5GNKFQAL.Dxllzg8R.js → diagram-5GNKFQAL.DMgJjWOX.js} +1 -1
- package/web/_astro/{diagram-KO2AKTUF.RuWppieD.js → diagram-KO2AKTUF.njjl-0AP.js} +1 -1
- package/web/_astro/{diagram-LMA3HP47.CL32Xn6s.js → diagram-LMA3HP47.CcCqgP8M.js} +1 -1
- package/web/_astro/{diagram-OG6HWLK6.CUneEhqB.js → diagram-OG6HWLK6.Btqd-YVE.js} +1 -1
- package/web/_astro/{erDiagram-TEJ5UH35.DI-92Lec.js → erDiagram-TEJ5UH35.BbhML_Xo.js} +1 -1
- package/web/_astro/{flowDiagram-I6XJVG4X.69Aqa1FF.js → flowDiagram-I6XJVG4X.CkvsIgY8.js} +1 -1
- package/web/_astro/{ganttDiagram-6RSMTGT7.DdpClZpa.js → ganttDiagram-6RSMTGT7.m8IWD_wW.js} +1 -1
- package/web/_astro/{gitGraphDiagram-PVQCEYII.xqWfkvB4.js → gitGraphDiagram-PVQCEYII.5z87HXO-.js} +1 -1
- package/web/_astro/index.nWve6EHS.css +1 -0
- package/web/_astro/{infoDiagram-5YYISTIA.B3G5sfKm.js → infoDiagram-5YYISTIA.Bvyvsd7Q.js} +1 -1
- package/web/_astro/{ishikawaDiagram-YF4QCWOH.ahVNsoAQ.js → ishikawaDiagram-YF4QCWOH.DdWVYO87.js} +1 -1
- package/web/_astro/{journeyDiagram-JHISSGLW.PmFHLc-X.js → journeyDiagram-JHISSGLW.C3kOlYH1.js} +1 -1
- package/web/_astro/{kanban-definition-UN3LZRKU.Co1qOPTd.js → kanban-definition-UN3LZRKU.CfKTUHVC.js} +1 -1
- package/web/_astro/{linear.DoHZ-iRt.js → linear.CMDHnzgX.js} +1 -1
- package/web/_astro/{mermaid.core.DNRElYN2.js → mermaid.core.DN7-WrsP.js} +4 -4
- package/web/_astro/{mindmap-definition-RKZ34NQL.CdfJZidJ.js → mindmap-definition-RKZ34NQL.DcQxLvqG.js} +1 -1
- package/web/_astro/{pieDiagram-4H26LBE5.C1A8dby4.js → pieDiagram-4H26LBE5.Nu-Inbw6.js} +1 -1
- package/web/_astro/{quadrantDiagram-W4KKPZXB.NmZqjG_c.js → quadrantDiagram-W4KKPZXB.Dck2EChs.js} +1 -1
- package/web/_astro/{requirementDiagram-4Y6WPE33.tY36zYtK.js → requirementDiagram-4Y6WPE33.C--E5XuW.js} +1 -1
- package/web/_astro/{sankeyDiagram-5OEKKPKP.rOEGZYjo.js → sankeyDiagram-5OEKKPKP.B_0iRNna.js} +1 -1
- package/web/_astro/{sequenceDiagram-3UESZ5HK.Dpnw3S9J.js → sequenceDiagram-3UESZ5HK.PKuKr9mk.js} +1 -1
- package/web/_astro/{stateDiagram-AJRCARHV.DGpvQ3Wz.js → stateDiagram-AJRCARHV.ClhGHb-O.js} +1 -1
- package/web/_astro/{stateDiagram-v2-BHNVJYJU.CbwQdEfu.js → stateDiagram-v2-BHNVJYJU.Bv6BBnvg.js} +1 -1
- package/web/_astro/{timeline-definition-PNZ67QCA.DAYUpUJT.js → timeline-definition-PNZ67QCA.BZm2ZvAH.js} +1 -1
- package/web/_astro/{vennDiagram-CIIHVFJN.C7JCCd6-.js → vennDiagram-CIIHVFJN.Dt6yZXry.js} +1 -1
- package/web/_astro/{wardley-L42UT6IY.BGgwOH5_.js → wardley-L42UT6IY.rUs-E00M.js} +1 -1
- package/web/_astro/{wardleyDiagram-YWT4CUSO.oIZqzI2l.js → wardleyDiagram-YWT4CUSO.BcWgv4cA.js} +1 -1
- package/web/_astro/{xychartDiagram-2RQKCTM6.DohcJzqm.js → xychartDiagram-2RQKCTM6.DH-M-cX9.js} +1 -1
- package/web/index.html +2 -2
- package/plugins/sp/commands/dev-history-load.md +0 -63
- package/plugins/sp/scripts/history-load.mjs +0 -268
- package/plugins/sp/scripts/history-load.ts +0 -400
- package/web/_astro/BoardApp.BJs3l7O8.js +0 -179
- package/web/_astro/BoardApp.D8InuCYx.js +0 -1
- package/web/_astro/channel.XCf1DcsL.js +0 -1
- package/web/_astro/index.DJl2RAVZ.css +0 -1
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
/**
|
|
3
3
|
* surface-drift-inventory — re-runnable drift inventory for `plugins/sp` and
|
|
4
|
-
* the tracked workflow-YAML SSOT tree
|
|
5
|
-
*
|
|
6
|
-
* (feature I3, task 0539 R1/R2).
|
|
4
|
+
* the tracked workflow-YAML SSOT tree against the live
|
|
5
|
+
* source-local `spur` CLI (feature I3, task 0539 R1/R2).
|
|
7
6
|
*
|
|
8
7
|
* Method (mechanical first, prose second — task 0539 Design):
|
|
9
8
|
* A. Plugin assertions: extract every `spur`-invocation (backticked spans, fenced
|
|
@@ -19,7 +18,7 @@
|
|
|
19
18
|
* in this repo — recorded unverified.
|
|
20
19
|
* D. Workflows: `spur workflow validate` (live engine, schema + semantic) and a
|
|
21
20
|
* `--dry-run` transition walk for all ten definitions; `.spur/workflows`
|
|
22
|
-
* symlink
|
|
21
|
+
* symlink is asserted absent (two-tier project→bundled model, task 0650).
|
|
23
22
|
*
|
|
24
23
|
* Output: markdown inventory on stdout-path via `--out`; exit 1 when any
|
|
25
24
|
* CONFIRMED mismatch remains (ok after repair); unverified entries never fail.
|
|
@@ -35,7 +34,6 @@ import {
|
|
|
35
34
|
mkdtempSync,
|
|
36
35
|
readdirSync,
|
|
37
36
|
readFileSync,
|
|
38
|
-
realpathSync,
|
|
39
37
|
rmSync,
|
|
40
38
|
writeFileSync,
|
|
41
39
|
} from 'node:fs';
|
|
@@ -130,6 +128,7 @@ interface Parsed {
|
|
|
130
128
|
}
|
|
131
129
|
|
|
132
130
|
const PLACEHOLDER = /^([<[{($#"'`]|…|\.\.\.)/;
|
|
131
|
+
const LEGACY_SELF_ALIASES = new Set(['init', 'migrate', 'serve', 'status']);
|
|
133
132
|
|
|
134
133
|
/** Normalize an asserted invocation span into nouns / verbs / flags. Null when it asserts nothing. */
|
|
135
134
|
export function parseInvocation(spanRaw: string): Parsed | null {
|
|
@@ -259,6 +258,32 @@ export function checkNounVerbFlags(
|
|
|
259
258
|
const root = surface([]);
|
|
260
259
|
for (const noun of nouns) {
|
|
261
260
|
if (noun === 'help' || /^(foo|bar|baz)$/.test(noun)) continue;
|
|
261
|
+
if (LEGACY_SELF_ALIASES.has(noun)) {
|
|
262
|
+
const self = surface(['self']);
|
|
263
|
+
const command = surface(['self', noun]);
|
|
264
|
+
const present = self.commands.includes(noun);
|
|
265
|
+
record(
|
|
266
|
+
`spur ${noun}`,
|
|
267
|
+
'help-capture(spur self; hidden root alias)',
|
|
268
|
+
present ? 'ok' : 'mismatch',
|
|
269
|
+
present
|
|
270
|
+
? `legacy alias; canonical self/${noun} command is present`
|
|
271
|
+
: `canonical self/${noun} command is absent`,
|
|
272
|
+
occ,
|
|
273
|
+
);
|
|
274
|
+
for (const f of flags) {
|
|
275
|
+
record(
|
|
276
|
+
`spur ${noun} ${f}`,
|
|
277
|
+
`help-capture(spur self ${noun}; hidden root alias)`,
|
|
278
|
+
present && command.flags.includes(f) ? 'ok' : 'mismatch',
|
|
279
|
+
command.flags.includes(f)
|
|
280
|
+
? 'flag present on canonical command'
|
|
281
|
+
: `flag absent (${command.flags.join(', ')})`,
|
|
282
|
+
occ,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
continue;
|
|
286
|
+
}
|
|
262
287
|
if (!root.commands.includes(noun)) {
|
|
263
288
|
record(
|
|
264
289
|
`spur ${noun}`,
|
|
@@ -315,6 +340,10 @@ export function checkNounVerbFlags(
|
|
|
315
340
|
}
|
|
316
341
|
}
|
|
317
342
|
for (const verb of verbs) {
|
|
343
|
+
if (nouns.length === 0 && LEGACY_SELF_ALIASES.has(verb)) {
|
|
344
|
+
checkNounVerbFlags([verb], [], flags, occ);
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
318
347
|
if (nouns.length === 0 && root.commands.includes(verb)) {
|
|
319
348
|
record(`spur ${verb}`, 'help-capture(root)', 'ok', 'root verb present', occ);
|
|
320
349
|
}
|
|
@@ -383,7 +412,10 @@ export function sweepPluginTrees(root: string = PLUGIN_ROOT): void {
|
|
|
383
412
|
const cells = line.split('|').map((c) => c.trim());
|
|
384
413
|
const lastCell = cells[cells.length - 2] ?? line;
|
|
385
414
|
if (first && first !== 'Verb' && first !== 'spur') {
|
|
386
|
-
|
|
415
|
+
const nounCommands = surface([refNoun]).commands;
|
|
416
|
+
if (nounCommands.includes(first)) {
|
|
417
|
+
checkNounVerbFlags([refNoun], [first], flagNames(lastCell), occ);
|
|
418
|
+
} else if (rootCommands.includes(first) || LEGACY_SELF_ALIASES.has(first)) {
|
|
387
419
|
checkNounVerbFlags([], [first], flagNames(lastCell), occ);
|
|
388
420
|
} else {
|
|
389
421
|
checkNounVerbFlags([refNoun], [first], flagNames(lastCell), occ);
|
|
@@ -611,7 +643,7 @@ const JSON_PROBES: string[][] = [
|
|
|
611
643
|
['agent', 'list', '--json'],
|
|
612
644
|
['agent', 'doctor', 'omp', '--json'],
|
|
613
645
|
['workflow', 'list', '--json'],
|
|
614
|
-
['workflow', 'validate', '
|
|
646
|
+
['workflow', 'validate', 'basic.yaml', '--json'],
|
|
615
647
|
['status', '--json'],
|
|
616
648
|
['team', 'status', '--json'],
|
|
617
649
|
['projects', 'list', '--json'],
|
|
@@ -758,18 +790,20 @@ export function sweepWorkflows(opts: { run?: CliRunner; wfDir?: string; link?: s
|
|
|
758
790
|
}
|
|
759
791
|
});
|
|
760
792
|
}
|
|
793
|
+
// Two-tier model (task 0648/0650): `.spur/workflows` is no longer a symlink and
|
|
794
|
+
// must not exist — the CLI resolves an explicit project path, then bundled fallback. Assert absence.
|
|
761
795
|
const link = opts.link ?? join(REPO_ROOT, '.spur', 'workflows');
|
|
762
|
-
let status: Row['status'] = '
|
|
763
|
-
let actual = '';
|
|
796
|
+
let status: Row['status'] = 'ok';
|
|
797
|
+
let actual = 'absent (two-tier project→bundled model, task 0650)';
|
|
764
798
|
try {
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
799
|
+
if (existsSync(link)) {
|
|
800
|
+
status = 'mismatch';
|
|
801
|
+
actual = 'still present — should be removed (task 0650 R3)';
|
|
802
|
+
}
|
|
769
803
|
} catch (e) {
|
|
770
|
-
actual = `
|
|
804
|
+
actual = `exists-check failed: ${String(e).slice(0, 120)}`;
|
|
771
805
|
}
|
|
772
|
-
record('.spur/workflows symlink', 'symlink-
|
|
806
|
+
record('.spur/workflows symlink', 'symlink-absent', status, actual, { file: '.spur/workflows', line: 1 });
|
|
773
807
|
}
|
|
774
808
|
|
|
775
809
|
// ─── Report ─────────────────────────────────────────────────────────────────
|
|
@@ -805,7 +839,7 @@ export function render(): string {
|
|
|
805
839
|
L.push(
|
|
806
840
|
"R1 scope: `plugins/sp/{commands,skills,scripts,hooks}` (tests/ and evals/ are the harness itself; agents/ prose is outside R1's named surface list).",
|
|
807
841
|
);
|
|
808
|
-
L.push('R2 scope: all workflow YAML via the
|
|
842
|
+
L.push('R2 scope: all workflow YAML via the bundled tree (two-tier project→bundled model since task 0648/0650).');
|
|
809
843
|
L.push('');
|
|
810
844
|
L.push('## Check methods');
|
|
811
845
|
L.push('');
|
|
@@ -825,7 +859,7 @@ export function render(): string {
|
|
|
825
859
|
L.push(
|
|
826
860
|
'| `workflow-validate` / `workflow-dry-run` | Live engine: schema+semantic validate; `--dry-run` transition walk |',
|
|
827
861
|
);
|
|
828
|
-
L.push('| `symlink-
|
|
862
|
+
L.push('| `symlink-absent` | `.spur/workflows` is asserted absent (two-tier project→bundled model, task 0650) |');
|
|
829
863
|
L.push('');
|
|
830
864
|
for (const [method, list] of byMethod) {
|
|
831
865
|
const mm = list.filter((r) => r.status === 'mismatch').length;
|
|
@@ -281,15 +281,22 @@ function checkTargetResolution(cmd: ParsedCommand, skillsDir: string, root: stri
|
|
|
281
281
|
}
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
// Workflow file refs —
|
|
285
|
-
|
|
284
|
+
// Workflow file refs — bare names (`spur workflow run <name>.yaml`, two-tier model
|
|
285
|
+
// 0648/0650) resolve against the bundled workflow-definition asset tree; legacy
|
|
286
|
+
// `.spur/workflows/<name>.yaml` paths are also caught as unification drift.
|
|
287
|
+
const wfDir = join(root, 'config', 'workflows');
|
|
288
|
+
const workflowRefs = [
|
|
289
|
+
...[...implSection.matchAll(/\.spur\/workflows\/([^\s)"\]]+\.yaml)/g)],
|
|
290
|
+
...[...implSection.matchAll(/spur workflow (?:run|validate) ([a-z0-9-]+\.yaml)/g)],
|
|
291
|
+
];
|
|
286
292
|
for (const ref of workflowRefs) {
|
|
287
|
-
const
|
|
293
|
+
const bare = (ref[1] ?? '').split('/').pop() ?? '';
|
|
294
|
+
const wfPath = join(wfDir, bare);
|
|
288
295
|
if (!existsSync(wfPath)) {
|
|
289
296
|
violations.push({
|
|
290
297
|
command: cmd.name,
|
|
291
298
|
gate: 'c',
|
|
292
|
-
message: `unresolved workflow file ${
|
|
299
|
+
message: `unresolved workflow file ${bare} (missing ${wfPath})`,
|
|
293
300
|
});
|
|
294
301
|
}
|
|
295
302
|
}
|
|
@@ -521,7 +521,7 @@ Do **not** use this skill for:
|
|
|
521
521
|
rubric.
|
|
522
522
|
- `plugins/sp/references/roles.md` — the Layer-1 role→tier table; this skill's verify/review modes
|
|
523
523
|
run under the `reviewer` role (0538 R4: this file points at roles.md, it does not restate tiers).
|
|
524
|
-
-
|
|
524
|
+
- `task-pipeline.yaml` — the `verify → record` gate that consumes the verdict.
|
|
525
525
|
- **`sp:spur-dev`** — the execution-half umbrella that drives the pipeline this skill gates.
|
|
526
526
|
- [references/code-improvement.md](references/code-improvement.md) — architecture-improvement lens
|
|
527
527
|
for module depth, seam placement, locality, coupling, and testability.
|
|
@@ -120,7 +120,7 @@ Wave C verification can emit the following additive `checks[]` rows:
|
|
|
120
120
|
|
|
121
121
|
## How the gate reads it
|
|
122
122
|
|
|
123
|
-
|
|
123
|
+
`task-pipeline.yaml`, transition `verify → record`:
|
|
124
124
|
|
|
125
125
|
```yaml
|
|
126
126
|
guard:
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: history-anatomy
|
|
3
|
+
description: "Independent owner of diagnostic interpretation over already-imported history — the daily/ad-hoc mode contract, a closed finding taxonomy, the eleven-section report contract, and the enrich/validate rubrics. Triggers: history-anatomy, run the daily report, ad-hoc diagnosis, find issues over history."
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
metadata:
|
|
7
|
+
author: spur
|
|
8
|
+
platforms: "claude-code,codex,openclaw,opencode,antigravity,pi"
|
|
9
|
+
category: analysis-core
|
|
10
|
+
interactions:
|
|
11
|
+
- pipeline
|
|
12
|
+
- inversion
|
|
13
|
+
pipeline_steps:
|
|
14
|
+
- report
|
|
15
|
+
- identify
|
|
16
|
+
- propose
|
|
17
|
+
- generate
|
|
18
|
+
openclaw:
|
|
19
|
+
emoji: "🩺"
|
|
20
|
+
see_also:
|
|
21
|
+
- sp:issue-finding
|
|
22
|
+
- sp:spur-cli
|
|
23
|
+
- sp:spur-dev
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# sp:history-anatomy
|
|
27
|
+
|
|
28
|
+
Owns **interpretation only** over already-imported history. It decides which arguments are legal
|
|
29
|
+
in which mode, what counts as evidence, how findings are keyed and graded, and what a published
|
|
30
|
+
report must contain, plus the rubrics its `enrich` and `validate` operations follow. It never
|
|
31
|
+
launches a workflow, never reprocesses raw history files, and never mutates the corpus, docs, or sources —
|
|
32
|
+
all orchestration lives in `history-anatomy.yaml` (0660), not here.
|
|
33
|
+
|
|
34
|
+
This body routes to the three references; the procedure lives there (the BODY_BUDGET shape — a
|
|
35
|
+
fresh skill cannot be added to the BASELINE exemption map).
|
|
36
|
+
|
|
37
|
+
**Choose the mode first.** The single entry is `--mode daily|ad-hoc` (default `daily`):
|
|
38
|
+
`references/modes.md`.
|
|
39
|
+
|
|
40
|
+
**Then hold the report to the contract.** Every report must contain the eleven sections and every
|
|
41
|
+
finding the full field set, with evidence rules and an explicit comparability verdict:
|
|
42
|
+
`references/report-contract.md`.
|
|
43
|
+
|
|
44
|
+
**Then apply the operations.** The workflow calls `enrich` to author the model half, and
|
|
45
|
+
`validate` to gate a candidate report; neither operation launches a workflow:
|
|
46
|
+
`references/operations.md`.
|
|
47
|
+
|
|
48
|
+
## Primary directive
|
|
49
|
+
|
|
50
|
+
- The artifact is the only evidence plane. A dimension the forensics artifact cannot support is a
|
|
51
|
+
**telemetry gap** reported as `not available` — never a raw history-file fallback.
|
|
52
|
+
- Every causal claim needs **two independent signals** (or one labelled hypothesis with a
|
|
53
|
+
confirmation path). Every finding carries at least one evidence anchor. No anchor, no finding.
|
|
54
|
+
- The report never states a trend, delta, or percentage it cannot support — an insufficient or
|
|
55
|
+
materially different baseline renders `not comparable`, with no fabricated comparison.
|
|
56
|
+
- Findings are keyed on a **stable key**, never the prose title, so rewording never reclassifies
|
|
57
|
+
recurrence.
|
|
58
|
+
- Remediation options are **proposals only**: an owner surface, expected impact, a verification
|
|
59
|
+
method, and reversibility. No applied change, diff, or command the report claims to have run.
|
|
60
|
+
|
|
61
|
+
## Read the references
|
|
62
|
+
|
|
63
|
+
| Reference | Owns |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| [`references/modes.md`](references/modes.md) | The daily/ad-hoc mode matrix, bounds normalization, the DST-aware calendar-day rule, and the fail-loud message shape. |
|
|
66
|
+
| [`references/report-contract.md`](references/report-contract.md) | The eleven sections (in order), the per-finding field set, the closed category vocabulary, the stable-key grammar, the evidence rules, comparison semantics, recurrence classes, and the positive-pattern / remediation standards. |
|
|
67
|
+
| [`references/operations.md`](references/operations.md) | The `enrich` and `validate` operation rubrics; neither launches a workflow. |
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Mode contract — `sp:history-anatomy` (HA-S1, 0658)
|
|
2
|
+
|
|
3
|
+
The skill resolves exactly two modes. Everything else fails loud. This matrix is the enforcement
|
|
4
|
+
surface the workflow (0660) and the skill share; keep the vocabulary frozen.
|
|
5
|
+
|
|
6
|
+
## Mode vocabulary (frozen)
|
|
7
|
+
|
|
8
|
+
- Modes: `daily` | `ad-hoc`.
|
|
9
|
+
- Unsupported value literal: `not available`.
|
|
10
|
+
|
|
11
|
+
## Resolution rule
|
|
12
|
+
|
|
13
|
+
`--mode <value>` selects the mode. If `--mode` is omitted, the resolved mode is **`daily`** and the
|
|
14
|
+
resolved window is the **current local calendar day**.
|
|
15
|
+
|
|
16
|
+
## `--mode daily` (default)
|
|
17
|
+
|
|
18
|
+
| Allowed | Behavior |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| (none) | Default window = the current local calendar day. |
|
|
21
|
+
| `--date <YYYY-MM-DD>` | Selects that local calendar day as the window. |
|
|
22
|
+
|
|
23
|
+
Rejected arguments (each fails loud, naming the offending argument):
|
|
24
|
+
|
|
25
|
+
| Argument | Why rejected |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| focus text (positional) | Daily mode has no focus string. |
|
|
28
|
+
| `--since` / `--until` | Daily always uses the calendar-day window. |
|
|
29
|
+
| `--output` | Daily always writes to the run directory (see 0660). |
|
|
30
|
+
|
|
31
|
+
A daily invocation must print the normalized **inclusive ISO bounds** and the timezone used, so the
|
|
32
|
+
wall-clock window is auditable.
|
|
33
|
+
|
|
34
|
+
## `--mode ad-hoc`
|
|
35
|
+
|
|
36
|
+
Requires a **non-empty focus** and **two ordered inclusive bounds**.
|
|
37
|
+
|
|
38
|
+
| Argument | Rule |
|
|
39
|
+
| --- | --- |
|
|
40
|
+
| focus (positional) | Required; a missing or empty focus fails loud. |
|
|
41
|
+
| `--since <iso>` | Required; the inclusive lower bound. |
|
|
42
|
+
| `--until <iso>` | Required; must be present with `--since`; must not be earlier than `--since`. |
|
|
43
|
+
| `--output <path>` | Optional; when present, writes to that explicit path. When absent, writes to the run directory. |
|
|
44
|
+
|
|
45
|
+
Rejected arguments (each fails loud, naming the offending argument):
|
|
46
|
+
|
|
47
|
+
| Argument | Why rejected |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `--date` | Ad-hoc windows are explicit bounds, not a single date. |
|
|
50
|
+
| `--recompute` | Ad-hoc never recomputes a cache (0660 owns the cache branch). |
|
|
51
|
+
|
|
52
|
+
## Bounds normalization
|
|
53
|
+
|
|
54
|
+
Normalize both bounds to inclusive ISO-8601 instants. The report prints the normalized bounds and
|
|
55
|
+
the timezone used.
|
|
56
|
+
|
|
57
|
+
## DST-aware calendar-day rule
|
|
58
|
+
|
|
59
|
+
`--date <YYYY-MM-DD>` must span the **full local calendar day including any DST shift** — it is
|
|
60
|
+
never a fixed 24-hour offset from local midnight.
|
|
61
|
+
|
|
62
|
+
- Resolve the local timezone (the operator's configured zone; state it in the report).
|
|
63
|
+
- The interval runs from the day's first local instant to the day's last local instant.
|
|
64
|
+
- On a 23-hour or 25-hour daylight-saving day, the interval is that actual length, not 24 hours.
|
|
65
|
+
- The bounds are NOT computed as `midnight + 24h`.
|
|
66
|
+
|
|
67
|
+
This is what makes a daily report's window reproducible across DST transitions.
|
|
68
|
+
|
|
69
|
+
## Fail-loud message shape
|
|
70
|
+
|
|
71
|
+
Every rejection names the offending argument and the rule it violated, e.g.:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
--mode daily rejects "focus text" (daily mode has no focus string)
|
|
75
|
+
--mode ad-hoc requires a non-empty focus
|
|
76
|
+
--mode ad-hoc: --until is missing --since
|
|
77
|
+
--mode ad-hoc: --until (2026-08-01T00:00:00Z) is earlier than --since (2026-08-02T00:00:00Z)
|
|
78
|
+
--mode ad-hoc rejects --date (ad-hoc uses explicit --since/--until bounds)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
A combined conflict (e.g. `--mode daily --since X`) reports **each** offending argument it can
|
|
82
|
+
attribute; at minimum it names the first conflicting one.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Operations — `sp:history-anatomy` (HA-S1, 0658)
|
|
2
|
+
|
|
3
|
+
The skill exposes exactly two operations, invoked by `history-anatomy.yaml` (0660):
|
|
4
|
+
|
|
5
|
+
- `enrich` — the model is given the rendered forensics artifacts (current + baseline) and authors
|
|
6
|
+
the model half of the report.
|
|
7
|
+
- `validate` — the model is given a candidate report and independently checks its evidence claims
|
|
8
|
+
against the artifacts.
|
|
9
|
+
|
|
10
|
+
Both are **skill operations**, not workflows. **Neither operation launches a workflow** — that is
|
|
11
|
+
the recursion guard. This is why the rubric lives here, single-sourced, rather than being
|
|
12
|
+
duplicated into the YAML: the rubric cannot recurse.
|
|
13
|
+
|
|
14
|
+
## Invocation contract
|
|
15
|
+
|
|
16
|
+
| Operation | Input | Output |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| `enrich` | current forensics artifact + baseline artifact (plain `HistoryArtifact` JSON) | the model-authored report sections (Baseline comparison, Findings, Recurrence ledger, Remediation options, Performance analysis, Workflow and process improvements, Positive patterns) meeting the report contract |
|
|
19
|
+
| `validate` | a candidate report + the current/baseline artifacts | a PASS / FAIL verdict with per-finding and per-section evidence checks, naming any failing rule |
|
|
20
|
+
|
|
21
|
+
Freeze these operation names and this input/output contract — 0660 consumes them verbatim.
|
|
22
|
+
|
|
23
|
+
## `enrich` rubric
|
|
24
|
+
|
|
25
|
+
Given the current and baseline artifacts, author the model half of the report. Apply, in order:
|
|
26
|
+
|
|
27
|
+
1. **Scope and provenance** + **Executive summary** + **Evidence ledger** are populated from the
|
|
28
|
+
artifact and rendered deterministically (or stated as the artifact's own data). The model
|
|
29
|
+
authors only the sections listed as model-authored.
|
|
30
|
+
2. **Baseline comparison** — apply the comparison semantics: daily → immediately preceding local
|
|
31
|
+
calendar day; ad-hoc → immediately preceding equal-duration window. If baseline coverage is
|
|
32
|
+
insufficient or materially different, emit `not comparable` and **no** trend/delta/percentage.
|
|
33
|
+
3. **Findings** — each with the full per-finding field set (key, category, impact, trend,
|
|
34
|
+
observation, inference, confidence, contradictions, evidenceAnchor). Categories from the closed
|
|
35
|
+
vocabulary; stable keys of the form `<category>:<owner-surface>:<signal>`.
|
|
36
|
+
4. **Recurrence ledger** — classify every finding against the baseline on the **stable key**.
|
|
37
|
+
5. **Telemetry gaps** — every dimension the artifact cannot support, rendered `not available`.
|
|
38
|
+
6. **Remediation options** — proposals only (owner surface, expected impact, verification method,
|
|
39
|
+
reversibility). No applied change/diff/command.
|
|
40
|
+
7. **Positive patterns** — same evidence standard as problems.
|
|
41
|
+
|
|
42
|
+
Never fabricate a value, a trend, an anchor, or an applied fix. Never launch a workflow.
|
|
43
|
+
|
|
44
|
+
## `validate` rubric
|
|
45
|
+
|
|
46
|
+
Given a candidate report and the artifacts, independently verify:
|
|
47
|
+
|
|
48
|
+
- **Eleven-section completeness and order** — all eleven section names present in the frozen
|
|
49
|
+
order; none renamed/omitted.
|
|
50
|
+
- **Per-finding fields** — every finding (problem and positive) carries key, category, impact,
|
|
51
|
+
trend, observation, inference, confidence, contradictions, evidenceAnchor; category in the closed
|
|
52
|
+
vocabulary; stable-key grammar.
|
|
53
|
+
- **Evidence anchors** — every finding has at least one verifiable anchor; no anchor → FAIL.
|
|
54
|
+
- **Causality gate** — a causal claim with one signal must be labelled a hypothesis with a
|
|
55
|
+
confirmation path; otherwise FAIL.
|
|
56
|
+
- **Inference names observations** — an inference that does not name its supporting observations
|
|
57
|
+
FAILs.
|
|
58
|
+
- **Comparability** — a `not comparable` baseline must state no trend/delta/percentage; a stated
|
|
59
|
+
trend must be supported by a comparable baseline.
|
|
60
|
+
- **Recurrence integrity** — classification is consistent with the stable keys (a rewording must
|
|
61
|
+
not flip a recurring finding to new).
|
|
62
|
+
- **Positive patterns** — held to the same standard; an anchor-less entry FAILs.
|
|
63
|
+
- **Remediation** — proposals only; any applied change, diff, or command the report claims to have
|
|
64
|
+
run FAILs.
|
|
65
|
+
|
|
66
|
+
Emit `PASS` only when every rule holds. On FAIL, name the section, the finding key, and the rule
|
|
67
|
+
violated. Never launch a workflow.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Report contract — `sp:history-anatomy` (HA-S1, 0658)
|
|
2
|
+
|
|
3
|
+
The published report is the skill's contract. This reference owns the eleven sections (in order),
|
|
4
|
+
the per-finding field set, the closed category vocabulary, the stable-key grammar, the evidence
|
|
5
|
+
rules, comparison semantics, recurrence classes, and the positive-pattern / remediation standards.
|
|
6
|
+
|
|
7
|
+
## Eleven required sections (in order, frozen)
|
|
8
|
+
|
|
9
|
+
1. Scope and provenance
|
|
10
|
+
2. Executive summary
|
|
11
|
+
3. Baseline comparison
|
|
12
|
+
4. Findings
|
|
13
|
+
5. Recurrence ledger
|
|
14
|
+
6. Telemetry gaps
|
|
15
|
+
7. Remediation options
|
|
16
|
+
8. Performance analysis
|
|
17
|
+
9. Workflow and process improvements
|
|
18
|
+
10. Positive patterns
|
|
19
|
+
11. Evidence ledger
|
|
20
|
+
|
|
21
|
+
These names are consumed verbatim by 0659's structure gate and 0660's validation stage. Do not
|
|
22
|
+
rename, reorder, omit, or restate them.
|
|
23
|
+
|
|
24
|
+
## Closed category vocabulary (frozen)
|
|
25
|
+
|
|
26
|
+
- Categories: `reliability` | `repetition` | `workflow` | `performance` | `coverage` |
|
|
27
|
+
`telemetry` | `positive`.
|
|
28
|
+
|
|
29
|
+
Every finding's category is drawn from this closed set. No category is invented.
|
|
30
|
+
|
|
31
|
+
## Stable finding key (frozen)
|
|
32
|
+
|
|
33
|
+
Each finding carries a stable key of the form:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
<category>:<owner-surface>:<signal>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `category` — one of the closed vocabulary above.
|
|
40
|
+
- `owner-surface` — the surface that would own a change (e.g. a module, command, or skill; free
|
|
41
|
+
text is allowed but must be stable across runs).
|
|
42
|
+
- `signal` — a concise, stable machine-readable identifier of the finding.
|
|
43
|
+
|
|
44
|
+
The key is the recurrence identity. Rewording a finding's title must **never** reclassify it.
|
|
45
|
+
|
|
46
|
+
## Per-finding field set
|
|
47
|
+
|
|
48
|
+
Every finding — problem and positive alike — carries the full field set:
|
|
49
|
+
|
|
50
|
+
| Field | Requirement |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `key` | Stable `<category>:<owner-surface>:<signal>` key. |
|
|
53
|
+
| `category` | From the closed vocabulary, matching the key's first segment. |
|
|
54
|
+
| `impact` | What the situation costs or enables (qualitative, or a concrete number where supported). |
|
|
55
|
+
| `trend` | `new` / `recurring` / `regressed` / `improved` / `resolved` / `not-comparable` (see recurrence). |
|
|
56
|
+
| `observation` | What the artifacts show — evidence, not interpretation. |
|
|
57
|
+
| `inference` | What the observation is reasoned to mean; names its supporting observations. |
|
|
58
|
+
| `confidence` | Per-finding: `high` / `medium` / `low`. Never one blanket report-level score. |
|
|
59
|
+
| `contradictions` | Any contradicting signal shown beside the finding, not silently reconciled. |
|
|
60
|
+
| `evidenceAnchor` | At least one anchor to the forensics artifact or cited `file:line`. An entry with no anchor is invalid. |
|
|
61
|
+
|
|
62
|
+
## Evidence rules
|
|
63
|
+
|
|
64
|
+
Enforcement rail for every claim:
|
|
65
|
+
|
|
66
|
+
1. **Causality needs two independent signals.** A causal claim supported by two or more
|
|
67
|
+
independent signals passes. Exactly one signal is not causation — it must be labelled a
|
|
68
|
+
**hypothesis** with a stated confirmation path.
|
|
69
|
+
2. **A process/workflow change needs recurrence** across two independent sessions, or a single
|
|
70
|
+
**high-impact contract violation cited at `file:line`**.
|
|
71
|
+
3. **Unsupported dimensions read `not available`** and are mirrored into the telemetry-gaps
|
|
72
|
+
section. Never a fabricated value, never a raw history-file fallback.
|
|
73
|
+
4. **Focus biases ranking, not collection.** A focus string changes finding ranking and emphasis;
|
|
74
|
+
it never suppresses material off-topic findings within the window.
|
|
75
|
+
5. **Every inference names its supporting observations.** An inference that does not name its
|
|
76
|
+
observations fails validation.
|
|
77
|
+
6. **Every finding has an evidence anchor.** No anchor, no finding — no row may be dropped because
|
|
78
|
+
it "lacks evidence" while still appearing in a summary.
|
|
79
|
+
|
|
80
|
+
## Comparison semantics
|
|
81
|
+
|
|
82
|
+
The baseline comparison states an explicit comparability verdict.
|
|
83
|
+
|
|
84
|
+
- **Daily** compares against the **immediately preceding local calendar day**.
|
|
85
|
+
- **Ad-hoc** compares against the **immediately preceding equal-duration window**.
|
|
86
|
+
- **Insufficient or materially different coverage** renders **`not comparable`**.
|
|
87
|
+
- A `not comparable` baseline states no trend, no delta, and no percentage. An unsupported
|
|
88
|
+
comparison is never fabricated.
|
|
89
|
+
|
|
90
|
+
## Recurrence ledger
|
|
91
|
+
|
|
92
|
+
Every finding is classified against the baseline using the **stable key**:
|
|
93
|
+
|
|
94
|
+
- `new` — not present in the baseline.
|
|
95
|
+
- `recurring` — present in the baseline with comparable severity.
|
|
96
|
+
- `regressed` — present but worse (severity, count, or impact increased).
|
|
97
|
+
- `improved` — present but better.
|
|
98
|
+
- `resolved` — present in the baseline but absent now.
|
|
99
|
+
- `not-comparable` — the baseline was `not comparable`.
|
|
100
|
+
|
|
101
|
+
Matching is on the stable key, never the prose title. Rewording a title between two runs must not
|
|
102
|
+
reclassify a recurring finding as new.
|
|
103
|
+
|
|
104
|
+
## Positive patterns
|
|
105
|
+
|
|
106
|
+
Positive entries are held to the **same evidence standard as problems**: they carry observation,
|
|
107
|
+
inference, confidence, and at least one evidence anchor. An entry without an anchor is invalid. The
|
|
108
|
+
section renders successful workflows, resolved past issues that stay resolved, and healthy,
|
|
109
|
+
repeating behavior worth keeping.
|
|
110
|
+
|
|
111
|
+
## Remediation options (proposals only)
|
|
112
|
+
|
|
113
|
+
Each option is a **proposal** that names:
|
|
114
|
+
|
|
115
|
+
- **owner surface** — who would apply it.
|
|
116
|
+
- **expected impact** — what it is expected to change.
|
|
117
|
+
- **verification method** — how the change would be confirmed.
|
|
118
|
+
- **reversibility** — whether and how it can be rolled back.
|
|
119
|
+
|
|
120
|
+
The report must contain **no applied change, no diff, and no command it claims to have run**. The
|
|
121
|
+
skill never applies a fix; it proposes one.
|
|
122
|
+
|
|
123
|
+
## Evidence ledger
|
|
124
|
+
|
|
125
|
+
The final section lists, for every finding, the artifact anchor(s) and any cited `file:line`,
|
|
126
|
+
so a reader can verify the report's claims against the evidence plane.
|
|
127
|
+
|
|
128
|
+
## Truthfulness invariants
|
|
129
|
+
|
|
130
|
+
- `not available` is the true rendering for an unsupported dimension, never a masked gap.
|
|
131
|
+
- `not comparable` is the true rendering for an unsupported comparison, never a computed delta.
|
|
132
|
+
- No bounded leaderboard length is presented as a population total (see 0657 / ADR-080: the
|
|
133
|
+
coverage section reads `artifact.population` and renders `top N of M`).
|
|
@@ -233,7 +233,7 @@ Also note **what worked well** so efficient patterns are preserved.
|
|
|
233
233
|
1. **Fix description** — documentation, skill reference, pipeline comment, hook, etc.
|
|
234
234
|
2. **Target location** — exact file path
|
|
235
235
|
- Skill guidance: `skills/<skill-name>/SKILL.md` or `references/<name>.md`
|
|
236
|
-
- Pipeline comments: runtime workflow
|
|
236
|
+
- Pipeline comments: runtime workflow resolves by bare name (`task-pipeline.yaml`)
|
|
237
237
|
- CLI reference: `skills/spur-cli/references/tasks/…`
|
|
238
238
|
3. **Proposed content** — text or code block to add
|
|
239
239
|
4. **Expected impact** — estimated time saved per future run
|
|
@@ -212,5 +212,5 @@ A6 → C5/C3 → unit first if verdict says so; else verify.
|
|
|
212
212
|
- Dev operations map: `plugins/sp/skills/spur-dev/references/dev-operations.md:37-56`
|
|
213
213
|
- `--next` chain on run: `plugins/sp/commands/dev-run.md:104-127`
|
|
214
214
|
- Refine skip-gate sections: `plugins/sp/skills/spur-dev/references/dev-operations.md:114-128`
|
|
215
|
-
- Task lifecycle wip→testing guard:
|
|
215
|
+
- Task lifecycle wip→testing guard: `task-lifecycle.yaml:48-54`
|
|
216
216
|
- Decision-brief format: `plugins/sp/skills/spur-dev/references/decision-brief.md`
|
|
@@ -39,7 +39,7 @@ that review effort happens on the PR, through Codex — not in the local session
|
|
|
39
39
|
sp:pr-reviewing (this skill — mode routing, triage, fix, rules)
|
|
40
40
|
│ deterministic spine, state order + guards:
|
|
41
41
|
▼
|
|
42
|
-
|
|
42
|
+
pr-review.yaml ← workflow SSOT (seeded by spur init; project-tunable)
|
|
43
43
|
│ every state resolves with `superskill script path` and shells out to:
|
|
44
44
|
▼
|
|
45
45
|
staged pr-reviewing.ts ← Bun entrypoint for the tested git/gh core
|
|
@@ -280,7 +280,7 @@ or review requests.
|
|
|
280
280
|
|
|
281
281
|
## Additional Resources
|
|
282
282
|
|
|
283
|
-
- **Workflow SSOT:**
|
|
283
|
+
- **Workflow SSOT:** `pr-review.yaml` (seeded by `spur init`; tune per project —
|
|
284
284
|
wait budget, `preReviewCmd`, dedupe policy)
|
|
285
285
|
- **Script source:** [scripts/pr-reviewing.ts](../../scripts/pr-reviewing.ts) — subcommand CLI
|
|
286
286
|
- **Tests:** [tests/pr-reviewing.test.ts](../../tests/pr-reviewing.test.ts) — stubbed git/gh suites
|
|
@@ -146,7 +146,7 @@ blank Design before implement (`/sp:dev-refine` / `dev-refineall`).
|
|
|
146
146
|
|
|
147
147
|
The `template` field is the **single variant axis** (TASK_VARIANTS): it selects the section
|
|
148
148
|
layout (the `section-matrix.yaml` variant), the scaffold body file
|
|
149
|
-
(`.spur/templates
|
|
149
|
+
(`.spur/tasks/templates/<variant>.md`), and is written to the task's `template:` frontmatter.
|
|
150
150
|
Which sections actually appear is **status-driven** by the runtime matrix — query
|
|
151
151
|
`spur task sections <wbs> list --json` rather than assuming a fixed list — pick the variant by
|
|
152
152
|
*purpose*, not by a section checklist.
|
|
@@ -64,7 +64,7 @@ fails, STOP and report the gap rather than papering over it with customization:
|
|
|
64
64
|
```
|
|
65
65
|
spur status
|
|
66
66
|
spur task create "__probe__" --template standard # confirms task template + matrix resolve
|
|
67
|
-
spur workflow validate
|
|
67
|
+
spur workflow validate task-pipeline.yaml
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
### Phase 1.6 — Rule glob adaptation (LLM-as-judge)
|
|
@@ -12,7 +12,7 @@ Read this before writing `Solution`, `Testing`, or `Review`. Section **writers**
|
|
|
12
12
|
evidence section (F92 0593 R1): implement owns `Solution`, the review coordinator
|
|
13
13
|
(`/sp:dev-review`) owns `Review`, and `spur task record` owns `Testing` (bare-`## Review`
|
|
14
14
|
backfill is fallback-only). The owning implementations are
|
|
15
|
-
|
|
15
|
+
`task-lifecycle.yaml`, `hasPopulatedPriorityTable()` in
|
|
16
16
|
`packages/app/src/services/task-check.ts`, the verdict normalizers in
|
|
17
17
|
`packages/app/src/services/task-record.ts`, and `TASK_CANONICAL_SECTIONS` in
|
|
18
18
|
`packages/domain/src/planning/markdown-document.ts`.
|
|
@@ -29,7 +29,7 @@ Authored workflows default to a project-local directory, grouped by purpose:
|
|
|
29
29
|
|
|
30
30
|
A `--file <path>` argument overrides the default. Keep one workflow per file, named for what it does
|
|
31
31
|
(`approval.yaml`, `import-file.yaml`), not for its mode. The canonical example
|
|
32
|
-
(
|
|
32
|
+
(`basic.yaml`) lives here; copy real schema shapes from it rather than from a
|
|
33
33
|
half-remembered snippet.
|
|
34
34
|
|
|
35
35
|
## Sub-procedure: mode-selection gate
|