package oracle import "git.mleku.dev/mleku/dendrite/pkg/ewma" // StabilityMonitor wraps the EWMA oscillation detector for oracle triggering. // When the bond rate of the current learning source oscillates (the organism // is no longer absorbing new structure), the monitor fires and the oracle // should cast a new reading. type StabilityMonitor struct { // Detector is the EWMA oscillation detector. Detector *ewma.OscillationDetector // LastSignalGen records when the most recent stability signal fired. LastSignalGen uint32 } // NewStabilityMonitor creates a monitor. ewmaWindow is the smoothing window // size for the EWMA (typical: 5-10). threshold is the reversal count needed // to declare oscillation (typical: 3 = ~1.5 full cycles). func NewStabilityMonitor(ewmaWindow, threshold int) *StabilityMonitor { return &StabilityMonitor{ Detector: ewma.NewDetector(ewmaWindow, 0, threshold), } } // Observe feeds a (fetched, bonded) pair from the current data source // into the EWMA. Returns true if the current reading has been absorbed // (the bond rate is oscillating = no more new structure being absorbed). // // After returning true, the caller should mark the oracle's current reading // as absorbed and cast a new one. The detector is reset automatically. func (sm *StabilityMonitor) Observe(fetched, bonded int64, gen uint32) bool { oscillating := sm.Detector.Observe(fetched, bonded) if oscillating { sm.LastSignalGen = gen sm.Detector.Reset() return true } return false }