Repository navigation
Commit 1489952
docs(spec): record:line_items columns hydrate from the child field, like the master-detail carriers (#24188)
Fixes #24140
Clause-②: no
The spec half of route B from the triage grade (comment 6229394877):
`record:line_items` `columns` now says that the block hydrates an
identity-only column from the child object's field, as the master-detail
carriers do. The heading of an identity-only column is then the child
field's label, and it translates with that label. This change adds no
key and changes no accept/reject result. The renderer half is
objectstack-ai/objectui#12854 (its `Blocked-by:` names this card).
## What changed
- **`packages/spec/src/ui/component.zod.ts`,
`RecordLineItemsProps.columns` describe.** Before, it said "this block
does NOT hydrate a column from the child object's field: declare
`label`, `type` and `options` yourself". It now states the carriers'
rule in the carriers' words: "identity-only entries ({ name }) hydrate
everything else from the child object's fields, `label`, `type` and
`options` included, so an identity-only column is headed by the child
field's label and translates with it". It also states the opt-out in
`InlineGridColumnSchema.type`'s words: "Declaring `type` opts a column
out of hydration — supply its `label`, `options` and other extras
yourself". The "Required, with at least one column" sentence is kept.
- **The same file, `RecordLineItemsProps` TSDoc.** The paragraph that
explained the old difference is rewritten. It now says that the column
means what it means on the carriers, because
`InlineGridColumnSchema.label`'s own describe governs every carrier. It
names the renderer half (`LineItemsPanel` reusing `hydrateColumns`, not
a second resolver). It also says that until the `.objectui-sha` pin
carries that half, an identity-only column still draws as a text cell
headed by its name. Last, it says that `defineStack`'s resolved-type
check (`collectHydratedInlineColumnErrors`) walks only the three
master-detail carriers. One phrase moved in the presence paragraph:
"draws `columns` as given" became "draws only the authored `columns`".
The column set is still never derived here.
- **`content/docs/references/ui/component.mdx`.** Regenerated by
`gen:docs`: one table row changed. `check:generated` named only this
artifact as stale.
- **`.changeset/24140-line-items-columns-hydrate.md`.**
`@objectstack/spec` `patch`, because the describe text ships in `dist`
and in the JSON Schema.
`packages/spec/src/data/field.zod.ts` is untouched.
`InlineGridColumnSchema.label` ("defaults to the child field's label via
hydration") and `type` ("Declaring it opts the column out of schema
hydration") were false for this one block. After this change they are
true for every carrier, so they do not need to name `record:line_items`.
## Measured before editing (origin/main cb8756b)
- **H1, the premise holds.** `component.zod.ts:2494` carried the "does
NOT hydrate" describe, and `field.zod.ts:971`/`:972` carried the
hydration describes. On the renderer side, objectui main `26323c4`
`packages/plugin-form/src/LineItemsPanel.tsx` hands
`applyColumnPermissions(schema.columns, …)` to the grid. A grep for
`hydrate` in that file returns zero hits. Control: the same grep finds
`hydrateColumns` in `deriveMasterDetail.ts`, `MasterDetailForm.tsx` and
their tests.
- **H2, the wording.** The carriers' describe (`inlineColumns`, and
`columns` on an `object-master-detail-form` detail entry) is
"identity-only entries ({ name }) hydrate everything else from the child
object's fields". objectui `hydrateColumns` (`deriveMasterDetail.ts`,
objectui `26323c4`) hydrates a column only when it declares no `type`,
and it keeps an authored `label`. It fills `label`, `type`, `required`,
`options`, the lookup target, the file props,
`readonlyWhen`/`requiredWhen` and a computed `expr`. The new describe
reuses the carriers' sentence and names the three keys the card names.
It adds no narrower or wider rule.
- **H3, the liveness ledger.** A case-insensitive grep for `line_items`
in `packages/spec/liveness/` hits only `page.json:57` and
`view.json:351`. In the `page.json` row `regions`, entry [15] cites
`columns L#gridField (applyColumnPermissions)`. That is a read point,
not a quote of the old describe. No row quotes "does NOT hydrate", so
the ledger is unchanged. Control: `related_list` hits twice each in
`field.json` and `page.json`. The `field.json` inline-column rows
(`inlineColumns`, lines 410-423) cite `hydrateColumns`, which stays
true.
- **H5, other statements of the old behaviour.** Hand-written
`content/docs/**` (outside `references/` and `releases/`) contains no
sentence about line-items hydration. Positive control: the same grep
finds `record:line_items` in `content/docs/ui/react-pages.mdx`, and
`layout-dsl.mdx:788` states the carriers' rule for
`object-master-detail-form`. `packages/lint` has no rule that prescribes
or enforces a `label` on these columns.
`validate-field-consumers.ts:392` says the block "derives nothing",
which is about the column set and stays true. The `skills/**` and
`examples/**` hits are listed under Acceptance notes and were not
edited.
## H4: accept/reject unchanged, measured on the built package
- `pnpm --filter @objectstack/spec build` ran at the base cb8756b and
again at a66b471. The script compares every JSON Schema with
`description` removed and lists the description paths that changed:
- `ui/RecordLineItemsProps.json`: structure identical once descriptions
are removed; one description path changed, `/properties/columns`.
- `objectstack.json`: structure identical once descriptions are removed;
one description path changed,
`/$defs/ui/RecordLineItemsProps/properties/columns`.
- Every other schema file is byte-identical. The only other file that
differs is `.build-input-hash-schema`.
- Control for the instrument: comparing `RecordHistoryProps.json`
against `RecordLineItemsProps.json` reports structure `False`, so the
comparison can fail.
- `packages/spec/authorable-surface/` is byte-identical before and after
the build.
- `inline-grid-column-carriers.test.ts` passes unchanged, including the
line-items section. Its test "CONTROL — defineStack does not judge an
identity-only line-items column" still asserts that `build()` accepts `{
name: 'amount', scale: 2 }` over a currency child field on
`record:line_items` and refuses the same column under
`object-master-detail-form`.
## Tests (all at a66b471)
- `pnpm --filter @objectstack/spec exec vitest run --project local
--maxWorkers=2 src/inline-grid-column-carriers.test.ts
src/ui/component-props-unknown-members.pin.test.ts
src/ui/page-print.test.ts`: `Test Files 3 passed (3)`, `Tests 138 passed
(138)`.
- `pnpm --filter @objectstack/spec test`: `Test Files 692 passed (692)`,
`Tests 20974 passed | 1 todo (20975)`, exit 0.
- `pnpm --filter @objectstack/spec typecheck`: exit 0. This covers `tsc
--noEmit`, `check:scripts-typecheck` and `check:test-typecheck` (OK, the
debt ledger held).
- No ablation. No tested behaviour changed: the diff is describe text,
TSDoc, a regenerated doc and a changeset.
## Gates (local subset, at a66b471)
- Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack`: 102 commands over 3 paths, measured against
the merge base cb8756b.
- 101 exit 0. Six of them first refused with exit 3 (PREREQUISITE NOT
MET) and were re-run after the prerequisite was met:
- The closure build `pnpm --workspace-concurrency=2 --filter
'@objectstack/lint...' --filter '@objectstack/client-react...' --filter
'@objectstack/objectql...' --filter '@objectstack/formula...' run build`
unblocked `check:doc-formula-expressions`, `check:doc-security-posture`,
`check:skill-examples`, `check:docs-transcript-drift` and
`check:lean-entry-closure`.
- A one-commit fetch of the self-test fixture `621a4876` unblocked
`check-plugin-teardown-shape --self-test`.
- 1 NOT MEASURED: `pnpm check:dual-build-cjs-loads` needs every
workspace package built. CI runs it in `Lint & Repo Gates`.
- `--ran` reconciliation: "102 derived famil(ies) accounted for — 101
run, 1 NOT-MEASURED".
- `pnpm --filter @objectstack/spec check:generated` reported
`content/docs/references/**` stale before regeneration, and only that
artifact.
## Acceptance notes
1. **`defineStack`'s resolved-type check does not reach
`record:line_items`.** `collectHydratedInlineColumnErrors`
(`packages/spec/src/stack.zod.ts`) judges "inline grid columns whose
TYPE comes from the child field" on three carriers. Once the renderer
half lands, an identity-only `record:line_items` column takes its type
from the child field too. A `{ name: 'amount', scale: 2 }` column over a
`currency` field will then publish green on this block and be reported
only at render time, while `object-master-detail-form` refuses the same
column at publish. Bringing the block into that check changes what
publishes, so it is out of this Clause-② `no` card. It is reported for a
separate card that depends on objectstack-ai/objectui#12854. The
carriers test's CONTROL title ("the panel draws it unhydrated")
describes the pinned renderer, and it flips with that card.
2. **The transition window.** Until objectstack-ai/objectui#12854 lands
and the `.objectui-sha` pin carries it, an identity-only
`record:line_items` column still draws as a text cell headed by its
field name. The TSDoc and the changeset both say this. The pin bump that
carries objectui#12854 should delete the TSDoc sentence that begins
"Until the `.objectui-sha` pin carries it".
3. **Showcase invoice page (held off).** The comment above the columns
in `examples/app-showcase/src/ui/pages/invoice-document.page.ts` (around
lines 59-66) still states the old behaviour, and so does the docblock of
`examples/app-showcase/test/invoice-document-line-items.test.ts` (lines
12-15). These belong to the showcase invoice card (#23985): its PR
decides whether to drop the literal labels.
4. **`skills/objectstack-ui/rules/pages.md:112-113` (Tier H, not
edited).** The print-page example writes identity-only
`record:line_items` columns (`{ name: 'product' }`, …). That matches the
new contract. Before objectui#12854 lands, those columns print raw field
names.
5. **`main` moved while this was open.** `main` gained #24170 (the
`record:json` retirement), which edits `component.zod.ts` at `:458` and
`:2571` and removes the `record:json` section of `component.mdx` (lines
1793-1805). Neither touches this diff's hunks, so `main` was not merged
in, per the dispatch's merge-on-conflict-only instruction. The PR's CI
and the merge queue validate the merge.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01TyRhWbVbbQpQJTDbW8VahJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7d6ec91 commit 1489952
3 files changed
Lines changed: 33 additions & 11 deletions
File tree
- .changeset
- content/docs/references/ui
- packages/spec/src/ui
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1800 | 1800 | | |
1801 | 1801 | | |
1802 | 1802 | | |
1803 | | - | |
| 1803 | + | |
1804 | 1804 | | |
1805 | 1805 | | |
1806 | 1806 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2430 | 2430 | | |
2431 | 2431 | | |
2432 | 2432 | | |
2433 | | - | |
2434 | | - | |
2435 | | - | |
2436 | | - | |
2437 | | - | |
2438 | | - | |
2439 | | - | |
2440 | | - | |
| 2433 | + | |
| 2434 | + | |
| 2435 | + | |
| 2436 | + | |
| 2437 | + | |
| 2438 | + | |
| 2439 | + | |
| 2440 | + | |
| 2441 | + | |
| 2442 | + | |
| 2443 | + | |
| 2444 | + | |
| 2445 | + | |
| 2446 | + | |
| 2447 | + | |
| 2448 | + | |
| 2449 | + | |
| 2450 | + | |
| 2451 | + | |
2441 | 2452 | | |
2442 | 2453 | | |
2443 | 2454 | | |
2444 | 2455 | | |
2445 | 2456 | | |
2446 | 2457 | | |
2447 | 2458 | | |
2448 | | - | |
| 2459 | + | |
2449 | 2460 | | |
2450 | 2461 | | |
2451 | 2462 | | |
| |||
2492 | 2503 | | |
2493 | 2504 | | |
2494 | 2505 | | |
2495 | | - | |
| 2506 | + | |
2496 | 2507 | | |
2497 | 2508 | | |
2498 | 2509 | | |
| |||
0 commit comments