Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions migrations/0001_extensions.sql
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
-- Own Postgres schema for every knowledge-engine table. Host control-plane
-- tables stay in public; this package never collides with or adopts them.
-- Knowledge plane owns its own Postgres schema. Never pollutes public.
CREATE SCHEMA IF NOT EXISTS "knowledge";

-- pgvector powers the dense retrieval channel. Per-model
-- "knowledge"."embedding_<key>" vector tables are created at runtime by the
-- embed-model activation path (dimensionality varies by model), not here.
-- pgvector for dense embeddings (cosine distance / HNSW).
CREATE EXTENSION IF NOT EXISTS vector;
179 changes: 179 additions & 0 deletions migrations/0002_knowledge_baseline.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
-- Single baseline for the knowledge plane (grant-tag authz from day one).
-- Document access is access_tags + creator post-filter; no visibility_* columns.

CREATE TABLE IF NOT EXISTS "knowledge"."document" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"kind" text NOT NULL,
"title" text NOT NULL,
"adapter" text NOT NULL,
"external_ref" text NOT NULL,
"access_tags" text[] NOT NULL DEFAULT '{}',
"attributes" jsonb NOT NULL DEFAULT '{}',
"created_at" timestamp NOT NULL DEFAULT now(),
"last_seen_at" timestamp NOT NULL DEFAULT now()
);

CREATE UNIQUE INDEX IF NOT EXISTS "document_tenant_adapter_external_ref_uniq"
ON "knowledge"."document" ("tenant_id", "adapter", "external_ref");

CREATE TABLE IF NOT EXISTS "knowledge"."raw_capture" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"adapter" text NOT NULL,
"external_ref" text NOT NULL,
"fetched_at" timestamp NOT NULL DEFAULT now(),
"content_type" text NOT NULL,
"raw_text" text,
"raw_bytes" bytea,
"metadata" jsonb NOT NULL DEFAULT '{}',
"source_hash" text NOT NULL
);

CREATE UNIQUE INDEX IF NOT EXISTS "raw_capture_tenant_source_hash_uniq"
ON "knowledge"."raw_capture" ("tenant_id", "source_hash");

CREATE INDEX IF NOT EXISTS "raw_capture_tenant_adapter_external_ref_idx"
ON "knowledge"."raw_capture" ("tenant_id", "adapter", "external_ref");

CREATE TABLE IF NOT EXISTS "knowledge"."version" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"document_id" text NOT NULL REFERENCES "knowledge"."document" ("id") ON DELETE CASCADE,
"version" integer NOT NULL,
"supersedes_version_id" text,
"status" text NOT NULL DEFAULT 'active',
"content_hash" text NOT NULL,
"occurred_at" timestamp NOT NULL,
"ingested_at" timestamp NOT NULL DEFAULT now(),
"deprecated_at" timestamp,
"deprecated_reason" text,
"created_by_principal_id" text,
"created_by_kind" text NOT NULL,
"generator_agent_id" text,
"authority" real NOT NULL DEFAULT 0,
"actor_count" integer NOT NULL DEFAULT 1,
"has_social_signal" boolean NOT NULL DEFAULT false,
"source_class" text NOT NULL DEFAULT 'native',
"raw_capture_id" text REFERENCES "knowledge"."raw_capture" ("id"),
"generation" text NOT NULL DEFAULT 'live',
CONSTRAINT "version_status_check"
CHECK ("status" IN ('active', 'superseded', 'deprecated', 'archived', 'tombstoned')),
CONSTRAINT "version_created_by_kind_check"
CHECK ("created_by_kind" IN ('human', 'agent', 'system', 'adapter')),
CONSTRAINT "version_source_class_check"
CHECK ("source_class" IN ('native', 'imported', 'derived'))
);

CREATE UNIQUE INDEX IF NOT EXISTS "version_document_generation_version_uniq"
ON "knowledge"."version" ("document_id", "generation", "version");

CREATE INDEX IF NOT EXISTS "version_document_status_idx"
ON "knowledge"."version" ("document_id", "status");

CREATE TABLE IF NOT EXISTS "knowledge"."chunk" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"version_id" text NOT NULL REFERENCES "knowledge"."version" ("id") ON DELETE CASCADE,
"document_id" text NOT NULL REFERENCES "knowledge"."document" ("id") ON DELETE CASCADE,
"ordinal" integer NOT NULL,
"text" text NOT NULL,
"role" text,
"created_at" timestamp NOT NULL DEFAULT now()
);

CREATE UNIQUE INDEX IF NOT EXISTS "chunk_version_ordinal_uniq"
ON "knowledge"."chunk" ("version_id", "ordinal");

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

CREATE INDEX IF NOT EXISTS "chunk_text_fts_idx"
ON "knowledge"."chunk" USING GIN ("text_fts");

CREATE TABLE IF NOT EXISTS "knowledge"."entity" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"kind" text NOT NULL,
"identifiers" jsonb NOT NULL DEFAULT '{}',
"created_at" timestamp NOT NULL DEFAULT now(),
"updated_at" timestamp NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS "entity_tenant_kind_idx"
ON "knowledge"."entity" ("tenant_id", "kind");

CREATE TABLE IF NOT EXISTS "knowledge"."edge" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"rel" text NOT NULL,
"from_type" text NOT NULL,
"from_ref" text NOT NULL,
"to_type" text NOT NULL,
"to_ref" text NOT NULL,
"created_at" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "edge_rel_check"
CHECK ("rel" IN (
'mentions', 'about', 'authored_by', 'involves',
'part_of', 'derived_from', 'supports', 'contradicts', 'supersedes'
)),
CONSTRAINT "edge_from_type_check"
CHECK ("from_type" IN ('document', 'version', 'chunk', 'entity')),
CONSTRAINT "edge_to_type_check"
CHECK ("to_type" IN ('document', 'version', 'chunk', 'entity'))
);

CREATE INDEX IF NOT EXISTS "edge_from_idx"
ON "knowledge"."edge" ("tenant_id", "from_type", "from_ref");

CREATE INDEX IF NOT EXISTS "edge_to_idx"
ON "knowledge"."edge" ("tenant_id", "to_type", "to_ref");

CREATE TABLE IF NOT EXISTS "knowledge"."embed_model" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"model_key" text NOT NULL,
"model_id" text NOT NULL,
"dims" integer NOT NULL,
"status" text NOT NULL DEFAULT 'active',
"created_at" timestamp NOT NULL DEFAULT now(),
"updated_at" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "embed_model_status_check"
CHECK ("status" IN ('active', 'retired'))
);

CREATE TABLE IF NOT EXISTS "knowledge"."transform_config" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"name" text NOT NULL,
"version" integer NOT NULL,
"params" jsonb NOT NULL DEFAULT '{}',
"created_at" timestamp NOT NULL DEFAULT now(),
CONSTRAINT "transform_config_tenant_name_version_uniq"
UNIQUE ("tenant_id", "name", "version")
);

CREATE TABLE IF NOT EXISTS "knowledge"."transform_run" (
"id" text PRIMARY KEY,
"tenant_id" text NOT NULL,
"config_id" text NOT NULL REFERENCES "knowledge"."transform_config" ("id"),
"scope" jsonb NOT NULL DEFAULT '{}',
"generation" text NOT NULL,
"status" text NOT NULL DEFAULT 'running',
"raw_count" integer NOT NULL DEFAULT 0,
"version_count" integer NOT NULL DEFAULT 0,
"error" text,
"created_at" timestamp NOT NULL DEFAULT now(),
"completed_at" timestamp,
CONSTRAINT "transform_run_status_check"
CHECK ("status" IN ('running', 'completed', 'failed'))
);

CREATE UNIQUE INDEX IF NOT EXISTS "transform_run_generation_uniq"
ON "knowledge"."transform_run" ("generation");

CREATE INDEX IF NOT EXISTS "transform_run_tenant_config_idx"
ON "knowledge"."transform_run" ("tenant_id", "config_id");
32 changes: 0 additions & 32 deletions migrations/0002_knowledge_document.sql

This file was deleted.

49 changes: 0 additions & 49 deletions migrations/0003_knowledge_version.sql

This file was deleted.

24 changes: 0 additions & 24 deletions migrations/0004_knowledge_chunk.sql

This file was deleted.

16 changes: 0 additions & 16 deletions migrations/0005_knowledge_entity.sql

This file was deleted.

37 changes: 0 additions & 37 deletions migrations/0006_knowledge_edge.sql

This file was deleted.

14 changes: 0 additions & 14 deletions migrations/0007_knowledge_embed_model.sql

This file was deleted.

27 changes: 0 additions & 27 deletions migrations/0008_raw_capture.sql

This file was deleted.

Loading
Loading