docs: enforce PR-merge automatic delivery

This commit is contained in:
Codex
2026-07-11 08:12:00 +02:00
parent 0e8ffe58d6
commit a7823cf919
8 changed files with 221 additions and 55 deletions
+15 -11
View File
@@ -22,7 +22,6 @@ bun scripts/cli.ts platform-infra gitea mirror status --target JD01
bun scripts/cli.ts platform-infra gitea mirror webhook status --target JD01
bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01
bun scripts/cli.ts platform-infra pipelines-as-code status --target JD01 --consumer hwlab-jd01-v03
bun scripts/cli.ts platform-infra pipelines-as-code closeout --target JD01 --consumer <consumer> --source-commit <sha> --wait
bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 --limit 10
bun scripts/cli.ts platform-infra pipelines-as-code history --target JD01 --id <pipelinerun>
bun scripts/cli.ts platform-infra pipelines-as-code debug-step --target JD01 --consumer <consumer>
@@ -47,9 +46,14 @@ bun scripts/cli.ts platform-infra pipelines-as-code source-artifact verify-runti
## P0 边界
- CI/CD、GitOps、rollout、PipelineRun、Argo、git-mirror 和 AgentRun 部署必须走受控 CLI;不要用裸 `kubectl``argo``tkn``curl` 当正式控制入口
- CI/CD source authority 只能来自 YAML 声明的 Kubernetes 托管 source authoritylegacy lane 使用 k8s git-mirror snapshotGitea/PaC migrated lane 使用 GitHub PR merge -> GitHub webhook bridge -> Gitea controlled mirror + immutable snapshot ref -> Pipelines-as-Code。受控命令先在 k8s 内同步/创建不可变 `refs/unidesk/snapshots/.../<commit>` stage refbuild/status/publish 只消费该 snapshothost worktree、本地 `git fetch/pull`、可变 branch ref 或 Pipeline 内直连 GitHub 都不能作为 authoritative source
- JD01/NC01 `agentrun-<node>-v02``sentinel-<node>-v03``hwlab-<node>-v03` 的正式 CI/CD closeout 入口是 `cicd status --node <NODE>``platform-infra pipelines-as-code closeout|status|history --target <NODE> --consumer <id>``closeout` 是通用 consumer 引导入口,只读取/等待 PaC、Tekton、GitOps、Argo 和 runtime 对齐,不触发旧手动发布。`cicd branch-follower``cicd gitea-actions-poc` 对这些 consumer 只保留历史/迁移只读用途,不得作为当前交付判断入口
- PaC migrated consumer 的唯一正式 CI/CD 触发是目标 source branch 的 GitHub PR merge。合并后由 GitHub webhook -> Gitea controlled mirror + immutable snapshot ref -> Gitea webhook -> PaC -> Tekton -> GitOps/Argo -> runtime 自动滚动;不得要求主代理、子代理或操作者再执行 apply、closeout、trigger、sync、flush 或补跑
- 自动链路不通时必须修复自动链自身,并通过修复 PR 合并产生的新正常事件验收。禁止人工 mirror sync、直接 Gitea push、人工 PipelineRun、`trigger-current`、运行面 patch 或其他手段补齐当前交付;只读 status/history/events/logs/closeout/debug-step 可用于定位,但不得改变交付状态
- CI/CD、GitOps、rollout、PipelineRun、Argo、git-mirror 和 AgentRun 的观察、诊断与 legacy 控制必须走受控 CLI;不要用裸 `kubectl``argo``tkn``curl` 当正式控制入口。PaC migrated consumer 仍只由 GitHub PR merge 触发,不得因“必须走 CLI”而额外调用写命令
- CI/CD source authority 只能来自 YAML 声明的 Kubernetes 托管 source authority
- legacy lane 由受控命令在 k8s 内同步并创建不可变 `refs/unidesk/snapshots/.../<commit>` stage ref
- Gitea/PaC migrated lane 由 GitHub PR merge 自动驱动 GitHub webhook bridge、Gitea controlled mirror 与 immutable snapshot ref,禁止合并后人工同步或创建 snapshot;
- build/status/publish 只消费对应 snapshothost worktree、本地 `git fetch/pull`、可变 branch ref 或 Pipeline 内直连 GitHub 都不能作为 authoritative source。
- JD01/NC01 `agentrun-<node>-v02``sentinel-<node>-v03``hwlab-<node>-v03` 的交付收口由自动链自行完成并写入状态。仅在显式调查自动链故障时读取 `cicd status --node <NODE>``platform-infra pipelines-as-code status|history --target <NODE> --consumer <id>`;主代理与子代理不得把 `closeout` 当作 PR 合并后的人工步骤。`cicd branch-follower``cicd gitea-actions-poc` 对这些 consumer 只保留历史/迁移只读用途。
- PaC `.tekton` 文件必须用 Repository CR 的 target/node 参数隔离 JD01/NC01,避免同一个 Gitea push 在一个 target cluster 内额外创建另一个 target 的 PipelineRunhistory/detail 必须按实际 PipelineRun prefix/pipeline 归属 consumer。
- PaC source artifact 必须遵循以下边界:
-`config/platform-infra/pipelines-as-code.yaml#consumers[].sourceArtifact` 显式声明;
@@ -73,16 +77,16 @@ bun scripts/cli.ts platform-infra pipelines-as-code source-artifact verify-runti
- 该入口只读且 `mutation=false`,不能创建 PipelineRun 或写 GitOps/runtime
- 未带 `--id` 时才只运行 evaluator fixture。
- GitHub/Git 相关 egress 必须走 YAML-first host proxy/sourceRefbranch-follower controller 读 `config/cicd-branch-followers.yaml#controller.source.githubSsh`runtime legacy git-mirror 读 owning lane/control-plane YAML 的 host proxy 和 `githubTransport`Gitea/PaC 迁移 lane 读 `config/platform-infra/gitea.yaml``config/platform-infra/pipelines-as-code.yaml`;禁止依赖未声明 host env、trans proxy、裸直连 GitHub 或 CLI 输出解析。
- Gitea/PaC lane 的 GitHub -> Gitea 自动同步必须用 `platform-infra gitea mirror webhook apply|status|test`。该路径是单向同步,只更新 Gitea branch 和 immutable snapshot ref不得引入 Gitea -> GitHub 回写、轮询 fallback、Gitea Actions/act_runner fallback 或第二套状态存储。
- Gitea webhook/FRPC/Caddy 变更的 closeout 必须看受控 CLI 的 rollout/status/test 证据;Secret 或 ConfigMap apply 成功不等于 connector Pod 已加载新 proxy/path。
- Gitea/PaC lane 的 GitHub -> Gitea 自动同步由 owning YAML 渲染的 webhook bridge 承担,只更新 Gitea branch 和 immutable snapshot ref。`platform-infra gitea mirror webhook status|test` 只用于观察和单步诊断;`apply` 仅属于首次平台 bootstrap,不得用于 source PR 合并后的交付或恢复。不得引入 Gitea -> GitHub 回写、轮询 fallback、Gitea Actions/act_runner fallback 或第二套状态存储。
- Gitea webhook/FRPC/Caddy 自动链变更的 closeout 必须观察修复 PR 合并后的 rollout/status/test 证据;Secret 或 ConfigMap 声明已生成不等于 connector Pod 已加载新 proxy/path,也不得用人工 apply 补齐
- `cicd branch-follower` 的自动跟随全过程不得读取或挂载 host worktree、target dev dir、`.worktree/*` 或 local git checkoutcontroller pod/一次性 reconcile Job 只能用 k8s git-mirror cache、Tekton PipelineRun、Argo Application、runtime workload 和 EmptyDir 执行,状态以 K8s ConfigMap/Lease 承载的 native observation 为准,不得解析下游 CLI 输出。
- k8s 运行面从拉取已构建镜像开始必须 0 Docker;CI 构建面可以使用 YAML 声明的原生构建工具,但不得把 Docker socket、Docker daemon 或 host Docker 带入运行面。
- 正式 CI/CD、publish、image build 和 rollout 必须走 Tekton Task/Pipeline/PipelineRun 承担 CI,并通过 GitOps/Argo 承担部署收敛;普通 Kubernetes Job 只允许用于 bounded helper、source sync、diagnostic、cleanup 或 bootstrap,不得作为正式发布、镜像构建或 rollout 入口。
- 正式 CI/CD 必须提供一键完成入口:同一受控命令完成 source sync、构建、发布、GitOps/Argo 收敛、runtime provenance 校验和 `/health` 端点验证;不要要求操作者手动串联多个 publish/apply/status 命令才能完成一次交付
- CI/CD 一键交付的端到端 wall-clock 目标是低于 2 分钟;计时从操作者触发受控命令开始,到 runtime ready 且 `/health` 端点验证完成为止。具体 wait/timeout/budget 字段必须从 YAML/source-of-truth 读取并配置到满足该目标。
- 未迁移的 legacy CI/CD 若仍保留人工入口,必须由单一受控命令完成 source sync、构建、发布、GitOps/Argo 收敛、runtime provenance 校验和 `/health` 端点验证。PaC migrated consumer 不得使用该人工入口,其唯一交付触发是 GitHub PR merge
- CI/CD 端到端 wall-clock 目标及预算只由 owning YAML 声明;PaC migrated consumer 从 GitHub PR merge 事件计时,legacy lane 才从操作者触发受控命令计时,均到 runtime ready 且 `/health` 端点验证完成为止。
- CI/CD validation 阶段只能验证部署对象的 `/health` 端点和必要 provenance;禁止在 CI/CD gate 中运行 web-probe、Playwright、远程浏览器截图、用户路径 E2E 或等价重型业务探针。业务/用户入口验证只能作为发布后的独立 post-deploy validation 证据,不得阻塞 CI/CD 一键交付。
- 任一 CI/CD 阶段或总耗时超过 2 分钟时,不要继续死等或把超长等待视为正常;先输出阶段耗时分解,并优先从 env reuse、git mirror、BuildKit/cache、GitOps/Argo watch 和 runtime readiness 探测方向优化后再继续交付。
- node-scoped `trigger-current --wait` 必须把 source sync、pre/post flush、PipelineRun、GitOps/Argo、runtime readiness 和 `/health` closeout 放进同一 120s 端到端预算;超预算时由 CLI 输出阶段分解、Argo target revision、runtime/public 状态和 TaskRun/Pod drill-down,不继续死等,也不要求操作者手动串联多个状态/flush 命令才能完成一次交付。
- 任一 CI/CD 阶段或总耗时超过 owning YAML 预算时,不要继续死等或把超长等待视为正常;先输出阶段耗时分解,并优先从 env reuse、git mirror、BuildKit/cache、GitOps/Argo watch 和 runtime readiness 探测方向优化后再继续交付。
- 仅 legacy lane 的 node-scoped `trigger-current --wait` 可以把 source sync、pre/post flush、PipelineRun、GitOps/Argo、runtime readiness 和 `/health` closeout 放进同一端到端 YAML 预算;超预算时由 CLI 输出阶段分解、Argo target revision、runtime/public 状态和 TaskRun/Pod drill-down。PaC migrated consumer 禁止执行 `trigger-current`,也禁止手动串联状态、sync 或 flush 命令补齐交付。
- node-scoped `control-plane status` 可见性规则:
- 必须立即输出 started/阶段,并按 owning YAML 输出 heartbeat
- 正常、总预算超时、中断和 worker 失败都要返回有界 closeout
@@ -97,7 +101,7 @@ bun scripts/cli.ts platform-infra pipelines-as-code source-artifact verify-runti
- CI/CD 验证、测试和性能度量必须在目标 NODE/k8s 内执行,尤其是 branch-follower、Tekton/Argo、runtime reuse/env reuse、git mirror 和 runtime-ready 相关改动;不要在 master/local host 跑 test 或用本地验证结果替代目标运行面证据。本机只用于源码阅读、编辑和必要静态语法检查,正式收敛结论必须来自目标 NODE 计算出的短摘要。
- in-cluster/controller/native helper 不能假设镜像内存在 `kubectl` binary。目标 Pod/Job 内读取或写入 Kubernetes 对象必须走 serviceaccount token + Kubernetes HTTPS API 或已封装的 native helper`kubectl` 只允许在 operator 侧受控 CLI/trans 边界作为 transport/debug 包装,不得进入正式 controller 状态读写链路。
- 一旦发现 CI/CD CLI 被误用且可能写入错误状态、产生伪证据或绕过目标运行面,必须立刻先把用法改成更符合直觉的公开入口并更新本 skill/reference,再继续验证或交付;不要只靠口头记忆、隐藏 flag、手动约定或后续小心来避免复发。内部 in-cluster 模式必须只由目标 k8s Job/Pod 调用,操作者从本机只能用公开入口提交目标侧 Job 或读取目标侧摘要。
- JD01 migrated consumer 的旧手动 publish/debug 命令不得作为正式 closeout 引导;正式 CLI 输出默认必须指向通用 `platform-infra pipelines-as-code closeout|status|history`。需要保留的旧命令只能标为 debug/test/recovery 单步,且 manual recovery 必须显式说明原因
- PaC migrated consumer 的旧手动 publish/debug 命令不得作为正式 closeout 引导;调查命令默认只能指向只读的 `platform-infra pipelines-as-code status|history``closeout` 仅保留只读兼容能力,不得作为主代理、子代理或操作者的 PR 合并后步骤。需要保留的旧命令只能 debug/test 单步,不得标记或引导 manual recovery;单步确认的自动链缺陷必须回到 YAML/controller/源码修复
- Secret 只通过 YAML sourceRef/targetKey 和受控 CLI 下发;输出只披露 presence/fingerprint。
- 长命令用异步 job 或短轮询;不要长时间挂住 trans/ssh。
@@ -1,22 +1,24 @@
# Gitea + Pipelines-as-Code
Gitea/Pipelines-as-Code migrated CI/CD uses one formal path:
Gitea/Pipelines-as-Code 迁移后的 CI/CD 只有一条正式路径:
```text
GitHub PR merge -> GitHub webhook bridge -> Gitea controlled mirror and immutable snapshot refs -> Gitea Repository webhook -> Pipelines-as-Code -> Tekton PipelineRun -> GitOps/Argo -> k8s runtime
```
GitHub remains the upstream write authority. A delivery should be triggered by merging the GitHub PR into the consumer's YAML-declared source branch, then observing the target node's Gitea mirror, PaC, Tekton, GitOps, Argo and runtime status. Do not replace this with Gitea Actions, `act_runner`, branch-follower, host worktree, direct GitHub-in-Pipeline, direct Gitea pushes, manual PipelineRun creation, `trigger-current`, `webhook-test`, or custom script fallback. Gitea Actions material under `config/cicd-gitea-actions-poc.yaml` is archived read-only POC context only; `webhook-test` is only a connectivity diagnostic.
GitHub 是唯一上游写入权威。目标 source branch 的 GitHub PR merge 是唯一正式交付触发事件;合并后必须由 webhook、mirrorPaCTektonGitOps/Argo 自动推进到运行面,无需主代理、子代理或操作者执行任何 apply、closeout、trigger、sync、flush 或补跑。状态与历史命令只能观察和诊断,不能推进交付。
## Source Of Truth
自动链任一环节不通时,任务目标是修复该环节的 YAML、controller 或源码,并以修复 PR 合并后产生的新自动链事件作为验收证据。禁止用 Gitea Actions、`act_runner`、branch-follower、host worktree、Pipeline 内直连 GitHub、直接 Gitea push、人工 mirror sync、人工 PipelineRun、`trigger-current``webhook-test` 或自定义脚本补齐当前交付。`config/cicd-gitea-actions-poc.yaml` 只保留只读历史材料;`webhook-test` 只允许诊断连通性。
- Gitea source authority, GitHub webhook bridge, public exposure and source snapshots: `config/platform-infra/gitea.yaml`.
- PaC controller, Repository CRs, consumer parameters, Tekton pipeline names and Argo applications: `config/platform-infra/pipelines-as-code.yaml`.
- Historical snapshot prefixes containing `gitea-actions` are retained only for existing refs. They do not mean Gitea Actions is the active trigger architecture.
- Node-level status for these consumers is `bun scripts/cli.ts cicd status --node <NODE>`. Consumer drill-down is `platform-infra pipelines-as-code status|history|closeout --target <NODE> --consumer <id>`.
- Multi-node PaC consumers that share a GitHub upstream must not share a webhook bridge URL. Each target node declares its own GitHub webhook public path and FRP remote port in `config/platform-infra/gitea.yaml#targets[].webhookSync`, then `platform-infra gitea apply --target <NODE> --confirm` renders the node-local bridge, FRPC proxy and PK01 Caddy path.
- PaC Repository CR `spec.url` matches the URL in Gitea webhook payloads. Keep `config/platform-infra/pipelines-as-code.yaml#repositories[].url` on the public Gitea repository URL, and keep k8s-internal service URLs only in `cloneUrl` or `params.git_read_url`; otherwise PaC logs `cannot find a repository match` and no PipelineRun is created.
- Repositories shared by JD01 and NC01 must pass a target-specific `node` Repository param, and each `.tekton` PipelineRun must filter on that param with `pipelinesascode.tekton.dev/on-cel-expression`. A push for one target must not create the other target's PipelineRun in the same target cluster.
## 唯一事实来源
- Gitea source authority、GitHub webhook bridge、公网暴露与 source snapshot 归属 `config/platform-infra/gitea.yaml`
- PaC controller、Repository CR、consumer 参数、Tekton pipeline 名称与 Argo Application 归属 `config/platform-infra/pipelines-as-code.yaml`
- 包含 `gitea-actions` 的历史 snapshot prefix 只为既有 ref 保留,不代表 Gitea Actions 仍是有效触发架构。
- node 级状态入口是 `bun scripts/cli.ts cicd status --node <NODE>`consumer 级下钻入口是 `platform-infra pipelines-as-code status|history|closeout --target <NODE> --consumer <id>`
- 共用 GitHub 上游的多 node PaC consumer 不得共用 webhook bridge URL。每个 target node 在 `config/platform-infra/gitea.yaml#targets[].webhookSync` 声明自己的 GitHub webhook 公网路径与 FRP remote port,并由平台自动交付渲染 node-local bridge、FRPC proxy 和 PK01 Caddy 路径;禁止在 source PR 合并后人工 apply 补齐。
- PaC Repository CR `spec.url` 必须与 Gitea webhook payload 中的 URL 一致。`config/platform-infra/pipelines-as-code.yaml#repositories[].url` 保持公网 Gitea repository URLk8s 内网 service URL 只能写入 `cloneUrl``params.git_read_url`;否则 PaC 会记录 `cannot find a repository match` 且不会创建 PipelineRun。
- JD01 与 NC01 共用的 repository 必须传入 target-specific `node` Repository param,每个 `.tekton` PipelineRun 必须用 `pipelinesascode.tekton.dev/on-cel-expression` 过滤该参数。一个 target 的 push 不得在同一 target cluster 创建另一 target 的 PipelineRun。
## PaC 源码侧制品同步
@@ -31,6 +33,7 @@ bun scripts/cli.ts platform-infra pipelines-as-code source-artifact verify-runti
```
- `config/platform-infra/pipelines-as-code.yaml#consumers[].sourceArtifact` 是生成职责的声明入口;未声明的 consumer 必须稳定拒绝,模板不得替它发明 owner。
- `source-artifact plan|check|write` 只能在 source PR 合并前生成或校验该 PR 的受管源码制品,不是合并后的 CI/CD 触发、同步、恢复或补跑入口。
- desired 只来自 owning YAML 与共享 domain rendererlive Pipeline 和 PipelineRun 只能作为只读诊断证据,禁止从运行面反向导出 desired 或源码制品。
- `plan``check``write` 只比较或更新显式消费仓 worktree,不访问运行面;worktree 必须是绝对路径、Git 根目录,并与声明仓库的精确 remote identity 一致。
- `write` 先完成全部路径、内容和 renderer 合同校验,再通过同目录临时文件与 rename 更新;连续执行必须无差异。
@@ -54,53 +57,55 @@ bun scripts/cli.ts platform-infra pipelines-as-code source-artifact verify-runti
- 不得在通用生成器中用字符串 marker 扫描建立第二真相。
- AgentRun source artifact 通过完整 owning Pipeline 与完整 spec 比较保留 RBAC、参数和 manager 环境合同。
## Coverage Matrix
## 覆盖矩阵
| Consumer | Source | PaC namespace | Pipeline | Argo application | Status |
| Consumer | Source | PaC namespace | Pipeline | Argo Application | 状态命令 |
|---|---|---|---|---|---|
| `agentrun-jd01-v02` | `pikasTech/agentrun@v0.2` | `agentrun-ci` | `agentrun-jd01-v02-ci-image-publish` | `agentrun-jd01-v02` | `platform-infra pipelines-as-code closeout --target JD01 --consumer agentrun-jd01-v02 --source-commit <sha> --wait` |
| `sentinel-jd01-v03` | `pikasTech/unidesk@master` | `devops-infra` | `hwlab-web-probe-sentinel-jd01-pac` | `hwlab-web-probe-sentinel-jd01` | `platform-infra pipelines-as-code closeout --target JD01 --consumer sentinel-jd01-v03 --source-commit <sha> --wait` |
| `hwlab-jd01-v03` | `pikasTech/HWLAB@v0.3` | `hwlab-ci` | `hwlab-jd01-v03-ci-image-publish` | `hwlab-node-v03` | `platform-infra pipelines-as-code closeout --target JD01 --consumer hwlab-jd01-v03 --source-commit <sha> --wait` |
| `agentrun-nc01-v02` | `pikasTech/agentrun@v0.2` | `agentrun-ci` | `agentrun-nc01-v02-ci-image-publish` | `agentrun-nc01-v02` | `platform-infra pipelines-as-code closeout --target NC01 --consumer agentrun-nc01-v02 --source-commit <sha> --wait` |
| `sentinel-nc01-v03` | `pikasTech/unidesk@master` | `devops-infra` | `hwlab-web-probe-sentinel-nc01-pac` | `hwlab-web-probe-sentinel-nc01` | `platform-infra pipelines-as-code closeout --target NC01 --consumer sentinel-nc01-v03 --source-commit <sha> --wait` |
| `hwlab-nc01-v03` | `pikasTech/HWLAB@v0.3` | `hwlab-ci` | `hwlab-nc01-v03-ci-image-publish` | `hwlab-node-v03` | `platform-infra pipelines-as-code closeout --target NC01 --consumer hwlab-nc01-v03 --source-commit <sha> --wait` |
| `agentrun-jd01-v02` | `pikasTech/agentrun@v0.2` | `agentrun-ci` | `agentrun-jd01-v02-ci-image-publish` | `agentrun-jd01-v02` | `platform-infra pipelines-as-code status --target JD01 --consumer agentrun-jd01-v02` |
| `sentinel-jd01-v03` | `pikasTech/unidesk@master` | `devops-infra` | `hwlab-web-probe-sentinel-jd01-pac` | `hwlab-web-probe-sentinel-jd01` | `platform-infra pipelines-as-code status --target JD01 --consumer sentinel-jd01-v03` |
| `hwlab-jd01-v03` | `pikasTech/HWLAB@v0.3` | `hwlab-ci` | `hwlab-jd01-v03-ci-image-publish` | `hwlab-node-v03` | `platform-infra pipelines-as-code status --target JD01 --consumer hwlab-jd01-v03` |
| `agentrun-nc01-v02` | `pikasTech/agentrun@v0.2` | `agentrun-ci` | `agentrun-nc01-v02-ci-image-publish` | `agentrun-nc01-v02` | `platform-infra pipelines-as-code status --target NC01 --consumer agentrun-nc01-v02` |
| `sentinel-nc01-v03` | `pikasTech/unidesk@master` | `devops-infra` | `hwlab-web-probe-sentinel-nc01-pac` | `hwlab-web-probe-sentinel-nc01` | `platform-infra pipelines-as-code status --target NC01 --consumer sentinel-nc01-v03` |
| `hwlab-nc01-v03` | `pikasTech/HWLAB@v0.3` | `hwlab-ci` | `hwlab-nc01-v03-ci-image-publish` | `hwlab-node-v03` | `platform-infra pipelines-as-code status --target NC01 --consumer hwlab-nc01-v03` |
Use `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --limit 10` for all-consumer trigger, timing and reuse audit. It must read live Gitea Repository CR plus Tekton PipelineRun/TaskRun objects on the target node, aggregate on the target side, and print `READ_ERRORS`.
`history --id <pipelinerun>` must still apply the consumer's actual PipelineRun prefix or Tekton pipeline match, so a PipelineRun in a shared namespace cannot be attributed to both JD01 and NC01 consumers.
使用 `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --limit 10` 审计全部 consumer 的触发、耗时与 reuse。命令必须读取 target node 上的实时 Gitea Repository CR Tekton PipelineRun/TaskRun,在 target 侧聚合并显式输出 `READ_ERRORS`
## Closeout Order
`history --id <pipelinerun>` 必须继续使用 consumer 实际 PipelineRun prefix 或 Tekton pipeline 归属匹配,避免共享 namespace 中的同一 PipelineRun 被同时归属到 JD01 和 NC01 consumer。
1. `bun scripts/cli.ts platform-infra gitea mirror status --target <NODE>`
2. `bun scripts/cli.ts platform-infra gitea mirror webhook status --target <NODE>`
3. `bun scripts/cli.ts platform-infra pipelines-as-code closeout --target <NODE> --consumer <id> --source-commit <sha> --wait`
4. `bun scripts/cli.ts platform-infra pipelines-as-code status --target <NODE> --consumer <id>`
5. `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --consumer <id> --limit 10`
6. For ambiguous rows, drill into the PipelineRun with `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --id <pipelinerun>`.
## 按需只读调查
`closeout` is the common formal entry for all migrated JD01 consumers. It waits only for PaC/Tekton/GitOps/Argo/runtime observation from live target-side summaries and does not trigger legacy publish paths. Consumer-specific debug commands such as Web sentinel `publish-current` are recovery/test steps only and must not be shown as the normal next action for formal delivery.
自动链必须在没有任何操作者命令的情况下完成交付并记录 terminal 状态。以下入口只在显式调查自动链故障时按需使用,不是 PR 合并后的默认顺序、交付前置或“下一步”:
GitHub webhook delivery `202` only means the bridge accepted the event. If `platform-infra gitea mirror webhook status --target <NODE>` shows `STALE=true`, treat the bridge event as stale and run the row's `REPAIR` command; the repair path is still the controlled `platform-infra gitea mirror sync --target <NODE> --repo <key> --confirm` entry and must not be replaced with a direct Gitea push.
- `bun scripts/cli.ts platform-infra gitea mirror status --target <NODE>`
- `bun scripts/cli.ts platform-infra gitea mirror webhook status --target <NODE>`
- `bun scripts/cli.ts platform-infra pipelines-as-code status --target <NODE> --consumer <id>`
- `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --consumer <id> --limit 10`
- 对归属或状态不明的行,使用 `bun scripts/cli.ts platform-infra pipelines-as-code history --target <NODE> --id <pipelinerun>` 下钻 PipelineRun。
The GitHub -> Gitea bridge must use YAML-declared bounded retry for its asynchronous `git fetch` and Gitea `push` worker. Retry ownership is `config/platform-infra/gitea.yaml#sourceAuthority.webhookSync.bridge.retry`; `webhook status` should show the active retry shape in the default summary. A GitHub delivery returning 202 is not enough to close a rollout or issue unless Gitea branch, snapshot ref and the latest bridge event are also aligned to GitHub head.
`closeout` 只保留为可选的只读历史/诊断兼容入口,不得出现在 migrated consumer 的默认观察顺序、覆盖矩阵、正常下一步或 PR 合并后的主/子代理任务中。它不得创建、同步、刷新、重试或补跑任何交付对象。consumer 专属 debug 命令只允许复现单步故障,不得成为正式交付或恢复入口。
Do not use `cicd branch-follower status` to decide whether the three migrated JD01 consumers are current. It is historical/migration-only and may contain stale state from before PaC cutover.
GitHub webhook delivery `202` 只代表 bridge 接收了事件。若状态显示 `STALE=true`,必须定位并修复 webhook bridge、受控 mirror 或 snapshot 自动同步逻辑;禁止输出或执行人工 `REPAIR`、mirror sync、直接 Gitea push 等补齐命令。修复后的端到端证据必须来自新的正常 GitHub PR merge。
For migrated sentinel CI/CD half-state triage, the PaC `status` command owns the source/registry/GitOps/Argo/runtime diagnosis. It must classify registry-missing, GitOps-missing, Argo-pending and runtime-mismatch states from target-side short probes, using YAML-declared probe endpoints such as `registry_probe_base`; do not reintroduce old control-plane status as the primary architecture or use registry manifest `HEAD` as the readiness check.
异步执行 `git fetch` 与 Gitea `push` 的 GitHub -> Gitea bridge worker 必须使用 YAML 声明的有界 retry。Retry 归属 `config/platform-infra/gitea.yaml#sourceAuthority.webhookSync.bridge.retry``webhook status` 应在默认摘要中显示当前 retry 形状。仅 GitHub delivery 返回 202 不足以收口 rollout 或 issue,还必须确认 Gitea branch、snapshot ref 与最新 bridge event 都对齐 GitHub head。
## Reuse Interpretation
不得使用 `cicd branch-follower status` 判定三个已迁移 JD01 consumer 是否最新。该入口只保留历史/迁移用途,可能包含 PaC cutover 前的过期状态。
- AgentRun `IMAGE_STATUS=reused` means the image build was skipped or registry artifact was reused for the same env identity.
- Sentinel `ENV_REUSE=hit` means dependency reuse was available; `cache=hit` is separate BuildKit evidence.
- HWLAB `skipped,skip=<n>` means service-level artifact planning skipped reusable builds; inspect the PipelineRun detail when deciding which service changed.
对已迁移 sentinel CI/CD 的 half-state 诊断,PaC `status` 命令负责 source/registry/GitOps/Argo/runtime 归因。它必须通过 target 侧短探针区分 registry-missing、GitOps-missing、Argo-pending 和 runtime-mismatch,并使用 `registry_probe_base` 等 YAML 声明的 probe endpoint;禁止重新把旧 control-plane status 当作主架构,也禁止把 registry manifest `HEAD` 当作 readiness 校验。
## UniDesk Host Runtime Change Filtering
## Reuse 证据解释
The `unidesk-host` consumer separates source observation from runtime delivery. `config/unidesk-host-k8s.yaml#delivery.changeDetection.runtimePaths` is the only editable list of source paths that can change the selected runtime, while `delivery.gitops.releaseStatePath` points to the generated GitOps release state used as the comparison baseline.
- AgentRun `IMAGE_STATUS=reused` 表示本次跳过 image build,或复用了同一 env identity 的 registry artifact。
- Sentinel `ENV_REUSE=hit` 表示依赖可复用;`cache=hit` 是独立的 BuildKit 证据。
- HWLAB `skipped,skip=<n>` 表示 service-level artifact plan 跳过了可复用 build;判定具体变更 service 时应查看 PipelineRun 详情。
- `build`: at least one declared runtime path changed, or no trustworthy prior release state is available. Build the image, update the manifest and release state, then let Argo converge.
- `skip`: the source commit advanced but no declared runtime path changed. Do not build an image, do not modify the GitOps branch, and do not cause an Argo rollout; retain the prior runtime source commit and digest as provenance.
- `disabled`: `delivery.enabled=false`. Remove the generated manifest and release state; this is service retirement, not a synonym for `skip`.
## UniDesk Host 运行面变更过滤
CLI, documentation, issue metadata and other files outside `runtimePaths` must resolve to `IMAGE_STATUS=skipped`. A successful skip still has a short PaC PipelineRun as source-observation evidence, but image build and GitOps publication are skipped. `status` and `closeout` must validate the retained digest, GitOps revision, Argo state, runtime readiness and health without requiring the runtime source commit to equal the newer non-runtime source commit.
`unidesk-host` consumer 将 source observation 与 runtime delivery 分离。`config/unidesk-host-k8s.yaml#delivery.changeDetection.runtimePaths` 是唯一可编辑的 runtime 变更 source path 列表,`delivery.gitops.releaseStatePath` 指向用作比较基线的 GitOps release state 生成物。
Missing reuse text is not proof of a failed reuse path. Check the consumer type and PipelineRun detail first.
- `build`:至少一个声明的 runtime path 发生变更,或没有可信的历史 release state。流水线构建 image、更新 manifest 与 release state,然后由 Argo 收敛。
- `skip`source commit 已推进,但没有声明的 runtime path 发生变更。流水线不得构建 image、修改 GitOps branch 或触发 Argo rollout,应保留既有 runtime source commit 与 digest 作为 provenance。
- `disabled``delivery.enabled=false`。删除生成的 manifest 与 release state;这代表 service retirement,不是 `skip` 的同义词。
CLI、文档、issue metadata 与 `runtimePaths` 之外的其他文件必须得到 `IMAGE_STATUS=skipped`。成功 skip 仍应产生一条短 PaC PipelineRun 作为 source-observation 证据,但应跳过 image build 与 GitOps publication。`status``closeout` 必须校验保留的 digest、GitOps revision、Argo state、runtime readiness 与 health,不得强制 runtime source commit 等于更新的非 runtime source commit。
缺少 reuse 文本不能证明 reuse path 失败,应先核对 consumer type 与 PipelineRun 详情。
@@ -0,0 +1,15 @@
# R1.1 任务报告
## 盘点结论
- 来源:https://github.com/pikasTech/unidesk/issues/1755
- 已识别会误导 migrated consumer 人工补链的旧规则:
-`trigger-current` 当作通用交付入口;
-`closeout --wait` 放入默认观察顺序与覆盖矩阵;
- 在 stale mirror 时引导人工 `REPAIR` 或 mirror sync
- 把“受控 CLI”误解为 PR 合并后仍需执行写命令。
- 已将 legacy/bootstrap 入口与 PaC migrated consumer 的自动交付边界分开。
## 结论
PaC migrated consumer 的交付不存在合并后人工“下一步”;若链路断开,只能修复自动链。
@@ -0,0 +1,24 @@
# R1.2 任务报告
## 规则收敛
- 来源:https://github.com/pikasTech/unidesk/issues/1755
- 唯一正式触发:目标 source branch 的 GitHub PR merge。
- 唯一正式链路:
- GitHub webhook
- Gitea controlled mirror 与 immutable snapshot ref
- Gitea webhook
- PaC
- Tekton
- GitOps/Argo
- runtime 自动滚动。
- 主代理、子代理与操作者均不得通过 apply、closeout、trigger、sync、flush、人工 PipelineRun 或运行面 patch 补链。
- 自动链失败时必须修复 owning YAML、controller 或源码,并以修复 PR 合并产生的新事件验收。
- `status/history/events/logs` 仅在显式故障调查时按需读取,不是交付前置。
- `closeout` 只保留可选只读历史/诊断兼容能力,不得成为默认观察顺序或代理任务。
## 变更位置
- `.agents/skills/unidesk-cicd/SKILL.md`
- `.agents/skills/unidesk-cicd/references/gitea-pac.md`
- `docs/reference/platform-infra.md`
@@ -0,0 +1,19 @@
# R1.3 任务报告
## 文档合同
- 来源:https://github.com/pikasTech/unidesk/issues/1755
- 新增 `scripts/src/cicd-pr-merge-auto-delivery-doc-contract.test.ts`
- 合同覆盖:
- PR merge 唯一触发与完整自动链;
- 主/子代理与操作者禁止人工补链;
- 故障调查入口只读;
- coverage matrix 与按需调查段不得重新引导 `closeout --wait`
- `source-artifact write` 仅限 PR 合并前;
- 可调整预算由 owning YAML 声明。
## 验证
- 命令:`bun test scripts/src/cicd-pr-merge-auto-delivery-doc-contract.test.ts`
- 结果:6 pass0 fail40 个断言通过。
- `git diff --check` 通过。
@@ -0,0 +1,22 @@
# PR 合并驱动的全自动交付
- 来源:https://github.com/pikasTech/unidesk/issues/1755
- 范围:长期规则、CI/CD skill 与文档合同。
- 边界:不执行任何人工 CI/CD 触发、补跑或运行面修改。
## R1 [in_progress]
固化 PR 合并驱动的全自动交付与故障修复边界,来源:https://github.com/pikasTech/unidesk/issues/1755,完成任务后将详细报告写入[任务报告](./details/pr-merge-driven-automatic-delivery/R1_Task_Report.md)。
### R1.1 [completed]
盘点并收敛会误导人工触发或补跑的长期规则,引用:https://github.com/pikasTech/unidesk/issues/1755,完成任务后将详细报告写入[任务报告](./details/pr-merge-driven-automatic-delivery/R1.1_Task_Report.md)。
### R1.2 [completed]
更新 CI/CD reference 与 skill,明确 PR merge 唯一触发及自动链故障修复边界,引用:https://github.com/pikasTech/unidesk/issues/1755,完成任务后将详细报告写入[任务报告](./details/pr-merge-driven-automatic-delivery/R1.2_Task_Report.md)。
### R1.3 [completed]
补充轻量文档合同检查,阻止人工交付入口重新成为正式路径,完成任务后将详细报告写入[任务报告](./details/pr-merge-driven-automatic-delivery/R1.3_Task_Report.md)。
### R1.4 [in_progress]
完成静态验证、报告、提交、推送与非草稿 PR,禁止触发或部署 CI/CD,完成任务后将详细报告写入[任务报告](./details/pr-merge-driven-automatic-delivery/R1.4_Task_Report.md)。
+2 -1
View File
@@ -23,7 +23,8 @@
- PaC Repository CR `spec.url` is the URL matcher for incoming Gitea webhook payloads, so `config/platform-infra/pipelines-as-code.yaml#repositories[].url` must use the public Gitea repository URL emitted by Gitea webhooks. Internal ClusterIP/service URLs belong in `cloneUrl` and `params.git_read_url`; putting an internal URL in `spec.url` makes PaC log `cannot find a repository match` and creates no PipelineRun even though the Gitea mirror is current.
- PaC Repository CR params must use the node-specific Gitea snapshot prefix declared for that consumer, such as `unidesk-master-nc01` for NC01 sentinel. A generic or other-node prefix can make the repository look healthy while fresh pushes cannot close out against the target node source.
- PaC history is the trigger/timing audit surface for Gitea/PaC-managed lanes. It must query Gitea Repository CR and Tekton PipelineRun/TaskRun live objects on the target node, aggregate there, return Beijing-time display by YAML timezone, expose a detail id for drill-down, and report read errors explicitly; a large namespace or unreadable target object must never be rendered as a successful empty table.
- Formal delivery for a PaC-migrated consumer starts with merging the GitHub PR into that consumer's YAML-declared upstream branch. The GitHub webhook bridge then syncs GitHub to the controlled Gitea mirror and immutable snapshot refs; the Gitea repository push webhook triggers Pipelines-as-Code, which creates the Tekton PipelineRun. Operators must not replace this with `trigger-current`, `webhook-test`, a direct Gitea push, raw PipelineRun creation, or a local Git mirror edit. `webhook-test` is only a connectivity diagnostic.
- PaC 迁移 consumer 的目标 source branch GitHub PR merge 是唯一正式交付触发事件。合并后必须由 GitHub webhook、Gitea controlled mirror immutable snapshot ref、Gitea webhook、PaC、Tekton、GitOps/Argo 自动推进到运行面;主代理、子代理和操作者都不得执行 apply、closeout、trigger、sync、flush、人工 PipelineRun、直接 Gitea push、本地 Git mirror 修改或其他补跑来完成本次交付。`webhook-test` 只是连通性诊断,不得代替真实 PR merge 事件。
- 自动链不通时必须修复 owning YAML、controller 或源码中的自动链缺陷,并用修复 PR 合并后产生的新自动事件验证;禁止用人工操作制造对齐状态或掩盖故障。`status``history``events``logs` 与单步 debug 入口只在显式调查时按需读取,不是交付前置;`closeout` 仅保留只读兼容能力,不得成为主/子代理的 PR 合并后步骤。任何诊断入口都不得隐式推进交付。
- `config/platform-infra/pipelines-as-code.yaml` may declare multiple repositories and consumers. JD01 and NC01 both declare AgentRun, Web sentinel and HWLAB consumers; use `cicd status --node <NODE>` for node-level status, `history --target <NODE>` for all-consumer audit, and `status --target <NODE> --consumer <id>` for consumer-scoped closeout. Consumer-scoped status must not mix PipelineRuns or env reuse evidence across repositories.
- Shared upstream repositories must isolate target-specific `.tekton` files with Repository CR params, currently `node`, and `pipelinesascode.tekton.dev/on-cel-expression`. A NC01 webhook delivery must not create JD01 PipelineRuns in the NC01 cluster, and history drill-down must not attribute the same PipelineRun to multiple consumers.
- Public Gitea UI may use the YAML-declared HTTPS hostname, but k8s-internal consumers must use the ClusterIP service URL from YAML. Internal CI/Argo/runtime reads must not loop through public DNS/Caddy/FRP, and migrated lanes must not fall back to legacy git-mirror read URLs when the commit exists only in Gitea.
@@ -0,0 +1,76 @@
import { describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { resolve } from "node:path";
const root = resolve(import.meta.dir, "../..");
const skill = readFileSync(resolve(root, ".agents/skills/unidesk-cicd/SKILL.md"), "utf8");
const reference = readFileSync(
resolve(root, ".agents/skills/unidesk-cicd/references/gitea-pac.md"),
"utf8",
);
const platform = readFileSync(resolve(root, "docs/reference/platform-infra.md"), "utf8");
describe("PR 合并驱动的自动交付文档合同", () => {
test("权威文档声明唯一触发、完整自动链和故障修复边界", () => {
for (const document of [skill, reference, platform]) {
expect(document).toContain("GitHub PR merge");
expect(document).toMatch(/唯一.*触发/);
expect(document).toMatch(
/GitHub webhook[\s\S]*Gitea[\s\S]*immutable snapshot[\s\S]*Gitea webhook[\s\S]*(?:PaC|Pipelines-as-Code)[\s\S]*Tekton[\s\S]*GitOps\/Argo[\s\S]*(?:runtime|运行面)/,
);
expect(document).toMatch(/自动链.*修复|修复.*自动链/);
}
});
test("主代理、子代理和操作者不得在 PR 合并后补齐交付", () => {
for (const document of [skill, reference, platform]) {
expect(document).toContain("主代理");
expect(document).toContain("子代理");
expect(document).toMatch(
/apply[\s\S]*closeout[\s\S]*trigger[\s\S]*sync[\s\S]*flush/,
);
expect(document).toMatch(/不得|禁止/);
}
});
test("状态与单步入口只读,自动链不通时不得人工恢复", () => {
expect(skill).toContain(
"status/history/events/logs/closeout/debug-step 可用于定位,但不得改变交付状态",
);
expect(skill).toContain("PaC migrated consumer 禁止执行 `trigger-current`");
expect(skill).not.toContain("需要保留的旧命令只能标为 debug/test/recovery");
expect(reference).toContain("`closeout` 只保留为可选的只读历史/诊断兼容入口");
expect(reference).toContain("禁止输出或执行人工 `REPAIR`");
expect(reference).not.toContain("run the row's `REPAIR` command");
expect(reference).not.toContain("manual recovery");
});
test("migrated consumer 默认观察与覆盖矩阵不再引导人工 closeout", () => {
const coverage = reference.slice(
reference.indexOf("## 覆盖矩阵"),
reference.indexOf("## 按需只读调查"),
);
const diagnosis = reference.slice(
reference.indexOf("## 按需只读调查"),
reference.indexOf("GitHub webhook delivery"),
);
expect(coverage).toContain("pipelines-as-code status");
expect(coverage).not.toContain("pipelines-as-code closeout");
expect(diagnosis).toContain("不是 PR 合并后的默认顺序、交付前置或“下一步”");
expect(diagnosis).not.toContain("pipelines-as-code closeout");
});
test("源码制品写入仅属于合并前,不得成为合并后触发器", () => {
expect(reference).toContain(
"`source-artifact plan|check|write` 只能在 source PR 合并前",
);
expect(reference).toContain("不是合并后的 CI/CD 触发、同步、恢复或补跑入口");
});
test("可调整预算继续归属 YAML,长期规则不固化当前数值", () => {
expect(skill).toContain("wall-clock 目标及预算只由 owning YAML 声明");
expect(skill).not.toContain("低于 2 分钟");
expect(skill).not.toContain("120s 端到端预算");
});
});