Skip to content

Decision: should Maestro ${} interpolation evaluate JS expressions (GraalJS parity) or stay lookup-only? #1292

Description

@thymikee

Decision to make

Should Maestro-compat ${...} interpolation evaluate JavaScript expressions (GraalJS parity), or remain variable-lookup-only with loud failure?

Context

The typed engine (ADR 0015) deliberately implements ${} as literal variable lookup: ${VAR} resolves from flow config/env/runFlow env/runScript output.*; anything unresolved throws INVALID_ARGS (fail-loud — a deliberate #1217 decision replacing an earlier silent pass-through). Upstream evaluates the full ${...} payload as a GraalJS expression: arithmetic, ternaries, string concat, maestro.* namespace, JS truthiness.

The conformance oracle (#1289) now names exactly where this bites real flows:

  • ${0 + 1} as tapOn.index (corpus upstream/032_element_index)
  • full assertTrue parity (corpus upstream/067_assertTrue_pass)
  • repeat.while / runFlow.when.true beyond platform comparisons
  • upstream's own 065_when_true.yaml exercises ${undefined}, ${0}, ${[]}, ${{...}} as truthy conditions

Lookup-scoped subsets are being handled separately and do NOT require this decision: numeric-field ${VAR} lookup, and assertTrue: ${VAR} truthiness (phase 1).

Options

  1. Stay lookup-only (status quo), document as a permanent deviation in ADR 0015 + the oracle's DOCUMENTED_DEVIATIONS. Cheapest; keeps the engine free of a JS-eval surface; flows using expressions keep failing loud with source lines.
  2. Bounded expression support via the existing Node vm sandbox used by runScript (arithmetic/comparison/truthiness, no maestro.* host API). Middle ground; needs a defined subset and its own conformance vectors.
  3. Full GraalJS-semantics parity. Largest surface; effectively an embedded expression engine with upstream-matching semantics; only worth it if real suites demand it.

Whatever is decided, encode it: option 1 → DOCUMENTED_DEVIATIONS entry; options 2/3 → corpus flows + generated vectors so the subset boundary is mechanical, not prose.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions