uu-graph-r 0.4.0__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.
- uu_graph_r-0.4.0/PKG-INFO +63 -0
- uu_graph_r-0.4.0/README.md +44 -0
- uu_graph_r-0.4.0/graph-r/.gitignore +23 -0
- uu_graph_r-0.4.0/graph-r/CHANGELOG.md +285 -0
- uu_graph_r-0.4.0/graph-r/Cargo.lock +950 -0
- uu_graph_r-0.4.0/graph-r/Cargo.toml +68 -0
- uu_graph_r-0.4.0/graph-r/LICENSE +27 -0
- uu_graph_r-0.4.0/graph-r/README.md +196 -0
- uu_graph_r-0.4.0/graph-r/benches/baselines/store.json +24 -0
- uu_graph_r-0.4.0/graph-r/benches/store_bench.rs +230 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/Cargo.lock +2270 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/Cargo.toml +37 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/README.md +44 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/graph_r.pyi +184 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/src/lib.rs +612 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_memory.py +92 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_persistence.py +138 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_smoke.py +137 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_sync.py +134 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_sync_github.py +161 -0
- uu_graph_r-0.4.0/graph-r/bindings/python/tests/test_threading.py +93 -0
- uu_graph_r-0.4.0/graph-r/deny.toml +74 -0
- uu_graph_r-0.4.0/graph-r/rust-toolchain.toml +24 -0
- uu_graph_r-0.4.0/graph-r/rustfmt.toml +14 -0
- uu_graph_r-0.4.0/graph-r/src/bytesio.rs +232 -0
- uu_graph_r-0.4.0/graph-r/src/compact.rs +562 -0
- uu_graph_r-0.4.0/graph-r/src/container.rs +319 -0
- uu_graph_r-0.4.0/graph-r/src/error.rs +94 -0
- uu_graph_r-0.4.0/graph-r/src/format/base.rs +760 -0
- uu_graph_r-0.4.0/graph-r/src/format/mod.rs +16 -0
- uu_graph_r-0.4.0/graph-r/src/format/wal.rs +637 -0
- uu_graph_r-0.4.0/graph-r/src/fsio.rs +120 -0
- uu_graph_r-0.4.0/graph-r/src/hash.rs +140 -0
- uu_graph_r-0.4.0/graph-r/src/key.rs +141 -0
- uu_graph_r-0.4.0/graph-r/src/lib.rs +115 -0
- uu_graph_r-0.4.0/graph-r/src/mmap.rs +123 -0
- uu_graph_r-0.4.0/graph-r/src/overlay.rs +285 -0
- uu_graph_r-0.4.0/graph-r/src/query.rs +576 -0
- uu_graph_r-0.4.0/graph-r/src/rank.rs +112 -0
- uu_graph_r-0.4.0/graph-r/src/snapshot.rs +678 -0
- uu_graph_r-0.4.0/graph-r/src/store.rs +821 -0
- uu_graph_r-0.4.0/graph-r/src/text.rs +146 -0
- uu_graph_r-0.4.0/graph-r/src/traverse.rs +214 -0
- uu_graph_r-0.4.0/graph-r/src/ttl.rs +162 -0
- uu_graph_r-0.4.0/graph-r/src/writer.rs +450 -0
- uu_graph_r-0.4.0/graph-r/tests/api_v030.rs +211 -0
- uu_graph_r-0.4.0/graph-r/tests/concurrency.rs +114 -0
- uu_graph_r-0.4.0/graph-r/tests/hermetic.rs +377 -0
- uu_graph_r-0.4.0/graph-r/tests/lineage.rs +202 -0
- uu_graph_r-0.4.0/graph-r/tests/proptest_model.proptest-regressions +10 -0
- uu_graph_r-0.4.0/graph-r/tests/proptest_model.rs +206 -0
- uu_graph_r-0.4.0/graph-r/tests/regression.rs +602 -0
- uu_graph_r-0.4.0/graph-r/tests/security.rs +385 -0
- uu_graph_r-0.4.0/graph-r/tests/support/golden.rs +191 -0
- uu_graph_r-0.4.0/graph_r.pyi +184 -0
- uu_graph_r-0.4.0/link-r/.gitignore +30 -0
- uu_graph_r-0.4.0/link-r/CHANGELOG.md +199 -0
- uu_graph_r-0.4.0/link-r/Cargo.lock +3913 -0
- uu_graph_r-0.4.0/link-r/Cargo.toml +171 -0
- uu_graph_r-0.4.0/link-r/LICENSE +27 -0
- uu_graph_r-0.4.0/link-r/README.md +175 -0
- uu_graph_r-0.4.0/link-r/benches/baselines/index.json +27 -0
- uu_graph_r-0.4.0/link-r/benches/crawl_bench.rs +318 -0
- uu_graph_r-0.4.0/link-r/benches/index_bench.rs +240 -0
- uu_graph_r-0.4.0/link-r/benches/kb_bench.rs +106 -0
- uu_graph_r-0.4.0/link-r/benches/support/mod.rs +99 -0
- uu_graph_r-0.4.0/link-r/deny.toml +74 -0
- uu_graph_r-0.4.0/link-r/examples/crawl_github_docs.rs +69 -0
- uu_graph_r-0.4.0/link-r/rust-toolchain.toml +27 -0
- uu_graph_r-0.4.0/link-r/src/auth/anonymous.rs +41 -0
- uu_graph_r-0.4.0/link-r/src/auth/mod.rs +136 -0
- uu_graph_r-0.4.0/link-r/src/auth/oauth.rs +175 -0
- uu_graph_r-0.4.0/link-r/src/auth/static_token.rs +160 -0
- uu_graph_r-0.4.0/link-r/src/bridge.rs +429 -0
- uu_graph_r-0.4.0/link-r/src/embed/hash.rs +179 -0
- uu_graph_r-0.4.0/link-r/src/embed/mod.rs +81 -0
- uu_graph_r-0.4.0/link-r/src/embed/onnx.rs +138 -0
- uu_graph_r-0.4.0/link-r/src/error.rs +307 -0
- uu_graph_r-0.4.0/link-r/src/extract/html.rs +442 -0
- uu_graph_r-0.4.0/link-r/src/extract/markdown.rs +256 -0
- uu_graph_r-0.4.0/link-r/src/extract/mod.rs +369 -0
- uu_graph_r-0.4.0/link-r/src/facade.rs +1984 -0
- uu_graph_r-0.4.0/link-r/src/fetch/http.rs +337 -0
- uu_graph_r-0.4.0/link-r/src/fetch/mod.rs +75 -0
- uu_graph_r-0.4.0/link-r/src/index/builder.rs +495 -0
- uu_graph_r-0.4.0/link-r/src/index/dense.rs +266 -0
- uu_graph_r-0.4.0/link-r/src/index/format.rs +437 -0
- uu_graph_r-0.4.0/link-r/src/index/fuse.rs +127 -0
- uu_graph_r-0.4.0/link-r/src/index/graph.rs +225 -0
- uu_graph_r-0.4.0/link-r/src/index/meta.rs +389 -0
- uu_graph_r-0.4.0/link-r/src/index/mod.rs +703 -0
- uu_graph_r-0.4.0/link-r/src/index/quant.rs +355 -0
- uu_graph_r-0.4.0/link-r/src/index/sparse.rs +453 -0
- uu_graph_r-0.4.0/link-r/src/kb.rs +602 -0
- uu_graph_r-0.4.0/link-r/src/lib.rs +136 -0
- uu_graph_r-0.4.0/link-r/src/metric.rs +45 -0
- uu_graph_r-0.4.0/link-r/src/payload.rs +173 -0
- uu_graph_r-0.4.0/link-r/src/query.rs +151 -0
- uu_graph_r-0.4.0/link-r/src/remote.rs +378 -0
- uu_graph_r-0.4.0/link-r/src/resource.rs +365 -0
- uu_graph_r-0.4.0/link-r/src/source/crawl.rs +1576 -0
- uu_graph_r-0.4.0/link-r/src/source/fs.rs +123 -0
- uu_graph_r-0.4.0/link-r/src/source/github.rs +689 -0
- uu_graph_r-0.4.0/link-r/src/source/mod.rs +41 -0
- uu_graph_r-0.4.0/link-r/src/text/mod.rs +27 -0
- uu_graph_r-0.4.0/link-r/src/url_key.rs +234 -0
- uu_graph_r-0.4.0/link-r/tests/api_v030.rs +143 -0
- uu_graph_r-0.4.0/link-r/tests/bridge_e2e.rs +409 -0
- uu_graph_r-0.4.0/link-r/tests/conditional_recrawl.rs +226 -0
- uu_graph_r-0.4.0/link-r/tests/fixtures/v0.4.0/facade.dump +52 -0
- uu_graph_r-0.4.0/link-r/tests/fixtures/v0.4.0/facade.lnkr +0 -0
- uu_graph_r-0.4.0/link-r/tests/github_source.rs +347 -0
- uu_graph_r-0.4.0/link-r/tests/golden_v040.rs +85 -0
- uu_graph_r-0.4.0/link-r/tests/hermetic_pipeline.rs +171 -0
- uu_graph_r-0.4.0/link-r/tests/kb.rs +285 -0
- uu_graph_r-0.4.0/link-r/tests/kb_gcs.rs +130 -0
- uu_graph_r-0.4.0/link-r/tests/proptest.rs +143 -0
- uu_graph_r-0.4.0/link-r/tests/proptest_kb.rs +110 -0
- uu_graph_r-0.4.0/link-r/tests/regression.rs +191 -0
- uu_graph_r-0.4.0/link-r/tests/remote.rs +274 -0
- uu_graph_r-0.4.0/link-r/tests/security.rs +154 -0
- uu_graph_r-0.4.0/link-r/tests/support/golden.rs +123 -0
- uu_graph_r-0.4.0/link-r/tests/support/kb_site.rs +164 -0
- uu_graph_r-0.4.0/objstore-r/.gitignore +14 -0
- uu_graph_r-0.4.0/objstore-r/CHANGELOG.md +64 -0
- uu_graph_r-0.4.0/objstore-r/Cargo.lock +2005 -0
- uu_graph_r-0.4.0/objstore-r/Cargo.toml +104 -0
- uu_graph_r-0.4.0/objstore-r/LICENSE +27 -0
- uu_graph_r-0.4.0/objstore-r/README.md +137 -0
- uu_graph_r-0.4.0/objstore-r/benches/mirror_bench.rs +92 -0
- uu_graph_r-0.4.0/objstore-r/benches/objstore_bench.rs +59 -0
- uu_graph_r-0.4.0/objstore-r/deny.toml +62 -0
- uu_graph_r-0.4.0/objstore-r/rust-toolchain.toml +24 -0
- uu_graph_r-0.4.0/objstore-r/rustfmt.toml +14 -0
- uu_graph_r-0.4.0/objstore-r/src/error.rs +97 -0
- uu_graph_r-0.4.0/objstore-r/src/fenced.rs +158 -0
- uu_graph_r-0.4.0/objstore-r/src/gcs/mod.rs +438 -0
- uu_graph_r-0.4.0/objstore-r/src/gcs/wire.rs +101 -0
- uu_graph_r-0.4.0/objstore-r/src/http.rs +258 -0
- uu_graph_r-0.4.0/objstore-r/src/join.rs +204 -0
- uu_graph_r-0.4.0/objstore-r/src/key.rs +171 -0
- uu_graph_r-0.4.0/objstore-r/src/lib.rs +197 -0
- uu_graph_r-0.4.0/objstore-r/src/local.rs +395 -0
- uu_graph_r-0.4.0/objstore-r/src/mem.rs +208 -0
- uu_graph_r-0.4.0/objstore-r/src/mirror/fsio.rs +35 -0
- uu_graph_r-0.4.0/objstore-r/src/mirror/manifest.rs +178 -0
- uu_graph_r-0.4.0/objstore-r/src/mirror/mod.rs +733 -0
- uu_graph_r-0.4.0/objstore-r/src/net.rs +175 -0
- uu_graph_r-0.4.0/objstore-r/src/sse.rs +170 -0
- uu_graph_r-0.4.0/objstore-r/src/testing.rs +230 -0
- uu_graph_r-0.4.0/objstore-r/src/token.rs +379 -0
- uu_graph_r-0.4.0/objstore-r/src/transport.rs +380 -0
- uu_graph_r-0.4.0/objstore-r/tests/conformance.rs +51 -0
- uu_graph_r-0.4.0/objstore-r/tests/mirror.rs +387 -0
- uu_graph_r-0.4.0/objstore-r/tests/mirror_gcs.rs +146 -0
- uu_graph_r-0.4.0/objstore-r/tests/proptest_mirror.rs +110 -0
- uu_graph_r-0.4.0/objstore-r/tests/proptest_model.proptest-regressions +8 -0
- uu_graph_r-0.4.0/objstore-r/tests/proptest_model.rs +151 -0
- uu_graph_r-0.4.0/objstore-r/tests/security.rs +242 -0
- uu_graph_r-0.4.0/objstore-r/tests/support/golden.rs +191 -0
- uu_graph_r-0.4.0/objstore-r/tests/transport.rs +216 -0
- uu_graph_r-0.4.0/pyproject.toml +46 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: uu-graph-r
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Classifier: Programming Language :: Rust
|
|
5
|
+
Classifier: Programming Language :: Python :: 3
|
|
6
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
7
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
8
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
9
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
10
|
+
Requires-Dist: pytest>=7 ; extra == 'test'
|
|
11
|
+
Provides-Extra: test
|
|
12
|
+
Summary: Embedded persistent knowledge graph: absorb a crawl, keep it fresh on an adaptive TTL, answer with URLs and anchors inside a token budget.
|
|
13
|
+
Keywords: knowledge-graph,embedded,crawler,index,ttl
|
|
14
|
+
Author-email: lituus-io <support@lituus.io>
|
|
15
|
+
License-Expression: AGPL-3.0-or-later OR LicenseRef-Proprietary
|
|
16
|
+
Requires-Python: >=3.12
|
|
17
|
+
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
18
|
+
|
|
19
|
+
# graph-r
|
|
20
|
+
|
|
21
|
+
`pip install uu-graph-r` → `import graph_r` (Python ≥ 3.12, one `abi3` wheel
|
|
22
|
+
per platform).
|
|
23
|
+
|
|
24
|
+
An embedded, persistent knowledge graph. Point it at a URL once; it crawls,
|
|
25
|
+
distills each page into compact lookup metadata (title, snippet, heading
|
|
26
|
+
anchors, links), and remembers. From then on, lookups answer **locally** —
|
|
27
|
+
with URLs and anchors inside a token budget, never document bodies — and
|
|
28
|
+
`sync` keeps the graph fresh for almost nothing: stored `ETag` validators are
|
|
29
|
+
replayed on every crawl, so unchanged pages answer `304` and transfer no body,
|
|
30
|
+
even after a process restart.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import graph_r
|
|
34
|
+
|
|
35
|
+
store = graph_r.Store.open_or_create("kb")
|
|
36
|
+
store.sync("https://docs.example.com/", depth=2) # crawl → absorb → compact
|
|
37
|
+
|
|
38
|
+
for hit in store.query("install on linux"):
|
|
39
|
+
print(hit.url, hit.anchor.label if hit.anchor else "", hit.score)
|
|
40
|
+
|
|
41
|
+
store.sync("https://docs.example.com/", depth=2) # unchanged: zero bodies
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- **One class, one loop.** `Store.sync` seeds an in-memory crawler from the
|
|
45
|
+
graph, crawls, absorbs, compacts, and discards the crawler — bodies and
|
|
46
|
+
vectors never outlive the call.
|
|
47
|
+
- **References, never bodies.** `query`, `related`, and `due` return URLs,
|
|
48
|
+
titles, snippets, and heading anchors; fetch the page yourself if you want
|
|
49
|
+
the content.
|
|
50
|
+
- **Adaptive freshness.** Every document carries a revalidation interval that
|
|
51
|
+
grows while unchanged and cuts sharply on change; `due()` lists what to
|
|
52
|
+
check next, ranked by importance.
|
|
53
|
+
- **Any producer.** `add`/`touch` are the writer seam for corpora that do not
|
|
54
|
+
arrive by crawl.
|
|
55
|
+
- **Thread-safe.** Every method detaches from the interpreter; driving the
|
|
56
|
+
store through `asyncio.to_thread` is the intended pattern.
|
|
57
|
+
- **Durable.** An mmapped, checksummed store with write-ahead logging,
|
|
58
|
+
crash-safe compaction, and lock-protected single-writer / many-reader
|
|
59
|
+
access — implemented in Rust, shipped as one `abi3` wheel per platform
|
|
60
|
+
(Python ≥ 3.12).
|
|
61
|
+
|
|
62
|
+
Dual-licensed AGPL-3.0-or-later / commercial (contact spicyzhug@gmail.com).
|
|
63
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# graph-r
|
|
2
|
+
|
|
3
|
+
`pip install uu-graph-r` → `import graph_r` (Python ≥ 3.12, one `abi3` wheel
|
|
4
|
+
per platform).
|
|
5
|
+
|
|
6
|
+
An embedded, persistent knowledge graph. Point it at a URL once; it crawls,
|
|
7
|
+
distills each page into compact lookup metadata (title, snippet, heading
|
|
8
|
+
anchors, links), and remembers. From then on, lookups answer **locally** —
|
|
9
|
+
with URLs and anchors inside a token budget, never document bodies — and
|
|
10
|
+
`sync` keeps the graph fresh for almost nothing: stored `ETag` validators are
|
|
11
|
+
replayed on every crawl, so unchanged pages answer `304` and transfer no body,
|
|
12
|
+
even after a process restart.
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import graph_r
|
|
16
|
+
|
|
17
|
+
store = graph_r.Store.open_or_create("kb")
|
|
18
|
+
store.sync("https://docs.example.com/", depth=2) # crawl → absorb → compact
|
|
19
|
+
|
|
20
|
+
for hit in store.query("install on linux"):
|
|
21
|
+
print(hit.url, hit.anchor.label if hit.anchor else "", hit.score)
|
|
22
|
+
|
|
23
|
+
store.sync("https://docs.example.com/", depth=2) # unchanged: zero bodies
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **One class, one loop.** `Store.sync` seeds an in-memory crawler from the
|
|
27
|
+
graph, crawls, absorbs, compacts, and discards the crawler — bodies and
|
|
28
|
+
vectors never outlive the call.
|
|
29
|
+
- **References, never bodies.** `query`, `related`, and `due` return URLs,
|
|
30
|
+
titles, snippets, and heading anchors; fetch the page yourself if you want
|
|
31
|
+
the content.
|
|
32
|
+
- **Adaptive freshness.** Every document carries a revalidation interval that
|
|
33
|
+
grows while unchanged and cuts sharply on change; `due()` lists what to
|
|
34
|
+
check next, ranked by importance.
|
|
35
|
+
- **Any producer.** `add`/`touch` are the writer seam for corpora that do not
|
|
36
|
+
arrive by crawl.
|
|
37
|
+
- **Thread-safe.** Every method detaches from the interpreter; driving the
|
|
38
|
+
store through `asyncio.to_thread` is the intended pattern.
|
|
39
|
+
- **Durable.** An mmapped, checksummed store with write-ahead logging,
|
|
40
|
+
crash-safe compaction, and lock-protected single-writer / many-reader
|
|
41
|
+
access — implemented in Rust, shipped as one `abi3` wheel per platform
|
|
42
|
+
(Python ≥ 3.12).
|
|
43
|
+
|
|
44
|
+
Dual-licensed AGPL-3.0-or-later / commercial (contact spicyzhug@gmail.com).
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Build artifacts
|
|
2
|
+
/target
|
|
3
|
+
**/target/
|
|
4
|
+
Cargo.lock.orig
|
|
5
|
+
|
|
6
|
+
# Fuzzing corpus and crash artifacts (findings are promoted to
|
|
7
|
+
# tests/regression.rs, so the corpus itself is not tracked)
|
|
8
|
+
/fuzz/corpus/
|
|
9
|
+
/fuzz/artifacts/
|
|
10
|
+
|
|
11
|
+
# Criterion output (baselines under benches/baselines/ ARE tracked)
|
|
12
|
+
/target/criterion/
|
|
13
|
+
|
|
14
|
+
# Python build/venv
|
|
15
|
+
*.so
|
|
16
|
+
dist/
|
|
17
|
+
__pycache__/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
.venv/
|
|
20
|
+
|
|
21
|
+
# OS / editor
|
|
22
|
+
.DS_Store
|
|
23
|
+
*.swp
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to graph-r are documented here. Format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning is
|
|
5
|
+
[SemVer](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## 0.4.0
|
|
8
|
+
|
|
9
|
+
Breaking: base format v2 and WAL format v2 (stores from 0.3 must be rebuilt
|
|
10
|
+
or re-ingested); several unused APIs removed. Every capability a consumer
|
|
11
|
+
(kb, mirror, the Python binding) uses is kept.
|
|
12
|
+
|
|
13
|
+
**One foundation for the stack**
|
|
14
|
+
- The core (no features: xxh3 alone) is now what link-r, objstore-r and
|
|
15
|
+
crab-r build on: `text` (tokenizer, case folding, char n-grams, stopwords,
|
|
16
|
+
`estimate_tokens` / `bytes_for_tokens`) moved here from link-r and is the
|
|
17
|
+
rule graph-r's lexicon and link-r's BM25 both use; `hash::fmix64` and
|
|
18
|
+
`hash::trigram`; `fsio::{lock, sync_dir, write_atomic_with}`;
|
|
19
|
+
`bytesio::{put_f32, put_len_prefixed}` and `Reader::{f32, len_prefixed}`;
|
|
20
|
+
`mmap::cast_f32`; per-section flags in `container`
|
|
21
|
+
(`Writer::section_flagged`, `Dir::{section_flags, has}`).
|
|
22
|
+
- Published as **uu-graph-r** on crates.io (the library is still
|
|
23
|
+
`graph_r`), one self-contained crate. Its satellites moved to the crates
|
|
24
|
+
they compose with, so the four libraries form no dependency cycle: the
|
|
25
|
+
link-r bridge is `link_r::bridge` (uu-link-r feature `graph`; the `bridge`
|
|
26
|
+
feature here is gone), the knowledge base is `link_r::kb` (feature `kb`),
|
|
27
|
+
and store mirroring is `objstore_r::mirror` (uu-objstore-r feature
|
|
28
|
+
`mirror`), built on the shared `objstore_r::fenced` protocol.
|
|
29
|
+
`graph_r::store::now_ms` is `graph_r::fsio::now_ms`.
|
|
30
|
+
|
|
31
|
+
**Fixed (independent review)**
|
|
32
|
+
- A read-only reader that caught a compaction between its two renames
|
|
33
|
+
reported `Corrupt`; it now re-reads and, if the window persists, returns
|
|
34
|
+
`Busy`. Only a writable open still treats a newer log as damage.
|
|
35
|
+
- A compaction refused in memory (every ring slot pinned) left a durable
|
|
36
|
+
base whose generation number the next compaction reused; readers then kept
|
|
37
|
+
the first base and skipped ops by count. Generations are now never reused,
|
|
38
|
+
and readers diff the log by sequence.
|
|
39
|
+
- An empty log on a writable open (external truncation) made the next
|
|
40
|
+
commit write a headerless file; the header is now restored.
|
|
41
|
+
- `reload_image` had no guard around the single-producer overlay; reloads
|
|
42
|
+
are now one at a time per handle, and both reloads are no-ops on writable
|
|
43
|
+
handles.
|
|
44
|
+
- The bridge never grew the interval of a known, unchanged page re-fetched
|
|
45
|
+
without a validator (no ETag), so it was re-crawled at the base interval
|
|
46
|
+
forever.
|
|
47
|
+
|
|
48
|
+
**Faster, cheaper**
|
|
49
|
+
- `reload_if_stale` reads only the log bytes appended since the last reload.
|
|
50
|
+
- Queries look tokens up through the hash order, a string-order index and a
|
|
51
|
+
trigram index instead of scanning the vocabulary, and score into reused
|
|
52
|
+
dense buffers: 9× faster at 10k documents, 2.2 ms at 100k with every
|
|
53
|
+
document matching. `due` selects instead of sorting everything.
|
|
54
|
+
- The bridge compacts after an ingest only when it added or changed
|
|
55
|
+
documents.
|
|
56
|
+
- Opening validates each byte once (header, directory, section checksums; no
|
|
57
|
+
whole-file trailer) and finds sections in O(1). Mirror no longer validates
|
|
58
|
+
a base twice.
|
|
59
|
+
- Community detection, computed at every compaction and read by nothing,
|
|
60
|
+
is gone; rank records shrink from 8 to 2 bytes.
|
|
61
|
+
|
|
62
|
+
**New**
|
|
63
|
+
- Lineage model: `EdgeType::{Contains, Derives, Conditions}`, the
|
|
64
|
+
`eflags::EXACT` copy flag (`Writer::set_edges_with_flags`), inbound edges
|
|
65
|
+
(`Snapshot::in_edges`, written as a reverse CSR at compaction), node
|
|
66
|
+
attributes for large values (`Writer::set_attrs`, `Snapshot::attr(s)`),
|
|
67
|
+
and one reusable, allocation-free walk (`Snapshot::walk` with `Walk`,
|
|
68
|
+
`Direction::{Out, In}`). Up to 4096 edges per node.
|
|
69
|
+
- A core build (`default-features = false`) of hashing, keys, byte codecs,
|
|
70
|
+
`container` (the checksummed sectioned file framing) and `fsio` (atomic
|
|
71
|
+
writes, the cross-process lock, the clock), with xxhash-rust as the only
|
|
72
|
+
dependency; `mmap` exposes `MappedFile`; `store` (default) is the store.
|
|
73
|
+
|
|
74
|
+
**Removed** (no consumer used them): the `llm` feature and `enrich`, segment
|
|
75
|
+
importance overrides, edge tiers, `community_summary`, `surprises`, `path`
|
|
76
|
+
(use `walk`), `pending_ops`, `Writer::staged`, `Snapshot::check`, the
|
|
77
|
+
`*_with` bridge variants (the plain ones are generic over the embedder), and
|
|
78
|
+
the `libc` and `thiserror` dependencies (std's `File::try_lock` now holds the
|
|
79
|
+
writer lock on every platform, released by the OS on crash).
|
|
80
|
+
|
|
81
|
+
- `hash`: the crate's xxh3 family (`xxh3_64`, `xxh3_64_seeded`, `xxh3_128`,
|
|
82
|
+
streaming `Hasher`) as thin public wrappers, so dependants fingerprint with
|
|
83
|
+
the exact function behind `UrlKey` without a second hashing crate.
|
|
84
|
+
|
|
85
|
+
## 0.3.0
|
|
86
|
+
|
|
87
|
+
Additive release: every 0.2 API, file format and default behaviour is
|
|
88
|
+
unchanged (`cargo semver-checks` against 0.2.1: no breaking change), and
|
|
89
|
+
stores written by 0.2.1 open and read identically (golden fixtures in
|
|
90
|
+
`tests/fixtures/v0.2.1`, including byte-identical compaction output and WAL
|
|
91
|
+
frames).
|
|
92
|
+
|
|
93
|
+
### New: `graph-r-mirror` (separate crate in `mirror/`)
|
|
94
|
+
|
|
95
|
+
Keeps a store directory in sync with an object store (Google Cloud Storage,
|
|
96
|
+
a local directory, or memory) through objstore-r. The files are moved byte
|
|
97
|
+
for byte, so a store can live on tmpfs on a stateless instance and be durable
|
|
98
|
+
in a bucket: `pull_into`, incremental `publish` (only new WAL frames; the new
|
|
99
|
+
base after a compaction; coalescing of long segment runs), `refresh_into` for
|
|
100
|
+
read-only replicas, a `HEAD` compare-and-swap that fences a second writer,
|
|
101
|
+
and an optional writer lease. `load_image` / `refresh_image` keep a replica
|
|
102
|
+
entirely in memory; the base and all segments are fetched concurrently. It is a separate crate so graph-r's own
|
|
103
|
+
manifest gains no dependency.
|
|
104
|
+
|
|
105
|
+
### New: `graph-r-kb` (separate crate in `kb/`)
|
|
106
|
+
|
|
107
|
+
graph-r + link-r as **one knowledge base** on one object store: a writer
|
|
108
|
+
(lease-holding, graph on tmpfs, durability in the bucket) crawls
|
|
109
|
+
conditionally — validators and known links come from the graph, so unchanged
|
|
110
|
+
pages cost a 304 — absorbs through the bridge, and publishes both halves
|
|
111
|
+
concurrently, fenced; `refresh_due` revalidates exactly what the graph's
|
|
112
|
+
adaptive freshness says is due. A replica needs no disk: the graph base and
|
|
113
|
+
the link index are served in place from the fetched bytes, and refreshes cost
|
|
114
|
+
two metadata requests when nothing changed. `lookup` fuses graph-r's
|
|
115
|
+
anchored, graph-aware ranking with link-r's hybrid search (reciprocal-rank
|
|
116
|
+
fusion; the graph work overlaps a remote query embedding). Tested end to end
|
|
117
|
+
on memory, local-directory, fake-gcs-server and a live bucket, with a
|
|
118
|
+
writer-vs-replica property test.
|
|
119
|
+
|
|
120
|
+
### New API
|
|
121
|
+
|
|
122
|
+
- `Store::open_image(base, wal)` and `Store::reload_image`: read-only stores
|
|
123
|
+
served straight from memory (e.g. objects fetched from a bucket) — the base
|
|
124
|
+
is used in place, fully validated, no file or mapping; `Store::is_image`.
|
|
125
|
+
- `bridge::{absorb_with, ingest_update_with, ingest_refresh_with}`: the
|
|
126
|
+
bridge for link-r indexes built with any embedder.
|
|
127
|
+
- `Store::dir()`, `Store::generation()`.
|
|
128
|
+
- `Store::set_compact_inline(bool)` and `Store::compaction_due()`: move
|
|
129
|
+
compaction off the commit path (inline remains the default).
|
|
130
|
+
- `format::wal::committed_len` and `committed_frames_len`: the intact prefix
|
|
131
|
+
`replay` would report, without collecting ops.
|
|
132
|
+
- `store::{BASE_FILE, WAL_FILE, LOCK_FILE}`.
|
|
133
|
+
|
|
134
|
+
### Fixes and performance
|
|
135
|
+
|
|
136
|
+
- Loading is one validated code path for files and images; replaying a
|
|
137
|
+
generation no longer clones every op into the overlay twice.
|
|
138
|
+
- `Store::reload_if_stale` is now cheap when nothing changed (two `stat`
|
|
139
|
+
calls; no remap, no read — the 0.2.1 notes promised this, but every call
|
|
140
|
+
re-mapped the base and re-read the whole WAL), and re-reads only the log
|
|
141
|
+
when only the log grew.
|
|
142
|
+
- Temporary files are named by pid **and** a process-wide counter and created
|
|
143
|
+
exclusively, so two stores or threads in one process can never collide on a
|
|
144
|
+
temporary, and a leftover from a crash is never reused.
|
|
145
|
+
- Windows: the writer lock is now an OS file lock (`LockFileEx` via std),
|
|
146
|
+
released by the kernel when the process dies. 0.2 created the lock file
|
|
147
|
+
exclusively and relied on deleting it, so a crashed writer left the store
|
|
148
|
+
locked until someone removed `graph.lock` by hand. (Do not run a 0.2 and a
|
|
149
|
+
0.3 writer on the same directory concurrently on Windows; unix is
|
|
150
|
+
unaffected — both use `flock`.)
|
|
151
|
+
- WAL framing hashes `seq‖payload` by streaming (identical checksums) instead
|
|
152
|
+
of building a concatenated copy per frame, on both encode and replay.
|
|
153
|
+
|
|
154
|
+
### Security
|
|
155
|
+
|
|
156
|
+
- Lockfiles (crate and Python binding) move to rustls 0.23.45 for
|
|
157
|
+
RUSTSEC-2026-0285 (TLS 1.3 handshake messages accepted across encryption
|
|
158
|
+
levels); reached through link-r's HTTP fetcher under `bridge`.
|
|
159
|
+
|
|
160
|
+
### Tooling
|
|
161
|
+
|
|
162
|
+
- New fuzz targets `fuzz_wal_committed_len` and `fuzz_open_image` (and `fuzz_manifest` in
|
|
163
|
+
`mirror/fuzz`).
|
|
164
|
+
- CI: a mirror job (memory, local directory, GCS emulator), a semver job
|
|
165
|
+
(additive-only against the previous tag), the 0.2.1 golden suite in the
|
|
166
|
+
security workflow, and `scripts/ci-local.sh` running every gate locally.
|
|
167
|
+
- `rust-version` is now 1.89 (std file locking); the pinned nightly is
|
|
168
|
+
unchanged.
|
|
169
|
+
|
|
170
|
+
## 0.2.1
|
|
171
|
+
|
|
172
|
+
### Python bindings
|
|
173
|
+
|
|
174
|
+
- `Store.reload_if_stale()` is now exposed: read-only handles pick up commits
|
|
175
|
+
and compactions made by a writing process — cheap when nothing changed (a
|
|
176
|
+
header comparison, no remap), returning True when a new generation or fresh
|
|
177
|
+
WAL frames became visible. The Rust API always had it; the binding gap made
|
|
178
|
+
long-lived readers (e.g. an MCP server holding a read-only store while a
|
|
179
|
+
background sync writes) serve stale results until reopen.
|
|
180
|
+
|
|
181
|
+
## 0.2.0
|
|
182
|
+
|
|
183
|
+
### GitHub repositories as a first-class source
|
|
184
|
+
|
|
185
|
+
`Store.sync` now routes by source form: a GitHub repository spec
|
|
186
|
+
(`https://github.com/owner/repo[/tree/ref[/dir]]` or
|
|
187
|
+
`github:owner/repo@ref[//dir]`) goes through link-r's new tree-API source —
|
|
188
|
+
one API call lists every file with its blob SHA, files whose SHA the graph
|
|
189
|
+
already stores are revalidated **without any fetch**, and only new/changed
|
|
190
|
+
blobs transfer. An unchanged repository costs exactly one HTTPS request per
|
|
191
|
+
sync, from a cold start included: the SHAs ride the existing `etag` →
|
|
192
|
+
`crawl_seed` → validators plumbing, unchanged.
|
|
193
|
+
|
|
194
|
+
- `depth` means directory levels below the subdir on this path (link hops on
|
|
195
|
+
the crawl path, as before); `max_bytes` skips oversized files from the
|
|
196
|
+
tree's own size field, no fetch issued.
|
|
197
|
+
- `token` (a PAT) reaches only the GitHub API and raw hosts — never a host a
|
|
198
|
+
document links to. Public, private, and internal repositories all work.
|
|
199
|
+
- `api_base`/`raw_base` (set together) target GitHub Enterprise.
|
|
200
|
+
- Crawl-only options passed with a GitHub spec raise `ValueError` rather than
|
|
201
|
+
being silently ignored.
|
|
202
|
+
|
|
203
|
+
### Cross-platform persistence and memory, tested
|
|
204
|
+
|
|
205
|
+
- The binding CI job now runs the full suite on Linux, macOS, and Windows on
|
|
206
|
+
every push. New `test_persistence.py` pins the file contract per-OS:
|
|
207
|
+
write→close→reopen→write-again cycles, stores under paths with spaces and
|
|
208
|
+
non-ASCII characters, fifty open/close cycles proving the lock releases
|
|
209
|
+
every time, a cross-process write via a child interpreter, and
|
|
210
|
+
`os.replace` stamp atomicity beside the store.
|
|
211
|
+
- New `test_memory.py` pins the harness read path's zero-growth property:
|
|
212
|
+
hundreds of query/due cycles — and a reader running under a live writer —
|
|
213
|
+
hold RSS flat and leave no Python-heap accumulation.
|
|
214
|
+
|
|
215
|
+
## 0.1.0
|
|
216
|
+
|
|
217
|
+
Initial release: an embedded, persistent knowledge graph that serves as the
|
|
218
|
+
durable backend for [link-r](https://github.com/lituus-io/link-r).
|
|
219
|
+
|
|
220
|
+
### Storage
|
|
221
|
+
|
|
222
|
+
- Two files. `graph.base` — an immutable, mmapped, checksummed, sectioned
|
|
223
|
+
snapshot (sorted fixed-width 72-byte node records for zero-copy binary search,
|
|
224
|
+
CSR edges, label heap, lexicon with delta-varint postings, persisted ranks).
|
|
225
|
+
`graph.wal` — an append-only op log with per-frame xxh3; torn tails are
|
|
226
|
+
truncated on open.
|
|
227
|
+
- Compaction folds base + WAL into a new **byte-reproducible** base via atomic
|
|
228
|
+
rename. A crash at any point in the sequence recovers: WAL replay skips
|
|
229
|
+
sequences already folded into the base.
|
|
230
|
+
- Every file is validated end to end before a single record is read — magic,
|
|
231
|
+
version, header and per-section checksums, directory bounds and alignment,
|
|
232
|
+
label-heap offsets, CSR monotonicity, edge destinations, lexicon ordering, and
|
|
233
|
+
node sortedness — which is what makes the zero-copy accessors infallible.
|
|
234
|
+
|
|
235
|
+
### Concurrency
|
|
236
|
+
|
|
237
|
+
- Any number of snapshot readers against a 4-slot generation ring; one writer,
|
|
238
|
+
serialized in-process by a mutex and across processes by `flock`.
|
|
239
|
+
- Snapshots are lifetime-bound borrow guards: no `Arc`, no async runtime, and a
|
|
240
|
+
single audited `unsafe` island (`src/os.rs`: mmap + flock) under a crate-wide
|
|
241
|
+
`#![deny(unsafe_code)]`.
|
|
242
|
+
|
|
243
|
+
### Freshness and intelligence
|
|
244
|
+
|
|
245
|
+
- Adaptive per-node revalidation interval — grown on an unchanged check, cut
|
|
246
|
+
sharply on change, clamped, and biased by importance — with `due()` work-lists
|
|
247
|
+
carrying stored ETags for conditional revalidation. Tombstones preserve the
|
|
248
|
+
history of sources that have gone away.
|
|
249
|
+
- Deterministic PageRank and hub-muted label-propagation communities with stable
|
|
250
|
+
ids, computed at compaction and persisted.
|
|
251
|
+
- Token-budgeted lookups that answer with URLs and heading anchors, never
|
|
252
|
+
document bodies: IDF-weighted tiered lexical scoring, per-term seed
|
|
253
|
+
guarantees, hub-refusing bounded BFS, and seeds-first rendering.
|
|
254
|
+
|
|
255
|
+
### Tiers and extension seams
|
|
256
|
+
|
|
257
|
+
- Crawl-tier writes never destroy enrichment-tier edges or scores, and vice
|
|
258
|
+
versa; segments are keyed by heading path so enrichment survives a re-crawl.
|
|
259
|
+
- Features: `default = []` (the pure embedded store), `bridge` (link-r ingest
|
|
260
|
+
and due-list refresh loop), `llm` (a vendor-free `Enricher` trait seam).
|
|
261
|
+
|
|
262
|
+
### The stateless loop and the Python wheel
|
|
263
|
+
|
|
264
|
+
- `bridge::crawl_seed` extracts the graph's stored validators and edges in
|
|
265
|
+
link-r's vocabulary, so a *fresh* index revalidates a known site with zero
|
|
266
|
+
body transfers — the "absorb and discard the index" design now survives a
|
|
267
|
+
process restart.
|
|
268
|
+
- Change detection in the bridge is graph-relative: a changed page arriving as
|
|
269
|
+
`Added` from an ephemeral index still cuts its refresh interval, because the
|
|
270
|
+
committed content hash — not the crawl's index — decides what changed.
|
|
271
|
+
- Python bindings (`pip install graph-r`, abi3, Python ≥ 3.12): one `Store`
|
|
272
|
+
class carrying the whole loop — `sync` (crawl → absorb → compact in a single
|
|
273
|
+
call, interpreter detached), `query`/`related`/`due`, the `add`/`touch`
|
|
274
|
+
writer seam, `pin`/`remove`/`compact`. Usable from any thread.
|
|
275
|
+
|
|
276
|
+
### Verification
|
|
277
|
+
|
|
278
|
+
- Unit, hermetic lifecycle, bridge end-to-end, and concurrency-stress suites.
|
|
279
|
+
- A model-based property test checking arbitrary op sequences against a
|
|
280
|
+
reference model through compaction and reopen, plus byte-reproducible
|
|
281
|
+
compaction and torn-WAL-at-any-byte recovery.
|
|
282
|
+
- Four fuzz targets over every decoder: arbitrary bytes must produce a typed
|
|
283
|
+
error, never a panic or an over-allocation.
|
|
284
|
+
- Criterion benchmarks, and zero clippy warnings across all features and
|
|
285
|
+
targets.
|