feat(memory): MemoryDistributionGrant + read-enforced revocation wired to HellGraph#43
Merged
Merged
Conversation
…wired to HellGraph Adds the per-endpoint distribution authority layer that sits between scope approval (governed-learning lifecycle) and compartment admission (WallGuard) — the third axis neither owned: may THIS device/profile/surface hold an already-approved memory, until when. Contract surface: - schemas/memory-distribution-grant.schema.json (+ 4 fixtures, validator, CI, doc). Chains upstream WallGuard + lifecycle refs rather than re-deciding them. Adds endpoint sensitivity ceiling, grant expiry, content digest, read-enforced revocation cursor, explicit offline posture, evidence-fabric receipt. Runtime surfaces (not just the spec): - memoryd: read-enforced revocation across InMemory/SQLite/Postgres backends + POST /v1/revoke. A revoked memory is excluded from every subsequent recall, incl. externally-indexed vectors. - HellGraph: revocation propagates into the graph materialization — memoryd retracts the derived edges (services/memoryd/app/hellgraph_retract.py, graceful-degrade). Closes the derived-graph-lane leak: recall, vector index, and graph all stop serving a revoked memory. - specs: /v1/revoke added to memoryd.openapi.yaml + memory.mesh.v1.trpc.yaml. - openclaw edge adapter: EdgeMemoryStore.revoke() + read-time revoked filter. Tests: services/memoryd/tests/test_distribution_revocation.py; e2e verified via FastAPI. Prompted by @hegu-1 on #18 (approved != synced).
…linkage
HellGraph edges are keyed by workspace-source:{surface}/{slug} refs (the CSKG ingest
path), not by memory id. Revoke was only using caller-supplied refs + a memory://{id}
self-ref, so revoking a PKG-ingest summary memory would have retracted zero real edges —
the workspace-source refs were stranded in the summary's content blob.
- workspace_ingestion: write the derived source_refs into the summary memory's
metadata.provenance_refs (not only the opaque content), so the linkage is durable.
- memoryd: /v1/revoke now reads the stored memory's metadata.provenance_refs and merges
them into the retract call (get_memory_metadata added to all three stores).
- Tests: workspace_ingestion asserts the writeback carries workspace-source provenance;
memoryd e2e asserts revoking a memory with stored provenance retracts those exact refs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Prompted by @hegu-1 on #18: approval ≠ sync/distribution authority. A globally-approved memory can still be too sensitive for a given endpoint, and revocation was propagation-latency-dependent.
We traced the estate first. Two of the three axes were already owned:
governed-learning-lifecycle-record(observed→…→approved→revoked).wallguard-memory-compartment-gate, WallGuard runtime memory gate and denied durable writeback #36).The third axis was genuinely missing: per-endpoint distribution authority, and revocation never reached the graph materialization.
What
Contract surface
schemas/memory-distribution-grant.schema.json+ 4 fixtures + Python validator + CI + architecture doc.Runtime surfaces (not just the spec)
POST /v1/revoke. A revoked memory is excluded from every subsequent recall, including externally-indexed vector hits.services/memoryd/app/hellgraph_retract.py, graceful-degrade whenHELLGRAPH_URLunset). Closes the derived-graph-lane leak so recall, the vector index, and the graph all stop serving a revoked memory./v1/revokeadded tomemoryd.openapi.yaml+memory.mesh.v1.trpc.yaml.EdgeMemoryStore.revoke()+ read-time revoked filter.Verification
services/memoryd/tests/test_distribution_revocation.py(in-memory + durable SQLite tombstone + graceful graph degrade).memory.revocation_propagatedevent fires.Closes the design gap raised in #18.