Repository navigation
fix(fields,plugin-form): the served help leg retires, and fieldHelpText moves to @object-ui/fields as the one read (objectui#12213) - #12283
Conversation
…xt moves to @object-ui/fields as the one read (objectui#12213) The record form and a field-backed action param read a field's help line through one function, fieldHelpText, now exported by @object-ui/fields: inlineHelpText, else description, an empty string reading as absent. The served help key is no longer read, per the ruling on the card: its one producer was an objectstack server on spec 17.6.0 or earlier, and 17.7.0 serves the translated text on description. Claude-Session: https://claude.ai/code/session_015YrgVw7e65cs1ndbebt46G 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#12213 (body and all 10 comments, ruling ① Derived judgmentsEvery accept-set and public-surface change the diff implies, each judged.
② Semver level
③ Boundary flagsDev report
Further flags, answered:
Check-runs on the head (their conclusions are the gate verdicts), read complete shortly before this record was posted (2026-10-13T00:29Z): 33 runs, all Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #12213
Clause-②: yes
What this changes
Ruling
6134063362(letter A): the servedhelpread leg retires now. A field's help line has ONE read,fieldHelpText, which now lives in@object-ui/fields, and both readers call it.ObjectForm's field builder andfromObjectSchemafieldHelpText:field.inlineHelpText || field.help || field.descriptionfieldHelpTextfrom@object-ui/fields:field.inlineHelpText || field.descriptionresolveActionParam, for a field-backed param with nohelpTextof its ownhelpincludedparam.helpText ?? fieldHelpText(field)helpmembers are gone: plugin-form'sFieldHelpTextSourcegoes with its copy of the function (plugin-form keeps no copy and no re-export), andRuntimeField.helpleaves the resolver.inlineHelpText: ''still falls back todescription(||, not??).packages/fields(the read, its home filefieldHelpText.ts, the entry's export) andpackages/plugin-form(the two callers), as the dispatch expected.packages/types/src/field-types.tschanges one docblock phrase only:fieldHelpTextnow lives in@object-ui/fields.bab76850c, fix(spec): serve a field's translated help ondescription, never on an undeclaredhelpobjectstack#21956). Against an older server, a field's help line shows its storeddescription, untranslated.Export closure, measured on the built declarations
A script built on the TypeScript checker lists
getExportsOfModuleof each package'sexports['.'].typesfile, on a build of base48fb558dand on a build of this head:@object-ui/fieldsdist/index.d.tsfieldHelpTextfieldHelpTextonly, typed(field: Pick of BaseFieldMetadata's "inlineHelpText" and "description") => string | undefined, declared indist/fieldHelpText.d.ts, whose one import isBaseFieldMetadatafrom@object-ui/types@object-ui/plugin-formdist/index.d.tsControls in the same runs:
resolveActionParamPRESENT in the fields entry,ObjectFormPRESENT in the plugin-form entry.FieldHelpTextSourceis not an export name at either point. Its only built home was plugin-form'sdist/sectionFields.d.ts, a file noexportsentry reaches, which carried it and the old function at base and carries neither now (0 hits). (Generic type arguments are spelled out in words here because GitHub strips angle-bracket spans from bodies.)No home both readers could reach without a public export exists:
@object-ui/fieldspublishes.and./style.cssonly, and plugin-form imports it through..The ruling's fork clause, measured (no other producer, so no stop)
objectui
48fb558d, outside tests and docs:.helpmember: the two retired here, plus non-field shapes only (the flow inspector's config fields inFlowNodeConfigField.tsxandStudioDesignSurface.tsx,ShareDialogoptions, andBulkActionDialog'sBulkActionParam.help, whichresolveBulkActionsfills from the resolver'shelpText).help:key: 17 files, none writing it onto a field definition (flow config fields, i18n catalogues, share options, bulk params). JSON"help":keys: 0 files (control"description":118 files).transformSpecTranslationsflattens a field'slabelandoptionsonly. The console requests/api/v1/i18n/translations(control hit) and nevergetFieldLabels(0 hits repo-wide).objectstack
84643802:packages/spec/src/system/i18n-resolver.ts:next.help =0 hits, controlnext.description = translatedDescription1 hit.help:hit outside tests and docs is a translation bundle entry (the translator's input), a spec alias table, the translation schema's ownhelpmember, a bulk-action param, or the/i18n/labelsresponse (GetFieldLabelsResponse.labels.FIELD.help, built byresolveObjectFieldLabels). That last one is a separate labels document, not a field definition, and objectui never requests it, so it reaches neither reader.Pins, flipped from "read" to "ignored"
The repo-wide sweep of tests for a served field
helpfound exactly two pins, both flipped in this round. Each now asserts the new meaning, not just the absence of the old one. (field-metadata-inline-help-text-12213.test.tsin types pinshelpas a refused authoring key; that stays true and is unchanged.)objectFormInlineHelpText-12213.test.tsx(plugin-form; flat, sectioned and tabbed): a field withhelpanddescriptiondraws thedescriptionand not thehelptext. A newhelpOnlyfield draws no help line (empty accessible description, text absent).inlineHelpTextstill wins overhelp.ActionParamDialog.fieldHelpLine-12213.test.tsx(app-shell, real resolve and real dialog): theservedfield lends itsdescription. A newhelpOnlyfield lends nohelpText, and the text is not on screen.fieldHelpText-12213.test.tsx(fields) pins the entry export: the order, the empty-string rule,helpignored, and, at type level, that a typed literal carryinghelpdoes not compile.Reverse verification (from committed head
06213286, restored and hash-checked)Both mutations went through
ablation-replace.mjsin wrap mode: anchor hit 1 to 0, blob changed, and after the run the blob equals the HEAD blob andgit diff HEADis empty. Vitest aliases@object-ui/fieldstosrc, so no dist leg was needed.fieldHelpTextreadshelpagain, betweeninlineHelpTextanddescription. The three pin files went from 28 passed to 7 failed and 21 passed. The 7 are the "ignored" cases: 3 form layouts, 2 dialog cases, 2 fieldHelpText cases.helpagain. The fields test type-check fails withTS2578: Unused '@ts-expect-error' directiveinfieldHelpText-12213.test.tsx.Gates (all at head
06213286)@object-ui/console...closure, 35 of 35 tasks; then the@object-ui/cli...and@object-ui/plugin-ai...closures, 10 of 10.tscchain, exit 0:@object-ui/types,@object-ui/fields,@object-ui/plugin-form,@object-ui/plugin-grid,@object-ui/app-shell.packages/fields/,packages/plugin-form/and the types 12213 pin: 431 files passed, 1 skipped; 6226 tests passed, 8 skipped. The consumer set: 97 files re-derived by a grep of tests namingresolveActionParam,ActionParamDialog,fieldHelpTextorinlineHelpText, plus three more from the dispatch's lead list and a widerhelpTextgrep of tests (FormPage.richTextHints-12110,FormPage.fieldSpec, plugin-grid'sresolveBulkActions): 100 files passed, 979 tests.scripts/__tests__/: 187 files passed, 2 skipped; 5621 tests passed.check:readme-exports(592 self-imports, all real, 0 unbuilt; the new README importfieldHelpTextis judged real),check:spec-symbols,check:self-import,check:phantom-deps,check:unreferenced-sources,check:handler-key-reads,check:designer-field-key-parity,check:eager-closure(a head reading only: 3131.3 KB gzipped against a 3204.6 KB budget, headroom 73.3 KB; the base was not measured),check:esm-specifiers,check:changeset-claims,check:pending-changeset-literals,check:new-line-citations(0 new),check:control-bytes,check-changeset-fixed,check-changeset-presence,check-changeset-no-major,check:test-path-roots,check:vi-mock-specifiers,check:dist-completeness,check-type-check-coverage. The governed-surface guard on the 13 paths answers NOT GOVERNED.eslint.config.jslints**/*.{ts,tsx}. Run:eslint --no-inline-config --format jsonover the 9 touched ts/tsx files, which the JSON output counts as 9 files: 0 errors and 213 warnings. 212 of the warnings are on the base blobs of the same files. The one new warning isreact-refresh/only-export-componentson the newfieldHelpTextre-export inpackages/fields/src/index.tsx, the same warning the file's 53 other non-component exports carry. Invariance: noparserOptions.projectorprojectService(type-aware linting is off), and no rule ineslint-rules/reads another file, so this diff cannot move a verdict on an untouched file.Changesets
.changeset/12213-fields-field-help-text-export.md(new,@object-ui/fieldsminor): the new export, with theClause-②line..changeset/12213-plugin-form-inline-help-text.mdand.changeset/12213-fields-action-param-help.mdare EDITED, patch to minor. Both are unreleased: the three CHANGELOGs carry 0 mentions of 12213. Each said thehelpleg is still read, which this change makes false within the same release. Each now states the change from the last release (FROMhelpfirst, TOinlineHelpText || description) and carries the BREAKING section with the server floor.check-changeset-overwrite(report-only) lists both as modified, its case 2: a deliberate correction.@object-ui/typesgets no new changeset: one docblock phrase in its shipped.d.ts, with no change to behaviour or surface. Its pending12213-types-inline-help-text.mdstays true.@object-ui/app-shellchanges a test only.Acceptance notes
ObjectFormCanvasdrawsdescriptiononly, and aplugin-detailcomment listshelpamong the keys the spec'stranslateObjectreads.RuntimeField.inlineHelpText's doc namesfieldHelpText, andRuntimeField.descriptiongained a one-line doc.Generated by Claude Code