Class: Legion::Extensions::Agentic::Defense::Bias::Helpers::BiasDetector

Inherits:
Object
  • Object
show all
Includes:
Constants
Defined in:
lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb

Constant Summary

Constants included from Constants

Constants::ANCHOR_DECAY, Constants::AVAILABILITY_RECENCY_WINDOW, Constants::BIAS_TYPES, Constants::CONFIRMATION_WEIGHT, Constants::CORRECTION_FACTOR, Constants::DECAY_RATE, Constants::DEFAULT_SUSCEPTIBILITY, Constants::DETECTION_THRESHOLD, Constants::MAX_ANCHORS, Constants::MAX_BIAS_EVENTS, Constants::SUSCEPTIBILITY_ALPHA

Instance Method Summary collapse

Constructor Details

#initializeBiasDetector

Returns a new instance of BiasDetector.



12
13
14
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 12

def initialize
  @susceptibility = Constants::BIAS_TYPES.to_h { |b| [b, Constants::DEFAULT_SUSCEPTIBILITY] }
end

Instance Method Details

#correction_for(magnitude) ⇒ Object



86
87
88
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 86

def correction_for(magnitude)
  (magnitude * Constants::CORRECTION_FACTOR).clamp(0.0, 1.0)
end

#detect_anchoring(current_value:, anchor_value:, domain: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



16
17
18
19
20
21
22
23
24
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 16

def detect_anchoring(current_value:, anchor_value:, domain: nil) # rubocop:disable Lint/UnusedMethodArgument
  return 0.0 if anchor_value.nil? || anchor_value.zero?

  distance = (current_value - anchor_value).abs.to_f / anchor_value.abs
  pull      = 1.0 - distance.clamp(0.0, 1.0)
  magnitude = pull * susceptibility_for(:anchoring)
  update_susceptibility(:anchoring, detected: magnitude >= Constants::DETECTION_THRESHOLD)
  magnitude.clamp(0.0, 1.0)
end

#detect_availability(recent_events:, domain: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



36
37
38
39
40
41
42
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 36

def detect_availability(recent_events:, domain: nil) # rubocop:disable Lint/UnusedMethodArgument
  window    = Constants::AVAILABILITY_RECENCY_WINDOW
  density   = [recent_events.size, window].min.to_f / window
  magnitude = density * susceptibility_for(:availability)
  update_susceptibility(:availability, detected: magnitude >= Constants::DETECTION_THRESHOLD)
  magnitude.clamp(0.0, 1.0)
end

#detect_confirmation(evidence_direction:, hypothesis_direction:, domain: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



26
27
28
29
30
31
32
33
34
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 26

def detect_confirmation(evidence_direction:, hypothesis_direction:, domain: nil) # rubocop:disable Lint/UnusedMethodArgument
  magnitude = if evidence_direction == hypothesis_direction
                Constants::CONFIRMATION_WEIGHT * susceptibility_for(:confirmation)
              else
                (1.0 - Constants::CONFIRMATION_WEIGHT) * susceptibility_for(:confirmation)
              end
  update_susceptibility(:confirmation, detected: magnitude >= Constants::DETECTION_THRESHOLD)
  magnitude.clamp(0.0, 1.0)
end

#detect_recency(data_points:, domain: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 44

def detect_recency(data_points:, domain: nil) # rubocop:disable Lint/UnusedMethodArgument
  return 0.0 if data_points.size < 2

  total = data_points.size
  half  = total / 2
  recent_half  = data_points.last(half)
  earlier_half = data_points.first(half)

  recent_mean  = mean(recent_half)
  earlier_mean = mean(earlier_half)

  range = (data_points.max - data_points.min).to_f
  return 0.0 if range.zero?

  skew      = (recent_mean - earlier_mean).abs / range
  magnitude = skew * susceptibility_for(:recency)
  update_susceptibility(:recency, detected: magnitude >= Constants::DETECTION_THRESHOLD)
  magnitude.clamp(0.0, 1.0)
end

#detect_sunk_cost(invested:, expected_return:, domain: nil) ⇒ Object

rubocop:disable Lint/UnusedMethodArgument



64
65
66
67
68
69
70
71
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 64

def detect_sunk_cost(invested:, expected_return:, domain: nil) # rubocop:disable Lint/UnusedMethodArgument
  return 0.0 if invested <= 0

  ratio     = invested.to_f / (invested + expected_return.abs + 1.0)
  magnitude = ratio * susceptibility_for(:sunk_cost)
  update_susceptibility(:sunk_cost, detected: magnitude >= Constants::DETECTION_THRESHOLD)
  magnitude.clamp(0.0, 1.0)
end

#susceptibility_for(bias_type) ⇒ Object



73
74
75
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 73

def susceptibility_for(bias_type)
  @susceptibility.fetch(bias_type, Constants::DEFAULT_SUSCEPTIBILITY)
end

#to_hObject



90
91
92
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 90

def to_h
  { susceptibility: @susceptibility.dup }
end

#update_susceptibility(bias_type, detected:) ⇒ Object



77
78
79
80
81
82
83
84
# File 'lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb', line 77

def update_susceptibility(bias_type, detected:)
  return unless @susceptibility.key?(bias_type)

  alpha   = Constants::SUSCEPTIBILITY_ALPHA
  signal  = detected ? 1.0 : 0.0
  current = @susceptibility[bias_type]
  @susceptibility[bias_type] = ((alpha * signal) + ((1.0 - alpha) * current)).clamp(0.0, 1.0)
end