diff --git a/semantica/kg/graph_validator.py b/semantica/kg/graph_validator.py index a8d126ca..a24fd16e 100644 --- a/semantica/kg/graph_validator.py +++ b/semantica/kg/graph_validator.py @@ -166,15 +166,24 @@ class GraphValidator: # Check ID uniqueness if eid: - if eid in entity_ids: + try: + if eid in entity_ids: + issues.append(ValidationIssue( + code="DUPLICATE_ID", + message=f"Duplicate entity ID found: {eid}", + severity=ValidationSeverity.CRITICAL, + element_id=eid, + element_type="entity" + )) + entity_ids.add(eid) + except TypeError: issues.append(ValidationIssue( - code="DUPLICATE_ID", - message=f"Duplicate entity ID found: {eid}", - severity=ValidationSeverity.CRITICAL, - element_id=eid, + code="INVALID_ID", + message=f"Entity ID is not hashable: {eid}", + severity=ValidationSeverity.ERROR, + element_id=str(eid), element_type="entity" )) - entity_ids.add(eid) # Schema Check (if schema provided) if self.schema and "entity_types" in self.schema: diff --git a/tests/kg/test_graph_validator.py b/tests/kg/test_graph_validator.py index a0c57add..103e67b5 100644 --- a/tests/kg/test_graph_validator.py +++ b/tests/kg/test_graph_validator.py @@ -32,3 +32,43 @@ def test_entity_id_aliases_are_validated_across_graph_structure(): issue.code in {"MISSING_FIELD", "DANGLING_EDGE", "ORPHAN_NODES"} for issue in result.issues ) + + +def test_entity_id_and_relationship_aliases_validate_without_builder(): + """Validator endpoint fallbacks should be tested without normalization.""" + result = GraphValidator().validate( + { + "entities": [ + {"entity_id": "alice:1", "name": "Alice", "type": "Person"}, + {"entity_id": "org:1", "name": "Acme", "type": "Organization"}, + ], + "relationships": [ + { + "source_id": "alice:1", + "target_id": "org:1", + "type": "WORKS_FOR", + } + ], + } + ) + + assert result.is_valid + assert not any( + issue.code in {"MISSING_FIELD", "DANGLING_EDGE", "ORPHAN_NODES"} + for issue in result.issues + ) + + +def test_unhashable_entity_id_returns_validation_issue(): + """Invalid unhashable IDs should produce an issue instead of crashing.""" + result = GraphValidator().validate( + { + "entities": [ + {"entity_id": ["alice:1"], "name": "Alice", "type": "Person"} + ], + "relationships": [], + } + ) + + assert not result.is_valid + assert any(issue.code == "INVALID_ID" for issue in result.issues)