memorymaster 3.24.0__tar.gz → 3.26.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 (411) hide show
  1. {memorymaster-3.24.0/memorymaster.egg-info → memorymaster-3.26.0}/PKG-INFO +2 -2
  2. {memorymaster-3.24.0 → memorymaster-3.26.0}/README.md +1 -1
  3. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/__init__.py +1 -1
  4. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/contradiction_probe.py +76 -11
  5. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/query_cache.py +25 -1
  6. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/rule_miner.py +43 -3
  7. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/steward.py +9 -1
  8. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/verbatim_cleanup.py +12 -3
  9. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/verbatim_store.py +80 -56
  10. {memorymaster-3.24.0 → memorymaster-3.26.0/memorymaster.egg-info}/PKG-INFO +2 -2
  11. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster.egg-info/SOURCES.txt +12 -0
  12. {memorymaster-3.24.0 → memorymaster-3.26.0}/pyproject.toml +1 -1
  13. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/bench_longmemeval.py +3 -2
  14. memorymaster-3.26.0/tests/test_bench_answer_prompt.py +75 -0
  15. memorymaster-3.26.0/tests/test_cli_handlers_extra.py +308 -0
  16. memorymaster-3.26.0/tests/test_context_hook_extra.py +643 -0
  17. memorymaster-3.26.0/tests/test_contradiction_probe.py +313 -0
  18. memorymaster-3.26.0/tests/test_db_merge_extra.py +237 -0
  19. memorymaster-3.26.0/tests/test_dream_bridge_extra.py +229 -0
  20. memorymaster-3.26.0/tests/test_entity_registry_extra.py +271 -0
  21. memorymaster-3.26.0/tests/test_llm_provider_extra.py +673 -0
  22. memorymaster-3.26.0/tests/test_observability_extra.py +335 -0
  23. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_query_cache.py +39 -0
  24. memorymaster-3.26.0/tests/test_retrieval_extra.py +320 -0
  25. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_rule_miner.py +72 -4
  26. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_service_coverage.py +96 -1
  27. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_contradiction_phase.py +70 -0
  28. memorymaster-3.26.0/tests/test_storage_extra.py +154 -0
  29. memorymaster-3.26.0/tests/test_vault_linter_extra.py +290 -0
  30. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_verbatim_cleanup.py +80 -0
  31. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_verbatim_dedup.py +48 -0
  32. memorymaster-3.26.0/tests/test_wiki_engine_extra.py +410 -0
  33. memorymaster-3.24.0/tests/test_contradiction_probe.py +0 -153
  34. {memorymaster-3.24.0 → memorymaster-3.26.0}/LICENSE +0 -0
  35. {memorymaster-3.24.0 → memorymaster-3.26.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
  36. {memorymaster-3.24.0 → memorymaster-3.26.0}/benchmarks/longmemeval_runner.py +0 -0
  37. {memorymaster-3.24.0 → memorymaster-3.26.0}/benchmarks/longmemeval_vector_runner.py +0 -0
  38. {memorymaster-3.24.0 → memorymaster-3.26.0}/benchmarks/perf_smoke.py +0 -0
  39. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/__main__.py +0 -0
  40. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_lifecycle.py +0 -0
  41. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_read.py +0 -0
  42. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_schema.py +0 -0
  43. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_shared.py +0 -0
  44. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_sources.py +0 -0
  45. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/_storage_write_claims.py +0 -0
  46. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/access_control.py +0 -0
  47. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/action_exporters.py +0 -0
  48. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/action_extractor.py +0 -0
  49. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/atlas_claim_extractor.py +0 -0
  50. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/atlas_contract.py +0 -0
  51. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/auto_extractor.py +0 -0
  52. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/auto_resolver.py +0 -0
  53. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/candidate_dedupe.py +0 -0
  54. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/claim_edges.py +0 -0
  55. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/claim_verifier.py +0 -0
  56. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/cli.py +0 -0
  57. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/cli_handlers_basic.py +0 -0
  58. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/cli_handlers_curation.py +0 -0
  59. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/cli_helpers.py +0 -0
  60. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/closets.py +0 -0
  61. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config.py +0 -0
  62. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/claude-md-append.md +0 -0
  63. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
  64. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
  65. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
  66. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +0 -0
  67. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
  68. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
  69. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
  70. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
  71. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
  72. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/conflict_resolver.py +0 -0
  73. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/connectors/__init__.py +0 -0
  74. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/connectors/whatsapp.py +0 -0
  75. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/context_hook.py +0 -0
  76. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/context_optimizer.py +0 -0
  77. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/daily_notes.py +0 -0
  78. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/dashboard.py +0 -0
  79. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/dashboard_auth.py +0 -0
  80. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/db_merge.py +0 -0
  81. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/delta_sync.py +0 -0
  82. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/dream_bridge.py +0 -0
  83. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/embeddings.py +0 -0
  84. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/entity_extractor.py +0 -0
  85. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/entity_graph.py +0 -0
  86. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/entity_registry.py +0 -0
  87. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/federated_graphify.py +0 -0
  88. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/feedback.py +0 -0
  89. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/graph_store.py +0 -0
  90. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/hook_log.py +0 -0
  91. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/__init__.py +0 -0
  92. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/calibration.py +0 -0
  93. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/compact_summaries.py +0 -0
  94. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/compactor.py +0 -0
  95. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/daydream_ingest.py +0 -0
  96. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/decay.py +0 -0
  97. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/dedup.py +0 -0
  98. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/deterministic.py +0 -0
  99. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/entity_graph_export.py +0 -0
  100. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/extractor.py +0 -0
  101. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/staleness.py +0 -0
  102. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/jobs/validator.py +0 -0
  103. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/key_rotator.py +0 -0
  104. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/lifecycle.py +0 -0
  105. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/llm_budget.py +0 -0
  106. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/llm_provider.py +0 -0
  107. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/llm_rerank.py +0 -0
  108. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/llm_steward.py +0 -0
  109. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/mcp_path_policy.py +0 -0
  110. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/mcp_server.py +0 -0
  111. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/mcp_usage.py +0 -0
  112. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/media_processing.py +0 -0
  113. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/media_providers.py +0 -0
  114. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/metrics_exporter.py +0 -0
  115. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/0001_initial.py +0 -0
  116. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/0002_miner_state.py +0 -0
  117. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/0003_contradiction_verdicts.py +0 -0
  118. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/0004_query_cache.py +0 -0
  119. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/__init__.py +0 -0
  120. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/migrations/runner.py +0 -0
  121. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/models.py +0 -0
  122. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/observability.py +0 -0
  123. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/operator.py +0 -0
  124. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/operator_queue.py +0 -0
  125. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/plugins.py +0 -0
  126. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/policy.py +0 -0
  127. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/postgres_store.py +0 -0
  128. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/qdrant_backend.py +0 -0
  129. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/qdrant_recall_fallback.py +0 -0
  130. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/qmd_bridge.py +0 -0
  131. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/query_classifier.py +0 -0
  132. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/query_expansion.py +0 -0
  133. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/recall_fusion.py +0 -0
  134. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/recall_tokenizer.py +0 -0
  135. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/retrieval.py +0 -0
  136. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/retry.py +0 -0
  137. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/review.py +0 -0
  138. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/rl_trainer.py +0 -0
  139. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/rules.py +0 -0
  140. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/scheduler.py +0 -0
  141. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/schema.py +0 -0
  142. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/schema.sql +0 -0
  143. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/schema_postgres.sql +0 -0
  144. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/scope_utils.py +0 -0
  145. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/security.py +0 -0
  146. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/service.py +0 -0
  147. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/session_tracker.py +0 -0
  148. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/setup_hooks.py +0 -0
  149. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/skill_evolver.py +0 -0
  150. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/snapshot.py +0 -0
  151. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/steward_classifier.py +0 -0
  152. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/steward_features.py +0 -0
  153. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/storage.py +0 -0
  154. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/store_factory.py +0 -0
  155. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/transcript_miner.py +0 -0
  156. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/turn_schema.py +0 -0
  157. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_bases.py +0 -0
  158. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_curator.py +0 -0
  159. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_exporter.py +0 -0
  160. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_linter.py +0 -0
  161. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_log.py +0 -0
  162. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_query_capture.py +0 -0
  163. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/vault_synthesis.py +0 -0
  164. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/verbatim_recall.py +0 -0
  165. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/webhook.py +0 -0
  166. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/wiki_engine.py +0 -0
  167. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/wiki_freshness.py +0 -0
  168. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/wiki_similarity.py +0 -0
  169. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/wiki_suggest.py +0 -0
  170. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster/wiki_validate.py +0 -0
  171. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster.egg-info/dependency_links.txt +0 -0
  172. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster.egg-info/entry_points.txt +0 -0
  173. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster.egg-info/requires.txt +0 -0
  174. {memorymaster-3.24.0 → memorymaster-3.26.0}/memorymaster.egg-info/top_level.txt +0 -0
  175. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/agg_recall_latency.py +0 -0
  176. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/alert_operator_metrics.py +0 -0
  177. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/audit_dedupe_precision.py +0 -0
  178. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/autoresearch_daemon.py +0 -0
  179. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/backfill_entity_extraction.py +0 -0
  180. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/backfill_graph_store.py +0 -0
  181. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/backfill_stop_hook_citations.py +0 -0
  182. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/backtest_steward_classifier.py +0 -0
  183. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/build_steward_training_set.py +0 -0
  184. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/check_hook_template_drift.py +0 -0
  185. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/claude_to_turns.py +0 -0
  186. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/codex_live_to_turns.py +0 -0
  187. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/compaction_edge_cases.py +0 -0
  188. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/compaction_trace_report.py +0 -0
  189. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/compaction_trace_validate.py +0 -0
  190. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/confusion_matrix_eval.py +0 -0
  191. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/conversation_importer.py +0 -0
  192. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/conversation_to_turns.py +0 -0
  193. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/e2e_operator.py +0 -0
  194. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/email_live_to_turns.py +0 -0
  195. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_bm25_sweep.py +0 -0
  196. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_classify_f1.py +0 -0
  197. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_memorymaster.py +0 -0
  198. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_recall_precision_at_5.py +0 -0
  199. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_recall_quality.py +0 -0
  200. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_steward_pareto.py +0 -0
  201. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/eval_verbatim_recall.py +0 -0
  202. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/expand_recall_eval.py +0 -0
  203. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/generate_drill_signoff.py +0 -0
  204. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/git_to_turns.py +0 -0
  205. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/github_live_to_turns.py +0 -0
  206. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/gitnexus_to_claims.py +0 -0
  207. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/grid_recall_weights.py +0 -0
  208. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/index_claims_to_qdrant.py +0 -0
  209. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/ingest_planning_docs.py +0 -0
  210. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/jira_live_to_turns.py +0 -0
  211. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/label_prompts_with_judge.py +0 -0
  212. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/llm_benchmark.py +0 -0
  213. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/measure_dedupe_thresholds.py +0 -0
  214. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/merge_scope_variants.py +0 -0
  215. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/messages_to_turns.py +0 -0
  216. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/operator_metrics.py +0 -0
  217. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/precompute_candidates.py +0 -0
  218. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/recurring_incident_drill.py +0 -0
  219. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/release_readiness.py +0 -0
  220. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/run_codex_autologger.py +0 -0
  221. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/run_incident_drill.py +0 -0
  222. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/scheduled_ingest.py +0 -0
  223. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/setup-hooks.py +0 -0
  224. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/slack_live_to_turns.py +0 -0
  225. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/sync_hook_templates.py +0 -0
  226. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/tickets_to_turns.py +0 -0
  227. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/train_steward_classifier.py +0 -0
  228. {memorymaster-3.24.0 → memorymaster-3.26.0}/scripts/webhook_to_turns.py +0 -0
  229. {memorymaster-3.24.0 → memorymaster-3.26.0}/setup.cfg +0 -0
  230. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/conftest.py +0 -0
  231. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
  232. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_access_control.py +0 -0
  233. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_action_exporters.py +0 -0
  234. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_action_extractor.py +0 -0
  235. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_atlas_claim_extractor.py +0 -0
  236. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_atlas_contract.py +0 -0
  237. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_atlas_source_schema.py +0 -0
  238. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_auto_extractor.py +0 -0
  239. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_auto_ingest_hook_citations.py +0 -0
  240. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_auto_ingest_hook_schema.py +0 -0
  241. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_auto_resolver.py +0 -0
  242. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_auto_validate.py +0 -0
  243. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_backend_parity.py +0 -0
  244. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_bm25_per_field.py +0 -0
  245. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_calibration.py +0 -0
  246. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_calibration_priors_applied.py +0 -0
  247. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_candidate_dedupe.py +0 -0
  248. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_claim_edges.py +0 -0
  249. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_claim_links.py +0 -0
  250. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_claim_type_ranking.py +0 -0
  251. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_classify_hook_f1.py +0 -0
  252. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_classify_hook_latency.py +0 -0
  253. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_claude_to_turns.py +0 -0
  254. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_cli_dry_run.py +0 -0
  255. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_cli_json_flag.py +0 -0
  256. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_cli_ready.py +0 -0
  257. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_cli_review_queue.py +0 -0
  258. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_cli_subcommands.py +0 -0
  259. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_closets.py +0 -0
  260. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_closets_recall_integration.py +0 -0
  261. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_compact_summaries.py +0 -0
  262. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_compact_summaries_sensitivity.py +0 -0
  263. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_compaction_trace.py +0 -0
  264. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_compactor_artifact_order.py +0 -0
  265. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_config.py +0 -0
  266. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_conflict_resolver.py +0 -0
  267. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_confusion_matrix_eval.py +0 -0
  268. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_connection_retry.py +0 -0
  269. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_connectors.py +0 -0
  270. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_context_hook.py +0 -0
  271. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_context_optimizer.py +0 -0
  272. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_context_optimizer_provider.py +0 -0
  273. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_conversation_to_turns.py +0 -0
  274. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard.py +0 -0
  275. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard_auth.py +0 -0
  276. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard_coverage.py +0 -0
  277. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard_latency.py +0 -0
  278. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard_lineage.py +0 -0
  279. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dashboard_review_queue.py +0 -0
  280. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_daydream_ingest.py +0 -0
  281. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_db_merge_confidence_conflict.py +0 -0
  282. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_db_merge_coverage_v2.py +0 -0
  283. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_decay_coverage.py +0 -0
  284. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_decay_respects_pinned.py +0 -0
  285. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dedup.py +0 -0
  286. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dedup_cli.py +0 -0
  287. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dedup_conflict_disambiguation.py +0 -0
  288. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_delta_sync.py +0 -0
  289. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_deterministic_predicates.py +0 -0
  290. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dream_bridge_coverage_v2.py +0 -0
  291. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_dream_bridge_sensitivity.py +0 -0
  292. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_embeddings_coverage.py +0 -0
  293. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_extractor.py +0 -0
  294. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_extractor_llm.py +0 -0
  295. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_graph.py +0 -0
  296. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_graph_export.py +0 -0
  297. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_new_kinds.py +0 -0
  298. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_regex_v3.py +0 -0
  299. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_entity_registry.py +0 -0
  300. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_eval_harness.py +0 -0
  301. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_events_schema.py +0 -0
  302. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_extract_llm_ollama.py +0 -0
  303. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_federated_graphify_mcp.py +0 -0
  304. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_federated_query_safety.py +0 -0
  305. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_feedback.py +0 -0
  306. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_floor_gate.py +0 -0
  307. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_fts5_search.py +0 -0
  308. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_graph_distance.py +0 -0
  309. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_graph_store.py +0 -0
  310. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_handler_regressions.py +0 -0
  311. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_hook_env_isolation.py +0 -0
  312. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_human_id.py +0 -0
  313. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_incident_drill_runner.py +0 -0
  314. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_integration_workflows.py +0 -0
  315. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_key_rotator.py +0 -0
  316. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_lifecycle.py +0 -0
  317. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_lifecycle_supersede_invariant.py +0 -0
  318. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_budget.py +0 -0
  319. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_fallback.py +0 -0
  320. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_provider_claude_cli.py +0 -0
  321. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_provider_key_rotation.py +0 -0
  322. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_steward_coverage.py +0 -0
  323. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_llm_steward_key_rotation.py +0 -0
  324. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_filter_bypass.py +0 -0
  325. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_helpers.py +0 -0
  326. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_path_policy.py +0 -0
  327. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_rate_limit.py +0 -0
  328. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_server_validation.py +0 -0
  329. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_mcp_usage.py +0 -0
  330. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_media_processing.py +0 -0
  331. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_meta_decisions.py +0 -0
  332. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_metrics_exporter.py +0 -0
  333. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_migrations.py +0 -0
  334. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_observability.py +0 -0
  335. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_obsidian_mind_patterns.py +0 -0
  336. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_operator.py +0 -0
  337. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_operator_queue.py +0 -0
  338. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_perf_smoke_config.py +0 -0
  339. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_plugins.py +0 -0
  340. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_policy_coverage.py +0 -0
  341. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_policy_mode_env.py +0 -0
  342. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_postgres_parity.py +0 -0
  343. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_qdrant_backend.py +0 -0
  344. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_qmd_bridge.py +0 -0
  345. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_qrels_regression.py +0 -0
  346. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_query_classifier.py +0 -0
  347. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_query_expansion.py +0 -0
  348. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_entity_fanout.py +0 -0
  349. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_fusion.py +0 -0
  350. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_latency.py +0 -0
  351. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_precision_at_5.py +0 -0
  352. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_tokenizer.py +0 -0
  353. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_recall_vector_fallback.py +0 -0
  354. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_reliability_hardening.py +0 -0
  355. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_resolvers_concurrent_supersede.py +0 -0
  356. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_retrieval_profile.py +0 -0
  357. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_retrieval_profiles.py +0 -0
  358. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_retrieval_rrf_tiebreaker.py +0 -0
  359. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_retrieval_weights.py +0 -0
  360. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_review.py +0 -0
  361. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_rl_trainer.py +0 -0
  362. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_rrf_auto_gate.py +0 -0
  363. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_rule_claims.py +0 -0
  364. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_scheduler.py +0 -0
  365. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_schema.py +0 -0
  366. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_scope_boost.py +0 -0
  367. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_scope_utils.py +0 -0
  368. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_security_access.py +0 -0
  369. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_security_patterns.py +0 -0
  370. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
  371. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
  372. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_sensitivity_filter_t07.py +0 -0
  373. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_session_tracker.py +0 -0
  374. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_snapshot.py +0 -0
  375. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_snapshot_roundtrip.py +0 -0
  376. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_sqlite_core.py +0 -0
  377. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_staleness.py +0 -0
  378. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_stealth_mode.py +0 -0
  379. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward.py +0 -0
  380. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_classifier.py +0 -0
  381. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_daydream_hook.py +0 -0
  382. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_features.py +0 -0
  383. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_features_v3.py +0 -0
  384. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_steward_resolution_parity.py +0 -0
  385. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_storage_parity.py +0 -0
  386. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_store_factory.py +0 -0
  387. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_tenant_isolation.py +0 -0
  388. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_turn_schema.py +0 -0
  389. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_two_pass_recall.py +0 -0
  390. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_v311_fixes.py +0 -0
  391. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_v313_e2e.py +0 -0
  392. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
  393. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_v390_e2e.py +0 -0
  394. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_v391_strict_warnings.py +0 -0
  395. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_vault_exporter.py +0 -0
  396. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_vault_linter_orphan.py +0 -0
  397. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_vector_search.py +0 -0
  398. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_verbatim_recall.py +0 -0
  399. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_verbatim_store.py +0 -0
  400. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_verbatim_store_qdrant.py +0 -0
  401. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_webhook.py +0 -0
  402. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_webhook_hmac.py +0 -0
  403. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_whatsapp_importer.py +0 -0
  404. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_autopromote.py +0 -0
  405. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_binding.py +0 -0
  406. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_engine_idempotency.py +0 -0
  407. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
  408. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_freshness.py +0 -0
  409. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_similarity_multiscope.py +0 -0
  410. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_suggest.py +0 -0
  411. {memorymaster-3.24.0 → memorymaster-3.26.0}/tests/test_wiki_validate_cli.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memorymaster
3
- Version: 3.24.0
3
+ Version: 3.26.0
4
4
  Summary: Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration.
5
5
  Author: wolverin0
6
6
  License: MIT
@@ -52,7 +52,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
52
52
 
53
53
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
54
54
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
55
- [![Tests](https://img.shields.io/badge/tests-2230-green.svg)]()
55
+ [![Tests](https://img.shields.io/badge/tests-2514-green.svg)]()
56
56
  [![MCP Tools](https://img.shields.io/badge/MCP%20tools-24-purple.svg)]()
57
57
  [![CLI Commands](https://img.shields.io/badge/CLI%20commands-86-orange.svg)]()
58
58
  [![PyPI](https://img.shields.io/pypi/v/memorymaster.svg)](https://pypi.org/project/memorymaster/)
@@ -6,7 +6,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
6
6
 
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
8
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
9
- [![Tests](https://img.shields.io/badge/tests-2230-green.svg)]()
9
+ [![Tests](https://img.shields.io/badge/tests-2514-green.svg)]()
10
10
  [![MCP Tools](https://img.shields.io/badge/MCP%20tools-24-purple.svg)]()
11
11
  [![CLI Commands](https://img.shields.io/badge/CLI%20commands-86-orange.svg)]()
12
12
  [![PyPI](https://img.shields.io/pypi/v/memorymaster.svg)](https://pypi.org/project/memorymaster/)
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "3.24.0"
5
+ __version__ = "3.26.0"
@@ -77,9 +77,23 @@ def _canonical_pair(a_id: int, b_id: int) -> tuple[int, int]:
77
77
  return (a_id, b_id) if a_id <= b_id else (b_id, a_id)
78
78
 
79
79
 
80
- def _ensure_verdict_table(conn: sqlite3.Connection) -> None:
80
+ _ensured_verdict_dbs: set[str] = set()
81
+
82
+
83
+ def _ensure_verdict_table(conn: sqlite3.Connection, *, db_key: str | None = None) -> None:
84
+ """Create the verdict cache table if absent.
85
+
86
+ ``db_key`` lets per-claim callers skip the redundant ``CREATE TABLE IF NOT
87
+ EXISTS`` + ``commit`` on every claim in a steward cycle: once a given DB has
88
+ been ensured in this process we never re-issue the DDL. ``run_probe`` (one
89
+ DDL per whole run) passes no key and always ensures, preserving its semantics.
90
+ """
91
+ if db_key is not None and db_key in _ensured_verdict_dbs:
92
+ return
81
93
  conn.execute(_VERDICT_DDL)
82
94
  conn.commit()
95
+ if db_key is not None:
96
+ _ensured_verdict_dbs.add(db_key)
83
97
 
84
98
 
85
99
  def _cache_get(conn: sqlite3.Connection, a_id: int, b_id: int, model: str) -> dict | None:
@@ -164,13 +178,23 @@ def sample_candidate_pairs(
164
178
  return []
165
179
  embeddings = [provider.embed(_embed_text(c)) for c in usable]
166
180
  pairs: list[tuple[Claim, Claim, float]] = []
181
+ # The cosine sweep is O(n^2). Once we have already collected ``limit`` in-band
182
+ # pairs there is no point paying for the rest of the quadratic scan — the
183
+ # caller only ever consumes the first ``limit`` after the sort below, so break
184
+ # early instead of building (then discarding) thousands of extra pairs.
185
+ done = False
167
186
  for i in range(len(usable)):
187
+ if done:
188
+ break
168
189
  for j in range(i + 1, len(usable)):
169
190
  if _prefiltered(usable[i], usable[j]):
170
191
  continue
171
192
  sim = cosine_similarity(embeddings[i], embeddings[j])
172
193
  if sim_low <= sim < sim_high:
173
194
  pairs.append((usable[i], usable[j], round(sim, 4)))
195
+ if limit is not None and len(pairs) >= limit:
196
+ done = True
197
+ break
174
198
  pairs.sort(key=lambda p: -p[2])
175
199
  if limit is not None:
176
200
  pairs = pairs[:limit]
@@ -193,7 +217,11 @@ def _judge_llm(a: Claim, b: Claim) -> dict | None:
193
217
  if isinstance(item, dict) and "contradicts" in item:
194
218
  return {
195
219
  "contradicts": bool(item.get("contradicts")),
196
- "severity": (item.get("severity") or "low").strip().lower(),
220
+ # Floor empty/off-vocabulary severity to "medium" at the source
221
+ # (the JSON contract is advisory). Defaulting to "low" here would
222
+ # silently bury a real contradiction in the least-actionable tier
223
+ # and made the "medium" default downstream dead code.
224
+ "severity": _coerce_severity(item.get("severity")),
197
225
  "reason": (item.get("reason") or "").strip(),
198
226
  "cached": False,
199
227
  }
@@ -206,6 +234,36 @@ def _model_key() -> str:
206
234
  return f"{provider}:{model}"
207
235
 
208
236
 
237
+ _VALID_SEVERITIES = {"low", "medium", "high"}
238
+
239
+
240
+ def _coerce_severity(value: Any) -> str:
241
+ """Normalize a verdict severity to a canonical bucket.
242
+
243
+ The LLM judge and verdict cache can both yield an empty or off-vocabulary
244
+ severity (the JSON contract is advisory, not enforced). When that happens we
245
+ floor to ``"medium"`` rather than ``"low"`` so a contradiction surfaced by
246
+ the probe is never silently downgraded to the least-actionable tier.
247
+ """
248
+ sev = str(value or "").strip().lower()
249
+ return sev if sev in _VALID_SEVERITIES else "medium"
250
+
251
+
252
+ def _safe_judge_reason(reason: Any) -> str | None:
253
+ """Return the raw judge reason unless it leaks sensitive content.
254
+
255
+ Both ``probe_for_claim`` and ``run_probe(apply=True)`` persist/surface the
256
+ LLM judge reason. Routing both through this guard ensures a reason that the
257
+ sensitivity filter flags is dropped (returns ``None``) on EVERY path — the
258
+ events table must never receive an unredacted secret.
259
+ """
260
+ text = str(reason or "")
261
+ _, leaks = redact_text(text)
262
+ if leaks:
263
+ return None
264
+ return text
265
+
266
+
209
267
  # ---------------------------------------------------------------------------
210
268
  # Wilson confidence interval
211
269
  # ---------------------------------------------------------------------------
@@ -303,15 +361,19 @@ def run_probe(
303
361
  if verdict["contradicts"]:
304
362
  stats["contradictions"] += 1
305
363
  loser, winner = (a, b) if a.confidence <= b.confidence else (b, a)
364
+ # Same sensitivity guard the per-claim path uses: never let an
365
+ # unredacted judge reason reach the events table on apply.
366
+ safe_reason = _safe_judge_reason(verdict.get("reason"))
306
367
  stats["found"].append({
307
368
  "claim_a_id": a.id, "claim_b_id": b.id, "similarity": sim,
308
- "severity": verdict["severity"], "reason": verdict["reason"],
369
+ "severity": verdict["severity"], "reason": verdict.get("reason", ""),
309
370
  "flag_candidate_id": loser.id,
310
371
  })
311
372
  if apply:
373
+ detail = f" ({safe_reason})" if safe_reason else ""
312
374
  transition_claim(
313
375
  service.store, loser.id, "conflicted",
314
- reason=f"contradiction_probe: contradicts claim {winner.id} ({verdict['reason']})",
376
+ reason=f"contradiction_probe: contradicts claim {winner.id}{detail}",
315
377
  event_type="transition",
316
378
  )
317
379
  stats["flagged_conflicted"] += 1
@@ -357,7 +419,7 @@ def probe_for_claim(
357
419
  metrics: dict[str, Any] = {
358
420
  "pairs_checked": 0, "contradictions": 0,
359
421
  "cache_hits": 0, "llm_calls": 0, "errors": 0,
360
- "timed_out": False, "duration_ms": 0.0,
422
+ "timed_out": False, "budget_exhausted": False, "duration_ms": 0.0,
361
423
  }
362
424
  reasons: list[dict[str, Any]] = []
363
425
 
@@ -415,7 +477,7 @@ def probe_for_claim(
415
477
 
416
478
  conn = sqlite3.connect(str(db_path))
417
479
  try:
418
- _ensure_verdict_table(conn)
480
+ _ensure_verdict_table(conn, db_key=str(db_path))
419
481
  model = _model_key()
420
482
  for peer, sim in candidates:
421
483
  metrics["pairs_checked"] += 1
@@ -426,7 +488,11 @@ def probe_for_claim(
426
488
  try:
427
489
  verdict = _judge_llm(claim, peer)
428
490
  except llm_budget.LLMBudgetExceeded:
429
- metrics["timed_out"] = True
491
+ # Budget exhaustion is an expected guardrail, NOT a probe
492
+ # failure — the steward must not count it toward the circuit
493
+ # breaker (which would disable the probe for the rest of the
494
+ # cycle). Flag it distinctly from a genuine timeout.
495
+ metrics["budget_exhausted"] = True
430
496
  break
431
497
  metrics["llm_calls"] += 1
432
498
  if verdict is None:
@@ -435,14 +501,13 @@ def probe_for_claim(
435
501
  _cache_put(conn, claim.id, peer.id, model, verdict)
436
502
  if not verdict.get("contradicts"):
437
503
  continue
438
- verdict_reason = verdict.get("reason", "")
439
- _, leaks = redact_text(verdict_reason)
440
- if leaks:
504
+ verdict_reason = _safe_judge_reason(verdict.get("reason"))
505
+ if verdict_reason is None:
441
506
  continue # drop rather than surface a sensitive judge-reason
442
507
  metrics["contradictions"] += 1
443
508
  reasons.append({
444
509
  "code": "contradiction_probe.semantic_pair",
445
- "severity": verdict.get("severity", "medium"),
510
+ "severity": _coerce_severity(verdict.get("severity")),
446
511
  "detail": f"Semantic contradiction with claim {peer.id}: {verdict_reason}",
447
512
  "evidence": {
448
513
  "peer_claim_id": int(peer.id),
@@ -116,7 +116,14 @@ def read(db_path: str, cache_key: str) -> list[dict] | None:
116
116
  "SELECT result_json, generation FROM query_cache WHERE cache_key = ?",
117
117
  (cache_key,),
118
118
  ).fetchone()
119
- if row is None or int(row["generation"]) != gen:
119
+ if row is None:
120
+ return None
121
+ if int(row["generation"]) != gen:
122
+ try:
123
+ conn.execute("DELETE FROM query_cache WHERE cache_key = ?", (cache_key,))
124
+ conn.commit()
125
+ except sqlite3.Error:
126
+ pass
120
127
  return None
121
128
  return json.loads(row["result_json"])
122
129
  except (sqlite3.Error, json.JSONDecodeError, ValueError) as exc:
@@ -126,6 +133,23 @@ def read(db_path: str, cache_key: str) -> list[dict] | None:
126
133
  conn.close()
127
134
 
128
135
 
136
+ def evict_stale(db_path: str) -> None:
137
+ """Delete query cache rows older than the current corpus generation."""
138
+ try:
139
+ conn = _connect(db_path)
140
+ except sqlite3.Error as exc:
141
+ logger.warning("query_cache.evict_stale connect failed: %s", exc)
142
+ return
143
+ try:
144
+ gen = current_generation(conn)
145
+ conn.execute("DELETE FROM query_cache WHERE generation < ?", (gen,))
146
+ conn.commit()
147
+ except (sqlite3.Error, ValueError) as exc:
148
+ logger.warning("query_cache.evict_stale failed: %s", exc)
149
+ finally:
150
+ conn.close()
151
+
152
+
129
153
  def write(db_path: str, cache_key: str, stub_rows: list[dict], generation: int) -> None:
130
154
  """Store result stubs tagged with ``generation``. Best-effort.
131
155
 
@@ -48,6 +48,11 @@ _CORRECTION_KEYWORDS = (
48
48
  "wrong", "not what", "that's not", "thats not", "revert", "undo",
49
49
  "should have", "shouldn't", "why did you", "no need", "stop ",
50
50
  )
51
+ _CORRECTION_FTS_MATCH = (
52
+ '"no" OR "don" OR "do" OR "dont" OR "instead" OR "actually" OR '
53
+ '"wrong" OR "not" OR "revert" OR "undo" OR "should" OR "shouldn" OR '
54
+ '"why" OR "stop"'
55
+ )
51
56
 
52
57
  _MINER_STATE_DDL = """
53
58
  CREATE TABLE IF NOT EXISTS miner_state (
@@ -132,6 +137,18 @@ def _candidate_batch(
132
137
  params: list[Any] = [since_id]
133
138
  params.extend(f"%{kw}%" for kw in _CORRECTION_KEYWORDS)
134
139
  params.append(batch_size)
140
+ try:
141
+ return conn.execute(
142
+ f"""SELECT v.id, v.session_id, v.content, v.scope FROM verbatim_fts f
143
+ JOIN verbatim_memories v ON v.id = f.rowid
144
+ WHERE verbatim_fts MATCH ?
145
+ AND v.role = 'user' AND v.id > ? AND ({like_clause})
146
+ ORDER BY v.id ASC LIMIT ?""",
147
+ [_CORRECTION_FTS_MATCH, *params],
148
+ ).fetchall()
149
+ except sqlite3.Error as exc:
150
+ logger.debug("rule_miner: verbatim_fts pre-filter failed, using LIKE scan: %s", exc)
151
+
135
152
  return conn.execute(
136
153
  f"""SELECT id, session_id, content, scope FROM verbatim_memories
137
154
  WHERE role = 'user' AND id > ? AND ({like_clause})
@@ -158,12 +175,26 @@ def _build_window(assistant_content: str, user_content: str) -> str:
158
175
  return f"ASSISTANT: {asst}\nUSER: {user}"
159
176
 
160
177
 
178
+ class TransientLLMError(RuntimeError):
179
+ """The LLM provider returned an empty response — almost always a transient
180
+ failure (outage, timeout, rate-limit returning ''), NOT a genuine "no
181
+ correction" verdict. Callers must distinguish the two: advancing the
182
+ watermark past a candidate that was never actually judged would permanently
183
+ skip real corrections during a provider outage. (audit:
184
+ mine-rules-silent-watermark-advance)"""
185
+
186
+
161
187
  def _extract_rule(window: str) -> dict[str, str] | None:
162
188
  """Ask the LLM to distill a rule. Returns ``{trigger, action, rationale}``
163
- or ``None`` when there is no correction. May raise ``LLMBudgetExceeded``."""
189
+ or ``None`` when the model responded but found no correction.
190
+
191
+ Raises ``LLMBudgetExceeded`` if the per-cycle cap is hit, and
192
+ ``TransientLLMError`` if the provider returned nothing (so the caller can
193
+ avoid advancing the watermark). A non-empty response that simply doesn't
194
+ parse to a rule is a genuine "no correction" (``None``), not transient."""
164
195
  raw = llm_provider.call_llm(_CORRECTION_PROMPT, window)
165
196
  if not raw or not raw.strip():
166
- return None
197
+ raise TransientLLMError("empty LLM response")
167
198
  for item in llm_provider.parse_json_response(raw):
168
199
  if not isinstance(item, dict):
169
200
  continue
@@ -300,6 +331,12 @@ def _process_candidate(
300
331
  except llm_budget.LLMBudgetExceeded as exc:
301
332
  stats["aborted_reason"] = exc.reason
302
333
  return "aborted"
334
+ except TransientLLMError:
335
+ # Provider returned empty (likely transient outage). Abort the run WITHOUT
336
+ # advancing the watermark past this row, so the candidate is retried next
337
+ # run instead of silently skipped. Stopping is safe: mining is a batch job.
338
+ stats["aborted_reason"] = "llm_transient_failure"
339
+ return "aborted"
303
340
 
304
341
  stats["llm_calls"] += 1
305
342
  if rule is None or _is_sensitive_rule(rule):
@@ -412,7 +449,10 @@ def mine_transcript_rules(
412
449
  stats["windows"] += 1
413
450
  try:
414
451
  rule = _extract_rule(_build_window(asst_text, user_text))
415
- except llm_budget.LLMBudgetExceeded:
452
+ except (llm_budget.LLMBudgetExceeded, TransientLLMError):
453
+ # Budget hit or provider returned empty — stop this best-effort
454
+ # Stop-hook pass. No watermark here, so nothing to skip; a
455
+ # later session re-mines its own corrections.
416
456
  break
417
457
  stats["llm_calls"] += 1
418
458
  if rule is None or _is_sensitive_rule(rule):
@@ -9,7 +9,7 @@ import subprocess
9
9
  import time
10
10
  from typing import Any, Literal
11
11
 
12
- from memorymaster import observability
12
+ from memorymaster import llm_budget, observability
13
13
  from memorymaster.lifecycle import transition_claim
14
14
  from memorymaster.security import is_sensitive_claim
15
15
  from memorymaster.service import MemoryService
@@ -891,6 +891,14 @@ def _make_circuit_open_result(probe: ProbeSpec, probe_type: str, probe_failure_t
891
891
  )
892
892
 
893
893
 
894
+ # Open ONE per-cycle LLM budget scope for the whole cycle so
895
+ # MEMORYMASTER_MAX_LLM_CALLS_PER_CYCLE (and the token / provider-failure caps)
896
+ # apply across every LLM-using probe this cycle — notably the contradiction
897
+ # probe's judge. cycle_scope is a @contextmanager, so it doubles as a context
898
+ # decorator and recreates a fresh scope per call. Without this the cap was a
899
+ # no-op for the steward and probe_for_claim's LLMBudgetExceeded handler was dead
900
+ # in production. (audit: probe-for-claim-budget-no-scope)
901
+ @llm_budget.cycle_scope()
894
902
  def _run_cycle(
895
903
  service: MemoryService,
896
904
  *,
@@ -132,10 +132,19 @@ def cleanup(
132
132
 
133
133
  if dedup:
134
134
  # Identify ids to drop: for each (session_id, content) group, keep
135
- # the smallest id (oldest), drop the rest.
135
+ # the smallest id (oldest), drop the rest. NOT EXISTS against a
136
+ # correlated "is there an older twin?" probe avoids the O(n^2)
137
+ # full-table anti-join that `id NOT IN (SELECT MIN(id) ...)` forces
138
+ # SQLite into on the cold CLI path. Results are identical: a row is
139
+ # dropped iff another row in the same (session_id, content) group has
140
+ # a strictly smaller id.
136
141
  rows = conn.execute(
137
- """SELECT id FROM verbatim_memories WHERE id NOT IN (
138
- SELECT MIN(id) FROM verbatim_memories GROUP BY session_id, content
142
+ """SELECT id FROM verbatim_memories AS v
143
+ WHERE EXISTS (
144
+ SELECT 1 FROM verbatim_memories AS older
145
+ WHERE older.session_id IS v.session_id
146
+ AND older.content = v.content
147
+ AND older.id < v.id
139
148
  )"""
140
149
  ).fetchall()
141
150
  ids = [int(r[0]) for r in rows]
@@ -22,11 +22,11 @@ from datetime import datetime, timezone
22
22
  from pathlib import Path
23
23
  from typing import Any
24
24
 
25
+ # Credential detection delegated to the canonical filter in memorymaster.security.
26
+ from memorymaster.security import redact_text as _redact_text
27
+
25
28
  logger = logging.getLogger(__name__)
26
29
 
27
- # Credential detection delegated to the canonical filter in
28
- # memorymaster.security — single source of truth.
29
- from memorymaster.security import redact_text as _redact_text
30
30
 
31
31
 
32
32
  def _contains_sensitive(text: str) -> bool:
@@ -76,6 +76,33 @@ def store_verbatim(
76
76
  timestamp: str | None = None,
77
77
  ) -> int | None:
78
78
  """Store a verbatim conversation turn. Returns row ID or None if filtered."""
79
+ # closing() guarantees the connection (and its WAL write lock) is released
80
+ # even if an INSERT/commit raises (e.g. "database is locked" under
81
+ # concurrent MCP/Stop-hook writers) - this is the hottest write path.
82
+ with closing(_connect(db_path)) as conn:
83
+ row_id = _store_verbatim_conn(
84
+ conn,
85
+ session_id,
86
+ role,
87
+ content,
88
+ scope,
89
+ source_agent,
90
+ timestamp,
91
+ )
92
+ conn.commit()
93
+ return row_id
94
+
95
+
96
+ def _store_verbatim_conn(
97
+ conn: sqlite3.Connection,
98
+ session_id: str,
99
+ role: str,
100
+ content: str,
101
+ scope: str = "project",
102
+ source_agent: str = "",
103
+ timestamp: str | None = None,
104
+ ) -> int | None:
105
+ """Store one turn using an existing connection without committing."""
79
106
  if not content or len(content) < 20:
80
107
  return None
81
108
  if _row_has_sensitive_field(role or "", source_agent or "", content):
@@ -83,37 +110,32 @@ def store_verbatim(
83
110
 
84
111
  now = timestamp or datetime.now(timezone.utc).isoformat()
85
112
 
86
- # closing() guarantees the connection (and its WAL write lock) is released
87
- # even if an INSERT/commit raises (e.g. "database is locked" under
88
- # concurrent MCP/Stop-hook writers) this is the hottest write path.
89
- with closing(_connect(db_path)) as conn:
90
- # Dedup by exact content within the same session. Uses idx_verbatim_session
91
- # so the lookup is O(rows-in-session), not table-scan. The previous FTS5-based
92
- # dedup query passed a sha256 hex prefix to MATCH which never resolves —
93
- # the FTS5 index stores the content text, not its hash. Result: 9M+ rows
94
- # accumulated for orchestrator sessions because every Stop event re-inserted
95
- # every message. Fixed 2026-05-03; see mm-0c43.
96
- existing = conn.execute(
97
- "SELECT id FROM verbatim_memories WHERE session_id = ? AND content = ? LIMIT 1",
98
- (session_id, content),
99
- ).fetchone()
100
- if existing:
101
- return None
102
-
103
- cur = conn.execute(
104
- """INSERT INTO verbatim_memories (session_id, role, content, scope, timestamp, source_agent)
105
- VALUES (?, ?, ?, ?, ?, ?)""",
106
- (session_id, role, content, scope, now, source_agent),
107
- )
108
- row_id = cur.lastrowid
113
+ # Dedup by exact content within the same session. Uses idx_verbatim_session
114
+ # so the lookup is O(rows-in-session), not table-scan. The previous FTS5-based
115
+ # dedup query passed a sha256 hex prefix to MATCH which never resolves -
116
+ # the FTS5 index stores the content text, not its hash. Result: 9M+ rows
117
+ # accumulated for orchestrator sessions because every Stop event re-inserted
118
+ # every message. Fixed 2026-05-03; see mm-0c43.
119
+ existing = conn.execute(
120
+ "SELECT id FROM verbatim_memories WHERE session_id = ? AND content = ? LIMIT 1",
121
+ (session_id, content),
122
+ ).fetchone()
123
+ if existing:
124
+ return None
109
125
 
110
- # Update FTS
111
- conn.execute(
112
- "INSERT INTO verbatim_fts(rowid, content) VALUES (?, ?)",
113
- (row_id, content),
114
- )
115
- conn.commit()
116
- return row_id
126
+ cur = conn.execute(
127
+ """INSERT INTO verbatim_memories (session_id, role, content, scope, timestamp, source_agent)
128
+ VALUES (?, ?, ?, ?, ?, ?)""",
129
+ (session_id, role, content, scope, now, source_agent),
130
+ )
131
+ row_id = cur.lastrowid
132
+
133
+ # Update FTS
134
+ conn.execute(
135
+ "INSERT INTO verbatim_fts(rowid, content) VALUES (?, ?)",
136
+ (row_id, content),
137
+ )
138
+ return row_id
117
139
 
118
140
 
119
141
  def _extract_role_content(entry: dict) -> tuple[str, str]:
@@ -164,29 +186,31 @@ def store_transcript(
164
186
  stats = {"stored": 0, "skipped": 0}
165
187
  session_id = path.stem # Use filename as session ID
166
188
 
167
- for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
168
- if not line.strip():
169
- continue
170
- try:
171
- entry = json.loads(line)
172
- except json.JSONDecodeError:
173
- continue
174
- if not isinstance(entry, dict):
175
- continue
176
-
177
- role, content = _extract_role_content(entry)
178
- if role not in ("user", "assistant"):
179
- stats["skipped"] += 1
180
- continue
181
- if not content or len(content) < 20:
182
- stats["skipped"] += 1
183
- continue
184
-
185
- row_id = store_verbatim(db_path, session_id, role, content, scope, source_agent)
186
- if row_id:
187
- stats["stored"] += 1
188
- else:
189
- stats["skipped"] += 1
189
+ with closing(_connect(db_path)) as conn:
190
+ for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
191
+ if not line.strip():
192
+ continue
193
+ try:
194
+ entry = json.loads(line)
195
+ except json.JSONDecodeError:
196
+ continue
197
+ if not isinstance(entry, dict):
198
+ continue
199
+
200
+ role, content = _extract_role_content(entry)
201
+ if role not in ("user", "assistant"):
202
+ stats["skipped"] += 1
203
+ continue
204
+ if not content or len(content) < 20:
205
+ stats["skipped"] += 1
206
+ continue
207
+
208
+ row_id = _store_verbatim_conn(conn, session_id, role, content, scope, source_agent)
209
+ if row_id:
210
+ stats["stored"] += 1
211
+ else:
212
+ stats["skipped"] += 1
213
+ conn.commit()
190
214
 
191
215
  return stats
192
216
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memorymaster
3
- Version: 3.24.0
3
+ Version: 3.26.0
4
4
  Summary: Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration.
5
5
  Author: wolverin0
6
6
  License: MIT
@@ -52,7 +52,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
52
52
 
53
53
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
54
54
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
55
- [![Tests](https://img.shields.io/badge/tests-2230-green.svg)]()
55
+ [![Tests](https://img.shields.io/badge/tests-2514-green.svg)]()
56
56
  [![MCP Tools](https://img.shields.io/badge/MCP%20tools-24-purple.svg)]()
57
57
  [![CLI Commands](https://img.shields.io/badge/CLI%20commands-86-orange.svg)]()
58
58
  [![PyPI](https://img.shields.io/pypi/v/memorymaster.svg)](https://pypi.org/project/memorymaster/)
@@ -218,6 +218,7 @@ tests/test_auto_ingest_hook_schema.py
218
218
  tests/test_auto_resolver.py
219
219
  tests/test_auto_validate.py
220
220
  tests/test_backend_parity.py
221
+ tests/test_bench_answer_prompt.py
221
222
  tests/test_bm25_per_field.py
222
223
  tests/test_calibration.py
223
224
  tests/test_calibration_priors_applied.py
@@ -229,6 +230,7 @@ tests/test_classify_hook_f1.py
229
230
  tests/test_classify_hook_latency.py
230
231
  tests/test_claude_to_turns.py
231
232
  tests/test_cli_dry_run.py
233
+ tests/test_cli_handlers_extra.py
232
234
  tests/test_cli_json_flag.py
233
235
  tests/test_cli_ready.py
234
236
  tests/test_cli_review_queue.py
@@ -245,6 +247,7 @@ tests/test_confusion_matrix_eval.py
245
247
  tests/test_connection_retry.py
246
248
  tests/test_connectors.py
247
249
  tests/test_context_hook.py
250
+ tests/test_context_hook_extra.py
248
251
  tests/test_context_optimizer.py
249
252
  tests/test_context_optimizer_provider.py
250
253
  tests/test_contradiction_probe.py
@@ -258,6 +261,7 @@ tests/test_dashboard_review_queue.py
258
261
  tests/test_daydream_ingest.py
259
262
  tests/test_db_merge_confidence_conflict.py
260
263
  tests/test_db_merge_coverage_v2.py
264
+ tests/test_db_merge_extra.py
261
265
  tests/test_decay_coverage.py
262
266
  tests/test_decay_respects_pinned.py
263
267
  tests/test_dedup.py
@@ -266,6 +270,7 @@ tests/test_dedup_conflict_disambiguation.py
266
270
  tests/test_delta_sync.py
267
271
  tests/test_deterministic_predicates.py
268
272
  tests/test_dream_bridge_coverage_v2.py
273
+ tests/test_dream_bridge_extra.py
269
274
  tests/test_dream_bridge_sensitivity.py
270
275
  tests/test_embeddings_coverage.py
271
276
  tests/test_entity_extractor.py
@@ -275,6 +280,7 @@ tests/test_entity_graph_export.py
275
280
  tests/test_entity_new_kinds.py
276
281
  tests/test_entity_regex_v3.py
277
282
  tests/test_entity_registry.py
283
+ tests/test_entity_registry_extra.py
278
284
  tests/test_eval_harness.py
279
285
  tests/test_events_schema.py
280
286
  tests/test_extract_llm_ollama.py
@@ -296,6 +302,7 @@ tests/test_lifecycle_supersede_invariant.py
296
302
  tests/test_llm_budget.py
297
303
  tests/test_llm_fallback.py
298
304
  tests/test_llm_provider_claude_cli.py
305
+ tests/test_llm_provider_extra.py
299
306
  tests/test_llm_provider_key_rotation.py
300
307
  tests/test_llm_steward_coverage.py
301
308
  tests/test_llm_steward_key_rotation.py
@@ -310,6 +317,7 @@ tests/test_meta_decisions.py
310
317
  tests/test_metrics_exporter.py
311
318
  tests/test_migrations.py
312
319
  tests/test_observability.py
320
+ tests/test_observability_extra.py
313
321
  tests/test_obsidian_mind_patterns.py
314
322
  tests/test_operator.py
315
323
  tests/test_operator_queue.py
@@ -332,6 +340,7 @@ tests/test_recall_tokenizer.py
332
340
  tests/test_recall_vector_fallback.py
333
341
  tests/test_reliability_hardening.py
334
342
  tests/test_resolvers_concurrent_supersede.py
343
+ tests/test_retrieval_extra.py
335
344
  tests/test_retrieval_profile.py
336
345
  tests/test_retrieval_profiles.py
337
346
  tests/test_retrieval_rrf_tiebreaker.py
@@ -364,6 +373,7 @@ tests/test_steward_daydream_hook.py
364
373
  tests/test_steward_features.py
365
374
  tests/test_steward_features_v3.py
366
375
  tests/test_steward_resolution_parity.py
376
+ tests/test_storage_extra.py
367
377
  tests/test_storage_parity.py
368
378
  tests/test_store_factory.py
369
379
  tests/test_tenant_isolation.py
@@ -375,6 +385,7 @@ tests/test_v313_run_cycle_dedupe.py
375
385
  tests/test_v390_e2e.py
376
386
  tests/test_v391_strict_warnings.py
377
387
  tests/test_vault_exporter.py
388
+ tests/test_vault_linter_extra.py
378
389
  tests/test_vault_linter_orphan.py
379
390
  tests/test_vector_search.py
380
391
  tests/test_verbatim_cleanup.py
@@ -387,6 +398,7 @@ tests/test_webhook_hmac.py
387
398
  tests/test_whatsapp_importer.py
388
399
  tests/test_wiki_autopromote.py
389
400
  tests/test_wiki_binding.py
401
+ tests/test_wiki_engine_extra.py
390
402
  tests/test_wiki_engine_idempotency.py
391
403
  tests/test_wiki_explored_and_contradictions.py
392
404
  tests/test_wiki_freshness.py