Sovereign Sanskrit retrieval engine grounded in Pāṇini's generative grammar. The Kaṇaja FSH algorithm beats the BEIR sentence-transformer baseline by >2x on a 21-query Sanskrit benchmark using only the 3-channel φ-RRF core (semantic + BM25 + prosodic). The novel rerankers (Poincaré, topology, fractal) are shipped as opt-in research components — see "Calibration honesty" below.
| Metric (production default — 3-channel φ-RRF) | Value |
|---|---|
| nDCG@5 at N=21 (small bench) | 0.7620 |
| nDCG@5 at N=141 (expanded bench) | (production default; primary number) |
| BEIR sentence-transformer baseline (same N=21) | 0.353 |
| BM25 keyword-search baseline (same N=21) | 0.080 |
| Mean query latency (warm) | 82 ms |
| Indexed Sanskrit chunks | 6,309 |
| Indexed classical texts | 13 |
Earlier README versions reported nDCG@5 = 0.7873 for a "full stack with
Poincaré + topological reranker enabled." That number is true at N=21 but
does not generalise. When the bench was expanded from N=21 → N=141 (see
tests/sanskrit_bench_v2.py and the audit at vak_engine_audit_2026-05-08):
- the Poincaré-consensus reranker delivered +0.0067 at N=21 but −0.0143 at N=141 — its small-N lift was inside the noise floor;
- the topological-persistence reranker similarly collapsed from +0.0186 at N=21 to +0.0019 at N=141;
- the fractal-affinity reranker was net-negative at every non-zero weight on the post-MFDFA-backfill embeddings.
All three rerankers are therefore shipped at weight 0 in production
(retrieval/rank_fusion.py) — the headline claim of the production engine
is the 3-channel φ-RRF result above. The novel rerankers are kept in the
codebase, tested, and exposed as opt-in components for researchers who want
to tune their own weights against their own corpora.
This is the public version of the falsify-eval discipline applied to the authoring engine: when scaling the bench falsifies a small-N claim, the small-N claim does not survive into the production headline. The plumbing stays for future investigation; the marketing does not.
Verified at commit 1e346b8 on branch phase1-fractal-upgrades (2026-05-01).
Score history (transparent):
19a743fbaseline = 0.7522 (pre-Phase-1, Δα=0 bug-artifact — seevak_engine_tech_debt_2026-04-30.md)39f9b7cstep 1.5 claimed 0.7891 (snapshot at commit time; subsequent ALTER TABLE migrations and MFDFA backfills mutatedcorpus/fractal_signatures.db, so this number is no longer reproducible against today's runtime artifacts — running 39f9b7c's code on today's DB scores 0.7206)e3c2748phase-A claimed 0.7620 ("score-neutral" — actual measurement, not a regression vs the unreproducible 0.7891)8265bf1phase-B = 0.7712d0bfbb4step 4 (Ricci pruning, offline only) = 0.76201e346b8step 5 (Poincaré, w=0) = 0.76201e346b8step 5 (Poincaré, w=0.001 default) = 0.7686c14b242README + Poincaré default flip- next commit step 3-wire-in (topo, w=0.001 default) = 0.7873 ← current (Item 3 was committed in 632187c but never wired into kanaja_fsh.py; wire-in landed 2026-05-01, calibrated via tests/bench_topo_sweep.py)
Lesson logged in vak_engine_tech_debt_2026-04-30.md: "score-neutral" commit annotations are only meaningful if the corpus DB hash is also locked. See tools/lock_corpus_state.py (planned).
# 1. Install (M1 / arm64; Python 3.14 required for vak_core wheel)
./install.sh # one-shot setup
# OR manually:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.lock.txt # macOS-arm64 / cp314 only — see file header
# 2. Build the corpus (or copy an existing fractal_signatures.db into corpus/)
python3 tools/preprocess_corpus.py # ITRANS → UTF-8
python3 main.py build # full build (~15 min on M1)
# 3. Sanity check
python3 tests/sanskrit_bench.py # expect mean nDCG@5 = 0.7873 (P+T at w=0.001)
# 4. Serve
make up # FastAPI on :8080 (Docker arm64)
curl http://localhost:8080/healthA query passes through three retrieval channels in parallel — semantic (FAISS IndexFlatIP over multilingual MiniLM-L12 ONNX int8 embeddings), lexical (BM25 with IAST-aware tokenization), and prosodic (Vedic svara / Dravidian quantity histogram similarity). Their per-chunk ranks are combined by φ-weighted Reciprocal Rank Fusion. Final results are the top-K of that fusion. A fourth channel — fractal-affinity rerank using h2/Δα/log1p(asym_f) MFDFA features — was tried and verified net-negative on 384-dim embeddings (full A/B in tests/bench_ab.py); the channel is disabled at default weight but the plumbing is preserved for future kernel-form changes.
┌─────────────────────────────────────────────────────────────────┐
│ query (English / IAST / mixed) │
└────────────────────────────────┬────────────────────────────────┘
▼
┌────────────────────┴────────────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ semantic │ │ bm25 │ │ prosodic │ (channels — parallel)
│ FAISS │ │ rank_bm25│ │ svara │
└────┬─────┘ └────┬─────┘ └────┬─────┘
└────────────┬───────┴───────────────────┘
▼
φ-weighted RRF (rank_fusion.fuse_rankings)
▼
fractal-affinity rerank (DISABLED at default; plumbing kept)
▼
Pramāṇa assignment (epistemic-status label)
▼
top-K + closed-loop log (feedback/loop.py best-effort)
| Path | Role |
|---|---|
retrieval/ |
The core 3-channel pipeline — kanaja_fsh.py, rank_fusion.py, adaptive_weights.py, engine_cache.py, pramana.py |
linguistic/ |
Encoders + IAST utilities — hybrid_encoder.py, onnx_encoder.py, iast_utils.py, domain_grid.py, auto_cluster.py, dravidian_flow.py, sanskrit_grid.py |
fractal/ |
MFDFA + IFS + Hurst — hurst.py, signature_db.py, ifs_engine.py, compression.py |
corpus/ |
Ingestion + adapters — universal.py, adapters/file_adapter.py, adapters/auto_anchor.py, plus the SQLite DB and FAISS index (gitignored) |
api/ |
FastAPI gateway — gateway.py (9 endpoints, OpenAI-compatible) |
output/ |
LLM synthesis — synthesizer.py (Kimi → Moonshot → Ollama → extractive fallback chain) |
mesh/ |
Phase 3 P2P mesh code (φ-ring, mDNS discovery, IFS sync). Currently not wired into make up; treat as library. |
feedback/ |
Closed-loop micro-update + queryable artifact store |
tests/ |
sanskrit_bench.py (truth) + bench_ab.py (A/B harness, --weight parameterised). Unit tests live in tests/unit/ (Phase B). |
tools/ |
One-off and recurring CLI utilities — see tools/SCRIPTS.md for the inventory |
models/ |
ONNX int8 encoder + tokenizer (gitignored — regenerable via tools/export_onnx.py) |
vak_core/ |
Rust hot-path crate (in progress — see KIMI_TASK_RUST.md) |
docker/, Dockerfile, docker-compose.yml |
Phase 7 deploy. Use requirements.docker.txt (Python 3.12, omits vak_core). |
Makefile |
make up / down / bench / shell / status / logs |
- Phase 1 — Single-node engine + MFDFA features (h2/Δα/asym_f) backfilled, A/B verified
- Phase 2 — API + IFS compression (7.75 ×)
- Phase 3 — P2P mesh (φ-ring, mDNS, IFS sync) — code exists in
mesh/, not yet runtime-wired - Phase 4 — Multilingual encoder, English-anchor bridging, adaptive weights
- Phase 5 — Universal corpus adapter (YAML → any language/domain)
- Phase 6 — Domain grid (auto-cluster + presets: legal/medical/philosophy)
- Phase 7 — Docker deploy (linux/arm64, one-command
make up) - Phase 8 — Hosted API + multi-tenant — next; see audit Phase C blockers
- Rust hot-path rewrite (in progress via
kc/KIMI_TASK_RUST.md) - arxiv v2 LaTeX
# Truth: full 21-query Sanskrit benchmark
python3 tests/sanskrit_bench.py # expect mean nDCG@5 = 0.7873 (P+T at w=0.001)
# A/B: fractal-affinity ablation (6 modes × 5 weights)
python3 tests/bench_ab.py # ≈3 min full sweep
python3 tests/bench_ab.py --weight 0.090 # single-weight slice (≈30 s)A regression that drops nDCG@5 below 0.78 in either should block the change.
A full audit lives at ../vak_engine_tech_debt_2026-04-30.md (parent folder). Phase A hygiene items are landed or staged in tools/cleanup_phase_a.sh. Phase B (CI + unit tests + structured logging) is the next track. Phase C (multi-tenant blockers — schema versioning, slowapi, secrets) and Phase D (bonus features: p-adic ultrametric, lacunarity) are listed there.
- Working log:
~/Documents/Obsidian Vault/Projects/Vak-Kanaja/work-log/ - Resume context:
~/Documents/Obsidian Vault/Projects/Vak-Kanaja/Claude-Context.md - arxiv v2 draft:
../vak_kanaja_arxiv_v2.md(markdown; LaTeX conversion pending) - Rust rewrite plan:
KIMI_TASK_RUST.md