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,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Paleontology::Runners::CognitivePaleontology do
4
+ let(:engine) { Legion::Extensions::Agentic::Memory::Paleontology::Helpers::PaleontologyEngine.new }
5
+ let(:runner) { described_class }
6
+
7
+ describe '.record_extinction' do
8
+ it 'succeeds' do
9
+ result = runner.record_extinction(
10
+ fossil_type: :strategy, domain: :cognitive, content: 'old way',
11
+ extinction_cause: :obsolescence, engine: engine
12
+ )
13
+ expect(result[:success]).to be true
14
+ expect(result[:fossil][:fossil_type]).to eq :strategy
15
+ end
16
+
17
+ it 'returns failure for invalid type' do
18
+ result = runner.record_extinction(
19
+ fossil_type: :bogus, domain: :cognitive, content: 'x',
20
+ extinction_cause: :obsolescence, engine: engine
21
+ )
22
+ expect(result[:success]).to be false
23
+ end
24
+ end
25
+
26
+ describe '.begin_excavation' do
27
+ it 'succeeds' do
28
+ result = runner.begin_excavation(target_stratum: 1, engine: engine)
29
+ expect(result[:success]).to be true
30
+ expect(result[:excavation][:target_stratum]).to eq 1
31
+ end
32
+ end
33
+
34
+ describe '.excavate' do
35
+ it 'returns fossil when found' do
36
+ engine.record_extinction(
37
+ fossil_type: :pattern, domain: :semantic, content: 'x',
38
+ extinction_cause: :displacement, stratum_depth: 1
39
+ )
40
+ exc = engine.begin_excavation(target_stratum: 1)
41
+ result = runner.excavate(excavation_id: exc.id, engine: engine)
42
+ expect(result[:success]).to be true
43
+ end
44
+
45
+ it 'returns nil message when empty stratum' do
46
+ exc = engine.begin_excavation(target_stratum: 4)
47
+ result = runner.excavate(excavation_id: exc.id, engine: engine)
48
+ expect(result[:success]).to be true
49
+ expect(result[:fossil]).to be_nil
50
+ end
51
+ end
52
+
53
+ describe '.list_fossils' do
54
+ before do
55
+ engine.record_extinction(
56
+ fossil_type: :strategy, domain: :cognitive, content: 'a',
57
+ extinction_cause: :obsolescence
58
+ )
59
+ engine.record_extinction(
60
+ fossil_type: :pattern, domain: :semantic, content: 'b',
61
+ extinction_cause: :displacement
62
+ )
63
+ end
64
+
65
+ it 'lists all' do
66
+ result = runner.list_fossils(engine: engine)
67
+ expect(result[:count]).to eq 2
68
+ end
69
+
70
+ it 'filters by type' do
71
+ result = runner.list_fossils(engine: engine, fossil_type: :strategy)
72
+ expect(result[:count]).to eq 1
73
+ end
74
+
75
+ it 'filters by cause' do
76
+ result = runner.list_fossils(engine: engine,
77
+ extinction_cause: :displacement)
78
+ expect(result[:count]).to eq 1
79
+ end
80
+ end
81
+
82
+ describe '.paleontology_status' do
83
+ it 'returns report' do
84
+ result = runner.paleontology_status(engine: engine)
85
+ expect(result[:success]).to be true
86
+ expect(result[:report]).to be_a Hash
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Palimpsest::Client do
4
+ subject(:client) { described_class.new }
5
+
6
+ it 'full lifecycle: overwrite, peek, ghost, drift, report' do
7
+ r1 = client.overwrite_belief(topic: 'democracy', content: 'mob rule', confidence: 0.4)
8
+ expect(r1[:success]).to be true
9
+
10
+ r2 = client.overwrite_belief(topic: 'democracy', content: 'representative government', confidence: 0.9)
11
+ expect(r2[:version]).to eq(2)
12
+
13
+ peek = client.peek_through_belief(topic: 'democracy', depth: 1)
14
+ expect(peek[:count]).to eq(1)
15
+ expect(peek[:layers].first[:content]).to eq('mob rule')
16
+
17
+ ghosts = client.ghost_layers(topic: 'democracy')
18
+ expect(ghosts[:count]).to eq(1)
19
+
20
+ drift = client.belief_drift(topic: 'democracy')
21
+ expect(drift[:drift]).to be_within(0.01).of(0.5)
22
+
23
+ report = client.palimpsest_report
24
+ expect(report[:palimpsest_count]).to eq(1)
25
+ expect(report[:total_ghosts]).to eq(1)
26
+ end
27
+
28
+ it 'accepts injected engine' do
29
+ engine = Legion::Extensions::Agentic::Memory::Palimpsest::Helpers::PalimpsestEngine.new
30
+ c = described_class.new(engine: engine)
31
+ c.overwrite_belief(topic: 'test', content: 'hello')
32
+ expect(engine.palimpsests).to have_key('test')
33
+ end
34
+
35
+ it 'erodes and decays' do
36
+ client.overwrite_belief(topic: 'erosion', content: 'v1', confidence: 0.8)
37
+ result = client.erode_belief(topic: 'erosion')
38
+ expect(result[:confidence]).to be < 0.8
39
+
40
+ client.overwrite_belief(topic: 'erosion', content: 'v2', confidence: 0.8)
41
+ decay_result = client.decay_all_ghosts
42
+ expect(decay_result[:success]).to be true
43
+ end
44
+
45
+ it 'domain_archaeology retrieves all layers for domain' do
46
+ client.create_palimpsest(topic: 'arch_topic', domain: :normative)
47
+ client.overwrite_belief(topic: 'arch_topic', content: 'old norm')
48
+ client.overwrite_belief(topic: 'arch_topic', content: 'new norm')
49
+ result = client.domain_archaeology(domain: :normative)
50
+ expect(result[:count]).to eq(2)
51
+ end
52
+
53
+ it 'most_rewritten respects limit' do
54
+ 5.times { |i| client.overwrite_belief(topic: "topic_#{i}", content: 'x') }
55
+ result = client.most_rewritten(limit: 3)
56
+ expect(result[:palimpsests].size).to eq(3)
57
+ end
58
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Palimpsest::Helpers::BeliefLayer do
4
+ subject(:layer) do
5
+ described_class.new(content: 'the sky is blue', confidence: 0.8, domain: :factual)
6
+ end
7
+
8
+ describe '#initialize' do
9
+ it 'sets content' do
10
+ expect(layer.content).to eq('the sky is blue')
11
+ end
12
+
13
+ it 'sets confidence' do
14
+ expect(layer.confidence).to eq(0.8)
15
+ end
16
+
17
+ it 'sets domain' do
18
+ expect(layer.domain).to eq(:factual)
19
+ end
20
+
21
+ it 'generates a uuid id' do
22
+ expect(layer.id).to match(/\A[0-9a-f-]{36}\z/)
23
+ end
24
+
25
+ it 'sets timestamp' do
26
+ expect(layer.timestamp).to be_a(Time)
27
+ end
28
+
29
+ it 'is not superseded by default' do
30
+ expect(layer.superseded_by).to be_nil
31
+ expect(layer.superseded?).to be false
32
+ end
33
+
34
+ it 'clamps confidence above 1.0' do
35
+ l = described_class.new(content: 'x', confidence: 1.5)
36
+ expect(l.confidence).to eq(1.0)
37
+ end
38
+
39
+ it 'clamps confidence below 0.0' do
40
+ l = described_class.new(content: 'x', confidence: -0.5)
41
+ expect(l.confidence).to eq(0.0)
42
+ end
43
+
44
+ it 'defaults version to 1' do
45
+ l = described_class.new(content: 'x')
46
+ expect(l.version).to eq(1)
47
+ end
48
+
49
+ it 'defaults author to :system' do
50
+ l = described_class.new(content: 'x')
51
+ expect(l.author).to eq(:system)
52
+ end
53
+ end
54
+
55
+ describe '#supersede!' do
56
+ it 'sets superseded_by' do
57
+ layer.supersede!('next-id')
58
+ expect(layer.superseded_by).to eq('next-id')
59
+ expect(layer.superseded?).to be true
60
+ end
61
+ end
62
+
63
+ describe '#ghost?' do
64
+ context 'when superseded with confidence above threshold' do
65
+ it 'is a ghost' do
66
+ layer.supersede!('x')
67
+ expect(layer.ghost?).to be true
68
+ end
69
+ end
70
+
71
+ context 'when not superseded' do
72
+ it 'is not a ghost' do
73
+ expect(layer.ghost?).to be false
74
+ end
75
+ end
76
+
77
+ context 'when superseded with confidence at or below threshold' do
78
+ it 'is not a ghost' do
79
+ low = described_class.new(content: 'x', confidence: 0.05)
80
+ low.supersede!('x')
81
+ expect(low.ghost?).to be false
82
+ end
83
+ end
84
+ end
85
+
86
+ describe '#dissipated?' do
87
+ it 'is dissipated when superseded and confidence at or below threshold' do
88
+ low = described_class.new(content: 'x', confidence: 0.05)
89
+ low.supersede!('x')
90
+ expect(low.dissipated?).to be true
91
+ end
92
+
93
+ it 'is not dissipated when not superseded' do
94
+ expect(layer.dissipated?).to be false
95
+ end
96
+ end
97
+
98
+ describe '#erode!' do
99
+ it 'reduces confidence by EROSION_RATE' do
100
+ original = layer.confidence
101
+ layer.erode!
102
+ expect(layer.confidence).to be < original
103
+ end
104
+
105
+ it 'does not go below 0.0' do
106
+ low = described_class.new(content: 'x', confidence: 0.02)
107
+ low.erode!(rate: 0.1)
108
+ expect(low.confidence).to eq(0.0)
109
+ end
110
+
111
+ it 'accepts a custom rate' do
112
+ layer.erode!(rate: 0.1)
113
+ expect(layer.confidence).to be_within(0.001).of(0.7)
114
+ end
115
+ end
116
+
117
+ describe '#confidence_label' do
118
+ it 'returns :high for 0.8' do
119
+ expect(layer.confidence_label).to eq(:high)
120
+ end
121
+
122
+ it 'returns :ghost for very low confidence' do
123
+ l = described_class.new(content: 'x', confidence: 0.05)
124
+ expect(l.confidence_label).to eq(:ghost)
125
+ end
126
+ end
127
+
128
+ describe '#ghost_label' do
129
+ it 'returns :not_ghost when not superseded' do
130
+ expect(layer.ghost_label).to eq(:not_ghost)
131
+ end
132
+
133
+ it 'returns :strong_ghost when superseded with high confidence' do
134
+ layer.supersede!('x')
135
+ expect(layer.ghost_label).to eq(:strong_ghost)
136
+ end
137
+ end
138
+
139
+ describe '#to_h' do
140
+ it 'returns expected keys' do
141
+ h = layer.to_h
142
+ expect(h).to include(:id, :content, :confidence, :domain, :version, :author,
143
+ :timestamp, :superseded_by, :superseded, :ghost, :label)
144
+ end
145
+
146
+ it 'rounds confidence to 4 decimal places' do
147
+ expect(layer.to_h[:confidence]).to eq(0.8)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Palimpsest::Helpers::Constants do
4
+ describe 'constants' do
5
+ it 'defines MAX_PALIMPSESTS' do
6
+ expect(described_class::MAX_PALIMPSESTS).to eq(200)
7
+ end
8
+
9
+ it 'defines MAX_LAYERS_PER_TOPIC' do
10
+ expect(described_class::MAX_LAYERS_PER_TOPIC).to eq(20)
11
+ end
12
+
13
+ it 'defines DEFAULT_CONFIDENCE' do
14
+ expect(described_class::DEFAULT_CONFIDENCE).to eq(0.7)
15
+ end
16
+
17
+ it 'defines GHOST_THRESHOLD' do
18
+ expect(described_class::GHOST_THRESHOLD).to eq(0.1)
19
+ end
20
+
21
+ it 'defines EROSION_RATE' do
22
+ expect(described_class::EROSION_RATE).to eq(0.05)
23
+ end
24
+
25
+ it 'defines GHOST_DECAY' do
26
+ expect(described_class::GHOST_DECAY).to eq(0.02)
27
+ end
28
+
29
+ it 'defines 8 LAYER_DOMAINS' do
30
+ expect(described_class::LAYER_DOMAINS.size).to eq(8)
31
+ end
32
+
33
+ it 'includes expected domains' do
34
+ expect(described_class::LAYER_DOMAINS).to include(:factual, :procedural, :normative, :identity)
35
+ end
36
+ end
37
+
38
+ describe '.label_for' do
39
+ it 'returns correct CONFIDENCE_LABELS label' do
40
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.95)).to eq(:certain)
41
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.75)).to eq(:high)
42
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.55)).to eq(:moderate)
43
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.35)).to eq(:low)
44
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.15)).to eq(:faint)
45
+ expect(described_class.label_for(described_class::CONFIDENCE_LABELS, 0.05)).to eq(:ghost)
46
+ end
47
+
48
+ it 'returns correct GHOST_LABELS label' do
49
+ expect(described_class.label_for(described_class::GHOST_LABELS, 0.6)).to eq(:strong_ghost)
50
+ expect(described_class.label_for(described_class::GHOST_LABELS, 0.4)).to eq(:moderate_ghost)
51
+ expect(described_class.label_for(described_class::GHOST_LABELS, 0.2)).to eq(:faint_ghost)
52
+ expect(described_class.label_for(described_class::GHOST_LABELS, 0.05)).to eq(:dissipated)
53
+ end
54
+
55
+ it 'returns correct DRIFT_LABELS label' do
56
+ expect(described_class.label_for(described_class::DRIFT_LABELS, 0.8)).to eq(:radical)
57
+ expect(described_class.label_for(described_class::DRIFT_LABELS, 0.5)).to eq(:major)
58
+ expect(described_class.label_for(described_class::DRIFT_LABELS, 0.3)).to eq(:moderate)
59
+ expect(described_class.label_for(described_class::DRIFT_LABELS, 0.1)).to eq(:minor)
60
+ expect(described_class.label_for(described_class::DRIFT_LABELS, 0.01)).to eq(:stable)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Palimpsest::Helpers::PalimpsestEngine do
4
+ subject(:engine) { described_class.new }
5
+
6
+ describe '#create' do
7
+ it 'creates a new palimpsest' do
8
+ p = engine.create(topic: 'gravity', domain: :factual)
9
+ expect(p).not_to be_nil
10
+ expect(p.topic).to eq('gravity')
11
+ end
12
+
13
+ it 'returns nil for duplicate topic' do
14
+ engine.create(topic: 'gravity')
15
+ expect(engine.create(topic: 'gravity')).to be_nil
16
+ end
17
+
18
+ it 'stores in palimpsests hash' do
19
+ engine.create(topic: 'light')
20
+ expect(engine.palimpsests).to have_key('light')
21
+ end
22
+ end
23
+
24
+ describe '#overwrite' do
25
+ it 'creates and overwrites in one call' do
26
+ layer = engine.overwrite(topic: 'sky', content: 'blue', confidence: 0.8)
27
+ expect(layer).not_to be_nil
28
+ expect(layer.content).to eq('blue')
29
+ end
30
+
31
+ it 'overwrites an existing palimpsest' do
32
+ engine.overwrite(topic: 'sky', content: 'v1', confidence: 0.7)
33
+ engine.overwrite(topic: 'sky', content: 'v2', confidence: 0.9)
34
+ expect(engine.palimpsests['sky'].current_layer.content).to eq('v2')
35
+ end
36
+ end
37
+
38
+ describe '#peek_through' do
39
+ it 'returns previous layers as hashes' do
40
+ engine.overwrite(topic: 'x', content: 'old')
41
+ engine.overwrite(topic: 'x', content: 'new')
42
+ layers = engine.peek_through(topic: 'x', depth: 1)
43
+ expect(layers.first[:content]).to eq('old')
44
+ end
45
+
46
+ it 'returns empty for unknown topic' do
47
+ expect(engine.peek_through(topic: 'unknown')).to eq([])
48
+ end
49
+ end
50
+
51
+ describe '#erode' do
52
+ it 'reduces confidence' do
53
+ engine.overwrite(topic: 'y', content: 'content', confidence: 0.8)
54
+ result = engine.erode(topic: 'y')
55
+ expect(result).to be < 0.8
56
+ end
57
+
58
+ it 'returns nil for unknown topic' do
59
+ expect(engine.erode(topic: 'missing')).to be_nil
60
+ end
61
+ end
62
+
63
+ describe '#ghost_layers_for' do
64
+ it 'returns ghost layers as hashes' do
65
+ engine.overwrite(topic: 'z', content: 'v1', confidence: 0.8)
66
+ engine.overwrite(topic: 'z', content: 'v2')
67
+ layers = engine.ghost_layers_for(topic: 'z')
68
+ expect(layers.size).to eq(1)
69
+ expect(layers.first).to be_a(Hash)
70
+ end
71
+
72
+ it 'returns empty for unknown topic' do
73
+ expect(engine.ghost_layers_for(topic: 'missing')).to eq([])
74
+ end
75
+ end
76
+
77
+ describe '#all_ghost_layers' do
78
+ it 'aggregates ghosts across all palimpsests' do
79
+ engine.overwrite(topic: 'a', content: 'v1', confidence: 0.8)
80
+ engine.overwrite(topic: 'a', content: 'v2')
81
+ engine.overwrite(topic: 'b', content: 'v1', confidence: 0.7)
82
+ engine.overwrite(topic: 'b', content: 'v2')
83
+ expect(engine.all_ghost_layers.size).to eq(2)
84
+ end
85
+ end
86
+
87
+ describe '#domain_archaeology' do
88
+ it 'returns all layers for a given domain' do
89
+ engine.create(topic: 'a', domain: :factual)
90
+ engine.overwrite(topic: 'a', content: 'v1')
91
+ engine.overwrite(topic: 'a', content: 'v2')
92
+ engine.create(topic: 'b', domain: :emotional)
93
+ engine.overwrite(topic: 'b', content: 'feeling')
94
+ layers = engine.domain_archaeology(domain: :factual)
95
+ expect(layers.size).to eq(2)
96
+ expect(layers.all? { |l| l[:topic] == 'a' }).to be true
97
+ end
98
+ end
99
+
100
+ describe '#belief_drift' do
101
+ it 'returns drift hash' do
102
+ engine.overwrite(topic: 'drift', content: 'v1', confidence: 0.3)
103
+ engine.overwrite(topic: 'drift', content: 'v2', confidence: 0.9)
104
+ result = engine.belief_drift(topic: 'drift')
105
+ expect(result[:drift]).to be > 0
106
+ expect(result[:label]).to be_a(Symbol)
107
+ end
108
+
109
+ it 'returns nil for unknown topic' do
110
+ expect(engine.belief_drift(topic: 'unknown')).to be_nil
111
+ end
112
+ end
113
+
114
+ describe '#overwrite_frequency' do
115
+ it 'returns count of overwrites' do
116
+ engine.overwrite(topic: 'freq', content: 'v1')
117
+ engine.overwrite(topic: 'freq', content: 'v2')
118
+ engine.overwrite(topic: 'freq', content: 'v3')
119
+ expect(engine.overwrite_frequency(topic: 'freq')).to eq(3)
120
+ end
121
+
122
+ it 'returns nil for unknown topic' do
123
+ expect(engine.overwrite_frequency(topic: 'missing')).to be_nil
124
+ end
125
+ end
126
+
127
+ describe '#most_rewritten' do
128
+ it 'returns palimpsests sorted by overwrite count descending' do
129
+ 3.times { engine.overwrite(topic: 'many', content: "v#{it}") }
130
+ engine.overwrite(topic: 'few', content: 'v1')
131
+ result = engine.most_rewritten(limit: 2)
132
+ expect(result.first[:topic]).to eq('many')
133
+ end
134
+
135
+ it 'respects limit' do
136
+ 5.times { |i| engine.overwrite(topic: "t#{i}", content: 'x') }
137
+ expect(engine.most_rewritten(limit: 3).size).to eq(3)
138
+ end
139
+ end
140
+
141
+ describe '#decay_all!' do
142
+ it 'decays ghost layers without raising' do
143
+ engine.overwrite(topic: 'g', content: 'v1', confidence: 0.8)
144
+ engine.overwrite(topic: 'g', content: 'v2')
145
+ old_conf = engine.palimpsests['g'].historical_layers.first.confidence
146
+ engine.decay_all!
147
+ expect(engine.palimpsests['g'].historical_layers.first.confidence).to be < old_conf
148
+ end
149
+ end
150
+
151
+ describe '#palimpsest_report' do
152
+ it 'returns report hash' do
153
+ engine.overwrite(topic: 'r1', content: 'v1', confidence: 0.8)
154
+ engine.overwrite(topic: 'r1', content: 'v2')
155
+ report = engine.palimpsest_report
156
+ expect(report).to include(:palimpsest_count, :total_ghosts, :average_drift, :most_rewritten)
157
+ expect(report[:palimpsest_count]).to eq(1)
158
+ end
159
+
160
+ it 'returns zero average_drift for empty engine' do
161
+ expect(engine.palimpsest_report[:average_drift]).to eq(0.0)
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,172 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Legion::Extensions::Agentic::Memory::Palimpsest::Helpers::Palimpsest do
4
+ subject(:pal) { described_class.new(topic: 'weather', domain: :factual) }
5
+
6
+ describe '#initialize' do
7
+ it 'sets topic and domain' do
8
+ expect(pal.topic).to eq('weather')
9
+ expect(pal.domain).to eq(:factual)
10
+ end
11
+
12
+ it 'starts with no layers' do
13
+ expect(pal.current_layer).to be_nil
14
+ expect(pal.historical_layers).to be_empty
15
+ end
16
+
17
+ it 'starts with overwrite_count of 0' do
18
+ expect(pal.overwrite_count).to eq(0)
19
+ end
20
+
21
+ it 'generates an id' do
22
+ expect(pal.id).to match(/\A[0-9a-f-]{36}\z/)
23
+ end
24
+ end
25
+
26
+ describe '#overwrite!' do
27
+ it 'sets the current layer on first call' do
28
+ layer = pal.overwrite!('it will rain', confidence: 0.7)
29
+ expect(pal.current_layer).to eq(layer)
30
+ expect(pal.current_layer.content).to eq('it will rain')
31
+ end
32
+
33
+ it 'increments overwrite_count' do
34
+ pal.overwrite!('v1')
35
+ pal.overwrite!('v2')
36
+ expect(pal.overwrite_count).to eq(2)
37
+ end
38
+
39
+ it 'moves current to historical on second write' do
40
+ pal.overwrite!('v1')
41
+ pal.overwrite!('v2')
42
+ expect(pal.historical_layers.size).to eq(1)
43
+ expect(pal.historical_layers.first.content).to eq('v1')
44
+ end
45
+
46
+ it 'marks the old layer as superseded' do
47
+ pal.overwrite!('v1')
48
+ v1 = pal.current_layer
49
+ pal.overwrite!('v2')
50
+ expect(v1.superseded?).to be true
51
+ end
52
+
53
+ it 'increments layer version' do
54
+ pal.overwrite!('v1')
55
+ pal.overwrite!('v2')
56
+ expect(pal.current_layer.version).to eq(2)
57
+ end
58
+ end
59
+
60
+ describe '#peek_through' do
61
+ before do
62
+ pal.overwrite!('v1')
63
+ pal.overwrite!('v2')
64
+ pal.overwrite!('v3')
65
+ end
66
+
67
+ it 'returns the most recent historical layer by default' do
68
+ layers = pal.peek_through(depth: 1)
69
+ expect(layers.size).to eq(1)
70
+ expect(layers.first.content).to eq('v2')
71
+ end
72
+
73
+ it 'returns multiple historical layers' do
74
+ layers = pal.peek_through(depth: 2)
75
+ expect(layers.size).to eq(2)
76
+ end
77
+
78
+ it 'returns empty when no history' do
79
+ fresh = described_class.new(topic: 'new')
80
+ expect(fresh.peek_through).to be_empty
81
+ end
82
+
83
+ it 'does not exceed available history' do
84
+ layers = pal.peek_through(depth: 100)
85
+ expect(layers.size).to eq(2)
86
+ end
87
+ end
88
+
89
+ describe '#erode_current!' do
90
+ it 'reduces confidence of current layer' do
91
+ pal.overwrite!('content', confidence: 0.8)
92
+ original = pal.current_layer.confidence
93
+ pal.erode_current!
94
+ expect(pal.current_layer.confidence).to be < original
95
+ end
96
+
97
+ it 'returns nil when no current layer' do
98
+ expect(pal.erode_current!).to be_nil
99
+ end
100
+ end
101
+
102
+ describe '#ghost_layers' do
103
+ it 'returns superseded layers with confidence above threshold' do
104
+ pal.overwrite!('v1', confidence: 0.8)
105
+ pal.overwrite!('v2')
106
+ expect(pal.ghost_layers.size).to eq(1)
107
+ end
108
+
109
+ it 'excludes dissipated layers' do
110
+ pal.overwrite!('v1', confidence: 0.05)
111
+ pal.overwrite!('v2')
112
+ expect(pal.ghost_layers).to be_empty
113
+ end
114
+ end
115
+
116
+ describe '#restoration_strength' do
117
+ it 'returns 0.0 with no ghosts' do
118
+ pal.overwrite!('v1')
119
+ expect(pal.restoration_strength).to eq(0.0)
120
+ end
121
+
122
+ it 'returns average ghost confidence' do
123
+ pal.overwrite!('v1', confidence: 0.8)
124
+ pal.overwrite!('v2', confidence: 0.6)
125
+ pal.overwrite!('v3')
126
+ strength = pal.restoration_strength
127
+ expect(strength).to be > 0.0
128
+ end
129
+ end
130
+
131
+ describe '#belief_drift' do
132
+ it 'returns 0.0 with no history' do
133
+ pal.overwrite!('v1', confidence: 0.7)
134
+ expect(pal.belief_drift).to eq(0.0)
135
+ end
136
+
137
+ it 'measures distance from origin to current' do
138
+ pal.overwrite!('v1', confidence: 0.3)
139
+ pal.overwrite!('v2', confidence: 0.8)
140
+ expect(pal.belief_drift).to be_within(0.01).of(0.5)
141
+ end
142
+ end
143
+
144
+ describe '#drift_label' do
145
+ it 'returns a symbol' do
146
+ pal.overwrite!('v1', confidence: 0.3)
147
+ pal.overwrite!('v2', confidence: 0.9)
148
+ expect(pal.drift_label).to be_a(Symbol)
149
+ end
150
+ end
151
+
152
+ describe '#decay_ghosts!' do
153
+ it 'erodes all historical layers' do
154
+ pal.overwrite!('v1', confidence: 0.8)
155
+ pal.overwrite!('v2')
156
+ old_conf = pal.historical_layers.first.confidence
157
+ pal.decay_ghosts!
158
+ expect(pal.historical_layers.first.confidence).to be < old_conf
159
+ end
160
+ end
161
+
162
+ describe '#to_h' do
163
+ before { pal.overwrite!('v1') }
164
+
165
+ it 'returns expected keys' do
166
+ h = pal.to_h
167
+ expect(h).to include(:id, :topic, :domain, :layer_count, :overwrite_count,
168
+ :ghost_count, :restoration_strength, :belief_drift,
169
+ :drift_label, :current_layer, :created_at)
170
+ end
171
+ end
172
+ end