Transition.emit cannot express that requiresPayload already validated its payload #48
Labels
No labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
iterative-works/support#48
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found in medeca-modul-poptavky while implementing MEDECA-453. Two independent code reviewers (architecture and security) flagged the same fold without seeing each other's finding.
What happens
A
Transition'semitrecomputes a value thatrequiresPayloadalready validated, and folds the failure case toSeq.empty:That
Leftbranch is unreachable only becauseWorkflowInterpreter.deciderunsrequiresPayload— which rejects the sameLeft— before it ever callsemit, over the oneval entity = ctx.entityit captures (workflow/shared/src/main/scala/works/iterative/workflow/WorkflowInterpreter.scala:49-75). Both reviewers traced that code and confirmed the invariant holds today.Why it is worth fixing
The guarantee lives in a different module from the code that depends on it, and it is not expressed in
emit's type. If an interpreter refactor reorders those calls, or the validating function is reused outsidedecide, a command that should be rejected turns into zero events and no error — work silently dropped, with nothing to observe. The transition author has no way to state the dependency and no way to be warned when it breaks.Logging the branch was considered and rejected at the call site:
PodaniEngineis cross-compiled shared code with no logger in scope.Suggested fix
Either:
decidepassrequiresPayload's accepted payload intoemit, soemitcannot re-derive the value and cannot fail; orTransitioncontract, so an author knowsemitmay assumerequiresPayloadsucceeded and a future interpreter change knows it must preserve that.(1) is the stronger fix — it makes the invariant unbreakable rather than merely written down.