diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..90d26950 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,54 @@ +# HWLAB Agent Index + +HWLAB 是硬件实验室运行面和控制面项目。本文是 agent、指挥官和 runner 进入本仓库时的顶级索引。 + +## Git 和 Workspace + +- 指挥官在主机侧固定使用 `/workspace/hwlab`,分支固定为 `main`。开始任何开发、文档或调度审阅前执行 `git status` 和 `git pull --ff-only origin main`。 +- D601 上的部署/构建副本固定为 `/home/ubuntu/workspace/hwlab`。通过 UniDesk 执行:`bun scripts/cli.ts ssh D601 'cd /home/ubuntu/workspace/hwlab && git pull --ff-only origin main'`。 +- D601 上 `/home/ubuntu/hwlab` 可能是 Code Queue runner 或并行任务工作区,不能当作发布真相,也不能由指挥官清理、reset 或临时复用。 +- PR 冲突由指挥官审查和合并;runner 不应承担复杂冲突合并。无法干净合并的 PR 应由指挥官判断手动合并、关闭重做或拆分。 + +## MVP 固定边界 + +- MVP 环境是 `dev`。 +- DEV 前端入口固定为 `http://74.48.78.17:16666/`。 +- DEV API/live 入口固定为 `http://74.48.78.17:16667/health/live`。 +- 旧公网 `:6666` / `:6667` 不是浏览器验收目标;内部 k3s service 仍可使用 `6667`。 +- UniDesk 只作为调度、CI 或 CD 基础设施,不能替代 HWLAB runtime。 + +## 关键文档 + +- 项目 README 与冻结服务 ID:[README.md](README.md) +- 操作与验收总 runbook:[docs/operator-runbook.md](docs/operator-runbook.md) +- Cloud Workbench 用户界面契约:[docs/cloud-web-workbench.md](docs/cloud-web-workbench.md) +- DEV 构建与发布镜像:[docs/dev-artifact-publish.md](docs/dev-artifact-publish.md) +- DEV apply / k3s 滚动发布:[docs/dev-deploy-apply.md](docs/dev-deploy-apply.md) +- M3 闭环 rollout runbook:[docs/reference/m3-loop-rollout-runbook.md](docs/reference/m3-loop-rollout-runbook.md) +- runner issue 可见性与 prompt handoff:[docs/reference/runner-issue-visibility-handoff.md](docs/reference/runner-issue-visibility-handoff.md) + +## D601 原生 k3s + +HWLAB 的真实 DEV runtime 在 D601 原生 k3s。所有手动诊断和发布必须显式使用: + +```sh +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev get deploy,svc,pod -o wide +``` + +不要使用默认 `kubectl` context 作为判断依据。D601 默认 context 可能是 `docker-desktop`,这会产生与公网入口无关的误导性状态。 + +## Cloud Web 手动 DEV 发布 + +已验证的手动路径记录在 [docs/dev-deploy-apply.md](docs/dev-deploy-apply.md) 的 Cloud Web 发布章节。关键点: + +- 先更新 D601 `/home/ubuntu/workspace/hwlab` 到 `origin/main`。 +- `hwlab-cloud-web` 必须先运行 `node web/hwlab-cloud-web/scripts/build.mjs` 刷新 `dist`,否则镜像 runtime 会优先服务旧 `dist`。 +- 镜像发布使用 `node scripts/dev-artifact-publish.mjs --publish --services hwlab-cloud-web`。 +- 滚动发布使用 D601 原生 k3s 的 `kubectl set image` 和 `rollout status`。 +- 公网验收必须检查 `16666/health/live` revision、HTML 语言/标题和 CSS 外层滚动锁定。 + +## 禁止误判 + +- `SOURCE`、`LOCAL`、`DRY-RUN`、fixture 和只读报告不能被称为 `DEV-LIVE`。 +- Cloud Workbench、Gate、诊断页、发布路径修复都是支撑任务,不等同于 M3 PASS。 +- 真正 M3 DEV-LIVE 必须证明 `res_boxsimu_1:DO1 -> hwlab-patch-panel -> res_boxsimu_2:DI1`,并带有 operation、audit、evidence 链。 diff --git a/docs/dev-artifact-publish.md b/docs/dev-artifact-publish.md index d121e607..53e9a679 100644 --- a/docs/dev-artifact-publish.md +++ b/docs/dev-artifact-publish.md @@ -59,6 +59,18 @@ Build and publish to the D601 local/internal registry: node scripts/dev-artifact-publish.mjs --publish ``` +For `hwlab-cloud-web`, refresh the static bundle before publishing: + +```sh +node web/hwlab-cloud-web/scripts/build.mjs +node scripts/dev-artifact-publish.mjs --publish --services hwlab-cloud-web --report reports/dev-gate/dev-artifacts-hwlab-cloud-web-.json +``` + +The runtime wrapper serves `/app/web/hwlab-cloud-web/dist` before the source +directory. If `dist` is stale, a newly tagged image can still serve old HTML, +CSS, and JavaScript. A publish for Cloud Web is not valid until the image has +been probed locally and the served HTML matches the intended source. + Use `--registry-prefix` only for another localhost/private/internal D601 registry prefix. The script rejects third-party registry hosts and any prefix that names PROD. Use `--base-image` only to override `HWLAB_DEV_BASE_IMAGE` with diff --git a/docs/dev-deploy-apply.md b/docs/dev-deploy-apply.md index e2e3b6a9..9b2d3c2e 100644 --- a/docs/dev-deploy-apply.md +++ b/docs/dev-deploy-apply.md @@ -104,6 +104,82 @@ node scripts/validate-dev-gate-report.mjs Only after that approval may the DEV-only apply command be used. +## Cloud Web Manual DEV Rollout + +This is the currently verified manual CD path for `hwlab-cloud-web` on D601. +It is the operational baseline that future CLI automation should reproduce from +`deploy/deploy.json`; do not rediscover ports or kube contexts during an +incident. + +Start from the D601 deployment copy, not a runner worktree: + +```sh +cd /home/ubuntu/workspace/hwlab +git pull --ff-only origin main +``` + +Refresh the static bundle before artifact publish. Cloud Web images serve +`web/hwlab-cloud-web/dist` first, so stale ignored build output can keep an old +English or old layout bundle alive even after the source commit is correct. + +```sh +node web/hwlab-cloud-web/scripts/build.mjs +node scripts/dev-artifact-publish.mjs --publish --services hwlab-cloud-web --report reports/dev-gate/dev-artifacts-hwlab-cloud-web-.json +``` + +Probe the image locally before touching k3s: + +```sh +docker run --rm -d --name hwlab-cloud-web-probe -p 127.0.0.1:18088:8080 127.0.0.1:5000/hwlab/hwlab-cloud-web: +sleep 1 +curl -fsS http://127.0.0.1:18088/health/live +curl -fsS http://127.0.0.1:18088/ | sed -n '1,40p' +docker rm -f hwlab-cloud-web-probe +``` + +Use the D601 native k3s kubeconfig explicitly: + +```sh +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev set image deployment/hwlab-cloud-web hwlab-cloud-web=127.0.0.1:5000/hwlab/hwlab-cloud-web: +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev rollout status deployment/hwlab-cloud-web --timeout=180s +KUBECONFIG=/etc/rancher/k3s/k3s.yaml kubectl -n hwlab-dev get deploy hwlab-cloud-web -o wide +``` + +Do not use the default kube context as the source of truth. On D601 it may be +`docker-desktop`, which is not the public DEV runtime behind `16666/16667`. + +Public acceptance must verify all of these: + +```sh +curl -fsS http://74.48.78.17:16666/health/live +curl -fsS http://74.48.78.17:16666/ | sed -n '1,80p' +curl -fsS http://74.48.78.17:16666/styles.css | rg 'overflow: hidden|100dvh' +curl -fsS http://74.48.78.17:16666/help.md | sed -n '1,40p' +``` + +For the Cloud Workbench Chinese/no-outer-scroll rollout, the accepted target +state was: + +- `GET /health/live` reports revision + `1e8805664970839b72be40c34636b08f6d18b131`; +- `GET /` returns `html lang="zh-CN"` and title `HWLAB 云工作台`; +- CSS locks the outer shell with `html, body { overflow: hidden; }` and + `.workbench-shell { height: 100dvh; overflow: hidden; }`; +- `GET /help.md` returns the Chinese Cloud Workbench help document. + +The public path is: + +1. master `hwlab-frps-dev` listens on `16666/16667`; +2. D601 `hwlab-frpc` runs in `hwlab-dev` from the `hwlab-frpc-config` + ConfigMap; +3. `hwlab-dev-cloud-web` maps to + `hwlab-cloud-web.hwlab-dev.svc.cluster.local:8080`; +4. `hwlab-dev-edge-proxy` maps to + `hwlab-edge-proxy.hwlab-dev.svc.cluster.local:6667`. + +Master `hwlab-browser-proxy-dev` is only an auxiliary local proxy on `18087`; +it is not the public browser endpoint. + ## Suspended Template Job Replacement Kubernetes Jobs cannot update `spec.template` in place. For DEV template Jobs