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,162 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/social/mentalizing/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Social::Mentalizing::Runners::Mentalizing do
6
+ let(:client) { Legion::Extensions::Agentic::Social::Mentalizing::Client.new }
7
+
8
+ describe '#attribute_belief' do
9
+ it 'returns attributed: true with belief hash' do
10
+ result = client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
11
+ expect(result[:attributed]).to be true
12
+ expect(result[:belief]).to include(:id, :agent_id, :subject, :content, :confidence, :depth)
13
+ end
14
+
15
+ it 'defaults confidence to DEFAULT_CONFIDENCE when not provided' do
16
+ result = client.attribute_belief(agent_id: 'alice', subject: 'snow', content: 'maybe')
17
+ expect(result[:belief][:confidence]).to eq(Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::DEFAULT_CONFIDENCE)
18
+ end
19
+
20
+ it 'caps depth at MAX_RECURSION_DEPTH' do
21
+ result = client.attribute_belief(agent_id: 'alice', subject: 's', content: 'c', depth: 100)
22
+ expect(result[:belief][:depth]).to eq(Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::MAX_RECURSION_DEPTH)
23
+ end
24
+
25
+ it 'accepts depth 0 (first-order)' do
26
+ result = client.attribute_belief(agent_id: 'alice', subject: 'trust', content: 'high', confidence: 0.9, depth: 0)
27
+ expect(result[:belief][:depth]).to eq(0)
28
+ end
29
+
30
+ it 'stores about_agent_id for second-order beliefs' do
31
+ result = client.attribute_belief(agent_id: 'alice', subject: 'plan', content: 'I will act', confidence: 0.7,
32
+ depth: 1, about_agent_id: 'bob')
33
+ expect(result[:belief][:about_agent_id]).to eq('bob')
34
+ end
35
+ end
36
+
37
+ describe '#project_belief' do
38
+ it 'returns projected: true with discounted confidence' do
39
+ result = client.project_belief(subject: 'plan', own_belief: 0.8, other_agent_id: 'bob')
40
+ expect(result[:projected]).to be true
41
+ discount = Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::PROJECTION_DISCOUNT
42
+ expect(result[:belief][:confidence]).to be_within(0.001).of(0.8 * discount)
43
+ end
44
+
45
+ it 'creates depth-1 belief about the other agent' do
46
+ result = client.project_belief(subject: 'plan', own_belief: 1.0, other_agent_id: 'carol')
47
+ expect(result[:belief][:depth]).to eq(1)
48
+ expect(result[:belief][:about_agent_id]).to eq('carol')
49
+ end
50
+ end
51
+
52
+ describe '#check_alignment' do
53
+ it 'returns alignment score of 0.0 when no shared beliefs' do
54
+ result = client.check_alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')
55
+ expect(result[:alignment]).to eq(0.0)
56
+ end
57
+
58
+ it 'returns alignment near 1.0 for identical confidences' do
59
+ client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.7)
60
+ client.attribute_belief(agent_id: 'bob', subject: 'rain', content: 'yes', confidence: 0.7)
61
+ result = client.check_alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')
62
+ expect(result[:alignment]).to be_within(0.001).of(1.0)
63
+ end
64
+
65
+ it 'returns subject in result' do
66
+ result = client.check_alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')
67
+ expect(result[:subject]).to eq('rain')
68
+ end
69
+ end
70
+
71
+ describe '#detect_false_belief' do
72
+ it 'detects false belief when agent belief contradicts reality' do
73
+ client.attribute_belief(agent_id: 'alice', subject: 'weather', content: 'sunny', confidence: 0.9)
74
+ result = client.detect_false_belief(agent_id: 'alice', subject: 'weather', reality: 'raining')
75
+ expect(result[:false_belief]).to be true
76
+ expect(result[:held_belief]).to eq('sunny')
77
+ end
78
+
79
+ it 'returns false_belief: false when belief matches reality' do
80
+ client.attribute_belief(agent_id: 'alice', subject: 'weather', content: 'sunny', confidence: 0.9)
81
+ result = client.detect_false_belief(agent_id: 'alice', subject: 'weather', reality: 'sunny')
82
+ expect(result[:false_belief]).to be false
83
+ end
84
+
85
+ it 'returns no_beliefs reason when agent unknown' do
86
+ result = client.detect_false_belief(agent_id: 'nobody', subject: 'weather', reality: 'sunny')
87
+ expect(result[:reason]).to eq(:no_beliefs)
88
+ end
89
+ end
90
+
91
+ describe '#beliefs_for_agent' do
92
+ it 'returns empty beliefs for unknown agent' do
93
+ result = client.beliefs_for_agent(agent_id: 'nobody')
94
+ expect(result[:beliefs]).to eq([])
95
+ expect(result[:count]).to eq(0)
96
+ end
97
+
98
+ it 'returns beliefs for known agent' do
99
+ client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
100
+ result = client.beliefs_for_agent(agent_id: 'alice')
101
+ expect(result[:count]).to eq(1)
102
+ expect(result[:beliefs].first[:agent_id]).to eq('alice')
103
+ end
104
+ end
105
+
106
+ describe '#beliefs_about_agent' do
107
+ it 'returns beliefs where about_agent_id matches' do
108
+ client.attribute_belief(agent_id: 'alice', subject: 'my_reliability', content: 'high', confidence: 0.8, about_agent_id: 'me')
109
+ client.attribute_belief(agent_id: 'bob', subject: 'my_reliability', content: 'low', confidence: 0.3, about_agent_id: 'me')
110
+ result = client.beliefs_about_agent(about_agent_id: 'me')
111
+ expect(result[:count]).to eq(2)
112
+ end
113
+
114
+ it 'returns empty when no beliefs about agent' do
115
+ result = client.beliefs_about_agent(about_agent_id: 'nobody')
116
+ expect(result[:count]).to eq(0)
117
+ end
118
+ end
119
+
120
+ describe '#recursive_belief_lookup' do
121
+ it 'returns found: false when no match' do
122
+ result = client.recursive_belief_lookup(agent_id: 'alice', about_agent_id: 'bob', subject: 'rain')
123
+ expect(result[:found]).to be false
124
+ end
125
+
126
+ it 'returns found: true with belief when match exists' do
127
+ client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'bob thinks rain', confidence: 0.75, about_agent_id: 'bob')
128
+ result = client.recursive_belief_lookup(agent_id: 'alice', about_agent_id: 'bob', subject: 'rain')
129
+ expect(result[:found]).to be true
130
+ expect(result[:belief][:content]).to eq('bob thinks rain')
131
+ end
132
+ end
133
+
134
+ describe '#update_mentalizing' do
135
+ it 'returns decayed: true' do
136
+ result = client.update_mentalizing
137
+ expect(result[:decayed]).to be true
138
+ end
139
+
140
+ it 'returns agent and belief counts' do
141
+ client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
142
+ result = client.update_mentalizing
143
+ expect(result).to have_key(:agents)
144
+ expect(result).to have_key(:beliefs)
145
+ end
146
+ end
147
+
148
+ describe '#mentalizing_stats' do
149
+ it 'returns agents and beliefs counts' do
150
+ result = client.mentalizing_stats
151
+ expect(result).to include(:agents, :beliefs)
152
+ end
153
+
154
+ it 'reflects current state' do
155
+ client.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
156
+ client.attribute_belief(agent_id: 'bob', subject: 'snow', content: 'no', confidence: 0.5)
157
+ result = client.mentalizing_stats
158
+ expect(result[:agents]).to eq(2)
159
+ expect(result[:beliefs]).to eq(2)
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/social/mirror/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Client do
6
+ subject(:client) { described_class.new }
7
+
8
+ it 'responds to observe runner methods' do
9
+ expect(client).to respond_to(:observe_action)
10
+ expect(client).to respond_to(:list_events)
11
+ end
12
+
13
+ it 'responds to simulate runner methods' do
14
+ expect(client).to respond_to(:simulate_action)
15
+ expect(client).to respond_to(:record_simulation_accuracy)
16
+ expect(client).to respond_to(:simulation_history)
17
+ end
18
+
19
+ it 'responds to resonance runner methods' do
20
+ expect(client).to respond_to(:empathic_resonance)
21
+ expect(client).to respond_to(:decay_resonances)
22
+ expect(client).to respond_to(:resonance_summary)
23
+ end
24
+
25
+ it 'shares a single internal engine across all runners' do
26
+ client.observe_action(agent_id: 'agent-1', action_type: :communication)
27
+ result = client.list_events(agent_id: 'agent-1')
28
+ expect(result[:count]).to eq(1)
29
+ end
30
+
31
+ it 'performs a full observe -> simulate -> resonance cycle' do
32
+ obs_result = client.observe_action(
33
+ agent_id: 'agent-1',
34
+ action_type: :decision,
35
+ emotional_valence: 0.6
36
+ )
37
+ expect(obs_result[:success]).to be(true)
38
+
39
+ event_id = obs_result[:event][:id]
40
+ sim_result = client.simulate_action(event_id: event_id, confidence: 0.75)
41
+ expect(sim_result[:success]).to be(true)
42
+ expect(sim_result[:simulation][:confidence]).to eq(0.75)
43
+
44
+ res_result = client.empathic_resonance(agent_id: 'agent-1')
45
+ expect(res_result[:resonance]).to be > 0.5
46
+ end
47
+
48
+ it 'records accuracy and returns it in subsequent queries' do
49
+ obs = client.observe_action(agent_id: 'agent-2', action_type: :analytical_task)
50
+ sim_result = client.simulate_action(event_id: obs[:event][:id])
51
+ sim_id = sim_result[:simulation][:id]
52
+
53
+ client.record_simulation_accuracy(simulation_id: sim_id, accuracy: 0.9)
54
+
55
+ res = client.empathic_resonance(agent_id: 'agent-2')
56
+ expect(res[:accuracy]).to be_within(0.001).of(0.9)
57
+ end
58
+
59
+ it 'global decay lowers resonance for all agents' do
60
+ client.observe_action(agent_id: 'agent-a', action_type: :movement)
61
+ client.observe_action(agent_id: 'agent-b', action_type: :social_interaction)
62
+
63
+ # Boost by simulating
64
+ list_a = client.list_events(agent_id: 'agent-a')
65
+ list_b = client.list_events(agent_id: 'agent-b')
66
+ client.simulate_action(event_id: list_a[:events].first[:id])
67
+ client.simulate_action(event_id: list_b[:events].first[:id])
68
+
69
+ before_a = client.empathic_resonance(agent_id: 'agent-a')[:resonance]
70
+ before_b = client.empathic_resonance(agent_id: 'agent-b')[:resonance]
71
+
72
+ client.decay_resonances
73
+
74
+ after_a = client.empathic_resonance(agent_id: 'agent-a')[:resonance]
75
+ after_b = client.empathic_resonance(agent_id: 'agent-b')[:resonance]
76
+
77
+ expect(after_a).to be < before_a
78
+ expect(after_b).to be < before_b
79
+ end
80
+
81
+ it 'resonance_summary shows all agents after observations' do
82
+ client.observe_action(agent_id: 'agent-x', action_type: :creative_act)
83
+ e = client.list_events(agent_id: 'agent-x')
84
+ client.simulate_action(event_id: e[:events].first[:id])
85
+
86
+ summary = client.resonance_summary
87
+ expect(summary[:total]).to be >= 1
88
+ agent_entry = summary[:agents].find { |a| a[:agent_id] == 'agent-x' }
89
+ expect(agent_entry).not_to be_nil
90
+ expect(agent_entry[:empathy_label]).to be_a(Symbol)
91
+ end
92
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants do
4
+ describe 'MAX_EVENTS' do
5
+ it 'equals 500' do
6
+ expect(described_class::MAX_EVENTS).to eq(500)
7
+ end
8
+ end
9
+
10
+ describe 'MAX_SIMULATIONS' do
11
+ it 'equals 300' do
12
+ expect(described_class::MAX_SIMULATIONS).to eq(300)
13
+ end
14
+ end
15
+
16
+ describe 'DEFAULT_RESONANCE' do
17
+ it 'equals 0.5' do
18
+ expect(described_class::DEFAULT_RESONANCE).to eq(0.5)
19
+ end
20
+ end
21
+
22
+ describe 'RESONANCE_BOOST' do
23
+ it 'equals 0.1' do
24
+ expect(described_class::RESONANCE_BOOST).to eq(0.1)
25
+ end
26
+ end
27
+
28
+ describe 'RESONANCE_DECAY' do
29
+ it 'equals 0.03' do
30
+ expect(described_class::RESONANCE_DECAY).to eq(0.03)
31
+ end
32
+ end
33
+
34
+ describe 'SIMULATION_CONFIDENCE_DEFAULT' do
35
+ it 'equals 0.5' do
36
+ expect(described_class::SIMULATION_CONFIDENCE_DEFAULT).to eq(0.5)
37
+ end
38
+ end
39
+
40
+ describe 'ACTION_TYPES' do
41
+ it 'contains exactly 8 types' do
42
+ expect(described_class::ACTION_TYPES.size).to eq(8)
43
+ end
44
+
45
+ it 'includes all expected types' do
46
+ expected = %i[movement communication decision emotional_expression
47
+ creative_act analytical_task social_interaction unknown]
48
+ expect(described_class::ACTION_TYPES).to match_array(expected)
49
+ end
50
+
51
+ it 'is frozen' do
52
+ expect(described_class::ACTION_TYPES).to be_frozen
53
+ end
54
+ end
55
+
56
+ describe 'RESONANCE_LABELS' do
57
+ it 'maps low values to :minimal' do
58
+ expect(described_class::RESONANCE_LABELS[(0.0..0.2)]).to eq(:minimal)
59
+ end
60
+
61
+ it 'maps high values to :deep' do
62
+ expect(described_class::RESONANCE_LABELS[(0.8..1.0)]).to eq(:deep)
63
+ end
64
+ end
65
+
66
+ describe 'CONFIDENCE_LABELS' do
67
+ it 'maps low values to :uncertain' do
68
+ expect(described_class::CONFIDENCE_LABELS[(0.0..0.2)]).to eq(:uncertain)
69
+ end
70
+
71
+ it 'maps high values to :certain' do
72
+ expect(described_class::CONFIDENCE_LABELS[(0.8..1.0)]).to eq(:certain)
73
+ end
74
+ end
75
+
76
+ describe 'EMPATHY_LABELS' do
77
+ it 'maps low values to :detached' do
78
+ expect(described_class::EMPATHY_LABELS[(0.0..0.2)]).to eq(:detached)
79
+ end
80
+
81
+ it 'maps high values to :immersed' do
82
+ expect(described_class::EMPATHY_LABELS[(0.8..1.0)]).to eq(:immersed)
83
+ end
84
+ end
85
+
86
+ describe '.label_for' do
87
+ it 'returns :minimal for 0.1' do
88
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 0.1)).to eq(:minimal)
89
+ end
90
+
91
+ it 'returns :low for 0.3' do
92
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 0.3)).to eq(:low)
93
+ end
94
+
95
+ it 'returns :moderate for 0.5' do
96
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 0.5)).to eq(:moderate)
97
+ end
98
+
99
+ it 'returns :high for 0.7' do
100
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 0.7)).to eq(:high)
101
+ end
102
+
103
+ it 'returns :deep for 0.9' do
104
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 0.9)).to eq(:deep)
105
+ end
106
+
107
+ it 'clamps values above 1.0' do
108
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, 1.5)).to eq(:deep)
109
+ end
110
+
111
+ it 'clamps values below 0.0' do
112
+ expect(described_class.label_for(described_class::RESONANCE_LABELS, -0.5)).to eq(:minimal)
113
+ end
114
+
115
+ it 'works with CONFIDENCE_LABELS' do
116
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.75)).to eq(:confident)
117
+ end
118
+
119
+ it 'works with EMPATHY_LABELS' do
120
+ expect(described_class.label_for(described_class::EMPATHY_LABELS, 0.65)).to eq(:resonant)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ let(:agent_id) { 'agent-alpha' }
7
+
8
+ def observe_event(action_type: :communication, valence: 0.5)
9
+ engine.observe(agent_id: agent_id, action_type: action_type, emotional_valence: valence)
10
+ end
11
+
12
+ describe '#initialize' do
13
+ it 'starts with empty events' do
14
+ expect(engine.events).to be_empty
15
+ end
16
+
17
+ it 'starts with empty simulations' do
18
+ expect(engine.simulations).to be_empty
19
+ end
20
+
21
+ it 'returns DEFAULT_RESONANCE for unknown agents' do
22
+ expect(engine.empathic_resonance('unknown-agent')).to eq(
23
+ Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::DEFAULT_RESONANCE
24
+ )
25
+ end
26
+ end
27
+
28
+ describe '#observe' do
29
+ it 'creates and stores a MirrorEvent' do
30
+ event = observe_event
31
+ expect(engine.events).to include(event)
32
+ end
33
+
34
+ it 'returns a MirrorEvent instance' do
35
+ expect(observe_event).to be_a(Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEvent)
36
+ end
37
+
38
+ it 'caps events at MAX_EVENTS' do
39
+ max = Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::MAX_EVENTS
40
+ (max + 5).times { observe_event }
41
+ expect(engine.events.size).to eq(max)
42
+ end
43
+ end
44
+
45
+ describe '#simulate' do
46
+ let(:event) { observe_event }
47
+
48
+ it 'returns a Simulation instance' do
49
+ sim = engine.simulate(event)
50
+ expect(sim).to be_a(Legion::Extensions::Agentic::Social::Mirror::Helpers::Simulation)
51
+ end
52
+
53
+ it 'links simulation to the event via event_id' do
54
+ sim = engine.simulate(event)
55
+ expect(sim.event_id).to eq(event.id)
56
+ end
57
+
58
+ it 'stores the simulation' do
59
+ sim = engine.simulate(event)
60
+ expect(engine.simulations).to include(sim)
61
+ end
62
+
63
+ it 'caps simulations at MAX_SIMULATIONS' do
64
+ max = Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::MAX_SIMULATIONS
65
+ (max + 5).times do
66
+ e = observe_event
67
+ engine.simulate(e)
68
+ end
69
+ expect(engine.simulations.size).to eq(max)
70
+ end
71
+
72
+ it 'uses provided confidence' do
73
+ sim = engine.simulate(event, confidence: 0.8)
74
+ expect(sim.confidence).to eq(0.8)
75
+ end
76
+ end
77
+
78
+ describe '#record_accuracy' do
79
+ it 'sets accuracy_score on the simulation' do
80
+ event = observe_event
81
+ sim = engine.simulate(event)
82
+ engine.record_accuracy(sim.id, 0.9)
83
+ expect(sim.accuracy_score).to eq(0.9)
84
+ end
85
+
86
+ it 'returns true when simulation found' do
87
+ event = observe_event
88
+ sim = engine.simulate(event)
89
+ expect(engine.record_accuracy(sim.id, 0.5)).to be(true)
90
+ end
91
+
92
+ it 'returns false when simulation not found' do
93
+ expect(engine.record_accuracy('nonexistent-id', 0.5)).to be(false)
94
+ end
95
+
96
+ it 'clamps accuracy to [0, 1]' do
97
+ event = observe_event
98
+ sim = engine.simulate(event)
99
+ engine.record_accuracy(sim.id, 1.5)
100
+ expect(sim.accuracy_score).to eq(1.0)
101
+ end
102
+ end
103
+
104
+ describe '#empathic_resonance' do
105
+ it 'returns DEFAULT_RESONANCE for new agents' do
106
+ expect(engine.empathic_resonance('new-agent')).to eq(0.5)
107
+ end
108
+
109
+ it 'reflects boosted resonance after boost_resonance' do
110
+ engine.boost_resonance(agent_id)
111
+ expect(engine.empathic_resonance(agent_id)).to be > 0.5
112
+ end
113
+ end
114
+
115
+ describe '#boost_resonance' do
116
+ it 'increases resonance by RESONANCE_BOOST' do
117
+ engine.boost_resonance(agent_id)
118
+ expected = (0.5 + Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::RESONANCE_BOOST).round(10)
119
+ expect(engine.empathic_resonance(agent_id)).to be_within(0.0001).of(expected)
120
+ end
121
+
122
+ it 'does not exceed 1.0' do
123
+ 10.times { engine.boost_resonance(agent_id) }
124
+ expect(engine.empathic_resonance(agent_id)).to be <= 1.0
125
+ end
126
+ end
127
+
128
+ describe '#decay_resonance' do
129
+ it 'decreases resonance by RESONANCE_DECAY' do
130
+ engine.boost_resonance(agent_id)
131
+ before = engine.empathic_resonance(agent_id)
132
+ engine.decay_resonance(agent_id)
133
+ expect(engine.empathic_resonance(agent_id)).to be < before
134
+ end
135
+
136
+ it 'does not go below 0.0' do
137
+ 20.times { engine.decay_resonance(agent_id) }
138
+ expect(engine.empathic_resonance(agent_id)).to be >= 0.0
139
+ end
140
+ end
141
+
142
+ describe '#decay_all_resonances' do
143
+ it 'decays resonance for all tracked agents' do
144
+ engine.boost_resonance('agent-1')
145
+ engine.boost_resonance('agent-2')
146
+ before_first = engine.empathic_resonance('agent-1')
147
+ before_second = engine.empathic_resonance('agent-2')
148
+ engine.decay_all_resonances
149
+ expect(engine.empathic_resonance('agent-1')).to be < before_first
150
+ expect(engine.empathic_resonance('agent-2')).to be < before_second
151
+ end
152
+ end
153
+
154
+ describe '#simulation_accuracy_for' do
155
+ it 'returns nil when no scored simulations' do
156
+ observe_event
157
+ expect(engine.simulation_accuracy_for(agent_id)).to be_nil
158
+ end
159
+
160
+ it 'returns average accuracy when scored' do
161
+ e1 = observe_event
162
+ e2 = observe_event
163
+ s1 = engine.simulate(e1)
164
+ s2 = engine.simulate(e2)
165
+ engine.record_accuracy(s1.id, 0.8)
166
+ engine.record_accuracy(s2.id, 0.6)
167
+ expect(engine.simulation_accuracy_for(agent_id)).to be_within(0.001).of(0.7)
168
+ end
169
+ end
170
+
171
+ describe '#events_for' do
172
+ it 'filters events by agent_id' do
173
+ observe_event
174
+ engine.observe(agent_id: 'other-agent', action_type: :movement)
175
+ expect(engine.events_for(agent_id).size).to eq(1)
176
+ expect(engine.events_for('other-agent').size).to eq(1)
177
+ end
178
+ end
179
+
180
+ describe '#simulations_for' do
181
+ it 'returns only simulations for a given agent' do
182
+ e = observe_event
183
+ engine.simulate(e)
184
+ other = engine.observe(agent_id: 'other', action_type: :movement)
185
+ engine.simulate(other)
186
+ expect(engine.simulations_for(agent_id).size).to eq(1)
187
+ end
188
+ end
189
+
190
+ describe '#simulation_history' do
191
+ it 'returns last N simulations as hashes' do
192
+ 3.times do
193
+ e = observe_event
194
+ engine.simulate(e)
195
+ end
196
+ history = engine.simulation_history(limit: 2)
197
+ expect(history.size).to eq(2)
198
+ expect(history.first).to be_a(Hash)
199
+ end
200
+
201
+ it 'defaults to 20 entries' do
202
+ 25.times do
203
+ e = observe_event
204
+ engine.simulate(e)
205
+ end
206
+ expect(engine.simulation_history.size).to eq(20)
207
+ end
208
+ end
209
+
210
+ describe '#known_agents' do
211
+ it 'returns agents with resonance entries' do
212
+ engine.boost_resonance('agent-a')
213
+ engine.boost_resonance('agent-b')
214
+ expect(engine.known_agents).to include('agent-a', 'agent-b')
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEvent do
4
+ let(:agent_id) { 'agent-001' }
5
+ let(:action_type) { :communication }
6
+ let(:context) { { message: 'hello', intent: 'greet' } }
7
+ let(:valence) { 0.7 }
8
+
9
+ subject(:event) do
10
+ described_class.new(
11
+ agent_id: agent_id,
12
+ action_type: action_type,
13
+ context: context,
14
+ emotional_valence: valence
15
+ )
16
+ end
17
+
18
+ describe '#initialize' do
19
+ it 'assigns a UUID id' do
20
+ expect(event.id).to match(/\A[0-9a-f-]{36}\z/)
21
+ end
22
+
23
+ it 'assigns agent_id' do
24
+ expect(event.agent_id).to eq('agent-001')
25
+ end
26
+
27
+ it 'normalizes known action_type' do
28
+ expect(event.action_type).to eq(:communication)
29
+ end
30
+
31
+ it 'normalizes unknown action_type to :unknown' do
32
+ e = described_class.new(agent_id: 'x', action_type: :nonexistent)
33
+ expect(e.action_type).to eq(:unknown)
34
+ end
35
+
36
+ it 'assigns string action_type by converting to symbol' do
37
+ e = described_class.new(agent_id: 'x', action_type: 'decision')
38
+ expect(e.action_type).to eq(:decision)
39
+ end
40
+
41
+ it 'assigns context hash' do
42
+ expect(event.context).to eq(context)
43
+ end
44
+
45
+ it 'treats non-hash context as empty hash' do
46
+ e = described_class.new(agent_id: 'x', action_type: :movement, context: 'not a hash')
47
+ expect(e.context).to eq({})
48
+ end
49
+
50
+ it 'clamps emotional_valence to [-1, 1]' do
51
+ e = described_class.new(agent_id: 'x', action_type: :movement, emotional_valence: 1.5)
52
+ expect(e.emotional_valence).to eq(1.0)
53
+ end
54
+
55
+ it 'clamps negative emotional_valence' do
56
+ e = described_class.new(agent_id: 'x', action_type: :movement, emotional_valence: -2.0)
57
+ expect(e.emotional_valence).to eq(-1.0)
58
+ end
59
+
60
+ it 'assigns observed_at as a Time' do
61
+ expect(event.observed_at).to be_a(Time)
62
+ end
63
+
64
+ it 'defaults context to empty hash' do
65
+ e = described_class.new(agent_id: 'x', action_type: :unknown)
66
+ expect(e.context).to eq({})
67
+ end
68
+
69
+ it 'defaults emotional_valence to 0.0' do
70
+ e = described_class.new(agent_id: 'x', action_type: :unknown)
71
+ expect(e.emotional_valence).to eq(0.0)
72
+ end
73
+ end
74
+
75
+ describe '#to_h' do
76
+ subject(:hash) { event.to_h }
77
+
78
+ it 'includes id' do
79
+ expect(hash[:id]).to eq(event.id)
80
+ end
81
+
82
+ it 'includes agent_id' do
83
+ expect(hash[:agent_id]).to eq('agent-001')
84
+ end
85
+
86
+ it 'includes action_type' do
87
+ expect(hash[:action_type]).to eq(:communication)
88
+ end
89
+
90
+ it 'includes context' do
91
+ expect(hash[:context]).to eq(context)
92
+ end
93
+
94
+ it 'includes emotional_valence' do
95
+ expect(hash[:emotional_valence]).to eq(0.7)
96
+ end
97
+
98
+ it 'includes observed_at' do
99
+ expect(hash[:observed_at]).to be_a(Time)
100
+ end
101
+ end
102
+ end