Skip to content

Commit 9249c37

Browse files
committed
docs: validating-metadata documents the react block field-prop class; fix a related-list example that named keys nothing reads
Two hand-written docs the docs-drift check flagged, both about the surface this PR changes. `deployment/validating-metadata.mdx` enumerates what `os validate` catches, and after this PR it missed the largest new class. §10 covers it: which block props resolve, that the record:* blocks ride the SAME descriptor table as §5 (so a component is described once and checked wherever it is authored), that <RecordRelatedList objectName> is the related child object, and why a filter position gates when everything else advises. §5 gains one line pointing at it. `ui/pages.mdx` authored its record:related_list example as `properties: { object, relationship }`. Neither key exists on RecordRelatedListProps and no conversion-layer alias maps them, so `properties` being unvalidated is the only reason the example parses — an author copying it gets a related list bound to nothing. Corrected to `objectName` / `relationshipField`, with a comment naming which object each one is: the same confusion this PR settles in the contract, one doc over. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012rK2McPogrTJBKdUsThrGs
1 parent a60f110 commit 9249c37

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

‎content/docs/deployment/validating-metadata.mdx‎

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,8 @@ Which object a component binds follows `dataSource.object` → `properties.objec
133133
against one page-wide guess. A `record:related_list`'s `columns`/`sort`/`filter`
134134
resolve against its **related** object (`objectName`), and its add-picker against
135135
its own. Advisory, like form-layout field references — every consumer degrades
136-
rather than failing.
136+
rather than failing. The same descriptor table drives the react page surface
137+
(§10), so a component is described once and checked wherever it is authored.
137138

138139
Skipped, to keep false positives at zero: relationship paths (`account.name`,
139140
resolved by the query engine), registry-injected system fields (`created_at`,
@@ -274,6 +275,49 @@ most-authored surfaces, so the tightening is scheduled on what this check finds
274275
rather than assumed. `defineStack` reports the same findings at config-load
275276
time, so an author sees them without running the CLI at all.
276277

278+
### 10. React block props naming fields the object doesn't have
279+
280+
§5 is about a metadata page's untyped `properties` bag. A `kind:'react'` page
281+
authors the **same** components as JSX props, and every prop that binds by field
282+
name has the same failure: the block skips the name and renders one column, one
283+
filter chip, or one form field short.
284+
285+
```jsx
286+
<ListView objectName="crm_account" columns={['name', 'revenue']} />
287+
// ↑ not a crm_account field → warning
288+
```
289+
290+
Checked on every injected block: `<ListView>`'s
291+
`fields`/`columns`/`sort`/`grouping`/`userFilters`, `<ObjectForm>`'s `fields`,
292+
`initialValues` keys, `sections[].fields[]` and `subforms` (each against its own
293+
`childObject`), and `<RecordHighlights>` / `<RecordDetails>` / `<RecordPath>` /
294+
`<RecordRelatedList>` — those last four through the **same** descriptor table
295+
§5 uses, so a component's field-bearing props are described once and checked on
296+
both surfaces. `<Block type="…">` reaches that table by the type the author
297+
writes, so the escape hatch is covered rather than left as a hole.
298+
299+
`<RecordRelatedList objectName>` is the **related (child)** object whose records
300+
are listed — the parent record is bound by `recordId`, and `relationshipField`
301+
is the child's field pointing back at it. Passing the parent there is the
302+
mistake this check was extended to catch.
303+
304+
A **filter position** is the exception that gates:
305+
306+
```jsx
307+
<ListView objectName="crm_account" filters={['revenu', '=', stage]} />
308+
// ↑ error, not a warning
309+
```
310+
311+
An unknown column in a predicate is not a skipped column — the predicate can
312+
never match, the driver's "no such column" is swallowed, and the list comes back
313+
empty and indistinguishable from *"there is no data"*. Each position of a filter
314+
is judged on its own, so the field above is still checked even though `stage`
315+
comes from React state.
316+
317+
Skipped, to keep false positives at zero: the same set as §8 — non-static
318+
values, `{...spread}` usages, relationship paths, system fields, and objects
319+
another package defines.
320+
277321
## The one gate, two entry points
278322

279323
`os validate` and `os build` (alias of `os compile`) run the **same** validator:

‎content/docs/ui/pages.mdx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,13 +228,15 @@ const accountRecordPage = {
228228
type: 'record:related_list',
229229
id: 'contacts',
230230
label: 'Contacts',
231-
properties: { object: 'contact', relationship: 'account' },
231+
// `objectName` is the RELATED (child) object being listed;
232+
// `relationshipField` is the child's field pointing back at this record.
233+
properties: { objectName: 'contact', relationshipField: 'account' },
232234
},
233235
{
234236
type: 'record:related_list',
235237
id: 'opportunities',
236238
label: 'Opportunities',
237-
properties: { object: 'opportunity', relationship: 'account' },
239+
properties: { objectName: 'opportunity', relationshipField: 'account' },
238240
},
239241
],
240242
},

0 commit comments

Comments
 (0)