Class: Legion::Extensions::Agentic::Social::Consent::Helpers::ConsentMap

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb

Constant Summary collapse

APPROVAL_TIMEOUT =

72 hours

259_200

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeConsentMap

Returns a new instance of ConsentMap.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 16

def initialize
  @domains = Hash.new do |h, k|
    h[k] = {
      tier:                 Tiers::DEFAULT_TIER,
      success_count:        0,
      failure_count:        0,
      total_actions:        0,
      last_changed_at:      nil,
      history:              [],
      pending_tier:         nil,
      pending_since:        nil,
      pending_requested_by: nil
    }
  end
  load_from_local
end

Instance Attribute Details

#domainsObject (readonly)

Returns the value of attribute domains.



14
15
16
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 14

def domains
  @domains
end

Instance Method Details

#clear_pending(domain) ⇒ Object



116
117
118
119
120
121
122
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 116

def clear_pending(domain)
  entry = @domains[domain]
  entry[:pending_tier] = nil
  entry[:pending_since] = nil
  entry[:pending_requested_by] = nil
  entry
end

#domain_countObject



97
98
99
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 97

def domain_count
  @domains.size
end

#eligible_for_change?(domain) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
74
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 65

def eligible_for_change?(domain)
  entry = @domains[domain]
  return false if entry[:total_actions] < Tiers::MIN_ACTIONS_TO_PROMOTE

  if entry[:last_changed_at]
    (Time.now.utc - entry[:last_changed_at]) >= Tiers::PROMOTION_COOLDOWN
  else
    true
  end
end

#evaluate_promotion(domain) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 76

def evaluate_promotion(domain)
  return :ineligible unless eligible_for_change?(domain)

  rate = success_rate(domain)
  current = get_tier(domain)

  if rate >= Tiers::PROMOTION_THRESHOLD
    promoted = Tiers.promote(current)
    return :already_max if promoted == current

    :promote
  elsif rate < Tiers::DEMOTION_THRESHOLD
    demoted = Tiers.demote(current)
    return :already_min if demoted == current

    :demote
  else
    :maintain
  end
end

#get_tier(domain) ⇒ Object



33
34
35
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 33

def get_tier(domain)
  @domains[domain][:tier]
end

#load_from_localObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 160

def load_from_local
  return unless defined?(Legion::Data::Local) && Legion::Data::Local.connected?

  Legion::Data::Local.connection[:consent_domains].each do |row|
    key = row[:domain_key]
    history = begin
      ::JSON.parse(row[:history] || '[]', symbolize_names: false).map do |h|
        { from: h['from'].to_sym, to: h['to'].to_sym, at: h['at'] }
      end
    rescue StandardError => _e
      []
    end

    @domains[key] = {
      tier:            row[:tier].to_sym,
      success_count:   row[:success_count].to_i,
      failure_count:   row[:failure_count].to_i,
      total_actions:   row[:total_actions].to_i,
      last_changed_at: row[:last_changed_at],
      history:         history
    }
  end
rescue StandardError => e
  Legion::Logging.warn "[consent] load_from_local failed: #{e.message}"
end

#pending?(domain) ⇒ Boolean

Returns:

  • (Boolean)


124
125
126
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 124

def pending?(domain)
  !@domains[domain][:pending_tier].nil?
end

#pending_expired?(domain, timeout: APPROVAL_TIMEOUT) ⇒ Boolean

Returns:

  • (Boolean)


128
129
130
131
132
133
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 128

def pending_expired?(domain, timeout: APPROVAL_TIMEOUT)
  entry = @domains[domain]
  return false unless entry[:pending_since]

  Time.now - entry[:pending_since] > timeout
end

#record_outcome(domain, success:) ⇒ Object



48
49
50
51
52
53
54
55
56
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 48

def record_outcome(domain, success:)
  entry = @domains[domain]
  entry[:total_actions] += 1
  if success
    entry[:success_count] += 1
  else
    entry[:failure_count] += 1
  end
end

#save_to_localObject



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 135

def save_to_local
  return unless defined?(Legion::Data::Local) && Legion::Data::Local.connected?

  dataset = Legion::Data::Local.connection[:consent_domains]
  @domains.each do |domain_key, entry|
    row = {
      domain_key:      domain_key,
      tier:            entry[:tier].to_s,
      success_count:   entry[:success_count],
      failure_count:   entry[:failure_count],
      total_actions:   entry[:total_actions],
      last_changed_at: entry[:last_changed_at],
      history:         ::JSON.generate(entry[:history].map { |h| h.transform_values(&:to_s) })
    }
    existing = dataset.where(domain_key: domain_key).first
    if existing
      dataset.where(domain_key: domain_key).update(row.except(:domain_key))
    else
      dataset.insert(row)
    end
  end
rescue StandardError => e
  Legion::Logging.warn "[consent] save_to_local failed: #{e.message}"
end

#set_pending(domain, proposed_tier:, requested_by: 'system') ⇒ Object



108
109
110
111
112
113
114
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 108

def set_pending(domain, proposed_tier:, requested_by: 'system')
  entry = @domains[domain]
  entry[:pending_tier] = proposed_tier
  entry[:pending_since] = Time.now
  entry[:pending_requested_by] = requested_by
  entry
end

#set_tier(domain, tier) ⇒ Object



37
38
39
40
41
42
43
44
45
46
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 37

def set_tier(domain, tier)
  return unless Tiers.valid_tier?(tier)

  entry = @domains[domain]
  old_tier = entry[:tier]
  entry[:tier] = tier
  entry[:last_changed_at] = Time.now.utc
  entry[:history] << { from: old_tier, to: tier, at: Time.now.utc }
  entry[:history].shift while entry[:history].size > 50
end

#success_rate(domain) ⇒ Object



58
59
60
61
62
63
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 58

def success_rate(domain)
  entry = @domains[domain]
  return 0.0 if entry[:total_actions].zero?

  entry[:success_count].to_f / entry[:total_actions]
end

#to_hObject



101
102
103
104
105
106
# File 'lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb', line 101

def to_h
  @domains.transform_values do |v|
    { tier: v[:tier], success_rate: success_rate_from(v), total_actions: v[:total_actions],
      pending_tier: v[:pending_tier], pending_since: v[:pending_since] }
  end
end