Skip to content

fix(formula): catch unknown functions in CEL conditions at build (#1877) - #1896

Merged
os-zhuang merged 2 commits into
mainfrom
fix/1877-unknown-condition-functions
Jun 15, 2026
Merged

fix(formula): catch unknown functions in CEL conditions at build (#1877)#1896
os-zhuang merged 2 commits into
mainfrom
fix/1877-unknown-condition-functions

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes#1877.

Problem

A flow whose trigger/edge condition calls an unknown functionPRIOR(status), a typo'd isBlnk(...) — was silently accepted: build + typecheck pass, then the broken condition no-op'd the flow at runtime with no log line. The reporter hit this on @objectstack 9.5.1 while runtime-testing the objectstack-ai/templates set (signal_to_topic_promotion, cta_creation_default).

Root cause

In packages/formula/src/cel-engine.ts, compile() discarded the type-check verdict:

constcheckErrors=compiled.check?.();if(checkErrors&&Array.isArray(checkErrors)&&checkErrors.length>0){ ... }

cel-js's check() returns a TypeCheckResultobject ({ valid, type?, error? }), never an array — so Array.isArray(...) was always false and the verdict was dropped. An unknown function type-checks as found no matching overload for 'PRIOR(dyn)', but that result never surfaced. Every author surface (objectstack compile via validate-expressions.ts, registerFlow's validateFlowExpressions, and the agent validate_expression tool) routes through this one compile(), so all of them accepted the predicate.

Fix

Read the documented { valid, error } shape. One change closes the gap for flow conditions, validation rules, and field formulas at once.

The runtime half of the issue is already loud on current main (post-ADR-0032): the unknown-function fault message found no matching overload doesn't match the no such overload numeric-retry guard, so it propagates as an attributed flow failure rather than return false. The reporter's silent skip was on 9.5.1, which predates that work — but build validation stayed broken until this change.

Verification

  • Confirmed empirically (against the real registered stdlib) that cel-js's check() cleanly separates valid predicates (record.rating >= 4, !isBlank(...), previous.status != null, every existing example flow condition) from unknown-function ones — no false positives.
  • New regression tests in cel-engine.test.ts and validate.test.ts (PRIOR(), short-circuit-guarded unknown call, typo'd isBlnk, plus assertions that registered stdlib isBlank still passes).
  • @objectstack/formula 95 passed · @objectstack/service-automation 187 passed · tsc --noEmit clean.

🤖 Generated with Claude Code

cel-js's `check()` returns a `TypeCheckResult` object (`{ valid, error }`),
not an array, so `compile()`'s `Array.isArray(checkErrors)` guard never
matched and the type-check verdict was silently discarded. A condition
calling an unknown function (`PRIOR(status)`, a typo'd `isBlnk(...)`)
type-checks as `found no matching overload`, but that result never
surfaced — so `objectstack compile`, `registerFlow`, and the
`validate_expression` tool all accepted the predicate, which then
silently no-op'd the flow at runtime.
Read the documented `{ valid, error }` shape instead. Because every
author surface routes through this one `compile()`, the fix closes the
gap for flow conditions, validation rules, and field formulas at once.
Verified cel-js's `check()` cleanly separates valid predicates from
unknown-function ones with no false positives on existing conditions.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercelBot commented Jun 15, 2026

Copy link
Copy Markdown

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

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

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Jun 15, 2026
@os-zhuang
os-zhuang merged commit bb00a50 into mainJun 15, 2026
13 checks passed
@os-zhuang
os-zhuang deleted the fix/1877-unknown-condition-functions branch June 15, 2026 07:27
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/steststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[P1] Flow trigger conditions with unknown functions are silently skipped (no error, passes build)

1 participant

@os-zhuang