@opengeni/db 0.31.1 → 0.36.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-auth.d.ts +209 -1
- package/dist/browser-downloads.d.ts +51 -0
- package/dist/browser-identities.d.ts +11 -2
- package/dist/browser-sessions.d.ts +83 -1
- package/dist/browser-state-artifacts.d.ts +75 -1
- package/dist/canonical-human-identities.d.ts +48 -0
- package/dist/canonical-human-identities.js +28 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/capability-integrations.d.ts +8 -6
- package/dist/{chunk-MWDVXQOL.js → chunk-5KTIEDX7.js} +5773 -4212
- package/dist/chunk-5KTIEDX7.js.map +1 -0
- package/dist/chunk-FPVAD4CO.js +117 -0
- package/dist/chunk-FPVAD4CO.js.map +1 -0
- package/dist/chunk-GYO7ED2Q.js +259 -0
- package/dist/chunk-GYO7ED2Q.js.map +1 -0
- package/dist/{chunk-F5FT7BEZ.js → chunk-HSOWSYOX.js} +2 -2
- package/dist/{chunk-YHZXQ7HP.js → chunk-VKLB2ZGI.js} +446 -19
- package/dist/chunk-VKLB2ZGI.js.map +1 -0
- package/dist/{chunk-NBE6CHRI.js → chunk-VTPRIXKG.js} +49 -9
- package/dist/chunk-VTPRIXKG.js.map +1 -0
- package/dist/{chunk-ISI2TIUG.js → chunk-Z7VYMNPZ.js} +76 -4
- package/dist/chunk-Z7VYMNPZ.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +467 -29
- package/dist/index.js +23247 -16232
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +23 -7
- package/dist/integration-bindings.d.ts +24 -24
- package/dist/integration-facets.d.ts +99 -0
- package/dist/interaction-revisions.d.ts +11 -0
- package/dist/interaction-schema.d.ts +698 -34
- package/dist/persistence-errors.d.ts +8 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +8 -7
- package/dist/schema.d.ts +9464 -5412
- package/dist/schema.js +51 -9
- package/dist/session-control.d.ts +29 -3
- package/dist/session-tenancy.d.ts +44 -0
- package/dist/session-tenancy.js +16 -0
- package/dist/session-tenancy.js.map +1 -0
- package/dist/slack-task-policy-schema.d.ts +847 -0
- package/dist/slack-task-policy.d.ts +65 -0
- package/dist/task-notes-schema.d.ts +924 -0
- package/dist/task-notes.d.ts +85 -0
- package/dist/video-generation.d.ts +9 -0
- package/dist/video-generation.js +5 -3
- package/dist/xai-subscription.d.ts +326 -0
- package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
- package/drizzle/0213_browser_interaction_authority.sql +67 -0
- package/drizzle/0214_browser_download_saves.sql +34 -0
- package/drizzle/0215_browser_controller_host.sql +385 -0
- package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
- package/drizzle/0217_external_browser_auth_operations.sql +22 -0
- package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
- package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
- package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
- package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
- package/drizzle/0220_session_channels.sql +54 -0
- package/drizzle/0221_sessions_channel_index.sql +5 -0
- package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
- package/drizzle/0222_sessions_channel_fk.sql +89 -0
- package/drizzle/0223_pending_tool_event_output.sql +55 -0
- package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
- package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
- package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
- package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
- package/drizzle/0227_slack_native_actions.sql +145 -0
- package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
- package/drizzle/0228_slack_task_policy.sql +400 -0
- package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
- package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
- package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
- package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
- package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
- package/drizzle/0234_xai_subscription_authority.sql +1139 -0
- package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
- package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
- package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
- package/drizzle/0237_interaction_transition_reaper.sql +263 -0
- package/drizzle/0238_goal_persistence_policy.sql +471 -0
- package/drizzle/0238_recover_unclaimed_session_turns.sql +307 -0
- package/drizzle/0238_supergrok_realtime_model.sql +29 -0
- package/drizzle/0239_supergrok_video_funding.sql +50 -0
- package/drizzle/0239_task_tree_notes.sql +990 -0
- package/package.json +13 -5
- package/src/browser-auth.ts +2600 -123
- package/src/browser-downloads.ts +517 -0
- package/src/browser-identities.ts +220 -3
- package/src/browser-sessions.ts +334 -45
- package/src/browser-state-artifacts.ts +402 -12
- package/src/canonical-human-identities.ts +317 -0
- package/src/capability-integrations.ts +121 -213
- package/src/database.ts +41 -1
- package/src/index.ts +4625 -411
- package/src/insights.ts +109 -28
- package/src/integration-bindings.ts +101 -101
- package/src/{integration-features.ts → integration-facets.ts} +187 -184
- package/src/interaction-revisions.ts +33 -3
- package/src/interaction-schema.ts +311 -8
- package/src/pack-components.ts +43 -43
- package/src/pack-installations.ts +0 -43
- package/src/persistence-errors.ts +60 -1
- package/src/plugin-packages.ts +9 -9
- package/src/provision-roles.ts +232 -0
- package/src/runtime-posture.ts +227 -14
- package/src/schema.ts +1188 -75
- package/src/session-control.ts +122 -37
- package/src/session-queue-commands.ts +78 -1
- package/src/session-tenancy.ts +188 -0
- package/src/session-tool-call-settlement.ts +9 -3
- package/src/slack-task-policy-schema.ts +130 -0
- package/src/slack-task-policy.ts +341 -0
- package/src/task-notes-schema.ts +135 -0
- package/src/task-notes.ts +178 -0
- package/src/video-generation.ts +90 -12
- package/src/workspace-artifacts.ts +1 -1
- package/src/xai-subscription.ts +1887 -0
- package/dist/chunk-ISI2TIUG.js.map +0 -1
- package/dist/chunk-MWDVXQOL.js.map +0 -1
- package/dist/chunk-NBE6CHRI.js.map +0 -1
- package/dist/chunk-YHZXQ7HP.js.map +0 -1
- package/dist/integration-features.d.ts +0 -99
- /package/dist/{chunk-F5FT7BEZ.js.map → chunk-HSOWSYOX.js.map} +0 -0
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Freeze the exact goal projection on each accepted logical turn and
|
|
3
|
+
-- separate semantic objective revisions from the established continuation
|
|
4
|
+
-- lifecycle version/wake ledger.
|
|
5
|
+
|
|
6
|
+
SET LOCAL lock_timeout = '5s';
|
|
7
|
+
SET LOCAL statement_timeout = '10min';
|
|
8
|
+
|
|
9
|
+
ALTER TABLE "session_goals"
|
|
10
|
+
ADD COLUMN IF NOT EXISTS "objective_revision" integer NOT NULL DEFAULT 1,
|
|
11
|
+
ADD COLUMN IF NOT EXISTS "mutation_policy" text NOT NULL DEFAULT 'preserve_intent';
|
|
12
|
+
|
|
13
|
+
ALTER TABLE "session_goals"
|
|
14
|
+
ADD CONSTRAINT "session_goals_objective_revision_chk"
|
|
15
|
+
CHECK ("objective_revision" > 0) NOT VALID,
|
|
16
|
+
ADD CONSTRAINT "session_goals_mutation_policy_chk"
|
|
17
|
+
CHECK ("mutation_policy" IN (
|
|
18
|
+
'review_changes', 'preserve_intent', 'autonomous_adaptation'
|
|
19
|
+
)) NOT VALID;
|
|
20
|
+
|
|
21
|
+
ALTER TABLE "session_goals"
|
|
22
|
+
VALIDATE CONSTRAINT "session_goals_objective_revision_chk",
|
|
23
|
+
VALIDATE CONSTRAINT "session_goals_mutation_policy_chk";
|
|
24
|
+
|
|
25
|
+
ALTER TABLE "session_turns"
|
|
26
|
+
ADD COLUMN IF NOT EXISTS "goal_snapshot" jsonb;
|
|
27
|
+
|
|
28
|
+
ALTER TABLE "session_turns"
|
|
29
|
+
ADD CONSTRAINT "session_turns_goal_snapshot_chk" CHECK (
|
|
30
|
+
"goal_snapshot" IS NULL
|
|
31
|
+
OR (
|
|
32
|
+
jsonb_typeof("goal_snapshot") = 'object'
|
|
33
|
+
AND "goal_snapshot" ->> 'state' IN ('none', 'active', 'paused', 'completed')
|
|
34
|
+
AND jsonb_typeof("goal_snapshot" -> 'capturedAt') = 'string'
|
|
35
|
+
AND (
|
|
36
|
+
("goal_snapshot" ->> 'state' = 'none'
|
|
37
|
+
AND "goal_snapshot" - 'state' - 'capturedAt' = '{}'::jsonb)
|
|
38
|
+
OR
|
|
39
|
+
("goal_snapshot" ->> 'state' IN ('active', 'paused', 'completed')
|
|
40
|
+
AND jsonb_typeof("goal_snapshot" -> 'goalId') = 'string'
|
|
41
|
+
AND jsonb_typeof("goal_snapshot" -> 'objectiveRevision') = 'number'
|
|
42
|
+
AND ("goal_snapshot" ->> 'objectiveRevision') ~ '^[1-9][0-9]*$'
|
|
43
|
+
AND jsonb_typeof("goal_snapshot" -> 'text') = 'string'
|
|
44
|
+
AND length("goal_snapshot" ->> 'text') > 0
|
|
45
|
+
AND octet_length("goal_snapshot" ->> 'text') <= 8192
|
|
46
|
+
AND (
|
|
47
|
+
"goal_snapshot" -> 'successCriteria' = 'null'::jsonb
|
|
48
|
+
OR (
|
|
49
|
+
jsonb_typeof("goal_snapshot" -> 'successCriteria') = 'string'
|
|
50
|
+
AND octet_length("goal_snapshot" ->> 'successCriteria') <= 8192
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
AND "goal_snapshot" ->> 'mutationPolicy' IN (
|
|
54
|
+
'review_changes', 'preserve_intent', 'autonomous_adaptation'
|
|
55
|
+
))
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
) NOT VALID;
|
|
59
|
+
|
|
60
|
+
ALTER TABLE "session_turns"
|
|
61
|
+
VALIDATE CONSTRAINT "session_turns_goal_snapshot_chk";
|
|
62
|
+
|
|
63
|
+
CREATE TABLE "session_goal_revisions" (
|
|
64
|
+
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
65
|
+
"account_id" uuid NOT NULL,
|
|
66
|
+
"workspace_id" uuid NOT NULL,
|
|
67
|
+
"session_id" uuid NOT NULL,
|
|
68
|
+
"goal_id" uuid NOT NULL,
|
|
69
|
+
"disposition" text NOT NULL,
|
|
70
|
+
"change_kind" text NOT NULL,
|
|
71
|
+
"base_objective_revision" integer NOT NULL,
|
|
72
|
+
"result_objective_revision" integer,
|
|
73
|
+
"text" text NOT NULL,
|
|
74
|
+
"success_criteria" text,
|
|
75
|
+
"mutation_policy" text NOT NULL,
|
|
76
|
+
"rationale" text NOT NULL,
|
|
77
|
+
"actor" text NOT NULL,
|
|
78
|
+
"actor_turn_id" uuid,
|
|
79
|
+
"actor_attempt_id" uuid,
|
|
80
|
+
"proposal_id" uuid,
|
|
81
|
+
"created_at" timestamptz NOT NULL DEFAULT now(),
|
|
82
|
+
CONSTRAINT "session_goal_revisions_workspace_account_fk"
|
|
83
|
+
FOREIGN KEY ("workspace_id", "account_id")
|
|
84
|
+
REFERENCES "workspaces"("id", "account_id") ON DELETE CASCADE,
|
|
85
|
+
CONSTRAINT "session_goal_revisions_workspace_session_fk"
|
|
86
|
+
FOREIGN KEY ("workspace_id", "session_id")
|
|
87
|
+
REFERENCES "sessions"("workspace_id", "id") ON DELETE CASCADE,
|
|
88
|
+
CONSTRAINT "session_goal_revisions_actor_turn_fk"
|
|
89
|
+
FOREIGN KEY ("workspace_id", "actor_turn_id")
|
|
90
|
+
REFERENCES "session_turns"("workspace_id", "id") ON DELETE RESTRICT,
|
|
91
|
+
CONSTRAINT "session_goal_revisions_actor_attempt_fk"
|
|
92
|
+
FOREIGN KEY ("workspace_id", "actor_attempt_id")
|
|
93
|
+
REFERENCES "session_turn_attempts"("workspace_id", "id") ON DELETE RESTRICT,
|
|
94
|
+
CONSTRAINT "session_goal_revisions_disposition_chk"
|
|
95
|
+
CHECK ("disposition" IN ('applied', 'proposed', 'rejected')),
|
|
96
|
+
CONSTRAINT "session_goal_revisions_change_kind_chk"
|
|
97
|
+
CHECK ("change_kind" IN ('refinement', 'adaptation', 'replacement')),
|
|
98
|
+
CONSTRAINT "session_goal_revisions_policy_chk"
|
|
99
|
+
CHECK ("mutation_policy" IN (
|
|
100
|
+
'review_changes', 'preserve_intent', 'autonomous_adaptation'
|
|
101
|
+
)),
|
|
102
|
+
CONSTRAINT "session_goal_revisions_actor_chk"
|
|
103
|
+
CHECK ("actor" IN ('agent', 'api', 'scheduled_task')),
|
|
104
|
+
CONSTRAINT "session_goal_revisions_revision_shape_chk" CHECK (
|
|
105
|
+
("disposition" = 'applied'
|
|
106
|
+
AND "result_objective_revision" = "base_objective_revision" + 1)
|
|
107
|
+
OR
|
|
108
|
+
("disposition" IN ('proposed', 'rejected')
|
|
109
|
+
AND "result_objective_revision" IS NULL)
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
CREATE UNIQUE INDEX "session_goal_revisions_workspace_id_uq"
|
|
114
|
+
ON "session_goal_revisions" ("workspace_id", "id");
|
|
115
|
+
CREATE UNIQUE INDEX "session_goal_revisions_applied_revision_uq"
|
|
116
|
+
ON "session_goal_revisions" (
|
|
117
|
+
"workspace_id", "goal_id", "result_objective_revision"
|
|
118
|
+
) WHERE "disposition" = 'applied';
|
|
119
|
+
CREATE INDEX "session_goal_revisions_goal_timeline_idx"
|
|
120
|
+
ON "session_goal_revisions" ("workspace_id", "goal_id", "created_at", "id");
|
|
121
|
+
ALTER TABLE "session_goal_revisions"
|
|
122
|
+
ADD CONSTRAINT "session_goal_revisions_proposal_fk"
|
|
123
|
+
FOREIGN KEY ("workspace_id", "proposal_id")
|
|
124
|
+
REFERENCES "session_goal_revisions"("workspace_id", "id") ON DELETE RESTRICT;
|
|
125
|
+
|
|
126
|
+
ALTER TABLE "session_goal_revisions" ENABLE ROW LEVEL SECURITY;
|
|
127
|
+
ALTER TABLE "session_goal_revisions" FORCE ROW LEVEL SECURITY;
|
|
128
|
+
CREATE POLICY workspace_isolation ON "session_goal_revisions"
|
|
129
|
+
USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
|
|
130
|
+
WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
|
|
131
|
+
CREATE POLICY session_visibility_isolation ON "session_goal_revisions"
|
|
132
|
+
AS RESTRICTIVE
|
|
133
|
+
USING (session_reference_visible(
|
|
134
|
+
"account_id", "workspace_id", "session_id"
|
|
135
|
+
))
|
|
136
|
+
WITH CHECK (session_reference_visible(
|
|
137
|
+
"account_id", "workspace_id", "session_id"
|
|
138
|
+
));
|
|
139
|
+
|
|
140
|
+
CREATE OR REPLACE FUNCTION session_goal_revision_reject_mutation()
|
|
141
|
+
RETURNS trigger
|
|
142
|
+
LANGUAGE plpgsql
|
|
143
|
+
AS $$
|
|
144
|
+
BEGIN
|
|
145
|
+
-- Parent lifecycle deletion is the sole mutation exception. PostgreSQL's
|
|
146
|
+
-- cascading constraint trigger runs only after its parent row is absent;
|
|
147
|
+
-- require both nested trigger context and one missing ownership edge so
|
|
148
|
+
-- direct or unrelated-trigger deletes remain fail-closed.
|
|
149
|
+
IF TG_OP = 'DELETE'
|
|
150
|
+
AND pg_trigger_depth() > 1
|
|
151
|
+
AND (
|
|
152
|
+
NOT EXISTS (SELECT 1 FROM "managed_accounts" WHERE "id" = OLD."account_id")
|
|
153
|
+
OR NOT EXISTS (SELECT 1 FROM "workspaces" WHERE "id" = OLD."workspace_id")
|
|
154
|
+
OR NOT EXISTS (SELECT 1 FROM "sessions" WHERE "id" = OLD."session_id")
|
|
155
|
+
)
|
|
156
|
+
THEN
|
|
157
|
+
RETURN OLD;
|
|
158
|
+
END IF;
|
|
159
|
+
RAISE EXCEPTION 'session goal revisions are immutable'
|
|
160
|
+
USING ERRCODE = '55000';
|
|
161
|
+
END;
|
|
162
|
+
$$;
|
|
163
|
+
|
|
164
|
+
DROP TRIGGER IF EXISTS session_goal_revisions_immutable
|
|
165
|
+
ON "session_goal_revisions";
|
|
166
|
+
CREATE TRIGGER session_goal_revisions_immutable
|
|
167
|
+
BEFORE UPDATE OR DELETE ON "session_goal_revisions"
|
|
168
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_revision_reject_mutation();
|
|
169
|
+
|
|
170
|
+
CREATE OR REPLACE FUNCTION session_goal_revision_bound_insert()
|
|
171
|
+
RETURNS trigger
|
|
172
|
+
LANGUAGE plpgsql
|
|
173
|
+
AS $$
|
|
174
|
+
BEGIN
|
|
175
|
+
IF octet_length(NEW."text") > 8192 THEN
|
|
176
|
+
RAISE EXCEPTION 'goal text exceeds 8192 UTF-8 bytes'
|
|
177
|
+
USING ERRCODE = '22001';
|
|
178
|
+
END IF;
|
|
179
|
+
IF NEW."success_criteria" IS NOT NULL
|
|
180
|
+
AND octet_length(NEW."success_criteria") > 8192 THEN
|
|
181
|
+
RAISE EXCEPTION 'goal success criteria exceeds 8192 UTF-8 bytes'
|
|
182
|
+
USING ERRCODE = '22001';
|
|
183
|
+
END IF;
|
|
184
|
+
IF octet_length(NEW."rationale") > 2048 THEN
|
|
185
|
+
RAISE EXCEPTION 'goal rationale exceeds 2048 UTF-8 bytes'
|
|
186
|
+
USING ERRCODE = '22001';
|
|
187
|
+
END IF;
|
|
188
|
+
RETURN NEW;
|
|
189
|
+
END;
|
|
190
|
+
$$;
|
|
191
|
+
|
|
192
|
+
INSERT INTO "session_goal_revisions" (
|
|
193
|
+
"account_id", "workspace_id", "session_id", "goal_id", "disposition",
|
|
194
|
+
"change_kind", "base_objective_revision", "result_objective_revision",
|
|
195
|
+
"text", "success_criteria", "mutation_policy", "rationale", "actor",
|
|
196
|
+
"created_at"
|
|
197
|
+
)
|
|
198
|
+
SELECT
|
|
199
|
+
goal."account_id", goal."workspace_id", goal."session_id", goal."id",
|
|
200
|
+
'applied', 'replacement', 0, 1, goal."text", goal."success_criteria",
|
|
201
|
+
goal."mutation_policy", 'Existing goal captured during policy activation',
|
|
202
|
+
CASE
|
|
203
|
+
WHEN goal."created_by" = 'scheduled_task' THEN 'scheduled_task'
|
|
204
|
+
WHEN goal."created_by" = 'agent' THEN 'agent'
|
|
205
|
+
ELSE 'api'
|
|
206
|
+
END,
|
|
207
|
+
goal."created_at"
|
|
208
|
+
FROM "session_goals" goal
|
|
209
|
+
ON CONFLICT ("workspace_id", "goal_id", "result_objective_revision")
|
|
210
|
+
WHERE "disposition" = 'applied'
|
|
211
|
+
DO NOTHING;
|
|
212
|
+
|
|
213
|
+
DROP TRIGGER IF EXISTS session_goal_revisions_bound_insert
|
|
214
|
+
ON "session_goal_revisions";
|
|
215
|
+
CREATE TRIGGER session_goal_revisions_bound_insert
|
|
216
|
+
BEFORE INSERT ON "session_goal_revisions"
|
|
217
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_revision_bound_insert();
|
|
218
|
+
|
|
219
|
+
CREATE OR REPLACE FUNCTION session_goal_revision_before_write()
|
|
220
|
+
RETURNS trigger
|
|
221
|
+
LANGUAGE plpgsql
|
|
222
|
+
AS $$
|
|
223
|
+
DECLARE
|
|
224
|
+
semantic_change boolean;
|
|
225
|
+
BEGIN
|
|
226
|
+
IF TG_OP = 'INSERT' THEN
|
|
227
|
+
IF octet_length(NEW."text") > 8192 THEN
|
|
228
|
+
RAISE EXCEPTION 'goal text exceeds 8192 UTF-8 bytes'
|
|
229
|
+
USING ERRCODE = '22001';
|
|
230
|
+
END IF;
|
|
231
|
+
IF NEW."success_criteria" IS NOT NULL
|
|
232
|
+
AND octet_length(NEW."success_criteria") > 8192 THEN
|
|
233
|
+
RAISE EXCEPTION 'goal success criteria exceeds 8192 UTF-8 bytes'
|
|
234
|
+
USING ERRCODE = '22001';
|
|
235
|
+
END IF;
|
|
236
|
+
IF NEW."objective_revision" <> 1 THEN
|
|
237
|
+
RAISE EXCEPTION 'a new goal must start at objective revision 1'
|
|
238
|
+
USING ERRCODE = '23514';
|
|
239
|
+
END IF;
|
|
240
|
+
RETURN NEW;
|
|
241
|
+
END IF;
|
|
242
|
+
|
|
243
|
+
semantic_change :=
|
|
244
|
+
NEW."text" IS DISTINCT FROM OLD."text"
|
|
245
|
+
OR NEW."success_criteria" IS DISTINCT FROM OLD."success_criteria"
|
|
246
|
+
OR NEW."mutation_policy" IS DISTINCT FROM OLD."mutation_policy";
|
|
247
|
+
|
|
248
|
+
IF semantic_change THEN
|
|
249
|
+
IF octet_length(NEW."text") > 8192 THEN
|
|
250
|
+
RAISE EXCEPTION 'goal text exceeds 8192 UTF-8 bytes'
|
|
251
|
+
USING ERRCODE = '22001';
|
|
252
|
+
END IF;
|
|
253
|
+
IF NEW."success_criteria" IS NOT NULL
|
|
254
|
+
AND octet_length(NEW."success_criteria") > 8192 THEN
|
|
255
|
+
RAISE EXCEPTION 'goal success criteria exceeds 8192 UTF-8 bytes'
|
|
256
|
+
USING ERRCODE = '22001';
|
|
257
|
+
END IF;
|
|
258
|
+
IF NEW."objective_revision" = OLD."objective_revision" THEN
|
|
259
|
+
-- Rolling-old writers know only the lifecycle version. Preserve their
|
|
260
|
+
-- semantic mutation while still advancing the new exact objective fence.
|
|
261
|
+
NEW."objective_revision" := OLD."objective_revision" + 1;
|
|
262
|
+
ELSIF NEW."objective_revision" <> OLD."objective_revision" + 1 THEN
|
|
263
|
+
RAISE EXCEPTION 'goal objective revision must advance exactly once'
|
|
264
|
+
USING ERRCODE = '40001';
|
|
265
|
+
END IF;
|
|
266
|
+
ELSIF NEW."objective_revision" <> OLD."objective_revision" THEN
|
|
267
|
+
RAISE EXCEPTION 'goal objective revision changed without semantic content'
|
|
268
|
+
USING ERRCODE = '23514';
|
|
269
|
+
END IF;
|
|
270
|
+
RETURN NEW;
|
|
271
|
+
END;
|
|
272
|
+
$$;
|
|
273
|
+
|
|
274
|
+
CREATE OR REPLACE FUNCTION session_goal_revision_after_write()
|
|
275
|
+
RETURNS trigger
|
|
276
|
+
LANGUAGE plpgsql
|
|
277
|
+
AS $$
|
|
278
|
+
DECLARE
|
|
279
|
+
semantic_change boolean := TG_OP = 'INSERT';
|
|
280
|
+
base_revision integer := 0;
|
|
281
|
+
change_kind text := 'replacement';
|
|
282
|
+
change_rationale text := 'Goal created';
|
|
283
|
+
change_actor text;
|
|
284
|
+
change_turn_id uuid;
|
|
285
|
+
change_attempt_id uuid;
|
|
286
|
+
source_proposal_id uuid;
|
|
287
|
+
BEGIN
|
|
288
|
+
IF TG_OP = 'UPDATE' THEN
|
|
289
|
+
semantic_change :=
|
|
290
|
+
NEW."text" IS DISTINCT FROM OLD."text"
|
|
291
|
+
OR NEW."success_criteria" IS DISTINCT FROM OLD."success_criteria"
|
|
292
|
+
OR NEW."mutation_policy" IS DISTINCT FROM OLD."mutation_policy";
|
|
293
|
+
base_revision := OLD."objective_revision";
|
|
294
|
+
change_rationale := 'Goal changed by a rolling-compatible writer';
|
|
295
|
+
END IF;
|
|
296
|
+
IF NOT semantic_change THEN
|
|
297
|
+
RETURN NEW;
|
|
298
|
+
END IF;
|
|
299
|
+
|
|
300
|
+
change_kind := COALESCE(
|
|
301
|
+
NULLIF(current_setting('opengeni.goal_change_kind', true), ''),
|
|
302
|
+
change_kind
|
|
303
|
+
);
|
|
304
|
+
change_rationale := COALESCE(
|
|
305
|
+
NULLIF(current_setting('opengeni.goal_change_rationale', true), ''),
|
|
306
|
+
change_rationale
|
|
307
|
+
);
|
|
308
|
+
change_actor := COALESCE(
|
|
309
|
+
NULLIF(current_setting('opengeni.goal_change_actor', true), ''),
|
|
310
|
+
CASE
|
|
311
|
+
WHEN NEW."created_by" = 'scheduled_task' THEN 'scheduled_task'
|
|
312
|
+
WHEN NEW."created_by" = 'agent' THEN 'agent'
|
|
313
|
+
ELSE 'api'
|
|
314
|
+
END
|
|
315
|
+
);
|
|
316
|
+
change_turn_id := NULLIF(
|
|
317
|
+
current_setting('opengeni.goal_change_turn_id', true), ''
|
|
318
|
+
)::uuid;
|
|
319
|
+
change_attempt_id := NULLIF(
|
|
320
|
+
current_setting('opengeni.goal_change_attempt_id', true), ''
|
|
321
|
+
)::uuid;
|
|
322
|
+
source_proposal_id := NULLIF(
|
|
323
|
+
current_setting('opengeni.goal_change_proposal_id', true), ''
|
|
324
|
+
)::uuid;
|
|
325
|
+
|
|
326
|
+
INSERT INTO "session_goal_revisions" (
|
|
327
|
+
"account_id", "workspace_id", "session_id", "goal_id", "disposition",
|
|
328
|
+
"change_kind", "base_objective_revision", "result_objective_revision",
|
|
329
|
+
"text", "success_criteria", "mutation_policy", "rationale", "actor",
|
|
330
|
+
"actor_turn_id", "actor_attempt_id", "proposal_id", "created_at"
|
|
331
|
+
) VALUES (
|
|
332
|
+
NEW."account_id", NEW."workspace_id", NEW."session_id", NEW."id",
|
|
333
|
+
'applied', change_kind, base_revision, NEW."objective_revision", NEW."text",
|
|
334
|
+
NEW."success_criteria", NEW."mutation_policy", change_rationale,
|
|
335
|
+
change_actor, change_turn_id, change_attempt_id, source_proposal_id, now()
|
|
336
|
+
)
|
|
337
|
+
ON CONFLICT ("workspace_id", "goal_id", "result_objective_revision")
|
|
338
|
+
WHERE "disposition" = 'applied'
|
|
339
|
+
DO NOTHING;
|
|
340
|
+
RETURN NEW;
|
|
341
|
+
END;
|
|
342
|
+
$$;
|
|
343
|
+
|
|
344
|
+
DROP TRIGGER IF EXISTS session_goal_revision_before_write_trigger ON "session_goals";
|
|
345
|
+
CREATE TRIGGER session_goal_revision_before_write_trigger
|
|
346
|
+
BEFORE INSERT OR UPDATE OF "text", "success_criteria", "mutation_policy", "objective_revision"
|
|
347
|
+
ON "session_goals"
|
|
348
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_revision_before_write();
|
|
349
|
+
|
|
350
|
+
DROP TRIGGER IF EXISTS session_goal_revision_after_write_trigger ON "session_goals";
|
|
351
|
+
CREATE TRIGGER session_goal_revision_after_write_trigger
|
|
352
|
+
AFTER INSERT OR UPDATE OF "text", "success_criteria", "mutation_policy"
|
|
353
|
+
ON "session_goals"
|
|
354
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_revision_after_write();
|
|
355
|
+
|
|
356
|
+
CREATE OR REPLACE FUNCTION session_goal_prompt_projection(
|
|
357
|
+
value text,
|
|
358
|
+
max_bytes integer
|
|
359
|
+
)
|
|
360
|
+
RETURNS text
|
|
361
|
+
LANGUAGE plpgsql
|
|
362
|
+
IMMUTABLE
|
|
363
|
+
STRICT
|
|
364
|
+
AS $$
|
|
365
|
+
DECLARE
|
|
366
|
+
original_bytes integer := octet_length(value);
|
|
367
|
+
marker text;
|
|
368
|
+
budget integer;
|
|
369
|
+
lower_chars integer := 0;
|
|
370
|
+
upper_chars integer := length(value);
|
|
371
|
+
midpoint integer;
|
|
372
|
+
BEGIN
|
|
373
|
+
IF original_bytes <= max_bytes THEN
|
|
374
|
+
RETURN value;
|
|
375
|
+
END IF;
|
|
376
|
+
marker := E'\n[truncated; original UTF-8 bytes=' || original_bytes::text || ']';
|
|
377
|
+
budget := greatest(0, max_bytes - octet_length(marker));
|
|
378
|
+
WHILE lower_chars < upper_chars LOOP
|
|
379
|
+
midpoint := (lower_chars + upper_chars + 1) / 2;
|
|
380
|
+
IF octet_length(left(value, midpoint)) <= budget THEN
|
|
381
|
+
lower_chars := midpoint;
|
|
382
|
+
ELSE
|
|
383
|
+
upper_chars := midpoint - 1;
|
|
384
|
+
END IF;
|
|
385
|
+
END LOOP;
|
|
386
|
+
RETURN left(value, lower_chars) || marker;
|
|
387
|
+
END;
|
|
388
|
+
$$;
|
|
389
|
+
|
|
390
|
+
CREATE OR REPLACE FUNCTION session_goal_freeze_turn_snapshot()
|
|
391
|
+
RETURNS trigger
|
|
392
|
+
LANGUAGE plpgsql
|
|
393
|
+
AS $$
|
|
394
|
+
DECLARE
|
|
395
|
+
goal_row "session_goals"%ROWTYPE;
|
|
396
|
+
BEGIN
|
|
397
|
+
SELECT * INTO goal_row
|
|
398
|
+
FROM "session_goals"
|
|
399
|
+
WHERE "workspace_id" = NEW."workspace_id"
|
|
400
|
+
AND "session_id" = NEW."session_id";
|
|
401
|
+
|
|
402
|
+
IF FOUND THEN
|
|
403
|
+
NEW."goal_snapshot" := jsonb_build_object(
|
|
404
|
+
'state', goal_row."status",
|
|
405
|
+
'goalId', goal_row."id"::text,
|
|
406
|
+
'objectiveRevision', goal_row."objective_revision",
|
|
407
|
+
'text', session_goal_prompt_projection(goal_row."text", 8192),
|
|
408
|
+
'successCriteria', to_jsonb(
|
|
409
|
+
session_goal_prompt_projection(goal_row."success_criteria", 8192)
|
|
410
|
+
),
|
|
411
|
+
'mutationPolicy', goal_row."mutation_policy",
|
|
412
|
+
'capturedAt', to_char(
|
|
413
|
+
NEW."created_at" AT TIME ZONE 'UTC',
|
|
414
|
+
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
|
|
415
|
+
)
|
|
416
|
+
);
|
|
417
|
+
ELSE
|
|
418
|
+
NEW."goal_snapshot" := jsonb_build_object(
|
|
419
|
+
'state', 'none',
|
|
420
|
+
'capturedAt', to_char(
|
|
421
|
+
NEW."created_at" AT TIME ZONE 'UTC',
|
|
422
|
+
'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'
|
|
423
|
+
)
|
|
424
|
+
);
|
|
425
|
+
END IF;
|
|
426
|
+
RETURN NEW;
|
|
427
|
+
END;
|
|
428
|
+
$$;
|
|
429
|
+
|
|
430
|
+
CREATE OR REPLACE FUNCTION session_goal_reject_turn_snapshot_mutation()
|
|
431
|
+
RETURNS trigger
|
|
432
|
+
LANGUAGE plpgsql
|
|
433
|
+
AS $$
|
|
434
|
+
BEGIN
|
|
435
|
+
IF OLD."goal_snapshot" IS NOT NULL
|
|
436
|
+
AND NEW."goal_snapshot" IS DISTINCT FROM OLD."goal_snapshot" THEN
|
|
437
|
+
RAISE EXCEPTION 'turn goal snapshot is immutable after acceptance'
|
|
438
|
+
USING ERRCODE = '55000';
|
|
439
|
+
END IF;
|
|
440
|
+
RETURN NEW;
|
|
441
|
+
END;
|
|
442
|
+
$$;
|
|
443
|
+
|
|
444
|
+
DROP TRIGGER IF EXISTS session_turns_goal_snapshot_insert ON "session_turns";
|
|
445
|
+
CREATE TRIGGER session_turns_goal_snapshot_insert
|
|
446
|
+
BEFORE INSERT ON "session_turns"
|
|
447
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_freeze_turn_snapshot();
|
|
448
|
+
|
|
449
|
+
DROP TRIGGER IF EXISTS session_turns_goal_snapshot_immutable ON "session_turns";
|
|
450
|
+
CREATE TRIGGER session_turns_goal_snapshot_immutable
|
|
451
|
+
BEFORE UPDATE OF "goal_snapshot" ON "session_turns"
|
|
452
|
+
FOR EACH ROW EXECUTE FUNCTION session_goal_reject_turn_snapshot_mutation();
|
|
453
|
+
|
|
454
|
+
DROP INDEX IF EXISTS "session_command_receipts_goal_progress_operation_uq";
|
|
455
|
+
CREATE UNIQUE INDEX "session_command_receipts_goal_progress_operation_uq"
|
|
456
|
+
ON "session_command_receipts" (
|
|
457
|
+
"workspace_id", "action", "target_session_id", "operation_key"
|
|
458
|
+
) WHERE "action" = 'goal.progress';
|
|
459
|
+
|
|
460
|
+
UPDATE "sessions"
|
|
461
|
+
SET "first_party_mcp_tools" = "first_party_mcp_tools" || '["goal_progress"]'::jsonb
|
|
462
|
+
WHERE "first_party_mcp_tools" ? 'goal_update'
|
|
463
|
+
AND NOT "first_party_mcp_tools" ? 'goal_progress';
|
|
464
|
+
|
|
465
|
+
DO $$
|
|
466
|
+
BEGIN
|
|
467
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
468
|
+
GRANT SELECT, INSERT ON "session_goal_revisions" TO opengeni_app;
|
|
469
|
+
REVOKE UPDATE, DELETE ON "session_goal_revisions" FROM opengeni_app;
|
|
470
|
+
END IF;
|
|
471
|
+
END $$;
|