feat(chv-muse-p1): 常驻 VM + WarmPool 扶正 + 气球 + vsock,对齐 Muse

每用户一台常驻 VM(暂停态,resume 到 SSH 5 秒内为待验证目标),
池空/失败回落冷启动;CHV 配置加 virtio-balloon + free-page-reporting
与 vsock notify 最小实现(SSH 仍是命令通道与就绪判定)。
新模块 resident_pool.py / vsock.py + 客内 vsock_notify.py;
_config 增加 CHV_RESIDENT_IDLE_MINUTES / CHV_BALLOON / CHV_VSOCK;
worker_adapter 接常驻孤儿清理 facade;ADR-17 差距表见
docs/chv-muse-p1-gap.md。

恢复收尾(分离后回归,见 gap.md §4):VmDeathTest 死亡模拟改杀
实际跑命令的 VM;两处冷路径旧测试显式关常驻;_balloon_vsock_payload
与 listen_notify 拆到 50 行内;resident_pool.py:208 mypy 修掉。
executor.py out 未注解与 marker_tools.py:142 是基线旧错,未动。

测试:全量 cloud 套件 1934 OK(skipped=8);mypy 在改动文件上
干净(仅基线旧错 4 处)。真机验证待第三棒让出 WSL 测试机。
This commit is contained in:
host committed 2026-11-06 21:31:48 +00:00
1 parent 06c3e172fe
commit 78098c5594
13 files changed
+2527 -36

No files matched your search

+54
View File
@@ -57,6 +57,60 @@
- 重启条件:将来要重新接线,必须先实现任务盘重供给并补
“任务盘来源”不变量测试,否则不得把 wired 改成 True。
## ADR-17 常驻 VM 池取代 WarmPool 接线(feat-chv-muse-p1)
- 决策:不再接线 WarmPool,改走新建的生产模块
`cloud/chv/resident_pool.py`(ResidentPool):每用户一台
常驻 VM,任务到时 resume 已暂停的 VM,跑完 pause,不
销毁;池空或任何一步失败都回落冷启动。WarmPool 实验模块
一字不动,`wired_to_dispatch` 仍恒 False,ADR-5 的定案
(预热盘是干净快照盘、不是任务盘)仍然成立、只是不再
是接线障碍——常驻 VM 的盘本来就是每用户持久工作区盘,
不是每任务新盘。
- 隔离单元变了:常驻路径下隔离单元从“每任务”变成“每用户”
——同一用户的任务共享同一台常驻 VM 与同一块工作区盘,
每任务新盘的不变量在常驻路径上不再成立。冷启动路径
(每任务新盘)保留作回落与隔离严格场景。当前是单租户,
这个取舍可接受;多租户重审前不得把常驻路径当多租户隔离。
任务 dict 目前无 user_id,全落到 "default" 键;user_id
出现时按键隔离,release 绝不把用过的 VM 放回给另一用户。
- 接线:`_run_with_vm` 先常驻 acquire,命中走常驻路径
(finally 里 release=pause),失败/未启用走原冷启动路径
(finally shutdown 不变,冷启动本体逐字移到 `_run_cold`);
dispatch/run/goal/goal_resume/断点续跑都走 `_run_with_vm`,
签名不动。常驻默认开,`CHV_RESIDENT_ENABLED=0` 可关;
开关用 getattr/env 惰性读,`__init__` 不动。池空时惰性
provision 一次(wake + pause)再取,仍无则冷启动——首个
任务自举常驻 VM,不依赖 worker 启动时预热。
- 常驻执行细节:`_run_guest`/`_run_guest_goal` 一律走常驻伪
任务 `{"id": "resident-<用户>"}` 传参(SSH known_hosts、
api-socket、密钥投递记录、VMM 登记都按常驻 VM 名算),
返回后把 `task_id` 改回真实任务 id;中途死亡判据同样按
常驻伪任务查登记进程。带密钥 extra_env 的任务不走常驻
(seed 是建池时定的,密钥只能冷启动随 seed 投递),直接
冷启动。同一用户同一时间只跑一个常驻任务,并发第二个
任务回落冷启动。
- Registry:`state_dir/resident-pool.json`,文件 IO 与损坏
语义复用 orphans(原子写、损坏 quarantine、单条目非法
只丢该条);重启后读到的条目一律 orphan 不复用、只清理。
空闲回收:paused 超 `CHV_RESIDENT_IDLE_MINUTES`(默认 0=
不自动关机)时 hibernate(pause + snapshot + shutdown)
并删条目,快照文件留作恢复物,restore 是后续工作。
- 依赖方向(ADR-12 的禁令全部保留):executor 仍绝不 import
orphans/experimental_pool(常驻池用方法内 import 拿
ResidentPool);resident_pool → orphans(只借 registry
文件 IO,与 experimental_pool 同款方向);worker 启动/
关闭调 `worker_adapter.reconcile_resident_pool` facade,
它只读 resident-pool.json 做清理,不构造 ResidentPool。
`reconcile_warm_pool` 不动。
- 诚实边界(未验证,不宣称):resume 耗时、到 SSH 5 秒内、
气球压内存——无真机验证(第三棒占着 WSL 测试机),一律
记入真机待验证清单;resume 失败时 `wait_guest_ready` 的
失败路径会 stop_vm(含删工作区盘),该路径的工作区以
Gitea 同步为准;pause 失败时条目留在 running(不删不销
毁),worker 关闭时 reconcile 清理,在此之前该用户只走
冷启动。
## ADR-6 Docker goal 解析分叉:共享正典 + 同步守卫(本轨定案)
- 决策:Local/CHV 共用 parse_goal_result 正典;Docker goal_task