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,231 @@
1
+ ---
2
+ name: bober-postmortem
3
+ description: Use after an incident is resolved to synthesize an evidence-cited postmortem from .bober/incidents/<id>/ artifacts — chronological timeline, 5-Whys from diagnoses, contributing factors from runbook execution, action items from gaps in process. Pure offline synthesis; no live observability access.
4
+ ---
5
+
6
+ # Postmortem Synthesis Discipline
7
+
8
+ ## Overview
9
+
10
+ A postmortem is a document of record. It is read by people who weren't in the room — sometimes months later, sometimes by auditors. Postmortems that contain opinion without evidence become political artifacts; postmortems that cite every claim become institutional memory.
11
+
12
+ **Core principle:** Every postmortem sentence traces to a specific artifact in `.bober/incidents/<id>/`. Citations are mandatory. Speculation is forbidden.
13
+
14
+ **Violating the letter of this discipline is violating the spirit of incident learning.**
15
+
16
+ ## The Iron Law
17
+
18
+ ```
19
+ NO POSTMORTEM SECTION WITHOUT EVIDENCE FROM INCIDENT ARTIFACTS
20
+ ```
21
+
22
+ Every non-template claim cites an artifact path (and line number where applicable). A section with no citations is a section that should not exist — or a section whose contents were fabricated. Either way: failure.
23
+
24
+ ## When to Use
25
+
26
+ Use this skill when:
27
+ - An incident transitions to `status: 'resolved'` (Sprint 22 gate)
28
+ - A human runs `bober postmortem generate <incidentId>` to (re)synthesize a postmortem
29
+ - An auditor needs to reconstruct the incident from artifact records
30
+
31
+ Do NOT use this skill for:
32
+ - Active incident response (use `bober.diagnose`)
33
+ - Remediation execution (use `bober.deploy`)
34
+ - Runbook authoring (use `bober.runbook`)
35
+
36
+ ## Synthesis Order
37
+
38
+ Read the following artifacts in EXACTLY this order. Earlier files seed later sections.
39
+
40
+ 1. **`incident.json`** — metadata: incidentId, symptom, createdAt, resolvedAt, status, resolutionCriteria, resolutionEvidence. The header block of the postmortem comes entirely from this file.
41
+ 2. **`timeline.jsonl`** — chronological master log. Walk linearly to construct the Timeline table. Each row carries `(timeline.jsonl#L<n>)` as its citation.
42
+ 3. **`observations.jsonl`** — verified facts. `phase: 1-2 + verified: true` rows seed the Impact section. `phase: 4` rows confirm Resolution.
43
+ 4. **`diagnoses/*.json`** — DiagnosisResult records (Sprint 15 schema). Sort by mtime descending; the most-recent diagnosis's highest-confidence hypothesis is the root-cause candidate for Why-2.
44
+ 5. **`changelog.jsonl`** — ChangeEntry records (with required inverse field, Sprint 21). Each entry within 30 minutes before incident `createdAt` is a Why-4/Why-5 candidate.
45
+ 6. **`runbook-execution.jsonl`** — RunbookExecutionEntry records. Failed steps populate Contributing Factors; successful steps populate What Went Well.
46
+ 7. **`actions.jsonl`** — ActionEntry records (safe + risky). Risky actions without preceding precondition pass become What Went Wrong entries.
47
+ 8. **`resolution-evidence/*.json`** — Sprint 22 metric verification samples. `allSamplesPassed: true` is the strongest possible Resolution citation.
48
+ 9. **`hypotheses.md`** — narrative. Lines starting "Disproved:" go to What Went Well; lines starting "Open:" go to Action Items.
49
+
50
+ Missing or empty artifacts are NOT failures of the synthesizer — they are facts about the incident. Cite the absence: `(diagnoses/ is empty)`.
51
+
52
+ ## 5-Whys Construction Heuristic
53
+
54
+ The 5-Whys section is the hardest part. The diagnoser's top hypothesis is usually Why-2 or Why-3, not Why-1. The synthesizer works backwards (symptom → root) AND forwards (changelog → symptom) to fill all five levels.
55
+
56
+ **Heuristic (deterministic; pseudocode for implementers):**
57
+
58
+ ```
59
+ why1 = "Why did <incident.symptom> happen?"
60
+ citation = "(incident.json)"
61
+
62
+ let diagnosis = mostRecentDiagnosis(diagnoses/)
63
+ let topHypothesis = diagnosis.hypotheses.sortBy(confidence: desc, supportingEvidence.length: desc)[0]
64
+ why2 = "Because " + topHypothesis.statement
65
+ citation = "(diagnoses/<diagnosisId>.json#" + topHypothesis.id + ")"
66
+
67
+ let strongestEvidence = topHypothesis.supportingEvidence.sortBy(specificity)[0]
68
+ why3 = "Because " + strongestEvidence.snippet
69
+ citation = "(" + strongestEvidence.path + ")"
70
+
71
+ let preIncidentChanges = changelog.jsonl.filter(c =>
72
+ c.executedAt < incident.createdAt &&
73
+ Date.parse(incident.createdAt) - Date.parse(c.executedAt) < 30 * 60 * 1000
74
+ ).sortBy(executedAt: desc)
75
+ why4 = preIncidentChanges[0]
76
+ ? "Because " + preIncidentChanges[0].description + " shipped " + minutesBetween + "m before symptom onset"
77
+ : null
78
+ citation = "(changelog.jsonl#L<n>)"
79
+
80
+ why5 = preIncidentChanges[1]
81
+ ? similar to why4 with the next-older change
82
+ : null
83
+
84
+ if (renderedWhys.length < 3) {
85
+ emitShallowWarning("5-Whys synthesis was shallow (only " + n + " level(s) derivable from artifacts). " +
86
+ "Missing evidence in <named-file>. Human review required to deepen this chain.")
87
+ }
88
+ ```
89
+
90
+ **Cite every level.** A 5-Whys section with 5 levels and 5 citations is the bar. 3 levels with citations + a shallow-warning is acceptable. Fewer than 3 with no warning is a synthesis failure.
91
+
92
+ ## Postmortem Template
93
+
94
+ Generated postmortems MUST match this structure. Section headings are template; everything else MUST cite.
95
+
96
+ ```markdown
97
+ # Postmortem: <incident.symptom truncated 80 chars>
98
+
99
+ **Incident ID:** <incidentId> (incident.json)
100
+ **Status:** Resolved
101
+ **Severity:** <S1|S2|S3|S4> *(derive from observation count + impact magnitude; default S3 if undeterminable)*
102
+ **Date:** <incident.createdAt> → <incident.resolvedAt> (incident.json)
103
+ **Duration:** <hh:mm computed from createdAt → resolvedAt>
104
+
105
+ ## TL;DR
106
+
107
+ <2-3 sentence summary: symptom from `incident.json.symptom` + root cause from top hypothesis + resolving action from changelog.jsonl last ChangeEntry.> Each clause carries an inline citation.
108
+
109
+ ## Impact
110
+
111
+ - <verified observation 1> (observations.jsonl#L<n>)
112
+ - <verified observation 2> (observations.jsonl#L<n>)
113
+ - Resolution sample: observed <resolution-evidence[*].observedValue> against threshold <criteria.threshold> (resolution-evidence/<file>.json)
114
+
115
+ ## Timeline
116
+
117
+ | Time (UTC) | Event | Source |
118
+ |------------|-------|--------|
119
+ | <hh:mm> | <event.summary truncated 80> | <event.source> (timeline.jsonl#L<n>) |
120
+ | <hh:mm> | … | … |
121
+
122
+ ## Root Cause (5-Whys)
123
+
124
+ 1. Why did <symptom> happen? (incident.json)
125
+ 2. Because <topHypothesis.statement>. (diagnoses/<diagnosisId>.json#<hyp-id>)
126
+ 3. Because <strongestEvidence.snippet>. (<evidence.path>)
127
+ 4. Because <preIncidentChange.description> shipped <m>m prior. (changelog.jsonl#L<n>)
128
+ 5. Because <olderPreIncidentChange.description>. (changelog.jsonl#L<n>)
129
+
130
+ *(If fewer than 3 Whys derivable: emit the shallow-warning paragraph below the partial chain.)*
131
+
132
+ ## Contributing Factors
133
+
134
+ - <runbook step failure 1>: <stepDescription> (runbook-execution.jsonl#L<n>)
135
+ - <unverified observation that nevertheless steered the response>: (observations.jsonl#L<n>)
136
+
137
+ ## What Went Well
138
+
139
+ - <successful runbook step or disproved hypothesis> (runbook-execution.jsonl#L<n>) or (hypotheses.md#L<n>)
140
+ - Resolution metric verified: <criteria.metricName> < <threshold> for <windowMinutes>m sustained (resolution-evidence/<file>.json)
141
+
142
+ ## What Went Wrong
143
+
144
+ - <runbook execution failure> (runbook-execution.jsonl#L<n>)
145
+ - <risky action without precondition pass> (actions.jsonl#L<n>)
146
+
147
+ ## Action Items
148
+
149
+ | Item | Owner | Due | Source |
150
+ |------|-------|-----|--------|
151
+ | <derived from a What Went Wrong row> | TBD | TBD | (<artifact>#L<n>) |
152
+ | Add monitoring for the root-cause signal (5-Whys Level 3) | TBD | TBD | (5-whys-3) |
153
+
154
+ ---
155
+ *<Redactions footer if applicable: "**Redactions:** N secret-like strings redacted from artifacts.">*
156
+ *Generated by `bober postmortem generate <incidentId>` (Sprint 23).*
157
+ ```
158
+
159
+ ## Citation Format
160
+
161
+ Citations are parenthesized inline references at the end of a sentence:
162
+
163
+ | Style | When to use | Example |
164
+ |-------|------------|---------|
165
+ | `(file)` | Single-record JSON files | `(incident.json)` |
166
+ | `(file#L<n>)` | JSONL files where line maps to record | `(timeline.jsonl#L7)` |
167
+ | `(file#<event-id>)` | Records with explicit ids | `(diagnoses/diagnosis-inc-x-2026-05-24T14:30:00Z.json#h1)` |
168
+ | `(file1#L<n>, file2#L<m>)` | Multi-source corroboration in one claim | `(observations.jsonl#L3, changelog.jsonl#L1)` |
169
+
170
+ Every Impact bullet, every Timeline row, every 5-Whys level, every Action Item — all cite. The synthesizer enforces a minimum-5-citation floor; below that, it emits a synthesis-failure warning.
171
+
172
+ ## Redaction Discipline
173
+
174
+ Postmortems are widely shared. Apply these regexes to EVERY quoted artifact snippet BEFORE composing the markdown:
175
+
176
+ ```regex
177
+ /AKIA[0-9A-Z]{16}/g
178
+ /aws_secret_access_key\s*[=:]\s*\S+/gi
179
+ /(?:Bearer|Token|token|apikey|api_key|api-key)[\s=:]+["']?[A-Za-z0-9._\-]{16,}["']?/gi
180
+ /sk-[A-Za-z0-9]{20,}/g
181
+ /sk_(?:live|test)_[A-Za-z0-9]{10,}/g
182
+ /ghp_[A-Za-z0-9]{20,}/g
183
+ /secret_[A-Za-z0-9_\-]+/gi
184
+ /password\s*[=:]\s*\S+/gi
185
+ /Authorization:\s*Bearer\s+\S+/gi
186
+ /-----BEGIN [A-Z ]+PRIVATE KEY-----[\s\S]+?-----END [A-Z ]+PRIVATE KEY-----/g
187
+ ```
188
+
189
+ Replace each match with `[REDACTED]`. Increment a counter. If counter > 0, append the footer "**Redactions:** <N> secret-like strings redacted from artifacts." The redaction patterns themselves are listed here in SKILL.md as the canonical reference — they must NOT be quoted differently by the implementation. The implementing TypeScript module (`src/incident/postmortem.ts`) must use these exact regexes.
190
+
191
+ ## Red Flags - STOP
192
+
193
+ - A postmortem with fewer than 5 inline citations
194
+ - A 5-Whys section with fewer than 3 levels and NO shallow-warning paragraph
195
+ - An Impact section that lists symptoms not present in observations.jsonl
196
+ - A Timeline row whose timestamp does not appear in timeline.jsonl
197
+ - A quoted artifact snippet containing what looks like an API key, token, or password
198
+ - "Action Items: None" — there is always at least the monitoring action item
199
+ - Section headings present but section bodies empty — empty sections must be explicit ("No <X> recorded for this incident — (artifact is empty).")
200
+
201
+ ## Common Rationalizations
202
+
203
+ | Excuse | Reality |
204
+ |--------|---------|
205
+ | "I'll skip the line number, the file is short" | Line numbers are how auditors reproduce the synthesis. Always include them for JSONL artifacts. |
206
+ | "The 5-Whys narrative reads better if I fill in Why-4 from intuition" | Intuition is fabrication. Either derive Why-4 from changelog.jsonl or stop at Why-3 with the shallow-warning. |
207
+ | "Generic 'TBD' owners are fine for Action Items, they're not actionable anyway" | Owner: TBD is explicit and acceptable. "Owner: the team" or "Owner: someone" is generic prose disguised as data. |
208
+ | "The secret is in a closed system, no redaction needed" | Redact ALL secret-pattern matches unconditionally. Closed today is open tomorrow. |
209
+ | "There were no contributing factors, the response was clean" | Every incident has factors visible in runbook-execution.jsonl or hypotheses.md. An empty section is failure. |
210
+ | "I'll add one citation per section to satisfy the floor" | Per-sentence citations, not per-section. The floor is 5 INLINE citations across the document. |
211
+
212
+ ## Quick Reference
213
+
214
+ | Section | Source | Citation format |
215
+ |---------|--------|-----------------|
216
+ | Header (ID/Status/Severity/Date/Duration) | `incident.json` | `(incident.json)` |
217
+ | TL;DR | symptom + top hypothesis + last change | 2-3 citations inline |
218
+ | Impact | `observations.jsonl` (`verified: true`) + `resolution-evidence/` | `(observations.jsonl#L<n>)` |
219
+ | Timeline | `timeline.jsonl` (every row) | `(timeline.jsonl#L<n>)` per row |
220
+ | Root Cause | `diagnoses/*.json` + `changelog.jsonl` | per-Why citation |
221
+ | Contributing Factors | `runbook-execution.jsonl` (failed steps) | `(runbook-execution.jsonl#L<n>)` |
222
+ | What Went Well | successful runbook + disproved hypotheses + verified resolution | mixed |
223
+ | What Went Wrong | failed runbook + risky actions without precondition | mixed |
224
+ | Action Items | derived from What Went Wrong + monitoring | one citation per row |
225
+
226
+ ## Related Skills
227
+
228
+ - **`bober.diagnose`** — Phase 4 resolution-criteria verification produces `resolution-evidence/*.json` that this skill's Impact and What-Went-Well sections cite.
229
+ - **`bober.deploy`** — every ChangeEntry in `changelog.jsonl` was written under bober.deploy with a required inverse. The postmortem cites these for Root Cause (Why-4/Why-5) and as Action Item source rows.
230
+ - **`bober.runbook`** — every `runbook-execution.jsonl` entry was written under bober.runbook; failed steps populate Contributing Factors.
231
+ - **`agents/bober-postmortemer.md`** — the (offline, read-only) agent prompt companion to this skill. The TypeScript implementation in `src/incident/postmortem.ts` synthesizes deterministically; the agent prompt documents the discipline that any human or future LLM author must follow.
@@ -91,9 +91,18 @@ If it fails, report the missing prerequisites and stop.
91
91
 
92
92
  ### 1c. Check for Existing Plans
93
93
 
94
- List all spec files in `.bober/specs/`. For each spec, read only the **first 5 lines** of the JSON file. The `status` field is near the top — if it says `"completed"`, skip that spec entirely (do not load its contracts or read further).
94
+ List all spec files in `.bober/specs/`. For each spec, read only the **first 10 lines** of the JSON file. The `status` field is near the top — apply the following triage:
95
95
 
96
- Collect only the specs where `status` is NOT `"completed"` (i.e. `"planned"` or `"in-progress"`). These are the **actionable specs**.
96
+ - `"completed"` or `"abandoned"` skip entirely (do not load its contracts).
97
+ - `"needs-clarification"` → **BLOCK and surface to user.** Read the spec's `clarificationQuestions` array and print each one with its category, options, and recommendation. Tell the user to resolve via:
98
+ - `npx agent-bober plan answer <specId>` (interactive walkthrough), or
99
+ - `npx agent-bober plan answer <specId> <questionId> "<answer>"` (one-shot per question), or
100
+ - Edit `.bober/specs/<specId>.json` directly and flip `status` to `"ready"` after answering.
101
+
102
+ Do NOT include this spec in the actionable set. Do NOT proceed past the planning phase if this is the only spec — the user must answer first.
103
+ - `"draft"`, `"ready"`, `"in-progress"` → this is an **actionable spec**, collect it.
104
+
105
+ Collect only the actionable specs.
97
106
 
98
107
  - **No actionable specs + user provided a new task:** Create a new plan (go to Step 2).
99
108
  - **No actionable specs + no task provided:** Tell the user all plans are complete. Stop.
@@ -166,10 +175,34 @@ When done, respond with EXACTLY this JSON structure (no other text):
166
175
 
167
176
  **After the planner subagent returns:**
168
177
 
169
- 1. Parse the planner's response to extract `specId` and `contractIds`.
170
- 2. Read `.bober/specs/<specId>.json` to verify it was created.
171
- 3. Read each contract file in `.bober/contracts/` to verify they exist.
172
- 4. Print the plan summary:
178
+ 1. Parse the planner's response. Inspect the `status` field FIRST.
179
+
180
+ 2. **If `status` is `"needs-clarification"`:** The planner refused to fully decompose the request. STOP the pipeline. Read `.bober/specs/<specId>.json` and print the open `clarificationQuestions` to the user:
181
+
182
+ ```
183
+ === PLAN BLOCKED — NEEDS CLARIFICATION ===
184
+ Spec: <specId>
185
+ Title: <title>
186
+ Ambiguity score: <N>/10
187
+
188
+ Open questions:
189
+ Q1 [<category>]: <question>
190
+ A) <option> — <description>
191
+ B) <option> — <description>
192
+ 💡 Suggested: <recommendation if any>
193
+ Q2 [<category>]: <question>
194
+ ...
195
+
196
+ Resolve via either:
197
+ npx agent-bober plan answer <specId> (interactive)
198
+ npx agent-bober plan answer <specId> Q1 "<your answer>" (one-shot)
199
+ Or edit .bober/specs/<specId>.json directly and flip status to "ready".
200
+ ```
201
+
202
+ Do NOT proceed to Step 3. Do NOT spawn the generator subagent. The user must resolve the questions before the pipeline can continue. Exit cleanly.
203
+
204
+ 3. **If `status` is `"draft"` or `"ready"`:** Extract `specId` and `contractIds`. Read `.bober/specs/<specId>.json` to verify it was created. Read each contract file in `.bober/contracts/` to verify they exist. Print the plan summary:
205
+
173
206
  ```
174
207
  === PLAN CREATED ===
175
208
  Spec: <specId>
@@ -179,7 +212,8 @@ When done, respond with EXACTLY this JSON structure (no other text):
179
212
  2. <Sprint 2 title>
180
213
  ...
181
214
  ```
182
- 5. If the planner subagent failed or returned an error, report it and stop the pipeline.
215
+
216
+ 4. If the planner subagent failed or returned an error, report it and stop the pipeline.
183
217
 
184
218
  ---
185
219
 
@@ -0,0 +1,335 @@
1
+ ---
2
+ name: bober-runbook
3
+ description: Use when executing a runbook or step-by-step recovery procedure — verify precondition before each step, execute, verify postcondition before advancing; hard gate around destructive operations
4
+ ---
5
+
6
+ > Adapted from [obra/superpowers](https://github.com/obra/superpowers) — MIT License.
7
+ > Structural source: verification-before-completion discipline (precondition → execute → postcondition loop).
8
+ > Adaptations: applied to runbook step execution; explicit hard gate around steps with blastRadius='risky'; rollback cascade for postcondition failures.
9
+
10
+ # Runbook Execution Discipline
11
+
12
+ ## Overview
13
+
14
+ A runbook is a contract between the author and the executor: each step asserts what must be true before it runs and what must be true after. Blindly running steps without verification turns a recovery procedure into a second incident. A step that succeeds silently while leaving the system in an unexpected state is MORE dangerous than a step that fails loudly.
15
+
16
+ **Core principle:** ALWAYS verify the precondition before executing each step, and the postcondition before advancing.
17
+
18
+ **Violating the letter of this process is violating the spirit of incident recovery.**
19
+
20
+ ## The Iron Law
21
+
22
+ ```
23
+ NO STEP EXECUTION WITHOUT VERIFIED PRECONDITION; NO ADVANCE WITHOUT VERIFIED POSTCONDITION
24
+ ```
25
+
26
+ A runbook is a contract: each step asserts what must be true BEFORE it runs and what must be true AFTER. Executing without verifying preconditions makes the incident worse. Advancing without verifying postconditions hides failures that the next step assumes have been handled.
27
+
28
+ ## When to Use
29
+
30
+ Use for ANY step-by-step operational procedure:
31
+ - Recovering from a production incident via a named runbook
32
+ - Following a disaster-recovery procedure
33
+ - Executing a curated playbook from `.bober/playbooks/`
34
+ - Rolling back a deployment via prescribed steps
35
+ - Running a database migration procedure
36
+ - Applying a pre-approved scaling policy
37
+
38
+ **Use this ESPECIALLY when:**
39
+ - An incident is active and seconds count (pressure makes step-skipping tempting)
40
+ - The runbook author is not in the room to answer questions
41
+ - The procedure involves destructive or stateful operations
42
+ - You are executing a runbook you have never run before in production
43
+
44
+ **Don't skip when:**
45
+ - "Everyone knows this runbook" — tribal knowledge is not a verified precondition
46
+ - "We ran it last week and it was fine" — system state changes; the precondition may no longer hold
47
+ - "The operator says skip the precondition" — the Iron Law is not advisory; get an explicit checkpoint approval if you must proceed without a check
48
+
49
+ ## Runbook Parse Format
50
+
51
+ A runbook is a markdown file with YAML frontmatter and numbered step sections.
52
+
53
+ **Frontmatter:**
54
+
55
+ ```yaml
56
+ ---
57
+ name: <kebab-case runbook name>
58
+ classification: standard | emergency
59
+ prerequisites:
60
+ - <human-readable prerequisite>
61
+ - <another prerequisite>
62
+ ---
63
+ ```
64
+
65
+ **Each step section:**
66
+
67
+ - `## Step <N>: <description>` — H2 with step number and one-line description
68
+ - `blastRadius: safe | risky` — REQUIRED. `safe` = read-only or trivially reversible (e.g., a kubectl get, a feature flag flip back to default). `risky` = stateful, destructive, externally-observable (e.g., kubectl scale, kubectl rollout, terraform apply, db migration).
69
+ - `precondition-check:` — REQUIRED. A bulleted list of conditions to verify BEFORE the step runs. Each bullet is either a concrete command (e.g., `kubectl get deployment api -o json | jq .spec.replicas — value is 3`) or a human-readable check (e.g., `acknowledgement received in channel`).
70
+ - `execute:` — REQUIRED. A bulleted list of the actual operation. For safe steps, may be a single command. For risky steps, ALWAYS a single command (multi-command risky steps must be split into separate numbered steps so each gets its own checkpoint).
71
+ - `postcondition-check:` — REQUIRED. A bulleted list of conditions to verify AFTER the step runs. Same format as precondition.
72
+ - `rollback:` — OPTIONAL. A bulleted list of operations to run if postcondition-check fails. If omitted, postcondition failure triggers immediate escalation (see Rollback Cascade).
73
+
74
+ **Worked frontmatter + two-step example:**
75
+
76
+ ~~~markdown
77
+ ---
78
+ name: high-error-rate-recovery
79
+ classification: emergency
80
+ prerequisites:
81
+ - logged in as production-on-call
82
+ - error rate observable in obs__datadog
83
+ ---
84
+
85
+ ## Step 1: Confirm error rate exceeded threshold
86
+ blastRadius: safe
87
+
88
+ precondition-check:
89
+ - Read obs__datadog metric `api.error_rate`; current value > 1% for >= 5 minutes
90
+
91
+ execute:
92
+ - (description only) Open the runbook approver in the team channel
93
+
94
+ postcondition-check:
95
+ - Acknowledgement received in channel from at least one approver
96
+
97
+ ## Step 2: Scale up replicas
98
+ blastRadius: risky # destructive — requires checkpoint approval
99
+
100
+ precondition-check:
101
+ - kubectl get deployment api-service -o json | jq .spec.replicas — value is 3
102
+
103
+ execute:
104
+ - kubectl scale deployment api-service --replicas=6
105
+
106
+ postcondition-check:
107
+ - kubectl get pods -l app=api-service -o json | jq '.items | map(select(.status.phase=="Running")) | length' — value is 6
108
+
109
+ rollback:
110
+ - kubectl scale deployment api-service --replicas=3
111
+ ~~~
112
+
113
+ <EXTREMELY-IMPORTANT>
114
+ BEFORE executing the first step, you MUST parse the runbook end-to-end and verify every step has a precondition-check and a postcondition-check declared. A runbook with an undeclared precondition-check on ANY step is malformed — abort and escalate via checkpoint. Do NOT silently default to "no check" — the absence of a check is a parse-time failure, not a runtime convenience.
115
+ </EXTREMELY-IMPORTANT>
116
+
117
+ ## Execution Discipline
118
+
119
+ For each step in the runbook, run the four-stage loop. Do not skip stages. Do not reorder.
120
+
121
+ ```
122
+ FOR each step IN runbook:
123
+ RUN precondition-check
124
+ IF precondition fails: STOP, report 'precondition_failed', do not advance
125
+ IF step.blastRadius == 'risky':
126
+ INVOKE checkpoint(pre-execute) — even in autopilot mode
127
+ IF checkpoint rejected: STOP, abort runbook
128
+ EXECUTE step (command, or await human action via checkpoint if description-only)
129
+ RUN postcondition-check
130
+ IF postcondition fails:
131
+ IF step.rollback defined: EXECUTE rollback
132
+ IF rollback postcondition still fails: ESCALATE via checkpoint, STOP
133
+ IF rollback NOT defined: ESCALATE via checkpoint, STOP
134
+ ADVANCE to next step
135
+ MARK runbook complete; write summary entry to .bober/incidents/<id>/runbook-execution.jsonl
136
+ ```
137
+
138
+ **STOP conditions enumerated:**
139
+
140
+ - **Precondition fails** → STOP. Write `{status: 'precondition_failed'}` to runbook-execution.jsonl. Do NOT execute.
141
+ - **Risky-step checkpoint rejected** → STOP. Write `{status: 'checkpoint_rejected'}`. Do NOT execute.
142
+ - **Step execution errors** → STOP. Write `{status: 'execution_failed'}`. Trigger rollback if defined; otherwise escalate.
143
+ - **Postcondition fails AND rollback fails (or no rollback)** → STOP. Write `{status: 'rollback_failed'}` (or `{status: 'postcondition_failed_no_rollback'}`). Escalate via checkpoint.
144
+
145
+ ADVANCE happens ONLY when the postcondition-check explicitly passes. Default behavior on uncertainty is STOP, not ADVANCE.
146
+
147
+ ## Hard Gate — Risky Steps
148
+
149
+ Any step with `blastRadius: 'risky'` MUST invoke the Tier 2 checkpoint mechanism before execution. This is UNCONDITIONAL:
150
+
151
+ - **`pipeline.mode='autopilot'` does NOT bypass risky-step approval.** Autopilot trades human-in-the-loop for speed on SAFE steps; the risky-step gate is the production safety floor and does not move.
152
+ - **`pipeline.checkpointMechanism='noop'` does NOT apply to risky steps.** When the configured mechanism is `noop` but the step is risky, the runbook executor uses the default `disk` fallback (Sprint 13's checkpoint mechanism). The gate cannot be configured away.
153
+ - **Multi-command bash invocations do NOT slip through the gate.** A step 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.
154
+
155
+ The gate receives the step's classification reasoning, the proposed command, and the declared rollback. The operator can approve, reject, or modify (the modification is recorded in `changelog.jsonl` via Sprint 19's `appendChange` with the required `inverse` field).
156
+
157
+ <EXTREMELY-IMPORTANT>
158
+ Risky steps invoke the Tier 2 checkpoint mechanism regardless of pipeline.mode. Autopilot mode does NOT bypass risky-step approval. If `pipeline.mode='autopilot'` and `pipeline.checkpointMechanism='noop'`, the runbook executor STILL invokes a non-noop mechanism (default 'disk' fallback) for any step with `blastRadius: 'risky'`. This is the production safety guarantee — bypassing it forfeits the guarantee.
159
+ </EXTREMELY-IMPORTANT>
160
+
161
+ The escape hatch — `pipeline.allowAutopilotRiskyActions=true` — is documented in `skills/bober.deploy/SKILL.md` (Sprint 20) and exists for fully-automated environments (CI, batch jobs) where no human is available. Default `false`. When set to `true`, risky steps are auto-approved BUT a stern warning is logged and the `ChangeEntry` is still recorded with the required `inverse`. This is "skip the interactive approval" — NOT "skip the audit trail."
162
+
163
+ ## Rollback Cascade
164
+
165
+ When a step's postcondition-check fails, the runbook executor follows a three-tier cascade. Each tier MUST be exhausted before falling to the next.
166
+
167
+ **Tier 1 — Run the declared rollback (if any).**
168
+ The rollback is itself a mini-step: it has an `execute` command and an implicit postcondition (the inverse of the failed step's postcondition). Run the rollback command. Then check whether the rollback's effect held — for example, if the original step scaled to 6 replicas and failed, the rollback `kubectl scale --replicas=3` is verified by `kubectl get deployment ... | jq .spec.replicas == 3`.
169
+
170
+ **Tier 2 — If rollback fails OR no rollback was declared, escalate via checkpoint.**
171
+ The checkpoint payload includes: the failed step number, the postcondition-check result, the rollback-attempt result (if attempted), and the current observable state. The operator (or the configured escalation handler) decides the next move — manual intervention, abort, or override.
172
+
173
+ **Tier 3 — Write the indeterminate state to the observation log and STOP the runbook.**
174
+ Regardless of which tier resolved (or did not resolve) the failure, append a complete record to `.bober/incidents/<id>/runbook-execution.jsonl` with `rollbackTriggered: true` (Tier 1 ran) and `status: 'rollback_failed' | 'escalated' | 'recovered_via_rollback'` as appropriate. Do NOT continue with subsequent steps — their preconditions assume the failed step's postcondition held, which it did not.
175
+
176
+ <EXTREMELY-IMPORTANT>
177
+ If a step's postcondition fails AND its declared rollback ALSO fails (or no rollback was declared), the runbook executor MUST escalate via the Tier 2 checkpoint mechanism — do not silently proceed, do not retry the failed step. The incident state is now indeterminate; only a human (or the configured escalation handler) can decide the next move.
178
+ </EXTREMELY-IMPORTANT>
179
+
180
+ ## Observation Log
181
+
182
+ Every step execution writes one line to `.bober/incidents/<id>/runbook-execution.jsonl`. Sprint 19's `appendRunbookExecution` helper provides the write primitive; this skill documents the schema.
183
+
184
+ **Line shape:**
185
+
186
+ ```json
187
+ {
188
+ "timestamp": "<ISO-8601, when the step completed (or failed)>",
189
+ "runbookName": "<frontmatter name from the runbook file>",
190
+ "stepNumber": "<integer, 1-indexed from the H2 ## Step N: ...>",
191
+ "status": "'precondition_failed' | 'checkpoint_rejected' | 'execution_failed' | 'postcondition_failed_no_rollback' | 'rollback_failed' | 'recovered_via_rollback' | 'success'",
192
+ "preconditionResult": "'pass' | 'fail' | 'not_run'",
193
+ "postconditionResult": "'pass' | 'fail' | 'not_run'",
194
+ "rollbackTriggered": "<boolean — true if Tier 1 of the cascade ran, false or omitted otherwise>"
195
+ }
196
+ ```
197
+
198
+ **Worked log entries (one runbook execution, three steps):**
199
+
200
+ ```jsonl
201
+ {"timestamp": "2026-05-24T14:10:00Z", "runbookName": "high-error-rate-recovery", "stepNumber": 1, "status": "success", "preconditionResult": "pass", "postconditionResult": "pass"}
202
+ {"timestamp": "2026-05-24T14:12:00Z", "runbookName": "high-error-rate-recovery", "stepNumber": 2, "status": "success", "preconditionResult": "pass", "postconditionResult": "pass"}
203
+ {"timestamp": "2026-05-24T14:15:00Z", "runbookName": "high-error-rate-recovery", "stepNumber": 3, "status": "recovered_via_rollback", "preconditionResult": "pass", "postconditionResult": "fail", "rollbackTriggered": true}
204
+ ```
205
+
206
+ The timeline.jsonl (Sprint 19) ALSO gains a corresponding line per step via Sprint 19's pattern that "every other append helper ALSO writes a corresponding timeline event." Operators get a chronological view via `cat timeline.jsonl`, and a runbook-specific view via `cat runbook-execution.jsonl`.
207
+
208
+ **Field-name lock:** The exact 7 field names above (`timestamp, runbookName, stepNumber, status, preconditionResult, postconditionResult, rollbackTriggered`) are the schema Sprint 19's writer will use. Do NOT introduce field-name variants — `step_number` vs `stepNumber`, `runbook_name` vs `runbookName` — schema drift between sprints breaks the timeline.
209
+
210
+ ## Worked Example — Recovering from API Error Spike
211
+
212
+ A worked end-to-end execution of `high-error-rate-recovery` (the runbook in §Runbook Parse Format).
213
+
214
+ **Setup:** Datadog alert fires at 14:00 UTC. `api.error_rate` at 4.2%. Diagnoser (via `bober.diagnose` Phase 1-3) hypothesizes "replicas exhausted under load, scaling up will relieve pressure." `nextActions[0]` is `{action: "follow runbook high-error-rate-recovery", blastRadius: "risky", requiresApproval: true}`. Orchestrator invokes this skill.
215
+
216
+ **Step 1 — Confirm error rate exceeded threshold (`blastRadius: safe`):**
217
+
218
+ Precondition-check:
219
+
220
+ ```bash
221
+ $ curl -s "https://datadog/api/v1/query?query=avg:api.error_rate{*}&from=now-5m" | jq .series[0].pointlist[-1][1]
222
+ 0.042 # 4.2% > 1% threshold — PASS
223
+ ```
224
+
225
+ Execute (description-only): "Open the runbook approver in the team channel" — agent awaits human action via checkpoint.
226
+
227
+ Postcondition-check:
228
+
229
+ ```bash
230
+ $ grep -c "approved" /tmp/channel-acks.log
231
+ 1 # at least one approver — PASS
232
+ ```
233
+
234
+ Status: `success`. ADVANCE to Step 2.
235
+
236
+ **Step 2 — Scale up replicas (`blastRadius: risky`):**
237
+
238
+ Precondition-check:
239
+
240
+ ```bash
241
+ $ kubectl get deployment api-service -o json | jq .spec.replicas
242
+ 3 # matches expected — PASS
243
+ ```
244
+
245
+ **Risky step — HARD GATE invoked.** Even though `pipeline.mode='autopilot'`, the checkpoint mechanism (default 'disk' fallback because configured 'noop' is overridden for risky steps) presents the action to the operator. Payload includes:
246
+ - Action: `kubectl scale deployment api-service --replicas=6`
247
+ - Classification reasoning: scale operation is stateful + externally-observable
248
+ - Proposed rollback: `kubectl scale deployment api-service --replicas=3`
249
+
250
+ Operator approves. Step executes.
251
+
252
+ Execute:
253
+
254
+ ```bash
255
+ $ kubectl scale deployment api-service --replicas=6
256
+ deployment.apps/api-service scaled
257
+ ```
258
+
259
+ Postcondition-check:
260
+
261
+ ```bash
262
+ $ kubectl get pods -l app=api-service -o json | jq '.items | map(select(.status.phase=="Running")) | length'
263
+ 6 # 6 pods Ready — PASS
264
+ ```
265
+
266
+ Status: `success`. ADVANCE.
267
+
268
+ **Log entries written:**
269
+
270
+ ```jsonl
271
+ {"timestamp": "2026-05-24T14:11:00Z", "runbookName": "high-error-rate-recovery", "stepNumber": 1, "status": "success", "preconditionResult": "pass", "postconditionResult": "pass"}
272
+ {"timestamp": "2026-05-24T14:14:00Z", "runbookName": "high-error-rate-recovery", "stepNumber": 2, "status": "success", "preconditionResult": "pass", "postconditionResult": "pass"}
273
+ ```
274
+
275
+ **Counter-example — rollback cascade in action.** Suppose Step 2's postcondition had returned `4` (only 4 pods Running). The runbook executor would:
276
+
277
+ 1. Run rollback `kubectl scale deployment api-service --replicas=3`.
278
+ 2. Verify rollback's effect: `kubectl get deployment api-service -o json | jq .spec.replicas == 3` → PASS.
279
+ 3. Write `{status: "recovered_via_rollback", rollbackTriggered: true, ...}` and STOP.
280
+
281
+ If the rollback ITSELF had failed (e.g., kubectl API errored), the executor escalates via checkpoint with `{status: "rollback_failed", rollbackTriggered: true, ...}` and STOPs. The operator decides next move; the runbook does NOT continue.
282
+
283
+ ## Red Flags - STOP and Follow Process
284
+
285
+ If you catch yourself thinking:
286
+ - "The precondition check is obvious, just run the step"
287
+ - "The postcondition is just a sanity check, advance anyway"
288
+ - "It's a small scale-up, skip the checkpoint"
289
+ - "The rollback should be safe to skip, the change was tiny"
290
+ - "Autopilot mode said skip approval"
291
+ - "The step failed but the next one might fix it, try advancing"
292
+ - "No rollback declared, that means it's safe to skip the cascade"
293
+ - "The runbook is in the playbook library so it must be safe"
294
+ - "Precondition timed out, retry without checking"
295
+ - Advancing to the next step without an explicit postcondition PASS result
296
+ - **"No time to check preconditions, the incident is live"**
297
+
298
+ **ALL of these mean: STOP. Return to the verification loop — parse, check, execute, verify.**
299
+
300
+ ## Common Rationalizations
301
+
302
+ | Excuse | Reality |
303
+ |--------|---------|
304
+ | "The precondition is just paperwork, the team always runs this step without checking" | Tribal-knowledge preconditions are precisely what the runbook formalizes. Run the check — if it's always true, it costs nothing; if it's not always true, you just averted an incident. |
305
+ | "The postcondition can be verified later, we're behind schedule" | Postcondition deferred is postcondition skipped. The next step's precondition assumes this step's postcondition held. Defer the verification, defer the failure into a worse moment. |
306
+ | "Autopilot mode is explicitly opt-in for trusted runbooks" | Autopilot mode trades human-in-the-loop for speed on SAFE steps. Risky-step approval is the safety floor — autopilot does NOT bypass it. Read the Iron Law again. |
307
+ | "Rollback failed but the system looks fine, mark step complete" | If the rollback failed, you do not know the system state. "Looks fine" is not state knowledge. Escalate via checkpoint — the operator decides whether to mark complete or treat as undetermined. |
308
+ | "No rollback declared because the step is reversible by retrying" | Retry-as-rollback is acceptable ONLY when declared as the rollback. An undeclared "we'll just retry" is implicit state, not a recoverable plan. Declare the rollback at runbook-write time. |
309
+ | "The runbook came from the playbook library, trust the author" | Trust the discipline, not the author. The parse format and the four-stage loop apply to every runbook regardless of author. The library passed review for SHAPE, not for situation fit. |
310
+ | "The step is idempotent so skipping the precondition is harmless" | Idempotency is a property of the happy path. An idempotent step run against an unexpected precondition state is NOT guaranteed idempotent — the precondition defines the state the idempotency guarantee assumes. |
311
+ | "It worked in staging, precondition must be fine" | Staging is a hypothesis about production state, not a verification. The precondition-check runs in production, against production state, immediately before the step executes. Staging results are not portable. |
312
+
313
+ ## Quick Reference
314
+
315
+ | Stage | Key Activities | Success Criteria |
316
+ |-------|---------------|------------------|
317
+ | **1. Parse** | Read frontmatter (name, classification, prerequisites); enumerate steps; verify each step has precondition-check + postcondition-check + blastRadius | Runbook is structurally valid; no undeclared checks |
318
+ | **2. Precondition** | Run precondition-check command (or read the condition); compare to expected state | Result matches expected; otherwise STOP |
319
+ | **3. Execute** | If step is risky → invoke Tier 2 checkpoint (regardless of pipeline.mode); on approval, run the step's command (or await human action) | Step ran without error |
320
+ | **4. Postcondition** | Run postcondition-check; if pass → advance; if fail → run rollback; if rollback also fails → escalate via checkpoint | Either step's postcondition holds OR rollback's postcondition holds OR escalation triggered |
321
+
322
+ ## Related Skills
323
+
324
+ - **`bober.diagnose`** (`skills/bober.diagnose/SKILL.md`, Sprint 17) — Upstream skill. The diagnoser identifies "follow runbook X" as a next-action; that next-action is then executed under this skill's discipline. Diagnose says WHAT to do; runbook says HOW to do each step safely.
325
+ - **`bober.deploy`** (`skills/bober.deploy/SKILL.md`, Sprint 20) — Downstream execution wiring. `bober.deploy` is the agent-level execution discipline (action classification, checkpoint gate enforcement, ChangeEntry recording with required inverse). `bober.runbook` is the operator-level discipline for executing a step-by-step procedure; `bober.deploy` is what actually runs the risky step. Risky steps in this skill DELEGATE to `agents/bober-deployer.md` for execution.
326
+ - **`.bober/playbooks/`** (Sprint 25) — Library of curated runbooks (`build-failure.md`, `migration-timeout.md`, `error-spike.md`, `latency-regression.md`). Each playbook MUST conform to the parse format documented in this skill. The diagnoser invokes `searchPlaybooks(symptom)` to find a matching playbook; matched playbooks are executed under this skill's discipline.
327
+ - **`.bober/anti-patterns/`** — Pattern catalog. Two anti-patterns are especially common in runbook execution: **Single-Layer Validation** (`defense-in-depth.md` — postcondition skipped because step "looked successful") and **Symptom-Fix Instead of Root-Cause** (`root-cause-tracing.md` — running a recovery runbook to mask an underlying defect).
328
+
329
+ ## Real-World Impact
330
+
331
+ From incident response patterns:
332
+ - Runbook execution with pre/post verification: regressions caught at the step boundary, not as downstream failures
333
+ - Runbook execution without postcondition checks: failures propagate silently, next-step preconditions assume state that no longer exists
334
+ - Risky steps with hard-gate enforcement: blast radius contained to the declared scope of the step
335
+ - Risky steps executed without approval in autopilot mode: unreviewed changes to production infrastructure with no audit trail