All the constraints. ;)
As you mentioned, there are tricky two-way mathematical constraints, like Sutherland's Sketchpad  and descendants , and Gosling's PhD Thesis , where the system understands the constraint expressions mathematically and transforms them algebraically.
 Ivan Sutherland's Sketchpad:
 Geometer's Sketchpad:
 Algebraic Constraints; James Gosling; CMU CS Department PhD Thesis:
And there are simpler one-way data flow constraints like Apple's KVO notification , Garnet's KR based constraints , and OpenLaszlo's event/delegate based constraints .
 Introduction to Key-Value Observing Programming Guide:
 KR: Constraint-Based Knowledge Representation:
 Oliver Steel: Instance-First Development:
As you pointed out, KVO constraints simply say that object.x = otherObject.y, so there's not much to them.
I think one thing holding back constraint programming is that they require an interpreter or compiler to understand them, or the programmer to write code in a constrained syntax.
Garnet's KR constraints are written as Lisp expressions implemented by Lisp macros, that parse the expressions and recognize certain expressions like "gvl" for "get value", and named path expressions. KR wires up the dependency graph based on that information, and marks the constraint as invalid if any of the links along the dependency path change, as well as when any of the final values the expressions reference change. But it doesn't understand the mathematical expressions themselves. At the time I was working on it, it didn't know hot to figure out which branches of conditional expressions mattered, so it would assume it depended on everything in the expression. (i.e. like the C expression "size = window.landscape ? parent.width : parent.height" -- if window.landscape is true, it depends on parent.width, else it depends on parent.height, but ). It only recalculates the constraint values lazily when you read them. ("pull" constraints).
OpenLaszlo constraints used a "push" model of propagating all dependent changes forward when you called "setValue", because that was the best trade-off at the time for speed and usability and how it was intended to be used. But with getters and setters you could implement a more convenient constraint system that didn't put so many constraints on the programmer and how you use them.