Commit 4c127cd
fix(plugin-detail): record:related_list stops requiring
Fixes #11613
Clause-②: yes
## What changes
The `record:related_list` registration in `@object-ui/plugin-detail`
(`ComponentRegistry.register('related_list', …)`) no longer declares
`required: true` on its `columns` input. The input's description now
says where the columns come from when the key is absent. The ledger row
`record:related_list.columns` in objectui#11605's enumeration pin is
deleted, so that pin now covers this member like the others.
This is triage's first grade on the card (comment `5980741977`), under
objectui#11605's ruling (a): the spec row
`ComponentPropsMap['record:related_list'].columns` is optional, and the
registration may not be stricter than the row it publishes. The spec
row's own describe says what an omitted list means: "Optional: when
omitted, columns derive from the related object's highlightFields /
default list columns".
No new manifest vocabulary, no new compile rule, no runtime change.
`packages/types`, `sdui-parser` and the renderer are not edited. Landing
site as dispatched: the registration in
`packages/plugin-detail/src/index.tsx`, the ledger row, and tests beside
them.
## Accept-set changes (for the contract review)
Measured against the manifest the console ships: `emitSduiManifest` over
`dev/manifest-registry.ts`, read back from the written
`sdui.manifest.json`. "Before" is the registration with `required: true`
(base `2abec3a`, re-measured on this branch by ablation 1 below);
"after" is this head. Nodes are written as JSON keys here; the pins
write the same nodes as JSX.
| `type: "record:related_list"` node with | Before | After |
|:--|:--|:--|
| `objectName`, `relationshipField`, `dataSource: { object, view }`, no
`columns` | `ok: false`, one `missing-required-prop` error naming
`columns` | `ok: true`, no diagnostics, the binding recorded |
| `objectName`, `relationshipField`, no `columns`, no binding | `ok:
false`, the same error | `ok: true`, no diagnostics |
| `objectName`, `relationshipField`, `dataSource: { object }` (no view),
no `columns` | `ok: false`, the same error | `ok: true`, no diagnostics
|
| `objectName`, `relationshipField`, `columns`, `dataSource: { object,
view }` (control) | `ok: true` | the same |
| `objectName`, `columns`, no `relationshipField` (control) | refused,
one error naming `relationshipField` | the same |
| `relationshipField`, `columns`, no `objectName`, bound by `dataSource:
{ object }` or not (control) | refused, one error naming `objectName` |
the same; the spec row requires it |
**What the accept set gains:** exactly the nodes that omit `columns` and
carry everything else the gate already required (`objectName` and
`relationshipField`), with or without a `dataSource` binding.
**What stays refused:** a node without `objectName`, bound or not, and a
node without `relationshipField`.
**Unchanged, and not refusals before or after:** a `columns` value of
the wrong kind (a number or a string) draws a `type-mismatch` warning
with `ok: true`; a spec-legal column object draws a
`member-type-mismatch` warning with `ok: true` (Acceptance notes).
Neither check reads `required`.
## What a columns-less node draws (measured, not assumed)
Triage's premise, that the neither node auto-derives its columns, is now
a measurement.
`RecordRelatedListRenderer.columnsOptional-11613.test.tsx` renders
through the real renderer, the real `ElementDataSourceGate`, the real
`RelatedList` and the real table, and reads header and body cells:
- The neither node draws columns derived from the related object
(`Subject`, `Status`, `Priority`, and not the foreign key back to the
parent). This holds unbound and bound by object alone. No hint, no
blank, no throw.
- The view-bound node draws the view's columns only (`Subject`).
- Authored `columns` win over the view and over the derivation.
## Who reads the registration's `required` for this input
Enumerated by grepping non-test sources for reads of `required` off
registration or manifest `inputs`:
- `@object-ui/sdui-parser` `validateTree`, the `missing-required-prop`
check (`input.required && !(input.name in node)`). It is the page
compile and its `ok`, the save gate. It now accepts the nodes above.
- `@object-ui/components`' page renderer, the `kind: 'html'` page
compile (`manifestFromConfigs` over the live registry). The same
validator at render time, so the same widening. Source reading, not
separately measured.
- `@object-ui/sdui-parser` codegen. `generateDts` now writes `columns?:
string[]` on `RecordRelatedListProps`, and `generateBlockList`'s
required column for the tag reads `objectName, relationshipField`.
Measured once on this branch by a throwaway probe, not committed.
- Downstream: the objectstack tools that load the shipped
`sdui.manifest.json` (the CLI's `compile`, `lint` and `validate`, and
`metadata-protocol`'s runtime authoring gate) inherit the widening when
the next console manifest ships. Not measured here.
- Studio's designer and the AI prompt keys: no reader of the
registration's `required` found. `check:prompt-keys` reads the key
bullets in `.github/prompts/**`, not `required`, and no prompt teaches
`columns` as required.
## Generated artifacts
`sdui.manifest.json`, `sdui-intrinsics.d.ts` and `sdui-blocks.md` are
not tracked: no tracked file has those names, and the positive control
`apps/console/scripts/emit-sdui-manifest.ts` is tracked. They regenerate
from the registration in the console build, as for objectui#11605. This
diff has no regeneration step.
## Pins
- New
`apps/console/src/__tests__/related-list-columns-optional-11613.test.ts`,
7 rows, judged against the shipped manifest:
- The published `columns` is not required, and its description names
`dataSource` and `highlightFields`. `objectName` and `relationshipField`
stay required.
- The view-bound node, the neither node, and the neither node bound by
object alone each compile `ok` with no diagnostic.
- Three controls: authored columns beside a view; no
`relationshipField`; no `objectName`, bound or not.
- New
`packages/plugin-detail/src/__tests__/RecordRelatedListRenderer.columnsOptional-11613.test.tsx`,
5 rows, as described above.
-
`apps/console/src/__tests__/objectname-binding-required-11605.test.ts`:
the `LEDGER` is now empty and says why. Its stale-row check stays, so a
future row is still judged.
**Ablations** on the committed fix (`0624118`), through objectstack's
`scripts/ablation-replace.mjs`. The console project aliases
`@object-ui/plugin-detail` and `@object-ui/sdui-parser` to `src`, so a
mutation reaches the tests without a build.
1. `required: true` put back on `columns`
(`packages/plugin-detail/src/index.tsx`, blob `62fba905fb9f` became
`23df5500cb78`), with the two console files run. Exactly 5 rows went red
and 50 passed. Red: the enumeration row for `record:related_list` (its
message names `"columns"`), the published-input row, and the three
columns-less compile rows, each with a `missing-required-prop` naming
`columns`. Every control stayed green.
2. `RelatedList`'s derivation switched off (the `if
(!objectSchema?.fields) return [];` guard made unconditional in
`RelatedList.tsx`, blob `3c5bbfc1b87d` became `e5a0270e381b`), with the
render file run. Exactly the 2 neither-node rows went red and 3 passed.
Each restore is proven by the tool: blob equals HEAD and `git diff HEAD`
is empty. The render rows need no "before" run: the runtime is not
changed, and they read triage's premise.
## Gates
Final head `305c738`, which merges `main` at `6e9090c`. Every run below
is on that head, from the repo root.
- `pnpm exec vitest run packages/plugin-detail/`, run as two path-scoped
halves to stay under the foreground time cap. `src/__tests__/`: 149
files passed, 1 skipped; 1335 tests passed, 8 skipped. `src/renderers/`,
`src/synth/` and the 7 top-level test files: 86 files, 991 tests passed.
The 236 files are all of the package's tracked test files.
- `pnpm exec vitest run apps/console/`, as two halves. `src/__tests__/`:
51 files, 880 tests passed. The rest: 97 files, 888 tests passed. The
148 files are all of the console's tracked test files.
- `pnpm --filter @object-ui/plugin-detail type-check` (echoed `tsc
--noEmit && tsc -p tsconfig.test.json`): exit 0, after `turbo run build
--filter='@object-ui/console^...'` rebuilt the dependency closure on
this head. `--listFiles`, run once before the merge, shows the new
render test is in the test program.
- `pnpm --filter @object-ui/console type-check` (echoed `tsc --noEmit &&
tsc -b tsconfig.node.json --force`): exit 0. Its tsconfig includes
`src`, so the new console test is in the program.
- Lint, narrowed to the 4 touched code files with `eslint --format
json`: 4 files, 0 errors, 34 warnings. `index.tsx` carries 32, the same
as at base `2abec3a` read through `--stdin`. The new render test carries
2 `no-explicit-any`, the pattern its sibling `redactedDerivation-9053`
test uses. The narrowing is a measurement because: each file is linted
by the root `eslint.config.js` (`--print-config` exit 0 for each); the
count comes from the JSON output; and `eslint.config.js` enables no
type-aware linting (no `parserOptions.project`, no `projectService`),
and no rule under `eslint-rules/` reads the disk, so this diff cannot
move any untouched file's verdict.
- Root checks, each exit 0: `check-changeset-presence.mjs`,
`check-changeset-no-major.mjs`, `check:changeset-claims`,
`check:pending-changeset-literals`, `check:new-line-citations` (0 new
citations), `check:control-bytes`, `check:test-path-roots`,
`check:vi-mock-specifiers`, `check:vi-mock-inherit`,
`check:vi-mock-override-shape`, `check:element-data-source-declaration`,
`check:prompt-keys`, `check:component-surface-parity` (report-only),
`check:unreferenced-sources`.
- The changeset scripts' own suites (`scripts/__tests__/` no-major,
presence, claims, fixed, overwrite, polarity census): 6 files, 277 tests
passed.
CI runs the full farm.
## Changeset
`.changeset/11613-plugin-detail-related-list-columns-optional.md`:
`@object-ui/plugin-detail` `minor`, with the widening paragraph opening
`**Clause-②: yes (widening)**`.
## Acceptance notes
- **The member kind on `columns`.** Measured on this head: a spec-legal
column object (`{ field, label }`) compiles `ok: true` with a
`member-type-mismatch` warning, because the registration declares `of:
'string'` while the spec row admits string or `ListColumn` members. This
is already recorded in-tree as a gap, in
`registry-inputs-spec-parity.test.ts`'s `record:related_list.columns`
entry. This PR does not change it.
- **A real producer of the neither node.** The platform's own
default-record-page synthesizer (`buildDefaultPageSchema` in this
package, fed by app-shell's `deriveRelatedLists`) emits
`record:related_list` nodes with no `columns` whenever the foreign key
declares no `relatedListColumns`. Whether such a node ever reached the
save gate was not measured.
- **The dispatch brief's churn note.** It said PR objectui#11612 last
touched both files. Measured: that PR touched the enumeration pin only.
`packages/plugin-detail/src/index.tsx` was last changed by
objectui#11531 (`6158e4c`).
- **Docs.** The binding doc's paragraph on the `objectName` exception
stays true. No doc or README says `columns` is required (grep over
`content/docs` and the package README), so no doc edit is owed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_015W8GBu6sBiqus2L2xjMsAL)_
---------
Co-authored-by: Claude <noreply@anthropic.com>columns, so the page compile accepts a node that lists none (objectui#11613) (#11621)1 parent c096f03 commit 4c127cd
5 files changed
Lines changed: 339 additions & 13 deletions
File tree
- .changeset
- apps/console/src/__tests__
- packages/plugin-detail/src
- __tests__
Lines changed: 23 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
Lines changed: 8 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
160 | 160 | | |
161 | 161 | | |
162 | 162 | | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
163 | 170 | | |
164 | | - | |
165 | | - | |
166 | | - | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
| 171 | + | |
176 | 172 | | |
177 | 173 | | |
178 | 174 | | |
| |||
Lines changed: 149 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
Lines changed: 147 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
623 | 623 | | |
624 | 624 | | |
625 | 625 | | |
626 | | - | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
627 | 638 | | |
628 | 639 | | |
629 | 640 | | |
| |||
0 commit comments