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:
Marius Ciepluch
2026-10-11 10:12:03 +02:00
co-authored by Claude Opus 4.8
parent c657c2219b
commit abb2058a54
3 changed files with 98 additions and 5 deletions
+22 -3
View File
@@ -404,12 +404,31 @@ class SnapshotAdapter:
spans.append(ChangedSpan(path_head.hex(), new_start, new_start + new_count - 1, "head"))
old_cursor, new_cursor = old_index + old_count, new_index + new_count
pairs.extend(_equal_line_pairs(old_lines, new_lines, old_cursor, len(old_lines), new_cursor, len(new_lines)))
old_counts, new_counts = Counter(old_lines), Counter(new_lines)
# Equal-region pairs are positionally 1:1 within a contiguous run
# (strictly +1/+1 from _equal_line_pairs). A line's content is a
# trustworthy positional anchor when it occupies exactly one old and
# one new run; content repeated across runs split by an edit is aligned
# arbitrarily by git and is withheld as ambiguous. Duplicates within one
# run stay forced and safe.
anchor_pairs = () if ambiguous_rename else pairs
anchor_runs: list[list[tuple[int, int]]] = []
for pair in anchor_pairs:
last = anchor_runs[-1][-1] if anchor_runs else None
if last is not None and pair[0] == last[0] + 1 and pair[1] == last[1] + 1:
anchor_runs[-1].append(pair)
else:
anchor_runs.append([pair])
old_runs: dict[bytes, set[int]] = {}
new_runs: dict[bytes, set[int]] = {}
for run_index, run in enumerate(anchor_runs):
for old_index, new_index in run:
old_runs.setdefault(old_lines[old_index], set()).add(run_index)
new_runs.setdefault(new_lines[new_index], set()).add(run_index)
ambiguous = False
for old_index, new_index in () if ambiguous_rename else pairs:
for old_index, new_index in anchor_pairs:
_check_budget(budget, cancelled)
content = old_lines[old_index]
if old_counts[content] != 1 or new_counts[content] != 1:
if len(old_runs.get(content, ())) != 1 or len(new_runs.get(content, ())) != 1:
ambiguous = True
continue
mappings.append(LineCorrespondence(path_base.hex(), path_head.hex(), old_index + 1, old_index + 1, new_index + 1))