fix(mesh): require exact pool coverage -- found by rendering, not by a metric

Rendering assembled e106 from Stage_S02 showed the old slab: e106_bdy_03 spanning
600x1600x998 where three other containers give 276x236x941. Its anchor had slack
3, and the coverage gate tolerated up to three unreferenced tail vertices --
tolerance that was hiding a mis-anchor, since real blocks reach their last vertex
exactly (8580 of 8629). Requiring exact coverage moves it to the block the other
containers agree on and the slab disappears.

Costs 3 resources (6212 -> 6209), inconsistency 39 -> 38, capture oracle
unchanged at 46/46, suite green. Evidence: captures/e106-cover-slack-before-after.png

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 06:56:49 +00:00
parent 9d33345560
commit f340815db6
4 changed files with 58 additions and 4 deletions

View File

@@ -976,6 +976,21 @@ fn grouped_consistency() -> f32 {
std::env::var("XBG7_GROUPED_CONSISTENCY").ok().and_then(|v| v.parse().ok()).unwrap_or(0.85)
}
/// Coverage requirement, as `max_index + N >= vtx_count`. **`1` since
/// 2026-08-12** — i.e. the indices must reach the pool's last vertex exactly.
///
/// The old `4` tolerated three unreferenced tail vertices, and that slack was a
/// mis-anchor tell rather than a real variation: 8 580 of 8 629 decoded
/// sub-meshes cover their pool exactly, and `e106_bdy_03` in `Stage_S02` was one
/// of the few that did not — slack 3, decoding to a 600×1600×998 slab visible in
/// a render, where three other containers give 276×236×941. Requiring exact
/// coverage moves it onto the block those containers agree on. Costs 3 resources
/// disc-wide; capture oracle unchanged at 46/46. `XBG7_COVER_SLACK` overrides
/// (note `0` rejects everything — the comparison is `max_idx + N >= vtx_count`).
fn cover_slack() -> usize {
std::env::var("XBG7_COVER_SLACK").ok().and_then(|v| v.parse().ok()).unwrap_or(1)
}
/// Smallest bounding-box extent a block may have (default `0.5`). An absolute
/// floor on a format with no unit convention is a scale assumption, so it is a
/// knob: `XBG7_MIN_EXTENT`.
@@ -1262,7 +1277,7 @@ fn validate_block_report(
}
max_idx = max_idx.max(i);
}
if (max_idx as usize) + 4 < vtx_count {
if (max_idx as usize) + cover_slack() < vtx_count {
return Err(format!(
"indices reach only {max_idx} of {vtx_count} vertices (buffer not covered)"
));
@@ -1525,7 +1540,7 @@ fn anchor_grouped_meshes(
max_idx = max_idx.max(i);
i < vc
});
if in_range && max_idx + 4 >= vc {
if in_range && max_idx + cover_slack() >= vc {
meshes.push(read_pool_mesh(bytes, ib, vb, ic, vc, decl));
}
vb += vc * stride;