Bug Description
Triplet and EdgeType datapoints are created without belongs_to_set, so node-set-filtered searches over their collections (Triplet_text, EdgeType_relationship_name) can never match anything — silently, and at full-scan cost.
In cognee/tasks/storage/add_data_points.py::_create_triplets_from_graph the triplet datapoint is built as:
triplets.append(
Triplet(
id=triplet_id,
from_node_id=str(source_node_id),
to_node_id=str(target_node_id),
text=embeddable_text,
)
)
Both endpoint nodes are available in node_map and carry belongs_to_set, but the tags are never propagated. Same pattern in cognee/tasks/storage/index_graph_edges.py::create_edge_type_datapoints — EdgeType(relationship_name=text, number_of_edges=count) with no tags.
The result on a real corpus (~800k triplets, cognee 1.4.2 + PGVector): 0 of 800,305 Triplet_text payloads carry any belongs_to_set value (all empty arrays), while Entity_name payloads are correctly tagged (73,005/73,005). Every node-set-scoped triplet search (node_name=[...] → payload filter (payload -> 'belongs_to_set') ?| tags) therefore:
- returns nothing, always, and
- costs a near-full collection pass doing it (we measured 15–20 s per query on the unmatched filter before adding indexes; the correct result would have been found in ~100 ms).
Because the failure mode is an empty-but-valid result, it never throws — retrieval quietly degrades to no-graph-context for every filtered caller.
Steps to Reproduce
add documents with node_set=["A"], cognify.
- Inspect the triplet collection:
SELECT payload->'belongs_to_set' FROM "Triplet_text" LIMIT 5; → all [] (Entity payloads are tagged, so the pipeline's tagging itself works).
- Run a search that reaches the triplet collection with
node_name=["A"] → 0 results regardless of content.
Expected behavior
Triplets (and EdgeTypes) inherit node-set membership from their endpoint nodes — e.g. the union of source.belongs_to_set and target.belongs_to_set — so scoped searches over pre-embedded triplets return the scoped subset instead of nothing.
We validated the union approach in production data by backfilling Triplet_text.payload.belongs_to_set via the deterministic triplet id (uuid5(source_id + relationship_name + target_id) from generate_node_id): scoped searches immediately returned correct results in ~75 ms.
Suggested fix
In _create_triplets_from_graph, after resolving source_node/target_node from node_map:
belongs_to_set = sorted(
set(getattr(source_node, "belongs_to_set", None) or [])
| set(getattr(target_node, "belongs_to_set", None) or [])
)
triplets.append(
Triplet(
id=triplet_id,
from_node_id=str(source_node_id),
to_node_id=str(target_node_id),
text=embeddable_text,
belongs_to_set=belongs_to_set or None,
)
)
and the analogous propagation in create_edge_type_datapoints (union over the edges aggregated into each retrieval text).
Environment
- cognee 1.4.2 (code unchanged in 1.5.3 — verified against the tag)
- PGVector adapter (pgvector 0.8.2, PostgreSQL 15/17), but the omission is backend-agnostic: the tags are dropped before any adapter sees the datapoint.
Related but distinct: #3914 / #4078 / #4079 cover node-set scoping at query time; this one is the creation-time gap that makes triplet-collection scoping structurally empty.
Bug Description
TripletandEdgeTypedatapoints are created withoutbelongs_to_set, so node-set-filtered searches over their collections (Triplet_text,EdgeType_relationship_name) can never match anything — silently, and at full-scan cost.In
cognee/tasks/storage/add_data_points.py::_create_triplets_from_graphthe triplet datapoint is built as:Both endpoint nodes are available in
node_mapand carrybelongs_to_set, but the tags are never propagated. Same pattern incognee/tasks/storage/index_graph_edges.py::create_edge_type_datapoints—EdgeType(relationship_name=text, number_of_edges=count)with no tags.The result on a real corpus (~800k triplets, cognee 1.4.2 + PGVector): 0 of 800,305
Triplet_textpayloads carry anybelongs_to_setvalue (all empty arrays), whileEntity_namepayloads are correctly tagged (73,005/73,005). Every node-set-scoped triplet search (node_name=[...]→ payload filter(payload -> 'belongs_to_set') ?| tags) therefore:Because the failure mode is an empty-but-valid result, it never throws — retrieval quietly degrades to no-graph-context for every filtered caller.
Steps to Reproduce
adddocuments withnode_set=["A"],cognify.SELECT payload->'belongs_to_set' FROM "Triplet_text" LIMIT 5;→ all[](Entity payloads are tagged, so the pipeline's tagging itself works).node_name=["A"]→ 0 results regardless of content.Expected behavior
Triplets (and EdgeTypes) inherit node-set membership from their endpoint nodes — e.g. the union of
source.belongs_to_setandtarget.belongs_to_set— so scoped searches over pre-embedded triplets return the scoped subset instead of nothing.We validated the union approach in production data by backfilling
Triplet_text.payload.belongs_to_setvia the deterministic triplet id (uuid5(source_id + relationship_name + target_id)fromgenerate_node_id): scoped searches immediately returned correct results in ~75 ms.Suggested fix
In
_create_triplets_from_graph, after resolvingsource_node/target_nodefromnode_map:and the analogous propagation in
create_edge_type_datapoints(union over the edges aggregated into each retrieval text).Environment
Related but distinct: #3914 / #4078 / #4079 cover node-set scoping at query time; this one is the creation-time gap that makes triplet-collection scoping structurally empty.