The class-ID retraction goes further: the claim was wrong before the fix
Pinned down the one slot that still cleared 100x after the record-boundary fix,
and it is the artifact this section was written to guard against.
The discriminator the original version lacked: a slot that really carries moby
class IDs must SPAN the ID space, so some of its values land above a level's moby
count. The artifact does the opposite.
type slot enrichment distinct values ABOVE the moby count
0xd76cc453 6 305x 9 0
0xf2ef4275 34 64x 9 341
0xf2ef4275 7 46x 16 412
0xf2ef4275 14 34x 16 432
0xd76cc453 9 32x 28 702
The 305x slot's nine values are 1, 3, 4, 5, 10, 11, 12, 13, 15 -- all under a
level's ~215 moby classes, so every one scores as a hit and 65536/215 = 305x.
Nine small numbers is not a class-ID array. Every slot that actually spans the ID
space scores 10x to 64x, which is chance.
So the original claim's own numbers gave it away and it was not read that way:
"5 to 42 distinct values at 153x to 289x" is exactly the artifact's shape -- a
handful of small values, none above the count. The record-boundary fix was never
what made this claim wrong. It was wrong when written, and the retraction is
complete rather than the partial one I committed two turns ago.
The test now separates the two quantities: slots clearing 100x (currently 1,
expected to remain the artifact) and slots clearing 100x WHILE ALSO having values
above the moby count (currently 0, must stay empty). That second number is the
one that means something, and a slot appearing in it would be the first genuine
evidence of a class-ID array anywhere in the container.
Worth noting the per-SLOT bookkeeping: the count of values above the moby count
is keyed by (type, slot), not by type. A first attempt keyed it by type and the
artifact type passed the check on the strength of its ordinary slots -- 783 of its
own values sat above the count at other slots. The check has to be about the
individual slot, or one good slot launders a bad one.
245 tests, clippy clean.
This commit is contained in:
@@ -3232,9 +3232,14 @@ fn chunk_records_start_16_byte_aligned() {
|
||||
/// boundaries measured against each record's successor, and ragged chunks
|
||||
/// skipped, only 2 types show a varying class-ID slot.
|
||||
///
|
||||
/// What survives is narrow and is asserted as such: 2 chunk types show a slot
|
||||
/// that varies in the manner of a class ID, and exactly 1 of those still clears
|
||||
/// 100x enrichment over chance. The
|
||||
/// **Nothing survives, and the flaw was present from the start.** The
|
||||
/// discriminator the original version lacked: a slot that really carries moby
|
||||
/// class IDs must span the ID space, so some values land ABOVE a level's moby
|
||||
/// count. The slot that scored 305x has 9 distinct values --
|
||||
/// 1, 3, 4, 5, 10, 11, 12, 13, 15 -- and **none** above the count, because all
|
||||
/// are under ~215. Every slot that does span the ID space scores 10x to 64x. The
|
||||
/// original "5 to 42 distinct values at 153x to 289x" had exactly the artifact's
|
||||
/// shape, so the record-boundary fix was never what made it wrong. The
|
||||
/// `distinct >= 4` filter is still load-bearing -- without it the top slots are
|
||||
/// constants that read as 305x because any value below the moby count counts as
|
||||
/// a hit. See `docs/formats/core-data-regions.md`.
|
||||
@@ -3259,6 +3264,10 @@ fn moby_class_ids_sit_in_one_slot_per_chunk_type() {
|
||||
|
||||
// (type, slot) -> (nonzero, hits, expected, distinct)
|
||||
let mut stat: BTreeMap<(u32, usize), (u64, u64, f64, usize)> = BTreeMap::new();
|
||||
// (type, slot) -> how many of that slot's values land above the moby count.
|
||||
// Keyed per SLOT, not per type: a type with one artifact slot and several
|
||||
// ordinary slots must not have the ordinary ones vouch for it.
|
||||
let mut above: BTreeMap<(u32, usize), usize> = BTreeMap::new();
|
||||
let mut seen: BTreeMap<(u32, usize), BTreeSet<u16>> = BTreeMap::new();
|
||||
|
||||
for n in 0..27 {
|
||||
@@ -3294,6 +3303,8 @@ fn moby_class_ids_sit_in_one_slot_per_chunk_type() {
|
||||
e.0 += 1;
|
||||
if (v as u64) < nm {
|
||||
e.1 += 1
|
||||
} else {
|
||||
*above.entry((t, k)).or_default() += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3328,16 +3339,37 @@ fn moby_class_ids_sit_in_one_slot_per_chunk_type() {
|
||||
// boundaries fixed, and this test skipping ragged chunks, only 2 types show
|
||||
// a varying class-ID slot -- so "one class-ID slot per chunk type" was a
|
||||
// measurement of the parser's over-read, not of the disc.
|
||||
// The discriminator the original version lacked. A slot that really carries
|
||||
// moby class IDs spans the ID space, so some of its values must land ABOVE a
|
||||
// level's moby count. The artifact does the opposite: every one of its values
|
||||
// sits below the count, so every value scores as a hit.
|
||||
//
|
||||
// type 0xd76cc453 slot 6 305x 9 distinct values 0 above the count
|
||||
// type 0xf2ef4275 slot 34 64x 9 distinct values 341 above the count
|
||||
// type 0xf2ef4275 slot 7 46x 16 distinct values 412 above the count
|
||||
//
|
||||
// The 305x slot's values are 1, 3, 4, 5, 10, 11, 12, 13, 15 -- all under a
|
||||
// level's ~215 moby classes, giving 65536/215 = 305x. Nine small numbers is
|
||||
// not a class-ID array, and every slot that does span the ID space scores in
|
||||
// single digits to tens. Nothing reaches 100x while also exceeding the count.
|
||||
let spanning: Vec<_> = best
|
||||
.iter()
|
||||
.filter(|(&t, &(k, r, _))| r >= 100.0 && above.get(&(t, k)).copied().unwrap_or(0) > 0)
|
||||
.collect();
|
||||
let strong: Vec<_> = best.values().filter(|(_, r, _)| *r >= 100.0).collect();
|
||||
assert!(
|
||||
!strong.is_empty(),
|
||||
"no type reaches 100x enrichment -- was 20 before the record-boundary fix"
|
||||
eprintln!(
|
||||
"chunk class-ID slots: {} types; {} at >=100x, of which {} also have \
|
||||
values above the moby count ({} is the small-value-set artifact)",
|
||||
best.len(),
|
||||
strong.len(),
|
||||
spanning.len(),
|
||||
strong.len() - spanning.len()
|
||||
);
|
||||
assert_eq!(strong.len(), 1, "strong-enrichment type count moved");
|
||||
assert!(
|
||||
best.len() >= 2,
|
||||
"only {} chunk types carry a varying class-ID slot (was >= 20)",
|
||||
best.len()
|
||||
spanning.is_empty(),
|
||||
"{} slots clear 100x while spanning the ID space -- there may be a real \
|
||||
class-ID array after all",
|
||||
spanning.len()
|
||||
);
|
||||
assert!(
|
||||
best.len() < 20,
|
||||
|
||||
@@ -986,13 +986,40 @@ With record boundaries measured against each record's successor, and ragged
|
||||
chunks skipped, what survives is:
|
||||
|
||||
chunk types with a varying class-ID-like slot 2 (was >= 20)
|
||||
of those, clearing 100x enrichment 1 (was >= 20)
|
||||
of those, ALSO spanning the ID space 0
|
||||
|
||||
So the general claim -- one class-ID slot per chunk type, across the container --
|
||||
does not hold and is withdrawn. One chunk type still shows a slot that varies in
|
||||
the manner of a class ID at 100x enrichment over chance. That is asserted, and
|
||||
the test also asserts the count has *not* returned to 20, so the retraction
|
||||
cannot quietly lapse back into the claim.
|
||||
does not hold and is withdrawn.
|
||||
|
||||
### And the flaw was there from the start
|
||||
|
||||
The discriminator the original version lacked is simple: **a slot that really
|
||||
carries moby class IDs must span the ID space**, so some of its values land above
|
||||
a level's moby count. The artifact does the opposite.
|
||||
|
||||
type slot enrichment distinct values ABOVE the moby count
|
||||
0xd76cc453 6 305x 9 0
|
||||
0xf2ef4275 34 64x 9 341
|
||||
0xf2ef4275 7 46x 16 412
|
||||
0xf2ef4275 14 34x 16 432
|
||||
0xd76cc453 9 32x 28 702
|
||||
|
||||
The 305x slot's nine values are `1, 3, 4, 5, 10, 11, 12, 13, 15` -- all under a
|
||||
level's ~215 moby classes, so every one scores as a hit and 65536/215 = 305x.
|
||||
Every slot that actually spans the ID space scores 10x to 64x, which is chance.
|
||||
|
||||
So the original claim's own numbers gave it away and it was not read that way:
|
||||
**"5 to 42 distinct values at 153x to 289x"** is exactly the artifact's shape --
|
||||
a handful of small values, none above the count. The record-boundary fix was
|
||||
never what made this claim wrong. It was wrong when written, and the retraction
|
||||
is complete rather than partial.
|
||||
|
||||
The test now separates the two: it counts slots clearing 100x (currently 1) and
|
||||
slots that clear 100x *while also* having values above the moby count (currently
|
||||
0). The second must stay empty; the first is expected to be the artifact. The
|
||||
count above the moby count is tracked per **slot**, not per type, because a type
|
||||
with one artifact slot and several ordinary slots must not have the ordinary
|
||||
ones vouch for it.
|
||||
|
||||
The `distinct >= 4` filter this section introduced is still load-bearing and is
|
||||
unaffected: without it the top slots are constants that read as 305x, because any
|
||||
|
||||
Reference in New Issue
Block a user