gabriel / muse public
test_stress_store_provenance.py python
437 lines 15.5 KB
Raw
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor ⚠ breaking 122 days ago
1 """Stress tests for CommitRecord, SnapshotRecord, TagRecord, and provenance fields.
2
3 Covers:
4 - CommitRecord round-trip through to_dict/from_dict for all format versions.
5 - format_version evolution: missing fields default correctly when reading old records.
6 - reviewed_by (ORSet semantics): list preserved, sorted, deduplicated via overwrite_commit.
7 - test_runs (GCounter semantics): monotonically increases via overwrite_commit.
8 - agent_id / model_id / toolchain_id / prompt_hash / signature fields.
9 - SnapshotRecord round-trip with large manifests.
10 - TagRecord round-trip.
11 - get_head_commit_id on empty branch returns None.
12 - write_commit is idempotent (won't overwrite).
13 - overwrite_commit updates the persisted record correctly.
14 - read_commit for absent commit returns None.
15 - list_commits and list_branches.
16 - list_tags returns all tags.
17 """
18
19 import datetime
20 import pathlib
21
22 import pytest
23
24 from muse.core.types import fake_id, long_id
25 from muse.core.paths import ref_path, muse_dir
26 from muse.core.crdts.or_set import ORSet
27 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
28 from muse.domain import SemVerBump
29 from muse.core.store import (
30 CommitDict,
31 CommitRecord,
32 SnapshotRecord,
33 TagRecord,
34 get_all_commits,
35 get_all_tags,
36 get_head_commit_id,
37 overwrite_commit,
38 read_commit,
39 read_snapshot,
40 write_commit,
41 write_snapshot,
42 write_tag,
43 )
44
45
46 # ---------------------------------------------------------------------------
47 # Fixtures
48 # ---------------------------------------------------------------------------
49
50
51 @pytest.fixture
52 def repo(tmp_path: pathlib.Path) -> pathlib.Path:
53 dot_muse = muse_dir(tmp_path)
54 (dot_muse / "commits").mkdir(parents=True)
55 (dot_muse / "snapshots").mkdir(parents=True)
56 (dot_muse / "tags").mkdir(parents=True)
57 (dot_muse / "refs" / "heads").mkdir(parents=True)
58 return tmp_path
59
60
61 def _now() -> datetime.datetime:
62 return datetime.datetime.now(datetime.timezone.utc)
63
64
65 _SNAP_ID: str = compute_snapshot_id({})
66
67
68 def _commit(
69 label: str = "default",
70 branch: str = "main",
71 parent: str | None = None,
72 ) -> CommitRecord:
73 """Create a CommitRecord with a real content-addressed commit_id."""
74 committed_at = _now()
75 cid = compute_commit_id(
76 parent_ids=[parent] if parent else [],
77 snapshot_id=_SNAP_ID,
78 message=f"commit {label}",
79 committed_at_iso=committed_at.isoformat(),
80 )
81 return CommitRecord(
82 commit_id=cid,
83 repo_id="test-repo",
84 branch=branch,
85 snapshot_id=_SNAP_ID,
86 message=f"commit {label}",
87 committed_at=committed_at,
88 parent_commit_id=parent,
89 )
90
91
92 # ===========================================================================
93 # CommitRecord round-trip
94 # ===========================================================================
95
96
97 class TestCommitRecordRoundTrip:
98 def test_minimal_round_trip(self) -> None:
99 c = _commit()
100 restored = CommitRecord.from_dict(c.to_dict())
101 assert restored.commit_id == c.commit_id
102 assert restored.branch == c.branch
103 assert restored.message == c.message
104
105 def test_all_provenance_fields_preserved(self) -> None:
106 c = CommitRecord(
107 commit_id="prov123",
108 repo_id="test-repo",
109 branch="main",
110 snapshot_id="snap",
111 message="provenance commit",
112 committed_at=_now(),
113 agent_id="claude-v4",
114 model_id="claude-3-5-sonnet",
115 toolchain_id="muse-cli-1.0",
116 prompt_hash="abc" * 10 + "ab",
117 signature=f"sig-{'x' * 60}",
118 signer_key_id="key-001",
119 )
120 d = c.to_dict()
121 restored = CommitRecord.from_dict(d)
122 assert restored.agent_id == "claude-v4"
123 assert restored.model_id == "claude-3-5-sonnet"
124 assert restored.toolchain_id == "muse-cli-1.0"
125 assert restored.signature == c.signature
126 assert restored.signer_key_id == "key-001"
127
128 def test_crdt_fields_preserved(self) -> None:
129 c = CommitRecord(
130 commit_id="crdt123",
131 repo_id="test-repo",
132 branch="main",
133 snapshot_id="snap",
134 message="crdt",
135 committed_at=_now(),
136 reviewed_by=["alice", "bob", "charlie"],
137 test_runs=42,
138 )
139 d = c.to_dict()
140 restored = CommitRecord.from_dict(d)
141 assert sorted(restored.reviewed_by) == ["alice", "bob", "charlie"]
142 assert restored.test_runs == 42
143
144 def test_sem_ver_bump_preserved(self) -> None:
145 bumps: tuple[SemVerBump, ...] = ("none", "patch", "minor", "major")
146 for bump in bumps:
147 c = CommitRecord(
148 commit_id="sv",
149 repo_id="test-repo",
150 branch="main",
151 snapshot_id="s",
152 message="m",
153 committed_at=_now(),
154 sem_ver_bump=bump,
155 )
156 assert CommitRecord.from_dict(c.to_dict()).sem_ver_bump == bump
157
158 def test_breaking_changes_preserved(self) -> None:
159 c = CommitRecord(
160 commit_id="bc",
161 repo_id="test-repo",
162 branch="main",
163 snapshot_id="s",
164 message="m",
165 committed_at=_now(),
166 breaking_changes=["removed `old_api`", "renamed `foo` → `bar`"],
167 )
168 restored = CommitRecord.from_dict(c.to_dict())
169 assert restored.breaking_changes == ["removed `old_api`", "renamed `foo` → `bar`"]
170
171 def test_parent_ids_preserved(self) -> None:
172 c = CommitRecord(
173 commit_id="merge",
174 repo_id="test-repo",
175 branch="main",
176 snapshot_id="s",
177 message="m",
178 committed_at=_now(),
179 parent_commit_id="parent-1",
180 parent2_commit_id="parent-2",
181 )
182 restored = CommitRecord.from_dict(c.to_dict())
183 assert restored.parent_commit_id == "parent-1"
184 assert restored.parent2_commit_id == "parent-2"
185
186 def test_missing_crdt_fields_default_correctly(self) -> None:
187 """Simulates reading an older commit that lacks reviewed_by / test_runs."""
188 minimal: CommitDict = {
189 "commit_id": "old",
190 "repo_id": "r",
191 "branch": "main",
192 "snapshot_id": "snap",
193 "message": "old commit",
194 "committed_at": _now().isoformat(),
195 }
196 restored = CommitRecord.from_dict(minimal)
197 assert restored.reviewed_by == []
198 assert restored.test_runs == 0
199
200 def test_committed_at_timezone_aware(self) -> None:
201 c = _commit()
202 restored = CommitRecord.from_dict(c.to_dict())
203 assert restored.committed_at.tzinfo is not None
204
205
206 # ===========================================================================
207 # CommitRecord persistence
208 # ===========================================================================
209
210
211 class TestCommitPersistence:
212 def test_write_and_read_back(self, repo: pathlib.Path) -> None:
213 c = _commit("id001")
214 write_commit(repo, c)
215 restored = read_commit(repo, c.commit_id)
216 assert restored is not None
217 assert restored.commit_id == c.commit_id
218
219 def test_write_is_idempotent(self, repo: pathlib.Path) -> None:
220 c = _commit("id002")
221 write_commit(repo, c)
222 # Write the same commit again — the store must not corrupt it.
223 write_commit(repo, c)
224 restored = read_commit(repo, c.commit_id)
225 assert restored is not None
226 assert restored.message == c.message
227
228 def test_read_absent_commit_returns_none(self, repo: pathlib.Path) -> None:
229 assert read_commit(repo, fake_id("does-not-exist")) is None
230
231 def test_overwrite_commit_updates_reviewed_by(self, repo: pathlib.Path) -> None:
232 c = _commit("id003")
233 write_commit(repo, c)
234 # Simulate ORSet merge: add reviewer.
235 updated = read_commit(repo, c.commit_id)
236 assert updated is not None
237 updated.reviewed_by = ["agent-x", "human-bob"]
238 overwrite_commit(repo, updated)
239 restored = read_commit(repo, c.commit_id)
240 assert restored is not None
241 assert "agent-x" in restored.reviewed_by
242 assert "human-bob" in restored.reviewed_by
243
244 def test_overwrite_commit_updates_test_runs(self, repo: pathlib.Path) -> None:
245 c = _commit("id004")
246 write_commit(repo, c)
247 for expected in range(1, 6):
248 rec = read_commit(repo, c.commit_id)
249 assert rec is not None
250 rec.test_runs += 1
251 overwrite_commit(repo, rec)
252 after = read_commit(repo, c.commit_id)
253 assert after is not None
254 assert after.test_runs == expected
255
256 def test_list_commits_returns_all_written(self, repo: pathlib.Path) -> None:
257 commits = [_commit(f"c{i:04d}") for i in range(20)]
258 for c in commits:
259 write_commit(repo, c)
260 found = {c.commit_id for c in get_all_commits(repo)}
261 for c in commits:
262 assert c.commit_id in found
263
264 def test_many_commits_all_retrievable(self, repo: pathlib.Path) -> None:
265 real_ids: list[str] = []
266 prev: str | None = None
267 base_ts = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
268 for i in range(100):
269 committed_at = base_ts + datetime.timedelta(seconds=i)
270 cid = compute_commit_id(
271 parent_ids=[prev] if prev else [],
272 snapshot_id=_SNAP_ID,
273 message=f"stress-{i:04d}",
274 committed_at_iso=committed_at.isoformat(),
275 )
276 write_commit(repo, CommitRecord(
277 commit_id=cid,
278 repo_id="test-repo",
279 branch="main",
280 snapshot_id=_SNAP_ID,
281 message=f"stress-{i:04d}",
282 committed_at=committed_at,
283 parent_commit_id=prev,
284 ))
285 real_ids.append(cid)
286 prev = cid
287 for cid in real_ids:
288 assert read_commit(repo, cid) is not None
289
290
291 # ===========================================================================
292 # SnapshotRecord
293 # ===========================================================================
294
295
296 class TestSnapshotRecordRoundTrip:
297 def test_minimal_round_trip(self) -> None:
298 s = SnapshotRecord(snapshot_id="snap-1", manifest={"f.mid": "hash1"})
299 restored = SnapshotRecord.from_dict(s.to_dict())
300 assert restored.snapshot_id == "snap-1"
301 assert restored.manifest == {"f.mid": "hash1"}
302
303 def test_large_manifest(self) -> None:
304 manifest = {f"track_{i:04d}.mid": f"hash-{i:064d}" for i in range(500)}
305 s = SnapshotRecord(snapshot_id="big-snap", manifest=manifest)
306 restored = SnapshotRecord.from_dict(s.to_dict())
307 assert len(restored.manifest) == 500
308 assert restored.manifest["track_0000.mid"] == f"hash-{0:064d}"
309
310 def test_write_and_read_back(self, repo: pathlib.Path) -> None:
311 manifest = {"a.mid": fake_id("a.mid-content"), "b.mid": fake_id("b.mid-content")}
312 snap_id = compute_snapshot_id(manifest)
313 s = SnapshotRecord(snapshot_id=snap_id, manifest=manifest)
314 write_snapshot(repo, s)
315 restored = read_snapshot(repo, snap_id)
316 assert restored is not None
317 assert restored.manifest == manifest
318
319 def test_empty_manifest_round_trip(self) -> None:
320 s = SnapshotRecord(snapshot_id="empty-snap", manifest={})
321 restored = SnapshotRecord.from_dict(s.to_dict())
322 assert restored.manifest == {}
323
324
325 # ===========================================================================
326 # TagRecord
327 # ===========================================================================
328
329
330 class TestTagRecord:
331 def test_round_trip(self) -> None:
332 t = TagRecord(
333 tag_id="tag-001",
334 repo_id="test-repo",
335 commit_id="abc123",
336 tag="v1.0.0",
337 )
338 restored = TagRecord.from_dict(t.to_dict())
339 assert restored.tag_id == "tag-001"
340 assert restored.tag == "v1.0.0"
341 assert restored.commit_id == "abc123"
342
343 def test_write_and_list(self, repo: pathlib.Path) -> None:
344 for i in range(10):
345 write_tag(repo, TagRecord(
346 tag_id=fake_id(f"tag-{i:04d}"),
347 repo_id=fake_id("repo"),
348 commit_id=fake_id(f"commit-{i:04d}"),
349 tag=f"v{i}.0.0",
350 ))
351 tags = get_all_tags(repo, fake_id("repo"))
352 assert len(tags) == 10
353
354 def test_created_at_preserved(self) -> None:
355 ts = datetime.datetime(2025, 6, 15, 12, 0, 0, tzinfo=datetime.timezone.utc)
356 t = TagRecord(tag_id="t", repo_id="r", commit_id="c", tag="v1", created_at=ts)
357 restored = TagRecord.from_dict(t.to_dict())
358 assert abs((restored.created_at - ts).total_seconds()) < 1.0
359
360
361 # ===========================================================================
362 # get_head_commit_id
363 # ===========================================================================
364
365
366 class TestGetHeadCommitId:
367 def test_empty_branch_returns_none(self, repo: pathlib.Path) -> None:
368 assert get_head_commit_id(repo, "nonexistent-branch") is None
369
370 def test_returns_id_after_writing_head_ref(self, repo: pathlib.Path) -> None:
371 cid = long_id("a" * 64)
372 ref_path(repo, "main").write_text(f"{cid}\n")
373 assert get_head_commit_id(repo, "main") == cid
374
375 def test_strips_whitespace(self, repo: pathlib.Path) -> None:
376 cid = long_id("b" * 64)
377 ref_path(repo, "feature").write_text(f" {cid} \n")
378 assert get_head_commit_id(repo, "feature") == cid
379
380
381 # ===========================================================================
382 # CRDT semantics on CommitRecord fields
383 # ===========================================================================
384
385
386 class TestCRDTAnnotationSemantics:
387 def test_reviewed_by_orset_union_semantics(self, repo: pathlib.Path) -> None:
388 """ORSet union: multiple overwrite_commit calls accumulate reviewers."""
389 c = _commit("crdt-or-001")
390 write_commit(repo, c)
391
392 # Agent 1 adds their name.
393 rec = read_commit(repo, c.commit_id)
394 assert rec is not None
395 s, tok1 = ORSet().add("agent-alpha")
396 rec.reviewed_by = list(s.elements())
397 overwrite_commit(repo, rec)
398
399 # Agent 2 independently adds their name.
400 rec2 = read_commit(repo, c.commit_id)
401 assert rec2 is not None
402 s2 = ORSet()
403 for name in rec2.reviewed_by:
404 s2, _ = s2.add(name)
405 s2, tok2 = s2.add("agent-beta")
406 rec2.reviewed_by = sorted(s2.elements())
407 overwrite_commit(repo, rec2)
408
409 final = read_commit(repo, c.commit_id)
410 assert final is not None
411 assert "agent-alpha" in final.reviewed_by
412 assert "agent-beta" in final.reviewed_by
413
414 def test_test_runs_gcounter_monotone(self, repo: pathlib.Path) -> None:
415 """GCounter: test_runs must never decrease."""
416 c = _commit("crdt-gc-001")
417 write_commit(repo, c)
418 prev = 0
419 for _ in range(50):
420 rec = read_commit(repo, c.commit_id)
421 assert rec is not None
422 rec.test_runs += 1
423 overwrite_commit(repo, rec)
424 current = read_commit(repo, c.commit_id)
425 assert current is not None
426 assert current.test_runs >= prev
427 prev = current.test_runs
428 assert prev == 50
429
430 def test_all_provenance_fields_default_to_empty_string(self) -> None:
431 c = _commit()
432 assert c.agent_id == ""
433 assert c.model_id == ""
434 assert c.toolchain_id == ""
435 assert c.prompt_hash == ""
436 assert c.signature == ""
437 assert c.signer_key_id == ""
File History 1 commit
sha256:51ce277f663e01a43eaffbe77509b1de7ac2d4251b55d23306304bcdeb92c90d feat(pack): delta-encode snapshots in MPackBundle wire format Sonnet 4.6 minor 122 days ago