@yuaone/core 0.3.2 → 0.4.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/dist/agent-loop.d.ts +62 -0
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +705 -18
- package/dist/agent-loop.js.map +1 -1
- package/dist/background-agent.d.ts +110 -0
- package/dist/background-agent.d.ts.map +1 -0
- package/dist/background-agent.js +255 -0
- package/dist/background-agent.js.map +1 -0
- package/dist/coding-standards.d.ts +45 -0
- package/dist/coding-standards.d.ts.map +1 -0
- package/dist/coding-standards.js +1152 -0
- package/dist/coding-standards.js.map +1 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +2 -6
- package/dist/constants.js.map +1 -1
- package/dist/context-manager.d.ts +6 -0
- package/dist/context-manager.d.ts.map +1 -1
- package/dist/context-manager.js +23 -4
- package/dist/context-manager.js.map +1 -1
- package/dist/index.d.ts +28 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -2
- package/dist/index.js.map +1 -1
- package/dist/llm-client.d.ts +8 -3
- package/dist/llm-client.d.ts.map +1 -1
- package/dist/llm-client.js +64 -13
- package/dist/llm-client.js.map +1 -1
- package/dist/plugin-auto-loader.d.ts +108 -0
- package/dist/plugin-auto-loader.d.ts.map +1 -0
- package/dist/plugin-auto-loader.js +743 -0
- package/dist/plugin-auto-loader.js.map +1 -0
- package/dist/plugin-registry.d.ts +112 -0
- package/dist/plugin-registry.d.ts.map +1 -0
- package/dist/plugin-registry.js +319 -0
- package/dist/plugin-registry.js.map +1 -0
- package/dist/plugin-types.d.ts +388 -0
- package/dist/plugin-types.d.ts.map +1 -0
- package/dist/plugin-types.js +8 -0
- package/dist/plugin-types.js.map +1 -0
- package/dist/plugin-validator.d.ts +54 -0
- package/dist/plugin-validator.d.ts.map +1 -0
- package/dist/plugin-validator.js +129 -0
- package/dist/plugin-validator.js.map +1 -0
- package/dist/repo-knowledge-graph.d.ts +112 -0
- package/dist/repo-knowledge-graph.d.ts.map +1 -0
- package/dist/repo-knowledge-graph.js +561 -0
- package/dist/repo-knowledge-graph.js.map +1 -0
- package/dist/role-registry.js +1 -1
- package/dist/role-registry.js.map +1 -1
- package/dist/self-debug-loop.d.ts +257 -0
- package/dist/self-debug-loop.d.ts.map +1 -0
- package/dist/self-debug-loop.js +870 -0
- package/dist/self-debug-loop.js.map +1 -0
- package/dist/skill-learner.d.ts +136 -0
- package/dist/skill-learner.d.ts.map +1 -0
- package/dist/skill-learner.js +382 -0
- package/dist/skill-learner.js.map +1 -0
- package/dist/skill-loader.d.ts +90 -0
- package/dist/skill-loader.d.ts.map +1 -0
- package/dist/skill-loader.js +309 -0
- package/dist/skill-loader.js.map +1 -0
- package/dist/specialist-registry.d.ts +132 -0
- package/dist/specialist-registry.d.ts.map +1 -0
- package/dist/specialist-registry.js +413 -0
- package/dist/specialist-registry.js.map +1 -0
- package/dist/sub-agent-prompts.d.ts +45 -0
- package/dist/sub-agent-prompts.d.ts.map +1 -0
- package/dist/sub-agent-prompts.js +177 -0
- package/dist/sub-agent-prompts.js.map +1 -0
- package/dist/sub-agent-router.d.ts +75 -0
- package/dist/sub-agent-router.d.ts.map +1 -0
- package/dist/sub-agent-router.js +174 -0
- package/dist/sub-agent-router.js.map +1 -0
- package/dist/sub-agent.d.ts +48 -0
- package/dist/sub-agent.d.ts.map +1 -1
- package/dist/sub-agent.js +108 -5
- package/dist/sub-agent.js.map +1 -1
- package/dist/system-prompt.d.ts +26 -0
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +177 -7
- package/dist/system-prompt.js.map +1 -1
- package/dist/task-classifier.d.ts +25 -1
- package/dist/task-classifier.d.ts.map +1 -1
- package/dist/task-classifier.js +171 -1
- package/dist/task-classifier.js.map +1 -1
- package/dist/tool-planner.d.ts +160 -0
- package/dist/tool-planner.d.ts.map +1 -0
- package/dist/tool-planner.js +501 -0
- package/dist/tool-planner.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/world-state.d.ts.map +1 -1
- package/dist/world-state.js +8 -1
- package/dist/world-state.js.map +1 -1
- package/package.json +2 -1
- package/plugins/git/patterns/branch-patterns.json +101 -0
- package/plugins/git/patterns/commit-patterns.json +186 -0
- package/plugins/git/plugin.yaml +128 -0
- package/plugins/git/skills/branch-strategy.md +172 -0
- package/plugins/git/skills/commit-conv.md +178 -0
- package/plugins/git/skills/conflict-resolve.md +159 -0
- package/plugins/git/skills/history-clean.md +199 -0
- package/plugins/git/skills/pr-review.md +196 -0
- package/plugins/git/strategies/conflict-resolve.json +244 -0
- package/plugins/git/strategies/release-flow.json +292 -0
- package/plugins/git/validators/rules.json +348 -0
- package/plugins/react/patterns/anti-patterns.json +88 -0
- package/plugins/react/patterns/components.json +80 -0
- package/plugins/react/patterns/hooks.json +72 -0
- package/plugins/react/plugin.yaml +229 -0
- package/plugins/react/skills/bugfix.md +208 -0
- package/plugins/react/skills/component-gen.md +206 -0
- package/plugins/react/skills/hook-extract.md +208 -0
- package/plugins/react/skills/ssr.md +256 -0
- package/plugins/react/skills/test.md +273 -0
- package/plugins/react/strategies/build-fix.json +43 -0
- package/plugins/react/strategies/hook-loop-fix.json +36 -0
- package/plugins/react/strategies/hydration-fix.json +42 -0
- package/plugins/react/validators/rules.json +92 -0
- package/plugins/typescript/patterns/best-practices.json +25 -0
- package/plugins/typescript/patterns/common-errors.json +32 -0
- package/plugins/typescript/plugin.yaml +74 -0
- package/plugins/typescript/skills/debug.md +23 -0
- package/plugins/typescript/skills/migration.md +24 -0
- package/plugins/typescript/skills/refactor.md +22 -0
- package/plugins/typescript/skills/strict-mode.md +23 -0
- package/plugins/typescript/strategies/strict-migration.json +37 -0
- package/plugins/typescript/strategies/type-error-fix.json +37 -0
- package/plugins/typescript/validators/rules.json +28 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# React SSR/Hydration Expert Skill
|
|
2
|
+
|
|
3
|
+
## Identity
|
|
4
|
+
- domain: react
|
|
5
|
+
- type: ssr
|
|
6
|
+
- confidence: 0.85
|
|
7
|
+
- persona: Senior full-stack React engineer with deep expertise in server-side rendering, Next.js App Router and Pages Router, React Server Components, streaming SSR, and hydration debugging. Understands the React fiber reconciliation process during hydration and the boundary between server and client execution.
|
|
8
|
+
|
|
9
|
+
## Known Error Patterns
|
|
10
|
+
|
|
11
|
+
### 1. Hydration Mismatch — Client-Only APIs
|
|
12
|
+
- **symptoms**:
|
|
13
|
+
- "Text content does not match server-rendered HTML"
|
|
14
|
+
- "Hydration failed because the initial UI does not match"
|
|
15
|
+
- Content flickers on page load
|
|
16
|
+
- Different content shown before and after JavaScript loads
|
|
17
|
+
- "There was an error while hydrating" with full client re-render
|
|
18
|
+
- **causes**:
|
|
19
|
+
- Direct access to `window`, `document`, `navigator`, `localStorage` in render
|
|
20
|
+
- `typeof window !== 'undefined'` check causing different output on server vs client
|
|
21
|
+
- `Date.now()`, `new Date().toLocaleString()` producing different values
|
|
22
|
+
- `Math.random()` in render path
|
|
23
|
+
- `navigator.userAgent` conditional rendering
|
|
24
|
+
- Third-party scripts/components that assume browser environment
|
|
25
|
+
- **strategy**:
|
|
26
|
+
1. Move client-only code into `useEffect`: renders null/placeholder on server, real content on client
|
|
27
|
+
2. Create `useIsClient` hook:
|
|
28
|
+
```
|
|
29
|
+
function useIsClient() {
|
|
30
|
+
const [isClient, setIsClient] = useState(false);
|
|
31
|
+
useEffect(() => setIsClient(true), []);
|
|
32
|
+
return isClient;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
3. Use `next/dynamic` with `{ ssr: false }` for entire components that need browser APIs
|
|
36
|
+
4. Use `suppressHydrationWarning` only for intentional mismatches (timestamps, user-specific content)
|
|
37
|
+
5. For dates, render a stable format on server and enhance on client
|
|
38
|
+
6. Wrap browser-API-dependent libraries in a client-only wrapper component
|
|
39
|
+
- **tools**: grep, file_read, file_edit, shell_exec
|
|
40
|
+
- **pitfalls**:
|
|
41
|
+
- `typeof window` checks in render cause hydration mismatches -- the check itself produces different branches
|
|
42
|
+
- `suppressHydrationWarning` only works on the direct element, not children
|
|
43
|
+
- Over-using `ssr: false` defeats the purpose of SSR -- only for truly client-only components
|
|
44
|
+
|
|
45
|
+
### 2. useEffect vs useLayoutEffect in SSR
|
|
46
|
+
- **symptoms**:
|
|
47
|
+
- "useLayoutEffect does nothing on the server" warning
|
|
48
|
+
- Flash of unstyled content (FOUC)
|
|
49
|
+
- Layout shift after hydration
|
|
50
|
+
- Measurements (getBoundingClientRect) returning 0 on server
|
|
51
|
+
- **causes**:
|
|
52
|
+
- `useLayoutEffect` runs synchronously after DOM mutations -- not possible on server
|
|
53
|
+
- Using `useLayoutEffect` for client-side layout measurements
|
|
54
|
+
- CSS-in-JS libraries using `useLayoutEffect` for style injection
|
|
55
|
+
- Animation libraries using `useLayoutEffect` for initial measurements
|
|
56
|
+
- **strategy**:
|
|
57
|
+
1. Use `useEffect` for most cases -- runs after paint, works on server
|
|
58
|
+
2. Create `useIsomorphicLayoutEffect`:
|
|
59
|
+
```
|
|
60
|
+
const useIsomorphicLayoutEffect =
|
|
61
|
+
typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
62
|
+
```
|
|
63
|
+
3. Only use `useLayoutEffect` when you need synchronous DOM measurement before paint
|
|
64
|
+
4. For CSS-in-JS, ensure server-side style extraction is configured (styled-components: `ServerStyleSheet`)
|
|
65
|
+
5. Accept minor layout shift vs. blocking paint -- `useEffect` is usually better for UX
|
|
66
|
+
- **tools**: grep, file_read, file_edit
|
|
67
|
+
- **pitfalls**:
|
|
68
|
+
- The `useIsomorphicLayoutEffect` pattern is a workaround, not a solution -- consider if you really need layout effect
|
|
69
|
+
- `useLayoutEffect` blocks paint -- use sparingly, even on client
|
|
70
|
+
- Most "layout" needs can be handled with CSS (grid, flexbox) without JS measurement
|
|
71
|
+
|
|
72
|
+
### 3. Server Components vs Client Components (Next.js 13+)
|
|
73
|
+
- **symptoms**:
|
|
74
|
+
- "You're importing a component that needs useState/useEffect. It only works in a Client Component"
|
|
75
|
+
- "async/await is not yet supported in Client Components"
|
|
76
|
+
- Props serialization errors ("only plain objects can be passed to Client Components")
|
|
77
|
+
- "Functions cannot be passed directly to Client Components unless you explicitly expose it"
|
|
78
|
+
- Import errors when mixing server and client components
|
|
79
|
+
- **causes**:
|
|
80
|
+
- Using hooks (`useState`, `useEffect`, `useContext`) in a Server Component
|
|
81
|
+
- Using event handlers (`onClick`, `onChange`) in a Server Component
|
|
82
|
+
- Using browser-only APIs in a Server Component
|
|
83
|
+
- Passing non-serializable props (functions, classes, Dates) from Server to Client Component
|
|
84
|
+
- Importing a Client Component into a Server Component without `'use client'` boundary
|
|
85
|
+
- **strategy**:
|
|
86
|
+
1. Add `'use client'` directive at the top of files that need hooks, events, or browser APIs
|
|
87
|
+
2. Keep Server Components as the default -- only add `'use client'` when needed
|
|
88
|
+
3. Push `'use client'` boundary as low as possible in the tree
|
|
89
|
+
4. For non-serializable props, restructure: pass IDs instead of objects, use server actions
|
|
90
|
+
5. Use the "donut pattern": Server Component wraps Client Component which wraps Server Component (via children)
|
|
91
|
+
6. Server Components can import Client Components, but not vice versa (except via children)
|
|
92
|
+
7. Fetch data in Server Components, pass serializable data to Client Components
|
|
93
|
+
- **tools**: grep, file_read, file_edit
|
|
94
|
+
- **pitfalls**:
|
|
95
|
+
- `'use client'` does NOT make it client-only -- it creates a boundary. The component still renders on server for SSR
|
|
96
|
+
- Do NOT add `'use client'` to a layout file unless absolutely necessary -- it opts out all children from Server Components
|
|
97
|
+
- `'use server'` is for Server Actions (mutations), NOT for making a Server Component
|
|
98
|
+
|
|
99
|
+
### 4. Dynamic Imports and Code Splitting
|
|
100
|
+
- **symptoms**:
|
|
101
|
+
- Large initial bundle size
|
|
102
|
+
- Slow Time to Interactive (TTI)
|
|
103
|
+
- Components that only show on interaction loaded upfront
|
|
104
|
+
- SSR errors from client-only libraries
|
|
105
|
+
- Flash of loading state on navigation
|
|
106
|
+
- **causes**:
|
|
107
|
+
- All components loaded eagerly in the initial bundle
|
|
108
|
+
- Heavy libraries (charts, editors, maps) included in server bundle
|
|
109
|
+
- No code splitting for route-level or feature-level components
|
|
110
|
+
- Client-only libraries imported at top level
|
|
111
|
+
- **strategy**:
|
|
112
|
+
1. Use `next/dynamic` for heavy or client-only components:
|
|
113
|
+
```
|
|
114
|
+
const Chart = dynamic(() => import('./Chart'), {
|
|
115
|
+
loading: () => <ChartSkeleton />,
|
|
116
|
+
ssr: false,
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
2. Use `React.lazy` + `Suspense` for CSR-only apps:
|
|
120
|
+
```
|
|
121
|
+
const LazyComponent = React.lazy(() => import('./Heavy'));
|
|
122
|
+
<Suspense fallback={<Skeleton />}><LazyComponent /></Suspense>
|
|
123
|
+
```
|
|
124
|
+
3. Route-level code splitting is automatic in Next.js App Router
|
|
125
|
+
4. Use `loading.tsx` files for route-level loading UI in App Router
|
|
126
|
+
5. For shared layouts, use route groups `(group)` to avoid unnecessary re-renders
|
|
127
|
+
6. Analyze bundle with `@next/bundle-analyzer` to identify split opportunities
|
|
128
|
+
- **tools**: file_read, file_edit, shell_exec, grep
|
|
129
|
+
- **pitfalls**:
|
|
130
|
+
- `React.lazy` does NOT work with SSR -- use `next/dynamic` in Next.js
|
|
131
|
+
- Do NOT lazy-load components that appear above the fold -- they should be in the initial bundle
|
|
132
|
+
- `ssr: false` means the component renders nothing until JS loads -- bad for SEO-critical content
|
|
133
|
+
|
|
134
|
+
### 5. Streaming SSR Patterns
|
|
135
|
+
- **symptoms**:
|
|
136
|
+
- Slow Time to First Byte (TTFB)
|
|
137
|
+
- Entire page blocks on slowest data fetch
|
|
138
|
+
- Users see blank page until all data loads
|
|
139
|
+
- Waterfall data fetching pattern
|
|
140
|
+
- Long server response times
|
|
141
|
+
- **causes**:
|
|
142
|
+
- All data fetched before any HTML is sent (`getServerSideProps` blocking pattern)
|
|
143
|
+
- No Suspense boundaries to enable streaming
|
|
144
|
+
- Monolithic page component that needs all data at once
|
|
145
|
+
- Database queries running sequentially instead of in parallel
|
|
146
|
+
- **strategy**:
|
|
147
|
+
1. Use Suspense boundaries to stream parts of the page:
|
|
148
|
+
```
|
|
149
|
+
<Suspense fallback={<HeaderSkeleton />}>
|
|
150
|
+
<Header />
|
|
151
|
+
</Suspense>
|
|
152
|
+
<Suspense fallback={<ContentSkeleton />}>
|
|
153
|
+
<SlowContent /> <!-- Streams in when ready -->
|
|
154
|
+
</Suspense>
|
|
155
|
+
```
|
|
156
|
+
2. In App Router, use `async` Server Components with Suspense for streaming
|
|
157
|
+
3. Run independent data fetches in parallel with `Promise.all`
|
|
158
|
+
4. Use `loading.tsx` for route-level streaming boundaries
|
|
159
|
+
5. Critical content (header, hero) should be fast -- wrap slow content in Suspense
|
|
160
|
+
6. Use `generateStaticParams` for static generation when data is known at build time
|
|
161
|
+
7. Consider ISR (Incremental Static Regeneration) with `revalidate` for semi-static pages
|
|
162
|
+
- **tools**: file_read, file_edit, shell_exec
|
|
163
|
+
- **pitfalls**:
|
|
164
|
+
- Streaming only works with Node.js runtime, not Edge runtime for all cases
|
|
165
|
+
- Too many Suspense boundaries can cause visual "popcorn" effect -- group related content
|
|
166
|
+
- `loading.tsx` applies to the entire route segment -- be intentional about placement
|
|
167
|
+
|
|
168
|
+
### 6. Data Fetching in Server Components
|
|
169
|
+
- **symptoms**:
|
|
170
|
+
- Using `useEffect` for data fetching in App Router
|
|
171
|
+
- Unnecessary client-side waterfalls
|
|
172
|
+
- Duplicate requests (server + client fetching same data)
|
|
173
|
+
- Stale data issues with client-side caching
|
|
174
|
+
- N+1 query patterns
|
|
175
|
+
- **causes**:
|
|
176
|
+
- Migrating Pages Router patterns to App Router without adaptation
|
|
177
|
+
- Not leveraging Server Component data fetching
|
|
178
|
+
- Missing Request Memoization (same URL fetched multiple times in same request)
|
|
179
|
+
- Not using `cache()` for database queries
|
|
180
|
+
- **strategy**:
|
|
181
|
+
1. Fetch data directly in Server Components (no hooks needed):
|
|
182
|
+
```
|
|
183
|
+
async function UserPage({ params }) {
|
|
184
|
+
const user = await getUser(params.id); // runs on server
|
|
185
|
+
return <UserProfile user={user} />;
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
2. Use `cache()` from React for request-level deduplication:
|
|
189
|
+
```
|
|
190
|
+
const getUser = cache(async (id: string) => {
|
|
191
|
+
return db.user.findUnique({ where: { id } });
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
3. Parallel fetching: `const [user, posts] = await Promise.all([getUser(id), getPosts(id)])`
|
|
195
|
+
4. Use Server Actions for mutations (forms, button clicks)
|
|
196
|
+
5. Revalidate with `revalidatePath` or `revalidateTag` after mutations
|
|
197
|
+
6. Use `unstable_cache` for cross-request caching (with tags for invalidation)
|
|
198
|
+
- **tools**: file_read, file_edit, grep
|
|
199
|
+
- **pitfalls**:
|
|
200
|
+
- `fetch` in Server Components is auto-memoized in Next.js -- manual dedup may not be needed
|
|
201
|
+
- `cache()` is request-scoped -- it does NOT cache across requests
|
|
202
|
+
- Do NOT use `getServerSideProps` in App Router -- use Server Components instead
|
|
203
|
+
- Server Actions are NOT GET requests -- do not use them for data fetching
|
|
204
|
+
|
|
205
|
+
### 7. Metadata and SEO in SSR
|
|
206
|
+
- **symptoms**:
|
|
207
|
+
- Missing or incorrect meta tags in page source
|
|
208
|
+
- Social media previews not working (Open Graph)
|
|
209
|
+
- Search engines not indexing dynamic content
|
|
210
|
+
- Duplicate title tags
|
|
211
|
+
- Missing canonical URLs
|
|
212
|
+
- **causes**:
|
|
213
|
+
- Using client-side `document.title` instead of framework metadata
|
|
214
|
+
- Not using `generateMetadata` in App Router
|
|
215
|
+
- Missing `Head` component in Pages Router
|
|
216
|
+
- Dynamic OG images not configured
|
|
217
|
+
- **strategy**:
|
|
218
|
+
1. App Router: export `metadata` or `generateMetadata` from page/layout:
|
|
219
|
+
```
|
|
220
|
+
export async function generateMetadata({ params }) {
|
|
221
|
+
const post = await getPost(params.id);
|
|
222
|
+
return { title: post.title, description: post.excerpt };
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
2. Pages Router: use `next/head` in every page
|
|
226
|
+
3. Configure OG images with `opengraph-image.tsx` or `generateImageMetadata`
|
|
227
|
+
4. Use `robots.txt` and `sitemap.xml` (App Router: `app/robots.ts`, `app/sitemap.ts`)
|
|
228
|
+
5. Add structured data (JSON-LD) in Server Components
|
|
229
|
+
- **tools**: file_read, file_edit, grep
|
|
230
|
+
- **pitfalls**:
|
|
231
|
+
- `<title>` in client components does not affect SSR HTML -- crawlers may not see it
|
|
232
|
+
- `generateMetadata` runs on the server -- do not use hooks or browser APIs in it
|
|
233
|
+
- Test with `curl` or "View Source" to verify server-rendered HTML, not browser DevTools
|
|
234
|
+
|
|
235
|
+
## Tool Sequence
|
|
236
|
+
1. **grep** -- Search for hydration-related errors, `'use client'` directives, and SSR patterns
|
|
237
|
+
2. **file_read** -- Read the problematic component and its parent chain
|
|
238
|
+
3. **grep** -- Search for `window`, `document`, `localStorage`, `navigator` usage in render paths
|
|
239
|
+
4. **grep** -- Search for `useEffect`, `useLayoutEffect`, `useState` to understand client/server split
|
|
240
|
+
5. **file_read** -- Read Next.js config (`next.config.js`) and layout files
|
|
241
|
+
6. **file_edit** -- Apply SSR-safe fixes (useEffect wrapping, dynamic imports, use client directive)
|
|
242
|
+
7. **shell_exec** -- Run `next build` to verify no build errors
|
|
243
|
+
8. **shell_exec** -- Run `next dev` and check browser console for hydration warnings
|
|
244
|
+
9. **grep** -- Verify no remaining hydration mismatches in build output
|
|
245
|
+
|
|
246
|
+
## Validation Checklist
|
|
247
|
+
- [ ] No hydration mismatch warnings in browser console
|
|
248
|
+
- [ ] `next build` passes without errors
|
|
249
|
+
- [ ] Server-rendered HTML contains expected content (check with `curl` or View Source)
|
|
250
|
+
- [ ] Client-only components properly wrapped with `dynamic({ ssr: false })` or `useEffect`
|
|
251
|
+
- [ ] `'use client'` directives are at the lowest possible level
|
|
252
|
+
- [ ] No `useLayoutEffect` warnings on server
|
|
253
|
+
- [ ] SEO meta tags present in server-rendered HTML
|
|
254
|
+
- [ ] Page loads meaningfully without JavaScript (progressive enhancement)
|
|
255
|
+
- [ ] Streaming Suspense boundaries placed around slow content
|
|
256
|
+
- [ ] No unnecessary client-side data fetching that could be done on server
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# React Test Generator Skill
|
|
2
|
+
|
|
3
|
+
## Identity
|
|
4
|
+
- domain: react
|
|
5
|
+
- type: testing
|
|
6
|
+
- confidence: 0.85
|
|
7
|
+
- persona: Senior test engineer specializing in React Testing Library, MSW for API mocking, and user-centric testing philosophy. Expert in writing tests that resemble how users interact with software, avoiding implementation detail testing.
|
|
8
|
+
|
|
9
|
+
## Known Error Patterns
|
|
10
|
+
|
|
11
|
+
### 1. Testing Implementation Details
|
|
12
|
+
- **symptoms**:
|
|
13
|
+
- Tests break when refactoring internal component structure
|
|
14
|
+
- Tests use `wrapper.instance()` or access internal state
|
|
15
|
+
- Tests assert on class names, CSS properties, or DOM structure
|
|
16
|
+
- Tests mock internal hooks or child component rendering
|
|
17
|
+
- Tests break from renaming internal variables
|
|
18
|
+
- **causes**:
|
|
19
|
+
- Using Enzyme-style testing patterns with RTL
|
|
20
|
+
- Testing "how" instead of "what" the component does
|
|
21
|
+
- Excessive mocking of internal modules
|
|
22
|
+
- Selecting elements by class name or test ID instead of role
|
|
23
|
+
- **strategy**:
|
|
24
|
+
1. Query by role: `getByRole('button', { name: /submit/i })`
|
|
25
|
+
2. Query by label: `getByLabelText(/email/i)`
|
|
26
|
+
3. Query by text: `getByText(/welcome/i)`
|
|
27
|
+
4. Use `getByTestId` only as last resort
|
|
28
|
+
5. Assert on visible output, not internal state
|
|
29
|
+
6. Test user interactions, not method calls
|
|
30
|
+
- **tools**: file_read, file_edit, shell_exec
|
|
31
|
+
- **pitfalls**:
|
|
32
|
+
- If you need `getByTestId` often, your component may lack proper accessibility
|
|
33
|
+
- Do NOT test that `setState` was called -- test that the UI changed
|
|
34
|
+
- Do NOT snapshot test frequently-changing components
|
|
35
|
+
|
|
36
|
+
### 2. Async Testing Failures
|
|
37
|
+
- **symptoms**:
|
|
38
|
+
- "not wrapped in act(...)" warnings
|
|
39
|
+
- Tests pass/fail intermittently (flaky tests)
|
|
40
|
+
- Assertion runs before async operation completes
|
|
41
|
+
- `waitFor` times out unexpectedly
|
|
42
|
+
- State updates after test cleanup
|
|
43
|
+
- **causes**:
|
|
44
|
+
- Not awaiting async operations
|
|
45
|
+
- Using `getBy*` for elements that appear asynchronously (should use `findBy*`)
|
|
46
|
+
- Missing `await` on `userEvent` calls (v14+)
|
|
47
|
+
- Timer-dependent code without fake timers
|
|
48
|
+
- Missing MSW handlers causing real network requests
|
|
49
|
+
- **strategy**:
|
|
50
|
+
1. Use `findBy*` for elements that appear after async work: `await screen.findByText(/loaded/i)`
|
|
51
|
+
2. Use `waitFor` for assertions that need retrying: `await waitFor(() => expect(...).toBe(...))`
|
|
52
|
+
3. Always `await` userEvent calls: `await user.click(button)`
|
|
53
|
+
4. Use `vi.useFakeTimers()` for timer-dependent code
|
|
54
|
+
5. Set up MSW handlers for all API calls in tests
|
|
55
|
+
6. Clean up with `afterEach` -- reset handlers, clear timers
|
|
56
|
+
- **tools**: file_read, file_edit, shell_exec
|
|
57
|
+
- **pitfalls**:
|
|
58
|
+
- `waitFor` should contain only assertions, not side effects
|
|
59
|
+
- Do NOT use `waitFor` with a `timeout` > 5000ms -- your test is probably wrong
|
|
60
|
+
- `findBy*` already wraps `waitFor` -- do not nest them
|
|
61
|
+
|
|
62
|
+
### 3. Improper Mocking
|
|
63
|
+
- **symptoms**:
|
|
64
|
+
- Tests pass but component fails in production
|
|
65
|
+
- Mocks do not match real API shape (type mismatch)
|
|
66
|
+
- Every test has extensive mock setup boilerplate
|
|
67
|
+
- Changing API requires updating dozens of mock files
|
|
68
|
+
- Tests do not catch real integration issues
|
|
69
|
+
- **causes**:
|
|
70
|
+
- Manual mocking of `fetch`/`axios` instead of using MSW
|
|
71
|
+
- Mock data not matching actual API response types
|
|
72
|
+
- Over-mocking (mocking things that should be tested)
|
|
73
|
+
- Not using TypeScript-typed mock factories
|
|
74
|
+
- **strategy**:
|
|
75
|
+
1. Use MSW for API mocking -- intercepts at network level
|
|
76
|
+
2. Define handlers per API endpoint: `rest.get('/api/users', (req, res, ctx) => ...)`
|
|
77
|
+
3. Create typed mock factories: `function createMockUser(overrides?: Partial<User>): User`
|
|
78
|
+
4. Share handlers across tests with a `handlers.ts` file
|
|
79
|
+
5. Override individual handlers per test: `server.use(rest.get('/api/users', errorHandler))`
|
|
80
|
+
6. Use `msw/node` for Vitest/Jest, `msw/browser` for Storybook
|
|
81
|
+
- **tools**: file_read, file_edit, grep
|
|
82
|
+
- **pitfalls**:
|
|
83
|
+
- MSW v2 uses a different API than v1 -- check which version is installed
|
|
84
|
+
- Do NOT mock `React.useState` or `React.useEffect` -- test the behavior they produce
|
|
85
|
+
- Mock at the highest appropriate level (network > module > function)
|
|
86
|
+
|
|
87
|
+
### 4. Missing Edge Case Coverage
|
|
88
|
+
- **symptoms**:
|
|
89
|
+
- Tests only cover the happy path
|
|
90
|
+
- No tests for loading states, error states, empty states
|
|
91
|
+
- No tests for boundary conditions (empty list, max length, special characters)
|
|
92
|
+
- No tests for keyboard navigation or screen reader
|
|
93
|
+
- Bugs found in production that should have been caught
|
|
94
|
+
- **causes**:
|
|
95
|
+
- Rushing to meet coverage targets with superficial tests
|
|
96
|
+
- Not thinking about failure modes during test design
|
|
97
|
+
- No test plan or checklist
|
|
98
|
+
- Only testing what was explicitly specified
|
|
99
|
+
- **strategy**:
|
|
100
|
+
1. For each component, test: render, interaction, loading, error, empty, edge
|
|
101
|
+
2. Test error boundaries: what happens when child throws
|
|
102
|
+
3. Test with empty data, null data, maximum data
|
|
103
|
+
4. Test keyboard interactions: Tab, Enter, Escape, Arrow keys
|
|
104
|
+
5. Test responsive behavior if component adapts to screen size
|
|
105
|
+
6. Test with slow network (MSW delay) for loading states
|
|
106
|
+
- **tools**: file_read, file_edit, shell_exec
|
|
107
|
+
- **pitfalls**:
|
|
108
|
+
- 100% code coverage does not mean 100% bug coverage -- focus on behavior coverage
|
|
109
|
+
- Do NOT write tests just to increase coverage numbers
|
|
110
|
+
- Edge cases are where most production bugs live
|
|
111
|
+
|
|
112
|
+
### 5. Snapshot Testing Misuse
|
|
113
|
+
- **symptoms**:
|
|
114
|
+
- Snapshot files are massive (1000+ lines)
|
|
115
|
+
- Developers blindly update snapshots with `--update`
|
|
116
|
+
- Snapshots break on every style change
|
|
117
|
+
- Snapshots do not catch meaningful regressions
|
|
118
|
+
- PR reviews skip snapshot diffs
|
|
119
|
+
- **causes**:
|
|
120
|
+
- Snapshotting entire page/component trees
|
|
121
|
+
- Using snapshots as primary testing strategy
|
|
122
|
+
- Not combining with behavioral assertions
|
|
123
|
+
- Snapshot of dynamic content (dates, random IDs)
|
|
124
|
+
- **strategy**:
|
|
125
|
+
1. Use inline snapshots for small, stable output: `expect(result).toMatchInlineSnapshot()`
|
|
126
|
+
2. Snapshot only the relevant portion, not the entire tree
|
|
127
|
+
3. Combine with behavioral tests -- snapshots supplement, not replace
|
|
128
|
+
4. Use `toMatchSnapshot` only for pure/stable components (icons, static layouts)
|
|
129
|
+
5. Review every snapshot update carefully in PRs
|
|
130
|
+
6. Prefer explicit assertions over snapshots for logic-heavy components
|
|
131
|
+
- **tools**: file_read, file_edit
|
|
132
|
+
- **pitfalls**:
|
|
133
|
+
- If you update snapshots without reviewing, you may be locking in a bug
|
|
134
|
+
- Snapshots with dynamic data (timestamps, UUIDs) will always fail -- mock or exclude
|
|
135
|
+
- Large snapshot files are a code smell -- your component may be too big
|
|
136
|
+
|
|
137
|
+
## Test Structure Template
|
|
138
|
+
|
|
139
|
+
### Basic Component Test
|
|
140
|
+
```typescript
|
|
141
|
+
import { render, screen } from '@testing-library/react';
|
|
142
|
+
import userEvent from '@testing-library/user-event';
|
|
143
|
+
import { describe, it, expect } from 'vitest';
|
|
144
|
+
import { Button } from './Button';
|
|
145
|
+
|
|
146
|
+
describe('Button', () => {
|
|
147
|
+
it('renders with label text', () => {
|
|
148
|
+
render(<Button>Click me</Button>);
|
|
149
|
+
expect(screen.getByRole('button', { name: /click me/i })).toBeInTheDocument();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('calls onClick when clicked', async () => {
|
|
153
|
+
const user = userEvent.setup();
|
|
154
|
+
const handleClick = vi.fn();
|
|
155
|
+
render(<Button onClick={handleClick}>Click</Button>);
|
|
156
|
+
await user.click(screen.getByRole('button'));
|
|
157
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('is disabled when disabled prop is true', () => {
|
|
161
|
+
render(<Button disabled>Click</Button>);
|
|
162
|
+
expect(screen.getByRole('button')).toBeDisabled();
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Async Component Test with MSW
|
|
168
|
+
```typescript
|
|
169
|
+
import { render, screen } from '@testing-library/react';
|
|
170
|
+
import { http, HttpResponse } from 'msw';
|
|
171
|
+
import { setupServer } from 'msw/node';
|
|
172
|
+
import { UserList } from './UserList';
|
|
173
|
+
|
|
174
|
+
const server = setupServer(
|
|
175
|
+
http.get('/api/users', () => {
|
|
176
|
+
return HttpResponse.json([
|
|
177
|
+
{ id: '1', name: 'Alice' },
|
|
178
|
+
{ id: '2', name: 'Bob' },
|
|
179
|
+
]);
|
|
180
|
+
})
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
beforeAll(() => server.listen());
|
|
184
|
+
afterEach(() => server.resetHandlers());
|
|
185
|
+
afterAll(() => server.close());
|
|
186
|
+
|
|
187
|
+
describe('UserList', () => {
|
|
188
|
+
it('shows loading then users', async () => {
|
|
189
|
+
render(<UserList />);
|
|
190
|
+
expect(screen.getByText(/loading/i)).toBeInTheDocument();
|
|
191
|
+
expect(await screen.findByText('Alice')).toBeInTheDocument();
|
|
192
|
+
expect(screen.getByText('Bob')).toBeInTheDocument();
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it('shows error on API failure', async () => {
|
|
196
|
+
server.use(
|
|
197
|
+
http.get('/api/users', () => {
|
|
198
|
+
return HttpResponse.json({ message: 'Server Error' }, { status: 500 });
|
|
199
|
+
})
|
|
200
|
+
);
|
|
201
|
+
render(<UserList />);
|
|
202
|
+
expect(await screen.findByText(/error/i)).toBeInTheDocument();
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('shows empty message when no users', async () => {
|
|
206
|
+
server.use(
|
|
207
|
+
http.get('/api/users', () => {
|
|
208
|
+
return HttpResponse.json([]);
|
|
209
|
+
})
|
|
210
|
+
);
|
|
211
|
+
render(<UserList />);
|
|
212
|
+
expect(await screen.findByText(/no users/i)).toBeInTheDocument();
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Custom Hook Test
|
|
218
|
+
```typescript
|
|
219
|
+
import { renderHook, act } from '@testing-library/react';
|
|
220
|
+
import { useCounter } from './useCounter';
|
|
221
|
+
|
|
222
|
+
describe('useCounter', () => {
|
|
223
|
+
it('initializes with default value', () => {
|
|
224
|
+
const { result } = renderHook(() => useCounter(0));
|
|
225
|
+
expect(result.current.count).toBe(0);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('increments', () => {
|
|
229
|
+
const { result } = renderHook(() => useCounter(0));
|
|
230
|
+
act(() => result.current.increment());
|
|
231
|
+
expect(result.current.count).toBe(1);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('resets to initial value', () => {
|
|
235
|
+
const { result } = renderHook(() => useCounter(5));
|
|
236
|
+
act(() => result.current.increment());
|
|
237
|
+
act(() => result.current.reset());
|
|
238
|
+
expect(result.current.count).toBe(5);
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## RTL Query Priority (Use in This Order)
|
|
244
|
+
1. `getByRole` -- accessible role (button, heading, textbox, etc.)
|
|
245
|
+
2. `getByLabelText` -- form elements with labels
|
|
246
|
+
3. `getByPlaceholderText` -- input placeholders
|
|
247
|
+
4. `getByText` -- visible text content
|
|
248
|
+
5. `getByDisplayValue` -- current input value
|
|
249
|
+
6. `getByAltText` -- images
|
|
250
|
+
7. `getByTitle` -- title attribute
|
|
251
|
+
8. `getByTestId` -- last resort, data-testid attribute
|
|
252
|
+
|
|
253
|
+
## Tool Sequence
|
|
254
|
+
1. **file_read** -- Read the target component to understand its behavior and props
|
|
255
|
+
2. **grep** -- Search for existing test patterns in the project (test runner, assertion style)
|
|
256
|
+
3. **grep** -- Check for MSW setup, test utilities, custom render wrappers
|
|
257
|
+
4. **file_read** -- Read related hooks/stores that the component depends on
|
|
258
|
+
5. **file_edit** -- Create the test file following project conventions
|
|
259
|
+
6. **file_edit** -- Add MSW handlers if the component makes API calls
|
|
260
|
+
7. **shell_exec** -- Run tests: `pnpm test` or `vitest run <file>`
|
|
261
|
+
8. **shell_exec** -- Check coverage: `vitest run --coverage <file>`
|
|
262
|
+
|
|
263
|
+
## Validation Checklist
|
|
264
|
+
- [ ] Tests use `getByRole` or `getByLabelText` as primary queries (not `getByTestId`)
|
|
265
|
+
- [ ] All async operations are properly awaited
|
|
266
|
+
- [ ] Loading, success, error, and empty states are tested
|
|
267
|
+
- [ ] User interactions are tested with `userEvent` (not `fireEvent`)
|
|
268
|
+
- [ ] API calls are mocked with MSW (not manual fetch/axios mocks)
|
|
269
|
+
- [ ] No "act(...)" warnings in test output
|
|
270
|
+
- [ ] Tests do not depend on implementation details (class names, internal state)
|
|
271
|
+
- [ ] All tests pass: `pnpm test`
|
|
272
|
+
- [ ] No flaky tests (run 3x to verify)
|
|
273
|
+
- [ ] Edge cases covered (empty input, max length, special characters)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "build-fix",
|
|
3
|
+
"name": "React/Next.js Build Error Fix",
|
|
4
|
+
"description": "Four-phase strategy to collect, categorize, fix, and verify React/Next.js build errors",
|
|
5
|
+
"problemClass": "build_error",
|
|
6
|
+
"phases": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Collect Build Errors",
|
|
9
|
+
"tools": ["shell_exec"],
|
|
10
|
+
"maxIterations": 2,
|
|
11
|
+
"successCriteria": "Full build output captured from 'pnpm build' or 'next build'. All error messages, file paths, and line numbers extracted. Error count documented."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Categorize Errors",
|
|
15
|
+
"tools": ["file_read", "grep"],
|
|
16
|
+
"maxIterations": 5,
|
|
17
|
+
"successCriteria": "Each error categorized as one of: (1) TypeScript type error — missing type, wrong type, generic inference failure, (2) Module not found — missing dependency, wrong import path, missing barrel export, (3) ESLint error — hooks rules, unused vars, import order, (4) Next.js specific — server/client boundary violation, metadata export error, route config issue, (5) Runtime error during SSG/ISR — data fetching failure, env var missing. Fix priority established (blocking errors first)."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Apply Fixes",
|
|
21
|
+
"tools": ["file_read", "file_edit", "shell_exec", "grep"],
|
|
22
|
+
"maxIterations": 10,
|
|
23
|
+
"successCriteria": "All categorized errors addressed. TypeScript errors fixed with proper types (no 'any' escape hatches). Missing modules installed or import paths corrected. ESLint errors fixed at source (not disabled). Next.js boundary issues resolved with 'use client'/'use server' directives. Each fix verified with incremental tsc --noEmit check."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "Verify Clean Build",
|
|
27
|
+
"tools": ["shell_exec"],
|
|
28
|
+
"maxIterations": 3,
|
|
29
|
+
"successCriteria": "Full 'pnpm build' or 'next build' passes with zero errors. No new warnings introduced. Build output size is reasonable (no accidental bundle bloat). All existing tests pass. TypeScript strict mode passes (tsc --noEmit)."
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"exitCriteria": [
|
|
33
|
+
"pnpm build (or next build) passes with zero errors",
|
|
34
|
+
"tsc --noEmit passes",
|
|
35
|
+
"No new ESLint warnings or errors",
|
|
36
|
+
"All existing tests pass",
|
|
37
|
+
"No 'any' type escape hatches introduced",
|
|
38
|
+
"Bundle size has not increased significantly"
|
|
39
|
+
],
|
|
40
|
+
"fallback": null,
|
|
41
|
+
"estimatedTokens": 4000,
|
|
42
|
+
"confidence": 0.80
|
|
43
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hook-loop-fix",
|
|
3
|
+
"name": "useEffect Infinite Loop Fix",
|
|
4
|
+
"description": "Three-phase strategy to identify, fix, and verify useEffect infinite loop / maximum update depth issues",
|
|
5
|
+
"problemClass": "infinite_render_loop",
|
|
6
|
+
"phases": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Identify Loop Source",
|
|
9
|
+
"tools": ["grep", "file_read"],
|
|
10
|
+
"maxIterations": 5,
|
|
11
|
+
"successCriteria": "Specific useEffect identified that causes the loop. Dependency array analyzed. Root cause classified as one of: (1) missing dependency array, (2) object/array reference in deps creating new reference each render, (3) state setter in effect body with that state in deps, (4) function reference in deps recreated each render, (5) mutual state updates between multiple effects. Call stack or component name identified."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Fix Dependencies",
|
|
15
|
+
"tools": ["file_read", "file_edit"],
|
|
16
|
+
"maxIterations": 5,
|
|
17
|
+
"successCriteria": "Fix applied using appropriate technique: (a) add missing dependency array, (b) stabilize object/array deps with useMemo, (c) use functional state updater to remove state from deps, (d) wrap function deps in useCallback, (e) extract primitive values from objects for deps, (f) refactor mutual updates into useReducer. No eslint-disable comments added for react-hooks/exhaustive-deps. No TypeScript errors."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Verify Stability",
|
|
21
|
+
"tools": ["shell_exec", "grep"],
|
|
22
|
+
"maxIterations": 3,
|
|
23
|
+
"successCriteria": "Build passes. No 'Maximum update depth exceeded' errors. No 'Too many re-renders' errors. Component renders expected number of times (verify with React DevTools Profiler or console.log count). All existing tests pass. No new ESLint warnings from react-hooks/exhaustive-deps."
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"exitCriteria": [
|
|
27
|
+
"No infinite loop or maximum update depth errors",
|
|
28
|
+
"Build passes without errors",
|
|
29
|
+
"Component renders correct number of times",
|
|
30
|
+
"eslint react-hooks/exhaustive-deps passes without disable comments",
|
|
31
|
+
"All existing tests pass"
|
|
32
|
+
],
|
|
33
|
+
"fallback": null,
|
|
34
|
+
"estimatedTokens": 2000,
|
|
35
|
+
"confidence": 0.85
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "hydration-fix",
|
|
3
|
+
"name": "Hydration Mismatch Fix",
|
|
4
|
+
"description": "Multi-phase strategy to diagnose and resolve React hydration mismatches in SSR/Next.js applications",
|
|
5
|
+
"problemClass": "hydration_error",
|
|
6
|
+
"phases": [
|
|
7
|
+
{
|
|
8
|
+
"name": "Reproduce & Collect Evidence",
|
|
9
|
+
"tools": ["shell_exec", "grep", "file_read"],
|
|
10
|
+
"maxIterations": 3,
|
|
11
|
+
"successCriteria": "Hydration error message identified with specific component and line reference. Build output collected showing the exact mismatch text."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"name": "Diagnose Root Cause",
|
|
15
|
+
"tools": ["grep", "file_read"],
|
|
16
|
+
"maxIterations": 5,
|
|
17
|
+
"successCriteria": "Root cause identified: one of (1) browser API in render path, (2) date/random in render, (3) conditional rendering based on typeof window, (4) third-party component accessing browser globals, (5) data mismatch between server and client. Affected files and line numbers documented."
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"name": "Apply Fix",
|
|
21
|
+
"tools": ["file_edit", "file_read"],
|
|
22
|
+
"maxIterations": 5,
|
|
23
|
+
"successCriteria": "Fix applied using appropriate strategy: (a) useEffect wrapper for client-only code, (b) next/dynamic with ssr:false for client-only components, (c) useIsClient hook for conditional rendering, (d) suppressHydrationWarning for intentional mismatches. No new TypeScript errors introduced."
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"name": "Verify Fix",
|
|
27
|
+
"tools": ["shell_exec", "grep"],
|
|
28
|
+
"maxIterations": 3,
|
|
29
|
+
"successCriteria": "next build passes without errors. Dev server shows zero hydration warnings in console. Server-rendered HTML verified with curl to contain expected content. Existing tests pass."
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"exitCriteria": [
|
|
33
|
+
"next build completes successfully",
|
|
34
|
+
"Zero hydration mismatch warnings in browser console",
|
|
35
|
+
"Server-rendered HTML contains expected content",
|
|
36
|
+
"All existing tests pass",
|
|
37
|
+
"No new TypeScript errors"
|
|
38
|
+
],
|
|
39
|
+
"fallback": "ssr-disable-component",
|
|
40
|
+
"estimatedTokens": 3000,
|
|
41
|
+
"confidence": 0.90
|
|
42
|
+
}
|