You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(formula): cover a Date-valued binding in the temporal-equality rewrite (#7168) (#8160)
* fix(formula): cover a Date-valued binding in the temporal-equality rewrite (#7168)
`record.due == previous.due` — `previous` hydrated by the driver as a `Date`,
`record` parsed from a JSON payload as `"2026-06-20"` — compared a string against
a Timestamp and answered a silent `false` (`!=` answered a silent `true`). No
fault, no log line: the wrong answer is shaped like a legitimate one.
`rewriteTemporalEquality` (#3183) already coerced the string operand with
`date(...)` when its counterpart was a temporal CALL. It now also fires when the
counterpart is a Date-valued BINDING. A binding's runtime type is not in the AST,
so this arm reads the evaluation scope — the same discipline
`rewriteFaultedOperands` (#7098) uses — and its verdict is never cached against
the source, because it is a property of the row and not of the expression. What
IS cached per source is the analysis: which occurrences could depend on a scope
at all, so sources without one keep the memoized static path.
The coercion requires the counterpart to be a real `Date` AND this operand to be
an ISO-8601 string that parses, which is what keeps the fix from becoming the
mirror-image defect. `"5"` and `"05"` are different strings that both parse to
2001-05-01; wrapping unconditionally would invent an equality between them and
turn a correct `false` into a silent `true`.
Fact 1 of the card (cross-type `in` membership) is deliberately untouched, per
the maintainer ruling of 2026-08-12: record-and-defer pending a measured victim.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014C8pAprWdmtecFsEprZax4
* docs(formulas): name the Date-valued-binding counterpart in the temporal-equality callout (#7168)
The callout describes the rewrite this PR extends, and its only named
counterpart was a temporal call — so after the code change it stayed true but
became incomplete in the direction that matters: a reader would still believe
`record.due == previous.due` silently answers `false`.
Extends that paragraph only: the counterpart may be a temporal call OR a binding
holding a `Date`, named through the reachable mixed-provenance shape. Also states
the fence, so the sentence cannot be read as "any string now matches a date":
the coercion needs one side to be a real `Date` and the other an ISO-8601 string.
No other prose touched, and cross-type `in` membership is deliberately not
mentioned — it is record-and-defer per the maintainer ruling on #7168.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014C8pAprWdmtecFsEprZax4
---------
Co-authored-by: Claude <noreply@anthropic.com>
0 commit comments