oneground 0.1.0rc1__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.
- oneground-0.1.0rc1/PKG-INFO +244 -0
- oneground-0.1.0rc1/README.md +200 -0
- oneground-0.1.0rc1/oneground/__init__.py +18 -0
- oneground-0.1.0rc1/oneground/adapters/__init__.py +28 -0
- oneground-0.1.0rc1/oneground/adapters/base.py +254 -0
- oneground-0.1.0rc1/oneground/adapters/conformance.py +320 -0
- oneground-0.1.0rc1/oneground/adapters/qdrant/__init__.py +3 -0
- oneground-0.1.0rc1/oneground/adapters/qdrant/adapter.py +371 -0
- oneground-0.1.0rc1/oneground/adapters/stub.py +154 -0
- oneground-0.1.0rc1/oneground/analogy.py +249 -0
- oneground-0.1.0rc1/oneground/calibrate/__init__.py +729 -0
- oneground-0.1.0rc1/oneground/calibrate/fixture.py +218 -0
- oneground-0.1.0rc1/oneground/calibrate/history.py +390 -0
- oneground-0.1.0rc1/oneground/calibrate/layers.py +230 -0
- oneground-0.1.0rc1/oneground/calibrate/reference.py +144 -0
- oneground-0.1.0rc1/oneground/calibrate/test_calibrate.py +728 -0
- oneground-0.1.0rc1/oneground/capacity.py +285 -0
- oneground-0.1.0rc1/oneground/characterize.py +522 -0
- oneground-0.1.0rc1/oneground/cli.py +277 -0
- oneground-0.1.0rc1/oneground/cost/__init__.py +233 -0
- oneground-0.1.0rc1/oneground/cost/test_cost.py +218 -0
- oneground-0.1.0rc1/oneground/embed/__init__.py +56 -0
- oneground-0.1.0rc1/oneground/environment.py +349 -0
- oneground-0.1.0rc1/oneground/fixture/__init__.py +16 -0
- oneground-0.1.0rc1/oneground/fixture/build.py +289 -0
- oneground-0.1.0rc1/oneground/fixture/reference.py +65 -0
- oneground-0.1.0rc1/oneground/fixture/test_verify.py +659 -0
- oneground-0.1.0rc1/oneground/fixture/verify.py +744 -0
- oneground-0.1.0rc1/oneground/fixture_verify.py +27 -0
- oneground-0.1.0rc1/oneground/intake/__init__.py +257 -0
- oneground-0.1.0rc1/oneground/intake/test_tier2.py +343 -0
- oneground-0.1.0rc1/oneground/measures/__init__.py +30 -0
- oneground-0.1.0rc1/oneground/measures/ambiguity.py +19 -0
- oneground-0.1.0rc1/oneground/measures/crispness.py +47 -0
- oneground-0.1.0rc1/oneground/measures/drift.py +82 -0
- oneground-0.1.0rc1/oneground/measures/lid.py +31 -0
- oneground-0.1.0rc1/oneground/measures/skew.py +17 -0
- oneground-0.1.0rc1/oneground/measures/test_measures.py +179 -0
- oneground-0.1.0rc1/oneground/models/__init__.py +49 -0
- oneground-0.1.0rc1/oneground/models/base.py +328 -0
- oneground-0.1.0rc1/oneground/models/hash_sharded/__init__.py +3 -0
- oneground-0.1.0rc1/oneground/models/hash_sharded/model.py +173 -0
- oneground-0.1.0rc1/oneground/models/semantic_sharded/__init__.py +3 -0
- oneground-0.1.0rc1/oneground/models/semantic_sharded/model.py +217 -0
- oneground-0.1.0rc1/oneground/models/single_node_hnsw/__init__.py +3 -0
- oneground-0.1.0rc1/oneground/models/single_node_hnsw/model.py +129 -0
- oneground-0.1.0rc1/oneground/models/test_conformance.py +368 -0
- oneground-0.1.0rc1/oneground/pod/__init__.py +60 -0
- oneground-0.1.0rc1/oneground/pod/__main__.py +7 -0
- oneground-0.1.0rc1/oneground/pod/api.py +394 -0
- oneground-0.1.0rc1/oneground/pod/cli.py +1078 -0
- oneground-0.1.0rc1/oneground/pod/confirm.py +139 -0
- oneground-0.1.0rc1/oneground/pod/plan.py +256 -0
- oneground-0.1.0rc1/oneground/pod/session.py +220 -0
- oneground-0.1.0rc1/oneground/pod/sshx.py +439 -0
- oneground-0.1.0rc1/oneground/pod/state.py +167 -0
- oneground-0.1.0rc1/oneground/pod/test_pod.py +2082 -0
- oneground-0.1.0rc1/oneground/receipts/__init__.py +170 -0
- oneground-0.1.0rc1/oneground/report/__init__.py +943 -0
- oneground-0.1.0rc1/oneground/report/html.py +464 -0
- oneground-0.1.0rc1/oneground/report/test_end_to_end.py +276 -0
- oneground-0.1.0rc1/oneground/report/test_verdict.py +650 -0
- oneground-0.1.0rc1/oneground/report/verdict.py +743 -0
- oneground-0.1.0rc1/oneground/sample/__init__.py +26 -0
- oneground-0.1.0rc1/oneground/sample/arxiv.py +128 -0
- oneground-0.1.0rc1/oneground/sample/loaders.py +195 -0
- oneground-0.1.0rc1/oneground/simulate/__init__.py +533 -0
- oneground-0.1.0rc1/oneground/simulate/test_simulate.py +269 -0
- oneground-0.1.0rc1/oneground/test_analogy.py +245 -0
- oneground-0.1.0rc1/oneground/test_capacity.py +184 -0
- oneground-0.1.0rc1/oneground/test_characterize.py +286 -0
- oneground-0.1.0rc1/oneground/test_cli.py +217 -0
- oneground-0.1.0rc1/oneground/test_environment.py +431 -0
- oneground-0.1.0rc1/oneground/truth/__init__.py +24 -0
- oneground-0.1.0rc1/oneground/verify/__init__.py +752 -0
- oneground-0.1.0rc1/oneground/verify/load.py +312 -0
- oneground-0.1.0rc1/oneground/verify/runpod.py +303 -0
- oneground-0.1.0rc1/oneground/verify/test_matched.py +1226 -0
- oneground-0.1.0rc1/oneground/verify/test_verify.py +322 -0
- oneground-0.1.0rc1/oneground.egg-info/PKG-INFO +244 -0
- oneground-0.1.0rc1/oneground.egg-info/SOURCES.txt +85 -0
- oneground-0.1.0rc1/oneground.egg-info/dependency_links.txt +1 -0
- oneground-0.1.0rc1/oneground.egg-info/entry_points.txt +2 -0
- oneground-0.1.0rc1/oneground.egg-info/requires.txt +28 -0
- oneground-0.1.0rc1/oneground.egg-info/top_level.txt +1 -0
- oneground-0.1.0rc1/pyproject.toml +92 -0
- oneground-0.1.0rc1/setup.cfg +4 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oneground
|
|
3
|
+
Version: 0.1.0rc1
|
|
4
|
+
Summary: Measure a retrieval architecture decision on your own vectors, with the receipt attached.
|
|
5
|
+
Author: oneproof
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/oneproof/oneground
|
|
8
|
+
Project-URL: Source, https://github.com/oneproof/oneground
|
|
9
|
+
Project-URL: Issues, https://github.com/oneproof/oneground/issues
|
|
10
|
+
Keywords: vector-search,retrieval,benchmarking,rag,embeddings
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.12
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
Requires-Dist: numpy==2.5.3
|
|
25
|
+
Requires-Dist: faiss-cpu==1.15.0
|
|
26
|
+
Requires-Dist: scikit-learn==1.9.0
|
|
27
|
+
Requires-Dist: pyyaml==6.0.3
|
|
28
|
+
Requires-Dist: zstandard==0.25.0
|
|
29
|
+
Provides-Extra: embed
|
|
30
|
+
Requires-Dist: sentence-transformers==6.0.1; extra == "embed"
|
|
31
|
+
Requires-Dist: torch==2.14.0; extra == "embed"
|
|
32
|
+
Provides-Extra: view
|
|
33
|
+
Requires-Dist: umap-learn==0.5.12; extra == "view"
|
|
34
|
+
Requires-Dist: pyarrow==25.0.1; extra == "view"
|
|
35
|
+
Requires-Dist: matplotlib==3.11.1; extra == "view"
|
|
36
|
+
Provides-Extra: qdrant
|
|
37
|
+
Requires-Dist: qdrant-client==1.19.0; extra == "qdrant"
|
|
38
|
+
Requires-Dist: pywin32==312; sys_platform == "win32" and extra == "qdrant"
|
|
39
|
+
Provides-Extra: pod
|
|
40
|
+
Provides-Extra: calibrate
|
|
41
|
+
Requires-Dist: h5py==3.16.0; extra == "calibrate"
|
|
42
|
+
Provides-Extra: test
|
|
43
|
+
Requires-Dist: pytest==9.1.1; extra == "test"
|
|
44
|
+
|
|
45
|
+
# oneground
|
|
46
|
+
|
|
47
|
+

|
|
48
|
+
|
|
49
|
+
Choosing a vector store, an index, and a sharding scheme is usually decided by
|
|
50
|
+
vendor leaderboards, a blog post, and whatever the last team did. oneground
|
|
51
|
+
measures that decision on **your own embeddings**, against exact k-NN ground
|
|
52
|
+
truth, and writes down every number with the seeds and digests needed to
|
|
53
|
+
re-derive it. It is local-first and offline: your vectors never leave the
|
|
54
|
+
machine, and there is no telemetry.
|
|
55
|
+
|
|
56
|
+
Part of the [oneproof](https://oneproof.dev) suite — the *Choose* door.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Install
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
pip install oneground
|
|
64
|
+
oneground --help
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Python 3.12 or newer. Extras, each named for the capability it unlocks:
|
|
68
|
+
|
|
69
|
+
| extra | for |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `[embed]` | handing oneground text instead of vectors |
|
|
72
|
+
| `[view]` | the ground view and the fixture builder's projection |
|
|
73
|
+
| `[qdrant]` | `oneground verify` against a real Qdrant |
|
|
74
|
+
| `[calibrate]` | reading the ANN-Benchmarks HDF5 |
|
|
75
|
+
| `[test]` | running the suite |
|
|
76
|
+
|
|
77
|
+
To work on oneground rather than with it:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git clone https://github.com/oneproof/oneground && cd oneground
|
|
81
|
+
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
82
|
+
pip install -r requirements.txt && pip install -e .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Use that venv's interpreter explicitly.** Every command that writes a
|
|
86
|
+
canonical artifact refuses to run when your numpy, faiss-cpu or scikit-learn
|
|
87
|
+
differ from `requirements.txt`, and prints which. A measurement computed under
|
|
88
|
+
different libraries is not the measurement the pins describe. `--allow-unpinned`
|
|
89
|
+
proceeds and stamps the artifact `unpinned environment` so every reader of it
|
|
90
|
+
can see that.
|
|
91
|
+
|
|
92
|
+
## Characterize your corpus
|
|
93
|
+
|
|
94
|
+
Copy [`requirements.example.yaml`](requirements.example.yaml) — it is the
|
|
95
|
+
schema by example — point it at your vectors, and run:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
oneground characterize requirements.yaml
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The minimum it needs is a sample of vectors, some queries, and a seed:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
oneground: 1
|
|
105
|
+
run:
|
|
106
|
+
name: support-tickets-2026q3
|
|
107
|
+
seed: 20260910
|
|
108
|
+
workdir: ./runs/support-tickets-2026q3
|
|
109
|
+
corpus:
|
|
110
|
+
sample:
|
|
111
|
+
kind: receipt
|
|
112
|
+
vectors: {path: ./data/sample_vectors.npy}
|
|
113
|
+
queries: {path: ./data/queries.npy, count_min: 50}
|
|
114
|
+
target_sample_size: 20000
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
You get five numbers about the shape of your corpus:
|
|
118
|
+
|
|
119
|
+
| measure | what it answers |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `intrinsic_dimensionality` | how many dimensions the data actually occupies, against how many the embedding declares |
|
|
122
|
+
| `boundary_crispness` | do vectors sit clearly inside one region, or on a boundary between two |
|
|
123
|
+
| `ambiguous_query_rate` | what share of queries cannot be routed confidently to a single shard |
|
|
124
|
+
| `skew_top10_share` | how much of the corpus lands in the ten largest of 256 regions |
|
|
125
|
+
| `drift` | what a partition trained on the past does to queries from the future |
|
|
126
|
+
|
|
127
|
+
and a directory of receipts beside them:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
runs/support-tickets-2026q3/
|
|
131
|
+
characterization.json the measurements (receipt)
|
|
132
|
+
sample_ids.json which rows were measured (receipt)
|
|
133
|
+
queries_ids.json which queries were used (receipt)
|
|
134
|
+
build_info.json versions, device, input digests (declared)
|
|
135
|
+
MANIFEST.sha256 a digest for each of the above
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Receipt** means re-derivable: same inputs and seed, same bytes.
|
|
139
|
+
**Declared** means recorded rather than re-derivable — timestamps, library
|
|
140
|
+
versions, the host. The two are never blurred, and anything that could not be
|
|
141
|
+
measured is reported as `couldnt_check` with the reason, never filled in from
|
|
142
|
+
a guess. Ask for drift without a timestamp column and you get
|
|
143
|
+
`"couldnt_check: no timestamp_field"`, not a number.
|
|
144
|
+
|
|
145
|
+
## Check your installation against a public fixture
|
|
146
|
+
|
|
147
|
+
`fixtures/arxiv-150k` is 150,000 arXiv abstracts (CC0) embedded with pinned
|
|
148
|
+
weights, with exact ground truth and published values. It exists so a stranger
|
|
149
|
+
can confirm an installation reproduces the numbers this project publishes — it
|
|
150
|
+
is not a leaderboard.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
oneground fixture verify arxiv-smoke
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
The picture at the top is that fixture. Almost all of it is one colour:
|
|
157
|
+
**84% of the vectors sit close enough to four different regions that they must
|
|
158
|
+
be copied into all of them.** The categories separate visibly, which is why
|
|
159
|
+
semantic sharding looks obviously right — and on this corpus it loses, 0.932
|
|
160
|
+
recall at 3.7x storage against 0.997 at 1x for a single flat index. That
|
|
161
|
+
result is why the tool exists.
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## How this tool is checked against numbers that are not its own
|
|
166
|
+
|
|
167
|
+
Every recommendation is only as good as the instrument behind it, so the
|
|
168
|
+
instrument is measured too — against published ANN-Benchmarks results on a
|
|
169
|
+
corpus and a ground truth oneground did not produce, and against real engines
|
|
170
|
+
on your own sample.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
oneground calibrate show # the history, and the latest outcome per check
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
[docs/VALIDATION.md](docs/VALIDATION.md) is the whole picture: the three
|
|
177
|
+
layers, what runs weekly, and — the part worth reading first — which measures
|
|
178
|
+
are **validated against a reference** and which are still **predictions with
|
|
179
|
+
no external counterpart** (boundary crispness, ambiguous query rate, drift).
|
|
180
|
+
A `contradicted` result blocks a release; `couldn't-check` never does, and is
|
|
181
|
+
never rounded up.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## What exists today
|
|
186
|
+
|
|
187
|
+
Everything in this list is in `0.1.0-preview` and has been run end to end.
|
|
188
|
+
|
|
189
|
+
- **`oneground characterize`** — the five measures on your own sample, with
|
|
190
|
+
receipts. Vectors (`.npy`, `.parquet`) or text (`.jsonl`) plus a pinned
|
|
191
|
+
model. Tier 2 (`corpus.declared`) describes a corpus you have not embedded
|
|
192
|
+
yet; it produces a fixture analogy and capacity arithmetic and **never a
|
|
193
|
+
verdict**. See [docs/INTAKE.md](docs/INTAKE.md).
|
|
194
|
+
- **`oneground simulate`** — `single_node_hnsw`, `hash_sharded` and
|
|
195
|
+
`semantic_sharded` as runnable families over your sample, against exact
|
|
196
|
+
k-NN, with loss decomposed into partitioning vs. index.
|
|
197
|
+
- **`oneground verify`** — a real engine on the same sample. One adapter today
|
|
198
|
+
(Qdrant), locally or in a matched environment on a pod where latency under
|
|
199
|
+
load is attributable. See [docs/VERIFY.md](docs/VERIFY.md).
|
|
200
|
+
- **`oneground report`** — the trade-off surface, three outcomes per option
|
|
201
|
+
(meets / fails / couldn't-check), a decision log naming every source field,
|
|
202
|
+
and a deployable manifest.
|
|
203
|
+
- **`oneground fixture verify`** — recompute a fixture's digests **and its
|
|
204
|
+
published values** and report verified / contradicted / couldn't-check for
|
|
205
|
+
each.
|
|
206
|
+
- **`oneground fixture build`** — rebuild a fixture from its spec and seeds.
|
|
207
|
+
- **`oneground pod`** — run a session on rented hardware, with the money
|
|
208
|
+
boundary documented in [docs/POD.md](docs/POD.md).
|
|
209
|
+
- **`oneground calibrate`** — measure this installation against published
|
|
210
|
+
ANN-Benchmarks values and against real engines, and keep the history. See
|
|
211
|
+
[docs/VALIDATION.md](docs/VALIDATION.md).
|
|
212
|
+
- **The arxiv-150k fixture**, `status: verified`: every digest and every
|
|
213
|
+
published value reproduced on a second machine and a second operating
|
|
214
|
+
system, under the same pinned versions.
|
|
215
|
+
|
|
216
|
+
## What is planned
|
|
217
|
+
|
|
218
|
+
Nothing below is implemented, and oneground will not pretend otherwise.
|
|
219
|
+
|
|
220
|
+
- **A second engine adapter** — pgvector. The `VectorEngine` protocol and its
|
|
221
|
+
conformance suite exist and are the contribution gate; no second adapter
|
|
222
|
+
has been written. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
223
|
+
- **`qps_max`** — the highest offered rate an engine sustains before latency
|
|
224
|
+
or errors break. Today's `qps` verdict answers a different question, whether
|
|
225
|
+
the engine held the rate it *was* offered, and the two must never share a
|
|
226
|
+
row. Documented and unimplemented in `oneground/report/verdict.py`.
|
|
227
|
+
- **A second corpus for the fixture analogy** — Tier 2 matches a declared
|
|
228
|
+
corpus against fixtures that publish an `analogy:` block, and only
|
|
229
|
+
arxiv-150k does. A support-ticket corpus therefore correctly gets *no*
|
|
230
|
+
analogy today.
|
|
231
|
+
- **The lab** — the ground view and query traces as interactive renderers over
|
|
232
|
+
the same simulator state the numbers come from.
|
|
233
|
+
|
|
234
|
+
The full plan, including what would make the project change course, is in
|
|
235
|
+
[docs/CHARTER.md](docs/CHARTER.md).
|
|
236
|
+
|
|
237
|
+
## Principles
|
|
238
|
+
|
|
239
|
+
- Your data or nothing. No recommendation from a canned corpus.
|
|
240
|
+
- No engine of our own, no favourite. Every engine behind one adapter.
|
|
241
|
+
- Receipts (re-derivable) and declarations (bytes frozen), never blurred.
|
|
242
|
+
- `couldnt_check` is never rounded up to a verdict.
|
|
243
|
+
- Runs on your machine. Your vectors never leave it. No telemetry.
|
|
244
|
+
- Nothing labelled as capability that is only planned.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# oneground
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Choosing a vector store, an index, and a sharding scheme is usually decided by
|
|
6
|
+
vendor leaderboards, a blog post, and whatever the last team did. oneground
|
|
7
|
+
measures that decision on **your own embeddings**, against exact k-NN ground
|
|
8
|
+
truth, and writes down every number with the seeds and digests needed to
|
|
9
|
+
re-derive it. It is local-first and offline: your vectors never leave the
|
|
10
|
+
machine, and there is no telemetry.
|
|
11
|
+
|
|
12
|
+
Part of the [oneproof](https://oneproof.dev) suite — the *Choose* door.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install oneground
|
|
20
|
+
oneground --help
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Python 3.12 or newer. Extras, each named for the capability it unlocks:
|
|
24
|
+
|
|
25
|
+
| extra | for |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| `[embed]` | handing oneground text instead of vectors |
|
|
28
|
+
| `[view]` | the ground view and the fixture builder's projection |
|
|
29
|
+
| `[qdrant]` | `oneground verify` against a real Qdrant |
|
|
30
|
+
| `[calibrate]` | reading the ANN-Benchmarks HDF5 |
|
|
31
|
+
| `[test]` | running the suite |
|
|
32
|
+
|
|
33
|
+
To work on oneground rather than with it:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
git clone https://github.com/oneproof/oneground && cd oneground
|
|
37
|
+
python -m venv .venv && . .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
38
|
+
pip install -r requirements.txt && pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Use that venv's interpreter explicitly.** Every command that writes a
|
|
42
|
+
canonical artifact refuses to run when your numpy, faiss-cpu or scikit-learn
|
|
43
|
+
differ from `requirements.txt`, and prints which. A measurement computed under
|
|
44
|
+
different libraries is not the measurement the pins describe. `--allow-unpinned`
|
|
45
|
+
proceeds and stamps the artifact `unpinned environment` so every reader of it
|
|
46
|
+
can see that.
|
|
47
|
+
|
|
48
|
+
## Characterize your corpus
|
|
49
|
+
|
|
50
|
+
Copy [`requirements.example.yaml`](requirements.example.yaml) — it is the
|
|
51
|
+
schema by example — point it at your vectors, and run:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
oneground characterize requirements.yaml
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The minimum it needs is a sample of vectors, some queries, and a seed:
|
|
58
|
+
|
|
59
|
+
```yaml
|
|
60
|
+
oneground: 1
|
|
61
|
+
run:
|
|
62
|
+
name: support-tickets-2026q3
|
|
63
|
+
seed: 20260910
|
|
64
|
+
workdir: ./runs/support-tickets-2026q3
|
|
65
|
+
corpus:
|
|
66
|
+
sample:
|
|
67
|
+
kind: receipt
|
|
68
|
+
vectors: {path: ./data/sample_vectors.npy}
|
|
69
|
+
queries: {path: ./data/queries.npy, count_min: 50}
|
|
70
|
+
target_sample_size: 20000
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
You get five numbers about the shape of your corpus:
|
|
74
|
+
|
|
75
|
+
| measure | what it answers |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `intrinsic_dimensionality` | how many dimensions the data actually occupies, against how many the embedding declares |
|
|
78
|
+
| `boundary_crispness` | do vectors sit clearly inside one region, or on a boundary between two |
|
|
79
|
+
| `ambiguous_query_rate` | what share of queries cannot be routed confidently to a single shard |
|
|
80
|
+
| `skew_top10_share` | how much of the corpus lands in the ten largest of 256 regions |
|
|
81
|
+
| `drift` | what a partition trained on the past does to queries from the future |
|
|
82
|
+
|
|
83
|
+
and a directory of receipts beside them:
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
runs/support-tickets-2026q3/
|
|
87
|
+
characterization.json the measurements (receipt)
|
|
88
|
+
sample_ids.json which rows were measured (receipt)
|
|
89
|
+
queries_ids.json which queries were used (receipt)
|
|
90
|
+
build_info.json versions, device, input digests (declared)
|
|
91
|
+
MANIFEST.sha256 a digest for each of the above
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Receipt** means re-derivable: same inputs and seed, same bytes.
|
|
95
|
+
**Declared** means recorded rather than re-derivable — timestamps, library
|
|
96
|
+
versions, the host. The two are never blurred, and anything that could not be
|
|
97
|
+
measured is reported as `couldnt_check` with the reason, never filled in from
|
|
98
|
+
a guess. Ask for drift without a timestamp column and you get
|
|
99
|
+
`"couldnt_check: no timestamp_field"`, not a number.
|
|
100
|
+
|
|
101
|
+
## Check your installation against a public fixture
|
|
102
|
+
|
|
103
|
+
`fixtures/arxiv-150k` is 150,000 arXiv abstracts (CC0) embedded with pinned
|
|
104
|
+
weights, with exact ground truth and published values. It exists so a stranger
|
|
105
|
+
can confirm an installation reproduces the numbers this project publishes — it
|
|
106
|
+
is not a leaderboard.
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
oneground fixture verify arxiv-smoke
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The picture at the top is that fixture. Almost all of it is one colour:
|
|
113
|
+
**84% of the vectors sit close enough to four different regions that they must
|
|
114
|
+
be copied into all of them.** The categories separate visibly, which is why
|
|
115
|
+
semantic sharding looks obviously right — and on this corpus it loses, 0.932
|
|
116
|
+
recall at 3.7x storage against 0.997 at 1x for a single flat index. That
|
|
117
|
+
result is why the tool exists.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## How this tool is checked against numbers that are not its own
|
|
122
|
+
|
|
123
|
+
Every recommendation is only as good as the instrument behind it, so the
|
|
124
|
+
instrument is measured too — against published ANN-Benchmarks results on a
|
|
125
|
+
corpus and a ground truth oneground did not produce, and against real engines
|
|
126
|
+
on your own sample.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
oneground calibrate show # the history, and the latest outcome per check
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
[docs/VALIDATION.md](docs/VALIDATION.md) is the whole picture: the three
|
|
133
|
+
layers, what runs weekly, and — the part worth reading first — which measures
|
|
134
|
+
are **validated against a reference** and which are still **predictions with
|
|
135
|
+
no external counterpart** (boundary crispness, ambiguous query rate, drift).
|
|
136
|
+
A `contradicted` result blocks a release; `couldn't-check` never does, and is
|
|
137
|
+
never rounded up.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## What exists today
|
|
142
|
+
|
|
143
|
+
Everything in this list is in `0.1.0-preview` and has been run end to end.
|
|
144
|
+
|
|
145
|
+
- **`oneground characterize`** — the five measures on your own sample, with
|
|
146
|
+
receipts. Vectors (`.npy`, `.parquet`) or text (`.jsonl`) plus a pinned
|
|
147
|
+
model. Tier 2 (`corpus.declared`) describes a corpus you have not embedded
|
|
148
|
+
yet; it produces a fixture analogy and capacity arithmetic and **never a
|
|
149
|
+
verdict**. See [docs/INTAKE.md](docs/INTAKE.md).
|
|
150
|
+
- **`oneground simulate`** — `single_node_hnsw`, `hash_sharded` and
|
|
151
|
+
`semantic_sharded` as runnable families over your sample, against exact
|
|
152
|
+
k-NN, with loss decomposed into partitioning vs. index.
|
|
153
|
+
- **`oneground verify`** — a real engine on the same sample. One adapter today
|
|
154
|
+
(Qdrant), locally or in a matched environment on a pod where latency under
|
|
155
|
+
load is attributable. See [docs/VERIFY.md](docs/VERIFY.md).
|
|
156
|
+
- **`oneground report`** — the trade-off surface, three outcomes per option
|
|
157
|
+
(meets / fails / couldn't-check), a decision log naming every source field,
|
|
158
|
+
and a deployable manifest.
|
|
159
|
+
- **`oneground fixture verify`** — recompute a fixture's digests **and its
|
|
160
|
+
published values** and report verified / contradicted / couldn't-check for
|
|
161
|
+
each.
|
|
162
|
+
- **`oneground fixture build`** — rebuild a fixture from its spec and seeds.
|
|
163
|
+
- **`oneground pod`** — run a session on rented hardware, with the money
|
|
164
|
+
boundary documented in [docs/POD.md](docs/POD.md).
|
|
165
|
+
- **`oneground calibrate`** — measure this installation against published
|
|
166
|
+
ANN-Benchmarks values and against real engines, and keep the history. See
|
|
167
|
+
[docs/VALIDATION.md](docs/VALIDATION.md).
|
|
168
|
+
- **The arxiv-150k fixture**, `status: verified`: every digest and every
|
|
169
|
+
published value reproduced on a second machine and a second operating
|
|
170
|
+
system, under the same pinned versions.
|
|
171
|
+
|
|
172
|
+
## What is planned
|
|
173
|
+
|
|
174
|
+
Nothing below is implemented, and oneground will not pretend otherwise.
|
|
175
|
+
|
|
176
|
+
- **A second engine adapter** — pgvector. The `VectorEngine` protocol and its
|
|
177
|
+
conformance suite exist and are the contribution gate; no second adapter
|
|
178
|
+
has been written. See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
179
|
+
- **`qps_max`** — the highest offered rate an engine sustains before latency
|
|
180
|
+
or errors break. Today's `qps` verdict answers a different question, whether
|
|
181
|
+
the engine held the rate it *was* offered, and the two must never share a
|
|
182
|
+
row. Documented and unimplemented in `oneground/report/verdict.py`.
|
|
183
|
+
- **A second corpus for the fixture analogy** — Tier 2 matches a declared
|
|
184
|
+
corpus against fixtures that publish an `analogy:` block, and only
|
|
185
|
+
arxiv-150k does. A support-ticket corpus therefore correctly gets *no*
|
|
186
|
+
analogy today.
|
|
187
|
+
- **The lab** — the ground view and query traces as interactive renderers over
|
|
188
|
+
the same simulator state the numbers come from.
|
|
189
|
+
|
|
190
|
+
The full plan, including what would make the project change course, is in
|
|
191
|
+
[docs/CHARTER.md](docs/CHARTER.md).
|
|
192
|
+
|
|
193
|
+
## Principles
|
|
194
|
+
|
|
195
|
+
- Your data or nothing. No recommendation from a canned corpus.
|
|
196
|
+
- No engine of our own, no favourite. Every engine behind one adapter.
|
|
197
|
+
- Receipts (re-derivable) and declarations (bytes frozen), never blurred.
|
|
198
|
+
- `couldnt_check` is never rounded up to a verdict.
|
|
199
|
+
- Runs on your machine. Your vectors never leave it. No telemetry.
|
|
200
|
+
- Nothing labelled as capability that is only planned.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""oneground — characterize, simulate, verify, report.
|
|
2
|
+
|
|
3
|
+
The "Choose" door of the oneproof suite: measure a retrieval architecture
|
|
4
|
+
decision on your own vectors, against exact k-NN ground truth, and keep the
|
|
5
|
+
receipt.
|
|
6
|
+
|
|
7
|
+
What exists today is `characterize` (the five measures on your own sample),
|
|
8
|
+
`fixture verify` (does this installation reproduce the published values), and
|
|
9
|
+
`pod` (run a session on rented hardware). Everything else in the charter is
|
|
10
|
+
planned, and this package says so rather than implying otherwise.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
# PEP 440 for the resolver, the display name for humans. `0.1.0rc1` is what
|
|
14
|
+
# pip compares and what the wheel is named; "0.1.0-preview" is what the
|
|
15
|
+
# release page, the teaser and `oneground --version` say. Neither is derived
|
|
16
|
+
# from the other, so neither can drift into a shape the other cannot read.
|
|
17
|
+
__version__ = "0.1.0rc1"
|
|
18
|
+
__display_version__ = "0.1.0-preview"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Engines, each behind the one `VectorEngine` protocol.
|
|
2
|
+
|
|
3
|
+
stub in-process exact search; what CI runs against
|
|
4
|
+
qdrant the official qdrant-client
|
|
5
|
+
|
|
6
|
+
No engine of our own, no favourite, no sponsored defaults. An adapter earns
|
|
7
|
+
its place by passing `conformance.py`, and nothing here picks an engine for
|
|
8
|
+
the user.
|
|
9
|
+
|
|
10
|
+
See `docs/ADAPTERS.md` for the protocol and the contribution gate.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from . import base, stub
|
|
14
|
+
from .base import (AdapterError, Candidates, EngineFacts, NotConnected,
|
|
15
|
+
UnknownEngine, UpsertStats, VectorEngine, engines,
|
|
16
|
+
get, managed_namespace, namespace_for, register)
|
|
17
|
+
|
|
18
|
+
# Qdrant is imported lazily: the client is an optional dependency, and a
|
|
19
|
+
# machine with no qdrant-client must still be able to run the stub suite.
|
|
20
|
+
try: # pragma: no cover
|
|
21
|
+
from . import qdrant # noqa: F401
|
|
22
|
+
except Exception: # noqa: BLE001
|
|
23
|
+
qdrant = None
|
|
24
|
+
|
|
25
|
+
__all__ = ["AdapterError", "Candidates", "EngineFacts", "NotConnected",
|
|
26
|
+
"UnknownEngine", "UpsertStats", "VectorEngine", "base", "engines",
|
|
27
|
+
"get", "managed_namespace", "namespace_for", "qdrant", "register",
|
|
28
|
+
"stub"]
|