test: guard code queue artifact dry-run readiness
This commit is contained in:
@@ -76,7 +76,7 @@ bun scripts/cli.ts artifact-registry deploy-service --service mdtodo --env dev -
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service mdtodo --env prod --commit <full-sha>
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service claudeqq --env dev --commit <full-sha>
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service claudeqq --env prod --commit <full-sha>
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service code-queue --env dev --commit <full-sha>
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service code-queue --env dev --commit <full-sha> --dry-run
|
||||
```
|
||||
|
||||
`plan` 输出架构边界、依赖项、默认路径和 backend-core artifact CD 流程。`render` 输出 systemd unit、Compose 文件和 registry config 的完整内容与 SHA-256。`install --dry-run` 只列出将要执行的远端动作,不写 D601 文件、不启动容器、不 reload systemd。
|
||||
@@ -85,7 +85,7 @@ bun scripts/cli.ts artifact-registry deploy-service --service code-queue --env d
|
||||
|
||||
`deploy-backend-core` 是旧兼容入口,当前作为标准路径已禁用。Backend-core CD 必须使用 `bun scripts/cli.ts deploy apply --env dev --service backend-core --commit <full-sha>` 或 `bun scripts/cli.ts deploy apply --env prod --service backend-core --commit <full-sha>`,由 deploy reconciler 先执行共同的 artifact-consumer guardrail,再调用通用 `deploy-service` consumer。旧入口只能返回 structured deprecated 结果,不得绕过 `deploy apply --env ...`。
|
||||
|
||||
`deploy-service` 是标准化后的最小通用 artifact consumer。它目前支持 dev/prod `backend-core`、`baidu-netdisk`、prod/dev `frontend`、`decision-center`、`mdtodo`、`claudeqq`、`project-manager`、`oa-event-flow`、`code-queue-mgr`、`todo-note`、`findjob`、`pipeline`、`met-nonlinear` 和 `k3sctl-adapter`,以及 dev-only `code-queue`。所有路径都必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证;`code-queue --env prod` 必须返回 structured unsupported,不能回退到生产 artifact deploy、rollout 或 manifest 变更;`code-queue-mgr` 的 prod live apply 仍需 supervisor 单独确认,`met-nonlinear` 与 `k3sctl-adapter` 当前只提供 plan/dry-run:
|
||||
`deploy-service` 是标准化后的最小通用 artifact consumer。它目前支持 dev/prod `backend-core`、`baidu-netdisk`、prod/dev `frontend`、`decision-center`、`mdtodo`、`claudeqq`、`project-manager`、`oa-event-flow`、`code-queue-mgr`、`todo-note`、`findjob`、`pipeline`、`met-nonlinear` 和 `k3sctl-adapter`,以及 dev-only `code-queue` dry-run。所有路径都必须先通过 D601 registry 的 commit-pinned manifest 校验,再执行拉取、导入/retag、部署和健康验证;`code-queue --env dev --dry-run` 必须显示 `requiresSupervisorApproval=true`、`selfBootstrapGuard`、commit tag/digest provenance、pull-only/no-build build boundary 和不会影响 production scheduler/runner/active tasks 的 `affectedRuntime` / `excludedTargets`;非 dry-run DEV apply 必须返回 supervisor/human authorization gate,不能由正在运行的 Code Queue task 自举执行;`code-queue --env prod` 必须返回 structured unsupported,不能回退到生产 artifact deploy、rollout 或 manifest 变更;`code-queue-mgr` 的 prod live apply 仍需 supervisor 单独确认,`met-nonlinear` 与 `k3sctl-adapter` 当前只提供 plan/dry-run:
|
||||
|
||||
```bash
|
||||
bun scripts/cli.ts artifact-registry deploy-service --service baidu-netdisk --commit <full-sha> --run-now
|
||||
@@ -103,12 +103,15 @@ bun scripts/cli.ts artifact-registry deploy-service --env dev --service mdtodo -
|
||||
bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> --run-now
|
||||
bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> --run-now
|
||||
bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> --run-now
|
||||
bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --run-now
|
||||
```
|
||||
|
||||
`code-queue-mgr` 是主 server Compose sidecar,不是 D601 Code Queue scheduler/runner。`artifact-registry deploy-service --env prod --service code-queue-mgr --commit <full-sha> --dry-run` 必须显示 target 仅为 `composeService=code-queue-mgr` / `containerName=code-queue-mgr-backend`,并在 `excludedTargets` 中说明不会触碰 `code-queue` scheduler、runner、任务、interrupt 或 cancel 状态。真实 prod apply 仍受 supervisor-only gate 保护;未经单服务授权不得执行非 dry-run apply。
|
||||
|
||||
`bun scripts/code-queue-mgr-artifact-readiness-contract-test.ts` 是这个 supervisor gate 的 focused source/contract 检查:它验证 prod `deploy.json` pin 到包含 stats endpoint 的 `code-queue-mgr` commit、`CI.json` 仍使用 `ci publish-user-service` 发布 `unidesk/code-queue-mgr:<commit>`、Rust runtime 暴露 `/api/tasks/stats` 且不返回 `skipped` 统计、`artifact-registry deploy-service --env prod --service code-queue-mgr --dry-run` 与 `deploy apply --env prod --service code-queue-mgr --dry-run` 都只计划 `code-queue-mgr-backend` 单个 Compose service,并保持 supervisor-only live apply 与 scheduler/runner/tasks/interrupt/cancel excluded target 合同。
|
||||
`bun scripts/code-queue-cicd-dry-run-contract-test.ts` 是 Code Queue 自举边界的 focused contract:它验证 `deploy plan`、`deploy apply --dry-run` 和 `artifact-registry deploy-service --dry-run` 都只给出 DEV 计划证据,显示 `requiresSupervisorApproval` / `selfBootstrapGuard`,保持 pull-only/no-build 和 digest provenance,并证明 PROD unsupported 且不会影响生产 scheduler/runner/active tasks、interrupt 或 cancel。
|
||||
|
||||
`bun scripts/code-queue-mgr-artifact-readiness-contract-test.ts` 是 Code Queue Manager supervisor gate 的 focused source/contract 检查:它验证 prod `deploy.json` pin 到包含 stats endpoint 的 `code-queue-mgr` commit、`CI.json` 仍使用 `ci publish-user-service` 发布 `unidesk/code-queue-mgr:<commit>`、Rust runtime 暴露 `/api/tasks/stats` 且不返回 `skipped` 统计、`artifact-registry deploy-service --env prod --service code-queue-mgr --dry-run` 与 `deploy apply --env prod --service code-queue-mgr --dry-run` 都只计划 `code-queue-mgr-backend` 单个 Compose service,并保持 supervisor-only live apply、`selfBootstrapGuard` 与 scheduler/runner/tasks/interrupt/cancel excluded target 合同。
|
||||
|
||||
Code Queue DEV live apply is not an automation default. The reviewed path is: publish the commit-pinned artifact, run `deploy plan --env dev --service code-queue` and `deploy apply --env dev --service code-queue --dry-run` or the equivalent artifact-registry dry-run, then have a human operator or supervisor authorize any DEV apply outside the running Code Queue task. PROD has no apply authorization point in this phase.
|
||||
|
||||
dry-run 输出会暴露 registry probe URL、required labels、目标 image、部署形态、目标 Deployment 列表、回滚信息,以及结构化 `registry`、`source` 和 `build` 字段;`registry.digest` 在 dry-run 中为 `null`,`digestSource` 指明真实 digest 来自 live registry manifest HEAD,`build.willCompile`、`build.willRunCargoBuild`、`build.willRunDockerBuild` 和 `build.willRunDockerComposeBuild` 必须为 false。dry-run 不得打印运行时密钥。`backend-core --env dev` 使用 `ci publish-backend-core` 产出的 `127.0.0.1:5000/unidesk/backend-core:<commit>`,导入 D601 native k3s containerd,更新 `unidesk-dev/backend-core-dev` Deployment,设置 image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health.deploy.commit` 和 `deploy.requestedCommit`;CD 阶段不得运行 Rust 编译或 Docker build。`baidu-netdisk` 是 PGDATA 备份链路依赖服务;它的 Compose artifact 路径会通过 provider-gateway Host SSH 把 `unidesk/baidu-netdisk:<commit>` 流式拉到 master server,retag 为 `baidu-netdisk` 和 `baidu-netdisk:<commit>`,在 canonical UniDesk 根目录使用 `providerGateway.upgrade.composeEnvFile` 指向的受控 env 文件写入 `UNIDESK_BAIDU_NETDISK_DEPLOY_*`,只 recreate `baidu-netdisk` service,并验证容器 image label 与 `/health.deploy.commit`。live apply 在 recreate 前必须确认受控 env 文件中存在 `UNIDESK_BAIDU_NETDISK_CLIENT_ID`、`UNIDESK_BAIDU_NETDISK_CLIENT_SECRET` 和 `UNIDESK_BAIDU_NETDISK_TOKEN_KEY`,输出只能包含 present/length/boolean;dry-run 输出 `runtimeSecrets.secretSource`、`requiredSecretsPresent`、`missingSecretKeys` 和 `recommendedAction`,让 dev secret source blocker 可诊断但不打印值;recreate 后必须验收 `/health.auth.configured`、`clientIdConfigured`、`clientSecretConfigured`、`tokenKeyConfigured` 和 `loggedIn` 全部为 true,否则返回失败或 degraded,并提示先恢复 env、单服务 recreate、再验证 `microservice health baidu-netdisk`。`findjob`、`pipeline` 和 `met-nonlinear` 的 D601 direct Compose 路径在 D601 本机验证 registry manifest、pull image、retag stable image、写入 `UNIDESK_*_DEPLOY_*` labels/env,并用 `docker compose up -d --no-build --no-deps --force-recreate <service>` 重新拉起对应 compose service;其中 `met-nonlinear` 当前因为 registered Dockerfile 和 long-running service contract 不一致而 live deploy blocked。`k3sctl-adapter` 是基础设施控制桥,只做 plan/dry-run,真实生产部署需要 supervisor 单独确认。`frontend --env prod` 使用同一 Compose artifact consumer,流式拉取 `unidesk/frontend:<commit>`,retag 为 `unidesk-frontend` 和 `unidesk-frontend:<commit>`,写入 `UNIDESK_FRONTEND_DEPLOY_*`,只 recreate `frontend` service,并验证 image label 与 `/health.deploy.commit`。`frontend --env dev`、`decision-center`、`mdtodo`、`claudeqq` 和 dev `code-queue` 的 k3s 路径会在 D601 上验证 commit image、导入 native k3s containerd、更新 Deployment image/env/annotations,并通过 Kubernetes API service proxy 验证 `/health` 中的 live commit 与 requested commit;dev frontend 还会在 rollout 前把主 server `config.json.auth` 同步到 `unidesk-dev` Secret/ConfigMap。`decision-center --env dev` 落到 `unidesk-dev/decision-center-dev`,prod 落到 `unidesk/decision-center`;`mdtodo` 和 `claudeqq` 使用同样的 dev 后 prod k3s consumer 结构。`code-queue --env dev` 只更新 `unidesk-dev` 中的 scheduler/read/write/provider-egress-proxy dev Deployments,prod 没有 consumer target。D601 direct Compose consumer 与 k3s-managed consumer 的区别是:前者只接触 D601 Docker/Compose 项目和私有 backend health,不创建 Kubernetes 对象;后者只通过 native k3s Deployment/Service、containerd import 和 Kubernetes API service proxy 验证 live commit。回滚信息通过同一 artifact consumer 的 `rollback` 字段暴露,提示操作者重新对一个旧 commit 运行相同命令,而不是切回 legacy maintenance-channel 构建。
|
||||
|
||||
|
||||
@@ -272,7 +272,7 @@ Code Queue follows the standard artifact split only up to a dev-only consumer:
|
||||
| Stage | Owner | Allowed output | Explicitly forbidden |
|
||||
| --- | --- | --- | --- |
|
||||
| CI producer | Tekton / CI runner outside Code Queue self-deploy | Build from pushed Git, publish `127.0.0.1:5000/unidesk/code-queue:<commit>`, report service id, source repo, source commit, Dockerfile, tag, digest and digest ref | `deploy apply`, `kubectl apply`, scheduler/read/write rollout, task `interrupt` or `cancel` |
|
||||
| CD dry-run | deploy/artifact-registry CLI | Read `origin/master:deploy.json`, show `unidesk-dev` target objects, required registry image, no-runtime-build validation and forbidden actions | Mutating runtime objects, using dirty worktrees, using mutable tags, falling back to `codex deploy` or D601 maintenance-channel source deploy |
|
||||
| CD dry-run | deploy/artifact-registry CLI | Read `origin/master:deploy.json`, show `unidesk-dev` target objects, required registry image tag/digest provenance, pull-only/no-runtime-build validation, `selfBootstrapGuard`, `requiresSupervisorApproval` and forbidden actions | Mutating runtime objects, using dirty worktrees, using mutable tags, falling back to `codex deploy` or D601 maintenance-channel source deploy |
|
||||
| DEV live apply | Human operator after dry-run evidence | Pull/import the existing commit image, update only `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects, verify health through the Kubernetes API service proxy | Touching production `unidesk` namespace, production PostgreSQL, production scheduler/runner, running task state or Code Queue Manager prod sidecar |
|
||||
| PROD | Not implemented | Structured unsupported / dry-run evidence only | Any production Code Queue artifact deploy, manifest mutation, rollout restart, scheduler/runner rebuild, task interrupt/cancel, or self-deploy by the running Code Queue task |
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
`bun scripts/cli.ts codex deploy <commitId>` 是旧兼容入口,现已禁用。原因是它会通过 backend-core `host.ssh` 维护通道直连 D601 部署 Code Queue,把维护入口扩张成第二套部署系统。
|
||||
|
||||
Code Queue 后续正式生产部署必须走一条受控 CD 路径并单独审查;当前阶段只提供 dev artifact consumer。`deploy apply --env dev --service code-queue` 或 `artifact-registry deploy-service --env dev --service code-queue` 可以消费 D601 registry 中的 `unidesk/code-queue:<commit>`,只更新 `unidesk-dev` Code Queue execution slice,并通过 Kubernetes API service proxy 验证健康。`--env prod --service code-queue` 必须明确 unsupported,不能执行生产 artifact deploy、rollout 或 manifest 变更。persistent dev apply 的完整服务范围见 `docs/reference/dev-environment.md`,Code Queue temporary smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`。
|
||||
Code Queue 后续正式生产部署必须走一条受控 CD 路径并单独审查;当前阶段只提供 dev artifact consumer 的 dry-run/source/contract readiness。`deploy apply --env dev --service code-queue --dry-run` 或 `artifact-registry deploy-service --env dev --service code-queue --dry-run` 可以计划消费 D601 registry 中的 `unidesk/code-queue:<commit>`,但输出必须显示 `selfBootstrapGuard`、`requiresSupervisorApproval`、pull-only/no-build、image tag/digest provenance,并说明只会在获授权后更新 `unidesk-dev` Code Queue execution slice。非 dry-run DEV apply 必须由 human operator/supervisor 在 Code Queue 任务之外授权;当前 Code Queue runner 不能自己上线 Code Queue。`--env prod --service code-queue` 必须明确 unsupported,不能执行生产 artifact deploy、rollout 或 manifest 变更。persistent dev apply 的完整服务范围见 `docs/reference/dev-environment.md`,Code Queue temporary smoke 仍通过 `ci run-dev-e2e`,规则见 `docs/reference/dev-ci-runner.md`。
|
||||
|
||||
The reproducible dry-run delivery path is:
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ Phase 5 introduces the dev Code Queue execution manifest at `src/components/micr
|
||||
|
||||
All dev Code Queue components must use `unidesk-dev-runtime-config` and `unidesk-dev-runtime-secrets`, connect to `postgres-dev.../unidesk_dev`, write logs and state under `/home/ubuntu/unidesk-dev-code-queue-deploy/state`, and expose HTTP on 4222 only as ClusterIP services. The scheduler uses `CODE_QUEUE_MAIN_PROVIDER_ID=D601-dev`, `CODE_QUEUE_WORKDIR=/workspace-dev`, `CODE_QUEUE_REMOTE_WORKDIR=/home/ubuntu/unidesk-dev-workspace`, disables ClaudeQQ notifications by default, and does not use the production `d601-tcp-egress-gateway` or production PostgreSQL route.
|
||||
|
||||
Maintenance-channel direct D601 apply must not deploy dev Code Queue and the old `codex deploy` compatibility entry remains disabled. Dev Code Queue deployment is allowed only as the D601 registry artifact consumer for `deploy apply --env dev --service code-queue` or the equivalent `artifact-registry deploy-service --env dev --service code-queue`: it verifies the existing `127.0.0.1:5000/unidesk/code-queue:<commit>` artifact, imports it into native k3s containerd, applies only the `unidesk-dev` Code Queue manifest, stamps `code-queue-scheduler-dev`, `code-queue-read-dev`, `code-queue-write-dev` and `d601-dev-provider-egress-proxy`, and verifies the scheduler Service through the Kubernetes API service proxy. `deploy apply --env prod --service code-queue` and `artifact-registry deploy-service --env prod --service code-queue` must return explicit unsupported output and must not mutate production Code Queue manifests, Deployments or rollouts. The scheduler has an explicit 5Gi memory limit and must use `Recreate` rollout strategy so an update does not temporarily require two scheduler replicas under the namespace quota. All dev Code Queue containers must set CPU limits so the namespace `LimitRange` does not inject a quota-breaking default CPU limit. Live health verification uses the Kubernetes API service proxy for the dev ClusterIP Service, not `kubectl exec` or debug binaries inside the application image. This dev execution slice proves artifact deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase.
|
||||
Maintenance-channel direct D601 apply must not deploy dev Code Queue and the old `codex deploy` compatibility entry remains disabled. Dev Code Queue deployment is allowed only as the D601 registry artifact consumer dry-run for `deploy apply --env dev --service code-queue --dry-run` or the equivalent `artifact-registry deploy-service --env dev --service code-queue --dry-run`: it verifies the planned `127.0.0.1:5000/unidesk/code-queue:<commit>` artifact, target image tag, pull-only/no-build boundary, `selfBootstrapGuard`, `requiresSupervisorApproval`, and the `unidesk-dev` target list. A non-dry-run DEV apply may import the artifact into native k3s containerd, apply only the `unidesk-dev` Code Queue manifest, stamp `code-queue-scheduler-dev`, `code-queue-read-dev`, `code-queue-write-dev` and `d601-dev-provider-egress-proxy`, and verify the scheduler Service only after a human operator or supervisor authorizes the action outside the running Code Queue task. `deploy apply --env prod --service code-queue` and `artifact-registry deploy-service --env prod --service code-queue` must return explicit unsupported output and must not mutate production Code Queue manifests, Deployments or rollouts. The scheduler has an explicit 5Gi memory limit and must use `Recreate` rollout strategy so an update does not temporarily require two scheduler replicas under the namespace quota. All dev Code Queue containers must set CPU limits so the namespace `LimitRange` does not inject a quota-breaking default CPU limit. Live health verification uses the Kubernetes API service proxy for the dev ClusterIP Service, not `kubectl exec` or debug binaries inside the application image. This dev execution slice proves artifact deployability, health and dev database isolation; wiring the dev frontend stable `code-queue` route through a dev `code-queue-mgr` is a separate later phase.
|
||||
|
||||
Production `code-queue-mgr` is a separate main-server Compose sidecar artifact consumer. `deploy apply --env prod --service code-queue-mgr --dry-run` may plan only the `code-queue-mgr` Compose service/container and must surface that D601 Code Queue scheduler/runner, queued tasks, interrupts and cancellations are excluded targets. Non-dry-run production apply for this sidecar remains supervisor-gated even when the artifact exists.
|
||||
|
||||
@@ -114,9 +114,9 @@ Production `code-queue-mgr` is a separate main-server Compose sidecar artifact c
|
||||
|
||||
Environment plan output must be sufficient to review the artifact matrix without running a live apply. Each service item includes `deploymentPath`, `artifactConsumer.consumerKind`, `artifactConsumer.registryImage`, `artifactConsumer.registry`, `artifactConsumer.source`, `artifactConsumer.build`, `artifactConsumer.noRuntimeSourceBuild`, `artifactConsumer.dryRunOnly`, `target`, `validation` and `liveApply` where relevant. `consumerKind=d601-direct-compose` means the reviewed consumer touches only the D601 Docker/Compose service and private health path; `consumerKind=d601-k3s-managed` means the reviewed consumer imports the artifact into native k3s/containerd and verifies through the Kubernetes API service proxy; `consumerKind=main-server-compose` means the reviewed consumer streams or loads the D601 artifact into the main-server Compose service; `consumerKind=d601-dev-target-side-build` is retained only as a legacy classification and should not appear for backend-core. Artifact consumer plan items must explicitly report `noRuntimeSourceBuild=true`, expose registry/source/build boundaries including digest provenance, and list forbidden build/public exposure actions. Services with runtime secret gates, currently `baidu-netdisk`, must also expose a redacted `artifactConsumer.runtimeSecrets` contract with `secretSource`, `requiredSecretsPresent`, `missingSecretKeys` and `recommendedAction`; this contract may report key names, booleans and lengths only, never secret values. Blocked or gated services must keep structured `dryRunOnly` / `blockedReason` output, for example `met-nonlinear` `runtime-verification-blocked` and `k3sctl-adapter` supervisor-only production apply.
|
||||
|
||||
For `--env dev --service code-queue`, the environment plan must also expose a `boundary` block that separates the CI producer from the dev CD consumer. CI is allowed to publish only `127.0.0.1:5000/unidesk/code-queue:<commit>` plus digest/label evidence. DEV CD may consume that artifact only for `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects after an operator reviews the dry-run. For `--env prod --service code-queue`, the service item must remain `deploymentPath=unsupported`, `artifactConsumer.consumerKind=unsupported`, `target.deployCommandShape=none` and `liveApply.allowed=false`; it must not expose production k3s as an executable target. The prod boundary must state that production Code Queue CD needs a future supervisor-approved design and that this runner cannot self-deploy, mutate the production namespace, restart scheduler/runner, or interrupt/cancel tasks.
|
||||
For `--env dev --service code-queue`, the environment plan must also expose a `boundary` block that separates the CI producer from the dev CD consumer. CI is allowed to publish only `127.0.0.1:5000/unidesk/code-queue:<commit>` plus digest/label evidence. DEV CD may consume that artifact only for `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects after an operator reviews the dry-run; the plan must set `artifactConsumer.dryRunOnly=true`, `liveApply.allowed=false`, `requiresSupervisorApproval=true`, and expose a `selfBootstrapGuard` so a running Code Queue task cannot authorize its own replacement. For `--env prod --service code-queue`, the service item must remain `deploymentPath=unsupported`, `artifactConsumer.consumerKind=unsupported`, `target.deployCommandShape=none` and `liveApply.allowed=false`; it must not expose production k3s as an executable target. The prod boundary must state that production Code Queue CD needs a future supervisor-approved design and that this runner cannot self-deploy, mutate the production namespace, restart scheduler/runner, or interrupt/cancel tasks.
|
||||
|
||||
`bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service <id>] [--commit <full-sha>] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status <jobId> --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` redeploys even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for `backend-core`/`frontend`/`baidu-netdisk`/`decision-center`/`mdtodo`/`claudeqq`/dev-only `code-queue`/`project-manager`/`oa-event-flow`/`code-queue-mgr`/`todo-note`/`findjob`/`pipeline`/`met-nonlinear` artifact consumers. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`; `code-queue-mgr` prod live apply is supervisor-gated and `k3sctl-adapter` is plan/dry-run only. `--commit` may override one selected reviewed artifact consumer in either dev or prod, for example `deploy apply --env dev --service backend-core --commit <full-sha>` or `deploy apply --env dev --service frontend --commit <release-v1-full-sha>`, and the image must already exist as `127.0.0.1:5000/unidesk/<service-id>:<commit>`. Unsupported prod services, especially `code-queue`, return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build.
|
||||
`bun scripts/cli.ts deploy apply [--file deploy.json | --env dev|prod] [--service <id>] [--commit <full-sha>] [--dry-run] [--force]` starts an asynchronous job only for supported targets. Use `bun scripts/cli.ts job status <jobId> --tail-bytes 30000` to observe progress. `--dry-run` resolves the same plan but does not build or replace runtime objects. `--force` redeploys even when the live commit matches. Environment apply is not the dev e2e trigger; use `bun scripts/cli.ts ci run-dev-e2e` for the Git-controlled temporary namespace smoke flow. `--env dev` apply is enabled for `backend-core`/`frontend`/`baidu-netdisk`/`decision-center`/`mdtodo`/`claudeqq`/dev-only `code-queue` dry-run/authorized apply, `project-manager`/`oa-event-flow`/`code-queue-mgr`/`todo-note`/`findjob`/`pipeline`/`met-nonlinear` artifact consumers. `--env prod` apply exposes the D601 registry artifact consumer for `backend-core`, `frontend`, `baidu-netdisk`, `decision-center`, `mdtodo`, `claudeqq`, `project-manager`, `oa-event-flow`, `todo-note`, `findjob`, `pipeline` and `met-nonlinear`; `code-queue-mgr` prod live apply is supervisor-gated and `k3sctl-adapter` is plan/dry-run only. `--commit` may override one selected reviewed artifact consumer in either dev or prod, for example `deploy apply --env dev --service backend-core --commit <full-sha>` or `deploy apply --env dev --service frontend --commit <release-v1-full-sha>`, and the image must already exist as `127.0.0.1:5000/unidesk/<service-id>:<commit>`. Unsupported prod services, especially `code-queue`, return a structured `unsupported` payload instead of silently falling back to a maintenance-channel source build.
|
||||
|
||||
All deploy commands output JSON. Long operations must use `.state/jobs/` and bounded log tails; no deploy path may succeed with missing progress output.
|
||||
|
||||
|
||||
@@ -182,5 +182,5 @@ Code Queue is dev-only for this artifact-consumer policy.
|
||||
|
||||
- The minimal standard artifact command is `bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha> --wait-ms 1200000`.
|
||||
- The expected artifact is `127.0.0.1:5000/unidesk/code-queue:<commit>` plus its registry digest from the CI output.
|
||||
- Dev CD may consume that artifact only with `deploy apply --env dev --service code-queue`, updating `unidesk-dev` scheduler/read/write/provider-egress-proxy objects and verifying health through the Kubernetes API service proxy.
|
||||
- Dev CD may be planned only with `deploy apply --env dev --service code-queue --dry-run` or the equivalent artifact-registry dry-run from a Code Queue task. The dry-run must expose `selfBootstrapGuard`, `requiresSupervisorApproval`, commit tag/digest provenance and pull-only/no-build behavior; any real DEV apply that updates `unidesk-dev` scheduler/read/write/provider-egress-proxy objects requires human operator or supervisor authorization outside the running Code Queue task.
|
||||
- Production artifact deploy, production rollout and production manifest mutation for `code-queue` are unsupported and must fail visibly.
|
||||
|
||||
@@ -48,12 +48,28 @@ const devArtifact = asRecord(devPlan.artifactConsumer, "dev artifactConsumer");
|
||||
const devTarget = asRecord(devPlan.target, "dev target");
|
||||
const devBoundary = asRecord(devPlan.boundary, "dev boundary");
|
||||
const devCd = asRecord(devBoundary.cdConsumer, "dev cdConsumer");
|
||||
const devPlanLiveApply = asRecord(devPlan.liveApply, "dev plan liveApply");
|
||||
const devPlanGuard = asRecord(devBoundary.selfBootstrapGuard, "dev boundary selfBootstrapGuard");
|
||||
const devArtifactGuard = asRecord(devArtifact.selfBootstrapGuard, "dev artifact selfBootstrapGuard");
|
||||
const devBuild = asRecord(devArtifact.build, "dev artifact build");
|
||||
const devRegistry = asRecord(devArtifact.registry, "dev artifact registry");
|
||||
|
||||
assertCondition(devArtifact.consumerKind === "d601-k3s-managed", "dev Code Queue must be a k3s-managed artifact consumer", devArtifact);
|
||||
assertCondition(devArtifact.noRuntimeSourceBuild === true, "dev Code Queue must not build source on the runtime target", devArtifact);
|
||||
assertCondition(devArtifact.dryRunOnly === true, "dev Code Queue artifact consumer must be dry-run-only until human authorization", devArtifact);
|
||||
assertCondition(String(devArtifact.blockedReason ?? "").includes("self-bootstrap"), "dev Code Queue blocked reason should name self-bootstrap", devArtifact);
|
||||
assertCondition(devArtifact.requiresSupervisorApproval === true, "dev Code Queue artifact consumer should require supervisor approval", devArtifact);
|
||||
assertCondition(devBuild.willRunDockerBuild === false && devBuild.willRunDockerComposeBuild === false, "dev Code Queue CD must be pull-only/no-build", devBuild);
|
||||
assertCondition(devRegistry.tag === devPlan.commitId && String(devRegistry.imageRef ?? "").endsWith(`:${devPlan.commitId}`), "dev Code Queue registry plan must expose commit tag/image", devRegistry);
|
||||
assertCondition(devTarget.namespace === "unidesk-dev", "dev Code Queue target namespace must be unidesk-dev", devTarget);
|
||||
assertCondition(devTarget.deployment === "code-queue-scheduler-dev", "dev Code Queue should target the dev scheduler deployment", devTarget);
|
||||
assertCondition(devPlanLiveApply.allowed === false, "dev Code Queue live apply must be blocked for Code Queue automation", devPlanLiveApply);
|
||||
assertCondition(devPlanLiveApply.requiresSupervisorApproval === true, "dev Code Queue live apply must require supervisor approval", devPlanLiveApply);
|
||||
assertCondition(devPlanGuard.selfBootstrapBlocked === true && devArtifactGuard.selfBootstrapBlocked === true, "dev Code Queue must expose self-bootstrap guards", { devPlanGuard, devArtifactGuard });
|
||||
assertCondition(devCd.prodMutationAllowed === false, "dev Code Queue boundary must prohibit production mutation", devCd);
|
||||
assertCondition(devCd.liveApplyAllowed === false, "dev Code Queue boundary must not advertise direct live apply", devCd);
|
||||
assertCondition(devCd.liveApplyCommandShape === null, "dev Code Queue boundary must not advertise a run-now command", devCd);
|
||||
assertCondition(devCd.requiresSupervisorApproval === true, "dev Code Queue boundary should require supervisor approval", devCd);
|
||||
assertCondition(String(devCd.manualAuthorizationPoint ?? "").includes("DEV apply"), "dev Code Queue boundary should expose the DEV manual authorization point", devCd);
|
||||
assertCondition(asRecord(devBoundary.ciProducer, "dev ciProducer").allowed === true, "Code Queue CI producer should be allowed for image publication", devBoundary);
|
||||
assertCondition(includes(devTarget.forbiddenActions, "docker build"), "dev target must forbid runtime docker build", devTarget);
|
||||
@@ -64,6 +80,7 @@ const prodArtifact = asRecord(prodPlan.artifactConsumer, "prod artifactConsumer"
|
||||
const prodTarget = asRecord(prodPlan.target, "prod target");
|
||||
const prodBoundary = asRecord(prodPlan.boundary, "prod boundary");
|
||||
const prodCd = asRecord(prodBoundary.cdConsumer, "prod cdConsumer");
|
||||
const prodGuard = asRecord(prodBoundary.selfBootstrapGuard, "prod boundary selfBootstrapGuard");
|
||||
const prodLiveApply = asRecord(prodPlan.liveApply, "prod liveApply");
|
||||
const prodUnsupported = asRecord(prodPlan.unsupported, "prod unsupported");
|
||||
const prodForbidden = asStringArray(prodTarget.forbiddenActions, "prod forbiddenActions");
|
||||
@@ -72,6 +89,7 @@ assertCondition(prodPlan.deploymentPath === "unsupported", "prod Code Queue depl
|
||||
assertCondition(prodArtifact.consumerKind === "unsupported", "prod Code Queue artifact consumer must be unsupported", prodArtifact);
|
||||
assertCondition(prodArtifact.registryImage === null, "prod Code Queue plan must not advertise a production registry image target", prodArtifact);
|
||||
assertCondition(prodArtifact.noRuntimeSourceBuild === true, "prod Code Queue plan must still block runtime source builds", prodArtifact);
|
||||
assertCondition(prodArtifact.requiresSupervisorApproval === true, "prod Code Queue artifact consumer should require supervisor approval", prodArtifact);
|
||||
assertCondition(prodTarget.runtimeHost === null, "prod Code Queue plan must not expose a runtime host target", prodTarget);
|
||||
assertCondition(prodTarget.deployCommandShape === "none", "prod Code Queue plan must not expose a deploy command shape", prodTarget);
|
||||
assertCondition(prodLiveApply.allowed === false, "prod Code Queue live apply must be blocked", prodLiveApply);
|
||||
@@ -79,6 +97,8 @@ assertCondition(String(prodLiveApply.reason ?? "").includes("production CD is in
|
||||
assertCondition(String(prodUnsupported.reason ?? "").includes("prod artifact deploy"), "prod unsupported reason should mention prod artifact deploy", prodUnsupported);
|
||||
assertCondition(prodCd.prodMutationAllowed === false, "prod Code Queue boundary must prohibit production mutation", prodCd);
|
||||
assertCondition(prodCd.liveApplyCommandShape === null, "prod Code Queue boundary must not advertise a live apply command", prodCd);
|
||||
assertCondition(prodCd.requiresSupervisorApproval === true, "prod Code Queue boundary should require supervisor approval", prodCd);
|
||||
assertCondition(prodGuard.selfBootstrapBlocked === true, "prod Code Queue boundary should expose self-bootstrap guard", prodGuard);
|
||||
assertCondition(String(prodCd.manualAuthorizationPoint ?? "").includes("future supervisor-approved"), "prod boundary should require a future supervisor-approved design", prodCd);
|
||||
assertCondition(prodForbidden.includes("production namespace mutation"), "prod forbidden actions must include production namespace mutation", prodTarget);
|
||||
assertCondition(prodForbidden.includes("interrupt running Code Queue tasks"), "prod forbidden actions must include task interrupt", prodTarget);
|
||||
@@ -97,7 +117,23 @@ const devArtifactDryRun = asRecord(runCli([
|
||||
"--dry-run",
|
||||
], 0).data, "dev artifact-registry dry-run");
|
||||
const artifactTarget = asRecord(devArtifactDryRun.target, "artifact dry-run target");
|
||||
const artifactRegistry = asRecord(devArtifactDryRun.registry, "artifact dry-run registry");
|
||||
const artifactBuild = asRecord(devArtifactDryRun.build, "artifact dry-run build");
|
||||
const artifactLiveApply = asRecord(devArtifactDryRun.liveApply, "artifact dry-run liveApply");
|
||||
const artifactGuard = asRecord(devArtifactDryRun.selfBootstrapGuard, "artifact dry-run selfBootstrapGuard");
|
||||
const artifactAffectedRuntime = asRecord(devArtifactDryRun.affectedRuntime, "artifact dry-run affectedRuntime");
|
||||
const artifactExcludedTargets = JSON.stringify(devArtifactDryRun.excludedTargets);
|
||||
assertCondition(devArtifactDryRun.mutation === false, "artifact-registry dev dry-run must be non-mutating", devArtifactDryRun);
|
||||
assertCondition(devArtifactDryRun.requiresSupervisorApproval === true, "artifact-registry dev dry-run must require supervisor approval", devArtifactDryRun);
|
||||
assertCondition(artifactRegistry.imageRef === `127.0.0.1:5000/unidesk/code-queue:${commit}`, "artifact-registry dev dry-run should expose commit-pinned image", artifactRegistry);
|
||||
assertCondition(artifactRegistry.digest === null && String(artifactRegistry.digestSource ?? "").includes("manifest HEAD"), "artifact-registry dev dry-run should expose digest provenance", artifactRegistry);
|
||||
assertCondition(artifactBuild.willCompile === false && artifactBuild.willRunDockerBuild === false && artifactBuild.willRunDockerComposeBuild === false, "artifact-registry dev dry-run must be pull-only/no-build", artifactBuild);
|
||||
assertCondition(artifactLiveApply.allowed === false && artifactLiveApply.policy === "supervisor-only", "artifact-registry dev dry-run must block self-bootstrap live apply", artifactLiveApply);
|
||||
assertCondition(artifactLiveApply.requiresSupervisorApproval === true, "artifact-registry dev liveApply should require supervisor approval", artifactLiveApply);
|
||||
assertCondition(artifactGuard.selfBootstrapBlocked === true, "artifact-registry dev dry-run must expose self-bootstrap guard", artifactGuard);
|
||||
assertCondition(artifactAffectedRuntime.productionNamespaceAffected === false, "artifact-registry dev dry-run must not affect production namespace", artifactAffectedRuntime);
|
||||
assertCondition(artifactAffectedRuntime.activeTaskInterruptCancelAffected === false, "artifact-registry dev dry-run must not affect active task control", artifactAffectedRuntime);
|
||||
assertCondition(artifactExcludedTargets.includes("active tasks") && artifactExcludedTargets.includes("cancel"), "artifact-registry dev dry-run should exclude active task interrupt/cancel", devArtifactDryRun);
|
||||
assertCondition(artifactTarget.namespace === "unidesk-dev", "artifact-registry dev dry-run must target unidesk-dev", artifactTarget);
|
||||
|
||||
const prodArtifactDryRun = asRecord(runCli([
|
||||
@@ -113,6 +149,9 @@ const prodArtifactDryRun = asRecord(runCli([
|
||||
], 1).data, "prod artifact-registry dry-run");
|
||||
assertCondition(prodArtifactDryRun.error === "unsupported-environment", "artifact-registry prod code-queue should be unsupported", prodArtifactDryRun);
|
||||
assertCondition(Array.isArray(prodArtifactDryRun.supportedEnvironments) && prodArtifactDryRun.supportedEnvironments.length === 1 && prodArtifactDryRun.supportedEnvironments[0] === "dev", "artifact-registry prod code-queue should expose only dev as supported", prodArtifactDryRun);
|
||||
assertCondition(prodArtifactDryRun.requiresSupervisorApproval === true, "artifact-registry prod code-queue should require supervisor approval before any future design", prodArtifactDryRun);
|
||||
assertCondition(asRecord(prodArtifactDryRun.selfBootstrapGuard, "prod artifact selfBootstrapGuard").selfBootstrapBlocked === true, "artifact-registry prod code-queue should expose self-bootstrap guard", prodArtifactDryRun);
|
||||
assertCondition(JSON.stringify(prodArtifactDryRun).includes("production artifact deploy") && JSON.stringify(prodArtifactDryRun).includes("active task"), "artifact-registry prod code-queue should explain prod deploy and active-task boundaries", prodArtifactDryRun);
|
||||
|
||||
process.stdout.write(`${JSON.stringify({
|
||||
ok: true,
|
||||
|
||||
@@ -88,6 +88,7 @@ function assertCommonDryRun(plan: JsonRecord, deployRef: string): void {
|
||||
const probe = asRecord(plan.registryProbe, "dry-run registryProbe");
|
||||
const target = asRecord(plan.target, "dry-run target");
|
||||
const liveApply = asRecord(plan.liveApply, "dry-run liveApply");
|
||||
const guard = asRecord(plan.selfBootstrapGuard, "dry-run selfBootstrapGuard");
|
||||
const validation = strings(plan.validation, "dry-run validation");
|
||||
const excludedTargets = asArray(plan.excludedTargets, "dry-run excludedTargets").map((item, index) => asRecord(item, `excludedTargets[${index}]`));
|
||||
const excludedText = JSON.stringify(excludedTargets);
|
||||
@@ -130,7 +131,11 @@ function assertCommonDryRun(plan: JsonRecord, deployRef: string): void {
|
||||
|
||||
assertCondition(liveApply.policy === "supervisor-only", "code-queue-mgr prod live apply must be supervisor-only", liveApply);
|
||||
assertCondition(liveApply.allowed === false, "code-queue-mgr prod live apply must be blocked in automation", liveApply);
|
||||
assertCondition(liveApply.requiresSupervisorApproval === true, "code-queue-mgr prod live apply must require supervisor approval", liveApply);
|
||||
assertCondition(String(liveApply.reason ?? "").includes("explicit supervisor confirmation"), "code-queue-mgr live apply reason must name supervisor confirmation", liveApply);
|
||||
assertCondition(plan.requiresSupervisorApproval === true, "code-queue-mgr prod dry-run must expose top-level supervisor approval requirement", plan);
|
||||
assertCondition(guard.selfBootstrapBlocked === true, "code-queue-mgr prod dry-run must expose self-bootstrap guard", guard);
|
||||
assertCondition(String(guard.targetScope ?? "").includes("code-queue-mgr-backend"), "code-queue-mgr guard must name the control-plane sidecar target", guard);
|
||||
assertCondition(validation.some((line) => line.includes("deploy.commit/deploy.requestedCommit")), "code-queue-mgr validation must require health deploy commit metadata", validation);
|
||||
assertCondition(excludedText.includes("code-queue"), "code-queue-mgr excluded targets must include code-queue", excludedTargets);
|
||||
assertCondition(excludedText.includes("scheduler"), "code-queue-mgr excluded targets must mention scheduler", excludedTargets);
|
||||
|
||||
@@ -140,6 +140,8 @@ interface ArtifactConsumerSpec {
|
||||
targets: Partial<Record<ArtifactDeployEnvironment, ArtifactConsumerTarget>>;
|
||||
prodLiveApply: "enabled" | "supervisor-only" | "unsupported";
|
||||
prodLiveBlockReason?: string;
|
||||
devLiveApply?: "enabled" | "supervisor-only";
|
||||
devLiveBlockReason?: string;
|
||||
runtimeVerification?: "strict" | "blocked";
|
||||
runtimeVerificationBlockReason?: string;
|
||||
}
|
||||
@@ -503,7 +505,9 @@ const artifactConsumerSpecs: Record<string, ArtifactConsumerSpec> = {
|
||||
registryRepository: "unidesk/code-queue",
|
||||
dockerfile: "src/components/microservices/code-queue/Dockerfile",
|
||||
prodLiveApply: "unsupported",
|
||||
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no prod artifact deploy, rollout, or manifest mutation target.",
|
||||
prodLiveBlockReason: "code-queue is dev-only for artifact consumer validation and has no production artifact deploy, production rollout, or production manifest mutation target.",
|
||||
devLiveApply: "supervisor-only",
|
||||
devLiveBlockReason: "Code Queue DEV live apply is self-bootstrap sensitive: a running Code Queue task may plan only dry-run evidence. A human operator or supervisor must explicitly authorize DEV apply outside Code Queue after reviewing the CI artifact digest and dry-run target list.",
|
||||
targets: {
|
||||
dev: {
|
||||
targetImage: "unidesk-code-queue:dev",
|
||||
@@ -1315,6 +1319,10 @@ function unsupportedService(serviceId: string, options: ArtifactRegistryOptions)
|
||||
|
||||
function unsupportedEnvironment(spec: ArtifactConsumerSpec, options: ArtifactRegistryOptions): Record<string, unknown> {
|
||||
const environment = options.environment ?? "prod";
|
||||
const codeQueueGuard = spec.serviceId === "code-queue" ? codeQueueSelfBootstrapGuard(environment) : undefined;
|
||||
const reason = spec.serviceId === "code-queue" && environment === "prod"
|
||||
? spec.prodLiveBlockReason ?? "Code Queue production artifact deploy, rollout and manifest mutation are intentionally unsupported in this phase."
|
||||
: `No standardized ${environment} registry artifact consumer is implemented for ${spec.serviceId}.`;
|
||||
return {
|
||||
ok: false,
|
||||
supported: false,
|
||||
@@ -1322,14 +1330,125 @@ function unsupportedEnvironment(spec: ArtifactConsumerSpec, options: ArtifactReg
|
||||
serviceId: spec.serviceId,
|
||||
environment,
|
||||
providerId: options.providerId,
|
||||
reason: `No standardized ${environment} registry artifact consumer is implemented for ${spec.serviceId}.`,
|
||||
reason,
|
||||
supportedEnvironments: Object.keys(spec.targets),
|
||||
requiresSupervisorApproval: spec.serviceId === "code-queue",
|
||||
selfBootstrapGuard: codeQueueGuard,
|
||||
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, false) : undefined,
|
||||
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
|
||||
policy: "artifact CD must not silently fall back to maintenance-channel source builds or legacy direct deployment",
|
||||
};
|
||||
}
|
||||
|
||||
function artifactConsumerLivePolicy(spec: ArtifactConsumerSpec, environment: ArtifactDeployEnvironment): "enabled" | "supervisor-only" | "unsupported" {
|
||||
return environment === "prod" ? spec.prodLiveApply : spec.devLiveApply ?? "enabled";
|
||||
}
|
||||
|
||||
function artifactConsumerLiveBlockReason(spec: ArtifactConsumerSpec, environment: ArtifactDeployEnvironment): string | null {
|
||||
if (spec.runtimeVerificationBlockReason !== undefined) return spec.runtimeVerificationBlockReason;
|
||||
return environment === "prod" ? spec.prodLiveBlockReason ?? null : spec.devLiveBlockReason ?? null;
|
||||
}
|
||||
|
||||
function codeQueueExcludedTargets(environment: ArtifactDeployEnvironment): Record<string, unknown>[] {
|
||||
const excluded: Record<string, unknown>[] = [
|
||||
{
|
||||
namespace: "unidesk",
|
||||
deployments: ["code-queue", "code-queue-read", "code-queue-write", "d601-provider-egress-proxy", "d601-tcp-egress-gateway"],
|
||||
reason: "production Code Queue execution-plane Deployments are outside this artifact consumer and must not be mutated by dry-run or self-bootstrap automation.",
|
||||
},
|
||||
{
|
||||
operations: ["restart scheduler", "restart runner", "interrupt active tasks", "cancel active tasks"],
|
||||
reason: "artifact CD planning must not alter scheduler/runner lifecycle or active task control state.",
|
||||
},
|
||||
];
|
||||
if (environment === "dev") {
|
||||
excluded.push({
|
||||
namespace: "unidesk-dev",
|
||||
nonDryRunMutation: "requires explicit supervisor or human authorization outside the running Code Queue task",
|
||||
reason: "DEV is the only Code Queue artifact consumer target, but self-bootstrap automation may produce dry-run evidence only.",
|
||||
});
|
||||
}
|
||||
return excluded;
|
||||
}
|
||||
|
||||
function codeQueueAffectedRuntime(environment: ArtifactDeployEnvironment, targetPlanned: boolean): Record<string, unknown> {
|
||||
return {
|
||||
dryRunMutation: false,
|
||||
plannedTarget: targetPlanned && environment === "dev"
|
||||
? {
|
||||
namespace: "unidesk-dev",
|
||||
deployments: ["code-queue-scheduler-dev", "code-queue-read-dev", "code-queue-write-dev", "d601-dev-provider-egress-proxy"],
|
||||
}
|
||||
: null,
|
||||
productionNamespaceAffected: false,
|
||||
productionSchedulerRunnerAffected: false,
|
||||
activeTaskControlAffected: false,
|
||||
activeTaskInterruptCancelAffected: false,
|
||||
};
|
||||
}
|
||||
|
||||
function codeQueueSelfBootstrapGuard(environment: ArtifactDeployEnvironment): Record<string, unknown> {
|
||||
return {
|
||||
check: "code-queue-self-bootstrap-guard",
|
||||
serviceId: "code-queue",
|
||||
selfBootstrapBlocked: true,
|
||||
requiresSupervisorApproval: true,
|
||||
actorBoundary: "a running Code Queue task may publish contract evidence and dry-run plans only; it must not deploy Code Queue itself",
|
||||
devApply: "requires explicit supervisor or human authorization outside the running Code Queue task",
|
||||
prodApply: "unsupported until a separate supervisor-approved production Code Queue CD design exists",
|
||||
allowedWithoutApproval: [
|
||||
"CI artifact publication",
|
||||
"deploy plan",
|
||||
"deploy apply --dry-run",
|
||||
"artifact-registry deploy-service --dry-run",
|
||||
],
|
||||
forbiddenActions: [
|
||||
"self-deploy Code Queue from Code Queue",
|
||||
"run a non-dry-run DEV apply from Code Queue",
|
||||
"production namespace mutation",
|
||||
"production manifest mutation",
|
||||
"scheduler or runner restart",
|
||||
"active task interrupt",
|
||||
"active task cancel",
|
||||
],
|
||||
environment,
|
||||
};
|
||||
}
|
||||
|
||||
function codeQueueMgrSelfBootstrapGuard(environment: ArtifactDeployEnvironment, requiresSupervisorApproval: boolean): Record<string, unknown> {
|
||||
return {
|
||||
check: "code-queue-mgr-control-plane-guard",
|
||||
serviceId: "code-queue-mgr",
|
||||
selfBootstrapBlocked: true,
|
||||
requiresSupervisorApproval,
|
||||
actorBoundary: "dry-run is allowed, but a running Code Queue task must not replace the Code Queue control-plane sidecar as part of delivering Code Queue itself",
|
||||
targetScope: "main-server Compose service code-queue-mgr / container code-queue-mgr-backend only",
|
||||
prodApply: "requires explicit supervisor confirmation",
|
||||
environment,
|
||||
forbiddenActions: [
|
||||
"mutate D601 Code Queue scheduler",
|
||||
"mutate D601 Code Queue runner",
|
||||
"restart active tasks",
|
||||
"interrupt active tasks",
|
||||
"cancel active tasks",
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
function artifactConsumerSelfBootstrapGuard(
|
||||
spec: ArtifactConsumerSpec,
|
||||
environment: ArtifactDeployEnvironment,
|
||||
requiresSupervisorApproval: boolean,
|
||||
): Record<string, unknown> | undefined {
|
||||
if (spec.serviceId === "code-queue") return codeQueueSelfBootstrapGuard(environment);
|
||||
if (spec.serviceId === "code-queue-mgr") return codeQueueMgrSelfBootstrapGuard(environment, requiresSupervisorApproval);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: ArtifactRegistryOptions): Record<string, unknown> | null {
|
||||
const environment = options.environment ?? "prod";
|
||||
const livePolicy = artifactConsumerLivePolicy(spec, environment);
|
||||
const liveReason = artifactConsumerLiveBlockReason(spec, environment);
|
||||
if (spec.runtimeVerification === "blocked") {
|
||||
return {
|
||||
ok: false,
|
||||
@@ -1347,8 +1466,8 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
|
||||
policy: "artifact CD must not accept a healthy old service or silently fall back to legacy rebuild paths",
|
||||
};
|
||||
}
|
||||
if (environment !== "prod" || spec.prodLiveApply === "enabled") return null;
|
||||
if (spec.prodLiveApply === "supervisor-only") {
|
||||
if (livePolicy === "enabled") return null;
|
||||
if (livePolicy === "supervisor-only") {
|
||||
return {
|
||||
ok: false,
|
||||
supported: true,
|
||||
@@ -1357,9 +1476,13 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
|
||||
serviceId: spec.serviceId,
|
||||
environment,
|
||||
providerId: options.providerId,
|
||||
reason: spec.prodLiveBlockReason ?? `${spec.serviceId} production artifact apply requires supervisor confirmation.`,
|
||||
dryRunCommandShape: `bun scripts/cli.ts artifact-registry deploy-service --env prod --service ${spec.serviceId} --commit <full-sha> --dry-run`,
|
||||
policy: "worker automation must not perform live production apply for this infrastructure control-plane service",
|
||||
reason: liveReason ?? `${spec.serviceId} ${environment} artifact apply requires supervisor confirmation.`,
|
||||
requiresSupervisorApproval: true,
|
||||
selfBootstrapGuard: artifactConsumerSelfBootstrapGuard(spec, environment, true),
|
||||
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, true) : undefined,
|
||||
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
|
||||
dryRunCommandShape: `bun scripts/cli.ts artifact-registry deploy-service --env ${environment} --service ${spec.serviceId} --commit <full-sha> --dry-run`,
|
||||
policy: "worker automation must not perform live apply for this supervisor-gated artifact consumer",
|
||||
};
|
||||
}
|
||||
return {
|
||||
@@ -1370,7 +1493,11 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
|
||||
serviceId: spec.serviceId,
|
||||
environment,
|
||||
providerId: options.providerId,
|
||||
reason: spec.prodLiveBlockReason ?? `${spec.serviceId} does not yet satisfy the artifact consumer runtime verification contract.`,
|
||||
reason: liveReason ?? `${spec.serviceId} does not yet satisfy the artifact consumer runtime verification contract.`,
|
||||
requiresSupervisorApproval: spec.serviceId === "code-queue",
|
||||
selfBootstrapGuard: spec.serviceId === "code-queue" ? codeQueueSelfBootstrapGuard(environment) : undefined,
|
||||
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, false) : undefined,
|
||||
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
|
||||
requiredBeforeLiveApply: [
|
||||
"CI can publish a commit-pinned image with matching service id, source repo, source commit, and Dockerfile labels",
|
||||
"runtime Compose env injects deploy commit/requestedCommit metadata",
|
||||
@@ -1380,6 +1507,7 @@ function artifactConsumerLiveBlock(spec: ArtifactConsumerSpec, options: Artifact
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function artifactImageRef(options: ArtifactRegistryOptions, spec: ArtifactConsumerSpec, commit: string): string {
|
||||
return `127.0.0.1:${options.port}/${(options.dryRun ? options.deployJsonService?.artifact?.repository : undefined) ?? spec.registryRepository}:${commit}`;
|
||||
}
|
||||
@@ -2627,7 +2755,9 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
: [];
|
||||
if (drifts.length > 0) return deployJsonDriftResult(deployJsonService, environment, drifts);
|
||||
const verificationBlocked = spec.runtimeVerification === "blocked";
|
||||
const livePolicy = environment === "prod" ? spec.prodLiveApply : "enabled";
|
||||
const livePolicy = artifactConsumerLivePolicy(spec, environment);
|
||||
const liveReason = artifactConsumerLiveBlockReason(spec, environment);
|
||||
const requiresSupervisorApproval = livePolicy === "supervisor-only" || spec.serviceId === "code-queue";
|
||||
const sourceImage = artifactImageRef(effectiveOptions, spec, commit);
|
||||
const registryEndpoint = `http://127.0.0.1:${effectiveOptions.port}`;
|
||||
const config = readConfig();
|
||||
@@ -2689,9 +2819,13 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
boundary: `${environment} CD is artifact-consumer only: verify commit-pinned registry image, pull/import, deploy, then verify live commit/image/health; it never builds source on the runtime target`,
|
||||
liveApply: {
|
||||
policy: livePolicy,
|
||||
allowed: !verificationBlocked && (environment !== "prod" || spec.prodLiveApply === "enabled"),
|
||||
reason: spec.runtimeVerificationBlockReason ?? (environment === "prod" ? spec.prodLiveBlockReason ?? null : null),
|
||||
allowed: !verificationBlocked && livePolicy === "enabled",
|
||||
requiresSupervisorApproval,
|
||||
reason: liveReason,
|
||||
},
|
||||
requiresSupervisorApproval,
|
||||
selfBootstrapGuard: artifactConsumerSelfBootstrapGuard(spec, environment, requiresSupervisorApproval),
|
||||
affectedRuntime: spec.serviceId === "code-queue" ? codeQueueAffectedRuntime(environment, true) : undefined,
|
||||
sourceOfTruth: deployJsonService !== null && hasDeployJsonExecutorContract(deployJsonService) ? deployJsonSourceOfTruth(deployJsonService, environment) : undefined,
|
||||
driftCheck: deployJsonService !== null && hasDeployJsonExecutorContract(deployJsonService) ? {
|
||||
ok: true,
|
||||
@@ -2727,6 +2861,8 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
reason: "dry-run does not mutate D601 Code Queue scheduler, runner, tasks, interrupts, or cancellations.",
|
||||
},
|
||||
]
|
||||
: spec.serviceId === "code-queue"
|
||||
? codeQueueExcludedTargets(environment)
|
||||
: undefined,
|
||||
validation: [
|
||||
"D601 registry /v2 manifest exists for the commit tag",
|
||||
@@ -2800,6 +2936,7 @@ function dryRunArtifactConsumerPlan(options: ArtifactRegistryOptions, spec: Arti
|
||||
memory: contractRuntime.memory,
|
||||
health: contractRuntime.health,
|
||||
},
|
||||
excludedTargets: spec.serviceId === "code-queue" ? codeQueueExcludedTargets(environment) : undefined,
|
||||
validation: [
|
||||
"D601 registry /v2 manifest exists for the commit tag before mutation",
|
||||
"D601 Docker-pulled image labels match service id, source repo, source commit, and Dockerfile",
|
||||
@@ -3183,7 +3320,7 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
],
|
||||
firstStage: "install now writes the rendered systemd/Compose/config files and starts the registry",
|
||||
artifactConsumers: {
|
||||
@@ -3218,7 +3355,7 @@ function localHelp(): Record<string, unknown> {
|
||||
"bun scripts/cli.ts deploy apply --env dev --service met-nonlinear --dry-run",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service mdtodo",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service claudeqq",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service code-queue",
|
||||
"bun scripts/cli.ts deploy apply --env dev --service code-queue --dry-run",
|
||||
],
|
||||
devOnlyConsumers: ["code-queue"],
|
||||
rollbackShape: "rerun the same artifact consumer with a previous commit-pinned image",
|
||||
|
||||
+82
-6
@@ -158,6 +158,9 @@ const prodArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
|
||||
["met-nonlinear", "met-nonlinear is blocked for live artifact deploy because config.json points at docker/unidesk/Dockerfile.ml while the compose service is met-nonlinear-ts."],
|
||||
["k3sctl-adapter", "k3sctl-adapter is an infrastructure control bridge; this executor exposes artifact consumer plan/dry-run only. Real production deployment requires supervisor confirmation outside this task."],
|
||||
]);
|
||||
const devArtifactLiveApplyBlockedServiceIds = new Map<string, string>([
|
||||
["code-queue", "Code Queue DEV live apply is self-bootstrap sensitive: a running Code Queue task may produce dry-run evidence only. A human operator or supervisor must explicitly authorize DEV apply outside Code Queue after reviewing the CI artifact digest and dry-run target list."],
|
||||
]);
|
||||
const artifactConsumerDryRunBlockedServiceIds = new Map<string, string>([
|
||||
["met-nonlinear", "runtime-verification-blocked: CI publishes the ML image Dockerfile contract, but the long-running Compose service is met-nonlinear-ts; CD cannot yet prove the running container image label matches the requested commit."],
|
||||
]);
|
||||
@@ -1141,11 +1144,41 @@ function unsupportedPlanTarget(serviceId: string, environment: DeployEnvironment
|
||||
};
|
||||
}
|
||||
|
||||
function codeQueueSelfBootstrapGuard(environment: DeployEnvironment): Record<string, unknown> | undefined {
|
||||
if (environment !== "dev" && environment !== "prod") return undefined;
|
||||
return {
|
||||
check: "code-queue-self-bootstrap-guard",
|
||||
selfBootstrapBlocked: true,
|
||||
requiresSupervisorApproval: true,
|
||||
actorBoundary: "a running Code Queue task may publish contract evidence and dry-run plans only; it must not deploy Code Queue itself",
|
||||
devApply: "requires explicit supervisor or human authorization outside the running Code Queue task",
|
||||
prodApply: "unsupported until a separate supervisor-approved production Code Queue CD design exists",
|
||||
allowedWithoutApproval: [
|
||||
"CI artifact publication",
|
||||
"deploy plan",
|
||||
"deploy apply --dry-run",
|
||||
"artifact-registry deploy-service --dry-run",
|
||||
],
|
||||
forbiddenActions: [
|
||||
"self-deploy Code Queue from Code Queue",
|
||||
"run a non-dry-run DEV apply from Code Queue",
|
||||
"production namespace mutation",
|
||||
"production manifest mutation",
|
||||
"scheduler or runner restart",
|
||||
"active task interrupt",
|
||||
"active task cancel",
|
||||
],
|
||||
environment,
|
||||
};
|
||||
}
|
||||
|
||||
function codeQueueCiCdBoundary(serviceId: string, environment: DeployEnvironment): Record<string, unknown> | undefined {
|
||||
if (serviceId !== "code-queue") return undefined;
|
||||
return {
|
||||
serviceId,
|
||||
selfDeployBlocked: true,
|
||||
requiresSupervisorApproval: true,
|
||||
selfBootstrapGuard: codeQueueSelfBootstrapGuard(environment),
|
||||
ciProducer: {
|
||||
command: "bun scripts/cli.ts ci publish-user-service --service code-queue --commit <full-sha>",
|
||||
allowed: true,
|
||||
@@ -1157,7 +1190,9 @@ function codeQueueCiCdBoundary(serviceId: string, environment: DeployEnvironment
|
||||
? {
|
||||
environment: "dev",
|
||||
dryRunCommand: "bun scripts/cli.ts deploy apply --env dev --service code-queue --commit <full-sha> --dry-run",
|
||||
liveApplyCommandShape: "bun scripts/cli.ts deploy apply --env dev --service code-queue --commit <full-sha> --run-now",
|
||||
liveApplyCommandShape: null,
|
||||
liveApplyAllowed: false,
|
||||
requiresSupervisorApproval: true,
|
||||
allowedTarget: "unidesk-dev Code Queue scheduler/read/write/provider-egress-proxy only",
|
||||
manualAuthorizationPoint: "operator reviews CI artifact summary and dev dry-run plan, then explicitly authorizes DEV apply outside this Code Queue task",
|
||||
prodMutationAllowed: false,
|
||||
@@ -1166,6 +1201,8 @@ function codeQueueCiCdBoundary(serviceId: string, environment: DeployEnvironment
|
||||
environment: "prod",
|
||||
dryRunCommand: "bun scripts/cli.ts deploy plan --env prod --service code-queue",
|
||||
liveApplyCommandShape: null,
|
||||
liveApplyAllowed: false,
|
||||
requiresSupervisorApproval: true,
|
||||
allowedTarget: null,
|
||||
manualAuthorizationPoint: "PROD requires a future supervisor-approved Code Queue CD design; current runner output is plan/unsupported only",
|
||||
prodMutationAllowed: false,
|
||||
@@ -3072,6 +3109,10 @@ function environmentDryRunPlan(
|
||||
: planTarget;
|
||||
const registryRepository = service.artifact?.repository ?? `unidesk/${service.id}`;
|
||||
const stableImage = service.consumer?.target.stableImage;
|
||||
const liveApplyBlockedReason = environment === "prod"
|
||||
? prodArtifactLiveApplyBlockedServiceIds.get(service.id) ?? null
|
||||
: devArtifactLiveApplyBlockedServiceIds.get(service.id) ?? null;
|
||||
const dryRunOnly = unsupported || liveApplyBlockedReason !== null || dryRunBlockedReason !== null;
|
||||
return {
|
||||
id: service.id,
|
||||
repo: service.repo,
|
||||
@@ -3119,8 +3160,10 @@ function environmentDryRunPlan(
|
||||
"unidesk.ai/dockerfile": serviceConfig.repository.dockerfile,
|
||||
},
|
||||
noRuntimeSourceBuild: unsupported || (service.consumer?.noRuntimeSourceBuild ?? effectivePlanKind !== "d601-dev-target-side-build"),
|
||||
dryRunOnly: unsupported || (environment === "prod" && prodArtifactLiveApplyBlockedServiceIds.has(service.id)) || dryRunBlockedReason !== null,
|
||||
blockedReason: unsupportedReason ?? dryRunBlockedReason ?? (environment === "prod" ? prodArtifactLiveApplyBlockedServiceIds.get(service.id) ?? null : null),
|
||||
dryRunOnly,
|
||||
blockedReason: unsupportedReason ?? dryRunBlockedReason ?? liveApplyBlockedReason,
|
||||
requiresSupervisorApproval: service.id === "code-queue" || liveApplyBlockedReason !== null,
|
||||
selfBootstrapGuard: service.id === "code-queue" ? codeQueueSelfBootstrapGuard(environment) : undefined,
|
||||
runtimeSecrets,
|
||||
sourceOfTruth: deployJsonContract ? deployJsonSourceOfTruth(service, environment) : undefined,
|
||||
driftCheck: deployJsonContract ? {
|
||||
@@ -3162,11 +3205,12 @@ function environmentDryRunPlan(
|
||||
reason: dryRunBlockedReason,
|
||||
dryRunOnly: true,
|
||||
}
|
||||
: environment === "prod" && prodArtifactLiveApplyBlockedServiceIds.has(service.id)
|
||||
: liveApplyBlockedReason !== null
|
||||
? {
|
||||
allowed: false,
|
||||
reason: prodArtifactLiveApplyBlockedServiceIds.get(service.id),
|
||||
reason: liveApplyBlockedReason,
|
||||
dryRunOnly: true,
|
||||
requiresSupervisorApproval: true,
|
||||
}
|
||||
: environment === "prod"
|
||||
? { allowed: prodArtifactConsumerServiceIds.has(service.id) }
|
||||
@@ -3240,7 +3284,17 @@ function prodArtifactUnsupportedResult(services: DeployManifestService[]): Recor
|
||||
repo: service.repo,
|
||||
commitId: service.commitId,
|
||||
supported: false,
|
||||
reason: "No standardized prod D601 registry artifact consumer is implemented for this service.",
|
||||
reason: unsupportedEnvironmentPlanReason(service.id, "prod"),
|
||||
requiresSupervisorApproval: service.id === "code-queue",
|
||||
selfBootstrapGuard: service.id === "code-queue" ? codeQueueSelfBootstrapGuard("prod") : undefined,
|
||||
affectedRuntime: service.id === "code-queue" ? {
|
||||
dryRunMutation: false,
|
||||
plannedTarget: null,
|
||||
productionNamespaceAffected: false,
|
||||
productionSchedulerRunnerAffected: false,
|
||||
activeTaskControlAffected: false,
|
||||
activeTaskInterruptCancelAffected: false,
|
||||
} : undefined,
|
||||
})),
|
||||
policy: "prod deploy must not silently fall back to legacy D601 maintenance-channel source builds",
|
||||
supportedServices: Array.from(prodArtifactConsumerServiceIds),
|
||||
@@ -3294,6 +3348,26 @@ function prodArtifactLiveApplyBlockedResult(services: DeployManifestService[]):
|
||||
};
|
||||
}
|
||||
|
||||
function devArtifactLiveApplyBlockedResult(services: DeployManifestService[]): Record<string, unknown> {
|
||||
return {
|
||||
ok: false,
|
||||
supported: true,
|
||||
error: "live-dev-apply-blocked",
|
||||
services: services.map((service) => ({
|
||||
id: service.id,
|
||||
repo: service.repo,
|
||||
commitId: service.commitId,
|
||||
supported: true,
|
||||
liveApplyAllowed: false,
|
||||
requiresSupervisorApproval: true,
|
||||
reason: devArtifactLiveApplyBlockedServiceIds.get(service.id) ?? "live DEV artifact apply is blocked by policy",
|
||||
selfBootstrapGuard: service.id === "code-queue" ? codeQueueSelfBootstrapGuard("dev") : undefined,
|
||||
})),
|
||||
policy: "dev dry-run/plan is available, but a running Code Queue task must not perform live DEV Code Queue apply without explicit supervisor or human authorization outside Code Queue",
|
||||
dryRunCommandShape: "bun scripts/cli.ts deploy apply --env dev --service <id> --dry-run",
|
||||
};
|
||||
}
|
||||
|
||||
async function runArtifactConsumerApplyNow(
|
||||
manifest: DeployManifest,
|
||||
options: DeployOptions,
|
||||
@@ -3472,6 +3546,8 @@ export async function runDeployCommand(config: UniDeskConfig | null, args: strin
|
||||
throw new Error("deploy apply --env dev cannot mix artifact consumer services with target-side rollout services in one invocation; pass --service");
|
||||
}
|
||||
if (devArtifactServices.length > 0) {
|
||||
const blocked = devArtifactServices.filter((service) => devArtifactLiveApplyBlockedServiceIds.has(service.id));
|
||||
if (!options.dryRun && blocked.length > 0) return devArtifactLiveApplyBlockedResult(blocked);
|
||||
if (options.dryRun || options.runNow) return await runArtifactConsumerApplyNow(manifest, options, "dev", devArtifactServices);
|
||||
return devArtifactApplyJob(args, options);
|
||||
}
|
||||
|
||||
+2
-2
@@ -349,7 +349,7 @@ function artifactRegistryHelp(): unknown {
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service mdtodo --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env prod --service claudeqq --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> [--dry-run] [--run-now] [--provider-id D601]",
|
||||
"bun scripts/cli.ts artifact-registry deploy-service --env dev --service code-queue --commit <full-sha> --dry-run [--provider-id D601]",
|
||||
],
|
||||
description: "Manage the declaration, rendered files and readonly checks for the D601 host-managed CNCF Distribution artifact registry.",
|
||||
boundary: [
|
||||
@@ -359,7 +359,7 @@ function artifactRegistryHelp(): unknown {
|
||||
"deploy-backend-core only pulls commit-pinned backend-core artifacts and does not build backend-core on the master server",
|
||||
"deploy-service currently supports backend-core, baidu-netdisk, prod/dev frontend, decision-center, mdtodo, claudeqq, project-manager, oa-event-flow, code-queue-mgr, todo-note, findjob, pipeline, met-nonlinear, k3sctl-adapter, and dev-only code-queue as standardized consumers",
|
||||
"findjob and pipeline have D601 direct dev/prod Compose artifact consumers; met-nonlinear is runtime-verification blocked; k3sctl-adapter is supervisor-only",
|
||||
"code-queue has no prod artifact deploy target and prod requests return structured unsupported",
|
||||
"code-queue has no prod artifact deploy target; dev requests are dry-run evidence only unless a human operator or supervisor authorizes DEV apply outside Code Queue",
|
||||
"status and health use provider-gateway Host SSH readonly checks",
|
||||
],
|
||||
legacyEntrypoints: {
|
||||
|
||||
Reference in New Issue
Block a user