thinkwork-cli 0.12.17 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/{api-client-JUBCQQDF.js → api-client-4DZ266J5.js} +1 -1
  2. package/dist/{chunk-STY44FQO.js → chunk-Y2WHJECR.js} +44 -12
  3. package/dist/cli.js +36715 -12965
  4. package/dist/drizzle/0227_analyst_reader_role.sql +100 -38
  5. package/dist/drizzle/0230_analyst_rls.sql +183 -66
  6. package/dist/drizzle/0232_memory_source_thin_ledger.sql +176 -0
  7. package/dist/drizzle/0232_message_source_event_id.sql +9 -0
  8. package/dist/drizzle/0233_msteams_install_and_links.sql +151 -0
  9. package/dist/drizzle/0233_workflow_memory_stage_tokens.sql +20 -0
  10. package/dist/drizzle/0234_memory_claim_lifecycle.sql +160 -0
  11. package/dist/drizzle/0235_workflow_token_execution_claim.sql +34 -0
  12. package/dist/drizzle/0236_memory_retraction_fencing.sql +50 -0
  13. package/dist/drizzle/0237_memory_claims_active_value_uidx.sql +172 -0
  14. package/dist/drizzle/0238_memory_erase_generation_fence.sql +97 -0
  15. package/dist/drizzle/0239_canonical_entity_identity.sql +257 -0
  16. package/dist/drizzle/0240_memory_personal_scope.sql +45 -0
  17. package/dist/drizzle/0241_knowledge_base_document_manifest.sql +67 -0
  18. package/dist/drizzle/0242_search_queries.sql +28 -0
  19. package/dist/drizzle/0243_section_sources_thread_refs.sql +12 -0
  20. package/dist/drizzle/0244_system_automations_and_memory_stage_overrides.sql +45 -0
  21. package/dist/drizzle/0245_wiki_page_render.sql +21 -0
  22. package/dist/drizzle/0246_automation_workflow_ownership.sql +30 -0
  23. package/dist/drizzle/0247_capability_runtime.sql +402 -0
  24. package/dist/drizzle/0248_capability_private_interpreter.sql +13 -0
  25. package/dist/drizzle/0249_capability_headless_execution_evidence.sql +40 -0
  26. package/dist/drizzle/0250_kg_schema_extraction.sql +549 -0
  27. package/dist/drizzle/0251_agents_json_render_ui.sql +25 -0
  28. package/dist/drizzle/0251_brain_stragglers.sql +242 -0
  29. package/dist/drizzle/0252_drop_kg_and_straggler_compat_views.sql +100 -0
  30. package/dist/drizzle/0253_drop_brain_substrate.sql +91 -0
  31. package/dist/drizzle/0254_capability_autonomous_admission.sql +29 -0
  32. package/dist/drizzle/0255_capability_autonomous_approval_mode.sql +16 -0
  33. package/dist/drizzle/0256_agent_profile_manifest_authority.sql +18 -0
  34. package/dist/drizzle/0257_capability_approvals.sql +53 -0
  35. package/dist/drizzle/0258_pending_tool_approvals.sql +84 -0
  36. package/dist/drizzle/0259_tenant_capability_registry_trust.sql +19 -0
  37. package/dist/drizzle/0260_scheduled_jobs_run_as_user.sql +20 -0
  38. package/dist/drizzle/0261_thread_turns_origin_turn_index.sql +11 -0
  39. package/dist/terraform/examples/greenfield/main.tf +40 -0
  40. package/dist/terraform/modules/app/agentcore-admin/main.tf +341 -0
  41. package/dist/terraform/modules/app/agentcore-admin/outputs.tf +20 -0
  42. package/dist/terraform/modules/app/agentcore-code-interpreter/main.tf +61 -0
  43. package/dist/terraform/modules/app/agentcore-harness/main.tf +101 -0
  44. package/dist/terraform/modules/app/agentcore-harness/outputs.tf +9 -0
  45. package/dist/terraform/modules/app/agentcore-harness/variables.tf +25 -0
  46. package/dist/terraform/modules/app/agentcore-pi/main.tf +7 -0
  47. package/dist/terraform/modules/app/capability-broker/main.tf +393 -0
  48. package/dist/terraform/modules/app/capability-broker/outputs.tf +54 -0
  49. package/dist/terraform/modules/app/capability-broker/variables.tf +98 -0
  50. package/dist/terraform/modules/app/deployment-control-plane/runner.py +46 -5
  51. package/dist/terraform/modules/app/deployment-control-plane/test_runner_bundle.py +94 -0
  52. package/dist/terraform/modules/app/lambda-api/capability-search-alarms.tf +60 -0
  53. package/dist/terraform/modules/app/lambda-api/handlers.tf +361 -16
  54. package/dist/terraform/modules/app/lambda-api/iam-grouped.tf +131 -5
  55. package/dist/terraform/modules/app/lambda-api/main.tf +11 -0
  56. package/dist/terraform/modules/app/lambda-api/memory-alarms.tf +92 -0
  57. package/dist/terraform/modules/app/lambda-api/msteams-app-secrets.tf +46 -0
  58. package/dist/terraform/modules/app/lambda-api/variables.tf +92 -0
  59. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/alarms.tf +47 -0
  60. package/dist/terraform/modules/app/workflow-interpreter-stepfunctions/main.tf +43 -2
  61. package/dist/terraform/modules/foundation/cognito/main.tf +32 -8
  62. package/dist/terraform/modules/foundation/cognito/variables.tf +12 -0
  63. package/dist/terraform/modules/foundation/vpc/outputs.tf +5 -0
  64. package/dist/terraform/modules/thinkwork/main.tf +152 -5
  65. package/dist/terraform/modules/thinkwork/outputs.tf +55 -0
  66. package/dist/terraform/modules/thinkwork/variables.tf +42 -0
  67. package/dist/workspace-defaults/files/TOOLS.md +39 -0
  68. package/dist/workspace-defaults/files/agents/analyst/INSTRUCTIONS.md +18 -0
  69. package/dist/workspace-defaults/files/agents/coding/INSTRUCTIONS.md +11 -0
  70. package/dist/workspace-defaults/files/agents/research/INSTRUCTIONS.md +12 -0
  71. package/dist/workspace-defaults/files/agents/reviewer/INSTRUCTIONS.md +15 -0
  72. package/dist/workspace-defaults/files/skills/document-composer/SKILL.md +6 -2
  73. package/package.json +4 -2
  74. /package/dist/workspace-defaults/files/{AGENTS.md → INSTRUCTIONS.md} +0 -0
@@ -0,0 +1,176 @@
1
+ -- THINK-193 U1: external-memory-compounding thin ledger.
2
+ -- Contents:
3
+ -- * memory_processor_configs — one processor per shared scope (partial
4
+ -- unique on active target).
5
+ -- * memory_source_configs — source bindings under a processor.
6
+ -- * memory_source_checkpoints — CAS cursor per source partition.
7
+ -- * memory_evidence_items — evidence ledger with lifecycle + lineage inputs.
8
+ -- * memory_run_items — per-run stage idempotency ledger.
9
+ -- * memory_derivations — evidence -> Hindsight projection lineage.
10
+ --
11
+ -- NOT done here (deliberately): no claims tables, no identity tables —
12
+ -- thin U1 set only.
13
+ --
14
+ -- Hand-rolled (drizzle meta journal is not in use for this change);
15
+ -- apply with: psql "$DATABASE_URL" -f drizzle/0232_memory_source_thin_ledger.sql
16
+ -- creates: public.memory_processor_configs
17
+ -- creates: public.memory_source_configs
18
+ -- creates: public.memory_source_checkpoints
19
+ -- creates: public.memory_evidence_items
20
+ -- creates: public.memory_run_items
21
+ -- creates: public.memory_derivations
22
+
23
+ CREATE TABLE IF NOT EXISTS public.memory_processor_configs (
24
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
25
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
26
+ mode text NOT NULL,
27
+ target_scope text NOT NULL,
28
+ target_id uuid NOT NULL,
29
+ workflow_id uuid REFERENCES public.workflows(id) ON DELETE SET NULL,
30
+ enabled boolean NOT NULL DEFAULT true,
31
+ status text NOT NULL DEFAULT 'active',
32
+ budget jsonb NOT NULL DEFAULT '{}'::jsonb,
33
+ config_version integer NOT NULL DEFAULT 1,
34
+ created_by_user_id uuid REFERENCES public.users(id) ON DELETE SET NULL,
35
+ created_at timestamptz NOT NULL DEFAULT now(),
36
+ updated_at timestamptz NOT NULL DEFAULT now(),
37
+ CONSTRAINT memory_processor_configs_mode_check
38
+ CHECK (mode IN ('personal', 'shared')),
39
+ CONSTRAINT memory_processor_configs_target_scope_check
40
+ CHECK (target_scope IN ('user', 'space', 'tenant')),
41
+ CONSTRAINT memory_processor_configs_status_check
42
+ CHECK (status IN ('active', 'disabled'))
43
+ );
44
+
45
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_processor_configs_active_target_uidx
46
+ ON public.memory_processor_configs (tenant_id, mode, target_scope, target_id)
47
+ WHERE status = 'active';
48
+
49
+ CREATE INDEX IF NOT EXISTS memory_processor_configs_tenant_idx
50
+ ON public.memory_processor_configs (tenant_id);
51
+
52
+ CREATE TABLE IF NOT EXISTS public.memory_source_configs (
53
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
54
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
55
+ processor_config_id uuid NOT NULL
56
+ REFERENCES public.memory_processor_configs(id) ON DELETE CASCADE,
57
+ source_family text NOT NULL,
58
+ source_binding_key text NOT NULL,
59
+ enabled boolean NOT NULL DEFAULT true,
60
+ boundary jsonb NOT NULL DEFAULT '{}'::jsonb,
61
+ policy_version integer NOT NULL DEFAULT 1,
62
+ created_at timestamptz NOT NULL DEFAULT now(),
63
+ updated_at timestamptz NOT NULL DEFAULT now(),
64
+ CONSTRAINT memory_source_configs_source_family_check
65
+ CHECK (source_family IN ('twenty', 'firecrawl', 'email', 'bedrock_kb'))
66
+ );
67
+
68
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_source_configs_binding_uidx
69
+ ON public.memory_source_configs (processor_config_id, source_family, source_binding_key);
70
+
71
+ CREATE INDEX IF NOT EXISTS memory_source_configs_tenant_idx
72
+ ON public.memory_source_configs (tenant_id);
73
+
74
+ CREATE TABLE IF NOT EXISTS public.memory_source_checkpoints (
75
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
76
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
77
+ source_config_id uuid NOT NULL
78
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
79
+ partition_key text NOT NULL,
80
+ "cursor" jsonb NOT NULL DEFAULT '{}'::jsonb,
81
+ version integer NOT NULL DEFAULT 0,
82
+ last_advanced_at timestamptz,
83
+ created_at timestamptz NOT NULL DEFAULT now(),
84
+ updated_at timestamptz NOT NULL DEFAULT now()
85
+ );
86
+
87
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_source_checkpoints_partition_uidx
88
+ ON public.memory_source_checkpoints (source_config_id, partition_key);
89
+
90
+ CREATE TABLE IF NOT EXISTS public.memory_evidence_items (
91
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
92
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
93
+ source_config_id uuid NOT NULL
94
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
95
+ source_item_id text NOT NULL,
96
+ source_version text NOT NULL,
97
+ source_timestamp timestamptz,
98
+ content_hash text NOT NULL,
99
+ acquisition_run_id uuid REFERENCES public.workflow_runs(id) ON DELETE SET NULL,
100
+ target_scope text NOT NULL,
101
+ target_id uuid NOT NULL,
102
+ lifecycle text NOT NULL DEFAULT 'active',
103
+ sensitivity text,
104
+ snapshot_ref text,
105
+ normalized_snapshot jsonb,
106
+ extraction_recipe jsonb NOT NULL DEFAULT '{}'::jsonb,
107
+ last_error text,
108
+ created_at timestamptz NOT NULL DEFAULT now(),
109
+ updated_at timestamptz NOT NULL DEFAULT now(),
110
+ CONSTRAINT memory_evidence_items_target_scope_check
111
+ CHECK (target_scope IN ('space', 'tenant')),
112
+ CONSTRAINT memory_evidence_items_lifecycle_check
113
+ CHECK (lifecycle IN ('active', 'superseded', 'deleted', 'deferred', 'failed'))
114
+ );
115
+
116
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_evidence_items_source_version_uidx
117
+ ON public.memory_evidence_items (source_config_id, source_item_id, source_version);
118
+
119
+ CREATE INDEX IF NOT EXISTS memory_evidence_items_tenant_idx
120
+ ON public.memory_evidence_items (tenant_id);
121
+
122
+ CREATE INDEX IF NOT EXISTS memory_evidence_items_source_lifecycle_idx
123
+ ON public.memory_evidence_items (source_config_id, lifecycle);
124
+
125
+ CREATE TABLE IF NOT EXISTS public.memory_run_items (
126
+ id bigserial PRIMARY KEY,
127
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
128
+ workflow_run_id uuid NOT NULL
129
+ REFERENCES public.workflow_runs(id) ON DELETE CASCADE,
130
+ source_config_id uuid NOT NULL
131
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
132
+ source_item_id text NOT NULL,
133
+ stage text NOT NULL,
134
+ result text NOT NULL,
135
+ detail jsonb NOT NULL DEFAULT '{}'::jsonb,
136
+ created_at timestamptz NOT NULL DEFAULT now(),
137
+ CONSTRAINT memory_run_items_stage_check
138
+ CHECK (stage IN ('acquire', 'extract', 'project', 'resolve', 'retain', 'compound', 'graph', 'wiki', 'preflight')),
139
+ CONSTRAINT memory_run_items_result_check
140
+ CHECK (result IN ('seen', 'changed', 'retracted', 'deferred', 'failed', 'noop'))
141
+ );
142
+
143
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_run_items_stage_uidx
144
+ ON public.memory_run_items (workflow_run_id, source_config_id, source_item_id, stage);
145
+
146
+ CREATE INDEX IF NOT EXISTS memory_run_items_run_idx
147
+ ON public.memory_run_items (workflow_run_id);
148
+
149
+ CREATE TABLE IF NOT EXISTS public.memory_derivations (
150
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
151
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
152
+ source_config_id uuid NOT NULL
153
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
154
+ evidence_item_id uuid NOT NULL
155
+ REFERENCES public.memory_evidence_items(id) ON DELETE CASCADE,
156
+ projection_key text NOT NULL,
157
+ target_bank_id text NOT NULL,
158
+ hindsight_document_id text NOT NULL,
159
+ current_version text NOT NULL,
160
+ lifecycle text NOT NULL DEFAULT 'active',
161
+ retracted_at timestamptz,
162
+ created_at timestamptz NOT NULL DEFAULT now(),
163
+ updated_at timestamptz NOT NULL DEFAULT now(),
164
+ CONSTRAINT memory_derivations_lifecycle_check
165
+ CHECK (lifecycle IN ('active', 'superseded', 'retracted'))
166
+ );
167
+
168
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_derivations_active_projection_uidx
169
+ ON public.memory_derivations (source_config_id, projection_key)
170
+ WHERE lifecycle = 'active';
171
+
172
+ CREATE INDEX IF NOT EXISTS memory_derivations_tenant_idx
173
+ ON public.memory_derivations (tenant_id);
174
+
175
+ CREATE INDEX IF NOT EXISTS memory_derivations_evidence_idx
176
+ ON public.memory_derivations (evidence_item_id);
@@ -0,0 +1,9 @@
1
+ -- creates-column: public.messages.source_event_id
2
+ -- creates: public.uq_messages_tenant_source_event_id
3
+
4
+ ALTER TABLE public.messages
5
+ ADD COLUMN IF NOT EXISTS source_event_id text;
6
+
7
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_messages_tenant_source_event_id
8
+ ON public.messages (tenant_id, source_event_id)
9
+ WHERE source_event_id IS NOT NULL;
@@ -0,0 +1,151 @@
1
+ -- Purpose: add Microsoft Teams application persistence for tenant installs, user links, and Teams conversation mapping.
2
+ -- Plan: THINK-84 (U6 install path; msteams_threads is created now so one migration covers the domain for U7)
3
+ -- Apply manually: psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -f packages/database-pg/drizzle/0233_msteams_install_and_links.sql
4
+ -- After applying, RE-APPLY 0227_analyst_reader_role.sql and 0230_analyst_rls.sql:
5
+ -- their regenerated grant/RLS sections cover the msteams tables, and databases
6
+ -- that ran them before these tables existed have no analyst grants/policies
7
+ -- for them (0230's msteams policy markers gate this in the drift reporter;
8
+ -- 0227's grants are not marker-checkable).
9
+ -- creates: public.msteams_tenant_installs
10
+ -- creates: public.msteams_user_links
11
+ -- creates: public.msteams_threads
12
+ -- creates: public.uq_msteams_tenant_installs_entra_tenant
13
+ -- creates: public.uq_msteams_tenant_installs_tenant_entra_tenant
14
+ -- creates: public.uq_msteams_tenant_installs_tenant_active
15
+ -- creates: public.idx_msteams_tenant_installs_tenant_status
16
+ -- creates: public.uq_msteams_user_links_entra_tenant_aad_object
17
+ -- creates: public.idx_msteams_user_links_tenant_user
18
+ -- creates: public.idx_msteams_user_links_user
19
+ -- creates: public.uq_msteams_threads_entra_tenant_conversation
20
+ -- creates: public.idx_msteams_threads_thread
21
+ -- creates: public.idx_msteams_threads_tenant_entra_tenant
22
+ -- creates-constraint: public.msteams_tenant_installs.msteams_tenant_installs_tenant_id_tenants_id_fk
23
+ -- creates-constraint: public.msteams_tenant_installs.msteams_tenant_installs_installed_by_user_id_users_id_fk
24
+ -- creates-constraint: public.msteams_tenant_installs.msteams_tenant_installs_status_allowed
25
+ -- creates-constraint: public.msteams_tenant_installs.msteams_tenant_installs_consent_status_allowed
26
+ -- creates-constraint: public.msteams_user_links.msteams_user_links_tenant_id_tenants_id_fk
27
+ -- creates-constraint: public.msteams_user_links.msteams_user_links_entra_tenant_id_installs_entra_tenant_id_fk
28
+ -- creates-constraint: public.msteams_user_links.msteams_user_links_user_id_users_id_fk
29
+ -- creates-constraint: public.msteams_user_links.msteams_user_links_status_allowed
30
+ -- creates-constraint: public.msteams_threads.msteams_threads_tenant_id_tenants_id_fk
31
+ -- creates-constraint: public.msteams_threads.msteams_threads_entra_tenant_id_installs_entra_tenant_id_fk
32
+ -- creates-constraint: public.msteams_threads.msteams_threads_thread_id_threads_id_fk
33
+
34
+ \set ON_ERROR_STOP on
35
+
36
+ BEGIN;
37
+
38
+ SET LOCAL lock_timeout = '5s';
39
+ SET LOCAL statement_timeout = '120s';
40
+
41
+ CREATE TABLE IF NOT EXISTS public.msteams_tenant_installs (
42
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
43
+ tenant_id uuid NOT NULL,
44
+ entra_tenant_id text NOT NULL,
45
+ bot_app_id text NOT NULL,
46
+ status text NOT NULL DEFAULT 'pending',
47
+ consent_status text NOT NULL DEFAULT 'pending',
48
+ installed_by_user_id uuid,
49
+ installed_at timestamptz,
50
+ uninstalled_at timestamptz,
51
+ created_at timestamptz NOT NULL DEFAULT now(),
52
+ updated_at timestamptz NOT NULL DEFAULT now(),
53
+ CONSTRAINT msteams_tenant_installs_tenant_id_tenants_id_fk
54
+ FOREIGN KEY (tenant_id)
55
+ REFERENCES public.tenants(id)
56
+ ON DELETE CASCADE,
57
+ CONSTRAINT msteams_tenant_installs_installed_by_user_id_users_id_fk
58
+ FOREIGN KEY (installed_by_user_id)
59
+ REFERENCES public.users(id)
60
+ ON DELETE SET NULL,
61
+ CONSTRAINT msteams_tenant_installs_status_allowed
62
+ CHECK (status IN ('pending','active','uninstalled','revoked')),
63
+ CONSTRAINT msteams_tenant_installs_consent_status_allowed
64
+ CHECK (consent_status IN ('pending','granted','admin_required','revoked'))
65
+ );
66
+
67
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_msteams_tenant_installs_entra_tenant
68
+ ON public.msteams_tenant_installs (entra_tenant_id);
69
+
70
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_msteams_tenant_installs_tenant_entra_tenant
71
+ ON public.msteams_tenant_installs (tenant_id, entra_tenant_id);
72
+
73
+ -- A ThinkWork tenant has at most one ACTIVE Entra binding; concurrent
74
+ -- consent callbacks cannot race two bindings live.
75
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_msteams_tenant_installs_tenant_active
76
+ ON public.msteams_tenant_installs (tenant_id)
77
+ WHERE status = 'active';
78
+
79
+ CREATE INDEX IF NOT EXISTS idx_msteams_tenant_installs_tenant_status
80
+ ON public.msteams_tenant_installs (tenant_id, status);
81
+
82
+ CREATE TABLE IF NOT EXISTS public.msteams_user_links (
83
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
84
+ tenant_id uuid NOT NULL,
85
+ entra_tenant_id text NOT NULL,
86
+ aad_object_id text NOT NULL,
87
+ user_id uuid NOT NULL,
88
+ display_name text,
89
+ status text NOT NULL DEFAULT 'active',
90
+ linked_at timestamptz NOT NULL DEFAULT now(),
91
+ unlinked_at timestamptz,
92
+ created_at timestamptz NOT NULL DEFAULT now(),
93
+ updated_at timestamptz NOT NULL DEFAULT now(),
94
+ CONSTRAINT msteams_user_links_tenant_id_tenants_id_fk
95
+ FOREIGN KEY (tenant_id)
96
+ REFERENCES public.tenants(id)
97
+ ON DELETE CASCADE,
98
+ CONSTRAINT msteams_user_links_entra_tenant_id_installs_entra_tenant_id_fk
99
+ FOREIGN KEY (entra_tenant_id)
100
+ REFERENCES public.msteams_tenant_installs(entra_tenant_id)
101
+ ON DELETE RESTRICT,
102
+ CONSTRAINT msteams_user_links_user_id_users_id_fk
103
+ FOREIGN KEY (user_id)
104
+ REFERENCES public.users(id)
105
+ ON DELETE RESTRICT,
106
+ CONSTRAINT msteams_user_links_status_allowed
107
+ CHECK (status IN ('active','unlinked','orphaned','suspended'))
108
+ );
109
+
110
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_msteams_user_links_entra_tenant_aad_object
111
+ ON public.msteams_user_links (entra_tenant_id, aad_object_id);
112
+
113
+ CREATE INDEX IF NOT EXISTS idx_msteams_user_links_tenant_user
114
+ ON public.msteams_user_links (tenant_id, user_id);
115
+
116
+ CREATE INDEX IF NOT EXISTS idx_msteams_user_links_user
117
+ ON public.msteams_user_links (user_id);
118
+
119
+ CREATE TABLE IF NOT EXISTS public.msteams_threads (
120
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
121
+ tenant_id uuid NOT NULL,
122
+ entra_tenant_id text NOT NULL,
123
+ conversation_id text NOT NULL,
124
+ service_url text NOT NULL,
125
+ thread_id uuid NOT NULL,
126
+ created_at timestamptz NOT NULL DEFAULT now(),
127
+ updated_at timestamptz NOT NULL DEFAULT now(),
128
+ CONSTRAINT msteams_threads_tenant_id_tenants_id_fk
129
+ FOREIGN KEY (tenant_id)
130
+ REFERENCES public.tenants(id)
131
+ ON DELETE CASCADE,
132
+ CONSTRAINT msteams_threads_entra_tenant_id_installs_entra_tenant_id_fk
133
+ FOREIGN KEY (entra_tenant_id)
134
+ REFERENCES public.msteams_tenant_installs(entra_tenant_id)
135
+ ON DELETE RESTRICT,
136
+ CONSTRAINT msteams_threads_thread_id_threads_id_fk
137
+ FOREIGN KEY (thread_id)
138
+ REFERENCES public.threads(id)
139
+ ON DELETE CASCADE
140
+ );
141
+
142
+ CREATE UNIQUE INDEX IF NOT EXISTS uq_msteams_threads_entra_tenant_conversation
143
+ ON public.msteams_threads (entra_tenant_id, conversation_id);
144
+
145
+ CREATE INDEX IF NOT EXISTS idx_msteams_threads_thread
146
+ ON public.msteams_threads (thread_id);
147
+
148
+ CREATE INDEX IF NOT EXISTS idx_msteams_threads_tenant_entra_tenant
149
+ ON public.msteams_threads (tenant_id, entra_tenant_id);
150
+
151
+ COMMIT;
@@ -0,0 +1,20 @@
1
+ -- THINK-193 U1: widen workflow_task_tokens purpose domain with
2
+ -- 'memory_stage' (task tokens held while a memory pipeline stage runs).
3
+ --
4
+ -- Hand-rolled (drizzle meta journal is not in use for this change);
5
+ -- apply with: psql "$DATABASE_URL" -f drizzle/0233_workflow_memory_stage_tokens.sql
6
+ -- creates-constraint: public.workflow_task_tokens.workflow_task_tokens_purpose_check_v2
7
+ --
8
+ -- The constraint is RENAMED (_v2), not redefined in place: the drift
9
+ -- reporter probes constraints by NAME only, so redefining under the old
10
+ -- name would report APPLIED on environments still carrying the narrow
11
+ -- 0221 list. The _v2 name makes an unapplied widening visible as MISSING.
12
+
13
+ ALTER TABLE public.workflow_task_tokens
14
+ DROP CONSTRAINT IF EXISTS workflow_task_tokens_purpose_check;
15
+ ALTER TABLE public.workflow_task_tokens
16
+ DROP CONSTRAINT IF EXISTS workflow_task_tokens_purpose_check_v2;
17
+ ALTER TABLE public.workflow_task_tokens
18
+ ADD CONSTRAINT workflow_task_tokens_purpose_check_v2 CHECK (
19
+ purpose IN ('agent_step', 'approval', 'memory_stage')
20
+ );
@@ -0,0 +1,160 @@
1
+ -- THINK-193 U2: external-memory claim lifecycle.
2
+ -- Contents:
3
+ -- * memory_source_authorizations — explicit grant, the MAXIMUM readable
4
+ -- envelope per (processor, family, binding) (partial unique on active).
5
+ -- * memory_claims — durable ontology-shaped claims with a null-safe
6
+ -- fingerprint unique index (COALESCE folds NULL effective_from).
7
+ -- * memory_claim_evidence — many-to-many claim <- evidence support edges.
8
+ -- * memory_retraction_attempts — idempotent multi-system retraction ledger
9
+ -- (retain-attempts-shaped: status/attempt/lock columns, partial unique so
10
+ -- a completed retraction can be re-queued later).
11
+ -- * memory_evidence_items.snapshot_expires_at — app-enforced S3 snapshot TTL.
12
+ --
13
+ -- Hand-rolled (drizzle meta journal is not in use for this change);
14
+ -- apply with: psql "$DATABASE_URL" -f drizzle/0234_memory_claim_lifecycle.sql
15
+ -- creates: public.memory_source_authorizations
16
+ -- creates: public.memory_claims
17
+ -- creates: public.memory_claim_evidence
18
+ -- creates: public.memory_retraction_attempts
19
+ -- creates-column: public.memory_evidence_items.snapshot_expires_at
20
+
21
+ CREATE TABLE IF NOT EXISTS public.memory_source_authorizations (
22
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
23
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
24
+ processor_config_id uuid NOT NULL
25
+ REFERENCES public.memory_processor_configs(id) ON DELETE CASCADE,
26
+ source_family text NOT NULL,
27
+ source_binding_key text NOT NULL,
28
+ boundary jsonb NOT NULL DEFAULT '{}'::jsonb,
29
+ granted_by_user_id uuid REFERENCES public.users(id) ON DELETE SET NULL,
30
+ grant_version integer NOT NULL DEFAULT 1,
31
+ status text NOT NULL DEFAULT 'active',
32
+ expires_at timestamptz,
33
+ revoked_at timestamptz,
34
+ sensitivity jsonb NOT NULL DEFAULT '{}'::jsonb,
35
+ created_at timestamptz NOT NULL DEFAULT now(),
36
+ updated_at timestamptz NOT NULL DEFAULT now(),
37
+ CONSTRAINT memory_source_authorizations_source_family_check
38
+ CHECK (source_family IN ('twenty', 'firecrawl', 'email', 'bedrock_kb')),
39
+ CONSTRAINT memory_source_authorizations_status_check
40
+ CHECK (status IN ('active', 'revoked', 'expired'))
41
+ );
42
+
43
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_source_authorizations_active_uidx
44
+ ON public.memory_source_authorizations (processor_config_id, source_family, source_binding_key)
45
+ WHERE status = 'active';
46
+
47
+ CREATE INDEX IF NOT EXISTS memory_source_authorizations_tenant_idx
48
+ ON public.memory_source_authorizations (tenant_id);
49
+
50
+ CREATE TABLE IF NOT EXISTS public.memory_claims (
51
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
52
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
53
+ target_scope text NOT NULL,
54
+ target_id uuid NOT NULL,
55
+ canonical_subject_id uuid,
56
+ subject_key text NOT NULL,
57
+ subject_entity_type text NOT NULL DEFAULT 'customer',
58
+ ontology_predicate text NOT NULL,
59
+ value jsonb NOT NULL,
60
+ value_hash text NOT NULL,
61
+ effective_from timestamptz,
62
+ effective_to timestamptz,
63
+ status text NOT NULL DEFAULT 'active',
64
+ conflict_state text NOT NULL DEFAULT 'none',
65
+ extraction_version text NOT NULL,
66
+ created_at timestamptz NOT NULL DEFAULT now(),
67
+ updated_at timestamptz NOT NULL DEFAULT now(),
68
+ CONSTRAINT memory_claims_target_scope_check
69
+ CHECK (target_scope IN ('space', 'tenant')),
70
+ CONSTRAINT memory_claims_status_check
71
+ CHECK (status IN ('active', 'superseded', 'retracted')),
72
+ CONSTRAINT memory_claims_conflict_state_check
73
+ CHECK (conflict_state IN ('none', 'conflicted'))
74
+ );
75
+
76
+ -- Null-safe fingerprint: COALESCE folds NULL effective_from into '-infinity'
77
+ -- so duplicate open-ended claims collide instead of coexisting.
78
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_claims_fingerprint_uidx
79
+ ON public.memory_claims (
80
+ tenant_id,
81
+ target_scope,
82
+ target_id,
83
+ subject_key,
84
+ ontology_predicate,
85
+ value_hash,
86
+ COALESCE(effective_from, '-infinity'::timestamptz)
87
+ );
88
+
89
+ CREATE INDEX IF NOT EXISTS memory_claims_target_subject_idx
90
+ ON public.memory_claims (tenant_id, target_scope, target_id, subject_key);
91
+
92
+ CREATE INDEX IF NOT EXISTS memory_claims_tenant_status_idx
93
+ ON public.memory_claims (tenant_id, status);
94
+
95
+ CREATE TABLE IF NOT EXISTS public.memory_claim_evidence (
96
+ id bigserial PRIMARY KEY,
97
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
98
+ claim_id uuid NOT NULL
99
+ REFERENCES public.memory_claims(id) ON DELETE CASCADE,
100
+ evidence_item_id uuid NOT NULL
101
+ REFERENCES public.memory_evidence_items(id) ON DELETE CASCADE,
102
+ source_config_id uuid NOT NULL
103
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
104
+ status text NOT NULL DEFAULT 'active',
105
+ created_at timestamptz NOT NULL DEFAULT now(),
106
+ retracted_at timestamptz,
107
+ CONSTRAINT memory_claim_evidence_status_check
108
+ CHECK (status IN ('active', 'retracted'))
109
+ );
110
+
111
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_claim_evidence_pair_uidx
112
+ ON public.memory_claim_evidence (claim_id, evidence_item_id);
113
+
114
+ CREATE INDEX IF NOT EXISTS memory_claim_evidence_evidence_idx
115
+ ON public.memory_claim_evidence (evidence_item_id);
116
+
117
+ CREATE INDEX IF NOT EXISTS memory_claim_evidence_claim_status_idx
118
+ ON public.memory_claim_evidence (claim_id, status);
119
+
120
+ CREATE TABLE IF NOT EXISTS public.memory_retraction_attempts (
121
+ id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
122
+ tenant_id uuid NOT NULL REFERENCES public.tenants(id) ON DELETE CASCADE,
123
+ scope text NOT NULL,
124
+ derivation_id uuid REFERENCES public.memory_derivations(id) ON DELETE SET NULL,
125
+ source_config_id uuid NOT NULL
126
+ REFERENCES public.memory_source_configs(id) ON DELETE CASCADE,
127
+ provider text NOT NULL DEFAULT 'hindsight',
128
+ provider_document_id text NOT NULL,
129
+ target_bank_id text NOT NULL,
130
+ status text NOT NULL DEFAULT 'queued',
131
+ attempt_count integer NOT NULL DEFAULT 0,
132
+ max_attempts integer NOT NULL DEFAULT 5,
133
+ next_retry_at timestamptz,
134
+ locked_at timestamptz,
135
+ locked_by text,
136
+ error_class text,
137
+ error_message text,
138
+ created_at timestamptz NOT NULL DEFAULT now(),
139
+ updated_at timestamptz NOT NULL DEFAULT now(),
140
+ completed_at timestamptz,
141
+ CONSTRAINT memory_retraction_attempts_scope_check
142
+ CHECK (scope IN ('derivation', 'source')),
143
+ CONSTRAINT memory_retraction_attempts_status_check
144
+ CHECK (status IN ('queued', 'running', 'supports_updated', 'provider_deleted', 'reconsolidated', 'retracted', 'failed', 'dead_lettered')),
145
+ CONSTRAINT memory_retraction_attempts_attempt_count_nonnegative
146
+ CHECK (attempt_count >= 0),
147
+ CONSTRAINT memory_retraction_attempts_max_attempts_positive
148
+ CHECK (max_attempts > 0)
149
+ );
150
+
151
+ -- Partial unique — a completed retraction can be re-queued later.
152
+ CREATE UNIQUE INDEX IF NOT EXISTS memory_retraction_attempts_document_uidx
153
+ ON public.memory_retraction_attempts (tenant_id, provider, provider_document_id)
154
+ WHERE status NOT IN ('retracted', 'dead_lettered');
155
+
156
+ CREATE INDEX IF NOT EXISTS memory_retraction_attempts_due_idx
157
+ ON public.memory_retraction_attempts (status, next_retry_at, created_at);
158
+
159
+ ALTER TABLE public.memory_evidence_items
160
+ ADD COLUMN IF NOT EXISTS snapshot_expires_at timestamptz;
@@ -0,0 +1,34 @@
1
+ -- THINK-193 U1 (Codex F1/F7/F9): durable pre-execution claim for workflow
2
+ -- task tokens. Adds the 'executing' status (pending -> executing -> consumed),
3
+ -- lease columns (locked_at/locked_by, stale claims are re-claimable), and a
4
+ -- persisted completion result for safe redrive after a SendTaskSuccess
5
+ -- transient failure.
6
+ --
7
+ -- Hand-rolled (drizzle meta journal is not in use for this change);
8
+ -- apply with: psql "$DATABASE_URL" -f drizzle/0235_workflow_token_execution_claim.sql
9
+ -- creates-constraint: public.workflow_task_tokens.workflow_task_tokens_status_check_v2
10
+ -- creates-column: public.workflow_task_tokens.locked_at
11
+ -- creates-column: public.workflow_task_tokens.locked_by
12
+ -- creates-column: public.workflow_task_tokens.result
13
+ --
14
+ -- The constraint is RENAMED (_v2), not redefined in place: the drift
15
+ -- reporter probes constraints by NAME only, so redefining under the old
16
+ -- name would report APPLIED on environments still carrying the narrow
17
+ -- three-status list. The _v2 name makes an unapplied widening visible as
18
+ -- MISSING. (Same precedent as 0233's purpose-check widening.)
19
+
20
+ ALTER TABLE public.workflow_task_tokens
21
+ ADD COLUMN IF NOT EXISTS locked_at timestamptz;
22
+ ALTER TABLE public.workflow_task_tokens
23
+ ADD COLUMN IF NOT EXISTS locked_by text;
24
+ ALTER TABLE public.workflow_task_tokens
25
+ ADD COLUMN IF NOT EXISTS result jsonb;
26
+
27
+ ALTER TABLE public.workflow_task_tokens
28
+ DROP CONSTRAINT IF EXISTS workflow_task_tokens_status_check;
29
+ ALTER TABLE public.workflow_task_tokens
30
+ DROP CONSTRAINT IF EXISTS workflow_task_tokens_status_check_v2;
31
+ ALTER TABLE public.workflow_task_tokens
32
+ ADD CONSTRAINT workflow_task_tokens_status_check_v2 CHECK (
33
+ status IN ('pending', 'executing', 'consumed', 'expired')
34
+ );
@@ -0,0 +1,50 @@
1
+ -- THINK-193 U2 (Codex P1/P2 merge blockers): retraction saga worker fencing
2
+ -- and durable source-erase aggregate markers.
3
+ -- Contents:
4
+ -- * memory_retraction_attempts.lock_generation — fencing token; every CAS
5
+ -- claim increments it and all saga transitions (recordProgress /
6
+ -- finalizeInternalState / markRetracted / markFailed) CAS on
7
+ -- (locked_by, lock_generation) so a worker reclaimed past a stale lease
8
+ -- can never clobber the newer claimant's progress.
9
+ -- * memory_retraction_attempts.reconsolidation_note — non-null when the
10
+ -- reconsolidation step was skipped (delete-capable adapter without a
11
+ -- consolidator): durable skipped-with-reason, distinct from success.
12
+ -- * scope CHECK v2 — adds 'erase': one durable aggregate marker row per
13
+ -- source erase (synthetic erase:<sourceConfigId> document id under the
14
+ -- existing partial unique document index). Markers are excluded from the
15
+ -- per-document saga; the scheduled memory-retraction-drainer keys its
16
+ -- self-finalizing cleanup sweep (S3 snapshot prefix -> evidence purge ->
17
+ -- checkpoints LAST) on them, covering sources with zero derivations.
18
+ -- NEW constraint name: the drift reporter probes by name only.
19
+ --
20
+ -- No status CHECK changes: the status value set is unchanged; only the
21
+ -- saga's transition ORDER moved (provider delete now precedes the internal
22
+ -- finalize transaction).
23
+ --
24
+ -- Hand-rolled (drizzle meta journal is not in use for this change);
25
+ -- apply with: psql "$DATABASE_URL" -f drizzle/0236_memory_retraction_fencing.sql
26
+ -- creates-column: public.memory_retraction_attempts.lock_generation
27
+ -- creates-column: public.memory_retraction_attempts.reconsolidation_note
28
+ -- creates-constraint: public.memory_retraction_attempts.memory_retraction_attempts_scope_check_v2
29
+
30
+ ALTER TABLE public.memory_retraction_attempts
31
+ ADD COLUMN IF NOT EXISTS lock_generation integer NOT NULL DEFAULT 0;
32
+
33
+ ALTER TABLE public.memory_retraction_attempts
34
+ ADD COLUMN IF NOT EXISTS reconsolidation_note text;
35
+
36
+ ALTER TABLE public.memory_retraction_attempts
37
+ DROP CONSTRAINT IF EXISTS memory_retraction_attempts_scope_check;
38
+
39
+ DO $$
40
+ BEGIN
41
+ IF NOT EXISTS (
42
+ SELECT 1 FROM pg_constraint
43
+ WHERE conname = 'memory_retraction_attempts_scope_check_v2'
44
+ AND conrelid = 'public.memory_retraction_attempts'::regclass
45
+ ) THEN
46
+ ALTER TABLE public.memory_retraction_attempts
47
+ ADD CONSTRAINT memory_retraction_attempts_scope_check_v2
48
+ CHECK (scope IN ('derivation', 'source', 'erase'));
49
+ END IF;
50
+ END $$;