specpipe 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +1319 -0
  2. package/bin/devkit.js +3 -0
  3. package/package.json +61 -0
  4. package/src/cli.js +76 -0
  5. package/src/commands/check.js +33 -0
  6. package/src/commands/diff.js +84 -0
  7. package/src/commands/init-adopt.js +54 -0
  8. package/src/commands/init-agents.js +118 -0
  9. package/src/commands/init-global.js +102 -0
  10. package/src/commands/init.js +311 -0
  11. package/src/commands/list.js +54 -0
  12. package/src/commands/remove.js +133 -0
  13. package/src/commands/upgrade.js +215 -0
  14. package/src/lib/agent-guards.js +100 -0
  15. package/src/lib/agent-install.js +161 -0
  16. package/src/lib/agents.js +280 -0
  17. package/src/lib/claude-global.js +183 -0
  18. package/src/lib/detector.js +93 -0
  19. package/src/lib/hasher.js +21 -0
  20. package/src/lib/installer.js +213 -0
  21. package/src/lib/logger.js +16 -0
  22. package/src/lib/manifest.js +102 -0
  23. package/src/lib/reconcile.js +56 -0
  24. package/templates/.claude/CLAUDE.md +79 -0
  25. package/templates/.claude/hooks/comment-guard.js +126 -0
  26. package/templates/.claude/hooks/file-guard.js +216 -0
  27. package/templates/.claude/hooks/glob-guard.js +104 -0
  28. package/templates/.claude/hooks/path-guard.sh +118 -0
  29. package/templates/.claude/hooks/self-review.sh +27 -0
  30. package/templates/.claude/hooks/sensitive-guard.sh +227 -0
  31. package/templates/.claude/settings.json +68 -0
  32. package/templates/docs/WORKFLOW.md +325 -0
  33. package/templates/docs/specs/.gitkeep +0 -0
  34. package/templates/hooks/specpipe-read-guard.sh +42 -0
  35. package/templates/hooks/specpipe-shell-guard.sh +65 -0
  36. package/templates/rules/specpipe-guards.md +40 -0
  37. package/templates/scripts/test-hooks.sh +66 -0
  38. package/templates/skills/sp-build/SKILL.md +776 -0
  39. package/templates/skills/sp-challenge/SKILL.md +255 -0
  40. package/templates/skills/sp-commit/SKILL.md +174 -0
  41. package/templates/skills/sp-explore/SKILL.md +730 -0
  42. package/templates/skills/sp-fix/SKILL.md +266 -0
  43. package/templates/skills/sp-humanize/SKILL.md +212 -0
  44. package/templates/skills/sp-investigate/SKILL.md +648 -0
  45. package/templates/skills/sp-md-render/SKILL.md +200 -0
  46. package/templates/skills/sp-md-render/components.md +415 -0
  47. package/templates/skills/sp-md-render/template.html +283 -0
  48. package/templates/skills/sp-plan/SKILL.md +947 -0
  49. package/templates/skills/sp-review/SKILL.md +268 -0
  50. package/templates/skills/sp-scaffold/SKILL.md +237 -0
  51. package/templates/skills/sp-scaffold/references/ARCHITECTURE.md.tmpl +228 -0
  52. package/templates/skills/sp-scaffold/references/DESIGN.md.tmpl +113 -0
  53. package/templates/skills/sp-scaffold/references/adr/NNNN-template.md +92 -0
  54. package/templates/skills/sp-scaffold/references/stack-profiles/react.md +36 -0
  55. package/templates/skills/sp-spec-render/SKILL.md +254 -0
  56. package/templates/skills/sp-spec-render/components.md +418 -0
  57. package/templates/skills/sp-spec-render/examples/user-auth.html +749 -0
  58. package/templates/skills/sp-spec-render/examples/user-auth.md +114 -0
  59. package/templates/skills/sp-spec-render/template.html +222 -0
  60. package/templates/skills/sp-voices/SKILL.md +1184 -0
@@ -0,0 +1,648 @@
1
+ ---
2
+ description: Read-only root-cause investigation — OPTIONAL branch before /sp-fix. Produces an investigation report with potential root cause hypotheses, evidence, blast radius — no code changes. Use when bug is complex, ambiguous, production-critical, or user explicitly wants to diagnose before fixing (outage, data corruption, regression, unclear stack trace, "it was working yesterday"). Skip for trivial bugs — go straight to /sp-fix. Writes docs/investigate/<slug>-YYYY-MM-DD.md and hands off to /sp-fix.
3
+ allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion, mcp__graphatlas__*
4
+ ---
5
+ Deep investigation — find root cause, map blast radius, report without changing code.
6
+
7
+ Target: $ARGUMENTS
8
+
9
+ ---
10
+
11
+ ## Scope
12
+
13
+ This skill **investigates only**. It does not write tests, fix code, or edit any file.
14
+
15
+ Output: a structured report with root cause hypothesis, evidence, blast radius,
16
+ and actionable next steps for whoever will fix it (human or `/sp-fix`).
17
+
18
+ ```
19
+ Allowed: Read, Grep, Glob, Bash (read-only: git log, git diff, git blame, find, cat, wc, etc.)
20
+ Write — ONLY to docs/investigate/<slug>-<date>.md (the handoff report)
21
+ Blocked: Edit (any existing file), Write outside docs/investigate/,
22
+ Bash (any command that modifies source/config/data, installs packages, or touches shared state)
23
+ ```
24
+
25
+ ## Adaptive Depth
26
+
27
+ This skill auto-scales based on what it finds. No upfront mode selection needed.
28
+
29
+ ```
30
+ Context signal (from $ARGUMENTS):
31
+ - Mentions "production", "outage", "data loss", "corruption"
32
+ → bias toward deeper investigation, full blast radius
33
+ - Mentions "UI", "minor", "cosmetic", "styling"
34
+ → bias toward early exit once root cause is clear
35
+
36
+ Phase 2 (Locate) finds root cause with HIGH confidence?
37
+ → Skip Phase 3 (pattern match)
38
+ → Jump to Phase 4 (form hypothesis) → Phase 5 (blast radius) → report
39
+ → Investigation naturally short (~5 min)
40
+
41
+ Phase 2 unclear, Phase 3 pattern match helps?
42
+ → Standard depth
43
+ → Investigation ~10-15 min
44
+
45
+ Phase 3 also unclear, 3-strike rule hit?
46
+ → Report INSUFFICIENT_EVIDENCE with everything gathered
47
+ → Don't spin past 15 min total
48
+
49
+ Impact is clearly ISOLATED (1 function, ≤2 callers)?
50
+ → Phase 5 simplified: skip diagram, list direct impacts only
51
+
52
+ Impact is MODULE or wider?
53
+ → Phase 5 full: diagram + blast radius + similar risk scan
54
+ ```
55
+
56
+ **Soft timebox guidance:** If stuck > 5 min on any single phase → consider moving
57
+ to next phase with partial findings. Don't let one phase consume the entire budget.
58
+
59
+ ---
60
+
61
+ ## Iron Law
62
+
63
+ **Follow the evidence. Never start with a theory.**
64
+
65
+ Premature hypotheses cause tunnel vision. Gather facts first, then form a theory that explains ALL facts — not just the convenient ones.
66
+
67
+ ---
68
+
69
+ ## Phase 0a — Graphatlas probe (run once, silently)
70
+
71
+ Before Phase 1, probe whether graphatlas (GA) is connected:
72
+
73
+ 1. Call `mcp__graphatlas__ga_architecture` with `max_modules: 1`.
74
+ 2. Interpret:
75
+ - Returns `modules` → **GA available.** Use `ga_*` for every locate / blast-radius step below. Grep is fallback.
76
+ - Error `STALE_INDEX` → call `mcp__graphatlas__ga_reindex` (mode `"full"`), retry once, then treat as available. (This skill is read-only, so no further reindex is needed during the run.)
77
+ - Tool not found / connection error / any other failure → **GA unavailable.** Use grep/glob throughout. Do not re-probe.
78
+ 3. Carry the outcome through Phases 1-5.
79
+
80
+ ---
81
+
82
+ ## Phase 1: Understand the Report
83
+
84
+ Parse what you're given. Clarify what you're not.
85
+
86
+ **Extract these from `$ARGUMENTS`:**
87
+
88
+ | Field | Required | If Missing |
89
+ |-------|----------|------------|
90
+ | Symptom | Yes | Cannot proceed — ask |
91
+ | Expected behavior | Yes | Cannot proceed — ask |
92
+ | Actual behavior | Yes | Cannot proceed — ask |
93
+ | Repro steps | Helpful | Attempt to infer from code; flag as assumption |
94
+ | Environment | Helpful | Assume production-like; flag as assumption |
95
+ | Frequency | Helpful | Assume consistent; flag if intermittent evidence found |
96
+
97
+ If 2+ required fields are missing → ask ONE question via `AskUserQuestion`:
98
+
99
+ ```json
100
+ {
101
+ "questions": [{
102
+ "question": "I need more context to investigate. What's happening?",
103
+ "header": "Bug context",
104
+ "multiSelect": false,
105
+ "options": [
106
+ {"label": "Describe behavior", "description": "What did you expect vs what actually happened"},
107
+ {"label": "Paste error", "description": "Error message, stack trace, or screenshot description"},
108
+ {"label": "Point to code", "description": "Specific file, function, or feature area to investigate"}
109
+ ]
110
+ }]
111
+ }
112
+ ```
113
+
114
+ **Do NOT proceed past Phase 1 without clear symptom + expected + actual.**
115
+
116
+ ---
117
+
118
+ ## Phase 2: Locate
119
+
120
+ Find where the bug lives. Work from the outside in.
121
+
122
+ ### 2.1 — Entry Point Search
123
+
124
+ Start with the most specific artifact available, in priority order:
125
+
126
+ | Have This? | Search Strategy |
127
+ |------------|----------------|
128
+ | Error message / stack trace | Grep exact error string → follow call stack |
129
+ | Function or class name | Grep definition → read implementation |
130
+ | Feature/screen name | Grep for route/handler/view name → trace to logic |
131
+ | Only vague description | Grep keywords → read surrounding code → narrow |
132
+
133
+ > **If GA available (per Phase 0a):** `ga_symbols("<function or type>")` for definitions (ranked by caller count — picks the popular def when names collide), then `ga_callers` / `ga_callees` to map the call graph; `ga_impact(symbol=...)` for a whole-feature view. **If GA unavailable, or the query is free-text error string inside a literal:** use the grep recipes below.
134
+
135
+ ```bash
136
+ # Extension set covers ~90% of mainstream code:
137
+ # JS/TS family, Python, Ruby, Go, Rust, Java/Kotlin/Scala/Groovy, Swift/ObjC,
138
+ # C/C++/C#, PHP, Dart, Elixir, Erlang, Haskell, Clojure, Elm, R, Julia,
139
+ # Zig, Nim, PowerShell, shell, SQL, web templates
140
+ EXT='*.{js,jsx,ts,tsx,mjs,cjs,vue,svelte,py,rb,go,rs,java,kt,kts,scala,groovy,swift,m,mm,c,cc,cpp,cxx,h,hh,hpp,cs,php,dart,lua,ex,exs,erl,hs,clj,cljs,elm,r,jl,zig,nim,ps1,sh,bash,zsh,sql,erb,html}'
141
+
142
+ # Error message → find origin
143
+ grep -rn "exact error text" --include="$EXT" .
144
+
145
+ # Function → find definition + callers
146
+ grep -rn "function_name" --include="$EXT" .
147
+
148
+ # Feature → find entry point
149
+ grep -rn "route\|handler\|endpoint\|view.*FeatureName" .
150
+ ```
151
+
152
+ ### 2.2 — Check for Recurring Bugs
153
+
154
+ Before diving deep, check if this area has a history of bugs:
155
+
156
+ ```bash
157
+ # How often has this file been fixed?
158
+ git log --oneline --all -- <affected-file> | grep -i "fix\|bug\|patch\|hotfix" | head -10
159
+
160
+ # How many authors have touched this file recently?
161
+ git shortlog -sn --since="6 months ago" -- <affected-file>
162
+ ```
163
+
164
+ **Recurring bug signal:** If the same file/module shows 3+ bug-fix commits targeting the **same function or same bug pattern** in recent history → this is likely an **architectural smell**, not a one-off bug. Flag this:
165
+
166
+ ```
167
+ ⚠️ RECURRING BUG AREA: <file:function> has N fix commits in last M months
168
+ Pattern: <what keeps breaking — same null check? same race? same state issue?>
169
+ Implication: root cause may be structural (wrong abstraction, missing invariant,
170
+ unclear ownership) rather than a simple code error
171
+ ```
172
+
173
+ Note: 3 fixes in the same FILE but targeting completely different functions/concerns
174
+ is normal churn, not a smell. The signal is repeated fixes for the SAME pattern.
175
+
176
+ ### 2.3 — Trace the Data Flow
177
+
178
+ Starting from the entry point, trace forward through the code:
179
+
180
+ ```
181
+ INPUT → Where does the data enter?
182
+ → TRANSFORM → What functions process it?
183
+ → DECISION → What branches/conditions control flow?
184
+ → OUTPUT → Where does the result surface to the user?
185
+ → SIDE EFFECTS → What else happens? (DB write, cache update, event emit)
186
+ ```
187
+
188
+ At each step, note:
189
+ - What type is the data? Can it be null/nil/None/undefined here?
190
+ - What assumptions does this code make about its input?
191
+ - Are there error paths? Do they swallow errors silently?
192
+
193
+ **Tentative hypotheses are fine.** You will naturally form theories while tracing.
194
+ That's good — note them. But don't commit to a hypothesis until the full causal chain
195
+ (location → mechanism → symptom) is verified with code evidence. The Iron Law says
196
+ "follow evidence first" — not "suppress all intuition."
197
+
198
+ ### 2.4 — Check History
199
+
200
+ ```bash
201
+ # Recent changes to affected files
202
+ git log --oneline -20 -- <affected-files>
203
+
204
+ # What changed in the last commit that touched this file?
205
+ git log -1 -p -- <affected-file>
206
+
207
+ # When was this line last changed? By whom?
208
+ git blame -L <start>,<end> -- <affected-file>
209
+
210
+ # Was this file recently refactored?
211
+ git log --oneline --diff-filter=M -10 -- <affected-file>
212
+ ```
213
+
214
+ **Regression signal:** If the behavior worked before and a recent commit changed the affected code → the bug is likely in that diff. Flag this:
215
+ ```
216
+ ⚠️ REGRESSION SIGNAL: <commit-hash> (<date>) — <commit message>
217
+ Changed: <file:lines>
218
+ Before: <old behavior>
219
+ After: <new behavior>
220
+ ```
221
+
222
+ ---
223
+
224
+ ## Phase 3: Pattern Match (when needed)
225
+
226
+ **Skip this phase if:** Phase 2 already produced a HIGH confidence hypothesis
227
+ with complete causal chain (location + mechanism + evidence). Jump to Phase 4.
228
+
229
+ **Use this phase when:**
230
+ - Symptom is unclear or ambiguous
231
+ - Data flow trace didn't reveal obvious cause
232
+ - Investigation is stuck — need a framework to think through
233
+ - Bug is non-obvious or intermittent
234
+
235
+ Match the observed symptom against known bug patterns.
236
+ Don't mechanically check every row — scan for patterns that FIT the evidence you have.
237
+
238
+ | # | Pattern | Signature | Investigation Steps |
239
+ |---|---------|-----------|-------------------|
240
+ | 1 | **Nil/null propagation** | TypeError, NullPointerException, "undefined is not a function", unwrap on None | Trace value backwards from crash site → find where it becomes nil. Check: is there a guard? Is the guard in the wrong place? |
241
+ | 2 | **Race condition** | Intermittent, timing-dependent, "works locally", flaky test | Find shared mutable state. Check: multiple concurrent accessors? Missing lock/mutex/actor isolation? |
242
+ | 3 | **State corruption** | Inconsistent data, partial update visible, "impossible" state | Find state mutation points. Check: transaction boundary? Cleanup after error? Multiple writers? |
243
+ | 4 | **Off-by-one / boundary** | Wrong count, missing last item, extra item, index out of bounds | Find loop/slice/range. Check: `<` vs `<=`? 0-indexed vs 1-indexed? Empty collection handled? |
244
+ | 5 | **Type coercion / cast** | Wrong value type, unexpected string "null", NaN, "0" vs 0 | Find type boundaries (JSON parse, DB query, API response). Check: implicit conversion? Missing validation? |
245
+ | 6 | **Stale data** | Shows old data, fixes on refresh/restart, cache-related | Find cache layers (memory, Redis, CDN, browser). Check: invalidation after write? TTL too long? |
246
+ | 7 | **Configuration drift** | Works locally, fails in staging/prod | Compare env vars, feature flags, DB schema, API versions across environments |
247
+ | 8 | **Silent error swallow** | No error shown but wrong behavior | Grep for empty catch blocks, `_ =`, `catch {}`, `.catch(() => {})`. Check: error logged but not propagated? |
248
+ | 9 | **Ordering / timing** | Depends on execution order, async operations complete out of order | Find async operations. Check: await missing? Race between promises/tasks? Event ordering assumed? |
249
+ | 10 | **Resource leak** | Gradually degrades, OOM, connection pool exhausted, file descriptor limit | Find open/acquire without close/release. Check: error path also closes? Loop creates without releasing? |
250
+ | 11 | **Incorrect merge / conflict resolution** | Bug appears after merge, code has conflicting logic | `git log --merges -5 -- <file>`. Check: merge conflict resolved incorrectly? Both sides kept when one should win? |
251
+ | 12 | **API contract mismatch** | Caller sends X, receiver expects Y | Find both sides of the boundary. Check: field names match? Types match? Optional vs required? |
252
+
253
+ For each matching pattern, record:
254
+ ```
255
+ PATTERN MATCH: #N <name>
256
+ Evidence: <specific code/log that matches this pattern>
257
+ Confidence: HIGH / MEDIUM / LOW
258
+ ```
259
+
260
+ ### External Search (when no pattern matches)
261
+
262
+ If the bug doesn't match any known pattern above, and the error message or behavior
263
+ is unfamiliar, search externally:
264
+
265
+ ```
266
+ Search: "{framework} {sanitized error type}"
267
+ Search: "{library} {component} known issues"
268
+ ```
269
+
270
+ **⚠️ SANITIZE BEFORE SEARCHING:**
271
+ Strip from the error message before using as search query:
272
+ - Hostnames, IPs, internal URLs
273
+ - File paths containing usernames or project names
274
+ - SQL fragments, query parameters
275
+ - Customer data, user IDs, email addresses
276
+ - API keys, tokens, secrets (obviously)
277
+
278
+ Search the **generic error type and framework context**, not the raw message.
279
+
280
+ If search reveals a documented bug or known issue → record as a candidate hypothesis
281
+ in Phase 4 with source link.
282
+
283
+ ---
284
+
285
+ ## Phase 4: Form Hypothesis
286
+
287
+ Based on evidence from Phases 2-3, form a **specific, testable** hypothesis.
288
+
289
+ ### Requirements for a Valid Hypothesis
290
+
291
+ ```
292
+ A valid hypothesis MUST:
293
+ ✓ Name a specific location (file:line or function)
294
+ ✓ Describe WHAT is wrong (the mechanism)
295
+ ✓ Explain WHY it produces the observed symptom
296
+ ✓ Be falsifiable (describe what evidence would DISPROVE it)
297
+
298
+ A hypothesis MUST NOT:
299
+ ✗ Be vague ("something is wrong with the cache")
300
+ ✗ Name a symptom as a cause ("it crashes because of a null pointer")
301
+ → WHY is the pointer null?
302
+ ✗ Require assumptions not grounded in code evidence
303
+ ```
304
+
305
+ ### Format
306
+
307
+ ```
308
+ HYPOTHESIS
309
+ ══════════
310
+ Location: <file:line or file:function>
311
+ Mechanism: <what is going wrong, mechanically>
312
+ Chain: <input> → <step 1> → <step 2> → ... → <symptom>
313
+ Disproof: <what evidence would prove this wrong>
314
+ Confidence: HIGH / MEDIUM / LOW
315
+ Basis: <list evidence that supports this>
316
+ ```
317
+
318
+ ### Confidence Levels
319
+
320
+ | Level | Definition | Threshold |
321
+ |-------|-----------|-----------|
322
+ | **HIGH** | Traced complete chain from cause to symptom in code. Regression commit identified. Or: reproduced deterministically. | Can explain every step with code references |
323
+ | **MEDIUM** | Strong circumstantial evidence. Chain mostly traced but 1-2 gaps remain. Pattern match is strong. | Most steps have code references, some inferred |
324
+ | **LOW** | Plausible theory consistent with symptoms but significant gaps in evidence. Multiple alternative explanations possible. | Theory fits but lacks direct code proof |
325
+
326
+ If confidence is LOW → do NOT present as finding. Continue investigating or report INSUFFICIENT_EVIDENCE.
327
+
328
+ ### Hypothesis Verification Suggestions
329
+
330
+ For each hypothesis, describe HOW it can be verified without changing code:
331
+
332
+ ```
333
+ VERIFICATION PLAN
334
+ ═════════════════
335
+ To confirm this hypothesis:
336
+ 1. <read-only step — e.g., "check value of X at runtime via existing logs">
337
+ 2. <read-only step — e.g., "grep for other callers of this function to see if they hit same path">
338
+ 3. <read-only step — e.g., "compare git blame output with the date the bug was first reported">
339
+
340
+ If read-only verification is insufficient:
341
+ Instrumentation suggestion: <e.g., "add temporary log at file:line to capture value of X">
342
+ ⚠️ This requires code change — note for whoever implements the fix.
343
+ ```
344
+
345
+ ### 3-Strike Rule
346
+
347
+ If 3 hypotheses are formed and NONE can be supported to MEDIUM+ confidence → **STOP**.
348
+
349
+ Use `AskUserQuestion`:
350
+
351
+ ```json
352
+ {
353
+ "questions": [{
354
+ "question": "3 hypotheses investigated, none confirmed to medium+ confidence. How to proceed?",
355
+ "header": "Stalled",
356
+ "multiSelect": false,
357
+ "options": [
358
+ {"label": "New evidence", "description": "I have additional context that might help (describe it)"},
359
+ {"label": "Instrument", "description": "Add logging to the affected area, catch it next time"},
360
+ {"label": "Report as-is", "description": "Publish findings so far with INSUFFICIENT_EVIDENCE status"}
361
+ ]
362
+ }]
363
+ }
364
+ ```
365
+
366
+ Do NOT keep spinning. 3 strikes = escalate or report partial findings.
367
+
368
+ ### Multiple Hypotheses
369
+
370
+ If evidence supports 2+ plausible root causes:
371
+
372
+ ```
373
+ HYPOTHESIS A (PRIMARY — HIGH confidence)
374
+ Location: ...
375
+ Mechanism: ...
376
+
377
+ HYPOTHESIS B (ALTERNATIVE — MEDIUM confidence)
378
+ Location: ...
379
+ Mechanism: ...
380
+ Why less likely: <specific reason A is preferred over B>
381
+ ```
382
+
383
+ Rank by confidence. Maximum 3 hypotheses — if you have more, you haven't narrowed enough.
384
+
385
+ ---
386
+
387
+ ## Phase 5: Map Blast Radius
388
+
389
+ Determine what else is affected. This informs fix priority and scope.
390
+
391
+ ### 5.0 — Declare Investigation Scope
392
+
393
+ Before mapping blast radius, declare the narrowest scope containing the bug:
394
+
395
+ ```
396
+ INVESTIGATION SCOPE
397
+ ═══════════════════════════════
398
+ Primary: <directory or module containing root cause>
399
+ Secondary: <directories containing direct callers/dependents>
400
+ Out of scope: <what was NOT investigated, and why>
401
+ ```
402
+
403
+ This helps whoever fixes the bug understand what was examined and what wasn't.
404
+
405
+ ### 5.1 — Bug Path Diagram (skip if ISOLATED)
406
+
407
+ **If impact scope is clearly ISOLATED** (bug in 1 function, ≤2 direct callers,
408
+ no shared state, no persistence side effects):
409
+ → Skip diagram. List direct impacts in 2-3 bullet points.
410
+
411
+ **If impact scope is MODULE or wider:**
412
+ → Draw full diagram:
413
+
414
+ ```
415
+ BUG PATH DIAGRAM
416
+ ═══════════════════════════
417
+ [+] <file>
418
+
419
+ └── affectedFunction()
420
+ ├── [★★ TESTED] Normal path — test_file:12
421
+ ├── [BUG] <edge case> (← root cause here)
422
+ │ ├── [GAP] <downstream effect 1> — NO TEST
423
+ │ └── [GAP] <downstream effect 2> — NO TEST
424
+ ├── [★★ TESTED] Other branch — test_file:20
425
+ └── [→MANUAL] View/UI rendering — visual verification only
426
+
427
+ Legend:
428
+ [★★ TESTED] = has test coverage
429
+ [BUG] = root cause location
430
+ [GAP] = no test, affected by bug
431
+ [→MANUAL] = UI/visual, cannot automate
432
+ [UNCLEAR] = couldn't determine coverage, needs human check
433
+ ```
434
+
435
+ > **If GA available, lean on it for blast radius.** `ga_impact(symbol=...)` is the one-shot tool — returns impacted files, tests, routes, and a runtime risk score. Pair with `ga_callers` / `ga_callees` for the call graph and `ga_architecture` to identify the module/layer (auth, payment, core). More accurate than grep — uses typed CALL/REFERENCES edges and resolves polymorphic dispatch. If GA is unavailable, fall back to grep + manual file reading.
436
+
437
+ ### 5.2 — Impact Scope
438
+
439
+ ```
440
+ BLAST RADIUS
441
+ ═══════════════════════════
442
+ Direct impact:
443
+ - <file:function> — <what goes wrong>
444
+ - <file:function> — <what goes wrong>
445
+
446
+ Indirect impact (callers of affected code):
447
+ - <file:function> calls <affected> → may see <effect>
448
+ - <file:function> calls <affected> → may see <effect>
449
+
450
+ Data impact:
451
+ - <table/collection> — could have <inconsistent state>
452
+ - <cache key> — could serve <stale data>
453
+
454
+ User-facing impact:
455
+ - <feature/screen> — user sees <wrong behavior>
456
+ - <API endpoint> — returns <wrong response>
457
+
458
+ Impact scope: ISOLATED | MODULE | CROSS-MODULE | SYSTEM-WIDE
459
+ ```
460
+
461
+ ### 5.3 — Similar Risk Scan (skip if ISOLATED + unique pattern)
462
+
463
+ **Skip if:** bug is ISOLATED AND the code pattern is unique to this location
464
+ (not a repeated idiom). Note: "scan skipped — pattern unique to this location."
465
+
466
+ **Run if:** the bug pattern could plausibly exist elsewhere (e.g., missing null check
467
+ on API response, unguarded concurrent access, cache not invalidated after write).
468
+
469
+ Grep for the same pattern elsewhere. Timebox: 5 minutes max.
470
+
471
+ ```bash
472
+ # Example: if bug is a missing null check on API response
473
+ grep -rn "\.data\." --include="*.ts" . | grep -v "?\.data\.\|\.data &&\|\.data !=\|\.data !=="
474
+ # → finds other places accessing .data without null check
475
+ ```
476
+
477
+ **Beyond grep — think at design level:**
478
+ - Same abstraction used elsewhere? (e.g., other repositories using same base class)
479
+ - Same API contract reused? (e.g., other endpoints making same assumption about response shape)
480
+ - Same concurrency pattern repeated? (e.g., other handlers doing read-modify-write without lock)
481
+ - Same cache pattern? (e.g., other services writing without invalidation)
482
+
483
+ Grep catches syntax-level repetition. Design-level thinking catches same-class-of-bug
484
+ in different code that looks nothing alike syntactically.
485
+
486
+ Record findings:
487
+ ```
488
+ SIMILAR RISK
489
+ ═══════════════════════════
490
+ Same pattern found at:
491
+ - <file:line> — <description>
492
+ - <file:line> — <description>
493
+ - (none found — pattern is unique to this location)
494
+
495
+ Scan scope: <what was searched, what pattern>
496
+ Timebox: 5 minutes (do not let this block the report)
497
+ ```
498
+
499
+ ---
500
+
501
+ ## Phase 6: Recommend Next Steps
502
+
503
+ Based on the investigation, recommend specific actions.
504
+
505
+ ```
506
+ RECOMMENDED ACTIONS
507
+ ═══════════════════════════
508
+
509
+ 1. [CRITICAL] <action — specific file, specific change>
510
+ Reason: <why this is needed>
511
+ Estimated scope: <N files, complexity LOW/MEDIUM/HIGH>
512
+
513
+ 2. [HIGH] <action>
514
+ Reason: ...
515
+
516
+ 3. [MEDIUM] <action>
517
+ Reason: ...
518
+
519
+ Test strategy:
520
+ - Regression test: <what to test, at what level (unit/integration)>
521
+ - Existing tests to verify: <list test names that should still pass>
522
+ - Manual verification: <what to check visually, if applicable>
523
+
524
+ Suggested fix approach:
525
+ □ Minimal fix (patch the specific bug) — use when blast radius is ISOLATED
526
+ □ Targeted refactor (fix pattern across affected module) — use when SIMILAR RISK has 3+ hits
527
+ □ Architectural fix (redesign the interaction) — use when root cause is structural
528
+
529
+ → To fix: run `/sp-fix <paste root cause summary>`
530
+ ```
531
+
532
+ ---
533
+
534
+ ## Output: Investigation Report
535
+
536
+ **Omit empty sections.** If a section has no meaningful content for this investigation,
537
+ leave it out entirely. A 5-section report for a simple bug is better than a 12-section
538
+ report with 7 empty sections.
539
+
540
+ ```
541
+ INVESTIGATION REPORT
542
+ ════════════════════════════════════════════════════════════════
543
+
544
+ Target: <what was investigated>
545
+ Date: <date>
546
+ Status: ROOT_CAUSE_FOUND | PROBABLE_CAUSE | INSUFFICIENT_EVIDENCE | BLOCKED
547
+
548
+ ─── SUMMARY ───
549
+ <2-3 sentences: what's wrong, why, and what to do about it>
550
+
551
+ ─── SYMPTOM ───
552
+ Expected: <what should happen>
553
+ Actual: <what happens instead>
554
+ Frequency: <always / intermittent / under specific conditions>
555
+
556
+ ─── ROOT CAUSE ───
557
+ HYPOTHESIS A (PRIMARY — <confidence>)
558
+ Location: <file:line>
559
+ Mechanism: <what is wrong>
560
+ Chain: <cause> → <step> → ... → <symptom>
561
+ Evidence:
562
+ - <file:line> — <what this code shows>
563
+ - <git commit> — <what this change reveals>
564
+ - <log/output> — <what this data proves>
565
+ Disproof: <what would prove this wrong>
566
+
567
+ (HYPOTHESIS B if applicable)
568
+
569
+ ─── POTENTIAL GAPS ───
570
+ Risks discovered during investigation that may not be the root cause of THIS bug,
571
+ but represent risks for future bugs:
572
+
573
+ - <file:line> — Missing guard/validation: <what's unprotected>
574
+ - <file:line> — Assumption not enforced: <what assumption could break>
575
+ - <file:function> — No test coverage for: <path/branch>
576
+ - <file:function> — Fragile pattern: <why this could easily break again>
577
+ - (none discovered — investigation scope was clean)
578
+
579
+ These are inputs for refactor/tech-debt decisions, not immediate fixes.
580
+
581
+ ─── REGRESSION? ───
582
+ <Yes — commit <hash> introduced this on <date> | No — pre-existing | Unknown>
583
+
584
+ ─── RECURRING? ───
585
+ <Yes — N fix commits in this area in last M months. Architectural smell suspected.
586
+ Pattern: <what keeps breaking> | No — first known bug in this area>
587
+
588
+ ─── BUG PATH ───
589
+ (omit if ISOLATED)
590
+ <Bug Path Diagram from Phase 5.1>
591
+
592
+ ─── BLAST RADIUS ───
593
+ Scope: <ISOLATED | MODULE | CROSS-MODULE | SYSTEM-WIDE>
594
+ <Impact details from Phase 5.2>
595
+
596
+ ─── SIMILAR RISK ───
597
+ (omit if scan skipped)
598
+ <Findings from Phase 5.3>
599
+
600
+ ─── RECOMMENDED ACTIONS ───
601
+ <From Phase 6>
602
+
603
+ ─── OPEN QUESTIONS ───
604
+ (omit if investigation is complete)
605
+ <Anything that couldn't be determined from code alone>
606
+ - <question — what additional info would help>
607
+ - <question — what test/experiment would clarify>
608
+
609
+ ════════════════════════════════════════════════════════════════
610
+ ```
611
+
612
+ ---
613
+
614
+ ## Handoff File
615
+
616
+ After producing the report, write it to `docs/investigate/<slug>-$(date +%Y-%m-%d).md` so `/sp-fix` can auto-detect it and skip redundant discovery.
617
+
618
+ - `<slug>` = kebab-case of the bug subject (e.g. `order-cancel-500`, `login-redirect-loop`)
619
+ - If a file for the same slug+date already exists → append `-NN` suffix (`...-2026-04-21-02.md`)
620
+ - The file contains the full Investigation Report block above, no wrapping prose
621
+ - Mention the path at the end of the chat response so the user can open it
622
+
623
+ Writing this file is the ONLY write operation this skill performs — it is output, not a code change. If `docs/investigate/` does not exist, create it.
624
+
625
+ After writing, signal handoff:
626
+
627
+ ```
628
+ ⚠️ Ready to fix — run `/sp-fix docs/investigate/<slug>-<date>.md`
629
+ (or paste root cause summary directly if you prefer to skip the file)
630
+ ```
631
+
632
+ ---
633
+
634
+ ## Rules
635
+
636
+ 1. **Read only for code.** Never modify source code, tests, configs, or any file outside `docs/investigate/`. The investigation report file is the single allowed write.
637
+ 2. **Evidence over intuition.** Every claim in the report must reference specific code (file:line) or data (git commit, log output).
638
+ 3. **Specific over vague.** "The cache isn't invalidated after write at storage.rs:142" not "there might be a cache issue".
639
+ 4. **Complete the chain.** Root cause → intermediate steps → symptom. No gaps. If there's a gap, say so.
640
+ 5. **Honest confidence.** LOW means LOW. Don't inflate to get past Phase 4. INSUFFICIENT_EVIDENCE is a valid outcome.
641
+ 6. **Timebox.** If after 15 minutes of investigation you can't form a MEDIUM+ hypothesis → report INSUFFICIENT_EVIDENCE with everything gathered so far. Don't spin.
642
+ 7. **One investigation, one report.** If `$ARGUMENTS` describes multiple bugs, investigate the most severe first. Mention others in OPEN QUESTIONS.
643
+
644
+ **Red flags — slow down:**
645
+ - Jumping to a hypothesis before tracing the data flow — you're guessing
646
+ - "It's probably X" without file:line evidence — investigate more
647
+ - Confirming your theory instead of trying to disprove it — confirmation bias
648
+ - Spending 10+ minutes on similar-risk scan — timebox and move on