stability.go raw

   1  package oracle
   2  
   3  import "git.mleku.dev/mleku/dendrite/pkg/ewma"
   4  
   5  // StabilityMonitor wraps the EWMA oscillation detector for oracle triggering.
   6  // When the bond rate of the current learning source oscillates (the organism
   7  // is no longer absorbing new structure), the monitor fires and the oracle
   8  // should cast a new reading.
   9  type StabilityMonitor struct {
  10  	// Detector is the EWMA oscillation detector.
  11  	Detector *ewma.OscillationDetector
  12  
  13  	// LastSignalGen records when the most recent stability signal fired.
  14  	LastSignalGen uint32
  15  }
  16  
  17  // NewStabilityMonitor creates a monitor. ewmaWindow is the smoothing window
  18  // size for the EWMA (typical: 5-10). threshold is the reversal count needed
  19  // to declare oscillation (typical: 3 = ~1.5 full cycles).
  20  func NewStabilityMonitor(ewmaWindow, threshold int) *StabilityMonitor {
  21  	return &StabilityMonitor{
  22  		Detector: ewma.NewDetector(ewmaWindow, 0, threshold),
  23  	}
  24  }
  25  
  26  // Observe feeds a (fetched, bonded) pair from the current data source
  27  // into the EWMA. Returns true if the current reading has been absorbed
  28  // (the bond rate is oscillating = no more new structure being absorbed).
  29  //
  30  // After returning true, the caller should mark the oracle's current reading
  31  // as absorbed and cast a new one. The detector is reset automatically.
  32  func (sm *StabilityMonitor) Observe(fetched, bonded int64, gen uint32) bool {
  33  	oscillating := sm.Detector.Observe(fetched, bonded)
  34  	if oscillating {
  35  		sm.LastSignalGen = gen
  36  		sm.Detector.Reset()
  37  		return true
  38  	}
  39  	return false
  40  }
  41