# domainCheck Ops Playbook Contract ## 1. 目标 这份文档用于冻结 `playbook catalog / preview / run / events` 的正式 contract。 这层的定位不是“页面里的一个弹窗”,而是: - 控制面的正式编排对象 - 海外 Codex 驾驶员可消费的标准作业对象 - Driver / Runbook / Release / Inspection 之间的统一中间层 核心原则: - 一次标准编排 = 一次 `playbook run` - 页面、CLI、Codex 必须共用同一份 `playbook` / `playbook run` 结构 - `playbook run` 只负责创建与聚合正式 `ops job` - 不允许前端再把“标准巡检 / 接管验收 / 现场日志”退回成零散按钮逻辑 建议与 [ops_job_contract.md](/www/wwwroot/getDomain/docs/schemas/ops_job_contract.md:1) 配套阅读。 --- ## 2. 当前接口面 当前已落地的主入口: - `GET /api/v1/ops/playbooks` - `POST /api/v1/ops/playbooks/preview` - `POST /api/v1/ops/playbooks/execute` - `GET /api/v1/ops/playbook-runs` - `GET /api/v1/ops/playbook-runs/{run_code}` - `GET /api/v1/ops/playbook-runs/{run_code}/events` - `POST /api/v1/ops/playbook-runs/{run_code}/rerun` - `POST /api/v1/ops/playbook-runs/{run_code}/cancel` 并且这层已经被以下入口复用: - `driver action -> open_playbook_dialog` - `runbook sequence -> secondary_resolution` - `inspection` - `activity-stream` 所以后续不应再新造第四套“标准作业对象”。 --- ## 3. Playbook Catalog Object 来源: - `GET /api/v1/ops/playbooks` - `preview / execute` 返回体中的 `playbook` 最小字段: ```json { "key": "inspection.standard", "group_key": "diagnostics", "group_title": "标准巡检", "title": "标准巡检", "description": "按 健康快照 -> Worker 日志 -> 诊断包 的顺序,对目标节点做一次标准联调巡检。", "target_scope": "node-set", "default_execution_mode": "remote-agent", "default_execution_mode_label": "Node Agent", "execution_modes": [ "remote-agent", "ssh" ], "execution_mode_options": [ { "value": "remote-agent", "label": "Node Agent", "is_default": true }, { "value": "ssh", "label": "SSH", "is_default": false } ], "default_auto_approve": true, "stop_on_failure": true, "steps": [ { "step_key": "health", "title": "采集健康快照", "template_key": "health.snapshot", "payload": {} } ] } ``` 正式约束: - `key` - 是 Playbook 的稳定主键 - `group_key` - 用于页面、CLI、Codex 做标准分组,不应用 `title` 猜 - `execution_modes` - 是能力白名单,不是建议文案 - `stop_on_failure` - 是编排级行为,不是某一步骤的临时说明 --- ## 4. Playbook Preview Contract 来源: - `POST /api/v1/ops/playbooks/preview` 最小请求体: ```json { "playbook_key": "inspection.standard", "node_codes": [ "mainland-worker-01" ], "execution_mode": "remote-agent", "auto_approve": true, "requested_by": "web-ui" } ``` 最小返回体: ```json { "playbook": {}, "requested_by": "web-ui", "execution_mode": "remote-agent", "execution_mode_label": "Node Agent", "auto_approve": true, "target_nodes_total": 1, "target_node_codes": [ "mainland-worker-01" ], "step_count": 3, "expected_jobs_total": 3, "template_keys": [ "health.snapshot", "logs.collect", "diagnostics.collect" ], "steps": [ { "order": 1, "step_key": "health", "title": "采集健康快照", "template_key": "health.snapshot", "action": "health.snapshot", "payload": {}, "execution_mode": "remote-agent", "execution_mode_label": "Node Agent", "auto_approve": true, "target_nodes_total": 1, "expected_jobs": 1 } ] } ``` 预览阶段必须回答: - 最终执行方式是什么 - 总共会展开多少步 - 每步会展开成什么模板 - 总共会生成多少个 `ops job` 这样页面、CLI、Codex 才能在执行前看见“这次会做什么”。 --- ## 5. Playbook Run Object 来源: - `GET /api/v1/ops/playbook-runs` - `GET /api/v1/ops/playbook-runs/{run_code}` - `POST /api/v1/ops/playbooks/execute` 最小字段: ```json { "run_code": "playbook-20260418-001", "playbook_key": "inspection.standard", "playbook_title": "标准巡检", "group_key": "diagnostics", "group_title": "标准巡检", "requested_by": "web-ui", "execution_mode": "remote-agent", "execution_mode_label": "Node Agent", "stop_on_failure": true, "step_count": 3, "expected_jobs_total": 3, "target_nodes_total": 1, "target_node_codes": [ "mainland-worker-01" ], "created_at": "2026-04-18 06:30:00", "updated_at": "2026-04-18 06:31:10", "status": "running", "status_label": "收口中", "status_counts": { "queued": 1, "running": 1, "success": 1 }, "jobs_total": 3, "success_jobs_total": 1, "terminal_jobs_total": 1, "completion_percent": 33.3, "steps_total": 3, "steps_success": 1, "steps_running": 1, "steps_problem": 0, "steps_terminal": 1, "focus_level": "warning", "focus_step_key": "worker_logs", "focus_step_title": "收集 Worker 日志", "focus_summary": "收集 Worker 日志 当前仍在执行,先等待回执或检查对应节点事件流。", "summary": "收集 Worker 日志 当前仍在执行,先等待回执或检查对应节点事件流。", "summary_text": "收集 Worker 日志 当前仍在执行,先等待回执或检查对应节点事件流。", "focus_ref": { "kind": "playbook_run", "run_code": "playbook-20260418-001", "playbook_key": "inspection.standard", "group_key": "diagnostics", "focus_step_key": "worker_logs", "focus_step_title": "收集 Worker 日志", "event_key": "", "node_code": "" }, "problem_steps": [], "active_steps": [], "latest_job": {}, "steps": [] } ``` 正式定义: > `playbook run` 是一轮标准编排在控制面的聚合对象,不是某一条单独任务。 也就是说: - `ops job` 是执行颗粒度 - `playbook run` 是观察、重跑、取消、钻取的编排颗粒度 --- ## 6. Playbook Step Object `playbook run.steps[]` 的最小结构: ```json { "step_key": "worker_logs", "title": "收集 Worker 日志", "template_key": "logs.collect", "order": 2, "jobs_total": 1, "nodes_total": 1, "target_node_codes": [ "mainland-worker-01" ], "status_counts": { "running": 1 }, "terminal_jobs_total": 0, "success_jobs_total": 0, "status": "running", "status_label": "收口中", "completion_percent": 0.0, "summary": "收集 Worker 日志 当前处于执行中,可继续观察该步骤事件。", "summary_text": "收集 Worker 日志 当前处于执行中,可继续观察该步骤事件。", "focus_ref": { "kind": "playbook_run", "run_code": "playbook-20260418-001", "playbook_key": "inspection.standard", "group_key": "diagnostics", "focus_step_key": "worker_logs", "focus_step_title": "收集 Worker 日志", "event_key": "", "node_code": "" }, "latest_job": {} } ``` 推荐 step 状态: - `queued` - `running` - `success` - `attention` 规则: - 只要该步骤出现失败、阻断、取消等终态问题,应收口为 `attention` - 页面与 Codex 都应优先盯 `problem_steps / active_steps`,而不是自己遍历所有子任务推断 --- ## 7. Playbook Event Stream 来源: - `GET /api/v1/ops/playbook-runs/{run_code}/events` 最小返回体: ```json { "run_code": "playbook-20260418-001", "playbook_run": {}, "events": [ { "job_id": 123, "job_code": "ops-20260418-123", "run_code": "playbook-20260418-001", "job_status": "running", "job_status_label": "收口中", "action": "logs.collect", "target_node_code": "mainland-worker-01", "step_key": "worker_logs", "step_title": "收集 Worker 日志", "event_type": "job_running", "level": "info", "level_label": "信息", "message": "开始收集 Worker 日志", "summary": "开始收集 Worker 日志", "summary_text": "开始收集 Worker 日志", "payload": {}, "event_key": "job-event:1001", "occurred_at": "2026-04-18 06:31:00", "focus_ref": { "kind": "playbook_run", "run_code": "playbook-20260418-001", "playbook_key": "inspection.standard", "group_key": "diagnostics", "focus_step_key": "worker_logs", "focus_step_title": "收集 Worker 日志", "event_key": "job-event:1001", "node_code": "mainland-worker-01" }, "created_at": "2026-04-18 06:31:00" } ], "summary": { "total": 1, "returned_total": 1, "available_step_counts": { "worker_logs": 1 }, "available_node_counts": { "mainland-worker-01": 1 }, "level_counts": { "info": 1 }, "event_type_counts": { "job_running": 1 }, "job_status_counts": { "running": 1 }, "latest_at": "2026-04-18 06:31:00", "filters": { "step_key": "", "node_code": "", "limit": 80 } } } ``` 这层必须支持: - 按 `step_key` 过滤 - 按 `node_code` 过滤 - 快速看到最近活动时间 否则 `playbook run` 只能看总览,不能真正钻取。 --- ## 8. 正式 Playbook Key 语义 当前最值得冻结成正式对象的 key: ### 8.1 `onboarding.bootstrap` 定位: - 生成节点接入工单 执行方式: - 仅 `control-plane` 正式语义: - 不直接接管节点 - 只创建标准接入方案对象 ### 8.2 `onboarding.acceptance` 定位: - 新节点接管后标准验收 当前标准步骤: 1. `health.snapshot` 2. `service.status(node-agent)` 3. `logs.collect(node-agent)` 4. `service.status(worker)` 5. `logs.collect(worker)` ### 8.3 `inspection.standard` 定位: - 标准巡检 当前标准步骤: 1. `health.snapshot` 2. `logs.collect(worker)` 3. `diagnostics.collect` 正式要求: - 这是 release / rollout 之前最核心的健康观察面 ### 8.4 `scene.logs.key` 定位: - 关键现场日志样本 正式要求: - 默认比 `scene.logs.full` 更轻 - 适合先看现场,再决定是否升级取证 ### 8.5 `scene.logs.full` 定位: - 全量现场取证 正式要求: - 应明确比 `scene.logs.key` 更重 - 默认应同时补诊断包 ### 8.6 `scene.diagnostics` 定位: - 轻量诊断包 正式要求: - 适合作为参与节点的常规取证动作 --- ## 9. 执行模式 Contract 推荐模式: - `remote-agent` - `ssh` - `control-plane` 正式约束: - `remote-agent` - 正式日常运维默认模式 - `ssh` - 仅用于首发接管与应急救援 - `control-plane` - 只适合控制面本地对象生成或极少量控制面动作 页面、CLI、Codex 不能自己发明第四种临时模式。 --- ## 10. Playbook Run 状态机 推荐状态: - `queued` - `running` - `success` - `attention` 含义: - `queued` - 子任务刚创建,尚未出现有效执行推进 - `running` - 已有子任务进入 `dispatching / running / awaiting_approval` - `success` - 全部子任务收口成功 - `attention` - 任一步骤出现失败、阻断、取消或部分成功,需要人工关注 正式规则: - 页面上的“标准巡检状态” - `activity-stream` 中的 playbook run 摘要 - Driver / Codex 的推荐动作 都必须共用这一套状态语义。 --- ## 11. 与 Driver / Runbook / Release 的关系 正式收口规则: - Driver 不直接“模拟巡检” - 应优先跳转或创建 `playbook run` - Runbook Sequence 不直接展开 shell - 应优先收口到 `driver action` 或 `playbook` - Release / Rollout 不自己维护另一套巡检摘要 - 应优先消费 `inspection.standard` 的最近结果 也就是说: - `scene` 是现场观察对象 - `inspection` 是标准健康对象 - `release / rollout` 是发布对象 三者不能再各自维护不同的“日志 / 诊断 / 巡检”定义。 --- ## 12. 正式要求 后续继续演进时,必须保持: 1. `playbook catalog` - 是稳定 contract,而不是页面枚举 2. `playbook preview` - 是执行前的唯一结构化预览面 3. `playbook run` - 是页面、CLI、Codex 共同观察的一轮编排对象 4. `playbook events` - 是整轮编排的钻取视角 5. 接管验收、标准巡检、现场观察 - 优先都收进 `playbook` 这样这套编排才能成为真正的正式平台能力,而不是一组“看起来像流程”的按钮。