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,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Social
7
+ module Conscience
8
+ module Helpers
9
+ class MoralStore
10
+ attr_reader :evaluator, :history, :dilemmas, :sensitivity_snapshots
11
+
12
+ def initialize(evaluator: nil)
13
+ @evaluator = evaluator || MoralEvaluator.new
14
+ @history = []
15
+ @dilemmas = []
16
+ @sensitivity_snapshots = []
17
+ @followed_count = 0
18
+ @overridden_count = 0
19
+ end
20
+
21
+ # Store a completed moral evaluation result
22
+ def record_evaluation(result)
23
+ @history << result
24
+ @history.shift while @history.size > Constants::MAX_MORAL_HISTORY
25
+
26
+ @dilemmas << result[:dilemma] if result[:dilemma]
27
+
28
+ snapshot_sensitivities(result[:verdict])
29
+
30
+ result
31
+ end
32
+
33
+ # Record whether the agent followed its moral verdict or overrode it.
34
+ # outcome: :followed | :overridden
35
+ def record_follow_through(verdict, outcome)
36
+ if outcome == :followed
37
+ @followed_count += 1
38
+ else
39
+ @overridden_count += 1
40
+ end
41
+
42
+ # Feed back into evaluator sensitivities
43
+ foundation_feedback(verdict, outcome)
44
+ end
45
+
46
+ # Ratio of evaluations where the agent followed its moral verdict
47
+ def consistency_score
48
+ total = @followed_count + @overridden_count
49
+ return 1.0 if total.zero?
50
+
51
+ (@followed_count.to_f / total).round(4)
52
+ end
53
+
54
+ # Current foundation sensitivities from the evaluator
55
+ def foundation_sensitivities
56
+ @evaluator.sensitivities.transform_values { |s| s.round(4) }
57
+ end
58
+
59
+ # Recent evaluations, newest last
60
+ def recent_evaluations(limit = 20)
61
+ @history.last(limit)
62
+ end
63
+
64
+ # Open dilemmas (not yet resolved)
65
+ def open_dilemmas
66
+ @dilemmas.last(20)
67
+ end
68
+
69
+ # Aggregate stats across all evaluations
70
+ def aggregate_stats
71
+ verdict_counts = Hash.new(0)
72
+ @history.each { |e| verdict_counts[e[:verdict]] += 1 }
73
+
74
+ {
75
+ total_evaluations: @history.size,
76
+ verdict_counts: verdict_counts,
77
+ dilemma_count: @dilemmas.size,
78
+ consistency_score: consistency_score,
79
+ followed_count: @followed_count,
80
+ overridden_count: @overridden_count,
81
+ foundation_sensitivities: foundation_sensitivities
82
+ }
83
+ end
84
+
85
+ private
86
+
87
+ def snapshot_sensitivities(verdict)
88
+ @sensitivity_snapshots << {
89
+ verdict: verdict,
90
+ sensitivities: @evaluator.sensitivities.dup,
91
+ at: Time.now.utc
92
+ }
93
+ @sensitivity_snapshots.shift while @sensitivity_snapshots.size > Constants::MAX_MORAL_HISTORY
94
+ end
95
+
96
+ def foundation_feedback(verdict, outcome)
97
+ # When an agent overrides a prohibited verdict, desensitize authority/sanctity
98
+ # When an agent follows a cautioned verdict, sensitize care/fairness
99
+ case [verdict, outcome]
100
+ when %i[prohibited overridden]
101
+ @evaluator.update_sensitivity(:care, -0.5)
102
+ @evaluator.update_sensitivity(:sanctity, -0.3)
103
+ when %i[cautioned followed]
104
+ @evaluator.update_sensitivity(:care, 0.8)
105
+ @evaluator.update_sensitivity(:fairness, 0.6)
106
+ when %i[permitted followed]
107
+ @evaluator.update_sensitivity(:liberty, 0.7)
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Social
7
+ module Conscience
8
+ module Runners
9
+ module Conscience
10
+ include Legion::Extensions::Helpers::Lex if Legion::Extensions.const_defined?(:Helpers) &&
11
+ Legion::Extensions::Helpers.const_defined?(:Lex)
12
+
13
+ # Full moral assessment of a proposed action.
14
+ # action: string or symbol describing what is about to happen
15
+ # context: hash of moral context signals (harm_to_others, consent_present, etc.)
16
+ def moral_evaluate(action:, context: {}, **)
17
+ result = moral_store.evaluator.evaluate(action: action, context: context)
18
+ moral_store.record_evaluation(result)
19
+
20
+ Legion::Logging.debug "[conscience] action=#{action} verdict=#{result[:verdict]} " \
21
+ "score=#{result[:weighted_score]} dilemma=#{result[:dilemma]&.dig(:type)}"
22
+
23
+ result
24
+ end
25
+
26
+ # Current moral sensitivities and consistency score
27
+ def moral_status(**)
28
+ stats = moral_store.aggregate_stats
29
+ sensitivities = moral_store.foundation_sensitivities
30
+
31
+ Legion::Logging.debug "[conscience] consistency=#{stats[:consistency_score]} " \
32
+ "evaluations=#{stats[:total_evaluations]}"
33
+
34
+ {
35
+ sensitivities: sensitivities,
36
+ consistency: stats[:consistency_score],
37
+ stats: stats
38
+ }
39
+ end
40
+
41
+ # Recent moral evaluation history
42
+ def moral_history(limit: 20, **)
43
+ recent = moral_store.recent_evaluations(limit)
44
+ Legion::Logging.debug "[conscience] history: #{recent.size} entries"
45
+
46
+ {
47
+ history: recent,
48
+ total: moral_store.history.size,
49
+ limit: limit
50
+ }
51
+ end
52
+
53
+ # Record whether the agent actually followed or overrode its moral verdict.
54
+ # outcome: :followed | :overridden
55
+ def update_moral_outcome(action:, outcome:, verdict: nil, **)
56
+ effective_verdict = verdict || infer_last_verdict(action)
57
+
58
+ moral_store.record_follow_through(effective_verdict, outcome)
59
+
60
+ Legion::Logging.debug "[conscience] follow_through action=#{action} " \
61
+ "verdict=#{effective_verdict} outcome=#{outcome} " \
62
+ "consistency=#{moral_store.consistency_score}"
63
+
64
+ {
65
+ action: action,
66
+ verdict: effective_verdict,
67
+ outcome: outcome,
68
+ consistency: moral_store.consistency_score
69
+ }
70
+ end
71
+
72
+ # List unresolved moral dilemmas (cases where foundations strongly disagreed)
73
+ def moral_dilemmas(**)
74
+ open = moral_store.open_dilemmas
75
+ Legion::Logging.debug "[conscience] dilemmas: #{open.size} open"
76
+
77
+ {
78
+ dilemmas: open,
79
+ count: open.size
80
+ }
81
+ end
82
+
83
+ # Aggregate moral reasoning stats
84
+ def conscience_stats(**)
85
+ stats = moral_store.aggregate_stats
86
+ Legion::Logging.debug '[conscience] stats'
87
+
88
+ stats.merge(
89
+ verdict_distribution: verdict_distribution(stats[:verdict_counts]),
90
+ foundation_weights: Helpers::Constants::MORAL_FOUNDATIONS.transform_values { |v| v[:weight] }
91
+ )
92
+ end
93
+
94
+ private
95
+
96
+ def moral_store
97
+ @moral_store ||= Helpers::MoralStore.new
98
+ end
99
+
100
+ def infer_last_verdict(action)
101
+ last = moral_store.history.reverse.find { |e| e[:action] == action }
102
+ last ? last[:verdict] : :permitted
103
+ end
104
+
105
+ def verdict_distribution(verdict_counts)
106
+ total = verdict_counts.values.sum.to_f
107
+ return {} if total.zero?
108
+
109
+ verdict_counts.transform_values { |count| (count / total).round(4) }
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Social
7
+ module Conscience
8
+ VERSION = '0.1.0'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/social/conscience/version'
4
+ require 'legion/extensions/agentic/social/conscience/helpers/constants'
5
+ require 'legion/extensions/agentic/social/conscience/helpers/moral_evaluator'
6
+ require 'legion/extensions/agentic/social/conscience/helpers/moral_store'
7
+ require 'legion/extensions/agentic/social/conscience/runners/conscience'
8
+ require 'legion/extensions/agentic/social/conscience/client'
9
+
10
+ module Legion
11
+ module Extensions
12
+ module Agentic
13
+ module Social
14
+ module Conscience
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/actors/every'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Social
9
+ module Consent
10
+ module Actor
11
+ class TierEvaluation < Legion::Extensions::Actors::Every
12
+ def runner_class
13
+ Legion::Extensions::Agentic::Social::Consent::Runners::Consent
14
+ end
15
+
16
+ def runner_function
17
+ 'evaluate_and_apply_tiers'
18
+ end
19
+
20
+ def time
21
+ 3600
22
+ end
23
+
24
+ def run_now?
25
+ false
26
+ end
27
+
28
+ def use_runner?
29
+ false
30
+ end
31
+
32
+ def check_subtask?
33
+ false
34
+ end
35
+
36
+ def generate_task?
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/social/consent/helpers/tiers'
4
+ require 'legion/extensions/agentic/social/consent/helpers/consent_map'
5
+ require 'legion/extensions/agentic/social/consent/runners/consent'
6
+
7
+ module Legion
8
+ module Extensions
9
+ module Agentic
10
+ module Social
11
+ module Consent
12
+ class Client
13
+ include Runners::Consent
14
+
15
+ def initialize(**)
16
+ @consent_map = Helpers::ConsentMap.new
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :consent_map
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,199 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Legion
6
+ module Extensions
7
+ module Agentic
8
+ module Social
9
+ module Consent
10
+ module Helpers
11
+ class ConsentMap
12
+ APPROVAL_TIMEOUT = 259_200 # 72 hours
13
+
14
+ attr_reader :domains
15
+
16
+ def initialize
17
+ @domains = Hash.new do |h, k|
18
+ h[k] = {
19
+ tier: Tiers::DEFAULT_TIER,
20
+ success_count: 0,
21
+ failure_count: 0,
22
+ total_actions: 0,
23
+ last_changed_at: nil,
24
+ history: [],
25
+ pending_tier: nil,
26
+ pending_since: nil,
27
+ pending_requested_by: nil
28
+ }
29
+ end
30
+ load_from_local
31
+ end
32
+
33
+ def get_tier(domain)
34
+ @domains[domain][:tier]
35
+ end
36
+
37
+ def set_tier(domain, tier)
38
+ return unless Tiers.valid_tier?(tier)
39
+
40
+ entry = @domains[domain]
41
+ old_tier = entry[:tier]
42
+ entry[:tier] = tier
43
+ entry[:last_changed_at] = Time.now.utc
44
+ entry[:history] << { from: old_tier, to: tier, at: Time.now.utc }
45
+ entry[:history].shift while entry[:history].size > 50
46
+ end
47
+
48
+ def record_outcome(domain, success:)
49
+ entry = @domains[domain]
50
+ entry[:total_actions] += 1
51
+ if success
52
+ entry[:success_count] += 1
53
+ else
54
+ entry[:failure_count] += 1
55
+ end
56
+ end
57
+
58
+ def success_rate(domain)
59
+ entry = @domains[domain]
60
+ return 0.0 if entry[:total_actions].zero?
61
+
62
+ entry[:success_count].to_f / entry[:total_actions]
63
+ end
64
+
65
+ def eligible_for_change?(domain)
66
+ entry = @domains[domain]
67
+ return false if entry[:total_actions] < Tiers::MIN_ACTIONS_TO_PROMOTE
68
+
69
+ if entry[:last_changed_at]
70
+ (Time.now.utc - entry[:last_changed_at]) >= Tiers::PROMOTION_COOLDOWN
71
+ else
72
+ true
73
+ end
74
+ end
75
+
76
+ def evaluate_promotion(domain)
77
+ return :ineligible unless eligible_for_change?(domain)
78
+
79
+ rate = success_rate(domain)
80
+ current = get_tier(domain)
81
+
82
+ if rate >= Tiers::PROMOTION_THRESHOLD
83
+ promoted = Tiers.promote(current)
84
+ return :already_max if promoted == current
85
+
86
+ :promote
87
+ elsif rate < Tiers::DEMOTION_THRESHOLD
88
+ demoted = Tiers.demote(current)
89
+ return :already_min if demoted == current
90
+
91
+ :demote
92
+ else
93
+ :maintain
94
+ end
95
+ end
96
+
97
+ def domain_count
98
+ @domains.size
99
+ end
100
+
101
+ def to_h
102
+ @domains.transform_values do |v|
103
+ { tier: v[:tier], success_rate: success_rate_from(v), total_actions: v[:total_actions],
104
+ pending_tier: v[:pending_tier], pending_since: v[:pending_since] }
105
+ end
106
+ end
107
+
108
+ def set_pending(domain, proposed_tier:, requested_by: 'system')
109
+ entry = @domains[domain]
110
+ entry[:pending_tier] = proposed_tier
111
+ entry[:pending_since] = Time.now
112
+ entry[:pending_requested_by] = requested_by
113
+ entry
114
+ end
115
+
116
+ def clear_pending(domain)
117
+ entry = @domains[domain]
118
+ entry[:pending_tier] = nil
119
+ entry[:pending_since] = nil
120
+ entry[:pending_requested_by] = nil
121
+ entry
122
+ end
123
+
124
+ def pending?(domain)
125
+ !@domains[domain][:pending_tier].nil?
126
+ end
127
+
128
+ def pending_expired?(domain, timeout: APPROVAL_TIMEOUT)
129
+ entry = @domains[domain]
130
+ return false unless entry[:pending_since]
131
+
132
+ Time.now - entry[:pending_since] > timeout
133
+ end
134
+
135
+ def save_to_local
136
+ return unless defined?(Legion::Data::Local) && Legion::Data::Local.connected?
137
+
138
+ dataset = Legion::Data::Local.connection[:consent_domains]
139
+ @domains.each do |domain_key, entry|
140
+ row = {
141
+ domain_key: domain_key,
142
+ tier: entry[:tier].to_s,
143
+ success_count: entry[:success_count],
144
+ failure_count: entry[:failure_count],
145
+ total_actions: entry[:total_actions],
146
+ last_changed_at: entry[:last_changed_at],
147
+ history: ::JSON.generate(entry[:history].map { |h| h.transform_values(&:to_s) })
148
+ }
149
+ existing = dataset.where(domain_key: domain_key).first
150
+ if existing
151
+ dataset.where(domain_key: domain_key).update(row.except(:domain_key))
152
+ else
153
+ dataset.insert(row)
154
+ end
155
+ end
156
+ rescue StandardError => e
157
+ Legion::Logging.warn "[consent] save_to_local failed: #{e.message}" if defined?(Legion::Logging)
158
+ end
159
+
160
+ def load_from_local
161
+ return unless defined?(Legion::Data::Local) && Legion::Data::Local.connected?
162
+
163
+ Legion::Data::Local.connection[:consent_domains].each do |row|
164
+ key = row[:domain_key]
165
+ history = begin
166
+ ::JSON.parse(row[:history] || '[]', symbolize_names: false).map do |h|
167
+ { from: h['from'].to_sym, to: h['to'].to_sym, at: h['at'] }
168
+ end
169
+ rescue StandardError
170
+ []
171
+ end
172
+
173
+ @domains[key] = {
174
+ tier: row[:tier].to_sym,
175
+ success_count: row[:success_count].to_i,
176
+ failure_count: row[:failure_count].to_i,
177
+ total_actions: row[:total_actions].to_i,
178
+ last_changed_at: row[:last_changed_at],
179
+ history: history
180
+ }
181
+ end
182
+ rescue StandardError => e
183
+ Legion::Logging.warn "[consent] load_from_local failed: #{e.message}" if defined?(Legion::Logging)
184
+ end
185
+
186
+ private
187
+
188
+ def success_rate_from(entry)
189
+ return 0.0 if entry[:total_actions].zero?
190
+
191
+ entry[:success_count].to_f / entry[:total_actions]
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Extensions
5
+ module Agentic
6
+ module Social
7
+ module Consent
8
+ module Helpers
9
+ module Tiers
10
+ # Four consent tiers (spec: consent-gradient-spec.md)
11
+ TIERS = %i[autonomous act_notify consult human_only].freeze
12
+
13
+ # Default starting tier for new domains
14
+ DEFAULT_TIER = :consult
15
+
16
+ # Thresholds for tier promotion/demotion
17
+ PROMOTION_THRESHOLD = 0.8 # success rate needed to promote
18
+ DEMOTION_THRESHOLD = 0.5 # success rate below which demotion occurs
19
+ MIN_ACTIONS_TO_PROMOTE = 10 # minimum actions before tier change
20
+ PROMOTION_COOLDOWN = 86_400 # seconds between tier changes (24h)
21
+
22
+ # Tier ordering (lower index = more autonomy)
23
+ TIER_ORDER = { autonomous: 0, act_notify: 1, consult: 2, human_only: 3 }.freeze
24
+
25
+ module_function
26
+
27
+ def valid_tier?(tier)
28
+ TIERS.include?(tier)
29
+ end
30
+
31
+ def more_autonomous?(tier_a, tier_b)
32
+ TIER_ORDER.fetch(tier_a, 99) < TIER_ORDER.fetch(tier_b, 99)
33
+ end
34
+
35
+ def promote(current_tier)
36
+ idx = TIER_ORDER.fetch(current_tier, 2)
37
+ return current_tier if idx.zero?
38
+
39
+ TIER_ORDER.key(idx - 1) || current_tier
40
+ end
41
+
42
+ def demote(current_tier)
43
+ idx = TIER_ORDER.fetch(current_tier, 2)
44
+ return current_tier if idx >= 3
45
+
46
+ TIER_ORDER.key(idx + 1) || current_tier
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ Sequel.migration do
4
+ change do
5
+ create_table(:consent_domains) do
6
+ primary_key :id
7
+ String :domain_key, null: false, unique: true, index: true
8
+ String :tier, null: false, default: 'consult'
9
+ Integer :success_count, default: 0
10
+ Integer :failure_count, default: 0
11
+ Integer :total_actions, default: 0
12
+ DateTime :last_changed_at
13
+ String :history, text: true
14
+ end
15
+ end
16
+ end