@opengeni/db 3.7.4 → 3.8.2-canary.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.
- package/dist/automations.d.ts +4 -0
- package/dist/canonical-human-identities.js +3 -3
- package/dist/{chunk-O56DM5GZ.js → chunk-53A2PEHT.js} +328 -31
- package/dist/chunk-53A2PEHT.js.map +1 -0
- package/dist/{chunk-SZAWDXQC.js → chunk-5S4BQAHX.js} +3 -3
- package/dist/{chunk-S3TDDCS2.js → chunk-CITYUGMW.js} +3 -3
- package/dist/{chunk-4NAR7FBA.js → chunk-F5YOZEYQ.js} +49 -1
- package/dist/chunk-F5YOZEYQ.js.map +1 -0
- package/dist/{chunk-F6PBS6WE.js → chunk-HZV7O6JR.js} +2 -2
- package/dist/{chunk-5NNCGFQY.js → chunk-RLQVPOVR.js} +2 -2
- package/dist/{chunk-DZCYW2WT.js → chunk-UKOGHUGC.js} +2 -2
- package/dist/{chunk-US4IS6IV.js → chunk-X6TO5HII.js} +2 -2
- package/dist/{chunk-U4WPPEBH.js → chunk-Y53WEFYB.js} +2 -2
- package/dist/connection-token-resolver.d.ts +4 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +164 -14
- package/dist/index.js +7327 -5442
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +9 -0
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/model-catalog.d.ts +153 -0
- package/dist/new-session-drafts.d.ts +12 -0
- package/dist/organization-membership-lifecycle.d.ts +8 -1
- package/dist/organization-model-providers.d.ts +101 -0
- package/dist/pack-components.d.ts +1 -0
- package/dist/pr-review.d.ts +9 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +7 -7
- package/dist/schema.d.ts +989 -2
- package/dist/schema.js +11 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +35 -0
- package/dist/session-queue-commands.d.ts +17 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/video-generation.js +3 -3
- package/dist/xai-subscription.d.ts +8 -0
- package/drizzle/0387_bound_host_export_session_payloads.sql +165 -0
- package/drizzle/0388_sandbox_provider_deadline_interactions.sql +491 -0
- package/drizzle/0389_model_catalog_and_gateway_custom_models.sql +241 -0
- package/drizzle/0390_organization_model_provider_connections.sql +197 -0
- package/drizzle/0391_sandbox_provider_deadline_interaction_followup.sql +295 -0
- package/drizzle/0392_context_compaction_pending_observability.sql +198 -0
- package/drizzle/0393_workspace_memory_and_learning_defaults.sql +102 -0
- package/drizzle/0394_session_selected_skill_activation.sql +20 -0
- package/drizzle/0395_scheduled_task_unclaimed_occurrence_invalidation.sql +154 -0
- package/drizzle/0396_model_call_equivalent_credit_cost.sql +28 -0
- package/drizzle/0397_sandbox_deadline_rotation_preemption.sql +113 -0
- package/drizzle/0398_organization_workspace_management_entry.sql +206 -0
- package/drizzle/0399_additional_managed_organization_creation.sql +691 -0
- package/package.json +6 -6
- package/src/automations.ts +9 -1
- package/src/connection-token-resolver.ts +12 -0
- package/src/index.ts +1551 -272
- package/src/insights-model-bundle.ts +54 -5
- package/src/insights.ts +53 -7
- package/src/model-catalog.ts +682 -0
- package/src/new-session-drafts.ts +66 -21
- package/src/organization-membership-lifecycle.ts +47 -5
- package/src/organization-model-providers.ts +614 -0
- package/src/pack-components.ts +15 -2
- package/src/pr-review.ts +19 -0
- package/src/provision-roles.ts +2 -0
- package/src/runtime-posture.ts +48 -0
- package/src/schema.ts +348 -32
- package/src/session-control.ts +170 -0
- package/src/session-queue-commands.ts +157 -82
- package/src/xai-subscription.ts +66 -14
- package/dist/chunk-4NAR7FBA.js.map +0 -1
- package/dist/chunk-O56DM5GZ.js.map +0 -1
- /package/dist/{chunk-SZAWDXQC.js.map → chunk-5S4BQAHX.js.map} +0 -0
- /package/dist/{chunk-S3TDDCS2.js.map → chunk-CITYUGMW.js.map} +0 -0
- /package/dist/{chunk-F6PBS6WE.js.map → chunk-HZV7O6JR.js.map} +0 -0
- /package/dist/{chunk-5NNCGFQY.js.map → chunk-RLQVPOVR.js.map} +0 -0
- /package/dist/{chunk-DZCYW2WT.js.map → chunk-UKOGHUGC.js.map} +0 -0
- /package/dist/{chunk-US4IS6IV.js.map → chunk-X6TO5HII.js.map} +0 -0
- /package/dist/{chunk-U4WPPEBH.js.map → chunk-Y53WEFYB.js.map} +0 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Repair the post-0388 provider-deadline interaction lifecycle without
|
|
3
|
+
-- widening ordinary interaction expiry or weakening the session-tenancy fence.
|
|
4
|
+
SET LOCAL lock_timeout = '5s';
|
|
5
|
+
SET LOCAL statement_timeout = '10min';
|
|
6
|
+
|
|
7
|
+
-- The TTL-aware fence inventory below must discover due lease-free controller
|
|
8
|
+
-- transitions before the SECURITY DEFINER reaper opens its fenced owner scope.
|
|
9
|
+
-- Keep this as inventory-only SELECT authority; the 0388 fenced owner policies
|
|
10
|
+
-- remain the sole mutation path after every workspace advisory lock is held.
|
|
11
|
+
DO $interaction_reaper_inventory_policies$
|
|
12
|
+
DECLARE
|
|
13
|
+
target_schema text := pg_catalog.current_schema();
|
|
14
|
+
target_schema_oid oid := pg_catalog.current_schema()::pg_catalog.regnamespace;
|
|
15
|
+
migration_owner text := current_user;
|
|
16
|
+
table_name text;
|
|
17
|
+
BEGIN
|
|
18
|
+
FOREACH table_name IN ARRAY ARRAY[
|
|
19
|
+
'browser_sessions',
|
|
20
|
+
'computer_sessions',
|
|
21
|
+
'interaction_operations'
|
|
22
|
+
] LOOP
|
|
23
|
+
EXECUTE pg_catalog.format(
|
|
24
|
+
'DROP POLICY IF EXISTS session_tenancy_fence_inventory_read ON %I.%I',
|
|
25
|
+
target_schema,
|
|
26
|
+
table_name
|
|
27
|
+
);
|
|
28
|
+
EXECUTE pg_catalog.format(
|
|
29
|
+
'CREATE POLICY session_tenancy_fence_inventory_read ON %I.%I '
|
|
30
|
+
|| 'FOR SELECT USING ('
|
|
31
|
+
|| '%I.session_tenancy_fence_owner_policy_active('
|
|
32
|
+
|| 'current_user::text, %L::text, %s::oid, workspace_id, true))',
|
|
33
|
+
target_schema,
|
|
34
|
+
table_name,
|
|
35
|
+
target_schema,
|
|
36
|
+
migration_owner,
|
|
37
|
+
target_schema_oid
|
|
38
|
+
);
|
|
39
|
+
END LOOP;
|
|
40
|
+
END
|
|
41
|
+
$interaction_reaper_inventory_policies$;
|
|
42
|
+
|
|
43
|
+
-- The no-argument helper remains installed for reap_sandbox_leases() and old
|
|
44
|
+
-- in-flight callers. The interaction reaper uses this overload so its bounded
|
|
45
|
+
-- stale-operation batch can also see lease-free Connected Machine and attached-
|
|
46
|
+
-- device workspaces. Because SKIP LOCKED can advance beyond any preselected
|
|
47
|
+
-- operation row, fence every currently due workspace, but no healthy lease-free
|
|
48
|
+
-- interaction workspace, in canonical UUID order before taking row locks.
|
|
49
|
+
CREATE OR REPLACE FUNCTION acquire_sandbox_reaper_session_tenancy_fences(
|
|
50
|
+
p_interaction_holder_ttl_ms bigint
|
|
51
|
+
)
|
|
52
|
+
RETURNS integer
|
|
53
|
+
LANGUAGE plpgsql
|
|
54
|
+
SECURITY DEFINER
|
|
55
|
+
SET search_path FROM CURRENT
|
|
56
|
+
AS $interaction_reaper_fences$
|
|
57
|
+
DECLARE
|
|
58
|
+
inventory_capability_id uuid;
|
|
59
|
+
workspace_id_value uuid;
|
|
60
|
+
locked_count integer := 0;
|
|
61
|
+
BEGIN
|
|
62
|
+
IF p_interaction_holder_ttl_ms <= 0 THEN
|
|
63
|
+
RETURN 0;
|
|
64
|
+
END IF;
|
|
65
|
+
PERFORM pg_catalog.set_config('opengeni.sandbox_recovery_protocol_v2', '1', true);
|
|
66
|
+
inventory_capability_id :=
|
|
67
|
+
opengeni_private.open_session_tenancy_fence_inventory(
|
|
68
|
+
session_tenancy_fence_target_schema()
|
|
69
|
+
);
|
|
70
|
+
FOR workspace_id_value IN
|
|
71
|
+
SELECT candidate.workspace_id
|
|
72
|
+
FROM (
|
|
73
|
+
SELECT lease.workspace_id
|
|
74
|
+
FROM sandbox_leases lease
|
|
75
|
+
WHERE lease.workspace_id IS NOT NULL
|
|
76
|
+
AND (
|
|
77
|
+
lease.liveness <> 'cold'
|
|
78
|
+
OR EXISTS (
|
|
79
|
+
SELECT 1
|
|
80
|
+
FROM sandbox_lease_holders holder
|
|
81
|
+
WHERE holder.lease_id = lease.id
|
|
82
|
+
)
|
|
83
|
+
)
|
|
84
|
+
UNION
|
|
85
|
+
SELECT operation.workspace_id
|
|
86
|
+
FROM interaction_operations operation
|
|
87
|
+
WHERE operation.workspace_id IS NOT NULL
|
|
88
|
+
-- Lease-free prepared operations remain replayable. A dispatched
|
|
89
|
+
-- operation is the first controller-side effect and is the only
|
|
90
|
+
-- lease-free transition the ordinary stale-transition reaper settles.
|
|
91
|
+
AND operation.state = 'dispatched'
|
|
92
|
+
AND operation.updated_at
|
|
93
|
+
< pg_catalog.now()
|
|
94
|
+
- pg_catalog.make_interval(
|
|
95
|
+
secs => p_interaction_holder_ttl_ms / 1000.0
|
|
96
|
+
)
|
|
97
|
+
AND (
|
|
98
|
+
EXISTS (
|
|
99
|
+
SELECT 1
|
|
100
|
+
FROM browser_sessions browser
|
|
101
|
+
WHERE operation.resource_kind = 'browser_session'
|
|
102
|
+
AND operation.account_id = browser.account_id
|
|
103
|
+
AND operation.workspace_id = browser.workspace_id
|
|
104
|
+
AND operation.resource_id = browser.id
|
|
105
|
+
AND browser.lifecycle IN (
|
|
106
|
+
'starting', 'suspending', 'restoring', 'ending'
|
|
107
|
+
)
|
|
108
|
+
)
|
|
109
|
+
OR EXISTS (
|
|
110
|
+
SELECT 1
|
|
111
|
+
FROM computer_sessions computer
|
|
112
|
+
WHERE operation.resource_kind = 'computer_session'
|
|
113
|
+
AND operation.account_id = computer.account_id
|
|
114
|
+
AND operation.workspace_id = computer.workspace_id
|
|
115
|
+
AND operation.resource_id = computer.id
|
|
116
|
+
AND computer.lifecycle IN ('starting', 'ending')
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
) candidate
|
|
120
|
+
ORDER BY candidate.workspace_id
|
|
121
|
+
LOOP
|
|
122
|
+
PERFORM acquire_session_tenancy_fence(workspace_id_value);
|
|
123
|
+
locked_count := locked_count + 1;
|
|
124
|
+
END LOOP;
|
|
125
|
+
PERFORM opengeni_private.close_session_tenancy_fence_inventory(
|
|
126
|
+
inventory_capability_id
|
|
127
|
+
);
|
|
128
|
+
RETURN locked_count;
|
|
129
|
+
EXCEPTION WHEN OTHERS THEN
|
|
130
|
+
PERFORM opengeni_private.close_session_tenancy_fence_inventory(
|
|
131
|
+
inventory_capability_id
|
|
132
|
+
);
|
|
133
|
+
RAISE;
|
|
134
|
+
END
|
|
135
|
+
$interaction_reaper_fences$;
|
|
136
|
+
|
|
137
|
+
REVOKE ALL ON FUNCTION
|
|
138
|
+
acquire_sandbox_reaper_session_tenancy_fences(bigint)
|
|
139
|
+
FROM PUBLIC;
|
|
140
|
+
|
|
141
|
+
-- CREATE OR REPLACE records `SET search_path FROM CURRENT` from the migrator
|
|
142
|
+
-- connection. Re-pin this overload to the exact target schema before callers
|
|
143
|
+
-- can invoke the enclosing reaper, so a caller-created temp relation cannot
|
|
144
|
+
-- shadow its lease-free inventory before workspace fences are acquired.
|
|
145
|
+
DO $pin_interaction_reaper_fence_helper$
|
|
146
|
+
DECLARE
|
|
147
|
+
target_schema text := pg_catalog.current_schema();
|
|
148
|
+
BEGIN
|
|
149
|
+
EXECUTE pg_catalog.format(
|
|
150
|
+
'ALTER FUNCTION %I.acquire_sandbox_reaper_session_tenancy_fences(bigint) '
|
|
151
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
152
|
+
target_schema,
|
|
153
|
+
target_schema
|
|
154
|
+
);
|
|
155
|
+
END
|
|
156
|
+
$pin_interaction_reaper_fence_helper$;
|
|
157
|
+
|
|
158
|
+
-- Patch only the exact 0388 definition. The interaction reaper keeps the
|
|
159
|
+
-- canonical advisory-fence -> owner capability -> operation -> lease -> holder
|
|
160
|
+
-- ordering. The holder EXISTS is an unlocked eligibility read before LIMIT;
|
|
161
|
+
-- lease rows are still the first ownership rows locked by the deadline phase.
|
|
162
|
+
DO $provider_deadline_interaction_followup$
|
|
163
|
+
DECLARE
|
|
164
|
+
data_schema text := pg_catalog.current_schema();
|
|
165
|
+
definition text;
|
|
166
|
+
patched text;
|
|
167
|
+
fence_anchor constant text :=
|
|
168
|
+
E' PERFORM acquire_sandbox_reaper_session_tenancy_fences();';
|
|
169
|
+
fence_replacement constant text :=
|
|
170
|
+
E' -- 0391 provider-deadline interaction follow-up: inventory due\n'
|
|
171
|
+
|| E' -- lease-free transitions before any interaction row lock.\n'
|
|
172
|
+
|| E' PERFORM acquire_sandbox_reaper_session_tenancy_fences(\n'
|
|
173
|
+
|| E' p_interaction_holder_ttl_ms\n'
|
|
174
|
+
|| E' );';
|
|
175
|
+
liveness_anchor constant text :=
|
|
176
|
+
E' AND lease.liveness IN (''warming'', ''warm'')';
|
|
177
|
+
liveness_replacement constant text :=
|
|
178
|
+
E' AND lease.liveness IN (''warming'', ''warm'', ''draining'')';
|
|
179
|
+
deadline_anchor constant text :=
|
|
180
|
+
E' AND lease.provider_deadline_at <= pg_catalog.now()';
|
|
181
|
+
deadline_replacement text;
|
|
182
|
+
occurrences integer;
|
|
183
|
+
BEGIN
|
|
184
|
+
SELECT pg_catalog.pg_get_functiondef(
|
|
185
|
+
'opengeni_private.reap_stale_interaction_transitions(bigint)'::regprocedure
|
|
186
|
+
) INTO definition;
|
|
187
|
+
|
|
188
|
+
IF definition IS NULL
|
|
189
|
+
OR pg_catalog.strpos(definition, 'deadline_lease_ids uuid[]') = 0
|
|
190
|
+
OR pg_catalog.strpos(definition, 'provider_deadline_rotation') = 0
|
|
191
|
+
OR pg_catalog.strpos(definition, 'open_session_tenancy_fenced_access') = 0
|
|
192
|
+
OR pg_catalog.strpos(definition, 'LIMIT 500') = 0
|
|
193
|
+
THEN
|
|
194
|
+
RAISE EXCEPTION '0391 interaction reaper prerequisite definition drift'
|
|
195
|
+
USING ERRCODE = '55000';
|
|
196
|
+
END IF;
|
|
197
|
+
|
|
198
|
+
IF pg_catalog.strpos(
|
|
199
|
+
definition,
|
|
200
|
+
'0391 provider-deadline interaction follow-up'
|
|
201
|
+
) > 0 THEN
|
|
202
|
+
IF pg_catalog.strpos(
|
|
203
|
+
definition,
|
|
204
|
+
'acquire_sandbox_reaper_session_tenancy_fences('
|
|
205
|
+
) = 0
|
|
206
|
+
OR pg_catalog.strpos(
|
|
207
|
+
definition,
|
|
208
|
+
'p_interaction_holder_ttl_ms'
|
|
209
|
+
) = 0
|
|
210
|
+
OR pg_catalog.strpos(
|
|
211
|
+
definition,
|
|
212
|
+
'lease.liveness IN (''warming'', ''warm'', ''draining'')'
|
|
213
|
+
) = 0
|
|
214
|
+
OR pg_catalog.strpos(
|
|
215
|
+
definition,
|
|
216
|
+
'interaction_holder.kind = ''interaction'''
|
|
217
|
+
) = 0
|
|
218
|
+
THEN
|
|
219
|
+
RAISE EXCEPTION '0391 interaction reaper replay definition drift'
|
|
220
|
+
USING ERRCODE = '55000';
|
|
221
|
+
END IF;
|
|
222
|
+
ELSE
|
|
223
|
+
patched := definition;
|
|
224
|
+
|
|
225
|
+
occurrences := (
|
|
226
|
+
pg_catalog.length(patched)
|
|
227
|
+
- pg_catalog.length(pg_catalog.replace(patched, fence_anchor, ''))
|
|
228
|
+
) / pg_catalog.length(fence_anchor);
|
|
229
|
+
IF occurrences <> 1 THEN
|
|
230
|
+
RAISE EXCEPTION '0391 interaction reaper fence anchor drift'
|
|
231
|
+
USING ERRCODE = '55000';
|
|
232
|
+
END IF;
|
|
233
|
+
patched := pg_catalog.replace(patched, fence_anchor, fence_replacement);
|
|
234
|
+
|
|
235
|
+
occurrences := (
|
|
236
|
+
pg_catalog.length(patched)
|
|
237
|
+
- pg_catalog.length(pg_catalog.replace(patched, liveness_anchor, ''))
|
|
238
|
+
) / pg_catalog.length(liveness_anchor);
|
|
239
|
+
IF occurrences <> 1 THEN
|
|
240
|
+
RAISE EXCEPTION '0391 interaction reaper liveness anchor drift'
|
|
241
|
+
USING ERRCODE = '55000';
|
|
242
|
+
END IF;
|
|
243
|
+
patched := pg_catalog.replace(
|
|
244
|
+
patched,
|
|
245
|
+
liveness_anchor,
|
|
246
|
+
liveness_replacement
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
occurrences := (
|
|
250
|
+
pg_catalog.length(patched)
|
|
251
|
+
- pg_catalog.length(pg_catalog.replace(patched, deadline_anchor, ''))
|
|
252
|
+
) / pg_catalog.length(deadline_anchor);
|
|
253
|
+
IF occurrences <> 1 THEN
|
|
254
|
+
RAISE EXCEPTION '0391 interaction reaper deadline anchor drift'
|
|
255
|
+
USING ERRCODE = '55000';
|
|
256
|
+
END IF;
|
|
257
|
+
deadline_replacement := deadline_anchor || pg_catalog.format(
|
|
258
|
+
E'\n AND EXISTS (\n'
|
|
259
|
+
|| E' SELECT 1\n'
|
|
260
|
+
|| E' FROM %I.sandbox_lease_holders interaction_holder\n'
|
|
261
|
+
|| E' WHERE interaction_holder.lease_id = lease.id\n'
|
|
262
|
+
|| E' AND interaction_holder.kind = ''interaction''\n'
|
|
263
|
+
|| E' )',
|
|
264
|
+
data_schema
|
|
265
|
+
);
|
|
266
|
+
patched := pg_catalog.replace(
|
|
267
|
+
patched,
|
|
268
|
+
deadline_anchor,
|
|
269
|
+
deadline_replacement
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
IF pg_catalog.strpos(
|
|
273
|
+
patched,
|
|
274
|
+
'0391 provider-deadline interaction follow-up'
|
|
275
|
+
) = 0
|
|
276
|
+
OR pg_catalog.strpos(
|
|
277
|
+
patched,
|
|
278
|
+
'lease.liveness IN (''warming'', ''warm'', ''draining'')'
|
|
279
|
+
) = 0
|
|
280
|
+
OR pg_catalog.strpos(
|
|
281
|
+
patched,
|
|
282
|
+
'interaction_holder.kind = ''interaction'''
|
|
283
|
+
) = 0
|
|
284
|
+
THEN
|
|
285
|
+
RAISE EXCEPTION '0391 interaction reaper patch failed'
|
|
286
|
+
USING ERRCODE = '55000';
|
|
287
|
+
END IF;
|
|
288
|
+
|
|
289
|
+
EXECUTE patched;
|
|
290
|
+
END IF;
|
|
291
|
+
END
|
|
292
|
+
$provider_deadline_interaction_followup$;
|
|
293
|
+
|
|
294
|
+
RESET statement_timeout;
|
|
295
|
+
RESET lock_timeout;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Project exact-attempt automatic compaction starts into one content-free,
|
|
3
|
+
-- restart-safe aggregate. Prometheus labels must never carry tenant/session ids,
|
|
4
|
+
-- while process-local start/completion timestamps cannot correlate concurrent
|
|
5
|
+
-- activities or survive the worker whose provider call became stuck.
|
|
6
|
+
|
|
7
|
+
CREATE TABLE opengeni_private.context_compaction_pending_observations (
|
|
8
|
+
workspace_id uuid NOT NULL,
|
|
9
|
+
attempt_id uuid NOT NULL,
|
|
10
|
+
started_at timestamp with time zone NOT NULL,
|
|
11
|
+
PRIMARY KEY (workspace_id, attempt_id),
|
|
12
|
+
CONSTRAINT context_compaction_pending_observations_attempt_fk
|
|
13
|
+
FOREIGN KEY (workspace_id, attempt_id)
|
|
14
|
+
REFERENCES session_turn_attempts (workspace_id, id)
|
|
15
|
+
ON DELETE CASCADE
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
REVOKE ALL ON TABLE opengeni_private.context_compaction_pending_observations FROM PUBLIC;
|
|
19
|
+
|
|
20
|
+
CREATE OR REPLACE FUNCTION opengeni_private.project_context_compaction_event()
|
|
21
|
+
RETURNS trigger
|
|
22
|
+
LANGUAGE plpgsql
|
|
23
|
+
SECURITY DEFINER
|
|
24
|
+
SET search_path = pg_catalog
|
|
25
|
+
AS $project_context_compaction_event$
|
|
26
|
+
BEGIN
|
|
27
|
+
IF NEW.turn_attempt_id IS NULL THEN
|
|
28
|
+
RETURN NEW;
|
|
29
|
+
END IF;
|
|
30
|
+
|
|
31
|
+
IF NEW.type = 'session.context.compaction.started'
|
|
32
|
+
AND NEW.payload ->> 'trigger' = 'auto'
|
|
33
|
+
THEN
|
|
34
|
+
INSERT INTO opengeni_private.context_compaction_pending_observations (
|
|
35
|
+
workspace_id,
|
|
36
|
+
attempt_id,
|
|
37
|
+
started_at
|
|
38
|
+
) VALUES (
|
|
39
|
+
NEW.workspace_id,
|
|
40
|
+
NEW.turn_attempt_id,
|
|
41
|
+
NEW.occurred_at
|
|
42
|
+
)
|
|
43
|
+
ON CONFLICT (workspace_id, attempt_id) DO UPDATE
|
|
44
|
+
SET started_at = EXCLUDED.started_at;
|
|
45
|
+
ELSIF NEW.type IN (
|
|
46
|
+
'session.context.compacted',
|
|
47
|
+
'session.context.compaction.skipped'
|
|
48
|
+
) THEN
|
|
49
|
+
DELETE FROM opengeni_private.context_compaction_pending_observations pending
|
|
50
|
+
WHERE pending.workspace_id = NEW.workspace_id
|
|
51
|
+
AND pending.attempt_id = NEW.turn_attempt_id;
|
|
52
|
+
END IF;
|
|
53
|
+
|
|
54
|
+
RETURN NEW;
|
|
55
|
+
END
|
|
56
|
+
$project_context_compaction_event$;
|
|
57
|
+
|
|
58
|
+
REVOKE ALL ON FUNCTION opengeni_private.project_context_compaction_event() FROM PUBLIC;
|
|
59
|
+
|
|
60
|
+
CREATE TRIGGER session_events_project_context_compaction_pending
|
|
61
|
+
AFTER INSERT ON session_events
|
|
62
|
+
FOR EACH ROW
|
|
63
|
+
WHEN (
|
|
64
|
+
NEW.type IN (
|
|
65
|
+
'session.context.compaction.started',
|
|
66
|
+
'session.context.compacted',
|
|
67
|
+
'session.context.compaction.skipped'
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
EXECUTE FUNCTION opengeni_private.project_context_compaction_event();
|
|
71
|
+
|
|
72
|
+
CREATE OR REPLACE FUNCTION opengeni_private.clear_context_compaction_pending_attempt()
|
|
73
|
+
RETURNS trigger
|
|
74
|
+
LANGUAGE plpgsql
|
|
75
|
+
SECURITY DEFINER
|
|
76
|
+
SET search_path = pg_catalog
|
|
77
|
+
AS $clear_context_compaction_pending_attempt$
|
|
78
|
+
BEGIN
|
|
79
|
+
IF OLD.state <> 'closed' AND NEW.state = 'closed' THEN
|
|
80
|
+
DELETE FROM opengeni_private.context_compaction_pending_observations pending
|
|
81
|
+
WHERE pending.workspace_id = NEW.workspace_id
|
|
82
|
+
AND pending.attempt_id = NEW.id;
|
|
83
|
+
END IF;
|
|
84
|
+
RETURN NEW;
|
|
85
|
+
END
|
|
86
|
+
$clear_context_compaction_pending_attempt$;
|
|
87
|
+
|
|
88
|
+
REVOKE ALL ON FUNCTION opengeni_private.clear_context_compaction_pending_attempt() FROM PUBLIC;
|
|
89
|
+
|
|
90
|
+
CREATE TRIGGER session_turn_attempts_clear_context_compaction_pending
|
|
91
|
+
AFTER UPDATE OF state ON session_turn_attempts
|
|
92
|
+
FOR EACH ROW
|
|
93
|
+
WHEN (OLD.state IS DISTINCT FROM NEW.state)
|
|
94
|
+
EXECUTE FUNCTION opengeni_private.clear_context_compaction_pending_attempt();
|
|
95
|
+
|
|
96
|
+
CREATE OR REPLACE FUNCTION opengeni_private.clear_context_compaction_pending_turn()
|
|
97
|
+
RETURNS trigger
|
|
98
|
+
LANGUAGE plpgsql
|
|
99
|
+
SECURITY DEFINER
|
|
100
|
+
SET search_path = pg_catalog
|
|
101
|
+
AS $clear_context_compaction_pending_turn$
|
|
102
|
+
BEGIN
|
|
103
|
+
IF OLD.active_attempt_id IS NOT NULL
|
|
104
|
+
AND OLD.active_attempt_id IS DISTINCT FROM NEW.active_attempt_id
|
|
105
|
+
THEN
|
|
106
|
+
DELETE FROM opengeni_private.context_compaction_pending_observations pending
|
|
107
|
+
WHERE pending.workspace_id = NEW.workspace_id
|
|
108
|
+
AND pending.attempt_id = OLD.active_attempt_id;
|
|
109
|
+
END IF;
|
|
110
|
+
RETURN NEW;
|
|
111
|
+
END
|
|
112
|
+
$clear_context_compaction_pending_turn$;
|
|
113
|
+
|
|
114
|
+
REVOKE ALL ON FUNCTION opengeni_private.clear_context_compaction_pending_turn() FROM PUBLIC;
|
|
115
|
+
|
|
116
|
+
CREATE TRIGGER session_turns_clear_context_compaction_pending
|
|
117
|
+
AFTER UPDATE OF active_attempt_id ON session_turns
|
|
118
|
+
FOR EACH ROW
|
|
119
|
+
WHEN (OLD.active_attempt_id IS DISTINCT FROM NEW.active_attempt_id)
|
|
120
|
+
EXECUTE FUNCTION opengeni_private.clear_context_compaction_pending_turn();
|
|
121
|
+
|
|
122
|
+
-- The migration owner is bound by FORCE RLS in production. Open the standard
|
|
123
|
+
-- owner-only posture window while reconstructing any automatic provider call
|
|
124
|
+
-- already in flight when this rolling migration lands.
|
|
125
|
+
ALTER TABLE session_events NO FORCE ROW LEVEL SECURITY;
|
|
126
|
+
ALTER TABLE session_turn_attempts NO FORCE ROW LEVEL SECURITY;
|
|
127
|
+
ALTER TABLE session_turns NO FORCE ROW LEVEL SECURITY;
|
|
128
|
+
|
|
129
|
+
WITH latest_landmark AS (
|
|
130
|
+
SELECT DISTINCT ON (event.workspace_id, event.turn_attempt_id)
|
|
131
|
+
event.workspace_id,
|
|
132
|
+
event.turn_attempt_id,
|
|
133
|
+
event.type,
|
|
134
|
+
event.payload,
|
|
135
|
+
event.occurred_at
|
|
136
|
+
FROM session_events event
|
|
137
|
+
WHERE event.turn_attempt_id IS NOT NULL
|
|
138
|
+
AND event.type IN (
|
|
139
|
+
'session.context.compaction.started',
|
|
140
|
+
'session.context.compacted',
|
|
141
|
+
'session.context.compaction.skipped'
|
|
142
|
+
)
|
|
143
|
+
ORDER BY
|
|
144
|
+
event.workspace_id,
|
|
145
|
+
event.turn_attempt_id,
|
|
146
|
+
event.sequence DESC,
|
|
147
|
+
event.id DESC
|
|
148
|
+
)
|
|
149
|
+
INSERT INTO opengeni_private.context_compaction_pending_observations (
|
|
150
|
+
workspace_id,
|
|
151
|
+
attempt_id,
|
|
152
|
+
started_at
|
|
153
|
+
)
|
|
154
|
+
SELECT
|
|
155
|
+
landmark.workspace_id,
|
|
156
|
+
landmark.turn_attempt_id,
|
|
157
|
+
landmark.occurred_at
|
|
158
|
+
FROM latest_landmark landmark
|
|
159
|
+
JOIN session_turn_attempts attempt
|
|
160
|
+
ON attempt.workspace_id = landmark.workspace_id
|
|
161
|
+
AND attempt.id = landmark.turn_attempt_id
|
|
162
|
+
JOIN session_turns turn
|
|
163
|
+
ON turn.workspace_id = attempt.workspace_id
|
|
164
|
+
AND turn.id = attempt.turn_id
|
|
165
|
+
AND turn.active_attempt_id = attempt.id
|
|
166
|
+
WHERE landmark.type = 'session.context.compaction.started'
|
|
167
|
+
AND landmark.payload ->> 'trigger' = 'auto'
|
|
168
|
+
AND attempt.state IN ('claimed', 'running')
|
|
169
|
+
ON CONFLICT (workspace_id, attempt_id) DO UPDATE
|
|
170
|
+
SET started_at = EXCLUDED.started_at;
|
|
171
|
+
|
|
172
|
+
ALTER TABLE session_turns FORCE ROW LEVEL SECURITY;
|
|
173
|
+
ALTER TABLE session_turn_attempts FORCE ROW LEVEL SECURITY;
|
|
174
|
+
ALTER TABLE session_events FORCE ROW LEVEL SECURITY;
|
|
175
|
+
|
|
176
|
+
CREATE OR REPLACE FUNCTION opengeni_private.context_compaction_pending_summary()
|
|
177
|
+
RETURNS TABLE (pending_count bigint, oldest_started_at timestamp with time zone)
|
|
178
|
+
LANGUAGE sql
|
|
179
|
+
STABLE
|
|
180
|
+
SECURITY DEFINER
|
|
181
|
+
SET search_path = pg_catalog
|
|
182
|
+
AS $context_compaction_pending_summary$
|
|
183
|
+
SELECT
|
|
184
|
+
count(*)::bigint AS pending_count,
|
|
185
|
+
min(pending.started_at) AS oldest_started_at
|
|
186
|
+
FROM opengeni_private.context_compaction_pending_observations pending
|
|
187
|
+
$context_compaction_pending_summary$;
|
|
188
|
+
|
|
189
|
+
REVOKE ALL ON FUNCTION opengeni_private.context_compaction_pending_summary() FROM PUBLIC;
|
|
190
|
+
|
|
191
|
+
DO $context_compaction_observability_grants$
|
|
192
|
+
BEGIN
|
|
193
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
194
|
+
GRANT EXECUTE ON FUNCTION opengeni_private.context_compaction_pending_summary()
|
|
195
|
+
TO opengeni_app;
|
|
196
|
+
END IF;
|
|
197
|
+
END
|
|
198
|
+
$context_compaction_observability_grants$;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Migration 0393: enable Workspace Memory by default and make approval-required
|
|
3
|
+
-- workspace instruction/Skill learning the default when no policy revision has
|
|
4
|
+
-- been activated.
|
|
5
|
+
--
|
|
6
|
+
-- Explicit memory opt-outs and activated learning-policy revisions remain
|
|
7
|
+
-- authoritative. Existing immutable turn and learning snapshots are untouched.
|
|
8
|
+
-- Materializing the Memory default in workspace settings keeps old and new
|
|
9
|
+
-- rolling binaries aligned while the application resolver changes omission to
|
|
10
|
+
-- enabled.
|
|
11
|
+
|
|
12
|
+
SET LOCAL lock_timeout = '5s';
|
|
13
|
+
SET LOCAL statement_timeout = '5min';
|
|
14
|
+
|
|
15
|
+
ALTER TABLE "workspaces"
|
|
16
|
+
ALTER COLUMN "settings" SET DEFAULT '{"memoryEnabled": true}'::jsonb;
|
|
17
|
+
|
|
18
|
+
UPDATE "workspaces"
|
|
19
|
+
SET "settings" = jsonb_set("settings", '{memoryEnabled}', 'true'::jsonb, true)
|
|
20
|
+
WHERE NOT ("settings" ? 'memoryEnabled');
|
|
21
|
+
|
|
22
|
+
-- Historical no-revision snapshots were frozen with workspace_mode = 'off'.
|
|
23
|
+
-- Keep those rows valid while allowing newly accepted attempts to freeze the
|
|
24
|
+
-- approval-required default below.
|
|
25
|
+
ALTER TABLE "workspace_learning_policy_snapshots"
|
|
26
|
+
DROP CONSTRAINT "workspace_learning_policy_snapshots_identity_chk";
|
|
27
|
+
|
|
28
|
+
ALTER TABLE "workspace_learning_policy_snapshots"
|
|
29
|
+
ADD CONSTRAINT "workspace_learning_policy_snapshots_identity_chk" CHECK (
|
|
30
|
+
(
|
|
31
|
+
"revision_id" IS NULL
|
|
32
|
+
AND "revision" IS NULL
|
|
33
|
+
AND "policy_hash" IS NULL
|
|
34
|
+
AND "activation_version" = 0
|
|
35
|
+
AND "activated_at" IS NULL
|
|
36
|
+
AND "workspace_mode" IN ('off', 'suggest')
|
|
37
|
+
AND "source_overrides" = '[]'::jsonb
|
|
38
|
+
)
|
|
39
|
+
OR (
|
|
40
|
+
"revision_id" IS NOT NULL
|
|
41
|
+
AND "revision" > 0
|
|
42
|
+
AND "policy_hash" ~ '^[0-9a-f]{64}$'
|
|
43
|
+
AND "activation_version" > 0
|
|
44
|
+
AND "activated_at" IS NOT NULL
|
|
45
|
+
)
|
|
46
|
+
) NOT VALID;
|
|
47
|
+
|
|
48
|
+
ALTER TABLE "workspace_learning_policy_snapshots"
|
|
49
|
+
VALIDATE CONSTRAINT "workspace_learning_policy_snapshots_identity_chk";
|
|
50
|
+
|
|
51
|
+
CREATE OR REPLACE FUNCTION workspace_learning_policy_canonical_at(
|
|
52
|
+
p_account_id uuid,
|
|
53
|
+
p_workspace_id uuid,
|
|
54
|
+
p_accepted_at timestamptz
|
|
55
|
+
) RETURNS jsonb
|
|
56
|
+
LANGUAGE sql
|
|
57
|
+
STABLE
|
|
58
|
+
AS $$
|
|
59
|
+
SELECT CASE WHEN active."id" IS NULL THEN
|
|
60
|
+
jsonb_build_object(
|
|
61
|
+
'revisionId', NULL,
|
|
62
|
+
'revision', NULL,
|
|
63
|
+
'policyHash', NULL,
|
|
64
|
+
'activationVersion', 0,
|
|
65
|
+
'activatedAt', NULL,
|
|
66
|
+
'workspaceMode', 'suggest',
|
|
67
|
+
'sourceOverrides', '[]'::jsonb
|
|
68
|
+
)
|
|
69
|
+
ELSE
|
|
70
|
+
jsonb_build_object(
|
|
71
|
+
'revisionId', revision."id"::text,
|
|
72
|
+
'revision', revision."revision",
|
|
73
|
+
'policyHash', revision."policy_hash",
|
|
74
|
+
'activationVersion', active."activation_version",
|
|
75
|
+
'activatedAt', to_char(
|
|
76
|
+
active."created_at" AT TIME ZONE 'UTC',
|
|
77
|
+
'YYYY-MM-DD"T"HH24:MI:SS.US"Z"'
|
|
78
|
+
),
|
|
79
|
+
'workspaceMode', revision."workspace_mode",
|
|
80
|
+
'sourceOverrides', revision."source_overrides"
|
|
81
|
+
)
|
|
82
|
+
END
|
|
83
|
+
FROM (SELECT 1) singleton
|
|
84
|
+
LEFT JOIN LATERAL (
|
|
85
|
+
SELECT event.*
|
|
86
|
+
FROM "workspace_learning_policy_activation_events" event
|
|
87
|
+
WHERE event."account_id" = p_account_id
|
|
88
|
+
AND event."workspace_id" = p_workspace_id
|
|
89
|
+
AND event."created_at" <= p_accepted_at
|
|
90
|
+
ORDER BY event."created_at" DESC, event."activation_version" DESC, event."id" DESC
|
|
91
|
+
LIMIT 1
|
|
92
|
+
) active ON true
|
|
93
|
+
LEFT JOIN "workspace_learning_policy_revisions" revision
|
|
94
|
+
ON revision."account_id" = active."account_id"
|
|
95
|
+
AND revision."workspace_id" = active."workspace_id"
|
|
96
|
+
AND revision."id" = active."new_revision_id"
|
|
97
|
+
AND revision."revision" = active."new_revision"
|
|
98
|
+
AND revision."policy_hash" = active."new_policy_hash";
|
|
99
|
+
$$;
|
|
100
|
+
|
|
101
|
+
REVOKE ALL ON FUNCTION workspace_learning_policy_canonical_at(uuid, uuid, timestamptz)
|
|
102
|
+
FROM PUBLIC;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
-- A session-selected Skill is installed and inspectable like any other Skill,
|
|
3
|
+
-- but the worker excludes it from ambient workspace resolution. An explicit
|
|
4
|
+
-- session create copies the immutable artifact onto that one session.
|
|
5
|
+
|
|
6
|
+
ALTER TABLE capability_facets
|
|
7
|
+
DROP CONSTRAINT capability_facets_activation_chk;
|
|
8
|
+
|
|
9
|
+
ALTER TABLE capability_facets
|
|
10
|
+
ADD CONSTRAINT capability_facets_activation_chk CHECK (
|
|
11
|
+
activation_mode IN (
|
|
12
|
+
'platform_available',
|
|
13
|
+
'runtime_baseline',
|
|
14
|
+
'workspace_managed',
|
|
15
|
+
'session_selected'
|
|
16
|
+
)
|
|
17
|
+
) NOT VALID;
|
|
18
|
+
|
|
19
|
+
ALTER TABLE capability_facets
|
|
20
|
+
VALIDATE CONSTRAINT capability_facets_activation_chk;
|