Symptom
On the console record detail page, the page header title does not resolve the object's declared nameField. An object that declares e.g. nameField: 'subject' (and has no field literally named name/title, no titleFormat) renders its header as <ObjectLabel> <id-prefix> instead of the record's subject value. If the object also has a name field, the header always shows name even when nameField points at a different field.
This is the record-page-header sibling of objectstack-ai/objectstack#1295 (LookupCellRenderer, fixed): the framework serves nameField correctly (spec object.zod.ts, ADR-0079/0085; displayNameField alias normalized), and @object-ui/core#getRecordDisplayName already treats nameField as the top-priority declared title pointer — but the page header renderer never calls it.
Root cause
Two spots, both bypass the unified ADR-0079 resolver:
-
packages/components/src/renderers/layout/containers.tsx ~970-982 (PageHeaderRenderer record chip) — title chain is:
explicitTitle → objSchema.primaryField → titleFormat → data.name/full_name/title/subject/display_name/label → objectLabel+id.
primaryField does not exist on the spec ObjectSchema (the canonical property is nameField), so it is always undefined for stack-defined objects, and the chain never consults objSchema.nameField/displayNameField nor getRecordDisplayName().
This is the header every default record detail page renders: RecordDetailView synthesizes the page via buildDefaultPageSchema() (renderViaSchema default-on) which emits a page:header node.
-
packages/app-shell/src/views/RecordDetailView.tsx ~1222 — primaryField derivation is objectDef.primaryField || fields.find(k => k === 'name' || k === 'title'), again ignoring objectDef.nameField. This value feeds detailSchema.primaryField (DetailView title priority 1) and buildDefaultPageSchema's highlight-strip dedup, so a nameField-titled record also gets its title field duplicated in the highlight strip.
Note DetailView.resolveDisplayTitle (plugin-detail) does call getRecordDisplayName — but that header is suppressed under the synthesized page (page:header renders instead), so the correct path is dead on the default console record page.
Expected
page:header resolves the record title through getRecordDisplayName(objSchema, data, { deriveFromRecordKeys: false }) (mirroring DetailView.resolveDisplayTitle), so nameField → displayNameField → titleFormat → type-aware derivation applies uniformly, matching gallery / kanban / calendar / gantt / lookup which already use the unified resolver. RecordDetailView's primaryField derivation should prefer objectDef.nameField over the literal name/title probe.
Repro
- Define an object with
nameField: 'subject', fields subject (text) + others; no name field, no titleFormat.
- Open a record in the console (default record page, no assigned Page).
- Header shows
<ObjectLabel> <first-8-chars-of-id> instead of the subject value.
Verified present at objectui main (36ee9bb) and at 7a53249d865f (the SHA bundled into @objectstack/framework's console).
Symptom
On the console record detail page, the page header title does not resolve the object's declared
nameField. An object that declares e.g.nameField: 'subject'(and has no field literally namedname/title, notitleFormat) renders its header as<ObjectLabel> <id-prefix>instead of the record's subject value. If the object also has anamefield, the header always showsnameeven whennameFieldpoints at a different field.This is the record-page-header sibling of objectstack-ai/objectstack#1295 (LookupCellRenderer, fixed): the framework serves
nameFieldcorrectly (specobject.zod.ts, ADR-0079/0085;displayNameFieldalias normalized), and@object-ui/core#getRecordDisplayNamealready treatsnameFieldas the top-priority declared title pointer — but the page header renderer never calls it.Root cause
Two spots, both bypass the unified ADR-0079 resolver:
packages/components/src/renderers/layout/containers.tsx~970-982 (PageHeaderRendererrecord chip) — title chain is:explicitTitle → objSchema.primaryField → titleFormat → data.name/full_name/title/subject/display_name/label → objectLabel+id.primaryFielddoes not exist on the spec ObjectSchema (the canonical property isnameField), so it is always undefined for stack-defined objects, and the chain never consultsobjSchema.nameField/displayNameFieldnorgetRecordDisplayName().This is the header every default record detail page renders:
RecordDetailViewsynthesizes the page viabuildDefaultPageSchema()(renderViaSchema default-on) which emits apage:headernode.packages/app-shell/src/views/RecordDetailView.tsx~1222 —primaryFieldderivation isobjectDef.primaryField || fields.find(k => k === 'name' || k === 'title'), again ignoringobjectDef.nameField. This value feedsdetailSchema.primaryField(DetailView title priority 1) andbuildDefaultPageSchema's highlight-strip dedup, so anameField-titled record also gets its title field duplicated in the highlight strip.Note
DetailView.resolveDisplayTitle(plugin-detail) does callgetRecordDisplayName— but that header is suppressed under the synthesized page (page:headerrenders instead), so the correct path is dead on the default console record page.Expected
page:headerresolves the record title throughgetRecordDisplayName(objSchema, data, { deriveFromRecordKeys: false })(mirroringDetailView.resolveDisplayTitle), sonameField → displayNameField → titleFormat → type-aware derivationapplies uniformly, matching gallery / kanban / calendar / gantt / lookup which already use the unified resolver.RecordDetailView'sprimaryFieldderivation should preferobjectDef.nameFieldover the literalname/titleprobe.Repro
nameField: 'subject', fieldssubject(text) + others; nonamefield, notitleFormat.<ObjectLabel> <first-8-chars-of-id>instead of the subject value.Verified present at objectui
main(36ee9bb) and at7a53249d865f(the SHA bundled into @objectstack/framework's console).