Opt in to the parallel-successor condition constraint in the modeler
>>> [!note] Migrated issue
<!-- Drupal.org comment -->
<!-- Migrated from issue #3588497. -->
Reported by: [jurgenhaas](https://www.drupal.org/user/168924)
Related to !619
>>>
<h3>Problem/Motivation</h3>
<p>ECA's runtime invokes a component's successors in order. When a component has two-or-more successors that all point to the same target, the only way to distinguish which successor should fire is via a condition. If any of those parallel successors has no condition, the runtime simply invokes the target unconditionally, which makes the conditional siblings redundant or contradictory — the model is meaningless in practice.</p>
<p>The modeler currently allows this configuration to be saved. Once the related <code>modeler_api</code> issue introduces an opt-in <code>requireConditionWhenParallel</code> flag on the per-type successor constraint, ECA can opt in to have the modeler reject such configurations both server-side at save time and client-side before save.</p>
<p>This issue is a follow-up to <a href="https://www.drupal.org/project/modeler/issues/3586864">modeler #3586864</a>, which made parallel edges visually distinguishable.</p>
<h3>Proposed resolution</h3>
<p>In ECA's model owner (<code>modules/ui/src/Plugin/ModelerApiModelOwner/Eca.php</code>), override <code>modelConstraints()</code> to set <code>requireConditionWhenParallel</code> to <code>TRUE</code> for every component type that can be a successor source in an ECA model — typically <code>COMPONENT_TYPE_START</code>, <code>COMPONENT_TYPE_ELEMENT</code>, and <code>COMPONENT_TYPE_GATEWAY</code>.</p>
<p>Example:</p>
<pre><pre>public function modelConstraints(): array {<br> return [<br> Api::COMPONENT_TYPE_START => [<br> 'successors' => ['requireConditionWhenParallel' => TRUE],<br> ],<br> Api::COMPONENT_TYPE_ELEMENT => [<br> 'successors' => ['requireConditionWhenParallel' => TRUE],<br> ],<br> Api::COMPONENT_TYPE_GATEWAY => [<br> 'successors' => ['requireConditionWhenParallel' => TRUE],<br> ],<br> ];<br>}</pre></pre><p>Maintainers should review which component types in ECA can legitimately have parallel successors and only opt in for those. If existing per-type cardinality constraints already cover some of the entries, merge the new flag into the existing return value rather than replacing it.</p>
<h3>Dependencies</h3>
<ul>
<li>Requires the new <code>requireConditionWhenParallel</code> flag in <code>modeler_api</code>: <em>(link to modeler_api issue once filed)</em></li>
<li>Requires the modeler UI mirror so the user sees errors before save: <em>(link to modeler issue once filed)</em></li>
</ul>
<h3>Implementation outline</h3>
<ol>
<li>Wait for the <code>modeler_api</code> change to land (or develop against the corresponding MR).</li>
<li>Override <code>modelConstraints()</code> in <code>Eca</code> to enable the flag for the relevant component types.</li>
<li>Add a unit test that confirms the constraint is reported by <code>modelConstraints()</code> for the expected types.</li>
<li>Add an integration test (or rely on the modeler-side E2E) that constructs a violating ECA model and asserts save is blocked.</li>
</ol>
<h3>Remaining tasks</h3>
<ul>
<li>Decide which component types should opt in.</li>
<li>Implement the override in <code>Eca::modelConstraints()</code>.</li>
<li>Tests.</li>
<li>Document in ECA's release notes that previously-saveable degenerate models will now be rejected.</li>
</ul>
<h3>User interface changes</h3>
<p>None directly in ECA. The modeler UI (which ECA uses) will refuse to save ECA models that have two-or-more uncondied successors between the same source and target, displaying a translated error message naming the offending components.</p>
<h3>API changes</h3>
<p>None.</p>
<h3>Data model changes</h3>
<p>None. Existing ECA models that already satisfy the rule are unaffected. Existing models that violate the rule will fail validation on the next save attempt — maintainers should call this out in release notes.</p>
<h3>Related issues</h3>
<ul>
<li>Constraint definition: <em>(link to modeler_api issue once filed)</em></li>
<li>Modeler UI mirror: <em>(link to modeler issue once filed)</em></li>
<li>Originating context: <a href="https://www.drupal.org/project/modeler/issues/3586864">modeler #3586864</a></li>
</ul>
> Related issue: [Issue #3588494](https://www.drupal.org/node/3588494)
issue