ADR-183: The AI section exists, and editor surfaces live in it
- Status
-
Accepted
- Date
-
2026-08-22
- Amends
-
ADR-119 (backend module placement)
- Authors
-
Netresearch DTT GmbH
Context
ADR-119 decided Administration, for now, and left the placement open with a named revisit trigger: the first cross-consumer editor surface. Issue #812 carried that open question so the next surface would not settle it by accident.
The question was put and answered rather than triggered. The section is created, and it is called AI.
Two arguments were weighed once more before deciding, and both are recorded because the second overturns a reason ADR-119 gave for the name.
"LLM" is the more precise name. It is not. Of the four products that share
the section, nr_repurpose generates audio and images, nr_ai_search
fuses BM25 keyword search with embeddings, and the cowriter drives CKEditor —
only nr_llm is a language-model product. A section named LLM holding a product
called AI Search that runs no language model would be wrong, not merely
unfashionable.
"Integrators look for AI." ADR-119 gave this as a reason and it does not hold: ADR-131 establishes that the section exists for editor-facing modules, so the label is read by editors. The conclusion survives its reason — "AI" is what an editor recognises, "LLM" is a developer's word — but the reason itself is withdrawn here.
Decision
A shared top-level section netresearch_ai holds five entries:
netresearch_ai no access check of its own
├── nrllm_aitasks access => user (editors)
├── nrllm_overview access => admin (aliases: nrllm)
├── nrllm_setup providers, models, configurations, use-case, wizard
├── nrllm_authoring tasks, skills, snippets
└── nrllm_operation tools, MCP, playground, runs, analytics
Four of those five come from the fourteen entries ADR-119 called a dumping
ground, which is the "three or four entries" it asks for. nrllm_aitasks
is the fifth and was never one of the fourteen: it sat under web.
The access check is the whole mechanic
The module menu drops every top-level module whose own access check fails,
together with its children (ADR-131). That is why
nrllm_aitasks was parented to web: under the admin-only nrllm
container it would have been invisible to the editors it exists for. Every
further editor surface would have landed flat under web for the same
reason, one entry at a time — the accretion #812 was filed to prevent.
A section carries no access key, exactly like the core's own sections
in cms-core/Configuration/Backend/Modules.php. It therefore never filters,
and its children filter individually. Admin-only and editor-facing modules can
share one place for the first time.
The nesting depth is unchanged. tools → nrllm → nrllm_providers was
already three levels; netresearch_ai → nrllm_setup → nrllm_providers is
the same shape with the top level owned rather than borrowed.
The four pre-settled answers, as applied
ADR-119 settled four things in advance for this moment. Three are applied verbatim; the fourth is applied with its reason corrected above.
- The name is "AI" — applied, reason revised.
- The identifier is vendor-scoped (
netresearch_ai) — applied. Module identifiers merge last-package-wins, so a bareaiwould be a shared namespace with no owner. - The flat entries do not move as they are — applied. Three subject containers, holding five, three and five entries.
- Old routes keep working — applied. Submodule identifiers and explicit
paths are unchanged,
setShortcutContextis repointed fromnrllmtonrllm_overview, and that module carries'aliases' => ['nrllm'].
Consequences
Backend shortcuts survive. They store the module identifier, and the alias
resolves it. This works only because nrllm is no longer registered as a
real module — an alias is shadowed by a real module of the same name.
Foreign anchors survive, and this was verified rather than assumed.
t3_cowriter positions itself with ['after' => 'nrllm'].
ModuleFactory::adaptAliasMappingFromModuleConfiguration() rewrites
position.before and position.after through aliases, not just
parent, so that anchor re-resolves to nrllm_overview with no change in
the cowriter.
The container URL does not survive. /module/nrllm was the container's
own path and has no successor; /module/nrllm/overview and every submodule
path are unchanged. ADR-119 accepted this when it settled on keeping the
submodule paths.
The three sibling extensions are not changed by this record. They may
register under netresearch_ai when they choose to; nothing breaks while
they do not. What this decision gives them is a place that exists.
The revisit trigger is spent. ADR-119's open question is closed, so a new editor surface is now an ordinary addition to an existing section rather than an occasion to decide where the section should be.
Alternatives
A container under Administration, the shape the core uses for
integrations. Rejected for the access-check reason above: a container
inherits its parent's visibility, and Administration is admin-only, so the
editor surfaces this exists for would still have had nowhere to live.
Leaving it until the trigger fired. Rejected because the trigger fires inside a change that is about something else, which is exactly how a placement gets settled by accretion. #812 existed to take the decision out of that moment.