There are 2 issues contributing to this in the XSL portal project.
1. XsltRenderContext generates the wrong URL; and
2. portal.xsl looks for the value in the wrong place.
SkinnableCharonPortal appears to generate the "pagePopupUrl" as not the full page's popup url, but the prefix for page popup URLs. I verified that portal/portal-render-engine-impl/pack/src/webapp/vm/defaultskin/macros.vm knows to append the pageId, so it looks like this is the intended usage.
Possibly a better fix (but with more chance of regression) would be to make it so SkinnableCharonPortal appends the pageId for you in the pagePopupUrl property.