@benjaminthomas/spec-driven-dev 1.8.0 → 1.11.0
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/LICENSE +1 -1
- package/README.md +220 -63
- package/bin/cli.mjs +203 -19
- package/bin/risk-eval.mjs +152 -0
- package/bin/risk.mjs +137 -0
- package/package.json +4 -3
- package/plugin/.claude-plugin/icon.png +0 -0
- package/plugin/.claude-plugin/plugin.json +20 -0
- package/{skills → plugin/skills}/spec-checkpoint/SKILL.md +25 -0
- package/{skills → plugin/skills}/spec-create/SKILL.md +30 -1
- package/plugin/skills/spec-create/references/log-template.md +27 -0
- package/{skills → plugin/skills}/spec-create/references/readme-template.md +12 -0
- package/{skills → plugin/skills}/spec-create/references/requirements-template.md +12 -4
- package/{skills → plugin/skills}/spec-create/references/task-template.md +18 -0
- package/{skills → plugin/skills}/spec-implement/SKILL.md +25 -6
- package/{skills → plugin/skills}/spec-implement/references/review-prompt-template.md +2 -1
- package/{skills → plugin/skills}/spec-investigate/SKILL.md +45 -5
- package/{skills → plugin/skills}/spec-investigate/references/report-template.md +12 -0
- package/plugin/skills/spec-review/SKILL.md +135 -0
- package/plugin/skills/spec-review/references/report-template.md +44 -0
- package/{skills → plugin/skills}/spec-setup/SKILL.md +54 -9
- package/plugin/skills/spec-setup/references/audit.md +71 -0
- package/{skills → plugin/skills}/spec-setup/references/config-template.yml +19 -2
- package/plugin/skills/spec-setup/references/context-template.md +83 -0
- package/{skills → plugin/skills}/spec-ship/SKILL.md +10 -0
- package/{skills → plugin/skills}/spec-verify/SKILL.md +10 -2
- /package/{skills → plugin/skills}/generative-seo/SKILL.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/citation-log-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/competitor-analysis-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/content-plan-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/geo-config-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/geo-playbook-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/assets/social-queue-template.md +0 -0
- /package/{skills → plugin/skills}/generative-seo/references/geo-methodology.md +0 -0
- /package/{skills → plugin/skills}/spec-create/references/action-required-template.md +0 -0
- /package/{skills → plugin/skills}/spec-create/references/complexity-rubric.md +0 -0
- /package/{skills → plugin/skills}/spec-implement/references/coder-prompt-template.md +0 -0
- /package/{skills → plugin/skills}/spec-implement/references/fix-prompt-template.md +0 -0
- /package/{skills → plugin/skills}/spec-verify/references/report-template.md +0 -0
package/bin/risk.mjs
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// GitRisk: per-file historical risk from git alone (no model, no tokens).
|
|
2
|
+
// Risk = 0.30·Churn + 0.35·BugDensity + 0.20·FanOut + 0.15·Security (each factor 0–100)
|
|
3
|
+
// The weights are a hypothesis to calibrate by backtest, so .spec-driven.yml `risk.weights` overrides them.
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
7
|
+
|
|
8
|
+
export const DEFAULT_WEIGHTS = { churn: 0.3, bug_density: 0.35, fan_out: 0.2, security: 0.15 };
|
|
9
|
+
export const TIERS = [[75, "critical"], [50, "high"], [25, "medium"], [0, "low"]];
|
|
10
|
+
const MIN_COMMITS = 3; // shortcut: a file with 1 commit that was a fix would score 100% bug density; divide by at least 3. Replace with Bayesian smoothing if calibration shows it matters.
|
|
11
|
+
|
|
12
|
+
// Classification uses the conventional-commit type when the repo uses one, and message keywords otherwise.
|
|
13
|
+
const BUG = /^(fix|hotfix|bugfix|revert)(\(.+\))?!?:|\b(fix(e[sd]|ing)?|bug|hotfix|regression|broken|crash(es|ed)?|patch(ed)?|defect)\b/i;
|
|
14
|
+
const SECURITY = /\b(security|cve-\d+|xss|csrf|ssrf|sqli|injection|vuln(erability)?|exploit|sanitiz(e|ation)|escap(e|ing) (html|input|output)|auth(entication|orization)? (bypass|fix)|privilege|secret(s)? (leak|exposed)|leak(ed|s)? (token|key|secret|credential)|rate.?limit|helmet|csp)\b/i;
|
|
15
|
+
const SKIP = /(^|\/)(node_modules|dist|build|out|vendor|coverage|\.next|graphify-out|specs)\/|\.(md|mdx|txt|lock|log|png|jpe?g|gif|svg|ico|webp|pdf|zip|map|snap|csv)$|(^|\/)(package-lock\.json|yarn\.lock|pnpm-lock\.yaml|Cargo\.lock|go\.sum|poetry\.lock|composer\.lock)$/i;
|
|
16
|
+
const CODE = /\.(m?[jt]sx?|cjs|py|rb|go|rs|java|kt|php|cs|swift|scala|vue|svelte)$/i;
|
|
17
|
+
|
|
18
|
+
const git = (cwd, args) => {
|
|
19
|
+
try { return execFileSync("git", args, { cwd, stdio: ["ignore", "pipe", "ignore"], maxBuffer: 512 * 1024 * 1024 }).toString(); } catch { return ""; }
|
|
20
|
+
};
|
|
21
|
+
export const classify = (subject) => ({ bug: BUG.test(subject), security: SECURITY.test(subject) });
|
|
22
|
+
export const tierOf = (score) => TIERS.find(([min]) => score >= min)[1];
|
|
23
|
+
|
|
24
|
+
// Value at the 90th percentile; "expected" in min(100, actual / expected × 100), so one outlier can't flatten everyone else.
|
|
25
|
+
function p90(values) {
|
|
26
|
+
const v = values.filter((x) => x > 0).sort((a, b) => a - b);
|
|
27
|
+
return v.length ? v[Math.min(v.length - 1, Math.floor(v.length * 0.9))] : 1;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Within-repo dependents: how many other files import this one. Relative JS/TS imports and Python module paths.
|
|
31
|
+
// shortcut: no tsconfig path aliases or cross-repo consumers (GitRisk open question U7); add when a repo needs them.
|
|
32
|
+
function fanOut(repo, files) {
|
|
33
|
+
const set = new Set(files), dependents = new Map(files.map((f) => [f, new Set()]));
|
|
34
|
+
const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", "/index.ts", "/index.tsx", "/index.js", "/index.jsx", ".py", "/__init__.py"];
|
|
35
|
+
const pyIndex = new Map(files.filter((f) => f.endsWith(".py")).map((f) => [f.replace(/\/__init__\.py$|\.py$/, "").split("/").join("."), f]));
|
|
36
|
+
for (const f of files) {
|
|
37
|
+
if (!CODE.test(f)) continue;
|
|
38
|
+
let text = "";
|
|
39
|
+
try { text = fs.readFileSync(path.join(repo, f), "utf8"); } catch { continue; }
|
|
40
|
+
if (text.length > 2e6) continue;
|
|
41
|
+
const targets = new Set();
|
|
42
|
+
for (const m of text.matchAll(/(?:from\s+|require\(\s*|import\(\s*|import\s+)["'](\.{1,2}\/[^"']+)["']/g)) {
|
|
43
|
+
const base = path.posix.normalize(path.posix.join(path.posix.dirname(f), m[1]));
|
|
44
|
+
const hit = exts.map((e) => base + e).find((c) => set.has(c));
|
|
45
|
+
if (hit) targets.add(hit);
|
|
46
|
+
}
|
|
47
|
+
if (f.endsWith(".py")) for (const m of text.matchAll(/^\s*(?:from\s+([\w.]+)\s+import|import\s+([\w.]+))/gm)) {
|
|
48
|
+
const hit = pyIndex.get(m[1] || m[2]);
|
|
49
|
+
if (hit) targets.add(hit);
|
|
50
|
+
}
|
|
51
|
+
for (const t of targets) if (t !== f) dependents.get(t).add(f);
|
|
52
|
+
}
|
|
53
|
+
return new Map([...dependents].map(([f, s]) => [f, s.size]));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Score every tracked code file in one repo. `prefix` labels files in multi-repo workspaces.
|
|
57
|
+
export function scoreRepo(repo, { since = "2 years ago", weights = DEFAULT_WEIGHTS, prefix = "" } = {}) {
|
|
58
|
+
const files = git(repo, ["ls-files"]).split("\n").filter((f) => f && !SKIP.test(f));
|
|
59
|
+
const tracked = new Set(files);
|
|
60
|
+
const stats = new Map(files.map((f) => [f, { commits: 0, bug: 0, security: 0 }]));
|
|
61
|
+
let commits = 0;
|
|
62
|
+
// \x1e starts each commit; the subject follows, then the changed file names.
|
|
63
|
+
for (const block of git(repo, ["log", "--no-merges", `--since=${since}`, "--name-only", "--format=%x1e%s"]).split("\x1e").slice(1)) {
|
|
64
|
+
const [subject, ...changed] = block.split("\n");
|
|
65
|
+
const c = classify(subject);
|
|
66
|
+
commits++;
|
|
67
|
+
for (const f of changed) {
|
|
68
|
+
const s = tracked.has(f) && stats.get(f);
|
|
69
|
+
if (!s) continue;
|
|
70
|
+
s.commits++;
|
|
71
|
+
if (c.bug) s.bug++;
|
|
72
|
+
if (c.security) s.security++;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const fan = fanOut(repo, files);
|
|
76
|
+
const expChurn = p90([...stats.values()].map((s) => s.commits)), expFan = p90([...fan.values()]);
|
|
77
|
+
const rows = files.map((f) => {
|
|
78
|
+
const s = stats.get(f), denom = Math.max(s.commits, MIN_COMMITS);
|
|
79
|
+
const factors = {
|
|
80
|
+
churn: Math.min(100, (s.commits / expChurn) * 100),
|
|
81
|
+
bug_density: s.commits ? (s.bug / denom) * 100 : 0,
|
|
82
|
+
fan_out: Math.min(100, ((fan.get(f) || 0) / expFan) * 100),
|
|
83
|
+
security: s.commits ? (s.security / denom) * 100 : 0,
|
|
84
|
+
};
|
|
85
|
+
const score = Object.keys(DEFAULT_WEIGHTS).reduce((t, k) => t + (Number(weights[k]) || 0) * factors[k], 0);
|
|
86
|
+
const r = (x) => Math.round(x * 10) / 10;
|
|
87
|
+
return { file: prefix ? `${prefix}/${f}` : f, score: r(score), tier: tierOf(score), commits: s.commits, bug_fixes: s.bug, security_fixes: s.security, dependents: fan.get(f) || 0,
|
|
88
|
+
factors: { churn: r(factors.churn), bug_density: r(factors.bug_density), fan_out: r(factors.fan_out), security: r(factors.security) } };
|
|
89
|
+
});
|
|
90
|
+
return { commits, head: git(repo, ["rev-parse", "--short", "HEAD"]).trim(), rows };
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function normWeights(w) {
|
|
94
|
+
const out = { ...DEFAULT_WEIGHTS };
|
|
95
|
+
for (const k of Object.keys(DEFAULT_WEIGHTS)) if (w && w[k] !== undefined && w[k] !== "") out[k] = Number(w[k]);
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
export function weightProblems(w) {
|
|
99
|
+
const p = [];
|
|
100
|
+
for (const [k, v] of Object.entries(w || {})) {
|
|
101
|
+
if (!(k in DEFAULT_WEIGHTS)) p.push(`risk.weights.${k}: unknown factor (use ${Object.keys(DEFAULT_WEIGHTS).join(", ")})`);
|
|
102
|
+
else if (!(Number(v) >= 0)) p.push(`risk.weights.${k} "${v}" must be a number ≥ 0`);
|
|
103
|
+
}
|
|
104
|
+
const sum = Object.values(normWeights(w)).reduce((a, b) => a + b, 0);
|
|
105
|
+
if (Math.abs(sum - 1) > 0.001) p.push(`risk.weights add up to ${Math.round(sum * 1000) / 1000}, not 1`);
|
|
106
|
+
return p;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// The area file skills read: top N files, within the 150-line area-file limit.
|
|
110
|
+
export function riskMarkdown({ rows, repos, weights, since, top }) {
|
|
111
|
+
const pct = (x) => `${Math.round(x * 100)}%`;
|
|
112
|
+
const w = weights;
|
|
113
|
+
const shown = rows.filter((r) => r.score > 0).slice(0, Math.min(top, 120));
|
|
114
|
+
const lines = [
|
|
115
|
+
"# Risk",
|
|
116
|
+
"<!-- Generated by `spec-driven-dev risk`. Don't edit by hand: re-run it. Skills read this only when risk.enabled is on. -->",
|
|
117
|
+
`Scored ${repos.map((r) => `${r.name} at ${r.head} (${r.commits} commits)`).join(", ")} · since ${since} · ${new Date().toISOString().slice(0, 10)}`,
|
|
118
|
+
"",
|
|
119
|
+
`Risk = ${w.churn} × Churn + ${w.bug_density} × Bug Density + ${w.fan_out} × Fan-out + ${w.security} × Security (each 0–100; weights ${pct(w.churn)} / ${pct(w.bug_density)} / ${pct(w.fan_out)} / ${pct(w.security)}).`,
|
|
120
|
+
"Tiers: critical ≥ 75 · high ≥ 50 · medium ≥ 25. A historical signal, not proof of a bug.",
|
|
121
|
+
"",
|
|
122
|
+
"| File | Score | Tier | Churn | Bug density | Fan-out | Security | Commits (fixes / security) |",
|
|
123
|
+
"|---|---|---|---|---|---|---|---|",
|
|
124
|
+
...shown.map((r) => `| \`${r.file}\` | ${r.score} | ${r.tier} | ${r.factors.churn} | ${r.factors.bug_density} | ${r.factors.fan_out} | ${r.factors.security} | ${r.commits} (${r.bug_fixes} / ${r.security_fixes}) |`),
|
|
125
|
+
];
|
|
126
|
+
if (rows.length > shown.length) lines.push("", `${rows.length - shown.length} more files not shown. \`spec-driven-dev risk --files=a,b\` prints any file's score.`);
|
|
127
|
+
return lines.join("\n") + "\n";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Change one `block: key: value` line in .spec-driven.yml text, keeping every comment and other line as is.
|
|
131
|
+
export function setConfigValue(text, blockName, key, value) {
|
|
132
|
+
const block = text.match(new RegExp(`^${blockName}:.*\\n(?:(?:[ \\t]+.*|[ \\t]*)\\n)*`, "m"));
|
|
133
|
+
const line = new RegExp(`^([ \\t]+${key}:[ \\t]*)[^\\s#]+`, "m");
|
|
134
|
+
if (!block) return `${text.replace(/\n*$/, "\n")}${blockName}:\n ${key}: ${value}\n`;
|
|
135
|
+
const body = line.test(block[0]) ? block[0].replace(line, `$1${value}`) : block[0].replace(new RegExp(`^${blockName}:.*\\n`), `$& ${key}: ${value}\n`);
|
|
136
|
+
return text.replace(block[0], body);
|
|
137
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@benjaminthomas/spec-driven-dev",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Spec-driven AI development workflow (investigate → spec → implement → verify → ship) as Agent Skills for Claude Code, Cursor, Codex CLI and Antigravity.",
|
|
3
|
+
"version": "1.11.0",
|
|
4
|
+
"description": "Spec-driven AI development workflow (investigate → spec → implement → verify → review → ship) as Agent Skills for Claude Code, Cursor, Codex CLI and Antigravity.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"spec-driven-dev": "bin/spec-driven-dev.cjs"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"bin",
|
|
11
|
-
"skills"
|
|
11
|
+
"plugin/skills",
|
|
12
|
+
"plugin/.claude-plugin"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"test": "python3 scripts/check.py && node scripts/test-cli.mjs"
|
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ticket-to-pr",
|
|
3
|
+
"version": "1.11.0",
|
|
4
|
+
"description": "Parallel-batch spec-driven feature workflow (spec-setup, spec-investigate, spec-create, spec-implement, spec-verify, spec-review, spec-checkpoint, spec-ship) plus a portable SEO/GEO operations skill (generative-seo) for any codebase.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Benjamin Thomas",
|
|
7
|
+
"url": "https://github.com/benjaminthomas"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"spec-driven-development",
|
|
11
|
+
"feature-workflow",
|
|
12
|
+
"parallel-agents",
|
|
13
|
+
"seo",
|
|
14
|
+
"geo",
|
|
15
|
+
"productivity"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/benjaminthomas/spec-driven-dev",
|
|
18
|
+
"repository": "https://github.com/benjaminthomas/spec-driven-dev",
|
|
19
|
+
"icon": ".claude-plugin/icon.png"
|
|
20
|
+
}
|
|
@@ -49,6 +49,28 @@ issues before proceeding — do not skip or ignore failures.
|
|
|
49
49
|
|
|
50
50
|
Iterate until every check passes cleanly. Only then move to the next step.
|
|
51
51
|
|
|
52
|
+
### Step 2b: Update project context (spec work only)
|
|
53
|
+
|
|
54
|
+
Skip this step unless the changes belong to a spec (`{specs_dir}/{feature}/` exists for this work).
|
|
55
|
+
|
|
56
|
+
1. Overwrite the README's **Resume here** (`Stage: committed`, `Next: spec-ship`). Write
|
|
57
|
+
`Last commit: this checkpoint (git log -1)`, because the commit's hash doesn't exist yet and
|
|
58
|
+
amending afterwards would change it again.
|
|
59
|
+
2. **When the feature is done** (every task checked) and `{specs_dir}/CONTEXT.md` exists, distil
|
|
60
|
+
the lasting lessons. Use the light model tier for this where the host lets you pick a subagent
|
|
61
|
+
model.
|
|
62
|
+
- Read the feature's `log.md`. This is the one time it's read in full.
|
|
63
|
+
- Keep only what a future feature in the same area needs: decisions and why, conventions found,
|
|
64
|
+
pitfalls. Drop routine progress.
|
|
65
|
+
- Add them to the end of the right `context/<area>.md` (create it if the area has none), and add
|
|
66
|
+
one line to CONTEXT.md's **Specs** list. Follow the rules in
|
|
67
|
+
references/context-template.md inside the installed `spec-setup` skill folder (not this repo): dated, with a source, added at the end, within the size
|
|
68
|
+
limits, superseded lines moved to `context/archive.md`.
|
|
69
|
+
- Show the context changes in the report so the user can correct them.
|
|
70
|
+
3. If `risk.enabled` is on and the CLI is available, re-run `spec-driven-dev risk` so the scores
|
|
71
|
+
include this work. It's git-only, so it costs no tokens.
|
|
72
|
+
4. No CONTEXT.md? Skip the distilling and suggest running `spec-setup` to create one.
|
|
73
|
+
|
|
52
74
|
### Step 3: Stage Everything
|
|
53
75
|
|
|
54
76
|
Stage all changes — tracked modifications, deletions, and new untracked files:
|
|
@@ -65,6 +87,9 @@ anything you don't recognize; skim its diff if you're unsure.
|
|
|
65
87
|
|
|
66
88
|
### Step 4: Craft the Commit Message
|
|
67
89
|
|
|
90
|
+
Check `{specs_dir}/CONTEXT.md`'s **Conventions** first, if it exists. A recorded rule about commits
|
|
91
|
+
(authorship, trailers, format) beats the defaults below.
|
|
92
|
+
|
|
68
93
|
Write a commit message in the config's `git.commit_style` (`conventional` → `feat: …`, `ticket` → `STP-123: …` using the ticket ID from the branch name, `freeform`). Without config, follow the project's existing conventions (observed from `git log`). Structure:
|
|
69
94
|
|
|
70
95
|
- **First line**: clear, concise summary in imperative mood (50-72 chars)
|
|
@@ -32,6 +32,31 @@ isn't, detect what this skill needs from the repo, ask about anything ambiguous,
|
|
|
32
32
|
the answers to `.spec-driven.yml` (keys: `layout`, `repos`, `tracker`, `git`, `commands`,
|
|
33
33
|
`specs_dir`).
|
|
34
34
|
|
|
35
|
+
## Project context
|
|
36
|
+
|
|
37
|
+
- **Take context from the investigation.** Use `investigation.md`'s **Relevant Context**. Without an
|
|
38
|
+
investigation, read `{specs_dir}/CONTEXT.md` (or `spec-driven-dev context`) and only the
|
|
39
|
+
`context/<area>.md` files this feature touches. Never load the archive.
|
|
40
|
+
- **Copy, don't link.** Put only the 3–5 lines each task needs into that task's **Project Context**.
|
|
41
|
+
Coders never read the context files, which keeps parallel coders from each loading them.
|
|
42
|
+
- **Trace requirements.** Number them R1, R2… (keep the investigation's numbers), fill **Covers** in
|
|
43
|
+
every task and the **Coverage** table in requirements.md. Don't finish while a requirement has no
|
|
44
|
+
task.
|
|
45
|
+
- **Start the memory.** Create or extend `log.md` (`references/log-template.md`) and fill the
|
|
46
|
+
README's **Resume here** block.
|
|
47
|
+
|
|
48
|
+
## Risk signal (GitRisk)
|
|
49
|
+
|
|
50
|
+
Same rule as `spec-investigate`: use it only when `risk.enabled` is on (or absent) and
|
|
51
|
+
`{specs_dir}/context/risk.md` exists, and ignore risk completely when it's `off`. For each task that
|
|
52
|
+
creates or modifies a **high** or **critical** file (from the investigation's **Risk Hotspots**, or
|
|
53
|
+
`spec-driven-dev risk --files=…`):
|
|
54
|
+
|
|
55
|
+
- **Raise its tier by one** (light → standard → deep), and say why in Complexity's Signals.
|
|
56
|
+
- Fill the task's **Risk** section: the file, its score, and the past failure pattern.
|
|
57
|
+
- Its **Tests** must include at least one test aimed at that past failure pattern, not just the new
|
|
58
|
+
behaviour.
|
|
59
|
+
|
|
35
60
|
## When to Use
|
|
36
61
|
|
|
37
62
|
- After a planning conversation where requirements and technical details have been discussed
|
|
@@ -92,6 +117,7 @@ specs/{feature-name}/
|
|
|
92
117
|
├── README.md
|
|
93
118
|
├── requirements.md
|
|
94
119
|
├── action-required.md
|
|
120
|
+
├── log.md
|
|
95
121
|
└── tasks/
|
|
96
122
|
├── task-01-{name}.md
|
|
97
123
|
├── task-02-{name}.md
|
|
@@ -103,6 +129,7 @@ Read the templates in `references/` before writing each file:
|
|
|
103
129
|
- `references/task-template.md` — for each task file (self-contained with all context)
|
|
104
130
|
- `references/requirements-template.md` — for the requirements document
|
|
105
131
|
- `references/action-required-template.md` — for manual human steps
|
|
132
|
+
- `references/log-template.md` — for the append-only log
|
|
106
133
|
|
|
107
134
|
Task files are numbered with zero-padded two-digit prefixes in topological order: Batch 1 tasks first, then Batch 2, etc. Within a batch, order is arbitrary but stable.
|
|
108
135
|
|
|
@@ -135,6 +162,7 @@ Files created:
|
|
|
135
162
|
- action-required.md
|
|
136
163
|
- tasks/ ({T} task files)
|
|
137
164
|
|
|
165
|
+
Coverage: R1–R{n} all mapped to tasks
|
|
138
166
|
Model plan: {n} light · {n} standard · {n} deep
|
|
139
167
|
(models from .spec-driven.yml → light: {model}, standard: {model}, deep: {model})
|
|
140
168
|
Deep tasks: {task-nn — main reason}
|
|
@@ -149,7 +177,7 @@ Next steps:
|
|
|
149
177
|
2. Review the requirements and task files
|
|
150
178
|
3. When you're happy with it, either:
|
|
151
179
|
- say "implement" to build it and stop for review, or
|
|
152
|
-
- say "approved, run it through" to build, verify and commit in one go (stops at any failure,
|
|
180
|
+
- say "approved, run it through" to build, verify, review and commit in one go (stops at any failure,
|
|
153
181
|
never pushes without asking)
|
|
154
182
|
```
|
|
155
183
|
|
|
@@ -163,4 +191,5 @@ by default after approval. Never start implementing from this skill.
|
|
|
163
191
|
- Tasks within the same batch must not modify overlapping files. Parallel agents on the same branch cannot safely touch the same files.
|
|
164
192
|
- Keep tasks atomic — one concern per task. If a task has more than 5-7 files to modify, consider splitting it.
|
|
165
193
|
- Put tests in each task's Tests section, not in separate testing tasks (unless the user asks, or it's a cross-cutting suite).
|
|
194
|
+
- Every requirement (R1…) maps to at least one task, and every task lists what it **Covers**.
|
|
166
195
|
- Number task files in topological order (batch 1 first, then batch 2, etc.) for easy scanning.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Log Template
|
|
2
|
+
|
|
3
|
+
`specs/{feature}/log.md` keeps what would otherwise live only in the chat: decisions, deviations,
|
|
4
|
+
answers from the user, review findings, and dead ends. Without it, those are lost when the session
|
|
5
|
+
ends or the conversation is compacted.
|
|
6
|
+
|
|
7
|
+
**Rules**
|
|
8
|
+
- **Append only.** Add entries at the bottom. Never rewrite or reorder.
|
|
9
|
+
- **Never read it in full.** A new session reads the README's **Resume here** block. Read the log's
|
|
10
|
+
last ~20 lines only when Resume here isn't enough.
|
|
11
|
+
- **One to three lines per entry.** Point to files as `path:line`. Don't paste code.
|
|
12
|
+
- **Log what's worth keeping:** a decision and its reason, a change from the spec, the user's answer
|
|
13
|
+
to a question, a review finding and its fix, an approach that failed and why. Skip routine
|
|
14
|
+
progress, which the checkboxes already show.
|
|
15
|
+
|
|
16
|
+
## Template
|
|
17
|
+
|
|
18
|
+
```markdown
|
|
19
|
+
# Log: {Feature Name}
|
|
20
|
+
|
|
21
|
+
- 2026-11-10 spec-create · Created spec: {N} tasks in {B} batches. Covers R1–R{n}.
|
|
22
|
+
- 2026-11-10 spec-implement · Decision: reuse `retryWithBackoff` (`src/lib/retry.ts:12`) instead of a new helper. The user asked for it.
|
|
23
|
+
- 2026-11-10 spec-implement · Deviation: task-03 also touches `src/api/routes.ts`, because the route table lives there.
|
|
24
|
+
- 2026-11-11 spec-verify · R3 failed: webhook retried 5 times, not 3. Fixed in task-04 and re-verified.
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Each entry has the date, the skill that wrote it, then what happened and why.
|
|
@@ -7,6 +7,15 @@ Use this structure for the README.md at the root of each spec folder. The README
|
|
|
7
7
|
```markdown
|
|
8
8
|
# {Feature Name}
|
|
9
9
|
|
|
10
|
+
## Resume here
|
|
11
|
+
|
|
12
|
+
<!-- Overwritten by each spec-* skill when it finishes. A new session reads this first. Keep it ~10 lines. -->
|
|
13
|
+
- **Stage:** spec created, awaiting approval
|
|
14
|
+
- **Next:** review the spec, then say "implement" (or "approved, run it through")
|
|
15
|
+
- **Open questions:** {none, or one line each}
|
|
16
|
+
- **Last commit:** {short sha, or "none yet"}
|
|
17
|
+
- **Areas:** {context areas this feature touches, e.g. billing, api}
|
|
18
|
+
|
|
10
19
|
## Overview
|
|
11
20
|
|
|
12
21
|
{One paragraph summary of what the feature does and why it exists.}
|
|
@@ -15,6 +24,7 @@ Use this structure for the README.md at the root of each spec folder. The README
|
|
|
15
24
|
|
|
16
25
|
- [Requirements](./requirements.md) — full requirements and acceptance criteria
|
|
17
26
|
- [Action Required](./action-required.md) — manual steps needing human action
|
|
27
|
+
- [Log](./log.md) — decisions, deviations and review findings (append-only)
|
|
18
28
|
|
|
19
29
|
## Dependency Graph
|
|
20
30
|
|
|
@@ -48,6 +58,8 @@ graph TD
|
|
|
48
58
|
|
|
49
59
|
## Key Points
|
|
50
60
|
|
|
61
|
+
- **Resume here** is the cheap way back in. Every `spec-*` skill overwrites it when it finishes (stage, next action, open questions, last commit), so a new or compacted session reads ~10 lines instead of the whole history. `spec-driven-dev status` prints each spec's **Next** line.
|
|
62
|
+
|
|
51
63
|
- The **Dependency Graph** uses Mermaid syntax (widely rendered in GitHub, VS Code, etc.). Each node shows the task number and title for quick reference.
|
|
52
64
|
- The **Batches** table provides a scannable overview of what runs in parallel.
|
|
53
65
|
- The **Task Status** section uses markdown checkboxes that the `spec-implement` skill updates as tasks complete. The orchestrator parses these to determine which batch to resume from.
|
|
@@ -26,11 +26,18 @@ Use this structure for the requirements.md at the root of each spec folder.
|
|
|
26
26
|
|
|
27
27
|
## Acceptance Criteria
|
|
28
28
|
|
|
29
|
-
{High-level criteria for the entire feature. Individual task files have their own granular criteria.}
|
|
29
|
+
{High-level criteria for the entire feature, numbered R1, R2… so tasks and verification can point to them. Keep the numbers from investigation.md if it has them. Individual task files have their own granular criteria.}
|
|
30
30
|
|
|
31
|
-
- [ ] {Criterion 1}
|
|
32
|
-
- [ ] {Criterion 2}
|
|
33
|
-
- [ ] {Criterion 3}
|
|
31
|
+
- [ ] R1: {Criterion 1}
|
|
32
|
+
- [ ] R2: {Criterion 2}
|
|
33
|
+
- [ ] R3: {Criterion 3}
|
|
34
|
+
|
|
35
|
+
## Coverage
|
|
36
|
+
|
|
37
|
+
| Requirement | Tasks |
|
|
38
|
+
|---|---|
|
|
39
|
+
| R1 | task-01, task-03 |
|
|
40
|
+
| R2 | task-02 |
|
|
34
41
|
|
|
35
42
|
## Assumptions
|
|
36
43
|
|
|
@@ -51,4 +58,5 @@ Use this structure for the requirements.md at the root of each spec folder.
|
|
|
51
58
|
|
|
52
59
|
- The requirements doc provides **overall feature context** that each coder agent receives alongside its task file. Keep it focused on the "what" and "why" — individual task files handle the "how."
|
|
53
60
|
- Non-goals are important: they prevent agents from over-building. If search functionality is out of scope, say so — otherwise a well-meaning agent might add it.
|
|
61
|
+
- **Every requirement must map to at least one task.** `spec-create` doesn't finish while the Coverage table has a requirement with no task, and `spec-verify` reports pass/fail per requirement number.
|
|
54
62
|
- Acceptance criteria here are feature-level (the whole thing works end-to-end). Task-level criteria live in each task file.
|
|
@@ -15,6 +15,10 @@ pending
|
|
|
15
15
|
|
|
16
16
|
{N}
|
|
17
17
|
|
|
18
|
+
## Covers
|
|
19
|
+
|
|
20
|
+
{Requirement numbers from requirements.md this task delivers, e.g. R1, R3.}
|
|
21
|
+
|
|
18
22
|
## Complexity
|
|
19
23
|
|
|
20
24
|
**Tier:** {light | standard | deep}
|
|
@@ -31,6 +35,18 @@ pending
|
|
|
31
35
|
|
|
32
36
|
**Context from dependencies:** {Prose summary of what the dependency tasks produce that this task needs. For example: "task-01-setup-database.md creates the PostgreSQL schema with users and sessions tables. This task builds the API routes that query those tables." This is what makes each file self-contained — the agent does not need to read other task files to understand its inputs.}
|
|
33
37
|
|
|
38
|
+
## Risk
|
|
39
|
+
|
|
40
|
+
{Only when the task touches a high/critical file and risk.enabled is on; otherwise write "None".}
|
|
41
|
+
|
|
42
|
+
- `path/to/file.ts`: {score} {tier}. Past failures: {what the fix commits show keeps breaking}. Test: {the test in Tests aimed at it}
|
|
43
|
+
|
|
44
|
+
## Project Context
|
|
45
|
+
|
|
46
|
+
{Only the 3–5 lines from the project context (CONTEXT.md / context/<area>.md, via the investigation's Relevant Context) that apply to THIS task: conventions, pitfalls, off-limits areas. The coder never reads the context files itself. Write "None" if nothing applies.}
|
|
47
|
+
|
|
48
|
+
- {e.g. Errors go through `AppError` (`src/lib/errors.ts:8`); never throw raw strings.}
|
|
49
|
+
|
|
34
50
|
## Files to Create
|
|
35
51
|
|
|
36
52
|
- `path/to/new-file.ts` — {Brief purpose}
|
|
@@ -87,6 +103,8 @@ pending
|
|
|
87
103
|
- The **Dependencies** section includes prose context (not just filenames) so the agent understands its inputs without reading other files. This is the most important part of making task files self-contained.
|
|
88
104
|
- **Files to Create** and **Files to Modify** make the task's scope explicit. Tasks in the same batch should not overlap on these lists.
|
|
89
105
|
- **Technical Details** captures everything from the planning conversation — CLI commands, schemas, code snippets, file paths, env vars, API endpoints. If it was discussed during planning and is relevant to this task, it belongs here.
|
|
106
|
+
- **Covers** links the task to requirement numbers, so nothing in requirements.md is left without a task.
|
|
107
|
+
- **Project Context** carries just the conventions this task needs. Copy lines; don't link to CONTEXT.md, because parallel coders reading the whole context would multiply the token cost.
|
|
90
108
|
- **Complexity** comes from `complexity-rubric.md`. `spec-implement` picks the coder's model from this tier, so rate honestly: under-rating a risky task is the expensive mistake.
|
|
91
109
|
- **Tests** names the tests the coder writes alongside the code. A behavioural acceptance criterion without a matching test is a gap — add the test or explain why it can only be checked by `spec-verify`.
|
|
92
110
|
- **Acceptance Criteria** should be specific enough that completion can be verified objectively (by a code review agent or a human).
|
|
@@ -38,6 +38,20 @@ isn't, detect what this skill needs from the repo, ask about anything ambiguous,
|
|
|
38
38
|
the answers to `.spec-driven.yml` (keys: `layout`, `repos`, `tracker`, `git`, `commands`,
|
|
39
39
|
`specs_dir`).
|
|
40
40
|
|
|
41
|
+
## Project context and memory
|
|
42
|
+
|
|
43
|
+
- **Start cheap.** Read the README's **Resume here** block first. Read the last ~20 lines of
|
|
44
|
+
`log.md` only if that isn't enough. You, the orchestrator, read `{specs_dir}/CONTEXT.md` once,
|
|
45
|
+
because its **Conventions** and **Off-limits** apply to your own work too: commit messages and
|
|
46
|
+
trailers, branches, files nobody may touch. Coders don't read it. Each task file's **Project
|
|
47
|
+
Context** already carries what its coder needs. Open one `context/<area>.md` only when a review
|
|
48
|
+
finding depends on a convention the task file doesn't state.
|
|
49
|
+
- **Log as you go.** Append 1–3 lines to `log.md` for each decision, deviation from the spec, user
|
|
50
|
+
answer, review finding and fix, or failed approach. Skip routine progress.
|
|
51
|
+
- **Before stopping for any reason** (batch done, failure, user stop, run-through gate), overwrite
|
|
52
|
+
**Resume here** with the stage, next action, open questions, and last commit. A new or compacted
|
|
53
|
+
session must be able to continue from that block alone.
|
|
54
|
+
|
|
41
55
|
## Orchestration Model
|
|
42
56
|
|
|
43
57
|
This skill's parallelism assumes your host can run multiple independent agents at once —
|
|
@@ -209,12 +223,14 @@ After the batch passes review (or the user chooses to proceed):
|
|
|
209
223
|
|
|
210
224
|
1. **Update task files**: for each completed task, change the Status field from `pending` to `complete`
|
|
211
225
|
2. **Update README.md**: change `- [ ]` to `- [x]` for each completed task
|
|
212
|
-
3. **
|
|
226
|
+
3. **Update memory**: append a log entry (what this batch decided or changed from the spec) and
|
|
227
|
+
overwrite the README's **Resume here** (`Stage: batch {N}/{total} done`, `Next: …`).
|
|
228
|
+
4. **Commit the batch**:
|
|
213
229
|
```
|
|
214
230
|
git add -A
|
|
215
231
|
git commit -m "feat({feature}): complete batch {N} — {brief summary}" # or the config's git.commit_style
|
|
216
232
|
```
|
|
217
|
-
|
|
233
|
+
5. **Report batch completion**:
|
|
218
234
|
```
|
|
219
235
|
Batch {N} of {total} complete.
|
|
220
236
|
|
|
@@ -254,7 +270,7 @@ Next steps:
|
|
|
254
270
|
|
|
255
271
|
## Run-through mode (after approval)
|
|
256
272
|
|
|
257
|
-
Run-through applies when the user asks for it ("approved, run it through", "build, verify and
|
|
273
|
+
Run-through applies when the user asks for it ("approved, run it through", "build, verify, review and
|
|
258
274
|
commit it") or when `.spec-driven.yml` has `pipeline.after_approval: run-through` and the user has
|
|
259
275
|
approved the spec. In that case, don't stop after Step 9. Continue:
|
|
260
276
|
|
|
@@ -262,16 +278,18 @@ approved the spec. In that case, don't stop after Step 9. Continue:
|
|
|
262
278
|
Run-through progress:
|
|
263
279
|
- [ ] Implement all batches (Steps 1–9) — every review gate passed
|
|
264
280
|
- [ ] Verify — follow the spec-verify skill; every acceptance criterion PASS
|
|
281
|
+
- [ ] Review — follow the spec-review skill; no blockers (should-fix items are listed, not blocking)
|
|
265
282
|
- [ ] Checkpoint — follow the spec-checkpoint skill; every check passes, commit made
|
|
266
283
|
- [ ] Stop and hand off to spec-ship
|
|
267
284
|
```
|
|
268
285
|
|
|
269
286
|
1. **Gate on each stage.** Move on only if the previous stage fully passed. On any failure (a review
|
|
270
|
-
gate exhausted its 3 cycles, a criterion FAILed or was SKIPPED, a
|
|
287
|
+
gate exhausted its 3 cycles, a criterion FAILed or was SKIPPED, spec-review found a blocker, a
|
|
288
|
+
check failed), stop the
|
|
271
289
|
run-through and report where it stopped, why, and the command to resume (e.g. "fix X, then say
|
|
272
290
|
'continue the run-through'").
|
|
273
|
-
2. **Verify, then checkpoint.** Follow those skills' own instructions in full, including
|
|
274
|
-
verification report. Don't shortcut them because you're running them in sequence.
|
|
291
|
+
2. **Verify, review, then checkpoint.** Follow those skills' own instructions in full, including
|
|
292
|
+
the verification report and review.md. Review fixes still need the user's yes. Don't shortcut them because you're running them in sequence.
|
|
275
293
|
3. **Never push.** The run-through ends at a local commit. Finish with the summary below and ask
|
|
276
294
|
whether to run `spec-ship`. `spec-ship` still shows exactly what will be pushed and waits for a
|
|
277
295
|
yes.
|
|
@@ -282,6 +300,7 @@ Run-through progress:
|
|
|
282
300
|
Run-through complete for "{feature}":
|
|
283
301
|
- Implement: {N} batches, all review gates PASS
|
|
284
302
|
- Verify: {P}/{P} criteria PASS (specs/{feature}/verification-report.md)
|
|
303
|
+
- Review: 0 blockers · {S} should-fix · {N} nits (specs/{feature}/review.md)
|
|
285
304
|
- Checkpoint: {commit hash} — {subject}
|
|
286
305
|
|
|
287
306
|
Ready to push and open a PR. Run spec-ship? (it will show exactly what gets pushed first)
|
|
@@ -25,7 +25,8 @@ You are reviewing the combined output of Batch {batch_number} of a feature imple
|
|
|
25
25
|
- No duplicate or conflicting definitions
|
|
26
26
|
- Shared state (env vars, config) is consistent
|
|
27
27
|
4. **Code Quality**: Check for security issues, performance problems, and adherence to project conventions.
|
|
28
|
-
5. **
|
|
28
|
+
5. **Risk**: for every task with a filled **Risk** section, check the code handles the past failure pattern it names, and that the test aimed at it exists and would fail without the fix.
|
|
29
|
+
6. **Scope**: Verify each task stayed within its defined scope (Files to Create/Modify). Flag any unexpected file changes.
|
|
29
30
|
|
|
30
31
|
## Verdict
|
|
31
32
|
|
|
@@ -8,9 +8,9 @@ description: >
|
|
|
8
8
|
plan it", or hands over any of those inputs and wants the
|
|
9
9
|
system understood (current behaviour, root cause, affected repos/files, risks, open
|
|
10
10
|
questions) rather than fixed or built yet. This is the first stage of the
|
|
11
|
-
investigate → create → (human approval) → implement → verify → ship pipeline — it hands off
|
|
11
|
+
investigate → create → (human approval) → implement → verify → review → ship pipeline — it hands off
|
|
12
12
|
to the existing spec-create skill and does not replace, duplicate, or invoke spec-create,
|
|
13
|
-
spec-implement, spec-verify, or spec-ship itself. Ticket-agnostic: works for bugs, features,
|
|
13
|
+
spec-implement, spec-verify, spec-review, or spec-ship itself. Ticket-agnostic: works for bugs, features,
|
|
14
14
|
refactors, security, performance, infra, or cross-repository tickets in any repo.
|
|
15
15
|
license: MIT
|
|
16
16
|
---
|
|
@@ -22,11 +22,11 @@ Discover and record the facts. Do not design the fix and do not write any code.
|
|
|
22
22
|
This skill is stage 1 of:
|
|
23
23
|
|
|
24
24
|
```
|
|
25
|
-
spec-investigate → spec-create → human approval → spec-implement → spec-verify → spec-ship
|
|
25
|
+
spec-investigate → spec-create → human approval → spec-implement → spec-verify → spec-review → spec-checkpoint → spec-ship
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
`spec-create`, `spec-implement`, `spec-verify`, and `spec-ship` already exist elsewhere (e.g. the
|
|
29
|
-
`
|
|
28
|
+
`spec-create`, `spec-implement`, `spec-verify`, `spec-review`, and `spec-ship` already exist elsewhere (e.g. the
|
|
29
|
+
`ticket-to-pr` plugin, or whatever equivalent this host provides). **Never create, redesign,
|
|
30
30
|
duplicate, or invoke those skills from here.** Your only output is an investigation report plus a
|
|
31
31
|
ready-to-use work branch; a human decides when to run `spec-create` next.
|
|
32
32
|
|
|
@@ -45,6 +45,42 @@ isn't, detect what this skill needs from the repo, ask about anything ambiguous,
|
|
|
45
45
|
the answers to `.spec-driven.yml` (keys: `layout`, `repos`, `tracker`, `git`, `commands`,
|
|
46
46
|
`specs_dir`).
|
|
47
47
|
|
|
48
|
+
## Project context (read before investigating)
|
|
49
|
+
|
|
50
|
+
Cheap sources first, code second:
|
|
51
|
+
|
|
52
|
+
1. Read `{specs_dir}/CONTEXT.md`, the index of 60 lines or fewer, or run
|
|
53
|
+
`spec-driven-dev context`. Pick the areas this work touches and read only those
|
|
54
|
+
`context/<area>.md` files (`spec-driven-dev context --areas=billing,api`). Never load
|
|
55
|
+
`context/archive.md`.
|
|
56
|
+
2. **Optional graph.** If `context.graph` isn't `off` and graphify is available
|
|
57
|
+
(`graphify-out/graph.json` exists or `graphify` is on the PATH), map the system with
|
|
58
|
+
`graphify query "<topic>" --budget 1500` and `graphify path "<A>" "<B>"` before grepping. Treat
|
|
59
|
+
INFERRED or AMBIGUOUS edges as hints. Never install it.
|
|
60
|
+
3. **Context is a lead, not evidence.** Verify it against the code like any other source. Where the
|
|
61
|
+
code contradicts it, record that under **Relevant Context → Context corrections**. Don't edit
|
|
62
|
+
CONTEXT.md from here.
|
|
63
|
+
4. Copy the 10–20 lines that apply into the report's **Relevant Context** section. That digest is
|
|
64
|
+
what later stages use, so they don't reload the context files.
|
|
65
|
+
|
|
66
|
+
No CONTEXT.md? Investigate as usual, and suggest running `spec-setup` afterwards to create one.
|
|
67
|
+
|
|
68
|
+
## Risk signal (GitRisk)
|
|
69
|
+
|
|
70
|
+
Use it only when `.spec-driven.yml` has `risk.enabled: on`, or has no `risk:` block, **and**
|
|
71
|
+
`{specs_dir}/context/risk.md` exists. If `risk.enabled: off`, ignore risk entirely: don't read the
|
|
72
|
+
file, compute scores, or mention risk. That keeps on/off comparisons (`spec-driven-dev risk-eval`)
|
|
73
|
+
clean.
|
|
74
|
+
|
|
75
|
+
1. Once you know the change surface, look up its files: `spec-driven-dev risk --files=a,b` (or
|
|
76
|
+
`npx -y @benjaminthomas/spec-driven-dev risk --files=…`), or find them in `risk.md`. Without the
|
|
77
|
+
CLI, approximate a file's history with `git log --since="2 years ago" --format=%s -- <file>`.
|
|
78
|
+
2. For each **high** or **critical** file in the surface, look harder: read its last ~10 commit
|
|
79
|
+
subjects and the diffs of its last 1–2 fix commits, and check its dependents. Write what keeps
|
|
80
|
+
breaking there in the report's **Risk Hotspots** section.
|
|
81
|
+
3. A score is a reason to look harder, never evidence. Hotspot findings still need their
|
|
82
|
+
VERIFIED / INFERRED labels.
|
|
83
|
+
|
|
48
84
|
## Invocation
|
|
49
85
|
|
|
50
86
|
```
|
|
@@ -285,6 +321,10 @@ needed — this mirrors where `spec-create` already keeps its own output, so the
|
|
|
285
321
|
naturally from the same place; don't commit this folder if the repo's convention already
|
|
286
322
|
gitignores `specs/`, matching whatever this repo already does there). Use the structure in `references/report-template.md`.
|
|
287
323
|
|
|
324
|
+
Number the **Potential Requirements** R1, R2… so `spec-create` and `spec-verify` can trace
|
|
325
|
+
each one. Start `{specs_dir}/{feature-slug}/log.md` (append-only; template: references/log-template.md inside the installed
|
|
326
|
+
`spec-create` skill folder, next to its SKILL.md, not in this repo) with one entry: the date, `spec-investigate`, and the headline finding.
|
|
327
|
+
|
|
288
328
|
Every section should be specific and evidence-backed, or explicitly say "None found" /
|
|
289
329
|
"Not applicable to this ticket" rather than being left looking like an oversight.
|
|
290
330
|
|
|
@@ -16,6 +16,17 @@ Copy this structure into `specs/{feature-slug}/investigation.md`.
|
|
|
16
16
|
- Base Branch:
|
|
17
17
|
- Base Commit:
|
|
18
18
|
|
|
19
|
+
## Relevant Context
|
|
20
|
+
<!-- 10–20 lines max: only what applies to this work, copied from specs/CONTEXT.md and context/<area>.md. spec-create passes these on to task files. -->
|
|
21
|
+
- Areas: (e.g. billing, api)
|
|
22
|
+
- Conventions / decisions / pitfalls that apply: (one line each, with the source)
|
|
23
|
+
- Context corrections: (where the code contradicts CONTEXT.md, with evidence; or "none")
|
|
24
|
+
|
|
25
|
+
## Risk Hotspots
|
|
26
|
+
<!-- Only when risk.enabled is on. One row per high/critical file in the change surface; else "none" or omit. -->
|
|
27
|
+
| File | Score / tier | What has broken here before (from fix commits) | What to watch in this change |
|
|
28
|
+
|---|---|---|---|
|
|
29
|
+
|
|
19
30
|
## Business Context
|
|
20
31
|
## Problem Statement
|
|
21
32
|
## Expected Behaviour
|
|
@@ -45,6 +56,7 @@ Copy this structure into `specs/{feature-slug}/investigation.md`.
|
|
|
45
56
|
### Business Decisions
|
|
46
57
|
### Technical Decisions
|
|
47
58
|
### Potential Requirements
|
|
59
|
+
(Number them R1, R2… so spec-create and spec-verify can trace each one.)
|
|
48
60
|
### Proposed Solutions Discussed
|
|
49
61
|
### Open Questions
|
|
50
62
|
### Conflicts / Discrepancies
|