tribunal-kit 2.4.6 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. package/.agent/agents/accessibility-reviewer.md +220 -134
  2. package/.agent/agents/ai-code-reviewer.md +233 -129
  3. package/.agent/agents/backend-specialist.md +238 -178
  4. package/.agent/agents/code-archaeologist.md +181 -119
  5. package/.agent/agents/database-architect.md +207 -164
  6. package/.agent/agents/debugger.md +218 -151
  7. package/.agent/agents/dependency-reviewer.md +136 -55
  8. package/.agent/agents/devops-engineer.md +238 -175
  9. package/.agent/agents/documentation-writer.md +221 -137
  10. package/.agent/agents/explorer-agent.md +180 -142
  11. package/.agent/agents/frontend-reviewer.md +194 -80
  12. package/.agent/agents/frontend-specialist.md +237 -188
  13. package/.agent/agents/game-developer.md +52 -184
  14. package/.agent/agents/logic-reviewer.md +149 -78
  15. package/.agent/agents/mobile-developer.md +223 -152
  16. package/.agent/agents/mobile-reviewer.md +195 -79
  17. package/.agent/agents/orchestrator.md +211 -170
  18. package/.agent/agents/penetration-tester.md +174 -131
  19. package/.agent/agents/performance-optimizer.md +203 -139
  20. package/.agent/agents/performance-reviewer.md +211 -108
  21. package/.agent/agents/product-manager.md +162 -108
  22. package/.agent/agents/project-planner.md +162 -142
  23. package/.agent/agents/qa-automation-engineer.md +242 -138
  24. package/.agent/agents/security-auditor.md +194 -170
  25. package/.agent/agents/seo-specialist.md +213 -132
  26. package/.agent/agents/sql-reviewer.md +194 -73
  27. package/.agent/agents/supervisor-agent.md +203 -156
  28. package/.agent/agents/test-coverage-reviewer.md +193 -81
  29. package/.agent/agents/type-safety-reviewer.md +208 -65
  30. package/.agent/scripts/__pycache__/auto_preview.cpython-311.pyc +0 -0
  31. package/.agent/scripts/__pycache__/bundle_analyzer.cpython-311.pyc +0 -0
  32. package/.agent/scripts/__pycache__/checklist.cpython-311.pyc +0 -0
  33. package/.agent/scripts/__pycache__/dependency_analyzer.cpython-311.pyc +0 -0
  34. package/.agent/scripts/__pycache__/security_scan.cpython-311.pyc +0 -0
  35. package/.agent/scripts/__pycache__/session_manager.cpython-311.pyc +0 -0
  36. package/.agent/scripts/__pycache__/skill_integrator.cpython-311.pyc +0 -0
  37. package/.agent/scripts/__pycache__/swarm_dispatcher.cpython-311.pyc +0 -0
  38. package/.agent/scripts/__pycache__/test_runner.cpython-311.pyc +0 -0
  39. package/.agent/scripts/__pycache__/verify_all.cpython-311.pyc +0 -0
  40. package/.agent/skills/agent-organizer/SKILL.md +126 -132
  41. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +155 -66
  42. package/.agent/skills/api-patterns/SKILL.md +289 -257
  43. package/.agent/skills/api-security-auditor/SKILL.md +172 -70
  44. package/.agent/skills/app-builder/templates/chrome-extension/TEMPLATE.md +1 -1
  45. package/.agent/skills/app-builder/templates/electron-desktop/TEMPLATE.md +1 -1
  46. package/.agent/skills/appflow-wireframe/SKILL.md +107 -100
  47. package/.agent/skills/architecture/SKILL.md +331 -200
  48. package/.agent/skills/authentication-best-practices/SKILL.md +168 -67
  49. package/.agent/skills/bash-linux/SKILL.md +154 -215
  50. package/.agent/skills/brainstorming/SKILL.md +104 -210
  51. package/.agent/skills/building-native-ui/SKILL.md +169 -70
  52. package/.agent/skills/clean-code/SKILL.md +360 -206
  53. package/.agent/skills/config-validator/SKILL.md +141 -165
  54. package/.agent/skills/csharp-developer/SKILL.md +528 -107
  55. package/.agent/skills/database-design/SKILL.md +455 -275
  56. package/.agent/skills/deployment-procedures/SKILL.md +145 -188
  57. package/.agent/skills/devops-engineer/SKILL.md +332 -134
  58. package/.agent/skills/devops-incident-responder/SKILL.md +113 -98
  59. package/.agent/skills/edge-computing/SKILL.md +157 -213
  60. package/.agent/skills/extract-design-system/SKILL.md +129 -69
  61. package/.agent/skills/framer-motion-expert/SKILL.md +939 -0
  62. package/.agent/skills/game-design-expert/SKILL.md +105 -0
  63. package/.agent/skills/game-engineering-expert/SKILL.md +122 -0
  64. package/.agent/skills/geo-fundamentals/SKILL.md +124 -215
  65. package/.agent/skills/github-operations/SKILL.md +314 -354
  66. package/.agent/skills/gsap-expert/SKILL.md +901 -0
  67. package/.agent/skills/i18n-localization/SKILL.md +138 -216
  68. package/.agent/skills/intelligent-routing/SKILL.md +127 -139
  69. package/.agent/skills/llm-engineering/SKILL.md +357 -258
  70. package/.agent/skills/local-first/SKILL.md +154 -203
  71. package/.agent/skills/mcp-builder/SKILL.md +118 -224
  72. package/.agent/skills/nextjs-react-expert/SKILL.md +783 -203
  73. package/.agent/skills/nodejs-best-practices/SKILL.md +559 -280
  74. package/.agent/skills/observability/SKILL.md +330 -285
  75. package/.agent/skills/parallel-agents/SKILL.md +122 -181
  76. package/.agent/skills/performance-profiling/SKILL.md +254 -197
  77. package/.agent/skills/plan-writing/SKILL.md +118 -188
  78. package/.agent/skills/platform-engineer/SKILL.md +123 -135
  79. package/.agent/skills/playwright-best-practices/SKILL.md +157 -76
  80. package/.agent/skills/powershell-windows/SKILL.md +146 -230
  81. package/.agent/skills/python-pro/SKILL.md +879 -114
  82. package/.agent/skills/react-specialist/SKILL.md +931 -108
  83. package/.agent/skills/realtime-patterns/SKILL.md +304 -296
  84. package/.agent/skills/rust-pro/SKILL.md +701 -240
  85. package/.agent/skills/seo-fundamentals/SKILL.md +154 -181
  86. package/.agent/skills/server-management/SKILL.md +190 -212
  87. package/.agent/skills/shadcn-ui-expert/SKILL.md +201 -68
  88. package/.agent/skills/sql-pro/SKILL.md +633 -104
  89. package/.agent/skills/swiftui-expert/SKILL.md +171 -70
  90. package/.agent/skills/systematic-debugging/SKILL.md +118 -186
  91. package/.agent/skills/tailwind-patterns/SKILL.md +576 -232
  92. package/.agent/skills/tdd-workflow/SKILL.md +137 -209
  93. package/.agent/skills/testing-patterns/SKILL.md +573 -205
  94. package/.agent/skills/vue-expert/SKILL.md +964 -119
  95. package/.agent/skills/vulnerability-scanner/SKILL.md +269 -316
  96. package/.agent/skills/web-accessibility-auditor/SKILL.md +188 -71
  97. package/.agent/skills/webapp-testing/SKILL.md +145 -236
  98. package/.agent/workflows/api-tester.md +151 -279
  99. package/.agent/workflows/audit.md +138 -168
  100. package/.agent/workflows/brainstorm.md +110 -146
  101. package/.agent/workflows/changelog.md +112 -144
  102. package/.agent/workflows/create.md +124 -139
  103. package/.agent/workflows/debug.md +189 -196
  104. package/.agent/workflows/deploy.md +189 -153
  105. package/.agent/workflows/enhance.md +151 -139
  106. package/.agent/workflows/fix.md +135 -143
  107. package/.agent/workflows/generate.md +157 -164
  108. package/.agent/workflows/migrate.md +160 -163
  109. package/.agent/workflows/orchestrate.md +168 -151
  110. package/.agent/workflows/performance-benchmarker.md +123 -305
  111. package/.agent/workflows/plan.md +173 -151
  112. package/.agent/workflows/preview.md +80 -137
  113. package/.agent/workflows/refactor.md +183 -153
  114. package/.agent/workflows/review-ai.md +129 -140
  115. package/.agent/workflows/review.md +116 -155
  116. package/.agent/workflows/session.md +94 -154
  117. package/.agent/workflows/status.md +79 -125
  118. package/.agent/workflows/strengthen-skills.md +139 -99
  119. package/.agent/workflows/swarm.md +179 -194
  120. package/.agent/workflows/test.md +211 -166
  121. package/.agent/workflows/tribunal-backend.md +113 -111
  122. package/.agent/workflows/tribunal-database.md +115 -132
  123. package/.agent/workflows/tribunal-frontend.md +118 -115
  124. package/.agent/workflows/tribunal-full.md +133 -136
  125. package/.agent/workflows/tribunal-mobile.md +119 -123
  126. package/.agent/workflows/tribunal-performance.md +133 -152
  127. package/.agent/workflows/ui-ux-pro-max.md +143 -171
  128. package/README.md +11 -15
  129. package/package.json +1 -1
  130. package/.agent/skills/dotnet-core-expert/SKILL.md +0 -103
  131. package/.agent/skills/framer-motion-animations/SKILL.md +0 -74
  132. package/.agent/skills/game-development/2d-games/SKILL.md +0 -119
  133. package/.agent/skills/game-development/3d-games/SKILL.md +0 -135
  134. package/.agent/skills/game-development/SKILL.md +0 -236
  135. package/.agent/skills/game-development/game-art/SKILL.md +0 -185
  136. package/.agent/skills/game-development/game-audio/SKILL.md +0 -190
  137. package/.agent/skills/game-development/game-design/SKILL.md +0 -129
  138. package/.agent/skills/game-development/mobile-games/SKILL.md +0 -108
  139. package/.agent/skills/game-development/multiplayer/SKILL.md +0 -132
  140. package/.agent/skills/game-development/pc-games/SKILL.md +0 -144
  141. package/.agent/skills/game-development/vr-ar/SKILL.md +0 -123
  142. package/.agent/skills/game-development/web-games/SKILL.md +0 -150
@@ -1,108 +1,931 @@
1
- ---
2
- name: react-specialist
3
- description: Senior React specialist (React 18+) focusing on advanced patterns, state management, performance optimization, and production architectures (Next.js/Remix).
4
- allowed-tools: Read, Write, Edit, Glob, Grep
5
- version: 1.0.0
6
- last-updated: 2026-03-12
7
- applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
8
- ---
9
-
10
- # React Specialist - Claude Code Sub-Agent
11
-
12
- You are a senior React specialist with expertise in React 18+ and the modern React ecosystem. Your focus spans advanced patterns, performance optimization, state management, and production architectures with emphasis on creating scalable applications that deliver exceptional user experiences.
13
-
14
- ## Configuration & Context Assessment
15
- When invoked:
16
- 1. Query context manager for React project requirements and architecture
17
- 2. Review component structure, state management, and performance needs
18
- 3. Analyze optimization opportunities, patterns, and best practices
19
- 4. Implement modern React solutions with performance and maintainability focus
20
-
21
- ---
22
-
23
- ## The React Excellence Checklist
24
- - React 18+ features utilized effectively
25
- - TypeScript strict mode enabled properly
26
- - Component reusability > 80% achieved
27
- - Performance score > 95 maintained
28
- - Test coverage > 90% implemented
29
- - Bundle size optimized thoroughly
30
- - Accessibility compliant consistently
31
-
32
- ---
33
-
34
- ## Core Architecture Decision Framework
35
-
36
- ### Advanced React Patterns & Hooks Mastery
37
- * Compound components, Render props, Custom hooks design, Ref forwarding, Portals.
38
- * `useState` patterns, `useEffect` optimization, `useMemo`/`useCallback` carefully applied, `useReducer` complex state, custom hooks library.
39
- * Concurrent features (`useTransition`, `useDeferredValue`, Suspense for data/streaming HTML).
40
-
41
- ### State Management & Components
42
- * **State:** Server state (React Query/TanStack), Global state (Zustand, Redux Toolkit, Jotai), Local and URL state.
43
- * **Structure:** Atomic design, Container/presentational separation, Error boundaries, Fragment usage.
44
-
45
- ### extreme Performance Optimization
46
- * `React.memo` usage, Code splitting, Virtual scrolling.
47
- * Selective hydration, Bundle analysis, Tree shaking.
48
- * Core Web Vitals driven implementation (LCP, FID, CLS).
49
-
50
- ### Production Architectures (SSR)
51
- * **Next.js/Remix:** Server components, Streaming SSR, Progressive enhancement, SEO optimization.
52
- * **Ecosystem:** React Query, Tailwind CSS, Framer Motion, React Hook Form.
53
-
54
- ---
55
-
56
- ## Output Format
57
-
58
- When this skill produces or reviews code, structure your output as follows:
59
-
60
- ```
61
- ━━━ React Specialist Report ━━━━━━━━━━━━━━━━━━━━━━━━
62
- Skill: React Specialist
63
- Language: [detected language / framework]
64
- Scope: [N files · N functions]
65
- ─────────────────────────────────────────────────
66
- Passed: [checks that passed, or "All clean"]
67
- ⚠️ Warnings: [non-blocking issues, or "None"]
68
- Blocked: [blocking issues requiring fix, or "None"]
69
- ─────────────────────────────────────────────────
70
- VBC status: PENDING VERIFIED
71
- Evidence: [test output / lint pass / compile success]
72
- ```
73
-
74
- **VBC (Verification-Before-Completion) is mandatory.**
75
- Do not mark status as VERIFIED until concrete terminal evidence is provided.
76
-
77
-
78
- ---
79
-
80
- ## 🏛️ Tribunal Integration (Anti-Hallucination)
81
-
82
- **Slash command: `/tribunal-frontend`**
83
- **Active reviewers: `logic` · `security` · `frontend` · `type-safety`**
84
-
85
- ### Forbidden AI Tropes in React
86
- 1. **Sloppy Layout Generation** — never build UI without explicit dimensional boundaries. You MUST apply strict numeric design tokens (e.g. 4px grid spacing) and explicit flex/grid layouts.
87
- 2. **Unnecessary `useEffect` Data Fetching** never fetch raw data inside a `useEffect` if a framework pattern (Server Components, SWR, React Query) is available.
88
- 3. **Missing `key` in maps** — always provide a unique, stable key. No using iteration index as the key.
89
- 4. **Prop Drilling Nightmare** — avoid passing props more than 3 levels deep; use Context or atomic stores (Zustand) instead.
90
- 4. **Over-Memoization** do not slap `useMemo`/`useCallback` on everything prematurely. Only use it when profiling proves a performance bottleneck.
91
- 5. **Class Components** — never hallucinate class `extends React.Component` or lifecycle methods (`componentDidMount`) in a modern React 18+ app unless explicitly requested for legacy migration.
92
-
93
- ### Pre-Flight Self-Audit
94
-
95
- Review these questions before generating React code:
96
- ```text
97
- Did I use strictly functional components with hooks?
98
- ✅ Is my component free of side effects during the render phase?
99
- Are array maps properly utilizing unique and stable `key` attributes?
100
- Did I configure proper fallbacks using `<Suspense>` and Error Boundaries?
101
- ✅ When handling state, did I ensure that mutated state is returned as a deeply cloned or immutable structure?
102
- ```
103
-
104
- ### 🛑 Verification-Before-Completion (VBC) Protocol
105
-
106
- **CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
107
- - ❌ **Forbidden:** Assuming a React component "works" just because it compiles or because the bundler gives no immediate warnings.
108
- - ✅ **Required:** You are explicitly forbidden from completing your UI assignment without providing **concrete terminal/test evidence** (e.g., passing Jest/Vitest logs, successful build output, or specific CLI execution results) proving the build is error-free.
1
+ ---
2
+ name: react-specialist
3
+ description: Senior React specialist (React 19+) focusing on advanced patterns, hooks mastery, React Compiler, Server Components, state management (Zustand/Jotai/React Query), performance optimization, and production architectures (Next.js/Remix). Use when building React components, optimizing renders, managing state, or implementing modern React 19 patterns.
4
+ allowed-tools: Read, Write, Edit, Glob, Grep
5
+ version: 2.0.0
6
+ last-updated: 2026-03-30
7
+ applies-to-model: gemini-2.5-pro, claude-3-7-sonnet
8
+ ---
9
+
10
+ # React Specialist React 19+ Mastery
11
+
12
+ > React 19 is a paradigm shift. Server Components are the default. The React Compiler handles memoization. `use()` replaces `useEffect` data fetching. If you're still writing React 18 patterns, you're writing legacy code.
13
+
14
+ ---
15
+
16
+ ## React 19 Core API Changes
17
+
18
+ ### The `use()` Hook
19
+
20
+ ```tsx
21
+ // use() can read promises and context — replaces many useEffect patterns
22
+ import { use } from "react";
23
+
24
+ function UserProfile({ userPromise }: { userPromise: Promise<User> }) {
25
+ const user = use(userPromise); // suspends until resolved
26
+ return <h1>{user.name}</h1>;
27
+ }
28
+
29
+ // use() with context (replaces useContext — can be used conditionally)
30
+ function Theme({ isAdmin }: { isAdmin: boolean }) {
31
+ if (isAdmin) {
32
+ const theme = use(ThemeContext); // ✅ conditional context read
33
+ return <AdminPanel theme={theme} />;
34
+ }
35
+ return <PublicPanel />;
36
+ }
37
+
38
+ // HALLUCINATION TRAP: use() is NOT useContext()
39
+ // useContext cannot be called inside conditionals or loops
40
+ // use() CAN be called inside conditionals (it's a new primitive)
41
+ ```
42
+
43
+ ### `useActionState` (Forms)
44
+
45
+ ```tsx
46
+ import { useActionState } from "react";
47
+
48
+ async function submitForm(prevState: FormState, formData: FormData) {
49
+ const email = formData.get("email") as string;
50
+
51
+ if (!email.includes("@")) {
52
+ return { error: "Invalid email", success: false };
53
+ }
54
+
55
+ await saveToDatabase(email);
56
+ return { error: null, success: true };
57
+ }
58
+
59
+ function SignupForm() {
60
+ const [state, formAction, isPending] = useActionState(submitForm, {
61
+ error: null,
62
+ success: false,
63
+ });
64
+
65
+ return (
66
+ <form action={formAction}>
67
+ <input name="email" type="email" disabled={isPending} />
68
+ {state.error && <p className="error">{state.error}</p>}
69
+ <button type="submit" disabled={isPending}>
70
+ {isPending ? "Submitting..." : "Sign Up"}
71
+ </button>
72
+ </form>
73
+ );
74
+ }
75
+
76
+ // ❌ HALLUCINATION TRAP: useActionState was briefly named useFormState
77
+ // in React canaries. The STABLE name is useActionState.
78
+ // ❌ HALLUCINATION TRAP: The signature is (action, initialState)
79
+ // The action receives (prevState, formData), NOT just formData
80
+ ```
81
+
82
+ ### `useOptimistic`
83
+
84
+ ```tsx
85
+ import { useOptimistic } from "react";
86
+
87
+ function TodoList({ todos }: { todos: Todo[] }) {
88
+ const [optimisticTodos, addOptimisticTodo] = useOptimistic(
89
+ todos,
90
+ (currentTodos, newTodo: Todo) => [...currentTodos, newTodo]
91
+ );
92
+
93
+ async function handleAdd(formData: FormData) {
94
+ const title = formData.get("title") as string;
95
+ const tempTodo = { id: crypto.randomUUID(), title, pending: true };
96
+
97
+ addOptimisticTodo(tempTodo); // instantly updates UI
98
+
99
+ await saveTodo(title); // actual API call
100
+ // When server responds, `todos` prop updates and optimistic state resets
101
+ }
102
+
103
+ return (
104
+ <div>
105
+ <form action={handleAdd}>
106
+ <input name="title" />
107
+ <button type="submit">Add</button>
108
+ </form>
109
+ <ul>
110
+ {optimisticTodos.map((todo) => (
111
+ <li key={todo.id} style={{ opacity: todo.pending ? 0.5 : 1 }}>
112
+ {todo.title}
113
+ </li>
114
+ ))}
115
+ </ul>
116
+ </div>
117
+ );
118
+ }
119
+ ```
120
+
121
+ ### `useFormStatus`
122
+
123
+ ```tsx
124
+ import { useFormStatus } from "react-dom";
125
+
126
+ // ❌ HALLUCINATION TRAP: useFormStatus must be called from a component
127
+ // INSIDE a <form> — it reads the nearest parent form's status.
128
+ // It does NOT work if called in the same component that renders the <form>.
129
+
130
+ function SubmitButton() {
131
+ const { pending, data, method, action } = useFormStatus();
132
+
133
+ return (
134
+ <button type="submit" disabled={pending}>
135
+ {pending ? "Saving..." : "Save"}
136
+ </button>
137
+ );
138
+ }
139
+
140
+ // Usage:
141
+ function MyForm() {
142
+ return (
143
+ <form action={serverAction}>
144
+ <input name="name" />
145
+ <SubmitButton /> {/* useFormStatus works here — inside the form */}
146
+ </form>
147
+ );
148
+ }
149
+ ```
150
+
151
+ ### `useTransition` (Non-Blocking State Updates)
152
+
153
+ ```tsx
154
+ import { useTransition } from "react";
155
+
156
+ function SearchPage() {
157
+ const [query, setQuery] = useState("");
158
+ const [results, setResults] = useState<Item[]>([]);
159
+ const [isPending, startTransition] = useTransition();
160
+
161
+ function handleSearch(e: React.ChangeEvent<HTMLInputElement>) {
162
+ const value = e.target.value;
163
+ setQuery(value); // urgent — update input immediately
164
+
165
+ startTransition(async () => {
166
+ // non-urgent — React can interrupt this if user types again
167
+ const data = await search(value);
168
+ setResults(data);
169
+ });
170
+ }
171
+
172
+ return (
173
+ <div>
174
+ <input value={query} onChange={handleSearch} />
175
+ {isPending && <Spinner />}
176
+ <ResultsList results={results} />
177
+ </div>
178
+ );
179
+ }
180
+
181
+ // React 19: startTransition now supports async functions
182
+ // React 18: startTransition was synchronous only
183
+ ```
184
+
185
+ ### `useDeferredValue`
186
+
187
+ ```tsx
188
+ import { useDeferredValue, memo } from "react";
189
+
190
+ function SearchResults({ query }: { query: string }) {
191
+ const deferredQuery = useDeferredValue(query);
192
+
193
+ // Shows stale results while the new ones compute
194
+ const isStale = query !== deferredQuery;
195
+
196
+ return (
197
+ <div style={{ opacity: isStale ? 0.6 : 1 }}>
198
+ <ExpensiveList query={deferredQuery} />
199
+ </div>
200
+ );
201
+ }
202
+
203
+ // Initial value support (React 19):
204
+ const value = useDeferredValue(fetchedData, initialFallback);
205
+ ```
206
+
207
+ ---
208
+
209
+ ## The React Compiler
210
+
211
+ ```tsx
212
+ // React 19 ships the React Compiler (formerly React Forget)
213
+ // It automatically memoizes components, values, and callbacks
214
+
215
+ // ❌ LEGACY — do NOT write this in React 19+
216
+ const memoizedValue = useMemo(() => expensiveCalc(a, b), [a, b]);
217
+ const memoizedFn = useCallback(() => handleClick(id), [id]);
218
+ const MemoizedComp = React.memo(MyComponent);
219
+
220
+ // ✅ REACT 19 — just write normal code
221
+ const value = expensiveCalc(a, b);
222
+ function handleClick() { /* ... */ }
223
+ function MyComponent() { /* ... */ }
224
+ // The compiler figures out what needs memoization automatically
225
+
226
+ // ❌ HALLUCINATION TRAP: Do NOT manually memoize in React 19+ projects
227
+ // The compiler is smarter than manual memoization and handles:
228
+ // - Component memoization (replaces React.memo)
229
+ // - Value memoization (replaces useMemo)
230
+ // - Callback memoization (replaces useCallback)
231
+ //
232
+ // EXCEPTION: If the React Compiler is explicitly disabled in the project
233
+ // config, then manual memoization is still appropriate.
234
+ ```
235
+
236
+ ### When Manual Memoization Is Still Valid
237
+
238
+ ```tsx
239
+ // 1. React Compiler is disabled in project config
240
+ // 2. Working with React 18 (no compiler)
241
+ // 3. Library code that must support React 17/18/19
242
+ // 4. Performance-critical code where compiler output is insufficient
243
+ // (measure first with React DevTools Profiler)
244
+
245
+ // Always add a comment explaining why:
246
+ // MANUAL_MEMO: React Compiler disabled in this project
247
+ const cached = useMemo(() => heavyComputation(data), [data]);
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Component Architecture Patterns
253
+
254
+ ### Compound Components
255
+
256
+ ```tsx
257
+ // Compound components share implicit state via context
258
+ const TabsContext = createContext<{
259
+ activeTab: string;
260
+ setActiveTab: (id: string) => void;
261
+ } | null>(null);
262
+
263
+ function Tabs({ children, defaultTab }: { children: ReactNode; defaultTab: string }) {
264
+ const [activeTab, setActiveTab] = useState(defaultTab);
265
+ return (
266
+ <TabsContext value={{ activeTab, setActiveTab }}>
267
+ <div className="tabs">{children}</div>
268
+ </TabsContext>
269
+ );
270
+ }
271
+
272
+ function TabList({ children }: { children: ReactNode }) {
273
+ return <div role="tablist" className="tab-list">{children}</div>;
274
+ }
275
+
276
+ function Tab({ id, children }: { id: string; children: ReactNode }) {
277
+ const ctx = use(TabsContext);
278
+ if (!ctx) throw new Error("Tab must be used inside <Tabs>");
279
+
280
+ return (
281
+ <button
282
+ role="tab"
283
+ aria-selected={ctx.activeTab === id}
284
+ onClick={() => ctx.setActiveTab(id)}
285
+ >
286
+ {children}
287
+ </button>
288
+ );
289
+ }
290
+
291
+ function TabPanel({ id, children }: { id: string; children: ReactNode }) {
292
+ const ctx = use(TabsContext);
293
+ if (!ctx) throw new Error("TabPanel must be used inside <Tabs>");
294
+ if (ctx.activeTab !== id) return null;
295
+
296
+ return <div role="tabpanel">{children}</div>;
297
+ }
298
+
299
+ // Usage:
300
+ <Tabs defaultTab="settings">
301
+ <TabList>
302
+ <Tab id="profile">Profile</Tab>
303
+ <Tab id="settings">Settings</Tab>
304
+ </TabList>
305
+ <TabPanel id="profile"><ProfileContent /></TabPanel>
306
+ <TabPanel id="settings"><SettingsContent /></TabPanel>
307
+ </Tabs>
308
+
309
+ // ❌ HALLUCINATION TRAP: In React 19, context uses <Ctx value={}>
310
+ // NOT <Ctx.Provider value={}>. The .Provider pattern is deprecated.
311
+ ```
312
+
313
+ ### Custom Hooks (Composable Logic)
314
+
315
+ ```tsx
316
+ // useFetch — reusable data fetching with loading/error states
317
+ function useFetch<T>(url: string) {
318
+ const [data, setData] = useState<T | null>(null);
319
+ const [error, setError] = useState<Error | null>(null);
320
+ const [isLoading, setIsLoading] = useState(true);
321
+
322
+ useEffect(() => {
323
+ const controller = new AbortController();
324
+
325
+ async function fetchData() {
326
+ try {
327
+ setIsLoading(true);
328
+ const res = await fetch(url, { signal: controller.signal });
329
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
330
+ const json = await res.json();
331
+ setData(json);
332
+ } catch (err) {
333
+ if (err instanceof Error && err.name !== "AbortError") {
334
+ setError(err);
335
+ }
336
+ } finally {
337
+ setIsLoading(false);
338
+ }
339
+ }
340
+
341
+ fetchData();
342
+ return () => controller.abort(); // cleanup on unmount or URL change
343
+ }, [url]);
344
+
345
+ return { data, error, isLoading };
346
+ }
347
+
348
+ // ❌ HALLUCINATION TRAP: Always include AbortController cleanup
349
+ // Without it, state updates on unmounted components cause warnings
350
+ // and potential memory leaks in SPAs
351
+ ```
352
+
353
+ ### Error Boundaries
354
+
355
+ ```tsx
356
+ // React 19 error boundaries — still class-based (no hook equivalent yet)
357
+ class ErrorBoundary extends Component<
358
+ { children: ReactNode; fallback: ReactNode },
359
+ { hasError: boolean; error: Error | null }
360
+ > {
361
+ state = { hasError: false, error: null };
362
+
363
+ static getDerivedStateFromError(error: Error) {
364
+ return { hasError: true, error };
365
+ }
366
+
367
+ componentDidCatch(error: Error, info: ErrorInfo) {
368
+ console.error("ErrorBoundary caught:", error, info.componentStack);
369
+ // Send to error tracking service (Sentry, etc.)
370
+ }
371
+
372
+ render() {
373
+ if (this.state.hasError) return this.props.fallback;
374
+ return this.props.children;
375
+ }
376
+ }
377
+
378
+ // Usage:
379
+ <ErrorBoundary fallback={<ErrorPage />}>
380
+ <Suspense fallback={<Loading />}>
381
+ <Dashboard />
382
+ </Suspense>
383
+ </ErrorBoundary>
384
+
385
+ // ❌ HALLUCINATION TRAP: There is NO useErrorBoundary hook in React core.
386
+ // Error boundaries MUST be class components.
387
+ // react-error-boundary (npm package) provides a hook-based wrapper.
388
+ ```
389
+
390
+ ### Render Props & Slots
391
+
392
+ ```tsx
393
+ // Render prop for flexible rendering
394
+ interface DataTableProps<T> {
395
+ data: T[];
396
+ renderRow: (item: T, index: number) => ReactNode;
397
+ renderHeader?: () => ReactNode;
398
+ renderEmpty?: () => ReactNode;
399
+ }
400
+
401
+ function DataTable<T>({ data, renderRow, renderHeader, renderEmpty }: DataTableProps<T>) {
402
+ if (data.length === 0) return renderEmpty?.() ?? <p>No data</p>;
403
+
404
+ return (
405
+ <table>
406
+ {renderHeader && <thead>{renderHeader()}</thead>}
407
+ <tbody>
408
+ {data.map((item, i) => (
409
+ <tr key={i}>{renderRow(item, i)}</tr>
410
+ ))}
411
+ </tbody>
412
+ </table>
413
+ );
414
+ }
415
+ ```
416
+
417
+ ---
418
+
419
+ ## State Management Decision Matrix
420
+
421
+ ```
422
+ ┌─────────────────────────────────────────────────────────────────┐
423
+ │ State Type Decision Tree │
424
+ ├─────────────────────────────────────────────────────────────────┤
425
+ │ │
426
+ │ Is it SERVER data (fetched from API/DB)? │
427
+ │ ├── YES → TanStack React Query / SWR │
428
+ │ │ (caching, deduplication, revalidation, optimistic) │
429
+ │ │ │
430
+ │ └── NO → Is it shared across many components? │
431
+ │ ├── YES → Is it complex (many actions/reducers)? │
432
+ │ │ ├── YES → Zustand or Redux Toolkit │
433
+ │ │ └── NO → Zustand (lightweight) or Jotai (atomic) │
434
+ │ │ │
435
+ │ └── NO → Is it just a toggle/input/form? │
436
+ │ ├── YES → useState / useReducer (local) │
437
+ │ └── Is it URL-dependent? │
438
+ │ └── YES → useSearchParams / nuqs │
439
+ └─────────────────────────────────────────────────────────────────┘
440
+ ```
441
+
442
+ ### Zustand (Recommended Default)
443
+
444
+ ```tsx
445
+ import { create } from "zustand";
446
+ import { devtools, persist } from "zustand/middleware";
447
+
448
+ interface CartStore {
449
+ items: CartItem[];
450
+ total: number;
451
+ addItem: (item: CartItem) => void;
452
+ removeItem: (id: string) => void;
453
+ clearCart: () => void;
454
+ }
455
+
456
+ const useCartStore = create<CartStore>()(
457
+ devtools(
458
+ persist(
459
+ (set, get) => ({
460
+ items: [],
461
+ total: 0,
462
+
463
+ addItem: (item) =>
464
+ set((state) => ({
465
+ items: [...state.items, item],
466
+ total: state.total + item.price,
467
+ })),
468
+
469
+ removeItem: (id) =>
470
+ set((state) => ({
471
+ items: state.items.filter((i) => i.id !== id),
472
+ total: state.items
473
+ .filter((i) => i.id !== id)
474
+ .reduce((sum, i) => sum + i.price, 0),
475
+ })),
476
+
477
+ clearCart: () => set({ items: [], total: 0 }),
478
+ }),
479
+ { name: "cart-storage" } // localStorage key
480
+ )
481
+ )
482
+ );
483
+
484
+ // Usage in component:
485
+ function CartIcon() {
486
+ // ✅ Selector — only re-renders when items.length changes
487
+ const count = useCartStore((state) => state.items.length);
488
+ return <span className="badge">{count}</span>;
489
+ }
490
+
491
+ // ❌ HALLUCINATION TRAP: Always use selectors with Zustand
492
+ // useCartStore() without a selector subscribes to EVERYTHING
493
+ // and causes unnecessary re-renders on any store change
494
+ ```
495
+
496
+ ### TanStack React Query (Server State)
497
+
498
+ ```tsx
499
+ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
500
+
501
+ function UserList() {
502
+ const { data, isLoading, error } = useQuery({
503
+ queryKey: ["users"],
504
+ queryFn: () => fetch("/api/users").then((r) => r.json()),
505
+ staleTime: 5 * 60 * 1000, // 5 min before refetch
506
+ gcTime: 10 * 60 * 1000, // 10 min cache lifetime
507
+ });
508
+
509
+ if (isLoading) return <Skeleton />;
510
+ if (error) return <ErrorDisplay error={error} />;
511
+
512
+ return data.map((user: User) => <UserCard key={user.id} user={user} />);
513
+ }
514
+
515
+ // Mutation with optimistic update
516
+ function useDeleteUser() {
517
+ const queryClient = useQueryClient();
518
+
519
+ return useMutation({
520
+ mutationFn: (userId: string) =>
521
+ fetch(`/api/users/${userId}`, { method: "DELETE" }),
522
+
523
+ onMutate: async (userId) => {
524
+ await queryClient.cancelQueries({ queryKey: ["users"] });
525
+ const previous = queryClient.getQueryData<User[]>(["users"]);
526
+
527
+ queryClient.setQueryData<User[]>(["users"], (old) =>
528
+ old?.filter((u) => u.id !== userId)
529
+ );
530
+
531
+ return { previous }; // context for rollback
532
+ },
533
+
534
+ onError: (_err, _userId, context) => {
535
+ queryClient.setQueryData(["users"], context?.previous); // rollback
536
+ },
537
+
538
+ onSettled: () => {
539
+ queryClient.invalidateQueries({ queryKey: ["users"] }); // refetch
540
+ },
541
+ });
542
+ }
543
+
544
+ // ❌ HALLUCINATION TRAP: `cacheTime` was renamed to `gcTime` in React Query v5
545
+ // ❌ HALLUCINATION TRAP: Import from "@tanstack/react-query", NOT "react-query"
546
+ ```
547
+
548
+ ---
549
+
550
+ ## Performance Optimization
551
+
552
+ ### Code Splitting & Lazy Loading
553
+
554
+ ```tsx
555
+ import { lazy, Suspense } from "react";
556
+
557
+ // Lazy load heavy components
558
+ const HeavyChart = lazy(() => import("./HeavyChart"));
559
+ const AdminPanel = lazy(() => import("./AdminPanel"));
560
+
561
+ function App() {
562
+ return (
563
+ <Suspense fallback={<Skeleton />}>
564
+ <HeavyChart />
565
+ </Suspense>
566
+ );
567
+ }
568
+
569
+ // Named exports require:
570
+ const Chart = lazy(() =>
571
+ import("./Charts").then((mod) => ({ default: mod.BarChart }))
572
+ );
573
+ ```
574
+
575
+ ### Virtual Scrolling (Large Lists)
576
+
577
+ ```tsx
578
+ import { useVirtualizer } from "@tanstack/react-virtual";
579
+
580
+ function VirtualList({ items }: { items: Item[] }) {
581
+ const parentRef = useRef<HTMLDivElement>(null);
582
+
583
+ const virtualizer = useVirtualizer({
584
+ count: items.length,
585
+ getScrollElement: () => parentRef.current,
586
+ estimateSize: () => 50, // estimated row height in px
587
+ overscan: 5, // render 5 extra items above/below viewport
588
+ });
589
+
590
+ return (
591
+ <div ref={parentRef} style={{ height: 600, overflow: "auto" }}>
592
+ <div style={{ height: virtualizer.getTotalSize(), position: "relative" }}>
593
+ {virtualizer.getVirtualItems().map((virtualRow) => (
594
+ <div
595
+ key={virtualRow.key}
596
+ style={{
597
+ position: "absolute",
598
+ top: virtualRow.start,
599
+ width: "100%",
600
+ height: virtualRow.size,
601
+ }}
602
+ >
603
+ {items[virtualRow.index].name}
604
+ </div>
605
+ ))}
606
+ </div>
607
+ </div>
608
+ );
609
+ }
610
+
611
+ // Use when: list has 500+ items
612
+ // Do NOT use for: lists under 100 items (adds complexity for no gain)
613
+ ```
614
+
615
+ ### Ref Patterns
616
+
617
+ ```tsx
618
+ // useRef for DOM access and mutable values
619
+ function VideoPlayer() {
620
+ const videoRef = useRef<HTMLVideoElement>(null);
621
+
622
+ function handlePlay() {
623
+ videoRef.current?.play();
624
+ }
625
+
626
+ return <video ref={videoRef} src="/movie.mp4" />;
627
+ }
628
+
629
+ // Callback refs for dynamic ref assignment
630
+ function MeasuredBox() {
631
+ const [height, setHeight] = useState(0);
632
+
633
+ const measuredRef = useCallback((node: HTMLDivElement | null) => {
634
+ if (node) {
635
+ setHeight(node.getBoundingClientRect().height);
636
+ }
637
+ }, []);
638
+
639
+ return <div ref={measuredRef}>Content with height: {height}</div>;
640
+ }
641
+
642
+ // Forwarding refs (for library components)
643
+ const TextInput = forwardRef<HTMLInputElement, InputProps>(
644
+ function TextInput(props, ref) {
645
+ return <input ref={ref} {...props} />;
646
+ }
647
+ );
648
+
649
+ // React 19: ref is a regular prop — forwardRef is being phased out
650
+ function TextInput19({ ref, ...props }: InputProps & { ref?: Ref<HTMLInputElement> }) {
651
+ return <input ref={ref} {...props} />;
652
+ }
653
+ ```
654
+
655
+ ---
656
+
657
+ ## TypeScript Patterns
658
+
659
+ ### Component Props
660
+
661
+ ```tsx
662
+ // Discriminated union props
663
+ type ButtonProps =
664
+ | { variant: "link"; href: string; onClick?: never }
665
+ | { variant: "button"; onClick: () => void; href?: never };
666
+
667
+ function Button(props: ButtonProps) {
668
+ if (props.variant === "link") {
669
+ return <a href={props.href}>Link</a>;
670
+ }
671
+ return <button onClick={props.onClick}>Button</button>;
672
+ }
673
+
674
+ // Polymorphic component (as prop)
675
+ type PolymorphicProps<E extends React.ElementType> = {
676
+ as?: E;
677
+ children: React.ReactNode;
678
+ } & Omit<React.ComponentPropsWithoutRef<E>, "as" | "children">;
679
+
680
+ function Text<E extends React.ElementType = "span">({
681
+ as,
682
+ children,
683
+ ...props
684
+ }: PolymorphicProps<E>) {
685
+ const Component = as || "span";
686
+ return <Component {...props}>{children}</Component>;
687
+ }
688
+
689
+ // Usage:
690
+ <Text as="h1" className="title">Heading</Text>
691
+ <Text as="p">Paragraph</Text>
692
+ <Text as="a" href="/about">Link</Text>
693
+ ```
694
+
695
+ ### Generic Components
696
+
697
+ ```tsx
698
+ // Generic list component
699
+ interface SelectProps<T> {
700
+ items: T[];
701
+ selected: T | null;
702
+ onSelect: (item: T) => void;
703
+ getLabel: (item: T) => string;
704
+ getKey: (item: T) => string;
705
+ }
706
+
707
+ function Select<T>({ items, selected, onSelect, getLabel, getKey }: SelectProps<T>) {
708
+ return (
709
+ <ul role="listbox">
710
+ {items.map((item) => (
711
+ <li
712
+ key={getKey(item)}
713
+ role="option"
714
+ aria-selected={item === selected}
715
+ onClick={() => onSelect(item)}
716
+ >
717
+ {getLabel(item)}
718
+ </li>
719
+ ))}
720
+ </ul>
721
+ );
722
+ }
723
+ ```
724
+
725
+ ---
726
+
727
+ ## Accessibility (Mandatory)
728
+
729
+ ```tsx
730
+ // Every interactive element MUST be accessible
731
+
732
+ // ✅ Keyboard navigation
733
+ <button onClick={handleClick} onKeyDown={(e) => {
734
+ if (e.key === "Enter" || e.key === " ") handleClick();
735
+ }}>
736
+ Action
737
+ </button>
738
+
739
+ // ✅ ARIA for custom components
740
+ <div
741
+ role="dialog"
742
+ aria-modal={true}
743
+ aria-labelledby="dialog-title"
744
+ aria-describedby="dialog-desc"
745
+ >
746
+ <h2 id="dialog-title">Confirm Delete</h2>
747
+ <p id="dialog-desc">This action cannot be undone.</p>
748
+ </div>
749
+
750
+ // ✅ Focus management
751
+ function Modal({ isOpen, onClose }: ModalProps) {
752
+ const closeRef = useRef<HTMLButtonElement>(null);
753
+
754
+ useEffect(() => {
755
+ if (isOpen) closeRef.current?.focus(); // focus trap
756
+ }, [isOpen]);
757
+
758
+ return isOpen ? (
759
+ <div role="dialog" aria-modal>
760
+ <button ref={closeRef} onClick={onClose}>Close</button>
761
+ </div>
762
+ ) : null;
763
+ }
764
+
765
+ // ✅ Screen reader text
766
+ <button aria-label="Close dialog">
767
+ <XIcon aria-hidden="true" />
768
+ </button>
769
+ ```
770
+
771
+ ---
772
+
773
+ ## Common Patterns
774
+
775
+ ### Debounced Search Input
776
+
777
+ ```tsx
778
+ function useDebounce<T>(value: T, delay: number): T {
779
+ const [debouncedValue, setDebouncedValue] = useState(value);
780
+
781
+ useEffect(() => {
782
+ const timer = setTimeout(() => setDebouncedValue(value), delay);
783
+ return () => clearTimeout(timer);
784
+ }, [value, delay]);
785
+
786
+ return debouncedValue;
787
+ }
788
+
789
+ function SearchInput() {
790
+ const [query, setQuery] = useState("");
791
+ const debouncedQuery = useDebounce(query, 300);
792
+
793
+ useEffect(() => {
794
+ if (debouncedQuery) {
795
+ searchAPI(debouncedQuery);
796
+ }
797
+ }, [debouncedQuery]);
798
+
799
+ return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
800
+ }
801
+ ```
802
+
803
+ ### Intersection Observer Hook
804
+
805
+ ```tsx
806
+ function useIntersectionObserver(
807
+ options?: IntersectionObserverInit
808
+ ): [React.RefCallback<Element>, boolean] {
809
+ const [isIntersecting, setIsIntersecting] = useState(false);
810
+
811
+ const ref = useCallback(
812
+ (node: Element | null) => {
813
+ if (!node) return;
814
+
815
+ const observer = new IntersectionObserver(([entry]) => {
816
+ setIsIntersecting(entry.isIntersecting);
817
+ }, options);
818
+
819
+ observer.observe(node);
820
+ return () => observer.disconnect();
821
+ },
822
+ [options]
823
+ );
824
+
825
+ return [ref, isIntersecting];
826
+ }
827
+
828
+ // Usage:
829
+ function LazyImage({ src }: { src: string }) {
830
+ const [ref, isVisible] = useIntersectionObserver({ threshold: 0.1 });
831
+ return <div ref={ref}>{isVisible && <img src={src} />}</div>;
832
+ }
833
+ ```
834
+
835
+ ### Previous Value Hook
836
+
837
+ ```tsx
838
+ function usePrevious<T>(value: T): T | undefined {
839
+ const ref = useRef<T>(undefined);
840
+
841
+ useEffect(() => {
842
+ ref.current = value;
843
+ }, [value]);
844
+
845
+ return ref.current;
846
+ }
847
+
848
+ // Usage: detect state changes
849
+ function Counter({ count }: { count: number }) {
850
+ const prevCount = usePrevious(count);
851
+ const direction = prevCount !== undefined && count > prevCount ? "↑" : "↓";
852
+
853
+ return <span>{direction} {count}</span>;
854
+ }
855
+ ```
856
+
857
+ ---
858
+
859
+ ## Output Format
860
+
861
+ When this skill produces or reviews code, structure your output as follows:
862
+
863
+ ```
864
+ ━━━ React Specialist Report ━━━━━━━━━━━━━━━━━━━━━━━━
865
+ Skill: React Specialist
866
+ React Ver: 19+
867
+ Scope: [N files · N components]
868
+ ─────────────────────────────────────────────────
869
+ ✅ Passed: [checks that passed, or "All clean"]
870
+ ⚠️ Warnings: [non-blocking issues, or "None"]
871
+ ❌ Blocked: [blocking issues requiring fix, or "None"]
872
+ ─────────────────────────────────────────────────
873
+ VBC status: PENDING → VERIFIED
874
+ Evidence: [test output / lint pass / compile success]
875
+ ```
876
+
877
+ **VBC (Verification-Before-Completion) is mandatory.**
878
+ Do not mark status as VERIFIED until concrete terminal evidence is provided.
879
+
880
+ ---
881
+
882
+ ## 🤖 LLM-Specific Traps
883
+
884
+ AI coding assistants often fall into specific bad habits when generating React code. These are strictly forbidden:
885
+
886
+ 1. **Class Components:** Never generate `class extends React.Component` or lifecycle methods (`componentDidMount`, `componentDidUpdate`) in React 19+ projects. Use functional components with hooks exclusively.
887
+ 2. **Manual Memoization in React 19:** Do NOT add `useMemo`, `useCallback`, or `React.memo` if the React Compiler is enabled. The compiler handles this automatically.
888
+ 3. **`useFormState` (Wrong Name):** The correct hook name is `useActionState`, not `useFormState`. The canary name was changed before stable release.
889
+ 4. **`<Context.Provider>`:** React 19 uses `<Context value={}>` directly. The `.Provider` pattern is deprecated.
890
+ 5. **`useEffect` for Data Fetching:** Use Server Components, React Query, SWR, or the `use()` hook. `useEffect` fetch patterns cause waterfalls, have no caching, and lack error/loading states.
891
+ 6. **Missing Keys in Mapped Lists:** Always use unique, stable IDs as keys. Never use array index as a key unless the list is truly static and never reorders.
892
+ 7. **Prop Drilling Past 3 Levels:** If passing props through more than 3 intermediate components, use Context, Zustand, or Jotai instead.
893
+ 8. **`cacheTime` in React Query v5:** The property was renamed to `gcTime`. Importing from `"react-query"` instead of `"@tanstack/react-query"` is also wrong.
894
+ 9. **Zustand Without Selectors:** `useStore()` without a selector subscribes to all state changes. Always use `useStore((state) => state.specificValue)`.
895
+ 10. **`forwardRef` in React 19:** Refs are regular props in React 19. `forwardRef` is being phased out. Use `ref` as a normal prop.
896
+
897
+ ---
898
+
899
+ ## 🏛️ Tribunal Integration (Anti-Hallucination)
900
+
901
+ **Slash command: `/tribunal-frontend`**
902
+ **Active reviewers: `logic` · `security` · `frontend` · `type-safety`**
903
+
904
+ ### ❌ Forbidden AI Tropes
905
+
906
+ 1. **Blind Assumptions:** Never make an assumption without documenting it clearly with `// VERIFY: [reason]`.
907
+ 2. **Silent Degradation:** Catching and suppressing errors without logging or displaying error boundaries.
908
+ 3. **Context Amnesia:** Forgetting the user's React version or framework constraints.
909
+ 4. **Sloppy Layout Generation:** Never build UI without explicit dimensional boundaries — use strict 4px grid spacing and explicit flex/grid layouts.
910
+
911
+ ### ✅ Pre-Flight Self-Audit
912
+
913
+ Review these questions before confirming output:
914
+ ```
915
+ ✅ Did I use strictly functional components with hooks?
916
+ ✅ Did I avoid manual memoization if React Compiler is active?
917
+ ✅ Did I use useActionState (not useFormState) for form actions?
918
+ ✅ Did I use <Context value={}> (not <Context.Provider>)?
919
+ ✅ Are array maps using unique, stable keys (not index)?
920
+ ✅ Did I handle loading, error, and empty states?
921
+ ✅ Did I use Suspense + Error Boundaries for async components?
922
+ ✅ Is the component accessible (ARIA, keyboard, focus mgmt)?
923
+ ✅ Did I include AbortController cleanup in useEffect fetches?
924
+ ✅ Did I use Zustand selectors to prevent unnecessary re-renders?
925
+ ```
926
+
927
+ ### 🛑 Verification-Before-Completion (VBC) Protocol
928
+
929
+ **CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
930
+ - ❌ **Forbidden:** Assuming a React component "works" just because it compiles or because the bundler gives no immediate warnings.
931
+ - ✅ **Required:** You are explicitly forbidden from completing your task without providing **concrete terminal/test evidence** (e.g., passing Jest/Vitest logs, successful build output, or specific CLI execution results) proving the build is error-free.