Files
codex-app-server/docs/chv-muse-p12-gap.md
T
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

6.3 KiB
Raw Blame History

对齐 Muse P12 差距表:审计轨迹与活动视图

依据:~/workspace/research_notes/meta-muse-ai-architecture-20261101-0755/report.md (官方新闻室、安全文 2026-09-08、设计文为准;第三方拆解只作参考, 不得把逆向细节写成官方架构)。基线:06c3e17。

1. Muse 官方要求(报告原文口径)

# 要求 来源
R1 完整审计轨迹(audit trail)展示已做与计划做的事 新闻室、设计文(报告 §2.2 第 7 步)
R2 头像下方显示正在做什么的摘要,点头像可见完整活动日志与已批准权限 设计文(任务简报口径;报告未逐字展开,列为设计文要求)
R3 确定性 UI:结构化审批卡(明确接受/拒绝动作)与凭证安全存储 设计文(报告 §2.6)
R4 审批请求由 Sentinel 直接发到客户端 UI(不是对话内),用户答复直接回 Sentinel 安全文(报告 §2.6)
R5 用户可自由检查、编辑、下载 VM 内所有文件,包括 Muse 关于用户的记忆 安全文(报告 §3 凭证与数据政策)

2. 现状(基线 06c3e17)

  • 审计是散的:cloud/auth.py 的 AuthStore.audit() 只追加 (user_id, project_id, action, detail, created_at) 到 SQLite audit_log 表,list_audit() 只按项目倒序取;cloud/worker.py 的 Worker._audit() 是 best-effort 包装;worker_adapter.py 的 make_chv_audit_callback 把 CHV 事件转成 (project_id, "chv_vm_" + event, detail)。没有统一记录模型,没有“已做/计划 做”汇总,没有活动视图,没有已批准权限清单,没有导出。
  • 审批侧:P3(分支 feat-chv-muse-p3,提交 a90cf78)有 ApprovalQueue(内存态 pending 记录:目标描述 + 原因 + ts); P5(分支 feat-chv-muse-p5,提交 25bcd35)有对话外审批通道 approval_channel.py(nonce + 15 分钟过期 + HMAC-SHA256 签名, 答复只能用一次)与 ScopedCapability.describe()(能力绑定描述)。 但 P3/P5 都不在本基线里,本轨不能 import 它们,只能按 dict 契约接线,集成时由 round-11 合并。
  • 状态存储:P7(feat-chv-muse-p7)正在做状态分离,本轨审计轨迹 的持久化先落独立 JSONL 文件 + 明确标注待迁移到 P7 存储, 不重复造 P7 的库。

3. 本轨改什么

  • cloud/chv/audit_trail.py(新,纯标准库):统一审计记录模型 (时间/主体/动作/对象/结果/原因/关联任务/关联审批/项目); 追加写 JSONL + SHA-256 哈希链(改写/删除/调序可被 verify() 发现);字段级白名单清洗(密钥、token 值、对话原文绝不进 审计,否定测试钉住);事件分类覆盖任务派发、VM 生命周期、 同步、审批、支付(P10)、配额(P11)、记忆操作(P7 的忘记)、 后台任务(P8)、推理/遥测(P9);from_legacy_row() 把现有 audit_log 行转成统一记录(标 legacy: true,无哈希链); 导出选 JSON(不做 CSV,见 §5)。
  • cloud/chv/activity.py(新,纯标准库):计划登记(已做 vs 计划做:pending/running/done/cancelled,非法流转拒绝); 已批准权限登记(接 P5 describe() 形状:连接器/主机/用例/ 档位/有效期/次数余量/撤销);activity_summary() 纯函数拼出 正在做摘要 + 近期已做 + 计划清单 + 已批准权限数。
  • cloud/chv/approval_card.py(新,纯标准库):结构化审批卡 数据(动作/目标/原因/风险分级/接受与拒绝两个明确动作/五档 授权类型选项,永久档标注须显式 opt-in);card_matches_channel() 校验卡数据与 P5 通道载荷一致(pending_id + 目标字段全等)。
  • 前端视图不做:本轨只给后端 + 数据接口,客户端 UI 是另一侧的 工作,契约见各模块 docstring。

4. 诚实边界

  • 哈希链是篡改可发现,不是防篡改:能写文件的人重算整条链 就能掩盖改动。真防篡改要外部锚定(远端日志/签名时间戳), 不在本轨。
  • 审计清洗是字段名黑名单 + key=value 模式脱敏,不是内容理解: 密钥若藏在自由文本字段里且不带 token=/password= 等标记, 清洗器看不出来。调用方仍须只传描述性字段(P3/P5 的口径)。
  • 活动视图的“正在做什么”来自计划登记与审计记录,不是实时 进程探针;VM 内真实执行状态以执行器为准。
  • 审批卡只做数据,不做签发:档位可选项由 Sentinel 决定(P5 口 径),本轨只呈现调用方传进来的档位列表。

5. 决定记录

  • 导出选 JSON 不选 CSV:JSON 保留哈希链与嵌套结构,CSV 会丢 字段;任务简报允许二选一。
  • 审计持久化先用独立 JSONL 文件(audit_trail.jsonl,0600), 待 P7 状态库就绪后迁移,迁移接口是 from_legacy_row() 同款 转换(本文件行 → 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. 审计轨迹(round-12 起走 StoreAuditTrail / SQLite,不再是 JSONL)在真实 VM 生命周期(wake/pause/resume/shutdown) 下的追加与 verify() 表现。
  2. 活动摘要与真实任务派发/完成事件的对应(正在做是否及时变 更、计划状态流转是否与 worker 终态一致)。
  3. 已批准权限清单与 P5 五档能力在 wake/同步路径下的真实表现 (签发→使用→过期→撤销全程)。
  4. 审批卡数据与 P5 对话外通道在真机上的端到端一致(卡上点的 接受/拒绝与通道答复同一 pending_id)。
  5. 审计库落盘权限(0600)与多进程追加(worker + host.py) 下的完整性(SQLite WAL + 30 秒 busy 超时)。