lex-agentic-social 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 (235) 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-social.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/social/apprenticeship/client.rb +28 -0
  8. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship.rb +90 -0
  9. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_engine.rb +109 -0
  10. data/lib/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_model.rb +93 -0
  11. data/lib/legion/extensions/agentic/social/apprenticeship/runners/cognitive_apprenticeship.rb +112 -0
  12. data/lib/legion/extensions/agentic/social/apprenticeship/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/social/apprenticeship.rb +19 -0
  14. data/lib/legion/extensions/agentic/social/conflict/actors/stale_check.rb +45 -0
  15. data/lib/legion/extensions/agentic/social/conflict/client.rb +27 -0
  16. data/lib/legion/extensions/agentic/social/conflict/helpers/conflict_log.rb +70 -0
  17. data/lib/legion/extensions/agentic/social/conflict/helpers/llm_enhancer.rb +130 -0
  18. data/lib/legion/extensions/agentic/social/conflict/helpers/severity.rb +47 -0
  19. data/lib/legion/extensions/agentic/social/conflict/runners/conflict.rb +112 -0
  20. data/lib/legion/extensions/agentic/social/conflict/version.rb +13 -0
  21. data/lib/legion/extensions/agentic/social/conflict.rb +19 -0
  22. data/lib/legion/extensions/agentic/social/conscience/client.rb +26 -0
  23. data/lib/legion/extensions/agentic/social/conscience/helpers/constants.rb +53 -0
  24. data/lib/legion/extensions/agentic/social/conscience/helpers/moral_evaluator.rb +178 -0
  25. data/lib/legion/extensions/agentic/social/conscience/helpers/moral_store.rb +116 -0
  26. data/lib/legion/extensions/agentic/social/conscience/runners/conscience.rb +117 -0
  27. data/lib/legion/extensions/agentic/social/conscience/version.rb +13 -0
  28. data/lib/legion/extensions/agentic/social/conscience.rb +19 -0
  29. data/lib/legion/extensions/agentic/social/consent/actors/tier_evaluation.rb +45 -0
  30. data/lib/legion/extensions/agentic/social/consent/client.rb +27 -0
  31. data/lib/legion/extensions/agentic/social/consent/helpers/consent_map.rb +199 -0
  32. data/lib/legion/extensions/agentic/social/consent/helpers/tiers.rb +54 -0
  33. data/lib/legion/extensions/agentic/social/consent/local_migrations/20260316000010_create_consent_domains.rb +16 -0
  34. data/lib/legion/extensions/agentic/social/consent/runners/consent.rb +228 -0
  35. data/lib/legion/extensions/agentic/social/consent/version.rb +13 -0
  36. data/lib/legion/extensions/agentic/social/consent.rb +25 -0
  37. data/lib/legion/extensions/agentic/social/entrainment/client.rb +19 -0
  38. data/lib/legion/extensions/agentic/social/entrainment/helpers/constants.rb +40 -0
  39. data/lib/legion/extensions/agentic/social/entrainment/helpers/entrainment_engine.rb +120 -0
  40. data/lib/legion/extensions/agentic/social/entrainment/helpers/pairing.rb +86 -0
  41. data/lib/legion/extensions/agentic/social/entrainment/runners/cognitive_entrainment.rb +89 -0
  42. data/lib/legion/extensions/agentic/social/entrainment/version.rb +13 -0
  43. data/lib/legion/extensions/agentic/social/entrainment.rb +19 -0
  44. data/lib/legion/extensions/agentic/social/governance/actors/shadow_ai_scan.rb +19 -0
  45. data/lib/legion/extensions/agentic/social/governance/actors/vote_timeout.rb +45 -0
  46. data/lib/legion/extensions/agentic/social/governance/client.rb +27 -0
  47. data/lib/legion/extensions/agentic/social/governance/helpers/layers.rb +40 -0
  48. data/lib/legion/extensions/agentic/social/governance/helpers/proposal.rb +94 -0
  49. data/lib/legion/extensions/agentic/social/governance/runners/governance.rb +87 -0
  50. data/lib/legion/extensions/agentic/social/governance/runners/shadow_ai.rb +93 -0
  51. data/lib/legion/extensions/agentic/social/governance/version.rb +13 -0
  52. data/lib/legion/extensions/agentic/social/governance.rb +20 -0
  53. data/lib/legion/extensions/agentic/social/joint_attention/actors/decay.rb +45 -0
  54. data/lib/legion/extensions/agentic/social/joint_attention/client.rb +28 -0
  55. data/lib/legion/extensions/agentic/social/joint_attention/helpers/attention_target.rb +124 -0
  56. data/lib/legion/extensions/agentic/social/joint_attention/helpers/constants.rb +34 -0
  57. data/lib/legion/extensions/agentic/social/joint_attention/helpers/joint_focus_manager.rb +157 -0
  58. data/lib/legion/extensions/agentic/social/joint_attention/runners/joint_attention.rb +88 -0
  59. data/lib/legion/extensions/agentic/social/joint_attention/version.rb +13 -0
  60. data/lib/legion/extensions/agentic/social/joint_attention.rb +20 -0
  61. data/lib/legion/extensions/agentic/social/mentalizing/actors/decay.rb +45 -0
  62. data/lib/legion/extensions/agentic/social/mentalizing/client.rb +28 -0
  63. data/lib/legion/extensions/agentic/social/mentalizing/helpers/belief_attribution.rb +58 -0
  64. data/lib/legion/extensions/agentic/social/mentalizing/helpers/constants.rb +33 -0
  65. data/lib/legion/extensions/agentic/social/mentalizing/helpers/mental_model.rb +137 -0
  66. data/lib/legion/extensions/agentic/social/mentalizing/runners/mentalizing.rb +93 -0
  67. data/lib/legion/extensions/agentic/social/mentalizing/version.rb +13 -0
  68. data/lib/legion/extensions/agentic/social/mentalizing.rb +20 -0
  69. data/lib/legion/extensions/agentic/social/mirror/client.rb +33 -0
  70. data/lib/legion/extensions/agentic/social/mirror/helpers/constants.rb +65 -0
  71. data/lib/legion/extensions/agentic/social/mirror/helpers/mirror_engine.rb +132 -0
  72. data/lib/legion/extensions/agentic/social/mirror/helpers/mirror_event.rb +46 -0
  73. data/lib/legion/extensions/agentic/social/mirror/helpers/simulation.rb +43 -0
  74. data/lib/legion/extensions/agentic/social/mirror/runners/observe.rb +52 -0
  75. data/lib/legion/extensions/agentic/social/mirror/runners/resonance.rb +79 -0
  76. data/lib/legion/extensions/agentic/social/mirror/runners/simulate.rb +63 -0
  77. data/lib/legion/extensions/agentic/social/mirror/version.rb +13 -0
  78. data/lib/legion/extensions/agentic/social/mirror.rb +22 -0
  79. data/lib/legion/extensions/agentic/social/mirror_system/actors/decay.rb +45 -0
  80. data/lib/legion/extensions/agentic/social/mirror_system/client.rb +28 -0
  81. data/lib/legion/extensions/agentic/social/mirror_system/helpers/constants.rb +62 -0
  82. data/lib/legion/extensions/agentic/social/mirror_system/helpers/mirror_system.rb +162 -0
  83. data/lib/legion/extensions/agentic/social/mirror_system/helpers/observed_behavior.rb +67 -0
  84. data/lib/legion/extensions/agentic/social/mirror_system/runners/mirror.rb +99 -0
  85. data/lib/legion/extensions/agentic/social/mirror_system/version.rb +13 -0
  86. data/lib/legion/extensions/agentic/social/mirror_system.rb +20 -0
  87. data/lib/legion/extensions/agentic/social/moral_reasoning/client.rb +19 -0
  88. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/constants.rb +49 -0
  89. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/dilemma.rb +68 -0
  90. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/llm_enhancer.rb +140 -0
  91. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine.rb +239 -0
  92. data/lib/legion/extensions/agentic/social/moral_reasoning/helpers/moral_foundation.rb +45 -0
  93. data/lib/legion/extensions/agentic/social/moral_reasoning/runners/moral_reasoning.rb +121 -0
  94. data/lib/legion/extensions/agentic/social/moral_reasoning/version.rb +13 -0
  95. data/lib/legion/extensions/agentic/social/moral_reasoning.rb +21 -0
  96. data/lib/legion/extensions/agentic/social/perspective_shifting/client.rb +29 -0
  97. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/constants.rb +67 -0
  98. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/perspective.rb +45 -0
  99. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_view.rb +57 -0
  100. data/lib/legion/extensions/agentic/social/perspective_shifting/helpers/shifting_engine.rb +166 -0
  101. data/lib/legion/extensions/agentic/social/perspective_shifting/runners/perspective_shifting.rb +167 -0
  102. data/lib/legion/extensions/agentic/social/perspective_shifting/version.rb +13 -0
  103. data/lib/legion/extensions/agentic/social/perspective_shifting.rb +20 -0
  104. data/lib/legion/extensions/agentic/social/social/client.rb +25 -0
  105. data/lib/legion/extensions/agentic/social/social/helpers/constants.rb +84 -0
  106. data/lib/legion/extensions/agentic/social/social/helpers/social_graph.rb +172 -0
  107. data/lib/legion/extensions/agentic/social/social/runners/social.rb +146 -0
  108. data/lib/legion/extensions/agentic/social/social/version.rb +13 -0
  109. data/lib/legion/extensions/agentic/social/social.rb +18 -0
  110. data/lib/legion/extensions/agentic/social/social_learning/client.rb +25 -0
  111. data/lib/legion/extensions/agentic/social/social_learning/helpers/constants.rb +42 -0
  112. data/lib/legion/extensions/agentic/social/social_learning/helpers/model_agent.rb +82 -0
  113. data/lib/legion/extensions/agentic/social/social_learning/helpers/observed_behavior.rb +61 -0
  114. data/lib/legion/extensions/agentic/social/social_learning/helpers/social_learning_engine.rb +134 -0
  115. data/lib/legion/extensions/agentic/social/social_learning/runners/social_learning.rb +105 -0
  116. data/lib/legion/extensions/agentic/social/social_learning/version.rb +13 -0
  117. data/lib/legion/extensions/agentic/social/social_learning.rb +20 -0
  118. data/lib/legion/extensions/agentic/social/symbiosis/client.rb +23 -0
  119. data/lib/legion/extensions/agentic/social/symbiosis/helpers/constants.rb +50 -0
  120. data/lib/legion/extensions/agentic/social/symbiosis/helpers/ecosystem.rb +113 -0
  121. data/lib/legion/extensions/agentic/social/symbiosis/helpers/symbiosis_engine.rb +104 -0
  122. data/lib/legion/extensions/agentic/social/symbiosis/helpers/symbiotic_bond.rb +112 -0
  123. data/lib/legion/extensions/agentic/social/symbiosis/runners/cognitive_symbiosis.rb +101 -0
  124. data/lib/legion/extensions/agentic/social/symbiosis/version.rb +13 -0
  125. data/lib/legion/extensions/agentic/social/symbiosis.rb +22 -0
  126. data/lib/legion/extensions/agentic/social/theory_of_mind/client.rb +26 -0
  127. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/agent_model.rb +173 -0
  128. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/constants.rb +70 -0
  129. data/lib/legion/extensions/agentic/social/theory_of_mind/helpers/mental_state_tracker.rb +169 -0
  130. data/lib/legion/extensions/agentic/social/theory_of_mind/runners/theory_of_mind.rb +159 -0
  131. data/lib/legion/extensions/agentic/social/theory_of_mind/version.rb +13 -0
  132. data/lib/legion/extensions/agentic/social/theory_of_mind.rb +19 -0
  133. data/lib/legion/extensions/agentic/social/trust/actors/decay.rb +45 -0
  134. data/lib/legion/extensions/agentic/social/trust/client.rb +27 -0
  135. data/lib/legion/extensions/agentic/social/trust/helpers/trust_map.rb +160 -0
  136. data/lib/legion/extensions/agentic/social/trust/helpers/trust_model.rb +52 -0
  137. data/lib/legion/extensions/agentic/social/trust/local_migrations/20260316000020_create_trust_entries.rb +23 -0
  138. data/lib/legion/extensions/agentic/social/trust/runners/trust.rb +80 -0
  139. data/lib/legion/extensions/agentic/social/trust/version.rb +13 -0
  140. data/lib/legion/extensions/agentic/social/trust.rb +25 -0
  141. data/lib/legion/extensions/agentic/social/version.rb +11 -0
  142. data/lib/legion/extensions/agentic/social.rb +34 -0
  143. data/spec/legion/extensions/agentic/social/apprenticeship/client_spec.rb +20 -0
  144. data/spec/legion/extensions/agentic/social/apprenticeship/cognitive_apprenticeship_spec.rb +11 -0
  145. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_engine_spec.rb +146 -0
  146. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_model_spec.rb +124 -0
  147. data/spec/legion/extensions/agentic/social/apprenticeship/helpers/apprenticeship_spec.rb +136 -0
  148. data/spec/legion/extensions/agentic/social/apprenticeship/runners/cognitive_apprenticeship_spec.rb +154 -0
  149. data/spec/legion/extensions/agentic/social/conflict/actors/stale_check_spec.rb +45 -0
  150. data/spec/legion/extensions/agentic/social/conflict/client_spec.rb +15 -0
  151. data/spec/legion/extensions/agentic/social/conflict/helpers/conflict_log_spec.rb +232 -0
  152. data/spec/legion/extensions/agentic/social/conflict/helpers/llm_enhancer_spec.rb +189 -0
  153. data/spec/legion/extensions/agentic/social/conflict/helpers/severity_spec.rb +215 -0
  154. data/spec/legion/extensions/agentic/social/conflict/runners/conflict_spec.rb +151 -0
  155. data/spec/legion/extensions/agentic/social/conscience/client_spec.rb +58 -0
  156. data/spec/legion/extensions/agentic/social/conscience/helpers/constants_spec.rb +124 -0
  157. data/spec/legion/extensions/agentic/social/conscience/helpers/moral_evaluator_spec.rb +253 -0
  158. data/spec/legion/extensions/agentic/social/conscience/helpers/moral_store_spec.rb +230 -0
  159. data/spec/legion/extensions/agentic/social/conscience/runners/conscience_spec.rb +239 -0
  160. data/spec/legion/extensions/agentic/social/consent/actors/tier_evaluation_spec.rb +46 -0
  161. data/spec/legion/extensions/agentic/social/consent/client_spec.rb +33 -0
  162. data/spec/legion/extensions/agentic/social/consent/helpers/tiers_spec.rb +49 -0
  163. data/spec/legion/extensions/agentic/social/consent/local_persistence_spec.rb +234 -0
  164. data/spec/legion/extensions/agentic/social/consent/runners/consent_spec.rb +224 -0
  165. data/spec/legion/extensions/agentic/social/entrainment/client_spec.rb +21 -0
  166. data/spec/legion/extensions/agentic/social/entrainment/helpers/entrainment_engine_spec.rb +116 -0
  167. data/spec/legion/extensions/agentic/social/entrainment/helpers/pairing_spec.rb +103 -0
  168. data/spec/legion/extensions/agentic/social/entrainment/runners/cognitive_entrainment_spec.rb +87 -0
  169. data/spec/legion/extensions/agentic/social/governance/actors/vote_timeout_spec.rb +45 -0
  170. data/spec/legion/extensions/agentic/social/governance/client_spec.rb +14 -0
  171. data/spec/legion/extensions/agentic/social/governance/helpers/layers_spec.rb +190 -0
  172. data/spec/legion/extensions/agentic/social/governance/helpers/proposal_spec.rb +188 -0
  173. data/spec/legion/extensions/agentic/social/governance/runners/governance_spec.rb +101 -0
  174. data/spec/legion/extensions/agentic/social/governance/runners/shadow_ai_spec.rb +65 -0
  175. data/spec/legion/extensions/agentic/social/joint_attention/client_spec.rb +36 -0
  176. data/spec/legion/extensions/agentic/social/joint_attention/helpers/attention_target_spec.rb +258 -0
  177. data/spec/legion/extensions/agentic/social/joint_attention/helpers/joint_focus_manager_spec.rb +238 -0
  178. data/spec/legion/extensions/agentic/social/joint_attention/runners/joint_attention_spec.rb +228 -0
  179. data/spec/legion/extensions/agentic/social/mentalizing/client_spec.rb +19 -0
  180. data/spec/legion/extensions/agentic/social/mentalizing/helpers/belief_attribution_spec.rb +108 -0
  181. data/spec/legion/extensions/agentic/social/mentalizing/helpers/mental_model_spec.rb +179 -0
  182. data/spec/legion/extensions/agentic/social/mentalizing/runners/mentalizing_spec.rb +162 -0
  183. data/spec/legion/extensions/agentic/social/mirror/client_spec.rb +92 -0
  184. data/spec/legion/extensions/agentic/social/mirror/helpers/constants_spec.rb +123 -0
  185. data/spec/legion/extensions/agentic/social/mirror/helpers/mirror_engine_spec.rb +217 -0
  186. data/spec/legion/extensions/agentic/social/mirror/helpers/mirror_event_spec.rb +102 -0
  187. data/spec/legion/extensions/agentic/social/mirror/helpers/simulation_spec.rb +100 -0
  188. data/spec/legion/extensions/agentic/social/mirror/runners/observe_spec.rb +77 -0
  189. data/spec/legion/extensions/agentic/social/mirror/runners/resonance_spec.rb +123 -0
  190. data/spec/legion/extensions/agentic/social/mirror/runners/simulate_spec.rb +103 -0
  191. data/spec/legion/extensions/agentic/social/mirror_system/client_spec.rb +40 -0
  192. data/spec/legion/extensions/agentic/social/mirror_system/helpers/mirror_system_spec.rb +144 -0
  193. data/spec/legion/extensions/agentic/social/mirror_system/helpers/observed_behavior_spec.rb +98 -0
  194. data/spec/legion/extensions/agentic/social/mirror_system/runners/mirror_spec.rb +122 -0
  195. data/spec/legion/extensions/agentic/social/moral_reasoning/client_spec.rb +34 -0
  196. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/dilemma_spec.rb +108 -0
  197. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/llm_enhancer_spec.rb +232 -0
  198. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/moral_engine_spec.rb +266 -0
  199. data/spec/legion/extensions/agentic/social/moral_reasoning/helpers/moral_foundation_spec.rb +70 -0
  200. data/spec/legion/extensions/agentic/social/moral_reasoning/runners/moral_reasoning_spec.rb +275 -0
  201. data/spec/legion/extensions/agentic/social/perspective_shifting/client_spec.rb +30 -0
  202. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/constants_spec.rb +99 -0
  203. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_spec.rb +77 -0
  204. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/perspective_view_spec.rb +105 -0
  205. data/spec/legion/extensions/agentic/social/perspective_shifting/helpers/shifting_engine_spec.rb +246 -0
  206. data/spec/legion/extensions/agentic/social/perspective_shifting/runners/perspective_shifting_spec.rb +277 -0
  207. data/spec/legion/extensions/agentic/social/social/client_spec.rb +72 -0
  208. data/spec/legion/extensions/agentic/social/social/helpers/constants_spec.rb +99 -0
  209. data/spec/legion/extensions/agentic/social/social/helpers/social_graph_spec.rb +322 -0
  210. data/spec/legion/extensions/agentic/social/social/runners/social_spec.rb +220 -0
  211. data/spec/legion/extensions/agentic/social/social_learning/client_spec.rb +25 -0
  212. data/spec/legion/extensions/agentic/social/social_learning/helpers/constants_spec.rb +44 -0
  213. data/spec/legion/extensions/agentic/social/social_learning/helpers/model_agent_spec.rb +120 -0
  214. data/spec/legion/extensions/agentic/social/social_learning/helpers/observed_behavior_spec.rb +81 -0
  215. data/spec/legion/extensions/agentic/social/social_learning/helpers/social_learning_engine_spec.rb +196 -0
  216. data/spec/legion/extensions/agentic/social/social_learning/runners/social_learning_spec.rb +150 -0
  217. data/spec/legion/extensions/agentic/social/symbiosis/client_spec.rb +45 -0
  218. data/spec/legion/extensions/agentic/social/symbiosis/helpers/constants_spec.rb +73 -0
  219. data/spec/legion/extensions/agentic/social/symbiosis/helpers/ecosystem_spec.rb +185 -0
  220. data/spec/legion/extensions/agentic/social/symbiosis/helpers/symbiosis_engine_spec.rb +182 -0
  221. data/spec/legion/extensions/agentic/social/symbiosis/helpers/symbiotic_bond_spec.rb +209 -0
  222. data/spec/legion/extensions/agentic/social/symbiosis/runners/cognitive_symbiosis_spec.rb +182 -0
  223. data/spec/legion/extensions/agentic/social/theory_of_mind/client_spec.rb +63 -0
  224. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/agent_model_spec.rb +244 -0
  225. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/constants_spec.rb +71 -0
  226. data/spec/legion/extensions/agentic/social/theory_of_mind/helpers/mental_state_tracker_spec.rb +228 -0
  227. data/spec/legion/extensions/agentic/social/theory_of_mind/runners/theory_of_mind_spec.rb +221 -0
  228. data/spec/legion/extensions/agentic/social/trust/actors/decay_spec.rb +62 -0
  229. data/spec/legion/extensions/agentic/social/trust/client_spec.rb +17 -0
  230. data/spec/legion/extensions/agentic/social/trust/helpers/trust_map_spec.rb +299 -0
  231. data/spec/legion/extensions/agentic/social/trust/helpers/trust_model_spec.rb +179 -0
  232. data/spec/legion/extensions/agentic/social/trust/local_persistence_spec.rb +359 -0
  233. data/spec/legion/extensions/agentic/social/trust/runners/trust_spec.rb +84 -0
  234. data/spec/spec_helper.rb +54 -0
  235. metadata +319 -0
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Symbiosis::Helpers::Ecosystem do
4
+ subject(:ecosystem) { described_class.new }
5
+
6
+ let(:bond_class) { Legion::Extensions::Agentic::Social::Symbiosis::Helpers::SymbioticBond }
7
+ let(:constants) { Legion::Extensions::Agentic::Social::Symbiosis::Helpers::Constants }
8
+
9
+ def make_bond(sys_a, sys_b, rel_type, strength: 0.5)
10
+ bond_class.new(subsystem_a: sys_a, subsystem_b: sys_b, relationship_type: rel_type, strength: strength)
11
+ end
12
+
13
+ describe '#register_bond' do
14
+ it 'registers a bond and returns it' do
15
+ bond = make_bond('memory', 'emotion', :mutualistic)
16
+ result = ecosystem.register_bond(bond)
17
+ expect(result).to be(bond)
18
+ end
19
+
20
+ it 'increments bond_count' do
21
+ ecosystem.register_bond(make_bond('a', 'b', :mutualistic))
22
+ expect(ecosystem.bond_count).to eq(1)
23
+ end
24
+
25
+ it 'raises ArgumentError for non-bond object' do
26
+ expect { ecosystem.register_bond('not_a_bond') }.to raise_error(ArgumentError, /must be a SymbioticBond/)
27
+ end
28
+
29
+ it 'raises ArgumentError when MAX_BONDS exceeded' do
30
+ constants::MAX_BONDS.times do |i|
31
+ b = bond_class.new(subsystem_a: "sys#{i}a", subsystem_b: "sys#{i}b", relationship_type: :commensal)
32
+ ecosystem.register_bond(b)
33
+ end
34
+ extra = make_bond('overflow_a', 'overflow_b', :mutualistic)
35
+ expect { ecosystem.register_bond(extra) }.to raise_error(ArgumentError, /MAX_BONDS/)
36
+ end
37
+ end
38
+
39
+ describe '#activate_bond' do
40
+ let(:bond) { make_bond('memory', 'emotion', :mutualistic) }
41
+
42
+ before { ecosystem.register_bond(bond) }
43
+
44
+ it 'returns found: true for existing bond' do
45
+ result = ecosystem.activate_bond(bond.bond_id)
46
+ expect(result[:found]).to be true
47
+ end
48
+
49
+ it 'increases strength on activation' do
50
+ before = bond.strength
51
+ ecosystem.activate_bond(bond.bond_id, amount: 0.1)
52
+ expect(bond.strength).to be > before
53
+ end
54
+
55
+ it 'returns found: false for unknown bond_id' do
56
+ result = ecosystem.activate_bond('nonexistent')
57
+ expect(result[:found]).to be false
58
+ end
59
+ end
60
+
61
+ describe '#measure_health' do
62
+ it 'returns 0.0 for empty ecosystem' do
63
+ expect(ecosystem.measure_health).to eq(0.0)
64
+ end
65
+
66
+ it 'returns higher score for more mutualistic bonds' do
67
+ 3.times { |i| ecosystem.register_bond(make_bond("m#{i}a", "m#{i}b", :mutualistic)) }
68
+ expect(ecosystem.measure_health).to be > 0.5
69
+ end
70
+
71
+ it 'returns lower score when parasitic bonds present' do
72
+ ecosystem.register_bond(make_bond('a', 'b', :mutualistic))
73
+ ecosystem.register_bond(make_bond('c', 'd', :parasitic))
74
+ expect(ecosystem.measure_health).to be < 1.0
75
+ end
76
+
77
+ it 'returns 0.0 when only dormant bonds exist' do
78
+ dormant = make_bond('a', 'b', :mutualistic, strength: 0.0)
79
+ ecosystem.register_bond(dormant)
80
+ expect(ecosystem.measure_health).to eq(0.0)
81
+ end
82
+ end
83
+
84
+ describe '#health_label' do
85
+ it 'returns :critical for empty ecosystem' do
86
+ expect(ecosystem.health_label).to eq(:critical)
87
+ end
88
+
89
+ it 'returns a symbol label' do
90
+ ecosystem.register_bond(make_bond('a', 'b', :mutualistic))
91
+ expect(ecosystem.health_label).to be_a(Symbol)
92
+ end
93
+ end
94
+
95
+ describe '#most_beneficial' do
96
+ it 'returns nil when no mutualistic bonds' do
97
+ ecosystem.register_bond(make_bond('a', 'b', :parasitic))
98
+ expect(ecosystem.most_beneficial).to be_nil
99
+ end
100
+
101
+ it 'returns the mutualistic bond with highest benefit*strength' do
102
+ low = bond_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, strength: 0.3, benefit_ratio: 0.2)
103
+ high = bond_class.new(subsystem_a: 'c', subsystem_b: 'd', relationship_type: :mutualistic, strength: 0.9, benefit_ratio: 0.9)
104
+ ecosystem.register_bond(low)
105
+ ecosystem.register_bond(high)
106
+ expect(ecosystem.most_beneficial).to be(high)
107
+ end
108
+ end
109
+
110
+ describe '#most_parasitic' do
111
+ it 'returns nil when no parasitic bonds' do
112
+ ecosystem.register_bond(make_bond('a', 'b', :mutualistic))
113
+ expect(ecosystem.most_parasitic).to be_nil
114
+ end
115
+
116
+ it 'returns parasitic bond' do
117
+ ecosystem.register_bond(make_bond('x', 'y', :parasitic))
118
+ expect(ecosystem.most_parasitic).not_to be_nil
119
+ end
120
+ end
121
+
122
+ describe '#decay_all!' do
123
+ it 'decays all bonds and returns count' do
124
+ 3.times { |i| ecosystem.register_bond(make_bond("a#{i}", "b#{i}", :mutualistic)) }
125
+ count = ecosystem.decay_all!
126
+ expect(count).to eq(3)
127
+ end
128
+ end
129
+
130
+ describe '#network_density' do
131
+ it 'returns 0.0 for empty ecosystem' do
132
+ expect(ecosystem.network_density).to eq(0.0)
133
+ end
134
+
135
+ it 'returns average strength of active bonds' do
136
+ ecosystem.register_bond(make_bond('a', 'b', :mutualistic, strength: 0.8))
137
+ ecosystem.register_bond(make_bond('c', 'd', :mutualistic, strength: 0.4))
138
+ expect(ecosystem.network_density).to be_within(0.01).of(0.6)
139
+ end
140
+ end
141
+
142
+ describe '#symbiotic_web' do
143
+ it 'returns all bonds involving a subsystem' do
144
+ ecosystem.register_bond(make_bond('memory', 'emotion', :mutualistic))
145
+ ecosystem.register_bond(make_bond('memory', 'prediction', :commensal))
146
+ ecosystem.register_bond(make_bond('trust', 'consent', :mutualistic))
147
+ web = ecosystem.symbiotic_web('memory')
148
+ expect(web.size).to eq(2)
149
+ end
150
+
151
+ it 'returns empty array for unknown subsystem' do
152
+ expect(ecosystem.symbiotic_web('nobody')).to be_empty
153
+ end
154
+ end
155
+
156
+ describe '#find_bond' do
157
+ before { ecosystem.register_bond(make_bond('alpha', 'beta', :mutualistic)) }
158
+
159
+ it 'finds bond by exact pair' do
160
+ expect(ecosystem.find_bond('alpha', 'beta')).not_to be_nil
161
+ end
162
+
163
+ it 'finds bond in reverse order' do
164
+ expect(ecosystem.find_bond('beta', 'alpha')).not_to be_nil
165
+ end
166
+
167
+ it 'returns nil for unknown pair' do
168
+ expect(ecosystem.find_bond('x', 'y')).to be_nil
169
+ end
170
+ end
171
+
172
+ describe '#all_bonds / #active_bonds' do
173
+ it 'all_bonds returns all including dormant' do
174
+ ecosystem.register_bond(make_bond('a', 'b', :commensal, strength: 0.0))
175
+ ecosystem.register_bond(make_bond('c', 'd', :mutualistic, strength: 0.5))
176
+ expect(ecosystem.all_bonds.size).to eq(2)
177
+ end
178
+
179
+ it 'active_bonds excludes dormant bonds' do
180
+ ecosystem.register_bond(make_bond('a', 'b', :commensal, strength: 0.0))
181
+ ecosystem.register_bond(make_bond('c', 'd', :mutualistic, strength: 0.5))
182
+ expect(ecosystem.active_bonds.size).to eq(1)
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Symbiosis::Helpers::SymbiosisEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ describe '#create_bond' do
7
+ it 'creates a mutualistic bond and returns created: true' do
8
+ result = engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :mutualistic)
9
+ expect(result[:created]).to be true
10
+ expect(result[:bond][:relationship_type]).to eq(:mutualistic)
11
+ end
12
+
13
+ it 'creates a parasitic bond' do
14
+ result = engine.create_bond(subsystem_a: 'cortex', subsystem_b: 'tick', relationship_type: :parasitic)
15
+ expect(result[:created]).to be true
16
+ end
17
+
18
+ it 'creates a commensal bond' do
19
+ result = engine.create_bond(subsystem_a: 'trust', subsystem_b: 'identity', relationship_type: :commensal)
20
+ expect(result[:created]).to be true
21
+ end
22
+
23
+ it 'returns created: false when bond already exists' do
24
+ engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :mutualistic)
25
+ result = engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :commensal)
26
+ expect(result[:created]).to be false
27
+ expect(result[:reason]).to eq(:already_exists)
28
+ end
29
+
30
+ it 'returns created: false for invalid relationship_type' do
31
+ result = engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :bogus)
32
+ expect(result[:created]).to be false
33
+ expect(result[:reason]).to eq(:invalid_arguments)
34
+ end
35
+
36
+ it 'accepts explicit strength' do
37
+ result = engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, strength: 0.9)
38
+ expect(result[:bond][:strength]).to eq(0.9)
39
+ end
40
+
41
+ it 'accepts explicit benefit_ratio' do
42
+ result = engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, benefit_ratio: 0.75)
43
+ expect(result[:bond][:benefit_ratio]).to eq(0.75)
44
+ end
45
+ end
46
+
47
+ describe '#activate_interaction' do
48
+ before { engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :mutualistic) }
49
+
50
+ it 'activates an existing bond' do
51
+ result = engine.activate_interaction(subsystem_a: 'memory', subsystem_b: 'emotion')
52
+ expect(result[:found]).to be true
53
+ end
54
+
55
+ it 'returns relationship_type in result' do
56
+ result = engine.activate_interaction(subsystem_a: 'memory', subsystem_b: 'emotion')
57
+ expect(result[:relationship_type]).to eq(:mutualistic)
58
+ end
59
+
60
+ it 'returns found: false for unknown pair' do
61
+ result = engine.activate_interaction(subsystem_a: 'x', subsystem_b: 'y')
62
+ expect(result[:found]).to be false
63
+ end
64
+
65
+ it 'works in reverse order' do
66
+ result = engine.activate_interaction(subsystem_a: 'emotion', subsystem_b: 'memory')
67
+ expect(result[:found]).to be true
68
+ end
69
+ end
70
+
71
+ describe '#measure_ecosystem_health' do
72
+ it 'returns a hash with score, label, bond_count, active_bonds, network_density' do
73
+ result = engine.measure_ecosystem_health
74
+ expect(result).to include(:score, :label, :bond_count, :active_bonds, :network_density)
75
+ end
76
+
77
+ it 'returns score 0.0 for fresh engine' do
78
+ expect(engine.measure_ecosystem_health[:score]).to eq(0.0)
79
+ end
80
+
81
+ it 'returns higher score after adding mutualistic bonds' do
82
+ engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic)
83
+ expect(engine.measure_ecosystem_health[:score]).to be > 0
84
+ end
85
+ end
86
+
87
+ describe '#find_partners' do
88
+ before do
89
+ engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :mutualistic, strength: 0.7)
90
+ engine.create_bond(subsystem_a: 'memory', subsystem_b: 'prediction', relationship_type: :parasitic, strength: 0.5)
91
+ engine.create_bond(subsystem_a: 'trust', subsystem_b: 'consent', relationship_type: :mutualistic, strength: 0.6)
92
+ end
93
+
94
+ it 'returns partners of a subsystem with positive benefit_ratio by default' do
95
+ partners = engine.find_partners('memory')
96
+ subsystems = partners.map { |p| p[:partner] }
97
+ expect(subsystems).to include('emotion')
98
+ end
99
+
100
+ it 'includes parasitic partners when min_benefit_ratio allows negatives' do
101
+ partners = engine.find_partners('memory', min_benefit_ratio: -1.0)
102
+ subsystems = partners.map { |p| p[:partner] }
103
+ expect(subsystems).to include('emotion', 'prediction')
104
+ end
105
+
106
+ it 'filters by min_benefit_ratio to exclude parasitic' do
107
+ partners = engine.find_partners('memory', min_benefit_ratio: 0.0)
108
+ types = partners.map { |p| p[:relationship_type] }
109
+ expect(types).not_to include(:parasitic)
110
+ end
111
+
112
+ it 'returns empty array for unknown subsystem' do
113
+ expect(engine.find_partners('nobody')).to be_empty
114
+ end
115
+
116
+ it 'sorts by strength descending' do
117
+ partners = engine.find_partners('memory', min_benefit_ratio: -1.0)
118
+ strengths = partners.map { |p| p[:strength] }
119
+ expect(strengths).to eq(strengths.sort.reverse)
120
+ end
121
+ end
122
+
123
+ describe '#detect_parasites' do
124
+ before do
125
+ engine.create_bond(subsystem_a: 'cortex', subsystem_b: 'emotion', relationship_type: :parasitic, strength: 0.6)
126
+ engine.create_bond(subsystem_a: 'memory', subsystem_b: 'trust', relationship_type: :mutualistic, strength: 0.5)
127
+ end
128
+
129
+ it 'returns only parasitic bonds' do
130
+ result = engine.detect_parasites
131
+ types = result.map { |b| b[:relationship_type] }
132
+ expect(types).to all(eq(:parasitic))
133
+ end
134
+
135
+ it 'excludes bonds below strength_threshold' do
136
+ result = engine.detect_parasites(strength_threshold: 0.8)
137
+ expect(result).to be_empty
138
+ end
139
+
140
+ it 'returns dormant parasitic bonds when threshold is 0' do
141
+ engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :parasitic, strength: 0.4)
142
+ result = engine.detect_parasites
143
+ expect(result.size).to be >= 1
144
+ end
145
+ end
146
+
147
+ describe '#ecosystem_report' do
148
+ before do
149
+ engine.create_bond(subsystem_a: 'memory', subsystem_b: 'emotion', relationship_type: :mutualistic, strength: 0.5)
150
+ engine.create_bond(subsystem_a: 'cortex', subsystem_b: 'tick', relationship_type: :parasitic, strength: 0.4)
151
+ end
152
+
153
+ it 'returns expected keys' do
154
+ report = engine.ecosystem_report
155
+ expect(report).to include(:health, :bonds_by_type, :most_beneficial, :most_parasitic, :total_bonds, :dormant_bonds)
156
+ end
157
+
158
+ it 'bonds_by_type contains all three relationship types' do
159
+ report = engine.ecosystem_report
160
+ expect(report[:bonds_by_type].keys).to include(:mutualistic, :parasitic, :commensal)
161
+ end
162
+
163
+ it 'total_bonds matches registered count' do
164
+ report = engine.ecosystem_report
165
+ expect(report[:total_bonds]).to eq(2)
166
+ end
167
+
168
+ it 'most_beneficial refers to mutualistic bond' do
169
+ report = engine.ecosystem_report
170
+ expect(report[:most_beneficial][:relationship_type]).to eq(:mutualistic)
171
+ end
172
+ end
173
+
174
+ describe '#decay_all' do
175
+ it 'returns decayed count and health_after' do
176
+ engine.create_bond(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic)
177
+ result = engine.decay_all
178
+ expect(result).to include(:decayed, :health_after)
179
+ expect(result[:decayed]).to eq(1)
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Symbiosis::Helpers::SymbioticBond do
4
+ let(:bond) do
5
+ described_class.new(
6
+ subsystem_a: 'memory',
7
+ subsystem_b: 'emotion',
8
+ relationship_type: :mutualistic
9
+ )
10
+ end
11
+
12
+ describe '#initialize' do
13
+ it 'assigns subsystem_a and subsystem_b' do
14
+ expect(bond.subsystem_a).to eq('memory')
15
+ expect(bond.subsystem_b).to eq('emotion')
16
+ end
17
+
18
+ it 'assigns relationship_type' do
19
+ expect(bond.relationship_type).to eq(:mutualistic)
20
+ end
21
+
22
+ it 'assigns a uuid bond_id' do
23
+ expect(bond.bond_id).to match(/\A[0-9a-f-]{36}\z/)
24
+ end
25
+
26
+ it 'sets default strength when not provided' do
27
+ expect(bond.strength).to eq(
28
+ Legion::Extensions::Agentic::Social::Symbiosis::Helpers::Constants::DEFAULT_STRENGTH
29
+ )
30
+ end
31
+
32
+ it 'clamps strength to 0.0..1.0' do
33
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, strength: 5.0)
34
+ expect(b.strength).to eq(1.0)
35
+ end
36
+
37
+ it 'clamps negative strength to 0.0' do
38
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, strength: -1.0)
39
+ expect(b.strength).to eq(0.0)
40
+ end
41
+
42
+ it 'assigns a positive benefit_ratio for mutualistic by default' do
43
+ expect(bond.benefit_ratio).to be > 0
44
+ end
45
+
46
+ it 'assigns a negative benefit_ratio for parasitic by default' do
47
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :parasitic)
48
+ expect(b.benefit_ratio).to be < 0
49
+ end
50
+
51
+ it 'accepts explicit benefit_ratio' do
52
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, benefit_ratio: 0.8)
53
+ expect(b.benefit_ratio).to eq(0.8)
54
+ end
55
+
56
+ it 'sets activation_count to 0' do
57
+ expect(bond.activation_count).to eq(0)
58
+ end
59
+
60
+ it 'sets last_activated_at to nil' do
61
+ expect(bond.last_activated_at).to be_nil
62
+ end
63
+
64
+ it 'raises ArgumentError for unknown relationship_type' do
65
+ expect do
66
+ described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :unknown)
67
+ end.to raise_error(ArgumentError, /unknown relationship_type/)
68
+ end
69
+ end
70
+
71
+ describe '#activate!' do
72
+ it 'increases strength' do
73
+ before = bond.strength
74
+ bond.activate!(amount: 0.1)
75
+ expect(bond.strength).to be > before
76
+ end
77
+
78
+ it 'increments activation_count' do
79
+ bond.activate!
80
+ expect(bond.activation_count).to eq(1)
81
+ end
82
+
83
+ it 'sets last_activated_at' do
84
+ bond.activate!
85
+ expect(bond.last_activated_at).not_to be_nil
86
+ end
87
+
88
+ it 'does not exceed MAX_STRENGTH' do
89
+ bond.activate!(amount: 10.0)
90
+ expect(bond.strength).to eq(1.0)
91
+ end
92
+
93
+ it 'clamps amount to 1.0 max' do
94
+ bond.activate!(amount: 99.0)
95
+ expect(bond.strength).to eq(1.0)
96
+ end
97
+
98
+ it 'returns self for chaining' do
99
+ expect(bond.activate!).to be(bond)
100
+ end
101
+ end
102
+
103
+ describe '#decay!' do
104
+ it 'decreases strength' do
105
+ bond.activate!(amount: 0.5)
106
+ before = bond.strength
107
+ bond.decay!
108
+ expect(bond.strength).to be < before
109
+ end
110
+
111
+ it 'does not go below MIN_STRENGTH' do
112
+ 50.times { bond.decay! }
113
+ expect(bond.strength).to eq(0.0)
114
+ end
115
+
116
+ it 'returns self for chaining' do
117
+ expect(bond.decay!).to be(bond)
118
+ end
119
+ end
120
+
121
+ describe '#dormant?' do
122
+ it 'returns true when strength is at or below DORMANT_THRESHOLD' do
123
+ b = described_class.new(
124
+ subsystem_a: 'a', subsystem_b: 'b', relationship_type: :commensal,
125
+ strength: Legion::Extensions::Agentic::Social::Symbiosis::Helpers::Constants::DORMANT_THRESHOLD
126
+ )
127
+ expect(b.dormant?).to be true
128
+ end
129
+
130
+ it 'returns false for active bond' do
131
+ bond.activate!(amount: 0.5)
132
+ expect(bond.dormant?).to be false
133
+ end
134
+ end
135
+
136
+ describe '#strong?' do
137
+ it 'returns false by default' do
138
+ expect(bond.strong?).to be false
139
+ end
140
+
141
+ it 'returns true when strength meets STRONG_THRESHOLD' do
142
+ b = described_class.new(
143
+ subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic,
144
+ strength: Legion::Extensions::Agentic::Social::Symbiosis::Helpers::Constants::STRONG_THRESHOLD
145
+ )
146
+ expect(b.strong?).to be true
147
+ end
148
+ end
149
+
150
+ describe '#strength_label' do
151
+ it 'returns :dormant for very low strength' do
152
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :commensal, strength: 0.01)
153
+ expect(b.strength_label).to eq(:dormant)
154
+ end
155
+
156
+ it 'returns :dominant for very high strength' do
157
+ b = described_class.new(subsystem_a: 'a', subsystem_b: 'b', relationship_type: :mutualistic, strength: 0.95)
158
+ expect(b.strength_label).to eq(:dominant)
159
+ end
160
+ end
161
+
162
+ describe '#involves?' do
163
+ it 'returns true when subsystem_a matches' do
164
+ expect(bond.involves?('memory')).to be true
165
+ end
166
+
167
+ it 'returns true when subsystem_b matches' do
168
+ expect(bond.involves?('emotion')).to be true
169
+ end
170
+
171
+ it 'returns false for unrelated subsystem' do
172
+ expect(bond.involves?('prediction')).to be false
173
+ end
174
+ end
175
+
176
+ describe '#partner_of' do
177
+ it 'returns subsystem_b when given subsystem_a' do
178
+ expect(bond.partner_of('memory')).to eq('emotion')
179
+ end
180
+
181
+ it 'returns subsystem_a when given subsystem_b' do
182
+ expect(bond.partner_of('emotion')).to eq('memory')
183
+ end
184
+
185
+ it 'returns nil for unknown subsystem' do
186
+ expect(bond.partner_of('unknown')).to be_nil
187
+ end
188
+ end
189
+
190
+ describe '#to_h' do
191
+ it 'includes all required keys' do
192
+ h = bond.to_h
193
+ expect(h).to include(
194
+ :bond_id, :subsystem_a, :subsystem_b, :relationship_type,
195
+ :strength, :strength_label, :benefit_ratio, :activation_count,
196
+ :dormant, :strong, :created_at, :last_activated_at
197
+ )
198
+ end
199
+
200
+ it 'last_activated_at is nil before first activation' do
201
+ expect(bond.to_h[:last_activated_at]).to be_nil
202
+ end
203
+
204
+ it 'last_activated_at is an ISO8601 string after activation' do
205
+ bond.activate!
206
+ expect(bond.to_h[:last_activated_at]).to match(/\d{4}-\d{2}-\d{2}T/)
207
+ end
208
+ end
209
+ end