agent-bober 0.11.6 → 0.15.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 (570) hide show
  1. package/CHANGELOG.md +311 -0
  2. package/README.md +124 -9
  3. package/agents/bober-architect.md +38 -0
  4. package/agents/bober-code-reviewer.md +236 -0
  5. package/agents/bober-curator.md +37 -0
  6. package/agents/bober-deployer.md +267 -0
  7. package/agents/bober-diagnoser.md +289 -0
  8. package/agents/bober-evaluator.md +127 -1
  9. package/agents/bober-generator.md +122 -3
  10. package/agents/bober-planner.md +293 -32
  11. package/agents/bober-postmortemer.md +185 -0
  12. package/agents/bober-researcher.md +38 -0
  13. package/dist/cli/commands/approve.d.ts +17 -0
  14. package/dist/cli/commands/approve.d.ts.map +1 -0
  15. package/dist/cli/commands/approve.js +64 -0
  16. package/dist/cli/commands/approve.js.map +1 -0
  17. package/dist/cli/commands/audit-show.d.ts +14 -0
  18. package/dist/cli/commands/audit-show.d.ts.map +1 -0
  19. package/dist/cli/commands/audit-show.js +85 -0
  20. package/dist/cli/commands/audit-show.js.map +1 -0
  21. package/dist/cli/commands/config.d.ts +10 -0
  22. package/dist/cli/commands/config.d.ts.map +1 -0
  23. package/dist/cli/commands/config.js +73 -0
  24. package/dist/cli/commands/config.js.map +1 -0
  25. package/dist/cli/commands/eval.js +6 -6
  26. package/dist/cli/commands/eval.js.map +1 -1
  27. package/dist/cli/commands/graph.d.ts +8 -0
  28. package/dist/cli/commands/graph.d.ts.map +1 -0
  29. package/dist/cli/commands/graph.js +219 -0
  30. package/dist/cli/commands/graph.js.map +1 -0
  31. package/dist/cli/commands/impact.d.ts +19 -0
  32. package/dist/cli/commands/impact.d.ts.map +1 -0
  33. package/dist/cli/commands/impact.js +191 -0
  34. package/dist/cli/commands/impact.js.map +1 -0
  35. package/dist/cli/commands/incident.d.ts +19 -0
  36. package/dist/cli/commands/incident.d.ts.map +1 -0
  37. package/dist/cli/commands/incident.js +324 -0
  38. package/dist/cli/commands/incident.js.map +1 -0
  39. package/dist/cli/commands/init.js +82 -3
  40. package/dist/cli/commands/init.js.map +1 -1
  41. package/dist/cli/commands/list-approvals.d.ts +16 -0
  42. package/dist/cli/commands/list-approvals.d.ts.map +1 -0
  43. package/dist/cli/commands/list-approvals.js +57 -0
  44. package/dist/cli/commands/list-approvals.js.map +1 -0
  45. package/dist/cli/commands/onboard.d.ts +3 -0
  46. package/dist/cli/commands/onboard.d.ts.map +1 -0
  47. package/dist/cli/commands/onboard.js +190 -0
  48. package/dist/cli/commands/onboard.js.map +1 -0
  49. package/dist/cli/commands/plan.d.ts +12 -0
  50. package/dist/cli/commands/plan.d.ts.map +1 -1
  51. package/dist/cli/commands/plan.js +232 -37
  52. package/dist/cli/commands/plan.js.map +1 -1
  53. package/dist/cli/commands/playbook.d.ts +17 -0
  54. package/dist/cli/commands/playbook.d.ts.map +1 -0
  55. package/dist/cli/commands/playbook.js +123 -0
  56. package/dist/cli/commands/playbook.js.map +1 -0
  57. package/dist/cli/commands/postmortem.d.ts +12 -0
  58. package/dist/cli/commands/postmortem.d.ts.map +1 -0
  59. package/dist/cli/commands/postmortem.js +67 -0
  60. package/dist/cli/commands/postmortem.js.map +1 -0
  61. package/dist/cli/commands/reject.d.ts +17 -0
  62. package/dist/cli/commands/reject.d.ts.map +1 -0
  63. package/dist/cli/commands/reject.js +52 -0
  64. package/dist/cli/commands/reject.js.map +1 -0
  65. package/dist/cli/commands/rollback.d.ts +21 -0
  66. package/dist/cli/commands/rollback.d.ts.map +1 -0
  67. package/dist/cli/commands/rollback.js +90 -0
  68. package/dist/cli/commands/rollback.js.map +1 -0
  69. package/dist/cli/commands/run.d.ts +9 -0
  70. package/dist/cli/commands/run.d.ts.map +1 -1
  71. package/dist/cli/commands/run.js +31 -2
  72. package/dist/cli/commands/run.js.map +1 -1
  73. package/dist/cli/commands/sprint.d.ts.map +1 -1
  74. package/dist/cli/commands/sprint.js +8 -8
  75. package/dist/cli/commands/sprint.js.map +1 -1
  76. package/dist/cli/commands/telemetry.d.ts +16 -0
  77. package/dist/cli/commands/telemetry.d.ts.map +1 -0
  78. package/dist/cli/commands/telemetry.js +152 -0
  79. package/dist/cli/commands/telemetry.js.map +1 -0
  80. package/dist/cli/commands/worktree.d.ts +12 -0
  81. package/dist/cli/commands/worktree.d.ts.map +1 -0
  82. package/dist/cli/commands/worktree.js +57 -0
  83. package/dist/cli/commands/worktree.js.map +1 -0
  84. package/dist/cli/index.js +73 -2
  85. package/dist/cli/index.js.map +1 -1
  86. package/dist/config/defaults.d.ts.map +1 -1
  87. package/dist/config/defaults.js +27 -0
  88. package/dist/config/defaults.js.map +1 -1
  89. package/dist/config/index.d.ts +1 -1
  90. package/dist/config/index.d.ts.map +1 -1
  91. package/dist/config/index.js +4 -0
  92. package/dist/config/index.js.map +1 -1
  93. package/dist/config/loader.d.ts.map +1 -1
  94. package/dist/config/loader.js +18 -1
  95. package/dist/config/loader.js.map +1 -1
  96. package/dist/config/schema.d.ts +1016 -96
  97. package/dist/config/schema.d.ts.map +1 -1
  98. package/dist/config/schema.js +147 -0
  99. package/dist/config/schema.js.map +1 -1
  100. package/dist/contracts/eval-result.d.ts +38 -38
  101. package/dist/contracts/index.d.ts +2 -2
  102. package/dist/contracts/index.d.ts.map +1 -1
  103. package/dist/contracts/index.js +8 -4
  104. package/dist/contracts/index.js.map +1 -1
  105. package/dist/contracts/spec.d.ts +335 -40
  106. package/dist/contracts/spec.d.ts.map +1 -1
  107. package/dist/contracts/spec.js +210 -18
  108. package/dist/contracts/spec.js.map +1 -1
  109. package/dist/contracts/sprint-contract.d.ts +155 -88
  110. package/dist/contracts/sprint-contract.d.ts.map +1 -1
  111. package/dist/contracts/sprint-contract.js +176 -29
  112. package/dist/contracts/sprint-contract.js.map +1 -1
  113. package/dist/evaluators/builtin/api-check.js +1 -1
  114. package/dist/evaluators/builtin/api-check.js.map +1 -1
  115. package/dist/graph/artifact-store.d.ts +14 -0
  116. package/dist/graph/artifact-store.d.ts.map +1 -0
  117. package/dist/graph/artifact-store.js +100 -0
  118. package/dist/graph/artifact-store.js.map +1 -0
  119. package/dist/graph/cli.d.ts +49 -0
  120. package/dist/graph/cli.d.ts.map +1 -0
  121. package/dist/graph/cli.js +140 -0
  122. package/dist/graph/cli.js.map +1 -0
  123. package/dist/graph/client.d.ts +64 -0
  124. package/dist/graph/client.d.ts.map +1 -0
  125. package/dist/graph/client.js +216 -0
  126. package/dist/graph/client.js.map +1 -0
  127. package/dist/graph/fallback.d.ts +13 -0
  128. package/dist/graph/fallback.d.ts.map +1 -0
  129. package/dist/graph/fallback.js +57 -0
  130. package/dist/graph/fallback.js.map +1 -0
  131. package/dist/graph/hook-handler.d.ts +50 -0
  132. package/dist/graph/hook-handler.d.ts.map +1 -0
  133. package/dist/graph/hook-handler.js +217 -0
  134. package/dist/graph/hook-handler.js.map +1 -0
  135. package/dist/graph/incidents.d.ts +59 -0
  136. package/dist/graph/incidents.d.ts.map +1 -0
  137. package/dist/graph/incidents.js +22 -0
  138. package/dist/graph/incidents.js.map +1 -0
  139. package/dist/graph/mcp-client.d.ts +51 -0
  140. package/dist/graph/mcp-client.d.ts.map +1 -0
  141. package/dist/graph/mcp-client.js +285 -0
  142. package/dist/graph/mcp-client.js.map +1 -0
  143. package/dist/graph/onboarding-composer.d.ts +30 -0
  144. package/dist/graph/onboarding-composer.d.ts.map +1 -0
  145. package/dist/graph/onboarding-composer.js +275 -0
  146. package/dist/graph/onboarding-composer.js.map +1 -0
  147. package/dist/graph/pipeline-lifecycle.d.ts +86 -0
  148. package/dist/graph/pipeline-lifecycle.d.ts.map +1 -0
  149. package/dist/graph/pipeline-lifecycle.js +329 -0
  150. package/dist/graph/pipeline-lifecycle.js.map +1 -0
  151. package/dist/graph/preflight-budgets.d.ts +52 -0
  152. package/dist/graph/preflight-budgets.d.ts.map +1 -0
  153. package/dist/graph/preflight-budgets.js +78 -0
  154. package/dist/graph/preflight-budgets.js.map +1 -0
  155. package/dist/graph/preflight-injector.d.ts +116 -0
  156. package/dist/graph/preflight-injector.d.ts.map +1 -0
  157. package/dist/graph/preflight-injector.js +538 -0
  158. package/dist/graph/preflight-injector.js.map +1 -0
  159. package/dist/graph/prereq.d.ts +12 -0
  160. package/dist/graph/prereq.d.ts.map +1 -0
  161. package/dist/graph/prereq.js +61 -0
  162. package/dist/graph/prereq.js.map +1 -0
  163. package/dist/graph/prompts.d.ts +42 -0
  164. package/dist/graph/prompts.d.ts.map +1 -0
  165. package/dist/graph/prompts.js +80 -0
  166. package/dist/graph/prompts.js.map +1 -0
  167. package/dist/graph/sandbox.d.ts +19 -0
  168. package/dist/graph/sandbox.d.ts.map +1 -0
  169. package/dist/graph/sandbox.js +25 -0
  170. package/dist/graph/sandbox.js.map +1 -0
  171. package/dist/graph/token-usage.d.ts +21 -0
  172. package/dist/graph/token-usage.d.ts.map +1 -0
  173. package/dist/graph/token-usage.js +22 -0
  174. package/dist/graph/token-usage.js.map +1 -0
  175. package/dist/graph/types.d.ts +129 -0
  176. package/dist/graph/types.d.ts.map +1 -0
  177. package/dist/graph/types.js +12 -0
  178. package/dist/graph/types.js.map +1 -0
  179. package/dist/incident/orchestrator.d.ts +168 -0
  180. package/dist/incident/orchestrator.d.ts.map +1 -0
  181. package/dist/incident/orchestrator.js +279 -0
  182. package/dist/incident/orchestrator.js.map +1 -0
  183. package/dist/incident/playbook-search.d.ts +67 -0
  184. package/dist/incident/playbook-search.d.ts.map +1 -0
  185. package/dist/incident/playbook-search.js +288 -0
  186. package/dist/incident/playbook-search.js.map +1 -0
  187. package/dist/incident/postmortem.d.ts +44 -0
  188. package/dist/incident/postmortem.d.ts.map +1 -0
  189. package/dist/incident/postmortem.js +486 -0
  190. package/dist/incident/postmortem.js.map +1 -0
  191. package/dist/incident/resolution-verify.d.ts +186 -0
  192. package/dist/incident/resolution-verify.d.ts.map +1 -0
  193. package/dist/incident/resolution-verify.js +210 -0
  194. package/dist/incident/resolution-verify.js.map +1 -0
  195. package/dist/incident/rollback.d.ts +137 -0
  196. package/dist/incident/rollback.d.ts.map +1 -0
  197. package/dist/incident/rollback.js +328 -0
  198. package/dist/incident/rollback.js.map +1 -0
  199. package/dist/incident/timeline.d.ts +147 -0
  200. package/dist/incident/timeline.d.ts.map +1 -0
  201. package/dist/incident/timeline.js +452 -0
  202. package/dist/incident/timeline.js.map +1 -0
  203. package/dist/incident/types.d.ts +335 -0
  204. package/dist/incident/types.d.ts.map +1 -0
  205. package/dist/incident/types.js +158 -0
  206. package/dist/incident/types.js.map +1 -0
  207. package/dist/index.d.ts +3 -3
  208. package/dist/index.d.ts.map +1 -1
  209. package/dist/index.js +3 -3
  210. package/dist/index.js.map +1 -1
  211. package/dist/mcp/event-stream.d.ts +46 -0
  212. package/dist/mcp/event-stream.d.ts.map +1 -0
  213. package/dist/mcp/event-stream.js +421 -0
  214. package/dist/mcp/event-stream.js.map +1 -0
  215. package/dist/mcp/external-client.d.ts +38 -0
  216. package/dist/mcp/external-client.d.ts.map +1 -0
  217. package/dist/mcp/external-client.js +121 -0
  218. package/dist/mcp/external-client.js.map +1 -0
  219. package/dist/mcp/run-manager.d.ts +74 -9
  220. package/dist/mcp/run-manager.d.ts.map +1 -1
  221. package/dist/mcp/run-manager.js +127 -31
  222. package/dist/mcp/run-manager.js.map +1 -1
  223. package/dist/mcp/server.d.ts.map +1 -1
  224. package/dist/mcp/server.js +56 -0
  225. package/dist/mcp/server.js.map +1 -1
  226. package/dist/mcp/tools/abort-run.d.ts +2 -0
  227. package/dist/mcp/tools/abort-run.d.ts.map +1 -0
  228. package/dist/mcp/tools/abort-run.js +62 -0
  229. package/dist/mcp/tools/abort-run.js.map +1 -0
  230. package/dist/mcp/tools/anchor.js +1 -1
  231. package/dist/mcp/tools/anchor.js.map +1 -1
  232. package/dist/mcp/tools/approve-checkpoint.d.ts +2 -0
  233. package/dist/mcp/tools/approve-checkpoint.d.ts.map +1 -0
  234. package/dist/mcp/tools/approve-checkpoint.js +70 -0
  235. package/dist/mcp/tools/approve-checkpoint.js.map +1 -0
  236. package/dist/mcp/tools/brownfield.js +1 -1
  237. package/dist/mcp/tools/brownfield.js.map +1 -1
  238. package/dist/mcp/tools/contracts.js +2 -2
  239. package/dist/mcp/tools/contracts.js.map +1 -1
  240. package/dist/mcp/tools/eval.js +8 -8
  241. package/dist/mcp/tools/eval.js.map +1 -1
  242. package/dist/mcp/tools/get-project-state.d.ts +2 -0
  243. package/dist/mcp/tools/get-project-state.d.ts.map +1 -0
  244. package/dist/mcp/tools/get-project-state.js +107 -0
  245. package/dist/mcp/tools/get-project-state.js.map +1 -0
  246. package/dist/mcp/tools/get-run-status.d.ts +2 -0
  247. package/dist/mcp/tools/get-run-status.d.ts.map +1 -0
  248. package/dist/mcp/tools/get-run-status.js +40 -0
  249. package/dist/mcp/tools/get-run-status.js.map +1 -0
  250. package/dist/mcp/tools/graph-schemas.d.ts +100 -0
  251. package/dist/mcp/tools/graph-schemas.d.ts.map +1 -0
  252. package/dist/mcp/tools/graph-schemas.js +39 -0
  253. package/dist/mcp/tools/graph-schemas.js.map +1 -0
  254. package/dist/mcp/tools/graph.d.ts +19 -0
  255. package/dist/mcp/tools/graph.d.ts.map +1 -0
  256. package/dist/mcp/tools/graph.js +263 -0
  257. package/dist/mcp/tools/graph.js.map +1 -0
  258. package/dist/mcp/tools/incident.d.ts +2 -0
  259. package/dist/mcp/tools/incident.d.ts.map +1 -0
  260. package/dist/mcp/tools/incident.js +246 -0
  261. package/dist/mcp/tools/incident.js.map +1 -0
  262. package/dist/mcp/tools/index.d.ts +38 -18
  263. package/dist/mcp/tools/index.d.ts.map +1 -1
  264. package/dist/mcp/tools/index.js +74 -18
  265. package/dist/mcp/tools/index.js.map +1 -1
  266. package/dist/mcp/tools/list-active-runs.d.ts +2 -0
  267. package/dist/mcp/tools/list-active-runs.d.ts.map +1 -0
  268. package/dist/mcp/tools/list-active-runs.js +35 -0
  269. package/dist/mcp/tools/list-active-runs.js.map +1 -0
  270. package/dist/mcp/tools/list-pending-approvals.d.ts +2 -0
  271. package/dist/mcp/tools/list-pending-approvals.d.ts.map +1 -0
  272. package/dist/mcp/tools/list-pending-approvals.js +40 -0
  273. package/dist/mcp/tools/list-pending-approvals.js.map +1 -0
  274. package/dist/mcp/tools/list-projects.d.ts +2 -0
  275. package/dist/mcp/tools/list-projects.d.ts.map +1 -0
  276. package/dist/mcp/tools/list-projects.js +101 -0
  277. package/dist/mcp/tools/list-projects.js.map +1 -0
  278. package/dist/mcp/tools/list-specs.d.ts +2 -0
  279. package/dist/mcp/tools/list-specs.d.ts.map +1 -0
  280. package/dist/mcp/tools/list-specs.js +48 -0
  281. package/dist/mcp/tools/list-specs.js.map +1 -0
  282. package/dist/mcp/tools/plan.d.ts.map +1 -1
  283. package/dist/mcp/tools/plan.js +40 -14
  284. package/dist/mcp/tools/plan.js.map +1 -1
  285. package/dist/mcp/tools/playbook.d.ts +2 -0
  286. package/dist/mcp/tools/playbook.d.ts.map +1 -0
  287. package/dist/mcp/tools/playbook.js +104 -0
  288. package/dist/mcp/tools/playbook.js.map +1 -0
  289. package/dist/mcp/tools/postmortem.d.ts +2 -0
  290. package/dist/mcp/tools/postmortem.d.ts.map +1 -0
  291. package/dist/mcp/tools/postmortem.js +75 -0
  292. package/dist/mcp/tools/postmortem.js.map +1 -0
  293. package/dist/mcp/tools/react.js +1 -1
  294. package/dist/mcp/tools/react.js.map +1 -1
  295. package/dist/mcp/tools/reject-checkpoint.d.ts +2 -0
  296. package/dist/mcp/tools/reject-checkpoint.d.ts.map +1 -0
  297. package/dist/mcp/tools/reject-checkpoint.js +79 -0
  298. package/dist/mcp/tools/reject-checkpoint.js.map +1 -0
  299. package/dist/mcp/tools/rollback.d.ts +2 -0
  300. package/dist/mcp/tools/rollback.d.ts.map +1 -0
  301. package/dist/mcp/tools/rollback.js +78 -0
  302. package/dist/mcp/tools/rollback.js.map +1 -0
  303. package/dist/mcp/tools/run-in-worktree.d.ts +2 -0
  304. package/dist/mcp/tools/run-in-worktree.d.ts.map +1 -0
  305. package/dist/mcp/tools/run-in-worktree.js +90 -0
  306. package/dist/mcp/tools/run-in-worktree.js.map +1 -0
  307. package/dist/mcp/tools/run.js +1 -1
  308. package/dist/mcp/tools/run.js.map +1 -1
  309. package/dist/mcp/tools/solidity.js +1 -1
  310. package/dist/mcp/tools/solidity.js.map +1 -1
  311. package/dist/mcp/tools/sprint.d.ts.map +1 -1
  312. package/dist/mcp/tools/sprint.js +11 -11
  313. package/dist/mcp/tools/sprint.js.map +1 -1
  314. package/dist/mcp/tools/status.d.ts.map +1 -1
  315. package/dist/mcp/tools/status.js +11 -0
  316. package/dist/mcp/tools/status.js.map +1 -1
  317. package/dist/mcp/tools/subscribe-events.d.ts +2 -0
  318. package/dist/mcp/tools/subscribe-events.d.ts.map +1 -0
  319. package/dist/mcp/tools/subscribe-events.js +48 -0
  320. package/dist/mcp/tools/subscribe-events.js.map +1 -0
  321. package/dist/mcp/tools/unsubscribe-events.d.ts +2 -0
  322. package/dist/mcp/tools/unsubscribe-events.d.ts.map +1 -0
  323. package/dist/mcp/tools/unsubscribe-events.js +45 -0
  324. package/dist/mcp/tools/unsubscribe-events.js.map +1 -0
  325. package/dist/orchestrator/agent-loader.d.ts +16 -0
  326. package/dist/orchestrator/agent-loader.d.ts.map +1 -1
  327. package/dist/orchestrator/agent-loader.js +16 -0
  328. package/dist/orchestrator/agent-loader.js.map +1 -1
  329. package/dist/orchestrator/architect-agent.d.ts.map +1 -1
  330. package/dist/orchestrator/architect-agent.js +37 -8
  331. package/dist/orchestrator/architect-agent.js.map +1 -1
  332. package/dist/orchestrator/checkpoints/audit.d.ts +128 -0
  333. package/dist/orchestrator/checkpoints/audit.d.ts.map +1 -0
  334. package/dist/orchestrator/checkpoints/audit.js +272 -0
  335. package/dist/orchestrator/checkpoints/audit.js.map +1 -0
  336. package/dist/orchestrator/checkpoints/feedback-router.d.ts +213 -0
  337. package/dist/orchestrator/checkpoints/feedback-router.d.ts.map +1 -0
  338. package/dist/orchestrator/checkpoints/feedback-router.js +438 -0
  339. package/dist/orchestrator/checkpoints/feedback-router.js.map +1 -0
  340. package/dist/orchestrator/checkpoints/index.d.ts +11 -0
  341. package/dist/orchestrator/checkpoints/index.d.ts.map +1 -0
  342. package/dist/orchestrator/checkpoints/index.js +12 -0
  343. package/dist/orchestrator/checkpoints/index.js.map +1 -0
  344. package/dist/orchestrator/checkpoints/mechanisms/cli.d.ts +35 -0
  345. package/dist/orchestrator/checkpoints/mechanisms/cli.d.ts.map +1 -0
  346. package/dist/orchestrator/checkpoints/mechanisms/cli.js +153 -0
  347. package/dist/orchestrator/checkpoints/mechanisms/cli.js.map +1 -0
  348. package/dist/orchestrator/checkpoints/mechanisms/disk.d.ts +34 -0
  349. package/dist/orchestrator/checkpoints/mechanisms/disk.d.ts.map +1 -0
  350. package/dist/orchestrator/checkpoints/mechanisms/disk.js +139 -0
  351. package/dist/orchestrator/checkpoints/mechanisms/disk.js.map +1 -0
  352. package/dist/orchestrator/checkpoints/mechanisms/pr.d.ts +141 -0
  353. package/dist/orchestrator/checkpoints/mechanisms/pr.d.ts.map +1 -0
  354. package/dist/orchestrator/checkpoints/mechanisms/pr.js +445 -0
  355. package/dist/orchestrator/checkpoints/mechanisms/pr.js.map +1 -0
  356. package/dist/orchestrator/checkpoints/noop.d.ts +12 -0
  357. package/dist/orchestrator/checkpoints/noop.d.ts.map +1 -0
  358. package/dist/orchestrator/checkpoints/noop.js +13 -0
  359. package/dist/orchestrator/checkpoints/noop.js.map +1 -0
  360. package/dist/orchestrator/checkpoints/registry.d.ts +48 -0
  361. package/dist/orchestrator/checkpoints/registry.d.ts.map +1 -0
  362. package/dist/orchestrator/checkpoints/registry.js +89 -0
  363. package/dist/orchestrator/checkpoints/registry.js.map +1 -0
  364. package/dist/orchestrator/checkpoints/renderers/_util.d.ts +50 -0
  365. package/dist/orchestrator/checkpoints/renderers/_util.d.ts.map +1 -0
  366. package/dist/orchestrator/checkpoints/renderers/_util.js +137 -0
  367. package/dist/orchestrator/checkpoints/renderers/_util.js.map +1 -0
  368. package/dist/orchestrator/checkpoints/renderers/code-review.d.ts +15 -0
  369. package/dist/orchestrator/checkpoints/renderers/code-review.d.ts.map +1 -0
  370. package/dist/orchestrator/checkpoints/renderers/code-review.js +66 -0
  371. package/dist/orchestrator/checkpoints/renderers/code-review.js.map +1 -0
  372. package/dist/orchestrator/checkpoints/renderers/curator-briefing.d.ts +15 -0
  373. package/dist/orchestrator/checkpoints/renderers/curator-briefing.d.ts.map +1 -0
  374. package/dist/orchestrator/checkpoints/renderers/curator-briefing.js +40 -0
  375. package/dist/orchestrator/checkpoints/renderers/curator-briefing.js.map +1 -0
  376. package/dist/orchestrator/checkpoints/renderers/eval-result.d.ts +15 -0
  377. package/dist/orchestrator/checkpoints/renderers/eval-result.d.ts.map +1 -0
  378. package/dist/orchestrator/checkpoints/renderers/eval-result.js +54 -0
  379. package/dist/orchestrator/checkpoints/renderers/eval-result.js.map +1 -0
  380. package/dist/orchestrator/checkpoints/renderers/generator-diff.d.ts +49 -0
  381. package/dist/orchestrator/checkpoints/renderers/generator-diff.d.ts.map +1 -0
  382. package/dist/orchestrator/checkpoints/renderers/generator-diff.js +154 -0
  383. package/dist/orchestrator/checkpoints/renderers/generator-diff.js.map +1 -0
  384. package/dist/orchestrator/checkpoints/renderers/pipeline-summary.d.ts +15 -0
  385. package/dist/orchestrator/checkpoints/renderers/pipeline-summary.d.ts.map +1 -0
  386. package/dist/orchestrator/checkpoints/renderers/pipeline-summary.js +59 -0
  387. package/dist/orchestrator/checkpoints/renderers/pipeline-summary.js.map +1 -0
  388. package/dist/orchestrator/checkpoints/renderers/plan.d.ts +15 -0
  389. package/dist/orchestrator/checkpoints/renderers/plan.d.ts.map +1 -0
  390. package/dist/orchestrator/checkpoints/renderers/plan.js +34 -0
  391. package/dist/orchestrator/checkpoints/renderers/plan.js.map +1 -0
  392. package/dist/orchestrator/checkpoints/renderers/registry.d.ts +43 -0
  393. package/dist/orchestrator/checkpoints/renderers/registry.d.ts.map +1 -0
  394. package/dist/orchestrator/checkpoints/renderers/registry.js +83 -0
  395. package/dist/orchestrator/checkpoints/renderers/registry.js.map +1 -0
  396. package/dist/orchestrator/checkpoints/renderers/research.d.ts +15 -0
  397. package/dist/orchestrator/checkpoints/renderers/research.d.ts.map +1 -0
  398. package/dist/orchestrator/checkpoints/renderers/research.js +39 -0
  399. package/dist/orchestrator/checkpoints/renderers/research.js.map +1 -0
  400. package/dist/orchestrator/checkpoints/renderers/sprint-contract.d.ts +20 -0
  401. package/dist/orchestrator/checkpoints/renderers/sprint-contract.d.ts.map +1 -0
  402. package/dist/orchestrator/checkpoints/renderers/sprint-contract.js +57 -0
  403. package/dist/orchestrator/checkpoints/renderers/sprint-contract.js.map +1 -0
  404. package/dist/orchestrator/checkpoints/renderers/sprint-summary.d.ts +15 -0
  405. package/dist/orchestrator/checkpoints/renderers/sprint-summary.d.ts.map +1 -0
  406. package/dist/orchestrator/checkpoints/renderers/sprint-summary.js +38 -0
  407. package/dist/orchestrator/checkpoints/renderers/sprint-summary.js.map +1 -0
  408. package/dist/orchestrator/checkpoints/sites.d.ts +22 -0
  409. package/dist/orchestrator/checkpoints/sites.d.ts.map +1 -0
  410. package/dist/orchestrator/checkpoints/sites.js +57 -0
  411. package/dist/orchestrator/checkpoints/sites.js.map +1 -0
  412. package/dist/orchestrator/checkpoints/types.d.ts +51 -0
  413. package/dist/orchestrator/checkpoints/types.d.ts.map +1 -0
  414. package/dist/orchestrator/checkpoints/types.js +9 -0
  415. package/dist/orchestrator/checkpoints/types.js.map +1 -0
  416. package/dist/orchestrator/code-reviewer-agent.d.ts +50 -0
  417. package/dist/orchestrator/code-reviewer-agent.d.ts.map +1 -0
  418. package/dist/orchestrator/code-reviewer-agent.js +283 -0
  419. package/dist/orchestrator/code-reviewer-agent.js.map +1 -0
  420. package/dist/orchestrator/context-handoff.d.ts +484 -224
  421. package/dist/orchestrator/context-handoff.d.ts.map +1 -1
  422. package/dist/orchestrator/context-handoff.js +32 -12
  423. package/dist/orchestrator/context-handoff.js.map +1 -1
  424. package/dist/orchestrator/curator-agent.d.ts.map +1 -1
  425. package/dist/orchestrator/curator-agent.js +63 -12
  426. package/dist/orchestrator/curator-agent.js.map +1 -1
  427. package/dist/orchestrator/deploy/classify.d.ts +31 -0
  428. package/dist/orchestrator/deploy/classify.d.ts.map +1 -0
  429. package/dist/orchestrator/deploy/classify.js +109 -0
  430. package/dist/orchestrator/deploy/classify.js.map +1 -0
  431. package/dist/orchestrator/deploy/execute.d.ts +45 -0
  432. package/dist/orchestrator/deploy/execute.d.ts.map +1 -0
  433. package/dist/orchestrator/deploy/execute.js +146 -0
  434. package/dist/orchestrator/deploy/execute.js.map +1 -0
  435. package/dist/orchestrator/deploy/executor.d.ts +22 -0
  436. package/dist/orchestrator/deploy/executor.d.ts.map +1 -0
  437. package/dist/orchestrator/deploy/executor.js +31 -0
  438. package/dist/orchestrator/deploy/executor.js.map +1 -0
  439. package/dist/orchestrator/deploy/index.d.ts +21 -0
  440. package/dist/orchestrator/deploy/index.d.ts.map +1 -0
  441. package/dist/orchestrator/deploy/index.js +21 -0
  442. package/dist/orchestrator/deploy/index.js.map +1 -0
  443. package/dist/orchestrator/deploy/resolve.d.ts +51 -0
  444. package/dist/orchestrator/deploy/resolve.d.ts.map +1 -0
  445. package/dist/orchestrator/deploy/resolve.js +53 -0
  446. package/dist/orchestrator/deploy/resolve.js.map +1 -0
  447. package/dist/orchestrator/deploy/spawn.d.ts +60 -0
  448. package/dist/orchestrator/deploy/spawn.d.ts.map +1 -0
  449. package/dist/orchestrator/deploy/spawn.js +62 -0
  450. package/dist/orchestrator/deploy/spawn.js.map +1 -0
  451. package/dist/orchestrator/deploy/types.d.ts +98 -0
  452. package/dist/orchestrator/deploy/types.d.ts.map +1 -0
  453. package/dist/orchestrator/deploy/types.js +39 -0
  454. package/dist/orchestrator/deploy/types.js.map +1 -0
  455. package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
  456. package/dist/orchestrator/evaluator-agent.js +23 -10
  457. package/dist/orchestrator/evaluator-agent.js.map +1 -1
  458. package/dist/orchestrator/generator-agent.d.ts.map +1 -1
  459. package/dist/orchestrator/generator-agent.js +24 -11
  460. package/dist/orchestrator/generator-agent.js.map +1 -1
  461. package/dist/orchestrator/model-resolver.d.ts.map +1 -1
  462. package/dist/orchestrator/model-resolver.js +4 -2
  463. package/dist/orchestrator/model-resolver.js.map +1 -1
  464. package/dist/orchestrator/observability/index.d.ts +12 -0
  465. package/dist/orchestrator/observability/index.d.ts.map +1 -0
  466. package/dist/orchestrator/observability/index.js +12 -0
  467. package/dist/orchestrator/observability/index.js.map +1 -0
  468. package/dist/orchestrator/observability/merge.d.ts +73 -0
  469. package/dist/orchestrator/observability/merge.d.ts.map +1 -0
  470. package/dist/orchestrator/observability/merge.js +110 -0
  471. package/dist/orchestrator/observability/merge.js.map +1 -0
  472. package/dist/orchestrator/pipeline.d.ts +28 -0
  473. package/dist/orchestrator/pipeline.d.ts.map +1 -1
  474. package/dist/orchestrator/pipeline.js +223 -30
  475. package/dist/orchestrator/pipeline.js.map +1 -1
  476. package/dist/orchestrator/planner-agent.d.ts +21 -1
  477. package/dist/orchestrator/planner-agent.d.ts.map +1 -1
  478. package/dist/orchestrator/planner-agent.js +16 -6
  479. package/dist/orchestrator/planner-agent.js.map +1 -1
  480. package/dist/orchestrator/research-agent.d.ts.map +1 -1
  481. package/dist/orchestrator/research-agent.js +46 -9
  482. package/dist/orchestrator/research-agent.js.map +1 -1
  483. package/dist/orchestrator/tools/handlers.d.ts +2 -0
  484. package/dist/orchestrator/tools/handlers.d.ts.map +1 -1
  485. package/dist/orchestrator/tools/handlers.js +1 -1
  486. package/dist/orchestrator/tools/handlers.js.map +1 -1
  487. package/dist/orchestrator/tools/index.d.ts +84 -1
  488. package/dist/orchestrator/tools/index.d.ts.map +1 -1
  489. package/dist/orchestrator/tools/index.js +164 -1
  490. package/dist/orchestrator/tools/index.js.map +1 -1
  491. package/dist/orchestrator/worktree.d.ts +18 -0
  492. package/dist/orchestrator/worktree.d.ts.map +1 -0
  493. package/dist/orchestrator/worktree.js +129 -0
  494. package/dist/orchestrator/worktree.js.map +1 -0
  495. package/dist/providers/anthropic.d.ts +8 -1
  496. package/dist/providers/anthropic.d.ts.map +1 -1
  497. package/dist/providers/anthropic.js +86 -5
  498. package/dist/providers/anthropic.js.map +1 -1
  499. package/dist/providers/factory.d.ts.map +1 -1
  500. package/dist/providers/factory.js +35 -2
  501. package/dist/providers/factory.js.map +1 -1
  502. package/dist/providers/google.d.ts.map +1 -1
  503. package/dist/providers/google.js +5 -0
  504. package/dist/providers/google.js.map +1 -1
  505. package/dist/providers/index.d.ts +1 -1
  506. package/dist/providers/index.d.ts.map +1 -1
  507. package/dist/providers/index.js.map +1 -1
  508. package/dist/providers/openai.d.ts.map +1 -1
  509. package/dist/providers/openai.js +4 -0
  510. package/dist/providers/openai.js.map +1 -1
  511. package/dist/providers/types.d.ts +25 -2
  512. package/dist/providers/types.d.ts.map +1 -1
  513. package/dist/state/approval-state.d.ts +74 -0
  514. package/dist/state/approval-state.d.ts.map +1 -0
  515. package/dist/state/approval-state.js +127 -0
  516. package/dist/state/approval-state.js.map +1 -0
  517. package/dist/state/history.d.ts.map +1 -1
  518. package/dist/state/history.js +3 -3
  519. package/dist/state/history.js.map +1 -1
  520. package/dist/state/index.d.ts +3 -0
  521. package/dist/state/index.d.ts.map +1 -1
  522. package/dist/state/index.js +4 -1
  523. package/dist/state/index.js.map +1 -1
  524. package/dist/state/plan-state.js +1 -1
  525. package/dist/state/plan-state.js.map +1 -1
  526. package/dist/state/review-state.d.ts +15 -0
  527. package/dist/state/review-state.d.ts.map +1 -0
  528. package/dist/state/review-state.js +51 -0
  529. package/dist/state/review-state.js.map +1 -0
  530. package/dist/state/run-state.d.ts +39 -0
  531. package/dist/state/run-state.d.ts.map +1 -0
  532. package/dist/state/run-state.js +101 -0
  533. package/dist/state/run-state.js.map +1 -0
  534. package/dist/state/sprint-state.d.ts +9 -2
  535. package/dist/state/sprint-state.d.ts.map +1 -1
  536. package/dist/state/sprint-state.js +25 -11
  537. package/dist/state/sprint-state.js.map +1 -1
  538. package/dist/telemetry/emit.d.ts +41 -0
  539. package/dist/telemetry/emit.d.ts.map +1 -0
  540. package/dist/telemetry/emit.js +65 -0
  541. package/dist/telemetry/emit.js.map +1 -0
  542. package/dist/utils/git.d.ts +27 -0
  543. package/dist/utils/git.d.ts.map +1 -1
  544. package/dist/utils/git.js +50 -0
  545. package/dist/utils/git.js.map +1 -1
  546. package/hooks/hooks.json +17 -1
  547. package/hooks/session-start +42 -0
  548. package/package.json +6 -2
  549. package/scripts/check-prereqs.sh +12 -0
  550. package/scripts/e2e-graph-smoke.sh +167 -0
  551. package/scripts/graph-hook.mjs +151 -0
  552. package/scripts/migrate-specs.mjs +127 -0
  553. package/scripts/run-kpi-gate.mjs +245 -0
  554. package/scripts/sync-skills.mjs +99 -0
  555. package/skills/bober.code-review/SKILL.md +186 -0
  556. package/skills/bober.debug/SKILL.md +300 -0
  557. package/skills/bober.deploy/SKILL.md +262 -0
  558. package/skills/bober.diagnose/SKILL.md +254 -0
  559. package/skills/bober.graph/SKILL.md +85 -0
  560. package/skills/bober.impact/SKILL.md +101 -0
  561. package/skills/bober.incident/SKILL.md +245 -0
  562. package/skills/bober.onboard/SKILL.md +84 -0
  563. package/skills/bober.plan/SKILL.md +51 -0
  564. package/skills/bober.plan/references/spec-schema.md +31 -4
  565. package/skills/bober.postmortem/SKILL.md +231 -0
  566. package/skills/bober.run/SKILL.md +41 -7
  567. package/skills/bober.runbook/SKILL.md +335 -0
  568. package/skills/bober.sprint/SKILL.md +6 -259
  569. package/skills/bober.using-bober/SKILL.md +133 -0
  570. package/skills/bober.verify/SKILL.md +143 -0
@@ -0,0 +1,262 @@
1
+ ---
2
+ name: bober-deploy
3
+ description: Use when executing a remediation action — classifies by blast radius, gates risky actions via Tier 2 checkpoint, records a ChangeEntry with inverse BEFORE execution. The execution-level discipline that runbook steps delegate to.
4
+ ---
5
+
6
+ # Remediation Execution Discipline
7
+
8
+ ## Overview
9
+
10
+ The deploy skill governs **how** a remediation action is executed — the precondition check, the risky-action gate, the execution itself, the ChangeEntry write, and the postcondition verification. It is the execution substrate that `bober.runbook` steps delegate to and that the `bober-deployer` agent implements.
11
+
12
+ The spirit of this discipline: **every change must be auditable, reversible, and gated by proportional human oversight**. Risky changes that cannot be reversed without human judgment must always pass through a checkpoint. This is not bureaucracy — it is the minimum viable safety net for a system that executes shell commands against production infrastructure.
13
+
14
+ ## The Iron Law
15
+
16
+ ```
17
+ NO RISKY ACTION WITHOUT CHECKPOINT APPROVAL; NO ACTION WITHOUT RECORDED INVERSE
18
+ ```
19
+
20
+ Both clauses are unconditional. They do not have exceptions for urgency, familiarity, or pipeline mode.
21
+
22
+ ## When to Use
23
+
24
+ Use this skill whenever:
25
+ - Executing a remediation action proposed by the `bober-diagnoser` agent
26
+ - Executing a runbook step with `blastRadius: 'risky'`
27
+ - Running any shell command that modifies system state (cluster, database, secrets, filesystem)
28
+ - Recording a deployment, configuration change, or rollback to the incident changelog
29
+
30
+ Do NOT use this skill for:
31
+ - Read-only investigations (use `bober.diagnose`)
32
+ - Runbook authoring (see `bober.runbook` for the step format)
33
+ - Postmortem writing (see `bober.postmortem`)
34
+
35
+ ## Action Classification
36
+
37
+ ### SAFE Actions
38
+
39
+ A safe action is one where: (a) it is read-only, (b) it can be reversed by simply re-running it with different parameters (idempotent redo), or (c) it flips a feature flag back to its default state.
40
+
41
+ | Category | Examples |
42
+ |----------|---------|
43
+ | Read-only cluster queries | `kubectl get`, `kubectl describe`, `kubectl logs`, `kubectl top` |
44
+ | Read-only container queries | `docker ps`, `docker logs`, `docker inspect` |
45
+ | Read-only file operations | `cat`, `head`, `tail`, `grep`, `find`, `jq` |
46
+ | Read-only HTTP probes | `curl -I`, `curl -X GET` |
47
+ | Read-only git operations | `git log`, `git diff`, `git status`, `git show` |
48
+ | System state reads | `ps`, `df`, `lsof`, `netstat`, `uptime` |
49
+ | Observability queries | All `obs__*__*` tools |
50
+ | Feature flag to default | `ff --set my.flag=false` when `false` is the declared default |
51
+
52
+ ### RISKY Actions
53
+
54
+ A risky action is one that is stateful, destructive, or externally observable — i.e., a failure could affect users, require manual recovery, or leave the system in an indeterminate state.
55
+
56
+ | Category | Examples |
57
+ |----------|---------|
58
+ | Kubernetes mutations | `kubectl scale`, `kubectl rollout restart`, `kubectl delete`, `kubectl apply`, `kubectl patch`, `kubectl edit` |
59
+ | Infrastructure mutations | `terraform apply`, `terraform destroy`, `helm install/upgrade/uninstall/rollback` |
60
+ | Database migrations | `alembic upgrade`, `rake db:migrate`, `flyway migrate`, `knex migrate`, `liquibase update` |
61
+ | Secret rotation | `vault write/rotate/delete`, `aws secretsmanager rotate-secret/put-secret-value` |
62
+ | DNS changes | `aws route53 change-resource-record-sets`, `gcloud dns record-sets create` |
63
+ | Load balancer config | `aws elbv2 modify-listener`, `aws elbv2 modify-target-group-attributes` |
64
+ | Process control | `systemctl start/stop/restart`, `service ... restart`, `kill`, `pkill`, `killall` |
65
+ | Package installation | `npm install`, `pip install`, `apt install`, `brew install`, `yarn add` |
66
+ | Privilege escalation | Any command prefixed with `sudo` |
67
+ | State-mutating HTTP | `curl -X POST/PUT/PATCH/DELETE` |
68
+ | File mutations | `rm`, `rmdir`, `mv` (overwrite), `cp` (overwrite), shell redirects `>`, `>>` |
69
+ | Feature flag from default | Any flag change that moves away from the declared default state |
70
+
71
+ ### Classification Rule
72
+
73
+ **WHEN IN DOUBT: classify risky.**
74
+
75
+ The cost of a false-risky classification is one extra checkpoint approval. The cost of a false-safe classification is an unreviewed mutation to production infrastructure.
76
+
77
+ The classifier (`classifyCommand()` in `src/orchestrator/deploy/classify.ts`) evaluates the **entire command string** — not just the leading verb. A multi-command Bash invocation such as `echo 'safe' && kubectl scale deployment api --replicas=6` is **risky** because `kubectl scale` appears in the command string. Wrapping a risky verb inside a safe-looking command does not change the blast radius.
78
+
79
+ ## Execution Loop
80
+
81
+ Execute each proposed action in this exact sequence. Do not skip steps. Do not reorder steps.
82
+
83
+ ```
84
+ FOR each ProposedAction (id, description, classification, reasoning, command, inverse):
85
+
86
+ 1. VALIDATE: assert inverse.description is non-empty. If empty → ABORT (reason: missing_inverse).
87
+ No ChangeEntry is written for an aborted action.
88
+
89
+ 2. CLASSIFY: re-run classifyCommand(action.command). If the executor's classification is
90
+ 'risky' even though action.classification is 'safe', treat the action as risky.
91
+ (The executor is the authoritative classifier — the agent's field is a hint.)
92
+
93
+ 3. LOG: append ActionEntry to actions.jsonl for the audit trail.
94
+
95
+ 4. PRECONDITION CHECK: if action.preconditionCheck is defined, run it.
96
+ If precondition fails → ABORT (reason: precondition_failed). No ChangeEntry written.
97
+
98
+ 5. GATE (risky actions only):
99
+ a. Resolve mechanism via resolveRiskyActionMechanismName(config, isRisky=true).
100
+ b. IF allowAutopilotRiskyActions=false (default): invoke mech.request() with the
101
+ action description, classification reasoning, command, and inverse.
102
+ c. IF outcome.approved=false → ABORT (reason: checkpoint_rejected). Append timeline event.
103
+ Do NOT execute. Do NOT write ChangeEntry.
104
+ d. IF outcome.edit=true → re-classify the modified command before executing.
105
+ e. IF allowAutopilotRiskyActions=true → skip interactive approval, log STERN WARNING to
106
+ stderr, proceed to execution. ChangeEntry IS STILL WRITTEN (audit trail preserved).
107
+
108
+ 6. WRITE ChangeEntry status='pending' to changelog.jsonl BEFORE execution.
109
+ (This ensures the ChangeEntry exists on disk even if the process crashes mid-execution.)
110
+
111
+ 7. EXECUTE via executor seam (defaultExecutor in production; injected seam in tests).
112
+
113
+ 8. WRITE ChangeEntry status='executed' | 'failed' to changelog.jsonl AFTER execution.
114
+ (Both 'pending' and terminal entries are present — operational tooling sees the transition.)
115
+
116
+ 9. POSTCONDITION CHECK: if action.postconditionCheck is defined, run it.
117
+ If postcondition fails → invoke Abort Discipline (see below).
118
+
119
+ 10. RECORD result in DeployResult (executed or aborted array).
120
+ ```
121
+
122
+ ## Hard Gate — Risky Actions
123
+
124
+ Any action classified as risky MUST invoke the Tier 2 checkpoint mechanism before execution. This is UNCONDITIONAL:
125
+
126
+ - **`pipeline.mode='autopilot'` does NOT bypass risky-action approval.** Autopilot trades human-in-the-loop for speed on SAFE actions; the risky-action gate is the production safety floor and does not move.
127
+ - **`pipeline.checkpointMechanism='noop'` does NOT apply to risky actions.** When the configured mechanism is `noop` but the action is risky, the executor uses the default `disk` fallback. The gate cannot be configured away.
128
+ - **Multi-command Bash invocations do NOT slip through the gate.** An action that wraps `kubectl scale` inside `echo 'safe' && kubectl scale ...` is classified by COMMAND CONTENT, not by step authorship. The classifier checks for state-mutating verbs in the entire command string.
129
+
130
+ The gate receives the action description, the classification reasoning, the proposed command, and the declared inverse. The operator can approve, reject, or modify. A modification is re-classified before execution.
131
+
132
+ <EXTREMELY-IMPORTANT>
133
+ Risky actions invoke the Tier 2 checkpoint mechanism regardless of pipeline.mode. Autopilot mode does NOT bypass risky-action approval. If `pipeline.mode='autopilot'` and `pipeline.checkpointMechanism='noop'`, the executor STILL invokes a non-noop mechanism (default 'disk' fallback) for any action classified as risky. This is the production safety guarantee — bypassing it forfeits the guarantee.
134
+ </EXTREMELY-IMPORTANT>
135
+
136
+ ## allowAutopilotRiskyActions Escape Hatch
137
+
138
+ `pipeline.allowAutopilotRiskyActions=true` is available for **fully-automated environments** (CI pipelines, batch remediation jobs) where no human is available to approve a checkpoint. Default: `false`.
139
+
140
+ When `true`:
141
+ - Interactive approval is skipped.
142
+ - A STERN WARNING is logged to stderr: `[bober deploy] WARN allowAutopilotRiskyActions=true — auto-approved risky action <id>: <description>. Inverse recorded: "<inverse.description>".`
143
+ - The ChangeEntry **IS STILL WRITTEN** with the required `inverse` field. The audit trail is ALWAYS preserved.
144
+ - This is **"skip the interactive approval"** — NOT **"skip the audit trail"**.
145
+
146
+ <EXTREMELY-IMPORTANT>
147
+ `pipeline.allowAutopilotRiskyActions=true` is a footgun. Setting it to `true` in a non-automated environment (i.e., a human-supervised incident response) removes the human checkpoint that catches misclassifications, operator errors, and cascade failures. Default `false` is the SAFE default. Set `true` ONLY when no human is available AND the risk of delayed remediation exceeds the risk of unreviewed execution. Document the justification in the incident postmortem.
148
+ </EXTREMELY-IMPORTANT>
149
+
150
+ ## ChangeEntry Write-then-Update
151
+
152
+ Every executed action writes TWO ChangeEntries to `changelog.jsonl`:
153
+
154
+ 1. **Before execution** — `status: 'pending'`. Written BEFORE the executor seam is called.
155
+ Purpose: if the process crashes mid-execution, the entry exists on disk. Operational tooling
156
+ can detect 'pending' entries that never transitioned to 'executed' or 'failed' and flag them
157
+ for manual review.
158
+
159
+ 2. **After execution** — `status: 'executed'` or `status: 'failed'`. Written AFTER the executor
160
+ returns (or throws). Both entries share the same `id` field; readers correlate by `id`.
161
+
162
+ The `inverse` field is REQUIRED on BOTH entries. Sprint 21 rollback awareness reads `inverse` from
163
+ changelog entries to reconstruct the rollback plan. An entry without `inverse` is a schema violation
164
+ (Zod will throw at write time).
165
+
166
+ ```jsonl
167
+ {"id":"act-1","type":"risky-action","executedAt":"2026-05-25T12:00:00Z","description":"scale api to 6","inverse":{"description":"scale back to 3","command":"kubectl scale deployment api --replicas=3"},"status":"pending"}
168
+ {"id":"act-1","type":"risky-action","executedAt":"2026-05-25T12:00:02Z","description":"scale api to 6","inverse":{"description":"scale back to 3","command":"kubectl scale deployment api --replicas=3"},"status":"executed"}
169
+ ```
170
+
171
+ ## Abort Discipline
172
+
173
+ When a postcondition check fails after execution, follow this three-step cascade:
174
+
175
+ **Step 1 — Execute the declared inverse.**
176
+ The inverse is the rollback command declared in `action.inverse.command`. Run it via the executor seam. The inverse itself is classified by `classifyCommand()` — if it is risky, it requires checkpoint approval too.
177
+
178
+ **Step 2 — Verify the inverse's effect.**
179
+ After executing the inverse, run the original precondition (or the action's postcondition with inverted expected state) to confirm the rollback held. If the inverse also fails, proceed to Step 3.
180
+
181
+ **Step 3 — Escalate via checkpoint and STOP.**
182
+ Even if Step 1 failed, escalate via the Tier 2 checkpoint mechanism with the full context: the failed action, the postcondition result, the inverse attempt result, and the current observable state. STOP — do not proceed to subsequent actions. Their preconditions may assume this action's postcondition held, which it did not.
183
+
184
+ <EXTREMELY-IMPORTANT>
185
+ If a postcondition fails AND the declared inverse also fails (or no inverse was declared), the incident state is now indeterminate. The executor MUST escalate via checkpoint — do not silently proceed, do not retry the failed action. Only a human (or the configured escalation handler) can decide the next move from an indeterminate state.
186
+ </EXTREMELY-IMPORTANT>
187
+
188
+ ## Worked Example — Scaling API Deployment
189
+
190
+ **Context:** Diagnoser hypothesizes replica exhaustion. Next action: `kubectl scale deployment api --replicas=6`.
191
+
192
+ **ProposedAction:**
193
+ ```json
194
+ {
195
+ "id": "act-scale-1",
196
+ "description": "Scale api deployment to 6 replicas to relieve replica pressure",
197
+ "classification": "risky",
198
+ "reasoning": "kubectl scale is stateful and externally observable — changes live traffic routing",
199
+ "command": "kubectl scale deployment api --replicas=6 -n prod",
200
+ "inverse": {
201
+ "description": "Scale api deployment back to 3 replicas",
202
+ "command": "kubectl scale deployment api --replicas=3 -n prod"
203
+ },
204
+ "preconditionCheck": "kubectl get deployment api -n prod -o jsonpath='{.status.readyReplicas}'",
205
+ "postconditionCheck": "kubectl get deployment api -n prod -o jsonpath='{.status.readyReplicas}' | grep -q '^6$'"
206
+ }
207
+ ```
208
+
209
+ **Execution trace:**
210
+ 1. `inverse.description` is non-empty — validation passes.
211
+ 2. `classifyCommand("kubectl scale deployment api --replicas=6 -n prod")` → `'risky'` (kubectl scale verb).
212
+ 3. ActionEntry written to `actions.jsonl`.
213
+ 4. Precondition check: `kubectl get deployment api ...` → returns `3` (replicas currently 3) — passes.
214
+ 5. Gate: mechanism resolves to `disk` (floor applies; checkpointMechanism=noop but action is risky). Operator approves via `.bober/approvals/` file.
215
+ 6. ChangeEntry `{id: "act-scale-1", status: "pending", inverse: {...}}` written to `changelog.jsonl`.
216
+ 7. Executor: `kubectl scale deployment api --replicas=6 -n prod` → exit code 0.
217
+ 8. ChangeEntry `{id: "act-scale-1", status: "executed", inverse: {...}}` written to `changelog.jsonl`.
218
+ 9. Postcondition check: `kubectl get deployment api ... | grep -q '^6$'` → passes.
219
+ 10. DeployResult: `executed: [{actionId: "act-scale-1", status: "executed", durationMs: 1240}]`.
220
+
221
+ ## Red Flags — STOP
222
+
223
+ - About to execute without an `inverse.description` on the ProposedAction — stop, you have no exit strategy.
224
+ - About to classify `echo 'safe' && kubectl scale ...` as safe — the classifier reads the entire string. `kubectl scale` makes it risky.
225
+ - About to skip the checkpoint because the pipeline is in autopilot mode — Iron Law: risky actions always gate.
226
+ - About to skip the ChangeEntry write because "the action is small" — the audit trail is the safety net for the next operator. Every change is recorded.
227
+ - About to skip the precondition check because "the incident confirms the bad state" — the precondition is also a guard against executing the wrong remediation on the wrong environment.
228
+ - About to continue to the next action after a postcondition failure — this is the most common failure mode. Stop. Execute the inverse. Escalate. Let the operator decide.
229
+ - About to set `allowAutopilotRiskyActions=true` in a human-supervised context — this flag is for unattended automation. In a live incident with a human in the loop, leave it `false`.
230
+ - About to skip the stern warning when `allowAutopilotRiskyActions=true` auto-approves — the warning is the audit signal that human approval was bypassed.
231
+
232
+ ## Common Rationalizations
233
+
234
+ | Rationalization | Reality |
235
+ |-----------------|---------|
236
+ | "The pipeline is in autopilot, so risky actions auto-approve" | Iron Law: risky actions always gate, regardless of pipeline.mode. Autopilot only skips approval for SAFE actions. |
237
+ | "kubectl scale is a minor operation — it's basically safe" | kubectl scale is stateful and externally observable. It is in the RISKY list explicitly. Classify it risky. |
238
+ | "I'll add the inverse after I see what the execution does" | The inverse must be declared BEFORE execution. Discovering it post-hoc means you cannot roll back if the execution crashes. |
239
+ | "allowAutopilotRiskyActions=true means skip all safety" | It means skip interactive approval. ChangeEntry IS still written. Audit trail IS still preserved. Warning IS still logged. |
240
+ | "The diagnoser recommended this — it's pre-approved" | Recommendation is not approval. Every risky action needs a checkpoint approval regardless of its source. |
241
+ | "The precondition passed last time — I won't check again" | System state changes. The precondition check is run immediately before execution, every time. |
242
+ | "Different words so the rule doesn't apply" | Spirit over letter. When in doubt, classify risky, require approval, record inverse. |
243
+ | "I can bundle two mutations into one command to save time" | Bundled mutations have bundled inverses. A failure mid-bundle leaves the system in a half-mutated state. Split them. |
244
+
245
+ ## Quick Reference
246
+
247
+ | Question | Answer |
248
+ |----------|--------|
249
+ | Is `kubectl get pods` safe? | Yes — read-only. |
250
+ | Is `kubectl scale` safe? | No — risky, requires checkpoint. |
251
+ | Is `echo 'ok' && kubectl delete pod x` safe? | No — `kubectl delete` is risky; entire string is risky. |
252
+ | Can autopilot mode bypass risky-action checkpoint? | No — Iron Law applies unconditionally. |
253
+ | What does `allowAutopilotRiskyActions=true` skip? | Interactive approval only. ChangeEntry is still written. Warning is still logged. |
254
+ | What happens if inverse is missing? | executeAction throws BEFORE execution. No ChangeEntry is written. |
255
+ | What happens if postcondition fails? | Execute inverse → escalate via checkpoint → STOP. |
256
+ | What happens if the executor crashes mid-execution? | ChangeEntry with status='pending' exists on disk. Final status may be absent or 'failed'. Operational tooling detects the 'pending' state. |
257
+
258
+ ## Related Skills
259
+
260
+ - **`bober.runbook`** (`skills/bober.runbook/SKILL.md`) — multi-step runbook execution. Runbook steps delegate to this skill's execution discipline for each step.
261
+ - **`bober.diagnose`** (`skills/bober.diagnose/SKILL.md`) — the investigation skill that produces `nextActions`. This skill executes what the diagnoser recommends.
262
+ - **`bober-deployer` agent** (`agents/bober-deployer.md`) — the agent that uses this skill. The agent prompt implements the discipline described here.
@@ -0,0 +1,254 @@
1
+ ---
2
+ name: bober-diagnose
3
+ description: Use when investigating a production incident or system-level failure — gather evidence at component boundaries, hypothesize-and-disprove, verify resolution against pre-defined criteria
4
+ ---
5
+
6
+ > Adapted from [obra/superpowers](https://github.com/obra/superpowers) — MIT License.
7
+ > Structural source: skills/systematic-debugging/SKILL.md (four-phase discipline).
8
+ > Adaptations: system-level (incident) context; boundary enumeration as Phase 2; pre-defined resolution-verification criteria as Phase 4.
9
+
10
+ # Systematic Incident Diagnosis
11
+
12
+ ## Overview
13
+
14
+ Random restarts mask root causes. Symptom-fixes destroy the ability to verify resolution. Reactive remediation without confirmed root cause prolongs incidents and introduces new failures.
15
+
16
+ **Core principle:** ALWAYS verify root cause at two independent boundaries before remediation.
17
+
18
+ **Violating the letter of this process is violating the spirit of incident response.**
19
+
20
+ ## The Iron Law
21
+
22
+ ```
23
+ NO REMEDIATION WITHOUT VERIFIED ROOT CAUSE AT TWO INDEPENDENT BOUNDARIES
24
+ ```
25
+
26
+ If your evidence comes from a single component, you have a candidate hypothesis — not a verified root cause. Continue gathering at independent boundaries before proposing any remediation.
27
+
28
+ ## When to Use
29
+
30
+ Use for ANY production incident:
31
+ - Error rate or latency regression
32
+ - Partial or total service outage
33
+ - Capacity event or unexpected resource exhaustion
34
+ - Data inconsistency or corruption report
35
+ - Security alert or anomalous traffic pattern
36
+ - Cascading failures across components
37
+
38
+ **Use this ESPECIALLY when:**
39
+ - Under time pressure (a page just fired — emergencies make guessing tempting)
40
+ - A restart "seems like it might help"
41
+ - The dashboard looks bad and everyone is watching
42
+ - You have one promising hypothesis and want to skip straight to fixing
43
+ - You've already tried one change and it didn't work
44
+
45
+ **Don't skip when:**
46
+ - Incident seems obvious ("it was the 14:00 deploy") — correlation must become causation via independent evidence
47
+ - Symptom looks simple (one endpoint, one user) — scope must be confirmed, not assumed
48
+ - Executive is watching — systematic diagnosis is FASTER than repeated rollbacks that don't fix the root cause
49
+
50
+ ## The Four Phases
51
+
52
+ You MUST complete each phase before proceeding to the next. The gates between phases are not advisory — they are the process.
53
+
54
+ ### Phase 1: Reproduce and Confirm
55
+
56
+ **BEFORE gathering evidence at component boundaries:**
57
+
58
+ 1. **Confirm Symptom Is Current (not stale)**
59
+ - Do NOT rely on the initial user report timestamp — that is when it was NOTICED, not necessarily when it is happening NOW.
60
+ - Query an observability MCP at this moment: `obs__datadog__query_metric`, `obs__loki__query_logs`, or equivalent configured in `bober.config.json` → `observability.providers`.
61
+ - If the symptom is no longer observable, record that — the incident may be self-resolved or intermittent. Do NOT proceed to Phase 2 on a stale symptom without confirming current status.
62
+
63
+ 2. **Confirm Scope**
64
+ - Is it one user, one customer, one region, one endpoint, or all of them?
65
+ - Scope determines which component boundaries matter in Phase 2. A tenant-isolated failure points to tenant-specific data paths; a global failure points to shared infrastructure.
66
+ - Record scope explicitly — "assumed global" is not confirmation.
67
+
68
+ 3. **Confirm Timing**
69
+ - When exactly did it start? (First alert timestamp ≠ first occurrence)
70
+ - Has severity changed since it started — increasing, plateau, or decreasing?
71
+ - Was there a deploy, config change, or infrastructure event within the relevant window? (Record as a potential correlation — not yet a cause.)
72
+
73
+ 4. **Record Initial State to `observations.jsonl`**
74
+ - Append each confirmed observation to `.bober/incidents/<id>/observations.jsonl` with the shape: `{timestamp, phase, observation, source, verified}`.
75
+ - Do NOT record assumptions as observations. `"verified": true` means you queried a source and got the data; `"verified": false` means a user-reported claim not yet confirmed.
76
+
77
+ **Worked example:**
78
+ ```jsonl
79
+ {"timestamp": "2026-05-24T14:05:00Z", "phase": 1, "observation": "Symptom: 500 errors on /api/checkout from 14:00 UTC; ~12% error rate; all regions", "source": "user-report", "verified": false}
80
+ {"timestamp": "2026-05-24T14:06:00Z", "phase": 1, "observation": "Confirmed current via fresh metric query — error rate still 11.8% at 14:06", "source": "obs__datadog__query_metric", "verified": true}
81
+ {"timestamp": "2026-05-24T14:07:00Z", "phase": 1, "observation": "Scope: all regions, all customers — global incident, not tenant-isolated", "source": "obs__datadog__query_metric", "verified": true}
82
+ ```
83
+
84
+ <EXTREMELY-IMPORTANT>
85
+ BEFORE proceeding to Phase 2, you MUST have completed Phase 1 in writing — symptom confirmed current, scope confirmed, timing confirmed, observations.jsonl appended. If any of these is incomplete, return to Phase 1. Skipping Phase 1 makes Phase 2 evidence-gathering ungrounded.
86
+ </EXTREMELY-IMPORTANT>
87
+
88
+ ### Phase 2: Gather Evidence at Boundaries
89
+
90
+ **BEFORE forming hypotheses, gather at every relevant boundary:**
91
+
92
+ 1. **Enumerate Component Boundaries**
93
+ - Draw the request/data path end to end: `client → CDN → load balancer → API gateway → service → cache → database → storage`.
94
+ - Each arrow between components is a boundary — a place where data crosses a trust or technology boundary and where failure can manifest differently on each side.
95
+ - The scope confirmed in Phase 1 determines which boundaries are relevant. A global failure requires querying all boundaries. A single-region failure may skip globally-shared boundaries.
96
+
97
+ 2. **Query at Each Boundary via Observability MCPs**
98
+ - Use the `obs__<provider>__<tool>` namespace configured in `bober.config.json` → `observability.providers`.
99
+ - Provider kinds: `logs | metrics | traces | errors | custom`.
100
+ - Query examples per boundary layer:
101
+ - CDN/network layer: `obs__cloudflare__query_analytics` — cache-hit rate, 5xx responses at edge
102
+ - App-layer logs: `obs__loki__query_logs` — structured error logs, trace IDs
103
+ - Infra metrics: `obs__datadog__query_metric` — CPU, memory, connection pool saturation
104
+ - Distributed traces: `obs__tempo__query_traces` — end-to-end latency, where spans break
105
+ - Error tracking: `obs__sentry__query_events` — exception types, frequency, first seen
106
+ - Record each query result to `observations.jsonl` with `phase: 2` and the `obs__<provider>__<tool>` value as `source`.
107
+
108
+ 3. **Correlate Timestamps with `changelog.jsonl`**
109
+ - Read `.bober/incidents/<id>/changelog.jsonl` for recent deploys, config changes, and infrastructure events.
110
+ - Cross-reference incident-start timestamp (confirmed in Phase 1) with deploy and change timestamps.
111
+ - **CRITICAL:** Temporal correlation is not causation. A deploy 5 minutes before symptom onset is a hypothesis input, not a conclusion. Record it as a candidate, not a confirmed cause.
112
+
113
+ 4. **Multi-Boundary Iron-Law Check**
114
+ - Before any hypothesis becomes remediation-eligible, you MUST have evidence from at least TWO independent boundaries.
115
+ - "Two log entries from the same service" is NOT two independent boundaries — that is one boundary queried twice.
116
+ - Two independent boundaries means two different components in the system path, each providing telemetry that either supports or contradicts the same hypothesis.
117
+
118
+ <EXTREMELY-IMPORTANT>
119
+ BEFORE proceeding to Phase 3, you MUST have queried at least two independent boundaries and recorded their findings as observations. If only one boundary has data, return to Phase 2 — Phase 3 hypothesis formation on single-boundary evidence violates the Iron Law.
120
+ </EXTREMELY-IMPORTANT>
121
+
122
+ ### Phase 3: Hypothesize and Disprove
123
+
124
+ **Scientific method under pressure:**
125
+
126
+ 1. **Formulate Falsifiable Hypotheses**
127
+ - Each hypothesis is a single falsifiable claim: "The database connection pool is exhausted, causing checkout service to queue and timeout, explaining the 500 errors on /api/checkout."
128
+ - Rank hypotheses by count of supporting evidence entries across independent boundaries — more independent boundary support = higher initial rank.
129
+ - Drop hypotheses with zero evidence from Phase 2. Ungrounded hypotheses are guesses, not hypotheses.
130
+
131
+ 2. **Pattern-Match Against the Anti-Pattern Catalog**
132
+ - Before listing a hypothesis as a candidate, check `.bober/anti-patterns/README.md` for pattern matches.
133
+ - Two anti-patterns are especially common in incidents: **Symptom-Fix Instead of Root-Cause** (see `root-cause-tracing.md`) and **Single-Layer Validation** (see `defense-in-depth.md`).
134
+ - If your hypothesis matches one, cite the anti-pattern by name in your hypothesis record.
135
+
136
+ 3. **ACTIVELY DISPROVE the Top Hypothesis** *(REQUIRED — not advisory)*
137
+ - Try to find evidence that DISPROVES your top hypothesis. A hypothesis you cannot disprove is not strongly tested.
138
+ - For each top hypothesis, ask: what would NOT be true if this hypothesis were correct? Go look for that evidence.
139
+ - Example: if your hypothesis is "the 14:00 deploy caused the error spike," actively look for contradicting evidence — was the error rate elevated BEFORE 14:00? Is the same endpoint failing in a region that did NOT receive the 14:00 deploy? Are the error signatures different from what a rollout regression would produce?
140
+ - Record the disproof attempt in `hypotheses.md` under the hypothesis. If you found contradicting evidence, demote the hypothesis. If you looked and found no contradicting evidence, the hypothesis survived the attempt — that is meaningful.
141
+ - You MUST document what you checked and what you found (or did not find). "I tried to disprove it" without a recorded attempt is not a disproof attempt.
142
+
143
+ 4. **Promote or Demote Confidence**
144
+ - Promote a hypothesis to `confidence: 'high'` ONLY if: (a) evidence from ≥2 independent boundaries AND (b) survived an active disproof attempt with no contradicting evidence found.
145
+ - Promote to `confidence: 'medium'` if: multi-boundary evidence but disproof attempt inconclusive (no contradicting evidence found, but also no strong confirming evidence).
146
+ - Assign `confidence: 'low'` if: single-boundary evidence OR disproof attempt found partially contradicting evidence.
147
+ - Only `confidence: 'medium'` or `confidence: 'high'` hypotheses are remediation-eligible. `confidence: 'low'` → return to Phase 2 for more evidence.
148
+ - `blastRadius: 'risky'` remediation actions require `requiresApproval: true` — set this in the `nextActions` entry regardless of confidence level.
149
+
150
+ <EXTREMELY-IMPORTANT>
151
+ BEFORE proceeding to Phase 4, you MUST have actively attempted to disprove your top hypothesis and recorded the attempt. A hypothesis that has NOT survived a disproof attempt is NOT remediation-eligible. If you have not yet tried to disprove it, return to Phase 3.
152
+ </EXTREMELY-IMPORTANT>
153
+
154
+ ### Phase 4: Verify Resolution Against Pre-Defined Criteria
155
+
156
+ **Resolution criteria MUST be defined BEFORE remediation — retrofitted criteria are meaningless.**
157
+
158
+ 1. **Pre-Define Resolution-Verification Criteria**
159
+ - Before ANY state-mutating action, write the resolution criteria. All five fields are REQUIRED: metric, threshold, window, comparison baseline, verification source. Without all five, the criterion is not actionable.
160
+
161
+ **Worked example:**
162
+ ```
163
+ Resolution criteria for inc-20260524-500-errors-on:
164
+ - Metric: api.checkout.error_rate
165
+ - Threshold: < 0.1%
166
+ - Window: 10 minutes sustained
167
+ - Comparison baseline: 7-day rolling average
168
+ - Verification source: obs__datadog__query_metric
169
+ ```
170
+
171
+ - Record these criteria in `actions.jsonl` BEFORE the remediation action that follows.
172
+ - Criteria written after the fact are retrofitted to the outcome and provide no verification value.
173
+
174
+ 2. **Apply Remediation via bober-deployer**
175
+ - NEVER run state-mutating commands from the diagnoser directly. The diagnoser emits a `nextActions` entry; the orchestrator routes it to `agents/bober-deployer.md` (Sprint 20 — `skills/bober.deploy/SKILL.md` once that sprint lands).
176
+ - Actions classified `blastRadius: 'risky'` MUST include `requiresApproval: true` and will trigger a Tier 2 checkpoint gate before execution.
177
+ - The deployer records each action in `changelog.jsonl` with a required `inverse` field — the rollback instruction for every state change.
178
+ - See `skills/bober.deploy/SKILL.md` (Sprint 20) for the full remediation execution discipline.
179
+
180
+ 3. **Monitor Against Criteria via Observability MCPs**
181
+ - After remediation completes, begin monitoring the named metric using the named verification source.
182
+ - Query at a cadence appropriate to the window (e.g., every 2 minutes for a 10-minute window).
183
+ - Record each observation to `observations.jsonl` with `phase: 4`.
184
+ - "The dashboard looks better" is NOT resolution. The criterion requires the named metric to meet the named threshold for the FULL named window.
185
+
186
+ 4. **Mark Resolved Only When Criteria Met for the Named Window**
187
+ - When the metric meets the threshold for the complete window duration, append resolution to `actions.jsonl` and update `incident.json` with `status: 'resolved'` and `resolvedAt`.
188
+ - If criteria are not met within a reasonable monitoring period, or if the symptom returns, return to Phase 1 — the remediation was symptomatic, not root cause. The incident is not closed.
189
+ - Explicitly forbidden: marking an incident resolved because the dashboard looks better, because a restart seemed to help, or because the page quieted down. These are not resolution criteria — they are noise.
190
+
191
+ ## Red Flags - STOP and Follow Process
192
+
193
+ If you catch yourself thinking:
194
+ - "The dashboard looks better, mark it resolved"
195
+ - "Just restart the service and see if it helps"
196
+ - "It's obviously the database, skip the cache layer"
197
+ - "The deploy at 14:00 must be it, ship the rollback"
198
+ - "One log line is enough — I can see the error right there"
199
+ - "No time for hypothesis-disproof, the page is loud"
200
+ - "The metric is back to baseline, declare resolved"
201
+ - "Stale alert — the customer probably just refreshed"
202
+ - "I've seen this before, I know what it is"
203
+ - Proposing remediation before confirming evidence at two independent boundaries
204
+ - **"Just one restart to stabilize, then we'll investigate"**
205
+
206
+ **ALL of these mean: STOP. Return to Phase 1.**
207
+
208
+ ## Common Rationalizations
209
+
210
+ | Excuse | Reality |
211
+ |--------|---------|
212
+ | "The dashboard looks green, we're resolved" | Resolution criteria require a NAMED metric meeting a NAMED threshold for a NAMED window. Eyeballing a dashboard is not verification. |
213
+ | "The deploy at 14:00 caused this — roll it back" | Correlation is not causation. Verify the deploy is the cause via independent telemetry before remediating. Rolling back the wrong thing extends the incident. |
214
+ | "Logs are unambiguous, one source is enough" | Iron Law: two independent boundaries. One source = continue gathering. Do not remediate on single-boundary evidence. |
215
+ | "No time to disprove the hypothesis, the page is loud" | Confirmation bias under pressure is the dominant incident-response failure mode. The disproof step exists EXACTLY for these moments. Skip it and you risk a second incident. |
216
+ | "Stale alert — the customer probably just refreshed" | Phase 1 requires CONFIRMING the symptom is current. "Probably refreshed" is not confirmation — query current state before proceeding. |
217
+ | "We'll set the resolution criteria after the fix lands" | Criteria set after the fix are retrofitted to the outcome. They MUST be pre-defined to be meaningful. Post-hoc criteria always pass. |
218
+ | "I've seen this before, skip to Phase 3" | Pattern memory is a hypothesis, not evidence. Phase 1 (confirm) and Phase 2 (boundaries) still produce the multi-source evidence required by the Iron Law. |
219
+ | "The MCP is slow, I'll just go from logs" | If a primary observability source is degraded, that is itself a diagnostic signal. Do NOT invent values for missing telemetry — low-confidence gaps are hypotheses, not evidence. |
220
+
221
+ ## Quick Reference
222
+
223
+ | Phase | Key Activities | Success Criteria |
224
+ |-------|---------------|------------------|
225
+ | **1. Reproduce + Confirm** | Confirm symptom current, confirm scope, confirm timing, write `observations.jsonl` | Symptom is real, scoped, and timed |
226
+ | **2. Gather at Boundaries** | Enumerate components; query `obs__<provider>__<tool>` at each boundary; correlate `changelog.jsonl` | Evidence at ≥2 independent boundaries |
227
+ | **3. Hypothesize + Disprove** | Rank hypotheses by evidence; pattern-match anti-catalog; actively seek contradicting evidence | Top hypothesis survived a recorded disproof attempt |
228
+ | **4. Verify Resolution** | Pre-define metric+threshold+window+baseline+source; remediate via bober-deployer; monitor; mark resolved | Criteria met for the full named window |
229
+
230
+ ## When Process Reveals "No Root Cause"
231
+
232
+ If systematic investigation across all relevant boundaries turns up no root cause:
233
+
234
+ 1. You have still completed the process — this is a valid outcome, not a process failure.
235
+ 2. Document every boundary queried and every hypothesis disproved in `hypotheses.md`.
236
+ 3. Implement appropriate defensive handling (circuit breaker, retry with backoff, graceful degradation).
237
+ 4. Add monitoring for early detection of recurrence.
238
+
239
+ **But:** 95% of "no root cause" cases are incomplete boundary coverage. Check that Phase 2 covered every component in the request path before declaring no root cause.
240
+
241
+ ## Related Skills
242
+
243
+ - **`bober.debug`** (`skills/bober.debug/SKILL.md`) — Use when the incident root cause turns out to be code-level (a test reproduces it, single component, deterministic). `bober.diagnose` handles "is the system broken?"; `bober.debug` handles "is the code wrong?". They are siblings, not parent-child. Used by `agents/bober-diagnoser.md`.
244
+ - **`bober.runbook`** (`skills/bober.runbook/SKILL.md`, Sprint 18) — When the diagnoser's next action is "follow runbook X", use `bober.runbook` for execution discipline (precondition → execute → postcondition for every step).
245
+ - **`bober.deploy`** (`skills/bober.deploy/SKILL.md`, Sprint 20) — Remediation execution via `agents/bober-deployer.md`. Required for any `blastRadius: 'risky'` action. Never run state-mutating commands from the diagnoser — always route through bober-deployer.
246
+ - **`.bober/anti-patterns/`** — Pattern catalog. Phase 3 hypothesis formation must check **Symptom-Fix Instead of Root-Cause** (`root-cause-tracing.md`) and **Single-Layer Validation** (`defense-in-depth.md`) for matches.
247
+
248
+ ## Real-World Impact
249
+
250
+ From incident response patterns:
251
+ - Systematic diagnosis with disproof discipline: median time-to-resolution 20–40 minutes
252
+ - Restart-and-see approach: 2–4 hours of repeated remediation attempts, each buying 15 minutes of relief
253
+ - Retrofitted resolution criteria: re-opening rate ~60% within 24 hours
254
+ - Pre-defined resolution criteria with named window: re-opening rate ~8%
@@ -0,0 +1,85 @@
1
+ ---
2
+ name: bober.graph
3
+ description: Manage the code graph index — init, sync, and check status. Requires graph.enabled=true in bober.config.json and tokensave installed.
4
+ handoffs:
5
+ - label: "Generate Onboarding Docs"
6
+ command: /bober-onboard
7
+ prompt: "Generate onboarding docs from the code graph"
8
+ - label: "Analyse Impact"
9
+ command: /bober-impact
10
+ prompt: "Analyse the impact radius of a symbol"
11
+ ---
12
+
13
+ # bober.graph — Code Graph Management Skill
14
+
15
+ You are running the **bober.graph** skill. Your job is to initialise, sync, or check the status of the code graph for this project.
16
+
17
+ The code graph is powered by `tokensave`. Once indexed, it enables semantic search, impact analysis, and onboarding document generation.
18
+
19
+ ## Prerequisites
20
+
21
+ - `tokensave` >= 6.0.0-beta.1 must be installed
22
+ - `graph.enabled: true` must be set in `bober.config.json`
23
+
24
+ Install tokensave:
25
+ - macOS: `brew install aovestdipaperino/tap/tokensave`
26
+ - Linux: `cargo install tokensave`
27
+ - Windows: `scoop bucket add tokensave https://github.com/aovestdipaperino/scoop-bucket && scoop install tokensave`
28
+
29
+ ## Available Subcommands
30
+
31
+ ### Check prerequisites
32
+ ```bash
33
+ agent-bober graph check-prereq
34
+ ```
35
+ Reports whether tokensave is installed and compatible. Outputs JSON.
36
+
37
+ ### Initialise the graph
38
+ ```bash
39
+ agent-bober graph init
40
+ ```
41
+ Runs `tokensave init --tier <languageTier>` and writes an initial manifest to `.bober/graph/manifest.json`. Run this once in a fresh checkout.
42
+
43
+ ### Sync the graph
44
+ ```bash
45
+ agent-bober graph sync
46
+ ```
47
+ Re-indexes changed files. Use `--force` for a full re-index regardless of changes.
48
+
49
+ ### Check graph status
50
+ ```bash
51
+ agent-bober graph status
52
+ ```
53
+ Prints whether the graph is ready, how many files are indexed, the tokensave version, and the last synced HEAD SHA.
54
+
55
+ Use `--json` for machine-readable output:
56
+ ```bash
57
+ agent-bober graph status --json
58
+ ```
59
+
60
+ ## Step-by-Step: Fresh Setup
61
+
62
+ 1. Verify prerequisites: `agent-bober graph check-prereq`
63
+ 2. Enable the graph in `bober.config.json`:
64
+ ```json
65
+ { "graph": { "enabled": true } }
66
+ ```
67
+ 3. Initialise: `agent-bober graph init`
68
+ 4. Check status: `agent-bober graph status`
69
+ 5. After committing new code, sync: `agent-bober graph sync`
70
+
71
+ ## Alternatively: Use MCP Tools Directly
72
+
73
+ If Claude Code is connected to the agent-bober MCP server with `exposeOnExternalMcp: true`, you can use the MCP tools:
74
+ - `semantic_search_nodes` — semantic search over the graph
75
+ - `query_graph` — trace callers, callees, imports, or test coverage
76
+ - `get_impact_radius` — find what a symbol affects
77
+ - `get_architecture_overview` — high-level structural summary
78
+ - `detect_changes` — risk-scored analysis of recent changes
79
+ - `get_review_context` — token-efficient source snippets for review
80
+
81
+ ## Error Handling
82
+
83
+ - If graph.enabled=false: the commands exit 1 with a message explaining how to enable it
84
+ - If tokensave is missing: `graph init` exits 2 with a platform-aware install hint
85
+ - If the graph is stale (new commits since last sync): `graph sync` to bring it up to date