Ontological layer
The turn, stored whole in the preservation plane, untouched by any cutting. Its digest is the same before indexing, after two different schemes, and after every retrieval.
An archive that preserves bytes exactly and expands any part of itself on demand is also a description of what a model needs from its own context. The same package carries a context layer, reachable over MCP: remember losslessly, address semantically, and get the record itself back — not a summary of it.
| Tool | The claim it has to hold up |
|---|---|
context_capture | Every byte of the transcript, or a refusal. A limit that would drop the front of a conversation is an error, not a quiet truncation. |
context_segment | An index family over the turns — and the archive is byte-identical before and after, which is checked rather than asserted. |
context_segment_export | The views to embed, with the identity that must come back with them, and a sample that names which part of the record it covered. |
context_attach_vectors | Vectors into the auxiliary plane: a sidecar beside the archive, never a record inside it. |
context_address | A question in, (turn, start_byte, end_byte) out, with the turn's digest re-checked against what the index was built from. |
From Neo.K's 同一性微積分: 切割 = 索引 — a cut adds a perspective and leaves the object whole. So a segment is (turn, start_byte, end_byte) in the auxiliary plane, several schemes coexist over one record, re-cutting rewrites nothing, and a segmenter is allowed to be wrong.
The turn, stored whole in the preservation plane, untouched by any cutting. Its digest is the same before indexing, after two different schemes, and after every retrieval.
Segments as raw byte offsets into that turn. A better segmenter later produces a new index family; the record is untouched, so choosing between schemes is a measurement rather than a migration.
Every figure below was produced by bench/context_bench.py into a JSON file this page is generated from, stamped with the revision and the corpus digest it was measured against.
6,581 turns
16.68 MiB → 11.00 MiB (66%)
lossless — every byte of the transcript is in the archive
61,458 segments
median 249 B · coverage 1.0000
no byte of any turn is unreachable through the index, and none is covered twice · preservation digest unchanged through indexing
61,458 × 768
| size | load | |
|---|---|---|
| JSON array of decimals | 932.74 MiB | 28.6 s |
| float32 behind a JSON header | 182.95 MiB | 0.13 s |
5.1× smaller · 221× faster to load
183 ms with NumPy
13 s pure Python
NumPy is optional and the preservation plane never needs it. The pure-Python path refuses only when its own projection passes a stated 30-second budget, and it quotes the projection so you can disagree with the estimate rather than with a constant.
2.54 s median for a whole addressed query
5/5 of them returned digest-verified exact bytes. A 64-wide query against a 768-wide corpus → INCOMPARABLE: dimensions differs — 64 against 768
Ground truth is located by exact search for a distinctive anchor string — and the question is then written to avoid that anchor entirely. So the label comes from a match the retriever never sees, and the query is exactly the case lexical search cannot answer.
| Scheme | Segments | p95 | R@1 | R@5 | MRR | Median rank |
|---|---|---|---|---|---|---|
whole-turn-v1 (baseline) | 6,581 | +0.443 | 0.17 | 0.42 | 0.280 | 7.5 |
structural-v1 | 18,814 | +0.356 | 0.50 | 0.58 | 0.545 | 2 |
sized-900-v1 (control) | 23,036 | +0.361 | 0.58 | 0.75 | 0.656 | 1 |
changepoint-v1 | 61,458 | +0.219 | 0.75 | 1.00 | 0.847 | 1 |
nomic-embed-text through Ollama — 137M parameters, Apache-2.0, 768 dimensions, which is the width this vector plane already used. Identical ground: the same corpus digest, the same queries, the same schemes, the same budget. Hosted → local.
| Scheme | R@1 | MRR | p95 |
|---|---|---|---|
whole-turn-v1 | 0.17 → 0.42 | 0.280 → 0.569 | +0.443 → +0.500 |
structural-v1 | 0.50 → 0.58 | 0.545 → 0.704 | +0.356 → +0.351 |
sized-900-v1 | 0.58 → 0.50 | 0.656 → 0.631 | +0.361 → +0.315 |
changepoint-v1 | 0.75 → 0.75 | 0.847 → 0.861 | +0.219 → +0.203 |
Typed edges the record states outright — a reply's parent, a tool call matched to its result, the same file named twice. Each carries a kind and its evidence, never a score. Measured against two controls: random pairs, and merely adjacent turns, which is what conversation order gives for free.
| relation | n | mean cosine | vs adjacency | already adjacent |
|---|---|---|---|---|
random (floor) | 7,999 | +0.0074 | 0.04× | — |
adjacent (free baseline) | 6,580 | +0.1850 | 1.00× | — |
mentions-path | 2,069 | +0.4723 | 2.55× | 23.8% |
mentions-path (gap>1) | 1,576 | +0.4473 | 2.42× | — |
tool-result-of | 1,737 | +0.2785 | 1.51× | 90.6% |
tool-result-of (gap>1) | 164 | +0.1324 | 0.72× | — |
replies-to | 5,244 | +0.1974 | 1.07× | 90.6% |
replies-to (gap>1) | 495 | +0.0887 | 0.48× | — |
Two 768-wide vectors from different models — or one model over two different preprocessings — compare to a confident, meaningless number, and nothing downstream can tell. Model, revision, dimensions, projection version and segmentation scheme must all agree, or the answer is INCOMPARABLE rather than a value. Width is not identity.
A byte limit that would drop the front of a transcript is refused. Taken deliberately, the result is reported as partial and names the byte range it dropped — because every downstream claim would otherwise be stated over a record the caller believes is whole.
A vectorised corpus covering a tenth of the index still returns its nearest hit, and that answer is indistinguishable from a complete search unless the share is stated. It is stated, on every call.
23 tools over stdio. Nothing here computes an embedding: the vectors come from whatever model the agent already has, and the identity travels with them so a local or browser model can replace the one used here without anything silently comparing across the two.
pip install "mcp>=1.10,<2"
python tools/mcp/anla_mcp.py
python bench/context_bench.py <transcript.jsonl>
python bench/segment_retrieval.py <transcript.jsonl>
The retrieval table needs an embedding model; everything else on this page runs offline. Source access is private · Source access is private