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