Files
codex-app-server/docs/chv-architecture.md
T

139 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Cloud Hypervisor 执行器架构决策记录(ADR)
范围:cloud/chv/ 执行器链(#216 → #221 → #230 → #232 → #234 → #239 → #246 → 本轨)。
本文件只记录已落代码的决策,不记录未验证为已验证;真机、压测、动态安全
仍见 docs/chv-production-readiness.md §11。
## ADR-1 SSH 目标:客机 IP 发现(已选) vs vsock / 纯 NAT(未选)
- 决策:显式 CHV_SSH_HOST > CHV_NET_JSON 首个带 ip 的 net 条目 >
显式 CHV_SSH_FORWARD=1 宣称下的回环;三者皆无报
ssh_target_undeclared,绝不无条件假设 127.0.0.1:2222 能通。
- 未选 vsock:需客内 agent + 宿主代理两套新代码,当前客机镜像
无此组件,写进代码仍是假保证。
- 未选纯 NAT:DNAT 是宿主防火墙外部状态,执行器代码既不能
创建也不能校验它,写进代码仍是假保证;宿主防火墙见就绪
清单 §11.4 部署清单,代码门 + 防火墙缺一不可。
## ADR-2 网关 key 走 seed 投递(已选) vs argv / 宿主环境(已弃)
- 决策:provisioned 模式下密钥子集随 seed 写进客内
/etc/chv/guest-env(0600),远程命令 source 它;传输层密钥
进 argv 直接 ValueError;keyscan 模式有密钥即 fail-closed。
- 放弃 argv:宿主 ps / /proc/<pid>/cmdline 可读;放弃宿主子进程
环境:Docker 线 -e 只传名、值仍在 CLI 子进程环境,CHV 比它
更严(值连宿主子进程环境都不进)。
- 残留:seed 随 stop 删,私钥在 seed 盘建好后即删,
cleanup_stale_secrets 扫崩溃残留;删失败 fail-fast 或脏标记拒起。
## ADR-3 磁盘 copy 默认,reuse 只作单租户实验(已选)
- 决策:CHV_DISK_MODE 默认 copy,每任务独立 disk.raw;
reuse 须同时满足 CHV_REUSE_SINGLE_TENANT_EXPERIMENT=1 与
CHV_SINGLE_TENANT_PROJECT 声明,且 wake 时审计放行。
- 边界:代码无法验证数据库多租户状态,声明 + 审计即机制,
不假装已校验;生产多租户下 reuse 一律不启用。
## ADR-4 restore 不重预置(纠正,见 #232 审计)
- 纠正:审计原说法“restore 须把 seed 接入 VmConfig”是错的——
restore 不走 vm.create,无 VmConfig 可挂盘;快照内已固化原
VM host key,重预置反而破坏钉死。
- 正确不变量:provisioned 下复用已钉死 known_hosts、缺失
fail-fast(host_key_not_pinned),绝不 keyscan 回落。
## ADR-5 WarmPool:实验性,生产 dispatch 永远冷启动(本轨定案)
- 决策(二选一的 B 项):把 WarmPool 从生产路径宣称里摘掉,
明确标为实验/停用,不再留“半接线”悬空状态。
- 原因:预热 VM 的磁盘是干净快照盘,不是任务盘;dispatch 前
查池若要真正接线,必须在派任务前给已暂停 VM 重新供给任务
盘(热换盘 / 二盘挂载 / host.py 磁盘语义三者都未实现),
把预热盘直接当任务盘用会击穿任务盘隔离不变量。
- 落地:WarmPool.wired_to_dispatch 恒为 False;_run_with_vm
绝不查池,dispatch 永远冷启动;acquire 内 resume 只保留为
实验接口;worker 启动/关闭仍调 reconcile_orphans()(上一世
残留清理是池子保留的唯一生产价值)。
- 重启条件:将来要重新接线,必须先实现任务盘重供给并补
“任务盘来源”不变量测试,否则不得把 wired 改成 True。
## ADR-6 Docker goal 解析分叉:共享正典 + 同步守卫(本轨定案)
- 决策:Local/CHV 共用 parse_goal_result 正典;Docker goal_task
内联版保留,但与正典的 8 个真实标记用例(met/unmet/
interrupted 标记/无结论异常退出/永久错误/无结论 rc0/
goal-resume 拒绝/已存在撞名)由 test_chv_arch95.py 的
DockerSyncGuardTest 行为测试钉住状态全等,任一实现改了
分叉测试即 fail,不再只靠文档清单。
- 注意:Docker 的超时证据路径仍与内联解析绑在一起,那是
有意保留的第二处差异,不在 8 用例的状态等价范围内。
## ADR-7 #215 未合并时的复用边界(不复制模块)
- 现状:#215(timeouts/gates/quota/sandbox_policy)未合并,
本链 base 里无其模块,本轨不复制其代码。
- 纠正(feat-chv-arch95plus,核对过 #215 远程分支真实
函数后):上一轨 ADR-7 的“超时→timeouts、配额→quota”
泛化映射是错的。#215 的 timeouts 收敛的是审批/队列
超时(None/0=不过期),quota 是按月美元配额,与 CHV
的 api/ready 秒数(0 无效)和 VM 数/磁盘 GB/快照数
单位与语义都不同,硬套会改行为,故这两项无映射。
- 真实映射(已落代码,见 cloud/chv/compat215.py):
gates.resolve_inside(base, rel) 目录门 → CHV 快照/磁盘
路径白名单已在 hardening 里使用,合并后改为 import;
sandbox_policy.tmpfs_isolated → CHV 客机 /tmp 落客机
磁盘、一律不隔离(fail-closed),合并后改为 import。
其余 #215 函数(审批、控制门、合并状态门、worker 寻址)
与 CHV 无交集,不映射。替换时须重跑本链测试,不得改语义。
## ADR-8 WarmPool 生产隔离:facade 而非类导入
- 决策:生产路径(worker 启动/关闭)只调
cloud/chv/pool.py 的 reconcile_orphans_for_executor()
facade,该函数内部才构造 WarmPool 并只调
reconcile_orphans();生产 dispatch 绝不调 prewarm/
acquire/release,executor.py 也不 import pool。
WarmPool 类与 sandbox re-export 保留仅为兼容(旧测试
import 路径),新代码不得经类入口进实验接口。
- 测试钉住:facade 测试断言 acquire/prewarm 绝不被调;
executor 不 import pool 由模块依赖检查覆盖。
## ADR-9 审计失败取舍:记日志 + 计数,不中断任务
- 选项 A(失败即中断任务):审计完整性最强,但 DB 短暂
不可用会把一次审计失败放大成任务失败,且与 worker
全局 best-effort 语义冲突,CHV 单独硬中断是不一致的。
- 选项 B(失败记日志 + 计数 + 不中断任务):已选。
executor._emit 失败时记宿主 error 日志并累加
audit_failure_count(宿主可观测,非任务状态),任务
继续;审计完整性本身没有保证,文档与就绪清单明写。
- 边界:本决策只针对 VM 生命周期审计;VM 启动/关机等
门禁失败仍按原有分类失败处理,不受本条影响。
## ADR-10 长函数抽不动的耦合点(本轨后已无 >50 行函数)
- 本轨后 cloud/chv/ 全部函数均 ≤50 行,上一轨的 7 个
长函数全部拆完:stop_vm(进程清理/文件清理/脏标记三
helper)、wait_guest_ready(provisioned 守卫/不匹配检查)、
restore_vm(校验/启动段)、cleanup_stale_secrets(单 VM
清理/活 VM 判定)、cleanup_stale_vms(死 socket 扫描/
登记清理)、_unix_socket_api(读头/解析长度/读体/解析
响应)、validate_net_entries(归一化/去重/冲突检查)、
build_chv_config(组装段纯移动)。
- 残留耦合点(已拆但仍需注意):stop_vm 的三块清理共享
同一脏标记,任一块失败即整 VM 标记脏(有意,不拆成
三个标记);_unix_socket_api 的读满语义仍由四个 helper
共同保证,改任一 helper 须重跑截断/超时测试。
## ADR-11 只读 VM 字段边界:chv_vm_dead 不是 live 状态
- 决策:server 任务序列化只在 CHV 任务且 worker 已把
VM 死亡写进 interrupted_reason 列时返回 chv_vm_dead=True,
其它情形字段不存在;worker 终局时把执行器的 vm_dead
原因写回该列(见 worker.py 终局块),否则该字段在
生产里永远不出现。
- 边界:该字段是“已报告死亡”,不是“VM 活着/死了”的
live 状态——server 进程没有 VM 登记表,live 状态编不
出来;前端无该字段时不显示 VM 状态,不猜测。VM 控制
按钮仍不做(后端无控制端点且安全审计 No-Go)。