add FBOrJoin (WCP-07 Structured Synchronizing Merge) - #76
Merged
Conversation
Key realization while designing this: the actual join-completion logic (wait until arrived size >= expected size, then aggregate and follow outgoing) is identical between AND-Join and OR-Join - the only difference is where `expected`'s size comes from. AND-Join uses the join node's static incoming count; OR-Join needs the count of branches the preceding OR-Split *actually started this time*, which is only known at runtime. Renamed FBAndJoinBehavior to the neutral FBJoinBehavior and share it between FBAndJoin and the new FBOrJoin, rather than duplicating the same logic into a separate FBOrJoinBehavior. Safe to rename outright (no compatibility class) since it's a behavior class - transient, never persisted per-instance in Soil, and was only introduced this session (PR #74), same reasoning as the FBJoinNode -> FBParallelJoinNode rename from PR #55. Verified the rename didn't leave stale source text anywhere (Class rename: updates the live binding but not already-compiled callers' decompiled source, so FBAndJoin>>defaultBehaviorClass needed an explicit recompile to actually say FBJoinBehavior in its source, not just resolve correctly at runtime) and re-grepped for lingering references to the old name. FBMultiChoiceGatewayBehavior (the OR-Split) now generates a splitId, determines which outgoing transitions actually match their condition *before* following any of them, registers that count via a new FBFlowInstance>>registerExpectedBranchCount:forSplitId:, then assigns each matching branch its own branchId - same pattern as FBAndSplitBehavior from PR #73. FBFlowInstance>>joinStateFor:splitId: now checks for a registered dynamic count first and falls back to the static incoming count (AND-Join's existing, unchanged path) only if none was registered. Verified with 1-of-2, 2-of-2, and 2-of-3 branch combinations: the join proceeds as soon as the branches actually taken have all arrived, never waiting for a branch whose condition was false and so was never started. Value aggregation (from PR #75) works the same way, containing only the actually-started branches. 138/138 tests passing (134 existing + 4 new in FBOrJoinBehaviorTest). Full sample-flow smoke test unchanged. FBOrJoin inherits the same >=2 incoming / <=1 outgoing arity validation as every other FBMergeGateway subclass, verified directly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Key realization while designing this: the actual join-completion logic (wait until arrived size >= expected size, then aggregate and follow outgoing) is identical between AND-Join and OR-Join - the only difference is where
expected's size comes from. AND-Join uses the join node's static incoming count; OR-Join needs the count of branches the preceding OR-Split actually started this time, which is only known at runtime.Renamed FBAndJoinBehavior to the neutral FBJoinBehavior and share it between FBAndJoin and the new FBOrJoin, rather than duplicating the same logic into a separate FBOrJoinBehavior. Safe to rename outright (no compatibility class) since it's a behavior class - transient, never persisted per-instance in Soil, and was only introduced this session (PR #74), same reasoning as the FBJoinNode -> FBParallelJoinNode rename from PR #55. Verified the rename didn't leave stale source text anywhere (Class rename: updates the live binding but not already-compiled callers' decompiled source, so FBAndJoin>>defaultBehaviorClass needed an explicit recompile to actually say FBJoinBehavior in its source, not just resolve correctly at runtime) and re-grepped for lingering references to the old name.
FBMultiChoiceGatewayBehavior (the OR-Split) now generates a splitId, determines which outgoing transitions actually match their condition before following any of them, registers that count via a new FBFlowInstance>>registerExpectedBranchCount:forSplitId:, then assigns each matching branch its own branchId - same pattern as FBAndSplitBehavior from PR #73. FBFlowInstance>>joinStateFor:splitId: now checks for a registered dynamic count first and falls back to the static incoming count (AND-Join's existing, unchanged path) only if none was registered.
Verified with 1-of-2, 2-of-2, and 2-of-3 branch combinations: the join proceeds as soon as the branches actually taken have all arrived, never waiting for a branch whose condition was false and so was never started. Value aggregation (from PR #75) works the same way, containing only the actually-started branches.
138/138 tests passing (134 existing + 4 new in FBOrJoinBehaviorTest). Full sample-flow smoke test unchanged. FBOrJoin inherits the same >=2 incoming / <=1 outgoing arity validation as every other FBMergeGateway subclass, verified directly.