@gobing-ai/spur 0.3.40 → 0.3.42
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 +15 -0
- package/README.md +15 -1
- package/config/templates/AGENTS.md +5 -3
- package/config/workflows/task-pipeline.yaml +103 -12
- package/package.json +15 -12
- package/plugins/README.md +655 -0
- package/plugins/sp/README.md +621 -0
- package/plugins/sp/agents/expert-spur.md +109 -0
- package/plugins/sp/agents/super-coder.md +126 -0
- package/plugins/sp/agents/super-planner.md +283 -0
- package/plugins/sp/agents/super-reviewer.md +154 -0
- package/plugins/sp/commands/dev-arch.md +30 -0
- package/plugins/sp/commands/dev-brainstorm.md +40 -0
- package/plugins/sp/commands/dev-changelog.md +28 -0
- package/plugins/sp/commands/dev-daily.md +29 -0
- package/plugins/sp/commands/dev-debug.md +29 -0
- package/plugins/sp/commands/dev-dogfood.md +33 -0
- package/plugins/sp/commands/dev-featurechange.md +130 -0
- package/plugins/sp/commands/dev-find-conflict.md +51 -0
- package/plugins/sp/commands/dev-find-issue.md +76 -0
- package/plugins/sp/commands/dev-find-next.md +60 -0
- package/plugins/sp/commands/dev-fixall.md +33 -0
- package/plugins/sp/commands/dev-gitmsg.md +28 -0
- package/plugins/sp/commands/dev-gtd.md +97 -0
- package/plugins/sp/commands/dev-handover.md +26 -0
- package/plugins/sp/commands/dev-idea.md +50 -0
- package/plugins/sp/commands/dev-next.md +31 -0
- package/plugins/sp/commands/dev-parallel.md +30 -0
- package/plugins/sp/commands/dev-plan.md +46 -0
- package/plugins/sp/commands/dev-refine.md +48 -0
- package/plugins/sp/commands/dev-refineall.md +65 -0
- package/plugins/sp/commands/dev-refresh.md +32 -0
- package/plugins/sp/commands/dev-reverse.md +32 -0
- package/plugins/sp/commands/dev-review.md +31 -0
- package/plugins/sp/commands/dev-run.md +63 -0
- package/plugins/sp/commands/dev-runall.md +80 -0
- package/plugins/sp/commands/dev-simplify.md +39 -0
- package/plugins/sp/commands/dev-unit.md +29 -0
- package/plugins/sp/commands/dev-verify.md +48 -0
- package/plugins/sp/commands/dev-verifyall.md +72 -0
- package/plugins/sp/commands/dev-wrap.md +30 -0
- package/plugins/sp/commands/dev-wrapall.md +33 -0
- package/plugins/sp/commands/rule-add.md +18 -0
- package/plugins/sp/commands/rule-refine.md +18 -0
- package/plugins/sp/commands/rule-scan.md +18 -0
- package/plugins/sp/commands/spur-init.md +22 -0
- package/plugins/sp/commands/workflow-add.md +18 -0
- package/plugins/sp/commands/workflow-refine.md +18 -0
- package/plugins/sp/hooks/agent-hint.ts +60 -0
- package/plugins/sp/hooks/careful-guard.ts +147 -0
- package/plugins/sp/hooks/context-post-tool.ts +325 -0
- package/plugins/sp/hooks/context-session-start.ts +182 -0
- package/plugins/sp/hooks/context-session-stop.ts +95 -0
- package/plugins/sp/hooks/hooks.json +51 -0
- package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
- package/plugins/sp/hooks/task-write-guard.ts +84 -0
- package/plugins/sp/plugin.json +8 -0
- package/plugins/sp/scripts/batch-preflight.ts +204 -0
- package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
- package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
- package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
- package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
- package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
- package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
- package/plugins/sp/scripts/task-size-precheck.ts +202 -0
- package/plugins/sp/scripts/validate-commands.ts +651 -0
- package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
- package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
- package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
- package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
- package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
- package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
- package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
- package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
- package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
- package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
- package/plugins/sp/skills/code-implementation/SKILL.md +176 -0
- package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
- package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
- package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
- package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
- package/plugins/sp/skills/code-review/SKILL.md +112 -0
- package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
- package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
- package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
- package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
- package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
- package/plugins/sp/skills/code-testing/SKILL.md +108 -0
- package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
- package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
- package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
- package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
- package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
- package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
- package/plugins/sp/skills/code-verification/SKILL.md +535 -0
- package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
- package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
- package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
- package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
- package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
- package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
- package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
- package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
- package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
- package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
- package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
- package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
- package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
- package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
- package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
- package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
- package/plugins/sp/skills/functional-review/SKILL.md +364 -0
- package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
- package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
- package/plugins/sp/skills/issue-finding/SKILL.md +424 -0
- package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
- package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
- package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
- package/plugins/sp/skills/issue-finding/references/session-formats.md +121 -0
- package/plugins/sp/skills/next-feature/SKILL.md +125 -0
- package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
- package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
- package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
- package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
- package/plugins/sp/skills/next-router/SKILL.md +181 -0
- package/plugins/sp/skills/next-router/references/messages.md +90 -0
- package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
- package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
- package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +100 -0
- package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
- package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
- package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
- package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
- package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
- package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
- package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
- package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
- package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
- package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
- package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
- package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
- package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
- package/plugins/sp/skills/spur-cli/references/features.md +234 -0
- package/plugins/sp/skills/spur-cli/references/init.md +119 -0
- package/plugins/sp/skills/spur-cli/references/message.md +98 -0
- package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
- package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
- package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
- package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
- package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
- package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
- package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
- package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
- package/plugins/sp/skills/spur-cli/references/tasks.md +278 -0
- package/plugins/sp/skills/spur-cli/references/team.md +133 -0
- package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
- package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
- package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
- package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
- package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
- package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
- package/plugins/sp/skills/spur-dev/references/cross-cutting.md +664 -0
- package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
- package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
- package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
- package/plugins/sp/skills/spur-dev/references/execution-batch.md +727 -0
- package/plugins/sp/skills/spur-dev/references/execution-workflow.md +350 -0
- package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
- package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
- package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
- package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
- package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
- package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +88 -0
- package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
- package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
- package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
- package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
- package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
- package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
- package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
- package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
- package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
- package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
- package/spur.js +6093 -5180
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: decomposition
|
|
3
|
+
description: Task decomposition conventions — the task-batch.schema.json contract, template-variant selection, scenario-to-task mapping.
|
|
4
|
+
see_also:
|
|
5
|
+
- spec-decomposition
|
|
6
|
+
- spur-dev
|
|
7
|
+
# Granularity knobs — tune the decomposition standard here (judgment guidance, not
|
|
8
|
+
# runtime-enforced). The skill cites these; editing them adjusts the agent's sizing.
|
|
9
|
+
granularity:
|
|
10
|
+
min_hours: 2 # never create a subtask smaller than this
|
|
11
|
+
target_min_hours: 2 # healthy task lower bound
|
|
12
|
+
target_max_hours: 8 # reassess (likely two deliverables) above this
|
|
13
|
+
force_decompose_above_hours: 16 # mandatory split regardless of other signals
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# Decomposition
|
|
17
|
+
|
|
18
|
+
Turning a feature's acceptance criteria into a validated task batch. The LLM produces JSON;
|
|
19
|
+
the CLI validates it against `task-batch.schema.json`; nothing is written until the gate
|
|
20
|
+
passes.
|
|
21
|
+
|
|
22
|
+
## Granularity — two dimensions
|
|
23
|
+
|
|
24
|
+
The frontmatter `granularity` knobs (`min_hours`, `target_min_hours`, `target_max_hours`,
|
|
25
|
+
`force_decompose_above_hours`) bound a task's *size in hours*. They are the **second** dimension
|
|
26
|
+
of sizing, not the only one. The **first** dimension is **cohesion**: work that edits the same
|
|
27
|
+
files, or that requires the same review context to judge, is one task — *even when the hour
|
|
28
|
+
estimate would justify splitting*.
|
|
29
|
+
|
|
30
|
+
### Cohesion decides legitimacy; hours bound size
|
|
31
|
+
|
|
32
|
+
Apply the two in order:
|
|
33
|
+
|
|
34
|
+
1. **Cohesion first — is the split legitimate at all?** If the candidate children would edit the
|
|
35
|
+
same file surface, or need to be read together to be reviewed, they are one task. Splitting
|
|
36
|
+
cohesive work multiplies the fixed per-task ceremony (precheck, implement, test, review,
|
|
37
|
+
approve, verify, record, done — plus a verdict artifact with full requirement and AC tables,
|
|
38
|
+
plus gate remediation at each transition) without reducing risk: the reviewer still reads one
|
|
39
|
+
diff, just across more files. **Ceremony cost is per-task**, which is why this rule exists and
|
|
40
|
+
why its rationale is written here rather than re-litigated at each decomposition.
|
|
41
|
+
2. **Hours second — is the resulting cohesive task too large?** Only after cohesion says a split is
|
|
42
|
+
legitimate do the hour knobs bound how large that single cohesive task may get. Above
|
|
43
|
+
`force_decompose_above_hours`, the size guard overrides cohesion: split even if the children
|
|
44
|
+
share a review context, because at that size the review itself becomes the risk.
|
|
45
|
+
|
|
46
|
+
Without the second clause, cohesion reads as "never split" — the opposite failure. The knobs are
|
|
47
|
+
the escape hatch; cohesion is the default.
|
|
48
|
+
|
|
49
|
+
### Worked example: H8's own first decomposition
|
|
50
|
+
|
|
51
|
+
Feature H8 ("sp command surface coherence") decomposed into five tasks, each 3–8h — fully inside
|
|
52
|
+
`target_min_hours`/`target_max_hours`. The operator rejected it as over-split, correctly: three of
|
|
53
|
+
the five (0399, 0401, 0402) all edited `dev-operations.md` and the `plugins/sp/commands/*.md`
|
|
54
|
+
surface, so the split created contention over one file surface and tripled the pipeline ceremony
|
|
55
|
+
for a diff a reviewer reads once. The merge (5 → 4, with 0402 absorbed into 0401) removed two full
|
|
56
|
+
sets of precheck/implement/test/review/approve/verify/record/done cycles over content the reviewer
|
|
57
|
+
was always going to read as one diff.
|
|
58
|
+
|
|
59
|
+
The hour knobs alone permitted the five-task split; cohesion is what flagged it. A numeric proxy
|
|
60
|
+
(`max_files_shared` or similar) would have been wrong often enough to be ignored — two tasks
|
|
61
|
+
touching one shared config file may be genuinely independent, and two tasks touching disjoint
|
|
62
|
+
files may share a review context entirely. Cohesion is a judgment about coupling, and it is stated
|
|
63
|
+
as prose for that reason.
|
|
64
|
+
|
|
65
|
+
### Second occurrence: E1's first charting (2026-08-06)
|
|
66
|
+
|
|
67
|
+
The same failure recurred through `sp:wayfinder`, which authors tickets without going through this
|
|
68
|
+
skill. A wayfinder map for feature E1 was charted with 8 investigation tickets where 4 were right —
|
|
69
|
+
four of the six merged pairs would have read the *same transcript files* to answer. Worse, the
|
|
70
|
+
discovery ticket covered only the four secondary agents while claude and codex, the operator's
|
|
71
|
+
primaries, were split into a separate ticket blocked downstream — so the ETL contract would have
|
|
72
|
+
been decided on evidence from the peripheral sources.
|
|
73
|
+
|
|
74
|
+
Two lessons, both now fixed rather than restated:
|
|
75
|
+
|
|
76
|
+
1. **Cohesion applies to investigation tickets, not just implementation tasks.** Two questions
|
|
77
|
+
answered by one body of evidence are one ticket, exactly as two changes to one file surface are
|
|
78
|
+
one task.
|
|
79
|
+
2. **The rule was unreachable from the surface that failed.** It lived only here, cited only by this
|
|
80
|
+
skill and the spur-dev planning path — while wayfinder, issue-finding, brainstorm, and
|
|
81
|
+
dogfood-testing all author tasks through other routes. The shared statement now lives in
|
|
82
|
+
[`../../spur-dev/references/cross-cutting.md`](../../spur-dev/references/cross-cutting.md)
|
|
83
|
+
§ Task sizing, which every command and skill already cites; this file keeps the full treatment
|
|
84
|
+
and the knobs. **Do not delete the cross-cutting section as duplication** — that reachability is
|
|
85
|
+
the fix.
|
|
86
|
+
|
|
87
|
+
## The batch schema
|
|
88
|
+
|
|
89
|
+
`apps/cli/schemas/task-batch.schema.json` (runtime SSOT: the Zod `taskBatchSchema` in
|
|
90
|
+
`@gobing-ai/spur-domain`) defines the JSON shape. **The top level is a JSON ARRAY of task items —
|
|
91
|
+
NOT an object with a `tasks` key.** Each item is `.strict()`: any field not in the table below is
|
|
92
|
+
rejected, and a single rejected item fails the whole batch (all-or-nothing).
|
|
93
|
+
|
|
94
|
+
| Field | Required | Notes |
|
|
95
|
+
|-------|----------|-------|
|
|
96
|
+
| `name` | yes | Task title; used in slug generation. |
|
|
97
|
+
| `template` | no | Template variant (`standard`, `feature-impl`, `issue`, `review`, `meta`, `brainstorm`); defaults to `standard` (`feature-impl` when `--feature` is given). |
|
|
98
|
+
| `feature_id` | no | Links the task to a feature — the single traceability edge. |
|
|
99
|
+
| `parent_wbs` | no | For sub-tasks; references the parent's WBS (quoted 4-digit string, e.g. `"0042"`). |
|
|
100
|
+
| `priority` | no | `P0`–`P3`; align with feature priority. |
|
|
101
|
+
| `tags` | no | String tags. |
|
|
102
|
+
| `background` | no | Pre-filled `## Background` body (the scenario→task mapping note goes here). |
|
|
103
|
+
| `requirements` | no | Pre-filled `## Requirements` body. |
|
|
104
|
+
| `design` | **default yes** | Pre-filled `### Design` (WHAT/WHY). **Author by default** on plan/decompose. Omit only under operator `--skip-design` (refine fills later). |
|
|
105
|
+
| `plan` | recommended | Pre-filled `### Plan` checklist when known at create. |
|
|
106
|
+
| `acceptance_criteria` | recommended | Pre-filled `### Acceptance Criteria` when scenarios are known. |
|
|
107
|
+
|
|
108
|
+
> There is **no** generic `sections` field and **no** `dependencies` field in the batch item — the
|
|
109
|
+
> Zod schema is strict and rejects both. Use `background`/`requirements`/`design`/`plan`/
|
|
110
|
+
> `acceptance_criteria` for content, and record ordering in `background` prose (the WBS-level
|
|
111
|
+
> `dependencies` frontmatter is set later, not at batch create).
|
|
112
|
+
|
|
113
|
+
### Section bodies are markdown — format them as markdown
|
|
114
|
+
|
|
115
|
+
Every body field is written into the task file verbatim and rendered by the Board's markdown
|
|
116
|
+
preview. **A body is not a plain-text blob**: consecutive lines with no list marker collapse into a
|
|
117
|
+
single run-on paragraph on render, even though they look like separate items in the JSON source.
|
|
118
|
+
|
|
119
|
+
**`requirements` — always author R-items as a GitHub task-list checkbox, one per line:**
|
|
120
|
+
|
|
121
|
+
```json
|
|
122
|
+
"requirements": "- [ ] R1. <text>\n- [ ] R2. <text>\n- [ ] R3. <text>"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`R1. <text>\nR2. <text>` (no marker) is the trap. `spur task check` **accepts** it — the L3
|
|
126
|
+
R-numbering rule matches the bare `Rn.` token — so nothing fails, and the defect only surfaces later
|
|
127
|
+
as an unreadable paragraph in Board preview. Do not rely on `check` to catch this. Keep the `Rn.`
|
|
128
|
+
(period) token inside the marker so R-numbering still resolves; see the canonical rule in
|
|
129
|
+
`sp:spur-dev` → `references/planning-workflow.md`.
|
|
130
|
+
|
|
131
|
+
Applies to the other body fields too: `plan` as an ordered list (`1. …\n2. …`), `acceptance_criteria`
|
|
132
|
+
as a fenced ```` ```gherkin ```` block, and any enumeration inside `background` or `design` as a
|
|
133
|
+
`- ` list.
|
|
134
|
+
|
|
135
|
+
### Design at create (default) vs `--skip-design`
|
|
136
|
+
|
|
137
|
+
**Default (no `--skip-design` on `/sp:dev-plan` / `/sp:dev-idea`):** every batch item for
|
|
138
|
+
`standard` / `feature-impl` (and any variant that carries Design at `todo`) **must** include a
|
|
139
|
+
non-empty `design` field — chosen approach + one-line reason, rejected alternatives, invariants,
|
|
140
|
+
key signatures (not code dumps). This is the capable-first cost path: lock the box once at create.
|
|
141
|
+
|
|
142
|
+
**`--skip-design`:** leave `design` empty (scaffold only). Refine is the **fallback** that fills
|
|
143
|
+
blank Design before implement (`/sp:dev-refine` / `dev-refineall`).
|
|
144
|
+
|
|
145
|
+
## Template-variant selection
|
|
146
|
+
|
|
147
|
+
The `template` field is the **single variant axis** (TASK_VARIANTS): it selects the section
|
|
148
|
+
layout (the `section-matrix.yaml` variant), the scaffold body file
|
|
149
|
+
(`.spur/templates/task/<variant>.md`), and is written to the task's `template:` frontmatter.
|
|
150
|
+
Which sections actually appear is **stage-driven** by the matrix (e.g. `Solution` only from `wip`),
|
|
151
|
+
not a fixed list — pick the variant by *purpose*, not by a section checklist.
|
|
152
|
+
|
|
153
|
+
| Variant | When to use |
|
|
154
|
+
|---------|-------------|
|
|
155
|
+
| `standard` | General-purpose implementation work (the workhorse) |
|
|
156
|
+
| `feature-impl` | Implementation tied to a feature; AC pre-seeded, Background from the feature `## Goal` |
|
|
157
|
+
| `issue` | Bug/defect — repro in Background, verified Root Cause, then fix |
|
|
158
|
+
| `review` | Code-review fix-up — logs the findings as **input** (`#### Review Findings` under Background) and fixes them; `### Review` is the **post-fix** reflection + back-issues |
|
|
159
|
+
| `meta` | Process / docs / chore — lightweight Background + Plan |
|
|
160
|
+
| `brainstorm` | Minimal idea capture |
|
|
161
|
+
|
|
162
|
+
Selection on the CLI: `spur task create "<title>" --template <variant>`; in a batch item: the
|
|
163
|
+
`template` field. A `--feature` link defaults the variant to `feature-impl`; otherwise `default`.
|
|
164
|
+
|
|
165
|
+
## Scenario-to-task mapping
|
|
166
|
+
|
|
167
|
+
**Run "Default to NOT decomposing" (below) first.** If the parent scores 0–2, there is no mapping to
|
|
168
|
+
do — write the steps in the parent's `## Plan` and stop. This section only applies once decomposition
|
|
169
|
+
has already been justified.
|
|
170
|
+
|
|
171
|
+
Scenario count is **not** task count. A feature with 7 scenarios does not imply 7 tasks; scenarios
|
|
172
|
+
describe observable behavior, tasks describe units of work, and one unit of work routinely delivers
|
|
173
|
+
several behaviors. Walk the scenarios and sort them into groups, then emit one task per group:
|
|
174
|
+
|
|
175
|
+
1. **Merge** scenarios that one task delivers — same file surface, same subsystem, or unreadable
|
|
176
|
+
apart in review. This is the **most common outcome** and the one agents skip. Two scenarios
|
|
177
|
+
describing two behaviors of one change are one task.
|
|
178
|
+
2. **One task** when a scenario is a unit of work on its own.
|
|
179
|
+
3. **Split into multiple tasks** only when a single scenario spans subsystems (e.g. auth service +
|
|
180
|
+
UI) and each part clears the rubric independently. Each task names the subsystem it owns.
|
|
181
|
+
4. **Record the mapping** in each task's `## Background`, listing every scenario it covers:
|
|
182
|
+
`Implements: R2 — …; R3 — Registered user can log in with email and password`.
|
|
183
|
+
|
|
184
|
+
**Merging never costs AC coverage.** `checkAcCoverage` matches by normalized scenario title across
|
|
185
|
+
each linked task's AC block, so one task carrying R2 and R3 in its `### Acceptance Criteria` covers
|
|
186
|
+
both — there is no orphan warning and no reason to split 1:1 to satisfy the gate. Splitting to keep
|
|
187
|
+
the coverage check quiet is the single most common cause of an over-decomposed batch.
|
|
188
|
+
|
|
189
|
+
### Two R-namespaces — do not mix them in one scenario list
|
|
190
|
+
|
|
191
|
+
A task's `### Requirements` are numbered **task-locally** (R1, R2, … within that task). A feature's AC
|
|
192
|
+
scenarios are numbered in the **feature's** namespace. Both appear in a task's
|
|
193
|
+
`### Acceptance Criteria`, and conflating them is how AC silently drifts from Requirements.
|
|
194
|
+
|
|
195
|
+
The rule:
|
|
196
|
+
|
|
197
|
+
- **Scenarios covering the task's own requirements carry the task-local R-prefix** —
|
|
198
|
+
`Scenario: R3 — <observable outcome>`. Tasks declaring `ac_numbering: task-local` in frontmatter
|
|
199
|
+
get these cross-checked by `spur task check` (`L3.ac-requirement-coverage`): a requirement with no
|
|
200
|
+
scenario, or a scenario citing a requirement that does not exist, is reported.
|
|
201
|
+
- **Scenarios carried verbatim from the feature (for DD-09 traceability) carry NO R-prefix** — copy
|
|
202
|
+
the title text only. `normalizeTitle` (`packages/domain/src/bdd/coverage.ts:58`) strips `R\d+`
|
|
203
|
+
before matching, so the prefix is invisible to feature coverage anyway; dropping it keeps the
|
|
204
|
+
feature's number from being read as a task requirement id. Verified empirically: removing the
|
|
205
|
+
prefix from a carried scenario left the feature's orphan count unchanged.
|
|
206
|
+
|
|
207
|
+
**Legacy tasks are exempt.** Most existing tasks predate this and copied feature AC wholesale,
|
|
208
|
+
carrying the feature's numbers. The coverage check is opt-in precisely so they emit nothing —
|
|
209
|
+
absent `ac_numbering`, only DD-09 applies. Opting an old task in is a pure prefix renumber; it cannot
|
|
210
|
+
break traceability. New tasks get `ac_numbering: task-local` from the templates automatically;
|
|
211
|
+
`spur task update <wbs> --ac-numbering task-local` opts in an existing one.
|
|
212
|
+
|
|
213
|
+
Edge-case scenarios may map to tasks, merge into a sibling, or be deferred. Record deferrals
|
|
214
|
+
explicitly: `Deferred: R7 — Edge case not in this iteration`.
|
|
215
|
+
|
|
216
|
+
## Default to NOT decomposing
|
|
217
|
+
|
|
218
|
+
**The default outcome of decomposition is "keep it as one task."** Splitting is the exception you
|
|
219
|
+
must justify, not the baseline. This is the single most important rule on this page, and the one
|
|
220
|
+
most often skipped when an agent moves fast: the agent reaches the decomposition step, sees a list
|
|
221
|
+
of requirements or findings, and emits one child per item by reflex — producing many small tasks
|
|
222
|
+
that the rubric would have rejected as Plan steps.
|
|
223
|
+
|
|
224
|
+
**Every subtask has a real cost** — a file to track, a sequential bottleneck, a separate review,
|
|
225
|
+
a context switch, a rollback boundary. Five subtasks at 1h each cost more total overhead than one
|
|
226
|
+
task at 5h, with no parallelism or review benefit gained. So before producing any batch JSON:
|
|
227
|
+
|
|
228
|
+
1. **Score the parent first.** Run the rubric (below) on the *whole* unit of work. If it lands at
|
|
229
|
+
0–2, the answer is **keep as one task** — stop, write the implementation steps in the parent's
|
|
230
|
+
`## Plan`, and do not call `batch-create` at all.
|
|
231
|
+
2. **Only if the parent scores 5+ (or a force-decompose override fires)** does decomposition even
|
|
232
|
+
enter the conversation. Then score each *candidate* child — any candidate that scores 0–2 on
|
|
233
|
+
its own is a Plan step, not a task; merge it into a sibling.
|
|
234
|
+
3. **"I can describe N pieces" is not a decomposition trigger.** A finding list, a requirement
|
|
235
|
+
list, or a bullet list is a *Plan checklist*, not a task list. Pieces become tasks only when
|
|
236
|
+
they clear the rubric independently (independent streams / distinct review gate / different
|
|
237
|
+
risk / different expert).
|
|
238
|
+
|
|
239
|
+
The failure mode this section exists to prevent: a parent carrying 6 findings becomes 6 child
|
|
240
|
+
tasks, several of which were <2h doc edits that belonged in the parent's Plan. When in doubt,
|
|
241
|
+
**don't decompose** — the operator can always ask for a split after seeing the Plan.
|
|
242
|
+
|
|
243
|
+
## When to decompose at all
|
|
244
|
+
|
|
245
|
+
**Every subtask has a cost** — a file to track, a sequential bottleneck, a separate review, a
|
|
246
|
+
context switch. The question is never "can I split this?" but "do I *need* to?" Decompose only
|
|
247
|
+
when a benefit outweighs that cost:
|
|
248
|
+
|
|
249
|
+
- The work has genuinely **independent parallel streams** (different agents, simultaneously).
|
|
250
|
+
- A part needs a **distinct review/approval gate** that cannot be combined.
|
|
251
|
+
- A part has a **materially different risk profile** (one safety-critical, one cosmetic).
|
|
252
|
+
- A part needs a **different domain expert** (DB vs UI).
|
|
253
|
+
|
|
254
|
+
Do **not** decompose when the work fits one agent's head, touches related files in one module,
|
|
255
|
+
has a single review gate, or is one deliverable with one rollback boundary. In that case write the
|
|
256
|
+
steps in the parent task's **Plan**, not as separate task files.
|
|
257
|
+
|
|
258
|
+
### Quick rubric (required artifact — record it before writing any batch JSON)
|
|
259
|
+
|
|
260
|
+
Estimate five signals — **E** effort (hours), **D** independently-reviewable deliverables,
|
|
261
|
+
**L** layers/modules, **C** coordination (0 none / 1 moderate / 2 high), **R** risk (0 low / 1 med
|
|
262
|
+
/ 2 high). `score = E + D + L + C + R`, with overrides applied in order:
|
|
263
|
+
|
|
264
|
+
1. **Force decompose** if `R = high` (2).
|
|
265
|
+
2. **Force decompose** if `E > force_decompose_above_hours` (frontmatter knob, default 16h).
|
|
266
|
+
3. **Force single-task** only if none of the above AND it is one file/module, one deliverable,
|
|
267
|
+
one layer, zero coordination, one rollback boundary.
|
|
268
|
+
|
|
269
|
+
| score | decision |
|
|
270
|
+
|-------|----------|
|
|
271
|
+
| 0–2 | keep as one task (write a one-line skip rationale in Plan) |
|
|
272
|
+
| 3–4 | decomposition optional — single-task plan allowed with rationale |
|
|
273
|
+
| 5+ | decompose into deliverable-based tasks |
|
|
274
|
+
|
|
275
|
+
**Record the assessment.** Before `batch-create`, the rubric assessment MUST be written down — for
|
|
276
|
+
the parent (and, if decomposing, each child candidate). This is the enforcement step that stops
|
|
277
|
+
reflexive over-decomposition: if you cannot show the score, you have not justified the split. Two
|
|
278
|
+
acceptable homes for the assessment:
|
|
279
|
+
|
|
280
|
+
- **In the parent's `## Plan`** (for the keep-as-one decision): a one-line skip rationale naming
|
|
281
|
+
the score, e.g. *"Rubric: E1 D1 L1 C0 R0 = 3 → kept whole; steps below."*
|
|
282
|
+
- **In each child's `background`** (when decomposing): a trailing line naming the score and the
|
|
283
|
+
trigger that cleared it, e.g. *"Rubric: E2 D1 L1 C1 R2 = 7 → decompose (force: R=high)."*
|
|
284
|
+
|
|
285
|
+
A batch produced without a recorded assessment is incomplete — re-score before submitting to
|
|
286
|
+
`batch-create`.
|
|
287
|
+
|
|
288
|
+
## Parent (umbrella) tasks
|
|
289
|
+
|
|
290
|
+
When a task decomposes into sub-task **files** (each carrying `parent_wbs`), the original becomes a
|
|
291
|
+
**parent/umbrella task**: it owns the requirements and the cross-cutting design, but it implements
|
|
292
|
+
**nothing itself** — the work lives in its children.
|
|
293
|
+
|
|
294
|
+
A parent is **not a skeleton task.** The "skeleton task" anti-pattern below targets *sub-tasks* that
|
|
295
|
+
punt their content to the parent ("see parent"). A parent that holds the requirements and a roster
|
|
296
|
+
of children is the *correct* shape — the inverse direction is fine.
|
|
297
|
+
|
|
298
|
+
Two rules make a parent verifiable:
|
|
299
|
+
|
|
300
|
+
1. **The parent's `## Plan` must carry the sub-task roster** — a table mapping each child to the
|
|
301
|
+
parent requirement(s) it covers, with its current status AND its blast radius. Write it
|
|
302
|
+
**immediately after `batch-create`** (the same step that lands the children); a parent without a
|
|
303
|
+
roster cannot be checked for completeness by a human. Roster row template:
|
|
304
|
+
|
|
305
|
+
| Sub-task | Covers | Surface | Title | Status |
|
|
306
|
+
|----------|--------|---------|-------|--------|
|
|
307
|
+
| `0110_<slug>.md` | R1, R2 | docs | <child title> | done / todo / wip |
|
|
308
|
+
|
|
309
|
+
The **Surface** column is the blast-radius signal for sequencing: `docs` (skill/command markdown,
|
|
310
|
+
no executable), `code` (app/package TS, has tests), or `infra` (DB schema/migration, workflow
|
|
311
|
+
YAML, CI/CD, `.github/`). When deciding execution order across children of the same priority,
|
|
312
|
+
**run `infra` first** (highest risk, load-bearing, hardest to revert), then `code`, then `docs`
|
|
313
|
+
— riskiest-first surfaces the hard problems while context is fresh and lets the cheap fixes
|
|
314
|
+
absorb any rework. A roster with only a Status column hides this and leads to priority-only
|
|
315
|
+
ordering that buries the infra change among doc edits.
|
|
316
|
+
|
|
317
|
+
The status column is generated by `spur task refresh-roster` (task 0123) — invoked
|
|
318
|
+
automatically by `spur task batch-create` for each distinct `parent_wbs` after the
|
|
319
|
+
atomic create lands (task 0178 F1). Re-run `spur task refresh-roster <parent-wbs>`
|
|
320
|
+
manually to re-emit the block after a child status change outside `batch-create`.
|
|
321
|
+
|
|
322
|
+
2. **A parent is complete only when every sub-task is `done` (or `cancelled`).** Cross-cutting
|
|
323
|
+
requirements satisfied across multiple children (e.g. "validate + doc-sync") are met *inside*
|
|
324
|
+
each child, not as separate tasks. Do not mark a parent `done` while a child is open, and do not
|
|
325
|
+
leave a parent open once all children are closed.
|
|
326
|
+
|
|
327
|
+
> **Gate note.** `spur task check` validates *structure*; parent/child roll-up is
|
|
328
|
+
> enforced by the L4 roll-up gate (`packages/app/src/services/task-check.ts:426`
|
|
329
|
+
> `runL4Rollup`, task 0121) which warns on parent/child status drift and missing
|
|
330
|
+
> roster. The roster itself is auto-generated by `spur task batch-create` (task
|
|
331
|
+
> 0178 F1) — the operator never hand-writes it.
|
|
332
|
+
|
|
333
|
+
## Decomposition heuristics
|
|
334
|
+
|
|
335
|
+
- **Deliverable, not phase.** A subtask must be describable in one sentence a non-technical
|
|
336
|
+
person understands ("Add the task-creation endpoint"), never an activity ("investigate X",
|
|
337
|
+
"design Y", "write tests for Z"). If a subtask name contains *investigate / research / design /
|
|
338
|
+
implement (standalone) / testing (standalone)* or a pipeline phase, you are decomposing by
|
|
339
|
+
phase — stop. Design lives in the parent's **Design** section; testing is part of each task.
|
|
340
|
+
- **Full lifecycle per task.** Each task owns the *complete* circle for its requirement(s):
|
|
341
|
+
define the issue, give the solution + acceptance criteria, draw the plan, record the review.
|
|
342
|
+
Never carve a single requirement into "design task / build task / test task".
|
|
343
|
+
- **Size floor / target (frontmatter knobs).** Never create a subtask smaller than `min_hours`
|
|
344
|
+
(default 2h) — merge it into the adjacent deliverable or make it a Plan step. Aim for
|
|
345
|
+
`target_min_hours`–`target_max_hours` (default 2–8h). If a subtask exceeds `target_max_hours`
|
|
346
|
+
after decomposition, reassess (it is probably two deliverables).
|
|
347
|
+
- **Self-contained.** Every task's Background + Requirements must stand alone (a reviewer should
|
|
348
|
+
not need to open the parent). If you cannot write a meaningful Background without referring to
|
|
349
|
+
the parent, it is a Plan step, not a task.
|
|
350
|
+
- **Ordering:** tasks with no dependencies come first. Note ordering in each task's `background`
|
|
351
|
+
prose at batch time; set the WBS-level `dependencies` frontmatter after creation if needed.
|
|
352
|
+
- **Parallelism:** mark independent tasks with the same priority — the pipeline can fan out.
|
|
353
|
+
- **Testing:** every `feature-impl` task produces its own tests. Do **not** create separate
|
|
354
|
+
"write tests" tasks — testing is part of implementation.
|
|
355
|
+
- **Review:** complex or cross-cutting tasks get a `review` companion task (template `review`).
|
|
356
|
+
Simple tasks skip it — the pipeline's review step suffices.
|
|
357
|
+
- **Record rejected split-alternatives (scope-creep guard).** When a requirement is split across
|
|
358
|
+
tasks (e.g. an R1/R2 split, or a finding that *could* have been its own task but was merged into
|
|
359
|
+
a sibling), record the alternative you rejected and why — in the parent's `## Plan` (for the
|
|
360
|
+
merge decision) or the child's `## Design` (for an R1/R2 split). This is what stops a 4h task
|
|
361
|
+
becoming a 2-day task: the moment you write "rejected: pidfile approach — another file artifact
|
|
362
|
+
to manage, stale on crash; the DB column is the natural home," the scope is bounded and the next
|
|
363
|
+
agent (or you, later) won't re-litigate it. A split without a recorded rejected-alternative is
|
|
364
|
+
incomplete — you have not shown the split was necessary, only that it was possible.
|
|
365
|
+
|
|
366
|
+
## Vertical slices (the slicing-direction axis)
|
|
367
|
+
|
|
368
|
+
The rubric above decides **whether** to split; this section decides **which direction** to cut once
|
|
369
|
+
you do. Every task in a batch must be a thin **vertical slice** through all the layers a scenario
|
|
370
|
+
touches (schema / API / UI / tests, as applicable) — independently demoable or verifiable on its
|
|
371
|
+
own. A vertical slice proves the feature works end-to-end at a small scale; a horizontal layer-task
|
|
372
|
+
proves nothing until every sibling layer-task also lands.
|
|
373
|
+
|
|
374
|
+
**Horizontal layer-tasks are a named anti-pattern** — see the table below (`all-schema` /
|
|
375
|
+
`all-API` / `all-UI` task split). The tell: task names read like layer inventories ("Add the users
|
|
376
|
+
table", "Build the users API", "Build the users UI") instead of capability inventories ("User can
|
|
377
|
+
register with email").
|
|
378
|
+
|
|
379
|
+
**Wrong vs right, worked:**
|
|
380
|
+
|
|
381
|
+
- **Wrong (horizontal):** Task 1 — add `users`/`sessions` tables. Task 2 — add
|
|
382
|
+
`POST /login`/`POST /register` endpoints. Task 3 — build the login/register UI. Nothing is
|
|
383
|
+
demoable until all three land; task 2 blocks on task 1, task 3 blocks on task 2 — a strict
|
|
384
|
+
chain with no parallelism, and a reviewer can't verify task 1 in isolation (a schema with no
|
|
385
|
+
caller proves nothing).
|
|
386
|
+
- **Right (vertical):** Task 1 — user can register with email (schema column + endpoint + form,
|
|
387
|
+
thin but complete). Task 2 — user can log in with email (same three layers, reusing task 1's
|
|
388
|
+
schema). Each task is independently demoable (`curl` the endpoint, or click through the form)
|
|
389
|
+
and independently reviewable; task 2 only depends on task 1's schema, not its UI.
|
|
390
|
+
|
|
391
|
+
**Prefactoring comes first.** "Make the change easy, then make the easy change" — when a vertical
|
|
392
|
+
slice is blocked by an awkward existing shape (a function that needs splitting, a type that needs
|
|
393
|
+
widening, a module boundary that needs to move), that refactor is its own task, ordered **before**
|
|
394
|
+
the slices that depend on it, and it changes no behavior. Do not fold prefactoring into the first
|
|
395
|
+
feature slice — a task that both reshapes existing code and adds a new capability is fighting two
|
|
396
|
+
review lenses at once (§Anti-patterns: this is a variant of under-decomposition when the refactor
|
|
397
|
+
is large enough to warrant its own review).
|
|
398
|
+
|
|
399
|
+
## Pre-batch-create HITL checkpoint (quiz gate)
|
|
400
|
+
|
|
401
|
+
Before calling `spur task batch-create`, present the proposed breakdown to the operator as a
|
|
402
|
+
numbered list and get it reviewed — a batch is atomic and hard to unwind piecemeal once children
|
|
403
|
+
exist, so this is the cheapest point to catch a granularity or ordering mistake.
|
|
404
|
+
|
|
405
|
+
**Present:**
|
|
406
|
+
|
|
407
|
+
```
|
|
408
|
+
1. <title> — blocked by: none — covers: R1 (user can register with email)
|
|
409
|
+
2. <title> — blocked by: #1 — covers: R2 (user can log in with email)
|
|
410
|
+
3. <title> — blocked by: none — covers: R3 (user can reset password)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
Present the quiz as a decision brief — recommended breakdown + the trade-off of each alternative
|
|
414
|
+
slicing, with an explicit recommendation — per the SSOT
|
|
415
|
+
[spur-dev/references/decision-brief.md](../../spur-dev/references/decision-brief.md).
|
|
416
|
+
|
|
417
|
+
**Quiz the operator on:**
|
|
418
|
+
- **Granularity** — does any task look like a horizontal layer-task, a phase-split, or a
|
|
419
|
+
<2h fragment that belongs in a Plan step instead?
|
|
420
|
+
- **Dependency correctness** — is the `blocked-by` chain minimal (no task waits on a sibling it
|
|
421
|
+
doesn't actually need), and does it match the vertical-slice ordering (schema-owning slice
|
|
422
|
+
before the slices that reuse it)?
|
|
423
|
+
|
|
424
|
+
Proceed to `batch-create` only after the operator confirms, or after they request adjustments and
|
|
425
|
+
you re-present the revised list. **Skip this checkpoint under `--auto`** (the profile that already
|
|
426
|
+
waives interactive HITL gates elsewhere in the pipeline) — record in the batch's parent Plan that
|
|
427
|
+
the quiz was auto-skipped, same as any other `--auto`-waived gate.
|
|
428
|
+
|
|
429
|
+
## Anti-patterns (do not do these)
|
|
430
|
+
|
|
431
|
+
| Anti-pattern | Why it's wrong | Instead |
|
|
432
|
+
|--------------|----------------|---------|
|
|
433
|
+
| **Phase split** (investigate → design → implement → test as 4 tasks) | Fragments one deliverable; the "design" task finishes while the feature isn't built | One task; phases become Plan steps |
|
|
434
|
+
| **Skeleton tasks** (empty Background/Requirements, "see parent") | Task files must be self-contained for review | Merge back, or write it as a Plan step |
|
|
435
|
+
| **Over-decomposition** (5 tasks each <30 min for one PR) | 5× tracking overhead for no parallelism or review benefit | One task with a Plan checklist |
|
|
436
|
+
| **Under-decomposition** (one task spanning 3 subsystems + 20h) | Unreviewable, one giant PR, no fan-out | Split by subsystem/deliverable |
|
|
437
|
+
| **Horizontal layer-task** (all-schema task, all-API task, all-UI task) | Nothing is demoable until every sibling layer lands; blocks in a strict chain with no parallelism | Cut vertical slices — one capability through all its layers, thin but complete |
|
|
438
|
+
|
|
439
|
+
### Worked example — the "list reflex" (the most common over-decomposition)
|
|
440
|
+
|
|
441
|
+
A review/findings task arrives carrying 6 findings. The reflex move is to emit one child task per
|
|
442
|
+
finding → 6 tasks. But several findings are typically <2h doc edits or one-line fixes that the
|
|
443
|
+
rubric scores at 0–2 on their own. Those are **Plan steps**, not tasks.
|
|
444
|
+
|
|
445
|
+
**Bad (reflex):** parent + 6 children, three of which were 30-min edits → 6 files, 6 reviews, 6
|
|
446
|
+
rollback boundaries, for work that fit one focused session.
|
|
447
|
+
|
|
448
|
+
**Better:** score each finding. Merge the <2h ones into the parent's `## Plan` as a checklist;
|
|
449
|
+
spawn children only for the findings that clear the rubric independently (distinct module + real
|
|
450
|
+
effort + own review boundary). A 6-finding parent often becomes parent + 2–3 children, not 6.
|
|
451
|
+
|
|
452
|
+
The tell that you're reflex-decomposing: your child names are *"F1 — …", "F2 — …", "F3 — …"* —
|
|
453
|
+
one per list item, sized by the list, not by the work. Re-score before submitting the batch.
|
|
454
|
+
|
|
455
|
+
### Worked example — the phase split
|
|
456
|
+
|
|
457
|
+
*"Add an Antigravity adapter"* decomposed as: 1) investigate the CLI, 2) design the abstraction,
|
|
458
|
+
3) implement the adapter, 4) integrate config switching, 5) add tests. Five tasks — but #1 is an
|
|
459
|
+
activity (not a deliverable), #2 belongs in the task's `## Design` section, #4 and #5 are part of
|
|
460
|
+
#3, and the whole thing is one deliverable one agent completes in a session. Correct: **one task**,
|
|
461
|
+
with research/design/implement/integrate/test as `## Plan` steps.
|
|
462
|
+
|
|
463
|
+
## Stage → sections, and the Design vs Solution split
|
|
464
|
+
|
|
465
|
+
A task created with a spec (a `--feature` link, or a batch item carrying `background`/
|
|
466
|
+
`requirements`) lands at **`todo`** — "ready to execute" (§2.3). A bare capture lands at
|
|
467
|
+
**`backlog`** — "still preparing". The Section-Status-Matrix
|
|
468
|
+
(`.spur/tasks/section-matrix.yaml`) decides which sections a task carries at each stage; the
|
|
469
|
+
producer renders them with invisible HTML guidance comments. You do **not** hand-build the section
|
|
470
|
+
list — `spur task create` / `batch-create` does it from the matrix.
|
|
471
|
+
|
|
472
|
+
| Stage | Means | Sections present |
|
|
473
|
+
|-------|-------|------------------|
|
|
474
|
+
| `backlog` | still preparing | Background |
|
|
475
|
+
| `todo` | ready to execute — the **HITL review gate** | Background, Acceptance Criteria, Design, Plan (+ Q&A/Requirements optional) |
|
|
476
|
+
| `wip` | implementing | + Solution (the change-map starts here) |
|
|
477
|
+
| `testing` | verifying | Solution, Testing |
|
|
478
|
+
| `done` | shipped | Solution, Testing, Review (gated) |
|
|
479
|
+
|
|
480
|
+
**Design (written at `todo`, for HITL review) = the decision record — WHAT/WHY:**
|
|
481
|
+
the chosen approach + a one-line reason, rejected alternatives, key interface/type **signatures**
|
|
482
|
+
(not bodies), and invariants. **Code budget: ≤2 illustrative snippets.** This is what a reviewer
|
|
483
|
+
reads to approve the task *before* any code is written.
|
|
484
|
+
|
|
485
|
+
> **Task `### Design` ≠ the feature design satellite.** This per-task section is code-level and narrow.
|
|
486
|
+
> The feature's cross-cutting design record is the **satellite** `docs/design/<slug>.md`, authored once
|
|
487
|
+
> per feature in the planning half (planning-workflow §Step 5.5), indexed from `04_DESIGN.md §0`. The
|
|
488
|
+
> two coexist: the satellite frames the area; each task's `### Design` records that task's local decision.
|
|
489
|
+
|
|
490
|
+
**Solution (written at `wip`/`testing`) = the change-map — HOW/WHERE:**
|
|
491
|
+
a `file:line` table of every touched site, one sentence each; **≤8-line snippets only for
|
|
492
|
+
non-obvious logic, never full-function dumps.** `spur task check` requires ≥1 `file:line` citation
|
|
493
|
+
once Solution has real content.
|
|
494
|
+
|
|
495
|
+
> **Avoid the legacy "too much code" failure.** Design shows *shape and decision*, not
|
|
496
|
+
> implementation; Solution *points at* the code (file:line), it does not reproduce it. If you find
|
|
497
|
+
> yourself pasting whole functions into either section, you are documenting the diff — stop and
|
|
498
|
+
> cite the location instead.
|
|
499
|
+
|
|
500
|
+
## Batch JSON example
|
|
501
|
+
|
|
502
|
+
The payload is a top-level JSON **array** (no `tasks` wrapper):
|
|
503
|
+
|
|
504
|
+
```json
|
|
505
|
+
[
|
|
506
|
+
{
|
|
507
|
+
"name": "Implement task creation endpoint",
|
|
508
|
+
"template": "feature-impl",
|
|
509
|
+
"feature_id": "A1",
|
|
510
|
+
"priority": "P0",
|
|
511
|
+
"background": "Implements: R1 — User can create a task with required fields",
|
|
512
|
+
"requirements": "- [ ] R1. Accept a title and an optional description on POST /tasks.\n- [ ] R2. Reject an empty title with a 400 and a reason.\n- [ ] R3. Allocate the task file through the CLI-gated write path.",
|
|
513
|
+
"design": "Approach: POST /tasks via existing TaskService.create.\nRejected: ad-hoc SQL in handler.\nInvariants: CLI-gated corpus writes only.",
|
|
514
|
+
"plan": "1. Contract\n2. Handler\n3. Tests",
|
|
515
|
+
"acceptance_criteria": "Scenario: create succeeds\n Given a valid title\n When POST /tasks\n Then a task file is allocated"
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
"name": "Implement task listing endpoint",
|
|
519
|
+
"template": "feature-impl",
|
|
520
|
+
"feature_id": "A1",
|
|
521
|
+
"priority": "P1",
|
|
522
|
+
"background": "Implements: R2 — User can list tasks filtered by status (runs after the create endpoint)",
|
|
523
|
+
"design": "Approach: GET /tasks with status filter on TaskService.list.\nRejected: client-side full scan only.\nInvariants: reuses list DTO from contracts.",
|
|
524
|
+
"plan": "1. Filter param\n2. Handler\n3. Tests"
|
|
525
|
+
}
|
|
526
|
+
]
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## Common schema violations
|
|
530
|
+
|
|
531
|
+
| Violation | Fix |
|
|
532
|
+
|-----------|-----|
|
|
533
|
+
| `name` is empty or missing | Every task must have a name. |
|
|
534
|
+
| `template` value not in the enum | Use one of: `default`, `feature-impl`, `issue`, `review`, `meta`. |
|
|
535
|
+
| `feature_id` references a non-existent feature | Run `spur feature list --json` to confirm the ID exists. |
|
|
536
|
+
| `priority` not `P0`–`P3` | Use the canonical priority scale. |
|
|
537
|
+
| Unknown field (e.g. `sections`, `dependencies`, `tasks` wrapper) | The item schema is strict — use only the documented fields; the payload is a bare array. |
|
|
538
|
+
| `parent_wbs` as a number (`0042`) | Quote it: `"0042"` — leading-zero numerics fail the 4-digit string schema. |
|
|
539
|
+
| `requirements` items written as bare `R1.` lines | Prefix each with `- [ ] ` — bare lines pass `check` but render as one paragraph in Board preview. See "Section bodies are markdown" above. |
|