Class: Legion::Extensions::Agentic::Self::Fingerprint::Helpers::FingerprintEngine

Inherits:
Object
  • Object
show all
Defined in:
lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFingerprintEngine

Returns a new instance of FingerprintEngine.



12
13
14
15
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 12

def initialize
  @traits  = {}
  @samples = []
end

Instance Attribute Details

#samplesObject (readonly)

Returns the value of attribute samples.



10
11
12
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 10

def samples
  @samples
end

Instance Method Details

#anomaly_check(category:, value:) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 80

def anomaly_check(category:, value:)
  trait = @traits[category]
  return { anomaly: false, reason: :no_baseline } unless trait

  dev     = trait.deviation_from(value.clamp(0.0, 1.0))
  anomaly = dev >= Constants::DEVIATION_THRESHOLD
  {
    anomaly:   anomaly,
    category:  category,
    value:     value.clamp(0.0, 1.0),
    baseline:  trait.baseline,
    deviation: dev.round(10),
    threshold: Constants::DEVIATION_THRESHOLD
  }
end

#fingerprint_hashObject



96
97
98
99
100
101
102
103
104
105
106
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 96

def fingerprint_hash
  return nil if @traits.empty?

  profile_string = Constants::TRAIT_CATEGORIES.map do |cat|
    t = @traits[cat]
    t ? "#{cat}:#{t.baseline.round(6)}" : "#{cat}:nil"
  end.join('|')

  require 'digest'
  ::Digest::SHA256.hexdigest(profile_string)[0, 16]
end

#fingerprint_reportObject



116
117
118
119
120
121
122
123
124
125
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 116

def fingerprint_report
  {
    fingerprint_hash:    fingerprint_hash,
    identity_confidence: identity_confidence,
    identity_label:      identity_label,
    trait_count:         trait_count,
    sample_count:        @samples.size,
    traits:              @traits.transform_values(&:to_h)
  }
end

#identity_confidenceObject



63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 63

def identity_confidence
  return 0.0 if @traits.empty?

  stable_count = @traits.values.count(&:stable?)
  sampled      = @traits.values.select { |t| t.sample_count.positive? }
  return 0.0 if sampled.empty?

  coverage  = sampled.size.to_f / Constants::TRAIT_CATEGORIES.size
  stability = stable_count.to_f / @traits.size

  ((coverage * 0.6) + (stability * 0.4)).round(10).clamp(0.0, 1.0)
end

#identity_labelObject



76
77
78
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 76

def identity_label
  Constants.identity_label_for(identity_confidence)
end

#record_observation(category:, value:) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 17

def record_observation(category:, value:)
  return { status: :invalid_category, category: category } unless Constants::TRAIT_CATEGORIES.include?(category)

  trait = get_or_create_trait(category)
  trait.record_sample!(value.clamp(0.0, 1.0))

  @samples << { category: category, value: value.clamp(0.0, 1.0), recorded_at: Time.now.utc }
  @samples.shift while @samples.size > Constants::MAX_SAMPLES

  {
    status:   :recorded,
    category: category,
    baseline: trait.baseline,
    variance: trait.variance,
    samples:  trait.sample_count
  }
end

#sample_countObject



112
113
114
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 112

def sample_count
  @samples.size
end

#strongest_traits(top_n = 3) ⇒ Object



49
50
51
52
53
54
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 49

def strongest_traits(top_n = 3)
  @traits.values
         .sort_by { |t| -t.baseline }
         .first(top_n)
         .map(&:to_h)
end

#to_hObject



127
128
129
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 127

def to_h
  fingerprint_report
end

#trait_countObject



108
109
110
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 108

def trait_count
  @traits.size
end

#trait_profileObject



45
46
47
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 45

def trait_profile
  @traits.transform_values(&:baseline)
end

#verify_identity(observations:) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 35

def verify_identity(observations:)
  return { match_score: 0.0, verdict: :insufficient_data } if observations.empty? || @traits.empty?

  scored = score_observations(observations)
  return { match_score: 0.0, verdict: :insufficient_data } if scored.empty?

  score = (scored.sum / scored.size).round(10)
  { match_score: score, verdict: score_verdict(score), observations_checked: scored.size }
end

#weakest_traits(top_n = 3) ⇒ Object



56
57
58
59
60
61
# File 'lib/legion/extensions/agentic/self/fingerprint/helpers/fingerprint_engine.rb', line 56

def weakest_traits(top_n = 3)
  @traits.values
         .sort_by(&:baseline)
         .first(top_n)
         .map(&:to_h)
end