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