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,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Defense
7
+ module Dissonance
8
+ module Runners
9
+ module Dissonance
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ def add_belief(domain:, content:, confidence: 0.7, importance: :moderate, **)
14
+ unless Helpers::Constants::IMPORTANCE_WEIGHTS.key?(importance)
15
+ return { success: false, error: :invalid_importance,
16
+ valid: Helpers::Constants::IMPORTANCE_WEIGHTS.keys }
17
+ end
18
+
19
+ result = dissonance_model.add_belief(domain: domain, content: content,
20
+ confidence: confidence, importance: importance)
21
+ belief = result[:belief]
22
+ new_evs = result[:new_dissonance_events]
23
+
24
+ Legion::Logging.debug "[dissonance] add_belief: id=#{belief.id[0..7]} domain=#{domain} importance=#{importance} new_events=#{new_evs.size}"
25
+
26
+ {
27
+ success: true,
28
+ belief_id: belief.id,
29
+ domain: domain,
30
+ new_dissonance_events: new_evs.map(&:to_h),
31
+ dissonance_triggered: new_evs.any? { |ev| ev.magnitude >= Helpers::Constants::DISSONANCE_THRESHOLD }
32
+ }
33
+ end
34
+
35
+ def update_dissonance(**)
36
+ dissonance_model.detect_contradictions
37
+ new_stress = dissonance_model.decay
38
+ unresolved = dissonance_model.unresolved_events
39
+
40
+ Legion::Logging.debug "[dissonance] update: stress=#{new_stress.round(3)} unresolved=#{unresolved.size}"
41
+
42
+ {
43
+ success: true,
44
+ stress: new_stress,
45
+ unresolved_count: unresolved.size,
46
+ above_threshold: unresolved.any? { |ev| ev.magnitude >= Helpers::Constants::DISSONANCE_THRESHOLD }
47
+ }
48
+ end
49
+
50
+ def resolve_dissonance(event_id:, strategy: :belief_revision, **)
51
+ unless Helpers::Constants::RESOLUTION_STRATEGIES.include?(strategy)
52
+ return { success: false, error: :invalid_strategy,
53
+ valid: Helpers::Constants::RESOLUTION_STRATEGIES }
54
+ end
55
+
56
+ event = dissonance_model.resolve(event_id, strategy: strategy)
57
+ if event
58
+ Legion::Logging.debug "[dissonance] resolved: id=#{event_id[0..7]} strategy=#{strategy}"
59
+ { success: true, resolved: true, strategy: strategy, event: event.to_h }
60
+ else
61
+ Legion::Logging.debug "[dissonance] resolve failed: id=#{event_id[0..7]} not_found_or_already_resolved"
62
+ { success: false, error: :not_found_or_already_resolved }
63
+ end
64
+ end
65
+
66
+ def dissonance_status(**)
67
+ model = dissonance_model
68
+ snapshot = model.to_h
69
+
70
+ Legion::Logging.debug "[dissonance] status: stress=#{snapshot[:stress].round(3)} " \
71
+ "beliefs=#{snapshot[:total_beliefs]} unresolved=#{snapshot[:unresolved_count]}"
72
+
73
+ {
74
+ success: true,
75
+ stress: snapshot[:stress],
76
+ total_beliefs: snapshot[:total_beliefs],
77
+ total_events: snapshot[:total_events],
78
+ unresolved_count: snapshot[:unresolved_count]
79
+ }
80
+ end
81
+
82
+ def domain_dissonance(domain:, **)
83
+ stress = dissonance_model.domain_stress(domain)
84
+ unresolved = dissonance_model.unresolved_events.select { |ev| ev.domain == domain }
85
+
86
+ Legion::Logging.debug "[dissonance] domain_dissonance: domain=#{domain} stress=#{stress.round(3)} unresolved=#{unresolved.size}"
87
+
88
+ {
89
+ success: true,
90
+ domain: domain,
91
+ stress: stress,
92
+ unresolved_count: unresolved.size,
93
+ events: unresolved.map(&:to_h)
94
+ }
95
+ end
96
+
97
+ def beliefs_for(domain:, **)
98
+ beliefs = dissonance_model.beliefs.values.select { |b| b.domain == domain }
99
+
100
+ Legion::Logging.debug "[dissonance] beliefs_for: domain=#{domain} count=#{beliefs.size}"
101
+
102
+ {
103
+ success: true,
104
+ domain: domain,
105
+ count: beliefs.size,
106
+ beliefs: beliefs.map(&:to_h)
107
+ }
108
+ end
109
+
110
+ def unresolved(**)
111
+ events = dissonance_model.unresolved_events
112
+
113
+ Legion::Logging.debug "[dissonance] unresolved: count=#{events.size}"
114
+
115
+ {
116
+ success: true,
117
+ count: events.size,
118
+ events: events.map(&:to_h)
119
+ }
120
+ end
121
+
122
+ def dissonance_stats(**)
123
+ model = dissonance_model
124
+ snapshot = model.to_h
125
+
126
+ domains = model.beliefs.values.map(&:domain).uniq
127
+ domain_stresses = domains.to_h { |d| [d, model.domain_stress(d)] }
128
+
129
+ unresolved = model.unresolved_events
130
+ resolved = model.events.values.select(&:resolved)
131
+
132
+ resolution_breakdown = Helpers::Constants::RESOLUTION_STRATEGIES.to_h do |s|
133
+ [s, resolved.count { |ev| ev.resolution_strategy == s }]
134
+ end
135
+
136
+ Legion::Logging.debug "[dissonance] stats: beliefs=#{snapshot[:total_beliefs]} " \
137
+ "events=#{snapshot[:total_events]} stress=#{snapshot[:stress].round(3)}"
138
+
139
+ {
140
+ success: true,
141
+ stress: snapshot[:stress],
142
+ total_beliefs: snapshot[:total_beliefs],
143
+ total_events: snapshot[:total_events],
144
+ unresolved_count: unresolved.size,
145
+ resolved_count: resolved.size,
146
+ domain_stresses: domain_stresses,
147
+ resolution_breakdown: resolution_breakdown,
148
+ above_threshold: unresolved.any? { |ev| ev.magnitude >= Helpers::Constants::DISSONANCE_THRESHOLD }
149
+ }
150
+ end
151
+
152
+ private
153
+
154
+ def dissonance_model
155
+ @dissonance_model ||= Helpers::DissonanceModel.new
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Defense
7
+ module Dissonance
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/defense/dissonance/version'
4
+ require 'legion/extensions/agentic/defense/dissonance/helpers/constants'
5
+ require 'legion/extensions/agentic/defense/dissonance/helpers/belief'
6
+ require 'legion/extensions/agentic/defense/dissonance/helpers/dissonance_event'
7
+ require 'legion/extensions/agentic/defense/dissonance/helpers/dissonance_model'
8
+ require 'legion/extensions/agentic/defense/dissonance/runners/dissonance'
9
+ require 'legion/extensions/agentic/defense/dissonance/client'
10
+
11
+ module Legion
12
+ module Extensions
13
+ module Agentic
14
+ module Defense
15
+ module Dissonance
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/every'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Defense
9
+ module EpistemicVigilance
10
+ module Actor
11
+ class Update < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Defense::EpistemicVigilance::Runners::EpistemicVigilance
14
+ end
15
+
16
+ def runner_function
17
+ 'update_epistemic_vigilance'
18
+ end
19
+
20
+ def time
21
+ 300
22
+ end
23
+
24
+ def run_now?
25
+ false
26
+ end
27
+
28
+ def use_runner?
29
+ false
30
+ end
31
+
32
+ def check_subtask?
33
+ false
34
+ end
35
+
36
+ def generate_task?
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/defense/epistemic_vigilance/helpers/constants'
4
+ require 'legion/extensions/agentic/defense/epistemic_vigilance/helpers/claim'
5
+ require 'legion/extensions/agentic/defense/epistemic_vigilance/helpers/source'
6
+ require 'legion/extensions/agentic/defense/epistemic_vigilance/helpers/vigilance_engine'
7
+ require 'legion/extensions/agentic/defense/epistemic_vigilance/runners/epistemic_vigilance'
8
+
9
+ module Legion
10
+ module Extensions
11
+ module Agentic
12
+ module Defense
13
+ module EpistemicVigilance
14
+ class Client
15
+ include Runners::EpistemicVigilance
16
+
17
+ private
18
+
19
+ def engine
20
+ @engine ||= Helpers::VigilanceEngine.new
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Defense
9
+ module EpistemicVigilance
10
+ module Helpers
11
+ class Claim
12
+ include Constants
13
+
14
+ attr_reader :id, :content, :source_id, :domain, :created_at,
15
+ :evidence_for, :evidence_against, :verdict
16
+ attr_accessor :confidence
17
+
18
+ def initialize(content:, source_id:, domain:, confidence: 0.5)
19
+ @id = SecureRandom.uuid
20
+ @content = content
21
+ @source_id = source_id
22
+ @domain = domain
23
+ @confidence = confidence.clamp(0.0, 1.0)
24
+ @verdict = :suspended
25
+ @evidence_for = 0
26
+ @evidence_against = 0
27
+ @created_at = Time.now.utc
28
+ end
29
+
30
+ def support!
31
+ @evidence_for += 1
32
+ @confidence = (@confidence + 0.05).clamp(0.0, 1.0)
33
+ end
34
+
35
+ def challenge!
36
+ @evidence_against += 1
37
+ @confidence = (@confidence - 0.08).clamp(0.0, 1.0)
38
+ end
39
+
40
+ def credibility_ratio
41
+ @evidence_for / (@evidence_for + @evidence_against + 1.0)
42
+ end
43
+
44
+ def contested?
45
+ @evidence_against.positive? && credibility_ratio < 0.6
46
+ end
47
+
48
+ def well_supported?
49
+ @evidence_for >= 3 && credibility_ratio > 0.7
50
+ end
51
+
52
+ def adjudicate!(verdict:)
53
+ @verdict = verdict
54
+ end
55
+
56
+ def to_h
57
+ {
58
+ id: @id,
59
+ content: @content,
60
+ source_id: @source_id,
61
+ domain: @domain,
62
+ confidence: @confidence,
63
+ verdict: @verdict,
64
+ evidence_for: @evidence_for,
65
+ evidence_against: @evidence_against,
66
+ credibility_ratio: credibility_ratio,
67
+ contested: contested?,
68
+ well_supported: well_supported?,
69
+ created_at: @created_at
70
+ }
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Defense
7
+ module EpistemicVigilance
8
+ module Helpers
9
+ class Client
10
+ include Runners::EpistemicVigilance
11
+
12
+ private
13
+
14
+ def engine
15
+ @engine ||= VigilanceEngine.new
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Defense
7
+ module EpistemicVigilance
8
+ module Helpers
9
+ module Constants
10
+ VIGILANCE_LEVELS = %i[trusting cautious skeptical hostile].freeze
11
+ VIGILANCE_THRESHOLDS = { trusting: 0.8, cautious: 0.6, skeptical: 0.3, hostile: 0.0 }.freeze
12
+ CLAIM_VERDICTS = %i[accepted provisionally_accepted suspended rejected].freeze
13
+ SOURCE_RELIABILITY_LABELS = {
14
+ (0.8..) => :highly_reliable,
15
+ (0.6...0.8) => :reliable,
16
+ (0.4...0.6) => :uncertain,
17
+ (0.2...0.4) => :unreliable,
18
+ (..0.2) => :deceptive
19
+ }.freeze
20
+
21
+ MAX_CLAIMS = 200
22
+ MAX_SOURCES = 100
23
+ MAX_HISTORY = 500
24
+ DEFAULT_SOURCE_RELIABILITY = 0.5
25
+ RELIABILITY_BOOST = 0.05
26
+ RELIABILITY_PENALTY = 0.1
27
+ CONSISTENCY_WEIGHT = 0.3
28
+ SOURCE_WEIGHT = 0.4
29
+ COHERENCE_WEIGHT = 0.3
30
+ DECAY_RATE = 0.01
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Defense
9
+ module EpistemicVigilance
10
+ module Helpers
11
+ class Source
12
+ include Constants
13
+
14
+ attr_reader :id, :name, :domain, :claims_made, :claims_verified, :claims_refuted
15
+ attr_accessor :reliability
16
+
17
+ def initialize(name:, domain:)
18
+ @id = SecureRandom.uuid
19
+ @name = name
20
+ @domain = domain
21
+ @reliability = DEFAULT_SOURCE_RELIABILITY
22
+ @claims_made = 0
23
+ @claims_verified = 0
24
+ @claims_refuted = 0
25
+ end
26
+
27
+ def record_verified!
28
+ @claims_verified += 1
29
+ @reliability = (@reliability + RELIABILITY_BOOST).clamp(0.0, 1.0)
30
+ end
31
+
32
+ def record_refuted!
33
+ @claims_refuted += 1
34
+ @reliability = (@reliability - RELIABILITY_PENALTY).clamp(0.0, 1.0)
35
+ end
36
+
37
+ def reliability_label
38
+ SOURCE_RELIABILITY_LABELS.find { |range, _label| range.include?(@reliability) }&.last || :uncertain
39
+ end
40
+
41
+ def track_record
42
+ @claims_verified / (@claims_verified + @claims_refuted + 1.0)
43
+ end
44
+
45
+ def to_h
46
+ {
47
+ id: @id,
48
+ name: @name,
49
+ domain: @domain,
50
+ reliability: @reliability,
51
+ reliability_label: reliability_label,
52
+ claims_made: @claims_made,
53
+ claims_verified: @claims_verified,
54
+ claims_refuted: @claims_refuted,
55
+ track_record: track_record
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,195 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Defense
7
+ module EpistemicVigilance
8
+ module Helpers
9
+ class VigilanceEngine
10
+ include Constants
11
+
12
+ def initialize
13
+ @sources = {}
14
+ @claims = {}
15
+ end
16
+
17
+ def register_source(name:, domain:)
18
+ source = Source.new(name: name, domain: domain)
19
+ @sources[source.id] = source
20
+ source.to_h
21
+ end
22
+
23
+ def submit_claim(content:, source_id:, domain:, initial_confidence: 0.5)
24
+ source = @sources[source_id]
25
+ return { error: :source_not_found } unless source
26
+
27
+ claim = Claim.new(content: content, source_id: source_id, domain: domain,
28
+ confidence: initial_confidence)
29
+ source.instance_variable_set(:@claims_made, source.claims_made + 1)
30
+ @claims[claim.id] = claim
31
+ assessment = assess_claim(claim_id: claim.id)
32
+ { claim: claim.to_h, assessment: assessment }
33
+ end
34
+
35
+ def assess_claim(claim_id:)
36
+ claim = @claims[claim_id]
37
+ return { error: :claim_not_found } unless claim
38
+
39
+ source = @sources[claim.source_id]
40
+ source_score = build_source_score(source)
41
+ consist_score = claim.credibility_ratio * CONSISTENCY_WEIGHT
42
+ coher_score = domain_coherence_score(claim.domain, exclude_id: claim_id)
43
+ total = source_score + consist_score + coher_score
44
+ verdict = recommended_verdict(total)
45
+
46
+ {
47
+ claim_id: claim_id,
48
+ source_score: source_score,
49
+ consistency_score: consist_score,
50
+ coherence_score: coher_score,
51
+ total_score: total,
52
+ recommended_verdict: verdict
53
+ }
54
+ end
55
+
56
+ def support_claim(claim_id:)
57
+ claim = @claims[claim_id]
58
+ source = claim && @sources[claim.source_id]
59
+ return { error: :claim_not_found } unless claim
60
+
61
+ claim.support!
62
+ source&.record_verified!
63
+ { claim_id: claim_id, confidence: claim.confidence, evidence_for: claim.evidence_for }
64
+ end
65
+
66
+ def challenge_claim(claim_id:)
67
+ claim = @claims[claim_id]
68
+ source = claim && @sources[claim.source_id]
69
+ return { error: :claim_not_found } unless claim
70
+
71
+ claim.challenge!
72
+ source&.record_refuted!
73
+ { claim_id: claim_id, confidence: claim.confidence, evidence_against: claim.evidence_against }
74
+ end
75
+
76
+ def adjudicate_claim(claim_id:, verdict:)
77
+ claim = @claims[claim_id]
78
+ source = claim && @sources[claim.source_id]
79
+ return { error: :claim_not_found } unless claim
80
+
81
+ claim.adjudicate!(verdict: verdict)
82
+ update_source_on_adjudication(source, verdict)
83
+ { claim_id: claim_id, verdict: verdict }
84
+ end
85
+
86
+ def source_reliability(source_id:)
87
+ source = @sources[source_id]
88
+ return { error: :source_not_found } unless source
89
+
90
+ { source_id: source_id, reliability: source.reliability, label: source.reliability_label }
91
+ end
92
+
93
+ def contested_claims
94
+ @claims.values.select(&:contested?).map(&:to_h)
95
+ end
96
+
97
+ def claims_by_source(source_id:)
98
+ @claims.values.select { |c| c.source_id == source_id }.map(&:to_h)
99
+ end
100
+
101
+ def claims_by_domain(domain:)
102
+ @claims.values.select { |c| c.domain == domain }.map(&:to_h)
103
+ end
104
+
105
+ def domain_vigilance_level(domain:)
106
+ domain_claims = @claims.values.select { |c| c.domain == domain }
107
+ return :skeptical if domain_claims.empty?
108
+
109
+ avg = domain_claims.sum(&:confidence) / domain_claims.size.to_f
110
+ level_for_score(avg)
111
+ end
112
+
113
+ def decay_all
114
+ @claims.each_value do |claim|
115
+ claim.confidence = (claim.confidence - DECAY_RATE).clamp(0.0, 1.0)
116
+ end
117
+ { decayed: @claims.size }
118
+ end
119
+
120
+ def prune_rejected
121
+ before = @claims.size
122
+ @claims.reject! { |_, c| c.verdict == :rejected && c.confidence < 0.1 }
123
+ { pruned: before - @claims.size, remaining: @claims.size }
124
+ end
125
+
126
+ def to_h
127
+ {
128
+ sources_count: @sources.size,
129
+ claims_count: @claims.size,
130
+ contested: contested_claims.size,
131
+ by_verdict: verdict_counts
132
+ }
133
+ end
134
+
135
+ private
136
+
137
+ def build_source_score(source)
138
+ return DEFAULT_SOURCE_RELIABILITY * SOURCE_WEIGHT unless source
139
+
140
+ source.reliability * SOURCE_WEIGHT
141
+ end
142
+
143
+ def domain_coherence_score(domain, exclude_id:)
144
+ peers = @claims.values.reject { |c| c.id == exclude_id }.select { |c| c.domain == domain }
145
+ return 0.0 if peers.empty?
146
+
147
+ avg = peers.sum(&:confidence) / peers.size.to_f
148
+ avg * COHERENCE_WEIGHT
149
+ end
150
+
151
+ def recommended_verdict(total_score)
152
+ if total_score >= VIGILANCE_THRESHOLDS[:trusting]
153
+ :accepted
154
+ elsif total_score >= VIGILANCE_THRESHOLDS[:cautious]
155
+ :provisionally_accepted
156
+ elsif total_score >= VIGILANCE_THRESHOLDS[:skeptical]
157
+ :suspended
158
+ else
159
+ :rejected
160
+ end
161
+ end
162
+
163
+ def level_for_score(score)
164
+ if score >= VIGILANCE_THRESHOLDS[:trusting]
165
+ :trusting
166
+ elsif score >= VIGILANCE_THRESHOLDS[:cautious]
167
+ :cautious
168
+ elsif score >= VIGILANCE_THRESHOLDS[:skeptical]
169
+ :skeptical
170
+ else
171
+ :hostile
172
+ end
173
+ end
174
+
175
+ def update_source_on_adjudication(source, verdict)
176
+ return unless source
177
+
178
+ case verdict
179
+ when :accepted then source.record_verified!
180
+ when :rejected then source.record_refuted!
181
+ end
182
+ end
183
+
184
+ def verdict_counts
185
+ CLAIM_VERDICTS.to_h do |v|
186
+ [v, @claims.values.count { |c| c.verdict == v }]
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+ end