FlowDrop Workflow Specification 1.0-draft

A configured expression must be valid for its engine at save

An expression that cannot parse can only fail once the workflow is already running. Catching it at save turns a runtime failure into an editing error.

The rule

Normative: this is the rule
  1. Every expression carried in a node's configuration must pass its engine's validation when the workflow is saved.
  2. A failure is refused with R11_EXPRESSION_INVALID, and the error names the node, the config key, the engine and the expression.
  3. The expressions checked are the ones the node types declare as expression-bearing: a data extractor's path, the value of each dynamic output of a data mapper, the sources of a data shaper's mapping (with reserved source values such as a literal or a now marker skipped, and nested _source and _each sources walked), and a prompt template's template.
  4. An empty expression is always valid.
  5. An expression naming an engine the implementation does not know is not reported here; R6's enum check on the engine key owns that error.
  6. An engine whose validation raises rather than returning a verdict is treated as a rejection, yielding one R11_EXPRESSION_INVALID for that expression; the failure is never propagated, so a misbehaving engine still produces a refusal against the workflow and never a server error.

What it means

Not every value written where an expression is expected is checked as one. A Data Shaper's mapping accepts reserved sentinel values — a literal, a "now" marker — that the runtime never evaluates as an expression at all, so checking their syntax would only invent errors against data that is already well formed. The walk does still reach into a mapping entry that iterates a nested source: a _source/_each pair inside an entry is not itself a sentinel, and the runtime does evaluate it, so its expression is checked exactly as a top-level one would be. An engine that raises rather than returning a verdict is treated the same as one that returns a rejection: the save still fails with the same per-expression error, never with the failure of the engine itself.

Example

A mapping with two sentinel values and one nested, iterated source whose expression cannot parse:

A mapping mixing sentinel values with a nested sourcerefused
{
  "literal": "_LITERAL:not [a path",
  "stamp": "_NOW_",
  "items": { "_source": "[unclosed", "_each": { "name": "[title]" } }
}

Neither sentinel is checked; the mapping is refused for the unparseable nested source alone.

Why

Recorded under OPEN-3.

Rule identifiers are permanent and are never renumbered. Each implementation publishes its own standing against these rules; this specification does not.spec 1.0-draft · R11 · changed in spec 1.0