Three platform gaps found while fixing dossiq's case flow live defects (dossiq#1625, proof-instance run 2026-09-01). Each turned a declarative mistake or an app-side omission into a silent runtime failure.
-
Engine-side identity scoping for contributed nodes. FlowRunService stamps the acting identity as a bare $context['runAs'] string; openregister's own nodes wrap their writes in ObjectService::runAs(), but app-contributed nodes (registered via RegisterFlowNodesEvent) execute with no ambient identity, so every app must reimplement the wrap. dossiq missed it in three nodes and every worker-driven write failed as Anonymous. Fix direction: scope contributed node execution centrally (wrap execute() in the run's identity), or at minimum export a constant for the context key plus a helper, and document the contract in the node registration docs.
-
Value templating for contributed nodes. The engine renders {{ }} templates only inside its own nodes (SetFieldsNode/ObjectReadNode). A contributed node that stores an authored value stores the literal: dossiq shipped an assignee of '{{ case.assignee }}' that no user could ever match. Fix direction: render node config values against the item before execute(), or expose FlowValueTemplate through the node context so contributed nodes have one obvious seam.
-
The importer accepts edge-level conditions it never reads. FlowTokenRouter reads conditions from node exits[] referenced by edge.fromExit; FlowDefinitionBuilder/import accepts 'condition' directly on an edge without warning, so a wrong-shaped declaration imports clean and silently misroutes (a COMPLETE case took the incomplete branch). Fix direction: refuse or at least warn on edge-level condition at import/validation time; the accepted grammar must be the executable one.
Related: the trigger id/slug defect and missing adoption seam from the same live run are fixed in #3285.
Three platform gaps found while fixing dossiq's case flow live defects (dossiq#1625, proof-instance run 2026-09-01). Each turned a declarative mistake or an app-side omission into a silent runtime failure.
Engine-side identity scoping for contributed nodes. FlowRunService stamps the acting identity as a bare $context['runAs'] string; openregister's own nodes wrap their writes in ObjectService::runAs(), but app-contributed nodes (registered via RegisterFlowNodesEvent) execute with no ambient identity, so every app must reimplement the wrap. dossiq missed it in three nodes and every worker-driven write failed as Anonymous. Fix direction: scope contributed node execution centrally (wrap execute() in the run's identity), or at minimum export a constant for the context key plus a helper, and document the contract in the node registration docs.
Value templating for contributed nodes. The engine renders {{ }} templates only inside its own nodes (SetFieldsNode/ObjectReadNode). A contributed node that stores an authored value stores the literal: dossiq shipped an assignee of '{{ case.assignee }}' that no user could ever match. Fix direction: render node config values against the item before execute(), or expose FlowValueTemplate through the node context so contributed nodes have one obvious seam.
The importer accepts edge-level conditions it never reads. FlowTokenRouter reads conditions from node exits[] referenced by edge.fromExit; FlowDefinitionBuilder/import accepts 'condition' directly on an edge without warning, so a wrong-shaped declaration imports clean and silently misroutes (a COMPLETE case took the incomplete branch). Fix direction: refuse or at least warn on edge-level condition at import/validation time; the accepted grammar must be the executable one.
Related: the trigger id/slug defect and missing adoption seam from the same live run are fixed in #3285.