Files
pikasTech-unidesk/docs/reference/hwlab.md
T

335 lines
64 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.
# 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 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`
- 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-firstP0 阶段先在 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` 和 PK01 外置 PostgreSQL。Cloud API 只做代理和同源 Web session/API key 鉴权,不维护第二套 user、credit、usage、ledger、redeem、subscription 或 payment 状态;Cloud Web 只消费 Cloud API 暴露的正式路径,不直连 user-billing 内部端口。D601 `hwlab-v03` namespace 内不得为了 user-billing 恢复本地 PostgreSQL StatefulSet/PVC 或第二账户库;`localPostgresAbsent=true` 和 PK01 bridge ready 是关闭和复验时的必要状态证据。
复验 D601 `v0.3` user-billing 管理闭环时使用 `https://hwlab.pikapython.com`,不要用 G14 `v0.2``19666/19667` 或旧 D601 legacy 端口替代。最小 smoke 应覆盖:`/health/live` revision 指向目标 source commitadmin Web session 登录;admin 创建/list/disable redeem code;普通用户注册或登录后兑换 code;重复兑换 one-time code 不重复入账;admin redemptions 和 ledger 能查到同一 ledger/redemptionsubscription/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` 做真实入口复验。
身份、权限、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。
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) 的浏览器回归小节为权威;UniDesk 指挥侧只记录运行入口和边界。HWLAB repo 中的专项入口位于 `web/hwlab-cloud-web`,通过 `bun run e2e:workbench -- --project=chromium` 构建 Cloud Web,并由 `playwright.workbench.config.ts` 启动同源 fake server 和 Playwright Chromium。该命令必须在 issue/CLI 选中的目标 node/lane workspace 或其独立 worktree 上运行,例如 D601 `v0.3``/home/ubuntu/workspace/hwlab-v03`;不要在 master server 本地运行浏览器或仓库级前端 check。
该套件验证 Web 工作台用户可见行为:session 切换和刷新恢复、SSE/REST 事件重放、`running`/`completed`/`failed`/`canceled` 状态一致性、Trace readable rows、deep link hydration 和延迟会话列表最终状态。fake server 只重放脱敏 fixture 和最小边界变形,不得访问 live Cloud API、AgentRun、HWPOD、数据库或 Kubernetes 作为通过条件;任何未 mock 的 `/auth/*``/v1/*``/health*` 请求都应失败并暴露 path。
通过 `hwlab nodes web-probe run|script` 在线上 public origin 发现的 Workbench 用户可见 bug,修复前必须先进入上述 fake-server Playwright 套件形成独立红灯,再改源码。issue 正文应明确写出对应 fake-server 复现要求、fixture 来源、目标 viewport 或用户路径、修复后需要运行的 `bun run e2e:workbench -- --project=chromium`,以及最终回到同一 node/lane public origin 的 `web-probe` 验收命令。线上 web-probe 是 P4 原入口验收,不替代本地可重复的 Workbench 回归用例。
线上环境不易稳定触发或不应主动制造的负向分支,例如跨 project 详情读取、过期 session 权威、上游 5xx、auth rollout 瞬态和 list/window 缺项,应由 fake-server fixture 提供确定性复现和断言;live `web-probe` 关闭时证明同一 node/lane public origin 的部署版本、自然路径和健康状态即可,并在 closeout 中说明该负向分支的确定性覆盖来自 fake-server。不要为了证明 5xx、rollout 中间态或第三方瞬态而故意破坏线上服务。
移动端、窄屏、session rail、按钮可见性和 selector readiness 类问题必须在 Playwright viewport 中表达可见性断言:目标入口应可见、可点击、具有非零 layout rect,并且与用户实际操作路径一致。不要把桌面 selector(例如 session rail 的某个固定 id)假定为所有 viewport 的稳定 readiness;若移动端存在等价折叠菜单或替代按钮,fake-server 用例和线上 `web-probe script` 都应验证该等价入口。
fixture seed 优先来自目标 node/lane 的受控真实样本;采集脚本只能输出脱敏后的 workspace/conversation/session/turn/trace shape、stable pseudo ids、sourceRef/presence/fingerprint 和 `valuesPrinted=false`。不得提交或打印 `HWLAB_API_KEY`、cookie、Authorization header、DB DSN、provider token、真实用户身份或非公开 prompt。截图、Playwright trace 和 HTML report 是 issue/PR closeout 证据,默认保存在 `.state/workbench-e2e/` 或通过受控远程 artifact 回传;它们不替代 OA spec,也不替代真实 public runtime 的 `hwlab nodes web-probe` 登录/DOM/Trace smoke。
### Web Live DOM Probe 验收
`scripts/web-live-dom-probe.mjs` 是 Cloud Web 原入口的 DOM 级等价验收 helper。它必须在 issue/CLI 选中的 node/lane workspace 上运行,并打到同一 public origin;例如 D601 `v0.3` 使用目标 workspace 的脚本和 `https://hwlab.pikapython.com`,不能在 master server 本地跑浏览器 smoke,也不能用旧端口或其他 lane fallback。跨 node/lane 的日常指挥验收优先使用 UniDesk `bun scripts/cli.ts hwlab nodes web-probe run --node <node> --lane <lane>`,由该入口解析 workspace、public origin 和 Web 登录 sourceRef,再把凭据作为一次性 stdin/env 注入目标 helper。需要自定义 Playwright route/intercept、延迟 API、读取 in-flight DOM 或生成专项 artifact 时,使用 `bun scripts/cli.ts hwlab nodes web-probe script --node <node> --lane <lane> <<'JS' ... JS`;该入口由 UniDesk 先通过同源 `/auth/login` 建立 `hwlab_session`,脚本只接收已认证的 `browser/context/page/baseUrl` 和 artifact helper。只修改该 helper 时属于无服务交付,按目标 HWLAB repo `AGENTS.md` 选择直接提交或 PR,关闭证据写明 `rollout=not-applicable`
`web-probe script` 注入的 `baseUrl` 是 public origin,并且可以带尾随 `/`。自定义脚本构造 API 或页面 URL 时必须使用 `new URL(path, baseUrl).toString()`;不要用 `` `${baseUrl}${path}` `` 直接拼接以 `/` 开头的 path,否则会生成 `//health`、`//v1/...` 这类双斜杠路径,可能被 edge-proxy 当成上游绝对 URL/异常代理路径处理,造成与真实浏览器页面不同的 502 或误判。
`web-probe script` 的 `fetchJson` 依赖已认证页面所在 origin。自定义脚本必须先通过 `waitWorkbenchReady`、`gotoStable` 或等价页面导航进入目标 public origin,再调用 `fetchJson` 读取 `/v1/...`;不要在 `about:blank` 上先发 API 请求,否则 status 0 只说明浏览器上下文尚未进入同源页面。Workbench 页面存在长连接、轮询或 SSE 时,不要用 Playwright `networkidle` 作为 reload/切换通过条件;应使用 `domcontentloaded` 加明确 DOM/API 条件,例如 final URL、route conversationId、active tab、message card、trace row 或 workspace `selectedConversationId`。
Workbench 历史会话 deep link 可能属于非默认 project。打开 `/workbench/sessions/<conversationId>` 时如果默认 project 返回 `conversation_project_mismatch`、页面提示 conversation 不可见,不能立即判定原 issue 失效;应先从 workspace/conversation 摘要确认该会话 projectId,再用等价 URL `/workbench/sessions/<conversationId>?projectId=<projectId>` 做 DOM 断言。closeout 证据应写明实际 projectId、finalUrl、terminal agent card 数量和负向文本断言,避免用默认 project 的 404 掩盖真实页面状态。
Web 登录凭据必须从目标 node/lane 的受控 source 解析并作为一次性进程环境注入,例如先用 `bun scripts/cli.ts hwlab nodes secret status|ensure --node <node> --lane <lane> --name hwlab-v03-bootstrap-admin` 确认 bootstrap admin sourceRef,再运行受控 `hwlab nodes web-probe run` / `hwlab nodes web-probe script`。目标 host 没有 owner-only source 文件时,受控入口应快速返回 `web_login_secret_missing`;不要依赖脚本历史默认密码,不要把凭据复制到目标 host、shell 启动文件、issue、日志或 Git 文档。若 sourceRef/fingerprint 已确认但 public `/auth/login` 仍不接受 source 密码,应先区分 API rollout、user-billing 回退和用户表状态;只有明确需要按 YAML source 重灌 bootstrap admin hash 时,才使用受控 `secret ensure --confirm --force`。
排查 probe 登录误报时,优先看 JSON 里的 `actions`、`dom.authState`、`finalUrl`、`failureDom` 和 `dom.requiredSelectors`。新版登录页 fallback 必须先等待真实登录 surface(`#workspace`、legacy id 或 `.login-card input`)再判断 input count;提交前还要确认表单值已经落到 DOM,例如 `actions.login.valuesReady=true`。只在 `authState=login` 的瞬间立即 `count()`,或在 Vue 尚未更新 input value 时 submit,都可能把前端填表时序误判成凭据错误。关闭 Workbench 登录/DOM helper 问题时,证据至少包含原命令、目标 URL/lane、登录 `selectorMode`、`valuesReady`、`finalUrl` 和 `workspace`/`commandInput` 等关键 selector 结果。
Trace 实时性问题必须使用间隔采样,而不是只看静态截图或终态 DOM。`hwlab nodes web-probe run` 可用 `--trace-sample-count` 和 `--trace-sample-interval-ms` 采集运行中样本;自定义场景使用 `hwlab nodes web-probe script` 在同一 public origin 上读取 `.message-card[data-role="agent"]`、`.trace-timeline`、`.trace-render-row`、`data-status` 和 `.trace-empty`。采样判断要区分“加载中”和“思考中”:加载中表示页面仍在拉取已有 trace 或 trace 资源未就绪;思考中表示 trace 容器已挂载、turn 正在运行,但还没有第一条可读 Code Agent 事件。终态 message cardcompleted/failed/blocked/timeout/canceled)不得继续保留“思考中”空态;若 full trace 为空,应显示与终态一致的空 trace 文案,并且该 article 的可读 `textContent` 不应包含“思考中”。通过证据应包含连续样本里的 `agentStatus`、`tracePresent`、`traceStatus`、`rowCount`、`emptyLabel` 和最后一行预览;终态空 trace 类 issue 还应统计 terminal agent card、terminalWithThinking 和 terminal trace-empty label。
浏览器控制台中的随机文件名脚本、扩展注入脚本或浏览器实验功能警告不得直接归因到 HWLAB Cloud Web。遇到 `Permissions policy violation`、`unload is not allowed` 或类似 console 噪声时,先用 `hwlab nodes web-probe script` 在干净 Playwright 上记录 `document.scripts`、同源响应 header 和相关 console 过滤结果;只有脚本实际来自 HWLAB public origin、部署产物或响应 header 明确由 HWLAB 设置时,才把它登记为 HWLAB Web bug。Edge/Copilot、浏览器扩展或用户侧注入脚本产生的随机 bundle 名称,应作为浏览器环境噪声记录,不阻塞已通过的 Web 功能验收。
### Cloud Web Workbench Prompt 浏览器闭环
Workbench prompt、TraceTimeline、final response、详情弹窗或工具调用展示类 issue 关闭前,必须同时有浏览器 UI 证据和同一 trace 的 typed CLI 交叉验证。浏览器侧优先使用 `trans <node>:<workspace> playwright --local-dir <local-dir>` 在选中 node/lane workspace 执行,并打到同一 public origin;不要在 master server 本地跑浏览器,也不要用其他 lane 的旧端口代替。heredoc 内应显式等待 `/auth/login`、`#workspace`、`#code-agent-provider-profile`、session 选择、`/v1/agent/chat` 和目标 trace selector,而不是只靠页面标题或宽泛 input count 判断成功。截图、PDF 或 summary artifact 必须通过 `--local-dir` 或 `trans <node> download` 回传,并在 closeout 中记录本地路径、bytes 和 SHA-256 verification。
一次完整的 Workbench prompt UI 证据应覆盖:Web session 登录成功;模型通道选择符合目标 provider profile;显式创建或选择 sessionprompt 被 `/v1/agent/chat` 接受并得到 `traceId/sessionId/conversationId/threadId`;页面可见用户消息、Agent message、final response;若 TraceTimeline 初始是 compact/result 压缩态,应在 Web 上触发 `回放 Trace` 后展开 timeline,让页面本身可见 `commandExecution` 等工具行。随后在同一 node/lane public origin 上,用 `hwlab-cli client agent result <traceId>`、`trace <traceId>` 和必要的 `inspect <traceId>` 交叉确认 terminal status、toolCalls、finalResponse、AgentRun run/command/runner ID 和脱敏状态。
对于失败终态的 final response UI 验收,浏览器证据必须读取 final response 正文或 `.message-text` 中的用户可见错误,并与同一 trace 的 `client agent result` / turn endpoint 的 `finalResponse.text` 对齐。若 API 已返回 `error.message` 但没有 `finalResponse.text`,问题在 HWLAB API/adapter 结果映射;若 API 已返回 `finalResponse.text` 但页面仍显示空 final、通用 fallback 或只在 trace row 中展示错误,问题在 Cloud Web 恢复/terminal 文本选择。两类问题都不能用 trace timeline 展示正常来关闭。
详情弹窗和恢复会话类验收还应覆盖“从持久化 conversation 恢复”的路径,而不是只在刚完成 turn 的内存态截图。若用户报告的原始 conversation 对当前验收 actor 不可见,但同一 trace 的 `result` 可读,可以创建当前 actor 可见的临时 conversation,消息中挂载同一个真实 `traceId` 和最小 terminal agent message,再在 Web 中选择该临时会话、打开运行详情并等待 result 诊断自动补齐;验收后删除临时 conversation。closeout 必须写明这是同 trace 的恢复路径验证,不能声称修改或读取了原始用户 conversation。
Completed turn、Trace 重放或 session deep link 类 issue 关闭前,必须用新的浏览器上下文或等价 fresh login 直接打开 `/workbench/sessions/<conversationId>?projectId=<projectId>`。同一 SPA 页面内发送后再 `reload` 只能证明当前内存态和同页缓存没有立即丢失,不能替代 fresh deep link 复测;fresh deep link 必须重新通过 conversation detail、turn/trace replay 或等价事件重放恢复用户消息、terminal agent message、Trace rows、active tab 和 `running=false` 终态。若同页 reload 正常但 fresh deep link 下 `/v1/agent/conversations/<conversationId>` 或 `/v1/agent/turns/<traceId>` 返回 404,且 DOM `messageCount=0` / `traceRowCount=0`,该 issue 仍未通过,必须保持打开或重开。
Session 切换、session rail 或 Workbench 恢复路径类问题必须同时验证点击态和持久化恢复态。浏览器证据应在同一 public origin 中选择一个非当前 session,等待足够覆盖 `hydrate`、`select-conversation`、active trace repair 等异步返回的空闲窗口,确认 active tab 没有回退;随后读取 `/v1/workbench/workspace?projectId=<projectId>` 确认后端 `selectedConversationId` 已改变并持久化;最后刷新页面并再次等待 session tabs,确认同一个 session 仍是 active。若当前 selected conversation 没有出现在 `/v1/agent/conversations` 当前列表窗口中,前端必须把 workspace 当前选中 conversation 合入 session rail;刷新后没有 active tab、状态显示“等待 workspace”,或只靠内存态显示成功,均不能作为通过证据。session rail 的刷新列表只是候选窗口,不是 selected session 的完整真相;list API 临时缺当前 conversation 时,不得清空当前 tab、取消 active 状态或让标签在刷新/深链恢复中闪烁消失。自定义 Playwright 验收不要只按 tab index 或重复标题判断,应锁定唯一 title、conversationId 或后端 selected id,并记录 `select-conversation` response;与 session 切换无关的 health/RPC 噪声应拆成独立 issue,不阻塞已经通过的切换闭环。
线上 session rail 当前列表窗口可能只有空会话,或包含已经过期的 stale conversation。选择非空、running 或 terminal 会话作为验收候选时,应先通过 `/v1/agent/conversations?projectId=<projectId>&limit=<N>` 扩大候选范围,再对候选逐个读取 `/v1/agent/conversations/<conversationId>?projectId=<projectId>`;只有 detail 200 且消息/trace shape 满足目标场景的会话才可作为正向切换、reload 或 terminal replay 证据。detail 404 的候选本身是 stale/list-window 负向信号,应用于验证隔离路径,而不能继续当作正向 reload 样本。
Code Agent turn 运行状态的权威入口是 `/v1/agent/turns/:traceId``traceId` 是单一查询键;`hwlab-cli client agent result <traceId>`、Web composer、cancel 按钮、session 标签动效和最终消息状态都应消费同一 turn snapshot 的 `running`、`terminal`、`status`、`finalResponse`、`error` 和 AgentRun provenance。`/v1/agent/trace*`、conversation list、workspace summary、message status、runnerTrace rows 和 currentRequest 只能作为详情、列表或上下文来源,不能再反向推断 turn 是否运行中、是否完成或是否失败,也不能作为 fallback 与 turn endpoint 竞争覆盖 UI 状态。CLI 等待 terminal 时也应优先使用 submit 返回的 `turnUrl` 或 `/v1/agent/turns/:traceId`,只有详情展示才读取 trace rows。
Code Agent 会话恢复的状态权威必须以最新 message 和同 turn trace 为准。conversation 顶层 `status=idle` 只能表示当前没有进行中的 turn,不能覆盖 message 自身的 `running` / `completed` / `failed`,也不能把 agent message 降级成 `source`conversation 顶层 `lastTraceId` 若与最新 user/agent message trace 脱节,后端 summary 应按最新同 turn user/agent trace 修正,前端 hydrate/select/retry 后也应从最新 active message reattach trace。关闭刷新、deep link 或切换 session 后丢消息/卡住类 issue 时,验收必须同时看 DOM 最后一条 agent 的 `data-status`、conversation API 顶层 `lastTraceId`、最后 user/agent message 的 `traceId`、`runnerTrace.status` 和 `/v1/agent/turns/:traceId` 的 `running` / `terminal`,不能只看 session rail 文案或 trace 面板是否出现占位文本。
Workbench session URL 是恢复路径的一部分。每个可见或当前选中的 session 都应能映射到 `/workbench/sessions/<conversationId>``/workspace/sessions/<conversationId>` 仅作为兼容 alias;从 `/workbench` 进入、创建 session 或点击 session rail 后,地址栏应反映当前 active `conversationId`,复制 session 信息时也应包含可直接打开的 session URL。直接打开 deep link 时,Cloud Web 静态层必须返回 SPA `index.html` 而不是 404;登录 redirect 必须保留原 path;登录后或 hydrate 后应通过 `/v1/agent/conversations/<conversationId>` 与 workspace select 路径把后端 `selectedConversationId` 收敛到 URL 中的 id。关闭 session URL/恢复类 issue 时,浏览器证据至少包含最终 URL、workspace API 的 `selectedConversationId`、active tab 判断,以及一次无 cookie direct GET 或等价探针确认 deep link 是 `200 text/html`。
Cloud Web 登录页的中文错误可能会把 API upstream 502、rollout 中间态或真实 401 都表现成登录失败。遇到登录失败先看 `web-probe script` 的 `probe.auth.retryCount`、`transientObserved`、`retryable`、`fallbackUsed`、`fingerprint` 和 `commanderAction`,再用目标 public origin probe `/health/live`、`/auth/login` 状态和选中 namespace 的 API/Web/edge-proxy rollout;只有 API 已 ready 且 `/auth/login` 明确返回 401 时,才把它归类为凭据或用户状态问题。rollout 瞬态恢复后重跑同一短生命周期 Playwright 验收即可,不要把 transient `upstream_unavailable` 写成长期功能缺陷。
## 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 stateG14 侧 `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 DNSNode 实现访问 `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` readyD601 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-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 能力缺失时改 AgentRunHWLAB 拥有的鉴权、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` 只保留历史交叉引用 stubUniDesk 指挥侧按 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 Agentsubject 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 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` 能力进入 D601frontend 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 dumpCLI 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 侧沉淀运行真相。