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 7f5b19d
Browse filesBrowse the repository at this point in the historyBrowse files
authored
docs(spec, skills): a queried composite record title is a stored computed field, not a formula; a stored field's expression is the engine's, never a client hint (#25183)
Fixes#25129
Clause-②: no
Metadata-protocol: none
**Governance: Tier H.** This diff touches `skills/**` (the published
`objectstack-data` skill), a governed surface, so it lands only on an
authorized APPROVED review. It stays a draft until then; the relay's
`pr_create` requests the governed review itself.
## What changes
Ruling 6308445871 (#24981, letter A), item 2: "The producer stores the
title it needs to query: a composite title that must round-trip through
import is a stored computed field (a non-formula field with an
`expression`, written on write — the #24619 shape), the remedy ADR-0079
item 9 already prescribes for sort and search." PR #25127 (#25071)
re-worded the record-title lint, ADR-0079 D3 and `formulas.mdx` to that
shape. This PR finishes the same reconciliation on the copies that card
did not claim, and keeps "a text formula title stays legal for display
only".
| Site | Before | After |
|---|---|---|
| `packages/spec/src/data/object.zod.ts`, the `titleFormat` describe |
"Migrate a single-field title to nameField, a composite to a formula
field designated as nameField." | a composite title that import, sort or
search must match → a stored computed field (a non-formula field with an
expression, computed and stored on every write) designated as nameField;
a text formula designated as nameField stays legal for a title shown for
display only |
| `content/docs/references/data/object.mdx`,
`references/api/metadata.mdx`, `references/system/migration.mdx` (two
rows) | generated copies of that describe | regenerated with `pnpm
--filter @objectstack/spec check:generated --fix` after the build; the
diff is the four `titleFormat` rows and nothing else |
| `packages/spec/src/system/metadata-form-zod-reconciliation.test.ts`,
the `titleFormat` omit-ledger note | quotes the old describe | quotes
the new prescription; "every target is authorable" |
| `skills/objectstack-data/SKILL.md`, `nameField` row | "or a formula
field (`returnType: 'text'`) for a composite title" | "a composite title
to import, sort or search by is a stored computed field (a non-`formula`
field with an `expression`, computed and stored on write); a text
formula is display-only" |
| `skills/objectstack-data/SKILL.md`, `titleFormat` row | "for a
composite title, designate a `returnType: 'text'` formula field as
`nameField`" | "a composite title follows the `nameField` row" |
| `skills/objectstack-data/rules/relationships.md`, the "Computed
column" bullet (seat pointer 6333459023) | "the server only treats
`type: 'formula'` as computed, so on a stored field the `expression` is
a client compute hint and the sent value is stored verbatim" | "the
engine computes a stored field's `expression` from the row the write
stores and stores the result, so a client-sent value never stands" |
The `nameField` describe carries no composite-to-formula prescription
(measured; the dispatch's H2 is falsified for that site). Its TSDoc
lists "formula→text" among the stored title fields, D1's wording that
ADR-0079's addendum qualifies without editing; it prescribes nothing for
a composite title and is left alone.
## The shape is real on origin/main
- `FieldSchema.expression` describe
(`packages/spec/src/data/field.zod.ts`): "On any other (stored) field:
computed by the engine from the row the write stores and stored, so a
client-sent value never stands".
- `packages/objectql/src/engine.ts` `planStoredExpressions` /
`replacedStoredExpressionFields`;
`packages/spec/src/contracts/data-engine.ts`: since #25000 a
`strictReadonlyWrites` write whose value such a field's expression
replaces is refused, and a non-strict one is reported under
`stored_expression`.
- ADR-0079 addendum item 9: a formula value is stored nowhere; a sort by
it is refused, search cannot reach it; an object that must sort or
search by a composite title stores it.
## Sweep (H2, H3)
- `packages/spec/src/**`: "composite" with "formula", "nameField" or
"title" → the describe and the reconciliation note only (control word
`titleFormat`: 10 files, none a prescription).
- `skills/**`: "composite" with "formula", "title" or "nameField" → the
two SKILL.md rows only; "compute hint", "stored verbatim", "only
treats", "as computed" → the relationships.md bullet only (control word
`titleFormat`: 3 hits; the other two are the formula skill's template
table and a query-filter example, neither a prescription).
`rules/field-types.md:124` already says a `formula` is virtual,
consistent with the new text.
- Repo-wide outside the card: the old sentence survives only in
`packages/*/CHANGELOG.md` (release-owned; never edited in a code PR) and
in two test docblocks describing landed in-repo migrations
(`packages/services/service-messaging/src/objects/notification-display-title.test.ts:18`,
`packages/platform-objects/src/identity/identity-display-title.test.ts:17`),
the in-repo `display_title` formulas the card excludes.
## skills/** readings
Published: `@objectstack/skills` (`packages/skills`,
`publishConfig.access: public`, in the changeset `fixed` group) ships
`skills/**` as `dist/skills/SKILL_NAME/…` through
`scripts/sync-catalog.mjs`, with `files: ["dist", "README.md",
"CHANGELOG.md"]`. So the skill half owes a changeset; it rides in the
same file as the spec half.
Lines (budget: at most +2 net across `skills/objectstack-data/`):
| File / set | Before | After | Net |
|---|---|---|---|
| `skills/objectstack-data/SKILL.md` | 469 | 465 | −4 |
| `skills/objectstack-data/rules/relationships.md` | 401 | 401 | 0 |
| whole package, every `.md` under `skills/objectstack-data/` | 3713 |
3709 | −4 |
| all `skills/**/SKILL.md` summed | 4393 | 4389 | −4 |
Tokens (`scripts/check-skills-token-ratchet.mjs`, `ceil(utf8 bytes /
4)`, release stamp unpriced):
| File | Before | After | Ceiling |
|---|---|---|---|
| `skills/objectstack-data/SKILL.md` | 6123 | 6099 | 6123 |
| `skills/objectstack-data/rules/relationships.md` | 3676 | 3672 | 3676
|
The first re-wording of the `nameField` row put `SKILL.md` 48 tokens
over its ceiling (`6171 / 6123`). Paid in the same file by deletion,
never by re-wrap: the two re-worded rows tightened; the incident
sentence "It used to clear both and then never match." dropped; the
parenthetical "(Reminder: two consecutive `os build` runs with no source
change must be byte-identical — see the determinism gate above.)"
dropped, because that gate lives in `references/seeds.md`, not above; a
doubled `---` separator removed. No ceiling moved.
## Tests
Measured at head `e74783922` (base `ab488d9b7`; `origin/main` has since
gained three commits that touch none of these paths, so no pre-PR
merge):
- `pnpm --filter @objectstack/spec build`, under the shared verify lock:
`VERDICT command-exit 0`. `packages/spec` has no workspace dependencies,
so the ① closure build is empty.
- `pnpm --filter @objectstack/spec check:generated`: `check:docs` was
the one stale artifact of 14; `--fix` regenerated it (under the lock,
`VERDICT command-exit 0`); the re-check reads `✓ check:docs`.
- `pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2` over
the six spec test files that mention `titleFormat` (the reconciliation
note among them): `Test Files 6 passed (6)`, `Tests 267 passed (267)`,
`VERDICT command-exit 0`. Declared narrowing: the spec suite is 779
files, over the foreground cap; only the reconciliation note pins the
changed text and no test reads the `titleFormat` describe; CI's `Test
Core` runs the whole suite.
- `pnpm --filter @objectstack/spec typecheck` (tsc,
`check:scripts-typecheck`, `check:test-typecheck`): `VERDICT
command-exit 0`.
- No ablation: no tested behaviour changed (a describe string, a ledger
note's prose, skill text).
## Gates
Derived on the final commit with `node scripts/pm/dispatch-gates.mjs
--commands --repo objectstack-ai/objectstack` (no paths; "gate list
derived from the tree of 'objectstack-ai/objectstack' at commit
e747839"): 119 commands. Each was run from the worktree root with its
exit code captured before any pipe and recorded as `COMMAND :: exit N`;
`--ran` then read: "119 derived famil(ies) accounted for — 118 run, 1
NOT-MEASURED (1 DERIVED from a recorded exit 3)".
- 118 commands exit 0, among them `check:docs`, `check:generated`,
`check:skill-docs`, `check:skill-refs`, `check:skill-examples` (after
building `@objectstack/client-react` / `@objectstack/client`, its
declared prerequisite), `check:skills-token-ratchet`,
`check:skill-identifier-liveness`, `check:skill-frame-sync`,
`check:skill-compatibility`, `check:doc-authoring`,
`check:doc-formula-expressions` (after building `@objectstack/formula` /
`@objectstack/lint`, its declared prerequisite),
`check-empty-changeset`, `check-changeset-no-major`,
`check-adr-0087-registration`, `check:nul-bytes`,
`check:pm-governed-merges`.
- NOT MEASURED: `pnpm check:dual-build-cjs-loads`, exit 3 (PREREQUISITE
NOT MET: it reads every package's `dist/`, a whole-repo build); CI runs
it. The diff changes no build output shape.
- Not derived, run by hand: `node
scripts/check-skills-token-ratchet.mjs` before and after the payment (`✗
over by 48`, then `✓ 54 authored bundle file(s) within their ceilings`).
## Changeset
`.changeset/25129-composite-title-stored-field.md`: `@objectstack/spec`
`patch` and `@objectstack/skills` `patch`, `Clause-②: no`,
`Metadata-protocol: none`. The text an author reads changes; no key,
type, default or accepted value does.
## Acceptance notes
- The `nameField` TSDoc's "(text / autonumber / formula→text)" lists a
formula among the "real stored" title fields, D1's wording that the
ADR-0079 addendum qualifies without editing; it prescribes nothing and
is not in scope. Noted, not filed.
- The two in-repo test docblocks and the CHANGELOG entries named under
Sweep keep the old sentence as a description of landed migrations; the
card excludes those packages. Noted, not filed.
## 维护者速读(草稿)
- **改了什么**:`titleFormat` 的 describe(及其三页生成的参考文档)、引用它的表单对账注记,以及已发布的
`objectstack-data` 技能包里 `nameField` / `titleFormat` 两行和「Computed
column」一条。措辞统一为:需要被导入匹配、排序或搜索的组合标题应使用存储型计算字段(非 formula 字段加
`expression`,写入时由引擎计算并落库);text formula 标题仍合法,但只用于展示。「Computed
column」改为:存储字段的 `expression` 由引擎按写入行计算并落库,客户端送来的值不作数。
- **为什么改**:旧文案把作者引向 formula 标题,而 formula
值不落库,导致排序被拒、搜索够不到、导入无法按标题匹配(ADR-0079 补充第 9 条与裁决 6308445871);PR #25127
已改了 lint 与 ADR,这是同一次对账剩下的几处。技能包里「expression 只是客户端提示、值按送达原样存储」与 main
上的引擎行为相反,是 AI 作者在同一个包里读到的自相矛盾。
- **风险与代价(含回滚)**:仅文案;无键、类型、默认值或接受值变化;技能包行数净 −4,token
在天花板内(6099/6123),天花板未动;为付 token 账删掉的三处都是失效指引或事故叙述。回滚即还原本 PR。
- **席位意见**:
- **你要做的**:本 PR 触及 `skills/**`,属 Tier H,需要一次授权的 APPROVED 评审后才能落地。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T1Y1g92DfSEz93iuCisju4)_
---------
Co-authored-by: os-bill <bill@objectstack.ai>
Co-authored-by: Claude <noreply@anthropic.com>
docs(spec, skills): the `titleFormat` description and the objectstack-data skill no longer steer a composite record title that must be queried into a formula field
7
+
8
+
Clause-②: no
9
+
Metadata-protocol: none
10
+
11
+
The `titleFormat` description (and its generated copies on the object, metadata and migration reference pages) and the `objectstack-data` skill's `nameField` and `titleFormat` rows told an author to migrate a composite record title to a `formula` field with `returnType: 'text'` designated as `nameField`. A formula value is computed on read and stored nowhere, so a sort by it is refused, search never reaches it, and an import cannot match a lookup cell against it. Both now say what the record-title lint and ADR-0079 D3 already say: a composite title that import, sort or search must match is a stored computed field, a non-`formula` field that declares an `expression`, which the engine computes and stores on every write, designated as `nameField`; a text formula designated as `nameField` stays legal for a title shown for display only.
12
+
13
+
The same skill's "Computed column" bullet (`rules/relationships.md`) said a stored field's `expression` is a client compute hint and the sent value is stored verbatim. The engine computes the expression from the row the write stores and stores the result, so a client-sent value never stands; the bullet now says so.
14
+
15
+
No key, type, default or accepted value changes; only the text an author reads changes.
Copy file name to clipboardExpand all lines: content/docs/references/api/metadata.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -961,7 +961,7 @@ Metadata query with filtering, sorting, and pagination
961
961
|**activityMilestones**|`{ field: string; value: string; summary: string; type?: string }[]`| optional | Declarative semantic activity milestones — emit a templated timeline row when a field transitions into a value, no hook code (ADR-0052 §5b.2). |
962
962
|**nameField**|`string`| optional |[ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
963
963
|**displayNameField**|`string`| optional |[DEPRECATED → nameField] Field to use as the record display name (e.g., "name", "title"). Accepted as an alias for nameField. |
964
-
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
964
+
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField; a composite title that import, sort or search must match to a stored computed field (a non-formula field with an expression, computed and stored on every write) designated as nameField — a text formula designated as nameField stays legal for a title shown for display only. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
965
965
|**imageField**|`string`| optional | The record's picture: names the field the record page header (record chrome) draws beside the title — one object-level declaration every record detail page reads, not a per-page header prop. Must name a field of this object whose type is `image` or `avatar`; any other name is refused. A record whose field is empty shows no picture (no initials or placeholder). |
966
966
|**highlightFields**|`string[]`| optional |[ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. |
967
967
|**stageField**|`string \| false`| optional |[ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. When the named field carries options, it must be a single-value `select` / `radio` with inline `options`, each declaring its `kind` ('open' / 'won' / 'lost'); a picklist-backed or multi-value stage field is refused. A name that resolves to no declared field, or a field with no options, is not judged at parse. |
Copy file name to clipboardExpand all lines: content/docs/references/data/object.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -164,7 +164,7 @@ const result = ApiMethod.parse(data);
164
164
|**activityMilestones**|`{ field: string; value: string; summary: string; type?: string }[]`| optional | Declarative semantic activity milestones — emit a templated timeline row when a field transitions into a value, no hook code (ADR-0052 §5b.2). |
165
165
|**nameField**|`string`| optional |[ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
166
166
|**displayNameField**|`string`| optional |[DEPRECATED → nameField] Field to use as the record display name (e.g., "name", "title"). Accepted as an alias for nameField. |
167
-
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
167
+
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField; a composite title that import, sort or search must match to a stored computed field (a non-formula field with an expression, computed and stored on every write) designated as nameField — a text formula designated as nameField stays legal for a title shown for display only. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
168
168
|**imageField**|`string`| optional | The record's picture: names the field the record page header (record chrome) draws beside the title — one object-level declaration every record detail page reads, not a per-page header prop. Must name a field of this object whose type is `image` or `avatar`; any other name is refused. A record whose field is empty shows no picture (no initials or placeholder). |
169
169
|**highlightFields**|`string[]`| optional |[ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. |
170
170
|**stageField**|`string \| false`| optional |[ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. When the named field carries options, it must be a single-value `select` / `radio` with inline `options`, each declaring its `kind` ('open' / 'won' / 'lost'); a picklist-backed or multi-value stage field is refused. A name that resolves to no declared field, or a field with no options, is not judged at parse. |
Copy file name to clipboardExpand all lines: content/docs/references/system/migration.mdx
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -346,7 +346,7 @@ Create a new object
346
346
|**activityMilestones**|`{ field: string; value: string; summary: string; type?: string }[]`| optional | Declarative semantic activity milestones — emit a templated timeline row when a field transitions into a value, no hook code (ADR-0052 §5b.2). |
347
347
|**nameField**|`string`| optional |[ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
348
348
|**displayNameField**|`string`| optional |[DEPRECATED → nameField] Field to use as the record display name (e.g., "name", "title"). Accepted as an alias for nameField. |
349
-
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
349
+
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField; a composite title that import, sort or search must match to a stored computed field (a non-formula field with an expression, computed and stored on every write) designated as nameField — a text formula designated as nameField stays legal for a title shown for display only. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
350
350
|**imageField**|`string`| optional | The record's picture: names the field the record page header (record chrome) draws beside the title — one object-level declaration every record detail page reads, not a per-page header prop. Must name a field of this object whose type is `image` or `avatar`; any other name is refused. A record whose field is empty shows no picture (no initials or placeholder). |
351
351
|**highlightFields**|`string[]`| optional |[ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. |
352
352
|**stageField**|`string \| false`| optional |[ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. When the named field carries options, it must be a single-value `select` / `radio` with inline `options`, each declaring its `kind` ('open' / 'won' / 'lost'); a picklist-backed or multi-value stage field is refused. A name that resolves to no declared field, or a field with no options, is not judged at parse. |
@@ -640,7 +640,7 @@ Create a new object
640
640
|**activityMilestones**|`{ field: string; value: string; summary: string; type?: string }[]`| optional | Declarative semantic activity milestones — emit a templated timeline row when a field transitions into a value, no hook code (ADR-0052 §5b.2). |
641
641
|**nameField**|`string`| optional |[ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
642
642
|**displayNameField**|`string`| optional |[DEPRECATED → nameField] Field to use as the record display name (e.g., "name", "title"). Accepted as an alias for nameField. |
643
-
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
643
+
|**titleFormat**|`string \| { dialect: 'template'; source?: string; ast?: any; meta?: object }`| optional |[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField; a composite title that import, sort or search must match to a stored computed field (a non-formula field with an expression, computed and stored on every write) designated as nameField — a text formula designated as nameField stays legal for a title shown for display only. Placeholders may be written `{{field}}` or `{field}` — the title renderers treat the two as equivalent, normalizing `{{field}}` to `{field}` before substituting; neither spelling is judged at parse time. |
644
644
|**imageField**|`string`| optional | The record's picture: names the field the record page header (record chrome) draws beside the title — one object-level declaration every record detail page reads, not a per-page header prop. Must name a field of this object whose type is `image` or `avatar`; any other name is refused. A record whose field is empty shows no picture (no initials or placeholder). |
645
645
|**highlightFields**|`string[]`| optional |[ADR-0085] Ordered most-important fields; first entry wins where only one fits. Drives default columns, cards, previews, detail highlight strip. Renamed from compactLayout. |
646
646
|**stageField**|`string \| false`| optional |[ADR-0085] Lifecycle stage field (linear/ordered), or false to declare the status field non-linear and suppress stage heuristics. Absent = heuristic detection allowed. When the named field carries options, it must be a single-value `select` / `radio` with inline `options`, each declaring its `kind` ('open' / 'won' / 'lost'); a picklist-backed or multi-value stage field is refused. A name that resolves to no declared field, or a field with no options, is not judged at parse. |
* cross-repo back-compat). New metadata should set `nameField`.
2842
2842
*/
2843
2843
displayNameField: z.string().optional().describe('[DEPRECATED → nameField] Field to use as the record display name (e.g., "name", "title"). Accepted as an alias for nameField.'),
2844
-
titleFormat: TemplateExpressionInputSchema.optional().describe('[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField, a composite to a formula field designated as nameField. Placeholders may be written {{field}} or {field} — the title renderers treat the two as equivalent, normalizing {{field}} to {field} before substituting; neither spelling is judged at parse time.'),
2844
+
titleFormat: TemplateExpressionInputSchema.optional().describe('[DEPRECATED → nameField (ADR-0079)] Render-only title template; the server cannot return or query it, and an explicit nameField now takes precedence. Migrate a single-field title to nameField; a composite title that import, sort or search must match to a stored computed field (a non-formula field with an expression, computed and stored on every write) designated as nameField — a text formula designated as nameField stays legal for a title shown for display only. Placeholders may be written {{field}} or {field} — the title renderers treat the two as equivalent, normalizing {{field}} to {field} before substituting; neither spelling is judged at parse time.'),
2845
2845
/**
2846
2846
* [#21182 — ruling A on objectstack-ai/hotcrm#1199] The record's PICTURE:
2847
2847
* names the field whose value the record page header — the record chrome
why: "`[DEPRECATED → nameField (ADR-0079)]` render-only title template the server cannot return or query, deliberately not offered to new authors; its own describe prescribes the migration — a single-field title to `nameField`, a composite to a formula field designated as `nameField`— and both targets are authorable",
404
+
why: "`[DEPRECATED → nameField (ADR-0079)]` render-only title template the server cannot return or query, deliberately not offered to new authors; its own describe prescribes the migration — a single-field title to `nameField`, a composite title that import, sort or search must match to a stored computed field (a non-formula field with an `expression`) designated as `nameField`, a text formula staying legal for display only — and every target is authorable",
0 commit comments