# 开发与构建执行环境

本文中的 `mdtodo` 是遗留开发运行面名；任务管理与迁移统一遵循 `$unidesk-tasktree`。

本文档是以下事项的权威出处：

- NC01、D601 与 Master server 的构建执行面边界；
- 持久化 `unidesk-dev` 环境；
- 公开开发前端端口；
- `deploy apply --env dev`；
- L1 任务 worktree 向固定 workspace 的收口；
- Rust backend-core 构建边界。

发布线和开发 lane 治理由 `docs/reference/release-governance.md` 与
[GitHub issue #6](https://github.com/pikasTech/unidesk/issues/6) 负责。
同一规则需要出现在其他入口时，详细规则保留在本文档，其他文档只留简短交叉引用。

## 目标

开发环境用于在不干扰生产环境的前提下体验下一版本 UniDesk：

- 生产环境继续使用 `http://74.48.78.17:18081/` 的正常公开前端。
- 开发环境通过独立的 Master server 端口 `http://74.48.78.17:18083/` 暴露。
- 开发后端和前端工作负载：
  - 运行在 D601 原生 k3s 的 `unidesk-dev` namespace；
  - 不运行在 Master server Compose stack。
- 开发 backend-core 和前端 rollout：
  - 使用 `origin/master:deploy.json#environments.dev` 中已推送的 Git commit；
  - 不使用脏 worktree。
- Rust backend-core 检查和构建：
  - 仍通过 `ci publish-backend-core` 使用其拥有的 D601 CI；
  - 开发 CD 只消费已发布镜像，不编译 Rust。
- Master server 唯一的构建例外是经过审查并显式限制并发的 backend-core 主服务上线操作。

## 通用构建执行面

- Master server 只负责轻量源码编辑、Git 操作、状态观察和受控调度。
- 通用 Docker 镜像、仓库级检查、浏览器验证及 Rust/Go/前端重型构建默认使用 NC01。
- D601 不再是通用构建首选，只在以下事实明确成立时使用：
  - owning CI 或 Tekton 流水线固定运行在 D601；
  - 目标产物必须进入 D601 node-local registry 或原生 k3s；
  - 任务需要 D601 自有硬件、workspace 或运行面；
  - 用户明确指定 D601。
- D601 离线不得阻塞与 D601 无关的通用镜像构建；此类任务直接切到 NC01。
- NC01 上的临时构建目录和容器只用于验证，不成为源码或部署真相。
- 构建产物必须回到项目声明的镜像标签、registry、Git 或可审计交付路径。

## 求职 Word 材料验收

- 求职相关的 Word 材料固定使用 D518 Windows 上的 Microsoft Word 作为最终视觉验收面。
- 文档可以在其他运行面生成，但交付前必须在 D518 Word 中完成以下检查：
  - 正常打开并重新保存后再次打开；
  - 核对总页数和分页位置；
  - 逐页检查表格边界、图片和证件照渲染；
  - 确认没有文字溢出、遮挡、截断或异常空白页。
- DOCX、PDF 和逐页截图通过 `$unidesk-trans` 的二进制传输入口流转。
- `python-docx` 等结构检查只能作为生成阶段校验，不能替代 D518 Word 的视觉验收。

## D601 UniDesk 工作区

`D601:UniDesk` 的固定开发 workspace 是 D601 节点上的 `/home/ubuntu/workspace/unidesk-dev`，固定使用 `master` 分支和 `origin git@github.com:pikasTech/unidesk.git`。所有需要在 D601 上改 UniDesk 代码、做轻量语法/命令形态验证、验证 `trans`/`tran`/Code Queue runner、收敛分布式敏捷实验补丁的工作，都应先进入这个目录。

每次开始 D601 UniDesk 分布式开发、切换任务、恢复中断或上下文压缩后，先通过 UniDesk SSH 维护桥执行：

```bash
trans D601:/home/ubuntu/workspace/unidesk-dev git status --short --branch
trans D601:/home/ubuntu/workspace/unidesk-dev git remote -v
```

若路径、分支或 remote 不符合预期，先修正 fixed workspace，再继续。`/home/ubuntu/cq-deploy`、Code Queue pod 内 `/root/unidesk`/`/app`、D601 上的 `/root/unidesk` 和 `/tmp/unidesk-*` 只作为部署副本、运行副本或临时实验面；运行面热修可以直接作用在 pod/容器，但必须随后把持久化修复提交到 Git remote，并在 fixed workspace 中复验。

固定 workspace 只作为 source truth 预检、fetch、受控 worktree 创建和最终同步入口。实际开发、文档修改、测试补丁和 PR 准备应在固定 repo 下的独立 worktree 中完成，例如 `/home/ubuntu/workspace/unidesk-dev/.worktree/<task>`；该 worktree 必须通过 `bun scripts/cli.ts dev-env worktree add .worktree/<task> --branch <branch> --from origin/master` 从最新 `origin/master` 创建，让 `.worktreecopy` 中声明的本地配置白名单自动复制到新 worktree。使用任务专属分支或 detached worktree 隔离当前改动，结束前用 `git status` 确认只包含本任务文件。不要把 `/home/ubuntu/workspace/unidesk-dev` 根目录当作并行任务 scratch 区，也不要复用其他任务遗留 worktree。

## D601-VM-HOST PikaPython 工作区

- PikaPython V2 的固定执行 route/workspace 是
  `D601-VM-HOST:/home/ubuntu/workspace/pika_workspace`。
- `D601-VM` 是目标和 Provider ID，不是 `trans` route；`D601` 是另一节点，
  两者均不得替代 `D601-VM-HOST` 执行该项目的构建、测试或 benchmark。
- 固定 workspace 保持 `master`，通过仓库 CLI 执行测试和 benchmark；根目录中的
  `.worktree/` 属于任务隔离目录，状态检查和同步时必须保留。
- 进入任务或上下文恢复后的首个只读检查为：

```bash
trans D601-VM-HOST:/home/ubuntu/workspace/pika_workspace git status --short --branch
```

- Master server 不作为 UniDesk 重型验证机：
  - 默认执行面是 NC01、CI runner 或目标运行面；
  - 重型验证包括仓库级 check 和 Playwright/browser smoke；
  - 重型构建包括镜像构建和 Rust/Go 编译；
  - Code Queue runner 实测也遵循同一执行面边界；
  - 只有 owning pipeline 或目标运行面固定属于 D601 时才使用 D601；
  - 唯一例外是用户或 issue 明确要求的 backend-core 主服务上线；
  - 该例外使用 `CARGO_BUILD_JOBS=1`、`--jobs 1` 或 CLI 内置等价方式限制并发；
  - 结果必须用异步 job/status/health 证据回写 issue。

- 主 server 高频控制入口包括：
  - `scripts/cli.ts`；
  - `scripts/trans`；
  - `scripts/tran`；
  - `scripts/src/ssh.ts`；
  - 相邻的 `trans`、`tran` 和 SSH helper。
- 这些客户端工具链可以直接在 master server `/root/unidesk` 轻量修改、提交并推送到 `origin/master`：
  - 例外范围只覆盖 CLI、`trans`、`tran` 客户端源码；
  - 同时覆盖帮助、轻量语法或命令形态验证和对应 reference 文档；
  - 不覆盖 `src/components/provider-gateway` 行为变更；
  - 不覆盖镜像构建、仓库级 check、浏览器 smoke 或其他重型验证；
  - 除非用户明确要求，CLI 改动不做单元测试、合同测试或新增测试脚本；
  - 涉及 provider-gateway 代码时，继续遵循其版本和远程升级规则。
- `trans`、`tran` 或 SSH 透传出现以下高频摩擦时，先优化 CLI 客户端：
  - 文件传输、stdin、chunk 或编码；
  - timeout；
  - route 或 operation 解析。
- 客户端优化应覆盖分块、校验、重试、可观测输出和帮助文档：
  - 使用目标 provider、pod 或 Windows route 的最小闭环证明；
  - 只有证据显示 client 侧无法规避边界时，才进入 provider-gateway 变更流程。

## L1 Native 执行边界

- L1 只使用 host 上的 native API、Worker、Web 和必要基础依赖：
  - 服务从 owning YAML 解析固定 workspace、端口、状态目录和依赖；
  - 启动、停止、重启、状态和日志统一走项目受控 lifecycle CLI；
  - `--over-api` 直接调用该 native API，不经过 Kubernetes Service 或集群 workload。
- L1 在任何情况下都不依赖 CI/CD、GitOps、Argo、Kubernetes、镜像发布或
  集群 rollout：
  - 正常启动、首次拉起、配置变更、合并后复测和故障处理都不等待这些系统；
  - 不用这些系统更新、修复或验收 L1 运行面；
  - 必须依赖集群对象的验证属于 L2。
- L1 始终使用本机小回环：
  - 通过 owning YAML 固定 native 端口完成 API、Worker、Workflow 和 Web 回归；
  - 同 host 可使用 YAML probe host，跨 host 使用 YAML 固定 native host；
  - 公共入口状态独立记录，不能成为 L1 业务门禁；
  - L1 任务不进入 CI/CD、Kubernetes 和 public-edge 调查或操作。
- L1 源码 provenance 是 lifecycle 状态的一部分：
  - 聚合 `status` 应同时披露 owning YAML 固定 repo、实际选中的 source workspace、commit 和进程工作目录一致性；
  - 迭代期间的 source workspace 可以是固定 workspace，也可以是 owning YAML 受控选择且属于固定 repo 的任务 worktree；
  - L1 完成时的 source workspace 必须回到 owning YAML 选定的固定 workspace，并满足下一节的收口合同；
  - 浏览器、CLI 或 smoke 命中其他 workspace 的旧代码时，结果只能证明旧运行面，不得作为当前修改的验收证据；
  - 状态缺少这些字段属于受控 CLI 可见性缺陷，应在当前 L1 任务内修复或登记到既有 source-worktree 改进任务，禁止用裸进程探测固化第二套验收流程。

## L1 固定工作区收口

- 任务 worktree 只承载隔离开发和短反馈迭代：
  - 可以从受控 worktree 启动临时 native 进程或 HMR 预览；
  - 此类结果只证明迭代版本，不能证明固定 L1 运行面已经更新；
  - 不得因为页面、CLI 或 smoke 在任务 worktree 中通过，就宣称 L1 完成。
- 宣称 L1 完成前必须按顺序完成以下动作：
  - 把本任务已验收的全部语义整理为边界明确的提交；
  - 将该提交语义合入 owning YAML 选定的固定 L1 workspace 和其固定跟踪分支；
  - 保留固定 workspace 中无关的并行改动，禁止用 reset、覆盖式 checkout 或文件复制代替语义合并；
  - 确认没有已验收语义只留在任务 worktree、未提交 diff 或临时产物中；
  - 通过项目 lifecycle CLI 从固定 workspace 重载或重启受影响的 API、Worker 和 Web；
  - 重新读取聚合 `status`，确认 repo、workspace、commit 和进程工作目录都指向固定 L1 workspace；
  - 从固定端口重新执行受影响的 CLI、API、Workflow 或 Web 回归。
- HMR 不改变收口要求：
  - 固定 workspace 合入后由 HMR 自动更新页面，可以不做无意义的前端进程重启；
  - API、Worker 或未被 HMR 接管的进程仍须通过 lifecycle CLI 重载；
  - 最终 provenance 和回归证据必须来自固定 workspace 合入后的版本。
- L1 本地合入不等于 L2 发布：
  - 固定 workspace 收口不依赖 CI/CD、镜像、Kubernetes 或集群 rollout；
  - 后续进入 L2 时，再按项目 Git 和发布规则推送并交付同一语义。
- 固定 workspace 暂时无法完成语义合并时：
  - 保留任务 worktree 和提交，不得删除或丢弃；
  - 将 L1 状态保持为未完成并报告具体阻塞；
  - 不得把仍指向任务 worktree 或旧固定版本的公网地址作为完成入口交付。
- 任务 worktree 只有在固定 workspace 已吸收全部语义、固定入口回归通过且不存在未吸收提交后才能清理。

## L1 受控 CLI 即时修复

- 执行 L1 开发、诊断或验收时，发现项目受控 CLI 存在问题即可在当前任务内即时修改：
  - 不需要把 CLI 缺陷降级为只读 blocker；
  - 不需要等待独立任务、issue 或额外授权；
  - 修复后继续完成原 L1 主线，不因 CLI 自身问题改用裸脚本或绕过产品入口。
- 可即时修改的范围包括：
  - YAML parser、参数校验和受控 lifecycle；
  - `--over-api` transport、状态、日志和窄查询；
  - 结构化输出、错误码、进度可见性和帮助文本；
  - 为恢复原 L1 入口所必需的相邻轻量 helper。
- 即时修改仍遵守原有边界：
  - owning YAML 继续是运行事实唯一来源；
  - 不由 CLI 缺陷推导服务端、生产、Secret、安全机制或重型构建的额外修改授权；
  - 修改使用正常 Git/PR 交付路径，并保护固定 worktree 中的并行改动；
  - 验证以具体文件语法、配置解析、目标命令和原 L1 入口最小闭环为准；
  - 默认不新增测试，不在 Master server 运行仓库级检查或重型 smoke。
- 以下情况属于应即时修复的 CLI 可见性问题：
  - 输出缺少关键状态、失败阶段或下一步；
  - 默认输出超过预算，导致无法完成判断。
  - 修复要求：
    - 优先补语义化摘要、稳定 identity、分页 cursor 或 id-specific drill-down；
    - 禁止长期依赖 `--raw`、临时 dump、运行面反解或裸原生工具代替受控 CLI。

## Public Dev Frontend Port

The main server owns one extra public entrypoint for dev UI:

```text
browser -> main-server:18083 -> dev-frontend-proxy -> prod backend-core microservice proxy -> k3sctl-adapter -> D601 k3s Service frontend-dev -> frontend-dev -> backend-core-dev
```

`dev-frontend-proxy` is an nginx sidecar in the main-server Compose project. It proxies requests to `backend-core:8080/api/microservices/k3sctl-adapter/proxy/api/services/frontend-dev/proxy...`, so D601 does not expose a new public port and the dev UI still crosses the existing UniDesk/k3sctl-adapter control boundary. The proxy is intentionally thin: it does not build frontend assets, does not talk to D601 directly, and does not contain DevOps logic.

`frontend-dev` and `backend-core-dev` are registered with `k3sctl-adapter` through the managed-service catalog `src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k3s.json`. The public dev port must use that cataloged Kubernetes API service-proxy path; it must not add a direct D601 public port, NodePort, or backend-core catalog entry for arbitrary k3s services.

The dev public port is configured in `config.json` as `network.devFrontend.port=18083`, surfaced by `server status` as `urls.devFrontend`, and managed by `server rebuild dev-frontend-proxy`. The proxy health depends on `frontend-dev`; it can be unhealthy until the D601 dev frontend has been deployed.

The unrestricted public network entries are therefore production frontend, dev frontend, and provider ingress. backend-core REST, PostgreSQL, user-service backend ports, k3s Services, NodePorts and D601 host ports remain private or explicitly restricted.

Dev and production frontend authentication must use the same `config.json.auth` username, password, session secret and session TTL. The public dev and production entrypoints share the same IP/host with different ports, so the `unidesk_session` cookie is host-scoped rather than port-scoped. `deploy apply --env dev --service frontend` must sync `unidesk-dev-runtime-secrets` and `unidesk-dev-runtime-config` from the main-server config before rolling out `frontend-dev`; dev manifests may contain placeholders but must not establish a separate dev login identity.

## Desired State

`deploy.json` remains the only version intent file. Dev entries live under `environments.dev` and are read from `origin/master:deploy.json`, never from a dirty local file, when using `--env dev` or `ci run-dev-e2e`.

The target release-governance model is to split stable maintenance validation from high-risk master integration, for example with explicit lanes such as `dev-v1` and `dev-master`. That split is not active until `deploy.json`, deploy commands, CI, frontend labels and diagnostics support it explicitly. Until then, the documented `environments.dev` behavior remains the active contract and must not be emulated through local manifest edits or hidden branch conventions.

During a `release/v1` stabilization window, this same implemented `environments.dev` lane is temporarily reserved for v1 validation. Use pushed commits and explicit `deploy.json` pins to validate v1 fixes; do not add a parallel `dev-v1`/`dev-master` schema in the middle of the stabilization window unless that split is the blocker for v1. The detailed phase rule lives in `docs/reference/release-governance.md`.

The persistent dev rollout currently supports:

- `backend-core`, `frontend`, `mdtodo`, `claudeqq` and `code-queue` as D601 registry artifact consumers in `unidesk-dev`. Decision Center moved to the NC01 YAML-first k8s lane and is no longer a current D601 persistent dev workload.
- `baidu-netdisk` as the main-server direct user-service artifact validation sample.

`deploy apply --env dev --service baidu-netdisk` consumes the D601 registry artifact and validates the main-server Compose service; it is not a persistent D601 k3s dev workload. `deploy apply --env dev --service code-queue` is intentionally dev-only and may mutate only `unidesk-dev` Code Queue scheduler/read/write/provider-egress-proxy objects. `deploy apply --env prod --service code-queue` must remain unsupported. The `environments.dev.ci` declaration and short launcher runner are owned by `docs/reference/dev-ci-runner.md`.

## Rust Backend-Core Boundary

backend-core is implemented as a Rust service. The default dev and CI path compiles backend-core on D601 CI and consumes commit-pinned artifacts. The master server may inspect files, run concrete-file lightweight syntax checks, dispatch jobs and proxy traffic, but it must not run repository-level checks, Compose checks or Rust compilation for ordinary backend-core iteration.

Narrow production-online exception: when a user or issue explicitly asks to put the current backend-core fix online on the main-server Compose runtime, master server may run backend-core-only Rust compilation with constrained parallelism (`CARGO_BUILD_JOBS=1`, `--jobs 1`, or the CLI's equivalent setting) and must use async job/status/health evidence. This exception does not allow repository-wide checks, Rust tests, Go builds, frontend builds, or other service builds on the master server.

Allowed on the master server:

- `git diff --check` and `bun --check <specific-file>`
- `bun scripts/cli.ts check --help`
- `bun scripts/cli.ts deploy plan --env dev --service backend-core`
- `bun scripts/cli.ts deploy apply --env dev --service backend-core`
- `bun scripts/cli.ts ci run --revision <commit>`
- `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`
- for reviewed backend-core main-server online only: backend-core-specific `cargo check`/build with `CARGO_BUILD_JOBS=1`, or `bun scripts/cli.ts server rebuild backend-core` followed by `job status` polling and health verification

Not allowed on the master server for this path:

- repository-wide `cargo check`, `cargo build`, `cargo test`, `rustfmt`, or any Rust command outside the backend-core main-server online exception.
- `bun scripts/cli.ts check --rust` without the D601 CI guard.
- `bun scripts/cli.ts server rebuild backend-core` as a way to iterate Rust backend-core or replace D601 CI artifact flow.
- Ad-hoc `docker build` of `src/components/backend-core/Dockerfile` on the master server outside the controlled CLI rebuild exception.

`check --rust` remains a D601 CI/dev-execution command: `UNIDESK_D601_RUST_CHECK=1 bun scripts/cli.ts check --full --rust`. It deliberately fails outside that guard with an explicit explanation instead of silently compiling on the wrong host; the main-server online exception is handled by the backend-core-specific build/rebuild path, not by weakening `check --rust`.

## Dev Deploy Path

`deploy apply --env dev --service backend-core|frontend|mdtodo|claudeqq|code-queue` is the controlled persistent dev rollout path for D601 dev workloads. The controller runs on the master server, but dev CD is a pull-only artifact consumer. All listed services consume CI-published commit-pinned artifacts from the D601 registry. Decision Center uses the NC01 k8s lane and GitHub storage checks instead of this D601 dev path.

1. Fetch `origin/master:deploy.json#environments.dev` and resolve the requested service commit to a full SHA.
2. Dispatch to D601 through the existing provider-gateway/Host SSH maintenance capability.
3. Require the existing registry image `127.0.0.1:5000/unidesk/<service-id>:<commit>` produced by `ci publish-backend-core` for backend-core or `ci publish-user-service --service <service-id>` for user services.
4. Verify the registry manifest and image labels for service id, source commit and Dockerfile. The dry-run plan exposes the registry image, planned digest source, target, source commit and `build.willCompile=false`.
5. Import the registry artifact into native k3s containerd at `/run/k3s/containerd/containerd.sock`.
6. Apply only the selected `unidesk-dev` Service/Deployment objects from the dev manifest.
7. For `frontend`, sync auth/session settings from main-server `config.json.auth` into the dev runtime Secret/ConfigMap before rollout.
8. Stamp the Deployment with `UNIDESK_DEPLOY_*` env and `unidesk.ai/deploy-*` annotations.
9. Verify health through the Kubernetes API service proxy and require the live commit to match the requested commit.

The dev path is not a fallback system. If artifact lookup, label verification, native k3s, containerd import, kubectl apply or live health verification fails, the job fails with logs. It must not fall back to `cargo build`, `docker build`, building on the master server, building source on the dev target, using a dirty worktree, direct D601 public ports, NodePort, hostPort, provider-gateway business HTTP, or another deployment command. k3s-managed health verification must use the Kubernetes API service proxy.

## DevOps Hygiene

The persistent dev environment follows the shared Git-backed deployment hygiene rules in `docs/reference/devops-hygiene.md`. In particular, D601 runtime edits, dirty-worktree builds, copied scripts/images/source, direct D601 ports, NodePorts and manual smoke checks without live commit agreement must not become deployment truth.

## Standard Workflow

Use this sequence for backend-core Rust and frontend dev work:

1. Preflight the fixed workspace, then create the task-scoped worktree with `bun scripts/cli.ts dev-env worktree add .worktree/<task> --branch <branch> --from origin/master`; keep unrelated parallel changes separated with `git status`/`git diff`.
2. Master server 只执行 diff 审查和具体文件的轻量语法检查。
   - 轻量语法检查示例是 `bun --check <specific-file>`。
   - 仓库级检查和类型检查默认在 NC01、CI 或目标运行面执行。
   - Compose 检查、前端检查和 Rust 检查遵循同一执行面边界。
   - 仅 D601 owning pipeline 使用 D601。
3. Commit the code from the task worktree and merge/push it to `origin/master` through the chosen lightweight PR or direct integration path; `deploy apply --env dev` cannot deploy unpushed local changes.
4. Update `deploy.json` `environments.dev.services` so `backend-core` and `frontend` point at the pushed commit, then commit and push that manifest update.
5. Preflight backend-core publication: `bun scripts/cli.ts ci publish-backend-core --commit <full-sha> --dry-run`. The result must have no `blockedScopes`, `wouldBuildOnD601=true`, D601 `unidesk-ci` Tekton runner metadata, D601 registry target `127.0.0.1:5000/unidesk/backend-core`, required labels for service id/source repo/source commit/Dockerfile, and `recommendedAction` pointing to the real publish command.
6. Publish the artifact first: `bun scripts/cli.ts ci publish-backend-core --commit <full-sha> --wait-ms 1200000` for backend-core, or `bun scripts/cli.ts ci publish-user-service --service <frontend|decision-center|mdtodo|claudeqq|code-queue> --commit <full-sha> --wait-ms 1200000` for user services.
7. Verify the publish output contains non-empty `artifactSummary.digest` and `artifactSummary.digestRef`, and that the pushed image labels match `backend-core`, the source repo, source commit and Dockerfile. This verification can use the publish output and the D601 registry manifest HEAD; it must not rebuild.
8. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core --dry-run` and confirm `artifactConsumer.noRuntimeSourceBuild=true`, `build.willCompile=false`, the registry image is `127.0.0.1:5000/unidesk/backend-core:<commit>`, and the target is `unidesk-dev/backend-core-dev`.
9. Run `bun scripts/cli.ts deploy apply --env dev --service backend-core` and observe the returned job with `bun scripts/cli.ts job status <jobId> --tail-bytes 30000`.
10. Run `bun scripts/cli.ts deploy apply --env dev --service <frontend|decision-center|mdtodo|claudeqq|code-queue>` and observe the job the same way; this must consume the registry artifact and verify live deploy metadata through the service health path.
11. If the dev service catalog changes, deploy the pushed `k3sctl-adapter` commit through the controlled local manifest exception, then verify `/api/control-plane` lists `k3s/dev/unidesk-dev-core.k3s.json`.
12. Rebuild or verify `dev-frontend-proxy` on the main server with `bun scripts/cli.ts server rebuild dev-frontend-proxy` when the proxy config or port changes.
13. Manually test `http://74.48.78.17:18083/` and the dev health endpoints.
14. Run D601 CI for the commit and the dev smoke runner: `bun scripts/cli.ts ci run --revision <commit> --wait-ms <ms>` and `bun scripts/cli.ts ci run-dev-e2e --wait-ms <ms>`. When Code Queue behavior changes, update the `code-queue` entry in `environments.dev.services` to the pushed commit before running dev artifact validation or the temporary dev smoke.

## Validation Commands

Useful read-only or bounded validation commands:

```bash
bun scripts/cli.ts server status
bun scripts/cli.ts deploy plan --env dev
bun scripts/cli.ts deploy plan --env dev --service backend-core
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-core.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-mdtodo.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-claudeqq.k8s.yaml
bun scripts/cli.ts dev-env validate --manifest src/components/microservices/k3sctl-adapter/k3s/dev/unidesk-dev-code-queue.k8s.yaml
bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000
bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/backend-core-dev/proxy/health --raw --full
bun scripts/cli.ts microservice proxy k3sctl-adapter /api/services/frontend-dev/proxy/health --raw --full
curl -fsS http://127.0.0.1:18083/health
```

When validating on D601 directly, always use the native kubeconfig explicitly: `KUBECONFIG=/etc/rancher/k3s/k3s.yaml`. The default `kubectl` context may point at Docker Desktop and is not valid for UniDesk native k3s verification.
