The bridge is honest — many-to-many is the business fact — the trap is grain amnesia on the far side of the walk. After karts→bookings, the grain is the relationship (kart × group), so kart-grain columns like fee appear once per booking. No data is dirty and no join is wrong; the multiplication is structural, so only computing each metric at its own grain fixes it.
SELECT SUM(k.fee) AS value FROM karts k JOIN bookings b ON b.kart = k.kart ;
SELECT SUM(k.fee) AS value FROM karts k WHERE EXISTS ( SELECT 1 FROM bookings b WHERE b.kart = k.kart );
The fleet value read 30 for karts worth 20 — joining through the bookings bridge made the grain kart×group, so each kart's fee counted once per booking.
Pre-aggregate the bridge to the entity's grain; EXISTS for has-any-booking questions; a grain sentence before any SUM through a bridge.