Skip to content

Commit 05539d4

Browse files
committed
fix(spec): the step-18 value-slot entry names every value slot the retirement reached (#19939 S7)
Claude-Session: https://claude.ai/code/session_01BRQ9Mp1yH7R1az6MaUM18H Co-authored-by: Claude <noreply@anthropic.com>
1 parent b1f1c0f commit 05539d4

2 files changed

Lines changed: 13 additions & 5 deletions

File tree

‎.changeset/19939-flow-single-brace-resolver-deleted.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ Clause-②: no (narrowing)
2020
- **Conditions.** `AutomationEngine.evaluateCondition(condition, variables, context?)` reads every condition as CEL — bare text, an envelope with `dialect: 'cel'`, or one naming no dialect. The template path it kept for a string carrying a `{var}` hole is deleted: such a string is refused as a CEL fault that names its source and says not to wrap field references in `{…}`, and an envelope with `dialect: 'template'` or `dialect: 'flow'` is refused before evaluation. `registerFlow` already refused both at every condition slot (a start node's `condition`, an edge `condition`, a `decision` branch's `expression`, a screen field's `visibleWhen`), so no registered flow changes. What changes is a direct caller: a plugin calling the method, or `@objectstack/verify`'s `stack.automation.evaluateCondition`, which hands the condition over as given.
2121
- **Value-slot literals.** A literal in a value slot — a `fields`, `input` or `templateData` value, an `assignment` value in any of its three shapes, a `notify` recipient, an `http` `body`, a screen's `defaults`, `defaultValue` or `recordId` — is handed on as a copy of what was written (arrays and plain objects copied, every other value as it is). The deleted interpolator walked every object's own entries, so a `Date` written in a code-defined flow reached the write as `{}`; it reaches it as the `Date`.
2222
- **`@objectstack/lint`.** `validateFlowTemplatePaths` reads the `{{ }}` holes of a node's strings and no single-brace token; a CRUD node's `filter` is not scanned, since each operand is a value slot that renders no template. So `flow-template-unknown-field` and `flow-template-lookup-traversal` report only `warning` now: their `error` at a filter operand, and every finding on a single-brace token, are gone, and the value-slot and text-slot judges refuse those tokens at the same doors as `expression-invalid`. Messages and hints spell a hole `{{ record.x }}`. `flow-double-brace-interpolation` and `flow-bare-dollar-reference`, at a string outside every value slot, text slot and declared literal (a plugin node's own config, a `connector_action` input), say the value is read as written, where they prescribed a `{var}` token nothing reads. The lint's mirror of the retired grammar is removed with its exports.
23-
- **`@objectstack/spec`.** The `FlowSchema` example's `connector_action` input holds a literal, since nothing reads a token there. The upgrade guide's step-18 text-slot entry says no other flow string reads the single-brace dialect, where it said every other one kept it.
23+
- **`@objectstack/spec`.** The `FlowSchema` example's `connector_action` input holds a literal, since nothing reads a token there. The upgrade guide's step-18 text-slot entry says no other flow string reads the single-brace dialect, where it said every other one kept it, and its value-slot entry names every value slot the retirement reached on this line, where it named only the `assignment` values and the CRUD `fields` map.
2424

2525
## FROM → TO
2626

‎packages/spec/src/migrations/registry.ts.template‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2040,10 +2040,18 @@ const STEP18_RATIONALE: readonly RationaleFragment[] = [
20402040
text:
20412041
'It retires the single-brace `{…}` template dialect from the flow VALUE slots (the C half of the '
20422042
+ 'maintainer\'s ruling D on the flow expression dialects): the `assignment` node\'s values, in all '
2043-
+ 'three shapes, and the `fields` map of `create_record` and `update_record`, where a CEL value '
2044-
+ 'envelope is already the expression form. A string there is now the literal '
2045-
+ 'text it spells, and one carrying a `{…}` token is refused — by `FlowValueSlotSchema`, '
2046-
+ '`registerFlow`, `objectstack validate` and the executor alike — with the CEL spelling of each token. '
2043+
+ 'three shapes; the `fields` map of `create_record` and `update_record`; the maps a node hands to a '
2044+
+ 'callee (a `subflow`\'s and a `map`\'s `input`, a `script`\'s `inputs`); a `screen`\'s `defaults`, each '
2045+
+ 'field\'s `defaultValue` and its `recordId`; the `collection` a `loop` with a `body` and a `map` '
2046+
+ 'iterate; a `notify` node\'s `recipients`, `templateData` and `sourceId`; an `http` node\'s `body`; and '
2047+
+ 'each operand of a `get_record`, `update_record` or `delete_record` `filter`. A CEL value envelope is '
2048+
+ 'the expression form in each. A string there is now the literal text it spells (a `collection`\'s '
2049+
+ 'literal is an inline array), and one carrying a `{…}` token is refused — by the node contracts, '
2050+
+ '`registerFlow`, `objectstack validate` and the executor alike — with the CEL spelling of each token; '
2051+
+ 'a whole-string query placeholder at a filter operand (`{current_user_id}`, `{today}`) stays the '
2052+
+ 'query engine\'s. A `notify` node\'s `sourceObject`, `actorId` and `payload` and an `http` node\'s '
2053+
+ '`method`, `durable`, `timeoutMs` and `signingSecret` are literals read as written, where a token is '
2054+
+ 'refused too. '
20472055
+ 'No D2 conversion exists: every authored spelling was measured lossy (an absent key writes nothing '
20482056
+ 'under the template and fails under CEL; CEL divides two integers as integers), so which value an '
20492057
+ 'absent key should write is the author\'s judgment. The `$User` paths are refused too: the flow CEL '

0 commit comments

Comments
 (0)