memorymaster 3.17.1__tar.gz → 3.18.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 (368) hide show
  1. {memorymaster-3.17.1/memorymaster.egg-info → memorymaster-3.18.0}/PKG-INFO +1 -1
  2. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config.py +61 -0
  3. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/retrieval.py +45 -7
  4. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/service.py +4 -0
  5. {memorymaster-3.17.1 → memorymaster-3.18.0/memorymaster.egg-info}/PKG-INFO +1 -1
  6. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster.egg-info/SOURCES.txt +1 -0
  7. {memorymaster-3.17.1 → memorymaster-3.18.0}/pyproject.toml +1 -1
  8. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/bench_longmemeval.py +66 -5
  9. memorymaster-3.18.0/tests/test_retrieval_profiles.py +142 -0
  10. {memorymaster-3.17.1 → memorymaster-3.18.0}/LICENSE +0 -0
  11. {memorymaster-3.17.1 → memorymaster-3.18.0}/README.md +0 -0
  12. {memorymaster-3.17.1 → memorymaster-3.18.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
  13. {memorymaster-3.17.1 → memorymaster-3.18.0}/benchmarks/longmemeval_runner.py +0 -0
  14. {memorymaster-3.17.1 → memorymaster-3.18.0}/benchmarks/longmemeval_vector_runner.py +0 -0
  15. {memorymaster-3.17.1 → memorymaster-3.18.0}/benchmarks/perf_smoke.py +0 -0
  16. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/__init__.py +0 -0
  17. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/__main__.py +0 -0
  18. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_lifecycle.py +0 -0
  19. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_read.py +0 -0
  20. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_schema.py +0 -0
  21. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_shared.py +0 -0
  22. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_sources.py +0 -0
  23. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/_storage_write_claims.py +0 -0
  24. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/access_control.py +0 -0
  25. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/action_exporters.py +0 -0
  26. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/action_extractor.py +0 -0
  27. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/atlas_claim_extractor.py +0 -0
  28. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/atlas_contract.py +0 -0
  29. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/auto_extractor.py +0 -0
  30. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/auto_resolver.py +0 -0
  31. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/candidate_dedupe.py +0 -0
  32. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/claim_edges.py +0 -0
  33. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/claim_verifier.py +0 -0
  34. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/cli.py +0 -0
  35. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/cli_handlers_basic.py +0 -0
  36. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/cli_handlers_curation.py +0 -0
  37. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/cli_helpers.py +0 -0
  38. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/closets.py +0 -0
  39. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/claude-md-append.md +0 -0
  40. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
  41. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +0 -0
  42. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
  43. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +0 -0
  44. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
  45. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
  46. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
  47. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
  48. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
  49. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/conflict_resolver.py +0 -0
  50. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/connectors/__init__.py +0 -0
  51. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/connectors/whatsapp.py +0 -0
  52. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/context_hook.py +0 -0
  53. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/context_optimizer.py +0 -0
  54. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/daily_notes.py +0 -0
  55. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/dashboard.py +0 -0
  56. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/db_merge.py +0 -0
  57. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/dream_bridge.py +0 -0
  58. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/embeddings.py +0 -0
  59. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/entity_extractor.py +0 -0
  60. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/entity_graph.py +0 -0
  61. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/entity_registry.py +0 -0
  62. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/federated_graphify.py +0 -0
  63. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/feedback.py +0 -0
  64. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/graph_store.py +0 -0
  65. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/hook_log.py +0 -0
  66. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/__init__.py +0 -0
  67. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/calibration.py +0 -0
  68. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/compact_summaries.py +0 -0
  69. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/compactor.py +0 -0
  70. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/daydream_ingest.py +0 -0
  71. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/decay.py +0 -0
  72. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/dedup.py +0 -0
  73. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/deterministic.py +0 -0
  74. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/entity_graph_export.py +0 -0
  75. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/extractor.py +0 -0
  76. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/staleness.py +0 -0
  77. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/jobs/validator.py +0 -0
  78. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/key_rotator.py +0 -0
  79. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/lifecycle.py +0 -0
  80. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/llm_provider.py +0 -0
  81. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/llm_rerank.py +0 -0
  82. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/llm_steward.py +0 -0
  83. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/mcp_server.py +0 -0
  84. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/mcp_usage.py +0 -0
  85. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/media_processing.py +0 -0
  86. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/media_providers.py +0 -0
  87. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/metrics_exporter.py +0 -0
  88. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/models.py +0 -0
  89. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/observability.py +0 -0
  90. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/operator.py +0 -0
  91. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/operator_queue.py +0 -0
  92. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/plugins.py +0 -0
  93. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/policy.py +0 -0
  94. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/postgres_store.py +0 -0
  95. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/qdrant_backend.py +0 -0
  96. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/qdrant_recall_fallback.py +0 -0
  97. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/qmd_bridge.py +0 -0
  98. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/query_classifier.py +0 -0
  99. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/query_expansion.py +0 -0
  100. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/recall_fusion.py +0 -0
  101. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/recall_tokenizer.py +0 -0
  102. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/retry.py +0 -0
  103. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/review.py +0 -0
  104. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/rl_trainer.py +0 -0
  105. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/scheduler.py +0 -0
  106. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/schema.py +0 -0
  107. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/schema.sql +0 -0
  108. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/schema_postgres.sql +0 -0
  109. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/scope_utils.py +0 -0
  110. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/security.py +0 -0
  111. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/session_tracker.py +0 -0
  112. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/setup_hooks.py +0 -0
  113. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/skill_evolver.py +0 -0
  114. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/snapshot.py +0 -0
  115. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/steward.py +0 -0
  116. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/steward_classifier.py +0 -0
  117. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/steward_features.py +0 -0
  118. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/storage.py +0 -0
  119. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/store_factory.py +0 -0
  120. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/transcript_miner.py +0 -0
  121. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/turn_schema.py +0 -0
  122. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_bases.py +0 -0
  123. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_curator.py +0 -0
  124. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_exporter.py +0 -0
  125. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_linter.py +0 -0
  126. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_log.py +0 -0
  127. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_query_capture.py +0 -0
  128. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/vault_synthesis.py +0 -0
  129. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/verbatim_recall.py +0 -0
  130. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/verbatim_store.py +0 -0
  131. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/webhook.py +0 -0
  132. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/wiki_engine.py +0 -0
  133. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/wiki_freshness.py +0 -0
  134. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/wiki_similarity.py +0 -0
  135. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/wiki_suggest.py +0 -0
  136. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster/wiki_validate.py +0 -0
  137. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster.egg-info/dependency_links.txt +0 -0
  138. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster.egg-info/entry_points.txt +0 -0
  139. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster.egg-info/requires.txt +0 -0
  140. {memorymaster-3.17.1 → memorymaster-3.18.0}/memorymaster.egg-info/top_level.txt +0 -0
  141. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/agg_recall_latency.py +0 -0
  142. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/alert_operator_metrics.py +0 -0
  143. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/audit_dedupe_precision.py +0 -0
  144. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/autoresearch_daemon.py +0 -0
  145. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/backfill_entity_extraction.py +0 -0
  146. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/backfill_graph_store.py +0 -0
  147. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/backfill_stop_hook_citations.py +0 -0
  148. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/backtest_steward_classifier.py +0 -0
  149. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/build_steward_training_set.py +0 -0
  150. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/check_hook_template_drift.py +0 -0
  151. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/claude_to_turns.py +0 -0
  152. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/codex_live_to_turns.py +0 -0
  153. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/compaction_edge_cases.py +0 -0
  154. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/compaction_trace_report.py +0 -0
  155. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/compaction_trace_validate.py +0 -0
  156. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/confusion_matrix_eval.py +0 -0
  157. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/conversation_importer.py +0 -0
  158. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/conversation_to_turns.py +0 -0
  159. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/e2e_operator.py +0 -0
  160. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/email_live_to_turns.py +0 -0
  161. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_bm25_sweep.py +0 -0
  162. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_classify_f1.py +0 -0
  163. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_memorymaster.py +0 -0
  164. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_recall_precision_at_5.py +0 -0
  165. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_recall_quality.py +0 -0
  166. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_steward_pareto.py +0 -0
  167. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/eval_verbatim_recall.py +0 -0
  168. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/expand_recall_eval.py +0 -0
  169. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/generate_drill_signoff.py +0 -0
  170. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/git_to_turns.py +0 -0
  171. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/github_live_to_turns.py +0 -0
  172. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/gitnexus_to_claims.py +0 -0
  173. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/grid_recall_weights.py +0 -0
  174. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/index_claims_to_qdrant.py +0 -0
  175. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/ingest_planning_docs.py +0 -0
  176. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/jira_live_to_turns.py +0 -0
  177. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/label_prompts_with_judge.py +0 -0
  178. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/llm_benchmark.py +0 -0
  179. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/measure_dedupe_thresholds.py +0 -0
  180. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/merge_scope_variants.py +0 -0
  181. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/messages_to_turns.py +0 -0
  182. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/operator_metrics.py +0 -0
  183. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/precompute_candidates.py +0 -0
  184. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/recurring_incident_drill.py +0 -0
  185. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/release_readiness.py +0 -0
  186. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/run_codex_autologger.py +0 -0
  187. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/run_incident_drill.py +0 -0
  188. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/scheduled_ingest.py +0 -0
  189. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/setup-hooks.py +0 -0
  190. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/slack_live_to_turns.py +0 -0
  191. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/sync_hook_templates.py +0 -0
  192. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/tickets_to_turns.py +0 -0
  193. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/train_steward_classifier.py +0 -0
  194. {memorymaster-3.17.1 → memorymaster-3.18.0}/scripts/webhook_to_turns.py +0 -0
  195. {memorymaster-3.17.1 → memorymaster-3.18.0}/setup.cfg +0 -0
  196. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/conftest.py +0 -0
  197. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
  198. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_access_control.py +0 -0
  199. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_action_exporters.py +0 -0
  200. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_action_extractor.py +0 -0
  201. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_atlas_claim_extractor.py +0 -0
  202. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_atlas_contract.py +0 -0
  203. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_atlas_source_schema.py +0 -0
  204. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_auto_extractor.py +0 -0
  205. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_auto_ingest_hook_citations.py +0 -0
  206. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_auto_ingest_hook_schema.py +0 -0
  207. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_auto_resolver.py +0 -0
  208. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_auto_validate.py +0 -0
  209. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_bm25_per_field.py +0 -0
  210. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_calibration.py +0 -0
  211. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_calibration_priors_applied.py +0 -0
  212. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_candidate_dedupe.py +0 -0
  213. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_claim_edges.py +0 -0
  214. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_claim_links.py +0 -0
  215. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_claim_type_ranking.py +0 -0
  216. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_classify_hook_f1.py +0 -0
  217. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_classify_hook_latency.py +0 -0
  218. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_claude_to_turns.py +0 -0
  219. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_cli_dry_run.py +0 -0
  220. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_cli_json_flag.py +0 -0
  221. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_cli_ready.py +0 -0
  222. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_cli_review_queue.py +0 -0
  223. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_cli_subcommands.py +0 -0
  224. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_closets.py +0 -0
  225. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_closets_recall_integration.py +0 -0
  226. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_compact_summaries.py +0 -0
  227. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_compact_summaries_sensitivity.py +0 -0
  228. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_compaction_trace.py +0 -0
  229. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_compactor_artifact_order.py +0 -0
  230. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_config.py +0 -0
  231. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_conflict_resolver.py +0 -0
  232. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_confusion_matrix_eval.py +0 -0
  233. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_connection_retry.py +0 -0
  234. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_connectors.py +0 -0
  235. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_context_hook.py +0 -0
  236. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_context_optimizer.py +0 -0
  237. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_context_optimizer_provider.py +0 -0
  238. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_conversation_to_turns.py +0 -0
  239. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dashboard.py +0 -0
  240. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dashboard_coverage.py +0 -0
  241. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dashboard_latency.py +0 -0
  242. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dashboard_lineage.py +0 -0
  243. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dashboard_review_queue.py +0 -0
  244. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_daydream_ingest.py +0 -0
  245. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_db_merge_confidence_conflict.py +0 -0
  246. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_db_merge_coverage_v2.py +0 -0
  247. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_decay_coverage.py +0 -0
  248. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_decay_respects_pinned.py +0 -0
  249. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dedup.py +0 -0
  250. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dedup_cli.py +0 -0
  251. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dedup_conflict_disambiguation.py +0 -0
  252. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_deterministic_predicates.py +0 -0
  253. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dream_bridge_coverage_v2.py +0 -0
  254. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_dream_bridge_sensitivity.py +0 -0
  255. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_embeddings_coverage.py +0 -0
  256. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_extractor.py +0 -0
  257. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_extractor_llm.py +0 -0
  258. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_graph.py +0 -0
  259. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_graph_export.py +0 -0
  260. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_new_kinds.py +0 -0
  261. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_regex_v3.py +0 -0
  262. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_entity_registry.py +0 -0
  263. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_eval_harness.py +0 -0
  264. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_events_schema.py +0 -0
  265. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_extract_llm_ollama.py +0 -0
  266. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_federated_graphify_mcp.py +0 -0
  267. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_federated_query_safety.py +0 -0
  268. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_feedback.py +0 -0
  269. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_fts5_search.py +0 -0
  270. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_graph_distance.py +0 -0
  271. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_graph_store.py +0 -0
  272. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_handler_regressions.py +0 -0
  273. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_hook_env_isolation.py +0 -0
  274. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_human_id.py +0 -0
  275. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_incident_drill_runner.py +0 -0
  276. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_integration_workflows.py +0 -0
  277. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_key_rotator.py +0 -0
  278. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_lifecycle.py +0 -0
  279. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_lifecycle_supersede_invariant.py +0 -0
  280. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_llm_fallback.py +0 -0
  281. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_llm_provider_claude_cli.py +0 -0
  282. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_llm_provider_key_rotation.py +0 -0
  283. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_llm_steward_coverage.py +0 -0
  284. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_llm_steward_key_rotation.py +0 -0
  285. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_mcp_filter_bypass.py +0 -0
  286. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_mcp_helpers.py +0 -0
  287. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_mcp_rate_limit.py +0 -0
  288. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_mcp_server_validation.py +0 -0
  289. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_mcp_usage.py +0 -0
  290. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_media_processing.py +0 -0
  291. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_meta_decisions.py +0 -0
  292. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_metrics_exporter.py +0 -0
  293. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_observability.py +0 -0
  294. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_obsidian_mind_patterns.py +0 -0
  295. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_operator.py +0 -0
  296. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_operator_queue.py +0 -0
  297. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_perf_smoke_config.py +0 -0
  298. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_plugins.py +0 -0
  299. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_policy_coverage.py +0 -0
  300. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_policy_mode_env.py +0 -0
  301. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_postgres_parity.py +0 -0
  302. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_qdrant_backend.py +0 -0
  303. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_qmd_bridge.py +0 -0
  304. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_query_classifier.py +0 -0
  305. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_query_expansion.py +0 -0
  306. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_entity_fanout.py +0 -0
  307. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_fusion.py +0 -0
  308. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_latency.py +0 -0
  309. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_precision_at_5.py +0 -0
  310. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_tokenizer.py +0 -0
  311. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_recall_vector_fallback.py +0 -0
  312. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_reliability_hardening.py +0 -0
  313. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_resolvers_concurrent_supersede.py +0 -0
  314. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_retrieval_profile.py +0 -0
  315. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_retrieval_rrf_tiebreaker.py +0 -0
  316. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_retrieval_weights.py +0 -0
  317. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_review.py +0 -0
  318. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_rl_trainer.py +0 -0
  319. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_rrf_auto_gate.py +0 -0
  320. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_scheduler.py +0 -0
  321. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_schema.py +0 -0
  322. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_scope_boost.py +0 -0
  323. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_scope_utils.py +0 -0
  324. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_security_access.py +0 -0
  325. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_security_patterns.py +0 -0
  326. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
  327. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
  328. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_sensitivity_filter_t07.py +0 -0
  329. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_service_coverage.py +0 -0
  330. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_session_tracker.py +0 -0
  331. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_snapshot.py +0 -0
  332. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_snapshot_roundtrip.py +0 -0
  333. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_sqlite_core.py +0 -0
  334. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_staleness.py +0 -0
  335. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_stealth_mode.py +0 -0
  336. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward.py +0 -0
  337. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward_classifier.py +0 -0
  338. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward_daydream_hook.py +0 -0
  339. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward_features.py +0 -0
  340. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward_features_v3.py +0 -0
  341. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_steward_resolution_parity.py +0 -0
  342. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_storage_parity.py +0 -0
  343. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_store_factory.py +0 -0
  344. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_tenant_isolation.py +0 -0
  345. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_turn_schema.py +0 -0
  346. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_two_pass_recall.py +0 -0
  347. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_v311_fixes.py +0 -0
  348. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_v313_e2e.py +0 -0
  349. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
  350. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_v390_e2e.py +0 -0
  351. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_v391_strict_warnings.py +0 -0
  352. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_vault_exporter.py +0 -0
  353. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_vault_linter_orphan.py +0 -0
  354. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_vector_search.py +0 -0
  355. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_verbatim_dedup.py +0 -0
  356. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_verbatim_recall.py +0 -0
  357. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_verbatim_store.py +0 -0
  358. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_verbatim_store_qdrant.py +0 -0
  359. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_webhook.py +0 -0
  360. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_whatsapp_importer.py +0 -0
  361. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_autopromote.py +0 -0
  362. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_binding.py +0 -0
  363. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_engine_idempotency.py +0 -0
  364. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
  365. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_freshness.py +0 -0
  366. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_similarity_multiscope.py +0 -0
  367. {memorymaster-3.17.1 → memorymaster-3.18.0}/tests/test_wiki_suggest.py +0 -0
  368. {memorymaster-3.17.1 → memorymaster-3.18.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.17.1
3
+ Version: 3.18.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
@@ -67,6 +67,17 @@ MEMORYMASTER_RRF_TIEBREAKER_THRESHOLD
67
67
  Maximum adjacent score gap considered a near tie.
68
68
  Default: ``0.01``
69
69
 
70
+ MEMORYMASTER_RETRIEVAL_PROFILE_<TYPE>
71
+ Per-question-type retrieval weight override. ``<TYPE>`` is the
72
+ upper-snake-case form of the question type (LongMemEval-S labels:
73
+ SINGLE_SESSION_USER, SINGLE_SESSION_ASSISTANT, SINGLE_SESSION_PREFERENCE,
74
+ TEMPORAL_REASONING, KNOWLEDGE_UPDATE, MULTI_SESSION). Value format
75
+ matches ``MEMORYMASTER_RETRIEVAL_WEIGHTS``: comma-separated floats
76
+ ``lex,conf,fresh,vec``. When set, ``Config.retrieval_profile(qtype)``
77
+ returns the profile and ``retrieval._compute_claim_score`` consumes it
78
+ instead of the default weights. Profiles are opt-in; missing types fall
79
+ back to the global ``cfg.retrieval_weights``.
80
+
70
81
  MEMORYMASTER_CONFIG_FILE
71
82
  Path to a JSON config file. Keys match attribute names on ``Config``.
72
83
  """
@@ -218,6 +229,15 @@ class Config:
218
229
  default_factory=lambda: dict(INITIAL_CONFIDENCE_BY_TYPE)
219
230
  )
220
231
 
232
+ # --- Per-question-type retrieval weight profiles (S3, opt-in) ---
233
+ # Maps the canonical question_type slug (lowercase, hyphens preserved,
234
+ # e.g. "single-session-preference") to a (W_LEX, W_CONF, W_FRESH, W_VEC)
235
+ # tuple. Populated by env vars MEMORYMASTER_RETRIEVAL_PROFILE_<TYPE>.
236
+ # Empty by default — retrieval falls back to ``retrieval_weights``.
237
+ retrieval_profiles: Dict[str, tuple[float, float, float, float]] = field(
238
+ default_factory=dict
239
+ )
240
+
221
241
  # --- Derived convenience dicts ---
222
242
 
223
243
  @property
@@ -270,6 +290,20 @@ class Config:
270
290
  self.lexical_weight_prefix,
271
291
  )
272
292
 
293
+ def retrieval_profile(
294
+ self, question_type: str | None
295
+ ) -> tuple[float, float, float, float] | None:
296
+ """Per-question-type weight override, or None to fall back to default.
297
+
298
+ Accepts the canonical bench label (e.g. ``single-session-preference``)
299
+ or the classifier output (e.g. ``preference``) — both lookup forms are
300
+ normalized to lowercase before lookup. Returning None signals the
301
+ caller to use ``retrieval_weights`` as usual.
302
+ """
303
+ if not question_type:
304
+ return None
305
+ return self.retrieval_profiles.get(question_type.strip().lower())
306
+
273
307
 
274
308
  # ---------------------------------------------------------------------------
275
309
  # Module-level singleton
@@ -363,6 +397,7 @@ def load_config(config_path: str | Path | None = None) -> Config:
363
397
  _apply_env_bool(overrides, "MEMORYMASTER_LLM_RERANK", "llm_rerank")
364
398
  _apply_env_bool(overrides, "MEMORYMASTER_RRF_TIEBREAKER", "rrf_tiebreaker_enabled")
365
399
  _apply_env_float(overrides, "MEMORYMASTER_RRF_TIEBREAKER_THRESHOLD", "rrf_tiebreaker_threshold")
400
+ _apply_env_retrieval_profiles(overrides)
366
401
 
367
402
  # Filter to only valid Config fields
368
403
  valid_fields = {f.name for f in Config.__dataclass_fields__.values()}
@@ -404,3 +439,29 @@ def _apply_env_bool(overrides: dict[str, object], env_var: str, key: str) -> Non
404
439
  if not raw:
405
440
  return
406
441
  overrides[key] = raw in {"1", "true", "yes", "on"}
442
+
443
+
444
+ _PROFILE_PREFIX = "MEMORYMASTER_RETRIEVAL_PROFILE_"
445
+
446
+
447
+ def _apply_env_retrieval_profiles(overrides: dict[str, object]) -> None:
448
+ """Collect per-type profile overrides from env into a single dict.
449
+
450
+ Scans every env var starting with ``MEMORYMASTER_RETRIEVAL_PROFILE_``.
451
+ The suffix becomes the question_type slug (lowercased, underscores
452
+ converted to hyphens to match the LongMemEval-S canonical labels like
453
+ ``single-session-preference``).
454
+ """
455
+ profiles: dict[str, tuple[float, float, float, float]] = {}
456
+ for key, raw in os.environ.items():
457
+ if not key.startswith(_PROFILE_PREFIX):
458
+ continue
459
+ raw = raw.strip()
460
+ if not raw:
461
+ continue
462
+ suffix = key[len(_PROFILE_PREFIX):]
463
+ qtype = suffix.lower().replace("_", "-")
464
+ values = _parse_floats(raw, 4)
465
+ profiles[qtype] = (values[0], values[1], values[2], values[3])
466
+ if profiles:
467
+ overrides["retrieval_profiles"] = profiles
@@ -130,14 +130,42 @@ def rank_claims(
130
130
  limit: int = 20,
131
131
  vector_hook: VectorSearchHook | None = None,
132
132
  semantic_vectors: bool = False,
133
+ query_type: str | None = None,
133
134
  ) -> list[Claim]:
134
- return [row.claim for row in rank_claim_rows(query_text, claims, mode=mode, limit=limit, vector_hook=vector_hook, semantic_vectors=semantic_vectors)]
135
-
136
-
137
- def _compute_claim_score(claim: Claim, lexical: float, confidence: float, freshness: float, vector: float, vector_enabled: bool, semantic_vectors: bool) -> float:
138
- """Compute relevance score for a claim."""
135
+ return [
136
+ row.claim
137
+ for row in rank_claim_rows(
138
+ query_text,
139
+ claims,
140
+ mode=mode,
141
+ limit=limit,
142
+ vector_hook=vector_hook,
143
+ semantic_vectors=semantic_vectors,
144
+ query_type=query_type,
145
+ )
146
+ ]
147
+
148
+
149
+ def _compute_claim_score(
150
+ claim: Claim,
151
+ lexical: float,
152
+ confidence: float,
153
+ freshness: float,
154
+ vector: float,
155
+ vector_enabled: bool,
156
+ semantic_vectors: bool,
157
+ query_type: str | None = None,
158
+ ) -> float:
159
+ """Compute relevance score for a claim.
160
+
161
+ When ``query_type`` matches a configured per-type profile
162
+ (``cfg.retrieval_profile(query_type)``), the profile's 4-tuple replaces
163
+ ``cfg.retrieval_weights`` for vector-enabled paths. The no-vector path
164
+ is unchanged — profiles only override the hybrid blend.
165
+ """
139
166
  cfg = get_config()
140
- w_l, w_c, w_f, w_v = cfg.retrieval_weights
167
+ profile = cfg.retrieval_profile(query_type) if query_type else None
168
+ w_l, w_c, w_f, w_v = profile if profile is not None else cfg.retrieval_weights
141
169
  if vector_enabled and semantic_vectors:
142
170
  # Real semantic embeddings use the same configurable blend as other
143
171
  # vector-enabled ranking so env sweeps affect both paths.
@@ -252,6 +280,7 @@ def rank_claim_rows(
252
280
  limit: int = 20,
253
281
  vector_hook: VectorSearchHook | None = None,
254
282
  semantic_vectors: bool = False,
283
+ query_type: str | None = None,
255
284
  ) -> list[RankedClaim]:
256
285
  if mode not in RETRIEVAL_MODES:
257
286
  raise ValueError(f"Unknown retrieval mode: {mode}")
@@ -289,7 +318,16 @@ def rank_claim_rows(
289
318
  freshness = _freshness_score(claim)
290
319
  vector = max(0.0, min(1.0, float(vector_scores.get(claim.id, 0.0))))
291
320
 
292
- score = _compute_claim_score(claim, lexical, confidence, freshness, vector, vector_enabled, semantic_vectors)
321
+ score = _compute_claim_score(
322
+ claim,
323
+ lexical,
324
+ confidence,
325
+ freshness,
326
+ vector,
327
+ vector_enabled,
328
+ semantic_vectors,
329
+ query_type=query_type,
330
+ )
293
331
 
294
332
  ranked.append(
295
333
  RankedClaim(
@@ -426,6 +426,7 @@ class MemoryService:
426
426
  retrieval_profile: str | None = None,
427
427
  allow_sensitive: bool = False,
428
428
  scope_allowlist: list[str] | None = None,
429
+ query_type: str | None = None,
429
430
  ) -> list[Claim]:
430
431
  rows = self.query_rows(
431
432
  query_text=query_text,
@@ -438,6 +439,7 @@ class MemoryService:
438
439
  retrieval_profile=retrieval_profile,
439
440
  allow_sensitive=allow_sensitive,
440
441
  scope_allowlist=scope_allowlist,
442
+ query_type=query_type,
441
443
  )
442
444
  return [row["claim"] for row in rows]
443
445
 
@@ -552,6 +554,7 @@ class MemoryService:
552
554
  scope_allowlist: list[str] | None = None,
553
555
  enrich_with_entities: bool = False,
554
556
  requesting_agent: str | None = None,
557
+ query_type: str | None = None,
555
558
  ) -> list[dict[str, Any]]:
556
559
  if limit <= 0:
557
560
  return []
@@ -603,6 +606,7 @@ class MemoryService:
603
606
  limit=rank_limit,
604
607
  vector_hook=vector_hook,
605
608
  semantic_vectors=semantic,
609
+ query_type=query_type,
606
610
  )
607
611
  ranked_rows = _rerank_with_profile(
608
612
  ranked_rows,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: memorymaster
3
- Version: 3.17.1
3
+ Version: 3.18.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
@@ -308,6 +308,7 @@ tests/test_recall_vector_fallback.py
308
308
  tests/test_reliability_hardening.py
309
309
  tests/test_resolvers_concurrent_supersede.py
310
310
  tests/test_retrieval_profile.py
311
+ tests/test_retrieval_profiles.py
311
312
  tests/test_retrieval_rrf_tiebreaker.py
312
313
  tests/test_retrieval_weights.py
313
314
  tests/test_review.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "memorymaster"
7
- version = "3.17.1"
7
+ version = "3.18.0"
8
8
  description = "Production-grade memory reliability system for AI coding agents. Lifecycle-managed claims with citations, conflict detection, steward governance, and MCP integration."
9
9
  license = {text = "MIT"}
10
10
  authors = [{name = "wolverin0"}]
@@ -37,6 +37,7 @@ OPENAI_CHAT_URL = "https://api.openai.com/v1/chat/completions"
37
37
  GEMINI_GENERATE_URL = "https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent"
38
38
  OPENAI_JUDGE_MODEL = "gpt-4o"
39
39
  GEMINI_FALLBACK_MODEL = "gemini-2.5-flash"
40
+ CLAUDE_CLI_JUDGE_MODEL = "claude-haiku-4-5-20251001"
40
41
  DEFAULT_JUDGE = "sonnet"
41
42
  DEFAULT_JUDGE_PACING_SECONDS = 1.0
42
43
  DEFAULT_QA_MAX_SECONDS = 90 * 60
@@ -126,6 +127,8 @@ class JudgeClient:
126
127
  if not self.openai_api_key:
127
128
  raise RuntimeError("OPENAI_API_KEY is not set")
128
129
  return call_openai_chat(prompt, self.openai_api_key, max_tokens=max_tokens, temperature=temperature)
130
+ if provider == "claude_cli":
131
+ return call_claude_cli_judge(prompt, max_tokens=max_tokens, temperature=temperature)
129
132
  raise ValueError(f"Unknown judge provider: {provider}")
130
133
 
131
134
  def _record(self, response: LLMResponse) -> None:
@@ -148,6 +151,8 @@ class JudgeClient:
148
151
  return "gemini-2.5-flash"
149
152
  if self.models_used == {ANTHROPIC_JUDGE_MODEL}:
150
153
  return "sonnet"
154
+ if self.models_used == {CLAUDE_CLI_JUDGE_MODEL}:
155
+ return "claude_cli"
151
156
  return "mixed"
152
157
 
153
158
  @staticmethod
@@ -158,6 +163,10 @@ class JudgeClient:
158
163
  return ["gpt-4o", "gemini", "sonnet"]
159
164
  if primary == "gemini":
160
165
  return ["gemini", "sonnet", "gpt-4o"]
166
+ if primary == "claude_cli":
167
+ # OAuth-only via local Claude Code binary; no API keys needed.
168
+ # Fall back to API providers only if explicit keys are present.
169
+ return ["claude_cli", "gpt-4o", "gemini", "sonnet"]
161
170
  raise ValueError(f"Unknown judge: {primary}")
162
171
 
163
172
  @staticmethod
@@ -166,6 +175,8 @@ class JudgeClient:
166
175
  return ANTHROPIC_JUDGE_MODEL
167
176
  if provider == "gemini":
168
177
  return GEMINI_FALLBACK_MODEL
178
+ if provider == "claude_cli":
179
+ return CLAUDE_CLI_JUDGE_MODEL
169
180
  return OPENAI_JUDGE_MODEL
170
181
 
171
182
 
@@ -256,7 +267,13 @@ def ingest_haystack(service: MemoryService, item: dict[str, Any], *, chunk_chars
256
267
  )
257
268
 
258
269
 
259
- def query_memory(service: MemoryService, question: str, top_k: int = 10) -> list[dict[str, Any]]:
270
+ def query_memory(
271
+ service: MemoryService,
272
+ question: str,
273
+ top_k: int = 10,
274
+ *,
275
+ query_type: str | None = None,
276
+ ) -> list[dict[str, Any]]:
260
277
  service_limit = top_k if llm_rerank_available() else top_k * 3
261
278
  return service.query_rows(
262
279
  query_text=question,
@@ -265,6 +282,7 @@ def query_memory(service: MemoryService, question: str, top_k: int = 10) -> list
265
282
  retrieval_mode="hybrid",
266
283
  scope_allowlist=[BENCH_SCOPE],
267
284
  allow_sensitive=True,
285
+ query_type=query_type,
268
286
  )
269
287
 
270
288
 
@@ -370,7 +388,12 @@ def run_retrieval(
370
388
  service = init_ephemeral_service(Path(tmp), embedding_provider=embedding_provider)
371
389
  try:
372
390
  ingest_haystack(service, item, chunk_chars=chunk_chars)
373
- rows = query_memory(service, str(item["question"]), top_k=10)
391
+ rows = query_memory(
392
+ service,
393
+ str(item["question"]),
394
+ top_k=10,
395
+ query_type=str(item.get("question_type") or "") or None,
396
+ )
374
397
  results.append(score_retrieval(item, rows))
375
398
  finally:
376
399
  del service
@@ -632,6 +655,43 @@ def call_anthropic_sonnet_requests(
632
655
  )
633
656
 
634
657
 
658
+ def call_claude_cli_judge(
659
+ prompt: str,
660
+ *,
661
+ max_tokens: int,
662
+ temperature: float = 0.0,
663
+ ) -> LLMResponse:
664
+ """OAuth-via-CLI judge — wraps memorymaster.llm_provider._call_claude_cli.
665
+
666
+ Routes the judge prompt through the user's local `claude --print` binary so
667
+ the bench runs against a Claude Code subscription instead of api.anthropic.com.
668
+ No ANTHROPIC_API_KEY required. Per-call cold-start latency ~3-15s; budget
669
+ accordingly for full runs (~500 questions × 2 calls each).
670
+
671
+ `max_tokens` and `temperature` are accepted for signature parity with the
672
+ HTTP providers; the CLI does not honour them per-call (model defaults apply).
673
+ """
674
+ # Local import — keeps the bench importable even if memorymaster is
675
+ # partially broken during dev. The provider helper handles binary discovery,
676
+ # timeouts, and Windows console suppression.
677
+ from memorymaster.llm_provider import _call_claude_cli
678
+
679
+ # Pin the model the bench reports via env, so judge_used_label stays stable.
680
+ os.environ.setdefault("MEMORYMASTER_LLM_MODEL", CLAUDE_CLI_JUDGE_MODEL)
681
+ text = _call_claude_cli(prompt, "").strip()
682
+ if not text:
683
+ raise RuntimeError(
684
+ "claude_cli judge returned empty output — check claude binary on PATH "
685
+ "and OAuth session validity"
686
+ )
687
+ return LLMResponse(
688
+ text=text,
689
+ model=CLAUDE_CLI_JUDGE_MODEL,
690
+ provider="claude_cli",
691
+ tokens=0,
692
+ )
693
+
694
+
635
695
  def answer_question(question: str, contexts: list[str], judge: JudgeClient) -> str:
636
696
  prompt = "\n\n".join(
637
697
  [
@@ -669,7 +729,8 @@ def run_full(
669
729
  anthropic_key = os.environ.get("ANTHROPIC_API_KEY", "").strip()
670
730
  openai_key = os.environ.get("OPENAI_API_KEY", "").strip()
671
731
  gemini_key = os.environ.get("GEMINI_API_KEY", "").strip()
672
- if not anthropic_key and not openai_key and not gemini_key:
732
+ # claude_cli judge runs entirely via local OAuth — no API keys required.
733
+ if judge_name != "claude_cli" and not anthropic_key and not openai_key and not gemini_key:
673
734
  print("[full] no ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY; deferring QA")
674
735
  return {
675
736
  "mode": mode,
@@ -849,9 +910,9 @@ def parse_args() -> argparse.Namespace:
849
910
  parser.add_argument("--qa-output", type=Path, default=QA_OUTPUT, help="QA-only output JSON path")
850
911
  parser.add_argument(
851
912
  "--judge",
852
- choices=["sonnet", "gpt-4o", "gemini"],
913
+ choices=["sonnet", "gpt-4o", "gemini", "claude_cli"],
853
914
  default=DEFAULT_JUDGE,
854
- help="Primary judge model; default sonnet",
915
+ help="Primary judge model; default sonnet. claude_cli uses local OAuth (no API key)",
855
916
  )
856
917
  parser.add_argument(
857
918
  "--judge-pacing-seconds",
@@ -0,0 +1,142 @@
1
+ """S3 regression tests — per-question-type retrieval weight profiles.
2
+
3
+ Verifies:
4
+ 1. With NO profile env var set, query_type is a no-op (back-compat).
5
+ 2. With a per-type profile env var set, _compute_claim_score swaps the
6
+ weight tuple for queries of that type.
7
+ 3. query_type that does NOT match any configured profile falls back to
8
+ the global retrieval_weights (default behaviour preserved).
9
+ 4. The env-var slug mapping (UPPER_SNAKE -> lower-hyphen) round-trips
10
+ correctly so LongMemEval-S labels like 'single-session-preference'
11
+ are reachable via MEMORYMASTER_RETRIEVAL_PROFILE_SINGLE_SESSION_PREFERENCE.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import pytest
16
+
17
+ from memorymaster.config import reset_config, get_config
18
+ from memorymaster.models import Claim
19
+ from memorymaster.retrieval import rank_claim_rows
20
+
21
+
22
+ @pytest.fixture(autouse=True)
23
+ def _reset_config():
24
+ reset_config()
25
+ yield
26
+ reset_config()
27
+
28
+
29
+ def _claim() -> Claim:
30
+ return Claim(
31
+ id=1,
32
+ text="alpha beta retrieval target",
33
+ idempotency_key=None,
34
+ normalized_text=None,
35
+ claim_type=None,
36
+ subject=None,
37
+ predicate=None,
38
+ object_value=None,
39
+ scope="project",
40
+ volatility="medium",
41
+ status="confirmed",
42
+ confidence=0.8,
43
+ pinned=False,
44
+ supersedes_claim_id=None,
45
+ replaced_by_claim_id=None,
46
+ created_at="2999-01-01T00:00:00+00:00",
47
+ updated_at="2999-01-01T00:00:00+00:00",
48
+ last_validated_at=None,
49
+ archived_at=None,
50
+ )
51
+
52
+
53
+ def _rank(*, semantic_vectors: bool, query_type: str | None = None):
54
+ def vector_hook(query, claims):
55
+ return {c.id: 0.6 for c in claims}
56
+
57
+ return rank_claim_rows(
58
+ "alpha beta",
59
+ [_claim()],
60
+ mode="hybrid",
61
+ limit=1,
62
+ vector_hook=vector_hook,
63
+ semantic_vectors=semantic_vectors,
64
+ query_type=query_type,
65
+ )[0]
66
+
67
+
68
+ def test_query_type_without_profile_is_noop():
69
+ """Passing query_type when no profile env var is set must not change
70
+ scores — back-compat with all existing callers."""
71
+ default = _rank(semantic_vectors=False)
72
+ typed = _rank(semantic_vectors=False, query_type="single-session-preference")
73
+ assert typed.score == pytest.approx(default.score)
74
+
75
+
76
+ def test_profile_env_var_overrides_default_weights(monkeypatch):
77
+ """When a profile env var matches the query_type, weights swap.
78
+
79
+ Default vec-enabled weights: (lex=0.30, conf=0.20, fresh=0.10, vec=0.40).
80
+ Profile under test: (lex=0.10, conf=0.10, fresh=0.10, vec=0.70) — heavy
81
+ on vector, which is the predicted direction for ``single-session-preference``
82
+ where lexical matching is structurally weak (preferences are paraphrased).
83
+ """
84
+ monkeypatch.setenv(
85
+ "MEMORYMASTER_RETRIEVAL_PROFILE_SINGLE_SESSION_PREFERENCE",
86
+ "0.10,0.10,0.10,0.70",
87
+ )
88
+ reset_config()
89
+
90
+ cfg = get_config()
91
+ assert cfg.retrieval_profile("single-session-preference") == (0.10, 0.10, 0.10, 0.70)
92
+
93
+ default = _rank(semantic_vectors=False)
94
+ typed = _rank(semantic_vectors=False, query_type="single-session-preference")
95
+ assert typed.score != default.score
96
+
97
+
98
+ def test_profile_does_not_leak_to_other_query_types(monkeypatch):
99
+ """Profile under one type must not affect queries with a different type
100
+ (or with no type at all)."""
101
+ monkeypatch.setenv(
102
+ "MEMORYMASTER_RETRIEVAL_PROFILE_SINGLE_SESSION_PREFERENCE",
103
+ "0.10,0.10,0.10,0.70",
104
+ )
105
+ reset_config()
106
+
107
+ default = _rank(semantic_vectors=False)
108
+ other_type = _rank(semantic_vectors=False, query_type="multi-session")
109
+ none_type = _rank(semantic_vectors=False, query_type=None)
110
+
111
+ assert other_type.score == pytest.approx(default.score)
112
+ assert none_type.score == pytest.approx(default.score)
113
+
114
+
115
+ def test_profile_slug_round_trips_underscores_to_hyphens(monkeypatch):
116
+ """Env var SINGLE_SESSION_PREFERENCE must be reachable as the canonical
117
+ bench label 'single-session-preference'."""
118
+ monkeypatch.setenv(
119
+ "MEMORYMASTER_RETRIEVAL_PROFILE_TEMPORAL_REASONING",
120
+ "0.20,0.10,0.40,0.30",
121
+ )
122
+ reset_config()
123
+
124
+ cfg = get_config()
125
+ assert cfg.retrieval_profile("temporal-reasoning") == (0.20, 0.10, 0.40, 0.30)
126
+ # And the env-form lookup (uppercased, underscored) finds nothing — only
127
+ # the canonical lower-hyphen form is the key.
128
+ assert cfg.retrieval_profile("TEMPORAL_REASONING") is None
129
+
130
+
131
+ def test_profile_works_in_semantic_path(monkeypatch):
132
+ """The semantic_vectors=True branch must also honour the profile —
133
+ same blend formula, just different signal source."""
134
+ monkeypatch.setenv(
135
+ "MEMORYMASTER_RETRIEVAL_PROFILE_SINGLE_SESSION_PREFERENCE",
136
+ "0.10,0.10,0.10,0.70",
137
+ )
138
+ reset_config()
139
+
140
+ default = _rank(semantic_vectors=True)
141
+ typed = _rank(semantic_vectors=True, query_type="single-session-preference")
142
+ assert typed.score != default.score
File without changes
File without changes