"""TDD — IdentityPlugin.schema() and protocol conformance. Covers: - schema() returns a valid DomainSchema - domain field is "identity" - Two dimensions: "identities" and "relationships" - Both dimensions are independently mergeable - "identities" dimension uses SetSchema keyed by handle - "relationships" dimension uses SetSchema keyed by (from, edge_type, to) - merge_mode is "three_way" - Plugin satisfies MuseDomainPlugin protocol (runtime isinstance check) - Plugin satisfies AddressedMergePlugin protocol (has merge_ops) - Plugin satisfies HarmonyPlugin protocol (has conflict_fingerprint) - drift() delegates to snapshot + diff correctly - apply() returns live_state unchanged (post-processing no-op for now) """ from __future__ import annotations import pathlib import pytest from muse.domain import ( DriftReport, LiveState, MergeResult, MuseDomainPlugin, AddressedMergePlugin, SnapshotManifest, StateDelta, StateSnapshot, ) from muse.plugins.identity.plugin import IdentityPlugin from muse.core.types import long_id @pytest.fixture def plugin() -> IdentityPlugin: return IdentityPlugin() # ── DomainSchema ────────────────────────────────────────────────────────────── class TestSchema: def test_domain_is_identity(self, plugin: IdentityPlugin) -> None: assert plugin.schema()["domain"] == "identity" def test_description_non_empty(self, plugin: IdentityPlugin) -> None: assert plugin.schema()["description"] def test_has_two_dimensions(self, plugin: IdentityPlugin) -> None: dims = plugin.schema()["dimensions"] assert len(dims) == 2 def test_identities_dimension_exists(self, plugin: IdentityPlugin) -> None: names = {d["name"] for d in plugin.schema()["dimensions"]} assert "identities" in names def test_relationships_dimension_exists(self, plugin: IdentityPlugin) -> None: names = {d["name"] for d in plugin.schema()["dimensions"]} assert "relationships" in names def test_both_dimensions_independently_mergeable(self, plugin: IdentityPlugin) -> None: for dim in plugin.schema()["dimensions"]: assert dim["independent_merge"] is True def test_identities_dimension_is_set_schema(self, plugin: IdentityPlugin) -> None: dim = next(d for d in plugin.schema()["dimensions"] if d["name"] == "identities") assert dim["schema"]["kind"] == "set" def test_relationships_dimension_is_set_schema(self, plugin: IdentityPlugin) -> None: dim = next(d for d in plugin.schema()["dimensions"] if d["name"] == "relationships") assert dim["schema"]["kind"] == "set" def test_merge_mode_is_three_way(self, plugin: IdentityPlugin) -> None: assert plugin.schema()["merge_mode"] == "three_way" def test_schema_version_is_string(self, plugin: IdentityPlugin) -> None: assert isinstance(plugin.schema()["schema_version"], str) # ── Protocol conformance ────────────────────────────────────────────────────── class TestProtocolConformance: def test_satisfies_muse_domain_plugin(self, plugin: IdentityPlugin) -> None: assert isinstance(plugin, MuseDomainPlugin) def test_satisfies_addressed_merge_plugin(self, plugin: IdentityPlugin) -> None: assert isinstance(plugin, AddressedMergePlugin) def test_has_conflict_fingerprint_harmony(self, plugin: IdentityPlugin) -> None: assert callable(getattr(plugin, "conflict_fingerprint", None)) def test_has_all_six_required_methods(self, plugin: IdentityPlugin) -> None: for method in ("snapshot", "diff", "merge", "drift", "apply", "schema"): assert callable(getattr(plugin, method, None)), f"missing: {method}" def test_has_merge_ops(self, plugin: IdentityPlugin) -> None: assert callable(getattr(plugin, "merge_ops", None)) # ── drift() ─────────────────────────────────────────────────────────────────── class TestDrift: def test_no_drift_when_tree_matches_commit(self, plugin: IdentityPlugin, tmp_path: pathlib.Path) -> None: snap = plugin.snapshot(tmp_path) report = plugin.drift(snap, tmp_path) assert report.has_drift is False def test_drift_detected_on_new_file(self, plugin: IdentityPlugin, tmp_path: pathlib.Path) -> None: snap = plugin.snapshot(tmp_path) (tmp_path / "identities").mkdir() (tmp_path / "identities" / "gabriel.json").write_bytes(b'{"handle":"gabriel"}') report = plugin.drift(snap, tmp_path) assert report.has_drift is True def test_drift_report_has_summary(self, plugin: IdentityPlugin, tmp_path: pathlib.Path) -> None: snap = plugin.snapshot(tmp_path) (tmp_path / "identities").mkdir() (tmp_path / "identities" / "alice.json").write_bytes(b'{"handle":"alice"}') report = plugin.drift(snap, tmp_path) assert hasattr(report, "summary") def test_no_drift_summary_indicates_clean(self, plugin: IdentityPlugin, tmp_path: pathlib.Path) -> None: snap = plugin.snapshot(tmp_path) report = plugin.drift(snap, tmp_path) # summary should convey "nothing changed" assert not report.has_drift # ── apply() ─────────────────────────────────────────────────────────────────── class TestApply: def test_apply_returns_live_state(self, plugin: IdentityPlugin, tmp_path: pathlib.Path) -> None: snap = plugin.snapshot(tmp_path) delta: StateDelta = {"ops": [], "summary": "", "domain": "identity"} result = plugin.apply(delta, tmp_path) assert result == tmp_path def test_apply_with_manifest_returns_manifest(self, plugin: IdentityPlugin) -> None: manifest = SnapshotManifest( files={"identities/alice.json": long_id("a" * 64)}, domain="identity", directories=[], ) delta: StateDelta = {"ops": [], "summary": "", "domain": "identity"} result = plugin.apply(delta, manifest) assert result == manifest