gitree: stamp jarvis node_key + :Node on Concept saves - #1622
Merged
Conversation
jarvis's create-or-merge resolves Concepts by
MERGE (node:Concept:Node {node_key, namespace}) — never by gitree's id
slug — so Concepts written here were invisible to it and every
jarvis-side write of the same concept forked a duplicate node. On one
prod graph this produced 27 empty stubs shadowing real concepts (85
READ_CONCEPT edges landed on empty bodies) plus 2 full-body duplicates.
saveConcept now computes the key jarvis would assign
(jarvisConceptNodeKey, a byte-for-byte port of jarvis's
sanitize_node_key + _compose_node_key, verified against 670
jarvis-written keys) and stamps it with the :Node label in a separate
best-effort statement after the content write. Kept out of the main
MERGE deliberately: node_key carries a (node_key, namespace) uniqueness
constraint, and a rename that computes an already-taken key must warn
and skip rather than fail the save. Existing nodes were backfilled
directly on the prod graph; identity stays MERGE {id}, so renames keep
updating the same node.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Problem
jarvis's create-or-merge resolves Concepts by
MERGE (node:Concept:Node {node_key, namespace})— never by gitree'sidslug — while gitree'ssaveConceptwrites over a raw bolt session with neither thenode_keyproperty nor the:Nodelabel. Each writer was blind to the other's nodes, so any concept touched from both sides forked a duplicate.On one prod graph this produced 27 empty jarvis-side stubs shadowing real gitree concepts (85
READ_CONCEPTedges had landed on the empty copies — agents were being routed to bodiless concepts) plus 2 full-body duplicate pairs.Fix
jarvisConceptNodeKey()(store/utils.ts) — byte-for-byte port of jarvis'ssanitize_node_key+_compose_node_key(api/helper/schema_validation.py): trim → remove spaces → lowercase → strip non-[a-zA-Z0-9\s]→concept-prefix, with the value portion replaced bysha256[:32]past 200 chars. Verified against 670 jarvis-assigned keys on the prod graph (670/670 match). Deliberately bug-compatible: non-space whitespace survives sanitization, as it does in jarvis.saveConceptstampsSET f:Node, f.node_key = <computed>in a separate best-effort statement after the content write. Kept out of the mainMERGE {id}on purpose:node_keycarries a(node_key, namespace)uniqueness constraint, and a rename that computes an already-taken key must warn and skip rather than fail the save.NOT EXISTSguards skip the stamp when another node holds the key; a lost race with a concurrent writer throws on the constraint and is caught the same way.Identity is unchanged — gitree still merges on
{id}, so renames keep updating the same node; the stamp only makes the node addressable by jarvis's merge so future jarvis-side writes land on it instead of forking.Prod state
The existing graph was repaired directly (duplicates merged via
apoc.refactor.mergeNodes, all 223 bolt-written concepts backfilled withnode_key+:Node, collision dry-run clean), so this change only needs to keep new writes consistent.Tests
6 new unit tests in
__tests__/jarvis-node-key.test.ts, 3 asserting against real prod-assigned keys; hash-path expectation generated from the actual Python. Full gitree suite 43/43.🤖 Generated with Claude Code