Oh, I think I see: ad_register_filter is supposed to only be called from *.init.tcl scripts, I guess (haven't found code to confirm this yet). Does this sound right? Then, after all all the package's init scripts have run, the nsv is scanned and the filters get registered with ns_register_filter in the proper priority order. After all, the nsv doesn't persist after restart so it would have to be populated at boot time.
In my case I was calling ad_register_filter from an after_instantiate callback, and was surprised that the filter was never registered. It did get registered (by ad_register_filter) after a restart, though, due to the fact that I am looping my app's package_ids in an *init.tcl script ...
I guess you should use the ns_ variant outside the init scripts, unless we come up with a persistent storage mechanism. But i wonder if I should still register rp_invoke_filter [list ...] instead of the filter directly ...
Hm, it looks as though some more thinking would be in order, if I can manage that on such a hot day as this.