Files
pikasTech-HWLAB/docs/reference/spec-v02-cicd.md
T
2026-06-08 12:22:54 +08:00

79 KiB
Raw Blame History

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,env 容器复用、三变量启动和 git mirror 加速设计见 pikasTech/HWLAB#572PR 合并后自动 CD 迁移计划见 pikasTech/HWLAB#848CI 无锁并发与 CD latest-only 迁移见 pikasTech/HWLAB#866。原 docs/plan/hwlab-v02-namespace-cicd.md 阶段计划全文已迁入 #530 评论。本文只记录稳定规格、边界和判定标准;不要把一次性执行记录、排障流水账或临时证据写入本文。

在系统中的职责划分

v0.2 CI/CD 是 G14 上的加法 lanesource 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 受控触发入口、CI/CD 专用 source repo、devops-infra git mirror、PipelineRun、component planner、BuildKit publish、GitOps promotion、Argo sync、GitHub flush 和公网验收构成。标准触发方式是 UniDesk CLI 合并 base=v0.2 PR 后自动进入 v02 CDtrigger-current 手动入口和 auto-cd --once 类补偿入口保留用于人工重跑、漏触发修复和迁移期验证。v0.2 不设置 k8s branch poller、control-plane reconciler 或其他 CronJobsource branch 只保存源码和人写配置;v0.2-gitops branch 保存 catalog 和 rendered runtime desired statelive runtime 是最终通过证据。固定开发 workspace 只服务人工开发和短连接源码工具,不参与 CI/CD source commit 选择。

首期自动化不要求 GitHub webhook。PR 创建、预检和 merge 已由 UniDesk CLI 控制时,merge 成功后的同一受控流程应直接解析最新 origin/v0.2 head 并调用现有 v02 control-plane。若未来接入 webhook,它只能作为唤醒信号;发布 source commit 仍必须由 /root/hwlab-v02-cicd.git fetch 到的 refs/remotes/origin/v0.2 决定,不能直接信任 webhook payload 创建 PipelineRun。

v0.2 的 GitOps 写路径采用真正写 mirrorpromotion 先把 v0.2-gitops 写入 devops-infra 本地 git mirror/relayArgo CD 从本地 mirror/relay 读取该 revision 并 rolloutCI 关键路径不等待 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 固定。
UniDesk v02 PR auto-CD monitor 观察并合并 base=v0.2 的 ready PRmerge 后调用现有 trigger-current、定点 statusgit-mirror flush
Tekton hwlab-v02-ci-image-publish 构建 affected images、复用 unchanged digest,并 promotion 到 v0.2-gitops
devops-infra git mirror/relay 读写 v0.2 allowlist refsCI 读 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 namespace74.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
Development workspace G14:/root/hwlab-v02,仅用于人工开发、短连接源码工具和可见性对照,不作为 CI/CD source commit 选择入口
CI/CD source repo G14:/root/hwlab-v02-cicd.git bare repo,由 UniDesk control-plane 自动 fetch origin/v0.2,再从 commit-pinned detached worktree render/apply 控制面
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
PR merge auto-CD UniDesk CLI v02 PR monitor 合并 base=v0.2 PR 后自动调用 trigger-current,并定点观察 merge head
Manual trigger UniDesk CLI bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm,仅作为人工重跑和迁移期补偿入口
Reconcile fallback UniDesk CLI v02 auto-cd --once 或等价补偿入口,对齐当前 origin/v0.2 head、PipelineRun、GitOps 和 mirror flush 状态
Scheduler/CronJob 不创建、不保留 v02 k8s CronJobPipelineRun 只能由 UniDesk CLI PR monitor、manual trigger 或 once reconcile 创建
Tekton ServiceAccount hwlab-ci/hwlab-v02-tekton-runner
PipelineRun prefix hwlab-v02-ci-poll-<short12>
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 runtimehwlab-v02 namespace 中 Deployment/StatefulSet template、Pod ready、事件、日志和 19666/19667 公网 health。
  2. Argo desired stateargocd/hwlab-g14-v02 的 revision、sync、health、source branch 和 runtime path。
  3. CI/CD source refsUniDesk control-plane 专用 bare repo refs/remotes/origin/v0.2、devops-infra mirror/relay 的 refs/heads/v0.2refs/mirror-stage/heads/v0.2 必须共同指向最新 source commit。
  4. devops-infra mirror/relay 中的 GitOps branchv0.2-gitops 中的 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/**
  5. Tekton 执行证据:UniDesk trigger-current 返回的 PipelineRun、TaskRun result、gitops-promote 终态。
  6. GitHub 上游归档状态:mirror/relay flush 后的 origin/v0.2-gitopsorigin/v0.2
  7. 固定开发 workspace/root/hwlab-v02HEAD、dirty 状态和 origin/v0.2 只作为人工开发对照线索;即使 workspace 脏或落后,也不得影响 CI/CD source commit 选择。

旧 commit 记忆、G14/G14-gitops DEV/PROD 产物、D601 legacy 路径、GitHub 上游尚未 flush 的短暂落后、source branch 中历史 generated 文件、固定开发 workspace 脏状态和临时 worktree 只能作为线索,不能作为 v0.2 发布通过证据。

source workspace 中被 .gitignore 忽略的 deploy/gitops/g14/runtime-v02/** 文件只可能是本地生成缓存。若这类文件与 v0.2-gitops 或 live runtime 不一致,应删除本地缓存并以 v0.2-gitops、Argo 和 live ConfigMap/Deployment 为准;不要在 source branch 修补 ignored generated 文件,也不要把它们的内容写入 issue closeout 作为发布证据。

Workspace 与 CI/CD 分离

v0.2 开发 workspace 和 CI/CD repo 必须分离。/root/hwlab-v02 是人工开发、短连接 hwlab-cli 和问题复现的固定 workspace;它允许出现并行任务产生的 untracked .worktree/、本地 dirty 文件或临时落后状态。CI/CD 不从该 checkout 的 HEAD、工作树 clean 状态或本地 branch 读取待发布 commit,也不得因为该 workspace 脏而跳过、误判或复用旧 PipelineRun。

UniDesk control-plane 必须使用独立 bare repo /root/hwlab-v02-cicd.git 作为 CI/CD source repo:每次 statusapplygit-mirror applytrigger-current 先自动 fetch origin/v0.2refs/remotes/origin/v0.2,再用目标 commit 创建 detached temp worktree 运行 scripts/g14-gitops-render.mjs --lane v02。该 repo 没有业务工作树,因此不会被人工开发 dirty 状态污染;如果它不可用,应以 v02-head-unresolved 或等价结构化错误失败,而不是回退到固定 workspace HEAD。

devops-infra git mirror 仍是 PipelineRun 和 Argo CD 的集群内读写源。trigger-current --lane v02 --confirm 在创建 PipelineRun 前必须比较 expectedSourceHead 与 mirror localV02,不一致时自动执行 bounded git-mirror sync Job。git-mirror status 必须分别暴露 localV02githubV02localGitopsgithubGitopssourceInSyncgitopsInSyncpendingFlushgithubInSync 不得再被理解为只代表 GitOps branch。

Source 与 GitOps 分层

v0.2 source branch 可以包含:

  • 源码、测试、文档、人写配置和模板。
  • deploy/deploy.yaml 或等价 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。

如果权限、schema 或 runtime desired state 发生迁移,必须分别核对 source schema/代码、v0.2-gitops rendered YAML 和 live runtime。source branch 应只保留当前 migration/ensure 逻辑,v0.2-gitops 与 live ConfigMap 应体现发布后的 rendered statefixed workspace 下 ignored runtime-v02/postgres.yaml 即使存在也不能代表真相。

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. PR open/update 阶段只运行 source CI、检查和 PR preflight,不修改 hwlab-v02 runtime,也不写 v0.2-gitops
  2. UniDesk CLI v02 PR monitor 只观察 pikasTech/HWLAB base=v0.2 的 ready PRready PR 不因为其他 commit 的 PipelineRun 仍在运行而阻塞 merge。merge 成功后重新 fetch /root/hwlab-v02-cicd.gitorigin/v0.2,以 fetch 后的完整 source commit SHA 作为待发布目标。
  3. monitor 调用现有 hwlab g14 control-plane trigger-current --lane v02 --confirm。该入口自动复核 devops-infra mirror 的 localV02 ref,必要时执行一次 bounded git-mirror sync Job,再创建 commit-pinned hwlab-v02-ci-poll-<short12> PipelineRun;同一 source commit 已有 PipelineRun 时只复用现有状态,不删除重建。默认 --dry-run 只返回将要创建的 manifest 和 mirror pre-sync 计划。人工重跑和 auto-cd --once 补偿必须复用同一入口,不得直接创建 PipelineRun。
  4. prepare-source 通过 devops-infra mirror checkout v0.2 source,并从 mirror 中的 v0.2-gitops 读取上一版 deploy/artifact-catalog.v02.json
  5. CI/CD 校验只保留最小构建、TypeScript 语义检查、自动单元测试、打包和必要冒烟检查;旧 DEV/D601/main gate、运行时内部证明型校验、健康诊断重断言和历史预检不进入 lane。
  6. planner 根据 component input 判断 affected/reused services。
  7. affected service 通过 BuildKit 发布到 G14 本地 registryreused service 复用 catalog digest。 所有 selected service 的 build TaskRun 都只依赖 plan-artifacts,不按 service 串行排队,也不设置 8 并发或其他 Pipeline 级限流。 实际并发由 Tekton controller、G14 节点资源、PVC I/O、BuildKit sidecar 和本地 registry 承载能力决定。 v0.2 保留 runtime servicehwlab-cloud-apihwlab-cloud-webhwlab-gatewayhwlab-edge-proxyhwlab-agent-skills)必须使用 env-reuse-git-mirror-checkout。 只有 package/runtime/env、env image 构建定义、launcher 输入变化或缺少可复用 env digest 时才构建 <service>-env 镜像。 service source 或 boot script 的 code-only 变化只更新三变量和 GitOps desired state,不再重新构建业务镜像。 hwlab-codex-api-forwarder sidecar 和 hwlab-deepseek-proxyresponses-bridgehwlab-cloud-api 的运行面关联容器,复用 hwlab-cloud-api-env 并通过各自 boot script 启动;它们不是独立 service matrix 成员,也不得增加第六个 env-reuse service。 CLI、CaseRun、HWPOD workspace 工具、文档、测试和其他非 service 资产不进入 env-reuse service 触发面。
  8. promotion 刷新 deploy/artifact-catalog.v02.jsonrender deploy/gitops/g14/runtime-v02/**,只在本 PipelineRun 的 source commit 仍是当前 origin/v0.2 head 时推送到 devops-infra mirror/relay 的 v0.2-gitops;若 source branch 已推进,本轮输出 superseded/no-op,写出 runtime-ready-required=false,不得回写旧 GitOps revision。
  9. hwlab-g14-v02 从本地 mirror/relay 的 v0.2-gitops:deploy/gitops/g14/runtime-v02 同步到 hwlab-v02
  10. UniDesk CLI auto-CD 观察定点 control-plane status --lane v02 --source-commit <merge-head>--pipeline-run <name>,确认 PipelineRun、Argo、runtime workload、public probes 和 planArtifacts build/reuse 摘要。历史 merge head 若因后续 origin/v0.2 推进而被 supersededPR 评论以 superseded 收口;最新 head 仍必须继续收敛到 runtime。
  11. UniDesk CLI 或 mirror/relay flush 操作把本地 v0.2-gitops 推送到 GitHub canonical remoteflush 不在 CI runtime-ready 的关键路径内,但自动 CD 收口必须查询 pending、lastFlushed 和 failure,必要时执行 git-mirror flush --confirm 并等待 pendingFlush=false
  12. 验收只观察 hwlab-v02 runtime 和 19666/19667,并把 source commit、PipelineRun、GitOps revision、build/reuse 摘要、Argo/runtime/public probe 状态写回 PR 或关联 issue。

trigger-current --lane v02 --confirm 默认返回异步 job,不等同于 PipelineRun 已经创建完成。调用方必须先运行返回的 job status <jobId>,等 progress.stage=create-pipelinerunprogress.pipelineCreated=true 后,再用 control-plane status --lane v02 --pipeline-run <name> 做定点发布观察。progress.pipelineRun 可以在 control-plane refresh 或 mirror pre-sync 阶段提前给出预期名称;此时如果重型 status 报 target-pipelinerun-not-found-or-unreadable,只能说明 PipelineRun 尚未创建,不能作为发布失败、mirror 失败或 runtime 回归结论。

定点发布观察优先使用 --pipeline-run <name>--source-commit <full-sha>,避免 branch 后续推进导致历史 run 被最新 head 口径误判。control-plane status 会同时做 source/mirror/TaskRun/Argo/runtime/web asset 汇总,可能比普通只读查询慢;高频轮询时先看异步 job progress 和 TaskRun 条件摘要,只在阶段收口或异常定位时再跑完整 status。

GitOps promotion 成功后,本地 mirror/relay 的 v0.2-gitops 可立即被 Argo 消费;GitHub 上游 flush 是归档与跨节点同步步骤,不在 runtime-ready 关键路径内。git-mirror status.pendingFlush=true 时自动 CD 和人工收口都应运行 git-mirror flush --confirm,再用该 flush job 的 job statusgit-mirror status 确认 pendingFlush=falselocalGitops=githubGitops。不要把 pending flush 误判为 runtime 未发布,也不要在 flush job 仍运行时反复做全量 status。

v0.2 可以复用 G14 的 registry、proxy、BuildKit、工具镜像和脚本库;不得复用 hwlab-g14-ci-image-publishhwlab-g14-branch-pollerhwlab-g14-control-plane-reconcilerG14-gitops runtime path 或 DEV/PROD Argo Application 作为 v0.2 发布入口。运行时不得为每个版本硬编码 namespace、catalog、runtime path 或健康判断;版本差异只通过 deploy.yaml.lanes[profile]、GitOps render 输入和实际 runtime 对象表达,新增版本不得新增运行时代码分支。

v0.2 不设 k8s 自动轮询发布。历史上若存在 hwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 或等价 CronJob,均视为迁移残留,应由 UniDesk control-plane apply 清理。PR 合并后的自动 CD 只能由 UniDesk CLI monitor 或一次性 reconcile job 驱动,并且必须复用 trigger-current、定点 statusgit-mirror flush。暂停发布时停止 UniDesk monitor 或停止创建新的 PipelineRun;不要通过新增 CronJob 维持重试。

v02 auto-CD 必须采用 CI 无锁并发与 CD latest-only 语义。不同 source commit 的 PipelineRun 可以并发运行;monitor 不等待旧 run 空闲,也不取消旧 run。同一个 source commit 已有 PipelineRun 时不得删除重建。GitOps promotion 是唯一写入点,必须在写 v0.2-gitops 前重新读取 origin/v0.2 head:只有当前 PipelineRun commit 仍是最新 head 才允许写入;旧 commit 继续跑完 CI 后必须 superseded/no-op 收口,不能把 runtime 或 GitOps branch 滚回旧 commit。auto-cd --once 或等价补偿入口用于处理人工 GitHub merge、直接 push、monitor 重启或上次触发失败:它比较最新 origin/v0.2 head、PipelineRun、Argo/GitOps 和 mirror flush 状态,缺什么补什么,但仍不绕过标准 control-plane 入口。

devops-infra git mirror/relay 同样不设周期 CronJob。标准触发命令 bun scripts/cli.ts hwlab g14 control-plane trigger-current --lane v02 --confirm 会在创建 PipelineRun 前按需同步 mirrorbun scripts/cli.ts hwlab g14 git-mirror sync --confirm 只作为显式 mirror 维护或诊断入口。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.2v0.2-gitopsG14G14-gitops,先 fetch 到隐藏 staging refs,校验 commit/tree/object closure,再用 update-ref 发布到公开 refs。这样 mirror read path 与 GitOps write path 都落在本地磁盘和集群网络,同时避免 CI 看到 ref 已更新但对象还不可 checkout 的半发布窗口。

mirror 的 HTTP upload-pack 必须允许按精确 commit SHA 拉取已存在对象:uploadpack.allowReachableSHA1InWant=trueuploadpack.allowAnySHA1InWant=true。v0.2 Code Agent 通过 AgentRun 传递 resourceBundleRef.commitId 来复现实验时的源码身份,runner 会执行等价的 git fetch --depth=1 origin <commitId>;如果 mirror 只允许 advertised refs,旧 runtime commit、GitOps 已推进后的 commit 或隐藏 staging 已验证对象会返回 Server does not allow request for unadvertised object 并表现为 git fetch failed with code 128。这不是把 AgentRun 降级成浮动 branch fetch 的理由,修复点是 mirror read service 的 upload-pack 策略。

hwlab-cli 不属于 v0.2 CI/CD service matrix。它是 G14:/root/hwlab-v02 和 v0.2 worktree 内的短连接源码 client,只用 Bun 直接调用 Cloud Web 同源 API;不得加入 PipelineRun services 参数、artifact catalog、BuildKit publish、runtime desired state、Deployment、Service、Job 或 image build。CLI-only source 变更推送到 origin/v0.2 后,trigger-current --lane v02 应表现为 build=0 reuse=<runtime-services> 的 source-only fast path,用于证明 source/mirror/GitOps 没有产生旧 runtime artifact 副作用。若出现 build-hwlab-cli TaskRun、hwlab-cli artifact service、CLI 镜像或 CLI 常驻服务,均视为旧门禁/旧断言残留,直接删除并回到 docs/reference/spec-v02-hwlab-cli.md 的短连接 client 口径。

rpt004:mvp:e2erunner:issue-visibility:preflightdev-base-image:preflight 不属于 v0.2 最小 CI/CD 校验入口;它们代表旧验收、旧 runner 可见性预检或旧镜像基础预检口径。v0.2 check/validate 不再引用这些任务,若它们重新进入默认 check plan、package script 或 PipelineRun,应直接删除该入口,而不是为其补兼容逻辑。

最小测试/校验机制

v0.2 最小校验的目标是拦截高确定性低级错误,不恢复旧重型门禁。hwlab-cloud-web 源码、模板或浏览器 bundle 输入发生变化时,CI 必须在镜像发布和 GitOps promotion 前执行 Cloud Web source check。该 check 至少包含实际 bundle 输入集合的 TypeScript 语义检查、自动发现的单元测试、bundle build 和 dist freshness 校验。

语法检查和 Bun build 不能证明浏览器运行路径安全。node --check 只解析语法,Bun.build() 只转译和打包,二者都可能放过 isRequestTraceEvent is not defined 这类未绑定标识符;因此 Cloud Web check 必须覆盖实际 Vite/React 入口和 web/hwlab-cloud-web/src/** bundle 输入,并运行 TypeScript semantic check,例如 tsc --noEmit 或等价 Bun/TS checker。该检查失败时不得继续发布 hwlab-cloud-web 镜像。

Cloud Web 单元测试必须自动发现并执行 repo-owned web/hwlab-cloud-web/**/*.test.ts,不能只依赖手写文件清单。新增 trace、markdown、auth、status 或 HWPOD node-ops 前端纯逻辑测试后,应天然进入 bun run --cwd web/hwlab-cloud-web check。trace 渲染核心路径必须有不依赖浏览器、Playwright、公网或真实 provider 的轻量单测,直接构造 runnerTrace.events 并调用 trace row/render helper,确保请求事件、setup 事件、tool command summary、assistant markdown 和 completion row 不会因未定义 helper 或数据形态漂移在浏览器运行时崩溃。

默认 v0.2 CI 不启动 Playwright、布局 smoke、移动端截图、旧 quick prompt 检查、旧 M3 evidence 检查或历史 DEV/D601 browser gate。这些检查只能作为显式人工诊断或专项验收命令存在,不能重新进入最小 CI/CD 关键路径。新增测试也必须只表达当前 v0.2 目标行为;发现旧 UI/旧路由/旧门禁断言阻碍当前目标时,删除旧断言而不是维护兼容分支。

远端验证短连接规则

G14 host、worktree、k3s 控制面或 pod 内的验证命令必须按短连接可见性设计。通过 UniDesk ssh/tran route 执行 npm run web:checknpm run web:layout、Playwright、Tekton/Argo 观察、镜像构建、发布等待或其他可能超过单次维护桥预算的动作时,不得让 SSH 连接长时间阻塞等待完整输出。标准做法是用一次短连接创建后台 job、PipelineRun、Tekton task 或显式脚本 job,把 stdout/stderr、exit code、开始/结束时间和关键元数据写入 /tmp.state 或 CI artifact;随后用有界短连接轮询 statustailexit.code、TaskRun result 或 Argo summary。

如果一次远端验证已经触发 UNIDESK_SSH_RUNTIME_TIMEOUT、日志尾部缺失、exit code 不可见或浏览器/CI 进度不可见,必须先把该验证改成后台 job 加短轮询,再继续排障或发布。禁止把 60s 维护桥断开当作测试失败、测试通过或外部依赖不可用;也禁止通过加大本地等待、重复长连接、全量日志 dump 或改回原生 SSH 绕过来处理。长期 CLI/CI 能力不足时,优先补 UniDesk CLI 的异步 job/status/tail 子命令,再用该入口完成验证。

写 mirror 的一致性模型是 local-first、manual-flush。promotion task 只能持有 mirror/relay 写凭证,不持有 GitHub deploy keyGitHub 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,不得静默丢弃。

性能预算与回归判定

v0.2 fast lane 的性能目标是让 code-only/env-reuse 场景主要受 G14 集群调度、PVC 和本地磁盘 I/O 限制,而不是受 GitHub 网络、重复依赖安装或无效 runtime 等待限制。性能预算只用于发现退化和指导排障,不新增发布门禁;发现退化时先按本节做现场热探测,再决定是否需要完整 CI/CD 复跑。

可见性优先于性能数字。 任何优化如果让触发阶段、mirror pre-sync、GitOps promotion、Argo refresh 或 runtime-ready 重新变成黑盒等待,即使总耗时暂时更短,也视为 P0 回归。 性能预算必须和日志契约一起判断:每个长等待都要能定位到具体阶段、目标 revision、等待对象和 pending/blocked 摘要。

代表性 env-reuse 场景的对比基线如下。后续更换 runner、PVC、Tekton controller、Argo repo server 或 mirror 存储后,必须重新测量并更新本表的预算口径。

场景 关键路径总耗时 主要阶段表现 判定口径
env-reuse + mirror-write 初始路径 约 108s prepare-source 约 56s;包含无效 npm ci 和多余探针;runtime wait 仍执行 只作为旧基线,不应回归。
移除 prepare-source 中的 npm ci 约 76s prepare-source 降到约 21s;其余路径仍有多余探针和 runtime wait 不应再恢复依赖安装。
剪裁 fast-path 探针 约 50s prepare-source 约 11sgitops-promote 约 7sruntime-ready 约 17s runtime 有实际变化时的合理预算。
P1 no-op runtime skip 约 37-40s 固定阶段预算见下文;runtime-ready 跳过 source-only 且 runtime identity-only 变化时的目标预算;当前代表性实测为 38s。

当前预算判定:source-only、所有 service 都复用 artifact、GitOps runtime 只发生 source identity 变化时,总耗时应接近 40s;超过 50s 需要先查是否误触发 runtime-ready、是否发生 GitHub 直连、是否恢复了 npm ci 或无效 preflight。真正需要 rollout 的 code-only 变更允许约 50s,因为 runtime-ready 必须等待 Argo 与 workload 收敛。涉及 BuildKit publish、env image rebuild、registry push 或真实 runtime 滚动时,不适用 40s 预算,应按 affected service 的 build 耗时单独测量。混合变更必须按 service 作用域裁剪:只改 package.jsonscripts、旧门禁入口、短连接 CLI、CLI 测试、非 runtime 文档或 HWPOD workspace 工具时,不得触发无关 runtime service 全量 build;若同一变更确实同时改了 internal/cloud/**、HWPOD node-ops server code 和 skill bundle,则只允许对应 service build/rollout,其他 service 必须复用 catalog digest。

真实 rebuild 场景必须按全并行 fan-out 判定性能。 plan-artifacts 之后所有 affected service build task 应同时进入 Tekton 调度队列,collect-artifacts 只做 fan-in 等待全部 build task 写入 service report。 不得为了稳定表面耗时在 Pipeline 拓扑上重新串行化,也不得引入固定 8 并发上限。 全量 rebuild 的关键路径应接近最慢 service build 耗时加上 source、planning、collect、promotion 和 runtime-ready 固定开销,而不是所有 service build 耗时求和。 若全并行导致节点 CPU、内存、PVC I/O、BuildKit sidecar 或 registry 竞争,先通过 TaskRun duration、Pod scheduling、node pressure、registry latency 和 BuildKit 日志定位容量瓶颈。 除非已经证明控制面无法承载,否则不要把容量问题回退成 service 串行依赖。

关键阶段预算如下:

阶段 正常预算 退化信号
prepare-source 约 10-12s 超过 20s、出现 npm ci、访问 GitHub canonical remote、catalog fetch 超过数秒。
source-clone 约 1-2s 超过 5s 通常说明没有命中 devops-infra mirror 或 PVC/网络异常。
catalog-fetch 小于 1s 超过 3s 先查 mirror refs、object closure 和 catalog branch。
plan-artifacts 约 5-7s buildServicesrolloutServices 非空但本轮只改 CI/CD 文档/脚本时,先查 component input 与 catalog 是否加载。
collect-artifacts 约 6-8s 未输出运行时服务矩阵的 artifact_reuse 或全部 runtime services reuse 时,先查 catalog digest、PipelineRun services 参数和 service identityhwlab-cli 不应出现在 build/reuse 统计中。
gitops-promote no-op 约 7-9s 未输出 skipped-runtime-unchanged,或写入了 v0.2-gitops,说明 runtime 比对未命中。
runtime-ready no-op 应跳过;真实 rollout 约 15-20s no-op 场景出现 TaskRun 即为 P1 退化;真实 rollout 超时则按 Argo/workload 排障。

真实 rollout 若超过约 20s,先区分是 workload 本身启动慢,还是 runtime-ready 观察集合过大。正常日志应带 observedCount,且该值应接近本轮 rolloutServices 数量加上明确连带依赖;如果 workloadCount 很大但 observedCount 缺失,或 FRP、Postgres 等无关服务在 cloud-web/cloud-api 变更中重启,通常说明 render 把复用服务的 Pod template 绑定到了全局 source commit。修复方向是收窄 runtime-ready 观察集合,并把复用服务 template identity 改成 artifact commit、boot commit、config hash 或 migration hash,而不是加大 timeout 或恢复全 namespace 等待。

性能优化原理

prepare-source 不安装依赖。该 task 只负责 checkout source、读取上一版 catalog、输出 source identity 和基础文件,不运行 npm ci、不探测 npm registry、不做与后续 task 重复的工具链检查。需要依赖的语法检查、render test 或 build task 必须使用各自镜像内已有工具或在专属阶段处理,不能把全仓依赖安装塞回 source 准备阶段。

Git 读写都走 devops-infra 本地 mirror/relay。读路径用 HTTP mirror checkout v0.2 source 和 v0.2-gitops catalog;写路径把 promotion 推到 mirror/relay 的 v0.2-gitopsArgo 也从 mirror/relay 读取。这样 source clone、catalog fetch、GitOps clone/push 都落在集群内网络和本地磁盘,GitHub 只通过手动 sync/flush 进入或离开本地 mirror,不在 CI 关键路径内。

任何仍需要访问 GitHub canonical remote 的 SSH 操作都必须显式走 G14 proxy。Host SSH config 可以使用 OpenBSD nc -X connect -x 127.0.0.1:10808 %h %pTekton GIT_SSH_COMMAND、git-mirror sync/flush 和其他容器内 git@github.comssh://git@ssh.github.com:443 路径必须使用 repo-owned Node HTTP CONNECT ProxyCommand,并保留短 ConnectTimeoutServerAlive*。只改 HTTP_PROXY/HTTPS_PROXY 对 OpenSSH 无效;BusyBox nc 不支持 -X connect,不得再把 ssh.github.com:443 当作等价 proxy 或让 GitHub SSH 直连反复 60s 超时。

env image 复用把系统依赖和业务代码身份分离。environmentDigest 表示可复用运行环境,HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SH 表示本次代码启动身份。service code-only 变更只更新 boot metadata 和 runtime identity,不发布新 env image;只有真实 env 输入、env image 构建定义、launcher 输入变化或缺少可复用 env digest 时才进入 env rebuild。AgentRun v0.1 是 HWLAB 外部共享执行基础设施,hwlab-agent-worker 不再作为 v0.2 service image 或 suspended Job template 参与 planner、BuildKit、artifact catalog 或 GitOps render。package.json 只按 dependency/runtime 字段参与 env/runtime hashscripts 只属于开发入口,不得因为清理旧门禁脚本而重建所有 service 或重建 env image。CLI、CaseRun、HWPOD workspace 工具、文档和测试不属于 v0.2 service runtime 输入,不得因为 env reuse 机制被纳入 service rollout 或 build 范围;若某个工具文件确实被浏览器或服务源码直接 import,必须作为对应 service 的显式 component path 建模,而不能通过宽泛 shared path 扩散到所有服务。env image 构建定义只包含真正改变 <service>-env 镜像内容或启动器行为的文件,不能把 planner、测试、CLI 或 host helper 混入环境输入。

BuildKit publish 采用 service 级全并行 fan-out。 每个 service build task 拥有独立 BuildKit sidecar、独立 service workdir 和独立 report 文件,均从同一 plan-artifacts 结果判断是否需要执行。 跳过的 task 由 Tekton when 表达式裁剪,执行的 task 并行写入 /workspace/source/service-results/<serviceId>.jsoncollect-artifacts 只从 report 目录收敛结果,不再通过 tasks.build-*.results 直接依赖某个前序 task 输出,因此全并行不会改变 artifact 身份语义。

全并行不是无限资源承诺,而是 DAG 不主动限流。 CI/CD 拓扑只表达依赖:prepare-source 输出 source/catalog,轻量检查并行完成后进入 plan-artifacts。 所有被选中的 build-* task 只依赖 plan-artifacts,最后由 collect-artifacts fan-in。 实际同一时刻运行的 Pod 数由 Tekton controller、Kubernetes scheduler、G14 node 资源、PVC I/O、BuildKit sidecar 和本地 registry 共同决定。 如果这些节点因为容量不足自然排队,可以接受真实并发低于 selected service 数。 不允许为了掩盖排队把 Pipeline YAML 改回服务串行链或固定并发上限。

限制全并行的关键节点如下:

  • Tekton controller 与 Kubernetes API 负责把 selected build task 展开成 TaskRun/Pod。 控制面慢会让 TaskRun 创建或状态更新延迟;退化信号是 plan-artifacts 已完成但 build TaskRun 创建时间分散。
  • Kubernetes scheduler 与 G14 node 决定 Pod 是否能同时落到节点。 CPU、内存、ephemeral storage 和 image pull 会限制实际并行度;退化信号是 Pod PendingUnschedulableOOMKilledEvicted 或 node pressure event 增多。
  • shared workspace PVC 与本地磁盘承载 source 读取、service workdir 复制、report 写入和 BuildKit 层数据。 退化信号是 build step 开始慢、cp/tar/workspace 操作耗时异常、Pod I/O wait 高或 PVC/local-path event。
  • 每个 TaskRun 的 BuildKit sidecar 独立运行,但同时消耗 CPU、内存、overlayfs、socket readiness 和 layer cache I/O。 退化信号是 buildkitd 启动慢、socket unavailable、build context upload 慢、sidecar OOM 或 build step 等待 daemon。
  • hwlab-ci 本地 registry 是全并行 rebuild 后半段的共享写点,承载所有 affected service 的 layer 和 manifest push。 退化信号是 push 耗时拉长、连接 reset、5xx、blob upload timeout 或 registry Pod CPU/I/O 压力。
  • devops-infra git mirror/relay 影响 prepare-source、catalog fetch 和 gitops-promote 的固定开销。 它通常不在 build fan-out 中;退化信号是 clone/catalog 超过预算、promotion push 慢或 mirror pending/outbox 堆积。

并发回归的高风险修改必须提前识别。 build-* task 之间新增 runAfter 会把关键路径改成服务耗时求和。 把所有 build 写到同一个 report 或共享 workdir 会产生覆盖和竞态。 直接依赖 tasks.build-*.results 会让 skipped task 的结果解析变脆。 在 build task 内修改 /workspace/source/repo 会污染其他并发 task 的输入。 对不同 service 复用同一 image repo/tag 会造成 registry tag 覆盖。 把容量抖动误判为拓扑问题会导致重新串行化。 正确做法是保持 source tree 只读、每个 service 独立 workdir 和 report、每个 service 独立 image repo。 先按容量节点定位真实瓶颈,再决定是否增加资源或修 sidecar/registry/mirror。

planner 必须按 service component model 裁剪 build。tools/ 下的短连接 CLI 源码不是 runtime service 输入;skills/ 只有 agent runtime 或 skills bundle 真正消费的子目录才影响对应 runtimeHWPOD workspace tools、hwpod-clihwpod-ctlhwpod-compiler-cli 属于 Code Agent workspace/skills 分发输入,不得让 cloud-api、gateway、edge-proxy 等服务重建。CI 读取 artifact catalog 时支持 repo 相对路径和绝对路径,便于用真实 catalog 做本地热探测;catalog 缺失才允许 fail closed 到 rebuild,不得把“诊断命令没读到 catalog”误判为生产路径必须全量构建。

P1 no-op runtime skip 只跳过无实际 runtime 变化的等待。planner 输出 buildServices=[]rolloutServices=[] 后,gitops-promote 会在写入前对旧 runtime-v02 与新 render 结果做归一化比较:忽略 source commit、artifact source commit、boot commit 和等价 commit env/annotation 这类 identity-only 字段。如果归一化结果相同,promotion 输出 skipped-runtime-unchanged,把 Tekton result runtime-ready-required=false 写出,并跳过 GitOps commit、push、Argo hard refresh 和 runtime-ready。如果 workload spec、image digest、env image、SecretRef、Service、Ingress、FRP、ConfigMap 或 rollout service 有实际变化,必须保持 runtime-ready-required=true 并等待 runtime 收敛。

runtime-ready 只能观察本轮 rolloutServices 对应的 workload readiness,不能把整个 hwlab-v02 namespace 的全量 workload 都绑定到当前 source commit 后等待。复用 service 的 Deployment metadata 可以记录本次 source commit 作为 GitOps revision 线索,但 Pod template identity 必须来自该 service 的 artifact/runtime commit、boot commit 或配置内容 hash;否则 catalog 复用会被误转成不必要 rollout,runtime-ready 会被无关服务拖慢。hwlab-cloud-api 的 rollout 允许连带观察 hwlab-deepseek-proxy,因为 deepseek bridge 复用 cloud-api 镜像作为运行载体;其他连带关系必须有明确运行依赖后再加入观察集合。基础对象如 FRP、Postgres 的 Pod template 不得写入全局 source commit,应用配置 hash 或 migration hash 表达真实重启边界。

runtime-ready 的可见性优先级高于耗时优化。Task 启动后必须立即输出 runtime-ready started 事件,明确 readinessMode、观察服务数和当前 revision;等待 Argo、source commit refresh 或 workload ready 时必须周期性输出 progress 事件,包含 observedCountworkloadCount、pending/blocked 摘要或 Argo sync/health 状态。service rollout 场景继续用 rolloutServices 对应的 Pod template source commit 判定;rolloutServices=[] 但 GitOps runtime 真实变化的 infra-only 场景不得黑盒等待 source commit,应改为等待 Argo Application Synced/Healthy 和 workload generation ready,并输出 argo-sync-health 事件。禁止再出现 runtime-ready 只在 240s timeout 后才输出一条日志的不可观察状态。

触发侧也必须可见。 hwlab g14 control-plane trigger-current --lane v02 --confirm 默认作为异步 job 返回 job.idstatusCommand、stdout/stderr 路径。 同步调试使用 --wait 时,stderr 必须输出 hwlab.v02.trigger.progress JSON 事件。 事件至少覆盖 control-plane-refreshgit-mirror-pre-syncdelete-existing-pipelineruncreate-pipelinerun。 每个阶段都要有 startedsucceededfailed,并携带足够定位的信息,例如 mirror sync job、mode、PipelineRun name 或耗时。 异步 job 的 stderr tail 也必须能看到同一类进度事件。 如果 trigger 卡住但只有一条启动命令或空日志,应先修 UniDesk CLI 可见性,不要把问题推给 Tekton 或反复重跑 Pipeline。

Pipeline 内部的 no-op fast lane 必须形成完整证据链。 prepare-source 输出 source-clonecatalog-fetch timing。 plan-artifacts 输出 g14-ci-plan,其中 buildServices=[]rolloutServices=[] 且 runtime service 全部 reuse。 gitops-promote 输出 skipped-runtime-unchangedruntime-identity-only,并把 gitops-commitgitops-push 标为 skipped。 PipelineRun 的 skipped tasks 中必须包含 runtime-ready。 这条证据链缺一项时,不能只看总耗时通过,应先确认是日志缺失、planner 误判还是 GitOps runtime 比对退化。

真实 rollout 的 runtime-ready 必须 fail-closed 且可观察。 service rollout 只能等待本轮 rolloutServices 对应 workload 的 Pod template source commit 与 readiness。 infra-only runtime change 只能等待 Argo Application Synced/Healthy 和 workload generation ready。 若 runtime-ready 超时但日志里没有 startedprogressargo-refreshargo-sync-healthworkload-readyobservedCount,先按可见性回归修复日志和观察集合。 再讨论 timeout、性能或容量问题。

Kubernetes label 里的配置 hash 必须使用短 hash,完整 64 位 sha256 只能放 annotation。FRP config-sha256、Postgres migration-sha256 这类字段如果进入 Pod template label,长度必须小于 Kubernetes label value 的 63 字节上限;annotation 保留完整 hash 用于排障和人工比对。Argo sync 报 must be no more than 63 bytes 时,优先检查是否把完整 sha256 写入 label,不要通过删除 hash、放宽 sync 或忽略 OutOfSync 绕过。

快速优化不能绕过 fail-closed 语义。mirror miss、commit ancestry 不合法、boot script 缺失、digest 缺失、Argo observer RBAC 不足、workload 未 ready 或公网 health 不一致,都不能为了追求耗时而降级为 warning。允许跳过的只有已经证明 runtime desired state 没有实际变化的等待。

快速排障

触发后先看异步 job 状态,确认卡点在 UniDesk trigger、mirror pre-sync、PipelineRun 创建,还是 Tekton 内部阶段。 正常触发日志应出现 hwlab.v02.trigger.progress 事件,且阶段至少包括 control-plane-refreshgit-mirror-pre-syncdelete-existing-pipelineruncreate-pipelinerun

bun scripts/cli.ts job status <trigger-job-id> --tail-bytes 30000

如果 trigger job stderr 没有进度事件,不要直接反复触发 CI/CD。 先修 trigger 可见性或查询 .state/jobs/<jobId>.stderr.log,让等待点重新暴露出来。 mirror pre-sync 慢时看 mirror sync job 与 git-mirror statusPipelineRun 创建后才进入 Tekton 排障。

先看一次 PipelineRun 总览,确认是否是性能退化、构建退化还是 runtime 收敛失败:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get pipelinerun -n "$ns" "$pr" \
  -o jsonpath="status={.status.conditions[0].status}{\"\\n\"}reason={.status.conditions[0].reason}{\"\\n\"}message={.status.conditions[0].message}{\"\\n\"}start={.status.startTime}{\"\\n\"}done={.status.completionTime}{\"\\n\"}"
echo taskruns
kubectl get taskrun -n "$ns" -l tekton.dev/pipelineRun="$pr" \
  -o jsonpath="{range .items[*]}{.metadata.name}{\"\\t\"}{.metadata.labels.tekton\\.dev/pipelineTask}{\"\\t\"}{.status.conditions[0].status}{\"\\t\"}{.status.conditions[0].reason}{\"\\t\"}{.status.startTime}{\"\\t\"}{.status.completionTime}{\"\\n\"}{end}" | sort -k2,2
echo skipped
kubectl get pipelinerun -n "$ns" "$pr" \
  -o jsonpath="{range .status.skippedTasks[*]}{.name}{\"\\n\"}{end}" | sort
'

再抓关键日志。正常 no-op fast lane 应看到 source-clone 约 1-2s、catalog-fetch 小于 1s、所有 runtime services reuse、skipped-runtime-unchangedgitops-commitgitops-pushskipped,并且 runtime-ready 出现在 skipped tasks 中。输出中不应出现 build-hwlab-cli

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
for task in prepare-source plan-artifacts collect-artifacts gitops-promote runtime-ready; do
  tr=$(kubectl get taskrun -n "$ns" \
    -l tekton.dev/pipelineRun="$pr",tekton.dev/pipelineTask="$task" \
    -o jsonpath="{.items[0].metadata.name}" 2>/dev/null || true)
  [ -n "$tr" ] || { echo "--- $task skipped/no-taskrun ---"; continue; }
  pod=$(kubectl get pod -n "$ns" -l tekton.dev/taskRun="$tr" \
    -o jsonpath="{.items[0].metadata.name}")
  echo "--- $task $pod selected logs ---"
  pattern="skipped-runtime-unchanged|runtime-ready-required|runtime-identity-only"
  pattern="$pattern|g14-cicd-timing|git-operation|g14-ci-plan|artifact_reuse|buildSkippedCount"
  pattern="$pattern|gitops-commit|gitops-push|runtime-ready|progress|argo-refresh"
  pattern="$pattern|argo-sync-health|workload-ready|observedCount"
  kubectl logs -n "$ns" "$pod" --all-containers=true | \
    grep -E "$pattern" || true
done
'

常见故障按以下顺序处理:

现象 优先检查 处理原则
prepare-source 回到 20s 以上 日志是否出现 npm ci、npm registry probe、GitHub URL、SSH setup 或长时间 catalog fetch 拆掉无效依赖安装和重复探针;读路径必须回到 mirror。
source-clone 超过 5s PipelineRun 参数 git-read-url、mirror service、PVC I/O、git-mirror status 不要改回 GitHub 直连;先修 mirror/read service。
catalog 缺失导致全量 build prepare-source 是否从 v0.2-gitops 取到 deploy/artifact-catalog.v02.json git-mirror sync --confirm;必要时查 mirror refs/object closure。
buildSkippedCount 偏低或突然变成 0 g14-ci-planaffectedServicesbuildServicesrolloutServices、catalog 加载状态、package.json 字段 diff 和 service component path 真实业务变更可以 build;脚本清理、CLI/测试/文档、host asset 或 code-only env-reuse 变更不应误触发全量 build。
多 service rebuild 仍串行执行 tekton-v02/pipeline.yaml 中所有 build-* task 的 runAfter,以及 TaskRun startTime 是否都紧跟 plan-artifacts build task 只能依赖 plan-artifacts;发现 build-B 依赖 build-A 时直接修 render 脚本和生成物,不保留串行兼容路径。
全并行 rebuild 变慢或不稳定 TaskRun duration、Pod Pending/Unschedulable、node pressure、PVC I/O、BuildKit sidecar 日志、本地 registry push latency 优先定位资源容量或 registry/BuildKit 瓶颈;不要先把 Pipeline 拓扑改回串行或固定 8 并发。
no-op 仍执行 runtime-ready gitops-promote 是否输出 runtime-ready-required=falseskipped-runtime-unchanged 查 runtime 归一化比较;不要直接删除 runtime-ready,只修 no-op 判定。
trigger 或 mirror pre-sync 黑盒等待 job status <trigger-job-id> stderr 是否输出 hwlab.v02.trigger.progress 先恢复 trigger 进度事件;不要重复触发或手工创建 PipelineRun 绕过。
runtime-ready timeout 后才输出一条日志 是否缺少 startedprogressworkload-readyobservedCount 这是可见性回归;先修日志和观察集合,不要先加大 timeout。
mirror pendingFlush=true 长期存在 bun scripts/cli.ts hwlab g14 git-mirror status 和最近一次 flush 错误 手动 git-mirror flush --confirmflush 不影响已 rollout 本地 revision,但不能静默积压。
Argo Synced/Healthy 但公网不通 hwlab-v02-frpc 日志、master frps allowlist、19666/19667 修 FRP allowlist 或 frpc;不要把 DEV/PROD 入口当作 v02 证据。
runtime-ready 超时 Argo app revision、workload Pod template source commit、Pod events、observer RBAC 真实 rollout 必须 fail closed;先定位 Argo 或 workload,不要降低等待为 warning。

全并行故障定位先判定是拓扑退化、调度排队、资源压力还是共享写点瓶颈。 不要用一次 PipelineRun 总耗时直接得出“并发失败”结论。 必须同时看 plan-artifacts 完成时间、每个 build TaskRun 创建时间、Pod startTime、container finishTime 和 build/push 日志。

检查 live Pipeline DAG,确认所有 build task 没有互相依赖:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pipeline=hwlab-v02-ci-image-publish
kubectl get pipeline -n "$ns" "$pipeline" \
  -o jsonpath="{range .spec.tasks[*]}{.name}{\"\\t\"}{.runAfter}{\"\\n\"}{end}" | \
  grep "^build-"
'

检查一次 PipelineRun 的真实并发时间线:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get taskrun -n "$ns" -l tekton.dev/pipelineRun="$pr" \
  -o custom-columns=START:.status.startTime,DONE:.status.completionTime,\
STATUS:.status.conditions[0].status,REASON:.status.conditions[0].reason,\
TASK:.metadata.labels.tekton\\.dev/pipelineTask,NAME:.metadata.name \
  --no-headers | \
  grep -E "build-|plan-artifacts" | sort
'

检查调度和节点压力:

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
kubectl get pod -n "$ns" -l tekton.dev/pipelineRun="$pr" -o wide
kubectl get events -n "$ns" --sort-by=.lastTimestamp | tail -80
kubectl describe node | grep -E "Name:|Pressure|Allocatable|Allocated resources|cpu|memory|ephemeral-storage" || true
'

检查 BuildKit 和 registry 共享写点。 先用 TaskRun 找到对应 Pod,再分别看 build step、BuildKit sidecar 和 registry Pod 日志。 如果 build step 卡在 push 或 sidecar 等待,优先处理 registry/BuildKit/PVC,而不是修改 Pipeline 并发拓扑。

bun scripts/cli.ts ssh G14:k3s script -- 'set -eu
ns=hwlab-ci
pr=<pipeline-run-name>
task=<build-task-name>
tr=$(kubectl get taskrun -n "$ns" \
  -l tekton.dev/pipelineRun="$pr",tekton.dev/pipelineTask="$task" \
  -o jsonpath="{.items[0].metadata.name}")
pod=$(kubectl get pod -n "$ns" -l tekton.dev/taskRun="$tr" \
  -o jsonpath="{.items[0].metadata.name}")
kubectl logs -n "$ns" "$pod" --all-containers=true | \
  grep -E "buildkit|daemon|socket|push|manifest|blob|timeout|reset|no space|OOM|killed" || true
kubectl get pod -n "$ns" -o name | grep -E "registry|hwlab-registry" || true
'

并发相关故障按下表归类,避免把不同问题混成“并行不稳定”:

故障类型 判定信号 修复方向
拓扑退化 build TaskRun 的 runAfter 出现其他 build taskstartTime 严格一个接一个且没有 Pod Pending 证据。 修 render 和 live Pipeline,恢复 build task 只依赖 plan-artifacts
控制面或调度排队 plan-artifacts 完成后 TaskRun/Pod 创建分散,event 出现调度等待。 查 Tekton controller、scheduler、API latency 和 node 可用资源。
节点资源压力 Pod PendingOOMKilledEvicted、ephemeral storage 不足或 node pressure。 增加/释放资源、调整单 task resource request,不能靠串行化掩盖。
PVC 或本地磁盘瓶颈 build step 在复制 source、上传 context、写 layer 或写 report 时集体变慢。 减少共享写、确认 source tree 只读、必要时优化 service workdir 和 BuildKit 存储。
BuildKit sidecar 竞态 step 日志出现 daemon/socket not ready、sidecar OOM 或 buildkitd 异常退出。 修 sidecar readiness、资源和日志;不要把问题转成 build task 互相依赖。
registry 写瓶颈 多个 build 同时 push 时出现 5xx、reset、blob timeout 或 registry Pod 压力。 查 registry Pod、存储和网络;必要时提升 registry 资源或存储能力。
report fan-in 异常 collect-artifacts 找不到某个 service report,或多个 service 报告内容互相覆盖。 确认 report 文件名按 serviceId 隔离,失败 task 能输出明确失败报告。
skipped task 误判 selected service 正确跳过,但 collect 误读为失败或缺 digest。 保持 collect 读 catalog+report 目录,不恢复 tasks.build-*.results 硬依赖。
下游 promotion 慢 build 全部完成后才慢,日志集中在 mirror push、Argo refresh 或 runtime-ready。 按 mirror/GitOps/runtime 排障;这不是 build 并发问题。

性能退化排障结束后,只把可复用的预算、原理和入口更新到本文;一次性 PipelineRun 名称、Pod 名称、日志全文和临时证据放到 issue 或 PR,不写入长期规格。

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.yaml;发布入口不得要求人工填写 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.yaml 中 serviceId 到 boot script 的映射,默认形态为 deploy/runtime/boot/<serviceId>.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 必须失败。

HWLAB_BOOT_REF 是由 lane 的 source branch 派生的 mirror transport hint, 不属于发布身份三变量,也不得作为人工 OPS 参数。env-reuse launcher 必须先通过 HWLAB_BOOT_REF 读取 mirror 中可广告的分支/ref,再 checkout HWLAB_BOOT_COMMIT 不得直接 git fetch <sha> 依赖 smart HTTP 对 unadvertised object 的支持。 这样可以稳定支持历史 commit rollout、Argo 回滚和 env image 复用, 同时保持发布身份仍由 HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SH 三变量表达。

推荐启动形态是 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 私有 emptyDirmain container 复用同一 env image,并执行 checkout 后代码目录里的 $HWLAB_BOOT_SH。env image 只承载系统依赖、runtime、launcher、git client 和通用工具,不把业务代码或旧 boot script 当作运行真相。

service code-only 变更时,planner 必须输出 envChanged=falsecodeChanged=true,跳过 BuildKit image publish,复用上一版 env image digest,只更新 catalog 和 workload Pod template 中的 HWLAB_BOOT_COMMIT、code identity annotation 与相关 health metadata。非 service 变更必须输出空 affectedServices 或只影响自身所属的非 runtime 流程,不得为了 env reuse 触发 runtime service rollout。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-checkoutenvironmentImageenvironmentDigestenvironmentInputHashbootRepobootCommitbootShcodeInputHash 和三变量写入证据。
  • 同一 source commit 对同一 service 应生成同一镜像;lane 差异放在 manifest、env、SecretRef、namespace、FRP 和 DB 配置中,不 bake 进镜像。
  • deploy/deploy.yaml 只承载人写 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-v02destination 必须是 hwlab-v02
  • hwlab-v02-frpc 只能暴露 19666/19667,不能复用 17666/1766718666/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-gitopsv0.2-gitops

硬边界

以下边界是 v0.2 CI/CD 的最小硬约束:

  • source branch 必须是 v0.2
  • PR 自动 CD 只能观察和合并 base=v0.2 的 PR;其他 base branch 不得触发 v02 runtime rollout。
  • 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.jsondeploy/gitops/g14/runtime-v02/** 变更。
  • source workspace 下若残留 ignored deploy/gitops/g14/runtime-v02/** 生成物,不能作为 source diff、PR 内容、回归证据或人工修补目标;发现和当前 v0.2-gitops 不一致时删除本地缓存。
  • GitOps promotion 的 changed paths 只能落在 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/** 及必要的 v02 Argo/GitOps 元数据。
  • 公网验收只能使用 19666/19667
  • v0.2 不得创建或依赖 k8s CronJobhwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 或同类调度器出现时应清理,而不是接入发布链路。
  • GitHub webhook 不是 v02 首期自动 CD 的必需入口;若未来接入,只能作为唤醒信号,不能直接决定发布 commit 或创建 PipelineRun。
  • 自动 CD、手动 trigger 和 once 补偿都必须复用 UniDesk trigger-current、定点 statusgit-mirror flush;不得绕到裸 kubectl、Argo、Tekton 或手写 GitHub API。
  • 旧 DEV/D601/main gate、fallback、legacy mode 和双路径兼容不得进入 v0.2 调用链。
  • env 容器复用 fast lane 中,HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SH 必须由 CI/CD 自动推导并写入 GitOps desired state,不得作为人工发布参数或 runtime 临时 patch。
  • deploy/deploy.yaml 只保存人写运行意图,不得被 auto-CD、promotion 或 flush 回写 commitId、service imageHWLAB_COMMIT_IDHWLAB_IMAGEHWLAB_IMAGE_TAG 等发布产物字段。
  • 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 pathpromotion 断言 GitOps branch/changed pathsArgo 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-devhwlab-prod namespace。
  • hwlab-g14-devhwlab-g14-prod Argo Application。
  • DEV 17666/17667 与 PROD 18666/18667 FRP 入口。
  • D601 legacy 回溯路径和旧运行面边界。

如果 v0.2 接入失败,回滚或暂停只能作用于 hwlab-v02 lane:停止 UniDesk v02 monitor、停止手动触发新的 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-publishhwlab-v02-tekton-runner;不存在 v02 CronJob。hwlab-v02-branch-pollerhwlab-v02-control-plane-reconciler 不再作为 v02 标准对象,若历史残留应由 UniDesk control-plane apply 清理。
  • base=v0.2 的 ready PR 由 UniDesk CLI 合并后,会自动触发对应 merge head 的 v02 PipelineRun;其他 commit 的运行中 PipelineRun 不阻塞 ready PR merge 或 CI 启动。
  • 同一个 source commit 已有 PipelineRun 时不重复创建,也不删除重建;失败 run 的人工重试必须走后续显式 retry 策略,不恢复默认 delete/create。
  • 自动 CD 在旧 run 运行期间遇到新 origin/v0.2 head 时,新 head 可直接触发自己的 PipelineRun;旧 run 继续完成 CI,但 promotion 必须在写 GitOps 前发现 stale head 并 superseded/no-op,不能回写旧 v0.2-gitops 或回滚 runtime。
  • 最新 v0.2 source commit 对应的 PipelineRun 完成,且 promotion 写入 v0.2-gitops
  • v0.2-gitops 中存在 deploy/artifact-catalog.v02.jsondeploy/gitops/g14/runtime-v02/**
  • argocd/hwlab-g14-v02 指向 devops-infra 本地 mirror/relay 的 v0.2-gitops:deploy/gitops/g14/runtime-v02sync 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 已完成,但 auto-CD 收口必须在 pendingFlush=true 时触发 flush 并最终观察到 pendingFlush=false
  • runtime-ready 必须以 workload Pod template 的 source commit 判断 Argo 刷新,并在 Argo 刷新超时、observer RBAC 不足或 workload 未就绪时失败;不得把 CrashLoop、未刷新或公网不可用的 runtime 标成绿色。
  • 启用 env 容器复用的 runtime service 必须在 catalog、Pod template annotation/env 和 /health/live 或等价 runtime identity 中同时暴露 env image digest 与 HWLAB_BOOT_REPO/HWLAB_BOOT_COMMIT/HWLAB_BOOT_SH;只暴露镜像 digest 不能证明 service code-only rollout 已生效。
  • code-only rollout 的 PipelineRun 必须能证明没有发布新 env image、复用了上一版 env digest、只更新 boot commit/code identity,并由 Kubernetes Pod template hash 触发滚动。
  • 非 service 资产变更必须能证明没有因为 env reuse 触发 runtime service build 或 rollout;典型非 service 资产包括 tools/hwlab-cli*、CaseRun runner/helper、.hwlab/ workspace spec、docs 和 tests。
  • 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 healthpayload 中的 namespace、revision 或 runtime identity 能与 hwlab-v02/v0.2 对齐。
  • trigger-current 的异步 job 或 --wait 输出必须能显示 trigger 阶段进度;若 control-plane refresh、mirror pre-sync 或 delete/create PipelineRun 卡住,日志必须能定位阶段名和状态。
  • 自动 CD 回写 PR 或关联 issue 的 rollout 评论必须包含 source commit、PipelineRun、GitOps revision、planArtifacts build/reuse 摘要、Argo/runtime/public probe 状态和耗时;该评论不能替代需要用户原入口验收的问题关闭证据。
  • 自动 CD 过程中 source branch 的 deploy/deploy.yaml 不得出现 commitId、service imageHWLAB_COMMIT_IDHWLAB_IMAGEHWLAB_IMAGE_TAG 回写。
  • no-op env-reuse fast lane 必须输出完整证据链:g14-ci-plan 全复用、skipped-runtime-unchangedgitops-commit/gitops-push skipped、runtime-ready skipped。 不能只用 PipelineRun Completed 或总耗时证明没有退化。
  • 真实 rollout 的 runtime-ready 必须输出 started、周期性 progress 和最终 argo-refresh/argo-sync-health/workload-ready 类事件;缺少这些事件时应按可见性回归处理。
  • Bun 语法检查和测试入口必须分开:bun --check <file.ts> 只用于非测试 TypeScript 源文件语法/转译检查;*.test.ts*.test.mts 或其他使用 test(...) 的文件必须用 bun test <file> 或 repo-owned package script 执行。不得再用 bun --check 直接跑 .test.ts,该命令会在测试运行器外求值并报 Cannot use test outside of the test runner,这不是业务回归证据。

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.jsondeploy/gitops/g14/runtime-v02/** 生成物。

T2

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:查询 Argo hwlab-g14-v02,确认 source repo 为 devops-infra 本地 mirror/relaybranch/path 为 v0.2-gitops:deploy/gitops/g14/runtime-v02destination namespace 为 hwlab-v02sync 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/livecodeAgent=ready 证明 provider 鉴权通过。

T5

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:对启用 env 容器复用的服务触发一次 code-only commit,确认 PipelineRun 标记 envChanged=false、复用上一版 env digest、catalog 与 Pod template 写入 HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SHruntime 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/relayArgo 从本地 mirror/relay rollout;再执行 git-mirror flush --confirm,确认 GitHub origin/v0.2-gitops 快进到同一 revisionstatus 中 pending 清空。

T8

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:在 v0.2 source checkout 或对应 PipelineRun primitive validation 日志中确认 bun run --cwd web/hwlab-cloud-web check 会在 hwlab-cloud-web 镜像发布前执行,并且该 check 包含实际 bundle 输入集合的 TypeScript 语义检查、自动发现的 *.test.ts 单元测试、bundle build 和 dist freshness 校验。

T9

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:确认默认 v0.2 CI 没有重新加入 Playwright、旧 layout smoke、旧 quick prompt、旧 M3 evidence 或 DEV/D601 browser gate;若这些旧门禁重新进入最小 check plan 或 PipelineRun,应直接删除入口并保留 Cloud Web semantic check 与单元测试。

T10

阅读 docs/reference/spec-v02-cicd.md,然后用 cli 手动测试以下内容:用一个低风险 base=v0.2 PR 验证 UniDesk v02 PR monitor 的端到端链路,确认 merge 后自动触发对应 merge head 的 hwlab-v02-ci-poll-<short12>,定点 status 通过,pendingFlush=true 时自动 flushPR 或关联 issue 评论包含 source commit、PipelineRun、GitOps revision、build/reuse 摘要、Argo/runtime/public probe 状态和耗时,且 deploy/deploy.yaml 没有发布产物回写。

规格的实现情况

规格项 状态 说明
v02 独立 source/GitOps/runtime lane 已实现 v0.2v0.2-gitopshwlab-v02runtime-v02 已固定。
手动 CLI trigger/pipeline/promotion 已实现 通过 UniDesk trigger-current 创建 commit-pinned PipelineRunv02 不设 CronJob,由 hwlab-v02-ci-image-publish 与 GitOps promotion 管理。
PR merge 后自动 CD 待迁移 目标见 #848UniDesk CLI v02 PR monitor 合并 base=v0.2 PR 后复用 trigger-current、定点 statusgit-mirror flush;首期不要求 GitHub webhook,也不创建 k8s CronJob。
v02 runtime readiness fail-closed 已实现 gitops-promote 推送后触发 Argo hard refreshruntime-ready 读取 workload Pod template source committimeout、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 容器复用三变量启动 已实现/持续约束 五个 v0.2 runtime service 均启用 env-reuse fast lane,并由 CI/CD 自动推导 HWLAB_BOOT_REPOHWLAB_BOOT_COMMITHWLAB_BOOT_SHservice code-only rollout 复用 env image digest,只更新代码身份。
非 service 资产不触发 env reuse 已实现/持续约束 CLI、CaseRun、HWPOD workspace 工具、.hwlab/、docs 和 tests 不进入 env-reuse service 触发面;被服务直接 import 的文件必须显式挂到对应 service component path。
devops-infra git mirror/relay 加速 已实现/持续约束 source/catalog/runtime checkout 读路径和 GitOps promotion 写路径均使用独立基础设施集群 mirror/relayArgo source 指向本地 mirrorGitHub flush 由 UniDesk CLI 手动触发,不设置 CronJob。runtime namespace 不持有 GitHub deploy keyregistry 保持 G14 hwlab-ci/hwlab-registry
hwlab-cli 不进 CI/CD service matrix 已实现/持续约束 CLI 是固定 repo 短连接 client,不发布镜像、不生成 artifact、不创建 build-hwlab-cli TaskRun;相关旧入口出现时直接删除。
CI/CD fast lane 性能预算 已实现/持续约束 env-reuse no-op 目标约 40s;真实 runtime rollout 目标约 50s;不得恢复 prepare-source 依赖安装、GitHub 关键路径写入或 no-op runtime 等待。
Service build 全并行 fan-out 已实现/持续约束 selected services 的 build TaskRun 全部只依赖 plan-artifacts,不设置 8 并发或其他 Pipeline 级限流;collect-artifacts 通过 service report 目录 fan-in。
自动 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_KEYSecret 更新后必须滚动 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/livecodeAgent=readycodexStdio=ready 只能证明运行时结构、二进制、workspace、token boundary 和会话 supervisor 就绪;它不证明真实 provider 鉴权可用。涉及 Code Agent 的扩容验收必须追加一次真实短连接聊天闭环:用 Prefer: respond-asyncX-HWLAB-Short-Connection: 1 提交 /v1/agent/chat,再轮询 /v1/agent/chat/result/<traceId>,只有 status=completed 且 assistant reply 非空才算通过。

如果 trace 里出现 Authentication Failsupstream stream errorcodex_stdio_provider_retry,先按 profile 分层判断:deepseek profile 走 hwlab-deepseek-proxy.<namespace>.svc.cluster.local:4000/v1/responses 和 Moon Bridgecodex-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/liveenvironmentendpoint关键 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/CDsource 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 证明可行的配置和源码。