@opengeni/db 0.19.0 → 0.22.1

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.
@@ -0,0 +1,603 @@
1
+ import { sql } from "drizzle-orm";
2
+ import {
3
+ bigint,
4
+ boolean,
5
+ index,
6
+ integer,
7
+ jsonb,
8
+ pgTable,
9
+ text,
10
+ timestamp,
11
+ uniqueIndex,
12
+ uuid,
13
+ } from "drizzle-orm/pg-core";
14
+
15
+ // Cross-row/composite foreign keys, immutable-history triggers, lifecycle
16
+ // functions, and FORCE-RLS policies live in migration 0154. This schema leaf is
17
+ // deliberately cycle-free so the repository module can use typed table names
18
+ // without making the main schema declaration harder to navigate.
19
+
20
+ function tenantScopeColumns() {
21
+ return {
22
+ accountId: uuid("account_id").notNull(),
23
+ scopeKind: text("scope_kind").notNull(),
24
+ scopeWorkspaceId: uuid("scope_workspace_id"),
25
+ scopeSubjectId: text("scope_subject_id"),
26
+ scopeKey: text("scope_key").notNull(),
27
+ };
28
+ }
29
+
30
+ function actorColumns() {
31
+ return {
32
+ actorKind: text("actor_kind").notNull(),
33
+ actorSubjectId: text("actor_subject_id").notNull(),
34
+ initiatingHumanSubjectId: text("initiating_human_subject_id"),
35
+ };
36
+ }
37
+
38
+ export const knowledgeOperationReceipts = pgTable(
39
+ "knowledge_operation_receipts",
40
+ {
41
+ id: uuid("id").primaryKey().defaultRandom(),
42
+ ...tenantScopeColumns(),
43
+ operationKind: text("operation_kind").notNull(),
44
+ operationNamespace: text("operation_namespace").notNull(),
45
+ operationId: text("operation_id").notNull(),
46
+ inputHash: text("input_hash").notNull(),
47
+ resultId: uuid("result_id").notNull(),
48
+ ...actorColumns(),
49
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
50
+ },
51
+ (table) => ({
52
+ operation: uniqueIndex("knowledge_operation_receipts_operation_uq").on(
53
+ table.accountId,
54
+ table.operationKind,
55
+ table.operationNamespace,
56
+ table.operationId,
57
+ ),
58
+ result: index("knowledge_operation_receipts_result_idx").on(
59
+ table.operationKind,
60
+ table.resultId,
61
+ ),
62
+ }),
63
+ );
64
+
65
+ export const knowledgeProviders = pgTable(
66
+ "knowledge_providers",
67
+ {
68
+ id: uuid("id").primaryKey().defaultRandom(),
69
+ ...tenantScopeColumns(),
70
+ providerKey: text("provider_key").notNull(),
71
+ externalTenantId: text("external_tenant_id").notNull(),
72
+ lifecycleState: text("lifecycle_state").notNull().default("active"),
73
+ lifecycleGeneration: bigint("lifecycle_generation", { mode: "number" }).notNull().default(1),
74
+ operationId: text("operation_id").notNull(),
75
+ inputHash: text("input_hash").notNull(),
76
+ ...actorColumns(),
77
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
78
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
79
+ },
80
+ (table) => ({
81
+ externalIdentity: uniqueIndex("knowledge_providers_external_identity_uq").on(
82
+ table.accountId,
83
+ table.providerKey,
84
+ table.externalTenantId,
85
+ ),
86
+ operation: uniqueIndex("knowledge_providers_operation_uq").on(
87
+ table.accountId,
88
+ table.operationId,
89
+ ),
90
+ scopeIdentity: uniqueIndex("knowledge_providers_scope_identity_uq").on(
91
+ table.accountId,
92
+ table.id,
93
+ table.scopeKey,
94
+ ),
95
+ scopeLifecycle: index("knowledge_providers_scope_lifecycle_idx").on(
96
+ table.accountId,
97
+ table.scopeKey,
98
+ table.lifecycleState,
99
+ ),
100
+ }),
101
+ );
102
+
103
+ export const knowledgeSources = pgTable(
104
+ "knowledge_sources",
105
+ {
106
+ id: uuid("id").primaryKey().defaultRandom(),
107
+ ...tenantScopeColumns(),
108
+ providerId: uuid("provider_id").notNull(),
109
+ externalSourceId: text("external_source_id").notNull(),
110
+ sourceKind: text("source_kind").notNull(),
111
+ sourceUri: text("source_uri"),
112
+ currentAclGeneration: bigint("current_acl_generation", { mode: "number" }),
113
+ syncGeneration: bigint("sync_generation", { mode: "number" }).notNull().default(0),
114
+ syncCursor: text("sync_cursor"),
115
+ lifecycleState: text("lifecycle_state").notNull().default("active"),
116
+ lifecycleGeneration: bigint("lifecycle_generation", { mode: "number" }).notNull().default(1),
117
+ operationId: text("operation_id").notNull(),
118
+ inputHash: text("input_hash").notNull(),
119
+ ...actorColumns(),
120
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
121
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
122
+ },
123
+ (table) => ({
124
+ externalIdentity: uniqueIndex("knowledge_sources_external_identity_uq").on(
125
+ table.providerId,
126
+ table.externalSourceId,
127
+ ),
128
+ operation: uniqueIndex("knowledge_sources_operation_uq").on(table.accountId, table.operationId),
129
+ scopeIdentity: uniqueIndex("knowledge_sources_scope_identity_uq").on(
130
+ table.accountId,
131
+ table.id,
132
+ table.scopeKey,
133
+ ),
134
+ currentAcl: uniqueIndex("knowledge_sources_current_acl_identity_uq").on(
135
+ table.accountId,
136
+ table.id,
137
+ table.currentAclGeneration,
138
+ ),
139
+ provider: index("knowledge_sources_provider_idx").on(table.providerId, table.externalSourceId),
140
+ }),
141
+ );
142
+
143
+ export const knowledgeSourceAclVersions = pgTable(
144
+ "knowledge_source_acl_versions",
145
+ {
146
+ id: uuid("id").primaryKey().defaultRandom(),
147
+ ...tenantScopeColumns(),
148
+ sourceId: uuid("source_id").notNull(),
149
+ sourceScopeKey: text("source_scope_key").notNull(),
150
+ generation: bigint("generation", { mode: "number" }).notNull(),
151
+ aclVersion: text("acl_version"),
152
+ aclHash: text("acl_hash").notNull(),
153
+ agentAccess: boolean("agent_access").notNull().default(true),
154
+ operationId: text("operation_id").notNull(),
155
+ inputHash: text("input_hash").notNull(),
156
+ ...actorColumns(),
157
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
158
+ },
159
+ (table) => ({
160
+ sourceGeneration: uniqueIndex("knowledge_source_acl_versions_source_generation_uq").on(
161
+ table.accountId,
162
+ table.sourceId,
163
+ table.generation,
164
+ ),
165
+ sourceOperation: uniqueIndex("knowledge_source_acl_versions_source_operation_uq").on(
166
+ table.sourceId,
167
+ table.operationId,
168
+ ),
169
+ sourceTimeline: index("knowledge_source_acl_versions_source_timeline_idx").on(
170
+ table.sourceId,
171
+ table.generation,
172
+ ),
173
+ }),
174
+ );
175
+
176
+ export const knowledgeSyncRuns = pgTable(
177
+ "knowledge_sync_runs",
178
+ {
179
+ id: uuid("id").primaryKey().defaultRandom(),
180
+ ...tenantScopeColumns(),
181
+ sourceId: uuid("source_id").notNull(),
182
+ inputSyncGeneration: bigint("input_sync_generation", { mode: "number" }).notNull(),
183
+ inputLifecycleGeneration: bigint("input_lifecycle_generation", { mode: "number" }).notNull(),
184
+ inputCursor: text("input_cursor"),
185
+ inputHash: text("input_hash").notNull(),
186
+ operationId: text("operation_id").notNull(),
187
+ state: text("state").notNull().default("started"),
188
+ outputCursor: text("output_cursor"),
189
+ watermark: timestamp("watermark", { withTimezone: true }),
190
+ metadata: jsonb("metadata").$type<Record<string, unknown>>().notNull().default({}),
191
+ errorCode: text("error_code"),
192
+ completionHash: text("completion_hash"),
193
+ ...actorColumns(),
194
+ startedAt: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
195
+ completedAt: timestamp("completed_at", { withTimezone: true }),
196
+ },
197
+ (table) => ({
198
+ sourceOperation: uniqueIndex("knowledge_sync_runs_source_operation_uq").on(
199
+ table.sourceId,
200
+ table.operationId,
201
+ ),
202
+ sourceState: index("knowledge_sync_runs_source_state_idx").on(
203
+ table.sourceId,
204
+ table.state,
205
+ table.startedAt,
206
+ ),
207
+ }),
208
+ );
209
+
210
+ export const knowledgeSourceObjects = pgTable(
211
+ "knowledge_source_objects",
212
+ {
213
+ id: uuid("id").primaryKey().defaultRandom(),
214
+ ...tenantScopeColumns(),
215
+ sourceId: uuid("source_id").notNull(),
216
+ externalObjectId: text("external_object_id").notNull(),
217
+ documentId: uuid("document_id"),
218
+ lifecycleState: text("lifecycle_state").notNull().default("active"),
219
+ lifecycleGeneration: bigint("lifecycle_generation", { mode: "number" }).notNull().default(1),
220
+ versionGeneration: bigint("version_generation", { mode: "number" }).notNull().default(0),
221
+ currentVersionId: uuid("current_version_id"),
222
+ operationId: text("operation_id").notNull(),
223
+ inputHash: text("input_hash").notNull(),
224
+ ...actorColumns(),
225
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
226
+ updatedAt: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
227
+ },
228
+ (table) => ({
229
+ externalIdentity: uniqueIndex("knowledge_source_objects_external_identity_uq").on(
230
+ table.sourceId,
231
+ table.externalObjectId,
232
+ ),
233
+ sourceOperation: uniqueIndex("knowledge_source_objects_source_operation_uq").on(
234
+ table.sourceId,
235
+ table.operationId,
236
+ ),
237
+ scopeIdentity: uniqueIndex("knowledge_source_objects_scope_identity_uq").on(
238
+ table.accountId,
239
+ table.id,
240
+ table.scopeKey,
241
+ ),
242
+ sourceIdentity: uniqueIndex("knowledge_source_objects_source_identity_uq").on(
243
+ table.accountId,
244
+ table.id,
245
+ table.sourceId,
246
+ table.scopeKey,
247
+ ),
248
+ currentVersion: uniqueIndex("knowledge_source_objects_current_version_identity_uq").on(
249
+ table.accountId,
250
+ table.id,
251
+ table.currentVersionId,
252
+ ),
253
+ }),
254
+ );
255
+
256
+ export const knowledgeDocumentVersions = pgTable(
257
+ "knowledge_document_versions",
258
+ {
259
+ id: uuid("id").primaryKey().defaultRandom(),
260
+ ...tenantScopeColumns(),
261
+ sourceId: uuid("source_id").notNull(),
262
+ objectId: uuid("object_id").notNull(),
263
+ versionGeneration: bigint("version_generation", { mode: "number" }).notNull(),
264
+ externalVersionId: text("external_version_id").notNull(),
265
+ contentSha256: text("content_sha256").notNull(),
266
+ ingestionKey: text("ingestion_key").notNull(),
267
+ sourceCursor: text("source_cursor"),
268
+ sourceMetadata: jsonb("source_metadata").$type<Record<string, unknown>>().notNull().default({}),
269
+ sourceCreatedAt: timestamp("source_created_at", { withTimezone: true }),
270
+ sourceUpdatedAt: timestamp("source_updated_at", { withTimezone: true }),
271
+ observedAt: timestamp("observed_at", { withTimezone: true }).notNull().defaultNow(),
272
+ aclVersionId: uuid("acl_version_id").notNull(),
273
+ aclGeneration: bigint("acl_generation", { mode: "number" }).notNull(),
274
+ documentId: uuid("document_id"),
275
+ fileId: uuid("file_id"),
276
+ locationMetadata: jsonb("location_metadata")
277
+ .$type<Record<string, unknown>>()
278
+ .notNull()
279
+ .default({}),
280
+ operationId: text("operation_id").notNull(),
281
+ inputHash: text("input_hash").notNull(),
282
+ ...actorColumns(),
283
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
284
+ },
285
+ (table) => ({
286
+ objectGeneration: uniqueIndex("knowledge_document_versions_object_generation_uq").on(
287
+ table.accountId,
288
+ table.objectId,
289
+ table.versionGeneration,
290
+ ),
291
+ objectExternalVersion: uniqueIndex("knowledge_document_versions_object_external_version_uq").on(
292
+ table.objectId,
293
+ table.externalVersionId,
294
+ ),
295
+ objectIngestion: uniqueIndex("knowledge_document_versions_object_ingestion_uq").on(
296
+ table.objectId,
297
+ table.ingestionKey,
298
+ ),
299
+ objectOperation: uniqueIndex("knowledge_document_versions_object_operation_uq").on(
300
+ table.objectId,
301
+ table.operationId,
302
+ ),
303
+ objectIdentity: uniqueIndex("knowledge_document_versions_object_identity_uq").on(
304
+ table.accountId,
305
+ table.objectId,
306
+ table.id,
307
+ ),
308
+ scopeIdentity: uniqueIndex("knowledge_document_versions_scope_identity_uq").on(
309
+ table.accountId,
310
+ table.id,
311
+ table.scopeKey,
312
+ ),
313
+ }),
314
+ );
315
+
316
+ export const knowledgeLifecycleEvents = pgTable(
317
+ "knowledge_lifecycle_events",
318
+ {
319
+ id: uuid("id").primaryKey().defaultRandom(),
320
+ ...tenantScopeColumns(),
321
+ targetKind: text("target_kind").notNull(),
322
+ providerId: uuid("provider_id"),
323
+ sourceId: uuid("source_id"),
324
+ objectId: uuid("object_id"),
325
+ eventType: text("event_type").notNull(),
326
+ oldState: text("old_state").notNull(),
327
+ newState: text("new_state").notNull(),
328
+ oldGeneration: bigint("old_generation", { mode: "number" }).notNull(),
329
+ newGeneration: bigint("new_generation", { mode: "number" }).notNull(),
330
+ operationId: text("operation_id").notNull(),
331
+ inputHash: text("input_hash").notNull(),
332
+ reasonCode: text("reason_code").notNull(),
333
+ ...actorColumns(),
334
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
335
+ },
336
+ (table) => ({
337
+ targetTimeline: index("knowledge_lifecycle_events_target_timeline_idx").on(
338
+ table.targetKind,
339
+ table.providerId,
340
+ table.sourceId,
341
+ table.objectId,
342
+ table.createdAt,
343
+ ),
344
+ }),
345
+ );
346
+
347
+ export const knowledgeEntities = pgTable(
348
+ "knowledge_entities",
349
+ {
350
+ id: uuid("id").primaryKey().defaultRandom(),
351
+ ...tenantScopeColumns(),
352
+ entityType: text("entity_type").notNull(),
353
+ normalizedKey: text("normalized_key").notNull(),
354
+ displayName: text("display_name").notNull(),
355
+ operationId: text("operation_id").notNull(),
356
+ inputHash: text("input_hash").notNull(),
357
+ ...actorColumns(),
358
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
359
+ },
360
+ (table) => ({
361
+ naturalIdentity: uniqueIndex("knowledge_entities_natural_identity_uq").on(
362
+ table.accountId,
363
+ table.scopeKey,
364
+ table.entityType,
365
+ table.normalizedKey,
366
+ ),
367
+ operation: uniqueIndex("knowledge_entities_operation_uq").on(
368
+ table.accountId,
369
+ table.operationId,
370
+ ),
371
+ scopeIdentity: uniqueIndex("knowledge_entities_scope_identity_uq").on(
372
+ table.accountId,
373
+ table.id,
374
+ table.scopeKey,
375
+ ),
376
+ }),
377
+ );
378
+
379
+ export const knowledgeEntityAliases = pgTable(
380
+ "knowledge_entity_aliases",
381
+ {
382
+ id: uuid("id").primaryKey().defaultRandom(),
383
+ ...tenantScopeColumns(),
384
+ entityId: uuid("entity_id").notNull(),
385
+ entityType: text("entity_type").notNull(),
386
+ alias: text("alias").notNull(),
387
+ normalizedAlias: text("normalized_alias").notNull(),
388
+ operationId: text("operation_id").notNull(),
389
+ inputHash: text("input_hash").notNull(),
390
+ ...actorColumns(),
391
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
392
+ },
393
+ (table) => ({
394
+ naturalIdentity: uniqueIndex("knowledge_entity_aliases_natural_identity_uq").on(
395
+ table.accountId,
396
+ table.scopeKey,
397
+ table.entityType,
398
+ table.normalizedAlias,
399
+ ),
400
+ operation: uniqueIndex("knowledge_entity_aliases_operation_uq").on(
401
+ table.accountId,
402
+ table.operationId,
403
+ ),
404
+ entity: index("knowledge_entity_aliases_entity_idx").on(table.entityId, table.createdAt),
405
+ }),
406
+ );
407
+
408
+ export const knowledgeFacts = pgTable(
409
+ "knowledge_facts",
410
+ {
411
+ id: uuid("id").primaryKey().defaultRandom(),
412
+ ...tenantScopeColumns(),
413
+ subjectEntityId: uuid("subject_entity_id").notNull(),
414
+ predicateKey: text("predicate_key").notNull(),
415
+ objectKind: text("object_kind").notNull(),
416
+ objectEntityId: uuid("object_entity_id"),
417
+ objectValue: jsonb("object_value").$type<unknown>(),
418
+ objectHash: text("object_hash").notNull(),
419
+ operationId: text("operation_id").notNull(),
420
+ inputHash: text("input_hash").notNull(),
421
+ ...actorColumns(),
422
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
423
+ },
424
+ (table) => ({
425
+ naturalIdentity: uniqueIndex("knowledge_facts_natural_identity_uq").on(
426
+ table.accountId,
427
+ table.scopeKey,
428
+ table.subjectEntityId,
429
+ table.predicateKey,
430
+ table.objectHash,
431
+ ),
432
+ operation: uniqueIndex("knowledge_facts_operation_uq").on(table.accountId, table.operationId),
433
+ scopeIdentity: uniqueIndex("knowledge_facts_scope_identity_uq").on(
434
+ table.accountId,
435
+ table.id,
436
+ table.scopeKey,
437
+ ),
438
+ }),
439
+ );
440
+
441
+ export const knowledgeClaims = pgTable(
442
+ "knowledge_claims",
443
+ {
444
+ id: uuid("id").primaryKey().defaultRandom(),
445
+ ...tenantScopeColumns(),
446
+ factId: uuid("fact_id").notNull(),
447
+ origin: text("origin").notNull(),
448
+ confidenceBps: integer("confidence_bps").notNull(),
449
+ effectiveAt: timestamp("effective_at", { withTimezone: true }).notNull(),
450
+ expiresAt: timestamp("expires_at", { withTimezone: true }),
451
+ extractionMethod: text("extraction_method").notNull(),
452
+ extractionMetadata: jsonb("extraction_metadata")
453
+ .$type<Record<string, unknown>>()
454
+ .notNull()
455
+ .default({}),
456
+ modelProvider: text("model_provider"),
457
+ modelName: text("model_name"),
458
+ modelVersion: text("model_version"),
459
+ operationId: text("operation_id").notNull(),
460
+ inputHash: text("input_hash").notNull(),
461
+ ...actorColumns(),
462
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
463
+ },
464
+ (table) => ({
465
+ operation: uniqueIndex("knowledge_claims_operation_uq").on(table.accountId, table.operationId),
466
+ scopeIdentity: uniqueIndex("knowledge_claims_scope_identity_uq").on(
467
+ table.accountId,
468
+ table.id,
469
+ table.scopeKey,
470
+ ),
471
+ factTimeline: index("knowledge_claims_fact_timeline_idx").on(
472
+ table.factId,
473
+ table.effectiveAt,
474
+ table.createdAt,
475
+ ),
476
+ }),
477
+ );
478
+
479
+ export const knowledgeClaimRelations = pgTable(
480
+ "knowledge_claim_relations",
481
+ {
482
+ id: uuid("id").primaryKey().defaultRandom(),
483
+ ...tenantScopeColumns(),
484
+ relationType: text("relation_type").notNull(),
485
+ fromClaimId: uuid("from_claim_id").notNull(),
486
+ toClaimId: uuid("to_claim_id").notNull(),
487
+ operationId: text("operation_id").notNull(),
488
+ inputHash: text("input_hash").notNull(),
489
+ ...actorColumns(),
490
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
491
+ },
492
+ (table) => ({
493
+ naturalIdentity: uniqueIndex("knowledge_claim_relations_natural_identity_uq").on(
494
+ table.relationType,
495
+ table.fromClaimId,
496
+ table.toClaimId,
497
+ ),
498
+ operation: uniqueIndex("knowledge_claim_relations_operation_uq").on(
499
+ table.accountId,
500
+ table.operationId,
501
+ ),
502
+ }),
503
+ );
504
+
505
+ export const knowledgeClaimEvidence = pgTable(
506
+ "knowledge_claim_evidence",
507
+ {
508
+ id: uuid("id").primaryKey().defaultRandom(),
509
+ ...tenantScopeColumns(),
510
+ claimId: uuid("claim_id").notNull(),
511
+ documentVersionId: uuid("document_version_id").notNull(),
512
+ polarity: text("polarity").notNull(),
513
+ documentChunkId: uuid("document_chunk_id"),
514
+ chunkIndex: integer("chunk_index"),
515
+ locator: text("locator"),
516
+ quoteHash: text("quote_hash"),
517
+ contentHash: text("content_hash").notNull(),
518
+ operationId: text("operation_id").notNull(),
519
+ inputHash: text("input_hash").notNull(),
520
+ ...actorColumns(),
521
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
522
+ },
523
+ (table) => ({
524
+ naturalIdentity: uniqueIndex("knowledge_claim_evidence_natural_identity_uq").on(
525
+ table.claimId,
526
+ table.documentVersionId,
527
+ table.polarity,
528
+ sql`coalesce(${table.documentChunkId}::text, '')`,
529
+ sql`coalesce(${table.locator}, '')`,
530
+ ),
531
+ operation: uniqueIndex("knowledge_claim_evidence_operation_uq").on(
532
+ table.accountId,
533
+ table.operationId,
534
+ ),
535
+ claimPolarity: index("knowledge_claim_evidence_claim_polarity_idx").on(
536
+ table.claimId,
537
+ table.polarity,
538
+ table.createdAt,
539
+ ),
540
+ }),
541
+ );
542
+
543
+ export const knowledgeClaimReviews = pgTable(
544
+ "knowledge_claim_reviews",
545
+ {
546
+ id: uuid("id").primaryKey().defaultRandom(),
547
+ ...tenantScopeColumns(),
548
+ claimId: uuid("claim_id").notNull(),
549
+ reviewRevision: bigint("review_revision", { mode: "number" })
550
+ .notNull()
551
+ .default(sql`nextval('knowledge_claim_review_revision_seq')`),
552
+ state: text("state").notNull(),
553
+ reason: text("reason").notNull(),
554
+ operationId: text("operation_id").notNull(),
555
+ inputHash: text("input_hash").notNull(),
556
+ ...actorColumns(),
557
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
558
+ },
559
+ (table) => ({
560
+ claimRevision: uniqueIndex("knowledge_claim_reviews_claim_revision_uq").on(
561
+ table.claimId,
562
+ table.reviewRevision,
563
+ ),
564
+ operation: uniqueIndex("knowledge_claim_reviews_operation_uq").on(
565
+ table.accountId,
566
+ table.operationId,
567
+ ),
568
+ claimTimeline: index("knowledge_claim_reviews_claim_timeline_idx").on(
569
+ table.claimId,
570
+ table.reviewRevision,
571
+ ),
572
+ }),
573
+ );
574
+
575
+ export const knowledgeChangeProposals = pgTable(
576
+ "knowledge_change_proposals",
577
+ {
578
+ id: uuid("id").primaryKey().defaultRandom(),
579
+ ...tenantScopeColumns(),
580
+ targetKind: text("target_kind").notNull(),
581
+ targetScope: text("target_scope").notNull(),
582
+ targetKey: text("target_key"),
583
+ content: text("content").notNull(),
584
+ contentHash: text("content_hash").notNull(),
585
+ claimId: uuid("claim_id").notNull(),
586
+ evidenceId: uuid("evidence_id").notNull(),
587
+ status: text("status").notNull().default("proposed"),
588
+ operationId: text("operation_id").notNull(),
589
+ inputHash: text("input_hash").notNull(),
590
+ ...actorColumns(),
591
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
592
+ },
593
+ (table) => ({
594
+ operation: uniqueIndex("knowledge_change_proposals_operation_uq").on(
595
+ table.accountId,
596
+ table.operationId,
597
+ ),
598
+ claimTimeline: index("knowledge_change_proposals_claim_timeline_idx").on(
599
+ table.claimId,
600
+ table.createdAt,
601
+ ),
602
+ }),
603
+ );