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,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Helpers::Simulation do
4
+ let(:event_id) { 'event-uuid-001' }
5
+ let(:outcome) { { action_type: :communication, predicted_intent: :inform_or_persuade } }
6
+
7
+ subject(:sim) do
8
+ described_class.new(
9
+ event_id: event_id,
10
+ simulated_outcome: outcome,
11
+ confidence: 0.7,
12
+ emotional_resonance: 0.6
13
+ )
14
+ end
15
+
16
+ describe '#initialize' do
17
+ it 'assigns a UUID id' do
18
+ expect(sim.id).to match(/\A[0-9a-f-]{36}\z/)
19
+ end
20
+
21
+ it 'assigns event_id' do
22
+ expect(sim.event_id).to eq(event_id)
23
+ end
24
+
25
+ it 'assigns simulated_outcome' do
26
+ expect(sim.simulated_outcome).to eq(outcome)
27
+ end
28
+
29
+ it 'clamps confidence to [0, 1]' do
30
+ s = described_class.new(event_id: 'x', simulated_outcome: {}, confidence: 1.5)
31
+ expect(s.confidence).to eq(1.0)
32
+ end
33
+
34
+ it 'clamps emotional_resonance to [0, 1]' do
35
+ s = described_class.new(event_id: 'x', simulated_outcome: {}, emotional_resonance: -0.3)
36
+ expect(s.emotional_resonance).to eq(0.0)
37
+ end
38
+
39
+ it 'defaults accuracy_score to nil' do
40
+ expect(sim.accuracy_score).to be_nil
41
+ end
42
+
43
+ it 'assigns simulated_at as a Time' do
44
+ expect(sim.simulated_at).to be_a(Time)
45
+ end
46
+
47
+ it 'uses SIMULATION_CONFIDENCE_DEFAULT when confidence not given' do
48
+ s = described_class.new(event_id: 'x', simulated_outcome: {})
49
+ expect(s.confidence).to eq(
50
+ Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::SIMULATION_CONFIDENCE_DEFAULT
51
+ )
52
+ end
53
+
54
+ it 'uses DEFAULT_RESONANCE when emotional_resonance not given' do
55
+ s = described_class.new(event_id: 'x', simulated_outcome: {})
56
+ expect(s.emotional_resonance).to eq(
57
+ Legion::Extensions::Agentic::Social::Mirror::Helpers::Constants::DEFAULT_RESONANCE
58
+ )
59
+ end
60
+ end
61
+
62
+ describe '#accuracy_score=' do
63
+ it 'allows setting accuracy_score' do
64
+ sim.accuracy_score = 0.85
65
+ expect(sim.accuracy_score).to eq(0.85)
66
+ end
67
+ end
68
+
69
+ describe '#to_h' do
70
+ subject(:hash) { sim.to_h }
71
+
72
+ it 'includes id' do
73
+ expect(hash[:id]).to eq(sim.id)
74
+ end
75
+
76
+ it 'includes event_id' do
77
+ expect(hash[:event_id]).to eq(event_id)
78
+ end
79
+
80
+ it 'includes simulated_outcome' do
81
+ expect(hash[:simulated_outcome]).to eq(outcome)
82
+ end
83
+
84
+ it 'includes confidence' do
85
+ expect(hash[:confidence]).to eq(0.7)
86
+ end
87
+
88
+ it 'includes emotional_resonance' do
89
+ expect(hash[:emotional_resonance]).to eq(0.6)
90
+ end
91
+
92
+ it 'includes simulated_at' do
93
+ expect(hash[:simulated_at]).to be_a(Time)
94
+ end
95
+
96
+ it 'includes accuracy_score as nil initially' do
97
+ expect(hash[:accuracy_score]).to be_nil
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Runners::Observe do
4
+ let(:engine) { Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEngine.new }
5
+
6
+ let(:host) do
7
+ obj = Object.new
8
+ obj.extend(described_class)
9
+ obj
10
+ end
11
+
12
+ describe '#observe_action' do
13
+ it 'returns success: true' do
14
+ result = host.observe_action(agent_id: 'agent-1', action_type: :communication, engine: engine)
15
+ expect(result[:success]).to be(true)
16
+ end
17
+
18
+ it 'returns the observed event hash' do
19
+ result = host.observe_action(agent_id: 'agent-1', action_type: :decision, engine: engine)
20
+ expect(result[:event]).to be_a(Hash)
21
+ expect(result[:event][:action_type]).to eq(:decision)
22
+ end
23
+
24
+ it 'returns a resonance_tier symbol' do
25
+ result = host.observe_action(agent_id: 'agent-1', action_type: :communication, engine: engine)
26
+ expect(result[:resonance_tier]).to be_a(Symbol)
27
+ end
28
+
29
+ it 'accepts unknown action_type gracefully' do
30
+ result = host.observe_action(agent_id: 'agent-1', action_type: :something_weird, engine: engine)
31
+ expect(result[:success]).to be(true)
32
+ expect(result[:event][:action_type]).to eq(:unknown)
33
+ end
34
+
35
+ it 'passes emotional_valence to the event' do
36
+ result = host.observe_action(
37
+ agent_id: 'agent-1', action_type: :emotional_expression,
38
+ emotional_valence: 0.8, engine: engine
39
+ )
40
+ expect(result[:event][:emotional_valence]).to eq(0.8)
41
+ end
42
+
43
+ it 'passes context to the event' do
44
+ ctx = { detail: 'test' }
45
+ result = host.observe_action(
46
+ agent_id: 'agent-1', action_type: :communication,
47
+ context: ctx, engine: engine
48
+ )
49
+ expect(result[:event][:context]).to eq(ctx)
50
+ end
51
+ end
52
+
53
+ describe '#list_events' do
54
+ before do
55
+ host.observe_action(agent_id: 'agent-1', action_type: :communication, engine: engine)
56
+ host.observe_action(agent_id: 'agent-2', action_type: :decision, engine: engine)
57
+ end
58
+
59
+ it 'returns all events when no agent_id given' do
60
+ result = host.list_events(engine: engine)
61
+ expect(result[:success]).to be(true)
62
+ expect(result[:count]).to eq(2)
63
+ end
64
+
65
+ it 'filters by agent_id' do
66
+ result = host.list_events(agent_id: 'agent-1', engine: engine)
67
+ expect(result[:count]).to eq(1)
68
+ expect(result[:events].first[:agent_id]).to eq('agent-1')
69
+ end
70
+
71
+ it 'returns empty list for unknown agent' do
72
+ result = host.list_events(agent_id: 'nobody', engine: engine)
73
+ expect(result[:count]).to eq(0)
74
+ expect(result[:events]).to be_empty
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Runners::Resonance do
4
+ let(:engine) { Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEngine.new }
5
+
6
+ let(:host) do
7
+ obj = Object.new
8
+ obj.extend(described_class)
9
+ obj
10
+ end
11
+
12
+ describe '#empathic_resonance' do
13
+ it 'returns success: true' do
14
+ result = host.empathic_resonance(agent_id: 'agent-1', engine: engine)
15
+ expect(result[:success]).to be(true)
16
+ end
17
+
18
+ it 'returns resonance value in [0, 1]' do
19
+ result = host.empathic_resonance(agent_id: 'agent-1', engine: engine)
20
+ expect(result[:resonance]).to be_between(0.0, 1.0)
21
+ end
22
+
23
+ it 'returns resonance_label and empathy_label symbols' do
24
+ result = host.empathic_resonance(agent_id: 'agent-1', engine: engine)
25
+ expect(result[:resonance_label]).to be_a(Symbol)
26
+ expect(result[:empathy_label]).to be_a(Symbol)
27
+ end
28
+
29
+ it 'returns accuracy as nil for new agent with no simulations' do
30
+ result = host.empathic_resonance(agent_id: 'brand-new', engine: engine)
31
+ expect(result[:accuracy]).to be_nil
32
+ end
33
+
34
+ it 'returns event_count and simulation_count' do
35
+ event = engine.observe(agent_id: 'agent-1', action_type: :communication)
36
+ engine.simulate(event)
37
+ result = host.empathic_resonance(agent_id: 'agent-1', engine: engine)
38
+ expect(result[:event_count]).to eq(1)
39
+ expect(result[:simulation_count]).to eq(1)
40
+ end
41
+
42
+ it 'returns :moderate label for DEFAULT_RESONANCE' do
43
+ result = host.empathic_resonance(agent_id: 'new-agent', engine: engine)
44
+ expect(result[:resonance_label]).to eq(:moderate)
45
+ end
46
+ end
47
+
48
+ describe '#decay_resonances' do
49
+ context 'with agent_id specified' do
50
+ before { engine.boost_resonance('agent-1') }
51
+
52
+ it 'returns success: true' do
53
+ result = host.decay_resonances(agent_id: 'agent-1', engine: engine)
54
+ expect(result[:success]).to be(true)
55
+ end
56
+
57
+ it 'returns resonance_after' do
58
+ before = engine.empathic_resonance('agent-1')
59
+ result = host.decay_resonances(agent_id: 'agent-1', engine: engine)
60
+ expect(result[:resonance_after]).to be < before
61
+ end
62
+
63
+ it 'returns agent_id in response' do
64
+ result = host.decay_resonances(agent_id: 'agent-1', engine: engine)
65
+ expect(result[:agent_id]).to eq('agent-1')
66
+ end
67
+ end
68
+
69
+ context 'without agent_id (global decay)' do
70
+ before do
71
+ engine.boost_resonance('agent-a')
72
+ engine.boost_resonance('agent-b')
73
+ end
74
+
75
+ it 'returns success: true' do
76
+ result = host.decay_resonances(engine: engine)
77
+ expect(result[:success]).to be(true)
78
+ end
79
+
80
+ it 'returns agents_decayed count' do
81
+ result = host.decay_resonances(engine: engine)
82
+ expect(result[:agents_decayed]).to eq(2)
83
+ end
84
+
85
+ it 'returns resonances hash' do
86
+ result = host.decay_resonances(engine: engine)
87
+ expect(result[:resonances]).to be_a(Hash)
88
+ expect(result[:resonances].keys).to include('agent-a', 'agent-b')
89
+ end
90
+ end
91
+ end
92
+
93
+ describe '#resonance_summary' do
94
+ before do
95
+ engine.boost_resonance('agent-x')
96
+ engine.boost_resonance('agent-y')
97
+ end
98
+
99
+ it 'returns success: true' do
100
+ result = host.resonance_summary(engine: engine)
101
+ expect(result[:success]).to be(true)
102
+ end
103
+
104
+ it 'lists all known agents' do
105
+ result = host.resonance_summary(engine: engine)
106
+ expect(result[:total]).to eq(2)
107
+ end
108
+
109
+ it 'includes empathy_label for each agent' do
110
+ result = host.resonance_summary(engine: engine)
111
+ result[:agents].each do |entry|
112
+ expect(entry[:empathy_label]).to be_a(Symbol)
113
+ end
114
+ end
115
+
116
+ it 'returns empty when no agents' do
117
+ fresh_engine = Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEngine.new
118
+ result = host.resonance_summary(engine: fresh_engine)
119
+ expect(result[:total]).to eq(0)
120
+ expect(result[:agents]).to be_empty
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mirror::Runners::Simulate do
4
+ let(:engine) { Legion::Extensions::Agentic::Social::Mirror::Helpers::MirrorEngine.new }
5
+
6
+ let(:host) do
7
+ obj = Object.new
8
+ obj.extend(described_class)
9
+ obj
10
+ end
11
+
12
+ let(:event) do
13
+ engine.observe(agent_id: 'agent-1', action_type: :communication, emotional_valence: 0.5)
14
+ end
15
+
16
+ describe '#simulate_action' do
17
+ it 'returns success: true for known event_id' do
18
+ result = host.simulate_action(event_id: event.id, engine: engine)
19
+ expect(result[:success]).to be(true)
20
+ end
21
+
22
+ it 'returns simulation hash' do
23
+ result = host.simulate_action(event_id: event.id, engine: engine)
24
+ expect(result[:simulation]).to be_a(Hash)
25
+ expect(result[:simulation][:event_id]).to eq(event.id)
26
+ end
27
+
28
+ it 'returns a confidence_tier symbol' do
29
+ result = host.simulate_action(event_id: event.id, engine: engine)
30
+ expect(result[:confidence_tier]).to be_a(Symbol)
31
+ end
32
+
33
+ it 'returns success: false for unknown event_id' do
34
+ result = host.simulate_action(event_id: 'nonexistent', engine: engine)
35
+ expect(result[:success]).to be(false)
36
+ expect(result[:error]).to eq('event not found')
37
+ end
38
+
39
+ it 'respects provided confidence' do
40
+ result = host.simulate_action(event_id: event.id, confidence: 0.9, engine: engine)
41
+ expect(result[:simulation][:confidence]).to eq(0.9)
42
+ end
43
+
44
+ it 'boosts agent resonance after simulation' do
45
+ before = engine.empathic_resonance('agent-1')
46
+ host.simulate_action(event_id: event.id, engine: engine)
47
+ expect(engine.empathic_resonance('agent-1')).to be > before
48
+ end
49
+ end
50
+
51
+ describe '#record_simulation_accuracy' do
52
+ let(:sim) { engine.simulate(event) }
53
+
54
+ it 'returns success: true when simulation found' do
55
+ result = host.record_simulation_accuracy(simulation_id: sim.id, accuracy: 0.8, engine: engine)
56
+ expect(result[:success]).to be(true)
57
+ end
58
+
59
+ it 'records the accuracy value' do
60
+ host.record_simulation_accuracy(simulation_id: sim.id, accuracy: 0.75, engine: engine)
61
+ expect(sim.accuracy_score).to eq(0.75)
62
+ end
63
+
64
+ it 'returns success: false for unknown simulation' do
65
+ result = host.record_simulation_accuracy(simulation_id: 'nope', accuracy: 0.5, engine: engine)
66
+ expect(result[:success]).to be(false)
67
+ expect(result[:error]).to eq('simulation not found')
68
+ end
69
+
70
+ it 'clamps accuracy to [0, 1]' do
71
+ result = host.record_simulation_accuracy(simulation_id: sim.id, accuracy: 1.5, engine: engine)
72
+ expect(result[:accuracy]).to eq(1.0)
73
+ end
74
+ end
75
+
76
+ describe '#simulation_history' do
77
+ before do
78
+ 3.times do
79
+ e = engine.observe(agent_id: 'agent-1', action_type: :decision)
80
+ engine.simulate(e)
81
+ end
82
+ end
83
+
84
+ it 'returns success: true' do
85
+ expect(host.simulation_history(engine: engine)[:success]).to be(true)
86
+ end
87
+
88
+ it 'returns simulation hashes' do
89
+ result = host.simulation_history(engine: engine)
90
+ expect(result[:simulations]).to all(be_a(Hash))
91
+ end
92
+
93
+ it 'respects limit parameter' do
94
+ result = host.simulation_history(limit: 2, engine: engine)
95
+ expect(result[:count]).to eq(2)
96
+ end
97
+
98
+ it 'returns all when limit exceeds available' do
99
+ result = host.simulation_history(limit: 100, engine: engine)
100
+ expect(result[:count]).to eq(3)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::MirrorSystem::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'includes Runners::Mirror' do
7
+ expect(described_class.ancestors).to include(Legion::Extensions::Agentic::Social::MirrorSystem::Runners::Mirror)
8
+ end
9
+
10
+ it 'responds to all runner methods' do
11
+ expect(client).to respond_to(:observe_behavior, :imitate_behavior, :report_imitation_outcome)
12
+ expect(client).to respond_to(:strongest_mirrors, :observations_for, :observations_in)
13
+ expect(client).to respond_to(:repertoire_status, :update_mirror, :mirror_stats)
14
+ end
15
+
16
+ it 'supports full mirror lifecycle' do
17
+ # Observe another agent deploying successfully
18
+ client.observe_behavior(agent_id: 'expert', action: :canary_deploy, domain: :production, outcome: :success)
19
+ client.observe_behavior(agent_id: 'expert', action: :canary_deploy, domain: :production, outcome: :success)
20
+
21
+ # Imitate the behavior
22
+ result = client.imitate_behavior(action: :canary_deploy, domain: :production)
23
+ expect(result[:imitated]).to be true
24
+ expect(result[:source]).to eq('expert')
25
+
26
+ # Report outcome
27
+ client.report_imitation_outcome(action: :canary_deploy, domain: :production, success_flag: true)
28
+
29
+ # Check repertoire
30
+ rep = client.repertoire_status
31
+ expect(rep[:size]).to eq(1)
32
+
33
+ # Tick
34
+ client.update_mirror
35
+
36
+ # Stats
37
+ stats = client.mirror_stats
38
+ expect(stats[:stats][:mirrored_agents]).to eq(1)
39
+ end
40
+ end
@@ -0,0 +1,144 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::MirrorSystem do
4
+ subject(:system) { described_class.new }
5
+
6
+ describe '#observe' do
7
+ it 'creates a new observation' do
8
+ obs = system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
9
+ expect(obs).to be_a(Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::ObservedBehavior)
10
+ expect(system.observation_count).to eq(1)
11
+ end
12
+
13
+ it 'increments count on repeated observation' do
14
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
15
+ obs = system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
16
+ expect(obs.observation_count).to eq(2)
17
+ expect(system.observation_count).to eq(1)
18
+ end
19
+
20
+ it 'boosts familiarity when behavior is in repertoire' do
21
+ system.add_to_repertoire(:deploy, :infra)
22
+ obs = system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
23
+ default = Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::DEFAULT_RESONANCE
24
+ boost = Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::FAMILIARITY_BOOST
25
+ expect(obs.resonance).to be_within(0.001).of(default + boost)
26
+ end
27
+
28
+ it 'tracks separate observations per agent' do
29
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
30
+ system.observe(agent_id: 'bob', action: :deploy, domain: :infra)
31
+ expect(system.observation_count).to eq(2)
32
+ end
33
+ end
34
+
35
+ describe '#imitate' do
36
+ it 'returns nil when no observations exist' do
37
+ expect(system.imitate(action: :deploy, domain: :infra)).to be_nil
38
+ end
39
+
40
+ it 'imitates observed behavior and adds to repertoire' do
41
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
42
+ result = system.imitate(action: :deploy, domain: :infra)
43
+ expect(result).not_to be_nil
44
+ expect(result[:observation].agent_id).to eq('alice')
45
+ expect(result[:fidelity]).to be_a(Float)
46
+ expect(system.repertoire_includes?(:deploy, :infra)).to be true
47
+ end
48
+
49
+ it 'filters by source_agent when specified' do
50
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
51
+ system.observe(agent_id: 'bob', action: :deploy, domain: :infra)
52
+ result = system.imitate(action: :deploy, domain: :infra, source_agent: 'alice')
53
+ expect(result[:observation].agent_id).to eq('alice')
54
+ end
55
+
56
+ it 'picks highest resonance observation' do
57
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
58
+ obs_bob = system.observe(agent_id: 'bob', action: :deploy, domain: :infra)
59
+ obs_bob.resonance = 0.9
60
+ result = system.imitate(action: :deploy, domain: :infra)
61
+ expect(result[:observation].agent_id).to eq('bob')
62
+ end
63
+ end
64
+
65
+ describe '#update_fidelity' do
66
+ it 'increases fidelity on success' do
67
+ before = system.fidelity_for(:deploy, :infra)
68
+ system.update_fidelity(action: :deploy, domain: :infra, success: true)
69
+ expect(system.fidelity_for(:deploy, :infra)).to be > before
70
+ end
71
+
72
+ it 'decreases fidelity on failure' do
73
+ before = system.fidelity_for(:deploy, :infra)
74
+ system.update_fidelity(action: :deploy, domain: :infra, success: false)
75
+ expect(system.fidelity_for(:deploy, :infra)).to be < before
76
+ end
77
+
78
+ it 'clamps to 0..1' do
79
+ 20.times { system.update_fidelity(action: :deploy, domain: :infra, success: true) }
80
+ expect(system.fidelity_for(:deploy, :infra)).to be <= 1.0
81
+ end
82
+ end
83
+
84
+ describe '#observations_for_agent' do
85
+ it 'returns observations by specific agent' do
86
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
87
+ system.observe(agent_id: 'alice', action: :test, domain: :infra)
88
+ system.observe(agent_id: 'bob', action: :deploy, domain: :infra)
89
+ expect(system.observations_for_agent('alice').size).to eq(2)
90
+ end
91
+ end
92
+
93
+ describe '#observations_in_domain' do
94
+ it 'returns observations in domain' do
95
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
96
+ system.observe(agent_id: 'alice', action: :test, domain: :code)
97
+ expect(system.observations_in_domain(:infra).size).to eq(1)
98
+ end
99
+ end
100
+
101
+ describe '#strongest_mirrors' do
102
+ it 'returns top N by resonance' do
103
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
104
+ obs = system.observe(agent_id: 'bob', action: :test, domain: :code)
105
+ obs.resonance = 0.9
106
+ top = system.strongest_mirrors(1)
107
+ expect(top.size).to eq(1)
108
+ expect(top.first.agent_id).to eq('bob')
109
+ end
110
+ end
111
+
112
+ describe '#decay_all' do
113
+ it 'decays all observations' do
114
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
115
+ before = system.observations.values.first.resonance
116
+ system.decay_all
117
+ after = system.observations.values.first&.resonance
118
+ expect(after).to be < before if after
119
+ end
120
+
121
+ it 'prunes faded observations' do
122
+ obs = system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
123
+ obs.resonance = Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::RESONANCE_FLOOR + 0.005
124
+ system.decay_all
125
+ expect(system.observation_count).to eq(0)
126
+ end
127
+ end
128
+
129
+ describe '#mirrored_agents' do
130
+ it 'lists unique observed agents' do
131
+ system.observe(agent_id: 'alice', action: :deploy, domain: :infra)
132
+ system.observe(agent_id: 'bob', action: :test, domain: :code)
133
+ system.observe(agent_id: 'alice', action: :test, domain: :code)
134
+ expect(system.mirrored_agents).to contain_exactly('alice', 'bob')
135
+ end
136
+ end
137
+
138
+ describe '#to_h' do
139
+ it 'returns stats hash' do
140
+ h = system.to_h
141
+ expect(h).to include(:observations, :repertoire_size, :mirrored_agents, :history_size)
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::ObservedBehavior do
4
+ subject(:obs) { described_class.new(agent_id: 'alice', action: :deploy, domain: :infra) }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns fields' do
8
+ expect(obs.agent_id).to eq('alice')
9
+ expect(obs.action).to eq(:deploy)
10
+ expect(obs.domain).to eq(:infra)
11
+ expect(obs.observation_count).to eq(1)
12
+ end
13
+
14
+ it 'assigns uuid and timestamp' do
15
+ expect(obs.id).to match(/\A[0-9a-f-]{36}\z/)
16
+ expect(obs.created_at).to be_a(Time)
17
+ end
18
+
19
+ it 'defaults resonance to DEFAULT_RESONANCE' do
20
+ expect(obs.resonance).to eq(Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::DEFAULT_RESONANCE)
21
+ end
22
+
23
+ it 'clamps resonance' do
24
+ high = described_class.new(agent_id: 'a', action: :x, domain: :d, resonance: 5.0)
25
+ expect(high.resonance).to eq(Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::MAX_RESONANCE)
26
+ end
27
+ end
28
+
29
+ describe '#observe_again' do
30
+ it 'increments observation count' do
31
+ obs.observe_again
32
+ expect(obs.observation_count).to eq(2)
33
+ end
34
+
35
+ it 'boosts resonance by REPETITION_BOOST' do
36
+ before = obs.resonance
37
+ obs.observe_again
38
+ expect(obs.resonance).to be > before
39
+ end
40
+ end
41
+
42
+ describe '#boost_familiarity' do
43
+ it 'boosts resonance by FAMILIARITY_BOOST' do
44
+ before = obs.resonance
45
+ obs.boost_familiarity
46
+ boost = Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::FAMILIARITY_BOOST
47
+ expect(obs.resonance).to be_within(0.001).of(before + boost)
48
+ end
49
+
50
+ it 'caps at MAX_RESONANCE' do
51
+ obs.resonance = 0.95
52
+ obs.boost_familiarity
53
+ expect(obs.resonance).to eq(Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::MAX_RESONANCE)
54
+ end
55
+ end
56
+
57
+ describe '#decay' do
58
+ it 'reduces resonance' do
59
+ before = obs.resonance
60
+ obs.decay
61
+ expect(obs.resonance).to be < before
62
+ end
63
+
64
+ it 'does not drop below RESONANCE_FLOOR' do
65
+ 50.times { obs.decay }
66
+ expect(obs.resonance).to be >= Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::RESONANCE_FLOOR
67
+ end
68
+ end
69
+
70
+ describe '#faded?' do
71
+ it 'returns false for strong observation' do
72
+ expect(obs.faded?).to be false
73
+ end
74
+
75
+ it 'returns true at floor' do
76
+ obs.resonance = Legion::Extensions::Agentic::Social::MirrorSystem::Helpers::Constants::RESONANCE_FLOOR
77
+ expect(obs.faded?).to be true
78
+ end
79
+ end
80
+
81
+ describe '#label' do
82
+ it 'returns :faint for default resonance' do
83
+ expect(obs.label).to eq(:faint)
84
+ end
85
+
86
+ it 'returns :strong_mirror for high resonance' do
87
+ obs.resonance = 0.9
88
+ expect(obs.label).to eq(:strong_mirror)
89
+ end
90
+ end
91
+
92
+ describe '#to_h' do
93
+ it 'returns hash with all fields' do
94
+ h = obs.to_h
95
+ expect(h).to include(:id, :agent_id, :action, :domain, :resonance, :observation_count, :label, :created_at)
96
+ end
97
+ end
98
+ end