A bit more detail here, as this is biting me as well right now. I don't believe that the end event is actually terminating the flow-- I think it's just not propogating the error back to the caller.
Using your examples (which are awsome, BTW), when I check the session state after execution, the session is marked as STATE_ACTIVE, not STATE_COMPLETED. This seems to indicate that the engine still thinks that the process is running, when clearly it is not. For a test I created an identical flow that put the steps into an embedded sub-process (rather than a called one), and the sequence of events is identical but the process state is STATE_COMPLETED.
Now, if I remove the boundaryEvent that handles the error, the embedded version of the flow returns STATE_ABORTED (which I would expect), but the call version still returns STATE_ACTIVE. It sure looks like the issue is that the error in the sub-flow is not getting passed back up, so the error handling in the caller never gets executed.