Okay, it works as long as we do not trigger constraints... let's try that next ;-)
Nah, not quite there yet: the constraint gets correctly activated, but
the method of finding a constraint acceleration that exactly cancels
out (in the linerization) the current violation and its velocity ends
up injecting accelerations everywhere. Seems like I forget to multiply
with a Jacobian somewhere?
Not quite there yet. But noticed that the method for anticipating
constraint violations may need to be more involved and happen inside
the Constraint subclass. For now, will just try switching back to the
soft/hard joint limit approach I tried originally (detecting at soft
and holding at hart, instead of the other way around).
Aha, no: the problem stems from injecting constraints as accelerations
only, that ends up leaving a velocity spike in the state, which then
carries the constraint avoidance too far back in the next step,
allowing the objectives to pull back into the constraint. Duh, that
should have been obvious.
Alright, slowly approaching sanity here. Constraint satisfaction is
now done in velocity space, where it belongs. The trick was to use two
separate velocities: one needed to bring constraints into range, the
other one to re-seed the model velocity with something that is zero
along the constraint direction.

But now the problem is (again?) that the primary teask does not get
fulfilled even if it is feasible after taking the constraints into
account. I guess we'd need to re-project based on the original
objective hierarchy (as was my initial hunch, ah well).