fix(mesh): grouped pools no longer emit sub-meshes with out-of-range indices
coverage_audit measures index coverage per decoded sub-mesh. 8586 of them reference their last vertex exactly, so the 'buffer not covered' gate is well founded -- but 18 had NEGATIVE slack: indices up to 364 vertices past the end of their own buffer, emitted because anchor_grouped_meshes reads pre-pivot sub-meshes unconditionally. Quality gates stay relaxed there (a tiny flat lead part is legitimately poor) but index range is now required. Coverage 6069/6294 unchanged, inconsistency 56 unchanged, truth table still 46/46 claimed, suite green; the vertex total drops by exactly the 1546 garbage verts. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1391,7 +1391,17 @@ fn anchor_grouped_meshes(
|
||||
if !ok && i > kmax {
|
||||
break; // chain diverged — emit the validated prefix, no garbage
|
||||
}
|
||||
meshes.push(read_pool_mesh(bytes, ib, vb, ic, vc, decl));
|
||||
// Sub-meshes BEFORE the pivot are emitted even when they fail the
|
||||
// quality gates (a tiny flat lead part is legitimately poor), but
|
||||
// an index that addresses past its own vertex buffer is not a
|
||||
// quality question — it is unusable. Measured 2026-08-12: 18
|
||||
// sub-meshes disc-wide carried indices up to 364 vertices past
|
||||
// the end (`coverage_audit`), which any renderer would fault on.
|
||||
let in_range =
|
||||
(0..ic).all(|k| (be16(bytes, ib + k * 2) as usize) < vc);
|
||||
if in_range {
|
||||
meshes.push(read_pool_mesh(bytes, ib, vb, ic, vc, decl));
|
||||
}
|
||||
vb += vc * stride;
|
||||
}
|
||||
return meshes;
|
||||
|
||||
Reference in New Issue
Block a user