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,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/economy/helpers/demand'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::Economy::Helpers::Demand do
6
+ subject(:demand) do
7
+ described_class.new(label: 'test task', demand_type: :task, priority: 0.7, cost: 0.3, roi: 0.9)
8
+ end
9
+
10
+ describe '#initialize' do
11
+ it 'assigns a uuid id' do
12
+ expect(demand.id).to match(/\A[0-9a-f-]{36}\z/)
13
+ end
14
+
15
+ it 'stores label' do
16
+ expect(demand.label).to eq('test task')
17
+ end
18
+
19
+ it 'stores demand_type' do
20
+ expect(demand.demand_type).to eq(:task)
21
+ end
22
+
23
+ it 'clamps priority to [0.0, 1.0]' do
24
+ d = described_class.new(label: 'x', demand_type: :task, priority: 1.5, cost: 0.1)
25
+ expect(d.priority).to eq(1.0)
26
+ end
27
+
28
+ it 'clamps cost to [0.0, 1.0]' do
29
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: -0.1)
30
+ expect(d.cost).to eq(0.0)
31
+ end
32
+
33
+ it 'clamps roi to [0.0, 1.0]' do
34
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.1, roi: 2.0)
35
+ expect(d.roi).to eq(1.0)
36
+ end
37
+
38
+ it 'defaults roi to 0.5' do
39
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.1)
40
+ expect(d.roi).to eq(0.5)
41
+ end
42
+
43
+ it 'starts with 0.0 allocated' do
44
+ expect(demand.allocated).to eq(0.0)
45
+ end
46
+
47
+ it 'sets created_at' do
48
+ expect(demand.created_at).to be_a(Time)
49
+ end
50
+ end
51
+
52
+ describe '#allocate!' do
53
+ it 'sets allocated amount' do
54
+ demand.allocate!(amount: 0.25)
55
+ expect(demand.allocated).to eq(0.25)
56
+ end
57
+
58
+ it 'clamps allocated to [0.0, 1.0]' do
59
+ demand.allocate!(amount: 1.5)
60
+ expect(demand.allocated).to eq(1.0)
61
+ end
62
+ end
63
+
64
+ describe '#deallocate!' do
65
+ it 'resets allocated to 0.0' do
66
+ demand.allocate!(amount: 0.3)
67
+ demand.deallocate!
68
+ expect(demand.allocated).to eq(0.0)
69
+ end
70
+ end
71
+
72
+ describe '#efficiency' do
73
+ it 'computes roi / cost' do
74
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.5, roi: 1.0)
75
+ expect(d.efficiency).to eq(1.0)
76
+ end
77
+
78
+ it 'returns 0.0 when cost is zero' do
79
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.0, roi: 0.8)
80
+ expect(d.efficiency).to eq(0.0)
81
+ end
82
+
83
+ it 'clamps efficiency to [0.0, 1.0]' do
84
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.1, roi: 1.0)
85
+ expect(d.efficiency).to be <= 1.0
86
+ end
87
+ end
88
+
89
+ describe '#efficiency_label' do
90
+ it 'returns :excellent for high efficiency' do
91
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.1, roi: 1.0)
92
+ expect(d.efficiency_label).to eq(:excellent)
93
+ end
94
+
95
+ it 'returns :wasted for zero efficiency' do
96
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.5, cost: 0.0, roi: 0.0)
97
+ expect(d.efficiency_label).to eq(:wasted)
98
+ end
99
+ end
100
+
101
+ describe '#priority_label' do
102
+ it 'returns :critical for priority 0.9' do
103
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.9, cost: 0.1)
104
+ expect(d.priority_label).to eq(:critical)
105
+ end
106
+
107
+ it 'returns :high for priority 0.7' do
108
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.7, cost: 0.1)
109
+ expect(d.priority_label).to eq(:high)
110
+ end
111
+
112
+ it 'returns :background for priority 0.1' do
113
+ d = described_class.new(label: 'x', demand_type: :task, priority: 0.1, cost: 0.1)
114
+ expect(d.priority_label).to eq(:background)
115
+ end
116
+ end
117
+
118
+ describe '#to_h' do
119
+ it 'includes all fields' do
120
+ h = demand.to_h
121
+ expect(h).to include(:id, :label, :demand_type, :priority, :priority_label, :cost, :roi, :allocated, :efficiency, :efficiency_label, :created_at)
122
+ end
123
+
124
+ it 'priority_label is correct in to_h' do
125
+ expect(demand.to_h[:priority_label]).to eq(:high)
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/economy/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::Economy::Runners::AttentionEconomy do
6
+ let(:client) { Legion::Extensions::Agentic::Attention::Economy::Client.new }
7
+
8
+ def add_task(label: 'test', demand_type: :task, priority: 0.5, cost: 0.2, roi: 0.6)
9
+ client.add_demand(label: label, demand_type: demand_type, priority: priority, cost: cost, roi: roi)
10
+ end
11
+
12
+ describe '#add_demand' do
13
+ it 'returns created: true on success' do
14
+ result = add_task
15
+ expect(result[:created]).to be true
16
+ end
17
+
18
+ it 'returns demand hash on success' do
19
+ result = add_task
20
+ expect(result[:demand]).to include(:id, :label, :priority, :cost, :roi)
21
+ end
22
+
23
+ it 'returns created: false for invalid demand_type' do
24
+ result = client.add_demand(label: 'x', demand_type: :invalid, priority: 0.5, cost: 0.1)
25
+ expect(result[:created]).to be false
26
+ expect(result[:reason]).to include('demand_type')
27
+ end
28
+
29
+ it 'supports all valid demand types' do
30
+ %i[task sensory social emotional cognitive maintenance].each do |type|
31
+ result = client.add_demand(label: type.to_s, demand_type: type, priority: 0.5, cost: 0.1)
32
+ expect(result[:created]).to be true
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#allocate_demand' do
38
+ it 'allocates existing demand' do
39
+ demand_id = add_task[:demand][:id]
40
+ result = client.allocate_demand(demand_id: demand_id)
41
+ expect(result[:allocated]).to be true
42
+ end
43
+
44
+ it 'includes remaining budget in result' do
45
+ demand_id = add_task(cost: 0.3)[:demand][:id]
46
+ result = client.allocate_demand(demand_id: demand_id)
47
+ expect(result[:remaining]).to be_within(0.001).of(0.7)
48
+ end
49
+
50
+ it 'returns allocated: false for unknown demand' do
51
+ result = client.allocate_demand(demand_id: 'nonexistent')
52
+ expect(result[:allocated]).to be false
53
+ end
54
+
55
+ it 'supports explicit amount override' do
56
+ demand_id = add_task(cost: 0.3)[:demand][:id]
57
+ result = client.allocate_demand(demand_id: demand_id, amount: 0.1)
58
+ expect(result[:amount]).to eq(0.1)
59
+ end
60
+ end
61
+
62
+ describe '#deallocate_demand' do
63
+ it 'deallocates allocated demand' do
64
+ demand_id = add_task(cost: 0.3)[:demand][:id]
65
+ client.allocate_demand(demand_id: demand_id)
66
+ result = client.deallocate_demand(demand_id: demand_id)
67
+ expect(result[:deallocated]).to be true
68
+ end
69
+
70
+ it 'frees the allocated amount' do
71
+ demand_id = add_task(cost: 0.3)[:demand][:id]
72
+ client.allocate_demand(demand_id: demand_id)
73
+ result = client.deallocate_demand(demand_id: demand_id)
74
+ expect(result[:freed]).to be_within(0.001).of(0.3)
75
+ end
76
+ end
77
+
78
+ describe '#recover_budget' do
79
+ it 'recovers budget using default rate' do
80
+ demand_id = add_task(cost: 0.3)[:demand][:id]
81
+ client.allocate_demand(demand_id: demand_id)
82
+ result = client.recover_budget
83
+ expect(result[:recovered]).to be > 0
84
+ end
85
+
86
+ it 'accepts custom recovery amount' do
87
+ demand_id = add_task(cost: 0.5)[:demand][:id]
88
+ client.allocate_demand(demand_id: demand_id)
89
+ result = client.recover_budget(amount: 0.2)
90
+ expect(result[:spent]).to be_within(0.001).of(0.3)
91
+ end
92
+ end
93
+
94
+ describe '#prioritized_demands' do
95
+ it 'returns demands sorted by priority descending' do
96
+ client.add_demand(label: 'low', demand_type: :task, priority: 0.1, cost: 0.1)
97
+ client.add_demand(label: 'high', demand_type: :task, priority: 0.9, cost: 0.1)
98
+ result = client.prioritized_demands
99
+ expect(result[:demands].first[:priority]).to be >= result[:demands].last[:priority]
100
+ end
101
+
102
+ it 'returns count of demands' do
103
+ add_task(label: 'a')
104
+ add_task(label: 'b')
105
+ expect(client.prioritized_demands[:count]).to eq(2)
106
+ end
107
+ end
108
+
109
+ describe '#best_roi_demands' do
110
+ it 'returns top demands by efficiency' do
111
+ client.add_demand(label: 'poor', demand_type: :task, priority: 0.5, cost: 0.9, roi: 0.1)
112
+ client.add_demand(label: 'great', demand_type: :task, priority: 0.5, cost: 0.1, roi: 0.9)
113
+ result = client.best_roi_demands(limit: 1)
114
+ expect(result[:demands].first[:label]).to eq('great')
115
+ end
116
+
117
+ it 'defaults limit to 5' do
118
+ 6.times { |i| add_task(label: "d#{i}") }
119
+ result = client.best_roi_demands
120
+ expect(result[:count]).to eq(5)
121
+ end
122
+ end
123
+
124
+ describe '#rebalance_budget' do
125
+ it 'returns rebalanced key' do
126
+ result = client.rebalance_budget
127
+ expect(result).to have_key(:rebalanced)
128
+ end
129
+
130
+ it 'returns 0 when not over budget' do
131
+ result = client.rebalance_budget
132
+ expect(result[:rebalanced]).to eq(0)
133
+ end
134
+ end
135
+
136
+ describe '#attention_status' do
137
+ it 'returns budget report keys' do
138
+ result = client.attention_status
139
+ %i[total_budget spent available utilization demand_count].each do |key|
140
+ expect(result).to have_key(key)
141
+ end
142
+ end
143
+
144
+ it 'reflects demand count' do
145
+ add_task
146
+ expect(client.attention_status[:demand_count]).to eq(1)
147
+ end
148
+ end
149
+
150
+ describe '#attention_snapshot' do
151
+ it 'includes demands array' do
152
+ add_task
153
+ result = client.attention_snapshot
154
+ expect(result[:demands]).to be_an(Array)
155
+ expect(result[:demands].size).to eq(1)
156
+ end
157
+
158
+ it 'includes budget metrics' do
159
+ result = client.attention_snapshot
160
+ expect(result).to include(:total_budget, :spent, :available)
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/attention/feature_binding/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Attention::FeatureBinding::Client do
6
+ subject(:client) { described_class.new }
7
+
8
+ it 'registers and binds features' do
9
+ client.register_feature(id: 'f:red', dimension: :color, value: :red)
10
+ client.register_feature(id: 'f:circle', dimension: :shape, value: :circle)
11
+ result = client.bind_features(feature_ids: %w[f:red f:circle], attention: true)
12
+ expect(result[:success]).to be true
13
+ expect(result[:object][:confirmed]).to be true
14
+ end
15
+
16
+ it 'reports stats' do
17
+ result = client.feature_binding_stats
18
+ expect(result[:success]).to be true
19
+ end
20
+ end
@@ -0,0 +1,207 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::BindingField do
4
+ subject(:field) { described_class.new }
5
+
6
+ let(:constants) { Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Constants }
7
+
8
+ def register_pair
9
+ field.register_feature(id: 'f:red', dimension: :color, value: :red)
10
+ field.register_feature(id: 'f:circle', dimension: :shape, value: :circle)
11
+ end
12
+
13
+ describe '#register_feature' do
14
+ it 'adds a feature' do
15
+ f = field.register_feature(id: 'f:red', dimension: :color, value: :red)
16
+ expect(f).to be_a(Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Feature)
17
+ expect(field.feature_count).to eq(1)
18
+ end
19
+
20
+ it 'returns existing feature on duplicate id' do
21
+ first = field.register_feature(id: 'f:red', dimension: :color, value: :red)
22
+ second = field.register_feature(id: 'f:red', dimension: :color, value: :blue)
23
+ expect(second).to equal(first)
24
+ expect(field.feature_count).to eq(1)
25
+ end
26
+
27
+ it 'enforces MAX_FEATURES limit' do
28
+ constants::MAX_FEATURES.times do |i|
29
+ field.register_feature(id: "f:#{i}", dimension: :color, value: i)
30
+ end
31
+ result = field.register_feature(id: 'f:overflow', dimension: :color, value: :x)
32
+ expect(result).to be_nil
33
+ end
34
+ end
35
+
36
+ describe '#bind' do
37
+ it 'creates a bound object from feature ids' do
38
+ register_pair
39
+ obj = field.bind(feature_ids: %w[f:red f:circle])
40
+ expect(obj).to be_a(Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::BoundObject)
41
+ expect(field.object_count).to eq(1)
42
+ end
43
+
44
+ it 'returns nil with fewer than 2 valid features' do
45
+ field.register_feature(id: 'f:red', dimension: :color, value: :red)
46
+ expect(field.bind(feature_ids: %w[f:red])).to be_nil
47
+ end
48
+
49
+ it 'ignores unknown feature ids' do
50
+ field.register_feature(id: 'f:red', dimension: :color, value: :red)
51
+ expect(field.bind(feature_ids: %w[f:red f:nonexistent])).to be_nil
52
+ end
53
+
54
+ it 'boosts strength with attention' do
55
+ register_pair
56
+ obj = field.bind(feature_ids: %w[f:red f:circle], attention: true)
57
+ expect(obj.binding_strength).to be > constants::DEFAULT_BINDING_STRENGTH
58
+ end
59
+
60
+ it 'auto-confirms with attention' do
61
+ register_pair
62
+ obj = field.bind(feature_ids: %w[f:red f:circle], attention: true)
63
+ expect(obj.confirmed?).to be true
64
+ end
65
+
66
+ it 'records binding in history' do
67
+ register_pair
68
+ field.bind(feature_ids: %w[f:red f:circle])
69
+ expect(field.binding_history.size).to eq(1)
70
+ end
71
+
72
+ it 'enforces MAX_OBJECTS limit' do
73
+ (constants::MAX_OBJECTS + 5).times do |i|
74
+ field.register_feature(id: "a:#{i}", dimension: :color, value: i)
75
+ field.register_feature(id: "b:#{i}", dimension: :shape, value: i)
76
+ field.bind(feature_ids: ["a:#{i}", "b:#{i}"])
77
+ end
78
+ expect(field.object_count).to be <= constants::MAX_OBJECTS
79
+ end
80
+ end
81
+
82
+ describe '#attend' do
83
+ it 'strengthens and confirms an object' do
84
+ register_pair
85
+ obj = field.bind(feature_ids: %w[f:red f:circle])
86
+ result = field.attend(object_id: obj.id)
87
+ expect(result.confirmed?).to be true
88
+ expect(result.binding_strength).to be > constants::DEFAULT_BINDING_STRENGTH
89
+ end
90
+
91
+ it 'returns nil for unknown object' do
92
+ expect(field.attend(object_id: :nonexistent)).to be_nil
93
+ end
94
+ end
95
+
96
+ describe '#unbind' do
97
+ it 'removes an object' do
98
+ register_pair
99
+ obj = field.bind(feature_ids: %w[f:red f:circle])
100
+ expect(field.unbind(object_id: obj.id)).to be true
101
+ expect(field.object_count).to eq(0)
102
+ end
103
+
104
+ it 'returns false for unknown object' do
105
+ expect(field.unbind(object_id: :nonexistent)).to be false
106
+ end
107
+ end
108
+
109
+ describe '#features_of' do
110
+ it 'returns features of a bound object' do
111
+ register_pair
112
+ obj = field.bind(feature_ids: %w[f:red f:circle])
113
+ features = field.features_of(object_id: obj.id)
114
+ expect(features.size).to eq(2)
115
+ expect(features.first).to include(:id, :dimension)
116
+ end
117
+
118
+ it 'returns empty for unknown object' do
119
+ expect(field.features_of(object_id: :nope)).to be_empty
120
+ end
121
+ end
122
+
123
+ describe '#objects_with_feature' do
124
+ it 'finds objects containing a feature' do
125
+ register_pair
126
+ field.bind(feature_ids: %w[f:red f:circle])
127
+ results = field.objects_with_feature(feature_id: 'f:red')
128
+ expect(results.size).to eq(1)
129
+ end
130
+
131
+ it 'returns empty when no objects contain feature' do
132
+ expect(field.objects_with_feature(feature_id: 'f:none')).to be_empty
133
+ end
134
+ end
135
+
136
+ describe '#illusory_conjunctions' do
137
+ it 'returns objects in illusory state' do
138
+ register_pair
139
+ obj = field.bind(feature_ids: %w[f:red f:circle])
140
+ obj.binding_strength = constants::ILLUSORY_CONJUNCTION_THRESHOLD - 0.1
141
+ illusions = field.illusory_conjunctions
142
+ expect(illusions.size).to eq(1)
143
+ end
144
+ end
145
+
146
+ describe '#unbound_features' do
147
+ it 'returns features not bound to any object' do
148
+ register_pair
149
+ field.register_feature(id: 'f:large', dimension: :size, value: :large)
150
+ field.bind(feature_ids: %w[f:red f:circle])
151
+ unbound = field.unbound_features
152
+ expect(unbound.size).to eq(1)
153
+ expect(unbound.first[:id]).to eq('f:large')
154
+ end
155
+ end
156
+
157
+ describe '#search_by_dimension' do
158
+ it 'filters by dimension' do
159
+ field.register_feature(id: 'f:red', dimension: :color, value: :red)
160
+ field.register_feature(id: 'f:blue', dimension: :color, value: :blue)
161
+ field.register_feature(id: 'f:circle', dimension: :shape, value: :circle)
162
+ results = field.search_by_dimension(dimension: :color)
163
+ expect(results.size).to eq(2)
164
+ end
165
+
166
+ it 'filters by dimension and value' do
167
+ field.register_feature(id: 'f:red', dimension: :color, value: :red)
168
+ field.register_feature(id: 'f:blue', dimension: :color, value: :blue)
169
+ results = field.search_by_dimension(dimension: :color, value: :red)
170
+ expect(results.size).to eq(1)
171
+ end
172
+ end
173
+
174
+ describe '#decay_all' do
175
+ it 'decays features and objects' do
176
+ register_pair
177
+ obj = field.bind(feature_ids: %w[f:red f:circle])
178
+ before_feature = field.features['f:red'].salience
179
+ before_obj = obj.binding_strength
180
+ field.decay_all
181
+ expect(field.features['f:red']&.salience || 0).to be <= before_feature
182
+ expect(obj.binding_strength).to be < before_obj
183
+ end
184
+
185
+ it 'removes faded features' do
186
+ field.register_feature(id: 'f:faint', dimension: :color, value: :x, salience: 0.06)
187
+ 10.times { field.decay_all }
188
+ expect(field.features).not_to have_key('f:faint')
189
+ end
190
+
191
+ it 'removes dissolved objects' do
192
+ register_pair
193
+ obj = field.bind(feature_ids: %w[f:red f:circle])
194
+ obj.binding_strength = constants::BINDING_STRENGTH_FLOOR + constants::BINDING_DECAY
195
+ field.decay_all
196
+ expect(field.object_count).to eq(0)
197
+ end
198
+ end
199
+
200
+ describe '#to_h' do
201
+ it 'returns summary hash' do
202
+ h = field.to_h
203
+ expect(h).to include(:features, :objects, :confirmed_objects, :illusory_count,
204
+ :unbound_features, :history_size)
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,149 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::BoundObject do
4
+ subject(:obj) { described_class.new(id: :obj_one, feature_ids: %w[f:red f:circle]) }
5
+
6
+ let(:constants) { Legion::Extensions::Agentic::Attention::FeatureBinding::Helpers::Constants }
7
+
8
+ describe '#initialize' do
9
+ it 'sets id and feature_ids' do
10
+ expect(obj.id).to eq(:obj_one)
11
+ expect(obj.feature_ids).to eq(%w[f:red f:circle])
12
+ end
13
+
14
+ it 'deduplicates feature_ids' do
15
+ o = described_class.new(id: :dup, feature_ids: %w[a a b])
16
+ expect(o.feature_ids).to eq(%w[a b])
17
+ end
18
+
19
+ it 'uses default binding strength' do
20
+ expect(obj.binding_strength).to eq(constants::DEFAULT_BINDING_STRENGTH)
21
+ end
22
+
23
+ it 'starts unconfirmed' do
24
+ expect(obj.confirmed?).to be false
25
+ end
26
+ end
27
+
28
+ describe '#confirm' do
29
+ it 'marks as confirmed' do
30
+ obj.confirm
31
+ expect(obj.confirmed?).to be true
32
+ end
33
+
34
+ it 'boosts binding strength' do
35
+ before = obj.binding_strength
36
+ obj.confirm
37
+ expect(obj.binding_strength).to be > before
38
+ end
39
+
40
+ it 'sets confirmed_at' do
41
+ obj.confirm
42
+ expect(obj.confirmed_at).to be_a(Time)
43
+ end
44
+ end
45
+
46
+ describe '#strengthen' do
47
+ it 'increases binding strength' do
48
+ before = obj.binding_strength
49
+ obj.strengthen
50
+ expect(obj.binding_strength).to be > before
51
+ end
52
+
53
+ it 'clamps at 1.0' do
54
+ 10.times { obj.strengthen }
55
+ expect(obj.binding_strength).to be <= 1.0
56
+ end
57
+
58
+ it 'accepts custom amount' do
59
+ before = obj.binding_strength
60
+ obj.strengthen(0.01)
61
+ expect(obj.binding_strength).to eq(before + 0.01)
62
+ end
63
+ end
64
+
65
+ describe '#decay' do
66
+ it 'reduces binding strength' do
67
+ before = obj.binding_strength
68
+ obj.decay
69
+ expect(obj.binding_strength).to be < before
70
+ end
71
+
72
+ it 'does not go below zero' do
73
+ 100.times { obj.decay }
74
+ expect(obj.binding_strength).to be >= 0.0
75
+ end
76
+ end
77
+
78
+ describe '#dissolved?' do
79
+ it 'returns false initially' do
80
+ expect(obj.dissolved?).to be false
81
+ end
82
+
83
+ it 'returns true at floor' do
84
+ obj.binding_strength = constants::BINDING_STRENGTH_FLOOR
85
+ expect(obj.dissolved?).to be true
86
+ end
87
+ end
88
+
89
+ describe '#state' do
90
+ it 'returns :tentative initially (unconfirmed, above illusory threshold)' do
91
+ expect(obj.state).to eq(:tentative)
92
+ end
93
+
94
+ it 'returns :bound when confirmed and above confirmation threshold' do
95
+ obj.binding_strength = constants::BINDING_CONFIRMATION_THRESHOLD + 0.1
96
+ obj.confirm
97
+ expect(obj.state).to eq(:bound)
98
+ end
99
+
100
+ it 'returns :illusory below illusory threshold but above floor' do
101
+ obj.binding_strength = constants::ILLUSORY_CONJUNCTION_THRESHOLD - 0.1
102
+ expect(obj.state).to eq(:illusory)
103
+ end
104
+
105
+ it 'returns :unbound at floor' do
106
+ obj.binding_strength = constants::BINDING_STRENGTH_FLOOR
107
+ expect(obj.state).to eq(:unbound)
108
+ end
109
+ end
110
+
111
+ describe '#feature_count' do
112
+ it 'returns number of features' do
113
+ expect(obj.feature_count).to eq(2)
114
+ end
115
+ end
116
+
117
+ describe '#includes_feature?' do
118
+ it 'returns true for included feature' do
119
+ expect(obj.includes_feature?('f:red')).to be true
120
+ end
121
+
122
+ it 'returns false for missing feature' do
123
+ expect(obj.includes_feature?('f:blue')).to be false
124
+ end
125
+ end
126
+
127
+ describe '#strength_label' do
128
+ it 'returns a symbol' do
129
+ expect(obj.strength_label).to be_a(Symbol)
130
+ end
131
+
132
+ it 'returns :weak for default strength (0.3)' do
133
+ expect(obj.strength_label).to eq(:weak)
134
+ end
135
+
136
+ it 'returns :solid for high strength' do
137
+ obj.binding_strength = 0.9
138
+ expect(obj.strength_label).to eq(:solid)
139
+ end
140
+ end
141
+
142
+ describe '#to_h' do
143
+ it 'returns expected keys' do
144
+ h = obj.to_h
145
+ expect(h).to include(:id, :features, :feature_count, :binding_strength,
146
+ :strength_label, :state, :state_label, :confirmed, :bound_at)
147
+ end
148
+ end
149
+ end