@opengeni/db 4.4.0-canary.0 → 4.4.0-canary.2

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 (105) hide show
  1. package/dist/canonical-human-identities.js +4 -3
  2. package/dist/{chunk-2ZMTQVTR.js → chunk-2KOLL33E.js} +2 -2
  3. package/dist/chunk-45CP2YKY.js +1062 -0
  4. package/dist/chunk-45CP2YKY.js.map +1 -0
  5. package/dist/{chunk-6TKL3GQO.js → chunk-5UUWZDAV.js} +6531 -6480
  6. package/dist/chunk-5UUWZDAV.js.map +1 -0
  7. package/dist/{chunk-QLA3UQNX.js → chunk-6IJD3XXF.js} +17 -3
  8. package/dist/chunk-6IJD3XXF.js.map +1 -0
  9. package/dist/{chunk-232VC2LW.js → chunk-6V3HDEMR.js} +2 -2
  10. package/dist/{chunk-M7PSMVFF.js → chunk-CHBLBEU6.js} +2 -2
  11. package/dist/chunk-M4PKBJRS.js +20318 -0
  12. package/dist/chunk-M4PKBJRS.js.map +1 -0
  13. package/dist/chunk-S2TZ3F4L.js +237 -0
  14. package/dist/chunk-S2TZ3F4L.js.map +1 -0
  15. package/dist/{chunk-UK57QA2H.js → chunk-UOXWVP3T.js} +2 -2
  16. package/dist/{chunk-GVZJ7XSR.js → chunk-WFU6PS54.js} +11 -4
  17. package/dist/chunk-WFU6PS54.js.map +1 -0
  18. package/dist/{chunk-THJGMEK5.js → chunk-XJP7KJ6U.js} +121 -66
  19. package/dist/chunk-XJP7KJ6U.js.map +1 -0
  20. package/dist/connection-token-resolver.d.ts +2 -0
  21. package/dist/database.d.ts +2 -0
  22. package/dist/editable-artifact-durable-export.js +3 -2
  23. package/dist/editable-artifact-durable-export.js.map +1 -1
  24. package/dist/editable-artifacts.js +4 -3
  25. package/dist/external-identities.d.ts +1 -0
  26. package/dist/external-membership-operations.d.ts +44 -0
  27. package/dist/governed-learning-evaluator.d.ts +1 -14
  28. package/dist/host-mcp-bindings.d.ts +4 -0
  29. package/dist/host-mcp-resolvers.d.ts +47 -0
  30. package/dist/host-mcp-task-authority.d.ts +2 -6
  31. package/dist/index.d.ts +29 -31
  32. package/dist/index.js +8616 -8321
  33. package/dist/index.js.map +1 -1
  34. package/dist/knowledge-document-preparation.d.ts +56 -0
  35. package/dist/knowledge-entries-schema.d.ts +2479 -0
  36. package/dist/knowledge-entries.d.ts +421 -0
  37. package/dist/knowledge-indexing.d.ts +99 -0
  38. package/dist/knowledge-migration.d.ts +6 -0
  39. package/dist/managed-auth-session-sets.js +4 -3
  40. package/dist/mcp-operations.js +3 -2
  41. package/dist/mcp-operations.js.map +1 -1
  42. package/dist/migrate.js +2 -1
  43. package/dist/provision-roles.js +1 -1
  44. package/dist/retained-provider-commands.js +3 -2
  45. package/dist/retained-provider-commands.js.map +1 -1
  46. package/dist/runtime-posture.d.ts +7 -7
  47. package/dist/schema.d.ts +115 -12
  48. package/dist/schema.js +26 -1
  49. package/dist/session-background-commands.js +5 -4
  50. package/dist/session-command-output.js +8 -6
  51. package/dist/session-command-output.js.map +1 -1
  52. package/dist/session-event-slices.js +6 -4
  53. package/dist/session-event-slices.js.map +1 -1
  54. package/dist/session-mcp-credential-rotation.js +5 -4
  55. package/dist/session-mcp-credential-rotation.js.map +1 -1
  56. package/dist/session-tenancy.js +4 -3
  57. package/dist/video-generation.js +4 -3
  58. package/dist/workspace-artifacts.d.ts +1 -0
  59. package/dist/workspace-instruction-policies-schema.d.ts +21 -2
  60. package/dist/workspace-instruction-policies.d.ts +1 -1
  61. package/dist/workspace-membership-access.d.ts +11 -0
  62. package/dist/workspace-tool-defaults.js +5 -4
  63. package/dist/workspace-tool-defaults.js.map +1 -1
  64. package/drizzle/0461_unified_knowledge.sql +2859 -0
  65. package/drizzle/0462_agent_instruction_non_destructive_edits.sql +212 -0
  66. package/drizzle/0463_host_mcp_resolver_registration.sql +111 -0
  67. package/drizzle/0464_external_workspace_membership_operations.sql +166 -0
  68. package/package.json +6 -6
  69. package/src/connection-token-resolver.ts +75 -6
  70. package/src/database.ts +12 -1
  71. package/src/external-identities.ts +1 -0
  72. package/src/external-membership-operations.ts +134 -0
  73. package/src/governed-learning-evaluator.ts +0 -69
  74. package/src/host-mcp-binding-match.ts +1 -0
  75. package/src/host-mcp-bindings.ts +24 -1
  76. package/src/host-mcp-resolvers.ts +266 -0
  77. package/src/host-mcp-task-authority.ts +11 -10
  78. package/src/index.ts +307 -128
  79. package/src/knowledge-document-preparation.ts +90 -0
  80. package/src/knowledge-entries-schema.ts +264 -0
  81. package/src/knowledge-entries.ts +860 -0
  82. package/src/knowledge-indexing.ts +126 -0
  83. package/src/knowledge-migration.ts +761 -0
  84. package/src/knowledge-source-sync.ts +46 -7
  85. package/src/migrate.ts +19 -0
  86. package/src/provision-roles.ts +23 -57
  87. package/src/runtime-posture.ts +103 -7
  88. package/src/schema.ts +15 -3
  89. package/src/skills.ts +4 -0
  90. package/src/video-generation.ts +14 -0
  91. package/src/workspace-artifacts.ts +2 -0
  92. package/src/workspace-instruction-policies-schema.ts +1 -0
  93. package/src/workspace-membership-access.ts +61 -0
  94. package/dist/chunk-6TKL3GQO.js.map +0 -1
  95. package/dist/chunk-EYF6MH6C.js +0 -4772
  96. package/dist/chunk-EYF6MH6C.js.map +0 -1
  97. package/dist/chunk-GSBONN55.js +0 -533
  98. package/dist/chunk-GSBONN55.js.map +0 -1
  99. package/dist/chunk-GVZJ7XSR.js.map +0 -1
  100. package/dist/chunk-QLA3UQNX.js.map +0 -1
  101. package/dist/chunk-THJGMEK5.js.map +0 -1
  102. /package/dist/{chunk-2ZMTQVTR.js.map → chunk-2KOLL33E.js.map} +0 -0
  103. /package/dist/{chunk-232VC2LW.js.map → chunk-6V3HDEMR.js.map} +0 -0
  104. /package/dist/{chunk-M7PSMVFF.js.map → chunk-CHBLBEU6.js.map} +0 -0
  105. /package/dist/{chunk-UK57QA2H.js.map → chunk-UOXWVP3T.js.map} +0 -0
@@ -1,6 +1,6 @@
1
+ import { requireScheduledTaskKnowledgeSource } from "@opengeni/contracts";
1
2
  import {
2
3
  type FileAsset,
3
- KnowledgeSourceSyncAction,
4
4
  KnowledgeSourceSyncRunSummary,
5
5
  type ScheduledTask,
6
6
  } from "@opengeni/contracts";
@@ -108,7 +108,7 @@ export async function ensureKnowledgeSourceSyncState(
108
108
  db: Database,
109
109
  task: ScheduledTask,
110
110
  ): Promise<KnowledgeSourceSyncState> {
111
- const action = KnowledgeSourceSyncAction.parse(task.action);
111
+ const action = requireScheduledTaskKnowledgeSource(task);
112
112
  return await withRlsContext(
113
113
  db,
114
114
  { accountId: task.accountId, workspaceId: task.workspaceId },
@@ -151,6 +151,12 @@ export async function ensureKnowledgeSourceSyncState(
151
151
  destination: action.destination,
152
152
  updatedAt: new Date(),
153
153
  },
154
+ // A frozen older run must never rewind a newer connector selection.
155
+ setWhere: sql`${schema.knowledgeSourceSyncStates.sourceLifecycleGeneration} <= ${action.sourceLifecycleGeneration}
156
+ AND (${schema.knowledgeSourceSyncStates.sourceConfigGeneration} < ${action.sourceConfigGeneration}
157
+ OR (${schema.knowledgeSourceSyncStates.sourceConfigGeneration} = ${action.sourceConfigGeneration}
158
+ AND ${schema.knowledgeSourceSyncStates.connectionId} = ${action.connection.connectionId}::uuid
159
+ AND ${schema.knowledgeSourceSyncStates.connectionVersion} <= ${action.connection.connectionVersion}))`,
154
160
  })
155
161
  .returning();
156
162
  if (!row) throw new Error("Failed to persist knowledge source sync state");
@@ -303,7 +309,12 @@ export async function claimKnowledgeSourceSyncLease(
303
309
  await tx
304
310
  .update(schema.scheduledTaskRuns)
305
311
  .set({ status: "skipped", completedAt: new Date(), updatedAt: new Date() })
306
- .where(eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId));
312
+ .where(
313
+ and(
314
+ eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId),
315
+ eq(schema.scheduledTaskRuns.actionKind, "knowledge_source_sync"),
316
+ ),
317
+ );
307
318
  const [state] = await tx
308
319
  .select()
309
320
  .from(schema.knowledgeSourceSyncStates)
@@ -325,7 +336,12 @@ export async function claimKnowledgeSourceSyncLease(
325
336
  await tx
326
337
  .update(schema.scheduledTaskRuns)
327
338
  .set({ status: "skipped", completedAt: new Date(), updatedAt: new Date() })
328
- .where(eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId));
339
+ .where(
340
+ and(
341
+ eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId),
342
+ eq(schema.scheduledTaskRuns.actionKind, "knowledge_source_sync"),
343
+ ),
344
+ );
329
345
  await tx
330
346
  .update(schema.knowledgeSourceSyncWakes)
331
347
  .set({ coalesced: true, claimedAt: new Date(), completedAt: new Date() })
@@ -344,7 +360,12 @@ export async function claimKnowledgeSourceSyncLease(
344
360
  await tx
345
361
  .update(schema.scheduledTaskRuns)
346
362
  .set({ status: "skipped", completedAt: new Date(), updatedAt: new Date() })
347
- .where(eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId));
363
+ .where(
364
+ and(
365
+ eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId),
366
+ eq(schema.scheduledTaskRuns.actionKind, "knowledge_source_sync"),
367
+ ),
368
+ );
348
369
  await tx
349
370
  .update(schema.knowledgeSourceSyncWakes)
350
371
  .set({ coalesced: true, claimedAt: new Date(), completedAt: new Date() })
@@ -608,6 +629,19 @@ export async function settleKnowledgeSourceSyncLease(
608
629
  throw new Error("Knowledge source generation changed before lease settlement");
609
630
  }
610
631
  const completedAt = new Date();
632
+ await tx
633
+ .update(schema.scheduledTaskRuns)
634
+ .set({
635
+ knowledgeSyncRunId: input.knowledgeSyncRunId ?? null,
636
+ knowledgeSummary: summary,
637
+ updatedAt: completedAt,
638
+ })
639
+ .where(
640
+ and(
641
+ eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId),
642
+ eq(schema.scheduledTaskRuns.actionKind, "agent_turn"),
643
+ ),
644
+ );
611
645
  await tx
612
646
  .update(schema.scheduledTaskRuns)
613
647
  .set({
@@ -618,7 +652,12 @@ export async function settleKnowledgeSourceSyncLease(
618
652
  error: input.error ?? null,
619
653
  updatedAt: completedAt,
620
654
  })
621
- .where(eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId));
655
+ .where(
656
+ and(
657
+ eq(schema.scheduledTaskRuns.id, input.scheduledTaskRunId),
658
+ eq(schema.scheduledTaskRuns.actionKind, "knowledge_source_sync"),
659
+ ),
660
+ );
622
661
  await tx
623
662
  .update(schema.knowledgeSourceSyncStates)
624
663
  .set({
@@ -673,7 +712,7 @@ export async function settleKnowledgeSourceSyncLease(
673
712
  .update(schema.scheduledTaskRuns)
674
713
  .set({ status: "skipped", completedAt, updatedAt: completedAt })
675
714
  .where(
676
- sql`${schema.scheduledTaskRuns.id} in (${sql.join(
715
+ sql`${schema.scheduledTaskRuns.actionKind} = 'knowledge_source_sync' AND ${schema.scheduledTaskRuns.id} in (${sql.join(
677
716
  supersededWakes.map((wake) => sql`${wake.scheduledTaskRunId}::uuid`),
678
717
  sql`, `,
679
718
  )})`,
package/src/migrate.ts CHANGED
@@ -2,6 +2,7 @@ import { readdir, readFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import postgres from "postgres";
5
+ import { KNOWLEDGE_MIGRATION_MARKER, migrateRetainedKnowledge } from "./knowledge-migration";
5
6
  import { migrateLegacySkillConfigurations } from "./skill-config-migration";
6
7
  import { batchedBackfillTransactionLocalSetting } from "./migration-runner-settings";
7
8
  import {
@@ -193,6 +194,24 @@ export async function executeMigrationFile(
193
194
  });
194
195
  return;
195
196
  }
197
+ if (sqlText.includes(KNOWLEDGE_MIGRATION_MARKER)) {
198
+ if (file !== "0461_unified_knowledge.sql")
199
+ throw new Error("Knowledge conversion is restricted to migration 0461");
200
+ const parts = sqlText.split(KNOWLEDGE_MIGRATION_MARKER);
201
+ if (parts.length !== 2) throw new Error("0461 requires exactly one Knowledge conversion stage");
202
+ await sql.begin(async (transaction) => {
203
+ await transaction`CREATE TEMP TABLE knowledge_conversion_0461(completed boolean NOT NULL) ON COMMIT DROP`;
204
+ await transaction`SELECT
205
+ pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2','1',true),
206
+ pg_catalog.set_config('opengeni.session_variable_set_attachments_v1','1',true)`;
207
+ await transaction.unsafe(parts[0]!);
208
+ await migrateRetainedKnowledge(transaction);
209
+ await transaction`INSERT INTO pg_temp.knowledge_conversion_0461 VALUES(true)`;
210
+ await transaction.unsafe(parts[1]!);
211
+ await transaction`INSERT INTO schema_migrations(name) VALUES(${file}) ON CONFLICT DO NOTHING`;
212
+ });
213
+ return;
214
+ }
196
215
  const batchedBackfill = parseBatchedBackfillMigration(file, sqlText);
197
216
  if (batchedBackfill) {
198
217
  await sql`select set_config('lock_timeout', ${batchedBackfill.lockTimeout}, false)`;
@@ -525,6 +525,9 @@ async function grantAppRoleIfSchemaExists(
525
525
  const workClaimCapabilityRoutines = `ARRAY[${WORK_CLAIM_CAPABILITY_ROUTINES.map(literal).join(", ")}]`;
526
526
  const organizationMembershipLifecycleRoutines = `ARRAY[${[
527
527
  "ensure_external_identity(uuid,text,text)",
528
+ "lookup_external_identity(uuid,text,text,text)",
529
+ "prepare_external_workspace_membership_operation(jsonb)",
530
+ "record_external_workspace_membership_operation(jsonb,jsonb)",
528
531
  "get_external_identity_link_reference(uuid,uuid,text)",
529
532
  "get_external_identity_link_inventory_references(uuid,uuid[])",
530
533
  "list_self_organization_memberships(text)",
@@ -826,6 +829,17 @@ BEGIN
826
829
  EXECUTE format('GRANT EXECUTE ON FUNCTION %I.skill_apply_lifecycle(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
827
830
  EXECUTE format('GRANT EXECUTE ON FUNCTION %I.skill_files_valid(jsonb) TO %I', ${literal(schema)}, ${literal(role)});
828
831
  END IF;
832
+ IF to_regprocedure(format('%I.knowledge_entry_apply(uuid,uuid,jsonb,jsonb)', ${literal(schema)})) IS NOT NULL THEN
833
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_index_claim(text,integer,integer) TO %I', ${literal(schema)}, ${literal(role)});
834
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_index_work(uuid,uuid,uuid,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
835
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.agent_instruction_apply(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
836
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_entry_apply(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
837
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_entry_confirm_legacy(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
838
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_entry_read(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
839
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_entry_prepare_file(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
840
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.knowledge_document_prepare(uuid,uuid,uuid,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
841
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.agent_learning_manage(uuid,uuid,jsonb,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
842
+ END IF;
829
843
  IF to_regprocedure(
830
844
  format('%I.preference_registry_lock_heads(uuid[])', ${literal(schema)})
831
845
  ) IS NOT NULL THEN
@@ -835,30 +849,8 @@ BEGIN
835
849
  ${literal(role)}
836
850
  );
837
851
  END IF;
838
- IF to_regprocedure(
839
- format(
840
- '%I.knowledge_memory_apply_operation(jsonb,text,text,text,uuid,uuid,uuid,integer)',
841
- ${literal(schema)}
842
- )
843
- ) IS NOT NULL THEN
844
- EXECUTE format(
845
- 'GRANT EXECUTE ON FUNCTION %I.knowledge_memory_apply_operation(jsonb, text, text, text, uuid, uuid, uuid, integer) TO %I',
846
- ${literal(schema)},
847
- ${literal(role)}
848
- );
849
- END IF;
850
- IF to_regprocedure(
851
- format(
852
- '%I.knowledge_memory_revert_operation(uuid,uuid,text,text,text,uuid,uuid,uuid,integer)',
853
- ${literal(schema)}
854
- )
855
- ) IS NOT NULL THEN
856
- EXECUTE format(
857
- 'GRANT EXECUTE ON FUNCTION %I.knowledge_memory_revert_operation(uuid, uuid, text, text, text, uuid, uuid, uuid, integer) TO %I',
858
- ${literal(schema)},
859
- ${literal(role)}
860
- );
861
- END IF;
852
+
853
+
862
854
  IF to_regprocedure(
863
855
  format(
864
856
  '%I.preference_registry_get_or_create_snapshot(uuid,uuid,uuid,uuid,uuid,integer)',
@@ -944,6 +936,9 @@ BEGIN
944
936
  ${literal(role)}
945
937
  );
946
938
  END IF;
939
+ -- Older-schema fixtures and the maintenance conversion can still prepare
940
+ -- historical evidence; current runtimes receive only the undo/read seam.
941
+ IF to_regclass(format('%I.knowledge_entries', ${literal(schema)})) IS NULL THEN
947
942
  IF to_regprocedure(
948
943
  format(
949
944
  '%I.evaluate_governed_learning_proposal(uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid,uuid,uuid)',
@@ -974,28 +969,10 @@ BEGIN
974
969
  ${literal(role)}
975
970
  );
976
971
  END IF;
977
- IF to_regprocedure(
978
- format('%I.confirm_remember_knowledge_claim(uuid,uuid,uuid,uuid,integer,uuid,uuid,uuid)', ${literal(schema)})
979
- ) IS NOT NULL THEN
980
- EXECUTE format(
981
- 'GRANT EXECUTE ON FUNCTION %I.confirm_remember_knowledge_claim(uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid) TO %I',
982
- ${literal(schema)},
983
- ${literal(role)}
984
- );
985
- END IF;
986
- IF to_regprocedure(
987
- format('%I.materialize_remember_knowledge_memory(uuid,uuid,uuid)', ${literal(schema)})
988
- ) IS NOT NULL THEN
989
- EXECUTE format(
990
- 'REVOKE ALL ON FUNCTION %I.materialize_remember_knowledge_memory(uuid, uuid, uuid) FROM PUBLIC',
991
- ${literal(schema)}
992
- );
993
- EXECUTE format(
994
- 'GRANT EXECUTE ON FUNCTION %I.materialize_remember_knowledge_memory(uuid, uuid, uuid) TO %I',
995
- ${literal(schema)},
996
- ${literal(role)}
997
- );
972
+
973
+
998
974
  END IF;
975
+
999
976
  IF to_regprocedure(
1000
977
  format('%I.undo_governed_learning_activation(uuid,uuid,uuid,uuid)', ${literal(schema)})
1001
978
  ) IS NOT NULL THEN
@@ -1165,18 +1142,7 @@ BEGIN
1165
1142
  ${literal(role)}
1166
1143
  );
1167
1144
  END IF;
1168
- IF to_regprocedure(
1169
- format(
1170
- '%I.workspace_learning_policy_apply_activation(uuid,text,uuid,uuid,uuid,uuid,bigint,text,text,text)',
1171
- ${literal(schema)}
1172
- )
1173
- ) IS NOT NULL THEN
1174
- EXECUTE format(
1175
- 'GRANT EXECUTE ON FUNCTION %I.workspace_learning_policy_apply_activation(uuid, text, uuid, uuid, uuid, uuid, bigint, text, text, text) TO %I',
1176
- ${literal(schema)},
1177
- ${literal(role)}
1178
- );
1179
- END IF;
1145
+
1180
1146
  IF to_regprocedure(
1181
1147
  format('%I.workspace_learning_policy_source_overrides_valid(jsonb)', ${literal(schema)})
1182
1148
  ) IS NOT NULL THEN
@@ -106,6 +106,9 @@ const ORGANIZATION_MEMBERSHIP_LIFECYCLE_ROUTINES = [
106
106
  "get_external_identity_link_reference(uuid, uuid, text)",
107
107
  "get_external_identity_link_inventory_references(uuid, uuid[])",
108
108
  "ensure_external_identity(uuid, text, text)",
109
+ "lookup_external_identity(uuid, text, text, text)",
110
+ "prepare_external_workspace_membership_operation(jsonb)",
111
+ "record_external_workspace_membership_operation(jsonb, jsonb)",
109
112
  "list_self_organization_memberships(text)",
110
113
  "list_self_organization_invitations(text)",
111
114
  "list_self_organization_invitations(text, uuid, integer)",
@@ -424,10 +427,6 @@ const COMPANY_BRAIN_CONTEXT_INSPECTION_ROUTINE =
424
427
  const GOVERNED_LEARNING_EVALUATION_ROUTINE =
425
428
  "evaluate_governed_learning_proposal(uuid, uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid, uuid, uuid)";
426
429
  const GOVERNED_LEARNING_ACTIVATION_ROUTINES = [
427
- "activate_governed_learning_decision(uuid, uuid, uuid, uuid)",
428
- "activate_human_confirmed_learning_decision(uuid, uuid, uuid, uuid, uuid)",
429
- "confirm_remember_knowledge_claim(uuid, uuid, uuid, uuid, integer, uuid, uuid, uuid)",
430
- "materialize_remember_knowledge_memory(uuid, uuid, uuid)",
431
430
  "undo_governed_learning_activation(uuid, uuid, uuid, uuid)",
432
431
  ] as const;
433
432
  const GOVERNED_LEARNING_INSPECTION_ROUTINES = [
@@ -573,13 +572,48 @@ const XAI_AUTHORITY_TABLES = [
573
572
  "xai_subscription_credentials",
574
573
  ] as const;
575
574
 
575
+ const UNIFIED_KNOWLEDGE_ROUTINES = [
576
+ "knowledge_index_claim(text, integer, integer)",
577
+ "knowledge_index_work(uuid, uuid, uuid, jsonb)",
578
+ "knowledge_entry_apply(uuid, uuid, jsonb, jsonb)",
579
+ "knowledge_entry_confirm_legacy(uuid, uuid, jsonb, jsonb)",
580
+ "agent_instruction_apply(uuid, uuid, jsonb, jsonb)",
581
+ "knowledge_entry_read(uuid, uuid, jsonb, jsonb)",
582
+ "knowledge_entry_prepare_file(uuid, uuid, jsonb, jsonb)",
583
+ "knowledge_document_prepare(uuid, uuid, uuid, jsonb)",
584
+ "agent_learning_manage(uuid, uuid, jsonb, jsonb)",
585
+ ] as const;
586
+ const UNIFIED_KNOWLEDGE_ROUTINE_SET = new Set<string>(UNIFIED_KNOWLEDGE_ROUTINES);
587
+ const UNIFIED_KNOWLEDGE_AUTHORITY_TABLES = [
588
+ "knowledge_entries",
589
+ "knowledge_entry_revisions",
590
+ "knowledge_entry_decisions",
591
+ "knowledge_entry_links",
592
+ "knowledge_entry_operations",
593
+ "knowledge_entry_search",
594
+ "knowledge_index_jobs",
595
+ "knowledge_entry_vectors",
596
+ "knowledge_review_batches",
597
+ "agent_learning_revisions",
598
+ "agent_learning_snapshots",
599
+ "agent_instruction_operations",
600
+ "workspace_instruction_policy_revisions",
601
+ "workspace_instruction_policy_heads",
602
+ "workspace_instruction_policy_activation_events",
603
+ "workspaces",
604
+ "sessions",
605
+ "session_turns",
606
+ "session_turn_attempts",
607
+ "files",
608
+ "documents",
609
+ ] as const;
576
610
  export const RUNTIME_TARGET_SCHEMA_CAPABILITY_ROUTINES = [
611
+ ...UNIFIED_KNOWLEDGE_ROUTINES,
577
612
  MCP_OPERATION_CAPABILITY_ROUTINE,
578
613
  "skill_apply_lifecycle(uuid, uuid, jsonb, jsonb)",
579
614
  COMPANY_BRAIN_CONTEXT_INSPECTION_ROUTINE,
580
615
  COMPANY_BRAIN_CONTEXT_SELECTION_ROUTINE,
581
616
  ...COMPANY_PROFILE_AGENT_ADMIN_ROUTINES,
582
- GOVERNED_LEARNING_EVALUATION_ROUTINE,
583
617
  ...GOVERNED_LEARNING_ACTIVATION_ROUTINES,
584
618
  ...GOVERNED_LEARNING_INSPECTION_ROUTINES,
585
619
  FORK_SESSION_CONTENT_ROUTINE,
@@ -663,6 +697,9 @@ const RUNTIME_TARGET_SCHEMA_INVOKER_ROUTINE_SET = new Set<string>(
663
697
  */
664
698
  export const FORCE_RLS_TABLES = [
665
699
  "additional_organization_creation_receipts",
700
+ "agent_instruction_operations",
701
+ "agent_learning_revisions",
702
+ "agent_learning_snapshots",
666
703
  "agent_run_states",
667
704
  "api_keys",
668
705
  "attached_browser_devices",
@@ -777,6 +814,8 @@ export const FORCE_RLS_TABLES = [
777
814
  "host_export_outbox",
778
815
  "host_mcp_bindings",
779
816
  "host_mcp_delegations",
817
+ "host_mcp_resolver_operations",
818
+ "host_mcp_resolvers",
780
819
  "host_mcp_task_authorities",
781
820
  "host_mcp_turn_authorities",
782
821
  "image_generation_operations",
@@ -798,13 +837,22 @@ export const FORCE_RLS_TABLES = [
798
837
  "knowledge_document_versions",
799
838
  "knowledge_entities",
800
839
  "knowledge_entity_aliases",
840
+ "knowledge_entries",
841
+ "knowledge_entry_decisions",
842
+ "knowledge_entry_links",
843
+ "knowledge_entry_operations",
844
+ "knowledge_entry_revisions",
845
+ "knowledge_entry_search",
846
+ "knowledge_entry_vectors",
801
847
  "knowledge_facts",
848
+ "knowledge_index_jobs",
802
849
  "knowledge_lifecycle_events",
803
850
  "knowledge_memories",
804
851
  "knowledge_memory_lifecycle_events",
805
852
  "knowledge_memory_relationships",
806
853
  "knowledge_operation_receipts",
807
854
  "knowledge_providers",
855
+ "knowledge_review_batches",
808
856
  "knowledge_source_acl_versions",
809
857
  "knowledge_source_objects",
810
858
  "knowledge_source_sync_index_obligations",
@@ -1125,7 +1173,6 @@ export const RUNTIME_FULL_DML_TABLES = [
1125
1173
  "integration_facet_bindings",
1126
1174
  "integration_oauth_clients",
1127
1175
  "integration_oauth_state_nonces",
1128
- "knowledge_memories",
1129
1176
  "knowledge_source_sync_index_obligations",
1130
1177
  "knowledge_source_sync_item_outcomes",
1131
1178
  "knowledge_source_sync_object_observations",
@@ -1244,6 +1291,7 @@ export const RUNTIME_READ_ONLY_TABLES = [
1244
1291
  "deployment_model_catalog",
1245
1292
  "document_authority_reclassifications",
1246
1293
  "knowledge_lifecycle_events",
1294
+ "knowledge_memories",
1247
1295
  "knowledge_memory_lifecycle_events",
1248
1296
  "knowledge_memory_relationships",
1249
1297
  "nested_agent_depth_configuration",
@@ -1261,6 +1309,7 @@ export const RUNTIME_READ_ONLY_TABLES = [
1261
1309
  "workspace_instruction_policy_snapshots",
1262
1310
  "workspace_learning_policy_activation_events",
1263
1311
  "workspace_learning_policy_heads",
1312
+ "workspace_learning_policy_revisions",
1264
1313
  "workspace_learning_policy_snapshots",
1265
1314
  ] as const;
1266
1315
 
@@ -1288,6 +1337,7 @@ export const RUNTIME_READ_INSERT_TABLES = [
1288
1337
  "feedback_submissions",
1289
1338
  "google_drive_object_acl_evidence",
1290
1339
  "google_drive_object_acl_principals",
1340
+ "host_mcp_resolver_operations",
1291
1341
  "host_mcp_task_authorities",
1292
1342
  "host_mcp_turn_authorities",
1293
1343
  "knowledge_change_proposals",
@@ -1319,7 +1369,6 @@ export const RUNTIME_READ_INSERT_TABLES = [
1319
1369
  "workspace_instruction_policy_activation_events",
1320
1370
  "workspace_instruction_policy_onboarding_proposals",
1321
1371
  "workspace_instruction_policy_revisions",
1322
- "workspace_learning_policy_revisions",
1323
1372
  ] as const;
1324
1373
 
1325
1374
  /** Durable operation journals are append/read plus claim/settle updates, never deletes. */
@@ -1343,6 +1392,7 @@ export const RUNTIME_READ_INSERT_UPDATE_TABLES = [
1343
1392
  "editable_artifact_session_links",
1344
1393
  "editable_artifacts",
1345
1394
  "external_identity_links",
1395
+ "host_mcp_resolvers",
1346
1396
  "integration_facet_definitions",
1347
1397
  "integration_spec_revisions",
1348
1398
  "integration_tools",
@@ -1366,6 +1416,9 @@ export const RUNTIME_READ_INSERT_UPDATE_TABLES = [
1366
1416
  */
1367
1417
  export const PROTECTED_NO_DIRECT_DML_TABLES = [
1368
1418
  "additional_organization_creation_receipts",
1419
+ "agent_instruction_operations",
1420
+ "agent_learning_revisions",
1421
+ "agent_learning_snapshots",
1369
1422
  "canonical_human_identities",
1370
1423
  "canonical_human_identity_operations",
1371
1424
  "canonical_human_identity_subjects",
@@ -1392,6 +1445,15 @@ export const PROTECTED_NO_DIRECT_DML_TABLES = [
1392
1445
  "host_export_cursor_state",
1393
1446
  "host_export_dead_letters",
1394
1447
  "host_export_outbox",
1448
+ "knowledge_entries",
1449
+ "knowledge_entry_decisions",
1450
+ "knowledge_entry_links",
1451
+ "knowledge_entry_operations",
1452
+ "knowledge_entry_revisions",
1453
+ "knowledge_entry_search",
1454
+ "knowledge_entry_vectors",
1455
+ "knowledge_index_jobs",
1456
+ "knowledge_review_batches",
1395
1457
  "managed_auth_actor_mutation_leases",
1396
1458
  "managed_auth_browser_installations",
1397
1459
  "managed_auth_login_return_intents",
@@ -2287,6 +2349,28 @@ export function evaluateRuntimeDatabasePosture(
2287
2349
  );
2288
2350
  }
2289
2351
  }
2352
+ } else if (
2353
+ [
2354
+ "lookup_external_identity(uuid, text, text, text)",
2355
+ "prepare_external_workspace_membership_operation(jsonb)",
2356
+ "record_external_workspace_membership_operation(jsonb, jsonb)",
2357
+ ].includes(routine.name)
2358
+ ) {
2359
+ const names = [
2360
+ "external_identities",
2361
+ "organization_memberships",
2362
+ "organization_workspace_operation_receipts",
2363
+ "api_keys",
2364
+ ];
2365
+ if (
2366
+ names.some(
2367
+ (name) => !tableByName.has(name) || tableByName.get(name)!.owner !== routine.owner,
2368
+ )
2369
+ ) {
2370
+ violations.push(
2371
+ `target-schema runtime capability ${routine.name} authority table owners do not match`,
2372
+ );
2373
+ }
2290
2374
  } else if (
2291
2375
  [
2292
2376
  "ensure_external_identity(uuid, text, text)",
@@ -2512,6 +2596,18 @@ export function evaluateRuntimeDatabasePosture(
2512
2596
  );
2513
2597
  }
2514
2598
  }
2599
+ } else if (UNIFIED_KNOWLEDGE_ROUTINE_SET.has(routine.name)) {
2600
+ // PostgreSQL 15+ public is owned by pg_database_owner while migrated
2601
+ // tables/functions share the concrete migrator. Check the authority graph,
2602
+ // as for the native Skill lifecycle, rather than the schema label.
2603
+ for (const name of UNIFIED_KNOWLEDGE_AUTHORITY_TABLES) {
2604
+ const table = tableByName.get(name);
2605
+ if (!table) violations.push(`Knowledge authority table ${name} is missing`);
2606
+ else if (routine.owner !== table.owner)
2607
+ violations.push(
2608
+ `Knowledge capability ${routine.name} owner ${routine.owner} does not match ${name} owner ${table.owner}`,
2609
+ );
2610
+ }
2515
2611
  } else if (routine.name === "skill_apply_lifecycle(uuid, uuid, jsonb, jsonb)") {
2516
2612
  const authorityTables = [
2517
2613
  "preference_registry_preferences",
package/src/schema.ts CHANGED
@@ -26,6 +26,7 @@ import type {
26
26
  } from "@opengeni/contracts";
27
27
  import { WORKSPACE_XAI_PROVIDER_ACCOUNT_AUTHORITY_SNAPSHOT_V1 } from "@opengeni/contracts";
28
28
  import { sql } from "drizzle-orm";
29
+ export * from "./knowledge-entries-schema";
29
30
  import type { SessionToolPolicy } from "@opengeni/contracts";
30
31
  import type { HumanInputQuestion, HumanInputResponse } from "@opengeni/contracts";
31
32
  import {
@@ -5479,13 +5480,15 @@ export const sessionMcpServers = pgTable(
5479
5480
  export const files = pgTable(
5480
5481
  "files",
5481
5482
  {
5483
+ privateOwnerSubjectIds: text("private_owner_subject_ids").array().default(sql`CASE
5484
+ WHEN nullif(current_setting('opengeni.private_file_owner',true),'') IS NULL THEN NULL
5485
+ ELSE ARRAY[current_setting('opengeni.private_file_owner',true)] END`),
5482
5486
  id: uuid("id").primaryKey().defaultRandom(),
5483
5487
  accountId: uuid("account_id")
5484
5488
  .notNull()
5485
5489
  .references(() => managedAccounts.id, { onDelete: "cascade" }),
5486
- workspaceId: uuid("workspace_id")
5487
- .notNull()
5488
- .references(() => workspaces.id, { onDelete: "cascade" }),
5490
+ // Origin only for personal originals; SQL owns the generated retention FK.
5491
+ workspaceId: uuid("workspace_id").notNull(),
5489
5492
  status: text("status").notNull().default("pending_upload"),
5490
5493
  filename: text("filename").notNull(),
5491
5494
  safeFilename: text("safe_filename").notNull(),
@@ -5522,6 +5525,9 @@ export const fileUploads = pgTable(
5522
5525
  fileId: uuid("file_id")
5523
5526
  .notNull()
5524
5527
  .references(() => files.id, { onDelete: "cascade" }),
5528
+ privateFileOwnerSubjectId: text("private_file_owner_subject_id").default(
5529
+ sql`nullif(current_setting('opengeni.private_file_owner',true),'')`,
5530
+ ),
5525
5531
  status: text("status").notNull().default("pending"),
5526
5532
  expiresAt: timestamp("expires_at", { withTimezone: true }).notNull(),
5527
5533
  completedAt: timestamp("completed_at", { withTimezone: true }),
@@ -5809,6 +5815,9 @@ export const videoGenerationOperations = pgTable(
5809
5815
  workspaceId: uuid("workspace_id")
5810
5816
  .notNull()
5811
5817
  .references(() => workspaces.id, { onDelete: "cascade" }),
5818
+ privateFileOwnerSubjectId: text("private_file_owner_subject_id").default(
5819
+ sql`nullif(current_setting('opengeni.private_file_owner',true),'')`,
5820
+ ),
5812
5821
  sessionId: uuid("session_id").references(() => sessions.id, {
5813
5822
  onDelete: "set null",
5814
5823
  }),
@@ -6121,6 +6130,9 @@ export const retainedScreenshotArtifacts = pgTable(
6121
6130
  workspaceId: uuid("workspace_id")
6122
6131
  .notNull()
6123
6132
  .references(() => workspaces.id, { onDelete: "cascade" }),
6133
+ privateFileOwnerSubjectId: text("private_file_owner_subject_id").default(
6134
+ sql`nullif(current_setting('opengeni.private_file_owner',true),'')`,
6135
+ ),
6124
6136
  sessionId: uuid("session_id").references(() => sessions.id, {
6125
6137
  onDelete: "set null",
6126
6138
  }),
package/src/skills.ts CHANGED
@@ -56,6 +56,7 @@ export async function applySkillLifecycle(
56
56
  content = main?.content;
57
57
  } else if (
58
58
  request.operation === "approve" ||
59
+ request.operation === "reject" ||
59
60
  request.operation === "restore" ||
60
61
  request.operation === "confirm_response"
61
62
  ) {
@@ -216,6 +217,9 @@ export async function listSkillRecords(
216
217
  FROM skill_write_receipts pending WHERE pending.account_id=h.account_id
217
218
  AND pending.workspace_id=${context.workspaceId}::uuid AND pending.receipt->>'skillId'=h.id::text
218
219
  AND pending.receipt->>'outcome'='pending'
220
+ AND coalesce(pending.receipt->>'pendingReason','approval')='approval'
221
+ AND (pending.receipt->>'revisionId')::uuid=(SELECT newest.id FROM preference_registry_revisions newest
222
+ WHERE newest.account_id=h.account_id AND newest.preference_id=h.id ORDER BY newest.revision DESC LIMIT 1)
219
223
  AND NOT EXISTS(SELECT 1 FROM preference_registry_events e WHERE e.preference_id=h.id
220
224
  AND e.new_revision_id=(pending.receipt->>'revisionId')::uuid
221
225
  AND e.type IN ('activated','corrected','rejected'))),'[]'::jsonb),
@@ -926,6 +926,11 @@ export async function settleVideoGenerationReady(
926
926
  if (operation.expectedArtifactId === operation.expectedFileId) {
927
927
  throw new Error("Video artifact and File identities must be distinct");
928
928
  }
929
+ // The durable provider operation owns this write, including when its
930
+ // original session has since disappeared. Ordinary file reads stay scoped.
931
+ await tx.execute(
932
+ sql`SELECT set_config('opengeni.private_file_owner',${operation.privateFileOwnerSubjectId ?? ""},true)`,
933
+ );
929
934
  const now = new Date();
930
935
  await tx.insert(schema.files).values({
931
936
  id: input.fileId,
@@ -1265,6 +1270,15 @@ export async function getVideoGenerationOperationSummary(
1265
1270
  ): Promise<import("@opengeni/contracts").VideoGenerationOperationSummary | null> {
1266
1271
  const operation = await getVideoGenerationOperation(db, workspaceId, operationId);
1267
1272
  if (!operation) return null;
1273
+ if (operation.privateFileOwnerSubjectId) {
1274
+ const [context] = await withWorkspaceRls(db, workspaceId, (tx) =>
1275
+ rawRows<{ owner: string | null }>(
1276
+ tx,
1277
+ sql`SELECT nullif(current_setting('opengeni.private_file_owner',true),'') AS owner`,
1278
+ ),
1279
+ );
1280
+ if (context?.owner !== operation.privateFileOwnerSubjectId) return null;
1281
+ }
1268
1282
  const terminal = inArrayValue(operation.status, [
1269
1283
  "completed",
1270
1284
  "provider_failed",
@@ -376,6 +376,7 @@ export async function getWorkspaceArtifactContentRef(
376
376
  versionId?: string,
377
377
  ): Promise<{
378
378
  artifactId: string;
379
+ status: WorkspaceArtifact["status"];
379
380
  version: WorkspaceArtifactVersion;
380
381
  contentKey: string;
381
382
  sourceKey: string | null;
@@ -399,6 +400,7 @@ export async function getWorkspaceArtifactContentRef(
399
400
  if (!version) throw new WorkspaceArtifactNotFoundError("Artifact version not found");
400
401
  return {
401
402
  artifactId,
403
+ status: artifact.status,
402
404
  version: versionFromRow(version),
403
405
  contentKey: version.contentKey,
404
406
  sourceKey: version.sourceKey,
@@ -35,6 +35,7 @@ export const workspaceInstructionPolicyRevisions = pgTable(
35
35
  contentHash: text("content_hash").notNull(),
36
36
  provenanceSource: text("provenance_source").notNull(),
37
37
  provenanceSourceId: text("provenance_source_id"),
38
+ agentLearningContext: jsonb("agent_learning_context").$type<Record<string, unknown>>(),
38
39
  supersedesRevisionId: uuid("supersedes_revision_id"),
39
40
  createdBySubjectId: text("created_by_subject_id").notNull(),
40
41
  createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),