specpipe 1.0.1 → 1.0.3
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/README.md +111 -311
- package/package.json +2 -1
- package/src/cli.js +16 -6
- package/src/commands/diff.js +1 -1
- package/src/commands/init-agents.js +48 -20
- package/src/commands/init-global.js +104 -33
- package/src/commands/init-interactive.js +71 -0
- package/src/commands/init.js +68 -20
- package/src/commands/remove.js +159 -49
- package/src/commands/upgrade.js +21 -56
- package/src/lib/agent-guards.js +34 -78
- package/src/lib/agent-install.js +38 -25
- package/src/lib/agents.js +53 -11
- package/src/lib/claude-global.js +55 -77
- package/src/lib/hooks.js +203 -0
- package/src/lib/installer.js +104 -62
- package/src/lib/reconcile.js +13 -8
- package/templates/{.claude/hooks → hooks}/file-guard.js +26 -21
- package/templates/hooks/specpipe-read-guard.sh +94 -21
- package/templates/hooks/specpipe-shell-guard.sh +121 -29
- package/templates/rules/specpipe-rules.md +77 -0
- package/templates/skills/sp-build/SKILL.md +101 -1
- package/templates/skills/sp-build-behavior-matrix/SKILL.md +876 -0
- package/templates/skills/sp-challenge/SKILL.md +34 -0
- package/templates/skills/sp-challenge-behavior-matrix/SKILL.md +289 -0
- package/templates/skills/sp-explore/SKILL.md +132 -0
- package/templates/skills/sp-explore-behavior-matrix/SKILL.md +862 -0
- package/templates/skills/sp-fix/SKILL.md +73 -1
- package/templates/skills/sp-fix-behavior-matrix/SKILL.md +338 -0
- package/templates/skills/sp-investigate/SKILL.md +70 -0
- package/templates/skills/sp-investigate-behavior-matrix/SKILL.md +718 -0
- package/templates/skills/sp-plan/SKILL.md +90 -0
- package/templates/skills/sp-plan-behavior-matrix/SKILL.md +1037 -0
- package/templates/skills/sp-review/SKILL.md +29 -3
- package/templates/skills/sp-review-behavior-matrix/SKILL.md +294 -0
- package/templates/.claude/CLAUDE.md +0 -79
- package/templates/.claude/hooks/path-guard.sh +0 -118
- package/templates/.claude/hooks/self-review.sh +0 -27
- package/templates/.claude/hooks/sensitive-guard.sh +0 -227
- package/templates/.claude/settings.json +0 -68
- package/templates/docs/WORKFLOW.md +0 -325
- package/templates/docs/specs/.gitkeep +0 -0
- package/templates/rules/specpipe-guards.md +0 -40
- package/templates/scripts/test-hooks.sh +0 -66
- /package/templates/{.claude/hooks → hooks}/comment-guard.js +0 -0
- /package/templates/{.claude/hooks → hooks}/glob-guard.js +0 -0
|
@@ -58,9 +58,46 @@ Don't jump to code. Understand the bug first:
|
|
|
58
58
|
| Integration failure | Timeout, unexpected response | External API calls, service boundaries |
|
|
59
59
|
| Config drift | Works locally, fails in staging/prod | Env vars, feature flags, DB state |
|
|
60
60
|
| Stale cache | Shows old data, fixes on cache clear | Redis, CDN, browser cache |
|
|
61
|
+
| Lifecycle/parity/cascade | Correct on one state/viewer/surface but wrong on another | `## Behavior Matrix`, read models, queues, dashboard counts, feed, notifications, APIs |
|
|
61
62
|
|
|
62
63
|
5. **Reproduce deterministically.** If you can't trigger the bug reliably → gather more evidence. Do NOT guess.
|
|
63
64
|
|
|
65
|
+
6. **Behavior Matrix mapping.** If a related spec contains `## Behavior Matrix`, or the bug mentions status/state, role/viewer, list/detail/worklist/dashboard/feed/API/email/calendar, classify the bug before writing the test:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
BM BUG CLASSIFICATION
|
|
69
|
+
════════════════════════════════
|
|
70
|
+
State/status: <state or transition, e.g. Confirmed -> Rescheduled>
|
|
71
|
+
Viewer/role: <actor/viewer/relationship, e.g. assigned trainer>
|
|
72
|
+
Surface/path: <list/detail/API/feed/calendar/etc.>
|
|
73
|
+
Matrix cell: BM.AS-NNN.<surface> | GAP-NNN | N/A:<reason> | NO_CELL
|
|
74
|
+
Bug class: lifecycle | viewer-parity | surface-parity | cascade | external-down | other
|
|
75
|
+
Spec status: covered | gap-open | suspicious-N/A | missing-cell
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If the bug maps to `NO_CELL`, `GAP`, or suspicious `N/A`, the fix may still proceed, but Phase 5 must emit a Spec Update Signal. Do not silently fix behavior that the spec cannot name.
|
|
79
|
+
|
|
80
|
+
Use the invariant registry README/schema as base knowledge; README examples are not runtime entries. Then read project-local invariant entries if present: `docs/invariants/INV-*.md`. If an invariant matches the component or bug class, include it in the hypothesis and regression test. Status handling:
|
|
81
|
+
- `enforced` → the fix must preserve or update the referenced `test_ref` / equivalent regression.
|
|
82
|
+
- `confirmed` → add/update a regression that proves the invariant for the touched component when feasible.
|
|
83
|
+
- `candidate` → use as an investigation hint; do not treat it as a hard build requirement unless the bug confirms it.
|
|
84
|
+
- `retired` → ignore unless this fix reintroduces the retired component.
|
|
85
|
+
|
|
86
|
+
**Sibling Discovery Pass (candidate only):** Run this for lifecycle/parity/cascade bugs, existing-operation fixes, or any bug whose symptom names one surface but the operation may exist on sibling entry-points. This is the same recipe as `/sp-explore` Phase 0.5, scoped to the bug:
|
|
87
|
+
|
|
88
|
+
1. Seed nouns/verbs from the raw symptom, failing test, touched component, and matching invariant entries.
|
|
89
|
+
2. Find shared-anchor callers (`ga_callers` if GA is available; otherwise grep) for helpers/constants/schemas that define the operation.
|
|
90
|
+
3. Fuzzy-search parallel names such as `create_from_*`, `*_from_<source>`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, `cancel*`, `delete*`, plus domain verbs from the symptom.
|
|
91
|
+
4. Inspect recent git co-change around touched files (`git log --name-only -- <seed-file>`) for repeatedly paired files/functions.
|
|
92
|
+
|
|
93
|
+
Record a `Sibling Candidate Table` in the investigation notes:
|
|
94
|
+
|
|
95
|
+
| Candidate | Operation | Evidence | Confidence | Fix disposition |
|
|
96
|
+
|---|---|---|---|---|
|
|
97
|
+
| `<surface/path/symbol>` | same create/update/delete/send/read op? | ga_callers / grep / co-change / invariant / symptom | high / medium / low | test-now / spec-GAP / ignore(reason) |
|
|
98
|
+
|
|
99
|
+
Do not auto-fix candidates. `test-now` means this bug confirms the sibling belongs in the regression scope. `spec-GAP` means emit a Spec Update Signal because behavior/scope is unclear. `ignore(reason)` means false positive or intentionally out of scope.
|
|
100
|
+
|
|
64
101
|
> **If GA available, lean on it for steps 2 and 4.** `ga_symbols` resolves names, `ga_callers`/`ga_callees` map the call graph, `ga_impact` returns blast radius + test gaps + risk, `ga_architecture` reveals which module/layer (auth, payment, core) the bug sits in, `ga_risk` scores whether a change here is safe. If GA is unavailable, fall back to grep + `git log` + manual reading.
|
|
65
102
|
|
|
66
103
|
**Required output:** `Root cause hypothesis: ...` — a specific, testable claim about what is wrong and why.
|
|
@@ -124,6 +161,16 @@ All test commands below use `TEST_CMD` to mean the resolved command. For filtere
|
|
|
124
161
|
|
|
125
162
|
**REGRESSION RULE:** If the bug exists because the diff changed existing behavior AND no test covered that path → this is a regression. A regression test is a **CRITICAL requirement.** Add the comment: `// Regression: <bug> — <file:line> broke this path`
|
|
126
163
|
|
|
164
|
+
**BEHAVIOR MATRIX REGRESSION RULE:** If Phase 0 mapped the bug to `BM.AS-NNN.<surface>`, the failing test name or description MUST include the AS id or BM id. Prefer the most specific form:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
it("BM.AS-012 appointment-list preserves assigned trainer after reschedule", ...)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If the bug maps to `GAP-NNN`, name the test with the eventual AS only after the spec is resolved; until then write a targeted reproduction if needed but mark the Phase 5 status `DONE_WITH_CONCERNS` and emit Spec Update Signal.
|
|
171
|
+
|
|
172
|
+
If the bug maps to `NO_CELL`, add the reproduction test only if the expected behavior is already unambiguous from product behavior or user instruction. Otherwise stop and request spec clarification before coding.
|
|
173
|
+
|
|
127
174
|
Write a test that reproduces the bug. It **MUST fail** with current code.
|
|
128
175
|
|
|
129
176
|
Verify filter match first (see "Filter pattern verification" in the Test Command section). Then run:
|
|
@@ -176,6 +223,7 @@ Make the **minimal change** needed.
|
|
|
176
223
|
**Similar-risk scan (MANDATORY after fix, before Phase 3):** Grep for the same pattern that caused this bug, scoped to:
|
|
177
224
|
1. The same file as the fix (all sibling functions in the fixed file).
|
|
178
225
|
2. Direct callers of the fixed function (one level up — if GA available, `ga_callers`; otherwise grep or IDE refs).
|
|
226
|
+
3. For lifecycle/parity/cascade bugs: sibling surfaces from the Behavior Matrix, handoff axes, project-local invariant entries, and this run's Sibling Candidate Table (list/detail/worklist/dashboard/feed/API/email/calendar/search/export/audit). This is a scan, not an auto-fix.
|
|
179
227
|
|
|
180
228
|
Do NOT auto-fix findings — the minimal-fix rule stands. Record each under Phase 5 `SIMILAR_RISK:` as `<file:line> — same pattern, unguarded`.
|
|
181
229
|
|
|
@@ -187,6 +235,7 @@ Do NOT auto-fix findings — the minimal-fix rule stands. Record each under Phas
|
|
|
187
235
|
|
|
188
236
|
1. Run the bug test: `TEST_CMD --filter "<test name>"` → must PASS.
|
|
189
237
|
2. Run full suite: `TEST_CMD` → no regressions.
|
|
238
|
+
3. For `BM.AS-NNN` fixes, verify the relevant cell-level test is not vacuous: it must assert the named surface/source/timing. A test that mocks the exact boundary under test (API projection, read-model query, queue/feed, email provider, calendar provider) is not sufficient by itself.
|
|
190
239
|
|
|
191
240
|
If other tests break → the fix caused a regression. Investigate. Do NOT weaken existing tests.
|
|
192
241
|
|
|
@@ -205,6 +254,14 @@ Prevention: <suggest one: type constraint, validation, lint rule, spec update (i
|
|
|
205
254
|
|
|
206
255
|
This is non-optional for serious bugs. For trivial bugs, the fix summary is enough.
|
|
207
256
|
|
|
257
|
+
For lifecycle/parity/cascade bugs, include:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
Behavior Matrix cell: <BM.AS-NNN.surface | GAP-NNN | NO_CELL>
|
|
261
|
+
Invariant impact: <existing invariant preserved | new invariant should be logged | none>
|
|
262
|
+
Regression class: <carry-forward | viewer-relative | invite-on-reschedule | orphan cleanup | stale projection | other>
|
|
263
|
+
```
|
|
264
|
+
|
|
208
265
|
---
|
|
209
266
|
|
|
210
267
|
## Phase 5: Summary
|
|
@@ -221,6 +278,8 @@ Evidence: <paste raw failing-then-passing test output, verbatim>
|
|
|
221
278
|
Regression test: <file:test name>
|
|
222
279
|
Full suite: All passing ✓
|
|
223
280
|
Similar risk: [SIMILAR_RISK findings from Phase 2 scan, or "none"]
|
|
281
|
+
Behavior Matrix: <BM.AS-NNN.surface | GAP-NNN | NO_CELL | N/A>
|
|
282
|
+
Invariant: <matched invariant / new invariant recommended / none>
|
|
224
283
|
Manual needed: [→MANUAL gaps, or "none"]
|
|
225
284
|
Status: DONE | DONE_WITH_CONCERNS | BLOCKED
|
|
226
285
|
════════════════════════════════════════
|
|
@@ -237,6 +296,8 @@ After fixing, check these conditions. If ANY is true → **must** signal.
|
|
|
237
296
|
| S1 | Fix covers an edge case or error path with no corresponding AS in the spec |
|
|
238
297
|
| S2 | Bug existed because an AS described wrong behavior — After fix, code and AS now conflict |
|
|
239
298
|
| S3 | Fix adds a new constraint or guard (null check, balance guard, validation) not in spec |
|
|
299
|
+
| S4 | Bug maps to `NO_CELL`, `GAP-NNN`, or suspicious `N/A` in `## Behavior Matrix` |
|
|
300
|
+
| S5 | Fix reveals a repeated lifecycle/parity/cascade invariant not present in invariant logs |
|
|
240
301
|
|
|
241
302
|
**Do not signal when:**
|
|
242
303
|
- Fix is a clear typo/off-by-one — code was always wrong relative to spec, no new behavior
|
|
@@ -245,7 +306,18 @@ After fixing, check these conditions. If ANY is true → **must** signal.
|
|
|
245
306
|
**Signal format:**
|
|
246
307
|
```
|
|
247
308
|
⚠️ Spec Update Needed — run `/sp-plan docs/specs/<feature>/<feature>.md '<describe change>'`
|
|
248
|
-
Reason: [S1 | S2 | S3] — <one line: what is missing or mismatched>
|
|
309
|
+
Reason: [S1 | S2 | S3 | S4 | S5] — <one line: what is missing or mismatched>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
If S5 applies, also emit:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
⚠️ Invariant Log Update Needed
|
|
316
|
+
Component: <component/module>
|
|
317
|
+
Invariant: <state/viewer/surface rule that must stay true>
|
|
318
|
+
Reason: repeated bug class — <carry-forward/viewer-relative/invite-on-reschedule/orphan/etc.>
|
|
319
|
+
Suggested registry path: docs/invariants/INV-###-<short-name>.md
|
|
320
|
+
Suggested status: candidate (promote to confirmed when accepted; enforced only when test_ref exists and passes)
|
|
249
321
|
```
|
|
250
322
|
|
|
251
323
|
## Multiple Bugs
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: |
|
|
3
|
+
Test-first bug fix — write failing test, fix code, verify green.
|
|
4
|
+
Iron Law: never fix without finding root cause first.
|
|
5
|
+
Use when asked to "fix this bug", "fix bug", "sửa lỗi", "sửa bug",
|
|
6
|
+
"this is broken", "cái này hỏng", or when user reports a reproducible
|
|
7
|
+
bug with repro steps or a stack trace.
|
|
8
|
+
Proactively invoke this skill (do NOT patch directly) when the user
|
|
9
|
+
describes a bug they want fixed.
|
|
10
|
+
For complex/ambiguous bugs (outage, regression, "it was working yesterday",
|
|
11
|
+
data corruption), start with /sp-investigate first, then hand the report to /sp-fix.
|
|
12
|
+
Skip for typos or one-line obvious fixes.
|
|
13
|
+
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, mcp__graphatlas__*
|
|
14
|
+
---
|
|
15
|
+
Test-first bug fix — write failing test, fix code, verify green.
|
|
16
|
+
|
|
17
|
+
Bug: $ARGUMENTS
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Iron Law
|
|
22
|
+
|
|
23
|
+
**NEVER fix without finding the root cause first.**
|
|
24
|
+
|
|
25
|
+
Fixing symptoms creates whack-a-mole debugging. Every fix that doesn't address the root cause makes the next bug harder to find.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Phase 0a — Graphatlas probe (run once)
|
|
30
|
+
|
|
31
|
+
Before locating code, probe whether graphatlas (GA) is connected:
|
|
32
|
+
|
|
33
|
+
1. Call `mcp__graphatlas__ga_architecture` with `max_modules: 1`.
|
|
34
|
+
2. Interpret:
|
|
35
|
+
- Returns `modules` → **GA available.** Use `ga_*` for code discovery, blast-radius, and risk. Grep is fallback only.
|
|
36
|
+
- Error `STALE_INDEX` → call `mcp__graphatlas__ga_reindex` (mode `"full"`), retry once, then treat as available.
|
|
37
|
+
- Tool not found / connection error / any other failure → **GA unavailable.** Use grep/glob throughout this run. Do not re-probe.
|
|
38
|
+
3. After edits the graph goes stale. Reindex on demand: when a later `ga_*` call returns `STALE_INDEX`, call `mcp__graphatlas__ga_reindex` (mode `"full"`) once then retry. Don't reindex preemptively after every edit.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Phase 0: Investigate
|
|
43
|
+
|
|
44
|
+
Don't jump to code. Understand the bug first:
|
|
45
|
+
|
|
46
|
+
0. **Investigation handoff check.** If `$ARGUMENTS` references a file under `docs/investigate/`, read it first — it contains pre-built root cause hypothesis, blast radius, and recommended actions from `/sp-investigate`. Skip redundant discovery; jump to Phase 1 using its findings. If no such file and the bug is complex/ambiguous/production-critical → suggest the user run `/sp-investigate "<bug>"` first; otherwise proceed.
|
|
47
|
+
|
|
48
|
+
1. **Parse the report.** Symptom? Expected vs actual? Repro steps? If context is missing → ask ONE question via AskUserQuestion before proceeding.
|
|
49
|
+
2. **Locate the code.** **If GA available (per Phase 0a):** `ga_symbols("<function or type>")` → definitions; `ga_callers` + `ga_callees` on the resolved symbol → call graph; `ga_impact(symbol=...)` → blast radius + affected tests + risk in one shot; `ga_file_summary` before reading a file in full. **If GA unavailable or the query is free text** (error strings inside literals, log lines): grep.
|
|
50
|
+
3. **Check history.** `git log --oneline -20 -- <affected-files>` — was this working before? What changed? Regression = root cause is in the diff.
|
|
51
|
+
4. **Pattern check.** Match the symptom against known bug patterns:
|
|
52
|
+
|
|
53
|
+
| Pattern | Signature | Where to look |
|
|
54
|
+
|---------|-----------|---------------|
|
|
55
|
+
| Race condition | Intermittent, timing-dependent | Concurrent access to shared state |
|
|
56
|
+
| Nil/null propagation | NoMethodError, TypeError, NullPointerException | Missing guards on optional values |
|
|
57
|
+
| State corruption | Inconsistent data, partial updates | Transactions, callbacks, hooks |
|
|
58
|
+
| Integration failure | Timeout, unexpected response | External API calls, service boundaries |
|
|
59
|
+
| Config drift | Works locally, fails in staging/prod | Env vars, feature flags, DB state |
|
|
60
|
+
| Stale cache | Shows old data, fixes on cache clear | Redis, CDN, browser cache |
|
|
61
|
+
| Lifecycle/parity/cascade | Correct on one state/viewer/surface but wrong on another | `## Behavior Matrix`, read models, queues, dashboard counts, feed, notifications, APIs |
|
|
62
|
+
|
|
63
|
+
5. **Reproduce deterministically.** If you can't trigger the bug reliably → gather more evidence. Do NOT guess.
|
|
64
|
+
|
|
65
|
+
6. **Behavior Matrix mapping.** If a related spec contains `## Behavior Matrix`, or the bug mentions status/state, role/viewer, list/detail/worklist/dashboard/feed/API/email/calendar, classify the bug before writing the test:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
BM BUG CLASSIFICATION
|
|
69
|
+
════════════════════════════════
|
|
70
|
+
State/status: <state or transition, e.g. Confirmed -> Rescheduled>
|
|
71
|
+
Viewer/role: <actor/viewer/relationship, e.g. assigned trainer>
|
|
72
|
+
Surface/path: <list/detail/API/feed/calendar/etc.>
|
|
73
|
+
Matrix cell: BM.AS-NNN.<surface> | GAP-NNN | N/A:<reason> | NO_CELL
|
|
74
|
+
Bug class: lifecycle | viewer-parity | surface-parity | cascade | external-down | other
|
|
75
|
+
Spec status: covered | gap-open | suspicious-N/A | missing-cell
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
If the bug maps to `NO_CELL`, `GAP`, or suspicious `N/A`, the fix may still proceed, but Phase 5 must emit a Spec Update Signal. Do not silently fix behavior that the spec cannot name.
|
|
79
|
+
|
|
80
|
+
Use the invariant registry README/schema as base knowledge; README examples are not runtime entries. Then read project-local invariant entries if present: `docs/invariants/INV-*.md`. If an invariant matches the component or bug class, include it in the hypothesis and regression test. Status handling:
|
|
81
|
+
- `enforced` → the fix must preserve or update the referenced `test_ref` / equivalent regression.
|
|
82
|
+
- `confirmed` → add/update a regression that proves the invariant for the touched component when feasible.
|
|
83
|
+
- `candidate` → use as an investigation hint; do not treat it as a hard build requirement unless the bug confirms it.
|
|
84
|
+
- `retired` → ignore unless this fix reintroduces the retired component.
|
|
85
|
+
|
|
86
|
+
**Sibling Discovery Pass (candidate only):** Run this for lifecycle/parity/cascade bugs, existing-operation fixes, or any bug whose symptom names one surface but the operation may exist on sibling entry-points. This is the same recipe as `/sp-explore` Phase 0.5, scoped to the bug:
|
|
87
|
+
|
|
88
|
+
1. Seed nouns/verbs from the raw symptom, failing test, touched component, and matching invariant entries.
|
|
89
|
+
2. Find shared-anchor callers (`ga_callers` if GA is available; otherwise grep) for helpers/constants/schemas that define the operation.
|
|
90
|
+
3. Fuzzy-search parallel names such as `create_from_*`, `*_from_<source>`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, `cancel*`, `delete*`, plus domain verbs from the symptom.
|
|
91
|
+
4. Inspect recent git co-change around touched files (`git log --name-only -- <seed-file>`) for repeatedly paired files/functions.
|
|
92
|
+
|
|
93
|
+
Record a `Sibling Candidate Table` in the investigation notes:
|
|
94
|
+
|
|
95
|
+
| Candidate | Operation | Evidence | Confidence | Fix disposition |
|
|
96
|
+
|---|---|---|---|---|
|
|
97
|
+
| `<surface/path/symbol>` | same create/update/delete/send/read op? | ga_callers / grep / co-change / invariant / symptom | high / medium / low | test-now / spec-GAP / ignore(reason) |
|
|
98
|
+
|
|
99
|
+
Do not auto-fix candidates. `test-now` means this bug confirms the sibling belongs in the regression scope. `spec-GAP` means emit a Spec Update Signal because behavior/scope is unclear. `ignore(reason)` means false positive or intentionally out of scope.
|
|
100
|
+
|
|
101
|
+
> **If GA available, lean on it for steps 2 and 4.** `ga_symbols` resolves names, `ga_callers`/`ga_callees` map the call graph, `ga_impact` returns blast radius + test gaps + risk, `ga_architecture` reveals which module/layer (auth, payment, core) the bug sits in, `ga_risk` scores whether a change here is safe. If GA is unavailable, fall back to grep + `git log` + manual reading.
|
|
102
|
+
|
|
103
|
+
**Required output:** `Root cause hypothesis: ...` — a specific, testable claim about what is wrong and why.
|
|
104
|
+
|
|
105
|
+
**Required output 2: Bug Path Diagram**
|
|
106
|
+
|
|
107
|
+
Draw a coverage diagram for the buggy function using the same format as sp-build:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
CODE PATH COVERAGE
|
|
111
|
+
===========================
|
|
112
|
+
[+] src/services/affected.ts
|
|
113
|
+
│
|
|
114
|
+
└── affectedFn()
|
|
115
|
+
├── [★★ TESTED] Normal path — affected.test.ts:12
|
|
116
|
+
├── [GAP] Edge case X (← bug lives here) — NO TEST
|
|
117
|
+
│ └── [GAP] Downstream effect — NO TEST
|
|
118
|
+
└── [★★ TESTED] Other branch — affected.test.ts:20
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
If the bug is in a view/template layer (UI render, layout, data binding, styling) — mark the view path `[→MANUAL]` and test the logic layer backing it (ViewModel, Presenter, helper) instead. If there is no logic layer to test, the fix is `[→MANUAL]` only — note what to visually verify.
|
|
122
|
+
|
|
123
|
+
If you cannot identify a specific `[GAP]` path → the hypothesis is not specific enough. Investigate further.
|
|
124
|
+
|
|
125
|
+
If the bug is in a dependency/config/data (not project code), say so before proceeding.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Test Command
|
|
130
|
+
|
|
131
|
+
Resolve once before running tests. Auto-detect from project markers:
|
|
132
|
+
|
|
133
|
+
| Marker | Run all | Run filtered |
|
|
134
|
+
|--------|---------|-------------|
|
|
135
|
+
| vitest config / vitest in package.json | `npx vitest run` | `npx vitest run -t "<pattern>"` |
|
|
136
|
+
| jest config / jest in package.json | `npx jest --no-cache` | `npx jest --no-cache -t "<pattern>"` |
|
|
137
|
+
| pyproject.toml / pytest.ini | `python3 -m pytest -x` | `python3 -m pytest -x -k "<pattern>"` |
|
|
138
|
+
| Cargo.toml | `cargo test` | `cargo test "<pattern>"` |
|
|
139
|
+
| go.mod | `go test ./...` | `go test ./... -run "<pattern>"` |
|
|
140
|
+
| build.gradle | `./gradlew test` | `./gradlew test --tests "<pattern>"` |
|
|
141
|
+
| *.sln | `dotnet test` | `dotnet test --filter "<pattern>"` |
|
|
142
|
+
| Package.swift | `swift test` | `swift test --filter "<pattern>"` |
|
|
143
|
+
| Gemfile | `bundle exec rspec` | `bundle exec rspec -e "<pattern>"` |
|
|
144
|
+
|
|
145
|
+
All test commands below use `TEST_CMD` to mean the resolved command. For filtered runs, use the framework's native filter flag from the table above.
|
|
146
|
+
|
|
147
|
+
**Filter pattern verification (MANDATORY):** A filter matching 0 tests exits 0 on many frameworks — false green. Before trusting any filtered run, confirm match count ≥1:
|
|
148
|
+
|
|
149
|
+
- vitest: `npx vitest list -t "<pattern>"`
|
|
150
|
+
- jest: add `--passWithNoTests=false`
|
|
151
|
+
- pytest: `-k "<pattern>" --collect-only -q`
|
|
152
|
+
- cargo: `cargo test "<pattern>" -- --list`
|
|
153
|
+
- go: `go test -run "<pattern>" -list ".*" ./...`
|
|
154
|
+
- gradle / dotnet / swift / rspec / other: if no equivalent listing command is known, fall back to `grep -r "<test name>" <test-dir>` — string must exist. Log `FILTER_VERIFY: fallback-grep` in Phase 5 report.
|
|
155
|
+
|
|
156
|
+
0 matches → test name / file location wrong. Fix before proceeding. Never interpret 0-match as PASS. **Max 3 retry attempts** on filter-match failure; if still 0 after 3, stop and report BLOCKED.
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Phase 1: Write a Failing Test
|
|
161
|
+
|
|
162
|
+
**REGRESSION RULE:** If the bug exists because the diff changed existing behavior AND no test covered that path → this is a regression. A regression test is a **CRITICAL requirement.** Add the comment: `// Regression: <bug> — <file:line> broke this path`
|
|
163
|
+
|
|
164
|
+
**BEHAVIOR MATRIX REGRESSION RULE:** If Phase 0 mapped the bug to `BM.AS-NNN.<surface>`, the failing test name or description MUST include the AS id or BM id. Prefer the most specific form:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
it("BM.AS-012 appointment-list preserves assigned trainer after reschedule", ...)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
If the bug maps to `GAP-NNN`, name the test with the eventual AS only after the spec is resolved; until then write a targeted reproduction if needed but mark the Phase 5 status `DONE_WITH_CONCERNS` and emit Spec Update Signal.
|
|
171
|
+
|
|
172
|
+
If the bug maps to `NO_CELL`, add the reproduction test only if the expected behavior is already unambiguous from product behavior or user instruction. Otherwise stop and request spec clarification before coding.
|
|
173
|
+
|
|
174
|
+
Write a test that reproduces the bug. It **MUST fail** with current code.
|
|
175
|
+
|
|
176
|
+
Verify filter match first (see "Filter pattern verification" in the Test Command section). Then run:
|
|
177
|
+
```
|
|
178
|
+
TEST_CMD --filter "<test name>"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Capture the raw failure output** (stack trace / assertion diff). Paste it into the Phase 5 DEBUG REPORT `Evidence:` field verbatim — a summary like "test fails" is not evidence.
|
|
182
|
+
|
|
183
|
+
- **FAILS** → reproduced. Continue.
|
|
184
|
+
- **0 TESTS MATCHED** → filter/test name issue, not reproduction. Fix before proceeding.
|
|
185
|
+
- **PASSES** → hypothesis may be wrong. Use `AskUserQuestion`:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"questions": [
|
|
190
|
+
{
|
|
191
|
+
"question": "The test passes with current code — the bug isn't reproduced yet. How to proceed?",
|
|
192
|
+
"header": "Test Passes Unexpectedly",
|
|
193
|
+
"multiSelect": false,
|
|
194
|
+
"options": [
|
|
195
|
+
{"label": "Provide different repro steps or environment details (human: ~30m / CC: ~5m) | Completeness: 10/10"},
|
|
196
|
+
{"label": "The bug may be environment-specific — describe the setup (human: ~1h / CC: ~10m) | Completeness: 9/10"},
|
|
197
|
+
{"label": "Stop and report BLOCKED — cannot reproduce, need human investigation (Completeness: N/A — no fix applied)"}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**3-strike rule:** If 3 hypotheses all fail to reproduce the bug → STOP. Use AskUserQuestion:
|
|
205
|
+
"3 hypotheses tested, none confirmed. This may be architectural — not a simple bug."
|
|
206
|
+
Options: A) New hypothesis (describe new evidence), B) Escalate for human review, C) Instrument the area and catch it next time
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Phase 2: Fix
|
|
211
|
+
|
|
212
|
+
Make the **minimal change** needed.
|
|
213
|
+
|
|
214
|
+
| Do | Don't |
|
|
215
|
+
|----|-------|
|
|
216
|
+
| Fix the specific bug | Refactor surrounding code |
|
|
217
|
+
| Add a guard for the edge case | Rewrite the function |
|
|
218
|
+
| Explain what and why before editing | Silently change code |
|
|
219
|
+
|
|
220
|
+
**Blast radius check:** If the fix requires touching >5 files → stop and use AskUserQuestion before editing anything:
|
|
221
|
+
"This fix touches N files — that's a large blast radius for a bug fix. A) Proceed — root cause genuinely spans these files, B) Split — fix critical path now, defer the rest, C) Rethink — there may be a more targeted approach"
|
|
222
|
+
|
|
223
|
+
**Similar-risk scan (MANDATORY after fix, before Phase 3):** Grep for the same pattern that caused this bug, scoped to:
|
|
224
|
+
1. The same file as the fix (all sibling functions in the fixed file).
|
|
225
|
+
2. Direct callers of the fixed function (one level up — if GA available, `ga_callers`; otherwise grep or IDE refs).
|
|
226
|
+
3. For lifecycle/parity/cascade bugs: sibling surfaces from the Behavior Matrix, handoff axes, project-local invariant entries, and this run's Sibling Candidate Table (list/detail/worklist/dashboard/feed/API/email/calendar/search/export/audit). This is a scan, not an auto-fix.
|
|
227
|
+
|
|
228
|
+
Do NOT auto-fix findings — the minimal-fix rule stands. Record each under Phase 5 `SIMILAR_RISK:` as `<file:line> — same pattern, unguarded`.
|
|
229
|
+
|
|
230
|
+
**Timebox:** 5 minutes max. If the pattern is too generic to grep cleanly (e.g., fix is a common idiom), record `SIMILAR_RISK: scan skipped — pattern too generic, reason: <why>` and move on. Do NOT let this phase block the fix from landing. Silent skipping without a reason note is not acceptable.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Phase 3: Verify
|
|
235
|
+
|
|
236
|
+
1. Run the bug test: `TEST_CMD --filter "<test name>"` → must PASS.
|
|
237
|
+
2. Run full suite: `TEST_CMD` → no regressions.
|
|
238
|
+
3. For `BM.AS-NNN` fixes, verify the relevant cell-level test is not vacuous: it must assert the named surface/source/timing. A test that mocks the exact boundary under test (API projection, read-model query, queue/feed, email provider, calendar provider) is not sufficient by itself.
|
|
239
|
+
|
|
240
|
+
If other tests break → the fix caused a regression. Investigate. Do NOT weaken existing tests.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Phase 4: Root Cause Analysis
|
|
245
|
+
|
|
246
|
+
After fixing, document:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
Symptom: <what the user saw>
|
|
250
|
+
Root cause: <why it happened>
|
|
251
|
+
Gap: <why not caught earlier — missing test? wrong assumption? missing spec?>
|
|
252
|
+
Prevention: <suggest one: type constraint, validation, lint rule, spec update (including acceptance scenarios)>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
This is non-optional for serious bugs. For trivial bugs, the fix summary is enough.
|
|
256
|
+
|
|
257
|
+
For lifecycle/parity/cascade bugs, include:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
Behavior Matrix cell: <BM.AS-NNN.surface | GAP-NNN | NO_CELL>
|
|
261
|
+
Invariant impact: <existing invariant preserved | new invariant should be logged | none>
|
|
262
|
+
Regression class: <carry-forward | viewer-relative | invite-on-reschedule | orphan cleanup | stale projection | other>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Phase 5: Summary
|
|
268
|
+
|
|
269
|
+
```
|
|
270
|
+
DEBUG REPORT
|
|
271
|
+
════════════════════════════════════════
|
|
272
|
+
Bug: <description>
|
|
273
|
+
Hypothesis: <what you predicted> → <confirmed or actual cause>
|
|
274
|
+
Root cause: <what was actually wrong>
|
|
275
|
+
Files changed: [all production files touched]
|
|
276
|
+
Fix: <file:line — what changed>
|
|
277
|
+
Evidence: <paste raw failing-then-passing test output, verbatim>
|
|
278
|
+
Regression test: <file:test name>
|
|
279
|
+
Full suite: All passing ✓
|
|
280
|
+
Similar risk: [SIMILAR_RISK findings from Phase 2 scan, or "none"]
|
|
281
|
+
Behavior Matrix: <BM.AS-NNN.surface | GAP-NNN | NO_CELL | N/A>
|
|
282
|
+
Invariant: <matched invariant / new invariant recommended / none>
|
|
283
|
+
Manual needed: [→MANUAL gaps, or "none"]
|
|
284
|
+
Status: DONE | DONE_WITH_CONCERNS | BLOCKED
|
|
285
|
+
════════════════════════════════════════
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Spec Update Signal
|
|
289
|
+
|
|
290
|
+
After fixing, check these conditions. If ANY is true → **must** signal.
|
|
291
|
+
|
|
292
|
+
**Signal when (MUST):**
|
|
293
|
+
|
|
294
|
+
| # | Condition |
|
|
295
|
+
|---|-----------|
|
|
296
|
+
| S1 | Fix covers an edge case or error path with no corresponding AS in the spec |
|
|
297
|
+
| S2 | Bug existed because an AS described wrong behavior — After fix, code and AS now conflict |
|
|
298
|
+
| S3 | Fix adds a new constraint or guard (null check, balance guard, validation) not in spec |
|
|
299
|
+
| S4 | Bug maps to `NO_CELL`, `GAP-NNN`, or suspicious `N/A` in `## Behavior Matrix` |
|
|
300
|
+
| S5 | Fix reveals a repeated lifecycle/parity/cascade invariant not present in invariant logs |
|
|
301
|
+
|
|
302
|
+
**Do not signal when:**
|
|
303
|
+
- Fix is a clear typo/off-by-one — code was always wrong relative to spec, no new behavior
|
|
304
|
+
- Performance-only fix — output unchanged
|
|
305
|
+
|
|
306
|
+
**Signal format:**
|
|
307
|
+
```
|
|
308
|
+
⚠️ Spec Update Needed — run `/sp-plan docs/specs/<feature>/<feature>.md '<describe change>'`
|
|
309
|
+
Reason: [S1 | S2 | S3 | S4 | S5] — <one line: what is missing or mismatched>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
If S5 applies, also emit:
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
⚠️ Invariant Log Update Needed
|
|
316
|
+
Component: <component/module>
|
|
317
|
+
Invariant: <state/viewer/surface rule that must stay true>
|
|
318
|
+
Reason: repeated bug class — <carry-forward/viewer-relative/invite-on-reschedule/orphan/etc.>
|
|
319
|
+
Suggested registry path: docs/invariants/INV-###-<short-name>.md
|
|
320
|
+
Suggested status: candidate (promote to confirmed when accepted; enforced only when test_ref exists and passes)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Multiple Bugs
|
|
324
|
+
|
|
325
|
+
If `$ARGUMENTS` describes multiple bugs: triage by severity, fix one at a time, commit each separately.
|
|
326
|
+
|
|
327
|
+
## Rules
|
|
328
|
+
1. **Investigate before coding.** Root cause hypothesis before test. Evidence before fix.
|
|
329
|
+
2. **Minimal fix.** One bug, one change. Don't improve the neighborhood.
|
|
330
|
+
3. **Never weaken tests.** If existing tests break, the fix is wrong.
|
|
331
|
+
4. **Ask before touching production code** if unsure.
|
|
332
|
+
5. **One bug, one commit.** Each fix independently revertable.
|
|
333
|
+
|
|
334
|
+
**Red flags — slow down if you see these:**
|
|
335
|
+
- "Quick fix for now" — there is no "for now". Fix it right or escalate.
|
|
336
|
+
- Proposing a fix before tracing data flow — you're guessing, not debugging.
|
|
337
|
+
- Each fix reveals a new problem elsewhere — wrong layer, not wrong code.
|
|
338
|
+
- Never say "this should fix it" — verify and prove it. Run the tests.
|
|
@@ -113,6 +113,46 @@ If 2+ required fields are missing → ask ONE question via `AskUserQuestion`:
|
|
|
113
113
|
|
|
114
114
|
**Do NOT proceed past Phase 1 without clear symptom + expected + actual.**
|
|
115
115
|
|
|
116
|
+
### 1.5 — Behavior Matrix context
|
|
117
|
+
|
|
118
|
+
If the report mentions status/state, role/viewer, list/detail/worklist/dashboard/feed/API/email/calendar, notification, external provider, or cross-module inconsistency, look for a related spec with `## Behavior Matrix`. Use the invariant registry README/schema as base knowledge; README examples are not runtime entries. Then read project-local invariant entries if present:
|
|
119
|
+
|
|
120
|
+
- `docs/specs/<feature>/<feature>.md`
|
|
121
|
+
- `docs/invariants/INV-*.md`
|
|
122
|
+
|
|
123
|
+
Record the current mapping hypothesis. This is allowed to be partial until Phase 4:
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
BM CONTEXT
|
|
127
|
+
═══════════════════════════════
|
|
128
|
+
State/status: <state or transition | unknown>
|
|
129
|
+
Viewer/role: <actor/viewer/relationship | unknown>
|
|
130
|
+
Surface/path: <list/detail/API/feed/calendar/etc. | unknown>
|
|
131
|
+
Matrix cell: BM.AS-NNN.<surface> | GAP-NNN | N/A:<reason> | NO_CELL | unknown
|
|
132
|
+
Invariant match: <INV/C id + status | invariant text | none | no registry found>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
If no spec or invariant registry exists, continue. Do not invent one during investigation; report the absence as a gap if it matters. If the bug confirms a repeated lifecycle/parity/cascade rule, end the report with `Invariant action needed: add/update invariant: ...`.
|
|
136
|
+
|
|
137
|
+
### 1.6 — Sibling Discovery Pass (candidate only)
|
|
138
|
+
|
|
139
|
+
Run this for lifecycle/parity/cascade bugs, existing-operation investigations, or any report whose symptom names one surface but the operation may exist on sibling entry-points.
|
|
140
|
+
|
|
141
|
+
Purpose: diagnose blast radius before deciding root cause. This produces candidates, not requirements or fixes.
|
|
142
|
+
|
|
143
|
+
1. Seed nouns/verbs from the raw symptom, touched component, related spec/BM context, and matching invariant entries.
|
|
144
|
+
2. Find shared-anchor callers (`ga_callers` if GA is available; otherwise grep) for helpers/constants/schemas that define the operation.
|
|
145
|
+
3. Fuzzy-search parallel names such as `create_from_*`, `*_from_<source>`, `send_*invite*`, `*_outcome*`, `reschedule*`, `book_next*`, `cancel*`, `delete*`, plus domain verbs from the symptom.
|
|
146
|
+
4. Inspect recent git co-change around touched files (`git log --name-only -- <seed-file>`) for repeatedly paired files/functions.
|
|
147
|
+
|
|
148
|
+
Record a `Sibling Candidate Table` in the investigation output:
|
|
149
|
+
|
|
150
|
+
| Candidate | Operation | Evidence | Confidence | Investigation disposition |
|
|
151
|
+
|---|---|---|---|---|
|
|
152
|
+
| `<surface/path/symbol>` | same create/update/delete/send/read op? | ga_callers / grep / co-change / invariant / symptom | high / medium / low | likely-related / needs-spec-GAP / ignore(reason) |
|
|
153
|
+
|
|
154
|
+
Do not auto-fix candidates. `likely-related` means the candidate belongs in the root-cause/blast-radius analysis. `needs-spec-GAP` means the report exposes an underspecified sibling. `ignore(reason)` must name why the candidate is false positive or out of scope.
|
|
155
|
+
|
|
116
156
|
---
|
|
117
157
|
|
|
118
158
|
## Phase 2: Locate
|
|
@@ -249,6 +289,9 @@ Don't mechanically check every row — scan for patterns that FIT the evidence y
|
|
|
249
289
|
| 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
290
|
| 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
291
|
| 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? |
|
|
292
|
+
| 13 | **Lifecycle / viewer / surface parity** | Correct on one status/role/surface but wrong on another | Map state x viewer x surface; compare write model, read models, queues, dashboard counts, feed, APIs, notifications, calendar |
|
|
293
|
+
| 14 | **Cascade propagation gap** | Write succeeds but derived surfaces are stale/missing | Trace write side effects into projections, cache invalidation, event handlers, queues, external integrations |
|
|
294
|
+
| 15 | **External-down divergence** | Internal state updates but provider/email/calendar state is wrong or invisible | Trace retry queue, provider status, user-visible retry surface, idempotency key |
|
|
252
295
|
|
|
253
296
|
For each matching pattern, record:
|
|
254
297
|
```
|
|
@@ -313,6 +356,13 @@ Chain: <input> → <step 1> → <step 2> → ... → <symptom>
|
|
|
313
356
|
Disproof: <what evidence would prove this wrong>
|
|
314
357
|
Confidence: HIGH / MEDIUM / LOW
|
|
315
358
|
Basis: <list evidence that supports this>
|
|
359
|
+
Behavior Matrix:
|
|
360
|
+
State/status: <state or transition>
|
|
361
|
+
Viewer/role: <viewer/relationship>
|
|
362
|
+
Surface/path: <surface>
|
|
363
|
+
Cell: BM.AS-NNN.<surface> | GAP-NNN | N/A:<reason> | NO_CELL
|
|
364
|
+
Spec gap: none | gap-open | suspicious-N/A | missing-cell
|
|
365
|
+
Invariant: <matched invariant | new invariant candidate | none>
|
|
316
366
|
```
|
|
317
367
|
|
|
318
368
|
### Confidence Levels
|
|
@@ -455,6 +505,10 @@ User-facing impact:
|
|
|
455
505
|
- <feature/screen> — user sees <wrong behavior>
|
|
456
506
|
- <API endpoint> — returns <wrong response>
|
|
457
507
|
|
|
508
|
+
Behavior Matrix impact:
|
|
509
|
+
- <BM.AS-NNN.surface> — <broken state/viewer/surface behavior>
|
|
510
|
+
- <GAP-NNN or NO_CELL> — <spec hole exposed by bug>
|
|
511
|
+
|
|
458
512
|
Impact scope: ISOLATED | MODULE | CROSS-MODULE | SYSTEM-WIDE
|
|
459
513
|
```
|
|
460
514
|
|
|
@@ -518,6 +572,7 @@ RECOMMENDED ACTIONS
|
|
|
518
572
|
|
|
519
573
|
Test strategy:
|
|
520
574
|
- Regression test: <what to test, at what level (unit/integration)>
|
|
575
|
+
- Behavior Matrix regression: <BM.AS-NNN.surface test name, or "spec gap before test">
|
|
521
576
|
- Existing tests to verify: <list test names that should still pass>
|
|
522
577
|
- Manual verification: <what to check visually, if applicable>
|
|
523
578
|
|
|
@@ -558,6 +613,13 @@ HYPOTHESIS A (PRIMARY — <confidence>)
|
|
|
558
613
|
Location: <file:line>
|
|
559
614
|
Mechanism: <what is wrong>
|
|
560
615
|
Chain: <cause> → <step> → ... → <symptom>
|
|
616
|
+
Behavior Matrix:
|
|
617
|
+
State/status: <state or transition>
|
|
618
|
+
Viewer/role: <viewer/relationship>
|
|
619
|
+
Surface/path: <surface>
|
|
620
|
+
Cell: BM.AS-NNN.<surface> | GAP-NNN | N/A:<reason> | NO_CELL
|
|
621
|
+
Spec gap: none | gap-open | suspicious-N/A | missing-cell
|
|
622
|
+
Invariant: <matched invariant | new invariant candidate | none>
|
|
561
623
|
Evidence:
|
|
562
624
|
- <file:line> — <what this code shows>
|
|
563
625
|
- <git commit> — <what this change reveals>
|
|
@@ -593,6 +655,14 @@ These are inputs for refactor/tech-debt decisions, not immediate fixes.
|
|
|
593
655
|
Scope: <ISOLATED | MODULE | CROSS-MODULE | SYSTEM-WIDE>
|
|
594
656
|
<Impact details from Phase 5.2>
|
|
595
657
|
|
|
658
|
+
─── BEHAVIOR MATRIX IMPACT ───
|
|
659
|
+
Cells:
|
|
660
|
+
- <BM.AS-NNN.surface> — <affected behavior>
|
|
661
|
+
- <GAP-NNN / NO_CELL> — <spec hole if found>
|
|
662
|
+
State/viewer/surface class: <lifecycle | viewer-parity | surface-parity | cascade | external-down | other>
|
|
663
|
+
Spec action needed: <none | resolve GAP | add matrix cell | correct suspicious N/A | update AS wording>
|
|
664
|
+
Invariant action needed: <none | add/update invariant: ...>
|
|
665
|
+
|
|
596
666
|
─── SIMILAR RISK ───
|
|
597
667
|
(omit if scan skipped)
|
|
598
668
|
<Findings from Phase 5.3>
|