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,223 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Reaction do
4
+ let(:default_activation) { Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Constants::ACTIVATION_ENERGY }
5
+
6
+ subject(:reaction) { described_class.new(reaction_type: :synthesis, reactants: %w[idea_a idea_b]) }
7
+
8
+ describe '#initialize' do
9
+ it 'assigns a uuid id' do
10
+ expect(reaction.id).to match(/\A[0-9a-f-]{36}\z/)
11
+ end
12
+
13
+ it 'assigns reaction_type' do
14
+ expect(reaction.reaction_type).to eq(:synthesis)
15
+ end
16
+
17
+ it 'assigns reactants as array' do
18
+ expect(reaction.reactants).to eq(%w[idea_a idea_b])
19
+ end
20
+
21
+ it 'defaults activation_energy to ACTIVATION_ENERGY' do
22
+ expect(reaction.activation_energy).to eq(default_activation)
23
+ end
24
+
25
+ it 'defaults yield_value to 0.0' do
26
+ expect(reaction.yield_value).to eq(0.0)
27
+ end
28
+
29
+ it 'defaults catalyzed to false' do
30
+ expect(reaction.catalyzed).to be false
31
+ end
32
+
33
+ it 'defaults catalyst_id to nil' do
34
+ expect(reaction.catalyst_id).to be_nil
35
+ end
36
+
37
+ it 'defaults completed to false' do
38
+ expect(reaction.completed).to be false
39
+ end
40
+
41
+ it 'records created_at' do
42
+ expect(reaction.created_at).to be_a(Time)
43
+ end
44
+
45
+ it 'accepts custom activation_energy' do
46
+ r = described_class.new(reaction_type: :exchange, reactants: [], activation_energy: 0.3)
47
+ expect(r.activation_energy).to eq(0.3)
48
+ end
49
+
50
+ it 'clamps activation_energy to 0..1' do
51
+ r = described_class.new(reaction_type: :exchange, reactants: [], activation_energy: 2.0)
52
+ expect(r.activation_energy).to eq(1.0)
53
+ end
54
+
55
+ it 'wraps single reactant string in array' do
56
+ r = described_class.new(reaction_type: :synthesis, reactants: 'single_idea')
57
+ expect(r.reactants).to eq(['single_idea'])
58
+ end
59
+ end
60
+
61
+ describe '#apply_catalyst!' do
62
+ let(:catalyst) do
63
+ Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Catalyst.new(
64
+ catalyst_type: :insight, domain: :reasoning, potency: 0.8, specificity: 0.5
65
+ )
66
+ end
67
+
68
+ it 'reduces activation_energy' do
69
+ original = reaction.activation_energy
70
+ reaction.apply_catalyst!(catalyst)
71
+ expect(reaction.activation_energy).to be < original
72
+ end
73
+
74
+ it 'sets catalyzed to true' do
75
+ reaction.apply_catalyst!(catalyst)
76
+ expect(reaction.catalyzed).to be true
77
+ end
78
+
79
+ it 'records catalyst_id' do
80
+ reaction.apply_catalyst!(catalyst)
81
+ expect(reaction.catalyst_id).to eq(catalyst.id)
82
+ end
83
+
84
+ it 'increments catalyst uses_count' do
85
+ expect { reaction.apply_catalyst!(catalyst) }.to change(catalyst, :uses_count).by(1)
86
+ end
87
+
88
+ it 'does not reduce activation_energy below 0.0' do
89
+ strong = Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Catalyst.new(
90
+ catalyst_type: :insight, domain: :d, potency: 1.0, specificity: 1.0
91
+ )
92
+ 10.times { reaction.apply_catalyst!(strong) }
93
+ expect(reaction.activation_energy).to eq(0.0)
94
+ end
95
+ end
96
+
97
+ describe '#attempt!' do
98
+ context 'when energy_input >= activation_energy' do
99
+ it 'returns true' do
100
+ expect(reaction.attempt!(0.8)).to be true
101
+ end
102
+
103
+ it 'sets completed to true' do
104
+ reaction.attempt!(0.8)
105
+ expect(reaction.completed).to be true
106
+ end
107
+
108
+ it 'calculates yield_value > 0.5' do
109
+ reaction.attempt!(1.0)
110
+ expect(reaction.yield_value).to be > 0.5
111
+ end
112
+
113
+ it 'returns maximum yield on full surplus (activation_energy=0)' do
114
+ r = described_class.new(reaction_type: :synthesis, reactants: [], activation_energy: 0.0)
115
+ r.attempt!(1.0)
116
+ expect(r.yield_value).to eq(1.0)
117
+ end
118
+
119
+ it 'returns minimum passing yield at exact threshold' do
120
+ reaction.attempt!(reaction.activation_energy)
121
+ expect(reaction.yield_value).to be_within(0.0001).of(0.5)
122
+ end
123
+ end
124
+
125
+ context 'when energy_input < activation_energy' do
126
+ it 'returns false' do
127
+ expect(reaction.attempt!(0.1)).to be false
128
+ end
129
+
130
+ it 'leaves completed as false' do
131
+ reaction.attempt!(0.1)
132
+ expect(reaction.completed).to be false
133
+ end
134
+
135
+ it 'leaves yield_value at 0.0' do
136
+ reaction.attempt!(0.1)
137
+ expect(reaction.yield_value).to eq(0.0)
138
+ end
139
+ end
140
+
141
+ it 'returns false if already completed' do
142
+ reaction.attempt!(1.0)
143
+ expect(reaction.attempt!(1.0)).to be false
144
+ end
145
+ end
146
+
147
+ describe '#complete?' do
148
+ it 'returns false before attempt' do
149
+ expect(reaction.complete?).to be false
150
+ end
151
+
152
+ it 'returns true after successful attempt' do
153
+ reaction.attempt!(1.0)
154
+ expect(reaction.complete?).to be true
155
+ end
156
+ end
157
+
158
+ describe '#catalyzed?' do
159
+ it 'returns false when no catalyst applied' do
160
+ expect(reaction.catalyzed?).to be false
161
+ end
162
+
163
+ it 'returns true after catalyst applied' do
164
+ catalyst = Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Catalyst.new(
165
+ catalyst_type: :insight, domain: :d
166
+ )
167
+ reaction.apply_catalyst!(catalyst)
168
+ expect(reaction.catalyzed?).to be true
169
+ end
170
+ end
171
+
172
+ describe '#spontaneous?' do
173
+ it 'returns false when not completed' do
174
+ expect(reaction.spontaneous?).to be false
175
+ end
176
+
177
+ it 'returns true when completed without catalyst' do
178
+ reaction.attempt!(1.0)
179
+ expect(reaction.spontaneous?).to be true
180
+ end
181
+
182
+ it 'returns false when completed with catalyst' do
183
+ catalyst = Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Catalyst.new(
184
+ catalyst_type: :insight, domain: :d
185
+ )
186
+ reaction.apply_catalyst!(catalyst)
187
+ reaction.attempt!(1.0)
188
+ expect(reaction.spontaneous?).to be false
189
+ end
190
+ end
191
+
192
+ describe '#yield_label' do
193
+ it 'returns :negligible before completion' do
194
+ expect(reaction.yield_label).to eq(:negligible)
195
+ end
196
+
197
+ it 'returns :excellent for high yield (activation_energy=0, full surplus)' do
198
+ r = described_class.new(reaction_type: :synthesis, reactants: [], activation_energy: 0.0)
199
+ r.attempt!(1.0)
200
+ expect(r.yield_label).to eq(:excellent)
201
+ end
202
+
203
+ it 'returns :fair for moderate yield' do
204
+ r = described_class.new(reaction_type: :synthesis, reactants: [], activation_energy: 0.1)
205
+ r.attempt!(0.2)
206
+ expect(%i[fair good poor excellent negligible]).to include(r.yield_label)
207
+ end
208
+ end
209
+
210
+ describe '#to_h' do
211
+ it 'includes all required keys' do
212
+ h = reaction.to_h
213
+ expect(h).to include(:id, :reaction_type, :reactants, :activation_energy,
214
+ :yield_value, :yield_label, :catalyzed, :catalyst_id,
215
+ :completed, :spontaneous, :created_at)
216
+ end
217
+
218
+ it 'reflects completed state' do
219
+ reaction.attempt!(1.0)
220
+ expect(reaction.to_h[:completed]).to be true
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Catalyst::Runners::CognitiveCatalyst do
4
+ let(:client) { Legion::Extensions::Agentic::Learning::Catalyst::Client.new }
5
+ let(:engine) { Legion::Extensions::Agentic::Learning::Catalyst::Helpers::CatalystEngine.new }
6
+
7
+ def create_catalyst(client_instance = client, **)
8
+ defaults = { catalyst_type: :insight, domain: :reasoning, engine: engine }
9
+ client_instance.create_catalyst(**defaults, **)
10
+ end
11
+
12
+ def create_reaction(client_instance = client, **)
13
+ defaults = { reaction_type: :synthesis, reactants: %w[idea_a idea_b], engine: engine }
14
+ client_instance.create_reaction(**defaults, **)
15
+ end
16
+
17
+ describe '#create_catalyst' do
18
+ it 'returns success: true' do
19
+ result = create_catalyst
20
+ expect(result[:success]).to be true
21
+ end
22
+
23
+ it 'includes catalyst hash in result' do
24
+ result = create_catalyst
25
+ expect(result[:catalyst]).to include(:id, :catalyst_type, :domain, :potency)
26
+ end
27
+
28
+ it 'uses default potency 0.5 when not specified' do
29
+ result = create_catalyst
30
+ expect(result[:catalyst][:potency]).to eq(0.5)
31
+ end
32
+
33
+ it 'uses custom potency when provided' do
34
+ result = create_catalyst(potency: 0.9)
35
+ expect(result[:catalyst][:potency]).to eq(0.9)
36
+ end
37
+
38
+ it 'uses custom specificity when provided' do
39
+ result = create_catalyst(specificity: 0.8)
40
+ expect(result[:catalyst][:specificity]).to eq(0.8)
41
+ end
42
+
43
+ it 'accepts all valid catalyst types' do
44
+ Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Constants::CATALYST_TYPES.each do |type|
45
+ result = client.create_catalyst(catalyst_type: type, domain: :d, engine: engine)
46
+ expect(result[:success]).to be true
47
+ end
48
+ end
49
+
50
+ it 'returns success: false for invalid catalyst_type' do
51
+ result = client.create_catalyst(catalyst_type: :invalid, domain: :d, engine: engine)
52
+ expect(result[:success]).to be false
53
+ expect(result[:reason]).to be_a(String)
54
+ end
55
+ end
56
+
57
+ describe '#create_reaction' do
58
+ it 'returns success: true' do
59
+ result = create_reaction
60
+ expect(result[:success]).to be true
61
+ end
62
+
63
+ it 'includes reaction hash in result' do
64
+ result = create_reaction
65
+ expect(result[:reaction]).to include(:id, :reaction_type, :reactants, :activation_energy)
66
+ end
67
+
68
+ it 'accepts all valid reaction types' do
69
+ Legion::Extensions::Agentic::Learning::Catalyst::Helpers::Constants::REACTION_TYPES.each do |type|
70
+ result = client.create_reaction(reaction_type: type, reactants: ['x'], engine: engine)
71
+ expect(result[:success]).to be true
72
+ end
73
+ end
74
+
75
+ it 'returns success: false for invalid reaction_type' do
76
+ result = client.create_reaction(reaction_type: :explode, reactants: [], engine: engine)
77
+ expect(result[:success]).to be false
78
+ end
79
+
80
+ it 'uses custom activation_energy' do
81
+ result = create_reaction(activation_energy: 0.3)
82
+ expect(result[:reaction][:activation_energy]).to eq(0.3)
83
+ end
84
+ end
85
+
86
+ describe '#apply_catalyst' do
87
+ it 'lowers activation energy and returns success' do
88
+ cat = create_catalyst
89
+ rxn = create_reaction
90
+ result = client.apply_catalyst(catalyst_id: cat[:catalyst][:id],
91
+ reaction_id: rxn[:reaction][:id],
92
+ engine: engine)
93
+ expect(result[:success]).to be true
94
+ expect(result[:activation_energy]).to be < 0.6
95
+ end
96
+
97
+ it 'returns failure for unknown catalyst_id' do
98
+ rxn = create_reaction
99
+ result = client.apply_catalyst(catalyst_id: 'bad',
100
+ reaction_id: rxn[:reaction][:id],
101
+ engine: engine)
102
+ expect(result[:success]).to be false
103
+ end
104
+
105
+ it 'returns failure for unknown reaction_id' do
106
+ cat = create_catalyst
107
+ result = client.apply_catalyst(catalyst_id: cat[:catalyst][:id],
108
+ reaction_id: 'bad',
109
+ engine: engine)
110
+ expect(result[:success]).to be false
111
+ end
112
+ end
113
+
114
+ describe '#attempt_reaction' do
115
+ it 'completes reaction with sufficient energy' do
116
+ rxn = create_reaction
117
+ result = client.attempt_reaction(reaction_id: rxn[:reaction][:id],
118
+ energy_input: 1.0,
119
+ engine: engine)
120
+ expect(result[:completed]).to be true
121
+ end
122
+
123
+ it 'does not complete with insufficient energy' do
124
+ rxn = create_reaction
125
+ result = client.attempt_reaction(reaction_id: rxn[:reaction][:id],
126
+ energy_input: 0.1,
127
+ engine: engine)
128
+ expect(result[:completed]).to be false
129
+ end
130
+
131
+ it 'includes yield data when completed' do
132
+ rxn = create_reaction
133
+ result = client.attempt_reaction(reaction_id: rxn[:reaction][:id],
134
+ energy_input: 1.0,
135
+ engine: engine)
136
+ expect(result).to include(:yield_value, :yield_label)
137
+ end
138
+
139
+ it 'returns not_found for unknown reaction' do
140
+ result = client.attempt_reaction(reaction_id: 'missing', energy_input: 1.0, engine: engine)
141
+ expect(result[:reason]).to eq(:not_found)
142
+ end
143
+ end
144
+
145
+ describe '#recharge' do
146
+ it 'increases catalyst potency' do
147
+ cat = create_catalyst(potency: 0.3)
148
+ result = client.recharge(catalyst_id: cat[:catalyst][:id], amount: 0.2, engine: engine)
149
+ expect(result[:success]).to be true
150
+ expect(result[:potency]).to be > 0.3
151
+ end
152
+
153
+ it 'returns failure for unknown catalyst' do
154
+ result = client.recharge(catalyst_id: 'bad', amount: 0.2, engine: engine)
155
+ expect(result[:success]).to be false
156
+ end
157
+ end
158
+
159
+ describe '#list_catalysts' do
160
+ it 'returns success: true' do
161
+ result = client.list_catalysts(engine: engine)
162
+ expect(result[:success]).to be true
163
+ end
164
+
165
+ it 'returns empty list initially' do
166
+ result = client.list_catalysts(engine: engine)
167
+ expect(result[:count]).to eq(0)
168
+ end
169
+
170
+ it 'reflects created catalysts' do
171
+ create_catalyst
172
+ create_catalyst(catalyst_type: :analogy)
173
+ result = client.list_catalysts(engine: engine)
174
+ expect(result[:count]).to eq(2)
175
+ end
176
+
177
+ it 'includes catalyst hashes in the list' do
178
+ create_catalyst
179
+ result = client.list_catalysts(engine: engine)
180
+ expect(result[:catalysts].first).to include(:id, :catalyst_type, :potency)
181
+ end
182
+ end
183
+
184
+ describe '#catalyst_status' do
185
+ it 'returns success: true' do
186
+ result = client.catalyst_status(engine: engine)
187
+ expect(result[:success]).to be true
188
+ end
189
+
190
+ it 'includes report keys' do
191
+ result = client.catalyst_status(engine: engine)
192
+ expect(result).to include(:total_catalysts, :total_reactions, :completed,
193
+ :catalyzed_count, :catalyzed_rate, :avg_potency,
194
+ :powerful_count, :inert_count)
195
+ end
196
+
197
+ it 'reflects catalysts and reactions created' do
198
+ create_catalyst
199
+ create_reaction
200
+ result = client.catalyst_status(engine: engine)
201
+ expect(result[:total_catalysts]).to eq(1)
202
+ expect(result[:total_reactions]).to eq(1)
203
+ end
204
+
205
+ it 'shows catalyzed_rate 0.0 initially' do
206
+ result = client.catalyst_status(engine: engine)
207
+ expect(result[:catalyzed_rate]).to eq(0.0)
208
+ end
209
+
210
+ it 'reflects completed reactions in report' do
211
+ rxn = create_reaction
212
+ client.attempt_reaction(reaction_id: rxn[:reaction][:id], energy_input: 1.0, engine: engine)
213
+ result = client.catalyst_status(engine: engine)
214
+ expect(result[:completed]).to eq(1)
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Chrysalis::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'responds to create_chrysalis' do
7
+ expect(client).to respond_to(:create_chrysalis)
8
+ end
9
+
10
+ it 'responds to create_cocoon' do
11
+ expect(client).to respond_to(:create_cocoon)
12
+ end
13
+
14
+ it 'responds to spin' do
15
+ expect(client).to respond_to(:spin)
16
+ end
17
+
18
+ it 'responds to enclose' do
19
+ expect(client).to respond_to(:enclose)
20
+ end
21
+
22
+ it 'responds to incubate' do
23
+ expect(client).to respond_to(:incubate)
24
+ end
25
+
26
+ it 'responds to emerge' do
27
+ expect(client).to respond_to(:emerge)
28
+ end
29
+
30
+ it 'responds to disturb' do
31
+ expect(client).to respond_to(:disturb)
32
+ end
33
+
34
+ it 'responds to list_chrysalises' do
35
+ expect(client).to respond_to(:list_chrysalises)
36
+ end
37
+
38
+ it 'responds to metamorphosis_status' do
39
+ expect(client).to respond_to(:metamorphosis_status)
40
+ end
41
+
42
+ it 'exposes the engine as a MetamorphosisEngine' do
43
+ expect(client.engine).to be_a(Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::MetamorphosisEngine)
44
+ end
45
+
46
+ it 'uses the same engine for all calls by default' do
47
+ client.create_chrysalis(chrysalis_type: :silk, content: 'c1')
48
+ status = client.metamorphosis_status
49
+ expect(status[:total_chrysalises]).to eq(1)
50
+ end
51
+
52
+ describe 'full lifecycle via client default engine' do
53
+ it 'creates a chrysalis, encloses it, incubates it, and emerges it' do
54
+ cid = client.create_chrysalis(chrysalis_type: :silk, content: 'an insight')[:chrysalis][:id]
55
+ coc = client.create_cocoon(environment: 'forest')[:cocoon][:id]
56
+ client.enclose(chrysalis_id: cid, cocoon_id: coc)
57
+ 12.times { client.incubate(chrysalis_id: cid) }
58
+ result = client.emerge(chrysalis_id: cid)
59
+ expect(result[:stage]).to eq(:butterfly)
60
+ end
61
+
62
+ it 'reports metamorphosis status after activity' do
63
+ client.create_chrysalis(chrysalis_type: :leaf, content: 'leaf thought')
64
+ status = client.metamorphosis_status
65
+ expect(status[:total_chrysalises]).to eq(1)
66
+ end
67
+
68
+ it 'can disturb a cocoon and observe effects' do
69
+ cid = client.create_chrysalis(chrysalis_type: :underground, content: 'idea')[:chrysalis][:id]
70
+ coc = client.create_cocoon(environment: 'cave')[:cocoon][:id]
71
+ client.enclose(chrysalis_id: cid, cocoon_id: coc)
72
+ result = client.disturb(cocoon_id: coc, force: 1.0)
73
+ expect(result[:success]).to be true
74
+ end
75
+
76
+ it 'lists created chrysalises' do
77
+ client.create_chrysalis(chrysalis_type: :bark, content: 'a')
78
+ client.create_chrysalis(chrysalis_type: :paper, content: 'b')
79
+ result = client.list_chrysalises
80
+ expect(result[:count]).to eq(2)
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Chrysalis do
4
+ it 'has a version number' do
5
+ expect(Legion::Extensions::Agentic::Learning::Chrysalis::VERSION).not_to be_nil
6
+ end
7
+
8
+ it 'has a version that is a string' do
9
+ expect(Legion::Extensions::Agentic::Learning::Chrysalis::VERSION).to be_a(String)
10
+ end
11
+
12
+ it 'version is 0.1.0' do
13
+ expect(Legion::Extensions::Agentic::Learning::Chrysalis::VERSION).to eq('0.1.0')
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file intentionally tests the MetamorphosisEngine via focused unit scenarios
4
+ # previously covered by a now-replaced helper. See metamorphosis_engine_spec.rb for full coverage.
5
+
6
+ RSpec.describe 'MetamorphosisEngine capacity and butterfly tracking' do
7
+ let(:engine) { Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::MetamorphosisEngine.new }
8
+
9
+ it 'tracks butterflies separately from active chrysalises' do
10
+ cid = engine.create_chrysalis(chrysalis_type: :silk, content: 'idea')[:chrysalis][:id]
11
+ engine.force_emerge(chrysalis_id: cid)
12
+ expect(engine.butterflies.size).to eq(1)
13
+ report = engine.metamorphosis_report
14
+ expect(report[:butterflies_count]).to eq(1)
15
+ end
16
+
17
+ it 'counts premature butterflies in report' do
18
+ cid = engine.create_chrysalis(chrysalis_type: :paper, content: 'fragile')[:chrysalis][:id]
19
+ engine.force_emerge(chrysalis_id: cid)
20
+ report = engine.metamorphosis_report
21
+ expect(report[:premature_count]).to eq(1)
22
+ end
23
+
24
+ it 'returns 0 avg_beauty when no butterflies exist' do
25
+ engine.create_chrysalis(chrysalis_type: :bark, content: 'c')
26
+ expect(engine.metamorphosis_report[:avg_beauty]).to eq(0.0)
27
+ end
28
+
29
+ it 'calculates non-zero avg_progress after incubation' do
30
+ cid = engine.create_chrysalis(chrysalis_type: :leaf, content: 'c')[:chrysalis][:id]
31
+ coc = engine.create_cocoon(environment: 'forest')[:cocoon][:id]
32
+ engine.enclose(chrysalis_id: cid, cocoon_id: coc)
33
+ engine.incubate(chrysalis_id: cid)
34
+ expect(engine.metamorphosis_report[:avg_progress]).to be > 0.0
35
+ end
36
+
37
+ it 'incubate_all returns success: true even with no chrysalises' do
38
+ expect(engine.incubate_all![:success]).to be true
39
+ end
40
+
41
+ it 'disturb_cocoon with full force can trigger forced emergence' do
42
+ cid = engine.create_chrysalis(chrysalis_type: :underground, content: 'deep')[:chrysalis][:id]
43
+ coc = engine.create_cocoon(environment: 'cave')[:cocoon][:id]
44
+ engine.enclose(chrysalis_id: cid, cocoon_id: coc)
45
+ engine.disturb_cocoon(cocoon_id: coc, force: 1.0)
46
+ c = engine.instance_variable_get(:@chrysalises)[cid]
47
+ expect(c.butterfly?).to be true
48
+ end
49
+
50
+ it 'applies ideal cocoon modifier, increasing progress faster' do
51
+ cid = engine.create_chrysalis(chrysalis_type: :silk, content: 'c1')[:chrysalis][:id]
52
+ coc = engine.create_cocoon(environment: 'ideal', temperature: 0.55, humidity: 0.55)[:cocoon][:id]
53
+ engine.enclose(chrysalis_id: cid, cocoon_id: coc)
54
+ result = engine.incubate(chrysalis_id: cid)
55
+ expect(result[:progress]).to be > Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants::TRANSFORMATION_RATE
56
+ end
57
+ end