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,305 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Chrysalis do
4
+ subject(:chrysalis) { described_class.new(chrysalis_type: :silk, content: 'a new idea') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a uuid id' do
8
+ expect(chrysalis.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets chrysalis_type to the given symbol' do
12
+ expect(chrysalis.chrysalis_type).to eq(:silk)
13
+ end
14
+
15
+ it 'sets content to the given string' do
16
+ expect(chrysalis.content).to eq('a new idea')
17
+ end
18
+
19
+ it 'starts in :larva stage' do
20
+ expect(chrysalis.stage).to eq(:larva)
21
+ end
22
+
23
+ it 'starts with transformation_progress 0.0' do
24
+ expect(chrysalis.transformation_progress).to eq(0.0)
25
+ end
26
+
27
+ it 'starts with protection 0.8' do
28
+ expect(chrysalis.protection).to eq(0.8)
29
+ end
30
+
31
+ it 'starts with beauty 0.0' do
32
+ expect(chrysalis.beauty).to eq(0.0)
33
+ end
34
+
35
+ it 'records created_at as a Time' do
36
+ expect(chrysalis.created_at).to be_a(Time)
37
+ end
38
+ end
39
+
40
+ describe '#spin!' do
41
+ it 'transitions stage from :larva to :spinning' do
42
+ chrysalis.spin!
43
+ expect(chrysalis.stage).to eq(:spinning)
44
+ end
45
+
46
+ it 'returns true' do
47
+ expect(chrysalis.spin!).to be true
48
+ end
49
+
50
+ it 'raises ArgumentError when not in :larva stage' do
51
+ chrysalis.spin!
52
+ expect { chrysalis.spin! }.to raise_error(ArgumentError)
53
+ end
54
+ end
55
+
56
+ describe '#cocoon!' do
57
+ before { chrysalis.spin! }
58
+
59
+ it 'transitions stage from :spinning to :cocooned' do
60
+ chrysalis.cocoon!
61
+ expect(chrysalis.stage).to eq(:cocooned)
62
+ end
63
+
64
+ it 'returns true' do
65
+ expect(chrysalis.cocoon!).to be true
66
+ end
67
+
68
+ it 'raises ArgumentError when not in :spinning stage' do
69
+ chrysalis.cocoon!
70
+ expect { chrysalis.cocoon! }.to raise_error(ArgumentError)
71
+ end
72
+ end
73
+
74
+ describe '#transform!' do
75
+ it 'increments transformation_progress by TRANSFORMATION_RATE by default' do
76
+ chrysalis.transform!
77
+ expect(chrysalis.transformation_progress).to be_within(0.0001).of(0.08)
78
+ end
79
+
80
+ it 'accepts a custom rate' do
81
+ chrysalis.transform!(0.2)
82
+ expect(chrysalis.transformation_progress).to be_within(0.0001).of(0.2)
83
+ end
84
+
85
+ it 'increases beauty proportionally' do
86
+ chrysalis.transform!(0.5)
87
+ expect(chrysalis.beauty).to be > 0.0
88
+ end
89
+
90
+ it 'clamps transformation_progress to 1.0' do
91
+ 15.times { chrysalis.transform! }
92
+ expect(chrysalis.transformation_progress).to eq(1.0)
93
+ end
94
+
95
+ it 'returns false when already a butterfly' do
96
+ chrysalis.transform!(1.0)
97
+ chrysalis.emerge!
98
+ expect(chrysalis.transform!).to be false
99
+ end
100
+
101
+ it 'updates stage when progress crosses 0.6 threshold' do
102
+ chrysalis.transform!(0.65)
103
+ expect(chrysalis.stage).to eq(:transforming)
104
+ end
105
+
106
+ it 'updates stage to :emerging when progress crosses 0.8 threshold' do
107
+ chrysalis.transform!(0.85)
108
+ expect(chrysalis.stage).to eq(:emerging)
109
+ end
110
+ end
111
+
112
+ describe '#emerge!' do
113
+ context 'when transformation_progress >= EMERGENCE_THRESHOLD' do
114
+ before { chrysalis.transform!(0.95) }
115
+
116
+ it 'transitions to :butterfly' do
117
+ chrysalis.emerge!
118
+ expect(chrysalis.stage).to eq(:butterfly)
119
+ end
120
+
121
+ it 'sets beauty to 1.0' do
122
+ chrysalis.emerge!
123
+ expect(chrysalis.beauty).to eq(1.0)
124
+ end
125
+
126
+ it 'returns true' do
127
+ expect(chrysalis.emerge!).to be true
128
+ end
129
+ end
130
+
131
+ context 'when transformation_progress < EMERGENCE_THRESHOLD' do
132
+ it 'returns false without forcing' do
133
+ chrysalis.transform!(0.5)
134
+ expect(chrysalis.emerge!).to be false
135
+ end
136
+
137
+ it 'stage remains unchanged' do
138
+ chrysalis.transform!(0.5)
139
+ stage_before = chrysalis.stage
140
+ chrysalis.emerge!
141
+ expect(chrysalis.stage).to eq(stage_before)
142
+ end
143
+ end
144
+
145
+ context 'when forced early' do
146
+ before { chrysalis.transform!(0.3) }
147
+
148
+ it 'transitions to :butterfly' do
149
+ chrysalis.emerge!(force: true)
150
+ expect(chrysalis.stage).to eq(:butterfly)
151
+ end
152
+
153
+ it 'applies PREMATURE_PENALTY to beauty' do
154
+ beauty_before = chrysalis.beauty
155
+ chrysalis.emerge!(force: true)
156
+ expect(chrysalis.beauty).to be <= beauty_before
157
+ end
158
+
159
+ it 'returns true' do
160
+ expect(chrysalis.emerge!(force: true)).to be true
161
+ end
162
+ end
163
+ end
164
+
165
+ describe '#decay_protection!' do
166
+ it 'reduces protection by PROTECTION_DECAY' do
167
+ original = chrysalis.protection
168
+ chrysalis.decay_protection!
169
+ expected = (original - Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants::PROTECTION_DECAY).round(10)
170
+ expect(chrysalis.protection).to be_within(0.0001).of(expected)
171
+ end
172
+
173
+ it 'does not go below 0.0' do
174
+ 30.times { chrysalis.decay_protection! }
175
+ expect(chrysalis.protection).to eq(0.0)
176
+ end
177
+ end
178
+
179
+ describe '#disturb!' do
180
+ it 'reduces protection by the given force' do
181
+ chrysalis.disturb!(0.2)
182
+ expect(chrysalis.protection).to be_within(0.0001).of(0.6)
183
+ end
184
+
185
+ it 'forces premature emergence when protection drops to zero for a cocooned chrysalis' do
186
+ chrysalis.spin!
187
+ chrysalis.cocoon!
188
+ chrysalis.disturb!(1.0)
189
+ expect(chrysalis.stage).to eq(:butterfly)
190
+ end
191
+
192
+ it 'does not force-emerge a larva when protection hits zero' do
193
+ chrysalis.disturb!(1.0)
194
+ expect(chrysalis.stage).to eq(:larva)
195
+ end
196
+ end
197
+
198
+ describe '#butterfly?' do
199
+ it 'returns false before emergence' do
200
+ expect(chrysalis.butterfly?).to be false
201
+ end
202
+
203
+ it 'returns true after natural emergence' do
204
+ chrysalis.transform!(1.0)
205
+ chrysalis.emerge!
206
+ expect(chrysalis.butterfly?).to be true
207
+ end
208
+ end
209
+
210
+ describe '#cocooned?' do
211
+ it 'returns false initially' do
212
+ expect(chrysalis.cocooned?).to be false
213
+ end
214
+
215
+ it 'returns true after cocooning' do
216
+ chrysalis.spin!
217
+ chrysalis.cocoon!
218
+ expect(chrysalis.cocooned?).to be true
219
+ end
220
+ end
221
+
222
+ describe '#transforming?' do
223
+ it 'returns false initially' do
224
+ expect(chrysalis.transforming?).to be false
225
+ end
226
+
227
+ it 'returns true after sufficient progress' do
228
+ chrysalis.transform!(0.65)
229
+ expect(chrysalis.transforming?).to be true
230
+ end
231
+ end
232
+
233
+ describe '#premature?' do
234
+ it 'returns false for a non-butterfly' do
235
+ expect(chrysalis.premature?).to be false
236
+ end
237
+
238
+ it 'returns false for a naturally emerged butterfly' do
239
+ chrysalis.transform!(1.0)
240
+ chrysalis.emerge!
241
+ expect(chrysalis.premature?).to be false
242
+ end
243
+
244
+ it 'returns true for a forcibly emerged butterfly with low beauty' do
245
+ chrysalis.transform!(0.05)
246
+ chrysalis.emerge!(force: true)
247
+ expect(chrysalis.premature?).to be true
248
+ end
249
+ end
250
+
251
+ describe '#stage_label' do
252
+ it 'returns a symbol' do
253
+ expect(chrysalis.stage_label).to be_a(Symbol)
254
+ end
255
+
256
+ it 'returns :larva for a fresh chrysalis' do
257
+ expect(chrysalis.stage_label).to eq(:larva)
258
+ end
259
+ end
260
+
261
+ describe '#beauty_label' do
262
+ it 'returns :dull for beauty 0.0' do
263
+ expect(chrysalis.beauty_label).to eq(:dull)
264
+ end
265
+
266
+ it 'returns :magnificent after natural emergence' do
267
+ chrysalis.transform!(1.0)
268
+ chrysalis.emerge!
269
+ expect(chrysalis.beauty_label).to eq(:magnificent)
270
+ end
271
+ end
272
+
273
+ describe '#to_h' do
274
+ it 'returns a hash' do
275
+ expect(chrysalis.to_h).to be_a(Hash)
276
+ end
277
+
278
+ it 'includes id, stage, content, chrysalis_type' do
279
+ h = chrysalis.to_h
280
+ expect(h[:id]).to eq(chrysalis.id)
281
+ expect(h[:stage]).to eq(:larva)
282
+ expect(h[:content]).to eq('a new idea')
283
+ expect(h[:chrysalis_type]).to eq(:silk)
284
+ end
285
+
286
+ it 'includes transformation_progress and protection and beauty' do
287
+ h = chrysalis.to_h
288
+ expect(h).to have_key(:transformation_progress)
289
+ expect(h).to have_key(:protection)
290
+ expect(h).to have_key(:beauty)
291
+ end
292
+
293
+ it 'includes stage_label and beauty_label' do
294
+ h = chrysalis.to_h
295
+ expect(h).to have_key(:stage_label)
296
+ expect(h).to have_key(:beauty_label)
297
+ end
298
+
299
+ it 'includes premature and created_at' do
300
+ h = chrysalis.to_h
301
+ expect(h).to have_key(:premature)
302
+ expect(h).to have_key(:created_at)
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Cocoon do
4
+ subject(:cocoon) { described_class.new(environment: 'forest_floor') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a uuid id' do
8
+ expect(cocoon.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets environment' do
12
+ expect(cocoon.environment).to eq('forest_floor')
13
+ end
14
+
15
+ it 'defaults temperature to 0.5' do
16
+ expect(cocoon.temperature).to eq(0.5)
17
+ end
18
+
19
+ it 'defaults humidity to 0.5' do
20
+ expect(cocoon.humidity).to eq(0.5)
21
+ end
22
+
23
+ it 'starts with empty chrysalis_ids' do
24
+ expect(cocoon.chrysalis_ids).to eq([])
25
+ end
26
+
27
+ it 'records created_at as a Time' do
28
+ expect(cocoon.created_at).to be_a(Time)
29
+ end
30
+
31
+ it 'accepts custom temperature and humidity' do
32
+ c = described_class.new(environment: 'sunny', temperature: 0.7, humidity: 0.3)
33
+ expect(c.temperature).to eq(0.7)
34
+ expect(c.humidity).to eq(0.3)
35
+ end
36
+ end
37
+
38
+ describe '#shelter' do
39
+ it 'adds a chrysalis_id to the list' do
40
+ cocoon.shelter('abc-123')
41
+ expect(cocoon.chrysalis_ids).to include('abc-123')
42
+ end
43
+
44
+ it 'returns true' do
45
+ expect(cocoon.shelter('abc-123')).to be true
46
+ end
47
+
48
+ it 'does not duplicate existing ids' do
49
+ cocoon.shelter('abc-123')
50
+ cocoon.shelter('abc-123')
51
+ expect(cocoon.chrysalis_ids.count('abc-123')).to eq(1)
52
+ end
53
+ end
54
+
55
+ describe '#expose' do
56
+ before { cocoon.shelter('abc-123') }
57
+
58
+ it 'removes a chrysalis_id from the list' do
59
+ cocoon.expose('abc-123')
60
+ expect(cocoon.chrysalis_ids).not_to include('abc-123')
61
+ end
62
+
63
+ it 'returns true' do
64
+ expect(cocoon.expose('abc-123')).to be true
65
+ end
66
+
67
+ it 'is idempotent for non-existent ids' do
68
+ expect { cocoon.expose('non-existent') }.not_to raise_error
69
+ end
70
+ end
71
+
72
+ describe '#warm!' do
73
+ it 'increases temperature by TEMP_ADJUST' do
74
+ before_temp = cocoon.temperature
75
+ cocoon.warm!
76
+ expect(cocoon.temperature).to be > before_temp
77
+ end
78
+
79
+ it 'clamps temperature at 1.0' do
80
+ 25.times { cocoon.warm! }
81
+ expect(cocoon.temperature).to eq(1.0)
82
+ end
83
+ end
84
+
85
+ describe '#cool!' do
86
+ it 'decreases temperature by TEMP_ADJUST' do
87
+ before_temp = cocoon.temperature
88
+ cocoon.cool!
89
+ expect(cocoon.temperature).to be < before_temp
90
+ end
91
+
92
+ it 'clamps temperature at 0.0' do
93
+ 25.times { cocoon.cool! }
94
+ expect(cocoon.temperature).to eq(0.0)
95
+ end
96
+ end
97
+
98
+ describe '#moisten!' do
99
+ it 'increases humidity by HUMID_ADJUST' do
100
+ before_humid = cocoon.humidity
101
+ cocoon.moisten!
102
+ expect(cocoon.humidity).to be > before_humid
103
+ end
104
+
105
+ it 'clamps humidity at 1.0' do
106
+ 25.times { cocoon.moisten! }
107
+ expect(cocoon.humidity).to eq(1.0)
108
+ end
109
+ end
110
+
111
+ describe '#dry!' do
112
+ it 'decreases humidity by HUMID_ADJUST' do
113
+ before_humid = cocoon.humidity
114
+ cocoon.dry!
115
+ expect(cocoon.humidity).to be < before_humid
116
+ end
117
+
118
+ it 'clamps humidity at 0.0' do
119
+ 25.times { cocoon.dry! }
120
+ expect(cocoon.humidity).to eq(0.0)
121
+ end
122
+ end
123
+
124
+ describe '#ideal?' do
125
+ it 'returns true when temperature and humidity are both in 0.4-0.7 range' do
126
+ ideal = described_class.new(environment: 'ideal', temperature: 0.55, humidity: 0.55)
127
+ expect(ideal.ideal?).to be true
128
+ end
129
+
130
+ it 'returns false when temperature is out of ideal range' do
131
+ c = described_class.new(environment: 'hot', temperature: 0.8, humidity: 0.5)
132
+ expect(c.ideal?).to be false
133
+ end
134
+
135
+ it 'returns false when humidity is out of ideal range' do
136
+ c = described_class.new(environment: 'dry', temperature: 0.5, humidity: 0.2)
137
+ expect(c.ideal?).to be false
138
+ end
139
+ end
140
+
141
+ describe '#hostile?' do
142
+ it 'returns true when temperature > 0.9' do
143
+ c = described_class.new(environment: 'furnace', temperature: 0.95, humidity: 0.5)
144
+ expect(c.hostile?).to be true
145
+ end
146
+
147
+ it 'returns true when humidity < 0.1' do
148
+ c = described_class.new(environment: 'desert', temperature: 0.5, humidity: 0.05)
149
+ expect(c.hostile?).to be true
150
+ end
151
+
152
+ it 'returns false for normal conditions' do
153
+ expect(cocoon.hostile?).to be false
154
+ end
155
+ end
156
+
157
+ describe '#growth_modifier' do
158
+ it 'returns 0.1 for ideal conditions' do
159
+ ideal = described_class.new(environment: 'ideal', temperature: 0.55, humidity: 0.55)
160
+ expect(ideal.growth_modifier).to eq(0.1)
161
+ end
162
+
163
+ it 'returns -0.05 for hostile conditions' do
164
+ hostile = described_class.new(environment: 'hostile', temperature: 0.95, humidity: 0.5)
165
+ expect(hostile.growth_modifier).to eq(-0.05)
166
+ end
167
+
168
+ it 'returns 0.0 for neutral conditions' do
169
+ neutral = described_class.new(environment: 'neutral', temperature: 0.2, humidity: 0.5)
170
+ expect(neutral.growth_modifier).to eq(0.0)
171
+ end
172
+ end
173
+
174
+ describe '#to_h' do
175
+ it 'returns a Hash' do
176
+ expect(cocoon.to_h).to be_a(Hash)
177
+ end
178
+
179
+ it 'includes all key fields' do
180
+ h = cocoon.to_h
181
+ expect(h[:id]).to eq(cocoon.id)
182
+ expect(h[:environment]).to eq('forest_floor')
183
+ expect(h[:temperature]).to eq(0.5)
184
+ expect(h[:humidity]).to eq(0.5)
185
+ expect(h[:chrysalis_ids]).to eq([])
186
+ end
187
+
188
+ it 'includes ideal and hostile booleans' do
189
+ h = cocoon.to_h
190
+ expect(h).to have_key(:ideal)
191
+ expect(h).to have_key(:hostile)
192
+ end
193
+
194
+ it 'includes growth_modifier' do
195
+ h = cocoon.to_h
196
+ expect(h).to have_key(:growth_modifier)
197
+ end
198
+
199
+ it 'returns a dup of chrysalis_ids (not the original array)' do
200
+ cocoon.shelter('id-1')
201
+ h = cocoon.to_h
202
+ h[:chrysalis_ids] << 'injected'
203
+ expect(cocoon.chrysalis_ids).not_to include('injected')
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,109 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants do
4
+ subject(:constants) { described_class }
5
+
6
+ describe 'LIFE_STAGES' do
7
+ it 'contains the six metamorphic stages' do
8
+ expect(constants::LIFE_STAGES).to eq(%i[larva spinning cocooned transforming emerging butterfly])
9
+ end
10
+
11
+ it 'is frozen' do
12
+ expect(constants::LIFE_STAGES).to be_frozen
13
+ end
14
+ end
15
+
16
+ describe 'CHRYSALIS_TYPES' do
17
+ it 'contains the five chrysalis types' do
18
+ expect(constants::CHRYSALIS_TYPES).to eq(%i[silk paper bark leaf underground])
19
+ end
20
+
21
+ it 'is frozen' do
22
+ expect(constants::CHRYSALIS_TYPES).to be_frozen
23
+ end
24
+ end
25
+
26
+ describe 'numeric constants' do
27
+ it 'has MAX_CHRYSALISES = 200' do
28
+ expect(constants::MAX_CHRYSALISES).to eq(200)
29
+ end
30
+
31
+ it 'has MAX_BUTTERFLIES = 500' do
32
+ expect(constants::MAX_BUTTERFLIES).to eq(500)
33
+ end
34
+
35
+ it 'has TRANSFORMATION_RATE = 0.08' do
36
+ expect(constants::TRANSFORMATION_RATE).to eq(0.08)
37
+ end
38
+
39
+ it 'has PROTECTION_DECAY = 0.03' do
40
+ expect(constants::PROTECTION_DECAY).to eq(0.03)
41
+ end
42
+
43
+ it 'has EMERGENCE_THRESHOLD = 0.9' do
44
+ expect(constants::EMERGENCE_THRESHOLD).to eq(0.9)
45
+ end
46
+
47
+ it 'has PREMATURE_PENALTY = 0.4' do
48
+ expect(constants::PREMATURE_PENALTY).to eq(0.4)
49
+ end
50
+ end
51
+
52
+ describe 'STAGE_LABELS' do
53
+ it 'is a hash' do
54
+ expect(constants::STAGE_LABELS).to be_a(Hash)
55
+ end
56
+
57
+ it 'is frozen' do
58
+ expect(constants::STAGE_LABELS).to be_frozen
59
+ end
60
+ end
61
+
62
+ describe 'BEAUTY_LABELS' do
63
+ it 'is a hash' do
64
+ expect(constants::BEAUTY_LABELS).to be_a(Hash)
65
+ end
66
+
67
+ it 'is frozen' do
68
+ expect(constants::BEAUTY_LABELS).to be_frozen
69
+ end
70
+ end
71
+
72
+ describe '.label_for' do
73
+ it 'returns :larva for progress 0.0' do
74
+ expect(constants.label_for(constants::STAGE_LABELS, 0.0)).to eq(:larva)
75
+ end
76
+
77
+ it 'returns :butterfly for progress 0.95' do
78
+ expect(constants.label_for(constants::STAGE_LABELS, 0.95)).to eq(:butterfly)
79
+ end
80
+
81
+ it 'returns :transforming for progress 0.7' do
82
+ expect(constants.label_for(constants::STAGE_LABELS, 0.7)).to eq(:transforming)
83
+ end
84
+
85
+ it 'returns :dull for beauty 0.0' do
86
+ expect(constants.label_for(constants::BEAUTY_LABELS, 0.0)).to eq(:dull)
87
+ end
88
+
89
+ it 'returns :magnificent for beauty 0.95' do
90
+ expect(constants.label_for(constants::BEAUTY_LABELS, 0.95)).to eq(:magnificent)
91
+ end
92
+
93
+ it 'returns :beautiful for beauty 0.75' do
94
+ expect(constants.label_for(constants::BEAUTY_LABELS, 0.75)).to eq(:beautiful)
95
+ end
96
+
97
+ it 'returns :striking for beauty 0.5' do
98
+ expect(constants.label_for(constants::BEAUTY_LABELS, 0.5)).to eq(:striking)
99
+ end
100
+
101
+ it 'returns :plain for beauty 0.25' do
102
+ expect(constants.label_for(constants::BEAUTY_LABELS, 0.25)).to eq(:plain)
103
+ end
104
+
105
+ it 'returns the last label when value exceeds all ranges' do
106
+ expect(constants.label_for(constants::STAGE_LABELS, 1.1)).to eq(:butterfly)
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Tests focused on Chrysalis stage progression through repeated transform! calls
4
+ RSpec.describe 'Chrysalis stage progression' do
5
+ let(:chrysalis) { Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Chrysalis.new(chrysalis_type: :silk, content: 'journey') }
6
+ let(:rate) { Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants::TRANSFORMATION_RATE }
7
+
8
+ it 'progresses through larva -> spinning -> cocooned -> transforming -> emerging over time' do
9
+ # 0.0 = larva
10
+ expect(chrysalis.stage).to eq(:larva)
11
+
12
+ # Cross 0.2 = spinning
13
+ 3.times { chrysalis.transform! }
14
+ expect(chrysalis.stage).to eq(:spinning)
15
+
16
+ # Cross 0.4 = cocooned
17
+ 3.times { chrysalis.transform! }
18
+ expect(chrysalis.stage).to eq(:cocooned)
19
+
20
+ # Cross 0.6 = transforming
21
+ 3.times { chrysalis.transform! }
22
+ expect(chrysalis.stage).to eq(:transforming)
23
+
24
+ # Cross 0.8 = emerging
25
+ 3.times { chrysalis.transform! }
26
+ expect(chrysalis.stage).to eq(:emerging)
27
+ end
28
+
29
+ it 'can emerge after crossing the threshold' do
30
+ 12.times { chrysalis.transform! }
31
+ result = chrysalis.emerge!
32
+ expect(result).to be true
33
+ expect(chrysalis.butterfly?).to be true
34
+ end
35
+
36
+ it 'beauty grows with each transform step' do
37
+ beauty_before = chrysalis.beauty
38
+ chrysalis.transform!
39
+ expect(chrysalis.beauty).to be > beauty_before
40
+ end
41
+
42
+ it 'stage_label matches transformation_progress' do
43
+ chrysalis.transform!(0.25)
44
+ label = Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants.label_for(
45
+ Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants::STAGE_LABELS,
46
+ chrysalis.transformation_progress
47
+ )
48
+ expect(chrysalis.stage_label).to eq(label)
49
+ end
50
+
51
+ it 'beauty_label matches beauty' do
52
+ chrysalis.transform!(0.7)
53
+ label = Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants.label_for(
54
+ Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Constants::BEAUTY_LABELS,
55
+ chrysalis.beauty
56
+ )
57
+ expect(chrysalis.beauty_label).to eq(label)
58
+ end
59
+
60
+ it 'multiple chrysalises have unique ids' do
61
+ a = Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Chrysalis.new(chrysalis_type: :bark, content: 'a')
62
+ b = Legion::Extensions::Agentic::Learning::Chrysalis::Helpers::Chrysalis.new(chrysalis_type: :bark, content: 'b')
63
+ expect(a.id).not_to eq(b.id)
64
+ end
65
+
66
+ it 'premature? is false after natural emergence' do
67
+ 12.times { chrysalis.transform! }
68
+ chrysalis.emerge!
69
+ expect(chrysalis.premature?).to be false
70
+ end
71
+
72
+ it 'premature? is true after forced emergence from larva stage' do
73
+ chrysalis.emerge!(force: true)
74
+ expect(chrysalis.premature?).to be true
75
+ end
76
+ end