feat: knowledge-graph resource + observe identity provenance - #5
Merged
Conversation
Parity with @memmesh/sdk v0.9.0 (thinkfleet-memory-sdk#21). New `mm.graph()` — stats, list_entities, get_entity, list_edges, traverse. There was no graph surface before, so the structural half of memory was unreachable from Rust. Edges deserialize as `GraphTraversalEdge`, the shape the read routes actually return: `subject` and `object` are hydrated entities, not ids, plus a `hop` counter. Modelling the raw `memory_edge` row instead fails against production with `missing field 'subjectId'` — found by running this against the live API, and fixed in the TS SDK too. `hop` is 0 from list_edges (no seed) and 1-indexed from traverse. Query values are percent-encoded. An unescaped `&` in a `search` filter would otherwise truncate it server-side and quietly return the wrong page. Observe gains user_id / agent_id / session_id. The server route has always accepted them; the SDK was dropping them, so provenance never arrived. Inserted only when set, so existing call sites send identical requests. They are provenance, NOT a tenancy boundary. Verified live against app.memmesh.ai — 12142 entities / 287698 edges, and edges decode as `NVIDIA CORP -[reported_metric]-> Cost of Revenue`. 113 tests pass (9 new), clippy clean.
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.
Rust parity with
@memmesh/sdkv0.9.0 — seethinkfleet-memory-sdk#21.
New:
mm.graph()stats()GET /admin/memory/graph/statslist_entities(..)GET /admin/memory/entitiesget_entity(id, ..)GET /admin/memory/entities/:idlist_edges(..)GET /admin/memory/graph/edgestraverse(id, ..)POST /admin/memory/graph/traverseThere was no graph surface before, so the structural half of memory — the
entities and typed edges extraction builds — was unreachable from Rust.
Use
stats(), notlist_entities(..).len()for any "how big is it"question. The list routes page, so their length is the page size. Against a real
project that is the difference between reporting 1,000 and the actual 12,142.
Edges are hydrated, and modelling them wrong is a hard failure
list_edges,traverse, andget_entity().edgesreturn the server'sGraphTraversalEdge—subjectandobjectare full entities, not ids,plus a
hopcounter. There is nosubjectId/objectId/brainIdon thewire.
I found this by running the port against production, where strict decoding blew
up with
missing field 'subjectId'. The same mistake was live in the TypeScriptPR, where structural typing hid it — the call compiled and handed back objects
whose declared fields were all
undefinedat runtime. Fixed in both.The raw
memory_edgerow shape is deliberately not modelled: no read routereturns it, and a type nothing returns is a trap.
hopis 0 fromlist_edges(no seed) and 1-indexed fromtraverse.Query encoding
Filter values are percent-encoded. An unescaped
&in asearchstring wouldotherwise truncate the query server-side and quietly return the wrong page —
covered by
with_query_encodes_values.observeforwards identityuser_id/agent_id/session_idnow reach the server. The route has alwaysaccepted them; the SDK was dropping them, so provenance never arrived.
Inserted only when set, so an existing call site sends an identical request
(
observe_text_omits_identity_when_unset).Provenance, not a tenancy boundary — search filters
chatIdentityId IS NULL OR = $1, permissive by design.Verification
cargo clippy --all-targetsclean.app.memmesh.aiviaexamples/graph_live.rs:12,142 entities / 287,698 edges, decoding real edges as
NVIDIA CORP -[reported_metric]-> Cost of Revenueand the literal-object caseNVIDIA CORP -[ticker_symbol]-> NVDA.Remaining parity gaps
.NET and Go are next. Go is furthest behind — no raw-text
observeat all.