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,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Prism::Runners::CognitivePrism do
4
+ let(:engine) { Legion::Extensions::Agentic::Attention::Prism::Helpers::PrismEngine.new }
5
+
6
+ describe '#create_beam' do
7
+ it 'creates a beam via the provided engine' do
8
+ result = described_class.create_beam(domain: :science, content: 'relativity theory', engine: engine)
9
+ expect(result[:success]).to be true
10
+ expect(result[:domain]).to eq(:science)
11
+ end
12
+
13
+ it 'returns beam_id' do
14
+ result = described_class.create_beam(domain: :art, content: 'impressionism', engine: engine)
15
+ expect(result[:beam_id]).to be_a(String)
16
+ end
17
+
18
+ it 'returns failure on ArgumentError (MAX_BEAMS)' do
19
+ stub_const('Legion::Extensions::Agentic::Attention::Prism::Helpers::Constants::MAX_BEAMS', 0)
20
+ result = described_class.create_beam(domain: :d, content: 'x', engine: engine)
21
+ expect(result[:success]).to be false
22
+ expect(result[:error]).to be_a(String)
23
+ end
24
+
25
+ it 'accepts extra kwargs via ** splat' do
26
+ result = described_class.create_beam(domain: :test, content: 'splat test', engine: engine, extra: :ignored)
27
+ expect(result[:success]).to be true
28
+ end
29
+ end
30
+
31
+ describe '#decompose' do
32
+ let(:beam_id) { described_class.create_beam(domain: :physics, content: 'wave-particle duality', engine: engine)[:beam_id] }
33
+
34
+ it 'returns success with component count' do
35
+ result = described_class.decompose(beam_id: beam_id, engine: engine)
36
+ expect(result[:success]).to be true
37
+ expect(result[:component_count]).to eq(8)
38
+ end
39
+
40
+ it 'returns failure for unknown beam_id' do
41
+ result = described_class.decompose(beam_id: 'ghost', engine: engine)
42
+ expect(result[:success]).to be false
43
+ end
44
+ end
45
+
46
+ describe '#recompose' do
47
+ let(:beam_id) do
48
+ id = described_class.create_beam(domain: :math, content: 'topology and manifolds', engine: engine)[:beam_id]
49
+ described_class.decompose(beam_id: id, engine: engine)
50
+ id
51
+ end
52
+
53
+ it 'returns success' do
54
+ result = described_class.recompose(component_ids: [], engine: engine)
55
+ expect(result[:success]).to be true
56
+ end
57
+
58
+ it 'accepts extra kwargs' do
59
+ result = described_class.recompose(component_ids: [], engine: engine, meta: :data)
60
+ expect(result[:success]).to be true
61
+ end
62
+ end
63
+
64
+ describe '#attenuate_all' do
65
+ before do
66
+ id = described_class.create_beam(domain: :d, content: 'idea to attenuate', engine: engine)[:beam_id]
67
+ described_class.decompose(beam_id: id, engine: engine)
68
+ end
69
+
70
+ it 'returns success' do
71
+ result = described_class.attenuate_all(engine: engine)
72
+ expect(result[:success]).to be true
73
+ end
74
+
75
+ it 'reports attenuated count' do
76
+ result = described_class.attenuate_all(engine: engine)
77
+ expect(result[:attenuated]).to eq(8)
78
+ end
79
+
80
+ it 'accepts a custom rate' do
81
+ result = described_class.attenuate_all(rate: 0.2, engine: engine)
82
+ expect(result[:rate]).to eq(0.2)
83
+ end
84
+ end
85
+
86
+ describe '#dominant_bands' do
87
+ it 'returns success with bands hash' do
88
+ result = described_class.dominant_bands(engine: engine)
89
+ expect(result[:success]).to be true
90
+ expect(result[:bands]).to be_a(Hash)
91
+ end
92
+
93
+ it 'bands hash has values after decomposition' do
94
+ id = described_class.create_beam(domain: :d, content: 'bright idea', engine: engine)[:beam_id]
95
+ described_class.decompose(beam_id: id, engine: engine)
96
+ result = described_class.dominant_bands(engine: engine)
97
+ expect(result[:bands]).not_to be_empty
98
+ end
99
+ end
100
+
101
+ describe '#most_intense' do
102
+ before do
103
+ id = described_class.create_beam(domain: :d, content: 'intense thought', engine: engine)[:beam_id]
104
+ described_class.decompose(beam_id: id, engine: engine)
105
+ end
106
+
107
+ it 'returns success with components array' do
108
+ result = described_class.most_intense(engine: engine)
109
+ expect(result[:success]).to be true
110
+ expect(result[:components]).to be_an(Array)
111
+ end
112
+
113
+ it 'respects the limit parameter' do
114
+ result = described_class.most_intense(limit: 3, engine: engine)
115
+ expect(result[:components].size).to be <= 3
116
+ end
117
+ end
118
+
119
+ describe '#spectral_report' do
120
+ it 'returns success with report keys' do
121
+ result = described_class.spectral_report(engine: engine)
122
+ expect(result[:success]).to be true
123
+ expect(result).to have_key(:total_beams)
124
+ expect(result).to have_key(:decomposed_beams)
125
+ end
126
+
127
+ it 'includes avg_purity' do
128
+ result = described_class.spectral_report(engine: engine)
129
+ expect(result).to have_key(:avg_purity)
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Regulation::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'full lifecycle: add targets, focus, zoom, scan, rest' do
7
+ a = client.add_attention_target(name: 'urgent email', domain: :work, salience: 0.8)
8
+ expect(a[:success]).to be true
9
+
10
+ b = client.add_attention_target(name: 'background music', domain: :ambient, salience: 0.2)
11
+ expect(b[:success]).to be true
12
+
13
+ focus_result = client.focus_attention(target_id: a[:target_id])
14
+ expect(focus_result[:success]).to be true
15
+ expect(focus_result[:mode]).to eq(:focused)
16
+
17
+ zoom_result = client.zoom_attention_in(amount: 0.2)
18
+ expect(zoom_result[:zoom]).to be > 0.5
19
+
20
+ current = client.current_attention_target
21
+ expect(current[:target][:name]).to eq('urgent email')
22
+
23
+ client.defocus_attention
24
+ client.rest_attention
25
+
26
+ stats = client.attention_regulation_stats
27
+ expect(stats[:mode]).to eq(:resting)
28
+ expect(stats[:target_count]).to eq(2)
29
+ end
30
+
31
+ it 'accepts an injected controller' do
32
+ ctrl = Legion::Extensions::Agentic::Attention::Regulation::Helpers::AttentionController.new
33
+ c = described_class.new(controller: ctrl)
34
+ c.add_attention_target(name: 'injected', salience: 0.5)
35
+ expect(ctrl.to_h[:target_count]).to eq(1)
36
+ end
37
+
38
+ it 'captures high-salience target during scan' do
39
+ client.add_attention_target(name: 'alarm', domain: :safety, salience: 0.9)
40
+ result = client.scan_attention
41
+ expect(result[:captured_target_id]).not_to be_nil
42
+ end
43
+
44
+ it 'resource drains when focused and recovers when resting' do
45
+ t = client.add_attention_target(name: 'work', salience: 0.5)
46
+ client.focus_attention(target_id: t[:target_id])
47
+ initial = client.attention_regulation_stats[:resource]
48
+
49
+ 5.times { client.update_attention }
50
+ drained = client.attention_regulation_stats[:resource]
51
+ expect(drained).to be < initial
52
+
53
+ client.rest_attention
54
+ client.update_attention
55
+ recovered = client.attention_regulation_stats[:resource]
56
+ expect(recovered).to be > drained
57
+ end
58
+ end
@@ -0,0 +1,295 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Regulation::Helpers::AttentionController do
4
+ subject(:ctrl) { described_class.new }
5
+
6
+ describe '#initialize' do
7
+ it 'starts in :diffuse mode' do
8
+ expect(ctrl.to_h[:mode]).to eq(:diffuse)
9
+ end
10
+
11
+ it 'starts with full resource' do
12
+ expect(ctrl.to_h[:resource]).to eq(1.0)
13
+ end
14
+
15
+ it 'starts with default zoom' do
16
+ expect(ctrl.to_h[:zoom]).to eq(0.5)
17
+ end
18
+
19
+ it 'starts with zero targets' do
20
+ expect(ctrl.to_h[:target_count]).to eq(0)
21
+ end
22
+ end
23
+
24
+ describe '#add_target' do
25
+ it 'adds a target and returns it' do
26
+ target = ctrl.add_target(name: 'inbox', domain: :work, salience: 0.4)
27
+ expect(target).to be_a(Legion::Extensions::Agentic::Attention::Regulation::Helpers::AttentionTarget)
28
+ expect(target.name).to eq('inbox')
29
+ end
30
+
31
+ it 'increments target count' do
32
+ ctrl.add_target(name: 'first', salience: 0.3)
33
+ ctrl.add_target(name: 'second', salience: 0.5)
34
+ expect(ctrl.to_h[:target_count]).to eq(2)
35
+ end
36
+
37
+ it 'assigns unique ids' do
38
+ t1 = ctrl.add_target(name: 'a', salience: 0.3)
39
+ t2 = ctrl.add_target(name: 'b', salience: 0.4)
40
+ expect(t1.id).not_to eq(t2.id)
41
+ end
42
+
43
+ it 'returns nil when limit is reached' do
44
+ 30.times { |i| ctrl.add_target(name: "target #{i}", salience: 0.3) }
45
+ result = ctrl.add_target(name: 'overflow', salience: 0.5)
46
+ expect(result).to be_nil
47
+ end
48
+ end
49
+
50
+ describe '#focus_on' do
51
+ let(:target) { ctrl.add_target(name: 'focus me', salience: 0.5) }
52
+
53
+ it 'sets mode to :focused' do
54
+ ctrl.focus_on(target_id: target.id)
55
+ expect(ctrl.to_h[:mode]).to eq(:focused)
56
+ end
57
+
58
+ it 'sets the current target' do
59
+ ctrl.focus_on(target_id: target.id)
60
+ expect(ctrl.current_target).to eq(target)
61
+ end
62
+
63
+ it 'marks the target as attended' do
64
+ ctrl.focus_on(target_id: target.id)
65
+ expect(target.state).to eq(:attended)
66
+ end
67
+
68
+ it 'returns nil for unknown target' do
69
+ result = ctrl.focus_on(target_id: :nonexistent)
70
+ expect(result).to be_nil
71
+ end
72
+
73
+ it 'marks previous target as peripheral when switching focus' do
74
+ t1 = ctrl.add_target(name: 'first', salience: 0.4)
75
+ t2 = ctrl.add_target(name: 'second', salience: 0.5)
76
+ ctrl.focus_on(target_id: t1.id)
77
+ ctrl.focus_on(target_id: t2.id)
78
+ expect(t1.state).to eq(:peripheral)
79
+ expect(t2.state).to eq(:attended)
80
+ end
81
+ end
82
+
83
+ describe '#defocus' do
84
+ it 'sets mode to :diffuse' do
85
+ target = ctrl.add_target(name: 'x', salience: 0.4)
86
+ ctrl.focus_on(target_id: target.id)
87
+ ctrl.defocus
88
+ expect(ctrl.to_h[:mode]).to eq(:diffuse)
89
+ end
90
+
91
+ it 'clears current target' do
92
+ target = ctrl.add_target(name: 'x', salience: 0.4)
93
+ ctrl.focus_on(target_id: target.id)
94
+ ctrl.defocus
95
+ expect(ctrl.current_target).to be_nil
96
+ end
97
+
98
+ it 'marks previously attended target as peripheral' do
99
+ target = ctrl.add_target(name: 'x', salience: 0.4)
100
+ ctrl.focus_on(target_id: target.id)
101
+ ctrl.defocus
102
+ expect(target.state).to eq(:peripheral)
103
+ end
104
+ end
105
+
106
+ describe '#scan' do
107
+ it 'sets mode to :scanning' do
108
+ ctrl.scan
109
+ expect(ctrl.to_h[:mode]).to eq(:scanning)
110
+ end
111
+
112
+ it 'captures a high-salience target automatically' do
113
+ ctrl.add_target(name: 'urgent', salience: 0.9)
114
+ ctrl.scan
115
+ expect(ctrl.to_h[:mode]).to eq(:captured)
116
+ end
117
+
118
+ it 'does not capture when no target meets threshold' do
119
+ ctrl.add_target(name: 'low', salience: 0.3)
120
+ ctrl.scan
121
+ expect(ctrl.to_h[:mode]).to eq(:scanning)
122
+ end
123
+ end
124
+
125
+ describe '#rest' do
126
+ it 'sets mode to :resting' do
127
+ ctrl.rest
128
+ expect(ctrl.to_h[:mode]).to eq(:resting)
129
+ end
130
+
131
+ it 'clears current target' do
132
+ t = ctrl.add_target(name: 'x', salience: 0.4)
133
+ ctrl.focus_on(target_id: t.id)
134
+ ctrl.rest
135
+ expect(ctrl.current_target).to be_nil
136
+ end
137
+ end
138
+
139
+ describe '#zoom_in' do
140
+ it 'increases zoom' do
141
+ original = ctrl.to_h[:zoom]
142
+ ctrl.zoom_in(amount: 0.2)
143
+ expect(ctrl.to_h[:zoom]).to be > original
144
+ end
145
+
146
+ it 'clamps zoom at ceiling' do
147
+ ctrl.zoom_in(amount: 2.0)
148
+ expect(ctrl.to_h[:zoom]).to eq(1.0)
149
+ end
150
+ end
151
+
152
+ describe '#zoom_out' do
153
+ it 'decreases zoom' do
154
+ original = ctrl.to_h[:zoom]
155
+ ctrl.zoom_out(amount: 0.2)
156
+ expect(ctrl.to_h[:zoom]).to be < original
157
+ end
158
+
159
+ it 'clamps zoom at floor' do
160
+ ctrl.zoom_out(amount: 2.0)
161
+ expect(ctrl.to_h[:zoom]).to eq(0.1)
162
+ end
163
+ end
164
+
165
+ describe '#check_capture' do
166
+ it 'captures the most salient unattended target above threshold' do
167
+ ctrl.add_target(name: 'medium', salience: 0.75)
168
+ ctrl.add_target(name: 'high', salience: 0.95)
169
+ result = ctrl.check_capture
170
+ expect(result).not_to be_nil
171
+ expect(result.salience).to eq(0.95)
172
+ end
173
+
174
+ it 'returns nil when no target is salient enough' do
175
+ ctrl.add_target(name: 'low', salience: 0.2)
176
+ expect(ctrl.check_capture).to be_nil
177
+ end
178
+
179
+ it 'returns nil when resource is too low' do
180
+ ctrl.add_target(name: 'urgent', salience: 0.9)
181
+ # set resource below the 0.3 capture threshold directly
182
+ ctrl.instance_variable_set(:@resource, 0.1)
183
+ expect(ctrl.check_capture).to be_nil
184
+ end
185
+
186
+ it 'does not capture an already attended target' do
187
+ t = ctrl.add_target(name: 'urgent', salience: 0.9)
188
+ ctrl.focus_on(target_id: t.id)
189
+ # attended target should not self-capture
190
+ result = ctrl.check_capture
191
+ expect(result).to be_nil
192
+ end
193
+ end
194
+
195
+ describe '#current_target' do
196
+ it 'returns nil when not focused' do
197
+ expect(ctrl.current_target).to be_nil
198
+ end
199
+
200
+ it 'returns the focused target' do
201
+ t = ctrl.add_target(name: 'active', salience: 0.5)
202
+ ctrl.focus_on(target_id: t.id)
203
+ expect(ctrl.current_target).to eq(t)
204
+ end
205
+ end
206
+
207
+ describe '#most_salient' do
208
+ it 'returns the target with highest salience' do
209
+ ctrl.add_target(name: 'low', salience: 0.2)
210
+ ctrl.add_target(name: 'high', salience: 0.8)
211
+ ctrl.add_target(name: 'mid', salience: 0.5)
212
+ expect(ctrl.most_salient.name).to eq('high')
213
+ end
214
+
215
+ it 'returns nil when no targets exist' do
216
+ expect(ctrl.most_salient).to be_nil
217
+ end
218
+ end
219
+
220
+ describe '#attended_targets' do
221
+ it 'returns only attended targets' do
222
+ t1 = ctrl.add_target(name: 'a', salience: 0.5)
223
+ ctrl.add_target(name: 'b', salience: 0.4)
224
+ ctrl.focus_on(target_id: t1.id)
225
+ expect(ctrl.attended_targets.size).to eq(1)
226
+ expect(ctrl.attended_targets.first).to eq(t1)
227
+ end
228
+ end
229
+
230
+ describe '#peripheral_targets' do
231
+ it 'returns targets in :peripheral state' do
232
+ ctrl.add_target(name: 'a', salience: 0.3)
233
+ ctrl.add_target(name: 'b', salience: 0.4)
234
+ expect(ctrl.peripheral_targets.size).to eq(2)
235
+ end
236
+ end
237
+
238
+ describe '#tick' do
239
+ it 'drains resource when focused' do
240
+ t = ctrl.add_target(name: 'x', salience: 0.4)
241
+ ctrl.focus_on(target_id: t.id)
242
+ original = ctrl.to_h[:resource]
243
+ ctrl.tick
244
+ expect(ctrl.to_h[:resource]).to be < original
245
+ end
246
+
247
+ it 'recovers resource when resting' do
248
+ # first drain a bit
249
+ t = ctrl.add_target(name: 'x', salience: 0.4)
250
+ ctrl.focus_on(target_id: t.id)
251
+ 5.times { ctrl.tick }
252
+ ctrl.rest
253
+ before_rest = ctrl.to_h[:resource]
254
+ ctrl.tick
255
+ expect(ctrl.to_h[:resource]).to be > before_rest
256
+ end
257
+
258
+ it 'does not change resource in diffuse mode' do
259
+ original = ctrl.to_h[:resource]
260
+ ctrl.tick
261
+ expect(ctrl.to_h[:resource]).to eq(original)
262
+ end
263
+
264
+ it 'triggers capture during scan tick' do
265
+ ctrl.add_target(name: 'urgent', salience: 0.9)
266
+ ctrl.scan
267
+ # scan already triggered capture in #scan, let's reset and test tick-triggered
268
+ ctrl2 = described_class.new
269
+ ctrl2.add_target(name: 'urgent', salience: 0.9)
270
+ # put in scanning mode without triggering capture (no target above threshold yet)
271
+ ctrl2.instance_variable_set(:@mode, :scanning)
272
+ ctrl2.tick
273
+ expect(ctrl2.to_h[:mode]).to eq(:captured)
274
+ end
275
+ end
276
+
277
+ describe '#resource_label' do
278
+ it 'returns :abundant for full resource' do
279
+ expect(ctrl.resource_label).to eq(:abundant)
280
+ end
281
+
282
+ it 'returns a symbol' do
283
+ expect(ctrl.resource_label).to be_a(Symbol)
284
+ end
285
+ end
286
+
287
+ describe '#to_h' do
288
+ it 'returns expected keys' do
289
+ expect(ctrl.to_h).to include(
290
+ :mode, :zoom, :resource, :resource_label,
291
+ :current_target_id, :target_count, :attended_count, :peripheral_count
292
+ )
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Regulation::Helpers::AttentionTarget do
4
+ subject(:target) do
5
+ described_class.new(id: :target_one, name: 'urgent task', domain: :work, salience: 0.6)
6
+ end
7
+
8
+ describe '#initialize' do
9
+ it 'sets id, name, domain, salience' do
10
+ expect(target.id).to eq(:target_one)
11
+ expect(target.name).to eq('urgent task')
12
+ expect(target.domain).to eq(:work)
13
+ expect(target.salience).to eq(0.6)
14
+ end
15
+
16
+ it 'starts in :peripheral state' do
17
+ expect(target.state).to eq(:peripheral)
18
+ end
19
+
20
+ it 'starts with nil attended_since' do
21
+ expect(target.attended_since).to be_nil
22
+ end
23
+
24
+ it 'clamps salience to 0..1' do
25
+ t = described_class.new(id: :x, name: 'x', salience: 2.5)
26
+ expect(t.salience).to eq(1.0)
27
+ end
28
+
29
+ it 'clamps salience floor to 0' do
30
+ t = described_class.new(id: :x, name: 'x', salience: -0.5)
31
+ expect(t.salience).to eq(0.0)
32
+ end
33
+ end
34
+
35
+ describe '#attend!' do
36
+ it 'sets state to :attended' do
37
+ target.attend!
38
+ expect(target.state).to eq(:attended)
39
+ end
40
+
41
+ it 'records attended_since timestamp' do
42
+ target.attend!
43
+ expect(target.attended_since).to be_a(Time)
44
+ end
45
+ end
46
+
47
+ describe '#ignore!' do
48
+ it 'sets state to :ignored' do
49
+ target.attend!
50
+ target.ignore!
51
+ expect(target.state).to eq(:ignored)
52
+ end
53
+
54
+ it 'clears attended_since' do
55
+ target.attend!
56
+ target.ignore!
57
+ expect(target.attended_since).to be_nil
58
+ end
59
+ end
60
+
61
+ describe '#peripheral!' do
62
+ it 'sets state to :peripheral' do
63
+ target.attend!
64
+ target.peripheral!
65
+ expect(target.state).to eq(:peripheral)
66
+ end
67
+
68
+ it 'clears attended_since' do
69
+ target.attend!
70
+ target.peripheral!
71
+ expect(target.attended_since).to be_nil
72
+ end
73
+ end
74
+
75
+ describe '#salient_enough_to_capture?' do
76
+ it 'returns false when salience is below threshold' do
77
+ t = described_class.new(id: :x, name: 'x', salience: 0.5)
78
+ expect(t.salient_enough_to_capture?).to be false
79
+ end
80
+
81
+ it 'returns true when salience meets threshold' do
82
+ t = described_class.new(id: :x, name: 'x', salience: 0.7)
83
+ expect(t.salient_enough_to_capture?).to be true
84
+ end
85
+
86
+ it 'returns true when salience exceeds threshold' do
87
+ t = described_class.new(id: :x, name: 'x', salience: 0.9)
88
+ expect(t.salient_enough_to_capture?).to be true
89
+ end
90
+ end
91
+
92
+ describe '#duration' do
93
+ it 'returns nil when not attended' do
94
+ expect(target.duration).to be_nil
95
+ end
96
+
97
+ it 'returns nil when ignored' do
98
+ target.attend!
99
+ target.ignore!
100
+ expect(target.duration).to be_nil
101
+ end
102
+
103
+ it 'returns elapsed time when attended' do
104
+ target.attend!
105
+ sleep(0.01)
106
+ expect(target.duration).to be_a(Float)
107
+ expect(target.duration).to be > 0
108
+ end
109
+ end
110
+
111
+ describe '#to_h' do
112
+ it 'returns a hash with expected keys' do
113
+ h = target.to_h
114
+ expect(h).to include(:id, :name, :domain, :salience, :state, :attended_since)
115
+ end
116
+
117
+ it 'rounds salience to 4 decimal places' do
118
+ t = described_class.new(id: :x, name: 'x', salience: 0.123456789)
119
+ expect(t.to_h[:salience]).to eq(0.1235)
120
+ end
121
+ end
122
+ end