You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0c910d5
Browse filesBrowse the repository at this point in the historyBrowse files
fix(spec): field and object form expression help states what the engine does (#24803)
Closes#24735
Clause-②: no
## What
The `expression` help text in the field designer
(`packages/spec/src/data/field.form.ts`) said the expression "makes it
read-only". The engine does not do that. The object designer's field
grid (`packages/spec/src/data/object.form.ts`) showed the `expression`
row for `formula` fields only, with the help text "CEL formula
expression". Both rows now carry the same sentence, which matches the
landed `FieldSchema.expression` describe:
> CEL expression the field's value is computed from. On a formula field:
computed on read, no stored column. On any other field: computed by the
engine from the row each write stores, and stored, so a client-sent
value never stands.
Nothing changes in behaviour, and no gate is added.
## Engine behaviour the text was checked against (`origin/main`
46bb5e3)
- `planStoredExpressions` (`packages/objectql/src/engine.ts`): every
non-`formula` field that declares an `expression` is computed over the
row the write stores and written onto the payload. A client-sent value
is overwritten.
- `stripComputedWriteFields`: strips `formula` fields only. A `formula`
has no column and is computed on read.
- `settleBulkStoredExpressions`: a predicate update that moves an input
stores the single value when every matched row agrees, and refuses the
update otherwise.
- Only `readonly: true` makes a client value a readonly drop.
The sentence makes no claim about whether the overwrite is reported. It
stays true before and after the open draft for #24690, which would add a
`stored_expression` dropped-field report. "A client-sent value never
stands" holds either way.
## Grid row decision: widened to every type
`FieldSchema` accepts `expression` on every field type: there is no type
gate in `field.zod.ts`, and `planStoredExpressions` acts on any
non-formula type. The field designer's own row has no `visibleWhen`.
With the formula-only row, a stored field's live `expression` could not
be seen or edited in the grid, while the field form showed it. I found
no concrete reason to keep the narrower row, so the `visibleWhen` is
removed and the help text matches `field.form.ts`. A comment at the row
records why.
## Translations
The zh-CN, ja-JP and es-ES values of both leaves made the same false
claim, or the formula-only one. Two examples: zh-CN "自动设为只读" and es-ES
"lo hace de solo lectura". AGENTS.md says translated-locale values are
hand-written. The extractor's merge mode keeps every existing translated
value, and authored leaves carry no source hash, so regenerating could
not correct them. I re-translated the six leaves by hand. The `en`
bundle was regenerated with `node scripts/check-i18n-bundles.mjs --write
--filter=platform-objects`, which rewrote only
`en.metadata-forms.generated.ts`. The en pin for
`object.fields['fields.expression'].helpText` in
`object-field-editor-panel-echo-decisions.test.ts` follows the new
source, with its reason amended.
## Verification (head 28b565d)
- `pnpm --filter @objectstack/spec build`: exit 0. Then `pnpm --filter
@objectstack/spec check:generated`: "All 14 generated artifacts are up
to date".
- `pnpm --filter @objectstack/spec test`: 702 files / 21352 tests
passed. `pnpm --filter @objectstack/spec typecheck`: exit 0.
- `pnpm --filter @objectstack/platform-objects test`: 79 files / 1195
tests passed. `pnpm --filter @objectstack/platform-objects typecheck`:
exit 0.
- `pnpm check:i18n`: "OK (10 package(s) — all bundles in sync, no
undeclared authoring keys)". `check:i18n-stale-fill`: OK.
- `node scripts/pm/dispatch-gates.mjs --ran`: 88 derived families
accounted for, 87 run at exit 0. NOT MEASURED:
`check:dual-build-cjs-loads`. It exited 3 with PREREQUISITE NOT MET
because unrelated workspace packages have no `dist/`. CI builds the
whole workspace and runs it.
- `pnpm lint` (repo-wide eslint) was not run locally and is left to CI.
## Acceptance notes
- Nothing was driven in a browser. The objectui grid renders the row
from this form metadata, and the only change it sees is that
`visibleWhen` is gone.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01D6F9axfoPzR7t8G1J7Ytzz)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
Field and object designer forms: the `expression` help text now states what the engine does instead of claiming the expression "makes it read-only". On a `formula` field the expression is computed on read with no stored column; on any other field the engine computes it from the row each write stores and stores the result, so a client-sent value never stands (only `readonly: true` makes a client value a readonly drop). The object designer's field grid now shows the `expression` row for every field type, as the field designer already did, since `FieldSchema` accepts `expression` on any type. The zh-CN, ja-JP and es-ES translations of both rows are updated to match.
helpText: "CEL expression the field's value is computed from. On a formula field: computed on read, no stored column. On any other field: computed by the engine from the row each write stores, and stored, so a client-sent value never stands."
helpText: "CEL expression to calculate this field (makes it read-only)"
766
+
helpText: "CEL expression the field's value is computed from. On a formula field: computed on read, no stored column. On any other field: computed by the engine from the row each write stores, and stored, so a client-sent value never stands."
helpText: "Expresión CEL con la que se calcula el valor del campo. En un campo de fórmula: se calcula al leer, sin columna almacenada. En cualquier otro campo: el motor lo calcula a partir de la fila que guarda cada escritura y lo almacena, por lo que un valor enviado por el cliente nunca prevalece."
helpText: "Expresión CEL para calcular este campo (lo hace de solo lectura)"
766
+
helpText: "Expresión CEL con la que se calcula el valor del campo. En un campo de fórmula: se calcula al leer, sin columna almacenada. En cualquier otro campo: el motor lo calcula a partir de la fila que guarda cada escritura y lo almacena, por lo que un valor enviado por el cliente nunca prevalece."
en: "CEL expression the field's value is computed from. On a formula field: computed on read, no stored column. On any other field: computed by the engine from the row each write stores, and stored, so a client-sent value never stands.",
221
221
verdict: ALL_TRANSLATE,
222
222
reason:
223
-
'CEL is a language name and stays verbatim; the rest is prose. The formula vocabulary already exists on this very panel — returnType.helpText ("Result type for formulas") is authored in all three locales — so this leaf was simply never reached.',
223
+
'CEL is a language name and stays verbatim; the rest is prose. The formula vocabulary already exists on this very panel — returnType.helpText ("Result type for formulas") is authored in all three locales — so this leaf was simply never reached. Re-translated when the row widened past `formula` to every type: the sentence is the field designer\'s own expression.helpText, authored in the same words in all three locales.',
{field: 'expression',widget: 'textarea',helpText: 'CEL expression to calculate this field (makes it read-only)'},
340
+
{field: 'expression',widget: 'textarea',helpText: 'CEL expression the field\'s value is computed from. On a formula field: computed on read, no stored column. On any other field: computed by the engine from the row each write stores, and stored, so a client-sent value never stands.'},
341
341
// The five members are what FieldSchema declares — an explicit list, not
342
342
// the derived enum, so this row cannot pick up a member the formula
343
343
// return type does not have. `currency` joined with #22727; its currency
// `expression`, not `formula` — the key is named for what it holds,
362
-
// not for the field type that uses it.
363
-
{field: 'expression',type: 'code',language: 'expression',helpText: 'CEL formula expression',visibleWhen: "data.type == 'formula'"},
362
+
// not for the field type that uses it. Shown for every type, as the
363
+
// field designer's own row in `field.form.ts` is: `FieldSchema`
364
+
// accepts `expression` on any type, and on a non-formula field the
365
+
// engine computes and stores it on write (`planStoredExpressions`),
366
+
// so a formula-only row hid a live key on a stored field.
367
+
{field: 'expression',type: 'code',language: 'expression',helpText: 'CEL expression the field\'s value is computed from. On a formula field: computed on read, no stored column. On any other field: computed by the engine from the row each write stores, and stored, so a client-sent value never stands.'},
364
368
// The five members are what `FieldSchema.returnType` declares, and
365
369
// the same explicit list the field designer's own control carries
366
370
// in `field.form.ts` (#19677). This grid additionally offered
0 commit comments