@opengeni/db 3.6.0 → 3.7.4-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.
Files changed (92) hide show
  1. package/dist/automations.d.ts +4 -0
  2. package/dist/canonical-human-identities.js +3 -3
  3. package/dist/{chunk-UGDVSQ6U.js → chunk-3ZMN4EXC.js} +2 -2
  4. package/dist/{chunk-744DFC65.js → chunk-6FIVOJ3V.js} +96 -6
  5. package/dist/chunk-6FIVOJ3V.js.map +1 -0
  6. package/dist/{chunk-UJ2EW3QI.js → chunk-DXJ2WY6W.js} +427 -85
  7. package/dist/chunk-DXJ2WY6W.js.map +1 -0
  8. package/dist/{chunk-CDMMSUWJ.js → chunk-JP6IYGYI.js} +3 -3
  9. package/dist/{chunk-Q5YUGQVK.js → chunk-JS3AWDKZ.js} +3 -3
  10. package/dist/{chunk-G3732M3T.js → chunk-LHKB62GC.js} +2 -2
  11. package/dist/{chunk-2NT476HD.js → chunk-QL4AHBYD.js} +2 -2
  12. package/dist/{chunk-IW6O6G7R.js → chunk-VDXHLVDE.js} +2 -2
  13. package/dist/{chunk-WW7AJ5IC.js → chunk-ZTSJPFDH.js} +5 -7
  14. package/dist/chunk-ZTSJPFDH.js.map +1 -0
  15. package/dist/codex-token-resolver.d.ts +12 -1
  16. package/dist/company-profile-agent-admin.d.ts +4 -2
  17. package/dist/company-profile-agent-policy.d.ts +20 -0
  18. package/dist/company-profile-schema.d.ts +573 -0
  19. package/dist/editable-artifact-durable-export.js +2 -2
  20. package/dist/editable-artifacts.js +3 -3
  21. package/dist/index.d.ts +487 -20
  22. package/dist/index.js +9489 -6041
  23. package/dist/index.js.map +1 -1
  24. package/dist/managed-auth-session-sets.js +3 -3
  25. package/dist/managed-human-provisioning.d.ts +3 -3
  26. package/dist/memory-domain.d.ts +5 -3
  27. package/dist/model-catalog.d.ts +153 -0
  28. package/dist/pr-review.d.ts +9 -0
  29. package/dist/provision-roles.js +1 -1
  30. package/dist/runtime-posture.d.ts +7 -7
  31. package/dist/schema.d.ts +1069 -6
  32. package/dist/schema.js +17 -1
  33. package/dist/session-background-commands.js +3 -3
  34. package/dist/session-control.d.ts +75 -5
  35. package/dist/session-queue-commands.d.ts +19 -0
  36. package/dist/session-tenancy.js +3 -3
  37. package/dist/user-resource-authority.d.ts +8 -0
  38. package/dist/video-generation.js +3 -3
  39. package/dist/xai-subscription.d.ts +8 -0
  40. package/drizzle/0369_local_human_personal_authority.sql +350 -0
  41. package/drizzle/0370_workspace_member_management_scope.sql +98 -0
  42. package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
  43. package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
  44. package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
  45. package/drizzle/0374_session_event_cursors.sql +315 -0
  46. package/drizzle/0375_session_recovery_observability.sql +73 -0
  47. package/drizzle/0376_organization_workspace_inventory.sql +88 -0
  48. package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
  49. package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
  50. package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
  51. package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
  52. package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
  53. package/drizzle/0382_organization_api_key_provenance.sql +91 -0
  54. package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
  55. package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
  56. package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
  57. package/drizzle/0386_local_organization_administration.sql +157 -0
  58. package/drizzle/0387_bound_host_export_session_payloads.sql +165 -0
  59. package/drizzle/0388_sandbox_provider_deadline_interactions.sql +491 -0
  60. package/drizzle/0389_model_catalog_and_gateway_custom_models.sql +241 -0
  61. package/package.json +6 -6
  62. package/src/automations.ts +9 -1
  63. package/src/codex-token-resolver.ts +26 -1
  64. package/src/company-brain-governed-writes.ts +30 -1
  65. package/src/company-profile-agent-admin.ts +68 -1
  66. package/src/company-profile-agent-policy.ts +126 -0
  67. package/src/company-profile-schema.ts +115 -1
  68. package/src/database.ts +3 -5
  69. package/src/index.ts +4473 -570
  70. package/src/insights.ts +21 -7
  71. package/src/managed-human-provisioning.ts +3 -3
  72. package/src/memory-domain.ts +9 -4
  73. package/src/model-catalog.ts +682 -0
  74. package/src/organization-membership-lifecycle.ts +0 -1
  75. package/src/pr-review.ts +19 -0
  76. package/src/provision-roles.ts +83 -4
  77. package/src/runtime-posture.ts +26 -0
  78. package/src/schema.ts +259 -10
  79. package/src/session-control.ts +347 -59
  80. package/src/session-queue-commands.ts +303 -122
  81. package/src/session-tool-call-settlement.ts +34 -7
  82. package/src/user-resource-authority.ts +56 -0
  83. package/src/xai-subscription.ts +66 -14
  84. package/dist/chunk-744DFC65.js.map +0 -1
  85. package/dist/chunk-UJ2EW3QI.js.map +0 -1
  86. package/dist/chunk-WW7AJ5IC.js.map +0 -1
  87. /package/dist/{chunk-UGDVSQ6U.js.map → chunk-3ZMN4EXC.js.map} +0 -0
  88. /package/dist/{chunk-CDMMSUWJ.js.map → chunk-JP6IYGYI.js.map} +0 -0
  89. /package/dist/{chunk-Q5YUGQVK.js.map → chunk-JS3AWDKZ.js.map} +0 -0
  90. /package/dist/{chunk-G3732M3T.js.map → chunk-LHKB62GC.js.map} +0 -0
  91. /package/dist/{chunk-2NT476HD.js.map → chunk-QL4AHBYD.js.map} +0 -0
  92. /package/dist/{chunk-IW6O6G7R.js.map → chunk-VDXHLVDE.js.map} +0 -0
@@ -0,0 +1,491 @@
1
+ -- deployment-mode: rolling
2
+ -- Active BrowserSession/ComputerSession placement deliberately survives UI and
3
+ -- API-owner disappearance. A finite-lifetime Modal identity is the exception:
4
+ -- once its hard provider deadline passes, retaining an interaction holder can
5
+ -- no longer preserve a usable controller and must not pin rotation forever.
6
+ SET LOCAL lock_timeout = '5s';
7
+ SET LOCAL statement_timeout = '10min';
8
+
9
+ -- The interaction reaper became an owner-only global mutator before the
10
+ -- session-tenancy cutover, but 0345 added its exact capability/lock policy only
11
+ -- to the lease tables. A NOSUPERUSER migration owner otherwise sees no
12
+ -- BrowserSession/ComputerSession/operation rows under FORCE RLS and treats
13
+ -- every interaction holder as an orphan. Admit the same already-fenced owner
14
+ -- only on the four interaction tables the reaper reads or updates.
15
+ DO $interaction_reaper_owner_policies$
16
+ DECLARE
17
+ target_schema text := pg_catalog.current_schema();
18
+ target_schema_oid oid := pg_catalog.current_schema()::pg_catalog.regnamespace;
19
+ migration_owner text := current_user;
20
+ table_name text;
21
+ BEGIN
22
+ FOREACH table_name IN ARRAY ARRAY[
23
+ 'browser_sessions',
24
+ 'computer_sessions',
25
+ 'interaction_operations',
26
+ 'workspace_interaction_revisions'
27
+ ] LOOP
28
+ EXECUTE pg_catalog.format(
29
+ 'CREATE POLICY session_tenancy_fenced_owner_interaction ON %I.%I '
30
+ || 'FOR ALL USING ('
31
+ || '%I.session_tenancy_fence_owner_policy_active('
32
+ || 'current_user, %L, %s::oid, workspace_id, false)) '
33
+ || 'WITH CHECK ('
34
+ || '%I.session_tenancy_fence_owner_policy_active('
35
+ || 'current_user, %L, %s::oid, workspace_id, false))',
36
+ target_schema,
37
+ table_name,
38
+ target_schema,
39
+ migration_owner,
40
+ target_schema_oid,
41
+ target_schema,
42
+ migration_owner,
43
+ target_schema_oid
44
+ );
45
+ END LOOP;
46
+ END
47
+ $interaction_reaper_owner_policies$;
48
+
49
+ DO $deadline_interaction_reaper$
50
+ DECLARE
51
+ data_schema text := current_schema();
52
+ definition text;
53
+ patched text;
54
+ declaration_anchor constant text :=
55
+ E' affected_lease_ids uuid[] := ARRAY[]::uuid[];\n'
56
+ || E' settled_count integer := 0;';
57
+ entry_anchor constant text :=
58
+ E' fenced_access_capability_id :=\n'
59
+ || E' opengeni_private.open_session_tenancy_fenced_access(\n'
60
+ || E' session_tenancy_fence_target_schema()\n'
61
+ || E' );';
62
+ settled_anchor constant text :=
63
+ E' GET DIAGNOSTICS settled_count = ROW_COUNT;';
64
+ revision_anchor constant text :=
65
+ E' WHERE revision.workspace_id = ANY(changed_workspace_ids || orphan_workspace_ids);';
66
+ deadline_block text;
67
+ occurrences integer;
68
+ BEGIN
69
+ SELECT pg_catalog.pg_get_functiondef(
70
+ 'opengeni_private.reap_stale_interaction_transitions(bigint)'::regprocedure
71
+ ) INTO definition;
72
+
73
+ IF definition IS NULL
74
+ OR pg_catalog.strpos(definition, 'error_code = ''outcome_unknown''') = 0
75
+ OR pg_catalog.strpos(
76
+ definition,
77
+ 'acquire_sandbox_reaper_session_tenancy_fences'
78
+ ) = 0
79
+ OR pg_catalog.strpos(definition, 'open_session_tenancy_fenced_access') = 0
80
+ OR pg_catalog.strpos(definition, 'close_session_tenancy_fenced_access') = 0
81
+ THEN
82
+ RAISE EXCEPTION '0388 interaction reaper prerequisite definition drift'
83
+ USING ERRCODE = '55000';
84
+ END IF;
85
+
86
+ IF pg_catalog.strpos(definition, 'deadline_lease_ids') > 0
87
+ OR pg_catalog.strpos(definition, 'provider_deadline_rotation') > 0
88
+ THEN
89
+ RAISE EXCEPTION '0388 interaction reaper deadline patch already present'
90
+ USING ERRCODE = '55000';
91
+ END IF;
92
+
93
+ occurrences := (
94
+ pg_catalog.length(definition)
95
+ - pg_catalog.length(pg_catalog.replace(definition, declaration_anchor, ''))
96
+ ) / pg_catalog.length(declaration_anchor);
97
+ IF occurrences <> 1 THEN
98
+ RAISE EXCEPTION '0388 interaction reaper declaration anchor drift'
99
+ USING ERRCODE = '55000';
100
+ END IF;
101
+ patched := pg_catalog.replace(
102
+ definition,
103
+ declaration_anchor,
104
+ E' affected_lease_ids uuid[] := ARRAY[]::uuid[];\n'
105
+ || E' deadline_lease_ids uuid[] := ARRAY[]::uuid[];\n'
106
+ || E' deadline_holder_ids uuid[] := ARRAY[]::uuid[];\n'
107
+ || E' deadline_browser_ids uuid[] := ARRAY[]::uuid[];\n'
108
+ || E' deadline_computer_ids uuid[] := ARRAY[]::uuid[];\n'
109
+ || E' deadline_workspace_ids uuid[] := ARRAY[]::uuid[];\n'
110
+ || E' deadline_settled_count integer := 0;\n'
111
+ || E' settled_count integer := 0;'
112
+ );
113
+
114
+ deadline_block := pg_catalog.format($block$
115
+
116
+ -- Active interaction placement has no timestamp expiry: a human may
117
+ -- legitimately leave it active for days. A requested Modal rotation
118
+ -- whose provider deadline is already due is different. The controller
119
+ -- cannot outlive that identity, so close only that exact holder/resource
120
+ -- population in a bounded batch. The enclosing function has already
121
+ -- acquired every affected workspace tenancy fence and owner-only access.
122
+ SELECT coalesce(
123
+ pg_catalog.array_agg(candidate.id),
124
+ ARRAY[]::uuid[]
125
+ )
126
+ INTO deadline_lease_ids
127
+ FROM (
128
+ SELECT lease.id
129
+ FROM %1$I.sandbox_leases lease
130
+ WHERE lease.backend = 'modal'
131
+ AND lease.liveness IN ('warming', 'warm')
132
+ AND lease.rotation_requested_at IS NOT NULL
133
+ AND lease.provider_deadline_at IS NOT NULL
134
+ AND lease.provider_deadline_at <= pg_catalog.now()
135
+ ORDER BY lease.provider_deadline_at, lease.id
136
+ LIMIT 500
137
+ FOR UPDATE OF lease SKIP LOCKED
138
+ ) candidate;
139
+
140
+ -- Lease before holder is the canonical sandbox ownership lock order.
141
+ -- A large shared lease is drained over multiple sweeps instead of making
142
+ -- one global reaper transaction unbounded.
143
+ SELECT coalesce(
144
+ pg_catalog.array_agg(candidate.id),
145
+ ARRAY[]::uuid[]
146
+ )
147
+ INTO deadline_holder_ids
148
+ FROM (
149
+ SELECT holder.id
150
+ FROM %1$I.sandbox_lease_holders holder
151
+ WHERE holder.lease_id = ANY(deadline_lease_ids)
152
+ AND holder.kind = 'interaction'
153
+ ORDER BY holder.id
154
+ LIMIT 500
155
+ FOR UPDATE OF holder SKIP LOCKED
156
+ ) candidate;
157
+
158
+ SELECT
159
+ coalesce(
160
+ pg_catalog.array_agg(DISTINCT browser.id)
161
+ FILTER (WHERE browser.id IS NOT NULL),
162
+ ARRAY[]::uuid[]
163
+ ),
164
+ coalesce(
165
+ pg_catalog.array_agg(DISTINCT computer.id)
166
+ FILTER (WHERE computer.id IS NOT NULL),
167
+ ARRAY[]::uuid[]
168
+ ),
169
+ coalesce(
170
+ pg_catalog.array_agg(DISTINCT holder.workspace_id),
171
+ ARRAY[]::uuid[]
172
+ )
173
+ INTO deadline_browser_ids, deadline_computer_ids, deadline_workspace_ids
174
+ FROM %1$I.sandbox_lease_holders holder
175
+ JOIN %1$I.sandbox_leases lease ON lease.id = holder.lease_id
176
+ LEFT JOIN %1$I.browser_sessions browser
177
+ ON holder.holder_id = ('browser-session:' || browser.id::text)
178
+ AND holder.account_id = browser.account_id
179
+ AND holder.workspace_id = browser.workspace_id
180
+ AND browser.controller_host_sandbox_group_id = lease.sandbox_group_id
181
+ LEFT JOIN %1$I.computer_sessions computer
182
+ ON holder.holder_id = ('computer-session:' || computer.id::text)
183
+ AND holder.account_id = computer.account_id
184
+ AND holder.workspace_id = computer.workspace_id
185
+ AND computer.sandbox_group_id = lease.sandbox_group_id
186
+ WHERE holder.id = ANY(deadline_holder_ids);
187
+
188
+ -- Match the ordinary lifecycle lock order for rows the controller API
189
+ -- also touches: operation before BrowserSession/ComputerSession.
190
+ PERFORM operation.operation_id
191
+ FROM %1$I.interaction_operations operation
192
+ WHERE (
193
+ (
194
+ operation.resource_kind = 'browser_session'
195
+ AND operation.resource_id = ANY(deadline_browser_ids)
196
+ ) OR (
197
+ operation.resource_kind = 'computer_session'
198
+ AND operation.resource_id = ANY(deadline_computer_ids)
199
+ )
200
+ )
201
+ AND operation.state IN ('prepared', 'dispatched')
202
+ ORDER BY operation.operation_id
203
+ FOR UPDATE OF operation;
204
+
205
+ PERFORM browser.id
206
+ FROM %1$I.browser_sessions browser
207
+ WHERE browser.id = ANY(deadline_browser_ids)
208
+ ORDER BY browser.id
209
+ FOR UPDATE OF browser;
210
+
211
+ PERFORM computer.id
212
+ FROM %1$I.computer_sessions computer
213
+ WHERE computer.id = ANY(deadline_computer_ids)
214
+ ORDER BY computer.id
215
+ FOR UPDATE OF computer;
216
+
217
+ -- Prepared operations have no provider side effect and fail
218
+ -- deterministically. Dispatched operations retain honest uncertainty.
219
+ UPDATE %1$I.interaction_operations operation
220
+ SET state = CASE
221
+ WHEN operation.state = 'dispatched' THEN 'outcome_unknown'
222
+ ELSE 'failed'
223
+ END,
224
+ error_code = CASE
225
+ WHEN operation.state = 'dispatched' THEN 'outcome_unknown'
226
+ ELSE 'controller_lost'
227
+ END,
228
+ error_message = 'Interaction controller reached its sandbox provider deadline',
229
+ error_retryable = false,
230
+ error_details = pg_catalog.jsonb_build_object(
231
+ 'reason', 'provider_deadline_rotation'
232
+ ),
233
+ settled_at = pg_catalog.now(),
234
+ updated_at = pg_catalog.now()
235
+ WHERE (
236
+ (
237
+ operation.resource_kind = 'browser_session'
238
+ AND operation.resource_id = ANY(deadline_browser_ids)
239
+ ) OR (
240
+ operation.resource_kind = 'computer_session'
241
+ AND operation.resource_id = ANY(deadline_computer_ids)
242
+ )
243
+ )
244
+ AND operation.state IN ('prepared', 'dispatched');
245
+ GET DIAGNOSTICS deadline_settled_count = ROW_COUNT;
246
+
247
+ -- Preserve the exact controller binding for cleanup/audit. The ordinary
248
+ -- orphan phase below removes holders for these now-terminal resources;
249
+ -- reap_sandbox_leases() then recomputes refcounts and returns the exact
250
+ -- drainable box in this same outer transaction.
251
+ UPDATE %1$I.browser_sessions browser
252
+ SET lifecycle = 'lost',
253
+ failure_code = 'provider_deadline_rotation',
254
+ updated_at = pg_catalog.now()
255
+ WHERE browser.id = ANY(deadline_browser_ids)
256
+ AND browser.lifecycle IN (
257
+ 'starting', 'active', 'suspending', 'restoring', 'ending'
258
+ )
259
+ AND EXISTS (
260
+ SELECT 1
261
+ FROM %1$I.sandbox_lease_holders holder
262
+ JOIN %1$I.sandbox_leases lease ON lease.id = holder.lease_id
263
+ WHERE holder.id = ANY(deadline_holder_ids)
264
+ AND holder.holder_id = ('browser-session:' || browser.id::text)
265
+ AND holder.account_id = browser.account_id
266
+ AND holder.workspace_id = browser.workspace_id
267
+ AND browser.controller_host_sandbox_group_id = lease.sandbox_group_id
268
+ );
269
+
270
+ UPDATE %1$I.computer_sessions computer
271
+ SET lifecycle = 'lost',
272
+ failure_code = 'provider_deadline_rotation',
273
+ updated_at = pg_catalog.now()
274
+ WHERE computer.id = ANY(deadline_computer_ids)
275
+ AND computer.lifecycle IN (
276
+ 'starting', 'active', 'suspending', 'restoring', 'ending'
277
+ )
278
+ AND EXISTS (
279
+ SELECT 1
280
+ FROM %1$I.sandbox_lease_holders holder
281
+ JOIN %1$I.sandbox_leases lease ON lease.id = holder.lease_id
282
+ WHERE holder.id = ANY(deadline_holder_ids)
283
+ AND holder.holder_id = ('computer-session:' || computer.id::text)
284
+ AND holder.account_id = computer.account_id
285
+ AND holder.workspace_id = computer.workspace_id
286
+ AND computer.sandbox_group_id = lease.sandbox_group_id
287
+ );
288
+ $block$, data_schema);
289
+
290
+ occurrences := (
291
+ pg_catalog.length(patched)
292
+ - pg_catalog.length(pg_catalog.replace(patched, entry_anchor, ''))
293
+ ) / pg_catalog.length(entry_anchor);
294
+ IF occurrences <> 1 THEN
295
+ RAISE EXCEPTION '0388 interaction reaper entry anchor drift'
296
+ USING ERRCODE = '55000';
297
+ END IF;
298
+ patched := pg_catalog.replace(
299
+ patched,
300
+ entry_anchor,
301
+ entry_anchor || deadline_block
302
+ );
303
+
304
+ occurrences := (
305
+ pg_catalog.length(patched)
306
+ - pg_catalog.length(pg_catalog.replace(patched, settled_anchor, ''))
307
+ ) / pg_catalog.length(settled_anchor);
308
+ IF occurrences <> 1 THEN
309
+ RAISE EXCEPTION '0388 interaction reaper settlement anchor drift'
310
+ USING ERRCODE = '55000';
311
+ END IF;
312
+ patched := pg_catalog.replace(
313
+ patched,
314
+ settled_anchor,
315
+ settled_anchor
316
+ || E'\n settled_count := settled_count + deadline_settled_count;'
317
+ );
318
+
319
+ occurrences := (
320
+ pg_catalog.length(patched)
321
+ - pg_catalog.length(pg_catalog.replace(patched, revision_anchor, ''))
322
+ ) / pg_catalog.length(revision_anchor);
323
+ IF occurrences <> 1 THEN
324
+ RAISE EXCEPTION '0388 interaction reaper revision anchor drift'
325
+ USING ERRCODE = '55000';
326
+ END IF;
327
+ patched := pg_catalog.replace(
328
+ patched,
329
+ revision_anchor,
330
+ E' WHERE revision.workspace_id = ANY(\n'
331
+ || E' changed_workspace_ids || deadline_workspace_ids || orphan_workspace_ids\n'
332
+ || E' );'
333
+ );
334
+
335
+ IF pg_catalog.strpos(patched, 'deadline_lease_ids uuid[]') = 0
336
+ OR pg_catalog.strpos(patched, 'LIMIT 500') = 0
337
+ OR pg_catalog.strpos(patched, 'provider_deadline_at <= pg_catalog.now()') = 0
338
+ OR pg_catalog.strpos(patched, 'provider_deadline_rotation') = 0
339
+ OR pg_catalog.strpos(patched, 'settled_count + deadline_settled_count') = 0
340
+ THEN
341
+ RAISE EXCEPTION '0388 interaction reaper deadline patch failed'
342
+ USING ERRCODE = '55000';
343
+ END IF;
344
+
345
+ EXECUTE patched;
346
+ END
347
+ $deadline_interaction_reaper$;
348
+
349
+ DO $interaction_backlog_metric$
350
+ DECLARE data_schema text := current_schema();
351
+ BEGIN
352
+ IF pg_catalog.to_regprocedure(
353
+ 'opengeni_private.sandbox_rotation_backlog()'
354
+ ) IS NULL THEN
355
+ RAISE EXCEPTION '0388 sandbox rotation backlog prerequisite missing'
356
+ USING ERRCODE = '55000';
357
+ END IF;
358
+
359
+ EXECUTE pg_catalog.format($create$
360
+ CREATE OR REPLACE FUNCTION opengeni_private.sandbox_rotation_backlog()
361
+ RETURNS TABLE (
362
+ requested bigint,
363
+ overdue bigint,
364
+ turn_blocked bigint,
365
+ direct_blocked bigint,
366
+ process_blocked bigint
367
+ )
368
+ LANGUAGE plpgsql
369
+ SECURITY DEFINER
370
+ SET search_path = pg_catalog
371
+ AS $function$
372
+ DECLARE inventory_capability_id uuid;
373
+ BEGIN
374
+ inventory_capability_id :=
375
+ opengeni_private.open_session_tenancy_fence_inventory(
376
+ %1$I.session_tenancy_fence_target_schema()
377
+ );
378
+ RETURN QUERY
379
+ SELECT
380
+ pg_catalog.count(*) FILTER (
381
+ WHERE lease.rotation_requested_at IS NOT NULL
382
+ )::bigint,
383
+ pg_catalog.count(*) FILTER (
384
+ WHERE lease.rotation_requested_at IS NOT NULL
385
+ AND lease.provider_deadline_at <= pg_catalog.now()
386
+ )::bigint,
387
+ pg_catalog.count(*) FILTER (
388
+ WHERE lease.rotation_requested_at IS NOT NULL
389
+ AND EXISTS (
390
+ SELECT 1
391
+ FROM %1$I.sandbox_lease_holders holder
392
+ WHERE holder.lease_id = lease.id
393
+ AND holder.kind = 'turn'
394
+ )
395
+ )::bigint,
396
+ pg_catalog.count(*) FILTER (
397
+ WHERE lease.rotation_requested_at IS NOT NULL
398
+ AND EXISTS (
399
+ SELECT 1
400
+ FROM %1$I.sandbox_lease_holders holder
401
+ WHERE holder.lease_id = lease.id
402
+ AND holder.kind = 'direct'
403
+ )
404
+ )::bigint,
405
+ pg_catalog.count(*) FILTER (
406
+ WHERE lease.rotation_requested_at IS NOT NULL
407
+ AND EXISTS (
408
+ SELECT 1
409
+ FROM %1$I.sandbox_lease_holders holder
410
+ WHERE holder.lease_id = lease.id
411
+ AND holder.kind = 'process'
412
+ )
413
+ )::bigint
414
+ FROM %1$I.sandbox_leases lease
415
+ WHERE lease.backend = 'modal'
416
+ AND lease.liveness IN ('warming', 'warm', 'draining');
417
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(
418
+ inventory_capability_id
419
+ );
420
+ EXCEPTION WHEN OTHERS THEN
421
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(
422
+ inventory_capability_id
423
+ );
424
+ RAISE;
425
+ END
426
+ $function$;
427
+
428
+ CREATE OR REPLACE FUNCTION
429
+ opengeni_private.sandbox_rotation_interaction_blocked()
430
+ RETURNS bigint
431
+ LANGUAGE plpgsql
432
+ SECURITY DEFINER
433
+ SET search_path = pg_catalog
434
+ AS $function$
435
+ DECLARE
436
+ inventory_capability_id uuid;
437
+ blocked_count bigint;
438
+ BEGIN
439
+ inventory_capability_id :=
440
+ opengeni_private.open_session_tenancy_fence_inventory(
441
+ %1$I.session_tenancy_fence_target_schema()
442
+ );
443
+ SELECT pg_catalog.count(*)::bigint
444
+ INTO blocked_count
445
+ FROM %1$I.sandbox_leases lease
446
+ WHERE lease.backend = 'modal'
447
+ AND lease.liveness IN ('warming', 'warm', 'draining')
448
+ AND lease.rotation_requested_at IS NOT NULL
449
+ AND EXISTS (
450
+ SELECT 1
451
+ FROM %1$I.sandbox_lease_holders holder
452
+ WHERE holder.lease_id = lease.id
453
+ AND holder.kind = 'interaction'
454
+ );
455
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(
456
+ inventory_capability_id
457
+ );
458
+ RETURN blocked_count;
459
+ EXCEPTION WHEN OTHERS THEN
460
+ PERFORM opengeni_private.close_session_tenancy_fence_inventory(
461
+ inventory_capability_id
462
+ );
463
+ RAISE;
464
+ END
465
+ $function$;
466
+ $create$, data_schema);
467
+ END
468
+ $interaction_backlog_metric$;
469
+
470
+ REVOKE ALL ON FUNCTION
471
+ opengeni_private.sandbox_rotation_backlog()
472
+ FROM PUBLIC;
473
+ REVOKE ALL ON FUNCTION
474
+ opengeni_private.sandbox_rotation_interaction_blocked()
475
+ FROM PUBLIC;
476
+
477
+ DO $interaction_backlog_grant$
478
+ BEGIN
479
+ IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
480
+ GRANT EXECUTE ON FUNCTION
481
+ opengeni_private.sandbox_rotation_backlog()
482
+ TO opengeni_app;
483
+ GRANT EXECUTE ON FUNCTION
484
+ opengeni_private.sandbox_rotation_interaction_blocked()
485
+ TO opengeni_app;
486
+ END IF;
487
+ END
488
+ $interaction_backlog_grant$;
489
+
490
+ RESET statement_timeout;
491
+ RESET lock_timeout;