Skip to content

fix(formula): hydrate ISO date/datetime strings on CEL overload fault (#1530) - #1560

Merged
hotlong merged 2 commits into
mainfrom
fix/1530-date-formula-cel
Jun 3, 2026
Merged

fix(formula): hydrate ISO date/datetime strings on CEL overload fault (#1530)#1560
hotlong merged 2 commits into
mainfrom
fix/1530-date-formula-cel

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

Problem

Date-typed formula fields — and any predicate comparing a date field to a temporal builtin — always evaluate to null (#1530). Field.date serializes to "YYYY-MM-DD" and Field.datetime to a full ISO string; cel-js compares that raw string against the google.protobuf.Timestamp returned by today() / now() / daysFromNow() and raises no such overload, which is swallowed to null (contrary to ADR-0032 §1c "no silent failure").

Repro (templates all aggregate, 7.7.0): contracts_contract.is_expiring_soon, todo_task.is_overdue, hr_employee.tenure_years all return null even with clean date-only values.

Fix

This is the date analogue of the numeric-string fix (#1534), so it reuses the exact same fault-retry path in cel-engine.ts: on a no such overload, hydrate the offending scope and retry once. I extended that hydration to also coerce strict ISO-8601 date / date-time strings → Date, alongside the existing numeric-string → number coercion (hydrateNumericStringshydrateOverloadStrings).

Fixing it in the engine (rather than in objectql's applyFormulaPlan, as the issue hypothesized) repairs every caller — formula fields, flow conditions, validation/workflow predicates — not just formula projection.

Safety, matching the #1534 precedent:

  • Hydration runs only after a fault, so an expression that already type-checks is never re-interpreted.
  • A genuine non-temporal string ("soon") still faults loudly.
  • string == string already type-checks → retry never runs → no spurious coercion of date-looking strings.
  • The ISO regex is strict and anchored (no ReDoS).

Tests

8 new cases in cel-engine.test.ts: date-only is_expiring_soon window, unmet compare → false (not fault), is_overdue, full ISO datetime vs now(), timestamp arithmetic today() - hire_date, mixed date+numeric record, non-temporal string still faults, no spurious coercion on string == string.

Full @objectstack/formula suite green: 90/90.

Note: I could not run the package's BUILD_DTS step in my environment (the spec declaration build OOMs — unrelated to this change, reproducible on main). The change is confined to packages/formula and is type-trivial (same shape as the existing helper). Please confirm CI's DTS/build pass.

Closes#1530.

🤖 Generated with Claude Code

…#1530)
Date-typed formula fields (and any predicate comparing a date field to a
temporal builtin) always evaluated to null. `Field.date` serializes to
"YYYY-MM-DD" and `Field.datetime` to a full ISO string; cel-js compares that
raw string against the `google.protobuf.Timestamp` returned by today() / now()
/ daysFromNow() and raises `no such overload`, which surfaced as a silent null
(ADR-0032 §1c).
This is the date analogue of the numeric-string fix (#1534), so it reuses the
exact same fault-retry path in cel-engine: on a `no such overload`, hydrate the
offending scope and retry ONCE. Extend that hydration to also coerce strict
ISO-8601 date / date-time strings to `Date`, alongside the existing
numeric-string → number coercion. Renamed `hydrateNumericStrings` →
`hydrateOverloadStrings` to reflect both.
Fixing it in the engine (not in objectql's applyFormulaPlan as the issue
hypothesized) repairs every caller — formula fields, flow conditions,
validation/workflow predicates — not just formula projection. Hydration runs
only after a fault, so expressions that already type-check are never
re-interpreted, and a genuine non-temporal string still faults loudly.
Tests: 8 new cases in cel-engine.test.ts (is_expiring_soon date-only window,
unmet compare → false, is_overdue, full ISO datetime vs now(), timestamp
arithmetic today() - hire_date, mixed date+numeric record, non-temporal string
still faults, no spurious coercion on string==string). Full formula suite green
(90/90).
Closes#1530.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercelBot commented Jun 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJun 3, 2026 7:22am

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling and removed documentation Improvements or additions to documentation tests tooling labels Jun 3, 2026
@hotlong
hotlong merged commit b8de091 into mainJun 3, 2026
12 checks passed
@xuyushun441-sys
xuyushun441-sys deleted the fix/1530-date-formula-cel branch June 3, 2026 07:36
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

3 participants

@xuyushun441-sys@hotlong@os-zhuang