lex-mind-growth 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -0
  3. data/lib/legion/extensions/mind_growth/actors/growth_cycle.rb +3 -3
  4. data/lib/legion/extensions/mind_growth/helpers/composition_map.rb +4 -4
  5. data/lib/legion/extensions/mind_growth/helpers/concept_proposal.rb +1 -1
  6. data/lib/legion/extensions/mind_growth/helpers/phase_allocator.rb +1 -1
  7. data/lib/legion/extensions/mind_growth/runners/builder.rb +64 -22
  8. data/lib/legion/extensions/mind_growth/runners/competitive_evolver.rb +3 -2
  9. data/lib/legion/extensions/mind_growth/runners/composer.rb +3 -3
  10. data/lib/legion/extensions/mind_growth/runners/consensus_builder.rb +4 -3
  11. data/lib/legion/extensions/mind_growth/runners/dashboard.rb +2 -2
  12. data/lib/legion/extensions/mind_growth/runners/dream_ideation.rb +2 -2
  13. data/lib/legion/extensions/mind_growth/runners/evolver.rb +15 -8
  14. data/lib/legion/extensions/mind_growth/runners/governance.rb +2 -2
  15. data/lib/legion/extensions/mind_growth/runners/integration_tester.rb +4 -3
  16. data/lib/legion/extensions/mind_growth/runners/monitor.rb +2 -2
  17. data/lib/legion/extensions/mind_growth/runners/orchestrator.rb +2 -2
  18. data/lib/legion/extensions/mind_growth/runners/proposer.rb +25 -11
  19. data/lib/legion/extensions/mind_growth/runners/retrospective.rb +12 -7
  20. data/lib/legion/extensions/mind_growth/runners/risk_assessor.rb +2 -2
  21. data/lib/legion/extensions/mind_growth/runners/swarm_builder.rb +1 -1
  22. data/lib/legion/extensions/mind_growth/runners/wirer.rb +2 -2
  23. data/lib/legion/extensions/mind_growth/version.rb +1 -1
  24. data/lib/legion/extensions/mind_growth.rb +1 -1
  25. data/spec/legion/extensions/mind_growth/actors/growth_cycle_spec.rb +2 -2
  26. data/spec/legion/extensions/mind_growth/helpers/composition_map_spec.rb +1 -1
  27. data/spec/legion/extensions/mind_growth/helpers/proposal_store_spec.rb +2 -2
  28. data/spec/legion/extensions/mind_growth/runners/competitive_evolver_spec.rb +1 -1
  29. data/spec/legion/extensions/mind_growth/runners/governance_spec.rb +1 -1
  30. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ee2be00d683bb637298c7cd47ade31afe6164e69d00d032577ede07a85e23c7
4
- data.tar.gz: aa60548111e18409e2cf09476e8e37cfa9bd4eb8912a57e174b41d6c1e80bfb0
3
+ metadata.gz: e8f21cd00a0fb432c27fd057addf7294b2d84425c7927d6298bab0c87496d868
4
+ data.tar.gz: c0a512a778e049b13d5442ab3f72bf513ce5104bc0be3632891eda965b1fa668
5
5
  SHA512:
6
- metadata.gz: 3f82c6da963f5ff2eea9a603e0b1c509ac643ebac93039bff7855cb3c673f927153e664412dc1ecf97bed571102793ecd3ac0859f58c55ce159e596ca82cb532
7
- data.tar.gz: 2c8517423557a7e7c77c2c76b2ac8adbdddb08e3570d1eb430ba25b479b7da664d39af19f6f7800e2200f33af53d475b25c44a5bfb35ff93ab44631e613507f5
6
+ metadata.gz: f772d447b870acf41484209df88a82352e4b27b00a7f30335dfb0b5fee1e26c6cc7b06d6194aaf46d2d7506e55cb7e5d264aa9b005872db00c632f3caea1a4bf
7
+ data.tar.gz: d4aee3639b1cec1a35015c9a432cb7041715bd3f3ad0571534a9d441ce11e79481a6361e72295076fb06605cc2afd357805e385ff04bf28503302c7f003bcbd5
data/Gemfile CHANGED
@@ -8,6 +8,7 @@ group :test do
8
8
  gem 'rspec', '~> 3.13'
9
9
  gem 'rspec_junit_formatter'
10
10
  gem 'rubocop', '~> 1.75'
11
+ gem 'rubocop-legion', '~> 0.1.7'
11
12
  gem 'rubocop-rspec'
12
13
  gem 'simplecov'
13
14
  end
@@ -6,7 +6,7 @@ module Legion
6
6
  module Extensions
7
7
  module MindGrowth
8
8
  module Actor
9
- class GrowthCycle < Legion::Extensions::Actors::Every
9
+ class GrowthCycle < Legion::Extensions::Actors::Every # rubocop:disable Legion/Extension/EveryActorRequiresTime
10
10
  def runner_class
11
11
  Legion::Extensions::MindGrowth::Runners::Orchestrator
12
12
  end
@@ -19,7 +19,7 @@ module Legion
19
19
  3600
20
20
  end
21
21
 
22
- def enabled?
22
+ def enabled? # rubocop:disable Legion/Extension/ActorEnabledSideEffects
23
23
  codegen_loaded? || exec_loaded?
24
24
  end
25
25
 
@@ -32,7 +32,7 @@ module Legion
32
32
  end
33
33
 
34
34
  def check_subtask?
35
- false
35
+ true
36
36
  end
37
37
 
38
38
  def generate_task?
@@ -7,7 +7,7 @@ module Legion
7
7
  module CompositionMap
8
8
  module_function
9
9
 
10
- @rules = {}
10
+ @rules = {} # rubocop:disable ThreadSafety/MutableClassInstanceVariable
11
11
  @mutex = Mutex.new
12
12
 
13
13
  def add_rule(source_extension:, output_key:, target_extension:, target_method:, transform: nil, **)
@@ -19,7 +19,7 @@ module Legion
19
19
  target_extension: target_extension.to_s,
20
20
  target_method: target_method.to_sym,
21
21
  transform: transform
22
- }
22
+ }.freeze
23
23
  @mutex.synchronize { @rules[rule_id] = rule }
24
24
  { success: true, rule_id: rule_id }
25
25
  end
@@ -31,7 +31,7 @@ module Legion
31
31
 
32
32
  def rules_for(source_extension:, **)
33
33
  src = source_extension.to_s
34
- @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
34
+ @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src }.map(&:dup) }
35
35
  end
36
36
 
37
37
  def all_rules
@@ -41,7 +41,7 @@ module Legion
41
41
  def match_output(source_extension:, output:, **)
42
42
  src = source_extension.to_s
43
43
  out_h = output.is_a?(Hash) ? output : {}
44
- rules = @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src } }
44
+ rules = @mutex.synchronize { @rules.values.select { |r| r[:source_extension] == src }.map(&:dup) }
45
45
 
46
46
  rules.filter_map do |rule|
47
47
  key = rule[:output_key]
@@ -12,7 +12,7 @@ module Legion
12
12
 
13
13
  attr_reader(*FIELDS)
14
14
 
15
- def initialize(name:, module_name:, category:, description:, metaphor: nil, helpers: [],
15
+ def initialize(name:, module_name:, category:, description:, metaphor: nil, helpers: [], # rubocop:disable Metrics/ParameterLists
16
16
  runner_methods: [], rationale: nil, origin: :proposer)
17
17
  @id = SecureRandom.uuid
18
18
  @name = name
@@ -89,7 +89,7 @@ module Legion
89
89
  end
90
90
 
91
91
  def valid_phase?(phase)
92
- CATEGORY_PHASE_MAP.values.include?(phase) || DREAM_PHASE_MAP.values.include?(phase)
92
+ CATEGORY_PHASE_MAP.value?(phase) || DREAM_PHASE_MAP.value?(phase)
93
93
  end
94
94
 
95
95
  def phases_for_category(category)
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Builder
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -59,13 +59,21 @@ module Legion
59
59
  end
60
60
 
61
61
  def strip_lex_prefix(name)
62
- name.to_s.sub(/\Alex-/, '')
62
+ name.to_s.delete_prefix('lex-')
63
+ end
64
+
65
+ def proposal_id_for(proposal)
66
+ proposal.id if proposal.respond_to?(:id)
63
67
  end
64
68
 
65
69
  # --- Scaffold Stage ---
66
70
  # Delegates to lex-codegen when loaded; stubs otherwise
67
71
  def scaffold_stage(proposal, base_path)
68
- return { success: true, stage: :scaffold, files: 0, message: 'scaffold requires lex-codegen' } unless codegen_available?
72
+ unless codegen_available?
73
+ return { success: true, stage: :scaffold, files: 0, message: 'scaffold requires lex-codegen',
74
+ proposal_id: proposal_id_for(proposal),
75
+ path: ext_path(proposal, base_path) }
76
+ end
69
77
 
70
78
  name = strip_lex_prefix(proposal.name)
71
79
  result = Legion::Extensions::Codegen::Runners::Generate.scaffold_extension(
@@ -79,14 +87,18 @@ module Legion
79
87
  )
80
88
 
81
89
  { success: result[:success], stage: :scaffold, files: result[:files_created] || 0,
82
- path: result[:path], error: result[:error] }
90
+ path: result[:path] || ext_path(proposal, base_path), error: result[:error],
91
+ proposal_id: proposal_id_for(proposal) }
83
92
  end
84
93
 
85
94
  # --- Implement Stage ---
86
95
  # Delegates to lex-codegen FromGap when loaded; falls back to legion-llm; stubs otherwise
87
96
  def implement_stage(proposal, base_path)
88
97
  unless llm_available? || codegen_from_gap_available?
89
- return { success: true, stage: :implement, message: 'implementation requires legion-llm or lex-codegen' }
98
+ return { success: true, stage: :implement,
99
+ message: 'implementation requires legion-llm or lex-codegen',
100
+ proposal_id: proposal_id_for(proposal),
101
+ path: ext_path(proposal, base_path) }
90
102
  end
91
103
 
92
104
  path = ext_path(proposal, base_path)
@@ -94,7 +106,9 @@ module Legion
94
106
 
95
107
  if target_files.empty?
96
108
  return { success: true, stage: :implement, files_implemented: 0,
97
- message: 'no implementation targets found' }
109
+ message: 'no implementation targets found',
110
+ proposal_id: proposal_id_for(proposal),
111
+ path: path }
98
112
  end
99
113
 
100
114
  files_implemented = 0
@@ -111,43 +125,64 @@ module Legion
111
125
 
112
126
  success = errors.empty?
113
127
  { success: success, stage: :implement, files_implemented: files_implemented,
114
- total_files: target_files.size, error: success ? nil : errors.join('; ') }
128
+ total_files: target_files.size, error: success ? nil : errors.join('; '),
129
+ proposal_id: proposal_id_for(proposal),
130
+ path: path }
115
131
  end
116
132
 
117
133
  # --- Test Stage ---
118
134
  # Delegates to lex-exec bundler runners when loaded; stubs otherwise
119
135
  def test_stage(proposal, base_path)
120
- return { success: true, stage: :test, message: 'testing requires lex-exec' } unless exec_available?
121
-
122
- path = ext_path(proposal, base_path)
136
+ unless exec_available?
137
+ return { success: true, stage: :test, message: 'testing requires lex-exec',
138
+ proposal_id: proposal_id_for(proposal),
139
+ path: ext_path(proposal, base_path) }
140
+ end
123
141
 
142
+ path = ext_path(proposal, base_path)
143
+ pid = proposal_id_for(proposal)
124
144
  install = Legion::Extensions::Exec::Runners::Bundler.install(path: path)
125
145
  unless install[:success]
126
146
  return { success: false, stage: :test, step: :install,
127
- error: install[:stderr] || install[:error] }
147
+ error: install[:stderr] || install[:error],
148
+ proposal_id: pid, path: path }
128
149
  end
129
150
 
151
+ run_test_suite(path: path, pid: pid)
152
+ end
153
+
154
+ def run_test_suite(path:, pid:)
130
155
  rspec = Legion::Extensions::Exec::Runners::Bundler.exec_rspec(path: path)
131
156
  rubocop = Legion::Extensions::Exec::Runners::Bundler.exec_rubocop(path: path)
132
157
 
133
158
  rspec_ok = rspec[:success] && (rspec.dig(:parsed, :failures) || 0).zero?
134
159
  rubocop_ok = rubocop[:success]
135
160
 
136
- errors = [
137
- (rspec_ok ? nil : "rspec: #{rspec[:parsed] || rspec[:stderr]}"),
138
- (rubocop_ok ? nil : "rubocop: #{rubocop[:parsed] || rubocop[:stderr]}")
139
- ].compact.join('; ')
161
+ errors = build_test_errors(rspec: rspec, rubocop: rubocop, rspec_ok: rspec_ok, rubocop_ok: rubocop_ok)
140
162
 
141
163
  { success: rspec_ok && rubocop_ok, stage: :test,
142
164
  rspec: rspec[:parsed] || { raw: rspec[:stdout] },
143
165
  rubocop: rubocop[:parsed] || { raw: rubocop[:stdout] },
144
- error: errors.empty? ? nil : errors }
166
+ error: errors.empty? ? nil : errors,
167
+ proposal_id: pid,
168
+ path: path }
169
+ end
170
+
171
+ def build_test_errors(rspec:, rubocop:, rspec_ok:, rubocop_ok:)
172
+ [
173
+ (rspec_ok ? nil : "rspec: #{rspec[:parsed] || rspec[:stderr]}"),
174
+ (rubocop_ok ? nil : "rubocop: #{rubocop[:parsed] || rubocop[:stderr]}")
175
+ ].compact.join('; ')
145
176
  end
146
177
 
147
178
  # --- Validate Stage ---
148
179
  # Delegates to lex-codegen validators when loaded; stubs otherwise
149
180
  def validate_stage(proposal, base_path)
150
- return { success: true, stage: :validate, message: 'validation requires lex-codegen' } unless codegen_available?
181
+ unless codegen_available?
182
+ return { success: true, stage: :validate, message: 'validation requires lex-codegen',
183
+ proposal_id: proposal_id_for(proposal),
184
+ path: ext_path(proposal, base_path) }
185
+ end
151
186
 
152
187
  path = ext_path(proposal, base_path)
153
188
  structure = Legion::Extensions::Codegen::Runners::Validate.validate_structure(path: path)
@@ -155,13 +190,19 @@ module Legion
155
190
 
156
191
  valid = structure[:valid] && gemspec[:valid]
157
192
  { success: valid, stage: :validate, structure: structure, gemspec: gemspec,
158
- error: valid ? nil : "structure: #{structure[:missing]}, gemspec: #{gemspec[:issues]}" }
193
+ error: valid ? nil : "structure: #{structure[:missing]}, gemspec: #{gemspec[:issues]}",
194
+ proposal_id: proposal_id_for(proposal),
195
+ path: path }
159
196
  end
160
197
 
161
198
  # --- Register Stage ---
162
199
  # Delegates to lex-metacognition registry when loaded; stubs otherwise
163
200
  def register_stage(proposal)
164
- return { success: true, stage: :register, message: 'registration requires lex-metacognition registry' } unless registry_available?
201
+ unless registry_available?
202
+ return { success: true, stage: :register,
203
+ message: 'registration requires lex-metacognition registry',
204
+ proposal_id: proposal_id_for(proposal) }
205
+ end
165
206
 
166
207
  result = Legion::Extensions::Metacognition::Runners::Registry.register_extension(
167
208
  name: proposal.name,
@@ -170,7 +211,8 @@ module Legion
170
211
  description: proposal.description
171
212
  )
172
213
 
173
- { success: result[:success], stage: :register, error: result[:error] }
214
+ { success: result[:success], stage: :register, error: result[:error],
215
+ proposal_id: proposal_id_for(proposal) }
174
216
  end
175
217
 
176
218
  # --- LLM implementation helpers ---
@@ -205,7 +247,7 @@ module Legion
205
247
  def legacy_implement_file(file_path, proposal)
206
248
  stub_content = ::File.read(file_path)
207
249
 
208
- chat = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'build' }, intent: { capability: :reasoning })
250
+ chat = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'build' }, intent: { capability: :reasoning }) # rubocop:disable Legion/HelperMigration/DirectLlm
209
251
  chat.with_instructions(implementation_instructions)
210
252
  response = chat.ask(file_implementation_prompt(stub_content, proposal))
211
253
  code = extract_ruby_code(response.content)
@@ -7,7 +7,8 @@ module Legion
7
7
  module CompetitiveEvolver
8
8
  extend self
9
9
 
10
- COMPETITION_STATUSES = %i[pending active evaluating decided cancelled].freeze
10
+ COMPETITION_STATUSES = %i[pending active evaluating decided cancelled].freeze
11
+ ACTIVE_STATUSES = %i[pending active evaluating].freeze
11
12
  MIN_TRIAL_ITERATIONS = 10
12
13
 
13
14
  def create_competition(gap:, proposal_ids:, **)
@@ -108,7 +109,7 @@ module Legion
108
109
  end
109
110
 
110
111
  def active_competitions(**)
111
- comps = all_competitions.select { |c| %i[pending active evaluating].include?(c[:status]) }
112
+ comps = all_competitions.select { |c| ACTIVE_STATUSES.include?(c[:status]) }
112
113
  { success: true, competitions: comps.map { |c| { id: c[:id], gap: c[:gap], status: c[:status] } },
113
114
  count: comps.size }
114
115
  end
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Composer
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -108,7 +108,7 @@ module Legion
108
108
  def suggest_with_llm(extensions)
109
109
  suggestions = heuristic_suggestions(extensions)
110
110
  { success: true, suggestions: suggestions, count: suggestions.size }
111
- rescue StandardError
111
+ rescue StandardError => _e
112
112
  { success: true, suggestions: [], count: 0 }
113
113
  end
114
114
  end
@@ -9,6 +9,7 @@ module Legion
9
9
 
10
10
  CONSENSUS_THRESHOLD = 0.67
11
11
  DISAGREEMENT_ESCALATION_THRESHOLD = 0.5
12
+ DECIDED_CONSENSUSES = %i[approved rejected].freeze
12
13
 
13
14
  def propose_to_swarm(charter_id:, proposal_id:, proposer_agent_id:, **)
14
15
  if swarm_available?
@@ -52,8 +53,8 @@ module Legion
52
53
  def tally_swarm_votes(charter_id:, proposal_id:, **)
53
54
  votes = fetch_votes(charter_id, proposal_id)
54
55
 
55
- approve_count = votes.count { |v| [:approve, 'approve'].include?(v[:vote]) }
56
- reject_count = votes.count { |v| [:reject, 'reject'].include?(v[:vote]) }
56
+ approve_count = votes.count { |v| v[:vote].to_s == 'approve' }
57
+ reject_count = votes.count { |v| v[:vote].to_s == 'reject' }
57
58
  total = votes.size
58
59
 
59
60
  consensus = if !total.zero? && (approve_count.to_f / total) >= CONSENSUS_THRESHOLD
@@ -95,7 +96,7 @@ module Legion
95
96
  record = { proposal_id: pid, consensus: tally[:consensus],
96
97
  approve_count: tally[:approve_count], reject_count: tally[:reject_count] }
97
98
 
98
- if %i[approved rejected].include?(tally[:consensus])
99
+ if DECIDED_CONSENSUSES.include?(tally[:consensus])
99
100
  decided << record
100
101
  else
101
102
  pending << record
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Dashboard
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  module_function
12
12
 
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module DreamIdeation
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -5,19 +5,20 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Evolver
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
13
- BOTTOM_PERCENTILE = 0.05
13
+ BOTTOM_PERCENTILE = 0.05
14
14
  SPECIATION_DRIFT_THRESHOLD = 0.5
15
+ INELIGIBLE_STATUSES = %i[building testing].freeze
15
16
 
16
17
  def select_for_improvement(extensions:, count: 3, **)
17
18
  exts = Array(extensions)
18
19
  return { success: true, candidates: [], count: 0, total_evaluated: 0 } if exts.empty?
19
20
 
20
- eligible = exts.reject { |e| %i[building testing].include?((e[:status] || :active).to_sym) }
21
+ eligible = exts.reject { |e| INELIGIBLE_STATUSES.include?((e[:status] || :active).to_sym) }
21
22
  ranked = Helpers::FitnessEvaluator.rank(eligible)
22
23
  bottom_n = ranked.last(count)
23
24
 
@@ -50,7 +51,7 @@ module Legion
50
51
  name_a = extension_a[:name] || extension_a[:extension_name]
51
52
  name_b = extension_b[:name] || extension_b[:extension_name]
52
53
  cat_a = (extension_a[:category] || :cognition).to_sym
53
- merged = merged_name || "lex-merged-#{name_a.to_s.sub(/\Alex-/, '')}-#{name_b.to_s.sub(/\Alex-/, '')}"
54
+ merged = merged_name || "lex-merged-#{name_a.to_s.delete_prefix('lex-')}-#{name_b.to_s.delete_prefix('lex-')}"
54
55
  desc = "Merged extension combining capabilities of #{name_a} and #{name_b}"
55
56
 
56
57
  proposal = Runners::Proposer.propose_concept(
@@ -126,11 +127,17 @@ module Legion
126
127
  end
127
128
 
128
129
  def llm_suggestions(name, fitness, weaknesses)
130
+ # rubocop:disable Legion/HelperMigration/DirectLlm
129
131
  response = Legion::LLM.chat(
130
- caller: { extension: 'lex-mind-growth', operation: 'evolver', phase: 'suggest' }
132
+ caller: {
133
+ extension: 'lex-mind-growth',
134
+ operation: 'evolver',
135
+ phase: 'suggest'
136
+ }
131
137
  ).ask(improvement_prompt(name, fitness, weaknesses))
138
+ # rubocop:enable Legion/HelperMigration/DirectLlm
132
139
  parse_llm_suggestions(response.content)
133
- rescue StandardError
140
+ rescue StandardError => _e
134
141
  nil
135
142
  end
136
143
 
@@ -151,7 +158,7 @@ module Legion
151
158
  return nil unless data.is_a?(Array)
152
159
 
153
160
  data.map(&:to_s).reject(&:empty?)
154
- rescue ::JSON::ParserError
161
+ rescue ::JSON::ParserError => _e
155
162
  nil
156
163
  end
157
164
 
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Governance
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module IntegrationTester
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -42,8 +42,9 @@ module Legion
42
42
 
43
43
  def benchmark_tick(with_extension: nil, iterations: 5, **)
44
44
  return { success: false, reason: :gaia_not_available } unless gaia_available?
45
+ return { success: false, reason: :invalid_iterations, iterations: iterations } unless iterations.is_a?(Integer) && iterations >= 1
45
46
 
46
- timings = iterations.times.map do
47
+ timings = Array.new(iterations) do
47
48
  start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
48
49
  Legion::Gaia.heartbeat if Legion::Gaia.respond_to?(:heartbeat)
49
50
  finish = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Monitor
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Orchestrator
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -7,8 +7,8 @@ module Legion
7
7
  module MindGrowth
8
8
  module Runners
9
9
  module Proposer
10
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
- Legion::Extensions::Helpers.const_defined?(:Lex)
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
12
12
 
13
13
  extend self
14
14
 
@@ -96,7 +96,7 @@ module Legion
96
96
  end
97
97
 
98
98
  def derive_module_name(gem_name)
99
- gem_name.to_s.sub(/\Alex-/, '').split('-').map(&:capitalize).join
99
+ gem_name.to_s.delete_prefix('lex-').split('-').map(&:capitalize).join
100
100
  end
101
101
 
102
102
  def suggest_category
@@ -117,8 +117,15 @@ module Legion
117
117
  def enrich_proposal(name, category, description)
118
118
  return {} unless llm_available?
119
119
 
120
- response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose',
121
- phase: 'capability' }).ask(enrichment_prompt(name, category, description))
120
+ # rubocop:disable Legion/HelperMigration/DirectLlm
121
+ response = Legion::LLM.chat(
122
+ caller: {
123
+ extension: 'lex-mind-growth',
124
+ operation: 'propose',
125
+ phase: 'capability'
126
+ }
127
+ ).ask(enrichment_prompt(name, category, description))
128
+ # rubocop:enable Legion/HelperMigration/DirectLlm
122
129
  parse_enrichment(response.content)
123
130
  rescue StandardError => e
124
131
  log.debug "[mind_growth:proposer] LLM enrichment failed: #{e.message}"
@@ -151,7 +158,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
151
158
  { name: r[:name].to_s, params: Array(r[:params]).map(&:to_s), returns: r[:returns].to_s }
152
159
  end
153
160
  }
154
- rescue ::JSON::ParserError, NoMethodError
161
+ rescue ::JSON::ParserError, NoMethodError => _e
155
162
  {}
156
163
  end
157
164
 
@@ -162,7 +169,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
162
169
  def score_with_llm(proposal)
163
170
  return nil unless llm_available?
164
171
 
165
- response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose', phase: 'score' }).ask(scoring_prompt(proposal))
172
+ response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose', phase: 'score' }).ask(scoring_prompt(proposal)) # rubocop:disable Legion/HelperMigration/DirectLlm
166
173
  parse_scores(response.content)
167
174
  rescue StandardError => e
168
175
  log.debug "[mind_growth:proposer] LLM scoring failed: #{e.message}"
@@ -203,7 +210,7 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
203
210
 
204
211
  [dim, val.to_f.clamp(0.0, 1.0)]
205
212
  end
206
- rescue ::JSON::ParserError, NoMethodError
213
+ rescue ::JSON::ParserError, NoMethodError => _e
207
214
  nil
208
215
  end
209
216
 
@@ -225,8 +232,15 @@ phase: 'capability' }).ask(enrichment_prompt(name, category, description))
225
232
  return nil unless llm_available?
226
233
 
227
234
  candidates = existing.last(20).map { |p| { name: p.name, description: p.description } }
228
- response = Legion::LLM.chat(caller: { extension: 'lex-mind-growth', operation: 'propose',
229
- phase: 'validate' }).ask(redundancy_prompt(name, description, candidates))
235
+ # rubocop:disable Legion/HelperMigration/DirectLlm
236
+ response = Legion::LLM.chat(
237
+ caller: {
238
+ extension: 'lex-mind-growth',
239
+ operation: 'propose',
240
+ phase: 'validate'
241
+ }
242
+ ).ask(redundancy_prompt(name, description, candidates))
243
+ # rubocop:enable Legion/HelperMigration/DirectLlm
230
244
  parse_redundancy(response.content)
231
245
  rescue StandardError => e
232
246
  log.debug "[mind_growth:proposer] LLM redundancy check failed: #{e.message}"
@@ -264,7 +278,7 @@ phase: 'validate' }).ask(redundancy_prompt(name, description, candidates))
264
278
  similar_to: data[:similar_to],
265
279
  score: score
266
280
  }
267
- rescue ::JSON::ParserError, NoMethodError
281
+ rescue ::JSON::ParserError, NoMethodError => _e
268
282
  nil
269
283
  end
270
284
  end
@@ -5,19 +5,24 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Retrospective
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
13
+ BUILT_STATUSES = %i[passing wired active].freeze
14
+ FAILED_STATUSES = %i[build_failed rejected pruned].freeze
15
+ IN_PROGRESS_STATUSES = %i[proposed evaluating approved building testing].freeze
16
+ SUCCEEDED_STATUSES = BUILT_STATUSES
17
+
13
18
  # Generates a summary of growth activity: proposals by status, recent builds, failures
14
19
  def session_report(**)
15
20
  proposals = Runners::Proposer.proposal_stats
16
21
  recent = Runners::Proposer.list_proposals(limit: 10)
17
22
 
18
- built = recent[:proposals].select { |p| %i[passing wired active].include?(p[:status]) }
19
- failed = recent[:proposals].select { |p| %i[build_failed rejected pruned].include?(p[:status]) }
20
- in_progress = recent[:proposals].select { |p| %i[proposed evaluating approved building testing].include?(p[:status]) }
23
+ built = recent[:proposals].select { |p| BUILT_STATUSES.include?(p[:status]) }
24
+ failed = recent[:proposals].select { |p| FAILED_STATUSES.include?(p[:status]) }
25
+ in_progress = recent[:proposals].select { |p| IN_PROGRESS_STATUSES.include?(p[:status]) }
21
26
 
22
27
  {
23
28
  success: true,
@@ -64,7 +69,7 @@ module Legion
64
69
 
65
70
  failed = proposals.select { |p| p[:status] == :build_failed }
66
71
  rejected = proposals.select { |p| p[:status] == :rejected }
67
- succeeded = proposals.select { |p| %i[passing wired active].include?(p[:status]) }
72
+ succeeded = proposals.select { |p| SUCCEEDED_STATUSES.include?(p[:status]) }
68
73
 
69
74
  # Category success rates
70
75
  category_stats = compute_category_stats(proposals)
@@ -92,7 +97,7 @@ module Legion
92
97
  def compute_category_stats(proposals)
93
98
  by_category = proposals.group_by { |p| p[:category] }
94
99
  by_category.transform_values do |cat_proposals|
95
- succeeded = cat_proposals.count { |p| %i[passing wired active].include?(p[:status]) }
100
+ succeeded = cat_proposals.count { |p| SUCCEEDED_STATUSES.include?(p[:status]) }
96
101
  {
97
102
  total: cat_proposals.size,
98
103
  succeeded: succeeded,
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module RiskAssessor
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -67,7 +67,7 @@ module Legion
67
67
  when :integration_sweep then execute_integration_sweep(charter_id)
68
68
  end
69
69
 
70
- { success: true, charter_type: charter_type, results: Array(results) }
70
+ { success: true, charter_id: charter_id, charter_type: charter_type, results: Array(results) }
71
71
  end
72
72
 
73
73
  def complete_build_swarm(charter_id:, outcome: :success, **)
@@ -5,8 +5,8 @@ module Legion
5
5
  module MindGrowth
6
6
  module Runners
7
7
  module Wirer
8
- include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
9
- Legion::Extensions::Helpers.const_defined?(:Lex)
8
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers, false) &&
9
+ Legion::Extensions::Helpers.const_defined?(:Lex, false)
10
10
 
11
11
  extend self
12
12
 
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module MindGrowth
6
- VERSION = '0.2.5'
6
+ VERSION = '0.2.7'
7
7
  end
8
8
  end
9
9
  end
@@ -34,7 +34,7 @@ require 'legion/extensions/mind_growth/client'
34
34
  module Legion
35
35
  module Extensions
36
36
  module MindGrowth
37
- extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core)
37
+ extend Legion::Extensions::Core if Legion::Extensions.const_defined?(:Core, false)
38
38
 
39
39
  def self.remote_invocable?
40
40
  false
@@ -68,8 +68,8 @@ RSpec.describe Legion::Extensions::MindGrowth::Actor::GrowthCycle do
68
68
  end
69
69
 
70
70
  describe '#check_subtask?' do
71
- it 'returns false' do
72
- expect(actor.check_subtask?).to be false
71
+ it 'returns true' do
72
+ expect(actor.check_subtask?).to be true
73
73
  end
74
74
  end
75
75
 
@@ -235,7 +235,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::CompositionMap do
235
235
 
236
236
  describe 'thread safety' do
237
237
  it 'records all rules when added concurrently' do
238
- threads = 20.times.map do |i|
238
+ threads = Array.new(20) do |i|
239
239
  Thread.new do
240
240
  map.add_rule(source_extension: "lex-#{i}", output_key: :result,
241
241
  target_extension: 'lex-target', target_method: :run)
@@ -160,7 +160,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::ProposalStore do
160
160
  it 'evicts the oldest proposal when at capacity' do
161
161
  stub_const("#{described_class}::MAX_PROPOSALS", 3)
162
162
  small_store = described_class.new
163
- proposals = 4.times.map do |i|
163
+ proposals = Array.new(4) do |i|
164
164
  Legion::Extensions::MindGrowth::Helpers::ConceptProposal.new(
165
165
  name: "lex-evict-#{i}", module_name: "E#{i}", category: :cognition, description: "evict #{i}"
166
166
  )
@@ -188,7 +188,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Helpers::ProposalStore do
188
188
 
189
189
  describe 'thread safety' do
190
190
  it 'handles concurrent stores without error' do
191
- threads = 10.times.map do |i|
191
+ threads = Array.new(10) do |i|
192
192
  Thread.new do
193
193
  p = Legion::Extensions::MindGrowth::Helpers::ConceptProposal.new(
194
194
  name: "lex-thread-#{i}", module_name: "T#{i}", category: :cognition, description: "thread #{i}"
@@ -329,7 +329,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Runners::CompetitiveEvolver do
329
329
 
330
330
  describe 'thread safety' do
331
331
  it 'handles concurrent competition creation' do
332
- threads = 10.times.map do |i|
332
+ threads = Array.new(10) do |i|
333
333
  Thread.new { evolver.create_competition(gap: "gap-#{i}", proposal_ids: %w[a b]) }
334
334
  end
335
335
  results = threads.map(&:value)
@@ -154,7 +154,7 @@ RSpec.describe Legion::Extensions::MindGrowth::Runners::Governance do
154
154
 
155
155
  context 'thread safety' do
156
156
  it 'records all votes when cast concurrently' do
157
- threads = 10.times.map do |i|
157
+ threads = Array.new(10) do |i|
158
158
  Thread.new { governance.vote_on_proposal(proposal_id: proposal.id, vote: :approve, agent_id: "t#{i}") }
159
159
  end
160
160
  threads.each(&:join)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-mind-growth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity