AbstractMemory 0.3.1__tar.gz → 0.4.0__tar.gz

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 (259) hide show
  1. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/CHANGELOG.md +163 -2
  2. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/PKG-INFO +20 -3
  3. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/README.md +13 -2
  4. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/README.md +1 -0
  5. abstractmemory-0.4.0/docs/adr/0001-altered-memories-ripple.md +147 -0
  6. abstractmemory-0.4.0/docs/adr/0002-abstractmemory-owns-the-memory-graph.md +92 -0
  7. abstractmemory-0.4.0/docs/adr/0003-one-graph-ledger-provenance-and-revisions.md +261 -0
  8. abstractmemory-0.4.0/docs/adr/README.md +10 -0
  9. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/api.md +125 -5
  10. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/architecture.md +7 -2
  11. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/overview.md +36 -5
  12. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0050_entity_registry_identity_and_reversible_merges.md +42 -0
  13. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0051_claim_lifecycle_and_revision_log.md +39 -0
  14. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0052_document_knowledge_retrieval.md +37 -0
  15. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0053_self_organisation_communities_consolidation_reflection.md +38 -0
  16. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0054_ripple_propagation_and_activation.md +41 -0
  17. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0055_notes_and_diary_layer_for_consumers.md +36 -0
  18. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0056_ledger_provenance_contract_and_revision_log.md +175 -0
  19. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0057_one_mind_per_plane_sqlite_home.md +69 -0
  20. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0058_home_store_performance_indexes_vectors.md +148 -0
  21. abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/README.md +87 -0
  22. abstractmemory-0.4.0/docs/backlog/proposed/ripple_wave/0001_change_records_and_ripple_primitives.md +31 -0
  23. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/faq.md +2 -2
  24. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/getting-started.md +35 -0
  25. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/memory-system.md +26 -0
  26. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/stores.md +42 -5
  27. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/troubleshooting.md +23 -1
  28. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/llms-full.txt +273 -17
  29. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/llms.txt +2 -1
  30. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/pyproject.toml +11 -1
  31. abstractmemory-0.4.0/release-notes.md +146 -0
  32. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/__init__.py +16 -0
  33. abstractmemory-0.4.0/src/abstractmemory/graph/__init__.py +60 -0
  34. abstractmemory-0.4.0/src/abstractmemory/graph/backend.py +117 -0
  35. abstractmemory-0.4.0/src/abstractmemory/graph/graph.py +1363 -0
  36. abstractmemory-0.4.0/src/abstractmemory/graph/lancedb_backend.py +580 -0
  37. abstractmemory-0.4.0/src/abstractmemory/graph/provenance.py +323 -0
  38. abstractmemory-0.4.0/src/abstractmemory/graph/revisions.py +239 -0
  39. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/in_memory_store.py +84 -21
  40. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/journal.py +15 -4
  41. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/journal_sqlite.py +46 -20
  42. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/journal_sqlite_rows.py +4 -1
  43. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/lancedb_store.py +5 -0
  44. abstractmemory-0.4.0/src/abstractmemory/sleep_cadence.py +290 -0
  45. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/sqlite_store.py +493 -56
  46. abstractmemory-0.4.0/src/abstractmemory/store_tuning.py +71 -0
  47. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/system.py +2 -1
  48. abstractmemory-0.4.0/src/abstractmemory/vector_matrix.py +434 -0
  49. abstractmemory-0.4.0/tests/bench/bench_graph.py +210 -0
  50. abstractmemory-0.4.0/tests/bench/bench_store.py +329 -0
  51. abstractmemory-0.4.0/tests/graph_support.py +203 -0
  52. abstractmemory-0.4.0/tests/test_cadence_cursor.py +296 -0
  53. abstractmemory-0.4.0/tests/test_graph_conformance.py +354 -0
  54. abstractmemory-0.4.0/tests/test_graph_e2e.py +197 -0
  55. abstractmemory-0.4.0/tests/test_graph_performance.py +193 -0
  56. abstractmemory-0.4.0/tests/test_graph_provenance.py +502 -0
  57. abstractmemory-0.4.0/tests/test_graph_revisions.py +620 -0
  58. abstractmemory-0.4.0/tests/test_home_open_is_a_read.py +91 -0
  59. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_journal_backends.py +15 -0
  60. abstractmemory-0.4.0/tests/test_narrow_assertion.py +142 -0
  61. abstractmemory-0.4.0/tests/test_store_performance.py +179 -0
  62. abstractmemory-0.4.0/tests/test_vector_encoding_marker.py +51 -0
  63. abstractmemory-0.4.0/tests/test_vector_matrix.py +569 -0
  64. abstractmemory-0.4.0/tests/test_vector_matrix_footprint.py +88 -0
  65. abstractmemory-0.3.1/release-notes.md +0 -12
  66. abstractmemory-0.3.1/src/abstractmemory/sleep_cadence.py +0 -74
  67. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  68. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/.github/workflows/ci.yml +0 -0
  69. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/.github/workflows/release.yml +0 -0
  70. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/.gitignore +0 -0
  71. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/ACKNOWLEDGMENTS.md +0 -0
  72. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/CODE_OF_CONDUCT.md +0 -0
  73. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/CONTRIBUTING.md +0 -0
  74. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/LICENSE +0 -0
  75. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/SECURITY.md +0 -0
  76. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/0008_gateway_memory_install_and_config_boundary.md +0 -0
  77. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/002_sqlite_database_compatibility_and_store_capabilities.md +0 -0
  78. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/004_recall_trace_and_access_events_contract.md +0 -0
  79. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/005_source_linked_summaries_and_derived_assertion_lineage.md +0 -0
  80. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/007_read_only_memory_observer_contract.md +0 -0
  81. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0037_familiarity_metamemory_read.md +0 -0
  82. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0038_open_commitments_and_triggers.md +0 -0
  83. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0039_tend_election_grammar.md +0 -0
  84. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0049_stable_shelf_order_for_prefix_reuse.md +0 -0
  85. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0009_assertion_identity_and_batch_read_contract.md +0 -0
  86. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0010_append_only_closure_records_for_retract_and_supersede.md +0 -0
  87. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0011_cross_backend_parity_conformance_suite.md +0 -0
  88. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0013_store_concurrency_and_thread_safety_contract.md +0 -0
  89. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0014_embedding_space_integrity_manifest.md +0 -0
  90. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0017_memory_journal_and_scope_bindings_layer.md +0 -0
  91. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0018_neurotransmitter_attention_strengthen_weaken_decay.md +0 -0
  92. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0019_hybrid_retrieval_channels_fts_vector_exact.md +0 -0
  93. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0020_reconstruction_shelf_and_selection_traces.md +0 -0
  94. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0021_memory_records_and_remember_api.md +0 -0
  95. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0022_probe_and_bounded_source_expansion.md +0 -0
  96. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0023_maintenance_sleep_consolidate_dream.md +0 -0
  97. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0024_memory_system_facade_and_consumer_migration.md +0 -0
  98. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0025_graph_backend_decision_record_memgraph_rejected.md +0 -0
  99. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0026_spreading_activation_and_working_set.md +0 -0
  100. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0027_runtime_seam_contract_v1.md +0 -0
  101. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0029_sleep_reactivity_dreams_as_reaction.md +0 -0
  102. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0030_fork_comparison_adoption_wave.md +0 -0
  103. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0031_second_fork_pass_and_lifecycle_closure.md +0 -0
  104. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0036_third_pass_extension_wave.md +0 -0
  105. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0032_dream_subconscious_lifecycle.md +0 -0
  106. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0033_world_model_orientation_cards.md +0 -0
  107. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0034_situate_temporal_relational_reconstruction.md +0 -0
  108. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0035_lessons_layer_conventions.md +0 -0
  109. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/deprecated/001_semantics_aligned_memory_record_conventions.md +0 -0
  110. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/deprecated/003_bounded_graph_traversal_over_triples.md +0 -0
  111. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/deprecated/006_deterministic_anchor_and_facet_index.md +0 -0
  112. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/planned/extension_wave/README.md +0 -0
  113. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/planned/subconscious_wave/README.md +0 -0
  114. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0040_recurrence_probe_and_presentation_fold.md +0 -0
  115. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0041_loss_absence_anchors.md +0 -0
  116. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0042_explain_recall_serving_contract.md +0 -0
  117. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0043_mind_health_report.md +0 -0
  118. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0044_origin_time_axis_for_imports.md +0 -0
  119. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0045_n_party_memory_contract.md +0 -0
  120. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0046_transcript_adoption_verb.md +0 -0
  121. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0047_cue_hygiene_at_recall_boundary.md +0 -0
  122. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0048_writer_forensics_for_homes.md +0 -0
  123. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/README.md +0 -0
  124. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0012_lancedb_backend_hardening_and_explicit_schema.md +0 -0
  125. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0015_capabilities_extensions_and_deterministic_export_import.md +0 -0
  126. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0016_semantics_vocabulary_validation_and_aliasing_module.md +0 -0
  127. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0028_lateral_inhibition_theory.md +0 -0
  128. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/README.md +0 -0
  129. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/development.md +0 -0
  130. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/docs/operator.md +0 -0
  131. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/examples/entity_home_maintenance_proof.py +0 -0
  132. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/examples/realistic_session.py +0 -0
  133. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/alive_drives.py +0 -0
  134. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/archive_import.py +0 -0
  135. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/attention.py +0 -0
  136. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/candidate_miner.py +0 -0
  137. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/canonical_text.py +0 -0
  138. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/channels.py +0 -0
  139. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/cognition_health.py +0 -0
  140. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/concept_anchor.py +0 -0
  141. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/consolidation.py +0 -0
  142. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/diary.py +0 -0
  143. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/disposal.py +0 -0
  144. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/doctoring.py +0 -0
  145. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/dream_resolution.py +0 -0
  146. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/dream_signals.py +0 -0
  147. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/drive_grouping.py +0 -0
  148. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/drive_pressure.py +0 -0
  149. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/embedding_pin.py +0 -0
  150. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/embeddings.py +0 -0
  151. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/embeddings_openai_compat.py +0 -0
  152. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/engine_manifest.py +0 -0
  153. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/engram.py +0 -0
  154. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/entity_card.py +0 -0
  155. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/feelings_reads.py +0 -0
  156. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/folds.py +0 -0
  157. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/gradation.py +0 -0
  158. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/identity_review.py +0 -0
  159. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/journal_common.py +0 -0
  160. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/journal_memory.py +0 -0
  161. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/maintenance.py +0 -0
  162. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/mind_mass.py +0 -0
  163. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/models.py +0 -0
  164. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/origin_diversity.py +0 -0
  165. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/probe.py +0 -0
  166. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/recall_reads.py +0 -0
  167. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/recent_records.py +0 -0
  168. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/reconstruct.py +0 -0
  169. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/records.py +0 -0
  170. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/redigestion.py +0 -0
  171. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/reembed.py +0 -0
  172. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/render_order.py +0 -0
  173. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/replay.py +0 -0
  174. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/seam.py +0 -0
  175. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/selection.py +0 -0
  176. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/self_component.py +0 -0
  177. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/shelf.py +0 -0
  178. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/situate.py +0 -0
  179. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/sleep_policy.py +0 -0
  180. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/spark.py +0 -0
  181. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/spreading.py +0 -0
  182. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/store.py +0 -0
  183. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/system_access.py +0 -0
  184. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/system_valence.py +0 -0
  185. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/tend.py +0 -0
  186. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/text_tokens.py +0 -0
  187. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/vector_scoring.py +0 -0
  188. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/world_model.py +0 -0
  189. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/src/abstractmemory/world_model_alias.py +0 -0
  190. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/conftest.py +0 -0
  191. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/golden/pre_identity_wave_result.json +0 -0
  192. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/realistic_fixtures.py +0 -0
  193. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_access_counts.py +0 -0
  194. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_alive_drives.py +0 -0
  195. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_anchored_summon.py +0 -0
  196. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_archive_import.py +0 -0
  197. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_attention.py +0 -0
  198. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_audit_wave.py +0 -0
  199. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_binding_visibility.py +0 -0
  200. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_candidate_miner.py +0 -0
  201. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_clean_owner_keys.py +0 -0
  202. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_close_assertion.py +0 -0
  203. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_co_use_trails.py +0 -0
  204. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_cognition_health.py +0 -0
  205. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_commitments.py +0 -0
  206. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_consolidation.py +0 -0
  207. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_disposal.py +0 -0
  208. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_doctoring.py +0 -0
  209. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_dream_resolution.py +0 -0
  210. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_dream_signals.py +0 -0
  211. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_drive_grouping.py +0 -0
  212. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_drive_pressure.py +0 -0
  213. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_embedding_pin.py +0 -0
  214. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_engine_manifest.py +0 -0
  215. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_engram.py +0 -0
  216. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_entity_card.py +0 -0
  217. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_explain_recall.py +0 -0
  218. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_familiarity.py +0 -0
  219. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_feelings_reads.py +0 -0
  220. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_gradation.py +0 -0
  221. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_home_lease_contract.py +0 -0
  222. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_identity_review.py +0 -0
  223. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_identity_self.py +0 -0
  224. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_in_memory_query_text_fallback.py +0 -0
  225. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_keyword_fts.py +0 -0
  226. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_lancedb_triple_store.py +0 -0
  227. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_lessons_layer.py +0 -0
  228. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_maintenance.py +0 -0
  229. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_mind_mass.py +0 -0
  230. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_origin_diversity.py +0 -0
  231. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_participants_channel.py +0 -0
  232. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_phase_artifact_pin.py +0 -0
  233. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_probe.py +0 -0
  234. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_realistic_lmstudio.py +0 -0
  235. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_recall_reads.py +0 -0
  236. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_recent_records.py +0 -0
  237. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_reconstruct.py +0 -0
  238. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_records.py +0 -0
  239. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_redigestion.py +0 -0
  240. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_render_order.py +0 -0
  241. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_replay.py +0 -0
  242. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_replay_idempotency.py +0 -0
  243. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_review_wave.py +0 -0
  244. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_seam_addendum.py +0 -0
  245. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_seam_contracts.py +0 -0
  246. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_situate.py +0 -0
  247. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_spark.py +0 -0
  248. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_spreading.py +0 -0
  249. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_sqlite_triple_store.py +0 -0
  250. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_stm_union.py +0 -0
  251. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_store_vectors.py +0 -0
  252. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_system.py +0 -0
  253. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_tend.py +0 -0
  254. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_term_canonicalization.py +0 -0
  255. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_triple_store_limits.py +0 -0
  256. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_two_sided_visit_contract.py +0 -0
  257. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_valence_gradation.py +0 -0
  258. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_world_model.py +0 -0
  259. {abstractmemory-0.3.1 → abstractmemory-0.4.0}/tests/test_world_model_alias.py +0 -0
@@ -5,9 +5,170 @@ All notable changes to this package will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html) (pre-1.0).
7
7
 
8
- ## Unreleased
8
+ ## [0.4.0] - 2026-10-27
9
+
10
+ The memory graph ([ADR 0003](docs/adr/0003-one-graph-ledger-provenance-and-revisions.md), backlogs 0056-0058):
11
+ `abstractmemory.graph.MemoryGraph` is the only manipulation surface of a mind; every change is a revision, every
12
+ memory points back to the ledger, and every database is a connector behind the graph (SQLite the default). The home
13
+ store holds a notebook-sized corpus. The API is additive: every 0.3.x call keeps working (`close_assertion` stays;
14
+ `ClosureRecord` gains only the `merged` kind). Operator decisions adopted (2026-10-27): visibility is strict
15
+ ownership (lineage never crosses owners; ADR 0003 decision 2); stores are connectors behind `MemoryGraph`, SQLite the
16
+ default (decision 3); the vector re-encoding below is a documented one-way migration with a `vector_encoding` marker.
17
+
18
+ ### Upgrade notes: ONE-WAY migration
19
+
20
+ - Opening a SQLite home with 0.4.0 rewrites its JSON-text vectors as float32 BLOBs. A 0.3.x reader decodes JSON
21
+ vectors only: on a home a 0.4.0 process has written it silently finds no vectors (zero semantic hits, no error).
22
+ Every process sharing a home or a plane must move to 0.4.0 together; an entity home copied to a 0.3.x install
23
+ loses semantic recall. A 0.4.0 home declares it: `<table>_meta` key `vector_encoding` = `float32-blob`
24
+ (`abstractmemory.vector_matrix.VECTOR_ENCODING_KEY`), written by the first write or by the upgrade, never by a
25
+ plain open.
26
+ - Graph homes add four tables (`memg_revisions`, `memg_provenance`, `memg_derivations`, `memg_history`) on first
27
+ use; nothing else in an existing file changes shape.
9
28
 
10
- *No unreleased changes.*
29
+ ### Added
30
+
31
+ - **Connectors** (ADR 0003 decision 3, operator decision 2026-10-27): `MemoryGraph` is the only manipulation
32
+ surface of a mind and every store is a connector behind it: `abstractmemory.graph.backend` (`GraphBackend`,
33
+ `GraphTx` Protocols with their invariants; `register_backend`, `backend_for`, `registered_backends`). SQLite (the
34
+ default for planes and entity homes) and in-memory are declared implementations; a new LanceDB connector
35
+ (`abstractmemory.graph.lancedb_backend`, over `LanceDBTripleStore`: explicit Arrow schemas, a staged transaction,
36
+ a log-first commit, `repair()` re-derives a half-projected revision from the log). One conformance suite,
37
+ `tests/test_graph_conformance.py`, runs every connector; the LanceDB connector cannot promise serialized writers
38
+ across processes nor invisibility of a half-projected revision before `repair()` (strict xfails).
39
+ - **`abstractmemory.graph`**, the one write path of a mind:
40
+ - `SourceRef` (`run`, `step` with the ledger row address `(run_id, seq)`, `seq` 1-based, `artifact`, `message`, `event`,
41
+ `diary_entry`; optional `runtime_id`; one canonical `key()`), validated per kind (`InvalidSourceRef`); a
42
+ `run` / `step` ref naming a synthetic run id (`SYNTHETIC_RUN_ID_PREFIXES`: `chat-`, `diary:`,
43
+ `session_memory_`, `global_memory`) is refused.
44
+ - `Provenance(sources, derived_from, actor, reader, reason, extra)`, strict about its shape;
45
+ `Provenance.from_legacy(...)` lifts the old flat keys (`run_id`, `span_id`, `payload_ref`, `entry_id`, ...)
46
+ in one place, never fabricates a reference (a synthetic run id stays in `extra`), and reads the mixed shape
47
+ the runtime stamps (flat keys plus `sources`: flat keys into `extra`).
48
+ - `Revision` (`revision_id`, `scope`, `owner_id`, `cause`, `occurred_at`, `recorded_at`, `ops`, `provenance`,
49
+ `summary`) with the ops `assert`, `close` (`retract` / `supersede` / `reinterpreted` / `merged`, replacement
50
+ ids, ripple source and hops) and `narrow`. Every time a revision carries is parsed and normalized to one
51
+ UTC text form; a non-timestamp is refused. A close ends the row at the earlier of its current end and the
52
+ close (so `TripleQuery(active_at=)` and ranked recall agree after every close); a close or narrow before the
53
+ claim's `valid_from` is refused.
54
+ - `MemoryGraph(store, journal).apply_revision(rev)`: refuses a memory that is neither sourced nor derived from a
55
+ grounded memory (`ProvenanceRequired`; chains that never reach a source and cycles included); applies all ops
56
+ in ONE SQLite transaction (triples and their keyword rows, window changes, the journal closure when the
57
+ journal shares the file, the revision, provenance, derivation and history rows), or not at all; idempotent on
58
+ the revision id; deterministic ids so the logged revision replays identically. A store row written outside
59
+ the graph is adopted only by an `import` / `migration` revision that carries it as stored (logged with its
60
+ previous provenance, so a replay reproduces it); a different claim under an id the graph holds is refused;
61
+ a close/narrow-only revision must name a cause other than the memories it changes; a `derived_from` across
62
+ owners is refused (other owners' knowledge enters as a source). Re-observation, not duplication: an open
63
+ assert of a claim the graph holds open records its sources on the held memory (`re_observed`, history
64
+ `re-observed`) instead of a second row. Record time is the store's: a fresh apply stamps `recorded_at` with
65
+ its clock (`apply_revision(rev, replay=True)`, used by `replay_into`, keeps the logged value). A revision
66
+ already in the log returns its logged outcome. Every memory is also indexed by the sources of the revision
67
+ that wrote it (`via`). `SourceRef.digest`: an optional sha256 of the verbatim, beside the address.
68
+ - Reads, all bounded index reads: `history(memory_id)` (asserted / closed / narrowed, by which revision, with
69
+ its cause), `sources_of(memory_id, transitive=True)`, `derived_from_source(ref)` (a `run` ref matches
70
+ everything stamped with that run), the lossless change feed `revisions(after=cursor)` (a cursor beyond the
71
+ log's head is refused), `replay_into(target)` (an empty home replays to the same file, adoptions included),
72
+ `names_ref(ref, owner_ids)` (the owner gate in one index probe), and `repair()` for closures a crash left
73
+ unwritten when the journal lives in another file (never needed for same-file plane and entity homes).
74
+ - Four tables in the home file: `memg_revisions`, `memg_provenance`, `memg_derivations`, `memg_history`.
75
+ - **`narrow_assertion(assertion_id, valid_until)`** on `SQLiteTripleStore` and `InMemoryTripleStore`: moves an
76
+ already-closed validity window earlier and never widens it (`ValueError` for an open window or a value that is
77
+ not a timestamp; `False` for an unknown id or a date at or after the current end, compared as instants). `LanceDBTripleStore.narrow_assertion` raises
78
+ `NotImplementedError` (on LanceDB a window changes through the graph's LanceDB connector). AbstractNote no longer
79
+ needs to write the store's private table.
80
+ - **Closure kind `merged`** (`abstractmemory.journal.CLOSURE_KINDS`): the memory was merged into another, named in
81
+ `replacement_ids`. `close_assertions` and `close_record` accept it.
82
+ - Docs: `api.md` (the graph section and its tables), `memory-system.md` ("Time axes", "Provenance").
83
+ - Measured at 50,000 assertions (`tests/bench/bench_graph.py`): `history` 0.02 ms, `sources_of` 0.04 ms,
84
+ `derived_from_source` by step 0.05 ms and by run 0.8 ms, a change-feed page of 100 revisions 4 ms; the 0.3
85
+ alternative (scanning provenance JSON) took 18 ms on vectorless rows and 38 ms with 384-d vectors in the rows.
86
+
87
+ ### Performance (0058)
88
+
89
+ Backlog 0058 (ADR 0003 decisions 3 and 12): the SQLite home store holds a
90
+ notebook-sized corpus. Measured with `tests/bench/bench_store.py`, `main`
91
+ versus this release on the same machine, back to back: subject + owner query
92
+ at 50k rows 14.8 ms -> 0.33 ms; scope "latest 100" 377 ms -> 0.9 ms; scope
93
+ full scan 2.6 s -> 0.5 s; vector query at 50k 5.3 s -> 1.4 ms (first query of
94
+ a handle 0.44 s, it builds the matrix); file 449 MB -> 122 MB; MemorySystem
95
+ `reconstruct` at 20k records 2.7 s -> 0.2 s; `maintenance_due` at 20k 1.9 s ->
96
+ 0.07 ms when nothing is new, 0.1 s after new records. Full table: backlog
97
+ 0058's Report.
98
+
99
+ - **Owner-filtered reads use the indexes.** The owner filter is now
100
+ `owner_id = ?` instead of `COALESCE(owner_id, '') = ?` (same rows: the
101
+ filter only applies to a non-empty owner, which a NULL or empty stored owner
102
+ never equals). A new index `idx_<table>_scope_owner_observed (scope,
103
+ owner_id, observed_at, assertion_id)` serves "latest N in a (scope, owner)",
104
+ as-of windows and per-pair scans in query order without sorting the
105
+ partition; reads anchored on ids, a subject or an object use their own index
106
+ and check scope/owner per row. Existing homes gain the index when the store
107
+ is opened; no row is rewritten. `SQLiteTripleStore.query_plan(q)` returns
108
+ SQLite's `EXPLAIN QUERY PLAN` lines for a query (tests pin the plans).
109
+ - **Structured reads no longer fetch the vector column.** `query` (without
110
+ `query_text`/`query_vector`) and `query_keywords` select the assertion
111
+ columns only, instead of `SELECT *` dragging the stored embedding (several KB
112
+ per row) and the canonical text through every scan. They no longer read the
113
+ embedding pin either (it guards semantic queries only). Semantic queries and
114
+ `stored_vector` still read the vector; `TripleAssertion` is unchanged.
115
+ - **Vectors are float32 BLOBs.** `SQLiteTripleStore` stores vectors as float32
116
+ little-endian BLOBs (4 bytes per dimension instead of ~20 bytes of JSON
117
+ text). Homes holding JSON vectors are upgraded in place when the store opens:
118
+ rows above the `vector_blob_high_water` cursor are rewritten in bounded
119
+ transactions (idempotent; an interrupted upgrade resumes; ~5 s once for 50k
120
+ rows of 384-d vectors). Stored precision is float32: a score differs from
121
+ the float64 value an embedder returned by about 1e-7. A value float32 cannot
122
+ hold raises `ValueError` at write (zero rows written) instead of being
123
+ stored as infinity; `stored_vector` returns the float32 values. One-way: see
124
+ "Upgrade notes" above.
125
+ - **Opening a home is a read.** `SQLiteTripleStore` and `SQLiteJournal` take no write lock when opening an
126
+ up-to-date home (the keyword-index and vector backfills run only when there is work; every insert path keeps
127
+ their cursors at the head; the journal checks its schema in a deferred transaction), so a reader never waits
128
+ behind a writer (before: up to `busy_timeout`, then "database is locked").
129
+ - **Matrix cache footprint.** A (re)build reserves exactly the table's vector rows (one allocation); appends
130
+ grow by at most 10 % (`store_tuning.VECTOR_MATRIX_GROWTH`; no doubling). Per process that queries a home:
131
+ rows x dims x 4 B plus about 170 B per row (`store_tuning.py`). Measured at 100k x 1024: 424 MB held (552 MB
132
+ with doubling), build peak 460 MB (833 MB).
133
+ - **Vector queries from an in-process matrix cache.** With numpy installed
134
+ (new extra `abstractmemory[fast]`; also in `all`, `all-apple`, `all-gpu`
135
+ and `test`), vector queries are served from a float32 matrix built at a
136
+ handle's first semantic query, appended with rows written since by any
137
+ handle or process, and rebuilt when the vectors are rewritten
138
+ (`replace_vectors`, the upgrade; `vector_generation` in the meta sidecar).
139
+ Results are the reference scan's (`vector_scoring.rank_by_cosine`): same
140
+ rows, same order (ties in rowid order), bit-identical scores — a float32
141
+ pass picks the candidates with a margin above its error bound, and they are
142
+ re-scored with the reference arithmetic. Without numpy, or when a stored
143
+ vector cannot be scored exactly (mixed dimensions, non-finite values), the
144
+ Python scan answers, labelled once per handle with a `#FALLBACK`
145
+ `RuntimeWarning`. `SQLiteTripleStore.vector_engine` reports the path.
146
+ - **`maintenance_due` bounded by a cursor.** For the SQLite and in-memory
147
+ stores the answer is folded from the new store change feed
148
+ `assertions_after(cursor, *, scope, owner_id, limit)`: a check reads only the
149
+ rows written since the previous check of the same (store, journal, scopes)
150
+ and re-reads the journal's formation bindings only when the journal moved.
151
+ `last_maintenance_seq` uses the same fold. The answer is the full scan's
152
+ (other stores keep the scan).
153
+ - Tuning constants of the store (margins, batch and page sizes) live in
154
+ `abstractmemory.store_tuning`, each with its bound or measurement.
155
+ - The benchmark lives in the repository: `tests/bench/bench_store.py`.
156
+
157
+ ## [0.3.2] - 2026-10-20
158
+
159
+ ### Added
160
+
161
+ - **A third closure kind, `reinterpreted`**, for an assertion whose reading was
162
+ superseded by a re-interpretation of its source: the writer no longer reads
163
+ that source this way (for example, AbstractNote understanding a note again
164
+ against an earlier foundation withdraws its previous reading). It is neither
165
+ `retract` (the fact was wrong) nor `supersede` (a later fact replaced it).
166
+ `ClosureRecord`, `close_assertions` and `close_record` accept it;
167
+ `replacement_ids` is optional (the new reading's assertions, when there are
168
+ any); like the other kinds, a `reinterpreted` closure takes the assertion out
169
+ of ranked retrieval while it stays in the store and in history. The accepted
170
+ kinds are listed in `abstractmemory.journal.CLOSURE_KINDS`.
171
+ Additive: existing callers and stored journals are unaffected.
11
172
 
12
173
  ## [0.3.1] - 2026-10-19
13
174
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: AbstractMemory
3
- Version: 0.3.1
3
+ Version: 0.4.0
4
4
  Summary: AbstractMemory: temporal, provenance-aware semantic memory primitives for AbstractFramework.
5
5
  Project-URL: AbstractFramework (monorepo), https://github.com/lpalbou/abstractframework
6
6
  Author: Laurent-Philippe Albou
@@ -19,18 +19,24 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: >=3.10
20
20
  Provides-Extra: all
21
21
  Requires-Dist: lancedb; extra == 'all'
22
+ Requires-Dist: numpy>=1.24; extra == 'all'
22
23
  Provides-Extra: all-apple
23
24
  Requires-Dist: lancedb; extra == 'all-apple'
25
+ Requires-Dist: numpy>=1.24; extra == 'all-apple'
24
26
  Provides-Extra: all-gpu
25
27
  Requires-Dist: lancedb; extra == 'all-gpu'
28
+ Requires-Dist: numpy>=1.24; extra == 'all-gpu'
26
29
  Provides-Extra: apple
27
30
  Provides-Extra: dev
28
31
  Requires-Dist: pytest>=7.0.0; extra == 'dev'
32
+ Provides-Extra: fast
33
+ Requires-Dist: numpy>=1.24; extra == 'fast'
29
34
  Provides-Extra: gpu
30
35
  Provides-Extra: lancedb
31
36
  Requires-Dist: lancedb; extra == 'lancedb'
32
37
  Provides-Extra: test
33
38
  Requires-Dist: lancedb; extra == 'test'
39
+ Requires-Dist: numpy>=1.24; extra == 'test'
34
40
  Requires-Dist: pytest>=7.0.0; extra == 'test'
35
41
  Description-Content-Type: text/markdown
36
42
 
@@ -86,6 +92,13 @@ Optional LanceDB backend:
86
92
  python -m pip install -e ".[lancedb]"
87
93
  ```
88
94
 
95
+ Fast vector search on the SQLite store (numpy; without it the store serves the
96
+ same results from a labelled Python scan):
97
+
98
+ ```bash
99
+ python -m pip install -e ".[fast]"
100
+ ```
101
+
89
102
  PyPI (packaged release):
90
103
 
91
104
  ```bash
@@ -93,7 +106,7 @@ python -m pip install AbstractMemory
93
106
  python -m pip install "AbstractMemory[lancedb]"
94
107
  ```
95
108
 
96
- The distribution name is `AbstractMemory` (pip is case-insensitive); the import name is `abstractmemory`. The `[apple]`/`[gpu]` extras are no-op compatibility aliases; `[all]`, `[all-apple]`, and `[all-gpu]` install the LanceDB backend.
109
+ The distribution name is `AbstractMemory` (pip is case-insensitive); the import name is `abstractmemory`. The `[apple]`/`[gpu]` extras are no-op compatibility aliases; `[fast]` installs numpy for the SQLite store's vector matrix cache; `[all]`, `[all-apple]`, and `[all-gpu]` install the LanceDB backend and numpy.
97
110
 
98
111
  ## Quick example — layer 1 (triples)
99
112
 
@@ -141,6 +154,10 @@ result = system.reconstruct(Stimulus(cue_text="pool outage"), scopes=[("session"
141
154
  system.commit_selection(result.trace_id, [h.record_id for h in result.handles[:2]])
142
155
  ```
143
156
 
157
+ ## The memory graph: revisions and provenance
158
+
159
+ `abstractmemory.graph` is the write path of a mind (0.4.0): every change to the graph is one `Revision` (a cause such as `ingest`, `reinterpret` or `maintenance`, plus `assert` / `close` / `narrow` operations applied together and atomically, once per revision id), and every memory must name where it came from in AbstractRuntime's ledger (a `SourceRef` to a run, a step `(run_id, seq)`, an artifact, a message, an event or a diary entry) or the memories it was derived from; a write with neither is refused with `ProvenanceRequired`. `MemoryGraph(store, journal)` then answers `history(memory_id)` (asserted, closed, narrowed: by which revision and why), `sources_of(memory_id)`, `derived_from_source(ref)`, a lossless change feed `revisions(after=cursor)`, and `replay_into(...)`. The database is a connector behind the graph (`abstractmemory.graph.backend`): SQLite by default, LanceDB and in-memory held to the same conformance suite. See [`docs/api.md`](docs/api.md#the-memory-graph-revisions-and-provenance) and the "Time axes" and "Provenance" sections of [`docs/memory-system.md`](docs/memory-system.md).
160
+
144
161
  ## Documentation
145
162
 
146
163
  - Getting started: [`docs/getting-started.md`](docs/getting-started.md)
@@ -164,7 +181,7 @@ system.commit_selection(result.trace_id, [h.record_id for h in result.handles[:2
164
181
 
165
182
  ## Design principles
166
183
 
167
- - **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
184
+ - **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede/reinterpreted/merged); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
168
185
  - **Reads are pure**: reconstruction, inspection, replay, and the entity card deposit nothing. `commit_selection` is the only strengthening path.
169
186
  - **One seq axis**: the journal assigns a monotonic `seq` to every record; any past state is reproducible by anchoring reads at `as_of`.
170
187
  - **Works-or-loud**: degraded paths are labeled `#FALLBACK` in result warnings; invalid inputs raise actionable errors instead of silently meaning something else.
@@ -50,6 +50,13 @@ Optional LanceDB backend:
50
50
  python -m pip install -e ".[lancedb]"
51
51
  ```
52
52
 
53
+ Fast vector search on the SQLite store (numpy; without it the store serves the
54
+ same results from a labelled Python scan):
55
+
56
+ ```bash
57
+ python -m pip install -e ".[fast]"
58
+ ```
59
+
53
60
  PyPI (packaged release):
54
61
 
55
62
  ```bash
@@ -57,7 +64,7 @@ python -m pip install AbstractMemory
57
64
  python -m pip install "AbstractMemory[lancedb]"
58
65
  ```
59
66
 
60
- The distribution name is `AbstractMemory` (pip is case-insensitive); the import name is `abstractmemory`. The `[apple]`/`[gpu]` extras are no-op compatibility aliases; `[all]`, `[all-apple]`, and `[all-gpu]` install the LanceDB backend.
67
+ The distribution name is `AbstractMemory` (pip is case-insensitive); the import name is `abstractmemory`. The `[apple]`/`[gpu]` extras are no-op compatibility aliases; `[fast]` installs numpy for the SQLite store's vector matrix cache; `[all]`, `[all-apple]`, and `[all-gpu]` install the LanceDB backend and numpy.
61
68
 
62
69
  ## Quick example — layer 1 (triples)
63
70
 
@@ -105,6 +112,10 @@ result = system.reconstruct(Stimulus(cue_text="pool outage"), scopes=[("session"
105
112
  system.commit_selection(result.trace_id, [h.record_id for h in result.handles[:2]])
106
113
  ```
107
114
 
115
+ ## The memory graph: revisions and provenance
116
+
117
+ `abstractmemory.graph` is the write path of a mind (0.4.0): every change to the graph is one `Revision` (a cause such as `ingest`, `reinterpret` or `maintenance`, plus `assert` / `close` / `narrow` operations applied together and atomically, once per revision id), and every memory must name where it came from in AbstractRuntime's ledger (a `SourceRef` to a run, a step `(run_id, seq)`, an artifact, a message, an event or a diary entry) or the memories it was derived from; a write with neither is refused with `ProvenanceRequired`. `MemoryGraph(store, journal)` then answers `history(memory_id)` (asserted, closed, narrowed: by which revision and why), `sources_of(memory_id)`, `derived_from_source(ref)`, a lossless change feed `revisions(after=cursor)`, and `replay_into(...)`. The database is a connector behind the graph (`abstractmemory.graph.backend`): SQLite by default, LanceDB and in-memory held to the same conformance suite. See [`docs/api.md`](docs/api.md#the-memory-graph-revisions-and-provenance) and the "Time axes" and "Provenance" sections of [`docs/memory-system.md`](docs/memory-system.md).
118
+
108
119
  ## Documentation
109
120
 
110
121
  - Getting started: [`docs/getting-started.md`](docs/getting-started.md)
@@ -128,7 +139,7 @@ system.commit_selection(result.trace_id, [h.record_id for h in result.handles[:2
128
139
 
129
140
  ## Design principles
130
141
 
131
- - **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
142
+ - **Append-only, no deletion**: updates are new assertions; belief revision is closure records (retract/supersede/reinterpreted/merged); forgetting is decay of retrieval strength plus closures and silencing — the substrate is lossless.
132
143
  - **Reads are pure**: reconstruction, inspection, replay, and the entity card deposit nothing. `commit_selection` is the only strengthening path.
133
144
  - **One seq axis**: the journal assigns a monotonic `seq` to every record; any past state is reproducible by anchoring reads at `as_of`.
134
145
  - **Works-or-loud**: degraded paths are labeled `#FALLBACK` in result warnings; invalid inputs raise actionable errors instead of silently meaning something else.
@@ -19,6 +19,7 @@ AbstractMemory is a Python library for durable, append-only agent memory: tempor
19
19
  - FAQ: [`faq.md`](faq.md) — common questions and current limits.
20
20
  - Troubleshooting: [`troubleshooting.md`](troubleshooting.md) — symptom-oriented fixes for setup, retrieval, embedding-space, durability, and maintenance problems.
21
21
  - Development: [`development.md`](development.md) — local setup, tests, and the design backlog.
22
+ - Architecture decisions: [`adr/README.md`](adr/README.md) — durable rules, including ADR 0001 (an altered memory ripples through the memories connected to it) and ADR 0002 (AbstractMemory owns the semantic temporal memory graph and all of its processing; applications build on it).
22
23
 
23
24
  ## Related
24
25
 
@@ -0,0 +1,147 @@
1
+ # ADR 0001: An altered memory ripples through the memories connected to it
2
+
3
+ Status: Accepted (operator ruling, 2026-10-21; activation model confirmed with the operator the same day).
4
+ Amended 2026-10-27 (operator ruling): the ripple is AbstractMemory's process end to end, not a consumer's
5
+ (ADR 0002). Aspirational: AbstractMemory does not implement it yet; AbstractNote holds a prototype
6
+ (its ADR 0008 propagation lane) that is to be absorbed here, not kept as the implementation.
7
+
8
+ ## Context
9
+
10
+ A memory system is not a filing cabinet. When one memory is altered, because new evidence arrived, because an
11
+ earlier record was found, because a causal root was identified, or because a reading was revised, what we
12
+ thought we knew about the memories connected to it is also in question. Sometimes the effect is subtle: an
13
+ incremental refinement of a neighbour's summary. Sometimes it is dramatic: a restructuring of a whole region of
14
+ the graph, as when a new causal root gives a deeper understanding of several things we thought we understood.
15
+ Dramatic changes are rare in a stable system that has learned enough; in the early days of a memory system
16
+ they happen often.
17
+
18
+ Today the stores treat an alteration as local: `close_assertion`, closure records (`retract`, `supersede`,
19
+ `reinterpreted`), reinforcement, attenuation and silencing change one record's standing or window, and the
20
+ sleep passes (`consolidation.py`: `sleep_pass`, `consolidation_pass`, `dream_pass`, `maintenance_report`)
21
+ tend the graph without re-evaluating the neighbours of a record whose meaning changed. Nothing in the library
22
+ asks "given that A changed this much, what must be reconsidered about B and E?".
23
+
24
+ ## Decision
25
+
26
+ 1. **A change in a memory is an event with a magnitude, not a silent update.** Any operation that alters what a
27
+ memory means (its type or kind, its summary or content, its belief window, its relationships) MUST produce a
28
+ change record that names the memory, what changed, and a measured magnitude. The magnitude combines the
29
+ dimensions that matter for meaning: type change, distance between the old and new summary (an embedding
30
+ distance, calibrated above the writer model's own rewrite noise), the share of statements replaced, and the
31
+ share of relationships replaced. The thresholds live in one named place and are tuned by measurement, never
32
+ hard-coded in several places.
33
+ 2. **The ripple is evaluated hop by hop and decided by effect, not by distance alone.** When memory A changes,
34
+ every memory connected to A is a candidate for reconsideration, weighted by how much it relied on A
35
+ (the strength and recency of their relationship, the share of its own statements that involve A). Each
36
+ candidate is reconsidered; if the effect on B is minor (below the magnitude threshold once measured), the
37
+ ripple stops at B; if the effect on E is large, E's own change becomes a new event and the memories
38
+ connected to E are candidates in turn, iteratively, until no candidate's measured change clears the
39
+ threshold.
40
+ 3. **Propagation carries decaying impact and never amplifies.** The impact handed from A to its neighbours is the
41
+ measured magnitude scaled by reliance and by a decay factor; a reconsidered memory may hand on at most what it
42
+ received or what it measured itself, whichever is smaller; a floor stops the spread. Cycles therefore die out
43
+ by damping rather than by assuming the graph is a tree: the memory graph is not a DAG and the rule must not
44
+ require one.
45
+ 4. **Numbers choose, meaning is decided by the reader.** Magnitudes, reliance weights, decay and order select
46
+ which memories are reconsidered, in which order, and under what budget. What a reconsidered memory now means
47
+ is decided by the same reader that wrote it (a model, or the consumer's own interpretation step), never by
48
+ string rules on content.
49
+ 5. **Every ripple is bounded, visible and resumable.** Before a ripple runs, the system can say how many memories
50
+ may be reconsidered and why (the sources and their magnitudes). A ripple runs under a budget; when the budget
51
+ stops it, what was left is recorded and reported, never dropped silently (root framework ADR-0026). A second
52
+ pass over the same change, with nothing new, costs no reader call: an unchanged reconsideration is settled by
53
+ comparing structure, and is itself recorded.
54
+ 6. **History is kept.** A reconsidered memory keeps its previous reading in the journal; the as-received view of
55
+ the graph before the ripple stays answerable. Closures caused by a ripple carry their cause (the source memory
56
+ and the hop count) so that a later reader, human or model, can see why a belief moved.
57
+ 7. **The ripple is an activation with a threshold, not a distance rule.** Whether a connected memory is
58
+ reconsidered is decided by an activation function over the impact it receives: each memory accumulates the
59
+ reliance-weighted impacts of every changed neighbour within a pass (several small changes together can
60
+ cross what none crosses alone), the accumulated potential passes through a smooth gate (a logistic
61
+ `1 / (1 + e^-k(x - θ))` or an equivalent monotone function; the gate is a configuration, not a model), and
62
+ the memory is reconsidered when the gated potential is above the floor. The potential's input is a weighted
63
+ sum of standardised signals (type change, summary distance, statements replaced, relationships replaced),
64
+ each standardised against the reader's own rewrite noise, and divided by the memory's **mass** (how much
65
+ evidence already supports it): a thinly evidenced memory moves on little, a heavily evidenced one needs
66
+ more, which is how a stable system comes to ripple rarely without anyone scheduling quiet. Onward
67
+ propagation beyond one hop uses the **measured** change of the reconsidered memory, never the predicted
68
+ impact alone. Termination is guaranteed by three rules together: a memory is reconsidered at most once per
69
+ pass (a refractory period), impact never amplifies (loop gain `decay × max reliance × max gate slope < 1`),
70
+ and the floor stops the tail. Every gate decision is recorded with its potential, so thresholds can be
71
+ re-tuned from the record without re-running the ripple.
72
+ 8. **Edges learn.** The reliance weight of an edge may be adjusted from history: an edge whose ripples
73
+ repeatedly produced an unchanged reconsideration conducts less next time; an edge whose ripples produced
74
+ real change conducts more. Adjustments are bounded, recorded, and never silence an edge entirely.
75
+ 9. **Stable systems ripple rarely; young systems ripple often, and that is expected.** The cadence predicate of
76
+ the sleep pass (`maintenance_due`) and any consumer's scheduler MUST treat pending ripples as work due,
77
+ with priority given to the largest sources, and MUST NOT suppress ripples to keep a young system quiet.
78
+
79
+ ## Consequences
80
+
81
+ ### Positive
82
+ - The graph says what we know *now*, with the understanding the newest evidence allows, instead of what we
83
+ happened to believe when each memory was first written.
84
+ - Deep changes (a new causal root, a re-dated archive, an entity that turns out to be a person as well as a
85
+ project) reach the memories that leaned on them, in a bounded and explainable way.
86
+ - Every moved belief has a cause on record.
87
+
88
+ ### Negative
89
+ - Reconsideration costs reader calls; a young system pays more. Budgets and the no-call settle rule bound it,
90
+ and the operator sees the bound before the run.
91
+ - Thresholds are empirical; a wrong threshold either spreads noise (too low) or freezes understanding (too
92
+ high). Calibration against the reader's own rewrite noise is mandatory before a threshold is trusted.
93
+ - The journal grows: one record per reconsideration and per change event.
94
+
95
+ ### Neutral
96
+ - AbstractMemory owns the whole ripple: the primitives (change records, closure causes, additive windows,
97
+ journal history), the propagation and activation, the budget and the reconsideration step. The reader that
98
+ decides what a reconsidered memory now means (decision 4) is a model the host supplies to AbstractMemory
99
+ (an injected reader), so the process lives here while the model choice stays with the host. Consumers
100
+ (AbstractNote, AbstractEntity, gateway apps) trigger and display ripples; they do not implement them.
101
+
102
+ ## Enforcement
103
+
104
+ - A pull request that adds or changes an operation altering a memory's meaning MUST either emit a change record
105
+ with a magnitude or state in the ADR-linked backlog item why the operation cannot (and what the consumer must
106
+ do instead).
107
+ - Closure records written because of a ripple MUST carry the cause (`source memory`, `hops`); a reviewer rejects
108
+ a cause-less ripple closure.
109
+ - No code path may cap a ripple without recording what was left out (`left_out`) and warning; the marker
110
+ `#[WARNING:TRUNCATION]` applies to any bounded preview of a ripple's members.
111
+ - Threshold constants live in one module with their calibration quoted; a second copy of a threshold is a
112
+ review failure.
113
+ - Docs: `memory-system.md` "Sleep and dreams" MUST describe the ripple when the pass gains one; until then it
114
+ states that the ripple is planned in AbstractMemory (backlog 0054) and points here.
115
+ - A consumer package MUST NOT add its own ripple, propagation or activation logic over memories; a gap in
116
+ AbstractMemory is raised as an AbstractMemory backlog item (ADR 0002).
117
+
118
+ ## Validation
119
+
120
+ - Unit: a deep change spreads one hop; a shallow change does not; two sub-threshold changes on the same neighbour
121
+ together cross the gate; a heavily evidenced memory needs more impact than a thin one; the floor stops a hub;
122
+ a cycle dies within a bounded number of hops with the loop gain below one; a second pass with nothing new makes
123
+ no reader call; a budget stop records `left_out` equal to what is pending; every gate decision is on record with
124
+ its potential. Each check MUST go red when its mechanism is removed (mutation list in the test file).
125
+ - Calibration: the summary-distance threshold is set from a measured distribution of same-memory rewrites by the
126
+ reader in use, and the report that set it is linked from the constants module.
127
+ - Scenario: a dated archive that changes the type of one memory (project → person) must reconsider the memories
128
+ connected to it and leave unrelated regions untouched; the as-received view before the ripple still answers.
129
+
130
+ ## Backlog links
131
+
132
+ - Proposed: [ripple_wave/0001_change_records_and_ripple_primitives.md](../backlog/proposed/ripple_wave/0001_change_records_and_ripple_primitives.md)
133
+ (the AbstractMemory primitives: change records with magnitude, closure causes, `maintenance_due` counting pending
134
+ ripples, `narrow_assertion`).
135
+ - Planned: [knowledge_graph_convergence/0054_ripple_propagation_and_activation.md](../backlog/planned/knowledge_graph_convergence/0054_ripple_propagation_and_activation.md)
136
+ (the propagation, activation and reconsideration process in AbstractMemory).
137
+ - Prototype to absorb, not to keep: AbstractNote ADR 0008 and its propagation lane (R6, 2026-10-20/21: calibrated
138
+ thresholds, decay 0.5, floor 0.1, one hop per pass, budgeted stage, no-call settle), see
139
+ `abstractnote/docs/adr/0008-interpretation-is-a-derived-view.md`, `abstractnote/untracked/briefs/R6-propagation-design.md`,
140
+ and AbstractNote's unmerged branch `retro/integration` (`recall/propagation.py`, `recall/activation.py`).
141
+
142
+ ## Related
143
+
144
+ - ADR 0002 (AbstractMemory owns the semantic temporal memory graph and all its processing).
145
+ - Root framework ADR-0026 (truncation policy: nothing silent).
146
+ - `memory-system.md` (attention, closures, sleep and dreams), `api.md` (closure records, `close_assertion`, consolidation).
147
+ - AbstractEntity's maintenance phases (the sleep phase where the graph is tended) as prior art for a scheduled, bounded night.
@@ -0,0 +1,92 @@
1
+ # ADR 0002: AbstractMemory owns the semantic temporal memory graph and all of its processing
2
+
3
+ Status: Accepted (operator ruling, 2026-10-27). Aspirational for existing consumers: AbstractNote currently
4
+ keeps a parallel graph (its ADR 0003) that is to converge here (backlog track `knowledge_graph_convergence/`).
5
+
6
+ ## Context
7
+
8
+ AbstractMemory is the framework's semantic, temporal memory graph: the place where notes, messages,
9
+ documents and an entity's own experience become knowledge that structures and reorganises itself over
10
+ time. In October 2026 AbstractNote, an application built on AbstractGateway, needed capabilities AbstractMemory
11
+ did not offer for document knowledge (an entity registry with reversible merges, a claim lifecycle with a
12
+ revision log, hybrid search and timelines, communities, consolidation, reflection, the ripple of ADR 0001). It
13
+ built them inside its own package, over its own SQLite index, and kept AbstractMemory only as a write-only
14
+ projection of its claims (AbstractNote ADR 0003), including direct writes to AbstractMemory's private tables.
15
+ About half of AbstractNote's code is now generic memory-graph logic that no other application can use.
16
+
17
+ That is the wrong direction for the framework. AbstractEntity (self-evolving persistent agents that keep
18
+ diaries and leave notes for themselves) needs the same capabilities, and so does any assistant or agent that
19
+ should learn from what it reads. Some of AbstractNote's designs are newer and stronger than AbstractMemory's;
20
+ they belong in AbstractMemory so every consumer benefits, not in one application.
21
+
22
+ ## Decision
23
+
24
+ 1. **One home for memory.** Everything that structures, links, revises, consolidates, reorganises or
25
+ retrieves memories lives in AbstractMemory: entities and identity, claims and their lifecycle, revisions
26
+ and history, retrieval (search, expansion, timelines, then-versus-now), self-organisation (consolidation,
27
+ communities, topics), reflection and review, and the ripple of an altered memory (ADR 0001).
28
+ 2. **Consumers build on the graph; they never rebuild it.** An application or package may add an abstraction
29
+ on top of AbstractMemory (for example a notes or diary layer) through its public API. It must not keep a
30
+ parallel graph, a second store of the same knowledge, or its own copy of memory processes, and must never
31
+ write AbstractMemory's private tables.
32
+ 3. **A gap is fixed in AbstractMemory.** When AbstractMemory is not good enough for a consumer, the fix is an
33
+ AbstractMemory change (raised as an AbstractMemory backlog item), not a workaround in the consumer.
34
+ 4. **Better designs are absorbed.** A design proven in a consumer (as AbstractNote's entity registry, revision
35
+ log or ripple prototype) is generalised into AbstractMemory and the consumer then uses it.
36
+ 5. **The process lives here; the model is supplied.** Steps that need judgement (a model deciding identity,
37
+ what a revised memory means, a summary) run inside AbstractMemory's process through a reader the host
38
+ supplies (an injected model client or callable). Model choice and cost stay with the host; the process,
39
+ its bounds and its records stay in AbstractMemory.
40
+ 6. **Note-specific and agent-specific framing stays with the consumer.** Capture, file import, the wording of
41
+ prompts for one kind of input, and the views an application shows remain the consumer's, as long as they
42
+ read and write through AbstractMemory.
43
+
44
+ ## Consequences
45
+
46
+ ### Positive
47
+ - Every application (AbstractNote, AbstractEntity, AbstractAssistant, agents) runs on one implementation of
48
+ memory, and improvements to memory reach all of them.
49
+ - Knowledge captured through one app is visible to its OWNER's other apps through the gateway (and an entity's to
50
+ the person who owns the entity); never to another person by default: visibility is strict ownership, and a plane
51
+ is not a sharing scope (ADR 0003 decision 2, amended 2026-10-27).
52
+
53
+ ### Negative
54
+ - AbstractMemory grows a document and world-knowledge layer beside its agent memory system, and must keep both
55
+ coherent.
56
+ - AbstractNote must migrate off its parallel graph capability by capability, which is real work and
57
+ temporarily slows its own features.
58
+
59
+ ### Neutral
60
+ - Generic infrastructure AbstractNote also built (a durable work queue with leases and retries, a memory read
61
+ API over HTTP) belongs to AbstractRuntime and AbstractGateway rather than here; this ADR does not decide their
62
+ shape.
63
+
64
+ ## Enforcement
65
+
66
+ - Review rejects, in any consumer, access to AbstractMemory internals (`_table`, `_conn`, `_lock` or any `_`
67
+ attribute of a store) and any new memory-graph process (entity resolution, claim revision, consolidation,
68
+ communities, ripple, retrieval fusion) added outside AbstractMemory.
69
+ - A consumer that needs a missing capability opens an AbstractMemory backlog item and links it from its own
70
+ backlog; the consumer item is blocked on it rather than implementing a workaround.
71
+ - New AbstractMemory capabilities absorbed from a consumer cite that consumer's design and tests as prior art.
72
+
73
+ ## Validation
74
+
75
+ - A search for private-attribute access to AbstractMemory objects in consumer repositories returns nothing once
76
+ each migration item closes (AbstractNote today: `store/kg.py`).
77
+ - Each capability in the convergence track has a scenario test that a consumer-shaped client passes through the
78
+ public API alone.
79
+ - AbstractNote's backlog shows each parallel-graph capability either migrated or with a linked AbstractMemory item.
80
+
81
+ ## Backlog links
82
+
83
+ - Planned track: [knowledge_graph_convergence/](../backlog/planned/knowledge_graph_convergence/README.md)
84
+ (items 0050-0055).
85
+ - Related: [ripple_wave/0001](../backlog/proposed/ripple_wave/0001_change_records_and_ripple_primitives.md)
86
+ (the ripple primitives).
87
+ - Consumer side: AbstractNote backlog 0033-0036 (track `planned/memory_convergence/`).
88
+
89
+ ## Related
90
+
91
+ - ADR 0001 (an altered memory ripples through the memories connected to it).
92
+ - AbstractNote ADR 0003 (its parallel graph, now transitional) and ADR 0008 (its ripple prototype).