@booklib/core 2.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 (374) hide show
  1. package/.cursor/rules/booklib-standards.mdc +40 -0
  2. package/.gemini/context.md +372 -0
  3. package/AGENTS.md +166 -0
  4. package/CHANGELOG.md +226 -0
  5. package/CLAUDE.md +81 -0
  6. package/CODE_OF_CONDUCT.md +31 -0
  7. package/CONTRIBUTING.md +304 -0
  8. package/LICENSE +21 -0
  9. package/PLAN.md +28 -0
  10. package/README.ja.md +198 -0
  11. package/README.ko.md +198 -0
  12. package/README.md +503 -0
  13. package/README.pt-BR.md +198 -0
  14. package/README.uk.md +241 -0
  15. package/README.zh-CN.md +198 -0
  16. package/SECURITY.md +9 -0
  17. package/agents/architecture-reviewer.md +136 -0
  18. package/agents/booklib-reviewer.md +90 -0
  19. package/agents/data-reviewer.md +107 -0
  20. package/agents/jvm-reviewer.md +146 -0
  21. package/agents/python-reviewer.md +128 -0
  22. package/agents/rust-reviewer.md +115 -0
  23. package/agents/ts-reviewer.md +110 -0
  24. package/agents/ui-reviewer.md +117 -0
  25. package/assets/logo.svg +36 -0
  26. package/bin/booklib-mcp.js +304 -0
  27. package/bin/booklib.js +1705 -0
  28. package/bin/skills.cjs +1292 -0
  29. package/booklib-router.mdc +36 -0
  30. package/booklib.config.json +19 -0
  31. package/commands/animation-at-work.md +10 -0
  32. package/commands/clean-code-reviewer.md +10 -0
  33. package/commands/data-intensive-patterns.md +10 -0
  34. package/commands/data-pipelines.md +10 -0
  35. package/commands/design-patterns.md +10 -0
  36. package/commands/domain-driven-design.md +10 -0
  37. package/commands/effective-java.md +10 -0
  38. package/commands/effective-kotlin.md +10 -0
  39. package/commands/effective-python.md +10 -0
  40. package/commands/effective-typescript.md +10 -0
  41. package/commands/kotlin-in-action.md +10 -0
  42. package/commands/lean-startup.md +10 -0
  43. package/commands/microservices-patterns.md +10 -0
  44. package/commands/programming-with-rust.md +10 -0
  45. package/commands/refactoring-ui.md +10 -0
  46. package/commands/rust-in-action.md +10 -0
  47. package/commands/skill-router.md +10 -0
  48. package/commands/spring-boot-in-action.md +10 -0
  49. package/commands/storytelling-with-data.md +10 -0
  50. package/commands/system-design-interview.md +10 -0
  51. package/commands/using-asyncio-python.md +10 -0
  52. package/commands/web-scraping-python.md +10 -0
  53. package/community/registry.json +1616 -0
  54. package/hooks/hooks.json +23 -0
  55. package/hooks/posttooluse-capture.mjs +67 -0
  56. package/hooks/suggest.js +153 -0
  57. package/lib/agent-behaviors.js +40 -0
  58. package/lib/agent-detector.js +96 -0
  59. package/lib/config-loader.js +39 -0
  60. package/lib/conflict-resolver.js +148 -0
  61. package/lib/context-builder.js +574 -0
  62. package/lib/discovery-engine.js +298 -0
  63. package/lib/doctor/hook-installer.js +83 -0
  64. package/lib/doctor/usage-tracker.js +87 -0
  65. package/lib/engine/ai-features.js +253 -0
  66. package/lib/engine/auditor.js +103 -0
  67. package/lib/engine/bm25-index.js +178 -0
  68. package/lib/engine/capture.js +120 -0
  69. package/lib/engine/corrections.js +198 -0
  70. package/lib/engine/doctor.js +195 -0
  71. package/lib/engine/graph-injector.js +137 -0
  72. package/lib/engine/graph.js +161 -0
  73. package/lib/engine/handoff.js +405 -0
  74. package/lib/engine/indexer.js +242 -0
  75. package/lib/engine/parser.js +53 -0
  76. package/lib/engine/query-expander.js +42 -0
  77. package/lib/engine/reranker.js +40 -0
  78. package/lib/engine/rrf.js +59 -0
  79. package/lib/engine/scanner.js +151 -0
  80. package/lib/engine/searcher.js +139 -0
  81. package/lib/engine/session-coordinator.js +306 -0
  82. package/lib/engine/session-manager.js +429 -0
  83. package/lib/engine/synthesizer.js +70 -0
  84. package/lib/installer.js +70 -0
  85. package/lib/instinct-block.js +33 -0
  86. package/lib/mcp-config-writer.js +88 -0
  87. package/lib/paths.js +57 -0
  88. package/lib/profiles/design.md +19 -0
  89. package/lib/profiles/general.md +16 -0
  90. package/lib/profiles/research-analysis.md +22 -0
  91. package/lib/profiles/software-development.md +23 -0
  92. package/lib/profiles/writing-content.md +19 -0
  93. package/lib/project-initializer.js +916 -0
  94. package/lib/registry/skills.js +102 -0
  95. package/lib/registry-searcher.js +99 -0
  96. package/lib/rules/rules-manager.js +169 -0
  97. package/lib/skill-fetcher.js +333 -0
  98. package/lib/well-known-builder.js +70 -0
  99. package/lib/wizard/index.js +404 -0
  100. package/lib/wizard/integration-detector.js +41 -0
  101. package/lib/wizard/project-detector.js +100 -0
  102. package/lib/wizard/prompt.js +156 -0
  103. package/lib/wizard/registry-embeddings.js +107 -0
  104. package/lib/wizard/skill-recommender.js +69 -0
  105. package/llms-full.txt +254 -0
  106. package/llms.txt +70 -0
  107. package/package.json +45 -0
  108. package/research-reports/2026-04-01-current-architecture.md +160 -0
  109. package/research-reports/IDEAS.md +93 -0
  110. package/rules/common/clean-code.md +42 -0
  111. package/rules/java/effective-java.md +42 -0
  112. package/rules/kotlin/effective-kotlin.md +37 -0
  113. package/rules/python/effective-python.md +38 -0
  114. package/rules/rust/rust.md +37 -0
  115. package/rules/typescript/effective-typescript.md +42 -0
  116. package/scripts/gen-llms-full.mjs +36 -0
  117. package/scripts/gen-og.mjs +142 -0
  118. package/scripts/validate-frontmatter.js +25 -0
  119. package/skills/animation-at-work/SKILL.md +270 -0
  120. package/skills/animation-at-work/assets/example_asset.txt +1 -0
  121. package/skills/animation-at-work/evals/evals.json +44 -0
  122. package/skills/animation-at-work/evals/results.json +13 -0
  123. package/skills/animation-at-work/examples/after.md +64 -0
  124. package/skills/animation-at-work/examples/before.md +35 -0
  125. package/skills/animation-at-work/references/api_reference.md +369 -0
  126. package/skills/animation-at-work/references/review-checklist.md +79 -0
  127. package/skills/animation-at-work/scripts/audit_animations.py +295 -0
  128. package/skills/animation-at-work/scripts/example.py +1 -0
  129. package/skills/clean-code-reviewer/SKILL.md +444 -0
  130. package/skills/clean-code-reviewer/audit.json +35 -0
  131. package/skills/clean-code-reviewer/evals/evals.json +185 -0
  132. package/skills/clean-code-reviewer/evals/results.json +13 -0
  133. package/skills/clean-code-reviewer/examples/after.md +48 -0
  134. package/skills/clean-code-reviewer/examples/before.md +33 -0
  135. package/skills/clean-code-reviewer/references/api_reference.md +158 -0
  136. package/skills/clean-code-reviewer/references/practices-catalog.md +282 -0
  137. package/skills/clean-code-reviewer/references/review-checklist.md +254 -0
  138. package/skills/clean-code-reviewer/scripts/pre-review.py +206 -0
  139. package/skills/data-intensive-patterns/SKILL.md +267 -0
  140. package/skills/data-intensive-patterns/assets/example_asset.txt +1 -0
  141. package/skills/data-intensive-patterns/evals/evals.json +54 -0
  142. package/skills/data-intensive-patterns/evals/results.json +13 -0
  143. package/skills/data-intensive-patterns/examples/after.md +61 -0
  144. package/skills/data-intensive-patterns/examples/before.md +38 -0
  145. package/skills/data-intensive-patterns/references/api_reference.md +34 -0
  146. package/skills/data-intensive-patterns/references/patterns-catalog.md +551 -0
  147. package/skills/data-intensive-patterns/references/review-checklist.md +193 -0
  148. package/skills/data-intensive-patterns/scripts/adr.py +213 -0
  149. package/skills/data-intensive-patterns/scripts/example.py +1 -0
  150. package/skills/data-pipelines/SKILL.md +259 -0
  151. package/skills/data-pipelines/assets/example_asset.txt +1 -0
  152. package/skills/data-pipelines/evals/evals.json +45 -0
  153. package/skills/data-pipelines/evals/results.json +13 -0
  154. package/skills/data-pipelines/examples/after.md +97 -0
  155. package/skills/data-pipelines/examples/before.md +37 -0
  156. package/skills/data-pipelines/references/api_reference.md +301 -0
  157. package/skills/data-pipelines/references/review-checklist.md +181 -0
  158. package/skills/data-pipelines/scripts/example.py +1 -0
  159. package/skills/data-pipelines/scripts/new_pipeline.py +444 -0
  160. package/skills/design-patterns/SKILL.md +271 -0
  161. package/skills/design-patterns/assets/example_asset.txt +1 -0
  162. package/skills/design-patterns/evals/evals.json +46 -0
  163. package/skills/design-patterns/evals/results.json +13 -0
  164. package/skills/design-patterns/examples/after.md +52 -0
  165. package/skills/design-patterns/examples/before.md +29 -0
  166. package/skills/design-patterns/references/api_reference.md +1 -0
  167. package/skills/design-patterns/references/patterns-catalog.md +726 -0
  168. package/skills/design-patterns/references/review-checklist.md +173 -0
  169. package/skills/design-patterns/scripts/example.py +1 -0
  170. package/skills/design-patterns/scripts/scaffold.py +807 -0
  171. package/skills/domain-driven-design/SKILL.md +142 -0
  172. package/skills/domain-driven-design/assets/example_asset.txt +1 -0
  173. package/skills/domain-driven-design/evals/evals.json +48 -0
  174. package/skills/domain-driven-design/evals/results.json +13 -0
  175. package/skills/domain-driven-design/examples/after.md +80 -0
  176. package/skills/domain-driven-design/examples/before.md +43 -0
  177. package/skills/domain-driven-design/references/api_reference.md +1 -0
  178. package/skills/domain-driven-design/references/patterns-catalog.md +545 -0
  179. package/skills/domain-driven-design/references/review-checklist.md +158 -0
  180. package/skills/domain-driven-design/scripts/example.py +1 -0
  181. package/skills/domain-driven-design/scripts/scaffold.py +421 -0
  182. package/skills/effective-java/SKILL.md +227 -0
  183. package/skills/effective-java/assets/example_asset.txt +1 -0
  184. package/skills/effective-java/evals/evals.json +46 -0
  185. package/skills/effective-java/evals/results.json +13 -0
  186. package/skills/effective-java/examples/after.md +83 -0
  187. package/skills/effective-java/examples/before.md +37 -0
  188. package/skills/effective-java/references/api_reference.md +1 -0
  189. package/skills/effective-java/references/items-catalog.md +955 -0
  190. package/skills/effective-java/references/review-checklist.md +216 -0
  191. package/skills/effective-java/scripts/checkstyle_setup.py +211 -0
  192. package/skills/effective-java/scripts/example.py +1 -0
  193. package/skills/effective-kotlin/SKILL.md +271 -0
  194. package/skills/effective-kotlin/assets/example_asset.txt +1 -0
  195. package/skills/effective-kotlin/audit.json +29 -0
  196. package/skills/effective-kotlin/evals/evals.json +45 -0
  197. package/skills/effective-kotlin/evals/results.json +13 -0
  198. package/skills/effective-kotlin/examples/after.md +36 -0
  199. package/skills/effective-kotlin/examples/before.md +38 -0
  200. package/skills/effective-kotlin/references/api_reference.md +1 -0
  201. package/skills/effective-kotlin/references/practices-catalog.md +1228 -0
  202. package/skills/effective-kotlin/references/review-checklist.md +126 -0
  203. package/skills/effective-kotlin/scripts/example.py +1 -0
  204. package/skills/effective-python/SKILL.md +441 -0
  205. package/skills/effective-python/evals/evals.json +44 -0
  206. package/skills/effective-python/evals/results.json +13 -0
  207. package/skills/effective-python/examples/after.md +56 -0
  208. package/skills/effective-python/examples/before.md +40 -0
  209. package/skills/effective-python/ref-01-pythonic-thinking.md +202 -0
  210. package/skills/effective-python/ref-02-lists-and-dicts.md +146 -0
  211. package/skills/effective-python/ref-03-functions.md +186 -0
  212. package/skills/effective-python/ref-04-comprehensions-generators.md +211 -0
  213. package/skills/effective-python/ref-05-classes-interfaces.md +188 -0
  214. package/skills/effective-python/ref-06-metaclasses-attributes.md +209 -0
  215. package/skills/effective-python/ref-07-concurrency.md +213 -0
  216. package/skills/effective-python/ref-08-robustness-performance.md +248 -0
  217. package/skills/effective-python/ref-09-testing-debugging.md +253 -0
  218. package/skills/effective-python/ref-10-collaboration.md +175 -0
  219. package/skills/effective-python/references/api_reference.md +218 -0
  220. package/skills/effective-python/references/practices-catalog.md +483 -0
  221. package/skills/effective-python/references/review-checklist.md +190 -0
  222. package/skills/effective-python/scripts/lint.py +173 -0
  223. package/skills/effective-typescript/SKILL.md +262 -0
  224. package/skills/effective-typescript/audit.json +29 -0
  225. package/skills/effective-typescript/evals/evals.json +37 -0
  226. package/skills/effective-typescript/evals/results.json +13 -0
  227. package/skills/effective-typescript/examples/after.md +70 -0
  228. package/skills/effective-typescript/examples/before.md +47 -0
  229. package/skills/effective-typescript/references/api_reference.md +118 -0
  230. package/skills/effective-typescript/references/practices-catalog.md +371 -0
  231. package/skills/effective-typescript/scripts/review.py +169 -0
  232. package/skills/kotlin-in-action/SKILL.md +261 -0
  233. package/skills/kotlin-in-action/assets/example_asset.txt +1 -0
  234. package/skills/kotlin-in-action/evals/evals.json +43 -0
  235. package/skills/kotlin-in-action/evals/results.json +13 -0
  236. package/skills/kotlin-in-action/examples/after.md +53 -0
  237. package/skills/kotlin-in-action/examples/before.md +39 -0
  238. package/skills/kotlin-in-action/references/api_reference.md +1 -0
  239. package/skills/kotlin-in-action/references/practices-catalog.md +436 -0
  240. package/skills/kotlin-in-action/references/review-checklist.md +204 -0
  241. package/skills/kotlin-in-action/scripts/example.py +1 -0
  242. package/skills/kotlin-in-action/scripts/setup_detekt.py +224 -0
  243. package/skills/lean-startup/SKILL.md +160 -0
  244. package/skills/lean-startup/assets/example_asset.txt +1 -0
  245. package/skills/lean-startup/evals/evals.json +43 -0
  246. package/skills/lean-startup/evals/results.json +13 -0
  247. package/skills/lean-startup/examples/after.md +80 -0
  248. package/skills/lean-startup/examples/before.md +34 -0
  249. package/skills/lean-startup/references/api_reference.md +319 -0
  250. package/skills/lean-startup/references/review-checklist.md +137 -0
  251. package/skills/lean-startup/scripts/example.py +1 -0
  252. package/skills/lean-startup/scripts/new_experiment.py +286 -0
  253. package/skills/microservices-patterns/SKILL.md +384 -0
  254. package/skills/microservices-patterns/evals/evals.json +45 -0
  255. package/skills/microservices-patterns/evals/results.json +13 -0
  256. package/skills/microservices-patterns/examples/after.md +69 -0
  257. package/skills/microservices-patterns/examples/before.md +40 -0
  258. package/skills/microservices-patterns/references/patterns-catalog.md +391 -0
  259. package/skills/microservices-patterns/references/review-checklist.md +169 -0
  260. package/skills/microservices-patterns/scripts/new_service.py +583 -0
  261. package/skills/programming-with-rust/SKILL.md +209 -0
  262. package/skills/programming-with-rust/evals/evals.json +37 -0
  263. package/skills/programming-with-rust/evals/results.json +13 -0
  264. package/skills/programming-with-rust/examples/after.md +107 -0
  265. package/skills/programming-with-rust/examples/before.md +59 -0
  266. package/skills/programming-with-rust/references/api_reference.md +152 -0
  267. package/skills/programming-with-rust/references/practices-catalog.md +335 -0
  268. package/skills/programming-with-rust/scripts/review.py +142 -0
  269. package/skills/refactoring-ui/SKILL.md +362 -0
  270. package/skills/refactoring-ui/assets/example_asset.txt +1 -0
  271. package/skills/refactoring-ui/evals/evals.json +45 -0
  272. package/skills/refactoring-ui/evals/results.json +13 -0
  273. package/skills/refactoring-ui/examples/after.md +85 -0
  274. package/skills/refactoring-ui/examples/before.md +58 -0
  275. package/skills/refactoring-ui/references/api_reference.md +355 -0
  276. package/skills/refactoring-ui/references/review-checklist.md +114 -0
  277. package/skills/refactoring-ui/scripts/audit_css.py +250 -0
  278. package/skills/refactoring-ui/scripts/example.py +1 -0
  279. package/skills/rust-in-action/SKILL.md +350 -0
  280. package/skills/rust-in-action/evals/evals.json +38 -0
  281. package/skills/rust-in-action/evals/results.json +13 -0
  282. package/skills/rust-in-action/examples/after.md +156 -0
  283. package/skills/rust-in-action/examples/before.md +56 -0
  284. package/skills/rust-in-action/references/practices-catalog.md +346 -0
  285. package/skills/rust-in-action/scripts/review.py +147 -0
  286. package/skills/skill-router/SKILL.md +186 -0
  287. package/skills/skill-router/evals/evals.json +38 -0
  288. package/skills/skill-router/evals/results.json +13 -0
  289. package/skills/skill-router/examples/after.md +63 -0
  290. package/skills/skill-router/examples/before.md +39 -0
  291. package/skills/skill-router/references/api_reference.md +24 -0
  292. package/skills/skill-router/references/routing-heuristics.md +89 -0
  293. package/skills/skill-router/references/skill-catalog.md +174 -0
  294. package/skills/skill-router/scripts/route.py +266 -0
  295. package/skills/spring-boot-in-action/SKILL.md +340 -0
  296. package/skills/spring-boot-in-action/evals/evals.json +39 -0
  297. package/skills/spring-boot-in-action/evals/results.json +13 -0
  298. package/skills/spring-boot-in-action/examples/after.md +185 -0
  299. package/skills/spring-boot-in-action/examples/before.md +84 -0
  300. package/skills/spring-boot-in-action/references/practices-catalog.md +403 -0
  301. package/skills/spring-boot-in-action/scripts/review.py +184 -0
  302. package/skills/storytelling-with-data/SKILL.md +241 -0
  303. package/skills/storytelling-with-data/assets/example_asset.txt +1 -0
  304. package/skills/storytelling-with-data/evals/evals.json +47 -0
  305. package/skills/storytelling-with-data/evals/results.json +13 -0
  306. package/skills/storytelling-with-data/examples/after.md +50 -0
  307. package/skills/storytelling-with-data/examples/before.md +33 -0
  308. package/skills/storytelling-with-data/references/api_reference.md +379 -0
  309. package/skills/storytelling-with-data/references/review-checklist.md +111 -0
  310. package/skills/storytelling-with-data/scripts/chart_review.py +301 -0
  311. package/skills/storytelling-with-data/scripts/example.py +1 -0
  312. package/skills/system-design-interview/SKILL.md +233 -0
  313. package/skills/system-design-interview/assets/example_asset.txt +1 -0
  314. package/skills/system-design-interview/evals/evals.json +46 -0
  315. package/skills/system-design-interview/evals/results.json +13 -0
  316. package/skills/system-design-interview/examples/after.md +94 -0
  317. package/skills/system-design-interview/examples/before.md +27 -0
  318. package/skills/system-design-interview/references/api_reference.md +582 -0
  319. package/skills/system-design-interview/references/review-checklist.md +201 -0
  320. package/skills/system-design-interview/scripts/example.py +1 -0
  321. package/skills/system-design-interview/scripts/new_design.py +421 -0
  322. package/skills/using-asyncio-python/SKILL.md +290 -0
  323. package/skills/using-asyncio-python/assets/example_asset.txt +1 -0
  324. package/skills/using-asyncio-python/evals/evals.json +43 -0
  325. package/skills/using-asyncio-python/evals/results.json +13 -0
  326. package/skills/using-asyncio-python/examples/after.md +68 -0
  327. package/skills/using-asyncio-python/examples/before.md +39 -0
  328. package/skills/using-asyncio-python/references/api_reference.md +267 -0
  329. package/skills/using-asyncio-python/references/review-checklist.md +149 -0
  330. package/skills/using-asyncio-python/scripts/check_blocking.py +270 -0
  331. package/skills/using-asyncio-python/scripts/example.py +1 -0
  332. package/skills/web-scraping-python/SKILL.md +280 -0
  333. package/skills/web-scraping-python/assets/example_asset.txt +1 -0
  334. package/skills/web-scraping-python/evals/evals.json +46 -0
  335. package/skills/web-scraping-python/evals/results.json +13 -0
  336. package/skills/web-scraping-python/examples/after.md +109 -0
  337. package/skills/web-scraping-python/examples/before.md +40 -0
  338. package/skills/web-scraping-python/references/api_reference.md +393 -0
  339. package/skills/web-scraping-python/references/review-checklist.md +163 -0
  340. package/skills/web-scraping-python/scripts/example.py +1 -0
  341. package/skills/web-scraping-python/scripts/new_scraper.py +231 -0
  342. package/skills/writing-plans/audit.json +34 -0
  343. package/tests/agent-detector.test.js +83 -0
  344. package/tests/corrections.test.js +245 -0
  345. package/tests/doctor/hook-installer.test.js +72 -0
  346. package/tests/doctor/usage-tracker.test.js +140 -0
  347. package/tests/engine/benchmark-eval.test.js +31 -0
  348. package/tests/engine/bm25-index.test.js +85 -0
  349. package/tests/engine/capture-command.test.js +35 -0
  350. package/tests/engine/capture.test.js +17 -0
  351. package/tests/engine/graph-augmented-search.test.js +107 -0
  352. package/tests/engine/graph-injector.test.js +44 -0
  353. package/tests/engine/graph.test.js +216 -0
  354. package/tests/engine/hybrid-searcher.test.js +74 -0
  355. package/tests/engine/indexer-bm25.test.js +37 -0
  356. package/tests/engine/mcp-tools.test.js +73 -0
  357. package/tests/engine/project-initializer-mcp.test.js +99 -0
  358. package/tests/engine/query-expander.test.js +36 -0
  359. package/tests/engine/reranker.test.js +51 -0
  360. package/tests/engine/rrf.test.js +49 -0
  361. package/tests/engine/srag-prefix.test.js +47 -0
  362. package/tests/instinct-block.test.js +23 -0
  363. package/tests/mcp-config-writer.test.js +60 -0
  364. package/tests/project-initializer-new-agents.test.js +48 -0
  365. package/tests/rules/rules-manager.test.js +230 -0
  366. package/tests/well-known-builder.test.js +40 -0
  367. package/tests/wizard/integration-detector.test.js +31 -0
  368. package/tests/wizard/project-detector.test.js +51 -0
  369. package/tests/wizard/prompt-session.test.js +61 -0
  370. package/tests/wizard/prompt.test.js +16 -0
  371. package/tests/wizard/registry-embeddings.test.js +35 -0
  372. package/tests/wizard/skill-recommender.test.js +34 -0
  373. package/tests/wizard/slot-count.test.js +25 -0
  374. package/vercel.json +21 -0
@@ -0,0 +1,206 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ pre-review.py — Pre-analysis script for Clean Code reviews.
4
+ Usage: python pre-review.py <file>
5
+
6
+ Produces a structured report covering file stats, long functions, deep nesting,
7
+ argument count violations, and linter output — ready to feed an agent as context.
8
+ """
9
+
10
+ import ast
11
+ import os
12
+ import subprocess
13
+ import sys
14
+ from pathlib import Path
15
+
16
+
17
+ def detect_language(path: Path) -> str:
18
+ return {
19
+ ".py": "python",
20
+ ".js": "javascript",
21
+ ".ts": "typescript",
22
+ ".java": "java",
23
+ ".go": "go",
24
+ ".rb": "ruby",
25
+ ".rs": "rust",
26
+ }.get(path.suffix.lower(), "unknown")
27
+
28
+
29
+ def count_lines(source: str) -> int:
30
+ return len(source.splitlines())
31
+
32
+
33
+ def measure_nesting_depth(node: ast.AST, depth: int = 0) -> int:
34
+ nesting_nodes = (
35
+ ast.If, ast.For, ast.While, ast.With, ast.Try,
36
+ ast.ExceptHandler, ast.AsyncFor, ast.AsyncWith,
37
+ )
38
+ max_depth = depth
39
+ for child in ast.iter_child_nodes(node):
40
+ if isinstance(child, nesting_nodes):
41
+ max_depth = max(max_depth, measure_nesting_depth(child, depth + 1))
42
+ else:
43
+ max_depth = max(max_depth, measure_nesting_depth(child, depth))
44
+ return max_depth
45
+
46
+
47
+ def analyze_python_ast(source: str):
48
+ """Return function/class stats using AST. Returns list of dicts."""
49
+ try:
50
+ tree = ast.parse(source)
51
+ except SyntaxError as exc:
52
+ return None, f"AST parse failed: {exc}"
53
+
54
+ lines = source.splitlines()
55
+ results = []
56
+
57
+ for node in ast.walk(tree):
58
+ if not isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
59
+ continue
60
+
61
+ kind = "class" if isinstance(node, ast.ClassDef) else "function"
62
+ start = node.lineno
63
+ end = node.end_lineno if hasattr(node, "end_lineno") else start
64
+ length = end - start + 1
65
+
66
+ arg_count = 0
67
+ nesting = 0
68
+ if kind == "function":
69
+ args = node.args
70
+ arg_count = (
71
+ len(args.args)
72
+ + len(args.posonlyargs)
73
+ + len(args.kwonlyargs)
74
+ + (1 if args.vararg else 0)
75
+ + (1 if args.kwarg else 0)
76
+ )
77
+ # Don't count 'self' / 'cls'
78
+ first = args.posonlyargs[0].arg if args.posonlyargs else (args.args[0].arg if args.args else None)
79
+ if first in ("self", "cls"):
80
+ arg_count = max(0, arg_count - 1)
81
+ nesting = measure_nesting_depth(node)
82
+
83
+ results.append({
84
+ "kind": kind,
85
+ "name": node.name,
86
+ "start": start,
87
+ "end": end,
88
+ "length": length,
89
+ "arg_count": arg_count,
90
+ "nesting": nesting,
91
+ })
92
+
93
+ return results, None
94
+
95
+
96
+ def run_ruff(filepath: Path):
97
+ """Run ruff on the file; return (output_lines, error_message)."""
98
+ try:
99
+ result = subprocess.run(
100
+ ["ruff", "check", "--output-format", "concise", str(filepath)],
101
+ capture_output=True, text=True, timeout=30,
102
+ )
103
+ output = (result.stdout + result.stderr).strip()
104
+ return output.splitlines() if output else [], None
105
+ except FileNotFoundError:
106
+ return [], "ruff not installed (pip install ruff)"
107
+ except subprocess.TimeoutExpired:
108
+ return [], "ruff timed out"
109
+
110
+
111
+ def separator(char="-", width=70):
112
+ return char * width
113
+
114
+
115
+ def main():
116
+ if len(sys.argv) < 2:
117
+ print("Usage: python pre-review.py <file>")
118
+ sys.exit(1)
119
+
120
+ filepath = Path(sys.argv[1])
121
+ if not filepath.exists():
122
+ print(f"Error: file not found: {filepath}")
123
+ sys.exit(1)
124
+
125
+ source = filepath.read_text(encoding="utf-8", errors="replace")
126
+ language = detect_language(filepath)
127
+ total_lines = count_lines(source)
128
+ file_size = filepath.stat().st_size
129
+
130
+ print(separator("="))
131
+ print(f"CLEAN CODE PRE-REVIEW REPORT")
132
+ print(separator("="))
133
+ print(f"File : {filepath}")
134
+ print(f"Language : {language}")
135
+ print(f"Size : {file_size:,} bytes | {total_lines} lines")
136
+ print()
137
+
138
+ # --- AST analysis (Python only) ---
139
+ if language == "python":
140
+ print(separator())
141
+ print("FUNCTION / CLASS ANALYSIS (AST)")
142
+ print(separator())
143
+ items, err = analyze_python_ast(source)
144
+ if err:
145
+ print(f" Warning: {err}")
146
+ elif items:
147
+ long_fns = [i for i in items if i["kind"] == "function" and i["length"] > 20]
148
+ deep_fns = [i for i in items if i["kind"] == "function" and i["nesting"] >= 3]
149
+ many_args = [i for i in items if i["kind"] == "function" and i["arg_count"] > 3]
150
+
151
+ print(f" Total functions : {sum(1 for i in items if i['kind'] == 'function')}")
152
+ print(f" Total classes : {sum(1 for i in items if i['kind'] == 'class')}")
153
+ print()
154
+
155
+ if long_fns:
156
+ print(f" [!] LONG FUNCTIONS (>20 lines) — Clean Code: functions should do one thing")
157
+ for fn in long_fns:
158
+ print(f" {fn['name']}() lines {fn['start']}-{fn['end']} ({fn['length']} lines)")
159
+ else:
160
+ print(" [OK] No functions exceed 20 lines.")
161
+
162
+ print()
163
+ if deep_fns:
164
+ print(f" [!] DEEP NESTING (>=3 levels) — consider early returns or extraction")
165
+ for fn in deep_fns:
166
+ print(f" {fn['name']}() line {fn['start']} (max nesting: {fn['nesting']})")
167
+ else:
168
+ print(" [OK] No functions have excessive nesting depth.")
169
+
170
+ print()
171
+ if many_args:
172
+ print(f" [!] TOO MANY ARGUMENTS (>3) — Clean Code: prefer parameter objects")
173
+ for fn in many_args:
174
+ print(f" {fn['name']}() line {fn['start']} ({fn['arg_count']} args)")
175
+ else:
176
+ print(" [OK] All functions have 3 or fewer arguments.")
177
+ else:
178
+ print(" No functions or classes found.")
179
+ print()
180
+
181
+ # --- Linter output ---
182
+ print(separator())
183
+ if language == "python":
184
+ print("RUFF LINTER OUTPUT")
185
+ print(separator())
186
+ ruff_lines, ruff_err = run_ruff(filepath)
187
+ if ruff_err:
188
+ print(f" Note: {ruff_err}")
189
+ elif ruff_lines:
190
+ for line in ruff_lines:
191
+ print(f" {line}")
192
+ else:
193
+ print(" [OK] ruff found no issues.")
194
+ else:
195
+ print(f"LINTER")
196
+ print(separator())
197
+ print(f" Automated linting not configured for '{language}'. Run language-specific tools manually.")
198
+
199
+ print()
200
+ print(separator("="))
201
+ print("END OF PRE-REVIEW REPORT")
202
+ print(separator("="))
203
+
204
+
205
+ if __name__ == "__main__":
206
+ main()
@@ -0,0 +1,267 @@
1
+ ---
2
+ name: data-intensive-patterns
3
+ version: "1.0"
4
+ license: MIT
5
+ tags: [architecture, databases, distributed-systems]
6
+ description: >
7
+ Generate and review data-intensive application code using patterns from Martin Kleppmann's
8
+ "Designing Data-Intensive Applications." Use this skill whenever the user asks about data
9
+ storage engines, replication, partitioning, transactions, distributed systems, batch or stream
10
+ processing, encoding/serialization, consistency models, consensus, event sourcing, CQRS,
11
+ change data capture, or anything related to building reliable, scalable, and maintainable
12
+ data systems. Trigger on phrases like "data-intensive", "replication", "partitioning",
13
+ "sharding", "LSM-tree", "B-tree", "transaction isolation", "distributed consensus",
14
+ "stream processing", "batch processing", "event sourcing", "CQRS", "CDC",
15
+ "change data capture", "serialization format", "schema evolution", "consensus algorithm",
16
+ "leader election", "total order broadcast", or "data pipeline."
17
+ ---
18
+
19
+ # Data-Intensive Patterns Skill
20
+
21
+ You are an expert data systems architect grounded in the patterns and principles from
22
+ Martin Kleppmann's *Designing Data-Intensive Applications*. You help developers in two modes:
23
+
24
+ 1. **Code Generation** — Produce well-structured code for data-intensive components
25
+ 2. **Code Review** — Analyze existing data system code and recommend improvements
26
+
27
+ ## How to Decide Which Mode
28
+
29
+ - If the user asks you to *build*, *create*, *generate*, *implement*, or *scaffold* something → **Code Generation**
30
+ - If the user asks you to *review*, *check*, *improve*, *audit*, or *critique* code → **Code Review**
31
+ - If ambiguous, ask briefly which mode they'd prefer
32
+
33
+ ---
34
+
35
+ ## Mode 1: Code Generation
36
+
37
+ When generating data-intensive application code, follow this decision flow:
38
+
39
+ ### Step 1 — Understand the Data Requirements
40
+
41
+ Ask (or infer from context) what the system's data characteristics are:
42
+
43
+ - **Read/write ratio** — Is it read-heavy (analytics, caching) or write-heavy (logging, IoT)?
44
+ - **Consistency requirements** — Does it need strong consistency or is eventual consistency acceptable?
45
+ - **Scale expectations** — Single node sufficient, or does it need horizontal scaling?
46
+ - **Latency requirements** — Real-time (milliseconds), near-real-time (seconds), or batch (minutes/hours)?
47
+ - **Data model** — Relational, document, graph, time-series, or event log?
48
+
49
+ ### Step 2 — Select the Right Patterns
50
+
51
+ Read `references/patterns-catalog.md` for full pattern details. Quick decision guide:
52
+
53
+ | Problem | Pattern to Apply |
54
+ |---------|-----------------|
55
+ | How to model data? | Relational, Document, or Graph model (Chapter 2) |
56
+ | How to store data on disk? | LSM-Tree (write-optimized) or B-Tree (read-optimized) (Chapter 3) |
57
+ | How to encode data for storage/network? | Avro, Protobuf, Thrift with schema registry (Chapter 4) |
58
+ | How to replicate for high availability? | Single-leader, Multi-leader, or Leaderless replication (Chapter 5) |
59
+ | How to scale beyond one node? | Partitioning by key range or hash (Chapter 6) |
60
+ | How to handle concurrent writes? | Transaction isolation level selection (Chapter 7) |
61
+ | How to handle partial failures? | Timeouts, retries with idempotency, fencing tokens (Chapter 8) |
62
+ | How to achieve consensus? | Raft/Paxos via ZooKeeper/etcd, or total order broadcast (Chapter 9) |
63
+ | How to process large datasets? | MapReduce or dataflow engines (Spark, Flink) (Chapter 10) |
64
+ | How to process real-time events? | Stream processing with Kafka + Flink/Spark Streaming (Chapter 11) |
65
+ | How to keep derived data in sync? | CDC, event sourcing, or transactional outbox (Chapters 11-12) |
66
+ | How to query across data sources? | CQRS with denormalized read models (Chapters 11-12) |
67
+
68
+ ### Step 3 — Generate the Code
69
+
70
+ Follow these principles when writing code:
71
+
72
+ <core_principles>
73
+ - **Choose the right storage engine** — LSM-trees (LevelDB, RocksDB, Cassandra) for write-heavy workloads; B-trees (PostgreSQL, MySQL InnoDB) for read-heavy workloads with point lookups
74
+ - **Schema evolution from day one** — Use encoding formats that support forward and backward compatibility (Avro with schema registry, Protobuf with field tags)
75
+ - **Replication topology matches the use case** — Single-leader for strong consistency needs; multi-leader for multi-datacenter writes; leaderless for high availability with tunable consistency
76
+ - **Partition for scale, not prematurely** — Key-range partitioning for range scans; hash partitioning for uniform distribution; compound keys for related-data locality
77
+ - **Pick the weakest isolation level that's correct** — Read Committed for most cases; Snapshot Isolation for read-heavy analytics; Serializable only when write skew is a real risk
78
+ - **Idempotent operations everywhere** — Every retry, every message consumer, every saga step must be safe to re-execute
79
+ - **Derive, don't share** — Derived data (caches, search indexes, materialized views) should be rebuilt from the log of record, not maintained by shared writes
80
+ - **End-to-end correctness** — Don't rely on a single component for exactly-once; use idempotency keys and deduplication at application boundaries
81
+ </core_principles>
82
+
83
+ When generating code, produce:
84
+
85
+ 1. **Data model definition** (schema, encoding format, evolution strategy)
86
+ 2. **Storage layer** (engine choice, indexing strategy, partitioning scheme)
87
+ 3. **Replication configuration** (topology, consistency guarantees, failover)
88
+ 4. **Processing pipeline** (batch or stream, with fault tolerance approach)
89
+ 5. **Integration layer** (CDC, event publishing, derived view maintenance)
90
+
91
+ Use the user's preferred language/framework. If unspecified, adapt to the most natural fit:
92
+ Java/Scala for Kafka/Spark/Flink pipelines, Python for data processing scripts, Go for
93
+ infrastructure components, SQL for schema definitions.
94
+
95
+ ### Code Generation Examples
96
+
97
+ <examples>
98
+ <example id="1" title="Event-Sourced Order System with CDC">
99
+ ```
100
+ User: "Build an order tracking system that keeps a search index and analytics dashboard in sync"
101
+
102
+ You should generate:
103
+ - Order aggregate with event log (OrderPlaced, OrderShipped, OrderDelivered, OrderCancelled)
104
+ - Event store schema with append-only writes
105
+ - CDC connector configuration (Debezium) to capture changes
106
+ - Kafka topic setup with partitioning by order ID
107
+ - Stream processor that maintains:
108
+ - Elasticsearch index for order search (denormalized view)
109
+ - Analytics materialized view for dashboard queries
110
+ - Idempotent consumers with deduplication by event ID
111
+ - Schema registry configuration for event evolution
112
+ ```
113
+ </example>
114
+
115
+ <example id="2" title="Partitioned Time-Series Ingestion">
116
+ ```
117
+ User: "I need to ingest millions of sensor readings per second with range queries by time"
118
+
119
+ You should generate:
120
+ - LSM-tree based storage (e.g., Cassandra or TimescaleDB schema)
121
+ - Partitioning strategy: compound key (sensor_id, time_bucket)
122
+ - Write path: batch writes with write-ahead log
123
+ - Read path: range scan by time window within a partition
124
+ - Replication: factor of 3 with tunable consistency (ONE for writes, QUORUM for reads)
125
+ - Compaction strategy: time-window compaction for efficient cleanup
126
+ - Retention policy configuration
127
+ ```
128
+ </example>
129
+
130
+ <example id="3" title="Distributed Transaction with Saga">
131
+ ```
132
+ User: "Coordinate a payment and inventory reservation across two services"
133
+
134
+ You should generate:
135
+ - Saga orchestrator with steps and compensating actions
136
+ - Transactional outbox pattern for reliable event publishing
137
+ - Idempotency keys for each saga step
138
+ - Timeout and retry configuration with exponential backoff
139
+ - Dead letter queue for failed messages
140
+ - Monitoring: saga state machine with observable transitions
141
+ ```
142
+ </example>
143
+ </examples>
144
+
145
+ ---
146
+
147
+ ## Mode 2: Code Review
148
+
149
+ When reviewing data-intensive application code, read `references/review-checklist.md` for
150
+ the full checklist. Apply these categories systematically:
151
+
152
+ ### Review Process
153
+
154
+ 1. **Identify the data model** — relational, document, graph, event log? Does the model fit the access patterns?
155
+ 2. **Check storage choices** — is the storage engine appropriate for the workload (read-heavy vs write-heavy)?
156
+ 3. **Check encoding** — are serialization formats evolvable? Forward/backward compatibility maintained?
157
+ 4. **Check replication** — is the replication topology appropriate? Are failover and lag handled?
158
+ 5. **Check partitioning** — are hot spots avoided? Is the partition key well-chosen?
159
+ 6. **Check transactions** — is the isolation level appropriate? Are write skew and phantoms addressed?
160
+ 7. **Check distributed systems concerns** — timeouts, retries, idempotency, fencing tokens present?
161
+ 8. **Check processing pipelines** — are batch/stream jobs fault-tolerant? Exactly-once or at-least-once with idempotency?
162
+ 9. **Check derived data** — are caches/indexes/views maintained via events? Is consistency model acceptable?
163
+ 10. **Check operational readiness** — monitoring, alerting, backpressure handling, graceful degradation?
164
+
165
+ ### Review Output Format
166
+
167
+ Structure your review as:
168
+
169
+ ```
170
+ ## Summary
171
+ One paragraph: what the system does, which patterns it uses, overall assessment.
172
+
173
+ ## Strengths
174
+ What the code does well, which patterns are correctly applied. Be specific and generous:
175
+ name each well-applied pattern explicitly (e.g., "the `from_events` classmethod correctly
176
+ implements event sourcing — the event log is the source of truth"; "CQRS is correctly
177
+ applied: the Order aggregate is the write model, SearchIndexProjection is the read model";
178
+ "optimistic concurrency control via expected_version prevents lost updates").
179
+
180
+ ## Issues Found
181
+ For each genuine issue:
182
+ - **What**: describe the problem
183
+ - **Why it matters**: explain the reliability/scalability/maintainability risk
184
+ - **Pattern to apply**: which data-intensive pattern addresses this
185
+ - **Suggested fix**: concrete code change or restructuring
186
+
187
+ Only include genuine anti-patterns actually present in the code. Do NOT manufacture issues.
188
+
189
+ ## Recommendations (optional)
190
+ For well-designed code, any suggestions are optional future considerations, not required
191
+ fixes. Frame them explicitly: "Future consideration (not a current issue): …". For example,
192
+ snapshotting for long-lived event streams is a performance optimization for the future, not
193
+ a current violation of any pattern.
194
+ ```
195
+
196
+ ### Reviewing Well-Designed Code
197
+
198
+ When you encounter well-designed code that correctly applies data-intensive patterns,
199
+ **your primary job is to recognize and praise the good design**, not to find problems.
200
+
201
+ Key patterns to recognize and praise explicitly when present:
202
+
203
+ <strengths_to_praise>
204
+ - **Event sourcing with `from_events`** — aggregate state rebuilt from the event log means the log is the source of truth (Ch 11)
205
+ - **Optimistic concurrency via `expected_version`** — prevents lost updates without pessimistic locking (Ch 7)
206
+ - **Immutable event objects** — frozen dataclasses/records for events enforce append-only semantics (Ch 11)
207
+ - **Idempotent consumers with deduplication by event ID** — makes projections safe to replay (Ch 11)
208
+ - **CQRS — write model (aggregate) separate from read model (projection)** — enables independent scaling (Ch 11)
209
+ - **Transactional outbox** — atomically writes event and publishes it (Ch 11)
210
+ - **Snapshotting** — when suggested, frame it as a future optimization for performance, not a current deficiency
211
+ </strengths_to_praise>
212
+
213
+ For well-designed systems: if you have no genuine concerns, state that clearly. Any
214
+ suggestions for well-designed code must go in the **Recommendations** section and must be
215
+ framed as optional future optimizations — never as "Issues Found", never described as
216
+ "worth addressing before production."
217
+
218
+ **Specific false positives to reject when the code correctly uses event sourcing with idempotent consumers:**
219
+
220
+ <false_positives>
221
+ - **Schema evolution** — In-process Python/Java dataclasses with no Avro/Protobuf/JSON
222
+ serialization layer do NOT need a schema registry. Absence of a serialization format is
223
+ NOT a defect. Only flag schema evolution when there is an explicit encoding format present.
224
+ - **Atomicity gap** — If projections implement `_already_processed(event_id)` or similar
225
+ deduplication, the atomicity gap is handled. This is the correct pattern; do NOT flag it
226
+ as a production-blocking issue.
227
+ - **Snapshotting** — Always a future performance optimization, never a current deficiency.
228
+ </false_positives>
229
+
230
+ ### Common Anti-Patterns to Flag
231
+
232
+ <anti_patterns>
233
+ - **Wrong storage engine for the workload** — Using B-tree for append-heavy logging; using LSM-tree where point reads dominate
234
+ - **Missing schema evolution strategy** — Encoding formats (Avro/Protobuf/JSON) without backward/forward compatibility; only applicable when there is an explicit serialization layer
235
+ - **Inappropriate isolation level for check-then-act patterns** — Using READ COMMITTED or Snapshot Isolation (REPEATABLE READ) for check-then-act patterns (read a value, decide to write based on it) allows write skew: two concurrent transactions both pass the check and both write, violating the invariant; READ COMMITTED is insufficient because it only prevents dirty reads, not this race; Snapshot Isolation is also insufficient because both transactions read the same pre-write snapshot; only SERIALIZABLE isolation or SELECT FOR UPDATE (which materializes the conflict as a row lock) prevents write skew (Ch 7: write skew, phantoms, serializable snapshot isolation)
236
+ - **Shared mutable state across services** — Multiple services writing to the same database table
237
+ - **Synchronous replication where async suffices** — Unnecessary latency from waiting for all replicas
238
+ - **Hot partition** — All writes landing on the same partition (e.g., monotonically increasing key with hash partitioning, or celebrity user in social feed)
239
+ - **No idempotency on retries** — Retry logic without deduplication keys, causing duplicate side effects
240
+ - **Distributed transactions via 2PC** — Two-phase commit across heterogeneous systems (fragile, blocks on coordinator failure)
241
+ - **Missing backpressure** — Producer overwhelms consumer with no flow control
242
+ - **Derived data maintained by dual writes** — Updating both primary store and derived view in application code instead of via CDC/events
243
+ - **Clock-dependent ordering** — Using wall-clock timestamps for event ordering across nodes instead of logical clocks or sequence numbers
244
+ - **Synchronous chain without idempotency** — Chained service calls where any downstream failure leaves the system inconsistent; non-idempotent endpoints get called multiple times on retry, causing duplicate side effects (e.g., double reservation, double charge); the recommended fix is to replace the full chain with event-driven processing: publish a domain event (`OrderPlaced`, `PaymentInitiated`) and have each downstream service consume it asynchronously — this is not the same as wrapping the chain in a saga, which is still synchronous orchestration
245
+ - **Non-transactional services in synchronous chain** — Side-effect-only services (notifications, emails, analytics) should never be in a synchronous chain; their failure must not roll back business-critical operations
246
+ - **No event log in stateful services** — Services that mutate state without an append-only event log have no replayable source of truth; flag this as a concrete reliability issue, not a vague "future consideration" — crash recovery, audit trails, and derived view rebuilding all require a durable event log or WAL (Ch 11)
247
+ - **Event-driven transition without transactional outbox** — When recommending replacement of a synchronous chain with event-driven processing, always specify the transactional outbox pattern: write the domain state change and the outbox event in the same local database transaction, then have a separate relay process publish events to the message broker; this is the only way to guarantee events are not lost on crash between the write and the publish (Ch 11)
248
+ - **DELETE/cancel without idempotency tracking** — While a bare SQL DELETE is accidentally idempotent (deleting a non-existent row is a no-op), cancel operations in distributed contexts (sagas, at-least-once message delivery, API retries) need idempotency keys or logged outcomes to ensure exactly-once semantics; flag cancel handlers that lack deduplication
249
+ - **OLTP and analytics sharing the same tables** — Analytics queries (aggregations, range scans, multi-table JOINs) running against the same tables as transactional workloads cause lock contention and slow both; separate the OLTP write path from the OLAP read path via CDC, batch export, or a dedicated analytics store (Ch 10: OLTP vs OLAP separation)
250
+ </anti_patterns>
251
+
252
+ ---
253
+
254
+ ## General Guidelines
255
+
256
+ <guidelines>
257
+ - Be practical, not dogmatic. A single-node PostgreSQL database handles most workloads.
258
+ Recommend distributed patterns only when the problem actually demands them.
259
+ - The three pillars are **reliability** (fault-tolerant), **scalability** (handles growth),
260
+ and **maintainability** (easy to evolve). Every recommendation should advance at least one.
261
+ - Distributed systems add complexity. If the system can run on a single node, say so.
262
+ Kleppmann himself emphasizes understanding trade-offs before reaching for distribution.
263
+ - When the user's data fits in memory on one machine, a simple in-process data structure
264
+ often beats a distributed system.
265
+ - For deeper pattern details, read `references/patterns-catalog.md` before generating code.
266
+ - For review checklists, read `references/review-checklist.md` before reviewing code.
267
+ </guidelines>
@@ -0,0 +1,54 @@
1
+ {
2
+ "evals": [
3
+ {
4
+ "id": "eval-01-synchronous-rest-no-event-log",
5
+ "prompt": "Review this microservices architecture description and pseudo-code:\n\n```\nSystem: E-commerce order processing\nServices: OrderService, InventoryService, PaymentService, NotificationService\n\nFlow (all synchronous REST over HTTP):\n\n# OrderService.place_order()\nPOST /orders → validates cart\n → GET /inventory/{sku} (blocks on InventoryService response)\n → POST /inventory/reserve (blocks, decrements stock)\n → POST /payments/charge (blocks on PaymentService)\n → POST /notifications/send (blocks on NotificationService)\n → INSERT orders (status='CONFIRMED') into orders_db\n → return 201\n\n# If PaymentService times out:\n# - inventory already reserved, order not yet written\n# - caller gets 504, retries POST /orders\n# - inventory reserved again (double reservation)\n\n# InventoryService\nGET /inventory/{sku} → SELECT stock FROM inventory WHERE sku=?\nPOST /inventory/reserve → UPDATE inventory SET stock=stock-qty WHERE sku=?\n\n# Shared database: orders_db is directly accessed by both OrderService\n# and InventoryService for reporting queries\n```",
6
+ "expectations": [
7
+ "Flags the fully synchronous REST chain as a distributed systems anti-pattern: a failure or timeout in any downstream service leaves the system in an inconsistent state (Ch 8: partial failures, timeouts, retries)",
8
+ "Identifies the double-reservation bug as a direct consequence of no idempotency on POST /inventory/reserve; recommends idempotency keys on all mutating endpoints (Ch 8: idempotent operations everywhere)",
9
+ "Flags the absence of an event log or write-ahead log: there is no source of truth to replay from if a service crashes mid-flow (Ch 11: event sourcing, log as source of truth)",
10
+ "Flags shared database access between OrderService and InventoryService as shared mutable state across services, violating service autonomy (Ch 12: shared mutable state across services anti-pattern)",
11
+ "Recommends replacing the synchronous chain with an event-driven approach: publish an OrderPlaced event, have downstream services react asynchronously (Ch 11: stream processing, event-driven)",
12
+ "Recommends the transactional outbox pattern to atomically write the order and publish the event in one local transaction (Ch 11: CDC, transactional outbox)",
13
+ "Notes that NotificationService is particularly ill-suited for the synchronous chain since a notification failure should not roll back a payment"
14
+ ]
15
+ },
16
+ {
17
+ "id": "eval-02-schema-without-access-patterns",
18
+ "prompt": "Review this database schema design:\n\n```sql\n-- Proposed schema for a social media analytics platform\n-- Requirements: show user activity feeds, compute engagement scores,\n-- support time-range queries on posts, and generate daily digest emails\n\nCREATE TABLE users (\n id BIGINT PRIMARY KEY,\n username VARCHAR(50),\n email VARCHAR(255),\n created_at TIMESTAMP\n);\n\nCREATE TABLE posts (\n id BIGINT PRIMARY KEY,\n user_id BIGINT REFERENCES users(id),\n content TEXT,\n created_at TIMESTAMP\n);\n\nCREATE TABLE events (\n id BIGINT PRIMARY KEY,\n post_id BIGINT REFERENCES posts(id),\n user_id BIGINT REFERENCES users(id),\n event_type VARCHAR(20), -- 'like', 'comment', 'share', 'view'\n occurred_at TIMESTAMP\n);\n\n-- All analytics queries will be run against these three tables via JOINs\n-- Indexes: only the primary keys above\n```",
19
+ "expectations": [
20
+ "Flags the absence of secondary indexes for the primary access patterns: time-range queries on posts (created_at) and per-user activity (user_id + created_at) will require full table scans (Ch 3: indexing strategies, B-tree vs LSM-tree, DDIA Chapter 3)",
21
+ "Identifies the schema is designed around normalization, not around read patterns; for analytics (read-heavy) workloads, this forces expensive multi-table JOINs on every query (Ch 2: document model vs relational model, denormalization for read-heavy workloads)",
22
+ "Flags that the `events` table mixing four different event types in one table with no partitioning will become a hot write target and a slow scan table as it grows (Ch 6: partitioning to spread load)",
23
+ "Notes there is no derived/materialized view for engagement scores, meaning every score computation re-scans all events; recommends pre-computed aggregates or a materialized view updated via CDC (Ch 11: derived data, CQRS)",
24
+ "Flags that the schema has no time-based partitioning on the `events` table despite time-range queries being a stated requirement (Ch 6: partitioning by key range for range scan efficiency)",
25
+ "Recommends separating the OLTP write path from the OLAP analytics read path, using CDC or batch export to feed an analytics store (Ch 10: batch processing, OLTP vs OLAP separation)"
26
+ ]
27
+ },
28
+ {
29
+ "id": "eval-04-write-skew-transaction-isolation",
30
+ "prompt": "Review this room booking service:\n\n```python\nclass RoomBookingService:\n def book_room(\n self,\n room_id: int,\n user_id: int,\n start_date: date,\n end_date: date,\n ) -> bool:\n with self.db.transaction(): # READ COMMITTED isolation (default)\n # Check availability\n count = self.db.query(\n \"SELECT COUNT(*) FROM bookings \"\n \"WHERE room_id = %s AND start_date < %s AND end_date > %s\",\n (room_id, end_date, start_date)\n ).fetchone()[0]\n\n if count > 0:\n return False # already booked\n\n # Reserve the room\n self.db.execute(\n \"INSERT INTO bookings (room_id, user_id, start_date, end_date) \"\n \"VALUES (%s, %s, %s, %s)\",\n (room_id, user_id, start_date, end_date)\n )\n return True\n\n def cancel_booking(self, booking_id: int, user_id: int) -> None:\n self.db.execute(\n \"DELETE FROM bookings WHERE id = %s AND user_id = %s\",\n (booking_id, user_id)\n )\n```",
31
+ "expectations": [
32
+ "Identifies the write skew bug: two concurrent transactions both read count=0 under READ COMMITTED, both pass the check, and both insert — resulting in a double booking for the same room and dates (Ch 7: write skew, check-then-act pattern)",
33
+ "Explains that READ COMMITTED prevents dirty reads but does NOT prevent write skew — each transaction sees a consistent snapshot at statement time, but the check-and-insert is not atomic (Ch 7: isolation levels)",
34
+ "Recommends a concrete fix: either upgrade to SERIALIZABLE isolation, or use SELECT FOR UPDATE on the availability check to acquire a pessimistic lock (Ch 7: preventing write skew, materializing conflicts)",
35
+ "Notes that Snapshot Isolation (REPEATABLE READ) also does NOT prevent this write skew pattern — both transactions still read the pre-insert snapshot (Ch 7: snapshot isolation limitations)",
36
+ "Flags that cancel_booking has no idempotency protection — retrying a DELETE is safe by coincidence, but a retry after partial failure in a larger saga could cause correctness issues; recommends idempotency keys or at-minimum logging the delete outcome (Ch 8: idempotent operations)"
37
+ ]
38
+ },
39
+ {
40
+ "id": "eval-03-well-designed-event-sourced-system",
41
+ "prompt": "Review this event-sourced order system design:\n\n```python\n# Event definitions\n@dataclass(frozen=True)\nclass OrderPlaced:\n order_id: str\n customer_id: str\n items: tuple # immutable list of (sku, qty, price)\n occurred_at: datetime\n event_id: str = field(default_factory=lambda: str(uuid4()))\n\n@dataclass(frozen=True)\nclass OrderShipped:\n order_id: str\n tracking_number: str\n occurred_at: datetime\n event_id: str = field(default_factory=lambda: str(uuid4()))\n\n@dataclass(frozen=True)\nclass OrderCancelled:\n order_id: str\n reason: str\n occurred_at: datetime\n event_id: str = field(default_factory=lambda: str(uuid4()))\n\n# Append-only event store\nclass EventStore:\n def append(self, stream_id: str, events: list, expected_version: int) -> None:\n \"\"\"Append events with optimistic concurrency check.\"\"\"\n ...\n\n def load(self, stream_id: str) -> list:\n \"\"\"Load all events for a stream in order.\"\"\"\n ...\n\n# Aggregate rebuilt from events\nclass Order:\n def __init__(self):\n self.status = None\n self.items = []\n self._version = 0\n\n @classmethod\n def from_events(cls, events: list) -> 'Order':\n order = cls()\n for event in events:\n order._apply(event)\n return order\n\n def _apply(self, event):\n match event:\n case OrderPlaced(items=items):\n self.status = 'placed'\n self.items = list(items)\n case OrderShipped():\n self.status = 'shipped'\n case OrderCancelled():\n self.status = 'cancelled'\n self._version += 1\n\n# Idempotent consumer for search index projection\nclass SearchIndexProjection:\n def handle(self, event, event_id: str) -> None:\n if self._already_processed(event_id):\n return\n # update search index\n self._mark_processed(event_id)\n```",
42
+ "expectations": [
43
+ "Recognizes this is a well-designed event-sourced system and says so explicitly",
44
+ "Praises the append-only event store with optimistic concurrency control via `expected_version` preventing lost updates (Ch 7: transaction isolation, write conflicts)",
45
+ "Praises rebuilding aggregate state from events via `from_events` — the event log is the source of truth (Ch 11: event sourcing, log-centric architecture)",
46
+ "Praises frozen dataclasses for events ensuring immutability, which is correct for an append-only log (Ch 11: immutable events)",
47
+ "Praises the idempotent consumer with deduplication by `event_id` in `SearchIndexProjection` making the projection safe to replay (Ch 11: idempotent consumers, exactly-once semantics)",
48
+ "Praises the separation of the write model (Order aggregate) from the read model (SearchIndexProjection) as CQRS (Ch 11: CQRS, derived data)",
49
+ "Does NOT manufacture issues to appear thorough; any suggestions are explicitly framed as minor optional improvements",
50
+ "May suggest snapshotting for long-lived streams as a performance optimization, but frames it as a future concern, not a current violation"
51
+ ]
52
+ }
53
+ ]
54
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "pass_rate": 1,
3
+ "passed": 26,
4
+ "total": 26,
5
+ "baseline_pass_rate": 0.769,
6
+ "baseline_passed": 20,
7
+ "baseline_total": 26,
8
+ "delta": 0.231,
9
+ "model": "default",
10
+ "evals_run": 4,
11
+ "date": "2026-03-29",
12
+ "non_standard_provider": true
13
+ }
@@ -0,0 +1,61 @@
1
+ # After
2
+
3
+ An event-driven architecture where writes go through a message log, read models are derived via CDC, read replicas serve analytics, and the command/query paths are separated.
4
+
5
+ ```
6
+ ARCHITECTURE: E-Commerce Platform (Event-Driven + CQRS)
7
+
8
+ WRITE PATH
9
+ ──────────
10
+ [Mobile App / Web Browser]
11
+ │ REST (commands only: place order, update product)
12
+ v
13
+ [API Gateway] ──> [Order Command Service] ──> [Orders DB - Postgres]
14
+
15
+ [Debezium CDC connector]
16
+
17
+ v
18
+ [Kafka: order.events topic]
19
+ (append-only event log,
20
+ partitioned by order_id)
21
+
22
+ READ PATH (derived models — rebuilt from event log, no dual-writes)
23
+ ──────────────────────────────────────────────────────────────────
24
+ [Kafka: order.events]
25
+
26
+ ├──> [Inventory Consumer] ──> [Inventory Read DB - Postgres replica]
27
+ │ (product weekly sales view)
28
+
29
+ ├──> [Search Consumer] ──> [Elasticsearch Index]
30
+ │ (product search, updated async)
31
+
32
+ └──> [Analytics Consumer] ──> [BigQuery Streaming Insert]
33
+ (append-only fact table,
34
+ no load on production DB)
35
+
36
+ QUERY ENDPOINTS (served from read models, not production write DB)
37
+ ──────────────────────────────────────────────────────────────────
38
+ GET /inventory/reorder-candidates → Inventory Read DB
39
+ GET /search/products?q=... → Elasticsearch
40
+ GET /reports/revenue?period=... → BigQuery
41
+
42
+ ASYNC COORDINATION (replaces synchronous call chain)
43
+ ────────────────────────────────────────────────────
44
+ Place order → write Orders DB → CDC → Kafka
45
+ → Payment Service consumes event → publishes PaymentAuthorized
46
+ → Notification Service consumes PaymentAuthorized → sends email
47
+ (no synchronous chain; each step is independently retried)
48
+
49
+ CONSISTENCY MODEL
50
+ ─────────────────
51
+ Orders DB → strongly consistent (single Postgres primary)
52
+ Read models → eventually consistent (seconds of lag, acceptable for reads)
53
+ Analytics → eventually consistent (minutes of lag, acceptable for reports)
54
+ ```
55
+
56
+ Key improvements:
57
+ - Append-only event log (Kafka) is the single source of truth — derived views are rebuilt from it, never maintained by dual-writes (Ch 11: derived data vs. system of record)
58
+ - CDC via Debezium captures changes from the Orders DB atomically — no risk of writing to DB and failing to publish the event (Ch 11: Change Data Capture)
59
+ - Analytics consumers write to BigQuery directly from Kafka — no SELECT queries on the production Orders DB (Ch 10: separation of OLTP and OLAP)
60
+ - CQRS separates command endpoints (write path) from query endpoints (read path) — each can scale independently
61
+ - The synchronous call chain (place order → payment → notification) is replaced by event-driven coordination — failure of one consumer does not block the order write
@@ -0,0 +1,38 @@
1
+ # Before
2
+
3
+ A text architecture diagram showing an e-commerce platform where every component communicates synchronously via REST with no event log, no read replicas, and no separation of read/write paths.
4
+
5
+ ```
6
+ ARCHITECTURE: E-Commerce Platform (Synchronous REST Only)
7
+
8
+ [Mobile App] ──REST──> [API Server]
9
+ [Web Browser] ──REST──> [API Server]
10
+
11
+ ┌───────────────┼──────────────────┐
12
+ │ │ │
13
+ v v v
14
+ [Order DB] [Product DB] [User DB]
15
+ (Postgres) (Postgres) (Postgres)
16
+ │ │
17
+ v v
18
+ [Analytics REST] [Search REST] (both query
19
+ calls Order DB calls Product production
20
+ directly via DB directly DBs live)
21
+ SQL over HTTP
22
+
23
+ FLOWS:
24
+ Place order → API → write Order DB → REST call to
25
+ Inventory Service → REST call to
26
+ Payment Service → REST call to
27
+ Notification Service
28
+ (all synchronous, chain fails if any step fails)
29
+
30
+ Dashboard → API → query Order DB, Product DB, User DB
31
+ in sequence (3 serial DB queries on write path)
32
+
33
+ Search → API → query Product DB directly
34
+ (full table scans, no index service)
35
+
36
+ Reports → Analytics service polls Order DB every 5 min
37
+ via REST (puts load on production DB)
38
+ ```