Repository navigation
fix(graph): scope edge reads to one layer, and make the migration inventory precise - #177
Merged
Merged
Conversation
memory_graph_edges filtered the requested layer on the source node only while returning BOTH endpoints' content, so an edge from the requested layer to another layer answered with the foreign layer's text. Reproduced on 7fae1f6: layer=user returned an agent node's content through a user->agent edge, and the agent side leaked user text symmetrically. The user_id half of this asymmetry was closed by F54, which added the predicate to both endpoints; the layer half was missed. Both branches now require s.layer and t.layer, which keeps every same-layer edge and hides only the cross-layer ones. Latent today — the live bases have no cross-layer edges — and live the moment graph nodes are re-layered: the pending historical migration would create tens of thousands of them in hermes alone. Also corrects count_edges' docstring, which claimed its source-only convention was the one memory_graph_edges used. After this change it is not, and on a cross-layer edge the counter will exceed what the tool lists.
Two precision defects measured on the three live bases. An identity/profile node that enumerates the address forms matched several markers at once and became a migration candidate in every base. It is legitimate user-layer knowledge — moving it would delete the owner's own profile from user memory. Exclusions now mark such a node decision="exclude" and keep it in the manifest so the decision stays reviewable; the policy block carries only version/source/count/sha256, never the patterns. wiki_page is a structural signal whose content is a filesystem path rather than prose, so it produced candidates with no text evidence (7/15/1 across the live bases). The type is out of the structural set; such nodes carry no agent text. summary gains reviewable = candidates - excluded, because the confidence buckets count every emitted candidate and a consumer should not have to know to subtract excluded itself.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars.
|
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.
Two packages, both found by measuring the real bases
1.
memory_graph_edgesleaked the other layer's contentIt filtered the requested layer on the source node only, while returning both endpoints' content:
Reproduced on
7fae1f6:layer="user"returned an agent node's content through auser → agentedge, and the agent side leaked user text symmetrically. Theuser_idhalf of this asymmetry was closed by F54 (both endpoints); the layer half was missed.Both branches now require
s.layerandt.layer. Same-layer edges are untouched; only cross-layer ones are hidden.Latent today — the live bases have zero cross-layer edges — and live the moment graph nodes are re-layered: the pending historical migration would create ~36 000 of them in hermes alone. This is why the fix has to land before any node is moved.
Verifier confirmed the reproduction on base and killed all three guards by mutation (target predicate, source predicate, F54 user predicate). Over-filtering probed: same-layer edges survive for
out/in/both, both layers symmetric,node_id=0unscoped branch, limit clamping intact.Also corrected
count_edges' docstring, which claimed its source-only convention was the onememory_graph_edgesused. After this change it is not, and on a cross-layer edge the counter will exceed what the tool lists — stated in the docstring rather than silently diverging.2. The inventory flagged things it should not
Measured on the three live bases with a marker list of the address forms agents use for the owner:
wiki_pagewiki_pagewiki_pageTwo precision defects:
decision="exclude"and keep it in the manifest so the decision stays reviewable. The policy block carries onlyversion/source/count/sha256, never the patterns.wiki_pageis a pointer, not prose. Itscontentis a filesystem path, so it produced candidates with no text evidence. Removed from the structural set.summarygainsreviewable = candidates - excluded, because the confidence buckets count every emitted candidate and a consumer should not have to know to subtractexcludeditself.Result: 642 / 20 / 26 candidates, exactly one excluded per base — the same
#5profile node in each.Verification
Two blind verifier passes, both
FIX_CONFIRMED, plus corrections for what they found:summary.excludedoverlapped the confidence buckets — fixed withreviewable;reasonslegitimately echoexcluded:<pattern>.Regression probes: read-only snapshot + WAL (committed-but-uncheckpointed rows visible, source bytes unchanged), fingerprint, output guards for
memory.db/-wal/-shm/-journal/hardlink/symlink, atomic replace, exact PK validation, duplicate and target-collision fields, user-scoped edge evidence,applystill rejected, byte-identical output on two runs.Still not done
applyis not implemented. It is a separate package with snapshot, fingerprint gate, postconditions and an explicit write approval. No live base has been modified.Known divergence left open on purpose: after a re-layering,
count_edgeswill count cross-layer edges thatmemory_graph_edgeswill not list. Documented, not fixed — it needs a decision about what the statistic should mean.Gates