Your use of association_proxy seems odd to me. That plugin is normally used to "cut out" the middleman when using a join with an association pattern and avoid a hop/remount a relationship from one object onto another.
With my understanding and use of that plugin, you're basically setting the following shortcut, and most other behaviors are a side-effect.
Reservation.packages == Reservation._packages_rel.package
Since ReservationPackage has a primary key on `id`, it should be able to handle non-unique combinations.
These 2 both jumps out to me as potential problems :
ReservationPackage-
package - there is no backref or back-populates.
package - should this have a uselist=False setting?
__init__ - this handles the package, but not the reservation ?
Reservation-
package_rel - no backref or back-populates
In my experience, the bulk of problems with 'collections' have happened because of incomplete or improper relationships. I'd try setting up everything with fully declared relationships (ie, back_populates) and see how that affects the design of your relations and how the code runs.
You can pretty much expect the collections to not work properly unless you have backref/back-populates declared. That's the biggest issue and warning sign to me -- sqlalchemy only knows half of your relationship info.