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,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Constants do
4
+ describe 'NODE_TYPES' do
5
+ it 'includes all expected node types' do
6
+ expected = %i[corridor junction dead_end entrance exit minotaur_lair]
7
+ expect(described_class::NODE_TYPES).to eq(expected)
8
+ end
9
+
10
+ it 'is frozen' do
11
+ expect(described_class::NODE_TYPES).to be_frozen
12
+ end
13
+ end
14
+
15
+ describe 'MAX_LABYRINTHS' do
16
+ it 'is a positive integer' do
17
+ expect(described_class::MAX_LABYRINTHS).to be_a(Integer)
18
+ expect(described_class::MAX_LABYRINTHS).to be_positive
19
+ end
20
+ end
21
+
22
+ describe 'MAX_NODES' do
23
+ it 'is a positive integer' do
24
+ expect(described_class::MAX_NODES).to be_a(Integer)
25
+ expect(described_class::MAX_NODES).to be_positive
26
+ end
27
+ end
28
+
29
+ describe 'COMPLEXITY_LABELS' do
30
+ it 'covers the full 0..1 range' do
31
+ [0.0, 0.1, 0.3, 0.5, 0.7, 0.9, 1.0].each do |score|
32
+ match = described_class::COMPLEXITY_LABELS.any? { |range, _| range.cover?(score) }
33
+ expect(match).to be(true), "score #{score} not covered by COMPLEXITY_LABELS"
34
+ end
35
+ end
36
+
37
+ it 'maps low scores to :trivial' do
38
+ label = described_class::COMPLEXITY_LABELS.find { |r, _| r.cover?(0.05) }&.last
39
+ expect(label).to eq(:trivial)
40
+ end
41
+
42
+ it 'maps high scores to :labyrinthine' do
43
+ label = described_class::COMPLEXITY_LABELS.find { |r, _| r.cover?(0.95) }&.last
44
+ expect(label).to eq(:labyrinthine)
45
+ end
46
+ end
47
+
48
+ describe 'DANGER_LABELS' do
49
+ it 'covers the full 0..1 range' do
50
+ [0.0, 0.24, 0.3, 0.6, 0.8, 1.0].each do |level|
51
+ match = described_class::DANGER_LABELS.any? { |range, _| range.cover?(level) }
52
+ expect(match).to be(true), "level #{level} not covered by DANGER_LABELS"
53
+ end
54
+ end
55
+
56
+ it 'maps low danger to :safe' do
57
+ label = described_class::DANGER_LABELS.find { |r, _| r.cover?(0.1) }&.last
58
+ expect(label).to eq(:safe)
59
+ end
60
+
61
+ it 'maps high danger to :lethal' do
62
+ label = described_class::DANGER_LABELS.find { |r, _| r.cover?(0.9) }&.last
63
+ expect(label).to eq(:lethal)
64
+ end
65
+ end
66
+
67
+ describe 'MINOTAUR_DANGER_LEVEL' do
68
+ it 'is >= 0.5' do
69
+ expect(described_class::MINOTAUR_DANGER_LEVEL).to be >= 0.5
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,222 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::LabyrinthEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ let(:lab_id) do
7
+ result = engine.create_labyrinth(name: 'Test Maze')
8
+ result.labyrinth_id
9
+ end
10
+
11
+ describe '#create_labyrinth' do
12
+ it 'creates a new labyrinth and returns it' do
13
+ lab = engine.create_labyrinth(name: 'Puzzle', domain: :logic)
14
+ expect(lab).to be_a(Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Labyrinth)
15
+ expect(lab.name).to eq('Puzzle')
16
+ expect(lab.domain).to eq(:logic)
17
+ end
18
+
19
+ it 'uses provided labyrinth_id' do
20
+ lab = engine.create_labyrinth(name: 'Custom', labyrinth_id: 'my-id')
21
+ expect(lab.labyrinth_id).to eq('my-id')
22
+ end
23
+
24
+ it 'generates a UUID when labyrinth_id is not provided' do
25
+ lab = engine.create_labyrinth(name: 'Auto')
26
+ expect(lab.labyrinth_id).to match(/\A[0-9a-f-]{36}\z/)
27
+ end
28
+
29
+ it 'raises ArgumentError at MAX_LABYRINTHS' do
30
+ max = Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Constants::MAX_LABYRINTHS
31
+ max.times { |i| engine.create_labyrinth(name: "lab #{i}") }
32
+ expect { engine.create_labyrinth(name: 'overflow') }.to raise_error(ArgumentError, /max labyrinths/)
33
+ end
34
+
35
+ it 'stores the labyrinth in @labyrinths' do
36
+ lab = engine.create_labyrinth(name: 'Stored')
37
+ expect(engine.labyrinths[lab.labyrinth_id]).to eq(lab)
38
+ end
39
+ end
40
+
41
+ describe '#add_node_to' do
42
+ it 'adds a corridor node' do
43
+ node = engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, content: 'a dark hallway')
44
+ expect(node.node_type).to eq(:corridor)
45
+ expect(node.content).to eq('a dark hallway')
46
+ end
47
+
48
+ it 'auto-assigns danger level for minotaur_lair' do
49
+ node = engine.add_node_to(labyrinth_id: lab_id, node_type: :minotaur_lair)
50
+ expect(node.danger_level).to eq(Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Constants::MINOTAUR_DANGER_LEVEL)
51
+ end
52
+
53
+ it 'uses provided node_id' do
54
+ node = engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, node_id: 'fixed-id')
55
+ expect(node.node_id).to eq('fixed-id')
56
+ end
57
+
58
+ it 'raises ArgumentError for unknown labyrinth' do
59
+ expect do
60
+ engine.add_node_to(labyrinth_id: 'nonexistent', node_type: :corridor)
61
+ end.to raise_error(ArgumentError, /not found/)
62
+ end
63
+ end
64
+
65
+ describe '#connect_nodes' do
66
+ let(:from_id) { engine.add_node_to(labyrinth_id: lab_id, node_type: :entrance).node_id }
67
+ let(:to_id) { engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor).node_id }
68
+
69
+ it 'connects two nodes bidirectionally by default' do
70
+ engine.connect_nodes(labyrinth_id: lab_id, from_id: from_id, to_id: to_id)
71
+ lab = engine.labyrinths[lab_id]
72
+ expect(lab.nodes[from_id].connections).to include(to_id)
73
+ expect(lab.nodes[to_id].connections).to include(from_id)
74
+ end
75
+
76
+ it 'connects one-way when bidirectional: false' do
77
+ engine.connect_nodes(labyrinth_id: lab_id, from_id: from_id, to_id: to_id, bidirectional: false)
78
+ lab = engine.labyrinths[lab_id]
79
+ expect(lab.nodes[from_id].connections).to include(to_id)
80
+ expect(lab.nodes[to_id].connections).not_to include(from_id)
81
+ end
82
+
83
+ it 'returns a result hash' do
84
+ result = engine.connect_nodes(labyrinth_id: lab_id, from_id: from_id, to_id: to_id)
85
+ expect(result[:connected]).to be(true)
86
+ expect(result[:from]).to eq(from_id)
87
+ expect(result[:to]).to eq(to_id)
88
+ end
89
+ end
90
+
91
+ describe '#move' do
92
+ before do
93
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance')
94
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor')
95
+ engine.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor')
96
+ end
97
+
98
+ it 'moves to a connected node and returns result hash' do
99
+ result = engine.move(labyrinth_id: lab_id, node_id: 'corridor')
100
+ expect(result[:success]).to be(true)
101
+ expect(result[:node_id]).to eq('corridor')
102
+ expect(result[:node_type]).to eq(:corridor)
103
+ expect(result[:path_length]).to eq(1)
104
+ end
105
+
106
+ it 'includes minotaur check result' do
107
+ result = engine.move(labyrinth_id: lab_id, node_id: 'corridor')
108
+ expect(result[:minotaur]).to be_a(Hash)
109
+ expect(result[:minotaur][:encountered]).to be(false)
110
+ end
111
+ end
112
+
113
+ describe '#backtrack' do
114
+ before do
115
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance')
116
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor')
117
+ engine.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor')
118
+ engine.move(labyrinth_id: lab_id, node_id: 'corridor')
119
+ end
120
+
121
+ it 'backtracks to previous node' do
122
+ result = engine.backtrack(labyrinth_id: lab_id)
123
+ expect(result[:success]).to be(true)
124
+ expect(result[:node_id]).to eq('entrance')
125
+ end
126
+
127
+ it 'returns failure when no breadcrumbs' do
128
+ engine.backtrack(labyrinth_id: lab_id)
129
+ result = engine.backtrack(labyrinth_id: lab_id)
130
+ expect(result[:success]).to be(false)
131
+ expect(result[:reason]).to eq(:no_breadcrumbs)
132
+ end
133
+ end
134
+
135
+ describe '#follow_thread' do
136
+ before do
137
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance')
138
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, node_id: 'corridor')
139
+ engine.connect_nodes(labyrinth_id: lab_id, from_id: 'entrance', to_id: 'corridor')
140
+ end
141
+
142
+ it 'follows to the first unvisited node' do
143
+ result = engine.follow_thread(labyrinth_id: lab_id)
144
+ expect(result[:success]).to be(true)
145
+ expect(result[:node_id]).to eq('corridor')
146
+ end
147
+
148
+ it 'returns thread_exhausted when nothing unvisited' do
149
+ engine.labyrinths[lab_id].nodes['corridor'].visited = true
150
+ result = engine.follow_thread(labyrinth_id: lab_id)
151
+ expect(result[:success]).to be(false)
152
+ expect(result[:reason]).to eq(:thread_exhausted)
153
+ end
154
+ end
155
+
156
+ describe '#check_minotaur' do
157
+ before do
158
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :minotaur_lair, node_id: 'lair', content: 'sunk cost fallacy')
159
+ end
160
+
161
+ it 'returns encountered: true when on minotaur_lair' do
162
+ engine.labyrinths[lab_id].instance_variable_set(:@current_node_id, 'lair')
163
+ result = engine.check_minotaur(labyrinth_id: lab_id)
164
+ expect(result[:encountered]).to be(true)
165
+ expect(result[:misconception]).to eq('sunk cost fallacy')
166
+ expect(result[:danger_label]).to be_a(Symbol)
167
+ end
168
+
169
+ it 'returns encountered: false for safe node' do
170
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :corridor, node_id: 'safe')
171
+ engine.labyrinths[lab_id].instance_variable_set(:@current_node_id, 'safe')
172
+ result = engine.check_minotaur(labyrinth_id: lab_id)
173
+ expect(result[:encountered]).to be(false)
174
+ end
175
+ end
176
+
177
+ describe '#labyrinth_report' do
178
+ before do
179
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :entrance, node_id: 'entrance')
180
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :dead_end, node_id: 'dead')
181
+ engine.add_node_to(labyrinth_id: lab_id, node_type: :exit, node_id: 'exit')
182
+ end
183
+
184
+ it 'returns a comprehensive report hash' do
185
+ report = engine.labyrinth_report(labyrinth_id: lab_id)
186
+ expect(report).to include(:labyrinth_id, :name, :node_count, :nodes_by_type, :visited_count, :breadcrumb_trail, :lost)
187
+ end
188
+
189
+ it 'includes nodes_by_type breakdown' do
190
+ report = engine.labyrinth_report(labyrinth_id: lab_id)
191
+ expect(report[:nodes_by_type]).to include(entrance: 1, dead_end: 1, exit: 1)
192
+ end
193
+ end
194
+
195
+ describe '#list_labyrinths' do
196
+ it 'returns empty array initially' do
197
+ fresh = described_class.new
198
+ expect(fresh.list_labyrinths).to eq([])
199
+ end
200
+
201
+ it 'lists all created labyrinths' do
202
+ fresh = described_class.new
203
+ fresh.create_labyrinth(name: 'A')
204
+ fresh.create_labyrinth(name: 'B')
205
+ list = fresh.list_labyrinths
206
+ expect(list.size).to eq(2)
207
+ expect(list.map { |l| l[:name] }).to include('A', 'B')
208
+ end
209
+ end
210
+
211
+ describe '#delete_labyrinth' do
212
+ it 'removes the labyrinth' do
213
+ result = engine.delete_labyrinth(labyrinth_id: lab_id)
214
+ expect(result[:deleted]).to be(true)
215
+ expect(engine.labyrinths).not_to have_key(lab_id)
216
+ end
217
+
218
+ it 'raises ArgumentError for unknown labyrinth' do
219
+ expect { engine.delete_labyrinth(labyrinth_id: 'nope') }.to raise_error(ArgumentError, /not found/)
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,235 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Labyrinth do
4
+ let(:labyrinth_id) { 'lab-001' }
5
+ let(:labyrinth) { described_class.new(labyrinth_id: labyrinth_id, name: 'Test Maze', domain: :reasoning) }
6
+
7
+ let(:node_class) { Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Node }
8
+
9
+ def make_node(id, type, **)
10
+ node_class.new(node_id: id, node_type: type, **)
11
+ end
12
+
13
+ describe '#initialize' do
14
+ it 'creates a labyrinth with correct attributes' do
15
+ expect(labyrinth.labyrinth_id).to eq(labyrinth_id)
16
+ expect(labyrinth.name).to eq('Test Maze')
17
+ expect(labyrinth.domain).to eq(:reasoning)
18
+ expect(labyrinth.nodes).to eq({})
19
+ expect(labyrinth.breadcrumbs).to eq([])
20
+ expect(labyrinth.current_node_id).to be_nil
21
+ expect(labyrinth.solved).to be(false)
22
+ end
23
+ end
24
+
25
+ describe '#add_node' do
26
+ it 'adds a node to the labyrinth' do
27
+ node = make_node('n1', :corridor)
28
+ labyrinth.add_node(node)
29
+ expect(labyrinth.nodes['n1']).to eq(node)
30
+ end
31
+
32
+ it 'sets current_node_id to entrance node' do
33
+ entrance = make_node('entrance-1', :entrance)
34
+ labyrinth.add_node(entrance)
35
+ expect(labyrinth.current_node_id).to eq('entrance-1')
36
+ end
37
+
38
+ it 'does not override current_node_id once set' do
39
+ entrance = make_node('entrance-1', :entrance)
40
+ entrance2 = make_node('entrance-2', :entrance)
41
+ labyrinth.add_node(entrance)
42
+ labyrinth.add_node(entrance2)
43
+ expect(labyrinth.current_node_id).to eq('entrance-1')
44
+ end
45
+
46
+ it 'raises ArgumentError for non-Node argument' do
47
+ expect { labyrinth.add_node('not a node') }.to raise_error(ArgumentError, /must be a/)
48
+ end
49
+
50
+ it 'raises ArgumentError when MAX_NODES exceeded' do
51
+ max = Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Constants::MAX_NODES
52
+ max.times { |i| labyrinth.add_node(make_node("n#{i}", :corridor)) }
53
+ expect { labyrinth.add_node(make_node('overflow', :corridor)) }.to raise_error(ArgumentError, /max nodes/)
54
+ end
55
+ end
56
+
57
+ describe '#move_to!' do
58
+ before do
59
+ entrance = make_node('entrance', :entrance)
60
+ corridor = make_node('corridor', :corridor)
61
+ exit_node = make_node('exit', :exit)
62
+ entrance.connect!('corridor')
63
+ corridor.connect!('entrance')
64
+ corridor.connect!('exit')
65
+ exit_node.connect!('corridor')
66
+ labyrinth.add_node(entrance)
67
+ labyrinth.add_node(corridor)
68
+ labyrinth.add_node(exit_node)
69
+ end
70
+
71
+ it 'moves to a connected node' do
72
+ labyrinth.move_to!('corridor')
73
+ expect(labyrinth.current_node_id).to eq('corridor')
74
+ end
75
+
76
+ it 'marks the target node as visited' do
77
+ labyrinth.move_to!('corridor')
78
+ expect(labyrinth.nodes['corridor'].visited).to be(true)
79
+ end
80
+
81
+ it 'drops a breadcrumb on the previous node' do
82
+ labyrinth.move_to!('corridor')
83
+ expect(labyrinth.breadcrumbs).to include('entrance')
84
+ end
85
+
86
+ it 'sets solved when moving to exit' do
87
+ labyrinth.move_to!('corridor')
88
+ labyrinth.move_to!('exit')
89
+ expect(labyrinth.solved?).to be(true)
90
+ end
91
+
92
+ it 'raises ArgumentError for unknown node_id' do
93
+ expect { labyrinth.move_to!('unknown') }.to raise_error(ArgumentError, /not found/)
94
+ end
95
+
96
+ it 'raises ArgumentError when not connected' do
97
+ expect { labyrinth.move_to!('exit') }.to raise_error(ArgumentError, /not connected/)
98
+ end
99
+ end
100
+
101
+ describe '#backtrack!' do
102
+ before do
103
+ entrance = make_node('entrance', :entrance)
104
+ corridor = make_node('corridor', :corridor)
105
+ entrance.connect!('corridor')
106
+ corridor.connect!('entrance')
107
+ labyrinth.add_node(entrance)
108
+ labyrinth.add_node(corridor)
109
+ labyrinth.move_to!('corridor')
110
+ end
111
+
112
+ it 'returns nil when no breadcrumbs' do
113
+ empty_lab = described_class.new(labyrinth_id: 'x', name: 'x')
114
+ expect(empty_lab.backtrack!).to be_nil
115
+ end
116
+
117
+ it 'moves back to the previous node' do
118
+ labyrinth.backtrack!
119
+ expect(labyrinth.current_node_id).to eq('entrance')
120
+ end
121
+ end
122
+
123
+ describe '#follow_thread' do
124
+ before do
125
+ entrance = make_node('entrance', :entrance)
126
+ corridor = make_node('corridor', :corridor)
127
+ entrance.connect!('corridor')
128
+ corridor.connect!('entrance')
129
+ labyrinth.add_node(entrance)
130
+ labyrinth.add_node(corridor)
131
+ end
132
+
133
+ it 'moves to the first unvisited connected node' do
134
+ result = labyrinth.follow_thread
135
+ expect(result).not_to be_nil
136
+ expect(labyrinth.current_node_id).to eq('corridor')
137
+ end
138
+
139
+ it 'returns nil when all connections are visited' do
140
+ labyrinth.nodes['corridor'].visited = true
141
+ result = labyrinth.follow_thread
142
+ expect(result).to be_nil
143
+ end
144
+
145
+ it 'returns nil when current node is nil' do
146
+ empty_lab = described_class.new(labyrinth_id: 'x', name: 'x')
147
+ expect(empty_lab.follow_thread).to be_nil
148
+ end
149
+ end
150
+
151
+ describe '#path_length' do
152
+ it 'returns 0 when no moves made' do
153
+ expect(labyrinth.path_length).to eq(0)
154
+ end
155
+
156
+ it 'returns breadcrumb count' do
157
+ entrance = make_node('entrance', :entrance)
158
+ corridor = make_node('corridor', :corridor)
159
+ entrance.connect!('corridor')
160
+ corridor.connect!('entrance')
161
+ labyrinth.add_node(entrance)
162
+ labyrinth.add_node(corridor)
163
+ labyrinth.move_to!('corridor')
164
+ expect(labyrinth.path_length).to eq(1)
165
+ end
166
+ end
167
+
168
+ describe '#complexity' do
169
+ it 'returns 0.0 for empty labyrinth' do
170
+ expect(labyrinth.complexity).to eq(0.0)
171
+ end
172
+
173
+ it 'is higher with more dead ends and minotaur lairs' do
174
+ labyrinth.add_node(make_node('d1', :dead_end))
175
+ labyrinth.add_node(make_node('d2', :dead_end))
176
+ labyrinth.add_node(make_node('m1', :minotaur_lair))
177
+ expect(labyrinth.complexity).to be > 0.0
178
+ end
179
+
180
+ it 'is clamped between 0.0 and 1.0' do
181
+ labyrinth.add_node(make_node('m1', :minotaur_lair))
182
+ expect(labyrinth.complexity).to be_between(0.0, 1.0)
183
+ end
184
+
185
+ it 'rounds to 10 decimal places' do
186
+ labyrinth.add_node(make_node('n1', :corridor))
187
+ expect(labyrinth.complexity.to_s.split('.').last.to_s.length).to be <= 10
188
+ end
189
+ end
190
+
191
+ describe '#complexity_label' do
192
+ it 'returns a symbol' do
193
+ labyrinth.add_node(make_node('n1', :corridor))
194
+ expect(labyrinth.complexity_label).to be_a(Symbol)
195
+ end
196
+
197
+ it 'returns :trivial for a labyrinth with only well-connected corridors' do
198
+ # A junction connected to several corridors — no dead ends, no minotaurs
199
+ j = make_node('j', :junction)
200
+ c1 = make_node('c1', :corridor)
201
+ c2 = make_node('c2', :corridor)
202
+ c3 = make_node('c3', :corridor)
203
+ j.connect!('c1')
204
+ j.connect!('c2')
205
+ j.connect!('c3')
206
+ c1.connect!('j')
207
+ c2.connect!('j')
208
+ c3.connect!('j')
209
+ labyrinth.add_node(j)
210
+ labyrinth.add_node(c1)
211
+ labyrinth.add_node(c2)
212
+ labyrinth.add_node(c3)
213
+ expect(labyrinth.complexity_label).to eq(:trivial)
214
+ end
215
+ end
216
+
217
+ describe '#solved?' do
218
+ it 'returns false by default' do
219
+ expect(labyrinth.solved?).to be(false)
220
+ end
221
+ end
222
+
223
+ describe '#lost?' do
224
+ it 'returns false with no current node' do
225
+ expect(labyrinth.lost?).to be(false)
226
+ end
227
+ end
228
+
229
+ describe '#to_h' do
230
+ it 'includes expected keys' do
231
+ h = labyrinth.to_h
232
+ expect(h).to include(:labyrinth_id, :name, :domain, :node_count, :current_node_id, :path_length, :solved, :complexity, :complexity_label)
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,157 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Node do
4
+ let(:node_id) { 'node-001' }
5
+
6
+ describe '#initialize' do
7
+ it 'creates a corridor node' do
8
+ node = described_class.new(node_id: node_id, node_type: :corridor)
9
+ expect(node.node_id).to eq(node_id)
10
+ expect(node.node_type).to eq(:corridor)
11
+ expect(node.visited).to be(false)
12
+ expect(node.connections).to eq([])
13
+ expect(node.danger_level).to eq(0.0)
14
+ end
15
+
16
+ it 'creates a minotaur_lair node' do
17
+ node = described_class.new(node_id: node_id, node_type: :minotaur_lair, content: 'false belief')
18
+ expect(node.node_type).to eq(:minotaur_lair)
19
+ expect(node.content).to eq('false belief')
20
+ end
21
+
22
+ it 'clamps danger_level to 0..1' do
23
+ node = described_class.new(node_id: node_id, node_type: :corridor, danger_level: 2.5)
24
+ expect(node.danger_level).to eq(1.0)
25
+
26
+ node2 = described_class.new(node_id: node_id, node_type: :corridor, danger_level: -1.0)
27
+ expect(node2.danger_level).to eq(0.0)
28
+ end
29
+
30
+ it 'raises ArgumentError for unknown node_type' do
31
+ expect do
32
+ described_class.new(node_id: node_id, node_type: :dungeon)
33
+ end.to raise_error(ArgumentError, /unknown node_type/)
34
+ end
35
+
36
+ it 'accepts all valid node types' do
37
+ Legion::Extensions::Agentic::Integration::Labyrinth::Helpers::Constants::NODE_TYPES.each do |type|
38
+ expect { described_class.new(node_id: "n-#{type}", node_type: type) }.not_to raise_error
39
+ end
40
+ end
41
+ end
42
+
43
+ describe '#connect!' do
44
+ it 'adds a connection' do
45
+ node = described_class.new(node_id: node_id, node_type: :corridor)
46
+ node.connect!('other-node')
47
+ expect(node.connections).to include('other-node')
48
+ end
49
+
50
+ it 'does not duplicate connections' do
51
+ node = described_class.new(node_id: node_id, node_type: :corridor)
52
+ node.connect!('other-node')
53
+ node.connect!('other-node')
54
+ expect(node.connections.count('other-node')).to eq(1)
55
+ end
56
+
57
+ it 'returns self for chaining' do
58
+ node = described_class.new(node_id: node_id, node_type: :corridor)
59
+ expect(node.connect!('other')).to eq(node)
60
+ end
61
+ end
62
+
63
+ describe '#disconnect!' do
64
+ it 'removes a connection' do
65
+ node = described_class.new(node_id: node_id, node_type: :corridor)
66
+ node.connect!('other-node')
67
+ node.disconnect!('other-node')
68
+ expect(node.connections).not_to include('other-node')
69
+ end
70
+
71
+ it 'returns self for chaining' do
72
+ node = described_class.new(node_id: node_id, node_type: :corridor)
73
+ expect(node.disconnect!('nonexistent')).to eq(node)
74
+ end
75
+ end
76
+
77
+ describe '#dead_end?' do
78
+ it 'returns true for :dead_end type' do
79
+ node = described_class.new(node_id: node_id, node_type: :dead_end)
80
+ expect(node.dead_end?).to be(true)
81
+ end
82
+
83
+ it 'returns true for corridor with no connections' do
84
+ node = described_class.new(node_id: node_id, node_type: :corridor)
85
+ expect(node.dead_end?).to be(true)
86
+ end
87
+
88
+ it 'returns false for corridor with connections' do
89
+ node = described_class.new(node_id: node_id, node_type: :corridor)
90
+ node.connect!('somewhere')
91
+ expect(node.dead_end?).to be(false)
92
+ end
93
+
94
+ it 'returns false for entrance with no connections' do
95
+ node = described_class.new(node_id: node_id, node_type: :entrance)
96
+ expect(node.dead_end?).to be(false)
97
+ end
98
+
99
+ it 'returns false for exit with no connections' do
100
+ node = described_class.new(node_id: node_id, node_type: :exit)
101
+ expect(node.dead_end?).to be(false)
102
+ end
103
+ end
104
+
105
+ describe '#junction?' do
106
+ it 'returns true for :junction type' do
107
+ node = described_class.new(node_id: node_id, node_type: :junction)
108
+ expect(node.junction?).to be(true)
109
+ end
110
+
111
+ it 'returns true for corridor with 3+ connections' do
112
+ node = described_class.new(node_id: node_id, node_type: :corridor)
113
+ node.connect!('a')
114
+ node.connect!('b')
115
+ node.connect!('c')
116
+ expect(node.junction?).to be(true)
117
+ end
118
+
119
+ it 'returns false for corridor with 2 connections' do
120
+ node = described_class.new(node_id: node_id, node_type: :corridor)
121
+ node.connect!('a')
122
+ node.connect!('b')
123
+ expect(node.junction?).to be(false)
124
+ end
125
+ end
126
+
127
+ describe '#dangerous?' do
128
+ it 'returns true for :minotaur_lair type' do
129
+ node = described_class.new(node_id: node_id, node_type: :minotaur_lair)
130
+ expect(node.dangerous?).to be(true)
131
+ end
132
+
133
+ it 'returns true for danger_level >= 0.5' do
134
+ node = described_class.new(node_id: node_id, node_type: :corridor, danger_level: 0.5)
135
+ expect(node.dangerous?).to be(true)
136
+ end
137
+
138
+ it 'returns false for safe corridor' do
139
+ node = described_class.new(node_id: node_id, node_type: :corridor, danger_level: 0.2)
140
+ expect(node.dangerous?).to be(false)
141
+ end
142
+ end
143
+
144
+ describe '#to_h' do
145
+ it 'returns a hash with expected keys' do
146
+ node = described_class.new(node_id: node_id, node_type: :junction, content: 'crossroads', danger_level: 0.3)
147
+ node.connect!('n2')
148
+ h = node.to_h
149
+ expect(h[:node_id]).to eq(node_id)
150
+ expect(h[:node_type]).to eq(:junction)
151
+ expect(h[:content]).to eq('crossroads')
152
+ expect(h[:connections]).to eq(['n2'])
153
+ expect(h[:visited]).to be(false)
154
+ expect(h[:danger_level]).to eq(0.3)
155
+ end
156
+ end
157
+ end