docs: complete DEV CD authority contract

This commit is contained in:
Code Queue Review
2026-05-23 13:20:01 +00:00
parent 57582f86eb
commit 7721d1578b
3 changed files with 95 additions and 13 deletions
+1 -1
View File
@@ -34,7 +34,7 @@ HWLAB 是硬件实验室运行面和控制面项目。本文是 agent、指挥
- 文档治理与 docs-spec 本地权威:[docs/reference/documentation-governance.md](docs/reference/documentation-governance.md)
- 架构和 M3 主线:[docs/reference/architecture.md](docs/reference/architecture.md)
- DEV 运行态、端口、k3s 和 DB DNS 边界:[docs/reference/dev-runtime-boundary.md](docs/reference/dev-runtime-boundary.md)
- 部署正规化、`deploy.json` DEV CD 路径、镜像发布、回滚和 Cloud Web 路径[docs/reference/deployment-publish.md](docs/reference/deployment-publish.md)
- 部署正规化、`deploy.json` DEV CD 路径、SecretRef preflight、runner/host 边界和镜像发布:[docs/reference/deployment-publish.md](docs/reference/deployment-publish.md)
- Code Agent 对话就绪与真实回复判定:[docs/reference/code-agent-chat-readiness.md](docs/reference/code-agent-chat-readiness.md)
- MVP E2E 验收测试与带编号测试报告 issue 规则:[docs/reference/MVP-e2e-acceptance.md](docs/reference/MVP-e2e-acceptance.md)
- 指挥官协作、PR 和 runner 交接:[docs/reference/commander-collaboration.md](docs/reference/commander-collaboration.md)
+2 -1
View File
@@ -20,7 +20,7 @@
| 文档治理与 docs-spec 本地权威 | [documentation-governance.md](documentation-governance.md) |
| 架构和 M3 上位约束 | [architecture.md](architecture.md) |
| DEV 运行态、端口、k3s、DB readiness 和环境边界 | [dev-runtime-boundary.md](dev-runtime-boundary.md) |
| 部署正规化、`deploy.json` DEV CD 路径、单事务入口、artifact 发布、回滚和 Cloud Web rollout | [deployment-publish.md](deployment-publish.md) |
| 部署正规化、`deploy.json` DEV CD 路径、SecretRef preflight、runner/host 边界、artifact 发布和 Cloud Web rollout | [deployment-publish.md](deployment-publish.md) |
| Cloud Workbench 默认界面和 UX 边界 | [cloud-workbench.md](cloud-workbench.md) |
| Code Agent chat 同源通道 readiness 与真实回复判定 | [code-agent-chat-readiness.md](code-agent-chat-readiness.md) |
| MVP E2E 验收测试与带编号测试报告 issue 规则 | [MVP-e2e-acceptance.md](MVP-e2e-acceptance.md) |
@@ -41,6 +41,7 @@
- [pikasTech/HWLAB#61](https://github.com/pikasTech/HWLAB/issues/61)DEV 手动 rollout 复盘,以及走向 CLI 加 `deploy/deploy.json` 自动化的路径。
- [pikasTech/HWLAB#109](https://github.com/pikasTech/HWLAB/issues/109):文档治理和长期参考体系。
- [pikasTech/HWLAB#116](https://github.com/pikasTech/HWLAB/issues/116):服务部署正规化三阶段:长期参考、受控 CLI/脚本入口、UniDesk CI/CD 加镜像化交付。
- [pikasTech/HWLAB#235](https://github.com/pikasTech/HWLAB/issues/235)Cloud API、DB、部署与运行态专题,承载 deploy.json、DEV CD、runtime 和 16666/16667 运行态收敛关系。
- [pikasTech/HWLAB#340](https://github.com/pikasTech/HWLAB/issues/340)`deploy.json` DEV CD 路径长期化、master CLI wrapper、Secret preflight 和恢复后健康审计。
当 issue、报告或旧文档与本目录 reference 文档冲突时,先更新 reference 文档,再让 `AGENTS.md` 保持短索引。过程记录不得被改写;只能把稳定结论蒸馏进这里。
+92 -11
View File
@@ -23,7 +23,9 @@ Every DEV CD status, apply, rollback, smoke, and manual Kubernetes command must
use `KUBECONFIG=/etc/rancher/k3s/k3s.yaml` and verify node `d601` before any
mutation or acceptance. Bare `kubectl`, `docker-desktop` context,
`desktop-control-plane`, or `127.0.0.1:11700` are wrong-control-plane signals,
not HWLAB DEV-LIVE evidence.
not HWLAB DEV-LIVE evidence. A second `hwlab-dev` control plane, including a
Docker Desktop cluster that happens to contain similarly named resources, is a
blocker and cannot be used as deploy, rollout, smoke, or acceptance proof.
## Workspaces
@@ -107,7 +109,7 @@ status/dry-run 中执行 rollout。这些模式 host commander 和 runner 都可
不可用时,状态面应返回 `lock.status=unavailable` 和脱敏原因,而不是把
只读观测失败升级成写路径 blocker。
## 当前已验证的 `deploy.json` 部署路径
## `deploy.json` DEV CD 路径
当前已经验证可用的过渡路径是:master server 只作为受控指挥入口,通过
UniDesk CLI 进入 D601D601 上使用干净 HWLAB 工作区运行本仓库
@@ -119,18 +121,29 @@ UniDesk CLI 进入 D601D601 上使用干净 HWLAB 工作区运行本仓库
单事务入口和发布锁见 [pikasTech/HWLAB#274](https://github.com/pikasTech/HWLAB/issues/274)
D601 控制面归一见 [pikasTech/unidesk#138](https://github.com/pikasTech/unidesk/issues/138)。
受控入口形态:
稳定调用合同如下;外层 master CLI 或 UniDesk wrapper 只能包裹这些
repo-owned 入口,不能绕过它们直接拼接 publish、apply、rollout 或 smoke
| 目的 | 稳定入口 | 副作用边界 |
| --- | --- | --- |
| 读取 DEV CD 状态 | `node scripts/dev-cd-apply.mjs --status` | 不写入、不获取 Lease、不读取 Secret value。 |
| 事务 dry-run preflight | `node scripts/dev-cd-apply.mjs --dry-run` | 不 publish、不 apply、不 rollout。 |
| 检查 desired-state 收敛 | `node scripts/deploy-desired-state-plan.mjs --promotion-commit <sha> --check` | 只读 source/report。 |
| 执行 DEV CD 事务 | `node scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report` | 仅 DEV,在 `Lease/hwlab-dev/hwlab-dev-cd-lock` 下 publish/apply/verify。 |
| 读取 D601 k3s 证据 | `node scripts/d601-k3s-readonly-observability.mjs` | 只读可见性报告;不 rollout、不输出 Secret value。 |
使用 master-side wrapper 时,稳定形态是:
```sh
cd /root/unidesk
bun scripts/cli.ts ssh D601 argv bash -lc 'cd /home/ubuntu/hwlab-cd-master-cli && node scripts/dev-cd-apply.mjs --status'
bun scripts/cli.ts ssh D601 argv bash -lc 'cd /home/ubuntu/hwlab-cd-master-cli && node scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report'
bun scripts/cli.ts ssh D601 argv bash -lc 'cd <clean-hwlab-cd-worktree> && KUBECONFIG=/etc/rancher/k3s/k3s.yaml node scripts/dev-cd-apply.mjs --status'
bun scripts/cli.ts ssh D601 argv bash -lc 'cd <clean-hwlab-cd-worktree> && KUBECONFIG=/etc/rancher/k3s/k3s.yaml node scripts/dev-cd-apply.mjs --apply --confirm-dev --confirmed-non-production --write-report'
```
`/home/ubuntu/hwlab-cd-master-cli` 必须指向干净工作区。该工作区可以是固定
clean mirror,也可以是一次性 `git clone --shared --no-checkout` 生成的
ephemeral worktree;它不能是 `/home/ubuntu/hwlab` 这类 runner/历史任务集合
目录。进入 apply 前必须证明:
`<clean-hwlab-cd-worktree>` 必须指向干净工作区。该工作区可以是固定 clean
mirror,也可以是一次性 `git clone --shared --no-checkout` 生成的 ephemeral
worktree;它不能是 `/home/ubuntu/hwlab` 这类 runner/历史任务集合目录。进入
apply 前必须证明:
- `git status --short` 为空;
- `.git/FETCH_HEAD``.git/worktrees` 没有阻止普通部署用户读取或创建
@@ -138,11 +151,45 @@ ephemeral worktree;它不能是 `/home/ubuntu/hwlab` 这类 runner/历史任
- `node scripts/dev-cd-apply.mjs --status` 显示 `promotionSource=deploy-json`
- `deploy/deploy.json` 的 commit、`deploy/artifact-catalog.dev.json`
`deploy/k8s/base/workloads.yaml` 收敛到同一个 promotion commit / image tag
- `kubectl.kubeconfigSource` 指向 D601 原生 k3s,或命令显式设置
`KUBECONFIG=/etc/rancher/k3s/k3s.yaml`
- `KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl get nodes` 能看到节点 `d601`
- `kubectl config current-context`、cluster server 或节点列表没有
`docker-desktop``desktop-control-plane``127.0.0.1:11700` 或第二套
`hwlab-dev` 控制面证据;
- `Lease/hwlab-dev-cd-lock` 未被未过期事务持有,或者 stale lock 已由受控
`--break-stale-lock --confirm-dev` 审计处理。
desired-state 来源关系固定如下:
| 来源 | 权威范围 |
| --- | --- |
| `deploy/deploy.json` | DEV environment、namespace、endpoint、service set、promotion commit 和事务消费的 image tag。 |
| `deploy/artifact-catalog.dev.json` | 同一 promotion commit 的不可变 artifact digest/tag 证据。 |
| `deploy/k8s/base/workloads.yaml` | Kubernetes workload desired state,必须镜像 `deploy.json` 和 artifact catalog 后才能 apply。 |
| `reports/dev-gate/*.json` | 只作为证据快照;不能覆盖 repo desired state。 |
| `Lease/hwlab-dev/hwlab-dev-cd-lock` | 只作为事务互斥锁和审计状态;永远不是 desired-state 来源。 |
只改文档的 commit 如果没有修改 `deploy/deploy.json`
`deploy/artifact-catalog.dev.json``deploy/k8s/base/workloads.yaml`、service
source 或 runtime manifest,就不会产生新的 DEV image 或 promotion commit。
这类 commit 的 artifact build/publish 结论是 not applicable,除非另一个
artifact 任务明确更新 desired state。
## Runner 和 Host 边界
Deployment/CD 工作按以下边界分工:
| 角色 | 可以执行 | 没有明确 rollout 授权时不得执行 |
| --- | --- | --- |
| Code Queue runner | 准备分支和 PR;在任务授权且检查通过后更新或自合并 docs/code/artifact PR;通过 repo-owned 路径 build/publish artifact;在被分配时刷新 artifact report 或 desired-state 文件;运行只读 `status`/`dry-run`/preflight 检查。 | 竞争 DEV CD Lease、执行 DEV apply、rollout、声称 `16666/16667` live verification、收口 `#7``#242`、修改 PROD、打印 Secret value、手工修 live resource。 |
| Host commander | 在需要指挥官 review 时审阅并合并最终 PR;执行单一 DEV deploy apply 事务;执行 rollout 和 `16666/16667` live verification;收口 `#7`/`#242` 状态。 | 绕过 repo-owned CD 入口、使用第二控制面、用 UniDesk runtime 替代 HWLAB runtime、只凭报告而不做一手复验就当作 live evidence。 |
Runner 自合并权限只在任务边界内生效。它不授予 DEV apply、rollout、
live health verification 或看板/status 收口权限。Runner 发布 artifact 时,
输出必须包含 tag、digest 和 report 证据,并把 desired-state convergence 与
live rollout evidence 分开。
## SecretRef Preflight
apply 前还必须把必要 SecretRef 作为 preflight 条件处理,而不是等待
runtime Job 进入 `CreateContainerConfigError`
@@ -156,6 +203,40 @@ DEV-only secret reconcile 从 `unidesk-dev/postgres-dev` runtime source 生成
并写入 `hwlab-dev`;长期应迁移到 declarative secret、sealed/external secret
或统一 secret controller。
SecretRef preflight report 必须使用布尔值和脱敏 metadata:
| 检查项 | 必要证据 | 缺失时 blocker |
| --- | --- | --- |
| Source desired-state reference | `deploy/deploy.json``deploy/k8s/base/workloads.yaml` 声明预期 `secretRef` / `secretKeyRef` name 和 key。 | `contract_blocker`scope 指向所属 manifest 或 service。 |
| Live D601 Secret presence | 在 `hwlab-dev` namespace 中,repo-owned preflight 或 controller 证明必要 Secret resource 和 key 存在。 | `runtime_blocker`scope 指向缺失的 SecretRef。 |
| k3s access for the check | 检查使用 `/etc/rancher/k3s/k3s.yaml`,解析到节点 `d601`,没有命中 Docker Desktop 或第二控制面。 | `environment_blocker``observability_blocker`scope 指向 D601 k3s visibility。 |
| Redaction | Report 字段声明 `secretValuesPrinted=false`;日志不包含 decoded data、DSN、token、password、kubeconfig material 或 base64 Secret payload。 | `safety_blocker`;在 publish/apply 前停止。 |
preflight 可以报告 Secret name、key name、namespace、presence boolean、
owning workload、missing scope 和 repair runbook。它不得粘贴
`HWLAB_CLOUD_DB_URL`, `HWLAB_CLOUD_DB_ADMIN_URL`, `OPENAI_API_KEY`, bearer
tokens, passwords, kubeconfig contents, or Secret `.data` values into reports,
issues, PRs, logs, screenshots, or chat.
## Blocker 分类
DEV CD report 必须保持 blocker 分类稳定,使 runner 和 host 不读完整事务日志
也能路由工作:
| Type | 含义 |
| --- | --- |
| `safety_blocker` | 请求动作会违反 DEV-only、non-secret、non-PROD、lock 或控制面安全规则。 |
| `environment_blocker` | 必要 local/D601 tool、kubeconfig、k3s node、registry、workspace 或 permission 不可用。 |
| `contract_blocker` | Source manifest、desired-state 文件、artifact catalog、report schema 或 promotion provenance 不一致。 |
| `runtime_blocker` | DEV runtime 前置条件或后置条件缺失,包括 SecretRef presence、DB readiness、durable runtime、rollout 或 workload image convergence。 |
| `agent_blocker` | Code Agent provider/model/egress/SecretRef readiness 不完整。 |
| `network_blocker` | public 或 internal endpoint 不可达,或返回无效 health response。 |
| `observability_blocker` | runner 无法观测足够只读证据来证明状态,但底层 runtime 可能仍然健康。 |
每个 blocker 必须包含 `type``scope``status` 和单行 `summary`。可行时还
应包含 `unblockHint``nextTask`。Secret 相关 blocker 必须声明没有打印
value。
成功收口必须同时具备以下证据:
- `scripts/dev-cd-apply.mjs --status` 返回 `status=pass`