327 lines
46 KiB
Markdown
327 lines
46 KiB
Markdown
# Code Queue 指挥监督策略
|
||
|
||
本文定义在人工或 lead-agent 指挥官监督下,把 Code Queue 作为并行交付基础设施使用的长期运行模型。本文是协同策略,不替代 `docs/reference/microservices.md`、`docs/reference/observability.md`、`docs/reference/user-service-delivery.md` 或 Code Queue runtime 合同。
|
||
|
||
## 范围
|
||
|
||
当一个交付目标过大,无法由单个 Code Queue 任务完成,并且必须拆分到多个队列、服务或基础设施 lane 时,使用本策略。
|
||
|
||
本策略适用于:
|
||
|
||
- 用户服务 CI/CD 推广;
|
||
- 需要多个隔离 worktree 的跨服务修复;
|
||
- 用户服务开发过程中暴露出来的基础设施缺陷;
|
||
- 后续验证、retry、验收和任务接力协调;
|
||
- 指挥官为了保持 Code Queue 任务推进而做的手动监督工作,但不接管 worker 的具体实现。
|
||
|
||
本文不授权绕过正常部署、Git 或生产安全规则。
|
||
|
||
## 运行原则
|
||
|
||
指挥官对最终结果负责,Code Queue task 对边界明确的执行负责。
|
||
|
||
指挥官应维护交付目标、活跃队列、阻塞点、证据缺口和下一步恢复动作的实时地图。Code Queue worker 应收到自包含 prompt,prompt 中必须有足够上下文,不能依赖 GitHub issue 可见性或聊天历史。
|
||
|
||
集中指挥的目标是提升交付吞吐和可用性,而不是把每个缺陷都变成一次性的人工修补。
|
||
|
||
指挥官的最终目标是推动整体开发波次持续前进:跟踪队列进展、及时纠偏、审查完成质量,并安排下一轮任务,让交付计划持续复利式推进,而不是一批任务结束后停滞。
|
||
|
||
## 任务设计
|
||
|
||
每个 Code Queue task 都必须有清晰且狭窄的 ownership 边界。
|
||
|
||
- 尽量每个任务只负责一个服务、模块或基础设施缺陷。
|
||
- 每个任务使用共享 workspace 下自己的 detached worktree。
|
||
- 在 prompt 中直接写明写入范围、验证范围、提交/推送要求和禁止动作。
|
||
- 相关背景必须写进 prompt;issue 链接只能作为辅助引用,不能作为必要上下文。
|
||
- 优先复用已有队列;只有现有 lane 无法表达 ownership 边界时,才创建新队列。
|
||
- 队列并发必须受真实执行能力约束。通常目标是约 5 条并发 lane;当活跃任务写入范围彼此独立、heartbeat/trace 证据健康、成功率可接受时,指挥官可以把并发提高到约 10。若完成质量下降,应先降并发再继续扩张。
|
||
|
||
靠近生产的任务 prompt 必须明确禁止在 master server 上跑已知可能 OOM 的重型本地检查,并说明哪些验证应在 D601 CI、dev env 或目标服务容器中执行。
|
||
|
||
当一个指挥机需要突发创建大量 Code Queue 任务时,submit 默认应串行或接近串行。为了避免控制面在确认任务前被打爆,可以使用短本地锁或短延迟,尤其是在低内存主机上。目标是保持任务创建可观测且稳定,而不是最大化瞬时入队吞吐。
|
||
|
||
## 模型和成本路由
|
||
|
||
Code Queue 派单模型按成本、可信度和 blast radius 分层:GPT-5.5/Codex 处理高风险和复杂任务,DeepSeek/OpenCode 处理中等复杂度且边界清晰的任务,MiniMax/OpenCode 处理简单、低权限、可复核任务,生产重启、密钥、数据库手工写入和运行中任务控制保留给指挥官或人工。
|
||
|
||
当前提交合同由 `bun scripts/cli.ts codex submit` 暴露:prompt 必须来自位置参数、`--prompt-file` 或 `--prompt-stdin`;可选字段包括 `--queue/--queue-id`、`--provider-id/--provider`、`--cwd/--workdir`、`--model`、`--reasoning-effort`、`--execution-mode/--mode`、`--max-attempts` 和 `--reference-task-id/--reference/--ref`。这些字段写入任务 payload 后由 `code-queue-mgr` 入 PostgreSQL,核心任务字段包括 `queue_id`、`provider_id`、`execution_mode`、`model`、`cwd`、`prompt/base_prompt`、`reference_task_ids`、`reasoning_effort`、`max_attempts` 和 `task_json`;队列记录至少有 `id/name/created_at/updated_at`。模型治理应优先看任务 payload 和数据库字段,不靠 worker final response 自报。
|
||
|
||
运行态默认模型仍是 `gpt-5.5`。`CODE_QUEUE_MODELS` 当前长期合同至少包含 GPT-5.5、GPT-5.4、GPT-5.4 Mini、DeepSeek Chat 和 MiniMax M2.7;`deepseek`/`deepseek-chat` 与 `minimax-m2.7` 会走 OpenCode port,其余模型走 Codex port。只有当执行面 `/health` 或等价配置已经显示 DeepSeek 模型可用、并完成轻量 runner smoke 后,才允许真实提交 `--model deepseek-chat`。
|
||
|
||
`codex submit --dry-run` 是派单前的轻量 preflight。它输出 `routingRecommendation`、`policyContract` 和模型注册表,帮助指挥官看到推荐 runner/model、风险信号、缺失的 prompt guard、模型分层、并发上限、`opencodeModels` 和 `modelPorts`;它不会修改真实提交 payload,也不会替代指挥官判断。真实派单是否使用 `--model minimax-m2.7`、`--model deepseek-chat` 或 `--model gpt-5.5` 仍由指挥官显式决定。
|
||
|
||
并发治理按模型和风险一起决定。GPT-5.5 常规并发目标是 5 条 lane;当写入范围互不重叠、heartbeat/trace 健康、完成质量稳定时可以短时提高到 10。MiniMax 只承接简单任务时可以提高到 10,但必须保留指挥官审阅和证据核验。DeepSeek 用于中等复杂度任务,默认按约 5 条 lane 观察质量,再根据成功率和 reviewer 负载逐步调整。并发扩张的前提永远是任务质量和可观测性,而不是模型价格。
|
||
|
||
模型选择矩阵:
|
||
|
||
| 首选模型 | 适用任务 | 必须满足 | 禁止下放 |
|
||
| --- | --- | --- | --- |
|
||
| GPT-5.5/Codex | 高风险、复杂、跨模块、运行态、CI/CD、release、deploy、安全、最终质量裁决 | 多信号诊断、可回滚边界、必要的轻量或 dev 验证 | 不因成本把运行态和生产风险降级 |
|
||
| DeepSeek/OpenCode | 中等复杂度的前端功能、局部用户服务模块、局部 CLI/helper、明确 contract guard 或 unit test | prompt 自包含、写入范围窄、无生产/密钥/DB 写入、验证命令明确、指挥官审阅 | 不处理 Code Queue runtime、backend-core、provider-gateway、k3sctl-adapter、release/v1 或部署变更 |
|
||
| MiniMax/OpenCode | 只读调查、文档、简单前端/样式、低风险样板、轻量 dry-run/preflight 和小范围测试补齐 | issue 只作辅助引用、必须给出 diff/路径/命令证据、完成后保持未读待审 | 不处理共享核心、隐式远端状态、生产、密钥、DB、重启、复杂 bug 或最终裁决 |
|
||
| 指挥官/人工 | 真实生产动作、运行中任务控制、密钥/数据库/破坏性 Git、批量已读和高风险恢复 | 用户授权、只读诊断、恢复方案、记录 issue/#20/#24 | 不把执行权交给普通 worker |
|
||
|
||
外部 token provider、模型 API 和上游服务限流遵循本文监控章节的退避规则;`policyContract.externalProvider429` 只是把同一规则暴露给 dry-run 调度判断。
|
||
|
||
MiniMax/OpenCode 可承担任务必须同时满足这些条件:
|
||
|
||
| 类型 | 适用边界 | 必须证据 | 不可越界 |
|
||
| --- | --- | --- | --- |
|
||
| 只读调查 | 查找文件、梳理现有实现、列出候选入口、对比文档口径 | 文件路径、行号、命令输出摘要 | 不得把 issue 内容当唯一输入,不得声称读取了无法验证的远端状态 |
|
||
| 中文文档初稿或长期参考补丁 | `docs/reference/`、`AGENTS.md` 索引、一句话摘要、表格治理规则 | diff、文档位置、轻量格式/grep 检查 | 不写流水账,不改 release/v1 runtime |
|
||
| 轻量 CLI dry-run/preflight | 只读或 dry-run 输出、contract test、参数校验、错误分类 | dry-run JSON、contract test、`bun` 脚本验证 | 不改 runtime 调度核心,不触碰生产服务 |
|
||
| 局部测试补齐 | 单文件或小范围 contract/unit test,覆盖明确回归 | 测试命令、失败前提、通过输出 | 不跑 heavy check、E2E、Playwright |
|
||
| 小范围样板代码 | 非共享核心、可快速 review、可用类型检查或 dry-run 验证 | 修改文件、轻量类型/脚本验证、commit | 不跨多服务,不改凭证、网络、部署或数据库 |
|
||
| 数据整理和看板候选草案 | 生成 #20/#24 更新草案、任务表、验收 checklist | 草案 diff、来源列表、人工待审标记 | 不直接替代指挥官审阅,不自动清空未读任务 |
|
||
|
||
GPT-5.5/Codex 必须承担这些任务:
|
||
|
||
| 类型 | 原因 | 验收重点 |
|
||
| --- | --- | --- |
|
||
| Code Queue/backend-core/provider-gateway/k3sctl-adapter 运行态修复 | 运行面错误会影响调度、观测和恢复路径,MiniMax 误判成本高 | 多信号诊断、轻量 contract、必要时 dev 验证;不隐式 prod rollout |
|
||
| 跨模块架构或共享契约调整 | 需要理解系统边界、兼容性和长期演进 | 文档、代码、测试和回滚边界一致 |
|
||
| CI/CD、artifact、deploy、release/v1 治理 | 易影响发布真相和稳定维护线 | dry-run/plan、commit-pinned 证据、release governance 一致 |
|
||
| 安全、凭证、网络、egress/proxy 变更 | 涉及 secret 泄漏、访问路径和外部服务 | 不输出 token,最小权限,结构化失败 |
|
||
| 复杂 bug 修复和最终质量裁决 | 需要辨别不完整证据、伪造、隐藏失败 | trace/output/commit/test 交叉验证 |
|
||
| 生产部署方案设计或回滚方案 | 生产 blast radius 高,即使只写方案也需高可信推理 | 明确非目标、授权点、验证和回滚 |
|
||
|
||
只能由人工或指挥官处理的任务包括:真实生产重启、Code Queue backend 重建、运行中任务 interrupt/cancel、密钥读取或轮换、数据库手工写入、破坏性 Git 操作、强制回滚、把完成未读任务批量标记已读、以及任何需要用户授权的高风险恢复动作。这类任务可以让 worker 起草方案或 checklist,但执行权不下放给 MiniMax,也不应下放给普通 GPT worker,除非用户明确授权并给出边界。
|
||
|
||
MiniMax prompt 必须自包含:目标、背景、写入范围、禁止动作、验证命令、final response 字段都要写进 prompt;GitHub issue 只能作为辅助引用,不能作为唯一来源。禁止使用“读取 issue 后按里面做”这类 prompt。若确实需要 issue 内容,指挥官先把关键需求、约束和验收点摘入 prompt,再附 issue URL。
|
||
|
||
MiniMax 风险控制必须固定包含:禁止 prod/重启/密钥/DB 写入;禁止 release/v1 runtime 修改;禁止 heavy check/E2E/Playwright,除非任务明确改为 GPT-5.5 且用户授权;必须给出可验证证据,包括修改文件、命令、测试输出、commit 和未覆盖风险;完成后保持未读,由指挥官用 `codex task <taskId>` 审阅后再单独 `codex read <taskId>`。
|
||
|
||
对 MiniMax 的验收不能看 final response 自述。指挥官至少核验 diff、commit 是否在声明目标分支可 fetch、轻量验证命令是否真实存在、输出是否和任务范围匹配;遇到推测、遗漏、伪造证据或把失败写成成功时,先拆成更小任务或改派 GPT-5.5。
|
||
|
||
## GitHub Issue 和 PR 使用
|
||
|
||
GitHub issue 是长期需求、缺陷、阻塞和决策的 source of record。聊天上下文、Code Queue final response 和指挥简报可以帮助恢复现场,但不能替代 issue 中的可检索记录。指挥简报自身也按 issue 主体维护:#24 是兼容的长期入口,每日滚动简报可以使用标题形如 `YYYY-MM-DD 指挥简报(北京时间)` 的独立 issue。简报更新只改 issue 正文,不在评论区追加,且所有时间统一使用北京时间。
|
||
|
||
指挥官应在以下情况创建或更新 GitHub issue:
|
||
|
||
- 新需求需要跨多个 Code Queue task、跨服务或跨部署阶段推进;
|
||
- 运行中发现可复用的基础设施缺陷,例如 CLI 能力缺口、凭证注入缺口、runner 局部观测误导、部署路径不可达;
|
||
- 任务完成但缺少远端 commit、live verification、dev/prod 部署证据等验收闭环;
|
||
- 某个手动临时绕行暴露出长期产品化需求;
|
||
- 战略、流程、发布线或 CI/CD 规则发生需要后续任务遵循的决策。
|
||
|
||
issue 内容必须自包含,至少写清楚背景、外部收益、当前观察、需求范围、非目标、验收标准和关联任务。不要只贴聊天摘要或只写“见某任务”;Code Queue worker 可能看不到 issue,也可能无法访问完整历史,因此 issue 是人类和指挥官恢复全局态势的记录,不是 worker prompt 的替代品。
|
||
|
||
如果某个 worker 任务需要依赖 GitHub issue 内容,但 runner 的 issue 可达性尚未被单独验证,指挥官不能默认 worker 已能读取该 issue。此时 worker prompt 必须直接内嵌完整需求、约束和验收点,issue URL 只能作为辅助引用。若要把 issue 作为任务输入源,先单独做可达性探测,再决定是否把 issue 作为常规前置条件。
|
||
|
||
GitHub issue/PR 操作应优先使用 UniDesk CLI 的安全入口:`bun scripts/cli.ts gh auth status`、`gh issue list/read/view/create/update/comment create/comment delete/close/reopen/scan-escape/cleanup-plan/board-audit/board-row list/board-row get/board-row update`、`gh pr list/read/view/create/update/comment create/comment delete/close/reopen`。该入口默认 repo 是 `pikasTech/unidesk`,支持 `--repo owner/name`,输出稳定 JSON,并把 `missing-binary`、`missing-token`、`auth-failed`、`network-proxy-failed`、`permission-denied`、`repo-not-found`、`repo-forbidden`、`issue-not-found`、`pr-not-found`、`scope-insufficient`、`validation-failed`、`invalid-response`、`unsupported-command` 等失败原因结构化。失败对象必须包含 `runnerDisposition=infra-blocked|business-failed`,runner 应用它区分基础设施阻塞和业务/参数失败。`gh issue list --state open --limit N --json number,title,state,url` 是有界 issue 发现入口,`--state` 只接受 `open|closed|all`,list 字段白名单是 `number,title,state,url,updatedAt,createdAt,author,labels`;未知 state 或未知字段必须失败,不能静默返回空数组。`gh issue read <number> --json body` 是 canonical 入口,正文仍应从 `.data.issue.body` 读取;`view` 只保留为兼容别名。未知 `--json` 字段必须失败,不得让调用方把空正文误判为读取成功。`gh issue scan-escape --limit N [--dry-run]` 与 `gh issue cleanup-plan` 只读扫描 issue body/comments 的字面量 `\n`、shell escape、短 body、blank/null body,输出 `classification=suspected-pollution|explanatory-mention|risk`、body/comment id、预览和清理建议;说明性提到 `\n` 不应被当成污染,cleanup-plan 永远不真实清理历史评论。`gh issue board-audit --board-issue 20 --limit N --dry-run` 只读对比 GitHub open/closed issue 列表与 #20 的 OPEN/CLOSED Markdown 表格,输出 `missingOpenIssues`、`closedInOpenRows`、`missingClosedRows`、`rowValidationWarnings`、`ignoredIssues` 和 `recommendedActions`。存在 Issue 列时,row key 优先来自 Issue cell 的主 Markdown issue link `/issues/<N>`,其次是开头 `#N`;主引用后的标题说明引用不触发多 issue 告警。没有 Issue 列的旧表格仍使用整行 fallback 并保留 `multiple-issue-references`。`相关 Code Queue 任务` 可用 `—`、`-` 或等价无任务占位表达无关联 task,但 branch、acceptance 和 progress 仍必须填写真实值;默认把 #20/#24 作为 known-meta 忽略,标题匹配 `YYYY-MM-DD 指挥简报(北京时间)` 的每日滚动简报由 #20 顶部指挥简报索引管理,并以 `reason=brief-index-managed` 进入 `ignoredIssues`,不进入 OPEN/CLOSED 覆盖审计。指挥官发现 #20 可能漏跟 open issue 或分表错误时,应先跑 board audit 取得结构化缺口,再人工审阅和编辑 #20,不要只靠 grep。显式 `gh issue update <number> --body-profile commander-brief` 可用于 #24 legacy 简报和每日滚动简报 issue;每日简报 issue 应用标题 `YYYY-MM-DD 指挥简报(北京时间)` 或在既有正文首行/关键 heading 中标明简报身份,且新正文必须包含 `## 常驻观察与长期建议`。对非简报 issue 使用该 profile 应失败为 `profile-issue-mismatch`。`gh issue board-row list --board-issue 20 --state open|closed|all` 和 `gh issue board-row get <issueNumber> --board-issue 20` 复用同一个 parser 读取表格行;`gh issue board-row update <issueNumber> --board-issue 20 --field progress|status|validation|branch|tasks|focus --value <text>` 只替换一行一个单元格,输出 old/new row、body SHA、body guard 和 request plan,且默认 dry-run,正式写入必须带 `--expect-body-sha` 或 `--expect-updated-at`。字段映射中 `status`/`validation` 都指向 `验收状态`,`tasks` 指向 `相关 Code Queue 任务`,`focus` 指向 `当前关注点`;单元格管道会转义、真实换行会折叠为空格,避免新增字面量 `\n`。`gh issue board-row upsert` 可更新既有行或按 section 生成完整新行;`board-row add/move/delete` 已支持行级新增、OPEN/CLOSED 迁移和删除,全部默认 dry-run,正式 PATCH 必须带 `--expect-body-sha` 或 `--expect-updated-at`。`gh pr list|read|view --json ...` 支持 `body,title,state,number,url,author,head,base,draft,createdAt,updatedAt` 字段白名单。issue/PR 创建、更新、评论、评论删除、关闭和重开使用 GitHub REST API;只要有 `GH_TOKEN` 或 `GITHUB_TOKEN`,就不依赖系统 `gh` binary。`gh` binary 只作为状态探测和 `gh auth token` fallback,不是写操作的主路径。GitHub 不支持 issue/PR 硬删除,`gh issue delete` 和 `gh pr delete` 必须结构化返回 `unsupported-command`;生命周期删除语义使用 `close`。`gh pr merge` 仍然不开放。
|
||
|
||
CLI 是短 shout 的需求原语,不是长驻服务器进程。CLI 功能不好用、兼容性不足、安全 guard 不够或输出不利于 runner/指挥官使用时,应默认创建 GitHub issue 并用 Code Queue 推进;这类 CLI 问题走 `master`、remote commit、轻量 contract test 和文档更新,不套用 backend-core、Code Queue runtime 这类运行态服务的重部署门禁。若 CLI 缺陷已经阻塞当前指挥,可以先做最小安全绕行,同时把长期修复写入 issue 并派单。
|
||
|
||
所有 GitHub Markdown 正文写入必须来自 `--body-file <file>`。不要使用 `gh issue comment --body`、`gh api -f body=...` 或把多行正文直接拼进 shell 参数;这些路径容易把真实换行、反引号和 Markdown 表格污染成字面量 `\n` 或 shell escape。从 shell 生成正文文件时使用 quoted heredoc,例如 `cat <<'EOF' > /tmp/body.md`,保证反引号和反斜杠不被展开;JSON 请求体场景优先使用对应 CLI 的 `--body-file` 或 `--body-stdin`,不要把长 JSON 塞进命令行参数。`gh issue` 写命令不接受 stdin 正文;需要更新 #20 总看板或创建新 issue/comment 时,先把正文写入 Markdown 文件,再运行 `bun scripts/cli.ts gh issue update|comment create|create ... --body-file <file>`。`gh issue update --mode replace|append --body-file` 是主更新入口,`edit` 只是兼容别名;`append` 会先读取当前正文再追加文件字节,保留真实换行、反引号和 Markdown 表格,不走 shell 拼接。`gh issue update --body-file` 默认拒绝 `null`、空白和过短正文;#20 自动要求 `## 看板(OPEN)`,指挥简报 profile 自动要求 `## 常驻观察与长期建议`,并允许 #24 legacy 或每日滚动简报 issue。更新 body-only issue 前优先跑 `--dry-run`,查看旧/新正文长度、body SHA、关键标题、字面量 `\n` 和 shell 污染信号;正式写入长期正文时优先带上 `--expect-updated-at` 或 `--expect-body-sha`,避免旧缓存覆盖新正文。指挥简报更新正文时默认只写 GitHub issue,不自动向 ClaudeQQ 推送;#24 legacy 可用 `--notify-claudeqq-brief-diff` 通知 helper,如确需提醒用户,按本文的 ClaudeQQ 通知门槛单独发送。提交前或巡检时可用 `gh issue scan-escape --limit N --dry-run` 或 `gh issue cleanup-plan --limit N` 只读扫描污染并生成建议,不自动修复。
|
||
|
||
PR 是审查型交付入口,不是所有 Code Queue 任务的默认出口。默认 master-only 交付仍按项目 Git 规则执行;当变更风险高、跨模块、需要人工审查、或任务目标明确要求 PR 交付时,worker 可以创建 PR。PR 型任务必须报告源分支、目标分支、PR URL、关联 issue、测试证据和未完成风险。禁止把 PR 当成隐藏分支仓库;PR 分支必须来自最新目标线,保持小而可审查,并在合并后确认目标分支远端 commit 可 fetch。
|
||
|
||
PR 支持本身是 Code Queue 能力的一部分。当前 UniDesk CLI 支持 `gh pr list|view|create|update|comment create|comment delete|close|reopen`,其中 create 需要显式 `--title`、`--base`、`--head` 和正文来源,update 需要显式 PR number、正文来源和 `--mode replace|append`,comment create 需要显式 PR number 和正文来源,且推荐使用 `--body-file`。`pr create --dry-run`、`pr update --dry-run` 与 `pr comment create --dry-run` 只返回 planned operation,不创建 PR、不更新正文、不写评论;非 dry-run 创建前会校验 repo、base、head 和 compare ahead 状态,append 更新会先读取当前 PR body。`gh pr delete` 和 `gh pr merge` 仍是后续范围,本阶段没有 `--confirm` 可以启用真实 merge,也不能伪造硬删除;需要移除活跃 PR 时使用 `gh pr close`。普通 worker 不应隐式依赖未实现的 PR 合并能力;需要 PR 交付时,prompt 必须明确允许的人工或后续工具路径,并报告未覆盖范围。
|
||
|
||
### PR 驱动派单模板
|
||
|
||
PR 驱动是 Code Queue 协作的未来默认方向:worker 在独立 head branch 上提交,创建面向目标分支的 PR,指挥官审查后再合并并更新 issue/#20/#24。当前仍处于 runner GitHub 可达性补齐阶段;在 #19 的 runner GitHub 可达性未验收前,派单 prompt 必须自包含完整需求、约束、写入范围和验收标准,不能只贴 GitHub issue 链接。issue URL 只能作为辅助引用。
|
||
|
||
PR 型派单 prompt 至少包含以下字段:
|
||
|
||
- `目标 issue`:写明 issue 编号、URL 和本次任务要关闭或推进的验收点;不要假设 runner 能读取 issue。
|
||
- `目标分支`:明确 `master` 或经批准的维护分支;普通开发集成使用 `master`。
|
||
- `head branch`:使用可追踪命名,例如 `code-queue/issue-35-pr-dry-run-probe`、`code-queue/issue-<number>-<short-topic>` 或包含 task id 的等价短名;head branch 必须从最新 `origin/<目标分支>` 创建。
|
||
- `禁止动作`:禁止直接 push 目标分支,禁止 merge PR,禁止改 release/v1 运行态服务,禁止输出 token,禁止跑本任务未要求的重型 check/e2e/Playwright。
|
||
- `必须动作`:提交前运行轻量自测;push head branch;创建面向目标分支的 PR;PR body 写清关联 issue、修改文件、验证命令和风险;若创建 PR 前需要探测,先运行只读或 dry-run preflight。
|
||
- `final response 字段`:实际分支、目标分支、head branch、PR URL、远端 head commit、是否已创建 PR、是否未 merge、修改文件、验证命令和结果、遗留风险;如果 PR 未能创建,报告结构化原因和 runnerDisposition。
|
||
|
||
PR 型 prompt 可直接嵌入以下 Git 指令约束:
|
||
|
||
```text
|
||
Git/PR 交付要求:
|
||
- 目标分支:master。
|
||
- 从最新 origin/master 创建 head branch:code-queue/issue-<number>-<short-topic>。
|
||
- 不得直接 push master 或 release/v1。
|
||
- 必须 push head branch 并创建 PR 到 master;不得 merge PR。
|
||
- 创建 PR 前先运行只读/dry-run preflight,确认 GH_TOKEN/GITHUB_TOKEN、GitHub egress 和 repo 可见性,不得打印 token。
|
||
- final response 必须报告 head branch、PR URL、远端 head commit、修改文件、验证命令、是否未 merge。
|
||
```
|
||
|
||
Runner preflight 优先使用执行面诊断入口:
|
||
|
||
```bash
|
||
bun scripts/cli.ts codex pr-preflight --remote --issue 20
|
||
```
|
||
|
||
该命令经 backend-core 稳定 `code-queue` proxy 访问 D601 scheduler 的 `/api/runtime-preflight`,报告 scheduler/runner 环境里的 `GH_TOKEN`/`GITHUB_TOKEN` 覆盖、工具、Git worktree、GitHub egress、repo/issue/PR 只读探测和可选 push dry-run。需要复核 PR body/创建命令 guard 时追加 `--pr-create-dry-run --pr-create-dry-run-head <head>`;该 guard 只执行 dry-run,不创建 PR。缺少 env token 时必须返回 `ok=false`、`runnerDisposition=infra-blocked` 和 `tokenCoverage.missing=["GH_TOKEN","GITHUB_TOKEN"]`,因为 provider dev container 只能转发 scheduler 已经拥有的 token。`--remote` 在 runner-like 环境里不再要求本地 `unidesk-backend-core`、`unidesk-database`、`baidu-netdisk-backend` 容器存在;这些本地 target stack 缺失只作为证据,不是最终主阻塞。若远程控制面可达,输出继续保留 ready preflight;若远程控制面不可达,结构化失败归类为 `failureKind=proxy-gap` / `degradedReason=remote-control-plane-unreachable`。输出中的 `prCapabilityContract` 用于指挥官快速审查 runner handoff:目标分支固定显示、push/PR create dry-run 标记为不写远端、系统 `gh` binary 与 UniDesk REST `bun scripts/cli.ts gh` 可用性分开报告,且 merge 明确保持 `unsupported-command`。
|
||
|
||
本地 runner preflight 示例:
|
||
|
||
```bash
|
||
bun scripts/code-queue-pr-preflight-example.ts --repo pikasTech/unidesk --base master --head code-queue/issue-35-pr-dry-run-probe --comment-pr 1
|
||
```
|
||
|
||
该脚本只读调用 `gh auth status`,并执行 `gh pr create --dry-run` 与 `gh pr comment --dry-run`。它检查当前 shell 的 `GH_TOKEN/GITHUB_TOKEN` 是否存在、GitHub REST egress 是否可达、repo 是否可见,并且只输出 token 来源和存在性,不输出 token 值。它不能证明 Code Queue default scheduler 已注入 token;跨 queue 派单 admission 应使用 `codex pr-preflight`。
|
||
|
||
指挥官审查 checklist:
|
||
|
||
- PR base 是声明的目标分支,head branch 命名可追踪,远端 head commit 可 fetch。
|
||
- diff 只覆盖派单 ownership,未混入 release/v1 运行态服务或无关 dirty worktree。
|
||
- PR body 和 final response 都包含关联 issue、修改文件、验证证据、未完成风险和未 merge 状态。
|
||
- contract/dry-run 证据覆盖本次 PR 能力:`pr create --dry-run`、`pr list/view`、`pr comment --dry-run`,并确认 `gh pr merge` 返回结构化 unsupported。
|
||
- 没有 token、凭证、临时日志或构建产物进入 commit、PR body 或评论。
|
||
- 合并前由指挥官审查并决定是否 merge;合并后再验证目标分支远端 commit 可见,并按态势更新 issue/#20/#24。
|
||
|
||
## 监控
|
||
|
||
指挥官必须用 task 级和 queue 级证据监控 Code Queue,不能只看单一状态字段。
|
||
|
||
常用入口:
|
||
|
||
- `bun scripts/cli.ts codex tasks --view supervisor --limit N`:查看默认有界监督视图,包括 running、完成未读、最近完成、queued/runnable、execution diagnostics 和下一步 drill-down 命令。
|
||
- `bun scripts/cli.ts codex queues`:查看低噪声队列计数、active task id、完成未读队列、runnable 队列和控制面诊断;只有需要完整队列行时才加 `--full`。summary 和 full 都使用稳定 JSON path `.data.queues.items[]` 读取队列行,并从 `.data.queues.counts` 与 `.data.queues.executionDiagnostics` 读取全局计数和执行诊断。
|
||
- `bun scripts/cli.ts codex tasks --unread --limit N`:查看完成未读审阅积压;`--unread` 与 `--unread-only` 等价,不能被静默忽略。
|
||
- `bun scripts/cli.ts codex tasks --status succeeded --unread --limit N`:按具体终态过滤监督结果;不支持的 status filter 必须显式失败,不能扩大为未过滤结果。
|
||
- `bun scripts/cli.ts codex task <taskId>`:默认只查看原始 prompt、最终 response、最后错误和 drill-down 命令,这是完成未读任务审阅的第一步。
|
||
- 当默认审阅摘要不足时,再逐级使用 `bun scripts/cli.ts codex task <taskId> --detail`、`bun scripts/cli.ts codex task <taskId> --trace --limit N` 或 `codex output`。
|
||
- 当 master 控制面状态和 D601 scheduler 状态看起来分裂时,使用 `docs/reference/observability.md` 中的活性规则判断。
|
||
|
||
默认 supervisor 视图必须保持低噪声。每个任务应带 `commands.show`、`commands.trace`、`commands.output`、`commands.full` 和 `commands.read`,让下一步渐进披露动作明确;默认不得嵌入完整 queue 列表、完整 final response、raw output 页或完整 trace 行。`commands.read` 只是在人工审阅后的建议命令,listing 命令绝不能自动执行。
|
||
|
||
完成未读任务的审阅也必须遵循渐进披露。指挥官默认只拉取原始 prompt 和最终 response,用它判断任务是否声称完成、是否有明显越界、是否缺少验收证据;不要默认拉完整 trace、全量 tool summary 或 raw output。只有当 final response 与目标不一致、证据不足、远端 commit 无法验证、任务疑似造假、或需要追溯失败原因时,才继续展开 `--detail`、分页 `--trace`、或按 seq 读取 `codex output`。这条规则的目标是降低上下文压力,同时保留通过多步查询拿到完整证据的能力。
|
||
|
||
队列诊断中的 `split-brain` 表示控制面/执行面观测分裂,不自动证明任务已经死亡。只要任务 heartbeat 还在刷新、trace 仍在推进,就不能把它判成服务中断或要求立刻 stop;应把它视为 `splitBrainLive=true` 的 live 任务,继续监督并推进 #20 里的已排任务,而不是 interrupt、替换或把 backend 当成已经挂掉。队列摘要应显示 `effectiveLiveness=live`、`splitBrainLive=true` 和 `recommendedAction=continue-supervision`;只有 heartbeat expired/missing 或满足 stale-recovery 条件时,才应显示 `effectiveLiveness=at-risk` 并进入恢复判断。
|
||
|
||
单次 `provider is not online`、SSH 超时、proxy 超时或 registry 请求失败只能证明“当前观察路径失败”,不能单独升级为 D601 全局离线、CI/CD 全局阻塞或业务任务不可推进。指挥官和 runner 必须用多信号裁决运行面状态,至少区分以下观察面:
|
||
|
||
- backend-core 节点视图和 provider heartbeat,例如 `debug health` 中的 D601 `status`、`lastHeartbeat` 和 gateway 版本;
|
||
- Host SSH / WSL SSH 维护桥,例如 `ssh D601 hostname` 或短 argv 命令;
|
||
- D601 artifact registry health、k3sctl-adapter health、目标 microservice health;
|
||
- Code Queue scheduler heartbeat、任务 heartbeat、trace/output 是否持续入库;
|
||
- 当前 runner 容器内 CLI/proxy 路径是否只是局部不可达。
|
||
|
||
只有多个独立观察面同时失败,或同一关键路径在明确时间窗口内持续失败,才能把问题判为全局阻塞。否则应记录为 transient 或 runner-local observation gap,优先重试、steer 任务纠偏或拆出基础设施 follow-up;不得让业务 worker 把单次局部失败作为最终 blocker。CLI 和 runtime 必须把错误输出结构化为 `scope=runner-local|provider-gateway|ssh|registry|k3s|scheduler|service-proxy`、`observedAt`、`retryable`、`decision`、`healthyScopes`、`failedScopes` 和建议的交叉验证命令。
|
||
|
||
ClaudeQQ 是面向用户的主动提醒通道,不是 #24 简报更新的自动转发器。指挥官只应在三类情况下自主发送 ClaudeQQ 消息:核心服务或关键执行面宕机且需要用户知情,高风险决策需要用户请示,或出现里程碑式进展值得同步。消息必须简明扼要,一次不超过 200 个中文字符,写成一段话,不使用 Markdown 语法。普通轮询、普通 issue 更新、普通 #24 简报追加、外部 token provider 正常限流、以及无用户动作要求的中间状态,不发送 ClaudeQQ。发送失败只记录到 #24 或对应 blocker issue,不回滚已经完成的 GitHub issue 更新。
|
||
|
||
重启 Code Queue backend、重建 Code Queue backend 容器、重启 Code Queue 执行面,或对运行中 Code Queue 任务执行 interrupt/cancel 这类会改变执行状态的操作,都属于高风险干预。即使看起来是最小恢复动作,指挥官也必须先通过 ClaudeQQ 向用户上报原因、影响范围和拟执行动作,并等待用户明确同意;未获得同意前只能做只读诊断、记录 issue、更新看板和准备恢复方案。
|
||
|
||
host Codex 指挥官正规化后仍受同一条高风险边界约束。`docs/reference/host-codex-commander.md` 中的直管微服务只能把 host Codex 保活、SSH/PTY/stdio bridge、prompt plan、trace summary、#20/#46 issue 入口和 ClaudeQQ 审批记录产品化;它不是 Code Queue runner,也不是 Code Queue 自部署通道。第一阶段 `bun scripts/cli.ts commander ...` 只允许输出 contract/dry-run 计划,不得实际重启 backend、interrupt/cancel task、读取 token 明文、打开 bridge 或发送 ClaudeQQ。
|
||
|
||
当多信号裁决显示 provider 服务器、D601 执行面或关键维护桥疑似需要人工检查时,指挥官可以在更新 #24/#40 等记录之外,通过 ClaudeQQ 额外提醒用户检查 provider 服务器状态。提醒只在首次确认、状态恶化、恢复或需要用户介入时发送,不能在每轮轮询中重复轰炸。ClaudeQQ 提醒是 best-effort:若 ClaudeQQ 本身依赖同一条故障 provider/k3sctl 链路而不可达,指挥官应把通知失败的原因写入 #24 或对应 blocker issue,并继续按轮询和恢复规则推进。
|
||
|
||
在 UniDesk CLI 中,`bun scripts/cli.ts provider triage <providerId>` 是只读多信号裁决入口,适合作为 worker 和指挥官的统一健康判断前置。它必须至少保留这些合同:`provider is not online` 这类单路径失败只应落到 `decision=retryable-transient` / `blockingDisposition=runner-local-observation-gap`,不得直接输出 `global-offline`;只有 provider-gateway/SSH/k3s/scheduler 等多个独立关键路径同时失败且缺少健康交叉证据,才允许输出 `decision=global-offline`;registry 或单个 service proxy 失败但 heartbeat、SSH 或节点视图仍健康时,应输出 `decision=service-degraded`。`recommendedCrossChecks` 必须包含 `debug health`、`debug dispatch <providerId> host.ssh --wait-ms 15000`、`ssh <providerId> argv true`、`artifact-registry health --provider-id <providerId>`、`microservice health k3sctl-adapter`、`microservice health code-queue` 与 `codex tasks --view supervisor --limit 20`。
|
||
|
||
D601 artifact registry 的 systemd unit inactive 不等于 D601 全局离线。如果 `artifact-registry health` 或 `provider triage D601` 同时看到 registry container running、loopback listener healthy、`/v2/` 返回 200,且 provider heartbeat、Host SSH、k3sctl-adapter、Code Queue scheduler 或业务 API 有健康信号,这只能判为 `service-degraded`,不得写成 provider offline、D601 offline 或 CI/CD 全局不可推进。只有这些健康面也同时失败,才进入 `global-offline` 判断。
|
||
|
||
对于 trace 或 heartbeat 新鲜的长任务,通常应保持运行。每几分钟轮询一次优于反复 interrupt/retry。
|
||
|
||
外部 token provider、模型 API 或上游服务的限流和短时不可用是正常预期,不应自动升级为 Code Queue 基础设施缺陷。典型表现包括 `429 Too Many Requests`、provider transient error、上游 timeout 或模型服务短时失败。只要 Code Queue 的状态机仍在自动指数退避,task heartbeat 或 scheduler heartbeat 新鲜,且任务仍能从 `retry_wait` 回到 `running`,指挥官应等待外部 provider 自行恢复,不创建额外修复 issue、不重派重复任务、不把该现象写成 blocker。只有当退避机制失效、任务丢失、heartbeat 过期、状态机卡死,或重试耗尽进入不可恢复终态时,才按 Code Queue 基础设施问题介入。
|
||
|
||
对于大规模 CI/CD 迁移波次,除非发生事故,否则使用稳定但可自适应的监督节奏。指挥官可以根据任务活跃度、完成未读积压、heartbeat 风险和外部等待性质自行决定 sleep 时长,但单次 sleep 不能低于 5 分钟、不能高于 30 分钟。活跃排障、刚派出新任务、存在完成未读或 heartbeat 风险时使用接近 5 分钟的短轮询;长时间等待外部 CI、模型 provider 退避或镜像构建且 heartbeat 新鲜时,可以拉长到 10 到 30 分钟。每轮醒来后读取 `codex queues`,读取 terminal 或可疑任务摘要,然后决定接受、retry、拆分 blocker,或让健康任务继续运行。循环期间指挥官可以做不重叠的有用工作,例如文档或 issue 梳理,但这些辅助工作不能接管 worker 已分配的实现。
|
||
|
||
当任务离开 `running` 或 `judging` 后,其结果仍然是未读工作。指挥官必须检查 final response 和 judge 记录,然后再决定是否补充并发窗口。
|
||
|
||
禁止在检查前用批量 read 动作清空完成未读任务。每个完成任务必须先单独审阅,再用 `bun scripts/cli.ts codex read <taskId>` 单独标记已读,使未读状态继续代表“仍需审阅”。
|
||
|
||
每次新增 Code Queue 任务、补发 follow-up task,或处理一批完成未读任务后,都必须同步更新 GitHub 总看板 issue `#20` 的正文主表;如果发生实质态势变化,还要同步更新指挥简报 issue `#24` 的正文。看板更新应反映当前任务分布、关键 blocker 和粗略进度,不要只改聊天上下文或只改单个 issue,而让总态势图落后于实际调度状态。
|
||
|
||
成本路由接入 #20 看板时,#20 的每个 Code Queue 任务行都应显式保留推荐或实际 runner/model、风险等级、验证证据和审阅状态。推荐列的语义只来自指挥官判断或 `codex submit --dry-run` 的 `routingRecommendation`,不能来自 worker 自评。MiniMax 和 DeepSeek 任务在 #20 中必须先保持“待指挥官审阅”状态;只有指挥官核验 diff、commit、轻量验证和未越界后,才更新为已验收并执行 `codex read <taskId>`。若 dry-run 给出 `commander-human-only` 或 GPT-5.5 recommendation,#20 不应把该任务降级给 MiniMax/DeepSeek;若必须降级,必须在看板 progress 中写明人工接受的风险和额外审阅动作。
|
||
|
||
## 指挥工作流
|
||
|
||
对每个活跃任务,按顺序评估四件事:
|
||
|
||
1. 完成质量:是否真的满足任务验收边界;
|
||
2. 完成状态:是否已经终态、可 retry,或仍在推进;
|
||
3. 自阻塞风险:任务是否卡在它自己无法解决的问题上;
|
||
4. 下一步动作:接受、继续、替换为更窄任务,或上报基础设施问题。
|
||
|
||
如果 blocker 是可复用的基础设施问题,不要盲目反复重跑业务任务。应先把基础设施缺陷记录到 issue,再在 Code Queue 无法越过时手动修复基础设施,然后恢复交付波次。
|
||
|
||
指挥官应优先做只读分析和派发新的窄范围任务,而不是本地接管实现。手动工作只保留给基础设施 blocker、live recovery,以及队列无法安全自解的问题。
|
||
|
||
## 干预规则
|
||
|
||
只有存在明确理由时才干预。
|
||
|
||
- 如果任务还在运行且 trace 或 scheduler heartbeat 新鲜,应引导而不是 interrupt。
|
||
- 对运行中任务的引导应优先使用正式 CLI:`bun scripts/cli.ts codex steer <taskId> --prompt-file <path>`。该命令和 `codex task/tasks/read` 复用同一个 backend-core stable proxy helper;`--dry-run` 会显示 `method/path/stableProxyPath`、prompt 摘要和 raw proxy 等价命令但不发送。非 dry-run 失败时先看 `.data.diagnostics.reason`:`backend-core-unreachable` 属于本机到 core 的观察路径,`code-queue-microservice-unregistered`/`proxy-unauthorized`/`proxy-404` 属于 stable proxy 配置或权限,`steer-endpoint-404`/`upstream-runtime-rejected` 属于 D601 runtime 或任务状态,`stable-proxy-failed` 多为 provider/k3s/tunnel 链路问题。若正式 CLI 自身不可用,临时通过受控 microservice proxy 调用只能作为现场恢复手段;这类绕行必须记录到指挥简报 issue #24 主体的常驻观察,并创建正式 issue 补齐 CLI 能力,避免长期依赖隐式 API。
|
||
- 如果任务进入终态但缺少必要验收证据,应使用聚焦 continuation prompt retry 同一任务。
|
||
- 如果任务被可复用基础设施缺陷阻塞,应把该缺陷分配给合适的空闲或低风险队列,让原业务任务等待,或在修复后 retry。
|
||
- 如果基础设施缺陷影响 Code Queue 控制面可用性,指挥官可以执行恢复队列所需的最小受控部署,然后验证原任务能继续。
|
||
- 如果 retry、cancel、move 或 scheduler 行为错误,不要把手动 patch PostgreSQL 当作最终修复。应修复代码路径,必要时部署,然后通过正常 API 恢复受影响任务。
|
||
|
||
上一条中的“最小受控部署”不包括未经用户同意的 Code Queue backend 重启、容器重建或运行中任务 interrupt/cancel。凡是会改变 Code Queue backend 或执行中任务状态的恢复动作,必须先走 ClaudeQQ 请示;没有用户明确同意时,指挥官只能继续只读观察、拆出基础设施 issue、准备恢复命令和等待授权。
|
||
|
||
手动干预应尽可能保留原任务身份,以保持上下文连续。创建重复替代任务是 fallback,不是默认动作。
|
||
|
||
## 完成标准
|
||
|
||
Code Queue task 不是只要 push 代码就算完成。
|
||
|
||
对于 CI/CD 交付任务,验收必须包含目标交付策略要求的证据。对用户服务 artifact 交付,这意味着:
|
||
|
||
- CI artifact producer 从已推送 commit 运行;
|
||
- artifact ref 和 digest 已记录;
|
||
- dev 环境消费同一个 artifact;
|
||
- production CD 消费 artifact,且没有源代码 rebuild;
|
||
- live health、live commit 或 image label 证据与请求 commit 匹配。
|
||
|
||
对于基础设施任务,验收必须证明原本被阻塞的 workflow 可以继续,或明确说明 live 系统消费该修复还缺哪个部署步骤。
|
||
|
||
完成未读任务仍然是指挥官工作。它们必须被阅读、分类,并被接受、retry,或转成新的窄范围 follow-up task。
|
||
|
||
## 基础设施缺陷处理
|
||
|
||
交付计划中发现的基础设施缺陷,只要拆分后能提高吞吐或减少混乱,就应从用户服务工作中拆出来。
|
||
|
||
基础设施缺陷示例:
|
||
|
||
- retry API 遗留 stale cancellation state;
|
||
- healthcheck 不再匹配 runtime image;
|
||
- CLI 可观测性无法快速看到 running、最近完成或完成未读任务;
|
||
- WebUI 和 CLI 的 proxy 路径不一致;
|
||
- deploy job 报失败但服务 API 实际健康;
|
||
- 指挥侧突发 submit 打满 Code Queue manager 或低内存主机,导致队列还没确认任务就被压垮;
|
||
- Code Queue 容器缺少监督所需的基础工具或凭证路径,例如 `gh`、`hub` 或 GitHub token 注入路径。
|
||
- D601、provider-gateway、registry、k3sctl-adapter 或 service proxy 的单路径瞬时失败被 worker 放大为全局阻塞,而缺少多信号健康裁决和可重试错误分类。
|
||
|
||
这些缺陷应分配给基础设施队列,prompt 中要包含具体观测失败、期望长期合同,以及原交付任务继续所需的恢复动作。
|
||
|
||
如果缺陷只存在于 Code Queue 执行环境,且服务可以在 dev 中安全热修而不触碰 prod,应先做最小临时 live remedy。然后把修复持久化到相关 Dockerfile、容器镜像或凭证传播路径,并在 dev 验证持久化修复后再关闭问题。
|
||
|
||
如果业务任务发现缺少工具或凭证路径,指挥官应把它拆成独立 infra task,而不是埋在业务任务 prompt 中。业务任务在 bridge 存在时应继续推进。
|
||
|
||
Artifact publish preflight 也属于基础设施问题的只读分类范畴:`artifact-registry status|health` 和 `ci publish-user-service --dry-run` 返回 `runnerDisposition=infra-blocked` 时,通常说明 backend-core/database/provider 通道缺失,而不是用户服务本身的业务错误。此时应先恢复控制通道,再决定是否重试,不要把裸 `No such container` 当成可直接回归的业务失败。
|
||
|
||
## 指挥边界
|
||
|
||
指挥官可以:
|
||
|
||
- 读取 task、queue、health、job 和 service 状态;
|
||
- 通过正常 Code Queue 和 microservice proxy API submit、retry、interrupt 或 cancel;
|
||
- 创建自包含 follow-up task;
|
||
- 在用户允许生产修复且部署路径已验证时,为基础设施恢复执行受控生产部署;
|
||
- 当 main worktree 有无关并行变更时,为文档或受控部署动作使用干净 detached worktree。
|
||
|
||
指挥官自己的 UniDesk 指挥仓库必须保持在单一根 worktree 的最新 `master` checkout 上。不要为指挥、队列判断或日常监督创建额外 worktree,这样指挥官始终看到当前仓库头和生产协调依赖的同一份实时状态。如果 worker 或受控一次性操作需要隔离 worktree,该 worktree 属于 worker 或具体操作,不属于指挥官的常驻环境。
|
||
|
||
每个由指挥官派发的 worker prompt,都必须在 Git 指令前明确写明目标线。`master` 用于主动开发和集成工作;`release/v1` 只用于明确批准的稳定维护修复。worker 的 final response 必须报告实际推送分支、远端 commit hash,以及该 commit 是否可从 `origin/<target-branch>` 获取。如果 final response 引用的 commit 不能被指挥官从声明的目标分支 fetch 到,该任务不得验收为完成。
|
||
|
||
指挥官不得:
|
||
|
||
- 本地重做 worker 已分配的实现,除非用户明确要求手动接管;
|
||
- 在 master server 上跑已知可能 OOM 的 full check、full e2e 或 Playwright;
|
||
- 回滚无关 dirty worktree 变更;
|
||
- 在 Git 远端是 source of truth 时,把本地部署状态当作 source of truth;
|
||
- 在缺少验收证据时宣布交付完成。
|
||
|
||
## 文档反馈回路
|
||
|
||
每个重复出现或阻塞交付的问题,都应反馈到以下至少一个位置:
|
||
|
||
- 修复该缺陷的 Code Queue task;
|
||
- 记录阻塞条件和恢复依赖的 GitHub issue 或 issue comment;
|
||
- 当经验具有长期复用价值时,写入长期参考文档。
|
||
|
||
长期参考文档应记录可复用规则,而不是完整事故流水账。过程知识应降低未来监督成本,而不是变成又一个一次性日志。
|