re: monotone assignment refuted again -- box identity needs descriptor data

XBG7_MONOTONE=1 enforces descriptor order per (stride, vtx, idx) signature: 89
minority decodes, unchanged. Monotonicity constrains order WITHIN a container
while the disagreement is BETWEEN containers, which hold different numbers of
these boxes in different arrangements. The remaining 89 are bounding-box identity
ambiguities needing descriptor-level information, not another anchoring
heuristic. Knob kept, default off, measurement recorded; suites green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-12 18:30:58 +00:00
parent 1d8b783d26
commit e8434541f2
2 changed files with 53 additions and 4 deletions

View File

@@ -583,6 +583,7 @@ impl Xbg7Model {
&r.decl,
min_consistency,
&empty_taken,
0,
)
.into_iter()
.collect()
@@ -607,6 +608,7 @@ impl Xbg7Model {
&r.decl,
min_consistency,
&empty_taken,
0,
)
.into_iter()
.collect()
@@ -650,10 +652,39 @@ impl Xbg7Model {
// (the adjacency-anchor path) take part; grouped-pool models are left
// exactly as they were.
let mut taken: std::collections::HashSet<usize> = std::collections::HashSet::new();
// Opt-in monotone pass: the last offset handed to each (stride, vtx, idx)
// signature. Resources that share a signature are interchangeable to the
// validator — many containers hold dozens of identical 24-vertex bound
// boxes — so file order is the only thing that can pin which is which.
let monotone = std::env::var("XBG7_MONOTONE").is_ok();
let mut last_by_sig: std::collections::HashMap<(usize, usize, usize), usize> =
std::collections::HashMap::new();
let mut models: Vec<Xbg7Model> = Vec::with_capacity(decoded.len());
for (i, mut m) in decoded {
let r = &resources[i];
let starts = &starts_by_stride[&r.decl.stride];
if monotone && m.meshes.len() == 1 && r.markers.len() == 1 {
let (vc, ic) = r.markers[0];
let sig = (r.decl.stride, vc, ic);
let floor = last_by_sig.get(&sig).map_or(0, |o| o + 1);
if m.meshes[0].vbuf_offset.map_or(false, |o| o < floor) {
if let Some(alt) = anchor_pool_mesh(
bytes,
starts,
ic,
vc,
&r.decl,
min_consistency,
&taken,
floor,
) {
m.meshes[0] = alt;
}
}
if let Some(o) = m.meshes[0].vbuf_offset {
last_by_sig.insert(sig, o);
}
}
if let Some(vb) = m.meshes[0].vbuf_offset {
if taken.contains(&vb) {
if m.meshes.len() == 1 && r.markers.len() == 1 {
@@ -666,6 +697,7 @@ impl Xbg7Model {
&r.decl,
min_consistency,
&taken,
0,
) {
m.meshes[0] = alt;
}
@@ -1169,9 +1201,15 @@ fn anchor_pool_mesh(
decl: &VertexDecl,
min_consistency: f32,
taken: &std::collections::HashSet<usize>,
min_vb: usize,
) -> Option<GameMesh> {
let idx_bytes = index_count * 2;
for &vb in starts {
// Monotone assignment (opt-in): resources of one signature are laid out
// in descriptor order, so a later one may not take an earlier block.
if vb < min_vb {
continue;
}
// A buffer another resource already claimed is not a candidate: the
// engine draws each part from its own buffer (proved for the mirrored
// `e106_bdy_0{1,2}_l` twins by a runtime capture), so two resources