Repository navigation
fix(types,plugin-form,plugin-detail): field metadata members FieldSchema refuses retire as never, and their readers follow the spec keys (objectui#12242) - #12257
Conversation
…tire as never; form builders read visibleWhen and autonumber (objectui#12242) - BaseFieldMetadata: visible_on and filterable retire as never tombstones; visibleWhen is declared by reference to FieldSchema.visibleWhen. - CurrencyFieldMetadata: currency retires as never; currencyConfig is declared by reference. - Date/DateTime min_date and max_date, Location default_zoom, AutoNumber starting_number, Object schema and Vector normalize retire as never with no replacement key: no twin in the spec, and nothing reads them. - AutoNumberFieldMetadata.type is autonumber; ObjectFieldMetadata.type is json. - ObjectForm and sectionFields stop reading visible_on; ObjectForm's computed-type gate reads autonumber, the spelling a spec object carries. Claude-Session: https://claude.ai/code/session_0149MdowTfyuWZuSSESLUYnE Co-authored-by: Claude <noreply@anthropic.com>
…rop the inert autonumber gate change (objectui#12242) The computed-type gate's `auto_number` arm is left as it was: an ablation showed the flag changes nothing a person sees (the auto-number widget is display-only and the payload strips both spellings), so changing it bought no behaviour and no pin could fail on it. Claude-Session: https://claude.ai/code/session_0149MdowTfyuWZuSSESLUYnE Co-authored-by: Claude <noreply@anthropic.com>
… (objectui#12242) Claude-Session: https://claude.ai/code/session_0149MdowTfyuWZuSSESLUYnE Co-authored-by: Claude <noreply@anthropic.com>
…red members and type values (objectui#12242) - date/datetime: no range key; location: no zoom key; vector: no normalize key; currency: currencyConfig. - auto-number: type autonumber, no starting value key. - object: type json; a JSON value's shape is an object-level json_schema validation rule, not a field-level schema key. - check-doc-component-types: the two pages' exemption entries follow the new type values (autonumber, json, json_schema); string and boolean were stale. - changesets for @object-ui/types (minor, breaking) and @object-ui/plugin-form (patch). Claude-Session: https://claude.ai/code/session_0149MdowTfyuWZuSSESLUYnE Co-authored-by: Claude <noreply@anthropic.com>
…eld's currencyConfig (objectui#12242) RecordDetailPanel's field build and RelatedList's cell bag copied the field-level `currency` (which FieldSchema refuses) and dropped `currencyConfig` (the spec's fixed-currency declaration), so a fixed-EUR amount read in the tenant's currency there. The record page's sections already carried it. The summary-chip fixture re-spells its EUR field as currencyConfig. Claude-Session: https://claude.ai/code/session_0149MdowTfyuWZuSSESLUYnE Co-authored-by: Claude <noreply@anthropic.com>
✅ 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
|
Contract reviewServed-tier: Inputs: card objectui#12242 (body, triage Check-runs on the head: every run completed; every non-skipped run is ① Derived judgmentsPublic surface of
Other packages: ② Semver levelClause-②: yes The PR body and the
③ Boundary flagsDev flags (the report's
Open questions (the report's
Flags this review raises:
Implemented-by: VERDICT: PASS Generated by Claude Code |
Part of #12242
Clause-②: yes
The family close-out for "an exported
*FieldMetadatatype declares a member@objectstack/spec'sFieldSchemarefuses". I measured every member of every exported field metadata interface against the installed spec, then gave each refused member one verdict. Each member that can retire now retires onfield-types.ts's own?: neverconvention, the oneGridFieldMetadatauses formin_rows. Two type values become the spec'sFieldTypespellings. Readers move to the spec keys, and the docs pages teach the spec's spellings. Members that a live widget reads, that have no field-level spec twin, and whose removal would drop a working capability are kept and reported for a decision, as the dispatch's stop condition requires.What changed
@object-ui/types(field-types.ts):BaseFieldMetadata.visible_onbecomes anevertombstone.visibleWhenis declared by reference toFieldSchema.visibleWhen.CurrencyFieldMetadata.currencybecomes anevertombstone.currencyConfigis declared by reference.neverwith no replacement key, because the spec has no twin and nothing reads them:filterable,min_date/max_date(on both date types),default_zoom,starting_number,schemaandnormalize.AutoNumberFieldMetadata.typechanges'auto_number'→'autonumber'.ObjectFieldMetadata.typechanges'object'→'json'.VisibilityConditionis marked@deprecated, since no member declares it any more.@object-ui/plugin-form:ObjectForm's object-field builder and the sectioned forms' name-string entries stop readingvisible_on. Both already carriedvisibleWhen.@object-ui/plugin-detail(p2 position, outside the claim's listed file surface, named here per the dispatch):RecordDetailPanel's field build andRelatedList's cell bag forwarded the retiringcurrencyand droppedcurrencyConfig. On those two surfaces, a spec field declaringcurrencyConfig: { currencyMode: 'fixed', defaultCurrency: 'EUR' }read as a bare number. Measured red before the change:RelatedListcells["Tower","1,234.50","6,789.50"], with no€. Both sites now forwardcurrencyConfig. They are readers of the retiring member, which is why they move in this change (E3 (b) / E6).date,datetime,location,vector,currency,auto-numberandobjectundercontent/docs/fields/teach the spec's spellings.object.mdxnow teaches the object-leveljson_schemavalidation rule in place of the field-levelschema. It also no longer claims that the authoredschema"is carried on the field metadata untouched" to the server: the spec refuses that key at publish.scripts/check-doc-component-types.mjs(fixture triage, outside the listed file surface): the two pages' entries in that gate's per-file type ledger follow the new values (autonumber,json,json_schema). The oldauto_number,stringandbooleanentries had gone stale.summaryChip.displayLocale-9453.test.tsx, the EUR field cast toFieldMetadatais re-spelled ascurrencyConfig, which is what failedplugin-detailtype-check. InsectionFields.blankGate-11262.test.ts, thevisible_onchain row pinned the branch this change deletes. It is replaced by a load-bearing block: a predicate undervisible_onis not carried and is not reported, and the same predicate undervisibleOnstill is (control).E2: what reads
GRID_FIELD_RETIRED_KEYSTwo runtime refusals read it, and no alias does:
GridFielddraws a named refusal instead of the grid, and theFormFieldSchemazod mirror carries analiasKeyRefusalarm per entry. No reader accepts a snake key through it.?: nevermember shape and its docblock mapping: each tombstone's@deprecatedline names the key to write. It adds no new exported map constant. The grid map exists for those two runtime consumers, and this family has none. Only two of its retired members (visible_on,currency) even have a twin to map to. A constant with zero readers would be a new unpulled public export. The seat decides whether that matches the triage ruling's "mapped to its camelCase key". It is listed under open questions in the report.Census (installed
@objectstack/spec17.7.0, objectuimain923504f)Method:
FieldSchema.safeParseon a minimal field of the interface's own type, carrying the member. A type that is not a specFieldTypewas probed on the nearest spec type:autonumber,json,location,master_detail. Readers come from a non-testgit grepof each spelling inpackages/*/src. This table is a reading taken once. The retired rows are re-derived on every run byfield-metadata-family-retired-12242.test.ts, and nothing re-derives the kept rows.FieldSchemavisible_onunrecognized_keys, hint →visibleWhenvisibleWhen(CEL)ObjectForm,sectionFields. Both already readvisibleWhentoovisibleWhen, declared by reference; both snake reads removedfilterableunrecognized_keysfilterablehits areRelatedList/ActivityTimelinecomponent props)mobile_fullscreenunrecognized_keysTextAreaField,RichTextField, the form renderer; produced byObjectFormvalidateunrecognized_keysbuildValidationRulespattern,pattern_messageunrecognized_keysvalidations[]{ type: 'format', field, regex, message }buildValidationRules(field level only)currencyunrecognized_keyscurrencyConfig(fixed+defaultCurrency)resolveFieldCurrencyreads both;RecordDetailPanel/RelatedListforwarded onlycurrency(p2)currencyConfig, declared by reference; the two forwarders now carry itmin_date,max_dateunrecognized_keysmin/maxare numbers)dueLikeunrecognized_keysDetailViewFieldSchema.dueLikedefault_zoomunrecognized_keysidFieldunrecognized_keysLookupField,GridFieldlookup cellsreference_fieldunrecognized_keys, hint →referenceViaauto_numberinvalid_valueattypeautonumberfield:auto_number;mapFieldTypeToFormTypemaps both spellingsautonumberstarting_numberunrecognized_keyspicker,subtitleunrecognized_keysLookupField,UserFieldavatar_fieldunrecognized_keysobjectinvalid_valueattypejsonjsonandobjectboth resolve tofield:objectjsonschemaunrecognized_keysvalidations[]{ type: 'json_schema', field, schema }ObjectFieldchecks syntax only)normalizeunrecognized_keysVectorFieldreadsdimensionsonly)geolocationinvalid_valueattypelocationis a different widget)GeolocationFieldgridand its membersinvalid_valueattype; members refused onmaster_detailGridFieldAccepted by the spec, no action:
name,label,type,inlineHelpText,description,required,readonly,system,placeholder,defaultValue,sortable,dependsOn,unique.minLength/maxLength.rowson textarea / markdown / html / richtext.min,max,precision,scale,step,useGrouping.precision,min,max.precision,scale,min,max.formaton date / datetime / time / phone / autonumber.options,multiple,searchable.multiple,accept,maxSize.reference,multiple,searchable,options,displayField,allowCreate,descriptionField,lookupColumns,lookupPageSize,lookupFilters.expression,returnType. SummarysummaryOperations.multiple,lookupFilters.dimensions.min,max,step. Ratingmax. Master-detailreference.FieldType.Not field documents, so not censused:
SelectOptionMetadata(the option face, ruled under objectui#6153 / objectui#7014),LookupColumnDef/LookupFilterDef(nested in accepted keys), andUploadedFileMetadata(a field VALUE payload).Tests (run on
00f58c4unless noted)field-metadata-family-retired-12242.test.ts(@object-ui/types). One pin per member: a fresh annotated literal carrying the retired key is refused (@ts-expect-error), the two spec twins are declared by reference and compile, both type values go both ways, and the installed spec's own answer is checked for each, behind an accepting control.ObjectForm.visibleWhen-12242.test.tsx(@object-ui/plugin-form). Through the realObjectForm:visibleWhenhides the field until the record satisfies the predicate (the live control), and the same predicate undervisible_ongates nothing.currencyConfigRelay-12242.test.tsx(@object-ui/plugin-detail). The fixed-EUR amount reachesDetailSection,RecordDetailPanelandRelatedList, beside a no-currency control. It was red before the fix on exactly the panel and the related list.ablation-replace.mjs(anchor hit and blob change verified on disk), and restored toblob == HEADwith an emptygit diff HEAD:ObjectForm'svisible_onread back turns its pin red (visible_on is no gate: the field is drawn: expected null not to be null).sectionFields'visible_on ??back turns 5 rows red.currency(?: never→?: string) turnstsc -p tsconfig.test.jsonred (TS2578: Unused '@ts-expect-error' directiveat the_currencyrow).ObjectForm's computed-type gate from'auto_number'to'autonumber'. Restoring'auto_number'left its pin green: the auto-number widget is display-only, andsanitize.tsstrips both spellings, so thedisabledflag changes nothing a person sees. That edit and its vacuous pin were removed. The position is under Acceptance notes.Results at
00f58c4, all from the repo root under the verify lock:pnpm exec vitest runper package, each exit 0:packages/types/: 373 files, 10217 tests passed.packages/plugin-form/: 180 files; 2200 passed, 1 skipped.packages/fields/: 250 files (249 passed, 1 skipped); 4019 tests passed, 7 skipped.scripts/__tests__/: 183 files (181 passed, 2 skipped); 5541 tests passed, 2 skipped.scripts/that namecheck-doc-component-types(which this change edits): 9 files, 708 tests passed.packages/plugin-detail/: exit 1, with one test timing out:record-details.hideFieldsUncast-9965("resolved the mirror"), 34s against its 15s budget, mid-suite on a shared box. Run alone on the same HEAD it passes 10/10 in 7s; the other 260 files passed. This reads as load, not a verdict.type-check, after the dependency-closure build:@object-ui/types,fields,plugin-form,plugin-detailandplugin-grid, each exit 0, with the script name echoed.plugin-detailwas red once, on thesummaryChipfixture, before that fixture was re-spelled.check:doc-types: "Every documented component type is registered".check:doc-json.check:designer-field-key-parity: OK.check:spec-symbols.check:new-line-citations: 0 new.check:control-bytes: OK.changeset:check,check-changeset-presence,check-changeset-no-major,check:changeset-claims.check-doc-links,check-doc-example-ids,check-doc-fence-languages.--test: NOT GOVERNED.check:doc-snippetsandcheck:doc-examplesexit 2 (could not run): they need the whole package set built, and CI builds it. A narrowed measurement stands in. Everytsblock of the seven touched pages (14 snippets) compiles--strictagainst the freshly built@object-ui/types/@object-ui/fieldsdist/. A planted control carryingmin_dateon aDateFieldMetadatafails with TS2322, so the harness can fail.check:readme-exportscould not judge 407 self-imports on the unbuilt tree. This change touches no README and no export.The seat's disposition
The census found members the stop condition keeps, so they are not retired here:
mobile_fullscreen,validate,pattern/pattern_message,dueLike,idField,picker/subtitle, and thegeolocationtype value. The seat switched the first line fromFixestoPart of, so objectui#12242 stays open as the anchor for those positions. Their disposition is recorded on the card. The merge of this PR decides none of them.Acceptance notes (observed, not filed)
sectionFields' name-string chain still reads the object schema'svisibleOn. The spec refuses that key too ("did you meanvisibleOn→visibleWhen?"), so it is a read of a key no published object can carry. It is not a census member and is left as it is.resolveFieldCurrency(@object-ui/i18n) reads a field-levelcurrencybeforecurrencyConfig. That is a second spelling for field metadata, but the resolver is shared with presentation surfaces wherecurrencyis a spec key. It is reported, not extended, and not changed here.RecordDetailView's section build forwardscurrencywithoutcurrencyConfig. I did not measure whetherDetailSection's enrichment from the object schema puts it back on the record page.ObjectForm's computed-type gate still comparesauto_number. It is inert for the display-only widget, as the ablation above shows.auto-number.mdxteaches a{Q}(quarter) token. The spec'sparseAutonumberFormatreads{Q}as a FIELD interpolation, so the page's own example{YY}Q{Q}-{000}renders24Q-001(measured with the spec'srenderAutonumber), not24Q1-001. That is a different defect class from this card, and it goes to the report for the seat.Generated by Claude Code