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.
- {memorymaster-3.23.0/memorymaster.egg-info → memorymaster-3.25.0}/PKG-INFO +2 -2
- {memorymaster-3.23.0 → memorymaster-3.25.0}/README.md +1 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/__init__.py +1 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-auto-ingest.py +27 -31
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/contradiction_probe.py +6 -2
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_cache.py +40 -9
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rule_miner.py +26 -3
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/security.py +21 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/service.py +12 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward.py +9 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_store.py +142 -133
- {memorymaster-3.23.0 → memorymaster-3.25.0/memorymaster.egg-info}/PKG-INFO +2 -2
- {memorymaster-3.23.0 → memorymaster-3.25.0}/pyproject.toml +1 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/bench_longmemeval.py +42 -3
- memorymaster-3.25.0/tests/test_auto_ingest_hook_citations.py +102 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_cache.py +26 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rule_miner.py +21 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_t07.py +42 -1
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_contradiction_phase.py +70 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_store_qdrant.py +28 -0
- memorymaster-3.23.0/tests/test_auto_ingest_hook_citations.py +0 -147
- {memorymaster-3.23.0 → memorymaster-3.25.0}/LICENSE +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/artifacts/bm25-per-field-eval-harness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/longmemeval_runner.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/longmemeval_vector_runner.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/benchmarks/perf_smoke.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/__main__.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_lifecycle.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_read.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_shared.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_sources.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/_storage_write_claims.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/access_control.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/action_exporters.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/action_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/atlas_claim_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/atlas_contract.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/auto_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/auto_resolver.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/candidate_dedupe.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/claim_edges.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/claim_verifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_handlers_basic.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_handlers_curation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/cli_helpers.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/closets.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/claude-md-append.md +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/codex-agents-md-append.md +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-classify.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-dream-sync.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-precompact.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-recall.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-session-start.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-steward-cycle.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/config_templates/hooks/memorymaster-validate-wiki.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/conflict_resolver.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/connectors/__init__.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/connectors/whatsapp.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/context_hook.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/context_optimizer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/daily_notes.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dashboard.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dashboard_auth.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/db_merge.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/delta_sync.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/dream_bridge.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/embeddings.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_graph.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/entity_registry.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/federated_graphify.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/feedback.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/graph_store.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/hook_log.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/__init__.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/calibration.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/compact_summaries.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/compactor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/daydream_ingest.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/decay.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/dedup.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/deterministic.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/entity_graph_export.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/staleness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/jobs/validator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/key_rotator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/lifecycle.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_budget.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_provider.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_rerank.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/llm_steward.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_path_policy.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_server.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/mcp_usage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/media_processing.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/media_providers.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/metrics_exporter.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0001_initial.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0002_miner_state.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0003_contradiction_verdicts.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/0004_query_cache.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/__init__.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/migrations/runner.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/models.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/observability.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/operator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/operator_queue.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/plugins.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/policy.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/postgres_store.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qdrant_backend.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qdrant_recall_fallback.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/qmd_bridge.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/query_expansion.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/recall_fusion.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/recall_tokenizer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/retrieval.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/retry.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/review.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rl_trainer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/rules.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/scheduler.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema.sql +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/schema_postgres.sql +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/scope_utils.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/session_tracker.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/setup_hooks.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/skill_evolver.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/snapshot.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/steward_features.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/storage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/store_factory.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/transcript_miner.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/turn_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_bases.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_curator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_exporter.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_linter.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_log.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_query_capture.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/vault_synthesis.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_cleanup.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/verbatim_recall.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/webhook.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_engine.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_freshness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_similarity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_suggest.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster/wiki_validate.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/SOURCES.txt +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/dependency_links.txt +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/entry_points.txt +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/requires.txt +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/memorymaster.egg-info/top_level.txt +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/agg_recall_latency.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/alert_operator_metrics.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/audit_dedupe_precision.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/autoresearch_daemon.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_entity_extraction.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_graph_store.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backfill_stop_hook_citations.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/backtest_steward_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/build_steward_training_set.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/check_hook_template_drift.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/claude_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/codex_live_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_edge_cases.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_trace_report.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/compaction_trace_validate.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/confusion_matrix_eval.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/conversation_importer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/conversation_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/e2e_operator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/email_live_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_bm25_sweep.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_classify_f1.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_memorymaster.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_recall_precision_at_5.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_recall_quality.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_steward_pareto.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/eval_verbatim_recall.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/expand_recall_eval.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/generate_drill_signoff.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/git_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/github_live_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/gitnexus_to_claims.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/grid_recall_weights.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/index_claims_to_qdrant.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/ingest_planning_docs.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/jira_live_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/label_prompts_with_judge.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/llm_benchmark.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/measure_dedupe_thresholds.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/merge_scope_variants.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/messages_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/operator_metrics.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/precompute_candidates.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/recurring_incident_drill.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/release_readiness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/run_codex_autologger.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/run_incident_drill.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/scheduled_ingest.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/setup-hooks.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/slack_live_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/sync_hook_templates.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/tickets_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/train_steward_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/scripts/webhook_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/setup.cfg +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/conftest.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/integration/test_extract_llm_ollama_live.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_access_control.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_action_exporters.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_action_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_claim_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_contract.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_atlas_source_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_ingest_hook_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_resolver.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_auto_validate.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_backend_parity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_bm25_per_field.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_calibration.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_calibration_priors_applied.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_candidate_dedupe.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_edges.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_links.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claim_type_ranking.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_classify_hook_f1.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_classify_hook_latency.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_claude_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_dry_run.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_json_flag.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_ready.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_review_queue.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_cli_subcommands.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_closets.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_closets_recall_integration.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compact_summaries.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compact_summaries_sensitivity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compaction_trace.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_compactor_artifact_order.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_config.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_conflict_resolver.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_confusion_matrix_eval.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_connection_retry.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_connectors.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_hook.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_optimizer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_context_optimizer_provider.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_contradiction_probe.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_conversation_to_turns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_auth.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_latency.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_lineage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dashboard_review_queue.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_daydream_ingest.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_db_merge_confidence_conflict.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_db_merge_coverage_v2.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_decay_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_decay_respects_pinned.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup_cli.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dedup_conflict_disambiguation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_delta_sync.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_deterministic_predicates.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dream_bridge_coverage_v2.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_dream_bridge_sensitivity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_embeddings_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_extractor.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_extractor_llm.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_graph.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_graph_export.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_new_kinds.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_regex_v3.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_entity_registry.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_eval_harness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_events_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_extract_llm_ollama.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_federated_graphify_mcp.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_federated_query_safety.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_feedback.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_floor_gate.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_fts5_search.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_graph_distance.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_graph_store.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_handler_regressions.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_hook_env_isolation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_human_id.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_incident_drill_runner.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_integration_workflows.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_key_rotator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_lifecycle.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_lifecycle_supersede_invariant.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_budget.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_fallback.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_provider_claude_cli.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_provider_key_rotation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_steward_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_llm_steward_key_rotation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_filter_bypass.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_helpers.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_path_policy.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_rate_limit.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_server_validation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_mcp_usage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_media_processing.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_meta_decisions.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_metrics_exporter.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_migrations.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_observability.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_obsidian_mind_patterns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_operator.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_operator_queue.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_perf_smoke_config.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_plugins.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_policy_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_policy_mode_env.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_postgres_parity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qdrant_backend.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qmd_bridge.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_qrels_regression.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_query_expansion.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_entity_fanout.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_fusion.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_latency.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_precision_at_5.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_tokenizer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_recall_vector_fallback.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_reliability_hardening.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_resolvers_concurrent_supersede.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_profile.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_profiles.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_rrf_tiebreaker.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_retrieval_weights.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_review.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rl_trainer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rrf_auto_gate.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_rule_claims.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scheduler.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scope_boost.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_scope_utils.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_security_access.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_security_patterns.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_adversarial.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sensitivity_filter_adversarial_v2.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_service_coverage.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_session_tracker.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_snapshot.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_snapshot_roundtrip.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_sqlite_core.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_staleness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_stealth_mode.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_classifier.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_daydream_hook.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_features.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_features_v3.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_steward_resolution_parity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_storage_parity.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_store_factory.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_tenant_isolation.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_turn_schema.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_two_pass_recall.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v311_fixes.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v313_e2e.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v313_run_cycle_dedupe.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v390_e2e.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_v391_strict_warnings.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vault_exporter.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vault_linter_orphan.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_vector_search.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_cleanup.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_dedup.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_recall.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_verbatim_store.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_webhook.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_webhook_hmac.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_whatsapp_importer.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_autopromote.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_binding.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_engine_idempotency.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_explored_and_contradictions.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_freshness.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_similarity_multiscope.py +0 -0
- {memorymaster-3.23.0 → memorymaster-3.25.0}/tests/test_wiki_suggest.py +0 -0
- {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.
|
|
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)
|
|
54
54
|
[](https://www.python.org/downloads/)
|
|
55
|
-
[]()
|
|
56
56
|
[]()
|
|
57
57
|
[]()
|
|
58
58
|
[](https://pypi.org/project/memorymaster/)
|
|
@@ -6,7 +6,7 @@ Lifecycle-managed claims with citations, conflict detection, steward governance,
|
|
|
6
6
|
|
|
7
7
|
[](LICENSE)
|
|
8
8
|
[](https://www.python.org/downloads/)
|
|
9
|
-
[]()
|
|
10
10
|
[]()
|
|
11
11
|
[]()
|
|
12
12
|
[](https://pypi.org/project/memorymaster/)
|
|
@@ -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
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
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),
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
*,
|