The GitHub Actions job "CI" on grails-core.git/fix/dirty-checking-collection-tracking-8.0.x has succeeded. Run started by GitHub user codeconsole (triggered by codeconsole).
Head commit for run: f11e85549baad054bd6b7be59777578602ad40ba / Scott Murphy Heiberg <[email protected]> Re-bind a collection borrowed from another entity to the entity it is assigned to rewrap early-returned any value that was already a DirtyCheckableCollection, so 'a.shares = b.shares' stored B's wrapper on A. Its parent still pointed at B, so 'a.shares.add(x)' marked B dirty and left A clean, and the value kept assigned=false, so a persister diffed a wholesale replacement element by element. The worst shape is silent: when the two collections are equal in content the assignment is equality-suppressed, so A is never flagged at all, the save finds only lastUpdated to write, and the addition is lost while B absorbs it. That is what the new Mongo spec pins. A wrapper from another entity is now re-bound - its raw target re-wrapped against this parent, with assigned=true. Three things this must not do, each covered by a spec: - replace a store-specific wrapper (Neo4jList and friends) or a PersistentCollection with a generic one, which would reintroduce the Neo4j relationship-delete regression: those fail the exact-class check and are returned untouched; - mistake another entity's wrapper for this property's own when the two entities are equal by business key: the owner is compared by identity, never equals, which on an association can initialise a proxy; - re-bind onto an inner wrapper when an encoder has left one nested inside another, which would mark both entities dirty on every mutation. The re-binding runs whatever the property held before, including null - 'new Entity(shares: other.shares)' has the same defect and does not self-heal on insert, because the write-back assigns the field directly and never reaches this method. Tracking is still never introduced for a plain collection replacing an untracked value. Docs: describe the re-binding, and scope it to the properties GORM actually wraps. A one-to-many is held in a PersistentCollection, so the previous hasMany example was a case this does not cover. Report URL: https://github.com/apache/grails-core/actions/runs/34456754281 With regards, GitHub Actions via GitBox
