gabriel / muse public
test_identity_domain_records.py python
178 lines 5.9 KB
Raw
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 21 days ago
1 """TDD — IdentityPlugin records layer.
2
3 Covers:
4 - IdentityRecord, RelationshipRecord, SignatureRecord typed shapes
5 - identity_path / relationship_path encoding and round-trip parsing
6 - Record serialisation to / from JSON bytes
7 - parse_identity_path / parse_relationship_path (inverse of encode)
8 """
9 from __future__ import annotations
10
11 import json
12
13 import pytest
14
15 from muse.plugins.identity.records import (
16 IdentityRecord,
17 RelationshipRecord,
18 SignatureRecord,
19 identity_path,
20 parse_identity_path,
21 parse_relationship_path,
22 record_from_bytes,
23 record_to_bytes,
24 relationship_path,
25 )
26
27
28 # ── path encoding ─────────────────────────────────────────────────────────────
29
30 class TestIdentityPath:
31 def test_human_handle(self) -> None:
32 assert identity_path("gabriel") == "identities/gabriel.json"
33
34 def test_agent_handle(self) -> None:
35 assert identity_path("claude-code") == "identities/claude-code.json"
36
37 def test_org_handle(self) -> None:
38 assert identity_path("musehub-org") == "identities/musehub-org.json"
39
40 def test_path_is_posix(self) -> None:
41 p = identity_path("alice")
42 assert "/" in p
43 assert "\\" not in p
44
45 def test_parse_round_trips(self) -> None:
46 for handle in ("gabriel", "claude-code", "acme-org", "a1"):
47 encoded = identity_path(handle)
48 assert parse_identity_path(encoded) == handle
49
50 def test_non_identity_path_returns_none(self) -> None:
51 assert parse_identity_path("relationships/x--spawns--y.json") is None
52 assert parse_identity_path("other/file.json") is None
53
54
55 class TestRelationshipPath:
56 def test_spawns_edge(self) -> None:
57 p = relationship_path("gabriel", "spawns", "claude-code")
58 assert p == "relationships/gabriel--spawns--claude-code.json"
59
60 def test_member_of_edge(self) -> None:
61 p = relationship_path("gabriel", "member_of", "musehub-org")
62 assert p == "relationships/gabriel--member_of--musehub-org.json"
63
64 def test_path_is_posix(self) -> None:
65 p = relationship_path("a", "spawns", "b")
66 assert "/" in p
67 assert "\\" not in p
68
69 def test_parse_round_trips(self) -> None:
70 cases = [
71 ("gabriel", "spawns", "claude-code"),
72 ("gabriel", "member_of", "musehub-org"),
73 ("acme", "member_of", "lab"),
74 ]
75 for frm, edge, to in cases:
76 encoded = relationship_path(frm, edge, to)
77 assert parse_relationship_path(encoded) == (frm, edge, to)
78
79 def test_non_relationship_path_returns_none(self) -> None:
80 assert parse_relationship_path("identities/gabriel.json") is None
81 assert parse_relationship_path("other/file.json") is None
82
83
84 # ── record serialisation ──────────────────────────────────────────────────────
85
86 class TestIdentityRecordSerialisation:
87 def _human_record(self) -> IdentityRecord:
88 return IdentityRecord(
89 handle="gabriel",
90 type="human",
91 pubkey="ed25519:AAAA",
92 quorum=None,
93 registered_at="2026-04-21T22:00:00Z",
94 metadata={},
95 )
96
97 def test_round_trip_human(self) -> None:
98 rec = self._human_record()
99 raw = record_to_bytes(rec)
100 parsed = record_from_bytes(raw)
101 assert parsed == rec
102
103 def test_serialised_is_valid_json(self) -> None:
104 raw = record_to_bytes(self._human_record())
105 obj = json.loads(raw)
106 assert obj["handle"] == "gabriel"
107 assert obj["type"] == "human"
108
109 def test_round_trip_org(self) -> None:
110 rec = IdentityRecord(
111 handle="acme",
112 type="org",
113 pubkey=None,
114 quorum=2,
115 registered_at="2026-04-21T22:00:00Z",
116 metadata={},
117 )
118 assert record_from_bytes(record_to_bytes(rec)) == rec
119
120 def test_round_trip_agent(self) -> None:
121 rec = IdentityRecord(
122 handle="claude-code",
123 type="agent",
124 pubkey="ed25519:BBBB",
125 quorum=None,
126 registered_at="2026-04-21T22:00:00Z",
127 metadata={"model_id": "claude-sonnet-4-6"},
128 )
129 assert record_from_bytes(record_to_bytes(rec)) == rec
130
131
132 class TestRelationshipRecordSerialisation:
133 def _spawns_record(self) -> RelationshipRecord:
134 return RelationshipRecord(
135 from_handle="gabriel",
136 to_handle="claude-code",
137 edge_type="spawns",
138 weight=None,
139 authorized_by=[
140 SignatureRecord(
141 signer="gabriel",
142 signature="ed25519:CCCC",
143 signed_at="2026-04-21T22:00:00Z",
144 )
145 ],
146 )
147
148 def test_round_trip_spawns(self) -> None:
149 rec = self._spawns_record()
150 assert record_from_bytes(record_to_bytes(rec)) == rec
151
152 def test_round_trip_member_of(self) -> None:
153 rec = RelationshipRecord(
154 from_handle="gabriel",
155 to_handle="musehub-org",
156 edge_type="member_of",
157 weight="1",
158 authorized_by=[
159 SignatureRecord(
160 signer="gabriel",
161 signature="ed25519:DDDD",
162 signed_at="2026-04-21T22:00:00Z",
163 )
164 ],
165 )
166 assert record_from_bytes(record_to_bytes(rec)) == rec
167
168 def test_serialised_preserves_weight(self) -> None:
169 rec = RelationshipRecord(
170 from_handle="alice",
171 to_handle="acme",
172 edge_type="member_of",
173 weight="0.5",
174 authorized_by=[],
175 )
176 raw = record_to_bytes(rec)
177 parsed = record_from_bytes(raw)
178 assert parsed["weight"] == "0.5"
File History 4 commits
sha256:81ae324db5ad375fbfe4834c6fcb378312cafad3cc92dec5d3e5c427306621a2 fix: remove commit_exists filter from have anchors — server… Sonnet 4.6 patch 21 days ago
sha256:36c3cb3e76619d4c30a6d9bf81b5ec4ff148e30dcfed913e3114ca7b43b81c7e fix: rename objects→blobs in push client and all stale test… Sonnet 4.6 patch 22 days ago
sha256:c06a9b9b9fee26c68ea725b44d54b2c0a171301ce9de746d5b656617b4463a9a fix: repair four test failures from post-migration audit Sonnet 4.6 patch 29 days ago
sha256:1900655993c83c4107067375548a7be823e471d2515830842f1a12cba4bd3cdf fix: unified object store migration — idempotent writes, JS… Sonnet 4.6 minor 29 days ago