# UniDesk Manual Test Plan

## T1 CLI 可观测性与配置校验

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts help`、`bun scripts/cli.ts config show`、`bun scripts/cli.ts check`，确认每条命令都有 JSON 输出、失败时包含错误对象、`config.json` 是唯一配置来源，且默认 `check` 只执行轻量配置和 TypeScript 语法检查；需要覆盖关键文件、`scripts/` 类型、`src/components/` 类型、Docker Compose config 和日志策略时，显式运行 `bun scripts/cli.ts check --full`。运行 `set -o pipefail; bun scripts/cli.ts server status | head -1`，确认下游 pipe 关闭时不会打印 Bun EPIPE stack trace。

## T2 Docker 栈异步启动

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts server start`，确认命令立即返回 job id；随后运行 `bun scripts/cli.ts job status latest` 观察构建和启动进度，直到 job 状态为 `succeeded`，且输出包含 `.state/jobs/` 日志路径和 `logs/{YYYYMMDD}/` 服务日志路径。

## T3 主 server 自接入 Provider Gateway

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts server status`、`bun scripts/cli.ts server swap status` 和 `bun scripts/cli.ts debug health`，确认 `server status` 包含 `swap` 摘要，`server swap status` 快速返回 total memory、active swaps、`/etc/fstab` 持久化状态和 warning；面向浏览器/Provider 的公网入口只有 production frontend、dev frontend proxy 与 provider ingress，backend-core 显示为 Docker 内部端口，database/OA Event Flow 若因 D601 Code Queue 映射宿主端口也必须显示为受限宿主端口，且 `network.restrictedHostAccess.allowedSourceCidrs` 已生成来源限制，`/api/nodes` 中存在 `main-server` provider，状态为 `online`，`/api/nodes/system-status` 中存在 CPU/内存/硬盘采样，`/api/nodes/docker-status` 中存在 `main-server` 的 Docker 快照，且 provider 标签中能看到 Docker socket 可用性。若 `swap.warning` 非空，先运行 `bun scripts/cli.ts server swap ensure --dry-run` 审查动作，再谨慎执行 `bun scripts/cli.ts server swap ensure --size 2GiB`，确认输出包含 `before`/`after`、`actions`、`errors` 和 `status=ok|degraded`；已有 swap 时 ensure 必须 no-op。

## T4 前端控制台连通

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：先用 `bun scripts/cli.ts server status` 获取 frontend URL，再用浏览器访问该 URL，使用默认账号 `admin` 和默认密码 `Liang6516.` 登录，确认左侧主模块、顶部当前模块子标签、核心指标、Provider 控件和事件流可见；页面布局应紧凑、信息密度高、字体不过大，且移动端宽度下左侧栏转为高度一致、较窄、单行不换行的横向模块条，内容较少的主内容页和空状态也必须从顶部向下排列，不得上下居中留白。

## T5 真实任务下发链路

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts debug dispatch main-server docker.ps`，随后运行 `bun scripts/cli.ts debug health` 或在前端事件流中确认任务状态经历 `accepted`、`running`、`succeeded`，并能看到 provider 通过 Docker socket 返回容器列表摘要。

## T6 日志第一现场验证

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts server logs --tail-bytes 20000`，确认输出包含 `policy`、每个日志文件的 `sizeBytes/tailBytes/truncated` 和 Docker logs 的 tail 元数据，实际读取输出中列出的 `logs/{YYYYMMDD}/` 文件，确认 backend-core、frontend、provider-gateway、database 都有实时日志；运行 `bun scripts/cli.ts job list --limit 5` 和 `bun scripts/cli.ts job status latest --tail-bytes 20000`，确认 job 列表分页、状态输出只含 stdout/stderr 尾部且保留完整日志路径；backend-core 与 Code Queue/Codex app-server 日志必须按 `logs/{YYYYMMDD}/{startStamp}_{YYYYMMDD}_{HH}_{service}.jsonl` 小时切片，默认日志族总量不得超过 `1GiB`，超过后会删除最旧切片；日志不得只有启动行，错误日志必须包含可定位的错误消息或 stack。

## T7 停止与端口释放

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts server stop`，确认立即返回 job id；等待 `bun scripts/cli.ts job status latest` 成功后运行 `bun scripts/cli.ts server status`，确认 production frontend、dev frontend proxy 与 provider ingress 公网端口不再监听，backend-core 没有宿主机端口映射，database 的受限映射不再可用，容器状态不再运行。

## Issue 记录

测试发现的问题写入 `docs/issue/`，文件命名为 `{NN}_{issue_title}_{YYYYMMDD}.md`，其中 `NN` 从 `01` 递增；问题文档必须包含复现命令、实际输出摘要、期望行为和修复判定标准。

## T8 Playwright 公网前端 E2E

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：确认 `config.json` 的 `network.publicHost` 是主 server 公网地址，运行 `bun scripts/cli.ts e2e run`，要求 JSON 中 `network:only-frontend-provider-ports`、`network:core-public-blocked`、`network:database-public-blocked`、`network:findjob-public-blocked`、`network:met-nonlinear-public-blocked`、`network:todo-note-public-blocked`、`network:code-queue-public-blocked`、`core:internal-overview`、`core:pgdata-usage`、`core:performance-api`、`provider:self-node-online`、`provider:gateway-version-label`、`provider:system-status`、`provider:docker-status`、`provider:upgrade-plan`、`provider-ingress:public-health`、`microservice:catalog-findjob`、`microservice:catalog-pipeline`、`microservice:catalog-met-nonlinear`、`microservice:catalog-todo-note`、`microservice:catalog-code-queue`、`microservice:todo-note-health`、`microservice:todo-note-migrated-data`、`microservice:todo-note-write-path`、`microservice:code-queue-status`、`microservice:code-queue-health`、`microservice:code-queue-tasks`、`microservice:findjob-health`、`microservice:findjob-summary`、`microservice:findjob-jobs-preview`、`microservice:pipeline-status`、`microservice:pipeline-health`、`microservice:pipeline-snapshot`、`microservice:pipeline-oa-event-flow`、`microservice:met-nonlinear-status`、`microservice:met-nonlinear-health`、`microservice:met-nonlinear-queue`、`microservice:met-nonlinear-projects`、`microservice:met-nonlinear-image`、`database:named-volume-write`、`database:todo-note-pg-storage`、`frontend:login-provider-visible`、`frontend:public-provider-info-visible`、`frontend:sidebar-collapse`、`frontend:overview-pgdata-visible`、`frontend:no-naked-json-before-click`、`frontend:performance-panel-visible`、`frontend:system-monitor-visible`、`frontend:upgrade-plan-dispatch`、`frontend:docker-status-visible`、`frontend:gateway-version-records-visible`、`frontend:gateway-duration-subsecond-visible`、`frontend:provider-operation-availability-visible`、`frontend:microservice-catalog-visible`、`frontend:todo-note-integrated-visible`、`frontend:findjob-integrated-visible`、`frontend:code-queue-integrated-visible`、`frontend:pipeline-integrated-visible`、`frontend:pipeline-react-flow-visible`、`frontend:pipeline-step-timeline-visible`、`frontend:pipeline-oa-event-flow-visible`、`frontend:met-nonlinear-integrated-visible`、`frontend:met-nonlinear-project-tree-detail`、`frontend:met-nonlinear-queue-detail-speed` 全部 passed；打开输出的 screenshotPath，确认 Playwright 访问的是公网 frontend，页面上能看到 `main-server`、`Main Server Provider`、`D601`、`FindJob`、`Pipeline`、`MET Nonlinear`、`Code Queue`、`性能面板`、`SSH 透传`、`远程更新` 和结构化控件。

## T9 Database 命名卷持久化

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：向 `unidesk_e2e_markers` 插入一个唯一 marker，运行 `bun scripts/cli.ts server start` 并等待 `job status latest` 为 `succeeded`，再用 `docker exec unidesk-database psql -U unidesk -d unidesk` 查询该 marker 仍存在；同时审查 `docker-compose.yml` 和 `scripts/src/docker.ts`，确认 CLI server 控制没有使用 `down -v` 或 volume 删除命令。

## T10 前端 JSON 控件化展示

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `frontend:no-naked-json-before-click` passed；再用浏览器登录 frontend，确认节点标签、事件 payload、任务 payload/result 都渲染为徽标、字段摘要、表格或卡片，页面初始状态没有裸 JSON，只有点击 `查看原始JSON` 后才出现原始 JSON 弹窗或高级编辑区。

## T11 资源节点 Docker 状态

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `provider:docker-status`、`provider:gateway-restart-policy` 和 `frontend:docker-status-visible` passed；再用浏览器登录 frontend，进入左侧 `资源节点` 和顶部 `Docker 状态` 子标签，确认可以像 Docker Desktop 一样看到当前节点的 Containers、Images、Volumes、Networks 指标、容器表格、镜像/卷/网络侧栏和 Docker daemon 摘要，所有 running 的 provider-gateway 容器都在 Docker 快照或节点 labels 中显示 `restartPolicy=always` 且 `pidMode=host`，并确认在 `main-server` 节点下数据库命名卷 `unidesk_pgdata_10gb` 在 Volumes 区域和数据库命名卷卡片中显式可见；切换到 D518/D601 等计算节点时不应要求存在 pgdata 数据库卷，也不应显示数据库命名卷缺失告警。

## T12 前端 TypeScript + React 源码约束

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `find src/components/frontend -type f \\( -name '*.js' -o -name '*.jsx' \\) -print`，确认没有手写 frontend JS/JSX 源码；确认 `src/components/frontend/src/app.tsx` 只承担 shell/router，Todo Note、FindJob、Pipeline、MET Nonlinear、ClaudeQQ、Code Queue 分别在 `src/components/frontend/src/todo-note.tsx`、`src/components/frontend/src/findjob.tsx`、`src/components/frontend/src/pipeline.tsx`、`src/components/frontend/src/met-nonlinear.tsx`、`src/components/frontend/src/claudeqq.tsx`、`src/components/frontend/src/code-queue.tsx` 中维护；运行 `bun scripts/cli.ts check --components`，确认这些 TSX 模块全部纳入 TypeScript 检查，且浏览器请求 `/app.js` 由 frontend Bun server 从 TSX imports 转译生成。

## T13 资源节点任务管理器曲线

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `provider:system-status`、`provider:process-resource-status`、`frontend:system-monitor-visible` 和 `frontend:process-resource-sorting` passed；再用浏览器登录 frontend，进入左侧 `资源节点` 和顶部 `资源监控` 子标签，确认可以像 Windows 任务管理器一样看到 CPU、Memory、Disk 当前用量和历史曲线，Memory 明确显示为不含 Linux page cache / buffer 的实际内存占用；确认 `进程资源占用` 表默认按内存 PSS 降序且保留 RSS 展示，避免 PostgreSQL shared buffer 等共享页被多个进程重复计入，能点击 CPU、PID、用户、磁盘 I/O 等表头切换排序，且只通过 `查看原始JSON` 查看完整进程快照；最后确认能执行 `Provider Gateway 升级` 的 `预检升级`。

## T13A 通用性能面板

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run --only core:performance-api,frontend:performance-panel-visible`，确认 backend-core `/api/performance` 返回组件请求统计、内部操作统计、PGDATA 和 Code Queue PostgreSQL 存储摘要；再用浏览器登录 frontend，进入左侧 `运行总览` 和顶部 `性能面板` 子标签，确认页面能看到 `Bwebui` MB 趋势图、组件汇总、最近失败请求、内部操作汇总和最近慢操作，且没有失败请求时明确显示“最近没有失败请求”；完整性能 JSON 只能通过 `查看原始JSON` 打开。

## T14 Provider Gateway 远程升级

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：如果本次变更修改了 `src/components/provider-gateway` 代码或行为，先确认 `src/components/provider-gateway/package.json` 的 `version` 已递增；运行 `bun scripts/cli.ts debug dispatch main-server provider.upgrade`，随后查看任务历史或 `bun scripts/cli.ts debug health`，确认 `provider.upgrade` 通过真实 WebSocket 下发并以 `mode: plan` 成功返回升级计划且计划中包含 `providerId`、`providerName`、`providerGatewayVersion`、`targetProviderGatewayVersion`、`policy: "always-enabled"`、`--no-deps`、`--force-recreate`、`oldGatewaySleepMs`、`promoteOnlyAfterCandidateValidation`、`candidateRestartPolicyAfterPromotion: "always"`、`candidateUsesOldContainerEnvironment` 和 `candidateUsesHostPidNamespace`；对明确要升级或重建 `provider-gateway` 容器的计算节点，必须再运行 `bun scripts/cli.ts debug dispatch <PROVIDER_ID> provider.upgrade --mode schedule --wait-ms 15000`，确认任务成功、result 包含 updater 容器信息、候选 gateway 验证后节点重新上线，`providerGatewayVersion` 已上报目标新版本，且最终 provider-gateway 容器 Docker restart policy 是 `always` 并使用宿主 PID namespace。在非主 server 的计算节点上，必须使用 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch <PROVIDER_ID> provider.upgrade --mode schedule --wait-ms 15000` 做同一验证，证明该节点能通过公网 frontend remote CLI 自测自动升级，且不需要指定 `--main-server-key`。正式执行计算节点 `provider-gateway` 重建/升级只能通过前端 `资源监控` 的 `执行升级` 或等价的 `provider.upgrade mode=schedule` 显式调度完成，不能通过 `bun scripts/cli.ts ssh <PROVIDER_ID>` 或 Host SSH 维护桥同步执行自重建命令，也不能通过 `PROVIDER_UPGRADE_ENABLED` 或等价开关禁用远程升级。

## T15 待处理任务可追溯

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `frontend:pending-task-drilldown`、`frontend:mobile-nav-fixed-height` 和 `frontend:mobile-content-top-aligned` passed；再登录 frontend，点击 `态势总览` 的 `待处理任务` 指标，确认会进入 `任务调度 / 待处理任务` 子标签，并能看到每个 queued、dispatched、running 任务的 Provider、已等待时间、payload 摘要和 `查看原始JSON` 按钮。backend-core 超过 `TASK_PENDING_TIMEOUT_MS` 的待处理任务必须自动转为 failed，避免总览数字长期卡住。

## T16 任务历史诊断信息

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `frontend:task-history-diagnostics` passed；再登录 frontend，进入 `任务调度 / 任务历史`，确认每个任务行都能看到状态、任务命令和 id、Provider、任务耗时、载荷摘要、诊断信息、更新时间和 `查看原始JSON` 按钮。真实亚秒级耗时必须显示为小数秒或 `<0.01s`，不得显示成 `0s`。失败任务必须在默认表格中显示失败原因以及 exit code、timeout、previous status 等关键字段，完整 result 只能点击 `查看原始JSON` 查看。

## T17 Provider Gateway Host SSH / WSL SSH 维护桥

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：确认目标 provider-gateway 已只读挂载维护私钥目录到 `/run/host-ssh`，目标宿主或 WSL 的 sshd 已启动且 `authorized_keys` 包含对应公钥；运行 `bun scripts/cli.ts debug dispatch main-server host.ssh --wait-ms 15000`，再运行 `bun scripts/cli.ts debug task latest`，确认任务通过真实 WebSocket 下发、状态为 `succeeded`、result 中 `probeLine` 包含 `UNIDESK_SSH_TEST`、`exitCode` 为 0、`hostSshKeyPresent` 为 true。随后运行 `bun scripts/cli.ts ssh main-server hostname`，确认输出是远端 hostname 且进程 exit code 为 0；运行 `bun scripts/cli.ts ssh main-server find /home/ubuntu --max-depth 2 --type d --icontains unidesk --limit 5 --sort`，确认结构化 `find` 能返回远端目录且不需要手写括号或嵌套引号；运行 `bun scripts/cli.ts ssh main-server glob --root /home/ubuntu --icontains unidesk --type d --limit 5 --sort`，确认远端注入 `glob` 能返回目录；运行 `bun scripts/cli.ts ssh main-server rg -n UniDesk /home/ubuntu/unidesk/AGENTS.md`，确认 `rg` 直接子命令可用；再用 `printf 'pwd\nexit\n' | bun scripts/cli.ts ssh main-server` 验证无命令参数时能进入并退出远端登录 shell。对 D518 这类无公网 SSH 的 WSL 节点，使用同一命令替换 Provider ID 为 `D518`，必要时先用 debug dispatch 加 `--cwd /home/ubuntu` 覆盖远端工作目录，只能通过 provider-gateway 自连维护桥验证，不得把主 server 直连节点公网 22 端口作为通过标准；在计算节点本机还必须用 `bun scripts/cli.ts --main-server-ip 74.48.78.17 debug dispatch <PROVIDER_ID> host.ssh --wait-ms 15000` 和 `bun scripts/cli.ts --main-server-ip 74.48.78.17 ssh <PROVIDER_ID> hostname` 自测 remote CLI 透传，命令不得要求 `--main-server-key`。

## T18 Provider Gateway 版本与远程更新记录

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts e2e run`，确认 `provider:gateway-version-label`、`frontend:gateway-version-records-visible`、`frontend:gateway-duration-subsecond-visible` 和 `frontend:provider-operation-availability-visible` passed；再登录公网 frontend，进入 `资源节点 / 网关版本`，确认每个 Provider 行都显示 provider-gateway 版本号、升级策略、SSH 透传可用性、远程更新可用性、能力摘要、最近远程更新记录，并在下方以表格记录 `provider.upgrade` 的状态、模式、任务 id、来源、耗时、策略、指定 Provider 的 gateway 版本号、结果摘要和更新时间。远程更新记录的真实亚秒级耗时必须显示小数秒，不得显示成 `0s`；远程更新记录默认必须是结构化控件，不得展示裸 JSON；完整 task/result 只能通过 `查看原始JSON` 按钮查看。

## T18A Provider Gateway HTTP Tunnel

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：如果本次变更修改了 `src/components/provider-gateway`、backend-core 用户服务代理或 shared provider 协议，运行 `bun scripts/cli.ts debug health` 或公网 frontend 节点原始 JSON，确认目标 Provider labels 的 `unideskCapabilities` 同时包含 `microservice.http` 与 `microservice.http.tunnel`，且 `providerGatewayVersion` 已上报目标版本。随后对 D601 这类直管用户服务运行 `bun scripts/cli.ts microservice health findjob` 或任一已登记 `unidesk-direct` 用户服务的 health/proxy 命令，确认响应成功且代理诊断头或任务结果显示走 provider WebSocket HTTP tunnel；若目标 Provider 尚未升级到 tunnel capability，响应可以临时走旧 `microservice.http` dispatch，但验收记录必须标明该 Provider 仍需升级。重复执行 10 次同一只读 proxy 请求，不得出现偶发 `upstream proxy failed`、provider task missing 或 WebSocket socket closed 的 502。

## T19 前端单服务重建

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts server rebuild frontend`，确认命令立即返回 `server_rebuild` job id；随后运行 `bun scripts/cli.ts job status latest` 直到状态为 `succeeded`，stdout 中必须能看到先 build、再按 `frontend` 服务容器 label 移除、最后 `--no-deps frontend` 启动的过程。重建后运行 `bun scripts/cli.ts server status` 和 `bun scripts/cli.ts e2e run`，确认公网 frontend 恢复健康、Playwright 登录通过、database 命名卷未被删除；正式验收不得要求人工执行 `docker rm` 作为兜底。

## T20 D601 FindJob User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts microservice list`，确认 `findjob` 显示为 `providerId=D601`、`public=false`、`frontendOnly=true`、仓库 URL、commit id、`127.0.0.1:3254` 后端映射和 `findjob-server` 容器摘要；运行 `bun scripts/cli.ts microservice health findjob` 和 `bun scripts/cli.ts microservice proxy findjob /api/summary`，确认链路通过 backend-core、D601 provider-gateway 和 D601 本机 FindJob 后端；运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 microservice health findjob`，确认非主 server 也能通过公网 frontend remote CLI 验证同一链路且不需要 `--main-server-key`。随后运行 `bun scripts/cli.ts e2e run`，确认用户服务和 frontend FindJob 检查全部 passed；再登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / 服务目录` 和 `用户服务 / FindJob`，确认页面以 React 控件显示 D601、仓库引用、私有后端映射、FindJob 指标、岗位预览和草稿报告，默认没有裸 JSON，只有点击 `查看原始JSON` 才显示原始数据。FindJob 业务代码开发和调试必须用 `bun scripts/cli.ts ssh D601 ...` 进入 D601 的 `/home/ubuntu/findjob`，不得把 findjob 全量代码复制进 UniDesk 仓库，也不得占用主 server 部署调试服务。

## T21 D601 Pipeline User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts microservice list`，确认 `pipeline` 显示为 `providerId=D601`、`public=false`、`frontendOnly=true`、仓库 URL `https://github.com/pikasTech/pipeline`、commit id、`127.0.0.1:18082` 后端映射、`allowedMethods` 包含 `GET/HEAD/POST` 和 `pipeline-v2-control` 容器摘要；运行 `bun scripts/cli.ts microservice health pipeline`、`bun scripts/cli.ts microservice proxy pipeline '/api/snapshot?__unideskArrayLimit=registry.components:8,runs:3'` 和 `bun scripts/cli.ts microservice proxy pipeline /api/oa-event-flow/diagnostics`，确认链路通过 backend-core、D601 provider-gateway 和 D601 本机 Pipeline 后端，snapshot 返回 `ok=true`、组件 registry、Pipeline run 预览，diagnostics 返回 `mode=oa-event-flow-100`、禁止残留为 0、有无审核与 monitor 审核证据、node 完成事件不携带流程策略字段，且运行代码中不存在 `control-prompts.jsonl`、`monitor-prompts.jsonl`、`monitor-control`、`control-events.jsonl`、monitor stop 文件、`PIPELINE_*_APPEND_FILE`、本地 JSONL append/read helper 或 monitor `/pipeline-state` 挂载等旧文件传输残留；运行 `bun scripts/cli.ts --main-server-ip 74.48.78.17 microservice health pipeline`，确认非主 server 也能通过公网 frontend remote CLI 验证同一链路且不需要 `--main-server-key`。随后运行 `bun scripts/cli.ts e2e run --only microservice:pipeline,frontend:pipeline`，确认定向 Pipeline 验收通过；若没有正在运行且已产生 `node-long-running-observation` 的候选 run，E2E 会先通过 D601 SSH 透传启动 `monitor-management-behavior-test` 作为真实长任务观察种子，再由公网 frontend Playwright 验证甘特图连线和实时 running 条。再运行 `bun scripts/cli.ts e2e run`，确认 `microservice:pipeline-oa-event-flow`、`frontend:pipeline-oa-event-flow-visible` 和其他用户服务/frontend Pipeline 检查全部 passed；再登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / 服务目录` 和 `用户服务 / Pipeline`，确认页面以 React 控件显示 D601、仓库引用、私有后端映射、Pipeline 组件矩阵、React Flow 控制图框图、评分器 score 卡片、结构化 `OA 事件流` 诊断面板、epoch 列表、epoch 甘特图和运行材料索引，点击控制图中的 node 后会打开 node 精细控制面板，能通过“抓取过程”读取 node 执行过程，并显示 append prompt、guide 和 redo/restart 操作入口；甘特图必须按纵向时间轴绘制 node 工作竖条，滚动到某个时间窗口时自动隐藏该窗口内无工作的 node 列；点击甘特图执行线后必须显示 `OpenCode Trace`，Trace 正文必须复用 Code Queue 的公共 Trace 样式和 opencode port，废弃旧 Pipeline step/message/tool 卡片风格；Pipeline OA 事件流验收必须证明有审核和无审核流程都由 OA 从 `node-finished` 事实、config policy、monitor 控制事件和 runner control result 串起，不能保留独立审核请求事件、旧批次推进、runner 私有 JSONL 取证或 frontend/CLI 直写 `.state`；默认没有裸 JSON、JSONL 或逐行日志，只有点击 `查看原始JSON` 才显示原始数据。Pipeline 业务代码开发和调试必须用 `bun scripts/cli.ts ssh D601 ...` 进入 D601 的 `/home/ubuntu/pipeline`，不得把 pipeline 全量代码复制进 UniDesk 仓库，也不得占用主 server 部署调试服务。


## T22 Main Server Todo Note User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：确认 D518 `/mnt/d/work/todo_note` 已复制到主 server `/root/todo_note`，运行 `bun scripts/cli.ts microservice list`，确认 `todo-note` 显示为 `providerId=main-server`、`public=false`、`frontendOnly=true`、仓库 URL `https://gitee.com/Lyon1998/todo_note`、`todo-note:4211` 后端映射和 `todo-note-backend` 容器摘要；运行 `bun scripts/cli.ts microservice health todo-note`，确认返回 `storage=postgres`；运行 `bun scripts/cli.ts microservice proxy todo-note /api/instances --max-body-bytes 8000`，确认能看到 `CONSTAR`、`大论文`、`找工作`、`小论文`、`事务` 五个迁移清单，总任务数不低于 100。随后通过 backend-core 或 `bun scripts/cli.ts e2e run` 执行临时清单 create/add/toggle/undo/delete 写入循环，确认 Todo Note 写入真实经过 backend-core、main-server provider-gateway、`todo-note-backend` 和主 PostgreSQL，且删除前必须按唯一临时清单名称重新选中临时清单，不能误删迁移清单。最后登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / Todo Note`，确认清单、树形任务、筛选、提醒、移动、撤销/重做、字号控制都以 React 控件展示，默认没有裸 JSON，只有点击 `查看原始JSON` 才显示原始数据。

## T22A PGDATA -> Baidu Netdisk 只读复核

阅读 `AGENTS.md` 和 `docs/reference/deploy.md`，然后用 cli 手动测试以下内容：只运行 `bun scripts/cli.ts server status`、`bun scripts/cli.ts schedule list`、`bun scripts/cli.ts schedule runs --limit 20`、`bun scripts/cli.ts microservice status baidu-netdisk`、`bun scripts/cli.ts microservice health baidu-netdisk`、`bun scripts/cli.ts microservice proxy baidu-netdisk /api/auth/status --raw` 和 `bun scripts/cli.ts microservice proxy baidu-netdisk '/api/transfers?limit=20' --raw` 这些只读命令，确认能观察目标栈、Baidu auth health、配置存在性和最近 run/transfer 状态；不得运行 `schedule run`、`schedule retry-run`、`server start`、`server rebuild`、`deploy apply` 或 Baidu transfer POST。若 backend-core 目标容器缺失或仅有 `*.verify-*` 容器，CLI 必须非零退出并返回 `failureKind=target-stack-not-running`、`runnerDisposition=infra-blocked`、`targetStack.verifyOnlyObserved`、`readOnlyCommands` 和 `authorizationRequiredForRecovery`，而不是把空 stdout/stderr 当作通过。需要恢复时，测试记录必须先写明最小授权动作：恢复非空 Baidu Netdisk secret、启动或部署包含 backend-core/database/baidu-netdisk 的目标栈，随后再单独授权 `schedule retry-run` 或 `schedule run` 才能触发真实 PGDATA 备份。

## T23 D601 Code Queue User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts microservice list`，确认 `code-queue-mgr` 显示为 `providerId=main-server`、`deployment.mode=internal-sidecar`、Compose 后端 `http://code-queue-mgr:4278`、`frontend.integrated=false`，并确认稳定 `code-queue` 条目说明队列管理/提交/历史/轻量 Trace 默认由主 server `code-queue-mgr` 负责，D601 k3s Code Queue 只负责 scheduler/runner/active run control 和执行态写回；使用 `bun scripts/cli.ts server rebuild code-queue-mgr` 重建主 server 控制面，再运行 `bun scripts/cli.ts microservice health code-queue-mgr`、`bun scripts/cli.ts microservice health code-queue`、`bun scripts/cli.ts microservice proxy code-queue '/api/tasks/overview?limit=5&transcriptLimit=1&compact=1&afterSeq=0&preferId='`、`bun scripts/cli.ts codex submit --dry-run --queue <queueId> <prompt>`、`bun scripts/cli.ts codex steer <runningTaskId> --prompt-stdin --dry-run` 和 `bun scripts/cli.ts codex task <已有taskId>`，确认普通控制/读取路径经 backend-core 分流到 master `code-queue-mgr`，返回 `role=master-control-plane`、`schemaReady=true`、PostgreSQL pool 上限、`noRunnerDependencies=true`、任务初始 prompt、最后 assistant message、工具调用摘要、attempt/judge/error 和耗时；`codex steer --dry-run` 必须返回 `path=/api/tasks/<runningTaskId>/steer`、`method=POST`、prompt 字符数和 `truncated=false`，且不触碰运行中 session。随后运行 `bun scripts/cli.ts codex deploy <已push的commitId>`，确认命令返回结构化错误并明确说明维护通道直连 D601 部署已禁用，且不会返回异步部署 job id；再运行 `bun scripts/cli.ts deploy apply --service code-queue --dry-run --run-now` 可只做 would-deploy 预览，去掉 `--dry-run` 时必须在运行时变更前拒绝 D601 直连部署。确认主 server 根目录 `docker-compose.yml` 中只存在 `code-queue-mgr` 而不存在执行面 `code-queue` service，并通过 `bun scripts/cli.ts ssh D601 argv bash -lc 'systemctl is-active k3s && KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes -o wide && sudo ctr --address /run/k3s/containerd/containerd.sock -n k8s.io images ls | grep -F docker.io/rancher/mirrored-pause:3.6 && ! docker ps --format "{{.Names}} {{.Image}}" | grep -E "[[:space:]]rancher/k3s:" && ! docker ps --format "{{.Names}}" | grep -Fx code-queue-backend'` 或等价检查证明 D601 k3s 是 WSL 原生 systemd 服务、native containerd 已有正确 pause sandbox 镜像、没有 active `rancher/k3s` 控制面容器且旧 direct Docker `code-queue-backend` 没有并行运行。运行 `bun scripts/cli.ts microservice proxy k3sctl-adapter /api/control-plane --raw` 和执行面专属 `bun scripts/cli.ts microservice proxy code-queue /api/dev-ready --raw`，确认 D601 scheduler/read/write ready endpoint、`queue.storage.primary=postgres`、`queue.storage.postgresReady=true`、`queue.devReady.missingTools=[]`、`queue.devReady.docker.versionOk=true`、`queue.devReady.docker.composeOk=true`；`queue.devReady.ssh.ready` 只在需要跨 Provider SSH/Windows-native 任务时作为强制项。在 D601 active Code Queue Pod 内验证主 PostgreSQL 端口映射可执行 `select 1`，主 OA Event Flow 端口映射 `/health` 可访问，集群内 ClaudeQQ Service `http://claudeqq.unidesk.svc.cluster.local:3290/health` 可访问；这些映射不得成为任意公网入口。

随后登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / Code Queue`，确认页面显示默认模型 `gpt-5.5`、默认执行 Provider `D601`、默认工作目录 `/workspace`、模型下拉菜单包含 `gpt-5.4-mini`/`gpt-5.4`/`gpt-5.5`、入队份数、队列指标、任务 ID、复制任务 ID、引用按钮、任务耗时、引用任务 ID、清空输入、创建成功提示、任务提交表单、Trace 输出、attempt 表、MiniMax/fallback judge 状态、追加 prompt、打断和重试控件；通过页面提交一个小任务，确认任务进入 queued/running/succeeded 或可解释的 failed 状态，并且输出区能看到运行中的 Codex 消息。需要验证运行中纠偏时，提交一个明确会保持 running 的长任务，使用 `printf '<纠偏提示>' | bun scripts/cli.ts codex steer <runningTaskId> --prompt-stdin` 注入 prompt，确认命令返回有界 task/queue 摘要和 `codex task`/`codex output` 后续命令，且 `bun scripts/cli.ts codex task <runningTaskId> --trace --tail --limit 80` 能看到 `Steer prompt` 或 `turn/steer`；正式验收不得再使用底层 `microservice proxy code-queue /api/tasks/<taskId>/steer` 作为主入口。批量验收时设置 `入队份数=5` 或用 `---` 分隔 5 段 prompt，一次性入队 5 条任务，确认 5 条任务按顺序运行并全部进入 succeeded 或可解释的非成功终态，不能只运行第一条后停止；其中任一任务被 judge 判定 `fail` 时只能把当前任务标为 failed，后续 queued 任务仍必须继续推进。测试异常中断时可以提交长任务后点击 `打断`，确认任务变为 canceled 或被 judge 标记为非成功终态；自动重试只应在服务端/传输异常、任务正常结束但 execution record 显示未完成、或 judge 判定 retry 时发生；retry 必须复用已有 Codex thread 并 append 继续执行 prompt，只有当前任务 complete 后才推进队列中的下一个任务。MiniMax judge 必须能处理 Markdown fence/夹杂文本等 JSON 去噪；若去噪后仍失败，必须把解析错误和上一轮去噪前原始回答反馈给 MiniMax 修复后重试，日志中应出现 `judge_json_parse_retry`，且 repair 成功时仍以 `source=minimax` 返回。Codex provider key 只能通过 `OPENAI_API_KEY`、`CRS_OAI_KEY` 这类运行时环境透传，MiniMax API key 只能通过 D601 env-file 运行时环境传入，禁止写入 `config.json`、Dockerfile、源码或测试文档。

## T23D Code Queue CI/CD Dry-Run Contract

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：运行 `bun scripts/code-queue-cicd-dry-run-contract-test.ts`，确认 Code Queue 标准镜像化 CI/CD dry-run 合同输出 `ok=true`。该测试必须证明 CI 只负责发布 commit-pinned `unidesk/code-queue:<commit>` artifact 与 digest/label summary，DEV CD dry-run 只指向 `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy，PROD Code Queue 是 structured unsupported 且不暴露 production k3s runtime deploy target，并且输出显式禁止 `codex deploy`、`server rebuild code-queue`、production namespace/manifest mutation、scheduler/runner restart、任务 interrupt 和 cancel。该测试不得执行真实 deploy/rebuild/restart，不得 interrupt/cancel 运行中任务，也不得执行 prod apply。

## T23E Code Queue Commander View Contract

阅读 `AGENTS.md` 和 `docs/reference/code-queue-supervision.md`，然后用 cli 手动测试以下内容：运行 `bun scripts/code-queue-commander-view-contract-test.ts`，确认输出 `ok=true`。该测试必须证明 `bun scripts/cli.ts codex tasks --view commander` 是显式 host commander 轮询视图，默认输出有界，保留 exact active runner count 与来源/处置、queued/retry_wait 计数、terminal-unread 总数与 omitted 行数、active stale/heartbeat/final-response blocker 风险、HWLAB#7/#99/#116/#164/#317 和 UniDesk#20/#118 命中、确定性任务分类、`codex task`/`trace`/`output`/`read`/raw overview drill-down 命令，并且不输出完整 prompt、完整 final response、raw output 或 full trace。该测试还必须证明 `recentCompleted` 不重复 `completedUnread`，`--view supervisor` 与 `--view full` 仍可显式使用。本测试不得 deploy、rollout、重启 Code Queue backend、interrupt/cancel 运行中任务或批量 mark-read。

## T23A D601 k3s CI Gate

阅读 `AGENTS.md` 和 `docs/reference/ci.md`，运行 `bun scripts/cli.ts ci install`，确认 Tekton Pipelines `v1.12.0`、Tekton Triggers `v0.34.0` 和 `unidesk-ci` Pipeline/Task/EventListener 已部署到 D601 原生 k3s；随后运行 `bun scripts/cli.ts ci run --revision <已push的commitId> --wait-ms 1200000`，确认 PipelineRun 只执行 clone/check/performance，不调用 `deploy apply` 或 `codex deploy`，并确认临时 `code-queue-ci-read` 使用主 PostgreSQL 只读查询 Code Queue 首屏、TraceView summary、TraceView steps 和 step detail 的性能指标。若失败，使用 `bun scripts/cli.ts ci logs <pipelineRun>` 查看 TaskRun 和 Pod 日志；交付说明必须记录性能预算是否通过。

## T23C D601 Dev Environment And Rust Backend-Core

阅读 `AGENTS.md` 和 `docs/reference/dev-environment.md`，运行 `bun scripts/cli.ts check --help`、`bun scripts/cli.ts deploy --help`、`bun scripts/cli.ts server rebuild --help` 和 `bun scripts/cli.ts ci run-dev-e2e --help`，确认全部快速返回 JSON 帮助且说明 Rust backend-core 常规迭代不在 master server 编译，只有明确的 backend-core 主 server 上线例外可走受控限流 rebuild；运行 `bun scripts/cli.ts check --files --scripts-typecheck --compose --logs`，确认本地非 Rust 检查通过；确认没有在 master server 执行仓库级 `cargo check/build/test` 或绕过 CLI 的 `docker build src/components/backend-core/Dockerfile`。将已 push 的 backend-core/frontend commit 写入 `origin/master:deploy.json#environments.dev` 后，运行 `bun scripts/cli.ts deploy apply --env dev --service backend-core` 和 `bun scripts/cli.ts deploy apply --env dev --service frontend`，用 `bun scripts/cli.ts job status <jobId> --tail-bytes 30000` 观察 D601 target-side fetch、Rust build、k3s image import、`unidesk-dev` apply、Deployment stamp 和 live commit health 验证；随后运行 `bun scripts/cli.ts server rebuild dev-frontend-proxy` 并确认 `server status` 输出 `urls.devFrontend=http://74.48.78.17:18083`，`curl -fsS http://127.0.0.1:18083/health` 成功；最后访问公网 `http://74.48.78.17:18083/` 手动体验 dev 版本，并运行 `bun scripts/cli.ts ci run --revision <已push的commitId> --wait-ms 1200000` 与 `bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000` 完成 D601 CI 和 dev smoke 验证。

## T23B D601 Decision Center User Service

阅读 `AGENTS.md` 和 `docs/reference/microservices.md`，运行 `bun scripts/cli.ts microservice list`，确认 `decision-center` 显示为 `providerId=D601`、`public=false`、`frontendOnly=true`、仓库 URL `https://github.com/pikasTech/unidesk`、k3s/k8s `k3s://unidesk/decision-center:4277` 逻辑服务映射、`deployment.mode=k3sctl-managed`、`runtime.orchestrator=k3sctl` 且无业务直连容器摘要。随后运行 `bun scripts/cli.ts microservice health decision-center`，确认 `service=decision-center`、`storage=postgres`、`schemaReady=true` 且 health 中包含 `diaryEntryCount`；准备一份临时 Markdown 会议记录，运行 `bun scripts/cli.ts decision upload <markdown-file> --title <title> --type meeting --level G1 --status active --evidence <url>`，再运行 `bun scripts/cli.ts decision list` 和 `bun scripts/cli.ts decision show <id>`，确认 CLI 只通过 backend-core 用户服务代理访问，返回结构化 JSON，列表默认不携带完整 `body`，详情能看到刚上传记录的完整 Markdown。准备一份临时需求 Markdown，运行 `bun scripts/cli.ts decision requirement create --title <title> --body-file <markdown-file> --type external_goal --priority P0 --status active --source external --issue '#22' --doc-type GOAL --doc-priority P0 --doc-year 2026 --signer <signer> --issued-at 2026-05-21`，再运行 `bun scripts/cli.ts decision requirement list --doc-type GOAL --doc-priority P0 --year 2026`、`bun scripts/cli.ts decision requirement list --doc-no <docNo>`、`bun scripts/cli.ts decision requirement show <docNo>` 和 `bun scripts/cli.ts decision requirement update <docNo> --title <updated> --body-file <markdown-file> --type internal_goal --linked-goal-id <externalId> --supersedes DC-DCSN-P0-2026-001`，确认需求记录支持 create/list/show/update/upsert，字段包含类型、标题、内容、状态、优先级、来源、关联 issue/task、创建/更新时间、`docNo/docType/docPriority/docYear/docSeq/signer/issuedAt/effectiveScope/supersedes/supersededBy`，且 list/show 输出来自结构化字段而不是 Markdown body 解析；重复运行相同 `--doc-no` 的 create 必须返回结构化 JSON 错误 `doc_no_conflict` 或等价 409，upsert 同一 `docNo` 必须更新既有记录而不是创建重复记录。再准备两份都包含 `# 2026年5月1日` 的临时工作日志 Markdown，分别运行 `bun scripts/cli.ts decision diary import <file-a> --source-file source-a.md --tag e2e` 和 `bun scripts/cli.ts decision diary import <file-b> --source-file source-b.md --tag e2e`，随后运行 `bun scripts/cli.ts decision diary months`、`bun scripts/cli.ts decision diary list --month 2026-05`、`bun scripts/cli.ts decision diary history --month 2026-05`、`bun scripts/cli.ts decision diary show 2026-05-01 --source-file source-a.md`、`bun scripts/cli.ts decision diary show 2026-05-01 --source-file source-b.md`、`bun scripts/cli.ts decision diary today`、`bun scripts/cli.ts decision diary today --edit --body-file <today-file>`、`bun scripts/cli.ts decision diary upsert 2026-05-03 --body-file <markdown-file>` 和 `bun scripts/cli.ts decision diary edit 2026-05-03 --body-file <markdown-file> --tag e2e`，确认日记按 `YYYY-MM/YYYY-MM-DD.md` 虚拟路径拆分、写入 PostgreSQL、同日多 source 可精确读取、当天日记按真实日期自动创建、重复导入幂等且历史日记可按日期编辑。用户服务上线前的 dev 自动门禁使用 focused 集合：`bun scripts/cli.ts e2e run --only microservice:decision-center-record-crud,microservice:decision-center-diary-lifecycle,frontend:decision-center-visible,frontend:decision-center-demand-management-visible,frontend:decision-center-diary-visible`，该门禁只验证用户服务行为，不测试 CI/CD 自举，也不部署 prod。最后登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / Decision Center`，确认页面显示 G0/G1 目标、P0/P1 Blocker、停放事项、最近会议/决议、需求管理工作区、需求录入编辑器、全部记录表和工作日记编辑台；日记页支持“今天”自动填入真实日期、保存当天 Markdown、编辑历史 Markdown 并再次读取一致。prod 人工验收必须在 CD 拉取已发布 artifact 后执行，逐项确认 health、records、diary editor、frontend 页面、无公网业务端口、live commit / artifact 信息；页面不得提供聊天/LLM 会话窗口，默认不得裸 JSON，完整 JSON 只能通过 `查看原始JSON` 打开。

## T24 MET Nonlinear D601 GPU User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：确认 D601 `~/met_nonlinear` 中存在 `docker-compose.unidesk.yml`、`docker/unidesk/Dockerfile.ml`、`unidesk/server/src/index.ts` 和 `docs/reference/unidesk_microservice.md`；运行 `bun scripts/cli.ts microservice list`，确认 `met-nonlinear` 显示为 `providerId=D601`、`public=false`、`frontendOnly=true`、`127.0.0.1:3288` 后端映射和 `met-nonlinear-ts` 容器摘要；运行 `bun scripts/cli.ts microservice health met-nonlinear`、`bun scripts/cli.ts microservice proxy met-nonlinear /api/queue`、`bun scripts/cli.ts microservice proxy met-nonlinear '/api/projects?root=projects&limit=500'`、`bun scripts/cli.ts microservice proxy met-nonlinear '/api/projects?root=ex_projects&limit=500'`、`bun scripts/cli.ts microservice proxy met-nonlinear '/api/projects/config?path=projects/<name>' --raw` 和 `bun scripts/cli.ts microservice proxy met-nonlinear /api/images`，确认链路通过 backend-core、D601 provider-gateway 和 D601 本机 TS 后端，项目详情包含 `config`、`progress`、`data`、`model`、`metrics` 字段；最后登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / MET Nonlinear`，确认项目库按 `projects/` 和 `ex_projects/` 文件树层级展示且文件夹 Project 数与后端返回数量一致，点击项目行能看到结构化 `config.json`、`data/` 训练状态、模型参数量和指标；通过 UI 选择已有 source Project，设置训练轮数和最大并发，使用 `Fork Project` 创建新的 `projects/unidesk_forks/` Project，确认新 Project 被自动勾选但不会直接训练，再点击 `加入待启动队列` 和 `启动队列`；完整验收可用 UI 输入 `Fork 数量=10`、`训练轮数=200`、`最大并发=3`，但这个规模只能由输入框配置，不能作为硬编码按钮。确认最多按 UI 设置的并发数运行、目标 GPU 是 2080Ti、显存余量低于 20% 时自动限制并发、任务最终进入已完成或失败诊断标签且训练容器自动销毁。页面必须以 React 控件显示项目库、待启动/排队/训练中、已完成、失败诊断、GPU/镜像、训练进度、ETA、`epoch/h` 训练速度和历史记录；项目库、当前队列、已完成和失败列表中的项目必须可点击打开详情；默认没有裸 JSON，只有点击 `查看原始JSON` 才显示原始数据；前端不得再提供 `创建10个10轮任务` 这类硬编码测试按钮。

## T25 ClaudeQQ D601 QQ Gateway User Service

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 的解释职责），然后用 cli 手动测试以下内容：确认 D601 `/home/ubuntu/.agents/skills/claudeqq` 中存在 `napcat/config/onebot11.json`，确认 UniDesk 仓库中存在 `src/components/microservices/claudeqq/Dockerfile` 和 `src/components/microservices/claudeqq/adapter.js`；运行 `bun scripts/cli.ts microservice list`，确认 `claudeqq` 显示为 `providerId=D601`、`public=false`、`frontendOnly=true`、仓库 URL `https://gitee.com/lyon1998/agent_skills`、k3s/k8s `k3s://unidesk/claudeqq:3290` 逻辑服务映射、`deployment.mode=k3sctl-managed`、`runtime.orchestrator=k3sctl` 且无业务直连容器摘要；使用 `bun scripts/cli.ts deploy apply --service claudeqq` 按 `deploy.json` 期望状态部署，确认 job 能在 D601 target-side fetch/export 外部 repo 或验证过的 provider worktree、注入 UniDesk 管理的 ClaudeQQ Dockerfile/API adapter、构建 `unidesk-claudeqq:d601`、导入原生 k3s/containerd、apply `src/components/microservices/k3sctl-adapter/k3s/claudeqq.k8s.yaml`、stamp deployment commit、rollout 并通过 UniDesk microservice proxy 验证 live commit。运行 `bun scripts/cli.ts microservice health claudeqq`、`bun scripts/cli.ts microservice proxy claudeqq /api/napcat/login`、`bun scripts/cli.ts microservice proxy claudeqq /api/events/recent` 和 `bun scripts/cli.ts microservice proxy claudeqq /api/events/subscriptions`，确认链路通过 backend-core、k3sctl-adapter、Kubernetes API service proxy 和 D601 ClaudeQQ Service，health 返回 `service=claudeqq`、`pureBackend=true`、`napcat.containerized=true`、NapCat HTTP/WS 状态、登录状态/二维码、`/api/push/text` 与 `/api/events/subscriptions` 端点；通过 `POST /api/events/subscriptions` 创建临时 webhook 订阅再删除，确认 main server 和其他用户服务可订阅 QQ 消息事件；通过 `POST /api/push/text` 发送消息时若 NapCat 未登录必须返回可解释错误，NapCat 在线时必须返回消息 ID，人工推送验收只允许发给主用户私聊账号 `645275593`。最后登录公网 frontend `http://74.48.78.17:18081/`，进入 `用户服务 / ClaudeQQ`，确认页面以 React 控件显示 D601、仓库引用、私有后端映射、NapCat 容器登录二维码、NapCat 状态、QQ 事件订阅、消息推送、主用户私聊账号 `645275593`、最近 QQ 事件和已发送记录，默认没有裸 JSON，只有点击 `查看原始JSON` 才显示原始数据；不得把 D601 `3290/3000/3001/6099` 暴露到公网，也不得 iframe ClaudeQQ 旧 WebUI。

## T26 GitHub CLI PR 安全写入口

阅读 `AGENTS.md` 和 `docs/reference/cli.md`，然后用 cli 手动测试以下内容：准备一份包含真实换行、反引号和 Markdown 表格的临时正文文件，运行 `bun scripts/cli.ts gh help`，确认 help 中包含 `gh pr create`、`gh pr edit`、`gh pr comment`、`gh pr view <number|url|owner/repo#number>`、`gh pr read ... [compatibility alias for pr view]`、`--number N compat`、`gh pr preflight <number>`、`gh preflight <prNumber>`、`--raw|--full`、`gh pr files <number>` 和 `gh pr diff <number> --stat`。运行 `bun scripts/gh-cli-pr-contract-test.ts`，确认 mock GitHub 覆盖 PR view/read 的 GitHub URL、`owner/repo#number` shorthand、`--number` 兼容提示、`--raw` 完整披露、冲突 `--repo` 结构化失败、PR closeout GraphQL 字段、低噪声 `gh pr preflight`/`gh preflight`、PR edit/update REST PATCH payload、stdin `--body-file -` 和不回显完整正文。运行 `bun scripts/gh-cli-pr-files-contract-test.ts`，确认 mock GitHub 覆盖 `gh pr files` 的 REST changed-file/stat JSON、bounded file list、truncation metadata、next command、无 raw patch，以及 `gh pr diff --stat` 兼容别名和无 `--stat` raw diff 的结构化拒绝。对真实仓库只读观察可运行 `bun scripts/cli.ts gh pr files <number> --repo pikasTech/unidesk --limit 30`、`bun scripts/cli.ts gh pr diff <number> --repo pikasTech/unidesk --stat --limit 30` 或 `bun scripts/cli.ts gh pr preflight <number> --repo pikasTech/unidesk`，确认输出固定 JSON 且默认不含 raw diff 或完整 status contexts；需要完整 status contexts 时显式加 `--full`。运行 `bun scripts/cli.ts gh pr create --repo pikasTech/unidesk --title <title> --body-file <file> --base master --head <branch> --draft --dry-run`，确认命令不访问 GitHub、不创建 PR，JSON 中包含 `dryRun=true`、`planned=true`、repo、title、base、head、draft、bodyChars、bodyPreviewLines、request plan，并且正文预览保留真实换行和反引号。运行 `bun scripts/cli.ts gh pr edit <number> --repo pikasTech/unidesk --title <title> --body-file <file> --dry-run` 和 `bun scripts/cli.ts gh pr edit --number <number> --repo pikasTech/unidesk --title <title> --body-file <file> --dry-run`，确认命令使用 REST PATCH 计划、不访问 GitHub Projects Classic GraphQL/projectCards，`--number` 兼容路径返回 `standardSyntaxHint`，JSON 只包含 repo、PR number、changedFields、url、body 长度/SHA/source 和 request plan，不默认回显完整正文；再运行 `cat <file> | bun scripts/cli.ts gh pr edit <number> --repo pikasTech/unidesk --body-file - --dry-run`，确认 stdin source 标记为 `kind=stdin` 且同样低噪声。运行 `bun scripts/cli.ts gh pr comment <number> --repo pikasTech/unidesk --body-file <file> --dry-run`，确认命令不写评论，JSON 中包含 PR number、bodyChars、bodySource 和 request plan，且没有把换行污染成字面量 `\n`；运行 `bun scripts/cli.ts gh pr comment delete --number <commentId> --repo pikasTech/unidesk --dry-run`，确认 `--number` 按 commentId 兼容并返回 `standardSyntaxHint`。运行 `bun scripts/cli.ts gh pr merge <number> --repo pikasTech/unidesk`，确认 guarded merge plan 或结构化失败不会绕过预检。需要测试真实创建、编辑、评论或 merge 时，只允许使用明确的 throwaway 源分支和 PR，并在记录中写明 PR URL、number、源/目标分支和清理动作；默认验收只做 dry-run，不创建或修改真实 PR。

## T27 GitHub Issue/Comment 换行转义卫生扫描

阅读 `AGENTS.md` 和 `docs/reference/cli.md`，然后用 cli 手动测试以下内容：运行 `bun scripts/cli.ts gh help`，确认 help 中包含 `gh issue create --title <title> --body-file <file> [--label label[,label...]]...`、`gh issue view <number|url|owner/repo#number>`、`gh issue read ... [compatibility alias for issue view]`、`--number N compat`、`--raw|--full`、`gh issue scan-escape`、`gh issue cleanup-plan`、`gh issue board-row list` 和 `gh issue board-row update`，notes 中明确推荐 `--body-file`、quoted heredoc、只读 cleanup-plan、view/read shorthand、GitHub URL、`--number` 兼容提示、raw/full 显式完整披露、board-row update 默认 dry-run 和 `--expect-body-sha`/`--expect-updated-at` 并发保护。运行 `bun scripts/gh-cli-issue-guard-contract-test.ts`，确认 mock GitHub 覆盖 issue view/read 的 GitHub URL、`owner/repo#number` shorthand、`--number` 兼容提示、`--raw` 完整披露、冲突 `--repo` 结构化失败、污染命中、说明性 `\n` 命中不误报、短 body/null body guard、body-file dry-run 写入路径、`issue create --label cli,infra --label ops --dry-run` labels 解析和 request plan、真实 create REST payload labels、missing label 的结构化 `validation-failed`、comment-id/body-id 定位、comment delete --number commentId dry-run 和 cleanupSuggestions、board-row list/get 复用 #20 表格解析、board-row update 给出 old/new row、body SHA、guard 结果、表格管道转义、默认 dry-run 不写入、带 `--expect-body-sha` 时只对 mock server PATCH、以及 board-row move 迁移支持。对真实仓库只允许运行 `bun scripts/cli.ts gh issue scan-escape --repo pikasTech/unidesk --limit <N> --dry-run`、`bun scripts/cli.ts gh issue cleanup-plan --repo pikasTech/unidesk --limit <N>`、`bun scripts/cli.ts gh issue board-row list --repo pikasTech/unidesk --board-issue 20 --state open --dry-run` 或 `bun scripts/cli.ts gh issue board-row get <issueNumber> --repo pikasTech/unidesk --board-issue 20` 这类只读命令；不得运行真实历史评论清理、不得真实改写 #20/#24 正文，除非另有明确人工指令并先审阅 dry-run 输出和 body SHA。

## T28 Host Codex Commander Skeleton Contract

阅读 `AGENTS.md` 和 `docs/reference/host-codex-commander.md`，然后用 cli 手动测试以下内容：运行 `bun scripts/host-codex-commander-contract-test.ts`，确认输出 `ok=true`；运行 `bun scripts/cli.ts commander contract`，确认返回 `phase=source-contract`、`serviceId=host-codex-commander`、`daemonImplemented=false`、`liveOperationsImplemented=false`，且 required capabilities 包含 host Codex 进程发现/启动计划、SSH/PTY/stdio bridge、prompt guidance、trace summary、#20/#46 入口和 ClaudeQQ 高风险审批入口；运行 `bun scripts/cli.ts commander plan --dry-run --session-id primary`，确认所有 top-level plan 均为 `mutation=false`，start plan `enabled=false`，不会打开 SSH/PTY/stdio、不会注入 prompt、不会发送 ClaudeQQ；运行 `bun scripts/cli.ts commander plan`，确认非 dry-run 返回非零状态和 `error=dry-run-required`；运行 `bun scripts/cli.ts commander approval request --action code-queue-task-interrupt --task-id <taskId> --reason '<reason>' --dry-run`，确认只生成 ClaudeQQ 审批草案且 `claudeqq.mutation=false`、`sendImplemented=false`；运行 `bun scripts/cli.ts commander approval request --action read-token-file --dry-run`，确认返回 `validation-failed`。本测试不得部署、不得重启 Code Queue backend、不得 cancel/interrupt 运行任务、不得读取或输出 token 明文。

## T29 Playwright Commander Wrapper Contract

阅读 `AGENTS.md`（本项目 `AGENTS.md` 同时承担 `SKILL.md` 对 `scripts/cli.ts` 和 `scripts/playwright-cli.ts` 的解释职责）和 `docs/reference/cli.md`，然后用 cli 手动测试以下内容：运行 `bun scripts/playwright-cli-contract-test.ts`，确认输出 `ok=true`，并确认 `externalSkill` 字段明确记录外部 `~/.agents/skills/playwright` 是否仍是 passthrough/docs mismatch。运行 `bun scripts/playwright-cli.ts help`，确认帮助写明 wrapper 是短生命周期 JSON CLI、默认 headless、`--session` 只保存 storageState、不支持长驻 element-ref daemon，并给出 `xvfb-run -a` headed 兜底；该兜底依赖 `xvfb-run` 和 `xauth`。运行 `bun scripts/playwright-cli.ts --session=hwlab-dev screenshot http://127.0.0.1:16666/ /tmp/hwlab-dev.png --dry-run`，确认 `headless=true`、`sessionId=hwlab-dev`、`mutation=false`，且不会调用上游 `npx playwright`。运行 `bun scripts/playwright-cli.ts --session=hwlab-dev click e3`，确认返回非零状态和结构化 `unsupported-command`，下一步建议包含 `screenshot/open` 和 `xvfb-run -a`。在有可访问测试页面时运行 `bun scripts/playwright-cli.ts screenshot https://example.com /tmp/unidesk-playwright-example.png`，确认截图文件生成且 JSON 中含 `status`、`finalUrl`、`title`、`sessionSaved=true`；该测试不得访问 HWLAB 业务代码、不得部署、不得重启 Code Queue、不得读取或输出 token/secret。
