# v0.2 CI/CD 规格 本文是 HWLAB `v0.2` 在 G14 上接入 CI/CD 的长期规格。目标是把 `v0.2` 作为独立加法 lane 接入现有 G14 k3s、Tekton、GitOps 和 Argo CD 体系,同时保持 `G14` DEV/PROD 发布面稳定。 实施跟踪见 [pikasTech/HWLAB#530](https://github.com/pikasTech/HWLAB/issues/530),env 容器复用、三变量启动和 git mirror 加速设计见 [pikasTech/HWLAB#572](https://github.com/pikasTech/HWLAB/issues/572)。原 `docs/plan/hwlab-v02-namespace-cicd.md` 阶段计划全文已迁入 #530 评论。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。 ## 在系统中的职责划分 `v0.2` CI/CD 是 G14 上的加法 lane:source branch、GitOps branch、runtime namespace、artifact catalog、Argo Application、Tekton Pipeline 和 FRP 入口均独立于 DEV/PROD。它共享 G14 k3s、Tekton controller、Argo CD controller、本地 registry 和构建工具,但不能复用 DEV/PROD runtime path、namespace、Application 或公网端口作为 v02 发布证据。code-only fast lane 必须消费独立 `devops-infra` 集群提供的 git mirror/relay;该 mirror/relay 是跨项目 DevOps 基础设施,不属于 `hwlab-v02` runtime namespace,也不改变当前 G14 registry 的部署位置或镜像引用真相。 ## 内部架构 CI/CD 内部由 UniDesk 手动触发入口、PipelineRun、component planner、BuildKit publish、GitOps promotion、Argo sync、GitHub flush 和公网验收构成。`v0.2` 不设置 branch poller、control-plane reconciler 或其他 CronJob;source branch 只保存源码和人写配置;`v0.2-gitops` branch 保存 catalog 和 rendered runtime desired state;live runtime 是最终通过证据。 `v0.2` 的 GitOps 写路径采用真正写 mirror:promotion 先把 `v0.2-gitops` 写入 `devops-infra` 本地 git mirror/relay,Argo CD 从本地 mirror/relay 读取该 revision 并 rollout,CI 关键路径不等待 GitHub push。GitHub `pikasTech/HWLAB` 仍是长期源码与归档上游,但对 `v0.2-gitops` 来说是由 mirror/relay 负责 flush 的异步上游,不再是 promotion task 的同步写入目标。 ## API 接口说明 | 接口 | 说明 | | --- | --- | | `scripts/g14-gitops-render.mjs --lane v02` | v02 GitOps render 入口,负责 namespace、runtime path、catalog 和 endpoint 固定。 | | Tekton `hwlab-v02-ci-image-publish` | 构建 affected images、复用 unchanged digest,并 promotion 到 `v0.2-gitops`。 | | `devops-infra` git mirror/relay | 读写 `v0.2` allowlist refs;CI 读 source/catalog、写 `v0.2-gitops`,并通过手动 CLI flush 到 GitHub。 | | Argo `argocd/hwlab-g14-v02` | 从 `devops-infra` 本地 mirror/relay 的 `v0.2-gitops:deploy/gitops/g14/runtime-v02` 同步到 `hwlab-v02`。 | | `http://74.48.78.17:19666/` | v02 Cloud Web 公网入口。 | | `http://74.48.78.17:19667/health/live` | v02 API/live 公网验收入口。 | ## 规格目标 - `v0.2` 固定作为 G14 上的新增 CI/CD lane,不改写现有 `G14` DEV/PROD lane。 - `v0.2` source branch 只保存源码、人写配置、模板、脚本和文档;CI/CD 生成物只进入 `v0.2-gitops`。 - `hwlab-v02` 是唯一 runtime namespace;`74.48.78.17:19666/19667` 是唯一公网验收入口。 - 共享 G14 k3s、Tekton controller、Argo CD controller、本地 registry、工具镜像和脚本库;隔离分支、catalog、runtime path、Application、Pipeline、ServiceAccount、SecretRef、PVC 和 FRP 入口。 - 旧 DEV/D601/main 门禁不得进入 `v0.2` 发布调用链;新增检查只覆盖固定 branch、namespace、catalog、runtime path、GitOps branch、Argo destination 和公网入口这些硬边界。 ## 固定命名 | 对象 | v0.2 规格 | | --- | --- | | Source branch | `v0.2` | | Source workspace | `G14:/root/hwlab-v02` | | GitOps branch | `v0.2-gitops` | | Artifact catalog | `v0.2-gitops:deploy/artifact-catalog.v02.json` | | Runtime path | `v0.2-gitops:deploy/gitops/g14/runtime-v02` | | Runtime namespace | `hwlab-v02` | | Tekton Pipeline | `hwlab-ci/hwlab-v02-ci-image-publish` | | Manual trigger | UniDesk CLI `bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm` | | Scheduler/CronJob | 不创建、不保留 v02 CronJob;发布只由手动 CLI 创建 commit-pinned PipelineRun | | Tekton ServiceAccount | `hwlab-ci/hwlab-v02-tekton-runner` | | PipelineRun prefix | `hwlab-v02-ci-poll-` | | Argo CD AppProject | `argocd/hwlab-v02` | | Argo CD Application | `argocd/hwlab-g14-v02` | | FRP Deployment | `hwlab-v02/hwlab-v02-frpc` | | Web entry | `http://74.48.78.17:19666/` | | API/live entry | `http://74.48.78.17:19667/health/live` | | Git mirror/relay | 独立 `devops-infra` 集群读写服务;不设 CronJob;读 source/catalog,写 `v0.2-gitops`,按需由 UniDesk CLI 手动 sync/flush | | Registry | 维持当前 G14 `hwlab-ci/hwlab-registry` | `scripts/g14-gitops-render.mjs --lane v02` 是当前 `v0.2` GitOps render 入口。该 lane 必须把默认 source branch 改为 `v0.2`、GitOps branch 改为 `v0.2-gitops`、catalog 改为 `deploy/artifact-catalog.v02.json`、runtime endpoint 改为 `19667`、web endpoint 改为 `19666`,并使用完整 source commit 作为 image tag。 ## 真相源 `v0.2` 的发布真相按以下顺序判断: 1. live runtime:`hwlab-v02` namespace 中 Deployment/StatefulSet template、Pod ready、事件、日志和 `19666/19667` 公网 health。 2. Argo desired state:`argocd/hwlab-g14-v02` 的 revision、sync、health、source branch 和 runtime path。 3. devops-infra mirror/relay 中的 GitOps branch:`v0.2-gitops` 中的 `deploy/artifact-catalog.v02.json` 与 `deploy/gitops/g14/runtime-v02/**`。 4. Tekton 执行证据:UniDesk `trigger-current` 返回的 PipelineRun、TaskRun result、`gitops-promote` 终态。 5. GitHub 上游归档状态:mirror/relay flush 后的 `origin/v0.2-gitops` 与 `origin/v0.2`。 6. 干净 source workspace:`origin/v0.2`、`deploy/deploy.json`、模板、render 脚本和 `--no-write` 输出。 旧 commit 记忆、`G14`/`G14-gitops` DEV/PROD 产物、D601 legacy 路径、GitHub 上游尚未 flush 的短暂落后、source branch 中历史 generated 文件和临时 worktree 只能作为线索,不能作为 `v0.2` 发布通过证据。 ## Source 与 GitOps 分层 `v0.2` source branch 可以包含: - 源码、测试、文档、人写配置和模板。 - `deploy/deploy.json` 或等价 lane 配置。 - k8s 模板、render 脚本、CI/CD helper 和 catalog schema。 `v0.2` source branch 不得跟踪: - `deploy/artifact-catalog.v02.json`。 - `deploy/gitops/g14/runtime-v02/**`。 - Tekton/Argo 的 rendered runtime desired state。 - image digest、publish state、reuse evidence 或 CI 生成的 rollout metadata。 `v0.2-gitops` branch 必须包含: - `deploy/artifact-catalog.v02.json`,记录 image tag、digest、source commit、component identity、publish/reuse 状态。 - `deploy/gitops/g14/runtime-v02/**`,作为 Argo CD 实际消费的 desired state。 - 必要的 generated metadata,但不得包含 Secret 值。 首次初始化时,如果 `v0.2-gitops:deploy/artifact-catalog.v02.json` 尚不存在,只允许由 `v0.2` lane 的正式初始化步骤创建第一版 catalog。不得 fallback 到 `G14` source catalog、`G14-gitops` catalog、DEV runtime path 或 source branch 生成物。 ## CI/CD 链路 标准链路如下: 1. UniDesk CLI `hwlab g14 control-plane trigger-current --lane v02 --confirm` 解析当前 `origin/v0.2` 完整 source commit SHA,直接创建 commit-pinned `hwlab-v02-ci-poll-` PipelineRun;默认 `--dry-run` 只返回将要创建的 manifest。 2. `prepare-source` 通过 `devops-infra` mirror checkout `v0.2` source,并从 mirror 中的 `v0.2-gitops` 读取上一版 `deploy/artifact-catalog.v02.json`。 3. 原语校验 task 只覆盖 repo 报告护栏、GitOps render 合同和必要的代码语法/单元检查;旧 DEV/D601/main gate 不进入 lane。 4. planner 根据 component input 判断 affected/reused services。 5. affected service 通过 BuildKit 发布到 G14 本地 registry;reused service 复用 catalog digest。 6. promotion 刷新 `deploy/artifact-catalog.v02.json`,render `deploy/gitops/g14/runtime-v02/**`,只推送到 `devops-infra` mirror/relay 的 `v0.2-gitops`。 7. `hwlab-g14-v02` 从本地 mirror/relay 的 `v0.2-gitops:deploy/gitops/g14/runtime-v02` 同步到 `hwlab-v02`。 8. UniDesk CLI 或 mirror/relay flush 操作把本地 `v0.2-gitops` 推送到 GitHub canonical remote;flush 不在 CI runtime-ready 的关键路径内,但必须可查询 pending、lastFlushed 和 failure。 9. 验收只观察 `hwlab-v02` runtime 和 `19666/19667`。 `v0.2` 可以复用 G14 的 registry、proxy、BuildKit、工具镜像和脚本库;不得复用 `hwlab-g14-ci-image-publish`、`hwlab-g14-branch-poller`、`hwlab-g14-control-plane-reconciler`、`G14-gitops` runtime path 或 DEV/PROD Argo Application 作为 `v0.2` 发布入口。 `v0.2` 不设自动轮询发布。历史上若存在 `hwlab-v02-branch-poller`、`hwlab-v02-control-plane-reconciler` 或等价 CronJob,均视为迁移残留,应由 UniDesk control-plane apply 清理;后续发布、重跑、暂停和恢复都通过手动 CLI 触发或停止创建新的 PipelineRun 完成,不新增替代 CronJob。 `devops-infra` git mirror/relay 同样不设周期 CronJob。标准操作是先按需执行 `bun scripts/cli.ts hwlab g14 git-mirror sync --confirm` 把 GitHub allowlist refs 拉入本地 mirror,再执行 `bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm`。promotion 成功后可执行 `bun scripts/cli.ts hwlab g14 git-mirror flush --confirm` 把本地 `v0.2-gitops` 推送到 GitHub。`git-mirror apply` 维护 mirror 的 PVC、读服务、写服务、同步/flush 脚本和旧 CronJob 清理;`git-mirror sync` 创建一次性 Job,只同步 allowlist refs `v0.2`、`v0.2-gitops`、`G14` 和 `G14-gitops`,先 fetch 到隐藏 staging refs,校验 commit/tree/object closure,再用 `update-ref` 发布到公开 refs。这样 mirror read path 与 GitOps write path 都落在本地磁盘和集群网络,同时避免 CI 看到 ref 已更新但对象还不可 checkout 的半发布窗口。 写 mirror 的一致性模型是 local-first、manual-flush。promotion task 只能持有 mirror/relay 写凭证,不持有 GitHub deploy key;GitHub deploy key 只存在于 `devops-infra` mirror/relay sync/flush 边界。mirror/relay 必须在本地 receive 期间完成 object closure、目标 branch allowlist、non-fast-forward 拒绝和 changed-path 最小校验;receive 成功后本地 ref 即为 Argo 可消费事实。flush 失败不得回滚已经 rollout 的本地 GitOps revision,但必须保留 pending/outbox 状态,下一次手动 flush 可重试并输出 last error,不得静默丢弃。 ## Env 容器复用与三变量启动 `v0.2` code-only fast lane 的 runtime desired state 由三类输入组成:可复用 env image digest、自动推导的 code boot metadata、以及既有 service runtime config。开发者仍按当前 DEV/OPS 流程提交 `v0.2` source commit 和维护 `deploy/deploy.json`;发布入口不得要求人工填写 repo、commitId 或 boot script 路径。 code boot metadata 固定映射到三个启动环境变量: | 变量 | 自动推导来源 | 约束 | | --- | --- | --- | | `HWLAB_BOOT_REPO` | `v0.2` lane 的 canonical GitHub source repo 配置 | 必须是 canonical GitHub URL;用于身份记录,运行时读取由 resolver 自动分流到 mirror/cache。 | | `HWLAB_BOOT_COMMIT` | UniDesk `trigger-current` 解析到的 `origin/v0.2` 完整 source commit SHA,也就是 PipelineRun revision | 必须是完整 40 位 commit SHA;禁止 branch、tag、`latest` 或人工覆盖。 | | `HWLAB_BOOT_SH` | service model 或 `deploy/deploy.json` 中 serviceId 到 boot script 的映射,默认形态为 `deploy/runtime/boot/.sh` | 必须是 repo 内相对路径;禁止绝对路径、`..` 越界和从 env image 中隐式寻找旧脚本。 | CI/CD 必须把三变量同时写入 `deploy/artifact-catalog.v02.json`、rendered workload Pod template env/annotation 和 runtime health identity。三变量是由 lane 自动推导的发布事实,不是人工 OPS 参数;如果自动推导缺失或无法证明 `HWLAB_BOOT_COMMIT` 属于 `v0.2` 允许 ancestry,本轮 promotion 必须失败。 推荐启动形态是 initContainer + `emptyDir` + generic env image。initContainer 或 env image 内的 launcher 读取三变量,通过 resolver 把 `HWLAB_BOOT_REPO` 的只读 fetch/checkout 自动分流到 `devops-infra` git mirror/cache,按 `HWLAB_BOOT_COMMIT` checkout 到 Pod 私有 `emptyDir`;main container 复用同一 env image,并执行 checkout 后代码目录里的 `$HWLAB_BOOT_SH`。env image 只承载系统依赖、runtime、launcher、git client 和通用工具,不把业务代码或旧 boot script 当作运行真相。 code-only 变更时,planner 必须输出 `envChanged=false`、`codeChanged=true`,跳过 BuildKit image publish,复用上一版 env image digest,只更新 catalog 和 workload Pod template 中的 `HWLAB_BOOT_COMMIT`、code identity annotation 与相关 health metadata。Kubernetes 原生 Deployment/StatefulSet rolling update 仍由 Pod template hash 变化触发;不需要在容器内长期驻留 watcher,也不把 `git pull` 结果作为运行真相。 `devops-infra` git mirror/relay 是 allowlisted、PVC-backed 或等价持久化服务,负责缓存 GitHub 对象并承接 `v0.2-gitops` 本地写入。只有 mirror/relay sync/flush 边界持有 GitHub 远端凭证;`hwlab-v02`、AgentRun 和其他业务 namespace 只能访问只读 mirror/cache endpoint,不持有 GitHub deploy key。runtime checkout 失败、mirror miss 超过明确等待窗口、commit ancestry 不满足 lane 约束或 boot script 校验失败时,Pod 必须启动失败或 NotReady,不得回退到 env image 内旧代码,也不得在业务 namespace 直连 GitHub 拉取。 git mirror/relay 接入方式遵循“CI 写本地、GitHub 异步归档、读自动加速”。GitOps 和 deploy spec 中的 repo 字段仍记录 canonical GitHub URL 作为身份字段;launcher 或只读 runtime image 内的 resolver 负责读路径自动分流。需要 push `v0.2-gitops` 的 promotion task 必须 push devops-infra 本地 mirror/relay,不得在 CI 关键路径直接 push GitHub canonical remote。 registry 与 git mirror/relay 分属不同基础设施边界。registry 保持当前 G14 `hwlab-ci/hwlab-registry`,继续通过 repository prefix 服务 HWLAB、AgentRun 和后续 lane;新增 `devops-infra` git mirror/relay 不触发 registry 迁移,也不要求在 `devops-infra` 复制 registry。 ## Artifact 与镜像身份 - `v0.2` 镜像 tag 使用完整 40 位 source commitId。 - runtime manifest 必须使用 digest pin 作为部署身份。 - catalog 必须记录 lane/profile、source branch、GitOps branch、source commitId、serviceId、image tag、digest、component identity 和 publish/reuse 状态;启用 env 容器复用时还必须记录 `runtimeMode=env-reuse-git-mirror-checkout`、`environmentImage`、`environmentDigest`、`environmentInputHash`、`bootRepo`、`bootCommit`、`bootSh`、`codeInputHash` 和三变量写入证据。 - 同一 source commit 对同一 service 应生成同一镜像;lane 差异放在 manifest、env、SecretRef、namespace、FRP 和 DB 配置中,不 bake 进镜像。 - `deploy/deploy.json` 只承载人写 runtime intent,不承载 digest、publish state 或 reuse evidence。 ## Kubernetes 与 Argo 边界 - `hwlab-v02` namespace 只能由 `v0.2` GitOps lane 管理。 - `argocd/hwlab-v02` AppProject destination 只能包含 `hwlab-v02`。 - `argocd/hwlab-g14-v02` source 必须指向 `devops-infra` 本地 mirror/relay 中的 `v0.2-gitops:deploy/gitops/g14/runtime-v02`,destination 必须是 `hwlab-v02`。 - `hwlab-v02-frpc` 只能暴露 `19666/19667`,不能复用 `17666/17667` 或 `18666/18667`。 - `v0.2` Secret、DB 凭据、PVC、ServiceAccount 和 runtime config 必须独立命名或独立 namespace scope;文档、issue、trace 和 report 只记录 SecretRef 名称与 key,不记录值。 - `v0.2` 初期不新增自动 registry GC;后续如启用清理,selector 必须带 lane/profile 标签,registry digest 保护集必须同时覆盖 `G14-gitops` 与 `v0.2-gitops`。 ## 硬边界 以下边界是 `v0.2` CI/CD 的最小硬约束: - source branch 必须是 `v0.2`。 - GitOps branch 必须是 `v0.2-gitops`。 - runtime namespace 必须是 `hwlab-v02`。 - artifact catalog 必须是 `deploy/artifact-catalog.v02.json`。 - runtime path 必须是 `deploy/gitops/g14/runtime-v02`。 - Argo Application 必须是 `hwlab-g14-v02`,且只能部署到 `hwlab-v02`。 - source branch publish 后不得出现 `deploy/artifact-catalog.v02.json` 或 `deploy/gitops/g14/runtime-v02/**` 变更。 - GitOps promotion 的 changed paths 只能落在 `deploy/artifact-catalog.v02.json` 与 `deploy/gitops/g14/runtime-v02/**` 及必要的 v02 Argo/GitOps 元数据。 - 公网验收只能使用 `19666/19667`。 - `v0.2` 不得创建或依赖 CronJob;`hwlab-v02-branch-poller`、`hwlab-v02-control-plane-reconciler` 或同类调度器出现时应清理,而不是接入发布链路。 - 旧 DEV/D601/main gate、fallback、legacy mode 和双路径兼容不得进入 `v0.2` 调用链。 - env 容器复用 fast lane 中,`HWLAB_BOOT_REPO`、`HWLAB_BOOT_COMMIT` 和 `HWLAB_BOOT_SH` 必须由 CI/CD 自动推导并写入 GitOps desired state,不得作为人工发布参数或 runtime 临时 patch。 - git mirror/relay 必须来自独立 `devops-infra` 服务;`hwlab-v02` runtime namespace 不部署 mirror、不持有 GitHub deploy key、不在 mirror miss 时直连 GitHub fallback。 - GitOps promotion 必须写入 `devops-infra` 本地 mirror/relay 的 `v0.2-gitops`;除 mirror/relay flush 外,不得在 CI 关键路径直接 push GitHub canonical remote。 - mirror/relay write 必须只允许 allowlist refs,拒绝 non-fast-forward,拒绝越界 changed paths,并在 receive 成功前完成 object closure 校验。 这些硬边界优先在自然写入点做最小内联断言:render 断言 namespace/runtime path,promotion 断言 GitOps branch/changed paths,Argo spec 断言 destination,验收断言端口和 runtime identity。不要为每条设计约定再新增独立 preflight、guard、gate 或报告生成器。 ## G14 DEV/PROD 不变边界 接入 `v0.2` 不得改变以下对象: - `G14` source branch 的 poller/reconciler 语义。 - `G14-gitops` DEV/PROD catalog 与 runtime desired state。 - `hwlab-dev` 与 `hwlab-prod` namespace。 - `hwlab-g14-dev` 与 `hwlab-g14-prod` Argo Application。 - DEV `17666/17667` 与 PROD `18666/18667` FRP 入口。 - D601 legacy 回溯路径和旧运行面边界。 如果 `v0.2` 接入失败,回滚或暂停只能作用于 `hwlab-v02` lane:停止手动触发新的 v02 PipelineRun、暂停或删除 `hwlab-g14-v02`、回滚 `v0.2-gitops` runtime path、关闭 `hwlab-v02-frpc` 或清理 `hwlab-v02` namespace 资源;不得通过新增 CronJob 维持重试,也不得重启、删除或回滚 DEV/PROD 运行面。 ## 验收标准 `v0.2` CI/CD 通过必须同时满足: - `hwlab-ci` 中存在 `hwlab-v02-ci-image-publish` 和 `hwlab-v02-tekton-runner`;不存在 v02 CronJob。`hwlab-v02-branch-poller` 与 `hwlab-v02-control-plane-reconciler` 不再作为 v02 标准对象,若历史残留应由 UniDesk control-plane apply 清理。 - 最新 `v0.2` source commit 对应的 PipelineRun 完成,且 promotion 写入 `v0.2-gitops`。 - `v0.2-gitops` 中存在 `deploy/artifact-catalog.v02.json` 与 `deploy/gitops/g14/runtime-v02/**`。 - `argocd/hwlab-g14-v02` 指向 `devops-infra` 本地 mirror/relay 的 `v0.2-gitops:deploy/gitops/g14/runtime-v02`,sync revision 与目标 GitOps revision 对齐。 - `hwlab-v02` 中长驻 workload ready,没有把 DEV/PROD namespace 当成 `v0.2` 通过证据。 - `gitops-promote` 推送本地 mirror/relay 的 `v0.2-gitops` 后应触发 `argocd/hwlab-g14-v02` hard refresh,减少 GitOps push 与 Argo 仓库发现之间的漂移窗口;refresh 触发失败只作为低噪声事件输出,最终通过仍由 `runtime-ready` 判定。 - mirror/relay status 必须能显示本地 `v0.2-gitops` revision、GitHub 已 flush revision、pending flush revision 和最近一次 flush 错误;CI 通过不要求 GitHub flush 已完成,但运维观察必须能看到上游是否落后。 - `runtime-ready` 必须以 workload Pod template 的 source commit 判断 Argo 刷新,并在 Argo 刷新超时、observer RBAC 不足或 workload 未就绪时失败;不得把 CrashLoop、未刷新或公网不可用的 runtime 标成绿色。 - 启用 env 容器复用的服务必须在 catalog、Pod template annotation/env 和 `/health/live` 或等价 runtime identity 中同时暴露 env image digest 与 `HWLAB_BOOT_REPO`/`HWLAB_BOOT_COMMIT`/`HWLAB_BOOT_SH`;只暴露镜像 digest 不能证明 code-only rollout 已生效。 - code-only rollout 的 PipelineRun 必须能证明没有发布新 env image、复用了上一版 env digest、只更新 boot commit/code identity,并由 Kubernetes Pod template hash 触发滚动。 - `devops-infra` git mirror/cache miss、commit ancestry 拒绝或 boot script 校验失败必须导致本轮 rollout fail closed,不得隐式回退到 GitHub 或 env image 内旧代码。 - `http://74.48.78.17:19666/` 返回 `v0.2` Cloud Web。 - `http://74.48.78.17:19667/health/live` 返回 `v0.2` runtime health,payload 中的 namespace、revision 或 runtime identity 能与 `hwlab-v02`/`v0.2` 对齐。 GitOps branch 已更新、source branch render 通过、PipelineRun 名称存在或 `G14` DEV/PROD health 正常,都不能单独代表 `v0.2` CI/CD 通过。 ## 测试规格 ## T1 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:确认 `origin/v0.2` 最新 commit 对应的 PipelineRun 完成,promotion 只写入 `v0.2-gitops`,且 source branch 没有跟踪 `deploy/artifact-catalog.v02.json` 或 `deploy/gitops/g14/runtime-v02/**` 生成物。 ## T2 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:查询 Argo `hwlab-g14-v02`,确认 source repo 为 `devops-infra` 本地 mirror/relay,branch/path 为 `v0.2-gitops:deploy/gitops/g14/runtime-v02`,destination namespace 为 `hwlab-v02`,sync revision 与目标 GitOps revision 对齐。 ## T3 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:访问 `http://74.48.78.17:19666/` 和 `http://74.48.78.17:19667/health/live`,确认公网入口、payload environment、revision 和 runtime identity 都指向 v02,不把 DEV/PROD health 当作 v02 证据。 ## T4 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:涉及 Code Agent 时使用短连接 submit/result/trace 轮询,确认 `status=completed` 且 assistant reply 非空;不得只用 `/health/live` 中 `codeAgent=ready` 证明 provider 鉴权通过。 ## T5 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:对启用 env 容器复用的服务触发一次 code-only commit,确认 PipelineRun 标记 `envChanged=false`、复用上一版 env digest、catalog 与 Pod template 写入 `HWLAB_BOOT_REPO`、`HWLAB_BOOT_COMMIT`、`HWLAB_BOOT_SH`,runtime health 同时暴露 env digest 和 boot commit,且 `HWLAB_BOOT_COMMIT` 来自完整 `origin/v0.2` source commit SHA。 ## T6 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:在不打印任何 GitHub 凭证的前提下确认 runtime checkout 读路径命中 `devops-infra` git mirror/cache,业务 namespace 没有 GitHub deploy key;模拟 mirror miss 或非法 commit 时 rollout fail closed,不回退到 GitHub 直连或 env image 内旧代码。 ## T7 阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:触发一次 `v0.2` code-only promotion,确认 `gitops-promote` 只 push 到 `devops-infra` 本地 mirror/relay,Argo 从本地 mirror/relay rollout;再执行 `git-mirror flush --confirm`,确认 GitHub `origin/v0.2-gitops` 快进到同一 revision,status 中 pending 清空。 ## 规格的实现情况 | 规格项 | 状态 | 说明 | | --- | --- | --- | | v02 独立 source/GitOps/runtime lane | 已实现 | `v0.2`、`v0.2-gitops`、`hwlab-v02` 和 `runtime-v02` 已固定。 | | 手动 CLI trigger/pipeline/promotion | 已实现 | 通过 UniDesk `trigger-current` 创建 commit-pinned PipelineRun;v02 不设 CronJob,由 `hwlab-v02-ci-image-publish` 与 GitOps promotion 管理。 | | v02 runtime readiness fail-closed | 已实现 | `gitops-promote` 推送后触发 Argo hard refresh;`runtime-ready` 读取 workload Pod template source commit,timeout、observer RBAC 不足或未就绪会让 PipelineRun 失败。 | | v02 裁撤服务不进入发布面 | 已实现 | v02 Tekton build service set、artifact catalog 和 runtime render 只包含保留服务;v02 Argo 开启 prune 清理旧 live 对象;裁撤服务仍可保留在 DEV legacy 源码中。 | | Argo v02 Application | 已实现 | `hwlab-g14-v02` 指向 v02 GitOps path 和 namespace。 | | FRP `19666/19667` 入口 | 已实现 | 由 `hwlab-v02-frpc` 与 master frps allowlist 共同提供。 | | SecretRef 独立与 provider 验收 | 已实现/持续约束 | SecretRef 已独立;验收必须做真实短连接聊天。 | | env 容器复用三变量启动 | 已实现/持续约束 | device-pod fast lane 已由 CI/CD 自动推导 `HWLAB_BOOT_REPO`、`HWLAB_BOOT_COMMIT`、`HWLAB_BOOT_SH`;code-only rollout 复用 env image digest,只更新代码身份。 | | `devops-infra` git mirror/relay 加速 | 部分实现/待迁移写路径 | source/catalog/runtime checkout 读路径已使用独立基础设施集群 mirror/cache;下一步必须把 GitOps promotion、Argo source 和 GitHub flush 收敛到真正写 mirror。runtime namespace 不持有 GitHub deploy key,registry 保持 G14 `hwlab-ci/hwlab-registry`;mirror 同步和 flush 由 UniDesk CLI 手动触发,不设置 CronJob。 | | 自动 registry GC | 未实现 | 初期不启用自动 GC,后续需 lane/profile 保护集。 | ## 平行 lane 运维边界 后续新增 `v0.x` 或其他平行 runtime lane 时,优先复用本节的判定顺序和排障边界,避免把一次性补丁沉淀成新的宽泛门禁。本节只保留可复用的运维边界;具体执行记录、排障流水和一次性证据应放在 issue 或 PR 中。 ### Secret 导入与重启边界 平行 lane 的 Secret 必须独立命名,不能在 runtime 里直接引用 DEV Secret。允许把 DEV 当前值一次性导入到目标 lane 的独立 Secret 名,但验证只能输出 Secret 对象、key、字节数和哈希指纹,不能打印 Secret value、token 片段、完整 DB URL 或 `auth.json` 内容。 `v0.2` 至少需要独立维护以下 SecretRef: - `hwlab-v02-postgres/POSTGRES_PASSWORD`。 - `hwlab-cloud-api-v02-db/database-url`。 - `hwlab-v02-code-agent-provider/openai-api-key`。 - `hwlab-v02-code-agent-codex-auth/auth.json`。 Code Agent 的 Secret 修复不是只改一个 Secret 对象就结束。`hwlab-cloud-api` 通过 env 读取 `OPENAI_API_KEY`,Secret 更新后必须滚动 `hwlab-v02/hwlab-cloud-api`。DeepSeek profile 还通过 `hwlab-deepseek-proxy` 的 initContainer 把 `DEEPSEEK_API_KEY` 渲染进 Moon Bridge 配置,Secret 更新后也必须滚动 `hwlab-v02/hwlab-deepseek-proxy`,否则 proxy 仍会使用旧配置并返回上游鉴权失败。 ### Code Agent 验收 `/health/live` 中 `codeAgent=ready`、`codexStdio=ready` 只能证明运行时结构、二进制、workspace、token boundary 和会话 supervisor 就绪;它不证明真实 provider 鉴权可用。涉及 Code Agent 的扩容验收必须追加一次真实短连接聊天闭环:用 `Prefer: respond-async` 和 `X-HWLAB-Short-Connection: 1` 提交 `/v1/agent/chat`,再轮询 `/v1/agent/chat/result/`,只有 `status=completed` 且 assistant reply 非空才算通过。 如果 trace 里出现 `Authentication Fails`、`upstream stream error` 或 `codex_stdio_provider_retry`,先按 profile 分层判断:`deepseek` profile 走 `hwlab-deepseek-proxy..svc.cluster.local:4000/v1/responses` 和 Moon Bridge;`codex-api` profile 走 Pod-local loopback forwarder。不要用 `codex-api` readiness 掩盖 DeepSeek 专用凭证或 Moon Bridge 配置问题。 长耗时 smoke 不应通过 UniDesk SSH 长连接等待完整 Codex turn。Codex 首 token 可能超过短查询窗口,验证应使用短连接 submit/result/trace 轮询,避免把控制通道超时误判成 provider 失败。 ### GitOps 与 runtime 收敛 GitOps promotion 成功不等于 runtime 已经运行新版本。验收必须等待 `argocd/hwlab-g14-v02` 的 sync revision 对齐最新 `v0.2-gitops` revision,并确认 `19667/health/live` 的 `environment`、`endpoint`、关键 SecretRef 和 service revision 与目标 lane 对齐。 Argo `Synced/Healthy` 也不能单独替代公网验证。FRP server 侧 `allowPorts` 缺失时,`hwlab-v02-frpc` 会反复报告 `port not allowed`;这种问题应修 master 侧 `frps` allowlist 并只重启 `hwlab-frps-dev`,不要改 DEV/PROD GitOps、Service 或 v02 runtime path。修复后必须同时验证新增 `19666/19667` 和既有 DEV `17666/17667`。 ### 后续扩容建议 下一条平行 lane 建议先列一张最小资源映射表,再落地 CI/CD:source branch、GitOps branch、runtime namespace、runtime path、Argo Application、FRP ports、artifact catalog、Postgres Secret、Cloud API DB Secret、Code Agent provider Secret、Codex auth Secret、DeepSeek proxy restart 对象和公网验收 URL。映射表是执行清单,不是新 gate;只有 branch、namespace、runtime path、GitOps branch、Argo destination、SecretRef 名称和公网端口这些硬边界需要内联断言。 Secret、FRP 和 Argo 问题都应先在目标运行面做最小真实闭环,再进入完整 CI/CD 复跑。不要用完整 PipelineRun 反复探索 Secret 值、FRP allowlist 或 provider 鉴权;CI/CD 只负责固化已经在目标 namespace 证明可行的配置和源码。