From f5d58e0958556634f154a2882eb1d37a2f4f1abf Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 25 Aug 2026 15:16:43 +0000 Subject: [PATCH] =?UTF-8?q?docs(skills):=20correct=20the=20automation=20Ve?= =?UTF-8?q?rify=20passage=20=E2=80=94=20conditions=20fail=20loudly,=20node?= =?UTF-8?q?=20values=20fail=20at=20run=20time?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The '## Verify your work' opening taught that a typo'd field name, an unknown function, or a {…}-wrapped reference in a condition all fail SILENTLY at runtime. Two of the three were false, and the same file's Common Pitfalls row said the opposite. AutomationEngine.validateFlowExpressions runs a fatal pass (syntax, brace-in-CEL, unknown function) over every condition and declared bare-CEL slot at flow registration and throws; celEngine.compile reports an unknown function as a type fault, pinned in packages/formula. Only node VALUES take the single-brace flow-template dialect that no validator implements — an unknown function there raises FlowExpressionFunctionError at run time. Rewritten to distinguish the two dialects, with a typo'd field name kept as the one genuinely quiet case (advisory did-you-mean; os validate still errors on an unknown record.). The overlapping Common Pitfalls sentence is tightened in the same edit — it stated the same two facts and was the other half of the contradiction. Token-negative: 12643 -> 12642 against a 12643 ceiling. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01RMTpSRF5CjMmQBFfPtPCwJ --- skills/objectstack-automation/SKILL.md | 33 ++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/skills/objectstack-automation/SKILL.md b/skills/objectstack-automation/SKILL.md index 7979b4eb04..266d2298e8 100644 --- a/skills/objectstack-automation/SKILL.md +++ b/skills/objectstack-automation/SKILL.md @@ -938,9 +938,9 @@ them right the first time: `today()`, `daysFromNow(n)`, `daysAgo(n)`, `daysBetween(a, b)`, `isBlank(v)`, `coalesce(a, b)`, `abs/round/min/max`, `upper/lower/contains/matches`, plus CEL built-ins (`has`, `size`, `int`, `string`, …) — see **objectstack-formula** for the full table. - An UNKNOWN function (`PRIOR()`, a typo'd name) **fails the build**. And never - wrap a field reference in `{…}` inside a condition — that's a template brace - and fails as CEL: write `record.x`, not `{record.x}`. + An UNKNOWN function (`PRIOR()`, a typo'd name) and a `{…}`-wrapped field ref + both **fail the build**: a brace is a template, not CEL — write `record.x`, + not `{record.x}`. --- @@ -962,24 +962,27 @@ metadata first; reserve custom code for edge-case integrations. ## Verify your work -Flow predicates fail **silently at runtime** when malformed: a typo'd field -name, an unknown function, or a `{…}`-wrapped reference in a condition -evaluates to `null`/`false`, so the flow "fires" but does nothing — and nothing -errors at edit time. (Bare field refs like `status == 'open'` DO resolve in -start/decision/edge conditions — the engine flattens the trigger record's -fields into scope — but `record.status == 'open'` remains the canonical style.) -Catch it at author time before reporting a flow done: +**Conditions and declared bare-CEL slots** (`condition`, a screen's +`visibleWhen`) are validated at flow **registration** and by the build: a +syntax error, an unknown function (`PRIOR()`) or a `{…}`-wrapped reference +**throws**, located and corrective — never silent. + +**Node values** take the single-brace `flow-template` dialect (`'{round(x)}'`); +no validator implements it, so an unknown function there is NOT build-checked — +it throws `FlowExpressionFunctionError` at **run time**. + +The quiet case is a typo'd *field* name: bare refs (`status == 'open'`) DO +resolve (the engine flattens the record's fields into scope), so a typo is only +an advisory did-you-mean. `record.status` stays canonical; `os validate` errors +on unknown `record.`: ```bash os validate # CEL/predicate validation (record. existence) + schema # or: os build # the same gates, plus emits dist/ ``` -This runs the ADR-0032 expression gate over every flow condition, edge guard, -validation rule and sharing rule, exiting non-zero with a -located, corrective message. Remember conditions are **bare CEL** -(`record.status == 'x'`); only string node fields use `{…}` templates — see -objectstack-formula. In a scaffolded project this is `npm run validate`. +It runs the ADR-0032 gate over every condition, edge guard, validation and +sharing rule, exiting non-zero. In a scaffolded project: `npm run validate`. ---