re: 98.7% coverage, and the scale-free degeneracy fix is refuted
Under the winding gate, coverage is 6212/6294 (98.7%) with 82 misses left, attributed 42 degenerate/extent, 31 winding, 9 coverage, 0 connectivity. The biggest bucket turns out NOT to be the blocker: replacing the absolute area test with a scale-free collinearity test decodes no more resources and raises inconsistency 39 -> 44, and dropping the extent floor to 0.05 adds two. Both stay as opt-in knobs (XBG7_REL_DEGEN, XBG7_MIN_EXTENT) rather than defaults. Also fixed another stale default label in edge_cap_sweep. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -75,6 +75,6 @@ fn main() {
|
||||
}
|
||||
println!(
|
||||
"cap={} models={models} verts={verts} shared={shared} inconsistent={inconsistent}",
|
||||
std::env::var("XBG7_EDGE_CAP").unwrap_or_else(|_| "0.42 (default)".into())
|
||||
std::env::var("XBG7_EDGE_CAP").unwrap_or_else(|_| "library default".into())
|
||||
);
|
||||
}
|
||||
|
||||
@@ -831,7 +831,10 @@ pub fn debug_best_rejection(bytes: &[u8], name: &str) -> Option<(usize, String)>
|
||||
if vb < idx_bytes + pad {
|
||||
continue;
|
||||
}
|
||||
let mc = if pad == 0 { 0.0 } else { 0.85 };
|
||||
// Mirror production exactly: the pad-0 path now carries the winding
|
||||
// floor too. Reporting at 0.0 would accept blocks the decoder
|
||||
// rejects and point at the wrong gate.
|
||||
let mc = if pad == 0 { pad0_consistency() } else { 0.85 };
|
||||
if let Err(why) = validate_block_report(
|
||||
bytes,
|
||||
vb - idx_bytes - pad,
|
||||
@@ -966,6 +969,22 @@ fn edge_cap() -> f32 {
|
||||
std::env::var("XBG7_EDGE_CAP").ok().and_then(|v| v.parse().ok()).unwrap_or(1.0)
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
fn min_extent() -> f32 {
|
||||
std::env::var("XBG7_MIN_EXTENT").ok().and_then(|v| v.parse().ok()).unwrap_or(0.5)
|
||||
}
|
||||
|
||||
/// Use a scale-free collinearity test for degeneracy instead of the absolute
|
||||
/// triangle-area one (`XBG7_REL_DEGEN=1`). More principled in the abstract — an
|
||||
/// absolute area threshold calls a small object's every triangle degenerate —
|
||||
/// but measured on this disc it decodes **no more** resources and raises
|
||||
/// cross-container inconsistency 39 → 44, so it is **not** the default.
|
||||
fn rel_degen() -> bool {
|
||||
std::env::var("XBG7_REL_DEGEN").is_ok()
|
||||
}
|
||||
|
||||
/// Winding-consistency floor for the pad-0 single-block anchor.
|
||||
///
|
||||
/// **0.70 since 2026-08-12.** A triangle's face normal should agree with its
|
||||
@@ -1278,7 +1297,21 @@ fn validate_block_report(
|
||||
u[2] * w[0] - u[0] * w[2],
|
||||
u[0] * w[1] - u[1] * w[0],
|
||||
];
|
||||
if 0.5 * (cx[0] * cx[0] + cx[1] * cx[1] + cx[2] * cx[2]).sqrt() < 1.0e-9 {
|
||||
// Degeneracy = collinear vertices, which is a SCALE-FREE property:
|
||||
// compare the cross-product magnitude to the two edge lengths that
|
||||
// produced it (i.e. sin of the angle between them). The old absolute
|
||||
// `area < 1e-9` test called a small object's every triangle degenerate —
|
||||
// `g005` spans 0.346 units and scored 7 of 8 — so it rejected tiny props
|
||||
// for being tiny. `XBG7_ABS_DEGEN=1` restores the absolute test.
|
||||
let cross = (cx[0] * cx[0] + cx[1] * cx[1] + cx[2] * cx[2]).sqrt();
|
||||
let un = (u[0] * u[0] + u[1] * u[1] + u[2] * u[2]).sqrt();
|
||||
let wn = (w[0] * w[0] + w[1] * w[1] + w[2] * w[2]).sqrt();
|
||||
let is_degenerate = if rel_degen() {
|
||||
cross < 1.0e-6 * un * wn || un == 0.0 || wn == 0.0
|
||||
} else {
|
||||
0.5 * cross < 1.0e-9
|
||||
};
|
||||
if is_degenerate {
|
||||
degenerate += 1;
|
||||
} else if let Some(no) = decl.normal_offset {
|
||||
// Stored-normal agreement: the face normal should point the way
|
||||
@@ -1305,7 +1338,7 @@ fn validate_block_report(
|
||||
t += tstep;
|
||||
}
|
||||
let extent = (hi[0] - lo[0]).max(hi[1] - lo[1]).max(hi[2] - lo[2]);
|
||||
if extent < 0.5 || sampled == 0 || degenerate * 10 > sampled * 3 {
|
||||
if extent < min_extent() || sampled == 0 || degenerate * 10 > sampled * 3 {
|
||||
return Err(format!(
|
||||
"extent {extent:.3} (min 0.5), {degenerate}/{sampled} degenerate (max 30%)"
|
||||
));
|
||||
|
||||
@@ -1042,6 +1042,34 @@ not obviously right, and both points are one env var apart
|
||||
(`XBG7_PAD0_CONSISTENCY`, `XBG7_EDGE_CAP`) for anyone who wants the conservative
|
||||
end.
|
||||
|
||||
### Where the remaining 82 misses stand — and a refuted fix
|
||||
|
||||
With the winding gate shipped, coverage is **6 212 / 6 294 = 98.7 %** and only
|
||||
**82** resources never decode (was 225). Re-attributed:
|
||||
|
||||
| furthest gate reached | count |
|
||||
|---|---|
|
||||
| degenerate / implausible positions (`extent < 0.5`, >30 % degenerate) | 42 |
|
||||
| winding consistency | 31 |
|
||||
| buffer not covered by indices | 9 |
|
||||
| connectivity | 0 (inert) |
|
||||
|
||||
**The biggest bucket is not the blocker** — which is exactly the caveat this
|
||||
attribution carries. Both of its thresholds are *absolute*, which on a format
|
||||
with no unit convention is a scale assumption: an area test of `< 1e-9` calls
|
||||
every triangle of a small object degenerate (`g005` spans 0.346 units and scored
|
||||
7 of 8), and `extent < 0.5` rejects it outright. Replacing the area test with a
|
||||
**scale-free collinearity** test (`|u × w| < 1e-6·|u|·|w|`, i.e. sin of the angle
|
||||
between the edges) is the principled version — and measured on this disc it
|
||||
decodes **no more resources at all**, while raising cross-container inconsistency
|
||||
39 → 44. Lowering the extent floor to 0.05 adds **two**.
|
||||
|
||||
So the fix that the histogram appeared to point at is refuted: those 42 are
|
||||
resources where some *wrong* candidate reached that gate, not where the true
|
||||
block was rejected. Both are kept as knobs (`XBG7_REL_DEGEN`, `XBG7_MIN_EXTENT`),
|
||||
neither is the default, and the measurement is recorded so the next reader does
|
||||
not re-derive it.
|
||||
|
||||
### Coverage has a denominator now, and the misses have a cause breakdown
|
||||
|
||||
Coverage has been quoted as "resources decoded" with no total. `examples/undecoded.rs`
|
||||
|
||||
Reference in New Issue
Block a user