host
7cba3c2b21
fix(chv-muse-r12fix3-2): worker socket 组权限 + allowed_uids 含 chv(P6 缺口 ②)
...
R12 复测 2 钉死:即使 worker active,chv 客户端也永远连不上
socket——worker root + 目录 /run/chv-gitea 0700 root + socket
0600 root + allowed_uids=(0,) 三处锁死;chv ping 一律 EACCES
(rc=2),root ping rc=0,privsep_worker_call 恒为 0,全部同步
走回落。
修法:三处配套改,只改一处仍锁死——
1. chv-gitea-worker.py:DEFAULT_ALLOWED_UIDS=(0, 1000)(root +
chv;round-11 authd 同款;环境变量
CHV_GITEA_WORKER_ALLOWED_UIDS 可覆盖);socket 用 group 权限
(目录 0750、socket 0660、组为第一个非 root 放行 uid 的主组,
_socket_group_gid/_set_group_perms 与 authd 同款实现;gid
解析不出时回落 root-only 0700/0600,绝不放给全员)。
拒绝 0666 探针口径。
2. build.sh tmpfiles.d:d /run/chv-gitea 改为 0750 root 1000,与
新方案一致。gid 写数字 1000 而不用组名 chv——tmpfiles-setup
跑在 07:23:24,chv 用户由 cloud-init 在 07:23:40 才建,组名
当时解析不出;1000 是 chv 的 uid/gid(seed users 块未指定
uid/gid,cloud-init 取首个空闲 1000;authd 同款假设)。
worker 启动时再按 passwd 重新推导 gid 并重设权限,tmpfiles
行只是开机存在性保证。审计日志仍 0600 root,不动。
3. 服务单元 ReadWritePaths 不动(/run/chv-gitea 仍在列,存在性
由 tmpfiles 保证)。
注意:单元内 agent 同样映射为 chv uid 1000,故也能走到 socket,
但只能走类型化协议——操作白名单、仓库 confinement、安全扫描三
处仍在,worker 不持凭证(见 worker 模块注释)。
测试:WorkerSocketGroupPermsTest 新增 7 项——默认白名单含
(0,1000)、环境变量覆盖、gid 可推导时 0750/0660 + 组正确、显式
socket_group 时同样组权限、只有 root 时回落 0700/0600、gid 推导
函数四档、tmpfiles 行 0750 root 1000;WorkerUnitTmpfilesTest 的
/run/chv-gitea 期望改 0750。P6/round12/P2/P4 四模块 205 项全过。
2026-11-08 09:48:16 +00:00
host
e31354dc58
fix(chv-muse-r12fix3-1): worker 开机时序竞态:Condition + path 触发,不赌重启预算(P6 缺口 ①)
...
R12 复测 2 钉死:剩下的 226 只点名 /home/chv/workspace——工作区由
cloud-final 的 chv-sync boot 克隆出来,晚于 multi-user.target 约
9 秒,worker 的 5 次启动预算在工作区出现前耗尽(5 台 VM 2 台
failed,手工 reset-failed + start 后立即 active,二进制无辜)。
修法三选一,选 (a)——让服务根本不在工作区出现前启动:
新单元 chv-gitea-worker.path(PathExists=/home/chv/workspace,
工作区一出现即触发启动)+ 服务加
ConditionPathExists=/home/chv/workspace(开机那次启动在命名空间
搭建之前干净跳过,不 226、不耗重启预算)。两者缺一不可:
Condition 本身绝不重试,没有 .path 它就是一次跳过、服务永远不
起;只有 .path 而无 Condition,开机那次启动仍会在命名空间搭建
时 226 撞上限速。WantedBy=multi-user.target 保留(is-enabled 仍
为 enabled),runcmd 只启动 .path 单元(cloud-final 时工作区尚
未 clone,直接 start 服务会 226);.path 进 buildinfo contents
与两处 lockfile 登记,P6 预检由三件扩为四件。
不用 (b) 放宽 StartLimit:放宽只是把竞态窗口拉大,wake 时间在
负载下已翻倍(R12 复测 2),预算仍可能耗尽,仍是时序赌博。
不用 (c) 把工作区创建提前到 tmpfiles-setup 之前:/home/chv 本身
07:23:40 才出现(cloud-init 建 chv 用户),晚于 tmpfiles-setup
(07:23:24);硬约束:绝不盲目补 tmpfiles 行。ExecStartPre 也不
行——命名空间搭建在它之前,救不了 226。
测试:WorkerUnitBootRaceTest 新增 8 项——Condition 在位、
StartLimit 未放宽(修法语义钉)、.path 触发配对(PathExists +
WantedBy、无 Unit= 覆盖)、服务 WantedBy 保留、build.sh 启用
.path + runcmd 只起 .path、绝无工作区 tmpfiles 行、buildinfo 与
lockfile 登记;BuildInfoContentsTest 的 P6 件加 .path;P2/P4 干
跑夹具一并拷入 .path。P6/P2/P4 三模块 174 项全过。
2026-11-08 09:45:48 +00:00
host
7c517f7fcc
fix(chv-muse-r12fix2-2): chv-sync 回落显性化:警告 + 每回落一行审计(P6-2)
...
R12 复测:worker 226 期间 chv-sync 全程静默走直接路径回落,pull/
push/status 表面 rc=0,privsep/safety 一行没跑——回落只有一句 stderr
警告,无事后可数的痕。本提交让一次回落留两处痕:stderr 警告保留
“worker 不在”标记(措辞加“未走 worker,privsep 未生效”,供驱动
识别)+ 追加一行 JSON 审计到
$USER_HOME/.chv-sync-fallback-audit.log(CHV_SYNC_FALLBACK_LOG 可改
位置;事件/动作/仓/时间戳,delegated_to_worker=false、
privsep_active=false)。审计写失败只记 stderr,绝不中断同步(与
worker _audit 同款口径)。gap 文档诚实边界第 4 条同步更新。
取舍:不改 fail-closed,仍是 fail-open。理由:旧镜像(无 worker)
须仍能同步,改 fail-closed 会把所有旧镜像的同步当场 brick,且无
镜像外恢复手段;本轮项 1 已让新镜像的 worker 开机即起,回落只在
worker 真挂 / 旧镜像时发生,不再是常态路径。旧镜像退役后改为无
worker 即 fail-closed(原定方向不变,见 chv-sync.sh 头注)。
测试:ChvSyncDelegationTest 新增——回落审计一行 JSON(字段全)、
两次回落两行、审计落盘失败不中断同步;走 worker 时不留回落审计
(反向对照)。
2026-11-08 06:01:54 +00:00
host
35d9c3ff3f
fix(chv-muse-r12fix2-1): tmpfiles.d 预建 worker 运行时路径(P6-1)
...
R12 复测钉死的根因:chv-gitea-worker.service 用 ProtectSystem=strict
+ ReadWritePaths=/home/chv/workspace /run/chv-gitea
/var/log/chv-gitea-worker.log,systemd 建 mount namespace 时要求每个
列出路径事先存在,否则 226/NAMESPACE crash-loop(NRestarts=12);
交付镜像里 /run/chv-gitea(/run 是 tmpfs)与
/var/log/chv-gitea-worker.log(worker 首次写审计才建)两处都不存在,
worker 从未起来过。
取舍:只用 tmpfiles.d(/etc/tmpfiles.d/chv.conf,加 d /run/chv-gitea
0700 与 f /var/log/chv-gitea-worker.log 0600,与 P4 的 /run/chv 同款
写法、同一文件)。ExecStartPre 不行——命名空间搭建在任何
ExecStartPre 之前,226 发生在它运行之前;改 ReadWritePaths 为已存在
目录(/var/log)会把写权限放大到整个目录。tmpfiles.d 由
systemd-tmpfiles-setup 在 sysinit 跑、早于 multi-user 的服务启动;
不新增进镜像的文件(chv.conf 本就是 build.sh 内联生成),lockfile
无需登记。unit 文件只加注释说明耦合,不改 ReadWritePaths 本身。
测试:WorkerUnitTmpfilesTest 钉住 ReadWritePaths 每一项挥发路径都有
对应的 tmpfiles 行(类型 + 模式)、P4 四行仍在、unit 无 ExecStartPre。
2026-11-08 06:00:58 +00:00
host
a18a530bfd
fix(chv-muse-r12fix-5): UsageLedger.record() 读-改-写原子化(P11)
...
R12 真机:4 线程 × 10 条记账 0 写错,但 verify_chain 返回
(False, first_bad=11),链 G、链 H 两次复现同一断点;根因是
record() 先 SELECT 链头、再算摘要、再 INSERT 提交,无锁无
事务,两线程读到同一 prev_hash 各写一条,链分叉。修法:
同一实例用 threading.Lock 串行化;SELECT 前 BEGIN IMMEDIATE
持库级写锁(WAL + busy_timeout 下等待而非立即失败),使另一
实例/进程读到的链头必是已提交最新值。record_warning 委托
record(),同款覆盖。新增并发测试:同款 4×10 复测两轮,
verify_chain 全真、40 条一条不丢(旧代码下该测试失败)。
2026-11-08 04:32:35 +00:00
host
0ebcdfb2a7
fix(chv-muse-r12fix-4): detect_checkout 接进 CDP broker(P10)
...
R12 真机:detect_checkout 在 chv-guest/、host.py、
executor.py 里零引用,结账页无任何拦截。按 P10 gap §4.1
接线:broker 加载 cloud/chv/checkout_detect.py(同目录
优先,仓库路径兜底;缺失时降级关闭检测、写警告,绝不
crash-loop);snapshot() 每次重算 verdict(aria 行拼伪节点,
与 _form_risk 同形),open() 导航前后两道门——落点是结账
页时返回 form_submit ask 并暂停,上一页是结账页时下一次
导航先审批;ask 批过后同 URL 不再重复 ask(批准即放行,
与 form_risk 同口径);verdict 进 snapshot()/status() 回包。
build.sh:checkout_detect.py 条件拷入 /usr/local/bin/(0644,
P3/P6 同款只警告口径,M4 不硬要求 cloud/),
extra_contents 与两处 lockfile 登记补齐。钱包三腿不在本轮
范围,未动。
2026-11-08 04:31:36 +00:00
host
1da0d86159
fix(chv-muse-r12fix-3): pull_memory_home 打包不再含顶层目录名(P7)
...
R12 真机:pull_memory_home 用 tar -czf - -C <父目录> <家目录名>
打包,解到镜像后文件落在 mirror/memory/MEMORY.md,而
MemoryFiles(mirror) 读的是 mirror/MEMORY.md——拉取与读取差
一层,host_pull_files=1 却报 memory file missing: MEMORY.md,
state-DB 备份与 host forget 同因失败。改为 -C <家目录> . 只打
包内容,MEMORY.md 直接落在镜像根;两处钉住的测试同步改形状
(旧测试本身钉的就是多一层的错误形状)。
2026-11-08 04:26:13 +00:00
host
33ca6c75ed
fix(chv-muse-r12fix-2): P6 worker 接进镜像(build.sh + BUILDINFO + lockfile)
...
R12 真机:chv-gitea-worker / chv-sync-worker-client /
privsep.py / safety.py / chv-gitea-worker.service 5 文件全不在
镜像内,build.sh 从未有 P6 拷入行,全链路无法跑。按 gap 文档
§2 接入说明落地:worker 三件硬校验 + 拷入 /usr/local/bin/
与 /etc/systemd/system/(mv 去后缀 + chmod +x + systemctl
enable);privsep/safety 叶子模块条件拷入
/usr/local/lib/chv-gitea/(与 P3 同款口径,缺失只警告);
叶子树 __init__ 用 stub(绝不拷真实 cloud/chv/__init__.py,
round-11 层 1 教训),stub 需 errors.py 故一并拷入;runcmd
在 chv-sync boot 前加 systemctl start chv-gitea-worker。
BUILDINFO contents 列入 worker 三件(无条件)与 privsep/
safety(条件,extra_contents);两处 lockfile 登记补齐 P6
五项,另补 P4 三件自 P4 起缺失的登记。
2026-11-08 04:25:33 +00:00
host
114b444554
fix(chv-muse-round12): 移植 round-11 的 Page.aria_snapshot() 纠正到 CDP broker
...
Playwright 1.64.1 没有 page.accessibility(Puppeteer 的 API),
broker 的 snapshot 调它必走异常分支。改调 Page.aria_snapshot()
(字符串);guard 的 truncate_a11y 换成字符串版 truncate_aria
(179a86d 原样),detect_injection/detect_form_risk 加字符串
分支(dict 分支保留);两边 fake 与 P4 文档同步改。a11y-only
契约不变:不读原始 DOM、不走 JS eval。
测试:test_chv_muse_p2 + test_chv_muse_p4 114 OK;全量 2523 OK
(skipped=10)。
2026-11-07 18:24:58 +00:00
host
9da74c2a78
merge(chv-muse-round12): 合入 round-11 修复轮 HEAD 50cae2a (RETEST6 全绿)
...
按 hunk 合入,不整文件覆盖。冲突 3 处:
- chv-guest/build.sh:取 P4 的 copy-in(cdp-broker/guard/blocklist/
chv-memory)+ cdp-broker service/enable 三件;取 R11 的 git
config(去掉 credential.helper store,层 5);tmpfiles 两边
并存(/run/chv/ask-queue + /run/chv-browser)。
- chv-guest/chv-browser.py:P4 架构保留(CDP broker 客户端 +
guard 模块);取 R11 两处仍适用的运行期修复:BROWSER_SOCK
移进 /run/chv-browser(缺陷 4,合入后的 broker 已指该路径)
与 handle_request 认 op=browser/action 透传;R11 的直连
Playwright 代码(validate_url/truncate_aria/_load_playwright/
_page snapshot)由 P4 取代,不带回。
- cloud/tests/test_chv_muse_p2.py:truncate 三测取 P4 的
GUARD.truncate_a11y(dict 树);FakeCdpBroker 取 P4 版,删
R11 的 FakePage 系列;干跑夹具取 R11 的 _fixture 调用,并
给 _fixture 补 P4 四件(否则合入后 build.sh fail-fast)。
合入内移植(R11 修复在 P4 里移了位置,不移植即静默丢失):
- chv-guest/chv-cdp-broker.py:_load_playwright 返回
sync_playwright()(原 R11 在 chv-browser.py 修过的同形
bug);回归测试由 test_p2 移植到 test_chv_muse_p4.py。
- test_chv_muse_p2.py:HOST 由模块级 eager 改懒加载(_host()):
host.py 顶层 import queue 会把 stdlib queue 缓进 sys.modules,
使同进程后加载的 test_queue_sandbox 取不到 cloud/queue.py
遮蔽而 ImportError(全量唯一失败)。
未移植(见报告):R11 的 Page.aria_snapshot() 纠正未进
chv-cdp-broker.py(仍调 accessibility.snapshot(),且 guard
的 dict 树 API 须配套改,属 P4 返工,不在本轮合入做)。
全量 cloud 套件:2522 tests OK (skipped=10),基线 a6f9597
为 2474 OK (skipped=12);+48 来自 R11 新增测试(p2 +36、
p3 +7、closeup +3、gaps +1、p4 +1 移植)。
2026-11-07 18:13:31 +00:00
host
50cae2a0af
part 6 修复:worktree 根移出 /app——RETEST5 挂载点回归
...
RETEST5:part 5 的 --bind=<workspace>/.chv-worktrees:/app/work
(adc7bf6,排在 --bind-ro=/app 之后)让所有 cell 启动失败:
后挂的 bind 只有在挂载点已存在时才能盖住,挂载点不存在时
nspawn 在只读 /app 下连建都建不起来(Failed to create mount
point .../app/work: Read-only file system,全量 73 次,
CELL-RC=0 共 0 次),缺陷 1 的 15/15 回退为 0/15。
三选一取 (a) worktree 根移出 /app:
- chv-cell 不再发任何指向 /app 之下的 bind,删
--bind=...:/app/work 与 worktrees_dir 参数;WORKTREE_DIR
(/home/chv/workspace/.chv-worktrees)改经
--setenv=CHV_WORKTREE_ROOT 传进单元——该路径在已可写绑进
单元的 workspace 之下,挂载点问题按构造即不存在;backing
仍在客机 workspace 下随磁盘持久化,隔离与落盘语义不变,
只是单元内路径从 /app/work/host-worktrees 改为
/home/chv/workspace/.chv-worktrees/host-worktrees。
- host.py 新增 worktree_base():CHV_WORKTREE_ROOT 优先;
CHV_CELL=1 但变量未设时回落到同一单元内路径(旧版 chv-cell
/ 单元内手动跑 host.py 仍不出 /app);单元外沿用
HERE/work/host-worktrees,行为不变。make_worktree 与
dispatch_from_branch(第二个 HERE/work 调用方)同走该函数,
goal/fork/依赖链一并修到。
- 不选 (b) 默认 --no-worktree:隔离丢了,且 goal/fork 同样
调 make_worktree,照样撞 Errno 30;不选 (c) 镜像预建空
目录 /app/work:修法耦合镜像构建,某次重建漏建即静默回归,
且单测无法钉住镜像内容。
- 根因 1(39084ce)与根因 3(0203f32)代码未动。
单测:删 part 5 钉 argv 顺序的 4 项(该顺序本身已被真机证伪),
新增 CellPart6WorktreeTest 4 项 + HostWorktreeBaseTest 5 项:
argv 里无任何指向 /app 之下的 bind、CHV_WORKTREE_ROOT 经
setenv 进单元、worktree 根只经可写 workspace 绑定可达、
两处同值常量一致、worktree_base 三路选择、make_worktree
真 git worktree 落点、dispatch_from_branch 同根。
全量:cloud/ 下 discover -s tests,2067 项 OK(skipped=9)。
(注:仓库根跑 discover 会把 queue 解析成标准库、致
test_queue_sandbox 导入失败,须在 cloud/ 下跑。)
2026-11-07 14:23:48 +00:00
host
0203f32627
part 5 修复 3:P2-9 degraded_logged=False——降级日志文案漂移
...
定位结论(已定位,不是时序、不是日志路径变化):part 4 提交
7a22732 把 serve() 从 peer_allowed 切到 peer_allowed_multi 时,
降级分支的 reason 与警告行都被改写成了“无 cell pid 文件”,
“cell.pid 缺失”这个串自此再也没进过 journal——P2-9 驱动
grep 'cell.pid 缺失' 自然命中不了,RETEST4 的
degraded_logged=False 即由此来。RETEST3 同项为 True,是因为
当时跑的还是 part 4 之前的 broker(serve 直接打印含该串的
警告行)。降级 ping 本身一直 ok=True,降级逻辑没坏,坏的是
日志里的认领字符串。
修复:peer_allowed_multi 无 pid 文件时的 reason 改回与单 cell
版 peer_allowed 完全一致的“uid 在范围内(cell.pid 缺失,未做
pid ns 对照)”;serve() 的警告行改走新 helper
_degraded_warning(reason, pid, uid),把 reason 原样打进日志
(不再手写第二份文案,避免两者再次悄悄漂移;今后改文案只改
reason 一处)。journalctl grep 'cell.pid 缺失' 恢复命中。
新测试 cloud/tests/test_chv_muse_p2.py::BrokerMultiTest(2 项):
reason 含“cell.pid 缺失”、警告行含该串且带 pid/uid。
2026-11-07 12:07:32 +00:00
host
adc7bf6666
part 5 修复 2:默认 dispatch 在只读 /app 下建不了 worktree——workspace 绑定 /app/work
...
RETEST4 新发现 2:make_worktree 把 worktree 建在 HERE/work/
host-worktrees,单元内 HERE=/app 而 /app 是 --bind-ro,带 repo
的默认 dispatch 撞 OSError Errno 30(--no-worktree 的同任务
越过此关、跑到真实 turn)。
二选一取 (a) 给 worktree 一条单元内可写路径:客机 workspace
下的 .chv-worktrees 以可写 --bind 挂到单元内 /app/work 上
(build_nspawn_argv 新增 worktrees_dir 参数,默认
WORKTREE_DIR=/home/chv/workspace/.chv-worktrees;run_cell 起
单元前 _ensure_bind_source 建好该目录并 chown 回 chv)。
取舍:
- 不选 (b) 执行器默认 dispatch 带 --no-worktree:worktree
隔离就丢了——任务改动直接落进 repo 本身,多任务同仓互撞,
merge/discard/seed-dir 语义全坏;且只修 dispatch,goal/fork
同样调 make_worktree,照样撞 Errno 30。
- (a) 内不选可写 tmpfs:tmpfs 随单元退出即丢 worktree,跨
cell 的 run/merge 续跑找不着工作区;workspace 绑定随客机
磁盘持久化,worktree 语义、隔离与落盘位置(仍是
/app/work/host-worktrees/<任务>)全都不变,也不碰 P2 的
/usr 只读约束。
- bind 必须排在 --bind-ro=/app 之后(nspawn 按顺序挂载,后挂
的才盖住只读子树下的子路径),单测钉住该顺序。
未决(须 RETEST5 真机验证):nspawn 对 --bind 目的路径的
处理(目的不存在时是否自动建挂载点)与挂载叠加顺序只能在
真机上验证,单测只能钉住 argv 形状;本轮不建镜像、不跑真机。
新测试 cloud/tests/test_chv_muse_p2.py::CellPart5WorktreeTest
(4 项):可写 bind 在位且在 workspace 下、顺序在
--bind-ro=/app 之后、自定义目录参数生效。
2026-11-07 12:07:01 +00:00
host
f20cbc79cd
part 4 附带:vm.boot/vm.create 500 记响应体
...
_boot_vm 只留 status 导致间歇 500 根因无法定位(两轮已提,
未改)。_api_call 的两个调用点现在都把响应体(截断到 500
字符单行)放进 ChvFailure 消息:vm_create_failed 与
vm_boot_failed 均含 status 与 body。body 是 VMM 的报错文本,
不含秘密;超长截断并标明。
新测试:test_wake_vm_boot_failed_records_body、
test_wake_vm_create_failed_records_body、
test_wake_vm_boot_failed_body_truncated。
2026-11-07 10:30:45 +00:00
host
7a227323f2
part 4 缺陷 3:并发 cell 撞毁——唯一身份 + run_cell 接线
...
RETEST3 缺陷 3:固定 ve-chv-cell 名 + 固定 10.200.0.1/24,
第二个 cell 在 nspawn 建 veth 时即 File exists/Address
already assigned。
- CellNet + allocate_cell_net():每次 run_cell 在 flock 锁下
(/run/chv/.cell-alloc.lock,30 秒超时)分配唯一身份:
machine chv-cell-<xx>(11 字符)、宿主 ve-chv-cell-<xx>
(14 字符,接口名 15 字符上限内)、10.200.<xx>.0/24;
扫描活接口 + 地址 + machinectl 在册名,避让注销滞后的下标。
- 配网命令表(host/cell/cleanup)与 build_nspawn_argv 接受
net/cell_net 参数;None 时仍用旧常量(argv 子命令与旧测试)。
- run_cell 重写:分配身份 -> 生成专属文件 -> 起步门 payload
-> 等 veth(20 秒)-> 宿主配网 -> 轮询 init pid(10 秒)
-> 写 pid 文件 -> 单元内配网 -> 开门 -> 等退出码;
nspawn 已死返回其退出码;finally 清 NAT/pid/专属文件。
共享网络模式跳过门与身份(无配网可等)。
- broker:pid ns 对照改多 cell 版(peer_allowed_multi +
_read_cell_pids:cell-<machine>.pid glob + 兼容旧 cell.pid;
对端 ns 与任一活单元同 ns 即放行;残留 pid 文件只跳过,
全部读不到才拒绝,不降级)。
新测试:CellAllocTest、CellPart4NetworkTest、
CellPart4ArgvTest(cell_net 两法)、BrokerMultiTest。
2026-11-07 10:30:30 +00:00
host
2be69af92c
part 4 缺陷 2:volatile 空根缺 /app 与 /etc 关键文件
...
RETEST3 缺陷 2:--volatile=yes 下单元根是基本空的 tmpfs,
/app、/etc/resolv.conf、/etc/hosts、/etc/ssl/certs 全无,
执行器单元路径一律 ENOENT、DNS/TLS 不可用。
- build_nspawn_argv:固定只读绑 --bind-ro=/app 与
--bind-ro=/etc/ssl/certs;新增 extra_ro_binds 参数
(单元专属 resolv.conf/hosts 由 run_cell 传进来)。
- prepare_cell_files():按客机有效 DNS 生成单元专属
resolv.conf/hosts(/run/chv/resolv.conf.<machine>、
hosts.<machine>,0644——单元 root 映射为客机 uid 1000,
0600 的 root 文件单元内读不到;DNS/hosts 不含秘密)。
客机 resolv.conf 可能是 systemd-resolved stub
(127.0.0.53),单元内无 resolved,直接绑 stub 即 DNS
全灭,故过滤 stub 后备选 /run/systemd/resolve/resolv.conf,
两处都没有即大声失败。nsswitch.conf 故意不绑(客机版
可能含 resolve 模块;glibc 默认 files+dns 正是单元需要的)。
新测试:CellFilesTest、CellPart4ArgvTest(绑定两法)。
run_cell 接线在缺陷 3 的重写里做。
2026-11-07 10:29:31 +00:00
host
fc33eed262
part 4 缺陷 1:cell 启动竞态——起步门 + init pid 轮询
...
RETEST3 缺陷 1:run_cell 里配网与 payload 零同步,快 payload
(run -- true)在配网完成前退出即撞墙,11 次只成 6 次。
本提交先落 helper(接线在缺陷 3 的 run_cell 重写里做):
- gate_wrapper_command():payload 包一层 sh 起步门,等
/run/chv/.cell-gate-<machine> 出现再 exec(绝对路径
/usr/bin/sh:volatile 单元根里 /bin 未必有)。
- find_cell_init_pid() 改带超时轮询(timeout 默认 0.0 = 单次,
旧调用行为不变;缺目录不再直接回 None;proc_alive 回调让
nspawn 已死时立刻回,不空等)。
新测试:CellGateTest、CellInitPidPollTest(5 个)。
2026-11-07 10:29:13 +00:00
host
581e850eb7
fix(chv-muse-r11fix): cell 只遮 /usr 下路径(复测新发现 1)
...
--volatile=yes 下容器根是基本空的 tmpfs(只挂进只读 /usr),
nspawn 按容器根解析 --inaccessible 路径,/etc/chv 与
/home/chv/.git-credentials 在容器根里根本不存在,解析失败即
Failed to resolve 而起不来;两条 /usr 旗可解析,保留。
凭证文件按构造即不可达(容器根里无 /home、无 /etc/chv),
遮蔽不再是必须项,安全属性不变。
探针证据:celldiag2/3/4——去 inaccessible 后完整 argv 0.4s/rc=0,
单元内 $HOME/.cache 可写,单元内 ls /etc/chv 本来就不存在。
2026-11-07 07:02:37 +00:00
host
04287f6053
fix(chv-muse-r11fix): chv-browser 补 sync_playwright 调用括号 + 接受 broker 的 browser op(复测新发现)
...
复测(RETEST.md §browser-defect、§broker-proto):
1. _load_playwright 返回裸 sync_playwright 函数(未调用),
_ensure_browser 对它调 __enter__ 即 AttributeError,open
永远失败。改返回 sync_playwright()(调用后的上下文管理器),
与单测假工厂的形状一致。回归测试用 stub 的 playwright 模块
钉住“返回调用结果、不是函数本身”。
2. broker 按设计原样转发 {op: browser, …},chv-browser 白名单
却不认 browser。在 chv-browser 的 handle_request 里归一化:
内层 op 在 action 里;无 action 但带 url 时默认 open(驱动
只发 url);action 同样受 FORBIDDEN_OPS 约束。broker 保持
原样转发不动(其 docstring 与单测均以此为契约)。
附:本提交含 test_chv_muse_p2.py 里 CellArgvTest 的配套更新
(c1d00b3 的 --volatile=yes 断言,同文件无法拆分提交)。
2026-11-07 05:24:42 +00:00
host
4a7ca25334
fix(chv-muse-r11fix): browser.sock 移进 chv-browser 自有目录(缺陷 4)+ vsock 自动启动
...
缺陷 4:/run/chv 是 0755 root root,chv-browser 在 bind 时
EACCES 而无限 crash loop(restart 21)。browser.sock 从
/run/chv/browser.sock 移到 /run/chv-browser/browser.sock
(broker 与 browser 两端常量同改);build.sh 建目录 + tmpfiles
登记(0755 chv-browser 所有)。不用组可写 /run/chv——那会给
chv-browser 对 broker.sock/cell.pid 的 unlink 能力。
vsock 自动启动:此前 build.sh 只拷 vsock_notify.py、不建服务,
vsock 通道从未自动启动。按 vsock_notify.py 的 docstring 补
vsock-notify.service(ExecStart=/usr/local/bin/vsock-notify %H,
Restart=no,After/WantedBy=multi-user.target)并 enable;
printf 格式串里 %H 写 %%H。测试:干跑针 /run/chv-browser;
vsock 在场时干跑含服务与 enable 语句。
2026-11-07 04:01:24 +00:00
host
f093558c0d
fix(chv-muse-r11fix): authd 层 5 去掉 store helper,chv-sync 回落改 fail-closed
...
round-11 真机测试证实:镜像 /etc/gitconfig 的 [credential]
helper = store 把 authd 释放的长效 token 写进了客内
/home/chv/.git-credentials(0600)。改动:build.sh 不再设
store helper;chv-sync boot 在 authd socket/helper 缺失时直接
die,不再把 token 写进 .git-credentials(旧落盘回落废止);
authd helper 是唯一凭证 helper,且自身绝不落盘。旧镜像上 boot
现在会直接失败,须用含 authd 的新镜像。测试:无 authd 时 boot
失败且 .git-credentials 不产生、干跑不再含 store helper;P3
差距表 §3.5 更新为已关闭。
2026-11-07 04:00:04 +00:00
host
9f593d62ef
fix(chv-muse-r11fix): authd 层 3 socket 用 group 权限、层 4 裸 .git 当 pull
...
层 3:AuthdServer 不再 0700/0600 一刀切。socket 共享组取显式
socket_group 或第一个非 root 放行 uid 的主组(build_server 透
传;生产默认 allowed_uids=(0,1000) 派生 chv 主组),目录 0750
+ socket 0660 + chgrp;解析不出(uid 无 passwd 条目)回落
root-only,绝不放 0666(探针 fixprobe8 用的 0666 不上生产)。
层 4:_operation_for_path 加裸 .git → GET/pull;Sentinel
gitea 规则加 (GET, suffix, .git),POST 裸 .git 仍拒。语义已定:
裸 .git 一律当 pull(只读默认),push 只走显式 git-receive-pack。
测试:Sentinel 允许 GET/拒绝 POST 裸 .git、helper 端到端裸路径
取凭证、组 gid 派生与回落、显式组落地 0750/0660。
2026-11-07 03:58:45 +00:00
host
2d12179b9a
fix(chv-muse-r11fix): authd 层 1 叶子树补 errors.py + stub __init__、层 2 seed 补三键
...
层 1:真实的 cloud/chv/__init__.py import executor/orphans,拷进
authd 最小叶子树(/usr/local/lib/chv-authd)会让 chv-authd 在
import 时 ModuleNotFoundError 而 crash loop——先是 errors.py
缺失,补上后又在 executor 上失败(探针 fixprobe3)。新增
chv-guest/authd_init_stub.py(仅导出 ChvFailure),build.sh 拷
errors.py + stub 作叶子树的 __init__.py,不再拷真实包 __init__;
P3_LIBS_PRESENT 条件加 errors.py;EXTRA_CONTENTS 加 errors.py 与
__init__.py;两 lockfile 脚本的 DECLARED_SOURCES 同款登记。
层 2:_seed_env_entries 把 guest-env 里的
GITEA_URL/GITEA_USER/SYNC_REPO 抄进 authd-seed(build_server
要求四键齐全,只 GITEA_TOKEN 即 ValueError);没有不补、不编
默认值。测试:seed 三键落盘/缺键不补、干跑夹具含新文件、lockfile
合成清单含新两项。
2026-11-07 03:56:24 +00:00
host
b41fb67026
fix(chv-muse-r11fix): 执行器以 sudo 调 chv-cell(缺陷 1)
...
chv-cell 须 root(nspawn + 配网),执行器经 SSH 以 chv 身份调,
此前无 sudo 即 rc=2。改 _guest_host_command 在单元开时前缀 sudo
(探针 p2.log 的手动调用即 sudo chv-cell run;chv 的 NOPASSWD
sudo 来自 seed users 块)。关时原命令不变。
2026-11-07 03:52:34 +00:00
host
e02828c590
fix(chv-muse-r11fix): nspawn 255 拒裸 --no-new-privileges 与 --directory=/(缺陷 2)
...
systemd 255 把裸 --no-new-privileges 当作带必填参数的选项,吞掉
下一个参数后报错(p2.log 实测);--directory=/ 也被拒,须
--ephemeral 或 --volatile。改 --no-new-privileges=yes,
--directory=/ 后加 --ephemeral:根快照 + overlay,单元内除 bind
出去的目录外一律可写、用完即弃,与 P2 共享客机 rootfs 设计一致;
--volatile 会把根置只读,codex 写 $HOME 下非 bind 路径会失败。
测试:CellArgvTest 断言新值、裸值不再出现。
2026-11-07 03:52:34 +00:00
host
d324d87529
fix(chv-muse-round11): lockfile DECLARED_SOURCES 补 P3/vsock 六项
...
717efc4 镜像真机实测:BUILDINFO.contents 含 chv-authd 三件套、
cloud/chv/authd.py、cloud/chv/sentinel.py、vsock_notify,但两
脚本 DECLARED_SOURCES 没有它们——generate 记 6 项 unresolved,
verify 与 check 双双失败(contents 未覆盖)。V-9 的 912edef
没暴露:它的 contents 里根本没有这 6 项。
与 9f929b1 的 P2 三件套同款修法:六项皆仓库内脚本,版本随
repo_commit。合成 BUILDINFO 清单扩到与 717efc4 真实 contents
一致(另补 systemd-container 进 dpkg 假值),反向对照已验:
只撤修复时 LockfileTest 4 测里 2 测失败。
附带教训:经 ssh->wsl.exe 的命令内层退出码一律被吞成 0
(python3 -c 'sys.exit(1)' 回显 RC=0),此前三项验证只看
RC 会把失败判成通过;此后一律以输出文本为准绳(须见
'lockfile 校验通过' 行且无 unresolved 警告)。
2026-11-07 01:08:28 +00:00
host
5d5041bb7c
round-12: merge round-11 head 717efc4 (V-9 real-machine fixes)
...
Round-11 moved on Gitea after round-12 branched (29d3a5a -> 717efc4 ):
V-9 guest-env fixes must be in any image built from this branch, or
the round-12 image would ship the known defects V-9 found (guest-env
never created when owner=chv:chv; wake reporting ready ~30s before
the runcmd chown lands). Contents, all from 717efc4 :
- build.sh: runcmd chowns /etc/chv/guest-env to chv:chv after
'start chv-authd', before 'chv-sync boot'
- check/generate_lockfile.py: DECLARED_SOURCES gains P2 trio
(chv-cell/broker/browser -> repo_commit)
- executor._wait_guest_env_usable: with secrets delivered, wait for
guest-env readable by the SSH user before reporting ready; timeout
stops the VM and raises guest_env_not_ready; called from _boot_vm
- hostkeys.py: V-9 root-cause comment (owner always root:root)
- test_chv_gitea_sync.py: 5 new tests
Conflict: build.sh runcmd line only. Resolved as union: 717efc4's
runcmd line (with chown) kept; HEAD's P4 trio + P7 chv-memory
copy-in lines (absent on the 717efc4 side) kept. executor.py
merged cleanly.
2026-11-07 01:05:51 +00:00
host
414e245752
round-12: ruff hygiene on migration code (import sort, narrow store except)
...
- test_chv_muse_round12.py: drop unused socket/time imports, drop
unnecessary sys.path.insert (P3 pattern needs none), sort method-local
imports (activity/capabilities, approval_card/channel/sentinel)
- audit_trail.py: single-line method-local imports (I001)
- swarm.py / presentation.py / browser_tasks.py: store-path fail-safe
except narrowed from bare Exception to (sqlite3.Error, OSError)
(DB/file failures only); transport spawn/ping/close handlers in
browser_tasks.py deliberately stay bare Exception (arbitrary
transport errors must map to failed/False/close_error)
- NOT fixed (pre-existing style, left as-is): UP031 % formatting
(used throughout the codebase incl. the copied lines), BLE001/
TRY004 in untouched code, F401 atomic_write + RUF059 swarm
(P7/P8 pre-existing)
2026-11-07 00:57:05 +00:00
host
717efc4688
feat(chv-muse-round11): 移植 V-9 真机修复(9f929b1/912edef/9fb0f4b)
...
- lockfile 两脚本 DECLARED_SOURCES 加 P2 三件套 chv-cell/broker/
browser -> repo_commit(9f929b1)。
- build.sh 99-chv-sync.cfg runcmd 在 chv-sync boot 之前加 chown
行:guest-env 由 write_files 以 root:root 写(建用户之前),
须在 final 阶段改归 chv(912edef;本分支 runcmd 多一行
start chv-authd,chown 插在它之后、boot 之前)。
- executor._wait_guest_env_usable:密钥已投递时等客内 guest-env
对 SSH 用户可读再报 ready,超时关 VM 抛 guest_env_not_ready
(9fb0f4b;runcmd chown 比 SSH 就绪晚约 30 秒)。
- hostkeys.py:本分支 _guest_env_entry 本来就写死 owner
root:root(P3 重构时已无 ssh_user 分支),912edef 的
hostkeys 改动无内容可移,只补 V-9 根因注释防回退。
- 测试(5 个新测试,8 个运行):owner 恒 root:root、build.sh
chown 位置、chv 用户下 wake 后 owner 仍 root、等到可读、
永不可读抛 guest_env_not_ready。
全量 cloud 套件 2019 OK(skipped=8)。
2026-11-07 00:48:25 +00:00
host
da8d0c29fd
round-12: fix integration fallout (P9 gate x P1, P7 check x P2/P4 fixtures)
...
- P1 resident tests: P9's inference gate is a precondition of
_run_with_vm, so _RealExecCase.make_executor now configures a
default inference origin (CHV_INFERENCE_ORIGIN=https://xgapi.lol
+ CHV_INFERENCE_ALLOW_HOSTS=xgapi.lol) and a public fake resolver
(same setup as P9's GateTest). No assertion changed; the gate's
fail-closed behavior on missing origin stays pinned by P9's own
ask test. 9 resident tests fixed (7 errors + 2 failures).
- P2/P4 dry-run fixtures: P7's build.sh hard check requires
chv-memory.py in the repo; add it to both fixtures' copy lists.
2 failures fixed.
- No production code changed in this commit (test setup only).
2026-11-07 00:43:50 +00:00
host
d4cef29cdb
round-12: migrate P8 registries + P12 audit to AppStateStore
...
- app_state.py: host_state_db_path() (host-level DB, distinct from
per-VM state_db_path); kv_get/kv_put/kv_delete on meta (namespaced
keys; kv_put skips the no-secrets guard by design — registry docs
hold user prompts, documented); audit_trail table (P12 record
shape + hash chain, seq explicit); counts()/backup() gain
audit_trail.
- swarm.py / presentation.py / browser_tasks.py: JSON-file backends
replaced by KV rows (p8-swarm / p8-ledger / p8-browser-tasks);
legacy JSON imported once on first load (renamed .migrated);
corrupt row / unreadable store returns empty (fail-safe, same
semantics as before; next successful save self-heals).
- audit_trail.py: StoreAuditTrail (same record shape, hash chain,
filters, export as JSONL version, backed by audit_trail table);
migrate_jsonl_to_store() moves a chain verbatim (broken chain
refused, divergent seq refused, re-run idempotent). JSONL class
kept for reading old files.
- P12 dict contracts now run against real P3/P5 code
(ApprovalQueue.record -> build_approval_card ->
card_matches_channel; CapabilityIssuer.issue -> describe ->
PermissionRegistry.record_grant).
- P6->P3 local protocol test: real PrivsepClient + real worker
server + real git status; worker git argv carries the real P3
helper + useHttpPath; no token in argv/env/audit. runuser + HTTP
pull stay real-machine-only (see gap docs).
- Gap docs updated: P8 migration done, guest-side browser follow-up
explicitly left for the real-machine track (no task_id in the
browser protocol yet; lifecycle needs a real VM to verify);
P6 wiring + P12 migration marked done; production-readiness.md
gains §20 (round-12 integration).
- Tests: new cloud/tests/test_chv_muse_round12.py, 24/24 OK;
test_chv_muse_p8.py ledger corrupt test rewritten for the KV
backend (+ legacy-import test). P7+P8: 95+1 tests OK.
2026-11-07 00:36:25 +00:00
host
466cf7eae7
merge(chv-muse-round12): 合入 P12 审计轨迹与活动视图 ( 9759be4)
2026-11-07 00:10:34 +00:00
host
77743e734d
merge(chv-muse-round12): 合入 P11 用量计量与配额 ( 60c371d)
...
- 冲突仅一处:docs/chv-production-readiness.md §15 撞号——
P11 节顺延为 §19(§15 P2 / §16 P4 / §17 P6 / §18 P7
保持不动),节内无自引 §15,无内容改动。
- P11 未决冲突原样保留(见 docs/chv-muse-p11-gap.md §5):
档位门只做准入、USD 路径不动,等待用户裁决,不悄悄统一。
- 测试:test_usage_quota 22/22 OK。
2026-11-07 00:10:32 +00:00
host
b55b49b358
feat(chv): 对齐 Muse P10 支付安全——凭证隔离 + 结账检测 + 每次购买人工审批 + 一次性卡号
...
- 支付凭证隔离:PaymentCredentialVault(只活内存、白名单
stripe-link/shop-pay、只存不透明 id + 掩码标签、原始卡号
PAN 拒绝入库、按次释放绑定商家/金额/货币、单次 + TTL)
- 结账页检测:detect_checkout(URL + 无障碍树信号,确定性
规则、不读原始 DOM、与 P4 detect_form_risk 同输入形状)
- 每次购买人工审批:PaymentGate 经 P5 对话外通道发审批,
payload 含确切购买详情;完成时先验签、再验详情摘要
(篡改即拒且审批保持待处理)、最后单次消费答复
- 一次性卡号:OneTimeCard 绑定商家/金额/货币/有效期,单次
兑现;SimulatedWalletBackend 沙箱钱包(假 PAN 只在后端
私有内存、charge 只记账不联网、取消即 void)
- 限额:SpendLimits 三档 minor units 比对,限额不可用时
不编造上限(limits_checked=False)
- 审计:PaymentAudit 只留允许字段,秘密字段名丢弃 + redacted
- 审批通道最小扩展:ApprovalRequest 增加可选 details 字段,
不传时 payload 与 P5 完全一致
- 真实支付与扣款不做:全部沙箱验证,真实钱包集成待用户
另行批准;新测试 79 项,全量 cloud 套件 2037 OK
round-12 集成说明:本提交为 acf98f8 的 cherry-pick(只含 P10
自有 diff,基线 25bcd35 已含的 P3/P5 内容未重复合入;
approval_channel.py 仅加可选 details 字段)。
2026-11-07 00:09:55 +00:00
host
90c42f6e1d
Merge feat-chv-muse-p9: inference/telemetry restricted channel
...
- executor.py: P9 _inference_gate inserted before P1 dispatcher
_run_with_vm; gate call is the first statement, so deny/ask
fail-closed before any resident resume or cold wake. P9's own
_run_with_vm (old-body variant) dropped: its body is byte-identical
to P1 _run_cold (verbatim move), kept once in _run_cold.
- sentinel.py: P9 superset version wins (P5 base + inference entries
POST /v1/responses, GET /v1/models + comments).
- inference_channel.py / telemetry.py / host.py: P9 as-is.
- Tests: P9 51 + closeup/gaps/optimize/cloud_hypervisor/fix 272 OK.
- mypy on changed files: P9's 5 cross-track errors gone (P5
capabilities.py now in tree); remaining 4 are 06c3e17 baseline
legacy (marker_tools.py:142, executor.py:1573/1578), untouched.
2026-11-07 00:09:26 +00:00
host
240949e444
merge(chv-muse-round12): 合入 P8 后台工作 ( 8d4771b)
2026-11-07 00:03:00 +00:00
host
320cd36921
merge(chv-muse-round12): 合入 P7 状态与记忆分离 ( 29fa0c8)
...
冲突按并集解:build.sh 保留 P2+P3+P4 检查/拷入 + P7 的
chv-memory 检查/拷入(P7 的重复 runcmd 行删掉——同一文件
写两次会盖掉 authd 启动行);buildinfo.py 加 chv-memory 一项;
production-readiness.md P7 一节顺延为 §18。P7 测试 46 项全过。
2026-11-07 00:02:54 +00:00
host
b0b9f5ed9d
merge(chv-muse-round12): 合入 P6 privsep worker + 确定性安全检查层 ( 81e4eaf)
...
唯一冲突是文档 §15 撞号:P6 一节顺延为 §17,基线说明更新
(P3 已在树里,接线走真实代码)。chv-sync.sh 自动合入正确:
P6 的 worker 路径与 P3 的 authd 路径(useHttpPath)都在。
P6 测试 43 项全过(skipped=1 是 root 下 uid 否定测试)。
2026-11-07 00:02:22 +00:00
host
d1c9a8e647
merge(chv-muse-round12): 合入 P5 Sentinel 纵深 ( 25bcd35)
2026-11-07 00:01:39 +00:00
host
c24cc0ba92
merge(chv-muse-round12): 合入 P4 浏览器完全对齐 ( 1c8fc3f)
...
冲突按并集解:build.sh 保留 P3 authd 检查/拷入/runcmd(含
start chv-authd)+ P4 三件套检查/拷入(P4 的重复 runcmd 行
删掉——同一文件写两次会盖掉 authd 启动行)+ P4 的
cdp-broker.service/tmpfiles(含 ask-queue)+ P3 叶子模块条件
拷入;buildinfo.py 两边内容项并集;chv-browser.py 取 P4 重构
版(broker 客户端);production-readiness.md P4 的 §15 顺延为
§16。P2 的 BrowserTest 改走假 CDP broker(断言不变),两路
干跑夹具补齐并集文件集。
2026-11-07 00:01:35 +00:00
chv
29d3a5a474
feat(chv-muse-round11): build.sh 补 P3 authd 进镜像 + gt 脚本哈希轮换
...
- authd 三件套 copy-in(chv-guest/authd.py 与 git-credential-chv-authd
-> /usr/local/bin/ 并 chmod +x,chv-authd.service ->
/etc/systemd/system/),云端叶子模块 cloud/chv/authd.py 与
sentinel.py + 两个 __init__.py -> /usr/local/lib/chv-authd/,
systemctl enable chv-authd;99-chv-sync.cfg runcmd 在 chv-sync
boot 之前加 systemctl start chv-authd;缺件即 fail-fast
- buildinfo BASE_CONTENTS 登记新增件;P2 干跑夹具补 P3 文件并断言
authd 步骤出现在干跑输出里
- GT_INSTALL_SH_SHA256 cf82... -> 49ffe090...:上游 2026-11-07
06:44 轮换,V-9 已核实(WSL fresh curl 与失败镜像内残留逐字节
一致;新脚本全文已读,只从 dl.gitea.com 取 1.0.0 二进制并验 hash)
- vsock_notify 条件拷入在合入后生效(cloud/chv/guest/vsock_notify.py
已在仓里,干跑不再报缺失警告)
- 定向单测 P1/P2/P3/chv_fix 172 项全过;全量套件仍在跑
2026-11-06 23:08:40 +00:00
host
c06ba50983
feat-chv-muse-p9: 推理与遥测受限通道(Sentinel 预审 + 遥测最小化 + 训练退出开关)
...
- 受限推理通道:cloud/chv/inference_channel.py(origin 解析、
allowlist、上限、Sentinel 预审),执行器 _run_with_vm 起 VM 前
必过 _inference_gate(allow 才继续,deny/ask 审计 + fail-closed,
任务级 extra_env 合并进预审);host.py 第二道防线(_server_command
的 origin 结构校验 + Server.request 超时/重试走 env)。
origin 规则:https 公网网关(只 443);http 只接受本地中继
(字面环回/私网 IP,如 http://172.17.0.1:28084,端口保留 ,
无 DNS、无重绑定,allowlist 与单次能力照常);未知 provider
标签走默认网关(与 _server_command 一致)。
- sentinel.py:从 P5(25bcd35)取的超集版本 + 推理连接器条目
(POST /v1/responses、GET /v1/models;scheme/端口只 https/443,
本地中继不走 evaluate,不把 http 加进表)。
- 遥测最小化:cloud/chv/telemetry.py(字段白名单、确定性采样、
落盘失败不影响任务、token 未回传记 null)+ 训练退出开关
(默认开,本项目决定;关后轨迹不再产生;损坏 fail-closed;变更审计)。
- 访问边界:docs/chv-access-boundary.md(运营访问口径 + 审计钩子,
不冒充技术不可访问;Confidential VM 明确未做)。
- 测试:cloud/tests/test_chv_muse_p9.py 51 组全过;5 个旧文件
的 make_exec 配假 origin + 假解析器(新 fail-closed 门要求的
测试配置);全量 cloud 套件 1918 OK(skipped=8)。
详见 docs/chv-muse-p9-gap.md(含自定清单与真机待验证清单)。
2026-11-06 23:03:06 +00:00
host
8d4771bce3
feat(chv): align Muse P8 background work (crons/swarm/presentation/per-task browser)
...
- crons: pause/resume, exponential-backoff retry (cap 1h), retry claim
single-winner reusing quota+task build, run_cron_tick cap 5/project
- swarm: per-agent task id + isolated workspace (resolve_inside gate),
tool register + invocation audit (no execution in swarm layer)
- presentation: worth-presenting rules (needs_input/failed/new
content only) + notification ledger dedup 1h per (task, reason)
- browser_tasks: one BrowserTransport instance per browser task,
single-use (reuse after destroy refused), shots dir per instance
- automations: paused status + retry columns (max_retries,
retry_backoff_seconds, consecutive_failures, next_retry_at)
- gap table docs/chv-muse-p8-gap.md; self-defined values listed there
(not Meta official): tick cap 5, swarm max 32/default 8, retry
base 60s cap 3600s, ledger window 3600s, snapshot trunc 200/64KB
- tests: 49 new in cloud/tests/test_chv_muse_p8.py (incl. negatives:
cron unauthorized trigger, cross-workspace access, no-content
silence, dedup); full cloud suite 1916 OK (skipped=8)
2026-11-06 22:42:31 +00:00
host
60c371d9d5
feat(chv): 对齐 Muse P11 用量计量与配额执行——四项计量 + 三档档位门 + 哈希链账本
...
- cloud/usage.py(新):TIER_LIMITS 三档提案(Free $0/Paid $19/Heavy $99,
提案非定价,payload 带 proposal 标注)、TierStore(无档位行不受档位门
约束)、UsageLedger(追加写哈希链,篡改可发现)、UsageMeter(token 读
cost_records、消息读账本、并发/存储注入实测)、QuotaGate(纯准入判定,
402,不碰在跑任务)、80% 提醒每维度每窗口一次
- cloud/server.py:_reject_if_over_quota 内加档位门(同一漏斗,双人门
自动覆盖;查询异常 fail-closed 503)、GET /users/me/usage、
GET/POST /admin/tiers、存储实测复用 _task_worktree_for_files
- docs/chv-muse-p11-gap.md:差距表(先写表再动手)+ 诚实边界(USD 路径
30 秒轮询掐断与“不掐断”语义不一致是已知待决;并发即拒与设计文档
排队不同;cloud 任务存储量不到;Heavy 消息/天提案未给,本轨定不限)
- 测试 22/22,全量 1889 OK(skipped=8);mypy 在 usage.py 上干净,
server.py 5 错均为基线旧错(marker_tools/sub2api/_row_get,与本轨无关)
- 真机验证排队在 round-11 与 P4~P9 之后;不接真实计费
2026-11-06 22:42:30 +00:00
host
29fa0c8813
feat(chv): 对齐 Muse P7——状态与记忆分离
...
- 每 VM 一个 SQLite 状态库(cloud/chv/app_state.py):
state_dir/<vm>/app-state.sqlite(0600,WAL),表 tasks/goals/
sessions/audit(只追加)/meta;写操作过无凭证守卫(键名 +
值模式);备份用 sqlite3 在线备份 + manifest(sha256),恢复
先验 manifest、先留 pre-restore 副本;DDL 用 SQLite 与
Postgres 共通受限子集,换 Postgres = 换连接工厂。
- 记忆文件接线(cloud/chv/memory_files.py):宿主镜像读/列/
写/追加(路径穿越守卫、写审计);MemorySystemClient 调真实
记忆系统 CLI(search/get/explain/forget-plan/forget-confirm/
backup/restore/export),不重造引擎;forget = plan → confirm
→ 本地清行 → search 验证查不到;pull_memory_home 经 SSH +
tar 拉取客机记忆家目录。
- 客内脚本 chv-guest/chv-memory.py(纯标准库,list/read/
append/forget/export),家目录 /home/chv/memory(workspace
之外,不同步到 Gitea);build.sh 拷入 + buildinfo 登记。
- 新测试 cloud/tests/test_chv_muse_p7.py 46 项全过(含真 CLI
write/search/forget/backup/restore 实测、假 ssh 拉取、否定
测试);全量 cloud 套件 1913 项 OK(skipped=8)。
- 存储选型:SQLite 不是 Postgres(见差距表 §4;轻量 VM 跑
Postgres server 太重,宿主共享 Postgres 破坏每用户 VM
隔离);忘记是尽力删除 + 验证,不是密码学擦除。
- 真机待验证(未做,等测试机空闲):见
docs/chv-muse-p7-gap.md §6 清单
2026-11-06 22:39:04 +00:00
host
9759be47bb
feat(chv): 对齐 Muse P12——审计轨迹与活动视图
...
统一审计记录模型(时间/主体/动作/对象/结果/原因/关联任务/
关联审批)+ 追加写 JSONL + SHA-256 哈希链(改写/删除/调序可
被 verify 发现)+ 字段级白名单清洗(密钥/token 值/对话原文
绝不进审计);事件分类覆盖任务派发、VM 生命周期、同步、审批、
支付、配额、记忆、后台、推理/遥测;from_legacy_row 承接现有
audit_log 行;导出选 JSON。
活动视图后端:计划登记(已做 vs 计划做,流转受控)+ 已批准
权限登记(接 P5 describe 形状)+ activity_summary 纯函数;
结构化审批卡数据(风险分级 + 接受/拒绝明确动作 + 五档授权
选项,永久档须显式 opt-in)+ card_matches_channel 校验卡与
P5 通道载荷一致。
只做后端 + 数据接口,前端视图留接口;P3/P5 不在本基线,
接线走 dict 契约,集成由 round-11 合并;审计持久化先落独立
JSONL,待 P7 状态库就绪后迁移。真机验证排队在 round-11 之后。
新测试 43/43,全量 cloud 套件 1910 OK(skipped=8);
mypy 在改动文件上干净。
2026-11-06 22:38:19 +00:00
host
1c8fc3f7c8
对齐 Muse P4:浏览器完全对齐(CDP broker 单元外 + a11y-tree-only + 确定性分类器)
...
- chv-guest/chv-cdp-broker.py(新):单元外 CDP broker,用户 chv-browser,
独家 chromium.launch(headless=True, args=LAUNCH_ARGS);启动参数白名单
无 --remote-debugging-port、无 devtools;导航前 URL 校验 + 拦截名单;
快照恒带 untrusted_input 与 injection_flags;高风险表单在页时 open
即 ask 入队;观测到导航 POST 自动暂停;命中拦截规则的下载取消 + 暂停
+ ask;全部回包与错误经 sanitize_error + response_leaks 检查。
- chv-guest/chv-browser.py(P2 版重构):改为 broker 客户端,不再直连
Playwright(本文件无 playwright import),保留 URL 校验 + 快照截断
作为第二层防线;暂停状态与 broker 同步。
- chv-guest/chv_browser_guard.py(新):纯 stdlib 共享规则——validate_url、
拦截名单加载/匹配、快照截断、错误消毒(去 HTML、截断 200 字符、凭据形
key=value 与 sk- 形 token 打码)、注入启发式(中英文各 6 条)、表单风险
扫描、下载扫描(可执行扩展名)、文件型 ask 队列(pending/allowed/denied,
与 P3 ApprovalQueue 同语义)、启动参数与回包泄露检查、脚本注入面
禁止清单(FORBIDDEN_PAGE_ATTRS/FORBIDDEN_OPS)。
- chv-guest/browser-blocklist.txt(新):静态拦截名单;首版只有 RFC 2606
.test 自测条目,生产条目由运维构建时填入,无在线更新。
- chv-guest/build.sh/buildinfo.py:P2 三脚本 + P4 三文件纳入镜像与
buildinfo;新增 chv-cdp-broker.service 与 /run/chv/ask-queue tmpfiles。
- docs/chv-muse-p4-gap.md(新):现状 vs Muse 官方要求差距表、改动、
诚实边界、P2 合入约定、真机待验证清单(round 12)。
- docs/chv-production-readiness.md:补 §15(P4 一节;编号合入时若与
P2 的 §15 撞,顺延)。
- cloud/tests/test_chv_muse_p4.py(新,36 项):guard 单元、AST 钉住
禁止属性、假 Playwright broker 测试、假 broker agent 测试、真 Unix
socket 联调、buildinfo/build 干跑断言;含否定测试(evaluate 被拒、
DOM 外泄被拒、DevTools 不可达、私有地址被拒、高风险表单被拦、
注入文本被标注)。
测试:P4 新测试 36/36;全量 cloud 套件 1903 项,两次连续全过
(skipped=8)。附记:第一次全量跑出 1 个失败但输出未保留、后两次
均未复现,疑为时序抖动,未追认。
真机验证未做:排队等 round-11/第三棒释放 100.65.51.33,清单见 gap
表 §5。本地提交,未推未合未部署。
2026-11-06 22:36:56 +00:00
host
81e4eaf4db
feat(chv): 对齐 Muse P6 privsep worker + 确定性安全检查层
...
- cloud/chv/privsep.py(新):Gitea worker 注册表(凭证白名单只含
GITEA_TOKEN)+ 类型化请求/响应(request_id 绑定、64KB 上限)+
Unix socket 客户端(超时/崩溃 -> 类型化失败 WorkerRefusal)+
客户端白名单校验
- cloud/chv/safety.py(新):UntrustedData 来源标记 +
InjectionScanner 确定性规则(block/flag/allow,中英)+
redact_secrets + AuditLogger(只记指纹,不记值)+
audit_inference_request/response
- chv-guest/chv-gitea-worker.py + .service(新):systemd 沙箱化
worker(SO_PEERCRED 只放 root,仓限 ~/workspace,git 只配 authd
helper,绝不持 token;输出先扫描再返回)
- chv-guest/chv-sync-worker-client.py(新):agent 侧薄 CLI
- chv-guest/chv-sync.sh:pull/push/status 有 socket 时走 worker,
否则旧路径 + stderr 警告(过渡兼容)
- cloud/chv/executor.py:_run_guest 前后加推理边界审计钩子
(best-effort)
- docs/chv-muse-p6-gap.md(新):差距表 + 覆盖边界 + 真机待验证清单
- docs/chv-production-readiness.md:§15
- cloud/tests/test_chv_muse_p6.py(新):43 项
测试:新测试 43/43;全量 cloud 套件 1910 OK(skipped=9);mypy
在新增文件上干净(剩余 4 处为基线旧错 executor.py:1396/1401、
marker_tools.py:142,未动)。
真机验证:未做,排队在 round-11 之后,清单见
docs/chv-muse-p6-gap.md §4。
2026-11-06 22:31:54 +00:00
host
25bcd355f8
feat(chv): 对齐 Muse P5 纵深——eBPF 污点传播 + 五档严格能力 + 对话外审批 + 默认策略
...
- taint.py:污点追踪器(登记/污点不可逆/子进程继承/审计)
- ebpf_taint.py:eBPF 程序源码 + 加载器(能力探测 + 降级);
本机实测加载被 seccomp 挡(bpf() EPERM),报 blocked 不冒充
- capabilities.py:五档严格能力(一次/会话/任务/时限/永久,
三元组绑定 + 精确匹配 + 撤销;permanent 默认不签发)
- policy.py:默认策略规则表 + 谨慎度三档(写操作与敏感路径
永远不自动放行,规则变化审计)
- approval_channel.py:对话外审批通道(nonce + 15 分钟过期 +
HMAC,答复一次有效,对话伪造无效)
- sentinel.py 接线:evaluate() 可选接 taint/policy/tier/scope,
不传时行为与 P3 一致;自动放行步骤 + 档位签发回落单次;
Capability 基类属性放宽为 Optional(None = 不限)
- 新测试 61 项;全量 cloud 套件 1958 项 OK(skipped=8)
真机待验证(未做,排队在 round-11 之后):见
docs/chv-muse-p5-gap.md §4
2026-11-06 22:25:55 +00:00
host
73176e135c
feat(chv-muse-round11): 执行器接 nspawn 单元(P2 差距表 §4)
...
客内 host.py 调用改为 chv-cell run -- python3 /app/host.py
--state /home/chv/.codex/host-state.json --codex-home
/home/chv/.codex --sandbox danger-full-access …,其余原参数
原样保留。--sandbox 放全局参数最后(argparse 后胜出),
单元内恒为 danger-full-access,调用方 read-only 不得盖回
bwrap;非单元路径(本地/Docker/冷启动回落)不动。
开关 CHV_CELL_ENABLED:只认 0/1,默认 1 开;非法值
ValueError(_to_switch 同款口径)。关时走原命令,给
lite10 及更早无单元的旧镜像留逃生口。
测试:新 test_chv_muse_round11_cell.py 7 项(开/关 argv、
原参数保留、sandbox 只在单元路径、非法值报错、SSH 层
接线);test_host_command_options_identical_across_executors
显式关单元测三执行器参数全等,断言本身未动。
全量 cloud 套件 2011 OK(skipped=8)。
2026-11-06 21:58:01 +00:00