Skip to content

Commit 79ebc54

Browse files
committed
feat(embedder)!: swap embedding model gte-modernbert-base → F2LLM-v2-80M (320-dim)
BREAKING CHANGE: the local ONNX embedder is now codefuse-ai/F2LLM-v2-80M (320-dim, was gte-modernbert-base 768-dim). Existing indexes MUST be rebuilt with `codehub analyze --embeddings` — 320-dim query vectors cannot be compared against stored 768-dim vectors. The embedder-fingerprint guard (ADR 0014) refuses queries against a stale store until re-analyze. What changed: - onnx-embedder.ts requests the in-graph `embedding` output (shape [B,320], last-token pooling + L2 norm baked into the graph) instead of pooling / normalizing in JS — clsPool + l2NormalizeInPlace are removed. Qwen2 pad id. - New Embedder.embedQuery() applies F2LLM's query-only `Instruct:` prefix; documents embed raw. Wired at the search/hybrid.ts query seam. New query-prefix.ts holds the instruction string. - Dimension parameterized 768→320 across embedder, search (NullEmbedder), storage (DEFAULT_DIM), ingestion pool, and HTTP/SageMaker defaults. - model-pins.ts: GTE_MODERNBERT_BASE_PINS → F2LLM_V2_80M_PINS; weights are a custom ONNX export hosted as the GitHub release asset `embed-v1`, SHA256-pinned. 3-file manifest (model + tokenizer.json + tokenizer_config.json). - Migration guard: analyze suppresses the content-hash cache on a model-id change so a swap forces a full re-embed (no mixed-dimension store). - Docs, CHANGELOGs, skills swept to F2LLM/320-dim. Collapsed the stale storage ADR chain (0001/0011/0013/0016 → 0019) and fixed the README's pre-ADR-0019 storage narrative. Fixed lefthook verdict guard to check store.sqlite (was the removed graph.lbug). Verified: pnpm -r build + test green (~2400 tests); tokenizer parity with Python AutoTokenizer (byte-identical IDs); production embedder reproduces the POC 4/4 top-1 ranking + byte-deterministic output; end-to-end analyze writes 320-dim rows; migration guard confirmed firing on a stale stamp.
1 parent 56eacef commit 79ebc54

66 files changed

Lines changed: 694 additions & 448 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/skills/opencodehub-guide/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ For any task that touches code understanding, debugging, impact analysis, refact
1515
2. Read `codehub://repo/{name}/context` — codebase stats and a staleness envelope.
1616
3. Match the task to a skill below and follow that skill's checklist.
1717

18-
> If the context envelope reports the index is stale, run `codehub analyze` in the terminal first. If it says weights are missing, run `codehub setup --embeddings` to fetch the 768d gte-modernbert-base ONNX weights.
18+
> If the context envelope reports the index is stale, run `codehub analyze` in the terminal first. If it says weights are missing, run `codehub setup --embeddings` to fetch the 320d F2LLM-v2-80M ONNX weights.
1919
2020
## Skills · analysis
2121

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [0.10.0](https://github.com/theagenticguy/opencodehub/compare/root-v0.9.1...root-v0.10.0) (2026-06-26)
4+
5+
6+
### ⚠ BREAKING CHANGES
7+
8+
* **embedder:** local embedding model swapped to `codefuse-ai/F2LLM-v2-80M` (320-dim, was gte-modernbert-base 768-dim). Existing stores must be rebuilt with `codehub analyze --embeddings`; queries against a stale-dim store are refused by the fingerprint guard.
9+
310
## [0.9.1](https://github.com/theagenticguy/opencodehub/compare/root-v0.9.0...root-v0.9.1) (2026-06-14)
411

512

README.md

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,31 @@ flowchart LR
7878
| **Local-first, offline-capable** | `codehub analyze --offline` opens zero sockets. Your code never leaves your machine. No telemetry. |
7979
| **Deterministic indexing** | Identical inputs produce a byte-identical graph hash. Reproducible. Auditable. Cacheable in CI. |
8080
| **MCP-native** | Works out-of-the-box with Claude Code, Cursor, Codex, Windsurf, OpenCode. The MCP server is the primary interface; CLI exists for scripts and CI. |
81-
| **Embedded storage, two-tier** | `@ladybugdb/core` holds the structural store: symbols, edges, embeddings, BM25 + HNSW. A dedicated DuckDB sibling holds the temporal views: cochanges and summaries. Embedded files. No daemon. No database to operate. Both tiers are always present, with no backend knob (ADR 0016). |
81+
| **Single-file embedded storage** | One `store.sqlite` file holds everything — symbols, edges, embeddings, BM25 (FTS5) + HNSW traversal, and the temporal views (cochanges, summaries) — via Node's built-in `node:sqlite`. No daemon, no database to operate, and **zero native storage bindings** (ADR 0019 removed both `@ladybugdb/core` and `@duckdb/node-api`). |
8282
| **15 languages at GA** | TypeScript, JavaScript, Python, Go, Rust, Java, C#, C, C++, Ruby, Kotlin, Swift, PHP, Dart, COBOL — tree-sitter for the first 14 plus a regex provider for fixed-format COBOL. |
83-
| **WASM-only parse runtime** | `web-tree-sitter` WASM is the only parse runtime. The 15 grammar `.wasm` blobs are vendored at `packages/ingestion/vendor/wasms/`, so parsing does **zero grammar/native builds and zero GitHub fetches** at install time — there is no native parser opt-in. Storage and embeddings still load prebuilt native bindings (see Platform support). |
83+
| **WASM-only parse runtime** | `web-tree-sitter` WASM is the only parse runtime. The 15 grammar `.wasm` blobs are vendored at `packages/ingestion/vendor/wasms/`, so parsing does **zero grammar/native builds and zero GitHub fetches** at install time — there is no native parser opt-in. Storage is pure `node:sqlite`; the only optional native dep is the local embedder (see Platform support). |
8484

8585
## Platform support
8686

87-
Parsing is WASM and runs anywhere Node does. The storage and embedding
88-
tiers, however, depend on **prebuilt native bindings**`@ladybugdb/core`
89-
(graph store), `@duckdb/node-api` (temporal store), and `onnxruntime-node`
90-
(local embeddings) — so OpenCodeHub runs on the platforms those bindings
91-
ship a prebuild for:
87+
Parsing is WASM and storage is pure `node:sqlite`, so the core runs anywhere
88+
Node ≥ 24.15 does — no prebuilt native storage bindings, no Docker, no
89+
postinstall compile (ADR 0019). There is exactly **one** optional native
90+
dependency: `onnxruntime-web`, the WASM ONNX runtime that powers
91+
`--embeddings`. It ships prebuilt WebAssembly (no node-gyp, no native
92+
binding) and runs single-threaded under Node, so it too is platform-agnostic;
93+
a BM25-only install never loads it.
9294

9395
| Platform | Supported |
9496
|---|---|
95-
| `darwin-arm64`, `darwin-x64` | ✅ prebuilt |
96-
| `linux-x64`, `linux-arm64` (glibc) | ✅ prebuilt |
97-
| `win32-x64` | ✅ prebuilt |
98-
| `win32-arm64` | ❌ no prebuild — `codehub analyze` fails at store open |
99-
| Alpine / musl, 32-bit Linux ARM | ❌ no prebuild — needs a source build of `@ladybugdb/core` |
100-
101-
On an unsupported platform the lbug binding fails to load and `open()`
102-
throws `GraphDbBindingError` (there is no DuckDB-graph fallback — see
103-
[ADR 0016](./docs/adr/0016-duckdb-graph-rip.md)). The five-target prebuilt
104-
matrix mirrors `@ladybugdb/core`'s release artifacts; track its upstream
105-
for musl / `win32-arm64` coverage.
97+
| `darwin-arm64`, `darwin-x64` ||
98+
| `linux-x64`, `linux-arm64` (glibc **and** musl/Alpine) ||
99+
| `win32-x64`, `win32-arm64` ||
100+
| anywhere else Node ≥ 24.15 runs ||
101+
102+
Because storage no longer depends on a platform-specific prebuild, the
103+
earlier `GraphDbBindingError` / unsupported-platform failure mode is gone —
104+
see [ADR 0019](./docs/adr/0019-single-file-sqlite-storage.md) (which
105+
superseded the native-binding storage of [ADR 0016](./docs/adr/0016-duckdb-graph-rip.md)).
106106

107107
## Quick start
108108

@@ -187,7 +187,7 @@ The monorepo is organised as 18 workspace packages under `packages/`:
187187
| `scanners` | Subprocess wrappers for 19 scanners — OSV, Semgrep, hadolint, tflint, betterleaks, and the rest |
188188
| `scip-ingest` | SCIP indexer runners (TS, Python, Go, Rust, Java) — emits CALLS, REFERENCES, IMPLEMENTS, TYPE_OF |
189189
| `search` | Hybrid BM25 + HNSW (ACORN-1 + RaBitQ) query layer |
190-
| `storage` | `IGraphStore` (`@ladybugdb/core`) + `ITemporalStore` (DuckDB) adapters; deterministic `graphHash` |
190+
| `storage` | One `SqliteStore` (`node:sqlite`) implementing both `IGraphStore` + `ITemporalStore` over a single `store.sqlite`; deterministic `graphHash` |
191191
| `summarizer` | Process + cluster summaries for MCP responses |
192192
| `wiki` | LLM-narrated module pages emitted by `codehub wiki --llm` |
193193

@@ -199,63 +199,67 @@ production package set ships free of test-time dependencies.
199199
## Embedding backends
200200

201201
OpenCodeHub ships with three embedding backends — all serve the same
202-
`gte-modernbert-base` 768-dim space, all use CLS pooling + L2 norm — and
203-
picks one at runtime based on environment variables:
202+
`codefuse-ai/F2LLM-v2-80M` 320-dim space (last-token pooling + L2 norm
203+
baked into the ONNX graph) — and picks one at runtime based on
204+
environment variables:
204205

205206
| Precedence | Env | Backend |
206207
|---|---|---|
207-
| 1 | `CODEHUB_EMBEDDING_SAGEMAKER_ENDPOINT` | **SageMaker** — invokes an AWS SageMaker Runtime endpoint (e.g. a TEI-served `gte-modernbert-embed`). Auth via the default AWS credential chain (profile, env vars, IMDS). No local weights needed. |
208+
| 1 | `CODEHUB_EMBEDDING_SAGEMAKER_ENDPOINT` | **SageMaker** — invokes an AWS SageMaker Runtime endpoint (e.g. a TEI-served `F2LLM-v2-80M`). Auth via the default AWS credential chain (profile, env vars, IMDS). No local weights needed. |
208209
| 2 | `CODEHUB_EMBEDDING_URL` + `CODEHUB_EMBEDDING_MODEL` | **HTTP (OpenAI-compatible)** — POSTs to a `/v1/embeddings` server (Infinity, vLLM, TEI, Ollama, LM Studio, OpenAI). Bearer auth optional via `CODEHUB_EMBEDDING_API_KEY`. |
209210
| 3 | *(nothing set)* | **Local ONNX** — deterministic, offline-safe. Requires `codehub setup --embeddings` to download the weights. |
210211

211212
**SageMaker-specific vars**:
212213

213214
| Var | Default | Purpose |
214215
|---|---|---|
215-
| `CODEHUB_EMBEDDING_SAGEMAKER_ENDPOINT` | *(required to select)* | Endpoint name (e.g. `gte-modernbert-embed`). |
216+
| `CODEHUB_EMBEDDING_SAGEMAKER_ENDPOINT` | *(required to select)* | Endpoint name (e.g. `F2LLM-v2-80M`). |
216217
| `CODEHUB_EMBEDDING_SAGEMAKER_REGION` | `us-east-1` | AWS region. |
217-
| `CODEHUB_EMBEDDING_DIMS` | `768` | Expected vector dimension — asserted on every response to catch model-swap drift. |
218-
| `CODEHUB_EMBEDDING_MODEL` | `gte-modernbert-base/sagemaker:<endpoint-name>` | Stable modelId stamp recorded in index metadata. Override only when bridging a non-gte endpoint. |
218+
| `CODEHUB_EMBEDDING_DIMS` | `320` | Expected vector dimension — asserted on every response to catch model-swap drift. |
219+
| `CODEHUB_EMBEDDING_MODEL` | `F2LLM-v2-80M/sagemaker:<endpoint-name>` | Stable modelId stamp recorded in index metadata. Override only when bridging a non-F2LLM endpoint. |
219220

220221
IAM: the caller needs `sagemaker:InvokeEndpoint` on the endpoint ARN —
221-
e.g. `arn:aws:sagemaker:us-east-1:<account>:endpoint/gte-modernbert-embed`.
222+
e.g. `arn:aws:sagemaker:us-east-1:<account>:endpoint/F2LLM-v2-80M`.
222223

223224
**Do not mix backends against the same index.** Backends are pinned to a
224225
single model identity via the `modelId` stamp in the `embeddings` table;
225226
switching mid-project requires `codehub analyze --rebuild-embeddings`.
226227
`--offline` refuses SageMaker and HTTP backends, so offline mode is
227228
compatible only with the local ONNX path.
228229

229-
## Storage backend — lbug graph + DuckDB temporal
230-
231-
The graph tier is always `@ladybugdb/core` (`<repo>/.codehub/graph.lbug`);
232-
the temporal tier — cochanges, structured symbol summaries, and the
233-
`codehub query --sql` escape hatch — is always DuckDB
234-
(`<repo>/.codehub/temporal.duckdb`). Both files are written on every
235-
`analyze`. There is no `CODEHUB_STORE` env var, no backend probe, no
236-
single-file `graph.duckdb` layout, and no mtime arbitration; if the lbug
237-
binding fails to load, `open()` throws `GraphDbBindingError` and the
238-
operation aborts.
239-
240-
`IGraphStore` lives only on `GraphDbStore`; `DuckDbStore` implements
241-
`ITemporalStore` only. The segregated interfaces stay because they are
242-
the v1.0 contract for community-fork adapters (AGE / Memgraph / Neo4j /
243-
Neptune target `IGraphStore`; DuckDB owns `ITemporalStore`). Embeddings
244-
live in `graph.lbug` and stream into a per-call DuckDB temp table at
245-
pack time so the byte-identical Parquet sidecar still works.
246-
247-
See [`docs/adr/0016-duckdb-graph-rip.md`](./docs/adr/0016-duckdb-graph-rip.md)
248-
for the rationale behind ripping out the DuckDB graph backend; it
249-
supersedes ADR 0013 and the DuckDB-as-graph passages of ADR 0011.
230+
## Storage backend — single-file SQLite
231+
232+
The entire index lives in ONE `<repo>/.codehub/store.sqlite` file (WAL),
233+
via Node's built-in `node:sqlite` — graph nodes, edges, embeddings, the
234+
FTS5 BM25 table, and the temporal tables (cochanges, symbol summaries, the
235+
`codehub query --sql` escape hatch). One `SqliteStore` class implements
236+
**both** `IGraphStore` and `ITemporalStore`; `openStore()` returns that
237+
single instance as both the `graph` and `temporal` views, so call sites use
238+
`store.graph.X()` / `store.temporal.Y()` unchanged. **Zero native storage
239+
bindings**`@ladybugdb/core` and `@duckdb/node-api` are both gone, so
240+
there is no `GraphDbBindingError`, no backend probe, and no platform-prebuild
241+
matrix.
242+
243+
The segregated `IGraphStore` / `ITemporalStore` interfaces stay as the
244+
community-fork escape hatch (AGE / Memgraph / Neo4j / Neptune) — a fork
245+
implements both, on one class or split. Install is zero-native-dep:
246+
`npm i -g @opencodehub/cli` + Node ≥ 24.15, no Docker, no postinstall
247+
compile. (`onnxruntime-web`, the optional WASM embedder, is the only native
248+
dependency — lazy-loaded under `--embeddings`.)
249+
250+
See [`docs/adr/0019-single-file-sqlite-storage.md`](./docs/adr/0019-single-file-sqlite-storage.md)
251+
for the rationale; it supersedes [ADR 0016](./docs/adr/0016-duckdb-graph-rip.md)
252+
(and, transitively, the native-binding storage of ADRs 0011 / 0013 / 0001).
250253

251254
## Parse runtime — WASM-only, vendored grammars
252255

253256
`@opencodehub/ingestion` runs `web-tree-sitter` (WASM) as the only parse
254257
runtime on the supported Node range (22 and 24). There is no native opt-in:
255258
the native `tree-sitter` N-API addon and all 14 `tree-sitter-<lang>` npm
256259
packages are gone from the install graph, so parsing pulls **zero native
257-
builds and zero GitHub fetches** at install time. (Storage and embeddings
258-
load prebuilt native bindings — see Platform support.)
260+
builds and zero GitHub fetches** at install time. (Storage is pure
261+
`node:sqlite`; the only optional native dep is the WASM embedder — see
262+
Platform support.)
259263

260264
All 15 grammar `.wasm` blobs are vendored at
261265
`packages/ingestion/vendor/wasms/`, built from the grammar sources

SPECS.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ first 14 plus a regex provider for fixed-format COBOL, runs SCIP indexers
1717
for TypeScript/JavaScript, Python, Go, Rust, and Java to upgrade tree-sitter
1818
heuristic edges to compiler-grade edges, clusters the graph into
1919
Communities and Processes, and optionally populates embeddings from a
20-
pinned gte-modernbert-base ONNX model (fp32 ~596 MB or int8 ~150 MB) or
20+
pinned F2LLM-v2-80M ONNX model (320-dim; fp32 ~321 MB or int8 ~81 MB) or
2121
an OpenAI-compatible HTTP endpoint.
2222

2323
At query time it exposes an MCP server with 28 tools (`query`, `context`,
@@ -171,7 +171,7 @@ last-analyzed commit) atomically and expose it via `getMeta`.
171171
BM25 + ANN search, fuse results with reciprocal rank fusion (`DEFAULT_RRF_K`),
172172
and return symbols grouped by their participating `Process`.
173173

174-
4.2 Where gte-modernbert-base weights are absent and no HTTP embedder is
174+
4.2 Where F2LLM-v2-80M weights are absent and no HTTP embedder is
175175
configured, the system shall fall back to BM25-only search and log a
176176
one-shot `[mcp] hybrid:` warning to stderr.
177177

@@ -264,8 +264,9 @@ and `sql`.
264264
claude-code, cursor, codex, windsurf, and opencode; pass `--undo` to
265265
restore the most recent `.bak`.
266266

267-
7.4 The `setup --embeddings` command shall download gte-modernbert-base
268-
weights (fp32 or int8) with SHA256 pins validated against
267+
7.4 The `setup --embeddings` command shall download the F2LLM-v2-80M
268+
ONNX export (fp32 or int8) — a custom-exported artifact hosted as a
269+
GitHub release asset — with SHA256 pins validated against
269270
`model-pins.ts`.
270271

271272
7.5 The `setup --plugin` command shall copy the bundled plugin into

docs/adr/0001-storage-backend.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
# ADR 0001 — Storage backend selection
22

3-
Status: **Accepted (superseded prior SQLite recommendation)** — 2026-04-18
3+
Status: **Superseded** — current storage is [ADR 0019 — Single-file SQLite
4+
storage](./0019-single-file-sqlite-storage.md) (2026-06-22). This ADR
5+
selected **DuckDB** as the embedded backend; that decision was unwound over
6+
[ADR 0011](./0011-graph-db-backend.md)[ADR 0013-m7](./0013-m7-default-flip-and-abstraction.md)
7+
[ADR 0016](./0016-duckdb-graph-rip.md) → ADR 0019, which lands on one
8+
`store.sqlite` file (Node built-in `node:sqlite`, **zero** native storage
9+
bindings — DuckDB included). Ironically ADR 0019 returns to the SQLite
10+
recommendation this ADR originally rejected. Read this ADR for the original
11+
license/determinism/binding-availability criteria only; the chosen engine is
12+
obsolete.
13+
14+
> Originally: **Accepted (superseded prior SQLite recommendation)** — 2026-04-18
415
516
## Context
617

docs/adr/0011-graph-db-backend.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# ADR 0011 — Graph-DB backend (LadybugDB phase-1)
22

3-
- Status: **Partially superseded** by [ADR 0016](./0016-duckdb-graph-rip.md)
4-
on 2026-05-16. The "DuckDB-default plus LadybugDB opt-in" framing is
5-
obsolete; lbug is the unconditional graph backend after the rip. The
6-
LadybugDB integration shape and `IGraphStore` design introduced here
7-
are unchanged.
3+
- Status: **Superseded** — current storage is [ADR 0019 — Single-file
4+
SQLite storage](./0019-single-file-sqlite-storage.md) (2026-06-22).
5+
Chain: this ADR (LadybugDB phase-1) → [ADR 0016](./0016-duckdb-graph-rip.md)
6+
(lbug-only graph, made the "DuckDB-default + LadybugDB opt-in" framing
7+
obsolete, 2026-05-16) → ADR 0019 (one `store.sqlite`, NO native bindings —
8+
`@ladybugdb/core` itself is now gone). The `IGraphStore` design introduced
9+
here survives ADR 0019 as a community-fork escape hatch; the LadybugDB
10+
binding does not. Read this ADR for historical rationale only.
811
- Was: **Accepted** on 2026-05-05 and flipped on the M3 merge.
912
- Authors: Laith Al-Saadoon + Claude.
1013
- Branch: `feat/v1-m3-m4`.

docs/adr/0013-m7-default-flip-and-abstraction.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@
55
> in-tree because they were authored in parallel branches and accepted
66
> on the same release. The next ADR uses 0014.
77
8-
- Status: **Superseded** by [ADR 0016](./0016-duckdb-graph-rip.md)
9-
on 2026-05-16. The auto-probe, dual-artifact arbitration, and
10-
`CODEHUB_STORE` resolver introduced here are gone. lbug is the only
11-
graph backend; DuckDB serves the temporal tier. The
12-
IGraphStore/ITemporalStore segregation survives because community
13-
adapters (AGE, Memgraph, Neo4j, Neptune) target it.
8+
- Status: **Superseded** — current storage is [ADR 0019 — Single-file
9+
SQLite storage](./0019-single-file-sqlite-storage.md) (2026-06-22).
10+
Chain: this ADR → [ADR 0016](./0016-duckdb-graph-rip.md) (2026-05-16,
11+
removed the auto-probe / dual-artifact arbitration / `CODEHUB_STORE`
12+
resolver introduced here) → ADR 0019 (one `store.sqlite`, no native
13+
bindings). The IGraphStore/ITemporalStore segregation introduced here
14+
survives all the way to ADR 0019 as the community-fork escape hatch
15+
(AGE, Memgraph, Neo4j, Neptune); everything else here is historical.
1416
- Was: **Accepted** on 2026-05-09 and flipped on the
1517
`feat/v1-finalize-track-a` merge (PR #71).
1618
- Authors: Laith Al-Saadoon + Claude.

docs/adr/0014-scip-references-and-embedder-fingerprint.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
# ADR 0014 — SCIP REFERENCES + TYPE_OF emission and embedder-fingerprint refusal
22

3-
**Status**: Accepted
3+
**Status**: Accepted (still in force)
44
**Date**: 2026-05-09
55
**Supersedes**: none
66
**Superseded by**: none
77

8+
> Note (2026-06-26): the embedder-fingerprint mechanism this ADR introduced
9+
> — persist `embedder_model_id`, refuse mismatched queries via
10+
> `assertEmbedderCompatible` — is unchanged and is precisely what guards the
11+
> later embedding-model swap from `gte-modernbert-base` (768-dim) to
12+
> `F2LLM-v2-80M` (320-dim). The `gte-modernbert-base` / `768` references
13+
> below are the contemporaneous examples; the dim/model are now 320 /
14+
> `f2llm-v2-80m/*` but the decision and the comparator are identical. The
15+
> `store_meta` storage substrate referenced here (DuckDB) was later replaced
16+
> per [ADR 0019](./0019-single-file-sqlite-storage.md); the column and
17+
> semantics carried over to `store.sqlite` verbatim.
18+
819
## Context
920

1021
Two unrelated holes in v1.0 finalize, both routing through a shared one-time graphHash content delta. They land in a single ADR per spec.md§Q7 because the fixture-regeneration cost is paid once.

docs/adr/0016-duckdb-graph-rip.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
# ADR 0016 — Rip out the DuckDB graph backend; lbug-only graph, DuckDB temporal-only
22

3-
- Status: **Accepted** — 2026-05-16.
3+
- Status: **Superseded** by [ADR 0019 — Single-file SQLite storage](./0019-single-file-sqlite-storage.md)
4+
on 2026-06-22, **in its entirety**. ADR 0019 removed BOTH native bindings
5+
this ADR settled on (`@ladybugdb/core` for the graph tier and
6+
`@duckdb/node-api` for the temporal tier) and replaced the pair with one
7+
`store.sqlite` file via Node's built-in `node:sqlite`. The segregated
8+
`IGraphStore` / `ITemporalStore` interfaces this ADR preserved for
9+
community forks survive — both are now implemented by a single
10+
`SqliteStore` class. Read this ADR only for the historical rationale of
11+
the lbug-graph / DuckDB-temporal split; **do not** treat its decision as
12+
current.
13+
- Was: **Accepted** — 2026-05-16.
414
- Authors: Laith Al-Saadoon + Claude.
515
- Branch: `feat/duckdb-graph-rip`.
616
- Supersedes: [ADR 0013 — M7 default flip and storage abstraction](./0013-m7-default-flip-and-abstraction.md)

0 commit comments

Comments
 (0)