Skip to content

Memory namespace model: signed cap claim + worker filter + audit#143

Open
hanwencheng wants to merge 1 commit into
mainfrom
claude/magical-joliot-ce4d57
Open

Memory namespace model: signed cap claim + worker filter + audit#143
hanwencheng wants to merge 1 commit into
mainfrom
claude/magical-joliot-ce4d57

Conversation

@hanwencheng
Copy link
Copy Markdown
Member

Closes #108.

Wires memory namespaces (personal / family / work / travel) through the whole stack so a device's cap-token can read/write one life-context but see nothing in the others — the semantic dimension behind the M1 demo's "the toy sees the Chengdu trip, not the peanut allergy." Strategic anchor: agent-iam-strategy.md §3.5; as-built spec: arch.md §17.6.

How it works (3 gates on a deterministic membership test)

  1. Broker mint signs namespaces_allowed: [...] into the cap payload. /v1/cap/memory-* validate each name against the v0 set (unknown → 400); cred caps always get []. The field sits at the same position in the broker and worker CapPayload so the signature verifies byte-for-byte.
  2. Worker filter re-verifies the broker signature, then refuses any namespace ∉ namespaces_allowed: a read returns an empty result (never the data, doesn't even reveal it exists); a write returns ok:false. Unknown namespace → 400.
  3. Audit — on a violation the MCP server emits a memory.namespace_violation row (new canonical op_kind 13).

The allowlist is operator-sourced (MCP_DEFAULT_NAMESPACES_ALLOWED), threaded into cap-mint — the agent can't widen its own scope by asking.

What landed

Acceptance criteria met: signed-and-re-verified claim, empty read for disallowed namespaces, audit row on violation, positive+negative unit tests.

What did NOT land

  • Hardware end-to-end (Act 1 against MagicLick 2.5 / xiaozhi-esp32): not runnable here — no device. The software path is covered by the three-act integration test + a live cross-namespace negative step in the stage-3 harness; hardware verification is a follow-up for whoever has the device.
  • Metadata-only storage layout (§3.5's eventual model): M1 ships the <namespace>/ path component instead, because the metadata-only filter presupposes the unbuilt 4-type LIST-and-filter retrieval. Deliberate, documented in arch.md §17.6. On-chain per-namespace scope (so a compromised MCP server can't exceed a grant) is also a later-phase hardening — M1 trust model is "operator configures the server."

Test plan

  • cargo test --workspace — green (53 suites, 0 failed)
  • cargo clippy --workspace --all-targets — clean
  • cargo fmt --check — clean
  • Live stage-3 harness (AGENTKEYS_CHAIN=heima bash harness/v2-stage3-demo.sh) — needs broker + chain + AWS
  • Hardware Act 1 on MagicLick device

🤖 Generated with Claude Code

…closes #108)

Wire memory namespaces (personal/family/work/travel) through the full
stack so a device's cap-token can read/write one life-context but not
others — the semantic dimension that makes the M1 demo's "toy sees the
trip, not the allergy" legible.

- agentkeys-types: new `Namespace` enum (v0 set + parse/validate).
- broker: `namespaces_allowed` is a SIGNED field in CapPayload; the
  /v1/cap/memory-* endpoints validate + sign it (unknown name → 400);
  cred caps always get []. Field order matches the worker mirror so the
  signature verifies byte-for-byte.
- worker-memory: re-verifies the signature then filters by deterministic
  string-set membership. Cross-namespace read → empty result (never the
  data); write → ok:false. Unknown namespace → 400. Blob keyed
  bots/<actor>/memory/<namespace>/<service>.enc so the four namespaces
  coexist under the agent-facing tools (which don't expose `service`).
- MCP server: threads the operator-configured allowlist into cap-mint
  (agent can't self-widen) and emits a `memory.namespace_violation`
  audit row (op_kind 13) on a violation.
- audit: new canonical op_kind 13 (MemoryNamespaceViolation) + body.
- docs: arch.md §17.6 + op_kind table; strategy §3.5 status; memory
  design wire format. harness stage-3 + stdio demo updated for the
  required `namespace` field, plus a live cross-namespace negative test.

Tests: namespace gate positive+negative (worker verify, broker validate,
types), three-act Act 1 now asserts the cross-namespace audit row.
Full workspace test + clippy + fmt green.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 1: Memory namespace model — wire to cap-token + worker filter

1 participant