Child of #3618694: Take every submodule out of the engine's words, in code and in prose. Two screens need to know what a row belongs to. A page title names the nearest one, so that two identically named rows are told apart: "Edit section VIP of Grand hall". A machine name is unique within the things it belongs to rather than across the site, so two halls may both name a section "vip".
Both were answered by a list of field names written in the engine. EntityTitle held venue, resource, slot, preset, pinning, configuration; the machine name widget held tenant, venue. Four of those seven names are fields the engine does not own: a hall belongs to the module that has halls. The module that adds a field is the one that knows what it means, and neither list could be kept honest by anything, because a field renamed on the far side leaves a title saying nothing and a key unique site-wide, and neither fails.
One question, asked of the owner
They are the same question. An entity type now declares what its rows belong to, nearest first, as parent_fields in its attribute. A title takes the first of the chain that names an entity; a machine name is narrowed by every field in the chain the row has filled. Twenty-two entity types declare their own chain, each in the module that defines it, and the engine names no field it does not own.
EntityParents is the one reader, so the property name is written once. The tenant is last in every chain because it is the widest wall, and it is a plain string rather than a reference, which is why a title skips it and a machine name does not: "of default" tells a reader nothing they came for, while a key free to collide across tenants is not unique at all.
Why this is declared rather than derived
An entity type attribute's additional is an open bag: a misspelled property is not an error, it is silence, and so is a field name that no longer exists. Both failures are invisible at runtime, which is the same shape of failure as #3618720: Call a partition of a resource a partition, in the engine and across the seam and #3618731: Carry the fields a module puts on a booking in a type of their own. So the guard comes with it: a test asserts that every yoyaku content entity type declares a chain, that every field named in one exists on that type, and that each chain ends at the tenant. Both failure modes were seen to fail before the change was trusted, by removing one declaration and by pointing another at a field that does not exist.
One deliberate change of behaviour
A resource also references a pinning and a configuration, and a slot references a pinning, and the old list treated those as scopes. They are policies attached to the row, not things it belongs to, so a resource with no hall used to be titled "of" the pinning it happened to use. Its chain is the hall and the tenant, and such a resource now names no parent.
Not in this change
BookingHooks keeps three lists that name other modules' fields, and it cannot use a declaration: those lists are read inside hook_entity_base_field_info_alter(), which answers by reading the very definitions that would carry it. That needs a mechanism of its own rather than this one bent to fit, so it is a separate issue.
ResourceFieldGroups is staying as it is, and not because it was missed. It maps every module's resource fields to a heading on the resource form, and that map is core curating one form's arrangement: the groups are core's own headings, a field no group names is left ungrouped rather than misplaced, and the reason the map is in one place is that two screens were grouping the same fields differently. Handing each module its own group would leave the whole arrangement owned by nobody.
Verification
phpstan at level 3 reports no errors, phpcs and cspell clean. Eight kernel classes green, including the machine name screens and the translation screens that read the same widget, plus a new test of the consequence at the surface: a hall that already has a "vip" section refuses a second, and another hall may name one of its own.
AI-Generated: Yes (Claude Code designed and made this change and wrote this summary. The mechanism is the entity type property bag that Drupal core uses for the same purpose, verified against core rather than assumed, and the chains were read off the running site rather than inferred from the code, so that every declaration reproduces what the two screens already did.)
Issue fork yoyaku-3618762
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
mably commented