"""Integration tests for schema drift detection using drift fixtures.""" import pytest from basic_memory.schema.parser import parse_schema_note from basic_memory.schema.diff import diff_schema from basic_memory.schema.inference import NoteData from test_schema.helpers import ( parse_frontmatter, parse_observations, parse_relations, DRIFT_SCHEMA_DIR, DRIFT_PEOPLE_DIR, ) def load_drift_notes() -> list[NoteData]: """Load all drift person fixture files as NoteData objects.""" return [ NoteData( identifier=filepath.stem, observations=parse_observations(filepath), relations=parse_relations(filepath), ) for filepath in sorted(DRIFT_PEOPLE_DIR.glob("*.md")) ] @pytest.fixture def drift_schema(): frontmatter = parse_frontmatter(DRIFT_SCHEMA_DIR / "Person.md") return parse_schema_note(frontmatter) @pytest.fixture def drift_notes(): return load_drift_notes() @pytest.fixture def drift_result(drift_schema, drift_notes): return diff_schema(drift_schema, drift_notes) class TestDriftCorpusSize: def test_minimum_drift_notes(self, drift_notes): assert len(drift_notes) >= 20 class TestNewFieldDetection: """github field appears in 60% of notes but is not in the schema.""" def test_github_detected_as_new_field(self, drift_result): new_field_names = [f.name for f in drift_result.new_fields] assert "github" in new_field_names class TestDroppedFieldDetection: """role field is in schema but only 5% of notes have it.""" def test_role_detected_as_dropped(self, drift_result): dropped_names = [f.name for f in drift_result.dropped_fields] assert "role" in dropped_names class TestCardinalityChanges: """works_at changed from single to multiple per note.""" def test_works_at_cardinality_change_detected(self, drift_result): changes = [msg for msg in drift_result.cardinality_changes if "works_at" in msg] assert len(changes) >= 1