Evidence
src/interfaces/shared/remember.ts:378-437 linkMemoryToEntities(db, memoryId, entityNames) — no scope parameter. The relationship insert at :423-427:
db.prepare(
`INSERT INTO relationships (id, source_entity_id, target_entity_id, type, weight, source_memories, created_at)
VALUES (?, ?, ?, 'related_to', 1.0, ?, unixepoch())`,
).run(relId, sourceId, targetId, JSON.stringify([memoryId]));
omits scope, so the column default 'global' (schema.ts:655) applies. The existing-edge branch (:417-420) does not call widenScope. The entity lookup (:385-390) is SELECT id, name FROM entities WHERE name = ? COLLATE NOCASE — any tenant's entity.
Sole caller: storeMemoryBatch at remember.ts:353, which already knows the memory's scope (:276).
Compare the graph module's write path, which does it right: src/graph/relationship.ts:229-244 inserts scope ?? "global" and calls widenScope on an existing edge (:214).
Mechanism
A remember_batch call from hermes:career with relates_to_entities: ["Acme"] creates related_to edges stamped global. Once #88 (explore filtering edges by scope) lands, these edges — and the fact that tenant A's memory links two of tenant A's entities — are visible to every tenant via explore / explore_selective. The source_memories array on the edge also exposes tenant A's memory id.
Suggested fix
Add a scope parameter to linkMemoryToEntities (pass scope from storeMemoryBatch), include it in the INSERT, and call widenScope(db, "relationships", existing.id, scope) in the update branch — same shape as findOrCreateRelationship. Optionally restrict the entity lookup to scope IN (?, 'global').
Related: #25, #88.
Evidence
src/interfaces/shared/remember.ts:378-437linkMemoryToEntities(db, memoryId, entityNames)— no scope parameter. The relationship insert at:423-427:omits
scope, so the column default'global'(schema.ts:655) applies. The existing-edge branch (:417-420) does not callwidenScope. The entity lookup (:385-390) isSELECT id, name FROM entities WHERE name = ? COLLATE NOCASE— any tenant's entity.Sole caller:
storeMemoryBatchatremember.ts:353, which already knows the memory's scope (:276).Compare the graph module's write path, which does it right:
src/graph/relationship.ts:229-244insertsscope ?? "global"and callswidenScopeon an existing edge (:214).Mechanism
A
remember_batchcall fromhermes:careerwithrelates_to_entities: ["Acme"]createsrelated_toedges stampedglobal. Once #88 (explore filtering edges by scope) lands, these edges — and the fact that tenant A's memory links two of tenant A's entities — are visible to every tenant viaexplore/explore_selective. Thesource_memoriesarray on the edge also exposes tenant A's memory id.Suggested fix
Add a
scopeparameter tolinkMemoryToEntities(passscopefromstoreMemoryBatch), include it in theINSERT, and callwidenScope(db, "relationships", existing.id, scope)in the update branch — same shape asfindOrCreateRelationship. Optionally restrict the entity lookup toscope IN (?, 'global').Related: #25, #88.