@polderlabs/bizar 6.2.5 → 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 (329) 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 +17 -18
  125. package/cli/commands/claude-cmd.mjs +348 -0
  126. package/cli/commands/install.mjs +12 -11
  127. package/cli/commands/validate.mjs +252 -325
  128. package/cli/dev-link.test.mjs +11 -11
  129. package/cli/doctor.mjs +131 -213
  130. package/cli/install.mjs +33 -37
  131. package/cli/install.test.mjs +9 -9
  132. package/cli/provision-claude.mjs +893 -0
  133. package/cli/provision.mjs +224 -227
  134. package/cli/utils.mjs +72 -58
  135. package/config/AGENTS.md +28 -28
  136. package/install.sh +66 -44
  137. package/package.json +19 -11
  138. package/packages/sdk/ARCHITECTURE.md +40 -36
  139. package/packages/sdk/package-lock.json +32 -0
  140. package/packages/sdk/package.json +15 -5
  141. package/{plugins/bizar → packages/sdk}/src/dangerous-patterns.ts +6 -28
  142. package/packages/sdk/src/fingerprint.ts +0 -0
  143. package/packages/sdk/src/index.ts +38 -73
  144. package/packages/sdk/src/mcp/bin.ts +51 -0
  145. package/packages/sdk/src/mcp/server.ts +498 -0
  146. package/{plugins/bizar/src/memory-vault.ts → packages/sdk/src/memory/index.ts} +18 -21
  147. package/packages/sdk/tests/sdk.test.mjs +148 -0
  148. package/packages/sdk/vitest.config.ts +1 -1
  149. package/scripts/bh-full-e2e.mjs +166 -363
  150. package/scripts/check-deps.mjs +28 -46
  151. package/scripts/mirror-claude-md.sh +78 -0
  152. package/scripts/test-in-container.sh +31 -9
  153. package/templates/clean-state-checklist.md +3 -3
  154. package/templates/sprint-contract.md +2 -2
  155. package/bizar-dash/.bizar/activity.log +0 -3
  156. package/bizar-dash/.omx/logs/omx-2026-07-07.jsonl +0 -1
  157. package/bizar-dash/.omx/state/session.json +0 -10
  158. package/bizar-dash/bizar-design/EXPLANATION.md +0 -307
  159. package/bizar-dash/bizar-design/INSTRUCTIONS.md +0 -149
  160. package/bizar-dash/bizar-design/canvas.html +0 -281
  161. package/bizar-dash/bizar-design/canvas.html.artifact.json +0 -19
  162. package/bizar-dash/bizar-design/components.css +0 -1665
  163. package/bizar-dash/bizar-design/components.html +0 -557
  164. package/bizar-dash/bizar-design/components.html.artifact.json +0 -19
  165. package/bizar-dash/bizar-design/desktop/agents.html +0 -74
  166. package/bizar-dash/bizar-design/desktop/agents.html.artifact.json +0 -19
  167. package/bizar-dash/bizar-design/desktop/memory.html +0 -75
  168. package/bizar-dash/bizar-design/desktop/memory.html.artifact.json +0 -19
  169. package/bizar-dash/bizar-design/desktop/metrics.html +0 -63
  170. package/bizar-dash/bizar-design/desktop/metrics.html.artifact.json +0 -19
  171. package/bizar-dash/bizar-design/desktop/overview.html +0 -95
  172. package/bizar-dash/bizar-design/desktop/overview.html.artifact.json +0 -19
  173. package/bizar-dash/bizar-design/desktop/settings.html +0 -70
  174. package/bizar-dash/bizar-design/desktop/settings.html.artifact.json +0 -19
  175. package/bizar-dash/bizar-design/icons.svg +0 -44
  176. package/bizar-dash/bizar-design/index.html +0 -192
  177. package/bizar-dash/bizar-design/index.html.artifact.json +0 -19
  178. package/bizar-dash/bizar-design/mobile/agents.html +0 -29
  179. package/bizar-dash/bizar-design/mobile/agents.html.artifact.json +0 -19
  180. package/bizar-dash/bizar-design/mobile/memory.html +0 -28
  181. package/bizar-dash/bizar-design/mobile/memory.html.artifact.json +0 -19
  182. package/bizar-dash/bizar-design/mobile/metrics.html +0 -29
  183. package/bizar-dash/bizar-design/mobile/metrics.html.artifact.json +0 -19
  184. package/bizar-dash/bizar-design/mobile/overview.html +0 -33
  185. package/bizar-dash/bizar-design/mobile/overview.html.artifact.json +0 -19
  186. package/bizar-dash/bizar-design/mobile/settings.html +0 -28
  187. package/bizar-dash/bizar-design/mobile/settings.html.artifact.json +0 -19
  188. package/bizar-dash/bizar-design/prototype.js +0 -114
  189. package/bizar-dash/bizar-design/tokens.css +0 -106
  190. package/bizar-dash/dist/assets/vendor-CeHGtduv.js.map +0 -1
  191. package/bizar-dash/node_modules/.package-lock.json +0 -6
  192. package/bizar-dash/package-lock.json +0 -6
  193. package/bizar-dash/src/server/cline-sdk.mjs +0 -132
  194. package/bizar-dash/src/server/routes/cline-session-detail.mjs +0 -559
  195. package/bizar-dash/src/server/routes/cline-sessions.mjs +0 -291
  196. package/cli/commands/cline-cmd.mjs +0 -289
  197. package/cli/commands/validate.test.mjs +0 -379
  198. package/cli/doctor.test.mjs +0 -350
  199. package/config/cline.json.template +0 -342
  200. package/packages/sdk/src/client.ts +0 -188
  201. package/packages/sdk/src/cline-events.ts +0 -134
  202. package/packages/sdk/src/cline-types.ts +0 -66
  203. package/packages/sdk/src/cline.ts +0 -339
  204. package/packages/sdk/src/errors.ts +0 -129
  205. package/packages/sdk/src/events.ts +0 -153
  206. package/packages/sdk/src/types.ts +0 -176
  207. package/packages/sdk/tests/client.test.ts +0 -217
  208. package/packages/sdk/tests/errors.test.ts +0 -108
  209. package/packages/sdk/tests/events.test.ts +0 -139
  210. package/packages/sdk/tests/fixtures/fetch-mock.ts +0 -152
  211. package/packages/sdk/tests/fixtures/sse-mock.ts +0 -30
  212. package/plugins/bizar/ARCHITECTURE.md +0 -142
  213. package/plugins/bizar/CONSTRAINTS.md +0 -67
  214. package/plugins/bizar/LICENSE +0 -21
  215. package/plugins/bizar/README.md +0 -448
  216. package/plugins/bizar/index.ts +0 -925
  217. package/plugins/bizar/package.json +0 -39
  218. package/plugins/bizar/scripts/check-forbidden-imports.sh +0 -33
  219. package/plugins/bizar/src/background-state.ts +0 -641
  220. package/plugins/bizar/src/background.ts +0 -1806
  221. package/plugins/bizar/src/cline-runner.ts +0 -203
  222. package/plugins/bizar/src/clineruntime.ts +0 -227
  223. package/plugins/bizar/src/commands-impl.ts +0 -151
  224. package/plugins/bizar/src/commands.ts +0 -1799
  225. package/plugins/bizar/src/compaction.d.mts +0 -48
  226. package/plugins/bizar/src/compaction.mjs +0 -192
  227. package/plugins/bizar/src/dashboard-client.ts +0 -233
  228. package/plugins/bizar/src/event-stream.ts +0 -606
  229. package/plugins/bizar/src/fingerprint.ts +0 -120
  230. package/plugins/bizar/src/handoff.ts +0 -79
  231. package/plugins/bizar/src/hooks/memory-flush-on-compact.ts +0 -123
  232. package/plugins/bizar/src/hooks/memory-inject.ts +0 -247
  233. package/plugins/bizar/src/hooks/memory-write-on-end.ts +0 -188
  234. package/plugins/bizar/src/hooks/skill-curator.ts +0 -180
  235. package/plugins/bizar/src/http-client.ts +0 -467
  236. package/plugins/bizar/src/key-rotation.ts +0 -218
  237. package/plugins/bizar/src/logger.ts +0 -144
  238. package/plugins/bizar/src/loop-engineering.ts +0 -241
  239. package/plugins/bizar/src/loop.ts +0 -176
  240. package/plugins/bizar/src/mistake-recovery.ts +0 -98
  241. package/plugins/bizar/src/odin.ts +0 -227
  242. package/plugins/bizar/src/options.ts +0 -470
  243. package/plugins/bizar/src/plan-fs.ts +0 -323
  244. package/plugins/bizar/src/reasoning-clean.ts +0 -454
  245. package/plugins/bizar/src/report.ts +0 -178
  246. package/plugins/bizar/src/research-prompt.ts +0 -35
  247. package/plugins/bizar/src/serve-info.ts +0 -228
  248. package/plugins/bizar/src/serve.ts +0 -496
  249. package/plugins/bizar/src/settings.ts +0 -349
  250. package/plugins/bizar/src/state.ts +0 -298
  251. package/plugins/bizar/src/tool-discipline.ts +0 -105
  252. package/plugins/bizar/src/tools/agent-browser.ts +0 -315
  253. package/plugins/bizar/src/tools/bg-collect.ts +0 -131
  254. package/plugins/bizar/src/tools/bg-get-comments.ts +0 -266
  255. package/plugins/bizar/src/tools/bg-kill.ts +0 -116
  256. package/plugins/bizar/src/tools/bg-pause.ts +0 -99
  257. package/plugins/bizar/src/tools/bg-report-progress.ts +0 -115
  258. package/plugins/bizar/src/tools/bg-resume.ts +0 -94
  259. package/plugins/bizar/src/tools/bg-send-message.ts +0 -223
  260. package/plugins/bizar/src/tools/bg-spawn.ts +0 -502
  261. package/plugins/bizar/src/tools/bg-status.ts +0 -130
  262. package/plugins/bizar/src/tools/graph-query.ts +0 -278
  263. package/plugins/bizar/src/tools/loop-engineering.ts +0 -193
  264. package/plugins/bizar/src/tools/memory-list.ts +0 -43
  265. package/plugins/bizar/src/tools/memory-read.ts +0 -69
  266. package/plugins/bizar/src/tools/memory-search.ts +0 -47
  267. package/plugins/bizar/src/tools/memory-write.ts +0 -54
  268. package/plugins/bizar/src/tools/open-kb.ts +0 -198
  269. package/plugins/bizar/src/tools/plan-action.ts +0 -785
  270. package/plugins/bizar/src/tools/read-glyph-feedback.ts +0 -191
  271. package/plugins/bizar/src/tools/sandbox.ts +0 -232
  272. package/plugins/bizar/src/tools/team-spawn.ts +0 -73
  273. package/plugins/bizar/src/tools/team-status.ts +0 -76
  274. package/plugins/bizar/src/tools/wait-for-feedback.ts +0 -415
  275. package/plugins/bizar/src/trajectory.ts +0 -104
  276. package/plugins/bizar/tests/README.md +0 -99
  277. package/plugins/bizar/tests/attach-handler-bug.test.ts +0 -169
  278. package/plugins/bizar/tests/background-state.test.ts +0 -277
  279. package/plugins/bizar/tests/background.test.ts +0 -402
  280. package/plugins/bizar/tests/block.test.ts +0 -195
  281. package/plugins/bizar/tests/canonical-key-order.test.ts +0 -75
  282. package/plugins/bizar/tests/clineruntime-config.test.ts +0 -283
  283. package/plugins/bizar/tests/commands-impl.test.ts +0 -316
  284. package/plugins/bizar/tests/commands.test.ts +0 -584
  285. package/plugins/bizar/tests/compaction.test.ts +0 -264
  286. package/plugins/bizar/tests/config.test.ts +0 -128
  287. package/plugins/bizar/tests/dashboard-client.test.ts +0 -159
  288. package/plugins/bizar/tests/dispose.test.ts +0 -336
  289. package/plugins/bizar/tests/event-stream.test.ts +0 -409
  290. package/plugins/bizar/tests/event.test.ts +0 -262
  291. package/plugins/bizar/tests/fingerprint.test.ts +0 -190
  292. package/plugins/bizar/tests/http-client.test.ts +0 -404
  293. package/plugins/bizar/tests/init-helpers.test.ts +0 -203
  294. package/plugins/bizar/tests/integration/slash-command.test.ts +0 -349
  295. package/plugins/bizar/tests/integration/tool-routing.test.ts +0 -98
  296. package/plugins/bizar/tests/key-rotation.test.ts +0 -396
  297. package/plugins/bizar/tests/loop-engineering.test.ts +0 -168
  298. package/plugins/bizar/tests/loop.test.ts +0 -397
  299. package/plugins/bizar/tests/memory-write-on-end.test.ts +0 -92
  300. package/plugins/bizar/tests/mistake-recovery.test.ts +0 -116
  301. package/plugins/bizar/tests/odin.test.ts +0 -125
  302. package/plugins/bizar/tests/options.test.ts +0 -329
  303. package/plugins/bizar/tests/reasoning-clean.test.ts +0 -422
  304. package/plugins/bizar/tests/safety.test.ts +0 -281
  305. package/plugins/bizar/tests/serve.test.ts +0 -339
  306. package/plugins/bizar/tests/settings.test.ts +0 -351
  307. package/plugins/bizar/tests/stall-think.test.ts +0 -750
  308. package/plugins/bizar/tests/state.test.ts +0 -276
  309. package/plugins/bizar/tests/tool-discipline.test.ts +0 -77
  310. package/plugins/bizar/tests/tools/agent-browser.test.ts +0 -98
  311. package/plugins/bizar/tests/tools/bg-collect.test.ts +0 -337
  312. package/plugins/bizar/tests/tools/bg-get-comments.test.ts +0 -485
  313. package/plugins/bizar/tests/tools/bg-kill.test.ts +0 -235
  314. package/plugins/bizar/tests/tools/bg-pause.test.ts +0 -61
  315. package/plugins/bizar/tests/tools/bg-report-progress.test.ts +0 -79
  316. package/plugins/bizar/tests/tools/bg-resume.test.ts +0 -40
  317. package/plugins/bizar/tests/tools/bg-send-message.test.ts +0 -116
  318. package/plugins/bizar/tests/tools/bg-spawn-delegation.test.ts +0 -147
  319. package/plugins/bizar/tests/tools/bg-spawn-http.test.ts +0 -233
  320. package/plugins/bizar/tests/tools/bg-spawn.test.ts +0 -311
  321. package/plugins/bizar/tests/tools/bg-status.test.ts +0 -217
  322. package/plugins/bizar/tests/tools/cline-runner.test.ts +0 -115
  323. package/plugins/bizar/tests/tools/plan-action.test.ts +0 -599
  324. package/plugins/bizar/tests/tools/read-glyph-feedback.test.ts +0 -253
  325. package/plugins/bizar/tests/tools/sandbox.test.ts +0 -117
  326. package/plugins/bizar/tests/tools/wait-for-feedback.test.ts +0 -390
  327. package/plugins/bizar/tests/update-deadlock.test.ts +0 -151
  328. package/plugins/bizar/tsconfig.json +0 -29
  329. package/scripts/mirror-agents-md.sh +0 -69
@@ -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