# Webterm 配置与受控部署

- 唯一配置来源：
  - `config/platform-infra/webterm.yaml` 是端口、自动标签、启动模式、浏览器历史和输出聚合策略的 owning YAML；
  - WebTerm 公网入口由各 target 的 `publicExposure` 唯一声明：
    - `local-7682` 使用 `term2.hwpod.com` 和 `127.0.0.1:7682`；
    - `local-7683` 使用 `term.hwpod.com` 和 `127.0.0.1:7683`；
    - 两者的健康路径与 WebSocket 语义均由 NC01 共享 `public-edge` 通过 `configRef` 和路径读取；
  - 已接入共享边缘的 target 不声明 PK01 Caddy 归属，禁止恢复旧域名或增加第二 authority；
  - `build/docker-compose.<port>.yaml` 是受控 CLI 渲染产物，禁止手工维护或在部署后恢复旧内容。
- 受控入口：
  - 预览使用 `bun scripts/cli.ts platform-infra webterm plan --target <target>`；
  - 部署使用 `bun scripts/cli.ts platform-infra webterm apply --target <target> --confirm`；
  - 收口使用同一入口的 `status` 与 `validate`。
  - 日志使用 `bun scripts/cli.ts platform-infra webterm logs --target <target> --tail <lines>`；
  - 日志默认返回最近 100 行，`--tail` 允许范围为 1 到 1000 行，且总输出保持有界。
- 匿名健康与 provider 判定：
  - Webterm `/healthz` 无需登录，返回 `ok`、`providers` 与 `sessions`；
  - `apply`、`status` 和 `validate` 必须读取 `/healthz`，且只在 `ok=true`、`providers>=1` 时判定本地运行面健康；
  - `/login` 可访问不能替代 provider 健康证据。
- 浏览器历史策略：
  - `browserTerminalHistory.desktopScrollbackLines` 控制桌面端 xterm 历史行数；
  - `browserTerminalHistory.mobileScrollbackLines` 控制移动端 xterm 历史行数；
  - `browserTerminalHistory.mobileMaxWidthPx` 与粗指针特征共同决定移动端策略；
  - 视口类型变化后，已有终端必须同步新上限并截断超出上限的旧行。
- 输出聚合策略：
  - `browserOutputPolicy.maxFramesPerSecond` 是每个浏览器连接、每个终端的最大输出消息频率；
  - `browserOutputPolicy.maxFrameBytes` 是单条聚合输出消息的字节上限；
  - 后端必须按终端独立排队，小数据在频率窗口内合并，积压数据按窗口顺序发送，禁止用字节阈值绕过频率上限。
- 持久 Codex Session 创建：
  - 适用于本地 provider 的 `mycx` 与 `oncx` runtime 自动恢复标签；
  - 新建必须直接调用原生 `codex app-server`，按顺序完成 `initialize`、`initialized`、`thread/start` 与 `thread/name/set`；
  - `thread/start` 必须显式传入 `ephemeral=false`，并以返回的 thread ID 作为后续恢复 Session ID；
  - 禁止通过附带 `--profile` 的 `mycx` 或 `oncx` 包装器启动 app-server，当前 Codex 只允许 profile 用于 runtime 命令；
  - `mycx` 创建沿用默认 Codex home，`oncx` 创建必须沿用包装器声明的 `CODEX_HOME`、`CODEX_SQLITE_HOME` 和凭据环境清理规则；
  - Webterm 运行在使用 `/usr/local/bin/host-shell` 的容器中时，app-server 必须通过宿主 namespace 执行原生 Codex；
  - 容器与宿主工作目录分层：
    - 容器进程工作目录必须使用容器内存在的目录；
    - 目标工作目录只通过 `thread/start.cwd` 传给宿主 Codex；
    - 禁止把仅宿主存在的路径直接作为容器 `spawn.cwd`；
  - 只有 `thread/name/set` 成功后才能把 Session ID 写入 runtime 数据域，再通过 `mycx|oncx resume <session-id> <prompt>` 启动终端；
  - 恢复 prompt 必须作为 CLI 参数传入，禁止在 xterm 中模拟键盘输入；
  - runtime 记录与 YAML 预置恢复标签必须共存，runtime 数据域不得改变 owning YAML 的预置定义。
- 持久 Session 最小验收：
  - 先执行目标的受控 `status`，确认 provider 健康和 runtime 数据域正确；
  - 再从真实浏览器加号入口创建一个持久 Session，关闭标签后从恢复列表重新打开；
  - 创建与恢复后的 Session ID 相同、标签为 runtime 自动恢复且终端进入 running，才判定端到端合同成立；
  - 单元测试只验证 app-server 消息顺序、模式环境和宿主 namespace 启动参数，不能替代真实浏览器验收。
