Skip to content

Commit 3a09125

Browse files
docs(skills): a primary related list is a body table in the Details tab, and the relatedLists refusal states its package boundary (#27958)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} --> _Requested by **Elon** · [project thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9D9EoRyLJMPig8fRoFZTwL2h)_ domain:skills#2 · os-elon-musk · session_016WV4cyuFKhHVaGYSSdTHG8 Fixes #27354 ## What changes - `skills/objectstack-ui/SKILL.md` (read side, related-list layout): a `relatedList: 'primary'` child is a full-width body table in the details column after the first field section, inside the Details tab with no tab of its own; every other list is a side card in the one shared **Related** tab; field changes (`trackHistory`) join the Timeline tab under its Changes filter, and there is no History tab. The paragraph also stops teaching an app-level `relatedLayout: 'tabs' | 'stack'` override as surviving: objectstack#27055 removed it from the synthesizer (`ui/packages/plugin-detail/src/synth/buildDefaultPageSchema.ts:163-171`), and no spec schema carries it. - `skills/objectstack-data/rules/relationships.md` (Detail-page related lists): the `'primary'` bullet says the same placement, and the `relatedLists` refusal states its boundary: a child in the stack with no inbound FK is refused everywhere; one that exists nowhere is refused by `os validate` / `os build` and by a metadata write naming no package; a write into a package stores it, and the page places nothing. - `.changeset/27354-skills-related-list-body-table.md`: `@objectstack/skills` patch. ## Why Both pages still taught the pre-v3 page after PR #27310 (`eef83734d`, record page v3) and PR #27352 (`ad3a640e3`, rewritten describes, seat ruling A on #27311). The new text follows `packages/spec/src/data/field.zod.ts:1831` (`relatedList`), `packages/spec/src/data/object.zod.ts:3178` (`relatedLists`), `:277` (`trackHistory`), and `buildDefaultTabs` in `buildDefaultPageSchema.ts:1016-1121`. Measured on `origin/main` `ca54eaca`: a shared Related tab still exists for non-primary lists (and attachments); History is no tab, it is the Timeline stream's Changes filter. `grep -rniE "own tab|related tab|matching no inbound"` over `skills/**` (evals included, every package) hits only the two passages fixed here; `content/docs/ui/pages.mdx:187` already teaches the side-card Related tab correctly. No eval teaches the old text. ## Token ratchet (`node scripts/check-skills-token-ratchet.mjs`) | File | Before | After | Ceiling | Ceiling moved | |:--|--:|--:|--:|:--| | `skills/objectstack-ui/SKILL.md` | 3848 | 3851 | 3851 | no | | `skills/objectstack-data/rules/relationships.md` | 3872 | 3848 | 3873 | no | Paid in-file by deleting restated text, no re-wrap: in `objectstack-ui`, the primary bullet's tab clause (now said once, in the layout paragraph), "Promoting a child table to a tab is a one-word change" and the surviving-`relatedLayout` sentence; in `relationships.md`, "The UI is derived from metadata (…)" (restates the sentence before it), the `'grid'` / `'form'` bullets' restatement of the code block's comments, the write-side parenthetical, "on the parent's detail page" in the default sentence, "(default with inlineEdit)" in the example comment (the bullet says it) and "both are optional — when omitted". No ceiling row is raised. ## Verification - `pnpm install --frozen-lockfile --ignore-scripts` (exit 0), then every family `node scripts/pm/dispatch-gates.mjs --commands` derives at `46c30d4c`: 45 families, re-derived after commit (identical). 40 exit 0 on the first run; 5 exit 3 (prerequisite: dists) until `pnpm exec turbo run build` (116 tasks, exit 0), then exit 0. `dispatch-gates --ran`: 45 derived, 45 run, 0 NOT-MEASURED, 0 UNRUN. Clause-②: no Metadata-protocol: none ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. (no names added) - [x] 3. No formatter ran. (Markdown only; `pnpm lint` not run locally, CI runs it.) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: n/a. - [x] 7. No hand edits to generated references, changelogs or release notes. - [x] 8. Title, body and comments are in English. ## 维护者速读 - 改了什么:两份对外技能(objectstack-ui、objectstack-data)里关于记录页「相关列表」的说法改成现状:主相关列表是详情页签里的整宽表格,不再单独占一个页签;其余列表是共享「关联」页签里的侧卡;字段变更在时间线的「变更」筛选里,没有历史页签。 - 为什么改:记录页 v3(#27310)与规范描述重写(#27352)落地后,技能还在教旧页面,AI 照着写会设计出不存在的页签,还以为任何拼错的 `relatedLists` 名都会被拒。 - 风险与回滚:只改文档文字,无代码、无 schema;回滚即撤回本 PR。两份文件都在 token 天花板之内,没有提高任何上限。 - 先看:`skills/objectstack-ui/SKILL.md` 的 Related-list layout 段,和 `relationships.md` 的 `relatedList` 三态列表。 - 两分钟验证:对照 `field.zod.ts:1831` 与 `object.zod.ts:3178` 的 describe 读两段新文字;跑 `node scripts/check-skills-token-ratchet.mjs`。 - 需要你做的:受管面 `skills/**`,欠一次契约复审(fable 档),落地为 Tier H,需受管审批人批准。 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_016WV4cyuFKhHVaGYSSdTHG8 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent e9caebe commit 3a09125

3 files changed

Lines changed: 39 additions & 27 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): objectstack-ui and objectstack-data teach a primary related list as a body table in the Details tab, and the relatedLists refusal with its package boundary
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Before.** Both skills said a `relatedList: 'primary'` child gets its own tab on the record page, `objectstack-ui` described one tab per primary list plus a shared Related tab and an app-level `relatedLayout` override, and `objectstack-data` said a `relatedLists` name matching no inbound FK is refused, with no boundary.
11+
- **Now.** A primary list is a full-width body table in the details column after the first field section (inside the Details tab, no tab of its own); every other list is a side card in the shared Related tab; field changes join the Timeline tab under its Changes filter. A `relatedLists` child in the stack with no inbound FK is refused everywhere; one that exists nowhere is refused by `os validate` / `os build` and by a metadata write naming no package, while a write into a package stores it and the page places nothing. No ceiling moves; no schema, key or behaviour changes.

‎skills/objectstack-data/rules/relationships.md‎

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -229,8 +229,7 @@ Declare inline editing **on the relationship**, in the data model — not in a f
229229
view. Set `inlineEdit: true` on the child's `master_detail` (or `lookup`) field
230230
that points back to the parent. The parent's **standard** create/edit form then
231231
renders an editable grid for these children and saves parent + children in **one
232-
atomic transaction** — with no form-view config and no bespoke page. The UI is
233-
derived from metadata (relationship FK + child fields → grid columns).
232+
atomic transaction** — with no form-view config and no bespoke page.
234233
235234
```typescript
236235
// On the CHILD object's FK field:
@@ -271,10 +270,9 @@ inlineEdit: 'grid' // editable line-item grid (fast bulk entry; thin childre
271270
inlineEdit: 'form' // read-only list; "Add" / per-row edit opens the FULL form
272271
```
273272
274-
- **`'grid'`** — spreadsheet-like editable grid. Best for *thin* line items
273+
- **`'grid'`** — best for *thin* line items
275274
(invoice/order lines): few columns, high volume, keyboard-fast.
276-
- **`'form'`** — compact read-only list; Add / per-row edit opens the child's
277-
complete form. Best for *fat* children (long text, attachments, many fields)
275+
- **`'form'`** — best for *fat* children (long text, attachments, many fields)
278276
that don't fit a narrow grid cell.
279277
- **`true`** / omitted — **smart default**: picks `form` when the child has
280278
rich/form-only fields (textarea, file, image, json, location…) or more than ~8
@@ -320,11 +318,10 @@ InvoiceLine = {
320318
321319
### Detail-page related lists (the read-side mirror)
322320
323-
Where `inlineEdit` is the **write** side (child pulled into the parent's entry
324-
form), the **related list** on the parent's record detail page is the **read**
321+
Where `inlineEdit` is the **write** side, the **related list** on the parent's record detail page is the **read**
325322
side. You usually don't declare it: every child relationship
326-
(`master_detail` and `lookup`) is shown as a related list on the parent's detail
327-
page **by default** — owned (`master_detail`) children first. The relationship
323+
(`master_detail` and `lookup`) is shown **by default** — owned (`master_detail`)
324+
children first. The relationship
328325
flags exist to *refine* that:
329326
330327
```typescript
@@ -333,7 +330,7 @@ project: {
333330
type: 'master_detail',
334331
reference: 'project',
335332
inlineEdit: true, // write side: edit inline in the Project form
336-
relatedList: 'primary', // read side: a body table (default with inlineEdit)
333+
relatedList: 'primary', // read side: a body table
337334
relatedListTitle: 'Tasks', // title of the detail-page list
338335
relatedListColumns: ['title', 'status', 'priority', 'due_date'],
339336
},
@@ -344,16 +341,21 @@ audit_ref: { type: 'master_detail', reference: 'invoice', relatedList: false },
344341
345342
`relatedList` is tri-state — placement (ADR-0085):
346343
347-
- `'primary'` — main content: a full-width table in the record's body (its own
348-
tab on the tabbed page). Default for a `master_detail` FK with `inlineEdit`.
344+
- `'primary'` — main content: a full-width table in the details column after
345+
the first field section (in the Details tab, no tab of its own). Default for a
346+
`master_detail` FK with `inlineEdit`.
349347
- `false` — hidden from the parent's page.
350348
- `true`, or omitted (except inline-edited `master_detail`) — a side card
351349
(the shared **Related** tab).
352350
- Order is the parent's: `relatedLists: ['task', 'event.related_to']` (child, or
353-
`object.field`) lists those first; a name matching no inbound FK is refused.
351+
`object.field`) lists those first. A child in the stack with no inbound FK is
352+
refused everywhere; one that exists nowhere is refused by `os validate` /
353+
`os build` (which leave a `sys_` / `cloud_` / `ai_` or sibling-artifact name
354+
to the runtime) and by a metadata write naming no package — a write into a
355+
package stores it, and the page places nothing.
354356
355357
`relatedListTitle` / `relatedListColumns` override the derived title / columns;
356-
both are optional — when omitted, columns auto-derive from the child object's
358+
otherwise columns auto-derive from the child object's
357359
`highlightFields` (the same source the lookup picker uses). Audit FKs
358360
(`created_by`/`updated_by`/`owner_id`) never become related lists. A child that
359361
references the parent through several FKs (e.g. `primary_account` +

‎skills/objectstack-ui/SKILL.md‎

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -106,25 +106,24 @@ and the form's `taxRateField` overrides which parent field drives the totals.
106106
related list on the parent's record DETAIL page. You don't author it: every
107107
child relationship is shown as a related list by default (owned `master_detail`
108108
children first). Refine on the relationship:
109-
- `relatedList: 'primary'` — main content: a body table, its **own tab** on the
110-
tabbed page (see layout below); it places, the parent's `relatedLists` orders
111-
(ADR-0085).
109+
- `relatedList: 'primary'` — main content: a full-width body table (see layout
110+
below); it places, the parent's `relatedLists` orders (ADR-0085).
112111
- `relatedList: false` — suppress a noisy child from the detail page.
113112
- `relatedListTitle` / `relatedListColumns` — override the derived title /
114113
columns (both optional; columns otherwise auto-derive from the child object's
115114
`highlightFields`). See objectstack-data → Relationships → Detail-page related lists.
116115

117116
**Related-list layout.** On the synthesized record page, each
118-
`relatedList: 'primary'` child (default: inline-edited `master_detail`) gets its
119-
**own tab**; every other list stacks under one shared **Related** tab, both in
120-
the object's `relatedLists` order. Promoting a child table to a tab is a
121-
one-word change on the relationship. The object still declares no per-surface
122-
*layout* hints: the old
123-
`detail.relatedLayout` toggle and object-level `detail: {...}` block stay
124-
**removed** (ADR-0085); `relatedLayout: 'tabs' | 'stack'` survives only as an
125-
app-level default override, not an object key. For arrangements the
126-
relationship layer can't express — filtered splits (e.g. Open vs Closed tabs), a
127-
chart/report tab — assign the object a **custom record Page** and lay it out
117+
`relatedList: 'primary'` child (default: inline-edited `master_detail`) is a
118+
body table in the details column after the first field section (in the
119+
Details tab, no tab of its own); every other list is a side card in one shared
120+
**Related** tab, both in the object's `relatedLists` order. Field changes
121+
(`trackHistory`) join the Timeline tab under its Changes filter; there is no
122+
History tab. The object declares no per-surface *layout* hints: the
123+
`detail.relatedLayout` toggle, object-level `detail: {...}` block and app-level
124+
`relatedLayout` are **removed** (ADR-0085). For arrangements the relationship
125+
layer can't express — filtered splits (e.g. Open vs Closed tabs), a chart/report
126+
tab — assign the object a **custom record Page** and lay it out
128127
explicitly with `record:related_list` (or inline-editable `line_items`) blocks.
129128

130129
### Field Conditional Rules in Forms

0 commit comments

Comments
 (0)