There’s nothing wrong with using a pm.Potential if it achieves your goal. It’s a simple way to add an arbitrary logp term to a model. The reason you may want to use a RandomVariable (or the helper wrapper DensityDist) instead of a Potential is if you want to do prior/posterior predictive or represent said RandomVariable nicely in a model graph.
Scan is the way to represent arbitrary looping in PyMC, and there’s nothing wrong with that either. Sometimes you can cook up a vectorized version that does not require looping, but that’s a separate matter.
I think all timeseries in PyMC are implemented in a centered parametrization. That is, if they were unobserved, the sampler would have to propose absolute values and not relative / innovation values. Most of the times, the timeseries variables are observed, so this is not a concern. There is an issue for addressing this for RandomWalk (which do use a vectorization trick to avoid scanning btw): Implement DiffTransform for RandomWalk distributions · Issue #6098 · pymc-devs/pymc · GitHub