- 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.