lex-agentic-learning 0.1.0

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 (192) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +12 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE +21 -0
  5. data/README.md +13 -0
  6. data/lex-agentic-learning.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/learning/anchoring/client.rb +26 -0
  8. data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor.rb +65 -0
  9. data/lib/legion/extensions/agentic/learning/anchoring/helpers/anchor_store.rb +132 -0
  10. data/lib/legion/extensions/agentic/learning/anchoring/helpers/constants.rb +31 -0
  11. data/lib/legion/extensions/agentic/learning/anchoring/runners/anchoring.rb +100 -0
  12. data/lib/legion/extensions/agentic/learning/anchoring/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/learning/anchoring.rb +19 -0
  14. data/lib/legion/extensions/agentic/learning/catalyst/client.rb +15 -0
  15. data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst.rb +87 -0
  16. data/lib/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine.rb +153 -0
  17. data/lib/legion/extensions/agentic/learning/catalyst/helpers/constants.rb +55 -0
  18. data/lib/legion/extensions/agentic/learning/catalyst/helpers/reaction.rb +87 -0
  19. data/lib/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst.rb +103 -0
  20. data/lib/legion/extensions/agentic/learning/catalyst/version.rb +13 -0
  21. data/lib/legion/extensions/agentic/learning/catalyst.rb +22 -0
  22. data/lib/legion/extensions/agentic/learning/chrysalis/client.rb +22 -0
  23. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis.rb +137 -0
  24. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/cocoon.rb +89 -0
  25. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/constants.rb +49 -0
  26. data/lib/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine.rb +157 -0
  27. data/lib/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis.rb +129 -0
  28. data/lib/legion/extensions/agentic/learning/chrysalis/version.rb +13 -0
  29. data/lib/legion/extensions/agentic/learning/chrysalis.rb +21 -0
  30. data/lib/legion/extensions/agentic/learning/curiosity/client.rb +28 -0
  31. data/lib/legion/extensions/agentic/learning/curiosity/helpers/constants.rb +30 -0
  32. data/lib/legion/extensions/agentic/learning/curiosity/helpers/gap_detector.rb +167 -0
  33. data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder.rb +73 -0
  34. data/lib/legion/extensions/agentic/learning/curiosity/helpers/wonder_store.rb +149 -0
  35. data/lib/legion/extensions/agentic/learning/curiosity/runners/curiosity.rb +163 -0
  36. data/lib/legion/extensions/agentic/learning/curiosity/version.rb +13 -0
  37. data/lib/legion/extensions/agentic/learning/curiosity.rb +21 -0
  38. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/client.rb +28 -0
  39. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants.rb +31 -0
  40. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine.rb +122 -0
  41. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap.rb +70 -0
  42. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity.rb +106 -0
  43. data/lib/legion/extensions/agentic/learning/epistemic_curiosity/version.rb +13 -0
  44. data/lib/legion/extensions/agentic/learning/epistemic_curiosity.rb +19 -0
  45. data/lib/legion/extensions/agentic/learning/fermentation/client.rb +19 -0
  46. data/lib/legion/extensions/agentic/learning/fermentation/helpers/batch.rb +75 -0
  47. data/lib/legion/extensions/agentic/learning/fermentation/helpers/constants.rb +78 -0
  48. data/lib/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine.rb +147 -0
  49. data/lib/legion/extensions/agentic/learning/fermentation/helpers/substrate.rb +108 -0
  50. data/lib/legion/extensions/agentic/learning/fermentation/runners/cognitive_fermentation.rb +60 -0
  51. data/lib/legion/extensions/agentic/learning/fermentation/version.rb +13 -0
  52. data/lib/legion/extensions/agentic/learning/fermentation.rb +22 -0
  53. data/lib/legion/extensions/agentic/learning/habit/client.rb +26 -0
  54. data/lib/legion/extensions/agentic/learning/habit/helpers/action_sequence.rb +120 -0
  55. data/lib/legion/extensions/agentic/learning/habit/helpers/constants.rb +44 -0
  56. data/lib/legion/extensions/agentic/learning/habit/helpers/habit_store.rb +148 -0
  57. data/lib/legion/extensions/agentic/learning/habit/runners/habit.rb +86 -0
  58. data/lib/legion/extensions/agentic/learning/habit/version.rb +13 -0
  59. data/lib/legion/extensions/agentic/learning/habit.rb +19 -0
  60. data/lib/legion/extensions/agentic/learning/hebbian/actors/decay.rb +45 -0
  61. data/lib/legion/extensions/agentic/learning/hebbian/client.rb +29 -0
  62. data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly.rb +82 -0
  63. data/lib/legion/extensions/agentic/learning/hebbian/helpers/assembly_network.rb +190 -0
  64. data/lib/legion/extensions/agentic/learning/hebbian/helpers/constants.rb +50 -0
  65. data/lib/legion/extensions/agentic/learning/hebbian/helpers/unit.rb +94 -0
  66. data/lib/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly.rb +94 -0
  67. data/lib/legion/extensions/agentic/learning/hebbian/version.rb +13 -0
  68. data/lib/legion/extensions/agentic/learning/hebbian.rb +20 -0
  69. data/lib/legion/extensions/agentic/learning/learning_rate/client.rb +25 -0
  70. data/lib/legion/extensions/agentic/learning/learning_rate/helpers/constants.rb +35 -0
  71. data/lib/legion/extensions/agentic/learning/learning_rate/helpers/rate_model.rb +133 -0
  72. data/lib/legion/extensions/agentic/learning/learning_rate/runners/learning_rate.rb +85 -0
  73. data/lib/legion/extensions/agentic/learning/learning_rate/version.rb +13 -0
  74. data/lib/legion/extensions/agentic/learning/learning_rate.rb +18 -0
  75. data/lib/legion/extensions/agentic/learning/meta_learning/client.rb +27 -0
  76. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/constants.rb +46 -0
  77. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain.rb +85 -0
  78. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine.rb +202 -0
  79. data/lib/legion/extensions/agentic/learning/meta_learning/helpers/strategy.rb +62 -0
  80. data/lib/legion/extensions/agentic/learning/meta_learning/runners/meta_learning.rb +118 -0
  81. data/lib/legion/extensions/agentic/learning/meta_learning/version.rb +13 -0
  82. data/lib/legion/extensions/agentic/learning/meta_learning.rb +20 -0
  83. data/lib/legion/extensions/agentic/learning/plasticity/client.rb +15 -0
  84. data/lib/legion/extensions/agentic/learning/plasticity/helpers/constants.rb +45 -0
  85. data/lib/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway.rb +85 -0
  86. data/lib/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine.rb +130 -0
  87. data/lib/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity.rb +85 -0
  88. data/lib/legion/extensions/agentic/learning/plasticity/version.rb +13 -0
  89. data/lib/legion/extensions/agentic/learning/plasticity.rb +19 -0
  90. data/lib/legion/extensions/agentic/learning/preference_learning/actors/decay.rb +45 -0
  91. data/lib/legion/extensions/agentic/learning/preference_learning/client.rb +28 -0
  92. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/constants.rb +35 -0
  93. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/option.rb +78 -0
  94. data/lib/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine.rb +121 -0
  95. data/lib/legion/extensions/agentic/learning/preference_learning/runners/preference_learning.rb +84 -0
  96. data/lib/legion/extensions/agentic/learning/preference_learning/version.rb +13 -0
  97. data/lib/legion/extensions/agentic/learning/preference_learning.rb +19 -0
  98. data/lib/legion/extensions/agentic/learning/procedural/client.rb +19 -0
  99. data/lib/legion/extensions/agentic/learning/procedural/helpers/constants.rb +46 -0
  100. data/lib/legion/extensions/agentic/learning/procedural/helpers/learning_engine.rb +160 -0
  101. data/lib/legion/extensions/agentic/learning/procedural/helpers/production.rb +66 -0
  102. data/lib/legion/extensions/agentic/learning/procedural/helpers/skill.rb +101 -0
  103. data/lib/legion/extensions/agentic/learning/procedural/runners/procedural_learning.rb +96 -0
  104. data/lib/legion/extensions/agentic/learning/procedural/version.rb +13 -0
  105. data/lib/legion/extensions/agentic/learning/procedural.rb +20 -0
  106. data/lib/legion/extensions/agentic/learning/scaffolding/client.rb +26 -0
  107. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/constants.rb +42 -0
  108. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffold.rb +136 -0
  109. data/lib/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine.rb +112 -0
  110. data/lib/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding.rb +107 -0
  111. data/lib/legion/extensions/agentic/learning/scaffolding/version.rb +13 -0
  112. data/lib/legion/extensions/agentic/learning/scaffolding.rb +19 -0
  113. data/lib/legion/extensions/agentic/learning/version.rb +11 -0
  114. data/lib/legion/extensions/agentic/learning.rb +31 -0
  115. data/spec/legion/extensions/agentic/learning/anchoring/client_spec.rb +32 -0
  116. data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_spec.rb +130 -0
  117. data/spec/legion/extensions/agentic/learning/anchoring/helpers/anchor_store_spec.rb +201 -0
  118. data/spec/legion/extensions/agentic/learning/anchoring/helpers/constants_spec.rb +63 -0
  119. data/spec/legion/extensions/agentic/learning/anchoring/runners/anchoring_spec.rb +199 -0
  120. data/spec/legion/extensions/agentic/learning/catalyst/client_spec.rb +58 -0
  121. data/spec/legion/extensions/agentic/learning/catalyst/cognitive_catalyst_spec.rb +49 -0
  122. data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_engine_spec.rb +263 -0
  123. data/spec/legion/extensions/agentic/learning/catalyst/helpers/catalyst_spec.rb +214 -0
  124. data/spec/legion/extensions/agentic/learning/catalyst/helpers/reaction_spec.rb +223 -0
  125. data/spec/legion/extensions/agentic/learning/catalyst/runners/cognitive_catalyst_spec.rb +217 -0
  126. data/spec/legion/extensions/agentic/learning/chrysalis/client_spec.rb +83 -0
  127. data/spec/legion/extensions/agentic/learning/chrysalis/cognitive_chrysalis_spec.rb +15 -0
  128. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_engine_spec.rb +57 -0
  129. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/chrysalis_spec.rb +305 -0
  130. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/cocoon_spec.rb +206 -0
  131. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/constants_spec.rb +109 -0
  132. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphic_cycle_spec.rb +76 -0
  133. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/metamorphosis_engine_spec.rb +247 -0
  134. data/spec/legion/extensions/agentic/learning/chrysalis/helpers/transformation_phase_spec.rb +98 -0
  135. data/spec/legion/extensions/agentic/learning/chrysalis/runners/cognitive_chrysalis_spec.rb +180 -0
  136. data/spec/legion/extensions/agentic/learning/chrysalis/runners/reporting_spec.rb +81 -0
  137. data/spec/legion/extensions/agentic/learning/chrysalis/runners/transformation_spec.rb +74 -0
  138. data/spec/legion/extensions/agentic/learning/curiosity/client_spec.rb +27 -0
  139. data/spec/legion/extensions/agentic/learning/curiosity/helpers/gap_detector_spec.rb +118 -0
  140. data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_spec.rb +130 -0
  141. data/spec/legion/extensions/agentic/learning/curiosity/helpers/wonder_store_spec.rb +136 -0
  142. data/spec/legion/extensions/agentic/learning/curiosity/runners/curiosity_spec.rb +159 -0
  143. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/client_spec.rb +47 -0
  144. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/constants_spec.rb +45 -0
  145. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/curiosity_engine_spec.rb +229 -0
  146. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/helpers/knowledge_gap_spec.rb +188 -0
  147. data/spec/legion/extensions/agentic/learning/epistemic_curiosity/runners/epistemic_curiosity_spec.rb +175 -0
  148. data/spec/legion/extensions/agentic/learning/fermentation/client_spec.rb +36 -0
  149. data/spec/legion/extensions/agentic/learning/fermentation/helpers/batch_spec.rb +72 -0
  150. data/spec/legion/extensions/agentic/learning/fermentation/helpers/fermentation_engine_spec.rb +138 -0
  151. data/spec/legion/extensions/agentic/learning/fermentation/helpers/substrate_spec.rb +146 -0
  152. data/spec/legion/extensions/agentic/learning/habit/client_spec.rb +50 -0
  153. data/spec/legion/extensions/agentic/learning/habit/helpers/action_sequence_spec.rb +276 -0
  154. data/spec/legion/extensions/agentic/learning/habit/helpers/constants_spec.rb +115 -0
  155. data/spec/legion/extensions/agentic/learning/habit/helpers/habit_store_spec.rb +274 -0
  156. data/spec/legion/extensions/agentic/learning/habit/runners/habit_spec.rb +228 -0
  157. data/spec/legion/extensions/agentic/learning/hebbian/client_spec.rb +38 -0
  158. data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_network_spec.rb +142 -0
  159. data/spec/legion/extensions/agentic/learning/hebbian/helpers/assembly_spec.rb +89 -0
  160. data/spec/legion/extensions/agentic/learning/hebbian/helpers/unit_spec.rb +119 -0
  161. data/spec/legion/extensions/agentic/learning/hebbian/runners/hebbian_assembly_spec.rb +109 -0
  162. data/spec/legion/extensions/agentic/learning/learning_rate/client_spec.rb +51 -0
  163. data/spec/legion/extensions/agentic/learning/learning_rate/helpers/constants_spec.rb +29 -0
  164. data/spec/legion/extensions/agentic/learning/learning_rate/helpers/rate_model_spec.rb +151 -0
  165. data/spec/legion/extensions/agentic/learning/learning_rate/runners/learning_rate_spec.rb +92 -0
  166. data/spec/legion/extensions/agentic/learning/meta_learning/client_spec.rb +27 -0
  167. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/constants_spec.rb +43 -0
  168. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/learning_domain_spec.rb +146 -0
  169. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/meta_learning_engine_spec.rb +309 -0
  170. data/spec/legion/extensions/agentic/learning/meta_learning/helpers/strategy_spec.rb +82 -0
  171. data/spec/legion/extensions/agentic/learning/meta_learning/runners/meta_learning_spec.rb +185 -0
  172. data/spec/legion/extensions/agentic/learning/plasticity/helpers/constants_spec.rb +54 -0
  173. data/spec/legion/extensions/agentic/learning/plasticity/helpers/neural_pathway_spec.rb +136 -0
  174. data/spec/legion/extensions/agentic/learning/plasticity/helpers/plasticity_engine_spec.rb +157 -0
  175. data/spec/legion/extensions/agentic/learning/plasticity/runners/cognitive_plasticity_spec.rb +83 -0
  176. data/spec/legion/extensions/agentic/learning/preference_learning/client_spec.rb +17 -0
  177. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/constants_spec.rb +67 -0
  178. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/option_spec.rb +104 -0
  179. data/spec/legion/extensions/agentic/learning/preference_learning/helpers/preference_engine_spec.rb +151 -0
  180. data/spec/legion/extensions/agentic/learning/preference_learning/runners/preference_learning_spec.rb +86 -0
  181. data/spec/legion/extensions/agentic/learning/procedural/client_spec.rb +22 -0
  182. data/spec/legion/extensions/agentic/learning/procedural/helpers/learning_engine_spec.rb +135 -0
  183. data/spec/legion/extensions/agentic/learning/procedural/helpers/production_spec.rb +66 -0
  184. data/spec/legion/extensions/agentic/learning/procedural/helpers/skill_spec.rb +102 -0
  185. data/spec/legion/extensions/agentic/learning/procedural/runners/procedural_learning_spec.rb +94 -0
  186. data/spec/legion/extensions/agentic/learning/scaffolding/client_spec.rb +20 -0
  187. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/constants_spec.rb +36 -0
  188. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffold_spec.rb +187 -0
  189. data/spec/legion/extensions/agentic/learning/scaffolding/helpers/scaffolding_engine_spec.rb +159 -0
  190. data/spec/legion/extensions/agentic/learning/scaffolding/runners/cognitive_scaffolding_spec.rb +163 -0
  191. data/spec/spec_helper.rb +46 -0
  192. metadata +277 -0
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/meta_learning/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Learning::MetaLearning::Runners::MetaLearning do
6
+ let(:client) { Legion::Extensions::Agentic::Learning::MetaLearning::Client.new }
7
+
8
+ let(:domain_result) { client.create_learning_domain(name: 'ruby') }
9
+ let(:domain_id) { domain_result[:id] }
10
+ let(:strategy_result) { client.register_learning_strategy(name: 'flash_cards', strategy_type: :repetition) }
11
+ let(:strategy_id) { strategy_result[:id] }
12
+
13
+ describe '#create_learning_domain' do
14
+ it 'returns a hash with id and name' do
15
+ result = client.create_learning_domain(name: 'python')
16
+ expect(result[:id]).to match(/\A[0-9a-f-]{36}\z/)
17
+ expect(result[:name]).to eq('python')
18
+ end
19
+
20
+ it 'applies custom learning rate' do
21
+ result = client.create_learning_domain(name: 'go', learning_rate: 0.2)
22
+ expect(result[:learning_rate]).to be_within(0.0001).of(0.2)
23
+ end
24
+
25
+ it 'accepts related_domains array' do
26
+ result = client.create_learning_domain(name: 'typescript', related_domains: ['javascript'])
27
+ expect(result[:related_domains]).to include('javascript')
28
+ end
29
+
30
+ it 'returns error hash on limit reached' do
31
+ stub_const('Legion::Extensions::Agentic::Learning::MetaLearning::Helpers::Constants::MAX_DOMAINS', 0)
32
+ result = client.create_learning_domain(name: 'test')
33
+ expect(result[:error]).to eq(:limit_reached)
34
+ end
35
+ end
36
+
37
+ describe '#register_learning_strategy' do
38
+ it 'returns a hash with id and name' do
39
+ result = client.register_learning_strategy(name: 'analogy', strategy_type: :analogy)
40
+ expect(result[:id]).to match(/\A[0-9a-f-]{36}\z/)
41
+ expect(result[:name]).to eq('analogy')
42
+ end
43
+
44
+ it 'returns error for invalid strategy_type' do
45
+ result = client.register_learning_strategy(name: 'bad', strategy_type: :invalid)
46
+ expect(result[:error]).to eq(:invalid_strategy_type)
47
+ end
48
+ end
49
+
50
+ describe '#record_learning_episode' do
51
+ it 'records a success and returns episode hash' do
52
+ result = client.record_learning_episode(domain_id: domain_id, success: true)
53
+ expect(result[:success]).to be true
54
+ expect(result[:domain_name]).to eq('ruby')
55
+ end
56
+
57
+ it 'records a failure' do
58
+ result = client.record_learning_episode(domain_id: domain_id, success: false)
59
+ expect(result[:success]).to be false
60
+ end
61
+
62
+ it 'returns error for unknown domain' do
63
+ result = client.record_learning_episode(domain_id: 'bad', success: true)
64
+ expect(result[:error]).to eq(:domain_not_found)
65
+ end
66
+
67
+ it 'accepts strategy_id' do
68
+ sid = strategy_id
69
+ result = client.record_learning_episode(domain_id: domain_id, strategy_id: sid, success: true)
70
+ expect(result[:strategy_id]).to eq(sid)
71
+ end
72
+ end
73
+
74
+ describe '#recommend_learning_strategy' do
75
+ it 'returns no_data when no strategy history' do
76
+ result = client.recommend_learning_strategy(domain_id: domain_id)
77
+ expect(result[:reason]).to eq(:no_data)
78
+ end
79
+
80
+ it 'recommends best strategy after episodes' do
81
+ sid = strategy_id
82
+ did = domain_id
83
+ 3.times { client.record_learning_episode(domain_id: did, strategy_id: sid, success: true) }
84
+ result = client.recommend_learning_strategy(domain_id: did)
85
+ expect(result[:recommendation]).to eq('flash_cards')
86
+ end
87
+
88
+ it 'returns error for unknown domain' do
89
+ result = client.recommend_learning_strategy(domain_id: 'bad')
90
+ expect(result[:error]).to eq(:domain_not_found)
91
+ end
92
+ end
93
+
94
+ describe '#check_transfer_learning' do
95
+ it 'returns not eligible when source proficiency is low' do
96
+ d1 = client.create_learning_domain(name: 'source')
97
+ d2 = client.create_learning_domain(name: 'target', related_domains: ['source'])
98
+ result = client.check_transfer_learning(source_domain_id: d1[:id], target_domain_id: d2[:id])
99
+ expect(result[:eligible]).to be false
100
+ end
101
+
102
+ it 'returns error for unknown domains' do
103
+ result = client.check_transfer_learning(source_domain_id: 'bad', target_domain_id: 'also-bad')
104
+ expect(result[:error]).to eq(:domain_not_found)
105
+ end
106
+ end
107
+
108
+ describe '#apply_transfer_bonus' do
109
+ it 'returns not applied when not eligible' do
110
+ d1 = client.create_learning_domain(name: 'src')
111
+ d2 = client.create_learning_domain(name: 'tgt', related_domains: ['src'])
112
+ result = client.apply_transfer_bonus(source_domain_id: d1[:id], target_domain_id: d2[:id])
113
+ expect(result[:applied]).to be false
114
+ end
115
+
116
+ it 'returns error for unknown domains' do
117
+ result = client.apply_transfer_bonus(source_domain_id: 'x', target_domain_id: 'y')
118
+ expect(result[:error]).to eq(:domain_not_found)
119
+ end
120
+ end
121
+
122
+ describe '#learning_domain_ranking' do
123
+ it 'returns ranking and count' do
124
+ client.create_learning_domain(name: 'a')
125
+ client.create_learning_domain(name: 'b')
126
+ result = client.learning_domain_ranking
127
+ expect(result[:ranking]).to be_an(Array)
128
+ expect(result[:count]).to eq(2)
129
+ end
130
+
131
+ it 'respects limit parameter' do
132
+ 5.times { |i| client.create_learning_domain(name: "d#{i}") }
133
+ result = client.learning_domain_ranking(limit: 2)
134
+ expect(result[:ranking].size).to eq(2)
135
+ end
136
+ end
137
+
138
+ describe '#learning_strategy_ranking' do
139
+ it 'returns ranking and count' do
140
+ client.register_learning_strategy(name: 's1', strategy_type: :repetition)
141
+ result = client.learning_strategy_ranking
142
+ expect(result[:ranking]).to be_an(Array)
143
+ expect(result[:count]).to eq(1)
144
+ end
145
+ end
146
+
147
+ describe '#learning_curve_report' do
148
+ it 'returns error for unknown domain' do
149
+ result = client.learning_curve_report(domain_id: 'bad')
150
+ expect(result[:error]).to eq(:domain_not_found)
151
+ end
152
+
153
+ it 'returns curve data for valid domain' do
154
+ did = domain_id
155
+ 2.times { client.record_learning_episode(domain_id: did, success: true) }
156
+ result = client.learning_curve_report(domain_id: did)
157
+ expect(result[:domain]).to eq('ruby')
158
+ expect(result[:curve].size).to eq(2)
159
+ end
160
+ end
161
+
162
+ describe '#update_meta_learning' do
163
+ it 'returns adapt, prune, and stats' do
164
+ result = client.update_meta_learning
165
+ expect(result).to include(:adapt, :prune, :stats)
166
+ end
167
+
168
+ it 'boosts rate for efficient domains' do
169
+ did = domain_id
170
+ 5.times { client.record_learning_episode(domain_id: did, success: true) }
171
+ result = client.update_meta_learning
172
+ expect(result[:adapt][:count]).to eq(1)
173
+ expect(result[:adapt][:adapted].first[:direction]).to eq(:boost)
174
+ end
175
+ end
176
+
177
+ describe '#meta_learning_stats' do
178
+ it 'returns engine stats hash' do
179
+ domain_id
180
+ result = client.meta_learning_stats
181
+ expect(result).to include(:domain_count, :strategy_count, :episode_count, :overall_efficiency)
182
+ expect(result[:domain_count]).to eq(1)
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Plasticity::Helpers::Constants do
4
+ let(:klass) { Class.new { include Legion::Extensions::Agentic::Learning::Plasticity::Helpers::Constants } }
5
+
6
+ describe 'PLASTICITY_LABELS' do
7
+ it 'is a frozen hash' do
8
+ expect(klass::PLASTICITY_LABELS).to be_a(Hash).and be_frozen
9
+ end
10
+
11
+ it 'covers the full 0..1 range' do
12
+ labels = klass::PLASTICITY_LABELS
13
+ [0.0, 0.3, 0.5, 0.7, 0.9].each do |val|
14
+ match = labels.find { |range, _| range.cover?(val) }
15
+ expect(match).not_to be_nil, "no label for #{val}"
16
+ end
17
+ end
18
+ end
19
+
20
+ describe 'STRENGTH_LABELS' do
21
+ it 'is a frozen hash' do
22
+ expect(klass::STRENGTH_LABELS).to be_a(Hash).and be_frozen
23
+ end
24
+ end
25
+
26
+ describe 'PATHWAY_TYPES' do
27
+ it 'is a frozen array of symbols' do
28
+ expect(klass::PATHWAY_TYPES).to be_a(Array).and be_frozen
29
+ expect(klass::PATHWAY_TYPES).to all(be_a(Symbol))
30
+ end
31
+
32
+ it 'includes synaptic' do
33
+ expect(klass::PATHWAY_TYPES).to include(:synaptic)
34
+ end
35
+ end
36
+
37
+ describe 'numeric constants' do
38
+ it 'has positive MAX_PATHWAYS' do
39
+ expect(klass::MAX_PATHWAYS).to be > 0
40
+ end
41
+
42
+ it 'has STRENGTHENING_RATE between 0 and 1' do
43
+ expect(klass::STRENGTHENING_RATE).to be_between(0.0, 1.0)
44
+ end
45
+
46
+ it 'has CRITICAL_PERIOD_MULTIPLIER > 1' do
47
+ expect(klass::CRITICAL_PERIOD_MULTIPLIER).to be > 1.0
48
+ end
49
+
50
+ it 'has PRUNING_THRESHOLD between 0 and 1' do
51
+ expect(klass::PRUNING_THRESHOLD).to be_between(0.0, 1.0)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Plasticity::Helpers::NeuralPathway do
4
+ subject(:pathway) { described_class.new(label: 'test_pathway') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a UUID id' do
8
+ expect(pathway.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets label' do
12
+ expect(pathway.label).to eq('test_pathway')
13
+ end
14
+
15
+ it 'defaults to synaptic type' do
16
+ expect(pathway.pathway_type).to eq(:synaptic)
17
+ end
18
+
19
+ it 'starts with default strength' do
20
+ expect(pathway.strength).to eq(0.3)
21
+ end
22
+
23
+ it 'starts with default learning rate as plasticity' do
24
+ default = Legion::Extensions::Agentic::Learning::Plasticity::Helpers::Constants::DEFAULT_LEARNING_RATE
25
+ expect(pathway.plasticity).to eq(default)
26
+ end
27
+
28
+ it 'starts with 0 activations' do
29
+ expect(pathway.activation_count).to eq(0)
30
+ end
31
+
32
+ it 'clamps initial strength to 0..1' do
33
+ high = described_class.new(label: 'h', initial_strength: 5.0)
34
+ expect(high.strength).to eq(1.0)
35
+ end
36
+ end
37
+
38
+ describe '#strengthen!' do
39
+ it 'increases strength' do
40
+ original = pathway.strength
41
+ pathway.strengthen!
42
+ expect(pathway.strength).to be > original
43
+ end
44
+
45
+ it 'increments activation_count' do
46
+ pathway.strengthen!
47
+ expect(pathway.activation_count).to eq(1)
48
+ end
49
+
50
+ it 'clamps at 1.0' do
51
+ p = described_class.new(label: 'strong', initial_strength: 0.99)
52
+ p.strengthen!(amount: 0.5)
53
+ expect(p.strength).to eq(1.0)
54
+ end
55
+
56
+ it 'applies critical period multiplier' do
57
+ p1 = described_class.new(label: 'normal')
58
+ p2 = described_class.new(label: 'critical')
59
+ p1.strengthen!(amount: 0.1)
60
+ p2.strengthen!(amount: 0.1, critical_period: true)
61
+ expect(p2.strength).to be > p1.strength
62
+ end
63
+
64
+ it 'returns self' do
65
+ expect(pathway.strengthen!).to eq(pathway)
66
+ end
67
+
68
+ it 'reduces plasticity (maturation)' do
69
+ original_plasticity = pathway.plasticity
70
+ pathway.strengthen!
71
+ expect(pathway.plasticity).to be < original_plasticity
72
+ end
73
+ end
74
+
75
+ describe '#weaken!' do
76
+ it 'decreases strength' do
77
+ original = pathway.strength
78
+ pathway.weaken!
79
+ expect(pathway.strength).to be < original
80
+ end
81
+
82
+ it 'clamps at 0.0' do
83
+ p = described_class.new(label: 'weak', initial_strength: 0.01)
84
+ p.weaken!(amount: 0.5)
85
+ expect(p.strength).to eq(0.0)
86
+ end
87
+ end
88
+
89
+ describe '#prune_candidate?' do
90
+ it 'is false for moderate strength' do
91
+ expect(pathway.prune_candidate?).to be false
92
+ end
93
+
94
+ it 'is true for very weak pathways' do
95
+ p = described_class.new(label: 'tiny', initial_strength: 0.1)
96
+ expect(p.prune_candidate?).to be true
97
+ end
98
+ end
99
+
100
+ describe '#rejuvenate!' do
101
+ it 'increases plasticity' do
102
+ pathway.strengthen!
103
+ reduced = pathway.plasticity
104
+ pathway.rejuvenate!(amount: 0.2)
105
+ expect(pathway.plasticity).to be > reduced
106
+ end
107
+
108
+ it 'clamps at 1.0' do
109
+ pathway.rejuvenate!(amount: 5.0)
110
+ expect(pathway.plasticity).to eq(1.0)
111
+ end
112
+ end
113
+
114
+ describe '#strength_label' do
115
+ it 'returns a symbol' do
116
+ expect(pathway.strength_label).to be_a(Symbol)
117
+ end
118
+ end
119
+
120
+ describe '#plasticity_label' do
121
+ it 'returns a symbol' do
122
+ expect(pathway.plasticity_label).to be_a(Symbol)
123
+ end
124
+ end
125
+
126
+ describe '#to_h' do
127
+ it 'includes all fields' do
128
+ hash = pathway.to_h
129
+ expect(hash).to include(
130
+ :id, :label, :pathway_type, :strength, :strength_label,
131
+ :plasticity, :plasticity_label, :activation_count,
132
+ :prune_candidate, :created_at
133
+ )
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Plasticity::Helpers::PlasticityEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ let(:pathway) { engine.create_pathway(label: 'test') }
7
+
8
+ describe '#create_pathway' do
9
+ it 'returns a NeuralPathway' do
10
+ expect(pathway).to be_a(Legion::Extensions::Agentic::Learning::Plasticity::Helpers::NeuralPathway)
11
+ end
12
+
13
+ it 'stores the pathway' do
14
+ pathway
15
+ expect(engine.to_h[:total_pathways]).to eq(1)
16
+ end
17
+ end
18
+
19
+ describe '#strengthen_pathway' do
20
+ it 'increases pathway strength' do
21
+ original = pathway.strength
22
+ engine.strengthen_pathway(pathway_id: pathway.id)
23
+ expect(pathway.strength).to be > original
24
+ end
25
+
26
+ it 'returns nil for unknown id' do
27
+ expect(engine.strengthen_pathway(pathway_id: 'fake')).to be_nil
28
+ end
29
+ end
30
+
31
+ describe '#weaken_pathway' do
32
+ it 'decreases pathway strength' do
33
+ original = pathway.strength
34
+ engine.weaken_pathway(pathway_id: pathway.id)
35
+ expect(pathway.strength).to be < original
36
+ end
37
+ end
38
+
39
+ describe '#rejuvenate_pathway' do
40
+ it 'increases pathway plasticity' do
41
+ engine.strengthen_pathway(pathway_id: pathway.id)
42
+ reduced = pathway.plasticity
43
+ engine.rejuvenate_pathway(pathway_id: pathway.id, amount: 0.2)
44
+ expect(pathway.plasticity).to be > reduced
45
+ end
46
+ end
47
+
48
+ describe '#critical_period' do
49
+ it 'starts as false' do
50
+ expect(engine.critical_period?).to be false
51
+ end
52
+
53
+ it 'can be entered and exited' do
54
+ engine.enter_critical_period!
55
+ expect(engine.critical_period?).to be true
56
+ engine.exit_critical_period!
57
+ expect(engine.critical_period?).to be false
58
+ end
59
+
60
+ it 'amplifies strengthening during critical period' do
61
+ p1 = engine.create_pathway(label: 'normal')
62
+ engine.strengthen_pathway(pathway_id: p1.id)
63
+ normal_strength = p1.strength
64
+
65
+ engine.enter_critical_period!
66
+ p2 = engine.create_pathway(label: 'boosted')
67
+ engine.strengthen_pathway(pathway_id: p2.id)
68
+ expect(p2.strength).to be > normal_strength
69
+ end
70
+ end
71
+
72
+ describe '#prune_weak_pathways!' do
73
+ it 'removes pathways below threshold' do
74
+ engine.create_pathway(label: 'weak', initial_strength: 0.05)
75
+ engine.create_pathway(label: 'strong', initial_strength: 0.8)
76
+ pruned = engine.prune_weak_pathways!
77
+ expect(pruned).to eq(1)
78
+ expect(engine.to_h[:total_pathways]).to eq(1)
79
+ end
80
+ end
81
+
82
+ describe '#pathways_by_type' do
83
+ it 'filters by type' do
84
+ engine.create_pathway(label: 'a', pathway_type: :structural)
85
+ engine.create_pathway(label: 'b', pathway_type: :synaptic)
86
+ result = engine.pathways_by_type(pathway_type: :structural)
87
+ expect(result.size).to eq(1)
88
+ end
89
+ end
90
+
91
+ describe '#strongest_pathways' do
92
+ it 'returns pathways sorted by strength descending' do
93
+ engine.create_pathway(label: 'weak', initial_strength: 0.2)
94
+ engine.create_pathway(label: 'strong', initial_strength: 0.9)
95
+ strongest = engine.strongest_pathways(limit: 1)
96
+ expect(strongest.first.label).to eq('strong')
97
+ end
98
+ end
99
+
100
+ describe '#weakest_pathways' do
101
+ it 'returns pathways sorted by strength ascending' do
102
+ engine.create_pathway(label: 'weak', initial_strength: 0.2)
103
+ engine.create_pathway(label: 'strong', initial_strength: 0.9)
104
+ weakest = engine.weakest_pathways(limit: 1)
105
+ expect(weakest.first.label).to eq('weak')
106
+ end
107
+ end
108
+
109
+ describe '#average_strength' do
110
+ it 'returns 0.0 with no pathways' do
111
+ expect(engine.average_strength).to eq(0.0)
112
+ end
113
+
114
+ it 'computes average across pathways' do
115
+ engine.create_pathway(label: 'a', initial_strength: 0.2)
116
+ engine.create_pathway(label: 'b', initial_strength: 0.8)
117
+ expect(engine.average_strength).to eq(0.5)
118
+ end
119
+ end
120
+
121
+ describe '#average_plasticity' do
122
+ it 'returns default with no pathways' do
123
+ default = Legion::Extensions::Agentic::Learning::Plasticity::Helpers::Constants::DEFAULT_LEARNING_RATE
124
+ expect(engine.average_plasticity).to eq(default)
125
+ end
126
+ end
127
+
128
+ describe '#plasticity_report' do
129
+ it 'includes all report fields' do
130
+ pathway
131
+ report = engine.plasticity_report
132
+ expect(report).to include(
133
+ :total_pathways, :critical_period, :average_strength,
134
+ :average_plasticity, :prune_candidates, :strongest
135
+ )
136
+ end
137
+ end
138
+
139
+ describe '#to_h' do
140
+ it 'includes summary fields' do
141
+ hash = engine.to_h
142
+ expect(hash).to include(
143
+ :total_pathways, :critical_period, :average_strength,
144
+ :average_plasticity, :prune_candidates
145
+ )
146
+ end
147
+ end
148
+
149
+ describe 'pruning' do
150
+ it 'prunes weakest pathway when limit reached' do
151
+ stub_const('Legion::Extensions::Agentic::Learning::Plasticity::Helpers::Constants::MAX_PATHWAYS', 3)
152
+ eng = described_class.new
153
+ 4.times { |i| eng.create_pathway(label: "p#{i}", initial_strength: (i + 1) * 0.2) }
154
+ expect(eng.to_h[:total_pathways]).to eq(3)
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Plasticity::Runners::CognitivePlasticity do
4
+ let(:client) { Legion::Extensions::Agentic::Learning::Plasticity::Client.new }
5
+
6
+ describe '#create_pathway' do
7
+ it 'returns success with pathway hash' do
8
+ result = client.create_pathway(label: 'test')
9
+ expect(result[:success]).to be true
10
+ expect(result[:pathway]).to include(:id, :label, :strength, :plasticity)
11
+ end
12
+ end
13
+
14
+ describe '#strengthen_pathway' do
15
+ it 'increases pathway strength' do
16
+ p = client.create_pathway(label: 'test')
17
+ pid = p[:pathway][:id]
18
+ result = client.strengthen_pathway(pathway_id: pid)
19
+ expect(result[:success]).to be true
20
+ expect(result[:pathway][:strength]).to be > 0.3
21
+ end
22
+
23
+ it 'returns failure for unknown id' do
24
+ result = client.strengthen_pathway(pathway_id: 'fake')
25
+ expect(result[:success]).to be false
26
+ end
27
+ end
28
+
29
+ describe '#weaken_pathway' do
30
+ it 'decreases pathway strength' do
31
+ p = client.create_pathway(label: 'test')
32
+ pid = p[:pathway][:id]
33
+ result = client.weaken_pathway(pathway_id: pid)
34
+ expect(result[:success]).to be true
35
+ expect(result[:pathway][:strength]).to be < 0.3
36
+ end
37
+ end
38
+
39
+ describe '#rejuvenate_pathway' do
40
+ it 'increases pathway plasticity' do
41
+ p = client.create_pathway(label: 'test')
42
+ pid = p[:pathway][:id]
43
+ client.strengthen_pathway(pathway_id: pid)
44
+ result = client.rejuvenate_pathway(pathway_id: pid, amount: 0.2)
45
+ expect(result[:success]).to be true
46
+ end
47
+ end
48
+
49
+ describe '#enter_critical_period / #exit_critical_period' do
50
+ it 'toggles critical period' do
51
+ result = client.enter_critical_period
52
+ expect(result[:critical_period]).to be true
53
+ result = client.exit_critical_period
54
+ expect(result[:critical_period]).to be false
55
+ end
56
+ end
57
+
58
+ describe '#prune_weak_pathways' do
59
+ it 'returns pruned count' do
60
+ client.create_pathway(label: 'weak', initial_strength: 0.05)
61
+ result = client.prune_weak_pathways
62
+ expect(result[:success]).to be true
63
+ expect(result[:pruned_count]).to eq(1)
64
+ end
65
+ end
66
+
67
+ describe '#strongest_pathways' do
68
+ it 'returns pathways array' do
69
+ client.create_pathway(label: 'a')
70
+ result = client.strongest_pathways
71
+ expect(result[:success]).to be true
72
+ expect(result[:pathways]).to be_a(Array)
73
+ end
74
+ end
75
+
76
+ describe '#plasticity_report' do
77
+ it 'returns a full report' do
78
+ result = client.plasticity_report
79
+ expect(result[:success]).to be true
80
+ expect(result[:report]).to include(:total_pathways, :average_plasticity)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/learning/preference_learning/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Learning::PreferenceLearning::Client do
6
+ let(:client) { described_class.new }
7
+
8
+ it 'responds to runner methods' do
9
+ expect(client).to respond_to(:register_preference_option)
10
+ expect(client).to respond_to(:record_preference_comparison)
11
+ expect(client).to respond_to(:predict_preference_outcome)
12
+ expect(client).to respond_to(:top_preferences_report)
13
+ expect(client).to respond_to(:preference_stability_report)
14
+ expect(client).to respond_to(:update_preference_learning)
15
+ expect(client).to respond_to(:preference_learning_stats)
16
+ end
17
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::PreferenceLearning::Helpers::Constants do
4
+ describe 'PREFERENCE_LABELS' do
5
+ subject(:labels) { described_class::PREFERENCE_LABELS }
6
+
7
+ it 'labels 0.9 as strongly_preferred' do
8
+ label = labels.find { |range, _| range.cover?(0.9) }&.last
9
+ expect(label).to eq(:strongly_preferred)
10
+ end
11
+
12
+ it 'labels 0.7 as preferred' do
13
+ label = labels.find { |range, _| range.cover?(0.7) }&.last
14
+ expect(label).to eq(:preferred)
15
+ end
16
+
17
+ it 'labels 0.5 as neutral' do
18
+ label = labels.find { |range, _| range.cover?(0.5) }&.last
19
+ expect(label).to eq(:neutral)
20
+ end
21
+
22
+ it 'labels 0.3 as disliked' do
23
+ label = labels.find { |range, _| range.cover?(0.3) }&.last
24
+ expect(label).to eq(:disliked)
25
+ end
26
+
27
+ it 'labels 0.1 as strongly_disliked' do
28
+ label = labels.find { |range, _| range.cover?(0.1) }&.last
29
+ expect(label).to eq(:strongly_disliked)
30
+ end
31
+ end
32
+
33
+ describe 'numeric constants' do
34
+ it 'defines MAX_OPTIONS' do
35
+ expect(described_class::MAX_OPTIONS).to eq(200)
36
+ end
37
+
38
+ it 'defines MAX_COMPARISONS' do
39
+ expect(described_class::MAX_COMPARISONS).to eq(1000)
40
+ end
41
+
42
+ it 'defines MAX_HISTORY' do
43
+ expect(described_class::MAX_HISTORY).to eq(500)
44
+ end
45
+
46
+ it 'defines DEFAULT_PREFERENCE as 0.5' do
47
+ expect(described_class::DEFAULT_PREFERENCE).to eq(0.5)
48
+ end
49
+
50
+ it 'defines PREFERENCE_FLOOR as 0.0' do
51
+ expect(described_class::PREFERENCE_FLOOR).to eq(0.0)
52
+ end
53
+
54
+ it 'defines PREFERENCE_CEILING as 1.0' do
55
+ expect(described_class::PREFERENCE_CEILING).to eq(1.0)
56
+ end
57
+
58
+ it 'WIN_BOOST is greater than LOSS_PENALTY inverted' do
59
+ expect(described_class::WIN_BOOST).to eq(0.08)
60
+ expect(described_class::LOSS_PENALTY).to eq(0.06)
61
+ end
62
+
63
+ it 'defines DECAY_RATE' do
64
+ expect(described_class::DECAY_RATE).to eq(0.01)
65
+ end
66
+ end
67
+ end