Is the orElse(sparseVal) here okay?  It seems to go against the spirit of a Semigroup not knowing of any zero value (the monoid also doesn't assume that the sparseVal is zero).

What about:

newV = buffer.get(idx).map(oldV => SemiGroup.plus(oldV, v)).getOrElse(v)