memorymaster 3.23.0__tar.gz → 3.25.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 (399) hide show
  1. {memorymaster-3.23.0/memorymaster.egg-info → memorymaster-3.25.0}/PKG-INFO +2 -2
  2. {memorymaster-3.23.0 → memorymaster-3.25.0}/README.md +1 -1
  3. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/__init__.py +1 -1
  4. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +27 -31
  5. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/contradiction_probe.py +6 -2
  6. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_cache.py +40 -9
  7. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rule_miner.py +26 -3
  8. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/security.py +21 -0
  9. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/service.py +12 -1
  10. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward.py +9 -1
  11. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_store.py +142 -133
  12. {memorymaster-3.23.0 → memorymaster-3.25.0/memorymaster.egg-info}/PKG-INFO +2 -2
  13. {memorymaster-3.23.0 → memorymaster-3.25.0}/pyproject.toml +1 -1
  14. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/bench_longmemeval.py +42 -3
  15. memorymaster-3.25.0/tests/test_auto_ingest_hook_citations.py +102 -0
  16. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_cache.py +26 -0
  17. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rule_miner.py +21 -0
  18. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_t07.py +42 -1
  19. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_contradiction_phase.py +70 -0
  20. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_store_qdrant.py +28 -0
  21. memorymaster-3.23.0/tests/test_auto_ingest_hook_citations.py +0 -147
  22. {memorymaster-3.23.0 → memorymaster-3.25.0}/LICENSE +0 -0
  23. {memorymaster-3.23.0 → memorymaster-3.25.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
  24. {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/longmemeval_runner.py +0 -0
  25. {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/longmemeval_vector_runner.py +0 -0
  26. {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/perf_smoke.py +0 -0
  27. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/__main__.py +0 -0
  28. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_lifecycle.py +0 -0
  29. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_read.py +0 -0
  30. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_schema.py +0 -0
  31. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_shared.py +0 -0
  32. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_sources.py +0 -0
  33. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_write_claims.py +0 -0
  34. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/access_control.py +0 -0
  35. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/action_exporters.py +0 -0
  36. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/action_extractor.py +0 -0
  37. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/atlas_claim_extractor.py +0 -0
  38. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/atlas_contract.py +0 -0
  39. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/auto_extractor.py +0 -0
  40. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/auto_resolver.py +0 -0
  41. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/candidate_dedupe.py +0 -0
  42. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/claim_edges.py +0 -0
  43. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/claim_verifier.py +0 -0
  44. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli.py +0 -0
  45. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_handlers_basic.py +0 -0
  46. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_handlers_curation.py +0 -0
  47. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_helpers.py +0 -0
  48. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/closets.py +0 -0
  49. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config.py +0 -0
  50. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/claude-md-append.md +0 -0
  51. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
  52. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
  53. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +0 -0
  54. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
  55. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
  56. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
  57. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
  58. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
  59. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/conflict_resolver.py +0 -0
  60. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/connectors/__init__.py +0 -0
  61. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/connectors/whatsapp.py +0 -0
  62. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/context_hook.py +0 -0
  63. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/context_optimizer.py +0 -0
  64. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/daily_notes.py +0 -0
  65. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dashboard.py +0 -0
  66. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dashboard_auth.py +0 -0
  67. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/db_merge.py +0 -0
  68. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/delta_sync.py +0 -0
  69. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dream_bridge.py +0 -0
  70. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/embeddings.py +0 -0
  71. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_extractor.py +0 -0
  72. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_graph.py +0 -0
  73. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_registry.py +0 -0
  74. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/federated_graphify.py +0 -0
  75. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/feedback.py +0 -0
  76. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/graph_store.py +0 -0
  77. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/hook_log.py +0 -0
  78. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/__init__.py +0 -0
  79. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/calibration.py +0 -0
  80. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/compact_summaries.py +0 -0
  81. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/compactor.py +0 -0
  82. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/daydream_ingest.py +0 -0
  83. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/decay.py +0 -0
  84. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/dedup.py +0 -0
  85. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/deterministic.py +0 -0
  86. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/entity_graph_export.py +0 -0
  87. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/extractor.py +0 -0
  88. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/staleness.py +0 -0
  89. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/validator.py +0 -0
  90. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/key_rotator.py +0 -0
  91. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/lifecycle.py +0 -0
  92. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_budget.py +0 -0
  93. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_provider.py +0 -0
  94. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_rerank.py +0 -0
  95. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_steward.py +0 -0
  96. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_path_policy.py +0 -0
  97. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_server.py +0 -0
  98. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_usage.py +0 -0
  99. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/media_processing.py +0 -0
  100. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/media_providers.py +0 -0
  101. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/metrics_exporter.py +0 -0
  102. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0001_initial.py +0 -0
  103. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0002_miner_state.py +0 -0
  104. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0003_contradiction_verdicts.py +0 -0
  105. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0004_query_cache.py +0 -0
  106. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/__init__.py +0 -0
  107. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/runner.py +0 -0
  108. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/models.py +0 -0
  109. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/observability.py +0 -0
  110. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/operator.py +0 -0
  111. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/operator_queue.py +0 -0
  112. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/plugins.py +0 -0
  113. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/policy.py +0 -0
  114. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/postgres_store.py +0 -0
  115. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qdrant_backend.py +0 -0
  116. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qdrant_recall_fallback.py +0 -0
  117. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qmd_bridge.py +0 -0
  118. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_classifier.py +0 -0
  119. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_expansion.py +0 -0
  120. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/recall_fusion.py +0 -0
  121. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/recall_tokenizer.py +0 -0
  122. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/retrieval.py +0 -0
  123. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/retry.py +0 -0
  124. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/review.py +0 -0
  125. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rl_trainer.py +0 -0
  126. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rules.py +0 -0
  127. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/scheduler.py +0 -0
  128. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema.py +0 -0
  129. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema.sql +0 -0
  130. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema_postgres.sql +0 -0
  131. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/scope_utils.py +0 -0
  132. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/session_tracker.py +0 -0
  133. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/setup_hooks.py +0 -0
  134. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/skill_evolver.py +0 -0
  135. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/snapshot.py +0 -0
  136. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward_classifier.py +0 -0
  137. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward_features.py +0 -0
  138. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/storage.py +0 -0
  139. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/store_factory.py +0 -0
  140. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/transcript_miner.py +0 -0
  141. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/turn_schema.py +0 -0
  142. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_bases.py +0 -0
  143. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_curator.py +0 -0
  144. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_exporter.py +0 -0
  145. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_linter.py +0 -0
  146. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_log.py +0 -0
  147. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_query_capture.py +0 -0
  148. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_synthesis.py +0 -0
  149. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_cleanup.py +0 -0
  150. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_recall.py +0 -0
  151. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/webhook.py +0 -0
  152. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_engine.py +0 -0
  153. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_freshness.py +0 -0
  154. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_similarity.py +0 -0
  155. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_suggest.py +0 -0
  156. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_validate.py +0 -0
  157. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/SOURCES.txt +0 -0
  158. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/dependency_links.txt +0 -0
  159. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/entry_points.txt +0 -0
  160. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/requires.txt +0 -0
  161. {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/top_level.txt +0 -0
  162. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/agg_recall_latency.py +0 -0
  163. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/alert_operator_metrics.py +0 -0
  164. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/audit_dedupe_precision.py +0 -0
  165. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/autoresearch_daemon.py +0 -0
  166. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_entity_extraction.py +0 -0
  167. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_graph_store.py +0 -0
  168. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_stop_hook_citations.py +0 -0
  169. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backtest_steward_classifier.py +0 -0
  170. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/build_steward_training_set.py +0 -0
  171. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/check_hook_template_drift.py +0 -0
  172. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/claude_to_turns.py +0 -0
  173. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/codex_live_to_turns.py +0 -0
  174. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_edge_cases.py +0 -0
  175. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_trace_report.py +0 -0
  176. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_trace_validate.py +0 -0
  177. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/confusion_matrix_eval.py +0 -0
  178. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/conversation_importer.py +0 -0
  179. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/conversation_to_turns.py +0 -0
  180. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/e2e_operator.py +0 -0
  181. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/email_live_to_turns.py +0 -0
  182. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_bm25_sweep.py +0 -0
  183. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_classify_f1.py +0 -0
  184. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_memorymaster.py +0 -0
  185. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_recall_precision_at_5.py +0 -0
  186. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_recall_quality.py +0 -0
  187. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_steward_pareto.py +0 -0
  188. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_verbatim_recall.py +0 -0
  189. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/expand_recall_eval.py +0 -0
  190. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/generate_drill_signoff.py +0 -0
  191. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/git_to_turns.py +0 -0
  192. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/github_live_to_turns.py +0 -0
  193. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/gitnexus_to_claims.py +0 -0
  194. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/grid_recall_weights.py +0 -0
  195. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/index_claims_to_qdrant.py +0 -0
  196. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/ingest_planning_docs.py +0 -0
  197. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/jira_live_to_turns.py +0 -0
  198. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/label_prompts_with_judge.py +0 -0
  199. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/llm_benchmark.py +0 -0
  200. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/measure_dedupe_thresholds.py +0 -0
  201. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/merge_scope_variants.py +0 -0
  202. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/messages_to_turns.py +0 -0
  203. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/operator_metrics.py +0 -0
  204. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/precompute_candidates.py +0 -0
  205. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/recurring_incident_drill.py +0 -0
  206. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/release_readiness.py +0 -0
  207. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/run_codex_autologger.py +0 -0
  208. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/run_incident_drill.py +0 -0
  209. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/scheduled_ingest.py +0 -0
  210. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/setup-hooks.py +0 -0
  211. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/slack_live_to_turns.py +0 -0
  212. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/sync_hook_templates.py +0 -0
  213. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/tickets_to_turns.py +0 -0
  214. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/train_steward_classifier.py +0 -0
  215. {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/webhook_to_turns.py +0 -0
  216. {memorymaster-3.23.0 → memorymaster-3.25.0}/setup.cfg +0 -0
  217. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/conftest.py +0 -0
  218. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
  219. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_access_control.py +0 -0
  220. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_action_exporters.py +0 -0
  221. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_action_extractor.py +0 -0
  222. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_claim_extractor.py +0 -0
  223. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_contract.py +0 -0
  224. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_source_schema.py +0 -0
  225. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_extractor.py +0 -0
  226. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_ingest_hook_schema.py +0 -0
  227. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_resolver.py +0 -0
  228. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_validate.py +0 -0
  229. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_backend_parity.py +0 -0
  230. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_bm25_per_field.py +0 -0
  231. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_calibration.py +0 -0
  232. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_calibration_priors_applied.py +0 -0
  233. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_candidate_dedupe.py +0 -0
  234. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_edges.py +0 -0
  235. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_links.py +0 -0
  236. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_type_ranking.py +0 -0
  237. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_classify_hook_f1.py +0 -0
  238. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_classify_hook_latency.py +0 -0
  239. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claude_to_turns.py +0 -0
  240. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_dry_run.py +0 -0
  241. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_json_flag.py +0 -0
  242. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_ready.py +0 -0
  243. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_review_queue.py +0 -0
  244. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_subcommands.py +0 -0
  245. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_closets.py +0 -0
  246. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_closets_recall_integration.py +0 -0
  247. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compact_summaries.py +0 -0
  248. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compact_summaries_sensitivity.py +0 -0
  249. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compaction_trace.py +0 -0
  250. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compactor_artifact_order.py +0 -0
  251. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_config.py +0 -0
  252. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_conflict_resolver.py +0 -0
  253. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_confusion_matrix_eval.py +0 -0
  254. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_connection_retry.py +0 -0
  255. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_connectors.py +0 -0
  256. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_hook.py +0 -0
  257. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_optimizer.py +0 -0
  258. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_optimizer_provider.py +0 -0
  259. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_contradiction_probe.py +0 -0
  260. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_conversation_to_turns.py +0 -0
  261. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard.py +0 -0
  262. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_auth.py +0 -0
  263. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_coverage.py +0 -0
  264. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_latency.py +0 -0
  265. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_lineage.py +0 -0
  266. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_review_queue.py +0 -0
  267. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_daydream_ingest.py +0 -0
  268. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_db_merge_confidence_conflict.py +0 -0
  269. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_db_merge_coverage_v2.py +0 -0
  270. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_decay_coverage.py +0 -0
  271. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_decay_respects_pinned.py +0 -0
  272. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup.py +0 -0
  273. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup_cli.py +0 -0
  274. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup_conflict_disambiguation.py +0 -0
  275. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_delta_sync.py +0 -0
  276. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_deterministic_predicates.py +0 -0
  277. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dream_bridge_coverage_v2.py +0 -0
  278. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dream_bridge_sensitivity.py +0 -0
  279. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_embeddings_coverage.py +0 -0
  280. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_extractor.py +0 -0
  281. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_extractor_llm.py +0 -0
  282. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_graph.py +0 -0
  283. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_graph_export.py +0 -0
  284. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_new_kinds.py +0 -0
  285. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_regex_v3.py +0 -0
  286. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_registry.py +0 -0
  287. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_eval_harness.py +0 -0
  288. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_events_schema.py +0 -0
  289. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_extract_llm_ollama.py +0 -0
  290. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_federated_graphify_mcp.py +0 -0
  291. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_federated_query_safety.py +0 -0
  292. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_feedback.py +0 -0
  293. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_floor_gate.py +0 -0
  294. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_fts5_search.py +0 -0
  295. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_graph_distance.py +0 -0
  296. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_graph_store.py +0 -0
  297. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_handler_regressions.py +0 -0
  298. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_hook_env_isolation.py +0 -0
  299. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_human_id.py +0 -0
  300. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_incident_drill_runner.py +0 -0
  301. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_integration_workflows.py +0 -0
  302. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_key_rotator.py +0 -0
  303. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_lifecycle.py +0 -0
  304. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_lifecycle_supersede_invariant.py +0 -0
  305. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_budget.py +0 -0
  306. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_fallback.py +0 -0
  307. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_provider_claude_cli.py +0 -0
  308. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_provider_key_rotation.py +0 -0
  309. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_steward_coverage.py +0 -0
  310. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_steward_key_rotation.py +0 -0
  311. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_filter_bypass.py +0 -0
  312. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_helpers.py +0 -0
  313. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_path_policy.py +0 -0
  314. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_rate_limit.py +0 -0
  315. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_server_validation.py +0 -0
  316. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_usage.py +0 -0
  317. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_media_processing.py +0 -0
  318. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_meta_decisions.py +0 -0
  319. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_metrics_exporter.py +0 -0
  320. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_migrations.py +0 -0
  321. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_observability.py +0 -0
  322. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_obsidian_mind_patterns.py +0 -0
  323. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_operator.py +0 -0
  324. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_operator_queue.py +0 -0
  325. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_perf_smoke_config.py +0 -0
  326. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_plugins.py +0 -0
  327. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_policy_coverage.py +0 -0
  328. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_policy_mode_env.py +0 -0
  329. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_postgres_parity.py +0 -0
  330. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qdrant_backend.py +0 -0
  331. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qmd_bridge.py +0 -0
  332. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qrels_regression.py +0 -0
  333. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_classifier.py +0 -0
  334. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_expansion.py +0 -0
  335. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_entity_fanout.py +0 -0
  336. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_fusion.py +0 -0
  337. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_latency.py +0 -0
  338. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_precision_at_5.py +0 -0
  339. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_tokenizer.py +0 -0
  340. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_vector_fallback.py +0 -0
  341. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_reliability_hardening.py +0 -0
  342. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_resolvers_concurrent_supersede.py +0 -0
  343. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_profile.py +0 -0
  344. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_profiles.py +0 -0
  345. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_rrf_tiebreaker.py +0 -0
  346. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_weights.py +0 -0
  347. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_review.py +0 -0
  348. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rl_trainer.py +0 -0
  349. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rrf_auto_gate.py +0 -0
  350. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rule_claims.py +0 -0
  351. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scheduler.py +0 -0
  352. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_schema.py +0 -0
  353. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scope_boost.py +0 -0
  354. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scope_utils.py +0 -0
  355. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_security_access.py +0 -0
  356. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_security_patterns.py +0 -0
  357. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
  358. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
  359. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_service_coverage.py +0 -0
  360. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_session_tracker.py +0 -0
  361. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_snapshot.py +0 -0
  362. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_snapshot_roundtrip.py +0 -0
  363. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sqlite_core.py +0 -0
  364. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_staleness.py +0 -0
  365. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_stealth_mode.py +0 -0
  366. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward.py +0 -0
  367. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_classifier.py +0 -0
  368. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_daydream_hook.py +0 -0
  369. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_features.py +0 -0
  370. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_features_v3.py +0 -0
  371. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_resolution_parity.py +0 -0
  372. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_storage_parity.py +0 -0
  373. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_store_factory.py +0 -0
  374. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_tenant_isolation.py +0 -0
  375. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_turn_schema.py +0 -0
  376. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_two_pass_recall.py +0 -0
  377. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v311_fixes.py +0 -0
  378. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v313_e2e.py +0 -0
  379. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
  380. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v390_e2e.py +0 -0
  381. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v391_strict_warnings.py +0 -0
  382. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vault_exporter.py +0 -0
  383. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vault_linter_orphan.py +0 -0
  384. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vector_search.py +0 -0
  385. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_cleanup.py +0 -0
  386. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_dedup.py +0 -0
  387. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_recall.py +0 -0
  388. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_store.py +0 -0
  389. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_webhook.py +0 -0
  390. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_webhook_hmac.py +0 -0
  391. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_whatsapp_importer.py +0 -0
  392. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_autopromote.py +0 -0
  393. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_binding.py +0 -0
  394. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_engine_idempotency.py +0 -0
  395. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
  396. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_freshness.py +0 -0
  397. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_similarity_multiscope.py +0 -0
  398. {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_suggest.py +0 -0
  399. {memorymaster-3.23.0 → memorymaster-3.25.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.23.0
3
+ Version: 3.25.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-2224-green.svg)]()
55
+ [![Tests](https://img.shields.io/badge/tests-2232-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-2224-green.svg)]()
9
+ [![Tests](https://img.shields.io/badge/tests-2232-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.23.0"
5
+ __version__ = "3.25.0"
@@ -10,9 +10,8 @@ import json
10
10
  import os
11
11
  import sys
12
12
  import re
13
- import sqlite3
14
13
  import hashlib
15
- from datetime import datetime, timezone
14
+ from datetime import datetime
16
15
  from pathlib import Path
17
16
 
18
17
  PROJECT_ROOT = "__MEMORYMASTER_PROJECT_ROOT__"
@@ -139,43 +138,40 @@ Only: bug root causes, decisions, gotchas, constraints. Never: credentials, IPs,
139
138
  return
140
139
 
141
140
  scope = "project:" + os.path.basename(cwd).lower().replace(" ", "-") if cwd else "global"
142
- now = datetime.now(timezone.utc).isoformat()
143
141
 
144
- conn = sqlite3.connect(DB_PATH)
142
+ # Route through MemoryService.ingest instead of raw SQL so claims gain
143
+ # the canonical ingest path: sensitivity sanitize (defense-in-depth on
144
+ # top of the _is_sensitive_claim drop above), content-hash + idempotency
145
+ # dedup, entity resolution, auto-citation, observability, and webhook.
146
+ # Mirrors _run_rule_extraction, which already uses the service.
147
+ from memorymaster.service import MemoryService
148
+ from memorymaster.models import CitationInput
149
+
150
+ svc = MemoryService(DB_PATH, workspace_root=Path(cwd or PROJECT_ROOT))
151
+ ingested = 0
145
152
  for c in claims:
146
153
  text = c.get("text", "")
147
154
  if not text or len(text) < 10:
148
155
  continue
149
- # Duplicate check by content hash
150
156
  text_hash = hashlib.sha256(text.strip().lower().encode()).hexdigest()[:16]
151
- idem = f"llm-stop-{text_hash}"
152
- if conn.execute("SELECT id FROM claims WHERE idempotency_key = ?", (idem,)).fetchone():
153
- continue
154
- cur = conn.execute(
155
- """INSERT INTO claims (text, idempotency_key, normalized_text, claim_type,
156
- subject, predicate, scope, status, confidence,
157
- source_agent, created_at, updated_at, tier, version, visibility,
158
- valid_from)
159
- VALUES (?, ?, ?, ?, ?, ?, ?, 'candidate', 0.6,
160
- 'llm-stop-hook', ?, ?, 'working', 1, 'public', ?)""",
161
- (text, idem, text.lower(), c.get("claim_type", "fact"),
162
- c.get("subject", "codebase"), c.get("predicate", "observation"),
163
- scope, now, now, now),
164
- )
165
- # Auto-citation: steward's min_citations>=1 gate requires at least one
166
- # row per claim. Without this, every llm-stop-hook claim is born
167
- # unpromotable. Source is the hook itself; locator = scope for
168
- # traceability; excerpt preserves the first 200 chars of the claim.
169
- conn.execute(
170
- """INSERT INTO citations (claim_id, source, locator, excerpt, created_at)
171
- VALUES (?, 'llm-stop-hook', ?, ?, ?)""",
172
- (cur.lastrowid, scope, text[:200], now),
173
- )
174
- conn.commit()
175
- conn.close()
157
+ try:
158
+ svc.ingest(
159
+ text=text,
160
+ citations=[CitationInput(source="llm-stop-hook", locator=scope, excerpt=text[:200])],
161
+ idempotency_key=f"llm-stop-{text_hash}",
162
+ claim_type=c.get("claim_type", "fact"),
163
+ subject=c.get("subject", "codebase"),
164
+ predicate=c.get("predicate", "observation"),
165
+ scope=scope,
166
+ confidence=0.6,
167
+ source_agent="llm-stop-hook",
168
+ )
169
+ ingested += 1
170
+ except Exception:
171
+ continue # one bad claim must not abort the rest
176
172
 
177
173
  provider = os.environ.get("MEMORYMASTER_LLM_PROVIDER", "google")
178
- sys.stderr.write(f"[MemoryMaster] {provider} extracted {len(claims)} learnings\n")
174
+ sys.stderr.write(f"[MemoryMaster] {provider} extracted {ingested} learnings\n")
179
175
  except Exception:
180
176
  pass
181
177
 
@@ -357,7 +357,7 @@ def probe_for_claim(
357
357
  metrics: dict[str, Any] = {
358
358
  "pairs_checked": 0, "contradictions": 0,
359
359
  "cache_hits": 0, "llm_calls": 0, "errors": 0,
360
- "timed_out": False, "duration_ms": 0.0,
360
+ "timed_out": False, "budget_exhausted": False, "duration_ms": 0.0,
361
361
  }
362
362
  reasons: list[dict[str, Any]] = []
363
363
 
@@ -426,7 +426,11 @@ def probe_for_claim(
426
426
  try:
427
427
  verdict = _judge_llm(claim, peer)
428
428
  except llm_budget.LLMBudgetExceeded:
429
- metrics["timed_out"] = True
429
+ # Budget exhaustion is an expected guardrail, NOT a probe
430
+ # failure — the steward must not count it toward the circuit
431
+ # breaker (which would disable the probe for the rest of the
432
+ # cycle). Flag it distinctly from a genuine timeout.
433
+ metrics["budget_exhausted"] = True
430
434
  break
431
435
  metrics["llm_calls"] += 1
432
436
  if verdict is None:
@@ -84,11 +84,31 @@ def current_generation(conn: sqlite3.Connection) -> int:
84
84
  return int(row[0]) if row else 0
85
85
 
86
86
 
87
+ def read_generation(db_path: str) -> int:
88
+ """Return the current corpus generation, or 0 on any error.
89
+
90
+ Callers capture this BEFORE reading the corpus they are about to compute a
91
+ result from, then pass it to ``write()`` — see the TOCTOU note there."""
92
+ try:
93
+ conn = _connect(db_path)
94
+ except sqlite3.Error as exc:
95
+ logger.warning("query_cache.read_generation connect failed: %s", exc)
96
+ return 0
97
+ try:
98
+ return current_generation(conn)
99
+ except (sqlite3.Error, ValueError) as exc:
100
+ logger.warning("query_cache.read_generation failed: %s", exc)
101
+ return 0
102
+ finally:
103
+ conn.close()
104
+
105
+
87
106
  def read(db_path: str, cache_key: str) -> list[dict] | None:
88
107
  """Return cached result stubs if present AND still fresh (generation match)."""
89
108
  try:
90
109
  conn = _connect(db_path)
91
- except sqlite3.Error:
110
+ except sqlite3.Error as exc:
111
+ logger.warning("query_cache.read connect failed: %s", exc)
92
112
  return None
93
113
  try:
94
114
  gen = current_generation(conn)
@@ -99,20 +119,31 @@ def read(db_path: str, cache_key: str) -> list[dict] | None:
99
119
  if row is None or int(row["generation"]) != gen:
100
120
  return None
101
121
  return json.loads(row["result_json"])
102
- except (sqlite3.Error, json.JSONDecodeError, ValueError):
122
+ except (sqlite3.Error, json.JSONDecodeError, ValueError) as exc:
123
+ logger.warning("query_cache.read failed (cache disabled for this query): %s", exc)
103
124
  return None
104
125
  finally:
105
126
  conn.close()
106
127
 
107
128
 
108
- def write(db_path: str, cache_key: str, stub_rows: list[dict]) -> None:
109
- """Store result stubs tagged with the current generation. Best-effort."""
129
+ def write(db_path: str, cache_key: str, stub_rows: list[dict], generation: int) -> None:
130
+ """Store result stubs tagged with ``generation``. Best-effort.
131
+
132
+ TOCTOU correctness: ``generation`` MUST be the corpus generation captured by
133
+ the caller BEFORE it read the candidates it computed ``stub_rows`` from. If
134
+ we re-read the generation here instead, a claim write that raced in between
135
+ the caller's corpus read and this write would have bumped the counter, and
136
+ we would tag a stale (generation-G) result as the new generation (G+1) — so
137
+ a subsequent read at G+1 would serve the stale ranking, defeating the
138
+ generation gate. Tagging with the compute-time generation guarantees any
139
+ racing write correctly invalidates this entry. (audit: qc-generation-toctou)
140
+ """
110
141
  try:
111
142
  conn = _connect(db_path)
112
- except sqlite3.Error:
143
+ except sqlite3.Error as exc:
144
+ logger.warning("query_cache.write connect failed: %s", exc)
113
145
  return
114
146
  try:
115
- gen = current_generation(conn)
116
147
  conn.execute(
117
148
  """INSERT INTO query_cache (cache_key, result_json, generation, created_at)
118
149
  VALUES (?, ?, ?, ?)
@@ -120,10 +151,10 @@ def write(db_path: str, cache_key: str, stub_rows: list[dict]) -> None:
120
151
  result_json = excluded.result_json,
121
152
  generation = excluded.generation,
122
153
  created_at = excluded.created_at""",
123
- (cache_key, json.dumps(stub_rows), gen, datetime.now(timezone.utc).isoformat()),
154
+ (cache_key, json.dumps(stub_rows), generation, datetime.now(timezone.utc).isoformat()),
124
155
  )
125
156
  conn.commit()
126
- except (sqlite3.Error, TypeError, ValueError):
127
- pass
157
+ except (sqlite3.Error, TypeError, ValueError) as exc:
158
+ logger.warning("query_cache.write failed (result not cached): %s", exc)
128
159
  finally:
129
160
  conn.close()
@@ -158,12 +158,26 @@ def _build_window(assistant_content: str, user_content: str) -> str:
158
158
  return f"ASSISTANT: {asst}\nUSER: {user}"
159
159
 
160
160
 
161
+ class TransientLLMError(RuntimeError):
162
+ """The LLM provider returned an empty response — almost always a transient
163
+ failure (outage, timeout, rate-limit returning ''), NOT a genuine "no
164
+ correction" verdict. Callers must distinguish the two: advancing the
165
+ watermark past a candidate that was never actually judged would permanently
166
+ skip real corrections during a provider outage. (audit:
167
+ mine-rules-silent-watermark-advance)"""
168
+
169
+
161
170
  def _extract_rule(window: str) -> dict[str, str] | None:
162
171
  """Ask the LLM to distill a rule. Returns ``{trigger, action, rationale}``
163
- or ``None`` when there is no correction. May raise ``LLMBudgetExceeded``."""
172
+ or ``None`` when the model responded but found no correction.
173
+
174
+ Raises ``LLMBudgetExceeded`` if the per-cycle cap is hit, and
175
+ ``TransientLLMError`` if the provider returned nothing (so the caller can
176
+ avoid advancing the watermark). A non-empty response that simply doesn't
177
+ parse to a rule is a genuine "no correction" (``None``), not transient."""
164
178
  raw = llm_provider.call_llm(_CORRECTION_PROMPT, window)
165
179
  if not raw or not raw.strip():
166
- return None
180
+ raise TransientLLMError("empty LLM response")
167
181
  for item in llm_provider.parse_json_response(raw):
168
182
  if not isinstance(item, dict):
169
183
  continue
@@ -300,6 +314,12 @@ def _process_candidate(
300
314
  except llm_budget.LLMBudgetExceeded as exc:
301
315
  stats["aborted_reason"] = exc.reason
302
316
  return "aborted"
317
+ except TransientLLMError:
318
+ # Provider returned empty (likely transient outage). Abort the run WITHOUT
319
+ # advancing the watermark past this row, so the candidate is retried next
320
+ # run instead of silently skipped. Stopping is safe: mining is a batch job.
321
+ stats["aborted_reason"] = "llm_transient_failure"
322
+ return "aborted"
303
323
 
304
324
  stats["llm_calls"] += 1
305
325
  if rule is None or _is_sensitive_rule(rule):
@@ -412,7 +432,10 @@ def mine_transcript_rules(
412
432
  stats["windows"] += 1
413
433
  try:
414
434
  rule = _extract_rule(_build_window(asst_text, user_text))
415
- except llm_budget.LLMBudgetExceeded:
435
+ except (llm_budget.LLMBudgetExceeded, TransientLLMError):
436
+ # Budget hit or provider returned empty — stop this best-effort
437
+ # Stop-hook pass. No watermark here, so nothing to skip; a
438
+ # later session re-mines its own corrections.
416
439
  break
417
440
  stats["llm_calls"] += 1
418
441
  if rule is None or _is_sensitive_rule(rule):
@@ -157,6 +157,8 @@ class SanitizedClaimInput:
157
157
  is_sensitive: bool
158
158
  findings: list[str]
159
159
  encrypted_payload: str | None
160
+ subject: str | None = None
161
+ predicate: str | None = None
160
162
 
161
163
 
162
164
  def _as_bool(value: object, *, field: str) -> bool:
@@ -320,6 +322,8 @@ def sanitize_claim_input(
320
322
  text: str,
321
323
  object_value: str | None,
322
324
  citations: list[CitationInput],
325
+ subject: str | None = None,
326
+ predicate: str | None = None,
323
327
  ) -> SanitizedClaimInput:
324
328
  redacted_text, findings = _redact(text)
325
329
  redacted_object = object_value
@@ -328,6 +332,19 @@ def sanitize_claim_input(
328
332
  redacted_object, object_findings = _redact(object_value)
329
333
  findings.extend(object_findings)
330
334
 
335
+ # subject/predicate are structured-claim fields that reach the store
336
+ # alongside text/object_value. They are exposed MCP ingest parameters, so a
337
+ # secret placed there must be caught by the ingest filter — the last line of
338
+ # defense — not only at display time. (audit: ingest-subject-skips-filter)
339
+ redacted_subject = subject
340
+ if subject:
341
+ redacted_subject, subject_findings = _redact(subject)
342
+ findings.extend(subject_findings)
343
+ redacted_predicate = predicate
344
+ if predicate:
345
+ redacted_predicate, predicate_findings = _redact(predicate)
346
+ findings.extend(predicate_findings)
347
+
331
348
  sanitized_citations: list[CitationInput] = []
332
349
  citation_findings: list[str] = []
333
350
  for cite in citations:
@@ -344,6 +361,8 @@ def sanitize_claim_input(
344
361
  {
345
362
  "text": text,
346
363
  "object_value": object_value,
364
+ "subject": subject,
365
+ "predicate": predicate,
347
366
  "citations": [asdict(c) for c in citations],
348
367
  }
349
368
  ) if is_sensitive else None
@@ -355,6 +374,8 @@ def sanitize_claim_input(
355
374
  is_sensitive=is_sensitive,
356
375
  findings=dedup_findings,
357
376
  encrypted_payload=encrypted_payload,
377
+ subject=redacted_subject,
378
+ predicate=redacted_predicate,
358
379
  )
359
380
 
360
381
 
@@ -251,9 +251,15 @@ class MemoryService:
251
251
  text=text.strip(),
252
252
  object_value=object_value,
253
253
  citations=citations,
254
+ subject=subject,
255
+ predicate=predicate,
254
256
  )
255
257
  if not sanitized.citations:
256
258
  raise ValueError("At least one citation is required.")
259
+ # Use the sanitized subject/predicate everywhere downstream so a secret
260
+ # placed in those fields is redacted at rest, not just at display time.
261
+ subject = sanitized.subject
262
+ predicate = sanitized.predicate
257
263
  # Resolve subject → canonical entity (GBrain-inspired entity registry)
258
264
  # and mine text for pattern-based entities (#127 Wave 3).
259
265
  entity_id = 0
@@ -667,6 +673,11 @@ class MemoryService:
667
673
  rows = self._rehydrate_cached_rows(cached)
668
674
  self._record_accesses(rows, query_text=query_text)
669
675
  return rows
676
+ # Capture the corpus generation BEFORE reading candidates so the cache
677
+ # entry is tagged with the generation it was actually computed against,
678
+ # not whatever it is after ranking/LLM-rerank (which a concurrent claim
679
+ # write could have bumped). See query_cache.write TOCTOU note.
680
+ cache_generation = query_cache.read_generation(cache_path) if cache_path else 0
670
681
  candidate_limit = max(limit * 6, 60, 50 if use_llm_rerank else 0)
671
682
  candidates = self.store.list_claims(
672
683
  limit=candidate_limit,
@@ -733,7 +744,7 @@ class MemoryService:
733
744
  "breakdown": r.get("breakdown"),
734
745
  }
735
746
  for r in results if r.get("claim") is not None
736
- ])
747
+ ], cache_generation)
737
748
  return results
738
749
 
739
750
  def _rehydrate_cached_rows(self, stubs: list[dict[str, Any]]) -> list[dict[str, Any]]:
@@ -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
  *,