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,228 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::JointAttention::Runners::JointAttention do
4
+ let(:client) { Legion::Extensions::Agentic::Social::JointAttention::Client.new }
5
+
6
+ let!(:target_result) do
7
+ client.create_attention_target(name: 'shared-task', domain: :work, priority: 0.7, creator: 'agent-1')
8
+ end
9
+ let(:target_id) { target_result[:target][:id] }
10
+
11
+ describe '#create_attention_target' do
12
+ it 'returns success: true' do
13
+ expect(target_result[:success]).to be true
14
+ end
15
+
16
+ it 'returns target with all fields' do
17
+ t = target_result[:target]
18
+ expect(t).to include(:id, :name, :domain, :priority, :creator_agent_id, :created_at, :attendee_count)
19
+ end
20
+
21
+ it 'sets the name correctly' do
22
+ expect(target_result[:target][:name]).to eq('shared-task')
23
+ end
24
+
25
+ it 'uses default priority when not specified' do
26
+ result = client.create_attention_target(name: 'default-prio', domain: :x, creator: 'a')
27
+ const = Legion::Extensions::Agentic::Social::JointAttention::Helpers::Constants::DEFAULT_FOCUS
28
+ expect(result[:target][:priority]).to be_within(0.01).of(const)
29
+ end
30
+
31
+ it 'auto-joins the creator' do
32
+ expect(target_result[:target][:attendee_count]).to eq(1)
33
+ end
34
+ end
35
+
36
+ describe '#join_attention' do
37
+ it 'joins a second agent and returns success' do
38
+ result = client.join_attention(target_id: target_id, agent_id: 'agent-2')
39
+ expect(result[:success]).to be true
40
+ expect(result[:result]).to eq(:joined)
41
+ end
42
+
43
+ it 'returns success for already_attending' do
44
+ client.join_attention(target_id: target_id, agent_id: 'agent-2')
45
+ result = client.join_attention(target_id: target_id, agent_id: 'agent-2')
46
+ expect(result[:success]).to be true
47
+ expect(result[:result]).to eq(:already_attending)
48
+ end
49
+
50
+ it 'returns success: false for unknown target' do
51
+ result = client.join_attention(target_id: 'bogus', agent_id: 'agent-2')
52
+ expect(result[:success]).to be false
53
+ expect(result[:result]).to eq(:target_not_found)
54
+ end
55
+
56
+ it 'includes target_id and agent_id in response' do
57
+ result = client.join_attention(target_id: target_id, agent_id: 'agent-2')
58
+ expect(result[:target_id]).to eq(target_id)
59
+ expect(result[:agent_id]).to eq('agent-2')
60
+ end
61
+
62
+ it 'accepts a gaze keyword' do
63
+ result = client.join_attention(target_id: target_id, agent_id: 'agent-2', gaze: :deadline)
64
+ expect(result[:success]).to be true
65
+ end
66
+ end
67
+
68
+ describe '#leave_attention' do
69
+ before { client.join_attention(target_id: target_id, agent_id: 'agent-2') }
70
+
71
+ it 'removes the agent and returns success' do
72
+ result = client.leave_attention(target_id: target_id, agent_id: 'agent-2')
73
+ expect(result[:success]).to be true
74
+ expect(result[:result]).to eq(:removed)
75
+ end
76
+
77
+ it 'returns success: false for not_found' do
78
+ result = client.leave_attention(target_id: target_id, agent_id: 'never-joined')
79
+ expect(result[:success]).to be false
80
+ end
81
+
82
+ it 'returns success: false for unknown target' do
83
+ result = client.leave_attention(target_id: 'bogus', agent_id: 'agent-2')
84
+ expect(result[:success]).to be false
85
+ end
86
+ end
87
+
88
+ describe '#direct_attention' do
89
+ it 'directs to_agent to target and returns success' do
90
+ result = client.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: target_id)
91
+ expect(result[:success]).to be true
92
+ expect(result[:result]).to eq(:directed)
93
+ end
94
+
95
+ it 'returns success: false for unknown target' do
96
+ result = client.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: 'bogus')
97
+ expect(result[:success]).to be false
98
+ end
99
+
100
+ it 'returns success: false when referrer is not attending' do
101
+ result = client.direct_attention(from_agent: 'nobody', to_agent: 'agent-2', target_id: target_id)
102
+ expect(result[:success]).to be false
103
+ expect(result[:result]).to eq(:referrer_not_attending)
104
+ end
105
+
106
+ it 'includes from_agent and to_agent in response' do
107
+ result = client.direct_attention(from_agent: 'agent-1', to_agent: 'agent-2', target_id: target_id)
108
+ expect(result[:from_agent]).to eq('agent-1')
109
+ expect(result[:to_agent]).to eq('agent-2')
110
+ end
111
+ end
112
+
113
+ describe '#establish_mutual_awareness' do
114
+ before { client.join_attention(target_id: target_id, agent_id: 'agent-2') }
115
+
116
+ it 'establishes shared awareness and returns success' do
117
+ result = client.establish_mutual_awareness(target_id: target_id, agent_a: 'agent-1', agent_b: 'agent-2')
118
+ expect(result[:success]).to be true
119
+ expect(result[:result]).to eq(:established)
120
+ end
121
+
122
+ it 'returns success: false for unknown target' do
123
+ result = client.establish_mutual_awareness(target_id: 'bogus', agent_a: 'agent-1', agent_b: 'agent-2')
124
+ expect(result[:success]).to be false
125
+ end
126
+
127
+ it 'returns success: false when one agent is not attending' do
128
+ result = client.establish_mutual_awareness(target_id: target_id, agent_a: 'agent-1', agent_b: 'stranger')
129
+ expect(result[:success]).to be false
130
+ end
131
+
132
+ it 'includes agent_a and agent_b in response' do
133
+ result = client.establish_mutual_awareness(target_id: target_id, agent_a: 'agent-1', agent_b: 'agent-2')
134
+ expect(result[:agent_a]).to eq('agent-1')
135
+ expect(result[:agent_b]).to eq('agent-2')
136
+ end
137
+ end
138
+
139
+ describe '#update_gaze' do
140
+ it 'updates gaze direction and returns success' do
141
+ result = client.update_gaze(target_id: target_id, agent_id: 'agent-1', gaze: :risk)
142
+ expect(result[:success]).to be true
143
+ expect(result[:result]).to eq(:updated)
144
+ expect(result[:gaze]).to eq(:risk)
145
+ end
146
+
147
+ it 'returns success: false for unknown target' do
148
+ result = client.update_gaze(target_id: 'bogus', agent_id: 'agent-1', gaze: :risk)
149
+ expect(result[:success]).to be false
150
+ end
151
+
152
+ it 'returns success: false for unknown agent' do
153
+ result = client.update_gaze(target_id: target_id, agent_id: 'nobody', gaze: :risk)
154
+ expect(result[:success]).to be false
155
+ end
156
+ end
157
+
158
+ describe '#shared_focus' do
159
+ it 'returns shared targets between two agents' do
160
+ client.join_attention(target_id: target_id, agent_id: 'agent-2')
161
+ result = client.shared_focus(agent_a: 'agent-1', agent_b: 'agent-2')
162
+ expect(result[:success]).to be true
163
+ expect(result[:count]).to eq(1)
164
+ expect(result[:shared_targets].first[:id]).to eq(target_id)
165
+ end
166
+
167
+ it 'returns empty when no shared targets' do
168
+ result = client.shared_focus(agent_a: 'agent-1', agent_b: 'loner')
169
+ expect(result[:success]).to be true
170
+ expect(result[:count]).to eq(0)
171
+ expect(result[:shared_targets]).to be_empty
172
+ end
173
+
174
+ it 'includes agent_a and agent_b in response' do
175
+ result = client.shared_focus(agent_a: 'agent-1', agent_b: 'agent-2')
176
+ expect(result[:agent_a]).to eq('agent-1')
177
+ expect(result[:agent_b]).to eq('agent-2')
178
+ end
179
+ end
180
+
181
+ describe '#attention_targets_for' do
182
+ it 'returns targets for an agent' do
183
+ result = client.attention_targets_for(agent_id: 'agent-1')
184
+ expect(result[:success]).to be true
185
+ expect(result[:count]).to eq(1)
186
+ expect(result[:targets].first[:id]).to eq(target_id)
187
+ end
188
+
189
+ it 'returns empty for unknown agent' do
190
+ result = client.attention_targets_for(agent_id: 'nobody')
191
+ expect(result[:success]).to be true
192
+ expect(result[:count]).to eq(0)
193
+ end
194
+
195
+ it 'includes agent_id in response' do
196
+ result = client.attention_targets_for(agent_id: 'agent-1')
197
+ expect(result[:agent_id]).to eq('agent-1')
198
+ end
199
+ end
200
+
201
+ describe '#update_joint_attention' do
202
+ it 'returns success with stats' do
203
+ result = client.update_joint_attention
204
+ expect(result[:success]).to be true
205
+ expect(result).to have_key(:targets)
206
+ expect(result).to have_key(:agents)
207
+ expect(result).to have_key(:history)
208
+ end
209
+
210
+ it 'reflects current target count' do
211
+ result = client.update_joint_attention
212
+ expect(result[:targets]).to be >= 1
213
+ end
214
+ end
215
+
216
+ describe '#joint_attention_stats' do
217
+ it 'returns success with full stats hash' do
218
+ result = client.joint_attention_stats
219
+ expect(result[:success]).to be true
220
+ expect(result[:stats]).to include(:target_count, :agent_count, :history_size, :targets)
221
+ end
222
+
223
+ it 'stats reflect created targets' do
224
+ stats = client.joint_attention_stats
225
+ expect(stats[:stats][:target_count]).to eq(1)
226
+ end
227
+ end
228
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/social/mentalizing/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Social::Mentalizing::Client do
6
+ let(:client) { described_class.new }
7
+
8
+ it 'responds to all runner methods' do
9
+ expect(client).to respond_to(:attribute_belief)
10
+ expect(client).to respond_to(:project_belief)
11
+ expect(client).to respond_to(:check_alignment)
12
+ expect(client).to respond_to(:detect_false_belief)
13
+ expect(client).to respond_to(:beliefs_for_agent)
14
+ expect(client).to respond_to(:beliefs_about_agent)
15
+ expect(client).to respond_to(:recursive_belief_lookup)
16
+ expect(client).to respond_to(:update_mentalizing)
17
+ expect(client).to respond_to(:mentalizing_stats)
18
+ end
19
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mentalizing::Helpers::BeliefAttribution do
4
+ subject(:belief) do
5
+ described_class.new(
6
+ agent_id: 'alice',
7
+ subject: 'weather',
8
+ content: 'it will rain',
9
+ confidence: 0.7,
10
+ depth: 1
11
+ )
12
+ end
13
+
14
+ describe '#initialize' do
15
+ it 'assigns fields correctly' do
16
+ expect(belief.agent_id).to eq('alice')
17
+ expect(belief.subject).to eq('weather')
18
+ expect(belief.content).to eq('it will rain')
19
+ expect(belief.depth).to eq(1)
20
+ expect(belief.about_agent_id).to be_nil
21
+ end
22
+
23
+ it 'clamps confidence to 0.0..1.0' do
24
+ over = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 1.5)
25
+ under = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: -0.5)
26
+ expect(over.confidence).to eq(1.0)
27
+ expect(under.confidence).to eq(0.0)
28
+ end
29
+
30
+ it 'assigns a uuid id' do
31
+ expect(belief.id).to match(/\A[0-9a-f-]{36}\z/)
32
+ end
33
+
34
+ it 'records created_at' do
35
+ expect(belief.created_at).to be_a(Time)
36
+ end
37
+ end
38
+
39
+ describe '#decay' do
40
+ it 'reduces confidence by BELIEF_DECAY' do
41
+ before = belief.confidence
42
+ belief.decay
43
+ expect(belief.confidence).to be_within(0.001).of(before - Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::BELIEF_DECAY)
44
+ end
45
+
46
+ it 'does not drop below BELIEF_FLOOR' do
47
+ 20.times { belief.decay }
48
+ expect(belief.confidence).to be >= Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::BELIEF_FLOOR
49
+ end
50
+ end
51
+
52
+ describe '#reinforce' do
53
+ it 'increases confidence by CONFIDENCE_ALPHA by default' do
54
+ belief_low = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.3)
55
+ before = belief_low.confidence
56
+ belief_low.reinforce
57
+ expect(belief_low.confidence).to be_within(0.001).of(before + Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::CONFIDENCE_ALPHA)
58
+ end
59
+
60
+ it 'does not exceed 1.0' do
61
+ high = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.95)
62
+ high.reinforce(amount: 0.5)
63
+ expect(high.confidence).to eq(1.0)
64
+ end
65
+
66
+ it 'accepts custom amount' do
67
+ low = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.2)
68
+ low.reinforce(amount: 0.3)
69
+ expect(low.confidence).to be_within(0.001).of(0.5)
70
+ end
71
+ end
72
+
73
+ describe '#label' do
74
+ it 'returns :certain for high confidence' do
75
+ high = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.9)
76
+ expect(high.label).to eq(:certain)
77
+ end
78
+
79
+ it 'returns :confident for 0.6..0.8 range' do
80
+ mid = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.7)
81
+ expect(mid.label).to eq(:confident)
82
+ end
83
+
84
+ it 'returns :uncertain for 0.4..0.6 range' do
85
+ unc = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.5)
86
+ expect(unc.label).to eq(:uncertain)
87
+ end
88
+
89
+ it 'returns :speculative for 0.2..0.4 range' do
90
+ spec_b = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.3)
91
+ expect(spec_b.label).to eq(:speculative)
92
+ end
93
+
94
+ it 'returns :unknown for very low confidence' do
95
+ low = described_class.new(agent_id: 'a', subject: 's', content: 'c', confidence: 0.1)
96
+ expect(low.label).to eq(:unknown)
97
+ end
98
+ end
99
+
100
+ describe '#to_h' do
101
+ it 'returns a hash with all fields' do
102
+ h = belief.to_h
103
+ expect(h).to include(:id, :agent_id, :subject, :content, :confidence, :depth, :about_agent_id, :label, :created_at)
104
+ expect(h[:agent_id]).to eq('alice')
105
+ expect(h[:depth]).to eq(1)
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Social::Mentalizing::Helpers::MentalModel do
4
+ subject(:model) { described_class.new }
5
+
6
+ describe '#attribute_belief' do
7
+ it 'stores a belief and returns a BeliefAttribution' do
8
+ belief = model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
9
+ expect(belief).to be_a(Legion::Extensions::Agentic::Social::Mentalizing::Helpers::BeliefAttribution)
10
+ expect(belief.agent_id).to eq('alice')
11
+ end
12
+
13
+ it 'stores separate beliefs per agent' do
14
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
15
+ model.attribute_belief(agent_id: 'bob', subject: 'rain', content: 'no', confidence: 0.6)
16
+ expect(model.beliefs_for(agent_id: 'alice').size).to eq(1)
17
+ expect(model.beliefs_for(agent_id: 'bob').size).to eq(1)
18
+ end
19
+
20
+ it 'caps depth at MAX_RECURSION_DEPTH' do
21
+ belief = model.attribute_belief(agent_id: 'alice', subject: 's', content: 'c', confidence: 0.5, depth: 99)
22
+ expect(belief.depth).to eq(Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::MAX_RECURSION_DEPTH)
23
+ end
24
+
25
+ it 'stores about_agent_id when provided' do
26
+ belief = model.attribute_belief(agent_id: 'alice', subject: 'trust', content: 'bob trusts me', confidence: 0.7, about_agent_id: 'bob')
27
+ expect(belief.about_agent_id).to eq('bob')
28
+ end
29
+ end
30
+
31
+ describe '#beliefs_for' do
32
+ it 'returns empty array for unknown agent' do
33
+ expect(model.beliefs_for(agent_id: 'nobody')).to eq([])
34
+ end
35
+
36
+ it 'returns all beliefs for known agent' do
37
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
38
+ model.attribute_belief(agent_id: 'alice', subject: 'snow', content: 'no', confidence: 0.4)
39
+ expect(model.beliefs_for(agent_id: 'alice').size).to eq(2)
40
+ end
41
+ end
42
+
43
+ describe '#beliefs_about' do
44
+ it 'returns beliefs where about_agent_id matches' do
45
+ model.attribute_belief(agent_id: 'alice', subject: 'my_trust', content: 'low', confidence: 0.4, about_agent_id: 'me')
46
+ model.attribute_belief(agent_id: 'bob', subject: 'my_trust', content: 'high', confidence: 0.9, about_agent_id: 'me')
47
+ model.attribute_belief(agent_id: 'carol', subject: 'other', content: 'n/a', confidence: 0.5, about_agent_id: 'other')
48
+ result = model.beliefs_about(about_agent_id: 'me')
49
+ expect(result.size).to eq(2)
50
+ expect(result.map(&:agent_id)).to contain_exactly('alice', 'bob')
51
+ end
52
+
53
+ it 'returns empty array when no beliefs about agent' do
54
+ expect(model.beliefs_about(about_agent_id: 'nobody')).to eq([])
55
+ end
56
+ end
57
+
58
+ describe '#recursive_belief' do
59
+ it 'returns nil when no matching recursive belief exists' do
60
+ result = model.recursive_belief(agent_id: 'alice', about_agent_id: 'bob', subject: 'rain')
61
+ expect(result).to be_nil
62
+ end
63
+
64
+ it 'returns the highest-confidence matching belief' do
65
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'low', confidence: 0.4, about_agent_id: 'bob')
66
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'high', confidence: 0.9, about_agent_id: 'bob')
67
+ result = model.recursive_belief(agent_id: 'alice', about_agent_id: 'bob', subject: 'rain')
68
+ expect(result.content).to eq('high')
69
+ end
70
+ end
71
+
72
+ describe '#project_self' do
73
+ it 'creates a depth-1 belief attributed to :self' do
74
+ belief = model.project_self(subject: 'plan', own_belief: 0.8, other_agent_id: 'bob')
75
+ expect(belief.agent_id).to eq(:self)
76
+ expect(belief.depth).to eq(1)
77
+ expect(belief.about_agent_id).to eq('bob')
78
+ end
79
+
80
+ it 'discounts confidence by PROJECTION_DISCOUNT' do
81
+ discount = Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::PROJECTION_DISCOUNT
82
+ belief = model.project_self(subject: 'plan', own_belief: 1.0, other_agent_id: 'bob')
83
+ expect(belief.confidence).to be_within(0.001).of(discount)
84
+ end
85
+
86
+ it 'clamps discounted confidence to 1.0' do
87
+ belief = model.project_self(subject: 'plan', own_belief: 0.1, other_agent_id: 'bob')
88
+ expect(belief.confidence).to be >= 0.0
89
+ expect(belief.confidence).to be <= 1.0
90
+ end
91
+ end
92
+
93
+ describe '#alignment' do
94
+ it 'returns 0.0 when either agent has no beliefs on subject' do
95
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
96
+ expect(model.alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')).to eq(0.0)
97
+ end
98
+
99
+ it 'returns 1.0 when both agents have identical confidence' do
100
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.7)
101
+ model.attribute_belief(agent_id: 'bob', subject: 'rain', content: 'yes', confidence: 0.7)
102
+ expect(model.alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')).to be_within(0.001).of(1.0)
103
+ end
104
+
105
+ it 'returns lower score for divergent beliefs' do
106
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'high', confidence: 0.9)
107
+ model.attribute_belief(agent_id: 'bob', subject: 'rain', content: 'low', confidence: 0.1)
108
+ score = model.alignment(agent_a: 'alice', agent_b: 'bob', subject: 'rain')
109
+ expect(score).to be < 0.5
110
+ end
111
+ end
112
+
113
+ describe '#detect_false_belief' do
114
+ it 'returns false_belief: false when belief matches reality' do
115
+ model.attribute_belief(agent_id: 'alice', subject: 'weather', content: 'sunny', confidence: 0.8)
116
+ result = model.detect_false_belief(agent_id: 'alice', subject: 'weather', reality: 'sunny')
117
+ expect(result[:false_belief]).to be false
118
+ end
119
+
120
+ it 'returns false_belief: true when belief contradicts reality' do
121
+ model.attribute_belief(agent_id: 'alice', subject: 'weather', content: 'sunny', confidence: 0.8)
122
+ result = model.detect_false_belief(agent_id: 'alice', subject: 'weather', reality: 'raining')
123
+ expect(result[:false_belief]).to be true
124
+ expect(result[:held_belief]).to eq('sunny')
125
+ expect(result[:reality]).to eq('raining')
126
+ end
127
+
128
+ it 'returns no_beliefs reason when agent has no beliefs on subject' do
129
+ result = model.detect_false_belief(agent_id: 'nobody', subject: 'weather', reality: 'sunny')
130
+ expect(result[:false_belief]).to be false
131
+ expect(result[:reason]).to eq(:no_beliefs)
132
+ end
133
+ end
134
+
135
+ describe '#decay_all' do
136
+ it 'reduces confidence on all beliefs' do
137
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
138
+ before = model.beliefs_for(agent_id: 'alice').first.confidence
139
+ model.decay_all
140
+ after = model.beliefs_for(agent_id: 'alice').first&.confidence
141
+ expect(after).to be_nil.or be < before
142
+ end
143
+
144
+ it 'prunes beliefs at or below BELIEF_FLOOR' do
145
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes',
146
+ confidence: Legion::Extensions::Agentic::Social::Mentalizing::Helpers::Constants::BELIEF_FLOOR)
147
+ model.decay_all
148
+ expect(model.beliefs_for(agent_id: 'alice')).to be_empty
149
+ end
150
+ end
151
+
152
+ describe '#remove_agent' do
153
+ it 'removes all beliefs for the agent' do
154
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
155
+ model.remove_agent(agent_id: 'alice')
156
+ expect(model.beliefs_for(agent_id: 'alice')).to eq([])
157
+ end
158
+ end
159
+
160
+ describe '#agent_count and #belief_count' do
161
+ it 'tracks counts correctly' do
162
+ expect(model.agent_count).to eq(0)
163
+ expect(model.belief_count).to eq(0)
164
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
165
+ model.attribute_belief(agent_id: 'bob', subject: 'snow', content: 'no', confidence: 0.5)
166
+ expect(model.agent_count).to eq(2)
167
+ expect(model.belief_count).to eq(2)
168
+ end
169
+ end
170
+
171
+ describe '#to_h' do
172
+ it 'serializes all beliefs as hashes' do
173
+ model.attribute_belief(agent_id: 'alice', subject: 'rain', content: 'yes', confidence: 0.8)
174
+ h = model.to_h
175
+ expect(h).to have_key('alice')
176
+ expect(h['alice'].first).to include(:agent_id, :subject, :confidence)
177
+ end
178
+ end
179
+ end