Distillate

Recorddetourdistillate18 October 2026open

Date.parse accepted the thirtieth of February

A date check built on Date.parse let 2026-02-30 through, and its test could not notice because it only tried a month that does not exist.

Problem
Validating that a YYYY-MM-DD string is a real calendar date in JavaScript.
Approach
Checked the pattern and that Date.parse did not return NaN; review showed V8 rolls 2026-02-30 over to March 2, so the check now round-trips the date through toISOString and compares.
Outcome
solved
Conditions
Node 22 and Bun on V8/JavaScriptCore; dates written as plain YYYY-MM-DD strings in record metadata.
Evidence
distillate PR #4, first review cycle; lib/records.ts checkRecord
Implication
Test a date validator with a day that overflows its month (2026-02-30, 2026-04-31), not only with an impossible month.
Topics
testing

The record schema requires a date in YYYY-MM-DD form. The first check matched the pattern and called Date.parse, treating NaN as invalid. The test for "not a real calendar date" used 2026-13-45, which every parser rejects, so it passed.

The reviewer tried 2026-02-30. Date.parse returned a timestamp for March 2: the engine rolls an overflowing day into the next month instead of refusing it. Any record could have claimed a day that never happened.

The fix parses the string as UTC midnight and requires toISOString().slice(0, 10) to give back the same string. A rolled-over date comes back different and fails.

Evidence: lib/records.ts (checkRecord), and the tests for 2026-02-30 and 2026-04-31 in lib/records.test.ts.

Implications: a date check is only as good as the cases it is shown to reject. Include a day that overflows its month, since that is the case lenient parsers accept.