When implementing matching/diff logic (especially for code/entities), define and test the algorithmic invariants you rely on, and avoid fragile heuristics.

Apply:

Example (structural hash rename-invariant):

fn compute_body_hash_invariant(content: &str, start: usize, end: usize, body_bytes: &[u8]) -> u64 {
    // Mask the entity name span so renames don’t change the structural hash.
    let mut bytes = body_bytes.to_vec();
    // Replace non-whitespace characters in [start, end) with spaces (conceptually).
    for b in &mut bytes {
        if *b != b' ' && *b != b'\n' && *b != b'\t' { *b = b' '; }
    }
    let mut hasher = std::collections::hash_map::DefaultHasher::new();
    bytes.hash(&mut hasher);
    hasher.finish()
}

Outcome: fewer misclassified diffs (renames vs modifications vs moves), deterministic behavior, and safer results under edge cases and degraded indexing.