gabriel / muse public

test_identity_domain_diff.py file-level

at sha256:8 · View file ↗ · Intel ↗

History
1 files
1 commits
0 hotspots
0 🧊 dead
0 πŸ’₯ blast risk
sha256:b adding issues docs to bust staging mpack prebuild cache. · gabriel · Jun 20, 2026
1 """TDD β€” IdentityPlugin.diff().
2
3 Covers:
4 - Add identity β†’ InsertOp with address = path
5 - Remove identity β†’ DeleteOp with address = path
6 - Add relationship β†’ InsertOp with address = path
7 - Remove relationship β†’ DeleteOp with address = path
8 - Modify identity (pubkey rotation) β†’ ReplaceOp
9 - No change β†’ empty ops list
10 - Summary field is non-empty for any non-trivial delta
11 - Ops are addressed by canonical path (identities/<handle>.json etc.)
12 """
13 from __future__ import annotations
14
15 import pytest
16
17 from muse.domain import SnapshotManifest, StructuredDelta
18 from muse.core.types import Manifest, long_id
19 from muse.plugins.identity.plugin import IdentityPlugin
20
21
22 @pytest.fixture
23 def plugin() -> IdentityPlugin:
24 return IdentityPlugin()
25
26
27 def snap(*paths: str) -> SnapshotManifest:
28 """Build a minimal snapshot from path β†’ fake-hash pairs."""
29 return SnapshotManifest(
30 files={p: long_id(f"{abs(hash(p)):064x}") for p in paths},
31 domain="identity",
32 directories=[],
33 )
34
35
36 def snap_with(files: Manifest) -> SnapshotManifest:
37 return SnapshotManifest(files=files, domain="identity", directories=[])
38
39
40 def op_addresses(delta: "StructuredDelta") -> set[str]:
41 return {op["address"] for op in delta["ops"]} # type: ignore[index]
42
43
44 def op_kinds(delta: "StructuredDelta") -> list[str]:
45 return [op["op"] for op in delta["ops"]] # type: ignore[index]
46
47
48 # ── identity adds / removes ───────────────────────────────────────────────────
49
50 class TestIdentityDiff:
51 def test_no_change_empty_delta(self, plugin: IdentityPlugin) -> None:
52 s = snap("identities/gabriel.json")
53 delta = plugin.diff(s, s)
54 assert delta["ops"] == []
55
56 def test_add_identity_produces_insert_op(self, plugin: IdentityPlugin) -> None:
57 base = snap()
58 target = snap("identities/gabriel.json")
59 delta = plugin.diff(base, target)
60 assert any(op["op"] == "insert" for op in delta["ops"])
61
62 def test_add_identity_address_is_path(self, plugin: IdentityPlugin) -> None:
63 base = snap()
64 target = snap("identities/gabriel.json")
65 delta = plugin.diff(base, target)
66 assert "identities/gabriel.json" in op_addresses(delta)
67
68 def test_remove_identity_produces_delete_op(self, plugin: IdentityPlugin) -> None:
69 base = snap("identities/gabriel.json")
70 target = snap()
71 delta = plugin.diff(base, target)
72 assert any(op["op"] == "delete" for op in delta["ops"])
73
74 def test_remove_identity_address_is_path(self, plugin: IdentityPlugin) -> None:
75 base = snap("identities/gabriel.json")
76 target = snap()
77 delta = plugin.diff(base, target)
78 assert "identities/gabriel.json" in op_addresses(delta)
79
80 def test_multiple_adds_produce_multiple_inserts(self, plugin: IdentityPlugin) -> None:
81 base = snap()
82 target = snap("identities/gabriel.json", "identities/alice.json")
83 delta = plugin.diff(base, target)
84 assert op_addresses(delta) == {
85 "identities/gabriel.json", "identities/alice.json"
86 }
87 assert all(op["op"] == "insert" for op in delta["ops"])
88
89 def test_modify_identity_produces_replace_op(self, plugin: IdentityPlugin) -> None:
90 base = snap_with({"identities/gabriel.json": long_id("a" * 64)})
91 target = snap_with({"identities/gabriel.json": long_id("b" * 64)})
92 delta = plugin.diff(base, target)
93 assert any(op["op"] == "replace" for op in delta["ops"])
94 assert "identities/gabriel.json" in op_addresses(delta)
95
96
97 # ── relationship adds / removes ───────────────────────────────────────────────
98
99 class TestRelationshipDiff:
100 def test_add_relationship_produces_insert_op(self, plugin: IdentityPlugin) -> None:
101 base = snap()
102 target = snap("relationships/gabriel--spawns--claude-code.json")
103 delta = plugin.diff(base, target)
104 assert any(op["op"] == "insert" for op in delta["ops"])
105 assert "relationships/gabriel--spawns--claude-code.json" in op_addresses(delta)
106
107 def test_remove_relationship_produces_delete_op(self, plugin: IdentityPlugin) -> None:
108 base = snap("relationships/gabriel--spawns--claude-code.json")
109 target = snap()
110 delta = plugin.diff(base, target)
111 assert any(op["op"] == "delete" for op in delta["ops"])
112
113 def test_add_multiple_relationships(self, plugin: IdentityPlugin) -> None:
114 base = snap()
115 target = snap(
116 "relationships/gabriel--spawns--claude-code.json",
117 "relationships/gabriel--member_of--musehub-org.json",
118 )
119 delta = plugin.diff(base, target)
120 assert len(delta["ops"]) == 2
121 assert all(op["op"] == "insert" for op in delta["ops"])
122
123
124 # ── mixed / compound diffs ────────────────────────────────────────────────────
125
126 class TestCompoundDiff:
127 def test_add_identity_and_relationship(self, plugin: IdentityPlugin) -> None:
128 base = snap()
129 target = snap(
130 "identities/gabriel.json",
131 "relationships/gabriel--spawns--claude-code.json",
132 )
133 delta = plugin.diff(base, target)
134 assert len(delta["ops"]) == 2
135
136 def test_remove_and_add_simultaneously(self, plugin: IdentityPlugin) -> None:
137 base = snap("identities/alice.json")
138 target = snap("identities/bob.json")
139 delta = plugin.diff(base, target)
140 kinds = set(op_kinds(delta))
141 assert "insert" in kinds
142 assert "delete" in kinds
143
144 def test_summary_non_empty_for_changes(self, plugin: IdentityPlugin) -> None:
145 base = snap()
146 target = snap("identities/gabriel.json")
147 delta = plugin.diff(base, target)
148 assert delta["summary"]
149
150 def test_summary_empty_for_no_changes(self, plugin: IdentityPlugin) -> None:
151 s = snap("identities/gabriel.json")
152 delta = plugin.diff(s, s)
153 # summary may be empty string or None for no-op
154 assert not delta["summary"] or delta["summary"] in ("", "no changes")