# HWLAB 指挥侧参考

本文定义 UniDesk 指挥官推进 `pikasTech/HWLAB` 时的固定入口、workspace、上线口径和常见误判边界。HWLAB 的项目内操作细则以 HWLAB 仓库自己的 `AGENTS.md` 和 `docs/reference/` 为准；本文只记录 UniDesk 侧如何进入和监督。

## 固定入口

- UniDesk 指挥侧 workspace：`/root/unidesk`，固定使用 `master`，开始前执行 `git status` 和 `git pull --ff-only origin master`。
- HWLAB legacy G14 DEV/PROD 已退役；`G14`/`G14-gitops`、`hwlab-dev`/`hwlab-prod`、17666/17667 和 18666/18667 不再是当前 source/runtime truth。退役状态和执行入口是 `bun scripts/cli.ts hwlab g14 retirement status|plan|execute --confirm`，细则见 `docs/reference/g14.md`。
- HWLAB 指挥侧目标选择必须以 issue 或 CLI 中明确写出的 lane/node 为准；只有没有明确目标时，才读取 `config/hwlab-node-lanes.yaml` 的默认值。`config/hwlab-node-lanes.yaml` 是 node、lane、workspace、CI/CD repo、namespace、GitOps path、公网入口和 Secret sourceRef 的配置真相，长期参考不能把 G14、D601、v0.2 或 v0.3 写成隐藏默认。
- HWLAB node-scoped `git-mirror` 的 GitHub upstream 标准传输使用 SSH，并由 `config/hwlab-node-control-plane.yaml` 的 `targets[].gitMirror.githubTransport.mode: ssh` 声明。D601/v03 固定通过 `GIT_SSH` wrapper 访问 `ssh://git@ssh.github.com:443/...`；node-global HTTP proxy 只作为 SSH CONNECT tunnel，不是 GitHub HTTPS auth/token transport。若运行面或 CLI 输出 `transport=https`、`GITHUB_TOKEN`、`git-mirror-github-token` 或 HTTPS token sourceRef，视为 control-plane drift/配置回归，先修 YAML 并执行 `hwlab nodes control-plane apply --node <node> --lane <lane> --confirm`，禁止改走 HTTPS、host workspace repair、fallback 或多来源仲裁。
- 进入任何 HWLAB lane 工作前，先解析目标 `--node <node> --lane <lane>` 或 issue 中的“目标分支/目标节点”，再用 YAML 解析出的 route/workspace/sourceBranch/kubeRoute/runtime namespace 做预检、快进和验证。例如 `目标分支: HWLAB v0.3` 且 `目标节点: D601` 时，工作面是 `D601:/home/ubuntu/workspace/hwlab-v03`、source branch 是 `v0.3`、k3s route 是 `D601:k3s`、runtime namespace 是 `hwlab-v03`、公网入口是 `https://hwlab.pikapython.com`。
- D518 的 HWLAB v0.3 固定主 workspace 是 `D518:/home/ubuntu/workspace/hwlab-v03`，固定跟踪 `github/v0.3`。D518 上的源码修改、PR 准备、运行面修复和 rollout 前 source truth 检查必须在该固定 workspace 下创建任务级 `.worktree/<task>`；master server 本地 `/root/HWLAB`、一次性 clone 或未由 YAML 选中的路径只能做只读对照，不能承担 D518 source truth。
- HWLAB 项目内长期规则入口仍以目标 repo 的 `AGENTS.md` 为准。进入已解析的目标 workspace 后，必须重新读取该 workspace 的规则文件；不能只凭主 server 的压缩上下文继续操作。
- 每次开始 node/lane 工作前必须通过 UniDesk SSH 桥检查目标 workspace，例如 `trans <node>:<workspace> sh -- 'git fetch origin <branch> && git pull --ff-only origin <branch> && git status --short --branch && git remote -v'`；若不满足目标 lane 预期，先修正 workspace，不能继续开发、render、polling 或部署。
- k3s 操作必须使用 YAML 解析出的 route 语法，例如 `trans D601:k3s ...` 或 `trans G14:k3s ...`。第一个 route token 必须定位分布式目标，后续 token 才是 operation。
- D601 node-scoped runtime（例如 `D601` + `v0.3`）不是 legacy；只要 issue/CLI 明确选择 D601 node/lane，就按 YAML 中的 D601 target 执行。D601 legacy 只指旧 DEV/迁移/回滚对照路径（如 `/home/ubuntu/workspace/hwlab-dev`、16666/16667 或历史 `deploy/deploy.json` wrapper），必须由 issue/CLI 明确写成 legacy/迁移/回滚才使用。
- `/root/HWLAB`、`/workspace/hwlab`、`/home/ubuntu/hwlab`、`/tmp/hwlab-*`、无关 runner clone、master-server checkout 或未由 YAML 选中的 workspace 都不能作为当前 HWLAB source truth。

## 关键 GitHub 入口

- UniDesk 总看板：`pikasTech/unidesk#20`。
- HWLAB 总看板：`pikasTech/HWLAB#7`。
- HWLAB 上位会议/冻结规则：`pikasTech/HWLAB#78`，当前 P0 是 M3 虚拟硬件可信闭环。
- HWLAB Cloud Workbench 用户界面：`pikasTech/HWLAB#99`。
- HWLAB 用户反馈入口：`pikasTech/HWLAB#108`。
- HWLAB 手动发布复盘与自动化收敛：`pikasTech/HWLAB#61`。

`pikasTech/unidesk#20` 只记录 UniDesk 侧 commander、Code Queue、CLI 和 infra governance。HWLAB 用户反馈、Cloud Workbench、DEV-LIVE、M3 闭环和其他产品事项必须写入 `pikasTech/HWLAB` 的 issue；如果需要在 #20 出现，只能作为 UniDesk 侧调度、CLI guard、infra blocker 或验收治理 lane 的上下文，而不能作为 HWLAB 产品 row。

## 规格真相与仓库 Reference 边界

HWLAB 需求规格的唯一长期正文在 UniDesk OA `project-management/PJ2026-01/specs/`。L0 总规格、硬件池、Agent编排、HarnessRL、客户端、用户管理、平台运维及其 L2/L3 都从这里索引；HWLAB repo 的 issue、PR、runtime reference 和阶段验证 issue 只能承载执行讨论、证据和操作入口，不能重新定义需求。

HWLAB v0.2/v0.3 仓库内 `docs/reference/spec-*`，以及已收编的 `cloud-workbench.md`、`code-agent-chat-readiness.md`、`g14-gitops-cicd.md` / `node-gitops-cicd.md`、`dev-runtime-boundary.md`、`gateway-outbound-demo.md`、`MVP-e2e-acceptance.md`、`architecture.md` 只保留到 UniDesk OA 的交叉引用或历史 stub。repo-local runbook 可以继续说明命令、路径、lane 和调试入口，但不得把公开能力、CLI/API 语义、测试大纲、Gateway 主动出站或 AgentRun 接入要求写成第二份规格正文。

公开入口、FRP/Caddy/域名和 Web/API 可达性需求以 [PJ2026-010604 公开入口](../../project-management/PJ2026-01/specs/PJ2026-010604-public-entry.md) 为权威；Prometheus、日志、trace、health、status 和运维监控需求以 [PJ2026-010605 可观测监控](../../project-management/PJ2026-01/specs/PJ2026-010605-observability-monitoring.md) 为权威。运行配置数值仍以 UniDesk YAML 和目标 HWLAB repo 的受控配置为准，长期 reference 只记录解析与验证方法。

重大规划型 issue 必须执行 P0 SPEC-first：P0 阶段先在 UniDesk OA `project-management/PJ2026-01/specs/` 维护对应 SPEC，确认 SPEC 编号、上级/关联规格、架构图、数据流图、关键时序图和代码引用规则，再进入后续实现。该 issue 范围内新增或修改的源码文件头部必须标注遵循的 SPEC 编号、短名和实现引用版本；自动生成、vendored、纯配置、锁文件或不能承载注释头的二进制产物可例外，但对应生成器、渲染器或配置入口必须能追溯到 SPEC。issue 正文和评论只承载执行计划、讨论和证据，不替代长期 SPEC。

## DEV 入口

- 退役 G14 DEV/PROD 前端/API 入口曾使用 `http://74.48.78.17:17666/`、`http://74.48.78.17:17667/health/live`、`http://74.48.78.17:18666/` 和 `http://74.48.78.17:18667/health/live`；这些端口不再作为当前 HWLAB runtime 证据。
- 当前入口必须从 `config/hwlab-node-lanes.yaml` 的选中 node/lane 读取，不从长期文档硬编码推断。G14 `v0.2` 的公开入口、G14 `v0.3` 的公开入口和 D601 `v0.3` 的 `https://hwlab.pikapython.com` 都只是各自 YAML target 的结果，不是彼此 fallback。
- D601 `v0.3` 前端/API 入口固定为 `https://hwlab.pikapython.com`，只能按 `config/hwlab-node-lanes.yaml` 中的 `lanes.v03.targets.D601.publicExposure` 验证；域名侧浏览器验收比裸 IP 或旧端口更能覆盖 Caddy、FRP、同源 cookie 和 Vue workbench 路由。
- D601 legacy DEV 前端/API 入口曾使用 `http://74.48.78.17:16666/` 和 `http://74.48.78.17:16667/health/live`；只在显式 D601 legacy 排障或迁移对照时使用，不能作为当前 HWLAB DEV 运行面证据。
- 旧公网 `:6666` 和 `:6667` 不是浏览器验收入口；内部 k3s service 仍可使用 `6667` 作为服务端口。
- 不要把 master 上的其他 UniDesk frontend/backend-core 路径误判为 HWLAB 前端。D601 legacy `16666/16667` 和 retired G14 DEV/PROD 端口的 FRP 说明只用于历史对照。

## D601 v0.3 User-Billing 管理闭环

D601 node-scoped `v0.3` 已按 `pikasTech/HWLAB#1176` 收敛到 Sub2API-style 的最小多用户运营基线。该基线包括 app-local 注册登录、用户自服务 API key/profile/password、admin users 管理、credit adjust、Code Agent reservation/terminal billing、`/v1/billing/summary`、plan/entitlement/quota/concurrency/RPM、admin usage/ledger filter/export、manual credit audit、redeem/manual recharge，以及 subscription/payment 的 provider-agnostic `unconfigured` 占位。审计细节、PR、PipelineRun、public smoke 和 closeout 证据以 #1176 及其 R1-R6 子 issue 为准；长期参考只记录完成态边界和复验入口。

该能力的业务 authority 仍是 HWLAB `hwlab-user-billing`。Cloud API 只做代理和同源 Web session/API key 鉴权，不维护第二套 user、credit、usage、ledger、redeem、subscription 或 payment 状态；Cloud Web 只消费 Cloud API 暴露的正式路径，不直连 user-billing 内部端口。

D601 `v0.3` 的 DB 执行面不再硬编码为外置 PostgreSQL，而由 UniDesk YAML `config/hwlab-node-lanes.yaml` 中选中 target 的 `runtimeStore.postgres.mode` 决定。mode 为 `local-k3s` 时，Cloud API、user-billing、workbench-runtime、project-management 和 OpenFGA 消费 `hwlab-v03` namespace 内的本地 `hwlab-v03-postgres`；复验和关闭证据应来自 `hwlab nodes control-plane plan|status`、`hwlab nodes secret status`、运行面 workload/Secret 摘要和 `external bridge/secrets not-required`，而不是要求本地 PostgreSQL 缺失。`externalPostgres` 与 PK01 platform DB YAML 必须继续保留为 `platform-service` mode 的候选配置；把 mode 切回 `platform-service` 时应重新启用 bridge/Secret 路径，但不得因为当前使用 `local-k3s` 删除外置配置。

复验 D601 `v0.3` user-billing 管理闭环时使用 `https://hwlab.pikapython.com`，不要用 G14 `v0.2` 的 `19666/19667` 或旧 D601 legacy 端口替代。最小 smoke 应覆盖：`/health/live` revision 指向目标 source commit；admin Web session 登录；admin 创建/list/disable redeem code；普通用户注册或登录后兑换 code；重复兑换 one-time code 不重复入账；admin redemptions 和 ledger 能查到同一 ledger/redemption；subscription/payment summary 在没有真实 provider 配置时明确返回 `unconfigured`；`/billing` 和 `/admin/billing` 页面加载且部署 bundle 包含对应 endpoint。验证输出只能记录对象 id、prefix、状态、计数和 redacted presence，不能打印 bootstrap admin password、raw redeem code、API key secret、DB DSN 或 provider token。

真实 payment provider、外部支付回调、订单结算和增长活动策略不是 #1176 完成态的一部分。只有当 `config/hwlab-node-lanes.yaml` 或 HWLAB 自有受控 YAML 明确声明 provider/sourceRef，并且 Secret sync、回调入口、ledger/order 状态机和 public end-to-end smoke 都齐备时，才可以把 D601 `v0.3` 从 provider-agnostic placeholder 扩展到真实支付；不得通过硬编码 provider、手写 k8s Secret、临时 SQL 或 Cloud API 平行账本绕过 user-billing authority。

## HWLAB 测试账号 YAML 归属

HWLAB node/lane 测试账号、bootstrap admin API key 观测、普通测试用户固定 API key、workbench 绑定、user-billing DB sync 输入和 sourceRef/targetKey 映射属于 UniDesk 指挥侧运维真相，必须写入 UniDesk `config/hwlab-test-accounts.yaml`，并通过 `bun scripts/cli.ts hwlab nodes test-accounts status|sync --node <node> --lane <lane>` 受控读取和同步。HWLAB 仓库可以保留应用代码、user-billing schema/migration 和业务 API，但不能另建一份账号 YAML 真相，也不能用运行面 Secret、pod env、日志或 DB 结果反推 owner-only key source。

`config/hwlab-test-accounts.yaml` 中的相对 `sourceRef` 以该文件的 `sourceRoot` 为根解析，属于 UniDesk 指挥侧 owner-only source，不要求也不应要求同名文件存在于 D601/G14 目标 host。目标 host 或 runtime pod 中没有该 env 文件不能判定为 key 缺失；应先用 UniDesk 受控 CLI 确认 source 与 target fingerprint，再把选中身份的 `HWLAB_API_KEY` 仅作为一次性进程环境注入目标 HWLAB CLI。不要为了复验把测试用户 key 持久化复制到目标 workspace、shell 启动文件、issue、日志或 Git tracked 文档。

该入口的输出只能记录 logicalId、role、permissions、workbench、sourceRef、sourceKey、targetKey、对象 id、byte count、prefix、fingerprint、presence、matchesSourceFingerprint 和 mutation 摘要；不得打印完整 `HWLAB_API_KEY`、完整 `DATABASE_URL`、base64 payload 或可复制凭据。D601 `v0.3` T1/T2 类验证如果需要 admin/test 两套身份，先用此 UniDesk YAML/CLI 准备账号，再在目标 HWLAB workspace 使用原 `hwlab-cli` 切换 `HWLAB_API_KEY` 做真实入口复验。

`test-accounts status|sync` 中涉及 DB 的读写也必须跟随选中 node/lane 的 DB authority。D601 `v0.3` 处于 `local-k3s` mode 时，工具不得从指挥机直接连接保留下来的外置 DB sourceRef；只有 mode 明确为 `platform-service` 时才使用外置 DB 路径。若旧 test-accounts DB 探测仍因外置 sourceRef DNS 或网络失败而报错，应登记为 CLI mode-awareness follow-up，不得把它当成 access-control 预置用户或根导航 ACL 的失败证据；这类 ACL 关闭证据应来自受控 preset-user Web/API 验证和 redacted Secret 状态。

身份、权限、workbench、trace/result 和 usage/billing 复验优先使用目标 HWLAB repo 的 typed CLI；`client request` 只能作为缺 typed wrapper 时的有界探测或后端路径确认。若 raw request 覆盖了真实用户验收所需的字段，关闭前必须把缺失的 typed CLI 包装登记到对应 HWLAB issue，不能把 raw request 静默当成长期正式用户入口。

### Code Agent TraceResult 展示证据

Code Agent trace 的长期 API 和 Web 行为规格以 UniDesk OA 为权威：API 资源形态见 [PJ2026-010403 API契约](../../project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md) 的 `GET /v1/agent/traces/{traceId}`，Web 自动补齐和分片显示见 [PJ2026-010401 Web工作台](../../project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md) 的 Trace阅读要求。UniDesk 指挥侧只记录验证入口和误判边界，不在本参考重新定义 trace endpoint、分页字段、游标语义或自动折叠策略。

实时 Trace 展示必须把 turn 状态和 trace event 分页视为两条独立读路径。`/v1/agent/turns/:traceId` 只回答 running/terminal/final/error 等 turn 状态；`/v1/agent/traces/:traceId` 只负责按下游读 cursor 拉取已经持久化的 trace events。Web 在运行中不能等 turn terminal 后才 hydrate trace，也不能让 compact turn snapshot 覆盖已经拉到的 trace rows。后端刷新 AgentRun 上游失败时，trace API 仍应返回本地 trace store 中已有的分页快照，并把 refresh failure 作为诊断字段暴露；已有事件不得被硬 502 遮住。关闭“运行中 Trace 加载不出”类 issue 时，应证明 running 期间 trace API 与 Web DOM 都能看到已写入事件，而不是只展示最终完成后的 timeline。

Workbench projection/read model 是持久化投影，不是 GET 侧隐式修复路径。Cloud API 重启、内存 finalizer 丢失或投影 worker 中断后，恢复只能由受控后台 projector/resumer 从 durable session、durable trace 和 AgentRun source cursor 继续推进；`/v1/agent/turns/:traceId`、`/v1/agent/traces/:traceId` 和 Web hydrate 不得为了让一次读取看起来正确而隐藏写入或 remap command。排查“AgentRun 已完成但 Workbench 仍 running/pending”时，先比较 AgentRun command result/session terminal、AgentRun raw event 最大 `sourceSeq`、HWLAB durable trace 最大 `sourceSeq` 和 session/turn 投影状态；若 AgentRun 已 terminal 且 HWLAB trace 落后，应归为 HWLAB projection resume gap，并用 YAML-first 配置的 projector/resumer 修复与验收。

Workbench 投影相关问题的禁用模式以 HWLAB issue 历史为判定边界。`pikasTech/HWLAB#1585` 已证明 GET/read-side 补 AgentRun result 会把恢复能力藏进一次读取，Cloud API 重启、rollout 或内存 finalizer 丢失后仍会让 Workbench 长期停在旧 `lastProjectedSeq`；因此“事后修补/0repair”不能替代 durable projector/resumer。`pikasTech/HWLAB#1596` 已证明 turn/card completed 与 TraceEventPage 不一致会直接变成用户可见的“已完成但暂无可读 Trace”；因此不能让 AgentRun raw result、session summary、turn snapshot、trace tail 或 DOM 互相竞争，再用优先级规则仲裁显示状态。`pikasTech/HWLAB#1690` 进一步固定 Trace 视觉顺序权威：`projectedSeq` 必须由 durable projection 幂等分配，局部 `event.seq`、`sourceSeq`、输入顺序和 renderer 文本匹配不能参与视觉位置仲裁；历史 collision 应暴露为 projection blocker，而不是交给读侧重排。读侧也不得从 event `completed`、message text、elapsed timeout 或 final result cache 推测 lifecycle；这些只能作为诊断输入，最终事实必须由唯一 Workbench projection 写出。具体 Web/CLI renderer 和 web-probe 验收口径统一见 `$unidesk-webdev`。

TraceEventPage 自身的分页契约修复可以在同一持久化快照内做稳定排序和输出 cursor 归一化，但不得改变 lifecycle、补写 projector 状态或引入第二事实源。修复完成后的关闭证据必须同时覆盖同一 session/trace 的 turn、trace events、range/monotonic cursor 和 DOM Trace 可读性，避免只凭 completed card 或单个 API 通过误关。

Code Agent trace/result 展示类问题的 typed CLI 关闭证据以 `hwlab-cli client agent result <traceId>`、`hwlab-cli client agent trace <traceId> --render web` 和必要的 `hwlab-cli client agent inspect --trace-id <traceId>` 为准，具体操作说明见 `$hwlab-code-agent` skill。三者的默认 JSON 都应暴露 `traceResultSummary`，其中 `ids`、`toolCalls`、`agentMessages`、`finalResponse`、`diagnostics`、`counts` 和 `upstreamGaps` 是给用户和审计者阅读的稳定摘要；不要要求关闭者从 raw `body`、`runnerTrace.events`、`rows` 或 `terminalEvidence` 人工拼事实。

`result` 和 `trace --render web` 必须能直接证明 final assistant response、实际工具调用及状态、关键 trace/session/conversation/run/command/runner ID 和 runner/provider/lane 诊断。`inspect` 用于确认 trace 所属 session/conversation/thread、恢复上下文和下一步入口；它可以佐证 ID 和上下文，但不能单独替代 final response 或 Web renderer 行。验证必须打到 issue/CLI 选中的同一 node/lane public origin 或等价 Cloud Web/Cloud API dispatcher，不能用临时 AgentRun manager 调用、手写 raw request 或旧 lane trace 代替。

失败详情类问题必须优先核对 `client agent result <traceId>` 的顶层 `error` 与 `agentRun`。`trace --render web` 只证明 rows/timeline 渲染，可能不携带 terminal result 的 `error`、`agentRun.runId`、`commandId`、`runnerId`、`jobName`、`namespace` 或 `terminalStatus`；Cloud Web 恢复会话时必须从 result 补齐这些诊断，再渲染详情弹窗。空字段不得渲染成大面积“未观测”占位；用户第一眼应看到错误码、错误类别和错误消息，有值的 AgentRun provenance 才进入状态摘要。

AgentRun terminal `failed`、`blocked` 或 `canceled` 也是最终结果，不是“没有 final response”。当 `/v1/agent/chat/result/:traceId` 或 `/v1/agent/turns/:traceId` 返回顶层 `error.message`、`blocker.summary` 或 terminal failure message 时，HWLAB Cloud API 必须把可读错误生成为 `finalResponse.text` 和 `traceSummary.finalAssistantRow`，Cloud Web 的 final response 展示区必须直接显示该错误文本。TraceTimeline 可以同时展示失败事件，但不能让用户只能从 trace rows 里找错误；也不能用“没有返回可展示的 final response”覆盖已有 terminal error。

`traceResultSummary.valuesPrinted=false` 只是脱敏声明，不等于免检。关闭前仍应扫描输出中是否出现完整 `HWLAB_API_KEY`、`hwl_live_*`、Authorization Bearer header、DB DSN、Secret payload 或 provider token。若 `upstreamGaps` 出现 `prompt_not_returned_by_upstream`，表示上游 trace/result payload 没有返回可脱敏展示的 prompt metadata；客户端不得发明 prompt 真相，应把该缺口拆到 Agent 编排或 trace payload issue，并说明它是否阻塞当前展示项。

### Workbench 浏览器回归专项

Workbench 浏览器回归需求以 UniDesk OA [PJ2026-010401 Web工作台](../../project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md) 为权威；具体 Web 开发、fake-server Playwright、fixture 采集脱敏、移动端断言、截图 artifact 和线上 web-probe 闭环统一见 `$unidesk-webdev`。HWLAB repo 只保留入口边界：专项代码位于 `web/hwlab-cloud-web`，命令必须在 issue/CLI 选中的目标 node/lane workspace 或独立 worktree 上运行，不得在 master server 本地跑浏览器或仓库级前端 check。

MDTODO/Project Management Web 的重写或布局类 issue 以 UniDesk OA 对应 SPEC 为权威；关闭时必须用选中 node/lane 的 public origin 和 `$unidesk-webdev` 的 `observe command` 证据证明默认任务正文、Rxx 树、Source/File 选择、报告侧栏和报告全屏状态。`observe` 同时采集 control/observer 页面时，显式 command result、control URL 和截图是用户动作证据；被动 observer 周期刷新或 stop 后根路由空态只能作为对照，不能覆盖用户入口截图和 command JSON。

Workbench session lifecycle、空 session 后台回收、archived/deleted deep link 和 GET 纯读投影的判定口径统一见 `$unidesk-webdev`。指挥侧关闭这类 issue 时只记录选中 node/lane、受控配置来源、后台 mutation/GC 证据、list/detail/messages/deep link 摘要和截图 SHA；TTL、interval、batch 等可调数值以选中 lane 的受控配置为准，不在本参考维护第二份数值真相。

### Web Live DOM Probe 验收

`scripts/web-live-dom-probe.mjs` 和 UniDesk `hwlab nodes web-probe run|script` 是 Cloud Web 原入口 DOM 验收底座。登录 sourceRef、同源 page helper、URL 构造、readiness、Trace 采样、浏览器噪声分类和 artifact 规则统一见 `$unidesk-webdev`；本文件不复制使用细则，避免与 UniDesk WebDev 操作面分叉。只修改该 helper 时属于无服务交付，按目标 HWLAB repo `AGENTS.md` 选择直接提交或 PR，关闭证据写明 `rollout=not-applicable`。

Cloud Web runtime config 或 YAML-first UI policy 类修复关闭前，除源码/fake-server 证据外，还必须证明选中 node/lane 的配置已进入部署链路：YAML 字段、GitOps render/env、Deployment 或 Pod env、public origin DOM/API 证据要分别记录。缓存、Pod 滚动和 browser helper 返回包装对象的细节由 `$unidesk-webdev` 规定；本文件只要求这些层次不能混为一个结论。

### Cloud Web Workbench Prompt 浏览器闭环

Workbench prompt、TraceTimeline、final response、详情弹窗、session 切换、deep link 和运行态一致性问题的浏览器证据要求统一见 `$unidesk-webdev`；typed CLI 交叉验证仍见 `$hwlab-code-agent`。这里不再复制 selector、fresh context、turn authority 或登录排障细则，避免与 WebDev 操作面产生多路径。

## HWLAB FRP 维护

HWLAB 公网 FRP server 由 master server 上的 `hwlab-frps-dev` 容器承担，容器使用 host network，并把 `/opt/hwlab-frp/frps.dev.toml` 只读挂载到 `/etc/frp/frps.toml`。这个 server 侧 allowlist 是 UniDesk 指挥侧维护对象，不属于 G14 k3s GitOps desired state；G14 侧 `frpc` ConfigMap/Deployment 只负责各 runtime namespace 的客户端 tunnel。

新增或恢复 HWLAB 公网入口时，先判断问题是否只是 server 侧 `allowPorts` 缺口。若 `frpc` 日志出现 `port not allowed`，优先在 master server 修改 `/opt/hwlab-frp/frps.dev.toml` 的 `allowPorts`，而不是改 active runtime lane 的 GitOps、Service 或 `frpc` ConfigMap。修改前保留一份本机备份，例如 `/opt/hwlab-frp/frps.dev.toml.bak-<reason>`；修改后只重启 `hwlab-frps-dev`，不要重建镜像、清理 Docker volume、重启无关 UniDesk/HWLAB 服务或触碰数据库状态。

当前 HWLAB FRP server allowlist 至少应覆盖 `config/hwlab-node-lanes.yaml` 中 active target 声明的 publicExposure 入口以及仍被明确使用的维护端口。Legacy `16666/16667` 和 retired G14 DEV/PROD `17666/17667`、`18666/18667` 只作为历史对照，不应作为新增 runtime 入口要求。新增端口或域名必须对应一个明确的 node/lane/namespace/runtime 入口，不能把大范围端口段作为默认放行策略。

FRP 维护验证顺序是：确认 `hwlab-frps-dev` 或 `config/hwlab-node-lanes.yaml` 指定的 publicExposure 入口仍挂载/渲染目标配置；重启或 apply 后用等价只读命令确认 FRP/Caddy 正在监听目标公网端口或 hostname；再在目标 namespace 查看 `frpc` 日志，确认对应 proxy `start proxy success`；最后验证选中 node/lane 的 active runtime 入口。D601 `v0.3` 验证使用 `https://hwlab.pikapython.com`；其他 node/lane 使用 YAML 中的 public URL。

FRP 文档、issue 和日志只能记录端口、容器名、ConfigMap 名、Secret 对象/key 是否存在和健康摘要；不得记录 Secret value、provider token、完整 DB URL、Codex auth JSON 或其他凭据内容。

## 门禁最小化与扩容治理

不要滑向不必要的复杂门禁是 HWLAB 指挥侧通用原则。Legacy G14 DEV/PROD 退役、runtime lane 扩容、CI/CD 迁移、运行面热修和文档治理都应优先靠固定边界、清晰命名、唯一真相源、标准入口和长期参考文档收敛，不要把每个设计约定、运行策略或回滚手册都做成新的 preflight、guard、gate 或报告生成器。

旧 DEV/main/G14/D601 特例门禁如果阻碍 issue/CLI 明确选中的 node/lane 路径，默认处理是从当前调用链删除，而不是做兼容迁移、fallback、legacy mode、双路径绕行或在旧门禁上叠加例外。新增门禁只能覆盖明确高价值风险，且必须最小、低噪声、容易删除；资源配额、RBAC 命名、清理策略、回滚顺序、人工同步策略等默认是设计约定或 runbook，不是 CI/CD 通过条件。

每个 runtime lane 的硬边界必须从 `config/hwlab-node-lanes.yaml` 的选中 target 解析：source branch、CI/CD source repo、GitOps branch/path、runtime namespace、publicExposure、service 列表和 workspace 都以 YAML 为准。长期文档只记录“如何解析和验证”，不得把某个 node/lane 的当前数值写成全局默认。其他事项应先作为决策表或 runbook 固化，只有被证明无法靠边界和标准入口自然收敛时，才允许加最小检查。

## 最小 Device Agent/Gateway 桥接模型

最小打通目标是只新增桥接面，不改动既有 HWLAB 应用、GitOps、FRP、CD 或前端路径：

- 在选中 node/lane runtime namespace 手动建立一个 standalone `device-agent-71-freq` Pod/Deployment 和 ClusterIP Service。它暴露设备语义入口，例如 `/health`、`/skills`、`/workspace/*`、`/run`，并把真实硬件调用转成 HWLAB cloud-api 的 gateway operation，而不是在 Pod 内直接访问 Windows 硬件。
- 在 `D601:win` 上启动 `hwlab-gateway`，作为 71-FREQ/ConStart/Keil/串口资源的外部 host bridge。gateway 通过公网或受控网络出站连接选中 node/lane 的 cloud-api，注册稳定的 `gatewaySessionId`、`resourceId` 和 `capabilityId`。
- `hwlab-gateway` 是 Windows 长驻 outbound poll 进程，不能用 `trans D601:win cmd start ...` 或 PowerShell `Start-Process` 直接挂在一次性 trans/tran 会话下；这种启动方式可能继承输出句柄或被 provider 按子进程树等待，导致 trans/tran 卡住并阻塞后续 provider session。临时实验也应通过 Windows Task Scheduler、Windows Service、NSSM、PM2 service 或等价 detached launcher 启动，`trans` 只负责触发和读取状态；通用规则见 `docs/reference/windows-passthrough.md`。
- D601 Windows gateway 的最小配置必须来自 profile 或环境变量，核心字段是 `HWLAB_GATEWAY_CLOUD_URL=<active-runtime-lane-cloud-api>`、`HWLAB_GATEWAY_ID`、`HWLAB_GATEWAY_SESSION_ID`、`HWLAB_GATEWAY_RESOURCE_ID`、`HWLAB_GATEWAY_CMD_CAPABILITY_ID`、`HWLAB_GATEWAY_CMD_EXEC_ENABLED=1`、`HWLAB_GATEWAY_DEMO_OPEN=1`、`HWLAB_GATEWAY_MAX_INFLIGHT` 和 `HWLAB_GATEWAY_CMD_TIMEOUT_MS`。这些值用于声明能力和执行边界，不得散落在 device-agent 代码里。
- device-agent 访问集群内 cloud-api 时优先使用选中 runtime lane 的 Service DNS；Node 实现访问 `6667` 时遵循 Node/Lane 运行面口径里的 bad-port 规则，不为 device-agent 单独维护另一套例外。
- 71-FREQ 的 device profile 必须配置化保存，至少包含工程根目录、Keil project/target、默认串口波特率、gateway/resource/capability 选择器和 workspace 根。不得把 `F:\Work\ConStart`、工程名、串口号或 probe UID 硬编码进 device-agent 镜像。
- 最小验收顺序是：选中 node/lane cloud-api `/health/live` ready；D601 Windows 能访问该 lane 的 public `/health/live`；D601 `hwlab-gateway` 注册后 cloud-api 能看到 gateway session/resource/capability；`device-agent-71-freq` `/health` 和 `/skills` 返回 ready；通过 device-agent 发起一条只读或 `echo` 级 gateway shell operation，并返回 operation/evidence/trace 摘要。
- 这个模型只证明 `device-agent Pod -> 选中 lane cloud-api -> D601 hwlab-gateway -> Windows host` 的控制链路。Keil 编译下载、串口日志抓取和 workspace CRUD 可以作为后续 device-agent skill 子命令逐步接入；未接入前不能把 device-agent 标成完整 71-FREQ 硬件代理。

## Master Server 校验边界

- master server 是 UniDesk/HWLAB 的生产入口且资源紧张；它只能承担轻量源码编辑、Git 操作、日志/健康观察、JSON CLI 指挥和受控 CD 审阅，不能承担正式校验执行面。
- 禁止在 master server 上运行 HWLAB 或 UniDesk 的仓库级 `check`/`test`/smoke 命令，包括但不限于 `bun scripts/cli.ts check`、`node --test`、`node web/hwlab-cloud-web/scripts/check.mjs`、`node scripts/dev-cloud-workbench-smoke.mjs`、Playwright/browser layout smoke，以及其他会长时间占用 CPU/内存、启动浏览器或遍历大仓库的校验流程。
- 需要正式验证时，固定切到 issue/CLI 选中的 node/lane workspace、k3s/Tekton、HWLAB repo-owned CI 或其他获批外部执行面；master server 只负责发起、观察和记录，不负责实际跑 check。
- 如果为了排障必须从 master server 生成命令或查看源码，后续验证命令也必须显式改到目标 node/lane 路径执行，例如 `trans D601:/home/ubuntu/workspace/hwlab-v03 sh -- ...` 或 `trans D601:k3s ...`，而不是直接在 `/root/unidesk` 或 master server 上本地运行。

## Node/Lane 运行面口径

HWLAB 当前真实 runtime 由 issue/CLI 选中的 node/lane 决定。只读观察使用 YAML 解析出的 kube route、namespace 和 public endpoint；例如 D601 `v0.3` 使用：

```sh
trans D601:k3s kubectl -n hwlab-v03 get deploy,svc,pod -o wide
```

HWLAB node/lane control-plane 的 PipelineRun 失败定位优先使用 UniDesk 受控状态入口，而不是先手工拼 TaskRun/Pod 查询：`bun scripts/cli.ts hwlab nodes control-plane status --node <node> --lane <lane> --pipeline-run <name>`、`trigger-current --wait` 的返回对象，以及异步 `bun scripts/cli.ts job status <jobId> --tail-bytes 12000` 都应直接暴露失败 TaskRun、Pod、container、失败 step、termination reason 和 bounded `trans <node>:k3s logs --namespace hwlab-ci --pod <pod> --container <container> --tail 200` 查看命令。默认状态输出只给诊断命令和受控摘要，不打印完整 pod 日志、Secret、完整 DSN、API key 或其他可复制凭据。遇到 service build 的 `step-publish` 失败时，下一步先跑 `bun scripts/cli.ts platform-infra sub2api status --target <node>` 和 `bun scripts/cli.ts platform-infra sub2api validate --target <node>`，区分 Sub2API/proxy 整体故障和单上游 transient，再选择受控 rerun 或修复 artifact-publish/envRecipe 的有限 retry。

`hwlab-cloud-api` 和 `hwlab-edge-proxy` 在集群内可使用 `6667` Service 端口；对外入口以选中 target 的 publicExposure/public URL 为准。Node/Bun/undici 的 Fetch 实现会按 Fetch bad-port 规则拒绝 `6667`，因此任何需要代理、转发、探测或服务间访问该端口的 Node 实现都必须使用 `node:http`/`node:https`、已有 repo-owned HTTP helper，或改用不触发 bad-port 的受控代理端口；不要把 Fetch bad-port 造成的 `fetch failed` / 502 误判为 Service DNS、PVC、数据库或 trace 数据缺失。G14 local details 见 `docs/reference/g14.md` 和 G14 节点 `/root/docs/hwlab-g14-workspace.md`；D601 node-scoped target 以 `config/hwlab-node-lanes.yaml` 的 `nodes.D601` 和 `lanes.v03.targets.D601` 为准。

D601 原生 k3s 是 D601 node-scoped runtime 的正式控制面；D601 legacy 对照也使用同一 native k3s guard。任何 D601 k3s 操作都必须显式使用 UniDesk route `D601:k3s` 或等价的 `/etc/rancher/k3s/k3s.yaml`，不能使用裸默认 kubeconfig：

```sh
KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev get deploy,svc,pod -o wide
```

D601 上不要直接相信默认 `kubectl` context。默认 context 可能是 `docker-desktop`，它会展示另一套与公网 legacy `16666/16667` 无关的状态，并可能给出误导性的 `ImagePullBackOff`。

历史 D601 legacy `frpc` 配置不是 D601 host `/etc/frp/frpc.toml`，而是 D601 legacy `hwlab-dev` namespace 里的 `hwlab-frpc-config` ConfigMap 和 `hwlab-frpc` Deployment。D601 `v0.3` publicExposure 以 `config/hwlab-node-lanes.yaml` 和 PK01 Caddy/FRP target 为准。

## Code Agent 模型通道

HWLAB 的 DeepSeek/Codex 兼容性属于 HWLAB runtime 规则，长期真相在 HWLAB 仓库 `AGENTS.md` 和目标 lane 对应的 `docs/reference/`。UniDesk 指挥侧只保留监督边界：诊断这类问题时，先在选中 node/lane 的目标 Pod 或临时 passthrough Pod 内闭环证明 Codex stdio、Responses 请求、tool call/tool result 顺序、模型目录和真实 provider 返回，再考虑 GitOps/CI/CD；不要用完整 CI/CD 作为每轮协议试错工具。

DeepSeek profile 应优先使用成熟 Responses/Anthropic 协议桥接方案，例如 Moon Bridge，来保留 prompt cache、tool-result 顺序和模型目录语义。HWLAB repo-owned compatibility bridge 只能承担薄层职责，例如 Codex zstd request body 解码、非 `function` tool 过滤、`/v1/models` 或 readiness 适配；不要在 UniDesk 或 HWLAB 中手写完整 Responses-to-Chat 转换器替代成熟桥接层。Secret 值、provider token 和完整模型请求正文不得写入 UniDesk 文档、issue 或日志。

HWLAB 与 AgentRun 协同修复必须按 `docs/reference/agentrun.md` 的职责边界执行：AgentRun 拥有的共享执行、trace/result、backend event、runner 和 CLI 能力缺失时改 AgentRun；HWLAB 拥有的鉴权、Cloud Web/CLI 对外 API、adapter 消费、业务和前端问题改 HWLAB。不得用一侧的观测、fallback 或兼容逻辑迁就另一侧未实现或未修复的能力。

### Code Agent Provider Profile 配置与验收

本小节只适用于明确选择 HWLAB `v0.2` provider profile 的任务；其他 node/lane 的 profile 配置必须先按 issue/CLI 目标和 `config/hwlab-node-lanes.yaml` 解析运行面，再读取目标 HWLAB repo 的对应规则。G14 节点参考、CLI 参考和 `hwlab-code-agent` skill 只交叉引用这里；AgentRun 内部 Secret 物化和 backend adapter 设计仍以 AgentRun 仓库自身为准。

HWLAB v0.2 provider profile 必须通过已部署的 HWLAB Cloud API/CLI 管理，正式入口是 `hwlab-cli client provider-profiles`。不要把手工 patch `agentrun-v01` Secret、直接调用 AgentRun manager 或临时 runner job 当作正式配置路径或关闭证据；这些只可作为基础设施定位证据。标准执行面是 `G14:/root/hwlab-v02`，调用前锁定 `HWLAB_RUNTIME_NAMESPACE=hwlab-v02`、`HWLAB_RUNTIME_WEB_URL=http://74.48.78.17:19666` 和 `HWLAB_RUNTIME_ENDPOINT_LOCKED=1`，`HWLAB_API_KEY` 从 `/root/.config/hwlab-v02/master-server-admin-api-key.env` 加载。

当明确需要把当前 operator 的 Codex 凭据作为 AgentRun 动态 profile 提供给 HWLAB Code Agent 或 CaseRun 使用时，固定操作手册在 `$hwlab-code-agent` 的 `AgentRun 动态 sub2api profile` 小节。该场景是 AgentRun runtime profile 投影，不替代上面的 HWLAB provider-profiles 正式配置路径；默认 profile 名为 `sub2api`、模型为 `gpt-5.5`，优先使用 G14 k3s 内 Sub2API ClusterIP 作为 `base_url`，并只记录 SecretRef、keyPresence、hash suffix 和原入口验收结果。

`config.toml` 和 Codex `auth.json` 是两个独立输入。`set-config <profile> --config-stdin` 写入 profile 的 Codex 配置文本；`set-auth-json <profile> --auth-json-stdin` 写入完整 Codex auth JSON object，并在 AgentRun runtime Secret 中作为 `auth.json` key 保留。`set-key --key-stdin` 只用于单值 API key profile；当输入本来就是 Codex `auth.json` 时，不得再把它压扁、拆成单个 key、改走 legacy API-key-only 路径或保留旧断言阻塞提交。遇到 CLI 不支持完整 auth JSON、输出不可见或缺少 hash/keyPresence 等证据时，先补 HWLAB CLI/API 和 AgentRun provider-profile 能力，再继续试机。

标准命令形态如下，文件名可按实际 profile 替换：

```bash
bun tools/hwlab-cli/bin/hwlab-cli.ts client provider-profiles set-config <profile> --config-stdin --no-session < config.toml
bun tools/hwlab-cli/bin/hwlab-cli.ts client provider-profiles set-auth-json <profile> --auth-json-stdin --no-session < auth.json
bun tools/hwlab-cli/bin/hwlab-cli.ts client provider-profiles list --no-session
```

AgentRun `v0.1` 运行面物化对象是 `agentrun-v01` namespace 中的 `agentrun-v01-provider-<profile>` Secret。基础 Codex profile 的稳定 key 是 `config.toml` 和 `auth.json`；需要本地模型目录的 profile 还必须按 AgentRun backend profile 声明补齐额外 key，例如 `dsflash-go` 必须同时具备 `model-catalog.json`，且 `config.toml` 中的 `model_catalog_json` 指向 runner 内 profile-local catalog 路径。文档、issue、trace 和 CLI 输出只能记录 profile 名、SecretRef、key 是否存在、字节数、redacted hash/hash suffix、resourceVersion 和验证结果；不得记录 Secret value、完整 `auth.json`、provider token、完整 API key 或可复用凭据命令。

profile 配置后的最小真实验收是通过同一 HWLAB v0.2 Cloud API/Web dispatcher 路径创建 Code Agent session 并完成一轮真实 turn：`client agent session create --provider-profile <profile>`，再 `client agent send --session-id <sessionId> --provider-profile <profile>`，最后用 `client agent result <traceId>` 和 `client agent trace <traceId> --render web` 确认终端状态和最终 assistant 文本。只看到 Secret 存在、AgentRun canary 通过、PipelineRun 成功或源码测试通过，都不能替代这一真实入口验收。对 profile-sensitive CaseRun 或 provider 修复，关闭证据还必须来自原入口 `case run`/Web 等价路径，结果中应同时显示 `requestedProviderProfile`、`resolvedBackendProfile`、AgentRun `backendProfile`、模型名和终端状态；涉及 ds-flash/Moon Bridge 时，还要确认 `deepseek-v4-flash`、1M context/model catalog 元数据生效，且归档中不再出现 `responses/compact 404` 或 `404 page not found`。当前 HY 凭据对的稳定 profile 名是 `hy`；复测时使用同一标准入口，不在任何长期文档或 issue 中记录凭据内容。

CaseRun 的 case/registry/aggregate、评价、回放、训练反馈和硬件证据闭环需求以 UniDesk OA 的 [PJ2026-0103 HarnessRL](../../project-management/PJ2026-01/specs/PJ2026-0103-harness-rl.md) 为权威；HWPOD 服务、AI 网关和 HWLAB 到 AgentRun 的装配接入分别以 [PJ2026-010103 HWPOD服务](../../project-management/PJ2026-01/specs/PJ2026-010103-hwpod-service.md)、[PJ2026-010104 AI网关](../../project-management/PJ2026-01/specs/PJ2026-010104-ai-gateway.md) 和 [PJ2026-010205 HWLAB接入](../../project-management/PJ2026-01/specs/PJ2026-010205-hwlab-dispatch.md) 为权威。HWLAB 仓库内 `docs/reference/spec-hwpod-harness.md` 只保留历史交叉引用 stub；UniDesk 指挥侧按 issue/CLI 选中的 node/lane 重新读取 HWLAB `AGENTS.md`、使用目标 workspace 原入口验证，并在关闭 issue 时记录 runId、traceId、provider profile、registry commit 和负向检索摘要。不要在 UniDesk reference 里复写 CaseRun prompt 细则或 `.agents/skills` 装配实现。

CaseRun skill 交付边界按 `docs/reference/agentrun.md#agentrun--hwlab-协同职责边界` 判定：专用 skill 通过 AgentRun `gitbundle` 装配给 Code Agent，subject repo 不能携带 `.agents/skills` 副本。关闭要求涉及 skill 的 case 时，除 runId、traceId、provider profile 和 registry commit 外，还应记录 `resourceBundlePolicy`、实际装配的 skill 名、AgentRun/CaseRun 归档中的 skill 读取证据，以及 subject repo diff 或 artifact 中没有新增 `.agents/skills` 的负向检索结果。

CaseRun `summary.md`、`result.json` 和 registry aggregate 是阅读索引，不是替代原始执行证据的判定器。若 summary 中的 build/download/UART 字段与 AgentRun trace、HWPOD command output、Keil job、下载日志或 UART 输出不一致，应先用原始 trace rows、terminal command id、硬件命令输出和串口证据收口当前用户问题，同时把 summary/aggregate 语义缺口提到拥有该契约的仓库继续修复。D601 硬件 case 的 UART 证据必须来自当前 run 的串口输出；`serial-monitor` 服务或 Windows wrapper 不可用时，应先恢复或登记基础设施问题，不能把串口不可见误判为 subject 源码失败。

### D601 v0.3 Web CaseRun 最小闭环

D601 `v03` 的 Web CaseRun 最小闭环是 Cloud Web -> Cloud Web proxy -> Cloud API `/v1/caserun*` -> built-in/configured case repo -> HWPOD node ops -> Python UI node/HWPOD -> Keil。验证 Web 用户入口时使用 UniDesk `bun scripts/cli.ts hwlab nodes web-probe script --node D601 --lane v03`，让 `config/hwlab-node-lanes.yaml` 中的 `webProbe.defaultOrigin` 选择内部 IP 或公网入口；只有显式临时覆盖时才传 `--url`，不要把内部 IP 写进脚本或 issue 作为长期默认。

Web-probe short script 仍受 60s 级别的交互超时约束；长 CaseRun 应拆成“启动 run”和“轮询 run”两段，或使用 observe/专用归档入口承接下载、UART 和 Arm2D stage D 这类长证据链。Cloud Web 对 GET `/v1/*` 可以走通用代理，但 POST/写操作必须在 Cloud Web route policy 中显式登记认证代理路由；新增 CaseRun 写入口时不能只验证 Cloud API 直连。

当前 Web smoke case 使用 `d601-f103-v2-compile` 的 Keil compile-only 能力。关闭 D601/v03 Web CaseRun compile-only 问题时，证据至少记录 runId、registry aggregate sha256、Keil jobId、`hwpodExitCode`、`.hex`/`.axf` artifact、YAML 选中的 origin、HWLAB source revision 和 GitOps revision。compile-only 不要求下载日志、UART 输出或 AgentRun traceId；需要这些硬件证据时按 `pikasTech/HWLAB#2120` 和 `pikasTech/HWLAB#2121` 继续扩展，不要把 compile-only smoke 误判为完整下载/UART/Arm2D 闭环。

## D601 Legacy HWLAB DEV CD Wrapper

以下 UniDesk wrapper 是旧 D601 DEV CD 指挥入口，只用于显式 legacy 诊断和迁移对照。当前 HWLAB 发布、GitOps 和运行面收敛必须优先按 issue/CLI 选中的 node/lane 与 HWLAB repo-owned 规则执行；不要把下面的 D601 legacy wrapper 当作 D601 `v0.3` 或其他当前 HWLAB release truth。

本节里的 `deploy/deploy.json` 只属于 D601 legacy DEV CD wrapper。当前 node/lane 的部署配置源以 HWLAB repo 和 UniDesk YAML 声明为准，并由对应 format-agnostic config layer 读取；不要把 legacy `deploy/deploy.json` 当作 D601 `v0.3` truth。

UniDesk 指挥侧固定入口：

```sh
bun scripts/cli.ts hwlab cd status --env dev
bun scripts/cli.ts hwlab cd audit --env dev
bun scripts/cli.ts hwlab cd preflight --env dev
bun scripts/cli.ts hwlab cd apply --env dev --dry-run
```

wrapper 的职责是把 host commander 常用的 HWLAB DEV rollout 查看/准备动作收敛到单一入口。默认路径通过 UniDesk main-server frontend/backend-core 的 provider `host.ssh` 能力进入 D601；frontend transport 先用多个短 `host.ssh` 命令把远端 runner 分块上传到 `/tmp/unidesk-hwlab-cd/`，再在 D601 上执行有界检查脚本，避免 provider-gateway 的短命令长度限制成为审计入口单点故障。经 frontend/backend-core 返回的 stdout 只允许承载短 JSON 摘要；完整结果必须写入 D601 `~/.state/unidesk-hwlab-cd/<run-id>/result.full.json`，防止 backend JSON 安全摘要把 stdout 截断后导致 CLI 失明。它只调用 HWLAB repo-owned 受控脚本，不在 UniDesk 内重写发布流程或拼接 ad hoc `kubectl apply`：

- 默认 HWLAB CD repo 是每次运行在 D601 `~/.state/unidesk-hwlab-cd/<run-id>/ephemeral-repo/HWLAB` 新建的一次性 clone。一次性 repo 只从专用 full bare cache `~/.cache/unidesk/hwlab-cd/git-cache/HWLAB.git` 拷贝生成，必须使用 `--no-hardlinks` 形成独立 `.git` 对象库，不能通过 `--shared` 或 alternates 在运行时依赖 cache 对象库。cache 本身只允许作为 HWLAB CD 专用 Git 加速源，不承载 runner workspace、部署副本、手工改代码、报告留痕或任何其他用途。
- 专用 cache 由当前 `host.ssh` 执行用户拥有，`~/.cache/unidesk/hwlab-cd` 必须保持 owner-only 权限；owner 不匹配、不可写或权限收紧失败时返回结构化 blocker。cache 初始化可以从本机已有 HWLAB clone seed 一次性拷贝，但 seed 只能用于降低首次出网成本，不能作为 release truth。cache remote 固定优先 `git@github.com:pikasTech/HWLAB.git`，GitHub 出网通过 D601 provider egress proxy `127.0.0.1:18789` 和 SSH `ProxyCommand`。cache 必须保存 full bare repo 历史，而不是 depth=1 浅缓存；wrapper 需要能解析 `refs/heads/main:deploy/deploy.json` 指向的 promotion commit，浅缓存即使 main HEAD 一致也不能证明 CD desired-state 完整。若 GitHub refresh 失败但本地 full cache 同时满足 main HEAD 和 deploy promotion commit，可作为 stale-cache 诊断继续读数，但必须暴露 `hwlab-cache-refresh` blocker，不能伪装成 release-truth PASS。
- 一次性 repo 是当前 `host.ssh` 执行用户创建的临时发布读数，避免长期 `/home/ubuntu/hwlab_cd` 被 root 或其他 runner owner 污染后成为 CD 单点故障。`--hwlab-repo` 或 `UNIDESK_HWLAB_REPO` 仍可显式指定同等干净 clone 供人工诊断；被指定的 clone 必须由执行用户拥有并可读写。root-owned 或其他用户拥有的 clone 会触发 Git dubious ownership、`FETCH_HEAD` 不可写和 `.git/worktrees` 权限 blocker。修复 owner 污染应重建或显式修正 mirror 权限，不能用 `git config --global safe.directory` 掩盖发布真相污染。wrapper 必须检查 `git status --short --branch`、origin remote、当前 branch `main`、本地 `origin/main`、`FETCH_HEAD` 和 worktree 权限；任何 dirty worktree、错误 remote、非 main、HEAD 未跟上本地 `origin/main` 或权限异常都返回结构化 blocker。`/home/ubuntu/hwlab` 是 runner 历史目录，不得作为发布真相。
- `deploy/deploy.json` 是唯一 desired-state。wrapper 只把 `deploy/artifact-catalog.dev.json`、`deploy/k8s/base/workloads.yaml` 和 `reports/dev-gate/dev-artifacts.json` 当作派生/证据读数；`status`/`preflight` 必须显示 target commit/ref、deploy.json、artifact catalog、workloads 和 live workload image 是否同源/收敛，不引入第二套 desired state。
- `status` 只读汇总 HWLAB repo path、Git clean/main/origin-main、desired-state 收敛、D601 native k3s guard 和 `Lease/hwlab-dev/hwlab-dev-cd-lock`；同时调用 HWLAB `scripts/dev-cd-apply.mjs --status --skip-live-verify` 取得 repo-owned target/promotion/deploy.json/artifact 摘要。16666/16667 live verification 不由本 runner 执行。
- `audit` 是 DEV CD 恢复后的只读健康审计，不是验收 gate 或报告生成器。它在 `status` 受控路径上补充只读 `kubectl get`/HTTP health probes，输出有界 JSON summary，分类 `control-plane-unavailable`、`docker-desktop-context-risk`、`second-control-plane-risk`、`workspace-unavailable`、`dirty-worktree`、`secret-missing`、`registry-unavailable`、`lease-held`、`lease-stale-candidate`、`artifact-missing`、`artifact-mismatch`、`runtime-job-blocked`、`rollout-unhealthy`、`public-tunnel-unhealthy` 和 `db-runtime-durability-risk`。audit 只显示 Secret 对象/key 是否存在，不显示值；只读判断 Lease 是否 stale，不释放或 break；只读拉取 16666/16667 `/health/live` 的 commit/readiness 摘要，不把它当作 M3 DEV-LIVE 验收。
- `preflight` 在 `status` 的基础上检查 apply 前 SecretRef：`hwlab-cloud-api-dev-db/database-url`、`hwlab-cloud-api-dev-db-admin/admin-url`、`hwlab-code-agent-provider/openai-api-key`。只验证 Secret 对象和 key 元数据存在性，缺失时返回 blocker、影响范围和修复 runbook；禁止读取或打印 Secret value。
- `apply --dry-run` 调用 HWLAB `scripts/dev-cd-apply.mjs --dry-run --kubeconfig /etc/rancher/k3s/k3s.yaml --skip-live-verify`，只生成受控事务准备/阻塞摘要，不做真实 apply、rollout、Lease mutation 或 live verification。历史 `scripts/dev-deploy-apply.mjs` 可作为 HWLAB 内部支持脚本出现，但 UniDesk wrapper 不能把它当成平行 CD 入口。
- 完整下游 stdout/stderr 和 kubectl 读命令输出写入 D601 `~/.state/unidesk-hwlab-cd/<run-id>/`，UniDesk 本地仅保存 provider task stdout/stderr dump；CLI stdout 只显示有界摘要和 dump path。
- wrapper 显式注入 `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` 并以这个显式目标作为唯一 gate：目标 context/server/nodes 若出现 `docker-desktop`、`desktop-control-plane` 或 `127.0.0.1:11700` 必须拒绝继续，写操作计划或 `apply --dry-run` 前目标 nodes 必须包含 `d601`。裸 `kubectl` 默认 context 只作为诊断输出；即使默认 kubeconfig 仍残留 Docker Desktop，只要显式 D601 kubeconfig 通过，也不能把默认 context 当成 CD blocker。

真实 DEV apply 只允许 host commander 在明确授权后执行。UniDesk wrapper 可以展示受控命令形状：

```sh
node scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report --kubeconfig /etc/rancher/k3s/k3s.yaml
```

本 Code Queue runner 没有 `ROLLOUT_OK` 时不得执行真实 apply、rollout、CD lock 竞争或 live health 复验。

## HWLAB 热修边界

当 HWLAB DEV runtime 的 Secret、环境变量、rollout、DNS、egress 或 provider 权限缺口阻塞业务闭环，并且 Code Queue runner 无法安全完成对应运行态操作时，UniDesk 指挥官只能承担指挥入口、授权确认、监督验收和误判边界收敛。UniDesk reference 可以记录“哪些状态不能被误判”和“哪些动作必须上收”，但不能成为 HWLAB runtime truth。

这类热修必须满足以下边界：

- 先确认用户或项目负责人已授权具体运行态修复范围；没有授权时只做只读诊断、issue 记录和修复方案准备。
- 证据只记录对象名、状态、revision、健康结果和已脱敏差异；不得把 Secret 值、token、可复用凭证命令或完整敏感 env 输出写入 issue、PR、日志或文档。
- live Secret、env、ConfigMap、Deployment patch 或 rollout 结果只能作为临时恢复证据，不能成为长期部署真相。
- HWLAB runtime truth 必须回写到 HWLAB 仓库自己的 issue、`AGENTS.md`、`docs/reference/`、部署配置或 secret 管理入口；UniDesk 只保留指挥侧边界和交叉引用。
- 热修后必须说明 durable source fix 如何进入 HWLAB 的 CLI、manifest、选中 node/lane 的配置/CI/CD/GitOps 路径，或显式 D601 legacy `deploy/deploy.json`；如果尚未完成，要保留 HWLAB issue 追踪。

## D601 Legacy Cloud Web 手动 DEV 发布路径

以下路径是 D601 legacy DEV 的历史手动发布基准，只用于迁移对照或显式 D601 回滚排障。当前 HWLAB 发布必须优先按 issue/CLI 选中的 node/lane、对应 GitOps 和 HWLAB repo-owned 规则执行；不要把这里的 D601 legacy 命令当作 D601 `v0.3` 发布入口。

1. 更新 D601 部署副本：

```sh
trans D601 'cd /home/ubuntu/workspace/hwlab && git pull --ff-only origin main'
```

2. 刷新 Cloud Web 静态构建产物。运行时 wrapper 优先读取 `web/hwlab-cloud-web/dist`，如果该目录残留旧内容，即使源码已经更新，镜像仍可能继续服务旧页面：

```sh
trans D601 'cd /home/ubuntu/workspace/hwlab && node web/hwlab-cloud-web/scripts/build.mjs'
```

3. 发布镜像到 D601 本地 registry：

```sh
trans D601 'cd /home/ubuntu/workspace/hwlab && node scripts/dev-artifact-publish.mjs --publish --services hwlab-cloud-web --report reports/dev-gate/dev-artifacts-hwlab-cloud-web-<tag>.json'
```

4. 在滚动前用一次本地容器探针确认镜像内容，不把 commit tag 等同于页面内容：

```sh
trans D601 'docker run --rm -d --name hwlab-cloud-web-probe -p 127.0.0.1:18088:8080 127.0.0.1:5000/hwlab/hwlab-cloud-web:<tag> && sleep 1 && curl -fsS http://127.0.0.1:18088/health/live && curl -fsS http://127.0.0.1:18088/ | sed -n "1,40p"; docker rm -f hwlab-cloud-web-probe'
```

5. 滚动 D601 原生 k3s：

```sh
trans D601 'KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev set image deployment/hwlab-cloud-web hwlab-cloud-web=127.0.0.1:5000/hwlab/hwlab-cloud-web:<tag> && KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev rollout status deployment/hwlab-cloud-web --timeout=180s'
```

6. 用公网入口验收：

```sh
curl -fsS http://74.48.78.17:16666/health/live
curl -fsS http://74.48.78.17:16666/ | sed -n '1,80p'
curl -fsS http://74.48.78.17:16666/styles.css | rg 'overflow: hidden|100dvh'
```

验收时必须同时看 `health/live` 的 revision、HTML 语言/标题和 CSS 外层滚动锁定。不能只看镜像 tag 或 deployment 镜像字段。

## 监督原则

- HWLAB 派单 prompt 必须自包含，并在开头引用 `DC-DCSN-P0-2026-003`，说明任务服务 M3 闭环的哪一环。
- `SOURCE`、`LOCAL`、`DRY-RUN`、fixture 或只读报告不能被当作 `DEV-LIVE`。真正的 M3 DEV-LIVE 需要证明 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` 并带有 operation、audit、evidence 链。
- 前端体验、Cloud Workbench polish、Gate 页面、诊断页和发布路径修复都是支撑任务，不等同于 M3 PASS。
- 指挥官可以手动处理 PR 冲突和最终合并判断；runner 不应承担复杂冲突合并。
- 任何临时手动上线或绕行都要回写 HWLAB issue 与 HWLAB 长期参考文档，并标明后续如何收敛到 CLI、选中 node/lane 的配置/CI/CD/GitOps 路径、显式 D601 legacy `deploy/deploy.json` 或等价发布路径。
- HWLAB Secret/env/rollout 热修按本文“HWLAB 热修边界”和 `docs/reference/devops-hygiene.md` 执行；UniDesk 侧只沉淀边界，HWLAB 侧沉淀运行真相。
