The bearer-token dispatch in orchestra_interaction (entry authorization, branch scoping, consumed-link lineage and the chain continuation) accreted fix by fix across #3608216: Webform interaction entry path does not enforce the dispatcher authorization: bearer-token resume and unauthenticated task-handle bind, #3608269: Authorize interaction resume by the node assignments, not the doorway; restore instance-scoped return display and #3608298: Follow a consumed branch-scoped link to its branch's current step (chain begins after the interactive node). It works and is well tested, but the decision logic is spread over the dispatcher, the gateway and the handlers, which is where the next subtle bug is most likely to hide.
Apply the decide-then-apply discipline that worked for the engine (#3608367: Rework the join and subprocess coordination into decide-then-apply collaborators (JoinCoordinator, SubprocessCoordinator)): a single resolver service evaluates a presented capability token and returns a value object stating what it may do now (dispatch this interactive step, show this consumed-branch status, refuse), and the controllers only apply it. The full interaction and webform test matrix must stay green; no route or token-format changes.
Issue fork orchestra-3608385
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 #3
mably commentedOpened MR !283. A CapabilityResolver service now makes every decision about a presented capability token in one place and one order, returning a CapabilityOutcome value object (finished, dispatch, messages, or nothing) the controller applies; resolveSignal carries the signal guards verbatim, including the assigned-step bearer refusal from #3608269: Authorize interaction resume by the node assignments, not the doorway; restore instance-scoped return display and the branch continuation plus catch-up from #3608298: Follow a consumed branch-scoped link to its branch's current step (chain begins after the interactive node).
The dispatcher controller drops from 510 to about 330 lines and only renders and resumes. Structural win beyond size: title() and step() consume the same outcome, so the page title can no longer disagree with the body (the hand-mirrored branchCurrentInteraction is gone). No route or token-format changes; all security comments moved verbatim onto the decisions they protect.
Verified locally with the concurrent sweep: root plus interaction stack plus inbox plus ui kernel suites (26 parallel batches, all green), the Functional suites in Docker (25), the inbox FunctionalJavascript test, phpcs and cspell.
Comment #5
mably commented