Clauses were flawed in a way that they are very hard to formalise forward compatibly. For example, assume a jOOQ version where GROUP BY only supported simple grouping sets. So GROUP BY would immediately contain fields. But then, suddenly, it would start supporting GROUPING SETS, which can be nested. This would require new clauses, probably? But how to communicate this to client code?
With QueryPart only checks, you can't really know "where you are" within a query. E.g. when you're visiting a Condition from within a Select, is it a WHERE, HAVING, QUALIFY condition?
So, with Clause being deprecated, the goal was to move towards the new experimental model API. You won't wait until you reach a Condition within a Select to make transformations. Instead, you transform the Select itself, depending on its Condition. It's only at the level of the Select object where you have complete information allowing to decide what to do. If you're waiting for the Condition visit event, then you'd need some stack maintenance to "remember" what the Select was, and that's way more complicated.
The blog post I've linked to is complicated as well. It is "clause aware", i.e. it tries to remember whether WHERE has already been rendered. That's because the VisitListener is triggered during the rendering of your SQL query. It would be much simpler to just transform the Select object itself (which you can do from within a VisitListener, btw).
This is why I said a combination of both VisitListener and replacement API will offer the simplest solution.