lex-agentic-memory 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 (267) 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-memory.gemspec +30 -0
  7. data/lib/legion/extensions/agentic/memory/archaeology/client.rb +19 -0
  8. data/lib/legion/extensions/agentic/memory/archaeology/helpers/archaeology_engine.rb +184 -0
  9. data/lib/legion/extensions/agentic/memory/archaeology/helpers/artifact.rb +146 -0
  10. data/lib/legion/extensions/agentic/memory/archaeology/helpers/constants.rb +95 -0
  11. data/lib/legion/extensions/agentic/memory/archaeology/helpers/excavation_site.rb +97 -0
  12. data/lib/legion/extensions/agentic/memory/archaeology/runners/cognitive_archaeology.rb +86 -0
  13. data/lib/legion/extensions/agentic/memory/archaeology/version.rb +13 -0
  14. data/lib/legion/extensions/agentic/memory/archaeology.rb +22 -0
  15. data/lib/legion/extensions/agentic/memory/compression/client.rb +15 -0
  16. data/lib/legion/extensions/agentic/memory/compression/helpers/compression_engine.rb +145 -0
  17. data/lib/legion/extensions/agentic/memory/compression/helpers/constants.rb +44 -0
  18. data/lib/legion/extensions/agentic/memory/compression/helpers/information_chunk.rb +81 -0
  19. data/lib/legion/extensions/agentic/memory/compression/runners/cognitive_compression.rb +76 -0
  20. data/lib/legion/extensions/agentic/memory/compression/version.rb +13 -0
  21. data/lib/legion/extensions/agentic/memory/compression.rb +19 -0
  22. data/lib/legion/extensions/agentic/memory/echo/client.rb +19 -0
  23. data/lib/legion/extensions/agentic/memory/echo/helpers/constants.rb +57 -0
  24. data/lib/legion/extensions/agentic/memory/echo/helpers/echo.rb +95 -0
  25. data/lib/legion/extensions/agentic/memory/echo/helpers/echo_engine.rb +136 -0
  26. data/lib/legion/extensions/agentic/memory/echo/runners/cognitive_echo.rb +81 -0
  27. data/lib/legion/extensions/agentic/memory/echo/version.rb +13 -0
  28. data/lib/legion/extensions/agentic/memory/echo.rb +19 -0
  29. data/lib/legion/extensions/agentic/memory/echo_chamber/client.rb +19 -0
  30. data/lib/legion/extensions/agentic/memory/echo_chamber/helpers/chamber.rb +134 -0
  31. data/lib/legion/extensions/agentic/memory/echo_chamber/helpers/chamber_engine.rb +156 -0
  32. data/lib/legion/extensions/agentic/memory/echo_chamber/helpers/constants.rb +60 -0
  33. data/lib/legion/extensions/agentic/memory/echo_chamber/helpers/echo.rb +96 -0
  34. data/lib/legion/extensions/agentic/memory/echo_chamber/runners/cognitive_echo_chamber.rb +84 -0
  35. data/lib/legion/extensions/agentic/memory/echo_chamber/version.rb +13 -0
  36. data/lib/legion/extensions/agentic/memory/echo_chamber.rb +21 -0
  37. data/lib/legion/extensions/agentic/memory/episodic/actors/decay.rb +45 -0
  38. data/lib/legion/extensions/agentic/memory/episodic/client.rb +25 -0
  39. data/lib/legion/extensions/agentic/memory/episodic/helpers/constants.rb +36 -0
  40. data/lib/legion/extensions/agentic/memory/episodic/helpers/episode.rb +104 -0
  41. data/lib/legion/extensions/agentic/memory/episodic/helpers/episodic_binding.rb +57 -0
  42. data/lib/legion/extensions/agentic/memory/episodic/helpers/episodic_store.rb +141 -0
  43. data/lib/legion/extensions/agentic/memory/episodic/runners/episodic_buffer.rb +108 -0
  44. data/lib/legion/extensions/agentic/memory/episodic/version.rb +13 -0
  45. data/lib/legion/extensions/agentic/memory/episodic.rb +20 -0
  46. data/lib/legion/extensions/agentic/memory/hologram/client.rb +23 -0
  47. data/lib/legion/extensions/agentic/memory/hologram/helpers/constants.rb +67 -0
  48. data/lib/legion/extensions/agentic/memory/hologram/helpers/hologram.rb +118 -0
  49. data/lib/legion/extensions/agentic/memory/hologram/helpers/hologram_engine.rb +117 -0
  50. data/lib/legion/extensions/agentic/memory/hologram/helpers/holographic_fragment.rb +70 -0
  51. data/lib/legion/extensions/agentic/memory/hologram/runners/cognitive_hologram.rb +110 -0
  52. data/lib/legion/extensions/agentic/memory/hologram/version.rb +13 -0
  53. data/lib/legion/extensions/agentic/memory/hologram.rb +22 -0
  54. data/lib/legion/extensions/agentic/memory/immune_memory/client.rb +19 -0
  55. data/lib/legion/extensions/agentic/memory/immune_memory/helpers/constants.rb +84 -0
  56. data/lib/legion/extensions/agentic/memory/immune_memory/helpers/encounter.rb +54 -0
  57. data/lib/legion/extensions/agentic/memory/immune_memory/helpers/immune_memory_engine.rb +171 -0
  58. data/lib/legion/extensions/agentic/memory/immune_memory/helpers/memory_cell.rb +97 -0
  59. data/lib/legion/extensions/agentic/memory/immune_memory/runners/cognitive_immune_memory.rb +76 -0
  60. data/lib/legion/extensions/agentic/memory/immune_memory/version.rb +13 -0
  61. data/lib/legion/extensions/agentic/memory/immune_memory.rb +20 -0
  62. data/lib/legion/extensions/agentic/memory/nostalgia/client.rb +31 -0
  63. data/lib/legion/extensions/agentic/memory/nostalgia/helpers/constants.rb +68 -0
  64. data/lib/legion/extensions/agentic/memory/nostalgia/helpers/nostalgia_engine.rb +148 -0
  65. data/lib/legion/extensions/agentic/memory/nostalgia/helpers/nostalgia_event.rb +44 -0
  66. data/lib/legion/extensions/agentic/memory/nostalgia/helpers/nostalgic_memory.rb +97 -0
  67. data/lib/legion/extensions/agentic/memory/nostalgia/runners/analysis.rb +61 -0
  68. data/lib/legion/extensions/agentic/memory/nostalgia/runners/recall.rb +60 -0
  69. data/lib/legion/extensions/agentic/memory/nostalgia/version.rb +13 -0
  70. data/lib/legion/extensions/agentic/memory/nostalgia.rb +21 -0
  71. data/lib/legion/extensions/agentic/memory/offloading/client.rb +29 -0
  72. data/lib/legion/extensions/agentic/memory/offloading/helpers/constants.rb +55 -0
  73. data/lib/legion/extensions/agentic/memory/offloading/helpers/external_store.rb +82 -0
  74. data/lib/legion/extensions/agentic/memory/offloading/helpers/offloaded_item.rb +65 -0
  75. data/lib/legion/extensions/agentic/memory/offloading/helpers/offloading_engine.rb +138 -0
  76. data/lib/legion/extensions/agentic/memory/offloading/runners/cognitive_offloading.rb +102 -0
  77. data/lib/legion/extensions/agentic/memory/offloading/version.rb +13 -0
  78. data/lib/legion/extensions/agentic/memory/offloading.rb +20 -0
  79. data/lib/legion/extensions/agentic/memory/paleontology/client.rb +19 -0
  80. data/lib/legion/extensions/agentic/memory/paleontology/helpers/constants.rb +69 -0
  81. data/lib/legion/extensions/agentic/memory/paleontology/helpers/excavation.rb +62 -0
  82. data/lib/legion/extensions/agentic/memory/paleontology/helpers/fossil.rb +125 -0
  83. data/lib/legion/extensions/agentic/memory/paleontology/helpers/paleontology_engine.rb +170 -0
  84. data/lib/legion/extensions/agentic/memory/paleontology/runners/cognitive_paleontology.rb +93 -0
  85. data/lib/legion/extensions/agentic/memory/paleontology/version.rb +13 -0
  86. data/lib/legion/extensions/agentic/memory/paleontology.rb +22 -0
  87. data/lib/legion/extensions/agentic/memory/palimpsest/client.rb +19 -0
  88. data/lib/legion/extensions/agentic/memory/palimpsest/helpers/belief_layer.rb +81 -0
  89. data/lib/legion/extensions/agentic/memory/palimpsest/helpers/constants.rb +56 -0
  90. data/lib/legion/extensions/agentic/memory/palimpsest/helpers/palimpsest.rb +124 -0
  91. data/lib/legion/extensions/agentic/memory/palimpsest/helpers/palimpsest_engine.rb +117 -0
  92. data/lib/legion/extensions/agentic/memory/palimpsest/runners/cognitive_palimpsest.rb +105 -0
  93. data/lib/legion/extensions/agentic/memory/palimpsest/version.rb +13 -0
  94. data/lib/legion/extensions/agentic/memory/palimpsest.rb +21 -0
  95. data/lib/legion/extensions/agentic/memory/reserve/client.rb +19 -0
  96. data/lib/legion/extensions/agentic/memory/reserve/helpers/constants.rb +58 -0
  97. data/lib/legion/extensions/agentic/memory/reserve/helpers/pathway.rb +112 -0
  98. data/lib/legion/extensions/agentic/memory/reserve/helpers/reserve_engine.rb +163 -0
  99. data/lib/legion/extensions/agentic/memory/reserve/runners/cognitive_reserve.rb +92 -0
  100. data/lib/legion/extensions/agentic/memory/reserve/version.rb +13 -0
  101. data/lib/legion/extensions/agentic/memory/reserve.rb +19 -0
  102. data/lib/legion/extensions/agentic/memory/semantic/actors/decay.rb +45 -0
  103. data/lib/legion/extensions/agentic/memory/semantic/client.rb +28 -0
  104. data/lib/legion/extensions/agentic/memory/semantic/helpers/concept.rb +101 -0
  105. data/lib/legion/extensions/agentic/memory/semantic/helpers/constants.rb +51 -0
  106. data/lib/legion/extensions/agentic/memory/semantic/helpers/knowledge_store.rb +145 -0
  107. data/lib/legion/extensions/agentic/memory/semantic/runners/semantic_memory.rb +94 -0
  108. data/lib/legion/extensions/agentic/memory/semantic/version.rb +13 -0
  109. data/lib/legion/extensions/agentic/memory/semantic.rb +20 -0
  110. data/lib/legion/extensions/agentic/memory/semantic_priming/client.rb +19 -0
  111. data/lib/legion/extensions/agentic/memory/semantic_priming/helpers/connection.rb +77 -0
  112. data/lib/legion/extensions/agentic/memory/semantic_priming/helpers/constants.rb +68 -0
  113. data/lib/legion/extensions/agentic/memory/semantic_priming/helpers/priming_network.rb +206 -0
  114. data/lib/legion/extensions/agentic/memory/semantic_priming/helpers/semantic_node.rb +81 -0
  115. data/lib/legion/extensions/agentic/memory/semantic_priming/runners/semantic_priming.rb +120 -0
  116. data/lib/legion/extensions/agentic/memory/semantic_priming/version.rb +13 -0
  117. data/lib/legion/extensions/agentic/memory/semantic_priming.rb +20 -0
  118. data/lib/legion/extensions/agentic/memory/semantic_satiation/client.rb +28 -0
  119. data/lib/legion/extensions/agentic/memory/semantic_satiation/helpers/concept.rb +82 -0
  120. data/lib/legion/extensions/agentic/memory/semantic_satiation/helpers/constants.rb +37 -0
  121. data/lib/legion/extensions/agentic/memory/semantic_satiation/helpers/satiation_engine.rb +103 -0
  122. data/lib/legion/extensions/agentic/memory/semantic_satiation/runners/semantic_satiation.rb +92 -0
  123. data/lib/legion/extensions/agentic/memory/semantic_satiation/version.rb +13 -0
  124. data/lib/legion/extensions/agentic/memory/semantic_satiation.rb +19 -0
  125. data/lib/legion/extensions/agentic/memory/source_monitoring/actors/decay.rb +31 -0
  126. data/lib/legion/extensions/agentic/memory/source_monitoring/client.rb +28 -0
  127. data/lib/legion/extensions/agentic/memory/source_monitoring/helpers/constants.rb +66 -0
  128. data/lib/legion/extensions/agentic/memory/source_monitoring/helpers/source_record.rb +94 -0
  129. data/lib/legion/extensions/agentic/memory/source_monitoring/helpers/source_tracker.rb +119 -0
  130. data/lib/legion/extensions/agentic/memory/source_monitoring/runners/source_monitoring.rb +95 -0
  131. data/lib/legion/extensions/agentic/memory/source_monitoring/version.rb +13 -0
  132. data/lib/legion/extensions/agentic/memory/source_monitoring.rb +19 -0
  133. data/lib/legion/extensions/agentic/memory/trace/actors/decay.rb +45 -0
  134. data/lib/legion/extensions/agentic/memory/trace/actors/tier_migration.rb +45 -0
  135. data/lib/legion/extensions/agentic/memory/trace/batch_decay.rb +44 -0
  136. data/lib/legion/extensions/agentic/memory/trace/client.rb +32 -0
  137. data/lib/legion/extensions/agentic/memory/trace/helpers/cache_store.rb +167 -0
  138. data/lib/legion/extensions/agentic/memory/trace/helpers/decay.rb +68 -0
  139. data/lib/legion/extensions/agentic/memory/trace/helpers/error_tracer.rb +94 -0
  140. data/lib/legion/extensions/agentic/memory/trace/helpers/store.rb +260 -0
  141. data/lib/legion/extensions/agentic/memory/trace/helpers/trace.rb +106 -0
  142. data/lib/legion/extensions/agentic/memory/trace/local_migrations/20260316000001_create_memory_traces.rb +31 -0
  143. data/lib/legion/extensions/agentic/memory/trace/local_migrations/20260316000002_create_memory_associations.rb +13 -0
  144. data/lib/legion/extensions/agentic/memory/trace/persistent_store.rb +94 -0
  145. data/lib/legion/extensions/agentic/memory/trace/quota.rb +55 -0
  146. data/lib/legion/extensions/agentic/memory/trace/runners/consolidation.rb +121 -0
  147. data/lib/legion/extensions/agentic/memory/trace/runners/traces.rb +105 -0
  148. data/lib/legion/extensions/agentic/memory/trace/version.rb +13 -0
  149. data/lib/legion/extensions/agentic/memory/trace.rb +54 -0
  150. data/lib/legion/extensions/agentic/memory/transfer/client.rb +28 -0
  151. data/lib/legion/extensions/agentic/memory/transfer/helpers/constants.rb +34 -0
  152. data/lib/legion/extensions/agentic/memory/transfer/helpers/domain_knowledge.rb +74 -0
  153. data/lib/legion/extensions/agentic/memory/transfer/helpers/transfer_engine.rb +188 -0
  154. data/lib/legion/extensions/agentic/memory/transfer/runners/transfer_learning.rb +77 -0
  155. data/lib/legion/extensions/agentic/memory/transfer/version.rb +13 -0
  156. data/lib/legion/extensions/agentic/memory/transfer.rb +19 -0
  157. data/lib/legion/extensions/agentic/memory/version.rb +11 -0
  158. data/lib/legion/extensions/agentic/memory.rb +35 -0
  159. data/spec/legion/extensions/agentic/memory/archaeology/client_spec.rb +38 -0
  160. data/spec/legion/extensions/agentic/memory/archaeology/cognitive_archaeology_spec.rb +7 -0
  161. data/spec/legion/extensions/agentic/memory/archaeology/helpers/archaeology_engine_spec.rb +165 -0
  162. data/spec/legion/extensions/agentic/memory/archaeology/helpers/artifact_spec.rb +196 -0
  163. data/spec/legion/extensions/agentic/memory/archaeology/helpers/constants_spec.rb +42 -0
  164. data/spec/legion/extensions/agentic/memory/archaeology/helpers/excavation_site_spec.rb +115 -0
  165. data/spec/legion/extensions/agentic/memory/archaeology/runners/cognitive_archaeology_spec.rb +96 -0
  166. data/spec/legion/extensions/agentic/memory/compression/helpers/compression_engine_spec.rb +138 -0
  167. data/spec/legion/extensions/agentic/memory/compression/helpers/constants_spec.rb +50 -0
  168. data/spec/legion/extensions/agentic/memory/compression/helpers/information_chunk_spec.rb +123 -0
  169. data/spec/legion/extensions/agentic/memory/compression/runners/cognitive_compression_spec.rb +80 -0
  170. data/spec/legion/extensions/agentic/memory/echo/client_spec.rb +20 -0
  171. data/spec/legion/extensions/agentic/memory/echo/cognitive_echo_spec.rb +7 -0
  172. data/spec/legion/extensions/agentic/memory/echo/helpers/echo_engine_spec.rb +152 -0
  173. data/spec/legion/extensions/agentic/memory/echo/helpers/echo_spec.rb +128 -0
  174. data/spec/legion/extensions/agentic/memory/echo/runners_spec.rb +80 -0
  175. data/spec/legion/extensions/agentic/memory/echo_chamber/client_spec.rb +84 -0
  176. data/spec/legion/extensions/agentic/memory/echo_chamber/helpers/chamber_engine_spec.rb +266 -0
  177. data/spec/legion/extensions/agentic/memory/echo_chamber/helpers/chamber_spec.rb +249 -0
  178. data/spec/legion/extensions/agentic/memory/echo_chamber/helpers/constants_spec.rb +130 -0
  179. data/spec/legion/extensions/agentic/memory/echo_chamber/helpers/echo_spec.rb +252 -0
  180. data/spec/legion/extensions/agentic/memory/echo_chamber/runners/cognitive_echo_chamber_spec.rb +185 -0
  181. data/spec/legion/extensions/agentic/memory/episodic/client_spec.rb +80 -0
  182. data/spec/legion/extensions/agentic/memory/episodic/episodic_buffer_spec.rb +15 -0
  183. data/spec/legion/extensions/agentic/memory/episodic/helpers/constants_spec.rb +86 -0
  184. data/spec/legion/extensions/agentic/memory/episodic/helpers/episode_spec.rb +188 -0
  185. data/spec/legion/extensions/agentic/memory/episodic/helpers/episodic_binding_spec.rb +114 -0
  186. data/spec/legion/extensions/agentic/memory/episodic/helpers/episodic_store_spec.rb +201 -0
  187. data/spec/legion/extensions/agentic/memory/episodic/runners/episodic_buffer_spec.rb +208 -0
  188. data/spec/legion/extensions/agentic/memory/hologram/client_spec.rb +89 -0
  189. data/spec/legion/extensions/agentic/memory/hologram/cognitive_hologram_spec.rb +39 -0
  190. data/spec/legion/extensions/agentic/memory/hologram/helpers/constants_spec.rb +143 -0
  191. data/spec/legion/extensions/agentic/memory/hologram/helpers/hologram_engine_spec.rb +268 -0
  192. data/spec/legion/extensions/agentic/memory/hologram/helpers/hologram_spec.rb +256 -0
  193. data/spec/legion/extensions/agentic/memory/hologram/helpers/holographic_fragment_spec.rb +213 -0
  194. data/spec/legion/extensions/agentic/memory/hologram/runners/cognitive_hologram_spec.rb +239 -0
  195. data/spec/legion/extensions/agentic/memory/immune_memory/client_spec.rb +18 -0
  196. data/spec/legion/extensions/agentic/memory/immune_memory/cognitive_immune_memory_spec.rb +7 -0
  197. data/spec/legion/extensions/agentic/memory/immune_memory/helpers/encounter_spec.rb +85 -0
  198. data/spec/legion/extensions/agentic/memory/immune_memory/helpers/immune_memory_engine_spec.rb +203 -0
  199. data/spec/legion/extensions/agentic/memory/immune_memory/helpers/memory_cell_spec.rb +190 -0
  200. data/spec/legion/extensions/agentic/memory/immune_memory/runners_spec.rb +83 -0
  201. data/spec/legion/extensions/agentic/memory/nostalgia/client_spec.rb +71 -0
  202. data/spec/legion/extensions/agentic/memory/nostalgia/helpers/constants_spec.rb +65 -0
  203. data/spec/legion/extensions/agentic/memory/nostalgia/helpers/nostalgia_engine_spec.rb +191 -0
  204. data/spec/legion/extensions/agentic/memory/nostalgia/helpers/nostalgia_event_spec.rb +59 -0
  205. data/spec/legion/extensions/agentic/memory/nostalgia/helpers/nostalgic_memory_spec.rb +134 -0
  206. data/spec/legion/extensions/agentic/memory/nostalgia/runners/analysis_spec.rb +97 -0
  207. data/spec/legion/extensions/agentic/memory/nostalgia/runners/recall_spec.rb +81 -0
  208. data/spec/legion/extensions/agentic/memory/offloading/client_spec.rb +30 -0
  209. data/spec/legion/extensions/agentic/memory/offloading/helpers/constants_spec.rb +71 -0
  210. data/spec/legion/extensions/agentic/memory/offloading/helpers/external_store_spec.rb +158 -0
  211. data/spec/legion/extensions/agentic/memory/offloading/helpers/offloaded_item_spec.rb +123 -0
  212. data/spec/legion/extensions/agentic/memory/offloading/helpers/offloading_engine_spec.rb +250 -0
  213. data/spec/legion/extensions/agentic/memory/offloading/runners/cognitive_offloading_spec.rb +194 -0
  214. data/spec/legion/extensions/agentic/memory/paleontology/client_spec.rb +27 -0
  215. data/spec/legion/extensions/agentic/memory/paleontology/cognitive_paleontology_spec.rb +7 -0
  216. data/spec/legion/extensions/agentic/memory/paleontology/helpers/constants_spec.rb +33 -0
  217. data/spec/legion/extensions/agentic/memory/paleontology/helpers/excavation_spec.rb +71 -0
  218. data/spec/legion/extensions/agentic/memory/paleontology/helpers/fossil_spec.rb +134 -0
  219. data/spec/legion/extensions/agentic/memory/paleontology/helpers/paleontology_engine_spec.rb +148 -0
  220. data/spec/legion/extensions/agentic/memory/paleontology/runners/cognitive_paleontology_spec.rb +89 -0
  221. data/spec/legion/extensions/agentic/memory/palimpsest/client_spec.rb +58 -0
  222. data/spec/legion/extensions/agentic/memory/palimpsest/helpers/belief_layer_spec.rb +150 -0
  223. data/spec/legion/extensions/agentic/memory/palimpsest/helpers/constants_spec.rb +63 -0
  224. data/spec/legion/extensions/agentic/memory/palimpsest/helpers/palimpsest_engine_spec.rb +164 -0
  225. data/spec/legion/extensions/agentic/memory/palimpsest/helpers/palimpsest_spec.rb +172 -0
  226. data/spec/legion/extensions/agentic/memory/palimpsest/runners/cognitive_palimpsest_spec.rb +165 -0
  227. data/spec/legion/extensions/agentic/memory/reserve/client_spec.rb +37 -0
  228. data/spec/legion/extensions/agentic/memory/reserve/helpers/pathway_spec.rb +165 -0
  229. data/spec/legion/extensions/agentic/memory/reserve/helpers/reserve_engine_spec.rb +196 -0
  230. data/spec/legion/extensions/agentic/memory/reserve/runners/cognitive_reserve_spec.rb +96 -0
  231. data/spec/legion/extensions/agentic/memory/semantic/client_spec.rb +35 -0
  232. data/spec/legion/extensions/agentic/memory/semantic/helpers/concept_spec.rb +119 -0
  233. data/spec/legion/extensions/agentic/memory/semantic/helpers/knowledge_store_spec.rb +140 -0
  234. data/spec/legion/extensions/agentic/memory/semantic/runners/semantic_memory_spec.rb +103 -0
  235. data/spec/legion/extensions/agentic/memory/semantic_priming/helpers/connection_spec.rb +98 -0
  236. data/spec/legion/extensions/agentic/memory/semantic_priming/helpers/priming_network_spec.rb +208 -0
  237. data/spec/legion/extensions/agentic/memory/semantic_priming/helpers/semantic_node_spec.rb +125 -0
  238. data/spec/legion/extensions/agentic/memory/semantic_priming/semantic_priming_spec.rb +7 -0
  239. data/spec/legion/extensions/agentic/memory/semantic_satiation/client_spec.rb +19 -0
  240. data/spec/legion/extensions/agentic/memory/semantic_satiation/helpers/concept_spec.rb +167 -0
  241. data/spec/legion/extensions/agentic/memory/semantic_satiation/helpers/constants_spec.rb +81 -0
  242. data/spec/legion/extensions/agentic/memory/semantic_satiation/helpers/satiation_engine_spec.rb +189 -0
  243. data/spec/legion/extensions/agentic/memory/semantic_satiation/runners/semantic_satiation_spec.rb +176 -0
  244. data/spec/legion/extensions/agentic/memory/source_monitoring/client_spec.rb +25 -0
  245. data/spec/legion/extensions/agentic/memory/source_monitoring/helpers/source_record_spec.rb +152 -0
  246. data/spec/legion/extensions/agentic/memory/source_monitoring/helpers/source_tracker_spec.rb +139 -0
  247. data/spec/legion/extensions/agentic/memory/source_monitoring/runners/source_monitoring_spec.rb +102 -0
  248. data/spec/legion/extensions/agentic/memory/trace/actors/decay_spec.rb +62 -0
  249. data/spec/legion/extensions/agentic/memory/trace/actors/tier_migration_spec.rb +62 -0
  250. data/spec/legion/extensions/agentic/memory/trace/batch_decay_spec.rb +26 -0
  251. data/spec/legion/extensions/agentic/memory/trace/client_spec.rb +62 -0
  252. data/spec/legion/extensions/agentic/memory/trace/helpers/decay_spec.rb +134 -0
  253. data/spec/legion/extensions/agentic/memory/trace/helpers/store_spec.rb +217 -0
  254. data/spec/legion/extensions/agentic/memory/trace/helpers/trace_spec.rb +120 -0
  255. data/spec/legion/extensions/agentic/memory/trace/local_persistence_spec.rb +255 -0
  256. data/spec/legion/extensions/agentic/memory/trace/memory_spec.rb +11 -0
  257. data/spec/legion/extensions/agentic/memory/trace/persistent_store_spec.rb +50 -0
  258. data/spec/legion/extensions/agentic/memory/trace/quota_spec.rb +56 -0
  259. data/spec/legion/extensions/agentic/memory/trace/runners/consolidation_spec.rb +118 -0
  260. data/spec/legion/extensions/agentic/memory/trace/runners/traces_spec.rb +69 -0
  261. data/spec/legion/extensions/agentic/memory/transfer/client_spec.rb +18 -0
  262. data/spec/legion/extensions/agentic/memory/transfer/helpers/constants_spec.rb +41 -0
  263. data/spec/legion/extensions/agentic/memory/transfer/helpers/domain_knowledge_spec.rb +134 -0
  264. data/spec/legion/extensions/agentic/memory/transfer/helpers/transfer_engine_spec.rb +299 -0
  265. data/spec/legion/extensions/agentic/memory/transfer/runners/transfer_learning_spec.rb +144 -0
  266. data/spec/spec_helper.rb +46 -0
  267. metadata +351 -0
@@ -0,0 +1,194 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'legion/extensions/agentic/memory/offloading/client'
4
+
5
+ RSpec.describe Legion::Extensions::Agentic::Memory::Offloading::Runners::CognitiveOffloading do
6
+ let(:engine) { Legion::Extensions::Agentic::Memory::Offloading::Helpers::OffloadingEngine.new }
7
+ let(:client) { Legion::Extensions::Agentic::Memory::Offloading::Client.new(engine: engine) }
8
+
9
+ let(:store) do
10
+ client.register_store(name: 'test_store', store_type: :database)
11
+ engine.stores.values.first
12
+ end
13
+
14
+ before { store }
15
+
16
+ describe '#register_store' do
17
+ it 'returns success: true on valid registration' do
18
+ result = client.register_store(name: 'another_store', store_type: :file)
19
+ expect(result[:success]).to be true
20
+ end
21
+
22
+ it 'returns the store hash' do
23
+ result = client.register_store(name: 'notes', store_type: :notes)
24
+ expect(result[:store]).to include(:id, :name, :store_type, :trust)
25
+ end
26
+
27
+ it 'returns success: false when limit reached' do
28
+ stub_const('Legion::Extensions::Agentic::Memory::Offloading::Helpers::Constants::MAX_STORES', 1)
29
+ fresh = Legion::Extensions::Agentic::Memory::Offloading::Client.new
30
+ fresh.register_store(name: 'first', store_type: :file)
31
+ result = fresh.register_store(name: 'overflow', store_type: :file)
32
+ expect(result[:success]).to be false
33
+ expect(result[:reason]).to eq(:limit_reached)
34
+ end
35
+
36
+ it 'accepts an injected engine' do
37
+ injected = Legion::Extensions::Agentic::Memory::Offloading::Helpers::OffloadingEngine.new
38
+ result = client.register_store(name: 'injected', store_type: :agent, engine: injected)
39
+ expect(result[:success]).to be true
40
+ end
41
+ end
42
+
43
+ describe '#offload_item' do
44
+ it 'returns success: true on valid offload' do
45
+ result = client.offload_item(content: 'fact', item_type: :fact, importance: 0.7, store_id: store.id)
46
+ expect(result[:success]).to be true
47
+ end
48
+
49
+ it 'returns the item hash' do
50
+ result = client.offload_item(content: 'plan', item_type: :plan, importance: 0.8, store_id: store.id)
51
+ expect(result[:item]).to include(:id, :content, :item_type, :importance)
52
+ end
53
+
54
+ it 'returns success: false for unknown store_id' do
55
+ result = client.offload_item(content: 'x', item_type: :fact, importance: 0.5, store_id: 'bogus')
56
+ expect(result[:success]).to be false
57
+ expect(result[:reason]).to eq(:offload_failed)
58
+ end
59
+
60
+ it 'returns success: false when item limit reached' do
61
+ stub_const('Legion::Extensions::Agentic::Memory::Offloading::Helpers::Constants::MAX_ITEMS', 1)
62
+ client.offload_item(content: 'first', item_type: :fact, importance: 0.5, store_id: store.id)
63
+ result = client.offload_item(content: 'second', item_type: :fact, importance: 0.5, store_id: store.id)
64
+ expect(result[:success]).to be false
65
+ end
66
+ end
67
+
68
+ describe '#retrieve_item' do
69
+ let!(:offloaded) do
70
+ client.offload_item(content: 'my fact', item_type: :fact, importance: 0.6, store_id: store.id)[:item]
71
+ end
72
+
73
+ it 'returns success: true for known item' do
74
+ result = client.retrieve_item(item_id: offloaded[:id])
75
+ expect(result[:success]).to be true
76
+ end
77
+
78
+ it 'returns the item hash on success' do
79
+ result = client.retrieve_item(item_id: offloaded[:id])
80
+ expect(result[:item]).to include(:id, :retrieved_count)
81
+ end
82
+
83
+ it 'increments retrieved_count' do
84
+ client.retrieve_item(item_id: offloaded[:id])
85
+ result = client.retrieve_item(item_id: offloaded[:id])
86
+ expect(result[:item][:retrieved_count]).to eq(2)
87
+ end
88
+
89
+ it 'returns success: false for unknown item_id' do
90
+ result = client.retrieve_item(item_id: 'no-such-item')
91
+ expect(result[:success]).to be false
92
+ expect(result[:reason]).to eq(:not_found)
93
+ end
94
+ end
95
+
96
+ describe '#report_retrieval_failure' do
97
+ let!(:offloaded) do
98
+ client.offload_item(content: 'plan', item_type: :plan, importance: 0.5, store_id: store.id)[:item]
99
+ end
100
+
101
+ it 'returns success: true for known item' do
102
+ result = client.report_retrieval_failure(item_id: offloaded[:id])
103
+ expect(result[:success]).to be true
104
+ end
105
+
106
+ it 'returns current store_trust' do
107
+ result = client.report_retrieval_failure(item_id: offloaded[:id])
108
+ expect(result[:store_trust]).to be_a(Float)
109
+ end
110
+
111
+ it 'decays trust on the store' do
112
+ trust_before = store.trust
113
+ client.report_retrieval_failure(item_id: offloaded[:id])
114
+ expect(store.trust).to be < trust_before
115
+ end
116
+
117
+ it 'returns success: false for unknown item_id' do
118
+ result = client.report_retrieval_failure(item_id: 'ghost')
119
+ expect(result[:success]).to be false
120
+ expect(result[:reason]).to eq(:not_found)
121
+ end
122
+ end
123
+
124
+ describe '#items_in_store' do
125
+ it 'returns items belonging to the store' do
126
+ client.offload_item(content: 'a', item_type: :fact, importance: 0.5, store_id: store.id)
127
+ client.offload_item(content: 'b', item_type: :reminder, importance: 0.3, store_id: store.id)
128
+ result = client.items_in_store(store_id: store.id)
129
+ expect(result[:success]).to be true
130
+ expect(result[:count]).to eq(2)
131
+ end
132
+
133
+ it 'returns empty list for store with no items' do
134
+ result = client.items_in_store(store_id: store.id)
135
+ expect(result[:items]).to eq([])
136
+ end
137
+ end
138
+
139
+ describe '#items_by_type' do
140
+ before do
141
+ client.offload_item(content: 'a', item_type: :calculation, importance: 0.4, store_id: store.id)
142
+ client.offload_item(content: 'b', item_type: :calculation, importance: 0.6, store_id: store.id)
143
+ client.offload_item(content: 'c', item_type: :delegation, importance: 0.8, store_id: store.id)
144
+ end
145
+
146
+ it 'returns items of matching type' do
147
+ result = client.items_by_type(item_type: :calculation)
148
+ expect(result[:count]).to eq(2)
149
+ end
150
+
151
+ it 'returns 0 for unused type' do
152
+ result = client.items_by_type(item_type: :reference)
153
+ expect(result[:count]).to eq(0)
154
+ end
155
+ end
156
+
157
+ describe '#most_important_offloaded' do
158
+ before do
159
+ client.offload_item(content: 'low', item_type: :fact, importance: 0.2, store_id: store.id)
160
+ client.offload_item(content: 'high', item_type: :fact, importance: 0.95, store_id: store.id)
161
+ client.offload_item(content: 'mid', item_type: :fact, importance: 0.5, store_id: store.id)
162
+ end
163
+
164
+ it 'returns items in importance-descending order' do
165
+ result = client.most_important_offloaded(limit: 3)
166
+ importances = result[:items].map { |i| i[:importance] }
167
+ expect(importances).to eq(importances.sort.reverse)
168
+ end
169
+
170
+ it 'respects the limit parameter' do
171
+ result = client.most_important_offloaded(limit: 2)
172
+ expect(result[:count]).to eq(2)
173
+ end
174
+ end
175
+
176
+ describe '#offloading_status' do
177
+ it 'returns success: true' do
178
+ result = client.offloading_status
179
+ expect(result[:success]).to be true
180
+ end
181
+
182
+ it 'includes the offloading report' do
183
+ result = client.offloading_status
184
+ expect(result[:report]).to include(:total_items, :total_stores, :offloading_ratio,
185
+ :overall_store_trust, :stores_summary)
186
+ end
187
+
188
+ it 'reflects current item count' do
189
+ client.offload_item(content: 'x', item_type: :context, importance: 0.5, store_id: store.id)
190
+ result = client.offloading_status
191
+ expect(result[:report][:total_items]).to eq(1)
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Client do
4
+ let(:client) { described_class.new }
5
+
6
+ it 'responds to runner methods' do
7
+ expect(client).to respond_to(:record_extinction, :begin_excavation,
8
+ :list_fossils, :paleontology_status)
9
+ end
10
+
11
+ describe '#record_extinction' do
12
+ it 'delegates' do
13
+ result = client.record_extinction(
14
+ fossil_type: :strategy, domain: :cognitive, content: 'old',
15
+ extinction_cause: :obsolescence
16
+ )
17
+ expect(result[:success]).to be true
18
+ end
19
+ end
20
+
21
+ describe '#paleontology_status' do
22
+ it 'returns report' do
23
+ result = client.paleontology_status
24
+ expect(result[:report]).to be_a Hash
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology do
4
+ it 'has a version number' do
5
+ expect(described_class::VERSION).to eq '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Helpers::Constants do
4
+ let(:c) { described_class }
5
+
6
+ it 'defines MAX_FOSSILS' do
7
+ expect(c::MAX_FOSSILS).to eq 500
8
+ end
9
+
10
+ it 'has 8 fossil types' do
11
+ expect(c::FOSSIL_TYPES.size).to eq 8
12
+ end
13
+
14
+ it 'has 6 extinction causes' do
15
+ expect(c::EXTINCTION_CAUSES.size).to eq 6
16
+ end
17
+
18
+ it 'has 8 era names' do
19
+ expect(c::ERA_NAMES.size).to eq 8
20
+ end
21
+
22
+ describe '.label_for' do
23
+ it 'returns matching preservation label' do
24
+ expect(c.label_for(c::PRESERVATION_LABELS, 0.9)).to eq :pristine
25
+ expect(c.label_for(c::PRESERVATION_LABELS, 0.1)).to eq :imprint
26
+ end
27
+
28
+ it 'returns matching significance label' do
29
+ expect(c.label_for(c::SIGNIFICANCE_LABELS, 0.9)).to eq :keystone
30
+ expect(c.label_for(c::SIGNIFICANCE_LABELS, 0.1)).to eq :trivial
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Helpers::Excavation do
4
+ let(:excavation) { described_class.new(target_stratum: 2) }
5
+
6
+ describe '#initialize' do
7
+ it 'assigns a UUID' do
8
+ expect(excavation.id).to match(/\A[0-9a-f-]{36}\z/)
9
+ end
10
+
11
+ it 'sets target_stratum' do
12
+ expect(excavation.target_stratum).to eq 2
13
+ end
14
+
15
+ it 'starts in_progress' do
16
+ expect(excavation.status).to eq :in_progress
17
+ end
18
+
19
+ it 'starts with no fossils' do
20
+ expect(excavation.fossils_found).to be_empty
21
+ end
22
+
23
+ it 'clamps stratum to 0..4' do
24
+ e = described_class.new(target_stratum: 99)
25
+ expect(e.target_stratum).to eq 4
26
+ end
27
+ end
28
+
29
+ describe '#record_find!' do
30
+ it 'adds fossil to finds' do
31
+ fossil = Legion::Extensions::Agentic::Memory::Paleontology::Helpers::Fossil.new(
32
+ fossil_type: :strategy, domain: :cognitive, content: 'x',
33
+ extinction_cause: :obsolescence
34
+ )
35
+ excavation.record_find!(fossil)
36
+ expect(excavation.fossils_found.size).to eq 1
37
+ end
38
+ end
39
+
40
+ describe '#complete!' do
41
+ it 'marks as completed' do
42
+ excavation.complete!
43
+ expect(excavation).to be_completed
44
+ end
45
+
46
+ it 'returns false if already completed' do
47
+ excavation.complete!
48
+ expect(excavation.complete!).to be false
49
+ end
50
+
51
+ it 'sets completed_at' do
52
+ excavation.complete!
53
+ expect(excavation.completed_at).to be_a Time
54
+ end
55
+ end
56
+
57
+ describe '#yield_rate' do
58
+ it 'returns 0.0 when empty' do
59
+ expect(excavation.yield_rate).to eq 0.0
60
+ end
61
+ end
62
+
63
+ describe '#to_h' do
64
+ it 'includes expected keys' do
65
+ %i[id target_stratum stratum_label fossils_count yield_rate
66
+ status started_at completed_at].each do |key|
67
+ expect(excavation.to_h).to have_key(key)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Helpers::Fossil do
4
+ let(:fossil) do
5
+ described_class.new(fossil_type: :strategy, domain: :cognitive,
6
+ content: 'old approach', extinction_cause: :obsolescence)
7
+ end
8
+
9
+ describe '#initialize' do
10
+ it 'assigns a UUID' do
11
+ expect(fossil.id).to match(/\A[0-9a-f-]{36}\z/)
12
+ end
13
+
14
+ it 'sets fossil_type' do
15
+ expect(fossil.fossil_type).to eq :strategy
16
+ end
17
+
18
+ it 'sets domain' do
19
+ expect(fossil.domain).to eq :cognitive
20
+ end
21
+
22
+ it 'sets extinction_cause' do
23
+ expect(fossil.extinction_cause).to eq :obsolescence
24
+ end
25
+
26
+ it 'defaults preservation to 0.8' do
27
+ expect(fossil.preservation).to eq 0.8
28
+ end
29
+
30
+ it 'defaults significance to 0.5' do
31
+ expect(fossil.significance).to eq 0.5
32
+ end
33
+
34
+ it 'assigns an era' do
35
+ expect(fossil.era).to be_a Symbol
36
+ end
37
+
38
+ it 'raises on invalid fossil_type' do
39
+ expect do
40
+ described_class.new(fossil_type: :bogus, domain: :cognitive,
41
+ content: 'x', extinction_cause: :obsolescence)
42
+ end.to raise_error(ArgumentError, /unknown fossil type/)
43
+ end
44
+
45
+ it 'raises on invalid extinction_cause' do
46
+ expect do
47
+ described_class.new(fossil_type: :strategy, domain: :cognitive,
48
+ content: 'x', extinction_cause: :bogus)
49
+ end.to raise_error(ArgumentError, /unknown extinction cause/)
50
+ end
51
+
52
+ it 'clamps stratum_depth to 0..4' do
53
+ f = described_class.new(fossil_type: :pattern, domain: :semantic,
54
+ content: 'x', extinction_cause: :irrelevance,
55
+ stratum_depth: 99)
56
+ expect(f.stratum_depth).to eq 4
57
+ end
58
+ end
59
+
60
+ describe '#erode!' do
61
+ it 'reduces preservation' do
62
+ original = fossil.preservation
63
+ fossil.erode!
64
+ expect(fossil.preservation).to be < original
65
+ end
66
+
67
+ it 'clamps at 0.0' do
68
+ 50.times { fossil.erode!(rate: 0.1) }
69
+ expect(fossil.preservation).to eq 0.0
70
+ end
71
+
72
+ it 'returns self' do
73
+ expect(fossil.erode!).to eq fossil
74
+ end
75
+ end
76
+
77
+ describe '#reinforce!' do
78
+ it 'increases significance' do
79
+ original = fossil.significance
80
+ fossil.reinforce!(boost: 0.2)
81
+ expect(fossil.significance).to be > original
82
+ end
83
+
84
+ it 'clamps at 1.0' do
85
+ fossil.reinforce!(boost: 5.0)
86
+ expect(fossil.significance).to eq 1.0
87
+ end
88
+ end
89
+
90
+ describe '#imprint?' do
91
+ it 'returns true when preservation < 0.2' do
92
+ fossil.instance_variable_set(:@preservation, 0.1)
93
+ expect(fossil.imprint?).to be true
94
+ end
95
+
96
+ it 'returns false otherwise' do
97
+ expect(fossil.imprint?).to be false
98
+ end
99
+ end
100
+
101
+ describe '#keystone?' do
102
+ it 'returns true when significance >= 0.8' do
103
+ fossil.instance_variable_set(:@significance, 0.9)
104
+ expect(fossil.keystone?).to be true
105
+ end
106
+
107
+ it 'returns false otherwise' do
108
+ expect(fossil.keystone?).to be false
109
+ end
110
+ end
111
+
112
+ describe '#link_lineage' do
113
+ it 'adds ancestor' do
114
+ fossil.link_lineage('ancestor-id')
115
+ expect(fossil.lineage_ids).to include('ancestor-id')
116
+ end
117
+
118
+ it 'does not duplicate' do
119
+ fossil.link_lineage('same')
120
+ fossil.link_lineage('same')
121
+ expect(fossil.lineage_ids.count('same')).to eq 1
122
+ end
123
+ end
124
+
125
+ describe '#to_h' do
126
+ it 'includes all fields' do
127
+ %i[id fossil_type domain content extinction_cause era stratum_depth
128
+ preservation significance discovered_at extinct_at lineage_ids
129
+ imprint keystone ancient].each do |key|
130
+ expect(fossil.to_h).to have_key(key)
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Helpers::PaleontologyEngine do
4
+ let(:engine) { described_class.new }
5
+ let(:fossil_args) do
6
+ { fossil_type: :strategy, domain: :cognitive, content: 'old way',
7
+ extinction_cause: :obsolescence }
8
+ end
9
+
10
+ describe '#record_extinction' do
11
+ it 'creates a fossil' do
12
+ f = engine.record_extinction(**fossil_args)
13
+ expect(f.fossil_type).to eq :strategy
14
+ end
15
+
16
+ it 'tracks fossil in all_fossils' do
17
+ engine.record_extinction(**fossil_args)
18
+ expect(engine.all_fossils.size).to eq 1
19
+ end
20
+
21
+ it 'raises on invalid type' do
22
+ expect do
23
+ engine.record_extinction(fossil_type: :bogus, domain: :x,
24
+ content: 'x', extinction_cause: :obsolescence)
25
+ end.to raise_error(ArgumentError)
26
+ end
27
+ end
28
+
29
+ describe '#begin_excavation' do
30
+ it 'creates an excavation' do
31
+ exc = engine.begin_excavation(target_stratum: 1)
32
+ expect(exc.target_stratum).to eq 1
33
+ end
34
+
35
+ it 'tracks in all_excavations' do
36
+ engine.begin_excavation(target_stratum: 0)
37
+ expect(engine.all_excavations.size).to eq 1
38
+ end
39
+ end
40
+
41
+ describe '#excavate!' do
42
+ it 'returns fossil from matching stratum' do
43
+ engine.record_extinction(**fossil_args, stratum_depth: 1)
44
+ exc = engine.begin_excavation(target_stratum: 1)
45
+ result = engine.excavate!(excavation_id: exc.id)
46
+ expect(result).to be_a(
47
+ Legion::Extensions::Agentic::Memory::Paleontology::Helpers::Fossil
48
+ )
49
+ end
50
+
51
+ it 'returns nil when no fossils at stratum' do
52
+ exc = engine.begin_excavation(target_stratum: 3)
53
+ expect(engine.excavate!(excavation_id: exc.id)).to be_nil
54
+ end
55
+
56
+ it 'raises when excavation is completed' do
57
+ exc = engine.begin_excavation(target_stratum: 0)
58
+ exc.complete!
59
+ expect do
60
+ engine.excavate!(excavation_id: exc.id)
61
+ end.to raise_error(ArgumentError, /already completed/)
62
+ end
63
+ end
64
+
65
+ describe '#complete_excavation' do
66
+ it 'completes the excavation' do
67
+ exc = engine.begin_excavation(target_stratum: 0)
68
+ result = engine.complete_excavation(excavation_id: exc.id)
69
+ expect(result).to be_completed
70
+ end
71
+ end
72
+
73
+ describe '#erode_all!' do
74
+ it 'reduces preservation' do
75
+ f = engine.record_extinction(**fossil_args)
76
+ original = f.preservation
77
+ engine.erode_all!
78
+ expect(f.preservation).to be < original
79
+ end
80
+
81
+ it 'prunes fossils at 0.0' do
82
+ f = engine.record_extinction(**fossil_args)
83
+ f.instance_variable_set(:@preservation, 0.01)
84
+ engine.erode_all!(rate: 0.5)
85
+ expect(engine.all_fossils).not_to include(f)
86
+ end
87
+ end
88
+
89
+ describe '#link_lineage' do
90
+ it 'links two fossils' do
91
+ f1 = engine.record_extinction(**fossil_args, content: 'child')
92
+ f2 = engine.record_extinction(**fossil_args, content: 'parent')
93
+ engine.link_lineage(fossil_id: f1.id, ancestor_id: f2.id)
94
+ expect(f1.lineage_ids).to include(f2.id)
95
+ end
96
+ end
97
+
98
+ describe '#fossils_by_type' do
99
+ it 'filters correctly' do
100
+ engine.record_extinction(**fossil_args)
101
+ expect(engine.fossils_by_type(:strategy).size).to eq 1
102
+ expect(engine.fossils_by_type(:pattern)).to be_empty
103
+ end
104
+ end
105
+
106
+ describe '#fossils_by_cause' do
107
+ it 'filters correctly' do
108
+ engine.record_extinction(**fossil_args)
109
+ expect(engine.fossils_by_cause(:obsolescence).size).to eq 1
110
+ end
111
+ end
112
+
113
+ describe '#keystone_fossils' do
114
+ it 'returns only keystones' do
115
+ f = engine.record_extinction(**fossil_args, significance: 0.9)
116
+ expect(engine.keystone_fossils).to include(f)
117
+ end
118
+ end
119
+
120
+ describe '#mass_extinction?' do
121
+ it 'returns false normally' do
122
+ expect(engine.mass_extinction?).to be false
123
+ end
124
+
125
+ it 'returns true after many rapid extinctions' do
126
+ 6.times do
127
+ engine.record_extinction(**fossil_args, content: SecureRandom.hex(4))
128
+ end
129
+ expect(engine.mass_extinction?(threshold: 5)).to be true
130
+ end
131
+ end
132
+
133
+ describe '#paleontology_report' do
134
+ it 'returns comprehensive report' do
135
+ engine.record_extinction(**fossil_args)
136
+ report = engine.paleontology_report
137
+ %i[total_fossils total_excavations type_breakdown cause_breakdown
138
+ era_breakdown avg_preservation avg_significance keystone_count
139
+ imprint_count ancient_count mass_extinction].each do |key|
140
+ expect(report).to have_key(key)
141
+ end
142
+ end
143
+
144
+ it 'works empty' do
145
+ expect(engine.paleontology_report[:total_fossils]).to eq 0
146
+ end
147
+ end
148
+ end