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,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Social::Social::Helpers::SocialGraph do
6
+ subject(:graph) { described_class.new }
7
+
8
+ describe '#initialize' do
9
+ it 'starts with empty groups' do
10
+ expect(graph.groups).to be_empty
11
+ end
12
+
13
+ it 'starts with empty reputation scores' do
14
+ expect(graph.reputation_scores).to be_empty
15
+ end
16
+
17
+ it 'starts with empty reciprocity ledger' do
18
+ expect(graph.reciprocity_ledger).to be_empty
19
+ end
20
+ end
21
+
22
+ describe '#join_group' do
23
+ it 'creates a new group entry' do
24
+ graph.join_group(group_id: :alpha)
25
+ expect(graph.groups).to have_key(:alpha)
26
+ end
27
+
28
+ it 'returns the group hash' do
29
+ result = graph.join_group(group_id: :alpha, role: :leader)
30
+ expect(result[:role]).to eq(:leader)
31
+ end
32
+
33
+ it 'defaults role to contributor' do
34
+ graph.join_group(group_id: :alpha)
35
+ expect(graph.groups[:alpha][:role]).to eq(:contributor)
36
+ end
37
+
38
+ it 'stores members' do
39
+ graph.join_group(group_id: :alpha, members: %w[a1 a2])
40
+ expect(graph.groups[:alpha][:members]).to eq(%w[a1 a2])
41
+ end
42
+
43
+ it 'initializes cohesion at 0.5' do
44
+ graph.join_group(group_id: :alpha)
45
+ expect(graph.groups[:alpha][:cohesion]).to eq(0.5)
46
+ end
47
+
48
+ it 'initializes empty violations' do
49
+ graph.join_group(group_id: :alpha)
50
+ expect(graph.groups[:alpha][:violations]).to be_empty
51
+ end
52
+
53
+ it 'does not overwrite existing group' do
54
+ graph.join_group(group_id: :alpha, role: :leader)
55
+ graph.join_group(group_id: :alpha, role: :observer)
56
+ expect(graph.groups[:alpha][:role]).to eq(:leader)
57
+ end
58
+
59
+ it 'trims groups beyond MAX_GROUPS' do
60
+ max = Legion::Extensions::Agentic::Social::Social::Helpers::Constants::MAX_GROUPS
61
+ (max + 3).times { |i| graph.join_group(group_id: :"group_#{i}") }
62
+ expect(graph.group_count).to eq(max)
63
+ end
64
+ end
65
+
66
+ describe '#leave_group' do
67
+ before { graph.join_group(group_id: :alpha) }
68
+
69
+ it 'removes the group' do
70
+ graph.leave_group(:alpha)
71
+ expect(graph.groups).not_to have_key(:alpha)
72
+ end
73
+
74
+ it 'returns nil for unknown group' do
75
+ expect(graph.leave_group(:unknown)).to be_nil
76
+ end
77
+ end
78
+
79
+ describe '#update_role' do
80
+ before { graph.join_group(group_id: :alpha, role: :contributor) }
81
+
82
+ it 'updates the role' do
83
+ graph.update_role(group_id: :alpha, role: :leader)
84
+ expect(graph.groups[:alpha][:role]).to eq(:leader)
85
+ end
86
+
87
+ it 'returns nil for unknown group' do
88
+ expect(graph.update_role(group_id: :unknown, role: :leader)).to be_nil
89
+ end
90
+
91
+ it 'returns nil for invalid role' do
92
+ expect(graph.update_role(group_id: :alpha, role: :invalid)).to be_nil
93
+ end
94
+ end
95
+
96
+ describe '#update_reputation' do
97
+ it 'initializes reputation scores for new agent' do
98
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.8)
99
+ expect(graph.reputation_scores[:a1]).to be_a(Hash)
100
+ end
101
+
102
+ it 'updates the specified dimension via EMA' do
103
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 1.0)
104
+ score = graph.reputation_scores[:a1][:reliability]
105
+ expect(score).to be > 0.5
106
+ expect(score).to be < 1.0
107
+ end
108
+
109
+ it 'clamps signal to 0..1' do
110
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 5.0)
111
+ score = graph.reputation_scores[:a1][:reliability]
112
+ expect(score).to be <= 1.0
113
+ end
114
+
115
+ it 'returns nil for invalid dimension' do
116
+ result = graph.update_reputation(agent_id: :a1, dimension: :fake, signal: 0.5)
117
+ expect(result).to be_nil
118
+ end
119
+
120
+ it 'converges toward signal over repeated updates' do
121
+ 20.times { graph.update_reputation(agent_id: :a1, dimension: :competence, signal: 0.9) }
122
+ expect(graph.reputation_scores[:a1][:competence]).to be > 0.8
123
+ end
124
+ end
125
+
126
+ describe '#reputation_for' do
127
+ before do
128
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.8)
129
+ end
130
+
131
+ it 'returns agent_id in the result' do
132
+ expect(graph.reputation_for(:a1)[:agent_id]).to eq(:a1)
133
+ end
134
+
135
+ it 'returns a composite score' do
136
+ expect(graph.reputation_for(:a1)[:composite]).to be_a(Float)
137
+ end
138
+
139
+ it 'returns a standing classification' do
140
+ expect(graph.reputation_for(:a1)[:standing]).to be_a(Symbol)
141
+ end
142
+
143
+ it 'returns rounded scores' do
144
+ rep = graph.reputation_for(:a1)
145
+ rep[:scores].each_value do |v|
146
+ expect(v.to_s.split('.').last.length).to be <= 4
147
+ end
148
+ end
149
+
150
+ it 'returns nil for unknown agent' do
151
+ expect(graph.reputation_for(:unknown)).to be_nil
152
+ end
153
+ end
154
+
155
+ describe '#social_standing' do
156
+ it 'returns :neutral when no agents tracked' do
157
+ expect(graph.social_standing).to eq(:neutral)
158
+ end
159
+
160
+ it 'returns a classification symbol with agents' do
161
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.9)
162
+ expect(graph.social_standing).to be_a(Symbol)
163
+ end
164
+ end
165
+
166
+ describe '#record_reciprocity' do
167
+ it 'adds an entry to the ledger' do
168
+ graph.record_reciprocity(agent_id: :a1, action: :helped, direction: :given)
169
+ expect(graph.reciprocity_ledger.size).to eq(1)
170
+ end
171
+
172
+ it 'tracks direction' do
173
+ graph.record_reciprocity(agent_id: :a1, action: :helped, direction: :given)
174
+ expect(graph.reciprocity_ledger.first[:direction]).to eq(:given)
175
+ end
176
+
177
+ it 'enforces RECIPROCITY_WINDOW' do
178
+ window = Legion::Extensions::Agentic::Social::Social::Helpers::Constants::RECIPROCITY_WINDOW
179
+ (window + 10).times do |i|
180
+ graph.record_reciprocity(agent_id: :a1, action: :"action_#{i}", direction: :given)
181
+ end
182
+ expect(graph.reciprocity_ledger.size).to eq(window)
183
+ end
184
+ end
185
+
186
+ describe '#reciprocity_balance' do
187
+ before do
188
+ 3.times { graph.record_reciprocity(agent_id: :a1, action: :help, direction: :given) }
189
+ graph.record_reciprocity(agent_id: :a1, action: :assist, direction: :received)
190
+ 2.times { graph.record_reciprocity(agent_id: :a2, action: :teach, direction: :given) }
191
+ end
192
+
193
+ it 'counts given correctly' do
194
+ expect(graph.reciprocity_balance(:a1)[:given]).to eq(3)
195
+ end
196
+
197
+ it 'counts received correctly' do
198
+ expect(graph.reciprocity_balance(:a1)[:received]).to eq(1)
199
+ end
200
+
201
+ it 'computes balance as given - received' do
202
+ expect(graph.reciprocity_balance(:a1)[:balance]).to eq(2)
203
+ end
204
+
205
+ it 'isolates by agent' do
206
+ expect(graph.reciprocity_balance(:a2)[:given]).to eq(2)
207
+ expect(graph.reciprocity_balance(:a2)[:received]).to eq(0)
208
+ end
209
+ end
210
+
211
+ describe '#record_violation' do
212
+ before { graph.join_group(group_id: :alpha) }
213
+
214
+ it 'records the violation' do
215
+ result = graph.record_violation(group_id: :alpha, type: :free_riding, agent_id: :a1)
216
+ expect(result[:type]).to eq(:free_riding)
217
+ end
218
+
219
+ it 'reduces cohesion' do
220
+ initial = graph.groups[:alpha][:cohesion]
221
+ graph.record_violation(group_id: :alpha, type: :defection, agent_id: :a1)
222
+ expect(graph.groups[:alpha][:cohesion]).to be < initial
223
+ end
224
+
225
+ it 'returns nil for unknown group' do
226
+ result = graph.record_violation(group_id: :unknown, type: :free_riding, agent_id: :a1)
227
+ expect(result).to be_nil
228
+ end
229
+
230
+ it 'returns nil for invalid violation type' do
231
+ result = graph.record_violation(group_id: :alpha, type: :invalid, agent_id: :a1)
232
+ expect(result).to be_nil
233
+ end
234
+
235
+ it 'cohesion does not go below 0' do
236
+ 10.times { graph.record_violation(group_id: :alpha, type: :free_riding, agent_id: :a1) }
237
+ expect(graph.groups[:alpha][:cohesion]).to be >= 0.0
238
+ end
239
+ end
240
+
241
+ describe '#group_cohesion' do
242
+ it 'returns nil for unknown group' do
243
+ expect(graph.group_cohesion(:unknown)).to be_nil
244
+ end
245
+
246
+ it 'returns the cohesion value' do
247
+ graph.join_group(group_id: :alpha)
248
+ expect(graph.group_cohesion(:alpha)).to eq(0.5)
249
+ end
250
+ end
251
+
252
+ describe '#update_cohesion' do
253
+ before { graph.join_group(group_id: :alpha) }
254
+
255
+ it 'moves cohesion toward signal via EMA' do
256
+ graph.update_cohesion(group_id: :alpha, signal: 1.0)
257
+ expect(graph.group_cohesion(:alpha)).to be > 0.5
258
+ end
259
+
260
+ it 'clamps signal to 0..1' do
261
+ graph.update_cohesion(group_id: :alpha, signal: 5.0)
262
+ expect(graph.group_cohesion(:alpha)).to be <= 1.0
263
+ end
264
+
265
+ it 'returns nil for unknown group' do
266
+ expect(graph.update_cohesion(group_id: :unknown, signal: 0.8)).to be_nil
267
+ end
268
+ end
269
+
270
+ describe '#classify_cohesion' do
271
+ before { graph.join_group(group_id: :alpha) }
272
+
273
+ it 'returns :moderate for default cohesion (0.5)' do
274
+ expect(graph.classify_cohesion(:alpha)).to eq(:moderate)
275
+ end
276
+
277
+ it 'returns :tight for high cohesion' do
278
+ 5.times { graph.update_cohesion(group_id: :alpha, signal: 1.0) }
279
+ 10.times { graph.update_cohesion(group_id: :alpha, signal: 1.0) }
280
+ expect(graph.classify_cohesion(:alpha)).to eq(:tight)
281
+ end
282
+
283
+ it 'returns nil for unknown group' do
284
+ expect(graph.classify_cohesion(:unknown)).to be_nil
285
+ end
286
+ end
287
+
288
+ describe '#group_count' do
289
+ it 'returns 0 with no groups' do
290
+ expect(graph.group_count).to eq(0)
291
+ end
292
+
293
+ it 'returns the number of groups' do
294
+ graph.join_group(group_id: :alpha)
295
+ graph.join_group(group_id: :beta)
296
+ expect(graph.group_count).to eq(2)
297
+ end
298
+ end
299
+
300
+ describe '#agents_tracked' do
301
+ it 'returns 0 with no agents' do
302
+ expect(graph.agents_tracked).to eq(0)
303
+ end
304
+
305
+ it 'counts unique agents with reputation' do
306
+ graph.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.5)
307
+ graph.update_reputation(agent_id: :a2, dimension: :competence, signal: 0.7)
308
+ expect(graph.agents_tracked).to eq(2)
309
+ end
310
+ end
311
+
312
+ describe '#to_h' do
313
+ it 'returns a hash with expected keys' do
314
+ result = graph.to_h
315
+ expect(result).to have_key(:groups)
316
+ expect(result).to have_key(:group_count)
317
+ expect(result).to have_key(:agents_tracked)
318
+ expect(result).to have_key(:social_standing)
319
+ expect(result).to have_key(:ledger_size)
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,220 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Social::Social::Runners::Social do
6
+ let(:graph) { Legion::Extensions::Agentic::Social::Social::Helpers::SocialGraph.new }
7
+
8
+ let(:host) do
9
+ Object.new.tap do |obj|
10
+ obj.extend(described_class)
11
+ obj.instance_variable_set(:@social_graph, graph)
12
+ end
13
+ end
14
+
15
+ describe '#join_group' do
16
+ it 'returns success' do
17
+ result = host.join_group(group_id: :alpha, role: :contributor)
18
+ expect(result[:success]).to be true
19
+ end
20
+
21
+ it 'returns the group_id and role' do
22
+ result = host.join_group(group_id: :alpha, role: :leader, members: %w[a1])
23
+ expect(result[:group_id]).to eq(:alpha)
24
+ expect(result[:role]).to eq(:leader)
25
+ end
26
+
27
+ it 'includes the group hash' do
28
+ result = host.join_group(group_id: :alpha)
29
+ expect(result[:group]).to be_a(Hash)
30
+ end
31
+ end
32
+
33
+ describe '#leave_group' do
34
+ before { host.join_group(group_id: :alpha) }
35
+
36
+ it 'returns success' do
37
+ result = host.leave_group(group_id: :alpha)
38
+ expect(result[:success]).to be true
39
+ end
40
+
41
+ it 'removes the group from the graph' do
42
+ host.leave_group(group_id: :alpha)
43
+ expect(graph.groups).not_to have_key(:alpha)
44
+ end
45
+ end
46
+
47
+ describe '#update_reputation' do
48
+ it 'returns success for valid dimension' do
49
+ result = host.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.8)
50
+ expect(result[:success]).to be true
51
+ end
52
+
53
+ it 'returns reputation hash' do
54
+ result = host.update_reputation(agent_id: :a1, dimension: :competence, signal: 0.9)
55
+ expect(result[:reputation]).to have_key(:composite)
56
+ end
57
+
58
+ it 'returns failure for invalid dimension' do
59
+ result = host.update_reputation(agent_id: :a1, dimension: :fake, signal: 0.5)
60
+ expect(result[:success]).to be false
61
+ end
62
+ end
63
+
64
+ describe '#agent_reputation' do
65
+ it 'returns reputation for known agent' do
66
+ host.update_reputation(agent_id: :a1, dimension: :reliability, signal: 0.8)
67
+ result = host.agent_reputation(agent_id: :a1)
68
+ expect(result[:composite]).to be_a(Float)
69
+ end
70
+
71
+ it 'returns error for unknown agent' do
72
+ result = host.agent_reputation(agent_id: :unknown)
73
+ expect(result[:error]).to eq('unknown agent')
74
+ end
75
+ end
76
+
77
+ describe '#reciprocity_status' do
78
+ it 'returns balance for agent' do
79
+ result = host.reciprocity_status(agent_id: :a1)
80
+ expect(result[:given]).to eq(0)
81
+ expect(result[:received]).to eq(0)
82
+ expect(result[:balance]).to eq(0)
83
+ end
84
+ end
85
+
86
+ describe '#record_exchange' do
87
+ it 'returns success' do
88
+ result = host.record_exchange(agent_id: :a1, action: :helped, direction: :given)
89
+ expect(result[:success]).to be true
90
+ end
91
+
92
+ it 'updates the reciprocity ledger' do
93
+ host.record_exchange(agent_id: :a1, action: :helped, direction: :given)
94
+ expect(graph.reciprocity_ledger.size).to eq(1)
95
+ end
96
+
97
+ it 'converts direction to symbol' do
98
+ host.record_exchange(agent_id: :a1, action: :helped, direction: 'received')
99
+ expect(graph.reciprocity_ledger.first[:direction]).to eq(:received)
100
+ end
101
+ end
102
+
103
+ describe '#report_violation' do
104
+ before { host.join_group(group_id: :alpha) }
105
+
106
+ it 'returns success for valid violation' do
107
+ result = host.report_violation(group_id: :alpha, type: :free_riding, agent_id: :a1)
108
+ expect(result[:success]).to be true
109
+ end
110
+
111
+ it 'returns the violation and cohesion' do
112
+ result = host.report_violation(group_id: :alpha, type: :defection, agent_id: :a1)
113
+ expect(result[:violation]).to be_a(Hash)
114
+ expect(result[:cohesion]).to be_a(Float)
115
+ end
116
+
117
+ it 'returns failure for invalid group' do
118
+ result = host.report_violation(group_id: :unknown, type: :free_riding, agent_id: :a1)
119
+ expect(result[:success]).to be false
120
+ end
121
+
122
+ it 'converts type to symbol' do
123
+ result = host.report_violation(group_id: :alpha, type: 'deception', agent_id: :a1)
124
+ expect(result[:success]).to be true
125
+ end
126
+ end
127
+
128
+ describe '#group_status' do
129
+ before { host.join_group(group_id: :alpha, role: :leader, members: %w[a1 a2]) }
130
+
131
+ it 'returns group details' do
132
+ result = host.group_status(group_id: :alpha)
133
+ expect(result[:group_id]).to eq(:alpha)
134
+ expect(result[:role]).to eq(:leader)
135
+ expect(result[:members]).to eq(2)
136
+ expect(result[:cohesion]).to be_a(Float)
137
+ expect(result[:cohesion_level]).to be_a(Symbol)
138
+ expect(result[:violations]).to eq(0)
139
+ end
140
+
141
+ it 'returns error for unknown group' do
142
+ result = host.group_status(group_id: :unknown)
143
+ expect(result[:error]).to eq('unknown group')
144
+ end
145
+ end
146
+
147
+ describe '#social_status' do
148
+ it 'returns a state hash' do
149
+ result = host.social_status
150
+ expect(result).to have_key(:groups)
151
+ expect(result).to have_key(:group_count)
152
+ expect(result).to have_key(:social_standing)
153
+ end
154
+ end
155
+
156
+ describe '#social_stats' do
157
+ before do
158
+ host.join_group(group_id: :alpha, role: :leader)
159
+ host.join_group(group_id: :beta, role: :contributor)
160
+ end
161
+
162
+ it 'returns group count' do
163
+ expect(host.social_stats[:groups]).to eq(2)
164
+ end
165
+
166
+ it 'returns group roles' do
167
+ roles = host.social_stats[:group_roles]
168
+ expect(roles[:alpha]).to eq(:leader)
169
+ expect(roles[:beta]).to eq(:contributor)
170
+ end
171
+
172
+ it 'returns ledger size' do
173
+ expect(host.social_stats[:ledger_size]).to eq(0)
174
+ end
175
+ end
176
+
177
+ describe '#update_social' do
178
+ before { host.join_group(group_id: :alpha) }
179
+
180
+ it 'returns social summary hash' do
181
+ result = host.update_social(tick_results: {})
182
+ expect(result).to have_key(:groups)
183
+ expect(result).to have_key(:agents_tracked)
184
+ expect(result).to have_key(:standing)
185
+ expect(result).to have_key(:ledger_size)
186
+ end
187
+
188
+ it 'extracts trust signals from tick results' do
189
+ tick = {
190
+ trust: {
191
+ updates: [
192
+ { agent_id: :a1, score: 0.9 },
193
+ { agent_id: :a2, score: 0.7 }
194
+ ]
195
+ }
196
+ }
197
+ host.update_social(tick_results: tick)
198
+ expect(graph.agents_tracked).to eq(2)
199
+ end
200
+
201
+ it 'handles missing trust data gracefully' do
202
+ result = host.update_social(tick_results: { trust: {} })
203
+ expect(result[:agents_tracked]).to eq(0)
204
+ end
205
+
206
+ it 'extracts mesh signals and updates cohesion' do
207
+ initial_cohesion = graph.group_cohesion(:alpha)
208
+ tick = { mesh_interface: { peer_count: 8 } }
209
+ host.update_social(tick_results: tick)
210
+ expect(graph.group_cohesion(:alpha)).to be > initial_cohesion
211
+ end
212
+
213
+ it 'skips mesh update when peer_count is zero' do
214
+ initial_cohesion = graph.group_cohesion(:alpha)
215
+ tick = { mesh_interface: { peer_count: 0 } }
216
+ host.update_social(tick_results: tick)
217
+ expect(graph.group_cohesion(:alpha)).to eq(initial_cohesion)
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::SocialLearning::Client do
4
+ let(:client) { described_class.new }
5
+
6
+ it 'responds to all runner methods' do
7
+ expect(client).to respond_to(:register_model_agent)
8
+ expect(client).to respond_to(:observe_agent_behavior)
9
+ expect(client).to respond_to(:retained_behaviors)
10
+ expect(client).to respond_to(:reproducible_behaviors)
11
+ expect(client).to respond_to(:reproduce_observed_behavior)
12
+ expect(client).to respond_to(:reinforce_reproduction)
13
+ expect(client).to respond_to(:best_model_agents)
14
+ expect(client).to respond_to(:domain_models)
15
+ expect(client).to respond_to(:update_social_learning)
16
+ expect(client).to respond_to(:social_learning_stats)
17
+ end
18
+
19
+ it 'accepts an injected engine' do
20
+ engine = Legion::Extensions::Agentic::Social::SocialLearning::Helpers::SocialLearningEngine.new
21
+ injected_client = described_class.new(engine: engine)
22
+ result = injected_client.social_learning_stats
23
+ expect(result[:success]).to be true
24
+ end
25
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::SocialLearning::Helpers::Constants do
4
+ it 'defines MAX_MODELS' do
5
+ expect(described_module::MAX_MODELS).to eq(200)
6
+ end
7
+
8
+ it 'defines MAX_BEHAVIORS' do
9
+ expect(described_module::MAX_BEHAVIORS).to eq(500)
10
+ end
11
+
12
+ it 'defines ATTENTION_THRESHOLD' do
13
+ expect(described_module::ATTENTION_THRESHOLD).to eq(0.3)
14
+ end
15
+
16
+ it 'defines REPRODUCTION_CONFIDENCE' do
17
+ expect(described_module::REPRODUCTION_CONFIDENCE).to eq(0.5)
18
+ end
19
+
20
+ it 'defines OUTCOME_TYPES' do
21
+ expect(described_module::OUTCOME_TYPES).to eq(%i[positive negative neutral])
22
+ end
23
+
24
+ it 'defines LEARNING_STAGES' do
25
+ expect(described_module::LEARNING_STAGES).to eq(%i[attention retention reproduction motivation])
26
+ end
27
+
28
+ it 'defines MODEL_LABELS mapping' do
29
+ expect(described_module::MODEL_LABELS).to be_a(Hash)
30
+ expect(described_module::MODEL_LABELS.size).to eq(5)
31
+ end
32
+
33
+ it 'PRESTIGE_FLOOR is 0.0' do
34
+ expect(described_module::PRESTIGE_FLOOR).to eq(0.0)
35
+ end
36
+
37
+ it 'PRESTIGE_CEILING is 1.0' do
38
+ expect(described_module::PRESTIGE_CEILING).to eq(1.0)
39
+ end
40
+
41
+ def described_module
42
+ Legion::Extensions::Agentic::Social::SocialLearning::Helpers::Constants
43
+ end
44
+ end