gabriel / muse public
feat patch snapshot task/supercharge-snapshot #1 / 1
AI Agent gabriel · 161 days ago · Apr 18, 2026 · Diff

feat(snapshot): add elapsed_ms/exit_code envelope, fix sha256: prefix bug, supercharge tests

- Add elapsed_ms and exit_code to all four snapshot JSON outputs (create, list, read, export); list output changes from bare array to object with a 'snapshots' key for consistency with the envelope pattern. - Fix bug in _list_all_snapshots and _resolve_snapshot: both were passing path.stem (bare hex) to read_snapshot, which then compared it against compute_snapshot_id output (sha256:-prefixed) and always failed content-hash verification — silently dropping every snapshot from list and resolve results. Fix: prepend 'sha256:' when calling read_snapshot from these two callers. - Add _SnapshotListJson TypedDict for the new top-level envelope. - Improve docstrings on all TypedDicts and subparser descriptions with full field documentation including elapsed_ms/exit_code. - Add 50-test supercharge suite: JSON envelope, schema completeness, sha256 prefix round-trip regression, data integrity (tar.gz + zip content verify), security (_safe_arcname zip-slip, ANSI injection in note, symlink skip, path traversal rejection), text mode, --prefix export, limit validation, idempotency, list ordering, concurrent stress (8 threads), large-file (5 MiB).

sha256:6b3973c0587bec03356978fd1b61d47f9345e1496c2f87915e3f34aa08a8e69a sha
+80 ~14 symbols
sha256:0310844cbf94619db0f98ed97eab07987f45cd2506853c8d92e8fbd6aac869c5 snapshot
+80
symbols added
~14
symbols modified
0
dead code introduced
Semantic Changes 94 symbols
+ TestConcurrentStress class class TestConcurrentStress L727–758
+ test_concurrent_creates_all_succeed method method test_concurrent_creates_all_succeed L728–758
+ TestDataIntegrity class class TestDataIntegrity L342–416
+ test_export_file_count_matches_snapshot method method test_export_file_count_matches_snapshot L389–402
+ test_export_size_bytes_matches_disk method method test_export_size_bytes_matches_disk L404–416
+ test_tar_gz_content_matches_source method method test_tar_gz_content_matches_source L345–366
+ test_zip_content_matches_source method method test_zip_content_matches_source L368–387
+ TestDefaultFilename class class TestDefaultFilename L800–826
+ test_export_default_filename_is_short_id_dot_format method method test_export_default_filename_is_short_id_dot_format L801–819
+ test_export_not_found_exits_nonzero method method test_export_not_found_exits_nonzero L821–826
+ TestIdempotency class class TestIdempotency L671–698
+ test_different_content_different_snapshot_id method method test_different_content_different_snapshot_id L679–686
+ test_list_shows_only_one_when_idempotent method method test_list_shows_only_one_when_idempotent L688–698
+ test_same_files_same_snapshot_id method method test_same_files_same_snapshot_id L672–677
+ TestJsonEnvelope class class TestJsonEnvelope L85–180
+ test_create_has_elapsed_ms method method test_create_has_elapsed_ms L88–94
+ test_create_has_exit_code_zero method method test_create_has_exit_code_zero L96–100
+ test_export_has_elapsed_ms method method test_export_has_elapsed_ms L151–166
+ test_export_has_exit_code_zero method method test_export_has_exit_code_zero L168–180
+ test_list_empty_has_envelope method method test_list_empty_has_envelope L121–128
+ test_list_has_elapsed_ms method method test_list_has_elapsed_ms L102–111
+ test_list_has_exit_code_zero method method test_list_has_exit_code_zero L113–119
+ test_read_has_elapsed_ms method method test_read_has_elapsed_ms L130–140
+ test_read_has_exit_code_zero method method test_read_has_exit_code_zero L142–149
+ TestJsonSchemaCompleteness class class TestJsonSchemaCompleteness L188–276
+ test_create_schema method method test_create_schema L191–206
+ test_export_schema method method test_export_schema L244–264
+ test_list_schema method method test_list_schema L208–224
+ test_manifest_keys_are_sorted method method test_manifest_keys_are_sorted L266–276
+ test_read_schema method method test_read_schema L226–242
+ TestLargeFileExport class class TestLargeFileExport L766–792
+ test_large_file_round_trips_correctly method method test_large_file_round_trips_correctly L767–792
+ TestLimitValidation class class TestLimitValidation L626–663
+ test_limit_one_returns_at_most_one method method test_limit_one_returns_at_most_one L634–644
+ test_limit_zero_rejected method method test_limit_zero_rejected L627–632
+ test_negative_limit_rejected method method test_negative_limit_rejected L646–651
+ test_short_flag_n_respected method method test_short_flag_n_respected L653–663
+ TestListOrdering class class TestListOrdering L706–719
+ test_list_newest_first method method test_list_newest_first L707–719
+ TestPrefixExport class class TestPrefixExport L566–618
+ test_empty_prefix_uses_flat_layout method method test_empty_prefix_uses_flat_layout L604–618
+ test_tar_gz_files_nested_under_prefix method method test_tar_gz_files_nested_under_prefix L567–581
+ test_zip_files_nested_under_prefix method method test_zip_files_nested_under_prefix L583–602
+ TestSecurity class class TestSecurity L424–504
+ test_ansi_escape_in_note_sanitized_in_text_output method method test_ansi_escape_in_note_sanitized_in_text_output L427–437
+ test_note_appears_sanitized_in_list_text method method test_note_appears_sanitized_in_list_text L439–446
+ test_path_traversal_in_snapshot_id_prefix_is_safe method method test_path_traversal_in_snapshot_id_prefix_is_safe L471–480
+ test_safe_arcname_accepts_normal_path method method test_safe_arcname_accepts_normal_path L495–499
+ test_safe_arcname_rejects_absolute_path method method test_safe_arcname_rejects_absolute_path L489–493
+ test_safe_arcname_rejects_dotdot_in_prefix method method test_safe_arcname_rejects_dotdot_in_prefix L501–504
+ test_safe_arcname_rejects_dotdot_path method method test_safe_arcname_rejects_dotdot_path L482–487
+ test_symlink_in_snapshots_dir_is_skipped method method test_symlink_in_snapshots_dir_is_skipped L448–469
+ TestSha256PrefixRoundTrip class class TestSha256PrefixRoundTrip L284–334
+ test_list_after_create_returns_snapshot method method test_list_after_create_returns_snapshot L290–298
+ test_read_by_full_id_succeeds method method test_read_by_full_id_succeeds L300–306
+ test_read_by_hex_prefix_succeeds method method test_read_by_hex_prefix_succeeds L308–315
+ test_read_by_sha256_prefix_succeeds method method test_read_by_sha256_prefix_succeeds L317–326
+ test_snapshot_id_in_read_matches_create method method test_snapshot_id_in_read_matches_create L328–334
+ TestTextMode class class TestTextMode L512–558
+ test_read_text_is_not_valid_json method method test_read_text_is_not_valid_json L547–558
+ test_read_text_shows_file_list method method test_read_text_shows_file_list L525–534
+ test_read_text_shows_note_when_set method method test_read_text_shows_note_when_set L536–545
+ test_read_text_shows_snapshot_id method method test_read_text_shows_snapshot_id L513–523
+ _create_files function function _create_files L61–67
+ _create_snapshot function function _create_snapshot L70–77
+ _env function function _env L57–58
+ _init_repo function function _init_repo L45–54
+ cli variable variable cli L35–35
+ CliRunner import import CliRunner L33–33
+ annotations import import annotations L22–22
+ json import import json L24–24
+ os import import os L25–25
+ pathlib import import pathlib L26–26
+ pytest import import pytest L31–31
+ tarfile import import tarfile L27–27
+ threading import import threading L28–28
+ zipfile import import zipfile L29–29
+ runner variable variable runner L37–37
← Older Oldest on task/supercharge-snapshot
All commits
Newer → Latest on task/supercharge-snapshot

0 comments

No comments yet. Be the first to start the discussion.

To add a comment, use the Muse CLI: muse hub commit comment sha256:6b3973c0587bec03356978fd1b61d47f9345e1496c2f87915e3f34aa08a8e69a --body "your comment"