diff --git a/.changeset/coalesce-replay-scope-docs.md b/.changeset/coalesce-replay-scope-docs.md deleted file mode 100644 index 0baf55ce..00000000 --- a/.changeset/coalesce-replay-scope-docs.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@nicia-ai/typegraph": patch ---- - -Docs: scope the `coalesceUnchangedUpserts` benefit correctly. Coalescing -eliminates _re-delivery_ churn (an already-applied change delivered again, -value-identical to the live row). It does not make a full replay-from-zero -free when the stream supersedes values in place: re-applying an older value -over the live row is a genuine change, and restoring the current value -afterwards is another, so such a replay still writes — and leaves a spurious -back-and-forth band in the live store's recorded history. Churn-free rebuilds -replay into a fresh store instead. Clarified in the option's TSDoc and in the -"Materializing external event logs" guide; no behavior change. diff --git a/.changeset/marker-gated-vector-storage.md b/.changeset/marker-gated-vector-storage.md deleted file mode 100644 index 7c36bd93..00000000 --- a/.changeset/marker-gated-vector-storage.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -"@nicia-ai/typegraph": minor ---- - -Vector storage now rides the #135 durable-contribution machinery, so the -runtime never issues DDL on the embedding hot path. - -Previously every vector op (`upsertEmbedding` / `deleteEmbedding` / -`vectorSearch` / `createVectorIndex`) lazily ran `CREATE TABLE IF NOT EXISTS` -for its per-`(kind, field)` table on whatever connection it executed on. On a -least-privilege Postgres role (USAGE on `public`, full DML, but no `CREATE`) -this failed with `permission denied for schema public` (SQLSTATE 42501) — even -when the table already existed, because Postgres runs the schema aclcheck before -the `IF NOT EXISTS` short-circuit. The fulltext path already avoided this via -durable markers; vectors now do too. - -What changed: - -- **Boot (privileged):** `createStoreWithSchema` provisions every embedding - `(kind, field)` table + a durable contribution marker, enumerated from the - graph. `evolve()` provisions any embedding fields it introduces. A slot - already provisioned at a *different* shape (the declared dimension changed) - is warned about and left untouched — boot stays reachable so - `store.reembedVectorField()` can recreate it; until then, writes to that - field fail with a `stale` `StoreNotInitializedError` that points at - `reembedVectorField`. -- **Runtime writes (DML-only):** `upsertEmbedding` (single and batch) and - `deleteEmbedding` assert the durable marker with a cached, signature-checked - SELECT and run DML — never DDL. `createVerifiedStore` verifies vector markers - at attach, alongside fulltext. -- **Vector reads are not marker-gated:** `store.search.vector`, - `store.search.hybrid`, and query-builder `.similarTo()` predicates compile to - SQL against the per-field table directly (searches may override the metric at - query time, so their slot legitimately differs from the provisioned shape); - against an un-provisioned database they surface the engine's missing-relation - error, which `createVerifiedStore` catches at attach. -- `reembedVectorField` re-stamps the marker after recreating storage at a new - dimension; vector-field reclaim (`materializeRemovals`) clears the marker when - it drops a table. - -**Breaking:** vector ops now require a prior privileged `createStoreWithSchema` -(exactly as fulltext already does). A plain `createStore` + embedding write with -no provisioning step throws `StoreNotInitializedError` instead of lazily -creating the table. - -**Migration:** after upgrading, run `createStoreWithSchema(graph, adminBackend)` -once under the schema-owner role. It creates the per-field vector tables + -markers; least-privilege runtimes then assert markers (SELECT) and run vector -DML with zero DDL — no `GRANT CREATE` required. - -Consumers that boot manually (raw DDL + the sync `createStore` attach + -`backend.ensureRuntimeContributions`) provision vectors the same way: the new -`resolveGraphVectorSlots(graph)` export enumerates every embedding -`(kind, field)` slot, and `backend.ensureVectorSlotContribution(slot)` -materializes each — the exact step `createStoreWithSchema` performs. Batch -counterparts (`backend.ensureVectorSlotContributions(slots)` / -`backend.assertVectorSlotsInitialized(slots)`) resolve every slot's markers -with one graph-scoped query — what boot and verified attach use, and the -right choice for many embedding fields over a remote connection. diff --git a/.changeset/set-based-graph-traversal.md b/.changeset/set-based-graph-traversal.md deleted file mode 100644 index 8c3ed7b2..00000000 --- a/.changeset/set-based-graph-traversal.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@nicia-ai/typegraph": patch ---- - -Replace path-enumerating recursive CTEs in `reachable`, `neighbors`, -`shortestPath`, and `canReach` with set-based breadth-first search. - -Transactional SQLite and PostgreSQL backends now execute graph iterations -against a connection-local temporary working table, de-duplicated by node kind -and ID on every round. Non-transactional backends retain parity through a -bind-limit-aware inline frontier. Traversals run in one snapshot where the -backend supports transactions, preserve temporal filtering, and clean up -temporary state on success or failure. diff --git a/.changeset/trusted-initial-import.md b/.changeset/trusted-initial-import.md deleted file mode 100644 index 05ca194b..00000000 --- a/.changeset/trusted-initial-import.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@nicia-ai/typegraph": minor ---- - -Add `trustedImportGraph` and `trustedImportGraphStream` for atomic initial loads -into a fresh, dedicated database. The distinct trusted surface bypasses schema, -reference, cardinality, and conflict validation; uses prepared SQLite writes or -PostgreSQL `UNNEST` ingestion; defers rebuildable secondary indexes; refreshes -planner statistics; and rolls the complete stream back on any failure. - -The first version rejects non-empty TypeGraph data tables, recorded history, -revision tracking, uniqueness constraints, searchable fields, vector fields, -and backends without the required native transactional path. diff --git a/packages/typegraph/CHANGELOG.md b/packages/typegraph/CHANGELOG.md index 79344fd6..498e0fc5 100644 --- a/packages/typegraph/CHANGELOG.md +++ b/packages/typegraph/CHANGELOG.md @@ -1,5 +1,97 @@ # @nicia-ai/typegraph +## 0.37.0 + +### Minor Changes + +- [#269](https://github.com/nicia-ai/typegraph/pull/269) [`92479d4`](https://github.com/nicia-ai/typegraph/commit/92479d44ba7f0fc76985d51174cb9801c055fd4d) Thanks [@pdlug](https://github.com/pdlug)! - Vector storage now rides the [#135](https://github.com/nicia-ai/typegraph/issues/135) durable-contribution machinery, so the + runtime never issues DDL on the embedding hot path. + + Previously every vector op (`upsertEmbedding` / `deleteEmbedding` / + `vectorSearch` / `createVectorIndex`) lazily ran `CREATE TABLE IF NOT EXISTS` + for its per-`(kind, field)` table on whatever connection it executed on. On a + least-privilege Postgres role (USAGE on `public`, full DML, but no `CREATE`) + this failed with `permission denied for schema public` (SQLSTATE 42501) — even + when the table already existed, because Postgres runs the schema aclcheck before + the `IF NOT EXISTS` short-circuit. The fulltext path already avoided this via + durable markers; vectors now do too. + + What changed: + + - **Boot (privileged):** `createStoreWithSchema` provisions every embedding + `(kind, field)` table + a durable contribution marker, enumerated from the + graph. `evolve()` provisions any embedding fields it introduces. A slot + already provisioned at a _different_ shape (the declared dimension changed) + is warned about and left untouched — boot stays reachable so + `store.reembedVectorField()` can recreate it; until then, writes to that + field fail with a `stale` `StoreNotInitializedError` that points at + `reembedVectorField`. + - **Runtime writes (DML-only):** `upsertEmbedding` (single and batch) and + `deleteEmbedding` assert the durable marker with a cached, signature-checked + SELECT and run DML — never DDL. `createVerifiedStore` verifies vector markers + at attach, alongside fulltext. + - **Vector reads are not marker-gated:** `store.search.vector`, + `store.search.hybrid`, and query-builder `.similarTo()` predicates compile to + SQL against the per-field table directly (searches may override the metric at + query time, so their slot legitimately differs from the provisioned shape); + against an un-provisioned database they surface the engine's missing-relation + error, which `createVerifiedStore` catches at attach. + - `reembedVectorField` re-stamps the marker after recreating storage at a new + dimension; vector-field reclaim (`materializeRemovals`) clears the marker when + it drops a table. + + **Breaking:** vector ops now require a prior privileged `createStoreWithSchema` + (exactly as fulltext already does). A plain `createStore` + embedding write with + no provisioning step throws `StoreNotInitializedError` instead of lazily + creating the table. + + **Migration:** after upgrading, run `createStoreWithSchema(graph, adminBackend)` + once under the schema-owner role. It creates the per-field vector tables + + markers; least-privilege runtimes then assert markers (SELECT) and run vector + DML with zero DDL — no `GRANT CREATE` required. + + Consumers that boot manually (raw DDL + the sync `createStore` attach + + `backend.ensureRuntimeContributions`) provision vectors the same way: the new + `resolveGraphVectorSlots(graph)` export enumerates every embedding + `(kind, field)` slot, and `backend.ensureVectorSlotContribution(slot)` + materializes each — the exact step `createStoreWithSchema` performs. Batch + counterparts (`backend.ensureVectorSlotContributions(slots)` / + `backend.assertVectorSlotsInitialized(slots)`) resolve every slot's markers + with one graph-scoped query — what boot and verified attach use, and the + right choice for many embedding fields over a remote connection. + +- [#273](https://github.com/nicia-ai/typegraph/pull/273) [`42f6941`](https://github.com/nicia-ai/typegraph/commit/42f6941fdb601629c0f45ec54fa9f3e50bd028ae) Thanks [@pdlug](https://github.com/pdlug)! - Add `trustedImportGraph` and `trustedImportGraphStream` for atomic initial loads + into a fresh, dedicated database. The distinct trusted surface bypasses schema, + reference, cardinality, and conflict validation; uses prepared SQLite writes or + PostgreSQL `UNNEST` ingestion; defers rebuildable secondary indexes; refreshes + planner statistics; and rolls the complete stream back on any failure. + + The first version rejects non-empty TypeGraph data tables, recorded history, + revision tracking, uniqueness constraints, searchable fields, vector fields, + and backends without the required native transactional path. + +### Patch Changes + +- [#265](https://github.com/nicia-ai/typegraph/pull/265) [`35ab2a0`](https://github.com/nicia-ai/typegraph/commit/35ab2a02af728df9059750518ddbdd12e489450e) Thanks [@pdlug](https://github.com/pdlug)! - Docs: scope the `coalesceUnchangedUpserts` benefit correctly. Coalescing + eliminates _re-delivery_ churn (an already-applied change delivered again, + value-identical to the live row). It does not make a full replay-from-zero + free when the stream supersedes values in place: re-applying an older value + over the live row is a genuine change, and restoring the current value + afterwards is another, so such a replay still writes — and leaves a spurious + back-and-forth band in the live store's recorded history. Churn-free rebuilds + replay into a fresh store instead. Clarified in the option's TSDoc and in the + "Materializing external event logs" guide; no behavior change. + +- [#274](https://github.com/nicia-ai/typegraph/pull/274) [`2a889aa`](https://github.com/nicia-ai/typegraph/commit/2a889aaea095a842fdd6f1b4a97feba5e6026d82) Thanks [@pdlug](https://github.com/pdlug)! - Replace path-enumerating recursive CTEs in `reachable`, `neighbors`, + `shortestPath`, and `canReach` with set-based breadth-first search. + + Transactional SQLite and PostgreSQL backends now execute graph iterations + against a connection-local temporary working table, de-duplicated by node kind + and ID on every round. Non-transactional backends retain parity through a + bind-limit-aware inline frontier. Traversals run in one snapshot where the + backend supports transactions, preserve temporal filtering, and clean up + temporary state on success or failure. + ## 0.36.0 ### Minor Changes diff --git a/packages/typegraph/package.json b/packages/typegraph/package.json index f8c35eac..cb99b897 100644 --- a/packages/typegraph/package.json +++ b/packages/typegraph/package.json @@ -1,6 +1,6 @@ { "name": "@nicia-ai/typegraph", - "version": "0.36.0", + "version": "0.37.0", "description": "TypeScript-first embedded knowledge graph library with ontological reasoning", "type": "module", "main": "./dist/index.cjs",