wavemind 2.2.3__tar.gz → 2.2.5__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.
- {wavemind-2.2.3 → wavemind-2.2.5}/PKG-INFO +47 -17
- {wavemind-2.2.3 → wavemind-2.2.5}/README.md +46 -16
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/scale_readiness_benchmark.py +119 -2
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/scale_readiness_results.json +21 -6
- {wavemind-2.2.3 → wavemind-2.2.5}/docker-compose.yml +1 -1
- {wavemind-2.2.3 → wavemind-2.2.5}/pyproject.toml +1 -1
- wavemind-2.2.5/tests/test_replication.py +198 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_scale_readiness_benchmark.py +5 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/__init__.py +15 -1
- wavemind-2.2.5/wavemind/replication.py +627 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind.egg-info/PKG-INFO +47 -17
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind.egg-info/SOURCES.txt +2 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/CONTRIBUTING.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/Dockerfile +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/LICENSE +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/MANIFEST.in +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/SECURITY.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/SUPPORT.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/BENCHMARK_LEADERBOARD.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/BENCHMARK_REPORT.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/agent_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/agent_memory_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/ann_index_curve_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/ann_index_curve_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/benchmark_matrix_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/benchmark_registry.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/dynamic_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/dynamic_memory_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/field_memory_dynamics_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/field_memory_dynamics_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/locomo_evidence_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/locomo_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/locomo_sentence_evidence_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/long_memory_evidence_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/long_memory_evidence_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_answer_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_answer_extractive_20_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_answer_qwen25_0_5b_50_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_answer_qwen25_1_5b_50_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_evidence_50_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_evidence_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/longmemeval_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/memory_competitor_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/memory_competitor_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/nomiracl_russian_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/nomiracl_russian_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/open_retrieval_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/open_retrieval_scifact_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_index_profile_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_qdrant_100k_tuned_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_qdrant_1m_ef_sweep_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_qdrant_1m_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_qdrant_1m_tuned_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/production_load_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/render_benchmark_charts.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/render_benchmark_leaderboard.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/render_benchmark_report.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/ru_sentences_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/benchmarks/wavemind_capacity_results.json +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/BENCHMARK_BRIEF.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/CHROMA_MIGRATION.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/DEMO_SCRIPT.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/LAUNCH_KIT.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/OBSERVABILITY.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/PROJECT_BOARD.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/RELEASE.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/ROADMAP.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/RU_LAUNCH_POSTS.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/USE_CASES.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/assets/benchmark-summary.svg +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/assets/wavemind-demo.gif +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/docs/assets/wavemind-social-card.svg +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/agent_with_memory.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/chroma_migration.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/customer_support_memory.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/demo.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/dynamic_memory_demo.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/framework_integrations.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/langchain_memory.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/llamaindex_retriever.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/observability/README.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/observability/docker-compose.yml +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/observability/otel-collector.yaml +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/observability/prometheus-alerts.yml +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/observability/prometheus.yml +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/production-index-profile/README.md +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/production-index-profile/docker-compose.yml +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/research_notebook_memory.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/examples/sharded_memory.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/install.bat +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/install.sh +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/requirements-optional.txt +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/requirements.txt +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/setup.cfg +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_agent_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_ann_index_curve_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_api.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_api_process_persistence.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_benchmark_brief.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_benchmark_charts.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_benchmark_leaderboard.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_benchmark_registry.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_benchmark_report.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_chroma_migration_example.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_cli_smoke.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_cluster.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_core_persistence.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_dynamic_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_examples.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_field_graph.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_field_graph_integration.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_field_memory_dynamics_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_framework_adapters.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_import_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_indexes_encoders.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_jobs.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_langchain_integration.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_locomo_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_long_memory_evidence_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_longmemeval_answer_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_longmemeval_memory_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_memory_competitor_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_multimodal.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_nomiracl_russian_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_observability.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_observability_docs.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_open_retrieval_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_packaging_files.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_postgres_storage.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_production_index_profile.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_production_load_benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_scale_plan.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_semantic_and_latency.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/tests/test_sharding.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/__main__.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/api.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/benchmark.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/cli.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/cluster.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/core.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/encoders.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/field_graph.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/importers.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/indexes.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/__init__.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/autogen.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/crewai.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/langchain.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/langgraph.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/integrations/llamaindex.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/jobs.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/multimodal.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/observability.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/scale.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/sharding.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/storage.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind/studio.py +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind.egg-info/dependency_links.txt +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind.egg-info/entry_points.txt +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/wavemind.egg-info/requires.txt +0 -0
- {wavemind-2.2.3 → wavemind-2.2.5}/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.
|
|
3
|
+
Version: 2.2.5
|
|
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,12 +543,13 @@ 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.01 ms`. |
|
|
546
|
-
|
|
|
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.44 ms`. |
|
|
547
|
+
| Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.75 ms`. |
|
|
547
548
|
|
|
548
|
-
This profile validates routing,
|
|
549
|
-
It is not a 10M-vector load test.
|
|
550
|
-
|
|
551
|
-
hardware.
|
|
549
|
+
This profile validates routing, quorum-replicated runtime behavior, cache
|
|
550
|
+
behavior, and structured payload handling. It is not a 10M-vector load test.
|
|
551
|
+
Real 100k, 1M, and 10M latency claims should come from service-backed
|
|
552
|
+
FAISS/Qdrant/pgvector load tests on production-like hardware.
|
|
552
553
|
|
|
553
554
|
Cluster placement planning:
|
|
554
555
|
|
|
@@ -565,8 +566,9 @@ wavemind cluster-plan \
|
|
|
565
566
|
|
|
566
567
|
This uses deterministic rendezvous placement so each namespace has a primary
|
|
567
568
|
and replica set. The emitted Kubernetes StatefulSet manifest is a deployment
|
|
568
|
-
starting point
|
|
569
|
-
|
|
569
|
+
starting point. Runtime quorum replication is available through
|
|
570
|
+
`ReplicatedWaveMind`; consensus across independently managed network services
|
|
571
|
+
should still use a production database or service layer.
|
|
570
572
|
|
|
571
573
|
The same planner is available over HTTP as `POST /cluster-plan`.
|
|
572
574
|
|
|
@@ -1039,7 +1041,7 @@ Current read:
|
|
|
1039
1041
|
| 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. |
|
|
1040
1042
|
| 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. |
|
|
1041
1043
|
| 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. |
|
|
1042
|
-
| 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`, and structured payload precision@1 `1.000`. | This proves routing
|
|
1044
|
+
| 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, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, and replicated-runtime foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
|
|
1043
1045
|
| 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. |
|
|
1044
1046
|
| 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. |
|
|
1045
1047
|
|
|
@@ -1058,7 +1060,7 @@ Current read:
|
|
|
1058
1060
|
| 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. |
|
|
1059
1061
|
| 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. |
|
|
1060
1062
|
| 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. |
|
|
1061
|
-
| Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters |
|
|
1063
|
+
| Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication and repair green while adding larger service-backed 10M load tests. |
|
|
1062
1064
|
| 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. |
|
|
1063
1065
|
| [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. |
|
|
1064
1066
|
| [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. |
|
|
@@ -1170,7 +1172,7 @@ If Chroma or Qdrant are not installed, use the baseline-only command:
|
|
|
1170
1172
|
python benchmarks/locomo_memory_benchmark.py --dataset benchmarks/data/locomo10.json --engines wavemind static --top-k 5
|
|
1171
1173
|
```
|
|
1172
1174
|
|
|
1173
|
-
## Namespace Sharding
|
|
1175
|
+
## Namespace Sharding And Replication
|
|
1174
1176
|
|
|
1175
1177
|
For multi-tenant local deployments, `ShardedWaveMind` routes namespaces across
|
|
1176
1178
|
multiple SQLite files:
|
|
@@ -1187,9 +1189,36 @@ print(memory.stats())
|
|
|
1187
1189
|
memory.close()
|
|
1188
1190
|
```
|
|
1189
1191
|
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1192
|
+
For HA-style local or service-mode deployments, `ReplicatedWaveMind` writes each
|
|
1193
|
+
namespace to a deterministic replica set and enforces read/write quorum:
|
|
1194
|
+
|
|
1195
|
+
```python
|
|
1196
|
+
from wavemind import ReplicatedWaveMind
|
|
1197
|
+
|
|
1198
|
+
memory = ReplicatedWaveMind(
|
|
1199
|
+
root_path="./state/wavemind-replicas",
|
|
1200
|
+
nodes=[
|
|
1201
|
+
{"id": "node-a", "address": "10.0.0.1:8000", "zone": "zone-a"},
|
|
1202
|
+
{"id": "node-b", "address": "10.0.0.2:8000", "zone": "zone-b"},
|
|
1203
|
+
{"id": "node-c", "address": "10.0.0.3:8000", "zone": "zone-c"},
|
|
1204
|
+
],
|
|
1205
|
+
replication_factor=3,
|
|
1206
|
+
)
|
|
1207
|
+
|
|
1208
|
+
memory.remember("Tenant A prefers short support replies.", namespace="tenant:a")
|
|
1209
|
+
print(memory.query("support replies", namespace="tenant:a", top_k=3))
|
|
1210
|
+
|
|
1211
|
+
memory.set_node_available("node-a", False)
|
|
1212
|
+
print(memory.query("support replies", namespace="tenant:a", top_k=3))
|
|
1213
|
+
memory.close()
|
|
1214
|
+
```
|
|
1215
|
+
|
|
1216
|
+
The runtime uses separate durable stores per node, stable replica keys, operation
|
|
1217
|
+
metadata, quorum writes, quorum reads, merged replica results, tombstone-aware
|
|
1218
|
+
delete propagation, and `repair_namespace()` for recovered replicas. It is the
|
|
1219
|
+
production foundation for namespace-level HA and eventual-consistency behavior;
|
|
1220
|
+
for full consensus across independent network services, deploy WaveMind with
|
|
1221
|
+
Postgres/Qdrant/ops-layer replication.
|
|
1193
1222
|
|
|
1194
1223
|
Checked-in official LoCoMo retrieval result:
|
|
1195
1224
|
|
|
@@ -1517,7 +1546,7 @@ python benchmarks/dynamic_memory_benchmark.py --engines wavemind chroma --memori
|
|
|
1517
1546
|
| Dynamic memory priority | Wave-field hotness, TTL, priority | Metadata/filter driven | Payload/filter driven |
|
|
1518
1547
|
| Built-in forgetting | TTL and explicit forget | Manual delete/filtering | Manual delete/filtering |
|
|
1519
1548
|
| Best fit | Small to medium memory streams with dynamic recall | Local RAG apps and prototypes | Large-scale vector search |
|
|
1520
|
-
| Scale target today |
|
|
1549
|
+
| Scale target today | Local exact mode for small streams; FAISS/Qdrant/pgvector plus replicated namespaces for production paths | Larger than WaveMind local exact mode | Production vector scale |
|
|
1521
1550
|
|
|
1522
1551
|
WaveMind is not trying to replace dedicated vector databases at scale. The intended product gap is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade. For static RAG over large document collections, use a mature vector database. For memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
|
|
1523
1552
|
|
|
@@ -1545,8 +1574,9 @@ If you already use Chroma for local memory, see the practical migration guide:
|
|
|
1545
1574
|
from SQLite on load/build, so large service-mode deployments still need a
|
|
1546
1575
|
measured rebuild strategy and index-health monitoring.
|
|
1547
1576
|
- The persisted FAISS backend validates a snapshot against current memory ids
|
|
1548
|
-
and avoids unnecessary FAISS rebuilds when the snapshot matches.
|
|
1549
|
-
a single-node flat-index path
|
|
1577
|
+
and avoids unnecessary FAISS rebuilds when the snapshot matches. FAISS itself
|
|
1578
|
+
is a single-node flat-index path; use `ReplicatedWaveMind` or external
|
|
1579
|
+
database/service replication when that is not enough.
|
|
1550
1580
|
- The `quantized` backend is an explicit int8 candidate-index experiment. It
|
|
1551
1581
|
reduces vector precision and must be benchmarked per workload before use.
|
|
1552
1582
|
- The synthetic long-term memory evidence benchmark is useful for regression and product-shape proof, but public claims should lean on LoCoMo and LongMemEval instead.
|
|
@@ -490,12 +490,13 @@ 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.01 ms`. |
|
|
493
|
-
|
|
|
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.44 ms`. |
|
|
494
|
+
| Structured payloads | image/audio/table/event retrieval, precision@1 `1.000`, p99 `0.75 ms`. |
|
|
494
495
|
|
|
495
|
-
This profile validates routing,
|
|
496
|
-
It is not a 10M-vector load test.
|
|
497
|
-
|
|
498
|
-
hardware.
|
|
496
|
+
This profile validates routing, quorum-replicated runtime behavior, cache
|
|
497
|
+
behavior, and structured payload handling. It is not a 10M-vector load test.
|
|
498
|
+
Real 100k, 1M, and 10M latency claims should come from service-backed
|
|
499
|
+
FAISS/Qdrant/pgvector load tests on production-like hardware.
|
|
499
500
|
|
|
500
501
|
Cluster placement planning:
|
|
501
502
|
|
|
@@ -512,8 +513,9 @@ wavemind cluster-plan \
|
|
|
512
513
|
|
|
513
514
|
This uses deterministic rendezvous placement so each namespace has a primary
|
|
514
515
|
and replica set. The emitted Kubernetes StatefulSet manifest is a deployment
|
|
515
|
-
starting point
|
|
516
|
-
|
|
516
|
+
starting point. Runtime quorum replication is available through
|
|
517
|
+
`ReplicatedWaveMind`; consensus across independently managed network services
|
|
518
|
+
should still use a production database or service layer.
|
|
517
519
|
|
|
518
520
|
The same planner is available over HTTP as `POST /cluster-plan`.
|
|
519
521
|
|
|
@@ -986,7 +988,7 @@ Current read:
|
|
|
986
988
|
| 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. |
|
|
987
989
|
| 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. |
|
|
988
990
|
| 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. |
|
|
989
|
-
| 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`, and structured payload precision@1 `1.000`. | This proves routing
|
|
991
|
+
| 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, and structured payload precision@1 `1.000`. | This proves routing, cache, payload, and replicated-runtime foundations. It is not a 10M-vector latency claim; real 10M latency still needs service-backed load tests on larger hardware. |
|
|
990
992
|
| 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. |
|
|
991
993
|
| 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. |
|
|
992
994
|
|
|
@@ -1005,7 +1007,7 @@ Current read:
|
|
|
1005
1007
|
| 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. |
|
|
1006
1008
|
| 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. |
|
|
1007
1009
|
| 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. |
|
|
1008
|
-
| Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters |
|
|
1010
|
+
| Scale readiness profile | Cluster placement, node/zone-loss simulation, quorum report, replicated runtime, hot-cache behavior, and structured/multimodal payload retrieval. | implemented | Mem0 / Zep / LangGraph persistent memory / GraphRAG target adapters | Keep quorum replication and repair green while adding larger service-backed 10M load tests. |
|
|
1009
1011
|
| 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. |
|
|
1010
1012
|
| [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. |
|
|
1011
1013
|
| [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. |
|
|
@@ -1117,7 +1119,7 @@ If Chroma or Qdrant are not installed, use the baseline-only command:
|
|
|
1117
1119
|
python benchmarks/locomo_memory_benchmark.py --dataset benchmarks/data/locomo10.json --engines wavemind static --top-k 5
|
|
1118
1120
|
```
|
|
1119
1121
|
|
|
1120
|
-
## Namespace Sharding
|
|
1122
|
+
## Namespace Sharding And Replication
|
|
1121
1123
|
|
|
1122
1124
|
For multi-tenant local deployments, `ShardedWaveMind` routes namespaces across
|
|
1123
1125
|
multiple SQLite files:
|
|
@@ -1134,9 +1136,36 @@ print(memory.stats())
|
|
|
1134
1136
|
memory.close()
|
|
1135
1137
|
```
|
|
1136
1138
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1139
|
+
For HA-style local or service-mode deployments, `ReplicatedWaveMind` writes each
|
|
1140
|
+
namespace to a deterministic replica set and enforces read/write quorum:
|
|
1141
|
+
|
|
1142
|
+
```python
|
|
1143
|
+
from wavemind import ReplicatedWaveMind
|
|
1144
|
+
|
|
1145
|
+
memory = ReplicatedWaveMind(
|
|
1146
|
+
root_path="./state/wavemind-replicas",
|
|
1147
|
+
nodes=[
|
|
1148
|
+
{"id": "node-a", "address": "10.0.0.1:8000", "zone": "zone-a"},
|
|
1149
|
+
{"id": "node-b", "address": "10.0.0.2:8000", "zone": "zone-b"},
|
|
1150
|
+
{"id": "node-c", "address": "10.0.0.3:8000", "zone": "zone-c"},
|
|
1151
|
+
],
|
|
1152
|
+
replication_factor=3,
|
|
1153
|
+
)
|
|
1154
|
+
|
|
1155
|
+
memory.remember("Tenant A prefers short support replies.", namespace="tenant:a")
|
|
1156
|
+
print(memory.query("support replies", namespace="tenant:a", top_k=3))
|
|
1157
|
+
|
|
1158
|
+
memory.set_node_available("node-a", False)
|
|
1159
|
+
print(memory.query("support replies", namespace="tenant:a", top_k=3))
|
|
1160
|
+
memory.close()
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
The runtime uses separate durable stores per node, stable replica keys, operation
|
|
1164
|
+
metadata, quorum writes, quorum reads, merged replica results, tombstone-aware
|
|
1165
|
+
delete propagation, and `repair_namespace()` for recovered replicas. It is the
|
|
1166
|
+
production foundation for namespace-level HA and eventual-consistency behavior;
|
|
1167
|
+
for full consensus across independent network services, deploy WaveMind with
|
|
1168
|
+
Postgres/Qdrant/ops-layer replication.
|
|
1140
1169
|
|
|
1141
1170
|
Checked-in official LoCoMo retrieval result:
|
|
1142
1171
|
|
|
@@ -1464,7 +1493,7 @@ python benchmarks/dynamic_memory_benchmark.py --engines wavemind chroma --memori
|
|
|
1464
1493
|
| Dynamic memory priority | Wave-field hotness, TTL, priority | Metadata/filter driven | Payload/filter driven |
|
|
1465
1494
|
| Built-in forgetting | TTL and explicit forget | Manual delete/filtering | Manual delete/filtering |
|
|
1466
1495
|
| Best fit | Small to medium memory streams with dynamic recall | Local RAG apps and prototypes | Large-scale vector search |
|
|
1467
|
-
| Scale target today |
|
|
1496
|
+
| Scale target today | Local exact mode for small streams; FAISS/Qdrant/pgvector plus replicated namespaces for production paths | Larger than WaveMind local exact mode | Production vector scale |
|
|
1468
1497
|
|
|
1469
1498
|
WaveMind is not trying to replace dedicated vector databases at scale. The intended product gap is dynamic priority: frequently used memories can become hotter while old or low-priority memories fade. For static RAG over large document collections, use a mature vector database. For memory that needs persistence, scoped recall, TTL, forgetting, and reinforcement, WaveMind is designed to sit above or beside the vector index.
|
|
1470
1499
|
|
|
@@ -1492,8 +1521,9 @@ If you already use Chroma for local memory, see the practical migration guide:
|
|
|
1492
1521
|
from SQLite on load/build, so large service-mode deployments still need a
|
|
1493
1522
|
measured rebuild strategy and index-health monitoring.
|
|
1494
1523
|
- The persisted FAISS backend validates a snapshot against current memory ids
|
|
1495
|
-
and avoids unnecessary FAISS rebuilds when the snapshot matches.
|
|
1496
|
-
a single-node flat-index path
|
|
1524
|
+
and avoids unnecessary FAISS rebuilds when the snapshot matches. FAISS itself
|
|
1525
|
+
is a single-node flat-index path; use `ReplicatedWaveMind` or external
|
|
1526
|
+
database/service replication when that is not enough.
|
|
1497
1527
|
- The `quantized` backend is an explicit int8 candidate-index experiment. It
|
|
1498
1528
|
reduces vector precision and must be benchmarked per workload before use.
|
|
1499
1529
|
- The synthetic long-term memory evidence benchmark is useful for regression and product-shape proof, but public claims should lean on LoCoMo and LongMemEval instead.
|
|
@@ -18,6 +18,7 @@ from wavemind import (
|
|
|
18
18
|
HashingTextEncoder,
|
|
19
19
|
HotMemoryCache,
|
|
20
20
|
QueryResult,
|
|
21
|
+
ReplicatedWaveMind,
|
|
21
22
|
WaveMind,
|
|
22
23
|
audio_payload,
|
|
23
24
|
build_cluster_plan,
|
|
@@ -127,6 +128,116 @@ def run_cache_profile(*, queries: int, capacity: int) -> dict[str, object]:
|
|
|
127
128
|
}
|
|
128
129
|
|
|
129
130
|
|
|
131
|
+
def run_replication_runtime_profile() -> dict[str, object]:
|
|
132
|
+
latencies: list[float] = []
|
|
133
|
+
with tempfile.TemporaryDirectory() as directory:
|
|
134
|
+
memory = ReplicatedWaveMind(
|
|
135
|
+
root_path=Path(directory) / "replicas",
|
|
136
|
+
nodes=[
|
|
137
|
+
{"id": "node-a", "address": "127.0.0.1:8101", "zone": "zone-a"},
|
|
138
|
+
{"id": "node-b", "address": "127.0.0.1:8102", "zone": "zone-b"},
|
|
139
|
+
{"id": "node-c", "address": "127.0.0.1:8103", "zone": "zone-c"},
|
|
140
|
+
],
|
|
141
|
+
replication_factor=3,
|
|
142
|
+
width=16,
|
|
143
|
+
height=16,
|
|
144
|
+
layers=1,
|
|
145
|
+
encoder=HashingTextEncoder(vector_dim=64),
|
|
146
|
+
)
|
|
147
|
+
try:
|
|
148
|
+
namespace = "tenant:replicated"
|
|
149
|
+
write = memory.remember(
|
|
150
|
+
"replicated user memory survives one node loss",
|
|
151
|
+
namespace=namespace,
|
|
152
|
+
)
|
|
153
|
+
placement = memory.placement(namespace)
|
|
154
|
+
lost_node = placement.primary
|
|
155
|
+
memory.set_node_available(lost_node, False)
|
|
156
|
+
started = time.perf_counter()
|
|
157
|
+
results = memory.query("survives node loss", namespace=namespace, top_k=1)
|
|
158
|
+
latencies.append((time.perf_counter() - started) * 1000.0)
|
|
159
|
+
recalled_after_loss = bool(results) and results[0].text == (
|
|
160
|
+
"replicated user memory survives one node loss"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
partial = ReplicatedWaveMind(
|
|
164
|
+
root_path=Path(directory) / "partial",
|
|
165
|
+
nodes=[
|
|
166
|
+
{"id": "node-a", "address": "127.0.0.1:8101", "zone": "zone-a"},
|
|
167
|
+
{"id": "node-b", "address": "127.0.0.1:8102", "zone": "zone-b"},
|
|
168
|
+
{"id": "node-c", "address": "127.0.0.1:8103", "zone": "zone-c"},
|
|
169
|
+
],
|
|
170
|
+
replication_factor=3,
|
|
171
|
+
write_quorum=1,
|
|
172
|
+
width=16,
|
|
173
|
+
height=16,
|
|
174
|
+
layers=1,
|
|
175
|
+
encoder=HashingTextEncoder(vector_dim=64),
|
|
176
|
+
)
|
|
177
|
+
try:
|
|
178
|
+
partial_placement = partial.placement(namespace)
|
|
179
|
+
recovering_node = partial_placement.replicas[-1]
|
|
180
|
+
partial.set_node_available(recovering_node, False)
|
|
181
|
+
partial.remember("repair copies missing replica state", namespace=namespace)
|
|
182
|
+
partial.set_node_available(recovering_node, True)
|
|
183
|
+
repair = partial.repair_namespace(namespace)
|
|
184
|
+
finally:
|
|
185
|
+
partial.close()
|
|
186
|
+
|
|
187
|
+
tombstone = ReplicatedWaveMind(
|
|
188
|
+
root_path=Path(directory) / "tombstone",
|
|
189
|
+
nodes=[
|
|
190
|
+
{"id": "node-a", "address": "127.0.0.1:8101", "zone": "zone-a"},
|
|
191
|
+
{"id": "node-b", "address": "127.0.0.1:8102", "zone": "zone-b"},
|
|
192
|
+
{"id": "node-c", "address": "127.0.0.1:8103", "zone": "zone-c"},
|
|
193
|
+
],
|
|
194
|
+
replication_factor=3,
|
|
195
|
+
width=16,
|
|
196
|
+
height=16,
|
|
197
|
+
layers=1,
|
|
198
|
+
encoder=HashingTextEncoder(vector_dim=64),
|
|
199
|
+
)
|
|
200
|
+
try:
|
|
201
|
+
tombstone_placement = tombstone.placement(namespace)
|
|
202
|
+
missed_delete = tombstone_placement.replicas[-1]
|
|
203
|
+
tombstone.remember("repair must not resurrect deleted memory", namespace=namespace)
|
|
204
|
+
tombstone.set_node_available(missed_delete, False)
|
|
205
|
+
tombstone.forget(
|
|
206
|
+
text="repair must not resurrect deleted memory",
|
|
207
|
+
namespace=namespace,
|
|
208
|
+
)
|
|
209
|
+
tombstone.set_node_available(missed_delete, True)
|
|
210
|
+
suppressed_before_repair = (
|
|
211
|
+
tombstone.query("resurrect deleted memory", namespace=namespace, top_k=1)
|
|
212
|
+
== []
|
|
213
|
+
)
|
|
214
|
+
tombstone_repair = tombstone.repair_namespace(namespace)
|
|
215
|
+
suppressed_after_repair = (
|
|
216
|
+
tombstone.query("resurrect deleted memory", namespace=namespace, top_k=1)
|
|
217
|
+
== []
|
|
218
|
+
)
|
|
219
|
+
finally:
|
|
220
|
+
tombstone.close()
|
|
221
|
+
|
|
222
|
+
return {
|
|
223
|
+
"engine": "WaveMind replicated runtime",
|
|
224
|
+
"nodes": 3,
|
|
225
|
+
"replication_factor": 3,
|
|
226
|
+
"write_quorum": memory.write_quorum,
|
|
227
|
+
"read_quorum": memory.read_quorum,
|
|
228
|
+
"writes": len(write.writes),
|
|
229
|
+
"recalled_after_node_loss": recalled_after_loss,
|
|
230
|
+
"repair_copied_records": repair.copied_records,
|
|
231
|
+
"tombstone_suppressed_before_repair": suppressed_before_repair,
|
|
232
|
+
"tombstone_suppressed_after_repair": suppressed_after_repair,
|
|
233
|
+
"tombstone_repair_deleted_records": tombstone_repair.deleted_records,
|
|
234
|
+
"avg_query_after_loss_ms": statistics.mean(latencies),
|
|
235
|
+
"p99_query_after_loss_ms": percentile(latencies, 99),
|
|
236
|
+
}
|
|
237
|
+
finally:
|
|
238
|
+
memory.close()
|
|
239
|
+
|
|
240
|
+
|
|
130
241
|
def run_multimodal_profile() -> dict[str, object]:
|
|
131
242
|
with tempfile.TemporaryDirectory() as directory:
|
|
132
243
|
memory = WaveMind(
|
|
@@ -213,6 +324,7 @@ def run_benchmark(
|
|
|
213
324
|
simulated_memories=simulated_memories,
|
|
214
325
|
),
|
|
215
326
|
run_cache_profile(queries=cache_queries, capacity=cache_capacity),
|
|
327
|
+
run_replication_runtime_profile(),
|
|
216
328
|
run_multimodal_profile(),
|
|
217
329
|
]
|
|
218
330
|
return {
|
|
@@ -224,8 +336,9 @@ def run_benchmark(
|
|
|
224
336
|
"replication_factor": replication_factor,
|
|
225
337
|
"description": (
|
|
226
338
|
"Deterministic scale-readiness profile for cluster placement, "
|
|
227
|
-
"node/zone loss simulation,
|
|
228
|
-
"payload retrieval. This is
|
|
339
|
+
"node/zone loss simulation, quorum-replicated runtime behavior, "
|
|
340
|
+
"hot-cache behavior, and structured payload retrieval. This is "
|
|
341
|
+
"not a 10M-vector database load test."
|
|
229
342
|
),
|
|
230
343
|
},
|
|
231
344
|
"results": results,
|
|
@@ -262,6 +375,10 @@ def main() -> int:
|
|
|
262
375
|
print(f"| cluster | zone_loss_min_availability | {zone_loss:.3f} |")
|
|
263
376
|
elif result["engine"] == "WaveMind hot cache":
|
|
264
377
|
print(f"| hot cache | hit_rate | {result['hit_rate']:.3f} |")
|
|
378
|
+
elif result["engine"] == "WaveMind replicated runtime":
|
|
379
|
+
print(f"| replicated runtime | recalled_after_node_loss | {result['recalled_after_node_loss']} |")
|
|
380
|
+
print(f"| replicated runtime | repair_copied_records | {result['repair_copied_records']} |")
|
|
381
|
+
print(f"| replicated runtime | tombstone_repair_deleted_records | {result['tombstone_repair_deleted_records']} |")
|
|
265
382
|
else:
|
|
266
383
|
print(f"| structured payloads | precision@1 | {result['precision_at_1']:.3f} |")
|
|
267
384
|
print(f"\nWrote {args.output}")
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"namespace_count": 4096,
|
|
6
6
|
"node_count": 4,
|
|
7
7
|
"replication_factor": 2,
|
|
8
|
-
"description": "Deterministic scale-readiness profile for cluster placement, node/zone loss simulation, hot-cache behavior, and structured payload retrieval. This is not a 10M-vector database load test."
|
|
8
|
+
"description": "Deterministic scale-readiness profile for cluster placement, node/zone loss simulation, quorum-replicated runtime behavior, hot-cache behavior, and structured payload retrieval. This is not a 10M-vector database load test."
|
|
9
9
|
},
|
|
10
10
|
"results": [
|
|
11
11
|
{
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"namespaces": 4096,
|
|
15
15
|
"nodes": 4,
|
|
16
16
|
"replication_factor": 2,
|
|
17
|
-
"placement_ms":
|
|
17
|
+
"placement_ms": 58.688499964773655,
|
|
18
18
|
"max_replica_load": 2413,
|
|
19
19
|
"min_replica_load": 1728,
|
|
20
20
|
"replica_load_stdev": 316.54462560593254,
|
|
@@ -32,8 +32,23 @@
|
|
|
32
32
|
"capacity": 512,
|
|
33
33
|
"hit_rate": 0.92,
|
|
34
34
|
"evictions": 0,
|
|
35
|
-
"avg_lookup_ms": 0.
|
|
36
|
-
"p99_lookup_ms": 0.
|
|
35
|
+
"avg_lookup_ms": 0.0016512502334080637,
|
|
36
|
+
"p99_lookup_ms": 0.005799985956400633
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"engine": "WaveMind replicated runtime",
|
|
40
|
+
"nodes": 3,
|
|
41
|
+
"replication_factor": 3,
|
|
42
|
+
"write_quorum": 2,
|
|
43
|
+
"read_quorum": 1,
|
|
44
|
+
"writes": 3,
|
|
45
|
+
"recalled_after_node_loss": true,
|
|
46
|
+
"repair_copied_records": 1,
|
|
47
|
+
"tombstone_suppressed_before_repair": true,
|
|
48
|
+
"tombstone_suppressed_after_repair": true,
|
|
49
|
+
"tombstone_repair_deleted_records": 1,
|
|
50
|
+
"avg_query_after_loss_ms": 1.435799989849329,
|
|
51
|
+
"p99_query_after_loss_ms": 1.435799989849329
|
|
37
52
|
},
|
|
38
53
|
{
|
|
39
54
|
"engine": "WaveMind structured payloads",
|
|
@@ -45,8 +60,8 @@
|
|
|
45
60
|
],
|
|
46
61
|
"queries": 4,
|
|
47
62
|
"precision_at_1": 1.0,
|
|
48
|
-
"avg_latency_ms": 0.
|
|
49
|
-
"p99_latency_ms":
|
|
63
|
+
"avg_latency_ms": 0.47089999134186655,
|
|
64
|
+
"p99_latency_ms": 0.7531000301241875
|
|
50
65
|
}
|
|
51
66
|
]
|
|
52
67
|
}
|