!str #16069 disallows using one Keyed sink/source ambiguously (many times)

This can / should wait for Patrik's move-all-the-things PR.
Refs #16069 
ok, just one more question, what was the asymmetry? should it have been?

    final override def equals(other: Any): Boolean = other match {
      case s: SourceVertex => (source, s.source) match {
        case (k1: KeyedSource[_], k2: KeyedSource[_]) => k1 == k2
        case _                                        => super.equals(other)
      }
      case _ => false
    }

hashCode must of course be implemented in similar way