lex-agentic-integration 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 (236) 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-integration.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/integration/boundary/client.rb +15 -0
  8. data/lib/legion/extensions/agentic/integration/boundary/helpers/boundary.rb +90 -0
  9. data/lib/legion/extensions/agentic/integration/boundary/helpers/boundary_engine.rb +123 -0
  10. data/lib/legion/extensions/agentic/integration/boundary/helpers/constants.rb +44 -0
  11. data/lib/legion/extensions/agentic/integration/boundary/runners/cognitive_boundary.rb +100 -0
  12. data/lib/legion/extensions/agentic/integration/boundary/version.rb +13 -0
  13. data/lib/legion/extensions/agentic/integration/boundary.rb +19 -0
  14. data/lib/legion/extensions/agentic/integration/context/client.rb +26 -0
  15. data/lib/legion/extensions/agentic/integration/context/helpers/constants.rb +34 -0
  16. data/lib/legion/extensions/agentic/integration/context/helpers/context_manager.rb +150 -0
  17. data/lib/legion/extensions/agentic/integration/context/helpers/frame.rb +99 -0
  18. data/lib/legion/extensions/agentic/integration/context/runners/context.rb +94 -0
  19. data/lib/legion/extensions/agentic/integration/context/version.rb +13 -0
  20. data/lib/legion/extensions/agentic/integration/context.rb +19 -0
  21. data/lib/legion/extensions/agentic/integration/distributed_cognition/client.rb +19 -0
  22. data/lib/legion/extensions/agentic/integration/distributed_cognition/helpers/constants.rb +51 -0
  23. data/lib/legion/extensions/agentic/integration/distributed_cognition/helpers/distribution_engine.rb +159 -0
  24. data/lib/legion/extensions/agentic/integration/distributed_cognition/helpers/participant.rb +100 -0
  25. data/lib/legion/extensions/agentic/integration/distributed_cognition/runners/distributed_cognition.rb +107 -0
  26. data/lib/legion/extensions/agentic/integration/distributed_cognition/version.rb +13 -0
  27. data/lib/legion/extensions/agentic/integration/distributed_cognition.rb +19 -0
  28. data/lib/legion/extensions/agentic/integration/gestalt/client.rb +21 -0
  29. data/lib/legion/extensions/agentic/integration/gestalt/helpers/constants.rb +51 -0
  30. data/lib/legion/extensions/agentic/integration/gestalt/helpers/pattern.rb +90 -0
  31. data/lib/legion/extensions/agentic/integration/gestalt/helpers/pattern_store.rb +123 -0
  32. data/lib/legion/extensions/agentic/integration/gestalt/runners/gestalt.rb +82 -0
  33. data/lib/legion/extensions/agentic/integration/gestalt/version.rb +13 -0
  34. data/lib/legion/extensions/agentic/integration/gestalt.rb +19 -0
  35. data/lib/legion/extensions/agentic/integration/global_workspace/actors/competition.rb +45 -0
  36. data/lib/legion/extensions/agentic/integration/global_workspace/client.rb +29 -0
  37. data/lib/legion/extensions/agentic/integration/global_workspace/helpers/broadcast.rb +62 -0
  38. data/lib/legion/extensions/agentic/integration/global_workspace/helpers/competitor.rb +59 -0
  39. data/lib/legion/extensions/agentic/integration/global_workspace/helpers/constants.rb +65 -0
  40. data/lib/legion/extensions/agentic/integration/global_workspace/helpers/workspace.rb +188 -0
  41. data/lib/legion/extensions/agentic/integration/global_workspace/runners/global_workspace.rb +104 -0
  42. data/lib/legion/extensions/agentic/integration/global_workspace/version.rb +13 -0
  43. data/lib/legion/extensions/agentic/integration/global_workspace.rb +20 -0
  44. data/lib/legion/extensions/agentic/integration/integration/client.rb +19 -0
  45. data/lib/legion/extensions/agentic/integration/integration/helpers/constants.rb +62 -0
  46. data/lib/legion/extensions/agentic/integration/integration/helpers/integrated_representation.rb +106 -0
  47. data/lib/legion/extensions/agentic/integration/integration/helpers/integration_engine.rb +163 -0
  48. data/lib/legion/extensions/agentic/integration/integration/helpers/modal_signal.rb +62 -0
  49. data/lib/legion/extensions/agentic/integration/integration/runners/cognitive_integration.rb +105 -0
  50. data/lib/legion/extensions/agentic/integration/integration/version.rb +13 -0
  51. data/lib/legion/extensions/agentic/integration/integration.rb +20 -0
  52. data/lib/legion/extensions/agentic/integration/labyrinth/actors/thread_walker.rb +45 -0
  53. data/lib/legion/extensions/agentic/integration/labyrinth/client.rb +23 -0
  54. data/lib/legion/extensions/agentic/integration/labyrinth/helpers/constants.rb +39 -0
  55. data/lib/legion/extensions/agentic/integration/labyrinth/helpers/labyrinth.rb +138 -0
  56. data/lib/legion/extensions/agentic/integration/labyrinth/helpers/labyrinth_engine.rb +177 -0
  57. data/lib/legion/extensions/agentic/integration/labyrinth/helpers/node.rb +64 -0
  58. data/lib/legion/extensions/agentic/integration/labyrinth/runners/cognitive_labyrinth.rb +128 -0
  59. data/lib/legion/extensions/agentic/integration/labyrinth/version.rb +13 -0
  60. data/lib/legion/extensions/agentic/integration/labyrinth.rb +22 -0
  61. data/lib/legion/extensions/agentic/integration/map/actors/decay.rb +45 -0
  62. data/lib/legion/extensions/agentic/integration/map/client.rb +29 -0
  63. data/lib/legion/extensions/agentic/integration/map/helpers/cognitive_map_store.rb +179 -0
  64. data/lib/legion/extensions/agentic/integration/map/helpers/constants.rb +71 -0
  65. data/lib/legion/extensions/agentic/integration/map/helpers/graph_traversal.rb +124 -0
  66. data/lib/legion/extensions/agentic/integration/map/helpers/location.rb +71 -0
  67. data/lib/legion/extensions/agentic/integration/map/runners/cognitive_map.rb +95 -0
  68. data/lib/legion/extensions/agentic/integration/map/version.rb +13 -0
  69. data/lib/legion/extensions/agentic/integration/map.rb +20 -0
  70. data/lib/legion/extensions/agentic/integration/mosaic/client.rb +15 -0
  71. data/lib/legion/extensions/agentic/integration/mosaic/helpers/constants.rb +55 -0
  72. data/lib/legion/extensions/agentic/integration/mosaic/helpers/mosaic.rb +111 -0
  73. data/lib/legion/extensions/agentic/integration/mosaic/helpers/mosaic_engine.rb +124 -0
  74. data/lib/legion/extensions/agentic/integration/mosaic/helpers/tessera.rb +86 -0
  75. data/lib/legion/extensions/agentic/integration/mosaic/runners/cognitive_mosaic.rb +76 -0
  76. data/lib/legion/extensions/agentic/integration/mosaic/version.rb +13 -0
  77. data/lib/legion/extensions/agentic/integration/mosaic.rb +22 -0
  78. data/lib/legion/extensions/agentic/integration/mycelium/client.rb +19 -0
  79. data/lib/legion/extensions/agentic/integration/mycelium/helpers/constants.rb +52 -0
  80. data/lib/legion/extensions/agentic/integration/mycelium/helpers/fruiting_body.rb +50 -0
  81. data/lib/legion/extensions/agentic/integration/mycelium/helpers/hypha.rb +76 -0
  82. data/lib/legion/extensions/agentic/integration/mycelium/helpers/mycelial_node.rb +72 -0
  83. data/lib/legion/extensions/agentic/integration/mycelium/helpers/mycelium_engine.rb +151 -0
  84. data/lib/legion/extensions/agentic/integration/mycelium/runners/cognitive_mycelium.rb +73 -0
  85. data/lib/legion/extensions/agentic/integration/mycelium/version.rb +13 -0
  86. data/lib/legion/extensions/agentic/integration/mycelium.rb +23 -0
  87. data/lib/legion/extensions/agentic/integration/phenomenal_binding/client.rb +25 -0
  88. data/lib/legion/extensions/agentic/integration/phenomenal_binding/helpers/binding_engine.rb +156 -0
  89. data/lib/legion/extensions/agentic/integration/phenomenal_binding/helpers/binding_unit.rb +72 -0
  90. data/lib/legion/extensions/agentic/integration/phenomenal_binding/helpers/constants.rb +35 -0
  91. data/lib/legion/extensions/agentic/integration/phenomenal_binding/helpers/stream.rb +51 -0
  92. data/lib/legion/extensions/agentic/integration/phenomenal_binding/runners/phenomenal_binding.rb +110 -0
  93. data/lib/legion/extensions/agentic/integration/phenomenal_binding/version.rb +13 -0
  94. data/lib/legion/extensions/agentic/integration/phenomenal_binding.rb +20 -0
  95. data/lib/legion/extensions/agentic/integration/qualia/client.rb +19 -0
  96. data/lib/legion/extensions/agentic/integration/qualia/helpers/constants.rb +74 -0
  97. data/lib/legion/extensions/agentic/integration/qualia/helpers/quale.rb +103 -0
  98. data/lib/legion/extensions/agentic/integration/qualia/helpers/qualia_engine.rb +142 -0
  99. data/lib/legion/extensions/agentic/integration/qualia/runners/qualia.rb +67 -0
  100. data/lib/legion/extensions/agentic/integration/qualia/version.rb +13 -0
  101. data/lib/legion/extensions/agentic/integration/qualia.rb +19 -0
  102. data/lib/legion/extensions/agentic/integration/situation_model/client.rb +28 -0
  103. data/lib/legion/extensions/agentic/integration/situation_model/helpers/client.rb +23 -0
  104. data/lib/legion/extensions/agentic/integration/situation_model/helpers/constants.rb +40 -0
  105. data/lib/legion/extensions/agentic/integration/situation_model/helpers/situation_engine.rb +73 -0
  106. data/lib/legion/extensions/agentic/integration/situation_model/helpers/situation_event.rb +56 -0
  107. data/lib/legion/extensions/agentic/integration/situation_model/helpers/situation_model.rb +90 -0
  108. data/lib/legion/extensions/agentic/integration/situation_model/runners/situation_model.rb +99 -0
  109. data/lib/legion/extensions/agentic/integration/situation_model/version.rb +13 -0
  110. data/lib/legion/extensions/agentic/integration/situation_model.rb +21 -0
  111. data/lib/legion/extensions/agentic/integration/synthesis/client.rb +29 -0
  112. data/lib/legion/extensions/agentic/integration/synthesis/helpers/constants.rb +41 -0
  113. data/lib/legion/extensions/agentic/integration/synthesis/helpers/synthesis.rb +63 -0
  114. data/lib/legion/extensions/agentic/integration/synthesis/helpers/synthesis_engine.rb +213 -0
  115. data/lib/legion/extensions/agentic/integration/synthesis/helpers/synthesis_stream.rb +67 -0
  116. data/lib/legion/extensions/agentic/integration/synthesis/runners/cognitive_synthesis.rb +82 -0
  117. data/lib/legion/extensions/agentic/integration/synthesis/version.rb +13 -0
  118. data/lib/legion/extensions/agentic/integration/synthesis.rb +20 -0
  119. data/lib/legion/extensions/agentic/integration/tapestry/client.rb +15 -0
  120. data/lib/legion/extensions/agentic/integration/tapestry/helpers/constants.rb +46 -0
  121. data/lib/legion/extensions/agentic/integration/tapestry/helpers/loom_engine.rb +125 -0
  122. data/lib/legion/extensions/agentic/integration/tapestry/helpers/tapestry.rb +144 -0
  123. data/lib/legion/extensions/agentic/integration/tapestry/helpers/thread.rb +112 -0
  124. data/lib/legion/extensions/agentic/integration/tapestry/runners/cognitive_tapestry.rb +81 -0
  125. data/lib/legion/extensions/agentic/integration/tapestry/version.rb +13 -0
  126. data/lib/legion/extensions/agentic/integration/tapestry.rb +22 -0
  127. data/lib/legion/extensions/agentic/integration/tessellation/client.rb +19 -0
  128. data/lib/legion/extensions/agentic/integration/tessellation/helpers/constants.rb +72 -0
  129. data/lib/legion/extensions/agentic/integration/tessellation/helpers/mosaic.rb +99 -0
  130. data/lib/legion/extensions/agentic/integration/tessellation/helpers/tessellation_engine.rb +141 -0
  131. data/lib/legion/extensions/agentic/integration/tessellation/helpers/tile.rb +76 -0
  132. data/lib/legion/extensions/agentic/integration/tessellation/runners/cognitive_tessellation.rb +58 -0
  133. data/lib/legion/extensions/agentic/integration/tessellation/version.rb +13 -0
  134. data/lib/legion/extensions/agentic/integration/tessellation.rb +22 -0
  135. data/lib/legion/extensions/agentic/integration/version.rb +11 -0
  136. data/lib/legion/extensions/agentic/integration/zeitgeist/helpers/client.rb +17 -0
  137. data/lib/legion/extensions/agentic/integration/zeitgeist/helpers/cognitive_signal.rb +38 -0
  138. data/lib/legion/extensions/agentic/integration/zeitgeist/helpers/constants.rb +64 -0
  139. data/lib/legion/extensions/agentic/integration/zeitgeist/helpers/trend_window.rb +80 -0
  140. data/lib/legion/extensions/agentic/integration/zeitgeist/helpers/zeitgeist_engine.rb +157 -0
  141. data/lib/legion/extensions/agentic/integration/zeitgeist/runners/cognitive_zeitgeist.rb +99 -0
  142. data/lib/legion/extensions/agentic/integration/zeitgeist/version.rb +13 -0
  143. data/lib/legion/extensions/agentic/integration/zeitgeist.rb +22 -0
  144. data/lib/legion/extensions/agentic/integration.rb +34 -0
  145. data/spec/legion/extensions/agentic/integration/boundary/helpers/boundary_engine_spec.rb +165 -0
  146. data/spec/legion/extensions/agentic/integration/boundary/helpers/boundary_spec.rb +168 -0
  147. data/spec/legion/extensions/agentic/integration/boundary/helpers/constants_spec.rb +65 -0
  148. data/spec/legion/extensions/agentic/integration/boundary/runners/cognitive_boundary_spec.rb +111 -0
  149. data/spec/legion/extensions/agentic/integration/context/client_spec.rb +58 -0
  150. data/spec/legion/extensions/agentic/integration/context/helpers/constants_spec.rb +32 -0
  151. data/spec/legion/extensions/agentic/integration/context/helpers/context_manager_spec.rb +190 -0
  152. data/spec/legion/extensions/agentic/integration/context/helpers/frame_spec.rb +164 -0
  153. data/spec/legion/extensions/agentic/integration/context/runners/context_spec.rb +142 -0
  154. data/spec/legion/extensions/agentic/integration/distributed_cognition/client_spec.rb +21 -0
  155. data/spec/legion/extensions/agentic/integration/distributed_cognition/helpers/distribution_engine_spec.rb +149 -0
  156. data/spec/legion/extensions/agentic/integration/distributed_cognition/helpers/participant_spec.rb +116 -0
  157. data/spec/legion/extensions/agentic/integration/distributed_cognition/runners/distributed_cognition_spec.rb +102 -0
  158. data/spec/legion/extensions/agentic/integration/gestalt/client_spec.rb +53 -0
  159. data/spec/legion/extensions/agentic/integration/gestalt/helpers/constants_spec.rb +27 -0
  160. data/spec/legion/extensions/agentic/integration/gestalt/helpers/pattern_spec.rb +128 -0
  161. data/spec/legion/extensions/agentic/integration/gestalt/helpers/pattern_store_spec.rb +155 -0
  162. data/spec/legion/extensions/agentic/integration/gestalt/runners/gestalt_spec.rb +114 -0
  163. data/spec/legion/extensions/agentic/integration/global_workspace/client_spec.rb +49 -0
  164. data/spec/legion/extensions/agentic/integration/global_workspace/helpers/broadcast_spec.rb +83 -0
  165. data/spec/legion/extensions/agentic/integration/global_workspace/helpers/competitor_spec.rb +84 -0
  166. data/spec/legion/extensions/agentic/integration/global_workspace/helpers/workspace_spec.rb +174 -0
  167. data/spec/legion/extensions/agentic/integration/global_workspace/runners/global_workspace_spec.rb +118 -0
  168. data/spec/legion/extensions/agentic/integration/integration/cognitive_integration_spec.rb +7 -0
  169. data/spec/legion/extensions/agentic/integration/integration/helpers/integrated_representation_spec.rb +149 -0
  170. data/spec/legion/extensions/agentic/integration/integration/helpers/integration_engine_spec.rb +191 -0
  171. data/spec/legion/extensions/agentic/integration/integration/helpers/modal_signal_spec.rb +81 -0
  172. data/spec/legion/extensions/agentic/integration/labyrinth/client_spec.rb +122 -0
  173. data/spec/legion/extensions/agentic/integration/labyrinth/cognitive_labyrinth_spec.rb +19 -0
  174. data/spec/legion/extensions/agentic/integration/labyrinth/helpers/constants_spec.rb +72 -0
  175. data/spec/legion/extensions/agentic/integration/labyrinth/helpers/labyrinth_engine_spec.rb +222 -0
  176. data/spec/legion/extensions/agentic/integration/labyrinth/helpers/labyrinth_spec.rb +235 -0
  177. data/spec/legion/extensions/agentic/integration/labyrinth/helpers/node_spec.rb +157 -0
  178. data/spec/legion/extensions/agentic/integration/labyrinth/runners/cognitive_labyrinth_spec.rb +209 -0
  179. data/spec/legion/extensions/agentic/integration/map/client_spec.rb +89 -0
  180. data/spec/legion/extensions/agentic/integration/map/helpers/cognitive_map_store_spec.rb +321 -0
  181. data/spec/legion/extensions/agentic/integration/map/helpers/location_spec.rb +165 -0
  182. data/spec/legion/extensions/agentic/integration/map/runners/cognitive_map_spec.rb +190 -0
  183. data/spec/legion/extensions/agentic/integration/mosaic/client_spec.rb +16 -0
  184. data/spec/legion/extensions/agentic/integration/mosaic/helpers/constants_spec.rb +37 -0
  185. data/spec/legion/extensions/agentic/integration/mosaic/helpers/mosaic_engine_spec.rb +108 -0
  186. data/spec/legion/extensions/agentic/integration/mosaic/helpers/mosaic_spec.rb +120 -0
  187. data/spec/legion/extensions/agentic/integration/mosaic/helpers/tessera_spec.rb +92 -0
  188. data/spec/legion/extensions/agentic/integration/mosaic/runners/cognitive_mosaic_spec.rb +88 -0
  189. data/spec/legion/extensions/agentic/integration/mycelium/client_spec.rb +25 -0
  190. data/spec/legion/extensions/agentic/integration/mycelium/cognitive_mycelium_spec.rb +7 -0
  191. data/spec/legion/extensions/agentic/integration/mycelium/helpers/constants_spec.rb +28 -0
  192. data/spec/legion/extensions/agentic/integration/mycelium/helpers/fruiting_body_spec.rb +33 -0
  193. data/spec/legion/extensions/agentic/integration/mycelium/helpers/hypha_spec.rb +69 -0
  194. data/spec/legion/extensions/agentic/integration/mycelium/helpers/mycelial_node_spec.rb +79 -0
  195. data/spec/legion/extensions/agentic/integration/mycelium/helpers/mycelium_engine_spec.rb +136 -0
  196. data/spec/legion/extensions/agentic/integration/mycelium/runners/cognitive_mycelium_spec.rb +61 -0
  197. data/spec/legion/extensions/agentic/integration/phenomenal_binding/client_spec.rb +52 -0
  198. data/spec/legion/extensions/agentic/integration/phenomenal_binding/helpers/binding_engine_spec.rb +290 -0
  199. data/spec/legion/extensions/agentic/integration/phenomenal_binding/helpers/binding_unit_spec.rb +195 -0
  200. data/spec/legion/extensions/agentic/integration/phenomenal_binding/helpers/constants_spec.rb +92 -0
  201. data/spec/legion/extensions/agentic/integration/phenomenal_binding/helpers/stream_spec.rb +128 -0
  202. data/spec/legion/extensions/agentic/integration/phenomenal_binding/runners/phenomenal_binding_spec.rb +174 -0
  203. data/spec/legion/extensions/agentic/integration/qualia/client_spec.rb +21 -0
  204. data/spec/legion/extensions/agentic/integration/qualia/helpers/quale_spec.rb +168 -0
  205. data/spec/legion/extensions/agentic/integration/qualia/helpers/qualia_engine_spec.rb +174 -0
  206. data/spec/legion/extensions/agentic/integration/qualia/qualia_spec.rb +7 -0
  207. data/spec/legion/extensions/agentic/integration/qualia/runners_spec.rb +70 -0
  208. data/spec/legion/extensions/agentic/integration/situation_model/client_spec.rb +51 -0
  209. data/spec/legion/extensions/agentic/integration/situation_model/helpers/constants_spec.rb +56 -0
  210. data/spec/legion/extensions/agentic/integration/situation_model/helpers/situation_engine_spec.rb +203 -0
  211. data/spec/legion/extensions/agentic/integration/situation_model/helpers/situation_event_spec.rb +94 -0
  212. data/spec/legion/extensions/agentic/integration/situation_model/helpers/situation_model_spec.rb +235 -0
  213. data/spec/legion/extensions/agentic/integration/situation_model/runners/situation_model_spec.rb +204 -0
  214. data/spec/legion/extensions/agentic/integration/synthesis/client_spec.rb +26 -0
  215. data/spec/legion/extensions/agentic/integration/synthesis/helpers/constants_spec.rb +87 -0
  216. data/spec/legion/extensions/agentic/integration/synthesis/helpers/synthesis_engine_spec.rb +233 -0
  217. data/spec/legion/extensions/agentic/integration/synthesis/helpers/synthesis_spec.rb +101 -0
  218. data/spec/legion/extensions/agentic/integration/synthesis/helpers/synthesis_stream_spec.rb +116 -0
  219. data/spec/legion/extensions/agentic/integration/synthesis/runners/cognitive_synthesis_spec.rb +181 -0
  220. data/spec/legion/extensions/agentic/integration/tapestry/client_spec.rb +55 -0
  221. data/spec/legion/extensions/agentic/integration/tapestry/helpers/constants_spec.rb +88 -0
  222. data/spec/legion/extensions/agentic/integration/tapestry/helpers/loom_engine_spec.rb +225 -0
  223. data/spec/legion/extensions/agentic/integration/tapestry/helpers/tapestry_spec.rb +229 -0
  224. data/spec/legion/extensions/agentic/integration/tapestry/helpers/thread_spec.rb +211 -0
  225. data/spec/legion/extensions/agentic/integration/tapestry/runners/cognitive_tapestry_spec.rb +171 -0
  226. data/spec/legion/extensions/agentic/integration/tessellation/client_spec.rb +40 -0
  227. data/spec/legion/extensions/agentic/integration/tessellation/helpers/mosaic_spec.rb +99 -0
  228. data/spec/legion/extensions/agentic/integration/tessellation/helpers/tessellation_engine_spec.rb +145 -0
  229. data/spec/legion/extensions/agentic/integration/tessellation/helpers/tile_spec.rb +138 -0
  230. data/spec/legion/extensions/agentic/integration/zeitgeist/helpers/cognitive_signal_spec.rb +62 -0
  231. data/spec/legion/extensions/agentic/integration/zeitgeist/helpers/constants_spec.rb +73 -0
  232. data/spec/legion/extensions/agentic/integration/zeitgeist/helpers/trend_window_spec.rb +100 -0
  233. data/spec/legion/extensions/agentic/integration/zeitgeist/helpers/zeitgeist_engine_spec.rb +163 -0
  234. data/spec/legion/extensions/agentic/integration/zeitgeist/runners/cognitive_zeitgeist_spec.rb +165 -0
  235. data/spec/spec_helper.rb +46 -0
  236. metadata +320 -0
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Labyrinth::Runners::CognitiveLabyrinth do
4
+ let(:engine) { Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::LabyrinthEngine.new }
5
+
6
+ let(:runner_host) do
7
+ host = Object.new
8
+ host.extend(described_class)
9
+ host
10
+ end
11
+
12
+ let(:lab_id) do
13
+ result = runner_host.create_labyrinth(name: 'Runner Test', engine: engine)
14
+ result[:labyrinth_id]
15
+ end
16
+
17
+ describe '#create_labyrinth' do
18
+ it 'returns success: true with labyrinth_id' do
19
+ result = runner_host.create_labyrinth(name: 'My Maze', engine: engine)
20
+ expect(result[:success]).to be(true)
21
+ expect(result[:labyrinth_id]).to be_a(String)
22
+ expect(result[:name]).to eq('My Maze')
23
+ end
24
+
25
+ it 'returns success: false when name is empty' do
26
+ result = runner_host.create_labyrinth(name: '', engine: engine)
27
+ expect(result[:success]).to be(false)
28
+ expect(result[:error]).to be_a(String)
29
+ end
30
+
31
+ it 'returns success: false when name is nil' do
32
+ result = runner_host.create_labyrinth(name: nil, engine: engine)
33
+ expect(result[:success]).to be(false)
34
+ end
35
+
36
+ it 'passes domain through' do
37
+ result = runner_host.create_labyrinth(name: 'Typed', domain: :epistemology, engine: engine)
38
+ expect(result[:success]).to be(true)
39
+ expect(result[:domain]).to eq(:epistemology)
40
+ end
41
+ end
42
+
43
+ describe '#add_node' do
44
+ it 'adds a node and returns success: true' do
45
+ result = runner_host.add_node(labyrinth_id: lab_id, node_type: :corridor, engine: engine)
46
+ expect(result[:success]).to be(true)
47
+ expect(result[:node_id]).to be_a(String)
48
+ expect(result[:node_type]).to eq(:corridor)
49
+ end
50
+
51
+ it 'returns success: false when labyrinth_id is nil' do
52
+ result = runner_host.add_node(labyrinth_id: nil, node_type: :corridor, engine: engine)
53
+ expect(result[:success]).to be(false)
54
+ end
55
+
56
+ it 'returns success: false when node_type is nil' do
57
+ result = runner_host.add_node(labyrinth_id: lab_id, node_type: nil, engine: engine)
58
+ expect(result[:success]).to be(false)
59
+ end
60
+
61
+ it 'returns success: false for invalid node_type' do
62
+ result = runner_host.add_node(labyrinth_id: lab_id, node_type: :dungeon, engine: engine)
63
+ expect(result[:success]).to be(false)
64
+ end
65
+ end
66
+
67
+ describe '#connect_nodes' do
68
+ let(:from_id) do
69
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :entrance, engine: engine)[:node_id]
70
+ end
71
+ let(:to_id) do
72
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :corridor, engine: engine)[:node_id]
73
+ end
74
+
75
+ it 'connects two nodes' do
76
+ result = runner_host.connect_nodes(labyrinth_id: lab_id, from_id: from_id, to_id: to_id, engine: engine)
77
+ expect(result[:connected]).to be(true)
78
+ end
79
+
80
+ it 'returns success: false when labyrinth_id is nil' do
81
+ result = runner_host.connect_nodes(labyrinth_id: nil, from_id: 'a', to_id: 'b', engine: engine)
82
+ expect(result[:success]).to be(false)
83
+ end
84
+ end
85
+
86
+ describe '#move' do
87
+ before do
88
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance', engine: engine)
89
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor', engine: engine)
90
+ runner_host.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor', engine: engine)
91
+ end
92
+
93
+ it 'moves to a connected node' do
94
+ result = runner_host.move(labyrinth_id: lab_id, node_id: 'corridor', engine: engine)
95
+ expect(result[:success]).to be(true)
96
+ expect(result[:node_id]).to eq('corridor')
97
+ end
98
+
99
+ it 'returns success: false for disconnected node' do
100
+ result = runner_host.move(labyrinth_id: lab_id, node_id: 'entrance', engine: engine)
101
+ expect(result[:success]).to be(false)
102
+ end
103
+
104
+ it 'returns success: false when labyrinth_id is nil' do
105
+ result = runner_host.move(labyrinth_id: nil, node_id: 'x', engine: engine)
106
+ expect(result[:success]).to be(false)
107
+ end
108
+
109
+ it 'returns success: false when node_id is nil' do
110
+ result = runner_host.move(labyrinth_id: lab_id, node_id: nil, engine: engine)
111
+ expect(result[:success]).to be(false)
112
+ end
113
+ end
114
+
115
+ describe '#backtrack' do
116
+ before do
117
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance', engine: engine)
118
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor', engine: engine)
119
+ runner_host.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor', engine: engine)
120
+ runner_host.move(labyrinth_id: lab_id, node_id: 'corridor', engine: engine)
121
+ end
122
+
123
+ it 'backtracks and returns success: true' do
124
+ result = runner_host.backtrack(labyrinth_id: lab_id, engine: engine)
125
+ expect(result[:success]).to be(true)
126
+ end
127
+
128
+ it 'returns success: false when labyrinth_id is nil' do
129
+ result = runner_host.backtrack(labyrinth_id: nil, engine: engine)
130
+ expect(result[:success]).to be(false)
131
+ end
132
+ end
133
+
134
+ describe '#follow_thread' do
135
+ before do
136
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance', engine: engine)
137
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor', engine: engine)
138
+ runner_host.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor', engine: engine)
139
+ end
140
+
141
+ it 'follows Ariadne\'s thread to an unvisited node' do
142
+ result = runner_host.follow_thread(labyrinth_id: lab_id, engine: engine)
143
+ expect(result[:success]).to be(true)
144
+ expect(result[:node_id]).to eq('corridor')
145
+ end
146
+
147
+ it 'returns success: false when labyrinth_id is nil' do
148
+ result = runner_host.follow_thread(labyrinth_id: nil, engine: engine)
149
+ expect(result[:success]).to be(false)
150
+ end
151
+ end
152
+
153
+ describe '#check_minotaur' do
154
+ before do
155
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :minotaur_lair, node_id: 'lair',
156
+ content: 'confirmation bias', engine: engine)
157
+ engine.labyrinths[lab_id].instance_variable_set(:@current_node_id, 'lair')
158
+ end
159
+
160
+ it 'returns encountered: true for minotaur_lair' do
161
+ result = runner_host.check_minotaur(labyrinth_id: lab_id, engine: engine)
162
+ expect(result[:encountered]).to be(true)
163
+ expect(result[:misconception]).to eq('confirmation bias')
164
+ end
165
+
166
+ it 'returns success: false when labyrinth_id is nil' do
167
+ result = runner_host.check_minotaur(labyrinth_id: nil, engine: engine)
168
+ expect(result[:success]).to be(false)
169
+ end
170
+ end
171
+
172
+ describe '#labyrinth_report' do
173
+ before do
174
+ runner_host.add_node(labyrinth_id: lab_id, node_type: :entrance, engine: engine)
175
+ end
176
+
177
+ it 'returns success: true with report data' do
178
+ result = runner_host.labyrinth_report(labyrinth_id: lab_id, engine: engine)
179
+ expect(result[:success]).to be(true)
180
+ expect(result[:labyrinth_id]).to eq(lab_id)
181
+ end
182
+
183
+ it 'returns success: false when labyrinth_id is nil' do
184
+ result = runner_host.labyrinth_report(labyrinth_id: nil, engine: engine)
185
+ expect(result[:success]).to be(false)
186
+ end
187
+ end
188
+
189
+ describe '#list_labyrinths' do
190
+ it 'returns a list of labyrinths' do
191
+ result = runner_host.list_labyrinths(engine: engine)
192
+ expect(result[:success]).to be(true)
193
+ expect(result[:labyrinths]).to be_an(Array)
194
+ expect(result[:count]).to be_a(Integer)
195
+ end
196
+ end
197
+
198
+ describe '#delete_labyrinth' do
199
+ it 'deletes a labyrinth' do
200
+ result = runner_host.delete_labyrinth(labyrinth_id: lab_id, engine: engine)
201
+ expect(result[:deleted]).to be(true)
202
+ end
203
+
204
+ it 'returns success: false when labyrinth_id is nil' do
205
+ result = runner_host.delete_labyrinth(labyrinth_id: nil, engine: engine)
206
+ expect(result[:success]).to be(false)
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/integration/map/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Integration::Map::Client do
6
+ subject(:client) { described_class.new }
7
+
8
+ it 'responds to all runner methods' do
9
+ expect(client).to respond_to(:add_location)
10
+ expect(client).to respond_to(:connect_locations)
11
+ expect(client).to respond_to(:visit_location)
12
+ expect(client).to respond_to(:find_path)
13
+ expect(client).to respond_to(:explore_neighborhood)
14
+ expect(client).to respond_to(:map_clusters)
15
+ expect(client).to respond_to(:familiar_locations)
16
+ expect(client).to respond_to(:switch_context)
17
+ expect(client).to respond_to(:update_cognitive_map)
18
+ expect(client).to respond_to(:cognitive_map_stats)
19
+ end
20
+
21
+ it 'accepts an injected map_store' do
22
+ custom_store = Legion::Extensions::Agentic::Integration::Map::Helpers::CognitiveMapStore.new
23
+ custom_store.add_location(id: 'pre_existing')
24
+ client2 = described_class.new(map_store: custom_store)
25
+ result = client2.cognitive_map_stats
26
+ expect(result[:location_count]).to eq(1)
27
+ end
28
+
29
+ describe 'integration: add and navigate' do
30
+ it 'adds locations, connects them, and finds a path' do
31
+ client.add_location(id: 'start', domain: :space)
32
+ client.add_location(id: 'mid', domain: :space)
33
+ client.add_location(id: 'end', domain: :space)
34
+ client.connect_locations(from: 'start', to: 'mid', distance: 1.0)
35
+ client.connect_locations(from: 'mid', to: 'end', distance: 1.0)
36
+
37
+ result = client.find_path(from: 'start', to: 'end')
38
+ expect(result[:success]).to be true
39
+ expect(result[:path]).to eq(%w[start mid end])
40
+ expect(result[:distance]).to eq(2.0)
41
+ end
42
+
43
+ it 'builds familiarity through visits' do
44
+ client.add_location(id: 'hub')
45
+ 5.times { client.visit_location(id: 'hub') }
46
+ familiar = client.familiar_locations(limit: 1)
47
+ expect(familiar[:locations].first[:id]).to eq('hub')
48
+ expect(familiar[:locations].first[:visit_count]).to eq(5)
49
+ end
50
+
51
+ it 'explores neighborhood up to a distance threshold' do
52
+ client.add_location(id: 'center')
53
+ client.add_location(id: 'near')
54
+ client.add_location(id: 'far')
55
+ client.connect_locations(from: 'center', to: 'near', distance: 1.0)
56
+ client.connect_locations(from: 'near', to: 'far', distance: 5.0)
57
+
58
+ result = client.explore_neighborhood(id: 'center', max_distance: 2.0)
59
+ ids = result[:reachable].map { |r| r[:id] }
60
+ expect(ids).to include('near')
61
+ expect(ids).not_to include('far')
62
+ end
63
+
64
+ it 'detects disconnected clusters' do
65
+ client.add_location(id: 'a')
66
+ client.add_location(id: 'b')
67
+ client.connect_locations(from: 'a', to: 'b')
68
+ client.add_location(id: 'island1')
69
+ client.add_location(id: 'island2')
70
+ client.connect_locations(from: 'island1', to: 'island2')
71
+
72
+ result = client.map_clusters
73
+ expect(result[:count]).to eq(2)
74
+ end
75
+
76
+ it 'isolates context maps from each other' do
77
+ client.add_location(id: 'shared_name', domain: :ctx_a)
78
+ client.switch_context(context_id: :ctx_b)
79
+ client.add_location(id: 'shared_name', domain: :ctx_b)
80
+
81
+ result_b = client.cognitive_map_stats
82
+ expect(result_b[:location_count]).to eq(1)
83
+
84
+ client.switch_context(context_id: :default)
85
+ result_default = client.cognitive_map_stats
86
+ expect(result_default[:location_count]).to eq(1)
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,321 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Map::Helpers::CognitiveMapStore do
4
+ subject(:store) { described_class.new }
5
+
6
+ def add_triangle
7
+ store.add_location(id: 'a')
8
+ store.add_location(id: 'b')
9
+ store.add_location(id: 'c')
10
+ store.connect(from: 'a', to: 'b', distance: 1.0)
11
+ store.connect(from: 'b', to: 'c', distance: 1.0)
12
+ store.connect(from: 'a', to: 'c', distance: 3.0)
13
+ end
14
+
15
+ describe '#add_location' do
16
+ it 'adds a location and returns true' do
17
+ expect(store.add_location(id: 'loc1')).to be true
18
+ end
19
+
20
+ it 'is idempotent for duplicate ids' do
21
+ store.add_location(id: 'loc1')
22
+ store.add_location(id: 'loc1', domain: :other)
23
+ expect(store.location_count).to eq(1)
24
+ end
25
+
26
+ it 'stores domain and properties' do
27
+ store.add_location(id: 'loc1', domain: :science, properties: { weight: 0.9 })
28
+ loc = store.location('loc1')
29
+ expect(loc.domain).to eq(:science)
30
+ expect(loc.properties[:weight]).to eq(0.9)
31
+ end
32
+
33
+ it 'enforces MAX_LOCATIONS' do
34
+ max = Legion::Extensions::Agentic::Integration::Map::Helpers::Constants::MAX_LOCATIONS
35
+ max.times { |i| store.add_location(id: "loc_#{i}") }
36
+ result = store.add_location(id: 'overflow')
37
+ expect(result).to be false
38
+ end
39
+ end
40
+
41
+ describe '#remove_location' do
42
+ it 'removes an existing location' do
43
+ store.add_location(id: 'loc1')
44
+ expect(store.remove_location('loc1')).to be true
45
+ expect(store.location('loc1')).to be_nil
46
+ end
47
+
48
+ it 'returns false for unknown location' do
49
+ expect(store.remove_location('nonexistent')).to be false
50
+ end
51
+
52
+ it 'removes edges pointing to removed location' do
53
+ store.add_location(id: 'a')
54
+ store.add_location(id: 'b')
55
+ store.connect(from: 'a', to: 'b')
56
+ store.remove_location('b')
57
+ expect(store.neighbors_of(id: 'a')).to be_empty
58
+ end
59
+ end
60
+
61
+ describe '#connect' do
62
+ before do
63
+ store.add_location(id: 'a')
64
+ store.add_location(id: 'b')
65
+ end
66
+
67
+ it 'creates a directed edge' do
68
+ expect(store.connect(from: 'a', to: 'b')).to be true
69
+ end
70
+
71
+ it 'creates bidirectional edges by default' do
72
+ store.connect(from: 'a', to: 'b', distance: 2.0)
73
+ a_neighbors = store.neighbors_of(id: 'a')
74
+ b_neighbors = store.neighbors_of(id: 'b')
75
+ expect(a_neighbors.map { |n| n[:id] }).to include('b')
76
+ expect(b_neighbors.map { |n| n[:id] }).to include('a')
77
+ end
78
+
79
+ it 'creates unidirectional edges when bidirectional: false' do
80
+ store.connect(from: 'a', to: 'b', bidirectional: false)
81
+ a_neighbors = store.neighbors_of(id: 'a')
82
+ b_neighbors = store.neighbors_of(id: 'b')
83
+ expect(a_neighbors.map { |n| n[:id] }).to include('b')
84
+ expect(b_neighbors.map { |n| n[:id] }).not_to include('a')
85
+ end
86
+
87
+ it 'returns false if a location is missing' do
88
+ expect(store.connect(from: 'a', to: 'missing')).to be false
89
+ end
90
+ end
91
+
92
+ describe '#disconnect' do
93
+ it 'removes an edge' do
94
+ store.add_location(id: 'a')
95
+ store.add_location(id: 'b')
96
+ store.connect(from: 'a', to: 'b')
97
+ store.disconnect(from: 'a', to: 'b')
98
+ expect(store.neighbors_of(id: 'a')).to be_empty
99
+ end
100
+
101
+ it 'returns false for unknown location' do
102
+ expect(store.disconnect(from: 'ghost', to: 'b')).to be false
103
+ end
104
+ end
105
+
106
+ describe '#visit' do
107
+ it 'marks location as visited' do
108
+ store.add_location(id: 'loc1')
109
+ result = store.visit(id: 'loc1')
110
+ expect(result[:found]).to be true
111
+ expect(result[:visit_count]).to eq(1)
112
+ end
113
+
114
+ it 'returns found: false for unknown location' do
115
+ result = store.visit(id: 'ghost')
116
+ expect(result[:found]).to be false
117
+ end
118
+
119
+ it 'boosts familiarity' do
120
+ store.add_location(id: 'loc1')
121
+ before = store.location('loc1').familiarity
122
+ store.visit(id: 'loc1')
123
+ expect(store.location('loc1').familiarity).to be > before
124
+ end
125
+ end
126
+
127
+ describe '#shortest_path' do
128
+ before { add_triangle }
129
+
130
+ it 'finds direct path between neighbors' do
131
+ result = store.shortest_path(from: 'a', to: 'b')
132
+ expect(result[:found]).to be true
133
+ expect(result[:path]).to eq(%w[a b])
134
+ expect(result[:distance]).to eq(1.0)
135
+ end
136
+
137
+ it 'finds shortest path avoiding longer direct edge' do
138
+ result = store.shortest_path(from: 'a', to: 'c')
139
+ expect(result[:found]).to be true
140
+ # a->b->c = 2.0, a->c = 3.0, so Dijkstra should pick a->b->c
141
+ expect(result[:distance]).to be <= 2.0
142
+ end
143
+
144
+ it 'returns trivial path for same start and end' do
145
+ result = store.shortest_path(from: 'a', to: 'a')
146
+ expect(result[:found]).to be true
147
+ expect(result[:path]).to eq(['a'])
148
+ expect(result[:distance]).to eq(0.0)
149
+ end
150
+
151
+ it 'returns found: false for missing start' do
152
+ result = store.shortest_path(from: 'ghost', to: 'a')
153
+ expect(result[:found]).to be false
154
+ end
155
+
156
+ it 'returns found: false for disconnected locations' do
157
+ store.add_location(id: 'island')
158
+ result = store.shortest_path(from: 'a', to: 'island')
159
+ expect(result[:found]).to be false
160
+ end
161
+
162
+ it 'caches repeated queries' do
163
+ store.shortest_path(from: 'a', to: 'c')
164
+ result2 = store.shortest_path(from: 'a', to: 'c')
165
+ expect(result2[:found]).to be true
166
+ end
167
+ end
168
+
169
+ describe '#neighbors_of' do
170
+ it 'returns direct neighbors' do
171
+ store.add_location(id: 'a')
172
+ store.add_location(id: 'b')
173
+ store.connect(from: 'a', to: 'b', distance: 1.5)
174
+ neighbors = store.neighbors_of(id: 'a')
175
+ expect(neighbors.size).to eq(1)
176
+ expect(neighbors.first[:id]).to eq('b')
177
+ expect(neighbors.first[:distance]).to eq(1.5)
178
+ end
179
+
180
+ it 'returns empty array for unknown location' do
181
+ expect(store.neighbors_of(id: 'ghost')).to be_empty
182
+ end
183
+
184
+ it 'includes distance category' do
185
+ store.add_location(id: 'a')
186
+ store.add_location(id: 'b')
187
+ store.connect(from: 'a', to: 'b', distance: 0.3)
188
+ neighbor = store.neighbors_of(id: 'a').first
189
+ expect(neighbor[:category]).to eq(:adjacent)
190
+ end
191
+ end
192
+
193
+ describe '#reachable_from' do
194
+ before { add_triangle }
195
+
196
+ it 'returns locations within max_distance' do
197
+ reachable = store.reachable_from(id: 'a', max_distance: 1.5)
198
+ ids = reachable.map { |r| r[:id] }
199
+ expect(ids).to include('b')
200
+ end
201
+
202
+ it 'excludes start location from results' do
203
+ reachable = store.reachable_from(id: 'a', max_distance: 5.0)
204
+ expect(reachable.map { |r| r[:id] }).not_to include('a')
205
+ end
206
+
207
+ it 'returns empty for isolated location' do
208
+ store.add_location(id: 'island')
209
+ expect(store.reachable_from(id: 'island', max_distance: 10.0)).to be_empty
210
+ end
211
+
212
+ it 'sorts results by distance' do
213
+ reachable = store.reachable_from(id: 'a', max_distance: 5.0)
214
+ distances = reachable.map { |r| r[:distance] }
215
+ expect(distances).to eq(distances.sort)
216
+ end
217
+ end
218
+
219
+ describe '#clusters' do
220
+ it 'returns one cluster for a connected graph' do
221
+ add_triangle
222
+ expect(store.clusters.size).to eq(1)
223
+ end
224
+
225
+ it 'returns multiple clusters for disconnected graph' do
226
+ store.add_location(id: 'a')
227
+ store.add_location(id: 'b')
228
+ store.add_location(id: 'island')
229
+ store.connect(from: 'a', to: 'b')
230
+ clusters = store.clusters
231
+ expect(clusters.size).to eq(2)
232
+ end
233
+
234
+ it 'returns empty array for empty map' do
235
+ expect(store.clusters).to be_empty
236
+ end
237
+ end
238
+
239
+ describe '#most_familiar' do
240
+ it 'returns top N locations by familiarity' do
241
+ 5.times { |i| store.add_location(id: "loc_#{i}") }
242
+ 3.times { store.visit(id: 'loc_0') }
243
+ store.visit(id: 'loc_1')
244
+ result = store.most_familiar(limit: 2)
245
+ expect(result.size).to eq(2)
246
+ expect(result.first[:id]).to eq('loc_0')
247
+ end
248
+
249
+ it 'returns fewer results than n when map has fewer locations' do
250
+ store.add_location(id: 'only_one')
251
+ result = store.most_familiar(limit: 10)
252
+ expect(result.size).to eq(1)
253
+ end
254
+ end
255
+
256
+ describe '#decay_all' do
257
+ it 'decays familiarity of all locations' do
258
+ store.add_location(id: 'a')
259
+ store.visit(id: 'a')
260
+ before = store.location('a').familiarity
261
+ store.decay_all
262
+ expect(store.location('a').familiarity).to be < before
263
+ end
264
+
265
+ it 'prunes faded locations' do
266
+ store.add_location(id: 'fresh')
267
+ store.add_location(id: 'faded')
268
+ # faded has floor familiarity and 0 visits — already qualifies as faded
269
+ result = store.decay_all
270
+ expect(result[:pruned]).to be >= 0
271
+ end
272
+
273
+ it 'returns decay and prune counts' do
274
+ store.add_location(id: 'a')
275
+ store.visit(id: 'a')
276
+ result = store.decay_all
277
+ expect(result).to include(:decayed, :pruned)
278
+ end
279
+ end
280
+
281
+ describe '#context_switch' do
282
+ it 'switches to a new context' do
283
+ result = store.context_switch(context_id: :work)
284
+ expect(result[:switched]).to be true
285
+ expect(result[:context]).to eq(:work)
286
+ end
287
+
288
+ it 'new context starts empty' do
289
+ store.add_location(id: 'default_loc')
290
+ store.context_switch(context_id: :new_context)
291
+ expect(store.location_count).to eq(0)
292
+ end
293
+
294
+ it 'preserves locations in original context' do
295
+ store.add_location(id: 'default_loc')
296
+ store.context_switch(context_id: :other)
297
+ store.context_switch(context_id: :default)
298
+ expect(store.location('default_loc')).not_to be_nil
299
+ end
300
+
301
+ it 'returns failure when MAX_CONTEXTS exceeded' do
302
+ max = Legion::Extensions::Agentic::Integration::Map::Helpers::Constants::MAX_CONTEXTS
303
+ max.times { |i| store.context_switch(context_id: :"ctx_#{i}") }
304
+ result = store.context_switch(context_id: :overflow)
305
+ expect(result[:switched]).to be false
306
+ end
307
+ end
308
+
309
+ describe '#to_h' do
310
+ it 'returns stats hash with expected keys' do
311
+ stats = store.to_h
312
+ expect(stats).to include(:context, :context_count, :location_count, :edge_count, :visit_history, :cached_paths)
313
+ end
314
+
315
+ it 'reflects current location count' do
316
+ store.add_location(id: 'a')
317
+ store.add_location(id: 'b')
318
+ expect(store.to_h[:location_count]).to eq(2)
319
+ end
320
+ end
321
+ end