feat(types,core,fields,app-shell,plugins)!: reference is the only relational-target spelling objectui writes or reads; reference_to retires (objectui#11070, round 4) - #11264
Conversation
…lling objectui writes or reads Round 4 of objectui#11070 (the reference_to round), under the objectui#6837 ruling. The ingestion pass folds a foreign reference_to / referenceTo onto reference and no longer stamps reference_to; the in-repo emitters write reference; LookupField, UserField and the lookup / user read cells read reference only; LookupFieldMetadata, MasterDetailFieldMetadata and DetailViewField (with its zod mirror) declare reference. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…ted notes on the pending entries this round made false The three relational copy-set controls asserted more than two keys; with reference_to retired the set is reference and displayField, so each floor now also names reference. The console shared-widget pin feeds its lookup the spec spelling. One changeset declares the round (minor, break stated), and fifteen pending changesets get an appended dated note. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…d displayField PR #11243 has landed, so the three column-building comments in ObjectGrid are in scope; they named reference_to and display_field, neither of which the copy set carries any more. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
…age and two console pins name reference PR #11233 has landed, so the remaining tail is in scope: the form-field zod comment, FormPage's metadata comment, plugin-form.mdx's field-slot row and the shared-field-resolver pin now spell the target reference. deriveRelatedLists' docblock drops the reference_to it has not read since objectui#6837 half 2. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
Keeps each touched test file at its base count of no-explicit-any warnings. Claude-Session: https://claude.ai/code/session_01TdiauJaVCHuj45EzZGUxHh Co-authored-by: Claude <noreply@anthropic.com>
|
changeset-claim-re-read
|
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Refs #11070
Clause-②: yes (narrowing).
LookupFieldMetadata,MasterDetailFieldMetadata, andDetailViewFieldretirereference_toand declarereference, and the ingestion pass no longer stampsreference_toonto served defs, under the startup no-gradualism rule. It is priced in the changeset.Round 4 of objectui#11070, the
reference_toround: the seat's answer A to Q1 (5915992755), under the maintainer ruling on objectui#6837 (5475017957, 2026-08-31, verbatim: 「objectui不是前端的项目吗?后端的元数据只要对,前端按协议执行就行了呀」, with the earlier question 「按 spec 拒绝面直接删不是更合理吗」). Claim5916640555.referenceis now the only spelling ObjectUI writes or reads for a relational field's target object. The one fold that remains is the ruling's choke point:normalizeFieldReferenceKeysfolds a foreignreference_to/referenceToontoreferencewhenreferenceis absent, keeps its dev warning, and never drops a key.What changed
@object-ui/types).LookupFieldMetadataandMasterDetailFieldMetadatadeclarereferencetyped by reference to@objectstack/spec'sFieldSchema.reference.DetailViewFieldand its zod mirrorDetailViewFieldSchemamove fromreference_totoreferencein the same commit, so the two faces keep equal key sets. Theform.tscomments and the form-field mirror's comment now say that the lookup and user widgets readreferenceonly.strict-face-read-keys-11070.test.tsmovesreference_tofrom the pending list to the retired list, and gains a type-level pin: both field metadata types carry the spec member, and none of the three contracts has areference_tokey.@object-ui/core,reference-keys.ts). The pass folds ontoreferenceand no longer stampsreference_to. The header prose that described a stamp of "BOTH snake_case keys" now describes the fold, and it records why the stamp protected nothing once both ends moved. The leave-arm rule stands.referenceonly:LookupField,UserField,LookupCellRendererandUserCellRenderer(only those two reads infields/src/index.tsx),InlineFieldInput's reference fallback,schemaDefaults'current_userseed,sectionFields' view override, andMetadataProvider's inline-subform parent.reference:paramToField,RecordDetailView,FlowReferenceField(its one target line),RecordDetailPanel,RecordMetaFooter,RelatedList,fieldEnrichment,buildDefaultPageSchema,sectionFields,bulkParamToFieldandObjectGallery.plugin-grid'sRELATIONAL_META_READ_SETloses itsreference_torow and theadapter-stampedverdict that row alone held.plugin-dashboard'sCELL_RELATIONAL_META_KEYSandFieldMetadropreference_to.resolveActionParams' unreadRuntimeField.reference_tomember goes.FieldDefaultsSchemaLikepins three members.lookup.mdx(typed fences, plaintext fences, prose, plus one paragraph on the retirement),record-edit-modes.md,plugin-form.mdx's field-slot row andplugin-form's README. The tests that fedreference_toto a widget, a cell or a served-def stub now feedreference. The pins whose job is the fold, or a refusal, keepreference_toas their input and assert the fold toreferencewith no stamp back, or the refusal..changeset/11070-reference-to-round4.md, minor with the break stated (AGENTS.md §9: nevermajor). Fifteen pending changesets that this round made false get an appended dated note, in the append-only shape:6837-reference-to-arm-deletion,6837-gantt-tree-referenceto-arms,6837-recorddrawer-invented-target-arms,6694-dashboard-lookup-reference-meta,6597-retire-fieldmeta-referenceto,7166-retire-inert-fieldmeta-copies,paramtofield-reference-rule-derives-from-core-5312,6711-retire-reference-to-field,6874-retire-titleformat,7155-converge-lookup-dialect-camelcase,6528-resolve-reference-to-census,7324-plugin-form-nameable-parameter-types,11070-field-metadata-spec-spellings,10535-person-name-read-gateand6875-grid-relational-meta-derive.Pins that flipped, and why
These pins asserted the stamp. Each now asserts that no stamp happens, and that the fold still does:
reference-keys.test.ts: areferencedef gains noreference_to;referenceTofolds toreferenceonly; idempotence; the map and array containers.reference-keys.legacyWarning-6837.test.ts, case 5: "the STAMP is unchanged" becomes "the FOLD still runs". ThereferenceTocase asserts noreference_to; thereference_tocase keeps the input key, because the pass never drops one.MetadataProvider.itemReferenceKeys-7650.test.tsx: the first pin asserted the stamp and now asserts its absence. The rest feed a legacy spelling, because areference-only def comes back unchanged and cannot show that the pass ran.getObjectSchema.test.ts(data-objectstack).reference_tooff an emitted bag:referenceArms-6837.divergent.test.ts(plugin-detail),RecordDetailDrawer.referenceArms-6837.test.tsx,HeaderHighlight.editable.test.tsx,relationalMetaCopySet-6711/-6874,lookupRelationalMeta-6694,sectionFields*,paramToField.test.ts,resolveActionParams.test.ts,bulkParamToField.test.ts.LookupFieldeach read no target from areference_to-only def.Pins that assert something else were not "fixed green". Three copy-set floors, which required more than two keys in
RELATIONAL_META_KEYS, now require more than one, because the set is nowreferenceanddisplayField, and each floor now also namesreference.Beyond the claim's file surface, stated
ObjectDataTable.tsxgainsObjectDataTableRetiredReferenceToSnakeTombstone, and both ObjectDataTable test files gain a directive and a counter-control for it. RetiringFieldMeta.reference_toremoved the key from the derived refusal bands' pool, andrecordFields.tsx's ownFieldMetadocblock requires that a retired member be re-refused by hand at that seam. This is the third tombstone, besidedecimalsandreferenceTo.auditHistoryDisplay.ts,deriveRelatedLists.ts,useDatasetFields.ts,object-fields-io.ts,components/custom/field.tsx, coreActionRunner.ts/chart-series.ts/expand-fields.ts,data-objectstack/src/index.ts,RecordPickerDialog.tsx,lookupColumnDisplay.tsx,HeaderHighlight.tsxandObjectGantt.tsx, plus the stamp prose in the gantt / tree / drawer 6837 pins.ObjectGrid.tsxrelational-metadata comments now namereferenceanddisplayField(seat message, 18:53Z).ListView.tsx's two lines were left as they are, because both are true after this round: one saysFieldSchemarefusesreference_to, the other that a list column declares neither spelling. PR fix(types,components,plugin-form,console,core): a faulted or blank visibleWhen refuses the submit, naming the field and the rule; a blank field rule is refused at authoring; blank gates are diagnosed (objectui#8069) #11233 landed, so theform.zod.tscomment, theFormPage.tsxcomment, theplugin-form.mdxrow and theFormPage.sharedFieldResolver-10179pin were folded as well (seat message, 19:54Z; the comment only inform.zod.ts, with no new declaration).FormPage.sharedWidgets-10179's lookup fixture moved first, because that test went red on the change.Census, before and after
Base: merge base
615346dfor the round's own diff. Code lines are non-comment lines inpackages/*/src,apps/console/srcandexamples/*/src, excluding tests. The typed half comes from a TypeScript LanguageServicefindReferencesover 5568 source files, with workspace packages resolved to source.reference_toonto a def or widgetfieldreference_toreference_to(grid ledger row, dashboard cell keys)reference_to(widgets, cells, inline editor, seeding, section override, subform parent)reference_tomembers (field-types ×2, views, views.zod, RuntimeField, FieldMeta, schemaDefaults ×2)reference_to?: neverrefusal (tombstone)reference_tomember: production writes / test writesThe eleven emitters are the PM census's eleven. The type-checker census found two of them typed (
FlowReferenceField,RelatedList); the other nine write throughanyorRecordbags. It found no typed reader: every reader was an untyped read.Runtime probe — the user-visible proof
A scratch vitest file, never committed, ran against the source at merge base
615346dand at head (1972d01, re-run at338b19dwith identical readings).ObjectFormin create mode opens its lookup picker;ObjectGridrenders a lookup column with a primitive id; the referenced record is{ id: 'a1', name: 'Acme Corp' }.referenceonly, throughObjectStackAdapterprobe_account; cell showsAcme Corp; served keyslabel, reference, reference_to, typeprobe_account; cell showsAcme Corp; served keyslabel, reference, typeDataSourcereferenceTothroughparamToFieldintoLookupFieldreference_to; picker queriesprobe_accountreference; picker queriesprobe_accountreference_to-only def served throughObjectStackAdapterreferenceadded); dev warning fires; picker and cell workreference_to-only def from a BYODataSourceprobe_account; cell showsAcme Corpfindcall at all; the cell shows the raw ida1(c2) is the break, and the changeset's BREAKING paragraph names that host.
Hypotheses
origin/main165c1d49e. The example apps writereference_tozero times, against a control of 30Field.lookup/Field.masterDetailcalls in 19 files; both helpers writereference.FieldSchemarefusesreference_toby name (installed 17.5.0:unrecognized_keys, "Did you meanreference_to→reference?"), and so does the spec's form-field schema. Thefield-reference-to-aliasconversion (packages/spec/src/conversions/registry.ts) rewrites stored rows on rehydration and inos migrate meta. The only other hits are refusals (the SQL and Mongo doors, verify, lint), a reader of three spellings inplugin-security, and a comment inplugin-approvalsthat describes this repo's widget key (noted below).RELATIONAL_META_KEYSis derived toreference, displayField, and the grid's derivation gate re-extracts the cell's read set withreferencein it.reference_topair was not in M3's class (ii) at this base. Round 1 (PR feat(types): declare the read keys the strict authoring face refused (objectui#11070) #11115) moved bothfields-lookupfixtures toreference, and round 3 reported class (ii) without it. Measured withscripts/measure-strict-authoring-face.mjs --jsonat merge baseaf9e957and at338b19d: every refusal figure is identical (2224 nodes, 105 strict-refused, 66 strict-only, 39 red today, 599 documents, 98 refused whole-tree), andreference_tooccurs in zero refusals at both. The only differences are the renderer-source word-mention counts, which the comment edits moved, and the error text of one authored module that fails to load under either build state. So this round moves M3 by zero in every class. The absolute class (ii) figure at this base is NOT MEASURED: round 3's shipped-face port of PR feat(cli):objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069'sfindUndeclaredKeyswas a scratch script and was never committed.Checks
Heavy runs went through
os-verify-lock(slotissue-11070). Exit codes were captured before any pipe.check-doc-snippet-types --build-filter, turbo--concurrency=2):35 successful, 35 total, before and after the first merge.Tasks: 56 successful, 56 total, before and after the first merge. After the second merge,@object-ui/typeswas rebuilt and type-checked again, exit 0.4 failed | 3527 passed | 5 skipped (3536). The four were pins that asserted the old shape: three copy-set floors of more than two keys, and the console shared-widget lookup fixture. They were fixed inc684de4and re-run:Test Files 4 passed (4),Tests 30 passed (30).338b19d), narrowed to the files both sides touched plus this round's relational surface (types, fields tests and widgets, the Flow inspectors, console components, plugin-grid, plugin-detail and plugin-dashboard tests, plugin-form, core reference-keys, the adapter, and app-shell providers and utils):Test Files 1137 passed | 3 skipped (1140),Tests 16884 passed | 31 skipped (16915). After the second merge (16b43a7, no file overlap):packages/types/295 passed (295),7375 passed (7375), includingzod-mirror-parity.test.ts, whose totals did not move.338b19d:check:doc-snippets696 of 696 block(s) judged, 0 failed;check:doc-examples,check:doc-types,check:spec-symbols,check:doc-example-readersandcheck:doc-example-idsall exit 0.16b43a7, all exit 0:check:doc-fences,docs:check-links,check:control-bytes,check:pending-changeset-literals,check-changeset-presence(174 source file(s) of 20 released package(s) changed, and this change declares 1 changeset(s)),changeset:check(no major),check:new-line-citations(0 new citation(s)),check:test-path-roots,check:changeset-claims(report-only; every named changeset was read), andcheck-governed-queue-guard --testover the 194 paths (NOT GOVERNED).eslint.config.js's**/*.{ts,tsx}files entry; there are noparserOptions.projectorprojectService, so type-aware linting is off and this diff cannot move an untouched file's verdict. The 174 changed.ts/.tsxfiles were linted at16b43a7and at merge base54a7830: 0 errors at both, 1909 warnings at both, and no file is worse than base.ablation-replace.mjs. In every case the anchor hit once, the blob moved, the blob was restored equal to HEAD, andgit diff HEADwas empty afterwards.lookup.mdx's fence writesreference_to.check:doc-snippetsexited 1 with696 of 696 block(s) judged, 1 failed, TS2561 "'reference_to' does not exist in type 'LookupFieldMetadata'. Did you mean to write 'reference'?", which proves the gate read the rebuilt.d.ts.reference_toagain. 6 red / 83 green, against 5 predicted: the three core stamp pins, the adapter pin and the provider pin, plus the empty-target pin, because an emptyreferencealso gained a stamp.LookupCellRendererreadsreference || reference_toagain. 2 red / 14 green, as predicted: the new cell refusal pin, and the grid derivation gate's unclassified-spelling check.338b19d: the seven contracts carry noreference_tomember. The control run of the same instrument onreferencefinds 7 declarations, the same two typed production writes that moved, 1 production read, 3 test reads and 10 test writes.54a7830. That is under the 5000-line human-merge threshold: 62 non-test files (16 of them changesets) and 132 test files.NOT MEASURED:
packages/types/. Its three incoming commits share no file with this branch, and none containsreference_to.ObjectForm/ObjectGridwith a stub or adapter-wrappedDataSource.Acceptance notes
docs/adr/0059-action-params-shared-field-widgets.md's decision section still recordsreferenceTo→reference_toasparamToField's mapping. It was left as written: it is the accepted decision's record (2026-07-19), and the ruling kept the historical record. Editingdocs/adr/**would also make this PR governed. The seat may want a dated amendment line in a docs-only PR.ROADMAP.md's two hits are completed items and changelog history, not current behaviour, so they were not changed..changeset/audit-field-def-reference-narrow.mdsays the choke point "stamps both snake_case spellings". It has empty front matter, so nothing publishes it, and no note was appended.plugin-approvals'sys-approval-request.object.tshas a comment saying the console resolves a lookup config asreference_to: sys_user. That spelling is nowreference. It is a comment in the sister repo, not a producer; noted, not filed.Generated by Claude Code