Skip to content

Commit 6189b56

Browse files
committed
Use DATABASE_URL and rename Postgres schema knowledge → memory
Hosts pass memory.databaseUrl or DATABASE_URL (same Postgres as the hub is fine); tables live under the memory schema. KNOWLEDGE_DATABASE_URL remains a deprecated alias. Fresh installs only for the schema rename.
1 parent bbc5b1a commit 6189b56

28 files changed

Lines changed: 211 additions & 145 deletions

‎AGENTS.md‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ port, or process entrypoint here, and there never should be.
1111
bun install # Bun 1.2+ required
1212
bun run typecheck # tsc --noEmit
1313
bun run test # bun test ./src (no network, no Postgres)
14-
bun run db:setup # apply migrations (needs KNOWLEDGE_DATABASE_URL)
14+
bun run db:setup # apply migrations (needs DATABASE_URL)
1515
docker compose up -d # local pgvector + model endpoints for manual runs
1616
```
1717

@@ -28,7 +28,7 @@ CI runs `typecheck` + `test` — both must pass before any push.
2828
- `src/services/` — capture / search / transform internals (not public verbs)
2929
- `src/ports/` — `DocumentStore` / `SourceProvider` + fakes
3030
- `src/core/` — embed/rerank clients, merge, arktype schemas
31-
- `src/db/` + `migrations/` — Drizzle schema + SQL migrations (pgvector, `knowledge.*`)
31+
- `src/db/` + `migrations/` — Drizzle schema + SQL migrations (pgvector, `memory.*`)
3232
- `packages/` — removed; DocumentStore adapters and Linear tools are sibling packages
3333
(`@corbits/mem0-memory-adapter`, `@corbits/supermemory-memory-adapter`,
3434
`@corbits/linear-tools`).
@@ -38,10 +38,11 @@ CI runs `typecheck` + `test` — both must pass before any push.
3838
1. **Authenticate nothing.** Identity is `c.get("principal")` from the
3939
Interchange context; authorization goes through the host's grant store
4040
(`@intx/authz`). Never add API keys, sessions, or OAuth here.
41-
2. **One Postgres**: `KNOWLEDGE_DATABASE_URL`, the engine's own vector plane.
42-
There is deliberately no `DATABASE_URL` fallback — the host's control-plane
43-
DB is never ours. No foreign keys into control-plane tables; cross-refs
44-
(`tenant_id`, `principal_id`) are plain `text`.
41+
2. **One Postgres connection, own schema.** Pass `memory.databaseUrl` (or env
42+
`DATABASE_URL`; deprecated alias `KNOWLEDGE_DATABASE_URL`). Tables live under
43+
the **`memory`** schema — never `public`. Cross-refs (`tenant_id`,
44+
`principal_id`) are plain `text` (no FKs into control-plane tables). Same
45+
Postgres instance as the host is fine; schema isolation is the boundary.
4546
3. **Never embed in-process.** Embedding/reranking are outbound HTTP calls to
4647
configured endpoints. A model endpoint is a trusted URL, same as the
4748
database URL — no self-host flags, no SSRF filtering here.

‎ARCHITECTURE.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ plane and the protected routes that read and write it.
99
The store was detachable from a larger backend, then mountable:
1010

1111
- No memory table has a foreign key into any control-plane table — cross-refs
12-
(`tenant_id`, `principal_id`, source refs) are plain `text`.
12+
(`tenant_id`, `principal_id`, source refs) are plain `text`. Tables live in
13+
the **`memory`** schema (same Postgres URL as the host is fine).
1314
- Embedding and reranking go out as plain HTTP to configured model endpoints.
1415
- Document access is Interchange grant tags on the row (`accessTags` + creator),
1516
not a private ACL engine inside this package.
@@ -32,8 +33,9 @@ config (or an injected store).
3233

3334
## Boundaries
3435

35-
- **Runtime**: Bun + Hono, mounted on the host app. **DB**: own pgvector
36-
Postgres (`KNOWLEDGE_DATABASE_URL`) unless `documentStore` is injected.
36+
- **Runtime**: Bun + Hono, mounted on the host app. **DB**: Postgres via
37+
passed `databaseUrl` / `DATABASE_URL` (`memory.*` schema) unless
38+
`documentStore` is injected.
3739
**Types**: arktype at every route boundary.
3840
- **No auth of its own.** Interchange resolves the caller and puts `principal`
3941
+ `tenant` on context; routes read identity from there

‎CHANGELOG.md‎

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
### Added
10+
### Changed
1111

12+
- **Breaking:** Postgres schema renamed from `knowledge` to **`memory`**. Fresh
13+
installs only — drop/recreate the old schema (or rename) on existing DBs.
14+
Citation `open.type` is now `"memory"`.
15+
- **Breaking:** env `KNOWLEDGE_DATABASE_URL` is no longer required. Prefer
16+
`DATABASE_URL` or pass `memory.databaseUrl` on config.
17+
`KNOWLEDGE_DATABASE_URL` remains a deprecated alias.
1218
- Interchange `defineTool` factories at `@corbits/memory/tools` (`memory_add`,
1319
`memory_search`, `memory_list`) — HTTP clients for mounted hub routes with
1420
install env `memoryBaseUrl` / `memoryTenantId` / `memoryAuthToken`. Declared
1521
via `package.json` `interchange.tools` and `exports["./tools"]`.
1622

17-
### Changed
23+
### Previously
1824

1925
- **Breaking:** package and public surface renamed from `@corbits/knowledge-engine`
2026
to `@corbits/memory`. Public APIs: `createMemory` (optional `app` registers HTTP),
@@ -24,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2430
`MemoryConfig`, `MemoryError`. HTTP paths are under
2531
`/api/tenants/:tenantId/memory/`; grants are
2632
`memory:add` / `memory:search`; access tags use `memory.owner:` / `memory.tenant:`
27-
/ `memory.space:`. Postgres schema name remains `knowledge`.
33+
/ `memory.space:`.
2834
- **Breaking:** memory plane surface is `add` / `search` / `list` with
2935
`principalId` + `tenantId` only. Inference is host-owned (no answer endpoint
3036
or personal-memory side-channel on the plane).

‎IMPLEMENTATION.md‎

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ src/
2424
deps.ts # RouteDeps, caller(c) (context identity), grantGuard
2525
add.ts, search.ts, list.ts
2626
db/
27-
schema.ts # Drizzle table defs (knowledge.* schema)
27+
schema.ts # Drizzle table defs (memory.* schema)
2828
client.ts # createDb(config) -> { db (drizzle), sql (raw postgres-js) }
2929
services/
3030
capture.ts # captureDocument, deriveFromRawCapture — the write path
@@ -75,7 +75,9 @@ fallback)` parses a positive integer or throws.
7575

7676
| Var | Required? | Default | Notes |
7777
|---|---|---|---|
78-
| `KNOWLEDGE_DATABASE_URL` | **yes** | — | the engine's own pgvector Postgres |
78+
| `DATABASE_URL` | **yes*** | — | Postgres for the memory plane (`memory.*` schema). Same DB as host is fine. |
79+
| `KNOWLEDGE_DATABASE_URL` | no | — | **Deprecated** alias for `DATABASE_URL` |
80+
7981
| `DB_POOL_MAX` | no | `8` | postgres-js pool size |
8082
| `FTS_LANGUAGE` | no | `english` | text search config for the lexical channel; fixed into the generated column at migration time — changing it later requires rebuilding the column (recipe below), and `runMemoryMigrations` fails loudly if config and column disagree. Unqualified `pg_catalog` config names only — a schema-qualified config (`myschema.mycfg`) is rejected explicitly, both when configuring and when read back from an already-migrated column. |
8183
| `EMBED_BASE_URL` | **yes** | — | embed endpoint root, no path suffix |
@@ -207,7 +209,7 @@ migration CHECK sets match the TS constants.
207209

208210
### Provenance and lineage (claim-bearing substrate)
209211

210-
Two axes on `knowledge.version`, orthogonal to ranking priors:
212+
Two axes on `memory.version`, orthogonal to ranking priors:
211213

212214
| Column / field | Values | Meaning |
213215
| --- | --- | --- |
@@ -220,7 +222,7 @@ A derived claim is a normal version with `provenance: inferred`, `lineageClass:
220222

221223
### Temporal model
222224

223-
See `docs/TEMPORAL.md`. On `knowledge.version`:
225+
See `docs/TEMPORAL.md`. On `memory.version`:
224226

225227
| Column | Role |
226228
| --- | --- |
@@ -471,7 +473,7 @@ search); otherwise it throws `MemorySearchInputError` (400).
471473
entity edges; `toHit` builds the wire `SearchHit` (citation/open-target
472474
resolution via `openTarget`, mapping known adapters — `artifact`, `task`,
473475
`workflow_run`, `mail` — to a deep-linkable `{type, id}`, else a generic
474-
`{type: "knowledge", id: documentId}`).
476+
`{type: "memory", id: documentId}`).
475477
11. **Evidence** — `deriveHybridEvidence`: `"none"` if zero hits; `"weak"` if
476478
the lexical channel contributed zero rows (a dense-only result never
477479
reports `"strong"`); otherwise `deriveEvidence` on the lexical rows —
@@ -599,7 +601,7 @@ Document access is Interchange authz — **not** a mini-ACL.
599601

600602
- Write path: `resolveAccessTags` always writes `memory.owner:<caller>` and
601603
merges optional `accessTags` / share sugar (`tenant`, peer `principals`,
602-
explicit `tags`). Stored on `knowledge.document.access_tags`.
604+
explicit `tags`). Stored on `memory.document.access_tags`.
603605
- Read path (search + list): `canAccessDocument` — creator always allowed;
604606
otherwise `authorize(grantStore, principal, tenant, tag, "search")` for any
605607
tag on the document.
@@ -625,15 +627,15 @@ docker compose up -d # pgvector + Ollama + rer
625627
docker compose exec ollama ollama pull nomic-embed-text
626628
cp .env.example .env
627629
bun install
628-
bun run db:setup # apply the knowledge schema, idempotent
630+
bun run db:setup # apply the memory schema, idempotent
629631
bun run test # unit suite (no external services)
630632
```
631633

632634
`compose.yml` provisions the pgvector Postgres (`knowledge` db, host port
633635
`5434`), an Ollama embeddings server (`:11434`), and a TEI reranker (`:8085`).
634636
The engine **never embeds internally** — `EMBED_BASE_URL` must point at a real
635637
endpoint. A model endpoint is just a URL + capability options, trusted the same
636-
as `KNOWLEDGE_DATABASE_URL`:
638+
as `DATABASE_URL`:
637639

638640
- **Local default**: Ollama at `http://localhost:11434`
639641
(`EMBED_API_STYLE=ollama`, `EMBED_MODEL=nomic-embed-text`).

‎PRODUCT.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,9 @@ stores, Linear tools. Core never imports vendor SDKs.
7777
- No answer/generation endpoint — host owns inference.
7878
- Workbench is a client, not required.
7979

80-
**Default durable store:** Postgres via `KNOWLEDGE_DATABASE_URL` only (no
81-
`DATABASE_URL` fallback), tables under the **`knowledge`** schema. When
80+
**Default durable store:** Postgres via `DATABASE_URL` (or passed
81+
`memory.databaseUrl`; deprecated alias `KNOWLEDGE_DATABASE_URL`), tables under
82+
the **`memory`** schema. When
8283
`documentStore` is injected, Postgres is not opened. Cross-refs are plain
8384
`text` — no FKs into the host control plane.
8485

‎README.md‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ import { createMemory, loadMemoryConfig } from "@corbits/memory";
3333

3434
const memory = createMemory({
3535
app,
36-
config: loadMemoryConfig(), // KNOWLEDGE_DATABASE_URL + embed env
36+
config: loadMemoryConfig(), // DATABASE_URL + embed env
37+
3738
grantStore,
3839
conditionRegistry,
3940
});
@@ -124,11 +125,12 @@ always sees their own docs. Details:
124125
## Config
125126

126127
`loadMemoryConfig()` reads env (see `.env.example`). For the default pgvector
127-
store you need `KNOWLEDGE_DATABASE_URL`, `EMBED_BASE_URL`, `EMBED_MODEL`.
128+
store you need `DATABASE_URL`, `EMBED_BASE_URL`, `EMBED_MODEL`.
128129

129130
```ts
130131
import { runMemoryMigrations } from "@corbits/memory/migrations";
131-
await runMemoryMigrations(process.env.KNOWLEDGE_DATABASE_URL!);
132+
await runMemoryMigrations(process.env.DATABASE_URL!);
133+
132134
```
133135

134136
Inject `documentStore` to use fakes, a host store, or a sibling adapter instead

‎docs/TEMPORAL.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Temporal model
22

3-
How `knowledge.version` times and ranking classes work. Implementation lives
3+
How `memory.version` times and ranking classes work. Implementation lives
44
in capture (write), hybrid-search (rank), and search/timeline (query filters).
55

66
## Four times (two stored, two derived)

‎migrations/0001_extensions.sql‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
-- Knowledge plane owns its own Postgres schema. Never pollutes public.
2-
CREATE SCHEMA IF NOT EXISTS "knowledge";
1+
-- Memory plane owns its own Postgres schema. Never pollutes public.
2+
CREATE SCHEMA IF NOT EXISTS "memory";
33

44
-- pgvector for dense embeddings (cosine distance / HNSW).
55
CREATE EXTENSION IF NOT EXISTS vector;

‎migrations/0002_knowledge_baseline.sql‎

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
-- Single baseline for the knowledge plane (grant-tag authz from day one).
22
-- Document access is access_tags + creator post-filter; no visibility_* columns.
33

4-
CREATE TABLE IF NOT EXISTS "knowledge"."document" (
4+
CREATE TABLE IF NOT EXISTS "memory"."document" (
55
"id" text PRIMARY KEY,
66
"tenant_id" text NOT NULL,
77
"kind" text NOT NULL,
@@ -15,9 +15,9 @@ CREATE TABLE IF NOT EXISTS "knowledge"."document" (
1515
);
1616

1717
CREATE UNIQUE INDEX IF NOT EXISTS "document_tenant_adapter_external_ref_uniq"
18-
ON "knowledge"."document" ("tenant_id", "adapter", "external_ref");
18+
ON "memory"."document" ("tenant_id", "adapter", "external_ref");
1919

20-
CREATE TABLE IF NOT EXISTS "knowledge"."raw_capture" (
20+
CREATE TABLE IF NOT EXISTS "memory"."raw_capture" (
2121
"id" text PRIMARY KEY,
2222
"tenant_id" text NOT NULL,
2323
"adapter" text NOT NULL,
@@ -31,15 +31,15 @@ CREATE TABLE IF NOT EXISTS "knowledge"."raw_capture" (
3131
);
3232

3333
CREATE UNIQUE INDEX IF NOT EXISTS "raw_capture_tenant_source_hash_uniq"
34-
ON "knowledge"."raw_capture" ("tenant_id", "source_hash");
34+
ON "memory"."raw_capture" ("tenant_id", "source_hash");
3535

3636
CREATE INDEX IF NOT EXISTS "raw_capture_tenant_adapter_external_ref_idx"
37-
ON "knowledge"."raw_capture" ("tenant_id", "adapter", "external_ref");
37+
ON "memory"."raw_capture" ("tenant_id", "adapter", "external_ref");
3838

39-
CREATE TABLE IF NOT EXISTS "knowledge"."version" (
39+
CREATE TABLE IF NOT EXISTS "memory"."version" (
4040
"id" text PRIMARY KEY,
4141
"tenant_id" text NOT NULL,
42-
"document_id" text NOT NULL REFERENCES "knowledge"."document" ("id") ON DELETE CASCADE,
42+
"document_id" text NOT NULL REFERENCES "memory"."document" ("id") ON DELETE CASCADE,
4343
"version" integer NOT NULL,
4444
"supersedes_version_id" text,
4545
"status" text NOT NULL DEFAULT 'active',
@@ -55,7 +55,7 @@ CREATE TABLE IF NOT EXISTS "knowledge"."version" (
5555
"actor_count" integer NOT NULL DEFAULT 1,
5656
"has_social_signal" boolean NOT NULL DEFAULT false,
5757
"source_class" text NOT NULL DEFAULT 'native',
58-
"raw_capture_id" text REFERENCES "knowledge"."raw_capture" ("id"),
58+
"raw_capture_id" text REFERENCES "memory"."raw_capture" ("id"),
5959
"generation" text NOT NULL DEFAULT 'live',
6060
CONSTRAINT "version_status_check"
6161
CHECK ("status" IN ('active', 'superseded', 'deprecated', 'archived', 'tombstoned')),
@@ -66,35 +66,35 @@ CREATE TABLE IF NOT EXISTS "knowledge"."version" (
6666
);
6767

6868
CREATE UNIQUE INDEX IF NOT EXISTS "version_document_generation_version_uniq"
69-
ON "knowledge"."version" ("document_id", "generation", "version");
69+
ON "memory"."version" ("document_id", "generation", "version");
7070

7171
CREATE INDEX IF NOT EXISTS "version_document_status_idx"
72-
ON "knowledge"."version" ("document_id", "status");
72+
ON "memory"."version" ("document_id", "status");
7373

74-
CREATE TABLE IF NOT EXISTS "knowledge"."chunk" (
74+
CREATE TABLE IF NOT EXISTS "memory"."chunk" (
7575
"id" text PRIMARY KEY,
7676
"tenant_id" text NOT NULL,
77-
"version_id" text NOT NULL REFERENCES "knowledge"."version" ("id") ON DELETE CASCADE,
78-
"document_id" text NOT NULL REFERENCES "knowledge"."document" ("id") ON DELETE CASCADE,
77+
"version_id" text NOT NULL REFERENCES "memory"."version" ("id") ON DELETE CASCADE,
78+
"document_id" text NOT NULL REFERENCES "memory"."document" ("id") ON DELETE CASCADE,
7979
"ordinal" integer NOT NULL,
8080
"text" text NOT NULL,
8181
"role" text,
8282
"created_at" timestamp NOT NULL DEFAULT now()
8383
);
8484

8585
CREATE UNIQUE INDEX IF NOT EXISTS "chunk_version_ordinal_uniq"
86-
ON "knowledge"."chunk" ("version_id", "ordinal");
86+
ON "memory"."chunk" ("version_id", "ordinal");
8787

8888
-- {{FTS_LANGUAGE}} is substituted by runKnowledgeMigrations from FTS_LANGUAGE
8989
-- (or opts.ftsLanguage). Must match the language used at query time.
90-
ALTER TABLE "knowledge"."chunk"
90+
ALTER TABLE "memory"."chunk"
9191
ADD COLUMN IF NOT EXISTS "text_fts" tsvector
9292
GENERATED ALWAYS AS (to_tsvector('{{FTS_LANGUAGE}}', "text")) STORED;
9393

9494
CREATE INDEX IF NOT EXISTS "chunk_text_fts_idx"
95-
ON "knowledge"."chunk" USING GIN ("text_fts");
95+
ON "memory"."chunk" USING GIN ("text_fts");
9696

97-
CREATE TABLE IF NOT EXISTS "knowledge"."entity" (
97+
CREATE TABLE IF NOT EXISTS "memory"."entity" (
9898
"id" text PRIMARY KEY,
9999
"tenant_id" text NOT NULL,
100100
"kind" text NOT NULL,
@@ -104,9 +104,9 @@ CREATE TABLE IF NOT EXISTS "knowledge"."entity" (
104104
);
105105

106106
CREATE INDEX IF NOT EXISTS "entity_tenant_kind_idx"
107-
ON "knowledge"."entity" ("tenant_id", "kind");
107+
ON "memory"."entity" ("tenant_id", "kind");
108108

109-
CREATE TABLE IF NOT EXISTS "knowledge"."edge" (
109+
CREATE TABLE IF NOT EXISTS "memory"."edge" (
110110
"id" text PRIMARY KEY,
111111
"tenant_id" text NOT NULL,
112112
"rel" text NOT NULL,
@@ -127,12 +127,12 @@ CREATE TABLE IF NOT EXISTS "knowledge"."edge" (
127127
);
128128

129129
CREATE INDEX IF NOT EXISTS "edge_from_idx"
130-
ON "knowledge"."edge" ("tenant_id", "from_type", "from_ref");
130+
ON "memory"."edge" ("tenant_id", "from_type", "from_ref");
131131

132132
CREATE INDEX IF NOT EXISTS "edge_to_idx"
133-
ON "knowledge"."edge" ("tenant_id", "to_type", "to_ref");
133+
ON "memory"."edge" ("tenant_id", "to_type", "to_ref");
134134

135-
CREATE TABLE IF NOT EXISTS "knowledge"."embed_model" (
135+
CREATE TABLE IF NOT EXISTS "memory"."embed_model" (
136136
"id" text PRIMARY KEY,
137137
"tenant_id" text NOT NULL,
138138
"model_key" text NOT NULL,
@@ -145,7 +145,7 @@ CREATE TABLE IF NOT EXISTS "knowledge"."embed_model" (
145145
CHECK ("status" IN ('active', 'retired'))
146146
);
147147

148-
CREATE TABLE IF NOT EXISTS "knowledge"."transform_config" (
148+
CREATE TABLE IF NOT EXISTS "memory"."transform_config" (
149149
"id" text PRIMARY KEY,
150150
"tenant_id" text NOT NULL,
151151
"name" text NOT NULL,
@@ -156,10 +156,10 @@ CREATE TABLE IF NOT EXISTS "knowledge"."transform_config" (
156156
UNIQUE ("tenant_id", "name", "version")
157157
);
158158

159-
CREATE TABLE IF NOT EXISTS "knowledge"."transform_run" (
159+
CREATE TABLE IF NOT EXISTS "memory"."transform_run" (
160160
"id" text PRIMARY KEY,
161161
"tenant_id" text NOT NULL,
162-
"config_id" text NOT NULL REFERENCES "knowledge"."transform_config" ("id"),
162+
"config_id" text NOT NULL REFERENCES "memory"."transform_config" ("id"),
163163
"scope" jsonb NOT NULL DEFAULT '{}',
164164
"generation" text NOT NULL,
165165
"status" text NOT NULL DEFAULT 'running',
@@ -173,7 +173,7 @@ CREATE TABLE IF NOT EXISTS "knowledge"."transform_run" (
173173
);
174174

175175
CREATE UNIQUE INDEX IF NOT EXISTS "transform_run_generation_uniq"
176-
ON "knowledge"."transform_run" ("generation");
176+
ON "memory"."transform_run" ("generation");
177177

178178
CREATE INDEX IF NOT EXISTS "transform_run_tenant_config_idx"
179-
ON "knowledge"."transform_run" ("tenant_id", "config_id");
179+
ON "memory"."transform_run" ("tenant_id", "config_id");

‎migrations/0003_claim_bearing.sql‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
-- Edge rel / ref-type CHECKs already match the canonical set in 0002;
33
-- this migration only adds how-content-was-obtained (stated vs inferred).
44

5-
ALTER TABLE "knowledge"."version"
5+
ALTER TABLE "memory"."version"
66
ADD COLUMN IF NOT EXISTS "provenance" text NOT NULL DEFAULT 'unknown';
77

8-
ALTER TABLE "knowledge"."version"
8+
ALTER TABLE "memory"."version"
99
DROP CONSTRAINT IF EXISTS "version_provenance_check";
1010

11-
ALTER TABLE "knowledge"."version"
11+
ALTER TABLE "memory"."version"
1212
ADD CONSTRAINT "version_provenance_check"
1313
CHECK ("provenance" IN ('stated', 'inferred', 'unknown'));

0 commit comments

Comments
 (0)