lex-agentic-attention 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 (315) 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-attention.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/attention/arousal/client.rb +27 -0
  8. data/lib/legion/extensions/agentic/attention/arousal/helpers/arousal_model.rb +84 -0
  9. data/lib/legion/extensions/agentic/attention/arousal/helpers/constants.rb +44 -0
  10. data/lib/legion/extensions/agentic/attention/arousal/runners/arousal.rb +119 -0
  11. data/lib/legion/extensions/agentic/attention/arousal/version.rb +13 -0
  12. data/lib/legion/extensions/agentic/attention/arousal.rb +18 -0
  13. data/lib/legion/extensions/agentic/attention/blindspot/client.rb +19 -0
  14. data/lib/legion/extensions/agentic/attention/blindspot/helpers/blindspot.rb +98 -0
  15. data/lib/legion/extensions/agentic/attention/blindspot/helpers/blindspot_engine.rb +174 -0
  16. data/lib/legion/extensions/agentic/attention/blindspot/helpers/constants.rb +63 -0
  17. data/lib/legion/extensions/agentic/attention/blindspot/helpers/knowledge_boundary.rb +62 -0
  18. data/lib/legion/extensions/agentic/attention/blindspot/runners/cognitive_blindspot.rb +103 -0
  19. data/lib/legion/extensions/agentic/attention/blindspot/version.rb +13 -0
  20. data/lib/legion/extensions/agentic/attention/blindspot.rb +20 -0
  21. data/lib/legion/extensions/agentic/attention/blink/client.rb +19 -0
  22. data/lib/legion/extensions/agentic/attention/blink/helpers/blink_engine.rb +171 -0
  23. data/lib/legion/extensions/agentic/attention/blink/helpers/constants.rb +46 -0
  24. data/lib/legion/extensions/agentic/attention/blink/helpers/stimulus.rb +68 -0
  25. data/lib/legion/extensions/agentic/attention/blink/runners/attentional_blink.rb +75 -0
  26. data/lib/legion/extensions/agentic/attention/blink/version.rb +13 -0
  27. data/lib/legion/extensions/agentic/attention/blink.rb +19 -0
  28. data/lib/legion/extensions/agentic/attention/economy/client.rb +28 -0
  29. data/lib/legion/extensions/agentic/attention/economy/helpers/attention_budget.rb +143 -0
  30. data/lib/legion/extensions/agentic/attention/economy/helpers/constants.rb +38 -0
  31. data/lib/legion/extensions/agentic/attention/economy/helpers/demand.rb +72 -0
  32. data/lib/legion/extensions/agentic/attention/economy/runners/attention_economy.rb +90 -0
  33. data/lib/legion/extensions/agentic/attention/economy/version.rb +13 -0
  34. data/lib/legion/extensions/agentic/attention/economy.rb +19 -0
  35. data/lib/legion/extensions/agentic/attention/feature_binding/actors/decay.rb +45 -0
  36. data/lib/legion/extensions/agentic/attention/feature_binding/client.rb +29 -0
  37. data/lib/legion/extensions/agentic/attention/feature_binding/helpers/binding_field.rb +124 -0
  38. data/lib/legion/extensions/agentic/attention/feature_binding/helpers/bound_object.rb +89 -0
  39. data/lib/legion/extensions/agentic/attention/feature_binding/helpers/constants.rb +52 -0
  40. data/lib/legion/extensions/agentic/attention/feature_binding/helpers/feature.rb +52 -0
  41. data/lib/legion/extensions/agentic/attention/feature_binding/runners/feature_binding.rb +102 -0
  42. data/lib/legion/extensions/agentic/attention/feature_binding/version.rb +13 -0
  43. data/lib/legion/extensions/agentic/attention/feature_binding.rb +20 -0
  44. data/lib/legion/extensions/agentic/attention/focus/client.rb +30 -0
  45. data/lib/legion/extensions/agentic/attention/focus/helpers/constants.rb +38 -0
  46. data/lib/legion/extensions/agentic/attention/focus/helpers/focus.rb +78 -0
  47. data/lib/legion/extensions/agentic/attention/focus/helpers/focus_manager.rb +67 -0
  48. data/lib/legion/extensions/agentic/attention/focus/helpers/habituation.rb +61 -0
  49. data/lib/legion/extensions/agentic/attention/focus/runners/attention.rb +121 -0
  50. data/lib/legion/extensions/agentic/attention/focus/version.rb +13 -0
  51. data/lib/legion/extensions/agentic/attention/focus.rb +20 -0
  52. data/lib/legion/extensions/agentic/attention/kaleidoscope/client.rb +15 -0
  53. data/lib/legion/extensions/agentic/attention/kaleidoscope/helpers/constants.rb +48 -0
  54. data/lib/legion/extensions/agentic/attention/kaleidoscope/helpers/facet.rb +90 -0
  55. data/lib/legion/extensions/agentic/attention/kaleidoscope/helpers/kaleidoscope_engine.rb +142 -0
  56. data/lib/legion/extensions/agentic/attention/kaleidoscope/helpers/pattern.rb +110 -0
  57. data/lib/legion/extensions/agentic/attention/kaleidoscope/runners/cognitive_kaleidoscope.rb +91 -0
  58. data/lib/legion/extensions/agentic/attention/kaleidoscope/version.rb +13 -0
  59. data/lib/legion/extensions/agentic/attention/kaleidoscope.rb +22 -0
  60. data/lib/legion/extensions/agentic/attention/latent_inhibition/client.rb +28 -0
  61. data/lib/legion/extensions/agentic/attention/latent_inhibition/helpers/constants.rb +33 -0
  62. data/lib/legion/extensions/agentic/attention/latent_inhibition/helpers/inhibition_engine.rb +118 -0
  63. data/lib/legion/extensions/agentic/attention/latent_inhibition/helpers/stimulus_record.rb +70 -0
  64. data/lib/legion/extensions/agentic/attention/latent_inhibition/runners/latent_inhibition.rb +78 -0
  65. data/lib/legion/extensions/agentic/attention/latent_inhibition/version.rb +13 -0
  66. data/lib/legion/extensions/agentic/attention/latent_inhibition.rb +19 -0
  67. data/lib/legion/extensions/agentic/attention/lens/client.rb +29 -0
  68. data/lib/legion/extensions/agentic/attention/lens/helpers/constants.rb +58 -0
  69. data/lib/legion/extensions/agentic/attention/lens/helpers/lens.rb +99 -0
  70. data/lib/legion/extensions/agentic/attention/lens/helpers/lens_engine.rb +101 -0
  71. data/lib/legion/extensions/agentic/attention/lens/helpers/lens_stack.rb +134 -0
  72. data/lib/legion/extensions/agentic/attention/lens/runners/cognitive_lens.rb +90 -0
  73. data/lib/legion/extensions/agentic/attention/lens/version.rb +13 -0
  74. data/lib/legion/extensions/agentic/attention/lens.rb +22 -0
  75. data/lib/legion/extensions/agentic/attention/lighthouse/client.rb +25 -0
  76. data/lib/legion/extensions/agentic/attention/lighthouse/helpers/beacon.rb +76 -0
  77. data/lib/legion/extensions/agentic/attention/lighthouse/helpers/constants.rb +49 -0
  78. data/lib/legion/extensions/agentic/attention/lighthouse/helpers/fog.rb +74 -0
  79. data/lib/legion/extensions/agentic/attention/lighthouse/helpers/lighthouse_engine.rb +127 -0
  80. data/lib/legion/extensions/agentic/attention/lighthouse/runners/cognitive_lighthouse.rb +80 -0
  81. data/lib/legion/extensions/agentic/attention/lighthouse/version.rb +13 -0
  82. data/lib/legion/extensions/agentic/attention/lighthouse.rb +22 -0
  83. data/lib/legion/extensions/agentic/attention/priming/client.rb +21 -0
  84. data/lib/legion/extensions/agentic/attention/priming/helpers/activation_network.rb +130 -0
  85. data/lib/legion/extensions/agentic/attention/priming/helpers/concept_node.rb +92 -0
  86. data/lib/legion/extensions/agentic/attention/priming/helpers/constants.rb +54 -0
  87. data/lib/legion/extensions/agentic/attention/priming/runners/priming.rb +94 -0
  88. data/lib/legion/extensions/agentic/attention/priming/version.rb +13 -0
  89. data/lib/legion/extensions/agentic/attention/priming.rb +19 -0
  90. data/lib/legion/extensions/agentic/attention/prism/client.rb +26 -0
  91. data/lib/legion/extensions/agentic/attention/prism/helpers/beam.rb +169 -0
  92. data/lib/legion/extensions/agentic/attention/prism/helpers/constants.rb +46 -0
  93. data/lib/legion/extensions/agentic/attention/prism/helpers/prism_engine.rb +136 -0
  94. data/lib/legion/extensions/agentic/attention/prism/helpers/spectral_component.rb +72 -0
  95. data/lib/legion/extensions/agentic/attention/prism/runners/cognitive_prism.rb +79 -0
  96. data/lib/legion/extensions/agentic/attention/prism/version.rb +13 -0
  97. data/lib/legion/extensions/agentic/attention/prism.rb +22 -0
  98. data/lib/legion/extensions/agentic/attention/regulation/client.rb +19 -0
  99. data/lib/legion/extensions/agentic/attention/regulation/helpers/attention_controller.rb +157 -0
  100. data/lib/legion/extensions/agentic/attention/regulation/helpers/attention_target.rb +64 -0
  101. data/lib/legion/extensions/agentic/attention/regulation/helpers/constants.rb +41 -0
  102. data/lib/legion/extensions/agentic/attention/regulation/runners/attention_regulation.rb +88 -0
  103. data/lib/legion/extensions/agentic/attention/regulation/version.rb +13 -0
  104. data/lib/legion/extensions/agentic/attention/regulation.rb +20 -0
  105. data/lib/legion/extensions/agentic/attention/relevance_theory/helpers/client.rb +17 -0
  106. data/lib/legion/extensions/agentic/attention/relevance_theory/helpers/cognitive_input.rb +88 -0
  107. data/lib/legion/extensions/agentic/attention/relevance_theory/helpers/constants.rb +50 -0
  108. data/lib/legion/extensions/agentic/attention/relevance_theory/helpers/relevance_engine.rb +152 -0
  109. data/lib/legion/extensions/agentic/attention/relevance_theory/runners/relevance_theory.rb +98 -0
  110. data/lib/legion/extensions/agentic/attention/relevance_theory/version.rb +13 -0
  111. data/lib/legion/extensions/agentic/attention/relevance_theory.rb +19 -0
  112. data/lib/legion/extensions/agentic/attention/salience/client.rb +21 -0
  113. data/lib/legion/extensions/agentic/attention/salience/helpers/constants.rb +44 -0
  114. data/lib/legion/extensions/agentic/attention/salience/helpers/salience_map.rb +122 -0
  115. data/lib/legion/extensions/agentic/attention/salience/helpers/signal_integrator.rb +97 -0
  116. data/lib/legion/extensions/agentic/attention/salience/runners/salience.rb +70 -0
  117. data/lib/legion/extensions/agentic/attention/salience/version.rb +13 -0
  118. data/lib/legion/extensions/agentic/attention/salience.rb +19 -0
  119. data/lib/legion/extensions/agentic/attention/schema/actors/decay.rb +45 -0
  120. data/lib/legion/extensions/agentic/attention/schema/client.rb +28 -0
  121. data/lib/legion/extensions/agentic/attention/schema/helpers/attention_schema_model.rb +226 -0
  122. data/lib/legion/extensions/agentic/attention/schema/helpers/constants.rb +66 -0
  123. data/lib/legion/extensions/agentic/attention/schema/helpers/schema_item.rb +68 -0
  124. data/lib/legion/extensions/agentic/attention/schema/runners/attention_schema.rb +117 -0
  125. data/lib/legion/extensions/agentic/attention/schema/version.rb +13 -0
  126. data/lib/legion/extensions/agentic/attention/schema.rb +19 -0
  127. data/lib/legion/extensions/agentic/attention/sensory_gating/client.rb +15 -0
  128. data/lib/legion/extensions/agentic/attention/sensory_gating/helpers/constants.rb +44 -0
  129. data/lib/legion/extensions/agentic/attention/sensory_gating/helpers/gating_engine.rb +109 -0
  130. data/lib/legion/extensions/agentic/attention/sensory_gating/helpers/sensory_filter.rb +100 -0
  131. data/lib/legion/extensions/agentic/attention/sensory_gating/runners/sensory_gating.rb +73 -0
  132. data/lib/legion/extensions/agentic/attention/sensory_gating/version.rb +13 -0
  133. data/lib/legion/extensions/agentic/attention/sensory_gating.rb +19 -0
  134. data/lib/legion/extensions/agentic/attention/signal_detection/client.rb +28 -0
  135. data/lib/legion/extensions/agentic/attention/signal_detection/helpers/constants.rb +66 -0
  136. data/lib/legion/extensions/agentic/attention/signal_detection/helpers/detection_engine.rb +129 -0
  137. data/lib/legion/extensions/agentic/attention/signal_detection/helpers/detector.rb +136 -0
  138. data/lib/legion/extensions/agentic/attention/signal_detection/runners/signal_detection.rb +113 -0
  139. data/lib/legion/extensions/agentic/attention/signal_detection/version.rb +13 -0
  140. data/lib/legion/extensions/agentic/attention/signal_detection.rb +19 -0
  141. data/lib/legion/extensions/agentic/attention/spotlight/client.rb +29 -0
  142. data/lib/legion/extensions/agentic/attention/spotlight/helpers/attention_target.rb +61 -0
  143. data/lib/legion/extensions/agentic/attention/spotlight/helpers/constants.rb +44 -0
  144. data/lib/legion/extensions/agentic/attention/spotlight/helpers/spotlight.rb +78 -0
  145. data/lib/legion/extensions/agentic/attention/spotlight/helpers/spotlight_engine.rb +163 -0
  146. data/lib/legion/extensions/agentic/attention/spotlight/runners/attention_spotlight.rb +122 -0
  147. data/lib/legion/extensions/agentic/attention/spotlight/version.rb +13 -0
  148. data/lib/legion/extensions/agentic/attention/spotlight.rb +20 -0
  149. data/lib/legion/extensions/agentic/attention/subliminal/client.rb +19 -0
  150. data/lib/legion/extensions/agentic/attention/subliminal/helpers/constants.rb +74 -0
  151. data/lib/legion/extensions/agentic/attention/subliminal/helpers/influence_event.rb +44 -0
  152. data/lib/legion/extensions/agentic/attention/subliminal/helpers/subliminal_engine.rb +149 -0
  153. data/lib/legion/extensions/agentic/attention/subliminal/helpers/subliminal_trace.rb +101 -0
  154. data/lib/legion/extensions/agentic/attention/subliminal/runners/subliminal.rb +71 -0
  155. data/lib/legion/extensions/agentic/attention/subliminal/version.rb +13 -0
  156. data/lib/legion/extensions/agentic/attention/subliminal.rb +20 -0
  157. data/lib/legion/extensions/agentic/attention/surprise/client.rb +22 -0
  158. data/lib/legion/extensions/agentic/attention/surprise/helpers/constants.rb +35 -0
  159. data/lib/legion/extensions/agentic/attention/surprise/helpers/habituation_model.rb +62 -0
  160. data/lib/legion/extensions/agentic/attention/surprise/helpers/surprise_event.rb +43 -0
  161. data/lib/legion/extensions/agentic/attention/surprise/helpers/surprise_store.rb +74 -0
  162. data/lib/legion/extensions/agentic/attention/surprise/runners/surprise.rb +174 -0
  163. data/lib/legion/extensions/agentic/attention/surprise/version.rb +13 -0
  164. data/lib/legion/extensions/agentic/attention/surprise.rb +20 -0
  165. data/lib/legion/extensions/agentic/attention/switching/client.rb +19 -0
  166. data/lib/legion/extensions/agentic/attention/switching/helpers/constants.rb +64 -0
  167. data/lib/legion/extensions/agentic/attention/switching/helpers/switch_event.rb +60 -0
  168. data/lib/legion/extensions/agentic/attention/switching/helpers/switching_engine.rb +172 -0
  169. data/lib/legion/extensions/agentic/attention/switching/helpers/task_set.rb +91 -0
  170. data/lib/legion/extensions/agentic/attention/switching/runners/attention_switching.rb +92 -0
  171. data/lib/legion/extensions/agentic/attention/switching/version.rb +13 -0
  172. data/lib/legion/extensions/agentic/attention/switching.rb +20 -0
  173. data/lib/legion/extensions/agentic/attention/synesthesia/client.rb +29 -0
  174. data/lib/legion/extensions/agentic/attention/synesthesia/helpers/constants.rb +52 -0
  175. data/lib/legion/extensions/agentic/attention/synesthesia/helpers/sensory_mapping.rb +70 -0
  176. data/lib/legion/extensions/agentic/attention/synesthesia/helpers/synesthesia_engine.rb +177 -0
  177. data/lib/legion/extensions/agentic/attention/synesthesia/helpers/synesthetic_event.rb +49 -0
  178. data/lib/legion/extensions/agentic/attention/synesthesia/runners/cognitive_synesthesia.rb +83 -0
  179. data/lib/legion/extensions/agentic/attention/synesthesia/version.rb +13 -0
  180. data/lib/legion/extensions/agentic/attention/synesthesia.rb +20 -0
  181. data/lib/legion/extensions/agentic/attention/telescope/client.rb +15 -0
  182. data/lib/legion/extensions/agentic/attention/telescope/helpers/constants.rb +60 -0
  183. data/lib/legion/extensions/agentic/attention/telescope/helpers/observation.rb +68 -0
  184. data/lib/legion/extensions/agentic/attention/telescope/helpers/observatory_engine.rb +126 -0
  185. data/lib/legion/extensions/agentic/attention/telescope/helpers/telescope.rb +129 -0
  186. data/lib/legion/extensions/agentic/attention/telescope/runners/cognitive_telescope.rb +103 -0
  187. data/lib/legion/extensions/agentic/attention/telescope/version.rb +13 -0
  188. data/lib/legion/extensions/agentic/attention/telescope.rb +22 -0
  189. data/lib/legion/extensions/agentic/attention/version.rb +11 -0
  190. data/lib/legion/extensions/agentic/attention.rb +41 -0
  191. data/spec/legion/extensions/agentic/attention/arousal/client_spec.rb +42 -0
  192. data/spec/legion/extensions/agentic/attention/arousal/helpers/arousal_model_spec.rb +160 -0
  193. data/spec/legion/extensions/agentic/attention/arousal/helpers/constants_spec.rb +61 -0
  194. data/spec/legion/extensions/agentic/attention/arousal/runners/arousal_spec.rb +137 -0
  195. data/spec/legion/extensions/agentic/attention/blindspot/client_spec.rb +41 -0
  196. data/spec/legion/extensions/agentic/attention/blindspot/helpers/blindspot_engine_spec.rb +246 -0
  197. data/spec/legion/extensions/agentic/attention/blindspot/helpers/blindspot_spec.rb +204 -0
  198. data/spec/legion/extensions/agentic/attention/blindspot/helpers/constants_spec.rb +82 -0
  199. data/spec/legion/extensions/agentic/attention/blindspot/helpers/knowledge_boundary_spec.rb +104 -0
  200. data/spec/legion/extensions/agentic/attention/blindspot/runners/cognitive_blindspot_spec.rb +179 -0
  201. data/spec/legion/extensions/agentic/attention/blink/client_spec.rb +18 -0
  202. data/spec/legion/extensions/agentic/attention/blink/helpers/blink_engine_spec.rb +147 -0
  203. data/spec/legion/extensions/agentic/attention/blink/helpers/constants_spec.rb +27 -0
  204. data/spec/legion/extensions/agentic/attention/blink/helpers/stimulus_spec.rb +77 -0
  205. data/spec/legion/extensions/agentic/attention/blink/runners/attentional_blink_spec.rb +77 -0
  206. data/spec/legion/extensions/agentic/attention/economy/client_spec.rb +30 -0
  207. data/spec/legion/extensions/agentic/attention/economy/helpers/attention_budget_spec.rb +222 -0
  208. data/spec/legion/extensions/agentic/attention/economy/helpers/constants_spec.rb +112 -0
  209. data/spec/legion/extensions/agentic/attention/economy/helpers/demand_spec.rb +128 -0
  210. data/spec/legion/extensions/agentic/attention/economy/runners/attention_economy_spec.rb +163 -0
  211. data/spec/legion/extensions/agentic/attention/feature_binding/client_spec.rb +20 -0
  212. data/spec/legion/extensions/agentic/attention/feature_binding/helpers/binding_field_spec.rb +207 -0
  213. data/spec/legion/extensions/agentic/attention/feature_binding/helpers/bound_object_spec.rb +149 -0
  214. data/spec/legion/extensions/agentic/attention/feature_binding/helpers/feature_spec.rb +86 -0
  215. data/spec/legion/extensions/agentic/attention/feature_binding/runners/feature_binding_spec.rb +106 -0
  216. data/spec/legion/extensions/agentic/attention/focus/client_spec.rb +19 -0
  217. data/spec/legion/extensions/agentic/attention/focus/helpers/focus_manager_spec.rb +105 -0
  218. data/spec/legion/extensions/agentic/attention/focus/helpers/focus_spec.rb +148 -0
  219. data/spec/legion/extensions/agentic/attention/focus/helpers/habituation_spec.rb +97 -0
  220. data/spec/legion/extensions/agentic/attention/focus/runners/attention_spec.rb +134 -0
  221. data/spec/legion/extensions/agentic/attention/kaleidoscope/client_spec.rb +38 -0
  222. data/spec/legion/extensions/agentic/attention/kaleidoscope/helpers/constants_spec.rb +79 -0
  223. data/spec/legion/extensions/agentic/attention/kaleidoscope/helpers/facet_spec.rb +155 -0
  224. data/spec/legion/extensions/agentic/attention/kaleidoscope/helpers/kaleidoscope_engine_spec.rb +164 -0
  225. data/spec/legion/extensions/agentic/attention/kaleidoscope/helpers/pattern_spec.rb +157 -0
  226. data/spec/legion/extensions/agentic/attention/kaleidoscope/runners/cognitive_kaleidoscope_spec.rb +112 -0
  227. data/spec/legion/extensions/agentic/attention/latent_inhibition/client_spec.rb +49 -0
  228. data/spec/legion/extensions/agentic/attention/latent_inhibition/helpers/constants_spec.rb +57 -0
  229. data/spec/legion/extensions/agentic/attention/latent_inhibition/helpers/inhibition_engine_spec.rb +207 -0
  230. data/spec/legion/extensions/agentic/attention/latent_inhibition/helpers/stimulus_record_spec.rb +175 -0
  231. data/spec/legion/extensions/agentic/attention/latent_inhibition/runners/latent_inhibition_spec.rb +148 -0
  232. data/spec/legion/extensions/agentic/attention/lens/client_spec.rb +64 -0
  233. data/spec/legion/extensions/agentic/attention/lens/helpers/constants_spec.rb +91 -0
  234. data/spec/legion/extensions/agentic/attention/lens/helpers/lens_engine_spec.rb +158 -0
  235. data/spec/legion/extensions/agentic/attention/lens/helpers/lens_spec.rb +222 -0
  236. data/spec/legion/extensions/agentic/attention/lens/helpers/lens_stack_spec.rb +179 -0
  237. data/spec/legion/extensions/agentic/attention/lens/runners/cognitive_lens_spec.rb +182 -0
  238. data/spec/legion/extensions/agentic/attention/lighthouse/client_spec.rb +103 -0
  239. data/spec/legion/extensions/agentic/attention/lighthouse/helpers/beacon_spec.rb +170 -0
  240. data/spec/legion/extensions/agentic/attention/lighthouse/helpers/constants_spec.rb +94 -0
  241. data/spec/legion/extensions/agentic/attention/lighthouse/helpers/fog_spec.rb +166 -0
  242. data/spec/legion/extensions/agentic/attention/lighthouse/helpers/lighthouse_engine_spec.rb +238 -0
  243. data/spec/legion/extensions/agentic/attention/lighthouse/runners/cognitive_lighthouse_spec.rb +182 -0
  244. data/spec/legion/extensions/agentic/attention/priming/client_spec.rb +80 -0
  245. data/spec/legion/extensions/agentic/attention/priming/helpers/activation_network_spec.rb +176 -0
  246. data/spec/legion/extensions/agentic/attention/priming/helpers/concept_node_spec.rb +165 -0
  247. data/spec/legion/extensions/agentic/attention/priming/helpers/constants_spec.rb +51 -0
  248. data/spec/legion/extensions/agentic/attention/priming/runners/priming_spec.rb +141 -0
  249. data/spec/legion/extensions/agentic/attention/prism/client_spec.rb +86 -0
  250. data/spec/legion/extensions/agentic/attention/prism/helpers/beam_spec.rb +182 -0
  251. data/spec/legion/extensions/agentic/attention/prism/helpers/constants_spec.rb +93 -0
  252. data/spec/legion/extensions/agentic/attention/prism/helpers/prism_engine_spec.rb +253 -0
  253. data/spec/legion/extensions/agentic/attention/prism/helpers/spectral_component_spec.rb +171 -0
  254. data/spec/legion/extensions/agentic/attention/prism/runners/cognitive_prism_spec.rb +132 -0
  255. data/spec/legion/extensions/agentic/attention/regulation/client_spec.rb +58 -0
  256. data/spec/legion/extensions/agentic/attention/regulation/helpers/attention_controller_spec.rb +295 -0
  257. data/spec/legion/extensions/agentic/attention/regulation/helpers/attention_target_spec.rb +122 -0
  258. data/spec/legion/extensions/agentic/attention/regulation/runners/attention_regulation_spec.rb +147 -0
  259. data/spec/legion/extensions/agentic/attention/relevance_theory/helpers/cognitive_input_spec.rb +121 -0
  260. data/spec/legion/extensions/agentic/attention/relevance_theory/helpers/relevance_engine_spec.rb +149 -0
  261. data/spec/legion/extensions/agentic/attention/relevance_theory/relevance_theory_spec.rb +11 -0
  262. data/spec/legion/extensions/agentic/attention/relevance_theory/runners/relevance_theory_spec.rb +86 -0
  263. data/spec/legion/extensions/agentic/attention/salience/client_spec.rb +60 -0
  264. data/spec/legion/extensions/agentic/attention/salience/helpers/constants_spec.rb +100 -0
  265. data/spec/legion/extensions/agentic/attention/salience/helpers/salience_map_spec.rb +189 -0
  266. data/spec/legion/extensions/agentic/attention/salience/helpers/signal_integrator_spec.rb +149 -0
  267. data/spec/legion/extensions/agentic/attention/salience/runners/salience_spec.rb +143 -0
  268. data/spec/legion/extensions/agentic/attention/schema/client_spec.rb +47 -0
  269. data/spec/legion/extensions/agentic/attention/schema/helpers/attention_schema_model_spec.rb +219 -0
  270. data/spec/legion/extensions/agentic/attention/schema/helpers/schema_item_spec.rb +114 -0
  271. data/spec/legion/extensions/agentic/attention/schema/runners/attention_schema_spec.rb +185 -0
  272. data/spec/legion/extensions/agentic/attention/sensory_gating/helpers/gating_engine_spec.rb +112 -0
  273. data/spec/legion/extensions/agentic/attention/sensory_gating/helpers/sensory_filter_spec.rb +121 -0
  274. data/spec/legion/extensions/agentic/attention/sensory_gating/runners/sensory_gating_spec.rb +61 -0
  275. data/spec/legion/extensions/agentic/attention/signal_detection/client_spec.rb +20 -0
  276. data/spec/legion/extensions/agentic/attention/signal_detection/helpers/constants_spec.rb +85 -0
  277. data/spec/legion/extensions/agentic/attention/signal_detection/helpers/detection_engine_spec.rb +143 -0
  278. data/spec/legion/extensions/agentic/attention/signal_detection/helpers/detector_spec.rb +179 -0
  279. data/spec/legion/extensions/agentic/attention/signal_detection/runners/signal_detection_spec.rb +151 -0
  280. data/spec/legion/extensions/agentic/attention/spotlight/client_spec.rb +31 -0
  281. data/spec/legion/extensions/agentic/attention/spotlight/helpers/attention_target_spec.rb +121 -0
  282. data/spec/legion/extensions/agentic/attention/spotlight/helpers/constants_spec.rb +82 -0
  283. data/spec/legion/extensions/agentic/attention/spotlight/helpers/spotlight_engine_spec.rb +275 -0
  284. data/spec/legion/extensions/agentic/attention/spotlight/helpers/spotlight_spec.rb +196 -0
  285. data/spec/legion/extensions/agentic/attention/spotlight/runners/attention_spotlight_spec.rb +251 -0
  286. data/spec/legion/extensions/agentic/attention/subliminal/client_spec.rb +21 -0
  287. data/spec/legion/extensions/agentic/attention/subliminal/helpers/influence_event_spec.rb +58 -0
  288. data/spec/legion/extensions/agentic/attention/subliminal/helpers/subliminal_engine_spec.rb +161 -0
  289. data/spec/legion/extensions/agentic/attention/subliminal/helpers/subliminal_trace_spec.rb +168 -0
  290. data/spec/legion/extensions/agentic/attention/subliminal/runners_spec.rb +78 -0
  291. data/spec/legion/extensions/agentic/attention/subliminal/subliminal_spec.rb +7 -0
  292. data/spec/legion/extensions/agentic/attention/surprise/client_spec.rb +122 -0
  293. data/spec/legion/extensions/agentic/attention/surprise/helpers/constants_spec.rb +112 -0
  294. data/spec/legion/extensions/agentic/attention/surprise/helpers/habituation_model_spec.rb +127 -0
  295. data/spec/legion/extensions/agentic/attention/surprise/helpers/surprise_event_spec.rb +102 -0
  296. data/spec/legion/extensions/agentic/attention/surprise/helpers/surprise_store_spec.rb +171 -0
  297. data/spec/legion/extensions/agentic/attention/surprise/runners/surprise_spec.rb +266 -0
  298. data/spec/legion/extensions/agentic/attention/switching/attention_switching_spec.rb +7 -0
  299. data/spec/legion/extensions/agentic/attention/switching/helpers/switch_event_spec.rb +74 -0
  300. data/spec/legion/extensions/agentic/attention/switching/helpers/switching_engine_spec.rb +164 -0
  301. data/spec/legion/extensions/agentic/attention/switching/helpers/task_set_spec.rb +134 -0
  302. data/spec/legion/extensions/agentic/attention/synesthesia/client_spec.rb +57 -0
  303. data/spec/legion/extensions/agentic/attention/synesthesia/helpers/constants_spec.rb +89 -0
  304. data/spec/legion/extensions/agentic/attention/synesthesia/helpers/sensory_mapping_spec.rb +135 -0
  305. data/spec/legion/extensions/agentic/attention/synesthesia/helpers/synesthesia_engine_spec.rb +260 -0
  306. data/spec/legion/extensions/agentic/attention/synesthesia/helpers/synesthetic_event_spec.rb +83 -0
  307. data/spec/legion/extensions/agentic/attention/synesthesia/runners/cognitive_synesthesia_spec.rb +192 -0
  308. data/spec/legion/extensions/agentic/attention/telescope/client_spec.rb +30 -0
  309. data/spec/legion/extensions/agentic/attention/telescope/helpers/constants_spec.rb +108 -0
  310. data/spec/legion/extensions/agentic/attention/telescope/helpers/observation_spec.rb +138 -0
  311. data/spec/legion/extensions/agentic/attention/telescope/helpers/observatory_engine_spec.rb +197 -0
  312. data/spec/legion/extensions/agentic/attention/telescope/helpers/telescope_spec.rb +251 -0
  313. data/spec/legion/extensions/agentic/attention/telescope/runners/cognitive_telescope_spec.rb +191 -0
  314. data/spec/spec_helper.rb +46 -0
  315. metadata +399 -0
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Feature do
4
+ subject(:feature) { described_class.new(id: 'f:red', dimension: :color, value: :red) }
5
+
6
+ let(:constants) { Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Constants }
7
+
8
+ describe '#initialize' do
9
+ it 'sets id, dimension, and value' do
10
+ expect(feature.id).to eq('f:red')
11
+ expect(feature.dimension).to eq(:color)
12
+ expect(feature.value).to eq(:red)
13
+ end
14
+
15
+ it 'defaults source to :perception' do
16
+ expect(feature.source).to eq(:perception)
17
+ end
18
+
19
+ it 'defaults salience to 0.5' do
20
+ expect(feature.salience).to eq(0.5)
21
+ end
22
+
23
+ it 'records detected_at' do
24
+ expect(feature.detected_at).to be_a(Time)
25
+ end
26
+
27
+ it 'clamps salience to [0, 1]' do
28
+ high = described_class.new(id: 'h', dimension: :color, value: :x, salience: 5.0)
29
+ low = described_class.new(id: 'l', dimension: :color, value: :x, salience: -1.0)
30
+ expect(high.salience).to eq(1.0)
31
+ expect(low.salience).to eq(0.0)
32
+ end
33
+
34
+ it 'accepts custom source' do
35
+ f = described_class.new(id: 'x', dimension: :shape, value: :circle, source: :memory)
36
+ expect(f.source).to eq(:memory)
37
+ end
38
+ end
39
+
40
+ describe '#salient?' do
41
+ it 'returns true when above floor' do
42
+ expect(feature.salient?).to be true
43
+ end
44
+
45
+ it 'returns false at zero salience' do
46
+ feature.salience = 0.0
47
+ expect(feature.salient?).to be false
48
+ end
49
+ end
50
+
51
+ describe '#decay' do
52
+ it 'reduces salience' do
53
+ before = feature.salience
54
+ feature.decay
55
+ expect(feature.salience).to be < before
56
+ end
57
+
58
+ it 'does not go below zero' do
59
+ 100.times { feature.decay }
60
+ expect(feature.salience).to be >= 0.0
61
+ end
62
+ end
63
+
64
+ describe '#faded?' do
65
+ it 'returns false for a new feature' do
66
+ expect(feature.faded?).to be false
67
+ end
68
+
69
+ it 'returns true when salience at floor' do
70
+ feature.salience = constants::FEATURE_SALIENCE_FLOOR
71
+ expect(feature.faded?).to be true
72
+ end
73
+ end
74
+
75
+ describe '#to_h' do
76
+ it 'returns expected keys' do
77
+ h = feature.to_h
78
+ expect(h).to include(:id, :dimension, :value, :source, :salience, :detected_at)
79
+ end
80
+
81
+ it 'rounds salience' do
82
+ feature.salience = 0.12345
83
+ expect(feature.to_h[:salience]).to eq(0.1235)
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/feature_binding/runners/feature_binding'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::FeatureBinding::Runners::FeatureBinding do
6
+ let(:field) { Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::BindingField.new }
7
+ let(:host) do
8
+ obj = Object.new
9
+ obj.extend(described_class)
10
+ obj.instance_variable_set(:@field, field)
11
+ obj
12
+ end
13
+
14
+ describe '#register_feature' do
15
+ it 'registers successfully' do
16
+ result = host.register_feature(id: 'f:red', dimension: :color, value: :red)
17
+ expect(result[:success]).to be true
18
+ expect(result[:feature][:id]).to eq('f:red')
19
+ end
20
+
21
+ it 'returns failure at limit' do
22
+ Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Constants::MAX_FEATURES.times do |i|
23
+ host.register_feature(id: "f:#{i}", dimension: :color, value: i)
24
+ end
25
+ result = host.register_feature(id: 'f:overflow', dimension: :color, value: :x)
26
+ expect(result[:success]).to be false
27
+ end
28
+ end
29
+
30
+ describe '#bind_features' do
31
+ before do
32
+ host.register_feature(id: 'f:red', dimension: :color, value: :red)
33
+ host.register_feature(id: 'f:circle', dimension: :shape, value: :circle)
34
+ end
35
+
36
+ it 'binds features into an object' do
37
+ result = host.bind_features(feature_ids: %w[f:red f:circle])
38
+ expect(result[:success]).to be true
39
+ expect(result[:object][:features]).to eq(%w[f:red f:circle])
40
+ end
41
+
42
+ it 'fails with insufficient features' do
43
+ result = host.bind_features(feature_ids: %w[f:red])
44
+ expect(result[:success]).to be false
45
+ end
46
+ end
47
+
48
+ describe '#attend_object' do
49
+ it 'strengthens and confirms' do
50
+ host.register_feature(id: 'a', dimension: :color, value: :x)
51
+ host.register_feature(id: 'b', dimension: :shape, value: :y)
52
+ bind_result = host.bind_features(feature_ids: %w[a b])
53
+ obj_id = bind_result[:object][:id]
54
+ result = host.attend_object(object_id: obj_id)
55
+ expect(result[:success]).to be true
56
+ expect(result[:object][:confirmed]).to be true
57
+ end
58
+
59
+ it 'returns failure for unknown object' do
60
+ result = host.attend_object(object_id: :nope)
61
+ expect(result[:success]).to be false
62
+ end
63
+ end
64
+
65
+ describe '#unbind_object' do
66
+ it 'removes the object' do
67
+ host.register_feature(id: 'a', dimension: :color, value: :x)
68
+ host.register_feature(id: 'b', dimension: :shape, value: :y)
69
+ bind_result = host.bind_features(feature_ids: %w[a b])
70
+ obj_id = bind_result[:object][:id]
71
+ result = host.unbind_object(object_id: obj_id)
72
+ expect(result[:success]).to be true
73
+ end
74
+ end
75
+
76
+ describe '#illusory_conjunctions' do
77
+ it 'returns illusory bindings' do
78
+ result = host.illusory_conjunctions
79
+ expect(result[:success]).to be true
80
+ expect(result[:illusory]).to be_an(Array)
81
+ end
82
+ end
83
+
84
+ describe '#search_features' do
85
+ it 'searches by dimension' do
86
+ host.register_feature(id: 'f:red', dimension: :color, value: :red)
87
+ result = host.search_features(dimension: :color)
88
+ expect(result[:count]).to eq(1)
89
+ end
90
+ end
91
+
92
+ describe '#update_feature_binding' do
93
+ it 'decays and returns counts' do
94
+ result = host.update_feature_binding
95
+ expect(result[:success]).to be true
96
+ end
97
+ end
98
+
99
+ describe '#feature_binding_stats' do
100
+ it 'returns stats hash' do
101
+ result = host.feature_binding_stats
102
+ expect(result[:success]).to be true
103
+ expect(result[:stats]).to include(:features, :objects)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Focus::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'initializes with default focus manager and habituation model' do
7
+ status = client.attention_status
8
+ expect(status[:manual_focus]).to eq({})
9
+ expect(status[:capacity]).to eq(Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::ATTENTIONAL_CAPACITY)
10
+ end
11
+
12
+ it 'includes the Attention runner' do
13
+ expect(client).to respond_to(:filter_signals)
14
+ expect(client).to respond_to(:attention_status)
15
+ expect(client).to respond_to(:focus_on)
16
+ expect(client).to respond_to(:release_focus)
17
+ expect(client).to respond_to(:habituation_stats)
18
+ end
19
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Focus::Helpers::FocusManager do
4
+ subject(:manager) { described_class.new }
5
+
6
+ describe '#focus_on' do
7
+ it 'focuses on a domain' do
8
+ expect(manager.focus_on(:terraform)).to eq(:focused)
9
+ expect(manager.focused?(:terraform)).to be true
10
+ end
11
+
12
+ it 'converts string domains to symbols' do
13
+ manager.focus_on('vault')
14
+ expect(manager.focused?(:vault)).to be true
15
+ end
16
+
17
+ it 'returns :already_focused for duplicate focus' do
18
+ manager.focus_on(:terraform)
19
+ expect(manager.focus_on(:terraform)).to eq(:already_focused)
20
+ end
21
+
22
+ it 'returns :capacity_full when max is reached' do
23
+ Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::MAX_MANUAL_FOCUS.times do |i|
24
+ manager.focus_on(:"domain_#{i}")
25
+ end
26
+ expect(manager.focus_on(:overflow)).to eq(:capacity_full)
27
+ end
28
+
29
+ it 'stores reason with the focus' do
30
+ manager.focus_on(:security, reason: 'incident response')
31
+ expect(manager.manual_focus[:security][:reason]).to eq('incident response')
32
+ end
33
+ end
34
+
35
+ describe '#release' do
36
+ it 'releases a focused domain' do
37
+ manager.focus_on(:terraform)
38
+ expect(manager.release(:terraform)).to eq(:released)
39
+ expect(manager.focused?(:terraform)).to be false
40
+ end
41
+
42
+ it 'returns :not_focused for unfocused domains' do
43
+ expect(manager.release(:nonexistent)).to eq(:not_focused)
44
+ end
45
+ end
46
+
47
+ describe '#focused?' do
48
+ it 'returns true for focused domains' do
49
+ manager.focus_on(:vault)
50
+ expect(manager.focused?(:vault)).to be true
51
+ end
52
+
53
+ it 'returns false for unfocused domains' do
54
+ expect(manager.focused?(:vault)).to be false
55
+ end
56
+ end
57
+
58
+ describe '#focus_boost' do
59
+ it 'returns FOCUS_BOOST for focused domains' do
60
+ manager.focus_on(:terraform)
61
+ expect(manager.focus_boost(:terraform)).to eq(
62
+ Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::FOCUS_BOOST
63
+ )
64
+ end
65
+
66
+ it 'returns 0.0 for unfocused domains' do
67
+ expect(manager.focus_boost(:terraform)).to eq(0.0)
68
+ end
69
+ end
70
+
71
+ describe '#goal_relevance' do
72
+ it 'returns 0.0 with no focus or wonders' do
73
+ signal = { domain: :terraform, salience: 0.5 }
74
+ expect(manager.goal_relevance(signal)).to eq(0.0)
75
+ end
76
+
77
+ it 'returns boost for manually focused domain' do
78
+ manager.focus_on(:terraform)
79
+ signal = { domain: :terraform, salience: 0.5 }
80
+ expect(manager.goal_relevance(signal)).to be > 0.0
81
+ end
82
+
83
+ it 'returns relevance for domain matching an active wonder' do
84
+ signal = { domain: :terraform, salience: 0.5 }
85
+ wonders = [{ domain: :terraform, salience: 0.8 }]
86
+ relevance = manager.goal_relevance(signal, active_wonders: wonders)
87
+ expect(relevance).to be > 0.0
88
+ end
89
+
90
+ it 'returns 0.0 for non-matching wonder domains' do
91
+ signal = { domain: :terraform, salience: 0.5 }
92
+ wonders = [{ domain: :vault, salience: 0.8 }]
93
+ relevance = manager.goal_relevance(signal, active_wonders: wonders)
94
+ expect(relevance).to eq(0.0)
95
+ end
96
+
97
+ it 'caps at 1.0 even with focus and wonders combined' do
98
+ manager.focus_on(:terraform)
99
+ signal = { domain: :terraform, salience: 0.5 }
100
+ wonders = [{ domain: :terraform, salience: 1.0 }]
101
+ relevance = manager.goal_relevance(signal, active_wonders: wonders)
102
+ expect(relevance).to be <= 1.0
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Focus::Helpers::Focus do
4
+ let(:focus) { described_class }
5
+
6
+ describe '.score_signal' do
7
+ it 'returns a float between 0 and 1' do
8
+ score = focus.score_signal({ salience: 0.5, novelty: 0.5 })
9
+ expect(score).to be_between(0.0, 1.0)
10
+ end
11
+
12
+ it 'returns higher scores for high salience signals' do
13
+ high = focus.score_signal({ salience: 0.9, novelty: 0.5 })
14
+ low = focus.score_signal({ salience: 0.1, novelty: 0.5 })
15
+ expect(high).to be > low
16
+ end
17
+
18
+ it 'reduces score with high habituation' do
19
+ fresh = focus.score_signal({ salience: 0.5 }, habituation_level: 0.0)
20
+ habituated = focus.score_signal({ salience: 0.5 }, habituation_level: 0.9)
21
+ expect(fresh).to be > habituated
22
+ end
23
+
24
+ it 'increases score with goal relevance' do
25
+ no_goal = focus.score_signal({ salience: 0.5 }, goal_relevance: 0.0)
26
+ with_goal = focus.score_signal({ salience: 0.5 }, goal_relevance: 1.0)
27
+ expect(with_goal).to be > no_goal
28
+ end
29
+
30
+ it 'clamps result to 1.0 max' do
31
+ score = focus.score_signal({ salience: 1.0, novelty: 1.0 },
32
+ habituation_level: 0.0, goal_relevance: 1.0)
33
+ expect(score).to eq(1.0)
34
+ end
35
+ end
36
+
37
+ describe '.extract_salience' do
38
+ it 'returns salience from signal hash' do
39
+ expect(focus.extract_salience({ salience: 0.7 })).to eq(0.7)
40
+ end
41
+
42
+ it 'falls back to attention_score' do
43
+ expect(focus.extract_salience({ attention_score: 0.4 })).to eq(0.4)
44
+ end
45
+
46
+ it 'defaults to 0.0 for non-hash' do
47
+ expect(focus.extract_salience('not a hash')).to eq(0.0)
48
+ end
49
+
50
+ it 'defaults to 0.0 for missing key' do
51
+ expect(focus.extract_salience({})).to eq(0.0)
52
+ end
53
+ end
54
+
55
+ describe '.extract_novelty' do
56
+ it 'returns novelty from signal hash' do
57
+ expect(focus.extract_novelty({ novelty: 0.8 })).to eq(0.8)
58
+ end
59
+
60
+ it 'defaults to 0.5' do
61
+ expect(focus.extract_novelty({})).to eq(0.5)
62
+ end
63
+
64
+ it 'defaults to 0.5 for non-hash' do
65
+ expect(focus.extract_novelty(42)).to eq(0.5)
66
+ end
67
+ end
68
+
69
+ describe '.extract_domain' do
70
+ it 'returns domain from signal hash' do
71
+ expect(focus.extract_domain({ domain: :terraform })).to eq(:terraform)
72
+ end
73
+
74
+ it 'falls back to source_type' do
75
+ expect(focus.extract_domain({ source_type: :consul })).to eq(:consul)
76
+ end
77
+
78
+ it 'defaults to :general' do
79
+ expect(focus.extract_domain({})).to eq(:general)
80
+ end
81
+
82
+ it 'defaults to :general for non-hash' do
83
+ expect(focus.extract_domain(nil)).to eq(:general)
84
+ end
85
+ end
86
+
87
+ describe '.tag_signal' do
88
+ it 'merges attention metadata into the signal' do
89
+ signal = { salience: 0.8, domain: :terraform }
90
+ tagged = focus.tag_signal(signal, attention_score: 0.75, attention_tier: :spotlight)
91
+ expect(tagged[:attention_score]).to eq(0.75)
92
+ expect(tagged[:attention_tier]).to eq(:spotlight)
93
+ expect(tagged[:salience]).to eq(0.8)
94
+ end
95
+
96
+ it 'returns non-hash signals unchanged' do
97
+ result = focus.tag_signal('string', attention_score: 0.5, attention_tier: :peripheral)
98
+ expect(result).to eq('string')
99
+ end
100
+ end
101
+
102
+ describe '.attention_tier' do
103
+ it 'returns :spotlight for >= 0.7' do
104
+ expect(focus.attention_tier(0.7)).to eq(:spotlight)
105
+ expect(focus.attention_tier(0.95)).to eq(:spotlight)
106
+ end
107
+
108
+ it 'returns :peripheral for >= 0.4' do
109
+ expect(focus.attention_tier(0.4)).to eq(:peripheral)
110
+ expect(focus.attention_tier(0.69)).to eq(:peripheral)
111
+ end
112
+
113
+ it 'returns :background for >= BACKGROUND_THRESHOLD' do
114
+ expect(focus.attention_tier(0.2)).to eq(:background)
115
+ expect(focus.attention_tier(0.39)).to eq(:background)
116
+ end
117
+
118
+ it 'returns :filtered for below BACKGROUND_THRESHOLD' do
119
+ expect(focus.attention_tier(0.19)).to eq(:filtered)
120
+ expect(focus.attention_tier(0.0)).to eq(:filtered)
121
+ end
122
+ end
123
+
124
+ describe '.deduplicate' do
125
+ it 'removes duplicate signals by identity' do
126
+ signals = [
127
+ { domain: :terraform, source_type: :event, value: 'deploy' },
128
+ { domain: :terraform, source_type: :event, value: 'deploy' },
129
+ { domain: :vault, source_type: :event, value: 'rotate' }
130
+ ]
131
+ result = focus.deduplicate(signals)
132
+ expect(result.size).to eq(2)
133
+ end
134
+
135
+ it 'preserves unique signals' do
136
+ signals = [
137
+ { domain: :a, value: 1 },
138
+ { domain: :b, value: 2 },
139
+ { domain: :c, value: 3 }
140
+ ]
141
+ expect(focus.deduplicate(signals).size).to eq(3)
142
+ end
143
+
144
+ it 'returns empty array for empty input' do
145
+ expect(focus.deduplicate([])).to eq([])
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Focus::Helpers::Habituation do
4
+ subject(:model) { described_class.new }
5
+
6
+ describe '#record' do
7
+ it 'increases habituation level for a domain' do
8
+ model.record(:terraform)
9
+ expect(model.level(:terraform)).to be > 0.0
10
+ end
11
+
12
+ it 'accumulates with repeated recordings' do
13
+ 3.times { model.record(:terraform) }
14
+ expect(model.level(:terraform)).to be > model.level(:vault).to_f
15
+ end
16
+
17
+ it 'caps at HABITUATION_CEILING' do
18
+ ceiling = Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::HABITUATION_CEILING
19
+ 20.times { model.record(:terraform) }
20
+ expect(model.level(:terraform)).to be <= ceiling
21
+ end
22
+
23
+ it 'converts string domains to symbols' do
24
+ model.record('terraform')
25
+ expect(model.level(:terraform)).to be > 0.0
26
+ end
27
+ end
28
+
29
+ describe '#level' do
30
+ it 'returns 0.0 for unknown domains' do
31
+ expect(model.level(:unknown)).to eq(0.0)
32
+ end
33
+ end
34
+
35
+ describe '#apply_novelty_reset' do
36
+ it 'does nothing when novelty <= 0.5' do
37
+ model.record(:terraform)
38
+ level_before = model.level(:terraform)
39
+ model.apply_novelty_reset(:terraform, novelty: 0.3)
40
+ expect(model.level(:terraform)).to eq(level_before)
41
+ end
42
+
43
+ it 'reduces habituation when novelty > 0.5' do
44
+ 5.times { model.record(:terraform) }
45
+ level_before = model.level(:terraform)
46
+ model.apply_novelty_reset(:terraform, novelty: 0.9)
47
+ expect(model.level(:terraform)).to be < level_before
48
+ end
49
+
50
+ it 'never reduces below 0.0' do
51
+ model.record(:terraform)
52
+ model.apply_novelty_reset(:terraform, novelty: 1.0)
53
+ expect(model.level(:terraform)).to be >= 0.0
54
+ end
55
+ end
56
+
57
+ describe '#decay_all' do
58
+ it 'reduces habituation for all recorded domains' do
59
+ 3.times { model.record(:terraform) }
60
+ 3.times { model.record(:vault) }
61
+ tf_before = model.level(:terraform)
62
+ v_before = model.level(:vault)
63
+
64
+ model.decay_all
65
+ expect(model.level(:terraform)).to be < tf_before
66
+ expect(model.level(:vault)).to be < v_before
67
+ end
68
+
69
+ it 'removes domains that decay to zero' do
70
+ model.record(:terraform)
71
+ model.apply_novelty_reset(:terraform, novelty: 1.0)
72
+ model.decay_all
73
+ expect(model.stats).not_to have_key(:terraform)
74
+ end
75
+ end
76
+
77
+ describe '#stats' do
78
+ it 'returns rounded exposure levels' do
79
+ model.record(:terraform)
80
+ stats = model.stats
81
+ expect(stats[:terraform]).to be_a(Float)
82
+ expect(stats[:terraform].to_s.split('.').last.length).to be <= 3
83
+ end
84
+ end
85
+
86
+ describe '#habituated_domains' do
87
+ it 'returns domains above threshold' do
88
+ 10.times { model.record(:terraform) }
89
+ expect(model.habituated_domains).to include(:terraform)
90
+ end
91
+
92
+ it 'excludes domains below threshold' do
93
+ model.record(:terraform)
94
+ expect(model.habituated_domains(threshold: 0.5)).not_to include(:terraform)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Focus::Runners::Attention do
4
+ let(:client) { Legion::Extensions::Agentic::Attention::Focus::Client.new }
5
+
6
+ describe '#filter_signals' do
7
+ it 'returns empty result for empty input' do
8
+ result = client.filter_signals(signals: [])
9
+ expect(result[:filtered]).to eq([])
10
+ expect(result[:spotlight]).to eq(0)
11
+ expect(result[:peripheral]).to eq(0)
12
+ expect(result[:background]).to eq(0)
13
+ expect(result[:dropped]).to eq(0)
14
+ end
15
+
16
+ it 'categorizes high-salience signals as spotlight with goal boost' do
17
+ signals = [{ salience: 0.9, domain: :terraform, novelty: 0.8 }]
18
+ wonders = [{ domain: :terraform, salience: 0.9 }]
19
+ result = client.filter_signals(signals: signals, active_wonders: wonders)
20
+ expect(result[:spotlight]).to be >= 1
21
+ end
22
+
23
+ it 'categorizes high-salience signals into filtered output' do
24
+ signals = [{ salience: 0.9, domain: :terraform, novelty: 0.8 }]
25
+ result = client.filter_signals(signals: signals)
26
+ expect(result[:filtered].size).to be >= 1
27
+ end
28
+
29
+ it 'drops low-salience signals' do
30
+ signals = [{ salience: 0.01, domain: :heartbeat, novelty: 0.0 }]
31
+ result = client.filter_signals(signals: signals)
32
+ expect(result[:dropped]).to be >= 0
33
+ expect(result[:filtered].size).to be <= 1
34
+ end
35
+
36
+ it 'boosts signals matching active wonders' do
37
+ signals = [{ salience: 0.3, domain: :terraform, novelty: 0.3 }]
38
+ wonders = [{ domain: :terraform, salience: 0.9 }]
39
+
40
+ without = client.filter_signals(signals: signals)
41
+ # New client to avoid habituation carryover
42
+ fresh = Legion::Extensions::Agentic::Attention::Focus::Client.new
43
+ with_wonders = fresh.filter_signals(signals: signals, active_wonders: wonders)
44
+
45
+ # With wonder boost, the signal should score higher
46
+ with_total = with_wonders[:spotlight] + with_wonders[:peripheral]
47
+ without_total = without[:spotlight] + without[:peripheral]
48
+ expect(with_total).to be >= without_total
49
+ end
50
+
51
+ it 'deduplicates identical signals' do
52
+ signals = [
53
+ { salience: 0.8, domain: :terraform, source_type: :event, value: 'deploy' },
54
+ { salience: 0.8, domain: :terraform, source_type: :event, value: 'deploy' }
55
+ ]
56
+ result = client.filter_signals(signals: signals)
57
+ expect(result[:spotlight] + result[:peripheral] + result[:background]).to be <= 1
58
+ end
59
+
60
+ it 'enforces attentional capacity' do
61
+ signals = 10.times.map { |i| { salience: 0.9, domain: :"domain_#{i}", novelty: 0.9 } }
62
+ result = client.filter_signals(signals: signals)
63
+ expect(result[:spotlight]).to be <= Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::ATTENTIONAL_CAPACITY
64
+ end
65
+
66
+ it 'habituates repeated domain signals' do
67
+ first_client = Legion::Extensions::Agentic::Attention::Focus::Client.new
68
+ signals = [{ salience: 0.6, domain: :terraform, novelty: 0.3 }]
69
+
70
+ first_result = first_client.filter_signals(signals: signals)
71
+ # Record same domain multiple times to build habituation
72
+ 10.times { first_client.filter_signals(signals: signals) }
73
+ later_result = first_client.filter_signals(signals: signals)
74
+
75
+ first_scores = first_result[:filtered].map { |s| s[:attention_score] || 0 }
76
+ later_scores = later_result[:filtered].map { |s| s[:attention_score] || 0 }
77
+
78
+ # Later scores should be lower due to habituation (if signal still passes)
79
+ expect(later_scores.max).to be <= first_scores.max if first_scores.any? && later_scores.any?
80
+ end
81
+ end
82
+
83
+ describe '#attention_status' do
84
+ it 'returns status hash' do
85
+ status = client.attention_status
86
+ expect(status[:manual_focus]).to eq({})
87
+ expect(status[:habituated_domains]).to eq([])
88
+ expect(status[:capacity]).to eq(Legion::Extensions::Agentic::Attention::Focus::Helpers::Constants::ATTENTIONAL_CAPACITY)
89
+ expect(status[:focus_count]).to eq(0)
90
+ end
91
+ end
92
+
93
+ describe '#focus_on' do
94
+ it 'focuses on a domain' do
95
+ result = client.focus_on(domain: :terraform, reason: 'deployment')
96
+ expect(result[:status]).to eq(:focused)
97
+ expect(result[:domain]).to eq(:terraform)
98
+ end
99
+
100
+ it 'updates attention status' do
101
+ client.focus_on(domain: :security, reason: 'incident')
102
+ status = client.attention_status
103
+ expect(status[:focus_count]).to eq(1)
104
+ end
105
+ end
106
+
107
+ describe '#release_focus' do
108
+ it 'releases a focused domain' do
109
+ client.focus_on(domain: :terraform)
110
+ result = client.release_focus(domain: :terraform)
111
+ expect(result[:status]).to eq(:released)
112
+ end
113
+
114
+ it 'returns :not_focused for unknown domain' do
115
+ result = client.release_focus(domain: :unknown)
116
+ expect(result[:status]).to eq(:not_focused)
117
+ end
118
+ end
119
+
120
+ describe '#habituation_stats' do
121
+ it 'returns stats hash' do
122
+ stats = client.habituation_stats
123
+ expect(stats[:domains]).to be_a(Hash)
124
+ expect(stats[:habituated]).to be_an(Array)
125
+ end
126
+
127
+ it 'reflects domain exposure after filtering' do
128
+ signals = [{ salience: 0.8, domain: :terraform, novelty: 0.3 }]
129
+ 5.times { client.filter_signals(signals: signals) }
130
+ stats = client.habituation_stats
131
+ expect(stats[:domains]).to have_key(:terraform)
132
+ end
133
+ end
134
+ end