wavemind 2.2.7__tar.gz → 2.2.8__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 (162) hide show
  1. {wavemind-2.2.7 → wavemind-2.2.8}/PKG-INFO +62 -31
  2. {wavemind-2.2.7 → wavemind-2.2.8}/README.md +61 -30
  3. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/BENCHMARK_LEADERBOARD.md +1 -1
  4. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/BENCHMARK_REPORT.md +1 -1
  5. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/benchmark_matrix_results.json +11 -10
  6. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/benchmark_registry.py +3 -2
  7. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/scale_readiness_benchmark.py +12 -5
  8. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/scale_readiness_results.json +11 -10
  9. {wavemind-2.2.7 → wavemind-2.2.8}/docker-compose.yml +1 -1
  10. {wavemind-2.2.7 → wavemind-2.2.8}/docs/BENCHMARK_BRIEF.md +1 -1
  11. {wavemind-2.2.7 → wavemind-2.2.8}/docs/ROADMAP.md +8 -6
  12. {wavemind-2.2.7 → wavemind-2.2.8}/pyproject.toml +1 -1
  13. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_cli_smoke.py +68 -0
  14. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_jobs.py +85 -0
  15. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_scale_readiness_benchmark.py +1 -0
  16. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/__init__.py +11 -2
  17. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/cli.py +87 -1
  18. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/jobs.py +100 -0
  19. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/replication.py +13 -0
  20. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/PKG-INFO +62 -31
  21. {wavemind-2.2.7 → wavemind-2.2.8}/CONTRIBUTING.md +0 -0
  22. {wavemind-2.2.7 → wavemind-2.2.8}/Dockerfile +0 -0
  23. {wavemind-2.2.7 → wavemind-2.2.8}/LICENSE +0 -0
  24. {wavemind-2.2.7 → wavemind-2.2.8}/MANIFEST.in +0 -0
  25. {wavemind-2.2.7 → wavemind-2.2.8}/SECURITY.md +0 -0
  26. {wavemind-2.2.7 → wavemind-2.2.8}/SUPPORT.md +0 -0
  27. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/agent_memory_benchmark.py +0 -0
  28. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/agent_memory_results.json +0 -0
  29. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/ann_index_curve_benchmark.py +0 -0
  30. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/ann_index_curve_results.json +0 -0
  31. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/dynamic_memory_benchmark.py +0 -0
  32. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/dynamic_memory_results.json +0 -0
  33. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/field_memory_dynamics_benchmark.py +0 -0
  34. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/field_memory_dynamics_results.json +0 -0
  35. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/locomo_evidence_results.json +0 -0
  36. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/locomo_memory_benchmark.py +0 -0
  37. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/locomo_sentence_evidence_results.json +0 -0
  38. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/long_memory_evidence_benchmark.py +0 -0
  39. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/long_memory_evidence_results.json +0 -0
  40. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_answer_benchmark.py +0 -0
  41. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_answer_extractive_20_results.json +0 -0
  42. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_answer_qwen25_0_5b_50_results.json +0 -0
  43. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_answer_qwen25_1_5b_50_results.json +0 -0
  44. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_evidence_50_results.json +0 -0
  45. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_evidence_results.json +0 -0
  46. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/longmemeval_memory_benchmark.py +0 -0
  47. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/memory_competitor_benchmark.py +0 -0
  48. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/memory_competitor_results.json +0 -0
  49. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/nomiracl_russian_benchmark.py +0 -0
  50. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/nomiracl_russian_results.json +0 -0
  51. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/open_retrieval_benchmark.py +0 -0
  52. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/open_retrieval_scifact_results.json +0 -0
  53. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_index_profile_results.json +0 -0
  54. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_benchmark.py +0 -0
  55. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_qdrant_100k_tuned_results.json +0 -0
  56. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_qdrant_1m_ef_sweep_results.json +0 -0
  57. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_qdrant_1m_results.json +0 -0
  58. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_qdrant_1m_tuned_results.json +0 -0
  59. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/production_load_results.json +0 -0
  60. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/render_benchmark_charts.py +0 -0
  61. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/render_benchmark_leaderboard.py +0 -0
  62. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/render_benchmark_report.py +0 -0
  63. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/ru_sentences_benchmark.py +0 -0
  64. {wavemind-2.2.7 → wavemind-2.2.8}/benchmarks/wavemind_capacity_results.json +0 -0
  65. {wavemind-2.2.7 → wavemind-2.2.8}/docs/CHROMA_MIGRATION.md +0 -0
  66. {wavemind-2.2.7 → wavemind-2.2.8}/docs/DEMO_SCRIPT.md +0 -0
  67. {wavemind-2.2.7 → wavemind-2.2.8}/docs/LAUNCH_KIT.md +0 -0
  68. {wavemind-2.2.7 → wavemind-2.2.8}/docs/OBSERVABILITY.md +0 -0
  69. {wavemind-2.2.7 → wavemind-2.2.8}/docs/PROJECT_BOARD.md +0 -0
  70. {wavemind-2.2.7 → wavemind-2.2.8}/docs/RELEASE.md +0 -0
  71. {wavemind-2.2.7 → wavemind-2.2.8}/docs/RU_LAUNCH_POSTS.md +0 -0
  72. {wavemind-2.2.7 → wavemind-2.2.8}/docs/USE_CASES.md +0 -0
  73. {wavemind-2.2.7 → wavemind-2.2.8}/docs/assets/benchmark-summary.svg +0 -0
  74. {wavemind-2.2.7 → wavemind-2.2.8}/docs/assets/wavemind-demo.gif +0 -0
  75. {wavemind-2.2.7 → wavemind-2.2.8}/docs/assets/wavemind-social-card.svg +0 -0
  76. {wavemind-2.2.7 → wavemind-2.2.8}/examples/agent_with_memory.py +0 -0
  77. {wavemind-2.2.7 → wavemind-2.2.8}/examples/chroma_migration.py +0 -0
  78. {wavemind-2.2.7 → wavemind-2.2.8}/examples/customer_support_memory.py +0 -0
  79. {wavemind-2.2.7 → wavemind-2.2.8}/examples/demo.py +0 -0
  80. {wavemind-2.2.7 → wavemind-2.2.8}/examples/dynamic_memory_demo.py +0 -0
  81. {wavemind-2.2.7 → wavemind-2.2.8}/examples/framework_integrations.py +0 -0
  82. {wavemind-2.2.7 → wavemind-2.2.8}/examples/langchain_memory.py +0 -0
  83. {wavemind-2.2.7 → wavemind-2.2.8}/examples/llamaindex_retriever.py +0 -0
  84. {wavemind-2.2.7 → wavemind-2.2.8}/examples/observability/README.md +0 -0
  85. {wavemind-2.2.7 → wavemind-2.2.8}/examples/observability/docker-compose.yml +0 -0
  86. {wavemind-2.2.7 → wavemind-2.2.8}/examples/observability/otel-collector.yaml +0 -0
  87. {wavemind-2.2.7 → wavemind-2.2.8}/examples/observability/prometheus-alerts.yml +0 -0
  88. {wavemind-2.2.7 → wavemind-2.2.8}/examples/observability/prometheus.yml +0 -0
  89. {wavemind-2.2.7 → wavemind-2.2.8}/examples/production-index-profile/README.md +0 -0
  90. {wavemind-2.2.7 → wavemind-2.2.8}/examples/production-index-profile/docker-compose.yml +0 -0
  91. {wavemind-2.2.7 → wavemind-2.2.8}/examples/research_notebook_memory.py +0 -0
  92. {wavemind-2.2.7 → wavemind-2.2.8}/examples/sharded_memory.py +0 -0
  93. {wavemind-2.2.7 → wavemind-2.2.8}/install.bat +0 -0
  94. {wavemind-2.2.7 → wavemind-2.2.8}/install.sh +0 -0
  95. {wavemind-2.2.7 → wavemind-2.2.8}/requirements-optional.txt +0 -0
  96. {wavemind-2.2.7 → wavemind-2.2.8}/requirements.txt +0 -0
  97. {wavemind-2.2.7 → wavemind-2.2.8}/setup.cfg +0 -0
  98. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_agent_memory_benchmark.py +0 -0
  99. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_ann_index_curve_benchmark.py +0 -0
  100. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_api.py +0 -0
  101. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_api_process_persistence.py +0 -0
  102. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_benchmark_brief.py +0 -0
  103. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_benchmark_charts.py +0 -0
  104. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_benchmark_leaderboard.py +0 -0
  105. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_benchmark_registry.py +0 -0
  106. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_benchmark_report.py +0 -0
  107. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_chroma_migration_example.py +0 -0
  108. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_cluster.py +0 -0
  109. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_core_persistence.py +0 -0
  110. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_dynamic_memory_benchmark.py +0 -0
  111. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_examples.py +0 -0
  112. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_field_graph.py +0 -0
  113. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_field_graph_integration.py +0 -0
  114. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_field_memory_dynamics_benchmark.py +0 -0
  115. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_framework_adapters.py +0 -0
  116. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_import_benchmark.py +0 -0
  117. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_indexes_encoders.py +0 -0
  118. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_langchain_integration.py +0 -0
  119. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_locomo_memory_benchmark.py +0 -0
  120. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_long_memory_evidence_benchmark.py +0 -0
  121. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_longmemeval_answer_benchmark.py +0 -0
  122. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_longmemeval_memory_benchmark.py +0 -0
  123. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_memory_competitor_benchmark.py +0 -0
  124. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_multimodal.py +0 -0
  125. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_nomiracl_russian_benchmark.py +0 -0
  126. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_observability.py +0 -0
  127. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_observability_docs.py +0 -0
  128. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_open_retrieval_benchmark.py +0 -0
  129. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_packaging_files.py +0 -0
  130. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_postgres_storage.py +0 -0
  131. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_production_index_profile.py +0 -0
  132. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_production_load_benchmark.py +0 -0
  133. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_replication.py +0 -0
  134. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_scale_plan.py +0 -0
  135. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_semantic_and_latency.py +0 -0
  136. {wavemind-2.2.7 → wavemind-2.2.8}/tests/test_sharding.py +0 -0
  137. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/__main__.py +0 -0
  138. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/api.py +0 -0
  139. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/benchmark.py +0 -0
  140. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/cluster.py +0 -0
  141. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/core.py +0 -0
  142. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/encoders.py +0 -0
  143. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/field_graph.py +0 -0
  144. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/importers.py +0 -0
  145. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/indexes.py +0 -0
  146. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/__init__.py +0 -0
  147. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/autogen.py +0 -0
  148. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/crewai.py +0 -0
  149. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/langchain.py +0 -0
  150. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/langgraph.py +0 -0
  151. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/integrations/llamaindex.py +0 -0
  152. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/multimodal.py +0 -0
  153. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/observability.py +0 -0
  154. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/scale.py +0 -0
  155. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/sharding.py +0 -0
  156. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/storage.py +0 -0
  157. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind/studio.py +0 -0
  158. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/SOURCES.txt +0 -0
  159. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/dependency_links.txt +0 -0
  160. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/entry_points.txt +0 -0
  161. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/requires.txt +0 -0
  162. {wavemind-2.2.7 → wavemind-2.2.8}/wavemind.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wavemind
3
- Version: 2.2.7
3
+ Version: 2.2.8
4
4
  Summary: Local-first dynamic memory field with vector search and wave-field re-ranking
5
5
  License-Expression: MIT
6
6
  Project-URL: Homepage, https://github.com/CaspianG/wavemind
@@ -543,10 +543,10 @@ Checked-in result:
543
543
  |---|---:|
544
544
  | Cluster planner | 4096 namespaces, 4 nodes, replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, write quorum `2`. |
545
545
  | Hot cache | 2000 lookups, hit rate `0.920`, p99 lookup `0.003 ms`. |
546
- | Replicated runtime | 3 physical WaveMind stores, replication factor 3, write quorum 2, node-loss recall `true`, repair copied `1` missing record, tombstone repair deleted `1` stale record, p99 query-after-loss `1.29 ms`. |
547
- | Active-active delta sync | 2 regions, bidirectional convergence `true`, stale import suppressed after delete `true`, tombstone convergence `true`, sync `112.50 ms`. |
548
- | Replicated snapshot | 3 replica files, manifest checksum validation `true`, restore `11.42 ms`, recall after restored-primary loss `true`. |
549
- | Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.67 ms`. |
546
+ | Replicated runtime | 3 physical WaveMind stores, replication factor 3, write quorum 2, node-loss recall `true`, repair copied `1` missing record, tombstone repair deleted `1` stale record, p99 query-after-loss `1.35 ms`. |
547
+ | Active-active delta sync | 2 regions, bidirectional convergence `true`, stale import suppressed after delete `true`, tombstone convergence `true`, sync `103.42 ms`. |
548
+ | Replicated snapshot job | 3 replica files, manifest checksum validation `true`, offsite mirror validation `true`, restore `7.10 ms`, recall after restored-primary loss `true`. |
549
+ | Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.59 ms`. |
550
550
 
551
551
  This profile validates routing, quorum-replicated runtime behavior, cache
552
552
  behavior, active-active namespace delta sync, replicated snapshot/restore, and
@@ -575,16 +575,18 @@ should still use a production database or service layer.
575
575
 
576
576
  The same planner is available over HTTP as `POST /cluster-plan`.
577
577
 
578
- Maintenance worker:
578
+ Maintenance workers:
579
579
 
580
580
  ```sh
581
581
  wavemind maintenance --namespace user:42 --consolidate-steps 10 --consolidate-concepts --json
582
+ wavemind replicated-snapshot --root ./state/replicas --node node-a --node node-b --node node-c --out ./backups/replicated --offsite ./offsite/replicated --keep-last 7 --json
582
583
  ```
583
584
 
584
- This runs one deterministic maintenance pass: expired-memory purge, optional
585
- field/concept consolidation, and index-health repair. Production deployments can
586
- call the same command from cron, systemd, Kubernetes CronJobs, Celery, RQ, or
587
- Temporal.
585
+ The first command runs one deterministic memory pass: expired-memory purge,
586
+ optional field/concept consolidation, and index-health repair. The second
587
+ command creates a verified replicated snapshot, mirrors it to an offsite path,
588
+ and applies retention. Production deployments can call these commands from
589
+ cron, systemd, Kubernetes CronJobs, Celery, RQ, or Temporal.
588
590
 
589
591
  Hot-cache options:
590
592
 
@@ -674,7 +676,7 @@ backup command.
674
676
  Replicated runtime snapshot/restore:
675
677
 
676
678
  ```python
677
- from wavemind import HashingTextEncoder, ReplicatedWaveMind
679
+ from wavemind import HashingTextEncoder, ReplicatedSnapshotWorker, ReplicatedWaveMind
678
680
 
679
681
  memory = ReplicatedWaveMind(
680
682
  root_path="./state/replicas",
@@ -684,20 +686,43 @@ memory = ReplicatedWaveMind(
684
686
  )
685
687
  memory.remember("Tenant A prefers short support replies.", namespace="tenant:a")
686
688
 
687
- snapshot = memory.snapshot("./backups/replicated")
688
- assert ReplicatedWaveMind.verify_snapshot(snapshot.snapshot_path)["healthy"]
689
+ snapshot_job = ReplicatedSnapshotWorker(memory).run_once(
690
+ destination="./backups/replicated",
691
+ offsite_destination="./offsite/replicated",
692
+ keep_last=7,
693
+ )
694
+ assert snapshot_job.ok
689
695
 
690
696
  restored, report = ReplicatedWaveMind.restore_snapshot(
691
- snapshot.snapshot_path,
697
+ snapshot_job.offsite_path,
692
698
  "./state/restored-replicas",
693
699
  encoder=HashingTextEncoder(vector_dim=64),
694
700
  )
695
701
  ```
696
702
 
697
- The replicated snapshot writes one SQLite backup per replica plus
703
+ The replicated snapshot job writes one SQLite backup per replica plus
698
704
  `manifest.json` with SHA-256 checksums, replica metadata, quorum settings, and
699
- node definitions. Restore refuses to overwrite a non-empty root unless
700
- `overwrite=True` is passed.
705
+ node definitions. It can mirror the snapshot to a second path for offsite
706
+ backup and applies `keep_last` retention locally and offsite. Restore refuses to
707
+ overwrite a non-empty root unless `overwrite=True` is passed.
708
+
709
+ Equivalent CLI:
710
+
711
+ ```sh
712
+ wavemind replicated-snapshot \
713
+ --root ./state/replicas \
714
+ --node node-a --node node-b --node node-c \
715
+ --out ./backups/replicated \
716
+ --offsite ./offsite/replicated \
717
+ --keep-last 7 \
718
+ --json
719
+
720
+ wavemind replicated-restore \
721
+ --from ./offsite/replicated/wavemind-replicated-20260705-120000 \
722
+ --to ./state/restored-replicas \
723
+ --overwrite \
724
+ --json
725
+ ```
701
726
 
702
727
  ## HTTP API
703
728
 
@@ -1072,7 +1097,7 @@ Current read:
1072
1097
  | LongMemEval 50-query smoke | On the first 50 non-abstention LongMemEval-S questions, WaveMind reaches `evidence_recall@5 0.920`, `precision@1 0.760`, and `MRR@5 0.827`; Chroma/Qdrant static reach `0.600`, `0.260`, and `0.385`. | This is the fast regression profile for checking current changes before rerunning the full LongMemEval profile. WaveMind wins on quality; latency still needs work. |
1073
1098
  | ANN/index curve | At 50000 generated 128-d vectors, NumPy exact keeps `recall@10 1.000` at `6.49 ms`; quantized int8 keeps `0.934` at `24.92 ms`; Annoy is faster at `4.92 ms` but drops to `0.730` recall; Qdrant local keeps `1.000` recall at `43.49 ms`. | Current local scale boundary is clear: quantized search needs kernel work, Annoy needs tuning/FAISS, and Qdrant should be tested in service mode for a fair production comparison. |
1074
1099
  | Production load | At 100000 generated 128-d vectors, service-mode Qdrant reaches `recall@10 1.000`, avg `10.28 ms`, p99 `21.26 ms`. At 1M, tuned Qdrant reaches `recall@10 0.984`, avg `116.80 ms`, p99 `209.28 ms`; an EF sweep finds `recall@10 0.977`, avg `64.76 ms`, p99 `103.77 ms` at `hnsw_ef=2048` on 30 queries. | 100k is production-grade on the tested machine. 1M recall is now strong, but p99 still needs tuning before claiming a stable sub-100 ms SLO. |
1075
- | Scale readiness | Deterministic 1M-memory simulation validates 4096 namespace placements over 4 nodes with replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, hot-cache hit rate `0.920`, quorum-replicated runtime recall after node loss, missing-record repair, tombstone repair, active-active delta sync, checksummed replicated snapshot/restore, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, replicated-runtime, namespace-delta, and restore-drill foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
1100
+ | Scale readiness | Deterministic 1M-memory simulation validates 4096 namespace placements over 4 nodes with replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, hot-cache hit rate `0.920`, quorum-replicated runtime recall after node loss, missing-record repair, tombstone repair, active-active delta sync, checksummed replicated snapshot/restore, offsite snapshot verification, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, replicated-runtime, namespace-delta, offsite backup, and restore-drill foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
1076
1101
  | Memory competitor adapters | WaveMind reaches `precision@1 0.80`, `precision@3 1.00`, stale suppression `1.00` on the small adapter profile. Mem0, Zep, and LangGraph are listed as skipped unless their real packages/services are configured. | This prevents fake competitor claims. The adapter harness is ready; real Mem0/Zep/LangGraph results still need configured installs. |
1077
1102
  | LongMemEval local answer generation | With the same local Ollama `qwen2.5:1.5b`, WaveMind reaches `exact_match 0.240`, `contains_answer 0.380`, `token_f1 0.333`, and `evidence_recall@5 0.920`; Chroma and Qdrant static both reach `0.120`, `0.160`, `0.170`, and `0.600`. | This is the first checked-in end-to-end answer benchmark against Chroma/Qdrant. It is still a 50-question lightweight smoke run, not a full LongMemEval leaderboard score. |
1078
1103
 
@@ -1091,7 +1116,7 @@ Current read:
1091
1116
  | Production index profile | Docker-backed 50000-vector profile for persisted FAISS, Qdrant service, and PostgreSQL/pgvector HNSW. | implemented | FAISS / Qdrant service / pgvector | Keep service-mode candidate generation above `0.95` recall@10 and below 10 ms average query latency at 50000 vectors. |
1092
1117
  | Production load profile | 100k and 1M service-backed candidate-index checks with p95/p99 latency. | implemented | Qdrant service / pgvector HNSW / FAISS persisted | Keep 100k at recall@10 `1.000`; push 1M p99 below 100 ms with recall@10 >= 0.95. |
1093
1118
  | Qdrant 1M HNSW ef sweep | One 1M Qdrant collection queried with multiple `hnsw_ef` values. | implemented | Qdrant service | Repeat with 100+ queries and collection-level HNSW build parameters before claiming a stable 1M SLO. |
1094
- | Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, active-active delta sync, replicated snapshot/restore, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication, namespace-delta sync, repair, and restore drills green while adding larger service-backed 10M load tests. |
1119
+ | Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, active-active delta sync, replicated snapshot/restore with offsite verification, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication, namespace-delta sync, repair, offsite backup, and restore drills green while adding larger service-backed 10M load tests. |
1095
1120
  | Memory competitor adapter profile | Dynamic-memory scenario wired for external memory frameworks. | implemented | Mem0 / Zep / LangGraph persistent memory | Report real competitor results only when their packages/services are explicitly configured. |
1096
1121
  | [BEIR](https://github.com/beir-cellar/beir) | Standard zero-shot information retrieval quality. | planned | Chroma / Qdrant / FAISS | Stay within 0.02 `nDCG@10` on identical embeddings. |
1097
1122
  | [MTEB Retrieval](https://github.com/embeddings-benchmark/mteb) | Separates encoder quality from retrieval-store quality. | planned | Chroma / Qdrant / FAISS | Prove WaveMind does not reduce same-embedding retrieval quality. |
@@ -1224,7 +1249,7 @@ For HA-style local or service-mode deployments, `ReplicatedWaveMind` writes each
1224
1249
  namespace to a deterministic replica set and enforces read/write quorum:
1225
1250
 
1226
1251
  ```python
1227
- from wavemind import ReplicatedWaveMind
1252
+ from wavemind import ReplicatedSnapshotWorker, ReplicatedWaveMind
1228
1253
 
1229
1254
  memory = ReplicatedWaveMind(
1230
1255
  root_path="./state/wavemind-replicas",
@@ -1265,21 +1290,26 @@ region_b.import_namespace_delta(region_a.export_namespace_delta("tenant:a"))
1265
1290
  The delta contains active records plus tombstones. Import is idempotent and
1266
1291
  tombstone-aware, so a stale region export cannot resurrect a deleted memory.
1267
1292
 
1268
- For operational recovery, `snapshot()` creates a checksummed replicated snapshot
1269
- and `restore_snapshot()` restores it into a fresh replica root:
1293
+ For operational recovery, `ReplicatedSnapshotWorker` creates a checksummed
1294
+ replicated snapshot, verifies an optional offsite mirror, and
1295
+ `restore_snapshot()` restores it into a fresh replica root:
1270
1296
 
1271
1297
  ```python
1272
- snapshot = memory.snapshot("./backups/replicated")
1273
- health = ReplicatedWaveMind.verify_snapshot(snapshot.snapshot_path)
1298
+ job = ReplicatedSnapshotWorker(memory).run_once(
1299
+ destination="./backups/replicated",
1300
+ offsite_destination="./offsite/replicated",
1301
+ keep_last=7,
1302
+ )
1274
1303
  restored, report = ReplicatedWaveMind.restore_snapshot(
1275
- snapshot.snapshot_path,
1304
+ job.offsite_path,
1276
1305
  "./state/restored-replicas",
1277
1306
  )
1278
1307
  ```
1279
1308
 
1280
- The checked-in scale-readiness profile verifies manifest checksums, restores
1281
- three replica files, then disables the restored primary and confirms the memory
1282
- is still recalled from the remaining replicas.
1309
+ The checked-in scale-readiness profile verifies manifest checksums, verifies the
1310
+ offsite mirror, restores three replica files from that offsite mirror, then
1311
+ disables the restored primary and confirms the memory is still recalled from the
1312
+ remaining replicas.
1283
1313
 
1284
1314
  Checked-in official LoCoMo retrieval result:
1285
1315
 
@@ -1669,9 +1699,10 @@ Near-term priorities:
1669
1699
  OpenClaw, and HTTP-only sidecar use.
1670
1700
  - Faster dynamic re-ranking through smaller candidate windows, caching, and
1671
1701
  background updates.
1672
- - Better production operations: OpenTelemetry is optional and implemented;
1673
- richer latency histograms, index-health metrics, alerting examples, scheduled
1674
- offsite snapshots, and Postgres PITR runbooks are next.
1702
+ - Better production operations: OpenTelemetry and replicated offsite snapshot
1703
+ jobs are implemented; richer latency histograms, index-health metrics,
1704
+ alerting examples, object-store upload adapters, and Postgres PITR runbooks
1705
+ are next.
1675
1706
 
1676
1707
  Longer-term direction:
1677
1708
 
@@ -490,10 +490,10 @@ Checked-in result:
490
490
  |---|---:|
491
491
  | Cluster planner | 4096 namespaces, 4 nodes, replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, write quorum `2`. |
492
492
  | Hot cache | 2000 lookups, hit rate `0.920`, p99 lookup `0.003 ms`. |
493
- | Replicated runtime | 3 physical WaveMind stores, replication factor 3, write quorum 2, node-loss recall `true`, repair copied `1` missing record, tombstone repair deleted `1` stale record, p99 query-after-loss `1.29 ms`. |
494
- | Active-active delta sync | 2 regions, bidirectional convergence `true`, stale import suppressed after delete `true`, tombstone convergence `true`, sync `112.50 ms`. |
495
- | Replicated snapshot | 3 replica files, manifest checksum validation `true`, restore `11.42 ms`, recall after restored-primary loss `true`. |
496
- | Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.67 ms`. |
493
+ | Replicated runtime | 3 physical WaveMind stores, replication factor 3, write quorum 2, node-loss recall `true`, repair copied `1` missing record, tombstone repair deleted `1` stale record, p99 query-after-loss `1.35 ms`. |
494
+ | Active-active delta sync | 2 regions, bidirectional convergence `true`, stale import suppressed after delete `true`, tombstone convergence `true`, sync `103.42 ms`. |
495
+ | Replicated snapshot job | 3 replica files, manifest checksum validation `true`, offsite mirror validation `true`, restore `7.10 ms`, recall after restored-primary loss `true`. |
496
+ | Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.59 ms`. |
497
497
 
498
498
  This profile validates routing, quorum-replicated runtime behavior, cache
499
499
  behavior, active-active namespace delta sync, replicated snapshot/restore, and
@@ -522,16 +522,18 @@ should still use a production database or service layer.
522
522
 
523
523
  The same planner is available over HTTP as `POST /cluster-plan`.
524
524
 
525
- Maintenance worker:
525
+ Maintenance workers:
526
526
 
527
527
  ```sh
528
528
  wavemind maintenance --namespace user:42 --consolidate-steps 10 --consolidate-concepts --json
529
+ wavemind replicated-snapshot --root ./state/replicas --node node-a --node node-b --node node-c --out ./backups/replicated --offsite ./offsite/replicated --keep-last 7 --json
529
530
  ```
530
531
 
531
- This runs one deterministic maintenance pass: expired-memory purge, optional
532
- field/concept consolidation, and index-health repair. Production deployments can
533
- call the same command from cron, systemd, Kubernetes CronJobs, Celery, RQ, or
534
- Temporal.
532
+ The first command runs one deterministic memory pass: expired-memory purge,
533
+ optional field/concept consolidation, and index-health repair. The second
534
+ command creates a verified replicated snapshot, mirrors it to an offsite path,
535
+ and applies retention. Production deployments can call these commands from
536
+ cron, systemd, Kubernetes CronJobs, Celery, RQ, or Temporal.
535
537
 
536
538
  Hot-cache options:
537
539
 
@@ -621,7 +623,7 @@ backup command.
621
623
  Replicated runtime snapshot/restore:
622
624
 
623
625
  ```python
624
- from wavemind import HashingTextEncoder, ReplicatedWaveMind
626
+ from wavemind import HashingTextEncoder, ReplicatedSnapshotWorker, ReplicatedWaveMind
625
627
 
626
628
  memory = ReplicatedWaveMind(
627
629
  root_path="./state/replicas",
@@ -631,20 +633,43 @@ memory = ReplicatedWaveMind(
631
633
  )
632
634
  memory.remember("Tenant A prefers short support replies.", namespace="tenant:a")
633
635
 
634
- snapshot = memory.snapshot("./backups/replicated")
635
- assert ReplicatedWaveMind.verify_snapshot(snapshot.snapshot_path)["healthy"]
636
+ snapshot_job = ReplicatedSnapshotWorker(memory).run_once(
637
+ destination="./backups/replicated",
638
+ offsite_destination="./offsite/replicated",
639
+ keep_last=7,
640
+ )
641
+ assert snapshot_job.ok
636
642
 
637
643
  restored, report = ReplicatedWaveMind.restore_snapshot(
638
- snapshot.snapshot_path,
644
+ snapshot_job.offsite_path,
639
645
  "./state/restored-replicas",
640
646
  encoder=HashingTextEncoder(vector_dim=64),
641
647
  )
642
648
  ```
643
649
 
644
- The replicated snapshot writes one SQLite backup per replica plus
650
+ The replicated snapshot job writes one SQLite backup per replica plus
645
651
  `manifest.json` with SHA-256 checksums, replica metadata, quorum settings, and
646
- node definitions. Restore refuses to overwrite a non-empty root unless
647
- `overwrite=True` is passed.
652
+ node definitions. It can mirror the snapshot to a second path for offsite
653
+ backup and applies `keep_last` retention locally and offsite. Restore refuses to
654
+ overwrite a non-empty root unless `overwrite=True` is passed.
655
+
656
+ Equivalent CLI:
657
+
658
+ ```sh
659
+ wavemind replicated-snapshot \
660
+ --root ./state/replicas \
661
+ --node node-a --node node-b --node node-c \
662
+ --out ./backups/replicated \
663
+ --offsite ./offsite/replicated \
664
+ --keep-last 7 \
665
+ --json
666
+
667
+ wavemind replicated-restore \
668
+ --from ./offsite/replicated/wavemind-replicated-20260705-120000 \
669
+ --to ./state/restored-replicas \
670
+ --overwrite \
671
+ --json
672
+ ```
648
673
 
649
674
  ## HTTP API
650
675
 
@@ -1019,7 +1044,7 @@ Current read:
1019
1044
  | LongMemEval 50-query smoke | On the first 50 non-abstention LongMemEval-S questions, WaveMind reaches `evidence_recall@5 0.920`, `precision@1 0.760`, and `MRR@5 0.827`; Chroma/Qdrant static reach `0.600`, `0.260`, and `0.385`. | This is the fast regression profile for checking current changes before rerunning the full LongMemEval profile. WaveMind wins on quality; latency still needs work. |
1020
1045
  | ANN/index curve | At 50000 generated 128-d vectors, NumPy exact keeps `recall@10 1.000` at `6.49 ms`; quantized int8 keeps `0.934` at `24.92 ms`; Annoy is faster at `4.92 ms` but drops to `0.730` recall; Qdrant local keeps `1.000` recall at `43.49 ms`. | Current local scale boundary is clear: quantized search needs kernel work, Annoy needs tuning/FAISS, and Qdrant should be tested in service mode for a fair production comparison. |
1021
1046
  | Production load | At 100000 generated 128-d vectors, service-mode Qdrant reaches `recall@10 1.000`, avg `10.28 ms`, p99 `21.26 ms`. At 1M, tuned Qdrant reaches `recall@10 0.984`, avg `116.80 ms`, p99 `209.28 ms`; an EF sweep finds `recall@10 0.977`, avg `64.76 ms`, p99 `103.77 ms` at `hnsw_ef=2048` on 30 queries. | 100k is production-grade on the tested machine. 1M recall is now strong, but p99 still needs tuning before claiming a stable sub-100 ms SLO. |
1022
- | Scale readiness | Deterministic 1M-memory simulation validates 4096 namespace placements over 4 nodes with replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, hot-cache hit rate `0.920`, quorum-replicated runtime recall after node loss, missing-record repair, tombstone repair, active-active delta sync, checksummed replicated snapshot/restore, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, replicated-runtime, namespace-delta, and restore-drill foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
1047
+ | Scale readiness | Deterministic 1M-memory simulation validates 4096 namespace placements over 4 nodes with replication factor 2, node-loss availability `1.000`, zone-loss availability `1.000`, hot-cache hit rate `0.920`, quorum-replicated runtime recall after node loss, missing-record repair, tombstone repair, active-active delta sync, checksummed replicated snapshot/restore, offsite snapshot verification, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, replicated-runtime, namespace-delta, offsite backup, and restore-drill foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
1023
1048
  | Memory competitor adapters | WaveMind reaches `precision@1 0.80`, `precision@3 1.00`, stale suppression `1.00` on the small adapter profile. Mem0, Zep, and LangGraph are listed as skipped unless their real packages/services are configured. | This prevents fake competitor claims. The adapter harness is ready; real Mem0/Zep/LangGraph results still need configured installs. |
1024
1049
  | LongMemEval local answer generation | With the same local Ollama `qwen2.5:1.5b`, WaveMind reaches `exact_match 0.240`, `contains_answer 0.380`, `token_f1 0.333`, and `evidence_recall@5 0.920`; Chroma and Qdrant static both reach `0.120`, `0.160`, `0.170`, and `0.600`. | This is the first checked-in end-to-end answer benchmark against Chroma/Qdrant. It is still a 50-question lightweight smoke run, not a full LongMemEval leaderboard score. |
1025
1050
 
@@ -1038,7 +1063,7 @@ Current read:
1038
1063
  | Production index profile | Docker-backed 50000-vector profile for persisted FAISS, Qdrant service, and PostgreSQL/pgvector HNSW. | implemented | FAISS / Qdrant service / pgvector | Keep service-mode candidate generation above `0.95` recall@10 and below 10 ms average query latency at 50000 vectors. |
1039
1064
  | Production load profile | 100k and 1M service-backed candidate-index checks with p95/p99 latency. | implemented | Qdrant service / pgvector HNSW / FAISS persisted | Keep 100k at recall@10 `1.000`; push 1M p99 below 100 ms with recall@10 >= 0.95. |
1040
1065
  | Qdrant 1M HNSW ef sweep | One 1M Qdrant collection queried with multiple `hnsw_ef` values. | implemented | Qdrant service | Repeat with 100+ queries and collection-level HNSW build parameters before claiming a stable 1M SLO. |
1041
- | Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, active-active delta sync, replicated snapshot/restore, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication, namespace-delta sync, repair, and restore drills green while adding larger service-backed 10M load tests. |
1066
+ | Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, active-active delta sync, replicated snapshot/restore with offsite verification, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication, namespace-delta sync, repair, offsite backup, and restore drills green while adding larger service-backed 10M load tests. |
1042
1067
  | Memory competitor adapter profile | Dynamic-memory scenario wired for external memory frameworks. | implemented | Mem0 / Zep / LangGraph persistent memory | Report real competitor results only when their packages/services are explicitly configured. |
1043
1068
  | [BEIR](https://github.com/beir-cellar/beir) | Standard zero-shot information retrieval quality. | planned | Chroma / Qdrant / FAISS | Stay within 0.02 `nDCG@10` on identical embeddings. |
1044
1069
  | [MTEB Retrieval](https://github.com/embeddings-benchmark/mteb) | Separates encoder quality from retrieval-store quality. | planned | Chroma / Qdrant / FAISS | Prove WaveMind does not reduce same-embedding retrieval quality. |
@@ -1171,7 +1196,7 @@ For HA-style local or service-mode deployments, `ReplicatedWaveMind` writes each
1171
1196
  namespace to a deterministic replica set and enforces read/write quorum:
1172
1197
 
1173
1198
  ```python
1174
- from wavemind import ReplicatedWaveMind
1199
+ from wavemind import ReplicatedSnapshotWorker, ReplicatedWaveMind
1175
1200
 
1176
1201
  memory = ReplicatedWaveMind(
1177
1202
  root_path="./state/wavemind-replicas",
@@ -1212,21 +1237,26 @@ region_b.import_namespace_delta(region_a.export_namespace_delta("tenant:a"))
1212
1237
  The delta contains active records plus tombstones. Import is idempotent and
1213
1238
  tombstone-aware, so a stale region export cannot resurrect a deleted memory.
1214
1239
 
1215
- For operational recovery, `snapshot()` creates a checksummed replicated snapshot
1216
- and `restore_snapshot()` restores it into a fresh replica root:
1240
+ For operational recovery, `ReplicatedSnapshotWorker` creates a checksummed
1241
+ replicated snapshot, verifies an optional offsite mirror, and
1242
+ `restore_snapshot()` restores it into a fresh replica root:
1217
1243
 
1218
1244
  ```python
1219
- snapshot = memory.snapshot("./backups/replicated")
1220
- health = ReplicatedWaveMind.verify_snapshot(snapshot.snapshot_path)
1245
+ job = ReplicatedSnapshotWorker(memory).run_once(
1246
+ destination="./backups/replicated",
1247
+ offsite_destination="./offsite/replicated",
1248
+ keep_last=7,
1249
+ )
1221
1250
  restored, report = ReplicatedWaveMind.restore_snapshot(
1222
- snapshot.snapshot_path,
1251
+ job.offsite_path,
1223
1252
  "./state/restored-replicas",
1224
1253
  )
1225
1254
  ```
1226
1255
 
1227
- The checked-in scale-readiness profile verifies manifest checksums, restores
1228
- three replica files, then disables the restored primary and confirms the memory
1229
- is still recalled from the remaining replicas.
1256
+ The checked-in scale-readiness profile verifies manifest checksums, verifies the
1257
+ offsite mirror, restores three replica files from that offsite mirror, then
1258
+ disables the restored primary and confirms the memory is still recalled from the
1259
+ remaining replicas.
1230
1260
 
1231
1261
  Checked-in official LoCoMo retrieval result:
1232
1262
 
@@ -1616,9 +1646,10 @@ Near-term priorities:
1616
1646
  OpenClaw, and HTTP-only sidecar use.
1617
1647
  - Faster dynamic re-ranking through smaller candidate windows, caching, and
1618
1648
  background updates.
1619
- - Better production operations: OpenTelemetry is optional and implemented;
1620
- richer latency histograms, index-health metrics, alerting examples, scheduled
1621
- offsite snapshots, and Postgres PITR runbooks are next.
1649
+ - Better production operations: OpenTelemetry and replicated offsite snapshot
1650
+ jobs are implemented; richer latency histograms, index-health metrics,
1651
+ alerting examples, object-store upload adapters, and Postgres PITR runbooks
1652
+ are next.
1622
1653
 
1623
1654
  Longer-term direction:
1624
1655
 
@@ -21,7 +21,7 @@ This is a compact reader-facing view of checked-in benchmark results. It is not
21
21
  | Production load profile 100k | production-scale | Recall@k | WaveMind pgvector: 0.736 / 17.8 ms | Qdrant service: 1 / 10.3 ms | Baseline leads on quality |
22
22
  | Production load profile 1M | production-scale | Recall@k | - | Qdrant service: 0.984 / 116.8 ms | No WaveMind result |
23
23
  | Qdrant 1M HNSW ef sweep | production-scale | Recall@k | - | hnsw_ef=2048: 0.977 / 64.8 ms | No WaveMind result |
24
- | Scale readiness profile | production-scale | precision@1 | WaveMind structured payloads: 1 / 0.448 ms | - | WaveMind-only check |
24
+ | Scale readiness profile | production-scale | precision@1 | WaveMind structured payloads: 1 / 0.401 ms | - | WaveMind-only check |
25
25
  | Memory competitor adapter profile | agent-memory | precision@1 | WaveMind: 0.8 / 0.554 ms | - | WaveMind-only check |
26
26
  | [LongMemEval answer generation](https://github.com/xiaowu0162/LongMemEval) | long-term-agent-memory | token F1 | WaveMind + qwen2.5:1.5b: 0.333 / - | Chroma static + qwen2.5:1.5b: 0.17 / - | WaveMind leads on quality |
27
27
 
@@ -24,7 +24,7 @@ Planned rows are not claimed wins. They are the public proof path WaveMind must
24
24
  | Production load profile 100k | production-scale | implemented | Qdrant service: Recall@k 1.00, avg latency 10.3, p95 latency 19.0, p99 latency ms 21.3, build ms 27439.3<br>WaveMind pgvector: Recall@k 0.74, avg latency 17.8, p95 latency 23.5, build ms 455703.7<br>WaveMind faiss-persisted: skipped - Set WAVEMIND_FAISS_PATH to use the persisted FAISS backend | Tune pgvector HNSW build/search parameters and add persisted FAISS from the Linux benchmark container. |
25
25
  | Production load profile 1M | production-scale | implemented | Qdrant service: Recall@k 0.98, avg latency 116.8, p95 latency 153.8, p99 latency ms 209.3, build ms 450674.6 | Tune Qdrant indexing/search params further, then add FAISS IVF/HNSW and pgvector 1M profiles on a larger disk. |
26
26
  | Qdrant 1M HNSW ef sweep | production-scale | implemented | hnsw_ef=512: Recall@k 0.75, avg latency 47.2, p95 latency 68.5, p99 latency ms 68.5, max latency ms 68.5<br>hnsw_ef=768: Recall@k 0.85, avg latency 44.0, p95 latency 69.1, p99 latency ms 69.8, max latency ms 69.8<br>hnsw_ef=1024: Recall@k 0.88, avg latency 62.9, p95 latency 81.1, p99 latency ms 85.5, max latency ms 85.5<br>hnsw_ef=1536: Recall@k 0.94, avg latency 65.6, p95 latency 111.2, p99 latency ms 119.7, max latency ms 119.7<br>hnsw_ef=2048: Recall@k 0.98, avg latency 64.8, p95 latency 91.2, p99 latency ms 103.8, max latency ms 103.8 | Repeat with 100+ queries and collection-level HNSW build parameters before claiming a stable production SLO. |
27
- | Scale readiness profile | production-scale | implemented | WaveMind cluster planner: simulated memories 1000000, namespaces 4096, nodes 4, replication factor 2, node loss min availability 1.00, zone loss min availability 1.00, read quorum 1, write quorum 2, placement ms 59.2<br>WaveMind hot cache: queries 2000, capacity 512, hit rate 0.92, evictions 0, p99 lookup ms 0.00<br>WaveMind replicated runtime: nodes 3, replication factor 3, write quorum 2, read quorum 1, recalled after node loss True, repair copied records 1, tombstone repair deleted records 1, p99 query after loss ms 1.29<br>WaveMind active-active delta sync: regions 2, replication factor per region 3, records imported 6, converged after bidirectional sync True, suppressed stale import after delete True, tombstone converged True, sync ms 112.5<br>WaveMind replicated snapshot: nodes 3, manifest healthy True, restored files 3, recalled after restore node loss True, snapshot ms 49.2, restore ms 11.4<br>WaveMind structured payloads: queries 4, precision@1 1.00, avg latency 0.45, p99 latency ms 0.67 | Move from local replicated runtime to service-backed replicated runs, scheduled/offsite snapshots, and larger 10M candidate-index load tests. |
27
+ | Scale readiness profile | production-scale | implemented | WaveMind cluster planner: simulated memories 1000000, namespaces 4096, nodes 4, replication factor 2, node loss min availability 1.00, zone loss min availability 1.00, read quorum 1, write quorum 2, placement ms 77.2<br>WaveMind hot cache: queries 2000, capacity 512, hit rate 0.92, evictions 0, p99 lookup ms 0.00<br>WaveMind replicated runtime: nodes 3, replication factor 3, write quorum 2, read quorum 1, recalled after node loss True, repair copied records 1, tombstone repair deleted records 1, p99 query after loss ms 1.35<br>WaveMind active-active delta sync: regions 2, replication factor per region 3, records imported 6, converged after bidirectional sync True, suppressed stale import after delete True, tombstone converged True, sync ms 103.4<br>WaveMind replicated snapshot: nodes 3, manifest healthy True, offsite verified True, restored files 3, recalled after restore node loss True, snapshot ms 69.7, restore ms 7.10<br>WaveMind structured payloads: queries 4, precision@1 1.00, avg latency 0.40, p99 latency ms 0.59 | Move from local replicated runtime to service-backed replicated runs, object-store snapshot adapters, and larger 10M candidate-index load tests. |
28
28
  | Memory competitor adapter profile | agent-memory | implemented | WaveMind: precision@1 0.80, precision@3 1.00, stale suppression 1.00, avg latency 0.55, p95 latency 0.83<br>Mem0: skipped - Install Mem0 to run this adapter profile: pip install "mem0ai"<br>Zep: skipped - Install the Zep client package and set ZEP_API_KEY or ZEP_API_URL.<br>LangGraph persistent memory: skipped - Install LangGraph to run this adapter profile: pip install "langgraph" | Add documented setup commands for each competitor adapter and store checked-in results only when those real adapters run. |
29
29
  | [LongMemEval answer generation](https://github.com/xiaowu0162/LongMemEval) | long-term-agent-memory | implemented | extractive smoke: queries 20, evidence recall@k 1.00, exact match 0.00, contains answer 0.05, token f1 0.02, avg retrieval ms 3.79, avg generation ms 0.77<br>WaveMind + qwen2.5:0.5b: queries 50, evidence recall@k 0.92, exact match 0.12, contains answer 0.18, token f1 0.18, avg retrieval ms 2.98, avg generation ms 1428.2<br>Chroma static + qwen2.5:0.5b: queries 50, evidence recall@k 0.60, exact match 0.10, contains answer 0.12, token f1 0.13, avg retrieval ms 4.10, avg generation ms 1234.7<br>Qdrant static + qwen2.5:0.5b: queries 50, evidence recall@k 0.60, exact match 0.10, contains answer 0.12, token f1 0.13, avg retrieval ms 63.8, avg generation ms 893.5<br>WaveMind + qwen2.5:1.5b: queries 50, evidence recall@k 0.92, exact match 0.24, contains answer 0.38, token f1 0.33, avg retrieval ms 2.00, avg generation ms 2153.0<br>Chroma static + qwen2.5:1.5b: queries 50, evidence recall@k 0.60, exact match 0.12, contains answer 0.16, token f1 0.17, avg retrieval ms 7.05, avg generation ms 2082.4<br>Qdrant static + qwen2.5:1.5b: queries 50, evidence recall@k 0.60, exact match 0.12, contains answer 0.16, token f1 0.17, avg retrieval ms 100.2, avg generation ms 758.1 | Run all 470 non-abstention questions with a stronger local/API model and add faithfulness/abstention scoring. |
30
30
 
@@ -764,14 +764,14 @@
764
764
  "zone_loss_min_availability": 1.0,
765
765
  "read_quorum": 1,
766
766
  "write_quorum": 2,
767
- "placement_ms": 59.205800003837794
767
+ "placement_ms": 77.1686999942176
768
768
  },
769
769
  "WaveMind hot cache": {
770
770
  "queries": 2000,
771
771
  "capacity": 512,
772
772
  "hit_rate": 0.92,
773
773
  "evictions": 0,
774
- "p99_lookup_ms": 0.002700020559132099
774
+ "p99_lookup_ms": 0.0030999653972685337
775
775
  },
776
776
  "WaveMind replicated runtime": {
777
777
  "nodes": 3,
@@ -781,7 +781,7 @@
781
781
  "recalled_after_node_loss": true,
782
782
  "repair_copied_records": 1,
783
783
  "tombstone_repair_deleted_records": 1,
784
- "p99_query_after_loss_ms": 1.2885000323876739
784
+ "p99_query_after_loss_ms": 1.35420000879094
785
785
  },
786
786
  "WaveMind active-active delta sync": {
787
787
  "regions": 2,
@@ -790,25 +790,26 @@
790
790
  "converged_after_bidirectional_sync": true,
791
791
  "suppressed_stale_import_after_delete": true,
792
792
  "tombstone_converged": true,
793
- "sync_ms": 112.49550001230091
793
+ "sync_ms": 103.42070000478998
794
794
  },
795
795
  "WaveMind replicated snapshot": {
796
796
  "nodes": 3,
797
797
  "manifest_healthy": true,
798
+ "offsite_verified": true,
798
799
  "restored_files": 3,
799
800
  "recalled_after_restore_node_loss": true,
800
- "snapshot_ms": 49.16400002548471,
801
- "restore_ms": 11.4187000435777
801
+ "snapshot_ms": 69.7173000080511,
802
+ "restore_ms": 7.101800001692027
802
803
  },
803
804
  "WaveMind structured payloads": {
804
805
  "queries": 4,
805
806
  "precision_at_1": 1.0,
806
- "avg_latency_ms": 0.44750000233761966,
807
- "p99_latency_ms": 0.6680000224150717
807
+ "avg_latency_ms": 0.40072499541565776,
808
+ "p99_latency_ms": 0.5899000097997487
808
809
  }
809
810
  },
810
- "target": "Prove the production foundation before heavier 100k, 1M, and 10M vector load tests: deterministic placement, survivable replicas, active-active sync, restore drills, hot-cache behavior, and structured payload recall.",
811
- "next_step": "Move from local replicated runtime to service-backed replicated runs, scheduled/offsite snapshots, and larger 10M candidate-index load tests."
811
+ "target": "Prove the production foundation before heavier 100k, 1M, and 10M vector load tests: deterministic placement, survivable replicas, active-active sync, offsite-verified restore drills, hot-cache behavior, and structured payload recall.",
812
+ "next_step": "Move from local replicated runtime to service-backed replicated runs, object-store snapshot adapters, and larger 10M candidate-index load tests."
812
813
  },
813
814
  {
814
815
  "id": "memory_competitor_adapter_profile",
@@ -765,6 +765,7 @@ def _implemented_entries(root: Path) -> list[dict[str, Any]]:
765
765
  (
766
766
  "nodes",
767
767
  "manifest_healthy",
768
+ "offsite_verified",
768
769
  "restored_files",
769
770
  "recalled_after_restore_node_loss",
770
771
  "snapshot_ms",
@@ -781,8 +782,8 @@ def _implemented_entries(root: Path) -> list[dict[str, Any]]:
781
782
  ),
782
783
  ),
783
784
  },
784
- "target": "Prove the production foundation before heavier 100k, 1M, and 10M vector load tests: deterministic placement, survivable replicas, active-active sync, restore drills, hot-cache behavior, and structured payload recall.",
785
- "next_step": "Move from local replicated runtime to service-backed replicated runs, scheduled/offsite snapshots, and larger 10M candidate-index load tests.",
785
+ "target": "Prove the production foundation before heavier 100k, 1M, and 10M vector load tests: deterministic placement, survivable replicas, active-active sync, offsite-verified restore drills, hot-cache behavior, and structured payload recall.",
786
+ "next_step": "Move from local replicated runtime to service-backed replicated runs, object-store snapshot adapters, and larger 10M candidate-index load tests.",
786
787
  },
787
788
  {
788
789
  "id": "memory_competitor_adapter_profile",
@@ -19,6 +19,7 @@ from wavemind import (
19
19
  HotMemoryCache,
20
20
  QueryResult,
21
21
  ReplicatedWaveMind,
22
+ ReplicatedSnapshotWorker,
22
23
  WaveMind,
23
24
  audio_payload,
24
25
  build_cluster_plan,
@@ -335,13 +336,17 @@ def run_replicated_snapshot_profile() -> dict[str, object]:
335
336
  namespace=namespace,
336
337
  )
337
338
  snapshot_started = time.perf_counter()
338
- snapshot = memory.snapshot(root / "snapshots")
339
+ snapshot_job = ReplicatedSnapshotWorker(memory).run_once(
340
+ destination=root / "snapshots",
341
+ offsite_destination=root / "offsite",
342
+ keep_last=2,
343
+ )
339
344
  snapshot_ms = (time.perf_counter() - snapshot_started) * 1000.0
340
- health = ReplicatedWaveMind.verify_snapshot(snapshot.snapshot_path)
345
+ health = ReplicatedWaveMind.verify_snapshot(snapshot_job.snapshot_path)
341
346
 
342
347
  restore_started = time.perf_counter()
343
348
  restored, restore = ReplicatedWaveMind.restore_snapshot(
344
- snapshot.snapshot_path,
349
+ snapshot_job.offsite_path,
345
350
  root / "restored",
346
351
  width=16,
347
352
  height=16,
@@ -356,9 +361,10 @@ def run_replicated_snapshot_profile() -> dict[str, object]:
356
361
  )
357
362
  return {
358
363
  "engine": "WaveMind replicated snapshot",
359
- "nodes": len(snapshot.nodes),
364
+ "nodes": len(snapshot_job.nodes),
360
365
  "manifest_healthy": health["healthy"],
361
- "total_bytes": snapshot.total_bytes,
366
+ "offsite_verified": snapshot_job.offsite_verified,
367
+ "total_bytes": snapshot_job.total_bytes,
362
368
  "snapshot_ms": snapshot_ms,
363
369
  "restore_ms": restore_ms,
364
370
  "restored_files": len(restore.restored_files),
@@ -519,6 +525,7 @@ def main() -> int:
519
525
  print(f"| active-active delta | tombstone_converged | {result['tombstone_converged']} |")
520
526
  elif result["engine"] == "WaveMind replicated snapshot":
521
527
  print(f"| replicated snapshot | manifest_healthy | {result['manifest_healthy']} |")
528
+ print(f"| replicated snapshot | offsite_verified | {result['offsite_verified']} |")
522
529
  print(f"| replicated snapshot | recalled_after_restore_node_loss | {result['recalled_after_restore_node_loss']} |")
523
530
  else:
524
531
  print(f"| structured payloads | precision@1 | {result['precision_at_1']:.3f} |")
@@ -14,7 +14,7 @@
14
14
  "namespaces": 4096,
15
15
  "nodes": 4,
16
16
  "replication_factor": 2,
17
- "placement_ms": 59.205800003837794,
17
+ "placement_ms": 77.1686999942176,
18
18
  "max_replica_load": 2413,
19
19
  "min_replica_load": 1728,
20
20
  "replica_load_stdev": 316.54462560593254,
@@ -32,8 +32,8 @@
32
32
  "capacity": 512,
33
33
  "hit_rate": 0.92,
34
34
  "evictions": 0,
35
- "avg_lookup_ms": 0.0014145502645988017,
36
- "p99_lookup_ms": 0.002700020559132099
35
+ "avg_lookup_ms": 0.0014047000149730593,
36
+ "p99_lookup_ms": 0.0030999653972685337
37
37
  },
38
38
  {
39
39
  "engine": "WaveMind replicated runtime",
@@ -47,8 +47,8 @@
47
47
  "tombstone_suppressed_before_repair": true,
48
48
  "tombstone_suppressed_after_repair": true,
49
49
  "tombstone_repair_deleted_records": 1,
50
- "avg_query_after_loss_ms": 1.2885000323876739,
51
- "p99_query_after_loss_ms": 1.2885000323876739
50
+ "avg_query_after_loss_ms": 1.35420000879094,
51
+ "p99_query_after_loss_ms": 1.35420000879094
52
52
  },
53
53
  {
54
54
  "engine": "WaveMind active-active delta sync",
@@ -56,7 +56,7 @@
56
56
  "replication_factor_per_region": 3,
57
57
  "records_imported": 6,
58
58
  "converged_after_bidirectional_sync": true,
59
- "sync_ms": 112.49550001230091,
59
+ "sync_ms": 103.42070000478998,
60
60
  "suppressed_stale_import_after_delete": true,
61
61
  "tombstone_deleted_records": 3,
62
62
  "tombstone_converged": true
@@ -65,9 +65,10 @@
65
65
  "engine": "WaveMind replicated snapshot",
66
66
  "nodes": 3,
67
67
  "manifest_healthy": true,
68
+ "offsite_verified": true,
68
69
  "total_bytes": 110592,
69
- "snapshot_ms": 49.16400002548471,
70
- "restore_ms": 11.4187000435777,
70
+ "snapshot_ms": 69.7173000080511,
71
+ "restore_ms": 7.101800001692027,
71
72
  "restored_files": 3,
72
73
  "recalled_after_restore_node_loss": true
73
74
  },
@@ -81,8 +82,8 @@
81
82
  ],
82
83
  "queries": 4,
83
84
  "precision_at_1": 1.0,
84
- "avg_latency_ms": 0.44750000233761966,
85
- "p99_latency_ms": 0.6680000224150717
85
+ "avg_latency_ms": 0.40072499541565776,
86
+ "p99_latency_ms": 0.5899000097997487
86
87
  }
87
88
  ]
88
89
  }
@@ -4,7 +4,7 @@ services:
4
4
  context: .
5
5
  args:
6
6
  INSTALL_OPTIONAL: "false"
7
- image: wavemind:2.2.7
7
+ image: wavemind:2.2.8
8
8
  restart: unless-stopped
9
9
  environment:
10
10
  WAVEMIND_DB: /data/wavemind.sqlite3
@@ -31,7 +31,7 @@ purpose-built vector databases.
31
31
  | NoMIRACL Russian retrieval | WaveMind reaches `nDCG@10 0.434`; Chroma reaches `0.435`; Qdrant reaches `0.433`. Chroma is faster. | `benchmarks/nomiracl_russian_results.json` | `python benchmarks/nomiracl_russian_benchmark.py --engines wavemind chroma qdrant --output benchmarks/nomiracl_russian_results.json` |
32
32
  | Production index profile | At 50000 vectors, persisted FAISS and Qdrant service both reach `recall@10 1.000`; pgvector with `ef_search=400` reaches `0.811`. | `benchmarks/production_index_profile_results.json` | `docker compose -f examples/production-index-profile/docker-compose.yml run --rm benchmark` |
33
33
  | Production load profile | At 100000 vectors, Qdrant service reaches `recall@10 1.000`, avg `10.28 ms`, p99 `21.26 ms`. At 1M vectors, tuned Qdrant reaches `0.984`, avg `116.80 ms`, p99 `209.28 ms`; the best EF-sweep point reaches `0.977`, avg `64.76 ms`, p99 `103.77 ms`. | `benchmarks/production_load_qdrant_100k_tuned_results.json`, `benchmarks/production_load_qdrant_1m_tuned_results.json`, `benchmarks/production_load_qdrant_1m_ef_sweep_results.json` | `python benchmarks/production_load_benchmark.py --sizes 100000 --engines qdrant-service` |
34
- | Scale readiness profile | Deterministic 1M-memory simulation: namespace placement survives node loss and zone loss at `1.000`, hot-cache hit rate is `0.920`, replicated runtime survives node loss, active-active delta sync converges, replicated snapshot restore survives primary loss, structured payload precision@1 is `1.000`. | `benchmarks/scale_readiness_results.json` | `python benchmarks/scale_readiness_benchmark.py --simulated-memories 1000000 --output benchmarks/scale_readiness_results.json` |
34
+ | Scale readiness profile | Deterministic 1M-memory simulation: namespace placement survives node loss and zone loss at `1.000`, hot-cache hit rate is `0.920`, replicated runtime survives node loss, active-active delta sync converges, replicated snapshot restore survives primary loss, offsite snapshot verification is `true`, structured payload precision@1 is `1.000`. | `benchmarks/scale_readiness_results.json` | `python benchmarks/scale_readiness_benchmark.py --simulated-memories 1000000 --output benchmarks/scale_readiness_results.json` |
35
35
  | Memory competitor adapter profile | WaveMind reaches `precision@1 0.80`, `precision@3 1.00`, stale suppression `1.00`; Mem0, Zep, and LangGraph are skipped until real packages/services are configured. | `benchmarks/memory_competitor_results.json` | `python benchmarks/memory_competitor_benchmark.py --engines wavemind mem0 zep langgraph` |
36
36
 
37
37
  The generated matrix view is in `benchmarks/BENCHMARK_REPORT.md`; the compact