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
Copy link
Copy Markdown

vercel Bot commented Jun 3, 2026

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 3, 2026 7:22am

Request Review

@github-actions github-actions Bot 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 main Jun 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 free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

3 participants