diff --git a/diffgraph/structural.py b/diffgraph/structural.py index e3985ec..5c00fa3 100644 --- a/diffgraph/structural.py +++ b/diffgraph/structural.py @@ -739,6 +739,18 @@ def _parse_failure_warning( ) +def _unsupported_language_warning(entry: SnapshotEntry, path: str) -> Dict[str, str]: + """Record the immutable snapshots outside the deterministic baseline.""" + return _warning( + "UNSUPPORTED_LANGUAGE", + path, + "Deterministic extraction currently supports Python (.py) only; " + "pre-change blob {}; post-change blob {}.".format( + entry.old_oid or "absent", entry.new_oid or "absent", + ), + ) + + def _symbol_id(path: str, qualified_name: str) -> str: return "sym::{}::{}".format(path, qualified_name) @@ -966,7 +978,7 @@ def analyze_local_diff( continue if file_entry["language"] != "python": skipped += 1 - warnings.append(_warning("UNSUPPORTED_LANGUAGE", path, "Deterministic extraction currently supports Python (.py) only.")) + warnings.append(_unsupported_language_warning(entry, path)) continue if (old is None and entry.old_oid is not None) or ( new is None and entry.new_oid is not None diff --git a/tests/test_structural.py b/tests/test_structural.py index 35d388b..3e5490b 100644 --- a/tests/test_structural.py +++ b/tests/test_structural.py @@ -181,16 +181,46 @@ def test_pathspec_scope_is_not_widened(tmp_path): def test_unsupported_language_is_explicit_and_not_overclaimed(tmp_path): + """Unsupported snapshots keep their explicit capability boundary and blobs.""" root = repo(tmp_path) write(root, "main.js", "export function value() { return 1; }\n") commit(root) write(root, "main.js", "export function value() { return 2; }\n") + old_oid = git(root, "rev-parse", "HEAD:main.js") + new_oid = git(root, "hash-object", "main.js") artifact = analyze_local_diff(str(root)) assert_valid(artifact) assert artifact["symbols"] == [] assert artifact["metadata"]["files_skipped"] == 1 assert artifact["metadata"]["warnings"][0]["code"] == "UNSUPPORTED_LANGUAGE" - assert "Python" in artifact["metadata"]["warnings"][0]["detail"] + assert artifact["metadata"]["warnings"][0]["detail"] == ( + "Deterministic extraction currently supports Python (.py) only; " + "pre-change blob {}; post-change blob {}." + ).format(old_oid, new_oid) + + +@pytest.mark.parametrize("change_kind", ["added", "deleted"]) +def test_unsupported_language_one_sided_blob_is_absent(tmp_path, change_kind): + """Added and deleted unsupported snapshots identify their missing blob side.""" + root = repo(tmp_path) + write(root, "main.js", "export function value() { return 1; }\n") + commit(root) + + if change_kind == "added": + write(root, "added.js", "export function value() { return 2; }\n") + old_oid = "absent" + new_oid = git(root, "hash-object", "added.js") + else: + old_oid = git(root, "rev-parse", "HEAD:main.js") + (root / "main.js").unlink() + new_oid = "absent" + + artifact = analyze_local_diff(str(root)) + assert_valid(artifact) + assert artifact["metadata"]["warnings"][0]["detail"] == ( + "Deterministic extraction currently supports Python (.py) only; " + "pre-change blob {}; post-change blob {}." + ).format(old_oid, new_oid) @pytest.mark.parametrize("staged", [False, True])