@polderlabs/bizar 6.2.4 → 6.3.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 (332) hide show
  1. package/.claude/CLAUDE.md +15 -0
  2. package/.claude/agents/_shared/AGENT_BASELINE.md +168 -0
  3. package/.claude/agents/_shared/CLAUDE_TOOLS.md +412 -0
  4. package/.claude/agents/_shared/SKILLS.md +109 -0
  5. package/.claude/agents/agent-browser.md +80 -0
  6. package/.claude/agents/baldr.md +49 -0
  7. package/.claude/agents/forseti.md +51 -0
  8. package/.claude/agents/frigg.md +42 -0
  9. package/.claude/agents/heimdall.md +33 -0
  10. package/.claude/agents/hermod.md +53 -0
  11. package/.claude/agents/mimir.md +49 -0
  12. package/.claude/agents/odin.md +287 -0
  13. package/.claude/agents/quick.md +34 -0
  14. package/.claude/agents/semble-search.md +50 -0
  15. package/.claude/agents/thor.md +53 -0
  16. package/.claude/agents/tyr.md +56 -0
  17. package/.claude/agents/vidarr.md +54 -0
  18. package/.claude/agents/vor.md +53 -0
  19. package/.claude/commands/audit.md +25 -0
  20. package/.claude/commands/bizar.md +22 -0
  21. package/.claude/commands/explain.md +17 -0
  22. package/.claude/commands/init.md +29 -0
  23. package/.claude/commands/learn.md +44 -0
  24. package/.claude/commands/plan.md +35 -0
  25. package/.claude/commands/plow-through.md +50 -0
  26. package/.claude/commands/pr-review.md +49 -0
  27. package/.claude/commands/setup-provider.md +96 -0
  28. package/.claude/commands/tailscale-serve.md +100 -0
  29. package/.claude/commands/team.md +132 -0
  30. package/.claude/commands/test.md +62 -0
  31. package/.claude/commands/validate.md +68 -0
  32. package/.claude/commands/visual-plan.md +24 -0
  33. package/.claude/hooks/README.md +92 -0
  34. package/.claude/hooks/posttooluse-editwrite.mjs +91 -0
  35. package/.claude/hooks/pretooluse-bash.mjs +81 -0
  36. package/.claude/hooks/pretooluse-editwrite.mjs +139 -0
  37. package/.claude/hooks/sessionend-recall.mjs +74 -0
  38. package/.claude/hooks/sessionstart-prime.mjs +80 -0
  39. package/.claude/hooks/userpromptsubmit-tag.mjs +80 -0
  40. package/.claude/settings.json +116 -0
  41. package/.claude/skills/9router/SKILL.md +80 -0
  42. package/.claude/skills/9router-chat/SKILL.md +73 -0
  43. package/.claude/skills/9router-embeddings/SKILL.md +69 -0
  44. package/.claude/skills/9router-image/SKILL.md +86 -0
  45. package/.claude/skills/9router-stt/SKILL.md +79 -0
  46. package/.claude/skills/9router-tts/SKILL.md +80 -0
  47. package/.claude/skills/9router-web-fetch/SKILL.md +99 -0
  48. package/.claude/skills/9router-web-search/SKILL.md +91 -0
  49. package/.claude/skills/bizar/README.md +9 -0
  50. package/.claude/skills/bizar/SKILL.md +450 -0
  51. package/.claude/skills/cpp-coding-standards/README.md +28 -0
  52. package/.claude/skills/cpp-coding-standards/SKILL.md +634 -0
  53. package/.claude/skills/cpp-coding-standards/references/concurrency.md +320 -0
  54. package/.claude/skills/cpp-coding-standards/references/error-handling.md +229 -0
  55. package/.claude/skills/cpp-coding-standards/references/memory-safety.md +216 -0
  56. package/.claude/skills/cpp-coding-standards/references/modern-idioms.md +282 -0
  57. package/.claude/skills/cpp-coding-standards/references/review-checklist.md +96 -0
  58. package/.claude/skills/cpp-testing/README.md +28 -0
  59. package/.claude/skills/cpp-testing/SKILL.md +304 -0
  60. package/.claude/skills/cpp-testing/references/coverage.md +370 -0
  61. package/.claude/skills/cpp-testing/references/framework-compare.md +175 -0
  62. package/.claude/skills/cpp-testing/references/host-test-for-embedded.md +499 -0
  63. package/.claude/skills/cpp-testing/references/mocking.md +364 -0
  64. package/.claude/skills/cpp-testing/references/tdd-workflow.md +308 -0
  65. package/.claude/skills/cubesandbox/SKILL.md +148 -0
  66. package/.claude/skills/embedded-esp-idf/README.md +41 -0
  67. package/.claude/skills/embedded-esp-idf/SKILL.md +439 -0
  68. package/.claude/skills/embedded-esp-idf/references/freertos-patterns.md +214 -0
  69. package/.claude/skills/embedded-esp-idf/references/host-tests.md +164 -0
  70. package/.claude/skills/embedded-esp-idf/references/idf-py-commands.md +157 -0
  71. package/.claude/skills/embedded-esp-idf/references/kconfig.md +159 -0
  72. package/.claude/skills/embedded-esp-idf/references/logging-discipline.md +118 -0
  73. package/.claude/skills/embedded-esp-idf/references/memory-and-iram.md +137 -0
  74. package/.claude/skills/embedded-esp-idf/references/nvs.md +121 -0
  75. package/.claude/skills/embedded-esp-idf/references/packed-structs.md +192 -0
  76. package/.claude/skills/embedded-esp-idf/scripts/idf_env.sh +47 -0
  77. package/.claude/skills/embedded-esp-idf/scripts/size_check.sh +77 -0
  78. package/.claude/skills/glyph/SKILL.md +163 -0
  79. package/.claude/skills/harness-engineering/SKILL.md +143 -0
  80. package/.claude/skills/lightrag/SKILL.md +81 -0
  81. package/.claude/skills/memory-protocol/SKILL.md +105 -0
  82. package/.claude/skills/obsidian/SKILL.md +306 -0
  83. package/.claude/skills/read-the-damn-docs/SKILL.md +113 -0
  84. package/.claude/skills/self-improvement/SKILL.md +64 -0
  85. package/README.md +87 -59
  86. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js → EnvVarsSection-B58aiJiE.js} +1 -1
  87. package/bizar-dash/dist/assets/{EnvVarsSection-DXM8gRm_.js.map → EnvVarsSection-B58aiJiE.js.map} +1 -1
  88. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js → MobileChat-BJrqwVDd.js} +1 -1
  89. package/bizar-dash/dist/assets/{MobileChat-BnKN_Ks_.js.map → MobileChat-BJrqwVDd.js.map} +1 -1
  90. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js → MobileSettings-CEQNJNLJ.js} +1 -1
  91. package/bizar-dash/dist/assets/{MobileSettings-DjCPxC-Q.js.map → MobileSettings-CEQNJNLJ.js.map} +1 -1
  92. package/bizar-dash/dist/assets/{main-DYiZqMrn.js → main-IvfQAOfy.js} +1 -1
  93. package/bizar-dash/dist/assets/{main-DYiZqMrn.js.map → main-IvfQAOfy.js.map} +1 -1
  94. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js → markdown-tOLaD6nm.js} +1 -1
  95. package/bizar-dash/dist/assets/{markdown-C6mXtQxD.js.map → markdown-tOLaD6nm.js.map} +1 -1
  96. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js → mobile-DYCHcUpq.js} +1 -1
  97. package/bizar-dash/dist/assets/{mobile-CMHqtLV2.js.map → mobile-DYCHcUpq.js.map} +1 -1
  98. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js → mobile-layout-CBHjpwsb.js} +2 -2
  99. package/bizar-dash/dist/assets/{mobile-layout-3jIhHX_p.js.map → mobile-layout-CBHjpwsb.js.map} +1 -1
  100. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js → useSlashCommands-Bd7_FA6U.js} +2 -2
  101. package/bizar-dash/dist/assets/{useSlashCommands-DtITw8Xv.js.map → useSlashCommands-Bd7_FA6U.js.map} +1 -1
  102. package/bizar-dash/dist/assets/{vendor-CeHGtduv.js → vendor-C843201K.js} +12 -12
  103. package/bizar-dash/dist/assets/vendor-C843201K.js.map +1 -0
  104. package/bizar-dash/dist/index.html +6 -6
  105. package/bizar-dash/dist/mobile.html +2 -2
  106. package/bizar-dash/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  107. package/bizar-dash/src/server/api.mjs +4 -4
  108. package/bizar-dash/src/server/background-store.mjs +15 -16
  109. package/bizar-dash/src/server/bg-poller.mjs +25 -35
  110. package/bizar-dash/src/server/bg-retry.mjs +66 -194
  111. package/bizar-dash/src/server/claude-bg-spawner.mjs +390 -0
  112. package/bizar-dash/src/server/claude-info.mjs +412 -0
  113. package/bizar-dash/src/server/{cline-runner.mjs → claude-runner.mjs} +53 -48
  114. package/bizar-dash/src/server/claude-sdk.mjs +191 -0
  115. package/bizar-dash/src/server/providers-store.mjs +22 -49
  116. package/bizar-dash/src/server/routes/background.mjs +24 -20
  117. package/bizar-dash/src/server/routes/chat.mjs +223 -326
  118. package/bizar-dash/src/server/routes/claude-session-detail.mjs +329 -0
  119. package/bizar-dash/src/server/routes/claude-sessions.mjs +259 -0
  120. package/bizar-dash/src/server/routes/tasks.mjs +20 -28
  121. package/bizar-dash/src/server/task-delegator.mjs +76 -77
  122. package/bizar-dash/src/web/components/chat/useChat.ts +23 -27
  123. package/bizar-dash/src/web/views/Chat.tsx +8 -8
  124. package/cli/bin.mjs +31 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/sandbox.mjs +220 -0
  128. package/cli/commands/validate.mjs +252 -288
  129. package/cli/dev-link.test.mjs +11 -11
  130. package/cli/doctor.mjs +131 -213
  131. package/cli/install.mjs +33 -37
  132. package/cli/install.test.mjs +9 -9
  133. package/cli/provision-claude.mjs +893 -0
  134. package/cli/provision.mjs +330 -226
  135. package/cli/provision.test.mjs +102 -0
  136. package/cli/utils.mjs +72 -58
  137. package/config/AGENTS.md +28 -28
  138. package/config/agents/_shared/AGENT_BASELINE.md +104 -684
  139. package/config/skills/bizar/SKILL.md +197 -0
  140. package/config/skills/cubesandbox/SKILL.md +148 -0
  141. package/config/skills/harness-engineering/SKILL.md +142 -0
  142. package/install.sh +66 -44
  143. package/package.json +19 -11
  144. package/packages/sdk/ARCHITECTURE.md +40 -36
  145. package/packages/sdk/package-lock.json +32 -0
  146. package/packages/sdk/package.json +15 -5
  147. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  148. package/packages/sdk/src/fingerprint.ts +0 -0
  149. package/packages/sdk/src/index.ts +38 -73
  150. package/packages/sdk/src/mcp/bin.ts +51 -0
  151. package/packages/sdk/src/mcp/server.ts +498 -0
  152. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  153. package/packages/sdk/tests/sdk.test.mjs +148 -0
  154. package/packages/sdk/vitest.config.ts +1 -1
  155. package/scripts/bh-full-e2e.mjs +166 -363
  156. package/scripts/check-deps.mjs +28 -46
  157. package/scripts/mirror-claude-md.sh +78 -0
  158. package/scripts/test-in-container.sh +157 -0
  159. package/templates/clean-state-checklist.md +3 -3
  160. package/templates/sprint-contract.md +2 -2
  161. package/bizar-dash/.bizar/activity.log +0 -3
  162. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  163. package/bizar-dash/.omx/state/session.json +0 -10
  164. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  165. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  166. package/bizar-dash/bizar-design/canvas.html +0 -281
  167. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  168. package/bizar-dash/bizar-design/components.css +0 -1665
  169. package/bizar-dash/bizar-design/components.html +0 -557
  170. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  172. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  174. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  176. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  177. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  178. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  179. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  180. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  181. package/bizar-dash/bizar-design/icons.svg +0 -44
  182. package/bizar-dash/bizar-design/index.html +0 -192
  183. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  185. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  189. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  190. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  191. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  192. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  193. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  194. package/bizar-dash/bizar-design/prototype.js +0 -114
  195. package/bizar-dash/bizar-design/tokens.css +0 -106
  196. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  197. package/bizar-dash/node_modules/.package-lock.json +0 -6
  198. package/bizar-dash/package-lock.json +0 -6
  199. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  200. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  201. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  202. package/cli/commands/cline-cmd.mjs +0 -289
  203. package/cli/commands/validate.test.mjs +0 -344
  204. package/cli/doctor.test.mjs +0 -350
  205. package/config/cline.json.template +0 -342
  206. package/packages/sdk/src/client.ts +0 -188
  207. package/packages/sdk/src/cline-events.ts +0 -134
  208. package/packages/sdk/src/cline-types.ts +0 -66
  209. package/packages/sdk/src/cline.ts +0 -339
  210. package/packages/sdk/src/errors.ts +0 -129
  211. package/packages/sdk/src/events.ts +0 -153
  212. package/packages/sdk/src/types.ts +0 -176
  213. package/packages/sdk/tests/client.test.ts +0 -217
  214. package/packages/sdk/tests/errors.test.ts +0 -108
  215. package/packages/sdk/tests/events.test.ts +0 -139
  216. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  217. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  218. package/plugins/bizar/ARCHITECTURE.md +0 -142
  219. package/plugins/bizar/CONSTRAINTS.md +0 -67
  220. package/plugins/bizar/LICENSE +0 -21
  221. package/plugins/bizar/README.md +0 -448
  222. package/plugins/bizar/index.ts +0 -872
  223. package/plugins/bizar/package.json +0 -39
  224. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  225. package/plugins/bizar/src/background-state.ts +0 -641
  226. package/plugins/bizar/src/background.ts +0 -1806
  227. package/plugins/bizar/src/cline-runner.ts +0 -203
  228. package/plugins/bizar/src/clineruntime.ts +0 -227
  229. package/plugins/bizar/src/commands-impl.ts +0 -151
  230. package/plugins/bizar/src/commands.ts +0 -1799
  231. package/plugins/bizar/src/compaction.d.mts +0 -48
  232. package/plugins/bizar/src/compaction.mjs +0 -192
  233. package/plugins/bizar/src/dashboard-client.ts +0 -233
  234. package/plugins/bizar/src/event-stream.ts +0 -606
  235. package/plugins/bizar/src/fingerprint.ts +0 -120
  236. package/plugins/bizar/src/handoff.ts +0 -79
  237. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  238. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  239. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  240. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  241. package/plugins/bizar/src/http-client.ts +0 -467
  242. package/plugins/bizar/src/key-rotation.ts +0 -218
  243. package/plugins/bizar/src/logger.ts +0 -144
  244. package/plugins/bizar/src/loop-engineering.ts +0 -241
  245. package/plugins/bizar/src/loop.ts +0 -176
  246. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  247. package/plugins/bizar/src/odin.ts +0 -227
  248. package/plugins/bizar/src/options.ts +0 -470
  249. package/plugins/bizar/src/plan-fs.ts +0 -323
  250. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  251. package/plugins/bizar/src/report.ts +0 -178
  252. package/plugins/bizar/src/research-prompt.ts +0 -35
  253. package/plugins/bizar/src/serve-info.ts +0 -228
  254. package/plugins/bizar/src/serve.ts +0 -496
  255. package/plugins/bizar/src/settings.ts +0 -349
  256. package/plugins/bizar/src/state.ts +0 -298
  257. package/plugins/bizar/src/tool-discipline.ts +0 -105
  258. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  259. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  260. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  261. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  262. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  263. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  264. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  265. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  266. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  267. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  268. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  269. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  270. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  271. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  272. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  273. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  274. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  275. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  276. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  277. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  278. package/plugins/bizar/src/tools/team-status.ts +0 -76
  279. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  280. package/plugins/bizar/src/trajectory.ts +0 -104
  281. package/plugins/bizar/tests/README.md +0 -99
  282. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  283. package/plugins/bizar/tests/background-state.test.ts +0 -277
  284. package/plugins/bizar/tests/background.test.ts +0 -402
  285. package/plugins/bizar/tests/block.test.ts +0 -195
  286. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  287. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  288. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  289. package/plugins/bizar/tests/commands.test.ts +0 -584
  290. package/plugins/bizar/tests/compaction.test.ts +0 -264
  291. package/plugins/bizar/tests/config.test.ts +0 -128
  292. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  293. package/plugins/bizar/tests/dispose.test.ts +0 -336
  294. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  295. package/plugins/bizar/tests/event.test.ts +0 -262
  296. package/plugins/bizar/tests/fingerprint.test.ts +0 -162
  297. package/plugins/bizar/tests/http-client.test.ts +0 -404
  298. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  299. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  300. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  301. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  302. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  303. package/plugins/bizar/tests/loop.test.ts +0 -397
  304. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  305. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  306. package/plugins/bizar/tests/odin.test.ts +0 -125
  307. package/plugins/bizar/tests/options.test.ts +0 -329
  308. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  309. package/plugins/bizar/tests/safety.test.ts +0 -256
  310. package/plugins/bizar/tests/serve.test.ts +0 -339
  311. package/plugins/bizar/tests/settings.test.ts +0 -351
  312. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  313. package/plugins/bizar/tests/state.test.ts +0 -276
  314. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  315. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  316. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  317. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  318. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  319. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  320. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  321. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  322. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  323. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  324. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  325. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  326. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  327. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  328. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  329. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  330. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  331. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  332. package/plugins/bizar/tsconfig.json +0 -29
@@ -0,0 +1,364 @@
1
+ # Mocking Strategies in C++
2
+
3
+ ## Overview
4
+
5
+ Mocking lets you test a unit in isolation by replacing its dependencies with controlled test doubles. In C++, the three primary strategies are:
6
+
7
+ 1. **Abstract Interface** — dependency inversion with a pure virtual interface
8
+ 2. **Link-Time Seam** — replace a compiled object at link time
9
+ 3. **`std::function` Injection** — pass behavior as a callable at runtime
10
+
11
+ Each has a different trade-off between isolation, compile-time cost, and how much you need to modify existing code.
12
+
13
+ ---
14
+
15
+ ## 1. Abstract Interface (Dependency Inversion)
16
+
17
+ ### Concept
18
+
19
+ Define a pure virtual interface. The class under test accepts a pointer/reference to the interface. In tests, pass a fake implementation.
20
+
21
+ ### When to Use
22
+
23
+ - You control the design and can introduce interfaces
24
+ - You need fine-grained control over mock behavior (ON_CALL, EXPECT_CALL)
25
+ - You want to test multiple implementations of the same interface
26
+
27
+ ### Code Example
28
+
29
+ ```cpp
30
+ // === interfaces/sensor_reading.h ===
31
+ #pragma once
32
+ #include <cstdint>
33
+ #include <optional>
34
+
35
+ struct ISensor {
36
+ virtual ~ISensor() = default;
37
+ virtual std::optional<double> read() = 0;
38
+ virtual bool is_connected() = 0;
39
+ };
40
+
41
+ // === main/policy/temp_monitor.h ===
42
+ #pragma once
43
+ #include "sensor_reading.h"
44
+
45
+ class TempMonitor {
46
+ public:
47
+ explicit TempMonitor(ISensor* sensor) : sensor_(sensor) {}
48
+ bool has_valid_reading();
49
+ double last_reading();
50
+ private:
51
+ ISensor* sensor_;
52
+ };
53
+
54
+ // === main/policy/temp_monitor.cpp ===
55
+ #include "temp_monitor.h"
56
+ #include <algorithm>
57
+
58
+ bool TempMonitor::has_valid_reading() {
59
+ return sensor_->is_connected() && sensor_->read().has_value();
60
+ }
61
+
62
+ double TempMonitor::last_reading() {
63
+ auto v = sensor_->read();
64
+ return v.value_or(0.0);
65
+ }
66
+
67
+ // === test/host/test_temp_monitor.cpp ===
68
+ #include <gtest/gtest.h>
69
+ #include "temp_monitor.h"
70
+ #include "sensor_reading.h"
71
+ #include <optional>
72
+
73
+ struct FakeSensor : ISensor {
74
+ std::optional<double> fake_value = std::nullopt;
75
+ bool connected = false;
76
+
77
+ std::optional<double> read() override { return fake_value; }
78
+ bool is_connected() override { return connected; }
79
+ };
80
+
81
+ TEST(TempMonitor, has_valid_reading_true_when_connected_and_has_value) {
82
+ FakeSensor fake;
83
+ fake.connected = true;
84
+ fake.fake_value = 23.5;
85
+ TempMonitor monitor(&fake);
86
+ EXPECT_TRUE(monitor.has_valid_reading());
87
+ EXPECT_DOUBLE_EQ(monitor.last_reading(), 23.5);
88
+ }
89
+
90
+ TEST(TempMonitor, has_valid_reading_false_when_disconnected) {
91
+ FakeSensor fake;
92
+ fake.connected = false;
93
+ fake.fake_value = 23.5;
94
+ TempMonitor monitor(&fake);
95
+ EXPECT_FALSE(monitor.has_valid_reading());
96
+ }
97
+
98
+ TEST(TempMonitor, has_valid_reading_false_when_no_value) {
99
+ FakeSensor fake;
100
+ fake.connected = true;
101
+ fake.fake_value = std::nullopt;
102
+ TempMonitor monitor(&fake);
103
+ EXPECT_FALSE(monitor.has_valid_reading());
104
+ }
105
+ ```
106
+
107
+ ### Trade-offs
108
+
109
+ | Pros | Cons |
110
+ |------|------|
111
+ | Full control over mock behavior | Requires interface in production code |
112
+ | Works with `gmock` (`ON_CALL`, `EXPECT_CALL`) | Adds indirection to class design |
113
+ | Tests are fully isolated | Can be verbose for simple cases |
114
+
115
+ ---
116
+
117
+ ## 2. Link-Time Seam
118
+
119
+ ### Concept
120
+
121
+ Compile a different version of a file at link time to replace the production implementation. The test links its own `.cpp` that provides a minimal or fake implementation of the dependency.
122
+
123
+ ### When to Use
124
+
125
+ - You cannot modify the existing production code to accept interfaces
126
+ - The dependency is a single global function or static method
127
+ - You want to test a module without any runtime injection mechanism
128
+
129
+ ### Code Example
130
+
131
+ ```cpp
132
+ // === main/policy/heartbeat.h ===
133
+ #pragma once
134
+ bool heartbeat_send(uint32_t interval_ms);
135
+
136
+ // === main/policy/heartbeat.cpp ===
137
+ #include "heartbeat.h"
138
+ #include "esp_timer.h" // FreeRTOS/ESP-IDF — not available on host
139
+
140
+ bool heartbeat_send(uint32_t interval_ms) {
141
+ esp_timer_start_periodic(..., interval_ms * 1000);
142
+ return true;
143
+ }
144
+
145
+ // === test/host/CMakeLists.txt ===
146
+ # Replace real heartbeat.cpp with stub at link time
147
+ add_executable(test_heartbeat
148
+ test_heartbeat.cpp
149
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../main/policy/heartbeat.cpp # production
150
+ ${CMAKE_CURRENT_SOURCE_DIR}/stubs/heartbeat_stub.cpp # our fake
151
+ )
152
+ ```
153
+
154
+ ```cpp
155
+ // === test/host/stubs/heartbeat_stub.cpp ===
156
+ #include "heartbeat.h"
157
+
158
+ bool heartbeat_send(uint32_t interval_ms) {
159
+ // No-op on host — just return true
160
+ (void)interval_ms;
161
+ return true;
162
+ }
163
+ ```
164
+
165
+ ```cpp
166
+ // === test/host/test_heartbeat.cpp ===
167
+ #include <gtest/gtest.h>
168
+ #include "heartbeat.h"
169
+
170
+ TEST(Heartbeat, send_returns_true) {
171
+ EXPECT_TRUE(heartbeat_send(1000));
172
+ }
173
+
174
+ TEST(Heartbeat, send_accepts_zero_interval) {
175
+ EXPECT_TRUE(heartbeat_send(0));
176
+ }
177
+ ```
178
+
179
+ ### Trade-offs
180
+
181
+ | Pros | Cons |
182
+ |------|------|
183
+ | No production code changes needed | Only works when you control what's linked |
184
+ | Works with any C/C++ function | Can mask integration issues if stub is too fake |
185
+ | Simple to implement | No runtime control — compile-time replacement only |
186
+
187
+ ---
188
+
189
+ ## 3. `std::function` Injection
190
+
191
+ ### Concept
192
+
193
+ Make behavior injectable via `std::function` member variables set at construction or via setters. No interface hierarchy needed.
194
+
195
+ ### When to Use
196
+
197
+ - You want minimal boilerplate
198
+ - The dependency is a simple callable (function, functor, lambda)
199
+ - You don't need `gmock` expectations — simple behavior is enough
200
+
201
+ ### Code Example
202
+
203
+ ```cpp
204
+ // === main/policy/resp_fallback.h ===
205
+ #pragma once
206
+ #include <functional>
207
+ #include "resp_fallback_types.h" // Response, FallbackResult
208
+
209
+ class RespFallback {
210
+ public:
211
+ using response_check_t = std::function<bool(const Response&)>;
212
+ using fallback_fn_t = std::function<FallbackResult(const Response*, Response*)>;
213
+
214
+ explicit RespFallback(response_check_t checker = nullptr,
215
+ fallback_fn_t fallback_fn = nullptr)
216
+ : checker_(std::move(checker)), fallback_fn_(std::move(fallback_fn)) {}
217
+
218
+ FallbackResult process(const Response* req, Response* out);
219
+
220
+ private:
221
+ response_check_t checker_;
222
+ fallback_fn_t fallback_fn_;
223
+ };
224
+
225
+ // === test/host/test_resp_fallback.cpp ===
226
+ #include <gtest/gtest.h>
227
+ #include "resp_fallback.h"
228
+
229
+ TEST(RespFallback, uses_checker_when_provided) {
230
+ bool checker_called = false;
231
+ RespFallback rf(
232
+ [&checker_called](const Response&) {
233
+ checker_called = true;
234
+ return true;
235
+ },
236
+ nullptr
237
+ );
238
+ Response out;
239
+ Response in = { .payload = "test", .payload_len = 4, .status_code = 500 };
240
+ rf.process(&in, &out);
241
+ EXPECT_TRUE(checker_called);
242
+ }
243
+
244
+ TEST(RespFallback, uses_fallback_fn_when_checker_fails) {
245
+ bool fallback_called = false;
246
+ RespFallback rf(
247
+ [](const Response&) { return false; }, // checker returns false
248
+ [&fallback_called](const Response*, Response* out) {
249
+ fallback_called = true;
250
+ out->payload = "fallback";
251
+ out->status_code = 200;
252
+ return FallbackResult::FALLBACK_OK;
253
+ }
254
+ );
255
+ Response out;
256
+ Response in = { .payload = "error", .payload_len = 5, .status_code = 500 };
257
+ FallbackResult r = rf.process(&in, &out);
258
+ EXPECT_TRUE(fallback_called);
259
+ EXPECT_EQ(r, FallbackResult::FALLBACK_OK);
260
+ }
261
+ ```
262
+
263
+ ### Trade-offs
264
+
265
+ | Pros | Cons |
266
+ |------|------|
267
+ | Zero boilerplate — no interface needed | Cannot use `EXPECT_CALL` / `ON_CALL` with gmock |
268
+ | Lambda-friendly | Lambdas can't be stored in `std::function` if they capture |
269
+ | Works with existing code (add a setter) | Tests must provide real behavior if production doesn't |
270
+
271
+ ---
272
+
273
+ ## 4. gmock (GoogleMock) — Struct-Level MATCHER
274
+
275
+ When using GoogleTest, `gmock` provides `MATCHER` and `ON_CALL` for fine-grained expectations on structs:
276
+
277
+ ```cpp
278
+ #include <gmock/gmock.h>
279
+ #include <gtest/gtest.h>
280
+
281
+ struct Reading {
282
+ double temperature;
283
+ uint32_t timestamp;
284
+ };
285
+
286
+ MATCHER_P(TempNear, expected, "") {
287
+ return std::abs(arg.temperature - expected) < 0.5;
288
+ }
289
+
290
+ TEST(Sensor, reading_near_expected) {
291
+ ::testing::MockFunction<bool(const Reading&)> mock_check;
292
+ ON_CALL(mock_check, Call)
293
+ .WillByDefault(::testing::Return(true));
294
+
295
+ EXPECT_CALL(mock_check, Call(TempNear(25.0))).Times(1);
296
+
297
+ Reading r = { 25.1, 123456 };
298
+ mock_check.Call(r);
299
+ }
300
+ ```
301
+
302
+ For simple structs, `MATCHER` is cleaner than writing a full fake class.
303
+
304
+ ---
305
+
306
+ ## Choosing a Strategy
307
+
308
+ | Situation | Recommended Strategy |
309
+ |-----------|---------------------|
310
+ | New code, you control design | Abstract Interface + `gmock` |
311
+ | Testing existing code with no interface | Link-Time Seam |
312
+ | Simple callable dependency, no gmock needed | `std::function` Injection |
313
+ | Struct-level assertions | `MATCHER` / `ON_CALL` |
314
+ | Need `EXPECT_CALL` with complex behavior | Abstract Interface + `gmock` |
315
+ | FreeRTOS/ESP-IDF call in production code | Link-Time Seam (stub at link) |
316
+
317
+ ---
318
+
319
+ ## Anti-Patterns
320
+
321
+ ### Don't Over-Mock
322
+
323
+ ```cpp
324
+ // BAD — mocking everything means you're not testing real code
325
+ TEST(System, processes_data) {
326
+ auto mock_storage = std::make_unique<MockStorage>();
327
+ auto mock_network = std::make_unique<MockNetwork>();
328
+ ON_CALL(*mock_storage, read).WillByDefault(...);
329
+ ON_CALL(*mock_network, send).WillByDefault(...);
330
+ System sys(std::move(mock_storage), std::move(mock_network));
331
+ // This tests nothing real
332
+ }
333
+ ```
334
+
335
+ **Better:** Test `System` with real `Storage` and mocked `Network`, or vice versa. Only mock at boundaries.
336
+
337
+ ### Don't Mock Value Types
338
+
339
+ ```cpp
340
+ // BAD — no need to mock a simple struct
341
+ struct Config { int timeout_ms; bool enabled; };
342
+
343
+ // GOOD — construct directly, no mock needed
344
+ Config cfg{1000, true};
345
+ ```
346
+
347
+ ### Don't Mock Stateless Utilities
348
+
349
+ ```cpp
350
+ // BAD — mocking a pure function like strlen is wasteful
351
+ // GOOD — just call strlen in tests directly
352
+ EXPECT_EQ(strlen("hello"), 5);
353
+ ```
354
+
355
+ ---
356
+
357
+ ## Combining Strategies
358
+
359
+ You can combine strategies in the same project. For example:
360
+ - Use **Abstract Interface** for `ISensor`, `IStorage` (core domain interfaces)
361
+ - Use **Link-Time Seam** for FreeRTOS / ESP-IDF API calls
362
+ - Use **`std::function`** for simple policy callbacks
363
+
364
+ The key principle: **mock at boundaries, not deep inside the system**.
@@ -0,0 +1,308 @@
1
+ # TDD Workflow for C++
2
+
3
+ ## Overview
4
+
5
+ Test-Driven Development (TDD) follows a short red-green-refactor cycle:
6
+
7
+ 1. **Red** — Write a failing test before touching production code.
8
+ 2. **Green** — Write the minimum production code to make the test pass.
9
+ 3. **Refactor** — Clean up both test and production code, keeping tests green.
10
+
11
+ The goal is **narrow, fast feedback**: every line of production code has a failing test that motivated it.
12
+
13
+ ---
14
+
15
+ ## The Cycle in Detail
16
+
17
+ ### Step 1: Red — Write a Failing Test
18
+
19
+ Write the smallest possible test that describes the behavior you want:
20
+
21
+ ```cpp
22
+ // test/host/test_rate_limiter.cpp
23
+ #include <gtest/gtest.h>
24
+ #include "rate_limiter.h"
25
+
26
+ TEST(RateLimiter, allows_request_under_limit) {
27
+ RateLimiter rl(10); // 10 requests per second
28
+ // First request should be allowed
29
+ EXPECT_TRUE(rl.allow());
30
+ }
31
+ ```
32
+
33
+ Compile and run. It **must fail** because `rate_limiter.h` / `rate_limiter.cpp` don't exist yet:
34
+
35
+ ```
36
+ error: 'RateLimiter' file not found
37
+ ```
38
+
39
+ This is the correct outcome — you've specified what you want before building it.
40
+
41
+ ### Step 2: Green — Write Minimum Production Code
42
+
43
+ Create the stub to make it compile, then the implementation to make it pass:
44
+
45
+ ```cpp
46
+ // main/policy/rate_limiter.h
47
+ #pragma once
48
+ class RateLimiter {
49
+ public:
50
+ explicit RateLimiter(int max_per_second);
51
+ bool allow();
52
+ };
53
+ ```
54
+
55
+ ```cpp
56
+ // main/policy/rate_limiter.cpp
57
+ #include "rate_limiter.h"
58
+
59
+ RateLimiter::RateLimiter(int max_per_second) {}
60
+ bool RateLimiter::allow() { return true; } // minimum: always allow
61
+ ```
62
+
63
+ Run tests — they should pass. You now have a compiling, passing test.
64
+
65
+ ### Step 3: Refactor
66
+
67
+ Now add the second test:
68
+
69
+ ```cpp
70
+ TEST(RateLimiter, blocks_request_over_limit) {
71
+ RateLimiter rl(2);
72
+ rl.allow(); // request 1
73
+ rl.allow(); // request 2
74
+ EXPECT_FALSE(rl.allow()); // request 3 — over limit
75
+ }
76
+ ```
77
+
78
+ Run tests — this new test **fails** (current impl always returns `true`). Go back to Step 2.
79
+
80
+ ```cpp
81
+ // main/policy/rate_limiter.cpp — minimum change
82
+ #include "rate_limiter.h"
83
+ #include <atomic>
84
+
85
+ RateLimiter::RateLimiter(int max_per_second) : max_per_second_(max_per_second), count_(0) {}
86
+
87
+ bool RateLimiter::allow() {
88
+ int current = count_.load();
89
+ if (current >= max_per_second_) return false;
90
+ count_.store(current + 1);
91
+ return true;
92
+ }
93
+ ```
94
+
95
+ Run tests — all pass. Repeat the cycle.
96
+
97
+ ---
98
+
99
+ ## Structuring Tests for TDD
100
+
101
+ ### Arrange-Act-Assert (AAA)
102
+
103
+ ```cpp
104
+ TEST(RateLimiter, blocks_over_limit) {
105
+ // Arrange
106
+ RateLimiter rl(1);
107
+ rl.allow(); // consume the one allowed request
108
+
109
+ // Act
110
+ bool allowed = rl.allow();
111
+
112
+ // Assert
113
+ EXPECT_FALSE(allowed);
114
+ }
115
+ ```
116
+
117
+ ### One Logical Assertion Per Test
118
+
119
+ Prefer multiple `EXPECT_*` calls that are all checking related aspects of one behavior over one test per `EXPECT_*`. Example:
120
+
121
+ ```cpp
122
+ // Good — one test, multiple related EXPECTs
123
+ TEST(RespFallback, error_returns_fallback_and_sets_status) {
124
+ Response in = { .payload = "error", .payload_len = 5, .status_code = 500 };
125
+ Response out;
126
+ FallbackResult r = resp_fallback_process(&in, &out);
127
+ EXPECT_EQ(r, FALLBACK_OK);
128
+ EXPECT_EQ(out.status_code, 200);
129
+ EXPECT_STREQ(out.payload, "default_response");
130
+ }
131
+ ```
132
+
133
+ ### Test Naming for TDD
134
+
135
+ Name tests to describe **behavior**, not implementation:
136
+
137
+ ```
138
+ GOOD: RespFallback_returns_fallback_when_upstream_fails
139
+ GOOD: Datacollector_append_returns_minus_one_when_full
140
+ BAD: TestRespFallback (no behavior described)
141
+ BAD: Test1 (meaningless)
142
+ ```
143
+
144
+ ---
145
+
146
+ ## TDD for Embedded Firmware Modules
147
+
148
+ ### Example: `feature_flags.cpp` from scratch
149
+
150
+ **Start:** You have an empty `feature_flags.cpp` with only a header stub.
151
+
152
+ **Test 1:** `is_active_returns_false_for_unknown_feature`
153
+
154
+ ```cpp
155
+ TEST(FeatureFlags, is_active_returns_false_for_unknown_feature) {
156
+ EXPECT_FALSE(feature_flags_is_active("nonexistent"));
157
+ }
158
+ ```
159
+
160
+ Compile → link error (no implementation). Add stub:
161
+
162
+ ```cpp
163
+ bool feature_flags_is_active(const char* name) { return false; }
164
+ ```
165
+
166
+ Test passes. (You chose the simplest implementation that makes the test pass.)
167
+
168
+ **Test 2:** `is_active_returns_true_for_known_feature`
169
+
170
+ ```cpp
171
+ TEST(FeatureFlags, is_active_returns_true_for_known_feature) {
172
+ EXPECT_TRUE(feature_flags_is_active("debug"));
173
+ }
174
+ ```
175
+
176
+ Test fails (still returns `false`). Implement:
177
+
178
+ ```cpp
179
+ bool feature_flags_is_active(const char* name) {
180
+ if (strcmp(name, "debug") == 0) return true;
181
+ return false;
182
+ }
183
+ ```
184
+
185
+ Test passes.
186
+
187
+ **Test 3:** `is_active_returns_false_for_nullptr`
188
+
189
+ ```cpp
190
+ TEST(FeatureFlags, is_active_returns_false_for_nullptr) {
191
+ EXPECT_FALSE(feature_flags_is_active(nullptr));
192
+ }
193
+ ```
194
+
195
+ Add the null check. Tests pass.
196
+
197
+ **Refactor:** Replace chain of `if/strcmp` with a lookup table:
198
+
199
+ ```cpp
200
+ static bool flags[] = { false, false, false }; // debug=0, trace=1, legacy=2
201
+ ```
202
+
203
+ The tests **still pass** because they assert on behavior, not representation.
204
+
205
+ ---
206
+
207
+ ## Red-Green-Refactor in Practice
208
+
209
+ ### Red Flags (stop and refactor if you see these)
210
+
211
+ - **Test takes too long to write** — break it into smaller pieces
212
+ - **Test requires many mocks** — the module under test may have too many dependencies (consider interface injection)
213
+ - **Production code can't be tested in isolation** — the module needs refactoring before tests can be written
214
+ - **Tests are brittle** — if renaming a private method breaks a test, you're testing the wrong thing
215
+
216
+ ### Refactoring Rules
217
+
218
+ 1. **Never change tests to make production code pass.** Change production code to make tests pass.
219
+ 2. **Keep tests deterministic.** No random values, no timing dependencies.
220
+ 3. **Test behavior, not implementation.** If you refactor internal representation and tests break, the tests were overspecified.
221
+ 4. **Run the full test suite after every refactor** — green before, green after.
222
+
223
+ ---
224
+
225
+ ## What to Test First
226
+
227
+ ### Priority 1: Happy Path (primary behavior)
228
+
229
+ ```cpp
230
+ TEST(RateLimiter, allows_requests_under_limit) { ... }
231
+ ```
232
+
233
+ ### Priority 2: Edge Cases (boundary values)
234
+
235
+ ```cpp
236
+ TEST(RateLimiter, allows_zero_limit_as_always_blocked) { ... }
237
+ TEST(RateLimiter, handles_negative_limit) { ... } // invalid input
238
+ ```
239
+
240
+ ### Priority 3: Error Paths
241
+
242
+ ```cpp
243
+ TEST(Datacollector, append_returns_error_when_full) { ... }
244
+ TEST(RespFallback, returns_invalid_when_nullptr) { ... }
245
+ ```
246
+
247
+ ### Priority 4: Negative Tests (the "what shouldn't happen")
248
+
249
+ ```cpp
250
+ TEST(FeatureFlags, is_active_does_not_crash_on_nullptr) { ... }
251
+ TEST(RateLimiter, does_not_allow_over_limit_regardless_of_speed) { ... }
252
+ ```
253
+
254
+ ---
255
+
256
+ ## Test Coverage in TDD
257
+
258
+ TDD naturally drives coverage high because:
259
+ - Every line of production code was written to satisfy a test
260
+ - You can't add code without a failing test first
261
+
262
+ However, TDD alone doesn't guarantee 80% coverage. Run `lcov` after the full suite to identify untested branches:
263
+
264
+ ```bash
265
+ cmake --build build -j$(nproc)
266
+ ./test_policy
267
+ lcov --capture --directory build --output coverage.info \
268
+ --exclude '*/test_*' --exclude '*/stubs/*' --exclude '*/build/*'
269
+ lcov --list coverage.info # inspect
270
+ ```
271
+
272
+ Add missing tests for any uncovered lines before opening a PR.
273
+
274
+ ---
275
+
276
+ ## When TDD Is Not Worth It
277
+
278
+ - **Trivial accessors** — `getter()` / `setter()` with no logic
279
+ - **Generated code** — auto-generated `serde`, `protobuf` bindings
280
+ - **One-off scripts** — not part of the production codebase
281
+ - **Quick prototypes** — exploratory code that will be thrown away
282
+
283
+ For these, write tests **after** if the code becomes permanent.
284
+
285
+ ---
286
+
287
+ ## TDD and the 80% Coverage Gate
288
+
289
+ TDD gets you to ~60-70% coverage naturally. The last 10-20% requires disciplined addition of:
290
+
291
+ 1. **Branch coverage** — every `if/else` and `switch` branch
292
+ 2. **Error paths** — every function that can return an error code
293
+ 3. **Negative tests** — every `if (ptr == nullptr)` path
294
+
295
+ Use `lcov --list coverage.info | grep -E "BRAN|BR" ` to find uncovered branches.
296
+
297
+ ---
298
+
299
+ ## Summary: TDD Checklist
300
+
301
+ Before each commit:
302
+ - [ ] Every new public method has at least one test
303
+ - [ ] Tests follow AAA structure
304
+ - [ ] Test names describe behavior (Subject_Behavior_Expected)
305
+ - [ ] Tests pass on first run (green)
306
+ - [ ] No test is skipped (`DISABLED_`) unless there's a tracked issue
307
+ - [ ] 80% line coverage gate passes (`lcov`)
308
+ - [ ] No new `// TODO` or `// FIXME` in test code