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.
- package/CHANGELOG.md +311 -0
- package/README.md +124 -9
- package/agents/bober-architect.md +38 -0
- package/agents/bober-code-reviewer.md +236 -0
- package/agents/bober-curator.md +37 -0
- package/agents/bober-deployer.md +267 -0
- package/agents/bober-diagnoser.md +289 -0
- package/agents/bober-evaluator.md +127 -1
- package/agents/bober-generator.md +122 -3
- package/agents/bober-planner.md +293 -32
- package/agents/bober-postmortemer.md +185 -0
- package/agents/bober-researcher.md +38 -0
- package/dist/cli/commands/approve.d.ts +17 -0
- package/dist/cli/commands/approve.d.ts.map +1 -0
- package/dist/cli/commands/approve.js +64 -0
- package/dist/cli/commands/approve.js.map +1 -0
- package/dist/cli/commands/audit-show.d.ts +14 -0
- package/dist/cli/commands/audit-show.d.ts.map +1 -0
- package/dist/cli/commands/audit-show.js +85 -0
- package/dist/cli/commands/audit-show.js.map +1 -0
- package/dist/cli/commands/config.d.ts +10 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +73 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/eval.js +6 -6
- package/dist/cli/commands/eval.js.map +1 -1
- package/dist/cli/commands/graph.d.ts +8 -0
- package/dist/cli/commands/graph.d.ts.map +1 -0
- package/dist/cli/commands/graph.js +219 -0
- package/dist/cli/commands/graph.js.map +1 -0
- package/dist/cli/commands/impact.d.ts +19 -0
- package/dist/cli/commands/impact.d.ts.map +1 -0
- package/dist/cli/commands/impact.js +191 -0
- package/dist/cli/commands/impact.js.map +1 -0
- package/dist/cli/commands/incident.d.ts +19 -0
- package/dist/cli/commands/incident.d.ts.map +1 -0
- package/dist/cli/commands/incident.js +324 -0
- package/dist/cli/commands/incident.js.map +1 -0
- package/dist/cli/commands/init.js +82 -3
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/list-approvals.d.ts +16 -0
- package/dist/cli/commands/list-approvals.d.ts.map +1 -0
- package/dist/cli/commands/list-approvals.js +57 -0
- package/dist/cli/commands/list-approvals.js.map +1 -0
- package/dist/cli/commands/onboard.d.ts +3 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -0
- package/dist/cli/commands/onboard.js +190 -0
- package/dist/cli/commands/onboard.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +12 -0
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +232 -37
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/playbook.d.ts +17 -0
- package/dist/cli/commands/playbook.d.ts.map +1 -0
- package/dist/cli/commands/playbook.js +123 -0
- package/dist/cli/commands/playbook.js.map +1 -0
- package/dist/cli/commands/postmortem.d.ts +12 -0
- package/dist/cli/commands/postmortem.d.ts.map +1 -0
- package/dist/cli/commands/postmortem.js +67 -0
- package/dist/cli/commands/postmortem.js.map +1 -0
- package/dist/cli/commands/reject.d.ts +17 -0
- package/dist/cli/commands/reject.d.ts.map +1 -0
- package/dist/cli/commands/reject.js +52 -0
- package/dist/cli/commands/reject.js.map +1 -0
- package/dist/cli/commands/rollback.d.ts +21 -0
- package/dist/cli/commands/rollback.d.ts.map +1 -0
- package/dist/cli/commands/rollback.js +90 -0
- package/dist/cli/commands/rollback.js.map +1 -0
- package/dist/cli/commands/run.d.ts +9 -0
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +31 -2
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts.map +1 -1
- package/dist/cli/commands/sprint.js +8 -8
- package/dist/cli/commands/sprint.js.map +1 -1
- package/dist/cli/commands/telemetry.d.ts +16 -0
- package/dist/cli/commands/telemetry.d.ts.map +1 -0
- package/dist/cli/commands/telemetry.js +152 -0
- package/dist/cli/commands/telemetry.js.map +1 -0
- package/dist/cli/commands/worktree.d.ts +12 -0
- package/dist/cli/commands/worktree.d.ts.map +1 -0
- package/dist/cli/commands/worktree.js +57 -0
- package/dist/cli/commands/worktree.js.map +1 -0
- package/dist/cli/index.js +73 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +27 -0
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +4 -0
- package/dist/config/index.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +18 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/schema.d.ts +1016 -96
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +147 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/contracts/eval-result.d.ts +38 -38
- package/dist/contracts/index.d.ts +2 -2
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +8 -4
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/spec.d.ts +335 -40
- package/dist/contracts/spec.d.ts.map +1 -1
- package/dist/contracts/spec.js +210 -18
- package/dist/contracts/spec.js.map +1 -1
- package/dist/contracts/sprint-contract.d.ts +155 -88
- package/dist/contracts/sprint-contract.d.ts.map +1 -1
- package/dist/contracts/sprint-contract.js +176 -29
- package/dist/contracts/sprint-contract.js.map +1 -1
- package/dist/evaluators/builtin/api-check.js +1 -1
- package/dist/evaluators/builtin/api-check.js.map +1 -1
- package/dist/graph/artifact-store.d.ts +14 -0
- package/dist/graph/artifact-store.d.ts.map +1 -0
- package/dist/graph/artifact-store.js +100 -0
- package/dist/graph/artifact-store.js.map +1 -0
- package/dist/graph/cli.d.ts +49 -0
- package/dist/graph/cli.d.ts.map +1 -0
- package/dist/graph/cli.js +140 -0
- package/dist/graph/cli.js.map +1 -0
- package/dist/graph/client.d.ts +64 -0
- package/dist/graph/client.d.ts.map +1 -0
- package/dist/graph/client.js +216 -0
- package/dist/graph/client.js.map +1 -0
- package/dist/graph/fallback.d.ts +13 -0
- package/dist/graph/fallback.d.ts.map +1 -0
- package/dist/graph/fallback.js +57 -0
- package/dist/graph/fallback.js.map +1 -0
- package/dist/graph/hook-handler.d.ts +50 -0
- package/dist/graph/hook-handler.d.ts.map +1 -0
- package/dist/graph/hook-handler.js +217 -0
- package/dist/graph/hook-handler.js.map +1 -0
- package/dist/graph/incidents.d.ts +59 -0
- package/dist/graph/incidents.d.ts.map +1 -0
- package/dist/graph/incidents.js +22 -0
- package/dist/graph/incidents.js.map +1 -0
- package/dist/graph/mcp-client.d.ts +51 -0
- package/dist/graph/mcp-client.d.ts.map +1 -0
- package/dist/graph/mcp-client.js +285 -0
- package/dist/graph/mcp-client.js.map +1 -0
- package/dist/graph/onboarding-composer.d.ts +30 -0
- package/dist/graph/onboarding-composer.d.ts.map +1 -0
- package/dist/graph/onboarding-composer.js +275 -0
- package/dist/graph/onboarding-composer.js.map +1 -0
- package/dist/graph/pipeline-lifecycle.d.ts +86 -0
- package/dist/graph/pipeline-lifecycle.d.ts.map +1 -0
- package/dist/graph/pipeline-lifecycle.js +329 -0
- package/dist/graph/pipeline-lifecycle.js.map +1 -0
- package/dist/graph/preflight-budgets.d.ts +52 -0
- package/dist/graph/preflight-budgets.d.ts.map +1 -0
- package/dist/graph/preflight-budgets.js +78 -0
- package/dist/graph/preflight-budgets.js.map +1 -0
- package/dist/graph/preflight-injector.d.ts +116 -0
- package/dist/graph/preflight-injector.d.ts.map +1 -0
- package/dist/graph/preflight-injector.js +538 -0
- package/dist/graph/preflight-injector.js.map +1 -0
- package/dist/graph/prereq.d.ts +12 -0
- package/dist/graph/prereq.d.ts.map +1 -0
- package/dist/graph/prereq.js +61 -0
- package/dist/graph/prereq.js.map +1 -0
- package/dist/graph/prompts.d.ts +42 -0
- package/dist/graph/prompts.d.ts.map +1 -0
- package/dist/graph/prompts.js +80 -0
- package/dist/graph/prompts.js.map +1 -0
- package/dist/graph/sandbox.d.ts +19 -0
- package/dist/graph/sandbox.d.ts.map +1 -0
- package/dist/graph/sandbox.js +25 -0
- package/dist/graph/sandbox.js.map +1 -0
- package/dist/graph/token-usage.d.ts +21 -0
- package/dist/graph/token-usage.d.ts.map +1 -0
- package/dist/graph/token-usage.js +22 -0
- package/dist/graph/token-usage.js.map +1 -0
- package/dist/graph/types.d.ts +129 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph/types.js +12 -0
- package/dist/graph/types.js.map +1 -0
- package/dist/incident/orchestrator.d.ts +168 -0
- package/dist/incident/orchestrator.d.ts.map +1 -0
- package/dist/incident/orchestrator.js +279 -0
- package/dist/incident/orchestrator.js.map +1 -0
- package/dist/incident/playbook-search.d.ts +67 -0
- package/dist/incident/playbook-search.d.ts.map +1 -0
- package/dist/incident/playbook-search.js +288 -0
- package/dist/incident/playbook-search.js.map +1 -0
- package/dist/incident/postmortem.d.ts +44 -0
- package/dist/incident/postmortem.d.ts.map +1 -0
- package/dist/incident/postmortem.js +486 -0
- package/dist/incident/postmortem.js.map +1 -0
- package/dist/incident/resolution-verify.d.ts +186 -0
- package/dist/incident/resolution-verify.d.ts.map +1 -0
- package/dist/incident/resolution-verify.js +210 -0
- package/dist/incident/resolution-verify.js.map +1 -0
- package/dist/incident/rollback.d.ts +137 -0
- package/dist/incident/rollback.d.ts.map +1 -0
- package/dist/incident/rollback.js +328 -0
- package/dist/incident/rollback.js.map +1 -0
- package/dist/incident/timeline.d.ts +147 -0
- package/dist/incident/timeline.d.ts.map +1 -0
- package/dist/incident/timeline.js +452 -0
- package/dist/incident/timeline.js.map +1 -0
- package/dist/incident/types.d.ts +335 -0
- package/dist/incident/types.d.ts.map +1 -0
- package/dist/incident/types.js +158 -0
- package/dist/incident/types.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/event-stream.d.ts +46 -0
- package/dist/mcp/event-stream.d.ts.map +1 -0
- package/dist/mcp/event-stream.js +421 -0
- package/dist/mcp/event-stream.js.map +1 -0
- package/dist/mcp/external-client.d.ts +38 -0
- package/dist/mcp/external-client.d.ts.map +1 -0
- package/dist/mcp/external-client.js +121 -0
- package/dist/mcp/external-client.js.map +1 -0
- package/dist/mcp/run-manager.d.ts +74 -9
- package/dist/mcp/run-manager.d.ts.map +1 -1
- package/dist/mcp/run-manager.js +127 -31
- package/dist/mcp/run-manager.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +56 -0
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/abort-run.d.ts +2 -0
- package/dist/mcp/tools/abort-run.d.ts.map +1 -0
- package/dist/mcp/tools/abort-run.js +62 -0
- package/dist/mcp/tools/abort-run.js.map +1 -0
- package/dist/mcp/tools/anchor.js +1 -1
- package/dist/mcp/tools/anchor.js.map +1 -1
- package/dist/mcp/tools/approve-checkpoint.d.ts +2 -0
- package/dist/mcp/tools/approve-checkpoint.d.ts.map +1 -0
- package/dist/mcp/tools/approve-checkpoint.js +70 -0
- package/dist/mcp/tools/approve-checkpoint.js.map +1 -0
- package/dist/mcp/tools/brownfield.js +1 -1
- package/dist/mcp/tools/brownfield.js.map +1 -1
- package/dist/mcp/tools/contracts.js +2 -2
- package/dist/mcp/tools/contracts.js.map +1 -1
- package/dist/mcp/tools/eval.js +8 -8
- package/dist/mcp/tools/eval.js.map +1 -1
- package/dist/mcp/tools/get-project-state.d.ts +2 -0
- package/dist/mcp/tools/get-project-state.d.ts.map +1 -0
- package/dist/mcp/tools/get-project-state.js +107 -0
- package/dist/mcp/tools/get-project-state.js.map +1 -0
- package/dist/mcp/tools/get-run-status.d.ts +2 -0
- package/dist/mcp/tools/get-run-status.d.ts.map +1 -0
- package/dist/mcp/tools/get-run-status.js +40 -0
- package/dist/mcp/tools/get-run-status.js.map +1 -0
- package/dist/mcp/tools/graph-schemas.d.ts +100 -0
- package/dist/mcp/tools/graph-schemas.d.ts.map +1 -0
- package/dist/mcp/tools/graph-schemas.js +39 -0
- package/dist/mcp/tools/graph-schemas.js.map +1 -0
- package/dist/mcp/tools/graph.d.ts +19 -0
- package/dist/mcp/tools/graph.d.ts.map +1 -0
- package/dist/mcp/tools/graph.js +263 -0
- package/dist/mcp/tools/graph.js.map +1 -0
- package/dist/mcp/tools/incident.d.ts +2 -0
- package/dist/mcp/tools/incident.d.ts.map +1 -0
- package/dist/mcp/tools/incident.js +246 -0
- package/dist/mcp/tools/incident.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +38 -18
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js +74 -18
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/list-active-runs.d.ts +2 -0
- package/dist/mcp/tools/list-active-runs.d.ts.map +1 -0
- package/dist/mcp/tools/list-active-runs.js +35 -0
- package/dist/mcp/tools/list-active-runs.js.map +1 -0
- package/dist/mcp/tools/list-pending-approvals.d.ts +2 -0
- package/dist/mcp/tools/list-pending-approvals.d.ts.map +1 -0
- package/dist/mcp/tools/list-pending-approvals.js +40 -0
- package/dist/mcp/tools/list-pending-approvals.js.map +1 -0
- package/dist/mcp/tools/list-projects.d.ts +2 -0
- package/dist/mcp/tools/list-projects.d.ts.map +1 -0
- package/dist/mcp/tools/list-projects.js +101 -0
- package/dist/mcp/tools/list-projects.js.map +1 -0
- package/dist/mcp/tools/list-specs.d.ts +2 -0
- package/dist/mcp/tools/list-specs.d.ts.map +1 -0
- package/dist/mcp/tools/list-specs.js +48 -0
- package/dist/mcp/tools/list-specs.js.map +1 -0
- package/dist/mcp/tools/plan.d.ts.map +1 -1
- package/dist/mcp/tools/plan.js +40 -14
- package/dist/mcp/tools/plan.js.map +1 -1
- package/dist/mcp/tools/playbook.d.ts +2 -0
- package/dist/mcp/tools/playbook.d.ts.map +1 -0
- package/dist/mcp/tools/playbook.js +104 -0
- package/dist/mcp/tools/playbook.js.map +1 -0
- package/dist/mcp/tools/postmortem.d.ts +2 -0
- package/dist/mcp/tools/postmortem.d.ts.map +1 -0
- package/dist/mcp/tools/postmortem.js +75 -0
- package/dist/mcp/tools/postmortem.js.map +1 -0
- package/dist/mcp/tools/react.js +1 -1
- package/dist/mcp/tools/react.js.map +1 -1
- package/dist/mcp/tools/reject-checkpoint.d.ts +2 -0
- package/dist/mcp/tools/reject-checkpoint.d.ts.map +1 -0
- package/dist/mcp/tools/reject-checkpoint.js +79 -0
- package/dist/mcp/tools/reject-checkpoint.js.map +1 -0
- package/dist/mcp/tools/rollback.d.ts +2 -0
- package/dist/mcp/tools/rollback.d.ts.map +1 -0
- package/dist/mcp/tools/rollback.js +78 -0
- package/dist/mcp/tools/rollback.js.map +1 -0
- package/dist/mcp/tools/run-in-worktree.d.ts +2 -0
- package/dist/mcp/tools/run-in-worktree.d.ts.map +1 -0
- package/dist/mcp/tools/run-in-worktree.js +90 -0
- package/dist/mcp/tools/run-in-worktree.js.map +1 -0
- package/dist/mcp/tools/run.js +1 -1
- package/dist/mcp/tools/run.js.map +1 -1
- package/dist/mcp/tools/solidity.js +1 -1
- package/dist/mcp/tools/solidity.js.map +1 -1
- package/dist/mcp/tools/sprint.d.ts.map +1 -1
- package/dist/mcp/tools/sprint.js +11 -11
- package/dist/mcp/tools/sprint.js.map +1 -1
- package/dist/mcp/tools/status.d.ts.map +1 -1
- package/dist/mcp/tools/status.js +11 -0
- package/dist/mcp/tools/status.js.map +1 -1
- package/dist/mcp/tools/subscribe-events.d.ts +2 -0
- package/dist/mcp/tools/subscribe-events.d.ts.map +1 -0
- package/dist/mcp/tools/subscribe-events.js +48 -0
- package/dist/mcp/tools/subscribe-events.js.map +1 -0
- package/dist/mcp/tools/unsubscribe-events.d.ts +2 -0
- package/dist/mcp/tools/unsubscribe-events.d.ts.map +1 -0
- package/dist/mcp/tools/unsubscribe-events.js +45 -0
- package/dist/mcp/tools/unsubscribe-events.js.map +1 -0
- package/dist/orchestrator/agent-loader.d.ts +16 -0
- package/dist/orchestrator/agent-loader.d.ts.map +1 -1
- package/dist/orchestrator/agent-loader.js +16 -0
- package/dist/orchestrator/agent-loader.js.map +1 -1
- package/dist/orchestrator/architect-agent.d.ts.map +1 -1
- package/dist/orchestrator/architect-agent.js +37 -8
- package/dist/orchestrator/architect-agent.js.map +1 -1
- package/dist/orchestrator/checkpoints/audit.d.ts +128 -0
- package/dist/orchestrator/checkpoints/audit.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/audit.js +272 -0
- package/dist/orchestrator/checkpoints/audit.js.map +1 -0
- package/dist/orchestrator/checkpoints/feedback-router.d.ts +213 -0
- package/dist/orchestrator/checkpoints/feedback-router.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/feedback-router.js +438 -0
- package/dist/orchestrator/checkpoints/feedback-router.js.map +1 -0
- package/dist/orchestrator/checkpoints/index.d.ts +11 -0
- package/dist/orchestrator/checkpoints/index.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/index.js +12 -0
- package/dist/orchestrator/checkpoints/index.js.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/cli.d.ts +35 -0
- package/dist/orchestrator/checkpoints/mechanisms/cli.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/cli.js +153 -0
- package/dist/orchestrator/checkpoints/mechanisms/cli.js.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/disk.d.ts +34 -0
- package/dist/orchestrator/checkpoints/mechanisms/disk.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/disk.js +139 -0
- package/dist/orchestrator/checkpoints/mechanisms/disk.js.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/pr.d.ts +141 -0
- package/dist/orchestrator/checkpoints/mechanisms/pr.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/mechanisms/pr.js +445 -0
- package/dist/orchestrator/checkpoints/mechanisms/pr.js.map +1 -0
- package/dist/orchestrator/checkpoints/noop.d.ts +12 -0
- package/dist/orchestrator/checkpoints/noop.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/noop.js +13 -0
- package/dist/orchestrator/checkpoints/noop.js.map +1 -0
- package/dist/orchestrator/checkpoints/registry.d.ts +48 -0
- package/dist/orchestrator/checkpoints/registry.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/registry.js +89 -0
- package/dist/orchestrator/checkpoints/registry.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/_util.d.ts +50 -0
- package/dist/orchestrator/checkpoints/renderers/_util.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/_util.js +137 -0
- package/dist/orchestrator/checkpoints/renderers/_util.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/code-review.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/code-review.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/code-review.js +66 -0
- package/dist/orchestrator/checkpoints/renderers/code-review.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/curator-briefing.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/curator-briefing.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/curator-briefing.js +40 -0
- package/dist/orchestrator/checkpoints/renderers/curator-briefing.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/eval-result.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/eval-result.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/eval-result.js +54 -0
- package/dist/orchestrator/checkpoints/renderers/eval-result.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/generator-diff.d.ts +49 -0
- package/dist/orchestrator/checkpoints/renderers/generator-diff.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/generator-diff.js +154 -0
- package/dist/orchestrator/checkpoints/renderers/generator-diff.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/pipeline-summary.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/pipeline-summary.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/pipeline-summary.js +59 -0
- package/dist/orchestrator/checkpoints/renderers/pipeline-summary.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/plan.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/plan.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/plan.js +34 -0
- package/dist/orchestrator/checkpoints/renderers/plan.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/registry.d.ts +43 -0
- package/dist/orchestrator/checkpoints/renderers/registry.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/registry.js +83 -0
- package/dist/orchestrator/checkpoints/renderers/registry.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/research.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/research.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/research.js +39 -0
- package/dist/orchestrator/checkpoints/renderers/research.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-contract.d.ts +20 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-contract.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-contract.js +57 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-contract.js.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-summary.d.ts +15 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-summary.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-summary.js +38 -0
- package/dist/orchestrator/checkpoints/renderers/sprint-summary.js.map +1 -0
- package/dist/orchestrator/checkpoints/sites.d.ts +22 -0
- package/dist/orchestrator/checkpoints/sites.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/sites.js +57 -0
- package/dist/orchestrator/checkpoints/sites.js.map +1 -0
- package/dist/orchestrator/checkpoints/types.d.ts +51 -0
- package/dist/orchestrator/checkpoints/types.d.ts.map +1 -0
- package/dist/orchestrator/checkpoints/types.js +9 -0
- package/dist/orchestrator/checkpoints/types.js.map +1 -0
- package/dist/orchestrator/code-reviewer-agent.d.ts +50 -0
- package/dist/orchestrator/code-reviewer-agent.d.ts.map +1 -0
- package/dist/orchestrator/code-reviewer-agent.js +283 -0
- package/dist/orchestrator/code-reviewer-agent.js.map +1 -0
- package/dist/orchestrator/context-handoff.d.ts +484 -224
- package/dist/orchestrator/context-handoff.d.ts.map +1 -1
- package/dist/orchestrator/context-handoff.js +32 -12
- package/dist/orchestrator/context-handoff.js.map +1 -1
- package/dist/orchestrator/curator-agent.d.ts.map +1 -1
- package/dist/orchestrator/curator-agent.js +63 -12
- package/dist/orchestrator/curator-agent.js.map +1 -1
- package/dist/orchestrator/deploy/classify.d.ts +31 -0
- package/dist/orchestrator/deploy/classify.d.ts.map +1 -0
- package/dist/orchestrator/deploy/classify.js +109 -0
- package/dist/orchestrator/deploy/classify.js.map +1 -0
- package/dist/orchestrator/deploy/execute.d.ts +45 -0
- package/dist/orchestrator/deploy/execute.d.ts.map +1 -0
- package/dist/orchestrator/deploy/execute.js +146 -0
- package/dist/orchestrator/deploy/execute.js.map +1 -0
- package/dist/orchestrator/deploy/executor.d.ts +22 -0
- package/dist/orchestrator/deploy/executor.d.ts.map +1 -0
- package/dist/orchestrator/deploy/executor.js +31 -0
- package/dist/orchestrator/deploy/executor.js.map +1 -0
- package/dist/orchestrator/deploy/index.d.ts +21 -0
- package/dist/orchestrator/deploy/index.d.ts.map +1 -0
- package/dist/orchestrator/deploy/index.js +21 -0
- package/dist/orchestrator/deploy/index.js.map +1 -0
- package/dist/orchestrator/deploy/resolve.d.ts +51 -0
- package/dist/orchestrator/deploy/resolve.d.ts.map +1 -0
- package/dist/orchestrator/deploy/resolve.js +53 -0
- package/dist/orchestrator/deploy/resolve.js.map +1 -0
- package/dist/orchestrator/deploy/spawn.d.ts +60 -0
- package/dist/orchestrator/deploy/spawn.d.ts.map +1 -0
- package/dist/orchestrator/deploy/spawn.js +62 -0
- package/dist/orchestrator/deploy/spawn.js.map +1 -0
- package/dist/orchestrator/deploy/types.d.ts +98 -0
- package/dist/orchestrator/deploy/types.d.ts.map +1 -0
- package/dist/orchestrator/deploy/types.js +39 -0
- package/dist/orchestrator/deploy/types.js.map +1 -0
- package/dist/orchestrator/evaluator-agent.d.ts.map +1 -1
- package/dist/orchestrator/evaluator-agent.js +23 -10
- package/dist/orchestrator/evaluator-agent.js.map +1 -1
- package/dist/orchestrator/generator-agent.d.ts.map +1 -1
- package/dist/orchestrator/generator-agent.js +24 -11
- package/dist/orchestrator/generator-agent.js.map +1 -1
- package/dist/orchestrator/model-resolver.d.ts.map +1 -1
- package/dist/orchestrator/model-resolver.js +4 -2
- package/dist/orchestrator/model-resolver.js.map +1 -1
- package/dist/orchestrator/observability/index.d.ts +12 -0
- package/dist/orchestrator/observability/index.d.ts.map +1 -0
- package/dist/orchestrator/observability/index.js +12 -0
- package/dist/orchestrator/observability/index.js.map +1 -0
- package/dist/orchestrator/observability/merge.d.ts +73 -0
- package/dist/orchestrator/observability/merge.d.ts.map +1 -0
- package/dist/orchestrator/observability/merge.js +110 -0
- package/dist/orchestrator/observability/merge.js.map +1 -0
- package/dist/orchestrator/pipeline.d.ts +28 -0
- package/dist/orchestrator/pipeline.d.ts.map +1 -1
- package/dist/orchestrator/pipeline.js +223 -30
- package/dist/orchestrator/pipeline.js.map +1 -1
- package/dist/orchestrator/planner-agent.d.ts +21 -1
- package/dist/orchestrator/planner-agent.d.ts.map +1 -1
- package/dist/orchestrator/planner-agent.js +16 -6
- package/dist/orchestrator/planner-agent.js.map +1 -1
- package/dist/orchestrator/research-agent.d.ts.map +1 -1
- package/dist/orchestrator/research-agent.js +46 -9
- package/dist/orchestrator/research-agent.js.map +1 -1
- package/dist/orchestrator/tools/handlers.d.ts +2 -0
- package/dist/orchestrator/tools/handlers.d.ts.map +1 -1
- package/dist/orchestrator/tools/handlers.js +1 -1
- package/dist/orchestrator/tools/handlers.js.map +1 -1
- package/dist/orchestrator/tools/index.d.ts +84 -1
- package/dist/orchestrator/tools/index.d.ts.map +1 -1
- package/dist/orchestrator/tools/index.js +164 -1
- package/dist/orchestrator/tools/index.js.map +1 -1
- package/dist/orchestrator/worktree.d.ts +18 -0
- package/dist/orchestrator/worktree.d.ts.map +1 -0
- package/dist/orchestrator/worktree.js +129 -0
- package/dist/orchestrator/worktree.js.map +1 -0
- package/dist/providers/anthropic.d.ts +8 -1
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +86 -5
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +35 -2
- package/dist/providers/factory.js.map +1 -1
- package/dist/providers/google.d.ts.map +1 -1
- package/dist/providers/google.js +5 -0
- package/dist/providers/google.js.map +1 -1
- package/dist/providers/index.d.ts +1 -1
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/openai.d.ts.map +1 -1
- package/dist/providers/openai.js +4 -0
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/types.d.ts +25 -2
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/state/approval-state.d.ts +74 -0
- package/dist/state/approval-state.d.ts.map +1 -0
- package/dist/state/approval-state.js +127 -0
- package/dist/state/approval-state.js.map +1 -0
- package/dist/state/history.d.ts.map +1 -1
- package/dist/state/history.js +3 -3
- package/dist/state/history.js.map +1 -1
- package/dist/state/index.d.ts +3 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +4 -1
- package/dist/state/index.js.map +1 -1
- package/dist/state/plan-state.js +1 -1
- package/dist/state/plan-state.js.map +1 -1
- package/dist/state/review-state.d.ts +15 -0
- package/dist/state/review-state.d.ts.map +1 -0
- package/dist/state/review-state.js +51 -0
- package/dist/state/review-state.js.map +1 -0
- package/dist/state/run-state.d.ts +39 -0
- package/dist/state/run-state.d.ts.map +1 -0
- package/dist/state/run-state.js +101 -0
- package/dist/state/run-state.js.map +1 -0
- package/dist/state/sprint-state.d.ts +9 -2
- package/dist/state/sprint-state.d.ts.map +1 -1
- package/dist/state/sprint-state.js +25 -11
- package/dist/state/sprint-state.js.map +1 -1
- package/dist/telemetry/emit.d.ts +41 -0
- package/dist/telemetry/emit.d.ts.map +1 -0
- package/dist/telemetry/emit.js +65 -0
- package/dist/telemetry/emit.js.map +1 -0
- package/dist/utils/git.d.ts +27 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +50 -0
- package/dist/utils/git.js.map +1 -1
- package/hooks/hooks.json +17 -1
- package/hooks/session-start +42 -0
- package/package.json +6 -2
- package/scripts/check-prereqs.sh +12 -0
- package/scripts/e2e-graph-smoke.sh +167 -0
- package/scripts/graph-hook.mjs +151 -0
- package/scripts/migrate-specs.mjs +127 -0
- package/scripts/run-kpi-gate.mjs +245 -0
- package/scripts/sync-skills.mjs +99 -0
- package/skills/bober.code-review/SKILL.md +186 -0
- package/skills/bober.debug/SKILL.md +300 -0
- package/skills/bober.deploy/SKILL.md +262 -0
- package/skills/bober.diagnose/SKILL.md +254 -0
- package/skills/bober.graph/SKILL.md +85 -0
- package/skills/bober.impact/SKILL.md +101 -0
- package/skills/bober.incident/SKILL.md +245 -0
- package/skills/bober.onboard/SKILL.md +84 -0
- package/skills/bober.plan/SKILL.md +51 -0
- package/skills/bober.plan/references/spec-schema.md +31 -4
- package/skills/bober.postmortem/SKILL.md +231 -0
- package/skills/bober.run/SKILL.md +41 -7
- package/skills/bober.runbook/SKILL.md +335 -0
- package/skills/bober.sprint/SKILL.md +6 -259
- package/skills/bober.using-bober/SKILL.md +133 -0
- 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
|
|
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
|
-
|
|
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
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|