fix(rust): first-max tie-breaking in dir matching + python-style score rounding
Two divergences found by diffing the Rust sorter plan against the python reference on a real 14k-file tree (both 99.82% identical): - compute_match_name used max_by (LAST max) where python max() keeps the FIRST; a same-faction dir hit and a cross-faction hit scored equally and the wrong entry won (25 Deathwatch files). - --json score used round() instead of round_ties_even(), printing 0.813 where python prints 0.812. After the fix the plans are identical: 14025/14025 targets, kinds and scores, zero differences.
This commit is contained in:
@@ -538,7 +538,7 @@ fn cmd_sorter(args: &SorterArgs) -> anyhow::Result<()> {
|
|||||||
"subfaction": i.subfaction,
|
"subfaction": i.subfaction,
|
||||||
"class": i.klass,
|
"class": i.klass,
|
||||||
"unit": i.unit,
|
"unit": i.unit,
|
||||||
"score": (i.match_score * 1000.0).round() / 1000.0,
|
"score": (i.match_score * 1000.0).round_ties_even() / 1000.0,
|
||||||
"kind": i.match_kind,
|
"kind": i.match_kind,
|
||||||
"inner_count": i.inner_names.len(),
|
"inner_count": i.inner_names.len(),
|
||||||
"target": i.target
|
"target": i.target
|
||||||
|
|||||||
@@ -906,16 +906,22 @@ fn compute_match_name(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let cands: Vec<(f64, usize, bool)> = [same, other].into_iter().flatten().collect();
|
let cands: Vec<(f64, usize, bool)> = [same, other].into_iter().flatten().collect();
|
||||||
if !cands.is_empty() {
|
if cands.is_empty() {
|
||||||
let normals: Vec<&(f64, usize, bool)> = cands.iter().filter(|c| !c.2).collect();
|
return None;
|
||||||
let winner = if normals.is_empty() {
|
|
||||||
cands.iter().max_by(|a, b| a.0.total_cmp(&b.0)).unwrap()
|
|
||||||
} else {
|
|
||||||
normals.iter().max_by(|a, b| a.0.total_cmp(&b.0)).unwrap()
|
|
||||||
};
|
|
||||||
return Some(winner.clone());
|
|
||||||
}
|
}
|
||||||
None
|
// python `max(normals or cands, key=score)` keeps the FIRST
|
||||||
|
// maximum; a normal (non-weak) candidate always beats a weak one.
|
||||||
|
let has_normal = cands.iter().any(|c| !c.2);
|
||||||
|
let mut winner: Option<(f64, usize, bool)> = None;
|
||||||
|
for c in &cands {
|
||||||
|
if has_normal && c.2 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if winner.as_ref().is_none_or(|w| c.0 > w.0) {
|
||||||
|
winner = Some(c.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return winner;
|
||||||
} else {
|
} else {
|
||||||
pool_best(clean, &pool, ctx, threshold, cache)
|
pool_best(clean, &pool, ctx, threshold, cache)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user