Found by Raincloud triage round 4 (#205) on world-energy-consumption (16 f64? columns). Same silent-corruption class as #210. Two distinct facets in SparseEncodingDecoder:
(b1) Null fill scalar coerced to 0. biofuel_cons_change_pct: vortex.sparse(f64?, fill_value: null) — the 21,307 unpatched positions are null in Rust, 0.0 in Java.
long fillBits = scalarToLong(fillScalar); // returns 0L for a null scalar
...
case F64 -> new LazySparseDoubleArray(..., Double.longBitsToDouble(fillBits) /* 0.0 */, ...);
scalarToLong falls through to return 0L for null; LazySparse*Array has no null-fill concept, so a null-fill sparse array decodes as non-nullable fill=0.0.
(b2) Nullable patch_values stripped. nuclear_share_energy (alp → sparse(i64?, fill 0) → patch_values: bitpacked(i64?), nulls=16998):
Array valData = patchValues instanceof MaskedArray m ? m.inner() : patchValues; // strips validity
16,998 patched-but-null positions decode to raw 0 → Java emits 0.0; Rust reads null.
Fix direction: LazySparse*Array must model (a) a null fill value (whole unpatched region null) and (b) per-patch validity from a nullable patch_values child — build the combined row validity and wrap in MaskedArray, mirroring #210.
Found by Raincloud triage round 4 (#205) on
world-energy-consumption(16f64?columns). Same silent-corruption class as #210. Two distinct facets inSparseEncodingDecoder:(b1) Null fill scalar coerced to 0.
biofuel_cons_change_pct:vortex.sparse(f64?, fill_value: null)— the 21,307 unpatched positions are null in Rust,0.0in Java.scalarToLongfalls through toreturn 0Lfor null;LazySparse*Arrayhas no null-fill concept, so a null-fill sparse array decodes as non-nullable fill=0.0.(b2) Nullable patch_values stripped.
nuclear_share_energy(alp → sparse(i64?, fill 0) → patch_values: bitpacked(i64?), nulls=16998):16,998 patched-but-null positions decode to raw 0 → Java emits
0.0; Rust reads null.Fix direction:
LazySparse*Arraymust model (a) a null fill value (whole unpatched region null) and (b) per-patch validity from a nullable patch_values child — build the combined row validity and wrap inMaskedArray, mirroring #210.