Skip to content

Commit 7f5b19d

Browse files
objectstack-fleet[bot]os-billclaude
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>
1 parent f7d7403 commit 7f5b19d

8 files changed

Lines changed: 27 additions & 16 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/spec': patch
3+
'@objectstack/skills': patch
4+
---
5+
6+
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.

‎content/docs/references/api/metadata.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -961,7 +961,7 @@ Metadata query with filtering, sorting, and pagination
961961
| **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). |
962962
| **nameField** | `string` | optional | [ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
963963
| **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. |
965965
| **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). |
966966
| **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. |
967967
| **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. |

‎content/docs/references/data/object.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ const result = ApiMethod.parse(data);
164164
| **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). |
165165
| **nameField** | `string` | optional | [ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
166166
| **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. |
168168
| **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). |
169169
| **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. |
170170
| **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. |

‎content/docs/references/system/migration.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ Create a new object
346346
| **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). |
347347
| **nameField** | `string` | optional | [ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
348348
| **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. |
350350
| **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). |
351351
| **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. |
352352
| **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
640640
| **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). |
641641
| **nameField** | `string` | optional | [ADR-0079] Canonical primary title field — the stored field used as the record display name (e.g. "name", "title"). |
642642
| **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. |
644644
| **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). |
645645
| **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. |
646646
| **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. |

‎packages/spec/src/data/object.zod.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2841,7 +2841,7 @@ const ObjectSchemaBase = strictObject(
28412841
* cross-repo back-compat). New metadata should set `nameField`.
28422842
*/
28432843
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.'),
28452845
/**
28462846
* [#21182 — ruling A on objectstack-ai/hotcrm#1199] The record's PICTURE:
28472847
* names the field whose value the record page header — the record chrome

‎packages/spec/src/system/metadata-form-zod-reconciliation.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ const LEDGER: ReadonlyArray<OmitEntry | SubsetEntry> = [
401401
type: 'object',
402402
path: ROOT_PATH,
403403
key: 'titleFormat',
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 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",
405405
},
406406
{
407407
kind: 'omit',

0 commit comments

Comments
 (0)