Skip to content

fix: DateTimeParts propagates null component rows instead of throwing (#235)#238

Merged
dfa1 merged 2 commits into
mainfrom
fix/235-datetimeparts-null
Jul 8, 2026
Merged

fix: DateTimeParts propagates null component rows instead of throwing (#235)#238
dfa1 merged 2 commits into
mainfrom
fix/235-datetimeparts-null

Conversation

@dfa1

@dfa1 dfa1 commented Jul 8, 2026

Copy link
Copy Markdown
Owner

What

vortex.datetimeparts splits a date/time into component children (days + seconds + subseconds). DateTimePartsArrays.readLong assembled them per row and threw VortexException: DateTimeParts: null cell at index 0 whenever a component decoded to a null.

That crash surfaced after PR #225 taught RunEndEncodingDecoder to propagate nulls: a null run now returns a MaskedArray (previously it decoded as a filler value like 0). A datetimeparts column whose day-component is a nullable RunEnd child then hit the throw, blocking export of the Raincloud slugs bi-yalelanguages and bi-euro2016.

Fix

In DateTimePartsEncodingDecoder.decode, mirror the AlpEncodingDecoder (#210) unwrap+re-wrap pattern:

  1. After decoding each component, if it is a MaskedArray, capture its validity and unwrap to .inner().
  2. Intersect the component validities (a row is valid only when every part is valid — matching the Rust reference: each part must be present to reassemble the epoch count).
  3. Build the LazyDateTimePartsLongArray over the unwrapped raw values.
  4. If any component contributed nulls, wrap the reassembled array in a MaskedArray carrying the combined mask.

DateTimePartsArrays.readLong no longer throws on a masked cell — it recurses to the raw value; null rows are now tracked by the reassembled array's own outer mask (downstream ExtensionStorage/decodeAll already gate on that).

Tests

  • New decode_nullDaysComponent_propagatesNullRowInsteadOfThrowing: a stub days-child returning a MaskedArray with row 0 null yields a masked result (row 0 invalid, row 1 valid and reassembled) instead of throwing.
  • Updated readLong_nullMaskedCell_* to assert the new non-throwing read-through behavior.
  • Full reader suite green (1190 tests).

Matrix updates for the two corpus slugs are handled separately — this PR just removes the crash.

Fixes #235.

🤖 Generated with Claude Code

dfa1 and others added 2 commits July 8, 2026 07:50
…#235)

When any component (days/seconds/subseconds) of a vortex.datetimeparts array
decodes to a null — as a nullable vortex.runend child now does after PR #225 —
the reassembled timestamp row is null. The decoder unwraps each MaskedArray
component to its raw values, intersects their validities, and re-wraps the
reassembled array with the combined mask, instead of throwing
"DateTimeParts: null cell at index".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
bi-yalelanguages: only issue was DateTimeParts null crash (#235), now fixed.
bi-euro2016: #235 crash masked a deeper #234 (AlpRd null loss); reclassify
so the gap forces the #234 fix to flip it to ok.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@dfa1 dfa1 merged commit e149779 into main Jul 8, 2026
0 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DateTimeParts extension crashes on null cells (exposed by #225 RunEnd validity fix)

1 participant