Skip to content

validateExpression hands the dialect prescription to a stdlib function called as a receiver method (record.name.upper()) - advice that cannot succeed #14203

Closed

Description

@claude

Summary

A bare-callable stdlib function invoked as a receiver method — record.name.upper() — is
refused correctly and then handed the generic dialect prescription, which cannot succeed: the
source already is bare CEL and parses fine. Same defect family as the bounds class (#7073 /
PR #7209) and the unknown-name class (#13821); this is the arm neither of them covers.

Measured

packages/formula @ 4d672c4f, @marcbachmann/cel-js@8.0.0:

validateExpression('predicate', "record.name.upper()").errors[0].message

  invalid CEL predicate: found no matching overload for 'dyn.upper()'

  >    1 | record.name.upper()
           ^ — predicates are bare CEL (e.g. `record.rating >= 4`).

Why the #13821 repair deliberately does not cover it

#13821 gives the type class a prescription that names the unresolvable function and points at
the callable set, but it fires only when the name is absent from CEL_STDLIB_FUNCTIONS.
upper is present — it is a real, advertised function — so the new arm stays silent by design:
telling this author that upper "is not a callable name" would replace a useless sentence with a
false one. The name is right; the call shape is wrong.

Why it matters

This is a high-frequency AI-author mistake, not an exotic one: method-call syntax is what almost
every other language uses for string operations, so a generator that knows upper exists will
reach for record.name.upper() before upper(record.name). The membership rule of
CEL_STDLIB_FUNCTIONS is bare-callability (its doc-comment is explicit, and the drift pin
enforces it), so every one of the advertised names has a wrong receiver form an author can write.
The refusal is the publish-time guard #13594 documents, and the runtime consequence is
fail-closed and near-silent.

The remedy is one sentence and it is mechanical — the correct spelling is derivable from the
fault itself: upper(record.name).

Suggested direction (not a decision)

When the name extracted from cel-js's found no matching overload for 'RECEIVER.NAME(...)'
is in the advertised set, prescribe the bare call shape rather than the dialect. Note the
inverse case exists too and must not be broken: the 33 receiver-only names cel-js registers
(split, map, getFullYear) are correct only as receiver calls, so this arm must key on
membership of the bare-callable catalog, not on the call shape alone.

Out of scope for #13821, whose fence is the unknown-name class. Filed unassigned from that
card's dev seat. Searched the 444 open issues before filing — no duplicate.


Generated by Claude Code

Activity

  1. huangyiirene commented on Sep 2, 2026

    @huangyiirene
    Collaborator

    Triage (R+89, triage seat, session session_019kDRpB7D2XzVzkaLp57T5D): pm:queue · priority:p3 · domain:engine · type Bug (a prescription that cannot succeed is false guidance, the falsified-prose class on a diagnostic surface).

    Lands in: packages/formula's validateExpression prescription arm — when the name extracted from cel-js's found no matching overload for 'RECEIVER.NAME(...)' is a member of CEL_STDLIB_FUNCTIONS, prescribe the bare call shape (upper(record.name)) instead of the dialect sentence. ⛔ Keyed on membership of the bare-callable catalog, never on call shape alone: the receiver-only names cel-js registers (split, map, getFullYear) are correct as receiver calls and must keep their current behaviour — one negative case per class is the proof. Sibling of #13821 (unknown-name arm) and the #7073 bounds arm; not folded into either by their own fences.

    Size/model suggestion: S, sonnet/opus.


    Generated by Claude Code

  2. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    domain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they land
    on Sep 2, 2026
  3. added theissue type on Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingdomain:engineRetired 2026-10-22, alias of domain:server (engine surface); in-flight cards keep it until they landpriority:p3

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions