@renzrollon/interlock 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.
- package/.claude-plugin/marketplace.json +19 -0
- package/.claude-plugin/plugin.json +58 -0
- package/CHANGELOG.md +380 -0
- package/LICENSE +21 -0
- package/README.md +358 -0
- package/agents/ping.md +8 -0
- package/agents/worker.md +8 -0
- package/bin/interlock +2655 -0
- package/bin/interlock-graph +6 -0
- package/bin/interlock-run +508 -0
- package/bin/interlock-ship-acp +39 -0
- package/hooks/_shared.mjs +162 -0
- package/hooks/guard-commit.mjs +77 -0
- package/hooks/guard-tasks.mjs +107 -0
- package/hooks/guard-tests.mjs +63 -0
- package/hooks/preflight.mjs +107 -0
- package/lib/artifacts.mjs +316 -0
- package/lib/autonomy.mjs +149 -0
- package/lib/conformance.mjs +132 -0
- package/lib/doctor.mjs +1176 -0
- package/lib/drift.mjs +409 -0
- package/lib/eval-history.mjs +304 -0
- package/lib/evals-calibrate.mjs +317 -0
- package/lib/evals-capture.mjs +437 -0
- package/lib/evals-promote.mjs +257 -0
- package/lib/evals-triage.mjs +216 -0
- package/lib/findings.mjs +340 -0
- package/lib/graph/cli.mjs +266 -0
- package/lib/graph/extract/config-json.mjs +74 -0
- package/lib/graph/extract/create-extractor.mjs +35 -0
- package/lib/graph/extract/memory.mjs +99 -0
- package/lib/graph/extract/openspec.mjs +80 -0
- package/lib/graph/extract/python.mjs +137 -0
- package/lib/graph/extract/regex-fallback.mjs +187 -0
- package/lib/graph/extract/shell.mjs +71 -0
- package/lib/graph/extract/typescript.mjs +217 -0
- package/lib/graph/extract/walk.mjs +272 -0
- package/lib/graph/format.mjs +51 -0
- package/lib/graph/graph/build.mjs +374 -0
- package/lib/graph/graph/query.mjs +249 -0
- package/lib/graph/graph/report.mjs +122 -0
- package/lib/graph/graph/update.mjs +47 -0
- package/lib/graph/paths.mjs +66 -0
- package/lib/graph/retrieve/context.mjs +86 -0
- package/lib/graph/retrieve/docs-index.mjs +116 -0
- package/lib/graph/retrieve/markdown.mjs +246 -0
- package/lib/host/acp.mjs +551 -0
- package/lib/host/claude-cli.mjs +285 -0
- package/lib/host/codex.mjs +231 -0
- package/lib/host/model-map.mjs +129 -0
- package/lib/host/qwen.mjs +176 -0
- package/lib/host/registry.mjs +213 -0
- package/lib/host.mjs +393 -0
- package/lib/ledger.mjs +444 -0
- package/lib/limits.mjs +525 -0
- package/lib/locators.mjs +99 -0
- package/lib/merge-lanes.mjs +148 -0
- package/lib/metrics.mjs +99 -0
- package/lib/notify.mjs +229 -0
- package/lib/outcomes.mjs +560 -0
- package/lib/plan-fingerprint.mjs +570 -0
- package/lib/project-slug.mjs +18 -0
- package/lib/prompts/commit.mjs +26 -0
- package/lib/prompts/dimensions.mjs +70 -0
- package/lib/prompts/handoff.mjs +86 -0
- package/lib/prompts/implementer.mjs +150 -0
- package/lib/prompts/index.mjs +250 -0
- package/lib/prompts/planner.mjs +70 -0
- package/lib/prompts/remediate.mjs +137 -0
- package/lib/prompts/replan.mjs +23 -0
- package/lib/prompts/review.mjs +107 -0
- package/lib/prompts/schemas.mjs +206 -0
- package/lib/prompts/stage.mjs +48 -0
- package/lib/prompts/verify.mjs +88 -0
- package/lib/ready.mjs +812 -0
- package/lib/receipt.mjs +434 -0
- package/lib/remediate.mjs +275 -0
- package/lib/report-html.mjs +623 -0
- package/lib/report.mjs +1124 -0
- package/lib/review-core.mjs +713 -0
- package/lib/risk.mjs +370 -0
- package/lib/run-log.mjs +1004 -0
- package/lib/run-paths.mjs +239 -0
- package/lib/run.mjs +2921 -0
- package/lib/ship-stage.mjs +223 -0
- package/lib/spill.mjs +150 -0
- package/lib/surface.mjs +195 -0
- package/lib/verify.mjs +1074 -0
- package/lib/waves.mjs +2661 -0
- package/package.json +40 -0
- package/shared/CONTEXT-HYGIENE.md +84 -0
- package/shared/DECISION-LEDGER.md +141 -0
- package/shared/EXPLORE-BRIEF.md +96 -0
- package/shared/INVARIANT-SWEEP.md +57 -0
- package/shared/SESSION-SHAPES.md +261 -0
- package/shared/SKILL-CANDIDATE-BRIEF.md +106 -0
- package/shared/TEST-PROFILE.md +204 -0
- package/shared/TOOL-ECONOMY.md +155 -0
- package/skills/bootstrap/SKILL.md +226 -0
- package/skills/commit/SKILL.md +99 -0
- package/skills/dispatch/SKILL.md +78 -0
- package/skills/docs-digest/SKILL.md +109 -0
- package/skills/evals/SKILL.md +160 -0
- package/skills/explain-code/SKILL.md +42 -0
- package/skills/explain-code/commit-teachin.md +136 -0
- package/skills/explain-code/module-walkthrough.md +358 -0
- package/skills/explore/SKILL.md +159 -0
- package/skills/fix-tests/SKILL.md +120 -0
- package/skills/graph/SKILL.md +136 -0
- package/skills/manual-test-plan/SKILL.md +121 -0
- package/skills/mr/SKILL.md +170 -0
- package/skills/report/SKILL.md +121 -0
- package/skills/review-artifacts/SKILL.md +127 -0
- package/skills/review-code/REVIEW.template.md +49 -0
- package/skills/review-code/SKILL.md +156 -0
- package/skills/review-code/dimensions/architecture.md +10 -0
- package/skills/review-code/dimensions/devops.md +12 -0
- package/skills/review-code/dimensions/language.md +12 -0
- package/skills/review-code/dimensions/qa.md +12 -0
- package/skills/review-code/dimensions/security.md +12 -0
- package/skills/review-code/dimensions/technical-lead.md +19 -0
- package/skills/ship/SKILL.md +67 -0
- package/skills/spec/SKILL.md +264 -0
- package/skills/spec/continuity.md +66 -0
- package/workflows/ship.js +565 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# Module walkthrough — explain-code
|
|
2
|
+
|
|
3
|
+
Teach TypeScript/React/Next.js code to a frontend beginner. Not reviewing — teaching.
|
|
4
|
+
|
|
5
|
+
## Scope
|
|
6
|
+
|
|
7
|
+
**Ecosystems covered:**
|
|
8
|
+
- TypeScript (strict mode, generics, utility types, Zod, discriminated unions)
|
|
9
|
+
- React 19 (hooks, components, context, refs, suspense, error boundaries)
|
|
10
|
+
- Next.js 15 App Router (server components, client components, server actions, route handlers, middleware, layouts, streaming)
|
|
11
|
+
- Related dependencies: Prisma ORM, Zustand, Radix UI, Tailwind CSS, better-auth, class-variance-authority
|
|
12
|
+
|
|
13
|
+
**Infrastructure & cloud services — always include when called:**
|
|
14
|
+
- PostgreSQL (via Prisma)
|
|
15
|
+
- AWS S3 (file storage/retrieval)
|
|
16
|
+
- AWS SQS (message queues)
|
|
17
|
+
- Any HTTP/REST calls to external services
|
|
18
|
+
- Authentication services (better-auth sessions)
|
|
19
|
+
|
|
20
|
+
**Context sources:**
|
|
21
|
+
- If `.claude/graph/DOCS_DIGEST.md` exists, Read it once as the domain primer (agent-only; see `/interlock:docs-digest`)
|
|
22
|
+
- Then use `interlock-graph context "<scope terms>" --budget 2000` for task-specific prose — do **not** read all of `docs/` upfront (see `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md` Rule 0.5)
|
|
23
|
+
- If graph missing: `interlock-graph docs "<terms>" --budget 800`, or grep headings in `docs/` then Read spans
|
|
24
|
+
|
|
25
|
+
**Files to explain:**
|
|
26
|
+
- **Module walkthrough:** every `.ts` / `.tsx` in the scoped tree (`src/`, `app/`, `lib/`, …)
|
|
27
|
+
- **Commit teach-in:** every source file touched in the commit range (skip binaries/lockfiles; cap ~25)
|
|
28
|
+
|
|
29
|
+
**Skip:**
|
|
30
|
+
- Test files (`*.test.ts`, `*.test.tsx`, `__tests__/`) — unless they are the only files in a commit teach-in and the user asked about them
|
|
31
|
+
- `node_modules/`, generated files, config files outside source trees
|
|
32
|
+
- Boilerplate: import statements, simple variable declarations, trivial type aliases, basic for loops
|
|
33
|
+
|
|
34
|
+
**This mode:** every `.ts` / `.tsx` in the scoped tree (`src/`, `app/`, `lib/`, …).
|
|
35
|
+
|
|
36
|
+
## Steps
|
|
37
|
+
|
|
38
|
+
1. Retrieve domain context on demand — Read `.claude/graph/DOCS_DIGEST.md` if present; then `interlock-graph context "<scope>" --budget 2000` (or `docs` with `--budget 800` if no graph). Do not preload every `docs/*.md`.
|
|
39
|
+
2. If `$ARGUMENTS` specifies a directory or file, explain only that scope; pass paths to `--changed` when using `context`.
|
|
40
|
+
3. If no arguments, use the graph to list modules/files in `app/`, `lib/`, `components/`, `types/`, and `prisma/` instead of blind `find`.
|
|
41
|
+
4. Graph-backed scope and call links: if `.claude/graph/graph.json` exists, use `interlock-graph explain <file>` and `interlock-graph consumers <symbol>` for **Called by** / **Calls into**. If missing and scope is large, `interlock-graph build .` once first.
|
|
42
|
+
5. Read each in-scope file; extract functions and logic blocks worth explaining (Read with offset/limit when locating via graph/grep).
|
|
43
|
+
6. Trace imports only where the graph is incomplete.
|
|
44
|
+
7. Order output: foundational files → data layer → components → pages/routes.
|
|
45
|
+
8. Build flow diagrams last; write to the output path resolved in `SKILL.md` — `docs/CODE_EXPLANATION.md` for an ad-hoc walkthrough, or `openspec/changes/<change-name>/code-explanation.md` when the walkthrough is scoped to an OpenSpec change.
|
|
46
|
+
|
|
47
|
+
## Per-file structure
|
|
48
|
+
|
|
49
|
+
### File Header (module walkthrough)
|
|
50
|
+
|
|
51
|
+
```markdown
|
|
52
|
+
## `src/path/to/file.ts`
|
|
53
|
+
|
|
54
|
+
**Role:** [one sentence — what this file's job is in the app]
|
|
55
|
+
**Called by:** [files that import from this one]
|
|
56
|
+
**Calls into:** [files this one imports, excluding node_modules]
|
|
57
|
+
**Infra/services touched:** [PostgreSQL, S3, SQS, external APIs — or "None"]
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Function/Block Breakdown
|
|
61
|
+
|
|
62
|
+
For each exported function, named function, or significant logic block:
|
|
63
|
+
|
|
64
|
+
```markdown
|
|
65
|
+
### `functionName(params)` → returnType
|
|
66
|
+
|
|
67
|
+
**What it does:** [1-2 sentences in plain language]
|
|
68
|
+
|
|
69
|
+
**How it works:**
|
|
70
|
+
- [Step-by-step walkthrough of the logic, skipping boilerplate]
|
|
71
|
+
- [Highlight conditionals, transformations, and side effects]
|
|
72
|
+
|
|
73
|
+
**Cross-file calls:**
|
|
74
|
+
- `helperFunction()` from `src/lib/helpers.ts` — [why it's called here]
|
|
75
|
+
- `prisma.user.findMany()` → PostgreSQL — [what data it fetches]
|
|
76
|
+
- `s3Client.send(PutObjectCommand)` → AWS S3 — [what it uploads and when]
|
|
77
|
+
|
|
78
|
+
**Pattern:** [Name the pattern if one applies]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## API & Data Flows (Required for route handlers and server actions)
|
|
82
|
+
|
|
83
|
+
### Route Handler Flow
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
### API Flow: `POST /api/v1/batches`
|
|
87
|
+
|
|
88
|
+
**Request:**
|
|
89
|
+
- Method: POST
|
|
90
|
+
- Body: `{ name: string, type: "BILLING" | "ACCRUAL", groupId: string }`
|
|
91
|
+
- Auth: Session cookie (better-auth)
|
|
92
|
+
- Headers: `Content-Type: application/json`
|
|
93
|
+
|
|
94
|
+
**Processing:**
|
|
95
|
+
1. Authenticate → `auth.api.getSession()` → checks session cookie
|
|
96
|
+
2. Authorize → `makeAuthorizationChecker()` → verifies user belongs to group
|
|
97
|
+
3. Validate → Zod schema `CreateBatchSchema` → rejects malformed input
|
|
98
|
+
4. Execute → `prisma.batch.create()` → **PostgreSQL** INSERT
|
|
99
|
+
5. Side effect → `sendToQueue()` → **AWS SQS** sends processing message
|
|
100
|
+
6. Respond → return created batch with 201
|
|
101
|
+
|
|
102
|
+
**Response:**
|
|
103
|
+
- 201: `{ id, name, type, status, createdAt }`
|
|
104
|
+
- 400: `{ error: "Validation failed", details: [...] }`
|
|
105
|
+
- 401: `{ error: "Unauthorized" }`
|
|
106
|
+
- 403: `{ error: "Forbidden" }`
|
|
107
|
+
|
|
108
|
+
**Flow diagram:**
|
|
109
|
+
```
|
|
110
|
+
Browser (fetch POST)
|
|
111
|
+
→ Next.js Route Handler (src/app/api/v1/batches/route.ts)
|
|
112
|
+
→ better-auth session check
|
|
113
|
+
→ Zod validation
|
|
114
|
+
→ Prisma ORM
|
|
115
|
+
→ [PostgreSQL] INSERT INTO batches
|
|
116
|
+
→ SQS client
|
|
117
|
+
→ [AWS SQS] SendMessage to processing queue
|
|
118
|
+
← 201 JSON response
|
|
119
|
+
← UI updates with new batch
|
|
120
|
+
```
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Server Action Flow
|
|
124
|
+
|
|
125
|
+
```markdown
|
|
126
|
+
### Server Action: `submitBatch(batchId)`
|
|
127
|
+
|
|
128
|
+
**Trigger:** Called from `SubmitButton` component via form action or onClick
|
|
129
|
+
**Input:** `batchId: string`
|
|
130
|
+
**Output:** `ActionResponse<{ batch: Batch }>` — `{ data }` or `{ error }`
|
|
131
|
+
|
|
132
|
+
**Flow:**
|
|
133
|
+
1. Client component calls `submitBatch(id)` — crosses network boundary
|
|
134
|
+
2. `'use server'` — executes on the server process, not the browser
|
|
135
|
+
3. `auth.api.getSession()` → validates session cookie
|
|
136
|
+
4. `makeAuthorizationChecker()` → checks SUBMIT permission on this batch
|
|
137
|
+
5. `prisma.batch.findUnique()` → **PostgreSQL** SELECT — verifies batch is DRAFT
|
|
138
|
+
6. `prisma.batch.update({ status: 'SUBMITTED' })` → **PostgreSQL** UPDATE
|
|
139
|
+
7. `sendToQueue(batch)` → **AWS SQS** — triggers async processing pipeline
|
|
140
|
+
8. Returns `{ data: { batch } }` to client component
|
|
141
|
+
9. Client re-renders with updated batch status
|
|
142
|
+
|
|
143
|
+
**Infra calls and when they happen:**
|
|
144
|
+
| Step | Service | Operation | Trigger condition |
|
|
145
|
+
|------|---------|-----------|-------------------|
|
|
146
|
+
| 3 | better-auth | Session lookup | Every call (authentication) |
|
|
147
|
+
| 5 | PostgreSQL | SELECT batch | After auth passes |
|
|
148
|
+
| 6 | PostgreSQL | UPDATE status | Only if batch is DRAFT |
|
|
149
|
+
| 7 | AWS SQS | SendMessage | Only after successful UPDATE |
|
|
150
|
+
|
|
151
|
+
**Error scenarios:**
|
|
152
|
+
- No session → returns `{ error: { message: "Unauthorized" } }`
|
|
153
|
+
- No permission → returns `{ error: { message: "Forbidden" } }`
|
|
154
|
+
- Batch not DRAFT → returns `{ error: { message: "Batch already submitted" } }`
|
|
155
|
+
- DB failure → caught by try/catch, logged via `logError()`, returns generic error
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## Infrastructure & Cloud Service Documentation
|
|
161
|
+
|
|
162
|
+
Whenever a file interacts with an external service, document:
|
|
163
|
+
|
|
164
|
+
```markdown
|
|
165
|
+
### Infrastructure Call: `uploadToS3(file, key)`
|
|
166
|
+
|
|
167
|
+
**Service:** AWS S3
|
|
168
|
+
**SDK:** `@aws-sdk/client-s3` → `S3Client` + `PutObjectCommand`
|
|
169
|
+
**When called:** User uploads a file via the batch item form
|
|
170
|
+
**How called:**
|
|
171
|
+
- Client: form submission → server action `uploadFile()`
|
|
172
|
+
- Server: validates file type/size → generates S3 key → calls `s3Client.send()`
|
|
173
|
+
**Configuration:** Bucket name from `process.env.S3_BUCKET`, region from `AWS_REGION`
|
|
174
|
+
**What flows in:** File buffer + content type + generated key path
|
|
175
|
+
**What flows out:** S3 URL (constructed from bucket + key)
|
|
176
|
+
**Error handling:** Wrapped in try/catch → logs error → returns `{ error }` to client
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Document these services whenever they appear:
|
|
180
|
+
|
|
181
|
+
| Service | Look for | What to document |
|
|
182
|
+
|---------|----------|------------------|
|
|
183
|
+
| PostgreSQL | `prisma.*` calls | Which model, which operation (SELECT/INSERT/UPDATE/DELETE), what data |
|
|
184
|
+
| AWS S3 | `s3Client`, `PutObjectCommand`, `GetObjectCommand` | Upload/download, bucket, key pattern, when triggered |
|
|
185
|
+
| AWS SQS | `sqsClient`, `SendMessageCommand` | Queue name, message shape, what triggers the send |
|
|
186
|
+
| External HTTP | `fetch()` to external URLs | URL pattern, method, request/response shape |
|
|
187
|
+
| better-auth | `auth.api.*` | Which auth operation, what it returns, session shape |
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Design Patterns to Detect and Explain
|
|
192
|
+
|
|
193
|
+
### TypeScript Patterns
|
|
194
|
+
| Pattern | What to look for | Why it matters |
|
|
195
|
+
|---------|-----------------|----------------|
|
|
196
|
+
| Discriminated Unions | `type Result = { ok: true; data: T } \| { ok: false; error: E }` | Type-safe branching without runtime checks |
|
|
197
|
+
| Type Guards | `function isX(val): val is X` | Narrows types so TS trusts your logic |
|
|
198
|
+
| Generics | `function fetch<T>(url): Promise<T>` | One function works with any type safely |
|
|
199
|
+
| Zod Schema Inference | `z.infer<typeof Schema>` | Single source of truth for runtime + compile-time types |
|
|
200
|
+
| Utility Types | `Partial<T>`, `Pick<T, K>`, `Omit<T, K>` | Transform types without rewriting them |
|
|
201
|
+
| Const Assertions | `as const` | Locks values to their literal types |
|
|
202
|
+
| Branded Types | `type Id = string & { __brand: 'Id' }` | Prevents mixing up IDs that are all strings |
|
|
203
|
+
|
|
204
|
+
### React Patterns
|
|
205
|
+
| Pattern | What to look for | Why it matters |
|
|
206
|
+
|---------|-----------------|----------------|
|
|
207
|
+
| Custom Hooks | `function useX()` | Reusable stateful logic extracted from components |
|
|
208
|
+
| Provider Pattern | Context + `useX()` hook | Dependency injection without prop drilling |
|
|
209
|
+
| Compound Components | Related components sharing implicit state | Flexible API for complex UI (like Radix) |
|
|
210
|
+
| Controlled Components | State owned by parent, passed via props | Predictable form behavior |
|
|
211
|
+
| Composition | Small components assembled via children/slots | Flexible, testable, reusable UI |
|
|
212
|
+
| Optimistic Updates | Update UI before server confirms | Feels instant to the user |
|
|
213
|
+
| Memoization | `useMemo`, `useCallback`, `React.memo` | Avoids expensive re-renders |
|
|
214
|
+
| Ref Forwarding | `forwardRef` | Lets parent access child's DOM node |
|
|
215
|
+
| Error Boundaries | Class component with `getDerivedStateFromError` | Catches render crashes gracefully |
|
|
216
|
+
|
|
217
|
+
### Next.js App Router Patterns
|
|
218
|
+
| Pattern | What to look for | Why it matters |
|
|
219
|
+
|---------|-----------------|----------------|
|
|
220
|
+
| Server Components | No `'use client'`, no hooks, no browser APIs | Zero JS shipped to client, fast initial load |
|
|
221
|
+
| Client Components | `'use client'` at top | Interactive, stateful, has access to browser |
|
|
222
|
+
| Server Actions | `'use server'` functions | Server-side mutations callable directly from client |
|
|
223
|
+
| Route Handlers | `route.ts` with `GET`/`POST`/etc exports | API endpoints within App Router |
|
|
224
|
+
| Layout Nesting | `layout.tsx` wrapping child routes | Persistent UI across navigation |
|
|
225
|
+
| Loading Convention | `loading.tsx` | Automatic Suspense boundary per route segment |
|
|
226
|
+
| Error Convention | `error.tsx` | Automatic error boundary per route segment |
|
|
227
|
+
| Middleware | `middleware.ts` at project root | Request interception (auth, redirects, headers) |
|
|
228
|
+
| Streaming | `<Suspense>` wrapping async server components | Progressive rendering — show what's ready |
|
|
229
|
+
| Metadata API | `export const metadata` or `generateMetadata()` | Per-route SEO and head management |
|
|
230
|
+
|
|
231
|
+
### Architectural Patterns
|
|
232
|
+
| Pattern | What to look for | Why it matters |
|
|
233
|
+
|---------|-----------------|----------------|
|
|
234
|
+
| Repository | Functions in `lib/db.ts` abstracting Prisma | Swap DB without touching business logic |
|
|
235
|
+
| Singleton | Single `prisma` or `auth` instance exported | One connection pool, not one per request |
|
|
236
|
+
| Adapter | Wrappers around S3/SQS SDK calls | Consistent interface; easy to mock/swap |
|
|
237
|
+
| Middleware/Pipeline | Chained checks (auth → authz → validate → execute) | Each step has one job; easy to reorder |
|
|
238
|
+
| Factory | Functions returning configured objects | Encapsulate complex creation logic |
|
|
239
|
+
| Strategy | Behavior varies by parameter/config | Same interface, different implementations |
|
|
240
|
+
|
|
241
|
+
## Important Scenarios to Cover
|
|
242
|
+
|
|
243
|
+
For each file, identify and explain the scenarios that matter:
|
|
244
|
+
|
|
245
|
+
- **Happy path** — normal successful flow from trigger to result
|
|
246
|
+
- **Error propagation** — where errors are caught, how they travel back to the UI
|
|
247
|
+
- **Edge cases** — empty arrays, null values, missing env vars, expired sessions
|
|
248
|
+
- **State transitions** — DRAFT → SUBMITTED → APPROVED (explain the state machine)
|
|
249
|
+
- **Permission gates** — who can call this, what roles/groups are checked
|
|
250
|
+
- **Async behavior** — loading states, what happens during the await, cleanup on unmount
|
|
251
|
+
- **Infra failure** — what if S3 is down? What if SQS rejects? What if DB times out?
|
|
252
|
+
|
|
253
|
+
## Output Format
|
|
254
|
+
|
|
255
|
+
### Module walkthrough
|
|
256
|
+
|
|
257
|
+
```markdown
|
|
258
|
+
# Code Explanation: [directory or feature area]
|
|
259
|
+
|
|
260
|
+
## Overview
|
|
261
|
+
[2-3 sentences: what this area of the codebase does, in plain language]
|
|
262
|
+
|
|
263
|
+
## Tech & Services Involved
|
|
264
|
+
| Layer | Technology | Role |
|
|
265
|
+
|-------|-----------|------|
|
|
266
|
+
| Frontend | React 19 + Next.js 15 | UI rendering, routing, server components |
|
|
267
|
+
| State | Zustand | Client-side state management |
|
|
268
|
+
| Validation | Zod | Runtime type checking |
|
|
269
|
+
| Database | Prisma + PostgreSQL | Data persistence |
|
|
270
|
+
| Storage | AWS S3 | File uploads |
|
|
271
|
+
| Queue | AWS SQS | Async processing |
|
|
272
|
+
| Auth | better-auth | Session management |
|
|
273
|
+
|
|
274
|
+
## File Map
|
|
275
|
+
[Simple tree showing which files exist and their one-line role]
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## `src/path/to/file.ts`
|
|
280
|
+
|
|
281
|
+
**Role:** ...
|
|
282
|
+
**Called by:** ...
|
|
283
|
+
**Calls into:** ...
|
|
284
|
+
**Infra/services touched:** ...
|
|
285
|
+
|
|
286
|
+
### `functionName(params)` → returnType
|
|
287
|
+
[explanation]
|
|
288
|
+
|
|
289
|
+
### Patterns Used
|
|
290
|
+
- **Pattern Name:** one-line explanation of why it's used here
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
[...repeat for each file...]
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Full Data Flow Diagram
|
|
299
|
+
|
|
300
|
+
```
|
|
301
|
+
User clicks "Submit Batch"
|
|
302
|
+
→ SubmitButton (client component, src/app/.../components/SubmitButton.tsx)
|
|
303
|
+
→ submitBatch(batchId) — server action (src/app/.../actions.ts)
|
|
304
|
+
→ [better-auth] session validation
|
|
305
|
+
→ [PostgreSQL] SELECT batch WHERE id = ?
|
|
306
|
+
→ [PostgreSQL] UPDATE batch SET status = 'SUBMITTED'
|
|
307
|
+
→ [AWS SQS] SendMessage { batchId, action: 'process' }
|
|
308
|
+
← { data: { batch: { ...updatedBatch } } }
|
|
309
|
+
← Re-render with new status badge showing "SUBMITTED"
|
|
310
|
+
|
|
311
|
+
Meanwhile, async:
|
|
312
|
+
[AWS SQS] → Processing Worker (separate service)
|
|
313
|
+
→ [PostgreSQL] UPDATE batch SET status = 'PROCESSING'
|
|
314
|
+
→ validate each batch item
|
|
315
|
+
→ [PostgreSQL] UPDATE batch SET status = 'APPROVED' or 'REJECTED'
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
## Key Patterns Summary
|
|
319
|
+
|
|
320
|
+
| Pattern | Where Used | Why |
|
|
321
|
+
|---------|-----------|-----|
|
|
322
|
+
| Server Action | `actions.ts` | Secure server-side mutations callable from client |
|
|
323
|
+
| Discriminated Union | `ActionResponse<T>` | Type-safe success/error without exceptions |
|
|
324
|
+
| Singleton | `src/lib/prisma.ts` | One DB connection pool for the whole app |
|
|
325
|
+
| Adapter | `src/lib/s3.ts`, `src/lib/sqs.ts` | Wrap AWS SDK behind simple functions |
|
|
326
|
+
| ... | ... | ... |
|
|
327
|
+
|
|
328
|
+
## Concepts You Learned
|
|
329
|
+
[Bulleted list of every concept explained, with one-line definition — becomes a reference card]
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Tone & Style
|
|
333
|
+
|
|
334
|
+
## Tone & Style
|
|
335
|
+
|
|
336
|
+
- **Friendly, encouraging, zero condescension** — "we" language, like a senior sitting next to you
|
|
337
|
+
- **Skip the obvious** — don't explain what `const x = 5` does
|
|
338
|
+
- **Explain the non-obvious** — why this pattern? why server vs client? why does this call SQS here?
|
|
339
|
+
- **Name every external service call** — never skip an infra interaction, these are critical for understanding the system
|
|
340
|
+
- **Use analogies** — "Think of SQS like a to-do list for a background worker — we drop a note saying 'process this batch', and a separate service picks it up later"
|
|
341
|
+
- **Show the full journey** — from user action → through the code → to the database/service → back to the UI
|
|
342
|
+
- **Keep it scannable** — headers, bullet points, tables, code blocks. No walls of text.
|
|
343
|
+
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## What NOT to Do
|
|
347
|
+
|
|
348
|
+
- Don't review or critique the code
|
|
349
|
+
- Don't suggest improvements (unless asked)
|
|
350
|
+
- Don't explain import statements, simple variable declarations, or trivial types
|
|
351
|
+
- Don't explain test files
|
|
352
|
+
- Don't use jargon without defining it on first use
|
|
353
|
+
- Don't be condescending ("as you probably know" / "this is simple")
|
|
354
|
+
- Don't explain node_modules or third-party library internals (just say what the library does)
|
|
355
|
+
- Don't skip infrastructure calls — every DB query, S3 operation, SQS message, and auth check must appear in the flow
|
|
356
|
+
- Don't use subagents or workflows — this skill requires sequential understanding across files
|
|
357
|
+
- In commit teach-in, don't skip Change Context fields — every changed source file needs Why / What / Blast radius / If left out
|
|
358
|
+
- Don't invent blast-radius callers or breakage modes not evidenced by the diff or reference search
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: explore
|
|
3
|
+
description: Deep codebase reconnaissance with parallel read-only investigators — fans out automatically when a question spans multiple subsystems, options, or cross-cutting concerns, then synthesizes one coherent picture. Use before designing a change, when tracing how something works end to end, or when you need to know the blast radius of touching a shared value.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Optional openspec CLI for change awareness. Node.js >= 18 for the bundled interlock-graph CLI.
|
|
6
|
+
argument-hint: "[question] [--autonomous]"
|
|
7
|
+
allowed-tools: Bash(interlock-graph *) Bash(openspec *) Agent Read Grep Glob
|
|
8
|
+
metadata:
|
|
9
|
+
type: discovery
|
|
10
|
+
outputs:
|
|
11
|
+
- .claude/handoff/explore-<slug>-<timestamp>.md
|
|
12
|
+
- openspec/changes/<name>/decisions.md
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Think deeply. Fan out when breadth is needed. Synthesize into understanding.
|
|
16
|
+
|
|
17
|
+
**Explore is for thinking, not implementing.** Read files, search code, investigate freely — but never write code and never implement a feature here. If asked to implement, say so and point at `/interlock:spec`. Writing OpenSpec artifacts or an explore brief is capturing thinking, not implementing, and is allowed.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Two modes
|
|
22
|
+
|
|
23
|
+
**Conversational (default).** A thinking partner. Ask the user which thread to pull when several look interesting. Iterate.
|
|
24
|
+
|
|
25
|
+
**Autonomous.** Activate on `--autonomous`, "no questions", "don't ask me", "pursue all threads", or when `/interlock:spec` invokes this skill. Then:
|
|
26
|
+
|
|
27
|
+
1. **No user Q&A.** No AskUserQuestion, no "which thread interests you?" menus. Open threads are work items, not questions.
|
|
28
|
+
2. **Fan out on every thread.** Each interesting thread or option gets a read-only investigator. Cap 2–5, merge in synthesis.
|
|
29
|
+
3. **Prefer defaults.** Ambiguous product intent → pick a reasonable default, record it under Assumptions Made and Pending Clarifications. Non-blocking. Every one of them is also a ledger row — see below.
|
|
30
|
+
4. **Write the explore brief.** Required exit criterion. Follow `${CLAUDE_PLUGIN_ROOT}/shared/EXPLORE-BRIEF.md`. Path: `.claude/handoff/explore-<slug>-<YYYYMMDD-HHMMSS>.md`.
|
|
31
|
+
5. **Close short.** Brief path plus a 3–5 line summary. Do not re-dump findings into chat — they are in the brief.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Graph-first reconnaissance, before any fan-out
|
|
36
|
+
|
|
37
|
+
Follow Rule 0 of `${CLAUDE_PLUGIN_ROOT}/shared/TOOL-ECONOMY.md`. If the graph exists, seed scopes then fan out:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
interlock-graph query "<subsystem tokens>" --budget 1500
|
|
41
|
+
interlock-graph consumers <symbol-or-field>
|
|
42
|
+
interlock-graph path <A> <B>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Scope investigators by real module nodes and consumer lists. Each investigator: graph, then grep for string-keyed and dynamic readers, then Read spans. If the graph is missing and the question spans 3+ subsystems, build it once (`interlock-graph build .`). Never rebuild when it already exists.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## When to fan out
|
|
50
|
+
|
|
51
|
+
**Fan out** when the question shows any of these:
|
|
52
|
+
|
|
53
|
+
| Signal | Example |
|
|
54
|
+
|--------|---------|
|
|
55
|
+
| Multiple subsystems touched | "How does deployment work end to end?" |
|
|
56
|
+
| Comparative analysis needed | "Redis or SQLite for this?" |
|
|
57
|
+
| Cross-file tracing required | "What validates the uploaded archive?" |
|
|
58
|
+
| Several options to research | "What are our options for real-time?" |
|
|
59
|
+
| Architecture mapping | "Map how auth flows through the system" |
|
|
60
|
+
|
|
61
|
+
**Mandatory fan-out — shared or derived value changes.** If the change alters what a value *means* or who reads it, run Pattern 4 per `${CLAUDE_PLUGIN_ROOT}/shared/INVARIANT-SWEEP.md`. This overrides the single-threaded default.
|
|
62
|
+
|
|
63
|
+
**Stay single-threaded** for conversational back-and-forth, single-file questions, quick clarifications, sequential discovery where A informs B, or when the user is thinking out loud.
|
|
64
|
+
|
|
65
|
+
When genuinely unsure, start single-threaded and escalate once you realize the question is broader than it looked.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## The four patterns
|
|
70
|
+
|
|
71
|
+
**Pattern 1 — Subsystem mapping.** The question spans several parts of the system. One investigator per stage of the flow. Synthesize into a diagram plus narrative.
|
|
72
|
+
|
|
73
|
+
**Pattern 2 — Option comparison.** Several viable approaches. One investigator per option, each reporting fit against *this* codebase, not generic pros and cons. Synthesize into a comparison table plus a recommendation.
|
|
74
|
+
|
|
75
|
+
**Pattern 3 — Layer sweep.** "Where does X happen?" when X could happen at several layers. One investigator per layer (client, API, business logic, persistence, post-processing). Synthesize into what each layer catches and where the gaps are.
|
|
76
|
+
|
|
77
|
+
**Pattern 4 — Impact analysis.** A change would alter what a value means or who reads it. One investigator per **disjoint** layer of the blast radius. Synthesize into an impact map with severity per area, and explicitly flag readers still consuming the raw, untransformed form.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Investigator rules
|
|
82
|
+
|
|
83
|
+
1. **Focused prompts.** Not "explore everything about X" — "trace the exact flow of Y through files A, B, C".
|
|
84
|
+
2. **Read-only.** Investigators search, read, and report. They never write.
|
|
85
|
+
3. **Structured returns.** JSON only (schema below). No narrative dump.
|
|
86
|
+
4. **2–5 agents.** Fewer than 2 is not a fan-out; more than 5 means the decomposition is too granular.
|
|
87
|
+
5. **Disjoint scopes.** Non-overlapping assignments so findings merge cleanly. For Pattern 4 this is load-bearing: partition the search space so no reader is missed or double-counted.
|
|
88
|
+
6. **Label clearly** so progress is visible.
|
|
89
|
+
7. **Use `subagent_type: "Explore"`** for read-only investigation.
|
|
90
|
+
8. **Context hygiene.** Wrap user-supplied values per `${CLAUDE_PLUGIN_ROOT}/shared/CONTEXT-HYGIENE.md` before echoing them into a subagent prompt.
|
|
91
|
+
9. **Locate before Read** — graph, then grep, then Read spans.
|
|
92
|
+
|
|
93
|
+
### Prompt template
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Investigate: [[SPECIFIC_QUESTION]]
|
|
97
|
+
|
|
98
|
+
Context: [[BROADER_TOPIC]]
|
|
99
|
+
|
|
100
|
+
Look for:
|
|
101
|
+
- [specific thing 1]
|
|
102
|
+
- [specific thing 2]
|
|
103
|
+
|
|
104
|
+
Return JSON only:
|
|
105
|
+
{ "files": [{ "path": "", "lines": "" }], "how": "", "connections": [], "gaps": [] }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Resolve `[[SPECIFIC_QUESTION]]` and `[[BROADER_TOPIC]]` from session state at emit time. **An unresolved placeholder halts the fan-out — never gap-fill one.**
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Synthesis
|
|
113
|
+
|
|
114
|
+
After investigators return, you **must** synthesize. Never dump raw agent output.
|
|
115
|
+
|
|
116
|
+
1. **Merge overlapping findings** — agents often reach the same file from different angles.
|
|
117
|
+
2. **Build one unified picture** — a diagram where structure matters.
|
|
118
|
+
3. **Name the gaps** — what did no agent find? What is still unclear?
|
|
119
|
+
4. **Surface contradictions** — when two agents disagree, say so; do not silently pick one.
|
|
120
|
+
5. **Run a completeness check.** Before closing, ask what is missing: a layer not swept, a reader not checked, an option not costed. **For Pattern 4 this is mandatory** — if any layer of the blast radius went uncovered, say so outright. A silent gap reads as "we covered everything" when you didn't.
|
|
121
|
+
6. **Offer direction.** What is worth exploring next? In autonomous mode, pursue it or record it in the brief rather than asking.
|
|
122
|
+
|
|
123
|
+
The result should read like a senior engineer who just debriefed four specialists — not like four reports stapled together.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## OpenSpec awareness
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
openspec list --json # is there an active change?
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
When a change exists, read its artifacts via `openspec status --change "<name>" --json` for context, and offer to capture decisions as they crystallize:
|
|
134
|
+
|
|
135
|
+
| Insight | Captured in |
|
|
136
|
+
|---|---|
|
|
137
|
+
| New or changed requirement | `specs/<capability>/spec.md` |
|
|
138
|
+
| Design decision | `design.md` |
|
|
139
|
+
| Scope change | `proposal.md` |
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Every ambiguity becomes a ledger row
|
|
144
|
+
|
|
145
|
+
Follow `${CLAUDE_PLUGIN_ROOT}/shared/DECISION-LEDGER.md`. Do not restate its format.
|
|
146
|
+
|
|
147
|
+
- `## Pending Clarifications` → `needs_human` rows.
|
|
148
|
+
- `## Assumptions Made` → `agent_resolved` rows with followable evidence (`obvious` is not evidence).
|
|
149
|
+
- Never only chat — a conversational answer still gets a row citing the human.
|
|
150
|
+
|
|
151
|
+
Active change → write `openspec/changes/<change>/decisions.md` now and run `interlock ledger <change>`. No change yet → number them `D1`, `D2`, … in the brief (class stated) so `/interlock:spec` transcribes them. Never renumber; never reuse an id.
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Exit
|
|
156
|
+
|
|
157
|
+
Conversational mode ends when the user has what they need.
|
|
158
|
+
|
|
159
|
+
Autonomous mode ends by writing the explore brief and reporting its path — the brief is what `/interlock:spec` reads instead of re-deriving discovery. Writing it is how explore pays forward.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fix-tests
|
|
3
|
+
description: Discover and persist how a project's tests run, then run the suite and repair failures by root cause — clustering failures by error signature, fixing the shared cause once, and asserting no test was weakened. Use when tests are failing, the suite is red, CI pasted a failure log, or someone asks to make the tests pass.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Requires the project's own test tooling. Node.js >= 18 for the bundled interlock CLI.
|
|
6
|
+
argument-hint: "[--e2e] [--dry-run] [--baseline <ref>] [--from-log <path>] [--reconfigure]"
|
|
7
|
+
allowed-tools: Bash Read Write Edit Glob Grep
|
|
8
|
+
metadata:
|
|
9
|
+
type: execution
|
|
10
|
+
outputs:
|
|
11
|
+
- .claude/testing/profile.json
|
|
12
|
+
- .claude/metrics/fix-tests-<timestamp>.json
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
Make the suite green **without making it weaker**.
|
|
16
|
+
|
|
17
|
+
The failure mode this skill exists to prevent is the one where a suite goes green by shrinking — a deleted assertion, a `.skip`, a narrowed glob, a loosened matcher. That is not a fix; it is the bug plus a lie. Every step below is built around detecting it.
|
|
18
|
+
|
|
19
|
+
| Flag | Effect |
|
|
20
|
+
|------|--------|
|
|
21
|
+
| `--e2e` | Also run the e2e suite (only when `e2e.command` is configured) |
|
|
22
|
+
| `--dry-run` | Diagnose and propose; edit nothing |
|
|
23
|
+
| `--baseline <ref>` | Treat failures already present at `<ref>` as pre-existing |
|
|
24
|
+
| `--from-log <path>` | Parse a pasted CI log instead of running the suite first |
|
|
25
|
+
| `--reconfigure` | Re-run test discovery from scratch |
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 1. Resolve the test profile
|
|
30
|
+
|
|
31
|
+
Read `.claude/testing/profile.json`. If it is missing or `--reconfigure` was passed, run the discovery ladder in `${CLAUDE_PLUGIN_ROOT}/shared/TEST-PROFILE.md`: manifests, then runner configs, then CI workflows, then **at most four questions** for gaps that genuinely block a correct run.
|
|
32
|
+
|
|
33
|
+
Resolve `typecheck.command` and `lint.command` on the same pass, the way `coverage.command` is resolved: the profile's own value first, then `package.json` `scripts.typecheck` / `scripts["type-check"]` and `scripts.lint`, then the step in the CI job that runs it. Never ask for either and never invent one — nothing found is `command: null`, which a ship run skips with a stated reason. A ship run's inter-wave checkpoint has no typecheck to run unless this field is filled, and a typecheck failure is a halting kind there.
|
|
34
|
+
|
|
35
|
+
This is the only skill permitted to interview the user about tests. Every later run is zero-question.
|
|
36
|
+
|
|
37
|
+
Persist the profile and mirror it into the `## Testing` block in `CLAUDE.md` (or `AGENTS.md`), between the managed markers, idempotently.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Run and baseline
|
|
42
|
+
|
|
43
|
+
Run the unit command. Record `total`, `passed`, `failed`, `skipped` — this is the baseline that step 6 asserts against.
|
|
44
|
+
|
|
45
|
+
Split failures into:
|
|
46
|
+
|
|
47
|
+
- **Newly broken** — not failing at `--baseline <ref>` (or all failures when no baseline was given)
|
|
48
|
+
- **Pre-existing** — already failing at the baseline. **Report only.** Do not absorb them into this fix unless the user explicitly widens scope.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 3. Flake check
|
|
53
|
+
|
|
54
|
+
Re-run **only** the failing files or test names, once, using `single_file` / `filter_syntax`.
|
|
55
|
+
|
|
56
|
+
- Still failing → a real failure; continue.
|
|
57
|
+
- Passed on re-run → record it in `profile.known_flaky` and **do not "fix" it**. Mention it in the report. A test that passes on retry is a flaky test, and "fixing" it usually means deleting the thing that caught a race.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. Cluster by error signature
|
|
62
|
+
|
|
63
|
+
| Signature | Example | Likely shared root cause |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| Same missing import | `Cannot find module './utils'` | Missing export or wrong path |
|
|
66
|
+
| Same type error | `Type 'X' not assignable to 'Y'` | Interface shape mismatch |
|
|
67
|
+
| Same fixture or setup | `ReferenceError: db is not defined` | Missing shared setup |
|
|
68
|
+
| Same env or config | `ECONNREFUSED`, `env.X is undefined` | Missing env or config |
|
|
69
|
+
| Same assertion pattern | Many `expected X received Y` | Logic bug in shared code |
|
|
70
|
+
|
|
71
|
+
With `--from-log`, parse the log into the same clusters without an initial run — but still record a live baseline before applying any fix.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 5. Fix by root cause
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
iterations = 0, MAX = 5
|
|
79
|
+
|
|
80
|
+
WHILE failures remain AND iterations < MAX AND NOT --dry-run:
|
|
81
|
+
1. Pick the cluster covering the MOST failures
|
|
82
|
+
2. Choose ONE fix — source first
|
|
83
|
+
3. Apply it
|
|
84
|
+
4. Re-run ONLY the affected tests
|
|
85
|
+
5. Drop resolved failures; iterations++
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**Source first.** When a test and the code disagree, the default assumption is that the code is wrong. Change the test only when you can state why the test's expectation was incorrect — and say that out loud in the report.
|
|
89
|
+
|
|
90
|
+
**Never**: delete a test, add `.skip`/`.only`, loosen an assertion to match observed output, narrow a glob, raise a timeout to hide a race, or catch-and-ignore an error to make a run pass.
|
|
91
|
+
|
|
92
|
+
`--dry-run` stops after clustering: print the diagnoses and proposed fixes, edit nothing.
|
|
93
|
+
|
|
94
|
+
After 5 iterations, stop and report the unresolved clusters and what was tried. Do not thrash.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## 6. Full re-run and no-regression assert
|
|
99
|
+
|
|
100
|
+
Run the full suite again, then assert against the baseline:
|
|
101
|
+
|
|
102
|
+
- `total >= baseline.total`
|
|
103
|
+
- `skipped <= baseline.skipped`
|
|
104
|
+
|
|
105
|
+
**If either assert fails, revert the weakening change** — something deleted tests or added skips. A green suite that runs fewer tests than it did before is a regression wearing a green badge.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 7. Persist
|
|
110
|
+
|
|
111
|
+
- Refresh `.claude/testing/profile.json` (`updated`, `known_flaky`, `notes`) with anything learned about running tests. Preserve every key you did not resolve yourself.
|
|
112
|
+
- Confirm the `## Testing` block is still a single idempotent pair of markers.
|
|
113
|
+
- Write at most **3** `.claude/memory/failure-modes/<slug>.md` entries for genuinely recurring gotchas, with index lines in `.claude/memory/MEMORY.md`. One-off typos do not belong in memory.
|
|
114
|
+
- Write `.claude/metrics/fix-tests-<YYYYMMDD-HHMMSS>.json` with the baseline, final counts, clusters, fixes applied, and anything unresolved.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 8. Report
|
|
119
|
+
|
|
120
|
+
Baseline → final counts. Root causes fixed, one line each. Failures reverted as pre-existing. Flaky tests recorded. Anything still red, and what was tried. If you changed a test rather than source, say which and why.
|