@marinoscar/kvox-eval 0.0.0-bootstrap → 0.1.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (245) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/LICENSE +21 -0
  3. package/README.md +166 -0
  4. package/dist/ask/index.d.ts +6 -0
  5. package/dist/ask/index.js +28 -0
  6. package/dist/ask/question-schema.d.ts +121 -0
  7. package/dist/ask/question-schema.js +167 -0
  8. package/dist/ask/report.d.ts +88 -0
  9. package/dist/ask/report.js +170 -0
  10. package/dist/ask/scorer.d.ts +104 -0
  11. package/dist/ask/scorer.js +164 -0
  12. package/dist/ask-run/ask-command.d.ts +62 -0
  13. package/dist/ask-run/ask-command.js +254 -0
  14. package/dist/ask-run/host/app.d.ts +65 -0
  15. package/dist/ask-run/host/app.js +146 -0
  16. package/dist/ask-run/host/db.d.ts +38 -0
  17. package/dist/ask-run/host/db.js +126 -0
  18. package/dist/ask-run/host/ports.d.ts +35 -0
  19. package/dist/ask-run/host/ports.js +113 -0
  20. package/dist/ask-run/index.d.ts +13 -0
  21. package/dist/ask-run/index.js +35 -0
  22. package/dist/ask-run/replay.d.ts +128 -0
  23. package/dist/ask-run/replay.js +212 -0
  24. package/dist/ask-run/run-ask-eval.d.ts +125 -0
  25. package/dist/ask-run/run-ask-eval.js +193 -0
  26. package/dist/ask-run/seed-golden-graph.d.ts +64 -0
  27. package/dist/ask-run/seed-golden-graph.js +495 -0
  28. package/dist/cli/index.d.ts +3 -0
  29. package/dist/cli/index.js +12 -0
  30. package/dist/cli/kg-command.d.ts +66 -0
  31. package/dist/cli/kg-command.js +238 -0
  32. package/dist/cli/main.d.ts +18 -0
  33. package/dist/cli/main.js +69 -0
  34. package/dist/fixtures/domains.d.ts +16 -0
  35. package/dist/fixtures/domains.js +33 -0
  36. package/dist/fixtures/fixture-schema.d.ts +323 -0
  37. package/dist/fixtures/fixture-schema.js +199 -0
  38. package/dist/fixtures/index.d.ts +16 -0
  39. package/dist/fixtures/index.js +40 -0
  40. package/dist/fixtures/load.d.ts +73 -0
  41. package/dist/fixtures/load.js +137 -0
  42. package/dist/fixtures/questions.d.ts +15 -0
  43. package/dist/fixtures/questions.js +26 -0
  44. package/dist/index.d.ts +20 -0
  45. package/dist/index.js +36 -0
  46. package/dist/kg/gold-runner.d.ts +13 -0
  47. package/dist/kg/gold-runner.js +57 -0
  48. package/dist/kg/index.d.ts +17 -0
  49. package/dist/kg/index.js +65 -0
  50. package/dist/kg/internals.d.ts +7 -0
  51. package/dist/kg/internals.js +17 -0
  52. package/dist/kg/prediction-schema.d.ts +245 -0
  53. package/dist/kg/prediction-schema.js +102 -0
  54. package/dist/kg/predictions.d.ts +11 -0
  55. package/dist/kg/predictions.js +49 -0
  56. package/dist/kg/report.d.ts +84 -0
  57. package/dist/kg/report.js +125 -0
  58. package/dist/kg/run-kg-eval.d.ts +77 -0
  59. package/dist/kg/run-kg-eval.js +137 -0
  60. package/dist/kg/runner.d.ts +72 -0
  61. package/dist/kg/runner.js +51 -0
  62. package/dist/kg/runners/extract-resolve-runner.d.ts +40 -0
  63. package/dist/kg/runners/extract-resolve-runner.js +199 -0
  64. package/dist/kg/runners/extract-runner.d.ts +65 -0
  65. package/dist/kg/runners/extract-runner.js +243 -0
  66. package/dist/kg/scorer.d.ts +226 -0
  67. package/dist/kg/scorer.js +463 -0
  68. package/dist/kg/targets.d.ts +17 -0
  69. package/dist/kg/targets.js +16 -0
  70. package/dist/kg/text.d.ts +45 -0
  71. package/dist/kg/text.js +100 -0
  72. package/dist/live/adapters.d.ts +16 -0
  73. package/dist/live/adapters.js +58 -0
  74. package/dist/live/env.d.ts +39 -0
  75. package/dist/live/env.js +56 -0
  76. package/dist/live/index.d.ts +6 -0
  77. package/dist/live/index.js +16 -0
  78. package/dist/live/live-ai.d.ts +104 -0
  79. package/dist/live/live-ai.js +157 -0
  80. package/dist/parity/constants.d.ts +79 -0
  81. package/dist/parity/constants.js +104 -0
  82. package/dist/parity/index.d.ts +20 -0
  83. package/dist/parity/index.js +38 -0
  84. package/dist/parity/internals.d.ts +8 -0
  85. package/dist/parity/internals.js +16 -0
  86. package/dist/parity/scenario.d.ts +45 -0
  87. package/dist/parity/scenario.js +245 -0
  88. package/dist/parity/script.d.ts +44 -0
  89. package/dist/parity/script.js +136 -0
  90. package/dist/parity/snapshot.d.ts +43 -0
  91. package/dist/parity/snapshot.js +71 -0
  92. package/dist/real-data/index.d.ts +2 -0
  93. package/dist/real-data/index.js +12 -0
  94. package/dist/real-data/real-data.d.ts +76 -0
  95. package/dist/real-data/real-data.js +156 -0
  96. package/fixtures/kg-golden/README.md +136 -0
  97. package/fixtures/kg-golden/ask-questions.json +458 -0
  98. package/fixtures/kg-golden/meetings/m01-northwind-pilot-kickoff.json +792 -0
  99. package/fixtures/kg-golden/meetings/m02-halden-migration-planning.json +814 -0
  100. package/fixtures/kg-golden/meetings/m03-larkspur-weekly-sync.json +601 -0
  101. package/fixtures/kg-golden/meetings/m04-corvid-intake-discovery.json +690 -0
  102. package/fixtures/kg-golden/meetings/m05-hosting-vendor-selection.json +631 -0
  103. package/fixtures/kg-golden/meetings/m06-northwind-floor-data-review.json +649 -0
  104. package/fixtures/kg-golden/meetings/m07-gullwing-intro-notes.json +428 -0
  105. package/fixtures/kg-golden/meetings/m08-halden-migration-checkpoint.json +672 -0
  106. package/fixtures/kg-golden/meetings/m09-northwind-platform-org-update.json +711 -0
  107. package/fixtures/kg-golden/meetings/m10-corvid-prototype-review.json +623 -0
  108. package/fixtures/kg-golden/meetings/m11-solvane-grid-dashboard-scoping.json +689 -0
  109. package/fixtures/kg-golden/meetings/m12-northwind-pilot-replan.json +681 -0
  110. package/fixtures/kg-golden/meetings/m13-halden-cutover-go-no-go.json +721 -0
  111. package/fixtures/kg-golden/meetings/m14-gullwing-discovery-readout.json +719 -0
  112. package/fixtures/kg-golden/meetings/m15-halden-handover-ravi-leaving.json +716 -0
  113. package/fixtures/kg-golden/meetings/m16-varden-claims-portal-intro.json +704 -0
  114. package/fixtures/kg-golden/meetings/m17-corvid-usability-debrief.json +572 -0
  115. package/fixtures/kg-golden/meetings/m18-hosting-decision-revisited.json +655 -0
  116. package/fixtures/kg-golden/meetings/m19-solvane-integration-kickoff.json +726 -0
  117. package/fixtures/kg-golden/meetings/m20-northwind-go-live-retro.json +673 -0
  118. package/fixtures/kg-golden/meetings/m21-quarterly-account-review.json +449 -0
  119. package/fixtures/kg-golden/meetings/m22-halden-intro-call-2020.json +558 -0
  120. package/fixtures/kg-golden/meetings/m23-gullwing-model-review.json +702 -0
  121. package/fixtures/kg-golden/meetings/m24-varden-discovery-midpoint.json +643 -0
  122. package/fixtures/kg-golden/meetings/m25-corvid-rollout-planning.json +642 -0
  123. package/fixtures/kg-golden/meetings/m26-larkspur-engineering-prep.json +695 -0
  124. package/fixtures/kg-golden/meetings/m27-solvane-phase-one-demo.json +649 -0
  125. package/fixtures/kg-golden/meetings/m28-northwind-building-5-scoping.json +715 -0
  126. package/fixtures/kg-golden/meetings/m29-halden-southern-cutover-review.json +752 -0
  127. package/fixtures/kg-golden/meetings/m30-varden-portal-build-kickoff.json +697 -0
  128. package/fixtures/kg-golden/meetings/m31-gullwing-rollout-renewal.json +681 -0
  129. package/fixtures/kg-golden/meetings/m32-brambleway-weekly-sync.json +472 -0
  130. package/fixtures/kg-golden/meetings/m33-nina-oliver-one-on-one.json +342 -0
  131. package/fixtures/kg-golden/meetings/m34-coffee-with-dana.json +249 -0
  132. package/fixtures/kg-golden/meetings/m35-brambleway-june-sync.json +553 -0
  133. package/fixtures/kg-golden/meetings/m36-copenhagen-conference-planning.json +296 -0
  134. package/host/generated/client.d.ts +1 -0
  135. package/host/generated/client.js +5 -0
  136. package/host/generated/default.d.ts +1 -0
  137. package/host/generated/default.js +5 -0
  138. package/host/generated/edge.d.ts +1 -0
  139. package/host/generated/edge.js +1658 -0
  140. package/host/generated/index-browser.js +1684 -0
  141. package/host/generated/index.d.ts +192335 -0
  142. package/host/generated/index.js +1658 -0
  143. package/host/generated/package.json +139 -0
  144. package/host/generated/query_compiler_fast_bg.js +2 -0
  145. package/host/generated/query_compiler_fast_bg.wasm +0 -0
  146. package/host/generated/query_compiler_fast_bg.wasm-base64.js +2 -0
  147. package/host/generated/runtime/client.d.ts +3433 -0
  148. package/host/generated/runtime/client.js +110 -0
  149. package/host/generated/runtime/index-browser.d.ts +90 -0
  150. package/host/generated/runtime/index-browser.js +6 -0
  151. package/host/generated/runtime/wasm-compiler-edge.js +100 -0
  152. package/host/generated/schema.prisma +6312 -0
  153. package/host/generated/wasm-edge-light-loader.mjs +5 -0
  154. package/host/generated/wasm-worker-loader.mjs +5 -0
  155. package/host/prisma/fragments/kvox.ask.prisma +126 -0
  156. package/host/prisma/fragments/kvox.graph.prisma +1073 -0
  157. package/host/prisma/fragments/kvox.notes.prisma +787 -0
  158. package/host/prisma/fragments/kvox.search.prisma +211 -0
  159. package/host/prisma/fragments/kvox.transcripts.prisma +790 -0
  160. package/host/prisma/kvox.lock +101 -0
  161. package/host/prisma/migrations/20240101000000_initial/migration.sql +297 -0
  162. package/host/prisma/migrations/20240101000001_add_personal_access_tokens/migration.sql +31 -0
  163. package/host/prisma/migrations/20240101000002_add_credentials/migration.sql +20 -0
  164. package/host/prisma/migrations/20240101000003_add_notification_deliveries/migration.sql +27 -0
  165. package/host/prisma/migrations/20240101000004_drop_stale_uuid_defaults/migration.sql +35 -0
  166. package/host/prisma/migrations/20240101000005_add_notifications/migration.sql +22 -0
  167. package/host/prisma/migrations/20240101000006_add_push_subscriptions/migration.sql +25 -0
  168. package/host/prisma/migrations/20240101000007_add_jobs/migration.sql +110 -0
  169. package/host/prisma/migrations/20240101000008_add_worker_nodes/migration.sql +90 -0
  170. package/host/prisma/migrations/20240101000009_add_database_backup_runs/migration.sql +104 -0
  171. package/host/prisma/migrations/20240101000010_add_notification_broadcasts/migration.sql +57 -0
  172. package/host/prisma/migrations/20240101000011_add_backup_run_job_link/migration.sql +87 -0
  173. package/host/prisma/migrations/20240101000012_add_job_node_secrets/migration.sql +61 -0
  174. package/host/prisma/migrations/20240101000013_add_backup_run_pg_dump_version/migration.sql +26 -0
  175. package/host/prisma/migrations/20240101000014_add_job_claim_token/migration.sql +92 -0
  176. package/host/prisma/migrations/20240101000015_add_ai_platform/migration.sql +108 -0
  177. package/host/prisma/migrations/20240101000016_revoke_viewer_ai_use/migration.sql +32 -0
  178. package/host/prisma/migrations/20240101000017_add_user_credentials/migration.sql +29 -0
  179. package/host/prisma/migrations/20240101000018_add_device_session_credential_link/migration.sql +52 -0
  180. package/host/prisma/migrations/20240101000019_add_worker_node_vitals/migration.sql +3 -0
  181. package/host/prisma/migrations/20240101000020_add_job_trace_context/migration.sql +6 -0
  182. package/host/prisma/migrations/20240101000021_add_retention_created_at_indexes/migration.sql +13 -0
  183. package/host/prisma/migrations/20240101000022_add_organizations/migration.sql +142 -0
  184. package/host/prisma/migrations/20240101000023_split_system_org_roles/migration.sql +131 -0
  185. package/host/prisma/migrations/20240101000024_org_scoped_rls/migration.sql +215 -0
  186. package/host/prisma/migrations/20240101000025_add_groups/migration.sql +165 -0
  187. package/host/prisma/migrations/20240101000026_add_grants/migration.sql +117 -0
  188. package/host/prisma/migrations/20240101000027_add_org_settings/migration.sql +49 -0
  189. package/host/prisma/migrations/20240101000028_add_org_credentials/migration.sql +54 -0
  190. package/host/prisma/migrations/20240101000029_add_jobs_org_id/migration.sql +18 -0
  191. package/host/prisma/migrations/20240101000030_add_jobs_org_id_status_index/migration.sql +6 -0
  192. package/host/prisma/migrations/20240101000031_add_broadcast_target_org/migration.sql +21 -0
  193. package/host/prisma/migrations/20240101000032_add_android_app/migration.sql +60 -0
  194. package/host/prisma/migrations/20240101000033_open_job_reason/migration.sql +16 -0
  195. package/host/prisma/migrations/20240101000034_ai_usage_feature/migration.sql +37 -0
  196. package/host/prisma/migrations/20240101000035_add_app_metadata/migration.sql +49 -0
  197. package/host/prisma/migrations/20240101000036_open_sharing_vocabularies/migration.sql +97 -0
  198. package/host/prisma/migrations/20260914130000_kvox_add_transcripts/migration.sql +322 -0
  199. package/host/prisma/migrations/20260914140000_kvox_add_notes/migration.sql +311 -0
  200. package/host/prisma/migrations/20260915120000_kvox_add_search_vectors/migration.sql +150 -0
  201. package/host/prisma/migrations/20260915130000_kvox_add_search_embeddings/migration.sql +362 -0
  202. package/host/prisma/migrations/20260915210000_kvox_add_note_title_source/migration.sql +30 -0
  203. package/host/prisma/migrations/20260923120000_kvox_add_note_generation_context_snapshot/migration.sql +24 -0
  204. package/host/prisma/migrations/20260923130000_kvox_add_user_hidden_note_templates/migration.sql +35 -0
  205. package/host/prisma/migrations/20260923140000_kvox_add_transcript_speaker_identities/migration.sql +6 -0
  206. package/host/prisma/migrations/20260923150000_kvox_transcript_name_checks/migration.sql +95 -0
  207. package/host/prisma/migrations/20260923160000_kvox_add_note_body_format/migration.sql +27 -0
  208. package/host/prisma/migrations/20260923170000_kvox_add_note_version_body_format/migration.sql +23 -0
  209. package/host/prisma/migrations/20260926012548_kvox_add_knowledge_graph/migration.sql +680 -0
  210. package/host/prisma/migrations/20260926030000_kvox_fix_kg_relations_valid_precision_chk/migration.sql +29 -0
  211. package/host/prisma/migrations/20260926030100_kvox_add_transcript_recorded_at/migration.sql +9 -0
  212. package/host/prisma/migrations/20260926030200_kvox_kg_evidence_invariant/migration.sql +60 -0
  213. package/host/prisma/migrations/20260926040000_kvox_add_kg_graph_layouts/migration.sql +30 -0
  214. package/host/prisma/migrations/20260926050000_kvox_add_ask_conversations/migration.sql +99 -0
  215. package/host/prisma/migrations/20260926231512_kvox_add_kg_exports/migration.sql +52 -0
  216. package/host/prisma/migrations/20261016120000_kvox_transcripts_org_id/migration.sql +49 -0
  217. package/host/prisma/platform.lock +319 -0
  218. package/host/prisma/schema/app.kvox.ask.prisma +110 -0
  219. package/host/prisma/schema/app.kvox.graph.prisma +1030 -0
  220. package/host/prisma/schema/app.kvox.notes.prisma +746 -0
  221. package/host/prisma/schema/app.kvox.search.prisma +208 -0
  222. package/host/prisma/schema/app.kvox.transcripts.prisma +726 -0
  223. package/host/prisma/schema/platform.ai.prisma +419 -0
  224. package/host/prisma/schema/platform.android-app.prisma +46 -0
  225. package/host/prisma/schema/platform.base.prisma +15 -0
  226. package/host/prisma/schema/platform.credentials.prisma +156 -0
  227. package/host/prisma/schema/platform.db-backup.prisma +359 -0
  228. package/host/prisma/schema/platform.identity.prisma +638 -0
  229. package/host/prisma/schema/platform.jobs.prisma +824 -0
  230. package/host/prisma/schema/platform.notifications.prisma +641 -0
  231. package/host/prisma/schema/platform.settings.prisma +53 -0
  232. package/host/prisma/schema/platform.sharing.prisma +208 -0
  233. package/host/prisma/schema/platform.storage.prisma +118 -0
  234. package/package.json +112 -1
  235. package/parity/requests.ask.json +2681 -0
  236. package/parity/requests.m01.json +1554 -0
  237. package/parity/requests.m02.json +1554 -0
  238. package/parity/requests.m03.json +1554 -0
  239. package/parity/requests.m04.json +1554 -0
  240. package/parity/requests.m05.json +1554 -0
  241. package/parity/requests.m06.json +1554 -0
  242. package/parity/requests.m07.json +1554 -0
  243. package/parity/requests.m08.json +1554 -0
  244. package/parity/requests.m09.json +1554 -0
  245. package/parity/requests.m10.json +1554 -0
@@ -0,0 +1,680 @@
1
+ -- CreateEnum
2
+ CREATE TYPE "kg_review_status" AS ENUM ('unreviewed', 'accepted', 'edited', 'rejected', 'merged', 'superseded');
3
+
4
+ -- CreateEnum
5
+ CREATE TYPE "kg_valid_precision" AS ENUM ('day', 'month', 'year', 'unknown');
6
+
7
+ -- CreateEnum
8
+ CREATE TYPE "kg_item_kind" AS ENUM ('commitment', 'decision', 'claim', 'person_fact');
9
+
10
+ -- CreateEnum
11
+ CREATE TYPE "kg_sensitivity" AS ENUM ('business', 'personal', 'sensitive');
12
+
13
+ -- CreateEnum
14
+ CREATE TYPE "kg_alias_source" AS ENUM ('user', 'extraction', 'speaker_naming', 'import');
15
+
16
+ -- CreateEnum
17
+ CREATE TYPE "kg_evidence_subject_kind" AS ENUM ('entity', 'relation', 'item', 'proposal_item', 'import');
18
+
19
+ -- CreateEnum
20
+ CREATE TYPE "kg_mention_status" AS ENUM ('suggested', 'linked', 'new', 'ignored');
21
+
22
+ -- CreateEnum
23
+ CREATE TYPE "kg_proposal_kind" AS ENUM ('extraction', 'import', 'resolution');
24
+
25
+ -- CreateEnum
26
+ CREATE TYPE "kg_proposal_status" AS ENUM ('draft', 'extracting', 'committed', 'discarded', 'failed', 'reverted');
27
+
28
+ -- CreateEnum
29
+ CREATE TYPE "kg_proposal_item_kind" AS ENUM ('entity', 'relation', 'item', 'closing');
30
+
31
+ -- CreateEnum
32
+ CREATE TYPE "kg_proposal_item_decision" AS ENUM ('pending', 'accept', 'edit', 'reject', 'merge_into');
33
+
34
+ -- CreateEnum
35
+ CREATE TYPE "kg_proposal_item_origin" AS ENUM ('ai', 'user');
36
+
37
+ -- CreateEnum
38
+ CREATE TYPE "kg_attribute_kind" AS ENUM ('text', 'number', 'date', 'boolean', 'select', 'multi_select', 'url', 'entity_ref');
39
+
40
+ -- ⚠ INTENTIONAL OMISSION: `prisma migrate dev` also proposed `DROP INDEX`
41
+ -- for `notes_search_vector_idx`, `search_embeddings_embedding_hnsw_idx`,
42
+ -- `transcript_segments_search_vector_idx`, `transcripts_title_search_vector_idx`,
43
+ -- plus `ALTER TABLE … ALTER COLUMN "search_vector" DROP DEFAULT` on
44
+ -- `notes`/`transcript_segments`/`transcripts` — none of it touches this
45
+ -- migration's own tables. It is Prisma re-discovering the PRE-EXISTING
46
+ -- hand-written schema drift `search.md` §2 and `SearchEmbedding`'s own block
47
+ -- comment already document (generated `tsvector` columns and the HNSW index
48
+ -- have no Prisma DSL, so `schema.prisma` cannot describe them exactly as the
49
+ -- database has them) and proposing to "fix" it by dropping and reasserting
50
+ -- those objects. Per this repo's own rule for exactly this situation (see
51
+ -- the CLAUDE.md "Adding a Job Type"/`Job` model's index comments and every
52
+ -- prior hand-written-index migration), those lines are deleted here rather
53
+ -- than applied — do not restore them.
54
+
55
+ -- CreateTable
56
+ CREATE TABLE "kg_entities" (
57
+ "id" UUID NOT NULL,
58
+ "owner_id" UUID NOT NULL,
59
+ "type" TEXT NOT NULL,
60
+ "label" TEXT NOT NULL,
61
+ "props" JSONB NOT NULL DEFAULT '{}',
62
+ "embedding" vector(1536),
63
+ "embedding_model" TEXT,
64
+ "embedding_hash" TEXT,
65
+ "review_status" "kg_review_status" NOT NULL DEFAULT 'accepted',
66
+ "merged_into_id" UUID,
67
+ "occurred_at" TIMESTAMPTZ,
68
+ "ontology_version" TEXT NOT NULL,
69
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
70
+ "updated_at" TIMESTAMPTZ NOT NULL,
71
+
72
+ CONSTRAINT "kg_entities_pkey" PRIMARY KEY ("id")
73
+ );
74
+
75
+ -- CreateTable
76
+ CREATE TABLE "kg_entity_aliases" (
77
+ "id" UUID NOT NULL,
78
+ "entity_id" UUID NOT NULL,
79
+ "owner_id" UUID NOT NULL,
80
+ "alias" TEXT NOT NULL,
81
+ "normalized" TEXT NOT NULL,
82
+ "source" "kg_alias_source" NOT NULL,
83
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
84
+
85
+ CONSTRAINT "kg_entity_aliases_pkey" PRIMARY KEY ("id")
86
+ );
87
+
88
+ -- CreateTable
89
+ CREATE TABLE "kg_relations" (
90
+ "id" UUID NOT NULL,
91
+ "owner_id" UUID NOT NULL,
92
+ "type" TEXT NOT NULL,
93
+ "from_id" UUID,
94
+ "from_speaker_id" UUID,
95
+ "to_id" UUID NOT NULL,
96
+ "props" JSONB NOT NULL DEFAULT '{}',
97
+ "valid" tstzrange,
98
+ "valid_precision" "kg_valid_precision",
99
+ "review_status" "kg_review_status" NOT NULL DEFAULT 'accepted',
100
+ "confidence" DOUBLE PRECISION,
101
+ "superseded_by_id" UUID,
102
+ "ontology_version" TEXT NOT NULL,
103
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
104
+ "updated_at" TIMESTAMPTZ NOT NULL,
105
+
106
+ CONSTRAINT "kg_relations_pkey" PRIMARY KEY ("id")
107
+ );
108
+
109
+ -- CreateTable
110
+ CREATE TABLE "kg_items" (
111
+ "id" UUID NOT NULL,
112
+ "owner_id" UUID NOT NULL,
113
+ "kind" "kg_item_kind" NOT NULL,
114
+ "subject_id" UUID,
115
+ "meeting_id" UUID,
116
+ "owner_person_id" UUID,
117
+ "counterparty_id" UUID,
118
+ "title" TEXT,
119
+ "statement" TEXT NOT NULL,
120
+ "status" TEXT NOT NULL,
121
+ "props" JSONB NOT NULL DEFAULT '{}',
122
+ "occurred_at" TIMESTAMPTZ,
123
+ "due_at" TIMESTAMPTZ,
124
+ "superseded_by_id" UUID,
125
+ "sensitivity" "kg_sensitivity",
126
+ "statement_hash" TEXT NOT NULL,
127
+ "valid" tstzrange,
128
+ "valid_precision" "kg_valid_precision",
129
+ "embedding" vector(1536),
130
+ "embedding_model" TEXT,
131
+ "embedding_hash" TEXT,
132
+ "review_status" "kg_review_status" NOT NULL DEFAULT 'accepted',
133
+ "confidence" DOUBLE PRECISION,
134
+ "ontology_version" TEXT NOT NULL,
135
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
136
+ "updated_at" TIMESTAMPTZ NOT NULL,
137
+
138
+ CONSTRAINT "kg_items_pkey" PRIMARY KEY ("id")
139
+ );
140
+
141
+ -- CreateTable
142
+ CREATE TABLE "kg_evidence" (
143
+ "id" UUID NOT NULL,
144
+ "owner_id" UUID NOT NULL,
145
+ "subject_kind" "kg_evidence_subject_kind" NOT NULL,
146
+ "subject_id" UUID NOT NULL,
147
+ "transcript_id" UUID,
148
+ "segment_id" UUID,
149
+ "segment_rev" INTEGER,
150
+ "start_ms" INTEGER,
151
+ "end_ms" INTEGER,
152
+ "note_id" UUID,
153
+ "note_version" INTEGER,
154
+ "char_start" INTEGER,
155
+ "char_end" INTEGER,
156
+ "quote" TEXT NOT NULL,
157
+ "import_object_id" UUID,
158
+ "source_iri" TEXT,
159
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
160
+
161
+ CONSTRAINT "kg_evidence_pkey" PRIMARY KEY ("id")
162
+ );
163
+
164
+ -- CreateTable
165
+ CREATE TABLE "kg_mentions" (
166
+ "id" UUID NOT NULL,
167
+ "owner_id" UUID NOT NULL,
168
+ "entity_id" UUID NOT NULL,
169
+ "note_id" UUID,
170
+ "transcript_id" UUID,
171
+ "span" JSONB,
172
+ "status" "kg_mention_status" NOT NULL DEFAULT 'linked',
173
+ "score" DOUBLE PRECISION,
174
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
175
+
176
+ CONSTRAINT "kg_mentions_pkey" PRIMARY KEY ("id")
177
+ );
178
+
179
+ -- CreateTable
180
+ CREATE TABLE "kg_proposals" (
181
+ "id" UUID NOT NULL,
182
+ "owner_id" UUID NOT NULL,
183
+ "kind" "kg_proposal_kind" NOT NULL,
184
+ "status" "kg_proposal_status" NOT NULL DEFAULT 'draft',
185
+ "note_id" UUID,
186
+ "note_version" INTEGER,
187
+ "model" TEXT,
188
+ "provider" TEXT,
189
+ "system_prompt" TEXT,
190
+ "user_content" TEXT,
191
+ "user_guidance" JSONB,
192
+ "stats" JSONB NOT NULL DEFAULT '{}',
193
+ "committed_at" TIMESTAMPTZ,
194
+ "reverted_at" TIMESTAMPTZ,
195
+ "job_id" UUID,
196
+ "commit_log" JSONB,
197
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
198
+ "updated_at" TIMESTAMPTZ NOT NULL,
199
+
200
+ CONSTRAINT "kg_proposals_pkey" PRIMARY KEY ("id")
201
+ );
202
+
203
+ -- CreateTable
204
+ CREATE TABLE "kg_proposal_items" (
205
+ "id" UUID NOT NULL,
206
+ "proposal_id" UUID NOT NULL,
207
+ "kind" "kg_proposal_item_kind" NOT NULL,
208
+ "payload" JSONB NOT NULL,
209
+ "resolution" JSONB,
210
+ "edited_payload" JSONB,
211
+ "decision" "kg_proposal_item_decision" NOT NULL DEFAULT 'pending',
212
+ "flags" TEXT[] DEFAULT ARRAY[]::TEXT[],
213
+ "origin" "kg_proposal_item_origin" NOT NULL DEFAULT 'ai',
214
+ "merge_into_id" UUID,
215
+ "distinct_from" TEXT[] DEFAULT ARRAY[]::TEXT[],
216
+ "committed_ref_id" UUID,
217
+ "sort_order" INTEGER NOT NULL DEFAULT 0,
218
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
219
+ "updated_at" TIMESTAMPTZ NOT NULL,
220
+
221
+ CONSTRAINT "kg_proposal_items_pkey" PRIMARY KEY ("id")
222
+ );
223
+
224
+ -- CreateTable
225
+ CREATE TABLE "kg_merges" (
226
+ "id" UUID NOT NULL,
227
+ "owner_id" UUID NOT NULL,
228
+ "survivor_id" UUID NOT NULL,
229
+ "merged_id" UUID NOT NULL,
230
+ "reversal" JSONB NOT NULL,
231
+ "reversed_at" TIMESTAMPTZ,
232
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
233
+
234
+ CONSTRAINT "kg_merges_pkey" PRIMARY KEY ("id")
235
+ );
236
+
237
+ -- CreateTable
238
+ CREATE TABLE "kg_distinct_pairs" (
239
+ "owner_id" UUID NOT NULL,
240
+ "a_id" UUID NOT NULL,
241
+ "b_id" UUID NOT NULL,
242
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
243
+
244
+ CONSTRAINT "kg_distinct_pairs_pkey" PRIMARY KEY ("owner_id","a_id","b_id")
245
+ );
246
+
247
+ -- CreateTable
248
+ CREATE TABLE "kg_attribute_defs" (
249
+ "id" UUID NOT NULL,
250
+ "owner_id" UUID NOT NULL,
251
+ "entity_type" TEXT NOT NULL,
252
+ "key" TEXT NOT NULL,
253
+ "label" TEXT NOT NULL,
254
+ "kind" "kg_attribute_kind" NOT NULL,
255
+ "options" JSONB,
256
+ "extractable" BOOLEAN NOT NULL DEFAULT false,
257
+ "extraction_hint" TEXT,
258
+ "sensitivity" "kg_sensitivity",
259
+ "sort_order" INTEGER NOT NULL DEFAULT 0,
260
+ "deprecated_at" TIMESTAMPTZ,
261
+ "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
262
+ "updated_at" TIMESTAMPTZ NOT NULL,
263
+
264
+ CONSTRAINT "kg_attribute_defs_pkey" PRIMARY KEY ("id")
265
+ );
266
+
267
+ -- CreateTable
268
+ CREATE TABLE "kg_entity_digests" (
269
+ "entity_id" UUID NOT NULL,
270
+ "owner_id" UUID NOT NULL,
271
+ "summary" TEXT NOT NULL,
272
+ "citations" JSONB NOT NULL,
273
+ "covers_until" TIMESTAMPTZ NOT NULL,
274
+ "model" TEXT NOT NULL,
275
+ "generated_at" TIMESTAMPTZ NOT NULL,
276
+
277
+ CONSTRAINT "kg_entity_digests_pkey" PRIMARY KEY ("entity_id")
278
+ );
279
+
280
+ -- CreateTable
281
+ CREATE TABLE "kg_entity_views" (
282
+ "id" UUID NOT NULL,
283
+ "user_id" UUID NOT NULL,
284
+ "entity_id" UUID NOT NULL,
285
+ "last_viewed_at" TIMESTAMPTZ NOT NULL,
286
+
287
+ CONSTRAINT "kg_entity_views_pkey" PRIMARY KEY ("id")
288
+ );
289
+
290
+ -- CreateIndex
291
+ CREATE INDEX "kg_entities_owner_id_type_review_status_idx" ON "kg_entities"("owner_id", "type", "review_status");
292
+
293
+ -- CreateIndex
294
+ CREATE INDEX "kg_entities_owner_id_updated_at_idx" ON "kg_entities"("owner_id", "updated_at" DESC);
295
+
296
+ -- CreateIndex
297
+ CREATE INDEX "kg_entities_merged_into_id_idx" ON "kg_entities"("merged_into_id");
298
+
299
+ -- CreateIndex
300
+ CREATE INDEX "kg_entity_aliases_owner_id_normalized_idx" ON "kg_entity_aliases"("owner_id", "normalized");
301
+
302
+ -- CreateIndex
303
+ CREATE INDEX "kg_entity_aliases_entity_id_idx" ON "kg_entity_aliases"("entity_id");
304
+
305
+ -- CreateIndex
306
+ CREATE UNIQUE INDEX "kg_entity_aliases_entity_id_normalized_key" ON "kg_entity_aliases"("entity_id", "normalized");
307
+
308
+ -- CreateIndex
309
+ CREATE INDEX "kg_relations_owner_id_from_id_type_idx" ON "kg_relations"("owner_id", "from_id", "type");
310
+
311
+ -- CreateIndex
312
+ CREATE INDEX "kg_relations_owner_id_to_id_type_idx" ON "kg_relations"("owner_id", "to_id", "type");
313
+
314
+ -- CreateIndex
315
+ CREATE INDEX "kg_relations_from_speaker_id_idx" ON "kg_relations"("from_speaker_id");
316
+
317
+ -- CreateIndex
318
+ CREATE INDEX "kg_relations_superseded_by_id_idx" ON "kg_relations"("superseded_by_id");
319
+
320
+ -- CreateIndex
321
+ CREATE INDEX "kg_relations_owner_id_type_review_status_idx" ON "kg_relations"("owner_id", "type", "review_status");
322
+
323
+ -- CreateIndex
324
+ CREATE INDEX "kg_items_owner_id_subject_id_occurred_at_idx" ON "kg_items"("owner_id", "subject_id", "occurred_at" DESC);
325
+
326
+ -- CreateIndex
327
+ CREATE INDEX "kg_items_owner_id_kind_status_idx" ON "kg_items"("owner_id", "kind", "status");
328
+
329
+ -- CreateIndex
330
+ CREATE INDEX "kg_items_owner_id_statement_hash_idx" ON "kg_items"("owner_id", "statement_hash");
331
+
332
+ -- CreateIndex
333
+ CREATE INDEX "kg_items_owner_person_id_idx" ON "kg_items"("owner_person_id");
334
+
335
+ -- CreateIndex
336
+ CREATE INDEX "kg_items_counterparty_id_idx" ON "kg_items"("counterparty_id");
337
+
338
+ -- CreateIndex
339
+ CREATE INDEX "kg_items_meeting_id_idx" ON "kg_items"("meeting_id");
340
+
341
+ -- CreateIndex
342
+ CREATE INDEX "kg_items_superseded_by_id_idx" ON "kg_items"("superseded_by_id");
343
+
344
+ -- CreateIndex
345
+ CREATE INDEX "kg_evidence_subject_kind_subject_id_idx" ON "kg_evidence"("subject_kind", "subject_id");
346
+
347
+ -- CreateIndex
348
+ CREATE INDEX "kg_evidence_owner_id_transcript_id_idx" ON "kg_evidence"("owner_id", "transcript_id");
349
+
350
+ -- CreateIndex
351
+ CREATE INDEX "kg_evidence_segment_id_idx" ON "kg_evidence"("segment_id");
352
+
353
+ -- CreateIndex
354
+ CREATE INDEX "kg_evidence_owner_id_note_id_idx" ON "kg_evidence"("owner_id", "note_id");
355
+
356
+ -- CreateIndex
357
+ CREATE INDEX "kg_mentions_owner_id_entity_id_idx" ON "kg_mentions"("owner_id", "entity_id");
358
+
359
+ -- CreateIndex
360
+ CREATE INDEX "kg_mentions_note_id_idx" ON "kg_mentions"("note_id");
361
+
362
+ -- CreateIndex
363
+ CREATE INDEX "kg_mentions_transcript_id_idx" ON "kg_mentions"("transcript_id");
364
+
365
+ -- CreateIndex
366
+ CREATE UNIQUE INDEX "kg_proposals_job_id_key" ON "kg_proposals"("job_id");
367
+
368
+ -- CreateIndex
369
+ CREATE INDEX "kg_proposals_owner_id_status_created_at_idx" ON "kg_proposals"("owner_id", "status", "created_at" DESC);
370
+
371
+ -- CreateIndex
372
+ CREATE INDEX "kg_proposals_note_id_created_at_idx" ON "kg_proposals"("note_id", "created_at" DESC);
373
+
374
+ -- CreateIndex
375
+ CREATE INDEX "kg_proposal_items_proposal_id_kind_sort_order_idx" ON "kg_proposal_items"("proposal_id", "kind", "sort_order");
376
+
377
+ -- CreateIndex
378
+ CREATE INDEX "kg_merges_owner_id_created_at_idx" ON "kg_merges"("owner_id", "created_at" DESC);
379
+
380
+ -- CreateIndex
381
+ CREATE INDEX "kg_merges_survivor_id_idx" ON "kg_merges"("survivor_id");
382
+
383
+ -- CreateIndex
384
+ CREATE INDEX "kg_merges_merged_id_idx" ON "kg_merges"("merged_id");
385
+
386
+ -- CreateIndex
387
+ CREATE INDEX "kg_attribute_defs_owner_id_entity_type_sort_order_idx" ON "kg_attribute_defs"("owner_id", "entity_type", "sort_order");
388
+
389
+ -- CreateIndex
390
+ CREATE UNIQUE INDEX "kg_attribute_defs_owner_id_entity_type_key_key" ON "kg_attribute_defs"("owner_id", "entity_type", "key");
391
+
392
+ -- CreateIndex
393
+ CREATE INDEX "kg_entity_digests_owner_id_idx" ON "kg_entity_digests"("owner_id");
394
+
395
+ -- CreateIndex
396
+ CREATE UNIQUE INDEX "kg_entity_views_user_id_entity_id_key" ON "kg_entity_views"("user_id", "entity_id");
397
+
398
+ -- AddForeignKey
399
+ ALTER TABLE "kg_entities" ADD CONSTRAINT "kg_entities_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
400
+
401
+ -- AddForeignKey
402
+ ALTER TABLE "kg_entities" ADD CONSTRAINT "kg_entities_merged_into_id_fkey" FOREIGN KEY ("merged_into_id") REFERENCES "kg_entities"("id") ON DELETE SET NULL ON UPDATE CASCADE;
403
+
404
+ -- AddForeignKey
405
+ ALTER TABLE "kg_entity_aliases" ADD CONSTRAINT "kg_entity_aliases_entity_id_fkey" FOREIGN KEY ("entity_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
406
+
407
+ -- AddForeignKey
408
+ ALTER TABLE "kg_entity_aliases" ADD CONSTRAINT "kg_entity_aliases_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
409
+
410
+ -- AddForeignKey
411
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
412
+
413
+ -- AddForeignKey
414
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_from_id_fkey" FOREIGN KEY ("from_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
415
+
416
+ -- AddForeignKey
417
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_from_speaker_id_fkey" FOREIGN KEY ("from_speaker_id") REFERENCES "transcript_speakers"("id") ON DELETE CASCADE ON UPDATE CASCADE;
418
+
419
+ -- AddForeignKey
420
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_to_id_fkey" FOREIGN KEY ("to_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
421
+
422
+ -- AddForeignKey
423
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_superseded_by_id_fkey" FOREIGN KEY ("superseded_by_id") REFERENCES "kg_relations"("id") ON DELETE SET NULL ON UPDATE CASCADE;
424
+
425
+ -- AddForeignKey
426
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
427
+
428
+ -- AddForeignKey
429
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_subject_id_fkey" FOREIGN KEY ("subject_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
430
+
431
+ -- AddForeignKey
432
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_meeting_id_fkey" FOREIGN KEY ("meeting_id") REFERENCES "kg_entities"("id") ON DELETE SET NULL ON UPDATE CASCADE;
433
+
434
+ -- AddForeignKey
435
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_owner_person_id_fkey" FOREIGN KEY ("owner_person_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
436
+
437
+ -- AddForeignKey
438
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_counterparty_id_fkey" FOREIGN KEY ("counterparty_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
439
+
440
+ -- AddForeignKey
441
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_superseded_by_id_fkey" FOREIGN KEY ("superseded_by_id") REFERENCES "kg_items"("id") ON DELETE SET NULL ON UPDATE CASCADE;
442
+
443
+ -- AddForeignKey
444
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
445
+
446
+ -- AddForeignKey
447
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE SET NULL ON UPDATE CASCADE;
448
+
449
+ -- AddForeignKey
450
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_segment_id_fkey" FOREIGN KEY ("segment_id") REFERENCES "transcript_segments"("id") ON DELETE SET NULL ON UPDATE CASCADE;
451
+
452
+ -- AddForeignKey
453
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_note_id_fkey" FOREIGN KEY ("note_id") REFERENCES "notes"("id") ON DELETE SET NULL ON UPDATE CASCADE;
454
+
455
+ -- AddForeignKey
456
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_import_object_id_fkey" FOREIGN KEY ("import_object_id") REFERENCES "storage_objects"("id") ON DELETE SET NULL ON UPDATE CASCADE;
457
+
458
+ -- AddForeignKey
459
+ ALTER TABLE "kg_mentions" ADD CONSTRAINT "kg_mentions_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
460
+
461
+ -- AddForeignKey
462
+ ALTER TABLE "kg_mentions" ADD CONSTRAINT "kg_mentions_entity_id_fkey" FOREIGN KEY ("entity_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
463
+
464
+ -- AddForeignKey
465
+ ALTER TABLE "kg_mentions" ADD CONSTRAINT "kg_mentions_note_id_fkey" FOREIGN KEY ("note_id") REFERENCES "notes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
466
+
467
+ -- AddForeignKey
468
+ ALTER TABLE "kg_mentions" ADD CONSTRAINT "kg_mentions_transcript_id_fkey" FOREIGN KEY ("transcript_id") REFERENCES "transcripts"("id") ON DELETE CASCADE ON UPDATE CASCADE;
469
+
470
+ -- AddForeignKey
471
+ ALTER TABLE "kg_proposals" ADD CONSTRAINT "kg_proposals_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
472
+
473
+ -- AddForeignKey
474
+ ALTER TABLE "kg_proposals" ADD CONSTRAINT "kg_proposals_note_id_fkey" FOREIGN KEY ("note_id") REFERENCES "notes"("id") ON DELETE SET NULL ON UPDATE CASCADE;
475
+
476
+ -- AddForeignKey
477
+ ALTER TABLE "kg_proposals" ADD CONSTRAINT "kg_proposals_job_id_fkey" FOREIGN KEY ("job_id") REFERENCES "jobs"("id") ON DELETE SET NULL ON UPDATE CASCADE;
478
+
479
+ -- AddForeignKey
480
+ ALTER TABLE "kg_proposal_items" ADD CONSTRAINT "kg_proposal_items_proposal_id_fkey" FOREIGN KEY ("proposal_id") REFERENCES "kg_proposals"("id") ON DELETE CASCADE ON UPDATE CASCADE;
481
+
482
+ -- AddForeignKey
483
+ ALTER TABLE "kg_proposal_items" ADD CONSTRAINT "kg_proposal_items_merge_into_id_fkey" FOREIGN KEY ("merge_into_id") REFERENCES "kg_entities"("id") ON DELETE SET NULL ON UPDATE CASCADE;
484
+
485
+ -- AddForeignKey
486
+ ALTER TABLE "kg_merges" ADD CONSTRAINT "kg_merges_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
487
+
488
+ -- AddForeignKey
489
+ ALTER TABLE "kg_merges" ADD CONSTRAINT "kg_merges_survivor_id_fkey" FOREIGN KEY ("survivor_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
490
+
491
+ -- AddForeignKey
492
+ ALTER TABLE "kg_merges" ADD CONSTRAINT "kg_merges_merged_id_fkey" FOREIGN KEY ("merged_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
493
+
494
+ -- AddForeignKey
495
+ ALTER TABLE "kg_distinct_pairs" ADD CONSTRAINT "kg_distinct_pairs_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
496
+
497
+ -- AddForeignKey
498
+ ALTER TABLE "kg_distinct_pairs" ADD CONSTRAINT "kg_distinct_pairs_a_id_fkey" FOREIGN KEY ("a_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
499
+
500
+ -- AddForeignKey
501
+ ALTER TABLE "kg_distinct_pairs" ADD CONSTRAINT "kg_distinct_pairs_b_id_fkey" FOREIGN KEY ("b_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
502
+
503
+ -- AddForeignKey
504
+ ALTER TABLE "kg_attribute_defs" ADD CONSTRAINT "kg_attribute_defs_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
505
+
506
+ -- AddForeignKey
507
+ ALTER TABLE "kg_entity_digests" ADD CONSTRAINT "kg_entity_digests_entity_id_fkey" FOREIGN KEY ("entity_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
508
+
509
+ -- AddForeignKey
510
+ ALTER TABLE "kg_entity_digests" ADD CONSTRAINT "kg_entity_digests_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
511
+
512
+ -- AddForeignKey
513
+ ALTER TABLE "kg_entity_views" ADD CONSTRAINT "kg_entity_views_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
514
+
515
+ -- AddForeignKey
516
+ ALTER TABLE "kg_entity_views" ADD CONSTRAINT "kg_entity_views_entity_id_fkey" FOREIGN KEY ("entity_id") REFERENCES "kg_entities"("id") ON DELETE CASCADE ON UPDATE CASCADE;
517
+
518
+ -- =============================================================================
519
+ -- HAND-WRITTEN, PRISMA-INEXPRESSIBLE SQL (issue #351)
520
+ -- =============================================================================
521
+ --
522
+ -- Everything below is intentional schema drift, in the same family as
523
+ -- `jobs_active_dedup_uniq_idx`, `database_backup_runs_active_uniq_idx`,
524
+ -- `transcript_speakers_transcript_id_label_key`, the transcript/note
525
+ -- generated `tsvector` columns, and `search_embeddings_embedding_hnsw_idx`.
526
+ -- Prisma's schema DSL has no way to express a trigram opclass, `USING gist`,
527
+ -- `USING hnsw`, a partial `WHERE` clause on a unique index, or a
528
+ -- cross-column/CASE-shaped CHECK constraint — every statement below is one
529
+ -- of those five, lives ONLY here, and `prisma migrate dev`/`diff` will
530
+ -- propose to drop all of it on every future schema change. WHEN THAT
531
+ -- HAPPENS, DELETE THE PROPOSED `DROP INDEX`/`DROP CONSTRAINT` LINES FROM THE
532
+ -- NEW MIGRATION — do not apply them, and do not try to force any of this
533
+ -- into `@@index`/`@@unique` syntax that does not exist.
534
+ --
535
+ -- `pg_trgm` IS A NEW MIGRATION REQUIREMENT FOR THIS CODEBASE — pgvector
536
+ -- already is not (`SearchEmbedding` already depends on it). It is a trusted
537
+ -- extension on PostgreSQL 13+, so the migration role needs no superuser, and
538
+ -- CI's `pgvector/pgvector:pg16` image ships it in contrib already.
539
+ CREATE EXTENSION IF NOT EXISTS pg_trgm;
540
+
541
+ -- -----------------------------------------------------------------------------
542
+ -- TRIGRAM INDEXES — fuzzy candidate generation (§7). `EXPLAIN … WHERE
543
+ -- normalized % 'sarah chen'` (with `enable_seqscan = off`) must use the
544
+ -- second of these two.
545
+ -- -----------------------------------------------------------------------------
546
+ CREATE INDEX "kg_entities_label_trgm_idx" ON "kg_entities" USING gin ("label" gin_trgm_ops);
547
+ CREATE INDEX "kg_entity_aliases_normalized_trgm_idx" ON "kg_entity_aliases" USING gin ("normalized" gin_trgm_ops);
548
+
549
+ -- -----------------------------------------------------------------------------
550
+ -- RANGE (GiST) INDEXES — §5.4's bitemporal model. `valid` is
551
+ -- `Unsupported("tstzrange")` in schema.prisma (see the block comment above
552
+ -- `KgRelation`): Prisma cannot construct, bind or select a range value, so
553
+ -- every write goes through `$executeRaw` and every read through
554
+ -- `$queryRaw(lower(valid), upper(valid), lower_inc(valid), upper_inc(valid))`
555
+ -- — #353 provides `toPgRange`/`fromPgRange` for exactly this. `EXPLAIN …
556
+ -- WHERE valid @> now()` (with `enable_seqscan = off`) must use these.
557
+ -- -----------------------------------------------------------------------------
558
+ CREATE INDEX "kg_relations_valid_gist_idx" ON "kg_relations" USING gist ("valid");
559
+ CREATE INDEX "kg_items_valid_gist_idx" ON "kg_items" USING gist ("valid");
560
+
561
+ -- -----------------------------------------------------------------------------
562
+ -- HNSW (VECTOR) INDEXES — matching `search_embeddings_embedding_hnsw_idx`'s
563
+ -- own discipline exactly: built against an empty table (HNSW needs no
564
+ -- representative sample, unlike IVFFlat), and `vector_cosine_ops` to match
565
+ -- the `<=>` operator any future ranking query uses — an HNSW index whose
566
+ -- opclass disagrees with the query's distance operator is silently unusable,
567
+ -- not merely slower. See that migration's own header for the full argument.
568
+ -- -----------------------------------------------------------------------------
569
+ CREATE INDEX "kg_entities_embedding_hnsw_idx" ON "kg_entities" USING hnsw ("embedding" vector_cosine_ops);
570
+ CREATE INDEX "kg_items_embedding_hnsw_idx" ON "kg_items" USING hnsw ("embedding" vector_cosine_ops);
571
+
572
+ -- -----------------------------------------------------------------------------
573
+ -- PARTIAL UNIQUE INDEXES — enforced in the database, never by a `findFirst`
574
+ -- before the insert, which cannot close the race a concurrent request needs
575
+ -- closed (the `database_backup_runs_active_uniq_idx` reasoning).
576
+ -- -----------------------------------------------------------------------------
577
+
578
+ -- The §8 "known, skipped" dedup guard: a verbatim restatement of an
579
+ -- already-live item attaches evidence instead of inserting a duplicate.
580
+ -- Scoped to accepted/edited rows with a subject so a rejected row's hash
581
+ -- never blocks a legitimate later insert, and an item with no subject
582
+ -- (impossible for claim/person_fact per `kg_items_subject_required_chk`,
583
+ -- but representable for commitment/decision) is never deduped by this index.
584
+ CREATE UNIQUE INDEX "kg_items_live_statement_uniq_idx"
585
+ ON "kg_items" ("owner_id", "kind", "subject_id", "statement_hash")
586
+ WHERE "review_status" IN ('accepted', 'edited') AND "subject_id" IS NOT NULL;
587
+
588
+ -- At most one OPEN draft per note. Whoever creates a new draft discards the
589
+ -- previous one in the same transaction (#363) — this index is what makes
590
+ -- "at most one" true under a race, not the service-layer discard alone.
591
+ CREATE UNIQUE INDEX "kg_proposals_note_draft_uniq_idx"
592
+ ON "kg_proposals" ("note_id") WHERE "status" = 'draft';
593
+
594
+ -- At most one RUNNING extraction per note (#363's 409 `extraction_running`).
595
+ CREATE UNIQUE INDEX "kg_proposals_note_extracting_uniq_idx"
596
+ ON "kg_proposals" ("note_id") WHERE "status" = 'extracting';
597
+
598
+ -- At most one RUNNING import per OWNER (#387's) — scoped by owner_id, not
599
+ -- note_id, because an import proposal has no note at all
600
+ -- (`kg_proposals_note_source_chk` below requires note_id NULL for it).
601
+ CREATE UNIQUE INDEX "kg_proposals_owner_import_extracting_uniq_idx"
602
+ ON "kg_proposals" ("owner_id") WHERE "kind" = 'import' AND "status" = 'extracting';
603
+
604
+ -- At most one `IDENTIFIED_AS` edge per diarized speaker.
605
+ CREATE UNIQUE INDEX "kg_relations_speaker_link_uniq_idx"
606
+ ON "kg_relations" ("from_speaker_id") WHERE "from_speaker_id" IS NOT NULL;
607
+
608
+ -- -----------------------------------------------------------------------------
609
+ -- CHECK CONSTRAINTS.
610
+ -- -----------------------------------------------------------------------------
611
+
612
+ -- Canonicalizes an unordered pair into exactly one storable row: (a, b) and
613
+ -- (b, a) can never both be inserted as two different "confirmed distinct"
614
+ -- facts about the same two entities.
615
+ ALTER TABLE "kg_distinct_pairs" ADD CONSTRAINT "kg_distinct_pairs_order_chk" CHECK ("a_id" < "b_id");
616
+
617
+ -- A mention always comes from exactly one source document.
618
+ ALTER TABLE "kg_mentions" ADD CONSTRAINT "kg_mentions_one_source_chk"
619
+ CHECK (num_nonnulls("note_id", "transcript_id") = 1);
620
+
621
+ -- A relation's `from` side is EITHER a resolved entity OR a diarized speaker
622
+ -- awaiting `IDENTIFIED_AS`, never both, never neither.
623
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_one_source_chk"
624
+ CHECK (num_nonnulls("from_id", "from_speaker_id") = 1);
625
+
626
+ -- `from_speaker_id` exists for exactly one relation type, and no other.
627
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_speaker_type_chk"
628
+ CHECK ("from_speaker_id" IS NULL OR "type" = 'IDENTIFIED_AS');
629
+
630
+ -- A temporal relation always states a precision, but `unknown` stays
631
+ -- representable even should `valid` itself later be cleared while a
632
+ -- precision remains on record as having once been claimed.
633
+ ALTER TABLE "kg_relations" ADD CONSTRAINT "kg_relations_valid_precision_chk"
634
+ CHECK (("valid" IS NULL) = ("valid_precision" IS NULL) OR "valid_precision" = 'unknown');
635
+
636
+ -- Sensitivity is meaningful for exactly one item kind (§5.6): a claim with a
637
+ -- sensitivity, or a person fact with none, are both unrepresentable.
638
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_sensitivity_chk"
639
+ CHECK (("kind" = 'person_fact') = ("sensitivity" IS NOT NULL));
640
+
641
+ -- A claim or a person fact is always ABOUT something; a commitment/decision
642
+ -- may stand on its own.
643
+ ALTER TABLE "kg_items" ADD CONSTRAINT "kg_items_subject_required_chk"
644
+ CHECK ("kind" NOT IN ('claim', 'person_fact') OR "subject_id" IS NOT NULL);
645
+
646
+ -- An end offset, when both ends are given, is never before its start. There
647
+ -- is deliberately NO CHECK requiring an anchor to be present at all — see
648
+ -- this migration's schema.prisma block comment above `KgEvidence` ("WHY
649
+ -- THERE IS NO ANCHOR CHECK"): every anchor FK is SetNull, and a fully
650
+ -- anchorless evidence row (every FK NULL, `quote` intact) is a valid,
651
+ -- expected end state, not a bug to prevent.
652
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_char_range_chk"
653
+ CHECK ("char_start" IS NULL OR "char_end" IS NULL OR "char_end" >= "char_start");
654
+ ALTER TABLE "kg_evidence" ADD CONSTRAINT "kg_evidence_ms_range_chk"
655
+ CHECK ("start_ms" IS NULL OR "end_ms" IS NULL OR "end_ms" >= "start_ms");
656
+
657
+ -- `payload` is always a JSON object, never a bare array or scalar, so every
658
+ -- reader can assume key access without a type guard.
659
+ ALTER TABLE "kg_proposal_items" ADD CONSTRAINT "kg_proposal_items_kind_payload_chk"
660
+ CHECK (jsonb_typeof("payload") = 'object');
661
+
662
+ -- The override column and the decision it overrides can never disagree
663
+ -- about which decision this row represents. `merge_into_id` is SetNull:
664
+ -- forgetting or purging the target entity clears the override, and the row
665
+ -- falls back to `pending` semantics at commit (#366 refuses a `merge_into`
666
+ -- row without a target).
667
+ ALTER TABLE "kg_proposal_items" ADD CONSTRAINT "kg_proposal_items_merge_into_chk"
668
+ CHECK ("merge_into_id" IS NULL OR "decision" = 'merge_into');
669
+
670
+ -- Only `kind = 'extraction'` has a note. Keys on `note_version`, NEVER on
671
+ -- `note_id`, and this is deliberate: `note_id` is inserted non-null for
672
+ -- every extraction proposal and can only become NULL afterwards through the
673
+ -- note's own SetNull FK once the note is hard-deleted. A CHECK keyed on
674
+ -- `note_id` would then start failing for rows that were valid when written;
675
+ -- a CHECK keyed on `note_version` (never nulled by any FK action) stays
676
+ -- satisfied for the life of the row, so hard-deleting a note never violates
677
+ -- this constraint on its own extraction proposals.
678
+ ALTER TABLE "kg_proposals" ADD CONSTRAINT "kg_proposals_note_source_chk"
679
+ CHECK (CASE WHEN "kind" = 'extraction' THEN "note_version" IS NOT NULL
680
+ ELSE "note_id" IS NULL AND "note_version" IS NULL END);