@opengeni/db 0.14.3 → 0.17.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.
Files changed (67) hide show
  1. package/dist/{chunk-Y5WZZVQK.js → chunk-SK7YYHBI.js} +5 -2
  2. package/dist/chunk-SK7YYHBI.js.map +1 -0
  3. package/dist/{chunk-ELMUCYZF.js → chunk-T6RSJT6C.js} +202 -43
  4. package/dist/chunk-T6RSJT6C.js.map +1 -0
  5. package/dist/chunk-TLAC622R.js +4990 -0
  6. package/dist/chunk-TLAC622R.js.map +1 -0
  7. package/dist/codex-token-resolver.d.ts +64 -0
  8. package/dist/connection-token-resolver.d.ts +90 -0
  9. package/dist/environment-crypto.d.ts +11 -0
  10. package/dist/event-payload-sanitizer.d.ts +32 -0
  11. package/dist/index.d.ts +6374 -10
  12. package/dist/index.js +8075 -2776
  13. package/dist/index.js.map +1 -1
  14. package/dist/insights.d.ts +157 -0
  15. package/dist/memory-domain.d.ts +44 -0
  16. package/dist/migrate.d.ts +5 -7
  17. package/dist/migrate.js +1 -1
  18. package/dist/new-session-drafts.d.ts +49 -0
  19. package/dist/persistence-errors.d.ts +69 -0
  20. package/dist/preference-registry-schema.d.ts +1147 -0
  21. package/dist/preference-registry.d.ts +878 -0
  22. package/dist/provision-roles.d.ts +4 -6489
  23. package/dist/provision-roles.js +1 -1
  24. package/dist/role-relationships.d.ts +35 -0
  25. package/dist/runtime-posture-cli.d.ts +1 -0
  26. package/dist/runtime-posture.d.ts +103 -0
  27. package/dist/schema.d.ts +25330 -3
  28. package/dist/schema.js +31 -1
  29. package/dist/session-control.d.ts +331 -0
  30. package/dist/session-queue-commands.d.ts +186 -0
  31. package/dist/session-tool-call-settlement.d.ts +32 -0
  32. package/dist/turn-initiator.d.ts +28 -0
  33. package/dist/workspace-artifacts.d.ts +62 -0
  34. package/dist/workspace-instruction-policies-schema.d.ts +735 -0
  35. package/dist/workspace-instruction-policies.d.ts +64 -0
  36. package/drizzle/0136_unified_session_tool_policy.sql +1 -1
  37. package/drizzle/0137_preference_registry.sql +1347 -0
  38. package/drizzle/0138_sandbox_checkpoint_artifacts_and_deadlines.sql +1074 -0
  39. package/drizzle/0139_codex_provider_artifact_invalidations.sql +51 -0
  40. package/drizzle/0140_sandbox_restore_and_reaper_fences.sql +276 -0
  41. package/drizzle/0142_sandbox_archive_capture_gate.sql +80 -0
  42. package/drizzle/0143_session_codex_compaction_mode.sql +20 -0
  43. package/drizzle/0144_sandbox_viewer_force_drain_gate.sql +95 -0
  44. package/drizzle/0145_model_call_facts.sql +96 -0
  45. package/drizzle/0146_slack_bot_delete_idempotency.sql +105 -0
  46. package/drizzle/0147_draft_latency_mode.sql +12 -0
  47. package/drizzle/0148_session_turn_latency_mode.sql +12 -0
  48. package/drizzle/0149_workspace_artifacts.sql +348 -0
  49. package/drizzle/0150_slack_task_interactions.sql +344 -0
  50. package/package.json +6 -6
  51. package/src/index.ts +5766 -275
  52. package/src/insights.ts +837 -0
  53. package/src/migrate.ts +9 -1
  54. package/src/new-session-drafts.ts +4 -0
  55. package/src/preference-registry-schema.ts +170 -0
  56. package/src/preference-registry.ts +1220 -0
  57. package/src/provision-roles.ts +95 -22
  58. package/src/role-relationships.ts +132 -0
  59. package/src/runtime-posture.ts +47 -27
  60. package/src/schema.ts +875 -19
  61. package/src/session-queue-commands.ts +39 -6
  62. package/src/workspace-artifacts.ts +751 -0
  63. package/dist/chunk-DW24CKCT.js +0 -4046
  64. package/dist/chunk-DW24CKCT.js.map +0 -1
  65. package/dist/chunk-ELMUCYZF.js.map +0 -1
  66. package/dist/chunk-Y5WZZVQK.js.map +0 -1
  67. package/dist/schema-DhkRhcuQ.d.ts +0 -22666
@@ -0,0 +1,1220 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS,
4
+ PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT,
5
+ PREFERENCE_REGISTRY_DESCRIPTOR_MAX_UTF8_BYTES,
6
+ PREFERENCE_REGISTRY_TITLE_MAX_CHARS,
7
+ PreferenceRegistryDescriptor,
8
+ PreferenceRegistryDetailResponse,
9
+ PreferenceRegistryEvent,
10
+ PreferenceRegistryFullContent,
11
+ PreferenceRegistryListResponse,
12
+ PreferenceRegistryRecord,
13
+ PreferenceRegistryRevisionSummary,
14
+ PreferenceRegistrySnapshot,
15
+ PreferenceRegistryScopeTarget,
16
+ type CreatePreferenceRegistryProposalRequest,
17
+ type PreferenceRegistryConflictStrategy,
18
+ type PreferenceRegistryProvenanceSource,
19
+ type PreferenceRegistryScope,
20
+ type PreferenceRegistryStatus,
21
+ type PreferenceRegistryTrust,
22
+ } from "@opengeni/contracts";
23
+ import { and, asc, desc, eq, gt, inArray, isNull, lte, or, sql, type SQL } from "drizzle-orm";
24
+ import type { Database } from "./index";
25
+ import { setSubjectRlsContext, withWorkspaceRls, withWorkspaceSubjectRls } from "./index";
26
+ import { nestedPostgresSqlState, safeDatabaseErrorFacts } from "./persistence-errors";
27
+ import * as schema from "./schema";
28
+
29
+ type PreferenceRow = typeof schema.preferenceRegistryPreferences.$inferSelect;
30
+ type RevisionRow = typeof schema.preferenceRegistryRevisions.$inferSelect;
31
+ type EventRow = typeof schema.preferenceRegistryEvents.$inferSelect;
32
+
33
+ const importedSources = new Set<PreferenceRegistryProvenanceSource>([
34
+ "knowledge_proposal",
35
+ "imported_document",
36
+ "slack",
37
+ "meeting_transcript",
38
+ "call_transcript",
39
+ ]);
40
+
41
+ export class PreferenceRegistryNotFoundError extends Error {
42
+ readonly name = "PreferenceRegistryNotFoundError";
43
+ }
44
+
45
+ export class PreferenceRegistryInvalidOperationError extends Error {
46
+ readonly name = "PreferenceRegistryInvalidOperationError";
47
+ }
48
+
49
+ export class PreferenceRegistryConflictError extends Error {
50
+ readonly name = "PreferenceRegistryConflictError";
51
+ readonly code = "PREFERENCE_REGISTRY_CONFLICT";
52
+
53
+ constructor(
54
+ message: string,
55
+ readonly currentRevisionId: string | null,
56
+ readonly scopeVersion: number | null,
57
+ ) {
58
+ super(message);
59
+ }
60
+ }
61
+
62
+ export class PreferenceRegistryInitiatorError extends Error {
63
+ readonly name = "PreferenceRegistryInitiatorError";
64
+ }
65
+
66
+ export class PreferenceRegistryStableKeyConflictError extends Error {
67
+ readonly name = "PreferenceRegistryStableKeyConflictError";
68
+ readonly code = "PREFERENCE_REGISTRY_STABLE_KEY_CONFLICT";
69
+ }
70
+
71
+ export type PreferenceRegistryAttemptClaims = {
72
+ accountId: string;
73
+ workspaceId: string;
74
+ sessionId: string;
75
+ turnId: string;
76
+ attemptId: string;
77
+ executionGeneration: number;
78
+ };
79
+
80
+ type PreferenceRegistryAttemptAuthority = PreferenceRegistryAttemptClaims & {
81
+ initiatingHumanSubjectId: string;
82
+ };
83
+
84
+ export type PreferenceRegistryScopeAuthorizer = (scope: PreferenceRegistryScope) => void;
85
+
86
+ function iso(value: Date | string): string {
87
+ return (value instanceof Date ? value : new Date(value)).toISOString();
88
+ }
89
+
90
+ function contentHash(value: string): string {
91
+ return createHash("sha256").update(value, "utf8").digest("hex");
92
+ }
93
+
94
+ /** Plain one-line descriptor text; never include full imported source content. */
95
+ export function sanitizePreferenceDescriptorText(value: string): string {
96
+ return value
97
+ .normalize("NFKC")
98
+ .replace(/[\p{Cc}\p{Cf}]/gu, " ")
99
+ .replace(/[<>{}[\]`]/g, " ")
100
+ .replace(/\s+/gu, " ")
101
+ .trim();
102
+ }
103
+
104
+ function boundedDescriptorText(value: string, maxChars: number): string {
105
+ return sanitizePreferenceDescriptorText(value).slice(0, maxChars).trim();
106
+ }
107
+
108
+ function isStableKeyConflict(error: unknown): boolean {
109
+ if (nestedPostgresSqlState(error) !== "23505") return false;
110
+ return (safeDatabaseErrorFacts(error).constraint ?? "").startsWith(
111
+ "preference_registry_preferences_",
112
+ );
113
+ }
114
+
115
+ function targetFor(
116
+ scope: PreferenceRegistryScope,
117
+ workspaceId: string,
118
+ subjectId: string,
119
+ ): PreferenceRegistryScopeTarget {
120
+ if (scope === "organization") return { scope, workspaceId: null, subjectId: null };
121
+ if (scope === "workspace") return { scope, workspaceId, subjectId: null };
122
+ return { scope, workspaceId: null, subjectId };
123
+ }
124
+
125
+ function targetFromRow(row: PreferenceRow): PreferenceRegistryScopeTarget {
126
+ return {
127
+ scope: row.scope as PreferenceRegistryScope,
128
+ workspaceId: row.scopeWorkspaceId,
129
+ subjectId: row.scopeSubjectId,
130
+ };
131
+ }
132
+
133
+ function trustFor(
134
+ scope: PreferenceRegistryScope,
135
+ source: PreferenceRegistryProvenanceSource,
136
+ ): PreferenceRegistryTrust {
137
+ if (importedSources.has(source)) return "untrusted_proposal";
138
+ if (scope === "organization") return "organization_managed";
139
+ if (scope === "workspace") return "workspace_managed";
140
+ return "personal";
141
+ }
142
+
143
+ function revisionSummary(row: RevisionRow, scope: PreferenceRegistryScope) {
144
+ return PreferenceRegistryRevisionSummary.parse({
145
+ id: row.id,
146
+ preferenceId: row.preferenceId,
147
+ revision: row.revision,
148
+ contentHash: row.contentHash,
149
+ title: row.title,
150
+ description: row.description,
151
+ precedence: {
152
+ tier: scope,
153
+ rank: row.precedenceRank,
154
+ conflictStrategy: row.conflictStrategy as PreferenceRegistryConflictStrategy,
155
+ conflictsWith: row.conflictsWith,
156
+ },
157
+ provenance: {
158
+ source: row.provenanceSource as PreferenceRegistryProvenanceSource,
159
+ sourceId: row.provenanceSourceId,
160
+ trust: row.trust as PreferenceRegistryTrust,
161
+ },
162
+ expiresAt: row.expiresAt ? iso(row.expiresAt) : null,
163
+ correctsRevisionId: row.correctsRevisionId,
164
+ createdBySubjectId: row.createdBySubjectId,
165
+ createdAt: iso(row.createdAt),
166
+ });
167
+ }
168
+
169
+ function effectiveStatus(
170
+ row: PreferenceRow,
171
+ revision: RevisionRow | null,
172
+ now: Date,
173
+ ): PreferenceRegistryStatus {
174
+ if (row.status === "active" && revision?.expiresAt && revision.expiresAt <= now) return "expired";
175
+ return row.status as PreferenceRegistryStatus;
176
+ }
177
+
178
+ function recordFromRows(row: PreferenceRow, active: RevisionRow | null, now = new Date()) {
179
+ return PreferenceRegistryRecord.parse({
180
+ id: row.id,
181
+ accountId: row.accountId,
182
+ stableKey: row.stableKey,
183
+ target: targetFromRow(row),
184
+ status: effectiveStatus(row, active, now),
185
+ scopeVersion: row.scopeVersion,
186
+ activationVersion: row.activationVersion,
187
+ activeRevision: active ? revisionSummary(active, row.scope as PreferenceRegistryScope) : null,
188
+ supersededByPreferenceId: row.supersededByPreferenceId,
189
+ createdBySubjectId: row.createdBySubjectId,
190
+ createdAt: iso(row.createdAt),
191
+ updatedAt: iso(row.updatedAt),
192
+ });
193
+ }
194
+
195
+ function eventTarget(scope: string | null, workspaceId: string | null, subjectId: string | null) {
196
+ return scope === null
197
+ ? null
198
+ : PreferenceRegistryScopeTarget.parse({ scope, workspaceId, subjectId });
199
+ }
200
+
201
+ function eventFromRow(row: EventRow) {
202
+ return PreferenceRegistryEvent.parse({
203
+ id: row.id,
204
+ accountId: row.accountId,
205
+ preferenceId: row.preferenceId,
206
+ type: row.type,
207
+ version: row.version,
208
+ oldRevisionId: row.oldRevisionId,
209
+ newRevisionId: row.newRevisionId,
210
+ oldTarget: eventTarget(row.oldScope, row.oldWorkspaceId, row.oldSubjectId),
211
+ newTarget: eventTarget(row.newScope, row.newWorkspaceId, row.newSubjectId),
212
+ relatedPreferenceId: row.relatedPreferenceId,
213
+ actorSubjectId: row.actorSubjectId,
214
+ reason: row.reason,
215
+ createdAt: iso(row.createdAt),
216
+ });
217
+ }
218
+
219
+ async function lockPreferenceIds(db: Database, ids: readonly string[]): Promise<string[]> {
220
+ const uniqueIds = [...new Set(ids)].sort();
221
+ const idArray = sql.join(
222
+ uniqueIds.map((id) => sql`${id}::uuid`),
223
+ sql`, `,
224
+ );
225
+ const rows = (await db.execute(sql`
226
+ SELECT preference_id
227
+ FROM preference_registry_lock_heads(ARRAY[${idArray}]::uuid[])
228
+ `)) as unknown as Array<{ preference_id: string }>;
229
+ const lockedIds = rows.map((row) => row.preference_id).sort();
230
+ if (
231
+ lockedIds.length !== uniqueIds.length ||
232
+ lockedIds.some((id, index) => id !== uniqueIds[index])
233
+ ) {
234
+ throw new PreferenceRegistryNotFoundError("Preference was not found");
235
+ }
236
+ return uniqueIds;
237
+ }
238
+
239
+ async function lockedPreference(db: Database, id: string): Promise<PreferenceRow> {
240
+ await lockPreferenceIds(db, [id]);
241
+ const [row] = await db
242
+ .select()
243
+ .from(schema.preferenceRegistryPreferences)
244
+ .where(eq(schema.preferenceRegistryPreferences.id, id))
245
+ .limit(1);
246
+ if (!row) throw new PreferenceRegistryNotFoundError("Preference was not found");
247
+ return row;
248
+ }
249
+
250
+ async function lockedPreferences(db: Database, ids: readonly string[]): Promise<PreferenceRow[]> {
251
+ const uniqueIds = await lockPreferenceIds(db, ids);
252
+ const rows = await db
253
+ .select()
254
+ .from(schema.preferenceRegistryPreferences)
255
+ .where(inArray(schema.preferenceRegistryPreferences.id, uniqueIds))
256
+ .orderBy(asc(schema.preferenceRegistryPreferences.id));
257
+ if (rows.length !== uniqueIds.length) {
258
+ throw new PreferenceRegistryNotFoundError("Preference was not found");
259
+ }
260
+ return rows;
261
+ }
262
+
263
+ async function revisionForPreference(
264
+ db: Database,
265
+ preferenceId: string,
266
+ revisionId: string,
267
+ ): Promise<RevisionRow> {
268
+ const [row] = await db
269
+ .select()
270
+ .from(schema.preferenceRegistryRevisions)
271
+ .where(
272
+ and(
273
+ eq(schema.preferenceRegistryRevisions.preferenceId, preferenceId),
274
+ eq(schema.preferenceRegistryRevisions.id, revisionId),
275
+ ),
276
+ )
277
+ .limit(1);
278
+ if (!row) throw new PreferenceRegistryNotFoundError("Preference revision was not found");
279
+ return row;
280
+ }
281
+
282
+ function targetColumns(target: PreferenceRegistryScopeTarget) {
283
+ return {
284
+ scope: target.scope,
285
+ scopeWorkspaceId: target.workspaceId,
286
+ scopeSubjectId: target.subjectId,
287
+ };
288
+ }
289
+
290
+ async function withPreferenceRegistryGovernanceRls<T>(
291
+ db: Database,
292
+ input: {
293
+ workspaceId: string;
294
+ actorSubjectId: string;
295
+ principalKind: string | undefined;
296
+ },
297
+ fn: (db: Database) => Promise<T>,
298
+ ): Promise<T> {
299
+ if (input.principalKind !== "human_session") {
300
+ throw new PreferenceRegistryInitiatorError(
301
+ "Preference governance requires an authenticated human session principal",
302
+ );
303
+ }
304
+ return await withWorkspaceSubjectRls(
305
+ db,
306
+ input.workspaceId,
307
+ input.actorSubjectId,
308
+ async (scopedDb) => {
309
+ const rows = (await scopedDb.execute(sql`
310
+ SELECT set_config('opengeni.principal_kind', ${input.principalKind}, true)
311
+ AS principal_kind
312
+ `)) as unknown as Array<{ principal_kind: string }>;
313
+ if (rows[0]?.principal_kind !== "human_session") {
314
+ throw new PreferenceRegistryInitiatorError(
315
+ "Preference governance principal kind was not applied to the transaction",
316
+ );
317
+ }
318
+ return await fn(scopedDb);
319
+ },
320
+ );
321
+ }
322
+
323
+ function requireExpectedScopeVersion(row: PreferenceRow, expectedScopeVersion: number): void {
324
+ if (row.scopeVersion !== expectedScopeVersion) {
325
+ throw new PreferenceRegistryConflictError(
326
+ "The preference scope changed in another request",
327
+ row.activeRevisionId,
328
+ row.scopeVersion,
329
+ );
330
+ }
331
+ }
332
+
333
+ async function lifecycleEvent(
334
+ db: Database,
335
+ input: {
336
+ operation:
337
+ | "proposal_created"
338
+ | "activate"
339
+ | "correct"
340
+ | "reject"
341
+ | "deactivate"
342
+ | "supersede"
343
+ | "scope";
344
+ preferenceId: string;
345
+ expectedScopeVersion: number;
346
+ expectedRevisionId: string | null;
347
+ revisionId?: string | null;
348
+ newScope?: PreferenceRegistryScope | null;
349
+ relatedPreferenceId?: string | null;
350
+ actorSubjectId: string;
351
+ reason: string;
352
+ },
353
+ ): Promise<EventRow> {
354
+ const rows = (await db.execute(sql`
355
+ SELECT event_id
356
+ FROM preference_registry_apply_lifecycle(
357
+ ${input.operation},
358
+ ${input.preferenceId}::uuid,
359
+ ${input.expectedScopeVersion},
360
+ ${input.expectedRevisionId}::uuid,
361
+ ${input.revisionId ?? null}::uuid,
362
+ ${input.newScope ?? null},
363
+ ${input.relatedPreferenceId ?? null}::uuid,
364
+ ${input.actorSubjectId},
365
+ ${input.reason}
366
+ )
367
+ `)) as unknown as Array<{ event_id: string }>;
368
+ const eventId = rows[0]?.event_id;
369
+ if (!eventId) throw new Error("Preference lifecycle mutation returned no event");
370
+ const [event] = await db
371
+ .select()
372
+ .from(schema.preferenceRegistryEvents)
373
+ .where(eq(schema.preferenceRegistryEvents.id, eventId))
374
+ .limit(1);
375
+ if (!event) throw new Error("Preference lifecycle event was not visible after mutation");
376
+ return event;
377
+ }
378
+
379
+ async function preferenceAfterMutation(db: Database, preferenceId: string): Promise<PreferenceRow> {
380
+ const [row] = await db
381
+ .select()
382
+ .from(schema.preferenceRegistryPreferences)
383
+ .where(eq(schema.preferenceRegistryPreferences.id, preferenceId))
384
+ .limit(1);
385
+ if (!row) throw new PreferenceRegistryNotFoundError("Preference was not found");
386
+ return row;
387
+ }
388
+
389
+ async function insertRevision(
390
+ db: Database,
391
+ input: {
392
+ accountId: string;
393
+ preferenceId: string;
394
+ scope: PreferenceRegistryScope;
395
+ actorSubjectId: string;
396
+ title: string;
397
+ description: string;
398
+ content: string;
399
+ precedenceRank: number;
400
+ conflictStrategy: PreferenceRegistryConflictStrategy;
401
+ conflictsWith: string[];
402
+ provenanceSource: PreferenceRegistryProvenanceSource;
403
+ provenanceSourceId: string | null;
404
+ expiresAt: string | null;
405
+ correctsRevisionId: string | null;
406
+ },
407
+ ): Promise<RevisionRow> {
408
+ const title = boundedDescriptorText(input.title, PREFERENCE_REGISTRY_TITLE_MAX_CHARS);
409
+ const description = boundedDescriptorText(
410
+ input.description,
411
+ PREFERENCE_REGISTRY_DESCRIPTOR_DESCRIPTION_MAX_CHARS,
412
+ );
413
+ if (!title || !description) {
414
+ throw new PreferenceRegistryInvalidOperationError(
415
+ "Preference title and description must contain visible plain text",
416
+ );
417
+ }
418
+ const [created] = await db
419
+ .insert(schema.preferenceRegistryRevisions)
420
+ .values({
421
+ accountId: input.accountId,
422
+ preferenceId: input.preferenceId,
423
+ title,
424
+ description,
425
+ content: input.content,
426
+ contentHash: contentHash(input.content),
427
+ precedenceRank: input.precedenceRank,
428
+ conflictStrategy: input.conflictStrategy,
429
+ conflictsWith: [...new Set(input.conflictsWith)].sort(),
430
+ provenanceSource: input.provenanceSource,
431
+ provenanceSourceId: input.provenanceSourceId,
432
+ trust: trustFor(input.scope, input.provenanceSource),
433
+ expiresAt: input.expiresAt ? new Date(input.expiresAt) : null,
434
+ correctsRevisionId: input.correctsRevisionId,
435
+ createdBySubjectId: input.actorSubjectId,
436
+ })
437
+ .returning();
438
+ if (!created) throw new Error("Preference revision was not created");
439
+ return created;
440
+ }
441
+
442
+ export async function createPreferenceRegistryProposal(
443
+ db: Database,
444
+ input: CreatePreferenceRegistryProposalRequest & {
445
+ accountId: string;
446
+ workspaceId: string;
447
+ actorSubjectId: string;
448
+ principalKind: string | undefined;
449
+ },
450
+ ) {
451
+ const target = targetFor(input.scope, input.workspaceId, input.actorSubjectId);
452
+ try {
453
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
454
+ const [preference] = await scopedDb
455
+ .insert(schema.preferenceRegistryPreferences)
456
+ .values({
457
+ accountId: input.accountId,
458
+ stableKey: input.stableKey,
459
+ ...targetColumns(target),
460
+ createdBySubjectId: input.actorSubjectId,
461
+ })
462
+ .returning();
463
+ if (!preference) throw new Error("Preference proposal was not created");
464
+ const revision = await insertRevision(scopedDb, {
465
+ ...input,
466
+ preferenceId: preference.id,
467
+ correctsRevisionId: null,
468
+ });
469
+ await lifecycleEvent(scopedDb, {
470
+ operation: "proposal_created",
471
+ preferenceId: preference.id,
472
+ expectedScopeVersion: preference.scopeVersion,
473
+ expectedRevisionId: null,
474
+ revisionId: revision.id,
475
+ actorSubjectId: input.actorSubjectId,
476
+ reason: importedSources.has(input.provenanceSource)
477
+ ? "Imported source proposal; inactive pending authorized human review"
478
+ : "Human-created preference proposal; inactive pending activation",
479
+ });
480
+ return recordFromRows(preference, null);
481
+ });
482
+ } catch (error) {
483
+ if (isStableKeyConflict(error)) {
484
+ throw new PreferenceRegistryStableKeyConflictError(
485
+ "A preference with this stable key already exists for the target scope",
486
+ );
487
+ }
488
+ throw error;
489
+ }
490
+ }
491
+
492
+ type PreferenceRegistryListInput = {
493
+ scope?: PreferenceRegistryScope | undefined;
494
+ status?: PreferenceRegistryStatus | undefined;
495
+ limit: number;
496
+ };
497
+
498
+ async function listPreferenceRegistryScoped(db: Database, input: PreferenceRegistryListInput) {
499
+ const now = new Date();
500
+ const conditions: SQL[] = [];
501
+ if (input.scope) conditions.push(eq(schema.preferenceRegistryPreferences.scope, input.scope));
502
+ if (input.status === "active") {
503
+ conditions.push(
504
+ eq(schema.preferenceRegistryPreferences.status, "active"),
505
+ or(
506
+ isNull(schema.preferenceRegistryRevisions.expiresAt),
507
+ gt(schema.preferenceRegistryRevisions.expiresAt, now),
508
+ )!,
509
+ );
510
+ } else if (input.status === "expired") {
511
+ conditions.push(
512
+ eq(schema.preferenceRegistryPreferences.status, "active"),
513
+ lte(schema.preferenceRegistryRevisions.expiresAt, now),
514
+ );
515
+ } else if (input.status) {
516
+ conditions.push(eq(schema.preferenceRegistryPreferences.status, input.status));
517
+ }
518
+ const rows = await db
519
+ .select({
520
+ preference: schema.preferenceRegistryPreferences,
521
+ revision: schema.preferenceRegistryRevisions,
522
+ })
523
+ .from(schema.preferenceRegistryPreferences)
524
+ .leftJoin(
525
+ schema.preferenceRegistryRevisions,
526
+ and(
527
+ eq(
528
+ schema.preferenceRegistryRevisions.id,
529
+ schema.preferenceRegistryPreferences.activeRevisionId,
530
+ ),
531
+ eq(
532
+ schema.preferenceRegistryRevisions.accountId,
533
+ schema.preferenceRegistryPreferences.accountId,
534
+ ),
535
+ ),
536
+ )
537
+ .where(conditions.length ? and(...conditions) : undefined)
538
+ .orderBy(
539
+ asc(schema.preferenceRegistryPreferences.stableKey),
540
+ asc(schema.preferenceRegistryPreferences.id),
541
+ )
542
+ .limit(input.limit);
543
+ const preferences = rows.map(({ preference, revision }) =>
544
+ recordFromRows(preference, revision, now),
545
+ );
546
+ return PreferenceRegistryListResponse.parse({ preferences });
547
+ }
548
+
549
+ export async function listPreferenceRegistry(
550
+ db: Database,
551
+ input: {
552
+ workspaceId: string;
553
+ subjectId: string;
554
+ } & PreferenceRegistryListInput,
555
+ ) {
556
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
557
+ return await listPreferenceRegistryScoped(scopedDb, input);
558
+ });
559
+ }
560
+
561
+ export async function listPreferenceRegistryForAttempt(
562
+ db: Database,
563
+ input: PreferenceRegistryAttemptClaims & PreferenceRegistryListInput,
564
+ ) {
565
+ return await withPreferenceRegistryAttemptAuthority(db, input, async (scopedDb) => {
566
+ return await listPreferenceRegistryScoped(scopedDb, input);
567
+ });
568
+ }
569
+
570
+ async function getPreferenceRegistryDetailScoped(db: Database, preferenceId: string) {
571
+ const [preference] = await db
572
+ .select()
573
+ .from(schema.preferenceRegistryPreferences)
574
+ .where(eq(schema.preferenceRegistryPreferences.id, preferenceId))
575
+ .limit(1);
576
+ if (!preference) throw new PreferenceRegistryNotFoundError("Preference was not found");
577
+ const [revisions, events] = await Promise.all([
578
+ db
579
+ .select()
580
+ .from(schema.preferenceRegistryRevisions)
581
+ .where(eq(schema.preferenceRegistryRevisions.preferenceId, preferenceId))
582
+ .orderBy(desc(schema.preferenceRegistryRevisions.revision)),
583
+ db
584
+ .select()
585
+ .from(schema.preferenceRegistryEvents)
586
+ .where(eq(schema.preferenceRegistryEvents.preferenceId, preferenceId))
587
+ .orderBy(desc(schema.preferenceRegistryEvents.version)),
588
+ ]);
589
+ const active = preference.activeRevisionId
590
+ ? (revisions.find((revision) => revision.id === preference.activeRevisionId) ?? null)
591
+ : null;
592
+ return PreferenceRegistryDetailResponse.parse({
593
+ preference: recordFromRows(preference, active),
594
+ revisions: revisions.map((revision) =>
595
+ revisionSummary(revision, preference.scope as PreferenceRegistryScope),
596
+ ),
597
+ events: events.map(eventFromRow),
598
+ });
599
+ }
600
+
601
+ export async function getPreferenceRegistryDetail(
602
+ db: Database,
603
+ input: { workspaceId: string; subjectId: string; preferenceId: string },
604
+ ) {
605
+ return await withWorkspaceSubjectRls(db, input.workspaceId, input.subjectId, async (scopedDb) => {
606
+ return await getPreferenceRegistryDetailScoped(scopedDb, input.preferenceId);
607
+ });
608
+ }
609
+
610
+ export async function getPreferenceRegistryDetailForAttempt(
611
+ db: Database,
612
+ input: PreferenceRegistryAttemptClaims & { preferenceId: string },
613
+ ) {
614
+ return await withPreferenceRegistryAttemptAuthority(db, input, async (scopedDb) => {
615
+ return await getPreferenceRegistryDetailScoped(scopedDb, input.preferenceId);
616
+ });
617
+ }
618
+
619
+ export async function activatePreferenceRegistryRevision(
620
+ db: Database,
621
+ input: {
622
+ accountId: string;
623
+ workspaceId: string;
624
+ actorSubjectId: string;
625
+ principalKind: string | undefined;
626
+ preferenceId: string;
627
+ revisionId: string;
628
+ expectedCurrentRevisionId: string | null;
629
+ expectedScopeVersion: number;
630
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
631
+ reason: string;
632
+ eventType?: "activated" | "corrected";
633
+ },
634
+ ) {
635
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
636
+ const preference = await lockedPreference(scopedDb, input.preferenceId);
637
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
638
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
639
+ if (preference.activeRevisionId !== input.expectedCurrentRevisionId) {
640
+ throw new PreferenceRegistryConflictError(
641
+ "The active preference revision changed in another request",
642
+ preference.activeRevisionId,
643
+ preference.scopeVersion,
644
+ );
645
+ }
646
+ if (preference.status === "superseded") {
647
+ throw new PreferenceRegistryInvalidOperationError(
648
+ "A superseded preference cannot be activated",
649
+ );
650
+ }
651
+ if (preference.status === "rejected") {
652
+ throw new PreferenceRegistryInvalidOperationError(
653
+ "A rejected preference proposal cannot be activated",
654
+ );
655
+ }
656
+ const revision = await revisionForPreference(scopedDb, preference.id, input.revisionId);
657
+ if (revision.id === preference.activeRevisionId) {
658
+ throw new PreferenceRegistryInvalidOperationError("The requested revision is already active");
659
+ }
660
+ const event = await lifecycleEvent(scopedDb, {
661
+ operation: input.eventType === "corrected" ? "correct" : "activate",
662
+ preferenceId: preference.id,
663
+ expectedScopeVersion: input.expectedScopeVersion,
664
+ expectedRevisionId: input.expectedCurrentRevisionId,
665
+ revisionId: revision.id,
666
+ actorSubjectId: input.actorSubjectId,
667
+ reason: input.reason,
668
+ });
669
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
670
+ return {
671
+ preference: recordFromRows(updated, revision),
672
+ event: eventFromRow(event),
673
+ };
674
+ });
675
+ }
676
+
677
+ export async function correctPreferenceRegistry(
678
+ db: Database,
679
+ input: {
680
+ accountId: string;
681
+ workspaceId: string;
682
+ actorSubjectId: string;
683
+ principalKind: string | undefined;
684
+ preferenceId: string;
685
+ expectedCurrentRevisionId: string;
686
+ expectedScopeVersion: number;
687
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
688
+ title: string;
689
+ description: string;
690
+ content: string;
691
+ precedenceRank: number;
692
+ conflictStrategy: PreferenceRegistryConflictStrategy;
693
+ conflictsWith: string[];
694
+ expiresAt: string | null;
695
+ reason: string;
696
+ },
697
+ ) {
698
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
699
+ const preference = await lockedPreference(scopedDb, input.preferenceId);
700
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
701
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
702
+ if (preference.status === "superseded" || preference.status === "rejected") {
703
+ throw new PreferenceRegistryInvalidOperationError(
704
+ "A rejected or superseded preference cannot be corrected",
705
+ );
706
+ }
707
+ if (preference.activeRevisionId !== input.expectedCurrentRevisionId) {
708
+ throw new PreferenceRegistryConflictError(
709
+ "The active preference revision changed before correction",
710
+ preference.activeRevisionId,
711
+ preference.scopeVersion,
712
+ );
713
+ }
714
+ const oldRevision = await revisionForPreference(
715
+ scopedDb,
716
+ preference.id,
717
+ input.expectedCurrentRevisionId,
718
+ );
719
+ const revision = await insertRevision(scopedDb, {
720
+ ...input,
721
+ scope: preference.scope as PreferenceRegistryScope,
722
+ provenanceSource: "human",
723
+ provenanceSourceId: `correction:${oldRevision.id}`,
724
+ correctsRevisionId: oldRevision.id,
725
+ });
726
+ const event = await lifecycleEvent(scopedDb, {
727
+ operation: "correct",
728
+ preferenceId: preference.id,
729
+ expectedScopeVersion: input.expectedScopeVersion,
730
+ expectedRevisionId: oldRevision.id,
731
+ revisionId: revision.id,
732
+ actorSubjectId: input.actorSubjectId,
733
+ reason: input.reason,
734
+ });
735
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
736
+ return { preference: recordFromRows(updated, revision), event: eventFromRow(event) };
737
+ });
738
+ }
739
+
740
+ export async function changePreferenceRegistryScope(
741
+ db: Database,
742
+ input: {
743
+ accountId: string;
744
+ workspaceId: string;
745
+ actorSubjectId: string;
746
+ principalKind: string | undefined;
747
+ preferenceId: string;
748
+ scope: PreferenceRegistryScope;
749
+ expectedScopeVersion: number;
750
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
751
+ reason: string;
752
+ },
753
+ ) {
754
+ try {
755
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
756
+ const preference = await lockedPreference(scopedDb, input.preferenceId);
757
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
758
+ input.authorizeScope(input.scope);
759
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
760
+ if (preference.status === "superseded" || preference.status === "rejected") {
761
+ throw new PreferenceRegistryInvalidOperationError(
762
+ "A rejected or superseded preference cannot change scope",
763
+ );
764
+ }
765
+ if (preference.scope === input.scope) {
766
+ throw new PreferenceRegistryInvalidOperationError(
767
+ "Preference already uses the requested scope",
768
+ );
769
+ }
770
+ const oldTarget = targetFromRow(preference);
771
+ const nextTarget = targetFor(input.scope, input.workspaceId, input.actorSubjectId);
772
+ const event = await lifecycleEvent(scopedDb, {
773
+ operation: "scope",
774
+ preferenceId: preference.id,
775
+ expectedScopeVersion: input.expectedScopeVersion,
776
+ expectedRevisionId: preference.activeRevisionId,
777
+ newScope: input.scope,
778
+ actorSubjectId: input.actorSubjectId,
779
+ reason: input.reason,
780
+ });
781
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
782
+ const active = updated.activeRevisionId
783
+ ? await revisionForPreference(scopedDb, updated.id, updated.activeRevisionId)
784
+ : null;
785
+ if (
786
+ event.oldScope !== oldTarget.scope ||
787
+ event.oldWorkspaceId !== oldTarget.workspaceId ||
788
+ event.oldSubjectId !== oldTarget.subjectId ||
789
+ event.newScope !== nextTarget.scope ||
790
+ event.newWorkspaceId !== nextTarget.workspaceId ||
791
+ event.newSubjectId !== nextTarget.subjectId
792
+ ) {
793
+ throw new Error("Preference scope event did not preserve the locked transition");
794
+ }
795
+ return { preference: recordFromRows(updated, active), event: eventFromRow(event) };
796
+ });
797
+ } catch (error) {
798
+ if (isStableKeyConflict(error)) {
799
+ throw new PreferenceRegistryStableKeyConflictError(
800
+ "A preference with this stable key already exists for the target scope",
801
+ );
802
+ }
803
+ throw error;
804
+ }
805
+ }
806
+
807
+ export async function deactivatePreferenceRegistry(
808
+ db: Database,
809
+ input: {
810
+ accountId: string;
811
+ workspaceId: string;
812
+ actorSubjectId: string;
813
+ principalKind: string | undefined;
814
+ preferenceId: string;
815
+ expectedCurrentRevisionId: string;
816
+ expectedScopeVersion: number;
817
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
818
+ reason: string;
819
+ },
820
+ ) {
821
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
822
+ const preference = await lockedPreference(scopedDb, input.preferenceId);
823
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
824
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
825
+ if (
826
+ preference.status !== "active" ||
827
+ preference.activeRevisionId !== input.expectedCurrentRevisionId
828
+ ) {
829
+ throw new PreferenceRegistryConflictError(
830
+ "The active preference revision changed before deactivation",
831
+ preference.activeRevisionId,
832
+ preference.scopeVersion,
833
+ );
834
+ }
835
+ const revision = await revisionForPreference(
836
+ scopedDb,
837
+ preference.id,
838
+ input.expectedCurrentRevisionId,
839
+ );
840
+ const event = await lifecycleEvent(scopedDb, {
841
+ operation: "deactivate",
842
+ preferenceId: preference.id,
843
+ expectedScopeVersion: input.expectedScopeVersion,
844
+ expectedRevisionId: revision.id,
845
+ actorSubjectId: input.actorSubjectId,
846
+ reason: input.reason,
847
+ });
848
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
849
+ return { preference: recordFromRows(updated, null), event: eventFromRow(event) };
850
+ });
851
+ }
852
+
853
+ export async function supersedePreferenceRegistry(
854
+ db: Database,
855
+ input: {
856
+ accountId: string;
857
+ workspaceId: string;
858
+ actorSubjectId: string;
859
+ principalKind: string | undefined;
860
+ preferenceId: string;
861
+ replacementPreferenceId: string;
862
+ expectedCurrentRevisionId: string;
863
+ expectedScopeVersion: number;
864
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
865
+ reason: string;
866
+ },
867
+ ) {
868
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
869
+ if (input.preferenceId === input.replacementPreferenceId) {
870
+ throw new PreferenceRegistryInvalidOperationError("A preference cannot supersede itself");
871
+ }
872
+ const locked = await lockedPreferences(scopedDb, [
873
+ input.preferenceId,
874
+ input.replacementPreferenceId,
875
+ ]);
876
+ const preference = locked.find((row) => row.id === input.preferenceId)!;
877
+ const replacement = locked.find((row) => row.id === input.replacementPreferenceId)!;
878
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
879
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
880
+ if (preference.activeRevisionId !== input.expectedCurrentRevisionId) {
881
+ throw new PreferenceRegistryConflictError(
882
+ "The active preference revision changed before supersession",
883
+ preference.activeRevisionId,
884
+ preference.scopeVersion,
885
+ );
886
+ }
887
+ if (preference.status !== "active") {
888
+ throw new PreferenceRegistryInvalidOperationError(
889
+ "Only an active preference can be superseded",
890
+ );
891
+ }
892
+ if (replacement.status !== "active" || !replacement.activeRevisionId) {
893
+ throw new PreferenceRegistryInvalidOperationError("Replacement preference must be active");
894
+ }
895
+ const [replacementRevision] = await scopedDb
896
+ .select()
897
+ .from(schema.preferenceRegistryRevisions)
898
+ .where(
899
+ and(
900
+ eq(schema.preferenceRegistryRevisions.id, replacement.activeRevisionId),
901
+ eq(schema.preferenceRegistryRevisions.preferenceId, replacement.id),
902
+ or(
903
+ isNull(schema.preferenceRegistryRevisions.expiresAt),
904
+ gt(schema.preferenceRegistryRevisions.expiresAt, sql`transaction_timestamp()`),
905
+ ),
906
+ ),
907
+ )
908
+ .limit(1);
909
+ if (!replacementRevision) {
910
+ throw new PreferenceRegistryInvalidOperationError(
911
+ "Replacement preference must have an unexpired active revision",
912
+ );
913
+ }
914
+ if (preference.scope !== replacement.scope) {
915
+ throw new PreferenceRegistryInvalidOperationError(
916
+ "Supersession requires the same scope tier",
917
+ );
918
+ }
919
+ const event = await lifecycleEvent(scopedDb, {
920
+ operation: "supersede",
921
+ preferenceId: preference.id,
922
+ expectedScopeVersion: input.expectedScopeVersion,
923
+ expectedRevisionId: preference.activeRevisionId,
924
+ relatedPreferenceId: replacement.id,
925
+ actorSubjectId: input.actorSubjectId,
926
+ reason: input.reason,
927
+ });
928
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
929
+ const revision = await revisionForPreference(
930
+ scopedDb,
931
+ preference.id,
932
+ preference.activeRevisionId!,
933
+ );
934
+ return { preference: recordFromRows(updated, revision), event: eventFromRow(event) };
935
+ });
936
+ }
937
+
938
+ export async function rejectPreferenceRegistryProposal(
939
+ db: Database,
940
+ input: {
941
+ accountId: string;
942
+ workspaceId: string;
943
+ actorSubjectId: string;
944
+ principalKind: string | undefined;
945
+ preferenceId: string;
946
+ revisionId: string;
947
+ expectedScopeVersion: number;
948
+ authorizeScope: PreferenceRegistryScopeAuthorizer;
949
+ reason: string;
950
+ },
951
+ ) {
952
+ return await withPreferenceRegistryGovernanceRls(db, input, async (scopedDb) => {
953
+ const preference = await lockedPreference(scopedDb, input.preferenceId);
954
+ input.authorizeScope(preference.scope as PreferenceRegistryScope);
955
+ requireExpectedScopeVersion(preference, input.expectedScopeVersion);
956
+ if (preference.activeRevisionId !== null || preference.status !== "proposed") {
957
+ throw new PreferenceRegistryInvalidOperationError(
958
+ "Only an inactive proposal can be rejected",
959
+ );
960
+ }
961
+ await revisionForPreference(scopedDb, preference.id, input.revisionId);
962
+ const event = await lifecycleEvent(scopedDb, {
963
+ operation: "reject",
964
+ preferenceId: preference.id,
965
+ expectedScopeVersion: input.expectedScopeVersion,
966
+ expectedRevisionId: null,
967
+ revisionId: input.revisionId,
968
+ actorSubjectId: input.actorSubjectId,
969
+ reason: input.reason,
970
+ });
971
+ const updated = await preferenceAfterMutation(scopedDb, preference.id);
972
+ return { preference: recordFromRows(updated, null), event: eventFromRow(event) };
973
+ });
974
+ }
975
+
976
+ async function withPreferenceRegistryAttemptAuthority<T>(
977
+ db: Database,
978
+ input: PreferenceRegistryAttemptClaims,
979
+ fn: (db: Database, authority: PreferenceRegistryAttemptAuthority) => Promise<T>,
980
+ ): Promise<T> {
981
+ return await withWorkspaceRls(db, input.workspaceId, async (scopedDb) => {
982
+ const rows = (await scopedDb.execute(sql`
983
+ WITH locked_workspace AS MATERIALIZED (
984
+ SELECT workspace.id, workspace.account_id
985
+ FROM workspaces workspace
986
+ WHERE workspace.id = ${input.workspaceId}::uuid
987
+ AND workspace.account_id = ${input.accountId}::uuid
988
+ FOR KEY SHARE OF workspace
989
+ ), locked_session AS MATERIALIZED (
990
+ SELECT session.id, session.account_id, session.workspace_id, session.active_turn_id
991
+ FROM sessions session
992
+ JOIN locked_workspace workspace
993
+ ON workspace.id = session.workspace_id
994
+ AND workspace.account_id = session.account_id
995
+ WHERE session.id = ${input.sessionId}::uuid
996
+ AND session.active_turn_id = ${input.turnId}::uuid
997
+ FOR SHARE OF session
998
+ ), locked_turn AS MATERIALIZED (
999
+ SELECT turn.id, turn.account_id, turn.workspace_id, turn.session_id,
1000
+ turn.active_attempt_id, turn.execution_generation,
1001
+ turn.initiator_kind, turn.initiator_subject_id
1002
+ FROM session_turns turn
1003
+ JOIN locked_session session
1004
+ ON session.id = turn.session_id
1005
+ AND session.workspace_id = turn.workspace_id
1006
+ AND session.account_id = turn.account_id
1007
+ WHERE turn.id = ${input.turnId}::uuid
1008
+ AND turn.active_attempt_id = ${input.attemptId}::uuid
1009
+ AND turn.execution_generation = ${input.executionGeneration}
1010
+ AND turn.status IN ('running', 'requires_action', 'recovering', 'waiting_capacity')
1011
+ AND turn.initiator_kind = 'subject'
1012
+ AND length(btrim(turn.initiator_subject_id)) BETWEEN 1 AND 1024
1013
+ FOR SHARE OF turn
1014
+ ), locked_attempt AS MATERIALIZED (
1015
+ SELECT attempt.id, attempt.account_id, attempt.workspace_id,
1016
+ attempt.session_id, attempt.turn_id, attempt.execution_generation
1017
+ FROM session_turn_attempts attempt
1018
+ JOIN locked_turn turn
1019
+ ON turn.id = attempt.turn_id
1020
+ AND turn.session_id = attempt.session_id
1021
+ AND turn.workspace_id = attempt.workspace_id
1022
+ AND turn.account_id = attempt.account_id
1023
+ WHERE attempt.id = ${input.attemptId}::uuid
1024
+ AND attempt.execution_generation = ${input.executionGeneration}
1025
+ AND attempt.state IN ('claimed', 'running')
1026
+ AND NOT EXISTS (
1027
+ SELECT 1
1028
+ FROM session_attempt_interruptions interruption
1029
+ WHERE interruption.workspace_id = attempt.workspace_id
1030
+ AND interruption.attempt_id = attempt.id
1031
+ AND interruption.state IN ('pending', 'delivered', 'acknowledged')
1032
+ )
1033
+ FOR SHARE OF attempt
1034
+ )
1035
+ SELECT turn.initiator_subject_id
1036
+ FROM locked_workspace workspace
1037
+ JOIN locked_session session ON true
1038
+ JOIN locked_turn turn ON true
1039
+ JOIN locked_attempt attempt ON true
1040
+ WHERE workspace.account_id = attempt.account_id
1041
+ AND workspace.id = attempt.workspace_id
1042
+ AND session.id = attempt.session_id
1043
+ AND turn.id = attempt.turn_id
1044
+ `)) as unknown as Array<{ initiator_subject_id: string }>;
1045
+ const initiatingHumanSubjectId = rows[0]?.initiator_subject_id;
1046
+ if (!initiatingHumanSubjectId) {
1047
+ throw new PreferenceRegistryInitiatorError(
1048
+ "Preference retrieval requires the exact current attempt, generation, and immutable human initiator",
1049
+ );
1050
+ }
1051
+ const authority = { ...input, initiatingHumanSubjectId };
1052
+ await setSubjectRlsContext(scopedDb, initiatingHumanSubjectId);
1053
+ return await fn(scopedDb, authority);
1054
+ });
1055
+ }
1056
+
1057
+ export function boundPreferenceRegistryDescriptors(
1058
+ descriptors: readonly PreferenceRegistryDescriptor[],
1059
+ ): { descriptors: PreferenceRegistryDescriptor[]; truncated: boolean } {
1060
+ const scopeOrder: Record<PreferenceRegistryScope, number> = {
1061
+ organization: 0,
1062
+ workspace: 1,
1063
+ user: 2,
1064
+ };
1065
+ const compareText = (left: string, right: string): number =>
1066
+ left < right ? -1 : left > right ? 1 : 0;
1067
+ const ordered = [...descriptors].sort(
1068
+ (left, right) =>
1069
+ scopeOrder[left.scope] - scopeOrder[right.scope] ||
1070
+ right.precedence.rank - left.precedence.rank ||
1071
+ compareText(left.stableKey, right.stableKey) ||
1072
+ compareText(left.id, right.id),
1073
+ );
1074
+ const selected: PreferenceRegistryDescriptor[] = [];
1075
+ for (const descriptor of ordered) {
1076
+ if (selected.length >= PREFERENCE_REGISTRY_DESCRIPTOR_MAX_COUNT) break;
1077
+ const candidate = [...selected, descriptor];
1078
+ if (postgresJsonbTextUtf8Bytes(candidate) > PREFERENCE_REGISTRY_DESCRIPTOR_MAX_UTF8_BYTES) {
1079
+ break;
1080
+ }
1081
+ selected.push(descriptor);
1082
+ }
1083
+ return { descriptors: selected, truncated: selected.length < ordered.length };
1084
+ }
1085
+
1086
+ function postgresJsonbTextUtf8Bytes(value: unknown): number {
1087
+ return Buffer.byteLength(JSON.stringify(value), "utf8") + postgresJsonbSpacingBytes(value);
1088
+ }
1089
+
1090
+ function postgresJsonbSpacingBytes(value: unknown): number {
1091
+ if (Array.isArray(value)) {
1092
+ return (
1093
+ Math.max(0, value.length - 1) +
1094
+ value.reduce<number>((total, entry) => total + postgresJsonbSpacingBytes(entry), 0)
1095
+ );
1096
+ }
1097
+ if (value !== null && typeof value === "object") {
1098
+ const entries = Object.values(value);
1099
+ return (
1100
+ entries.length +
1101
+ Math.max(0, entries.length - 1) +
1102
+ entries.reduce<number>((total, entry) => total + postgresJsonbSpacingBytes(entry), 0)
1103
+ );
1104
+ }
1105
+ return 0;
1106
+ }
1107
+
1108
+ export async function getOrCreatePreferenceRegistrySnapshot(
1109
+ db: Database,
1110
+ claims: PreferenceRegistryAttemptClaims,
1111
+ ) {
1112
+ try {
1113
+ return await withWorkspaceRls(db, claims.workspaceId, async (scopedDb) => {
1114
+ const rows = (await scopedDb.execute(sql`
1115
+ SELECT
1116
+ snapshot.id,
1117
+ snapshot.workspace_id AS "workspaceId",
1118
+ snapshot.session_id AS "sessionId",
1119
+ snapshot.turn_id AS "turnId",
1120
+ snapshot.attempt_id AS "attemptId",
1121
+ snapshot.execution_generation AS "executionGeneration",
1122
+ snapshot.initiating_human_subject_id AS "initiatingHumanSubjectId",
1123
+ snapshot.descriptor_hash AS "descriptorHash",
1124
+ snapshot.descriptors,
1125
+ snapshot.truncated,
1126
+ snapshot.created_at AS "createdAt"
1127
+ FROM preference_registry_get_or_create_snapshot(
1128
+ ${claims.accountId}::uuid,
1129
+ ${claims.workspaceId}::uuid,
1130
+ ${claims.sessionId}::uuid,
1131
+ ${claims.turnId}::uuid,
1132
+ ${claims.attemptId}::uuid,
1133
+ ${claims.executionGeneration}
1134
+ ) snapshot
1135
+ `)) as unknown as Array<{
1136
+ id: string;
1137
+ workspaceId: string;
1138
+ sessionId: string;
1139
+ turnId: string;
1140
+ attemptId: string;
1141
+ executionGeneration: number;
1142
+ initiatingHumanSubjectId: string;
1143
+ descriptorHash: string;
1144
+ descriptors: unknown;
1145
+ truncated: boolean;
1146
+ createdAt: Date | string;
1147
+ }>;
1148
+ const snapshot = rows[0];
1149
+ if (!snapshot) {
1150
+ throw new PreferenceRegistryInitiatorError(
1151
+ "Preference snapshot authority conflicts with the accepted human attempt",
1152
+ );
1153
+ }
1154
+ return PreferenceRegistrySnapshot.parse({
1155
+ ...snapshot,
1156
+ createdAt: iso(snapshot.createdAt),
1157
+ });
1158
+ });
1159
+ } catch (error) {
1160
+ if (["40001", "42501"].includes(nestedPostgresSqlState(error) ?? "")) {
1161
+ throw new PreferenceRegistryInitiatorError(
1162
+ "Preference snapshot requires the exact current attempt, generation, and immutable human initiator",
1163
+ );
1164
+ }
1165
+ throw error;
1166
+ }
1167
+ }
1168
+
1169
+ export async function getPreferenceRegistryFullContent(
1170
+ db: Database,
1171
+ claims: PreferenceRegistryAttemptClaims,
1172
+ handle: string,
1173
+ ) {
1174
+ return await withPreferenceRegistryAttemptAuthority(db, claims, async (scopedDb, authority) => {
1175
+ const [snapshot] = await scopedDb
1176
+ .select()
1177
+ .from(schema.preferenceRegistrySnapshots)
1178
+ .where(
1179
+ and(
1180
+ eq(schema.preferenceRegistrySnapshots.accountId, authority.accountId),
1181
+ eq(schema.preferenceRegistrySnapshots.workspaceId, authority.workspaceId),
1182
+ eq(schema.preferenceRegistrySnapshots.sessionId, authority.sessionId),
1183
+ eq(schema.preferenceRegistrySnapshots.turnId, authority.turnId),
1184
+ eq(schema.preferenceRegistrySnapshots.attemptId, authority.attemptId),
1185
+ eq(schema.preferenceRegistrySnapshots.executionGeneration, authority.executionGeneration),
1186
+ eq(
1187
+ schema.preferenceRegistrySnapshots.initiatingHumanSubjectId,
1188
+ authority.initiatingHumanSubjectId,
1189
+ ),
1190
+ ),
1191
+ )
1192
+ .limit(1);
1193
+ if (!snapshot) {
1194
+ throw new PreferenceRegistryInvalidOperationError(
1195
+ "Preference summary must be snapshotted before full-content retrieval",
1196
+ );
1197
+ }
1198
+ const descriptor = snapshot.descriptors.find(
1199
+ (candidate) => candidate.retrievalHandle === handle,
1200
+ );
1201
+ if (!descriptor)
1202
+ throw new PreferenceRegistryNotFoundError(
1203
+ "Preference retrieval handle is not in this attempt snapshot",
1204
+ );
1205
+ const [revision] = await scopedDb
1206
+ .select()
1207
+ .from(schema.preferenceRegistryRevisions)
1208
+ .where(
1209
+ and(
1210
+ eq(schema.preferenceRegistryRevisions.accountId, authority.accountId),
1211
+ eq(schema.preferenceRegistryRevisions.id, descriptor.revisionId),
1212
+ eq(schema.preferenceRegistryRevisions.preferenceId, descriptor.id),
1213
+ eq(schema.preferenceRegistryRevisions.contentHash, descriptor.contentHash),
1214
+ ),
1215
+ )
1216
+ .limit(1);
1217
+ if (!revision) throw new PreferenceRegistryNotFoundError("Preference revision was not found");
1218
+ return PreferenceRegistryFullContent.parse({ descriptor, content: revision.content });
1219
+ });
1220
+ }