Issue #3624283: Set the interaction plugins' validation errors on the element so they reach the field
Fixes #3624283.
An error is matched to its field by that element's #parents, while SubformState::setErrorByName() builds the name out of #array_parents. The two differ under the classic modeler, which renders every node beneath a structure wrapper and hands the plugin subform a #parents path without it:
#parents: ["nodes","n_task","settings","interaction_settings"]
#array_parents: ["structure","nodes","n_task","settings","interaction_settings"]So a named error belonged to no element on the page: the control went unmarked, with no error styling and no aria-invalid, and OrchestraCmForm opens a collapsed node section by matching error keys against ^(nodes|flows)\]\[, which structure][ does not match. The author was shown the message with nothing on screen to correct, on a form whose sections are collapsed by default.
Three call sites, not the two the issue names
EntityInteraction's form_operation, and WebformInteraction's mode and context_display. A sweep of every validateConfigurationForm() in the project finds no others: the node features and the condition tree already build their keys from #parents by hand, and the plain forms are not subforms.
The comments above each site asserted the opposite, that the host "prefixes the subform's own place in the form for us". That is true of what it builds and false of what the error matcher reads, so each is corrected with the fix.
How this got pinned as correct
The webform host test asserted the structure][ key outright, with a comment saying it named the mode select. Both existing tests hand-build the subform and stamped only #array_parents, which is exactly what let the wrong belief pass for correct, so both now carry the #parents the form builder stamps, and the assertion is the submitted path.
EntityInteractionEditorTest is the answer to that: it drives the real OrchestraCmForm through the form builder. One test measures the two paths, so the fact the fix rests on is checked rather than assumed; the other submits a refused operation and asserts where the error lands. Reverting either plugin fails one of them.
Verified
Whole suites for orchestra_content, orchestra_interaction_webform, orchestra_interaction and orchestra_cm (31 kernel classes) green, plus the 127 unit tests; phpcs on the CI ruleset and on Drupal,DrupalPractice, phpstan level 5 and cspell all clean on the changed files.
AI-Generated: Yes (Claude Code was used to help write this change, its tests and this description. I reviewed the work; the behavior was measured against the real modeler form rather than inferred, and each fix was confirmed to fail its test when reverted.)