Skip to content

Commit e4ec6ec

Browse files
fix(spec): the two step-18 flow-binding D3 entries name only a text-slot hole and a CEL expression as the reads to rename (#23384)
Fixes #23338 Clause-②: no Two ADR-0087 D3 semantic entries of protocol 18 still told an upgrading author to rename "a single-brace token in a value position" among the reads of a renamed variable. No protocol-18 value position reads a flow variable through a single-brace token, so this PR takes the phrase out of both `replacement` texts. It is a text-only change, following triage's direction (comment 6155971636): the card's "Wanted", as written. Dispatched by the `domain:spec` seat 2 PM, session `session_01BRQ9Mp1yH7R1az6MaUM18H`, under its claim comment 6159719865. ## What changes - `packages/spec/src/migrations/entries/semantic/18.flow-binding-name-dollar-refused.ts` and `18.flow-binding-variable-dollar-name-refused.ts`: the last clause of `replacement` names a text-slot hole and a CEL expression, and nothing else. Each entry keeps its `id`, `fromVersion`, `toVersion`, `surface`, `reason`, `acceptanceCriteria` and every other field byte-identical. No schema, door, conversion or entry id changes. - `.changeset/23338-flow-binding-d3-replacement-reads.md`: an `@objectstack/spec` patch, with the FROM → TO sentence. | FROM | TO | |:--|:--| | Rename every read of the old name with it — a text-slot hole, a CEL expression, a single-brace token in a value position | Rename every read of the old name with it — a text-slot hole, a CEL expression | The new wording is the one PR #23252 gave both entries' changesets (`22502` and `22572`, now under `.changeset/pre/`), and the one PR #23336 put in the `18.0.0-next.0` entries of `packages/spec/CHANGELOG.md`: "(a text-slot hole, a CEL expression)". The generated upgrade guide and `spec-changes.json` now say the same as those release notes. Why it is true: S6 (`615c69604`) made every CRUD `filter` operand a value slot, and S7 (`7958bdf36`) deleted the single-brace resolver. A value slot takes a CEL value envelope or a literal, and a `{…}` token there is refused. One measured nuance is stated in the changeset, so that its sentence stays true: a CRUD `filter` operand that is one whole query placeholder (`{current_user_id}`, `{today}`) is handed on to the query engine untouched (the `filterOperand` arm of `valueSlotTemplateRefusals`, judged by `classifyFlowFilterOperandString`). That placeholder reads no flow variable, so a renamed variable has no read there. ## The grep over every step-18 entry At base `713f23185`, over `packages/spec/src/migrations/entries/**/18.*` (769 files): 1. **The card's phrase**, `git grep -n "single-brace token in a value position"` over the whole repository: exactly 2 hits, the two entries above, and both are corrected here. At head `6bf205cb8` the only hit is the FROM cell of this PR's changeset. 2. **The same idea in other words**, `git grep -n -i -E "single[- ]brace|value position|\{token\}|brace token|\{var\}|single-curly|template dialect|template token"`: 22 hits in 9 entries. Apart from the two above, none reads the token as live: - `18.flow-builtin-node-config-values-refused.ts` :40, :57, :86: a `{token}` in a number or boolean slot is refused as the wrong type; at a plain string key it parses and registers as a literal; `http` interpolated "once" and "interpolates nothing now". No read is claimed. - `18.flow-text-slot-single-brace-refused.ts` (5 hits): the text-slot refusal. - `18.flow-text-slot-unbound-dollar-root-refused.ts` :32, :35: "In 17.x the slot was a plain string read by the single-brace interpolator", in the past tense, and a refusal's remedy. - `18.flow-value-slot-template-dialect-refused.ts` (4 hits): the value-slot refusal, with the query-placeholder carve-out named. - `18.flow-write-node-stored-metadata-target-refused.ts` :37: a `{token}` `objectName` cannot be read as a name. - `18.translation-flow-screen-title-text-slot-refused.ts` (4 hits): the translated-heading refusal. - `18.view-filter-rule-scalar-operator-array-refused.ts` :25: a filter rule's "value position", which has nothing to do with templates. 3. **A third pass**, `brace` or `interpolat` outside the two spellings above: 29 more hits in 13 entries. Each is in the past tense, a refusal, or another dialect (`${…}` in UI action URLs, a datasource secret, dashboard documents). None names a single-brace read as live. The step-18 rationale fragments in `registry.ts.template` carry no such sentence either. Their `single-brace` hits are refusals, plus the statement that the single-brace interpolator is deleted. ## Generated projections and pins - **No tracked file embeds the old sentence.** At base, `git grep "Rename every read of the old name"` finds only the two entries. `registry.ts`, `spec-changes.json` and the `content/docs/protocol-upgrade/` pages are gitignored build output, so nothing was regenerated or committed. - **The projections carry the new text, measured on this head.** `build-upgrade-guide.ts --out` and `build-spec-changes.ts --out` were written to a scratch path. The old phrase has 0 hits in each (grep exit 1). The new sentence has 2 hits in the guide and 4 in `spec-changes.json` (exit 0). In the built `dist/migrations/index.mjs` and `index.js`, the old phrase is absent (exit 1) and the new sentence has 2 hits each. - **No test reads either `replacement` text.** `flow-bound-variable-name.test.ts` pins only these two entries' `surface`, `conversionIds` and rationale id, and `migrations.test.ts` judges the shape of every semantic entry. No new test is added for a text fix. ## Verification All at head `6bf205cb8`, on base `713f23185`. - `pnpm --filter @objectstack/spec build`, under the verify lock: `VERDICT command-exit 0`. - `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/migrations src/automation/flow-bound-variable-name.test.ts`: 5 files, 323 tests passed. - `pnpm --filter @objectstack/spec run typecheck` (`tsc --noEmit`, `check:scripts-typecheck`, `check:test-typecheck`): exit 0. - `pnpm turbo run build --filter=!@objectstack/docs --concurrency=2`, under the lock: 75 successful, 75 total. This build is the prerequisite of three derived gates. - **Derived gates.** `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`, with no paths, gives 82 commands. Each ran with its exit code captured before any pipe. - First pass: 79 exited 0. 3 exited 3 (`PREREQUISITE NOT MET`, nothing built yet): `check:doc-formula-expressions`, `check:dual-build-cjs-loads` and `check:lean-entry-closure`. After the full build, all three exited 0. - Among the 82, all exit 0: `check-adr-0087-registration`, `check-empty-changeset`, `check-changeset-no-major`, `check:upgrade-guide`, `check:spec-changes`, `check:authorable-surface`, `check:doc-authoring` and `check:nul-bytes`. - `--ran`: "82 derived famil(ies) accounted for — 82 run, 0 NOT-MEASURED (a DERIVED zero — all 82 recorded an exit code and none of them is 3)." - **ESLint, a measured narrowing.** `eslint --no-inline-config --format json` over the 3 changed files. The 2 `.ts` files have 0 errors and 0 warnings. The config ignores the `.md` changeset. `eslint.config.mjs` enables no type-aware linting (no `parserOptions.project`), so the diff cannot move the verdict on an untouched file. - **No consumer sweep.** Only string values change, so no export, type or wire shape moves. ## Acceptance notes - `origin/main` moved to `28e294f45` after the gates ran. Its one new commit (plugin-sharing and runtime) touches neither entry and nothing in `packages/spec`. --- _Generated by [Claude Code](https://claude.ai/code/session_01BRQ9Mp1yH7R1az6MaUM18H)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 5e725b8 commit e4ec6ec

3 files changed

Lines changed: 19 additions & 2 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
fix(spec): the two step-18 flow-binding D3 entries name only the reads a renamed variable has on protocol 18, a text-slot hole and a CEL expression
6+
7+
Clause-②: no
8+
9+
The `replacement` text of two ADR-0087 D3 semantic entries, `flow-binding-name-dollar-refused` and `flow-binding-variable-dollar-name-refused`, listed three ways a flow reads the old variable name, for the author to rename. Protocol 18 has only the first two. The protocol upgrade guide and `spec-changes.json` are generated from these entries, so they now say what the two entries' release notes already say.
10+
11+
| FROM | TO |
12+
|:--|:--|
13+
| Rename every read of the old name with it — a text-slot hole, a CEL expression, a single-brace token in a value position | Rename every read of the old name with it — a text-slot hole, a CEL expression |
14+
15+
No protocol-18 value position reads a flow variable through a single-brace `{…}` token. A value slot takes a CEL value envelope or a literal, and a `{…}` token there is refused. The one `{…}` string a value slot hands on is a CRUD `filter` operand's whole-string query placeholder (`{current_user_id}`, `{today}`): the query engine reads it, and it names no flow variable. A text slot reads `{{ }}` holes.
16+
17+
Text only. No schema, door, conversion or entry id changes, and each entry keeps its `fromVersion`, `toVersion` and every other field.

‎packages/spec/src/migrations/entries/semantic/18.flow-binding-name-dollar-refused.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const entry: SemanticMigration = {
3232
'the same name without the dollar sign, read as a hole over that name: iteratorVariable: \'row\' read as '
3333
+ '{{ row.name }}, idVariable: \'account_id\' read as {{ account_id }}, a declared variable or an assignment '
3434
+ 'target named total read as {{ total }}. Rename every read of the old name with it — a text-slot hole, a '
35-
+ 'CEL expression, a single-brace token in a value position',
35+
+ 'CEL expression',
3636
reason:
3737
'The dollar-named variables are the flow engine\'s own: it binds $record, $runId, $flowName, $flowLabel and '
3838
+ '$error, a flat-graph loop binds $loopItems and $loopIndex, and a resume signal may not write any dollar '

‎packages/spec/src/migrations/entries/semantic/18.flow-binding-variable-dollar-name-refused.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const entry: SemanticMigration = {
2525
'the same name without the dollar sign, read as a hole over that name: errorVariable: \'caught\' read as '
2626
+ '{{ caught.message }}, outputVariable: \'lead\' read as {{ lead.name }}. A try_catch may instead drop '
2727
+ 'errorVariable and read the engine\'s default, {{ $error.message }}. Rename every read of the old name '
28-
+ 'with it — a text-slot hole, a CEL expression, a single-brace token in a value position',
28+
+ 'with it — a text-slot hole, a CEL expression',
2929
reason:
3030
'The dollar-named variables are the flow engine\'s own: it binds $record, $runId, $flowName, $flowLabel and '
3131
+ '$error, a flat-graph loop binds $loopItems and $loopIndex, and a resume signal may not write any dollar '

0 commit comments

Comments
 (0)