Files
pikasTech-unidesk/docs/reference/code-queue-supervision.md
T
Lyon 8ebc9c7023 fix(code-queue): preflight runner skills availability
fix(code-queue): preflight runner skills availability
2026-05-22 23:33:02 +08:00

344 lines
49 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 字段都要写进 promptGitHub 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;创建面向目标分支的 PRPR 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 branchcode-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
```
`codex pr-preflight --remote``auth-missing` 只表示 scheduler/runtime preflight surface`scheduler-runner-env`)没有看到 `GH_TOKEN/GITHUB_TOKEN` 或 auth-broker,不得被简化成“当前 active runner/dev container 不能创建 PR”。Code Queue 输出必须同时给出 `scopeBoundary``activeRunnerDevContainer`:前者说明 scheduler env 与当前 CLI/dev container 是独立 scope,后者只报告当前 CLI 进程是否看见 token,且不打印 token 值。指挥官看到 remote preflight `auth-missing` 时,应继续用当前 runner 内的 `bun scripts/cli.ts gh auth status --repo pikasTech/unidesk``gh pr create --dry-run``gh pr comment create --dry-run` 验证实际 PR 能力;只有这些 active runner 检查也失败时,才能把它判成当前 turn 不能 PR。
该命令经 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"]``authBroker.source="broker/auth-broker-needed"`,因为 provider dev container 只能转发 scheduler 已经拥有的 token,除非后续接入 broker-held GitHub credential。系统 `gh` binary 缺失只能作为 `tools.systemGhBinary.ok=false` 观测,不得把它误判为 UniDesk REST `bun scripts/cli.ts gh` 不可用。`--remote` 在 runner-like 环境里不再要求本地 `unidesk-backend-core``unidesk-database``baidu-netdisk-backend` 容器存在;这些本地 target stack 缺失只作为证据,不是最终主阻塞。若远程控制面可达,输出继续保留 ready preflight;若远程控制面不可达,结构化失败归类为 `failureKind=control-plane-missing` / `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`
### Runner Skill 可用性
D601 Code Queue runner 的长期 skills source of truth 是宿主 `/home/ubuntu/.agents/skills`,生产和 dev Code Queue Pod 都必须只读挂载到容器内 `/root/.agents/skills`,并设置 `UNIDESK_SKILLS_PATH=/root/.agents/skills`。不要使用或传播任何拼错的 skills 路径;诊断中只能把这类问题作为 forbidden path risk 暴露。
执行面 `/health``/api/dev-ready``/api/runtime-preflight` 必须输出同一份只读 skill availability report。稳定字段包括 `source``target``requiredSkills``missingSkills``degraded``blocker``valuesPrinted=false``requiredSkills` 至少覆盖 `docs-spec``cli-spec``frontend-design``playwright-cli`;如果目标目录缺失、不是只读挂载、必需 skill 缺失,或拼写错误路径存在,报告必须显示 `ok=false` 和结构化 `blocker`,不能把 runner 能力缺口伪装成业务任务失败。
受控加载路径是更新宿主 `/home/ubuntu/.agents/skills` 后让 Code Queue Pod 通过 hostPath 读取;在线热更新只能作为临时 runbook,长期验收必须以 manifest/source-of-truth、结构化 health/preflight 和合同测试为准。需要验证时优先运行:
```bash
bun scripts/code-queue-runner-skills-contract-test.ts
bun scripts/cli.ts codex pr-preflight --remote --issue <issue-number>
```
指挥官审查 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、完成未读、最多 5 条最近完成、queued/runnable、execution diagnostics、任务分类和下一步 drill-down 命令。默认行只保留短 prompt/body 预览、原始字符数和 `commands.show/detail/trace/output/full/read`,需要更多内容再按 taskId 展开。
- `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.detail``commands.trace``commands.output``commands.full``commands.read`,让下一步渐进披露动作明确;默认不得嵌入完整 queue 列表、完整 final response、raw output 页或完整 trace 行。`recentCompleted` 必须默认限量,且不得重复 `completedUnread` 里的未读终态,避免完成历史把当前 running、阻塞和未读审阅挤出视野;需要完整当前页时显式使用 `--view full``executionDiagnostics` 只能展示有界 task-id/reason 预览、总数、截断标记和 omitted counts;需要全量诊断时使用输出中的 raw command。`commands.read` 只是在人工审阅后的建议命令,listing 命令绝不能自动执行。
这条规则直接服务 HWLAB #132:指挥官要优先看到真实业务推进、部署修复、阻塞和需要人工审阅的未读结果,Gate/报告/审查/诊断类任务只能作为折叠的分类信号存在,不能在默认输出中用长 prompt/body 抢占上下文。
完成未读任务的审阅也必须遵循渐进披露。指挥官默认只拉取原始 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
- 当经验具有长期复用价值时,写入长期参考文档。
长期参考文档应记录可复用规则,而不是完整事故流水账。过程知识应降低未来监督成本,而不是变成又一个一次性日志。