@opengeni/db 3.6.0 → 3.7.4
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/canonical-human-identities.js +3 -3
- package/dist/{chunk-744DFC65.js → chunk-4NAR7FBA.js} +92 -6
- package/dist/chunk-4NAR7FBA.js.map +1 -0
- package/dist/{chunk-IW6O6G7R.js → chunk-5NNCGFQY.js} +2 -2
- package/dist/{chunk-G3732M3T.js → chunk-DZCYW2WT.js} +2 -2
- package/dist/{chunk-WW7AJ5IC.js → chunk-F6PBS6WE.js} +5 -7
- package/dist/chunk-F6PBS6WE.js.map +1 -0
- package/dist/{chunk-UJ2EW3QI.js → chunk-O56DM5GZ.js} +340 -85
- package/dist/chunk-O56DM5GZ.js.map +1 -0
- package/dist/{chunk-CDMMSUWJ.js → chunk-S3TDDCS2.js} +3 -3
- package/dist/{chunk-Q5YUGQVK.js → chunk-SZAWDXQC.js} +3 -3
- package/dist/{chunk-UGDVSQ6U.js → chunk-U4WPPEBH.js} +2 -2
- package/dist/{chunk-2NT476HD.js → chunk-US4IS6IV.js} +2 -2
- package/dist/codex-token-resolver.d.ts +12 -1
- package/dist/company-profile-agent-admin.d.ts +4 -2
- package/dist/company-profile-agent-policy.d.ts +20 -0
- package/dist/company-profile-schema.d.ts +573 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +382 -18
- package/dist/index.js +4513 -2065
- package/dist/index.js.map +1 -1
- package/dist/managed-auth-session-sets.js +3 -3
- package/dist/managed-human-provisioning.d.ts +3 -3
- package/dist/memory-domain.d.ts +5 -3
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +5 -5
- package/dist/schema.d.ts +725 -4
- package/dist/schema.js +13 -1
- package/dist/session-background-commands.js +3 -3
- package/dist/session-control.d.ts +40 -5
- package/dist/session-queue-commands.d.ts +2 -0
- package/dist/session-tenancy.js +3 -3
- package/dist/user-resource-authority.d.ts +8 -0
- package/dist/video-generation.js +3 -3
- package/drizzle/0369_local_human_personal_authority.sql +350 -0
- package/drizzle/0370_workspace_member_management_scope.sql +98 -0
- package/drizzle/0371_workspace_member_candidate_inventory.sql +128 -0
- package/drizzle/0372_ordered_variable_set_runtime_authority.sql +287 -0
- package/drizzle/0373_sandbox_shared_preparation.sql +59 -0
- package/drizzle/0374_session_event_cursors.sql +315 -0
- package/drizzle/0375_session_recovery_observability.sql +73 -0
- package/drizzle/0376_organization_workspace_inventory.sql +88 -0
- package/drizzle/0377_scoped_rig_health_projection.sql +80 -0
- package/drizzle/0378_scoped_rig_health_audit_timestamp.sql +77 -0
- package/drizzle/0379_session_event_raw_lane_activation.sql +518 -0
- package/drizzle/0380_autonomous_company_profile_agent_policy.sql +829 -0
- package/drizzle/0381_organization_codex_subscription_inheritance.sql +720 -0
- package/drizzle/0382_organization_api_key_provenance.sql +91 -0
- package/drizzle/0383_codex_cooldown_reconciliation.sql +51 -0
- package/drizzle/0384_codex_cooldown_revision_guard_privileges.sql +6 -0
- package/drizzle/0385_connected_machine_legacy_tilde_workdirs.sql +25 -0
- package/drizzle/0386_local_organization_administration.sql +157 -0
- package/package.json +5 -5
- package/src/codex-token-resolver.ts +26 -1
- package/src/company-brain-governed-writes.ts +30 -1
- package/src/company-profile-agent-admin.ts +68 -1
- package/src/company-profile-agent-policy.ts +126 -0
- package/src/company-profile-schema.ts +115 -1
- package/src/database.ts +3 -5
- package/src/index.ts +3626 -456
- package/src/managed-human-provisioning.ts +3 -3
- package/src/memory-domain.ts +9 -4
- package/src/organization-membership-lifecycle.ts +0 -1
- package/src/provision-roles.ts +83 -4
- package/src/runtime-posture.ts +22 -0
- package/src/schema.ts +161 -8
- package/src/session-control.ts +177 -59
- package/src/session-queue-commands.ts +146 -40
- package/src/session-tool-call-settlement.ts +34 -7
- package/src/user-resource-authority.ts +56 -0
- package/dist/chunk-744DFC65.js.map +0 -1
- package/dist/chunk-UJ2EW3QI.js.map +0 -1
- package/dist/chunk-WW7AJ5IC.js.map +0 -1
- /package/dist/{chunk-IW6O6G7R.js.map → chunk-5NNCGFQY.js.map} +0 -0
- /package/dist/{chunk-G3732M3T.js.map → chunk-DZCYW2WT.js.map} +0 -0
- /package/dist/{chunk-CDMMSUWJ.js.map → chunk-S3TDDCS2.js.map} +0 -0
- /package/dist/{chunk-Q5YUGQVK.js.map → chunk-SZAWDXQC.js.map} +0 -0
- /package/dist/{chunk-UGDVSQ6U.js.map → chunk-U4WPPEBH.js.map} +0 -0
- /package/dist/{chunk-2NT476HD.js.map → chunk-US4IS6IV.js.map} +0 -0
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Add an organization-owner policy for agent-authored company-profile changes.
|
|
3
|
+
-- Existing organizations default to `suggest`, preserving the exact bound
|
|
4
|
+
-- human-confirmation path. `automatic` replaces only that per-change prompt:
|
|
5
|
+
-- the live turn must still be initiated by the active organization owner, and
|
|
6
|
+
-- activation still uses the company-profile CAS lifecycle. `off` creates no
|
|
7
|
+
-- new proposal. The policy is organization-scoped and cannot be changed by a
|
|
8
|
+
-- workspace administrator.
|
|
9
|
+
--
|
|
10
|
+
-- Rolling compatibility: the v1 proposal function remains review-only for old
|
|
11
|
+
-- API processes, but now records the frozen policy and refuses `off`. New API
|
|
12
|
+
-- processes call v2, which consumes an `automatic` snapshot and records a
|
|
13
|
+
-- distinct automatic-activation receipt. Thus old processes can be stricter
|
|
14
|
+
-- during rollout but can never gain autonomous authority.
|
|
15
|
+
|
|
16
|
+
SET LOCAL lock_timeout = '5s';
|
|
17
|
+
SET LOCAL statement_timeout = '10min';
|
|
18
|
+
|
|
19
|
+
CREATE TABLE organization_company_profile_agent_policies (
|
|
20
|
+
account_id uuid PRIMARY KEY REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
21
|
+
mode text NOT NULL DEFAULT 'suggest',
|
|
22
|
+
version bigint NOT NULL DEFAULT 0,
|
|
23
|
+
updated_by_membership_id uuid,
|
|
24
|
+
updated_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
25
|
+
CONSTRAINT organization_company_profile_agent_policies_membership_fk
|
|
26
|
+
FOREIGN KEY (updated_by_membership_id, account_id)
|
|
27
|
+
REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
28
|
+
CONSTRAINT organization_company_profile_agent_policies_mode_check
|
|
29
|
+
CHECK (mode IN ('off', 'suggest', 'automatic')),
|
|
30
|
+
CONSTRAINT organization_company_profile_agent_policies_version_check CHECK (version >= 0)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
CREATE TABLE organization_company_profile_agent_policy_events (
|
|
34
|
+
id uuid PRIMARY KEY,
|
|
35
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
36
|
+
actor_membership_id uuid NOT NULL,
|
|
37
|
+
requested_mode text NOT NULL,
|
|
38
|
+
expected_version bigint NOT NULL,
|
|
39
|
+
result_mode text NOT NULL,
|
|
40
|
+
result_version bigint NOT NULL,
|
|
41
|
+
result_updated_at timestamptz NOT NULL,
|
|
42
|
+
changed boolean NOT NULL,
|
|
43
|
+
CONSTRAINT organization_company_profile_agent_policy_events_membership_fk
|
|
44
|
+
FOREIGN KEY (actor_membership_id, account_id)
|
|
45
|
+
REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
46
|
+
CONSTRAINT organization_company_profile_agent_policy_events_mode_check CHECK (
|
|
47
|
+
requested_mode IN ('off', 'suggest', 'automatic')
|
|
48
|
+
AND result_mode IN ('off', 'suggest', 'automatic')
|
|
49
|
+
),
|
|
50
|
+
CONSTRAINT organization_company_profile_agent_policy_events_version_check CHECK (
|
|
51
|
+
expected_version >= 0 AND result_version > 0
|
|
52
|
+
)
|
|
53
|
+
);
|
|
54
|
+
CREATE INDEX organization_company_profile_agent_policy_events_account_idx
|
|
55
|
+
ON organization_company_profile_agent_policy_events (account_id, result_version);
|
|
56
|
+
|
|
57
|
+
ALTER TABLE organization_company_profile_agent_policies ENABLE ROW LEVEL SECURITY;
|
|
58
|
+
ALTER TABLE organization_company_profile_agent_policies FORCE ROW LEVEL SECURITY;
|
|
59
|
+
ALTER TABLE organization_company_profile_agent_policy_events ENABLE ROW LEVEL SECURITY;
|
|
60
|
+
ALTER TABLE organization_company_profile_agent_policy_events FORCE ROW LEVEL SECURITY;
|
|
61
|
+
REVOKE ALL ON TABLE organization_company_profile_agent_policies FROM PUBLIC;
|
|
62
|
+
REVOKE ALL ON TABLE organization_company_profile_agent_policy_events FROM PUBLIC;
|
|
63
|
+
CREATE POLICY organization_company_profile_agent_policy_lifecycle
|
|
64
|
+
ON organization_company_profile_agent_policies
|
|
65
|
+
USING (current_setting('opengeni.company_profile_agent_policy_lifecycle', true)
|
|
66
|
+
= 'company_profile_agent_policy')
|
|
67
|
+
WITH CHECK (current_setting('opengeni.company_profile_agent_policy_lifecycle', true)
|
|
68
|
+
= 'company_profile_agent_policy');
|
|
69
|
+
CREATE POLICY organization_company_profile_agent_policy_lifecycle
|
|
70
|
+
ON organization_company_profile_agent_policy_events
|
|
71
|
+
USING (current_setting('opengeni.company_profile_agent_policy_lifecycle', true)
|
|
72
|
+
= 'company_profile_agent_policy')
|
|
73
|
+
WITH CHECK (current_setting('opengeni.company_profile_agent_policy_lifecycle', true)
|
|
74
|
+
= 'company_profile_agent_policy');
|
|
75
|
+
CREATE FUNCTION initialize_company_profile_agent_policy()
|
|
76
|
+
RETURNS trigger
|
|
77
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
78
|
+
SET search_path FROM CURRENT
|
|
79
|
+
AS $body$
|
|
80
|
+
BEGIN
|
|
81
|
+
PERFORM pg_catalog.set_config(
|
|
82
|
+
'opengeni.company_profile_agent_policy_lifecycle',
|
|
83
|
+
'company_profile_agent_policy', true
|
|
84
|
+
);
|
|
85
|
+
INSERT INTO organization_company_profile_agent_policies (
|
|
86
|
+
account_id, mode, version, updated_by_membership_id, updated_at
|
|
87
|
+
) VALUES (NEW.id, 'suggest', 0, NULL, NEW.created_at)
|
|
88
|
+
ON CONFLICT (account_id) DO NOTHING;
|
|
89
|
+
RETURN NEW;
|
|
90
|
+
END
|
|
91
|
+
$body$;
|
|
92
|
+
REVOKE ALL ON FUNCTION initialize_company_profile_agent_policy() FROM PUBLIC;
|
|
93
|
+
CREATE TRIGGER managed_accounts_initialize_company_profile_agent_policy
|
|
94
|
+
AFTER INSERT ON managed_accounts
|
|
95
|
+
FOR EACH ROW EXECUTE FUNCTION initialize_company_profile_agent_policy();
|
|
96
|
+
|
|
97
|
+
CREATE FUNCTION company_profile_agent_policy_events_immutable()
|
|
98
|
+
RETURNS trigger
|
|
99
|
+
LANGUAGE plpgsql
|
|
100
|
+
AS $body$
|
|
101
|
+
BEGIN
|
|
102
|
+
IF TG_OP = 'DELETE'
|
|
103
|
+
AND pg_trigger_depth() > 1
|
|
104
|
+
AND NOT EXISTS (SELECT 1 FROM managed_accounts account WHERE account.id = OLD.account_id)
|
|
105
|
+
THEN
|
|
106
|
+
RETURN OLD;
|
|
107
|
+
END IF;
|
|
108
|
+
RAISE EXCEPTION 'company-profile agent policy events are immutable'
|
|
109
|
+
USING ERRCODE = '55000';
|
|
110
|
+
END
|
|
111
|
+
$body$;
|
|
112
|
+
CREATE TRIGGER organization_company_profile_agent_policy_events_immutable
|
|
113
|
+
BEFORE UPDATE OR DELETE ON organization_company_profile_agent_policy_events
|
|
114
|
+
FOR EACH ROW EXECUTE FUNCTION company_profile_agent_policy_events_immutable();
|
|
115
|
+
|
|
116
|
+
SELECT pg_catalog.set_config(
|
|
117
|
+
'opengeni.company_profile_agent_policy_lifecycle',
|
|
118
|
+
'company_profile_agent_policy', true
|
|
119
|
+
);
|
|
120
|
+
-- Migrations run as the non-bypass table owner without tenant GUCs. Relax
|
|
121
|
+
-- FORCE only for this owner-visible backfill; the runtime role remains
|
|
122
|
+
-- policy-bound, and the migration transaction restores FORCE before commit.
|
|
123
|
+
ALTER TABLE organization_company_profile_agent_policies NO FORCE ROW LEVEL SECURITY;
|
|
124
|
+
INSERT INTO organization_company_profile_agent_policies (
|
|
125
|
+
account_id, mode, version, updated_by_membership_id, updated_at
|
|
126
|
+
)
|
|
127
|
+
SELECT account.id, 'suggest', 0, NULL, account.created_at
|
|
128
|
+
FROM managed_accounts account
|
|
129
|
+
ON CONFLICT (account_id) DO NOTHING;
|
|
130
|
+
ALTER TABLE organization_company_profile_agent_policies FORCE ROW LEVEL SECURITY;
|
|
131
|
+
|
|
132
|
+
CREATE FUNCTION get_company_profile_agent_policy(
|
|
133
|
+
p_account_id uuid,
|
|
134
|
+
p_workspace_id uuid,
|
|
135
|
+
p_actor_subject_id text
|
|
136
|
+
) RETURNS jsonb
|
|
137
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
138
|
+
SET search_path FROM CURRENT
|
|
139
|
+
AS $body$
|
|
140
|
+
DECLARE
|
|
141
|
+
context_account_id uuid := nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
142
|
+
context_workspace_id uuid := nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
143
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
144
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
145
|
+
actor organization_memberships%ROWTYPE;
|
|
146
|
+
policy organization_company_profile_agent_policies%ROWTYPE;
|
|
147
|
+
BEGIN
|
|
148
|
+
IF context_account_id IS DISTINCT FROM p_account_id
|
|
149
|
+
OR context_workspace_id IS DISTINCT FROM p_workspace_id
|
|
150
|
+
OR context_subject_id IS DISTINCT FROM p_actor_subject_id
|
|
151
|
+
OR context_principal_kind IS DISTINCT FROM 'human_session'
|
|
152
|
+
THEN
|
|
153
|
+
RAISE EXCEPTION 'organization owner authority required' USING ERRCODE = '42501';
|
|
154
|
+
END IF;
|
|
155
|
+
PERFORM pg_catalog.set_config(
|
|
156
|
+
'opengeni.company_profile_agent_policy_lifecycle',
|
|
157
|
+
'company_profile_agent_policy', true
|
|
158
|
+
);
|
|
159
|
+
PERFORM 1 FROM workspaces workspace
|
|
160
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id;
|
|
161
|
+
IF NOT FOUND THEN
|
|
162
|
+
RAISE EXCEPTION 'organization workspace is unavailable' USING ERRCODE = '42501';
|
|
163
|
+
END IF;
|
|
164
|
+
SELECT membership.* INTO actor FROM organization_memberships membership
|
|
165
|
+
WHERE membership.account_id = p_account_id
|
|
166
|
+
AND membership.subject_id = p_actor_subject_id
|
|
167
|
+
AND membership.status = 'active'
|
|
168
|
+
AND membership.role = 'owner';
|
|
169
|
+
IF NOT FOUND THEN
|
|
170
|
+
RAISE EXCEPTION 'organization owner authority required' USING ERRCODE = '42501';
|
|
171
|
+
END IF;
|
|
172
|
+
SELECT * INTO policy FROM organization_company_profile_agent_policies candidate
|
|
173
|
+
WHERE candidate.account_id = p_account_id;
|
|
174
|
+
IF NOT FOUND THEN
|
|
175
|
+
RAISE EXCEPTION 'company-profile agent policy is unavailable' USING ERRCODE = '55000';
|
|
176
|
+
END IF;
|
|
177
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
178
|
+
'organizationId', p_account_id,
|
|
179
|
+
'mode', policy.mode,
|
|
180
|
+
'version', policy.version,
|
|
181
|
+
'updatedAt', policy.updated_at
|
|
182
|
+
);
|
|
183
|
+
END
|
|
184
|
+
$body$;
|
|
185
|
+
REVOKE ALL ON FUNCTION get_company_profile_agent_policy(uuid,uuid,text) FROM PUBLIC;
|
|
186
|
+
|
|
187
|
+
CREATE FUNCTION update_company_profile_agent_policy(
|
|
188
|
+
p_account_id uuid,
|
|
189
|
+
p_workspace_id uuid,
|
|
190
|
+
p_actor_subject_id text,
|
|
191
|
+
p_mode text,
|
|
192
|
+
p_expected_version bigint,
|
|
193
|
+
p_operation_id uuid
|
|
194
|
+
) RETURNS jsonb
|
|
195
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
196
|
+
SET search_path FROM CURRENT
|
|
197
|
+
AS $body$
|
|
198
|
+
DECLARE
|
|
199
|
+
context_account_id uuid := nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
200
|
+
context_workspace_id uuid := nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
201
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
202
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
203
|
+
actor organization_memberships%ROWTYPE;
|
|
204
|
+
policy organization_company_profile_agent_policies%ROWTYPE;
|
|
205
|
+
prior organization_company_profile_agent_policy_events%ROWTYPE;
|
|
206
|
+
next_version bigint;
|
|
207
|
+
did_change boolean;
|
|
208
|
+
BEGIN
|
|
209
|
+
IF context_account_id IS DISTINCT FROM p_account_id
|
|
210
|
+
OR context_workspace_id IS DISTINCT FROM p_workspace_id
|
|
211
|
+
OR context_subject_id IS DISTINCT FROM p_actor_subject_id
|
|
212
|
+
OR context_principal_kind IS DISTINCT FROM 'human_session'
|
|
213
|
+
OR p_mode NOT IN ('off', 'suggest', 'automatic')
|
|
214
|
+
OR p_expected_version IS NULL OR p_expected_version < 0
|
|
215
|
+
OR p_operation_id IS NULL
|
|
216
|
+
THEN
|
|
217
|
+
RAISE EXCEPTION 'company-profile agent policy request is invalid' USING ERRCODE = '22023';
|
|
218
|
+
END IF;
|
|
219
|
+
PERFORM pg_catalog.pg_advisory_xact_lock(pg_catalog.hashtextextended(
|
|
220
|
+
'organization-membership:' || p_account_id::text, 0
|
|
221
|
+
));
|
|
222
|
+
PERFORM pg_catalog.set_config(
|
|
223
|
+
'opengeni.company_profile_agent_policy_lifecycle',
|
|
224
|
+
'company_profile_agent_policy', true
|
|
225
|
+
);
|
|
226
|
+
PERFORM 1 FROM managed_accounts account WHERE account.id = p_account_id FOR KEY SHARE;
|
|
227
|
+
IF NOT FOUND THEN RAISE EXCEPTION 'organization not found' USING ERRCODE = 'P0002'; END IF;
|
|
228
|
+
PERFORM 1 FROM workspaces workspace
|
|
229
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id;
|
|
230
|
+
IF NOT FOUND THEN
|
|
231
|
+
RAISE EXCEPTION 'organization workspace is unavailable' USING ERRCODE = '42501';
|
|
232
|
+
END IF;
|
|
233
|
+
SELECT membership.* INTO actor FROM organization_memberships membership
|
|
234
|
+
WHERE membership.account_id = p_account_id
|
|
235
|
+
AND membership.subject_id = p_actor_subject_id
|
|
236
|
+
AND membership.status = 'active'
|
|
237
|
+
AND membership.role = 'owner'
|
|
238
|
+
FOR SHARE;
|
|
239
|
+
IF NOT FOUND THEN
|
|
240
|
+
RAISE EXCEPTION 'organization owner authority required' USING ERRCODE = '42501';
|
|
241
|
+
END IF;
|
|
242
|
+
SELECT * INTO prior FROM organization_company_profile_agent_policy_events event
|
|
243
|
+
WHERE event.id = p_operation_id;
|
|
244
|
+
IF FOUND THEN
|
|
245
|
+
IF prior.account_id IS DISTINCT FROM p_account_id
|
|
246
|
+
OR prior.actor_membership_id IS DISTINCT FROM actor.id
|
|
247
|
+
OR prior.requested_mode IS DISTINCT FROM p_mode
|
|
248
|
+
OR prior.expected_version IS DISTINCT FROM p_expected_version
|
|
249
|
+
THEN
|
|
250
|
+
RAISE EXCEPTION 'company-profile agent policy operation id was reused'
|
|
251
|
+
USING ERRCODE = 'P1851';
|
|
252
|
+
END IF;
|
|
253
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
254
|
+
'organizationId', p_account_id,
|
|
255
|
+
'mode', prior.result_mode,
|
|
256
|
+
'version', prior.result_version,
|
|
257
|
+
'updatedAt', prior.result_updated_at,
|
|
258
|
+
'changed', prior.changed
|
|
259
|
+
);
|
|
260
|
+
END IF;
|
|
261
|
+
SELECT * INTO policy FROM organization_company_profile_agent_policies candidate
|
|
262
|
+
WHERE candidate.account_id = p_account_id FOR UPDATE;
|
|
263
|
+
IF NOT FOUND THEN
|
|
264
|
+
RAISE EXCEPTION 'company-profile agent policy is unavailable' USING ERRCODE = '55000';
|
|
265
|
+
END IF;
|
|
266
|
+
IF policy.version IS DISTINCT FROM p_expected_version THEN
|
|
267
|
+
RAISE EXCEPTION 'company-profile agent policy changed before update'
|
|
268
|
+
USING ERRCODE = '40001';
|
|
269
|
+
END IF;
|
|
270
|
+
did_change := policy.mode IS DISTINCT FROM p_mode;
|
|
271
|
+
next_version := policy.version + 1;
|
|
272
|
+
UPDATE organization_company_profile_agent_policies SET
|
|
273
|
+
mode = p_mode,
|
|
274
|
+
version = next_version,
|
|
275
|
+
updated_by_membership_id = actor.id,
|
|
276
|
+
updated_at = clock_timestamp()
|
|
277
|
+
WHERE account_id = p_account_id
|
|
278
|
+
RETURNING * INTO policy;
|
|
279
|
+
INSERT INTO organization_company_profile_agent_policy_events (
|
|
280
|
+
id, account_id, actor_membership_id, requested_mode, expected_version,
|
|
281
|
+
result_mode, result_version, result_updated_at, changed
|
|
282
|
+
) VALUES (
|
|
283
|
+
p_operation_id, p_account_id, actor.id, p_mode, p_expected_version,
|
|
284
|
+
policy.mode, policy.version, policy.updated_at, did_change
|
|
285
|
+
);
|
|
286
|
+
RETURN pg_catalog.jsonb_build_object(
|
|
287
|
+
'organizationId', p_account_id,
|
|
288
|
+
'mode', policy.mode,
|
|
289
|
+
'version', policy.version,
|
|
290
|
+
'updatedAt', policy.updated_at,
|
|
291
|
+
'changed', did_change
|
|
292
|
+
);
|
|
293
|
+
END
|
|
294
|
+
$body$;
|
|
295
|
+
REVOKE ALL ON FUNCTION
|
|
296
|
+
update_company_profile_agent_policy(uuid,uuid,text,text,bigint,uuid) FROM PUBLIC;
|
|
297
|
+
|
|
298
|
+
ALTER TABLE company_profile_agent_proposal_receipts
|
|
299
|
+
ADD COLUMN policy_mode text NOT NULL DEFAULT 'suggest',
|
|
300
|
+
ADD COLUMN policy_version bigint NOT NULL DEFAULT 0;
|
|
301
|
+
ALTER TABLE company_profile_agent_proposal_receipts
|
|
302
|
+
ADD CONSTRAINT company_profile_agent_proposals_policy_mode_check
|
|
303
|
+
CHECK (policy_mode IN ('suggest', 'automatic')),
|
|
304
|
+
ADD CONSTRAINT company_profile_agent_proposals_policy_version_check
|
|
305
|
+
CHECK (policy_version >= 0);
|
|
306
|
+
|
|
307
|
+
CREATE TABLE company_profile_agent_automatic_activation_receipts (
|
|
308
|
+
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
309
|
+
operation_id uuid NOT NULL,
|
|
310
|
+
input_hash text NOT NULL,
|
|
311
|
+
account_id uuid NOT NULL REFERENCES managed_accounts(id) ON DELETE CASCADE,
|
|
312
|
+
workspace_id uuid NOT NULL,
|
|
313
|
+
session_id uuid NOT NULL,
|
|
314
|
+
turn_id uuid NOT NULL,
|
|
315
|
+
activation_attempt_id uuid NOT NULL,
|
|
316
|
+
execution_generation integer NOT NULL,
|
|
317
|
+
proposal_receipt_id uuid NOT NULL,
|
|
318
|
+
proposal_revision_id uuid NOT NULL,
|
|
319
|
+
initiating_human_subject_id text NOT NULL,
|
|
320
|
+
initiating_membership_id uuid NOT NULL,
|
|
321
|
+
policy_version bigint NOT NULL,
|
|
322
|
+
activation_event_id uuid NOT NULL,
|
|
323
|
+
created_at timestamptz NOT NULL DEFAULT clock_timestamp(),
|
|
324
|
+
CONSTRAINT company_profile_agent_automatic_activations_workspace_fk
|
|
325
|
+
FOREIGN KEY (workspace_id, account_id)
|
|
326
|
+
REFERENCES workspaces(id, account_id) ON DELETE CASCADE,
|
|
327
|
+
CONSTRAINT company_profile_agent_automatic_activations_session_fk
|
|
328
|
+
FOREIGN KEY (workspace_id, session_id)
|
|
329
|
+
REFERENCES sessions(workspace_id, id) ON DELETE CASCADE,
|
|
330
|
+
CONSTRAINT company_profile_agent_automatic_activations_turn_fk
|
|
331
|
+
FOREIGN KEY (workspace_id, turn_id)
|
|
332
|
+
REFERENCES session_turns(workspace_id, id) ON DELETE CASCADE,
|
|
333
|
+
CONSTRAINT company_profile_agent_automatic_activations_attempt_fk
|
|
334
|
+
FOREIGN KEY (account_id, workspace_id, session_id, turn_id, activation_attempt_id)
|
|
335
|
+
REFERENCES session_turn_attempts(account_id, workspace_id, session_id, turn_id, id)
|
|
336
|
+
ON DELETE CASCADE,
|
|
337
|
+
CONSTRAINT company_profile_agent_automatic_activations_proposal_fk
|
|
338
|
+
FOREIGN KEY (proposal_receipt_id, account_id)
|
|
339
|
+
REFERENCES company_profile_agent_proposal_receipts(id, account_id) ON DELETE RESTRICT,
|
|
340
|
+
CONSTRAINT company_profile_agent_automatic_activations_revision_fk
|
|
341
|
+
FOREIGN KEY (proposal_revision_id, account_id)
|
|
342
|
+
REFERENCES company_profile_revisions(id, account_id) ON DELETE RESTRICT,
|
|
343
|
+
CONSTRAINT company_profile_agent_automatic_activations_membership_fk
|
|
344
|
+
FOREIGN KEY (initiating_membership_id, account_id)
|
|
345
|
+
REFERENCES organization_memberships(id, account_id) ON DELETE RESTRICT,
|
|
346
|
+
CONSTRAINT company_profile_agent_automatic_activations_event_fk
|
|
347
|
+
FOREIGN KEY (activation_event_id, account_id)
|
|
348
|
+
REFERENCES company_profile_activation_events(id, account_id) ON DELETE RESTRICT,
|
|
349
|
+
CONSTRAINT company_profile_agent_automatic_activations_input_hash_check CHECK (
|
|
350
|
+
input_hash ~ '^[0-9a-f]{64}$'
|
|
351
|
+
),
|
|
352
|
+
CONSTRAINT company_profile_agent_automatic_activations_generation_check CHECK (
|
|
353
|
+
execution_generation > 0 AND policy_version >= 0
|
|
354
|
+
),
|
|
355
|
+
CONSTRAINT company_profile_agent_automatic_activations_subject_check CHECK (
|
|
356
|
+
octet_length(btrim(initiating_human_subject_id)) BETWEEN 1 AND 1024
|
|
357
|
+
)
|
|
358
|
+
);
|
|
359
|
+
CREATE UNIQUE INDEX company_profile_agent_automatic_activations_account_operation_uq
|
|
360
|
+
ON company_profile_agent_automatic_activation_receipts (account_id, operation_id);
|
|
361
|
+
CREATE UNIQUE INDEX company_profile_agent_automatic_activations_proposal_uq
|
|
362
|
+
ON company_profile_agent_automatic_activation_receipts (account_id, proposal_receipt_id);
|
|
363
|
+
CREATE UNIQUE INDEX company_profile_agent_automatic_activations_event_uq
|
|
364
|
+
ON company_profile_agent_automatic_activation_receipts (account_id, activation_event_id);
|
|
365
|
+
CREATE INDEX company_profile_agent_automatic_activations_turn_idx
|
|
366
|
+
ON company_profile_agent_automatic_activation_receipts (
|
|
367
|
+
workspace_id, session_id, turn_id, execution_generation
|
|
368
|
+
);
|
|
369
|
+
|
|
370
|
+
ALTER TABLE company_profile_agent_automatic_activation_receipts ENABLE ROW LEVEL SECURITY;
|
|
371
|
+
ALTER TABLE company_profile_agent_automatic_activation_receipts FORCE ROW LEVEL SECURITY;
|
|
372
|
+
REVOKE ALL ON TABLE company_profile_agent_automatic_activation_receipts FROM PUBLIC;
|
|
373
|
+
CREATE POLICY company_profile_agent_admin_lifecycle
|
|
374
|
+
ON company_profile_agent_automatic_activation_receipts
|
|
375
|
+
USING (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
376
|
+
= 'company_profile_agent_admin')
|
|
377
|
+
WITH CHECK (current_setting('opengeni.company_profile_agent_admin_lifecycle', true)
|
|
378
|
+
= 'company_profile_agent_admin');
|
|
379
|
+
CREATE POLICY session_visibility_isolation
|
|
380
|
+
ON company_profile_agent_automatic_activation_receipts AS RESTRICTIVE
|
|
381
|
+
USING (session_reference_visible(account_id, workspace_id, session_id))
|
|
382
|
+
WITH CHECK (session_reference_visible(account_id, workspace_id, session_id));
|
|
383
|
+
CREATE TRIGGER company_profile_agent_automatic_activations_immutable
|
|
384
|
+
BEFORE UPDATE OR DELETE ON company_profile_agent_automatic_activation_receipts
|
|
385
|
+
FOR EACH ROW EXECUTE FUNCTION company_profile_agent_receipts_immutable();
|
|
386
|
+
|
|
387
|
+
CREATE OR REPLACE FUNCTION propose_company_profile_for_attempt(
|
|
388
|
+
p_account_id uuid,
|
|
389
|
+
p_workspace_id uuid,
|
|
390
|
+
p_session_id uuid,
|
|
391
|
+
p_turn_id uuid,
|
|
392
|
+
p_attempt_id uuid,
|
|
393
|
+
p_execution_generation integer,
|
|
394
|
+
p_operation_id uuid,
|
|
395
|
+
p_content_json text,
|
|
396
|
+
p_content_hash text,
|
|
397
|
+
p_reason text
|
|
398
|
+
) RETURNS TABLE (
|
|
399
|
+
receipt_id uuid,
|
|
400
|
+
revision_id uuid,
|
|
401
|
+
human_input jsonb,
|
|
402
|
+
replayed boolean
|
|
403
|
+
)
|
|
404
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
405
|
+
SET search_path FROM CURRENT
|
|
406
|
+
AS $body$
|
|
407
|
+
DECLARE
|
|
408
|
+
context_account_id uuid := nullif(current_setting('opengeni.account_id', true), '')::uuid;
|
|
409
|
+
context_workspace_id uuid := nullif(current_setting('opengeni.workspace_id', true), '')::uuid;
|
|
410
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
411
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
412
|
+
initiating_subject text;
|
|
413
|
+
actor_membership organization_memberships%ROWTYPE;
|
|
414
|
+
active_head company_profile_heads%ROWTYPE;
|
|
415
|
+
policy organization_company_profile_agent_policies%ROWTYPE;
|
|
416
|
+
prior company_profile_agent_proposal_receipts%ROWTYPE;
|
|
417
|
+
inserted_revision company_profile_revisions%ROWTYPE;
|
|
418
|
+
input_hash_value text;
|
|
419
|
+
new_receipt_id uuid := gen_random_uuid();
|
|
420
|
+
new_revision_id uuid := gen_random_uuid();
|
|
421
|
+
normalized_reason text := btrim(p_reason);
|
|
422
|
+
prompt jsonb;
|
|
423
|
+
BEGIN
|
|
424
|
+
IF context_account_id IS DISTINCT FROM p_account_id
|
|
425
|
+
OR context_workspace_id IS DISTINCT FROM p_workspace_id
|
|
426
|
+
OR context_subject_id IS NULL
|
|
427
|
+
OR context_principal_kind IS DISTINCT FROM 'agent_attempt'
|
|
428
|
+
OR p_execution_generation < 1
|
|
429
|
+
OR p_operation_id IS NULL
|
|
430
|
+
OR p_content_json IS NULL
|
|
431
|
+
OR p_content_hash !~ '^[0-9a-f]{64}$'
|
|
432
|
+
OR p_content_hash IS DISTINCT FROM encode(sha256(convert_to(p_content_json, 'UTF8')), 'hex')
|
|
433
|
+
OR octet_length(convert_to(p_content_json, 'UTF8')) NOT BETWEEN 1 AND 28672
|
|
434
|
+
OR octet_length(convert_to(normalized_reason, 'UTF8')) NOT BETWEEN 1 AND 16384
|
|
435
|
+
THEN
|
|
436
|
+
RAISE EXCEPTION 'company-profile agent proposal is invalid' USING ERRCODE = '22023';
|
|
437
|
+
END IF;
|
|
438
|
+
|
|
439
|
+
SELECT coalesce(
|
|
440
|
+
turn.initiating_human_subject_id,
|
|
441
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
442
|
+
) INTO initiating_subject
|
|
443
|
+
FROM session_turns turn
|
|
444
|
+
WHERE turn.account_id = p_account_id
|
|
445
|
+
AND turn.workspace_id = p_workspace_id
|
|
446
|
+
AND turn.session_id = p_session_id
|
|
447
|
+
AND turn.id = p_turn_id;
|
|
448
|
+
IF initiating_subject IS NULL THEN
|
|
449
|
+
RAISE EXCEPTION
|
|
450
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
451
|
+
USING ERRCODE = '42501';
|
|
452
|
+
END IF;
|
|
453
|
+
|
|
454
|
+
PERFORM 1 FROM workspaces workspace
|
|
455
|
+
WHERE workspace.account_id = p_account_id AND workspace.id = p_workspace_id
|
|
456
|
+
FOR KEY SHARE;
|
|
457
|
+
IF NOT FOUND THEN
|
|
458
|
+
RAISE EXCEPTION 'organization workspace is unavailable' USING ERRCODE = '42501';
|
|
459
|
+
END IF;
|
|
460
|
+
SELECT membership.* INTO actor_membership
|
|
461
|
+
FROM organization_memberships membership
|
|
462
|
+
WHERE membership.account_id = p_account_id
|
|
463
|
+
AND membership.subject_id = initiating_subject
|
|
464
|
+
AND membership.status = 'active'
|
|
465
|
+
AND membership.role = 'owner'
|
|
466
|
+
FOR KEY SHARE;
|
|
467
|
+
IF NOT FOUND THEN
|
|
468
|
+
RAISE EXCEPTION
|
|
469
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
470
|
+
USING ERRCODE = '42501';
|
|
471
|
+
END IF;
|
|
472
|
+
PERFORM 1
|
|
473
|
+
FROM sessions session
|
|
474
|
+
JOIN session_turns turn
|
|
475
|
+
ON turn.account_id = session.account_id
|
|
476
|
+
AND turn.workspace_id = session.workspace_id
|
|
477
|
+
AND turn.session_id = session.id
|
|
478
|
+
JOIN session_turn_attempts attempt
|
|
479
|
+
ON attempt.account_id = turn.account_id
|
|
480
|
+
AND attempt.workspace_id = turn.workspace_id
|
|
481
|
+
AND attempt.session_id = turn.session_id
|
|
482
|
+
AND attempt.turn_id = turn.id
|
|
483
|
+
WHERE session.account_id = p_account_id
|
|
484
|
+
AND session.workspace_id = p_workspace_id
|
|
485
|
+
AND session.id = p_session_id
|
|
486
|
+
AND session.active_turn_id = p_turn_id
|
|
487
|
+
AND turn.id = p_turn_id
|
|
488
|
+
AND turn.active_attempt_id = p_attempt_id
|
|
489
|
+
AND turn.execution_generation = p_execution_generation
|
|
490
|
+
AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
491
|
+
AND coalesce(
|
|
492
|
+
turn.initiating_human_subject_id,
|
|
493
|
+
CASE WHEN turn.initiator_kind = 'subject' THEN turn.initiator_subject_id END
|
|
494
|
+
) = actor_membership.subject_id
|
|
495
|
+
AND attempt.id = p_attempt_id
|
|
496
|
+
AND attempt.execution_generation = p_execution_generation
|
|
497
|
+
AND attempt.state IN ('claimed', 'running')
|
|
498
|
+
AND NOT EXISTS (
|
|
499
|
+
SELECT 1 FROM session_attempt_interruptions interruption
|
|
500
|
+
WHERE interruption.workspace_id = attempt.workspace_id
|
|
501
|
+
AND interruption.attempt_id = attempt.id
|
|
502
|
+
AND interruption.state IN ('pending', 'delivered', 'acknowledged')
|
|
503
|
+
)
|
|
504
|
+
FOR SHARE OF session, turn, attempt;
|
|
505
|
+
IF NOT FOUND THEN
|
|
506
|
+
RAISE EXCEPTION
|
|
507
|
+
'company-profile agent proposals require the exact live turn of the active organization owner'
|
|
508
|
+
USING ERRCODE = '42501';
|
|
509
|
+
END IF;
|
|
510
|
+
|
|
511
|
+
PERFORM 1 FROM managed_accounts account
|
|
512
|
+
WHERE account.id = p_account_id FOR KEY SHARE;
|
|
513
|
+
IF NOT FOUND THEN
|
|
514
|
+
RAISE EXCEPTION 'organization account is unavailable' USING ERRCODE = '42501';
|
|
515
|
+
END IF;
|
|
516
|
+
|
|
517
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
518
|
+
'company-profile-agent-proposal', 1, p_account_id, p_workspace_id,
|
|
519
|
+
p_session_id, p_turn_id, p_operation_id, p_content_hash, normalized_reason,
|
|
520
|
+
actor_membership.id, actor_membership.subject_id
|
|
521
|
+
)::text, 'UTF8')), 'hex');
|
|
522
|
+
PERFORM set_config(
|
|
523
|
+
'opengeni.company_profile_agent_admin_lifecycle',
|
|
524
|
+
'company_profile_agent_admin', true
|
|
525
|
+
);
|
|
526
|
+
SELECT * INTO prior FROM company_profile_agent_proposal_receipts receipt
|
|
527
|
+
WHERE receipt.account_id = p_account_id AND receipt.operation_id = p_operation_id;
|
|
528
|
+
IF FOUND THEN
|
|
529
|
+
IF prior.input_hash IS DISTINCT FROM input_hash_value THEN
|
|
530
|
+
RAISE EXCEPTION 'company-profile agent proposal operation id was reused'
|
|
531
|
+
USING ERRCODE = 'P1851';
|
|
532
|
+
END IF;
|
|
533
|
+
receipt_id := prior.id;
|
|
534
|
+
revision_id := prior.revision_id;
|
|
535
|
+
human_input := prior.human_input;
|
|
536
|
+
replayed := true;
|
|
537
|
+
RETURN NEXT;
|
|
538
|
+
RETURN;
|
|
539
|
+
END IF;
|
|
540
|
+
IF EXISTS (
|
|
541
|
+
SELECT 1 FROM company_profile_revisions revision
|
|
542
|
+
WHERE revision.account_id = p_account_id AND revision.operation_id = p_operation_id
|
|
543
|
+
) THEN
|
|
544
|
+
RAISE EXCEPTION 'company-profile agent proposal operation id was reused'
|
|
545
|
+
USING ERRCODE = 'P1851';
|
|
546
|
+
END IF;
|
|
547
|
+
|
|
548
|
+
PERFORM set_config(
|
|
549
|
+
'opengeni.company_profile_agent_policy_lifecycle',
|
|
550
|
+
'company_profile_agent_policy', true
|
|
551
|
+
);
|
|
552
|
+
SELECT * INTO policy FROM organization_company_profile_agent_policies candidate
|
|
553
|
+
WHERE candidate.account_id = p_account_id
|
|
554
|
+
FOR SHARE;
|
|
555
|
+
IF NOT FOUND THEN
|
|
556
|
+
RAISE EXCEPTION 'company-profile agent policy is unavailable' USING ERRCODE = '55000';
|
|
557
|
+
END IF;
|
|
558
|
+
IF policy.mode = 'off' THEN
|
|
559
|
+
RAISE EXCEPTION 'company-profile agent changes are disabled by organization policy'
|
|
560
|
+
USING ERRCODE = 'P1852';
|
|
561
|
+
END IF;
|
|
562
|
+
|
|
563
|
+
SELECT * INTO active_head FROM company_profile_heads head
|
|
564
|
+
WHERE head.account_id = p_account_id;
|
|
565
|
+
INSERT INTO company_profile_revisions (
|
|
566
|
+
id, operation_id, request_fingerprint, account_id, intent,
|
|
567
|
+
content_json, content_hash, provenance_source, provenance_source_id,
|
|
568
|
+
supersedes_revision_id, created_by_subject_id
|
|
569
|
+
) VALUES (
|
|
570
|
+
new_revision_id, p_operation_id, input_hash_value, p_account_id, 'proposal',
|
|
571
|
+
p_content_json, p_content_hash, 'agent_admin',
|
|
572
|
+
'agent-admin-proposal:' || new_receipt_id::text,
|
|
573
|
+
active_head.revision_id, context_subject_id
|
|
574
|
+
) RETURNING * INTO inserted_revision;
|
|
575
|
+
prompt := company_profile_agent_confirmation_prompt(
|
|
576
|
+
inserted_revision.id, inserted_revision.revision,
|
|
577
|
+
inserted_revision.content_hash, inserted_revision.content_json
|
|
578
|
+
);
|
|
579
|
+
INSERT INTO company_profile_agent_proposal_receipts (
|
|
580
|
+
id, operation_id, input_hash, account_id, workspace_id, session_id,
|
|
581
|
+
turn_id, creation_attempt_id, execution_generation,
|
|
582
|
+
initiating_human_subject_id, initiating_membership_id, revision_id,
|
|
583
|
+
expected_current_revision_id, expected_activation_version,
|
|
584
|
+
policy_mode, policy_version, reason, human_input
|
|
585
|
+
) VALUES (
|
|
586
|
+
new_receipt_id, p_operation_id, input_hash_value, p_account_id, p_workspace_id,
|
|
587
|
+
p_session_id, p_turn_id, p_attempt_id, p_execution_generation,
|
|
588
|
+
actor_membership.subject_id, actor_membership.id, inserted_revision.id,
|
|
589
|
+
active_head.revision_id, coalesce(active_head.activation_version, 0),
|
|
590
|
+
policy.mode, policy.version, normalized_reason, prompt
|
|
591
|
+
);
|
|
592
|
+
receipt_id := new_receipt_id;
|
|
593
|
+
revision_id := inserted_revision.id;
|
|
594
|
+
human_input := prompt;
|
|
595
|
+
replayed := false;
|
|
596
|
+
RETURN NEXT;
|
|
597
|
+
END
|
|
598
|
+
$body$;
|
|
599
|
+
|
|
600
|
+
CREATE FUNCTION propose_company_profile_for_attempt_v2(
|
|
601
|
+
p_account_id uuid,
|
|
602
|
+
p_workspace_id uuid,
|
|
603
|
+
p_session_id uuid,
|
|
604
|
+
p_turn_id uuid,
|
|
605
|
+
p_attempt_id uuid,
|
|
606
|
+
p_execution_generation integer,
|
|
607
|
+
p_operation_id uuid,
|
|
608
|
+
p_automatic_activation_operation_id uuid,
|
|
609
|
+
p_content_json text,
|
|
610
|
+
p_content_hash text,
|
|
611
|
+
p_reason text
|
|
612
|
+
) RETURNS TABLE (
|
|
613
|
+
receipt_id uuid,
|
|
614
|
+
revision_id uuid,
|
|
615
|
+
human_input jsonb,
|
|
616
|
+
policy_mode text,
|
|
617
|
+
automatic_activation_receipt_id uuid,
|
|
618
|
+
activation_event_id uuid,
|
|
619
|
+
replayed boolean
|
|
620
|
+
)
|
|
621
|
+
LANGUAGE plpgsql SECURITY DEFINER
|
|
622
|
+
SET search_path FROM CURRENT
|
|
623
|
+
AS $body$
|
|
624
|
+
DECLARE
|
|
625
|
+
context_subject_id text := nullif(current_setting('opengeni.subject_id', true), '');
|
|
626
|
+
context_principal_kind text := nullif(current_setting('opengeni.principal_kind', true), '');
|
|
627
|
+
base record;
|
|
628
|
+
proposal company_profile_agent_proposal_receipts%ROWTYPE;
|
|
629
|
+
proposal_revision company_profile_revisions%ROWTYPE;
|
|
630
|
+
prior company_profile_agent_automatic_activation_receipts%ROWTYPE;
|
|
631
|
+
input_hash_value text;
|
|
632
|
+
event_id_value uuid;
|
|
633
|
+
new_receipt_id uuid := gen_random_uuid();
|
|
634
|
+
service_actor text := 'service:company-profile-autonomy';
|
|
635
|
+
BEGIN
|
|
636
|
+
IF context_subject_id IS NULL
|
|
637
|
+
OR context_principal_kind IS DISTINCT FROM 'agent_attempt'
|
|
638
|
+
OR p_automatic_activation_operation_id IS NULL
|
|
639
|
+
OR p_automatic_activation_operation_id IS NOT DISTINCT FROM p_operation_id
|
|
640
|
+
THEN
|
|
641
|
+
RAISE EXCEPTION 'company-profile automatic activation operation is invalid'
|
|
642
|
+
USING ERRCODE = '22023';
|
|
643
|
+
END IF;
|
|
644
|
+
SELECT * INTO base FROM propose_company_profile_for_attempt(
|
|
645
|
+
p_account_id, p_workspace_id, p_session_id, p_turn_id, p_attempt_id,
|
|
646
|
+
p_execution_generation, p_operation_id, p_content_json, p_content_hash, p_reason
|
|
647
|
+
);
|
|
648
|
+
IF base.receipt_id IS NULL THEN
|
|
649
|
+
RAISE EXCEPTION 'company-profile proposal returned no receipt' USING ERRCODE = '55000';
|
|
650
|
+
END IF;
|
|
651
|
+
PERFORM set_config(
|
|
652
|
+
'opengeni.company_profile_agent_admin_lifecycle',
|
|
653
|
+
'company_profile_agent_admin', true
|
|
654
|
+
);
|
|
655
|
+
SELECT * INTO proposal FROM company_profile_agent_proposal_receipts receipt
|
|
656
|
+
WHERE receipt.account_id = p_account_id AND receipt.id = base.receipt_id
|
|
657
|
+
FOR SHARE;
|
|
658
|
+
IF NOT FOUND THEN
|
|
659
|
+
RAISE EXCEPTION 'company-profile proposal receipt is unavailable' USING ERRCODE = '55000';
|
|
660
|
+
END IF;
|
|
661
|
+
|
|
662
|
+
receipt_id := proposal.id;
|
|
663
|
+
revision_id := proposal.revision_id;
|
|
664
|
+
human_input := proposal.human_input;
|
|
665
|
+
policy_mode := proposal.policy_mode;
|
|
666
|
+
IF proposal.policy_mode = 'suggest' THEN
|
|
667
|
+
automatic_activation_receipt_id := NULL;
|
|
668
|
+
activation_event_id := NULL;
|
|
669
|
+
replayed := base.replayed;
|
|
670
|
+
RETURN NEXT;
|
|
671
|
+
RETURN;
|
|
672
|
+
END IF;
|
|
673
|
+
IF proposal.policy_mode IS DISTINCT FROM 'automatic' THEN
|
|
674
|
+
RAISE EXCEPTION 'company-profile proposal policy is invalid' USING ERRCODE = '55000';
|
|
675
|
+
END IF;
|
|
676
|
+
|
|
677
|
+
SELECT * INTO prior FROM company_profile_agent_automatic_activation_receipts receipt
|
|
678
|
+
WHERE receipt.account_id = p_account_id AND receipt.proposal_receipt_id = proposal.id;
|
|
679
|
+
IF FOUND THEN
|
|
680
|
+
IF prior.operation_id IS DISTINCT FROM p_automatic_activation_operation_id THEN
|
|
681
|
+
RAISE EXCEPTION 'company-profile automatic activation operation id was reused'
|
|
682
|
+
USING ERRCODE = 'P1851';
|
|
683
|
+
END IF;
|
|
684
|
+
automatic_activation_receipt_id := prior.id;
|
|
685
|
+
activation_event_id := prior.activation_event_id;
|
|
686
|
+
replayed := true;
|
|
687
|
+
RETURN NEXT;
|
|
688
|
+
RETURN;
|
|
689
|
+
END IF;
|
|
690
|
+
SELECT * INTO prior FROM company_profile_agent_automatic_activation_receipts receipt
|
|
691
|
+
WHERE receipt.account_id = p_account_id
|
|
692
|
+
AND receipt.operation_id = p_automatic_activation_operation_id;
|
|
693
|
+
IF FOUND THEN
|
|
694
|
+
RAISE EXCEPTION 'company-profile automatic activation operation id was reused'
|
|
695
|
+
USING ERRCODE = 'P1851';
|
|
696
|
+
END IF;
|
|
697
|
+
|
|
698
|
+
SELECT * INTO proposal_revision FROM company_profile_revisions revision
|
|
699
|
+
WHERE revision.account_id = p_account_id
|
|
700
|
+
AND revision.id = proposal.revision_id
|
|
701
|
+
AND revision.intent = 'proposal'
|
|
702
|
+
AND revision.provenance_source = 'agent_admin'
|
|
703
|
+
AND revision.provenance_source_id = 'agent-admin-proposal:' || proposal.id::text
|
|
704
|
+
FOR SHARE;
|
|
705
|
+
IF NOT FOUND THEN
|
|
706
|
+
RAISE EXCEPTION 'company-profile proposal revision is unavailable'
|
|
707
|
+
USING ERRCODE = '42501';
|
|
708
|
+
END IF;
|
|
709
|
+
|
|
710
|
+
input_hash_value := encode(sha256(convert_to(jsonb_build_array(
|
|
711
|
+
'company-profile-agent-automatic-activation', 1,
|
|
712
|
+
p_account_id, p_workspace_id, p_session_id, p_turn_id,
|
|
713
|
+
p_automatic_activation_operation_id, proposal.id, proposal.revision_id,
|
|
714
|
+
proposal.policy_version, proposal.initiating_membership_id,
|
|
715
|
+
proposal.initiating_human_subject_id
|
|
716
|
+
)::text, 'UTF8')), 'hex');
|
|
717
|
+
|
|
718
|
+
PERFORM set_config('opengeni.subject_id', service_actor, true);
|
|
719
|
+
PERFORM set_config('opengeni.principal_kind', 'service', true);
|
|
720
|
+
SELECT activation.event_id INTO event_id_value
|
|
721
|
+
FROM company_profile_apply_activation(
|
|
722
|
+
p_automatic_activation_operation_id, input_hash_value,
|
|
723
|
+
p_account_id, p_workspace_id, proposal_revision.id,
|
|
724
|
+
proposal.expected_current_revision_id, proposal.expected_activation_version,
|
|
725
|
+
'activate', service_actor, 'service',
|
|
726
|
+
'Automatically activated under the organization company-profile agent policy'
|
|
727
|
+
) activation;
|
|
728
|
+
IF event_id_value IS NULL THEN
|
|
729
|
+
RAISE EXCEPTION 'company-profile automatic activation returned no event'
|
|
730
|
+
USING ERRCODE = '55000';
|
|
731
|
+
END IF;
|
|
732
|
+
PERFORM set_config('opengeni.subject_id', context_subject_id, true);
|
|
733
|
+
PERFORM set_config('opengeni.principal_kind', context_principal_kind, true);
|
|
734
|
+
|
|
735
|
+
INSERT INTO company_profile_agent_automatic_activation_receipts (
|
|
736
|
+
id, operation_id, input_hash, account_id, workspace_id, session_id, turn_id,
|
|
737
|
+
activation_attempt_id, execution_generation, proposal_receipt_id,
|
|
738
|
+
proposal_revision_id, initiating_human_subject_id, initiating_membership_id,
|
|
739
|
+
policy_version, activation_event_id
|
|
740
|
+
) VALUES (
|
|
741
|
+
new_receipt_id, p_automatic_activation_operation_id, input_hash_value,
|
|
742
|
+
p_account_id, p_workspace_id, p_session_id, p_turn_id, p_attempt_id,
|
|
743
|
+
p_execution_generation, proposal.id, proposal.revision_id,
|
|
744
|
+
proposal.initiating_human_subject_id, proposal.initiating_membership_id,
|
|
745
|
+
proposal.policy_version, event_id_value
|
|
746
|
+
);
|
|
747
|
+
automatic_activation_receipt_id := new_receipt_id;
|
|
748
|
+
activation_event_id := event_id_value;
|
|
749
|
+
replayed := false;
|
|
750
|
+
RETURN NEXT;
|
|
751
|
+
END
|
|
752
|
+
$body$;
|
|
753
|
+
|
|
754
|
+
REVOKE ALL ON FUNCTION propose_company_profile_for_attempt_v2(
|
|
755
|
+
uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,text,text,text
|
|
756
|
+
) FROM PUBLIC;
|
|
757
|
+
|
|
758
|
+
DO $autonomous_company_profile_hardening$
|
|
759
|
+
DECLARE
|
|
760
|
+
target_schema text := current_schema();
|
|
761
|
+
runtime_role text := nullif(current_setting('opengeni.runtime_role', true), '');
|
|
762
|
+
BEGIN
|
|
763
|
+
EXECUTE format(
|
|
764
|
+
'ALTER FUNCTION %I.initialize_company_profile_agent_policy() '
|
|
765
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
766
|
+
target_schema, target_schema
|
|
767
|
+
);
|
|
768
|
+
EXECUTE format(
|
|
769
|
+
'ALTER FUNCTION %I.company_profile_agent_policy_events_immutable() '
|
|
770
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
771
|
+
target_schema, target_schema
|
|
772
|
+
);
|
|
773
|
+
EXECUTE format(
|
|
774
|
+
'ALTER FUNCTION %I.get_company_profile_agent_policy(uuid,uuid,text) '
|
|
775
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
776
|
+
target_schema, target_schema
|
|
777
|
+
);
|
|
778
|
+
EXECUTE format(
|
|
779
|
+
'ALTER FUNCTION %I.update_company_profile_agent_policy(uuid,uuid,text,text,bigint,uuid) '
|
|
780
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
781
|
+
target_schema, target_schema
|
|
782
|
+
);
|
|
783
|
+
EXECUTE format(
|
|
784
|
+
'ALTER FUNCTION %I.propose_company_profile_for_attempt('
|
|
785
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,text,text,text) '
|
|
786
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
787
|
+
target_schema, target_schema
|
|
788
|
+
);
|
|
789
|
+
EXECUTE format(
|
|
790
|
+
'ALTER FUNCTION %I.propose_company_profile_for_attempt_v2('
|
|
791
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,text,text,text) '
|
|
792
|
+
|| 'SET search_path = pg_catalog, %I, pg_temp',
|
|
793
|
+
target_schema, target_schema
|
|
794
|
+
);
|
|
795
|
+
IF runtime_role IS NOT NULL THEN
|
|
796
|
+
EXECUTE format(
|
|
797
|
+
'REVOKE ALL ON TABLE %I.organization_company_profile_agent_policies FROM %I',
|
|
798
|
+
target_schema, runtime_role
|
|
799
|
+
);
|
|
800
|
+
EXECUTE format(
|
|
801
|
+
'REVOKE ALL ON TABLE %I.organization_company_profile_agent_policy_events FROM %I',
|
|
802
|
+
target_schema, runtime_role
|
|
803
|
+
);
|
|
804
|
+
EXECUTE format(
|
|
805
|
+
'REVOKE ALL ON TABLE %I.company_profile_agent_automatic_activation_receipts FROM %I',
|
|
806
|
+
target_schema, runtime_role
|
|
807
|
+
);
|
|
808
|
+
EXECUTE format(
|
|
809
|
+
'GRANT EXECUTE ON FUNCTION %I.get_company_profile_agent_policy(uuid,uuid,text) TO %I',
|
|
810
|
+
target_schema, runtime_role
|
|
811
|
+
);
|
|
812
|
+
EXECUTE format(
|
|
813
|
+
'GRANT EXECUTE ON FUNCTION %I.update_company_profile_agent_policy('
|
|
814
|
+
|| 'uuid,uuid,text,text,bigint,uuid) TO %I',
|
|
815
|
+
target_schema, runtime_role
|
|
816
|
+
);
|
|
817
|
+
EXECUTE format(
|
|
818
|
+
'GRANT EXECUTE ON FUNCTION %I.propose_company_profile_for_attempt_v2('
|
|
819
|
+
|| 'uuid,uuid,uuid,uuid,uuid,integer,uuid,uuid,text,text,text) TO %I',
|
|
820
|
+
target_schema, runtime_role
|
|
821
|
+
);
|
|
822
|
+
END IF;
|
|
823
|
+
END
|
|
824
|
+
$autonomous_company_profile_hardening$;
|
|
825
|
+
|
|
826
|
+
COMMENT ON TABLE organization_company_profile_agent_policies IS
|
|
827
|
+
'Organization-owner policy for agent-authored company-profile changes; default suggest preserves per-change confirmation, automatic permits exact owner-initiated turns to activate through the company-profile lifecycle.';
|
|
828
|
+
COMMENT ON TABLE company_profile_agent_automatic_activation_receipts IS
|
|
829
|
+
'Immutable exact-attempt receipts for company-profile proposals activated without per-change confirmation under a frozen organization-owner automatic policy.';
|