host
c7ffb1fe6f
fix(chv): 浏览器单元去掉成环的 After=cloud-final
...
cloud-final 自己 After=multi-user.target,与浏览器的
Before=multi-user.target(WantedBy 隐含)成环,systemd 启动时
直接删掉浏览器任务:构建 #9 驱动实证服务从未启动(NRestarts=0、
无日志,journal 明言 Job deleted to break ordering cycle),
构建 #8 同款问题一直被手动 restart 掩盖。改排在数据盘挂载单元
home-chv-workspace.mount 之后(真依赖);单测钉死不再出现
cloud-final。
2026-11-08 09:45:00 +00:00
host
0100ffe207
fix(chv): 完整 Chromium 检测认 CFT 布局 chrome-linux64
...
Playwright 1.64.1 下的 chrome-linux64.zip 解压为 chrome-linux64/
chrome,旧检查只认 chrome-linux/chrome:数据盘上 403M 完整版
已装好(含 DEPENDENCIES_VALIDATED)仍报未安装、mount_full 误
回落(2026-11-08 构建 #8 驱动实证)。两种布局都认;驱动安装
步在仍未装好时重试一次(客机慢出口 CDN 30 秒超时是抖动)。
2026-11-08 09:45:00 +00:00
host
9d986becaf
feat(chv): 完整 Chromium 改装数据盘
...
根盘只剩 ~600MB,playwright install chromium 装根盘 109 秒后
ENOSPC 失败(2026-11-08 构建 #8 驱动实证)。完整版改装数据盘
/home/chv/workspace/.chv-browsers(9.3G 空闲),仍不 bake 进
base、按需;full 引擎启动时直接传 executable_path(channel 与
executable_path 互斥,且驱动进程启动时才读 env,运行中改 env
无效);status 增 full_browsers_dir,mount 失败报错给数据盘
安装命令。驱动的安装步同步改数据盘并 chown 给 chv-browser。
2026-11-08 09:45:00 +00:00
host
435664925e
fix(chv): cell 不再把 /run/chv 的组改回 root
...
chv-cell 每次跑 cell 都 _ensure_bind_source(BROKER_DIR, uid=0,
gid=0),把 /run/chv 的组改回 root,抹掉 tmpfiles 的 chv-browser
组;之后 chv-browser 重启时 os.remove(browser.sock) 报
Permission denied、无限 crash-loop(构建 #8 客机 62 次重启才
被发现,03:42 驱动两次跑 cell 正好在补丁后、重启前)。改:组
改取 chv-browser 的 gid(不存在回落 0);serve() 删 socket
失败时报错说清修法,不再只剩裸 traceback。
2026-11-08 09:45:00 +00:00
host
0bfb00ab1b
fix(chv): 快照改走 page.aria_snapshot()
...
Playwright 1.64.1 已移除 page.accessibility,真实快照一路报
AttributeError(P2 假实现用的旧 API,单测一直没抓到;2026-11-08
构建 #8 驱动 live 抓到)。新版 aria_snapshot() 返回字符串,
超 64KB 截断;旧版 accessibility.snapshot()(dict)只作回落。
驱动的 a11y 断言接受 str 或 dict。
2026-11-08 09:45:00 +00:00
host
7361b0654f
fix(chv): _load_playwright 须返回 sync_playwright() 实例
...
返回函数本身则无 __enter__,真实启动路径从未跑通过(P2 假实现
掩盖;2026-11-08 构建 #8 驱动 live 抓到)。回归测试钉死该契约。
2026-11-08 09:45:00 +00:00
host
eb495892e1
fix(chv): 阶段 3 live 根因——浏览器 socket 与数据盘 profile 的两处权限
...
- /run/chv 0755 root:root 时 chv-browser 建 browser.sock 报
PermissionError、服务无限 crash-loop(P2 遗留,阶段 2 从未验
过 browser.sock):tmpfiles 改 0775 root:chv-browser。
- /home/chv 默认 0750,chv-browser 穿不过家目录,ismount 判假、
profile 静默回落本机盘:chv-data-mount 挂载成功后 chmod 0751
/home/chv(只放行穿过,不放行列表)。
- 驱动:等 cloud-init done + 四服务 active 再验浏览器。
- 回归 97 项全过(新增 2 项接线断言)。
2026-11-08 09:45:00 +00:00
host
1188e4b000
feat(chv): 阶段 3 浏览器服务化——持久 profile + CDP + 多会话 + JPEG 截图 + 双浏览器
...
- chv-browser:launch_persistent_context,profile 固定数据盘
/home/chv/workspace/.chv-browser-profile(未挂载回落本机盘并明说);
CDP --remote-debugging-port 9222(op cdp 返回 webSocketDebuggerUrl);
多会话每会话一页;截图 JPEG q70、viewport 宽封顶 1280、diff_only
整帧相同跳过;mount_full/unmount_full 切 full/shell 引擎,full
未装或起不来回落 shell 并明说。
- chv-data-mount:挂载后预建 profile 目录(chv-browser:chv-browser 0700)。
- build.sh:chv-browser 单元 Restart=always、After cloud-final.service。
- chv-execd:codex 环境白名单加 CHV_BROWSER_ 前缀。
- 测试:新增 test_chv_opt_stage3.py(20 项);P2 假实现改为持久
上下文 + JPEG;stage2 的 Restart=always 计数 3→4。
- 全量回归 2032 过 skipped=8。
2026-11-08 09:45:00 +00:00
host
6a65c94254
fix(chv): execd 单元 KillMode=process(构建 #6 驱动实证)
...
缺 KillMode 时 systemd 默认 control-group,kill -9 execd 主进程
后重启会 SIGTERM 整个 cgroup,sleep 任务同 pid 存活的要求被破、
新 execd 认领时 pid 已死记 unknown,驱动 kill 相断言失败。
KillMode=process 只信号主进程,任务在重启后同 pid 存活认领;
stop 仍干净停 daemon 本身。回归测试
BuildWiringTest.test_build_sh_execd_unit_keeps_tasks_on_restart。
2026-11-08 09:45:00 +00:00
host
42adbd047f
fix(chv): 79-chv-cell.network 改回 root:root 644(构建 #5 驱动实证)
...
virt-customize --copy-in 保留构建宿主 uid/mode,79 文件在客机
落盘成 chv:chv 640,networkd 不认它、改配 80-container-ve.network、
刷掉 10.200.0.1,cell _iface_has_ip 复核失败、codex --help rc=1。
构建时显式 chown root:root + chmod 644 并断言属主与权限;
回归测试 BuildWiringTest.test_build_sh_fixes_cell_network_file_owner。
2026-11-08 09:45:00 +00:00
host
1cbaf7c1d5
chv-cell: networkd 不管 ve + 单元内 DNS 修复
...
- systemd-networkd(/usr/lib 80-container-ve.network,匹配 ve-*)
会在 veth 建好后几秒内刷掉静态 10.200.0.1、改 DHCP/链路本地,
致单元网关不可达、TCP/UDP 全灭(FORWARD/NAT 计数器恒 0;
早先一次 curl 403 是刷掉前的窗口期偶发)。修法:镜像内置
/etc/systemd/network/79-chv-cell.network(Unmanaged=yes),
须排在 80 之前(99 会被 80 抢走,已实测);build.sh copy-in
+ 校验、BASE_CONTENTS 与两处 DECLARED_SOURCES 登记。
- run_cell 配网后复核 ve 上确有 10.200.0.1(_iface_has_ip),
不见即大声失败、不跑无网单元(第二道防线)。
- 单元内 DNS:/etc/resolv.conf 是 127.0.0.53 stub,单元独立
netns 里自己的 lo 上没有 resolver;把上游
/run/systemd/resolve/resolv.conf 绑到 /etc/resolv.conf
(解析 symlink 后挂真实目标)。live 验证:DNS-UDP-OK、
getaddrinfo 解析成功、curl https://gitea.tose.top 200。
- 单测:CellResolvTest + _iface_has_ip 真实 lo 断言 + 规约
dns_resolv_conf 字段;P2 + 阶段 2 共 74 项全过。
2026-11-08 09:45:00 +00:00
host
4b5f2f124f
chv-cell: ns 内 setuid 修复 + 单元内 DNS(上游 resolv.conf 绑定)
...
- 中间进程不再先 setuid(1000) 再 unshare:真机对照实测那样
后续 unshare(CLONE_NEWNS) 得 EPERM;改为保持 root 外层身份
unshare(creator caps 在),孙进程在 ns 内 setgid/setuid(0)
切到内 0(映射到外层 chv 1000)。
- 单元内 DNS:客机 /etc/resolv.conf 是 127.0.0.53 stub,单元
独立 netns 里自己的 lo 上没有 resolver;把上游
/run/systemd/resolve/resolv.conf 绑到 /etc/resolv.conf
(解析 symlink 后挂真实目标),只在单元私有 mount ns 里。
- 单测:CellResolvTest(bind 参数/symlink 解析/缺失回落)
+ 规约 dns_resolv_conf 字段;P2 + 阶段 2 共 73 项全过。
2026-11-08 09:45:00 +00:00
host
afbb7772c5
fix(chv): cell 映射改由父进程写,中间进程先 setuid(1000)
...
两个真机教训(2026-11-07):
- 子进程自己写不进 uid_map:unshare 后 euid 变 overflow,
连 /proc/self/uid_map 的 open 都 EPERM——改由父进程
(仍在初始 ns 的 root)经 /proc/<pid>/uid_map 写。
- 映射按外层 uid 翻译:中间进程外层是 root(0) 时
“0 1000 1” 盖不住它、新 ns 里仍是 overflow——中间进程
须先 setgroups/setgid/setuid(1000) 再 unshare(实测
chv 身份 unshare 在客机上可行,AppArmor 不挡)。
另:中间进程异常加 traceback(调试用);userns 单测改测
父写映射真实路径(映射行按 split 比,内核会多空格对齐)。
2026-11-08 09:45:00 +00:00
host
a2a5624736
fix(chv): cell 后端由 nspawn 改为纯 stdlib userns 启动器
...
nspawn --directory=/ 在 systemd 255.4 上走不通(2026-11-07 真机
实测,修一个冒一个):裸 --no-new-privileges 被当成要值吞掉
下一个参数;--directory=/ 被根目录检查挡住;--volatile=state
又要 /run/host/os-release 挂载点与空 /dev(--tmpfs=/dev 不
生效)。cell 从未 live 跑通过(阶段 1 只测参数表纯函数)。
bwrap 作 chv 被 AppArmor userns 门挡住,newuidmap 客机未装。
新后端(同文件、同 CLI、同调用方):root 起进程,中间进程
unshare 用户 ns 并自己写 uid_map/gid_map(内 0 → 外 chv
1000),再进 mount/pid/net ns、挂 fresh /proc、/tmp tmpfs、
遮蔽敏感路径(目录盖 tmpfs、文件绑 /dev/null)、设
no_new_privileges + seccomp(禁 io_uring 三件套)+ 丢
capability,最后 exec payload;父进程配 veth/NAT、等退出码、
清 NAT。veth/NAT/nsenter 流程与旧版一致,seccomp BPF 与
capability 语义与 P2 设计一致。无新依赖、无 sysctl 改动。
2026-11-08 09:45:00 +00:00
host
42b295fc71
fix(chv): 阶段 2 syncd 改走 systemd RuntimeDirectory=/run/chv-syncd
...
tmpfiles 行 d /run/chv/syncd 0755 chv chv 没用:tmpfiles-setup
跑在 cloud-init 建 chv 用户之前,属主解析失败整行被跳过,
客内 /run/chv/syncd 根本不存在(2026-11-07 真机实测:镜像
里有这行、目录没有,syncd 反复退出、restart counter 57)。
改走单元 RuntimeDirectory=chv-syncd(服务启动时由 systemd
按服务用户建目录,不依赖启动时序);状态写失败改为记日志
不杀进程;daemon 与驱动的 syncd 路径同步改到
/run/chv-syncd/。
2026-11-08 09:45:00 +00:00
host
8013431f63
fix(chv): 阶段 2 syncd 写路径改到 chv 所有的 /run/chv/syncd/ 子目录
...
/run/chv 是 0755 root:root,chv 身份的 syncd 写不进状态文件
与 socket,_atomic_write 抛错致进程反复退出、systemctl 长期
activating(2026-11-07 真机实测)。socket 与状态文件改到
tmpfiles 预建的 /run/chv/syncd/(0755 chv:chv,与 chv-browser
的 shots 同款);daemon 的 sync 摘要读同一路径;驱动的
syncd socket 路径与 ls 检查同步更新;另修驱动 SSH poller
线程残留(daemon=True + wake 失败也 set 事件)。
2026-11-08 09:45:00 +00:00
host
9d77ae55a7
feat(chv): 阶段 2 客机运行时三分 daemon/execd/syncd + restore 留 seed.iso + tap 退避
...
- 客机三分(chv-guest/chv-daemon.py、chv-execd.py、chv-syncd.py,
仅标准库;systemd Restart=always;build.sh 拷入 + 单元 + enable;
buildinfo/check/generate lockfile 登记):
daemon=心跳/资源上报/快照配合(prepare-snapshot 问 execd,
有运行中任务或联系不上即拒绝);execd=shell/文件读写/codex
托管(chv-cell 起 host.py,setsid 脱离,任务登记落盘,
重启按 pid 认领;SO_PEERCRED 只认 uid 0/1000;codex env
白名单);syncd=常驻循环只调 chv-sync pull/push,规则一条
不改(先 pull --ff-only 再 push,分叉即停、不 --force、
不 rebase;仓不存在记 needs-boot 不擅自 clone)。
host.py 仍是唯一任务/codex 引擎,broker/browser/cell 分工
不变,不另起第二套 agent。
- 阶段 1 遗留修复:restore_vm 失败路径 stop_vm(keep_disk=True),
seed.iso 与任务盘都留,重试有输入;vm.boot/restore 的 tap
触点遇 Resource busy 等 tap 空闲后重试一次(_wait_tap_idle
看 ip link state,_ch_remote 报错带 stderr 尾巴以便识别);
诊断不用 pgrep -x(15 字符上限)。
- 单测 cloud/tests/test_chv_opt_stage2.py 25 项;P2 干跑夹具
与 enable 行断言随构建接线更新。
- 全量 cloud/tests 2001 全过(skipped=8)。
2026-11-08 09:45:00 +00:00
host
f809014bef
feat(chv): 阶段 1 数据盘与 tenant 标记同 overlay 解耦(copy 也供)
...
真机根因(2026-11-07,CHV v54 三变体实证):vm.boot 对任何
带 backing file 的 qcow2 都报 Maximum disk nesting depth
exceeded——overlay-only 与 overlay-rawbase 均 500,base 直接
启动(reuse)22.5 秒成功,数据盘与压缩均已排除。overlay 在
本 VMM 上不可用,持久 VM 须能在 copy 模式下跑。
- _provision_task_disk:copy 与 overlay 都供数据盘并写
tenant.json(只有 reuse 不供不写);_provision_data_disk_path
同理(reuse 才返回 None)。
- _cleanup_vm_task_disk:保护(持久登记/登记快照)不再只限
overlay 模式;无登记无快照的 copy 盘仍按旧语义删除。
- provision_data_disk:数据盘改 raw 稀疏盘(os.truncate,
零外部依赖)——copy 模式本来就不需要 qemu-img,数据盘
绝不能悄悄加上这个依赖;CHV 按后缀认 Raw。
- 测试:新增 copy 供数据盘+tenant 与 copy 持久盘 stop 保护;
VmConfig 三盘断言(任务+seed+数据)更新 arch95/fix 两处
旧“恰好两盘”契约与本轨 qcow2 类型断言。
回归:test_chv_*.py、test_cloud_hypervisor.py 42、test_chv_v3_fixes
38 全过(全量 cloud/tests 在跑)。
不推、不合、不部署;只本地分支。
2026-11-08 09:45:00 +00:00
host
a5f836e9fd
feat(chv-guest): 阶段 1 数据盘独立持久(客内挂载)
...
- 新增 chv-guest/chv-data-mount.sh:按 LABEL=CHVDATA 找盘
(不依赖 /dev/vd? 固定名;seed ISO 与根盘排除),无 fs
即 mkfs.ext4 -L CHVDATA,挂到 /home/chv/workspace,幂等;
无数据盘即静默退出 0(copy 模式旧 VM 不报错)。
- build.sh:缺脚本即失败(与 chv-sync.sh 同款门);拷入
镜像 /usr/local/bin/chv-data-mount;99-chv-sync.cfg
runcmd 在 chv-sync boot 之前调它(工作区先挂好再 clone)。
- buildinfo.py BASE_CONTENTS 与两 lockfile DECLARED_SOURCES
登记 chv-data-mount(repo_commit,随 P2 三脚本先例)。
- tests:test_chv_opt_stage1.DataMountScriptTest(脚本内容、
构建接线、lockfile 登记);P2 干跑夹具补新文件。
回归:discover test_chv_*.py 与 test_cloud_hypervisor.py 全过。
不推、不合、不部署;只本地分支。
2026-11-08 09:45:00 +00:00
host
7a6fae7993
feat(chv): 阶段 1 持久 VM、overlay 分层与预热快照
...
- disk.py:overlay 模式(qcow2 backing file 指只读 base,
建盘/复用/重建校验 + qemu-img fail-closed)、数据盘
data.qcow2 独立供给(不进快照/GC/stop)、配额增量口径
(overlay 本次增量 0)、快照登记 tenant 字段、每 VM
tenant.json、持久登记 persistent/<tenant>.json、快照
登记按 URL 查找。
- config.py:CHV_DISK_MODE 白名单加 overlay(默认仍 copy;
错误文案保留旧子串,防回归测试钉死)。
- executor.py:VmConfig image_type 按后缀(.qcow2→Qcow2,
其余 Raw)+ 数据盘第三块盘;overlay 供给写 tenant 标记;
snapshot_vm 登记带 tenant,_validate_restore 归属校验
(跨用户 snapshot_tenant_mismatch 拒绝 + 审计,legacy
未标记/未登记放行并警告);stop/GC 在 overlay 模式下
保护持久登记/快照认领的盘;持久 VM(prewarm/acquire/
suspend/dispatch_task_persistent/recycle_persistent_vm,
CHV_WARM_POOL_SIZE>=1 启用,=0 退化冷启旧语义),
resume 只认 vm.info=Paused + socket 活性 + 归属一致。
- tests:cloud/tests/test_chv_opt_stage1.py 26 项(overlay、
tenant、持久池、跨用户拒绝、两连任务、显式回收)。
回归:discover test_chv_*.py 与 test_cloud_hypervisor.py
全过(结构契约:函数 ≤50 行、公开 API 全注解、文案钉死)。
不推、不合、不部署;只本地分支。
2026-11-08 09:45:00 +00:00
host
c904ae9358
carry-over: 在途 V-9 根因修复 + Muse P2 对齐原样带入(未改一行业务逻辑)
...
来源:feat-chv-muse-p2 @ c918d69 的 6 个未提交文件(+157/-29):
build.sh(GT 哈希轮换 + 99-chv-sync.cfg runcmd chown)、
check_lockfile.py / generate_lockfile.py(DECLARED_SOURCES 加
chv-cell/chv-broker/chv-browser)、executor.py(_wait_guest_env_usable)、
hostkeys.py(guest-env owner 恒 root:root)、test_chv_v3_fixes.py。
单测:python3 -m unittest cloud.tests.test_chv_v3_fixes 38/38 通过。
本提交只搬运,不含阶段 1 改动;阶段 1 另起提交。
2026-11-08 09:45:00 +00:00
host
1836c5af32
fix(chv): V-7 复测缺陷复修 D1/D2 + F1 瞬时 reset 重试
...
D1:snapshot_vm 在配额预检后、ch-remote 前建好 file:// 目标
目录(新 helper _ensure_snapshot_dir;fresh URL 直接 snapshot
曾 rc=1 Destination is not a directory)。建目录只在 snapshot_vm
一处,hibernate 经此调用;配额拒绝仍先于任何文件改动。
D2:keep_disk=True 时 stop 保留 seed.iso(_remove_vm_seed_files
抽出;快照 config.json 的 disks 同时引用 disk.raw 与 seed.iso),
且 cleanup_stale_secrets 不清有登记快照的 VM 的 seed(与
gc_stale_disks 的盘保护同款逻辑);正常 stop 仍删两者。
F1:首条任务 SSH 撞 kex 阶段瞬时 reset(rc=255 + kex/reset 标记)
时重试恰好 1 次(_call_ssh_with_transient_retry,_run_guest 与
_run_guest_goal 共用;host key 拒绝/认证失败/远端失败不重试;
审计 vm_ssh_transient_retry)。§5“执行器内部不重试”的唯一例外,
结论写入 docs/chv-production-readiness.md §3/§5/§7。
测试:test_chv_v3_fixes 新增 12 项(D1×3、D2×4、F1×5);旧代码
上 12 项中 9 项失败(余 3 项为守卫既有行为)。全量 test_chv*
470 测试通过。
2026-11-08 09:45:00 +00:00
host
65504ae8cb
fix(chv): V-3/F1/F2 真机缺陷修复 + V-1/V-4 附带修复
...
V-3 快照/restore:
- snapshot 改传裸 URL(source_url= 是 restore 的键,服务端
Could not extract path from URL);快照产物是目录,校验
改为目录非空,登记计量/剪枝同步支持目录
- restore 起 VMM 前补 _restore_prepare:杀旧 VMM(登记的 +
未登记跨实例扫描)并清旧 socket,与 _wake_prepare 对等
- hibernate 评估结论:快照 config.json 引用原盘,旧 stop 删
盘致 restore 必失败;hibernate 的 stop 改 keep_disk=True,
GC 不删有登记快照的 VM 的盘,restore 前预检快照引用的盘
(snapshot_disk_missing fail-fast)
F1:re-wake 删旧盘——H5 删私钥致 re-wake 必然生成新 key 对,
旧盘复用时 cloud-init 不重应用新 seed,sshd 仍呈旧 key 而
known_hosts 钉新 key;wake 本就是冷启动,旧盘不是要保留的状态
F2:stop_vm 跨实例按 socket 进程扫描杀未登记 VMM
(/proc cmdline 精确 socket + VMM 二进制名 + 跳过自身/pid 1,
绝不误杀 ch-remote 与他人 VMM)
V-4:remote_command source 失败改 || exit 126 fail-fast;
guest-env 条目 owner 改归 SSH 用户(0600 不变),root 仍 root:root
V-1 附带:build.sh 预建 /app/work(1777 粘滞位 + stat 断言);
host.py default_codex_bin() 改 shutil.which,裸名不再让
health 报 ok:false
测试:新 test_chv_v3_fixes.py 23 项;旧快照测试按目录产物改写;
test_chv* 458 全过,全量 cloud 套件 1930 全过(skipped=8)
2026-11-08 09:45:00 +00:00
host
ef206cf554
feat(chv-guest): 对齐 Muse P2——nspawn 单元 + broker + 浏览器子代理
...
- chv-cell:systemd-nspawn 单命令单元,--private-users=1000:65536
(单元 root → 客机 chv),丢 8 项能力(含 SYS_PTRACE/NET_ADMIN),
syscall 过滤扣 io_uring,遮蔽 /etc/chv 与 playwright,
--network-veth(10.200.0.0/24 + NAT),白名单环境透传
- chv-broker:Unix socket + SO_PEERCRED(uid 范围 + pid ns 对照),
白名单 ping/sync/browser;sync 只调 chv-sync(runuser -u chv)
- chv-browser:单元外独立进程,只暴露 open/snapshot/screenshot/
close/ping,返回无障碍树快照(截断);evaluate/content 拒绝
- build.sh:装 systemd-container/iproute2/iptables,拷入三脚本,
建 chv-browser 用户与两个 systemd 单元;vsock_notify 条件拷入
- buildinfo:内容项加 P2 四项,支持可选 extra_contents
- 测试:cloud/tests/test_chv_muse_p2.py 40 项全过;broker/browser
真实 socket 回路冒烟通过(root 连 broker 被拒)
- 差距表:docs/chv-muse-p2-gap.md;真机验证待测试机空闲(round 11)
本地做,不推、不合、不部署
2026-11-08 09:44:59 +00:00
host
cef6353c85
fix(chv): restore 路径补 H7 net 校验+登记,seed 暂存文件走 atomic_file
...
restore_vm 此前既不校验 net 冲突、也不登记 net.json:
已登记 VM 的 tap/mac/ip 会被恢复出的 VM 静默复用,且
恢复出的 VM 自身不登记、后来的 wake 也看不到它,两边
都漏判。现与 wake 同款:_validate_restore 在起 VMM 前
校验冲突(net_tap_conflict + vm_failed 审计),
_restore_boot 在 restore 成功后登记 net.json,登记失败
审计 net_registry_write_failed + 拒绝恢复(P2-19 语义,
stop_vm 清半恢复 VM)。
hostkeys.write_seed/_apply_seed_extras 的 meta-data、
user-data、network-config 改走 atomic_file(mkstemp 0600
→ 写 → fsync → rename):user-data 含 host 私钥明文,
直接写 + 事后 chmod 会在 chmod 前以 umask 权限短暂可读;
半截文件本身到不了 ISO(唯一消费者 genisoimage 只在
write_seed 返回后跑),原子写同时堵住权限窗口与半截残留。
回归测试 6 个:restore 冲突拒起/恢复后登记/登记失败
拒起/无 net_json 不登记;seed 走原子写(0600、无 tmp
残留)/写失败不留半截文件。CHV 全套件 395 测试通过。
2026-11-08 09:44:59 +00:00
host
b3cd353a76
fix(chv): P2-20/P2-19/P2-17/P2-18 残留收尾 + NO_PROXY 合并
...
- P2-20:_guest_env_delivered 加专用锁,读写只走
_delivered_secrets/_mark/_clear 三个入口,并发 hammer 测试钉死
- P2-19:_record_net_entries 失败发 net_registry_write_failed
独立审计并返回 False;_boot_vm 见 False 即拒起(wake 随后清半醒 VM)
- P2-17:net.json 删失败发 vm_net_registry_delete_failed 审计;
_write_dirty_marker 失败发 dirty_marker_write_failed 审计并返回
False,stop 不抛的契约不变
- P2-18:新增 cloud/chv/atomic_file.py(mkstemp 随机名 + 文件
fsync + rename + 目录 fsync),net.json/known_hosts/
snapshots.json/pool registry/脏标记/spill 全部走它,固定 .tmp 清零
- H1 附带:NO_PROXY 实测确有覆盖 bug(env 重复赋值以后者为准,
调用方 NO_PROXY 被 egress 的 localhost 值静默覆盖),改为合并
单条发出;egress 已设时调用方代理变量(含小写)一律不发
- 测试:新增 cloud/tests/test_chv_residual.py(23 项),旧 closeup
两处钉死旧语义的测试按新语义更新
2026-11-08 09:44:59 +00:00
host
c94cb05157
fix(chv): known_hosts 22 端口写裸 host 行,修 provisioned 钉死失效
...
OpenSSH 默认端口只查裸 host 名、非默认端口只查
'[host]:port':known_hosts_line 对 22 端口也写
'[192.168.10.10]:22',ssh 永远匹配不上,报 Host key
verification failed、wake fail-closed 关 VM。keyscan
TOFU 输出裸行,lite9 没暴露。非 22 端口仍用括号形式。
2026-11-08 09:44:59 +00:00
host
82e4150e24
fix(chv): CHV 54 VmConfig 形态——payload.kernel/cmdline 纯字符串 + 磁盘显式 image_type Raw
...
真机 CHV 54.0.0 实测:旧顶层 kernel:{path}/cmdline:{args}
create 时 204 照放、vm.boot 400 'No bootitem provided';
补 payload 后又报 'Image type required for disk'(raw 盘
无魔数、探测失败),磁盘须显式 image_type,枚举原名
Raw(JSON 写小写 raw 报 unknown variant)。
2026-11-08 09:44:59 +00:00
host
e7fe0d65e1
fix(chv): api_client 接受 204 无 Content-Length 响应
...
WSL 真机实测(CHV 54.0.0):vm.create 成功回 204 No Content,
且不带 Content-Length、无体;严格校验(P1-6)把合法成功当
失败拒掉,wake_vm 卡在 vm.create。204/304 按 HTTP 语义体长
恒为 0,不要求长度、不读体(keep-alive 下读会等到超时);
其它状态仍严格(无长度/截断/chunked 均拒绝)。
测试:test_chv_cover100 新增 3 项(204 成功、200 无长度仍拒、
_parse_status)
2026-11-08 09:44:59 +00:00
host
af64f31138
feat(chv-guest): seed 附加项供客机用户与静态网络(wake 路径前置)
...
wake_vm 在 WSL 台架上跑通需要客机身份与网络:镜像本身不建
用户、tap 无 DHCP,缺 users 块的 VM 登不进去、缺 network-config
的 VM 拿不到静态 IP。最小补法(复用 write_seed 机制):
- hostkeys.write_seed 新增 user_data_extra(原样追加进
user-data,供 users: 块)与 network_config(写 seed
network-config 文件,0600);附加项含 runcmd: 即 ValueError
- config _seed_fragment:CHV_SEED_USER_DATA_EXTRA_FILE /
CHV_SEED_NETWORK_CONFIG_FILE(只存路径)
- executor._seed_extras 在 wake 起 VMM 前读入,缺失即
ChvFailure seed_extra_missing;provision_host_key 透传
- README §7 残留更新:guest-env 集成已做
- 测试:test_chv_gitea_sync 新增 5 项(写盘/禁 runcmd/
配置映射/wake 带附加项/缺失 fail-closed)
2026-11-08 09:44:59 +00:00
host
540cbaf473
feat(chv-guest): Gitea 同步变量经 seed 进 guest-env(执行器集成)
...
- 新增 cloud/chv/gitea_sync.py:6 键白名单,三源合并
(宿主 CHV_GITEA_* < 任务 gitea_sync < extra_env),
必填 4 键缺失即 fail-closed,空即不同步
- ssh_transport:GITEA_TOKEN 进密钥集(argv 拒绝),其余
5 键进 guest-env 集(split_guest_env)
- hostkeys.write_seed:guest_env 与 secret_env 合并写同一
条目,仍无 runcmd、0600
- config:_gitea_fragment 产 gitea_sync_env(函数内 import,
叶子模块顶层只许标准库)
- executor.wake_vm:起 VMM 前合并+校验(gitea_sync_incomplete),
guest-env 随 seed 投递;provision_host_key 透传 guest_env
- worker:_run_attempt 仅对 CHV 执行器把同步变量并进 gateway_env
- 测试:cloud/tests/test_chv_gitea_sync.py 20 项
- 边界:tasks 表无 JSON 列,DB 往返丢任务 gitea_sync;
生产主来源是宿主 CHV_GITEA_* 环境变量
2026-11-08 09:44:59 +00:00
host
706fe88f46
fix(chv-guest): seed user-data 不再自带 runcmd,防顶掉镜像钩子
...
sync-test 首轮实测:seed 的 runcmd 整体替换了镜像
/etc/cloud/cloud.cfg.d/99-chv-sync.cfg 的 runcmd(cloud-init
不跨配置类型合并,merge_how 救不了 conf.d),chv-sync
boot 钩子静默不跑、启动 clone 没跑。
- hostkeys.build_seed_user_data 不再发 runcmd;chmod 600
已由 write_files 0600 保证;sshd 重启搬到镜像自己的
runcmd(cloud-final,sshd 首次启动之后)。
- build.sh:99-chv-sync.cfg 的 runcmd 增加 restart ssh
一行(在 chv-sync boot 之前)。
- README §5 同步硬性要求;回归测试 2 项(无 runcmd、
带 secret 仍单 write_files 列表无 runcmd)。
- 针对性 147 项全过(test_chv_to10/gaps/secfix/fix/
arch95plus)。
本地提交,未推未部署。
2026-11-08 09:44:59 +00:00
host
e8cf356616
fix(chv-guest): 首启缺 key 时才生成 host key(B-23)
...
Minimal 底座 cloud.cfg 不含 ssh 模块,build.sh 又写
ssh_genkeytypes: [] 彻底关掉首启生成:客机无 host key、
sshd -t 失败、ssh.service 连败 5 次,SSH 全程不通(真机
冒烟 131s 未通,console 已到 login、ping 通、tap 正常)。
修正:99-chv-hostkey.cfg 改写首启 bootcmd,只在缺
ed25519 key 时 ssh-keygen -A;ssh_deletekeys: false 保留,
绝不重生成已预置的 per-VM key(bootcmd 跑在 seed
write_files 之前,预置 key 随后覆盖生成值)。README §5
同步修正;新增 BuildScriptTest 回归断言。
2026-11-08 09:44:59 +00:00
host
7674f7396b
feat(chv-guest): 轻量镜像 + Gitea 双向同步(停全量版,改 Ubuntu Minimal)
...
- build.sh 改轻量:Ubuntu Minimal 底座、apt 精简(git/ssh/cloud-init/
python3/pip/curl/ca-certificates/xz-utils/fonts-wqy-microhei)、
Playwright + chromium-headless-shell、去 B-16 +12G 扩盘;
加 git + gt 1.0.0(官方 install.sh + SHA256 校验,GITEA_CLI_VERSION
钉 1.0.0)与 chv-sync 启动钩子(cloud-init runcmd)
- B-19(新发现):dpkg freeze 的 ${Package} 会被客机 shell 展开
成空,284 行全空白;加反斜杠转义,探针实测已出真实版本
- buildinfo.py:轻量 contents、chromium-headless-shell、gt_version
- generate/check_lockfile.py:gt/chv-sync 声明来源、headless-shell 映射
- chv-sync.sh(新):boot/pull/push/status,分叉/脏树失败关闭,
凭证走 seed 盘 guest-env,不进镜像
- README §1/§2/§3/§4 改轻量口径,新增 §7 Gitea 双向同步
- tests:ChvSyncTest 6 项(本地 bare 仓当远端);针对性测试 144 项全过
2026-11-08 09:44:59 +00:00
host
3b5dd7a473
test(chv-guest): 构建脚本测试夹具跟进 B-09 新契约
...
- 假 codex 二进制须报出版本号(codex --version 核对)
- 假仓库改为真 git 仓库,REPO_COMMIT 取其实测短 hash
(旧 test123 非 hex,B-03 格式校验本应拒绝)
- 干跑行补 BUILDINFO.json 字样(断言依赖)
另:79ba56b(并行轨)已把 Playwright 改默认开启、单次
virt-customize、补 fonts-noto-cjk,本提交只补测试与干跑
文案,不动构建逻辑
2026-11-08 09:44:59 +00:00
host
bfc1010a24
fix(chv-guest): 客机镜像构建缺口补齐(B-02/B-03/B-04/B-05/B-06/B-07/B-08/B-09/B-10/B-13/B-15)
...
- B-10(实测):virt-customize chroot 里 sshd -t 必败,双因:
无 host key(exit 1)+ 缺 /run/sshd(exit 255);修为
mkdir -p /run/sshd + ssh-keygen -A 临时生成,断言通过后
立删临时 key,镜像仍不带 host key(已在 WSL 真机预演验证)
- B-08:Playwright 装在第二次定制,须重写 pip freeze 否则
BUILDINFO 里无 playwright;Chromium 以 ms-playwright 缓存
目录名记录进 guest-versions-chromium.txt
- B-09:codex --version 须含 CODEX_VERSION;REPO_COMMIT 须
等于 HEAD 短 hash;工作树脏即拒绝构建
- B-02/B-13:BUILDINFO 生成抽成 buildinfo.py(可单元测试),
补 disk.raw/vmlinux sha256+大小、ubuntu 镜像 sha、cmdline、
playwright 开关、image_sha256 字段
- generate_lockfile.py 改写:版本唯一来源改为
BUILDINFO.versions(客机读回),codex 三件套取
codex_version、/app/host.py 取 repo_commit、chromium 取
versions.chromium;不再查构建宿主 dpkg/pip(旧方法不成立)
- check_lockfile.py 补强:条目格式、contents 全覆盖、冻结
清单双向比对
- B-03/B-04 输入格式校验、B-05 curl 重试、B-06 哈希不符
删文件重下、B-07 磁盘预检、B-15 set -euo pipefail
- 同步改 test_chv_to10.py:generate 不再查宿主,改断言客机
版本来源 + 不回落宿主
2026-11-08 09:44:59 +00:00
host
7f83023fd2
test(chv): 补齐 chv 模块剩余覆盖到 100%(生产与实验分开计分)
2026-11-08 09:44:59 +00:00
host
c15fc9b41f
test(chv): 修复 isWorkerAlive 边界测试抖动(精确边界改确定性字段测)
2026-11-08 09:44:59 +00:00
host
2e789c0d48
feat-chv-closeup:收尾(executor 覆盖到 100%、合并/灰度准备,堆叠于 #264)
...
- 后端新增 cloud/tests/test_chv_closeup.py 85 项:唤醒失败
(vm.create/vm.boot/API 超时/guest 就绪超时/host key 不匹配/
provisioned 缺钉死)、恢复与快照失败、取消与清理(残留
socket/登记/磁盘/密钥、脏标记)、中途死亡分类、只读
execute 归类、入口校验、preflight 事后改写、防御性
except、worker_adapter 剩余分支;executor.py 覆盖 100%。
- 前端新增 src/api/chv.closeup.test.ts 13 项:显式 false、
undefined、可用性优先级、Workers 旧 bug 文案不复发、
120 秒边界;控制按钮与新页面仍不做。
- 新增 tools/chv_merge_precheck.py(只读):逐个核 base/head/
mergeable/CI/链衔接,实测 11 个 PR 全 NOT-READY(CI 全
FAIL、mergeState 全 UNSTABLE),退出码 1,绝不合并。
- docs/chv-production-readiness.md 新增 §14:审计落盘运维
runbook(定位/轮转/读取/清理,ADR-14 取舍不变)、mypy
默认口径 2 错评估(沙箱验证过的标注修法,本轨不改
其它链文件)、灰度三阶段可执行清单、V-1~V-9 检查表
(全部未验证)、逐项评分。
- 安全语义不变:egress、key seed 投递、磁盘删除、默认
provisioned、tap 校验、前端不绕后端白名单均未放宽。
- 只到 PR OPEN,不合并、不部署;CI 账单仍是硬门禁。
2026-11-08 09:44:59 +00:00
host
f42c1f2b9b
feat-chv-to10:往 10 分方向提升(类型/lint 清零、worker 适配抽取、审计落盘、lockfile 生成脚本、前端四态与统一文案、就绪清单 §13)
2026-11-08 09:44:59 +00:00
host
4fa94edd9b
feat(chv): 架构/可维护性/前端只读侧推进——生产实验分离、配置片段化、VM 只读展示
...
架构:WarmPool 从 cloud/chv/pool.py 移到 experimental_pool.py,
生产残留清理彻底分文件到 cloud/chv/orphans.py(facade 直接读
registry 文件清理,不构造池、不碰 prewarm/acquire/release);
cloud/chv 与 cloud/sandbox 不再导出 WarmPool,旧路径一律
ImportError(CHV 未合并、无生产用户,兼容保留已无保留理由);
worker 改走 orphans facade,不再持有 _warm_pool;#215 对齐从
接口形状推进到 REPLACEMENT_POINTS 替换清单(R1/R2 可机械替换、
R3 永不替换,#215 模块当前不存在由测试钉住)。
可维护性:build_chv_config 拆成 base/ssh/network/quota/disk/
timeout 六片段(组装只做 dict 合并,键冲突即报错;38 字段集
与取值不变,单项非法报错文案逐字一致);ADR-12 模块职责图
与禁 import 清单(AST 钉住);cloud/chv/ 公开 API 全量类型
标注、无 Any 逃逸,并修正三处旧标注错误;死代码扫一遍
(删实验池已无调用的 _quarantine 委托与未用 _LOGGER)。
前端(只读侧,不做控制按钮):chv.ts 新增纯逻辑谓词与文案
(执行器精确匹配、附件守卫、VM 状态文案、列表徽标);列表
行新增 VM 已报告死亡徽标;详情对全部 CHV 任务显示 VM 行
(已报告死亡/未报告死亡,不猜 live);WorkersSection 与成本
卡沿用已有数据,不新开池管理/成本页;服务端未新增第二个
生命周期字段(持久化事实只有三项,chv_vm_dead 已是完整派生),
只把派生抽成 _chv_vm_dead_from_row 并补 goal 回落形态测试。
2026-11-08 09:44:34 +00:00
host
56a6241bbe
feat(chv): 架构与代码质量 9.5+ 提升——长函数清零、WarmPool facade、#215 对齐、审计计数、只读 VM 字段、ADR-8~11
2026-11-08 09:43:59 +00:00
host
57cf397fe7
feat(chv): 架构与代码质量提升——WarmPool 定案、长函数提取、严格测试替身、Docker 同步守卫、配置统一校验、类型注解与 ADR
...
堆叠于 #246(feat-chv-secfix),只到 PR OPEN,未合并、未部署。
安全语义不变:egress、key seed 投递、磁盘删除、默认 provisioned、
tap 校验一律保留;前端零改动。
- WarmPool 定案为实验性(ADR-5):dispatch 永远冷启动,
wired_to_dispatch 恒 False,acquire/resume 只保留实验接口,
worker 仍调 reconcile_orphans 清理残留。
- 长函数提取:preflight 126→31、wake_vm 135→36、__init__ 69→31、
build_chv_config 159→58;错误文案逐字不变。
- 严格测试替身:fake API 校验 VmConfig(任务盘+seed 盘、net
无重复),fake SSH 校验 known_hosts 钉死;新增 5 项测试。
- Docker 同步守卫:8 个真实标记用例下 Docker 内联版与正典
parse_goal_result 状态全等,改分叉即 fail。
- 配置统一校验:preflight 以 config_invalid 统一兜底端口/配额/
超时/快照/host-key 模式(构造时已校验正常值,preflight 兜底
事后改写);CHV_NET 与 CHV_NET_JSON 双设仍警告不硬拒。
- 类型与 lint:chv 叶子模块公开 API 补类型注解;stdlib 扫描
揪出 executor 内 1 个真死 import(host_key_paths)并删除。
- ADR:docs/chv-architecture.md(ADR-1 至 ADR-7)。
测试:CHV 163 项全过;cloud 全量 1593 项三跑结果为 8 errors
(首跑详细日志因 tail 截断丢失)、全过、1 失败(浏览器代理
时序测试,与 CHV 无关),全量本身存在时序偶发,CHV 套件
确定性全过。
2026-11-08 09:43:17 +00:00
host
6a74d0182c
feat(chv): 安全审计修复 High/Medium/Low(堆叠于 #239)
...
审计报告 ~/workspace/chv-security-audit/REPORT.md(No-Go,
Critical 0 / High 7 / Medium 8 / Low 5)代码层修复,mock
测试覆盖,真机动态验证一律未做、只列清单(见
docs/chv-production-readiness.md §11)。
High:
- H1 egress 代码门:代理地址校验、直连显式允许+审计、
每 VM 独立 tap/mac/ip 校验、net 字段白名单;宿主防火墙
列为部署清单,代码门+防火墙缺一不可。
- H2 网关 key 移出 argv:provisioned seed 盘客内文件
/etc/chv/guest-env(0600)投递,传输层密钥进 argv 直接
ValueError;keyscan 模式密钥投递 fail-closed。
- H3 任务盘删除:stop/recycle/cleanup 删 disk.raw(保留期
0)+ 残留盘 GC,删失败审计+脏标记。
- H4 默认值改 provisioned:keyscan 只作显式 opt-in。
- H5 seed.iso 生成即 0600;宿主私钥 seed 盘建好后即删;
崩溃残留扫描 cleanup_stale_secrets。
- H6 state_dir 默认出 /tmp(~/.local/share/.../chv-vms,
preflight 保 0700);api-socket 组/其它可写即 fail-fast。
- H7 tap 隔离校验:net.json 登记+stop 释放,共享即拒绝审计。
Medium:M1 shlex 远程转义;M2 清理失败即拒起(脏标记);
M3 配额默认 50GB + 快照数/总量/保留期上限;M4 SHA256 必填
+ BUILDINFO versions 实测记录(事前 lockfile 列清单);
M5 host key/ preflight/失败审计补齐;M6 reuse 须声明单租户
项目;M7 容量计数只认连通 socket;M8 sshd 加固进 build.sh
断言。Low:L1 链接不跟随;L2 路径白名单;L3 失败审计;
L4 双变量警告+字段白名单;L5 预热盘/任务盘对应关系定义。
旧测试:实验室默认值与生产默认值区分标注;行为已变的旧
测试按新语义更新(容量死 socket、快照白名单、磁盘路径
白名单、网关 argv、reuse 租户声明)。
测试:新 test_chv_secfix 39 项;旧 117 项 + 2 项新增断言 =
158 项;worker 相关 129 项;前端 vitest 9 项;cloud 全量
1588 项(skipped 4)。
2026-11-08 09:43:17 +00:00
host
31fdcc51e0
feat(console): CHV production-grade frontend — worker availability, attachment guard, queue hint, build:console fix, vitest
2026-11-08 09:43:17 +00:00
host
3cf1562176
feat(console): CHV executor option in dispatch/env selectors + experimental note in detail/list
...
- DispatchSection: add cloud-hypervisor option (labelled experimental,
default off); default stays docker; hint states a KVM-host CHV worker
must claim the task (otherwise it stays queued; attachments are
rejected by the backend at creation) and that the frontend only passes
the executor value through, never bypassing the backend allowlist.
- EnvSection: same option, because the backend env-create allowlist
(local/docker/cloud-hypervisor) does allow it; note states env
allowlist excludes cloud.
- TaskListSection: add cloud-hypervisor to the executor filter so CHV
tasks are findable; list rows already showed executor.
- TaskDetailPanel: pure display note for cloud-hypervisor tasks
(experimental, default off, no VM controls); detail already showed
executor from the task API.
- README: document the CHV console entry, experimental marking, and
verbatim backend-error display.
- Rebuilt cloud/console.html from src (tsc + vite single-file build);
no backend change: executor is already returned by _task_to_dict.
2026-11-08 09:41:42 +00:00
host
7320d693ba
feat: CHV 审核修复 P2(范围恢复为全做)
...
P2-1:preflight reuse/CPU/内存校验块小提取为
_preflight_config_checks(纯移动,深耦合处如实停)。
P2-2:build_vm_command 降级为私有 _build_vm_command;
Docker goal 内联解析顶部加正典分叉说明 + 同步检查清单。
P2-3:gaps grep 文本断言改成真实 Worker._run_attempt
行为断言。P2-4:README/build.sh 口径对齐(章节顺序、
BUILDINFO 名字列表、Node.js 不装写实)。P2-5:stop_vm
删除失败记审计。P2-6:CPU/内存校验统一进 preflight。
测试:原 84 + 新增 33 = 117 项,mock,无真 VM。
2026-11-08 09:40:32 +00:00
host
7703695bad
feat: CHV 审核修复(P0+P1,堆叠于 #230)
...
P0:seed 磁盘 CIDATA ISO 挂进 VmConfig 第二块只读盘;
restore provisioned 下复用钉死 known_hosts、缺失 fail-fast
绝不 keyscan;preflight 拦截 CHV_DISK_MODE=reuse(显式
实验二次确认 + 审计放行);SSH 目标选客机 IP 方案(显式
host > net 静态 ip > 显式转发宣称回环,三者皆无 fail-fast)。
P1:网关 extra_env 经 SSH env 前缀注入、worker 守卫收窄到
Local/CHV;取消/清理/看门狗接 CHV 通用路径;WarmPool
acquire 内 resume;容量门持久化计数;磁盘配额总量+余量
与已存在磁盘校验重拷;API 按 Content-Length 验完整性;
快照 file:// 验落盘再 shutdown;execute 死端口归类
vm_not_running。
P2 全部排除未做(用户范围收窄令,留待以后一轨)。
测试:原 84 + 新增 29 = 113 项,mock,无真 VM。
2026-11-08 09:40:32 +00:00
host
f8f2034265
feat: CHV gap fill — worker breakpoint wiring, pool reconcile, per-VM host keys, egress validation, guest build script
...
Stack: #216 -> #221 -> this. Worker breakpoint branch now calls any
executor providing goal_resume_breakpoint_task (Local keeps its
original path, gateway tasks still loud-fail); WarmPool
reconcile_orphans is called on CHV worker startup and close with
audit-on-failure; per-VM SSH host keys are provisioned before VMM
start via cloud-init NoCloud seed (keyscan kept only as weak
fallback, CHV_HOST_KEY_MODE=provisioned|keyscan); CHV_NET_JSON is
validated in preflight and explicit direct egress is audited;
chv-guest/build.sh is now real steps with --dry-run and fails fast
without /dev/kvm. Tests: new test_chv_gaps.py (18), cloud full
1514 OK (skipped=4). No real VM verification: no KVM host.
2026-11-08 09:40:09 +00:00
host
e2a70da5e1
feat: CHV 执行器优化(拆模块/去重复/SSH 钉死/池持久化/中途死亡分类)
...
- 拆模块:CHV 从 cloud/sandbox.py 巨类拆到 cloud/chv/(executor/
pool/config/api_client/ssh_transport/disk/errors),sandbox 只留
兼容 re-export,旧导入路径与新路径是同一对象
- 去重复:goal 解析、host 顶层参数、runner 超时抽成共享 helper,
Local 与 CHV 在矩阵输入下结论全等(Docker goal-resume 变体
有意保留内联版,见 PR 描述)
- 安全:SSH host key 按 VM 钉死(state_dir/<vm>/known_hosts,
ssh-keyscan 首次捕获 TOFU),废除 no + /dev/null;CHV_SSH_USER
空串与 CHV_SSH_PORT 越界直接拒绝,不静默 fallback
- execute 语义:只读已运行 VM,未运行报 vm_not_running,不为
status 起 VM
- 预热池:registry 落盘、重启载入只当孤儿、reconcile 清理、
损坏 quarantine;条目仍一次性,绝不复用脏 VM
- 长任务:VM 中途死亡判 interrupted(断点可续跑);中途心跳
经评估不做(无客内进度信号可采)
- #215 未合并:只列复用清单,不复制模块
测试:原 42 项 + 新 24 项全过;相关旧套件与 cloud 全量 1496 项
全过(skipped=4)。验证仍是 mock + 干跑 + 单元测试,未做真机、
压测、安全审计;堆叠于 #216 之上,base 为 feat-cloud-hypervisor。
2026-11-08 09:40:09 +00:00