autonomous-coding-toolkit 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 (324) hide show
  1. package/.claude-plugin/marketplace.json +22 -0
  2. package/.claude-plugin/plugin.json +13 -0
  3. package/LICENSE +21 -0
  4. package/Makefile +21 -0
  5. package/README.md +140 -0
  6. package/SECURITY.md +28 -0
  7. package/agents/bash-expert.md +113 -0
  8. package/agents/dependency-auditor.md +138 -0
  9. package/agents/integration-tester.md +120 -0
  10. package/agents/lesson-scanner.md +149 -0
  11. package/agents/python-expert.md +179 -0
  12. package/agents/service-monitor.md +141 -0
  13. package/agents/shell-expert.md +147 -0
  14. package/benchmarks/runner.sh +147 -0
  15. package/benchmarks/tasks/01-rest-endpoint/rubric.sh +29 -0
  16. package/benchmarks/tasks/01-rest-endpoint/task.md +17 -0
  17. package/benchmarks/tasks/02-refactor-module/task.md +8 -0
  18. package/benchmarks/tasks/03-fix-integration-bug/task.md +8 -0
  19. package/benchmarks/tasks/04-add-test-coverage/task.md +8 -0
  20. package/benchmarks/tasks/05-multi-file-feature/task.md +8 -0
  21. package/bin/act.js +238 -0
  22. package/commands/autocode.md +6 -0
  23. package/commands/cancel-ralph.md +18 -0
  24. package/commands/code-factory.md +53 -0
  25. package/commands/create-prd.md +55 -0
  26. package/commands/ralph-loop.md +18 -0
  27. package/commands/run-plan.md +117 -0
  28. package/commands/submit-lesson.md +122 -0
  29. package/docs/ARCHITECTURE.md +630 -0
  30. package/docs/CONTRIBUTING.md +125 -0
  31. package/docs/lessons/0001-bare-exception-swallowing.md +34 -0
  32. package/docs/lessons/0002-async-def-without-await.md +28 -0
  33. package/docs/lessons/0003-create-task-without-callback.md +28 -0
  34. package/docs/lessons/0004-hardcoded-test-counts.md +28 -0
  35. package/docs/lessons/0005-sqlite-without-closing.md +33 -0
  36. package/docs/lessons/0006-venv-pip-path.md +27 -0
  37. package/docs/lessons/0007-runner-state-self-rejection.md +35 -0
  38. package/docs/lessons/0008-quality-gate-blind-spot.md +33 -0
  39. package/docs/lessons/0009-parser-overcount-empty-batches.md +36 -0
  40. package/docs/lessons/0010-local-outside-function-bash.md +33 -0
  41. package/docs/lessons/0011-batch-tests-for-unimplemented-code.md +36 -0
  42. package/docs/lessons/0012-api-markdown-unescaped-chars.md +33 -0
  43. package/docs/lessons/0013-export-prefix-env-parsing.md +33 -0
  44. package/docs/lessons/0014-decorator-registry-import-side-effect.md +43 -0
  45. package/docs/lessons/0015-frontend-backend-schema-drift.md +43 -0
  46. package/docs/lessons/0016-event-driven-cold-start-seeding.md +44 -0
  47. package/docs/lessons/0017-copy-paste-logic-diverges.md +43 -0
  48. package/docs/lessons/0018-layer-passes-pipeline-broken.md +45 -0
  49. package/docs/lessons/0019-systemd-envfile-ignores-export.md +41 -0
  50. package/docs/lessons/0020-persist-state-incrementally.md +44 -0
  51. package/docs/lessons/0021-dual-axis-testing.md +48 -0
  52. package/docs/lessons/0022-jsx-factory-shadowing.md +43 -0
  53. package/docs/lessons/0023-static-analysis-spiral.md +51 -0
  54. package/docs/lessons/0024-shared-pipeline-implementation.md +55 -0
  55. package/docs/lessons/0025-defense-in-depth-all-entry-points.md +65 -0
  56. package/docs/lessons/0026-linter-no-rules-false-enforcement.md +54 -0
  57. package/docs/lessons/0027-jsx-silent-prop-drop.md +64 -0
  58. package/docs/lessons/0028-no-infrastructure-in-client-code.md +49 -0
  59. package/docs/lessons/0029-never-write-secrets-to-files.md +61 -0
  60. package/docs/lessons/0030-cache-merge-not-replace.md +62 -0
  61. package/docs/lessons/0031-verify-units-at-boundaries.md +66 -0
  62. package/docs/lessons/0032-module-lifecycle-subscribe-unsubscribe.md +89 -0
  63. package/docs/lessons/0033-async-iteration-mutable-snapshot.md +72 -0
  64. package/docs/lessons/0034-caller-missing-await-silent-discard.md +65 -0
  65. package/docs/lessons/0035-duplicate-registration-silent-overwrite.md +85 -0
  66. package/docs/lessons/0036-websocket-dirty-disconnect.md +33 -0
  67. package/docs/lessons/0037-parallel-agents-worktree-corruption.md +31 -0
  68. package/docs/lessons/0038-subscribe-no-stored-ref.md +36 -0
  69. package/docs/lessons/0039-fallback-or-default-hides-bugs.md +34 -0
  70. package/docs/lessons/0040-event-firehose-filter-first.md +36 -0
  71. package/docs/lessons/0041-ambiguous-base-dir-path-nesting.md +32 -0
  72. package/docs/lessons/0042-spec-compliance-insufficient.md +36 -0
  73. package/docs/lessons/0043-exact-count-extensible-collections.md +32 -0
  74. package/docs/lessons/0044-relative-file-deps-worktree.md +39 -0
  75. package/docs/lessons/0045-iterative-design-improvement.md +33 -0
  76. package/docs/lessons/0046-plan-assertion-math-bugs.md +38 -0
  77. package/docs/lessons/0047-pytest-single-threaded-default.md +37 -0
  78. package/docs/lessons/0048-integration-wiring-batch.md +40 -0
  79. package/docs/lessons/0049-ab-verification.md +41 -0
  80. package/docs/lessons/0050-editing-sourced-files-during-execution.md +33 -0
  81. package/docs/lessons/0051-infrastructure-fixes-cant-self-heal.md +30 -0
  82. package/docs/lessons/0052-uncommitted-changes-poison-quality-gates.md +31 -0
  83. package/docs/lessons/0053-jq-compact-flag-inconsistency.md +31 -0
  84. package/docs/lessons/0054-parser-matches-inside-code-blocks.md +30 -0
  85. package/docs/lessons/0055-agents-compensate-for-garbled-prompts.md +31 -0
  86. package/docs/lessons/0056-grep-count-exit-code-on-zero.md +42 -0
  87. package/docs/lessons/0057-new-artifacts-break-git-clean-gates.md +42 -0
  88. package/docs/lessons/0058-dead-config-keys-never-consumed.md +49 -0
  89. package/docs/lessons/0059-contract-test-shared-structures.md +53 -0
  90. package/docs/lessons/0060-set-e-silent-death-in-runners.md +53 -0
  91. package/docs/lessons/0061-context-injection-dirty-state.md +50 -0
  92. package/docs/lessons/0062-sibling-bug-neighborhood-scan.md +29 -0
  93. package/docs/lessons/0063-one-flag-two-lifetimes.md +31 -0
  94. package/docs/lessons/0064-test-passes-wrong-reason.md +31 -0
  95. package/docs/lessons/0065-pipefail-grep-count-double-output.md +39 -0
  96. package/docs/lessons/0066-local-keyword-outside-function.md +37 -0
  97. package/docs/lessons/0067-stdin-hang-non-interactive-shell.md +36 -0
  98. package/docs/lessons/0068-agent-builds-wrong-thing-correctly.md +31 -0
  99. package/docs/lessons/0069-plan-quality-dominates-execution.md +30 -0
  100. package/docs/lessons/0070-spec-echo-back-prevents-drift.md +31 -0
  101. package/docs/lessons/0071-positive-instructions-outperform-negative.md +30 -0
  102. package/docs/lessons/0072-lost-in-the-middle-context-placement.md +30 -0
  103. package/docs/lessons/0073-unscoped-lessons-cause-false-positives.md +30 -0
  104. package/docs/lessons/0074-stale-context-injection-wrong-batch.md +32 -0
  105. package/docs/lessons/0075-research-artifacts-must-persist.md +32 -0
  106. package/docs/lessons/0076-wrong-decomposition-contaminates-downstream.md +30 -0
  107. package/docs/lessons/0077-cherry-pick-merges-need-manual-resolution.md +30 -0
  108. package/docs/lessons/0078-static-review-without-live-test.md +30 -0
  109. package/docs/lessons/0079-integration-wiring-batch-required.md +32 -0
  110. package/docs/lessons/FRAMEWORK.md +161 -0
  111. package/docs/lessons/SUMMARY.md +201 -0
  112. package/docs/lessons/TEMPLATE.md +85 -0
  113. package/docs/plans/2026-02-21-code-factory-v2-design.md +204 -0
  114. package/docs/plans/2026-02-21-code-factory-v2-implementation-plan.md +2189 -0
  115. package/docs/plans/2026-02-21-code-factory-v2-phase4-design.md +537 -0
  116. package/docs/plans/2026-02-21-code-factory-v2-phase4-implementation-plan.md +2012 -0
  117. package/docs/plans/2026-02-21-hardening-pass-design.md +108 -0
  118. package/docs/plans/2026-02-21-hardening-pass-plan.md +1378 -0
  119. package/docs/plans/2026-02-21-mab-research-report.md +406 -0
  120. package/docs/plans/2026-02-21-marketplace-restructure-design.md +240 -0
  121. package/docs/plans/2026-02-21-marketplace-restructure-plan.md +832 -0
  122. package/docs/plans/2026-02-21-phase4-completion-plan.md +697 -0
  123. package/docs/plans/2026-02-21-validator-suite-design.md +148 -0
  124. package/docs/plans/2026-02-21-validator-suite-plan.md +540 -0
  125. package/docs/plans/2026-02-22-mab-research-round2.md +556 -0
  126. package/docs/plans/2026-02-22-mab-run-design.md +462 -0
  127. package/docs/plans/2026-02-22-mab-run-plan.md +2046 -0
  128. package/docs/plans/2026-02-22-operations-design-methodology-research.md +681 -0
  129. package/docs/plans/2026-02-22-research-agent-failure-taxonomy.md +532 -0
  130. package/docs/plans/2026-02-22-research-code-guideline-policies.md +886 -0
  131. package/docs/plans/2026-02-22-research-codebase-audit-refactoring.md +908 -0
  132. package/docs/plans/2026-02-22-research-coding-standards-documentation.md +541 -0
  133. package/docs/plans/2026-02-22-research-competitive-landscape.md +687 -0
  134. package/docs/plans/2026-02-22-research-comprehensive-testing.md +1076 -0
  135. package/docs/plans/2026-02-22-research-context-utilization.md +459 -0
  136. package/docs/plans/2026-02-22-research-cost-quality-tradeoff.md +548 -0
  137. package/docs/plans/2026-02-22-research-lesson-transferability.md +508 -0
  138. package/docs/plans/2026-02-22-research-multi-agent-coordination.md +312 -0
  139. package/docs/plans/2026-02-22-research-phase-integration.md +602 -0
  140. package/docs/plans/2026-02-22-research-plan-quality.md +428 -0
  141. package/docs/plans/2026-02-22-research-prompt-engineering.md +558 -0
  142. package/docs/plans/2026-02-22-research-unconventional-perspectives.md +528 -0
  143. package/docs/plans/2026-02-22-research-user-adoption.md +638 -0
  144. package/docs/plans/2026-02-22-research-verification-effectiveness.md +433 -0
  145. package/docs/plans/2026-02-23-agent-suite-design.md +299 -0
  146. package/docs/plans/2026-02-23-agent-suite-plan.md +578 -0
  147. package/docs/plans/2026-02-23-phase3-cost-infrastructure-design.md +148 -0
  148. package/docs/plans/2026-02-23-phase3-cost-infrastructure-plan.md +1062 -0
  149. package/docs/plans/2026-02-23-research-bash-expert-agent.md +543 -0
  150. package/docs/plans/2026-02-23-research-dependency-auditor-agent.md +564 -0
  151. package/docs/plans/2026-02-23-research-improving-existing-agents.md +503 -0
  152. package/docs/plans/2026-02-23-research-integration-tester-agent.md +454 -0
  153. package/docs/plans/2026-02-23-research-python-expert-agent.md +429 -0
  154. package/docs/plans/2026-02-23-research-service-monitor-agent.md +425 -0
  155. package/docs/plans/2026-02-23-research-shell-expert-agent.md +533 -0
  156. package/docs/plans/2026-02-23-roadmap-to-completion.md +530 -0
  157. package/docs/plans/2026-02-24-headless-module-split-design.md +98 -0
  158. package/docs/plans/2026-02-24-headless-module-split.md +443 -0
  159. package/docs/plans/2026-02-24-lesson-scope-metadata-design.md +228 -0
  160. package/docs/plans/2026-02-24-lesson-scope-metadata-plan.md +968 -0
  161. package/docs/plans/2026-02-24-npm-packaging-design.md +841 -0
  162. package/docs/plans/2026-02-24-npm-packaging-plan.md +1965 -0
  163. package/docs/plans/audit-findings.md +186 -0
  164. package/docs/telegram-notification-format.md +98 -0
  165. package/examples/example-plan.md +51 -0
  166. package/examples/example-prd.json +72 -0
  167. package/examples/example-roadmap.md +33 -0
  168. package/examples/quickstart-plan.md +63 -0
  169. package/hooks/hooks.json +26 -0
  170. package/hooks/setup-symlinks.sh +48 -0
  171. package/hooks/stop-hook.sh +135 -0
  172. package/package.json +47 -0
  173. package/policies/bash.md +71 -0
  174. package/policies/python.md +71 -0
  175. package/policies/testing.md +61 -0
  176. package/policies/universal.md +60 -0
  177. package/scripts/analyze-report.sh +97 -0
  178. package/scripts/architecture-map.sh +145 -0
  179. package/scripts/auto-compound.sh +273 -0
  180. package/scripts/batch-audit.sh +42 -0
  181. package/scripts/batch-test.sh +101 -0
  182. package/scripts/entropy-audit.sh +221 -0
  183. package/scripts/failure-digest.sh +51 -0
  184. package/scripts/generate-ast-rules.sh +96 -0
  185. package/scripts/init.sh +112 -0
  186. package/scripts/lesson-check.sh +428 -0
  187. package/scripts/lib/common.sh +61 -0
  188. package/scripts/lib/cost-tracking.sh +153 -0
  189. package/scripts/lib/ollama.sh +60 -0
  190. package/scripts/lib/progress-writer.sh +128 -0
  191. package/scripts/lib/run-plan-context.sh +215 -0
  192. package/scripts/lib/run-plan-echo-back.sh +231 -0
  193. package/scripts/lib/run-plan-headless.sh +396 -0
  194. package/scripts/lib/run-plan-notify.sh +57 -0
  195. package/scripts/lib/run-plan-parser.sh +81 -0
  196. package/scripts/lib/run-plan-prompt.sh +215 -0
  197. package/scripts/lib/run-plan-quality-gate.sh +132 -0
  198. package/scripts/lib/run-plan-routing.sh +315 -0
  199. package/scripts/lib/run-plan-sampling.sh +170 -0
  200. package/scripts/lib/run-plan-scoring.sh +146 -0
  201. package/scripts/lib/run-plan-state.sh +142 -0
  202. package/scripts/lib/run-plan-team.sh +199 -0
  203. package/scripts/lib/telegram.sh +54 -0
  204. package/scripts/lib/thompson-sampling.sh +176 -0
  205. package/scripts/license-check.sh +74 -0
  206. package/scripts/mab-run.sh +575 -0
  207. package/scripts/module-size-check.sh +146 -0
  208. package/scripts/patterns/async-no-await.yml +5 -0
  209. package/scripts/patterns/bare-except.yml +6 -0
  210. package/scripts/patterns/empty-catch.yml +6 -0
  211. package/scripts/patterns/hardcoded-localhost.yml +9 -0
  212. package/scripts/patterns/retry-loop-no-backoff.yml +12 -0
  213. package/scripts/pipeline-status.sh +197 -0
  214. package/scripts/policy-check.sh +226 -0
  215. package/scripts/prior-art-search.sh +133 -0
  216. package/scripts/promote-mab-lessons.sh +126 -0
  217. package/scripts/prompts/agent-a-superpowers.md +29 -0
  218. package/scripts/prompts/agent-b-ralph.md +29 -0
  219. package/scripts/prompts/judge-agent.md +61 -0
  220. package/scripts/prompts/planner-agent.md +44 -0
  221. package/scripts/pull-community-lessons.sh +90 -0
  222. package/scripts/quality-gate.sh +266 -0
  223. package/scripts/research-gate.sh +90 -0
  224. package/scripts/run-plan.sh +329 -0
  225. package/scripts/scope-infer.sh +159 -0
  226. package/scripts/setup-ralph-loop.sh +155 -0
  227. package/scripts/telemetry.sh +230 -0
  228. package/scripts/tests/run-all-tests.sh +52 -0
  229. package/scripts/tests/test-act-cli.sh +46 -0
  230. package/scripts/tests/test-agents-md.sh +87 -0
  231. package/scripts/tests/test-analyze-report.sh +114 -0
  232. package/scripts/tests/test-architecture-map.sh +89 -0
  233. package/scripts/tests/test-auto-compound.sh +169 -0
  234. package/scripts/tests/test-batch-test.sh +65 -0
  235. package/scripts/tests/test-benchmark-runner.sh +25 -0
  236. package/scripts/tests/test-common.sh +168 -0
  237. package/scripts/tests/test-cost-tracking.sh +158 -0
  238. package/scripts/tests/test-echo-back.sh +180 -0
  239. package/scripts/tests/test-entropy-audit.sh +146 -0
  240. package/scripts/tests/test-failure-digest.sh +66 -0
  241. package/scripts/tests/test-generate-ast-rules.sh +145 -0
  242. package/scripts/tests/test-helpers.sh +82 -0
  243. package/scripts/tests/test-init.sh +47 -0
  244. package/scripts/tests/test-lesson-check.sh +278 -0
  245. package/scripts/tests/test-lesson-local.sh +55 -0
  246. package/scripts/tests/test-license-check.sh +109 -0
  247. package/scripts/tests/test-mab-run.sh +182 -0
  248. package/scripts/tests/test-ollama-lib.sh +49 -0
  249. package/scripts/tests/test-ollama.sh +60 -0
  250. package/scripts/tests/test-pipeline-status.sh +198 -0
  251. package/scripts/tests/test-policy-check.sh +124 -0
  252. package/scripts/tests/test-prior-art-search.sh +96 -0
  253. package/scripts/tests/test-progress-writer.sh +140 -0
  254. package/scripts/tests/test-promote-mab-lessons.sh +110 -0
  255. package/scripts/tests/test-pull-community-lessons.sh +149 -0
  256. package/scripts/tests/test-quality-gate.sh +241 -0
  257. package/scripts/tests/test-research-gate.sh +132 -0
  258. package/scripts/tests/test-run-plan-cli.sh +86 -0
  259. package/scripts/tests/test-run-plan-context.sh +305 -0
  260. package/scripts/tests/test-run-plan-e2e.sh +153 -0
  261. package/scripts/tests/test-run-plan-headless.sh +424 -0
  262. package/scripts/tests/test-run-plan-notify.sh +124 -0
  263. package/scripts/tests/test-run-plan-parser.sh +217 -0
  264. package/scripts/tests/test-run-plan-prompt.sh +254 -0
  265. package/scripts/tests/test-run-plan-quality-gate.sh +222 -0
  266. package/scripts/tests/test-run-plan-routing.sh +178 -0
  267. package/scripts/tests/test-run-plan-scoring.sh +148 -0
  268. package/scripts/tests/test-run-plan-state.sh +261 -0
  269. package/scripts/tests/test-run-plan-team.sh +157 -0
  270. package/scripts/tests/test-scope-infer.sh +150 -0
  271. package/scripts/tests/test-setup-ralph-loop.sh +63 -0
  272. package/scripts/tests/test-telegram-env.sh +38 -0
  273. package/scripts/tests/test-telegram.sh +121 -0
  274. package/scripts/tests/test-telemetry.sh +46 -0
  275. package/scripts/tests/test-thompson-sampling.sh +139 -0
  276. package/scripts/tests/test-validate-all.sh +60 -0
  277. package/scripts/tests/test-validate-commands.sh +89 -0
  278. package/scripts/tests/test-validate-hooks.sh +98 -0
  279. package/scripts/tests/test-validate-lessons.sh +150 -0
  280. package/scripts/tests/test-validate-plan-quality.sh +235 -0
  281. package/scripts/tests/test-validate-plans.sh +187 -0
  282. package/scripts/tests/test-validate-plugin.sh +106 -0
  283. package/scripts/tests/test-validate-prd.sh +184 -0
  284. package/scripts/tests/test-validate-skills.sh +134 -0
  285. package/scripts/validate-all.sh +57 -0
  286. package/scripts/validate-commands.sh +67 -0
  287. package/scripts/validate-hooks.sh +89 -0
  288. package/scripts/validate-lessons.sh +98 -0
  289. package/scripts/validate-plan-quality.sh +369 -0
  290. package/scripts/validate-plans.sh +120 -0
  291. package/scripts/validate-plugin.sh +86 -0
  292. package/scripts/validate-policies.sh +42 -0
  293. package/scripts/validate-prd.sh +118 -0
  294. package/scripts/validate-skills.sh +96 -0
  295. package/skills/autocode/SKILL.md +285 -0
  296. package/skills/autocode/ab-verification.md +51 -0
  297. package/skills/autocode/code-quality-standards.md +37 -0
  298. package/skills/autocode/competitive-mode.md +364 -0
  299. package/skills/brainstorming/SKILL.md +97 -0
  300. package/skills/capture-lesson/SKILL.md +187 -0
  301. package/skills/check-lessons/SKILL.md +116 -0
  302. package/skills/dispatching-parallel-agents/SKILL.md +110 -0
  303. package/skills/executing-plans/SKILL.md +85 -0
  304. package/skills/finishing-a-development-branch/SKILL.md +201 -0
  305. package/skills/receiving-code-review/SKILL.md +72 -0
  306. package/skills/requesting-code-review/SKILL.md +59 -0
  307. package/skills/requesting-code-review/code-reviewer.md +82 -0
  308. package/skills/research/SKILL.md +145 -0
  309. package/skills/roadmap/SKILL.md +115 -0
  310. package/skills/subagent-driven-development/SKILL.md +98 -0
  311. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +18 -0
  312. package/skills/subagent-driven-development/implementer-prompt.md +73 -0
  313. package/skills/subagent-driven-development/spec-reviewer-prompt.md +57 -0
  314. package/skills/systematic-debugging/SKILL.md +134 -0
  315. package/skills/systematic-debugging/condition-based-waiting.md +64 -0
  316. package/skills/systematic-debugging/defense-in-depth.md +32 -0
  317. package/skills/systematic-debugging/root-cause-tracing.md +55 -0
  318. package/skills/test-driven-development/SKILL.md +167 -0
  319. package/skills/using-git-worktrees/SKILL.md +219 -0
  320. package/skills/using-superpowers/SKILL.md +54 -0
  321. package/skills/verification-before-completion/SKILL.md +140 -0
  322. package/skills/verify/SKILL.md +82 -0
  323. package/skills/writing-plans/SKILL.md +128 -0
  324. package/skills/writing-skills/SKILL.md +93 -0
@@ -0,0 +1,125 @@
1
+ # Contributing Lessons
2
+
3
+ The autonomous-coding-toolkit improves with every user's production failures. When you encounter a bug caused by an anti-pattern, you can submit it as a lesson that becomes an automated check for every user.
4
+
5
+ ## How Lessons Become Checks
6
+
7
+ ```
8
+ You encounter a bug
9
+ → Run /submit-lesson to capture it
10
+ → PR is opened against this repo
11
+ → Maintainer reviews and merges
12
+ → Lesson file lands in docs/lessons/
13
+ → lesson-check.sh picks up syntactic patterns automatically
14
+ → lesson-scanner agent picks up semantic patterns automatically
15
+ → Every user's next scan catches that anti-pattern
16
+ ```
17
+
18
+ **Two tiers of enforcement:**
19
+
20
+ | Tier | Type | Speed | How it works |
21
+ |------|------|-------|-------------|
22
+ | Fast | Syntactic (grep-detectable) | <2 seconds | `lesson-check.sh` reads the lesson's `regex` field and runs `grep -P` |
23
+ | Deep | Semantic (needs context) | Minutes | `lesson-scanner` agent reads the lesson's `description` and `example` fields |
24
+
25
+ Adding a lesson file is all it takes — no code changes to the scanner or check script.
26
+
27
+ ## Submitting a Lesson
28
+
29
+ ### Option 1: Use the `/submit-lesson` command (recommended)
30
+
31
+ Inside a Claude Code session with this toolkit installed:
32
+
33
+ ```
34
+ /submit-lesson "bare except clauses hide failures in production"
35
+ ```
36
+
37
+ The command walks you through:
38
+ 1. Describing the bug
39
+ 2. Classifying severity and category
40
+ 3. Generating a grep pattern (if syntactic)
41
+ 4. Writing the lesson file
42
+ 5. Opening a PR
43
+
44
+ ### Option 2: Manual PR
45
+
46
+ 1. Copy `docs/lessons/TEMPLATE.md` to `docs/lessons/NNNN-<slug>.md`
47
+ 2. Fill in the YAML frontmatter and body sections
48
+ 3. Open a PR with title: `lesson: <short description>`
49
+
50
+ ## Lesson File Format
51
+
52
+ Every lesson file has YAML frontmatter that the tools parse:
53
+
54
+ ```yaml
55
+ ---
56
+ id: 7 # Auto-assigned sequential ID
57
+ title: "Short descriptive title"
58
+ severity: blocker # blocker | should-fix | nice-to-have
59
+ languages: [python] # python | javascript | typescript | shell | all
60
+ category: silent-failures # See categories below
61
+ pattern:
62
+ type: syntactic # syntactic | semantic
63
+ regex: "^\\s*except\\s*:" # grep -P pattern (syntactic only)
64
+ description: "what to look for"
65
+ fix: "how to fix it"
66
+ example:
67
+ bad: |
68
+ <anti-pattern code>
69
+ good: |
70
+ <correct code>
71
+ ---
72
+
73
+ ## Observation
74
+ [What happened — the bug, the symptom]
75
+
76
+ ## Insight
77
+ [Why it happened — the root cause]
78
+
79
+ ## Lesson
80
+ [The rule to follow going forward]
81
+ ```
82
+
83
+ ## Categories
84
+
85
+ | Category | What it covers |
86
+ |----------|---------------|
87
+ | `async-traps` | Forgotten awaits, concurrent modification, coroutine misuse |
88
+ | `resource-lifecycle` | Leaked connections, missing cleanup, subscription without unsubscribe |
89
+ | `silent-failures` | Bare exceptions, swallowed errors, lost stack traces |
90
+ | `integration-boundaries` | Cross-module bugs, path issues, API contract mismatches |
91
+ | `test-anti-patterns` | Brittle assertions, mocking the wrong thing, false confidence |
92
+ | `performance` | Missing filters, unnecessary work, resource waste |
93
+
94
+ ## Severity Guide
95
+
96
+ | Severity | When to use | Examples |
97
+ |----------|------------|---------|
98
+ | `blocker` | Data loss, crashes, silent corruption | Bare except swallowing errors, async def returning coroutine instead of result |
99
+ | `should-fix` | Subtle bugs, degraded behavior, tech debt | Leaked connections, hardcoded test counts, missing callbacks |
100
+ | `nice-to-have` | Code smells, future risks, style | Naming issues, missing type hints, suboptimal patterns |
101
+
102
+ ## Quality Bar
103
+
104
+ Before submitting, verify:
105
+
106
+ 1. **Real bug** — The lesson comes from a bug you actually encountered, not a hypothetical
107
+ 2. **Regex accuracy** (syntactic only) — The regex catches the bad example and does NOT match the good example
108
+ 3. **Clear description** — Someone unfamiliar with your codebase can understand the anti-pattern
109
+ 4. **Actionable fix** — The fix section tells you what to do, not just "be careful"
110
+ 5. **Realistic example** — The bad/good examples are from real code (anonymized if needed)
111
+
112
+ ## Review Process
113
+
114
+ 1. **Automated checks** — PR CI verifies the YAML frontmatter parses correctly and required fields are present
115
+ 2. **Regex testing** — Maintainer tests the regex against real codebases for false positive rate
116
+ 3. **Category review** — Maintainer verifies severity and category are appropriate
117
+ 4. **Merge** — Once approved, the lesson is immediately available to all users on next toolkit update
118
+
119
+ ## What Makes a Great Lesson
120
+
121
+ The best lessons:
122
+ - Come from bugs that took >30 minutes to debug
123
+ - Have a syntactic pattern (grep-detectable = instant enforcement for everyone)
124
+ - Apply across multiple projects (not just your specific codebase)
125
+ - Include the "why" — understanding the mechanism prevents the entire class of bug, not just this instance
@@ -0,0 +1,34 @@
1
+ ---
2
+ id: 1
3
+ title: "Bare exception swallowing hides failures"
4
+ severity: blocker
5
+ languages: [python]
6
+ scope: [language:python]
7
+ category: silent-failures
8
+ pattern:
9
+ type: syntactic
10
+ regex: "^\\s*except\\s*:"
11
+ description: "bare except clause without logging"
12
+ fix: "Always log the exception before returning a fallback: except Exception as e: logger.error(..., exc_info=True)"
13
+ example:
14
+ bad: |
15
+ try:
16
+ result = api_call()
17
+ except:
18
+ return default_value
19
+ good: |
20
+ try:
21
+ result = api_call()
22
+ except Exception as e:
23
+ logger.error("API call failed", exc_info=True)
24
+ return default_value
25
+ ---
26
+
27
+ ## Observation
28
+ Bare `except:` clauses silently swallow all exceptions including KeyboardInterrupt, SystemExit, and MemoryError. When the fallback value is returned, there's no log trail to indicate a failure occurred, making debugging impossible.
29
+
30
+ ## Insight
31
+ The root cause is a habit of writing "safe" exception handling that catches everything. The Python exception hierarchy means `except:` catches far more than intended. Combined with no logging, failures become invisible.
32
+
33
+ ## Lesson
34
+ Never use bare `except:` — always catch a specific exception class and log before returning a fallback. The 3-line rule: within 3 lines of an except clause, there must be a logging call.
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: 2
3
+ title: "async def without await returns truthy coroutine"
4
+ severity: blocker
5
+ languages: [python]
6
+ scope: [language:python]
7
+ category: async-traps
8
+ pattern:
9
+ type: semantic
10
+ description: "async def function body contains no await, async for, or async with — returns coroutine object instead of result"
11
+ fix: "Either add await for async I/O operations, or remove the async keyword if the function does no async work"
12
+ example:
13
+ bad: |
14
+ async def get_data():
15
+ return database.query("SELECT *") # Returns coroutine, not result
16
+ good: |
17
+ async def get_data():
18
+ return await database.query("SELECT *")
19
+ ---
20
+
21
+ ## Observation
22
+ An `async def` function that never uses `await`, `async for`, or `async with` returns a coroutine object instead of its result. Since coroutine objects are truthy, code like `if await get_data():` silently succeeds with a truthy coroutine even when the actual data would be falsy.
23
+
24
+ ## Insight
25
+ This is insidious because the function appears to work — it returns something truthy, no exceptions are raised, no warnings are logged. The bug only surfaces when the return value is used for its actual content rather than truthiness.
26
+
27
+ ## Lesson
28
+ Every `async def` must contain at least one `await`, `async for`, or `async with`. If it doesn't need any, remove the `async` keyword. This check requires multi-line analysis (scanning the full function body), so it's a semantic check in the lesson-scanner.
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: 3
3
+ title: "asyncio.create_task without done_callback swallows exceptions"
4
+ severity: should-fix
5
+ languages: [python]
6
+ scope: [language:python]
7
+ category: silent-failures
8
+ pattern:
9
+ type: semantic
10
+ description: "create_task() call without add_done_callback within 5 lines — untracked task may swallow exceptions silently"
11
+ fix: "Add a done_callback that logs exceptions: task.add_done_callback(lambda t: t.exception() and logger.error(...))"
12
+ example:
13
+ bad: |
14
+ task = asyncio.create_task(process_event(data))
15
+ # No callback — if process_event raises, you'll never know
16
+ good: |
17
+ task = asyncio.create_task(process_event(data))
18
+ task.add_done_callback(lambda t: t.exception() and logger.error("Task failed", exc_info=t.exception()))
19
+ ---
20
+
21
+ ## Observation
22
+ `asyncio.create_task()` launches a coroutine as a background task. If the task raises an exception and nobody awaits it or checks its result, Python logs a "Task exception was never retrieved" warning at garbage collection time — which may be much later or not at all.
23
+
24
+ ## Insight
25
+ Fire-and-forget tasks are a common pattern but they create invisible failure paths. The exception is silently stored in the task object and only surfaces (maybe) when the task is garbage collected.
26
+
27
+ ## Lesson
28
+ Every `create_task()` call should be followed within 5 lines by `add_done_callback()` that handles exceptions. Alternatively, store the task and await it later.
@@ -0,0 +1,28 @@
1
+ ---
2
+ id: 4
3
+ title: "Hardcoded count assertions break when datasets grow"
4
+ severity: should-fix
5
+ languages: [python, javascript, typescript]
6
+ scope: [universal]
7
+ category: test-anti-patterns
8
+ pattern:
9
+ type: syntactic
10
+ regex: "assert.*==\\s*\\d+|expect\\(.*\\)\\.toBe\\(\\d+\\)|assert_equal.*\\d+"
11
+ description: "test assertion comparing count to a hardcoded number"
12
+ fix: "Use >= for extensible collections, or assert against a computed expected value rather than a magic number"
13
+ example:
14
+ bad: |
15
+ assert len(collectors) == 15 # Breaks when a 16th collector is added
16
+ good: |
17
+ assert len(collectors) >= 15 # Passes as collection grows
18
+ # Or better: assert expected_collector in collectors
19
+ ---
20
+
21
+ ## Observation
22
+ Tests that assert exact counts (e.g., `assert len(items) == 15`) break every time a new item is added to an extensible collection. This creates friction where adding a feature requires updating unrelated test files.
23
+
24
+ ## Insight
25
+ Exact count assertions conflate "the collection is not empty and has the expected items" with "the collection has exactly N items." The former is what you usually want to test; the latter creates brittle coupling.
26
+
27
+ ## Lesson
28
+ For extensible collections, use `>=` assertions or check for specific members. Reserve exact count assertions for fixed-size structures where the count is genuinely part of the contract.
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: 5
3
+ title: "sqlite3 connections leak without closing() context manager"
4
+ severity: should-fix
5
+ languages: [python]
6
+ scope: [language:python]
7
+ category: silent-failures
8
+ pattern:
9
+ type: syntactic
10
+ regex: "sqlite3\\.connect\\("
11
+ description: "sqlite3.connect() — verify closing() context manager is used (with conn: manages transactions, not connections)"
12
+ fix: "Use contextlib.closing(): with closing(sqlite3.connect(db_path)) as conn:"
13
+ example:
14
+ bad: |
15
+ conn = sqlite3.connect("data.db")
16
+ with conn:
17
+ conn.execute("INSERT ...")
18
+ # Connection never explicitly closed — relies on GC
19
+ good: |
20
+ from contextlib import closing
21
+ with closing(sqlite3.connect("data.db")) as conn:
22
+ with conn:
23
+ conn.execute("INSERT ...")
24
+ ---
25
+
26
+ ## Observation
27
+ `with conn:` in sqlite3 manages transactions (auto-commit/rollback), NOT the connection lifecycle. The connection remains open until garbage collected. Under load or in long-running processes, this leaks file descriptors.
28
+
29
+ ## Insight
30
+ Python's sqlite3 `with` statement is misleading — it looks like a resource manager but only manages transactions. The actual connection close requires either `conn.close()` or `contextlib.closing()`.
31
+
32
+ ## Lesson
33
+ Always wrap `sqlite3.connect()` in `contextlib.closing()` for reliable cleanup. The pattern is: `with closing(connect(...)) as conn: with conn: ...` — outer for lifecycle, inner for transactions.
@@ -0,0 +1,27 @@
1
+ ---
2
+ id: 6
3
+ title: ".venv/bin/pip installs to wrong site-packages"
4
+ severity: should-fix
5
+ languages: [python, shell]
6
+ scope: [language:python, framework:pytest]
7
+ category: integration-boundaries
8
+ pattern:
9
+ type: syntactic
10
+ regex: "\\.venv/bin/pip\\b"
11
+ description: ".venv/bin/pip instead of .venv/bin/python -m pip — pip shebang may point to wrong Python"
12
+ fix: "Use .venv/bin/python -m pip to ensure packages install into the correct virtual environment"
13
+ example:
14
+ bad: |
15
+ .venv/bin/pip install requests
16
+ good: |
17
+ .venv/bin/python -m pip install requests
18
+ ---
19
+
20
+ ## Observation
21
+ When multiple Python versions exist on the system (e.g., system Python + Homebrew Python), `.venv/bin/pip` may resolve to the wrong Python interpreter via its shebang line. Packages install into the wrong site-packages directory, making them invisible to the venv's Python.
22
+
23
+ ## Insight
24
+ The pip executable's shebang (`#!/path/to/python`) is set at venv creation time. If PATH changes or another Python is installed later, the shebang becomes stale. Using `python -m pip` always uses the Python that's running it.
25
+
26
+ ## Lesson
27
+ Never call `.venv/bin/pip` directly. Always use `.venv/bin/python -m pip` to guarantee the correct interpreter and site-packages directory.
@@ -0,0 +1,35 @@
1
+ ---
2
+ id: 7
3
+ title: "Runner state file rejected by own git-clean check"
4
+ severity: should-fix
5
+ languages: [shell, all]
6
+ scope: [project:autonomous-coding-toolkit]
7
+ category: integration-boundaries
8
+ pattern:
9
+ type: semantic
10
+ description: "Tool-generated state files rejected by the tool's own git-clean check"
11
+ fix: "Add tool-generated state files to .gitignore before the first run"
12
+ example:
13
+ bad: |
14
+ #!/bin/bash
15
+ # Runner creates state file
16
+ echo '{"batch":1}' > .run-plan-state.json
17
+ # Later, quality gate rejects it
18
+ git status --porcelain | grep -q . && echo "ERROR: untracked files"
19
+ good: |
20
+ # .gitignore includes state file
21
+ echo ".run-plan-state.json" >> .gitignore
22
+ # Runner creates state file (now ignored)
23
+ echo '{"batch":1}' > .run-plan-state.json
24
+ # Quality gate passes
25
+ git status --porcelain | grep -q . || echo "OK: repo clean"
26
+ ---
27
+
28
+ ## Observation
29
+ A tool (e.g., plan runner) creates a state file (e.g., `.run-plan-state.json`) to persist execution progress. The tool's own quality gate includes a git-clean check that rejects untracked files. The tool creates the file, then its quality gate fails because the file is untracked.
30
+
31
+ ## Insight
32
+ The root cause is a missing `.gitignore` entry. Tool-generated state files are not version-controlled artifacts — they're runtime metadata. If the tool creates them but the `.gitignore` doesn't exclude them, every tool run will create a file that the next quality gate rejects. This is a self-inflicted tooling loop.
33
+
34
+ ## Lesson
35
+ Any tool that generates state files must add those files to `.gitignore` before the tool's first run. State files (`.state.json`, `.run-plan-state.json`, progress markers) are never version-controlled. The `.gitignore` is part of the tool's bootstrap, not the tool's runtime.
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: 8
3
+ title: "Quality gate blind spot for non-standard test suites"
4
+ severity: should-fix
5
+ languages: [shell, all]
6
+ scope: [project:autonomous-coding-toolkit]
7
+ category: silent-failures
8
+ pattern:
9
+ type: semantic
10
+ description: "Quality gate auto-detects only standard test frameworks, missing custom test suites"
11
+ fix: "Detect custom test runners by convention (executable run-all-tests.sh, test-*.sh glob)"
12
+ example:
13
+ bad: |
14
+ # Quality gate checks only standard frameworks
15
+ if [[ -f pytest.ini ]]; then pytest; fi
16
+ if [[ -f package.json ]]; then npm test; fi
17
+ if [[ -f Makefile ]]; then make test; fi
18
+ # Custom bash suite test-*.sh is never discovered
19
+ good: |
20
+ # Also check for executable test runners and test globs
21
+ if [[ -x run-all-tests.sh ]]; then ./run-all-tests.sh; fi
22
+ if ls test-*.sh &>/dev/null; then for t in test-*.sh; do ./"$t"; done; fi
23
+ # Plus standard framework checks...
24
+ ---
25
+
26
+ ## Observation
27
+ Quality gates that auto-detect test frameworks (pytest, npm test, make test) fail to discover custom test suites written as bash scripts (`test-integration.sh`, `test-smoke.sh`) or other non-standard runners. The gate reports "no tests detected" and passes, while hundreds of assertions exist and are never executed.
28
+
29
+ ## Insight
30
+ The root cause is convention-based detection that assumes all projects use a standard framework. Custom runners are often ignored because they're not a recognized pattern. The gate author knows pytest/npm/make but not the project's own conventions, leading to a blind spot.
31
+
32
+ ## Lesson
33
+ Quality gates must detect tests by multiple conventions: (1) standard frameworks (pytest, npm test, make), (2) executable scripts matching `test-*.sh`, and (3) a convention file like `run-all-tests.sh` that the project defines. If a gate only knows standard frameworks, it will miss half the projects using custom runners.
@@ -0,0 +1,36 @@
1
+ ---
2
+ id: 9
3
+ title: "Plan parser over-count burns empty API calls"
4
+ severity: should-fix
5
+ languages: [shell, all]
6
+ scope: [project:autonomous-coding-toolkit]
7
+ category: silent-failures
8
+ pattern:
9
+ type: semantic
10
+ description: "Plan parser counts batch headers without checking if batch has content"
11
+ fix: "Check get_batch_text is non-empty before executing a batch"
12
+ example:
13
+ bad: |
14
+ # Parser counts headers
15
+ batch_count=$(grep -c "^## Batch" plan.md)
16
+ for batch in $(seq 1 $batch_count); do
17
+ # Each batch triggers an agent, even if empty
18
+ run_batch "$batch"
19
+ done
20
+ good: |
21
+ # Parser checks if batch has content
22
+ for batch in $(seq 1 $batch_count); do
23
+ text=$(get_batch_text "$batch")
24
+ [[ -z "$text" ]] && continue # Skip empty batches
25
+ run_batch "$batch"
26
+ done
27
+ ---
28
+
29
+ ## Observation
30
+ A plan parser counts batch headers (e.g., `## Batch 1`, `## Batch 2`) to determine how many batches to execute. If the plan has trailing or empty headers, the count includes them. Each phantom batch spawns an agent context that discovers "nothing to do" — a wasted API call, time, and context.
31
+
32
+ ## Insight
33
+ The root cause is counting headers separately from extracting batch content. A header exists (line count is easy) but its content may be empty. Parser assumes every header has work, which is false for malformed or trailing headers.
34
+
35
+ ## Lesson
36
+ Never count batch headers separately. Always extract the batch content first, then check if it's non-empty before executing. Skip empty batches silently. This prevents wasted agent spawns and keeps the pipeline efficient.
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: 10
3
+ title: "`local` outside function silently misbehaves in bash"
4
+ severity: blocker
5
+ languages: [shell]
6
+ scope: [language:bash]
7
+ category: silent-failures
8
+ pattern:
9
+ type: syntactic
10
+ regex: "^local "
11
+ description: "`local` keyword used at script top-level, outside any function"
12
+ fix: "Never use `local` outside a function; use plain variable assignment at script scope"
13
+ example:
14
+ bad: |
15
+ #!/bin/bash
16
+ local result="value"
17
+ echo "Result: $result"
18
+ # Works on some shells, fails/ignored on others
19
+ good: |
20
+ #!/bin/bash
21
+ result="value"
22
+ echo "Result: $result"
23
+ # Works consistently across all shells
24
+ ---
25
+
26
+ ## Observation
27
+ A bash script uses the `local` keyword at script top-level, outside any function. The script works on one machine but fails on another, or silently produces empty values on a third. The `local` keyword is not portable when used outside function scope.
28
+
29
+ ## Insight
30
+ In bash, `local` is only defined for use within functions — it declares a variable in the local function scope. At script scope, `local` is undefined behavior. Some shells silently accept and ignore it (variable remains undefined), others error. Creating scripts that work on one machine but fail on another due to shell differences.
31
+
32
+ ## Lesson
33
+ Never use `local` outside a function. At script scope, use plain variable assignment (`var=value`). Functions use `local var=value` for local scope. Script scope has no `local` keyword — all variables are global by default. Grep patterns checking for `^local ` are syntactic checks to catch this at write time.
@@ -0,0 +1,36 @@
1
+ ---
2
+ id: 11
3
+ title: "Batch execution writes tests for unimplemented code"
4
+ severity: should-fix
5
+ languages: [all]
6
+ scope: [universal]
7
+ category: integration-boundaries
8
+ pattern:
9
+ type: semantic
10
+ description: "Tests in batch N reference code that won't exist until batch N+1"
11
+ fix: "Plan tasks so each batch is self-contained — tests only reference code from the same or earlier batches"
12
+ example:
13
+ bad: |
14
+ # Plan with forward-looking test
15
+ ## Batch 3: Add tests for pipeline
16
+ - Write tests that call pipeline.transform() (not written yet)
17
+
18
+ ## Batch 4: Implement pipeline
19
+ - Implement the transform() method
20
+ good: |
21
+ # Plan with self-contained batches
22
+ ## Batch 3: Implement pipeline
23
+ - Implement the transform() method
24
+
25
+ ## Batch 4: Add tests for pipeline
26
+ - Write tests that call pipeline.transform() (now exists)
27
+ ---
28
+
29
+ ## Observation
30
+ When a plan has batches 1-7 and batch 3's agent writes tests expecting batch 4's code, those tests fail until batch 4 runs. The agent does TDD correctly for its own batch (writes test, implements code) but accidentally creates forward dependencies when tests reference not-yet-implemented code from future batches.
31
+
32
+ ## Insight
33
+ The root cause is batching by concern instead of by dependency. The planner thinks "batch 3 is tests, batch 4 is implementation" without considering that tests depend on the code existing. Tests can't pass (or even import) if the code they reference isn't in the codebase yet.
34
+
35
+ ## Lesson
36
+ Plan tasks so each batch is self-contained. Tests reference only code from the same batch (TDD: write test, write code) or earlier batches (tested code). Never have batch N's tests reference batch N+1's code. If you need to test something, implement it in the same batch or an earlier batch.
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: 12
3
+ title: "API rejects markdown with unescaped special chars"
4
+ severity: nice-to-have
5
+ languages: [python, javascript, all]
6
+ scope: [universal]
7
+ category: integration-boundaries
8
+ pattern:
9
+ type: semantic
10
+ description: "Message API rejects text containing unescaped markdown special characters"
11
+ fix: "Either escape all special characters or use plain text mode as default with markdown as opt-in"
12
+ example:
13
+ bad: |
14
+ # Message with unescaped markdown chars
15
+ message = "Task: _compile_flags = ['-O2', '-Wall']"
16
+ response = api.send_message(message, parse_mode="Markdown")
17
+ # API rejects: parse error due to _ chars
18
+ good: |
19
+ # Either escape special chars
20
+ message = "Task: \\_compile\\_flags = ['-O2', '-Wall']"
21
+ response = api.send_message(message, parse_mode="Markdown")
22
+ # Or use plain text by default
23
+ response = api.send_message(message) # parse_mode=None
24
+ ---
25
+
26
+ ## Observation
27
+ An API with `parse_mode=Markdown` rejects messages containing unescaped special characters like `_`, `*`, `[`, `]`. The message silently fails or returns a parse error. Code that works with one message format fails with another that contains these characters.
28
+
29
+ ## Insight
30
+ The root cause is assuming plain text is safe to send with markdown parsing enabled. Markdown interpreters are strict — any `_` or `*` is interpreted as formatting syntax. If the text literally needs to include these characters (like code snippets or file paths), they must be escaped or the parser must be disabled.
31
+
32
+ ## Lesson
33
+ When sending messages to APIs with markdown parsing, either: (1) escape all special characters (`_`, `*`, `[`, `]`, `` ` ``) in the text, or (2) use plain text mode by default and require opt-in for markdown. Never assume plain text is safe with markdown parsing enabled.
@@ -0,0 +1,33 @@
1
+ ---
2
+ id: 13
3
+ title: "`export` prefix in env files breaks naive parsing"
4
+ severity: should-fix
5
+ languages: [shell]
6
+ scope: [language:bash]
7
+ category: silent-failures
8
+ pattern:
9
+ type: syntactic
10
+ regex: "cut -d= -f2"
11
+ description: "Env file parser using cut without stripping export prefix"
12
+ fix: "Strip `export ` prefix before parsing: sed 's/^export //'"
13
+ example:
14
+ bad: |
15
+ # .env file with export prefix
16
+ # export API_KEY=secret123
17
+ # Read without stripping export
18
+ value=$(grep "API_KEY" .env | cut -d= -f2)
19
+ # Works for KEY=value but fails for export KEY=value
20
+ good: |
21
+ # Strip export prefix before parsing
22
+ value=$(grep "API_KEY" .env | sed 's/^export //' | cut -d= -f2)
23
+ # Works for both KEY=value and export KEY=value
24
+ ---
25
+
26
+ ## Observation
27
+ `.env` files commonly use `export VAR=value` syntax (for shell-source-ability). A parser uses `grep VAR= file | cut -d= -f2` to extract values. For lines like `KEY=value` it works fine. For lines with `export KEY=value`, the `cut` command returns the correct value, but if the parsing step checks for the line format first (e.g., expecting no `export` prefix), it silently skips those lines.
28
+
29
+ ## Insight
30
+ The root cause is assuming `.env` format is always `KEY=value` without the `export` keyword. Many `.env` files use `export` for shell-sourcing (so they can be sourced with `source .env`). Parsers that don't account for this prefix will silently skip or misparse those lines.
31
+
32
+ ## Lesson
33
+ `.env` file parsers should strip the `export` prefix before parsing. Use `sed 's/^export //'` to normalize lines, then parse. This handles both `KEY=value` and `export KEY=value` consistently. Never assume the format — always normalize first.
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: 14
3
+ title: "Decorator registries are import-time side effects"
4
+ severity: should-fix
5
+ languages: [python]
6
+ scope: [language:python]
7
+ category: silent-failures
8
+ pattern:
9
+ type: semantic
10
+ description: "Decorator-based registry remains empty because module with decorated functions is never imported"
11
+ fix: "Ensure all modules with registrations are imported in __init__.py or an explicit loader"
12
+ example:
13
+ bad: |
14
+ # handlers.py
15
+ @register("command")
16
+ def handle_command(): pass
17
+
18
+ # main.py
19
+ # registry.get_all() returns empty — handlers.py was never imported
20
+ from registry import registry
21
+ for handler in registry.get_all(): # Empty!
22
+ handler()
23
+ good: |
24
+ # handlers.py (same as above)
25
+ @register("command")
26
+ def handle_command(): pass
27
+
28
+ # main.py
29
+ # Explicitly import to trigger decorators
30
+ from . import handlers # This runs the decorators
31
+ from registry import registry
32
+ for handler in registry.get_all(): # Has handlers now
33
+ handler()
34
+ ---
35
+
36
+ ## Observation
37
+ A Python project uses decorator-based registration (`@register("name")` adds a function to a registry). The registry is empty at runtime even though decorated functions exist in the codebase. No error is raised — the registry just returns an empty list.
38
+
39
+ ## Insight
40
+ Decorator-based registries execute at import time. If the module containing decorated functions is never imported (perhaps `main.py` only imports specific modules), the decorators never run and the registry stays empty. The mistake is assuming the module will be imported implicitly, when it must be imported explicitly.
41
+
42
+ ## Lesson
43
+ Decorator-based registries require explicit imports of all modules that have decorated functions. Add imports to `__init__.py` or a loader module that's guaranteed to run. Document this requirement. Alternatively, use a registration function that's called explicitly, instead of relying on import-time side effects. Never assume a module is imported — always be explicit.
@@ -0,0 +1,43 @@
1
+ ---
2
+ id: 15
3
+ title: "Frontend-backend schema drift invisible until e2e trace"
4
+ severity: should-fix
5
+ languages: [typescript, javascript, python, all]
6
+ scope: [universal]
7
+ category: integration-boundaries
8
+ pattern:
9
+ type: semantic
10
+ description: "Frontend and backend define the same data shape independently and drift over time"
11
+ fix: "Shared schema definition (types generated from API schema) or contract tests"
12
+ example:
13
+ bad: |
14
+ # Backend (Python)
15
+ def get_user():
16
+ return {"id": 1, "name": "Alice", "email": "alice@example.com"}
17
+
18
+ # Frontend (TypeScript, independent definition)
19
+ interface User { id: number; name: string; }
20
+ // Missing email field! Silent bug.
21
+ good: |
22
+ # Shared schema (OpenAPI/GraphQL)
23
+ components:
24
+ schemas:
25
+ User:
26
+ type: object
27
+ properties:
28
+ id: { type: integer }
29
+ name: { type: string }
30
+ email: { type: string }
31
+
32
+ # Generated TypeScript (from schema)
33
+ // User interface auto-generated, always in sync
34
+ ---
35
+
36
+ ## Observation
37
+ Frontend and backend define the same data shape (User, Product, etc.) independently. Over time they drift — backend adds an `email` field to User, frontend's User interface doesn't include it. The field is silently ignored on the frontend. No error until a feature tries to use the field and finds it missing.
38
+
39
+ ## Insight
40
+ The root cause is separate schema definitions. Each layer maintains its own types, and they're never synchronized. Backend and frontend evolve independently. The drift is invisible because both sides are "correct" within their own codebase — TypeScript compiles, Python runs, API calls succeed. Only end-to-end traces reveal the mismatch.
41
+
42
+ ## Lesson
43
+ Never define schemas independently in frontend and backend. Use a single source of truth: OpenAPI, GraphQL schema, Protobuf, or equivalent. Generate types from the shared schema. Alternatively, use contract tests that verify the API response matches what the frontend expects. The contract must be version-controlled and tested.