Dirty checking is one of the genuinely nice things a traditional ORM does for you: it writes only the columns that changed. The usual objection to value-based ORMs is that you lose it. You do not.
Hibernate has two ways to know what changed. It can snapshot every managed entity when it loads, and at flush time diff the current state against the snapshot to build the UPDATE. Or it can enhance your bytecode so that setters record which fields were touched. Both are clever, and both are the reason the session has to own your objects: the change tracking is a property of the managed lifecycle, not of the data. That ownership is exactly what gives you detached-state bugs and proxies that outlive their session.
ST/ORM detects changes the obvious way. Inside a transaction, it compares the entity you read with the entity you write, and it issues an UPDATE for only the columns that differ. That is the whole mechanism. No proxy, no bytecode enhancement, no snapshot held by a session, because the two values are all it needs. You read a User, you produce an updated copy, you save it, and ST/ORM writes the delta.
Because entities are immutable, producing an updated copy is the natural way to change one anyway, and the before and the after are two distinct values, which is precisely what a diff wants. Immutability pays off twice here. If you save the very same value you read, it is the same object, so reference identity settles the question before a single field is compared: nothing changed, and nothing is written. And when there is a change to inspect, ST/ORM reads the fields through the generated metamodel rather than by reflection, so the comparison is direct, generated access with no runtime lookup in the path.
The benefit is the same, minimal updates, but the cost structure is completely different. Change detection is now a function of two values rather than a lifecycle you have to keep an entity inside of. The entity outside a transaction is just data. Nothing is tracking it, nothing will flush it, and it cannot go stale in the way a managed object can. You get the ergonomic win of dirty checking without buying the session coupling that usually comes attached to it.
This is the pattern for the whole framework in miniature: keep the useful behavior, drop the hidden state that traditionally paid for it.