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,151 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/signal_detection/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::SignalDetection::Runners::SignalDetection do
6
+ let(:client) { Legion::Extensions::Agentic::Attention::SignalDetection::Client.new }
7
+
8
+ describe '#create_detector' do
9
+ it 'creates a detector and returns id' do
10
+ result = client.create_detector(domain: :threat)
11
+ expect(result[:created]).to be true
12
+ expect(result[:detector_id]).to match(/\A[0-9a-f-]{36}\z/)
13
+ expect(result[:domain]).to eq(:threat)
14
+ end
15
+ end
16
+
17
+ describe '#record_detection_trial' do
18
+ it 'records a hit' do
19
+ id = client.create_detector(domain: :test)[:detector_id]
20
+ result = client.record_detection_trial(detector_id: id, signal_present: true, responded_present: true)
21
+ expect(result[:outcome]).to eq(:hit)
22
+ expect(result[:trial_count]).to eq(1)
23
+ end
24
+
25
+ it 'records a miss' do
26
+ id = client.create_detector(domain: :test)[:detector_id]
27
+ result = client.record_detection_trial(detector_id: id, signal_present: true, responded_present: false)
28
+ expect(result[:outcome]).to eq(:miss)
29
+ end
30
+
31
+ it 'records a false alarm' do
32
+ id = client.create_detector(domain: :test)[:detector_id]
33
+ result = client.record_detection_trial(detector_id: id, signal_present: false, responded_present: true)
34
+ expect(result[:outcome]).to eq(:false_alarm)
35
+ end
36
+
37
+ it 'records a correct rejection' do
38
+ id = client.create_detector(domain: :test)[:detector_id]
39
+ result = client.record_detection_trial(detector_id: id, signal_present: false, responded_present: false)
40
+ expect(result[:outcome]).to eq(:correct_rejection)
41
+ end
42
+
43
+ it 'returns not_found for unknown detector' do
44
+ result = client.record_detection_trial(detector_id: 'nonexistent', signal_present: true, responded_present: true)
45
+ expect(result[:reason]).to eq(:not_found)
46
+ end
47
+ end
48
+
49
+ describe '#compute_detector_sensitivity' do
50
+ let(:detector_id) do
51
+ id = client.create_detector(domain: :test)[:detector_id]
52
+ 8.times { client.record_detection_trial(detector_id: id, signal_present: true, responded_present: true) }
53
+ 2.times { client.record_detection_trial(detector_id: id, signal_present: false, responded_present: true) }
54
+ id
55
+ end
56
+
57
+ it 'returns d_prime and criterion' do
58
+ result = client.compute_detector_sensitivity(detector_id: detector_id)
59
+ expect(result).to include(:d_prime, :criterion, :accuracy)
60
+ end
61
+
62
+ it 'returns sensitivity_label' do
63
+ result = client.compute_detector_sensitivity(detector_id: detector_id)
64
+ expect(result[:sensitivity_label]).to be_a(Symbol)
65
+ end
66
+
67
+ it 'returns not_found for unknown detector' do
68
+ result = client.compute_detector_sensitivity(detector_id: 'unknown')
69
+ expect(result[:found]).to be false
70
+ end
71
+ end
72
+
73
+ describe '#adjust_detector_bias' do
74
+ it 'shifts the criterion' do
75
+ id = client.create_detector(domain: :test)[:detector_id]
76
+ result = client.adjust_detector_bias(detector_id: id, amount: 0.5)
77
+ expect(result[:criterion]).to be > 0.0
78
+ expect(result[:bias_label]).to be_a(Symbol)
79
+ end
80
+
81
+ it 'returns not_found for unknown detector' do
82
+ result = client.adjust_detector_bias(detector_id: 'none', amount: 0.1)
83
+ expect(result[:adjusted]).to be false
84
+ end
85
+ end
86
+
87
+ describe '#best_detectors' do
88
+ it 'returns list sorted by sensitivity' do
89
+ client.create_detector(domain: :A)
90
+ client.create_detector(domain: :B)
91
+ result = client.best_detectors(limit: 2)
92
+ expect(result[:count]).to eq(2)
93
+ expect(result[:detectors]).to be_an(Array)
94
+ end
95
+ end
96
+
97
+ describe '#domain_detectors' do
98
+ it 'filters by domain' do
99
+ client.create_detector(domain: :audio)
100
+ client.create_detector(domain: :audio)
101
+ client.create_detector(domain: :visual)
102
+ result = client.domain_detectors(domain: :audio)
103
+ expect(result[:count]).to eq(2)
104
+ expect(result[:domain]).to eq(:audio)
105
+ end
106
+ end
107
+
108
+ describe '#optimal_detector_criterion' do
109
+ it 'returns optimal criterion for balanced prior' do
110
+ id = client.create_detector(domain: :test)[:detector_id]
111
+ result = client.optimal_detector_criterion(detector_id: id, signal_probability: 0.5)
112
+ expect(result[:optimal_criterion]).to be_within(0.001).of(0.0)
113
+ end
114
+
115
+ it 'returns not_found for unknown detector' do
116
+ result = client.optimal_detector_criterion(detector_id: 'none')
117
+ expect(result[:found]).to be false
118
+ end
119
+ end
120
+
121
+ describe '#detector_roc_point' do
122
+ it 'returns hit_rate and false_alarm_rate' do
123
+ id = client.create_detector(domain: :test)[:detector_id]
124
+ result = client.detector_roc_point(detector_id: id)
125
+ expect(result).to include(:hit_rate, :false_alarm_rate, :d_prime)
126
+ end
127
+
128
+ it 'returns not_found for unknown detector' do
129
+ result = client.detector_roc_point(detector_id: 'none')
130
+ expect(result[:found]).to be false
131
+ end
132
+ end
133
+
134
+ describe '#update_signal_detection' do
135
+ it 'runs decay cycle' do
136
+ id = client.create_detector(domain: :test)[:detector_id]
137
+ client.record_detection_trial(detector_id: id, signal_present: true, responded_present: true)
138
+ result = client.update_signal_detection
139
+ expect(result).to include(:decayed)
140
+ end
141
+ end
142
+
143
+ describe '#signal_detection_stats' do
144
+ it 'returns total_detectors and top_detectors' do
145
+ 2.times { |i| client.create_detector(domain: :"d#{i}") }
146
+ result = client.signal_detection_stats
147
+ expect(result[:total_detectors]).to eq(2)
148
+ expect(result[:top_detectors]).to be_an(Array)
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/spotlight/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::Spotlight::Client do
6
+ it 'responds to all runner methods' do
7
+ client = described_class.new
8
+ expect(client).to respond_to(:register_target)
9
+ expect(client).to respond_to(:focus_spotlight)
10
+ expect(client).to respond_to(:broaden_spotlight)
11
+ expect(client).to respond_to(:narrow_spotlight)
12
+ expect(client).to respond_to(:scan_targets)
13
+ expect(client).to respond_to(:check_peripheral)
14
+ expect(client).to respond_to(:check_capture)
15
+ expect(client).to respond_to(:release_focus)
16
+ expect(client).to respond_to(:spotlight_report)
17
+ expect(client).to respond_to(:most_salient)
18
+ expect(client).to respond_to(:spotlight_state)
19
+ end
20
+
21
+ it 'accepts an injected engine' do
22
+ engine = Legion::Extensions::Agentic::Attention::Spotlight::Helpers::SpotlightEngine.new
23
+ client = described_class.new(engine: engine)
24
+ expect(client.spotlight_state[:success]).to be true
25
+ end
26
+
27
+ it 'uses an internal engine when none injected' do
28
+ client = described_class.new
29
+ expect(client.spotlight_state[:success]).to be true
30
+ end
31
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Spotlight::Helpers::AttentionTarget do
4
+ subject(:target) { described_class.new(label: 'test task', domain: :work) }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a uuid id' do
8
+ expect(target.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets label' do
12
+ expect(target.label).to eq('test task')
13
+ end
14
+
15
+ it 'sets domain' do
16
+ expect(target.domain).to eq(:work)
17
+ end
18
+
19
+ it 'defaults salience to 0.5' do
20
+ expect(target.salience).to eq(0.5)
21
+ end
22
+
23
+ it 'defaults relevance to 0.5' do
24
+ expect(target.relevance).to eq(0.5)
25
+ end
26
+
27
+ it 'starts with in_spotlight false' do
28
+ expect(target.in_spotlight).to be false
29
+ end
30
+
31
+ it 'starts with in_periphery false' do
32
+ expect(target.in_periphery).to be false
33
+ end
34
+
35
+ it 'starts with capture_count 0' do
36
+ expect(target.capture_count).to eq(0)
37
+ end
38
+
39
+ it 'sets created_at' do
40
+ expect(target.created_at).to be_a(Time)
41
+ end
42
+
43
+ it 'starts with last_attended_at nil' do
44
+ expect(target.last_attended_at).to be_nil
45
+ end
46
+
47
+ it 'clamps salience above 1.0' do
48
+ t = described_class.new(label: 'x', domain: :test, salience: 2.5)
49
+ expect(t.salience).to eq(1.0)
50
+ end
51
+
52
+ it 'clamps salience below 0.0' do
53
+ t = described_class.new(label: 'x', domain: :test, salience: -0.5)
54
+ expect(t.salience).to eq(0.0)
55
+ end
56
+
57
+ it 'clamps relevance to valid range' do
58
+ t = described_class.new(label: 'x', domain: :test, relevance: 1.5)
59
+ expect(t.relevance).to eq(1.0)
60
+ end
61
+ end
62
+
63
+ describe '#compelling?' do
64
+ it 'returns false when salience is below capture threshold' do
65
+ target.salience = 0.7
66
+ expect(target.compelling?).to be false
67
+ end
68
+
69
+ it 'returns true when salience meets capture threshold' do
70
+ target.salience = 0.8
71
+ expect(target.compelling?).to be true
72
+ end
73
+
74
+ it 'returns true when salience exceeds capture threshold' do
75
+ target.salience = 0.95
76
+ expect(target.compelling?).to be true
77
+ end
78
+ end
79
+
80
+ describe '#salient?' do
81
+ it 'returns false when salience is below peripheral detection threshold' do
82
+ target.salience = 0.2
83
+ expect(target.salient?).to be false
84
+ end
85
+
86
+ it 'returns true when salience meets peripheral detection threshold' do
87
+ target.salience = 0.3
88
+ expect(target.salient?).to be true
89
+ end
90
+
91
+ it 'returns true when salience exceeds threshold' do
92
+ target.salience = 0.6
93
+ expect(target.salient?).to be true
94
+ end
95
+ end
96
+
97
+ describe '#to_h' do
98
+ it 'returns a hash with all expected keys' do
99
+ h = target.to_h
100
+ expect(h.keys).to include(:id, :label, :domain, :salience, :relevance,
101
+ :in_spotlight, :in_periphery, :capture_count,
102
+ :compelling, :salient, :created_at, :last_attended_at)
103
+ end
104
+
105
+ it 'rounds salience to 10 decimal places' do
106
+ target.salience = 1.0 / 3.0
107
+ h = target.to_h
108
+ expect(h[:salience]).to eq((1.0 / 3.0).round(10))
109
+ end
110
+
111
+ it 'includes computed compelling value' do
112
+ target.salience = 0.9
113
+ expect(target.to_h[:compelling]).to be true
114
+ end
115
+
116
+ it 'includes computed salient value' do
117
+ target.salience = 0.05
118
+ expect(target.to_h[:salient]).to be false
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Spotlight::Helpers::Constants do
4
+ subject(:mod) { described_class }
5
+
6
+ describe 'numeric constants' do
7
+ it 'has MAX_TARGETS = 200' do
8
+ expect(mod::MAX_TARGETS).to eq(200)
9
+ end
10
+
11
+ it 'has MAX_PERIPHERAL = 100' do
12
+ expect(mod::MAX_PERIPHERAL).to eq(100)
13
+ end
14
+
15
+ it 'has DEFAULT_INTENSITY = 0.5' do
16
+ expect(mod::DEFAULT_INTENSITY).to eq(0.5)
17
+ end
18
+
19
+ it 'has DEFAULT_BREADTH = 0.5' do
20
+ expect(mod::DEFAULT_BREADTH).to eq(0.5)
21
+ end
22
+
23
+ it 'has ZOOM_STEP = 0.1' do
24
+ expect(mod::ZOOM_STEP).to eq(0.1)
25
+ end
26
+
27
+ it 'has INTENSITY_GAIN = 0.15' do
28
+ expect(mod::INTENSITY_GAIN).to eq(0.15)
29
+ end
30
+
31
+ it 'has INTENSITY_LOSS = 0.1' do
32
+ expect(mod::INTENSITY_LOSS).to eq(0.1)
33
+ end
34
+
35
+ it 'has PERIPHERAL_DETECTION_THRESHOLD = 0.3' do
36
+ expect(mod::PERIPHERAL_DETECTION_THRESHOLD).to eq(0.3)
37
+ end
38
+
39
+ it 'has CAPTURE_THRESHOLD = 0.8' do
40
+ expect(mod::CAPTURE_THRESHOLD).to eq(0.8)
41
+ end
42
+ end
43
+
44
+ describe 'array constants' do
45
+ it 'has 5 ZOOM_LEVELS' do
46
+ expect(mod::ZOOM_LEVELS).to eq(%i[laser narrow moderate wide diffuse])
47
+ end
48
+
49
+ it 'has 4 MODE_LABELS' do
50
+ expect(mod::MODE_LABELS).to eq(%i[focused scanning captured idle])
51
+ end
52
+ end
53
+
54
+ describe 'ZOOM_RANGES' do
55
+ it 'covers 0.0 with :laser' do
56
+ entry = mod::ZOOM_RANGES.find { |z| z[:range].cover?(0.0) }
57
+ expect(entry[:level]).to eq(:laser)
58
+ end
59
+
60
+ it 'covers 0.5 with :moderate' do
61
+ entry = mod::ZOOM_RANGES.find { |z| z[:range].cover?(0.5) }
62
+ expect(entry[:level]).to eq(:moderate)
63
+ end
64
+
65
+ it 'covers 1.0 with :diffuse' do
66
+ entry = mod::ZOOM_RANGES.find { |z| z[:range].cover?(1.0) }
67
+ expect(entry[:level]).to eq(:diffuse)
68
+ end
69
+ end
70
+
71
+ describe 'INTENSITY_LABELS' do
72
+ it 'covers 0.9 with :blazing' do
73
+ entry = mod::INTENSITY_LABELS.find { |il| il[:range].cover?(0.9) }
74
+ expect(entry[:label]).to eq(:blazing)
75
+ end
76
+
77
+ it 'covers 0.1 with :dark' do
78
+ entry = mod::INTENSITY_LABELS.find { |il| il[:range].cover?(0.1) }
79
+ expect(entry[:label]).to eq(:dark)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,275 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::Spotlight::Helpers::SpotlightEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ def register(label: 'task', domain: :work, salience: 0.5, relevance: 0.5)
7
+ engine.register_target(label: label, domain: domain, salience: salience, relevance: relevance)
8
+ end
9
+
10
+ describe '#initialize' do
11
+ it 'starts with empty targets' do
12
+ expect(engine.targets).to be_empty
13
+ end
14
+
15
+ it 'starts with a Spotlight instance' do
16
+ expect(engine.spotlight).to be_a(Legion::Extensions::Agentic::Attention::Spotlight::Helpers::Spotlight)
17
+ end
18
+
19
+ it 'starts with empty peripheral' do
20
+ expect(engine.peripheral).to be_empty
21
+ end
22
+ end
23
+
24
+ describe '#register_target' do
25
+ it 'registers a target and returns a target_id' do
26
+ result = register
27
+ expect(result[:registered]).to be true
28
+ expect(result[:target_id]).to match(/\A[0-9a-f-]{36}\z/)
29
+ end
30
+
31
+ it 'stores the target in @targets' do
32
+ result = register
33
+ expect(engine.targets).to have_key(result[:target_id])
34
+ end
35
+
36
+ it 'respects MAX_TARGETS limit' do
37
+ stub_const('Legion::Extensions::Agentic::Attention::Spotlight::Helpers::Constants::MAX_TARGETS', 2)
38
+ register(label: 'a')
39
+ register(label: 'b')
40
+ result = register(label: 'c')
41
+ expect(result[:registered]).to be false
42
+ expect(result[:reason]).to eq(:max_targets_reached)
43
+ end
44
+
45
+ it 'returns the label and domain' do
46
+ result = register(label: 'my task', domain: :health)
47
+ expect(result[:label]).to eq('my task')
48
+ expect(result[:domain]).to eq(:health)
49
+ end
50
+ end
51
+
52
+ describe '#focus' do
53
+ it 'focuses on a registered target' do
54
+ id = register[:target_id]
55
+ result = engine.focus(target_id: id)
56
+ expect(result[:focused]).to be true
57
+ expect(result[:mode]).to eq(:focused)
58
+ end
59
+
60
+ it 'marks the target as in_spotlight' do
61
+ id = register[:target_id]
62
+ engine.focus(target_id: id)
63
+ expect(engine.targets[id].in_spotlight).to be true
64
+ end
65
+
66
+ it 'returns not_found for unknown target_id' do
67
+ result = engine.focus(target_id: 'nonexistent')
68
+ expect(result[:focused]).to be false
69
+ expect(result[:reason]).to eq(:not_found)
70
+ end
71
+
72
+ it 'sets last_attended_at on the target' do
73
+ id = register[:target_id]
74
+ engine.focus(target_id: id)
75
+ expect(engine.targets[id].last_attended_at).to be_a(Time)
76
+ end
77
+
78
+ it 'clears previous spotlight focus when refocusing' do
79
+ id1 = register(label: 'first')[:target_id]
80
+ id2 = register(label: 'second')[:target_id]
81
+ engine.focus(target_id: id1)
82
+ engine.focus(target_id: id2)
83
+ expect(engine.targets[id1].in_spotlight).to be false
84
+ end
85
+ end
86
+
87
+ describe '#broaden' do
88
+ it 'increases spotlight breadth' do
89
+ initial = engine.spotlight.breadth
90
+ engine.broaden
91
+ expect(engine.spotlight.breadth).to be > initial
92
+ end
93
+
94
+ it 'returns broadened true with zoom_level' do
95
+ result = engine.broaden
96
+ expect(result[:broadened]).to be true
97
+ expect(result).to have_key(:zoom_level)
98
+ end
99
+ end
100
+
101
+ describe '#narrow' do
102
+ it 'decreases spotlight breadth' do
103
+ engine.broaden
104
+ before = engine.spotlight.breadth
105
+ engine.narrow
106
+ expect(engine.spotlight.breadth).to be < before
107
+ end
108
+
109
+ it 'returns narrowed true with zoom_level' do
110
+ result = engine.narrow
111
+ expect(result[:narrowed]).to be true
112
+ expect(result).to have_key(:zoom_level)
113
+ end
114
+ end
115
+
116
+ describe '#scan' do
117
+ it 'sets spotlight mode to scanning' do
118
+ 3.times { |i| register(label: "task #{i}") }
119
+ engine.scan
120
+ expect(engine.spotlight.mode).to eq(:scanning)
121
+ end
122
+
123
+ it 'returns targets_swept count' do
124
+ 3.times { |i| register(label: "task #{i}") }
125
+ result = engine.scan
126
+ expect(result[:targets_swept]).to eq(3)
127
+ end
128
+
129
+ it 'marks all targets as attended' do
130
+ ids = 3.times.map { |i| register(label: "task #{i}")[:target_id] }
131
+ engine.scan
132
+ ids.each do |id|
133
+ expect(engine.targets[id].last_attended_at).to be_a(Time)
134
+ end
135
+ end
136
+ end
137
+
138
+ describe '#check_peripheral' do
139
+ it 'detects salient targets outside spotlight' do
140
+ register(label: 'salient', salience: 0.6)
141
+ engine.check_peripheral
142
+ expect(engine.peripheral).not_to be_empty
143
+ end
144
+
145
+ it 'does not detect targets below threshold' do
146
+ register(label: 'low', salience: 0.1)
147
+ engine.check_peripheral
148
+ expect(engine.peripheral).to be_empty
149
+ end
150
+
151
+ it 'marks detected targets as in_periphery' do
152
+ id = register(label: 'salient', salience: 0.6)[:target_id]
153
+ engine.check_peripheral
154
+ expect(engine.targets[id].in_periphery).to be true
155
+ end
156
+
157
+ it 'respects MAX_PERIPHERAL limit' do
158
+ stub_const('Legion::Extensions::Agentic::Attention::Spotlight::Helpers::Constants::MAX_PERIPHERAL', 2)
159
+ 5.times { |i| register(label: "t#{i}", salience: 0.8) }
160
+ result = engine.check_peripheral
161
+ expect(result[:detected]).to be <= 2
162
+ end
163
+ end
164
+
165
+ describe '#check_capture' do
166
+ it 'returns captured false when no compelling target exists' do
167
+ register(label: 'low', salience: 0.3)
168
+ result = engine.check_capture
169
+ expect(result[:captured]).to be false
170
+ end
171
+
172
+ it 'captures the most salient compelling target' do
173
+ register(label: 'high', salience: 0.9)
174
+ result = engine.check_capture
175
+ expect(result[:captured]).to be true
176
+ expect(result[:salience]).to eq(0.9)
177
+ end
178
+
179
+ it 'sets spotlight mode to captured' do
180
+ register(label: 'urgent', salience: 0.85)
181
+ engine.check_capture
182
+ expect(engine.spotlight.mode).to eq(:captured)
183
+ end
184
+
185
+ it 'increments capture_count on the captured target' do
186
+ id = register(label: 'urgent', salience: 0.85)[:target_id]
187
+ engine.check_capture
188
+ expect(engine.targets[id].capture_count).to eq(1)
189
+ end
190
+
191
+ it 'does not capture the currently spotlighted target' do
192
+ id = register(label: 'current', salience: 0.9)[:target_id]
193
+ engine.focus(target_id: id)
194
+ register(label: 'other', salience: 0.85)
195
+ result = engine.check_capture
196
+ expect(result[:target_id]).not_to eq(id)
197
+ end
198
+ end
199
+
200
+ describe '#release_focus' do
201
+ it 'returns released true' do
202
+ result = engine.release_focus
203
+ expect(result[:released]).to be true
204
+ end
205
+
206
+ it 'clears all spotlight flags' do
207
+ id = register(label: 'focused')[:target_id]
208
+ engine.focus(target_id: id)
209
+ engine.release_focus
210
+ expect(engine.targets[id].in_spotlight).to be false
211
+ end
212
+
213
+ it 'sets spotlight mode to idle' do
214
+ engine.release_focus
215
+ expect(engine.spotlight.mode).to eq(:idle)
216
+ end
217
+ end
218
+
219
+ describe '#targets_in_spotlight' do
220
+ it 'returns empty when no focus is set' do
221
+ register(label: 'x')
222
+ expect(engine.targets_in_spotlight).to be_empty
223
+ end
224
+
225
+ it 'returns the focused target' do
226
+ id = register(label: 'focused task')[:target_id]
227
+ engine.focus(target_id: id)
228
+ result = engine.targets_in_spotlight
229
+ ids = result.map(&:id)
230
+ expect(ids).to include(id)
231
+ end
232
+ end
233
+
234
+ describe '#most_salient' do
235
+ it 'returns targets ordered by salience descending' do
236
+ register(label: 'low', salience: 0.2)
237
+ register(label: 'high', salience: 0.9)
238
+ register(label: 'mid', salience: 0.5)
239
+ result = engine.most_salient(limit: 3)
240
+ expect(result.map(&:salience)).to eq([0.9, 0.5, 0.2])
241
+ end
242
+
243
+ it 'respects the limit parameter' do
244
+ 5.times { |i| register(label: "t#{i}", salience: i * 0.1) }
245
+ expect(engine.most_salient(limit: 2).size).to eq(2)
246
+ end
247
+ end
248
+
249
+ describe '#spotlight_report' do
250
+ it 'includes spotlight, in_spotlight, in_periphery, most_salient, total_targets' do
251
+ register(label: 'x', salience: 0.6)
252
+ report = engine.spotlight_report
253
+ expect(report.keys).to include(:spotlight, :in_spotlight, :in_periphery, :most_salient, :total_targets)
254
+ end
255
+
256
+ it 'includes peripheral_count' do
257
+ register(label: 'p', salience: 0.6)
258
+ engine.check_peripheral
259
+ report = engine.spotlight_report
260
+ expect(report).to have_key(:peripheral_count)
261
+ end
262
+ end
263
+
264
+ describe '#to_h' do
265
+ it 'returns a hash with spotlight and target_count' do
266
+ h = engine.to_h
267
+ expect(h.keys).to include(:spotlight, :target_count, :peripheral_count, :spotlight_targets)
268
+ end
269
+
270
+ it 'reflects correct target_count' do
271
+ 3.times { |i| register(label: "t#{i}") }
272
+ expect(engine.to_h[:target_count]).to eq(3)
273
+ end
274
+ end
275
+ end