I have further refined this and have concluded that it is a JBoss bug, but haven't narrowed it down to JBoss Portal (2.2.1SP3) or the AS (4.0.4GA).
I added a session attribute listener and printed the session ID when attributes were added from both the portlet and from the strategy class. The session IDs in all three places (portlet class, strategy class, and listener class) were the same. But the original problem is that the attributes added in the portlet in APPLICATION_SCOPE cannot be found by the strategy class. Printing the object and tracing a little in Eclipse showed that the StandardSessionFacade object behind the session retrieved was different, but contained the same session ID.
The attributes attached to each session object are mutually exclusive, which is a little confusing since they have the same session ID, and are supposed to be accessible.
Does anyone know if this bug is fixed in JBoss Portal 2.4? Can this be fixed easily in the 2.2.1SP3 code?