Tier 2 lost seven Nauvis anti-vacuity guards when #227 deleted the TypeScript arm. Each one counted per-point hits over the swept grid, and checksum_nauvis returns an order-sensitive fold, which cannot be decomposed back into counts. An engine export that answers a predicate over the sweep would restore all seven.
What went, and what each one was holding up
All seven lived in test/wasmNauvisParity.spec.ts and were deleted in the #227 source-deletion PR. Their frozen numbers are recorded here so a restoration re-measures them rather than re-deriving them - and so a number that comes back different is a finding rather than a surprise.
| guard |
frozen value |
what it caught |
| the tile field names match the catalog's own order |
21 tiles; FIELD_NAMES[16] = tile:deepwater, [36] = tile:red-desert-3, [37] = resolvedTileIndex |
a catalog reordering relabelling every downstream failure instead of failing here |
| the tree field names match the catalog's own order |
15 species; block base 57, base + 18 = treeDensity, base + 19 = cliffElevation |
same, for TREE_SPECIES |
| the enemy sweep reaches spots rather than folding the basement |
per case [331, 412, 484, 401, 393, 0]; 160 positions with a positive enemy probability |
a window that reached no enemy cone would fold the -1000 basement at every position and compare nothing |
| the cliff gate answers both ways and the rock density is not vacuous |
327 positions where cliffiness is 10; 72 with a non-zero rock density |
cliffiness is 0 or 10 and nothing else, so a window that answered one way everywhere would fold a constant |
| the tree density is not vacuous over the swept windows |
927 positions with a non-zero tree density |
a sweep with no forest in it folds zeros on both sides - agreement about nothing |
| the resolved tile index really is an index into the catalog |
integral, 0 <= v < 21, more than one distinct value in case 0 |
resolvedTileIndex crosses the ABI as an f64, so a wrong widening still folds to some number |
| every resource is actually drawn somewhere in the sweep |
[7, 3, 5, 4, 4, 1] positions per resource across the six cases |
a probability field folds 484 zeros where its resource is absent; a sweep with no ore in it grades nothing |
The 84-field x 6-case frozen fold itself is intact, as is "the cases actually differ from each other, field by field" (already read from the engine), the f32-grid coverage guard (it reads coordinates, not fields), and the two block-position guards (they read FIELD_NAMES literals).
Why the fold cannot stand in
Every one of these asks "how many swept positions satisfy P", and the export gives back one FNV fold of every value in sweep order. Two different hit counts can produce any pair of folds, so the count is not recoverable. Three of them - the enemy per-case array, the cliff gate, the resource drawn array - are exactly the "silent loss of coverage" the resource block's own comment was written about, so leaving them off is a real gap rather than tidying.
The shape of a fix
A predicate-counting export beside checksum_nauvis, something like:
pub extern "C" fn nauvis_field_hits(len: usize, field: u32, mode: u32) -> u32
where mode selects > 0, == 10, > ENEMY_BASEMENT + 100 and so on - the four predicates the seven guards between them need. resolvedTileIndex's range check needs a fifth answer (integral and inside 0..21), and the two name-order guards need the module to expose its field names rather than only nauvis_field_count().
Vulcanus did not need this: its guards were expressible as comparisons between folds (two slider settings, two windows, on-grid against off-grid), so #227 re-based them onto the engine and they still assert the same frozen counts - 50 of 74 fields moving with the sliders, all 74 moving with the window. See test/wasmVulcanusParity.spec.ts. Nauvis's are the ones that count positions rather than compare folds.
Related
Tier 2 lost seven Nauvis anti-vacuity guards when #227 deleted the TypeScript arm. Each one counted per-point hits over the swept grid, and
checksum_nauvisreturns an order-sensitive fold, which cannot be decomposed back into counts. An engine export that answers a predicate over the sweep would restore all seven.What went, and what each one was holding up
All seven lived in
test/wasmNauvisParity.spec.tsand were deleted in the #227 source-deletion PR. Their frozen numbers are recorded here so a restoration re-measures them rather than re-deriving them - and so a number that comes back different is a finding rather than a surprise.FIELD_NAMES[16] = tile:deepwater,[36] = tile:red-desert-3,[37] = resolvedTileIndexbase + 18 = treeDensity,base + 19 = cliffElevationTREE_SPECIES[331, 412, 484, 401, 393, 0]; 160 positions with a positive enemy probabilitycliffinessis 10; 72 with a non-zero rock densitycliffinessis 0 or 10 and nothing else, so a window that answered one way everywhere would fold a constant0 <= v < 21, more than one distinct value in case 0resolvedTileIndexcrosses the ABI as an f64, so a wrong widening still folds to some number[7, 3, 5, 4, 4, 1]positions per resource across the six casesprobabilityfield folds 484 zeros where its resource is absent; a sweep with no ore in it grades nothingThe 84-field x 6-case frozen fold itself is intact, as is "the cases actually differ from each other, field by field" (already read from the engine), the f32-grid coverage guard (it reads coordinates, not fields), and the two block-position guards (they read
FIELD_NAMESliterals).Why the fold cannot stand in
Every one of these asks "how many swept positions satisfy P", and the export gives back one FNV fold of every value in sweep order. Two different hit counts can produce any pair of folds, so the count is not recoverable. Three of them - the enemy per-case array, the cliff gate, the resource
drawnarray - are exactly the "silent loss of coverage" the resource block's own comment was written about, so leaving them off is a real gap rather than tidying.The shape of a fix
A predicate-counting export beside
checksum_nauvis, something like:where
modeselects> 0,== 10,> ENEMY_BASEMENT + 100and so on - the four predicates the seven guards between them need.resolvedTileIndex's range check needs a fifth answer (integral and inside0..21), and the two name-order guards need the module to expose its field names rather than onlynauvis_field_count().Vulcanus did not need this: its guards were expressible as comparisons between folds (two slider settings, two windows, on-grid against off-grid), so #227 re-based them onto the engine and they still assert the same frozen counts - 50 of 74 fields moving with the sliders, all 74 moving with the window. See
test/wasmVulcanusParity.spec.ts. Nauvis's are the ones that count positions rather than compare folds.Related
test/tier2Frozen.ts- why tier 2 keeps running at all once the reference implementation is gone.