Skip to content

Commit 342b74e

Browse files
committed
feat(fix): add Phase 0 pre-flight, scope guard, third-party guard, mandatory validation step, trim redundancy
1 parent e77c3cf commit 342b74e

2 files changed

Lines changed: 296 additions & 74 deletions

File tree

templates/commands/fix.md

Lines changed: 147 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,6 @@ You **MUST** consider the user input before proceeding (if not empty). This may
1515

1616
---
1717

18-
## Identity & role
19-
20-
You are a surgical correction agent operating inside a Spec Kit project. Your sole purpose: **receive errors (screenshots, logs, messages), diagnose them, and apply fixes directly** — in both `.md` spec files AND source code — without waiting for intermediate validation.
21-
22-
You do not vibe-code. You read the plan before writing a single line.
23-
24-
---
25-
26-
## Accepted triggers
27-
28-
You are activated by:
29-
- A screenshot of an error (UI, terminal, browser, IDE)
30-
- A log block pasted directly in chat
31-
- An error message (`TypeError`, `500`, `FAILED`, `ModuleNotFoundError`, etc.)
32-
- A link or path to a broken file
33-
34-
---
35-
3618
## Interactions with other Spec Kit commands
3719

3820
`/speckit.fix` does not work in isolation. It knows the role of every command in the workflow and knows exactly when to invoke or reference each one. Full map:
@@ -49,47 +31,100 @@ You are activated by:
4931
/speckit.fix → (you) post-implementation error correction
5032
```
5133

52-
### When `/speckit.fix` interacts with each command
34+
---
5335

54-
| Command | `/speckit.fix` interacts when... | Action taken by `/speckit.fix` |
36+
## Data Path Quick Reference
37+
38+
Every project has a data flow chain, but naming varies by framework and architecture.
39+
**Step 1: identify the project's own chain from the stack trace paths and directory names.**
40+
**Step 2: map the error to a functional role. Fix the role where the error *originates*, not where it *surfaces*.**
41+
42+
### Step 1 — Infer the project's chain
43+
44+
Look at the file paths in the stack trace (or the `FEATURE_DIR` structure). Match against the most common patterns:
45+
46+
| Pattern | Typical chain | Common in |
5547
|---|---|---|
56-
| `constitution` | The fix violates or exceeds a governing principle | Flag the conflict, **do not fix** — this file is read-only |
57-
| `specify` | The error reveals unspecified behaviornew feature needed | Produce a ready-to-use `/speckit.specify` prompt (Phase 2b) |
58-
| `clarify` | The spec is ambiguous and multiple interpretations are possible | Recommend `/speckit.clarify` before proceeding |
59-
| `plan` | The fix requires revisiting an architectural decision | Update `plan.md` AND flag that `/speckit.plan` must be re-validated |
60-
| `analyze` | The fix touches multiple features or creates cross-artifact inconsistency | Recommend `/speckit.analyze` after applying the fix |
61-
| `tasks` | A task in `tasks.md` is missing, mis-ordered, or poorly defined | Update `tasks.md` directly; add any missing tasks |
62-
| `implement` | The fix corrects an incomplete implementation of an existing task | Fix the code AND mark the relevant task in `tasks.md` |
63-
| `taskstoissues` | After the fix, uncovered edge cases should be tracked as issues | Suggest `/speckit.taskstoissues` to open them |
48+
| `views/`, `serializers/`, `models/` | `urls → middleware → view → serializer → model → db` | Django, DRF |
49+
| `controllers/`, `services/`, `models/` | `router → middlewarecontroller → service → model → db` | Express, NestJS, Laravel, Rails |
50+
| `handlers/`, `usecases/`, `repositories/` | `handler → use case → repository → data source` | Clean Architecture, Hexagonal |
51+
| `resolvers/`, `schema/` | `query → resolver → data loader → db` | GraphQL (Apollo, Strawberry) |
52+
| `commands/`, `lib/`, `cli/` | `entrypoint → argument parser → command → lib` | CLI tools |
53+
| `consumers/`, `producers/`, `aggregates/` | `event bus → consumer → aggregate → event store` | Event-driven, CQRS |
54+
| `components/`, `hooks/`, `store/` | `component → hook/store → api client → backend` | React, Vue, Angular (frontend only) |
55+
| `functions/`, `triggers/` | `trigger → function → external service` | Serverless (Lambda, Azure Functions) |
6456

65-
### Decision rules at a glance
57+
If the project does not match any pattern, derive the chain from the actual directory names present in the stack trace. Name each role yourself — do not force a known pattern.
6658

67-
```
68-
error received
69-
70-
├─ violates constitution.md?
71-
│ └─ YES → STOP. Explain the conflict. No changes made.
72-
73-
├─ behavior absent from all specs?
74-
│ └─ YES → STOP. Phase 2b → propose /speckit.specify
75-
76-
└─ fix within current scope
77-
├─ purely technical → fix code only
78-
├─ ambiguous spec → fix + update spec.md
79-
│ + recommend /speckit.clarify if doubt remains
80-
├─ incorrect technical plan → fix + update plan.md
81-
│ + flag re-validation via /speckit.plan
82-
├─ missing or broken task → fix + update tasks.md
83-
└─ cross-feature inconsistency → fix + recommend /speckit.analyze
84-
```
59+
### Step 2 — Map the error signature to a functional role
60+
61+
Use **functional role names** that map to the project's own naming:
62+
63+
| Error signature | Functional role | Typical files (adapt to project) |
64+
|---|---|---|
65+
| `IntegrityError`, `OperationalError`, `ColumnNotFound`, `ForeignKeyViolation` | **data-access** | `models/`, `repositories/`, `entities/`, `dao/` |
66+
| `ValidationError`, `SchemaError`, `SerializerError`, `422 Unprocessable` | **validation** | `serializers/`, `schemas/`, `validators/`, `forms/` |
67+
| `AttributeError`, `TypeError`, `KeyError` inside a logic file | **business-logic** | `services/`, `usecases/`, `domain/`, `lib/` |
68+
| `500 Internal Server Error`, unhandled exception in entry point | **entry-point** | `views/`, `controllers/`, `handlers/`, `resolvers/` |
69+
| `401 Unauthorized`, `403 Forbidden`, `InvalidTokenError` | **guard** | `middleware/`, `auth/`, `guards/`, `interceptors/` |
70+
| `404 Not Found`, route/path not matched | **routing** | `urls.py`, `routes/`, `router.*`, `app.*` |
71+
| `ModuleNotFoundError`, `ImportError` | **config** | the importing file only |
72+
| `FAILED tests/test_<name>.*::test_<fn>` | **test** | `tests/test_<name>.*` + the file under test |
73+
| JS/TS `TypeError`, `Cannot read properties of undefined` | **ui** | `components/`, `pages/`, `views/` (frontend) |
74+
| `fetch failed`, `axios error`, `CORS`, network error on client | **api-bridge** | `services/api.*`, `client.*`, `middleware/cors.*` |
75+
76+
**Rule: fix the functional role where the error *originates*, not where it *surfaces*.**
77+
A `NullPointerException` at the entry point often originates in the data-access layer returning `None`.
78+
An HTTP 500 in a view often originates in the business-logic layer throwing an uncaught exception.
79+
80+
---
81+
82+
## Phase 0 — Pre-flight
83+
84+
Before any extraction or triage, run these four checks in order. Each one can short-circuit the full workflow.
85+
86+
### 0.1 — Confidence threshold
87+
88+
If the input is too incomplete to triage (truncated log, blurry screenshot, ambiguous description), **do not guess**. Ask exactly one targeted question:
89+
90+
> "To diagnose this precisely, I need: [the one missing piece — full stack trace / the file path / the action that triggered the error]. Can you provide it?"
91+
92+
Do not proceed until you have enough information to fill the TRIAGE block.
93+
94+
### 0.2 — Multi-error input
95+
96+
If the input contains more than one distinct error (multiple FAILED tests, multiple exceptions):
97+
1. List all errors found.
98+
2. Identify the **most blocking** one (the one that causes others downstream, or the first in the execution chain).
99+
3. Fix that one first. State explicitly: _"Fixing [error A] first. [Error B] and [Error C] are noted and will be addressed next if still present."_
100+
101+
### 0.3 — Recurrent error check
102+
103+
If `specs/[feature]/fix.md` exists, scan it (titles only — do not read full entries) before diagnosing:
104+
- If a previous `FIX-NNN` entry addresses the same error → read that entry's `ROOT CAUSE` and `Decisions` sections before building the TRIAGE.
105+
- If a previous fix was applied and the error recurred → the root cause was misidentified. Flag this explicitly in Phase 2: `RECURRENT: YES — previous fix FIX-NNN did not resolve the root cause`.
106+
107+
### 0.4 — Trivial fast path
108+
109+
If the error is trivially identifiable (one of the below), skip Phases 1–2 entirely and go directly to Phase 3:
110+
111+
| Trivial error | Direct action |
112+
|---|---|
113+
| `SyntaxError` with file:line | Open the file, fix the syntax, done |
114+
| `ModuleNotFoundError: No module named 'x'` | Add the import or install the dependency |
115+
| `NameError: name 'x' is not defined` | Check for typo or missing import |
116+
| Typo in a config key (e.g. `DATABSE_URL`) | Fix the key name, done |
117+
| `IndentationError` | Fix indentation at the given line |
118+
119+
For trivial fixes: write the `fix.md` entry with `SCOPE: 1 file`, skip Phase 4 invariants (write `not applicable — trivial fix`).
85120

86121
---
87122

88123
## Phase 1 — Extraction & Context reading
89124

90125
### 1.1 Extract the error
91126

92-
Run `{SCRIPT}` once from repo root and parse the JSON output. Derive `FEATURE_DIR` and `AVAILABLE_DOCS`.
127+
If `FEATURE_DIR` is not identifiable from the stack trace paths, run `{SCRIPT}` from repo root to derive it.
93128

94129
If an image is provided, extract:
95130
- The **exact error message** (verbatim text)
@@ -101,20 +136,39 @@ If code or logs are pasted, identify:
101136
- The first abnormal line (the true entry point of the error)
102137
- The call chain that led to this state
103138

104-
### 1.2 Read the plan and specs
139+
### 1.2 Triage — classify the error
105140

106-
**Before any correction**, read in this order:
141+
**Before opening any file**, produce this block from the error message and stack trace alone (zero file I/O):
107142

108143
```
109-
1. .specify/memory/constitution.md → project governing principles
110-
2. .specify/specs/<feature>/spec.md → user stories and requirements
111-
3. .specify/specs/<feature>/plan.md → technical plan
112-
4. .specify/specs/<feature>/tasks.md → tasks, dependencies, status
144+
TRIAGE
145+
Error type : [ValueError | HTTP 500 | FAILED | TypeError | etc.]
146+
Stack entry : [file:line — the exact line that threw]
147+
Role : [functional role in this project's chain — e.g. data-access | validation | business-logic | entry-point | guard | routing | ui | api-bridge | config | test]
148+
Read set : [2–5 files to open — derived from the Data Path Quick Reference — and nothing else]
113149
```
114150

115-
If multiple features exist, identify the one related to the error (module name, endpoint, component).
151+
Use **Step 1** of the Data Path Quick Reference to identify the project's own chain, then **Step 2** to map the error signature to a functional role. Open only the files listed in `Read set`.
152+
153+
If multiple features exist, identify the one related to the error (module name, endpoint, component) before building the read set.
154+
155+
**Third-party guard**: if `Stack entry` points to a file inside `node_modules/`, `site-packages/`, `vendor/`, or any external dependency directory, the bug is in your call site, not in the library. Shift `Stack entry` to the last in-project frame in the stack trace, and derive `Read set` from that frame instead.
156+
157+
### 1.3 Selective spec read
116158

117-
Ask yourself after reading:
159+
Read spec/plan/tasks **only if** one of these conditions holds after the triage — otherwise skip directly to Phase 2:
160+
161+
| Condition | What to read |
162+
|---|---|
163+
| The fix would change a public API or data contract | `plan.md` — the relevant section only |
164+
| The expected behavior is unclear from the code alone | `spec.md` — the section relevant to the broken feature only |
165+
| A task is confirmed missing or wrongly sequenced | `tasks.md` only |
166+
| The fix may violate a project-wide constraint | `constitution.md` — if violated, **STOP** |
167+
| None of the above | **Read nothing.** Fix directly from the Read Set. |
168+
169+
`constitution.md` is **never** read proactively — only as a guard when a fix might violate it.
170+
171+
After reading (if applicable):
118172
- **Does the fix violate a principle in `constitution.md`?** → if yes, STOP
119173
- **Does the error come from a gap between the plan and the implementation?**
120174
- **Does the spec describe a different behavior from what is coded?**
@@ -125,15 +179,19 @@ Ask yourself after reading:
125179

126180
## Phase 2 — Structured diagnosis
127181

128-
Produce a 4-point diagnosis before writing anything:
182+
Produce a layered diagnosis before writing anything:
129183

130184
```
131-
ROOT CAUSE : [precise technical cause, 1 sentence]
132-
SPEC IMPACT : [none / spec.md / plan.md / tasks.md / multiple artifacts]
185+
LAYER : [functional role in this project — e.g. data-access | validation | business-logic | entry-point | guard | routing | ui | api-bridge | config | test]
186+
ROOT CAUSE : [precise technical cause, 1 sentence, referencing file:line]
187+
CHAIN IMPACT : [does this error propagate to upstream roles? YES / NO — which ones?]
188+
SPEC IMPACT : [none | spec.md | plan.md | tasks.md | multiple — only if triage triggered a read]
133189
NEW FEATURE : [YES / NO — does a full resolution require behavior absent from all specs?]
134-
SCOPE : [exhaustive list of files to modify — .md and/or code]
190+
SCOPE : [2–5 files maximum — code files only unless spec read was triggered]
135191
```
136192

193+
**If `SCOPE` lists more than 5 files → this is not a fix, it is a refactoring. Stop. Recommend `/speckit.plan` to revisit the architecture before proceeding.**
194+
137195
**If `NEW FEATURE = YES` → stop immediately and go to Phase 2b. Do not modify any file.**
138196

139197
---
@@ -210,6 +268,21 @@ Failure case: if no alternative action exists, the message states this clearly."
210268

211269
---
212270

271+
### When `/speckit.fix` interacts with each command
272+
273+
| Command | `/speckit.fix` interacts when... | Action taken by `/speckit.fix` |
274+
|---|---|---|
275+
| `constitution` | The fix violates or exceeds a governing principle | Flag the conflict, **do not fix** — this file is read-only |
276+
| `specify` | The error reveals unspecified behavior → new feature needed | Produce a ready-to-use `/speckit.specify` prompt (Phase 2b) |
277+
| `clarify` | The spec is ambiguous and multiple interpretations are possible | Recommend `/speckit.clarify` before proceeding |
278+
| `plan` | The fix requires revisiting an architectural decision | Update `plan.md` AND flag that `/speckit.plan` must be re-validated |
279+
| `analyze` | The fix touches multiple features or creates cross-artifact inconsistency | Recommend `/speckit.analyze` after applying the fix |
280+
| `tasks` | A task in `tasks.md` is missing, mis-ordered, or poorly defined | Update `tasks.md` directly; add any missing tasks |
281+
| `implement` | The fix corrects an incomplete implementation of an existing task | Fix the code AND mark the relevant task in `tasks.md` |
282+
| `taskstoissues` | After the fix, uncovered edge cases should be tracked as issues | Suggest `/speckit.taskstoissues` to open them |
283+
284+
---
285+
213286
## Phase 3 — Applying corrections
214287

215288
### Absolute rules
@@ -273,6 +346,20 @@ Examples:
273346

274347
For each edge case listed → evaluate whether a follow-up issue is warranted and suggest `/speckit.taskstoissues` if so.
275348

349+
### Validation test (mandatory)
350+
351+
Before moving to Phase 5, state how to verify the fix is effective:
352+
353+
```
354+
VALIDATION : [exact command, scenario, or navigation path that confirms the error is gone
355+
— e.g. "run pytest tests/test_payment.py::test_transfer",
356+
"POST /api/orders with missing field → expect 422 not 500",
357+
"navigate to /checkout as anonymous user → expect redirect to /login"]
358+
```
359+
360+
If no automated test covers this scenario → flag it:
361+
`COVERAGE GAP: this fix has no automated test. Consider adding one via /speckit.tasks.`
362+
276363
---
277364

278365
## Phase 5 — Write to fix.md + final report
@@ -314,20 +401,6 @@ After writing to `fix.md`, display this summary in the conversation:
314401
315402
**Edge cases not covered**:
316403
- [list — full honesty]
317-
318-
**Suggested validation test**:
319-
- [how to reproduce the corrected scenario to verify the fix]
320404
```
321405

322-
---
323-
324-
## Forbidden behaviors
325406

326-
- ❌ Modifying code without having read `constitution.md` and the specs
327-
- ❌ Fixing the implementation when the spec itself is wrong
328-
- ❌ Implementing a new feature without going through `/speckit.specify` — even if it "seems simple"
329-
- ❌ Modifying `constitution.md` — this file is **read-only** for `/speckit.fix`
330-
- ❌ Fixing "in the general direction" without identifying the exact root cause
331-
- ❌ Ignoring edge cases — list them explicitly even when not addressed
332-
- ❌ Refactoring healthy code under the pretense of proximity to the fix
333-
- ❌ Moving to Phase 3 without producing the complete Phase 2 diagnosis

0 commit comments

Comments
 (0)