@gobing-ai/spur 0.3.41 → 0.3.43

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.
Files changed (185) hide show
  1. package/.claude-plugin/marketplace.json +15 -0
  2. package/README.md +15 -1
  3. package/config/templates/AGENTS.md +5 -3
  4. package/config/workflows/task-pipeline.yaml +113 -12
  5. package/package.json +15 -12
  6. package/plugins/README.md +655 -0
  7. package/plugins/sp/README.md +621 -0
  8. package/plugins/sp/agents/expert-spur.md +109 -0
  9. package/plugins/sp/agents/super-coder.md +126 -0
  10. package/plugins/sp/agents/super-planner.md +283 -0
  11. package/plugins/sp/agents/super-reviewer.md +154 -0
  12. package/plugins/sp/commands/dev-arch.md +30 -0
  13. package/plugins/sp/commands/dev-brainstorm.md +40 -0
  14. package/plugins/sp/commands/dev-changelog.md +28 -0
  15. package/plugins/sp/commands/dev-daily.md +29 -0
  16. package/plugins/sp/commands/dev-debug.md +29 -0
  17. package/plugins/sp/commands/dev-dogfood.md +33 -0
  18. package/plugins/sp/commands/dev-featurechange.md +130 -0
  19. package/plugins/sp/commands/dev-find-conflict.md +51 -0
  20. package/plugins/sp/commands/dev-find-issue.md +76 -0
  21. package/plugins/sp/commands/dev-find-next.md +60 -0
  22. package/plugins/sp/commands/dev-fixall.md +33 -0
  23. package/plugins/sp/commands/dev-gitmsg.md +28 -0
  24. package/plugins/sp/commands/dev-gtd.md +97 -0
  25. package/plugins/sp/commands/dev-handover.md +26 -0
  26. package/plugins/sp/commands/dev-idea.md +50 -0
  27. package/plugins/sp/commands/dev-next.md +31 -0
  28. package/plugins/sp/commands/dev-parallel.md +30 -0
  29. package/plugins/sp/commands/dev-plan.md +46 -0
  30. package/plugins/sp/commands/dev-refine.md +48 -0
  31. package/plugins/sp/commands/dev-refineall.md +65 -0
  32. package/plugins/sp/commands/dev-refresh.md +32 -0
  33. package/plugins/sp/commands/dev-reverse.md +32 -0
  34. package/plugins/sp/commands/dev-review.md +31 -0
  35. package/plugins/sp/commands/dev-run.md +63 -0
  36. package/plugins/sp/commands/dev-runall.md +83 -0
  37. package/plugins/sp/commands/dev-simplify.md +39 -0
  38. package/plugins/sp/commands/dev-unit.md +29 -0
  39. package/plugins/sp/commands/dev-verify.md +48 -0
  40. package/plugins/sp/commands/dev-verifyall.md +72 -0
  41. package/plugins/sp/commands/dev-wrap.md +48 -0
  42. package/plugins/sp/commands/dev-wrapall.md +51 -0
  43. package/plugins/sp/commands/rule-add.md +18 -0
  44. package/plugins/sp/commands/rule-refine.md +18 -0
  45. package/plugins/sp/commands/rule-scan.md +18 -0
  46. package/plugins/sp/commands/spur-init.md +22 -0
  47. package/plugins/sp/commands/workflow-add.md +18 -0
  48. package/plugins/sp/commands/workflow-refine.md +18 -0
  49. package/plugins/sp/hooks/agent-hint.ts +60 -0
  50. package/plugins/sp/hooks/careful-guard.ts +147 -0
  51. package/plugins/sp/hooks/context-post-tool.ts +325 -0
  52. package/plugins/sp/hooks/context-session-start.ts +182 -0
  53. package/plugins/sp/hooks/context-session-stop.ts +95 -0
  54. package/plugins/sp/hooks/hooks.json +51 -0
  55. package/plugins/sp/hooks/pi/guard-extension.ts +341 -0
  56. package/plugins/sp/hooks/task-write-guard.ts +84 -0
  57. package/plugins/sp/plugin.json +8 -0
  58. package/plugins/sp/scripts/batch-preflight.ts +204 -0
  59. package/plugins/sp/scripts/daily-summary/daily-summary.ts +606 -0
  60. package/plugins/sp/scripts/daily-summary/logger.ts +28 -0
  61. package/plugins/sp/scripts/dogfood-testing/detect-pipeline-driving.ts +363 -0
  62. package/plugins/sp/scripts/dogfood-testing/validate-report.ts +168 -0
  63. package/plugins/sp/scripts/feature-sync-bounded.ts +451 -0
  64. package/plugins/sp/scripts/stage-registry-adapter.ts +1341 -0
  65. package/plugins/sp/scripts/task-size-precheck.ts +202 -0
  66. package/plugins/sp/scripts/validate-commands.ts +651 -0
  67. package/plugins/sp/scripts/validate-flag-contracts.ts +875 -0
  68. package/plugins/sp/skills/brainstorm/SKILL.md +361 -0
  69. package/plugins/sp/skills/brainstorm/agents/openai.yaml +14 -0
  70. package/plugins/sp/skills/brainstorm/examples/ideation-example.md +209 -0
  71. package/plugins/sp/skills/brainstorm/metadata.openclaw +7 -0
  72. package/plugins/sp/skills/brainstorm/references/grilling-interview.md +68 -0
  73. package/plugins/sp/skills/brainstorm/references/workflows.md +255 -0
  74. package/plugins/sp/skills/branch-workflow/SKILL.md +109 -0
  75. package/plugins/sp/skills/branch-workflow/references/branch-lifecycle.md +69 -0
  76. package/plugins/sp/skills/branch-workflow/references/worktree-patterns.md +100 -0
  77. package/plugins/sp/skills/code-implementation/SKILL.md +203 -0
  78. package/plugins/sp/skills/code-implementation/references/debugging.md +64 -0
  79. package/plugins/sp/skills/code-implementation/references/implementation-patterns.md +113 -0
  80. package/plugins/sp/skills/code-improvement/SKILL.md +231 -0
  81. package/plugins/sp/skills/code-improvement/references/deepening-signals.md +205 -0
  82. package/plugins/sp/skills/code-review/SKILL.md +112 -0
  83. package/plugins/sp/skills/code-review/references/receiving-code-review.md +70 -0
  84. package/plugins/sp/skills/code-review/references/review-lenses.md +117 -0
  85. package/plugins/sp/skills/code-review/references/self-review-checklist.md +53 -0
  86. package/plugins/sp/skills/code-review/references/verification-before-completion.md +68 -0
  87. package/plugins/sp/skills/code-simplification/SKILL.md +225 -0
  88. package/plugins/sp/skills/code-testing/SKILL.md +108 -0
  89. package/plugins/sp/skills/code-testing/references/stacks/bun-ts.md +165 -0
  90. package/plugins/sp/skills/code-testing/references/stacks/go.md +88 -0
  91. package/plugins/sp/skills/code-testing/references/stacks/python.md +117 -0
  92. package/plugins/sp/skills/code-testing/references/test-loop-breaker.md +37 -0
  93. package/plugins/sp/skills/code-testing/references/test-output-discipline.md +52 -0
  94. package/plugins/sp/skills/code-testing/references/unit-testing.md +212 -0
  95. package/plugins/sp/skills/code-verification/SKILL.md +535 -0
  96. package/plugins/sp/skills/code-verification/references/code-improvement.md +39 -0
  97. package/plugins/sp/skills/code-verification/references/secu-review.md +94 -0
  98. package/plugins/sp/skills/code-verification/references/verdict-schema.md +141 -0
  99. package/plugins/sp/skills/conflict-finding/SKILL.md +254 -0
  100. package/plugins/sp/skills/conflict-finding/references/authority-resolution.md +258 -0
  101. package/plugins/sp/skills/conflict-finding/references/comparison-protocol.md +277 -0
  102. package/plugins/sp/skills/conflict-finding/references/finding-contract.md +346 -0
  103. package/plugins/sp/skills/conflict-finding/references/remediation-routing.md +276 -0
  104. package/plugins/sp/skills/daily-summary/SKILL.md +171 -0
  105. package/plugins/sp/skills/daily-summary/agents/openai.yaml +13 -0
  106. package/plugins/sp/skills/doc-evolve/SKILL.md +175 -0
  107. package/plugins/sp/skills/doc-evolve/references/operations.md +93 -0
  108. package/plugins/sp/skills/dogfood-testing/SKILL.md +608 -0
  109. package/plugins/sp/skills/dogfood-testing/references/monitor-ledger.md +211 -0
  110. package/plugins/sp/skills/dogfood-testing/references/report-template.md +351 -0
  111. package/plugins/sp/skills/doubt-driven-development/SKILL.md +136 -0
  112. package/plugins/sp/skills/functional-review/SKILL.md +364 -0
  113. package/plugins/sp/skills/functional-review/references/verdict-schema.md +133 -0
  114. package/plugins/sp/skills/indexed-context/SKILL.md +164 -0
  115. package/plugins/sp/skills/issue-finding/SKILL.md +442 -0
  116. package/plugins/sp/skills/issue-finding/agents/openai.yaml +15 -0
  117. package/plugins/sp/skills/issue-finding/examples/expected-findings.json +27 -0
  118. package/plugins/sp/skills/issue-finding/examples/session-test-loop.jsonl +23 -0
  119. package/plugins/sp/skills/issue-finding/references/session-formats.md +151 -0
  120. package/plugins/sp/skills/next-feature/SKILL.md +125 -0
  121. package/plugins/sp/skills/next-feature/references/handoff-routing.md +92 -0
  122. package/plugins/sp/skills/next-feature/references/proposal-contract.md +49 -0
  123. package/plugins/sp/skills/next-feature/references/ranking-rubric.md +52 -0
  124. package/plugins/sp/skills/next-feature/references/signal-derivation.md +67 -0
  125. package/plugins/sp/skills/next-router/SKILL.md +181 -0
  126. package/plugins/sp/skills/next-router/references/messages.md +90 -0
  127. package/plugins/sp/skills/next-router/references/routing-table.md +216 -0
  128. package/plugins/sp/skills/parallel-execution/SKILL.md +148 -0
  129. package/plugins/sp/skills/parallel-execution/references/dispatch-surface.md +109 -0
  130. package/plugins/sp/skills/parallel-execution/references/fan-out-patterns.md +101 -0
  131. package/plugins/sp/skills/parallel-execution/references/result-synthesis.md +94 -0
  132. package/plugins/sp/skills/reverse-engineering/SKILL.md +375 -0
  133. package/plugins/sp/skills/reverse-engineering/agents/openai.yaml +18 -0
  134. package/plugins/sp/skills/source-driven-development/SKILL.md +124 -0
  135. package/plugins/sp/skills/spec-decomposition/SKILL.md +117 -0
  136. package/plugins/sp/skills/spec-decomposition/references/decomposition.md +539 -0
  137. package/plugins/sp/skills/spur-cli/SKILL.md +133 -0
  138. package/plugins/sp/skills/spur-cli/references/agent.md +179 -0
  139. package/plugins/sp/skills/spur-cli/references/features/acceptance-criteria.md +82 -0
  140. package/plugins/sp/skills/spur-cli/references/features/hierarchy-mece.md +177 -0
  141. package/plugins/sp/skills/spur-cli/references/features/roadmap-priority.md +84 -0
  142. package/plugins/sp/skills/spur-cli/references/features/verbs.md +122 -0
  143. package/plugins/sp/skills/spur-cli/references/features.md +234 -0
  144. package/plugins/sp/skills/spur-cli/references/init.md +119 -0
  145. package/plugins/sp/skills/spur-cli/references/message.md +98 -0
  146. package/plugins/sp/skills/spur-cli/references/rules/authoring-rules.md +212 -0
  147. package/plugins/sp/skills/spur-cli/references/rules/fine-tuning.md +148 -0
  148. package/plugins/sp/skills/spur-cli/references/rules/operations.md +228 -0
  149. package/plugins/sp/skills/spur-cli/references/rules/validation-and-extension.md +129 -0
  150. package/plugins/sp/skills/spur-cli/references/rules.md +209 -0
  151. package/plugins/sp/skills/spur-cli/references/serve.md +58 -0
  152. package/plugins/sp/skills/spur-cli/references/tasks/l3-guard-cheatsheet.md +98 -0
  153. package/plugins/sp/skills/spur-cli/references/tasks/section-editing.md +95 -0
  154. package/plugins/sp/skills/spur-cli/references/tasks/verbs.md +361 -0
  155. package/plugins/sp/skills/spur-cli/references/tasks.md +280 -0
  156. package/plugins/sp/skills/spur-cli/references/team.md +133 -0
  157. package/plugins/sp/skills/spur-cli/references/workflows/authoring-workflows.md +226 -0
  158. package/plugins/sp/skills/spur-cli/references/workflows/operations.md +211 -0
  159. package/plugins/sp/skills/spur-cli/references/workflows/validation-and-extension.md +129 -0
  160. package/plugins/sp/skills/spur-cli/references/workflows.md +355 -0
  161. package/plugins/sp/skills/spur-dev/SKILL.md +224 -0
  162. package/plugins/sp/skills/spur-dev/references/ac-style-guide.md +196 -0
  163. package/plugins/sp/skills/spur-dev/references/cross-cutting.md +680 -0
  164. package/plugins/sp/skills/spur-dev/references/decision-brief.md +80 -0
  165. package/plugins/sp/skills/spur-dev/references/dev-operations.md +546 -0
  166. package/plugins/sp/skills/spur-dev/references/done-housekeeping.md +164 -0
  167. package/plugins/sp/skills/spur-dev/references/execution-batch.md +790 -0
  168. package/plugins/sp/skills/spur-dev/references/execution-workflow.md +352 -0
  169. package/plugins/sp/skills/spur-dev/references/feature-link-helper.md +191 -0
  170. package/plugins/sp/skills/spur-dev/references/flag-glossary.md +417 -0
  171. package/plugins/sp/skills/spur-dev/references/gate-checklists.md +171 -0
  172. package/plugins/sp/skills/spur-dev/references/glossary.md +95 -0
  173. package/plugins/sp/skills/spur-dev/references/idea-evaluation.md +80 -0
  174. package/plugins/sp/skills/spur-dev/references/inline-pipeline-driver.md +120 -0
  175. package/plugins/sp/skills/spur-dev/references/planning-workflow.md +302 -0
  176. package/plugins/sp/skills/spur-dev/references/product-planning.md +206 -0
  177. package/plugins/sp/skills/spur-dev/references/section-batching.md +24 -0
  178. package/plugins/sp/skills/sys-architecture/SKILL.md +155 -0
  179. package/plugins/sp/skills/sys-architecture/references/decision-method.md +137 -0
  180. package/plugins/sp/skills/sys-architecture/references/upkeep-survey.md +75 -0
  181. package/plugins/sp/skills/sys-debugging/SKILL.md +228 -0
  182. package/plugins/sp/skills/sys-debugging/references/debugging-protocol.md +62 -0
  183. package/plugins/sp/skills/test-driven-development/SKILL.md +248 -0
  184. package/plugins/sp/skills/wayfinder/SKILL.md +292 -0
  185. package/spur.js +6035 -4963
@@ -0,0 +1,225 @@
1
+ ---
2
+ name: code-simplification
3
+ description: "Simplify code for clarity without changing behavior. Use when refactoring for readability or reducing complexity."
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: spur
7
+ version: "1.0"
8
+ platforms: "claude-code,codex,openclaw,opencode,antigravity"
9
+ category: execution
10
+ interactions:
11
+ - technique
12
+ operations:
13
+ - simplify
14
+ openclaw:
15
+ emoji: "🧹"
16
+ see_also:
17
+ - sp:code-review
18
+ - sp:code-implementation
19
+ - sp:test-driven-development
20
+ ---
21
+
22
+ # code-simplification — the simplification competency
23
+
24
+ Reduce complexity while preserving **exact** behavior. The goal is not fewer lines — it is code a
25
+ new reader understands faster. Every simplification must pass one test: *would a teammate understand
26
+ this version quicker than the original, and produce the same output for every input?* If either
27
+ answer is no, don't make the change.
28
+
29
+ This is a **technique** skill: it guides edits to source, it does not write task sections. When the
30
+ simplification lands inside a task, the `## Solution` change-map and status transitions stay with the
31
+ spine and `sp:code-implementation` — this skill owns *how to simplify well*.
32
+
33
+ ## When to use
34
+
35
+ - A feature works and tests pass, but the implementation reads heavier than it needs to.
36
+ - Review flagged readability or complexity (`sp:code-review` → this skill for the fix).
37
+ - Deep nesting, long functions, unclear names, or duplicated logic in code you just touched.
38
+ - Consolidating related logic that drifted apart under time pressure.
39
+
40
+ Do **not** use this skill for:
41
+
42
+ - **Already-clean code** — simplifying for its own sake is churn, not improvement.
43
+ - **Code you don't yet understand** — comprehend first (see Step 1); you cannot preserve behavior
44
+ you can't describe.
45
+ - **Hot paths where the simpler form is measurably slower** — clarity does not outrank a real,
46
+ measured performance requirement.
47
+ - **Throwaway code about to be rewritten** — simplifying code you're deleting wastes effort.
48
+
49
+ ## Five principles
50
+
51
+ 1. **Preserve behavior exactly.** Only how the code reads changes — never inputs, outputs, side
52
+ effects, error behavior, ordering, or edge cases. Unsure a change is behavior-preserving? Don't
53
+ make it. If a "simplification" needs a test edited to pass, you changed behavior — revert.
54
+ 2. **Follow project conventions.** Read `AGENTS.md` / `CLAUDE.md` and match neighboring code: import
55
+ style, declaration form, naming, error handling, type-annotation depth. Simplification that
56
+ breaks codebase consistency is churn, not simplification.
57
+ 3. **Prefer clarity over cleverness.** Explicit beats compact when the compact form needs a mental
58
+ pause to parse. A one-line nested ternary is not simpler than a five-line `if` chain.
59
+ 4. **Maintain balance.** Over-simplification is a real failure mode: don't inline a helper that gave
60
+ a concept a name, don't merge two clear functions into one tangled one, don't strip an abstraction
61
+ that earns its keep for testability or a second caller, and don't optimize for line count.
62
+ 5. **Scope to what changed** (R3 — surgical changes). Default to recently-modified code. No drive-by
63
+ refactors of unrelated code unless the operator widens the scope; unscoped edits create noisy
64
+ diffs and regressions in code you never meant to touch.
65
+
66
+ ## The process
67
+
68
+ ### Step 1 — Understand before touching (Chesterton's Fence)
69
+
70
+ Before changing or removing anything, know why it exists. Answer these; if you can't, read more
71
+ context first — you are not ready to simplify:
72
+
73
+ - What is this code's single responsibility? What calls it, and what does it call?
74
+ - What are its edge cases and error paths? Which tests pin the expected behavior?
75
+ - Why might it be shaped this way — a performance constraint, a platform quirk, a historical reason?
76
+ Check `git blame` / `git log` for the original context.
77
+
78
+ #### Over-Engineering Classifier & Reserved Pattern Audit
79
+
80
+ When encountering complex or indirect abstractions (factories, strategies, deep wrappers), classify them before acting:
81
+
82
+ 1. **Accidental LLM Over-Engineering**: Generic wrappers over single primitives, factory-for-a-factory, or single-implementation interfaces introduced during broad AI generation without sufficient local context.
83
+ 2. **Intentional Reserved Patterns**: Architectural extension points, framework contracts, or documented anchors reserved for upcoming roadmap features.
84
+
85
+ #### HITL Confirmation Gate for Over-Engineering Removal
86
+
87
+ If an abstraction appears to be accidental over-engineering:
88
+
89
+ ```text
90
+ IF abstraction has 0 callers or adds indirection without distinct value →
91
+ Formulate proposal:
92
+ - Target: file:line and symbol signature
93
+ - Reason: why it appears over-engineered
94
+ - Pros: reduced cognitive load, fewer lines, simpler debugging
95
+ - Cons / Risks: re-implementation cost if reserved for planned features
96
+ - Recommendation & Rationale: explicit recommendation (Remove vs Keep)
97
+ Present proposal to user → DO NOT delete until operator confirms.
98
+ ```
99
+
100
+ ### Step 2 — Identify opportunities
101
+
102
+ Each pattern below is a concrete signal, not a vague smell. Match against the target code.
103
+
104
+ **Structural complexity**
105
+
106
+ | Pattern | Signal | Move |
107
+ |---------|--------|------|
108
+ | Deep nesting (3+ levels) | Control flow hard to follow | Guard clauses / extracted helpers |
109
+ | Long function (50+ lines) | Multiple responsibilities | Split into focused, named functions |
110
+ | Nested ternaries | Needs a mental stack to parse | `if`/`else`, `switch`, or a lookup map |
111
+ | Boolean-flag params (`fn(true, false)`) | Opaque call sites | Options object or separate functions |
112
+ | Repeated conditional | Same check in many places | Extract a well-named predicate |
113
+
114
+ **Naming & readability**
115
+
116
+ | Pattern | Signal | Move |
117
+ |---------|--------|------|
118
+ | Generic names (`data`, `result`, `tmp`) | No intent conveyed | Rename for content (`userProfile`) |
119
+ | Misleading name | `get*` that also mutates | Rename to the real behavior |
120
+ | Comment restating the code | `// increment counter` over `count++` | Delete it |
121
+ | Comment carrying intent | `// retry: the API is flaky under load` | Keep it — the code can't say why |
122
+
123
+ **Redundancy & Over-engineering**
124
+
125
+ | Pattern | Signal | Move |
126
+ |---------|--------|------|
127
+ | Duplicated logic (local) | Same shape in 2+ places within scope | Extract local helper function |
128
+ | Duplicated logic (cross-module) | Common pattern across files | Follow 5-Stage Common Pattern Consolidation |
129
+ | Dead code | Unreachable branch, unused var, commented block | Remove after confirming it's dead |
130
+ | Pass-through wrapper | Adds indirection, no value | Inline it (after HITL confirmation) |
131
+ | Over-engineered pattern | Factory-for-a-factory, one-strategy strategy | Replace with direct approach (after HITL confirmation) |
132
+
133
+ #### 5-Stage Common Pattern Consolidation Protocol
134
+
135
+ When identical or structurally near-identical operations repeat across multiple locations:
136
+
137
+ 1. **Identify Candidate Patterns**: Locate repeated operations across files/modules within the allowed scope.
138
+ 2. **Operator Confirmation Gate**: Present proposed shared helper/utility signature, suggested module location (e.g. `utils/`, `helpers/`, or shared domain module), affected files/lines, and coupling trade-offs to the end user.
139
+ 3. **Implement Shared Unit**: After confirmation, author the shared helper/class in the appropriate shared location with dedicated unit tests in isolation.
140
+ 4. **Refactor Call-Sites**: Replace repeating logic site-by-site with invocations of the shared helper.
141
+ 5. **Regression Verification**: Run the project validation command (`--check <cmd>`) to verify all callers pass existing and unit tests cleanly.
142
+
143
+ A couple of stack-native examples (the discipline is stack-agnostic; these happen to be `bun:test` TS):
144
+
145
+ ```typescript
146
+ // nested conditionals → guard clauses (same behavior, shallower)
147
+ function process(data: Input) {
148
+ if (data == null) throw new TypeError('data is null');
149
+ if (!isValid(data)) throw new ValidationError('invalid data');
150
+ return doWork(data);
151
+ }
152
+
153
+ // manual accumulation → intent-revealing builtin
154
+ const activeUsers = users.filter((u) => u.isActive);
155
+
156
+ // redundant boolean round-trip
157
+ function isValid(input: string): boolean {
158
+ return input.length > 0 && input.length < 100;
159
+ }
160
+ ```
161
+
162
+ ### Step 3 — Apply incrementally
163
+
164
+ One simplification at a time. After each: run the **narrowest** test that covers it (`bun test <file>`
165
+ or the stack's equivalent). Passes → keep or continue; fails → revert that one change and reconsider.
166
+ Never batch untested simplifications — if something breaks you must know which change caused it.
167
+
168
+ **Separate refactoring from feature work.** A change that simplifies *and* adds behavior is two
169
+ changes; split them. **Rule of 500:** a refactor touching 500+ lines wants a codemod / AST transform,
170
+ not hand edits — manual work at that scale is error-prone and unreviewable.
171
+
172
+ ### Step 4 — Verify the result
173
+
174
+ Step back and judge the whole diff, not each edit:
175
+
176
+ - Is the result genuinely easier to understand, or just shorter?
177
+ - Did you introduce a pattern inconsistent with the codebase?
178
+ - Is the diff clean and reviewable, with nothing unrelated mixed in?
179
+
180
+ If the "simplified" version is harder to follow or review, revert it. Not every attempt succeeds, and
181
+ a failed simplification honestly reverted beats a clever one shipped.
182
+
183
+ ## Common Rationalizations
184
+
185
+ | Rationalization | Reality |
186
+ |---|---|
187
+ | "It works, don't touch it." | Working code that's hard to read is hard to fix when it breaks. The cost lands on every future change, not today. |
188
+ | "Fewer lines is always simpler." | Comprehension speed is the metric, not line count. A dense one-liner can be the harder version. |
189
+ | "I'll simplify this unrelated code too while I'm here." | Unscoped edits create noisy diffs and regressions in code you didn't mean to change. Stay in scope (R3). |
190
+ | "The original author must have had a reason." | Maybe — check `git blame` (Chesterton's Fence). But accumulated complexity often has no reason; it's residue of iteration under pressure. |
191
+ | "This abstraction might be useful later." | Speculative abstraction is complexity without a caller (R2). Remove it or confirm with operator; re-add when a second use actually arrives. |
192
+ | "I'll delete this generic wrapper immediately without asking." | Over-engineered abstractions may be intentional reserved patterns; classify and confirm with pros/cons/recommendation first. |
193
+ | "I'll refactor while I add this feature." | Mixed diffs are harder to review, revert, and read in history. Two changes, two commits. |
194
+ | "The types make it self-documenting." | Types document structure, not intent. A well-named function says *why* a signature can't. |
195
+
196
+ ## Red Flags
197
+
198
+ - Deleting an abstraction without checking if it's an intentional reserved pattern or confirming with the user.
199
+ - Extracting shared utilities across modules without operator confirmation or isolated unit tests.
200
+ - A simplification that required editing a test to pass — you changed behavior, not form.
201
+ - The "simplified" code is longer or harder to follow than the original.
202
+ - Renaming to your taste instead of the project's conventions.
203
+ - Removing error handling because it "makes the code cleaner."
204
+ - Simplifying code whose purpose you can't state in one sentence.
205
+ - Many simplifications batched into one large, un-testable commit.
206
+ - Refactoring outside the task's scope without being asked.
207
+
208
+ ## Verification
209
+
210
+ After a simplification pass, confirm — with evidence, not assertion:
211
+
212
+ - [ ] All existing tests pass **without modification** (paste the command + result).
213
+ - [ ] Potential over-engineering evaluated, classified, and confirmed with operator before removal.
214
+ - [ ] Common pattern extractions confirmed with operator, backed by isolated unit tests, and regression verified across call-sites.
215
+ - [ ] Build succeeds; lint/format clean (no style regressions).
216
+ - [ ] Each simplification is an incremental, reviewable change; the diff has nothing unrelated.
217
+ - [ ] The result follows project conventions (`AGENTS.md` / `CLAUDE.md`).
218
+ - [ ] No error handling was removed or weakened; no dead code left behind (unused imports, dead branches).
219
+ - [ ] A reviewer (`sp:code-review`) would call the change a net improvement.
220
+
221
+ ## See also
222
+
223
+ - **`sp:code-review`** — review the simplified diff; the review that flagged complexity hands the fix here.
224
+ - **`sp:code-implementation`** — the implement step that produced the code being simplified.
225
+ - **`sp:test-driven-development`** — the tests that pin behavior are the safety net that makes simplification safe.
@@ -0,0 +1,108 @@
1
+ ---
2
+ name: code-testing
3
+ description: "The testing competency — run tests, measure coverage, categorize gaps, extend the suite with targeted tests across Bun/TS, Python, Go. Triggers: \"write tests\", \"measure coverage\", \"what's untested\", \"coverage gap\", \"extend the test suite\", \"run the tests\"."
4
+ license: Apache-2.0
5
+ metadata:
6
+ author: spur
7
+ version: "1.0"
8
+ platforms: "claude-code,codex,openclaw,opencode,antigravity"
9
+ interactions:
10
+ - technique
11
+ competency: testing
12
+ openclaw:
13
+ emoji: "🧪"
14
+ ---
15
+
16
+ # code-testing — the testing competency
17
+
18
+ Run existing tests, measure what is covered, categorize the gaps, and extend the suite with targeted
19
+ tests — language-agnostic spine with per-stack adapters. This is the deep competency the
20
+ spine (`sp:spur-dev`) dispatches to at its `test` step (via `/sp:dev-unit`). It owns
21
+ *how to test and measure coverage well*, not *when* (the spine decides that).
22
+
23
+ ## When to use
24
+
25
+ - **Run + measure** — execute the suite, read the coverage report, identify untested paths.
26
+ - **Gap-fill** — add targeted tests to close a coverage gap on existing code.
27
+ - **The pipeline's `test` step** — `/sp:dev-unit <wbs>` dispatches here.
28
+
29
+ Do **not** use this skill for:
30
+
31
+ - **Writing the implementation** — that is `sp:code-implementation`.
32
+ - **Test-first design (red-green-refactor)** — that is `sp:test-driven-development` (composed with this skill).
33
+ - **Functional / requirements verification + review** — that is `sp:code-verification`.
34
+ - **Driving the lifecycle** — that is the spine, `sp:spur-dev`.
35
+
36
+ ## Behavior
37
+
38
+ This skill behaves as a **technique**: detect the stack → load the one matching adapter → run the
39
+ suite → parse coverage → categorize gaps (untested branch, missing boundary, absent error path) →
40
+ extend with the narrowest tests that close the highest-value gaps. Coverage is a signal, not the
41
+ goal: it favors behavior-meaningful tests over line-chasing.
42
+
43
+ Full procedure: **[references/unit-testing.md](references/unit-testing.md)** — file-focused vs
44
+ task-scoped workflows, gap categorization, coverage-vs-quality rules, escalation. Per-stack
45
+ mechanics (commands, coverage parsing, idioms, gotchas) live in the adapters:
46
+ [references/stacks/](references/stacks/) — `bun-ts.md`, `python.md`, `go.md`.
47
+
48
+ When a test is red, apply the **[test-loop breaker](references/test-loop-breaker.md)** before
49
+ re-running it. Keep command output bounded without hiding the exit status by following
50
+ **[test-output discipline](references/test-output-discipline.md)**.
51
+
52
+ ## Targeted-test-first verification loop
53
+
54
+ When iterating on a red test, run the **narrow** target before any full-suite gate so the loop does
55
+ not re-run the entire workspace on every attempt (task 0436 R2). Full-suite re-runs during a fix
56
+ loop are the dominant verification cost on a long chain.
57
+
58
+ 1. Run the narrow target: `bun test <file> --test-name-pattern <test>` (or the stack-equivalent
59
+ single-test filter in the matching adapter).
60
+ 2. Loop on that narrow target until green.
61
+ 3. **Then** run the single full `spur-check` (or `bun run check`) as the final gate.
62
+
63
+ Do not re-run the full suite per iteration, and do not run a full gate before the narrow target is
64
+ green. Target: full `spur-check` runs ≤2 per task.
65
+
66
+ ## Composition with the discipline + implementation skills
67
+
68
+ - **`sp:test-driven-development`** — they compose: TDD *designs* the tests (red-green-refactor, behavior naming,
69
+ mock-at-boundary); this skill *runs and extends* the suite for coverage. TDD is the how-to-design;
70
+ this skill is the run/measure/gap-fill.
71
+ - **`sp:code-implementation`** — the implement step writes code; this step proves it. The per-stack
72
+ adapters here are also the stack-idiom reference `code-implementation` consults cross-skill.
73
+
74
+ ## Per-stack adapters
75
+
76
+ | Detected by | Stack | Adapter |
77
+ |-------------|-------|---------|
78
+ | `bun.lock` / `bunfig.toml` | Bun + TypeScript | [stacks/bun-ts.md](references/stacks/bun-ts.md) |
79
+ | `pyproject.toml` / `pytest` | Python | [stacks/python.md](references/stacks/python.md) |
80
+ | `go.mod` | Go | [stacks/go.md](references/stacks/go.md) |
81
+
82
+ ## Gotchas
83
+
84
+ 1. **Coverage is a signal, not the target.** A test that survives a business-rule change is the
85
+ wrong test — assert intent, not implementation.
86
+ 2. **One adapter per run.** Detect the stack, load the single matching adapter; do not mix idioms.
87
+ 3. **Escalate to debugging when a failure needs root-causing**, not more test authoring
88
+ (`sp:code-implementation`'s debugging reference).
89
+
90
+ ## See also
91
+
92
+ - **`sp:spur-dev`** — the spine that dispatches this competency at the `test` step.
93
+ - **`sp:code-implementation`** — writes the code this skill tests; consults these stack adapters.
94
+ - **`sp:test-driven-development`** — the test-first discipline this skill composes with.
95
+ - **`sp:code-verification`** — functional/requirements verification + review (a distinct gate).
96
+ - **[Verification Before Completion](../spur-dev/references/cross-cutting.md#verification-before-completion)** — no "coverage met / tests pass" claim without fresh, pasted evidence run this turn.
97
+
98
+ ## Platform Notes
99
+
100
+ ### Claude Code
101
+
102
+ Invoked via `/sp:dev-unit <wbs>` (which the pipeline's `test` step calls), or directly via
103
+ `Skill(skill="sp:code-testing", args="<target>")`. Run the test/coverage commands via the Bash tool.
104
+
105
+ ### Codex / OpenClaw / OpenCode / Antigravity
106
+
107
+ Invoke this skill directly for testing technique; run the stack's test commands via the Bash tool.
108
+ The skill is the SSOT; the command and pipeline step are thin wrappers.
@@ -0,0 +1,165 @@
1
+ ---
2
+ name: stacks/bun-ts
3
+ description: "Stack adapter for Bun + TypeScript (and Node/TS) — test command, V8 coverage parsing, the V8 coverage-gap diagnostic, framework idioms. Loaded by unit-testing.md when the project uses bun/vitest/jest."
4
+ see_also:
5
+ - unit-testing
6
+ ---
7
+
8
+ # Stack adapter: Bun + TypeScript
9
+
10
+ Mechanics for the [unit-testing.md](../unit-testing.md) spine when the project is Bun/TS (or Node/TS).
11
+ The spine owns the procedure; this file owns Bun/TS commands, parsing, idioms, and gotchas.
12
+
13
+ ## Test + coverage command
14
+
15
+ ```bash
16
+ bun test --coverage
17
+ ```
18
+
19
+ Bun reports per-file `% Funcs` and `% Lines` (V8 coverage):
20
+
21
+ ```
22
+ File | % Funcs | % Lines | Uncovered Line #s
23
+ --------------|---------|---------|------------------
24
+ auth.ts | 80.00 | 92.31 | 23-27
25
+ --------------|---------|---------|------------------
26
+ All files | 77.00 | 90.48 |
27
+ ```
28
+
29
+ Spur target: **per-file line ≥ 90% and function ≥ 90%** (`bunfig.toml`), suite fully passing.
30
+
31
+ ## Test-file convention
32
+
33
+ Tests live in `<workspace>/tests/**/*.test.ts` next to the code (AGENTS.md). Use `bun:test`
34
+ (`import { test, expect, describe } from "bun:test"`). For a loose source file with no test, create
35
+ `tests/<name>.test.ts`.
36
+
37
+ ## Idioms
38
+
39
+ **Branch / parameterized tests** — one test per branch:
40
+
41
+ ```typescript
42
+ import { test, expect } from 'bun:test';
43
+
44
+ for (const [user, amount, expected] of [
45
+ ['vip', 150, 120],
46
+ ['vip', 50, 45],
47
+ ['regular', 100, 100],
48
+ ] as const) {
49
+ test(`discount: ${user} on ${amount} → ${expected}`, () => {
50
+ expect(calculateDiscount(makeUser(user), amount)).toBe(expected);
51
+ });
52
+ }
53
+ ```
54
+
55
+ **Mock at the boundary** — inject the dependency; do not mock internal collaborators:
56
+
57
+ ```typescript
58
+ test('fetchUser returns null on 404', async () => {
59
+ const result = await fetchUser(999, async () => ({ status: 404 }));
60
+ expect(result).toBeNull();
61
+ });
62
+ ```
63
+
64
+ **Inline coverage-exclusion rationale** (the accept-lower-coverage case):
65
+
66
+ ```typescript
67
+ // NOTE: unreachable in production — the adapter guarantees a non-null row here.
68
+ if (row == null) throw new Error('unreachable: adapter contract violated');
69
+ ```
70
+
71
+ ## Coverage-gap diagnostic (V8)
72
+
73
+ Bun uses V8 function coverage, which produces artifacts that look like missing tests but are
74
+ instrumentation/code-structure issues. **Rule these out before writing tests** — otherwise you write
75
+ tests that cannot move the metric.
76
+
77
+ | Symptom | Likely cause | Fix |
78
+ |---------|-------------|-----|
79
+ | `% Funcs` < threshold while `% Lines` ≥ threshold; child classes show "uncovered" | Implicit/synthetic constructor on a class that `extends` without an explicit `constructor()` | Add an explicit empty constructor with the sanctioned suppression (snippet 1) |
80
+ | `% Funcs` < threshold; flagged functions are module-level arrows never called directly | Anonymous/unused arrow at module scope counted as an uncovered function | `export` the arrow as a named pure function and test it, or inline it (snippet 2) |
81
+ | Coverage swings between runs; some files missing from the report entirely | File never imported by any test path, so V8 doesn't see it | Ensure the test (or a barrel imported by the test) statically imports every target module (snippet 3) |
82
+ | Worker/temp paths in coverage output; `coverageExclude` in `bunfig.toml` has no effect | Dynamic `import()` spawns a worker; V8 tracks worker coverage globally and ignores `coverageExclude` | Prefer a mock module-loader over real `import()`; if required, clean up in `afterAll` and accept temp paths when failures == 0 (snippet 4) |
83
+
84
+ ### Snippet 1 — explicit empty constructor
85
+
86
+ ```typescript
87
+ class Derived extends Base {
88
+ // biome-ignore lint/complexity/noUselessConstructor: V8 function coverage requires explicit constructor
89
+ constructor() {
90
+ super();
91
+ }
92
+ }
93
+ ```
94
+
95
+ This is the **only** sanctioned use of `biome-ignore lint/complexity/noUselessConstructor` in this
96
+ project. Do not generalize it.
97
+
98
+ ### Snippet 2 — promote module-level arrows
99
+
100
+ ```typescript
101
+ // Before: anonymous arrow at module scope, counted as an uncovered function
102
+ const transform = (x: number) => x * 2;
103
+ export function run(input: number[]) { return input.map(transform); }
104
+
105
+ // After option A: export the pure function and test it directly
106
+ export const transform = (x: number) => x * 2;
107
+
108
+ // After option B: inline into the only caller, removing the module-level entry point
109
+ export function run(input: number[]) {
110
+ return input.map((x) => x * 2);
111
+ }
112
+ ```
113
+
114
+ ### Snippet 3 — ensure targets are loaded
115
+
116
+ ```typescript
117
+ // In a test entry or a barrel imported by tests
118
+ import '../src/foo';
119
+ import '../src/bar';
120
+ import '../src/baz';
121
+ // Or maintain src/index.ts re-exporting everything, then `import '../src'` once.
122
+ ```
123
+
124
+ V8 only counts files that are actually loaded. A barrel is the lowest-maintenance way to cover the
125
+ whole module surface.
126
+
127
+ ### Snippet 4 — avoid the `import()` worker leak
128
+
129
+ ```typescript
130
+ // Prefer: inject a loader so production code uses import() but tests use a mock
131
+ type Loader = (id: string) => Promise<unknown>;
132
+ export async function loadAndRun(id: string, load: Loader = (i) => import(i)) {
133
+ return load(id);
134
+ }
135
+
136
+ // In tests, pass a mock loader — no real import(), no worker thread
137
+ test('loadAndRun uses the injected loader', async () => {
138
+ const result = await loadAndRun('ignored', async () => ({ ok: true }));
139
+ expect(result).toEqual({ ok: true });
140
+ });
141
+ ```
142
+
143
+ If real `import()` cannot be avoided: place teardown in `afterAll` (not `afterEach`) and treat temp
144
+ paths in the coverage output as benign when the suite reports `0` failures.
145
+
146
+ ### When to escalate instead of patch
147
+
148
+ - The diagnostic matches no symptom in the table → escalate (spine § Escalation).
149
+ - Applying the matching fix moves the metric < 1% → likely a different root cause; escalate to debugging.
150
+ - The fix would require disabling type/lint checks beyond snippet 1's sanctioned suppression → stop
151
+ and surface to the operator.
152
+
153
+ ## Node + TypeScript/JS (Vitest / Jest)
154
+
155
+ When the project is Node-based (no `bun.lock`) the spine is identical; only the command and reporter
156
+ change.
157
+
158
+ | Framework | Command | Coverage report |
159
+ |-----------|---------|-----------------|
160
+ | Vitest | `npx vitest run --coverage` | `% Stmts / % Branch / % Funcs / % Lines` table (istanbul or v8 provider) |
161
+ | Jest | `npx jest --coverage` | same table shape |
162
+
163
+ Vitest with the `v8` provider shares the V8 gotchas above (synthetic constructors, module loading).
164
+ With the istanbul provider, branch coverage is reported directly — prefer it for branch-sensitive
165
+ code. Test files: `*.test.ts` / `*.spec.ts` per the project's existing convention.
@@ -0,0 +1,88 @@
1
+ ---
2
+ name: stacks/go
3
+ description: "Stack adapter for Go — go test coverprofile command, per-function coverage parsing, table-driven test and interface-mocking idioms. Loaded by unit-testing.md for go.mod projects."
4
+ see_also:
5
+ - unit-testing
6
+ ---
7
+
8
+ # Stack adapter: Go
9
+
10
+ Mechanics for the [unit-testing.md](../unit-testing.md) spine when the project is Go.
11
+
12
+ ## Test + coverage command
13
+
14
+ ```bash
15
+ go test -v ./... # run + interpret
16
+ go test -coverprofile=coverage.out ./... && \
17
+ go tool cover -func=coverage.out # per-function coverage
18
+ ```
19
+
20
+ `-func` output lists per-function and total coverage:
21
+
22
+ ```
23
+ spur/internal/auth/auth.go:21: ValidateEmail 100.0%
24
+ spur/internal/auth/auth.go:42: Login 66.7%
25
+ total: (statements) 88.4%
26
+ ```
27
+
28
+ Use the per-function column to target the lowest-covered functions first. `go tool cover
29
+ -html=coverage.out` opens a line-level view for pinpointing branches.
30
+
31
+ ## Test-file convention
32
+
33
+ Tests live beside the code as `<name>_test.go` in the same package. Use the standard `testing`
34
+ package; no external runner.
35
+
36
+ ## Idioms
37
+
38
+ **Table-driven tests** — the canonical Go pattern; one row per branch/edge:
39
+
40
+ ```go
41
+ func TestValidateEmail(t *testing.T) {
42
+ tests := []struct {
43
+ name string
44
+ email string
45
+ wantErr bool
46
+ }{
47
+ {"valid standard", "user@example.com", false},
48
+ {"missing @", "userexample.com", true},
49
+ {"empty", "", true},
50
+ }
51
+ for _, tt := range tests {
52
+ t.Run(tt.name, func(t *testing.T) {
53
+ if err := ValidateEmail(tt.email); (err != nil) != tt.wantErr {
54
+ t.Errorf("ValidateEmail(%q) err = %v, wantErr %v", tt.email, err, tt.wantErr)
55
+ }
56
+ })
57
+ }
58
+ }
59
+ ```
60
+
61
+ **Mock at the boundary via interfaces** — inject a fake implementing the dependency interface:
62
+
63
+ ```go
64
+ func TestCreateUser_setsID(t *testing.T) {
65
+ repo := &MockRepository{SaveFunc: func(u *User) error { u.ID = 123; return nil }}
66
+ if err := NewUserService(repo).CreateUser(&User{Name: "Test"}); err != nil {
67
+ t.Fatalf("CreateUser() err = %v", err)
68
+ }
69
+ }
70
+ ```
71
+
72
+ **Inline coverage-exclusion rationale** — Go has no built-in line-exclusion pragma; document the
73
+ unreachable branch in a comment and exclude the file/function at the report level if needed:
74
+
75
+ ```go
76
+ // unreachable in production: the adapter guarantees a non-nil row here.
77
+ if row == nil {
78
+ panic("unreachable: adapter contract violated")
79
+ }
80
+ ```
81
+
82
+ ## Notes
83
+
84
+ - Go reports **statement** coverage, not branch coverage — a fully-covered statement count can still
85
+ miss a branch. For branch-sensitive logic, ensure the table has a row per branch and read the
86
+ `-html` view to confirm both sides of each conditional are green.
87
+ - Generated code (protobuf, mocks) is conventionally excluded by build tag or a `//go:generate`
88
+ boundary; do not chase coverage on it.