lex-agentic-defense 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 (219) 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-defense.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/defense/avalanche/client.rb +22 -0
  8. data/lib/legion/extensions/agentic/defense/avalanche/helpers/avalanche_engine.rb +132 -0
  9. data/lib/legion/extensions/agentic/defense/avalanche/helpers/cascade.rb +76 -0
  10. data/lib/legion/extensions/agentic/defense/avalanche/helpers/constants.rb +44 -0
  11. data/lib/legion/extensions/agentic/defense/avalanche/helpers/snowpack.rb +86 -0
  12. data/lib/legion/extensions/agentic/defense/avalanche/runners/cognitive_avalanche.rb +75 -0
  13. data/lib/legion/extensions/agentic/defense/avalanche/version.rb +13 -0
  14. data/lib/legion/extensions/agentic/defense/avalanche.rb +22 -0
  15. data/lib/legion/extensions/agentic/defense/bias/actors/update.rb +45 -0
  16. data/lib/legion/extensions/agentic/defense/bias/client.rb +30 -0
  17. data/lib/legion/extensions/agentic/defense/bias/helpers/bias_detector.rb +107 -0
  18. data/lib/legion/extensions/agentic/defense/bias/helpers/bias_event.rb +44 -0
  19. data/lib/legion/extensions/agentic/defense/bias/helpers/bias_store.rb +84 -0
  20. data/lib/legion/extensions/agentic/defense/bias/helpers/constants.rb +28 -0
  21. data/lib/legion/extensions/agentic/defense/bias/runners/bias.rb +151 -0
  22. data/lib/legion/extensions/agentic/defense/bias/version.rb +13 -0
  23. data/lib/legion/extensions/agentic/defense/bias.rb +20 -0
  24. data/lib/legion/extensions/agentic/defense/confabulation/actors/decay.rb +45 -0
  25. data/lib/legion/extensions/agentic/defense/confabulation/client.rb +28 -0
  26. data/lib/legion/extensions/agentic/defense/confabulation/helpers/claim.rb +67 -0
  27. data/lib/legion/extensions/agentic/defense/confabulation/helpers/confabulation_engine.rb +120 -0
  28. data/lib/legion/extensions/agentic/defense/confabulation/helpers/constants.rb +29 -0
  29. data/lib/legion/extensions/agentic/defense/confabulation/runners/confabulation.rb +74 -0
  30. data/lib/legion/extensions/agentic/defense/confabulation/version.rb +13 -0
  31. data/lib/legion/extensions/agentic/defense/confabulation.rb +19 -0
  32. data/lib/legion/extensions/agentic/defense/dissonance/client.rb +32 -0
  33. data/lib/legion/extensions/agentic/defense/dissonance/helpers/belief.rb +46 -0
  34. data/lib/legion/extensions/agentic/defense/dissonance/helpers/constants.rb +27 -0
  35. data/lib/legion/extensions/agentic/defense/dissonance/helpers/dissonance_event.rb +52 -0
  36. data/lib/legion/extensions/agentic/defense/dissonance/helpers/dissonance_model.rb +159 -0
  37. data/lib/legion/extensions/agentic/defense/dissonance/runners/dissonance.rb +163 -0
  38. data/lib/legion/extensions/agentic/defense/dissonance/version.rb +13 -0
  39. data/lib/legion/extensions/agentic/defense/dissonance.rb +20 -0
  40. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/actors/update.rb +45 -0
  41. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/client.rb +27 -0
  42. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/claim.rb +78 -0
  43. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/client.rb +23 -0
  44. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/constants.rb +37 -0
  45. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/source.rb +64 -0
  46. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/helpers/vigilance_engine.rb +195 -0
  47. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/runners/epistemic_vigilance.rb +91 -0
  48. data/lib/legion/extensions/agentic/defense/epistemic_vigilance/version.rb +13 -0
  49. data/lib/legion/extensions/agentic/defense/epistemic_vigilance.rb +20 -0
  50. data/lib/legion/extensions/agentic/defense/erosion/client.rb +23 -0
  51. data/lib/legion/extensions/agentic/defense/erosion/helpers/channel.rb +84 -0
  52. data/lib/legion/extensions/agentic/defense/erosion/helpers/constants.rb +47 -0
  53. data/lib/legion/extensions/agentic/defense/erosion/helpers/erosion_engine.rb +134 -0
  54. data/lib/legion/extensions/agentic/defense/erosion/helpers/formation.rb +100 -0
  55. data/lib/legion/extensions/agentic/defense/erosion/runners/cognitive_erosion.rb +93 -0
  56. data/lib/legion/extensions/agentic/defense/erosion/version.rb +13 -0
  57. data/lib/legion/extensions/agentic/defense/erosion.rb +21 -0
  58. data/lib/legion/extensions/agentic/defense/error_monitoring/actors/tick.rb +45 -0
  59. data/lib/legion/extensions/agentic/defense/error_monitoring/client.rb +28 -0
  60. data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/constants.rb +50 -0
  61. data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/error_monitor.rb +174 -0
  62. data/lib/legion/extensions/agentic/defense/error_monitoring/helpers/error_signal.rb +60 -0
  63. data/lib/legion/extensions/agentic/defense/error_monitoring/runners/error_monitoring.rb +102 -0
  64. data/lib/legion/extensions/agentic/defense/error_monitoring/version.rb +13 -0
  65. data/lib/legion/extensions/agentic/defense/error_monitoring.rb +19 -0
  66. data/lib/legion/extensions/agentic/defense/extinction/actors/protocol_monitor.rb +45 -0
  67. data/lib/legion/extensions/agentic/defense/extinction/client.rb +27 -0
  68. data/lib/legion/extensions/agentic/defense/extinction/helpers/levels.rb +43 -0
  69. data/lib/legion/extensions/agentic/defense/extinction/helpers/protocol_state.rb +125 -0
  70. data/lib/legion/extensions/agentic/defense/extinction/local_migrations/20260316000040_create_extinction_state.rb +13 -0
  71. data/lib/legion/extensions/agentic/defense/extinction/runners/extinction.rb +130 -0
  72. data/lib/legion/extensions/agentic/defense/extinction/version.rb +13 -0
  73. data/lib/legion/extensions/agentic/defense/extinction.rb +25 -0
  74. data/lib/legion/extensions/agentic/defense/friction/client.rb +15 -0
  75. data/lib/legion/extensions/agentic/defense/friction/helpers/constants.rb +38 -0
  76. data/lib/legion/extensions/agentic/defense/friction/helpers/friction_engine.rb +131 -0
  77. data/lib/legion/extensions/agentic/defense/friction/helpers/state_transition.rb +73 -0
  78. data/lib/legion/extensions/agentic/defense/friction/runners/cognitive_friction.rb +82 -0
  79. data/lib/legion/extensions/agentic/defense/friction/version.rb +13 -0
  80. data/lib/legion/extensions/agentic/defense/friction.rb +19 -0
  81. data/lib/legion/extensions/agentic/defense/immune_response/client.rb +19 -0
  82. data/lib/legion/extensions/agentic/defense/immune_response/helpers/antibody.rb +72 -0
  83. data/lib/legion/extensions/agentic/defense/immune_response/helpers/antigen.rb +87 -0
  84. data/lib/legion/extensions/agentic/defense/immune_response/helpers/constants.rb +75 -0
  85. data/lib/legion/extensions/agentic/defense/immune_response/helpers/immune_engine.rb +184 -0
  86. data/lib/legion/extensions/agentic/defense/immune_response/helpers/immune_response.rb +76 -0
  87. data/lib/legion/extensions/agentic/defense/immune_response/runners/cognitive_immune_response.rb +114 -0
  88. data/lib/legion/extensions/agentic/defense/immune_response/version.rb +13 -0
  89. data/lib/legion/extensions/agentic/defense/immune_response.rb +21 -0
  90. data/lib/legion/extensions/agentic/defense/immunology/client.rb +29 -0
  91. data/lib/legion/extensions/agentic/defense/immunology/helpers/antibody.rb +55 -0
  92. data/lib/legion/extensions/agentic/defense/immunology/helpers/constants.rb +43 -0
  93. data/lib/legion/extensions/agentic/defense/immunology/helpers/immune_engine.rb +187 -0
  94. data/lib/legion/extensions/agentic/defense/immunology/helpers/threat.rb +67 -0
  95. data/lib/legion/extensions/agentic/defense/immunology/runners/cognitive_immunology.rb +92 -0
  96. data/lib/legion/extensions/agentic/defense/immunology/version.rb +13 -0
  97. data/lib/legion/extensions/agentic/defense/immunology.rb +20 -0
  98. data/lib/legion/extensions/agentic/defense/phantom/client.rb +29 -0
  99. data/lib/legion/extensions/agentic/defense/phantom/helpers/constants.rb +54 -0
  100. data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_engine.rb +106 -0
  101. data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_limb.rb +103 -0
  102. data/lib/legion/extensions/agentic/defense/phantom/helpers/phantom_signal.rb +40 -0
  103. data/lib/legion/extensions/agentic/defense/phantom/runners/cognitive_phantom.rb +79 -0
  104. data/lib/legion/extensions/agentic/defense/phantom/version.rb +13 -0
  105. data/lib/legion/extensions/agentic/defense/phantom.rb +21 -0
  106. data/lib/legion/extensions/agentic/defense/quicksand/client.rb +15 -0
  107. data/lib/legion/extensions/agentic/defense/quicksand/helpers/constants.rb +48 -0
  108. data/lib/legion/extensions/agentic/defense/quicksand/helpers/pit.rb +82 -0
  109. data/lib/legion/extensions/agentic/defense/quicksand/helpers/quicksand_engine.rb +137 -0
  110. data/lib/legion/extensions/agentic/defense/quicksand/helpers/trap.rb +101 -0
  111. data/lib/legion/extensions/agentic/defense/quicksand/runners/cognitive_quicksand.rb +84 -0
  112. data/lib/legion/extensions/agentic/defense/quicksand/version.rb +13 -0
  113. data/lib/legion/extensions/agentic/defense/quicksand.rb +22 -0
  114. data/lib/legion/extensions/agentic/defense/quicksilver/client.rb +29 -0
  115. data/lib/legion/extensions/agentic/defense/quicksilver/helpers/constants.rb +50 -0
  116. data/lib/legion/extensions/agentic/defense/quicksilver/helpers/droplet.rb +126 -0
  117. data/lib/legion/extensions/agentic/defense/quicksilver/helpers/pool.rb +83 -0
  118. data/lib/legion/extensions/agentic/defense/quicksilver/helpers/quicksilver_engine.rb +124 -0
  119. data/lib/legion/extensions/agentic/defense/quicksilver/runners/cognitive_quicksilver.rb +130 -0
  120. data/lib/legion/extensions/agentic/defense/quicksilver/version.rb +13 -0
  121. data/lib/legion/extensions/agentic/defense/quicksilver.rb +21 -0
  122. data/lib/legion/extensions/agentic/defense/version.rb +11 -0
  123. data/lib/legion/extensions/agentic/defense/whirlpool/client.rb +65 -0
  124. data/lib/legion/extensions/agentic/defense/whirlpool/helpers/captured_thought.rb +67 -0
  125. data/lib/legion/extensions/agentic/defense/whirlpool/helpers/constants.rb +45 -0
  126. data/lib/legion/extensions/agentic/defense/whirlpool/helpers/vortex.rb +91 -0
  127. data/lib/legion/extensions/agentic/defense/whirlpool/helpers/whirlpool_engine.rb +92 -0
  128. data/lib/legion/extensions/agentic/defense/whirlpool/runners/cognitive_whirlpool.rb +117 -0
  129. data/lib/legion/extensions/agentic/defense/whirlpool/version.rb +13 -0
  130. data/lib/legion/extensions/agentic/defense/whirlpool.rb +22 -0
  131. data/lib/legion/extensions/agentic/defense.rb +32 -0
  132. data/spec/legion/extensions/agentic/defense/avalanche/client_spec.rb +96 -0
  133. data/spec/legion/extensions/agentic/defense/avalanche/helpers/avalanche_engine_spec.rb +276 -0
  134. data/spec/legion/extensions/agentic/defense/avalanche/helpers/cascade_spec.rb +190 -0
  135. data/spec/legion/extensions/agentic/defense/avalanche/helpers/constants_spec.rb +129 -0
  136. data/spec/legion/extensions/agentic/defense/avalanche/helpers/snowpack_spec.rb +197 -0
  137. data/spec/legion/extensions/agentic/defense/avalanche/runners/cognitive_avalanche_spec.rb +211 -0
  138. data/spec/legion/extensions/agentic/defense/bias/client_spec.rb +16 -0
  139. data/spec/legion/extensions/agentic/defense/bias/helpers/bias_detector_spec.rb +160 -0
  140. data/spec/legion/extensions/agentic/defense/bias/helpers/bias_event_spec.rb +64 -0
  141. data/spec/legion/extensions/agentic/defense/bias/helpers/bias_store_spec.rb +143 -0
  142. data/spec/legion/extensions/agentic/defense/bias/runners/bias_spec.rb +155 -0
  143. data/spec/legion/extensions/agentic/defense/confabulation/client_spec.rb +34 -0
  144. data/spec/legion/extensions/agentic/defense/confabulation/helpers/claim_spec.rb +119 -0
  145. data/spec/legion/extensions/agentic/defense/confabulation/helpers/confabulation_engine_spec.rb +163 -0
  146. data/spec/legion/extensions/agentic/defense/confabulation/helpers/constants_spec.rb +55 -0
  147. data/spec/legion/extensions/agentic/defense/confabulation/runners/confabulation_spec.rb +119 -0
  148. data/spec/legion/extensions/agentic/defense/dissonance/client_spec.rb +51 -0
  149. data/spec/legion/extensions/agentic/defense/dissonance/helpers/belief_spec.rb +103 -0
  150. data/spec/legion/extensions/agentic/defense/dissonance/helpers/constants_spec.rb +60 -0
  151. data/spec/legion/extensions/agentic/defense/dissonance/helpers/dissonance_event_spec.rb +113 -0
  152. data/spec/legion/extensions/agentic/defense/dissonance/helpers/dissonance_model_spec.rb +252 -0
  153. data/spec/legion/extensions/agentic/defense/dissonance/runners/dissonance_spec.rb +323 -0
  154. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/client_spec.rb +28 -0
  155. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/claim_spec.rb +135 -0
  156. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/constants_spec.rb +59 -0
  157. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/source_spec.rb +117 -0
  158. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/helpers/vigilance_engine_spec.rb +273 -0
  159. data/spec/legion/extensions/agentic/defense/epistemic_vigilance/runners/epistemic_vigilance_spec.rb +157 -0
  160. data/spec/legion/extensions/agentic/defense/erosion/client_spec.rb +90 -0
  161. data/spec/legion/extensions/agentic/defense/erosion/helpers/channel_spec.rb +173 -0
  162. data/spec/legion/extensions/agentic/defense/erosion/helpers/constants_spec.rb +137 -0
  163. data/spec/legion/extensions/agentic/defense/erosion/helpers/erosion_engine_spec.rb +263 -0
  164. data/spec/legion/extensions/agentic/defense/erosion/helpers/formation_spec.rb +206 -0
  165. data/spec/legion/extensions/agentic/defense/erosion/runners/cognitive_erosion_spec.rb +153 -0
  166. data/spec/legion/extensions/agentic/defense/error_monitoring/client_spec.rb +40 -0
  167. data/spec/legion/extensions/agentic/defense/error_monitoring/helpers/error_monitor_spec.rb +178 -0
  168. data/spec/legion/extensions/agentic/defense/error_monitoring/helpers/error_signal_spec.rb +76 -0
  169. data/spec/legion/extensions/agentic/defense/error_monitoring/runners/error_monitoring_spec.rb +87 -0
  170. data/spec/legion/extensions/agentic/defense/extinction/actors/protocol_monitor_spec.rb +45 -0
  171. data/spec/legion/extensions/agentic/defense/extinction/client_spec.rb +13 -0
  172. data/spec/legion/extensions/agentic/defense/extinction/helpers/levels_spec.rb +180 -0
  173. data/spec/legion/extensions/agentic/defense/extinction/helpers/protocol_state_spec.rb +291 -0
  174. data/spec/legion/extensions/agentic/defense/extinction/local_persistence_spec.rb +188 -0
  175. data/spec/legion/extensions/agentic/defense/extinction/runners/extinction_spec.rb +114 -0
  176. data/spec/legion/extensions/agentic/defense/friction/helpers/constants_spec.rb +46 -0
  177. data/spec/legion/extensions/agentic/defense/friction/helpers/friction_engine_spec.rb +175 -0
  178. data/spec/legion/extensions/agentic/defense/friction/helpers/state_transition_spec.rb +124 -0
  179. data/spec/legion/extensions/agentic/defense/friction/runners/cognitive_friction_spec.rb +89 -0
  180. data/spec/legion/extensions/agentic/defense/immune_response/client_spec.rb +32 -0
  181. data/spec/legion/extensions/agentic/defense/immune_response/cognitive_immune_response_spec.rb +7 -0
  182. data/spec/legion/extensions/agentic/defense/immune_response/helpers/antibody_spec.rb +117 -0
  183. data/spec/legion/extensions/agentic/defense/immune_response/helpers/antigen_spec.rb +125 -0
  184. data/spec/legion/extensions/agentic/defense/immune_response/helpers/constants_spec.rb +45 -0
  185. data/spec/legion/extensions/agentic/defense/immune_response/helpers/immune_engine_spec.rb +222 -0
  186. data/spec/legion/extensions/agentic/defense/immune_response/helpers/immune_response_spec.rb +84 -0
  187. data/spec/legion/extensions/agentic/defense/immune_response/runners_spec.rb +141 -0
  188. data/spec/legion/extensions/agentic/defense/immunology/client_spec.rb +61 -0
  189. data/spec/legion/extensions/agentic/defense/immunology/helpers/antibody_spec.rb +98 -0
  190. data/spec/legion/extensions/agentic/defense/immunology/helpers/constants_spec.rb +86 -0
  191. data/spec/legion/extensions/agentic/defense/immunology/helpers/immune_engine_spec.rb +275 -0
  192. data/spec/legion/extensions/agentic/defense/immunology/helpers/threat_spec.rb +133 -0
  193. data/spec/legion/extensions/agentic/defense/immunology/runners/cognitive_immunology_spec.rb +177 -0
  194. data/spec/legion/extensions/agentic/defense/phantom/client_spec.rb +53 -0
  195. data/spec/legion/extensions/agentic/defense/phantom/helpers/constants_spec.rb +87 -0
  196. data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_engine_spec.rb +222 -0
  197. data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_limb_spec.rb +180 -0
  198. data/spec/legion/extensions/agentic/defense/phantom/helpers/phantom_signal_spec.rb +59 -0
  199. data/spec/legion/extensions/agentic/defense/phantom/runners/cognitive_phantom_spec.rb +193 -0
  200. data/spec/legion/extensions/agentic/defense/quicksand/client_spec.rb +35 -0
  201. data/spec/legion/extensions/agentic/defense/quicksand/helpers/constants_spec.rb +58 -0
  202. data/spec/legion/extensions/agentic/defense/quicksand/helpers/pit_spec.rb +103 -0
  203. data/spec/legion/extensions/agentic/defense/quicksand/helpers/quicksand_engine_spec.rb +153 -0
  204. data/spec/legion/extensions/agentic/defense/quicksand/helpers/trap_spec.rb +166 -0
  205. data/spec/legion/extensions/agentic/defense/quicksand/runners/cognitive_quicksand_spec.rb +90 -0
  206. data/spec/legion/extensions/agentic/defense/quicksilver/client_spec.rb +72 -0
  207. data/spec/legion/extensions/agentic/defense/quicksilver/helpers/constants_spec.rb +105 -0
  208. data/spec/legion/extensions/agentic/defense/quicksilver/helpers/droplet_spec.rb +310 -0
  209. data/spec/legion/extensions/agentic/defense/quicksilver/helpers/pool_spec.rb +174 -0
  210. data/spec/legion/extensions/agentic/defense/quicksilver/helpers/quicksilver_engine_spec.rb +226 -0
  211. data/spec/legion/extensions/agentic/defense/quicksilver/runners/cognitive_quicksilver_spec.rb +227 -0
  212. data/spec/legion/extensions/agentic/defense/whirlpool/client_spec.rb +63 -0
  213. data/spec/legion/extensions/agentic/defense/whirlpool/helpers/captured_thought_spec.rb +171 -0
  214. data/spec/legion/extensions/agentic/defense/whirlpool/helpers/constants_spec.rb +65 -0
  215. data/spec/legion/extensions/agentic/defense/whirlpool/helpers/vortex_spec.rb +189 -0
  216. data/spec/legion/extensions/agentic/defense/whirlpool/helpers/whirlpool_engine_spec.rb +227 -0
  217. data/spec/legion/extensions/agentic/defense/whirlpool/runners/cognitive_whirlpool_spec.rb +226 -0
  218. data/spec/spec_helper.rb +46 -0
  219. metadata +303 -0
@@ -0,0 +1,263 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Erosion::Helpers::ErosionEngine do
4
+ let(:engine) { described_class.new }
5
+
6
+ let(:limestone_id) do
7
+ result = engine.create_formation(material_type: :limestone, domain: 'politics', content: 'taxes are necessary')
8
+ result[:formation_id]
9
+ end
10
+
11
+ let(:clay_id) do
12
+ result = engine.create_formation(material_type: :clay, domain: 'taste', content: 'pineapple on pizza is wrong')
13
+ result[:formation_id]
14
+ end
15
+
16
+ describe '#create_formation' do
17
+ it 'returns success: true' do
18
+ result = engine.create_formation(material_type: :granite, domain: 'science', content: 'gravity exists')
19
+ expect(result[:success]).to be(true)
20
+ end
21
+
22
+ it 'returns formation_id' do
23
+ result = engine.create_formation(material_type: :sandstone, domain: 'd', content: 'c')
24
+ expect(result[:formation_id]).to match(/\A[0-9a-f-]{36}\z/)
25
+ end
26
+
27
+ it 'returns formation hash' do
28
+ result = engine.create_formation(material_type: :chalk, domain: 'd', content: 'c')
29
+ expect(result[:formation]).to include(:formation_id, :material_type, :integrity)
30
+ end
31
+
32
+ it 'tracks formation_count' do
33
+ engine.create_formation(material_type: :limestone, domain: 'd', content: 'c')
34
+ expect(engine.formation_count).to eq(1)
35
+ end
36
+
37
+ it 'returns error for invalid material_type' do
38
+ result = engine.create_formation(material_type: :marble, domain: 'd', content: 'c')
39
+ expect(result[:success]).to be(false)
40
+ end
41
+
42
+ it 'returns error when MAX_FORMATIONS is reached' do
43
+ stub_const('Legion::Extensions::Agentic::Defense::Erosion::Helpers::Constants::MAX_FORMATIONS', 2)
44
+ engine.create_formation(material_type: :chalk, domain: 'd', content: 'c')
45
+ engine.create_formation(material_type: :clay, domain: 'd2', content: 'c2')
46
+ result = engine.create_formation(material_type: :granite, domain: 'd3', content: 'c3')
47
+ expect(result[:success]).to be(false)
48
+ end
49
+ end
50
+
51
+ describe '#erode' do
52
+ it 'returns success: true for valid erosion' do
53
+ id = limestone_id
54
+ result = engine.erode(formation_id: id, agent: :water, force: 0.3)
55
+ expect(result[:success]).to be(true)
56
+ end
57
+
58
+ it 'returns erosion details' do
59
+ id = limestone_id
60
+ result = engine.erode(formation_id: id, agent: :water, force: 0.3)
61
+ expect(result[:erosion]).to include(:effective_force, :integrity)
62
+ end
63
+
64
+ it 'returns channel details' do
65
+ id = limestone_id
66
+ result = engine.erode(formation_id: id, agent: :water, force: 0.3)
67
+ expect(result[:channel]).to include(:depth, :agent)
68
+ end
69
+
70
+ it 'returns formation_not_found for unknown id' do
71
+ result = engine.erode(formation_id: 'nope', agent: :water, force: 0.3)
72
+ expect(result[:error]).to eq(:formation_not_found)
73
+ end
74
+
75
+ it 'returns invalid_agent for bad agent' do
76
+ id = limestone_id
77
+ result = engine.erode(formation_id: id, agent: :laser, force: 0.3)
78
+ expect(result[:error]).to eq(:invalid_agent)
79
+ end
80
+
81
+ it 'creates a channel on first erosion' do
82
+ id = limestone_id
83
+ engine.erode(formation_id: id, agent: :wind, force: 0.2)
84
+ expect(engine.channel_count).to be >= 1
85
+ end
86
+
87
+ it 'deepens existing channel on repeated erosion' do
88
+ id = limestone_id
89
+ engine.erode(formation_id: id, agent: :water, force: 0.2)
90
+ result1 = engine.erode(formation_id: id, agent: :water, force: 0.2)
91
+ result2 = engine.erode(formation_id: id, agent: :water, force: 0.2)
92
+ expect(result2[:channel][:depth]).to be >= result1[:channel][:depth]
93
+ end
94
+
95
+ it 'does not create duplicate channels for same agent' do
96
+ id = limestone_id
97
+ 3.times { engine.erode(formation_id: id, agent: :water, force: 0.1) }
98
+ expect(engine.channel_count).to eq(1)
99
+ end
100
+ end
101
+
102
+ describe '#carve_channel' do
103
+ it 'creates a new channel' do
104
+ id = limestone_id
105
+ engine.carve_channel(formation_id: id, agent: :ice, force: 0.3)
106
+ expect(engine.channel_count).to be >= 1
107
+ end
108
+
109
+ it 'returns channel hash' do
110
+ id = limestone_id
111
+ result = engine.carve_channel(formation_id: id, agent: :wind)
112
+ expect(result).to include(:channel_id, :depth, :agent)
113
+ end
114
+
115
+ it 'reuses existing channel for same agent' do
116
+ id = limestone_id
117
+ engine.carve_channel(formation_id: id, agent: :water)
118
+ engine.carve_channel(formation_id: id, agent: :water)
119
+ expect(engine.channel_count).to eq(1)
120
+ end
121
+
122
+ it 'widens channel when depth >= 0.3' do
123
+ id = clay_id
124
+ engine.carve_channel(formation_id: id, agent: :water, force: 0.5)
125
+ engine.carve_channel(formation_id: id, agent: :water, force: 0.5)
126
+ result = engine.carve_channel(formation_id: id, agent: :water, force: 0.5)
127
+ expect(result[:width]).to be > 0.1
128
+ end
129
+ end
130
+
131
+ describe '#weather_all!' do
132
+ it 'weathers all formations' do
133
+ 3.times { |i| engine.create_formation(material_type: :chalk, domain: "d#{i}", content: "c#{i}") }
134
+ result = engine.weather_all!
135
+ expect(result[:weathered]).to eq(3)
136
+ end
137
+
138
+ it 'returns success: true' do
139
+ engine.create_formation(material_type: :limestone, domain: 'd', content: 'c')
140
+ result = engine.weather_all!
141
+ expect(result[:success]).to be(true)
142
+ end
143
+
144
+ it 'returns empty results when no formations' do
145
+ result = engine.weather_all!
146
+ expect(result[:weathered]).to eq(0)
147
+ end
148
+
149
+ it 'reduces integrity of formations' do
150
+ id = limestone_id
151
+ before = engine.get_formation(id)[:formation][:integrity]
152
+ engine.weather_all!(force: 0.5, agent: :wind)
153
+ after = engine.get_formation(id)[:formation][:integrity]
154
+ expect(after).to be < before
155
+ end
156
+ end
157
+
158
+ describe '#deepest_channels' do
159
+ before do
160
+ id1 = engine.create_formation(material_type: :clay, domain: 'd1', content: 'c1')[:formation_id]
161
+ id2 = engine.create_formation(material_type: :chalk, domain: 'd2', content: 'c2')[:formation_id]
162
+ 3.times { engine.erode(formation_id: id1, agent: :water, force: 0.4) }
163
+ engine.erode(formation_id: id2, agent: :wind, force: 0.1)
164
+ end
165
+
166
+ it 'returns channels sorted deepest first' do
167
+ channels = engine.deepest_channels(limit: 5)
168
+ depths = channels.map { |c| c[:depth] }
169
+ expect(depths).to eq(depths.sort.reverse)
170
+ end
171
+
172
+ it 'respects limit' do
173
+ channels = engine.deepest_channels(limit: 1)
174
+ expect(channels.size).to eq(1)
175
+ end
176
+
177
+ it 'returns channel hashes' do
178
+ channels = engine.deepest_channels
179
+ expect(channels.first).to include(:depth, :agent, :formation_id)
180
+ end
181
+ end
182
+
183
+ describe '#most_eroded' do
184
+ before do
185
+ id1 = engine.create_formation(material_type: :clay, domain: 'd1', content: 'c1')[:formation_id]
186
+ id2 = engine.create_formation(material_type: :granite, domain: 'd2', content: 'c2')[:formation_id]
187
+ 5.times { engine.erode(formation_id: id1, agent: :water, force: 0.5) }
188
+ engine.erode(formation_id: id2, agent: :water, force: 0.1)
189
+ end
190
+
191
+ it 'returns formations sorted by erosion_depth descending' do
192
+ formations = engine.most_eroded(limit: 5)
193
+ depths = formations.map { |f| f[:erosion_depth] }
194
+ expect(depths).to eq(depths.sort.reverse)
195
+ end
196
+
197
+ it 'respects limit' do
198
+ formations = engine.most_eroded(limit: 1)
199
+ expect(formations.size).to eq(1)
200
+ end
201
+ end
202
+
203
+ describe '#erosion_report' do
204
+ it 'returns success: true' do
205
+ result = engine.erosion_report
206
+ expect(result[:success]).to be(true)
207
+ end
208
+
209
+ it 'includes total_formations count' do
210
+ engine.create_formation(material_type: :limestone, domain: 'd', content: 'c')
211
+ result = engine.erosion_report
212
+ expect(result[:total_formations]).to eq(1)
213
+ end
214
+
215
+ it 'includes total_channels count' do
216
+ id = limestone_id
217
+ engine.erode(formation_id: id, agent: :water, force: 0.2)
218
+ result = engine.erosion_report
219
+ expect(result[:total_channels]).to be >= 1
220
+ end
221
+
222
+ it 'counts canyons correctly' do
223
+ id = clay_id
224
+ 10.times { engine.erode(formation_id: id, agent: :water, force: 1.0) }
225
+ result = engine.erosion_report
226
+ expect(result[:canyons]).to be >= 1
227
+ end
228
+
229
+ it 'includes average_depth' do
230
+ result = engine.erosion_report
231
+ expect(result).to have_key(:average_depth)
232
+ end
233
+
234
+ it 'reports average_depth 0.0 with no formations' do
235
+ result = engine.erosion_report
236
+ expect(result[:average_depth]).to eq(0.0)
237
+ end
238
+
239
+ it 'includes deepest_channels and most_eroded' do
240
+ result = engine.erosion_report
241
+ expect(result).to include(:deepest_channels, :most_eroded)
242
+ end
243
+ end
244
+
245
+ describe '#get_formation' do
246
+ it 'returns found: true for existing formation' do
247
+ id = limestone_id
248
+ result = engine.get_formation(id)
249
+ expect(result[:found]).to be(true)
250
+ end
251
+
252
+ it 'returns formation hash' do
253
+ id = limestone_id
254
+ result = engine.get_formation(id)
255
+ expect(result[:formation]).to include(:formation_id, :material_type)
256
+ end
257
+
258
+ it 'returns found: false for unknown id' do
259
+ result = engine.get_formation('nonexistent')
260
+ expect(result[:found]).to be(false)
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Erosion::Helpers::Formation do
4
+ let(:formation) { described_class.new(material_type: :limestone, domain: 'politics', content: 'taxes are bad') }
5
+ let(:granite_formation) { described_class.new(material_type: :granite, domain: 'science', content: 'gravity is real') }
6
+ let(:clay_formation) { described_class.new(material_type: :clay, domain: 'taste', content: 'chocolate is best') }
7
+
8
+ describe '#initialize' do
9
+ it 'assigns a UUID formation_id' do
10
+ expect(formation.formation_id).to match(/\A[0-9a-f-]{36}\z/)
11
+ end
12
+
13
+ it 'sets material_type' do
14
+ expect(formation.material_type).to eq(:limestone)
15
+ end
16
+
17
+ it 'sets domain' do
18
+ expect(formation.domain).to eq('politics')
19
+ end
20
+
21
+ it 'sets content' do
22
+ expect(formation.content).to eq('taxes are bad')
23
+ end
24
+
25
+ it 'sets resistance from constants by default' do
26
+ expect(formation.resistance).to eq(
27
+ Legion::Extensions::Agentic::Defense::Erosion::Helpers::Constants::RESISTANCE[:limestone]
28
+ )
29
+ end
30
+
31
+ it 'accepts an explicit resistance override' do
32
+ f = described_class.new(material_type: :chalk, domain: 'd', content: 'c', resistance: 0.75)
33
+ expect(f.resistance).to eq(0.75)
34
+ end
35
+
36
+ it 'starts with integrity 1.0' do
37
+ expect(formation.integrity).to eq(1.0)
38
+ end
39
+
40
+ it 'starts with erosion_depth 0.0' do
41
+ expect(formation.erosion_depth).to eq(0.0)
42
+ end
43
+
44
+ it 'raises ArgumentError for invalid material_type' do
45
+ expect do
46
+ described_class.new(material_type: :diamond, domain: 'd', content: 'c')
47
+ end.to raise_error(ArgumentError, /invalid material_type/)
48
+ end
49
+ end
50
+
51
+ describe '#erode!' do
52
+ it 'reduces integrity' do
53
+ before_integrity = formation.integrity
54
+ formation.erode!(:water, 0.5)
55
+ expect(formation.integrity).to be < before_integrity
56
+ end
57
+
58
+ it 'increases erosion_depth' do
59
+ formation.erode!(:water, 0.5)
60
+ expect(formation.erosion_depth).to be > 0.0
61
+ end
62
+
63
+ it 'returns a result hash with effective_force' do
64
+ result = formation.erode!(:wind, 0.3)
65
+ expect(result).to include(:agent, :force, :effective_force, :integrity, :erosion_depth)
66
+ end
67
+
68
+ it 'clamps force to 1.0 max' do
69
+ result = formation.erode!(:water, 5.0)
70
+ expect(result[:force]).to eq(1.0)
71
+ end
72
+
73
+ it 'clamps force to 0.0 min' do
74
+ result = formation.erode!(:water, -1.0)
75
+ expect(result[:force]).to eq(0.0)
76
+ end
77
+
78
+ it 'granite resists more than clay' do
79
+ granite_result = granite_formation.erode!(:water, 0.5)
80
+ clay_result = clay_formation.erode!(:water, 0.5)
81
+ expect(granite_result[:effective_force]).to be < clay_result[:effective_force]
82
+ end
83
+
84
+ it 'raises ArgumentError for invalid agent' do
85
+ expect { formation.erode!(:laser, 0.5) }.to raise_error(ArgumentError, /invalid agent/)
86
+ end
87
+
88
+ it 'does not reduce integrity below 0.0' do
89
+ 10.times { formation.erode!(:chemical, 1.0) }
90
+ expect(formation.integrity).to be >= 0.0
91
+ end
92
+
93
+ it 'does not increase erosion_depth above 1.0' do
94
+ 10.times { formation.erode!(:chemical, 1.0) }
95
+ expect(formation.erosion_depth).to be <= 1.0
96
+ end
97
+
98
+ it 'updates updated_at' do
99
+ original = formation.updated_at
100
+ sleep(0.001)
101
+ formation.erode!(:water, 0.1)
102
+ expect(formation.updated_at).to be >= original
103
+ end
104
+ end
105
+
106
+ describe '#resist!' do
107
+ it 'increases integrity' do
108
+ formation.erode!(:water, 0.5)
109
+ before = formation.integrity
110
+ formation.resist!
111
+ expect(formation.integrity).to be > before
112
+ end
113
+
114
+ it 'accepts a custom recovery amount' do
115
+ formation.erode!(:water, 0.5)
116
+ before = formation.integrity
117
+ formation.resist!(0.2)
118
+ expect(formation.integrity).to be_within(0.001).of(before + 0.2)
119
+ end
120
+
121
+ it 'clamps integrity to 1.0' do
122
+ formation.resist!(2.0)
123
+ expect(formation.integrity).to eq(1.0)
124
+ end
125
+
126
+ it 'returns a hash with integrity and recovered' do
127
+ result = formation.resist!
128
+ expect(result).to include(:integrity, :recovered)
129
+ end
130
+ end
131
+
132
+ describe '#weathered?' do
133
+ it 'returns false for pristine formation' do
134
+ expect(formation.weathered?).to be(false)
135
+ end
136
+
137
+ it 'returns true after significant erosion' do
138
+ formation.erode!(:chemical, 1.0)
139
+ formation.erode!(:chemical, 1.0)
140
+ formation.erode!(:chemical, 1.0)
141
+ expect(formation.weathered?).to be(true)
142
+ end
143
+ end
144
+
145
+ describe '#canyon?' do
146
+ it 'returns false for fresh formation' do
147
+ expect(formation.canyon?).to be(false)
148
+ end
149
+
150
+ it 'returns true when erosion_depth >= 0.7' do
151
+ 10.times { clay_formation.erode!(:water, 1.0) }
152
+ expect(clay_formation.canyon?).to be(true)
153
+ end
154
+ end
155
+
156
+ describe '#pristine?' do
157
+ it 'returns true for new formation' do
158
+ expect(formation.pristine?).to be(true)
159
+ end
160
+
161
+ it 'returns false after erosion reduces integrity below 0.9' do
162
+ formation.erode!(:chemical, 1.0)
163
+ expect(formation.pristine?).to be(false)
164
+ end
165
+ end
166
+
167
+ describe '#integrity_label' do
168
+ it 'returns :pristine for new formation' do
169
+ expect(formation.integrity_label).to eq(:pristine)
170
+ end
171
+
172
+ it 'returns :ruins for fully eroded formation' do
173
+ 10.times { clay_formation.erode!(:chemical, 1.0) }
174
+ expect(clay_formation.integrity_label).to eq(:ruins)
175
+ end
176
+ end
177
+
178
+ describe '#depth_label' do
179
+ it 'returns :surface_scratch for new formation' do
180
+ expect(formation.depth_label).to eq(:surface_scratch)
181
+ end
182
+
183
+ it 'returns :canyon for deeply eroded clay' do
184
+ 10.times { clay_formation.erode!(:water, 1.0) }
185
+ expect(clay_formation.depth_label).to eq(:canyon)
186
+ end
187
+ end
188
+
189
+ describe '#to_h' do
190
+ it 'returns a hash with all required keys' do
191
+ h = formation.to_h
192
+ expect(h).to include(
193
+ :formation_id, :material_type, :domain, :content, :resistance,
194
+ :integrity, :erosion_depth, :integrity_label, :depth_label,
195
+ :weathered, :canyon, :pristine, :created_at, :updated_at
196
+ )
197
+ end
198
+
199
+ it 'reflects current state' do
200
+ formation.erode!(:water, 0.3)
201
+ h = formation.to_h
202
+ expect(h[:integrity]).to be < 1.0
203
+ expect(h[:erosion_depth]).to be > 0.0
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Erosion::Runners::CognitiveErosion do
4
+ let(:engine) { Legion::Extensions::Agentic::Defense::Erosion::Helpers::ErosionEngine.new }
5
+
6
+ let(:formation_id) do
7
+ described_class.create_formation(
8
+ material_type: :limestone, domain: 'economy', content: 'growth is always good', engine: engine
9
+ )[:formation_id]
10
+ end
11
+
12
+ describe '.create_formation' do
13
+ it 'returns success: true' do
14
+ result = described_class.create_formation(
15
+ material_type: :granite, domain: 'science', content: 'vaccines work', engine: engine
16
+ )
17
+ expect(result[:success]).to be(true)
18
+ end
19
+
20
+ it 'returns formation_id' do
21
+ result = described_class.create_formation(
22
+ material_type: :chalk, domain: 'culture', content: 'tradition matters', engine: engine
23
+ )
24
+ expect(result[:formation_id]).to match(/\A[0-9a-f-]{36}\z/)
25
+ end
26
+
27
+ it 'returns failure for invalid material_type' do
28
+ result = described_class.create_formation(
29
+ material_type: :diamond, domain: 'd', content: 'c', engine: engine
30
+ )
31
+ expect(result[:success]).to be(false)
32
+ end
33
+ end
34
+
35
+ describe '.erode' do
36
+ it 'returns success: true' do
37
+ id = formation_id
38
+ result = described_class.erode(formation_id: id, agent: :water, force: 0.3, engine: engine)
39
+ expect(result[:success]).to be(true)
40
+ end
41
+
42
+ it 'returns erosion details' do
43
+ id = formation_id
44
+ result = described_class.erode(formation_id: id, agent: :wind, force: 0.2, engine: engine)
45
+ expect(result[:erosion]).to include(:effective_force)
46
+ end
47
+
48
+ it 'returns failure for unknown formation' do
49
+ result = described_class.erode(formation_id: 'nope', agent: :water, force: 0.3, engine: engine)
50
+ expect(result[:success]).to be(false)
51
+ end
52
+
53
+ it 'returns failure for invalid agent' do
54
+ id = formation_id
55
+ result = described_class.erode(formation_id: id, agent: :laser, force: 0.3, engine: engine)
56
+ expect(result[:success]).to be(false)
57
+ end
58
+ end
59
+
60
+ describe '.weather_all' do
61
+ it 'returns success: true' do
62
+ result = described_class.weather_all(engine: engine)
63
+ expect(result[:success]).to be(true)
64
+ end
65
+
66
+ it 'weathers all formations' do
67
+ described_class.create_formation(material_type: :chalk, domain: 'd1', content: 'c1', engine: engine)
68
+ described_class.create_formation(material_type: :clay, domain: 'd2', content: 'c2', engine: engine)
69
+ result = described_class.weather_all(engine: engine)
70
+ expect(result[:weathered]).to eq(2)
71
+ end
72
+
73
+ it 'accepts custom force and agent' do
74
+ described_class.create_formation(material_type: :sandstone, domain: 'd', content: 'c', engine: engine)
75
+ result = described_class.weather_all(force: 0.3, agent: :ice, engine: engine)
76
+ expect(result[:success]).to be(true)
77
+ end
78
+ end
79
+
80
+ describe '.deepest_channels' do
81
+ it 'returns success: true' do
82
+ result = described_class.deepest_channels(engine: engine)
83
+ expect(result[:success]).to be(true)
84
+ end
85
+
86
+ it 'returns channels array' do
87
+ result = described_class.deepest_channels(engine: engine)
88
+ expect(result[:channels]).to be_an(Array)
89
+ end
90
+
91
+ it 'includes count' do
92
+ result = described_class.deepest_channels(engine: engine)
93
+ expect(result).to have_key(:count)
94
+ end
95
+
96
+ it 'returns populated channels after erosion' do
97
+ id = formation_id
98
+ described_class.erode(formation_id: id, agent: :water, force: 0.4, engine: engine)
99
+ result = described_class.deepest_channels(limit: 5, engine: engine)
100
+ expect(result[:count]).to be >= 1
101
+ end
102
+ end
103
+
104
+ describe '.most_eroded' do
105
+ it 'returns success: true' do
106
+ result = described_class.most_eroded(engine: engine)
107
+ expect(result[:success]).to be(true)
108
+ end
109
+
110
+ it 'returns formations array' do
111
+ result = described_class.most_eroded(engine: engine)
112
+ expect(result[:formations]).to be_an(Array)
113
+ end
114
+
115
+ it 'returns populated formations after erosion' do
116
+ id = formation_id
117
+ 3.times { described_class.erode(formation_id: id, agent: :water, force: 0.5, engine: engine) }
118
+ result = described_class.most_eroded(limit: 5, engine: engine)
119
+ expect(result[:count]).to be >= 1
120
+ end
121
+ end
122
+
123
+ describe '.erosion_report' do
124
+ it 'returns success: true' do
125
+ result = described_class.erosion_report(engine: engine)
126
+ expect(result[:success]).to be(true)
127
+ end
128
+
129
+ it 'includes formation and channel counts' do
130
+ result = described_class.erosion_report(engine: engine)
131
+ expect(result).to include(:total_formations, :total_channels, :canyons, :weathered)
132
+ end
133
+
134
+ it 'reflects formations created' do
135
+ described_class.create_formation(material_type: :limestone, domain: 'd', content: 'c', engine: engine)
136
+ result = described_class.erosion_report(engine: engine)
137
+ expect(result[:total_formations]).to be >= 1
138
+ end
139
+ end
140
+
141
+ describe '.get_formation' do
142
+ it 'returns found: true for existing formation' do
143
+ id = formation_id
144
+ result = described_class.get_formation(formation_id: id, engine: engine)
145
+ expect(result[:found]).to be(true)
146
+ end
147
+
148
+ it 'returns found: false for unknown id' do
149
+ result = described_class.get_formation(formation_id: 'ghost', engine: engine)
150
+ expect(result[:found]).to be(false)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::ErrorMonitoring::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'includes Runners::ErrorMonitoring' do
7
+ expect(described_class.ancestors).to include(Legion::Extensions::Agentic::Defense::ErrorMonitoring::Runners::ErrorMonitoring)
8
+ end
9
+
10
+ it 'supports full error monitoring lifecycle' do
11
+ # Normal operation with some successes
12
+ 3.times { client.report_success(action: :process, domain: :data) }
13
+
14
+ # Error occurs
15
+ client.report_error(action: :api_call, domain: :network, intended: :ok, actual: :timeout, severity: 0.6)
16
+
17
+ # System should now be vigilant with slowdown
18
+ state = client.monitoring_state
19
+ expect(state[:slowdown]).to be > 0
20
+
21
+ # Conflict detected
22
+ client.report_conflict(action_a: :retry, action_b: :abort, domain: :network, intensity: 0.7)
23
+
24
+ # Correction applied
25
+ client.apply_correction(action: :api_call, domain: :network, original_error: :timeout,
26
+ correction: :retry_with_backoff)
27
+
28
+ # Verify correction
29
+ uncorrected = client.uncorrected_errors
30
+ expect(uncorrected[:count]).to eq(0)
31
+
32
+ # Tick to decay slowdown
33
+ client.update_error_monitoring
34
+
35
+ # Stats
36
+ stats = client.error_monitoring_stats
37
+ expect(stats[:stats][:total_errors]).to eq(1)
38
+ expect(stats[:stats][:correction_rate]).to eq(1.0)
39
+ end
40
+ end