mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-17 03:59:28 +00:00
push(snapshot): run-aware base/head line-correspondence (stop discarding intra-run anchors)
The correspondence mapped an equal-region base<->head line pair only when the line's content was GLOBALLY unique in the file, so common lines (`}`, blanks, imports) tripped `ambiguous_line_correspondence` and the finding's anchor was discarded -> the operation came back `unmapped` -> novelty `unknown` -> `comparison_unknown` -> the engine finding was suppressed (a direct cause of "near-blind to fixes"). Replace the global-uniqueness gate with run-aware positional anchoring: segment the equal-region pairs into contiguous runs (strictly +1/+1, as _equal_line_pairs emits), and map a pair when its content occupies exactly one old run and one new run. Duplicates WITHIN a contiguous run are positionally forced and now map; duplicates ACROSS runs split by an edit are aligned arbitrarily by git and stay withheld + flagged (soundness preserved -- the moved-repeated-operation guard still passes, so no false `new`/identity claims). Tests: update test_change_context_unknown_base_binary_and_ambiguous_lines_are_ unresolved (its two in-run sinks now anchor); keep the moved-operation soundness test; add intra-run-maps, cross-run-withheld, and distinctive-line-anchors cases. 163 push tests pass, ruff clean. Honest scope (design.md amendment): this removes one real cause but is necessary-not-sufficient -- live-testing a messy 14-file Java change showed coverage stays `incomplete` due to other, dominant blockers (capability_unavailable until Task 8.3; the engine produced no actionable defect; eligibility/projection gaps). Engine coverage on unseen diffs needs those too, not just correspondence. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c657c2219b
commit
abb2058a54
@@ -553,9 +553,12 @@ def test_change_context_unknown_base_binary_and_ambiguous_lines_are_unresolved(r
|
||||
assert "comparison_base_unavailable" in missing.unresolved_boundaries
|
||||
result = SnapshotAdapter(repo).compare(comparison(base, head))
|
||||
assert "declaration_paths_unavailable" in result.unresolved_boundaries
|
||||
assert any("ambiguous_line_correspondence" in b for b in result.unresolved_boundaries)
|
||||
# The two unchanged `sink();` lines form one contiguous equal run, so they anchor
|
||||
# positionally (intra-run duplicates are forced) and are no longer ambiguous.
|
||||
assert not any("ambiguous_line_correspondence" in b for b in result.unresolved_boundaries)
|
||||
assert {(m.base_start_line, m.head_start_line) for m in result.line_correspondences} >= {(2, 2), (3, 3)}
|
||||
# The binary file still cannot be line-corresponded.
|
||||
assert any("binary_line_correspondence_unavailable" in b for b in result.unresolved_boundaries)
|
||||
assert not result.line_correspondences
|
||||
|
||||
|
||||
def test_change_context_is_bounded_and_never_executes_diff_helpers(repo: Path) -> None:
|
||||
@@ -584,6 +587,36 @@ def test_change_context_moved_repeated_operations_do_not_claim_identity(repo: Pa
|
||||
assert result.decode_path(result.changed_paths[0]) == "api.js"
|
||||
|
||||
|
||||
def test_change_context_repeated_lines_in_one_run_map_positionally(repo: Path) -> None:
|
||||
# Three blank lines and a sink form one contiguous equal run (only line 1 changed);
|
||||
# intra-run duplicates are forced, so they all anchor without ambiguity.
|
||||
base = binary_commit(repo, [(b"100644", b"a.py", b"old()\n\n\n\nsink()\n")])
|
||||
head = binary_commit(repo, [(b"100644", b"a.py", b"new()\n\n\n\nsink()\n")])
|
||||
result = SnapshotAdapter(repo).compare(comparison(base, head), declaration_paths=())
|
||||
assert not any("ambiguous_line_correspondence" in b for b in result.unresolved_boundaries)
|
||||
assert {m.base_start_line for m in result.line_correspondences} >= {2, 3, 4, 5}
|
||||
|
||||
|
||||
def test_change_context_repeated_lines_split_across_hunks_are_withheld(repo: Path) -> None:
|
||||
# 'dup()' appears in two equal runs split by the changed a/b/c lines; git's alignment
|
||||
# of cross-run repeats is arbitrary, so those pairs are withheld and flagged.
|
||||
base = binary_commit(repo, [(b"100644", b"a.py", b"a()\ndup()\nb()\ndup()\nc()\n")])
|
||||
head = binary_commit(repo, [(b"100644", b"a.py", b"A()\ndup()\nB()\ndup()\nC()\n")])
|
||||
result = SnapshotAdapter(repo).compare(comparison(base, head), declaration_paths=())
|
||||
assert any("ambiguous_line_correspondence" in b for b in result.unresolved_boundaries)
|
||||
assert not any(m.base_start_line in (2, 4) for m in result.line_correspondences)
|
||||
|
||||
|
||||
def test_change_context_distinctive_line_anchors_despite_recurring_braces(repo: Path) -> None:
|
||||
# '}' recurs across two runs (ambiguous), but the distinctive sink line is a single-run
|
||||
# anchor and must still map -- this is the real "fix touches surrounding code" case.
|
||||
base = binary_commit(repo, [(b"100644", b"a.js", b"f() {\n old();\n}\ng() {\n distinctive(x);\n}\n")])
|
||||
head = binary_commit(repo, [(b"100644", b"a.js", b"f() {\n new();\n}\nh() {\n distinctive(x);\n}\n")])
|
||||
result = SnapshotAdapter(repo).compare(comparison(base, head), declaration_paths=())
|
||||
assert any("ambiguous_line_correspondence" in b for b in result.unresolved_boundaries)
|
||||
assert any(m.base_start_line == 5 and m.head_start_line == 5 for m in result.line_correspondences)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("limit", ["max_total_bytes", "max_diff_bytes", "max_mapping_lines", "max_files"])
|
||||
def test_change_context_total_limits_are_explicit(repo: Path, limit: str) -> None:
|
||||
from openultrasast.push.snapshot import SnapshotLimits
|
||||
|
||||
Reference in New Issue
Block a user