Measured while implementing #4914's dispatched fast-follow (items 1-3 + 5, PR pending). Filed unassigned.
The face
packages/fields/src/FieldEditWidget.tsx:85 — EDIT_WIDGETS contains:
This is not one of the faces #4914 enumerates. That card lists FieldEditWidget.tsx:170 (the COMPACT_EDIT_TYPES set, cosmetic — trigger sizing) as item 11. Line 85 is the routing table itself, and it is live.
Why it is live rather than dead
hasFieldEditWidget(type) answers resolveInlineEditType(type) in EDIT_WIDGETS, and resolveInlineEditType returns the type unchanged when it is already a key (FieldEditWidget.tsx:144). So the alias table is never consulted and the retirement never applies:
hasFieldEditWidget('owner') === true
Measured on origin/main @ 69dbea20a (post-#4915). Every host built on FieldEditWidget therefore still offers a working person picker for a stored field typed owner, while the record form answers the same field with the tombstone refusal — the same two-surfaces-disagree shape that promoted #4914 item 5 out of the "inert" framing.
Directly observed while reverse-verifying the #4914 work: with the retired-spelling refusal branch removed from InlineFieldInput and 'owner' gone from its routing table, a retired field still rendered a picker trigger reading Select… — tombstone: false, plainTextInput: false, one role=button. Deleting a routing-table membership does not disable the type; delegation reaches the same widget by another road.
Scope of the exposure
InlineFieldInput is not affected once #4914's fast-follow lands: its refusal branch runs before both the routing switch and the delegation tail. The unprotected consumers are the ones that call FieldEditWidget / hasFieldEditWidget directly — the grid's inline cell editor is the one with a user-facing surface.
Suggested fix
Drop the owner key from EDIT_WIDGETS and let resolveInlineEditType fall through to the alias table, which already answers retired spellings with field:owner (field-type-alias.ts) — i.e. make this seam consult the retirement the same way resolveFormWidgetType does. Better still, have hasFieldEditWidget answer false for any key of RETIRED_FIELD_TYPES so the whole class closes at once rather than one spelling at a time. COMPACT_EDIT_TYPES (#4914 item 11) can be cleaned in the same stroke.
Note for whoever takes it: packages/plugin-detail/src/__tests__/InlineFieldInput.retiredFieldType.test.tsx (landing with #4914's fast-follow) deliberately does not pin today's hasFieldEditWidget('owner') === true in either direction, precisely so it does not go red on this fix.
Generated by Claude Code
Measured while implementing #4914's dispatched fast-follow (items 1-3 + 5, PR pending). Filed unassigned.
The face
packages/fields/src/FieldEditWidget.tsx:85—EDIT_WIDGETScontains:This is not one of the faces #4914 enumerates. That card lists
FieldEditWidget.tsx:170(theCOMPACT_EDIT_TYPESset, cosmetic — trigger sizing) as item 11. Line 85 is the routing table itself, and it is live.Why it is live rather than dead
hasFieldEditWidget(type)answersresolveInlineEditType(type) in EDIT_WIDGETS, andresolveInlineEditTypereturns the type unchanged when it is already a key (FieldEditWidget.tsx:144). So the alias table is never consulted and the retirement never applies:Measured on
origin/main@69dbea20a(post-#4915). Every host built onFieldEditWidgettherefore still offers a working person picker for a stored field typedowner, while the record form answers the same field with the tombstone refusal — the same two-surfaces-disagree shape that promoted #4914 item 5 out of the "inert" framing.Directly observed while reverse-verifying the #4914 work: with the retired-spelling refusal branch removed from
InlineFieldInputand'owner'gone from its routing table, a retired field still rendered a picker trigger readingSelect…—tombstone: false,plainTextInput: false, onerole=button. Deleting a routing-table membership does not disable the type; delegation reaches the same widget by another road.Scope of the exposure
InlineFieldInputis not affected once #4914's fast-follow lands: its refusal branch runs before both the routing switch and the delegation tail. The unprotected consumers are the ones that callFieldEditWidget/hasFieldEditWidgetdirectly — the grid's inline cell editor is the one with a user-facing surface.Suggested fix
Drop the
ownerkey fromEDIT_WIDGETSand letresolveInlineEditTypefall through to the alias table, which already answers retired spellings withfield:owner(field-type-alias.ts) — i.e. make this seam consult the retirement the same wayresolveFormWidgetTypedoes. Better still, havehasFieldEditWidgetanswerfalsefor any key ofRETIRED_FIELD_TYPESso the whole class closes at once rather than one spelling at a time.COMPACT_EDIT_TYPES(#4914 item 11) can be cleaned in the same stroke.Note for whoever takes it:
packages/plugin-detail/src/__tests__/InlineFieldInput.retiredFieldType.test.tsx(landing with #4914's fast-follow) deliberately does not pin today'shasFieldEditWidget('owner') === truein either direction, precisely so it does not go red on this fix.Generated by Claude Code