Zaxy 2.3 Backend Continuity Options — Research Report
- Date: 2026-06-11
- Scope: stay-and-contain on frozen Kuzu 0.11.3 vs. adopt the LadybugDB fork vs. stand up a second embedded backend
- Evidence basis: every claim carries a source URL or a locally-verified observation. Local verification environment: Linux x86_64, Python 3.13, test scripts at
/tmp/zaxy-23-research/defect_tests.pyand/tmp/zaxy-23-research/defect_tests2.py, run againstladybug==0.17.1andkuzu==0.11.3in dedicated venvs (/tmp/zaxy-23-research/venv17,/tmp/zaxy-23-research/venvk). - Defect list under audit (from
docs/superpowers/specs/2026-06-11-zaxy-2-2-ann-engineering-plan.mdanddocs/research/ann-engineering-2026-06.md): 1. kuzu#5965 —SETon indexed columns rejected 2. kuzu#6040 —DROP_VECTOR_INDEXmetadata corruption 3. kuzu#6047 — sequential HNSW load can block DB open 4.COPY FROMin-memory Arrow with fixed-size-list column segfaults 5. unbound$parametersegfaults instead of raising 6. silent search breakage after in-place mutation under a live HNSW index
---
1. LadybugDB fork — in depth
1.1 Identity, history, governance
- Repo: <https://github.com/LadybugDB/ladybug>. Created 2025-10-07 — three days before the Kuzu archive (kuzudb/kuzu
archived: true, last push 2025-10-10; verified via GitHub API). Not archived, MIT license, 1,277 stars, 65 open issues, last push 2026-06-11 (today). (GitHub API, verified locally.) - Founder/maintainer: Arun Sharma (
adsharma, ex-Facebook/ex-Google), GitHub company field "Ladybug Memory, Inc" — there is a corporate entity behind it, announced as "a community-driven fork of the Kuzu repo but with a vision to be a full one-to-one replacement of Kuzu" (The Register: <https://www.theregister.com/2025/10/14/kuzudb_abandoned/>; gdotv weekly: <https://gdotv.com/blog/weekly-edge-kuzu-forks-duckdb-graph-cypher-24-october-2025/>). The original Kuzu team is not involved post-fork (their names appear only in inherited pre-fork commit history). - Bus factor — the weakest signal. Of the last 200 commits:
adsharma162,aheev34, all others ≤ 2 (GitHub API, verified). Every release since v0.12.0 was cut byadsharma(or the actions bot). This is a one-engineer project with one regular collaborator. Counterweights: ~monthly releases for 8 consecutive months, same-week responses on issues (e.g. #351, #452 threads), CodeQL workflow and SECURITY.md added (PRs #397, #385 in v0.15.4.2 release notes), nightly dev wheels on PyPI. Active, but ifadsharmastops, the project stops.
1.2 Releases and wheels
- GitHub releases: v0.12.0 (2025-11-04) → v0.13.x (Dec) → v0.14.x (Jan) → v0.15.x (Feb–Apr) → v0.16.x (Apr–May) → v0.17.1 (2026-06-02) — roughly monthly cadence (<https://github.com/LadybugDB/ladybug/releases>, verified via GitHub API).
- PyPI naming churn (a real migration hazard to pin around):
- First published as
real-ladybug(0.0.1.dev1 on 2025-10-30 → 0.15.3 on 2026-04-01), becauseladybugwas occupied (<https://pypi.org/project/real-ladybug/>). - Renamed to
ladybugat v0.15.4.2 (PR #374 "rename: real_ladybug -> ladybug"); PyPIladybugnow carries 0.15.3 → 0.17.1 (2026-06-02) plus nightly0.17.0.devYYYYMMDDwheels (<https://pypi.org/project/ladybug/>, verified via PyPI JSON).real-ladybugis now stale at 0.15.3 — anyone pinning the old name silently froze in April. - Wheel matrix for
ladybug0.17.1 (verified from PyPI): cp310–cp314 × {macosx_13_0_arm64, macosx_13_0_x86_64, manylinux_2_26_aarch64, manylinux_2_27_x86_64, musllinux_1_2 (both arches), win_amd64, win_arm64} + sdist. That is strictly broader than frozen kuzu 0.11.3 (adds cp314 on macOS/Windows, musllinux, win_arm64). Python 3.14 support landed in PR #221 (v0.15.0 release notes). One regression: macOS floor moved from 11.0 (kuzu) to 13.0 (ladybug). - License: MIT (GitHub API + PyPI metadata, verified).
1.3 API compatibility posture
- Drop-in at the Python API level, different import name.
ladybug0.17.1 exposesDatabase,Connection,AsyncConnection,PreparedStatement,QueryResult,torch_geometric_result_converter— the kuzu surface — plus newArrowQueryResult/CSR APIs (verified locally by import). Issue reporters routinely writeimport real_ladybug as kuzuand run unmodified Kuzu code (e.g. <https://github.com/LadybugDB/ladybug/issues/377>). - Locally verified: every Cypher/DDL form exercised in my defect battery ran unmodified on ladybug 0.17.1 —
CREATE NODE TABLE,CREATE REL TABLE,MATCH, parameterizedCREATE/SET/DELETE,INSTALL vector; LOAD vector;,CALL CREATE_VECTOR_INDEX,CALL QUERY_VECTOR_INDEX,COPY ... FROM,CHECKPOINT,EXPORT/IMPORT DATABASE. - Storage format is NOT compatible. Ladybug 0.17.1 refuses a Kuzu-0.11.3-written database:
RuntimeError: ... The file is not a valid Lbug database file!(locally verified). However the export path works: kuzu 0.11.3EXPORT DATABASE (format='parquet')→ ladybug 0.17.1IMPORT DATABASEround-tripped nodes, rels, and schema correctly (locally verified). For Zaxy this is nearly moot: the embedded store is a projection that can be rebuilt from the source of truth. - Divergence is beginning (Arrow-backed tables, open-type graphs, multiple labels, extension-ABI break at 0.16.0 per release notes) — today it is a superset; in a year the dialects may drift. Pin exact versions.
1.4 The defect ledger — fix evidence, one by one
All "locally verified" rows were run against ladybug==0.17.1 (scripts in /tmp/zaxy-23-research/), each case in an isolated subprocess so a segfault would be caught as a signal exit.
| # | Frozen-Kuzu defect | Status in ladybug 0.17.1 | Evidence |
|---|---|---|---|
| 1 | kuzu#5965: SET on indexed column rejected |
NOT fixed (still rejected, cleanly) | Locally verified: RuntimeError: Cannot set property vec in table embeddings because it is used in one or more indexes. Open feature request: <https://github.com/LadybugDB/ladybug/issues/377>. (Cosmetic bug: error message names the wrong table.) Zaxy already builds indexes after bulk load, so this is non-blocking — and the failure mode is an exception, not corruption. |
| 2 | kuzu#6040: DROP_VECTOR_INDEX metadata corruption |
FIXED | Fix commit 029d7aef25 (2025-10-28) "fix: DROP_VECTOR_INDEX persistence bug preventing property updates (#22)" <https://github.com/LadybugDB/ladybug/commit/029d7aef25>; tracking issue closed 2025-11-12: <https://github.com/LadybugDB/ladybug/issues/69>. Locally verified: create index → DROP_VECTOR_INDEX → CHECKPOINT → close → reopen → SET on the formerly-indexed column succeeds. Zaxy's drop-free generation-swap could be retired under ladybug (but see §1.5 before doing so). |
| 3 | kuzu#6047: sequential HNSW load can block DB open | No direct evidence of a fix | No matching issue/commit found in the fork (searched "HNSW load", "blocking database open", "6047"). Adjacent but distinct work exists (non-blocking concurrent checkpoint, PRs #332/#371, v0.15.4.2 notes). Treat as inherited until the Zaxy lane measures cold-start at 10^5. Zaxy's threshold-gated cold-start guard stays. |
| 4 | In-memory Arrow COPY FROM fixed-size-list segfault |
FIXED / not reproducible | Locally verified: COPY V FROM $tbl where $tbl is an in-memory pyarrow.Table with a pa.list_(pa.float32(), 4) column succeeded (exit 0, rows queryable) — the exact shape that segfaults kuzu 0.11.3 per the 2.2 E1 finding. No single fix commit identified; related closed fixes: param-binding FLOAT[N] segfault <https://github.com/LadybugDB/ladybug/issues/376> (closed 2026-04-12) and substantial Arrow-path work in 0.15–0.17. The parquet round-trip could be removed under ladybug after lane confirmation. |
| 5 | Unbound $parameter segfault |
Crash fixed; semantics now silent | Locally verified: an unbound $missing no longer segfaults — it evaluates to NULL and the query runs "successfully". That converts a crash into a silent-wrong-answer hazard. Zaxy's _QUERY_PARAMETER_RE choke point must stay regardless of backend. |
| 6 | Silent search breakage after in-place mutation under live HNSW | Substantially fixed; one residual hole | Fix lineage: issue #67 "vector index: poor recall after many deletions" (closed 2025-11-13) <https://github.com/LadybugDB/ladybug/issues/67>, fixed by PR #68 "vector index: fix checkpoint corruption" (root cause: OverflowFile::checkpoint() page allocation) <https://github.com/LadybugDB/ladybug/issues/68>. Locally verified (positive): delete + reinsert of all 100 rows one-by-one under a live index, then QUERY_VECTOR_INDEX → 5/5 overlap with exact ground truth. Locally verified (residual): MATCH (v:V) DELETE v (delete-ALL in one statement) then reinsert → the index permanently returns 0 rows on 0.17.1. Zaxy never does delete-all under a live index on the active generation (deltas are pure extensions; rebuilds are fresh generations), so this is avoided by existing design — but it means "empty superseded generation tables" remains the right pattern even though dropping is now safe. |
Bonus row — the defect that motivated 2.3 in the first place:
| The G3 failure (HNSW recall collapse at high dim / large N) | NOT addressed — by the maintainer's own statement | "There have been no significant changes to the vector indexing code since [the fork]" — adsharma, 2026-03-31, in <https://github.com/LadybugDB/ladybug/issues/351> (that issue's ~18%-recall report was traced to a downstream Rust-crate packaging error, not core HNSW). Ladybug ships the same NaviX HNSW that Zaxy's lane measured at 0.60–0.63 recall@10 at 50k×1536. Switching backends does not buy back high-dimension ANN; the numpy paths stay primary. |
1.5 Counter-signals (be blunt)
- Open issue #452 (2026-05-04, still open):
Database::~Database()SIGSEGV during checkpoint flush plus per-write throughput collapse on a ~60K-node graph on 0.16.x — 17K upserts unfinished after 13 minutes (<https://github.com/LadybugDB/ladybug/issues/452>). Maintainer triaged within days (binding lifetime bug; "LadybugDB isn't optimized for small writes" — <https://github.com/LadybugDB/ladybug/discussions/301>). Zaxy's COPY-based vector path aligns with the bulk-write posture, but any Zaxy sync path still doing row-at-a-time UNWIND mutation at 10^4–10^5 scale must be lane-tested on ladybug before adoption. - Closed-but-recent segfault reports in the bindings (#380 checkpoint segfault, #390 interpreter-shutdown segfault, #483 numpy
$paramAttributeError) show binding-layer churn. They get fixed quickly, but the layer Zaxy sits on is the one moving. - v0.15.0 release notes: "fixing known vulnerabilities via third-party dependencies" (<https://github.com/LadybugDB/ladybug/releases/tag/v0.15.0>) — i.e., the inherited dependency tree had known vulns. Ladybug patched them; frozen Kuzu still carries them (see §4).
- One person cuts every release. Monthly cadence for 8 months is real but not a guarantee.
1.6 Migration blast radius for Zaxy (qualitative, locally grounded)
Small. import kuzu appears in exactly two files (src/zaxy/embedded_graph_store.py:241, src/zaxy/doctor.py:362, both lazy imports — verified); the pin is kuzu>=0.11.0 in pyproject.toml. ~51 execute() call sites in the store run a dialect that executed unmodified in my tests. No file-format migration: projections rebuild. The 2.2 defect accommodations (parquet round-trip, generation swap, param choke point, cold-start guard) can all be kept under ladybug at zero cost — retire them only as the lane proves each one unnecessary.
---
2. Other Kuzu forks and continuations
| Fork | Status | Verdict |
|---|---|---|
| ryugraph (predictable-labs) <https://github.com/predictable-labs/ryugraph> | 137 stars; last push 2026-01-20; PyPI ryugraph 25.9.2 last published 2025-12-06 (verified) |
Stalled ~5 months. Early energy (the LadybugDB DROP_VECTOR_INDEX fix arrived "via ryugraph", per issue #69), now apparently abandoned. Not a candidate. |
| Vela-Engineering/kuzu <https://github.com/Vela-Engineering/kuzu> | Active (pushed 2026-06-07); tagged v0.12.0-vela.* releases (2026-06-07); claims concurrent multi-writer support; MIT |
Interesting engineering, but no PyPI distribution (verified: no vela-kuzu/kuzu-vela packages), 37 stars, single-company fork for their own agent-memory product. Watch, don't adopt. |
| Bighorn (Kineviz) <https://github.com/Kineviz/bighorn> | 130 stars; last push 2025-10-11 — the day after the archive; not on PyPI (verified) | Dead on arrival. |
LadybugDB is the only fork with releases, wheels, users, and a defect-fix record. (Fork landscape context: <https://gdotv.com/blog/weekly-edge-kuzu-forks-duckdb-graph-cypher-24-october-2025/>.)
---
3. Alternative embedded backends (scoped to Zaxy's profile)
Profile assumed: property-graph entities with temporal validity windows, typed relationships, traversal queries, exact + vector search — where 2.2 proved the numpy paths beat Kuzu HNSW at every measured scale, so the vector workload does not need to live in the graph engine.
3.1 DuckDB (+ property-graph approaches)
- Maintenance: excellent. 1.5.3 on PyPI 2026-05-20, cp310–cp314 wheels, MIT,
requires_python >=3.10(PyPI JSON, verified). Backed by DuckDB Labs + the independent DuckDB Foundation. - Embedded story: first-class, in-process, no sidecar.
- Graph-query fit: the catch. Native option is recursive CTEs (SQL). The property-graph option, DuckPGQ (SQL/PGQ), is a CWI research community extension — <https://github.com/cwida/duckpgq-extension>: 416 stars, MIT, last commit 2026-03-02, last repo push 2026-04-09, no formal releases (verified via GitHub API). Adopting it would swap one weak-maintenance dependency for another, now in the query dialect itself.
- Migration blast radius: high — every Cypher call site rewritten to SQL(/PGQ); traversals and the temporal-window predicates redesigned. Vector: DuckDB VSS exists but is unnecessary given the numpy paths.
3.2 SQLite (stdlib sqlite3, JSON + recursive CTEs as graph substrate)
- Maintenance: the best on Earth — public-domain, supported "through 2050" (<https://www.sqlite.org/lts.html>), ships inside CPython, zero new dependencies.
- Embedded story: definitional.
- Graph-query fit: adjacency tables + recursive CTEs (documented graph pattern: <https://www.sqlite.org/lang_with.html>). Typed relationships = rel tables; temporal validity windows = indexed columns (arguably a better fit in SQL than in Cypher). Loses Cypher expressiveness; fine if the audited traversal surface is shallow (single-/few-hop), painful if there are deep variable-length path queries.
- Migration blast radius: high (full store rewrite behind the projection contract), but it is the only option whose dependency risk is effectively zero forever.
3.3 LanceDB / lance-graph
- LanceDB: healthy — 0.33.0 on PyPI 2026-05-28, Apache-2.0, embedded, abi3 wheels (PyPI JSON, verified). But it is a vector/table store: no graph queries at all — wrong shape, and Zaxy doesn't even need its vector engine (numpy wins per 2.2 lanes).
- lance-graph (<https://github.com/lance-format/lance-graph>): "Run Graph Queries with Lance" — Apache-2.0, created 2025-09-29, pushed 2026-06-06, 154 stars (verified). Notable: ladybug contributor
aheevalso contributes here, and ex-Kuzu-DevRel prrao87 benchmarks "Kuzu, Ladybug and lance-graph" together (<https://github.com/prrao87/graph-benchmark>). The ecosystem's center of gravity may move here, but it is months old. Watch for 2.4+, not a 2.3 candidate.
3.4 Shrink the ask (Zaxy-owned projection store: SQLite/parquet + existing numpy vectors)
- Honest framing: 2.2 already moved the hard part out of the graph engine. The lane proved exact/int8 numpy superior to Kuzu HNSW at every measured scale, and ANN is gated to dim ≤ 64 (
docs/research/ann-engineering-2026-06.md§6). What remains in Kuzu is entity/relationship storage + traversal — a workload SQLite handles. - Maintenance signal: inherits SQLite's (§3.2). No C++ graph engine, no fork-watching, no wheel-matrix anxiety, ever.
- Blast radius: the largest engineering effort (a new store implementation + parity tests behind the projection contract), but the smallest permanent risk surface. The 2.2 strategy-pipeline consolidation and the single-choke-point design make the store more swappable than it was a release ago.
---
4. Risk timeline: staying on frozen Kuzu 0.11.3
- Python 3.13: covered. cp313 (+cp313t linux) wheels exist on all platforms (PyPI, verified).
- Python 3.14: already broken on macOS/Windows. kuzu 0.11.3 ships cp314/cp314t wheels for manylinux only — there are no macOS and no Windows cp314 wheels (<https://pypi.org/project/kuzu/0.11.3/#files>, verified via PyPI JSON). A macOS-arm64 developer on Python 3.14 cannot
pip install kuzutoday; they'd need a from-source build of an archived C++ tree (viability on current Xcode/clang: unverified, and nobody will fix it if it breaks). - Python 3.15: hard cliff, ~October 2026. CPython 3.15.0 final is scheduled 2026-10-01 (PEP 790: <https://peps.python.org/pep-0790/>). No 3.15 wheels will ever exist for kuzu; the sdist pins a pybind11 generation that predates 3.15. Zaxy declares
requires-python >=3.11with no upper bound — the first user on 3.15 hits an uninstallable default backend in ~4 months. - Platform drift. Wheels target macosx_11_0 and manylinux_2_26/2_27 — fine for existing platforms; the risk is new toolchains/SDKs breaking the source build, the only escape hatch an archived repo has. New platform targets (e.g. win_arm64, musl) will never appear (ladybug already ships both — §1.2).
- Security posture. kuzudb/kuzu has zero published security advisories (GitHub API, verified) — which means no process, not no bugs. Concretely: LadybugDB's v0.15.0 release notes say it focused on "fixing known vulnerabilities via third-party dependencies" (<https://github.com/LadybugDB/ladybug/releases/tag/v0.15.0>) — those same vulnerable vendored deps are frozen forever in 0.11.3. Zaxy's exposure is partially contained (embedded, local-first, no network-facing query surface; the unbound-param and Arrow-segfault choke points already guard the known crash inputs), but "unmaintained C++ parsing attacker-influenceable strings" is a liability that only grows.
- Net: stay-and-contain is not a strategy, it is a countdown with a visible expiry (~Oct 2026, or the first macOS-3.14 user — i.e., now).
---
5. Decision-ready comparison and recommendation
| Option | Continuity | Defect posture | Vector fit | Blast radius | Existential risk |
|---|---|---|---|---|---|
| Stay-and-contain (kuzu 0.11.3) | None; expires ~Oct 2026 (3.15), already broken for macOS py3.14 | All 6 defects permanent (all contained by 2.2 engineering) | numpy primary (proven) | Zero | High and rising |
| Adopt LadybugDB | Monthly releases; broader wheel matrix incl. cp314 all-platform | #6040 fixed, Arrow-COPY fixed, param segfault fixed(→NULL), mutation breakage fixed (delete-all residual), #5965 unchanged, #6047 unproven | Same NaviX HNSW — G3 unchanged; numpy stays primary | Small (2 import sites, pin change, projection rebuild; dialect ran unmodified) | Bus factor ≈ 1 |
| Second backend: SQLite (shrink the ask) | Effectively infinite | Entire defect class eliminated | numpy primary (unchanged) | Large (new store impl) | Lowest possible |
| DuckDB (+DuckPGQ) | DuckDB excellent; DuckPGQ research-grade | n/a | numpy primary | Large (SQL rewrite) + weak link in dialect | Medium (DuckPGQ) |
| LanceDB / lance-graph | LanceDB healthy; lance-graph embryonic | n/a | Redundant with numpy | Large + graph gap | High (immaturity) |
Recommendation (ranked)
- Adopt LadybugDB as the 2.3 default backend — confidence: medium-high. It is the only continuation with releases, full-matrix wheels (incl. the cp314 macOS/Windows gap that frozen Kuzu will never close), a verified drop-in API, a working EXPORT→IMPORT migration path, and commit-level fixes for three of the six documented defects (plus a crash→exception downgrade on a fourth) — all re-verified locally against 0.17.1 in this audit. Conditions that should be non-negotiable: exact-version pin (
ladybug==, never the stalereal-ladybugname); keep every 2.2 defect accommodation (param choke point — unbound params now silently NULL; generation-swap empties; cold-start guard — #6047 unproven) and retire each only on lane evidence; re-run the full vector-scale + graph-scale lanes on ladybug as the formal acceptance bar (the open #452 write-throughput report at exactly Zaxy-relevant scale is the thing the lane must clear); numpy paths remain the primary vector machinery — the fork does not change NaviX and does not reopen G3. The bus-factor-of-one is real and is the reason for item 2.
- Start the shrink-the-ask design study in parallel (2.3 research, 2.4+ delivery) — confidence: high that it removes the risk class; medium on cost. Ladybug fixes the continuity emergency, not the structural one (Zaxy's default path depends on whether one person keeps merging). A Zaxy-owned SQLite/parquet projection store + the existing numpy vector machinery is the only option whose maintenance risk goes to ~zero, and 2.2's strategy-pipeline consolidation already shrank the surface a second backend must implement. The pending Cypher-surface audit decides feasibility; if the traversal surface is shallow, this should become the long-term default.
- Stay-and-contain — acceptable only as the fallback if the ladybug lane runs fail — confidence: high in the assessment. It works today because 2.2 engineered around everything, but it has a dated expiry: no macOS/Windows wheels on Python 3.14 now, no Python 3.15 path in ~4 months, and a frozen vendored-dependency tree with known (since-patched-in-ladybug) vulnerabilities. If the lane rejects ladybug, pin hard, add an upper Python bound, and accelerate option 2.
- DuckDB / LanceDB as graph substrate — not recommended for 2.3 — confidence: high. DuckDB itself is the healthiest dependency in this report, but the property-graph story (DuckPGQ) is research-grade with no releases and a 3-month-old last commit; lance-graph is eight months old. Either would trade a verified small migration for a large rewrite onto a weaker link. Reassess lance-graph at 2.4+.