Scope ContextMessages::retract() to the completing step
Fixes #3608544 (audit finding I2).
ContextMessages::retract() drained all messenger messages of a severity and re-added only those whose rendered string did not match anything the service had posted this request, tracked in one flat list. Two problems followed: a second orchestra form on the page posted into the same request-scoped list, so completing one step withdrew the other step's still-relevant context; and the guarantee "other modules' messages are left untouched" held only for differing strings.
This scopes the tracking per step (instance and token) so retract(instance, token) withdraws only the completing step's own postings, and withdraws at most as many of each rendered string as that step posted (count-bounded). Another step's context and other modules' messages survive.
- ContextMessages::display()/retract() key their record by a step key; retract() gains (instance, token) parameters.
- OrchestraInteractionHandler passes the resumed step's instance and token to retract().
- Adds ContextMessagesTest::testRetractIsScopedToItsStep (two steps post context; completing one leaves the other's and an unrelated message in place). Verified it fails without the scoping and passes with it.
Documented limit (not fixable via the messenger API): Messenger::addMessage normalizes every message to a plain Markup (the object handed in is discarded) and de-dups equal strings, so a per-message object marker cannot survive and a byte-identical string from another source cannot be told apart. The per-step, count-bounded scoping is the strongest guarantee the public API allows.
Verified locally: ContextMessagesTest (7) and OrchestraInteractionHandlerTest (15) green, phpcs and cspell clean.