Collector Run Context
data class CollectorRunContext(val runId: String, val contextId: <Error class: unknown class>, val dryRun: Boolean = false, val clock: Clock = Clock.systemUTC())
Everything one run of the multi-signal collector needs beyond the candidate propositions themselves: a run id to tag its trace rows with, which context it's sweeping, whether it should hold off on anything that isn't read-only, and a clock so tests can pin "now".
A runner builds this once per sweep; tests can build one directly to exercise the strategy without a runner at all.