### Retrieval quality, pooled over both sites (93 questions)

| Model | Dims | R@1 | 95% CI of R@1 | R@5 | MRR@5 | Page R@5 | vs anchor, R@1 points [paired 95% CI] | Verdict |
|---|---|---|---|---|---|---|---|---|
| text-embedding-3-small (anchor) | 1536 | 63.4 | [53.7, 72.9] | 83.9 | 0.71 | 94.6 | anchor | anchor |
| text-embedding-3-large | 3072 | 60.2 | [50.5, 69.7] | 88.2 | 0.72 | 94.6 | -3.2 [-11.5, +6.0] | tied within noise |
| voyage-4 | 1024 | 66.7 | [54.2, 77.3] | 91.4 | 0.773 | 94.6 | +3.2 [-6.7, +13.0] | tied within noise |
| bge-m3 (hosted, DeepInfra) | 1024 | 57.0 | [47.0, 67.0] | 84.9 | 0.686 | 93.5 | -6.5 [-15.2, +2.1] | tied within noise |
| bge-m3 (Ollama) | 1024 | 57.0 | [45.2, 67.0] | 84.9 | 0.688 | 93.5 | -6.5 [-16.5, +2.2] | tied within noise |
| qwen3-embedding-8b | 4096 | 64.5 | [56.4, 72.7] | 91.4 | 0.757 | 95.7 | +1.1 [-5.7, +8.1] | tied within noise |
| nomic-embed-text (Ollama) | 768 | 61.3 | [53.3, 69.0] | 86.0 | 0.715 | 92.5 | -2.1 [-10.9, +5.6] | tied within noise |
| all-MiniLM-L6-v2 (256) | 384 | 44.1 | [34.0, 53.7] | 74.2 | 0.559 | 91.4 | -19.4 [-29.5, -10.6] | worse |
| 3-large, dimensions=1024 (extra row) | 1024 | 60.2 | [50.5, 69.7] | 88.2 | 0.712 | 94.6 | n/a | descriptive only |
| MiniLM, max_seq_length=512 (extra row) | 384 | 40.9 | [31.8, 50.5] | 75.3 | 0.538 | 90.3 | n/a | descriptive only |

### Per site, section R@1 / R@5

| Model | FastAPI R@1 | FastAPI R@5 | htmx R@1 | htmx R@5 |
|---|---|---|---|---|
| text-embedding-3-small (anchor) | 71.7 | 80.4 | 55.3 | 87.2 |
| text-embedding-3-large | 63.0 | 84.8 | 57.4 | 91.5 |
| voyage-4 | 73.9 | 91.3 | 59.6 | 91.5 |
| bge-m3 (hosted, DeepInfra) | 63.0 | 78.3 | 51.1 | 91.5 |
| bge-m3 (Ollama) | 63.0 | 78.3 | 51.1 | 91.5 |
| qwen3-embedding-8b | 71.7 | 91.3 | 57.4 | 91.5 |
| nomic-embed-text (Ollama) | 67.4 | 87.0 | 55.3 | 85.1 |
| all-MiniLM-L6-v2 (256) | 39.1 | 69.6 | 48.9 | 78.7 |
| 3-large, dimensions=1024 (extra row) | 60.9 | 87.0 | 59.6 | 89.4 |
| MiniLM, max_seq_length=512 (extra row) | 37.0 | 71.7 | 44.7 | 78.7 |

### Decision rule vs the anchor (pooled section R@1, points)

| Pair | Diff [95% CI] | Site signs (FastAPI, htmx) | Verdict |
|---|---|---|---|
| te3-large vs te3-small | -3.2 [-11.5, +6.0] | [-1, 1] | tied within noise |
| voyage-4 vs te3-small | +3.2 [-6.7, +13.0] | [1, 1] | tied within noise |
| bge-m3-hosted vs te3-small | -6.5 [-15.2, +2.1] | [-1, -1] | tied within noise |
| bge-m3-ollama vs te3-small | -6.5 [-16.5, +2.2] | [-1, -1] | tied within noise |
| qwen3-8b vs te3-small | +1.1 [-5.7, +8.1] | [0, 1] | tied within noise |
| nomic-ollama vs te3-small | -2.1 [-10.9, +5.6] | [-1, 0] | tied within noise |
| minilm-256 vs te3-small | -19.4 [-29.5, -10.6] | [-1, -1] | worse |
| bge-m3-ollama vs bge-m3-hosted | +0.0 [+0.0, +0.0] | [0, 0] | tied within noise |

### Tiers (best point estimate: voyage-4)

| Model | Diff of best minus model [95% CI], points | Excludes zero |
|---|---|---|
| te3-small | +3.2 [-6.2, +12.8] | False |
| te3-large | +6.5 [-2.3, +14.4] | False |
| bge-m3-hosted | +9.7 [+1.0, +18.8] | True |
| bge-m3-ollama | +9.7 [+0.0, +20.0] | False |
| qwen3-8b | +2.1 [-6.8, +10.4] | False |
| nomic-ollama | +5.4 [-5.0, +15.8] | False |
| minilm-256 | +22.6 [+13.1, +31.6] | True |

Tier 1: voyage-4, te3-small, te3-large, bge-m3-ollama, qwen3-8b, nomic-ollama. Below tier 1: bge-m3-hosted, minilm-256.


### Question set 2 (113 questions, written by claude-haiku-5.5), pooled

| Model | R@1 | R@5 | MRR@5 |
|---|---|---|---|
| text-embedding-3-small (anchor) | 65.5 | 86.7 | 0.745 |
| text-embedding-3-large | 60.2 | 90.3 | 0.723 |
| voyage-4 | 77.0 | 94.7 | 0.844 |
| bge-m3 (hosted, DeepInfra) | 61.9 | 86.7 | 0.721 |
| bge-m3 (Ollama) | 61.1 | 86.7 | 0.717 |
| qwen3-embedding-8b | 69.9 | 94.7 | 0.801 |
| nomic-embed-text (Ollama) | 66.4 | 87.6 | 0.749 |
| all-MiniLM-L6-v2 (256) | 47.8 | 79.6 | 0.601 |
| 3-large, dimensions=1024 (extra row) | 60.2 | 90.3 | 0.718 |
| MiniLM, max_seq_length=512 (extra row) | 46.0 | 79.6 | 0.595 |

Spearman rank correlation of model order, set 1 vs set 2 (8 main models, extras excluded): R@1 0.898, MRR@5 0.905.
Anchor minus bge-m3 (hosted): {'set1_diff_pts': 6.4, 'set2_diff_pts': 3.6}. Anchor minus nomic: {'set1_diff_pts': 2.1, 'set2_diff_pts': -0.9}.


### Cost per 1,000 pages (embedding only, extrapolated from 130 pages)

| Model | Price per 1M tokens | Corpus tokens (130 pages) | Tokens per page | Embedding cost, 130 pages | Per 1,000 pages |
|---|---|---|---|---|---|
| text-embedding-3-small (anchor) | $0.02 | 262,355 | 2018 | $0.0052 | $0.040 |
| text-embedding-3-large | $0.13 | 262,355 | 2018 | $0.0341 | $0.262 |
| voyage-4 | $0.06 | 263,256 | 2025 | $0.0158 | $0.121 |
| bge-m3 (hosted, DeepInfra) | $0.01 | 339,067 | 2608 | $0.0034 | $0.026 |
| bge-m3 (Ollama) | free | 339,067 | 2608 | $0 (own hardware) | $0 |
| qwen3-embedding-8b | $0.01 | 265,475 | 2042 | $0.0027 | $0.020 |
| nomic-embed-text (Ollama) | free | 337,396 | 2595 | $0 (own hardware) | $0 |
| all-MiniLM-L6-v2 (256) | free | 0 | 0 | $0 (own hardware) | $0 |

### Speed (median of 3 repeats, 128 chunks, batch 64 unless noted)

| Model | Where | Chunks per second | Single-query p50, ms | Batch |
|---|---|---|---|---|
| text-embedding-3-small (anchor) | hosted via OpenRouter (includes network) | 35.8 | 648.3 | 64 |
| text-embedding-3-large | hosted via OpenRouter (includes network) | 25.7 | 774.0 | 64 |
| voyage-4 | hosted via OpenRouter (includes network) | 45.4 | 470.7 | 64 |
| bge-m3 (hosted, DeepInfra) | hosted via OpenRouter (includes network) | 11.8 | 633.9 | 16 |
| qwen3-embedding-8b | hosted via OpenRouter (includes network) | 16.6 | 623.0 | 64 |
| bge-m3 (Ollama) | local, Ollama | 29.9 | 37.0 | 64 |
| nomic-embed-text (Ollama) | local, Ollama | 75.2 | 12.0 | 64 |
| all-MiniLM-L6-v2 (256) | local, sentence-transformers (MPS) | 656.0 | 5.8 | 64 |
