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

+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 文件一次导入、不丢去重状态。