Module: Legion::Extensions::MindGrowth::Runners::CompetitiveEvolver

Extended by:
CompetitiveEvolver
Included in:
CompetitiveEvolver
Defined in:
lib/legion/extensions/mind_growth/runners/competitive_evolver.rb

Constant Summary collapse

COMPETITION_STATUSES =
%i[pending active evaluating decided cancelled].freeze
ACTIVE_STATUSES =
%i[pending active evaluating].freeze
MIN_TRIAL_ITERATIONS =
10

Instance Method Summary collapse

Instance Method Details

#active_competitionsObject



111
112
113
114
115
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 111

def active_competitions(**)
  comps = all_competitions.select { |c| ACTIVE_STATUSES.include?(c[:status]) }
  { success: true, competitions: comps.map { |c| { id: c[:id], gap: c[:gap], status: c[:status] } },
    count: comps.size }
end

#compare_results(competition_id:) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 58

def compare_results(competition_id:, **)
  competition = get_competition(competition_id)
  return { success: false, reason: :not_found } unless competition

  trials = competition[:trials]
  return { success: true, comparison: [], leader: nil } if trials.empty?

  ranked = trials.values.sort_by { |t| [-t[:fitness], t[:avg_latency_ms]] }
  leader = ranked.first

  comparison = ranked.map.with_index(1) do |trial, rank|
    {
      extension_name: trial[:extension_name],
      fitness:        trial[:fitness],
      error_rate:     trial[:error_rate],
      avg_latency_ms: trial[:avg_latency_ms],
      rank:           rank
    }
  end

  { success: true, comparison: comparison, leader: leader[:extension_name] }
end

#competition_history(limit: 20) ⇒ Object



117
118
119
120
121
122
123
124
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 117

def competition_history(limit: 20, **)
  comps = all_competitions.sort_by { |c| c[:created_at] }.reverse.first(limit)
  entries = comps.map do |c|
    { id: c[:id], gap: c[:gap], status: c[:status], winner: c[:winner],
      competitors: c[:proposal_ids].size, trial_count: c[:trials].size }
  end
  { success: true, competitions: entries, count: entries.size }
end

#competition_status(competition_id:) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 102

def competition_status(competition_id:, **)
  competition = get_competition(competition_id)
  return { success: false, reason: :not_found } unless competition

  { success: true, id: competition[:id], gap: competition[:gap],
    status: competition[:status], competitors: competition[:proposal_ids],
    trial_count: competition[:trials].size, winner: competition[:winner] }
end

#create_competition(gap:, proposal_ids:) ⇒ Object



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 14

def create_competition(gap:, proposal_ids:, **)
  ids = Array(proposal_ids)
  return { success: false, reason: :insufficient_competitors } if ids.size < 2

  competition_id = SecureRandom.uuid
  competition = {
    id:           competition_id,
    gap:          gap.to_s,
    proposal_ids: ids,
    status:       :pending,
    trials:       {},
    winner:       nil,
    created_at:   Time.now.utc,
    decided_at:   nil
  }

  store_competition(competition)
  { success: true, competition_id: competition_id, gap: gap.to_s, competitors: ids.size }
end

#declare_winner(competition_id:) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 81

def declare_winner(competition_id:, **)
  competition = get_competition(competition_id)
  return { success: false, reason: :not_found } unless competition
  return { success: false, reason: :already_decided } if competition[:status] == :decided
  return { success: false, reason: :no_trials } if competition[:trials].empty?

  comparison = compare_results(competition_id: competition_id)
  winner_name = comparison[:leader]

  losers = competition[:trials].keys.reject { |name| name == winner_name }

  losers.each do |loser_name|
    Runners::Evolver.replace_extension(old_name: loser_name, new_proposal_id: "winner:#{winner_name}")
  end

  transition_competition(competition_id, :decided)
  set_winner(competition_id, winner_name)

  { success: true, winner: winner_name, losers: losers, competition_id: competition_id }
end

#run_trial(competition_id:, extension:, iterations: MIN_TRIAL_ITERATIONS) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/legion/extensions/mind_growth/runners/competitive_evolver.rb', line 34

def run_trial(competition_id:, extension:, iterations: MIN_TRIAL_ITERATIONS, **)
  competition = get_competition(competition_id)
  return { success: false, reason: :not_found } unless competition
  return { success: false, reason: :already_decided } if competition[:status] == :decided

  transition_competition(competition_id, :active) if competition[:status] == :pending

  fitness = Helpers::FitnessEvaluator.fitness(extension)
  name = extension[:name] || extension[:extension_name]

  trial = {
    extension_name: name,
    fitness:        fitness,
    error_rate:     extension[:error_rate] || 0.0,
    avg_latency_ms: extension[:avg_latency_ms] || 0,
    invocations:    extension[:invocation_count] || 0,
    iterations:     iterations,
    recorded_at:    Time.now.utc
  }

  record_trial(competition_id, name, trial)
  { success: true, competition_id: competition_id, trial: trial }
end