Repository navigation
docs(spec): record:line_items columns hydrate from the child field, like the master-detail carriers - #24188
Conversation
…carriers RecordLineItemsProps.columns said the block does not hydrate a column from the child object's field. The shared InlineGridColumnSchema it takes by reference says a column's label defaults to the child field's label via hydration, and the master-detail carriers honour that. The describe now states the carriers' rule in their words: identity-only entries hydrate label, type and options from the child field, so the heading translates with the child field's label; declaring type opts out. The TSDoc names the renderer half (objectui LineItemsPanel reusing hydrateColumns) and the defineStack resolved-type check that still walks only the three master-detail carriers. Describe text only: no key, no accept/reject change. Claude-Session: https://claude.ai/code/session_01TyRhWbVbbQpQJTDbW8VahJ Co-authored-by: Claude <noreply@anthropic.com>
…umns describe Claude-Session: https://claude.ai/code/session_01TyRhWbVbbQpQJTDbW8VahJ Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift Check1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 143 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 64556c2676dbc9ccdaa3775b97db6fd869aee0ed && git checkout 64556c2676dbc9ccdaa3775b97db6fd869aee0ed
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 727091c821d7dcaedb4eea547b77933838b471ed a66b47182e19561578a63d0c3c4c7955dabca68d && git checkout -B drift-repro 727091c821d7dcaedb4eea547b77933838b471ed && git merge --no-ff a66b47182e19561578a63d0c3c4c7955dabca68d
node scripts/docs-audit/affected-docs.mjs --json 727091c821d7dcaedb4eea547b77933838b471ed |
Contract reviewServed-tier: Inputs: card #24140 (body, comments 6229394877 / 6234986989 / 6236296173), PR #24188 (body, file list, net diff against ① Derived judgments
② Semver level
③ Boundary flags
Check-runs on Implemented-by: VERDICT: PASS Generated by Claude Code |
席位核对 · ACCEPT · PR #24188 @
|
Fixes #24140
Clause-②: no
The spec half of route B from the triage grade (comment 6229394877):
record:line_itemscolumnsnow 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 (itsBlocked-by:names this card).What changed
packages/spec/src/ui/component.zod.ts,RecordLineItemsProps.columnsdescribe. Before, it said "this block does NOT hydrate a column from the child object's field: declarelabel,typeandoptionsyourself". It now states the carriers' rule in the carriers' words: "identity-only entries ({ name }) hydrate everything else from the child object's fields,label,typeandoptionsincluded, so an identity-only column is headed by the child field's label and translates with it". It also states the opt-out inInlineGridColumnSchema.type's words: "Declaringtypeopts a column out of hydration — supply itslabel,optionsand other extras yourself". The "Required, with at least one column" sentence is kept.RecordLineItemsPropsTSDoc. The paragraph that explained the old difference is rewritten. It now says that the column means what it means on the carriers, becauseInlineGridColumnSchema.label's own describe governs every carrier. It names the renderer half (LineItemsPanelreusinghydrateColumns, not a second resolver). It also says that until the.objectui-shapin carries that half, an identity-only column still draws as a text cell headed by its name. Last, it says thatdefineStack's resolved-type check (collectHydratedInlineColumnErrors) walks only the three master-detail carriers. One phrase moved in the presence paragraph: "drawscolumnsas given" became "draws only the authoredcolumns". The column set is still never derived here.content/docs/references/ui/component.mdx. Regenerated bygen:docs: one table row changed.check:generatednamed only this artifact as stale..changeset/24140-line-items-columns-hydrate.md.@objectstack/specpatch, because the describe text ships indistand in the JSON Schema.packages/spec/src/data/field.zod.tsis untouched.InlineGridColumnSchema.label("defaults to the child field's label via hydration") andtype("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 namerecord:line_items.Measured before editing (origin/main cb8756b)
component.zod.ts:2494carried the "does NOT hydrate" describe, andfield.zod.ts:971/:972carried the hydration describes. On the renderer side, objectui main26323c4packages/plugin-form/src/LineItemsPanel.tsxhandsapplyColumnPermissions(schema.columns, …)to the grid. A grep forhydratein that file returns zero hits. Control: the same grep findshydrateColumnsinderiveMasterDetail.ts,MasterDetailForm.tsxand their tests.inlineColumns, andcolumnson anobject-master-detail-formdetail entry) is "identity-only entries ({ name }) hydrate everything else from the child object's fields". objectuihydrateColumns(deriveMasterDetail.ts, objectui26323c4) hydrates a column only when it declares notype, and it keeps an authoredlabel. It fillslabel,type,required,options, the lookup target, the file props,readonlyWhen/requiredWhenand a computedexpr. The new describe reuses the carriers' sentence and names the three keys the card names. It adds no narrower or wider rule.line_itemsinpackages/spec/liveness/hits onlypage.json:57andview.json:351. In thepage.jsonrowregions, entry [15] citescolumns 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_listhits twice each infield.jsonandpage.json. Thefield.jsoninline-column rows (inlineColumns, lines 410-423) citehydrateColumns, which stays true.content/docs/**(outsidereferences/andreleases/) contains no sentence about line-items hydration. Positive control: the same grep findsrecord:line_itemsincontent/docs/ui/react-pages.mdx, andlayout-dsl.mdx:788states the carriers' rule forobject-master-detail-form.packages/linthas no rule that prescribes or enforces alabelon these columns.validate-field-consumers.ts:392says the block "derives nothing", which is about the column set and stays true. Theskills/**andexamples/**hits are listed under Acceptance notes and were not edited.H4: accept/reject unchanged, measured on the built package
pnpm --filter @objectstack/spec buildran at the base cb8756b and again at a66b471. The script compares every JSON Schema withdescriptionremoved 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..build-input-hash-schema.RecordHistoryProps.jsonagainstRecordLineItemsProps.jsonreports structureFalse, so the comparison can fail.packages/spec/authorable-surface/is byte-identical before and after the build.inline-grid-column-carriers.test.tspasses unchanged, including the line-items section. Its test "CONTROL — defineStack does not judge an identity-only line-items column" still asserts thatbuild()accepts{ name: 'amount', scale: 2 }over a currency child field onrecord:line_itemsand refuses the same column underobject-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 coverstsc --noEmit,check:scripts-typecheckandcheck:test-typecheck(OK, the debt ledger held).Gates (local subset, at a66b471)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 102 commands over 3 paths, measured against the merge base cb8756b.pnpm --workspace-concurrency=2 --filter '@objectstack/lint...' --filter '@objectstack/client-react...' --filter '@objectstack/objectql...' --filter '@objectstack/formula...' run buildunblockedcheck:doc-formula-expressions,check:doc-security-posture,check:skill-examples,check:docs-transcript-driftandcheck:lean-entry-closure.621a4876unblockedcheck-plugin-teardown-shape --self-test.pnpm check:dual-build-cjs-loadsneeds every workspace package built. CI runs it inLint & Repo Gates.--ranreconciliation: "102 derived famil(ies) accounted for — 101 run, 1 NOT-MEASURED".pnpm --filter @objectstack/spec check:generatedreportedcontent/docs/references/**stale before regeneration, and only that artifact.Acceptance notes
defineStack's resolved-type check does not reachrecord: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-onlyrecord:line_itemscolumn takes its type from the child field too. A{ name: 'amount', scale: 2 }column over acurrencyfield will then publish green on this block and be reported only at render time, whileobject-master-detail-formrefuses the same column at publish. Bringing the block into that check changes what publishes, so it is out of this Clause-②nocard. It is reported for a separate card that depends on plugin-form: record:line_items hydrates an identity-only column from the child field (label, type, options) as the master-detail carriers do, so printed line-item headings translate (the objectui half of objectstack-ai/objectstack#24140) objectui#12854. The carriers test's CONTROL title ("the panel draws it unhydrated") describes the pinned renderer, and it flips with that card..objectui-shapin carries it, an identity-onlyrecord:line_itemscolumn 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-shapin carries it".examples/app-showcase/src/ui/pages/invoice-document.page.ts(around lines 59-66) still states the old behaviour, and so does the docblock ofexamples/app-showcase/test/invoice-document-line-items.test.ts(lines 12-15). These belong to the showcase invoice card (showcase: the invoice print page's line-items table prints the raw field namesdescription/quantity/unit_price/amountas its headings — itsrecord:line_itemscolumns declare nolabel, and that block draws a column exactly as declared #23985): its PR decides whether to drop the literal labels.skills/objectstack-ui/rules/pages.md:112-113(Tier H, not edited). The print-page example writes identity-onlyrecord:line_itemscolumns ({ name: 'product' }, …). That matches the new contract. Before objectui#12854 lands, those columns print raw field names.mainmoved while this was open.maingained feat(spec)!: record:json is retired — refused by name at the schema door, the approval request page's raw JSON panel it was declared for was dropped (#24162) #24170 (therecord:jsonretirement), which editscomponent.zod.tsat:458and:2571and removes therecord:jsonsection ofcomponent.mdx(lines 1793-1805). Neither touches this diff's hunks, somainwas 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