package runner import ( "sort" "sync" "time" ) // ValidatorTiming records domain validator work without treating a scheduler // permit or provider attempt as a logical LLM call. type ValidatorTiming struct { ModuleKey string `json:"module_key"` ModuleInstance string `json:"module_instance"` ValidatorName string `json:"validator_name"` LLMBacked bool `json:"llm_backed"` Calls int `json:"calls"` ElapsedMS int64 `json:"elapsed_ms"` } type validatorTimingCollector struct { mu sync.Mutex byKey map[string]*ValidatorTiming } func newValidatorTimingCollector() *validatorTimingCollector { return &validatorTimingCollector{byKey: make(map[string]*ValidatorTiming)} } func (c *validatorTimingCollector) record(moduleKey, moduleInstance, validatorName string, llmBacked bool, elapsed time.Duration) { c.mu.Lock() defer c.mu.Unlock() key := moduleInstance + "\x00" + validatorName timing := c.byKey[key] if timing == nil { timing = &ValidatorTiming{ModuleKey: moduleKey, ModuleInstance: moduleInstance, ValidatorName: validatorName, LLMBacked: llmBacked} c.byKey[key] = timing } timing.Calls++ timing.ElapsedMS += elapsed.Milliseconds() } func (c *validatorTimingCollector) snapshot() []ValidatorTiming { c.mu.Lock() defer c.mu.Unlock() result := make([]ValidatorTiming, 0, len(c.byKey)) for _, timing := range c.byKey { result = append(result, *timing) } sort.Slice(result, func(i, j int) bool { if result[i].ModuleInstance != result[j].ModuleInstance { return result[i].ModuleInstance < result[j].ModuleInstance } return result[i].ValidatorName < result[j].ValidatorName }) return result }