@opengeni/db 0.28.9 → 0.36.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 (225) hide show
  1. package/dist/attached-browser-devices.d.ts +42 -0
  2. package/dist/attempt-tool-catalogs.d.ts +16 -0
  3. package/dist/browser-auth.d.ts +299 -0
  4. package/dist/browser-downloads.d.ts +51 -0
  5. package/dist/browser-identities.d.ts +137 -0
  6. package/dist/browser-sessions.d.ts +354 -0
  7. package/dist/browser-state-artifacts.d.ts +91 -0
  8. package/dist/canonical-human-identities.d.ts +48 -0
  9. package/dist/canonical-human-identities.js +28 -0
  10. package/dist/canonical-human-identities.js.map +1 -0
  11. package/dist/capability-components.d.ts +37 -0
  12. package/dist/capability-integrations.d.ts +194 -0
  13. package/dist/chunk-5KTIEDX7.js +13200 -0
  14. package/dist/chunk-5KTIEDX7.js.map +1 -0
  15. package/dist/chunk-CQZ4QSP5.js +995 -0
  16. package/dist/chunk-CQZ4QSP5.js.map +1 -0
  17. package/dist/chunk-F32YT7MP.js +117 -0
  18. package/dist/chunk-F32YT7MP.js.map +1 -0
  19. package/dist/chunk-JC5QPLUM.js +666 -0
  20. package/dist/chunk-JC5QPLUM.js.map +1 -0
  21. package/dist/chunk-P3RE4D2B.js +3535 -0
  22. package/dist/chunk-P3RE4D2B.js.map +1 -0
  23. package/dist/chunk-TAUTWOS5.js +259 -0
  24. package/dist/chunk-TAUTWOS5.js.map +1 -0
  25. package/dist/chunk-VKLB2ZGI.js +2389 -0
  26. package/dist/chunk-VKLB2ZGI.js.map +1 -0
  27. package/dist/codemode-operations.d.ts +117 -0
  28. package/dist/codex-token-resolver.d.ts +2 -2
  29. package/dist/company-profile-schema.d.ts +798 -0
  30. package/dist/company-profile.d.ts +268 -0
  31. package/dist/computer-sessions.d.ts +109 -0
  32. package/dist/connection-token-resolver.d.ts +9 -4
  33. package/dist/database.d.ts +57 -3
  34. package/dist/editable-artifact-durable-export.d.ts +153 -0
  35. package/dist/editable-artifact-durable-export.js +788 -0
  36. package/dist/editable-artifact-durable-export.js.map +1 -0
  37. package/dist/editable-artifact-materialization.d.ts +123 -0
  38. package/dist/editable-artifacts-schema.d.ts +4152 -0
  39. package/dist/editable-artifacts.d.ts +610 -0
  40. package/dist/editable-artifacts.js +26 -0
  41. package/dist/editable-artifacts.js.map +1 -0
  42. package/dist/generated-images.d.ts +139 -0
  43. package/dist/index.d.ts +1122 -126
  44. package/dist/index.js +42329 -18407
  45. package/dist/index.js.map +1 -1
  46. package/dist/insights.d.ts +73 -10
  47. package/dist/integration-bindings.d.ts +70 -0
  48. package/dist/integration-facets.d.ts +99 -0
  49. package/dist/interaction-revisions.d.ts +14 -0
  50. package/dist/interaction-schema.d.ts +6036 -0
  51. package/dist/knowledge-source-sync-schema.d.ts +1679 -0
  52. package/dist/knowledge-source-sync.d.ts +274 -0
  53. package/dist/memory-governance.d.ts +2 -2
  54. package/dist/memory-slack-delivery.d.ts +101 -0
  55. package/dist/new-session-drafts.d.ts +2 -2
  56. package/dist/pack-components.d.ts +76 -0
  57. package/dist/pack-installations.d.ts +86 -0
  58. package/dist/persistence-errors.d.ts +3 -3
  59. package/dist/plugin-packages.d.ts +126 -0
  60. package/dist/preference-registry.d.ts +1 -1
  61. package/dist/provision-roles.d.ts +9 -1
  62. package/dist/provision-roles.js +1 -1
  63. package/dist/runtime-posture.d.ts +19 -6
  64. package/dist/schema.d.ts +22654 -9359
  65. package/dist/schema.js +209 -3
  66. package/dist/scoped-knowledge.d.ts +97 -1
  67. package/dist/session-control.d.ts +33 -7
  68. package/dist/session-queue-commands.d.ts +19 -11
  69. package/dist/session-realtime-context.d.ts +2 -2
  70. package/dist/session-realtime-ledger.d.ts +4 -4
  71. package/dist/session-realtime-mirror.d.ts +2 -2
  72. package/dist/session-realtime-state.d.ts +1 -1
  73. package/dist/session-realtime-terminal.d.ts +1 -1
  74. package/dist/session-realtime.d.ts +7 -7
  75. package/dist/session-tenancy.d.ts +44 -0
  76. package/dist/session-tenancy.js +16 -0
  77. package/dist/session-tenancy.js.map +1 -0
  78. package/dist/session-tool-call-settlement.d.ts +1 -1
  79. package/dist/slack-task-policy-schema.d.ts +847 -0
  80. package/dist/slack-task-policy.d.ts +65 -0
  81. package/dist/slack-user-link-access.d.ts +54 -0
  82. package/dist/task-notes-schema.d.ts +924 -0
  83. package/dist/task-notes.d.ts +85 -0
  84. package/dist/transcription-recordings.d.ts +2 -2
  85. package/dist/turn-initiator.d.ts +2 -2
  86. package/dist/video-generation.d.ts +225 -0
  87. package/dist/video-generation.js +68 -0
  88. package/dist/video-generation.js.map +1 -0
  89. package/dist/workspace-artifacts.d.ts +1 -1
  90. package/dist/workspace-instruction-policies.d.ts +1 -1
  91. package/dist/workspace-learning-policy-schema.d.ts +932 -0
  92. package/dist/workspace-learning-policy.d.ts +161 -0
  93. package/dist/xai-subscription.d.ts +326 -0
  94. package/drizzle/0183_model_call_provider_cost_estimates.sql +39 -0
  95. package/drizzle/0184_sandbox_drain_teardown_fence.sql +682 -0
  96. package/drizzle/0185_temporal_schedule_cleanup_outbox.sql +168 -0
  97. package/drizzle/0186_sandbox_capture_provider_contract.sql +400 -0
  98. package/drizzle/0187_generated_image_artifacts.sql +173 -0
  99. package/drizzle/0188_image_generation_retention_failure.sql +25 -0
  100. package/drizzle/0189_retained_session_image_formats.sql +13 -0
  101. package/drizzle/0190_timeline_annotations.sql +31 -0
  102. package/drizzle/0191_editable_artifact_engine.sql +3853 -0
  103. package/drizzle/0192_editable_artifact_live_tickets.sql +338 -0
  104. package/drizzle/0193_editable_artifact_authorization.sql +190 -0
  105. package/drizzle/0194_editable_artifact_durable_exports.sql +160 -0
  106. package/drizzle/0195_editable_artifact_import_authorization.sql +203 -0
  107. package/drizzle/0196_rig_provider_images.sql +152 -0
  108. package/drizzle/0197_knowledge_source_sync_schedules.sql +523 -0
  109. package/drizzle/0198_memory_slack_publication_delivery.sql +393 -0
  110. package/drizzle/0199_workspace_learning_policy.sql +980 -0
  111. package/drizzle/0201_company_profile_authority.sql +849 -0
  112. package/drizzle/0202_document_index_checkpoints.sql +85 -0
  113. package/drizzle/0203_durable_video_generation.sql +353 -0
  114. package/drizzle/0204_video_generation_funding.sql +44 -0
  115. package/drizzle/0205_attempt_tool_catalogs.sql +230 -0
  116. package/drizzle/0206_browser_sessions.sql +646 -0
  117. package/drizzle/0207_browser_identities.sql +379 -0
  118. package/drizzle/0208_attached_browser_devices.sql +165 -0
  119. package/drizzle/0209_computer_sessions.sql +575 -0
  120. package/drizzle/0210_browser_auth_network_interventions.sql +441 -0
  121. package/drizzle/0211_editable_artifact_session_links.sql +58 -0
  122. package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
  123. package/drizzle/0212_slack_installation_bindings.sql +348 -0
  124. package/drizzle/0213_browser_interaction_authority.sql +67 -0
  125. package/drizzle/0213_slack_user_link_access_requests.sql +177 -0
  126. package/drizzle/0214_browser_download_saves.sql +34 -0
  127. package/drizzle/0214_session_activity_commit_gate.sql +262 -0
  128. package/drizzle/0215_browser_controller_host.sql +385 -0
  129. package/drizzle/0215_capabilities_platform.sql +980 -0
  130. package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
  131. package/drizzle/0216_pack_component_ownership.sql +235 -0
  132. package/drizzle/0217_capability_definition_delete_authority.sql +32 -0
  133. package/drizzle/0217_external_browser_auth_operations.sql +22 -0
  134. package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
  135. package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
  136. package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
  137. package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
  138. package/drizzle/0220_session_channels.sql +54 -0
  139. package/drizzle/0221_sessions_channel_index.sql +5 -0
  140. package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
  141. package/drizzle/0222_sessions_channel_fk.sql +89 -0
  142. package/drizzle/0223_pending_tool_event_output.sql +55 -0
  143. package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
  144. package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
  145. package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
  146. package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
  147. package/drizzle/0227_slack_native_actions.sql +145 -0
  148. package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
  149. package/drizzle/0228_slack_task_policy.sql +400 -0
  150. package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
  151. package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
  152. package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
  153. package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
  154. package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
  155. package/drizzle/0234_xai_subscription_authority.sql +1139 -0
  156. package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
  157. package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
  158. package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
  159. package/drizzle/0237_interaction_transition_reaper.sql +263 -0
  160. package/drizzle/0238_goal_persistence_policy.sql +471 -0
  161. package/drizzle/0238_supergrok_realtime_model.sql +29 -0
  162. package/drizzle/0239_supergrok_video_funding.sql +50 -0
  163. package/drizzle/0239_task_tree_notes.sql +990 -0
  164. package/package.json +26 -5
  165. package/src/attached-browser-devices.ts +371 -0
  166. package/src/attempt-tool-catalogs.ts +131 -0
  167. package/src/browser-auth.ts +4373 -0
  168. package/src/browser-downloads.ts +517 -0
  169. package/src/browser-identities.ts +1385 -0
  170. package/src/browser-sessions.ts +2294 -0
  171. package/src/browser-state-artifacts.ts +449 -0
  172. package/src/canonical-human-identities.ts +317 -0
  173. package/src/capability-components.ts +166 -0
  174. package/src/capability-integrations.ts +1571 -0
  175. package/src/codemode-operations.ts +674 -0
  176. package/src/company-profile-schema.ts +143 -0
  177. package/src/company-profile.ts +968 -0
  178. package/src/computer-sessions.ts +1130 -0
  179. package/src/connection-token-resolver.ts +270 -25
  180. package/src/database.ts +468 -24
  181. package/src/editable-artifact-durable-export.ts +1201 -0
  182. package/src/editable-artifact-materialization.ts +893 -0
  183. package/src/editable-artifacts-schema.ts +879 -0
  184. package/src/editable-artifacts.ts +5404 -0
  185. package/src/generated-images.ts +740 -0
  186. package/src/index.ts +9963 -1465
  187. package/src/insights.ts +251 -23
  188. package/src/integration-bindings.ts +455 -0
  189. package/src/integration-facets.ts +862 -0
  190. package/src/interaction-revisions.ts +70 -0
  191. package/src/interaction-schema.ts +1606 -0
  192. package/src/knowledge-source-sync-schema.ts +192 -0
  193. package/src/knowledge-source-sync.ts +1922 -0
  194. package/src/memory-slack-delivery.ts +801 -0
  195. package/src/pack-components.ts +954 -0
  196. package/src/pack-installations.ts +886 -0
  197. package/src/persistence-errors.ts +4 -7
  198. package/src/plugin-packages.ts +1186 -0
  199. package/src/provision-roles.ts +534 -1
  200. package/src/runtime-posture-cli.ts +9 -0
  201. package/src/runtime-posture.ts +721 -5
  202. package/src/schema.ts +6270 -3159
  203. package/src/scoped-knowledge-schema.ts +1 -1
  204. package/src/scoped-knowledge.ts +655 -3
  205. package/src/session-control.ts +130 -42
  206. package/src/session-queue-commands.ts +265 -15
  207. package/src/session-realtime-context.ts +2 -2
  208. package/src/session-realtime-ledger.ts +3 -3
  209. package/src/session-realtime.ts +7 -7
  210. package/src/session-tenancy.ts +188 -0
  211. package/src/session-tool-call-settlement.ts +18 -3
  212. package/src/slack-task-policy-schema.ts +130 -0
  213. package/src/slack-task-policy.ts +341 -0
  214. package/src/slack-user-link-access.ts +702 -0
  215. package/src/task-notes-schema.ts +135 -0
  216. package/src/task-notes.ts +178 -0
  217. package/src/video-generation.ts +1530 -0
  218. package/src/workspace-artifacts.ts +1 -1
  219. package/src/workspace-learning-policy-schema.ts +139 -0
  220. package/src/workspace-learning-policy.ts +595 -0
  221. package/src/xai-subscription.ts +1887 -0
  222. package/dist/chunk-P6CUHXQZ.js +0 -7248
  223. package/dist/chunk-P6CUHXQZ.js.map +0 -1
  224. package/dist/chunk-VHBFHMPC.js +0 -1219
  225. package/dist/chunk-VHBFHMPC.js.map +0 -1
@@ -84,6 +84,18 @@ export class ScopedKnowledgeAuthorityError extends Error {
84
84
  readonly name = "ScopedKnowledgeAuthorityError";
85
85
  }
86
86
 
87
+ export class KnowledgeSourceSyncObservationFenceError extends Error {
88
+ readonly name = "KnowledgeSourceSyncObservationFenceError";
89
+ readonly code = "KNOWLEDGE_SOURCE_SYNC_OBSERVATION_FENCE";
90
+ }
91
+
92
+ export type KnowledgeSourceSyncVersionObservationFence = {
93
+ scheduledTaskRunId: string;
94
+ scanGeneration: number;
95
+ providerRevision: string | null;
96
+ metadataHash: string | null;
97
+ };
98
+
87
99
  function iso(value: Date | string): string {
88
100
  return (value instanceof Date ? value : new Date(value)).toISOString();
89
101
  }
@@ -808,6 +820,186 @@ export async function upsertKnowledgeSource(
808
820
  });
809
821
  }
810
822
 
823
+ export async function getKnowledgeSourceForSyncAuthority(
824
+ db: Database,
825
+ input: {
826
+ accountId: string;
827
+ workspaceId: string;
828
+ sourceId: string;
829
+ initiatingSubjectId: string;
830
+ },
831
+ ): Promise<{ source: KnowledgeSourceRecord; provider: KnowledgeProviderRecord } | null> {
832
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
833
+ const [row] = await scopedDb
834
+ .select({ source: schema.knowledgeSources, provider: schema.knowledgeProviders })
835
+ .from(schema.knowledgeSources)
836
+ .innerJoin(
837
+ schema.knowledgeProviders,
838
+ and(
839
+ eq(schema.knowledgeProviders.accountId, schema.knowledgeSources.accountId),
840
+ eq(schema.knowledgeProviders.id, schema.knowledgeSources.providerId),
841
+ eq(schema.knowledgeProviders.scopeKey, schema.knowledgeSources.scopeKey),
842
+ ),
843
+ )
844
+ .where(
845
+ and(
846
+ eq(schema.knowledgeSources.accountId, input.accountId),
847
+ eq(schema.knowledgeSources.id, input.sourceId),
848
+ ),
849
+ )
850
+ .limit(1);
851
+ return row
852
+ ? { source: sourceFromRow(row.source), provider: providerFromRow(row.provider) }
853
+ : null;
854
+ });
855
+ }
856
+
857
+ export async function getKnowledgeSourceByExternalIdentityForSyncAuthority(
858
+ db: Database,
859
+ input: {
860
+ accountId: string;
861
+ workspaceId: string;
862
+ providerId: string;
863
+ externalSourceId: string;
864
+ initiatingSubjectId: string;
865
+ },
866
+ ): Promise<KnowledgeSourceRecord | null> {
867
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
868
+ const [row] = await scopedDb
869
+ .select()
870
+ .from(schema.knowledgeSources)
871
+ .where(
872
+ and(
873
+ eq(schema.knowledgeSources.accountId, input.accountId),
874
+ eq(schema.knowledgeSources.providerId, input.providerId),
875
+ eq(schema.knowledgeSources.externalSourceId, input.externalSourceId),
876
+ ),
877
+ )
878
+ .limit(1);
879
+ return row ? sourceFromRow(row) : null;
880
+ });
881
+ }
882
+
883
+ export async function getKnowledgeSourceAclForSyncAuthority(
884
+ db: Database,
885
+ input: {
886
+ accountId: string;
887
+ workspaceId: string;
888
+ sourceId: string;
889
+ generation: number;
890
+ initiatingSubjectId: string;
891
+ },
892
+ ): Promise<KnowledgeSourceAclVersionRecord | null> {
893
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
894
+ const [row] = await scopedDb
895
+ .select()
896
+ .from(schema.knowledgeSourceAclVersions)
897
+ .where(
898
+ and(
899
+ eq(schema.knowledgeSourceAclVersions.accountId, input.accountId),
900
+ eq(schema.knowledgeSourceAclVersions.sourceId, input.sourceId),
901
+ eq(schema.knowledgeSourceAclVersions.generation, input.generation),
902
+ ),
903
+ )
904
+ .limit(1);
905
+ return row ? aclFromRow(row) : null;
906
+ });
907
+ }
908
+
909
+ export async function getKnowledgeSourceObjectForSyncAuthority(
910
+ db: Database,
911
+ input: {
912
+ accountId: string;
913
+ workspaceId: string;
914
+ sourceId: string;
915
+ externalObjectId: string;
916
+ initiatingSubjectId: string;
917
+ },
918
+ ): Promise<KnowledgeSourceObjectRecord | null> {
919
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
920
+ const [row] = await scopedDb
921
+ .select()
922
+ .from(schema.knowledgeSourceObjects)
923
+ .where(
924
+ and(
925
+ eq(schema.knowledgeSourceObjects.accountId, input.accountId),
926
+ eq(schema.knowledgeSourceObjects.sourceId, input.sourceId),
927
+ eq(schema.knowledgeSourceObjects.externalObjectId, input.externalObjectId),
928
+ ),
929
+ )
930
+ .limit(1);
931
+ return row ? objectFromRow(row) : null;
932
+ });
933
+ }
934
+
935
+ export async function getKnowledgeDocumentVersionForSyncAuthority(
936
+ db: Database,
937
+ input: {
938
+ accountId: string;
939
+ workspaceId: string;
940
+ versionId: string;
941
+ initiatingSubjectId: string;
942
+ },
943
+ ): Promise<KnowledgeDocumentVersionRecord | null> {
944
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
945
+ const [row] = await scopedDb
946
+ .select()
947
+ .from(schema.knowledgeDocumentVersions)
948
+ .where(
949
+ and(
950
+ eq(schema.knowledgeDocumentVersions.accountId, input.accountId),
951
+ eq(schema.knowledgeDocumentVersions.id, input.versionId),
952
+ ),
953
+ )
954
+ .limit(1);
955
+ return row ? versionFromRow(row) : null;
956
+ });
957
+ }
958
+
959
+ export async function getKnowledgeDocumentVersionObservationForSyncAuthority(
960
+ db: Database,
961
+ input: {
962
+ accountId: string;
963
+ workspaceId: string;
964
+ versionId: string;
965
+ initiatingSubjectId: string;
966
+ },
967
+ ): Promise<{
968
+ version: KnowledgeDocumentVersionRecord;
969
+ sourceMetadata: Record<string, unknown>;
970
+ sourceUpdatedAt: string | null;
971
+ locationMetadata: Record<string, unknown>;
972
+ documentChunkCount: number;
973
+ } | null> {
974
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
975
+ const [row] = await scopedDb
976
+ .select()
977
+ .from(schema.knowledgeDocumentVersions)
978
+ .where(
979
+ and(
980
+ eq(schema.knowledgeDocumentVersions.accountId, input.accountId),
981
+ eq(schema.knowledgeDocumentVersions.id, input.versionId),
982
+ ),
983
+ )
984
+ .limit(1);
985
+ if (!row) return null;
986
+ const [document] = row.documentId
987
+ ? await scopedDb
988
+ .select({ chunkCount: schema.documents.chunkCount })
989
+ .from(schema.documents)
990
+ .where(eq(schema.documents.id, row.documentId))
991
+ .limit(1)
992
+ : [];
993
+ return {
994
+ version: versionFromRow(row),
995
+ sourceMetadata: row.sourceMetadata,
996
+ sourceUpdatedAt: optionalIso(row.sourceUpdatedAt),
997
+ locationMetadata: row.locationMetadata,
998
+ documentChunkCount: document?.chunkCount ?? 0,
999
+ };
1000
+ });
1001
+ }
1002
+
811
1003
  export async function appendKnowledgeSourceAclVersion(
812
1004
  db: Database,
813
1005
  input: Omit<KnowledgeWriteContext, "scope"> & {
@@ -925,6 +1117,295 @@ export async function appendKnowledgeSourceAclVersion(
925
1117
  });
926
1118
  }
927
1119
 
1120
+ /** Atomically advance the source ACL to a deny generation and revoke every
1121
+ * materialized retrieval path. Delivery pause alone is never authorization. */
1122
+ export async function deauthorizeKnowledgeSourceRetrieval(
1123
+ db: Database,
1124
+ input: Omit<KnowledgeWriteContext, "scope"> & {
1125
+ sourceId: string;
1126
+ audience: ScopedKnowledgeScope;
1127
+ reasonCode: string;
1128
+ },
1129
+ ): Promise<KnowledgeSourceAclVersionRecord> {
1130
+ const reasonCode = normalizedStableKey(input.reasonCode, "reasonCode", 128);
1131
+ return await withKnowledgeWriteRls(db, { ...input, scope: input.audience }, async (scopedDb) => {
1132
+ const [source] = await scopedDb
1133
+ .select()
1134
+ .from(schema.knowledgeSources)
1135
+ .where(eq(schema.knowledgeSources.id, input.sourceId))
1136
+ .limit(1);
1137
+ if (!source) throw new ScopedKnowledgeNotFoundError("Knowledge source was not found");
1138
+ if (source.lifecycleState !== "active") {
1139
+ throw new ScopedKnowledgeInvalidOperationError(
1140
+ "A tombstoned knowledge source cannot be deauthorized",
1141
+ );
1142
+ }
1143
+ const acl = await appendKnowledgeSourceAclVersion(scopedDb, {
1144
+ accountId: input.accountId,
1145
+ workspaceId: input.workspaceId,
1146
+ sourceId: input.sourceId,
1147
+ audience: input.audience,
1148
+ expectedSourceLifecycleGeneration: source.lifecycleGeneration,
1149
+ expectedAclGeneration: source.currentAclGeneration ?? 0,
1150
+ aclVersion: `opengeni-deny:${reasonCode}`,
1151
+ agentAccess: false,
1152
+ operationId: input.operationId,
1153
+ reasonCode,
1154
+ actor: input.actor,
1155
+ });
1156
+ const revokedAt = new Date();
1157
+ const versions = await scopedDb
1158
+ .select({ documentId: schema.knowledgeDocumentVersions.documentId })
1159
+ .from(schema.knowledgeDocumentVersions)
1160
+ .where(eq(schema.knowledgeDocumentVersions.sourceId, input.sourceId));
1161
+ const documentIds = [
1162
+ ...new Set(versions.flatMap((version) => (version.documentId ? [version.documentId] : []))),
1163
+ ];
1164
+ await scopedDb
1165
+ .update(schema.knowledgeSourceSyncIndexObligations)
1166
+ .set({
1167
+ status: "invalidated",
1168
+ aclEligibility: "denied",
1169
+ failureCode: reasonCode,
1170
+ updatedAt: revokedAt,
1171
+ })
1172
+ .where(eq(schema.knowledgeSourceSyncIndexObligations.sourceId, input.sourceId));
1173
+ if (documentIds.length > 0) {
1174
+ await scopedDb
1175
+ .update(schema.documents)
1176
+ .set({ agentAccess: false, chunkCount: 0, updatedAt: revokedAt })
1177
+ .where(inArray(schema.documents.id, documentIds));
1178
+ await scopedDb
1179
+ .delete(schema.documentChunks)
1180
+ .where(inArray(schema.documentChunks.documentId, documentIds));
1181
+ }
1182
+ return acl;
1183
+ });
1184
+ }
1185
+
1186
+ type KnowledgeDocumentObservationMetadata = {
1187
+ title: string;
1188
+ sourceUri: string;
1189
+ sourceVersion: string;
1190
+ sourceUpdatedAt: Date | null;
1191
+ };
1192
+
1193
+ async function lockKnowledgeSourceSyncObservationFloor(
1194
+ scopedDb: Database,
1195
+ input: {
1196
+ sourceId: string;
1197
+ externalObjectId: string;
1198
+ fence: KnowledgeSourceSyncVersionObservationFence;
1199
+ },
1200
+ ): Promise<void> {
1201
+ const [observation] = await scopedDb
1202
+ .select({
1203
+ scheduledTaskRunId: schema.knowledgeSourceSyncObjectObservations.scheduledTaskRunId,
1204
+ scanGeneration: schema.knowledgeSourceSyncObjectObservations.scanGeneration,
1205
+ providerRevision: schema.knowledgeSourceSyncObjectObservations.providerRevision,
1206
+ metadataHash: schema.knowledgeSourceSyncObjectObservations.metadataHash,
1207
+ })
1208
+ .from(schema.knowledgeSourceSyncObjectObservations)
1209
+ .where(
1210
+ and(
1211
+ eq(schema.knowledgeSourceSyncObjectObservations.sourceId, input.sourceId),
1212
+ eq(schema.knowledgeSourceSyncObjectObservations.externalObjectId, input.externalObjectId),
1213
+ ),
1214
+ )
1215
+ .for("share")
1216
+ .limit(1);
1217
+ if (
1218
+ !observation ||
1219
+ observation.scheduledTaskRunId !== input.fence.scheduledTaskRunId ||
1220
+ observation.scanGeneration !== input.fence.scanGeneration ||
1221
+ observation.providerRevision !== input.fence.providerRevision ||
1222
+ observation.metadataHash !== input.fence.metadataHash
1223
+ ) {
1224
+ throw new KnowledgeSourceSyncObservationFenceError(
1225
+ "Knowledge source observation floor changed before document mutation",
1226
+ );
1227
+ }
1228
+ }
1229
+
1230
+ async function lockActiveKnowledgeDocumentAuthority(
1231
+ scopedDb: Database,
1232
+ input: {
1233
+ accountId: string;
1234
+ sourceId: string;
1235
+ expectedSourceLifecycleGeneration: number;
1236
+ objectId: string;
1237
+ expectedObjectLifecycleGeneration: number;
1238
+ },
1239
+ ): Promise<{ currentVersionId: string | null; externalObjectId: string }> {
1240
+ await scopedDb.execute(sql`
1241
+ SELECT knowledge_source_sync_lock_authority(
1242
+ ${input.accountId}::uuid,
1243
+ ${input.sourceId}::uuid,
1244
+ ${input.objectId}::uuid
1245
+ )
1246
+ `);
1247
+ const [[source], [object]] = await Promise.all([
1248
+ scopedDb
1249
+ .select({
1250
+ lifecycleState: schema.knowledgeSources.lifecycleState,
1251
+ lifecycleGeneration: schema.knowledgeSources.lifecycleGeneration,
1252
+ })
1253
+ .from(schema.knowledgeSources)
1254
+ .where(eq(schema.knowledgeSources.id, input.sourceId))
1255
+ .limit(1),
1256
+ scopedDb
1257
+ .select({
1258
+ sourceId: schema.knowledgeSourceObjects.sourceId,
1259
+ lifecycleState: schema.knowledgeSourceObjects.lifecycleState,
1260
+ lifecycleGeneration: schema.knowledgeSourceObjects.lifecycleGeneration,
1261
+ currentVersionId: schema.knowledgeSourceObjects.currentVersionId,
1262
+ externalObjectId: schema.knowledgeSourceObjects.externalObjectId,
1263
+ })
1264
+ .from(schema.knowledgeSourceObjects)
1265
+ .where(eq(schema.knowledgeSourceObjects.id, input.objectId))
1266
+ .limit(1),
1267
+ ]);
1268
+ if (
1269
+ !source ||
1270
+ !object ||
1271
+ source.lifecycleState !== "active" ||
1272
+ source.lifecycleGeneration !== input.expectedSourceLifecycleGeneration ||
1273
+ object.sourceId !== input.sourceId ||
1274
+ object.lifecycleState !== "active" ||
1275
+ object.lifecycleGeneration !== input.expectedObjectLifecycleGeneration
1276
+ ) {
1277
+ throw new ScopedKnowledgeGenerationConflictError(
1278
+ "Knowledge document metadata authority is no longer active",
1279
+ );
1280
+ }
1281
+ return { currentVersionId: object.currentVersionId, externalObjectId: object.externalObjectId };
1282
+ }
1283
+
1284
+ async function convergeKnowledgeDocumentObservationMetadata(
1285
+ scopedDb: Database,
1286
+ input: {
1287
+ accountId: string;
1288
+ workspaceId: string;
1289
+ documentId: string;
1290
+ metadata: KnowledgeDocumentObservationMetadata;
1291
+ },
1292
+ ): Promise<void> {
1293
+ const updatedAt = new Date();
1294
+ const chunkProvenanceMetadata = JSON.stringify({
1295
+ documentTitle: input.metadata.title,
1296
+ sourceUri: input.metadata.sourceUri,
1297
+ sourceTitle: input.metadata.title,
1298
+ sourceUpdatedAt: input.metadata.sourceUpdatedAt?.toISOString() ?? null,
1299
+ sourceVersion: input.metadata.sourceVersion,
1300
+ });
1301
+ const [updated] = await scopedDb
1302
+ .update(schema.documents)
1303
+ .set({
1304
+ title: input.metadata.title,
1305
+ sourceUri: input.metadata.sourceUri,
1306
+ sourceTitle: input.metadata.title,
1307
+ sourceVersion: input.metadata.sourceVersion,
1308
+ sourceUpdatedAt: input.metadata.sourceUpdatedAt,
1309
+ updatedAt,
1310
+ })
1311
+ .where(
1312
+ and(
1313
+ eq(schema.documents.accountId, input.accountId),
1314
+ eq(schema.documents.workspaceId, input.workspaceId),
1315
+ eq(schema.documents.id, input.documentId),
1316
+ ),
1317
+ )
1318
+ .returning({ id: schema.documents.id });
1319
+ if (!updated) throw new ScopedKnowledgeNotFoundError("Knowledge document was not found");
1320
+
1321
+ await scopedDb
1322
+ .update(schema.documentChunks)
1323
+ .set({
1324
+ metadata: sql<Record<string, unknown>>`${schema.documentChunks.metadata} ||
1325
+ ${chunkProvenanceMetadata}::jsonb`,
1326
+ })
1327
+ .where(
1328
+ and(
1329
+ eq(schema.documentChunks.accountId, input.accountId),
1330
+ eq(schema.documentChunks.workspaceId, input.workspaceId),
1331
+ eq(schema.documentChunks.documentId, input.documentId),
1332
+ ),
1333
+ );
1334
+ }
1335
+
1336
+ export async function updateKnowledgeSourceDocumentObservationMetadata(
1337
+ db: Database,
1338
+ input: {
1339
+ accountId: string;
1340
+ workspaceId: string;
1341
+ initiatingSubjectId: string;
1342
+ sourceId: string;
1343
+ expectedSourceLifecycleGeneration: number;
1344
+ objectId: string;
1345
+ expectedObjectLifecycleGeneration: number;
1346
+ versionId: string;
1347
+ documentId: string;
1348
+ title: string;
1349
+ sourceUri: string;
1350
+ sourceVersion: string;
1351
+ sourceUpdatedAt: string | null;
1352
+ syncObservation?: KnowledgeSourceSyncVersionObservationFence;
1353
+ },
1354
+ ): Promise<void> {
1355
+ const metadata: KnowledgeDocumentObservationMetadata = {
1356
+ title: boundedText(input.title, "title", 1000),
1357
+ sourceUri: boundedText(input.sourceUri, "sourceUri", 4096),
1358
+ sourceVersion: boundedText(input.sourceVersion, "sourceVersion", 1024),
1359
+ sourceUpdatedAt: input.sourceUpdatedAt ? new Date(input.sourceUpdatedAt) : null,
1360
+ };
1361
+ await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
1362
+ if (input.syncObservation) {
1363
+ const [observationObject] = await scopedDb
1364
+ .select({
1365
+ sourceId: schema.knowledgeSourceObjects.sourceId,
1366
+ externalObjectId: schema.knowledgeSourceObjects.externalObjectId,
1367
+ })
1368
+ .from(schema.knowledgeSourceObjects)
1369
+ .where(eq(schema.knowledgeSourceObjects.id, input.objectId))
1370
+ .limit(1);
1371
+ if (!observationObject || observationObject.sourceId !== input.sourceId) {
1372
+ throw new KnowledgeSourceSyncObservationFenceError(
1373
+ "Knowledge source observation object is no longer current",
1374
+ );
1375
+ }
1376
+ await lockKnowledgeSourceSyncObservationFloor(scopedDb, {
1377
+ sourceId: input.sourceId,
1378
+ externalObjectId: observationObject.externalObjectId,
1379
+ fence: input.syncObservation,
1380
+ });
1381
+ }
1382
+ const object = await lockActiveKnowledgeDocumentAuthority(scopedDb, input);
1383
+ const [version] = await scopedDb
1384
+ .select()
1385
+ .from(schema.knowledgeDocumentVersions)
1386
+ .where(eq(schema.knowledgeDocumentVersions.id, input.versionId))
1387
+ .limit(1);
1388
+ if (
1389
+ !object ||
1390
+ !version ||
1391
+ object.currentVersionId !== input.versionId ||
1392
+ version.sourceId !== input.sourceId ||
1393
+ version.objectId !== input.objectId ||
1394
+ version.documentId !== input.documentId
1395
+ ) {
1396
+ throw new ScopedKnowledgeGenerationConflictError(
1397
+ "Knowledge document metadata observation is no longer current",
1398
+ );
1399
+ }
1400
+ await convergeKnowledgeDocumentObservationMetadata(scopedDb, {
1401
+ accountId: input.accountId,
1402
+ workspaceId: input.workspaceId,
1403
+ documentId: input.documentId,
1404
+ metadata,
1405
+ });
1406
+ });
1407
+ }
1408
+
928
1409
  export async function beginKnowledgeSyncRun(
929
1410
  db: Database,
930
1411
  input: Omit<KnowledgeWriteContext, "scope"> & {
@@ -1026,6 +1507,32 @@ export async function beginKnowledgeSyncRun(
1026
1507
  );
1027
1508
  }
1028
1509
 
1510
+ export async function getKnowledgeSyncRunForSyncAuthority(
1511
+ db: Database,
1512
+ input: {
1513
+ accountId: string;
1514
+ workspaceId: string;
1515
+ sourceId: string;
1516
+ operationId: string;
1517
+ initiatingSubjectId: string;
1518
+ },
1519
+ ): Promise<KnowledgeSyncRunRecord | null> {
1520
+ return await withKnowledgeReadRls(db, { ...input, surface: "human" }, async (scopedDb) => {
1521
+ const [row] = await scopedDb
1522
+ .select()
1523
+ .from(schema.knowledgeSyncRuns)
1524
+ .where(
1525
+ and(
1526
+ eq(schema.knowledgeSyncRuns.accountId, input.accountId),
1527
+ eq(schema.knowledgeSyncRuns.sourceId, input.sourceId),
1528
+ eq(schema.knowledgeSyncRuns.operationId, input.operationId),
1529
+ ),
1530
+ )
1531
+ .limit(1);
1532
+ return row ? syncFromRow(row) : null;
1533
+ });
1534
+ }
1535
+
1029
1536
  export async function completeKnowledgeSyncRun(
1030
1537
  db: Database,
1031
1538
  input: {
@@ -1066,7 +1573,7 @@ export async function completeKnowledgeSyncRun(
1066
1573
  ${input.runId}::uuid,
1067
1574
  ${input.state},
1068
1575
  ${input.state === "succeeded" ? outputCursor : null},
1069
- ${input.watermark ? new Date(input.watermark) : null}::timestamptz,
1576
+ ${input.watermark ?? null}::timestamptz,
1070
1577
  ${JSON.stringify(metadata)}::jsonb,
1071
1578
  ${input.state === "failed" ? errorCode : null},
1072
1579
  ${completionHash},
@@ -1251,6 +1758,7 @@ export async function appendKnowledgeDocumentVersion(
1251
1758
  db: Database,
1252
1759
  input: Omit<KnowledgeWriteContext, "scope"> & {
1253
1760
  objectId: string;
1761
+ expectedSourceLifecycleGeneration: number;
1254
1762
  expectedObjectLifecycleGeneration: number;
1255
1763
  expectedVersionGeneration: number;
1256
1764
  externalVersionId: string;
@@ -1265,6 +1773,13 @@ export async function appendKnowledgeDocumentVersion(
1265
1773
  documentId?: string | null;
1266
1774
  fileId?: string | null;
1267
1775
  locationMetadata?: Record<string, unknown> | undefined;
1776
+ documentObservationMetadata?: {
1777
+ title: string;
1778
+ sourceUri: string;
1779
+ sourceVersion: string;
1780
+ sourceUpdatedAt: string | null;
1781
+ };
1782
+ syncObservation?: KnowledgeSourceSyncVersionObservationFence;
1268
1783
  reasonCode: string;
1269
1784
  },
1270
1785
  ): Promise<KnowledgeDocumentVersionRecord> {
@@ -1274,6 +1789,18 @@ export async function appendKnowledgeDocumentVersion(
1274
1789
  const sourceCursor =
1275
1790
  input.sourceCursor == null ? null : boundedText(input.sourceCursor, "sourceCursor", 4096);
1276
1791
  const reasonCode = normalizedStableKey(input.reasonCode, "reasonCode", 128);
1792
+ const documentObservationMetadata = input.documentObservationMetadata
1793
+ ? {
1794
+ title: boundedText(input.documentObservationMetadata.title, "title", 1000),
1795
+ sourceUri: boundedText(input.documentObservationMetadata.sourceUri, "sourceUri", 4096),
1796
+ sourceVersion: boundedText(
1797
+ input.documentObservationMetadata.sourceVersion,
1798
+ "sourceVersion",
1799
+ 1024,
1800
+ ),
1801
+ sourceUpdatedAt: input.documentObservationMetadata.sourceUpdatedAt,
1802
+ }
1803
+ : null;
1277
1804
  const placeholderScope: ScopedKnowledgeScope = {
1278
1805
  kind: "workspace",
1279
1806
  workspaceId: input.workspaceId,
@@ -1295,6 +1822,7 @@ export async function appendKnowledgeDocumentVersion(
1295
1822
  validateScope(objectScope, input.workspaceId, input.actor.initiatingHumanSubjectId);
1296
1823
  const inputHash = scopedKnowledgeInputHash({
1297
1824
  objectId: input.objectId,
1825
+ expectedSourceLifecycleGeneration: input.expectedSourceLifecycleGeneration,
1298
1826
  expectedObjectLifecycleGeneration: input.expectedObjectLifecycleGeneration,
1299
1827
  expectedVersionGeneration: input.expectedVersionGeneration,
1300
1828
  externalVersionId,
@@ -1309,9 +1837,51 @@ export async function appendKnowledgeDocumentVersion(
1309
1837
  documentId: input.documentId ?? null,
1310
1838
  fileId: input.fileId ?? null,
1311
1839
  locationMetadata: input.locationMetadata ?? {},
1840
+ documentObservationMetadata,
1841
+ syncObservation: input.syncObservation ?? null,
1312
1842
  reasonCode,
1313
1843
  actor: input.actor,
1314
1844
  });
1845
+ if (input.syncObservation) {
1846
+ await lockKnowledgeSourceSyncObservationFloor(scopedDb, {
1847
+ sourceId: object.sourceId,
1848
+ externalObjectId: object.externalObjectId,
1849
+ fence: input.syncObservation,
1850
+ });
1851
+ }
1852
+ const convergeDocumentObservation = async (version: VersionRow): Promise<void> => {
1853
+ if (!documentObservationMetadata) return;
1854
+ if (!version.documentId || version.documentId !== (input.documentId ?? null)) {
1855
+ throw new ScopedKnowledgeConflictError(
1856
+ "Knowledge document observation metadata has no matching document",
1857
+ );
1858
+ }
1859
+ const liveObject = await lockActiveKnowledgeDocumentAuthority(scopedDb, {
1860
+ accountId: input.accountId,
1861
+ sourceId: object.sourceId,
1862
+ expectedSourceLifecycleGeneration: input.expectedSourceLifecycleGeneration,
1863
+ objectId: input.objectId,
1864
+ expectedObjectLifecycleGeneration: input.expectedObjectLifecycleGeneration,
1865
+ });
1866
+ if (version.sourceId !== object.sourceId || liveObject.currentVersionId !== version.id) {
1867
+ throw new ScopedKnowledgeGenerationConflictError(
1868
+ "Knowledge document metadata observation is no longer current",
1869
+ );
1870
+ }
1871
+ await convergeKnowledgeDocumentObservationMetadata(scopedDb, {
1872
+ accountId: input.accountId,
1873
+ workspaceId: input.workspaceId,
1874
+ documentId: version.documentId,
1875
+ metadata: {
1876
+ title: documentObservationMetadata.title,
1877
+ sourceUri: documentObservationMetadata.sourceUri,
1878
+ sourceVersion: documentObservationMetadata.sourceVersion,
1879
+ sourceUpdatedAt: documentObservationMetadata.sourceUpdatedAt
1880
+ ? new Date(documentObservationMetadata.sourceUpdatedAt)
1881
+ : null,
1882
+ },
1883
+ });
1884
+ };
1315
1885
  const receiptResultId = await lockConvergentKnowledgeOperation(scopedDb, {
1316
1886
  accountId: input.accountId,
1317
1887
  operationKind: "document_version",
@@ -1330,6 +1900,7 @@ export async function appendKnowledgeDocumentVersion(
1330
1900
  "Knowledge document-version operation receipt has no visible result",
1331
1901
  );
1332
1902
  }
1903
+ await convergeDocumentObservation(replayed);
1333
1904
  return versionFromRow(replayed);
1334
1905
  }
1335
1906
  const existingRows = await scopedDb
@@ -1340,7 +1911,6 @@ export async function appendKnowledgeDocumentVersion(
1340
1911
  eq(schema.knowledgeDocumentVersions.objectId, input.objectId),
1341
1912
  sql`(
1342
1913
  ${schema.knowledgeDocumentVersions.operationId} = ${input.operationId}
1343
- OR ${schema.knowledgeDocumentVersions.externalVersionId} = ${externalVersionId}
1344
1914
  OR ${schema.knowledgeDocumentVersions.ingestionKey} = ${ingestionKey}
1345
1915
  )`,
1346
1916
  ),
@@ -1366,6 +1936,7 @@ export async function appendKnowledgeDocumentVersion(
1366
1936
  resultId: existing.id,
1367
1937
  actor: input.actor,
1368
1938
  });
1939
+ await convergeDocumentObservation(existing);
1369
1940
  return versionFromRow(existing);
1370
1941
  }
1371
1942
  const [source, acl] = await Promise.all([
@@ -1395,6 +1966,7 @@ export async function appendKnowledgeDocumentVersion(
1395
1966
  object.lifecycleGeneration !== input.expectedObjectLifecycleGeneration ||
1396
1967
  object.versionGeneration !== input.expectedVersionGeneration ||
1397
1968
  sourceRow.lifecycleState !== "active" ||
1969
+ sourceRow.lifecycleGeneration !== input.expectedSourceLifecycleGeneration ||
1398
1970
  sourceRow.currentAclGeneration !== input.aclGeneration
1399
1971
  ) {
1400
1972
  throw new ScopedKnowledgeGenerationConflictError(
@@ -1439,7 +2011,6 @@ export async function appendKnowledgeDocumentVersion(
1439
2011
  eq(schema.knowledgeDocumentVersions.objectId, input.objectId),
1440
2012
  sql`(
1441
2013
  ${schema.knowledgeDocumentVersions.operationId} = ${input.operationId}
1442
- OR ${schema.knowledgeDocumentVersions.externalVersionId} = ${externalVersionId}
1443
2014
  OR ${schema.knowledgeDocumentVersions.ingestionKey} = ${ingestionKey}
1444
2015
  )`,
1445
2016
  ),
@@ -1456,6 +2027,7 @@ export async function appendKnowledgeDocumentVersion(
1456
2027
  resultId: converged.id,
1457
2028
  actor: input.actor,
1458
2029
  });
2030
+ await convergeDocumentObservation(converged);
1459
2031
  return versionFromRow(converged);
1460
2032
  }
1461
2033
  throw new ScopedKnowledgeGenerationConflictError(
@@ -1477,6 +2049,44 @@ export async function appendKnowledgeDocumentVersion(
1477
2049
  ${input.actor.initiatingHumanSubjectId}
1478
2050
  )
1479
2051
  `);
2052
+ await convergeDocumentObservation(created);
2053
+ if (object.currentVersionId) {
2054
+ const [previousVersion] = await scopedDb
2055
+ .select({ documentId: schema.knowledgeDocumentVersions.documentId })
2056
+ .from(schema.knowledgeDocumentVersions)
2057
+ .where(eq(schema.knowledgeDocumentVersions.id, object.currentVersionId))
2058
+ .limit(1);
2059
+ if (previousVersion?.documentId) {
2060
+ const retiredAt = new Date();
2061
+ await scopedDb
2062
+ .update(schema.knowledgeSourceSyncIndexObligations)
2063
+ .set({
2064
+ status: "invalidated",
2065
+ aclEligibility: "denied",
2066
+ failureCode: "superseded_source_version",
2067
+ updatedAt: retiredAt,
2068
+ })
2069
+ .where(
2070
+ eq(
2071
+ schema.knowledgeSourceSyncIndexObligations.knowledgeDocumentVersionId,
2072
+ object.currentVersionId,
2073
+ ),
2074
+ );
2075
+ await scopedDb
2076
+ .update(schema.documents)
2077
+ .set({ agentAccess: false, updatedAt: retiredAt })
2078
+ .where(eq(schema.documents.id, previousVersion.documentId));
2079
+ if (previousVersion.documentId !== created.documentId) {
2080
+ await scopedDb
2081
+ .update(schema.documents)
2082
+ .set({ chunkCount: 0, updatedAt: retiredAt })
2083
+ .where(eq(schema.documents.id, previousVersion.documentId));
2084
+ await scopedDb
2085
+ .delete(schema.documentChunks)
2086
+ .where(eq(schema.documentChunks.documentId, previousVersion.documentId));
2087
+ }
2088
+ }
2089
+ }
1480
2090
  await recordConvergentKnowledgeOperation(scopedDb, {
1481
2091
  accountId: input.accountId,
1482
2092
  scope: objectScope,
@@ -1552,6 +2162,48 @@ export async function recordKnowledgeLifecycleEvent(
1552
2162
  }>;
1553
2163
  const row = rows[0];
1554
2164
  if (!row) throw new Error("Knowledge lifecycle transition returned no row");
2165
+ if (
2166
+ (input.targetKind === "source" || input.targetKind === "object") &&
2167
+ input.eventType !== "restored"
2168
+ ) {
2169
+ const retiredAt = new Date();
2170
+ const versions = await scopedDb
2171
+ .select({ documentId: schema.knowledgeDocumentVersions.documentId })
2172
+ .from(schema.knowledgeDocumentVersions)
2173
+ .where(
2174
+ input.targetKind === "source"
2175
+ ? eq(schema.knowledgeDocumentVersions.sourceId, input.targetId)
2176
+ : eq(schema.knowledgeDocumentVersions.objectId, input.targetId),
2177
+ );
2178
+ const documentIds = versions.flatMap((version) =>
2179
+ version.documentId ? [version.documentId] : [],
2180
+ );
2181
+ await scopedDb
2182
+ .update(schema.knowledgeSourceSyncIndexObligations)
2183
+ .set({
2184
+ status: "invalidated",
2185
+ aclEligibility: "denied",
2186
+ failureCode: `${input.targetKind}_${input.eventType}`,
2187
+ updatedAt: retiredAt,
2188
+ })
2189
+ .where(
2190
+ input.targetKind === "source"
2191
+ ? eq(schema.knowledgeSourceSyncIndexObligations.sourceId, input.targetId)
2192
+ : eq(
2193
+ schema.knowledgeSourceSyncIndexObligations.knowledgeSourceObjectId,
2194
+ input.targetId,
2195
+ ),
2196
+ );
2197
+ if (documentIds.length > 0) {
2198
+ await scopedDb
2199
+ .update(schema.documents)
2200
+ .set({ agentAccess: false, chunkCount: 0, updatedAt: retiredAt })
2201
+ .where(inArray(schema.documents.id, documentIds));
2202
+ await scopedDb
2203
+ .delete(schema.documentChunks)
2204
+ .where(inArray(schema.documentChunks.documentId, documentIds));
2205
+ }
2206
+ }
1555
2207
  return {
1556
2208
  targetId: row.target_id,
1557
2209
  lifecycleState: row.lifecycle_state,