Winnex Stack
WINNEX — Weighted Inference Neural Network Enhancement. A deterministic, training-free framework that improves a pretrained model using only the geometry it already learned.
What WINNEX is
Frontier models in regulated sectors cannot be retrained. You do not fine-tune a model that already passed validation, and you cannot ship a gradient step into a system under audit. WINNEX improves inference without touching the weights.
At the centre sits the Madhava bound engine: deterministic vector search in which every excluded document carries a Cauchy–Schwarz proof of exclusion. Around it sit a deterministic spectral tokenizer, a weight balancer that fuses multiple models without retraining, and native C++/OpenCL inference that runs without a GPU.
An approximate index tells you "here are the nearest neighbours." It cannot tell you "and here is the proof that nothing relevant was missed." Madhava answers the second question — per document, with arithmetic the reader can re-run.
That is the entire value proposition. Everything else in this stack exists to feed it, wrap it, or run alongside it.
Two propositions, deliberately distinct
The stack serves two different buyers with two different problems. They should not be sold as one thing, because they are not one thing.
The gold standard for regulated RAG
Who. Legal, medical, financial and government organisations — anywhere a regulator, auditor or court can ask why a document was not returned.
The problem. "The search said there was nothing — but what if it was wrong?"
The stack. normalize →
madhava → tracer.
The trade. You give up 20 to 100 times query speed above 50,000 vectors. In exchange you receive a mathematical and cryptographic certificate that no relevant document was lost.
The claim. The only stack that turns "we did not find it" into "we proved it does not exist."
Next-generation inference on restricted hardware
Who. Edge computing, startups with a limited GPU budget, and environments where security policy forbids PyTorch or CUDA.
The problem. A 7B model does not fit a 16 GB card with the standard stack, and PyTorch is a large, opaque binary.
The solution. winnex-nano — a
PyTorch-free inference engine running on OpenCL for CPU and GPU, with bf16
memory management that runs models Transformers rejects with OOM, while
keeping perplexity bit-exact with the reference.
The evidence. Qwen2.5-7B on a 16 GB card: 7.5 s against 69.8 s on CPU, perplexity 15.55171 against 15.55172. Identical output, 9.3× faster.
These do not compete. Proposal A is about proof. Proposal B is about reach — running models on hardware that would otherwise be unavailable. An organisation can adopt B to make the model run where it needs to, and A to make the retrieval defensible. The shared C++ core means adopting one does not double the footprint of the other.
The usual vendor forces a choice: either a compliance product that cannot run where you need it, or an optimized runtime with no audit story. WINNEX built one kernel set and derived two products from it — a bound engine for proof and an inference engine for reach. That is not a positioning trick; it is the reason the same team could ship both in two years on no outside capital.
Why this matters commercially
In a bank, a hospital, a law firm or a government body, the question is not "how fast is the search?" The question is "can you prove the search was complete?" — asked by a regulator, an auditor, a judge or an opposing counsel. An answer of "we use a well-known approximate index" is not a defence. A per-document mathematical bound is evidence.
This reference covers every package Winnex publishes. Each entry states what the package does, how to install it, a working example, and what it deliberately does not do.
If you need the fastest possible approximate search and nobody will ever ask why a document was excluded, use FAISS or Pinecone. Above roughly 50,000 vectors they are faster at query time. WINNEX exists for the case where the proof is the product — and at that job it is the only option in this stack.
Overview
The stack is layered and every layer is independent. You can run the engine alone, add the audit trail later, and never touch the inference or embedding packages. Nothing here requires the rest.
This section explains what each component is for, in plain terms, before the reference sections go into detail.
winnex-madhava — the search engine
What it is. A vector index that answers a question ordinary indexes cannot: prove that the search did not miss a relevant document.
What it does. When you ask for the 10 nearest vectors, it returns those 10. For every other vector in the corpus, it computes a Cauchy–Schwarz upper bound on how similar that vector could have been. If the bound sits below the similarity of the 10th result, the vector provably could not belong in the answer — and the arithmetic is recorded.
Why you would want it. Because "we searched and found nothing" is not a defensible statement in a regulated process. "We searched, found nothing, and here is the proof that nothing was there" is.
What it costs. Query speed, above roughly 50,000 vectors. It is 20 to 100 times slower than HNSW at that scale. That is the trade, and there is no way around it.
What it gives back. Two things HNSW cannot match. The index builds 23 times faster — 1.45 s against 33.6 s for the same corpus of 99,800 vectors. And below 50,000 vectors, query time is better than HNSW, because the bound eliminates most of the corpus before any distance is computed. The crossover at 1,000 vectors: 0.55 ms against 0.69 ms.
winnex-tracer — the audit artifact
What it is. The layer that turns a mathematical proof into a document.
What it does. Takes the per-query proof from the engine and writes it into a tamper-evident record: write-once storage, Ed25519 signature, SHA3-256 hash chain linking each record to the previous one, and an audit commitment so the issuer cannot later deny having produced it.
Why you would want it. The engine proves something to a mathematician. The tracer proves it to a court, an auditor or a regulator — who need a file with a hash, a signature and a timestamp, not a formula.
Think of it as: the engine produces the evidence, the tracer produces the exhibit.
winnex-ai-normalize — the input adapter and quality gate
What it is. The piece that turns whatever you have — text, or vectors from another system — into the exact format the engine accepts, and then tells you whether that input is good enough for the guarantee to mean anything.
What it does. Embeds text through a provider of your choice, validates the result, applies the L2 unit-norm contract, optionally quantizes to uint8 — and runs a thirteen-flag audit over the corpus before it is ever indexed.
Why the audit matters more than the conversion. A bound
proof is only as strong as the vectors it was computed on. The engine will
happily index a corpus full of NaN and return
bound_violations = 0, because the arithmetic is correct — the
inputs were garbage. This package is what stops that from happening
silently.
The flag system is the most useful part of this package and the part most people skip. It has its own section below.
The flag system — what it is for and why it exists
The purpose of signalling. Every quality defect produces a flag: a stable machine-readable code, a severity, a measured value and a threshold. Not a warning buried in a log — a structured object your pipeline can act on. The codes are stable across versions, so CI gates, monitoring rules and ingestion policy can key on them without parsing prose.
Three severities: pass, warn, fail.
A report exposes fail_flags, warn_flags and
has_fail, so the caller decides policy — abort ingestion,
quarantine the batch, alert, or proceed with recorded risk.
The thirteen flags
| Code | Severity | What it detects |
|---|---|---|
dataset.nan | fail | NaN or infinity anywhere in the corpus. These overflow float32 and produce garbage scores with zero bound violations |
dataset.degenerate | warn | Zero or negligible variance — a corpus where every vector is nearly identical, so no search can separate them |
dataset.foldable | warn | The one that matters. How much of the corpus the bound actually eliminates. High coverage means the proof is doing real work; low coverage means you pay for the proof and get almost none of the benefit |
dataset.recall_not_guaranteed | warn | The returned top-K is the best within the candidate pool, not proven to be the global top-K — silent collapse with violations still at zero |
embedding.resolution | warn | Gap between the top-1 and the k-th score is too small — the embedding cannot separate neighbours from noise |
embedding.provider_drift | warn | Same provider but the embedding space moved since the reference; old and new vectors are no longer comparable |
embedding.cross_provider | warn | Provider was switched. Two encoders produce two incompatible spaces — mixing them corrupts every query |
embedding.dim_shift | warn | Dimension changed between batches |
embedding.norm | warn | Norm distribution abnormal — typically a partially failed embedding call |
embedding.anisotropy | warn | The uint8-quantization trap: vectors collapsed into a narrow cone, destroying the separability the bound depends on |
integrity.corpus_alignment | warn | Corpus and reference misaligned — row i of the corpus does not correspond to row i of the labels |
integrity.query_corpus_proximity | warn | A query index collides with a corpus index — the benchmark is measuring the engine against itself |
dataset.recall_not_guaranteed | warn | Covered in its own section below — the flag that separates a report of success from a report of truth |
Why dataset.foldable decides whether the proof is worth
anything
The bound is only useful if it eliminates documents. If the corpus geometry lets the bound prune 80% of candidates before the exact path, the engine is doing its job. If it prunes 8%, you pay the cost of the proof and receive almost none of the benefit — and the report states the measured fraction instead of letting you assume.
The thresholds are calibrated against the engine, not guessed:
bound_frac ≥ 0.50 is strongly foldable, below 0.20
triggers the probe gate. They are documented in source next to the
constants.
Why dataset.recall_not_guaranteed exists
This flag was added after an honest discovery. A configuration can show zero bound violations and still not be globally guaranteed, because the violation count only covers the candidate pool. If stage-2 truncation dropped the true neighbour before it was ever considered, the bound never had a chance to be violated. The report says it plainly:
seed recall@K = 0.375 vs the motor's own search_exact (< floor 0.95);
8/8 seed queries are recall_guarantee=pool_only — the returned top-K is
the best WITHIN the pool, NOT proven the global top-K. viol=0 does not
cover this (silent collapse). For a global guarantee use
audit_exhaustive=True or k1=N.
This is the single most valuable output of the package. It is the difference between a system that reports success and a system that reports the truth.
How a pipeline should use the flags
from winnex_ai_normalize import audit_corpus, QualityGateError
report = audit_corpus(corpus, dim=384)
# 1. reject a corpus the engine cannot handle
if report.has_fail:
for f in report.fail_flags:
print(f"[{f.code}] {f.message}")
raise QualityGateError("corpus rejected")
# 2. is the proof actually doing work on this corpus?
fold = next((f for f in report.warn_flags
if f.code == "dataset.foldable"), None)
if fold and fold.metric < 0.2:
log.warning("bound covers only %.1f%% of the corpus",
100 * fold.metric)
# 3. never ship a config whose top-K is only pool-proven
recall = next((f for f in report.warn_flags
if f.code == "dataset.recall_not_guaranteed"), None)
if recall:
raise QualityGateError("top-K is not globally proven")
Because the codes are stable identifiers, they belong in your CI and your
alerting. A corpus that trips dataset.nan should never reach the
index — and the flag carries the exact percentage so the alert can say how
bad it is without anyone opening a log.
winnex-xfactor — the embedding shortcut
What it is. A way to get a usable embedding space from a model you already have, without training anything and without calling an external API.
What it does. Reads the model's own token-embedding table, computes the subspace where those embeddings actually live, and produces a projection basis. It derives this from the weights — it never runs the model.
Why you would want it. When you cannot send data to an embedding API (air-gapped, regulated, cost) and you do not want to train anything, this gives you a deterministic encoder derived from weights you already possess.
What it is not. A product on its own. It exists to feed the engine when a hosted embedding provider is not an option.
winnex-nano — the inference engine
What it is. A general-purpose LLM inference engine built on OpenCL. It runs on GPU and on CPU, without CUDA.
What it does. Loads the same weights and the same BPE vocabulary as Hugging Face Transformers and produces the same outputs — with memory management that lets larger models fit smaller cards.
It is bit-exact, not approximate. Measured on Qwen2.5-7B with 131 tokens: CPU path perplexity 15.55172, GPU path 15.55171 — a relative difference of 7×10⁻⁶. The checkpoint is already bf16, so the GPU reads exactly the numbers the CPU reads after widening them to f32. Nothing that was in the file is lost.
Where it wins. A 7B model in f32 is 26.1 GB against a 16 GB
card — the standard Transformers path runs out of memory. WINNEX sized the
weights in bf16 and streamed lm_head in 512-row blocks, taking that
tensor from 2.18 GB down to 7.3 MB. The 7B fits a 16 GB GPU and runs
9.3 times faster than CPU — 7.5 s against 69.8 s for the same
131 tokens, with identical perplexity.
This is an infrastructure alternative, not only a search feature. The engine competes on correctness and memory efficiency against the standard stack — not merely on producing exclusion proofs.
What it is still not. It is not a training framework, and it does not replace fine-tuning. The spectral tokenizer path remains slower and less compact than BPE; it exists as an autonomous encoding, not a drop-in replacement. Use the standard BPE path when you need parity with your existing pipeline.
winnex-tracer-core — the shared base
What it is. The substrate the tracer family is built on: write-once storage, signing, hash chain, retention policy.
Why it exists as a separate package. So the four vertical domains (GOV, JUS, MED, GAP) reuse one audited implementation instead of four copies. You install it on its own only when building a new tracer domain.
winnex-madhava-sec — agent security
What it is. The same bound pruning, applied to a different problem: detecting prompt injection in an AI agent's input.
What it does. Prunes most of the candidate corpus with the bound before the expensive classifier runs. That pruning is where the saving comes from.
What it does not do. It does not improve detection accuracy. Measured F1 is 0.8183 with pruning against 0.8262 for a direct search — the difference is noise. Adopt it for cost, never for accuracy.
Weight balancing — improving a model you cannot retrain
The problem. A bank runs a frontier model that has been through validation. It cannot be fine-tuned: the weights are frozen by policy, and a gradient step would void the validation. But the model performs unevenly across the institution's actual documents.
The mechanism. WeightBalancer fuses the weight
matrices of several models into one, without any training step:
W′ = Σᵢ αᵢ · R(qᵢ) · Wᵢ
Each source model contributes with a coefficient αᵢ and a
rotation R(qᵢ) derived from its own geometry. The result behaves
as a single model. No backward pass, no labelled data, no fine-tuning
dataset.
What it is honest about. Weight balancing changes the geometry the model reasons over. It does not make a weak model strong, and it does not improve generation quality in the way fine-tuning would. What it does is let an institution combine models it already has and already trusts — a general model, a domain model, an internally trained model — into one inference path that serves all its document types.
Streaming — indexing 100M vectors without loading them
The problem. A large corpus does not fit in RAM. A 100M vector corpus at 128 dimensions is roughly 12.8 GB raw. Loading it to build an index means either a very large machine or a very long wait.
The mechanism. The corpus is memory-mapped, never read into RAM. The C++ core builds quantized projections in streaming blocks of 500,000 vectors at a time, then caps stage-2 survivors so the exact post-filter stays bounded regardless of corpus size.
The measured result. Building the index over 100M vectors took 342.6 seconds on 4 CPUs, with 0 bound violations. Peak memory 28 GB. That is a build that fits in a maintenance window instead of a weekend.
An index that rebuilds in seconds instead of tens of minutes unlocks patterns that are simply not viable otherwise: re-indexing per tenant, rebuilding nightly instead of weekly, running experiments across dozens of configurations, and continuous ingestion where new documents enter the index as they arrive.
The build advantage measured on 99,800 vectors: 1.45 s against 33.6 s for HNSW — 23 times faster. At 1M vectors the build completes in 1.69 s.
How the pieces fit
| If you need… | Install |
|---|---|
| Proof that a search did not miss a document | winnex-madhava |
| That proof as a signed, timestamped artifact | winnex-tracer |
| Text converted to vectors, without silent corruption | winnex-ai-normalize |
| Embeddings without an external API call | winnex-xfactor |
| A 7B model on a 16 GB GPU, bit-exact with Transformers | winnex-nano |
| LLM inference without a GPU at all | winnex-nano |
| Prompt-injection screening at lower inference cost | winnex-madhava-sec |
| A new vertical domain on top of the tracer | winnex-tracer-core |
Installation
All packages are on PyPI and require Python 3.8 or newer. The C++ cores ship pre-built inside the wheels — no compiler, no build step.
# the core engine — start here
pip install winnex-madhava
# add-ons, install only what you need
pip install winnex-ai-normalize # text → vectors, with failover
pip install winnex-xfactor # manifold basis
pip install winnex-nano # native CPU inference
pip install winnex-tracer # audit trail
pip install winnex-madhava-sec # agent security
Verify the install
python -c "import winnex_madhava as m; print(m.__version__)"
# expected: 1.9.23
Requirements by package
| Package | Requires |
|---|---|
winnex-madhava | Python ≥ 3.8, NumPy |
winnex-ai-normalize | Python ≥ 3.8, NumPy, httpx |
winnex-xfactor | Python ≥ 3.8, NumPy |
winnex-nano | Python ≥ 3.8, NumPy, winnex-madhava ≥ 1.8.1 |
winnex-tracer | Python ≥ 3.8, NumPy |
winnex-tracer-core | Python ≥ 3.8, NumPy |
winnex-madhava-sec | Python ≥ 3.8, NumPy, scikit-learn, sentence-transformers, pandas |
Architecture
raw text raw vectors
│ │
▼ │
winnex-ai-normalize ◄────────────┘
· provider failover (OpenAI / Qwen3 / nano / xfactor / direct)
· validate dimension, NaN, norm — fails loudly
· L2 unit-normalize (cosine contract)
· quantize float32 → uint8
│
▼
winnex-madhava ──────────────────────► top-K
· Cauchy–Schwarz bound pruning +
· exact-L2 post-filter per-document proof
· audit_exhaustive mode of exclusion
│
▼
winnex-tracer
· WORM storage
· Ed25519 signing
· SHA3-256 hash chain
· AuditCommitment — non-repudiation
│
▼
audit report — the artifact a regulator or court acceptswinnex-madhava
core engine v1.9.23Deterministic vector search with mathematical guarantees.
What it solves
Approximate indexes answer "here are the k nearest neighbours." They cannot answer "prove you did not miss a relevant document." Madhava answers the second question.
For every vector excluded from the result, the engine computes a Cauchy–Schwarz upper bound on the inner product. That bound converts into a lower bound on squared L2 distance. If the lower bound exceeds the distance of the k-th result, the vector cannot be in the top-K — and the engine records the arithmetic that proves it.
Quick start
import numpy as np
import winnex_madhava as mad
# corpus: float32, L2-normalized, shape (N, D)
corpus = np.random.rand(10000, 384).astype(np.float32)
corpus /= np.linalg.norm(corpus, axis=1, keepdims=True)
engine = mad.build_engine(
corpus,
dim=384,
metric="cosine",
k=10,
k1_fraction=1.0, # keep all bound survivors
postfilter=True, # exact-L2 re-rank
audit_exhaustive=True # produce the proof
)
result = mad.retrieve(engine, corpus[0], k=10)
result["indices"] # top-K
result["bound_violations"] # must be 0
result["proof"] # per-document bound record
The default k1_fraction=0.05 keeps only 5% of candidates after
the wide bound. On some corpora that discards correct neighbours. Set
k1_fraction=1.0 with postfilter=True for exact
recall. This was measured across configurations, not assumed.
When to use it
- A regulator or court asks why a document was not returned
- Missing a document carries a financial or legal consequence
- You must hand an auditor a machine-checkable artifact
- You want proof per query, not a sampling argument
When not to use it
- You need sub-millisecond latency — use FAISS or HNSW
- Billions of vectors and cost dominates everything
- Nobody will ever ask why something was excluded
Top-1 agreement with exact cosine scan: 1.0000. setR@10 overlap: 0.9933. Bound violations: 0 across every configuration tested. 300 queries in 0.15 s.
winnex-ai-normalize
input layer v1.4.6Turns any input into a valid float32 corpus for the engine.
The Madhava engine is agnostic — it consumes float32 vectors and nothing else. This package is the adapter: it embeds text through a provider, validates the result, applies the L2 unit-norm contract, and optionally quantizes to uint8.
What it guarantees
- Provider failover — OpenAI, Qwen3, nano, xfactor or direct vectors, tried in order
- No silent fallback — if every provider fails it raises. It never substitutes a placeholder vector
- Validation — dimension mismatch, NaN and zero-norm are rejected before reaching the engine
A zero vector or random placeholder passes validation in most pipelines and silently corrupts every downstream bound. The engine's guarantee is only as good as the vectors it receives. Fail loudly instead.
from winnex_ai_normalize import normalize
corpus = normalize(
texts=["first document", "second document"],
provider="openai",
dim=384,
quantize=False
)
winnex-xfactor
embedding v1.0.8Training-free manifold basis extracted from a pretrained model's embedding table.
Given a model's embed_tokens matrix, X-Factor computes the
orthonormal basis of the subspace where those embeddings actually live. It
never runs the model — the basis is derived structurally.
Ē = E − mean(E) # center
C = ĒᵀĒ / V # covariance (D×D)
C = U Λ Uᵀ # eigendecomposition
r = min{r : cumsum(Λ₁..r)/ΣΛ ≥ τ} # effective rank
X = U[:, :r] # manifold basis (D×r)
P = X·Xᵀ # orthogonal projector
What you get
- Deterministic — identical model weights always produce an identical basis
- No training, no sampling, no random seed
- Dimension reduction that preserves the manifold where tokens live
X-Factor is a shortcut, and it should be described as one. It gives you a
usable embedding space without an API call, which matters when data cannot
leave the premises. But the real engineering value in this stack sits in
winnex-madhava for proof and winnex-nano for
inference reach. Adopt X-Factor when you need embeddings offline; do not
mistake it for the reason to choose WINNEX.
winnex-nano
inference v0.1.47General-purpose LLM inference on OpenCL — GPU and CPU, no CUDA. Bit-exact with Transformers, with memory management that fits a 7B model on a 16 GB card.
Model-agnostic (Qwen, BERT, DeepSeek, GPT), built on the Madhava kernels — the same QKᵀ matmul and the same selective top-K with Cauchy–Schwarz bounds. No logic is duplicated between the search engine and the inference engine.
Correctness comes first
The engine loads the same weights and the same BPE vocabulary as Hugging Face Transformers. It is not an approximation of the model — it is the model.
| Path | Perplexity | Time (131 tokens) |
|---|---|---|
| CPU | 15.55172 | 69.8 s |
GPU (device mode) |
15.55171 | 7.5 s |
Measured on RTX 5060 Ti 16 GB, 31 GB host, Qwen2.5-7B. Relative perplexity difference: 7×10⁻⁶. The checkpoint is already bf16, so the GPU reads exactly the numbers the CPU reads after widening to f32 — nothing that was in the file is lost. That is 9.3× faster with identical output quality.
Memory strategy — why this fits where Transformers does not
A 7B model in f32 is 26.1 GB against a 16 GB card. The standard path raises out-of-memory. Four decisions change that:
| Decision | Effect |
|---|---|
| bf16 weights when f32 does not fit | 26.1 GB → 13.1 GB. The dtype is chosen once for the whole model — mixing formats per matrix corrupts every launch after the first switch |
lm_head streamed in 512-row blocks |
2.18 GB → 7.3 MB for the largest single tensor (152064 × 3584) |
| Weights keyed by tensor name, not host pointer | Without this the device cache never hits and the GPU re-uploads 14.2 GB per forward — measured slower than CPU (90.8 s against 67.0 s) |
| 16×16 tiled GEMM in local memory | The original kernel measured 1 FLOP/byte against a machine balance of ~26 — it waited on its own weight reads. Tiling cuts global traffic per MAC by ~8× |
enable_gpu() picks one of three strategies automatically:
| Mode | What lives where | When |
|---|---|---|
device |
Every projection on the GPU (bf16 when f32 does not fit); host keeps only norms and biases | The model fits in VRAM |
stream |
One layer at a time through a scratch buffer | Half the model fits, the whole does not |
cpu |
Nothing on the device | The model does not fit even at bf16 |
Modules
| Module | Purpose |
|---|---|
ForwardEngine |
General-purpose LLM forward pass, bit-exact with Transformers |
WeightBalancer |
Multi-model fusion: W′ = Σᵢ αᵢ·R(qᵢ)·Wᵢ |
ChunkEngine |
Chunked generation with Madhava working memory |
SpectralTokenizer |
Character → quaternion spectrum. Deterministic, no vocabulary. An autonomous encoding, not a BPE replacement |
server_sse |
OpenAI-compatible /v1/chat/completions (stream and non-stream) |
Selective attention — exact, not heuristic
The default is exact causal softmax. MADHAVA_TOPK_ATTN=1
enables a selective mode where keys are pruned while the mass they account for
stays within MADHAVA_EPSILON_MASS of the full softmax mass, and the
retained set is renormalised. The guarantee is exact rather than a score bound:
‖attn_full − attn_pruned‖₁ ≤ 2ε.
On Qwen2.5-0.5B over 80 LAMBADA items, quality is preserved across all three arms — CPU softmax 35.0%, CPU with ε=1×10⁻⁴ 35.0%, CPU with ε=0.05 36.2% — all inside the confidence interval.
pip install winnex-nano
# with the OpenAI-compatible server
pip install "winnex-nano[server]"
Not a training framework and not a replacement for fine-tuning. The spectral tokenizer path is slower and far less compact than BPE — it exists as an autonomous encoding for the native engine, not as a drop-in replacement for a BPE-trained model. Generation quality through the spectral path is not yet demonstrated with standard metrics; the retrieval and the bit-exact Transformers-parity path are the load-bearing claims.
winnex-tracer
audit trail v1.1.3Turns a proof into a document.
The engine produces a proof per query. The tracer turns those proofs into a tamper-evident record that survives outside the system — the artifact you hand to an auditor, a regulator or a court.
| Component | Function |
|---|---|
| WORM storage | Write-once record of every query |
| Ed25519 signing | Each record signed by the issuing node |
| SHA3-256 hash chain | Each record commits to the previous — tampering breaks the chain |
| AuditCommitment | Non-repudiation: the issuer cannot deny producing it |
Domains
Four vertical wrappers ship inside the same package:
- Tracer-GOV — public sector audit and external control
- Tracer-JUS — e-discovery and legal production
- Tracer-MED — clinical retrieval and billing audit
- Tracer-GAP — financial gap and reconciliation analysis
pip install winnex-tracer # core only
pip install "winnex-tracer[med]" # with the medical domain
winnex-tracer-core
shared base v1.0.2The substrate the tracer family shares: WORM storage, Ed25519/ICP signing, tamper-evident audit log, retention policies and AuditCommitment. All four domains depend on it. Install it standalone only when building a new tracer domain.
winnex-madhava-sec
security v3.1.0Agent security through the same bound pruning.
Uses Cauchy–Schwarz bound pruning to detect prompt injection and classify agent inputs. Pruning removes most of the corpus before any classifier runs — that is where the saving comes from.
pip install winnex-madhava-sec
On published agent-security datasets, detection F1 is 0.8183 with bound pruning against 0.8262 for direct search. Accuracy is essentially equal — pruning does not make classification better.
What it saves is inference cost: the bound removes the majority of candidates before the expensive path. Do not adopt this package expecting higher accuracy.
Benchmarks as use cases
Benchmarks are only useful when they tell you what you can build. Each table
below is a measured scenario — not a leaderboard entry, but a configuration
with a concrete deployment behind it. Every number comes from code in this
repository against external ground truth, and the notebooks are public on
Kaggle (kleniopadilha).
Ground truth is external in every case: BIGANN's reference, an exact cosine scan, or the ANS regulatory document itself. Nothing was annotated by hand, and nothing is a self-referential claim of the engine against itself. Where a published figure was found to be invalid — the BIGANN ground-truth file in one Kaggle dataset turned out to point at the wrong vectors — it was withdrawn rather than kept. That is why some older numbers you may find quoted elsewhere no longer appear here.
Scenario: a regulatory document store per tenant
The setup. Ten thousand to fifty thousand documents per department. Nobody outside asks how fast it is; the audit team asks whether the retrieval was complete.
What the numbers say. In this size range Madhava is not just competitive, it is faster at query time than HNSW — 0.99 ms against 1.18 ms at 10,000 vectors, 2.42 ms against 2.35 ms at 50,000. The bound removes most of the corpus before any distance is computed, so below the crossover the proof costs effectively nothing. Above it, HNSW wins on latency and Madhava wins on the artifact.
Scenario: a corpus that grows every day
The setup. New documents arrive continuously and the index must be rebuilt without stopping the service.
What the numbers say. A 1M-vector index builds in 1.69 s. A 100M-vector corpus builds in 342.6 s on four CPUs, memory-mapped, with 0 bound violations. Rebuilding is a maintenance loop, not an outage.
Scenario: a hospital billing dispute
The setup. An operator denies a claim. The hospital needs to show the procedure was covered under the contract's segment.
What the numbers say. Against the ANS Rol as ground truth, coverage is decided correctly 97.5% of the time. A bill that should be paid is wrongly denied 1.5% of the time; a bill that should be denied is wrongly covered 1.0% of the time. Identifying the exact procedure is harder — 63.4% — and that figure is stated here because a procurement team will ask.
Scenario: proving that a search missed nothing
The setup. An auditor asks which documents were excluded and why.
What the numbers say. Top-1 agreement with exact scan is 1.0000 across 300 queries. setR@10 overlap is 0.9933. Bound violations: zero in every configuration tested. Each exclusion carries its bound; the tracer signs the record.
Reference tables
The detailed numbers follow.
Every number below was produced by code in this repository and can be reproduced. Ground truth is external: BIGANN, the ANS regulatory document, or an exact cosine scan.
Search engine
| Metric | Value | Source |
|---|---|---|
| Top-1 agreement with exact scan | 1.0000 | cosine reference, 300 queries |
| setR@10 overlap | 0.9933 | same run |
| Bound violations | 0 | all configurations |
| Recall@10, 1536-d, 99.8k vectors | 1.0000 | [128→256] configuration |
| Recall@10, 20k vectors | 1.0000 | GloVe / BIGANN |
Against HNSW
| Method | Recall | Latency |
|---|---|---|
| Madhava [128→256] | 1.0000 | 54.0 ms |
| HNSW (ef=256) | 0.9995 | 1.38 ms |
| HNSW (ef=128) | 0.9990 | 0.84 ms |
| HNSW (ef=64) | 0.9950 | 0.48 ms |
| IVF (nprobe=40) | 0.9640 | 3.15 ms |
Read this table carefully. HNSW is 20 to 100 times faster at query time. Madhava is not faster there and does not claim to be. What Madhava buys you is that HNSW at ef=64 returns recall 0.9950 without knowing which 0.5% it lost, while Madhava returns 1.0000 and can prove it per document.
Index build time — where Madhava wins by a wide margin
Query latency is only half the story. The other half is how long it takes to build the index — and this is where the comparison inverts.
Same corpus: 99,800 vectors at 1,536 dimensions.
| Method | Build time | Relative |
|---|---|---|
| Madhava [128→256] | 1.45 s | 1× |
| IVF (nprobe=40) | 15.62 s | 10.7× slower |
| HNSW (ef=256) | 33.60 s | 23.1× slower |
This is not a marginal difference. It changes what is practical: re-indexing after a schema change, rebuilding per tenant, running experiments across dozens of configurations, or rebuilding nightly instead of weekly.
Build time scales linearly and stays fast
| Corpus size | Build time |
|---|---|
| 1,000 vectors | 0.019 s |
| 10,000 vectors | 0.020 s |
| 50,000 vectors | 0.093 s |
| 200,000 vectors | 0.504 s |
| 500,000 vectors | 1.21 s |
| 1,000,000 vectors | 1.69 s |
One million vectors index in under two seconds. For comparison, building an HNSW index over the same 1M corpus typically takes minutes.
And at small scale, query latency is competitive
Below roughly 50,000 vectors, Madhava's query time is close to HNSW and faster than exact scan — because the bound prunes most of the corpus before any distance is computed.
| Corpus | Madhava | HNSW | Exact scan |
|---|---|---|---|
| 1,000 | 0.55 ms | 0.69 ms | 0.27 ms |
| 5,000 | 0.62 ms | 1.17 ms | 0.73 ms |
| 10,000 | 0.99 ms | 1.18 ms | 1.58 ms |
| 50,000 | 2.42 ms | 2.35 ms | 7.29 ms |
| 200,000 | 10.03 ms | 1.85 ms | 18.30 ms |
| 1,000,000 | 47.72 ms | 3.37 ms | 67.87 ms |
The crossover is around 50,000 vectors. Below it, Madhava is faster than HNSW and dramatically faster than exact scan. Above it, HNSW wins on latency — while Madhava stays far ahead on build time and keeps the proof.
This matters for the way real deployments work. Most regulated document corpora are per-tenant or per-department, and most sit in the thousands to tens of thousands of documents. At that size the proof costs almost nothing.
Domain benchmark — ANS regulatory corpus
Task: given a TUSS procedure term from a hospital bill, find the corresponding procedure in the ANS Rol and decide whether it is covered in the operator's segment. Ground truth is the ANS regulatory documents themselves, not human annotation. 3,401 procedures, 5,496 pairs, 800-pair sample.
| Metric | Value |
|---|---|
| Coverage decision accuracy | 97.5% |
| False covered — bill that would be denied | 1.0% |
| False denied — legitimate revenue lost | 1.5% |
| Exact procedure identification (top-1) | 63.4% |
The 63.4% is weak and is stated here deliberately. Identifying the exact procedure is harder than deciding coverage. Anyone evaluating this product should know that before a sales conversation, not after.
Limitations
Design constraints, not bugs scheduled for later.
Latency
20 to 100 times slower than HNSW at equal recall target. Bound computation and the exhaustive audit path have a cost that cannot be removed.
Scale
Benchmarked to 100k vectors in the reference configuration. Streaming 100M vectors via mmap is documented at roughly 18.6 GB RAM. Beyond that is unexplored in public benchmarks.
The proof covers the vector space, not the encoder
Madhava proves a document could not be in the top-K given the vectors it was indexed with. It does not prove the embedding was good. A poor encoder produces a correct but useless proof.
It does not improve classification
On classification tasks the pruning gives no benefit and can cost up to one percentage point of F1. This is a retrieval engine.
Not a compliance certificate
The audit trail is evidence, not ISO/IEC 42001 certification. A notified body will not accept a Cauchy–Schwarz bound in place of a conformity assessment. It is the technical artifact underneath that assessment.
License
Packages are released under the Business Source License 1.1 (BSL 1.1).
| Term | Detail |
|---|---|
| Permitted | Copy, modify, derivative works, non-production use |
| Restricted | Offering the licensed work as a commercial search service to third parties |
| Change date | 2036-01-01, converting to GPL v2.0 or later |
| Commercial | OEM embedding and redistribution require a commercial agreement |
For commercial licensing, OEM embedding or redistribution inside another product, write to pay@winnex.ai.
Resources
| PyPI organization | all published packages |
| GitHub | source and CI |
| Technical specification | DOI, pre-patent disclosure |
| winnex.ai | company |