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.
This commit is contained in:
host committed 2026-11-07 00:36:25 +00:00
1 parent 466cf7eae7
commit d4cef29cdb
11 files changed
+1147 -63

No files matched your search

+10 -4
View File
@@ -76,14 +76,20 @@
字段;任务简报允许二选一。
- 审计持久化先用独立 JSONL 文件(`audit_trail.jsonl`,0600),
待 P7 状态库就绪后迁移,迁移接口是 `from_legacy_row()` 同款
转换(本文件行 → P7 记录)。
转换(本文件行 → P7 记录)。**迁移已完成(round-12)**:
`StoreAuditTrail` 走宿主级 AppStateStore 的 `audit_trail` 表,
与 JSONL 版同一记录形状与哈希链;`migrate_jsonl_to_store()`
原样搬链(坏链拒绝、分叉拒绝、重跑幂等);JSONL 版保留读旧
文件,新写一律走 Store 版。测试钉在
`cloud/tests/test_chv_muse_round12.py`。
- project_id 强制:`list()`/`export()` 必须传 project_id,只返
回该项目记录;跨项目读取返回空,不抛错(与现有 `list_audit`
行为一致,不泄露“存在别的项目记录”这一事实)。
## 6. 真机待验证清单(未做,排队在 round-11 之后)
1. 审计 JSONL 在真实 VM 生命周期(wake/pause/resume/shutdown)
1. 审计轨迹(round-12 起走 StoreAuditTrail / SQLite,不再是
JSONL)在真实 VM 生命周期(wake/pause/resume/shutdown)
下的追加与 `verify()` 表现。
2. 活动摘要与真实任务派发/完成事件的对应(正在做是否及时变
更、计划状态流转是否与 worker 终态一致)。
@@ -91,5 +97,5 @@
(签发→使用→过期→撤销全程)。
4. 审批卡数据与 P5 对话外通道在真机上的端到端一致(卡上点的
接受/拒绝与通道答复同一 pending_id)。
5. 审计文件落盘权限(0600)与多进程追加(worker + host.py)
下的完整性。
5. 审计库落盘权限(0600)与多进程追加(worker + host.py)
下的完整性(SQLite WAL + 30 秒 busy 超时)。
+6
View File
@@ -129,6 +129,12 @@ Base64、零宽字符)、藏在图片/附件/二进制里的指令、需要理
authd socket 路径、Sentinel 评估发生在 authd 放凭证前)。本轨
测试用替身实现同一协议;与 P3 代码的真正接通发生在合入时,
须由集成轨跑通 worker→helper→authd→git 的全链路。
**已接通(round-12,本地部分)**:`cloud/tests/
test_chv_muse_round12.py`(WorkerProtocolTest)用真
PrivsepClient + 真 worker server + 真 git status 跑通,worker
的 git argv 含真实 P3 helper 与 useHttpPath、argv/env/审计
均不含 token;runuser 包装与 HTTP 拉取(需真实 gitea.tose.top
+ Sentinel 放行)留给真机轨。
2. **worker 跑在客内 root**:worker 守护进程以 root 身份跑在单元外
(与 P3 authd 同款选择),git 子进程再以 chv 身份跑。root worker
本身不受单元隔离保护——它的隔离来自 systemd 沙箱 + socket 白名单
+28 -13
View File
@@ -50,16 +50,19 @@ VM 观察,未见于官方页面原文,本轨不把它当官方术语用;
| `cloud/chv/browser_tasks.py`(新) | 每浏览器任务一个实例:建/绑/毁生命周期、单实例单任务(复用即错、毁后复用即错)、每实例独立状态目录;transport 接口注入(测试用 fake) | 本轨 |
| `cloud/automations.py`(改) | 只加重试/停用所需的列与抢单入口(`max_retries`、`retry_backoff_seconds`、`consecutive_failures`、`next_retry_at`、`paused` 状态);host.py run-due **不动**(host 侧唯一执行器,见该模块 docstring) | 本轨 |
**P7 状态落点(更新 2026-11-07 06:39):** P7 已完成并提交(分支
`feat-chv-muse-p7`,提交 `29fa0c8`:每 VM 一个 SQLite 状态库
AppStateStore,0600 WAL,tasks/goals/sessions/只追加 audit/meta)。
本轨仍先用 `state_dir` 下的原子 JSON 文件(复用
`cloud/chv/atomic_file.py`),模块 docstring 与本表明确标注“待迁移到
P7 状态存储”;不重复造一套状态库。集成轨(round-12)把
`swarms.json` / `notification-ledger.json` / `browser-tasks.json`
迁到 AppStateStore,接口(load/save/原子写)已按同一模式写好,迁移
只是换后端。crons 与 swarm 的状态复用 `automations` 表与 swarm 登记
文件(同款原子写),同样标注待迁移。
**P7 状态落点(更新 2026-11-07 06:39;迁移已完成,round-12 更新):**
P7 已完成并提交(分支 `feat-chv-muse-p7`,提交 `29fa0c8`:每 VM
一个 SQLite 状态库 AppStateStore,0600 WAL,
tasks/goals/sessions/只追加 audit/meta)。**round-12 已把三处登记
迁到 AppStateStore**(分支 `feat-chv-muse-round12`):宿主级库
`state_dir/app-state.sqlite`(`host_state_db_path`,与 per-VM 库
同库不同文件),命名空间 `p8-swarm` / `p8-ledger` /
`p8-browser-tasks`,一行存整份登记文档;旧 JSON 文件首次加载时
自动导入并改名 `.migrated`;KV 行损坏/库打不开时回空结构
(fail-safe,下次成功保存即覆盖自愈)。测试钉在
`cloud/tests/test_chv_muse_round12.py`(P8MigrationTest)与
`test_chv_muse_p8.py`(损坏行恢复 + 旧文件导入)。crons 的状态
仍在 `automations` 表,未动。
**客机侧跟进(本轨只写规约、不改 P2 的文件):** 每任务浏览器实例的客机
进程拉起/销毁在 P2 的 `chv-guest/chv-broker.py`(`browser` 操作固定转发到
@@ -67,6 +70,17 @@ P7 状态存储”;不重复造一套状态库。集成轨(round-12)把
socket),`close` 后杀掉进程。P2 的文件不在本分支基线里,本轨不复制、不
分叉,规约写进本表 §6,留给 round-12 集成时落在 P2 分支上。
**客机侧跟进(round-12 决定:未做,留给真机轨):** round-12 核实后未做,
原因三条:① `chv-browser.py` 的请求协议里没有任务 id 字段(只有
open/snapshot/screenshot/close/ping),broker 分不清请求属于哪个浏览器任
务,改 broker 之前须先改协议 + 调 broker 的调用方;② 进程拉起/销毁涉
及以 chv-browser 身份起进程、socket 就绪等待、close 后杀进程与僵尸回收、
broker 重启后的残留清理,在没有真机验证的情况下盲改,坏了就是每任务浏览
器全断;③ 本地只能用假浏览器进程测生命周期,真 Playwright + 真
chromium-headless-shell 的起停只能在真机上验。留给真机轨:先在真机上改
协议(请求加 task_id)→ broker 按任务拉起/杀进程 → 连续两任务端到端
(§6 第 4 项)。**不许写成已做。**
## 4. 自定数值清单(全部是本项目自定,非 Meta 官方值)
| 数值 | 本项目自定值 | 说明 |
@@ -104,6 +118,7 @@ VM/单元里(P1 常驻池 + P2 单元是底座)。“子代理构建自己
3. 回访通知端到端:后台任务完成后有新内容才通知、无新内容不通知、同一原因
1 小时内不重复通知。
4. 每任务浏览器实例端到端:连续两个浏览器任务各起全新实例、第二个看不到
第一个的截图与快照状态(需 §3 客机侧跟进先落地)。
5. 账本迁移:P7 存储已落地(AppStateStore,`feat-chv-muse-p7`
提交 `29fa0c8`),集成轨把通知账本从 JSON 文件迁过去、去重语义不变。
第一个的截图与快照状态(需 §3 客机侧跟进先落地;round-12 未做,见 §3)。
5. 账本迁移:**已完成(round-12)**——通知账本与另两处登记已迁到宿主级
AppStateStore(见 §3 更新),去重语义不变,测试钉住;真机上只需确认
升级后旧 JSON 文件一次导入、不丢去重状态。
+43
View File
@@ -1040,3 +1040,46 @@ auditd 审计、与 P3 authd/Sentinel 的真接线)。
- 真机待验证:真实 token 回传下的月度累计与 402、真实多任务下的并发门、
真实 worktree 下的存储门、提醒只发一次、账本并发写不断链。
## 20. 对齐 Muse round-12 集成:P4~P12 合入(分支 feat-chv-muse-round12)
- 合入顺序与提交:P4 c24cc0b → P5 d1c9a8e → P6 b0b9f5e → P7 320cd36 →
P8 240949e → P9 90c42f6 → P10 b55b49b(acf98f8 的 cherry-pick,只含
P10 自有 diff,基线已含的 P3/P5 未重复合)→ P11 77743e7 → P12
466cf7e。基线 round-11 HEAD 29d3a5a。
- 冲突处理(逐项):① executor.py:P9 的 `_inference_gate` 插到 P1
分发器 `_run_with_vm` 之前,gate 调用为分发器第一条语句(deny/ask
在常驻 resume 与冷启动 wake 之前 fail-closed);P9 自己的旧版本
`_run_with_vm` 丢弃——其本体与 P1 `_run_cold` 逐字节相同(P1 的
verbatim 搬运),合入时一度误删 `_run_cold` 体致 dispatch 回 None,
已从 HEAD 原样恢复并由测试钉住;sentinel.py 取 P9 超集版。
② build.sh/buildinfo.py:按 hunk 合,authd 三件套 + P2 三件套 +
P4 三文件 + P7 chv-memory 全在 contents 里,GT 哈希仍为已批准的
49ffe090…。③ docs §15 撞号:P4→§16、P6→§17、P7→§18、P11→§19,
顺序顺延,无覆盖。④ P4 弄坏的 P2 测试改走假 CDP broker,断言不变。
- AppStateStore 迁移(本轨做完):P8 三处登记(swarms.json /
notification-ledger.json / browser-tasks.json)迁到宿主级库
`state_dir/app-state.sqlite`(`host_state_db_path`,与 per-VM 库
同库不同文件),命名空间 `p8-swarm` / `p8-ledger` /
`p8-browser-tasks`,一行存整份文档;旧 JSON 首次加载自动导入并改名
`.migrated`;KV 行损坏回空 fail-safe。P12 审计 JSONL 迁到
`audit_trail` 表(`StoreAuditTrail`,同一记录形状与哈希链),
`migrate_jsonl_to_store()` 原样搬链(坏链拒绝、分叉拒绝、重跑幂
等);JSONL 版保留读旧文件,新写一律走 Store 版。`kv_put` 不过
无凭证守卫(登记文档含用户 prompt,见 app_state.py 注释)。
- 接线验证(本轨,本地):P6 worker→P3 helper/authd→git 跑通真
PrivsepClient + 真 worker server + 真 git status(argv 含真实
helper 与 useHttpPath,argv/env/审计不含 token;runuser 与 HTTP
拉取留给真机);P12 审批卡吃真实 P3 `ApprovalQueue.record()`、
权限登记吃真实 P5 `ScopedCapability.describe()`,均已用真实代码
跑通,不再用替身。
- 未决与留给真机轨:① P11 冲突原样保留(档位门只做准入、USD 路径
不动,等用户裁决,见 `docs/chv-muse-p11-gap.md` §5)。② P8 客机
侧跟进未做(`chv-browser.py` 请求协议无任务 id 字段、进程拉起/
销毁须真机验证,见 `docs/chv-muse-p8-gap.md` §3)。③ 真机验证排
在 round-11 之后:P1 常驻/balloon/vsock、P2 §5 九项否定测试、
P3 §3.6 五项、P4/P5/P6/P7/P8/P9/P10/P11/P12 各自差距表 §6 清单、
以及本轨新增的迁移后真机表现(旧 JSON 一次导入、Store 审计链
在 VM 生命周期下的追加)。
- 测试:新增 `cloud/tests/test_chv_muse_round12.py` 24 项全过;
全量 cloud 套件见合入提交说明(每次合入后跑相关测试,最终全量
一次跑通才算完)。