Child of #3618694: Take every submodule out of the engine's words, in code and in prose, and the last of the four lists it set out to remove. A resource carries forty-odd questions from six modules, and a rule may be written about most of them at the tenant, the type or the site. Three facts decide what happens to each: whether a rule reaches the field at all, what its reader lands on when no level answers, and whether a rule value is copied into the row instead of followed from it.

All three were lists of field names written in the engine: FOLLOWED with nineteen names, FALLS_BACK_TO with seventeen, COPIED_ON_CREATE with nine. Two thirds of those names are fields the engine does not own. A field renamed on the far side simply stopped matching, and nothing failed: no inherit choice on the widget, the stored value read literally by its reader, and a rule that reaches nothing.

Declared on the definition, by the module that builds it

Each module now says it on the fields it adds, with RuledField::FOLLOWS, RuledField::FALLS_BACK_TO and RuledField::COPIED_ON_CREATE as settings on the definition. Twenty-eight declarations across six modules, and the engine names no field it does not own.

The fallback belongs there for a reason of its own: it is what the READER lands on when no level names a value, and the reader lives beside the field. Each manager names the unit nothing recognizes, and seating a party together; the engine was holding those answers on their behalf.

Why the definition is the only place this could live

The inherit value is added in an alter on these very definitions, and the registry that knows which fields a rule reaches answers by reading them, so asking it from inside that alter recurses until PHP gives up. That is what the old comment said, and it was right: it is why the lists were there. But the alter is handed the definitions it would have to ask about, so reading the fact off the one in hand asks nobody anything. The constraint is respected rather than worked around.

The guard, and what it is for

Declaring moves the failure rather than removing it: a module that forgets leaves its field out of the rule chain, and that still fails nothing on its own. So the expected sets are written down in a test, module by module, and a forgotten declaration fails naming the field. Seen to fail before being trusted, by removing one. A third test asks the question an operator would: is "Inherit" offered on this field, is it what a new resource starts as, and does the choice say what inheriting all the way up lands on.

One dead entry removed

FALLS_BACK_TO carried settlement_grace, and nothing could ever read it: the alter requires the field to be followed first, and a duration is not a list of strings, so it was skipped every time. It is gone rather than translated into a declaration nothing would use.

Verification

phpstan at level 3 reports no errors, phpcs and cspell clean. Eight kernel classes green, including the field rule resolver, the rule form, the rule maker and the boundary guard. The new test installs all six declaring modules at once, which is the only way to see that every provider actually declared.

AI-Generated: Yes (Claude Code designed and made this change and wrote this summary. The first attempt at the twenty-eight edits was made with a script that scanned for the end of each statement and found a semicolon inside a comment instead, cutting the comment in half; it was reverted and redone using PHP's own tokenizer, which cannot make that mistake. The declarations themselves were checked against the running site, field by field, so each one is owned by the module the site says owns it.)

Issue fork yoyaku-3618769

Command icon 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

mably created an issue. See original summary.

mably’s picture

Status: Active » Needs review

  • mably committed 7a46e8f2 on 1.x
    task: #3618769 Let each field say how a rule reaches it, instead of the...
mably’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.