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,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::LatentInhibition::Client do
4
+ let(:client) { described_class.new }
5
+
6
+ it 'responds to all runner methods' do
7
+ %i[expose associate disinhibit novel_stimuli most_inhibited inhibition_report].each do |method|
8
+ expect(client).to respond_to(method)
9
+ end
10
+ end
11
+
12
+ it 'maintains state across calls on the default engine' do
13
+ client.expose(label: 'persistent')
14
+ client.expose(label: 'persistent')
15
+ report = client.inhibition_report
16
+ expect(report[:total_stimuli]).to eq(1)
17
+ end
18
+
19
+ it 'demonstrates the full latent inhibition cycle' do
20
+ # Pre-expose stimulus without consequence — builds inhibition
21
+ # 15 exposures => inhibition = 0.45, effectiveness = 0.55
22
+ 15.times { client.expose(label: 'neutral_tone') }
23
+
24
+ # Now try to form an association
25
+ result = client.associate(label: 'neutral_tone', outcome: 'shock')
26
+ expect(result[:effectiveness]).to be < 0.6
27
+
28
+ # Compare with a novel stimulus
29
+ novel_result = client.associate(label: 'new_tone', outcome: 'shock')
30
+ expect(novel_result[:effectiveness]).to be > result[:effectiveness]
31
+ end
32
+
33
+ it 'disinhibits a pre-exposed stimulus so it can learn again' do
34
+ 10.times { client.expose(label: 'primed') }
35
+ before_eff = client.associate(label: 'primed', outcome: 'test')[:effectiveness]
36
+
37
+ client.disinhibit(label: 'primed', intensity: 1.0)
38
+ after_eff = client.associate(label: 'primed', outcome: 'test')[:effectiveness]
39
+
40
+ expect(after_eff).to be > before_eff
41
+ end
42
+
43
+ it 'identifies novel stimuli correctly' do
44
+ client.expose(label: 'brand_new')
45
+ result = client.novel_stimuli
46
+ labels = result[:stimuli].map { |s| s[:label] }
47
+ expect(labels).to include('brand_new')
48
+ end
49
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants do
4
+ describe 'MAX_STIMULI' do
5
+ it 'is 500' do
6
+ expect(described_class::MAX_STIMULI).to eq(500)
7
+ end
8
+ end
9
+
10
+ describe 'INHIBITION_RATE' do
11
+ it 'is 0.03' do
12
+ expect(described_class::INHIBITION_RATE).to eq(0.03)
13
+ end
14
+ end
15
+
16
+ describe 'DISINHIBITION_RATE' do
17
+ it 'is 0.2' do
18
+ expect(described_class::DISINHIBITION_RATE).to eq(0.2)
19
+ end
20
+ end
21
+
22
+ describe 'NOVELTY_THRESHOLD' do
23
+ it 'is 3' do
24
+ expect(described_class::NOVELTY_THRESHOLD).to eq(3)
25
+ end
26
+ end
27
+
28
+ describe 'INHIBITION_LABELS' do
29
+ it 'covers the full 0.0..1.0 range' do
30
+ scores = [0.0, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0]
31
+ scores.each do |score|
32
+ match = described_class::INHIBITION_LABELS.find { |range, _| range.cover?(score) }
33
+ expect(match).not_to be_nil, "no label found for score #{score}"
34
+ end
35
+ end
36
+
37
+ it 'labels 0.0 as uninhibited' do
38
+ label = described_class::INHIBITION_LABELS.find { |range, _| range.cover?(0.0) }&.last
39
+ expect(label).to eq(:uninhibited)
40
+ end
41
+
42
+ it 'labels 1.0 as saturated' do
43
+ label = described_class::INHIBITION_LABELS.find { |range, _| range.cover?(1.0) }&.last
44
+ expect(label).to eq(:saturated)
45
+ end
46
+ end
47
+
48
+ describe 'NOVELTY_LABELS' do
49
+ it 'maps true to :novel' do
50
+ expect(described_class::NOVELTY_LABELS[true]).to eq(:novel)
51
+ end
52
+
53
+ it 'maps false to :familiar' do
54
+ expect(described_class::NOVELTY_LABELS[false]).to eq(:familiar)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::InhibitionEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ describe '#expose_stimulus' do
7
+ it 'returns a hash with stimulus data' do
8
+ result = engine.expose_stimulus(label: 'bell')
9
+ expect(result).to be_a(Hash)
10
+ expect(result[:label]).to eq('bell')
11
+ end
12
+
13
+ it 'increments exposure_count on repeated calls' do
14
+ engine.expose_stimulus(label: 'bell')
15
+ result = engine.expose_stimulus(label: 'bell')
16
+ expect(result[:exposure_count]).to eq(2)
17
+ end
18
+
19
+ it 'raises inhibition_score over time' do
20
+ result1 = engine.expose_stimulus(label: 'tone')
21
+ result2 = engine.expose_stimulus(label: 'tone')
22
+ expect(result2[:inhibition_score]).to be > result1[:inhibition_score]
23
+ end
24
+
25
+ it 'tracks novel status correctly' do
26
+ result = engine.expose_stimulus(label: 'new_thing')
27
+ expect(result[:novel]).to be(true)
28
+ end
29
+
30
+ it 'marks stimulus as not novel after threshold exposures' do
31
+ threshold = Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::NOVELTY_THRESHOLD
32
+ threshold.times { engine.expose_stimulus(label: 'frequent') }
33
+ result = engine.expose_stimulus(label: 'frequent')
34
+ expect(result[:novel]).to be(false)
35
+ end
36
+
37
+ it 'creates distinct stimuli for different labels' do
38
+ engine.expose_stimulus(label: 'a')
39
+ engine.expose_stimulus(label: 'b')
40
+ report = engine.inhibition_report
41
+ expect(report[:total_stimuli]).to eq(2)
42
+ end
43
+ end
44
+
45
+ describe '#attempt_association' do
46
+ it 'returns a hash with outcome and effectiveness' do
47
+ result = engine.attempt_association(label: 'bell', outcome: 'food')
48
+ expect(result[:outcome]).to eq('food')
49
+ expect(result[:effectiveness]).to be_between(0.0, 1.0)
50
+ end
51
+
52
+ it 'returns high effectiveness for novel stimulus' do
53
+ result = engine.attempt_association(label: 'new', outcome: 'reward')
54
+ expect(result[:effectiveness]).to be_within(0.001).of(1.0)
55
+ end
56
+
57
+ it 'returns reduced effectiveness after many exposures' do
58
+ 20.times { engine.expose_stimulus(label: 'old') }
59
+ result = engine.attempt_association(label: 'old', outcome: 'reward')
60
+ expect(result[:effectiveness]).to be < 0.5
61
+ end
62
+
63
+ it 'marks association as blocked when effectiveness is very low' do
64
+ 50.times { engine.expose_stimulus(label: 'saturated') }
65
+ result = engine.attempt_association(label: 'saturated', outcome: 'something')
66
+ expect(result[:blocked]).to be(true)
67
+ end
68
+
69
+ it 'includes inhibition_score and inhibition_label' do
70
+ result = engine.attempt_association(label: 'bell', outcome: 'food')
71
+ expect(result).to have_key(:inhibition_score)
72
+ expect(result).to have_key(:inhibition_label)
73
+ end
74
+ end
75
+
76
+ describe '#disinhibit' do
77
+ it 'returns not_found status for unknown label' do
78
+ result = engine.disinhibit(label: 'unknown', intensity: 1.0)
79
+ expect(result[:status]).to eq(:not_found)
80
+ end
81
+
82
+ it 'reduces inhibition_score for known stimulus' do
83
+ 10.times { engine.expose_stimulus(label: 'bell') }
84
+ result = engine.disinhibit(label: 'bell', intensity: 1.0)
85
+ expect(result[:new_score]).to be < result[:prior_score]
86
+ end
87
+
88
+ it 'returns prior_score and new_score' do
89
+ 5.times { engine.expose_stimulus(label: 'tone') }
90
+ result = engine.disinhibit(label: 'tone', intensity: 0.5)
91
+ expect(result[:prior_score]).to be > 0.0
92
+ expect(result[:new_score]).to be < result[:prior_score]
93
+ end
94
+
95
+ it 'includes reduction amount' do
96
+ 5.times { engine.expose_stimulus(label: 'cue') }
97
+ result = engine.disinhibit(label: 'cue', intensity: 1.0)
98
+ expect(result[:reduction]).to be_within(0.001).of(result[:prior_score] - result[:new_score])
99
+ end
100
+ end
101
+
102
+ describe '#novel_stimuli' do
103
+ it 'returns empty array when no stimuli exist' do
104
+ expect(engine.novel_stimuli).to be_empty
105
+ end
106
+
107
+ it 'returns novel stimuli' do
108
+ engine.expose_stimulus(label: 'fresh')
109
+ stimuli = engine.novel_stimuli
110
+ expect(stimuli.map { |s| s[:label] }).to include('fresh')
111
+ end
112
+
113
+ it 'excludes familiar stimuli' do
114
+ threshold = Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::NOVELTY_THRESHOLD
115
+ (threshold + 1).times { engine.expose_stimulus(label: 'old') }
116
+ stimuli = engine.novel_stimuli
117
+ expect(stimuli.map { |s| s[:label] }).not_to include('old')
118
+ end
119
+ end
120
+
121
+ describe '#most_inhibited' do
122
+ before do
123
+ 5.times { engine.expose_stimulus(label: 'low') }
124
+ 20.times { engine.expose_stimulus(label: 'high') }
125
+ engine.expose_stimulus(label: 'fresh')
126
+ end
127
+
128
+ it 'returns stimuli ordered by inhibition_score descending' do
129
+ stimuli = engine.most_inhibited(limit: 3)
130
+ scores = stimuli.map { |s| s[:inhibition_score] }
131
+ expect(scores).to eq(scores.sort.reverse)
132
+ end
133
+
134
+ it 'respects the limit parameter' do
135
+ stimuli = engine.most_inhibited(limit: 2)
136
+ expect(stimuli.size).to be <= 2
137
+ end
138
+
139
+ it 'includes the most inhibited stimulus first' do
140
+ stimuli = engine.most_inhibited(limit: 1)
141
+ expect(stimuli.first[:label]).to eq('high')
142
+ end
143
+ end
144
+
145
+ describe '#inhibition_report' do
146
+ it 'returns empty report when no stimuli exist' do
147
+ report = engine.inhibition_report
148
+ expect(report[:total_stimuli]).to eq(0)
149
+ expect(report[:mean_inhibition]).to eq(0.0)
150
+ end
151
+
152
+ it 'counts total stimuli correctly' do
153
+ engine.expose_stimulus(label: 'a')
154
+ engine.expose_stimulus(label: 'b')
155
+ expect(engine.inhibition_report[:total_stimuli]).to eq(2)
156
+ end
157
+
158
+ it 'counts novel stimuli' do
159
+ engine.expose_stimulus(label: 'new')
160
+ report = engine.inhibition_report
161
+ expect(report[:novel_count]).to eq(1)
162
+ end
163
+
164
+ it 'computes mean_inhibition' do
165
+ engine.expose_stimulus(label: 'x')
166
+ report = engine.inhibition_report
167
+ expect(report[:mean_inhibition]).to be > 0.0
168
+ end
169
+
170
+ it 'includes max_inhibition' do
171
+ 10.times { engine.expose_stimulus(label: 'heavy') }
172
+ engine.expose_stimulus(label: 'light')
173
+ report = engine.inhibition_report
174
+ expect(report[:max_inhibition]).to be > report[:mean_inhibition]
175
+ end
176
+
177
+ it 'includes label_breakdown hash' do
178
+ engine.expose_stimulus(label: 'x')
179
+ report = engine.inhibition_report
180
+ expect(report[:label_breakdown]).to be_a(Hash)
181
+ end
182
+
183
+ it 'counts saturated stimuli' do
184
+ 50.times { engine.expose_stimulus(label: 'saturated') }
185
+ report = engine.inhibition_report
186
+ expect(report[:saturated_count]).to eq(1)
187
+ end
188
+ end
189
+
190
+ describe '#prune_if_needed' do
191
+ it 'prunes oldest stimuli when MAX_STIMULI is exceeded' do
192
+ max = Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::MAX_STIMULI
193
+ (max + 5).times { |i| engine.expose_stimulus(label: "stim_#{i}") }
194
+ report = engine.inhibition_report
195
+ expect(report[:total_stimuli]).to be <= max
196
+ end
197
+ end
198
+
199
+ describe '#to_h' do
200
+ it 'includes stimuli and report keys' do
201
+ engine.expose_stimulus(label: 'test')
202
+ h = engine.to_h
203
+ expect(h).to have_key(:stimuli)
204
+ expect(h).to have_key(:report)
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,175 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::StimulusRecord do
4
+ subject(:record) { described_class.new(label: 'test_stimulus') }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a UUID id' do
8
+ expect(record.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets label' do
12
+ expect(record.label).to eq('test_stimulus')
13
+ end
14
+
15
+ it 'starts with zero exposure_count' do
16
+ expect(record.exposure_count).to eq(0)
17
+ end
18
+
19
+ it 'starts with zero inhibition_score' do
20
+ expect(record.inhibition_score).to eq(0.0)
21
+ end
22
+
23
+ it 'starts with nil last_exposed_at' do
24
+ expect(record.last_exposed_at).to be_nil
25
+ end
26
+
27
+ it 'starts with empty associations' do
28
+ expect(record.associations).to be_empty
29
+ end
30
+ end
31
+
32
+ describe '#expose!' do
33
+ it 'increments exposure_count' do
34
+ record.expose!
35
+ expect(record.exposure_count).to eq(1)
36
+ end
37
+
38
+ it 'raises inhibition_score by INHIBITION_RATE' do
39
+ record.expose!
40
+ expect(record.inhibition_score).to be_within(0.0001).of(
41
+ Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::INHIBITION_RATE
42
+ )
43
+ end
44
+
45
+ it 'sets last_exposed_at' do
46
+ record.expose!
47
+ expect(record.last_exposed_at).to be_a(Time)
48
+ end
49
+
50
+ it 'returns self for chaining' do
51
+ expect(record.expose!).to eq(record)
52
+ end
53
+
54
+ it 'clamps inhibition_score at 1.0 after many exposures' do
55
+ 50.times { record.expose! }
56
+ expect(record.inhibition_score).to be <= 1.0
57
+ end
58
+
59
+ it 'accumulates inhibition with multiple exposures' do
60
+ 3.times { record.expose! }
61
+ expected = (Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::INHIBITION_RATE * 3).round(10)
62
+ expect(record.inhibition_score).to be_within(0.0001).of(expected)
63
+ end
64
+ end
65
+
66
+ describe '#associate!' do
67
+ it 'returns effectiveness of 1.0 for uninhibited stimulus' do
68
+ effectiveness = record.associate!(outcome: 'reward')
69
+ expect(effectiveness).to be_within(0.001).of(1.0)
70
+ end
71
+
72
+ it 'returns reduced effectiveness for inhibited stimulus' do
73
+ 20.times { record.expose! }
74
+ effectiveness = record.associate!(outcome: 'reward')
75
+ expect(effectiveness).to be < 1.0
76
+ end
77
+
78
+ it 'appends to associations array' do
79
+ record.associate!(outcome: 'reward')
80
+ expect(record.associations.size).to eq(1)
81
+ expect(record.associations.first[:outcome]).to eq('reward')
82
+ end
83
+
84
+ it 'stores effectiveness in association record' do
85
+ eff = record.associate!(outcome: 'pain')
86
+ expect(record.associations.last[:effectiveness]).to eq(eff)
87
+ end
88
+
89
+ it 'stores recorded_at timestamp' do
90
+ record.associate!(outcome: 'neutral')
91
+ expect(record.associations.last[:recorded_at]).to be_a(Time)
92
+ end
93
+
94
+ it 'rounds effectiveness to 10 decimal places' do
95
+ 20.times { record.expose! }
96
+ eff = record.associate!(outcome: 'test')
97
+ expect(eff.to_s.split('.').last.length).to be <= 10
98
+ end
99
+ end
100
+
101
+ describe '#disinhibit!' do
102
+ before { 10.times { record.expose! } }
103
+
104
+ it 'reduces inhibition_score' do
105
+ prior = record.inhibition_score
106
+ record.disinhibit!(intensity: 1.0)
107
+ expect(record.inhibition_score).to be < prior
108
+ end
109
+
110
+ it 'clamps score at 0.0 when reduction exceeds current score' do
111
+ # 3 exposures => score = 0.09, which is less than DISINHIBITION_RATE (0.2)
112
+ fresh = Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::StimulusRecord.new(label: 'tiny')
113
+ 3.times { fresh.expose! }
114
+ fresh.disinhibit!(intensity: 1.0)
115
+ expect(fresh.inhibition_score).to eq(0.0)
116
+ end
117
+
118
+ it 'returns self for chaining' do
119
+ expect(record.disinhibit!(intensity: 0.5)).to eq(record)
120
+ end
121
+
122
+ it 'applies partial disinhibition proportionally to intensity' do
123
+ prior = record.inhibition_score
124
+ record.disinhibit!(intensity: 0.5)
125
+ expected_reduction = (Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::DISINHIBITION_RATE * 0.5).round(10)
126
+ expect(prior - record.inhibition_score).to be_within(0.0001).of(expected_reduction)
127
+ end
128
+
129
+ it 'clamps intensity to [0.0, 1.0] before applying' do
130
+ prior = record.inhibition_score
131
+ record.disinhibit!(intensity: 5.0)
132
+ max_reduction = Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::DISINHIBITION_RATE
133
+ expect(prior - record.inhibition_score).to be_within(0.0001).of(max_reduction)
134
+ end
135
+ end
136
+
137
+ describe '#novel?' do
138
+ it 'returns true when exposure_count < NOVELTY_THRESHOLD' do
139
+ expect(record.novel?).to be(true)
140
+ end
141
+
142
+ it 'returns false after NOVELTY_THRESHOLD or more exposures' do
143
+ Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::Constants::NOVELTY_THRESHOLD.times { record.expose! }
144
+ expect(record.novel?).to be(false)
145
+ end
146
+ end
147
+
148
+ describe '#inhibition_label' do
149
+ it 'returns :uninhibited for a new record' do
150
+ expect(record.inhibition_label).to eq(:uninhibited)
151
+ end
152
+
153
+ it 'returns :saturated after many exposures' do
154
+ 50.times { record.expose! }
155
+ expect(record.inhibition_label).to eq(:saturated)
156
+ end
157
+ end
158
+
159
+ describe '#to_h' do
160
+ before { record.expose! }
161
+
162
+ it 'includes all expected keys' do
163
+ h = record.to_h
164
+ %i[id label exposure_count inhibition_score inhibition_label novel last_exposed_at associations].each do |key|
165
+ expect(h).to have_key(key)
166
+ end
167
+ end
168
+
169
+ it 'reflects current state' do
170
+ h = record.to_h
171
+ expect(h[:exposure_count]).to eq(1)
172
+ expect(h[:label]).to eq('test_stimulus')
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::LatentInhibition::Runners::LatentInhibition do
4
+ let(:engine) { Legion::Extensions::Agentic::Attention::LatentInhibition::Helpers::InhibitionEngine.new }
5
+ let(:client) { Legion::Extensions::Agentic::Attention::LatentInhibition::Client.new }
6
+
7
+ describe '#expose' do
8
+ it 'returns a hash with exposure data' do
9
+ result = client.expose(label: 'bell', engine: engine)
10
+ expect(result).to be_a(Hash)
11
+ expect(result[:label]).to eq('bell')
12
+ expect(result[:exposure_count]).to eq(1)
13
+ end
14
+
15
+ it 'increments exposure on repeated calls' do
16
+ client.expose(label: 'bell', engine: engine)
17
+ result = client.expose(label: 'bell', engine: engine)
18
+ expect(result[:exposure_count]).to eq(2)
19
+ end
20
+
21
+ it 'includes inhibition_score' do
22
+ result = client.expose(label: 'tone', engine: engine)
23
+ expect(result).to have_key(:inhibition_score)
24
+ end
25
+
26
+ it 'includes novel status' do
27
+ result = client.expose(label: 'new', engine: engine)
28
+ expect(result[:novel]).to be(true)
29
+ end
30
+
31
+ it 'uses default engine when none provided' do
32
+ result = client.expose(label: 'default_test')
33
+ expect(result[:label]).to eq('default_test')
34
+ end
35
+ end
36
+
37
+ describe '#associate' do
38
+ it 'returns a hash with effectiveness' do
39
+ result = client.associate(label: 'bell', outcome: 'food', engine: engine)
40
+ expect(result[:effectiveness]).to be_between(0.0, 1.0)
41
+ end
42
+
43
+ it 'returns full effectiveness for fresh stimulus' do
44
+ result = client.associate(label: 'fresh', outcome: 'reward', engine: engine)
45
+ expect(result[:effectiveness]).to be_within(0.001).of(1.0)
46
+ end
47
+
48
+ it 'returns reduced effectiveness after pre-exposure' do
49
+ 20.times { engine.expose_stimulus(label: 'pre_exposed') }
50
+ result = client.associate(label: 'pre_exposed', outcome: 'reward', engine: engine)
51
+ expect(result[:effectiveness]).to be < 0.5
52
+ end
53
+
54
+ it 'includes blocked flag' do
55
+ result = client.associate(label: 'fresh', outcome: 'test', engine: engine)
56
+ expect(result).to have_key(:blocked)
57
+ end
58
+
59
+ it 'marks association as blocked after saturation' do
60
+ 50.times { engine.expose_stimulus(label: 'saturated') }
61
+ result = client.associate(label: 'saturated', outcome: 'anything', engine: engine)
62
+ expect(result[:blocked]).to be(true)
63
+ end
64
+ end
65
+
66
+ describe '#disinhibit' do
67
+ it 'returns not_found for unknown stimulus' do
68
+ result = client.disinhibit(label: 'unknown', engine: engine)
69
+ expect(result[:status]).to eq(:not_found)
70
+ end
71
+
72
+ it 'reduces inhibition after significant event' do
73
+ 10.times { engine.expose_stimulus(label: 'conditioned') }
74
+ result = client.disinhibit(label: 'conditioned', intensity: 1.0, engine: engine)
75
+ expect(result[:new_score]).to be < result[:prior_score]
76
+ end
77
+
78
+ it 'defaults intensity to 1.0' do
79
+ 5.times { engine.expose_stimulus(label: 'cue') }
80
+ result = client.disinhibit(label: 'cue', engine: engine)
81
+ expect(result[:reduction]).to be > 0.0
82
+ end
83
+ end
84
+
85
+ describe '#novel_stimuli' do
86
+ it 'returns hash with stimuli and count' do
87
+ result = client.novel_stimuli(engine: engine)
88
+ expect(result).to have_key(:stimuli)
89
+ expect(result).to have_key(:count)
90
+ end
91
+
92
+ it 'returns novel stimuli list' do
93
+ engine.expose_stimulus(label: 'new_thing')
94
+ result = client.novel_stimuli(engine: engine)
95
+ expect(result[:count]).to eq(1)
96
+ end
97
+
98
+ it 'count matches stimuli array size' do
99
+ engine.expose_stimulus(label: 'a')
100
+ engine.expose_stimulus(label: 'b')
101
+ result = client.novel_stimuli(engine: engine)
102
+ expect(result[:count]).to eq(result[:stimuli].size)
103
+ end
104
+ end
105
+
106
+ describe '#most_inhibited' do
107
+ before do
108
+ 5.times { engine.expose_stimulus(label: 'mid') }
109
+ 20.times { engine.expose_stimulus(label: 'top') }
110
+ end
111
+
112
+ it 'returns hash with stimuli and count' do
113
+ result = client.most_inhibited(engine: engine)
114
+ expect(result).to have_key(:stimuli)
115
+ expect(result).to have_key(:count)
116
+ end
117
+
118
+ it 'respects limit parameter' do
119
+ result = client.most_inhibited(limit: 1, engine: engine)
120
+ expect(result[:stimuli].size).to eq(1)
121
+ end
122
+
123
+ it 'returns most inhibited first' do
124
+ result = client.most_inhibited(limit: 2, engine: engine)
125
+ expect(result[:stimuli].first[:label]).to eq('top')
126
+ end
127
+ end
128
+
129
+ describe '#inhibition_report' do
130
+ it 'returns a report hash' do
131
+ result = client.inhibition_report(engine: engine)
132
+ expect(result[:total_stimuli]).to eq(0)
133
+ end
134
+
135
+ it 'reflects current engine state' do
136
+ engine.expose_stimulus(label: 'tracked')
137
+ result = client.inhibition_report(engine: engine)
138
+ expect(result[:total_stimuli]).to eq(1)
139
+ end
140
+
141
+ it 'includes all required report fields' do
142
+ result = client.inhibition_report(engine: engine)
143
+ %i[total_stimuli novel_count inhibited_count saturated_count mean_inhibition max_inhibition label_breakdown].each do |key|
144
+ expect(result).to have_key(key)
145
+ end
146
+ end
147
+ end
148
+ end