gabriel / muse public
test_cmd_cat.py python
603 lines 24.1 KB
Raw
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago
1 """Comprehensive tests for ``muse code cat``.
2
3 Coverage
4 --------
5 Unit
6 _extract_source — basic slice, context lines, unicode, binary-safe
7 _format_line_numbers — numbering, width padding, first-line offset
8 _resolve_symbol — qualified match, bare-name match, ambiguous, missing
9 _get_file_bytes — workdir read, object-store fallback, not-in-manifest
10
11 Integration
12 cat ADDRESS — found, missing, no "::", JSON output
13 cat --all — all symbols in file, kind filter
14 cat --at REF — historical snapshot
15 cat --context N — surrounding lines appear
16 cat --line-numbers — line numbers prefix
17 cat --json — schema, errors list, unicode
18 cat multiple addresses — batch lookup, partial errors
19 cat untracked file — exits 1
20
21 Security
22 sanitize_display — control chars in address do not crash
23 missing repo — exits non-zero outside repo
24
25 Stress
26 file with 200 symbols — --all completes in < 5 s
27 50 addresses in one call — batch under 3 s
28 """
29
30 from __future__ import annotations
31
32 import json
33 import pathlib
34 import textwrap
35 import time
36
37 import pytest
38
39 from typing import Literal
40
41 from tests.cli_test_helper import CliRunner
42 from muse.cli.commands.cat import (
43 _FileError,
44 _extract_source,
45 _format_line_numbers,
46 _get_file_bytes,
47 _resolve_symbol,
48 )
49 from muse.plugins.code.ast_parser import SymbolRecord, SymbolKind
50
51 cli = None
52 runner = CliRunner()
53
54
55 # ---------------------------------------------------------------------------
56 # Helpers
57 # ---------------------------------------------------------------------------
58
59
60 def _make_record(
61 qualified_name: str,
62 name: str,
63 lineno: int,
64 end_lineno: int,
65 kind: SymbolKind = "function",
66 ) -> SymbolRecord:
67 return SymbolRecord(
68 name=name,
69 qualified_name=qualified_name,
70 kind=kind,
71 lineno=lineno,
72 end_lineno=end_lineno,
73 content_id="a" * 64,
74 body_hash="b" * 64,
75 signature_id="c" * 64,
76 metadata_id="",
77 canonical_key=f"mod.py###{kind}#{name}#{lineno}",
78 )
79
80
81 # ---------------------------------------------------------------------------
82 # Shared repo fixture
83 # ---------------------------------------------------------------------------
84
85
86 @pytest.fixture
87 def repo(tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch) -> pathlib.Path:
88 monkeypatch.chdir(tmp_path)
89 monkeypatch.setenv("MUSE_REPO_ROOT", str(tmp_path))
90 r = runner.invoke(cli, ["init", "--domain", "code"])
91 assert r.exit_code == 0, r.output
92
93 (tmp_path / "billing.py").write_text(textwrap.dedent("""\
94 class Invoice:
95 def compute_total(self, items: list[int]) -> int:
96 return sum(items)
97
98 def apply_discount(self, total: float, pct: float) -> float:
99 return total * (1 - pct)
100
101 def validate_amount(amount: float) -> bool:
102 return amount > 0
103
104 def format_receipt(amount: float) -> str:
105 return f"Total: {amount:.2f}"
106 """))
107
108 r2 = runner.invoke(cli, ["commit", "-m", "initial"])
109 assert r2.exit_code == 0, r2.output
110 return tmp_path
111
112
113 # ---------------------------------------------------------------------------
114 # Unit — _extract_source
115 # ---------------------------------------------------------------------------
116
117
118 class TestExtractSource:
119 _SOURCE = b"line1\nline2\nline3\nline4\nline5\n"
120
121 def test_basic_slice(self) -> None:
122 result = _extract_source(self._SOURCE, lineno=2, end_lineno=3)
123 assert result == "line2\nline3"
124
125 def test_single_line(self) -> None:
126 result = _extract_source(self._SOURCE, lineno=1, end_lineno=1)
127 assert result == "line1"
128
129 def test_context_before(self) -> None:
130 result = _extract_source(self._SOURCE, lineno=3, end_lineno=3, context=1)
131 assert "line2" in result
132 assert "line3" in result
133
134 def test_context_after(self) -> None:
135 result = _extract_source(self._SOURCE, lineno=3, end_lineno=3, context=1)
136 assert "line4" in result
137
138 def test_context_clamps_at_start(self) -> None:
139 # Asking for 10 lines of context before line 1 must not go negative.
140 result = _extract_source(self._SOURCE, lineno=1, end_lineno=1, context=10)
141 assert "line1" in result
142
143 def test_context_clamps_at_end(self) -> None:
144 result = _extract_source(self._SOURCE, lineno=5, end_lineno=5, context=10)
145 assert "line5" in result
146
147 def test_unicode_round_trips(self) -> None:
148 src = "def café() -> str:\n return 'café'\n".encode()
149 result = _extract_source(src, lineno=1, end_lineno=2)
150 assert "café" in result
151
152 def test_binary_errors_replaced(self) -> None:
153 src = b"def foo():\n x = \xff\xfe\n"
154 result = _extract_source(src, lineno=1, end_lineno=2)
155 assert "foo" in result # must not raise
156
157
158 # ---------------------------------------------------------------------------
159 # Unit — _format_line_numbers
160 # ---------------------------------------------------------------------------
161
162
163 class TestFormatLineNumbers:
164 def test_single_line_numbered(self) -> None:
165 result = _format_line_numbers("hello", start_lineno=5)
166 assert result.startswith("5")
167 assert "hello" in result
168
169 def test_multiline_numbered(self) -> None:
170 source = "a\nb\nc"
171 result = _format_line_numbers(source, start_lineno=1)
172 lines = result.splitlines()
173 assert len(lines) == 3
174 assert lines[0].startswith("1")
175 assert lines[2].startswith("3")
176
177 def test_width_pads_for_large_line_numbers(self) -> None:
178 # 100 lines → width=3; the separator " " appears at offset 3 for every line.
179 source = "\n".join(f"line_{i}" for i in range(100))
180 result = _format_line_numbers(source, start_lineno=1)
181 expected_width = len(str(100)) # 3
182 for line in result.splitlines():
183 sep = line[expected_width : expected_width + 2]
184 assert sep == " ", f"separator not at col {expected_width} in {line!r}"
185
186 def test_offset_start_lineno(self) -> None:
187 result = _format_line_numbers("hello", start_lineno=42)
188 assert result.startswith("42")
189
190
191 # ---------------------------------------------------------------------------
192 # Unit — _resolve_symbol
193 # ---------------------------------------------------------------------------
194
195
196 class TestResolveSymbol:
197 def test_qualified_name_match(self) -> None:
198 tree = {
199 "mod.py::MyClass.my_method": _make_record("MyClass.my_method", "my_method", 5, 7),
200 }
201 record, err = _resolve_symbol(tree, "MyClass.my_method", "mod.py")
202 assert record is not None
203 assert err == ""
204
205 def test_bare_name_unambiguous(self) -> None:
206 tree = {
207 "mod.py::my_func": _make_record("my_func", "my_func", 1, 3),
208 }
209 record, err = _resolve_symbol(tree, "my_func", "mod.py")
210 assert record is not None
211
212 def test_bare_name_ambiguous_returns_error(self) -> None:
213 tree = {
214 "mod.py::A.validate": _make_record("A.validate", "validate", 1, 2),
215 "mod.py::B.validate": _make_record("B.validate", "validate", 5, 6),
216 }
217 record, err = _resolve_symbol(tree, "validate", "mod.py")
218 assert record is None
219 assert "ambiguous" in err.lower() or "qualify" in err.lower()
220
221 def test_not_found_returns_error_message(self) -> None:
222 tree = {
223 "mod.py::existing": _make_record("existing", "existing", 1, 3),
224 }
225 record, err = _resolve_symbol(tree, "missing_func", "mod.py")
226 assert record is None
227 assert "not found" in err.lower() or "missing_func" in err
228
229 def test_empty_tree_returns_error(self) -> None:
230 record, err = _resolve_symbol({}, "anything", "mod.py")
231 assert record is None
232 assert len(err) > 0
233
234 def test_import_symbols_excluded_from_suggestions(self) -> None:
235 """Import pseudo-symbols must not show up as 'available' options."""
236 tree = {
237 "mod.py::import::os": _make_record("import::os", "os", 1, 1, kind="import"),
238 }
239 record, err = _resolve_symbol(tree, "missing", "mod.py")
240 assert record is None
241 assert "import::os" not in err
242
243
244 # ---------------------------------------------------------------------------
245 # Integration — basic address lookup
246 # ---------------------------------------------------------------------------
247
248
249 class TestCatBasic:
250 def test_finds_top_level_function(self, repo: pathlib.Path) -> None:
251 result = runner.invoke(cli, ["code", "cat", "billing.py::validate_amount"])
252 assert result.exit_code == 0, result.output
253 assert "validate_amount" in result.output
254
255 def test_shows_function_body(self, repo: pathlib.Path) -> None:
256 result = runner.invoke(cli, ["code", "cat", "billing.py::validate_amount"])
257 assert result.exit_code == 0
258 assert "amount > 0" in result.output
259
260 def test_finds_method(self, repo: pathlib.Path) -> None:
261 result = runner.invoke(cli, ["code", "cat", "billing.py::Invoice.compute_total"])
262 assert result.exit_code == 0
263 assert "compute_total" in result.output
264
265 def test_missing_symbol_exits_one(self, repo: pathlib.Path) -> None:
266 result = runner.invoke(cli, ["code", "cat", "billing.py::zzz_nonexistent"])
267 assert result.exit_code == 1
268
269 def test_no_separator_exits_one(self, repo: pathlib.Path) -> None:
270 result = runner.invoke(cli, ["code", "cat", "billing.py"])
271 assert result.exit_code == 1
272
273 def test_untracked_file_exits_one(self, repo: pathlib.Path) -> None:
274 result = runner.invoke(cli, ["code", "cat", "nowhere.py::foo"])
275 assert result.exit_code == 1
276
277
278 # ---------------------------------------------------------------------------
279 # Integration — --all mode
280 # ---------------------------------------------------------------------------
281
282
283 class TestCatFileFlag:
284 """--file <path> is a convenience alias for <path> --all."""
285
286 def test_file_flag_prints_all_symbols(self, repo: pathlib.Path) -> None:
287 result = runner.invoke(cli, ["code", "cat", "--file", "billing.py"])
288 assert result.exit_code == 0
289 assert "validate_amount" in result.output
290 assert "format_receipt" in result.output
291 assert "compute_total" in result.output
292
293 def test_file_flag_accepts_kind_filter(self, repo: pathlib.Path) -> None:
294 result = runner.invoke(cli, ["code", "cat", "--file", "billing.py", "--kind", "function"])
295 assert result.exit_code == 0
296 assert "validate_amount" in result.output
297
298 def test_file_flag_json_output(self, repo: pathlib.Path) -> None:
299 result = runner.invoke(cli, ["code", "cat", "--file", "billing.py", "--json"])
300 assert result.exit_code == 0
301 data = json.loads(result.output)
302 assert "results" in data
303 names = [r["symbol"] for r in data["results"]]
304 assert "validate_amount" in names
305
306 def test_file_flag_untracked_file_errors(self, repo: pathlib.Path) -> None:
307 result = runner.invoke(cli, ["code", "cat", "--file", "missing.py"])
308 assert result.exit_code != 0
309
310
311 class TestCatAll:
312 def test_all_prints_every_non_import_symbol(self, repo: pathlib.Path) -> None:
313 result = runner.invoke(cli, ["code", "cat", "--all", "billing.py"])
314 assert result.exit_code == 0
315 assert "validate_amount" in result.output
316 assert "format_receipt" in result.output
317 assert "compute_total" in result.output
318
319 def test_all_kind_filter_functions_only(self, repo: pathlib.Path) -> None:
320 result = runner.invoke(cli, ["code", "cat", "--all", "--kind", "function", "billing.py"])
321 assert result.exit_code == 0
322 assert "validate_amount" in result.output
323 # Classes should not appear as their own block (only functions).
324
325 def test_all_untracked_file_skips_gracefully(self, repo: pathlib.Path) -> None:
326 result = runner.invoke(cli, ["code", "cat", "--all", "missing.py"])
327 # Should exit with error since file not in manifest.
328 assert result.exit_code != 0 or "not tracked" in result.output.lower()
329
330
331 # ---------------------------------------------------------------------------
332 # Integration — --line-numbers and --context
333 # ---------------------------------------------------------------------------
334
335
336 class TestCatLineNumbers:
337 def test_line_numbers_flag(self, repo: pathlib.Path) -> None:
338 result = runner.invoke(cli, [
339 "code", "cat", "--line-numbers", "billing.py::validate_amount",
340 ])
341 assert result.exit_code == 0
342 # Some line in the output should start with a digit.
343 output_lines = result.output.splitlines()
344 has_number = any(line.strip() and line.strip()[0].isdigit() for line in output_lines)
345 assert has_number
346
347 def test_context_includes_surrounding_lines(self, repo: pathlib.Path) -> None:
348 result = runner.invoke(cli, [
349 "code", "cat", "--context", "2", "billing.py::validate_amount",
350 ])
351 assert result.exit_code == 0
352 # With context=2 the preceding lines of the file should appear.
353 assert len(result.output.splitlines()) > 2
354
355
356 # ---------------------------------------------------------------------------
357 # Integration — --json
358 # ---------------------------------------------------------------------------
359
360
361 class TestCatJson:
362 def test_json_schema(self, repo: pathlib.Path) -> None:
363 result = runner.invoke(cli, ["code", "cat", "--json", "billing.py::validate_amount"])
364 assert result.exit_code == 0, result.output
365 data = json.loads(result.output)
366 assert "results" in data
367 assert "errors" in data
368 assert len(data["results"]) == 1
369
370 def test_json_result_fields(self, repo: pathlib.Path) -> None:
371 result = runner.invoke(cli, ["code", "cat", "--json", "billing.py::validate_amount"])
372 data = json.loads(result.output)
373 r = data["results"][0]
374 for field in ("address", "source", "kind", "lineno", "end_lineno"):
375 assert field in r, f"missing field {field!r}"
376
377 def test_json_missing_symbol_in_errors(self, repo: pathlib.Path) -> None:
378 result = runner.invoke(cli, ["code", "cat", "--json", "billing.py::zzz_missing"])
379 data = json.loads(result.output)
380 assert len(data["errors"]) == 1
381 assert "zzz_missing" in data["errors"][0].get("error", "")
382
383 def test_json_multiple_results(self, repo: pathlib.Path) -> None:
384 result = runner.invoke(cli, [
385 "code", "cat", "--json",
386 "billing.py::validate_amount",
387 "billing.py::format_receipt",
388 ])
389 data = json.loads(result.output)
390 assert len(data["results"]) == 2
391
392 def test_json_partial_error(self, repo: pathlib.Path) -> None:
393 result = runner.invoke(cli, [
394 "code", "cat", "--json",
395 "billing.py::validate_amount",
396 "billing.py::zzz_missing",
397 ])
398 data = json.loads(result.output)
399 assert len(data["results"]) == 1
400 assert len(data["errors"]) == 1
401
402 def test_json_has_elapsed_seconds(self, repo: pathlib.Path) -> None:
403 result = runner.invoke(cli, ["code", "cat", "--json", "billing.py::validate_amount"])
404 assert result.exit_code == 0
405 data = json.loads(result.output)
406 assert "elapsed_seconds" in data
407 assert isinstance(data["elapsed_seconds"], float)
408 assert data["elapsed_seconds"] >= 0.0
409
410 def test_json_has_source_ref(self, repo: pathlib.Path) -> None:
411 result = runner.invoke(cli, ["code", "cat", "--json", "billing.py::validate_amount"])
412 data = json.loads(result.output)
413 assert "source_ref" in data
414 assert data["source_ref"] == "working tree"
415
416 def test_format_json_flag(self, repo: pathlib.Path) -> None:
417 """--format json is equivalent to --json."""
418 result = runner.invoke(cli, [
419 "code", "cat", "--format", "json", "billing.py::validate_amount",
420 ])
421 assert result.exit_code == 0
422 data = json.loads(result.output)
423 assert "results" in data
424
425 def test_format_text_is_default(self, repo: pathlib.Path) -> None:
426 """Default (no flag) produces text output, not JSON."""
427 result = runner.invoke(cli, ["code", "cat", "billing.py::validate_amount"])
428 assert result.exit_code == 0
429 # Text output starts with a '#' header, not a JSON brace.
430 assert result.output.strip().startswith("#")
431
432 def test_json_error_has_error_code(self, repo: pathlib.Path) -> None:
433 """Every error entry in JSON output must have an error_code field."""
434 result = runner.invoke(cli, [
435 "code", "cat", "--json",
436 "billing.py::zzz_missing",
437 "nowhere.py::foo",
438 ])
439 data = json.loads(result.output)
440 for err in data["errors"]:
441 assert "error_code" in err, f"error_code missing from {err}"
442
443
444 # ---------------------------------------------------------------------------
445 # Integration — --at historical snapshot
446 # ---------------------------------------------------------------------------
447
448
449 class TestCatAtRef:
450 def test_at_head_works(self, repo: pathlib.Path) -> None:
451 result = runner.invoke(cli, [
452 "code", "cat", "--at", "HEAD", "billing.py::validate_amount",
453 ])
454 assert result.exit_code == 0, result.output
455 assert "validate_amount" in result.output
456
457 def test_at_bad_ref_exits_one(self, repo: pathlib.Path) -> None:
458 result = runner.invoke(cli, [
459 "code", "cat", "--at", "zzz_bad_ref_xyz",
460 "billing.py::validate_amount",
461 ])
462 assert result.exit_code == 1
463
464
465 # ---------------------------------------------------------------------------
466 # Security
467 # ---------------------------------------------------------------------------
468
469
470 class TestCatSecurity:
471 def test_requires_repo(
472 self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
473 ) -> None:
474 monkeypatch.chdir(tmp_path)
475 monkeypatch.delenv("MUSE_REPO_ROOT", raising=False)
476 result = runner.invoke(cli, ["code", "cat", "billing.py::foo"])
477 assert result.exit_code != 0
478
479 def test_control_chars_in_address_do_not_crash(self, repo: pathlib.Path) -> None:
480 result = runner.invoke(cli, ["code", "cat", "billing.py::foo\x01bar"])
481 assert result.exit_code in (0, 1) # must not raise unhandled exception
482
483 def test_symlink_workdir_rejected(
484 self, repo: pathlib.Path, monkeypatch: pytest.MonkeyPatch
485 ) -> None:
486 """A tracked file that is actually a symlink must be rejected."""
487 # Create a real file so the manifest knows about it, then replace with a symlink.
488 real = repo / "billing.py"
489 link = repo / "link.py"
490 link.symlink_to(real)
491 # Inject the symlink path into a fake manifest and call _get_file_bytes directly.
492 fake_manifest = {"link.py": "a" * 64}
493 with pytest.raises(_FileError) as exc_info:
494 _get_file_bytes(repo, "link.py", fake_manifest, source_is_workdir=True)
495 assert exc_info.value.code == "SYMLINK_REJECTED"
496
497 def test_path_traversal_rejected(
498 self, repo: pathlib.Path, monkeypatch: pytest.MonkeyPatch
499 ) -> None:
500 """A manifest entry with '..' that escapes the repo must be rejected."""
501 fake_manifest = {"../outside.py": "a" * 64}
502 with pytest.raises(_FileError) as exc_info:
503 _get_file_bytes(repo, "../outside.py", fake_manifest, source_is_workdir=True)
504 assert exc_info.value.code in ("PATH_TRAVERSAL", "FILE_NOT_TRACKED")
505
506 def test_blob_not_found_gives_precise_error_code(
507 self, repo: pathlib.Path
508 ) -> None:
509 """Missing blob raises _FileError with BLOB_NOT_FOUND, not generic exit."""
510 fake_manifest = {"billing.py": "0" * 64} # blob that doesn't exist in store
511 with pytest.raises(_FileError) as exc_info:
512 _get_file_bytes(repo, "billing.py", fake_manifest, source_is_workdir=False)
513 assert exc_info.value.code == "BLOB_NOT_FOUND"
514
515 def test_symlink_in_json_gives_error_code(self, repo: pathlib.Path) -> None:
516 """Symlink rejection surfaces as a JSON error, not a crash."""
517 link = repo / "symlink_billing.py"
518 link.symlink_to(repo / "billing.py")
519 # Commit so symlink_billing.py appears in the manifest (won't — symlinks
520 # are not tracked by the code plugin, so we test via _all_ on an untracked path).
521 result = runner.invoke(cli, ["code", "cat", "--json", "symlink_billing.py::foo"])
522 # Either exit 0 with an error in the errors list, or exit 1 — never a crash.
523 assert result.exit_code in (0, 1)
524 try:
525 data = json.loads(result.output)
526 # If JSON, errors list must be non-empty or results non-empty.
527 assert isinstance(data, dict)
528 except json.JSONDecodeError:
529 pass # text-mode output is also acceptable here
530
531
532 # ---------------------------------------------------------------------------
533 # Stress
534 # ---------------------------------------------------------------------------
535
536
537 class TestCatStress:
538 @pytest.fixture
539 def large_repo(
540 self, tmp_path: pathlib.Path, monkeypatch: pytest.MonkeyPatch
541 ) -> pathlib.Path:
542 monkeypatch.chdir(tmp_path)
543 monkeypatch.setenv("MUSE_REPO_ROOT", str(tmp_path))
544 runner.invoke(cli, ["init", "--domain", "code"])
545
546 lines: list[str] = []
547 for i in range(200):
548 lines.append(f"def symbol_{i:04d}(x: int) -> int:")
549 lines.append(f" return x + {i}")
550 lines.append("")
551 (tmp_path / "big.py").write_text("\n".join(lines))
552
553 r = runner.invoke(cli, ["commit", "-m", "big module"])
554 assert r.exit_code == 0, r.output
555 return tmp_path
556
557 def test_all_200_symbols_under_5s(self, large_repo: pathlib.Path) -> None:
558 start = time.monotonic()
559 result = runner.invoke(cli, ["code", "cat", "--all", "big.py"])
560 elapsed = time.monotonic() - start
561 assert result.exit_code == 0, result.output
562 assert elapsed < 5.0, f"--all on 200 symbols took {elapsed:.2f}s"
563 assert "symbol_0000" in result.output
564 assert "symbol_0199" in result.output
565
566 def test_50_addresses_batch_under_5s(self, large_repo: pathlib.Path) -> None:
567 addresses = [f"big.py::symbol_{i:04d}" for i in range(50)]
568 start = time.monotonic()
569 result = runner.invoke(cli, ["code", "cat", "--json"] + addresses)
570 elapsed = time.monotonic() - start
571 assert result.exit_code == 0, result.output
572 assert elapsed < 5.0, f"50-address batch took {elapsed:.2f}s"
573 data = json.loads(result.output)
574 assert len(data["results"]) == 50
575
576 def test_all_json_200_symbols_schema_valid(self, large_repo: pathlib.Path) -> None:
577 result = runner.invoke(cli, ["code", "cat", "--all", "--json", "big.py"])
578 assert result.exit_code == 0, result.output
579 data = json.loads(result.output)
580 assert len(data["results"]) == 200
581 for r in data["results"]:
582 assert "source" in r
583 assert "lineno" in r
584
585 def test_file_cache_batch_same_file_under_2s(self, large_repo: pathlib.Path) -> None:
586 """50 addresses to the same file should benefit from caching: one read, one parse."""
587 addresses = [f"big.py::symbol_{i:04d}" for i in range(50)]
588 start = time.monotonic()
589 result = runner.invoke(cli, ["code", "cat", "--json"] + addresses)
590 elapsed = time.monotonic() - start
591 assert result.exit_code == 0, result.output
592 # With caching, 50 same-file lookups should be fast.
593 assert elapsed < 2.0, f"50 same-file addresses took {elapsed:.2f}s — cache may not be working"
594 data = json.loads(result.output)
595 assert len(data["results"]) == 50
596
597 def test_elapsed_seconds_in_large_batch(self, large_repo: pathlib.Path) -> None:
598 addresses = [f"big.py::symbol_{i:04d}" for i in range(20)]
599 result = runner.invoke(cli, ["code", "cat", "--json"] + addresses)
600 assert result.exit_code == 0
601 data = json.loads(result.output)
602 assert isinstance(data["elapsed_seconds"], float)
603 assert data["elapsed_seconds"] >= 0.0
File History 5 commits
sha256:660fcac1df3ab28f61862e961890bd2ca8b754fa0242079d93ca1e25037ec8a6 chore(tests): add docstring to tests/__init__.py so rc14 tr… Human 26 days ago
sha256:d8316ffae901be06347e16ab55be11868eb519dd16ade3e8aa16a99e662f7e62 baseline: rc14 re-baseline after rc3 store corruption recovery Human patch 26 days ago
sha256:50d413a635f57761c3fce1f70251b957b6423821525bf330747ef4007339222e Merge branch 'dev' into main Human 29 days ago
sha256:fb67fed5a4d3e40de84bdd163de94ef1386570bef1dd1a020a732c8a038962ce Merge branch 'dev' into main Human 48 days ago
sha256:1c4b3e3a9a1f300774c3ee662b572a698d5fd405bf765a71e6011a2e9c3eaaaa feat: Muse — version control for the agent era Human 100 days ago