lex-agentic-learning 0.1.0 → 0.1.2

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 (22) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +41 -3
  4. data/lex-agentic-learning.gemspec +8 -0
  5. data/lib/legion/extensions/agentic/learning/anchoring/runners/anchoring.rb +12 -12
  6. data/lib/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst.rb +16 -16
  7. data/lib/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis.rb +8 -8
  8. data/lib/legion/extensions/agentic/learning/curiosity/runners/curiosity.rb +10 -10
  9. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity.rb +13 -13
  10. data/lib/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine.rb +4 -0
  11. data/lib/legion/extensions/agentic/learning/fermentation/version.rb +1 -1
  12. data/lib/legion/extensions/agentic/learning/habit/runners/habit.rb +7 -7
  13. data/lib/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly.rb +10 -10
  14. data/lib/legion/extensions/agentic/learning/learning_rate/runners/learning_rate.rb +4 -4
  15. data/lib/legion/extensions/agentic/learning/meta_learning/runners/meta_learning.rb +20 -20
  16. data/lib/legion/extensions/agentic/learning/preference_learning/runners/preference_learning.rb +10 -10
  17. data/lib/legion/extensions/agentic/learning/procedural/runners/procedural_learning.rb +14 -14
  18. data/lib/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding.rb +19 -19
  19. data/lib/legion/extensions/agentic/learning/version.rb +1 -1
  20. data/spec/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine_spec.rb +26 -0
  21. data/spec/spec_helper.rb +21 -21
  22. metadata +99 -1
@@ -11,14 +11,14 @@ module Legion
11
11
  Legion::Extensions::Helpers.const_defined?(:Lex)
12
12
 
13
13
  def activate_unit(id:, level: 1.0, domain: :general, **)
14
- Legion::Logging.debug "[hebbian] activate: id=#{id} level=#{level}"
14
+ log.debug "[hebbian] activate: id=#{id} level=#{level}"
15
15
  network.add_unit(id: id, domain: domain)
16
16
  unit = network.activate_unit(id: id, level: level)
17
17
  { success: true, unit: unit.to_h, assemblies: network.assembly_count }
18
18
  end
19
19
 
20
20
  def co_activate_units(ids:, level: 1.0, **)
21
- Legion::Logging.debug "[hebbian] co_activate: ids=#{ids}"
21
+ log.debug "[hebbian] co_activate: ids=#{ids}"
22
22
  results = network.co_activate(ids: ids, level: level)
23
23
  { success: true, units: results, assemblies: network.assembly_count }
24
24
  end
@@ -27,19 +27,19 @@ module Legion
27
27
  w = network.query_weight(from: from, to: to)
28
28
  label = Helpers::Constants::WEIGHT_LABELS.each { |range, l| break l if range.cover?(w) }
29
29
  label = :nascent unless label.is_a?(Symbol)
30
- Legion::Logging.debug "[hebbian] weight: #{from}->#{to} = #{w}"
30
+ log.debug "[hebbian] weight: #{from}->#{to} = #{w}"
31
31
  { success: true, from: from, to: to, weight: w.round(4), label: label }
32
32
  end
33
33
 
34
34
  def list_assemblies(**)
35
35
  assemblies = network.assemblies.values.map(&:to_h)
36
- Legion::Logging.debug "[hebbian] list_assemblies: #{assemblies.size}"
36
+ log.debug "[hebbian] list_assemblies: #{assemblies.size}"
37
37
  { success: true, assemblies: assemblies, count: assemblies.size }
38
38
  end
39
39
 
40
40
  def query_assembly(id:, **)
41
41
  asm = network.query_assembly(id: id.to_sym)
42
- Legion::Logging.debug "[hebbian] query_assembly: id=#{id} found=#{!asm.nil?}"
42
+ log.debug "[hebbian] query_assembly: id=#{id} found=#{!asm.nil?}"
43
43
  if asm
44
44
  { success: true, assembly: asm.to_h }
45
45
  else
@@ -48,7 +48,7 @@ module Legion
48
48
  end
49
49
 
50
50
  def pattern_complete(partial_ids:, **)
51
- Legion::Logging.debug "[hebbian] pattern_complete: partial=#{partial_ids}"
51
+ log.debug "[hebbian] pattern_complete: partial=#{partial_ids}"
52
52
  result = network.pattern_complete(partial_ids: partial_ids)
53
53
  if result
54
54
  { success: true, completion: result }
@@ -59,24 +59,24 @@ module Legion
59
59
 
60
60
  def strongest_units(limit: 10, **)
61
61
  units = network.strongest_units(limit.to_i)
62
- Legion::Logging.debug "[hebbian] strongest_units: #{units.size}"
62
+ log.debug "[hebbian] strongest_units: #{units.size}"
63
63
  { success: true, units: units }
64
64
  end
65
65
 
66
66
  def assemblies_for(unit_id:, **)
67
67
  asms = network.assemblies_containing(unit_id: unit_id).map(&:to_h)
68
- Legion::Logging.debug "[hebbian] assemblies_for: unit=#{unit_id} count=#{asms.size}"
68
+ log.debug "[hebbian] assemblies_for: unit=#{unit_id} count=#{asms.size}"
69
69
  { success: true, assemblies: asms, count: asms.size }
70
70
  end
71
71
 
72
72
  def update_hebbian(**)
73
- Legion::Logging.debug '[hebbian] decay tick'
73
+ log.debug '[hebbian] decay tick'
74
74
  network.decay_all
75
75
  { success: true, units: network.unit_count, assemblies: network.assembly_count }
76
76
  end
77
77
 
78
78
  def hebbian_stats(**)
79
- Legion::Logging.debug '[hebbian] stats'
79
+ log.debug '[hebbian] stats'
80
80
  { success: true, stats: network.to_h }
81
81
  end
82
82
 
@@ -14,7 +14,7 @@ module Legion
14
14
  rate_model.record_prediction(domain: domain, correct: correct)
15
15
  rate = rate_model.rate_for(domain)
16
16
  accuracy = rate_model.accuracy_for(domain)
17
- Legion::Logging.debug "[learning_rate] prediction: domain=#{domain} correct=#{correct} rate=#{rate.round(3)} accuracy=#{accuracy.round(3)}"
17
+ log.debug "[learning_rate] prediction: domain=#{domain} correct=#{correct} rate=#{rate.round(3)} accuracy=#{accuracy.round(3)}"
18
18
  {
19
19
  success: true,
20
20
  domain: domain,
@@ -27,14 +27,14 @@ module Legion
27
27
  def record_surprise(magnitude:, domain: :general, **)
28
28
  rate_model.record_surprise(domain: domain, magnitude: magnitude)
29
29
  rate = rate_model.rate_for(domain)
30
- Legion::Logging.debug "[learning_rate] surprise: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
30
+ log.debug "[learning_rate] surprise: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
31
31
  { success: true, domain: domain, rate: rate, label: rate_model.label_for(domain) }
32
32
  end
33
33
 
34
34
  def record_error(magnitude:, domain: :general, **)
35
35
  rate_model.record_error(domain: domain, magnitude: magnitude)
36
36
  rate = rate_model.rate_for(domain)
37
- Legion::Logging.debug "[learning_rate] error: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
37
+ log.debug "[learning_rate] error: domain=#{domain} magnitude=#{magnitude.round(3)} rate=#{rate.round(3)}"
38
38
  { success: true, domain: domain, rate: rate, label: rate_model.label_for(domain) }
39
39
  end
40
40
 
@@ -63,7 +63,7 @@ module Legion
63
63
  def update_learning_rate(**)
64
64
  rate_model.decay
65
65
  overall = rate_model.overall_rate
66
- Legion::Logging.debug "[learning_rate] tick: domains=#{rate_model.domain_count} overall=#{overall.round(3)}"
66
+ log.debug "[learning_rate] tick: domains=#{rate_model.domain_count} overall=#{overall.round(3)}"
67
67
  { success: true, domain_count: rate_model.domain_count, overall_rate: overall }
68
68
  end
69
69
 
@@ -14,77 +14,77 @@ module Legion
14
14
  related_domains: [], **)
15
15
  result = engine.create_domain(name: name, learning_rate: learning_rate, related_domains: related_domains)
16
16
  if result.is_a?(Hash) && result[:error]
17
- Legion::Logging.warn "[meta_learning] create_domain failed: #{result[:error]}"
17
+ log.warn "[meta_learning] create_domain failed: #{result[:error]}"
18
18
  return result
19
19
  end
20
20
 
21
- Legion::Logging.debug "[meta_learning] domain created: #{result.name} id=#{result.id[0..7]}"
21
+ log.debug "[meta_learning] domain created: #{result.name} id=#{result.id[0..7]}"
22
22
  result.to_h
23
23
  end
24
24
 
25
25
  def register_learning_strategy(name:, strategy_type:, **)
26
26
  result = engine.create_strategy(name: name, strategy_type: strategy_type)
27
27
  if result.is_a?(Hash) && result[:error]
28
- Legion::Logging.warn "[meta_learning] create_strategy failed: #{result[:error]}"
28
+ log.warn "[meta_learning] create_strategy failed: #{result[:error]}"
29
29
  return result
30
30
  end
31
31
 
32
- Legion::Logging.debug "[meta_learning] strategy registered: #{result.name} type=#{result.strategy_type}"
32
+ log.debug "[meta_learning] strategy registered: #{result.name} type=#{result.strategy_type}"
33
33
  result.to_h
34
34
  end
35
35
 
36
36
  def record_learning_episode(domain_id:, success:, strategy_id: nil, **)
37
37
  result = engine.record_episode(domain_id: domain_id, strategy_id: strategy_id, success: success)
38
38
  if result.is_a?(Hash) && result[:error]
39
- Legion::Logging.warn "[meta_learning] record_episode failed: #{result[:error]}"
39
+ log.warn "[meta_learning] record_episode failed: #{result[:error]}"
40
40
  return result
41
41
  end
42
42
 
43
- Legion::Logging.debug "[meta_learning] episode recorded domain=#{result[:domain_name]} " \
44
- "success=#{success} proficiency=#{result[:proficiency].round(4)}"
43
+ log.debug "[meta_learning] episode recorded domain=#{result[:domain_name]} " \
44
+ "success=#{success} proficiency=#{result[:proficiency].round(4)}"
45
45
  result
46
46
  end
47
47
 
48
48
  def recommend_learning_strategy(domain_id:, **)
49
49
  result = engine.recommend_strategy(domain_id: domain_id)
50
- Legion::Logging.debug "[meta_learning] strategy recommendation domain=#{domain_id[0..7]} " \
51
- "recommendation=#{result[:recommendation]}"
50
+ log.debug "[meta_learning] strategy recommendation domain=#{domain_id[0..7]} " \
51
+ "recommendation=#{result[:recommendation]}"
52
52
  result
53
53
  end
54
54
 
55
55
  def check_transfer_learning(source_domain_id:, target_domain_id:, **)
56
56
  result = engine.transfer_check(source_domain_id: source_domain_id, target_domain_id: target_domain_id)
57
- Legion::Logging.debug "[meta_learning] transfer check eligible=#{result[:eligible]}"
57
+ log.debug "[meta_learning] transfer check eligible=#{result[:eligible]}"
58
58
  result
59
59
  end
60
60
 
61
61
  def apply_transfer_bonus(source_domain_id:, target_domain_id:, **)
62
62
  result = engine.apply_transfer(source_domain_id: source_domain_id, target_domain_id: target_domain_id)
63
- Legion::Logging.info "[meta_learning] transfer applied=#{result[:applied]}"
63
+ log.info "[meta_learning] transfer applied=#{result[:applied]}"
64
64
  result
65
65
  end
66
66
 
67
67
  def learning_domain_ranking(limit: 10, **)
68
68
  ranking = engine.domain_ranking(limit: limit)
69
- Legion::Logging.debug "[meta_learning] domain ranking returned #{ranking.size} domains"
69
+ log.debug "[meta_learning] domain ranking returned #{ranking.size} domains"
70
70
  { ranking: ranking, count: ranking.size }
71
71
  end
72
72
 
73
73
  def learning_strategy_ranking(limit: 10, **)
74
74
  ranking = engine.strategy_ranking(limit: limit)
75
- Legion::Logging.debug "[meta_learning] strategy ranking returned #{ranking.size} strategies"
75
+ log.debug "[meta_learning] strategy ranking returned #{ranking.size} strategies"
76
76
  { ranking: ranking, count: ranking.size }
77
77
  end
78
78
 
79
79
  def learning_curve_report(domain_id:, **)
80
80
  result = engine.learning_curve(domain_id: domain_id)
81
81
  if result.is_a?(Hash) && result[:error]
82
- Legion::Logging.warn "[meta_learning] learning_curve failed: #{result[:error]}"
82
+ log.warn "[meta_learning] learning_curve failed: #{result[:error]}"
83
83
  return result
84
84
  end
85
85
 
86
- Legion::Logging.debug "[meta_learning] learning curve domain=#{result[:domain]} " \
87
- "episodes=#{result[:curve].size}"
86
+ log.debug "[meta_learning] learning curve domain=#{result[:domain]} " \
87
+ "episodes=#{result[:curve].size}"
88
88
  result
89
89
  end
90
90
 
@@ -92,15 +92,15 @@ module Legion
92
92
  adapt_result = engine.adapt_rates
93
93
  prune_result = engine.prune_stale_domains
94
94
  stats = engine.to_h
95
- Legion::Logging.info "[meta_learning] update: adapted=#{adapt_result[:count]} " \
96
- "pruned=#{prune_result[:pruned]} domains=#{stats[:domain_count]}"
95
+ log.info "[meta_learning] update: adapted=#{adapt_result[:count]} " \
96
+ "pruned=#{prune_result[:pruned]} domains=#{stats[:domain_count]}"
97
97
  { adapt: adapt_result, prune: prune_result, stats: stats }
98
98
  end
99
99
 
100
100
  def meta_learning_stats(**)
101
101
  stats = engine.to_h
102
- Legion::Logging.debug "[meta_learning] stats domains=#{stats[:domain_count]} " \
103
- "strategies=#{stats[:strategy_count]} efficiency=#{stats[:overall_efficiency]}"
102
+ log.debug "[meta_learning] stats domains=#{stats[:domain_count]} " \
103
+ "strategies=#{stats[:strategy_count]} efficiency=#{stats[:overall_efficiency]}"
104
104
  stats
105
105
  end
106
106
 
@@ -13,9 +13,9 @@ module Legion
13
13
  def register_preference_option(label:, domain: :general, **)
14
14
  result = preference_engine.register_option(label: label, domain: domain)
15
15
  if result[:error]
16
- Legion::Logging.warn "[preference_learning] register failed: #{result[:error]}"
16
+ log.warn "[preference_learning] register failed: #{result[:error]}"
17
17
  else
18
- Legion::Logging.debug "[preference_learning] registered option id=#{result[:id]} label=#{label} domain=#{domain}"
18
+ log.debug "[preference_learning] registered option id=#{result[:id]} label=#{label} domain=#{domain}"
19
19
  end
20
20
  result
21
21
  end
@@ -23,9 +23,9 @@ module Legion
23
23
  def record_preference_comparison(winner_id:, loser_id:, **)
24
24
  result = preference_engine.record_comparison(winner_id: winner_id, loser_id: loser_id)
25
25
  if result[:error]
26
- Legion::Logging.warn "[preference_learning] comparison failed: #{result[:error]}"
26
+ log.warn "[preference_learning] comparison failed: #{result[:error]}"
27
27
  else
28
- Legion::Logging.info "[preference_learning] comparison: winner=#{winner_id} loser=#{loser_id} total=#{result[:comparisons]}"
28
+ log.info "[preference_learning] comparison: winner=#{winner_id} loser=#{loser_id} total=#{result[:comparisons]}"
29
29
  end
30
30
  result
31
31
  end
@@ -33,35 +33,35 @@ module Legion
33
33
  def predict_preference_outcome(option_a_id:, option_b_id:, **)
34
34
  result = preference_engine.predict_preference(option_a_id: option_a_id, option_b_id: option_b_id)
35
35
  if result[:error]
36
- Legion::Logging.warn "[preference_learning] predict failed: #{result[:error]}"
36
+ log.warn "[preference_learning] predict failed: #{result[:error]}"
37
37
  else
38
- Legion::Logging.debug "[preference_learning] predict: preferred=#{result[:preferred_label]} confidence=#{result[:confidence].round(2)}"
38
+ log.debug "[preference_learning] predict: preferred=#{result[:preferred_label]} confidence=#{result[:confidence].round(2)}"
39
39
  end
40
40
  result
41
41
  end
42
42
 
43
43
  def top_preferences_report(domain: nil, limit: 5, **)
44
44
  options = preference_engine.top_preferences(domain: domain, limit: limit)
45
- Legion::Logging.debug "[preference_learning] top #{limit} preferences domain=#{domain.inspect} count=#{options.size}"
45
+ log.debug "[preference_learning] top #{limit} preferences domain=#{domain.inspect} count=#{options.size}"
46
46
  { domain: domain, limit: limit, options: options }
47
47
  end
48
48
 
49
49
  def preference_stability_report(**)
50
50
  stability = preference_engine.preference_stability
51
51
  label = stability < 0.1 ? :stable : :variable
52
- Legion::Logging.debug "[preference_learning] stability=#{stability.round(4)} label=#{label}"
52
+ log.debug "[preference_learning] stability=#{stability.round(4)} label=#{label}"
53
53
  { stability: stability, label: label }
54
54
  end
55
55
 
56
56
  def update_preference_learning(**)
57
57
  count = preference_engine.decay_all
58
- Legion::Logging.debug "[preference_learning] decay cycle: options_updated=#{count}"
58
+ log.debug "[preference_learning] decay cycle: options_updated=#{count}"
59
59
  { decayed: count }
60
60
  end
61
61
 
62
62
  def preference_learning_stats(**)
63
63
  engine_hash = preference_engine.to_h
64
- Legion::Logging.debug "[preference_learning] stats: total_options=#{engine_hash[:total_options]} comparisons=#{engine_hash[:comparisons]}"
64
+ log.debug "[preference_learning] stats: total_options=#{engine_hash[:total_options]} comparisons=#{engine_hash[:comparisons]}"
65
65
  engine_hash.merge(stability_label: preference_engine_stability_label)
66
66
  end
67
67
 
@@ -12,8 +12,8 @@ module Legion
12
12
 
13
13
  def create_skill(name:, domain:, **)
14
14
  skill = engine.create_skill(name: name, domain: domain)
15
- Legion::Logging.debug "[procedural_learning] created skill=#{name} " \
16
- "domain=#{domain} id=#{skill.id[0..7]}"
15
+ log.debug "[procedural_learning] created skill=#{name} " \
16
+ "domain=#{domain} id=#{skill.id[0..7]}"
17
17
  { success: true, skill_id: skill.id, name: name, domain: domain,
18
18
  proficiency: skill.proficiency, stage: skill.stage }
19
19
  end
@@ -26,59 +26,59 @@ module Legion
26
26
 
27
27
  return result unless result.is_a?(Helpers::Production)
28
28
 
29
- Legion::Logging.debug '[procedural_learning] production added ' \
30
- "skill=#{skill_id[0..7]} condition=#{condition}"
29
+ log.debug '[procedural_learning] production added ' \
30
+ "skill=#{skill_id[0..7]} condition=#{condition}"
31
31
  { success: true, production_id: result.id, skill_id: skill_id }
32
32
  end
33
33
 
34
34
  def practice_skill(skill_id:, success:, **)
35
35
  result = engine.practice_skill(skill_id: skill_id, success: success)
36
- Legion::Logging.debug "[procedural_learning] practice skill=#{skill_id[0..7]} " \
37
- "success=#{success} proficiency=#{result[:proficiency]&.round(3)}"
36
+ log.debug "[procedural_learning] practice skill=#{skill_id[0..7]} " \
37
+ "success=#{success} proficiency=#{result[:proficiency]&.round(3)}"
38
38
  result
39
39
  end
40
40
 
41
41
  def execute_production(production_id:, success:, **)
42
42
  result = engine.execute_production(production_id: production_id, success: success)
43
- Legion::Logging.debug "[procedural_learning] execute production=#{production_id[0..7]} " \
44
- "success=#{success}"
43
+ log.debug "[procedural_learning] execute production=#{production_id[0..7]} " \
44
+ "success=#{success}"
45
45
  result
46
46
  end
47
47
 
48
48
  def skill_assessment(skill_id:, **)
49
49
  result = engine.skill_assessment(skill_id: skill_id)
50
- Legion::Logging.debug "[procedural_learning] assessment skill=#{skill_id[0..7]}"
50
+ log.debug "[procedural_learning] assessment skill=#{skill_id[0..7]}"
51
51
  result
52
52
  end
53
53
 
54
54
  def compiled_skills(**)
55
55
  skills = engine.compiled_skills
56
- Legion::Logging.debug "[procedural_learning] compiled count=#{skills.size}"
56
+ log.debug "[procedural_learning] compiled count=#{skills.size}"
57
57
  { success: true, skills: skills.map(&:to_h), count: skills.size }
58
58
  end
59
59
 
60
60
  def autonomous_skills(**)
61
61
  skills = engine.autonomous_skills
62
- Legion::Logging.debug "[procedural_learning] autonomous count=#{skills.size}"
62
+ log.debug "[procedural_learning] autonomous count=#{skills.size}"
63
63
  { success: true, skills: skills.map(&:to_h), count: skills.size }
64
64
  end
65
65
 
66
66
  def most_practiced_skills(limit: 5, **)
67
67
  skills = engine.most_practiced(limit: limit)
68
- Legion::Logging.debug "[procedural_learning] most_practiced limit=#{limit}"
68
+ log.debug "[procedural_learning] most_practiced limit=#{limit}"
69
69
  { success: true, skills: skills.map(&:to_h), count: skills.size }
70
70
  end
71
71
 
72
72
  def update_procedural_learning(**)
73
73
  engine.decay_all
74
74
  pruned = engine.prune_stale
75
- Legion::Logging.debug "[procedural_learning] decay+prune pruned=#{pruned}"
75
+ log.debug "[procedural_learning] decay+prune pruned=#{pruned}"
76
76
  { success: true, pruned: pruned }
77
77
  end
78
78
 
79
79
  def procedural_learning_stats(**)
80
80
  stats = engine.to_h
81
- Legion::Logging.debug "[procedural_learning] stats total=#{stats[:total_skills]}"
81
+ log.debug "[procedural_learning] stats total=#{stats[:total_skills]}"
82
82
  { success: true }.merge(stats)
83
83
  end
84
84
 
@@ -13,83 +13,83 @@ module Legion
13
13
  def create_scaffold(skill_name:, domain:, competence: nil, **)
14
14
  comp = competence || Helpers::Constants::DEFAULT_COMPETENCE
15
15
  scaffold = engine.create_scaffold(skill_name: skill_name, domain: domain, competence: comp)
16
- Legion::Logging.debug "[cognitive_scaffolding] created: skill=#{skill_name} domain=#{domain} " \
17
- "competence=#{scaffold.competence.round(2)} zone=#{scaffold.current_zone}"
16
+ log.debug "[cognitive_scaffolding] created: skill=#{skill_name} domain=#{domain} " \
17
+ "competence=#{scaffold.competence.round(2)} zone=#{scaffold.current_zone}"
18
18
  { success: true, scaffold: scaffold.to_h }
19
19
  end
20
20
 
21
21
  def attempt_scaffolded_task(scaffold_id:, difficulty:, success:, **)
22
22
  scaffold = engine.attempt_scaffolded_task(scaffold_id: scaffold_id, difficulty: difficulty, success: success)
23
23
  unless scaffold
24
- Legion::Logging.debug "[cognitive_scaffolding] attempt: scaffold_id=#{scaffold_id} not found"
24
+ log.debug "[cognitive_scaffolding] attempt: scaffold_id=#{scaffold_id} not found"
25
25
  return { success: false, reason: :not_found, scaffold_id: scaffold_id }
26
26
  end
27
27
 
28
- Legion::Logging.debug "[cognitive_scaffolding] attempt: skill=#{scaffold.skill_name} " \
29
- "difficulty=#{difficulty.round(2)} success=#{success} " \
30
- "competence=#{scaffold.competence.round(2)} zone=#{scaffold.current_zone}"
28
+ log.debug "[cognitive_scaffolding] attempt: skill=#{scaffold.skill_name} " \
29
+ "difficulty=#{difficulty.round(2)} success=#{success} " \
30
+ "competence=#{scaffold.competence.round(2)} zone=#{scaffold.current_zone}"
31
31
  { success: true, scaffold: scaffold.to_h }
32
32
  end
33
33
 
34
34
  def recommend_scaffolded_task(scaffold_id:, **)
35
35
  recommendation = engine.recommend_task(scaffold_id: scaffold_id)
36
36
  unless recommendation
37
- Legion::Logging.debug "[cognitive_scaffolding] recommend: scaffold_id=#{scaffold_id} not found"
37
+ log.debug "[cognitive_scaffolding] recommend: scaffold_id=#{scaffold_id} not found"
38
38
  return { success: false, reason: :not_found, scaffold_id: scaffold_id }
39
39
  end
40
40
 
41
- Legion::Logging.debug "[cognitive_scaffolding] recommend: difficulty=#{recommendation[:difficulty].round(2)} " \
42
- "support=#{recommendation[:support_level]} zone=#{recommendation[:zone]}"
41
+ log.debug "[cognitive_scaffolding] recommend: difficulty=#{recommendation[:difficulty].round(2)} " \
42
+ "support=#{recommendation[:support_level]} zone=#{recommendation[:zone]}"
43
43
  { success: true, recommendation: recommendation }
44
44
  end
45
45
 
46
46
  def mastered_scaffolded_skills(**)
47
47
  skills = engine.mastered_skills
48
- Legion::Logging.debug "[cognitive_scaffolding] mastered: count=#{skills.size}"
48
+ log.debug "[cognitive_scaffolding] mastered: count=#{skills.size}"
49
49
  { success: true, skills: skills.map(&:to_h), count: skills.size }
50
50
  end
51
51
 
52
52
  def zpd_skills(**)
53
53
  skills = engine.zpd_skills
54
- Legion::Logging.debug "[cognitive_scaffolding] zpd: count=#{skills.size}"
54
+ log.debug "[cognitive_scaffolding] zpd: count=#{skills.size}"
55
55
  { success: true, skills: skills.map(&:to_h), count: skills.size }
56
56
  end
57
57
 
58
58
  def domain_scaffolds(domain:, **)
59
59
  scaffolds = engine.by_domain(domain: domain)
60
- Legion::Logging.debug "[cognitive_scaffolding] domain: domain=#{domain} count=#{scaffolds.size}"
60
+ log.debug "[cognitive_scaffolding] domain: domain=#{domain} count=#{scaffolds.size}"
61
61
  { success: true, domain: domain, scaffolds: scaffolds.map(&:to_h), count: scaffolds.size }
62
62
  end
63
63
 
64
64
  def adjust_scaffold_support(scaffold_id:, direction:, **)
65
65
  scaffold = engine.adjust_support(scaffold_id: scaffold_id, direction: direction)
66
66
  unless scaffold
67
- Legion::Logging.debug "[cognitive_scaffolding] adjust_support: scaffold_id=#{scaffold_id} not found"
67
+ log.debug "[cognitive_scaffolding] adjust_support: scaffold_id=#{scaffold_id} not found"
68
68
  return { success: false, reason: :not_found, scaffold_id: scaffold_id }
69
69
  end
70
70
 
71
- Legion::Logging.debug "[cognitive_scaffolding] adjust_support: skill=#{scaffold.skill_name} " \
72
- "direction=#{direction} support=#{scaffold.support_level}"
71
+ log.debug "[cognitive_scaffolding] adjust_support: skill=#{scaffold.skill_name} " \
72
+ "direction=#{direction} support=#{scaffold.support_level}"
73
73
  { success: true, scaffold: scaffold.to_h }
74
74
  end
75
75
 
76
76
  def overall_scaffolded_competence(**)
77
77
  overall = engine.overall_competence
78
- Legion::Logging.debug "[cognitive_scaffolding] overall_competence: #{overall.round(3)}"
78
+ log.debug "[cognitive_scaffolding] overall_competence: #{overall.round(3)}"
79
79
  { success: true, overall_competence: overall.round(4) }
80
80
  end
81
81
 
82
82
  def update_cognitive_scaffolding(**)
83
83
  count = engine.decay_all
84
84
  overall = engine.overall_competence
85
- Legion::Logging.debug "[cognitive_scaffolding] decay: scaffolds=#{count} overall=#{overall.round(3)}"
85
+ log.debug "[cognitive_scaffolding] decay: scaffolds=#{count} overall=#{overall.round(3)}"
86
86
  { success: true, action: :decay, scaffold_count: count, overall_competence: overall.round(4) }
87
87
  end
88
88
 
89
89
  def cognitive_scaffolding_stats(**)
90
90
  stats = engine.to_h
91
- Legion::Logging.debug "[cognitive_scaffolding] stats: total=#{stats[:total_scaffolds]} " \
92
- "mastered=#{stats[:mastered_count]} zpd=#{stats[:zpd_count]}"
91
+ log.debug "[cognitive_scaffolding] stats: total=#{stats[:total_scaffolds]} " \
92
+ "mastered=#{stats[:mastered_count]} zpd=#{stats[:zpd_count]}"
93
93
  { success: true, stats: stats }
94
94
  end
95
95
 
@@ -4,7 +4,7 @@ module Legion
4
4
  module Extensions
5
5
  module Agentic
6
6
  module Learning
7
- VERSION = '0.1.0'
7
+ VERSION = '0.1.2'
8
8
  end
9
9
  end
10
10
  end
@@ -26,6 +26,18 @@ RSpec.describe Legion::Extensions::Agentic::Learning::Fermentation::Helpers::Fer
26
26
  engine.create_substrate(substrate_type: :raw_idea, domain: :emotional)
27
27
  expect(engine.fermentation_report[:total_batches]).to eq(2)
28
28
  end
29
+
30
+ it 'rejects invalid substrate_type' do
31
+ expect(engine.create_substrate(substrate_type: :telekinesis, domain: :cognitive)).to be_nil
32
+ end
33
+
34
+ it 'accepts all valid SUBSTRATE_TYPES' do
35
+ constants = Legion::Extensions::Agentic::Learning::Fermentation::Helpers::Constants
36
+ constants::SUBSTRATE_TYPES.each do |st|
37
+ result = engine.create_substrate(substrate_type: st, domain: :cognitive)
38
+ expect(result).not_to be_nil
39
+ end
40
+ end
29
41
  end
30
42
 
31
43
  describe '#ferment' do
@@ -50,6 +62,20 @@ RSpec.describe Legion::Extensions::Agentic::Learning::Fermentation::Helpers::Fer
50
62
  it 'returns nil for unknown substrate' do
51
63
  expect(engine.catalyze(substrate_id: 'x', catalyst_type: :analogy)).to be_nil
52
64
  end
65
+
66
+ it 'rejects invalid catalyst_type' do
67
+ sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive)
68
+ expect(engine.catalyze(substrate_id: sub.id, catalyst_type: :magic)).to be_nil
69
+ end
70
+
71
+ it 'accepts all valid CATALYST_TYPES' do
72
+ constants = Legion::Extensions::Agentic::Learning::Fermentation::Helpers::Constants
73
+ sub = engine.create_substrate(substrate_type: :raw_idea, domain: :cognitive, potency: 0.1)
74
+ constants::CATALYST_TYPES.each do |ct|
75
+ result = engine.catalyze(substrate_id: sub.id, catalyst_type: ct)
76
+ expect(result).not_to be_nil
77
+ end
78
+ end
53
79
  end
54
80
 
55
81
  describe '#ferment_all!' do
data/spec/spec_helper.rb CHANGED
@@ -1,41 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/setup'
4
+ require 'legion/logging'
5
+ require 'legion/settings'
6
+ require 'legion/cache/helper'
7
+ require 'legion/crypt/helper'
8
+ require 'legion/data/helper'
9
+ require 'legion/json/helper'
10
+ require 'legion/transport'
4
11
 
5
12
  module Legion
6
- module Logging
7
- def self.debug(_msg); end
8
- def self.info(_msg); end
9
- def self.warn(_msg); end
10
- def self.error(_msg); end
11
- def self.fatal(_msg); end
12
- end
13
-
14
13
  module Extensions
15
- module Core
16
- def self.extended(_base); end
17
- end
18
-
19
14
  module Helpers
20
15
  module Lex
21
- def self.included(_base); end
16
+ include Legion::Logging::Helper
17
+ include Legion::Settings::Helper
18
+ include Legion::Cache::Helper
19
+ include Legion::Crypt::Helper
20
+ include Legion::Data::Helper
21
+ include Legion::JSON::Helper
22
+ include Legion::Transport::Helper
22
23
  end
23
24
  end
24
- end
25
- end
26
25
 
27
- # rubocop:disable Lint/EmptyClass, Style/OneClassPerFile
28
- module Legion
29
- module Extensions
30
26
  module Actors
31
- class Every; end
32
- class Once; end
27
+ class Every
28
+ include Helpers::Lex
29
+ end
30
+
31
+ class Once
32
+ include Helpers::Lex
33
+ end
33
34
  end
34
35
  end
35
36
  end
36
37
  $LOADED_FEATURES << 'legion/extensions/actors/every'
37
38
  $LOADED_FEATURES << 'legion/extensions/actors/once'
38
- # rubocop:enable Lint/EmptyClass, Style/OneClassPerFile
39
39
 
40
40
  require 'legion/extensions/agentic/learning'
41
41