Files
pikasTech-unidesk/docs/reference/code-queue-supervision.md
T
2026-06-11 11:54:35 +00:00

462 lines
90 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.
# AgentRun Queue 与旧 Code Queue 指挥监督策略
本文定义在人工或 lead-agent 指挥官监督下,使用 AgentRun Queue 作为新任务并行交付基础设施、使用旧 Code Queue 作为历史归档和残留任务停止入口的长期运行模型。本文是协同策略,不替代 `docs/reference/microservices.md``docs/reference/observability.md``docs/reference/user-service-delivery.md``docs/reference/agentrun.md` 或 Code Queue runtime 合同。
## 范围
当一个交付目标过大,无法由单个 AgentRun task 完成,并且必须拆分到多个队列、服务或基础设施 lane 时,使用本策略。
本策略适用于:
- 用户服务 CI/CD 推广;
- 需要多个隔离 worktree 的跨服务修复;
- 用户服务开发过程中暴露出来的基础设施缺陷;
- 后续验证、retry、验收和任务接力协调;
- 指挥官为了保持 AgentRun 任务推进而做的手动监督工作,但不接管 worker 的具体实现。
本文不授权绕过正常部署、Git 或生产安全规则。
## 运行原则
指挥官对最终结果负责,AgentRun task 对边界明确的执行负责。
指挥官应维护交付目标、活跃队列、阻塞点、证据缺口和下一步恢复动作的实时地图。AgentRun worker 应收到自包含 prompt,prompt 中必须有足够上下文,不能依赖 GitHub issue 可见性或聊天历史。
集中指挥的目标是提升交付吞吐和可用性,而不是把每个缺陷都变成一次性的人工修补。
指挥官的最终目标是推动整体开发波次持续前进:跟踪队列进展、及时纠偏、审查完成质量,并安排下一轮任务,让交付计划持续复利式推进,而不是一批任务结束后停滞。
## HWLAB / #20 监督口径
`pikasTech/unidesk#20` 只承载 UniDesk 指挥控制面:command/control、AgentRun Queue、旧 Code Queue 归档、CLI、基础设施、PR 收口和治理态势。HWLAB 产品功能、用户体验、M3 验收、DEV runtime、发布收敛和用户反馈必须进入 `pikasTech/HWLAB` issue/PR,并由 `pikasTech/HWLAB#7` 或 HWLAB 侧对应看板承载;#20 只能保留指挥侧路由行、关联 task、阻塞分类和回链,不复制 HWLAB 产品验收口径。更新 #20 时优先使用 `bun scripts/cli.ts gh issue update|board-row ... --board-issue 20`,该 guard 会拒绝把 HWLAB 产品 issue 行写入 #20,并提示改写到 `pikasTech/HWLAB`。HWLAB 指挥侧固定入口、热修边界和长期 source of truth 见 `docs/reference/hwlab.md`
当 HWLAB 是当前优先级最高的推进对象时,所有派单 prompt 的开头都必须显式引用 `DC-DCSN-P0-2026-003`,并说明任务究竟服务于 M3 虚拟硬件可信闭环的哪一环。如果任务只是在做发布前置、诊断、证据收口或文档治理,也必须明确写出它不抢占 M3 P0。
HWLAB 业务目标、验收和实现优先级归 `pikasTech/HWLAB#7`;UniDesk 指挥治理、队列监督、并发窗口、PR handoff 和 runner 能力归 `pikasTech/unidesk#20`#20 可以记录 HWLAB #7 的调度状态和证据链接,但不能替代 HWLAB 业务 issue。
审阅 HWLAB runner 输出时,不能把 `SOURCE``LOCAL``DRY-RUN`、fixture 或只读报告误当成 `DEV-LIVE`。除非输出真的证明了 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` 的真链路,并且带有 operation / audit / evidence 关联,否则只能归类为 support、diagnostics 或 contract。
`split-brain live` 且 heartbeat/trace 新鲜时,指挥官必须继续监督,不把它当作服务中断。此类状态的优先动作是继续轮询、继续审阅和在 AgentRun Queue 中派发新任务,而不是默认 interrupt、cancel 或重启旧运行面。旧 `codex task/tasks/output/read/unread/queues` 的 bounded summary 仍用于历史监督;旧 `codex submit` 不再作为新任务写入确认来源。需要 raw drill-down 时使用返回的 `queue.listPreviewPolicy.rawCommand`,即 `bun scripts/cli.ts microservice proxy code-queue /api/tasks/overview?limit=30 --raw --full`
`codex tasks --view commander --limit N` 是指挥官高频轮询入口,必须保持默认 stdout 严格有界。它优先展示 active runner 精确计数与少量 active item、queued/retry_wait count、terminal unread compact counts、关键 risk counts 和 drill-down commands;历史 terminal unread item details、prompt preview、final response preview、trace/output 和 raw overview 不在默认 commander 输出中展开。需要审阅 terminal unread 详情时使用 `bun scripts/cli.ts codex unread --limit N``bun scripts/cli.ts codex tasks --unread --view supervisor --limit N``bun scripts/cli.ts codex tasks --view full --limit N` 或 per-task `bun scripts/cli.ts codex read <taskId>`
live-read browser audit 只用于观察已部署 UI,不授权写入。未获得显式 live mutation 授权时,审计浏览器只能放行 `GET``HEAD``OPTIONS``POST``PUT``PATCH``DELETE` 以及其他可能改变状态的方法必须被拦截并 abort,报告时统一标记为 `audit guard blocked page mutation attempt`,同时记录 method、path、触发的页面动作和已拦截事实。这个证据只能证明页面渲染、只读请求和某个交互会尝试发起写请求;它不能证明 backend outage、写入失败、写入成功、持久化状态变化或 mutating workflow 已验收。需要真实点击、提交、启动、停止、保存、删除、训练或其他 live-mutating acceptance 时,必须先取得针对目标服务、动作和环境的明确授权,并按授权后的验证规则单独记录结果。
每次新派一批任务、接收一批 completed unread 结果,或者发生实质态势变化时,都要同步更新 `#20` 的正文主表;如果当天有滚动简报,则同时更新当日简报 issue 的正文主内容,而不是只在聊天中补上下文。
## DEV 测试授权分级
`DEV` 只说明目标环境,不自动说明允许的写入级别。所有 runner prompt 和 supervisor closeout 都必须把 DEV 验证分成 `read-only``live-read``live-mutating` 三类;如果 prompt 没有显式分类,默认按 `read-only` 处理。
| 分级 | 含义 | 常见允许动作 | 禁止动作 |
| --- | --- | --- | --- |
| `read-only` | 不连接或不观察正在运行的 DEV 服务,只验证源码、fixture、mock、dry-run 或静态输出。 | `git diff``rg`、语法检查、CLI `--dry-run`、生成计划或补文档。 | 访问 live service、触发任务、写数据库、部署、重启、rollout、真实硬件或虚拟硬件动作。 |
| `live-read` | 读取正在运行的 DEV 服务、日志、health、status、metrics、Kubernetes 只读对象或只读 API,不改变 live 状态。 | `GET /health``GET /status`、只读 proxy、`kubectl get/describe/logs`、只读 CLI status/diagnostics。 | `POST/PUT/PATCH/DELETE``kubectl apply/delete/rollout restart`、触发 schedule/job/task、写 issue/PR 之外的 runtime 状态、任何会创建 operation/audit/evidence 的动作。 |
| `live-mutating` | 在 DEV 环境执行会改变 live 状态的命令,即使目标是 smoke、复测或诊断。 | 经 prompt 明确授权的 dev deploy/apply/rollout、trigger/run/retry、task submit/steer、写配置、创建 operation/audit/evidence、HWLAB M3 DO/DI 链路触发。 | 任何未被 prompt 精确列出的 live mutation;生产写入、密钥读取、数据库手工 patch、Code Queue 高风险干预仍按更高安全边界处理。 |
`DEV smoke``M3 smoke``live smoke``复测``验证` 这类词本身不构成 live mutation 授权。只要命令会改变 DEV runtime、触发真实或虚拟设备动作、创建任务/operation/audit/evidence、改变 deployment 或写入服务状态,就必须归入 `live-mutating`
派单 prompt 必须显式写出:
- `DEV test class`:只能是 `read-only``live-read``live-mutating`
- `允许的 live mutation`:若 class 是 `live-mutating`,必须逐项列出允许的命令形态或动作、目标环境/服务/namespace、可接受的状态变化、观察和回滚步骤;若没有授权,写 `none`
- `禁止动作`:至少说明 prod mutation、密钥明文、数据库手工 patch、Code Queue backend 重启/重建、运行中任务 interrupt/cancel 是否禁止;未写明的高风险动作一律禁止。
- `closeout 字段`runner final response 必须报告实际执行的 test class、是否发生 live mutation、执行命令摘要、目标环境、证据链接或 ID,以及未覆盖风险。
runner 收到未分类或含糊的 prompt 时,只能执行 `read-only` 范围;如果完成任务需要 `live-read``live-mutating`,必须停在计划和待授权状态,列出拟执行命令、风险和需要指挥官补充的授权,不能自行把“DEV”解释成允许写入。
supervisor closeout 不能只看 runner 的成功自述,必须核对 prompt 授权和实际命令级别:
- `read-only` closeout 应证明没有 live service 写入,证据来自 diff、静态检查、语法检查或 dry-run 输出。
- `live-read` closeout 应记录读取的 DEV endpoint、service、namespace 或日志范围,并明确没有触发 runtime 状态变化。
- `live-mutating` closeout 应指出 prompt 中的明确授权、实际变更目标、operation/audit/evidence/task/job ID、回滚或恢复观察,以及 prod 未触碰。
- 如果 runner 在没有明确 prompt 授权时执行了 live mutation,即使 smoke 结果成功,也不能把任务验收为正常完成;指挥官应先核实 live 状态和 blast radius,再把它记录为治理缺陷或 follow-up,并修正后续 prompt 模板。
HWLAB M3 口径使用同一分级:只读报告、fixture、LOCAL/DRY-RUN 和 diagnostics 只能算 `read-only``live-read`;触发 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` 的可信闭环属于 `live-mutating`,必须有 prompt 明确授权并在 closeout 中给出 operation / audit / evidence 关联。
## 任务设计
每个 AgentRun task 都必须有清晰且狭窄的 ownership 边界。
- 尽量每个任务只负责一个服务、模块或基础设施缺陷。
- 每个任务使用共享 workspace 下自己的 detached worktree。
- 在 prompt 中直接写明写入范围、验证范围、提交/推送要求和禁止动作。
- 相关背景必须写进 prompt;issue 链接只能作为辅助引用,不能作为必要上下文。
- 优先复用已有队列;只有现有 lane 无法表达 ownership 边界时,才创建新队列。
- 队列并发必须受真实执行能力约束。通常目标是约 5 条并发 lane;当活跃任务写入范围彼此独立、heartbeat/trace 证据健康、成功率可接受时,指挥官可以把并发提高到约 10。若完成质量下降,应先降并发再继续扩张。
靠近生产的任务 prompt 必须明确禁止在 master server 上跑已知可能 OOM 的重型本地检查,并说明哪些验证应在 D601 CI、dev env 或目标服务容器中执行。
当一个指挥机需要突发创建大量 AgentRun 任务时,`agentrun create task``agentrun apply -f -` 默认应串行或接近串行。为了避免控制面在确认任务前被打爆,可以使用短本地锁或短延迟,尤其是在低内存主机上。目标是保持任务创建可观测且稳定,而不是最大化瞬时入队吞吐。
## 模型和成本路由
AgentRun 新派单和历史 Code Queue 审阅都按成本、可信度和 blast radius 分层:GPT-5.5/Codex 处理高风险和复杂任务,DeepSeek/OpenCode 处理中等复杂度且边界清晰的任务,MiniMax/OpenCode 处理简单、低权限、可复核任务,生产重启、密钥、数据库手工写入和运行中任务控制保留给指挥官或人工。
当前新任务派发合同由 `bun scripts/cli.ts agentrun get|describe|events|logs|result|ack|cancel|dispatch|create|apply|steer|send` 资源原语暴露:`get tasks --queue commander` 查看指挥官队列,`create task --aipod Artificer --prompt-stdin``apply -f -` 创建任务,`dispatch task/<taskId>` 派发,`events/logs/result/ack/cancel/steer/send` 读取和控制 AgentRun task、run 与 session。UniDesk 是 render-only client:日常一次性 YAML/JSON 和 prompt 输入优先用 quoted heredoc/stdin,客户端按 `config/agentrun.yaml` 直连 AgentRun REST API 并保留 k8s 风格渲染;`--json-file``--prompt-file``--runner-json-file` 只是客户端输入来源。该路径不经过 HWLAB runtime、SSH official CLI 或旧 bridge wrapper,不做旧 Code Queue 双写,也不迁移旧历史。
`codex submit/enqueue``codex steer``codex resume`、旧 queue mutation、task move 和旧 workdir mutation 已冻结。CLI 必须返回 `ok=false``frozen=true``degradedReason=legacy-code-queue-frozen` 和 AgentRun 替代命令;服务端旧 API 写入口必须返回 410。旧 `codex task/tasks/output/read/unread/queues` 继续作为历史归档和只读排障入口,`codex interrupt|cancel` 只用于停止残留旧任务。
新任务模型由 AgentRun task payload 和 AgentRun runtime 配置决定;旧 Code Queue 的 `CODE_QUEUE_MODELS` 只作为历史任务审阅和残留运行面配置参考,长期合同至少包含 GPT-5.5、GPT-5.4、GPT-5.4 Mini、DeepSeek Chat、MiniMax M3 和 MiniMax M2.7 两路并行配置;`deepseek`/`deepseek-chat``minimax-m3``minimax-m2.7` 会走 OpenCode port,其余模型走 Codex port。PROD 集群把 `MINIMAX_MODEL` 切到 `MiniMax-M3`M3 是新任务的默认 provider model),judge 与 opencode 跟随;M2.7 仍然作为并行配置存在,切换只需把 `MINIMAX_MODEL` 改成 `MiniMax-M2.7` 后 rollout restart。两者不存在自动 fallback 关系:M3 任务失败不会自动改派 M2.7,task 要用 M2.7 必须显式 `--model minimax-m2.7`。只有当执行面 `/health` 或等价配置已经显示 DeepSeek 模型可用、并完成轻量 runner smoke 后,才允许真实提交 `--model deepseek-chat`
AgentRun 派单边界由指挥官直接审查和负责,不再通过额外本地派单审查命令。新任务 prompt 仍必须自包含,并写清写入范围、验证范围、禁止动作、是否允许运行态变更、提交/推送/PR/merge 边界和 closeout 字段;这些要求属于调度质量责任,不是额外 CLI guard。
Device Pod 类 DS 派单必须把工具可用性设计进 prompt,而不是靠事后强制纠偏。prompt 应明确唯一 pod、workspace selector、目标工程/target、允许的 live mutation、禁止的 pod/BOOT/生产/密钥/数据库范围和 closeout 字段;文本源码修改默认要求 `hwpod ... workspace apply-patch`,新文件使用 `apply-patch --add-file`,整文件替换使用 `apply-patch --replace-file`,不要优先 `workspace put`。命令入口默认写短别名 `hwpod`,不要写长路径 `node /app/skills/device-pod-cli/scripts/device-pod-cli.mjs``hwpod` 必须作为 Code Queue 镜像和 provider dev container 的 PATH 命令存在,并从 `DEVICE_POD_CLI``UNIDESK_SKILLS_PATH/device-pod-cli`、当前 workspace 的 `skills/device-pod-cli``tools/device-pod-cli.mjs` 解析真实 CLI。添加 Keil 源文件、build clean、download、UART/JSON-RPC smoke 也应走 `hwpod`。prompt 中只允许把 `/app/tools/tran.mjs``/app/tools/hwlab-gateway-tran.mjs`、临时 Python/PowerShell/JS 上传脚本列为禁止绕行;如果 DS 仍然需要这些绕行,指挥官应先把缺失能力补进 `device-pod-cli`/`hwpod`,再重置 workspace 让 DS 复测。
Device Pod 类 DS 验收不能只看最终回复。指挥官必须用 `codex task <taskId> --trace` / `codex output <taskId>` 审计实际命令面:确认是否使用 `hwpod`,是否出现长 CLI 路径、`tran.mjs``hwlab-gateway-tran.mjs`、临时脚本上传、`workspace put` 或构建产物 patch/put/delete;同时核对 build job、download job、UART/JSON-RPC 或屏幕/串口等硬件证据。若任务因为模型上游 429/503、transport 断连或 Code Queue continuation 被错误降级而没有进入工具调用,不应把它记作 device-pod-cli 失败样本,应先处理调度/运行面摩擦,再重新派发干净任务。
并发治理按模型和风险一起决定。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、明确 dry-run 或语法验证 | prompt 自包含、写入范围窄、无生产/密钥/DB 写入、验证命令明确、指挥官审阅 | 不处理 Code Queue runtime、backend-core、provider-gateway、k3sctl-adapter、release/v1 或部署变更 |
| MiniMax/OpenCode (M3 / M2.7 并行) | 只读调查、文档、简单前端/样式、低风险样板、轻量 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 输出、参数校验、错误分类 | dry-run JSON、语法检查或原入口命令输出 | 不改 runtime 调度核心,不触碰生产服务 |
| 局部回归验证 | 用户明确要求时才补最小测试,否则只做语法/命令形态检查 | 验证命令、失败前提、通过输出 | 不跑 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 任务涉及远端文本修改时,prompt 必须显式指定标准写入入口和失败恢复动作:默认使用 workspace-prefixed `trans <route> apply-patch < patch.diff` 或对应业务 CLI 的 `apply-patch` 子命令;若 stderr 报 `failed to find expected lines`,必须重新读取当前目标块,缩小或拆分 `Update File` hunk 后继续 `apply-patch`。不得把上下文过期当作改用 `download`/`upload`、远端 Python/Perl/sed heredoc、`cat >`/`tee` 整文件重写或 `apply-patch-v1` 的理由。指挥官验收 MiniMax trace 时应搜索这些 forbidden command 形态;若出现,优先修 CLI hint/prompt 或拆小任务后复测,而不是把绕行作为合格完成。
对 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 的替代品。
长任务和跨回合排障应把专题 issue 的评论区作为进展锚点。调查结论、细化方案、阶段性修复、rollout 状态、阻塞原因、复测 trace、最终验收和后续风险都应追加到同一个专题 issue 评论中,并引用相关 PR、commit、job、trace 或 runtime revision;正文只保留稳定背景、范围、验收标准和当前摘要,不写成每一步流水账。上下文压缩、切换指挥官或恢复中断后,先读取专题 issue 最新评论,再继续执行,避免只依赖聊天记忆或本地临时文件。写评论必须使用 `bun scripts/cli.ts gh issue comment create ... --body-file <file|->`,长正文不得用 shell 参数拼接。
如果某个 worker 任务需要依赖 GitHub issue 内容,但 runner 的 issue 可达性尚未被单独验证,指挥官不能默认 worker 已能读取该 issue。此时 worker prompt 必须直接内嵌完整需求、约束和验收点,issue URL 只能作为辅助引用。若要把 issue 作为任务输入源,先单独做可达性探测,再决定是否把 issue 作为常规前置条件。
### 长期总看板治理
`#20` 是指挥入口和当前态势摘要,不是全量 issue 仓库、历史流水账或验收直播页。它必须帮助指挥官在低上下文成本下判断当前最高约束、当前阶段、P0/P1 直达项、用户反馈和专题入口;具体证据、历史表格、完成记录和专题展开应放在归档 issue、专题 issue、每日指挥简报或对应业务 issue 中。
当总看板正文超过约一百二十行、正文体量接近或超过一万五千字符、OPEN/CLOSED 明细行超过四十行,或指挥官需要滚动很久才能看到当前重点时,应触发总看板瘦身。瘦身流程固定为:先用 `gh issue board-audit --board-issue 20 --dry-run` 记录旧正文长度、行数和 body SHA;再创建归档 issue 保存清理前完整正文;随后把 OPEN 项按业务域归纳成约四到六个专题 issue;最后替换 `#20` 正文,只保留当前指挥入口、当前阶段、P0/P1 直达表、用户反馈表、专题总表、每日简报索引、维护规则和归档入口。当前阶段表固定使用 `维度``当前判断``关键约束` 三列;用户反馈表必须包含百分比进度;专题总表必须包含 `承接入口``下一步重点`。已关闭事项和历史更新段不得继续留在 `#20` 正文中。
专题 issue 的职责是承接展开信息,不替代单个业务 issue。每个专题 issue 应写清范围、关联 issue、当前判断、主要阻塞、下一步推进方式和验收口径;专题 issue 只做归纳和入口,不应复制每个业务 issue 的完整历史。总看板中的专题总表只保留专题 issue、范围、当前状态、最高优先级项和下一步动作。
每日指挥简报必须独立成 issue,并由 `#20` 的简报索引引用。日内滚动记录、completed unread 审阅摘要、任务证据和历史更新都写入当日简报或对应 issue;不得在 `#20` 追加日期段落。若需要向用户展示近期指挥官工作情况,在 `#20` 的当前阶段区域放简短表格索引,不写长段流水。
每日或专题进展简报默认采用语义化写法,而不是 PR/commit 时间线复读。指挥官先按用户可理解的能力域归类,再用中文列表说明“完成了什么能力、解决了什么摩擦、对使用者有什么影响”;PR 号、commit、测试命令和 live revision 只作为证据补充,不作为正文主语。HWLAB v0.2 类工作常用三段是 `Code Agent 改进``device-pod 改进``基础设施改进`;其他项目应按真实工作内容选三到五个语义域。每段保留四到八条短句,优先描述当前可复用能力、体验变化、稳定性提升和仍需观察的风险,避免写成“几点几分合并某 PR”的流水账。若需要列出审阅发现或风险,把它们放在简报前后的独立小节,不能混入进展 bullet 冒充已完成成果。
`#20` 当前仍受 body profile 保护,正文必须保留 `## 看板(OPEN` heading;该 heading 可用于承载紧凑的 P0/P1 直达表或当前活跃入口,不再要求恢复旧式 OPEN/CLOSED 全覆盖明细表。`gh issue board-audit` 只做只读结构审计,不再负责检查 GitHub open/closed issue 是否被表格完全覆盖;维护旧式表格时才使用 `board-row` 系列命令。
GitHub issue/PR 操作应优先使用 UniDesk CLI 的安全入口:`bun scripts/cli.ts gh auth status``gh issue list/read/view/create/update/comment create/comment update/comment edit/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 update/comment edit/comment delete/close/reopen`。该入口默认 repo 是 `pikasTech/unidesk`,支持 `--repo owner/name`,输出稳定 JSON,并把 `missing-binary``missing-token``auth-failed``github-transient``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 应用它区分基础设施阻塞和业务/参数失败。`github-transient` 专指 GitHub DNS 或 API 连接在收到 HTTP 状态前失败,例如 `Temporary failure in name resolution``Could not resolve host: github.com/api.github.com``error connecting to api.github.com`;它必须带 `retryable=true` 或等价 retry/backoff 指示,并且不是 `missing-token``auth-failed``scope-insufficient``validation-failed` 或 PR 语义失败。指挥官看到这类结果时,优先重试或退避;如果对应 Code Queue 任务 heartbeat/trace 仍新鲜,应保持任务运行并继续监督,不要立即 close/requeue 业务工作。runner 不应直接运行系统 `gh auth status` 并把输出贴入 Code Queue 日志;系统 `gh` 的 masked token 行仍会暴露 token 前缀和 scope 片段。需要验证当前 runner GitHub auth 时使用 `bun scripts/cli.ts gh auth status --repo pikasTech/unidesk``bun scripts/cli.ts codex pr-preflight --remote`,输出只能保留 token 是否存在、来源、长度和掩码,不得打印 token 值或 token 片段。Code Queue 输出层必须在保留 command output、trace、raw output 页面和 commander 摘要前 redaction `gh auth status` 风格 token 行,并给出 UniDesk CLI wrapper 提示。`gh issue list --state open --limit N --json number,title,state,closed,closedAt,url` 是有界 issue 发现入口,`--state` 只接受 `open|closed|all`list 字段白名单是 `number,title,state,closed,closedAt,url,updatedAt,createdAt,author,labels`;未知 state 或未知字段必须失败,不能静默返回空数组。`gh issue view <number> --json body,title,state,closed,closedAt` 是 canonical 入口,`read` 只保留为兼容别名,正文仍应从 `.data.issue.body` 读取。单 issue/PR/comment 数字目标命令兼容 `--number N`,但成功响应必须带 `standardSyntaxHint` 提示标准位置参数写法;comment update/edit/delete 中的 `--number` 表示 commentId。未知 `--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` 只读审计目标 board issue 正文结构,返回正文长度、行数、body SHA、可解析 Markdown board sections、section 行数和 parser warnings;它不再拉取 GitHub open/closed issue 列表,也不再校验 OPEN/CLOSED 表覆盖关系。兼容字段 `missingOpenIssues``closedInOpenRows``missingClosedRows``rowValidationWarnings``ignoredIssues``recommendedActions` 仍保留为空数组或 0。显式 `gh issue update <number> --body-profile commander-brief` 可用于 #24 legacy 简报和每日滚动简报 issue;每日简报 issue 应用标题 `YYYY-MM-DD 指挥简报(北京时间)` 或在既有正文首行/关键 heading 中标明简报身份,且新正文必须包含 `## 常驻观察与长期建议`。对非简报 issue 使用该 profile 应失败为 `profile-issue-mismatch`。需要维护旧式 OPEN/CLOSED 明细表时,继续使用 `gh issue board-row list --board-issue 20 --state open|closed|all``gh issue board-row get <issueNumber> --board-issue 20``gh issue board-row update <issueNumber> --board-issue 20 --field progress|status|validation|branch|tasks|focus --value <text>``board-row update` 只替换一行一个单元格,输出 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 --json ...` 支持 `body,title,state,number,url,author,head,base,draft,createdAt,updatedAt` 字段白名单;`gh pr read|view --json ...` 还支持 `stateDetail,closed,closedAt,merged,mergedAt,mergeCommit,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup``stateDetail=open|closed|merged` 用于区分 REST `state=closed` 中的普通关闭和已合并;`closed*``merged*``mergeCommit` 和分支名字段都来自 REST。只有 mergeability/check rollup 需要请求 GraphQL,适合 PR 收口前判断可合并性和检查汇总。GraphQL 权限不足、网络失败、GitHub 仍返回 `UNKNOWN`/null、或需要 UniDesk CLI 尚未开放的官方字段、review/merge 操作时,回退系统 `gh` 只读观察或 GitHub UI;不要把缺失元数据当成已可合并。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` 是 guarded write:先执行 closeout preflight,只在 open、非 draft、无冲突、merge state CLEAN 且 checks 无失败/pending 时调用 GitHub REST merge`--dry-run` 只输出计划不写远端。
CLI 是短 shout 的需求原语,不是长驻服务器进程。CLI 功能不好用、兼容性不足、安全 guard 不够或输出不利于 runner/指挥官使用时,应默认创建 GitHub issue 并用 Code Queue 推进;这类 CLI 问题走 `master`、remote commit、语法/命令形态验证和文档更新,不套用 backend-core、Code Queue runtime 这类运行态服务的重部署门禁。除非用户明确要求,CLI 改动不做单元测试、合同测试或新增测试脚本。若 CLI 缺陷已经阻塞当前指挥,可以先做最小安全绕行,同时把长期修复写入 issue 并派单。
所有 GitHub Markdown 正文写入优先使用 `--body-stdin``--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 comment create|update|edit``gh pr comment create|update|edit` 都支持 `--body-stdin` 作为多行 Markdown 的第一等入口,`--body` 仅适合短单行文本。`gh issue` 正文更新主入口仍是 `update --mode replace|append --body-stdin|--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 任务的默认出口。UniDesk 默认集成目标仍是 `master`,但不再禁止任务分支;当变更风险高、跨模块、需要人工审查、或任务目标明确要求 PR 交付时,worker 可以创建 PR。PR 型任务必须报告源分支、目标分支、PR URL、关联 issue、测试证据和未完成风险。禁止把 PR 当成隐藏分支仓库;PR 分支必须来自最新目标线,保持小而可审查,并在合并后确认目标分支远端 commit 可 fetch。
PR handoff 的职责默认分开:runner 实现、测试、提交、push head branch 并创建 PR;指挥官监督并发、steer、审阅、确认 checks 和合并裁决。短期内 GPT-5.5 runner 如果收到明确 PR 收口授权,并且 PR 是普通 UniDesk source 变更、checks 满足任务要求、无冲突且不涉及 prod/runtime/release/security/database/破坏性回滚,可以自行用 repo-owned GitHub merge/close 路径完成收口并报告 SHA。高风险、边界不清、checks 失败或用户/指挥官保留 final action 的 PR 仍必须交回 commander 审查。host commander 也不把直接编辑业务代码当成常规 PR 替代路径。
PR 支持本身是 Code Queue 能力的一部分。当前 UniDesk CLI 支持 `gh pr list|view|create|update|comment create|comment update|comment edit|comment delete|close|reopen`,其中 create 需要显式 `--title``--base``--head` 和正文来源,update 需要显式 PR number、正文来源和 `--mode replace|append`comment create/update/edit 需要显式 commentId 或目标 shorthand 和正文来源,且推荐使用 `--body-stdin``--body-file`。PR 收口观察应使用 `gh pr view <number> --json state,stateDetail,closed,closedAt,merged,mergedAt,mergeCommit,headRefName,baseRefName,mergeable,mergeStateStatus,statusCheckRollup` 获取普通关闭/已合并区分、merge commit、目标分支、源分支、mergeability 和检查汇总;该路径仍是只读元数据,不执行 merge,且 `closeoutMetadata.ok=false``missingOrUnknownFields` 或 GraphQL failure 都只能作为“需要人工复核/重试”的信号。`pr create --dry-run``pr update --dry-run``pr comment create/update/edit --dry-run` 只返回 planned operation,不创建 PR、不更新正文、不写评论;非 dry-run 创建前会校验 repo、base、head 和 compare ahead 状态,append 更新会先读取当前 PR body。`gh pr list` 不开放 mergeability/statusCheckRollup 列表字段,避免默认拉取 noisy/raw 状态汇总。`gh pr delete` 在 UniDesk REST CLI 中返回 `unsupported-command`,不能伪造硬删除;需要移除活跃 PR 时使用 `gh pr close``gh pr merge` 是 guarded REST write,没有 `--confirm` 可以绕过 preflight;获得收口授权的 GPT-5.5 runner 可使用 UniDesk `gh pr merge`、GitHub UI 或等价 repo-owned GitHub merge path 处理普通 PR,并报告结果 SHA。需要 PR 交付时,prompt 必须明确允许的人工、runner 或后续工具路径,并报告未覆盖范围。
### 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 目标分支;除非 prompt 明确授予普通 PR 收口权,否则禁止 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/close 状态和 SHA 或未 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;除非本 prompt 明确授权普通 PR 收口,否则不得 merge PR。
- 创建 PR 前先运行只读/dry-run preflight,确认 GH_TOKEN/GITHUB_TOKEN、GitHub egress 和 repo 可见性,不得打印 token。
- final response 必须报告 head branch、PR URL、远端 head commit、修改文件、验证命令、merge/close 状态和 SHA 或未 merge 原因。
```
GPT-5.5 PR/收口类 prompt 由指挥官在提交前直接审查。legacy `codex submit` 已冻结,新任务 payload 只走 AgentRun `create/apply` 资源原语;不得再把额外本地审查命令当成派单 admission、业务 PR 门禁或生产风险豁免依据。
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”。默认输出必须优先给出有界的 `authScopeSummary``scopeBoundary``activeRunnerDevContainer``recommendedActions``authScopeSummary` 用一句话说明 scheduler auth missing 只是 scoped finding`scopeBoundary` 明确 scheduler env 与当前 CLI/dev container 是独立 scope`activeRunnerDevContainer` 只报告当前 CLI 进程是否看见 token,且不打印 token 值;`recommendedActions` 保持低噪声,先给 active task 内的 `bun scripts/cli.ts gh auth status --repo pikasTech/unidesk``gh pr create --dry-run`,再给 scheduler 侧长期的 auth-broker 或 runtime secret 修复。指挥官看到 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。GitHub DNS/API 瞬时连接失败必须返回 `failureKind=github-transient``degradedReason=github-dns-api-transient``retryable=true` 和低噪声 `githubTransient.failedProbes` 摘要;这与 `auth-missing``git-remote-gap``proxy-gap``validation-failed` 或 PR 语义失败分开处理。系统 `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 缺失只作为证据,不是最终主阻塞,并应额外标成 `blockingDisposition=runner-local-observation-gap``localObservationGap.kind=runner-local-observation-gap`。若远程控制面可达,输出继续保留 ready preflight;若远程控制面不可达,结构化失败归类为 `failureKind=control-plane-missing` / `degradedReason=remote-control-plane-unreachable`,并额外标成 `blockingDisposition=control-plane-observation-gap``runnerDisposition` 可以为了旧调用方兼容继续保持 `infra-blocked`,但 observation-gap 字段才是判断“观测路径缺口,不是 scheduler 停摆”的稳定口径。输出中的 `prCapabilityContract` 用于指挥官快速审查 runner handoff:目标分支固定显示、push/PR create dry-run 标记为不写远端、系统 `gh` binary 与 UniDesk REST `bun scripts/cli.ts gh` 可用性分开报告,且 merge 能力必须指向 guarded `gh pr merge --dry-run` 预检路径。
本地 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`。provider dev container 由 scheduler 通过 Docker 启动时,也必须把同一宿主 source 只读 bind 到同一 target,并把 `UNIDESK_SKILLS_PATH` 显式传给 Codex/OpenCode 进程。target 缺失时即使 approved source 可读也不能 fallback 给 runnerhealth/preflight 必须标记 `runnerUsable=false``contractOk=false``resolvedPathSource=missing``degradedReason=skills-target-missing``resolution.hostRolloutRequired=true`。不要使用或传播任何拼错的 skills 路径;如果配置的 source 或 target 命中拼写错误路径,health/preflight 必须直接返回 `blocker=forbidden-skills-path-configured`,并在 `pathSpelling.forbiddenPathConfigured=true``pathSpelling.forbiddenPathRoles` 中标明是 source、target 或两者,而不是降级成普通 missing path。
执行面 `/health``/api/dev-ready``/api/runtime-preflight` 必须输出同一份只读 skill availability report。稳定字段包括 `source``target``resolvedPath``resolvedPathSource``resolution``requiredSkills``missingSkills``sourceSkillCount``targetSkillCount``degraded``degradedReason``blocker``pathSpelling``valuesPrinted=false``requiredSkills` 至少覆盖 `docs-spec``cli-spec``frontend-design``playwright-cli`;如果 source 与 target 都缺失、必需 skill 均不可用、拼写错误路径被配置或拼写错误路径已存在,报告必须显示 `ok=false` 和结构化 `blocker`,不能把 runner 能力缺口伪装成业务任务失败。target symlink 到 approved source 属于可接受的兼容修复,必须显示 `resolvedPathSource=target-symlink` 和有界 skill count。
`codex pr-preflight --remote` 默认视图必须保留同一份可操作 `skillsContract`,不能只给出模糊的 `skills-target-missing`。稳定字段包括 `source``target``resolvedPath``resolvedPathSource``requiredSkills``missingSkills``sourceSkillCount``targetSkillCount``sourceMissingSkills``targetMissingSkills``hostRolloutRequired``degradedReason``blocker``repairHint``pathSpelling``valuesPrinted=false`。当 `/api/runtime-preflight` 的旧 `skills` report 缺少 `resolution` 或 counts,但 `skillsSync` 已证明 approved source 可读且 target 未投影时,CLI 必须从 `skillsSync` 合成同一份 `skillsContract`,并显示 `hostRolloutRequired=true` 与修复指令。`--full``--raw` 可以展开完整 `skills``skillsSync`、tool 和 transport 观测;默认输出仍保持低噪声,只保留指挥官能直接判断和恢复的字段。
执行面还必须提供 dry-run skills sync/preflight 合同:稳定入口是 `GET /api/skills-sync?dryRun=1`CLI 入口是 `bun scripts/cli.ts codex skills-sync --dry-run [--full]`。该合同只描述受控 hostPath 生命周期,不复制文件、不从任意路径静默加载、不重启服务、不 rollout Pod、不读取 Secret。默认输出保持紧凑,必须报告 source、target、expected env/mount、required skill 列表、source/target skill counts、missing source/target skills、permission failure count、plannedActions 和修复指令;逐 skill 细节、完整 permission failure 和原始报告只能通过 `--full` 显式展开。非 dry-run 请求必须失败。
受控生命周期是更新宿主 `/home/ubuntu/.agents/skills` 这一 approved source,然后让生产和 dev Code Queue Pod 通过 manifest 中的 read-only hostPath 挂载读取 `/root/.agents/skills`provider dev container 还必须通过启动脚本把同一 source bind 到同一 target。在线热更新只能作为临时恢复手段,长期验收必须以 manifest/source-of-truth、runner container bind、dry-run sync surface 和结构化 health/preflight 为准。需要验证时优先运行:
```bash
bun scripts/cli.ts codex skills-sync --dry-run
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/close 状态。
- contract/dry-run 证据覆盖本次 PR 能力:`pr create --dry-run``pr list/view``pr comment --dry-run``pr merge --dry-run` guarded plan;若 runner 被授权最终 merge/close,还要报告使用的 repo-owned GitHub 路径和结果 SHA。
- 没有 token、凭证、临时日志或构建产物进入 commit、PR body 或评论。
- 未授权 runner 收口的 PR 由指挥官审查并决定是否 merge;已授权 runner 收口的普通 PR 在合并后仍要验证目标分支远端 commit 可见,并按态势更新 issue/#20/#24
### Runner Resume 收口
PR 小修、冲突、rebase、补测和 reviewer feedback 的新执行入口是 AgentRun 资源原语。仍在 AgentRun session 内的工作优先使用 `bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin``send session/<sessionId>`;已沉淀成新工作项时使用 `bun scripts/cli.ts agentrun create task --aipod Artificer --prompt-stdin``agentrun apply -f -`。旧 `codex resume` 已冻结,不再作为 follow-up turn 入口。
旧 Code Queue task 只保留历史审阅和残留停止;需要基于旧任务产出继续推进时,在 AgentRun payload 中显式引用旧 task id、PR/branch 和审阅结论,而不是把旧 task 重新入队、resume 或 double-write。
AgentRun turn 的 timeout 监督按无响应空闲时间处理,而不是固定 wall-clock `backend-timeout`。只要 result/session liveness 的 `lastActivityAt``lastActivitySeq` 或 events 仍在刷新,指挥官应继续轮询,不应 interrupt、重派或判定 backend 死亡。若 command 因 idle timeout、provider stream disconnect、runner stdio inactive 或其他非业务终态停止,指挥官本人必须先读 `result``events``logs/trace`,确认最后有效工具输出、已完成修改、失败原因和下一步,再把这个摘要作为后续 prompt 发送给 Artificer;不能要求 Artificer 自己去猜旧 trace,也不能因为一次 timeout 就停止整个交付。
Artificer 默认应携带可续跑 `sessionRef`。仍有 `sessionId` 的 follow-up、补测、reviewer feedback 和 timeout 恢复,优先使用 `bun scripts/cli.ts agentrun send session/<sessionId> --aipod Artificer --prompt-stdin``steer session/<sessionId>` 继续同一个 session;只有历史任务没有 `sessionRef`、session 已 evicted、或同 session 已证明不可恢复时,才创建新 AgentRun task。新 task 必须在 prompt 中写明“这是基于旧 task/trace 的 manager-read continuation”,并记录旧 task/run/branch、管理者读 trace 得出的当前状态和下一步。
replacement runner 只用于方向明显错误、质量不可接受、原 task 上下文不可恢复、原分支/PR 已废弃,或 AgentRun reuse/steer 已证明无法继续的情况。关闭或替换旧 PR 时必须在 PR/body/final response 中说明 superseded/replacement 关系,避免 competing branch 扩散。
## 监控
指挥官必须用 task 级和 queue 级证据监控 Code Queue,不能只看单一状态字段。
常用入口:
- `bun scripts/cli.ts codex tasks --view commander --limit N`host commander 轮询的推荐入口。输出是有界 action map,必须直接显示 `activeRunners.count`、计数来源、split-brain/heartbeat 处置、queued/retry_wait 精确计数、terminal-unread 总数和已省略行数、active 风险数、stale/heartbeat/trace gap、`finalResponse` 已出现但仍非终态的 awaiting terminal/judge、blocker-like final response、HWLAB#7/#99/#116/#164/#317 与 UniDesk#20/#118 命中、任务分类和下一步 drill-down 命令。默认不得输出完整 prompt、完整 final response、raw output、完整 trace 或 raw overview;需要详情只能按 task id 使用 `codex task``codex task --trace``codex output``codex read``rawOverview` 命令渐进展开。
- `bun scripts/cli.ts codex tasks --view supervisor --limit N`:查看旧 Code Queue 历史默认低噪声监督视图,包括 `activeRunning`、running、完成未读、少量最近完成、queued/runnable、activity、commanderConcurrency、execution diagnostics、任务分类和下一步 drill-down 命令。默认行只保留 task id、队列、短 prompt/body 预览和原始字符数;`--limit` 是扫描/分页预算,不是返回几十条肥行的开关,CLI effective limit 安全上限为 100,输出必须用 `filters.requestedLimit``filters.effectiveLimit``filters.limitCapped``source.requestedLimit``source.effectiveLimit` 区分用户请求、CLI cap 和 overview 源拉取预算。新任务派发和 follow-up 不再使用旧 `codex submit/resume/steer`,统一走 AgentRun 资源原语。
- `bun scripts/cli.ts codex queues`:默认是 commander-first 队列态势摘要,`--commander` 是显式同义开关。输出前部固定使用 `.data.queues.commander`,先给出 `activeRunnerCount``source``target=15``slotDeficit``queuedCount``runningTasks``heartbeat.fresh``heartbeat.risk``heartbeat.staleRecoveryCandidates`、active/runnable queue 小页和 drill-down 命令;历史 queue item 列表保留在 `.data.queues.items[]`,但只是分页的次要行。需要完整队列行视图时加 `--full`,但 `--full` 仍默认分页,继续用 `--limit N``--page N``--offset N` 渐进展开。summary 和 full 都使用稳定 JSON path `.data.queues.items[]` 读取队列行,并从 `.data.queues.commander``.data.queues.commanderConcurrency``.data.queues.activity``.data.queues.counts``.data.queues.executionDiagnostics` 读取全局活跃计数和执行诊断;完整 upstream 只通过输出中的 raw command 显式获取。若 `/api/queues` 没有返回 task row`runningTasks.items[].name` 会是 `null``nameSource=not-returned-by-api-queues`,此时按返回的 `codex task <taskId>` 或 supervisor 命令展开,不要假设任务没有名称。
- `bun scripts/cli.ts codex execution-plane [--full|--raw]`:只读巡检 D601 原生 k3s `unidesk` namespace 下的旧 Code Queue 执行面。该命令用于历史归档和残留任务诊断,不作为新任务能力门禁;新任务真实运行面验收走 AgentRun `v0.1` queue/session 原入口。默认不打印完整 Kubernetes Deployment JSON、环境变量全集、SecretRef 值或命令 stdout;需要逐项展开时使用 `--full`,需要安全裁剪后的原始观察对象时使用 `--raw`
- `bun scripts/cli.ts codex unread --limit N`:查看完成未读审阅积压的默认 triage,按 repo、issue、status 和 queue 汇总,并给出有界最新任务紧凑行;默认行只包含 task id、状态、queue、issues、updatedAt/finishedAt 和一条 `nextStep`,不重复每任务 `show/detail/trace/output/read` 命令,也不输出 raw prompt、final response、trace 或 output。完整 per-task 命令必须显式使用 `codex unread --full``codex unread --view full``codex unread list` 或单任务 `codex task <taskId>`/`codex read <taskId>` 展开;默认输出必须保留一次性的模板命令和分页命令。
- `bun scripts/cli.ts codex unread mark-read --repo owner/name --issue N --limit N --confirm`:批量已读入口,必须显式 `mark-read``--confirm`,否则结构化失败且不 POST `/read`
- `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`
- `bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin`:对 AgentRun 中仍可继续的 session 追加修正;旧 `codex resume` 已冻结。
- 当 master 控制面状态和 D601 scheduler 状态看起来分裂时,使用 `docs/reference/observability.md` 中的活性规则判断。
默认 commander/supervisor 视图必须保持低噪声。commander 视图用于回答“现在需要处理什么”,supervisor 视图用于看分区小页和红线细节。commander 的 `activeRunners.count` 是指挥官 active runner 计数,supervisor 的 `activeRunning.count` 是 running+judging 状态计数;两者都必须标明 exact/source,不能把返回行数当成并发总数。`activeRunning.count` 来源是 queue summary 的 status counts 时 `activeRunning.exact=true`,用于 redline 判断;`activeRunning.rowPage.returned` / `running.returned` 只表示本次返回的紧凑任务行。`activeRunning.redline` 必须写明 `countField`、routine target、burst redline、hard redline、`state``decisionReady`;只有 `decisionReady=true` 时,才能直接用该 count 做红线/补派判断。commander 的 `attention.items` 只返回最需要处理的有界任务,`attention.total/returned/omitted` 必须保留省略计数;`sections.recentCompleted` 不得重复 `sections.terminalUnread` 的未读终态。`running``completedUnread``queued` 即使传入较大的 `--limit`,默认也只返回一个很小的有界页,并通过 section `commands.next` 继续分页;`--limit` 保留为扫描/分页预算和 full view 返回预算,不得让一次 commander/supervisor 调用输出几十条肥行。每个任务行只应带 task id 和必要摘要,`show``detail``trace``output``full``read` 使用 section template 或 row commands 表达,让下一步渐进披露动作明确且不重复;默认不得嵌入完整 queue 列表、完整 final response、raw output 页或完整 trace 行。`recentCompleted` 必须默认限量,且不得重复 `completedUnread` 里的未读终态,避免完成历史把当前 running、阻塞和未读审阅挤出视野;需要完整当前页时显式使用 `--view full``executionDiagnostics` 只能展示有界 task-id/reason 预览、总数、截断标记和 omitted counts;需要全量诊断时使用输出中的 raw command。`commands.read` 只是在人工审阅后的建议命令,listing 命令绝不能自动执行。
commander 视图的任务分类必须是确定性字段,至少区分 `user-facing``cd-artifact``infra-governance``noise-report``workflow``infrastructure-blocker``unknown``infrastructure-blocker` 只能由强基础设施故障信号触发,例如 storage/PostgreSQL degraded、provider/k3s/proxy/auth 等基础设施上下文同时出现 blocked/failed/unreachable/timeout 等阻塞信号;普通 prompt 中的 runner、CLI、commander、supervisor、治理或历史任务上下文不得单独升级为 blocker,没有把握时使用 `workflow``unknown`。分类只用于监督优先级和噪声折叠,不替代任务验收;当 final response 带 blocker-like 语言、failed/terminal-unread、heartbeat/stale risk、trace gap 或 awaiting terminal/judge 时,分类再低噪声也必须进入 attention 或风险计数。
`codex tasks` 中的 `status` 永远是 scheduler/control-plane 原始状态,不因为看到 worker final response 而改写。若某个非终态任务的最后 assistant 文本来自 `finalResponse`CLI 会额外显示 `statusLabel``awaitingTerminalJudge=true``closeoutState=awaiting-terminal-or-judge``awaiting-judge`,并附带 closeout hint。指挥官应把这类行理解为“worker 已经产出最终回复文本,但 Code Queue 还在等待 agent terminal event、scheduler 写回或 judge 结果”;它仍占用 active/running 监督窗口,不能按完成任务 `read` 或验收,直到 `status` 进入 `succeeded``failed``canceled` 并可审阅 judge/terminal 记录。
这条规则直接服务 HWLAB #132:指挥官要优先看到真实业务推进、部署修复、阻塞和需要人工审阅的未读结果,Gate/报告/审查/诊断类任务只能作为折叠的分类信号存在,不能在默认输出中用长 prompt/body 抢占上下文。
完成未读任务的审阅也必须遵循渐进披露。指挥官默认只拉取原始 prompt 和最终 response,用它判断任务是否声称完成、是否有明显越界、是否缺少验收证据;不要默认拉完整 trace、全量 tool summary 或 raw output。`codex task --detail` 也是有界摘要,只提供少量 attempt/tool 行和短文本预览;需要完整证据时再继续展开 `--detail --full --tool-limit N`、分页 `--trace`,或按 seq 读取 `codex output``codex output` 默认仍会限制返回行数和单条文本预览;只有明确使用 `--full-text` 且选定 seq window 时才读取该页全文。只有当 final response 与目标不一致、证据不足、远端 commit 无法验证、任务疑似造假、或需要追溯失败原因时,才进入这些展开路径。这条规则的目标是降低上下文压力,同时保留通过多步查询拿到完整证据的能力。
队列诊断中的 `split-brain` 表示控制面/执行面观测分裂,不自动证明任务已经死亡。只要任务 heartbeat 还在刷新、trace 仍在推进,就不能把它判成服务中断或要求立刻 stop;应把它视为 `splitBrainLive=true` 的 live 任务,继续监督并推进 #20 里的已排任务,而不是 interrupt、替换或把 backend 当成已经挂掉。队列摘要应显示 `effectiveLiveness=live``splitBrainLive=true``recommendedAction=continue-supervision`compact 输出还应在 `executionDiagnostics.liveness` 中重复这些低噪声字段,并突出 `activeHeartbeatCount`、有界 `heartbeatFreshTaskIds``databaseActiveTaskCount``schedulerActiveRunSlotCount`。当 master/control-plane 的 `schedulerActiveRunSlotCount=0``heartbeatFreshTaskIds` 非空时,active 数应优先按 scheduler heartbeat 摘要解释为 live,而不是按 master 本地 slot 0 解释为执行停摆。只有 heartbeat expired/missing 或满足 stale-recovery 条件时,才应显示 `effectiveLiveness=at-risk` 并进入恢复判断。
旧 Code Queue 的 bounded snapshot 只作为历史监督证据,不再作为新派单或恢复判据。新任务派发后应通过 `bun scripts/cli.ts agentrun get tasks --queue commander --limit 20``describe task/<taskId>``events run/<runId>``logs session/<sessionId>``result run/<runId> --command <commandId>` 观察 AgentRun 队列、run 与 session。
默认 supervisor poll 也遵循同一低噪声语义:heartbeat expired/missing、`heartbeatRiskTaskIds``staleRecoveryCandidateTaskIds` 必须可见,但第一次 poll 只表示 `transient-needs-repoll``activity.recovery.hint` 应为 `re-poll supervisor before recovery`。只有 repeated poll 仍确认 owner heartbeat expired、scheduler local no active run、database-active task 仍存在,并且输出显式带 `repeatedPollConfirmed=true` 或 confirmed stale candidate,才允许进入 bounded dry-run reconcile;真实恢复仍受高风险边界约束。
stale-active 恢复和 `/api/scheduler/reconcile?staleMs=...` 诊断入口的 heartbeat stale 阈值必须按安全下限归一化:缺省和低于默认 5 分钟的值都按 5 分钟处理,过大值按 24 小时上限截断,并在结构化响应中返回 `requestedStaleMs*``staleMsAdjusted``staleMsAdjustmentReason``minStaleMs``maxStaleMs`。任何 `staleMs=0` 或过低阈值都不能把仍有 fresh scheduler heartbeat 的任务判成 stale/recoverable。
`codex queues``codex tasks --view commander` 和默认 supervisor 视图的 `activity` / `commanderConcurrency` 是指挥官并发治理的主读数。并发决策固定使用 `commanderConcurrency.activeRunnerCount``.data.queues.commander.activeRunnerCount` 或 commander `activeRunners.count`,它等于 `activity.effectiveActiveTaskCount`15 并发策略的可补窗口按 `15 - activeRunnerCount` 计算,CLI 也会直接给出 `.data.queues.commander.slotDeficit`,不能用 `activeQueueIds.length` 或 scheduler-local slot 数替代。`effectiveActiveTaskCount` 表示用于调度判断的有效活跃任务数;`databaseRunningTaskCount` 来自 PostgreSQL 中 `running` 状态计数;`databaseActiveTaskCount` 覆盖 running/judging 等数据库活跃任务;`heartbeatFreshActiveTaskCount` 表示 heartbeat-fresh 的有效 runner 数;`schedulerLocalActiveQueueCount``schedulerLocalActiveRunSlotCount` 只表示当前控制面本地可见 active run slots。`activeQueueIds``activeQueueCount` 是 scheduler-local 字段,可能在 `counts.running>0` 且 heartbeat 新鲜时为 0;看到这种组合时应按 `activity.effectiveActiveTaskCount``activity.heartbeatFreshActiveTaskCount``.data.queues.commander.runningTasks``splitBrainLive` 决策,不得把空 `activeQueueIds` 当作零并发或停摆证据。`commanderConcurrency.splitBrainDisposition=live-count-as-active` 表示 split-brain 仍是 live 且应计入 active runner`attentionRequired=true` 表示需要人工看一眼或重新 poll`interventionRequired=true` 才表示当前输出已经足以进入高风险介入路径。单次 heartbeat risk、stale recovery candidates 或 `recommendedAction=investigate-heartbeat-risk` 应先落到 `attentionRequired=true``re-poll supervisor before recovery`,不得直接等价为恢复授权。
单次 `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 维护桥,例如 `trans 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``external-provider-backoff``control-plane-observation-gap`,优先重试、steer 任务纠偏或拆出基础设施 follow-up;不得让业务 worker 把单次局部失败作为最终 blocker。CLI 和 runtime 必须把错误输出结构化为 `scope=runner-local|external-provider|control-plane|provider-gateway|ssh|registry|k3s|scheduler|service-proxy``observedAt``retryable``decision``blockingDisposition``healthyScopes``failedScopes` 和建议的交叉验证命令。当前 runner/local backend-core 容器缺失属于 runner-local observation gap;远程控制面也不可达属于 control-plane observation gap;两者都不能单独写成 active runner 数归零或 scheduler 停摆。
ClaudeQQ 是面向用户的主动提醒通道,不是 #24 简报更新的自动转发器。指挥官只应在三类情况下自主发送 ClaudeQQ 消息:核心服务或关键执行面宕机且需要用户知情,高风险决策需要用户请示,或出现里程碑式进展值得同步。消息必须简明扼要,一次不超过 200 个中文字符,写成一段话,不使用 Markdown 语法。普通轮询、普通 issue 更新、普通 #24 简报追加、外部 token provider 正常限流、以及无用户动作要求的中间状态,不发送 ClaudeQQ。发送失败只记录到 #24 或对应 blocker issue,不回滚已经完成的 GitHub issue 更新。高风险审批通知不得走本机 ClaudeQQ skill、powershell 或本地 serverrepo-owned 路径是先用 `bun scripts/cli.ts commander approval request --action <action> --dry-run [--task-id id] [--reason text]` 生成草案,获得授权后才使用 backend-core proxy 命令 `bun scripts/cli.ts microservice proxy claudeqq /api/push/text --method POST --body-json '<payload>' --raw`
重启 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。若 dry-run 返回 `notification-path-unavailable`,这是正式发送未开放的 blocker;指挥官应记录到 issue/#24,并使用输出里的 backend-core proxy command 作为后续授权后的唯一候选命令。
当多信号裁决显示 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 和指挥官的统一健康判断前置。它必须至少保留这些合同:默认输出只展示裁决、scope、失败/降级/未知信号和有界 evidence 摘要,完整 evidence 必须显式加 `--full``--raw``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``trans <providerId> argv true``artifact-registry health --provider-id <providerId>``microservice health k3sctl-adapter``microservice health code-queue``codex tasks --view commander --limit 20`;需要分区小页时再用 `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。
`databaseActiveTaskIds` 非空、scheduler 本地 active run/slot 为空、且 owner scheduler heartbeat 已过期时,运行面应把该任务列为 stale-active recovery candidate,并通过 scheduler reconcile 路径把它恢复为 `retry_wait`,不应依赖 rollout restart 触发 startup recovery。恢复入口必须保留 fresh heartbeat 保护:heartbeat 新鲜的 split-brain live 任务只能继续监督,trace gap 但 heartbeat 新鲜也不能触发 stale retry。只读诊断优先使用队列/health 中的 `executionDiagnostics``reconcile` 字段;需要人工确认时可先调用 bounded dry-run reconcile,只有明确使用 `POST /api/scheduler/reconcile?recover=1` 且通过高风险恢复边界后才执行恢复。OA Event Flow publisher 积压或 overflow 只能降低 trace/stats 可观测性,必须在 `oaPublisher` 状态中显式暴露并隔离为观测降级,不能阻断 PostgreSQL task state、heartbeat 或 stale recovery。
外部 token provider、模型 API 或上游服务的限流和短时不可用是正常预期,不应自动升级为 Code Queue 基础设施缺陷。典型表现包括 `429 Too Many Requests`、provider transient error、上游 timeout 或模型服务短时失败。runner 必须把这类 OpenAI/模型 provider 429 归类为 `scope=external-provider``failureKind=external-provider-rate-limit``externalProvider429=true`,并在 attempt 的 `runnerErrorClassification.backoffHint`、任务 output 的 `queue/backoff` 行和日志 `task_retry_backoff` 中暴露指数退避与 jitter 证据。退避策略是保守指数退避加稳定正向 jitter:429 至少等待 30 秒,单次不超过 10 分钟,jitter 按 task id 和 completed attempt count 稳定计算,避免多 runner 同时恢复造成 provider 再次拥塞。只要 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 的每个 AgentRun/历史 Code Queue 任务行都应显式保留推荐或实际 runner/model、风险等级、验证证据和审阅状态。推荐列的语义来自指挥官判断或 AgentRun task payload 审查,不能来自 worker 自评。MiniMax 和 DeepSeek 任务在 #20 中必须先保持“待指挥官审阅”状态;只有指挥官核验 diff、commit、轻量验证和未越界后,才更新为已验收并执行对应的 AgentRun/历史 read 标记。
## 指挥工作流
对每个活跃任务,按顺序评估四件事:
1. 完成质量:是否真的满足任务验收边界;
2. 完成状态:是否已经终态、可 retry,或仍在推进;
3. 自阻塞风险:任务是否卡在它自己无法解决的问题上;
4. 下一步动作:接受、继续、替换为更窄任务,或上报基础设施问题。
如果 blocker 是可复用的基础设施问题,不要盲目反复重跑业务任务。应先把基础设施缺陷记录到 issue,再在 Code Queue 无法越过时手动修复基础设施,然后恢复交付波次。
指挥官应优先做只读分析和派发新的窄范围任务,而不是本地接管实现。手动工作只保留给基础设施 blocker、live recovery,以及队列无法安全自解的问题。
## 干预规则
只有存在明确理由时才干预。
- 如果任务还在运行且 trace 或 scheduler heartbeat 新鲜,应引导而不是 interrupt。
- 对 AgentRun 运行中 session 的引导应优先使用正式 CLI:`bun scripts/cli.ts agentrun steer session/<sessionId> --prompt-stdin`,再用 `logs/events/result/ack` 确认。旧 `codex steer` 已冻结,只保留历史 trace confirmation 查询。
- 真实 steer 输出必须保持低噪声:成功显示 `steer.status``steer.deliveryState``steer.steerId`、有界 `traceConfirmation` 和后续命令,不回显 prompt 或完整 task state;失败默认不带 request body、不带 upstream body preview,也不带 raw response,需要上游预览或原始失败对象时显式重跑 `--full``--raw``deliveryState=accepted` 表示 backend 已接受;`not_accepted` 表示任务状态/权限/输入未接受;`accepted_response_timeout` 表示 stable proxy 响应超时但 trace confirmation 找到该 `steerId``unknown` 表示响应路径失败且确认查询仍未证明接受。
- 旧 Code Queue 的 provider tunnel 失败只作为历史运行面诊断线索;新任务控制面失败优先按 AgentRun `describe task``events``logs``result`、G14 `agentrun-v01` manager 和 runner job 证据分流。
- 新 AgentRun 任务失败分流以 AgentRun queue/session/runner-job 返回字段为准。旧 Code Queue `.data.diagnostics.reason` 只用于历史任务和残留运行面,不再引导新 `codex submit/steer/resume`
- 如果任务进入终态但缺少必要验收证据,应使用聚焦 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``tran` 或 GitHub token 注入路径。
- D601、provider-gateway、registry、k3sctl-adapter 或 service proxy 的单路径瞬时失败被 worker 放大为全局阻塞,而缺少多信号健康裁决和可重试错误分类。
- runner、provider 或目标 runtime 缺少 Secret/env 注入、DNS、egress、registry auth、GitHub auth 或受控 rollout 权限,导致业务任务无法通过常规路径完成。
这些缺陷应分配给基础设施队列,prompt 中要包含具体观测失败、期望长期合同,以及原交付任务继续所需的恢复动作。
如果缺陷只存在于 Code Queue 执行环境,且服务可以在 dev 中安全热修而不触碰 prod,应先做最小临时 live remedy。然后把修复持久化到相关 Dockerfile、容器镜像或凭证传播路径,并在 dev 验证持久化修复后再关闭问题。
Code Queue runner 的分布式访问能力必须通过镜像内 `/usr/local/bin/tran` 固化,而不是依赖临时拷贝脚本或手工记忆命令前缀。runner 内 `tran` 走公网 frontend 控制面;其中 `ssh`/provider route 通过 authenticated frontend `/ws/ssh` WebSocket 代理接入 backend-core SSH bridgestdout/stderr 必须按字节流直通到 runner,不得再通过 `/api/dispatch``/api/tasks` 或 task JSON compact 返回。runner 不要求持有 provider token,也不要求能解析 backend-core 集群内 DNSfrontend 是唯一对 runner 暴露的控制面,provider token 只存在于 frontend/backend-core 运行侧。runner 环境中的非 SSH remote frontend HTTP 读写默认使用 `curl` 后端,以降低部分 runner 上 Bun HTTP body 读取 native crash 的风险;这不是绕过控制面,route parser、WebSocket open payload 和 API request 仍由 UniDesk CLI 生成。当前必需验收目标是 D601 的真实 Code Queue pod:至少执行 `tran D601 argv ...``tran G14 argv ...` 以及一个 `tran <provider>:k3s ...` 只读命令,并用长 stdout 的长度/哈希证明没有 `...<truncated:N>` 标记,证明 D601 runner 能跨 provider host 与 k3s route 透传。G14 runner 可作为后续兼容性观察,不作为该合同当前阻塞条件。
如果业务任务发现缺少工具、Secret/env、DNS、egress 或凭证路径,指挥官应把它拆成独立 infra task,并标记为 `runnerDisposition=infra-blocked` 或等价基础设施阻塞,而不是埋在业务任务 prompt 中。业务 runner 不应自行摸索 live Secret、打印 env/token、复制凭证命令、扩大网络出口或通过反复 rollout 猜测问题;它只能提交脱敏证据、说明缺失能力和等待指挥官或 infra lane 处理。业务任务在 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
- 当经验具有长期复用价值时,写入长期参考文档。
长期参考文档应记录可复用规则,而不是完整事故流水账。过程知识应降低未来监督成本,而不是变成又一个一次性日志。