One last point that might help a reader -- while the difference between $q->param() and $q->url_param() turned out to be interesting, I think the real issue with the CGI scoping came from the web server itself. I had
<Directory /var/www/html/id/bin>
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options +ExecCGI
</Directory>
and that doesn't seem to like subroutines well. Switching to
<Directory /var/www/html/id/bin>
SetHandler perl-script
PerlResponseHandler ModPerl::PerlRun
PerlOptions +ParseHeaders
Options +ExecCGI
</Directory>
and I haven't seen the problem since.