I have a plain client (public static void main) calling #1 MySesRemote.testExcept() method. This method calls another stateless bean #2 otherLocal.methodThrowsSystemEx() that throws a Runtime (system) exception.
Bean #2 runs in the transaction started by Bean #1. For bean #2 - I am in the first use-case as per MZ guide: 'Bean #2 method runs in the context of the caller's transaction'. The action is to 'Throw javax.ejb.EJBTransactionRolledbackException to client', the client being bean #1. This is what actually happens.
Since I don't start any transaction in the client, the container starts one before entering testExcept() method.
Bean #1 is in another use-case: 'Bean #1 method runs in the context of a transaction that the container started immediately before dispatching the business method.' For system exceptions, it should 'Throw EJBException to client.', but it does NOT - it rethrows the EJBTransactionRolledbackException.
I'm learning this as I go along too, and am concious that I don't want to add any confusion to your question.
Until I looked at your linked MZ Guide table 10.1, I was unaware that the javax.ejb.EJBTransactionRolledbackException existed, and just assumed that all clients (regardless of who started their transaction) got an EJBException. I've included some quotes below to that effect.
Without being too much help, I would try to find other sources to back up the assertions in the MZ Guide, and if they prove to be correct then it could be a container bug? Which container are you using?
On the other hand, all exceptions that inherit from either java.rmi.RemoteExceptions or java.lang.RuntimeException are assumed to be system exceptions (as you might already know, all exceptions that inherit from java.lang.RuntimeException are unchecked). In EJB, it is not assumed that system exceptions are expected by the client. When encountered, such exceptions are not passed to the client as is but are wrapped in a javax.ejb.EJBException instead.
Pages 195/196 continue:
If the container detects a system exception, such as an ArrayIndexOutOfBounds or NullPointerException that you didn’t plan for, it will still roll back the CMT. However, in such cases the container will also assume that the bean is in inconsistent state and will destroy the instance.