spec-planning · diff
git:20260826.2310e7b to git:20260917.265f088
43 added, 2 removed. Audit A to A.
---
name: spec-planning
description: |
Spec-first planning: task breakdown, measurable acceptance criteria, dependency order, risk priority.
planner-csk applies it; the plan goes to docs/PLAN.md.
Use when the scope is unclear or the work spans more than one change.
---
# Spec-First Planning
<!-- routing-eval reads this line; it lives in the BODY so the always-on skill LISTING stays inside
Claude Code's budget (1% of the context window) — an overflowing listing gets descriptions
truncated or dropped, which strips the very keywords a match depends on. -->
Trigger phrases: "plan", "spec", "task breakdown", "acceptance criteria", "roadmap", "how do we split this"
Before writing code: what will be done, how it counts as "done", and in what order to proceed become clear.
## Steps
1. **Purpose & scope:** the problem being solved in a single sentence; also write the out-of-scope explicitly (prevent scope creep).
2. **Split into vertical slices:** the smallest end-to-end working pieces (not horizontal layers). Each slice delivers value on its own.
3. **A contract for every task:** input · output · **measurable acceptance criterion** (testable) · estimated risk.
4. **Dependency graph:** which task waits on what; no cycles. **Bring the riskiest/most-unknown to the front** (fail-fast).
5. **Uncertainties:** assumption list + open questions; do not fill ambiguous spots with a guess, ask with explicit options.
## Output (docs/PLAN.md)
```
# <Feature> — Plan
## Acceptance criteria
- - [ ] <measurable outcome>
+ - [ ] AC-1: <measurable outcome>
+ - [ ] AC-2: <measurable outcome>
## Tasks (order)
- 1. <task> — criterion: <...> — dependency: <none/#n> — risk: <low/medium/high>
+ 1. <task> — satisfies: AC-1 — dependency: <none/#n> — risk: <low/medium/high>
## Assumptions / Open questions
- ...
```
+ **Every criterion carries a stable id, and every task names the ids it satisfies.** The id is what makes the plan
+ checkable later: "AC-2 is only partly built" can be said, argued about and tracked; "the second checkbox" cannot,
+ and renumbering a list silently re-points every reference to it. Never reuse or renumber an id — a dropped
+ criterion keeps its id with a strike-through and a one-line reason. A criterion no task satisfies, and a task that
+ satisfies no criterion, are both findings before a line of code is written.
+
## Mark what you do not know — do not fill it in
Where a requirement admits more than one reading, write the marker **`[NEEDS CLARIFICATION: <the question>]`** at
that exact spot in the plan. Do not resolve it with the likeliest interpretation and move on.
This is the difference between a discipline and a hope. "Stop and ask when unsure" (§1) depends on noticing the
uncertainty in the moment; a marker survives into the artifact, where the user, a reviewer and a later session
can all see it. A plausible assumption silently written into a spec is indistinguishable from a decision, and
that is exactly how the wrong feature gets built correctly.
Rules that keep it honest:
- The marker carries the **question**, not the label. `[NEEDS CLARIFICATION: does an expired invite count as
used, or can it be re-sent?]` is actionable; `[NEEDS CLARIFICATION: invites]` is noise.
- A plan may ship with markers — that is the point. It may **not** ship with a marker inside an acceptance
criterion: a criterion nobody can evaluate is not a criterion.
- Resolve by asking, never by choosing. When the user answers, replace the marker with the answer *and* record
which reading was rejected — the alternative is what a future reader needs.
- Zero markers on a genuinely ambiguous brief is a smell, not a win.
+ ## Converge — before the work is called done, hold the code up against the plan
+
+ Tests prove the code does what the tests say. Nothing so far proves it does what the PLAN said: a criterion can be
+ quietly half-built with every test green, and code nobody asked for can ride along unremarked. So when a plan
+ exists, closing the work includes one pass that reads each criterion against the code as it now stands.
+
+ Bound the pass to what the plan names — the criteria, the tasks, and the files and components they point at. Do not
+ widen the audit into the rest of the codebase. For each `AC-n`, look at the code in that scope and record a finding
+ **only where there is a gap**, classified as exactly one of:
+
+ | Gap | Means |
+ |---|---|
+ | **missing** | nothing in the code implements the criterion |
+ | **partial** | something does, but not all of what the criterion states |
+ | **contradicts** | the code does something that conflicts with the criterion or a plan decision |
+ | **unrequested** | the code contains work no criterion or task called for |
+
+ `unrequested` is the one that is easy to skip and should not be: it is scope creep made visible (principle 3,
+ "surgical change"). It is surfaced, never deleted by this pass — the user decides whether it stays, and if it
+ does, it gets a criterion.
+
+ Report it as a table — `AC-n | gap | evidence (file/area) | remaining work` — then either:
+ - **Converged:** zero findings. Say so in one line, with how many criteria were checked.
+ - **Not converged:** append each remaining item to the plan as a task that names its `AC-n`, and go back to
+ producing. Repeat the pass after that work, until it converges or the user accepts a named gap explicitly.
+
+ This is model discipline, not a gate: no exit code can judge "partially built". What makes it hold is the table —
+ a pass that produced no table did not run.
+
+ Adapted from `converge` in github/spec-kit (MIT), trimmed to the part this kit was missing: its plan already had
+ acceptance criteria, but nothing ever checked the finished code against them.
+
## DoD (this skill's contribution)
- Every task's "done" is testable; ordering and dependencies are visible; the riskiest work has been brought to the front.
- Every unresolved ambiguity carries a `[NEEDS CLARIFICATION: …]` marker; no acceptance criterion contains one.
+ - Every criterion has a stable `AC-n` id and at least one task that satisfies it; at close, a converge pass
+ has run and either reported **Converged** or left its remaining items in the plan as tasks.