re: coverage is 96.4% (6069/6294) -- and the 225 misses get a gate breakdown

undecoded.rs supplies the denominator the coverage numbers never had; the disc
holds 6294 XBG7 resources, 6069 decode, 225 are searched and missed, 0 lack a
descriptor. gate_histogram.rs attributes each miss to the furthest gate its best
candidate reached: 120 connectivity, 74 grouped-pool (different path), 15
degenerate/extent, 9 winding, 7 buffer-not-covered. Recorded as a work-list, not
a verdict -- a wrong candidate can pass more gates than the true block.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 04:22:43 +00:00
parent db8104ab99
commit c9c98cf942
4 changed files with 209 additions and 0 deletions

View File

@@ -755,6 +755,67 @@ pub fn debug_try_anchor(
None
}
/// How far did the anchor scan get for a resource it failed to place?
///
/// Runs the same candidate loop the decoder runs and keeps the **furthest**
/// rejection — the candidate that passed the most gates before failing. Over the
/// resources that never decode, the distribution of these says which gate to
/// work on, instead of tuning one threshold and re-measuring.
pub fn debug_best_rejection(bytes: &[u8], name: &str) -> Option<(usize, String)> {
let (decl, markers) = decl_of(bytes, name)?;
let starts = debug_vertex_run_starts(bytes, decl.stride);
let rank = |why: &str| -> usize {
if why.contains("out of range") {
1
} else if why.contains("buffer not covered") {
2
} else if why.contains("not finite") || why.contains("degenerate") {
3
} else if why.contains("connectivity") {
4
} else if why.contains("winding") {
5
} else {
0
}
};
// Only the single-block path is modelled here. A grouped-pool resource is
// placed by its pivot, so running the single-block loop on `markers[0]`
// would report a gate the decoder never consulted.
if markers.len() > 1 {
return Some((9, format!("grouped pool ({} sub-meshes) — not analysed here", markers.len())));
}
let (vtx_count, index_count) = *markers.first()?;
let idx_bytes = index_count * 2;
let mut best = (0usize, String::from("no candidate reached any gate"));
for &vb in &starts {
for pad in 0..=3usize {
if vb < idx_bytes + pad {
continue;
}
let mc = if pad == 0 { 0.0 } else { 0.85 };
if let Err(why) = validate_block_report(
bytes,
vb - idx_bytes - pad,
vb,
vtx_count,
index_count,
&decl,
mc,
true,
) {
let r = rank(&why);
if r > best.0 {
best = (r, why);
}
} else {
return None; // it would have decoded — not a miss
}
}
}
Some(best)
}
/// Diagnostic: why does the decoder refuse a grouped-pool resource at a given
/// pool start? Recomputes the pool layout exactly as [`anchor_grouped_meshes`]
/// does and reports the pivot sub-mesh's verdict for each index/vertex pad —