@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,1827 @@
1
+ # Flutter & Dart Anti-Patterns
2
+
3
+ > Flutter's reactive, widget-based architecture is powerful but unforgiving. A single misplaced `setState`, a forgotten `dispose`, or a monolithic widget can cascade into jank, memory leaks, and unmaintainable spaghetti. These anti-patterns are drawn from real production incidents, community post-mortems, and the collective pain of the Flutter ecosystem. Knowing them prevents more bugs than any amount of best-practice documentation.
4
+
5
+ > **Domain:** Frontend
6
+ > **Anti-patterns covered:** 21
7
+ > **Highest severity:** Critical
8
+
9
+ ## Anti-Patterns
10
+
11
+ ### AP-01: The God Widget
12
+
13
+ **Also known as:** Monolithic Widget, Kitchen Sink Widget, The 800-Line build()
14
+ **Frequency:** Very Common
15
+ **Severity:** High
16
+ **Detection difficulty:** Easy
17
+
18
+ **What it looks like:**
19
+
20
+ A single widget file containing hundreds or thousands of lines, mixing layout, business logic, API calls, navigation, and state management in one `build()` method.
21
+
22
+ ```dart
23
+ // BAD: 600-line widget doing everything
24
+ class DashboardScreen extends StatefulWidget {
25
+ @override
26
+ _DashboardScreenState createState() => _DashboardScreenState();
27
+ }
28
+
29
+ class _DashboardScreenState extends State<DashboardScreen> {
30
+ List<User> users = [];
31
+ bool isLoading = true;
32
+ String? error;
33
+ int selectedTab = 0;
34
+
35
+ @override
36
+ void initState() {
37
+ super.initState();
38
+ fetchUsers();
39
+ }
40
+
41
+ Future<void> fetchUsers() async {
42
+ final response = await http.get(Uri.parse('https://api.example.com/users'));
43
+ // ... parsing logic here ...
44
+ setState(() { users = parsed; isLoading = false; });
45
+ }
46
+
47
+ @override
48
+ Widget build(BuildContext context) {
49
+ return Scaffold(
50
+ appBar: AppBar(/* 40 lines of app bar config */),
51
+ body: Column(
52
+ children: [
53
+ // 50 lines of tab bar
54
+ // 80 lines of search/filter UI
55
+ // 100 lines of list rendering
56
+ // 60 lines of bottom sheet logic
57
+ // 40 lines of dialogs
58
+ ],
59
+ ),
60
+ );
61
+ }
62
+ }
63
+ ```
64
+
65
+ **Why developers do it:**
66
+
67
+ Flutter makes it easy to keep adding widgets inline. When prototyping, developers add "just one more widget" to the build method. There is no compile-time warning for large widgets, and the app still runs fine, so the problem creeps up gradually. Beginners coming from imperative frameworks often do not think in terms of composition.
68
+
69
+ **What goes wrong:**
70
+
71
+ - The entire widget tree rebuilds on every `setState`, even parts that did not change.
72
+ - Testing any single piece of functionality requires instantiating the entire screen.
73
+ - Multiple developers editing the same file causes merge conflicts constantly.
74
+ - Performance degrades as the widget tree grows -- Flutter DevTools rebuild stats show hundreds of unnecessary rebuilds per frame in severe cases.
75
+ - Code reuse becomes impossible; similar UI sections get copy-pasted.
76
+
77
+ **The fix:**
78
+
79
+ Extract sub-trees into separate `StatelessWidget` or `StatefulWidget` classes. Move business logic into services, repositories, or state management classes (BLoC, Riverpod, etc.).
80
+
81
+ ```dart
82
+ // GOOD: Composed from small, focused widgets
83
+ class DashboardScreen extends StatelessWidget {
84
+ @override
85
+ Widget build(BuildContext context) {
86
+ return Scaffold(
87
+ appBar: const DashboardAppBar(),
88
+ body: Column(
89
+ children: [
90
+ const DashboardTabBar(),
91
+ const UserSearchBar(),
92
+ Expanded(child: UserListView()),
93
+ ],
94
+ ),
95
+ );
96
+ }
97
+ }
98
+
99
+ // Each sub-widget is its own class with focused responsibility
100
+ class UserListView extends StatelessWidget {
101
+ @override
102
+ Widget build(BuildContext context) {
103
+ final users = context.watch<UserProvider>().users;
104
+ return ListView.builder(
105
+ itemCount: users.length,
106
+ itemBuilder: (context, index) => UserCard(user: users[index]),
107
+ );
108
+ }
109
+ }
110
+ ```
111
+
112
+ **Detection rule:**
113
+ If a single widget file exceeds 200 lines or its `build()` method exceeds 80 lines, suspect AP-01. If a widget imports HTTP clients, databases, or service classes directly, it is almost certainly a God Widget.
114
+
115
+ ---
116
+
117
+ ### AP-02: Splitting Widgets into Methods Instead of Classes
118
+
119
+ **Also known as:** Helper Method Anti-Pattern, The Private Build Method Trap
120
+ **Frequency:** Very Common
121
+ **Severity:** Medium
122
+ **Detection difficulty:** Moderate
123
+
124
+ **What it looks like:**
125
+
126
+ Developers break up a large `build()` by extracting pieces into private methods like `_buildHeader()`, `_buildBody()`, `_buildFooter()` instead of creating separate widget classes.
127
+
128
+ ```dart
129
+ // BAD: Methods instead of widgets
130
+ class ProfileScreen extends StatefulWidget {
131
+ @override
132
+ _ProfileScreenState createState() => _ProfileScreenState();
133
+ }
134
+
135
+ class _ProfileScreenState extends State<ProfileScreen> {
136
+ String name = 'User';
137
+
138
+ Widget _buildAvatar() {
139
+ return CircleAvatar(child: Text(name[0]));
140
+ }
141
+
142
+ Widget _buildStats() {
143
+ return Row(
144
+ children: [
145
+ Text('Posts: 42'),
146
+ Text('Followers: 100'),
147
+ ],
148
+ );
149
+ }
150
+
151
+ @override
152
+ Widget build(BuildContext context) {
153
+ return Column(
154
+ children: [
155
+ _buildAvatar(),
156
+ _buildStats(), // Rebuilds every time even though data hasn't changed
157
+ ],
158
+ );
159
+ }
160
+ }
161
+ ```
162
+
163
+ **Why developers do it:**
164
+
165
+ It looks cleaner than one massive `build()`. In other frameworks (React class components, Android XML), extracting helper methods is standard practice. IDE refactoring tools offer "Extract Method" as the first option. Developers assume methods and classes are interchangeable for this purpose.
166
+
167
+ **What goes wrong:**
168
+
169
+ When the parent calls `setState`, Flutter rebuilds the entire widget subtree. Methods are re-invoked unconditionally because Flutter has no way to know whether a method's output has changed. In contrast, a separate `StatelessWidget` with `const` constructor can be skipped entirely during rebuilds. This was documented extensively by Iiro Krankka in his widely-cited article "Splitting widgets to methods is a performance anti-pattern" and confirmed by the Flutter team. In complex screens with animations, this can cause visible jank on lower-end devices.
170
+
171
+ **The fix:**
172
+
173
+ ```dart
174
+ // GOOD: Separate widget classes
175
+ class ProfileAvatar extends StatelessWidget {
176
+ final String name;
177
+ const ProfileAvatar({required this.name});
178
+
179
+ @override
180
+ Widget build(BuildContext context) {
181
+ return CircleAvatar(child: Text(name[0]));
182
+ }
183
+ }
184
+
185
+ class ProfileStats extends StatelessWidget {
186
+ const ProfileStats();
187
+
188
+ @override
189
+ Widget build(BuildContext context) {
190
+ return const Row(
191
+ children: [
192
+ Text('Posts: 42'),
193
+ Text('Followers: 100'),
194
+ ],
195
+ );
196
+ }
197
+ }
198
+ ```
199
+
200
+ **Detection rule:**
201
+ If a `State` class contains private methods returning `Widget` (pattern: `Widget _build*(`), suspect AP-02. DCM lint rule `avoid-returning-widgets` catches this automatically.
202
+
203
+ ---
204
+
205
+ ### AP-03: Missing const Constructors
206
+
207
+ **Also known as:** The Rebuild Tax, Const Blindness
208
+ **Frequency:** Very Common
209
+ **Severity:** Medium
210
+ **Detection difficulty:** Easy
211
+
212
+ **What it looks like:**
213
+
214
+ Widgets that could be `const` are instantiated without the `const` keyword, forcing Flutter to rebuild them on every parent rebuild.
215
+
216
+ ```dart
217
+ // BAD: No const, rebuilds every time parent rebuilds
218
+ class MyApp extends StatelessWidget {
219
+ @override
220
+ Widget build(BuildContext context) {
221
+ return MaterialApp(
222
+ home: Scaffold(
223
+ appBar: AppBar(title: Text('My App')), // Not const
224
+ body: Center(
225
+ child: Padding(
226
+ padding: EdgeInsets.all(16.0), // Not const
227
+ child: Text('Hello World'), // Not const
228
+ ),
229
+ ),
230
+ ),
231
+ );
232
+ }
233
+ }
234
+ ```
235
+
236
+ **Why developers do it:**
237
+
238
+ It still compiles and runs without `const`. Many developers coming from other languages are not accustomed to `const` at the expression level. Before Dart 2.12+ lints, there was no automated warning. Some developers believe `const` is only a style preference, not a performance mechanism.
239
+
240
+ **What goes wrong:**
241
+
242
+ Without `const`, Flutter allocates a new widget object on every rebuild and must diff it against the previous tree. With `const`, Flutter recognizes the widget as identical to the previous build via canonical instance comparison and skips the entire subtree. In apps with frequent rebuilds (animations, scrolling, real-time data), this compounds into measurable frame drops. The Dart VM also loses compile-time optimizations: constant folding, pre-allocated memory, and reduced garbage collection pressure.
243
+
244
+ **The fix:**
245
+
246
+ ```dart
247
+ // GOOD: const everywhere possible
248
+ class MyApp extends StatelessWidget {
249
+ const MyApp();
250
+
251
+ @override
252
+ Widget build(BuildContext context) {
253
+ return MaterialApp(
254
+ home: Scaffold(
255
+ appBar: AppBar(title: const Text('My App')),
256
+ body: const Center(
257
+ child: Padding(
258
+ padding: EdgeInsets.all(16.0),
259
+ child: Text('Hello World'),
260
+ ),
261
+ ),
262
+ ),
263
+ );
264
+ }
265
+ }
266
+ ```
267
+
268
+ **Detection rule:**
269
+ Enable `prefer_const_constructors`, `prefer_const_declarations`, and `prefer_const_literals_to_create_immutables` lint rules. Any widget whose constructor arguments are all compile-time constants but is instantiated without `const` is AP-03.
270
+
271
+ ---
272
+
273
+ ### AP-04: setState for Everything
274
+
275
+ **Also known as:** setState Hell, Prop Drilling Nightmare, The Scalability Wall
276
+ **Frequency:** Very Common
277
+ **Severity:** High
278
+ **Detection difficulty:** Moderate
279
+
280
+ **What it looks like:**
281
+
282
+ Using `setState` as the sole state management approach across the entire app, passing callbacks and data through multiple widget layers.
283
+
284
+ ```dart
285
+ // BAD: setState cascading through the entire tree
286
+ class ShoppingApp extends StatefulWidget {
287
+ @override
288
+ _ShoppingAppState createState() => _ShoppingAppState();
289
+ }
290
+
291
+ class _ShoppingAppState extends State<ShoppingApp> {
292
+ List<CartItem> cart = [];
293
+ User? currentUser;
294
+ String selectedCategory = 'all';
295
+ bool isDarkMode = false;
296
+
297
+ void addToCart(Product p) {
298
+ setState(() { cart.add(CartItem(product: p, qty: 1)); });
299
+ }
300
+
301
+ @override
302
+ Widget build(BuildContext context) {
303
+ return MaterialApp(
304
+ home: HomePage(
305
+ cart: cart,
306
+ user: currentUser,
307
+ selectedCategory: selectedCategory,
308
+ isDarkMode: isDarkMode,
309
+ onAddToCart: addToCart, // Drilled 3 levels deep
310
+ onCategoryChange: (c) => setState(() => selectedCategory = c),
311
+ onThemeToggle: () => setState(() => isDarkMode = !isDarkMode),
312
+ ),
313
+ );
314
+ }
315
+ }
316
+ ```
317
+
318
+ **Why developers do it:**
319
+
320
+ `setState` is the first state management tool taught in every Flutter tutorial. It works perfectly for simple apps and prototypes. Adding a state management library (Riverpod, BLoC, Provider) feels like over-engineering for small projects, so developers keep using `setState` as the app grows.
321
+
322
+ **What goes wrong:**
323
+
324
+ - Every `setState` rebuilds the entire subtree from that widget down, even if only one piece of data changed.
325
+ - Prop drilling (passing data through widgets that do not use it) makes the code brittle and hard to refactor.
326
+ - Business logic becomes entangled with UI code, making unit testing impossible without widget tests.
327
+ - When two distant widgets need the same state, the state must be lifted to a common ancestor, often the root, causing the entire app to rebuild on any state change.
328
+ - Teams report that apps using only `setState` beyond 15-20 screens become effectively unmaintainable.
329
+
330
+ **The fix:**
331
+
332
+ Use `setState` only for truly local UI state (a toggle, a text field focus, an animation). Use a state management solution for shared or complex state.
333
+
334
+ ```dart
335
+ // GOOD: Riverpod for shared state, setState for local UI state
336
+ final cartProvider = StateNotifierProvider<CartNotifier, List<CartItem>>(
337
+ (ref) => CartNotifier(),
338
+ );
339
+
340
+ class CartNotifier extends StateNotifier<List<CartItem>> {
341
+ CartNotifier() : super([]);
342
+
343
+ void add(Product p) {
344
+ state = [...state, CartItem(product: p, qty: 1)];
345
+ }
346
+ }
347
+
348
+ // Widget only rebuilds when cart changes
349
+ class CartBadge extends ConsumerWidget {
350
+ const CartBadge();
351
+
352
+ @override
353
+ Widget build(BuildContext context, WidgetRef ref) {
354
+ final count = ref.watch(cartProvider).length;
355
+ return Badge(label: Text('$count'));
356
+ }
357
+ }
358
+ ```
359
+
360
+ **Detection rule:**
361
+ If `setState` is called more than 5 times in a single `State` class, or if callback functions are passed through more than 2 widget levels, suspect AP-04. If `setState` modifies data that conceptually belongs to the application (not the widget), it is AP-04.
362
+
363
+ ---
364
+
365
+ ### AP-05: Forgetting to Dispose Controllers and Streams
366
+
367
+ **Also known as:** The Silent Memory Leak, Zombie Subscriptions, Disposal Amnesia
368
+ **Frequency:** Very Common
369
+ **Severity:** Critical
370
+ **Detection difficulty:** Hard
371
+
372
+ **What it looks like:**
373
+
374
+ Creating `TextEditingController`, `AnimationController`, `ScrollController`, `StreamSubscription`, or `Timer` in a `StatefulWidget` without calling `dispose()` or `cancel()`.
375
+
376
+ ```dart
377
+ // BAD: Controllers never disposed
378
+ class SearchScreen extends StatefulWidget {
379
+ @override
380
+ _SearchScreenState createState() => _SearchScreenState();
381
+ }
382
+
383
+ class _SearchScreenState extends State<SearchScreen>
384
+ with SingleTickerProviderStateMixin {
385
+ final searchController = TextEditingController();
386
+ final scrollController = ScrollController();
387
+ late AnimationController animController;
388
+ late StreamSubscription<LocationData> locationSub;
389
+
390
+ @override
391
+ void initState() {
392
+ super.initState();
393
+ animController = AnimationController(vsync: this, duration: Duration(seconds: 1));
394
+ locationSub = locationService.stream.listen((data) {
395
+ setState(() { /* update location */ });
396
+ });
397
+ }
398
+
399
+ // No dispose() method!
400
+
401
+ @override
402
+ Widget build(BuildContext context) => /* ... */;
403
+ }
404
+ ```
405
+
406
+ **Why developers do it:**
407
+
408
+ The app appears to work fine in development because the garbage collector eventually reclaims some objects, and short debugging sessions do not reveal the leak. Developers forget because `initState` and `dispose` are not symmetrically enforced by the compiler. Stream subscriptions are particularly easy to forget because `listen()` returns the subscription as a value that developers often ignore.
409
+
410
+ **What goes wrong:**
411
+
412
+ - `TextEditingController` and `ScrollController` leak native resources and listeners.
413
+ - `AnimationController` continues ticking after the widget is removed, consuming CPU and eventually crashing with "setState called after dispose."
414
+ - `StreamSubscription` keeps firing callbacks on a disposed widget, causing crashes or corrupted state.
415
+ - In navigation-heavy apps, every push/pop cycle leaks more memory. Users on low-end Android devices report apps slowing to a crawl after 10-15 minutes of use.
416
+ - DCM's blog on memory leaks documents cases where undisposed stream subscriptions caused apps to consume 500MB+ of memory within minutes of normal use.
417
+
418
+ **The fix:**
419
+
420
+ ```dart
421
+ // GOOD: Always dispose in dispose()
422
+ class _SearchScreenState extends State<SearchScreen>
423
+ with SingleTickerProviderStateMixin {
424
+ final searchController = TextEditingController();
425
+ final scrollController = ScrollController();
426
+ late AnimationController animController;
427
+ late StreamSubscription<LocationData> locationSub;
428
+
429
+ @override
430
+ void initState() {
431
+ super.initState();
432
+ animController = AnimationController(vsync: this, duration: Duration(seconds: 1));
433
+ locationSub = locationService.stream.listen((data) {
434
+ if (mounted) setState(() { /* update */ });
435
+ });
436
+ }
437
+
438
+ @override
439
+ void dispose() {
440
+ searchController.dispose();
441
+ scrollController.dispose();
442
+ animController.dispose();
443
+ locationSub.cancel();
444
+ super.dispose();
445
+ }
446
+
447
+ @override
448
+ Widget build(BuildContext context) => /* ... */;
449
+ }
450
+ ```
451
+
452
+ **Detection rule:**
453
+ If a `State` class creates a `TextEditingController`, `AnimationController`, `ScrollController`, `FocusNode`, `StreamSubscription`, or `Timer` in `initState` or field initialization, but has no `dispose()` method (or the `dispose()` method does not reference that object), it is AP-05. Lint rule: `close_sinks`, `cancel_subscriptions`.
454
+
455
+ ---
456
+
457
+ ### AP-06: Blocking the UI Thread with Heavy Computation
458
+
459
+ **Also known as:** Main Thread Abuse, The Jank Generator, Synchronous Sin
460
+ **Frequency:** Common
461
+ **Severity:** Critical
462
+ **Detection difficulty:** Moderate
463
+
464
+ **What it looks like:**
465
+
466
+ Running expensive computation, large JSON parsing, image processing, or file I/O directly in the `build()` method or in response to user interaction on the main isolate.
467
+
468
+ ```dart
469
+ // BAD: Heavy computation on main thread
470
+ class ReportScreen extends StatefulWidget {
471
+ @override
472
+ _ReportScreenState createState() => _ReportScreenState();
473
+ }
474
+
475
+ class _ReportScreenState extends State<ReportScreen> {
476
+ List<ChartData> chartData = [];
477
+
478
+ void generateReport() {
479
+ // This blocks the UI for 2-3 seconds
480
+ final rawData = loadCsvSync('large_dataset.csv'); // 50MB file
481
+ final parsed = rawData.split('\n').map((line) {
482
+ final cols = line.split(',');
483
+ return ChartData(
484
+ x: double.parse(cols[0]),
485
+ y: double.parse(cols[1]),
486
+ label: cols[2],
487
+ );
488
+ }).toList();
489
+
490
+ // Sort, filter, aggregate -- all on main thread
491
+ parsed.sort((a, b) => a.x.compareTo(b.x));
492
+ setState(() { chartData = parsed; });
493
+ }
494
+
495
+ @override
496
+ Widget build(BuildContext context) => /* ... */;
497
+ }
498
+ ```
499
+
500
+ **Why developers do it:**
501
+
502
+ Dart's `async`/`await` syntax looks like it solves concurrency, but `async` in Dart is cooperative concurrency on a single thread, not parallelism. A `Future` still runs on the main isolate. Developers assume `await` means "run in background" when it actually means "yield the event loop but still use the same thread." The distinction between concurrency and parallelism is not well understood.
503
+
504
+ **What goes wrong:**
505
+
506
+ - Flutter targets 60fps (16ms per frame). Any computation exceeding 16ms causes dropped frames visible as jank.
507
+ - On low-end Android devices, even 5ms of synchronous work in `build()` can cause visible stutter.
508
+ - Users perceive the app as frozen; if the main thread is blocked for more than 5 seconds on Android, the OS shows an ANR (Application Not Responding) dialog.
509
+ - Flutter GitHub issue #121720 documents cases where even isolate spawning can briefly block UI if not managed correctly.
510
+
511
+ **The fix:**
512
+
513
+ Use `Isolate.run()` (Dart 2.19+) or `compute()` for CPU-intensive work.
514
+
515
+ ```dart
516
+ // GOOD: Heavy work in a separate isolate
517
+ Future<void> generateReport() async {
518
+ setState(() { isLoading = true; });
519
+
520
+ final chartData = await Isolate.run(() {
521
+ final rawData = File('large_dataset.csv').readAsStringSync();
522
+ final parsed = rawData.split('\n').map((line) {
523
+ final cols = line.split(',');
524
+ return ChartData(
525
+ x: double.parse(cols[0]),
526
+ y: double.parse(cols[1]),
527
+ label: cols[2],
528
+ );
529
+ }).toList();
530
+ parsed.sort((a, b) => a.x.compareTo(b.x));
531
+ return parsed;
532
+ });
533
+
534
+ setState(() { this.chartData = chartData; isLoading = false; });
535
+ }
536
+ ```
537
+
538
+ **Detection rule:**
539
+ If `build()` contains loops processing more than a trivial number of items, file I/O, JSON parsing of unbounded data, or sorting of large collections, suspect AP-06. If a synchronous method is called that could take >16ms, it is AP-06. Look for `readAsStringSync`, `jsonDecode` on large payloads, or nested loops inside widget methods.
540
+
541
+ ---
542
+
543
+ ### AP-07: Excessive GlobalKey Usage
544
+
545
+ **Also known as:** GlobalKey Overload, The Expensive Identity
546
+ **Frequency:** Common
547
+ **Severity:** Medium
548
+ **Detection difficulty:** Moderate
549
+
550
+ **What it looks like:**
551
+
552
+ Using `GlobalKey` for tasks that could be accomplished with `ValueKey`, `UniqueKey`, or no key at all. Creating `GlobalKey` instances inside `build()`.
553
+
554
+ ```dart
555
+ // BAD: GlobalKey created in build -- destroys and recreates subtree every build
556
+ class MyWidget extends StatelessWidget {
557
+ @override
558
+ Widget build(BuildContext context) {
559
+ return Form(
560
+ key: GlobalKey<FormState>(), // NEW key every build!
561
+ child: Column(/* ... */),
562
+ );
563
+ }
564
+ }
565
+
566
+ // BAD: GlobalKey used just to read a value
567
+ class ParentWidget extends StatefulWidget {
568
+ @override
569
+ _ParentWidgetState createState() => _ParentWidgetState();
570
+ }
571
+
572
+ class _ParentWidgetState extends State<ParentWidget> {
573
+ final _childKey = GlobalKey<_ChildWidgetState>();
574
+
575
+ void doSomething() {
576
+ // Reaching into child state via GlobalKey
577
+ _childKey.currentState?.someValue;
578
+ }
579
+
580
+ @override
581
+ Widget build(BuildContext context) {
582
+ return ChildWidget(key: _childKey);
583
+ }
584
+ }
585
+ ```
586
+
587
+ **Why developers do it:**
588
+
589
+ `GlobalKey` provides direct access to a widget's `State`, which feels convenient for cross-widget communication. Tutorials for `Form` validation use `GlobalKey<FormState>()` prominently, leading developers to assume GlobalKey is the standard approach for all inter-widget communication.
590
+
591
+ **What goes wrong:**
592
+
593
+ - Creating `GlobalKey` in `build()` throws away the entire subtree state on every rebuild, as documented in Flutter's official API docs. A `GestureDetector` in that subtree loses ongoing gesture tracking. Text fields lose their content.
594
+ - Each `GlobalKey` is registered in a global lookup table, increasing memory consumption linearly with the number of keys.
595
+ - Flutter issue #35730 documents the performance overhead: GlobalKeys are more expensive than other keys because they require global uniqueness checks.
596
+ - Using GlobalKey to access child state creates tight coupling and makes refactoring dangerous.
597
+
598
+ **The fix:**
599
+
600
+ Instantiate GlobalKey in `initState` or as a field, never in `build()`. Prefer callbacks, state management, or `ValueKey`/`UniqueKey` where GlobalKey is not strictly needed.
601
+
602
+ ```dart
603
+ // GOOD: GlobalKey created once, outside build
604
+ class _MyFormState extends State<MyForm> {
605
+ final _formKey = GlobalKey<FormState>(); // Created once
606
+
607
+ @override
608
+ Widget build(BuildContext context) {
609
+ return Form(
610
+ key: _formKey,
611
+ child: Column(/* ... */),
612
+ );
613
+ }
614
+ }
615
+
616
+ // BETTER: Use callbacks instead of reaching into child state
617
+ class ParentWidget extends StatefulWidget {
618
+ @override
619
+ _ParentWidgetState createState() => _ParentWidgetState();
620
+ }
621
+
622
+ class _ParentWidgetState extends State<ParentWidget> {
623
+ String? childValue;
624
+
625
+ @override
626
+ Widget build(BuildContext context) {
627
+ return ChildWidget(
628
+ onValueChanged: (v) => setState(() => childValue = v),
629
+ );
630
+ }
631
+ }
632
+ ```
633
+
634
+ **Detection rule:**
635
+ If `GlobalKey()` appears inside a `build()` method, it is always AP-07. If `GlobalKey` is used to access child state and a callback pattern could replace it, it is AP-07. Count GlobalKeys per screen: more than 2-3 is a code smell.
636
+
637
+ ---
638
+
639
+ ### AP-08: Missing Keys in Lists
640
+
641
+ **Also known as:** The Phantom Reorder, State Mismatch Bug, Keyless Lists
642
+ **Frequency:** Common
643
+ **Severity:** High
644
+ **Detection difficulty:** Hard
645
+
646
+ **What it looks like:**
647
+
648
+ Building lists of stateful widgets without providing keys, or using the list index as the key.
649
+
650
+ ```dart
651
+ // BAD: No keys -- state gets confused when items reorder
652
+ ListView.builder(
653
+ itemCount: todos.length,
654
+ itemBuilder: (context, index) {
655
+ return TodoTile(todo: todos[index]); // No key!
656
+ },
657
+ );
658
+
659
+ // ALSO BAD: Index as key -- same problem when items are removed/reordered
660
+ ListView.builder(
661
+ itemCount: todos.length,
662
+ itemBuilder: (context, index) {
663
+ return TodoTile(
664
+ key: ValueKey(index), // Index changes when items reorder!
665
+ todo: todos[index],
666
+ );
667
+ },
668
+ );
669
+ ```
670
+
671
+ **Why developers do it:**
672
+
673
+ Keys are not required by the compiler, and lists appear to work correctly until items are reordered, deleted, or inserted. The bug manifests as "the checkbox state moved to the wrong item," which developers blame on their state management rather than missing keys.
674
+
675
+ **What goes wrong:**
676
+
677
+ - Flutter matches old and new widgets by position in the list. When an item is removed from the middle, all subsequent widgets inherit the state of their predecessor.
678
+ - Checkboxes appear checked on wrong items, text fields show wrong content, animations play on wrong elements.
679
+ - This is one of the most frequently reported "unexplainable bugs" in the Flutter community, as noted on FlutterClutter and multiple Stack Overflow threads.
680
+ - Using index as key is equally broken: if item at index 2 is deleted, the old index-3 item now has key 2 and inherits index-2's state.
681
+
682
+ **The fix:**
683
+
684
+ ```dart
685
+ // GOOD: Stable, unique key per item
686
+ ListView.builder(
687
+ itemCount: todos.length,
688
+ itemBuilder: (context, index) {
689
+ return TodoTile(
690
+ key: ValueKey(todos[index].id), // Stable unique identifier
691
+ todo: todos[index],
692
+ );
693
+ },
694
+ );
695
+ ```
696
+
697
+ **Detection rule:**
698
+ If a `ListView.builder`, `Column`, or `Row` renders stateful widgets without a `key` parameter, suspect AP-08. If `ValueKey(index)` is used where the list supports reordering or deletion, it is AP-08.
699
+
700
+ ---
701
+
702
+ ### AP-09: Using BuildContext Across Async Gaps
703
+
704
+ **Also known as:** Stale Context, The Mounted Check Omission, Context After Dispose
705
+ **Frequency:** Very Common
706
+ **Severity:** Critical
707
+ **Detection difficulty:** Moderate
708
+
709
+ **What it looks like:**
710
+
711
+ Using `BuildContext` after an `await` call without checking if the widget is still mounted.
712
+
713
+ ```dart
714
+ // BAD: Context used after async gap
715
+ Future<void> _submit() async {
716
+ final response = await api.submitForm(data);
717
+
718
+ // Widget might be disposed by now!
719
+ ScaffoldMessenger.of(context).showSnackBar(
720
+ SnackBar(content: Text('Success!')),
721
+ );
722
+ Navigator.of(context).pushReplacementNamed('/home');
723
+ }
724
+ ```
725
+
726
+ **Why developers do it:**
727
+
728
+ It works most of the time because the widget is usually still mounted when the `Future` completes. The bug only surfaces when users navigate away during the async operation (press back while a form is submitting), which is a race condition that rarely occurs during development but happens constantly in production.
729
+
730
+ **What goes wrong:**
731
+
732
+ - `BuildContext` references a widget that no longer exists in the tree, leading to "Looking up a deactivated widget's ancestor is unsafe" errors.
733
+ - On navigation-heavy apps, this causes crashes that are difficult to reproduce because they depend on timing.
734
+ - The Dart linter rule `use_build_context_synchronously` was created specifically because this pattern caused so many production crashes.
735
+ - Flutter GitHub issues #110694 and #122953 document extensive community frustration with this pattern.
736
+
737
+ **The fix:**
738
+
739
+ ```dart
740
+ // GOOD: Check mounted before using context after await
741
+ Future<void> _submit() async {
742
+ final response = await api.submitForm(data);
743
+
744
+ if (!mounted) return; // Widget was disposed during await
745
+
746
+ ScaffoldMessenger.of(context).showSnackBar(
747
+ SnackBar(content: Text('Success!')),
748
+ );
749
+ Navigator.of(context).pushReplacementNamed('/home');
750
+ }
751
+
752
+ // BETTER: Use a callback pattern or state management
753
+ // so the widget doesn't need context after the async gap
754
+ ```
755
+
756
+ **Detection rule:**
757
+ If any method calls `await` and then references `context` (including `Navigator.of(context)`, `ScaffoldMessenger.of(context)`, `Theme.of(context)`, `MediaQuery.of(context)`) without a `mounted` check between the `await` and the context usage, it is AP-09. Lint rule: `use_build_context_synchronously`.
758
+
759
+ ---
760
+
761
+ ### AP-10: FutureBuilder/StreamBuilder Without Handling All States
762
+
763
+ **Also known as:** The Missing Loading Screen, Partial Snapshot Handling, Optimistic Builder
764
+ **Frequency:** Very Common
765
+ **Severity:** Medium
766
+ **Detection difficulty:** Easy
767
+
768
+ **What it looks like:**
769
+
770
+ Using `FutureBuilder` or `StreamBuilder` but only checking for the "done with data" case, ignoring loading, error, and null-data states.
771
+
772
+ ```dart
773
+ // BAD: Only handles success case
774
+ FutureBuilder<User>(
775
+ future: fetchUser(),
776
+ builder: (context, snapshot) {
777
+ // What about loading? Errors? Null data?
778
+ return Text(snapshot.data!.name); // Crashes if data is null
779
+ },
780
+ );
781
+ ```
782
+
783
+ **Why developers do it:**
784
+
785
+ During development, the API is fast and always succeeds. Developers focus on the happy path because that is what they see in the emulator. The `snapshot.data!` force-unwrap suppresses the null warning, making the code "work" in dev.
786
+
787
+ **What goes wrong:**
788
+
789
+ - `snapshot.data` is null during `ConnectionState.waiting`, causing null-pointer crashes on slow networks.
790
+ - API errors produce `snapshot.hasError == true` but no error UI is shown; users see a blank screen or crash.
791
+ - On rebuilds, the `FutureBuilder` briefly returns to `ConnectionState.waiting` before the data arrives again, causing screen flicker.
792
+ - A common secondary bug: creating the Future inside `build()` causes the request to fire on every rebuild (see AP-14).
793
+
794
+ **The fix:**
795
+
796
+ ```dart
797
+ // GOOD: Handle all states
798
+ FutureBuilder<User>(
799
+ future: _userFuture, // Created in initState, not build!
800
+ builder: (context, snapshot) {
801
+ if (snapshot.connectionState == ConnectionState.waiting) {
802
+ return const Center(child: CircularProgressIndicator());
803
+ }
804
+ if (snapshot.hasError) {
805
+ return Center(child: Text('Error: ${snapshot.error}'));
806
+ }
807
+ if (!snapshot.hasData) {
808
+ return const Center(child: Text('No user found'));
809
+ }
810
+ final user = snapshot.data!;
811
+ return Text(user.name);
812
+ },
813
+ );
814
+ ```
815
+
816
+ **Detection rule:**
817
+ If a `FutureBuilder` or `StreamBuilder` builder function does not contain checks for `ConnectionState.waiting`, `snapshot.hasError`, and `snapshot.hasData`, it is AP-10. If `snapshot.data!` is used without a preceding null/error check, it is AP-10.
818
+
819
+ ---
820
+
821
+ ### AP-11: Hardcoded Dimensions
822
+
823
+ **Also known as:** Pixel-Perfect Fragility, The Single-Device Design, Magic Numbers
824
+ **Frequency:** Very Common
825
+ **Severity:** Medium
826
+ **Detection difficulty:** Easy
827
+
828
+ **What it looks like:**
829
+
830
+ Using fixed pixel values for widths, heights, padding, and font sizes instead of responsive sizing.
831
+
832
+ ```dart
833
+ // BAD: Hardcoded dimensions
834
+ Container(
835
+ width: 375, // iPhone 8 width
836
+ height: 812, // iPhone X height
837
+ padding: EdgeInsets.only(top: 44), // iPhone X safe area, hardcoded
838
+ child: Column(
839
+ children: [
840
+ SizedBox(height: 200), // Fixed header height
841
+ Container(
842
+ width: 340,
843
+ height: 50,
844
+ child: TextField(),
845
+ ),
846
+ ],
847
+ ),
848
+ );
849
+ ```
850
+
851
+ **Why developers do it:**
852
+
853
+ The app looks perfect on the developer's test device. Flutter's hot reload makes it easy to tweak pixels until it looks right on one screen. Designers hand off specs in exact pixel values. Using `MediaQuery` or `LayoutBuilder` requires understanding constraints, which adds complexity.
854
+
855
+ **What goes wrong:**
856
+
857
+ - Overflow errors on smaller screens (the yellow-and-black striped bar that every Flutter developer recognizes).
858
+ - Wasted space on tablets and foldables.
859
+ - Text truncation on devices with larger system font sizes.
860
+ - Landscape mode becomes completely broken.
861
+ - Apps that look fine on a Pixel 6 break on Samsung Galaxy Fold, iPad, or budget Android devices with unusual aspect ratios.
862
+
863
+ **The fix:**
864
+
865
+ ```dart
866
+ // GOOD: Responsive dimensions
867
+ LayoutBuilder(
868
+ builder: (context, constraints) {
869
+ return Padding(
870
+ padding: EdgeInsets.symmetric(
871
+ horizontal: constraints.maxWidth * 0.05,
872
+ ),
873
+ child: Column(
874
+ children: [
875
+ SizedBox(height: constraints.maxHeight * 0.1),
876
+ ConstrainedBox(
877
+ constraints: BoxConstraints(maxWidth: 600),
878
+ child: const TextField(),
879
+ ),
880
+ ],
881
+ ),
882
+ );
883
+ },
884
+ );
885
+
886
+ // Also: use MediaQuery.paddingOf(context) for safe area
887
+ // Also: use Flexible/Expanded instead of fixed SizedBox
888
+ ```
889
+
890
+ **Detection rule:**
891
+ If a `Container`, `SizedBox`, `Padding`, or `Positioned` uses literal numeric values greater than 100 for width/height, suspect AP-11. If `EdgeInsets` uses literal values greater than 32, verify they are intentional. Exception: small spacing values (4, 8, 16) are usually fine.
892
+
893
+ ---
894
+
895
+ ### AP-12: Rebuilding Entire Widget Trees Unnecessarily
896
+
897
+ **Also known as:** The Rebuild Avalanche, Unscoped State, Overly Broad setState
898
+ **Frequency:** Very Common
899
+ **Severity:** High
900
+ **Detection difficulty:** Hard
901
+
902
+ **What it looks like:**
903
+
904
+ A `setState` call or state change triggers a rebuild of the entire screen when only a small portion of the UI actually changed.
905
+
906
+ ```dart
907
+ // BAD: Entire screen rebuilds when only the counter changes
908
+ class DashboardScreen extends StatefulWidget {
909
+ @override
910
+ _DashboardScreenState createState() => _DashboardScreenState();
911
+ }
912
+
913
+ class _DashboardScreenState extends State<DashboardScreen> {
914
+ int notificationCount = 0;
915
+
916
+ @override
917
+ Widget build(BuildContext context) {
918
+ return Scaffold(
919
+ appBar: AppBar(
920
+ title: Text('Dashboard'),
921
+ actions: [
922
+ Badge(
923
+ label: Text('$notificationCount'), // Only this changes
924
+ child: Icon(Icons.notifications),
925
+ ),
926
+ ],
927
+ ),
928
+ body: Column(
929
+ children: [
930
+ ExpensiveChart(), // Rebuilds unnecessarily
931
+ ExpensiveUserList(), // Rebuilds unnecessarily
932
+ ExpensiveActivityFeed(),// Rebuilds unnecessarily
933
+ ],
934
+ ),
935
+ floatingActionButton: FloatingActionButton(
936
+ onPressed: () => setState(() => notificationCount++),
937
+ ),
938
+ );
939
+ }
940
+ }
941
+ ```
942
+
943
+ **Why developers do it:**
944
+
945
+ `setState` is a blunt instrument -- it marks the entire `State` as dirty. Developers do not realize that every child widget's `build()` runs again. Flutter DevTools is not always used during development, so the rebuild count goes unnoticed.
946
+
947
+ **What goes wrong:**
948
+
949
+ - In the example above, every tap rebuilds `ExpensiveChart`, `ExpensiveUserList`, and `ExpensiveActivityFeed` even though their data has not changed.
950
+ - On screens with heavy widgets (charts, maps, video players), this causes visible stutter.
951
+ - Community reports document apps dropping from 60fps to 15fps due to a single poorly scoped `setState` on a complex dashboard.
952
+ - Calling `MediaQuery.of(context)` in the root widget creates an implicit dependency that rebuilds the entire tree when the keyboard opens or orientation changes.
953
+
954
+ **The fix:**
955
+
956
+ Push state down to the smallest widget that needs it, or use granular state management.
957
+
958
+ ```dart
959
+ // GOOD: Only the badge rebuilds
960
+ class NotificationBadge extends StatelessWidget {
961
+ const NotificationBadge();
962
+
963
+ @override
964
+ Widget build(BuildContext context) {
965
+ final count = context.watch<NotificationProvider>().count;
966
+ return Badge(
967
+ label: Text('$count'),
968
+ child: const Icon(Icons.notifications),
969
+ );
970
+ }
971
+ }
972
+
973
+ // Dashboard no longer rebuilds its expensive children
974
+ class DashboardScreen extends StatelessWidget {
975
+ const DashboardScreen();
976
+
977
+ @override
978
+ Widget build(BuildContext context) {
979
+ return Scaffold(
980
+ appBar: AppBar(
981
+ title: const Text('Dashboard'),
982
+ actions: [const NotificationBadge()],
983
+ ),
984
+ body: const Column(
985
+ children: [
986
+ ExpensiveChart(),
987
+ ExpensiveUserList(),
988
+ ExpensiveActivityFeed(),
989
+ ],
990
+ ),
991
+ );
992
+ }
993
+ }
994
+ ```
995
+
996
+ **Detection rule:**
997
+ If `setState` modifies only one variable but the `build()` method constructs 5+ widgets, suspect AP-12. Use Flutter DevTools Rebuild Stats to verify: if widgets with unchanged data show rebuild counts >1, it is AP-12.
998
+
999
+ ---
1000
+
1001
+ ### AP-13: Mixing Business Logic in Widgets
1002
+
1003
+ **Also known as:** Fat Widget, Logic Leak, The Untestable Screen
1004
+ **Frequency:** Very Common
1005
+ **Severity:** High
1006
+ **Detection difficulty:** Moderate
1007
+
1008
+ **What it looks like:**
1009
+
1010
+ API calls, data transformation, validation logic, and business rules living directly inside widget classes.
1011
+
1012
+ ```dart
1013
+ // BAD: Business logic embedded in widget
1014
+ class OrderScreen extends StatefulWidget {
1015
+ @override
1016
+ _OrderScreenState createState() => _OrderScreenState();
1017
+ }
1018
+
1019
+ class _OrderScreenState extends State<OrderScreen> {
1020
+ Future<void> placeOrder() async {
1021
+ // Validation logic in widget
1022
+ if (cart.isEmpty) { showError('Cart is empty'); return; }
1023
+ if (cart.total < 10.0) { showError('Minimum order: \$10'); return; }
1024
+
1025
+ // Price calculation in widget
1026
+ final subtotal = cart.items.fold(0.0, (sum, i) => sum + i.price * i.qty);
1027
+ final tax = subtotal * 0.08;
1028
+ final shipping = subtotal > 50 ? 0 : 5.99;
1029
+ final total = subtotal + tax + shipping;
1030
+
1031
+ // API call in widget
1032
+ final response = await http.post(
1033
+ Uri.parse('https://api.example.com/orders'),
1034
+ body: jsonEncode({'items': cart.items, 'total': total}),
1035
+ );
1036
+
1037
+ // Navigation in response to API
1038
+ if (response.statusCode == 201) {
1039
+ Navigator.pushNamed(context, '/confirmation');
1040
+ }
1041
+ }
1042
+
1043
+ @override
1044
+ Widget build(BuildContext context) => /* ... */;
1045
+ }
1046
+ ```
1047
+
1048
+ **Why developers do it:**
1049
+
1050
+ It is the fastest way to get features working. During prototyping, separating layers feels like unnecessary abstraction. Small apps genuinely do not need separation. The problem is that developers never go back to refactor once the app grows.
1051
+
1052
+ **What goes wrong:**
1053
+
1054
+ - Business rules (minimum order amount, tax calculation, shipping thresholds) cannot be unit tested without instantiating a widget.
1055
+ - Changing the API endpoint requires editing a UI file.
1056
+ - The same business logic gets duplicated across multiple screens (order confirmation, order history, admin dashboard all recalculate totals).
1057
+ - When business rules change (tax rate update), developers must find and update every widget that embedded the old rate.
1058
+ - Flutter's official architecture guide explicitly warns against this: "Views should not contain any business logic."
1059
+
1060
+ **The fix:**
1061
+
1062
+ ```dart
1063
+ // GOOD: Separated layers
1064
+ // domain/order_service.dart
1065
+ class OrderService {
1066
+ final ApiClient _api;
1067
+ OrderService(this._api);
1068
+
1069
+ double calculateTotal(Cart cart) {
1070
+ final subtotal = cart.items.fold(0.0, (sum, i) => sum + i.price * i.qty);
1071
+ final tax = subtotal * 0.08;
1072
+ final shipping = subtotal > 50 ? 0.0 : 5.99;
1073
+ return subtotal + tax + shipping;
1074
+ }
1075
+
1076
+ String? validate(Cart cart) {
1077
+ if (cart.isEmpty) return 'Cart is empty';
1078
+ if (cart.total < 10.0) return 'Minimum order: \$10';
1079
+ return null;
1080
+ }
1081
+
1082
+ Future<Order> placeOrder(Cart cart) async {
1083
+ final total = calculateTotal(cart);
1084
+ return _api.post('/orders', {'items': cart.items, 'total': total});
1085
+ }
1086
+ }
1087
+
1088
+ // Widget is now thin -- only UI concerns
1089
+ class OrderScreen extends ConsumerWidget {
1090
+ @override
1091
+ Widget build(BuildContext context, WidgetRef ref) {
1092
+ return ElevatedButton(
1093
+ onPressed: () async {
1094
+ final service = ref.read(orderServiceProvider);
1095
+ final error = service.validate(cart);
1096
+ if (error != null) { showError(error); return; }
1097
+ await service.placeOrder(cart);
1098
+ if (context.mounted) Navigator.pushNamed(context, '/confirmation');
1099
+ },
1100
+ child: const Text('Place Order'),
1101
+ );
1102
+ }
1103
+ }
1104
+ ```
1105
+
1106
+ **Detection rule:**
1107
+ If a widget class imports `dart:convert`, `package:http`, or a database package, suspect AP-13. If a widget method contains conditional business logic (price calculation, validation rules, permission checks), it is AP-13.
1108
+
1109
+ ---
1110
+
1111
+ ### AP-14: Creating Futures/Streams Inside build()
1112
+
1113
+ **Also known as:** The Infinite Request Loop, Build-Time Side Effects
1114
+ **Frequency:** Common
1115
+ **Severity:** Critical
1116
+ **Detection difficulty:** Moderate
1117
+
1118
+ **What it looks like:**
1119
+
1120
+ Calling an API, creating a `Future`, or opening a `Stream` inside the `build()` method, often inside a `FutureBuilder` or `StreamBuilder`.
1121
+
1122
+ ```dart
1123
+ // BAD: API called on every rebuild
1124
+ class UserProfile extends StatelessWidget {
1125
+ @override
1126
+ Widget build(BuildContext context) {
1127
+ return FutureBuilder<User>(
1128
+ future: fetchUser(), // Called on EVERY rebuild!
1129
+ builder: (context, snapshot) {
1130
+ if (snapshot.hasData) return Text(snapshot.data!.name);
1131
+ return CircularProgressIndicator();
1132
+ },
1133
+ );
1134
+ }
1135
+ }
1136
+ ```
1137
+
1138
+ **Why developers do it:**
1139
+
1140
+ `FutureBuilder` accepts a `future` parameter, so developers naturally pass the function call directly. It works on the first render. The problem only appears when the widget rebuilds (parent setState, keyboard open/close, navigation) and fires the request again.
1141
+
1142
+ **What goes wrong:**
1143
+
1144
+ - Every rebuild triggers a new network request, potentially hundreds per second during animations or scrolling.
1145
+ - The UI flickers between loading and loaded states as each new request starts.
1146
+ - API rate limits are hit. Server costs spike.
1147
+ - The Flutter `FutureBuilder` class documentation explicitly warns: "The future must not be created during the State.build or StatelessWidget.build method call."
1148
+
1149
+ **The fix:**
1150
+
1151
+ ```dart
1152
+ // GOOD: Future created once in initState
1153
+ class UserProfile extends StatefulWidget {
1154
+ @override
1155
+ _UserProfileState createState() => _UserProfileState();
1156
+ }
1157
+
1158
+ class _UserProfileState extends State<UserProfile> {
1159
+ late final Future<User> _userFuture;
1160
+
1161
+ @override
1162
+ void initState() {
1163
+ super.initState();
1164
+ _userFuture = fetchUser(); // Created once
1165
+ }
1166
+
1167
+ @override
1168
+ Widget build(BuildContext context) {
1169
+ return FutureBuilder<User>(
1170
+ future: _userFuture, // Same Future instance on every rebuild
1171
+ builder: (context, snapshot) {
1172
+ if (snapshot.connectionState == ConnectionState.waiting) {
1173
+ return const CircularProgressIndicator();
1174
+ }
1175
+ if (snapshot.hasError) return Text('Error: ${snapshot.error}');
1176
+ return Text(snapshot.data!.name);
1177
+ },
1178
+ );
1179
+ }
1180
+ }
1181
+ ```
1182
+
1183
+ **Detection rule:**
1184
+ If a `FutureBuilder` or `StreamBuilder` has its `future:` or `stream:` parameter set to a function call (not a variable reference), it is AP-14. Pattern: `FutureBuilder(future: someFunctionCall(),` inside a `build()` method.
1185
+
1186
+ ---
1187
+
1188
+ ### AP-15: Overusing StatefulWidget
1189
+
1190
+ **Also known as:** Stateful by Default, The Unnecessary Lifecycle
1191
+ **Frequency:** Common
1192
+ **Severity:** Low
1193
+ **Detection difficulty:** Easy
1194
+
1195
+ **What it looks like:**
1196
+
1197
+ Using `StatefulWidget` for widgets that have no mutable state, or that receive all their data from parent widgets or state management.
1198
+
1199
+ ```dart
1200
+ // BAD: StatefulWidget with no mutable state
1201
+ class UserCard extends StatefulWidget {
1202
+ final User user;
1203
+ const UserCard({required this.user});
1204
+
1205
+ @override
1206
+ _UserCardState createState() => _UserCardState();
1207
+ }
1208
+
1209
+ class _UserCardState extends State<UserCard> {
1210
+ // No state variables!
1211
+ // No initState doing anything!
1212
+ // No dispose needed!
1213
+
1214
+ @override
1215
+ Widget build(BuildContext context) {
1216
+ return Card(
1217
+ child: ListTile(
1218
+ title: Text(widget.user.name),
1219
+ subtitle: Text(widget.user.email),
1220
+ ),
1221
+ );
1222
+ }
1223
+ }
1224
+ ```
1225
+
1226
+ **Why developers do it:**
1227
+
1228
+ Beginners are unsure whether they will need state later, so they default to `StatefulWidget` "just in case." Some tutorials use `StatefulWidget` for all examples. IDE templates sometimes generate `StatefulWidget` scaffolds.
1229
+
1230
+ **What goes wrong:**
1231
+
1232
+ - `StatefulWidget` allocates a `State` object with its own lifecycle, consuming more memory than `StatelessWidget`.
1233
+ - It signals to other developers that this widget has mutable state, misleading code reviewers.
1234
+ - It prevents the widget from being `const`, eliminating Flutter's rebuild optimization.
1235
+ - While the performance impact per widget is small, in a list of hundreds of items (e.g., a chat app), the cumulative overhead is measurable.
1236
+
1237
+ **The fix:**
1238
+
1239
+ ```dart
1240
+ // GOOD: StatelessWidget when there's no state
1241
+ class UserCard extends StatelessWidget {
1242
+ final User user;
1243
+ const UserCard({required this.user});
1244
+
1245
+ @override
1246
+ Widget build(BuildContext context) {
1247
+ return Card(
1248
+ child: ListTile(
1249
+ title: Text(user.name),
1250
+ subtitle: Text(user.email),
1251
+ ),
1252
+ );
1253
+ }
1254
+ }
1255
+ ```
1256
+
1257
+ **Detection rule:**
1258
+ If a `State` class has no mutable fields (no `late` variables, no non-final fields), no `initState` override, and no `dispose` override, the widget should be `StatelessWidget`. This is AP-15.
1259
+
1260
+ ---
1261
+
1262
+ ### AP-16: Abusing the Null Check Operator (!)
1263
+
1264
+ **Also known as:** Bang Operator Abuse, Force Unwrap Everywhere, The Lazy Null Fix
1265
+ **Frequency:** Very Common
1266
+ **Severity:** High
1267
+ **Detection difficulty:** Easy
1268
+
1269
+ **What it looks like:**
1270
+
1271
+ Using the `!` operator to silence null safety warnings instead of handling nullable types properly.
1272
+
1273
+ ```dart
1274
+ // BAD: Force unwrapping everywhere
1275
+ class UserProfile extends StatelessWidget {
1276
+ final User? user;
1277
+ const UserProfile({this.user});
1278
+
1279
+ @override
1280
+ Widget build(BuildContext context) {
1281
+ return Column(
1282
+ children: [
1283
+ Text(user!.name), // Crashes if user is null
1284
+ Text(user!.email!), // Double crash potential
1285
+ Text(user!.address!.city!), // Triple crash potential
1286
+ Image.network(user!.avatar!),
1287
+ ],
1288
+ );
1289
+ }
1290
+ }
1291
+
1292
+ // BAD: Using ! to "fix" migration warnings
1293
+ String getUserName(Map<String, dynamic> json) {
1294
+ return json['name']! as String; // Crashes on missing key
1295
+ }
1296
+ ```
1297
+
1298
+ **Why developers do it:**
1299
+
1300
+ The `!` operator is the fastest way to make a null-safety error disappear. During the null safety migration, the `dart migrate` tool sometimes inserted `!` in places where proper null handling was needed. Developers see `!` used in official examples (e.g., `snapshot.data!` in FutureBuilder) and generalize its use.
1301
+
1302
+ **What goes wrong:**
1303
+
1304
+ - Every `!` is an implicit assertion that throws a runtime exception if the value is null, converting a compile-time safety feature into a runtime crash.
1305
+ - In production, this manifests as `Null check operator used on a null value` -- one of the most common Flutter crash reports.
1306
+ - The crash message gives no context about which `!` caused it when multiple are on the same line.
1307
+ - It defeats the entire purpose of Dart's sound null safety, which was designed to eliminate null pointer exceptions at compile time.
1308
+
1309
+ **The fix:**
1310
+
1311
+ ```dart
1312
+ // GOOD: Proper null handling
1313
+ class UserProfile extends StatelessWidget {
1314
+ final User? user;
1315
+ const UserProfile({this.user});
1316
+
1317
+ @override
1318
+ Widget build(BuildContext context) {
1319
+ final currentUser = user;
1320
+ if (currentUser == null) {
1321
+ return const Center(child: Text('No user data'));
1322
+ }
1323
+
1324
+ return Column(
1325
+ children: [
1326
+ Text(currentUser.name),
1327
+ Text(currentUser.email ?? 'No email'),
1328
+ Text(currentUser.address?.city ?? 'Unknown city'),
1329
+ if (currentUser.avatar != null)
1330
+ Image.network(currentUser.avatar!),
1331
+ ],
1332
+ );
1333
+ }
1334
+ }
1335
+ ```
1336
+
1337
+ **Detection rule:**
1338
+ If `!` appears more than 3 times in a single method, suspect AP-16. If `!` is used on a value that could legitimately be null at runtime (user input, API response, map lookup), it is AP-16. Pattern: `json['key']!`, `snapshot.data!` without preceding `hasData` check, chained `!` operators like `a!.b!.c!`.
1339
+
1340
+ ---
1341
+
1342
+ ### AP-17: Not Handling Platform Differences
1343
+
1344
+ **Also known as:** iOS-Only Development, Android Amnesia, The Platform Blindspot
1345
+ **Frequency:** Common
1346
+ **Severity:** Medium
1347
+ **Detection difficulty:** Hard
1348
+
1349
+ **What it looks like:**
1350
+
1351
+ Assuming Flutter automatically handles all platform differences, ignoring iOS/Android behavioral differences, safe areas, navigation patterns, and permissions.
1352
+
1353
+ ```dart
1354
+ // BAD: Ignoring platform differences
1355
+ class SettingsScreen extends StatelessWidget {
1356
+ @override
1357
+ Widget build(BuildContext context) {
1358
+ return Scaffold(
1359
+ appBar: AppBar(title: Text('Settings')),
1360
+ body: ListView(
1361
+ children: [
1362
+ ListTile(
1363
+ title: Text('Notifications'),
1364
+ onTap: () {
1365
+ // Only handles Android permission model
1366
+ requestNotificationPermission();
1367
+ },
1368
+ ),
1369
+ ListTile(
1370
+ title: Text('Share'),
1371
+ onTap: () {
1372
+ // Uses Android intent pattern, breaks on iOS
1373
+ shareViaIntent(data);
1374
+ },
1375
+ ),
1376
+ ],
1377
+ ),
1378
+ );
1379
+ }
1380
+ }
1381
+ ```
1382
+
1383
+ **Why developers do it:**
1384
+
1385
+ Flutter's "write once, run anywhere" marketing creates a false sense of complete platform abstraction. Developers test on only one platform (usually the one their primary device runs). Platform-specific behavior is documented across multiple Flutter and platform-specific docs, making it easy to miss.
1386
+
1387
+ **What goes wrong:**
1388
+
1389
+ - iOS back navigation (swipe-from-edge) conflicts with horizontal scroll/drawer gestures if not handled.
1390
+ - Android 13+ requires explicit notification permission requests; iOS has required this since iOS 10.
1391
+ - `WillPopScope` (now `PopScope`) behaves differently with Android predictive back gestures (Android 13+), as documented in Flutter breaking changes and GitHub issue #140869.
1392
+ - Status bar and notch/Dynamic Island handling differs between platforms.
1393
+ - File paths, app lifecycle events, and deep linking all have platform-specific behaviors.
1394
+
1395
+ **The fix:**
1396
+
1397
+ ```dart
1398
+ // GOOD: Platform-aware code
1399
+ import 'dart:io' show Platform;
1400
+
1401
+ class SettingsScreen extends StatelessWidget {
1402
+ @override
1403
+ Widget build(BuildContext context) {
1404
+ return Scaffold(
1405
+ appBar: AppBar(title: const Text('Settings')),
1406
+ body: SafeArea( // Handles notch, Dynamic Island, etc.
1407
+ child: ListView(
1408
+ children: [
1409
+ ListTile(
1410
+ title: const Text('Notifications'),
1411
+ onTap: () async {
1412
+ if (Platform.isIOS) {
1413
+ await requestIOSNotificationPermission();
1414
+ } else {
1415
+ await requestAndroidNotificationPermission();
1416
+ }
1417
+ },
1418
+ ),
1419
+ ],
1420
+ ),
1421
+ ),
1422
+ );
1423
+ }
1424
+ }
1425
+ ```
1426
+
1427
+ **Detection rule:**
1428
+ If a Flutter app targets both iOS and Android but contains no `Platform.isIOS` / `Platform.isAndroid` checks and no `SafeArea` widgets, suspect AP-17. If `PopScope` or navigation handling does not account for Android predictive back, it is AP-17.
1429
+
1430
+ ---
1431
+
1432
+ ### AP-18: Over-Relying on Packages for Simple Tasks
1433
+
1434
+ **Also known as:** Package Bloat, The pub.dev Reflex, Dependency Addiction
1435
+ **Frequency:** Common
1436
+ **Severity:** Medium
1437
+ **Detection difficulty:** Moderate
1438
+
1439
+ **What it looks like:**
1440
+
1441
+ Adding third-party packages for functionality that Dart or Flutter provide natively, or for trivial implementations.
1442
+
1443
+ ```dart
1444
+ # pubspec.yaml -- BAD: packages for trivial tasks
1445
+ dependencies:
1446
+ flutter:
1447
+ sdk: flutter
1448
+ string_extensions: ^1.0.0 # For .capitalize() -- just write it
1449
+ date_formatter: ^2.0.0 # For date formatting -- intl is built-in
1450
+ device_info: ^3.0.0 # Used once to get platform name
1451
+ url_launcher: ^6.0.0 # Actually needed
1452
+ connectivity: ^3.0.0 # Actually needed
1453
+ random_color: ^1.0.0 # For generating random colors -- 3 lines of code
1454
+ validators: ^2.0.0 # For email validation -- one regex
1455
+ screen_size_util: ^1.0.0 # For screen breakpoints -- 10 lines of code
1456
+ ```
1457
+
1458
+ **Why developers do it:**
1459
+
1460
+ pub.dev makes it trivially easy to add packages. "There's a package for that" is a common response in the Flutter community. Developers overestimate the complexity of implementing simple utilities. Adding a package feels faster than writing 10 lines of code.
1461
+
1462
+ **What goes wrong:**
1463
+
1464
+ - Each package adds transitive dependencies, inflating binary size.
1465
+ - Version conflicts between packages become frequent -- `flutter pub get` starts failing with "version solving failed" as documented in FlutterFlow community posts and Dart dependency management guides.
1466
+ - Abandoned or unmaintained packages create security vulnerabilities and compatibility issues with new Flutter versions.
1467
+ - Upgrading Flutter SDK often breaks multiple packages simultaneously.
1468
+ - Debug builds become slow because Dart analyzes all dependency code.
1469
+ - One popular left-pad-style incident: when a package author unpublished their package, multiple apps broke.
1470
+
1471
+ **The fix:**
1472
+
1473
+ Before adding a package, ask: "Can I implement this in under 20 lines?" If yes, write it yourself.
1474
+
1475
+ ```dart
1476
+ // Instead of string_extensions package:
1477
+ extension StringCaps on String {
1478
+ String get capitalize =>
1479
+ isEmpty ? '' : '${this[0].toUpperCase()}${substring(1)}';
1480
+ }
1481
+
1482
+ // Instead of random_color package:
1483
+ Color randomColor() => Color((Random().nextDouble() * 0xFFFFFF).toInt())
1484
+ .withOpacity(1.0);
1485
+
1486
+ // Instead of validators package for email:
1487
+ bool isValidEmail(String email) =>
1488
+ RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(email);
1489
+ ```
1490
+
1491
+ **Detection rule:**
1492
+ If `pubspec.yaml` has more than 15 direct dependencies, review each for necessity. If a package is imported in only one file and used for a single function call, suspect AP-18. Run `dart pub deps --no-dev` and check for deep transitive dependency trees.
1493
+
1494
+ ---
1495
+
1496
+ ### AP-19: Not Handling Navigation and Back Button Properly
1497
+
1498
+ **Also known as:** Navigation Amnesia, Double-Pop Bug, Exit-on-Accident
1499
+ **Frequency:** Common
1500
+ **Severity:** Medium
1501
+ **Detection difficulty:** Moderate
1502
+
1503
+ **What it looks like:**
1504
+
1505
+ Not intercepting the back button on critical screens (forms, payment flows), allowing accidental data loss. Not handling deep link navigation state. Using deprecated `WillPopScope` on Flutter 3.12+.
1506
+
1507
+ ```dart
1508
+ // BAD: No back button protection on a checkout flow
1509
+ class CheckoutScreen extends StatefulWidget {
1510
+ @override
1511
+ _CheckoutScreenState createState() => _CheckoutScreenState();
1512
+ }
1513
+
1514
+ class _CheckoutScreenState extends State<CheckoutScreen> {
1515
+ // User has filled in address, payment info, selected shipping...
1516
+ // But pressing back just pops the screen with no warning
1517
+
1518
+ @override
1519
+ Widget build(BuildContext context) {
1520
+ return Scaffold(
1521
+ appBar: AppBar(title: Text('Checkout')),
1522
+ body: CheckoutForm(), // No PopScope wrapper!
1523
+ );
1524
+ }
1525
+ }
1526
+ ```
1527
+
1528
+ **Why developers do it:**
1529
+
1530
+ Navigation "just works" by default -- the back button pops the current route. Protecting against accidental back is seen as optional polish rather than critical UX. The migration from `WillPopScope` to `PopScope` in Flutter 3.12 confused many developers, and some skipped back-button handling entirely.
1531
+
1532
+ **What goes wrong:**
1533
+
1534
+ - Users accidentally lose form data, unsaved edits, or in-progress transactions.
1535
+ - On Android 13+, the predictive back gesture animation plays even when the pop should be blocked, as documented in Flutter issue #140869 and #139050.
1536
+ - Deep links that should navigate to a specific screen within a stack instead navigate to the screen with no back stack, trapping the user.
1537
+ - Double-tapping back on the home screen exits the app without confirmation.
1538
+
1539
+ **The fix:**
1540
+
1541
+ ```dart
1542
+ // GOOD: PopScope with confirmation dialog (Flutter 3.12+)
1543
+ class CheckoutScreen extends StatefulWidget {
1544
+ @override
1545
+ _CheckoutScreenState createState() => _CheckoutScreenState();
1546
+ }
1547
+
1548
+ class _CheckoutScreenState extends State<CheckoutScreen> {
1549
+ bool _hasUnsavedChanges = true;
1550
+
1551
+ Future<bool> _confirmDiscard() async {
1552
+ if (!_hasUnsavedChanges) return true;
1553
+ final result = await showDialog<bool>(
1554
+ context: context,
1555
+ builder: (context) => AlertDialog(
1556
+ title: const Text('Discard changes?'),
1557
+ content: const Text('You have unsaved checkout information.'),
1558
+ actions: [
1559
+ TextButton(onPressed: () => Navigator.pop(context, false), child: const Text('Cancel')),
1560
+ TextButton(onPressed: () => Navigator.pop(context, true), child: const Text('Discard')),
1561
+ ],
1562
+ ),
1563
+ );
1564
+ return result ?? false;
1565
+ }
1566
+
1567
+ @override
1568
+ Widget build(BuildContext context) {
1569
+ return PopScope(
1570
+ canPop: !_hasUnsavedChanges,
1571
+ onPopInvokedWithResult: (didPop, result) async {
1572
+ if (didPop) return;
1573
+ final shouldPop = await _confirmDiscard();
1574
+ if (shouldPop && mounted) Navigator.of(context).pop();
1575
+ },
1576
+ child: Scaffold(
1577
+ appBar: AppBar(title: const Text('Checkout')),
1578
+ body: CheckoutForm(),
1579
+ ),
1580
+ );
1581
+ }
1582
+ }
1583
+ ```
1584
+
1585
+ **Detection rule:**
1586
+ If a screen handles user input (forms, editors, multi-step flows) but contains no `PopScope` or `WillPopScope` wrapper, suspect AP-19. If `WillPopScope` is used on Flutter 3.12+, it is deprecated and should be migrated to `PopScope`.
1587
+
1588
+ ---
1589
+
1590
+ ### AP-20: Using Strings for Everything (No Type Safety)
1591
+
1592
+ **Also known as:** Stringly-Typed Code, The Dynamic Map Plague, Type Erasure
1593
+ **Frequency:** Common
1594
+ **Severity:** Medium
1595
+ **Detection difficulty:** Moderate
1596
+
1597
+ **What it looks like:**
1598
+
1599
+ Passing data as `Map<String, dynamic>` throughout the app instead of defining typed model classes. Using string literals for routes, event names, and configuration keys.
1600
+
1601
+ ```dart
1602
+ // BAD: Stringly-typed data flow
1603
+ Future<Map<String, dynamic>> fetchUser() async {
1604
+ final response = await http.get(Uri.parse('/api/user'));
1605
+ return jsonDecode(response.body) as Map<String, dynamic>;
1606
+ }
1607
+
1608
+ // Later in a widget:
1609
+ Text(userData['name'] as String), // Typo-prone
1610
+ Text(userData['adress'] as String), // Misspelled key -- runtime crash
1611
+ Text('${userData['age']}'), // No type checking
1612
+
1613
+ // BAD: String-based navigation
1614
+ Navigator.pushNamed(context, '/usr/profile'); // Typo -- silent failure
1615
+ ```
1616
+
1617
+ **Why developers do it:**
1618
+
1619
+ `jsonDecode` returns `Map<String, dynamic>` by default, and it works immediately. Creating model classes for every API response feels like boilerplate. Dynamic typing is faster for prototyping. Coming from JavaScript/Python, developers are accustomed to working with maps and dictionaries.
1620
+
1621
+ **What goes wrong:**
1622
+
1623
+ - Typos in string keys cause runtime crashes, not compile-time errors: `userData['adress']` returns null silently.
1624
+ - Refactoring is dangerous: renaming a field requires finding all string references manually; the compiler cannot help.
1625
+ - No IDE autocomplete for map keys.
1626
+ - No documentation of data shape -- new developers must read API docs or print the map to understand its structure.
1627
+ - The `as String` casts sprinkled everywhere are each a potential `TypeError` at runtime.
1628
+
1629
+ **The fix:**
1630
+
1631
+ ```dart
1632
+ // GOOD: Typed model classes
1633
+ class User {
1634
+ final String name;
1635
+ final String email;
1636
+ final int age;
1637
+ final Address address;
1638
+
1639
+ const User({
1640
+ required this.name,
1641
+ required this.email,
1642
+ required this.age,
1643
+ required this.address,
1644
+ });
1645
+
1646
+ factory User.fromJson(Map<String, dynamic> json) {
1647
+ return User(
1648
+ name: json['name'] as String,
1649
+ email: json['email'] as String,
1650
+ age: json['age'] as int,
1651
+ address: Address.fromJson(json['address'] as Map<String, dynamic>),
1652
+ );
1653
+ }
1654
+ }
1655
+
1656
+ // Usage: compile-time safety
1657
+ final user = User.fromJson(jsonData);
1658
+ Text(user.name); // Autocomplete, type-safe
1659
+ Text(user.email); // Cannot misspell
1660
+ Text('${user.age}'); // Guaranteed int
1661
+
1662
+ // GOOD: Type-safe routing
1663
+ enum AppRoute { home, profile, settings }
1664
+ // Or use go_router with typed routes
1665
+ ```
1666
+
1667
+ **Detection rule:**
1668
+ If `Map<String, dynamic>` appears as a parameter type or return type outside of JSON serialization boundaries, suspect AP-20. If string literals are used for route names and appear in more than one file, it is AP-20. If `as String`, `as int`, `as double` casts appear frequently outside `fromJson` factories, it is AP-20.
1669
+
1670
+ ---
1671
+
1672
+ ### AP-21: Not Testing Widgets
1673
+
1674
+ **Also known as:** The "It Works on My Phone" Syndrome, Test-Free UI, Manual-Only QA
1675
+ **Frequency:** Very Common
1676
+ **Severity:** High
1677
+ **Detection difficulty:** Easy
1678
+
1679
+ **What it looks like:**
1680
+
1681
+ An app with zero or near-zero widget tests, relying entirely on manual testing or only unit tests for business logic.
1682
+
1683
+ ```
1684
+ # Project structure -- BAD: no widget tests
1685
+ lib/
1686
+ screens/
1687
+ home_screen.dart
1688
+ profile_screen.dart
1689
+ settings_screen.dart
1690
+ widgets/
1691
+ user_card.dart
1692
+ product_tile.dart
1693
+ test/
1694
+ services/
1695
+ auth_service_test.dart # Only service tests exist
1696
+ api_client_test.dart
1697
+ # No widget tests at all!
1698
+ ```
1699
+
1700
+ **Why developers do it:**
1701
+
1702
+ Widget tests require wrapping widgets in `MaterialApp`, providing mock dependencies, and calling `pumpAndSettle()` -- setup that feels heavyweight compared to unit tests. Developers assume "if the logic is tested and it looks right on the emulator, it works." Widget test documentation is extensive but intimidating for beginners.
1703
+
1704
+ **What goes wrong:**
1705
+
1706
+ - Overflow errors on different screen sizes are only caught when users report them.
1707
+ - State management bugs (wrong widget rebuilding, stale state) are invisible without automated tests.
1708
+ - Regression bugs appear silently: a refactored widget renders differently but no test catches it.
1709
+ - Accessibility issues (missing semantics labels, broken screen reader order) are never detected.
1710
+ - As documented on QuickCoder.org, common pitfalls include overflow errors only appearing in tests (different default test viewport size), animations not triggering without `pump()`, and incorrect finder usage with Material button named constructors.
1711
+
1712
+ **The fix:**
1713
+
1714
+ Write widget tests for every screen and every reusable widget.
1715
+
1716
+ ```dart
1717
+ // GOOD: Widget test
1718
+ void main() {
1719
+ testWidgets('UserCard displays name and email', (tester) async {
1720
+ const user = User(name: 'Alice', email: 'alice@example.com');
1721
+
1722
+ await tester.pumpWidget(
1723
+ const MaterialApp(
1724
+ home: Scaffold(body: UserCard(user: user)),
1725
+ ),
1726
+ );
1727
+
1728
+ expect(find.text('Alice'), findsOneWidget);
1729
+ expect(find.text('alice@example.com'), findsOneWidget);
1730
+ });
1731
+
1732
+ testWidgets('UserCard tap navigates to profile', (tester) async {
1733
+ const user = User(name: 'Alice', email: 'alice@example.com');
1734
+
1735
+ await tester.pumpWidget(
1736
+ MaterialApp(
1737
+ home: Scaffold(body: UserCard(user: user)),
1738
+ routes: {'/profile': (_) => const ProfileScreen()},
1739
+ ),
1740
+ );
1741
+
1742
+ await tester.tap(find.byType(UserCard));
1743
+ await tester.pumpAndSettle();
1744
+
1745
+ expect(find.byType(ProfileScreen), findsOneWidget);
1746
+ });
1747
+ }
1748
+ ```
1749
+
1750
+ **Detection rule:**
1751
+ If the `test/` directory contains no `*_test.dart` files that import `flutter_test`, suspect AP-21. If the ratio of widget test files to widget files (`lib/widgets/` + `lib/screens/`) is less than 0.3, it is AP-21. If `testWidgets` appears nowhere in the test directory, it is AP-21.
1752
+
1753
+ ---
1754
+
1755
+ ## Root Cause Analysis
1756
+
1757
+ | Anti-Pattern | Root Cause | Prevention |
1758
+ |-------------|------------|------------|
1759
+ | AP-01: God Widget | Laziness / Ignorance | Enforce max widget file length in linter; code review checklist |
1760
+ | AP-02: Methods not Widgets | Cargo culting from other frameworks | DCM `avoid-returning-widgets` lint rule |
1761
+ | AP-03: Missing const | Ignorance of Flutter internals | Enable `prefer_const_constructors` lint |
1762
+ | AP-04: setState for everything | Laziness / Tutorial-driven development | Introduce state management early; architecture templates |
1763
+ | AP-05: Missing dispose | Ignorance / Forgetfulness | `cancel_subscriptions` and `close_sinks` lints; code review |
1764
+ | AP-06: Blocking UI thread | Ignorance (async != parallel) | Profile with DevTools; educate on isolates |
1765
+ | AP-07: GlobalKey overuse | Cargo culting from Form tutorials | Code review; prefer callbacks and state management |
1766
+ | AP-08: Missing list keys | Ignorance of Flutter reconciliation | Lint for missing keys in list builders |
1767
+ | AP-09: Context across async | Ignorance / Race condition blindness | `use_build_context_synchronously` lint |
1768
+ | AP-10: Partial snapshot handling | Laziness / Happy-path development | Template for FutureBuilder/StreamBuilder usage |
1769
+ | AP-11: Hardcoded dimensions | Laziness / Single-device testing | Test on multiple screen sizes; design review |
1770
+ | AP-12: Unnecessary rebuilds | Ignorance of rebuild mechanics | Flutter DevTools Rebuild Stats; const widgets |
1771
+ | AP-13: Logic in widgets | Laziness / Premature shortcuts | Architecture templates; code review for imports |
1772
+ | AP-14: Futures in build | Copy-paste from AI/Stack Overflow | FutureBuilder lint; code review |
1773
+ | AP-15: Overusing StatefulWidget | Ignorance / "Just in case" thinking | Start StatelessWidget, convert when needed |
1774
+ | AP-16: Bang operator abuse | Laziness / Migration shortcuts | Limit `!` per file; code review |
1775
+ | AP-17: Ignoring platform diffs | Ignorance / Single-platform testing | Test on both platforms; platform checklist |
1776
+ | AP-18: Package bloat | Laziness / "There's a package for that" | Review pubspec.yaml in PRs; 20-line rule |
1777
+ | AP-19: Bad navigation handling | Ignorance / "It just works" assumption | Navigation checklist for forms and flows |
1778
+ | AP-20: Stringly-typed code | Laziness / Prototype not refactored | Enforce model classes; ban `Map<String, dynamic>` outside serialization |
1779
+ | AP-21: No widget tests | Laziness / "Looks right on emulator" | CI/CD coverage gates; widget test templates |
1780
+
1781
+ ## Self-Check Questions
1782
+
1783
+ 1. Does this widget file exceed 200 lines? Should I split it into composed sub-widgets?
1784
+ 2. Am I returning `Widget` from a private method? Should this be a separate `StatelessWidget` class instead?
1785
+ 3. Can I add `const` to this constructor or widget instantiation? If not, why not?
1786
+ 4. Am I using `setState` to manage data that other widgets also need? Should I use a state management solution?
1787
+ 5. For every controller, subscription, timer, or focus node I create in `initState`, do I have a corresponding cleanup in `dispose()`?
1788
+ 6. Will this computation take more than 16ms? Should it run in an `Isolate` instead of the main thread?
1789
+ 7. Am I using `BuildContext` after an `await`? Have I checked `mounted` first?
1790
+ 8. Does my `FutureBuilder`/`StreamBuilder` handle loading, error, and empty-data states, not just the success case?
1791
+ 9. Am I creating a `Future` or `Stream` inside `build()`? Should it be in `initState` instead?
1792
+ 10. Am I using `!` to silence a null warning? Can I handle the null case properly with `??`, `?.`, or a null check?
1793
+ 11. Have I tested this screen on both iOS and Android? On a small screen and a large screen?
1794
+ 12. Could I implement this package's functionality in under 20 lines of Dart?
1795
+ 13. Does this screen with user input have back-button protection (`PopScope`)?
1796
+ 14. Am I passing `Map<String, dynamic>` where a typed model class would provide compile-time safety?
1797
+ 15. Do I have at least one widget test for every screen in this app?
1798
+
1799
+ ## Code Smell Quick Reference
1800
+
1801
+ | If you see... | Suspect... | Verify... |
1802
+ |---------------|-----------|-----------|
1803
+ | `build()` method > 80 lines | AP-01: God Widget | Can sub-trees be extracted to separate widget classes? |
1804
+ | `Widget _build*()` private methods | AP-02: Method not Widget | Replace with `StatelessWidget` class for rebuild optimization |
1805
+ | Widget constructor without `const` keyword when all args are constant | AP-03: Missing const | Add `const`; enable `prefer_const_constructors` lint |
1806
+ | `setState` called 5+ times in one State class | AP-04: setState overload | Introduce Provider/Riverpod/BLoC for shared state |
1807
+ | `TextEditingController()` / `StreamSubscription` without matching `dispose()` | AP-05: Missing dispose | Add `dispose()` with cleanup for every resource |
1808
+ | Loops, JSON parsing, or file I/O inside `build()` | AP-06: UI thread blocked | Move to `Isolate.run()` or `compute()` |
1809
+ | `GlobalKey()` inside `build()` | AP-07: GlobalKey in build | Move to field or `initState`; prefer callbacks |
1810
+ | `ListView.builder` items without `key:` parameter | AP-08: Missing keys | Add `ValueKey(item.id)` with stable identifier |
1811
+ | `context` used after `await` without `mounted` check | AP-09: Stale context | Add `if (!mounted) return;` after every `await` |
1812
+ | `FutureBuilder` without `ConnectionState.waiting` check | AP-10: Partial state handling | Handle waiting, error, no-data, and success states |
1813
+ | Literal numbers > 100 for width/height | AP-11: Hardcoded dimensions | Use `LayoutBuilder`, `MediaQuery`, or `Flexible` |
1814
+ | `setState` modifies 1 field but `build()` creates 10+ widgets | AP-12: Rebuild avalanche | Push state down to smallest widget; use `const` children |
1815
+ | Widget importing `http`, `dart:convert`, database packages | AP-13: Logic in widget | Extract to service/repository class |
1816
+ | `FutureBuilder(future: fetchData(),` inside `build()` | AP-14: Future in build | Create Future in `initState`, reference it in builder |
1817
+ | `StatefulWidget` with no mutable fields in State | AP-15: Unnecessary StatefulWidget | Convert to `StatelessWidget` |
1818
+ | Multiple `!` operators on same line | AP-16: Bang abuse | Use `?.`, `??`, null checks, or early return |
1819
+ | No `Platform.isIOS` / `SafeArea` in cross-platform app | AP-17: Platform blindness | Test on both platforms; add platform-specific handling |
1820
+ | 15+ dependencies in `pubspec.yaml` | AP-18: Package bloat | Review each: can it be implemented in < 20 lines? |
1821
+ | Form screen without `PopScope` wrapper | AP-19: Unprotected navigation | Add `PopScope` with confirmation dialog |
1822
+ | `Map<String, dynamic>` passed between methods | AP-20: Stringly-typed | Create typed model class with `fromJson` factory |
1823
+ | No `testWidgets` in test directory | AP-21: No widget tests | Add widget tests for screens and reusable widgets |
1824
+
1825
+ ---
1826
+
1827
+ *Researched: 2026-03-08 | Sources: [Flutter Performance Best Practices](https://docs.flutter.dev/perf/best-practices), [DCM Anti-Patterns](https://dartcodemetrics.dev/docs/anti-patterns), [DCM: Memory Leaks in Dart and Flutter](https://dcm.dev/blog/2024/10/21/lets-talk-about-memory-leaks-in-dart-and-flutter/), [DCM: 15 Common Mistakes](https://dcm.dev/blog/2025/03/24/fifteen-common-mistakes-flutter-dart-development/), [Splitting Widgets to Methods is an Anti-Pattern (Iiro Krankka)](https://iiro.dev/splitting-widgets-to-methods-performance-antipattern/), [Flutter Widget Rebuild Optimization](https://763p.me/blog/2025/09/28/mastering-flutter-rebuild-optimization-eliminating-unnecessary-widget-rebuilds/), [Flutter Concurrency and Isolates](https://docs.flutter.dev/perf/isolates), [Flutter GlobalKey Documentation](https://api.flutter.dev/flutter/widgets/GlobalKey-class.html), [Flutter GlobalKey Performance Issue #35730](https://github.com/flutter/flutter/issues/35730), [FutureBuilder Common Mistakes](https://medium.com/@wartelski/futurebuilder-in-flutter-mistakes-you-might-be-making-e97209f66c2f), [BuildContext Across Async Gaps](https://dart.dev/tools/linter-rules/use_build_context_synchronously), [Flutter PopScope Breaking Changes](https://docs.flutter.dev/release/breaking-changes/android-predictive-back), [PopScope Issue #140869](https://github.com/flutter/flutter/issues/140869), [Flutter Architecture Guide](https://docs.flutter.dev/app-architecture/guide), [Effective Dart: Design](https://dart.dev/effective-dart/design), [Widget Testing Introduction](https://docs.flutter.dev/cookbook/testing/widget/introduction), [Widget Testing Pitfalls (QuickCoder)](https://quickcoder.org/a-short-excursion-into-the-pitfalls-of-flutter-widget-testing/), [Stop Doing These Flutter Performance Mistakes (2026)](https://medium.com/@tiger.chirag/stop-doing-these-flutter-performance-mistakes-2026-edition-79cae09d5f22), [Flutter State Management Guide (2026)](https://medium.com/@satishparmarparmar486/the-ultimate-guide-to-flutter-state-management-in-2026-from-setstate-to-bloc-riverpod-561192c31e1c), [Flutter Responsive Design](https://docs.flutter.dev/ui/adaptive-responsive/general)*