AbstractMemory 0.3.2__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.
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/CHANGELOG.md +147 -2
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/PKG-INFO +20 -3
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/README.md +13 -2
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/README.md +1 -0
- abstractmemory-0.4.0/docs/adr/0001-altered-memories-ripple.md +147 -0
- abstractmemory-0.4.0/docs/adr/0002-abstractmemory-owns-the-memory-graph.md +92 -0
- abstractmemory-0.4.0/docs/adr/0003-one-graph-ledger-provenance-and-revisions.md +261 -0
- abstractmemory-0.4.0/docs/adr/README.md +10 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/api.md +125 -5
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/architecture.md +7 -2
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/overview.md +36 -5
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0050_entity_registry_identity_and_reversible_merges.md +42 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0051_claim_lifecycle_and_revision_log.md +39 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0052_document_knowledge_retrieval.md +37 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0053_self_organisation_communities_consolidation_reflection.md +38 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0054_ripple_propagation_and_activation.md +41 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0055_notes_and_diary_layer_for_consumers.md +36 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0056_ledger_provenance_contract_and_revision_log.md +175 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0057_one_mind_per_plane_sqlite_home.md +69 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/0058_home_store_performance_indexes_vectors.md +148 -0
- abstractmemory-0.4.0/docs/backlog/planned/knowledge_graph_convergence/README.md +87 -0
- abstractmemory-0.4.0/docs/backlog/proposed/ripple_wave/0001_change_records_and_ripple_primitives.md +31 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/faq.md +1 -1
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/getting-started.md +35 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/memory-system.md +26 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/stores.md +42 -5
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/troubleshooting.md +22 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/llms-full.txt +271 -15
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/llms.txt +2 -1
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/pyproject.toml +11 -1
- abstractmemory-0.4.0/release-notes.md +146 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/__init__.py +16 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/__init__.py +60 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/backend.py +117 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/graph.py +1363 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/lancedb_backend.py +580 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/provenance.py +323 -0
- abstractmemory-0.4.0/src/abstractmemory/graph/revisions.py +239 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/in_memory_store.py +84 -21
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/journal.py +5 -4
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/journal_sqlite.py +46 -20
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/journal_sqlite_rows.py +4 -1
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/lancedb_store.py +5 -0
- abstractmemory-0.4.0/src/abstractmemory/sleep_cadence.py +290 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/sqlite_store.py +493 -56
- abstractmemory-0.4.0/src/abstractmemory/store_tuning.py +71 -0
- abstractmemory-0.4.0/src/abstractmemory/vector_matrix.py +434 -0
- abstractmemory-0.4.0/tests/bench/bench_graph.py +210 -0
- abstractmemory-0.4.0/tests/bench/bench_store.py +329 -0
- abstractmemory-0.4.0/tests/graph_support.py +203 -0
- abstractmemory-0.4.0/tests/test_cadence_cursor.py +296 -0
- abstractmemory-0.4.0/tests/test_graph_conformance.py +354 -0
- abstractmemory-0.4.0/tests/test_graph_e2e.py +197 -0
- abstractmemory-0.4.0/tests/test_graph_performance.py +193 -0
- abstractmemory-0.4.0/tests/test_graph_provenance.py +502 -0
- abstractmemory-0.4.0/tests/test_graph_revisions.py +620 -0
- abstractmemory-0.4.0/tests/test_home_open_is_a_read.py +91 -0
- abstractmemory-0.4.0/tests/test_narrow_assertion.py +142 -0
- abstractmemory-0.4.0/tests/test_store_performance.py +179 -0
- abstractmemory-0.4.0/tests/test_vector_encoding_marker.py +51 -0
- abstractmemory-0.4.0/tests/test_vector_matrix.py +569 -0
- abstractmemory-0.4.0/tests/test_vector_matrix_footprint.py +88 -0
- abstractmemory-0.3.2/release-notes.md +0 -13
- abstractmemory-0.3.2/src/abstractmemory/sleep_cadence.py +0 -74
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/.github/workflows/ci.yml +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/.github/workflows/release.yml +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/.gitignore +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/ACKNOWLEDGMENTS.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/CODE_OF_CONDUCT.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/CONTRIBUTING.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/LICENSE +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/SECURITY.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/0008_gateway_memory_install_and_config_boundary.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/002_sqlite_database_compatibility_and_store_capabilities.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/004_recall_trace_and_access_events_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/005_source_linked_summaries_and_derived_assertion_lineage.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/007_read_only_memory_observer_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0037_familiarity_metamemory_read.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0038_open_commitments_and_triggers.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0039_tend_election_grammar.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/extension_wave/0049_stable_shelf_order_for_prefix_reuse.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0009_assertion_identity_and_batch_read_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0010_append_only_closure_records_for_retract_and_supersede.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0011_cross_backend_parity_conformance_suite.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0013_store_concurrency_and_thread_safety_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0014_embedding_space_integrity_manifest.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0017_memory_journal_and_scope_bindings_layer.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0018_neurotransmitter_attention_strengthen_weaken_decay.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0019_hybrid_retrieval_channels_fts_vector_exact.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0020_reconstruction_shelf_and_selection_traces.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0021_memory_records_and_remember_api.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0022_probe_and_bounded_source_expansion.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0023_maintenance_sleep_consolidate_dream.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0024_memory_system_facade_and_consumer_migration.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0025_graph_backend_decision_record_memgraph_rejected.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0026_spreading_activation_and_working_set.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0027_runtime_seam_contract_v1.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0029_sleep_reactivity_dreams_as_reaction.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0030_fork_comparison_adoption_wave.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0031_second_fork_pass_and_lifecycle_closure.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/memory_system_v1/0036_third_pass_extension_wave.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0032_dream_subconscious_lifecycle.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0033_world_model_orientation_cards.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0034_situate_temporal_relational_reconstruction.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/completed/subconscious_wave/0035_lessons_layer_conventions.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/deprecated/001_semantics_aligned_memory_record_conventions.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/deprecated/003_bounded_graph_traversal_over_triples.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/deprecated/006_deterministic_anchor_and_facet_index.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/planned/extension_wave/README.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/planned/subconscious_wave/README.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0040_recurrence_probe_and_presentation_fold.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0041_loss_absence_anchors.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0042_explain_recall_serving_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0043_mind_health_report.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0044_origin_time_axis_for_imports.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0045_n_party_memory_contract.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0046_transcript_adoption_verb.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0047_cue_hygiene_at_recall_boundary.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/0048_writer_forensics_for_homes.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/extension_wave/README.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0012_lancedb_backend_hardening_and_explicit_schema.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0015_capabilities_extensions_and_deterministic_export_import.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0016_semantics_vocabulary_validation_and_aliasing_module.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/0028_lateral_inhibition_theory.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/backlog/proposed/memory_system_v1/README.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/development.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/docs/operator.md +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/examples/entity_home_maintenance_proof.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/examples/realistic_session.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/alive_drives.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/archive_import.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/attention.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/candidate_miner.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/canonical_text.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/channels.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/cognition_health.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/concept_anchor.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/consolidation.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/diary.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/disposal.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/doctoring.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/dream_resolution.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/dream_signals.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/drive_grouping.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/drive_pressure.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/embedding_pin.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/embeddings.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/embeddings_openai_compat.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/engine_manifest.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/engram.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/entity_card.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/feelings_reads.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/folds.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/gradation.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/identity_review.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/journal_common.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/journal_memory.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/maintenance.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/mind_mass.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/models.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/origin_diversity.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/probe.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/recall_reads.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/recent_records.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/reconstruct.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/records.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/redigestion.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/reembed.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/render_order.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/replay.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/seam.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/selection.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/self_component.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/shelf.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/situate.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/sleep_policy.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/spark.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/spreading.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/store.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/system.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/system_access.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/system_valence.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/tend.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/text_tokens.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/vector_scoring.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/world_model.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/src/abstractmemory/world_model_alias.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/conftest.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/golden/pre_identity_wave_result.json +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/realistic_fixtures.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_access_counts.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_alive_drives.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_anchored_summon.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_archive_import.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_attention.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_audit_wave.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_binding_visibility.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_candidate_miner.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_clean_owner_keys.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_close_assertion.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_co_use_trails.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_cognition_health.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_commitments.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_consolidation.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_disposal.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_doctoring.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_dream_resolution.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_dream_signals.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_drive_grouping.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_drive_pressure.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_embedding_pin.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_engine_manifest.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_engram.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_entity_card.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_explain_recall.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_familiarity.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_feelings_reads.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_gradation.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_home_lease_contract.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_identity_review.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_identity_self.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_in_memory_query_text_fallback.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_journal_backends.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_keyword_fts.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_lancedb_triple_store.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_lessons_layer.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_maintenance.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_mind_mass.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_origin_diversity.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_participants_channel.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_phase_artifact_pin.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_probe.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_realistic_lmstudio.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_recall_reads.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_recent_records.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_reconstruct.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_records.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_redigestion.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_render_order.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_replay.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_replay_idempotency.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_review_wave.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_seam_addendum.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_seam_contracts.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_situate.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_spark.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_spreading.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_sqlite_triple_store.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_stm_union.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_store_vectors.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_system.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_tend.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_term_canonicalization.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_triple_store_limits.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_two_sided_visit_contract.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_valence_gradation.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_world_model.py +0 -0
- {abstractmemory-0.3.2 → abstractmemory-0.4.0}/tests/test_world_model_alias.py +0 -0
|
@@ -5,9 +5,154 @@ 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
|
-
##
|
|
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
|
-
|
|
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`.
|
|
11
156
|
|
|
12
157
|
## [0.3.2] - 2026-10-20
|
|
13
158
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: AbstractMemory
|
|
3
|
-
Version: 0.
|
|
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/reinterpreted); 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/reinterpreted); 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).
|