DecayWeightingSpec
Wire-friendly counterpart of DecayWeighting. The two strategies are split by field type rather than discriminated union so each decay-stat spec can statically constrain itself to the right strategy (e.g. DecayingSum only accepts HalfLife).
Wall-clock durations travel as Long milliseconds rather than kotlin.time.Duration to avoid the experimental Duration serializer and keep the wire compact.