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,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Immunology::Helpers::Constants do
4
+ describe 'DEFAULT_RESISTANCE' do
5
+ it 'is 0.5' do
6
+ expect(described_class::DEFAULT_RESISTANCE).to eq(0.5)
7
+ end
8
+ end
9
+
10
+ describe 'RESISTANCE_BOOST' do
11
+ it 'is 0.1' do
12
+ expect(described_class::RESISTANCE_BOOST).to eq(0.1)
13
+ end
14
+ end
15
+
16
+ describe 'RESISTANCE_DECAY' do
17
+ it 'is 0.02' do
18
+ expect(described_class::RESISTANCE_DECAY).to eq(0.02)
19
+ end
20
+ end
21
+
22
+ describe 'MAX_THREATS' do
23
+ it 'is 500' do
24
+ expect(described_class::MAX_THREATS).to eq(500)
25
+ end
26
+ end
27
+
28
+ describe 'MAX_ANTIBODIES' do
29
+ it 'is 200' do
30
+ expect(described_class::MAX_ANTIBODIES).to eq(200)
31
+ end
32
+ end
33
+
34
+ describe 'THREAT_LABELS' do
35
+ it 'labels 0.9 as critical' do
36
+ label = described_class::THREAT_LABELS.find { |r, _| r.cover?(0.9) }&.last
37
+ expect(label).to eq(:critical)
38
+ end
39
+
40
+ it 'labels 0.7 as severe' do
41
+ label = described_class::THREAT_LABELS.find { |r, _| r.cover?(0.7) }&.last
42
+ expect(label).to eq(:severe)
43
+ end
44
+
45
+ it 'labels 0.5 as moderate' do
46
+ label = described_class::THREAT_LABELS.find { |r, _| r.cover?(0.5) }&.last
47
+ expect(label).to eq(:moderate)
48
+ end
49
+
50
+ it 'labels 0.3 as low' do
51
+ label = described_class::THREAT_LABELS.find { |r, _| r.cover?(0.3) }&.last
52
+ expect(label).to eq(:low)
53
+ end
54
+
55
+ it 'labels 0.1 as negligible' do
56
+ label = described_class::THREAT_LABELS.find { |r, _| r.cover?(0.1) }&.last
57
+ expect(label).to eq(:negligible)
58
+ end
59
+ end
60
+
61
+ describe 'IMMUNITY_LABELS' do
62
+ it 'labels 0.9 as immune' do
63
+ label = described_class::IMMUNITY_LABELS.find { |r, _| r.cover?(0.9) }&.last
64
+ expect(label).to eq(:immune)
65
+ end
66
+
67
+ it 'labels 0.1 as compromised' do
68
+ label = described_class::IMMUNITY_LABELS.find { |r, _| r.cover?(0.1) }&.last
69
+ expect(label).to eq(:compromised)
70
+ end
71
+ end
72
+
73
+ describe 'MANIPULATION_TACTICS' do
74
+ it 'has 10 tactics' do
75
+ expect(described_class::MANIPULATION_TACTICS.size).to eq(10)
76
+ end
77
+
78
+ it 'includes authority_appeal' do
79
+ expect(described_class::MANIPULATION_TACTICS).to include(:authority_appeal)
80
+ end
81
+
82
+ it 'includes gaslighting' do
83
+ expect(described_class::MANIPULATION_TACTICS).to include(:gaslighting)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Immunology::Helpers::ImmuneEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ describe '#initialize' do
7
+ it 'starts with DEFAULT_RESISTANCE' do
8
+ expect(engine.resistance).to eq(Legion::Extensions::Agentic::Defense::Immunology::Helpers::Constants::DEFAULT_RESISTANCE)
9
+ end
10
+
11
+ it 'starts with inflammatory false' do
12
+ expect(engine.inflammatory).to be false
13
+ end
14
+ end
15
+
16
+ describe '#detect_threat' do
17
+ it 'returns a Threat object' do
18
+ threat = engine.detect_threat(source: 'user', tactic: :gaslighting, content_hash: 'h1')
19
+ expect(threat).to be_a(Legion::Extensions::Agentic::Defense::Immunology::Helpers::Threat)
20
+ end
21
+
22
+ it 'stores the threat' do
23
+ threat = engine.detect_threat(source: 'user', tactic: :strawman, content_hash: 'h2')
24
+ expect(engine.to_h[:threat_count]).to eq(1)
25
+ expect(threat.id).not_to be_nil
26
+ end
27
+
28
+ it 'applies antibody resistance to threat_level' do
29
+ engine.create_antibody(tactic: :authority_appeal, pattern: 'expert claim', strength: 0.8)
30
+ threat = engine.detect_threat(source: 'src', tactic: :authority_appeal, content_hash: 'h3', threat_level: 0.8)
31
+ expect(threat.threat_level).to be < 0.8
32
+ end
33
+
34
+ it 'tracks multiple threats' do
35
+ engine.detect_threat(source: 's1', tactic: :gaslighting, content_hash: 'a')
36
+ engine.detect_threat(source: 's2', tactic: :strawman, content_hash: 'b')
37
+ expect(engine.to_h[:threat_count]).to eq(2)
38
+ end
39
+ end
40
+
41
+ describe '#quarantine_threat' do
42
+ let(:threat) { engine.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1') }
43
+
44
+ it 'quarantines an existing threat' do
45
+ result = engine.quarantine_threat(threat_id: threat.id)
46
+ expect(result[:success]).to be true
47
+ expect(threat.quarantined).to be true
48
+ end
49
+
50
+ it 'returns failure for unknown threat_id' do
51
+ result = engine.quarantine_threat(threat_id: 'nonexistent')
52
+ expect(result[:success]).to be false
53
+ end
54
+
55
+ it 'increments quarantined_count' do
56
+ engine.quarantine_threat(threat_id: threat.id)
57
+ expect(engine.to_h[:quarantined_count]).to eq(1)
58
+ end
59
+ end
60
+
61
+ describe '#release_threat' do
62
+ let(:threat) { engine.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1') }
63
+
64
+ it 'releases a quarantined threat' do
65
+ engine.quarantine_threat(threat_id: threat.id)
66
+ result = engine.release_threat(threat_id: threat.id)
67
+ expect(result[:success]).to be true
68
+ expect(threat.quarantined).to be false
69
+ end
70
+
71
+ it 'returns failure for unknown threat_id' do
72
+ result = engine.release_threat(threat_id: 'nonexistent')
73
+ expect(result[:success]).to be false
74
+ end
75
+ end
76
+
77
+ describe '#inoculate' do
78
+ let(:threat) { engine.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1') }
79
+
80
+ it 'returns success for existing threat' do
81
+ result = engine.inoculate(threat_id: threat.id)
82
+ expect(result[:success]).to be true
83
+ end
84
+
85
+ it 'increments exposure_count on the threat' do
86
+ engine.inoculate(threat_id: threat.id)
87
+ expect(threat.exposure_count).to eq(1)
88
+ end
89
+
90
+ it 'boosts overall resistance' do
91
+ original = engine.resistance
92
+ engine.inoculate(threat_id: threat.id)
93
+ expect(engine.resistance).to be > original
94
+ end
95
+
96
+ it 'returns failure for unknown threat_id' do
97
+ result = engine.inoculate(threat_id: 'nonexistent')
98
+ expect(result[:success]).to be false
99
+ end
100
+ end
101
+
102
+ describe '#create_antibody' do
103
+ it 'returns an Antibody object' do
104
+ ab = engine.create_antibody(tactic: :gaslighting, pattern: 'reality questioning')
105
+ expect(ab).to be_a(Legion::Extensions::Agentic::Defense::Immunology::Helpers::Antibody)
106
+ end
107
+
108
+ it 'stores the antibody' do
109
+ engine.create_antibody(tactic: :strawman, pattern: 'misrepresentation')
110
+ expect(engine.to_h[:antibody_count]).to eq(1)
111
+ end
112
+
113
+ it 'accepts custom strength' do
114
+ ab = engine.create_antibody(tactic: :gaslighting, pattern: 'test', strength: 0.8)
115
+ expect(ab.strength).to eq(0.8)
116
+ end
117
+ end
118
+
119
+ describe '#scan_for_tactic' do
120
+ before do
121
+ engine.detect_threat(source: 's1', tactic: :gaslighting, content_hash: 'h1')
122
+ engine.detect_threat(source: 's2', tactic: :gaslighting, content_hash: 'h2')
123
+ engine.detect_threat(source: 's3', tactic: :strawman, content_hash: 'h3')
124
+ end
125
+
126
+ it 'returns threats matching the tactic' do
127
+ threats = engine.scan_for_tactic(tactic: :gaslighting)
128
+ expect(threats.size).to eq(2)
129
+ expect(threats.all? { |t| t.tactic == :gaslighting }).to be true
130
+ end
131
+
132
+ it 'returns empty array for unknown tactic' do
133
+ threats = engine.scan_for_tactic(tactic: :bandwagon)
134
+ expect(threats).to be_empty
135
+ end
136
+ end
137
+
138
+ describe '#trigger_inflammatory_response' do
139
+ it 'sets inflammatory to true' do
140
+ engine.trigger_inflammatory_response
141
+ expect(engine.inflammatory).to be true
142
+ end
143
+
144
+ it 'returns inflammatory: true' do
145
+ result = engine.trigger_inflammatory_response
146
+ expect(result[:inflammatory]).to be true
147
+ end
148
+ end
149
+
150
+ describe '#resolve_inflammation' do
151
+ before { engine.trigger_inflammatory_response }
152
+
153
+ it 'sets inflammatory to false' do
154
+ engine.resolve_inflammation
155
+ expect(engine.inflammatory).to be false
156
+ end
157
+
158
+ it 'returns inflammatory: false' do
159
+ result = engine.resolve_inflammation
160
+ expect(result[:inflammatory]).to be false
161
+ end
162
+ end
163
+
164
+ describe '#overall_immunity' do
165
+ it 'returns a float between 0.0 and 1.0' do
166
+ score = engine.overall_immunity
167
+ expect(score).to be_between(0.0, 1.0)
168
+ end
169
+
170
+ it 'increases with more effective antibodies' do
171
+ base = engine.overall_immunity
172
+ engine.create_antibody(tactic: :gaslighting, pattern: 'test', strength: 0.9)
173
+ engine.create_antibody(tactic: :strawman, pattern: 'test2', strength: 0.9)
174
+ expect(engine.overall_immunity).to be > base
175
+ end
176
+ end
177
+
178
+ describe '#immunity_label' do
179
+ it 'returns a symbol' do
180
+ expect(engine.immunity_label).to be_a(Symbol)
181
+ end
182
+
183
+ it 'returns :normal at default resistance with no antibodies' do
184
+ label = engine.immunity_label
185
+ expect(%i[normal vulnerable]).to include(label)
186
+ end
187
+ end
188
+
189
+ describe '#vulnerability_report' do
190
+ it 'returns covered, uncovered, and coverage' do
191
+ report = engine.vulnerability_report
192
+ expect(report).to include(:covered, :uncovered, :coverage)
193
+ end
194
+
195
+ it 'starts fully uncovered' do
196
+ report = engine.vulnerability_report
197
+ expect(report[:uncovered].size).to eq(Legion::Extensions::Agentic::Defense::Immunology::Helpers::Constants::MANIPULATION_TACTICS.size)
198
+ end
199
+
200
+ it 'reduces uncovered after creating an antibody' do
201
+ engine.create_antibody(tactic: :gaslighting, pattern: 'test')
202
+ report = engine.vulnerability_report
203
+ expect(report[:uncovered]).not_to include(:gaslighting)
204
+ end
205
+ end
206
+
207
+ describe '#threat_history' do
208
+ before do
209
+ 5.times { |i| engine.detect_threat(source: "s#{i}", tactic: :gaslighting, content_hash: "h#{i}") }
210
+ end
211
+
212
+ it 'returns up to limit threats' do
213
+ history = engine.threat_history(limit: 3)
214
+ expect(history.size).to eq(3)
215
+ end
216
+
217
+ it 'returns hashes' do
218
+ history = engine.threat_history
219
+ expect(history.first).to be_a(Hash)
220
+ end
221
+
222
+ it 'defaults to limit 10' do
223
+ history = engine.threat_history
224
+ expect(history.size).to be <= 10
225
+ end
226
+ end
227
+
228
+ describe '#decay_all' do
229
+ it 'decays antibodies' do
230
+ ab = engine.create_antibody(tactic: :gaslighting, pattern: 'test', strength: 0.5)
231
+ original_strength = ab.strength
232
+ engine.decay_all
233
+ expect(ab.strength).to be < original_strength
234
+ end
235
+
236
+ it 'decays overall resistance' do
237
+ original = engine.resistance
238
+ engine.decay_all
239
+ expect(engine.resistance).to be < original
240
+ end
241
+
242
+ it 'returns resistance and antibodies_decayed' do
243
+ engine.create_antibody(tactic: :gaslighting, pattern: 'test')
244
+ result = engine.decay_all
245
+ expect(result).to include(:resistance, :antibodies_decayed)
246
+ end
247
+ end
248
+
249
+ describe '#prune_ineffective' do
250
+ it 'removes antibodies below effective threshold' do
251
+ engine.create_antibody(tactic: :gaslighting, pattern: 'strong', strength: 0.8)
252
+ engine.create_antibody(tactic: :strawman, pattern: 'weak', strength: 0.1)
253
+ result = engine.prune_ineffective
254
+ expect(result[:pruned]).to eq(1)
255
+ expect(result[:remaining]).to eq(1)
256
+ end
257
+
258
+ it 'returns 0 pruned when all are effective' do
259
+ engine.create_antibody(tactic: :gaslighting, pattern: 'strong', strength: 0.8)
260
+ result = engine.prune_ineffective
261
+ expect(result[:pruned]).to eq(0)
262
+ end
263
+ end
264
+
265
+ describe '#to_h' do
266
+ it 'returns engine stats as hash' do
267
+ h = engine.to_h
268
+ expect(h).to include(
269
+ :threat_count, :quarantined_count, :antibody_count,
270
+ :effective_antibody_count, :resistance, :inflammatory,
271
+ :overall_immunity, :immunity_label
272
+ )
273
+ end
274
+ end
275
+ end
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Immunology::Helpers::Threat do
4
+ subject(:threat) { described_class.new(source: 'test', tactic: :gaslighting, content_hash: 'abc123') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a uuid id' do
8
+ expect(threat.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'stores source' do
12
+ expect(threat.source).to eq('test')
13
+ end
14
+
15
+ it 'stores tactic' do
16
+ expect(threat.tactic).to eq(:gaslighting)
17
+ end
18
+
19
+ it 'stores content_hash' do
20
+ expect(threat.content_hash).to eq('abc123')
21
+ end
22
+
23
+ it 'defaults threat_level to 0.5' do
24
+ expect(threat.threat_level).to eq(0.5)
25
+ end
26
+
27
+ it 'defaults quarantined to false' do
28
+ expect(threat.quarantined).to be false
29
+ end
30
+
31
+ it 'defaults exposure_count to 0' do
32
+ expect(threat.exposure_count).to eq(0)
33
+ end
34
+
35
+ it 'clamps threat_level above 1.0' do
36
+ t = described_class.new(source: 's', tactic: :strawman, content_hash: 'x', threat_level: 1.5)
37
+ expect(t.threat_level).to eq(1.0)
38
+ end
39
+
40
+ it 'clamps threat_level below 0.0' do
41
+ t = described_class.new(source: 's', tactic: :strawman, content_hash: 'x', threat_level: -0.5)
42
+ expect(t.threat_level).to eq(0.0)
43
+ end
44
+ end
45
+
46
+ describe '#threat_label' do
47
+ it 'returns :critical for 0.9' do
48
+ t = described_class.new(source: 's', tactic: :gaslighting, content_hash: 'x', threat_level: 0.9)
49
+ expect(t.threat_label).to eq(:critical)
50
+ end
51
+
52
+ it 'returns :moderate for 0.5' do
53
+ expect(threat.threat_label).to eq(:moderate)
54
+ end
55
+
56
+ it 'returns :negligible for 0.1' do
57
+ t = described_class.new(source: 's', tactic: :gaslighting, content_hash: 'x', threat_level: 0.1)
58
+ expect(t.threat_label).to eq(:negligible)
59
+ end
60
+ end
61
+
62
+ describe '#quarantine!' do
63
+ it 'sets quarantined to true' do
64
+ threat.quarantine!
65
+ expect(threat.quarantined).to be true
66
+ end
67
+ end
68
+
69
+ describe '#release!' do
70
+ it 'sets quarantined back to false' do
71
+ threat.quarantine!
72
+ threat.release!
73
+ expect(threat.quarantined).to be false
74
+ end
75
+ end
76
+
77
+ describe '#expose!' do
78
+ it 'increments exposure_count' do
79
+ threat.expose!
80
+ expect(threat.exposure_count).to eq(1)
81
+ end
82
+
83
+ it 'reduces threat_level (inoculation effect)' do
84
+ original = threat.threat_level
85
+ threat.expose!
86
+ expect(threat.threat_level).to be < original
87
+ end
88
+
89
+ it 'does not drop threat_level below 0.0' do
90
+ t = described_class.new(source: 's', tactic: :gaslighting, content_hash: 'x', threat_level: 0.0)
91
+ t.expose!
92
+ expect(t.threat_level).to eq(0.0)
93
+ end
94
+
95
+ it 'diminishing reduction on repeated exposure' do
96
+ first_level = threat.threat_level
97
+ threat.expose!
98
+ reduction1 = first_level - threat.threat_level
99
+
100
+ second_level = threat.threat_level
101
+ threat.expose!
102
+ reduction2 = second_level - threat.threat_level
103
+
104
+ expect(reduction2).to be <= reduction1
105
+ end
106
+ end
107
+
108
+ describe '#escalate!' do
109
+ it 'increases threat_level by default 0.1' do
110
+ original = threat.threat_level
111
+ threat.escalate!
112
+ expect(threat.threat_level).to be_within(0.001).of(original + 0.1)
113
+ end
114
+
115
+ it 'respects custom amount' do
116
+ threat.escalate!(amount: 0.2)
117
+ expect(threat.threat_level).to be_within(0.001).of(0.7)
118
+ end
119
+
120
+ it 'does not exceed 1.0' do
121
+ t = described_class.new(source: 's', tactic: :gaslighting, content_hash: 'x', threat_level: 0.95)
122
+ t.escalate!(amount: 0.5)
123
+ expect(t.threat_level).to eq(1.0)
124
+ end
125
+ end
126
+
127
+ describe '#to_h' do
128
+ it 'returns a hash with all fields' do
129
+ h = threat.to_h
130
+ expect(h).to include(:id, :source, :tactic, :content_hash, :threat_level, :threat_label, :quarantined, :exposure_count, :created_at)
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Defense::Immunology::Runners::CognitiveImmunology do
4
+ let(:client) { Legion::Extensions::Agentic::Defense::Immunology::Client.new }
5
+
6
+ describe '#detect_threat' do
7
+ it 'returns success true with threat data' do
8
+ result = client.detect_threat(source: 'test', tactic: :gaslighting, content_hash: 'h1')
9
+ expect(result[:success]).to be true
10
+ expect(result[:threat]).to include(:id, :tactic, :threat_level)
11
+ end
12
+
13
+ it 'uses custom threat_level' do
14
+ result = client.detect_threat(source: 'src', tactic: :strawman, content_hash: 'h2', threat_level: 0.9)
15
+ expect(result[:threat][:threat_level]).to be_within(0.01).of(0.9)
16
+ end
17
+ end
18
+
19
+ describe '#quarantine_threat' do
20
+ let(:threat_id) do
21
+ client.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1')[:threat][:id]
22
+ end
23
+
24
+ it 'quarantines an existing threat' do
25
+ result = client.quarantine_threat(threat_id: threat_id)
26
+ expect(result[:success]).to be true
27
+ end
28
+
29
+ it 'fails for unknown id' do
30
+ result = client.quarantine_threat(threat_id: 'unknown')
31
+ expect(result[:success]).to be false
32
+ end
33
+ end
34
+
35
+ describe '#release_threat' do
36
+ let(:threat_id) do
37
+ id = client.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1')[:threat][:id]
38
+ client.quarantine_threat(threat_id: id)
39
+ id
40
+ end
41
+
42
+ it 'releases a quarantined threat' do
43
+ result = client.release_threat(threat_id: threat_id)
44
+ expect(result[:success]).to be true
45
+ end
46
+ end
47
+
48
+ describe '#inoculate' do
49
+ let(:threat_id) do
50
+ client.detect_threat(source: 'src', tactic: :gaslighting, content_hash: 'h1')[:threat][:id]
51
+ end
52
+
53
+ it 'returns success and exposure_count' do
54
+ result = client.inoculate(threat_id: threat_id)
55
+ expect(result[:success]).to be true
56
+ expect(result[:exposure_count]).to eq(1)
57
+ end
58
+
59
+ it 'boosts resistance' do
60
+ before_status = client.immune_status
61
+ client.inoculate(threat_id: threat_id)
62
+ after_status = client.immune_status
63
+ expect(after_status[:resistance]).to be >= before_status[:resistance]
64
+ end
65
+
66
+ it 'fails for unknown threat' do
67
+ result = client.inoculate(threat_id: 'nope')
68
+ expect(result[:success]).to be false
69
+ end
70
+ end
71
+
72
+ describe '#create_antibody' do
73
+ it 'returns success with antibody data' do
74
+ result = client.create_antibody(tactic: :authority_appeal, pattern: 'expert claim')
75
+ expect(result[:success]).to be true
76
+ expect(result[:antibody]).to include(:id, :tactic, :strength)
77
+ end
78
+
79
+ it 'accepts custom strength' do
80
+ result = client.create_antibody(tactic: :gaslighting, pattern: 'test', strength: 0.7)
81
+ expect(result[:antibody][:strength]).to eq(0.7)
82
+ end
83
+ end
84
+
85
+ describe '#scan_for_tactic' do
86
+ before do
87
+ client.detect_threat(source: 's1', tactic: :strawman, content_hash: 'h1')
88
+ client.detect_threat(source: 's2', tactic: :strawman, content_hash: 'h2')
89
+ end
90
+
91
+ it 'returns threats for matching tactic' do
92
+ result = client.scan_for_tactic(tactic: :strawman)
93
+ expect(result[:success]).to be true
94
+ expect(result[:count]).to eq(2)
95
+ end
96
+
97
+ it 'returns empty for unmatched tactic' do
98
+ result = client.scan_for_tactic(tactic: :bandwagon)
99
+ expect(result[:count]).to eq(0)
100
+ end
101
+ end
102
+
103
+ describe '#trigger_inflammatory_response' do
104
+ it 'activates inflammatory mode' do
105
+ result = client.trigger_inflammatory_response
106
+ expect(result[:success]).to be true
107
+ expect(result[:inflammatory]).to be true
108
+ end
109
+ end
110
+
111
+ describe '#resolve_inflammation' do
112
+ before { client.trigger_inflammatory_response }
113
+
114
+ it 'deactivates inflammatory mode' do
115
+ result = client.resolve_inflammation
116
+ expect(result[:success]).to be true
117
+ expect(result[:inflammatory]).to be false
118
+ end
119
+ end
120
+
121
+ describe '#overall_immunity' do
122
+ it 'returns score and label' do
123
+ result = client.overall_immunity
124
+ expect(result[:success]).to be true
125
+ expect(result[:score]).to be_between(0.0, 1.0)
126
+ expect(result[:label]).to be_a(Symbol)
127
+ end
128
+ end
129
+
130
+ describe '#vulnerability_report' do
131
+ it 'returns coverage info' do
132
+ result = client.vulnerability_report
133
+ expect(result[:success]).to be true
134
+ expect(result).to include(:covered, :uncovered, :coverage)
135
+ end
136
+ end
137
+
138
+ describe '#threat_history' do
139
+ before { 3.times { |i| client.detect_threat(source: "s#{i}", tactic: :gaslighting, content_hash: "h#{i}") } }
140
+
141
+ it 'returns threats list' do
142
+ result = client.threat_history
143
+ expect(result[:success]).to be true
144
+ expect(result[:count]).to eq(3)
145
+ end
146
+
147
+ it 'respects limit' do
148
+ result = client.threat_history(limit: 2)
149
+ expect(result[:count]).to eq(2)
150
+ end
151
+ end
152
+
153
+ describe '#decay_all' do
154
+ it 'returns success with resistance' do
155
+ result = client.decay_all
156
+ expect(result[:success]).to be true
157
+ expect(result).to include(:resistance)
158
+ end
159
+ end
160
+
161
+ describe '#prune_ineffective' do
162
+ it 'returns pruned and remaining counts' do
163
+ client.create_antibody(tactic: :gaslighting, pattern: 'weak', strength: 0.1)
164
+ result = client.prune_ineffective
165
+ expect(result[:success]).to be true
166
+ expect(result[:pruned]).to eq(1)
167
+ end
168
+ end
169
+
170
+ describe '#immune_status' do
171
+ it 'returns full engine stats' do
172
+ result = client.immune_status
173
+ expect(result[:success]).to be true
174
+ expect(result).to include(:threat_count, :antibody_count, :resistance, :inflammatory)
175
+ end
176
+ end
177
+ end