From c569503fc5f9a71ba091926899eab5cc246c2f5a Mon Sep 17 00:00:00 2001 From: lyon Date: Mon, 15 Jun 2026 16:02:37 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=94=B6=E7=BC=96=20reference=20?= =?UTF-8?q?=E5=88=B0=20UniDesk=20OA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/reference/MVP-e2e-acceptance.md | 159 +------ docs/reference/architecture.md | 100 +---- docs/reference/cloud-workbench.md | 299 +------------ docs/reference/code-agent-chat-readiness.md | 328 +------------- docs/reference/dev-runtime-boundary.md | 461 +------------------- docs/reference/gateway-outbound-demo.md | 94 +--- docs/reference/node-gitops-cicd.md | 257 +---------- 7 files changed, 61 insertions(+), 1637 deletions(-) diff --git a/docs/reference/MVP-e2e-acceptance.md b/docs/reference/MVP-e2e-acceptance.md index c60868f1..63115147 100644 --- a/docs/reference/MVP-e2e-acceptance.md +++ b/docs/reference/MVP-e2e-acceptance.md @@ -1,155 +1,12 @@ -# HWLAB MVP E2E 验收测试与报告 issue 规则 +# HWLAB MVP E2E 验收(历史路径) -> **门禁最小化见 AGENTS.md P0**: Critical Guard Minimalism Rule、Critical Latest-Requirement Test Rule。以下用例为当前 MVP 验收清单(一次性验证参考,非长期保留门禁)。旧用例阻碍最新交付时删除,新增用例只覆盖明确高价值风险。 +本文不再承载长期测试规格或需求正文。 -本文定义 HWLAB MVP 的用户可读、Agent 可执行验收测试规格。它按 `cli-spec` 的 `TEST.md` 风格组织用例,但报告产物不写入 `docs/` 或 `repository report directory `;每轮验收必须创建一个带编号的 GitHub 测试报告 issue。 +统一规格和过程控制出处是 UniDesk OA: -## 适用范围 +- [PJ2026-01 HWLAB 总规格](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-01-HWLAB.md) +- [PJ2026-0103 HarnessRL](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0103-harness-rl.md) +- [PJ2026-010402 HWLAB CLI](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010402-hwlab-cli.md) +- [内测一期测试大纲 issue](https://github.com/pikasTech/HWLAB/issues/1231) -- 当前浏览器、API、edge 和 live health 入口必须从 issue/CLI 明确的 node + lane control-plane status 读取;没有明确目标时才从受控 lane 配置解析,禁止把 G14 DEV、v0.2 或 D601 legacy 端口写成全局默认。 -- D601 v0.3 这类 node-scoped runtime lane 是正式验收目标,不属于 D601 legacy。 -- 当前 MVP 上位约束是 `DC-DCSN-P0-2026-003` / [pikasTech/HWLAB#78](https://github.com/pikasTech/HWLAB/issues/78):M3 虚拟硬件可信闭环必须证明 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1`。 -- 当前默认前端方向以 [pikasTech/HWLAB#99](https://github.com/pikasTech/HWLAB/issues/99) 为准:`/` 必须是类 VS Code 的 Cloud Workbench,不是 Gate、status 或 diagnostics 首页。 - -## 报告 issue 规则 - -测试报告产物必须落到 GitHub issue,不进入长期文档目录,也不提交一次性报告文件。 - -- 报告 issue 标题格式:`[MVP-E2E-RPT-] HWLAB MVP E2E 验收测试报告:<简短范围>`。 -- `` 从 `001` 开始递增;创建前先搜索 open 和 closed issue 中已有的 `MVP-E2E-RPT-` 编号,选择下一个编号。 -- 报告 issue 必须包含:测试日期、测试人或 runner、源文档路径、本次目标、DEV URL、observed commit/revision/tag/digest、每个 `T{x}` 用例的状态、blocker class、关键截图或截图附件、operation/trace/audit/evidence id、最终结论和后续 issue。 -- 如果 Playwright 截图无法直接上传到 issue,报告 issue 必须记录截图文件路径、文件名、SHA 或可审查的 artifact URL;不能只写“已截图”。 -- 任一用例为 `failed` 或 `blocked` 时,总结论只能是 failed/blocked,不得写 pass。 - -推荐报告 issue body 结构: - -```markdown -## 测试范围 - -- 源文档:docs/reference/MVP-e2e-acceptance.md -- 报告编号:MVP-E2E-RPT- -- Target Cloud Web: -- Target API/edge: -- observed frontend revision: -- observed API revision: -- runner / tester: - -## 结果总览 - -| 用例 | 状态 | 证据等级 | blocker class | 截图/证据 | -| --- | --- | --- | --- | --- | -| T1 | pass/failed/blocked | DEV-LIVE/SOURCE/DRY-RUN/BLOCKED | | | - -## 详细记录 - -## T1 - -- 操作: -- 观察: -- 截图: -- 关键 ID: -- 结论: - -## 安全边界 - -- 未触碰 PROD: -- 未读取 secret 明文: -- 未重启 UniDesk / Code Queue / backend-core: -- 未把 UniDesk runtime 当 HWLAB runtime: -``` - -## 证据等级 - -- `DEV-LIVE`:真实目标 node/lane 上的浏览器、API、runtime 或短生命周期授权操作证据。 -- `SOURCE`:源代码、静态检查、合同校验或未部署构建证据。 -- `LOCAL`:本地浏览器、fixture 或本地服务证据。 -- `DRY-RUN`:显式 dry-run 输出,不触碰 DEV runtime。 -- `BLOCKED`:因为环境、权限、运行态、agent、DB、evidence 或安全边界无法继续。 - -禁止把 `SOURCE`、`LOCAL`、`DRY-RUN`、fixture、edge-only health、前端静态状态或 UniDesk runtime 代理写成 M3 或 MVP `DEV-LIVE` 通过。 - -## 验收用例 - -## T1 DEV 入口与运行边界 - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:打开当前目标 Cloud Web URL,确认默认页是 HWLAB Cloud Workbench,不是 Gate、status、help 或 diagnostics;访问当前目标 API health 和 live health,确认返回 HWLAB API/edge identity。报告必须写明实际 node、lane、Web URL、API URL,且 legacy public `:16666/:16667`、public `:6666/:6667`、G14/v0.2 旧入口或其他 lane 未作为当前验收入口,UniDesk backend、provider-gateway 和 microservice proxy 未作为 HWLAB runtime 替代。 - -通过标准: - -- 目标 Web 根页可由浏览器打开,页面标题、主导航或首屏内容明确指向 HWLAB 云工作台。 -- 目标 health 或 live health 返回 JSON,包含 HWLAB service identity 和当前 node/lane environment。 -- 报告 issue 附桌面首屏截图和 API/health 摘要。 - -## T2 Cloud Workbench 首屏、布局与中文 UX - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:分别在桌面视口和 `390x844` 移动视口截图,确认左侧资源/功能导航、中间 Agent 对话/trace/输入区、右侧硬件状态和控制/接线/可信记录区域可见;外层页面不滚动,滚动只发生在内部面板;用户可见文案中文优先;使用说明是内部入口且由 Markdown 渲染,不是默认首页。 - -通过标准: - -- 默认页显示工作台,不显示 Gate/M0-M5/验收报告作为首屏主体。 -- 桌面和移动视口下 `html/body` 或等价应用根节点没有页面级滚动路径。 -- 关键中文标签可见,必要机器标识可以保留原文。 -- 报告 issue 附桌面、移动和使用说明内部页截图。 - -## T3 M3 虚拟硬件可信闭环 - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:在明确授权的 DEV live 窗口内,通过工作台或等价受控入口执行 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1` 的 true/false 循环。报告必须记录两个 distinct box-simu、两个 distinct gateway-simu、一个 patch-panel、patch-panel-owned wiring、operationId、traceId、auditId 和 evidenceId。 - -通过标准: - -- 写 `DO1=true` 后,`DI1=true` 经 `hwlab-patch-panel` 同步可见;写 `DO1=false` 后,`DI1=false` 同步可见。 -- 证据链明确归因到 `hwlab-patch-panel`,没有 box loopback、前端直改状态或 UniDesk runtime 替代。 -- operation、trace、audit 和 evidence id 能互相指向同一轮操作。 -- 未获授权、目标缺失、持久化 blocked 或任一关键 ID 缺失时,必须标为 `BLOCKED`,不得 claim M3 PASS。 - -## T4 Code Agent 真实 runner 能力 - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:在目标 Web 工作台 Agent 区输入 `pwd` 和“列出你可用的 skills”,确认返回来自真实 Codex runner、workspace、tool calls 和 skills 注入,而不是 `openai-responses` text-chat-only。随后让 Agent 通过目标 lane 的 `hwlab-cloud-api` 执行同一 M3 硬件任务,确认 agent trace 引用对应 hardware operation 和 audit。 - -通过标准: - -- `pwd` 返回真实 runner 工作目录或结构化 runner blocker。 -- skills 查询返回真实 skill 列表、skill 发现输出或结构化 skills blocker。 -- runner trace 中能看到工具调用、workspace 证据和 hardware operation/audit 关联。 -- 如果只能文本聊天、provider unavailable、无工具调用或无 workspace 证据,必须标为 `BLOCKED/agent-runtime` 或 `BLOCKED/credential`。 - -## T5 Audit、Evidence 与持久化 - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:确认直接 M3 操作和 Agent M3 操作都能在工作台、API 或 CLI 输出中看到 hardware audit、agent trace 和 evidence record。最小 evidence record 至少包含 `sessionId`、worker image 或 digest、`skillsCommitId`、`skillsTreeSha` 或文件清单 hash、`workspaceMode`、`agentTraceId`、`operationId`、`auditId`、`result` 和 `createdAt`。 - -通过标准: - -- hardware audit 由 HWLAB cloud/gateway/patch-panel 硬件链路生成,agent 自述不能替代 audit。 -- evidence 中不包含 secret/token 明文。 -- durable DB 或 evidence adapter 仍 blocked 时,报告必须标注准确 blocker,不得写 trusted green。 - -## T6 报告 issue 创建与编号 - -阅读 `AGENTS.md`,然后用浏览器或 Playwright 手动测试以下内容:按本文“报告 issue 规则”创建一个带递增编号的测试报告 issue,标题使用 `[MVP-E2E-RPT-]` 前缀。报告 issue 必须挂载本次所有截图、关键 JSON 摘要、测试结论和后续 issue 链接;不得把测试报告正文写入 `docs/reference/`,不得提交一次性报告文件来替代 issue。 - -通过标准: - -- 报告 issue 存在,编号未与历史报告冲突。 -- 每个 `T{x}` 都有状态、证据等级和简短证据。 -- 最终结论与各用例状态一致。 -- 安全边界明确写出:未触碰 PROD、未读取 secret 明文、未重启 UniDesk / Code Queue / backend-core、未用 UniDesk runtime 替代 HWLAB runtime。 - -## 停止条件 - -出现以下情况时停止后续 live 或 mutating 测试,并在报告 issue 中标为 `BLOCKED` 或 `failed`: - -- 入口不是当前 issue/CLI 明确 node + lane 的 Web/API,或命中非当前 HWLAB runtime。 -- 需要读取或打印 Secret/token 明文。 -- 需要触碰 PROD。 -- 需要重启 UniDesk、Code Queue、backend-core 或无关基础设施。 -- M3 目标不能证明两个 distinct box-simu、两个 distinct gateway-simu 和 patch-panel-owned wiring。 -- agent 只能文本聊天,不能证明真实 runner/workspace/tool/skills。 -- 任一结果要求把 SOURCE、LOCAL、DRY-RUN、fixture 或 edge-only 证据升级为 DEV-LIVE。 - -## 稳定来源 - -- [architecture.md](architecture.md):MVP 边界、M3 trusted loop 和证据等级。 -- [dev-runtime-boundary.md](dev-runtime-boundary.md):node/lane Web/API、k3s 和运行态边界;D601 legacy 只指旧 DEV/CD 回溯,D601 v0.3 属于正式 node-scoped lane。 -- [cloud-workbench.md](cloud-workbench.md):Cloud Workbench 默认首页和 UX 约束。 -- [code-agent-chat-readiness.md](code-agent-chat-readiness.md):Code Agent 真实回复和 provider/runner blocker 判定。 -- [m3-loop-rollout-runbook.md](m3-loop-rollout-runbook.md):M3 live 操作授权、证据和失败分类。 +历史 T1-T6 和报告模板只作为迁移前参考。新的阶段测试大纲写入专项 issue,测试失败按主责 L1/L2 分流,不把一次性报告正文写回本仓 reference。 diff --git a/docs/reference/architecture.md b/docs/reference/architecture.md index 844d4fca..703d746b 100644 --- a/docs/reference/architecture.md +++ b/docs/reference/architecture.md @@ -1,95 +1,13 @@ -# HWLAB Architecture Reference +# HWLAB Architecture Reference(历史路径) -HWLAB is the hardware lab runtime and control plane for DEV-first MVP work. -The current P0 direction is fixed by `DC-DCSN-P0-2026-003` and -[pikasTech/HWLAB#78](https://github.com/pikasTech/HWLAB/issues/78): prove the -M3 virtual hardware trusted loop before broadening the product surface. +本文不再承载 HWLAB 架构、MVP boundary、trusted loop 或 evidence label 需求规格正文。 -## MVP Boundary +统一规格出处是 UniDesk OA: -- Environment: MVP runtime work must use the node/lane explicitly selected by the issue, PR, CLI parameters, or controlled lane config. G14 DEV/PROD and D601 v0.3 are lane examples, not global defaults. -- Current Cloud Web entry: read from the selected node/lane control-plane status. -- Current API/edge entry: read from the selected node/lane control-plane status. -- PROD entries exist only when the selected lane is a PROD lane and must be verified through its own GitOps/public health path. -- Legacy public `:16666/:16667`, `:6666`, and `:6667` are historical or internal-port surfaces and must not be used as current browser or API acceptance targets. D601 node-scoped lanes such as D601 v0.3 are not legacy. -- UniDesk may support scheduling, CI, or CD. It is not a HWLAB runtime - substitute. -- M3 mutating proof remains DEV-first; PROD presence is verified through GitOps, Argo sync, Deployment readiness and public health, not through hardware mutation. +- [PJ2026-01 HWLAB 总规格](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-01-HWLAB.md) +- [PJ2026-0101 硬件池](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0101-hardware-pool.md) +- [PJ2026-0102 Agent编排](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0102-agent-orchestration.md) +- [PJ2026-0103 HarnessRL](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0103-harness-rl.md) +- [PJ2026-0104 客户端](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0104-client.md) -## Runtime Shape - -Current service ownership and v0.2 keep/remove decisions are authoritative in -[spec-v02-services.md](spec-v02-services.md). The selected node/lane runtime path is: - -```text -browser or CLI --> master edge / frp public ports --> selected node/lane namespace --> HWLAB cloud/runtime services --> gateway, simulators, patch panel, agent services -``` - -For M3 hardware proof, the required runtime participants are: - -- two distinct `hwlab-box-simu` identities; -- two distinct `hwlab-gateway-simu` identities; -- one `hwlab-patch-panel` that owns the route decision. - -真实设备目标以 `hwpod` 作为硬件研发执行逻辑实体。`hwpod` -统一封装 target device、workspace、debug probe 和 io probe 四要素; -快速阶段由 workspace-local `hwpod-spec`、`hwpod-cli`、`hwpod-ctl`、 -`hwpod-compiler-cli`、cloud-api `/v1/hwpod-node-ops` 和 host/edge -`hwpod-node` 打通闭环,规格见 [spec-hwpod-harness.md](spec-hwpod-harness.md)。 - -`v0.2` 用户和权限管理规格只保留 `admin` 和 `user` 两类基础角色:code agent -session 归属于创建用户,HWPOD 和其他工具能力由 Cloud API 通过 OpenFGA 按用户和工具授权; -Kubernetes 只做运行时隔离和资源兜底,不承载最终用户权限。权威口径见 -[spec-user-access.md](spec-user-access.md) 和 [spec-v02-openfga-authorization.md](spec-v02-openfga-authorization.md)。 - -## M3 Trusted Loop - -M3 DEV-LIVE requires this specific path: - -```text -res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1 -``` - -The pass evidence must include operation, trace, audit, and evidence -identifiers tied to the same loop. Direct box loopback, front-end state edits, -UniDesk substitution, fixture output, and local-only smoke output are not M3 -DEV-LIVE. - -The detailed step order and failure classes are authoritative in -[m3-loop-rollout-runbook.md](m3-loop-rollout-runbook.md). - -## Evidence Labels - -Use the labels below consistently in docs, reports, CLI output, and Cloud Web: - -| Label | Meaning | -| --- | --- | -| `SOURCE` | Repository source, contracts, manifests, fixtures, or checked-in reports. | -| `LOCAL` | Localhost or in-process smoke result. | -| `DRY-RUN` | No-mutation plan or fixture-backed preview. | -| `DEV-LIVE` | Observation from the real DEV route for the exact component or loop claimed. | -| `BLOCKED` | Missing, stale, unsafe, or not-yet-authorized evidence/action. | - -Only `DEV-LIVE` can support live runtime claims, and only the full M3 loop can -support M3 PASS. Edge health, Cloud Workbench polish, artifact reports, and -desired-state plans are support signals until joined with the required loop -evidence. - -Code Agent chat 证据单独分级:只有真实同源 `/v1/agent/chat` -`completed` 响应可以证明 chat reply readiness;provider credential gap -必须保持 `BLOCKED`。它不能升级为 M3、M4、M5 或硬件闭环验收,判定细则见 -[code-agent-chat-readiness.md](code-agent-chat-readiness.md)。 - -## Stable Sources - -- [pikasTech/HWLAB#7](https://github.com/pikasTech/HWLAB/issues/7): current - board and priority status. -- [pikasTech/HWLAB#78](https://github.com/pikasTech/HWLAB/issues/78): M3 - decision and prompt/review guardrails. -- [dev-runtime-boundary.md](dev-runtime-boundary.md): node/lane runtime boundary and known lane examples. -- [spec-v02-services.md](spec-v02-services.md): v0.2 microservice keep/remove and dependency boundary. -- [spec-v02-documentation-governance.md](spec-v02-documentation-governance.md): root README and legacy process document migration. +本文件只保留为历史链接兼容 stub。系统边界、M3/CaseRun/HWPOD/AgentRun 关系和 evidence 口径只更新 UniDesk OA 规格或对应测试 issue。 diff --git a/docs/reference/cloud-workbench.md b/docs/reference/cloud-workbench.md index 345504ce..f20e3b04 100644 --- a/docs/reference/cloud-workbench.md +++ b/docs/reference/cloud-workbench.md @@ -1,295 +1,12 @@ -# HWLAB Cloud Workbench Reference +# HWLAB Cloud Workbench Reference(历史路径) -Cloud Workbench is the default user-facing frontend for the current target -node/lane Web entry, resolved from issue/CLI control-plane status. It must serve the #99 workbench direction and the -#108 UX constraints while respecting the M3 boundary from -`DC-DCSN-P0-2026-003`. +本文不再承载 Cloud Workbench 需求规格正文。 -## Default Route +统一规格出处是 UniDesk OA: -- `/` must show the Cloud Workbench, not Gate, status, help, or diagnostics. -- The default first screen must not show Gate, `BLOCKED`, `M0-M5`, or - acceptance-review copy. Those terms may remain in hidden/internal views. -- Checked-in Gate reports and aggregator summaries are read-only support data. - They must not be rendered as the default homepage or used to rename the - default route away from Cloud Workbench. -- Gate and diagnostics are secondary routes or right-panel support views. -- `/gate` and `/diagnostics/gate` are internal diagnostic aliases served by the - same Cloud Web app router. They may carry Gate, blocker, and M0-M5 evidence - because they are not the default homepage. -- The API/edge boundary is the current target node/lane API URL; it must be read from control-plane status or controlled lane config, not from a hardcoded G14/v0.2 default. -- Browser data sources are same-origin `/v1`, read-only `/json-rpc`, source - reports, gate reports, and blocked reports. -- Code Agent conversation 使用受控同源 `POST /v1/agent/chat` 通道。直接 - API/edge 访问、source reports、本地 echo、mock replies 或 provider - credential gaps 不能被写成真实 assistant reply;readiness 权威文档是 - [code-agent-chat-readiness.md](code-agent-chat-readiness.md). -- Cloud Web 的 Code Agent 非视觉业务路径必须能被 `hwlab-cli client agent` - 复现。Web 发现 AgentRun、session continuation、trace/result 或 provider - 问题时,先用 CLI 通过同一 Cloud Web base URL、同一 `/v1/agent/chat`、同一 - 显式 `conversationId/sessionId/threadId/retryOf` 复现,再进入前端状态机或样式修复。 - Code Agent session 管理必须手动化:无 session 时先显式创建 session,session failed/stale - 时保留失败证据并要求显式新建或选择 session;不能用只覆盖首轮自动新会话的 CLI 验收 - 替代 Web continuation 验收。 +- [PJ2026-0104 客户端](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0104-client.md) +- [PJ2026-010401 Web工作台](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md) +- [PJ2026-010402 HWLAB CLI](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010402-hwlab-cli.md) +- [PJ2026-010403 API契约](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md) -## Required Layout - -The default workbench follows the #99 VS Code-style structure: - -| Region | Required role | -| --- | --- | -| Left | Activity rail, project/function/resource navigation, hardware resources. | -| Center top | Agent messages, execution process, trace, selected operation context. | -| Center bottom | Agent input or equivalent command composer. | -| Right top | BOX-SIMU, Gateway-SIMU, and patch-panel hardware state. | -| Right bottom | Controls, wiring, trusted records, Audit, and Diagnostics tabs. | - -Unavailable or future controls must be disabled with blocker context. The -frontend must not imply generic direct hardware control. - -The center-bottom command composer is the primary user action surface. Topbar -runtime summaries, live-build indicators, dialogs, and status chips may report -context, but they must never cover or intercept clicks intended for the command -composer, Code Agent input, send controls, or quick-prompt buttons. If a fixed -or visually persistent status surface can overlap after `scrollIntoView`, mobile -reflow, or trace updates, the command composer must keep quick prompts inside -its own flow below the primary input controls, and non-interactive summary text -must not become a pointer target. Layout/browser smoke should treat this as a -real hit-target failure, not as a test flake. - -The left resource explorer is a controlled resizable column on desktop-class -viewports. Its width defaults to `292px`, clamps inside a bounded range -(`220px` to `420px` before viewport-specific clamping), and is changed through -the `#explorer-resize` separator. The separator has a Chinese accessible name, -supports pointer drag plus Arrow/Page/Home/End keyboard adjustment, and stores -only the clamped width in versioned `localStorage` key -`hwlab.workbench.layout.v1`. Collapsing the resource tree hides the column but -keeps the saved width so expanding restores it. At `<=860px`, the resize handle -is removed from the focus/hit-target flow and the mobile drawer/collapse flow -owns the layout. - -The `panel-wiring` / `hwlab-patch-panel` view must use a two-column long table -instead of an eight-column wide table. The first table row/header names the two -connected devices, for example `res_boxsimu_1` and `res_boxsimu_2`; following -rows map IO ports, for example `DO1` to `DI1`. The patch-panel service, -status, evidence source, and trace/evidence details remain visible in Chinese -summary or row detail text, but they must not become separate horizontal -columns that force the right sidebar to scroll sideways. - -## UX Constraints - -The #108 constraints are current baseline: - -- no page-level vertical scroll on the outer shell; scrolling belongs inside - workbench panels; -- user-visible UI text is Chinese except machine identifiers, protocol names, - API paths, IDs, commits, endpoints, and source labels that need their exact - spelling; -- an internal help page exists, but it is not the homepage; -- help content is maintained as `web/hwlab-cloud-web/help.md` and rendered by - the frontend instead of being only a JS string. - -## Evidence And Labels - -Visible runtime or evidence state must keep `SOURCE`, `LOCAL`, `DRY-RUN`, -`DEV-LIVE`, and `BLOCKED` distinct. Loading the current target Web URL proves only -that Cloud Web is reachable. It does not prove DB readiness, M3, M4, M5, or a -hardware loop. - -The frontend may show read-only DEV observations when they are tied to the -exact route or component. It must not upgrade source fixtures, dry-run output, -front-end state, or edge-only health into M3 DEV-LIVE. - -The default workbench runtime label must not expose raw `degraded` as the -user-facing conclusion. `live-status` maps current probes into four Chinese -states: - -| State | Visible label | Required attribution | -| --- | --- | --- | -| Pass | `API 正常` | The exact service and API that proved readiness, normally `hwlab-cloud-api /health/live`. | -| Error | `API 错误` | Concrete service/API/reason, for example `hwlab-cloud-api /v1/agent/chat provider_http_504` or `hwlab-patch-panel /v1/m3/io m3_wiring_missing`. | -| Unverified | `等待验证` | The service/API still waiting for observation; it must not be treated as pass. | -| Read-only | `只读模式` | Explicit permission, fallback, DB persistence, or runtime durable reason, for example `runtime_durable_adapter_schema_blocked`, `runtime_durable_false`, or `fallback_text_chat_only`. | - -Raw `degraded` may be retained in internal details, reports, and `/gate`, but -the main workbench status must translate it into one of these actionable -states. Real `/v1/agent/chat` failures, provider timeouts, text-chat-only -fallback, runner blockers, and M3 `cloud-api -> gateway-simu -> box-simu -> -hwlab-patch-panel` failures must name the responsible microservice/API and the -error category. When the response carries trace, operation, audit, evidence, or -session identifiers, the visible detail must include a short redacted -`trace=`/`evidence=` style summary. - -如果 `/v1/agent/chat` 返回 `provider_unavailable` 或报告缺少 -`OPENAI_API_KEY`,可见状态必须保持 `BLOCKED/credential`。在同源 DEV 请求按 -[Code Agent readiness](code-agent-chat-readiness.md) 合同返回 completed -且非空的 assistant response 前,Workbench 不得暗示已有真实 assistant reply。 - -Code Agent trace 在消息卡片内使用独立滚动容器展示。SSE、轮询或“回放 trace” -更新只能刷新内容,不得重置用户已展开/折叠状态,也不得把 `#conversation-list` -或 `.message-trace-events` 的滚动位置跳回顶部;渲染前后必须保存并恢复外层 -conversation list 和按 `messageId/traceId` 记录的 trace list -`scrollTop/scrollLeft`。`#conversation-list` 需要绑定 scroll listener 持续记录用户 -位置,并在 DOM 替换后立即恢复一次、下一帧再恢复一次,避免布局重算或 scroll -anchoring 把列表拉回顶部。 - -Trace 展示遵循 UniDesk commander loop 的低噪声完整可读事件线原则:原始 trace -JSON 仍是复制/下载和追责的完整来源;页面内默认展示每个有意义的 agent message、 -command/tool completed、stderr/error、turn/status 和 gateway JSON-RPC 结果。token -delta、assistant chunk、command output chunk、reasoning delta 等噪声可以聚合或隐藏, -但聚合不得吞掉中间的可读 message/tool call。命令和工具行必须至少保留状态、exit -code、耗时、输出体量、关键 operation/evidence id 和可读摘要。 - -Workbench 面向用户的 trace 视图不得展示“压缩窗口”作为可读事件列表,也不得把 -result polling 返回的 head-tail 窗口或少量摘要冒充完整 trace。只要发现 -`eventsCompacted=true`,前端必须自动请求 `/v1/agent/chat/trace/` 回放完整 -trace;回放期间只能显示“完整 trace 回放中/当前已载入”状态,回放完成后才显示 -“显示全部可读事件”。如果完整 trace 已过期或后端缺失,必须显式展示缺失状态。 -assistant chunk、token delta、command output chunk 可以在同一 message/tool output 内 -合并成一条高可读行,但不能隐藏任意 assistant message、tool call、tool completed、 -stderr/error 或 turn/status 边界。 - -Code Agent 工作台状态必须跨浏览器刷新持久化。前端至少保存 -`conversationId/sessionId/threadId/sessionStatus`、最近消息、traceId 和必要的 runtime -摘要,刷新或重新打开页面后继续使用同一 HWLAB session/thread 和 AgentRun `SessionRef`/PVC -workspace;除非运行面无法恢复或用户显式清空对话或登出,不得把下一轮 -请求降级成“首轮新会话”。登录态采用 server cookie 与本地 session 双轨:server session -可用时优先使用;server 内存 session 因 Pod/replica 切换丢失时,只要本地 session 未过期, -刷新页面不得要求用户重新登录。 - -当后端使用 AgentRun v0.1 短连接 runner 时,Web 必须把当前 conversation 的 `threadId` 作为 -唯一会话连续性字段提交;HWLAB adapter 必须把它写入 AgentRun command `payload.threadId` -和 `SessionRef.threadId`,runner 只按该标准字段执行 Codex app-server `thread/resume`。resume 失败 -必须作为标准 `threadId` 路径上的结构化错误/trace 事件暴露。 - -恢复出的历史消息如果携带 `traceId`,前端必须先对 `/v1/agent/chat/result/` 做 -终态归一,再回放 `/trace`。旧的 `running` 消息不能只因为 localStorage restore 被降级成 -`source` 后停留在“处理中”文本;如果后端 result 已经完成,消息卡片必须替换为真实 -reply/blocker/session/providerTrace。如果 trace 只显示 `result:*` 终态事件而消息仍未完成, -也必须立即查 result,而不是把 `Code Agent result is ready for short-connection polling.` 当成 -最终回复或让用户手工重试。 - -Cloud Workbench 的 Code Agent 单元测试不得依赖真实 token、真实公网 provider 或真实硬件。 -前端状态机测试应使用固定 fixture/mock fetch 覆盖 submit accepted、result completed、result -failed、session busy、partial timeout、trace compacted、SSE 断流和页面恢复;后端测试应使用 -fake Codex app-server client 覆盖长耗时和缺失 `turn/completed`。真实 DEV `--live` smoke 只用于 -发布后读写边界明确的验收,不作为 PR 默认回归测试。 - -## Lightweight Checks - -Use the existing lightweight checks unless a task explicitly authorizes a -heavier browser run: - -```sh -node web/hwlab-cloud-web/scripts/check.mjs -node web/hwlab-cloud-web/scripts/build.mjs -node scripts/dev-cloud-workbench-smoke.mjs --static -node scripts/dev-cloud-workbench-layout-smoke.mjs --static -node scripts/dev-cloud-workbench-smoke.mjs --dom-only --url -``` - -`npm run web:check` 是 Cloud Workbench 的 repo-owned 前端检查入口。它会 -运行源码合同、移动视口 smoke、本地 Code Agent fixture,以及 #273 -SOURCE/static layout smoke;默认不访问公网 DEV,不部署、不重启服务,也不调用 -M3 IO。 - -默认 `web:check` 只把当前工作台主路径、Code Agent/trace/quick-prompt、布局命中和 -安全边界作为阻断检查。历史 auth fixture、演示 fixture 或与当前改动无关的浏览器 -> **门禁最小化见 AGENTS.md P0** — 以下检查为一次性验证入口,非长期保留门禁。 - -默认 `web:check` 只把当前工作台主路径、Code Agent/trace/quick-prompt、布局命中和 -安全边界作为阻断检查。历史 auth fixture、演示 fixture 或与当前改动无关的浏览器 -journey 可以继续产出诊断报告,但不得因为 Playwright `scrollIntoView` 与固定命令栏、 -顶部状态摘要等布局细节耦合而阻塞目标 node/lane CI/CD。需要恢复为阻断检查时,必须先证明该 -fixture 代表真实用户入口问题,而不是旧检查假设。 - -The static smoke checks both sides of the route contract: `/` remains the -user-facing workbench, while `/gate` and `/diagnostics/gate` remain available -for internal diagnostics. This PR-class check is intentionally source-only and -does not deploy, restart services, call public DEV, or run the full live Code -Agent browser journey. - -Live checks against the current target Web URL are read-only and must report -blocked/skip instead of false green when the browser or network path is not -available. - -`--dom-only` keeps the runtime and web-asset identity preflight checks, then -continues with read-only DOM/help validation for the deployed workbench even -when identity drift blocks the full journey. It never sends `POST -/v1/agent/chat`; the Code Agent journey is recorded as `not_applicable` and -must not be used as a DEV-LIVE reply, Secret, mutation, or M3/M4/M5 acceptance -claim. - -## Layout Smoke - -`scripts/dev-cloud-workbench-layout-smoke.mjs` 是 #273 前端布局/遮挡护栏的 -runner 入口。它使用 Playwright 覆盖 `1366x768`、`1024x768` 和 `390x844` -三档视口,检查 M3 控制区、Code Agent 输入区、右侧硬件/可信记录容器、当前 -`/gate` 内部页、外层滚动锁和内部面板滚动。命中测试使用真实 Playwright -点击与 `document.elementsFromPoint()`;不得使用 `force: true` 或纯 DOM -dispatch 绕过用户命中。 - -Layout smoke also covers #278 resize behavior. Desktop and narrow desktop runs -drag `#explorer-resize`, exercise Arrow/Home/End keyboard changes, assert -min/max/clamp and versioned storage restore, then collapse and expand the -resource tree to prove width state is retained. The mobile run asserts the -handle is not displayed or focusable and that no horizontal overflow appears. - -常用命令: - -```sh -npm run web:check -npm run web:layout -npm run web:layout:build -npm run web:layout:live -``` - -三种模式分工: - -| Mode | Command | When | -| --- | --- | --- | -| SOURCE/static | `npm run web:check` 或 `npm run web:layout` | PR/source gate 默认运行,不依赖公网 DEV。 | -| local-build | `npm run web:layout:build` | Cloud Web build/publish 前运行;会先刷新本地 `dist`。 | -| target live | `npm run web:layout:live` | 目标 node/lane deploy 后对当前 Web URL 运行,只证明 UI layout/clickability。 | - -报告字段必须能定位 `status=pass|blocked|skip`、`viewport`、`selector`、 -`failureType` 和 artifact 路径。当前允许的 `failureType` 包括 `overlap`、 -`covered-hit-target`、`overflow`、`outer-scroll-regression`、`screenshot-diff` -以及未上线覆盖项的 `skip`。脚本会保存右侧面板、M3 控制表单、Code Agent -输入区和 `/gate` 当前页局部截图,但不做整页像素 diff 门禁。 - -默认 `web:check` 失败时会把完整 JSON 报告写入 -`tmp/dev-cloud-workbench-layout-web-check.json`,终端断言只输出 compact -blockers/failures:`viewport`、`selector`、`failureType`、summary 和 artifact -路径。`/tmp/hwlab-dev-gate/dev-cloud-workbench-layout*.json` 是显式 `web:layout*` -命令的报告路径;它们属于 #273 UI layout blocker 证据,不属于 M3 trusted green -证据。 - -#287 的硬件状态标签化和 #288 的 `/gate` 单一大表如果尚未上线,layout smoke -只能把对应覆盖项记录为 `skip`,同时继续检查当前可见容器的溢出、遮挡和外层 -滚动。该 UI smoke 只能证明布局/可点击性护栏通过,不等于 M3 DEV-LIVE 硬件 -闭环通过,也不能替代 #227 的 DO/DI 功能验收。 - -该脚本同时覆盖 #276 的接线面板:打开右侧 `接线` 标签,断言 -`panel-wiring` 是两列长表、表头为 `res_boxsimu_1` / `res_boxsimu_2`、IO -行为 `DO1` 对 `DI1`,并记录右侧接线面板 `scrollWidth <= clientWidth`,禁止 -内部横向滚动。该证据仍只证明 UI 布局,不等于 M3 trusted green。 - -## Stable Sources - -- [pikasTech/HWLAB#99](https://github.com/pikasTech/HWLAB/issues/99): default - Cloud Workbench direction. -- [pikasTech/HWLAB#108](https://github.com/pikasTech/HWLAB/issues/108): no - outer scroll, Chinese UI, internal Markdown help. -- [pikasTech/HWLAB#273](https://github.com/pikasTech/HWLAB/issues/273): - Playwright layout and overlap guardrail. -- [pikasTech/HWLAB#276](https://github.com/pikasTech/HWLAB/issues/276): - patch-panel wiring panel two-column long-table feedback. -- [pikasTech/HWLAB#278](https://github.com/pikasTech/HWLAB/issues/278): - resource explorer collapse and controlled resize feedback. -- [code-agent-chat-readiness.md](code-agent-chat-readiness.md): Code Agent - chat 同源 readiness 和 provider credential blocker 边界。 -- [spec-v02-services.md](spec-v02-services.md): Cloud Web runtime wrapper and browser-side TypeScript migration boundary. -- [pikasTech/HWLAB#532](https://github.com/pikasTech/HWLAB/issues/532): archived historical `docs/cloud-web-workbench.md` content. -- [node-gitops-cicd.md](node-gitops-cicd.md): Cloud Web rollout through node-scoped Tekton, GitOps and Argo CD - path. +历史 layout smoke、浏览器排障和实现细节只作为运行参考,不定义需求边界。需要修改 Web 工作台、同源 CLI、trace/result 或公开入口口径时,只更新 UniDesk OA。 diff --git a/docs/reference/code-agent-chat-readiness.md b/docs/reference/code-agent-chat-readiness.md index 2ed9ab50..15f8c26e 100644 --- a/docs/reference/code-agent-chat-readiness.md +++ b/docs/reference/code-agent-chat-readiness.md @@ -1,323 +1,13 @@ -# Code Agent Chat Readiness Runbook +# Code Agent Chat Readiness(历史路径) -本文定义 Cloud Workbench `POST /v1/agent/chat` 的 readiness 判定。它只处理 -Code Agent 回复链路是否具备复测条件,不修复、不读取、不打印、不创建也不修改任何 -Secret 或 token。 +本文不再承载 Code Agent 聊天、provider readiness 或 AgentRun 接入需求规格正文。 -## 运行边界 +统一规格出处是 UniDesk OA: -- Cloud Web 和 API/edge 入口必须从当前 issue/CLI 明确的 node + lane control-plane status 读取;没有明确目标时才从受控 lane 配置解析,禁止把 G14 DEV、v0.2 或 D601 legacy 端口写成全局默认。 -- API/edge 入口不能替代 Workbench 同源聊天入口的真实回复证据;Web 问题必须在同一目标 Cloud Web base URL 下复现和验收。 -- `internal/cloud/code-agent-chat.ts` 是 `/v1/agent/chat` 的后端处理入口。 -- `scripts/code-agent-chat-smoke.mjs` 是 Code Agent chat schema 与 readiness - 合同检查。 -- `scripts/dev-cloud-workbench-smoke.mjs --static` 只验证 Workbench 源码合同和 - `/v1/agent/chat` 前端接线;它不是 DEV-LIVE 回复证明。 +- [PJ2026-0102 Agent编排](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0102-agent-orchestration.md) +- [PJ2026-010202 Runtime装配](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010202-runtime-assembly.md) +- [PJ2026-010204 后端Profile](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010204-backend-profile.md) +- [PJ2026-010205 HWLAB接入](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010205-hwlab-dispatch.md) +- [PJ2026-010401 Web工作台](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010401-web-workbench.md) -## Provider 前置条件 - -当前 v0.2 部署合同中,`hwlab-cloud-api` 把 Code Agent 执行委托给 AgentRun `v0.1`。运行时必须具备可用的 AgentRun manager、runner job、`ResourceBundleRef`、`SessionRef`/PVC、profile SecretRef 和目标 backend profile;如果该 backend 使用 Codex app-server,runner 内还必须证明 workspace、`CODEX_HOME`、Codex binary 和 native thread/session continuation 可用。Per-profile config/credential/dynamic slug 管理见 [spec-v02-provider-management.md](spec-v02-provider-management.md),dispatch/session/child inheritance 见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md)。 - -Codex token boundary 仍由授权路径把 `OPENAI_API_KEY` 注入到目标 runtime。目标 Pod -不能直接指向 public `api.openai.com`。`deepseek` profile 通常指向 -`http://hwlab-deepseek-proxy..svc.cluster.local:4000/v1/responses`;该 -Service 必须先进入 `hwlab-deepseek-responses-bridge`,由 bridge 解压 Codex -Responses 的 zstd request body、规范化 `/v1/models` 返回、丢弃非 `function` tool, -再转发到同 Pod 内 Moon Bridge 4001。Moon Bridge 是 DeepSeek profile 的真实 -Responses 转换和 prompt cache 保留层;不要在 HWLAB 中手写完整转换器替代它。 -`codex-api` profile 是独立的 Codex/OpenAI-compatible Responses 通道。node-scoped runtime 中 -`hwlab-cloud-api` 应把 `codex-api` base URL 指向同 Pod 的 `127.0.0.1` loopback -forwarder;forwarder 再直连 `hyueapi.com` / `.hyueapi.com`,并把这两个域名显式保留在 -`NO_PROXY` / `no_proxy`。这不是 DeepSeek bridge,也不是公网 `api.openai.com`,不能把 -hyueapi 流量改成 HTTP/SOCKS proxy。`http://172.26.26.227:17680/v1/responses` 只能作为 -明确选择旧 D601 Code Queue runner 或历史 egress 时的对照线索;不得把它写回任何当前 node/lane 的默认 `codex-api` base URL,也不得用 DeepSeek bridge 伪装 `codex-api` 通过。 - -Runner 不得尝试修补、读取、回显或替换该 Secret。若 DEV runtime 缺少该授权凭证注入, -`provider_unavailable` 且 `error.missingEnv` 包含 `OPENAI_API_KEY` 必须判为 -`BLOCKED/credential`。 - -部署前和部署后的自动化只允许证明 env 名称、`secretKeyRef` 的 Secret 名和 key 名、以及 -DEV egress/base-url 合同是否声明和保留;不得读取 Secret data,也不得把 Secret 值写入 -report、issue、PR 或截图。 - -## Provider 切换排查方法论 - -Provider/profile 切换故障必须先在目标 pod/host 上打通最小真实闭环。普通 profile config/credential/validate 走 AgentRun 管理 API,不进入 GitOps render 或服务发布;只有共享 bridge/forwarder/runtime/env/SecretRef plumbing 变化才进入 CI/CD。`deepseek`、`dsflash-go`、`codex-api` 和未来 provider 共享 cloud-api 会话与 Workbench UI,但排查时必须把 profile config、SecretRef、认证、网络、模型、AgentRun runner 和 Codex CLI/app-server(若适用)逐层拆开,避免用一个 profile 的成功掩盖另一个 profile 的退化。 - -最小闭环按以下顺序分层,任何一层失败都不能跳到正式 CI/CD 试错: - -1. 运行面确认:在当前 issue/CLI 明确的 node/lane 固定 workspace 与目标 k3s Pod 内确认当前分支、镜像、env overlay、 - `CODEX_HOME`、Codex 版本和 workspace;D601 v0.3 这类 node-scoped lane 是正式目标,不得按 legacy 对照排除。 -2. 凭证边界:只检查 Secret 引用、`auth.json` 顶层 key 和值长度,不打印 secret。Codex CLI 的 - `auth.json` 应能暴露 `OPENAI_API_KEY` 顶层 key;形如 `auth` 的不明结构必须先按 blocker 处理。 -3. 直连边界:`hyueapi.com` / `.hyueapi.com` 必须在 `NO_PROXY` 与 `no_proxy` 内。需要同时检查 - shell env 和 Codex/Rust trace;若 trace 显示 `network_proxy: None` 且直接连接 `hyueapi.com:443`, - 不能再把问题归类为 proxy 污染。 -4. 裸 Responses API:在同一个目标 pod 内用同一份 auth、同一模型、同一 base host 发 - `/responses` 或 `/v1/responses` 流式请求,确认网络、认证和模型是否可用。裸 API 通过只证明 - upstream 可达,不等于 Workbench 或 Codex runner 通过。 -5. Codex CLI 对照:用同一模型、同一 `CODEX_HOME`、同一 prompt 运行 `codex exec --json`;如果任务明确需要旧 D601 Code Queue runner 或其他节点对照,再记录版本、config 形态、NO_PROXY、proxy env 和 transport 摘要。跨节点对照只用于定位差异,不能把对照路径写回当前 node/lane 默认运行态。 -6. Loopback forwarder 对照:如果裸 Responses API 通过、Codex CLI 直连失败,并且 trace 已确认 - `network_proxy: None`,必须在同一个目标 Pod 内增加只监听 `127.0.0.1` 的临时 forwarder,使用同一份 - auth、同一模型和同一 prompt 复测 `codex exec` 与 `/v1/agent/chat`。forwarder 只能把流量转到可配置的 - hyueapi upstream,不能硬编码 D601 IP,也不能复用 DeepSeek bridge。 -7. AgentRun command 闭环:最终证据必须来自真实 AgentRun command result,返回 `completed` 且 final assistant reply 非空,并暴露真实 backend/profile/provider/model。Node/raw HTTPS、stub、bridge、source-only smoke、前端状态都不能升级成 DEV-LIVE reply pass。 - -排查记录应保留稳定结论和判定方法,不写 Secret、一次性 trace 全文或日期化流水账。遇到 -“裸 API 通过但 Codex CLI/app-server 失败”时,优先抓 Codex/Rust transport 日志并与 D601 成功 -路径或其他明确对照路径比对:模型、service tier、`auth.json` 结构、base URL、是否直连、实际连接 IP、请求体大小、 -SSE 是否 completed。只有这些证据归一后,才修改源码、render、SecretRef 或发布配置。 - -## Codex API 转发根因 - -`codex-api` 在 node-scoped runtime 上采用 pod-local loopback forwarder 是一个受控传输边界修复,不是为了规避 -hyueapi 直连要求。根因判定按以下证据链成立: - -- 同一目标 Pod 内,使用同一份 auth、同一模型、同一 Responses payload,通过 Node HTTPS 直接请求 - `hyueapi.com` 能获得完整 SSE `response.completed`;这排除了模型、Secret、请求体、基本网络可达性和 - hyueapi 账号本身不可用。 -- 同一目标 Pod 内,Codex CLI/Rust 传输直连 `https://hyueapi.com/responses` 会在 streaming 阶段断开; - Rust trace 显示 `network_proxy: None` 且连接目标是 `hyueapi.com:443`,这排除了全局 proxy 污染和 - `NO_PROXY` 未生效作为主因。 -- 把 Codex CLI 的 base URL 改为同 Pod `127.0.0.1`,再由 Node forwarder 使用直连 HTTPS 转发到 - hyueapi,`codex exec` 与 `/v1/agent/chat` 均能完成并返回非空 assistant 回复;这把失败边界收敛到 - Codex CLI 的 Rust HTTPS/SSE transport 与 G14->hyueapi 边缘路径组合,而不是 Workbench、DeepSeek、 - 模型或 auth。 -- 旧 D601 Code Queue runner 使用同模型可成功,只能证明该对照路径可用;不能把 - `172.26.26.227:17680` 写回当前 node/lane 默认配置。 - -因此,在不修改 Codex CLI 二进制、不要求 hyueapi 改边缘行为、也不把 hyueapi 流量送进 HTTP/SOCKS -proxy 的前提下,pod-local Node forwarder 是当前可控的最小修复。它的职责只是替换 Codex CLI 失败的 -直接 HTTPS/SSE transport;hyueapi 仍由 forwarder 进程直连,`hyueapi.com` / `.hyueapi.com` 仍必须在 -`NO_PROXY` 和 `no_proxy` 中。 - -## 转发器迁移与隔离 - -Codex API forwarder 必须是 Pod 内部能力,推荐作为 `hwlab-cloud-api` 同 Pod sidecar 或等价的同 Pod -受控进程运行。`hwlab-cloud-api` 只连接 `http://127.0.0.1:`;forwarder 通过 env 配置 upstream, -默认 upstream host 为 `hyueapi.com`。以下约束保证它可迁移且不会污染其他运行面: - -- 禁止硬编码 provider host IP、D601 `172.26.26.227`、G14 节点 IP、namespace 名或 NodePort。可配置项只应是 - loopback listen port、upstream base URL、模型 profile env 和 Secret 引用。 -- forwarder 不创建 Kubernetes Service、Ingress、NodePort 或 host port;它只监听 Pod network namespace 内的 - `127.0.0.1`。同一 k3s 集群内 `hwlab-dev`、`hwlab-prod` 或其他 namespace 可以同时各自运行一个 - `hwlab-cloud-api` Pod 和同端口 forwarder,因为每个 Pod 都有独立 loopback。 -- 不要给 `hwlab-cloud-api` Pod 启用 `hostNetwork` 来承载 forwarder。若某个迁移目标必须使用 hostNetwork, - 必须重新评估端口冲突和隔离边界,不能沿用“Pod 内同端口无冲突”的结论。 -- 迁移到其他 k3s 时,只需要保证目标 Pod 能直连 `hyueapi.com:443`、SecretRef 仍以 `OPENAI_API_KEY` 注入、 - `CODEX_HOME/auth.json` 形态正确、`NO_PROXY/no_proxy` 包含 `hyueapi.com` 与 `.hyueapi.com`,以及 - loopback forwarder 进程跟 `hwlab-cloud-api` 在同一 Pod network namespace。 -- DEV、PROD 和临时 smoke Pod 的证据必须分开记录。DEV forwarder 通过不能自动证明 PROD 通过;PROD - 需要在 PROD namespace 的目标 Pod 内复跑最小 `/v1/agent/chat` 闭环。 - -## 自动化兼容性 - -Forwarder 不需要人工维护长驻进程。正式固化后,它应由 Kubernetes Deployment 管理生命周期:Pod 创建时随 -`hwlab-cloud-api` 启动,Pod 删除时一起退出,异常退出由 kubelet 按 Pod/容器 restart policy 重启。人工只允许在 -临时 smoke Pod 中手动启动 forwarder 做分层诊断;运行态不应依赖手动 `kubectl exec` 后台进程。 - -自动化合同验证(一次性检查,非长期门禁。门禁最小化见 AGENTS.md P0): - - -- `codex-api` profile base URL 指向 Pod-local loopback,不指向 D601 IP 或 `api.openai.com`。 -- forwarder upstream base URL 默认 `hyueapi.com`,`NO_PROXY/no_proxy` 包含 `hyueapi.com` / `.hyueapi.com`。 -- `hwlab-cloud-api` Pod 包含 forwarder sidecar,forwarder 不暴露 Service/NodePort/Ingress/hostPort。 -- `deepseek` profile 仍指向 DeepSeek bridge/Moon Bridge;`codex-api` profile 不依赖 DeepSeek bridge。 - -完整 CI/CD、GitOps render 或发布流水线只能在目标 Pod 最小闭环已经通过、且当前 CI/CD 基础设施可用时继续。 -最小闭环没有通过时,不要通过反复推送 CI/CD 来探索 provider transport;CI/CD 只能固化已经在目标运行面证明可行的 -配置和代码。 - -## 判定标准 - -| 观测结果 | readiness | -| --- | --- | -| `status: "failed"`,`error.code: "provider_unavailable"`,且 `error.missingEnv` 包含 `OPENAI_API_KEY` | `BLOCKED/credential`;provider 凭证缺失,不能标真实回复通过。 | -| AgentRun dispatch/runner/profile blocker,或 blocker 包含 `runner_lifecycle_missing`、`workspace_mount_missing`、`workspace_write_boundary_blocked`、`codex_cli_binary_missing`、`codex_cli_not_executable`、`codex_home_missing`、`provider_token_boundary` | 真实 AgentRun runner / backend profile 未具备;必须按 blocker 处理,不能表述为完整 Code Agent session。 | -| `status: "completed"`,但来自 mock、fixture、本地 stub、source-only smoke、浏览器本地回显或人工拼接 | 不是 DEV-LIVE reply pass。 | -| 真实 DEV `POST /v1/agent/chat` 返回 `status: "completed"`,且 `reply.content` 是非空 assistant 回复 | 可标 DEV-LIVE reply pass。 | -| 传输失败、schema 不完整、HTTP 非预期、`reply.content` 为空或缺失 | `BLOCKED`,按 runtime/schema/transport 分析。 | - -只有“真实 DEV 路由 + `completed` + 非空 assistant reply”能作为 DEV-LIVE 回复通过依据。 -不得把 mock、fixture、本地 echo、source report、静态检查或前端状态当作通过。 - -`agentrun-v01` 只能表示执行基础设施,不等同于真实 provider/model。Code Agent result `completed` 要被 Web 或 CLI 标记为真实完成,必须同时具备 final assistant response、真实 provider/model/backend profile、`providerTrace`、traceId、conversationId/sessionId 和可回放 trace;否则应显示“完成证据不足”,不能用 SOURCE、fixture、echo、mock 或 stub 补齐。AgentRun adapter 应把真实执行形态暴露为具体 backend profile,例如 `dsflash-go`、`deepseek`、`codex-api` 或 `minimax-m3`,把 `agentrun-v01` 保留在 adapter、runner 或 infrastructure 字段里。 - -同一 conversation/session 的后续消息必须在 AgentRun runner reuse window 有效时进入既有 run/runner 的新 command/turn,避免每次消息都重新 bundle、重新启动 runner、再把历史 thread 当作新 runner 可 resume 的 rollout。每条消息都重新 bundle 或启动新 runner 是功能缺口,不得只靠 trace 说明包装成通过。只有 run 已 terminal、runner reuse window 过期或 AgentRun manager 明确拒绝复用时才允许新建 runner;trace/result 可以说明原因,但该说明只是诊断证据,不替代复用能力本身。 - -Trace 展示问题按“同源 row 转换优先”排查:先用 `hwlab-cli client agent trace --render web` 输出 Cloud Web 同一 trace row 摘要;CLI 也乱说明 row 转换逻辑问题,CLI 正常而浏览器乱再查 DOM、CSS、滚动和增量 patch。 - -## 自然语言单一路由 - -`/v1/agent/chat` 的自然语言请求唯一执行路径是 AgentRun v0.1 delegated Code Agent command。cloud-api 不再把自然语言预分类到 M3 Skill CLI、`/v1/m3/io`、 -`external.network.check`、`session_context`、`security.hardware-boundary`、 -`hardware.invoke.shell` shortcut 或 OpenAI text fallback。 - -自然语言里即使出现 M3、DO/DI、DAP、PWM、gateway、box-simu、patch-panel、Keil、 -serial-monitor、Windows skill、串口、下载、烧录、启动日志等词,也必须把完整请求交给 -AgentRun Code Agent turn。Agent turn 自己根据仓库、skill 文档和可用工具决定调用 repo wrapper、 -Windows skill CLI、项目脚本或其他真实可达路径;cloud-api 只负责 session 生命周期、trace、 -result 轮询和 schema 化返回。 - -如果 AgentRun Code Agent 不具备运行条件,`/v1/agent/chat` 只能返回 AgentRun readiness -blocker,不能降级到 M3 Skill CLI、受控硬件 shortcut、外网专用检查或普通 OpenAI 文本回复。 -显式 `/v1/m3/io` 控制面可以作为独立 API 或 UI 控制面继续存在,但聊天自然语言不得自动路由 -到该 API,也不得保留要求自然语言先满足 M3 白名单的源码检查或测试。该显式控制面也不得在 -进入 gateway 前保留固定 `DO1/DI1` 或固定 gateway 身份白名单预拦截;真实下游执行失败可以 -返回执行失败,但不能由 cloud-api 用旧白名单提前拒绝。 - -显式持久 session 是默认合同:用户、Workbench 或 CLI 必须先显式创建或选择 Code Agent -session,之后同一个 `conversationId/sessionId` 才能映射到 AgentRun `SessionRef`/PVC/thread 和固定 workspace。刷新前端、重新打开页面或短连接 result 轮询只能恢复已显式选中的 session, -不得创建新的短期 runner,也不得在无 session 时自动生成 `conversationId/sessionId/threadId`。 -没有已选 session 时,`/v1/agent/chat` 必须返回 `session_required`;session failed/stale/canceled -时必须返回 `session_not_usable` 或等价 blocker。失败 session 保留 trace、thread、partial output -和错误证据,不自动滚动、不隐式清理后继续;继续工作前必须显式创建或选择另一个 session。 -除非运行面无法恢复,usable session 的 workspace、thread/session 绑定和 -可见 trace 应持续存在。Workbench 前端可以持久化这些会话标识和最近消息,但只作为显式 session -selection 的缓存;用户显式清空对话或登出时才清除该本地状态。 - -## PC Gateway Windows Skill 调用 - -Code Agent 通过已登记 PC gateway 执行 Windows 侧命令时,必须让 Codex turn 自己调用仓库 wrapper,不能由 cloud-api 字符串匹配短路到 gateway: - -```sh -node /app/tools/hwlab-gateway-shell.mjs --json --timeout-ms --powershell-stdin <<'PS1' - -PS1 -``` - -PowerShell 默认使用 wrapper 的 `-EncodedCommand` 路径;不要手写 `cmd /c powershell ...` 的管道、引号或中文转义。简单 `cmd` 命令仍可用 `--command "cmd /d /s /c ..."`,但涉及目录枚举、Unicode、管道、排序或 JSON 输出时优先用 `--powershell-stdin`。 - -Workbench 会把“Gateway 命令超时”控件的毫秒值随 `/v1/agent/chat` 传入 `gatewayShellTimeoutMs`。Codex prompt 必须把该值落实到 wrapper 的 `--timeout-ms`,cloud-api `hardware.invoke.shell` dispatch timeout 必须取环境配置、请求 `input.timeoutMs` 和 120s 默认值中的较大值并加 grace;不得让 20s/30s 的旧默认提前返回 `dispatchStatus=timed_out`。wrapper 自身 HTTP request timeout 要比 shell timeout 稍长,确保用户看到的是 gateway/cloud 返回的结构化 `status/operationId/dispatch`,不是 wrapper 先超时丢失结果。 - -调大 timeout 不能替代正确的长任务控制语义。Gateway poll loop 必须支持后台 in-flight 执行,长 Keil/UV4 命令运行期间仍能处理短 `job-status`、state/log 读取和健康探测;如果 trace 出现 `shellExecuted=false` 的 dispatch timeout,优先检查 gateway 是否队头阻塞或离线,而不是把所有 wrapper 调用改成长等待。 - -Workbench trace 对已知 JSON-RPC gateway 响应应按普通 tool call 展示:前端首行用中性 `tool gateway.shell status= op= exit= s=`,正文展示 request、gateway/resource/capability、dispatch、command、audit/evidence 以及有界 stdout/stderr。不要把整段 JSON 原样刷屏;复制/下载完整 trace 仍保留原始 JSON。 - -## 短连接 result 轮询 - -## AgentRun/Codex Runner 请求处理与 trace 可见性 - -当 AgentRun backend 使用 Codex app-server stdio 时,runner client 必须把 app-server 发来的 JSON-RPC client request 当作一等协议处理,不能只等待 notification。请求 id 可能是数字也可能是字符串;只支持数字 id 会导致 approval/requestUserInput 等请求永远得不到响应,最终表现为已有 assistant partial output 后卡在 `waitingFor=app-server-notification`,直到 idle timeout。 - -非交互 HWLAB Code Agent 的处理规则如下: - -- `item/commandExecution/requestApproval`、`item/fileChange/requestApproval` 和 `item/permissions/requestApproval` 必须自动返回可用的 approved 决策,优先使用 `availableDecisions` 中的 `approved`、`approved_for_session` 或其他 `approved*`,不能因为旧 approval gate 把真实工具调用拒绝掉。 -- `item/tool/requestUserInput` 和 `mcpServer/elicitation/request` 必须返回结构化 denied/canceled;聊天运行中不能弹人工输入,也不能静默等待用户。 -- 未知 client request 必须返回 JSON-RPC unsupported error,并在 trace 中记录 `client/request:unsupported`;禁止忽略请求。 -- 每个已处理 client request 都必须追加 `client/request/handled` trace 事件,包含 method、decision、itemId/targetItemId,并把 `waitingFor` 推进到 `turn/completed`,避免前端只显示未知 `providerTrace 缺失` 或 `app-server-notification`。 - -commandExecution trace 必须 bounded:命令文本和 stdout/stderr summary 默认只展示有界摘要,但必须保留 `commandBytes`、`commandTruncated`、`outputBytes` 和 stderr 摘要,复制/下载 trace 仍可按后端保留策略展开原始事件。前端和 CLI 不能为了避免输出爆炸而要求 Code Agent 默认加 `| head`、`grep` 或 shell pipe;输出裁剪应在 trace/result 层完成,不能把 stdout pipe 行为变成工具调用是否完成的隐式前提。 - -在 Linux container 内启动 Codex app-server 时,应优先直接执行 `@openai/codex-linux-*` native binary,并把同包 `path` 目录加入 `PATH`;只有找不到 native binary 时才回退到 npm wrapper。直接启动 native binary 可以减少 Node wrapper 双进程、孤儿进程和 close 后未清理进程组导致的 session 卡死风险。关闭 stdio client 时必须终止整个子进程组,不只关闭父进程 stdin。 - -Workbench 与 Code Agent 的用户请求必须是短连接 submit + 短连接 result/trace 轮询;浏览器或 cloud-web 不应持有一次长 HTTP 请求等待整个 Codex turn 结束。`POST /v1/agent/chat` 返回 `202` 后,前端轮询 `/v1/agent/chat/result/` 获取终态,并用 `/v1/agent/chat/trace/` 刷新可视 trace。 - -Code Agent backend 的 completed 语义只能来自真实 Codex app-server `turn/completed` 成功事件。`item/agentMessage/delta`、`item/completed`、已有 assistant 文本、transport close 或 activity idle timeout 都不能单独升级成 `status: "completed"`。如果已经收到部分 assistant 文本但没有收到 `turn/completed`,终态必须是 timeout/partial blocker,并保留 trace、session、thread、partial output 摘要和可重试提示;Workbench 只能显示“部分回复/超时”,不能标 DEV-LIVE reply pass。 - -`Codex app-server transport closed after partial assistant output but before turn/completed` 不能单独判定为 CI/CD 滚动中断。排查必须同时看三类证据:失败 trace 的 `providerTrace`/`runnerTrace`、对应 `hwlab-cloud-api` Pod 的 restart/age、以及同一时间窗口内的 Kubernetes rollout/kill 事件。若 Pod 在 trace 开始前已经稳定且 `RESTARTS=0`,应归类为 Codex app-server transport/session 失败,提示用户显式创建新 session 后重试;只有 trace 时间窗口内存在当前会话所在 Pod 的删除、重建或 restart 证据时,才归类为滚动导致的中断。失败响应也必须尽量保留 `providerTrace`,即使 `terminalStatus=failed`,避免前端把“providerTrace 缺失”误报成未知降级。 - -cloud-web 同源代理必须把短连接语义原样转发给 cloud-api,至少包括 `Prefer: respond-async`、`X-HWLAB-Short-Connection` 和 `X-Trace-Id`。如果这些 header 在 cloud-web 层被过滤,cloud-api 会把同一个请求当成长同步请求处理,用户入口会表现为 `17666` 卡住或代理超时,而 `17667` 直连 cloud-api 正常。此类问题应先比对同一 trace 在 `17666` 与 `17667` 的 submit 行为,再修代理 header 透传,而不是调大前端等待时间。 - -`/v1/agent/chat/result/` 是终态摘要接口,不是完整 trace 下载接口。它可以携带压缩后的 `runnerTrace` 窗口用于传输保活,但 Workbench 用户界面不得把该窗口显示为“压缩窗口”或“显示全部”。只要结果或轮询快照声明 `eventsCompacted=true`,前端必须自动请求 `/v1/agent/chat/trace/` 并用完整 trace 替换可视事件线;回放完成前只能显示“完整 trace 回放中/当前已载入”状态。result 响应仍必须保留 `eventCount`、`lastEvent`、`providerTrace`、`threadId/sessionId` 和终态 reply/blocker;完整 trace 只能从 `/v1/agent/chat/trace/`、复制 JSON 或下载 trace 入口取得。默认 result trace 窗口上限由 `HWLAB_CODE_AGENT_RESULT_TRACE_EVENT_LIMIT` 控制;不要把数百个大 chunk 原样塞进 result 响应,避免 cloud-web 代理层或浏览器 fetch 把“正常执行中的大响应”表现成 503、非 JSON 或空响应。 - -result 轮询的 408/425/429/5xx、浏览器 timeout、非 JSON 或空响应应按“可恢复传输抖动”处理:前端先拉取一次 trace 刷新活性,再带退避继续轮询,只有后端返回结构化 terminal blocker、真实终态失败,或 trace 按无新事件 idle timeout 超时,才向用户显示失败。只要 `/trace` 仍显示新事件或 `waitingFor` 仍在推进,就不能把一次 result poll 失败标成“Code Agent API 错误”并停止。 - -Workbench 的 trace 展示不是终态真相。只要 trace 中出现 `result:completed`、`result:failed`、`result:canceled`、`session:session_busy` 这类 terminal event,或浏览器从本地状态恢复出带 `traceId` 的非终态消息,前端必须再请求 `/v1/agent/chat/result/` 做 result reconciliation,并用 result 的 reply/blocker/session/providerTrace 替换消息卡片。仅回放 `/trace` 不能把旧 running 消息改成完成,也不能把 `Code Agent result is ready for short-connection polling.` 当作用户可见最终回复。 - -长耗时和前后端协同缺陷必须优先用 mock/fixture 复现,不得把真实 token 调用作为日常回归测试。后端单元测试使用 fake Codex app-server JSON-RPC client 模拟 `thread/started`、`turn/started`、assistant delta、command output、`turn/completed` 缺失、transport close 和 idle timeout;前端测试使用固定 `/result`、`/trace`、EventSource、localStorage fixture 验证 result reconciliation、刷新恢复、transient poll error 和 compact trace 回放。真实 `--live` Code Agent smoke 只作为显式授权的 DEV 验证,不进入默认 PR 单元测试路径。 - -Windows 侧 skill、编译器、脚本工具和多参数命令都应走同一个通用传输模式,不新增某个工具的专用 wrapper 子命令: - -- 工作目录优先用 wrapper 的 `--cwd ` 或脚本内 `Set-Location -LiteralPath ` 表达,不要在 prompt 里拼 `cmd /c "cd ... && ..."`。 -- 命令参数在 PowerShell 脚本里用数组或显式变量传递,例如 `$args = @("subcommand", "-p", $projectPath)` 后 `& $exe @args`,避免让模型手动嵌套引号。 -- 对所有 Windows skill 都先复用 `C:\Users\liang\.agents\skills\\SKILL.md` 和该 skill 自带 CLI;Code Agent 只负责通过 repo wrapper 调用,不把 skill 行为复制到 cloud-api 或 wrapper。 -- 一次探测命令失败后,只做一次更窄、更结构化的修正;若仍失败,返回失败 `operationId`、stderr 摘要和下一步,而不是连续试错。 - -Windows 文件系统探测必须是有界小输出: - -- 对 `F:\work`、`F:\work\ConStart` 或同类目录先做顶层目录/项目标记探测,不要读取 Secret、env、kubeconfig、DB URL 或完整源码内容。 -- 使用 `-LiteralPath`、`Select-Object -First `、`ConvertTo-Json -Compress -Depth `,stdout 目标控制在约 12 KB 内。 -- wrapper 的 PowerShell prologue 已设置 UTF-8 console/output,并提供 `Read-HwlabText`、`Select-HwlabText`、`ConvertTo-HwlabJson`。读取中文 `SKILL.md`、Keil 日志或 manifest 时优先用这些 helper,避免 `Get-Content`/`Select-String` 的扩展对象字段和系统代码页造成乱码。 -- 不要先输出完整目录 JSON 再依赖终端截断;需要更多信息时按明确候选项目二次查询。 -- 如果命令已经到达 gateway 但因脚本语法或输出大小失败,只允许简化修正一次;最终回复要记录失败 `operationId`、修正后的成功 `operationId` 和有界输出摘要。 - -Keil 编译、下载或探测请求必须优先使用 Windows 侧 skill,而不是在 prompt 中重写 Keil 调用逻辑: - -```sh -cd C:\Users\liang\.agents\skills\keil -py -3 keil-cli.py build -p -t -py -3 keil-cli.py job-status -``` - -多 probe、烧录和 reset-run 的具体参数以 Windows 侧 `C:\Users\liang\.agents\skills\keil\SKILL.md` 为准;Code Agent 只负责通过 repo wrapper 调用该 skill CLI 并返回 trace、operation/evidence 和 bounded stdout/stderr 摘要。 - -对 build/download 这类长任务,Code Agent 应优先使用 skill 自带的异步 job 语义:启动命令用短 wrapper timeout 拿到 job id 或明确的启动失败,再用短 `job-status`、state 文件和日志读取轮询进展。除非用户明确要求同步等待并设置了足够大的 Gateway 命令超时,不要通过 gateway 执行 `--wait` 长轮询;同步等待会占用一个 in-flight 槽位,旧 gateway 还会造成队头阻塞。 - -串口启动日志请求必须优先使用 Windows 侧 `serial-monitor` skill,而不是在 cloud-api 新增串口专用 route: - -```sh -cd C:\Users\liang\.agents\skills\serial-monitor -npm run cli -- server status -npm run cli -- server start -npm run cli -- monitor start -p -b -npm run cli -- fetch --session-only --no-dedup -``` - -Keil 下载后的启动日志抓取应和 build/download 共用同一个 Codex stdio session 与 gateway wrapper trace。71-FREQ 类项目的串口参数以 Windows 侧 `serial-monitor\SKILL.md` 和实时设备枚举为准;需要轮询时用短 wrapper 调用读取 session/state/log,而不是新增聊天层白名单或 blocker。 - -## Smoke Checks - -本地合同检查: - -```sh -node scripts/code-agent-chat-smoke.mjs -``` - -该命令验证 schema、`provider_unavailable` provider gap、`OPENAI_API_KEY` -missing-env 分类,以及本地 stub completion 不能升级为 DEV-LIVE pass。 - -Workbench 静态接线检查: - -```sh -node scripts/dev-cloud-workbench-smoke.mjs --static -node scripts/dev-cloud-workbench-smoke.mjs --dom-only --url -``` - -该命令验证 Workbench 默认页、同源只读边界和 `/v1/agent/chat` 前端主流程接线。它只产出 -`SOURCE` 级证据。`--dom-only` 会保留部署 runtime/web-asset identity preflight, -但只做真实 DEV DOM/help 只读观察;它不会发送 `/v1/agent/chat`,Code Agent journey -必须记录为 `not_applicable`,不能冒充真实 DEV-LIVE reply。 - -授权凭证注入后的真实 DEV 复测: - -```sh -node scripts/code-agent-chat-smoke.mjs --live -node scripts/code-agent-chat-smoke.mjs --live --url --timeout-ms 45000 -``` - -`--live` 会向真实 DEV `/v1/agent/chat` 发送一条最小聊天请求。输出只包含 -readiness、provider/model/backend、assistant 回复是否非空和长度、错误分类等摘要;不打印 -assistant 回复正文,不读取或打印任何 Secret 值。 - -默认 `--live` 应指向当前 issue/CLI 明确 node + lane 的 API/edge 入口,而不是历史 D601 legacy 端口、G14 DEV 端口或其他 lane 入口。 -健康的 Codex stdio 冷启动首个 assistant token 可能需要数十秒;10 秒级 transport -timeout 会把健康环境误报为 transport blocker。把 timeout 提高到 45 秒左右只是在真 -实 DEV 路由上减少误报,不能替代 `completed` + 非空 assistant reply 的最终判定标 -准。 - -## 复测结果解释 - -- 若输出 `readiness.level: "BLOCKED/credential"`,后续动作是由授权路径注入 - `hwlab-code-agent-provider/openai-api-key`,不是由 runner 临时补 Secret。 -- 若输出 `readiness.level: "#143 DEV-LIVE reply pass"`,只说明真实回复链路通过; - 它不自动证明 M3、M4、M5 或硬件闭环通过。 -- 若 `scripts/dev-cloud-workbench-smoke.mjs --static` 通过,而 `--live` 未通过,结论是 - Workbench 接线和源合同通过,但真实 provider readiness 仍 blocked。 - -## 稳定来源 - -- [docs/reference/cloud-workbench.md](cloud-workbench.md):Cloud Workbench 默认页和同源边界。 -- [docs/reference/dev-runtime-boundary.md](dev-runtime-boundary.md):DEV 端口、k3s 与运行态边界。 -- [docs/reference/architecture.md](architecture.md):`SOURCE`、`LOCAL`、`DRY-RUN`、 - `DEV-LIVE`、`BLOCKED` 证据分级。 +历史 provider 排查方法和 smoke 命令只作为运行参考,不替代显式 session、自然语言单一路由、Codex app-server 协议、result/trace 终态或 failureKind 的 OA 规格。 diff --git a/docs/reference/dev-runtime-boundary.md b/docs/reference/dev-runtime-boundary.md index c85f4823..f3509067 100644 --- a/docs/reference/dev-runtime-boundary.md +++ b/docs/reference/dev-runtime-boundary.md @@ -1,456 +1,13 @@ -# HWLAB Runtime Boundary +# HWLAB Runtime Boundary(历史路径) -This reference defines the stable node/lane environment, port, k3s, and runtime -substitution rules. Current work must resolve its target from the issue, PR, -CLI parameters, or controlled lane config before using any URL or workspace. +本文不再承载 HWLAB runtime boundary、source truth、公开入口或 runtime substitution 需求规格正文。 -## Runtime Ports And Lane Examples +统一规格出处是 UniDesk OA: -Current Web/API/live entries are read from `hwlab nodes ... --node --lane status` or the equivalent control-plane status. The table below records known lane examples; it is not a global default. +- [PJ2026-0106 平台运维](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0106-platform-ops.md) +- [PJ2026-010601 发布流水](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010601-controlled-release.md) +- [PJ2026-010602 源码同步](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010602-source-sync.md) +- [PJ2026-010603 YAML运维](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010603-yaml-first-ops.md) +- [PJ2026-010604 公开入口](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010604-public-entry.md) -| Surface | G14 DEV example | G14 PROD example | G14 v0.2 example | D601 v0.3 example | -| --- | --- | --- | --- | -| Cloud Web browser entry | `http://74.48.78.17:17666/` | `http://74.48.78.17:18666/` | `http://74.48.78.17:19666/` | `https://hwlab.pikapython.com/` | -| API/edge entry | `http://74.48.78.17:17667/` | `http://74.48.78.17:18667/` | `http://74.48.78.17:19667/` | `https://hwlab.pikapython.com/` | -| API/live health | `http://74.48.78.17:17667/health/live` | `http://74.48.78.17:18667/health/live` | `http://74.48.78.17:19667/health/live` | `https://hwlab.pikapython.com/health/live` | - -Public `:16666` and `:16667` are D601 legacy DEV endpoints. They can be used only for migration comparison or incident replay, not as the current HWLAB runtime acceptance target. D601 node-scoped lanes such as D601 v0.3 are not legacy. Internal k3s services may still listen on `6667`; do not rewrite that as a public endpoint. - -D601 `v0.3` 的公网入口是 `https://hwlab.pikapython.com/`,API/live health 是 `https://hwlab.pikapython.com/health/live`。该 lane 的内部 `hwlab-cloud-api` / `hwlab-edge-proxy` Service 仍可监听 `6667`,但浏览器、Web admin smoke 和公网验收必须以 HTTPS edge 为准。Node/undici `fetch` 会按 WHATWG bad-port 规则拒绝 `6666`/`6667`;探测内部 `:6667` 时使用 `curl`、Node `http`/`https` 原生 request、repo-owned probe,或改走公网 HTTPS。gateway 侧同一限制见 [gateway-outbound-demo.md](gateway-outbound-demo.md)。 - -## Route Shape - -Known route examples: - -```text -master hwlab-frps-dev :17666/:17667 --> G14 hwlab-node-frpc in namespace hwlab-dev --> hwlab-cloud-web on internal :8080 for browser traffic --> hwlab-edge-proxy / hwlab-cloud-api on internal :6667 for API and health - -master hwlab-frps-dev :18666/:18667 --> G14 hwlab-node-prod-frpc in namespace hwlab-prod --> hwlab-cloud-web on internal :8080 for browser traffic --> hwlab-edge-proxy / hwlab-cloud-api on internal :6667 for API and health - -master hwlab-frps-dev :19666/:19667 --> G14 v0.2 frpc in namespace hwlab-v02 --> hwlab-cloud-web on internal :8080 for browser traffic --> hwlab-edge-proxy / hwlab-cloud-api on internal :6667 for API and health - -PK01 Caddy/FRP HTTPS --> D601 v0.3 frpc in namespace hwlab-v03 --> hwlab-cloud-web on internal :8080 for browser traffic --> hwlab-edge-proxy / hwlab-cloud-api on internal :6667 for API and health -``` - -G14 PROD is rendered by GitOps as namespace `hwlab-prod` and Argo CD application `hwlab-node-prod`; it uses the `:18666/:18667` public endpoints when enabled. G14 desired state is generated into `deploy/gitops/node/runtime-dev` and `deploy/gitops/node/runtime-prod` and promoted through the `G14-gitops` branch. - -G14 `v0.2` is an additive lane, not a replacement for DEV or PROD. It uses source branch `v0.2`, fixed development workspace `G14:/root/hwlab-v02`, dedicated CI/CD source repo `G14:/root/hwlab-v02-cicd.git`, namespace `hwlab-v02`, and public ports `19666/19667`. The `v0.2` GitOps branch, runtime path and Argo Application must be distinct from DEV/PROD before any automated rollout is enabled. - -## Node k3s Source Of Truth - -The target node's native k3s is the runtime source of truth for the selected lane. Commands that observe or mutate current HWLAB runtime must go through the selected UniDesk route, for example: - -```sh -tran G14:k3s kubectl -n hwlab-dev get deploy,svc,pod -o wide -tran G14:k3s kubectl -n argocd get application hwlab-node-dev hwlab-node-prod -tran G14:k3s kubectl -n hwlab-v02 get deploy,svc,pod -o wide -tran D601:k3s kubectl -n hwlab-v03 get deploy,svc,pod -o wide -``` - -Do not use another node's kubeconfig, D601 legacy `dev-cd-apply`, old JS `ci-publish`, Docker Desktop Kubernetes, or master-server local checks as current runtime acceptance evidence. D601 legacy is only the old DEV/CD replay path; D601 v0.3 is a valid current target when selected by issue/CLI. - -## Branch Role Boundary - -Current runtime work uses explicit node/lane branch lines. For example, D601 v0.3 uses `origin/v0.3` and namespace `hwlab-v03`; G14 v0.2 uses `origin/v0.2`, `/root/hwlab-v02-cicd.git`, `devops-infra` git mirror/relay and `hwlab-v02`. Do not merge `origin/main` as a routine precondition for node-scoped runtime work. Treat `main` only as a historical branch-governance or legacy reference unless a current issue explicitly assigns a `main` migration task. Lane-specific CI/CD branch, runtime path and acceptance rules are authoritative in the corresponding spec and control-plane status. - -## Distributed Passthrough Hygiene - -When running more than one command on a target node, keep all commands inside one remote `script` block: - -```sh -tran : script <<'SCRIPT' -sed -n '1,80p' docs/reference/dev-runtime-boundary.md -sed -n '1,80p' AGENTS.md -SCRIPT -``` - -Do not write `tran : sed ... && sed ...` unless the second command is intentionally local. Shell operators such as `&&`, `;`, and pipes outside the `tran` invocation are evaluated by the local shell; this can make later commands run on the master server and look like a missing-file or truncation bug. - -## Cloud API DB Readiness Authority - -`hwlab-cloud-api` reads the DEV database connection string from Secret -reference `hwlab-cloud-api-dev-db/database-url`. The Secret value is not stored -in source, not printed by reports, and not required for offline validation. - -Runtime DB readiness uses the redacted host parsed from the injected -`HWLAB_CLOUD_DB_URL` Secret value: - -| Field | Value | -| --- | --- | -| Authority source | `secret-url-host` | -| Authority env | `HWLAB_CLOUD_DB_URL` | -| Required for readiness | `true` | -| Probe target | redacted host and port parsed from the Secret URL | - -Health output may report `endpointSource: secret-url-host`, DNS/TCP result, -`liveConnected`, and `liveDbEvidence`, but must keep the DB endpoint and Secret -value redacted. - -The non-secret `cloud-api-db` name is an optional desired alias: - -| Field | Value | -| --- | --- | -| Source | `optional-public-dns-alias` | -| Service | `cloud-api-db` | -| Namespace | `hwlab-dev` | -| Host | `cloud-api-db.hwlab-dev.svc.cluster.local` | -| Port | `5432` | -| Port name | `postgres` | -| Required for readiness | `false` | -| Used for probe | `false` | - -Missing `Service/cloud-api-db`, Endpoint, EndpointSlice, or alias env vars must -not reverse-fail live DB success from the Secret URL host. A future PR may make -that alias operational only if it also owns the Service plus Endpoint or -EndpointSlice manifests and the rollout/apply contract. - -Source validation checks `HWLAB_CLOUD_DB_URL`, `HWLAB_CLOUD_DB_SSL_MODE`, -`endpointSource=secret-url-host`, and `liveDbEvidence=true` with secret values -redacted. It must not require `HWLAB_CLOUD_DB_SERVICE_NAME`, -`HWLAB_CLOUD_DB_SERVICE_NAMESPACE`, `HWLAB_CLOUD_DB_HOST`, or -`HWLAB_CLOUD_DB_PORT` as current readiness inputs. - -The DB readiness contract is layered: - -| Layer | Required evidence | -| --- | --- | -| DNS | The configured target resolves from the `hwlab-cloud-api` runtime path and is not a `.invalid` placeholder. | -| TCP | A redacted TCP probe reaches the configured Postgres port. | -| Auth | Authenticated database access succeeds without printing the connection string. | -| Schema | Required HWLAB schema/migration checks pass without using fixture output as live evidence. | - -`*.invalid` and `hwlab-dev-db.invalid` are forbidden DEV runtime targets. They -may appear only as negative test fixtures; source and runtime health must not -treat them as desired DEV DB endpoints. - -## Code Agent Provider Contract - -DEV Code Agent execution is delegated to AgentRun `v0.1`; source-controlled manifests declare only shared env names, SecretRef plumbing, workspace/runtime settings and non-secret egress settings. Per-profile config/credential/dynamic slug authority is [spec-v02-provider-management.md](spec-v02-provider-management.md); dispatch/session/child inheritance authority is [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md). Dynamic profile changes such as `dsflash-go` are AgentRun profile data, not HWLAB service code changes. - -DEV pods must not call `https://api.openai.com/v1/responses` directly. G14 -`codex-api` must send Codex CLI/app-server traffic to a same-Pod `127.0.0.1` -loopback forwarder; that forwarder direct-connects to `hyueapi.com` / -`.hyueapi.com` and keeps both domains in `NO_PROXY` and `no_proxy`. DeepSeek uses -the cluster bridge/Moon Bridge path. `http://172.26.26.227:17680/v1/responses` is -only a D601 legacy egress or Code Queue runner comparison clue after the migration -to G14, not a G14 default runtime contract. Provider reachability must be proven by -the target pod minimal closure described in [Code Agent Chat Readiness Runbook](code-agent-chat-readiness.md), -not by a one-off runtime patch or by pushing full CI/CD while the closure is still -failing. - -Reports, smokes, and health payloads may show Secret name/key presence, -`missingEnv`, provider status, model, trace IDs, and redacted egress status. -They must never print the OpenAI API key, bearer token, database URL password, -kubeconfig material, or other secret values. - -## Hotfix To Source Rule - -DEV runtime hotfixes are temporary recovery actions. After a hotfix proves the -minimal live path, the durable follow-up is source automation: update manifests, -contracts, docs, and tests so future rollouts reproduce the same env and safety -boundaries. The runner must not re-execute the live hotfix, restart services, -read Secrets, mutate PROD, or claim live evidence from source-only changes. - -DEV pod/Deployment file overrides, ConfigMap mounts, and pod-local edits are -governed by [dev-runtime-hotfix-runbook.md](dev-runtime-hotfix-runbook.md). The -stable audit entry is: - -```sh -node scripts/dev-runtime-hotfix-audit.mjs --pretty -node scripts/dev-runtime-hotfix-audit.mjs --collect-readonly --pretty -``` - -The default mode only prints a read-only plan. `--collect-readonly` may run -`kubectl get` and `kubectl exec` checks with -`KUBECONFIG=/etc/rancher/k3s/k3s.yaml`; it must not apply, patch, rollout, -restart, delete, create, read Secret resources, or print secret values. - -## Durable Runtime Readiness Contract - -DB live readiness and durable runtime readiness are separate gates. A -`/health/live` payload with `db.connected=true` and `db.liveDbEvidence=true` -only proves that the Cloud API reached the DEV DB endpoint without exposing -secret values. It does not prove that runtime writes are persisted through a -durable store. - -When health reports: - -- `runtime.adapter: "memory"` -- `runtime.durable: false` -- `runtime.status: "degraded"` - -the Cloud API is using the process-local runtime store in -`internal/db/runtime-store.ts`. Gateway sessions, box resources, operations, -audit events, and evidence records accepted through the runtime can be lost on -pod restart, redeploy, or scale-out, and cannot be treated as durable M3/M4/M5 -evidence. Users may see accepted operations or evidence disappear after a -runtime replacement, and agent-loop/MVP acceptance must remain degraded or -blocked even if the DB connection layer is green. - -Readiness reports must keep these dimensions distinct: - -| Dimension | Green condition | Degraded/blocking condition | -| --- | --- | --- | -| DB live | `db.ready=true`, `db.connected=true`, `db.liveDbEvidence=true` | Missing env, failed connection, disabled probe, or no `liveDbEvidence` | -| Runtime durability | `runtime.adapter="postgres"`, `runtime.durable=true`, `runtime.ready=true`, `runtime.liveRuntimeEvidence=true`, and runtime auth/schema/migration/read gates are all ready | `runtime.adapter="memory"`, `runtime.durable=false`, missing migration ledger, failed schema/auth/readiness, or no `liveRuntimeEvidence` | - -Do not declare DEV-LIVE complete while `runtime.adapter="memory"` or -`runtime.durable=false`, even when DB live readiness is connected. A selected -Postgres adapter may report `runtime.durableRequested=true`, but it still stays -non-durable until the schema, migration ledger, and read readiness gates are -proven through the configured adapter. - -`HWLAB_CLOUD_DB_SSL_MODE` is the non-secret runtime authority for Postgres TLS -mode. When DEV sets it to `disable`, the runtime strips stale URL `sslmode`, -`ssl`, and certificate query parameters before constructing the `pg` pool; a -Secret URL query parameter must not silently override the manifest SSL contract. - -`/health` and `/health/live` expose this split in `readiness.durability`. -`dbLiveEvidenceObserved=true` with -`dbLiveEvidenceIsDurabilityEvidence=false` means the DB TCP/live layer is -separate from runtime persistence. If runtime durability is blocked, -`blockedLayer` names the current adapter/ssl/auth/schema/migration/durability query -layer, and `requiredEvidence` remains the durable adapter schema, migration, -and read query contract. - -When the active blocker is `runtime_durable_adapter_query_blocked`, DB -connectivity is live but the durable runtime adapter has not completed the -required read queries through the runtime store. Future reports must call this a -runtime durability blocker, not a DB connectivity blocker, and must keep M3, -M4, and M5 full acceptance blocked until the durable runtime postconditions -below are true. - -## DEV DB Provisioning Automation - -The cloud-api image owns a stable DEV DB provisioning entrypoint: - -```sh -bun cmd/hwlab-cloud-api/provision.ts --check -bun cmd/hwlab-cloud-api/provision.ts --dry-run --allow-live-db-read --confirm-dev --report /tmp/hwlab-dev-gate/dev-runtime-provisioning-report.json -bun cmd/hwlab-cloud-api/provision.ts --apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-provisioning-report.json -``` - -This is the preferred image-internal operator command for `hwlab-cloud-api`. -It delegates to the same repo-owned provisioning implementation as the root -script and receives admin/target DB inputs only through SecretRef-backed env. - -The repo-level compatibility entrypoint remains: - -```sh -node scripts/dev-runtime-provisioning.mjs --check -node scripts/dev-runtime-provisioning.mjs --dry-run --allow-live-db-read --confirm-dev --report /tmp/hwlab-dev-gate/dev-runtime-provisioning-report.json -``` - -The default `--check` path validates the redacted target DB URL contract only: -the application role name, target database name, password presence, SecretRef -names, and endpoint authority are represented as booleans or redacted endpoint -class. It never connects to Postgres, never reads Kubernetes Secret data, and -never prints the target role, database name, host, password, token, DSN, or -kubeconfig material. - -An authorized DEV provisioning apply is: - -```sh -node scripts/dev-runtime-provisioning.mjs --apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-provisioning-report.json -``` - -The apply path uses `HWLAB_CLOUD_DB_URL` from -`hwlab-cloud-api-dev-db/database-url` as the redacted target contract and -`HWLAB_CLOUD_DB_ADMIN_URL` from -`hwlab-cloud-api-dev-db-admin/admin-url` as the admin SecretRef env. It may -create or update only the DEV target role, target database, database `CONNECT` -grant, and `public` schema `USAGE, CREATE` grants needed by the cloud-api -durable runtime. It must report `created` or `existed` booleans and structured -blockers such as role missing, database missing, SSL, auth, schema, migration, -or durability readiness. It must not read Secret objects, print Secret values, -run PROD changes, use manual `psql`, or perform schema migration. - -Provisioning reports intentionally keep target role, database, host, password, -and admin DSN out of the output. `role missing` and `database missing` are -reported as separate blockers so an auth failure cannot be repaired with an -untracked manual DB write. - -## Runtime Migration Automation - -The cloud-api image owns a stable runtime migration entrypoint: - -```sh -bun cmd/hwlab-cloud-api/migrate.ts --check -bun cmd/hwlab-cloud-api/migrate.ts --dry-run --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json -bun cmd/hwlab-cloud-api/migrate.ts --apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json -``` - -This is the preferred image-internal operator command for `hwlab-cloud-api`. -It delegates to the same repo-owned migration implementation as the root -script, so there is only one migration contract and one output format. The -cloud-api artifact build copies `cmd/`, `scripts/`, `internal/`, `package.json`, -and runtime dependencies into the image; the DEV CD runtime migration Job uses -`bun cmd/hwlab-cloud-api/migrate.ts` from the current cloud-api image and -injects DB inputs only through SecretRef-backed env. - -The repo-level compatibility entrypoint remains: - -```sh -node scripts/dev-runtime-migration.mjs --check -node scripts/dev-runtime-migration.mjs --dry-run --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json -``` - -Those default paths are source-only. They validate -`internal/db/migrations/0001_cloud_core_skeleton.sql`, the required -`hwlab_schema_migrations` ledger row, and the durable runtime table/column -contract without connecting to Postgres, reading Kubernetes Secrets, or writing -DEV/PROD state. - -An authorized operator may run a read-only live verification only after -injecting the DEV DB URL through the existing Secret/env path: - -```sh -node scripts/dev-runtime-migration.mjs --dry-run --allow-live-db-read --confirm-dev --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json -``` - -A real DEV migration apply is intentionally separate and requires all explicit -write flags: - -```sh -node scripts/dev-runtime-migration.mjs --apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json -``` - -The apply command is scoped to DEV Postgres schema objects declared by -`internal/db/migrations/0001_cloud_core_skeleton.sql` and the -`hwlab_schema_migrations` ledger row. It must not be run for PROD, must not -read Kubernetes Secret resources, must not print `HWLAB_CLOUD_DB_URL` or any -password/token value, and must not be described as M3/M4/M5 acceptance. - -Runtime migration reports separate the blockers as: - -| Gate | Meaning | -| --- | --- | -| Auth | DB driver/auth/authorization can run the readiness query. | -| Schema | Required durable runtime tables and columns are present. | -| Migration | The required source migration is recorded in the ledger. | -| Readiness | Durable runtime read readiness passed after schema and ledger checks. | - -## Durable Runtime Postflight - -The repo-owned postflight entrypoint is: - -```sh -node scripts/dev-runtime-postflight.mjs --check -node scripts/dev-runtime-postflight.mjs --live --confirm-dev --confirmed-non-production --target api --report /tmp/hwlab-dev-gate/dev-runtime-postflight-report.json -``` - -Default `--check` is source-only. Live mode first reads -`http://74.48.78.17:17667/health/live` and -`http://74.48.78.17:17667/v1`. `/v1` must expose only the controlled -same-origin M3 IO route `/v1/m3/io` with contract `m3-io-control-v1`; generic -frontend gateway/box/patch-panel access is not a valid postflight substitute. -The postflight only performs the M3 -`DO1=true -> DI1=true -> DO1=false -> DI1=false` write/read sequence when both -endpoints prove `runtime.adapter="postgres"`, `runtime.durable=true`, -`runtime.ready=true`, and `runtime.liveRuntimeEvidence=true`. - -The M3 portion must then prove all four expected operations, exact true/false -values, operation/trace/audit/evidence identifiers, `evidenceState.status="green"`, -`evidenceState.sourceKind="DEV-LIVE"`, `evidenceState.durable=true`, and -`evidenceState.writeStatus="persisted"`. DB SecretRef presence, TCP -connectivity, `db.connected=true`, or `db.liveDbEvidence=true` alone must leave -the postflight blocked with the durable runtime blocker preserved. - -## Durable Runtime Unblock Runbook - -This runbook is a reusable checklist for a future authorized live -mutation/migration. It does not itself authorize a live write. Runners working -from source must stop at the read-only rows unless the commander explicitly -authorizes the DEV apply command and the preconditions below are already true. - -| Check | Safe for normal runners | Evidence allowed | Not allowed | -| --- | --- | --- | --- | -| Source migration contract | Yes | `node scripts/dev-runtime-migration.mjs --check` and `node scripts/dev-runtime-migration.mjs --dry-run --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json` | DB connection, Secret read, DEV/PROD write | -| Static runtime boundary contract | Yes | `node scripts/validate-runtime-boundary.mjs`, source docs, manifests, and redacted Secret refs | Live mutation, service restart, Secret value output | -| Public health observation | Yes, when command scope is read-only | `/health/live` fields such as `db.liveDbEvidence`, `runtime.adapter`, `runtime.durable`, `runtime.blocker`, `readiness.durability.blockedLayer`, `requiredEvidence`, and redaction/safety flags | Printing DB URLs, passwords, tokens, kubeconfig material, or Secret data | -| Live provisioning apply | No, unless explicitly authorized by commander/operator | `node scripts/dev-runtime-provisioning.mjs --apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-provisioning-report.json` with role/database created/existed booleans and no secret output | PROD apply, Secret value output, manual DB shell, schema migration, service restart, M3 acceptance promotion | -| Live DB read verification | Only with explicit DEV read authorization | `--dry-run --allow-live-db-read --confirm-dev --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json` output with redacted endpoint and `secretValuesPrinted=false` | Kubernetes Secret reads, writes, migration apply, PROD target | -| Live migration/repair apply | No, unless explicitly authorized by commander/operator | `--apply --confirm-dev --confirmed-non-production --report /tmp/hwlab-dev-gate/dev-runtime-migration-report.json` plus post-apply health evidence | PROD apply, Secret value output, service restart, Code Agent POST, hardware write, or acceptance promotion | -| Durable runtime postflight | Only after durable runtime readiness is already green | `node scripts/dev-runtime-postflight.mjs --live --confirm-dev --confirmed-non-production --target api --report /tmp/hwlab-dev-gate/dev-runtime-postflight-report.json` with `/health/live`, `/v1`, and M3 true/false durable green evidence | Running M3 writes while runtime durable readiness is blocked, Secret output, PROD, or manual rollout | - -Secret handling rules are the same for every row: verify env names, -`secretKeyRef` names/keys, configured provider/model/base URL, redacted endpoint -source, readiness booleans, blocker codes, and `secretValuesPrinted=false`. -Do not run `kubectl get secret`, do not decode Secret data, and do not paste -`HWLAB_CLOUD_DB_URL`, `OPENAI_API_KEY`, bearer tokens, kubeconfig content, or -passwords into reports, PRs, issues, logs, screenshots, or chat. - -Before any authorized live migration or repair, all of these preconditions must -be true: - -- The commander has explicitly authorized a DEV-only migration/repair for this - blocker; no PROD target, deploy, restart, or unrelated smoke is bundled into - the same action. -- Source validation passes for `internal/db/migrations/0001_cloud_core_skeleton.sql`, - the durable runtime tables/columns, and the `hwlab_schema_migrations` ledger - row. -- DEV DB provisioning is ready: target role and database are either already - present or created by `scripts/dev-runtime-provisioning.mjs`, and the report - carries only created/existed booleans plus redacted endpoint class. -- The runtime is requesting the Postgres durable adapter, not silently using - memory: `runtime.adapter="postgres"` or equivalent selected-adapter evidence, - with `runtime.durableRequested=true`. -- DB live evidence is already green through the redacted Secret URL host: - `db.liveDbEvidence=true` and `db.endpointSource="secret-url-host"`. -- The current blocker is recorded exactly, for example - `runtime_durable_adapter_query_blocked`, with `blockedLayer` and - `requiredEvidence` preserved in the report. -- The runner/operator can produce a redacted report that states - `secretValuesPrinted=false` and does not require reading Kubernetes Secret - resources. - -After an authorized migration/repair, the blocker has moved or cleared only -when a new read-only health/report observation proves one of these exact -postconditions: - -- Cleared: `runtime.adapter="postgres"`, `runtime.durable=true`, - `runtime.ready=true`, `runtime.liveRuntimeEvidence=true`, - `readiness.durability.ready=true`, no - `runtime_durable_adapter_query_blocked`, and durable auth/schema/migration/read - gates are all ready. -- Moved: the old `runtime_durable_adapter_query_blocked` code is absent and a - different explicit blocker is present, such as auth, schema, migration, or - driver readiness; the report must name the new blocker and keep acceptance - blocked. -- Still blocked: `runtime_durable_adapter_query_blocked` remains present, - `runtime.durable=false`, or `runtime.liveRuntimeEvidence=false`; no full - M3/M4/M5 acceptance may be claimed. - -No full M3, M4, or M5 acceptance is allowed while runtime durability is blocked. -DB live readiness, Code Agent readiness, source migration readiness, and -read-only health observations are supporting evidence only; they do not prove -durable runtime evidence or the M3 trusted hardware loop. - -## Runtime Substitution Ban - -UniDesk services, provider-gateway, backend-core, microservice proxies, local -fixtures, and runner-local mocks may support scheduling, CI, CD, source checks, -or dry-runs. They cannot be described as HWLAB runtime and cannot satisfy M3, -M4, or M5 live evidence. - -## Stable Sources - -- [deploy/frp/README.md](../../deploy/frp/README.md): FRP DEV contract. -- [spec-v02-cicd.md](spec-v02-cicd.md): v0.2 runtime namespace, FRP ports and GitOps lane boundary. -- [pikasTech/HWLAB#532](https://github.com/pikasTech/HWLAB/issues/532): archived legacy D601 observability and DEV acceptance root docs. -- [pikasTech/HWLAB#164](https://github.com/pikasTech/HWLAB/issues/164): - Code Agent provider and DB live hotfix follow-up contract. -- [pikasTech/HWLAB#61](https://github.com/pikasTech/HWLAB/issues/61): manual - rollout review and automation requirements. +历史 hotfix、DB unblock、postflight 和迁移命令只作为运行手册线索,不定义长期规格。当前 node/lane、workspace、public URL 和 runtime 状态必须从受控配置、CLI 和 OA 规格确认。 diff --git a/docs/reference/gateway-outbound-demo.md b/docs/reference/gateway-outbound-demo.md index 4603001a..2aa80485 100644 --- a/docs/reference/gateway-outbound-demo.md +++ b/docs/reference/gateway-outbound-demo.md @@ -1,90 +1,12 @@ -# Gateway 主动出站 demo +# Gateway 主动出站 demo(历史路径) -本文是 `hwlab-gateway` 最小主动出站闭环的长期参考。该 demo 只验证 gateway 主动连接 cloud、cloud 下发命令、gateway 执行并回传结果;不得把它当作 M3 `DEV-LIVE` 虚拟硬件可信闭环,也不得替代 `BOX-SIMU / Gateway-SIMU / hwlab-patch-panel` 的 M3 验收链路。 +本文不再承载 AI 网关、HWPOD 服务或 gateway API 需求规格正文。 -## 边界 +统一规格出处是 UniDesk OA: -- `hwlab-gateway` 运行在用户 PC 或本地环境,主动访问 `hwlab-cloud-api`;cloud 不需要也不应入站访问 gateway。 -- demo 采用普通 HTTP poll/result:gateway 调 `POST /v1/gateway/poll` 拉取命令,执行后调 `POST /v1/gateway/result` 回传 JSON-RPC response。 -- `hardware.invoke.shell` 仍是 cloud-api 对外 RPC 方法;有在线 gateway 时通过主动出站链路派发,没有在线 gateway 时保留 `not_connected` 降级返回。 -- 当前命令执行能力只用于受限 demo;正式 HWPOD 控制以 [spec-hwpod-harness.md](spec-hwpod-harness.md) 和 [spec-user-access.md](spec-user-access.md) 为权威:用户权限由 `cloud-api` 的 `admin/user` 与 OpenFGA tool capability 判断;设备执行收敛到 `hwpod-cli -> hwpod-compiler-cli -> cloud-api /v1/hwpod-node-ops -> hwpod-node`。 +- [PJ2026-0101 硬件池](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0101-hardware-pool.md) +- [PJ2026-010103 HWPOD服务](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010103-hwpod-service.md) +- [PJ2026-010104 AI网关](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010104-ai-gateway.md) +- [PJ2026-010403 API契约](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010403-api-contract.md) -## Cloud API 入口 - -- `GET /v1/gateway/sessions`:只读查看在线 gateway、队列深度和 last-seen。 -- `POST /v1/gateway/poll`:gateway 主动注册、心跳并领取下一条待执行 JSON-RPC 请求。 -- `POST /v1/gateway/result`:gateway 主动回传 JSON-RPC response,cloud-api 用 request id 完成等待中的 `hardware.invoke.shell`。 -- `POST /json-rpc` 或 `POST /v1/rpc/hardware.invoke.shell`:用户、agent 或 smoke 仍只调用 cloud-api,不直连 gateway。 - -## Poll Loop 和长命令并发 - -Gateway 的 poll loop 不能等待单条 shell 命令结束后才继续 poll。Keil build/download、烧录或 Windows skill 可能运行数分钟;这些长命令必须在 gateway 内作为 in-flight 请求后台执行,poll loop 继续注册心跳并领取短状态读取、日志读取和取消/诊断请求。 - -判断问题类型时区分两种 timeout: - -- `shellExecuted=true` 且有 `operationId`:命令已经到达 gateway,本次 shell 超过了命令超时;下一步应读取 job state、日志或产物时间戳,而不是盲目把超时继续调大。 -- `shellExecuted=false`、`dispatchStatus=timed_out` 且旧链路可能 `operationId=null`:cloud-api 等不到 gateway 领取或回传,通常是 gateway poll loop 被前一个长命令队头阻塞,或 gateway 离线;修复重点是非阻塞 poll 和 in-flight 可观测性,不是只加大 dispatch timeout。 - -Gateway 必须在 registration payload 和 `/v1/gateway/sessions` 中暴露 `inflightCount`、`maxInflightRequests` 和当前 in-flight 摘要。默认允许少量并发,使一个长 Keil 操作不会阻塞后续只读 `job-status`、state/log 读取或健康探测;超过并发上限时应返回结构化 `gateway_busy`,不能让请求静默排队到 cloud dispatch timeout。 - -## Gateway 环境变量 - -| 变量 | 作用 | -| --- | --- | -| `HWLAB_GATEWAY_CLOUD_URL` | cloud-api 或 edge-proxy 地址;本地可用 `http://127.0.0.1:6667`,目标运行面使用当前 issue/CLI node + lane 的 API/edge URL。 | -| `HWLAB_GATEWAY_ID` | gateway 稳定身份,例如 `gtw_windows_1`。 | -| `HWLAB_GATEWAY_SESSION_ID` | gateway session id;不填时默认为 `gws_${HWLAB_GATEWAY_ID}`。 | -| `HWLAB_GATEWAY_CMD_EXEC_ENABLED=1` | 允许执行 shell 命令;未设置时 gateway 拒绝 `hardware.invoke.shell`。 | -| `HWLAB_GATEWAY_DEMO_OPEN=1` | demo 明确打开标记;本地 smoke 会设置。 | -| `HWLAB_GATEWAY_POLL_INTERVAL_MS` | poll 间隔,默认 500ms。 | -| `HWLAB_GATEWAY_MAX_INFLIGHT` | 同一 gateway 同时执行的 cloud 请求数,默认 3;用于避免长 Keil/UV4 命令阻塞短状态查询。 | -| `HWLAB_GATEWAY_CMD_TIMEOUT_MS` | 单条命令超时,默认 120000ms;Workbench 发起 Code Agent 请求时可通过“Gateway 命令超时”控件把本轮 wrapper `--timeout-ms` 调到 1/2/3/5/10 分钟。 | -| `HWLAB_GATEWAY_CMD_OUTPUT_LIMIT_BYTES` | stdout/stderr 单路输出上限,默认 65536 bytes。 | - -本地或内网存在代理时,必须显式设置: - -```powershell -$env:NO_PROXY="localhost,127.0.0.1,::1" -$env:no_proxy="localhost,127.0.0.1,::1" -``` - -## 本地验证 - -优先使用一键 smoke,避免手动多终端状态不一致: - -```powershell -npm run gateway:demo:smoke -npm run gateway:demo:edge-smoke -``` - -- `gateway:demo:smoke` 启动本地 `hwlab-cloud-api` 和 `hwlab-gateway`,验证 `hardware.invoke.shell` 返回 `stdout=hwlab-demo`。 -- `gateway:demo:edge-smoke` 额外启动本地 `hwlab-edge-proxy`,验证普通 HTTP proxy 能转发 `/v1/gateway/poll`、`/v1/gateway/result` 和 `/json-rpc`。 -- 两个 smoke 都会设置 `NO_PROXY/no_proxy`,用于规避本地代理误触发。 -- 对目标 pod 内部 `127.0.0.1:6667` 或 service `:6667` 做 Node 探测时,不要用 Web/undici `fetch`;`6667` 属于 WHATWG bad port,Node 会直接报 `bad port`。gateway 传输层和 repo-owned 探测脚本应使用 `http/https` 原生 request,或改走当前 target API/browser 入口。 - -## DEV 使用 - -DEV cloud-api 部署包含 `/v1/gateway/*` 后,Windows gateway 可用以下方式主动连接: - -```powershell -$env:HWLAB_GATEWAY_CLOUD_URL="" -$env:HWLAB_GATEWAY_ID="gtw_windows_1" -$env:HWLAB_GATEWAY_SESSION_ID="gws_gtw_windows_1" -$env:HWLAB_GATEWAY_CMD_EXEC_ENABLED="1" -$env:HWLAB_GATEWAY_DEMO_OPEN="1" -bun run .\cmd\hwlab-gateway\main.ts -``` - -验证时从 cloud-api 侧调用 `hardware.invoke.shell`,不要尝试从 cloud 入站访问 Windows gateway。若 `GET /v1/gateway/sessions` 能看到对应 `gatewaySessionId` 且 JSON-RPC 返回 `dispatch.shellExecuted=true`,说明主动出站 demo 链路成立。 - -## 后续替换为 WebSocket - -HTTP poll 是最小 demo 形态。后续替换成 WebSocket 时,应保留: - -- `hardware.invoke.shell` 对外 RPC 方法名; -- JSON-RPC request/response envelope; -- gateway 执行器的 stdout/stderr/exitCode/timedOut 返回形态; -- audit/evidence 由 gateway/cloud 硬件通道产生的原则; -- cloud-web、agent 和 CLI 不直连 gateway 的边界。 - -只替换传输层:`/v1/gateway/poll` 和 `/v1/gateway/result` 合并到 gateway 主动建立的 `/v1/gateway/ws` 长连接。 +历史 demo 命令只证明过最小主动出站链路,不替代 HWPOD、AI 网关、in-flight、gateway_busy 或 cloud-only API 边界规格。 diff --git a/docs/reference/node-gitops-cicd.md b/docs/reference/node-gitops-cicd.md index 27c3feb7..01eeaf35 100644 --- a/docs/reference/node-gitops-cicd.md +++ b/docs/reference/node-gitops-cicd.md @@ -1,251 +1,14 @@ -# Node GitOps CI/CD +# Node GitOps CI/CD(历史路径) -HWLAB CI/CD 运行面目标必须由当前 issue、PR、CLI 参数或受控 lane 配置解析为明确的 node + lane。CI/CD 只能作用于该 node 的 k3s 和该 lane 的 GitOps/namespace,不接管其他 node/lane,不使用 UniDesk Code Queue 作为调度器,也不把 UniDesk backend、provider-gateway 或 microservice proxy 当作 HWLAB runtime。G14 DEV/PROD、G14 v0.2 和 D601 v0.3 都只是 node/lane 实例;D601 legacy 只指旧 DEV/CD 回放路径。 +本文不再承载 node/lane CI/CD、GitOps 或公开入口需求规格正文。 -## 目标模型 +统一规格出处是 UniDesk OA: -- Source of truth:业务版本以 Git source commit 为唯一身份;镜像 tag、OCI labels、runtime annotation 和 Argo CD desired state 都必须记录同一个 source commit。 -- CI:Tekton 在目标 node k3s 内运行 lane 对应 Pipeline,由 `scripts/gitops-render.mjs` 或 node/lane control-plane 直接生成原生 task;最小校验固定为当前 lane 需要的原语,随后按 component plan 做 per-service BuildKit publish 与 GitOps promote;没有 `CI.json` runner、DIND 单任务发布或 Docker fallback。 -- Artifact:镜像使用 commit tag,例如 `/hwlab-cloud-api:`;digest 由 registry 返回,CI report 只作为审计证据,不作为 CD 真相。发布态 artifact catalog 由 Tekton 写入当前 lane 的 GitOps branch。 -- Branch split:source branch 只保存人写源码、声明和 seed contract;GitOps branch 是 Tekton promotion 写入的生成分支,保存 artifact catalog 与 `deploy/gitops/node/**` desired state。CI/CD 不再把 catalog promotion commit 写回 source branch。 -- v0.2 扩容线:G14 v0.2 的固定 workspace、CI/CD source repo、runtime namespace 和 GitOps branch 只适用于当前任务明确选择 G14 v0.2 时;详细规格见 [spec-v02-cicd.md](spec-v02-cicd.md)。不得把 G14 v0.2 默认带入 D601 v0.3 或其他 lane。 -- CD:Argo CD 只消费当前 node/lane Git desired state,不重新构建镜像,不读取其他 node 状态,不获取 legacy DEV CD Lease。 -- FRP:公网暴露端口和 HTTPS host 必须由当前 node/lane control-plane status 或 lane 配置确认。G14 DEV/PROD、G14 v0.2 和 D601 v0.3 的入口都是示例实例,不得互相替代验收证据。 -- 并行性:不同 source commit 的 CI build 不共享发布锁;并行安全由 immutable commit tag/digest 和 Git desired state 保证。最终运行版本由 Argo CD 当前同步的 Git revision 决定。 +- [PJ2026-0106 平台运维](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-0106-platform-ops.md) +- [PJ2026-010601 发布流水](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010601-controlled-release.md) +- [PJ2026-010602 源码同步](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010602-source-sync.md) +- [PJ2026-010603 YAML运维](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010603-yaml-first-ops.md) +- [PJ2026-010604 公开入口](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010604-public-entry.md) +- [PJ2026-010605 运维监控](https://github.com/pikasTech/unidesk/blob/master/project-management/PJ2026-01/specs/PJ2026-010605-observability-monitoring.md) -## 门禁最小化与扩容治理 - -不要滑向不必要的复杂门禁是 HWLAB node/lane CI/CD 和 lane 扩容的通用原则。架构迁移、分支扩容和运行面治理应优先靠固定边界、清晰命名、唯一真相源、标准入口和长期参考文档收敛;不要把每个设计约定、运行策略、观测项或回滚手册都做成新的 preflight、guard、gate 或报告生成器。 - -旧 DEV/D601/main 门禁如果阻碍当前 node/lane 路径,默认处理是从当前调用链删除,而不是做兼容性迁移、fallback、legacy mode、双路径绕行或在旧门禁上叠加例外。新增门禁只能覆盖明确高价值风险,且必须最小、低噪声、容易删除;资源配额、RBAC 命名、清理策略、回滚顺序、人工同步策略等默认是设计约定或 runbook,不是 CI/CD 通过条件。 - -`v0.2` 的硬边界只包括:source branch 必须是 `v0.2`,CI/CD source repo 必须是 `/root/hwlab-v02-cicd.git`,GitOps branch 必须是 `v0.2-gitops`,Git mirror/relay 必须来自 `devops-infra`,runtime namespace 必须是 `hwlab-v02`,runtime path 必须是 `deploy/gitops/node/runtime-v02`,Argo Application 必须指向 `v0.2` GitOps lane,公网入口只能是 `19666/19667`,`v0.2` source branch 不跟踪生成物,旧 DEV/D601/main 门禁不进入 `v0.2` 调用链。其他事项先写成决策表或 runbook;只有被证明无法靠上述边界和标准入口自然收敛时,才允许新增最小检查。 - -## 生成入口 - -`scripts/gitops-render.mjs` 是 node/lane GitOps 转换器;G14 相关默认只在目标 lane 明确选择 G14 时使用: - -- 架构迁移时,过时的自检、预检、guard、gate 优先删除,不在旧门禁上叠加例外或复杂度;新门禁只允许覆盖明确高价值风险,必须保持最小、低噪声、易迁移。 - -- 直接声明 Tekton Pipeline、最小原语校验 task 和 PipelineRun 样板;不再读取 `CI.json` 或生成 `ci-json` step。 -- 读取 `deploy/deploy.yaml` 与 `deploy/k8s/*`,生成 Argo CD 可消费的目标 node/lane runtime Kustomize path。 -- Tekton 的镜像构建发布入口必须是 `scripts/artifact-publish.mjs`;它只是集群内 Task 的 build/push helper,不做 rollout、不写其他 node、不获取 legacy DEV CD Lease。旧 `scripts/dev-artifact-publish.mjs` 入口已删除;`dev-cd-apply`、`ci-publish` 和旧 `main` JS CD 入口禁止出现在当前 node/lane Pipeline 生成脚本和验收证据中。 -- `node-contract-check` 在 fresh source clone 内取当前 `HEAD`,把 GitOps 产物渲染到 `mktemp -d` 临时目录,并立刻用同一个 `--source-revision` 执行 `--check`;它校验 render 代码、原生 Tekton 产物生成合同和 forbidden-fragment 护栏,不依赖 source branch 预先存在 `deploy/gitops/node/source.json`。面向已发布 runtime 的 `source.json` 只存在于 `G14-gitops` 生成分支,作为 promotion evidence。 -- 生成 `hwlab-node-branch-poller` CronJob:它使用 G14 集群内的 Git SSH Secret 轮询 `G14` 分支,按 source commit 创建确定命名的 Tekton PipelineRun。 -- 生成 node/lane control-plane reconciler:它使用对应 Git SSH Secret 轮询目标 source branch,运行 repo 内 `scripts/gitops-render.mjs`,并 server-side apply 生成的 Tekton RBAC、Pipeline、Poller 和 Reconciler manifests;因此 CI 控制面变化应自动进入目标 node k3s,不需要人工长期执行 render/apply。 -- 默认输出到 `deploy/gitops/node/`。 -- GitOps 生成分支由当前 node/lane 配置决定;Pipeline 成功后把本次 source commit 对应的 artifact catalog 与 `deploy/gitops/node/**` 推送到该 lane 的 GitOps 分支,避免把生成提交继续写回 source branch。 -- `v0.2` GitOps lane 必须使用独立生成身份,例如 `v0.2-gitops`、`deploy/artifact-catalog.v02.json` 和 `deploy/gitops/node/runtime-v02`,并由独立 Argo CD Application 指向 `hwlab-v02`。若后续实现选择复用某个脚本入口,也必须通过显式参数区分 source branch、catalog、runtime path、Application 和 namespace,不能靠修改默认值让 `G14` DEV/PROD 行为漂移。 -- Registry prefix 由当前 node/lane 配置决定;G14 单节点 k3s 的 node-local registry 示例是 `127.0.0.1:5000/hwlab`。 -- CI/CD proxy 由当前 node bootstrap 和 lane 配置决定;G14 本机示例是 `http://127.0.0.1:10808` / `socks5h://127.0.0.1:10808`。Tekton CI step、BuildKit sidecar 和 publish step 都注入 proxy/no_proxy;服务镜像构建只允许通过 Pod 内 BuildKit Unix socket 直接 push 到目标 registry,不能回退到 Docker daemon、DIND 或 host Docker。 -- `prepare-source` 和最小原语校验 task 不允许每次运行时重新 `apk add`、`apt-get install` 或临时下载 browser/runtime 依赖。工具镜像由当前 node/lane 配置解析,G14 示例为 `127.0.0.1:5000/hwlab/hwlab-ci-node-tools:node22-alpine-bun-v1`。镜像内容由 `deploy/ci/hwlab-ci-node-tools.Dockerfile` 声明;脚本启动时必须输出工具与 proxy preflight 结构化日志。缺少工具时应先在目标 node 构建并推送新的工具镜像,再修改 `HWLAB_NODE_CI_TOOLS_IMAGE`/render 默认值,不能回退到 runtime 安装。 -- 目标 node host 只用于 source workspace、GitOps render、k3s 控制和轻量语法/静态合同检查;不要把 host 当成浏览器执行面。低频 browser smoke 已不再属于默认 primitive CI。若确实需要一次性布局、移动端或交互验证,必须显式在目标 node/k3s/Tekton 的专用 Playwright 镜像或 UniDesk `trans playwright` 透传内运行,不能回退成 host 上强装 browser 的长期方案。 -- Poller、control-plane reconciler、image publish 和 GitOps promote step 都不允许每次运行时 `apk add` / `apt-get install`。当前 node/lane 固定工具镜像必须来自配置,生成的脚本只做 proxy preflight 与工具存在性检查。若需要升级工具,先在目标 node 构建/推送新的工具镜像,再修改 `HWLAB_NODE_CI_TOOLS_IMAGE`/render 默认值并由 reconciler apply。 -- 服务镜像构建的默认 parent/base image 不得从 Docker Hub 反复拉取。parent/base image 必须镜像到目标 node/lane registry 并由配置引用;G14 示例为 `127.0.0.1:5000/hwlab/hwlab-node20-base:20-bookworm-slim`。需要升级 parent image 时,先通过目标 node proxy 拉取并推送到目标 registry,再修改 `HWLAB_NODE_DEV_BASE_IMAGE`/render 默认值;image publish step 只允许从本地 registry pull base image,且 tag 必须符合 publish gate 的 allowlist。 -- 任何依赖下载阶段都必须有可观测诊断。生成的 Tekton 脚本在 npm、BuildKit base image/local registry probe 和 GitOps promote 之前输出结构化 `dependency-proxy-probe`、`dependency-curl-probe` 或 `dependency-download-*` 日志,至少包含 phase、目标 URL/镜像、脱敏 proxy、首包耗时、总耗时、下载字节数和速度。CI/CD 卡在下载时,先用这些日志判断是 proxy 不可达、目标源慢、DNS/首包慢还是下载吞吐低,再决定是否切换 G14 代理节点或预热镜像;不能只凭 PipelineRun Running 时长判断业务测试失败。 - -常用命令: - -```sh -npm run gitops:render -- --source-revision -``` - -人工 source workspace 不再对 `deploy/gitops/node/**` 做生成物对比;这些文件在 source 分支下是忽略的生成物,旧文件和 `source.json` 不是真相。需要看渲染计划时使用 `npm run gitops:render -- --no-write`;正式发布态只看 `G14-gitops`、Argo Application 和 live runtime。 - -## 原生 k8s Tekton + Argo 配置面 vs 已废弃的 CI.json runner - -当前 G14 已完全删除 `CI.json` 和 `ci-json` step。下面的对比只保留为迁移理由:Tekton + Argo 是唯一发布控制面;repo-local 校验已经收敛为 render 内建的少量原语 task,而不是再保留一条 shell runner 路线。 - -| 维度 | 原生 k8s Tekton + Argo 配置面 | 已废弃的 `CI.json` runner 路线 | -| --- | --- | --- | -| 权威职责 | 构建、发布、GitOps promotion、Argo sync、runtime rollout | repo-local 静态合同、schema、focused smoke、预检命令 | -| 真相来源 | PipelineRun、TaskRun result、`G14-gitops` revision、Argo Application、live workload | 仓库内 `CI.json` 命令、runner 镜像、单个 `ci-json` TaskRun 日志 | -| 优点 | 控制面声明式、k8s 可观测、并行 fan-out、TaskRun result 可复用、CD 与 runtime 验收边界清楚 | 改 repo 内检查成本低、命令贴近源码、适合 source-only 合同和 focused preflight、无需每加一条检查就手写一套新 Tekton Task | -| 缺点 | render/generated/cluster 模板三层更复杂,控制面改动要等 reconciler apply 后才能验证,source 与 generated 漂移会制造噪声 | shell 包装、命令链和日志语义更脆弱;多个检查挤在一个 step 内时失败隔离差,天然不提供 GitOps desired state、Argo rollout 或 live runtime 证据 | -| 适用场景 | 需要发布真相、并发构建、artifact identity、GitOps promotion、CD rollout、live runtime 判定 | 需要 repo-local 源码检查、静态合同、快速 smoke、focused preflight,但不需要声明 runtime 期望状态 | -| 不该承担的职责 | 不应回退成 D601 legacy JS CD 或 target-side build | 不应被提升为独立 CD 路线,也不应用来替代 Argo sync、live workload ready 或公网 health | - -选择规则: - -- 只要问题涉及 release truth、rollout、runtime desired state、namespace workload 健康、public health 或 artifact provenance,就必须回到 Tekton + Argo 配置面。 -- 只要问题仍停留在 repo-local 静态合同或 focused preflight,就把它实现成独立的原语 Tekton task;不值得长期保留的检查直接删除,而不是重新引入 `CI.json` runner。 -- 不要再创建第二套 shell 命令发布面;如果一项检查开始依赖 rollout 顺序、TaskRun results、GitOps branch、Argo revision 或 live runtime,它就必须属于 Tekton/Argo 标准路径。 - -## Monorepo 组件计划与兼容 render - -HWLAB 是 monorepo,G14 CI/CD 加速必须按组件输入判断构建和滚动;v0.2 env-reuse 的组件边界与环境配方直接来自 `deploy/deploy.yaml`,运行态镜像身份来自 per-service artifact catalog;`CI.json` 已删除,不再作为任何 planner 输入。 - -- `deploy/deploy.yaml` 是当前 v0.2 人写 deploy/runtime 配置单一出处;`deploy/deploy.json` 不得作为 v0.2 兼容源恢复。配置读写由 `scripts/src/structured-config.mjs` 和 `scripts/src/deploy-config.mjs` 统一承载,只有该格式无关层直接处理 YAML/JSON 解析;planner、renderer、smoke、artifact helper 和 CLI 只调用读写 helper。 -- `scripts/ci-plan.mjs` 是只读 planner,默认读取当前 workspace 的 `deploy/deploy.yaml`、lane artifact catalog,以及 `deploy/deploy.yaml` 内的 lane service declarations/env recipe,输出 `affectedServices`、`reusedServices`、`componentCommitId`、`componentInputHash`、`dockerfileHash`、`baseImageDigest`、`buildArgsHash` 和原因;它不得修改 deploy、catalog 或 GitOps 文件。Tekton `prepare-source` 会先从当前 lane GitOps branch 注入上一轮发布态 catalog,source 分支里的 catalog 只作为 seed contract。 -- v0.2 服务清单来自显式 `--services` 或 `deploy.lanes.v02.envReuseServices`;旧 `deploy.services[]`、`deploy.k3s.serviceMappings[]` 和 `internal/protocol.SERVICE_IDS` 推导路径不再作为 planner 输入。 -- v0.2 env-reuse 组件边界和环境镜像配方以 `deploy/deploy.yaml` 的 `lanes.v02.serviceDeclarations`、`lanes.v02.envRecipe` 和 `lanes.v02.bootConfig` 为单一配置点;新增服务或调整 `componentPaths`、`runtimeKind`、`entrypoint`、Bun 版本、系统包、launcher 路径和 HWPOD alias 时先改 deploy 配置与 schema/测试,不再把这些属性硬编码进 planner 或 artifact publish helper。 -- `hwpod` 是 runner 内的稳定 HWPOD task 入口,由 `tools/hwpod-cli.ts`、`tools/hwpod-compiler-cli.ts`、`tools/hwpod-ctl.ts`、`tools/hwpod-node.ts` 和 `skills/hwpod-cli/`、`skills/hwpod-ctl/` 组成。修改这些路径时,G14/v0.2 CI 必须至少触发携带 `/usr/local/bin/hwpod` 的 runtime skills/env-reuse 重新装配或 rollout,不能全量复用旧 artifact 后只报告 PipelineRun 成功。 -- `scripts/artifact-publish.mjs` 默认启用组件级 lazy build:先运行 planner,再只构建/推送 `affectedServices`,`reusedServices` 从 `deploy/artifact-catalog.dev.json` 或 lane catalog 复用已有 sha256 digest。非 env-reuse 服务复用前必须满足 artifact provenance 自证:catalog 有可验证 digest、catalog 的 `sourceCommitId` 在当前 repo 可解析、用该 `sourceCommitId` 的 source tree 重新计算出的 `componentInputHash` 等于 catalog 记录、该 hash 再等于本轮 planner 计算值,且 `dockerfileHash`/`buildArgsHash` 没有不一致。catalog 缺 digest、缺 provenance、source tree 无法解析、catalog hash 与 catalog source tree 不一致、或 catalog hash 与本轮 input 不一致时,planner 必须把该服务列为 affected 并重新发布,不能用旧 guard 阻塞,也不能退回 Docker 或 legacy full-build 路线。 -- Artifact catalog 的 per-service provenance 是镜像 digest 的身份证明,不是本轮 planner 状态缓存。reuse 路径只能保留旧 artifact 自身的 `sourceCommitId`、`componentCommitId`、`componentInputHash`、`dockerfileHash`、`baseImage*` 和 `buildArgsHash`;禁止把当前 planner 的 component/build 元数据写入复用的旧 digest,否则下一轮 planner 会把旧镜像误判成已包含新输入,造成 CI/CD false-green。 -- `scripts/artifact-publish.mjs` 的 publish report 必须携带 planner 的 per-service 元数据;`scripts/refresh-artifact-catalog.mjs` 默认只预览,只有当前 lane Tekton promotion 显式传 `--write` 时,才把生成的 `commitId`、`image`、`imageTag`、`digest`、`publishState` 和 component provenance 字段写进当前 lane artifact catalog,随后只提交到当前 lane GitOps branch。`deploy/deploy.yaml` 是人写的 runtime config 真相源,不得被 promotion、refresh 脚本或人工发布流程回写镜像身份字段。 -- `scripts/gitops-render.mjs` 只支持混合 desired state:workload 的 container image、`HWLAB_IMAGE`、`HWLAB_IMAGE_TAG` 和 pod template `source-commit` 来自 `deploy/artifact-catalog.dev.json` 的 per-service artifact identity;普通 env、replica、healthPath、profile 等配置来自 `deploy/deploy.yaml`。全局 GitOps metadata 仍记录本次 source commit。`--legacy-source-images` 与 `HWLAB_NODE_USE_DEPLOY_IMAGES=0` 已废弃,不得把所有 workload image 回退渲染为同一个 source commit tag。 -- 当前 lane Tekton promotion 在推送 GitOps branch 前,必须用 publish report 显式 `--write` 刷新 lane artifact catalog,然后把刷新后的 catalog 和 rendered GitOps desired state 一起提交到当前 lane GitOps branch。promotion 不得自动修改或推送 source branch,也不得自动修改 `deploy/deploy.yaml` 或 `deploy/k8s/base/workloads.yaml`,这样人写配置不会和 CI 生成身份反复冲突。 -- Tekton 并发化只能以 planner 输出作为输入;每个 service 都有独立 TaskRun,changed service 启动 BuildKit,unchanged service 只写 reuse result 并复用 catalog digest,且不能改 pod template,避免无意义 rollout。没有完整 per-service desired state 证据时,必须修复 planner/catalog 证据,不能使用 `--full-build`、`--legacy-source-images`、DIND 或 Docker fallback 回退。 - -## 加速判定与当前瓶颈 - -G14 CI/CD 加速的第一判定标准不是 PipelineRun 总耗时单点变短,而是 monorepo 组件粒度的“少构建、少滚动、可并发”是否成立。 - -- 触发延迟:`hwlab-node-branch-poller` 固定每 1 分钟轮询 `G14`。相对 5 分钟轮询,平均触发等待应从约 2.5 分钟降到约 0.5 分钟,最坏等待从 5 分钟降到 1 分钟。发现 `kubectl -n hwlab-ci get cronjob hwlab-node-branch-poller -o jsonpath='{.spec.schedule}'` 不是 `* * * * *` 时,应先修 poller/reconciler,而不是手工长期创建 PipelineRun。 -- 组件懒构建:docs-only、GitOps-only、poller/reconciler manifest-only 等不影响服务输入的变更,planner 应输出 `affectedServices=[]`、`buildSkippedCount=<全部服务数>`,各 service TaskRun 应写出 `status=reused` 和 `build-backend=reused-catalog`。这类变更不应重新构建任何服务镜像,也不应把 workload image 改成当前 source commit tag。 -- 并发 fan-out:per-service TaskRun 应由 Tekton/k8s scheduler 同时调度,多个 service 的 build/reuse 窗口应接近“最慢单个服务任务耗时”,而不是所有服务串行相加。reuse-only 场景的 fan-out 窗口当前基线约为十几秒;真实组件构建场景仍需按 changed service 单独记录 BuildKit 耗时和 cache hit 情况。 -- CD rollout:unchanged service 必须复用 `deploy/artifact-catalog.dev.json` 的 image/digest,pod template 不应因全局 source commit 改变而无意义滚动。手写 manifest(例如 `deepseek-proxy`、device-agent 类辅助 workload)只要复用某个已发布服务镜像,也必须走同一个 catalog image 选择逻辑,不能直接用当前 source commit tag。 -- 运行态验证:GitOps promote 成功只说明 `G14-gitops` 分支更新;最终通过必须看 Argo Application revision、sync 状态、目标 namespace Deployment/StatefulSet ready、公网 health。Argo 还停在旧 revision 时,优先做 `argocd.argoproj.io/refresh=hard` 刷新;不要把已经推送的 `G14-gitops` 分支误判成运行面已滚动。 -- Argo health 判定:v0.2 不再生成 HWLAB 自有 agent worker Job template;AgentRun v0.1 作为外部共享执行基础设施接入。`hwlab-cli` 不创建镜像、Service 或 Job template,只在固定 repo 内短连接执行。真正发布验收仍以长驻 workload ready、公网 health 和失败 Pod 清单为准。 - -当前仍然慢的主要位置: - -- `prepare-source` 与最小原语校验 task 仍是前段主要开销。它们包含 Git clone、checkout、必要的 `npm ci`、`repo-reports-guard`、`node-contract-check` 和 `codex-api-forwarder-check`。继续加速应优先减少 workspace cold start 与依赖安装成本,而不是重新塞回一条 shell runner。 -- `gitops-promote` 仍是大头,当前量级约 100 秒。它包含 source branch freshness check、artifact catalog refresh、render、clone `G14-gitops`、复制 catalog 与 generated desired state、commit 和 push。继续加速应优先减少 git clone/push 成本,例如使用浅 clone、持久 workspace、server-side patch 或把 GitOps repo 操作单独缓存。 -- per-service TaskRun 数量增加后会有 k8s 调度和 sidecar 生命周期开销。reuse-only 任务很快,但如果每个 unchanged service 都启动完整 buildkit sidecar,调度开销会抵消部分收益;长期目标是让 unchanged service 走更轻量的 reuse Task,changed service 才启动 BuildKit。 -- per-service BuildKit 必须使用 Pod 内 Unix socket 或其他 Pod-scoped 端点,禁止在 hostNetwork 下绑定固定 TCP 端口。多个 service TaskRun 并发时,如果 sidecar 统一监听 `0.0.0.0:1234`,会抢同一个宿主端口,导致主 step 结果成功但 Pod phase 显示 Failed,严重污染 CI 观测。 -- Argo sync/health 不是 instant。`Sync=Synced` 后 health 仍可能因为 replicas=0 的模板 Deployment、未排除 health 的模板 Job 或 StatefulSet 旧 revision 显示 `Suspended`/`Progressing`。这时应先看实际长驻 workload ready 与具体 unhealthy resource,不要只看 Application 总 health;如果 suspended Job 只是模板资源,应修 render 注解而不是把 DEV rollout 判成失败。 -- StatefulSet 旧 ordinal pod 可能长期卡在历史缺失镜像上,即使 StatefulSet 当前 template 已经修正。DEV 可按运行面热修流程删除旧 Pending pod 让 StatefulSet 按当前 template 重建;PROD namespace 需要明确 maintenance 授权后再做同类删除。 - -每次优化 CI/CD 都必须保留可比测量:记录 PipelineRun 总耗时、`prepare-source`、`repo-reports-guard`、`node-contract-check`、`codex-api-forwarder-check`、`plan-artifacts`、per-service fan-out 起止窗口、`collect-artifacts`、`gitops-promote`、Argo sync 到 workload ready 的时间,并标明本轮是 reuse-only、单组件 build 还是多组件 build。没有这些分段数据,不要只用“感觉变快/变慢”判断优化成败。 - - -## Code Agent Provider Profiles - -G14/v0.2 Code Agent 执行委托给 AgentRun `v0.1`。Per-profile config、credential、dynamic slug 和 validate 的唯一管理规格见 [spec-v02-provider-management.md](spec-v02-provider-management.md);session dispatch 与 nested child `spawn` env-only 继承规则见 [agentrun-code-agent-dispatch.md](agentrun-code-agent-dispatch.md)。GitOps 只管理共享运行面、bridge/forwarder、NO_PROXY、SecretRef 约定和镜像;新增或调整普通 provider profile slug 不应为了静态 allowlist 修改 Cloud API/Web 服务代码,也不应因此单独触发 CI/CD。 - -当前 profile 示例不是静态枚举:`deepseek` 通过集群内 DeepSeek Responses bridge/Moon Bridge,`dsflash-go` 等动态 slug 由 AgentRun profile config/SecretRef 承接,`codex-api` 使用同 Pod loopback forwarder 直连 hyueapi,`minimax-m3` 由 AgentRun `backendProfile=minimax-m3` 承接。HWLAB 对外的 conversation/session/thread 合同不随 AgentRun backend 切换而改变;adapter 内部传给 AgentRun 的 `sessionRef.sessionId` 必须按 `backendProfile` 分域,`accessController` 持久化记录仍以 HWLAB 原始 session 归属为准,嵌套 `agentRun.sessionId` 保存 AgentRun scoped sessionRef。G14 cloud-api 的 `NO_PROXY/no_proxy` 必须包含 `hyueapi.com` 和 `.hyueapi.com`;`codex-api` 的 hyueapi upstream 由同 Pod loopback forwarder 直连,不能被 proxy 注入污染。 - -当前 node/lane 的 `codex-api` 不得把 `http://172.26.26.227:17680/v1/responses` 作为默认 base URL;该地址只保留为旧 D601 Code Queue runner 或历史 egress 对照线索。`codex-api` 应先进入同 Pod `127.0.0.1` loopback forwarder,再由 forwarder 直连 `hyueapi.com` / `.hyueapi.com`;这两个域名必须同时进入 `NO_PROXY` 和 `no_proxy`。DeepSeek profile 可以通过集群内 bridge/Moon Bridge 转换,`codex-api` 不能用 DeepSeek bridge 伪装通过,也不能因为默认 profile 切到 DeepSeek 而删除或覆盖 `codex-api` 的独立模型、base URL、auth 和最小闭环验证。 - -共享 bridge/forwarder/runtime 变更必须按 [Code Agent Chat Readiness Runbook](code-agent-chat-readiness.md) 的分层方法先做目标 pod 最小闭环。普通 AgentRun profile config/credential/validate 走 [spec-v02-provider-management.md](spec-v02-provider-management.md),不通过 GitOps render 或服务发布试错。裸 HTTP/SSE 请求通过只能证明 upstream、认证和模型可用;没有 AgentRun command result `completed` + 非空 reply 前,不得把 Workbench 状态标成 DEV-LIVE reply pass。 - -Codex app-server 当前要求 provider `wire_api="responses"`,不得把 DeepSeek profile 切到旧 `chat` wire API。DeepSeek profile 的真实 Responses 转换层固定使用 Moon Bridge;不要在 HWLAB 里手写完整 Responses-to-Chat/Anthropic 转换器,因为这会破坏 Moon Bridge 对 prompt cache、tool-result 顺序和模型目录的成熟处理。Codex 发往 `/v1/responses` 的请求体可能带 `Content-Encoding: zstd`,而 Moon Bridge 不负责解压 Codex zstd body。因此 GitOps 中的 `hwlab-deepseek-proxy` Pod 必须包含 repo-owned `hwlab-deepseek-responses-bridge` sidecar:Service 端口 4000 指向 bridge,bridge 只做 zstd request body 解压、删除 `Content-Encoding`/重写 `Content-Length`、丢弃非 `function` tool 类型和 Codex-style `GET /v1/models` 目录适配,再把请求转发给 4001 的 Moon Bridge。DeepSeek API 只接受 `function` tools,bridge 必须在转发前丢弃 Codex Responses 请求里的非 `function` tool 类型(例如 `web_search`、`image_generation`),但不得移除 shell/apply-patch 等 function tools。模型、cache、tool 调用顺序、密钥和真实推理仍由 Moon Bridge 管理;bridge 不新增业务 gate,也不得把兼容失败伪装成 SOURCE/legacy blocker。 - -DeepSeek proxy manifest 是 GitOps desired state 的一部分,并生成在当前 lane runtime path。Moon Bridge 镜像由 `deploy/moonbridge/Dockerfile` 从上游 `ZhiYi-R/moon-bridge` 固定 commit 构建,镜像 registry 由当前 node/lane 配置解析;GitHub、Google 或 Docker base image 下载必须优先使用目标节点本地 proxy。DeepSeek key 仍通过 `hwlab-code-agent-provider/openai-api-key` Secret 注入到 init container 并写入 Pod 内 `emptyDir` 配置文件;ConfigMap、文档、trace、health、issue 和日志不得打印 Secret 值。 - -## Polling 触发 - -G14 不要求 GitHub webhook 或 GitHub Actions 配置。`hwlab-ci/hwlab-node-branch-poller` CronJob 每 1 分钟通过 Git SSH 拉取 `G14` HEAD,并用 source commit 的前 12 位生成 PipelineRun 名称 `hwlab-node-ci-poll-`。 - -`v0.2` 接入不再新增 HWLAB 发布触发 CronJob;标准入口是 UniDesk CLI `bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm`,由该入口自动 fetch `/root/hwlab-v02-cicd.git`、解析当前 `origin/v0.2` HEAD,并直接创建可区分的 commit-pinned PipelineRun,例如 `hwlab-v02-ci-poll-`。该 lane 的 GitOps promotion 只允许写入 `v0.2` 专属 catalog、runtime path 和 GitOps branch;不得向 `G14` 或现有 DEV/PROD runtime path 写入生成物,也不得从 `/root/hwlab-v02` 工作树状态选择待发布 commit。 - -G14 lane 中如果同名 PipelineRun 已存在,poller 直接跳过;如果不存在,则创建新的 PipelineRun。这样可以用 Kubernetes 原生 CronJob、ServiceAccount、RBAC 和 Tekton API 实现无 GitHub webhook 的分支监控,同时避免同一个 commit 被反复派单。历史上的 `chore: promote G14 GitOps source ...` source 分支生成提交已经废弃;G14 poller 只应该看到人写 source commit。 - -Pipeline 的标准路径是:`G14` source commit -> Tekton 原语校验 task -> commit-tagged image push 到 G14 registry -> refresh artifact catalog -> render `deploy/gitops/node/**` -> push catalog 与 GitOps desired state 到 `G14-gitops` -> Argo CD 同步 runtime。CD 只消费已经构建好的镜像和 Git desired state,不在 Argo CD 内构建镜像。 - -GitOps promotion 成功只证明 `G14-gitops` 分支已经写入新 desired state;如果 render 改变了 Argo Application、AppProject、runtime path 或 DEV/PROD 拆分目录,必须同步检查并应用 `deploy/gitops/node/argocd/project.yaml`、`application-dev.yaml` 和 `application-prod.yaml`。`hwlab-node-dev` 必须指向 `deploy/gitops/node/runtime-dev`,`hwlab-node-prod` 必须指向 `deploy/gitops/node/runtime-prod`;如果集群里 Application 仍指向旧 `deploy/gitops/node/runtime`,Argo 会停在旧 revision,即使 CI/publish/promote 全部成功也不会滚动新镜像。 - -观察 PipelineRun、Argo 和 rollout 时使用短连接轮询:一次 `kubectl get` 或有限 `logs --tail` 后返回,由指挥侧间隔重试。不要用长时间 `kubectl wait --timeout=900s` 占住 `tran G14:k3s` 透传锁;如果误用长 wait,只能杀掉本地等待客户端并清理 stale tran lock,不能把这个等待过程当成 CD 失败。 - -下载阶段排障命令: - -```sh -KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-ci logs pod/ --all-containers --tail=400 \ - | grep -E 'dependency-(proxy|curl|download)' -``` - -如果 probe 显示 `proxy-env-missing`、`proxy-connect-failed`、`timeout` 或速度长期接近 0,应先按 `/root/docs/vpn-proxy-ops.md` 检查 v2rayN/Hysteria,再重跑 polling。若 probe 正常但后续校验失败,按对应 Tekton task 日志和业务检查排障。 - -手动 render/apply 只允许作为 bootstrap 或 reconciler 故障抢修;正常路径必须由 `hwlab-node-control-plane-reconciler` 自动完成 CI 控制面 manifest 更新。 - -修改 `scripts/gitops-render.mjs`、Tekton Pipeline、RBAC、poller 或 reconciler 这类 CI 控制面后,不能立刻用旧集群 PipelineRun 作为新模板验证。必须先确认 `hwlab-node-control-plane-reconciler` 已完成并且集群内 Pipeline manifest 包含新字段,再触发手动 poller 或等待下一轮 source commit;否则 PipelineRun 会在旧 Pipeline 下创建,容易把已经修复的 sidecar、proxy 或 TaskRun 行为误判为仍然失败。 - -## 集群资源 - -- `hwlab-ci`:registry、Tekton runner RBAC、Polling CronJob、Pipeline/PipelineRun 所在 namespace。 -- `hwlab-ci/hwlab-node-control-plane-reconciler`:自动 render/apply G14 CI 控制面 manifest 的 CronJob。 -- `argocd`:Argo CD 控制面和 `hwlab-node-dev` / `hwlab-node-prod` Application 所在 namespace。 -- `hwlab-dev`:HWLAB DEV runtime namespace,由 Argo CD 应用 `deploy/gitops/node/runtime-dev`。 -- `hwlab-prod`:HWLAB PROD runtime namespace,由 Argo CD 应用 `deploy/gitops/node/runtime-prod`;通过 `hwlab-node-prod-frpc` 映射到 `18666/18667`,正式验收必须同时检查 Argo sync、Deployment ready、FRP public health 与 source commit。 -- `hwlab-v02`:HWLAB `v0.2` runtime namespace,只能由 `v0.2` 专属 Argo CD Application 和 GitOps runtime path 管理;规划通过独立 frpc 映射到 `19666/19667`。创建 `hwlab-v02` 不得删除、重命名或改写 `hwlab-dev`/`hwlab-prod`。 - -G14 registry 由 Kubernetes Deployment `hwlab-ci/hwlab-registry` 承载,使用 host network 暴露 `127.0.0.1:5000` 给 k3s/containerd 和 host-network Tekton build pod。旧 host Docker registry 不能与该 Deployment 同时占用 5000 端口。 - -G14 k3s/containerd 的 Pod 镜像拉取也必须长期使用 G14 本机代理。主机配置记录在 `/root/docs/kubernetes-ops.md`,当前 systemd env 文件是 `/etc/systemd/system/k3s.service.env`。修改代理后需要 `systemctl daemon-reload && systemctl restart k3s`,并确认 `k3s-server` 进程环境中存在 `HTTP_PROXY` / `NO_PROXY`。 - -## 凭证边界 - -HWLAB repo 是私有仓库时,Tekton 和 Argo CD 需要各自的 Git SSH Secret。Secret 只能从 G14 本机已有 SSH key 创建,不能写入 Git,不能打印 key 内容。 - -Tekton 约定 Secret 名称:`hwlab-ci/hwlab-git-ssh`。 - -Argo CD 约定 repository Secret:`argocd/hwlab-git-ssh`,并带 label `argocd.argoproj.io/secret-type=repository`。 - -## D601 边界 - -G14 GitOps manifests 不包含 D601 kubeconfig、D601 node guard、D601 FRP 公网入口或 UniDesk Code Queue 调度入口。D601 仍由既有生产路径维护;G14 GitOps 的安装、PipelineRun、Argo sync 和 registry 操作都不能对 D601 执行 kubectl、docker 或流量切换动作。 - -## 真相源与常见误判 - -G14 PR、CI、CD 的判断应按以下顺序收敛真相,越靠前越接近最终运行面: - -1. live runtime:目标 namespace 的 Deployment/StatefulSet template、Pod ready、`describe`、容器日志和公网 health。 -2. Argo desired state:`hwlab-node-dev` / `hwlab-node-prod` 的 Application revision、sync、health 和实际 runtime path;`v0.2` 接入后还要看 `hwlab-node-v02` 或等价专属 Application 是否指向 `v0.2` GitOps lane 和 `hwlab-v02`。 -3. Tekton 执行证据:branch-poller 日志、PipelineRun、TaskRun results、`gitops-promote` 终态。 -4. 干净 source workspace:`origin/G14` 当前内容,以及 `npm run gitops:render -- --no-write` 和 planner 输出。 -5. 对照线索:旧 commit 记忆、坏 worktree、D601 legacy 路径、脚本旧默认值,只能当线索,不能当真相。 - -常见误判与纠正: - -- 不要把 `/root/hwlab` 当前 checkout、任意 `/tmp` worktree 或带 conflict marker 的目录当 source truth;只有跟踪 `origin/G14` 的干净 worktree 才能作为当前发布依据。 -- 不要按“某个预期 commit 是否出现在 ancestry 中”判断功能是否已经合入;当前 `origin/G14` 实际内容比历史 commit 轨迹更重要。 -- 改了 source 但没有触发 Tekton promotion 时,`G14-gitops` 仍停在旧 generated state 是正常现象,不等于 Tekton 或 Argo 本身坏掉。 -- 不要把 `build-*` TaskRun 名称直接当作镜像重建证据;reuse-only 变更也会扇出同名 TaskRun,必须看 Tekton result 的 `status=reused` 与 `build-backend=reused-catalog`。 -- 不要把 `G14-gitops` 分支已更新误判成 DEV 或 PROD 已滚动;只有 Argo Application revision、目标 workload ready 和 live manifest 生效,才算 CD 真实通过。 -- 不要把 health payload 中的镜像 commit 当成 runtime manifest commit;runtime-only 修复可能复用旧镜像,只改变 probe、env、annotation 或 sidecar 行为。 -- sidecar 监听 `127.0.0.1` 时,Pod-IP `httpGet` probe 失败不等于 sidecar 自身 crash;必须同时对照 sidecar listen 日志和 probe target 语义。 -- 真实 live smoke 超时要先排除脚本入口和 timeout 误报;健康的 Codex stdio 冷启动首 token 可能需要数十秒,10 秒级 transport timeout 不能直接判服务故障。 - -- 不要重新引入把多条检查挤成顶层 shell 链的 runner。旧 `CI.json` 的 `a && b && c` 一旦直接内联到顶层 shell,就会出现前半失败但 TaskRun 继续成功的假绿;原语化 CI 的原则是每个检查保持独立 task/result,失败语义直接由 Tekton 负责。 - -## PR -> CI -> CD 最短零误判 SOP - -1. 工作区与路由预检 - -```sh -bun scripts/cli.ts ssh G14:/root/hwlab shell 'git status --short --branch && git remote -v | sed -n "1,4p"' -``` - -- `/root/hwlab` 是固定 source workspace 和 worktree 管理入口;完成预检后,在 `/root/hwlab/.worktree/` 从最新 `origin/G14` 创建任务专属 worktree,再开始本轮代码、文档、测试和提交修改。 -- 只有独立 worktree 跟踪正确 base 且 `git status` 只包含本任务文件时才继续;不要在 `/root/hwlab` 根目录直接堆叠并行开发改动,也不要复用其他任务遗留 worktree。 -- k3s 只走 `G14:k3s`;不要混用 D601 kubeconfig、master server 执行面或旧 SSH route 语法。 - -2. Source / PR 预检 - -```sh -npm run gitops:render -- --no-write -node scripts/ci-plan.mjs --base-ref origin/G14 --target-ref HEAD --pretty -``` - -- 先看当前内容和长期参考,不按旧 commit 记忆判断“功能是否已合入”。 -- GitOps、manifest、poller/reconciler、provider profile 相关改动先跑 render no-write;planner 用于判断本轮是 docs-only、reuse-only 还是需要真实构建。不要在 source 分支对 ignored generated output 跑 drift check。 -- provider/profile 变更在进入 PR 或 CI 之前,先按 `code-agent-chat-readiness.md` 做目标 Pod 最小���环;不要把完整 CI/CD 当成 transport 试错工具。 - -3. 合并或推送到 `G14` - -- `G14` 是 poller 的唯一 source branch。只有 source 侧检查通过后,才进入 merge 或 push。 -- push 被 fast-forward 拒绝时,先 `fetch` 和 `rebase` 到最新 `origin/G14`;不要为了抢跑 poller 强推覆盖别人的 GitOps promote 提交。 - -4. 确认 CI 已接单 - -- 先看最新 branch-poller job 或日志,确认它是否识别到新的 `G14` HEAD。 -- 再看 `hwlab-ci` 里的 PipelineRun 是否出现 `hwlab-node-ci-poll-`。poller 还没创建 PipelineRun 时,不要先把问题归类为 Tekton 故障。 -- 如果本轮改的是 poller、Pipeline、RBAC、reconciler 或 render 模板,先确认 `hwlab-node-control-plane-reconciler` 已经把新控制面 apply 进去,再用新 commit 验证。 - -5. 确认 CI 真实通过 - -- 最低通过条件是:`prepare-source`、`repo-reports-guard`、`node-contract-check`、`codex-api-forwarder-check`、`plan-artifacts`、per-service fan-out、`collect-artifacts`、`gitops-promote` 全部成功。 -- `build-*` fan-out 要按 result 判断 reused 还是 rebuilt;不要只看 TaskRun 名称。 -- reuse-only 变更的目标是 `affectedServices=[]`、全部 service `status=reused`,且不触发无意义 rollout。 - -6. 确认 CD 真实通过 - -- 先确认 `G14-gitops` 头 revision 已更新,再看 Argo Application 当前 revision 是否追上该 GitOps revision。 -- 然后检查目标 namespace 的 Deployment、StatefulSet、ReplicaSet、Pod ready 和失败事件。 -- runtime-only 修复要直接检查 live Deployment template 是否带上新的 probe、env 或 annotation;不要只盯公网 health 里的镜像 commit。 - -7. 做最终运行态验证 - -- 先看公网 `/health/live`,再跑 focused live smoke;业务 smoke 必须在目标运行面已经 Healthy 后进行。 -- Code Agent 对话链路用 `node scripts/code-agent-chat-smoke.mjs --live --url --timeout-ms 45000`;通过标准是“真实目标 node/lane 路由 + `completed` + 非空 assistant reply”,不是单纯 HTTP 200、非 JSON chunk 或 10 秒内首包。 +目标 node/lane 的具体实现、PipelineRun 观察和运行命令仍按本仓 `AGENTS.md` 与受控 CLI 执行;需求边界、node/lane 规则和运维职责只更新 UniDesk OA。