@opengeni/db 0.26.0 → 0.27.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.
@@ -0,0 +1,202 @@
1
+ -- deployment-mode: rolling
2
+
3
+ -- Onboarding inputs create immutable proposal receipts plus ordinary inactive
4
+ -- instruction-policy revisions. This table is provenance/audit evidence only:
5
+ -- it never writes or owns an active policy head.
6
+ CREATE TABLE "workspace_instruction_policy_onboarding_proposals" (
7
+ "id" uuid PRIMARY KEY DEFAULT gen_random_uuid(),
8
+ "operation_id" uuid NOT NULL,
9
+ "request_fingerprint" text NOT NULL,
10
+ "account_id" uuid NOT NULL REFERENCES "managed_accounts"("id") ON DELETE CASCADE,
11
+ "workspace_id" uuid NOT NULL REFERENCES "workspaces"("id") ON DELETE CASCADE,
12
+ "kind" text NOT NULL,
13
+ "scope" text NOT NULL,
14
+ "role_key" text,
15
+ "source_id" text NOT NULL,
16
+ "source_version" text NOT NULL,
17
+ "confidence_bps" integer NOT NULL,
18
+ "baseline_revision_id" uuid REFERENCES "workspace_instruction_policy_revisions"("id")
19
+ ON DELETE RESTRICT,
20
+ "baseline_revision" bigint,
21
+ "baseline_content_hash" text,
22
+ "baseline_activation_version" bigint NOT NULL,
23
+ "baseline_activated_at" timestamptz,
24
+ "draft_revision_id" uuid NOT NULL REFERENCES "workspace_instruction_policy_revisions"("id")
25
+ ON DELETE RESTRICT,
26
+ "draft_revision" bigint NOT NULL,
27
+ "draft_content_hash" text NOT NULL,
28
+ "status" text NOT NULL DEFAULT 'proposed',
29
+ "created_by_subject_id" text NOT NULL,
30
+ "created_at" timestamptz NOT NULL DEFAULT now(),
31
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_operation_receipt_chk" CHECK (
32
+ "request_fingerprint" ~ '^[0-9a-f]{64}$'
33
+ ),
34
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_target_chk" CHECK (
35
+ ("kind" = 'charter' AND "scope" = 'global' AND "role_key" IS NULL)
36
+ OR ("kind" = 'policy' AND "scope" = 'global' AND "role_key" IS NULL)
37
+ OR ("kind" = 'policy' AND "scope" = 'role' AND "role_key" IS NOT NULL)
38
+ ),
39
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_role_key_chk" CHECK (
40
+ "role_key" IS NULL
41
+ OR (
42
+ "role_key" = lower(btrim("role_key"))
43
+ AND length("role_key") BETWEEN 1 AND 64
44
+ AND "role_key" ~ '^[a-z0-9](?:[a-z0-9._-]*[a-z0-9])?$'
45
+ AND "role_key" !~ '--'
46
+ )
47
+ ),
48
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_source_chk" CHECK (
49
+ length(btrim("source_id")) BETWEEN 1 AND 512
50
+ AND length(btrim("source_version")) BETWEEN 1 AND 256
51
+ AND "confidence_bps" BETWEEN 0 AND 10000
52
+ ),
53
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_baseline_chk" CHECK (
54
+ (
55
+ "baseline_revision_id" IS NULL
56
+ AND "baseline_revision" IS NULL
57
+ AND "baseline_content_hash" IS NULL
58
+ AND "baseline_activation_version" = 0
59
+ AND "baseline_activated_at" IS NULL
60
+ ) OR (
61
+ "baseline_revision_id" IS NOT NULL
62
+ AND "baseline_revision" > 0
63
+ AND "baseline_content_hash" ~ '^[0-9a-f]{64}$'
64
+ AND "baseline_activation_version" > 0
65
+ AND "baseline_activated_at" IS NOT NULL
66
+ )
67
+ ),
68
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_draft_chk" CHECK (
69
+ "draft_revision" > 0
70
+ AND "draft_content_hash" ~ '^[0-9a-f]{64}$'
71
+ AND "status" = 'proposed'
72
+ ),
73
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_actor_chk" CHECK (
74
+ length(btrim("created_by_subject_id")) BETWEEN 1 AND 1024
75
+ ),
76
+ CONSTRAINT "workspace_instruction_policy_onboarding_proposals_workspace_operation_uq"
77
+ UNIQUE ("workspace_id", "operation_id")
78
+ );
79
+
80
+ CREATE UNIQUE INDEX "workspace_instruction_policy_onboarding_proposals_source_version_target_uq"
81
+ ON "workspace_instruction_policy_onboarding_proposals"
82
+ (
83
+ "workspace_id",
84
+ "kind",
85
+ "scope",
86
+ coalesce("role_key", ''),
87
+ "source_id",
88
+ "source_version"
89
+ );
90
+
91
+ CREATE INDEX "workspace_instruction_policy_onboarding_proposals_workspace_time_idx"
92
+ ON "workspace_instruction_policy_onboarding_proposals"
93
+ ("workspace_id", "created_at" DESC, "id" DESC);
94
+
95
+ CREATE OR REPLACE FUNCTION workspace_instruction_policy_validate_onboarding_proposal()
96
+ RETURNS trigger
97
+ LANGUAGE plpgsql
98
+ AS $$
99
+ BEGIN
100
+ IF NEW."baseline_revision_id" IS NULL THEN
101
+ IF EXISTS (
102
+ SELECT 1
103
+ FROM "workspace_instruction_policy_heads" head
104
+ WHERE head."account_id" = NEW."account_id"
105
+ AND head."workspace_id" = NEW."workspace_id"
106
+ AND head."kind" = NEW."kind"
107
+ AND head."scope" = NEW."scope"
108
+ AND head."role_key" IS NOT DISTINCT FROM NEW."role_key"
109
+ ) THEN
110
+ RAISE EXCEPTION 'instruction-policy onboarding proposal must capture the exact active head baseline'
111
+ USING ERRCODE = '23514';
112
+ END IF;
113
+ ELSIF NOT EXISTS (
114
+ SELECT 1
115
+ FROM "workspace_instruction_policy_heads" head
116
+ WHERE head."account_id" = NEW."account_id"
117
+ AND head."workspace_id" = NEW."workspace_id"
118
+ AND head."kind" = NEW."kind"
119
+ AND head."scope" = NEW."scope"
120
+ AND head."role_key" IS NOT DISTINCT FROM NEW."role_key"
121
+ AND head."revision_id" = NEW."baseline_revision_id"
122
+ AND head."revision" = NEW."baseline_revision"
123
+ AND head."content_hash" = NEW."baseline_content_hash"
124
+ AND head."activation_version" = NEW."baseline_activation_version"
125
+ AND head."activated_at" = NEW."baseline_activated_at"
126
+ ) THEN
127
+ RAISE EXCEPTION 'instruction-policy onboarding proposal must capture the exact active head baseline'
128
+ USING ERRCODE = '23514';
129
+ END IF;
130
+
131
+ IF NEW."baseline_revision_id" IS NOT NULL AND NOT EXISTS (
132
+ SELECT 1
133
+ FROM "workspace_instruction_policy_revisions" revision
134
+ WHERE revision."id" = NEW."baseline_revision_id"
135
+ AND revision."account_id" = NEW."account_id"
136
+ AND revision."workspace_id" = NEW."workspace_id"
137
+ AND revision."kind" = NEW."kind"
138
+ AND revision."scope" = NEW."scope"
139
+ AND revision."role_key" IS NOT DISTINCT FROM NEW."role_key"
140
+ AND revision."revision" = NEW."baseline_revision"
141
+ AND revision."content_hash" = NEW."baseline_content_hash"
142
+ ) THEN
143
+ RAISE EXCEPTION 'instruction-policy onboarding proposal has an invalid baseline revision'
144
+ USING ERRCODE = '23514';
145
+ END IF;
146
+
147
+ IF NOT EXISTS (
148
+ SELECT 1
149
+ FROM "workspace_instruction_policy_revisions" revision
150
+ WHERE revision."id" = NEW."draft_revision_id"
151
+ AND revision."operation_id" = NEW."operation_id"
152
+ AND revision."request_fingerprint" = NEW."request_fingerprint"
153
+ AND revision."account_id" = NEW."account_id"
154
+ AND revision."workspace_id" = NEW."workspace_id"
155
+ AND revision."kind" = NEW."kind"
156
+ AND revision."scope" = NEW."scope"
157
+ AND revision."role_key" IS NOT DISTINCT FROM NEW."role_key"
158
+ AND revision."revision" = NEW."draft_revision"
159
+ AND revision."content_hash" = NEW."draft_content_hash"
160
+ AND revision."provenance_source" = 'onboarding'
161
+ AND revision."provenance_source_id" = NEW."id"::text
162
+ AND revision."supersedes_revision_id" IS NOT DISTINCT FROM NEW."baseline_revision_id"
163
+ AND revision."created_by_subject_id" = NEW."created_by_subject_id"
164
+ ) THEN
165
+ RAISE EXCEPTION 'instruction-policy onboarding proposal must identify its exact inactive draft'
166
+ USING ERRCODE = '23514';
167
+ END IF;
168
+
169
+ IF EXISTS (
170
+ SELECT 1
171
+ FROM "workspace_instruction_policy_heads" head
172
+ WHERE head."account_id" = NEW."account_id"
173
+ AND head."workspace_id" = NEW."workspace_id"
174
+ AND head."revision_id" = NEW."draft_revision_id"
175
+ ) OR EXISTS (
176
+ SELECT 1
177
+ FROM "workspace_instruction_policy_activation_events" event
178
+ WHERE event."account_id" = NEW."account_id"
179
+ AND event."workspace_id" = NEW."workspace_id"
180
+ AND event."new_revision_id" = NEW."draft_revision_id"
181
+ ) THEN
182
+ RAISE EXCEPTION 'instruction-policy onboarding proposal must identify a never-activated inactive draft'
183
+ USING ERRCODE = '23514';
184
+ END IF;
185
+ RETURN NEW;
186
+ END;
187
+ $$;
188
+
189
+ CREATE TRIGGER workspace_instruction_policy_onboarding_proposals_validate_draft
190
+ BEFORE INSERT OR UPDATE ON "workspace_instruction_policy_onboarding_proposals"
191
+ FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_validate_onboarding_proposal();
192
+
193
+ CREATE TRIGGER workspace_instruction_policy_onboarding_proposals_immutable
194
+ BEFORE UPDATE OR DELETE ON "workspace_instruction_policy_onboarding_proposals"
195
+ FOR EACH ROW EXECUTE FUNCTION workspace_instruction_policy_reject_mutation();
196
+
197
+ ALTER TABLE "workspace_instruction_policy_onboarding_proposals" ENABLE ROW LEVEL SECURITY;
198
+ ALTER TABLE "workspace_instruction_policy_onboarding_proposals" FORCE ROW LEVEL SECURITY;
199
+
200
+ CREATE POLICY workspace_isolation ON "workspace_instruction_policy_onboarding_proposals"
201
+ USING (opengeni_private.workspace_rls_visible("account_id", "workspace_id"))
202
+ WITH CHECK (opengeni_private.workspace_rls_visible("account_id", "workspace_id"));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeni/db",
3
- "version": "0.26.0",
3
+ "version": "0.27.0",
4
4
  "description": "OpenGeni persistence: Drizzle schema, RLS-scoped query layer, the SQL migration runner, and role provisioning.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -51,8 +51,8 @@
51
51
  },
52
52
  "dependencies": {
53
53
  "@opengeni/codex": "^0.2.10",
54
- "@opengeni/config": "^0.10.6",
55
- "@opengeni/contracts": "^0.35.0",
54
+ "@opengeni/config": "^0.10.7",
55
+ "@opengeni/contracts": "^0.36.0",
56
56
  "@opengeni/network": "^0.1.1",
57
57
  "drizzle-orm": "^0.45.2",
58
58
  "postgres": "^3.4.7"
@@ -126,6 +126,7 @@ export const FORCE_RLS_TABLES = [
126
126
  "workspace_inference_controls",
127
127
  "workspace_instruction_policy_activation_events",
128
128
  "workspace_instruction_policy_heads",
129
+ "workspace_instruction_policy_onboarding_proposals",
129
130
  "workspace_instruction_policy_revisions",
130
131
  "workspace_instruction_policy_snapshots",
131
132
  "workspace_model_policies",
@@ -294,6 +295,7 @@ export const RUNTIME_READ_INSERT_TABLES = [
294
295
  "workspace_artifact_events",
295
296
  "workspace_artifact_versions",
296
297
  "workspace_instruction_policy_activation_events",
298
+ "workspace_instruction_policy_onboarding_proposals",
297
299
  "workspace_instruction_policy_revisions",
298
300
  ] as const;
299
301
 
@@ -172,6 +172,92 @@ export const workspaceInstructionPolicyActivationEvents = pgTable(
172
172
  }),
173
173
  );
174
174
 
175
+ export const workspaceInstructionPolicyOnboardingProposals = pgTable(
176
+ "workspace_instruction_policy_onboarding_proposals",
177
+ {
178
+ id: uuid("id").primaryKey().defaultRandom(),
179
+ operationId: uuid("operation_id").notNull(),
180
+ requestFingerprint: text("request_fingerprint").notNull(),
181
+ accountId: uuid("account_id").notNull(),
182
+ workspaceId: uuid("workspace_id").notNull(),
183
+ kind: text("kind").notNull(),
184
+ scope: text("scope").notNull(),
185
+ roleKey: text("role_key"),
186
+ sourceId: text("source_id").notNull(),
187
+ sourceVersion: text("source_version").notNull(),
188
+ confidenceBps: integer("confidence_bps").notNull(),
189
+ baselineRevisionId: uuid("baseline_revision_id"),
190
+ baselineRevision: bigint("baseline_revision", { mode: "number" }),
191
+ baselineContentHash: text("baseline_content_hash"),
192
+ baselineActivationVersion: bigint("baseline_activation_version", { mode: "number" }).notNull(),
193
+ baselineActivatedAt: timestamp("baseline_activated_at", { withTimezone: true }),
194
+ draftRevisionId: uuid("draft_revision_id").notNull(),
195
+ draftRevision: bigint("draft_revision", { mode: "number" }).notNull(),
196
+ draftContentHash: text("draft_content_hash").notNull(),
197
+ status: text("status").notNull().default("proposed"),
198
+ createdBySubjectId: text("created_by_subject_id").notNull(),
199
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
200
+ },
201
+ (table) => ({
202
+ workspaceOperation: uniqueIndex(
203
+ "workspace_instruction_policy_onboarding_proposals_workspace_operation_uq",
204
+ ).on(table.workspaceId, table.operationId),
205
+ sourceVersionTarget: uniqueIndex(
206
+ "workspace_instruction_policy_onboarding_proposals_source_version_target_uq",
207
+ ).on(
208
+ table.workspaceId,
209
+ table.kind,
210
+ table.scope,
211
+ sql`coalesce(${table.roleKey}, '')`,
212
+ table.sourceId,
213
+ table.sourceVersion,
214
+ ),
215
+ workspaceTimeline: index(
216
+ "workspace_instruction_policy_onboarding_proposals_workspace_time_idx",
217
+ ).on(table.workspaceId, table.createdAt, table.id),
218
+ operationReceipt: check(
219
+ "workspace_instruction_policy_onboarding_proposals_operation_receipt_chk",
220
+ sql`${table.requestFingerprint} ~ '^[0-9a-f]{64}$'`,
221
+ ),
222
+ target: check(
223
+ "workspace_instruction_policy_onboarding_proposals_target_chk",
224
+ sql`(
225
+ (${table.kind} = 'charter' and ${table.scope} = 'global' and ${table.roleKey} is null)
226
+ or (${table.kind} = 'policy' and ${table.scope} = 'global' and ${table.roleKey} is null)
227
+ or (${table.kind} = 'policy' and ${table.scope} = 'role' and ${table.roleKey} is not null)
228
+ )`,
229
+ ),
230
+ source: check(
231
+ "workspace_instruction_policy_onboarding_proposals_source_chk",
232
+ sql`length(btrim(${table.sourceId})) between 1 and 512
233
+ and length(btrim(${table.sourceVersion})) between 1 and 256
234
+ and ${table.confidenceBps} between 0 and 10000`,
235
+ ),
236
+ baseline: check(
237
+ "workspace_instruction_policy_onboarding_proposals_baseline_chk",
238
+ sql`(
239
+ ${table.baselineRevisionId} is null
240
+ and ${table.baselineRevision} is null
241
+ and ${table.baselineContentHash} is null
242
+ and ${table.baselineActivationVersion} = 0
243
+ and ${table.baselineActivatedAt} is null
244
+ ) or (
245
+ ${table.baselineRevisionId} is not null
246
+ and ${table.baselineRevision} > 0
247
+ and ${table.baselineContentHash} ~ '^[0-9a-f]{64}$'
248
+ and ${table.baselineActivationVersion} > 0
249
+ and ${table.baselineActivatedAt} is not null
250
+ )`,
251
+ ),
252
+ draft: check(
253
+ "workspace_instruction_policy_onboarding_proposals_draft_chk",
254
+ sql`${table.draftRevision} > 0
255
+ and ${table.draftContentHash} ~ '^[0-9a-f]{64}$'
256
+ and ${table.status} = 'proposed'`,
257
+ ),
258
+ }),
259
+ );
260
+
175
261
  export const workspaceInstructionPolicySnapshots = pgTable(
176
262
  "workspace_instruction_policy_snapshots",
177
263
  {