@wazir-dev/cli 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.
Files changed (629) hide show
  1. package/AGENTS.md +111 -0
  2. package/CHANGELOG.md +14 -0
  3. package/CONTRIBUTING.md +101 -0
  4. package/LICENSE +21 -0
  5. package/README.md +314 -0
  6. package/assets/composition-engine.mmd +34 -0
  7. package/assets/demo-script.sh +17 -0
  8. package/assets/logo-dark.svg +14 -0
  9. package/assets/logo.svg +14 -0
  10. package/assets/pipeline.mmd +39 -0
  11. package/assets/record-demo.sh +51 -0
  12. package/docs/README.md +51 -0
  13. package/docs/adapters/context-mode.md +60 -0
  14. package/docs/concepts/architecture.md +87 -0
  15. package/docs/concepts/artifact-model.md +60 -0
  16. package/docs/concepts/composition-engine.md +36 -0
  17. package/docs/concepts/indexing-and-recall.md +160 -0
  18. package/docs/concepts/observability.md +41 -0
  19. package/docs/concepts/roles-and-workflows.md +59 -0
  20. package/docs/concepts/terminology-policy.md +27 -0
  21. package/docs/getting-started/01-installation.md +78 -0
  22. package/docs/getting-started/02-first-run.md +102 -0
  23. package/docs/getting-started/03-adding-to-project.md +15 -0
  24. package/docs/getting-started/04-host-setup.md +15 -0
  25. package/docs/guides/ci-integration.md +15 -0
  26. package/docs/guides/creating-skills.md +15 -0
  27. package/docs/guides/expertise-module-authoring.md +15 -0
  28. package/docs/guides/hook-development.md +15 -0
  29. package/docs/guides/memory-and-learnings.md +34 -0
  30. package/docs/guides/multi-host-export.md +15 -0
  31. package/docs/guides/troubleshooting.md +101 -0
  32. package/docs/guides/writing-custom-roles.md +15 -0
  33. package/docs/plans/2026-03-15-cli-pipeline-integration-design.md +592 -0
  34. package/docs/plans/2026-03-15-cli-pipeline-integration-plan.md +598 -0
  35. package/docs/plans/2026-03-15-docs-enforcement-plan.md +238 -0
  36. package/docs/readmes/INDEX.md +99 -0
  37. package/docs/readmes/features/expertise/README.md +171 -0
  38. package/docs/readmes/features/exports/README.md +222 -0
  39. package/docs/readmes/features/hooks/README.md +103 -0
  40. package/docs/readmes/features/hooks/loop-cap-guard.md +133 -0
  41. package/docs/readmes/features/hooks/post-tool-capture.md +121 -0
  42. package/docs/readmes/features/hooks/post-tool-lint.md +130 -0
  43. package/docs/readmes/features/hooks/pre-compact-summary.md +122 -0
  44. package/docs/readmes/features/hooks/pre-tool-capture-route.md +100 -0
  45. package/docs/readmes/features/hooks/protected-path-write-guard.md +128 -0
  46. package/docs/readmes/features/hooks/session-start.md +119 -0
  47. package/docs/readmes/features/hooks/stop-handoff-harvest.md +125 -0
  48. package/docs/readmes/features/roles/README.md +157 -0
  49. package/docs/readmes/features/roles/clarifier.md +152 -0
  50. package/docs/readmes/features/roles/content-author.md +190 -0
  51. package/docs/readmes/features/roles/designer.md +193 -0
  52. package/docs/readmes/features/roles/executor.md +184 -0
  53. package/docs/readmes/features/roles/learner.md +210 -0
  54. package/docs/readmes/features/roles/planner.md +182 -0
  55. package/docs/readmes/features/roles/researcher.md +164 -0
  56. package/docs/readmes/features/roles/reviewer.md +184 -0
  57. package/docs/readmes/features/roles/specifier.md +162 -0
  58. package/docs/readmes/features/roles/verifier.md +215 -0
  59. package/docs/readmes/features/schemas/README.md +178 -0
  60. package/docs/readmes/features/skills/README.md +63 -0
  61. package/docs/readmes/features/skills/brainstorming.md +96 -0
  62. package/docs/readmes/features/skills/debugging.md +148 -0
  63. package/docs/readmes/features/skills/design.md +120 -0
  64. package/docs/readmes/features/skills/prepare-next.md +109 -0
  65. package/docs/readmes/features/skills/run-audit.md +159 -0
  66. package/docs/readmes/features/skills/scan-project.md +109 -0
  67. package/docs/readmes/features/skills/self-audit.md +176 -0
  68. package/docs/readmes/features/skills/tdd.md +137 -0
  69. package/docs/readmes/features/skills/using-skills.md +92 -0
  70. package/docs/readmes/features/skills/verification.md +120 -0
  71. package/docs/readmes/features/skills/writing-plans.md +104 -0
  72. package/docs/readmes/features/tooling/README.md +320 -0
  73. package/docs/readmes/features/workflows/README.md +186 -0
  74. package/docs/readmes/features/workflows/author.md +181 -0
  75. package/docs/readmes/features/workflows/clarify.md +154 -0
  76. package/docs/readmes/features/workflows/design-review.md +171 -0
  77. package/docs/readmes/features/workflows/design.md +169 -0
  78. package/docs/readmes/features/workflows/discover.md +162 -0
  79. package/docs/readmes/features/workflows/execute.md +173 -0
  80. package/docs/readmes/features/workflows/learn.md +167 -0
  81. package/docs/readmes/features/workflows/plan-review.md +165 -0
  82. package/docs/readmes/features/workflows/plan.md +170 -0
  83. package/docs/readmes/features/workflows/prepare-next.md +167 -0
  84. package/docs/readmes/features/workflows/review.md +169 -0
  85. package/docs/readmes/features/workflows/run-audit.md +191 -0
  86. package/docs/readmes/features/workflows/spec-challenge.md +159 -0
  87. package/docs/readmes/features/workflows/specify.md +160 -0
  88. package/docs/readmes/features/workflows/verify.md +177 -0
  89. package/docs/readmes/packages/README.md +50 -0
  90. package/docs/readmes/packages/ajv.md +117 -0
  91. package/docs/readmes/packages/context-mode.md +118 -0
  92. package/docs/readmes/packages/gray-matter.md +116 -0
  93. package/docs/readmes/packages/node-test.md +137 -0
  94. package/docs/readmes/packages/yaml.md +112 -0
  95. package/docs/reference/configuration-reference.md +159 -0
  96. package/docs/reference/expertise-index.md +52 -0
  97. package/docs/reference/git-flow.md +43 -0
  98. package/docs/reference/hooks.md +87 -0
  99. package/docs/reference/host-exports.md +50 -0
  100. package/docs/reference/launch-checklist.md +172 -0
  101. package/docs/reference/marketplace-listings.md +76 -0
  102. package/docs/reference/release-process.md +34 -0
  103. package/docs/reference/roles-reference.md +77 -0
  104. package/docs/reference/skills.md +33 -0
  105. package/docs/reference/templates.md +29 -0
  106. package/docs/reference/tooling-cli.md +94 -0
  107. package/docs/truth-claims.yaml +222 -0
  108. package/expertise/PROGRESS.md +63 -0
  109. package/expertise/README.md +18 -0
  110. package/expertise/antipatterns/PROGRESS.md +56 -0
  111. package/expertise/antipatterns/backend/api-design-antipatterns.md +1271 -0
  112. package/expertise/antipatterns/backend/auth-antipatterns.md +1195 -0
  113. package/expertise/antipatterns/backend/caching-antipatterns.md +622 -0
  114. package/expertise/antipatterns/backend/database-antipatterns.md +1038 -0
  115. package/expertise/antipatterns/backend/index.md +24 -0
  116. package/expertise/antipatterns/backend/microservices-antipatterns.md +850 -0
  117. package/expertise/antipatterns/code/architecture-antipatterns.md +919 -0
  118. package/expertise/antipatterns/code/async-antipatterns.md +622 -0
  119. package/expertise/antipatterns/code/code-smells.md +1186 -0
  120. package/expertise/antipatterns/code/dependency-antipatterns.md +1209 -0
  121. package/expertise/antipatterns/code/error-handling-antipatterns.md +1360 -0
  122. package/expertise/antipatterns/code/index.md +27 -0
  123. package/expertise/antipatterns/code/naming-and-abstraction.md +1118 -0
  124. package/expertise/antipatterns/code/state-management-antipatterns.md +1076 -0
  125. package/expertise/antipatterns/code/testing-antipatterns.md +1053 -0
  126. package/expertise/antipatterns/design/accessibility-antipatterns.md +1136 -0
  127. package/expertise/antipatterns/design/dark-patterns.md +1121 -0
  128. package/expertise/antipatterns/design/index.md +22 -0
  129. package/expertise/antipatterns/design/ui-antipatterns.md +1202 -0
  130. package/expertise/antipatterns/design/ux-antipatterns.md +680 -0
  131. package/expertise/antipatterns/frontend/css-layout-antipatterns.md +691 -0
  132. package/expertise/antipatterns/frontend/flutter-antipatterns.md +1827 -0
  133. package/expertise/antipatterns/frontend/index.md +23 -0
  134. package/expertise/antipatterns/frontend/mobile-antipatterns.md +573 -0
  135. package/expertise/antipatterns/frontend/react-antipatterns.md +1128 -0
  136. package/expertise/antipatterns/frontend/spa-antipatterns.md +1235 -0
  137. package/expertise/antipatterns/index.md +31 -0
  138. package/expertise/antipatterns/performance/index.md +20 -0
  139. package/expertise/antipatterns/performance/performance-antipatterns.md +1013 -0
  140. package/expertise/antipatterns/performance/premature-optimization.md +623 -0
  141. package/expertise/antipatterns/performance/scaling-antipatterns.md +785 -0
  142. package/expertise/antipatterns/process/ai-coding-antipatterns.md +853 -0
  143. package/expertise/antipatterns/process/code-review-antipatterns.md +656 -0
  144. package/expertise/antipatterns/process/deployment-antipatterns.md +920 -0
  145. package/expertise/antipatterns/process/index.md +23 -0
  146. package/expertise/antipatterns/process/technical-debt-antipatterns.md +647 -0
  147. package/expertise/antipatterns/security/index.md +20 -0
  148. package/expertise/antipatterns/security/secrets-antipatterns.md +849 -0
  149. package/expertise/antipatterns/security/security-theater.md +843 -0
  150. package/expertise/antipatterns/security/vulnerability-patterns.md +801 -0
  151. package/expertise/architecture/PROGRESS.md +70 -0
  152. package/expertise/architecture/data/caching-architecture.md +671 -0
  153. package/expertise/architecture/data/data-consistency.md +574 -0
  154. package/expertise/architecture/data/data-modeling.md +536 -0
  155. package/expertise/architecture/data/event-streams-and-queues.md +634 -0
  156. package/expertise/architecture/data/index.md +25 -0
  157. package/expertise/architecture/data/search-architecture.md +663 -0
  158. package/expertise/architecture/data/sql-vs-nosql.md +708 -0
  159. package/expertise/architecture/decisions/architecture-decision-records.md +640 -0
  160. package/expertise/architecture/decisions/build-vs-buy.md +616 -0
  161. package/expertise/architecture/decisions/index.md +23 -0
  162. package/expertise/architecture/decisions/monolith-to-microservices.md +790 -0
  163. package/expertise/architecture/decisions/technology-selection.md +616 -0
  164. package/expertise/architecture/distributed/cap-theorem-and-tradeoffs.md +800 -0
  165. package/expertise/architecture/distributed/circuit-breaker-bulkhead.md +741 -0
  166. package/expertise/architecture/distributed/consensus-and-coordination.md +796 -0
  167. package/expertise/architecture/distributed/distributed-systems-fundamentals.md +564 -0
  168. package/expertise/architecture/distributed/idempotency-and-retry.md +796 -0
  169. package/expertise/architecture/distributed/index.md +25 -0
  170. package/expertise/architecture/distributed/saga-pattern.md +797 -0
  171. package/expertise/architecture/foundations/architectural-thinking.md +460 -0
  172. package/expertise/architecture/foundations/coupling-and-cohesion.md +770 -0
  173. package/expertise/architecture/foundations/design-principles-solid.md +649 -0
  174. package/expertise/architecture/foundations/domain-driven-design.md +719 -0
  175. package/expertise/architecture/foundations/index.md +25 -0
  176. package/expertise/architecture/foundations/separation-of-concerns.md +472 -0
  177. package/expertise/architecture/foundations/twelve-factor-app.md +797 -0
  178. package/expertise/architecture/index.md +34 -0
  179. package/expertise/architecture/integration/api-design-graphql.md +638 -0
  180. package/expertise/architecture/integration/api-design-grpc.md +804 -0
  181. package/expertise/architecture/integration/api-design-rest.md +892 -0
  182. package/expertise/architecture/integration/index.md +25 -0
  183. package/expertise/architecture/integration/third-party-integration.md +795 -0
  184. package/expertise/architecture/integration/webhooks-and-callbacks.md +1152 -0
  185. package/expertise/architecture/integration/websockets-realtime.md +791 -0
  186. package/expertise/architecture/mobile-architecture/index.md +22 -0
  187. package/expertise/architecture/mobile-architecture/mobile-app-architecture.md +780 -0
  188. package/expertise/architecture/mobile-architecture/mobile-backend-for-frontend.md +670 -0
  189. package/expertise/architecture/mobile-architecture/offline-first.md +719 -0
  190. package/expertise/architecture/mobile-architecture/push-and-sync.md +782 -0
  191. package/expertise/architecture/patterns/cqrs-event-sourcing.md +717 -0
  192. package/expertise/architecture/patterns/event-driven.md +797 -0
  193. package/expertise/architecture/patterns/hexagonal-clean-architecture.md +870 -0
  194. package/expertise/architecture/patterns/index.md +27 -0
  195. package/expertise/architecture/patterns/layered-architecture.md +736 -0
  196. package/expertise/architecture/patterns/microservices.md +753 -0
  197. package/expertise/architecture/patterns/modular-monolith.md +692 -0
  198. package/expertise/architecture/patterns/monolith.md +626 -0
  199. package/expertise/architecture/patterns/plugin-architecture.md +735 -0
  200. package/expertise/architecture/patterns/serverless.md +780 -0
  201. package/expertise/architecture/scaling/database-scaling.md +615 -0
  202. package/expertise/architecture/scaling/feature-flags-and-rollouts.md +757 -0
  203. package/expertise/architecture/scaling/horizontal-vs-vertical.md +606 -0
  204. package/expertise/architecture/scaling/index.md +24 -0
  205. package/expertise/architecture/scaling/multi-tenancy.md +800 -0
  206. package/expertise/architecture/scaling/stateless-design.md +787 -0
  207. package/expertise/backend/embedded-firmware.md +625 -0
  208. package/expertise/backend/go.md +853 -0
  209. package/expertise/backend/index.md +24 -0
  210. package/expertise/backend/java-spring.md +448 -0
  211. package/expertise/backend/node-typescript.md +625 -0
  212. package/expertise/backend/python-fastapi.md +724 -0
  213. package/expertise/backend/rust.md +458 -0
  214. package/expertise/backend/solidity.md +711 -0
  215. package/expertise/composition-map.yaml +443 -0
  216. package/expertise/content/foundations/content-modeling.md +395 -0
  217. package/expertise/content/foundations/editorial-standards.md +449 -0
  218. package/expertise/content/foundations/index.md +24 -0
  219. package/expertise/content/foundations/microcopy.md +455 -0
  220. package/expertise/content/foundations/terminology-governance.md +509 -0
  221. package/expertise/content/index.md +34 -0
  222. package/expertise/content/patterns/accessibility-copy.md +518 -0
  223. package/expertise/content/patterns/index.md +24 -0
  224. package/expertise/content/patterns/notification-content.md +433 -0
  225. package/expertise/content/patterns/sample-content.md +486 -0
  226. package/expertise/content/patterns/state-copy.md +439 -0
  227. package/expertise/design/PROGRESS.md +58 -0
  228. package/expertise/design/disciplines/dark-mode-theming.md +577 -0
  229. package/expertise/design/disciplines/design-systems.md +595 -0
  230. package/expertise/design/disciplines/index.md +25 -0
  231. package/expertise/design/disciplines/information-architecture.md +800 -0
  232. package/expertise/design/disciplines/interaction-design.md +788 -0
  233. package/expertise/design/disciplines/responsive-design.md +552 -0
  234. package/expertise/design/disciplines/usability-testing.md +516 -0
  235. package/expertise/design/disciplines/user-research.md +792 -0
  236. package/expertise/design/foundations/accessibility-design.md +796 -0
  237. package/expertise/design/foundations/color-theory.md +797 -0
  238. package/expertise/design/foundations/iconography.md +795 -0
  239. package/expertise/design/foundations/index.md +26 -0
  240. package/expertise/design/foundations/motion-and-animation.md +653 -0
  241. package/expertise/design/foundations/rtl-design.md +585 -0
  242. package/expertise/design/foundations/spacing-and-layout.md +607 -0
  243. package/expertise/design/foundations/typography.md +800 -0
  244. package/expertise/design/foundations/visual-hierarchy.md +761 -0
  245. package/expertise/design/index.md +32 -0
  246. package/expertise/design/patterns/authentication-flows.md +474 -0
  247. package/expertise/design/patterns/content-consumption.md +789 -0
  248. package/expertise/design/patterns/data-display.md +618 -0
  249. package/expertise/design/patterns/e-commerce.md +1494 -0
  250. package/expertise/design/patterns/feedback-and-states.md +642 -0
  251. package/expertise/design/patterns/forms-and-input.md +819 -0
  252. package/expertise/design/patterns/gamification.md +801 -0
  253. package/expertise/design/patterns/index.md +31 -0
  254. package/expertise/design/patterns/microinteractions.md +449 -0
  255. package/expertise/design/patterns/navigation.md +800 -0
  256. package/expertise/design/patterns/notifications.md +705 -0
  257. package/expertise/design/patterns/onboarding.md +700 -0
  258. package/expertise/design/patterns/search-and-filter.md +601 -0
  259. package/expertise/design/patterns/settings-and-preferences.md +768 -0
  260. package/expertise/design/patterns/social-and-community.md +748 -0
  261. package/expertise/design/platforms/desktop-native.md +612 -0
  262. package/expertise/design/platforms/index.md +25 -0
  263. package/expertise/design/platforms/mobile-android.md +825 -0
  264. package/expertise/design/platforms/mobile-cross-platform.md +983 -0
  265. package/expertise/design/platforms/mobile-ios.md +699 -0
  266. package/expertise/design/platforms/tablet.md +794 -0
  267. package/expertise/design/platforms/web-dashboard.md +790 -0
  268. package/expertise/design/platforms/web-responsive.md +550 -0
  269. package/expertise/design/psychology/behavioral-nudges.md +449 -0
  270. package/expertise/design/psychology/cognitive-load.md +1191 -0
  271. package/expertise/design/psychology/error-psychology.md +778 -0
  272. package/expertise/design/psychology/index.md +22 -0
  273. package/expertise/design/psychology/persuasive-design.md +736 -0
  274. package/expertise/design/psychology/user-mental-models.md +623 -0
  275. package/expertise/design/tooling/open-pencil.md +266 -0
  276. package/expertise/frontend/angular.md +1073 -0
  277. package/expertise/frontend/desktop-electron.md +546 -0
  278. package/expertise/frontend/flutter.md +782 -0
  279. package/expertise/frontend/index.md +27 -0
  280. package/expertise/frontend/native-android.md +409 -0
  281. package/expertise/frontend/native-ios.md +490 -0
  282. package/expertise/frontend/react-native.md +1160 -0
  283. package/expertise/frontend/react.md +808 -0
  284. package/expertise/frontend/vue.md +1089 -0
  285. package/expertise/humanize/domain-rules-code.md +79 -0
  286. package/expertise/humanize/domain-rules-content.md +67 -0
  287. package/expertise/humanize/domain-rules-technical-docs.md +56 -0
  288. package/expertise/humanize/index.md +35 -0
  289. package/expertise/humanize/self-audit-checklist.md +87 -0
  290. package/expertise/humanize/sentence-patterns.md +218 -0
  291. package/expertise/humanize/vocabulary-blacklist.md +105 -0
  292. package/expertise/i18n/PROGRESS.md +65 -0
  293. package/expertise/i18n/advanced/accessibility-and-i18n.md +28 -0
  294. package/expertise/i18n/advanced/bidirectional-text-algorithm.md +38 -0
  295. package/expertise/i18n/advanced/complex-scripts.md +30 -0
  296. package/expertise/i18n/advanced/performance-and-i18n.md +27 -0
  297. package/expertise/i18n/advanced/testing-i18n.md +28 -0
  298. package/expertise/i18n/content/content-adaptation.md +23 -0
  299. package/expertise/i18n/content/locale-specific-formatting.md +23 -0
  300. package/expertise/i18n/content/machine-translation-integration.md +28 -0
  301. package/expertise/i18n/content/translation-management.md +29 -0
  302. package/expertise/i18n/foundations/date-time-calendars.md +67 -0
  303. package/expertise/i18n/foundations/i18n-architecture.md +272 -0
  304. package/expertise/i18n/foundations/locale-and-language-tags.md +79 -0
  305. package/expertise/i18n/foundations/numbers-currency-units.md +61 -0
  306. package/expertise/i18n/foundations/pluralization-and-gender.md +109 -0
  307. package/expertise/i18n/foundations/string-externalization.md +236 -0
  308. package/expertise/i18n/foundations/text-direction-bidi.md +241 -0
  309. package/expertise/i18n/foundations/unicode-and-encoding.md +86 -0
  310. package/expertise/i18n/index.md +38 -0
  311. package/expertise/i18n/platform/backend-i18n.md +31 -0
  312. package/expertise/i18n/platform/flutter-i18n.md +148 -0
  313. package/expertise/i18n/platform/native-android-i18n.md +36 -0
  314. package/expertise/i18n/platform/native-ios-i18n.md +36 -0
  315. package/expertise/i18n/platform/react-i18n.md +103 -0
  316. package/expertise/i18n/platform/web-css-i18n.md +81 -0
  317. package/expertise/i18n/rtl/arabic-specific.md +175 -0
  318. package/expertise/i18n/rtl/hebrew-specific.md +149 -0
  319. package/expertise/i18n/rtl/rtl-animations-and-transitions.md +111 -0
  320. package/expertise/i18n/rtl/rtl-forms-and-input.md +161 -0
  321. package/expertise/i18n/rtl/rtl-fundamentals.md +211 -0
  322. package/expertise/i18n/rtl/rtl-icons-and-images.md +181 -0
  323. package/expertise/i18n/rtl/rtl-layout-mirroring.md +252 -0
  324. package/expertise/i18n/rtl/rtl-navigation-and-gestures.md +107 -0
  325. package/expertise/i18n/rtl/rtl-testing-and-qa.md +147 -0
  326. package/expertise/i18n/rtl/rtl-typography.md +160 -0
  327. package/expertise/index.md +113 -0
  328. package/expertise/index.yaml +216 -0
  329. package/expertise/infrastructure/cloud-aws.md +597 -0
  330. package/expertise/infrastructure/cloud-gcp.md +599 -0
  331. package/expertise/infrastructure/cybersecurity.md +816 -0
  332. package/expertise/infrastructure/database-mongodb.md +447 -0
  333. package/expertise/infrastructure/database-postgres.md +400 -0
  334. package/expertise/infrastructure/devops-cicd.md +787 -0
  335. package/expertise/infrastructure/index.md +27 -0
  336. package/expertise/performance/PROGRESS.md +50 -0
  337. package/expertise/performance/backend/api-latency.md +1204 -0
  338. package/expertise/performance/backend/background-jobs.md +506 -0
  339. package/expertise/performance/backend/connection-pooling.md +1209 -0
  340. package/expertise/performance/backend/database-query-optimization.md +515 -0
  341. package/expertise/performance/backend/index.md +23 -0
  342. package/expertise/performance/backend/rate-limiting-and-throttling.md +971 -0
  343. package/expertise/performance/foundations/algorithmic-complexity.md +954 -0
  344. package/expertise/performance/foundations/caching-strategies.md +489 -0
  345. package/expertise/performance/foundations/concurrency-and-parallelism.md +847 -0
  346. package/expertise/performance/foundations/index.md +24 -0
  347. package/expertise/performance/foundations/measuring-and-profiling.md +440 -0
  348. package/expertise/performance/foundations/memory-management.md +964 -0
  349. package/expertise/performance/foundations/performance-budgets.md +1314 -0
  350. package/expertise/performance/index.md +31 -0
  351. package/expertise/performance/infrastructure/auto-scaling.md +1059 -0
  352. package/expertise/performance/infrastructure/cdn-and-edge.md +1081 -0
  353. package/expertise/performance/infrastructure/index.md +22 -0
  354. package/expertise/performance/infrastructure/load-balancing.md +1081 -0
  355. package/expertise/performance/infrastructure/observability.md +1079 -0
  356. package/expertise/performance/mobile/index.md +23 -0
  357. package/expertise/performance/mobile/mobile-animations.md +544 -0
  358. package/expertise/performance/mobile/mobile-memory-battery.md +416 -0
  359. package/expertise/performance/mobile/mobile-network.md +452 -0
  360. package/expertise/performance/mobile/mobile-rendering.md +599 -0
  361. package/expertise/performance/mobile/mobile-startup-time.md +505 -0
  362. package/expertise/performance/platform-specific/flutter-performance.md +647 -0
  363. package/expertise/performance/platform-specific/index.md +22 -0
  364. package/expertise/performance/platform-specific/node-performance.md +1307 -0
  365. package/expertise/performance/platform-specific/postgres-performance.md +1366 -0
  366. package/expertise/performance/platform-specific/react-performance.md +1403 -0
  367. package/expertise/performance/web/bundle-optimization.md +1239 -0
  368. package/expertise/performance/web/image-and-media.md +636 -0
  369. package/expertise/performance/web/index.md +24 -0
  370. package/expertise/performance/web/network-optimization.md +1133 -0
  371. package/expertise/performance/web/rendering-performance.md +1098 -0
  372. package/expertise/performance/web/ssr-and-hydration.md +918 -0
  373. package/expertise/performance/web/web-vitals.md +1374 -0
  374. package/expertise/quality/accessibility.md +985 -0
  375. package/expertise/quality/evidence-based-verification.md +499 -0
  376. package/expertise/quality/index.md +24 -0
  377. package/expertise/quality/ml-model-audit.md +614 -0
  378. package/expertise/quality/performance.md +600 -0
  379. package/expertise/quality/testing-api.md +891 -0
  380. package/expertise/quality/testing-mobile.md +496 -0
  381. package/expertise/quality/testing-web.md +849 -0
  382. package/expertise/security/PROGRESS.md +54 -0
  383. package/expertise/security/agentic-identity.md +540 -0
  384. package/expertise/security/compliance-frameworks.md +601 -0
  385. package/expertise/security/data/data-encryption.md +364 -0
  386. package/expertise/security/data/data-privacy-gdpr.md +692 -0
  387. package/expertise/security/data/database-security.md +1171 -0
  388. package/expertise/security/data/index.md +22 -0
  389. package/expertise/security/data/pii-handling.md +531 -0
  390. package/expertise/security/foundations/authentication.md +1041 -0
  391. package/expertise/security/foundations/authorization.md +603 -0
  392. package/expertise/security/foundations/cryptography.md +1001 -0
  393. package/expertise/security/foundations/index.md +25 -0
  394. package/expertise/security/foundations/owasp-top-10.md +1354 -0
  395. package/expertise/security/foundations/secrets-management.md +1217 -0
  396. package/expertise/security/foundations/secure-sdlc.md +700 -0
  397. package/expertise/security/foundations/supply-chain-security.md +698 -0
  398. package/expertise/security/index.md +31 -0
  399. package/expertise/security/infrastructure/cloud-security-aws.md +1296 -0
  400. package/expertise/security/infrastructure/cloud-security-gcp.md +1376 -0
  401. package/expertise/security/infrastructure/container-security.md +721 -0
  402. package/expertise/security/infrastructure/incident-response.md +1295 -0
  403. package/expertise/security/infrastructure/index.md +24 -0
  404. package/expertise/security/infrastructure/logging-and-monitoring.md +1618 -0
  405. package/expertise/security/infrastructure/network-security.md +1337 -0
  406. package/expertise/security/mobile/index.md +23 -0
  407. package/expertise/security/mobile/mobile-android-security.md +1218 -0
  408. package/expertise/security/mobile/mobile-binary-protection.md +1229 -0
  409. package/expertise/security/mobile/mobile-data-storage.md +1265 -0
  410. package/expertise/security/mobile/mobile-ios-security.md +1401 -0
  411. package/expertise/security/mobile/mobile-network-security.md +1520 -0
  412. package/expertise/security/smart-contract-security.md +594 -0
  413. package/expertise/security/testing/index.md +22 -0
  414. package/expertise/security/testing/penetration-testing.md +1258 -0
  415. package/expertise/security/testing/security-code-review.md +1765 -0
  416. package/expertise/security/testing/threat-modeling.md +1074 -0
  417. package/expertise/security/testing/vulnerability-scanning.md +1062 -0
  418. package/expertise/security/web/api-security.md +586 -0
  419. package/expertise/security/web/cors-and-headers.md +433 -0
  420. package/expertise/security/web/csrf.md +562 -0
  421. package/expertise/security/web/file-upload.md +1477 -0
  422. package/expertise/security/web/index.md +25 -0
  423. package/expertise/security/web/injection.md +1375 -0
  424. package/expertise/security/web/session-management.md +1101 -0
  425. package/expertise/security/web/xss.md +1158 -0
  426. package/exports/README.md +17 -0
  427. package/exports/hosts/claude/.claude/agents/clarifier.md +42 -0
  428. package/exports/hosts/claude/.claude/agents/content-author.md +63 -0
  429. package/exports/hosts/claude/.claude/agents/designer.md +55 -0
  430. package/exports/hosts/claude/.claude/agents/executor.md +55 -0
  431. package/exports/hosts/claude/.claude/agents/learner.md +51 -0
  432. package/exports/hosts/claude/.claude/agents/planner.md +53 -0
  433. package/exports/hosts/claude/.claude/agents/researcher.md +43 -0
  434. package/exports/hosts/claude/.claude/agents/reviewer.md +54 -0
  435. package/exports/hosts/claude/.claude/agents/specifier.md +47 -0
  436. package/exports/hosts/claude/.claude/agents/verifier.md +71 -0
  437. package/exports/hosts/claude/.claude/commands/author.md +42 -0
  438. package/exports/hosts/claude/.claude/commands/clarify.md +38 -0
  439. package/exports/hosts/claude/.claude/commands/design-review.md +46 -0
  440. package/exports/hosts/claude/.claude/commands/design.md +44 -0
  441. package/exports/hosts/claude/.claude/commands/discover.md +37 -0
  442. package/exports/hosts/claude/.claude/commands/execute.md +48 -0
  443. package/exports/hosts/claude/.claude/commands/learn.md +38 -0
  444. package/exports/hosts/claude/.claude/commands/plan-review.md +42 -0
  445. package/exports/hosts/claude/.claude/commands/plan.md +39 -0
  446. package/exports/hosts/claude/.claude/commands/prepare-next.md +37 -0
  447. package/exports/hosts/claude/.claude/commands/review.md +40 -0
  448. package/exports/hosts/claude/.claude/commands/run-audit.md +41 -0
  449. package/exports/hosts/claude/.claude/commands/spec-challenge.md +41 -0
  450. package/exports/hosts/claude/.claude/commands/specify.md +38 -0
  451. package/exports/hosts/claude/.claude/commands/verify.md +37 -0
  452. package/exports/hosts/claude/.claude/settings.json +34 -0
  453. package/exports/hosts/claude/CLAUDE.md +19 -0
  454. package/exports/hosts/claude/export.manifest.json +38 -0
  455. package/exports/hosts/claude/host-package.json +67 -0
  456. package/exports/hosts/codex/AGENTS.md +19 -0
  457. package/exports/hosts/codex/export.manifest.json +38 -0
  458. package/exports/hosts/codex/host-package.json +41 -0
  459. package/exports/hosts/cursor/.cursor/hooks.json +16 -0
  460. package/exports/hosts/cursor/.cursor/rules/wazir-core.mdc +19 -0
  461. package/exports/hosts/cursor/export.manifest.json +38 -0
  462. package/exports/hosts/cursor/host-package.json +42 -0
  463. package/exports/hosts/gemini/GEMINI.md +19 -0
  464. package/exports/hosts/gemini/export.manifest.json +38 -0
  465. package/exports/hosts/gemini/host-package.json +41 -0
  466. package/hooks/README.md +18 -0
  467. package/hooks/definitions/loop_cap_guard.yaml +21 -0
  468. package/hooks/definitions/post_tool_capture.yaml +24 -0
  469. package/hooks/definitions/pre_compact_summary.yaml +19 -0
  470. package/hooks/definitions/pre_tool_capture_route.yaml +19 -0
  471. package/hooks/definitions/protected_path_write_guard.yaml +19 -0
  472. package/hooks/definitions/session_start.yaml +19 -0
  473. package/hooks/definitions/stop_handoff_harvest.yaml +20 -0
  474. package/hooks/loop-cap-guard +17 -0
  475. package/hooks/post-tool-lint +36 -0
  476. package/hooks/protected-path-write-guard +17 -0
  477. package/hooks/session-start +41 -0
  478. package/llms-full.txt +2355 -0
  479. package/llms.txt +43 -0
  480. package/package.json +79 -0
  481. package/roles/README.md +20 -0
  482. package/roles/clarifier.md +42 -0
  483. package/roles/content-author.md +63 -0
  484. package/roles/designer.md +55 -0
  485. package/roles/executor.md +55 -0
  486. package/roles/learner.md +51 -0
  487. package/roles/planner.md +53 -0
  488. package/roles/researcher.md +43 -0
  489. package/roles/reviewer.md +54 -0
  490. package/roles/specifier.md +47 -0
  491. package/roles/verifier.md +71 -0
  492. package/schemas/README.md +24 -0
  493. package/schemas/accepted-learning.schema.json +20 -0
  494. package/schemas/author-artifact.schema.json +156 -0
  495. package/schemas/clarification.schema.json +19 -0
  496. package/schemas/design-artifact.schema.json +80 -0
  497. package/schemas/docs-claim.schema.json +18 -0
  498. package/schemas/export-manifest.schema.json +20 -0
  499. package/schemas/hook.schema.json +67 -0
  500. package/schemas/host-export-package.schema.json +18 -0
  501. package/schemas/implementation-plan.schema.json +19 -0
  502. package/schemas/proposed-learning.schema.json +19 -0
  503. package/schemas/research.schema.json +18 -0
  504. package/schemas/review.schema.json +29 -0
  505. package/schemas/run-manifest.schema.json +18 -0
  506. package/schemas/spec-challenge.schema.json +18 -0
  507. package/schemas/spec.schema.json +20 -0
  508. package/schemas/usage.schema.json +102 -0
  509. package/schemas/verification-proof.schema.json +29 -0
  510. package/schemas/wazir-manifest.schema.json +173 -0
  511. package/skills/README.md +40 -0
  512. package/skills/brainstorming/SKILL.md +77 -0
  513. package/skills/debugging/SKILL.md +50 -0
  514. package/skills/design/SKILL.md +61 -0
  515. package/skills/dispatching-parallel-agents/SKILL.md +128 -0
  516. package/skills/executing-plans/SKILL.md +70 -0
  517. package/skills/finishing-a-development-branch/SKILL.md +169 -0
  518. package/skills/humanize/SKILL.md +123 -0
  519. package/skills/init-pipeline/SKILL.md +124 -0
  520. package/skills/prepare-next/SKILL.md +20 -0
  521. package/skills/receiving-code-review/SKILL.md +123 -0
  522. package/skills/requesting-code-review/SKILL.md +105 -0
  523. package/skills/requesting-code-review/code-reviewer.md +108 -0
  524. package/skills/run-audit/SKILL.md +197 -0
  525. package/skills/scan-project/SKILL.md +41 -0
  526. package/skills/self-audit/SKILL.md +153 -0
  527. package/skills/subagent-driven-development/SKILL.md +154 -0
  528. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +26 -0
  529. package/skills/subagent-driven-development/implementer-prompt.md +102 -0
  530. package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
  531. package/skills/tdd/SKILL.md +23 -0
  532. package/skills/using-git-worktrees/SKILL.md +163 -0
  533. package/skills/using-skills/SKILL.md +95 -0
  534. package/skills/verification/SKILL.md +22 -0
  535. package/skills/wazir/SKILL.md +463 -0
  536. package/skills/writing-plans/SKILL.md +30 -0
  537. package/skills/writing-skills/SKILL.md +157 -0
  538. package/skills/writing-skills/anthropic-best-practices.md +122 -0
  539. package/skills/writing-skills/persuasion-principles.md +50 -0
  540. package/templates/README.md +20 -0
  541. package/templates/artifacts/README.md +10 -0
  542. package/templates/artifacts/accepted-learning.md +19 -0
  543. package/templates/artifacts/accepted-learning.template.json +12 -0
  544. package/templates/artifacts/author.md +74 -0
  545. package/templates/artifacts/author.template.json +19 -0
  546. package/templates/artifacts/clarification.md +21 -0
  547. package/templates/artifacts/clarification.template.json +12 -0
  548. package/templates/artifacts/execute-notes.md +19 -0
  549. package/templates/artifacts/implementation-plan.md +21 -0
  550. package/templates/artifacts/implementation-plan.template.json +11 -0
  551. package/templates/artifacts/learning-proposal.md +19 -0
  552. package/templates/artifacts/next-run-handoff.md +21 -0
  553. package/templates/artifacts/plan-review.md +19 -0
  554. package/templates/artifacts/proposed-learning.template.json +12 -0
  555. package/templates/artifacts/research.md +21 -0
  556. package/templates/artifacts/research.template.json +12 -0
  557. package/templates/artifacts/review-findings.md +19 -0
  558. package/templates/artifacts/review.template.json +11 -0
  559. package/templates/artifacts/run-manifest.template.json +8 -0
  560. package/templates/artifacts/spec-challenge.md +19 -0
  561. package/templates/artifacts/spec-challenge.template.json +11 -0
  562. package/templates/artifacts/spec.md +21 -0
  563. package/templates/artifacts/spec.template.json +12 -0
  564. package/templates/artifacts/verification-proof.md +19 -0
  565. package/templates/artifacts/verification-proof.template.json +11 -0
  566. package/templates/examples/accepted-learning.example.json +14 -0
  567. package/templates/examples/author.example.json +152 -0
  568. package/templates/examples/clarification.example.json +15 -0
  569. package/templates/examples/docs-claim.example.json +8 -0
  570. package/templates/examples/export-manifest.example.json +7 -0
  571. package/templates/examples/host-export-package.example.json +11 -0
  572. package/templates/examples/implementation-plan.example.json +17 -0
  573. package/templates/examples/proposed-learning.example.json +13 -0
  574. package/templates/examples/research.example.json +15 -0
  575. package/templates/examples/research.example.md +6 -0
  576. package/templates/examples/review.example.json +17 -0
  577. package/templates/examples/run-manifest.example.json +9 -0
  578. package/templates/examples/spec-challenge.example.json +14 -0
  579. package/templates/examples/spec.example.json +21 -0
  580. package/templates/examples/verification-proof.example.json +21 -0
  581. package/templates/examples/wazir-manifest.example.yaml +65 -0
  582. package/templates/task-definition-schema.md +99 -0
  583. package/tooling/README.md +20 -0
  584. package/tooling/src/adapters/context-mode.js +50 -0
  585. package/tooling/src/capture/command.js +376 -0
  586. package/tooling/src/capture/store.js +99 -0
  587. package/tooling/src/capture/usage.js +270 -0
  588. package/tooling/src/checks/branches.js +50 -0
  589. package/tooling/src/checks/brand-truth.js +110 -0
  590. package/tooling/src/checks/changelog.js +231 -0
  591. package/tooling/src/checks/command-registry.js +36 -0
  592. package/tooling/src/checks/commits.js +102 -0
  593. package/tooling/src/checks/docs-drift.js +103 -0
  594. package/tooling/src/checks/docs-truth.js +201 -0
  595. package/tooling/src/checks/runtime-surface.js +156 -0
  596. package/tooling/src/cli.js +116 -0
  597. package/tooling/src/command-options.js +56 -0
  598. package/tooling/src/commands/validate.js +320 -0
  599. package/tooling/src/doctor/command.js +91 -0
  600. package/tooling/src/export/command.js +77 -0
  601. package/tooling/src/export/compiler.js +498 -0
  602. package/tooling/src/guards/loop-cap-guard.js +52 -0
  603. package/tooling/src/guards/protected-path-write-guard.js +67 -0
  604. package/tooling/src/index/command.js +152 -0
  605. package/tooling/src/index/storage.js +1061 -0
  606. package/tooling/src/index/summarizers.js +261 -0
  607. package/tooling/src/loaders.js +18 -0
  608. package/tooling/src/project-root.js +22 -0
  609. package/tooling/src/recall/command.js +225 -0
  610. package/tooling/src/schema-validator.js +30 -0
  611. package/tooling/src/state-root.js +40 -0
  612. package/tooling/src/status/command.js +71 -0
  613. package/wazir.manifest.yaml +135 -0
  614. package/workflows/README.md +19 -0
  615. package/workflows/author.md +42 -0
  616. package/workflows/clarify.md +38 -0
  617. package/workflows/design-review.md +46 -0
  618. package/workflows/design.md +44 -0
  619. package/workflows/discover.md +37 -0
  620. package/workflows/execute.md +48 -0
  621. package/workflows/learn.md +38 -0
  622. package/workflows/plan-review.md +42 -0
  623. package/workflows/plan.md +39 -0
  624. package/workflows/prepare-next.md +37 -0
  625. package/workflows/review.md +40 -0
  626. package/workflows/run-audit.md +41 -0
  627. package/workflows/spec-challenge.md +41 -0
  628. package/workflows/specify.md +38 -0
  629. package/workflows/verify.md +37 -0
@@ -0,0 +1,1128 @@
1
+ # React Anti-Patterns
2
+ > **Domain:** Frontend
3
+ > **Anti-patterns covered:** 20
4
+ > **Highest severity:** High
5
+
6
+ React's component model and hooks API are expressive but present a wide surface area for misuse. Many of these patterns feel correct in isolation — they compile, they run, they even pass shallow tests — yet they silently degrade performance, correctness, or maintainability. This module catalogs the 20 most consequential React anti-patterns observed in production codebases, sourced from real-world audits, community post-mortems, and the official React documentation's own "you might not need an effect" guidance.
7
+
8
+ Each entry is classified by how often it appears, how badly it hurts, and how hard it is to catch without tooling.
9
+
10
+ ---
11
+
12
+ ## Anti-Pattern Entries
13
+
14
+ ---
15
+
16
+ ### AP-01: Prop Drilling Through Many Layers
17
+
18
+ **Also known as:** Threading props, Christmas-tree props, prop tunneling
19
+ **Frequency:** Very Common
20
+ **Severity:** Medium
21
+ **Detection difficulty:** Easy
22
+
23
+ **What it looks like:**
24
+ ```jsx
25
+ // App passes `user` through 4 layers that don't use it
26
+ function App() {
27
+ const user = useCurrentUser();
28
+ return <Layout user={user} />;
29
+ }
30
+ function Layout({ user }) {
31
+ return <Sidebar user={user} />;
32
+ }
33
+ function Sidebar({ user }) {
34
+ return <NavMenu user={user} />;
35
+ }
36
+ function NavMenu({ user }) {
37
+ return <Avatar name={user.name} />; // Only this component needs it
38
+ }
39
+ ```
40
+
41
+ **Why developers do it:**
42
+ It works, and when a codebase starts small it is the most obvious path. Developers reach for it by default because it requires no new abstractions.
43
+
44
+ **What goes wrong:**
45
+ - Every intermediate component takes on a prop it does not use, coupling unrelated layers
46
+ - Refactoring the prop type (e.g., renaming `user.name` to `user.displayName`) requires touching every intermediate component
47
+ - Adding a second consumer at a different level requires reopening multiple files
48
+ - Tests for intermediate components must supply the prop even though it is irrelevant to their behaviour
49
+
50
+ **The fix:**
51
+ ```jsx
52
+ // Before: 4-layer thread
53
+ // After: Context at the appropriate boundary
54
+
55
+ const UserContext = React.createContext(null);
56
+
57
+ function App() {
58
+ const user = useCurrentUser();
59
+ return (
60
+ <UserContext.Provider value={user}>
61
+ <Layout />
62
+ </UserContext.Provider>
63
+ );
64
+ }
65
+
66
+ function Avatar() {
67
+ const user = useContext(UserContext);
68
+ return <img src={user.avatarUrl} alt={user.name} />;
69
+ }
70
+ ```
71
+ Alternatively, use component composition (slot pattern) to pass `<Avatar />` directly without threading props.
72
+
73
+ **Detection rule:**
74
+ Flag any prop that appears in a component's props signature but is never read by that component's JSX or logic — only forwarded to a child.
75
+
76
+ ---
77
+
78
+ ### AP-02: Using useEffect for Derived State
79
+
80
+ **Also known as:** Effect-driven derivation, useState + useEffect sync pattern
81
+ **Frequency:** Very Common
82
+ **Severity:** High
83
+ **Detection difficulty:** Moderate
84
+
85
+ **What it looks like:**
86
+ ```jsx
87
+ function ProductList({ products, filter }) {
88
+ const [filtered, setFiltered] = useState([]);
89
+
90
+ useEffect(() => {
91
+ setFiltered(products.filter(p => p.category === filter));
92
+ }, [products, filter]);
93
+
94
+ return <ul>{filtered.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
95
+ }
96
+ ```
97
+
98
+ **Why developers do it:**
99
+ Developers treat `useEffect` as "run code when things change", which sounds like the right tool for deriving a new value from props.
100
+
101
+ **What goes wrong:**
102
+ - Causes a guaranteed double render: first render uses stale `filtered`, effect fires, second render uses fresh value
103
+ - Introduces a state variable that exists solely to hold a value calculable inline
104
+ - Can trigger cascading effect chains when the derived state is itself a dependency elsewhere
105
+ - React's documentation explicitly names this as one of the most common misuses of `useEffect`
106
+
107
+ **The fix:**
108
+ ```jsx
109
+ // Before: effect + state
110
+ const [filtered, setFiltered] = useState([]);
111
+ useEffect(() => {
112
+ setFiltered(products.filter(p => p.category === filter));
113
+ }, [products, filter]);
114
+
115
+ // After: plain derivation during render
116
+ const filtered = products.filter(p => p.category === filter);
117
+ // Wrap in useMemo only if the computation is measurably expensive
118
+ const filtered = useMemo(
119
+ () => products.filter(p => p.category === filter),
120
+ [products, filter]
121
+ );
122
+ ```
123
+
124
+ **Detection rule:**
125
+ Flag any `useEffect` whose sole body is a `setState` call where the new value is a pure transformation of the effect's dependencies.
126
+
127
+ ---
128
+
129
+ ### AP-03: Index as List Key
130
+
131
+ **Also known as:** Array index key, positional key
132
+ **Frequency:** Very Common
133
+ **Severity:** High
134
+ **Detection difficulty:** Easy
135
+
136
+ **What it looks like:**
137
+ ```jsx
138
+ function TodoList({ todos }) {
139
+ return (
140
+ <ul>
141
+ {todos.map((todo, index) => (
142
+ <TodoItem key={index} todo={todo} /> // index as key
143
+ ))}
144
+ </ul>
145
+ );
146
+ }
147
+ ```
148
+
149
+ **Why developers do it:**
150
+ `index` is always available when mapping, so it is the path of least resistance. ESLint's `react/jsx-key` rule only checks that a key exists — not that it is stable.
151
+
152
+ **What goes wrong:**
153
+ - When items are reordered, added to the middle, or removed, React reconciles by position rather than identity, causing wrong components to be updated, wrong animations to fire, and uncontrolled inputs to show stale values
154
+ - Component state (form inputs, scroll position, focus) migrates to the wrong item silently
155
+ - Particularly destructive in drag-and-drop lists and paginated tables
156
+
157
+ **The fix:**
158
+ ```jsx
159
+ // Before: index key
160
+ todos.map((todo, index) => <TodoItem key={index} todo={todo} />)
161
+
162
+ // After: stable unique key
163
+ todos.map(todo => <TodoItem key={todo.id} todo={todo} />)
164
+
165
+ // If items have no ID, derive a stable key from a unique field combination
166
+ todos.map(todo => <TodoItem key={`${todo.userId}-${todo.createdAt}`} todo={todo} />)
167
+ ```
168
+
169
+ **Detection rule:**
170
+ Flag any `key={index}` or `key={i}` where the variable name matches the second argument of a `.map()` callback.
171
+
172
+ ---
173
+
174
+ ### AP-04: Mutating State Directly
175
+
176
+ **Also known as:** Direct state mutation, in-place array/object mutation
177
+ **Frequency:** Very Common
178
+ **Severity:** High
179
+ **Detection difficulty:** Moderate
180
+
181
+ **What it looks like:**
182
+ ```jsx
183
+ function Cart() {
184
+ const [items, setItems] = useState([]);
185
+
186
+ function addItem(item) {
187
+ items.push(item); // mutation
188
+ setItems(items); // same reference — React bails out
189
+ }
190
+
191
+ function updateQty(id, qty) {
192
+ const item = items.find(i => i.id === id);
193
+ item.qty = qty; // nested mutation
194
+ setItems([...items]); // spread creates new array but objects are still mutated
195
+ }
196
+ }
197
+ ```
198
+
199
+ **Why developers do it:**
200
+ JavaScript arrays and objects are mutable by default. Developers coming from non-React backgrounds (or from class components with `this.state`) expect mutation to be the normal model.
201
+
202
+ **What goes wrong:**
203
+ - `setItems(items)` after mutation passes the same reference; React's `Object.is` check short-circuits and skips the re-render
204
+ - Mutated objects break `React.memo`, `useMemo`, and `useCallback` because their dependencies appear unchanged
205
+ - Mutations bypass Redux DevTools time-travel and React DevTools state snapshots
206
+ - Concurrently rendered trees can read inconsistent intermediate states
207
+
208
+ **The fix:**
209
+ ```jsx
210
+ // Before: mutation
211
+ items.push(item);
212
+ setItems(items);
213
+
214
+ // After: new reference
215
+ setItems(prev => [...prev, item]);
216
+
217
+ // Before: nested mutation
218
+ item.qty = qty;
219
+ setItems([...items]);
220
+
221
+ // After: immutable update
222
+ setItems(prev =>
223
+ prev.map(i => i.id === id ? { ...i, qty } : i)
224
+ );
225
+ ```
226
+
227
+ **Detection rule:**
228
+ Flag calls to `.push()`, `.pop()`, `.splice()`, `.sort()`, `.reverse()`, or direct property assignment (`obj.key = value`) on variables that are the first argument of a `useState` destructure or `useReducer` state binding.
229
+
230
+ ---
231
+
232
+ ### AP-05: Creating Components Inside Render
233
+
234
+ **Also known as:** Inline component definition, component factory inside JSX, nested component declaration
235
+ **Frequency:** Common
236
+ **Severity:** High
237
+ **Detection difficulty:** Easy
238
+
239
+ **What it looks like:**
240
+ ```jsx
241
+ function ParentList({ items }) {
242
+ // New function reference every render
243
+ const Item = ({ text }) => <li className="item">{text}</li>;
244
+
245
+ return (
246
+ <ul>
247
+ {items.map(item => <Item key={item.id} text={item.label} />)}
248
+ </ul>
249
+ );
250
+ }
251
+ ```
252
+
253
+ **Why developers do it:**
254
+ It keeps related code co-located and avoids creating a separate named component for something that feels "small". It also gives the inner component easy access to the parent's scope.
255
+
256
+ **What goes wrong:**
257
+ - Every render of `ParentList` creates a new `Item` function reference
258
+ - React sees a new component type at the same tree position and unmounts + remounts every `<Item />` — destroying DOM nodes, focus state, and any component-local state
259
+ - Negates any memoisation on the inner component entirely
260
+ - Creates invisible performance cliffs that only appear under load
261
+
262
+ **The fix:**
263
+ ```jsx
264
+ // Before: defined inside render
265
+ function ParentList({ items }) {
266
+ const Item = ({ text }) => <li>{text}</li>;
267
+ return <ul>{items.map(item => <Item key={item.id} text={item.label} />)}</ul>;
268
+ }
269
+
270
+ // After: defined at module scope (or in its own file)
271
+ function Item({ text }) {
272
+ return <li className="item">{text}</li>;
273
+ }
274
+
275
+ function ParentList({ items }) {
276
+ return <ul>{items.map(item => <Item key={item.id} text={item.label} />)}</ul>;
277
+ }
278
+ ```
279
+
280
+ **Detection rule:**
281
+ Flag any function or arrow-function declaration that (a) returns JSX, (b) begins with an uppercase letter, and (c) is declared inside the body of another React component function.
282
+
283
+ ---
284
+
285
+ ### AP-06: useEffect as onChange Handler
286
+
287
+ **Also known as:** Reactive effect for synchronous events, watching state with effects
288
+ **Frequency:** Very Common
289
+ **Severity:** Medium
290
+ **Detection difficulty:** Moderate
291
+
292
+ **What it looks like:**
293
+ ```jsx
294
+ function SearchBox() {
295
+ const [query, setQuery] = useState('');
296
+ const [results, setResults] = useState([]);
297
+
298
+ // Treating useEffect like an onChange watcher
299
+ useEffect(() => {
300
+ if (query) {
301
+ const filtered = allItems.filter(i => i.name.includes(query));
302
+ setResults(filtered);
303
+ }
304
+ }, [query]);
305
+
306
+ return <input value={query} onChange={e => setQuery(e.target.value)} />;
307
+ }
308
+ ```
309
+
310
+ **Why developers do it:**
311
+ The mental model of "do X whenever Y changes" maps naturally to `useEffect`. It mimics Vue's watchers and MobX reactions.
312
+
313
+ **What goes wrong:**
314
+ - The state update in the effect schedules a second render; synchronous derived logic can run inline
315
+ - Creates temporal coupling: the user sees the old `results` for one render cycle before the effect fires
316
+ - Harder to trace the data flow — `results` appears to update magically rather than at the call site
317
+ - Opens the door for accidental infinite loops when the derived state is also a dependency
318
+
319
+ **The fix:**
320
+ ```jsx
321
+ // Before: effect watcher
322
+ useEffect(() => {
323
+ setResults(allItems.filter(i => i.name.includes(query)));
324
+ }, [query]);
325
+
326
+ // After: inline derivation (synchronous, zero extra renders)
327
+ const results = query
328
+ ? allItems.filter(i => i.name.includes(query))
329
+ : [];
330
+ // Move setQuery+derivation into the event handler if side effects are also needed
331
+ function handleChange(e) {
332
+ const q = e.target.value;
333
+ setQuery(q);
334
+ // fire async fetch here if needed, not in an effect watching query
335
+ }
336
+ ```
337
+
338
+ **Detection rule:**
339
+ Flag any `useEffect` that watches a single state variable and whose only body is a `setState` call producing a derived value from that variable.
340
+
341
+ ---
342
+
343
+ ### AP-07: Not Cleaning Up Effects
344
+
345
+ **Also known as:** Leaking effects, missing cleanup, unmounted component state updates
346
+ **Frequency:** Common
347
+ **Severity:** High
348
+ **Detection difficulty:** Moderate
349
+
350
+ **What it looks like:**
351
+ ```jsx
352
+ function UserProfile({ userId }) {
353
+ const [user, setUser] = useState(null);
354
+
355
+ useEffect(() => {
356
+ fetch(`/api/users/${userId}`)
357
+ .then(r => r.json())
358
+ .then(data => setUser(data)); // setState after potential unmount
359
+ }, [userId]);
360
+ }
361
+ ```
362
+
363
+ **Why developers do it:**
364
+ The happy path works. Most developers learn the two-argument form of `useEffect` but are not taught that the callback's return value is a cleanup function.
365
+
366
+ **What goes wrong:**
367
+ - If the component unmounts before the fetch resolves, `setUser` runs on an unmounted component, producing a React warning and, in some cases, subtle state corruption if the component remounts
368
+ - Race conditions: rapid `userId` changes queue multiple fetches; a slow earlier response can overwrite a fast later one
369
+ - Subscriptions (WebSockets, event listeners, timers) run indefinitely after the component is gone, leaking memory and producing phantom state updates
370
+
371
+ **The fix:**
372
+ ```jsx
373
+ useEffect(() => {
374
+ let cancelled = false;
375
+ const controller = new AbortController();
376
+
377
+ fetch(`/api/users/${userId}`, { signal: controller.signal })
378
+ .then(r => r.json())
379
+ .then(data => {
380
+ if (!cancelled) setUser(data);
381
+ })
382
+ .catch(err => {
383
+ if (err.name !== 'AbortError') setError(err);
384
+ });
385
+
386
+ return () => {
387
+ cancelled = true;
388
+ controller.abort();
389
+ };
390
+ }, [userId]);
391
+ ```
392
+
393
+ **Detection rule:**
394
+ Flag any `useEffect` that contains a `fetch()` call, a `setTimeout`/`setInterval`, or an `.addEventListener()` call and whose callback does not return a cleanup function.
395
+
396
+ ---
397
+
398
+ ### AP-08: Unnecessary useMemo / useCallback
399
+
400
+ **Also known as:** Premature memoisation, defensive wrapping, cargo-cult hooks
401
+ **Frequency:** Very Common
402
+ **Severity:** Low
403
+ **Detection difficulty:** Hard
404
+
405
+ **What it looks like:**
406
+ ```jsx
407
+ function Greeting({ name }) {
408
+ // Memoising a trivial string concatenation
409
+ const greeting = useMemo(() => `Hello, ${name}!`, [name]);
410
+
411
+ // Memoising a handler on a non-memoised child
412
+ const handleClick = useCallback(() => {
413
+ console.log('clicked');
414
+ }, []);
415
+
416
+ return <button onClick={handleClick}>{greeting}</button>;
417
+ }
418
+ ```
419
+
420
+ **Why developers do it:**
421
+ Developers cargo-cult patterns from performance-critical code, "just to be safe". Code reviews sometimes reward defensive memoisation without verifying that the memoised boundary is actually a performance bottleneck.
422
+
423
+ **What goes wrong:**
424
+ - `useMemo` and `useCallback` add overhead on every render (dependency comparison, closure allocation) — they make the initial render measurably slower
425
+ - The memoised value is only useful if the consumer is wrapped in `React.memo`; without that, the parent re-render forces child re-renders regardless
426
+ - Adds cognitive noise, making it harder to distinguish meaningful memoisation from boilerplate
427
+ - With the React Compiler (stable as of late 2025), manual memoisation is largely redundant and can conflict with compiler optimisations
428
+
429
+ **The fix:**
430
+ Remove the hooks. Add them back only after profiling shows a specific render as a bottleneck, and only when the memoised value is consumed by a `React.memo`-wrapped child or is a referentially stable dependency of another hook.
431
+
432
+ **Detection rule:**
433
+ Flag `useMemo` calls whose computation is a simple expression (string template, arithmetic, property access) or `useCallback` calls whose dependencies array is `[]` and the callback is not passed to a `React.memo`-wrapped component.
434
+
435
+ ---
436
+
437
+ ### AP-09: Missing useMemo / useCallback Causing Re-renders
438
+
439
+ **Also known as:** New reference on every render, unstable prop identity, memoisation gap
440
+ **Frequency:** Common
441
+ **Severity:** High
442
+ **Detection difficulty:** Hard
443
+
444
+ **What it looks like:**
445
+ ```jsx
446
+ function Dashboard({ userId }) {
447
+ // New object reference every render
448
+ const config = { userId, theme: 'dark' };
449
+
450
+ // New function reference every render
451
+ const fetchData = () => fetch(`/api/data?user=${userId}`);
452
+
453
+ return <ExpensiveChart config={config} onRefresh={fetchData} />;
454
+ }
455
+
456
+ // ExpensiveChart is wrapped in React.memo — but memo is useless here
457
+ const ExpensiveChart = React.memo(({ config, onRefresh }) => { ... });
458
+ ```
459
+
460
+ **Why developers do it:**
461
+ The broken memoisation chain is invisible. `React.memo` looks correct in isolation, but the parent silently destroys its effectiveness by producing new references every render.
462
+
463
+ **What goes wrong:**
464
+ - `React.memo` performs a shallow comparison; new object/function references always fail the comparison, triggering a re-render regardless of whether the data changed
465
+ - Expensive computations re-run on every parent re-render
466
+ - Can cause cascading re-renders through a subtree
467
+
468
+ **The fix:**
469
+ ```jsx
470
+ function Dashboard({ userId }) {
471
+ const config = useMemo(() => ({ userId, theme: 'dark' }), [userId]);
472
+ const fetchData = useCallback(() => fetch(`/api/data?user=${userId}`), [userId]);
473
+
474
+ return <ExpensiveChart config={config} onRefresh={fetchData} />;
475
+ }
476
+ ```
477
+
478
+ **Detection rule:**
479
+ Flag object literals (`{}`) and function expressions/arrow functions created inline as JSX props on components that are wrapped in `React.memo`.
480
+
481
+ ---
482
+
483
+ ### AP-10: God Component (500+ Line Components)
484
+
485
+ **Also known as:** Monolithic component, kitchen-sink component, do-everything component
486
+ **Frequency:** Common
487
+ **Severity:** High
488
+ **Detection difficulty:** Easy
489
+
490
+ **What it looks like:**
491
+ ```jsx
492
+ // UserDashboard.jsx — 800 lines
493
+ function UserDashboard() {
494
+ // 15+ useState hooks
495
+ // 8+ useEffect hooks
496
+ // Inline form handling, API fetching, data transformation,
497
+ // role-based rendering, modal management, CSV export logic...
498
+ return (
499
+ <div>
500
+ {/* 300 lines of deeply nested JSX */}
501
+ </div>
502
+ );
503
+ }
504
+ ```
505
+
506
+ **Why developers do it:**
507
+ Features accrete incrementally. A 100-line component becomes 200 lines, then 400, each addition feeling like a small change. The cost is invisible until the component becomes unmaintainable.
508
+
509
+ **What goes wrong:**
510
+ - A single change requires reading and reasoning about hundreds of lines of unrelated logic
511
+ - Testing requires mocking every concern the component touches
512
+ - Re-renders are expensive because a single state change invalidates a massive render tree
513
+ - Impossible to reuse sub-behaviours in other contexts
514
+ - New developers on the team avoid touching the component, causing further feature drift
515
+
516
+ **The fix:**
517
+ Extract by concern:
518
+ - Split data-fetching into a custom hook (`useUserDashboardData`)
519
+ - Extract each logical section into its own component (`UserProfile`, `ActivityFeed`, `ExportPanel`)
520
+ - Move business logic out of JSX into pure functions
521
+
522
+ Target: no component should exceed ~150 lines; no component should contain more than 3–4 `useEffect` hooks.
523
+
524
+ **Detection rule:**
525
+ Flag any component function whose source length exceeds 200 lines or contains more than 5 `useState` calls.
526
+
527
+ ---
528
+
529
+ ### AP-11: Using Context for Frequently Changing Values
530
+
531
+ **Also known as:** God context, context performance trap, high-frequency context updates
532
+ **Frequency:** Common
533
+ **Severity:** High
534
+ **Detection difficulty:** Hard
535
+
536
+ **What it looks like:**
537
+ ```jsx
538
+ const AppContext = React.createContext();
539
+
540
+ function App() {
541
+ const [mousePos, setMousePos] = useState({ x: 0, y: 0 });
542
+ const [user, setUser] = useState(null);
543
+ const [theme, setTheme] = useState('light');
544
+
545
+ // Mouse position changes 60 times/second — all consumers re-render
546
+ return (
547
+ <AppContext.Provider value={{ mousePos, user, theme, setTheme }}>
548
+ <Router />
549
+ </AppContext.Provider>
550
+ );
551
+ }
552
+ ```
553
+
554
+ **Why developers do it:**
555
+ Context is introduced to solve prop drilling, then values are added to it progressively. It starts with `user` and `theme`, then gains `mousePos`, `notifications`, cart counts, and more.
556
+
557
+ **What goes wrong:**
558
+ - Every consumer of the context re-renders whenever **any** value in the context object changes
559
+ - Frequently updating values (mouse position, animation frame counters, live websocket data) will cause every consumer to re-render at that frequency
560
+ - React has no built-in mechanism to subscribe to a subset of context values
561
+
562
+ **The fix:**
563
+ ```jsx
564
+ // Split contexts by change frequency
565
+ const UserContext = React.createContext(null); // static after login
566
+ const ThemeContext = React.createContext('light'); // rare changes
567
+ const MouseContext = React.createContext({ x: 0, y: 0 }); // frequent — move to Zustand/Jotai or pass directly
568
+
569
+ function App() {
570
+ return (
571
+ <UserContext.Provider value={user}>
572
+ <ThemeContext.Provider value={theme}>
573
+ <Router />
574
+ </ThemeContext.Provider>
575
+ </UserContext.Provider>
576
+ );
577
+ }
578
+ ```
579
+ For high-frequency values, prefer a fine-grained state library (Zustand, Jotai) or a subscription-based pattern.
580
+
581
+ **Detection rule:**
582
+ Flag context `value` props that are object literals containing more than 4 keys, or that include values derived from `requestAnimationFrame`, scroll, or mouse event handlers.
583
+
584
+ ---
585
+
586
+ ### AP-12: Fetching in useEffect Without Abort / Cleanup
587
+
588
+ **Also known as:** Unguarded fetch, race-condition fetch, fire-and-forget effect
589
+ **Frequency:** Very Common
590
+ **Severity:** High
591
+ **Detection difficulty:** Easy
592
+
593
+ **What it looks like:**
594
+ ```jsx
595
+ function ArticleView({ articleId }) {
596
+ const [article, setArticle] = useState(null);
597
+
598
+ useEffect(() => {
599
+ fetch(`/api/articles/${articleId}`)
600
+ .then(r => r.json())
601
+ .then(setArticle);
602
+ // No cleanup, no abort, no race-condition guard
603
+ }, [articleId]);
604
+ }
605
+ ```
606
+
607
+ **Why developers do it:**
608
+ The basic `fetch` + `useEffect` pattern is taught in introductory React courses without the cleanup addendum. The bug only manifests under fast navigation or slow networks.
609
+
610
+ **What goes wrong:**
611
+ - Navigating between articles quickly can cause an older, slower request to resolve after a newer one, displaying stale content
612
+ - React's StrictMode double-invokes effects, immediately triggering a second fetch that the first cannot cancel
613
+ - Memory leaks in long-running SPAs as references pile up
614
+ - "Can't perform a React state update on an unmounted component" warnings in production logs
615
+
616
+ **The fix:**
617
+ ```jsx
618
+ useEffect(() => {
619
+ const controller = new AbortController();
620
+ setLoading(true);
621
+
622
+ fetch(`/api/articles/${articleId}`, { signal: controller.signal })
623
+ .then(r => r.json())
624
+ .then(data => {
625
+ setArticle(data);
626
+ setLoading(false);
627
+ })
628
+ .catch(err => {
629
+ if (err.name !== 'AbortError') setError(err.message);
630
+ });
631
+
632
+ return () => controller.abort();
633
+ }, [articleId]);
634
+ ```
635
+ Better still: use a data-fetching library (React Query, SWR) that handles all of this by default.
636
+
637
+ **Detection rule:**
638
+ Flag any `useEffect` containing a `fetch()` call that does not return a cleanup function calling `AbortController.abort()` or equivalent.
639
+
640
+ ---
641
+
642
+ ### AP-13: Not Handling Loading / Error / Empty States
643
+
644
+ **Also known as:** Happy-path-only UI, missing state branches, undefined UI
645
+ **Frequency:** Very Common
646
+ **Severity:** Medium
647
+ **Detection difficulty:** Easy
648
+
649
+ **What it looks like:**
650
+ ```jsx
651
+ function UserList() {
652
+ const [users, setUsers] = useState([]);
653
+
654
+ useEffect(() => {
655
+ fetch('/api/users').then(r => r.json()).then(setUsers);
656
+ }, []);
657
+
658
+ // What shows during load? What if fetch fails? What if users is []?
659
+ return (
660
+ <ul>
661
+ {users.map(u => <li key={u.id}>{u.name}</li>)}
662
+ </ul>
663
+ );
664
+ }
665
+ ```
666
+
667
+ **Why developers do it:**
668
+ Initial development focuses on the data-available path. Empty and error states are treated as edge cases to add "later" — and later often never arrives.
669
+
670
+ **What goes wrong:**
671
+ - Users see a blank screen during fetch with no indication that anything is happening
672
+ - A failed request is silent; users do not know whether to wait or retry
673
+ - An empty response looks identical to a loading state or an error state
674
+ - Production incidents are harder to debug because the UI gives no indication of which branch was hit
675
+
676
+ **The fix:**
677
+ ```jsx
678
+ function UserList() {
679
+ const [users, setUsers] = useState([]);
680
+ const [loading, setLoading] = useState(true);
681
+ const [error, setError] = useState(null);
682
+
683
+ useEffect(() => { /* ... with cleanup ... */ }, []);
684
+
685
+ if (loading) return <Spinner />;
686
+ if (error) return <ErrorMessage message={error} onRetry={refetch} />;
687
+ if (users.length === 0) return <EmptyState message="No users found." />;
688
+
689
+ return <ul>{users.map(u => <li key={u.id}>{u.name}</li>)}</ul>;
690
+ }
691
+ ```
692
+
693
+ **Detection rule:**
694
+ Flag any component that renders a list derived from an async source but does not contain branches for at least two of: loading state, error state, empty-array state.
695
+
696
+ ---
697
+
698
+ ### AP-14: Using dangerouslySetInnerHTML
699
+
700
+ **Also known as:** Raw HTML injection, innerHTML prop, XSS gateway
701
+ **Frequency:** Occasional
702
+ **Severity:** High
703
+ **Detection difficulty:** Easy
704
+
705
+ **What it looks like:**
706
+ ```jsx
707
+ function BlogPost({ post }) {
708
+ return (
709
+ <article
710
+ dangerouslySetInnerHTML={{ __html: post.content }}
711
+ />
712
+ );
713
+ }
714
+ ```
715
+
716
+ **Why developers do it:**
717
+ CMS content, rich-text editors, and Markdown renderers produce HTML strings. `dangerouslySetInnerHTML` is the only built-in way to inject raw HTML into the DOM, and its name is sometimes read as a warning rather than a stop sign.
718
+
719
+ **What goes wrong:**
720
+ - If `post.content` contains any user-controlled data (comments, user profile fields, URL parameters) an attacker can inject `<script>` tags or event handler attributes, achieving stored or reflected XSS
721
+ - React's automatic HTML escaping is completely bypassed
722
+ - Content Security Policy headers may not fully mitigate DOM-based injection
723
+ - Search engine crawlers may not index dynamically injected HTML reliably
724
+
725
+ **The fix:**
726
+ ```jsx
727
+ import DOMPurify from 'dompurify';
728
+
729
+ // Option A: sanitise before injecting
730
+ function BlogPost({ post }) {
731
+ const clean = DOMPurify.sanitize(post.content);
732
+ return <article dangerouslySetInnerHTML={{ __html: clean }} />;
733
+ }
734
+
735
+ // Option B (preferred): use a Markdown/rich-text renderer that produces React elements
736
+ import ReactMarkdown from 'react-markdown';
737
+ function BlogPost({ post }) {
738
+ return <article><ReactMarkdown>{post.markdownContent}</ReactMarkdown></article>;
739
+ }
740
+ ```
741
+
742
+ **Detection rule:**
743
+ Flag every occurrence of `dangerouslySetInnerHTML` as requiring a security review comment; flag any occurrence where the `__html` value is not the return value of a recognised sanitisation function (`DOMPurify.sanitize`, `sanitizeHtml`, etc.).
744
+
745
+ ---
746
+
747
+ ### AP-15: Not Using Error Boundaries
748
+
749
+ **Also known as:** Missing error boundary, unguarded render tree, uncaught render error
750
+ **Frequency:** Common
751
+ **Severity:** High
752
+ **Detection difficulty:** Easy
753
+
754
+ **What it looks like:**
755
+ ```jsx
756
+ // Root renders everything with no error boundary
757
+ function App() {
758
+ return (
759
+ <Router>
760
+ <UserProfile /> {/* Any render error here... */}
761
+ <ActivityFeed /> {/* ...or here... */}
762
+ <RecommendedPosts /> {/* ...or here unmounts the entire app */}
763
+ </Router>
764
+ );
765
+ }
766
+ ```
767
+
768
+ **Why developers do it:**
769
+ React's Error Boundary API requires a class component, which feels out of place in a hooks-based codebase. Developers either don't know the API or delay adding it.
770
+
771
+ **What goes wrong:**
772
+ - An unhandled JavaScript error during render, in a lifecycle method, or in a constructor propagates up and unmounts the **entire React tree** — users see a blank white screen
773
+ - No user-facing recovery path; the only option is a full page reload
774
+ - Errors in third-party components (analytics widgets, ad scripts embedded in React trees) can bring down the whole application
775
+
776
+ **The fix:**
777
+ ```jsx
778
+ // Use react-error-boundary (de-facto standard utility)
779
+ import { ErrorBoundary } from 'react-error-boundary';
780
+
781
+ function App() {
782
+ return (
783
+ <ErrorBoundary fallback={<AppCrashPage />}>
784
+ <Router>
785
+ <ErrorBoundary fallback={<WidgetError />}>
786
+ <UserProfile />
787
+ </ErrorBoundary>
788
+ <ActivityFeed />
789
+ </Router>
790
+ </ErrorBoundary>
791
+ );
792
+ }
793
+ ```
794
+ Add error boundaries at: (1) the app root, (2) each major route, (3) each independently-loaded widget or panel.
795
+
796
+ **Detection rule:**
797
+ Flag any `ReactDOM.render` or `createRoot().render()` call where the root component is not wrapped in, or does not itself contain, at least one `ErrorBoundary` (class or `react-error-boundary`).
798
+
799
+ ---
800
+
801
+ ### AP-16: Mixing Controlled and Uncontrolled Components
802
+
803
+ **Also known as:** Hybrid input, value/defaultValue conflict, controlled-to-uncontrolled switch
804
+ **Frequency:** Common
805
+ **Severity:** Medium
806
+ **Detection difficulty:** Easy
807
+
808
+ **What it looks like:**
809
+ ```jsx
810
+ function ProfileForm({ initialName }) {
811
+ const [name, setName] = useState(initialName); // may be undefined initially
812
+
813
+ return (
814
+ <input
815
+ value={name} // controlled when name is defined
816
+ onChange={e => setName(e.target.value)}
817
+ />
818
+ // If initialName is undefined, value={undefined} makes React treat this
819
+ // as uncontrolled; when state later becomes a string, React emits a warning
820
+ // and behaviour is undefined
821
+ );
822
+ }
823
+ ```
824
+
825
+ **Why developers do it:**
826
+ The bug is triggered by an undefined or null initial value, which is easy to miss in development when data is always present but manifests in production during loading states.
827
+
828
+ **What goes wrong:**
829
+ - React warns: "A component is changing an uncontrolled input to be controlled"
830
+ - The input's internal DOM value and React's state value diverge, causing the input to display stale data
831
+ - Form submission may read the wrong value depending on which controller wins
832
+ - Hydration mismatches in SSR applications
833
+
834
+ **The fix:**
835
+ ```jsx
836
+ // Always initialise state with a defined value
837
+ const [name, setName] = useState(initialName ?? '');
838
+
839
+ // Or choose uncontrolled deliberately with a ref
840
+ const nameRef = useRef(null);
841
+ <input ref={nameRef} defaultValue={initialName ?? ''} />
842
+ ```
843
+ Never mix `value` and `defaultValue` on the same input. Never let a controlled input's `value` become `undefined` or `null`.
844
+
845
+ **Detection rule:**
846
+ Flag inputs that use `value={someVar}` where `someVar` could be `undefined` or `null` based on its type annotation or initial `useState` value.
847
+
848
+ ---
849
+
850
+ ### AP-17: useState for Everything (Not Lifting State)
851
+
852
+ **Also known as:** State isolation, duplicate state, out-of-sync sibling state
853
+ **Frequency:** Very Common
854
+ **Severity:** Medium
855
+ **Detection difficulty:** Moderate
856
+
857
+ **What it looks like:**
858
+ ```jsx
859
+ function App() {
860
+ return (
861
+ <>
862
+ <FilterPanel /> {/* owns selectedCategory state */}
863
+ <ProductList /> {/* needs selectedCategory but can't access it */}
864
+ </>
865
+ );
866
+ }
867
+
868
+ function FilterPanel() {
869
+ const [selectedCategory, setSelectedCategory] = useState('all');
870
+ // ProductList can never know about this
871
+ }
872
+ ```
873
+
874
+ **Why developers do it:**
875
+ Co-locating state with the component that first needs it is correct practice — until a sibling component also needs it. Developers often add a second `useState` in the sibling and try to keep them in sync with effects.
876
+
877
+ **What goes wrong:**
878
+ - Two copies of the same truth must be kept in sync manually (usually with effects — see AP-02 and AP-06)
879
+ - Sync logic is fragile; any event path that updates one copy but not the other causes stale UI
880
+ - The data flow becomes implicit and hard to trace
881
+ - Tests must simulate both state machines
882
+
883
+ **The fix:**
884
+ ```jsx
885
+ // Lift to the lowest common ancestor
886
+ function App() {
887
+ const [selectedCategory, setSelectedCategory] = useState('all');
888
+ return (
889
+ <>
890
+ <FilterPanel category={selectedCategory} onCategoryChange={setSelectedCategory} />
891
+ <ProductList category={selectedCategory} />
892
+ </>
893
+ );
894
+ }
895
+ ```
896
+
897
+ **Detection rule:**
898
+ Flag sibling components that declare `useState` with names that appear semantically equivalent (e.g., `selectedId`/`activeId`, `filter`/`currentFilter`), or that contain `useEffect` hooks whose only purpose is to mirror another component's prop or state.
899
+
900
+ ---
901
+
902
+ ### AP-18: Too Many useState Variables (Should be useReducer)
903
+
904
+ **Also known as:** useState explosion, fragmented state, scattered state variables
905
+ **Frequency:** Common
906
+ **Severity:** Medium
907
+ **Detection difficulty:** Moderate
908
+
909
+ **What it looks like:**
910
+ ```jsx
911
+ function CheckoutForm() {
912
+ const [name, setName] = useState('');
913
+ const [email, setEmail] = useState('');
914
+ const [address, setAddress] = useState('');
915
+ const [cardNumber, setCardNumber] = useState('');
916
+ const [cvv, setCvv] = useState('');
917
+ const [loading, setLoading] = useState(false);
918
+ const [error, setError] = useState(null);
919
+ const [step, setStep] = useState(1);
920
+ const [promoCode, setPromoCode] = useState('');
921
+ const [discount, setDiscount] = useState(0);
922
+ // ...6 more
923
+ }
924
+ ```
925
+
926
+ **Why developers do it:**
927
+ `useState` is simpler to learn and reach for. The explosion happens gradually — each addition feels like adding one variable.
928
+
929
+ **What goes wrong:**
930
+ - Coordinated state transitions become error-prone: when submitting, you must remember to set `loading = true`, `error = null`, and clear fields simultaneously — miss one and the UI is inconsistent
931
+ - Invalid intermediate states become representable (e.g., `loading = true` and `error = 'Network timeout'` simultaneously)
932
+ - Reset logic must enumerate every variable individually
933
+ - Test setup for the component requires constructing many independent initial values
934
+
935
+ **The fix:**
936
+ ```jsx
937
+ const initialState = {
938
+ fields: { name: '', email: '', address: '', cardNumber: '', cvv: '' },
939
+ ui: { loading: false, error: null, step: 1 },
940
+ promo: { code: '', discount: 0 },
941
+ };
942
+
943
+ function reducer(state, action) {
944
+ switch (action.type) {
945
+ case 'SUBMIT_START':
946
+ return { ...state, ui: { ...state.ui, loading: true, error: null } };
947
+ case 'SUBMIT_SUCCESS':
948
+ return { ...state, ui: { loading: false, error: null, step: state.ui.step + 1 } };
949
+ case 'SUBMIT_ERROR':
950
+ return { ...state, ui: { ...state.ui, loading: false, error: action.payload } };
951
+ default:
952
+ return state;
953
+ }
954
+ }
955
+
956
+ const [state, dispatch] = useReducer(reducer, initialState);
957
+ ```
958
+
959
+ **Detection rule:**
960
+ Flag any component containing more than 5 `useState` declarations where the state variables share a logical domain (form fields, async status, wizard steps).
961
+
962
+ ---
963
+
964
+ ### AP-19: Stale Closures Over State
965
+
966
+ **Also known as:** Stale closure bug, captured stale value, hook dependency omission
967
+ **Frequency:** Common
968
+ **Severity:** High
969
+ **Detection difficulty:** Hard
970
+
971
+ **What it looks like:**
972
+ ```jsx
973
+ function Counter() {
974
+ const [count, setCount] = useState(0);
975
+
976
+ useEffect(() => {
977
+ const interval = setInterval(() => {
978
+ setCount(count + 1); // captures count=0 from mount closure
979
+ }, 1000);
980
+ return () => clearInterval(interval);
981
+ }, []); // empty deps — count is never refreshed
982
+ }
983
+ ```
984
+
985
+ **Why developers do it:**
986
+ Developers add `[]` to `useEffect` to mean "run once on mount", correctly for setup — but when the effect's callback references state, the closure freezes the value at the time of creation. This is a non-obvious consequence of how JavaScript closures work.
987
+
988
+ **What goes wrong:**
989
+ - `count` is always `0` inside the interval callback; the counter increments from 0 to 1 and then freezes
990
+ - Similar bugs appear in `useCallback` with stale `props`, in `setTimeout` handlers, and in event listeners registered once
991
+ - The bug is invisible in tests that don't advance time and in development under StrictMode if intervals are manually re-registered
992
+
993
+ **The fix:**
994
+ ```jsx
995
+ // Option A: use the functional updater form (avoids reading state in closure)
996
+ useEffect(() => {
997
+ const interval = setInterval(() => {
998
+ setCount(prev => prev + 1); // reads current state, not closed-over value
999
+ }, 1000);
1000
+ return () => clearInterval(interval);
1001
+ }, []);
1002
+
1003
+ // Option B: add count to deps (re-registers interval on every change)
1004
+ useEffect(() => {
1005
+ const interval = setInterval(() => setCount(count + 1), 1000);
1006
+ return () => clearInterval(interval);
1007
+ }, [count]);
1008
+
1009
+ // Option C: use useRef to hold a mutable callback (advanced)
1010
+ const savedCallback = useRef();
1011
+ useEffect(() => { savedCallback.current = () => setCount(c => c + 1); });
1012
+ useEffect(() => {
1013
+ const tick = () => savedCallback.current();
1014
+ const id = setInterval(tick, 1000);
1015
+ return () => clearInterval(id);
1016
+ }, []);
1017
+ ```
1018
+
1019
+ **Detection rule:**
1020
+ The `eslint-plugin-react-hooks` `exhaustive-deps` rule catches this automatically — flag any suppression comment (`// eslint-disable-next-line`) on a `useEffect`, `useCallback`, or `useMemo` dependency array.
1021
+
1022
+ ---
1023
+
1024
+ ### AP-20: Ignoring React.StrictMode Warnings
1025
+
1026
+ **Also known as:** StrictMode suppression, double-invoke blind spot, silenced dev warnings
1027
+ **Frequency:** Common
1028
+ **Severity:** Medium
1029
+ **Detection difficulty:** Easy
1030
+
1031
+ **What it looks like:**
1032
+ ```jsx
1033
+ // Common "fix": remove StrictMode to silence the double-invoke noise
1034
+ // Root file:
1035
+ root.render(
1036
+ // <React.StrictMode> <-- removed because "it caused bugs"
1037
+ <App />
1038
+ // </React.StrictMode>
1039
+ );
1040
+ ```
1041
+
1042
+ **Why developers do it:**
1043
+ `React.StrictMode` double-invokes render functions and effects in development to expose impure renders and missing cleanups. When this surfaces bugs, developers often interpret the double-invoke as the cause rather than the revealer and remove `StrictMode`.
1044
+
1045
+ **What goes wrong:**
1046
+ - `StrictMode` removal hides real bugs that will manifest in React 18+ Concurrent Mode features (Suspense, transitions, deferred rendering), which legitimately re-invoke renders and effects
1047
+ - The underlying bugs (impure renders, missing cleanup, mutated state) persist and surface in production under real concurrent rendering conditions
1048
+ - Future upgrades to React become vastly more painful
1049
+
1050
+ **Common warnings and their root causes:**
1051
+
1052
+ | Warning | Root Cause |
1053
+ |---|---|
1054
+ | "Cannot update a component while rendering" | State update triggered during another component's render |
1055
+ | "Each child in a list should have a unique key" | AP-03 |
1056
+ | "Can't perform state update on unmounted component" | AP-07 or AP-12 |
1057
+ | "A component is changing uncontrolled to controlled" | AP-16 |
1058
+ | Double network requests in dev | Missing cleanup in AP-07 / AP-12 |
1059
+
1060
+ **The fix:**
1061
+ Keep `<React.StrictMode>` enabled at all times during development. Treat every warning it surfaces as a bug to fix, not noise to suppress. Fix missing cleanups (AP-07), impure renders (AP-04), and unguarded effects (AP-12) rather than disabling the detector.
1062
+
1063
+ **Detection rule:**
1064
+ Flag any `createRoot().render()` or `ReactDOM.render()` call that does not wrap the root in `<React.StrictMode>`. Flag any git commit that removes `StrictMode` without a documented architectural reason.
1065
+
1066
+ ---
1067
+
1068
+ ## Root Cause Analysis
1069
+
1070
+ The 20 anti-patterns above cluster into six underlying causes:
1071
+
1072
+ | Root Cause | Anti-Patterns | Core Problem |
1073
+ |---|---|---|
1074
+ | Mental model mismatch | AP-02, AP-06, AP-19 | Treating React's render model as a reactive event system or imperative loop |
1075
+ | JavaScript primitive behaviour | AP-03, AP-04, AP-09 | Reference equality, array mutability, and closure capture are not React-specific |
1076
+ | Incremental growth | AP-10, AP-17, AP-18 | Patterns that are correct at small scale become anti-patterns at scale |
1077
+ | Missing lifecycle knowledge | AP-07, AP-12, AP-20 | Incomplete understanding of effect cleanup and StrictMode's purpose |
1078
+ | Security / safety omission | AP-14, AP-15 | Features that require explicit opt-in to be safe |
1079
+ | Performance misapplication | AP-08, AP-09, AP-11 | Memoisation and context tools used without understanding their cost model |
1080
+
1081
+ ---
1082
+
1083
+ ## Self-Check Questions
1084
+
1085
+ Use these during code review or self-review to catch the anti-patterns above before they reach production.
1086
+
1087
+ 1. Does any component receive a prop it never reads — only passes to a child? *(AP-01)*
1088
+ 2. Is there a `useState` + `useEffect` pair where the only thing the effect does is call `setState` with a value derived from the dependencies? *(AP-02, AP-06)*
1089
+ 3. Are all list keys stable unique identifiers from the data domain, not array indices? *(AP-03)*
1090
+ 4. Are `.push()`, `.splice()`, or direct property assignments ever called on values from `useState`? *(AP-04)*
1091
+ 5. Are any components (starting with an uppercase letter, returning JSX) declared inside the body of another component function? *(AP-05)*
1092
+ 6. Does every `useEffect` that opens a subscription, sets a timer, or starts a fetch return a cleanup function? *(AP-07, AP-12)*
1093
+ 7. Is every `useMemo` and `useCallback` accompanied by a measurable reason and consumed by a `React.memo`-wrapped component or a hook dependency? *(AP-08, AP-09)*
1094
+ 8. Does any component exceed 150–200 lines or contain more than 5 `useState` hooks? *(AP-10, AP-18)*
1095
+ 9. Is context split by change frequency — fast-changing values isolated from slow-changing ones? *(AP-11)*
1096
+ 10. Do all data-fetching components render distinct UI for loading, error, and empty states? *(AP-13)*
1097
+ 11. Is every use of `dangerouslySetInnerHTML` sanitised with DOMPurify or an equivalent library? *(AP-14)*
1098
+ 12. Is there at least one `ErrorBoundary` at the app root and around each independently deployable UI section? *(AP-15)*
1099
+ 13. Can any controlled input's `value` prop evaluate to `undefined` or `null`? *(AP-16)*
1100
+ 14. Do sibling components manage state that they need to share — requiring an effect to keep them in sync? *(AP-17)*
1101
+ 15. Is `React.StrictMode` enabled in all development builds, and are its warnings treated as bugs? *(AP-20)*
1102
+
1103
+ ---
1104
+
1105
+ ## Code Smell Quick Reference
1106
+
1107
+ | Smell | Likely Anti-Pattern | Severity |
1108
+ |---|---|---|
1109
+ | `key={index}` in a `.map()` | AP-03 | High |
1110
+ | `useState` + `useEffect` that only calls `setState` | AP-02, AP-06 | High |
1111
+ | `useEffect` with no return value, contains `fetch()` | AP-07, AP-12 | High |
1112
+ | `const Component = () =>` inside a component body | AP-05 | High |
1113
+ | `dangerouslySetInnerHTML` without sanitisation call | AP-14 | High |
1114
+ | `items.push(...)` followed by `setItems(items)` | AP-04 | High |
1115
+ | Object literal `{}` or arrow function as prop on `React.memo` component | AP-09 | High |
1116
+ | No `ErrorBoundary` wrapping route or root | AP-15 | High |
1117
+ | 6+ `useState` declarations in one component | AP-10, AP-18 | Medium |
1118
+ | Props passed through 3+ layers that an intermediate component ignores | AP-01 | Medium |
1119
+ | `<React.StrictMode>` absent or commented out | AP-20 | Medium |
1120
+ | `useMemo` on a simple expression (string, number, single property) | AP-08 | Low |
1121
+ | Context provider whose `value` is an inline object `{{ a, b, c, d, e }}` | AP-11 | High |
1122
+ | `value={someVar}` input with no fallback for `undefined` | AP-16 | Medium |
1123
+ | No loading/error/empty branch in a component that fetches | AP-13 | Medium |
1124
+ | `setInterval`/`setTimeout` in `useEffect` with `[]` deps and state read inside callback | AP-19 | High |
1125
+
1126
+ ---
1127
+
1128
+ *Researched: 2026-03-08 | Sources: [React — You Might Not Need an Effect](https://react.dev/learn/you-might-not-need-an-effect), [Kent C. Dodds — Prop Drilling](https://kentcdodds.com/blog/prop-drilling), [Kent C. Dodds — When to useMemo and useCallback](https://kentcdodds.com/blog/usememo-and-usecallback), [Dmitri Pavlutin — Stale Closures in React Hooks](https://dmitripavlutin.com/react-hooks-stale-closures/), [LogRocket — 15 common useEffect mistakes](https://blog.logrocket.com/15-common-useeffect-mistakes-react/), [Nadia Makarevich — How to useMemo and useCallback: you can remove most of them](https://www.developerway.com/posts/how-to-use-memo-use-callback), [React Hooks Anti-Patterns — Tech Insights](https://techinsights.manisuec.com/reactjs/react-hooks-antipatterns/), [React 19 Compiler and memoisation](https://isitdev.com/react-19-compiler-usememo-usecallback-2025/), [React XSS and dangerouslySetInnerHTML — StackHawk](https://www.stackhawk.com/blog/react-xss-guide-examples-and-prevention/), [15 React Anti-Patterns — jsdev.space](https://jsdev.space/react-anti-patterns-2025/), [6 Common React Anti-Patterns — ITNEXT](https://itnext.io/6-common-react-anti-patterns-that-are-hurting-your-code-quality-904b9c32e933)]*