Skip to content

lint: validate-visibility-predicates passes unknown CEL functions clean (the validateExpression premise is falsified) — ruled: extend to function-existence ERROR, scoped supersession of the parse-only ruling #13594

Description

@claude

Summary

validateExpression (@objectstack/formula) reports ok: true, zero errors and zero warnings for a CEL source that calls a function the engine does not have. The same source then fails at runtime with found no matching overload. Authoring-time validation — the publish gate — does not check that the functions a predicate calls exist.

Measured

@objectstack/formula@17.2.0 (@marcbachmann/cel-js@8.0.0), node, one process:

"totallyBogusFn(1,2)"            validate.ok= true  warnings= 0  | runtime.ok= false - found no matching overload for 'totallyBogusFn(int, int)'
"record.x.nosuchmethod('a')"     validate.ok= true  warnings= 0  | runtime.ok= false - found no matching overload for 'dyn.nosuchmethod(string)'
"upper('a')"                     validate.ok= true  warnings= 0  | runtime.ok= true

Both the global-call form and the receiver/member-call form are affected. validateExpression catches parse errors and unbound roots today (SCOPE_ROOTS is enforced), so the function name is the one part of a call that nothing checks.

Why it matters

The runtime fault is not loud where it lands. On the ObjectUI action surfaces a faulting visible predicate is fail-CLOSED — ActionEngine.getActionsForLocation and DeclaredActionsBar both evaluate with throwOnError: true and hide the action on a throw. So a single mistyped or non-existent function name in an authored predicate produces:

  • publish: clean, no error, no warning;
  • runtime: the action is invisible for every user, including ones who hold the grant;
  • the only signal is one deduped console.warn in the browser.

That is the failure mode metadata validation exists to prevent, and it is the one an AI-authored app is most likely to hit — a plausible-looking function name that does not exist is exactly what a generator invents. Measured on this while investigating objectui#4421, where an authored current_user.can(object, verb) predicate validated clean and then faulted at runtime on every surface.

Suggested direction (not a decision)

The engine already knows its own function registry — CEL_STDLIB_FUNCTIONS is exported, and cel-js Environment exposes getDefinitions(). Resolving each call node in the parsed AST against that set inside validateExpression would turn this into a publish-time error with a nearestName suggestion (the helper already exists in this package for identifiers). Whether an unknown function should be an ERROR or a WARNING is a contract call — an error is the enforce-or-remove-consistent answer, but it can reject predicates that a host registers extra functions for, if any host does that.

Filed unassigned from an objectui dev seat; no fix attempted here.


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions