thinkwork-cli 0.13.1 → 1.0.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 (262) hide show
  1. package/README.md +3 -14
  2. package/dist/{api-client-4DZ266J5.js → api-client-4P4JZOBX.js} +3 -1
  3. package/dist/bowser-6Z6JFAIR.js +2822 -0
  4. package/dist/{chunk-Y2WHJECR.js → chunk-4OMDWYZQ.js} +5 -44
  5. package/dist/chunk-AD2NIWB5.js +6516 -0
  6. package/dist/chunk-DV3MRBR5.js +43 -0
  7. package/dist/chunk-EI5ZX7CN.js +522 -0
  8. package/dist/chunk-EUJ7X6YD.js +126 -0
  9. package/dist/chunk-GG5WKBOX.js +436 -0
  10. package/dist/chunk-I64EZSU5.js +358 -0
  11. package/dist/chunk-KMIJ5KGT.js +128 -0
  12. package/dist/chunk-MWQ7RO76.js +137 -0
  13. package/dist/chunk-OCPHU34C.js +996 -0
  14. package/dist/chunk-OLUQ4U2Z.js +1728 -0
  15. package/dist/chunk-XYM7PE2A.js +2264 -0
  16. package/dist/chunk-YQCYD6NE.js +3299 -0
  17. package/dist/cli.js +49156 -31257
  18. package/dist/commands/enterprise/templates/deploy-repo/scripts/apply-release.mjs +0 -1
  19. package/dist/commands/enterprise/templates/deploy-repo/scripts/smoke.mjs +0 -1
  20. package/dist/commands/enterprise/templates/deploy-repo/terraform/main.tf +0 -14
  21. package/dist/dist-es-2OTNTL4N.js +315 -0
  22. package/dist/dist-es-2XVAH4BQ.js +14726 -0
  23. package/dist/dist-es-3DPDUJAH.js +2000 -0
  24. package/dist/dist-es-BNZTBBVC.js +176 -0
  25. package/dist/dist-es-CD2RBDAC.js +88 -0
  26. package/dist/dist-es-I4FW57PS.js +88 -0
  27. package/dist/dist-es-KL7Y5NB2.js +377 -0
  28. package/dist/dist-es-KVFWJNDY.js +318 -0
  29. package/dist/dist-es-PS73DWNL.js +70 -0
  30. package/dist/dist-es-S3NZQFGT.js +170 -0
  31. package/dist/dist-es-SGCA4P32.js +48 -0
  32. package/dist/dist-es-WBM6J4RA.js +70 -0
  33. package/dist/dist-es-ZGVADYIF.js +485 -0
  34. package/dist/dist-es-ZKC2QKD2.js +377 -0
  35. package/dist/drizzle/0076_scheduled_jobs_marco_backfill.sql +2 -1
  36. package/dist/drizzle/0079_seed_tenant_customize_catalog.sql +1 -0
  37. package/dist/drizzle/0090_brain_schema_extraction.sql +10 -0
  38. package/dist/drizzle/0132_drop_computer_tables.sql +3 -0
  39. package/dist/drizzle/0160_compliance_event_types_plugins.sql +2 -0
  40. package/dist/drizzle/0214_think137_drop_judge_evidence_roi.sql +1 -0
  41. package/dist/drizzle/0216_drop_agent_loop_versions_goal_worker_policy.sql +1 -0
  42. package/dist/drizzle/0227_analyst_reader_role.sql +17 -20
  43. package/dist/drizzle/0230_analyst_rls.sql +28 -36
  44. package/dist/drizzle/0250_kg_schema_extraction.sql +27 -0
  45. package/dist/drizzle/0251_brain_stragglers.sql +21 -0
  46. package/dist/drizzle/0253_drop_brain_substrate.sql +2 -0
  47. package/dist/drizzle/0257_agents_runtime_allow_harness.sql +24 -0
  48. package/dist/drizzle/0261_native_auth_control_plane.sql +332 -0
  49. package/dist/drizzle/0262_auth_subscription_tickets.sql +59 -0
  50. package/dist/drizzle/0263_agentcore_runtime_identifier.sql +69 -0
  51. package/dist/drizzle/0263_drop_workos_auth_runtime.sql +236 -0
  52. package/dist/drizzle/0264_auth_enrollment_attempt_limits.sql +15 -0
  53. package/dist/drizzle/0265_eval_runs_requester_identity.sql +28 -0
  54. package/dist/drizzle/0265_require_fully_valid_auth_publication.sql +27 -0
  55. package/dist/drizzle/0266_auth_identity_recovery_grants.sql +9 -0
  56. package/dist/drizzle/0266_eval_profiles_runtime_type.sql +12 -0
  57. package/dist/drizzle/0267_ontology_candidate_rejections.sql +53 -0
  58. package/dist/drizzle/0268_identity_crosswalk_routing.sql +182 -0
  59. package/dist/drizzle/0269_ontology_system_map.sql +31 -0
  60. package/dist/drizzle/0270_tool_execution_ledger.sql +115 -0
  61. package/dist/drizzle/0271_ontology_twin_declarations.sql +47 -0
  62. package/dist/drizzle/0272_identity_graph_projection_cursor.sql +23 -0
  63. package/dist/drizzle/0273_twin_materialization_suggestions.sql +29 -0
  64. package/dist/drizzle/0274_tenant_mcp_twin_keys.sql +59 -0
  65. package/dist/drizzle/0275_identity_bulk_rebuild_fence.sql +30 -0
  66. package/dist/drizzle/0276_tool_execution_ledger_allow_cascade_delete.sql +18 -0
  67. package/dist/drizzle/0277_knowledge_base_sources.sql +107 -0
  68. package/dist/drizzle/0278_kb_page_transcription.sql +55 -0
  69. package/dist/drizzle/0279_mcp_servers_off_plugin_provenance.sql +93 -0
  70. package/dist/drizzle/0280_work_item_external_refs_drop_plane_provider.sql +46 -0
  71. package/dist/drizzle/0281_tenant_mcp_twin_keys_expiry_suffix.sql +9 -0
  72. package/dist/drizzle/0282_tenant_mcp_twin_keys_grants.sql +24 -0
  73. package/dist/drizzle/0283_agents_agentcore_runtime_dispatch.sql +13 -0
  74. package/dist/drizzle/0284_user_brain_claims.sql +69 -0
  75. package/dist/drizzle/0285_tenant_mcp_twin_keys_trusted_subsystem.sql +30 -0
  76. package/dist/drizzle/0286_brain_analytics_key.sql +26 -0
  77. package/dist/drizzle/0287_brain_subject.sql +25 -0
  78. package/dist/drizzle/0288_multi_lane_identities.sql +25 -0
  79. package/dist/event-streams-7JNLJEEL.js +894 -0
  80. package/dist/event-streams-KDF5RWR6.js +1515 -0
  81. package/dist/loadSso-ETCXTR4I.js +576 -0
  82. package/dist/loadSso-UBD7KUHE.js +583 -0
  83. package/dist/plugins/README.md +2 -2
  84. package/dist/plugins/catalog/package.json +1 -5
  85. package/dist/plugins/catalog/src/__tests__/build-catalog.test.ts +6 -4
  86. package/dist/plugins/catalog/src/__tests__/catalog.test.ts +21 -21
  87. package/dist/plugins/catalog/src/__tests__/contracts.test.ts +102 -94
  88. package/dist/plugins/catalog/src/__tests__/plugin-package.test.ts +7 -8
  89. package/dist/plugins/catalog/src/__tests__/plugin-registry.test.ts +0 -20
  90. package/dist/plugins/catalog/src/contracts.ts +17 -179
  91. package/dist/plugins/catalog/src/registry/generated-first-party.ts +0 -24
  92. package/dist/plugins/n8n/test/integrated-app-contract.test.ts +1 -1
  93. package/dist/plugins/twenty/package.json +2 -1
  94. package/dist/plugins/twenty/scripts/LAMBDA_DEPLOY.md +114 -0
  95. package/dist/plugins/twenty/scripts/build-lambda.sh +29 -0
  96. package/dist/plugins/twenty/scripts/configure-product-views.ts +195 -0
  97. package/dist/plugins/twenty/scripts/lambda-handler.ts +49 -0
  98. package/dist/plugins/twenty/scripts/lib/__tests__/load-attachments.test.ts +38 -0
  99. package/dist/plugins/twenty/scripts/lib/__tests__/load-records.test.ts +145 -2
  100. package/dist/plugins/twenty/scripts/lib/__tests__/mappers.test.ts +397 -151
  101. package/dist/plugins/twenty/scripts/lib/__tests__/members-ensure.test.ts +28 -129
  102. package/dist/plugins/twenty/scripts/lib/__tests__/provision-members-db.test.ts +10 -0
  103. package/dist/plugins/twenty/scripts/lib/__tests__/schema-ensure.test.ts +13 -8
  104. package/dist/plugins/twenty/scripts/lib/lastmile-reader.ts +222 -2
  105. package/dist/plugins/twenty/scripts/lib/load-attachments.ts +29 -0
  106. package/dist/plugins/twenty/scripts/lib/load-records.ts +160 -43
  107. package/dist/plugins/twenty/scripts/lib/mappers.ts +368 -152
  108. package/dist/plugins/twenty/scripts/lib/members-ensure.ts +43 -268
  109. package/dist/plugins/twenty/scripts/lib/provision-members-db.ts +57 -0
  110. package/dist/plugins/twenty/scripts/lib/schema-ensure.ts +136 -31
  111. package/dist/plugins/twenty/scripts/migrate-lastmile.ts +254 -152
  112. package/dist/plugins/twenty/scripts/provision-twenty-members.ts +44 -1
  113. package/dist/plugins/twenty/scripts/purge-lastmile-import.ts +178 -0
  114. package/dist/plugins/twenty/scripts/restructure-products.ts +312 -0
  115. package/dist/plugins/twenty/scripts/retag-stage-values.ts +362 -0
  116. package/dist/plugins/twenty/test/manifest.test.ts +2 -4
  117. package/dist/scripts/post-deploy.sh +79 -1
  118. package/dist/signin-5QZNRSOO.js +821 -0
  119. package/dist/sso-oidc-XK673P54.js +837 -0
  120. package/dist/sts-OXI2UALF.js +1113 -0
  121. package/dist/sts-SQW4NBK3.js +1117 -0
  122. package/dist/terraform/examples/greenfield/main.tf +391 -176
  123. package/dist/terraform/examples/greenfield/terraform.tfvars.example +26 -8
  124. package/dist/terraform/modules/app/agentcore-admin/main.tf +47 -0
  125. package/dist/terraform/modules/app/agentcore-code-interpreter/README.md +39 -47
  126. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +13 -66
  127. package/dist/terraform/modules/app/agentcore-identity/main.tf +253 -0
  128. package/dist/terraform/modules/app/agentcore-identity/outputs.tf +51 -0
  129. package/dist/terraform/modules/app/agentcore-identity/scripts/bootstrap_twenty_oauth_client.sh +239 -0
  130. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_identity.sh +22 -0
  131. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_twenty_identity.sh +16 -0
  132. package/dist/terraform/modules/app/agentcore-identity/scripts/delete_workload_identity.sh +19 -0
  133. package/dist/terraform/modules/app/agentcore-identity/scripts/ensure_workload_identity.sh +29 -0
  134. package/dist/terraform/modules/app/agentcore-identity/scripts/read_identity.sh +55 -0
  135. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_identity.sh +73 -0
  136. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_identity.sh +45 -0
  137. package/dist/terraform/modules/app/agentcore-identity/scripts/reconcile_twenty_provider.mjs +123 -0
  138. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/after.tf +15 -0
  139. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/before.tf +7 -0
  140. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-after.tf +8 -0
  141. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/identity-before.tf +9 -0
  142. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-after.tf +3 -0
  143. package/dist/terraform/modules/app/agentcore-identity/tests/tainted-marker/thinkwork-before.tf +3 -0
  144. package/dist/terraform/modules/app/agentcore-identity/variables.tf +60 -0
  145. package/dist/terraform/modules/app/agentcore-memory/README.md +46 -9
  146. package/dist/terraform/modules/app/agentcore-memory/main.tf +27 -10
  147. package/dist/terraform/modules/app/agentcore-memory/scripts/create_or_find_memory.sh +156 -24
  148. package/dist/terraform/modules/app/agentcore-pi/README.md +1 -3
  149. package/dist/terraform/modules/app/agentcore-pi/main.tf +42 -52
  150. package/dist/terraform/modules/app/agentcore-pi/outputs.tf +3 -3
  151. package/dist/terraform/modules/app/agentcore-pi/scripts/reconcile_pi_runtime.mjs +175 -0
  152. package/dist/terraform/modules/app/agentcore-pi/variables.tf +35 -28
  153. package/dist/terraform/modules/app/agentcore-platform/main.tf +68 -0
  154. package/dist/terraform/modules/app/agentcore-runtime/main.tf +4 -20
  155. package/dist/terraform/modules/app/appsync-subscriptions/main.tf +127 -21
  156. package/dist/terraform/modules/app/appsync-subscriptions/outputs.tf +0 -6
  157. package/dist/terraform/modules/app/appsync-subscriptions/variables.tf +5 -0
  158. package/dist/terraform/modules/app/capability-broker/main.tf +2 -2
  159. package/dist/terraform/modules/app/capability-broker/variables.tf +11 -0
  160. package/dist/terraform/modules/app/deployment-control-plane/README.md +264 -0
  161. package/dist/terraform/modules/app/deployment-control-plane/buildspec.yml +4 -1
  162. package/dist/terraform/modules/app/deployment-control-plane/main.tf +94 -0
  163. package/dist/terraform/modules/app/deployment-control-plane/outputs.tf +5 -0
  164. package/dist/terraform/modules/app/deployment-control-plane/runner.py +3689 -233
  165. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +2579 -140
  166. package/dist/terraform/modules/app/deployment-control-plane/variables.tf +33 -0
  167. package/dist/terraform/modules/app/lambda-api/auth-state.tf +72 -0
  168. package/dist/terraform/modules/app/lambda-api/chat-latency-observability.tf +466 -0
  169. package/dist/terraform/modules/app/lambda-api/dispatch-dlq.tf +55 -0
  170. package/dist/terraform/modules/app/lambda-api/handlers.tf +531 -619
  171. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +350 -241
  172. package/dist/terraform/modules/app/lambda-api/main.tf +75 -13
  173. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +3 -28
  174. package/dist/terraform/modules/app/lambda-api/oauth-secrets.tf +1 -2
  175. package/dist/terraform/modules/app/lambda-api/outputs.tf +17 -10
  176. package/dist/terraform/modules/app/lambda-api/runtime-config.tf +3 -21
  177. package/dist/terraform/modules/app/lambda-api/turn-assertion.tf +45 -0
  178. package/dist/terraform/modules/app/lambda-api/variables.tf +307 -121
  179. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/README.md +1 -1
  180. package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/main.tf +18 -18
  181. package/dist/terraform/modules/app/sandbox-log-scrubber/README.md +11 -10
  182. package/dist/terraform/modules/app/sandbox-log-scrubber/main.tf +5 -5
  183. package/dist/terraform/modules/app/static-site/main.tf +1 -1
  184. package/dist/terraform/modules/app/www-dns/main.tf +9 -27
  185. package/dist/terraform/modules/app/www-dns/variables.tf +4 -10
  186. package/dist/terraform/modules/data/aurora-postgres/README.md +34 -0
  187. package/dist/terraform/modules/data/aurora-postgres/alarms.tf +82 -0
  188. package/dist/terraform/modules/data/aurora-postgres/main.tf +27 -57
  189. package/dist/terraform/modules/data/aurora-postgres/outputs.tf +0 -9
  190. package/dist/terraform/modules/data/aurora-postgres/variables.tf +41 -0
  191. package/dist/terraform/modules/data/s3-buckets/main.tf +5 -6
  192. package/dist/terraform/modules/foundation/cognito/main.tf +367 -72
  193. package/dist/terraform/modules/foundation/cognito/outputs.tf +47 -0
  194. package/dist/terraform/modules/foundation/cognito/variables.tf +131 -9
  195. package/dist/terraform/modules/thinkwork/README.md +5 -1
  196. package/dist/terraform/modules/thinkwork/main.tf +459 -234
  197. package/dist/terraform/modules/thinkwork/outputs.tf +44 -62
  198. package/dist/terraform/modules/thinkwork/variables.tf +353 -89
  199. package/dist/terraform/schema.graphql +69 -36
  200. package/dist/workspace-defaults/files/INSTRUCTIONS.md +9 -11
  201. package/dist/workspace-defaults/files/MEMORY_GUIDE.md +38 -35
  202. package/dist/workspace-defaults/files/ROUTER.md +1 -1
  203. package/dist/workspace-defaults/files/TOOLS.md +9 -39
  204. package/dist/workspace-defaults/files/USER.md +1 -0
  205. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +6 -3
  206. package/dist/workspace-defaults/files/catalog-skills/brain-brief-builder/SKILL.md +165 -0
  207. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/SKILL.md +75 -0
  208. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/mcp-tooling.md +40 -0
  209. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/validation-and-handoff.md +40 -0
  210. package/dist/workspace-defaults/files/catalog-skills/n8n-workflow-operator/references/workflow-authoring.md +46 -0
  211. package/dist/workspace-defaults/files/skills/artifact-builder/references/crm-dashboard.md +1 -1
  212. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +22 -3
  213. package/package.json +3 -2
  214. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +0 -11
  215. package/dist/plugins/company-data/README.md +0 -49
  216. package/dist/plugins/company-data/package.json +0 -21
  217. package/dist/plugins/company-data/src/index.ts +0 -30
  218. package/dist/plugins/company-data/src/manifest.ts +0 -26
  219. package/dist/plugins/company-data/test/manifest.test.ts +0 -116
  220. package/dist/plugins/company-data/tsconfig.json +0 -8
  221. package/dist/plugins/company-etl/README.md +0 -46
  222. package/dist/plugins/company-etl/package.json +0 -21
  223. package/dist/plugins/company-etl/src/index.ts +0 -29
  224. package/dist/plugins/company-etl/src/manifest.ts +0 -26
  225. package/dist/plugins/company-etl/test/manifest.test.ts +0 -108
  226. package/dist/plugins/company-etl/tsconfig.json +0 -8
  227. package/dist/plugins/lastmile/README.md +0 -50
  228. package/dist/plugins/lastmile/package.json +0 -23
  229. package/dist/plugins/lastmile/smoke/lastmile-plugin-smoke.mjs +0 -661
  230. package/dist/plugins/lastmile/src/api/tasks-adapter.ts +0 -572
  231. package/dist/plugins/lastmile/src/discovery.fixture.ts +0 -64
  232. package/dist/plugins/lastmile/src/index.ts +0 -46
  233. package/dist/plugins/lastmile/src/manifest.ts +0 -139
  234. package/dist/plugins/lastmile/test/api/tasks-adapter.test.ts +0 -266
  235. package/dist/plugins/lastmile/test/discovery.test.ts +0 -88
  236. package/dist/plugins/lastmile/tsconfig.json +0 -8
  237. package/dist/plugins/n8n/smoke/n8n-managed-app-smoke.mjs +0 -409
  238. package/dist/plugins/twenty/smoke/twenty-managed-app-smoke.mjs +0 -359
  239. package/dist/plugins/workos-auth/package.json +0 -22
  240. package/dist/plugins/workos-auth/src/index.ts +0 -30
  241. package/dist/plugins/workos-auth/src/manifest.ts +0 -40
  242. package/dist/plugins/workos-auth/src/provider-contract.ts +0 -39
  243. package/dist/plugins/workos-auth/test/manifest.test.ts +0 -94
  244. package/dist/plugins/workos-auth/tsconfig.json +0 -8
  245. package/dist/terraform/modules/app/agentcore-code-interpreter/Dockerfile.sandbox-base +0 -61
  246. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/sitecustomize.py +0 -227
  247. package/dist/terraform/modules/app/agentcore-code-interpreter/sandbox/test_sitecustomize.py +0 -277
  248. package/dist/terraform/modules/app/agentcore-code-interpreter/scripts/build_and_push_sandbox_base.sh +0 -70
  249. package/dist/terraform/modules/app/agentcore-harness/main.tf +0 -101
  250. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +0 -9
  251. package/dist/terraform/modules/app/agentcore-harness/variables.tf +0 -25
  252. package/dist/terraform/modules/app/hindsight-memory/README.md +0 -89
  253. package/dist/terraform/modules/app/hindsight-memory/main.tf +0 -411
  254. package/dist/terraform/modules/data/bedrock-knowledge-base/main.tf +0 -102
  255. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/outputs.tf +0 -0
  256. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/sync-database.py +0 -0
  257. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/scripts/test_sync_database.py +0 -0
  258. /package/dist/{plugins/n8n/terraform → terraform/modules/app}/n8n/variables.tf +0 -0
  259. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/README.md +0 -0
  260. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/main.tf +0 -0
  261. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/outputs.tf +0 -0
  262. /package/dist/{plugins/twenty/terraform → terraform/modules/app}/twenty/variables.tf +0 -0
@@ -0,0 +1,236 @@
1
+ -- 0263_drop_workos_auth_runtime.sql
2
+ --
3
+ -- Final guarded retirement of the WorkOS login broker. Historical migrations
4
+ -- 0174/0175 remain in the repository; this migration removes their runtime
5
+ -- tables only after a completed native-auth cutover proves identity,
6
+ -- client-shutdown, token-drain, realtime-drain, and zero-reader/writer gates.
7
+ -- Raw WorkOS profile/session data is deliberately purged, not archived.
8
+ --
9
+ -- drops: public.workos_auth_bridges
10
+ -- drops: public.workos_auth_sessions
11
+ -- creates-constraint: public.plugin_components.plugin_components_type_allowed
12
+ -- creates-constraint: public.auth_provider_resources.auth_provider_resources_lifecycle_state_allowed
13
+ -- creates-constraint: public.auth_route_clients.auth_route_clients_lifecycle_allowed
14
+ -- deployment-phase: auth-retired
15
+
16
+ \set ON_ERROR_STOP on
17
+
18
+ BEGIN;
19
+
20
+ SET LOCAL lock_timeout = '30s';
21
+ SET LOCAL statement_timeout = '300s';
22
+
23
+ SELECT pg_advisory_xact_lock(hashtext('drop_workos_auth_runtime'));
24
+ SELECT set_config('thinkwork.auth_retirement_stage', :'stage', true);
25
+
26
+ DO $$
27
+ DECLARE
28
+ cutover record;
29
+ residue_exists boolean;
30
+ table_has_rows boolean;
31
+ pending_count bigint;
32
+ BEGIN
33
+ IF current_database() != 'thinkwork' THEN
34
+ RAISE EXCEPTION 'wrong database: %, expected thinkwork', current_database();
35
+ END IF;
36
+
37
+ SELECT
38
+ EXISTS (
39
+ SELECT 1 FROM public.auth_provider_resources
40
+ WHERE provider_kind = 'legacy_workos' OR lifecycle_state = 'coexistence'
41
+ )
42
+ OR EXISTS (
43
+ SELECT 1 FROM public.auth_route_clients
44
+ WHERE lifecycle_state = 'coexistence'
45
+ )
46
+ OR EXISTS (
47
+ SELECT 1 FROM public.plugin_installs WHERE plugin_key = 'workos-auth'
48
+ )
49
+ INTO residue_exists;
50
+
51
+ IF to_regclass('public.workos_auth_bridges') IS NOT NULL THEN
52
+ EXECUTE 'SELECT EXISTS (SELECT 1 FROM public.workos_auth_bridges)'
53
+ INTO table_has_rows;
54
+ residue_exists := residue_exists OR table_has_rows;
55
+ END IF;
56
+ IF to_regclass('public.workos_auth_sessions') IS NOT NULL THEN
57
+ EXECUTE 'SELECT EXISTS (SELECT 1 FROM public.workos_auth_sessions)'
58
+ INTO table_has_rows;
59
+ residue_exists := residue_exists OR table_has_rows;
60
+ END IF;
61
+
62
+ IF NOT residue_exists THEN
63
+ RAISE NOTICE 'No WorkOS auth data exists — empty historical tables may be retired without cutover evidence';
64
+ RETURN;
65
+ END IF;
66
+
67
+ SELECT * INTO cutover
68
+ FROM public.auth_cutover_runs
69
+ WHERE stage = current_setting('thinkwork.auth_retirement_stage')
70
+ ORDER BY created_at DESC, id DESC
71
+ LIMIT 1;
72
+
73
+ IF cutover.id IS NULL THEN
74
+ RAISE EXCEPTION 'WorkOS retirement blocked: no auth_cutover_runs evidence for stage %',
75
+ current_setting('thinkwork.auth_retirement_stage');
76
+ END IF;
77
+
78
+ IF cutover.status <> 'complete' OR cutover.completed_at IS NULL THEN
79
+ RAISE EXCEPTION 'WorkOS retirement blocked: newest auth_cutover_runs evidence for stage % is %',
80
+ current_setting('thinkwork.auth_retirement_stage'), cutover.status;
81
+ END IF;
82
+
83
+ IF COALESCE((cutover.terminal_dispositions->>'allTerminal')::boolean, false) IS NOT TRUE
84
+ OR COALESCE((cutover.terminal_dispositions->>'unresolved')::bigint, -1) <> 0
85
+ OR COALESCE((cutover.terminal_dispositions->>'signoutExpected')::bigint, -1) <= 0
86
+ OR COALESCE((cutover.terminal_dispositions->>'signoutAttempts')::bigint, -1)
87
+ <> COALESCE((cutover.terminal_dispositions->>'signoutExpected')::bigint, -2)
88
+ OR COALESCE((cutover.terminal_dispositions->>'signoutFailures')::bigint, -1) <> 0
89
+ OR COALESCE((cutover.terminal_dispositions->>'compatibilityFallbackReads')::bigint, -1) <> 0
90
+ THEN
91
+ RAISE EXCEPTION 'WorkOS retirement blocked: identity/signout/fallback evidence is incomplete';
92
+ END IF;
93
+
94
+ IF COALESCE((cutover.client_shutdown_evidence->>'workosStartsEnabled')::boolean, true) IS NOT FALSE
95
+ OR COALESCE((cutover.client_shutdown_evidence->>'legacyClientsEnabled')::bigint, -1) <> 0
96
+ OR COALESCE((cutover.client_shutdown_evidence->>'legacyAudiencesAccepted')::bigint, -1) <> 0
97
+ THEN
98
+ RAISE EXCEPTION 'WorkOS retirement blocked: legacy clients or audiences remain enabled';
99
+ END IF;
100
+
101
+ IF COALESCE((cutover.drain_evidence->>'drainCompleted')::boolean, false) IS NOT TRUE
102
+ OR COALESCE((cutover.drain_evidence->>'legacyRouteTraffic')::bigint, -1) <> 0
103
+ OR COALESCE((cutover.drain_evidence->>'workosTableReads')::bigint, -1) <> 0
104
+ OR COALESCE((cutover.drain_evidence->>'workosTableWrites')::bigint, -1) <> 0
105
+ OR COALESCE((cutover.drain_evidence->>'activeLegacySubscriptions')::bigint, -1) <> 0
106
+ THEN
107
+ RAISE EXCEPTION 'WorkOS retirement blocked: traffic, persistence, or realtime drain evidence is incomplete';
108
+ END IF;
109
+
110
+ IF COALESCE(cutover.drain_evidence->'provenance'->>'domain', '')
111
+ <> 'thinkwork.auth-cutover-evidence.v1'
112
+ OR COALESCE(cutover.drain_evidence->'provenance'->>'source', '')
113
+ <> 'verify-native-auth-cutover'
114
+ OR COALESCE(cutover.drain_evidence->'provenance'->>'stage', '')
115
+ <> current_setting('thinkwork.auth_retirement_stage')
116
+ OR COALESCE(cutover.drain_evidence->'provenance'->>'runId', '') <> cutover.id::text
117
+ OR COALESCE(cutover.drain_evidence->'provenance'->>'deploymentRevision', '')
118
+ !~ '^([a-f0-9]{40}|[a-f0-9]{64})$'
119
+ OR COALESCE(cutover.drain_evidence->'provenance'->>'payloadHash', '')
120
+ !~ '^[a-f0-9]{64}$'
121
+ OR length(COALESCE(cutover.drain_evidence->'provenance'->>'signature', '')) < 40
122
+ OR (cutover.drain_evidence->'provenance'->>'observedAt')::timestamptz < cutover.started_at
123
+ OR cutover.completed_at < (cutover.drain_evidence->'provenance'->>'observedAt')::timestamptz
124
+ OR cutover.completed_at > (cutover.drain_evidence->'provenance'->>'expiresAt')::timestamptz
125
+ THEN
126
+ RAISE EXCEPTION 'WorkOS retirement blocked: signed stage/revision/time provenance is missing or stale';
127
+ END IF;
128
+
129
+ IF COALESCE((cutover.drain_evidence->>'guardEnabled')::boolean, false) IS NOT TRUE
130
+ -- AppSync GraphQL WebSocket connections can survive for 24 hours, longer
131
+ -- than the legacy clients' one-hour ID/access tokens.
132
+ OR COALESCE((cutover.drain_evidence->>'requiredSoakSeconds')::bigint, 0) < 86400
133
+ OR COALESCE(cutover.drain_evidence->>'deploymentRevision', '')
134
+ <> COALESCE(cutover.drain_evidence->'provenance'->>'deploymentRevision', '')
135
+ OR cutover.drain_evidence->>'baselineDatabaseStatsResetAt' IS NULL
136
+ OR cutover.drain_evidence->>'databaseStatsResetAt' IS NULL
137
+ OR cutover.drain_evidence->>'baselineDatabaseStatsResetAt'
138
+ <> cutover.drain_evidence->>'databaseStatsResetAt'
139
+ OR cutover.drain_evidence->>'soakStartedAt' IS NULL
140
+ OR (cutover.drain_evidence->'provenance'->>'observedAt')::timestamptz
141
+ < (cutover.drain_evidence->>'soakStartedAt')::timestamptz
142
+ + make_interval(secs => (cutover.drain_evidence->>'requiredSoakSeconds')::integer)
143
+ THEN
144
+ RAISE EXCEPTION 'WorkOS retirement blocked: revision-bound drain soak is missing or incomplete';
145
+ END IF;
146
+
147
+ SELECT count(*) INTO pending_count
148
+ FROM public.auth_identity_enrollments enrollment
149
+ JOIN public.auth_provider_resources resource
150
+ ON resource.id = enrollment.auth_provider_resource_id
151
+ WHERE (resource.provider_kind = 'legacy_workos' OR resource.lifecycle_state = 'coexistence')
152
+ AND enrollment.status = 'pending'
153
+ AND enrollment.expires_at > now();
154
+ IF pending_count <> 0 THEN
155
+ RAISE EXCEPTION 'WorkOS retirement blocked: % live legacy identity enrollment(s)', pending_count;
156
+ END IF;
157
+
158
+ IF to_regclass('public.workos_auth_sessions') IS NOT NULL THEN
159
+ EXECUTE 'SELECT count(*) FROM public.workos_auth_sessions WHERE status = ''active'' AND expires_at > now()'
160
+ INTO pending_count;
161
+ IF pending_count <> 0 THEN
162
+ RAISE EXCEPTION 'WorkOS retirement blocked: % active WorkOS session(s)', pending_count;
163
+ END IF;
164
+ END IF;
165
+
166
+ IF to_regclass('public.workos_auth_bridges') IS NOT NULL THEN
167
+ EXECUTE 'SELECT count(*) FROM public.workos_auth_bridges WHERE status = ''pending'' AND expires_at > now()'
168
+ INTO pending_count;
169
+ IF pending_count <> 0 THEN
170
+ RAISE EXCEPTION 'WorkOS retirement blocked: % live WorkOS bridge(s)', pending_count;
171
+ END IF;
172
+ END IF;
173
+ END $$;
174
+
175
+ DROP TABLE IF EXISTS public.workos_auth_bridges;
176
+ DROP TABLE IF EXISTS public.workos_auth_sessions;
177
+
178
+ DELETE FROM public.auth_identity_proofs proof
179
+ USING public.user_auth_identities identity, public.auth_provider_resources resource
180
+ WHERE proof.user_auth_identity_id = identity.id
181
+ AND identity.auth_provider_resource_id = resource.id
182
+ AND (resource.provider_kind = 'legacy_workos' OR resource.lifecycle_state = 'coexistence');
183
+
184
+ DELETE FROM public.auth_identity_enrollments enrollment
185
+ USING public.auth_provider_resources resource
186
+ WHERE enrollment.auth_provider_resource_id = resource.id
187
+ AND (resource.provider_kind = 'legacy_workos' OR resource.lifecycle_state = 'coexistence');
188
+
189
+ DELETE FROM public.user_auth_identities identity
190
+ USING public.auth_provider_resources resource
191
+ WHERE identity.auth_provider_resource_id = resource.id
192
+ AND (resource.provider_kind = 'legacy_workos' OR resource.lifecycle_state = 'coexistence');
193
+
194
+ DELETE FROM public.tenant_auth_provider_references reference
195
+ USING public.auth_provider_resources resource
196
+ WHERE reference.auth_provider_resource_id = resource.id
197
+ AND (resource.provider_kind = 'legacy_workos' OR resource.lifecycle_state = 'coexistence');
198
+
199
+ DELETE FROM public.auth_provider_resources
200
+ WHERE provider_kind = 'legacy_workos' OR lifecycle_state = 'coexistence';
201
+
202
+ DELETE FROM public.auth_route_clients WHERE lifecycle_state = 'coexistence';
203
+ DELETE FROM public.plugin_installs WHERE plugin_key = 'workos-auth';
204
+
205
+ DO $$
206
+ BEGIN
207
+ IF EXISTS (
208
+ SELECT 1 FROM public.plugin_components WHERE component_type = 'auth-provider'
209
+ ) THEN
210
+ RAISE EXCEPTION 'WorkOS retirement blocked: non-retired auth-provider plugin components remain';
211
+ END IF;
212
+ END $$;
213
+
214
+ ALTER TABLE public.plugin_components
215
+ DROP CONSTRAINT IF EXISTS plugin_components_type_allowed;
216
+ ALTER TABLE public.plugin_components
217
+ ADD CONSTRAINT plugin_components_type_allowed
218
+ CHECK (component_type IN ('mcp-server', 'skills', 'infrastructure', 'ui-surface'));
219
+
220
+ ALTER TABLE public.auth_provider_resources
221
+ ALTER COLUMN connection_key DROP DEFAULT,
222
+ ALTER COLUMN provider_kind DROP DEFAULT,
223
+ ALTER COLUMN lifecycle_state SET DEFAULT 'native';
224
+ ALTER TABLE public.auth_provider_resources
225
+ DROP CONSTRAINT IF EXISTS auth_provider_resources_lifecycle_state_allowed;
226
+ ALTER TABLE public.auth_provider_resources
227
+ ADD CONSTRAINT auth_provider_resources_lifecycle_state_allowed
228
+ CHECK (lifecycle_state IN ('native', 'denied'));
229
+
230
+ ALTER TABLE public.auth_route_clients
231
+ DROP CONSTRAINT IF EXISTS auth_route_clients_lifecycle_allowed;
232
+ ALTER TABLE public.auth_route_clients
233
+ ADD CONSTRAINT auth_route_clients_lifecycle_allowed
234
+ CHECK (lifecycle_state IN ('native', 'denied'));
235
+
236
+ COMMIT;
@@ -0,0 +1,15 @@
1
+ -- Cap recipient-challenge guesses across every route for an enrollment grant.
2
+ -- creates-column: public.auth_identity_enrollments.failed_attempts
3
+ -- creates-column: public.auth_identity_enrollments.locked_at
4
+ -- creates-constraint: public.auth_identity_enrollments.auth_identity_enrollments_failed_attempts_nonnegative
5
+
6
+ ALTER TABLE public.auth_identity_enrollments
7
+ ADD COLUMN IF NOT EXISTS failed_attempts integer NOT NULL DEFAULT 0,
8
+ ADD COLUMN IF NOT EXISTS locked_at timestamptz;
9
+
10
+ ALTER TABLE public.auth_identity_enrollments
11
+ DROP CONSTRAINT IF EXISTS auth_identity_enrollments_failed_attempts_nonnegative;
12
+
13
+ ALTER TABLE public.auth_identity_enrollments
14
+ ADD CONSTRAINT auth_identity_enrollments_failed_attempts_nonnegative
15
+ CHECK (failed_attempts >= 0);
@@ -0,0 +1,28 @@
1
+ -- creates-column: public.eval_runs.requester_user_id
2
+ -- creates: public.idx_eval_runs_requester_user_id
3
+ -- Exact human principal used to resolve per-user identity and capabilities for
4
+ -- production-shaped AgentCore Harness evaluation turns. Nullable preserves
5
+ -- legacy Pi evaluation rows; Harness dispatch fails closed when it is absent.
6
+
7
+ ALTER TABLE public.eval_runs
8
+ ADD COLUMN IF NOT EXISTS requester_user_id uuid;
9
+
10
+ DO $$
11
+ BEGIN
12
+ IF NOT EXISTS (
13
+ SELECT 1
14
+ FROM pg_constraint
15
+ WHERE conname = 'eval_runs_requester_user_id_users_id_fk'
16
+ AND conrelid = 'public.eval_runs'::regclass
17
+ ) THEN
18
+ ALTER TABLE public.eval_runs
19
+ ADD CONSTRAINT eval_runs_requester_user_id_users_id_fk
20
+ FOREIGN KEY (requester_user_id)
21
+ REFERENCES public.users(id)
22
+ ON DELETE SET NULL;
23
+ END IF;
24
+ END
25
+ $$;
26
+
27
+ CREATE INDEX IF NOT EXISTS idx_eval_runs_requester_user_id
28
+ ON public.eval_runs (requester_user_id);
@@ -0,0 +1,27 @@
1
+ -- 0265_require_fully_valid_auth_publication.sql
2
+ -- Partially validated providers must never be published or admitted. Existing
3
+ -- rows are unpublished before the stricter canonical constraint is installed.
4
+ -- creates-constraint: public.auth_provider_resources.auth_provider_resources_no_public_without_valid
5
+
6
+ BEGIN;
7
+
8
+ UPDATE public.auth_provider_resources
9
+ SET public_options_published = false,
10
+ updated_at = now()
11
+ WHERE public_options_published = true
12
+ AND validation_status <> 'valid';
13
+
14
+ ALTER TABLE public.auth_provider_resources
15
+ DROP CONSTRAINT IF EXISTS auth_provider_resources_no_public_without_valid;
16
+
17
+ ALTER TABLE public.auth_provider_resources
18
+ ADD CONSTRAINT auth_provider_resources_no_public_without_valid
19
+ CHECK (
20
+ public_options_published = false
21
+ OR (
22
+ validation_status = 'valid'
23
+ AND lifecycle_state <> 'denied'
24
+ )
25
+ );
26
+
27
+ COMMIT;
@@ -0,0 +1,9 @@
1
+ -- 0266_auth_identity_recovery_grants.sql
2
+ -- creates-constraint: public.auth_identity_enrollments.auth_identity_enrollments_grant_kind_allowed
3
+
4
+ ALTER TABLE public.auth_identity_enrollments
5
+ DROP CONSTRAINT IF EXISTS auth_identity_enrollments_grant_kind_allowed;
6
+
7
+ ALTER TABLE public.auth_identity_enrollments
8
+ ADD CONSTRAINT auth_identity_enrollments_grant_kind_allowed
9
+ CHECK (recipient_grant_kind IN ('membership', 'pending_owner', 'identity_recovery', 'session_migration'));
@@ -0,0 +1,12 @@
1
+ -- creates-column: public.eval_profiles.runtime_type
2
+ -- creates-constraint: public.eval_profiles.eval_profiles_runtime_type_check
3
+
4
+ ALTER TABLE public.eval_profiles
5
+ ADD COLUMN IF NOT EXISTS runtime_type text NOT NULL DEFAULT 'pi';
6
+
7
+ ALTER TABLE public.eval_profiles
8
+ DROP CONSTRAINT IF EXISTS eval_profiles_runtime_type_check;
9
+
10
+ ALTER TABLE public.eval_profiles
11
+ ADD CONSTRAINT eval_profiles_runtime_type_check
12
+ CHECK (runtime_type IN ('pi', 'agentcore'));
@@ -0,0 +1,53 @@
1
+ -- Purpose: durable candidate-rejection fingerprints (KTD-6 / R13) and the
2
+ -- `deferred` change-set item status (R15) for the Ontology Living Map.
3
+ -- Plan: docs/plans/2026-07-18-001-feat-ontology-living-map-plan.md (U2)
4
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0267_ontology_candidate_rejections.sql
5
+ -- creates: ontology.candidate_rejections
6
+ -- creates: ontology.uq_ontology_candidate_rejections_fingerprint
7
+ -- creates: ontology.idx_ontology_candidate_rejections_tenant
8
+ -- creates-constraint: ontology.candidate_rejections.ontology_candidate_rejections_tenant_id_tenants_id_fk
9
+ -- creates-constraint: ontology.candidate_rejections.ontology_candidate_rejections_kind_allowed
10
+ -- creates-constraint: ontology.change_set_items.ontology_change_set_items_status_allowed
11
+
12
+ \set ON_ERROR_STOP on
13
+
14
+ BEGIN;
15
+
16
+ SET LOCAL lock_timeout = '5s';
17
+ SET LOCAL statement_timeout = '120s';
18
+
19
+ CREATE TABLE IF NOT EXISTS ontology.candidate_rejections (
20
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
21
+ tenant_id uuid NOT NULL,
22
+ kind text NOT NULL,
23
+ slug text NOT NULL,
24
+ fingerprint text NOT NULL,
25
+ rejected_by uuid,
26
+ rejected_at timestamptz NOT NULL DEFAULT now(),
27
+ CONSTRAINT ontology_candidate_rejections_tenant_id_tenants_id_fk
28
+ FOREIGN KEY (tenant_id)
29
+ REFERENCES public.tenants(id)
30
+ ON DELETE CASCADE,
31
+ CONSTRAINT ontology_candidate_rejections_rejected_by_users_id_fk
32
+ FOREIGN KEY (rejected_by)
33
+ REFERENCES public.users(id)
34
+ ON DELETE SET NULL,
35
+ CONSTRAINT ontology_candidate_rejections_kind_allowed
36
+ CHECK (kind IN ('entity_type','relationship_type','facet_template','external_mapping'))
37
+ );
38
+
39
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_ontology_candidate_rejections_fingerprint
40
+ ON ontology.candidate_rejections (tenant_id, kind, fingerprint);
41
+
42
+ CREATE INDEX IF NOT EXISTS idx_ontology_candidate_rejections_tenant
43
+ ON ontology.candidate_rejections (tenant_id);
44
+
45
+ -- R15: excluded-at-approval items become `deferred` (re-reviewable) — widen
46
+ -- the item status CHECK to admit the new value.
47
+ ALTER TABLE ontology.change_set_items
48
+ DROP CONSTRAINT IF EXISTS ontology_change_set_items_status_allowed;
49
+ ALTER TABLE ontology.change_set_items
50
+ ADD CONSTRAINT ontology_change_set_items_status_allowed
51
+ CHECK (status IN ('pending_review','approved','rejected','applied','deferred'));
52
+
53
+ COMMIT;
@@ -0,0 +1,182 @@
1
+ -- THINK-321 U1: identity crosswalk routing vocabulary and linkage.
2
+ -- Plan: docs/plans/2026-07-19-001-feat-ontology-identity-crosswalk-agent-routing-plan.md (U1)
3
+ -- Contents:
4
+ -- * identity.entity_source_mappings — `created_by` CHECK gains 'user'
5
+ -- (in-turn confirm attribution); nullable created_by_user_id +
6
+ -- created_thread_ref audit columns.
7
+ -- * identity.entity_resolution_events — `event_type` CHECK gains
8
+ -- 'revoke' and 'split' (the V1 "no split" restriction is lifted).
9
+ -- * identity.mapping_rejections — negative evidence: rejected
10
+ -- (source identity <-> canonical entity) pairings, honored by the
11
+ -- matcher (KTD-6).
12
+ -- * identity.source_system_connectors — source_system -> tenant connector
13
+ -- linkage, read fail-closed by resolve (KTD-5).
14
+ -- * identity.match_jobs — bootstrap/drift match jobs mirroring
15
+ -- ontology.suggestion_scan_jobs (KTD-7).
16
+ -- * identity.mapping_candidate_sets — in-turn confirm echo-check store:
17
+ -- written by propose, invalidated on confirm/decline/re-propose,
18
+ -- expired rows refused (KTD-2).
19
+ -- Constraint widening ships BEFORE any writer code (this unit has none).
20
+ --
21
+ -- Hand-rolled (drizzle meta journal is not in use for this change).
22
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0268_identity_crosswalk_routing.sql
23
+ -- creates-column: identity.entity_source_mappings.created_by_user_id
24
+ -- creates-column: identity.entity_source_mappings.created_thread_ref
25
+ -- creates-constraint: identity.entity_source_mappings.entity_source_mappings_created_by_allowed
26
+ -- creates-constraint: identity.entity_resolution_events.entity_resolution_events_type_allowed
27
+ -- creates: identity.mapping_rejections
28
+ -- creates: identity.uq_mapping_rejections_pairing
29
+ -- creates: identity.idx_mapping_rejections_tenant_canonical
30
+ -- creates-constraint: identity.mapping_rejections.mapping_rejections_created_by_allowed
31
+ -- creates: identity.source_system_connectors
32
+ -- creates-constraint: identity.source_system_connectors.source_system_connectors_connector_slug_fk
33
+ -- creates: identity.match_jobs
34
+ -- creates: identity.uq_identity_match_jobs_dedupe
35
+ -- creates: identity.idx_identity_match_jobs_tenant_status
36
+ -- creates-constraint: identity.match_jobs.match_jobs_status_allowed
37
+ -- creates: identity.mapping_candidate_sets
38
+ -- creates: identity.idx_mapping_candidate_sets_tenant_thread
39
+ -- creates-constraint: identity.mapping_candidate_sets.mapping_candidate_sets_status_allowed
40
+
41
+ \set ON_ERROR_STOP on
42
+
43
+ BEGIN;
44
+
45
+ SELECT pg_advisory_xact_lock(hashtext('identity_crosswalk_routing_0268'));
46
+
47
+ SET LOCAL lock_timeout = '5s';
48
+ SET LOCAL statement_timeout = '120s';
49
+
50
+ -- ---------------------------------------------------------------------------
51
+ -- identity.entity_source_mappings — user attribution vocabulary
52
+ -- ---------------------------------------------------------------------------
53
+
54
+ ALTER TABLE identity.entity_source_mappings
55
+ ADD COLUMN IF NOT EXISTS created_by_user_id uuid
56
+ REFERENCES public.users(id) ON DELETE SET NULL;
57
+
58
+ ALTER TABLE identity.entity_source_mappings
59
+ ADD COLUMN IF NOT EXISTS created_thread_ref text;
60
+
61
+ ALTER TABLE identity.entity_source_mappings
62
+ DROP CONSTRAINT IF EXISTS entity_source_mappings_created_by_allowed;
63
+ ALTER TABLE identity.entity_source_mappings
64
+ ADD CONSTRAINT entity_source_mappings_created_by_allowed
65
+ CHECK (created_by IN ('rule','operator','backfill','user'));
66
+
67
+ -- ---------------------------------------------------------------------------
68
+ -- identity.entity_resolution_events — revoke + split event vocabulary
69
+ -- ---------------------------------------------------------------------------
70
+
71
+ ALTER TABLE identity.entity_resolution_events
72
+ DROP CONSTRAINT IF EXISTS entity_resolution_events_type_allowed;
73
+ ALTER TABLE identity.entity_resolution_events
74
+ ADD CONSTRAINT entity_resolution_events_type_allowed
75
+ CHECK (event_type IN ('create','link','defer','reject','merge','revoke','split'));
76
+
77
+ -- ---------------------------------------------------------------------------
78
+ -- identity.mapping_rejections — negative evidence (KTD-6)
79
+ -- ---------------------------------------------------------------------------
80
+
81
+ CREATE TABLE IF NOT EXISTS identity.mapping_rejections (
82
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
83
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
84
+ source_system text NOT NULL,
85
+ namespace text NOT NULL DEFAULT '',
86
+ external_id text NOT NULL,
87
+ canonical_entity_id uuid NOT NULL
88
+ REFERENCES identity.canonical_entities(id) ON DELETE CASCADE,
89
+ reason text,
90
+ created_by text NOT NULL,
91
+ created_at timestamptz NOT NULL DEFAULT now(),
92
+ CONSTRAINT mapping_rejections_created_by_allowed
93
+ CHECK (created_by IN ('user','operator','rule','system'))
94
+ );
95
+
96
+ -- One rejection row per (source identity, canonical entity) pairing.
97
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_mapping_rejections_pairing
98
+ ON identity.mapping_rejections
99
+ (tenant_id, source_system, namespace, external_id, canonical_entity_id);
100
+
101
+ CREATE INDEX IF NOT EXISTS idx_mapping_rejections_tenant_canonical
102
+ ON identity.mapping_rejections (tenant_id, canonical_entity_id);
103
+
104
+ -- ---------------------------------------------------------------------------
105
+ -- identity.source_system_connectors — source_system -> connector link (KTD-5)
106
+ -- ---------------------------------------------------------------------------
107
+
108
+ -- The composite FK targets the plain unique index uq_tenant_mcp_servers_slug
109
+ -- on public.tenant_mcp_servers (tenant_id, slug) — Postgres accepts a
110
+ -- non-partial unique index as an FK target. ON UPDATE/DELETE CASCADE keeps
111
+ -- the link from dangling when a connector is renamed or removed; resolve
112
+ -- reads it fail-closed either way.
113
+ CREATE TABLE IF NOT EXISTS identity.source_system_connectors (
114
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
115
+ source_system text NOT NULL,
116
+ connector_slug text NOT NULL,
117
+ created_at timestamptz NOT NULL DEFAULT now(),
118
+ PRIMARY KEY (tenant_id, source_system),
119
+ CONSTRAINT source_system_connectors_connector_slug_fk
120
+ FOREIGN KEY (tenant_id, connector_slug)
121
+ REFERENCES public.tenant_mcp_servers (tenant_id, slug)
122
+ ON UPDATE CASCADE
123
+ ON DELETE CASCADE
124
+ );
125
+
126
+ -- ---------------------------------------------------------------------------
127
+ -- identity.match_jobs — bootstrap/drift match jobs (KTD-7)
128
+ -- ---------------------------------------------------------------------------
129
+
130
+ CREATE TABLE IF NOT EXISTS identity.match_jobs (
131
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
132
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
133
+ status text NOT NULL DEFAULT 'pending',
134
+ trigger text NOT NULL DEFAULT 'manual',
135
+ dedupe_key text,
136
+ source_systems jsonb NOT NULL DEFAULT '[]'::jsonb,
137
+ result jsonb NOT NULL DEFAULT '{}'::jsonb,
138
+ metrics jsonb NOT NULL DEFAULT '{}'::jsonb,
139
+ error text,
140
+ created_at timestamptz NOT NULL DEFAULT now(),
141
+ started_at timestamptz,
142
+ finished_at timestamptz,
143
+ CONSTRAINT match_jobs_status_allowed
144
+ CHECK (status IN ('pending','running','succeeded','failed'))
145
+ );
146
+
147
+ -- Insert-or-load dedupe: at most one job per live dedupe key.
148
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_identity_match_jobs_dedupe
149
+ ON identity.match_jobs (tenant_id, dedupe_key)
150
+ WHERE dedupe_key IS NOT NULL;
151
+
152
+ CREATE INDEX IF NOT EXISTS idx_identity_match_jobs_tenant_status
153
+ ON identity.match_jobs (tenant_id, status);
154
+
155
+ -- ---------------------------------------------------------------------------
156
+ -- identity.mapping_candidate_sets — confirm echo-check store (KTD-2)
157
+ -- ---------------------------------------------------------------------------
158
+
159
+ -- Lifecycle: written by propose (status='open'); invalidated on
160
+ -- confirm/decline/re-propose (confirmed/declined/superseded); expired rows
161
+ -- are refused. confirm_mapping succeeds only when the echoed candidate id
162
+ -- matches the recorded selection on an open, unexpired row for the thread.
163
+ CREATE TABLE IF NOT EXISTS identity.mapping_candidate_sets (
164
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
165
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
166
+ thread_ref text NOT NULL,
167
+ source_system text NOT NULL,
168
+ namespace text NOT NULL DEFAULT '',
169
+ target_entity_ref jsonb,
170
+ candidates jsonb NOT NULL DEFAULT '[]'::jsonb,
171
+ status text NOT NULL DEFAULT 'open',
172
+ selected_candidate_id text,
173
+ created_at timestamptz NOT NULL DEFAULT now(),
174
+ expires_at timestamptz,
175
+ CONSTRAINT mapping_candidate_sets_status_allowed
176
+ CHECK (status IN ('open','confirmed','declined','superseded','expired'))
177
+ );
178
+
179
+ CREATE INDEX IF NOT EXISTS idx_mapping_candidate_sets_tenant_thread
180
+ ON identity.mapping_candidate_sets (tenant_id, thread_ref);
181
+
182
+ COMMIT;
@@ -0,0 +1,31 @@
1
+ -- Purpose: type-level system map (THINK-321 U3 / KTD-3 / R6) — per-entity-type
2
+ -- declarations of which attached system holds which facets, shaped
3
+ -- `{ facet, sourceSystem, note? }`, plus the `identity_map` change-set item
4
+ -- type that governs edits (never a direct write).
5
+ -- Plan: docs/plans/2026-07-19-001-feat-ontology-identity-crosswalk-agent-routing-plan.md (U3)
6
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0269_ontology_system_map.sql
7
+ -- creates-column: ontology.entity_types.system_map
8
+ -- creates-column: ontology.entity_types.system_map_version
9
+ -- creates-constraint: ontology.change_set_items.ontology_change_set_items_type_allowed
10
+
11
+ \set ON_ERROR_STOP on
12
+
13
+ BEGIN;
14
+
15
+ SET LOCAL lock_timeout = '5s';
16
+ SET LOCAL statement_timeout = '120s';
17
+
18
+ ALTER TABLE ontology.entity_types
19
+ ADD COLUMN IF NOT EXISTS system_map jsonb NOT NULL DEFAULT '[]'::jsonb;
20
+ ALTER TABLE ontology.entity_types
21
+ ADD COLUMN IF NOT EXISTS system_map_version integer NOT NULL DEFAULT 0;
22
+
23
+ -- R6: `identity_map` change-set items carry system-map edits through the
24
+ -- change-set approval loop — widen the item type CHECK to admit the value.
25
+ ALTER TABLE ontology.change_set_items
26
+ DROP CONSTRAINT IF EXISTS ontology_change_set_items_type_allowed;
27
+ ALTER TABLE ontology.change_set_items
28
+ ADD CONSTRAINT ontology_change_set_items_type_allowed
29
+ CHECK (item_type IN ('entity_type','relationship_type','facet_template','external_mapping','identity_map'));
30
+
31
+ COMMIT;