@opengeni/db 0.18.1 → 0.21.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.
- package/dist/chunk-NK2A36KP.js +5822 -0
- package/dist/chunk-NK2A36KP.js.map +1 -0
- package/dist/{chunk-T6RSJT6C.js → chunk-OTJHD33E.js} +109 -1
- package/dist/chunk-OTJHD33E.js.map +1 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.js +5761 -2827
- package/dist/index.js.map +1 -1
- package/dist/memory-domain.d.ts +110 -1
- package/dist/memory-governance-schema.d.ts +562 -0
- package/dist/memory-governance.d.ts +41 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +3 -3
- package/dist/schema.d.ts +425 -0
- package/dist/schema.js +37 -1
- package/dist/scoped-knowledge-schema.d.ts +5341 -0
- package/dist/scoped-knowledge.d.ts +208 -0
- package/dist/session-queue-commands.d.ts +2 -1
- package/drizzle/0152_hierarchical_memory_foundation.sql +1589 -0
- package/drizzle/0153_mcp_personal_connection_delegations.sql +181 -0
- package/drizzle/0154_scoped_knowledge_foundation.sql +2292 -0
- package/package.json +3 -3
- package/src/connection-token-resolver.ts +3 -0
- package/src/index.ts +351 -12
- package/src/memory-domain.ts +360 -1
- package/src/memory-governance-schema.ts +162 -0
- package/src/memory-governance.ts +317 -0
- package/src/provision-roles.ts +72 -0
- package/src/runtime-posture.ts +36 -0
- package/src/schema.ts +87 -4
- package/src/scoped-knowledge-schema.ts +603 -0
- package/src/scoped-knowledge.ts +2891 -0
- package/src/session-queue-commands.ts +48 -0
- package/dist/chunk-T6RSJT6C.js.map +0 -1
- package/dist/chunk-YKWJ7QJ2.js +0 -5000
- package/dist/chunk-YKWJ7QJ2.js.map +0 -1
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
2
|
+
import type { Database } from "./index";
|
|
3
|
+
import { setSubjectRlsContext, withWorkspaceRls } from "./index";
|
|
4
|
+
import {
|
|
5
|
+
hashMemoryOperationPlan,
|
|
6
|
+
hashMemoryRevertPlan,
|
|
7
|
+
normalizeMemoryOperationPlan,
|
|
8
|
+
normalizeMemoryRevertPlan,
|
|
9
|
+
normalizeMemoryRoleKey,
|
|
10
|
+
type MemoryOperationPlanInput,
|
|
11
|
+
type MemoryRevertPlanInput,
|
|
12
|
+
} from "./memory-domain";
|
|
13
|
+
|
|
14
|
+
export class MemoryGovernanceAuthorityError extends Error {
|
|
15
|
+
readonly name = "MemoryGovernanceAuthorityError";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type MemoryGovernanceDirectSubjectAuthority = {
|
|
19
|
+
kind: "subject";
|
|
20
|
+
accountId: string;
|
|
21
|
+
workspaceId: string;
|
|
22
|
+
subjectId: string;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type MemoryGovernanceDirectServiceAuthority = {
|
|
26
|
+
kind: "service";
|
|
27
|
+
accountId: string;
|
|
28
|
+
workspaceId: string;
|
|
29
|
+
serviceId: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type MemoryGovernanceAttemptAuthority = {
|
|
33
|
+
kind: "attempt";
|
|
34
|
+
accountId: string;
|
|
35
|
+
workspaceId: string;
|
|
36
|
+
sessionId: string;
|
|
37
|
+
turnId: string;
|
|
38
|
+
attemptId: string;
|
|
39
|
+
executionGeneration: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type MemoryGovernanceAuthority =
|
|
43
|
+
| MemoryGovernanceDirectSubjectAuthority
|
|
44
|
+
| MemoryGovernanceDirectServiceAuthority
|
|
45
|
+
| MemoryGovernanceAttemptAuthority;
|
|
46
|
+
|
|
47
|
+
type ResolvedMemoryGovernanceAuthority = {
|
|
48
|
+
accountId: string;
|
|
49
|
+
workspaceId: string;
|
|
50
|
+
actorKind: "subject" | "service";
|
|
51
|
+
actorSubjectId: string;
|
|
52
|
+
sessionId: string | null;
|
|
53
|
+
turnId: string | null;
|
|
54
|
+
attemptId: string | null;
|
|
55
|
+
executionGeneration: number | null;
|
|
56
|
+
roleKey: string | null;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
function requireBoundedActorId(value: string, label: string): string {
|
|
60
|
+
const normalized = value.trim();
|
|
61
|
+
if (!normalized || normalized.length > 1024) {
|
|
62
|
+
throw new MemoryGovernanceAuthorityError(`${label} must be a non-empty bounded identifier`);
|
|
63
|
+
}
|
|
64
|
+
return normalized;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function setAndVerifyMemoryGovernanceContext(
|
|
68
|
+
db: Database,
|
|
69
|
+
authority: ResolvedMemoryGovernanceAuthority,
|
|
70
|
+
): Promise<void> {
|
|
71
|
+
if (authority.actorKind === "subject") {
|
|
72
|
+
await setSubjectRlsContext(db, authority.actorSubjectId);
|
|
73
|
+
} else {
|
|
74
|
+
await db.execute(sql`select set_config('opengeni.subject_id', '', true)`);
|
|
75
|
+
}
|
|
76
|
+
await db.execute(sql`
|
|
77
|
+
select
|
|
78
|
+
set_config('opengeni.memory_actor_kind', ${authority.actorKind}, true),
|
|
79
|
+
set_config('opengeni.memory_actor_id', ${authority.actorSubjectId}, true),
|
|
80
|
+
set_config('opengeni.memory_session_id', ${authority.sessionId ?? ""}, true),
|
|
81
|
+
set_config('opengeni.memory_role_key', ${authority.roleKey ?? ""}, true)
|
|
82
|
+
`);
|
|
83
|
+
const rows = (await db.execute(sql`
|
|
84
|
+
select
|
|
85
|
+
nullif(current_setting('opengeni.account_id', true), '') as account_id,
|
|
86
|
+
nullif(current_setting('opengeni.workspace_id', true), '') as workspace_id,
|
|
87
|
+
nullif(current_setting('opengeni.subject_id', true), '') as subject_id,
|
|
88
|
+
nullif(current_setting('opengeni.memory_actor_kind', true), '') as actor_kind,
|
|
89
|
+
nullif(current_setting('opengeni.memory_actor_id', true), '') as actor_id,
|
|
90
|
+
nullif(current_setting('opengeni.memory_session_id', true), '') as session_id,
|
|
91
|
+
nullif(current_setting('opengeni.memory_role_key', true), '') as role_key
|
|
92
|
+
`)) as unknown as Array<{
|
|
93
|
+
account_id: string | null;
|
|
94
|
+
workspace_id: string | null;
|
|
95
|
+
subject_id: string | null;
|
|
96
|
+
actor_kind: string | null;
|
|
97
|
+
actor_id: string | null;
|
|
98
|
+
session_id: string | null;
|
|
99
|
+
role_key: string | null;
|
|
100
|
+
}>;
|
|
101
|
+
const applied = rows[0];
|
|
102
|
+
if (
|
|
103
|
+
!applied ||
|
|
104
|
+
applied.account_id !== authority.accountId ||
|
|
105
|
+
applied.workspace_id !== authority.workspaceId ||
|
|
106
|
+
applied.subject_id !== (authority.actorKind === "subject" ? authority.actorSubjectId : null) ||
|
|
107
|
+
applied.actor_kind !== authority.actorKind ||
|
|
108
|
+
applied.actor_id !== authority.actorSubjectId ||
|
|
109
|
+
applied.session_id !== authority.sessionId ||
|
|
110
|
+
applied.role_key !== authority.roleKey
|
|
111
|
+
) {
|
|
112
|
+
throw new MemoryGovernanceAuthorityError(
|
|
113
|
+
"Memory governance authority was not applied on the active database backend",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function resolveAttemptAuthority(
|
|
119
|
+
db: Database,
|
|
120
|
+
input: MemoryGovernanceAttemptAuthority,
|
|
121
|
+
): Promise<ResolvedMemoryGovernanceAuthority> {
|
|
122
|
+
if (!Number.isSafeInteger(input.executionGeneration) || input.executionGeneration <= 0) {
|
|
123
|
+
throw new MemoryGovernanceAuthorityError(
|
|
124
|
+
"Memory governance attempt requires a positive execution generation",
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
const rows = (await db.execute(sql`
|
|
128
|
+
with locked_workspace as materialized (
|
|
129
|
+
select workspace.id, workspace.account_id
|
|
130
|
+
from workspaces workspace
|
|
131
|
+
where workspace.id = ${input.workspaceId}::uuid
|
|
132
|
+
and workspace.account_id = ${input.accountId}::uuid
|
|
133
|
+
for key share of workspace
|
|
134
|
+
), locked_session as materialized (
|
|
135
|
+
select session.id, session.account_id, session.workspace_id,
|
|
136
|
+
session.active_turn_id, session.metadata ->> 'memoryRoleKey' as memory_role_key
|
|
137
|
+
from sessions session
|
|
138
|
+
join locked_workspace workspace
|
|
139
|
+
on workspace.id = session.workspace_id
|
|
140
|
+
and workspace.account_id = session.account_id
|
|
141
|
+
where session.id = ${input.sessionId}::uuid
|
|
142
|
+
and session.active_turn_id = ${input.turnId}::uuid
|
|
143
|
+
for share of session
|
|
144
|
+
), locked_turn as materialized (
|
|
145
|
+
select turn.id, turn.account_id, turn.workspace_id, turn.session_id,
|
|
146
|
+
turn.active_attempt_id, turn.execution_generation,
|
|
147
|
+
turn.initiator_kind, turn.initiator_subject_id
|
|
148
|
+
from session_turns turn
|
|
149
|
+
join locked_session session
|
|
150
|
+
on session.id = turn.session_id
|
|
151
|
+
and session.workspace_id = turn.workspace_id
|
|
152
|
+
and session.account_id = turn.account_id
|
|
153
|
+
where turn.id = ${input.turnId}::uuid
|
|
154
|
+
and turn.active_attempt_id = ${input.attemptId}::uuid
|
|
155
|
+
and turn.execution_generation = ${input.executionGeneration}
|
|
156
|
+
and turn.status in ('running', 'requires_action', 'recovering', 'waiting_capacity')
|
|
157
|
+
and turn.initiator_kind in ('subject', 'service')
|
|
158
|
+
and length(btrim(turn.initiator_subject_id)) between 1 and 1024
|
|
159
|
+
for share of turn
|
|
160
|
+
), locked_attempt as materialized (
|
|
161
|
+
select attempt.id, attempt.account_id, attempt.workspace_id,
|
|
162
|
+
attempt.session_id, attempt.turn_id, attempt.execution_generation
|
|
163
|
+
from session_turn_attempts attempt
|
|
164
|
+
join locked_turn turn
|
|
165
|
+
on turn.id = attempt.turn_id
|
|
166
|
+
and turn.session_id = attempt.session_id
|
|
167
|
+
and turn.workspace_id = attempt.workspace_id
|
|
168
|
+
and turn.account_id = attempt.account_id
|
|
169
|
+
where attempt.id = ${input.attemptId}::uuid
|
|
170
|
+
and attempt.execution_generation = ${input.executionGeneration}
|
|
171
|
+
and attempt.state in ('claimed', 'running')
|
|
172
|
+
and not exists (
|
|
173
|
+
select 1
|
|
174
|
+
from session_attempt_interruptions interruption
|
|
175
|
+
where interruption.workspace_id = attempt.workspace_id
|
|
176
|
+
and interruption.attempt_id = attempt.id
|
|
177
|
+
and interruption.state in ('pending', 'delivered', 'acknowledged')
|
|
178
|
+
)
|
|
179
|
+
for share of attempt
|
|
180
|
+
)
|
|
181
|
+
select turn.initiator_kind, turn.initiator_subject_id, session.memory_role_key
|
|
182
|
+
from locked_workspace workspace
|
|
183
|
+
join locked_session session on true
|
|
184
|
+
join locked_turn turn on true
|
|
185
|
+
join locked_attempt attempt on true
|
|
186
|
+
where workspace.account_id = attempt.account_id
|
|
187
|
+
and workspace.id = attempt.workspace_id
|
|
188
|
+
and session.id = attempt.session_id
|
|
189
|
+
and turn.id = attempt.turn_id
|
|
190
|
+
`)) as unknown as Array<{
|
|
191
|
+
initiator_kind: "subject" | "service";
|
|
192
|
+
initiator_subject_id: string;
|
|
193
|
+
memory_role_key: string | null;
|
|
194
|
+
}>;
|
|
195
|
+
const row = rows[0];
|
|
196
|
+
if (!row) {
|
|
197
|
+
throw new MemoryGovernanceAuthorityError(
|
|
198
|
+
"Memory governance requires the exact current attempt, generation, and immutable initiator",
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
let roleKey: string | null = null;
|
|
202
|
+
if (row.memory_role_key !== null) {
|
|
203
|
+
try {
|
|
204
|
+
roleKey = normalizeMemoryRoleKey(row.memory_role_key);
|
|
205
|
+
} catch {
|
|
206
|
+
throw new MemoryGovernanceAuthorityError(
|
|
207
|
+
"Persisted session memoryRoleKey is invalid; role-scoped authority fails closed",
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (roleKey !== row.memory_role_key) {
|
|
211
|
+
throw new MemoryGovernanceAuthorityError(
|
|
212
|
+
"Persisted session memoryRoleKey is not canonical; role-scoped authority fails closed",
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return {
|
|
217
|
+
accountId: input.accountId,
|
|
218
|
+
workspaceId: input.workspaceId,
|
|
219
|
+
actorKind: row.initiator_kind,
|
|
220
|
+
actorSubjectId: row.initiator_subject_id,
|
|
221
|
+
sessionId: input.sessionId,
|
|
222
|
+
turnId: input.turnId,
|
|
223
|
+
attemptId: input.attemptId,
|
|
224
|
+
executionGeneration: input.executionGeneration,
|
|
225
|
+
roleKey,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
async function withMemoryGovernanceAuthority<T>(
|
|
230
|
+
db: Database,
|
|
231
|
+
authority: MemoryGovernanceAuthority,
|
|
232
|
+
fn: (db: Database, authority: ResolvedMemoryGovernanceAuthority) => Promise<T>,
|
|
233
|
+
): Promise<T> {
|
|
234
|
+
return await withWorkspaceRls(db, authority.workspaceId, async (scopedDb) => {
|
|
235
|
+
let resolved: ResolvedMemoryGovernanceAuthority;
|
|
236
|
+
if (authority.kind === "attempt") {
|
|
237
|
+
resolved = await resolveAttemptAuthority(scopedDb, authority);
|
|
238
|
+
} else {
|
|
239
|
+
const actorSubjectId = requireBoundedActorId(
|
|
240
|
+
authority.kind === "subject" ? authority.subjectId : authority.serviceId,
|
|
241
|
+
authority.kind === "subject" ? "subject id" : "service id",
|
|
242
|
+
);
|
|
243
|
+
resolved = {
|
|
244
|
+
accountId: authority.accountId,
|
|
245
|
+
workspaceId: authority.workspaceId,
|
|
246
|
+
actorKind: authority.kind,
|
|
247
|
+
actorSubjectId,
|
|
248
|
+
sessionId: null,
|
|
249
|
+
turnId: null,
|
|
250
|
+
attemptId: null,
|
|
251
|
+
executionGeneration: null,
|
|
252
|
+
roleKey: null,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
await setAndVerifyMemoryGovernanceContext(scopedDb, resolved);
|
|
256
|
+
return await fn(scopedDb, resolved);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export async function applyKnowledgeMemoryOperation(
|
|
261
|
+
db: Database,
|
|
262
|
+
input: {
|
|
263
|
+
authority: MemoryGovernanceAuthority;
|
|
264
|
+
plan: MemoryOperationPlanInput;
|
|
265
|
+
},
|
|
266
|
+
): Promise<{ eventId: string; planHash: string }> {
|
|
267
|
+
const plan = normalizeMemoryOperationPlan(input.plan);
|
|
268
|
+
const planHash = hashMemoryOperationPlan(plan);
|
|
269
|
+
return await withMemoryGovernanceAuthority(db, input.authority, async (scopedDb, authority) => {
|
|
270
|
+
const rows = (await scopedDb.execute(sql`
|
|
271
|
+
select event_id
|
|
272
|
+
from knowledge_memory_apply_operation(
|
|
273
|
+
${JSON.stringify(plan)}::jsonb,
|
|
274
|
+
${planHash},
|
|
275
|
+
${authority.actorKind},
|
|
276
|
+
${authority.actorSubjectId},
|
|
277
|
+
${authority.sessionId}::uuid,
|
|
278
|
+
${authority.turnId}::uuid,
|
|
279
|
+
${authority.attemptId}::uuid,
|
|
280
|
+
${authority.executionGeneration}::integer
|
|
281
|
+
)
|
|
282
|
+
`)) as unknown as Array<{ event_id: string }>;
|
|
283
|
+
const eventId = rows[0]?.event_id;
|
|
284
|
+
if (!eventId) throw new Error("Memory governance apply operation returned no event");
|
|
285
|
+
return { eventId, planHash };
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export async function revertKnowledgeMemoryOperation(
|
|
290
|
+
db: Database,
|
|
291
|
+
input: {
|
|
292
|
+
authority: MemoryGovernanceAuthority;
|
|
293
|
+
plan: MemoryRevertPlanInput;
|
|
294
|
+
},
|
|
295
|
+
): Promise<{ eventId: string; planHash: string }> {
|
|
296
|
+
const plan = normalizeMemoryRevertPlan(input.plan);
|
|
297
|
+
const planHash = hashMemoryRevertPlan(plan);
|
|
298
|
+
return await withMemoryGovernanceAuthority(db, input.authority, async (scopedDb, authority) => {
|
|
299
|
+
const rows = (await scopedDb.execute(sql`
|
|
300
|
+
select event_id
|
|
301
|
+
from knowledge_memory_revert_operation(
|
|
302
|
+
${plan.operationId}::uuid,
|
|
303
|
+
${plan.appliedOperationId}::uuid,
|
|
304
|
+
${planHash},
|
|
305
|
+
${authority.actorKind},
|
|
306
|
+
${authority.actorSubjectId},
|
|
307
|
+
${authority.sessionId}::uuid,
|
|
308
|
+
${authority.turnId}::uuid,
|
|
309
|
+
${authority.attemptId}::uuid,
|
|
310
|
+
${authority.executionGeneration}::integer
|
|
311
|
+
)
|
|
312
|
+
`)) as unknown as Array<{ event_id: string }>;
|
|
313
|
+
const eventId = rows[0]?.event_id;
|
|
314
|
+
if (!eventId) throw new Error("Memory governance revert operation returned no event");
|
|
315
|
+
return { eventId, planHash };
|
|
316
|
+
});
|
|
317
|
+
}
|
package/src/provision-roles.ts
CHANGED
|
@@ -433,6 +433,30 @@ BEGIN
|
|
|
433
433
|
${literal(role)}
|
|
434
434
|
);
|
|
435
435
|
END IF;
|
|
436
|
+
IF to_regprocedure(
|
|
437
|
+
format(
|
|
438
|
+
'%I.knowledge_memory_apply_operation(jsonb,text,text,text,uuid,uuid,uuid,integer)',
|
|
439
|
+
${literal(schema)}
|
|
440
|
+
)
|
|
441
|
+
) IS NOT NULL THEN
|
|
442
|
+
EXECUTE format(
|
|
443
|
+
'GRANT EXECUTE ON FUNCTION %I.knowledge_memory_apply_operation(jsonb, text, text, text, uuid, uuid, uuid, integer) TO %I',
|
|
444
|
+
${literal(schema)},
|
|
445
|
+
${literal(role)}
|
|
446
|
+
);
|
|
447
|
+
END IF;
|
|
448
|
+
IF to_regprocedure(
|
|
449
|
+
format(
|
|
450
|
+
'%I.knowledge_memory_revert_operation(uuid,uuid,text,text,text,uuid,uuid,uuid,integer)',
|
|
451
|
+
${literal(schema)}
|
|
452
|
+
)
|
|
453
|
+
) IS NOT NULL THEN
|
|
454
|
+
EXECUTE format(
|
|
455
|
+
'GRANT EXECUTE ON FUNCTION %I.knowledge_memory_revert_operation(uuid, uuid, text, text, text, uuid, uuid, uuid, integer) TO %I',
|
|
456
|
+
${literal(schema)},
|
|
457
|
+
${literal(role)}
|
|
458
|
+
);
|
|
459
|
+
END IF;
|
|
436
460
|
IF to_regprocedure(
|
|
437
461
|
format(
|
|
438
462
|
'%I.preference_registry_get_or_create_snapshot(uuid,uuid,uuid,uuid,uuid,integer)',
|
|
@@ -445,6 +469,54 @@ BEGIN
|
|
|
445
469
|
${literal(role)}
|
|
446
470
|
);
|
|
447
471
|
END IF;
|
|
472
|
+
IF to_regprocedure(
|
|
473
|
+
format(
|
|
474
|
+
'%I.scoped_knowledge_apply_lifecycle(uuid,text,uuid,text,bigint,text,text,text,text,text,text)',
|
|
475
|
+
${literal(schema)}
|
|
476
|
+
)
|
|
477
|
+
) IS NOT NULL THEN
|
|
478
|
+
EXECUTE format(
|
|
479
|
+
'GRANT EXECUTE ON FUNCTION %I.scoped_knowledge_apply_lifecycle(uuid, text, uuid, text, bigint, text, text, text, text, text, text) TO %I',
|
|
480
|
+
${literal(schema)},
|
|
481
|
+
${literal(role)}
|
|
482
|
+
);
|
|
483
|
+
END IF;
|
|
484
|
+
IF to_regprocedure(
|
|
485
|
+
format(
|
|
486
|
+
'%I.scoped_knowledge_advance_source_acl(uuid,uuid,bigint,bigint,uuid,text,text,text,text,text,text)',
|
|
487
|
+
${literal(schema)}
|
|
488
|
+
)
|
|
489
|
+
) IS NOT NULL THEN
|
|
490
|
+
EXECUTE format(
|
|
491
|
+
'GRANT EXECUTE ON FUNCTION %I.scoped_knowledge_advance_source_acl(uuid, uuid, bigint, bigint, uuid, text, text, text, text, text, text) TO %I',
|
|
492
|
+
${literal(schema)},
|
|
493
|
+
${literal(role)}
|
|
494
|
+
);
|
|
495
|
+
END IF;
|
|
496
|
+
IF to_regprocedure(
|
|
497
|
+
format(
|
|
498
|
+
'%I.scoped_knowledge_complete_sync(uuid,uuid,text,text,timestamptz,jsonb,text,text,text)',
|
|
499
|
+
${literal(schema)}
|
|
500
|
+
)
|
|
501
|
+
) IS NOT NULL THEN
|
|
502
|
+
EXECUTE format(
|
|
503
|
+
'GRANT EXECUTE ON FUNCTION %I.scoped_knowledge_complete_sync(uuid, uuid, text, text, timestamptz, jsonb, text, text, text) TO %I',
|
|
504
|
+
${literal(schema)},
|
|
505
|
+
${literal(role)}
|
|
506
|
+
);
|
|
507
|
+
END IF;
|
|
508
|
+
IF to_regprocedure(
|
|
509
|
+
format(
|
|
510
|
+
'%I.scoped_knowledge_advance_object_version(uuid,uuid,bigint,bigint,uuid,text,text,text,text,text,text)',
|
|
511
|
+
${literal(schema)}
|
|
512
|
+
)
|
|
513
|
+
) IS NOT NULL THEN
|
|
514
|
+
EXECUTE format(
|
|
515
|
+
'GRANT EXECUTE ON FUNCTION %I.scoped_knowledge_advance_object_version(uuid, uuid, bigint, bigint, uuid, text, text, text, text, text, text) TO %I',
|
|
516
|
+
${literal(schema)},
|
|
517
|
+
${literal(role)}
|
|
518
|
+
);
|
|
519
|
+
END IF;
|
|
448
520
|
EXECUTE format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA %I TO %I', ${literal(schema)}, ${literal(role)});
|
|
449
521
|
EXECUTE format(
|
|
450
522
|
'ALTER DEFAULT PRIVILEGES FOR ROLE %I IN SCHEMA %I REVOKE ALL PRIVILEGES ON TABLES FROM %I',
|
package/src/runtime-posture.ts
CHANGED
|
@@ -42,7 +42,25 @@ export const FORCE_RLS_TABLES = [
|
|
|
42
42
|
"host_export_outbox",
|
|
43
43
|
"import_batches",
|
|
44
44
|
"integration_oauth_state_nonces",
|
|
45
|
+
"knowledge_change_proposals",
|
|
46
|
+
"knowledge_claim_evidence",
|
|
47
|
+
"knowledge_claim_relations",
|
|
48
|
+
"knowledge_claim_reviews",
|
|
49
|
+
"knowledge_claims",
|
|
50
|
+
"knowledge_document_versions",
|
|
51
|
+
"knowledge_entities",
|
|
52
|
+
"knowledge_entity_aliases",
|
|
53
|
+
"knowledge_facts",
|
|
54
|
+
"knowledge_lifecycle_events",
|
|
45
55
|
"knowledge_memories",
|
|
56
|
+
"knowledge_memory_lifecycle_events",
|
|
57
|
+
"knowledge_memory_relationships",
|
|
58
|
+
"knowledge_operation_receipts",
|
|
59
|
+
"knowledge_providers",
|
|
60
|
+
"knowledge_source_acl_versions",
|
|
61
|
+
"knowledge_source_objects",
|
|
62
|
+
"knowledge_sources",
|
|
63
|
+
"knowledge_sync_runs",
|
|
46
64
|
"machine_metrics_latest",
|
|
47
65
|
"machine_metrics_series",
|
|
48
66
|
"model_call_facts",
|
|
@@ -229,6 +247,9 @@ export const RUNTIME_FULL_DML_TABLES = [
|
|
|
229
247
|
|
|
230
248
|
/** Configuration and lifecycle-owned audit rows are read-only at runtime. */
|
|
231
249
|
export const RUNTIME_READ_ONLY_TABLES = [
|
|
250
|
+
"knowledge_lifecycle_events",
|
|
251
|
+
"knowledge_memory_lifecycle_events",
|
|
252
|
+
"knowledge_memory_relationships",
|
|
232
253
|
"nested_agent_depth_configuration",
|
|
233
254
|
"preference_registry_events",
|
|
234
255
|
"preference_registry_snapshots",
|
|
@@ -236,6 +257,21 @@ export const RUNTIME_READ_ONLY_TABLES = [
|
|
|
236
257
|
|
|
237
258
|
/** Append-only evidence/revision tables are insertable and queryable, never mutable. */
|
|
238
259
|
export const RUNTIME_READ_INSERT_TABLES = [
|
|
260
|
+
"knowledge_change_proposals",
|
|
261
|
+
"knowledge_claim_evidence",
|
|
262
|
+
"knowledge_claim_relations",
|
|
263
|
+
"knowledge_claim_reviews",
|
|
264
|
+
"knowledge_claims",
|
|
265
|
+
"knowledge_document_versions",
|
|
266
|
+
"knowledge_entities",
|
|
267
|
+
"knowledge_entity_aliases",
|
|
268
|
+
"knowledge_facts",
|
|
269
|
+
"knowledge_operation_receipts",
|
|
270
|
+
"knowledge_providers",
|
|
271
|
+
"knowledge_source_acl_versions",
|
|
272
|
+
"knowledge_source_objects",
|
|
273
|
+
"knowledge_sources",
|
|
274
|
+
"knowledge_sync_runs",
|
|
239
275
|
"preference_registry_preferences",
|
|
240
276
|
"preference_registry_revisions",
|
|
241
277
|
"session_spawn_denials",
|
package/src/schema.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
FirstPartyMcpToolName,
|
|
3
|
+
McpPersonalConnectionDelegation,
|
|
3
4
|
McpServerConnectionRef,
|
|
4
5
|
SessionMcpApprovalPolicy,
|
|
5
6
|
} from "@opengeni/contracts";
|
|
@@ -1316,6 +1317,14 @@ export const sessions = pgTable(
|
|
|
1316
1317
|
// Exact model-visible first-party tool selection. All catalogued tools are
|
|
1317
1318
|
// selected by default; [] intentionally selects no broad-server tools.
|
|
1318
1319
|
firstPartyMcpTools: jsonb("first_party_mcp_tools").$type<FirstPartyMcpToolName[]>().notNull(),
|
|
1320
|
+
// Initial-command staging only. initializeSessionStartAtomically copies
|
|
1321
|
+
// this immutable snapshot onto the first turn so create repair survives a
|
|
1322
|
+
// crash between the session insert and first-turn transaction. Runtime
|
|
1323
|
+
// credential authority must never read this session field.
|
|
1324
|
+
initialPersonalConnectionDelegations: jsonb("initial_personal_connection_delegations")
|
|
1325
|
+
.$type<McpPersonalConnectionDelegation[]>()
|
|
1326
|
+
.notNull()
|
|
1327
|
+
.default([]),
|
|
1319
1328
|
// Durable tool-policy origin. Migration 0136 removes the old null/legacy
|
|
1320
1329
|
// representation so every session has one explicit policy mode.
|
|
1321
1330
|
toolPolicy: jsonb("tool_policy").$type<SessionToolPolicy>().notNull(),
|
|
@@ -1325,9 +1334,15 @@ export const sessions = pgTable(
|
|
|
1325
1334
|
// when the creating grant carried a worker-signed sessionId claim (a session
|
|
1326
1335
|
// spawning a worker); null for direct API creates and scheduled-task runs.
|
|
1327
1336
|
// When set, this worker's terminal-for-now transitions wake the parent so a
|
|
1328
|
-
// manager can orchestrate workers without busy-polling.
|
|
1329
|
-
// ON DELETE
|
|
1337
|
+
// manager can orchestrate workers without busy-polling. The migration-owned
|
|
1338
|
+
// self-reference uses ON DELETE RESTRICT so immutable hierarchy and
|
|
1339
|
+
// authority lineage cannot be silently orphaned by a parent hard delete.
|
|
1330
1340
|
parentSessionId: uuid("parent_session_id"),
|
|
1341
|
+
// Exact parent turn whose worker-signed attempt created this child. This is
|
|
1342
|
+
// private immutable authority lineage: child completion copies personal MCP
|
|
1343
|
+
// authority from that turn, never from whichever parent turn ran most
|
|
1344
|
+
// recently. Null for top-level and legacy child sessions.
|
|
1345
|
+
parentTurnId: uuid("parent_turn_id"),
|
|
1331
1346
|
// Workspace-scoped CREATE idempotency key. NULL means the create carried no
|
|
1332
1347
|
// key (each such create is independent). When set, the partial unique index
|
|
1333
1348
|
// below collapses concurrent/retried creates with the same key in the same
|
|
@@ -1885,6 +1900,21 @@ export const knowledgeMemories = pgTable(
|
|
|
1885
1900
|
supersededById: uuid("superseded_by_id"),
|
|
1886
1901
|
validFrom: timestamp("valid_from", { withTimezone: true }).notNull().defaultNow(),
|
|
1887
1902
|
validUntil: timestamp("valid_until", { withTimezone: true }),
|
|
1903
|
+
// Hierarchical memory foundation (migration 0152). `scope` remains the V1
|
|
1904
|
+
// compatibility projection; typed selectors are the fail-closed authority.
|
|
1905
|
+
scopeType: text("scope_type").notNull().default("workspace"),
|
|
1906
|
+
scopeSubjectId: text("scope_subject_id"),
|
|
1907
|
+
scopeRoleKey: text("scope_role_key"),
|
|
1908
|
+
scopeSessionId: uuid("scope_session_id"),
|
|
1909
|
+
namespace: text("namespace_key").notNull().default("general"),
|
|
1910
|
+
labels: text("labels").array().notNull().default([]),
|
|
1911
|
+
memoryVersion: integer("memory_version").notNull().default(1),
|
|
1912
|
+
createdByKind: text("created_by_kind").notNull().default("service"),
|
|
1913
|
+
createdBySubjectId: text("created_by_subject_id").notNull().default("unattributed-legacy"),
|
|
1914
|
+
createdByContext: jsonb("created_by_context")
|
|
1915
|
+
.$type<Record<string, unknown>>()
|
|
1916
|
+
.notNull()
|
|
1917
|
+
.default({ backfill: true }),
|
|
1888
1918
|
// sha256(normalizeMemoryText(text)) — exact-dedup key; see memory-domain.
|
|
1889
1919
|
textHash: text("text_hash"),
|
|
1890
1920
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
|
@@ -1901,6 +1931,18 @@ export const knowledgeMemories = pgTable(
|
|
|
1901
1931
|
table.workspaceId,
|
|
1902
1932
|
table.scope,
|
|
1903
1933
|
),
|
|
1934
|
+
workspaceTypedScope: index("knowledge_memories_workspace_typed_scope_idx").on(
|
|
1935
|
+
table.workspaceId,
|
|
1936
|
+
table.scopeType,
|
|
1937
|
+
table.scopeSubjectId,
|
|
1938
|
+
table.scopeRoleKey,
|
|
1939
|
+
table.scopeSessionId,
|
|
1940
|
+
),
|
|
1941
|
+
workspaceNamespace: index("knowledge_memories_workspace_namespace_idx").on(
|
|
1942
|
+
table.workspaceId,
|
|
1943
|
+
table.namespace,
|
|
1944
|
+
),
|
|
1945
|
+
labelsGin: index("knowledge_memories_labels_idx").using("gin", table.labels),
|
|
1904
1946
|
createdBySession: index("knowledge_memories_workspace_created_by_session_idx").on(
|
|
1905
1947
|
table.workspaceId,
|
|
1906
1948
|
table.createdBySessionId,
|
|
@@ -1913,8 +1955,18 @@ export const knowledgeMemories = pgTable(
|
|
|
1913
1955
|
table.workspaceId,
|
|
1914
1956
|
table.textHash,
|
|
1915
1957
|
),
|
|
1916
|
-
|
|
1917
|
-
|
|
1958
|
+
// Drizzle 0.45 cannot encode PostgreSQL `NULLS NOT DISTINCT`; migration
|
|
1959
|
+
// 0152 owns that option so nullable scope selectors remain one identity.
|
|
1960
|
+
scopeVisibleTextHashUnique: uniqueIndex("knowledge_memories_scope_visible_text_hash_uq")
|
|
1961
|
+
.on(
|
|
1962
|
+
table.workspaceId,
|
|
1963
|
+
table.scopeType,
|
|
1964
|
+
table.scopeSubjectId,
|
|
1965
|
+
table.scopeRoleKey,
|
|
1966
|
+
table.scopeSessionId,
|
|
1967
|
+
table.namespace,
|
|
1968
|
+
table.textHash,
|
|
1969
|
+
)
|
|
1918
1970
|
.where(sql`${table.status} in ('active', 'approved') and ${table.textHash} is not null`),
|
|
1919
1971
|
}),
|
|
1920
1972
|
);
|
|
@@ -1971,6 +2023,13 @@ export const sessionTurns = pgTable(
|
|
|
1971
2023
|
.$type<Record<string, unknown>>()
|
|
1972
2024
|
.notNull()
|
|
1973
2025
|
.default({ backfill: true }),
|
|
2026
|
+
// Immutable exact personal MCP authority for this logical turn. Recovery,
|
|
2027
|
+
// approval, retries, and Toolspace reuse this row; no runtime may infer
|
|
2028
|
+
// broader authority from the session creator or mutable session state.
|
|
2029
|
+
personalConnectionDelegations: jsonb("personal_connection_delegations")
|
|
2030
|
+
.$type<McpPersonalConnectionDelegation[]>()
|
|
2031
|
+
.notNull()
|
|
2032
|
+
.default([]),
|
|
1974
2033
|
cancelledBy: text("cancelled_by"),
|
|
1975
2034
|
cancelReason: text("cancel_reason"),
|
|
1976
2035
|
// Atomic per-turn toolspace call budget counter (migration 0043). Incremented
|
|
@@ -2410,6 +2469,12 @@ export const sessionSystemUpdates = pgTable(
|
|
|
2410
2469
|
summary: text("summary").notNull(),
|
|
2411
2470
|
payload: jsonb("payload").$type<Record<string, unknown>>().notNull().default({}),
|
|
2412
2471
|
lineage: jsonb("lineage").$type<Record<string, unknown>>().notNull().default({}),
|
|
2472
|
+
// Private immutable authority frozen when this machine input is accepted.
|
|
2473
|
+
// Public projections intentionally omit connection ids and owner subjects.
|
|
2474
|
+
personalConnectionDelegations: jsonb("personal_connection_delegations")
|
|
2475
|
+
.$type<McpPersonalConnectionDelegation[]>()
|
|
2476
|
+
.notNull()
|
|
2477
|
+
.default([]),
|
|
2413
2478
|
// pending is visible queue truth; delivered means its exact model-memory
|
|
2414
2479
|
// batch was durably claimed. Terminal cancellation/supersession is explicit.
|
|
2415
2480
|
state: text("state").notNull().default("pending"),
|
|
@@ -2489,6 +2554,12 @@ export const sessionSystemUpdateOutbox = pgTable(
|
|
|
2489
2554
|
summary: text("summary").notNull(),
|
|
2490
2555
|
payload: jsonb("payload").$type<Record<string, unknown>>().notNull().default({}),
|
|
2491
2556
|
lineage: jsonb("lineage").$type<Record<string, unknown>>().notNull().default({}),
|
|
2557
|
+
// Exact private authority copied from the causal parent turn in the source
|
|
2558
|
+
// terminal transaction. Delivery retries cannot replace this snapshot.
|
|
2559
|
+
personalConnectionDelegations: jsonb("personal_connection_delegations")
|
|
2560
|
+
.$type<McpPersonalConnectionDelegation[]>()
|
|
2561
|
+
.notNull()
|
|
2562
|
+
.default([]),
|
|
2492
2563
|
status: text("status").notNull().default("pending"),
|
|
2493
2564
|
attempts: integer("attempts").notNull().default(0),
|
|
2494
2565
|
updateId: uuid("update_id"),
|
|
@@ -4288,6 +4359,16 @@ export const scheduledTasks = pgTable(
|
|
|
4288
4359
|
runMode: text("run_mode").notNull().default("new_session_per_run"),
|
|
4289
4360
|
overlapPolicy: text("overlap_policy").notNull().default("allow_concurrent"),
|
|
4290
4361
|
agentConfig: jsonb("agent_config").$type<unknown>().notNull(),
|
|
4362
|
+
createdByKind: text("created_by_kind").notNull().default("service"),
|
|
4363
|
+
createdBySubjectId: text("created_by_subject_id").notNull().default("unattributed-legacy"),
|
|
4364
|
+
createdByContext: jsonb("created_by_context")
|
|
4365
|
+
.$type<Record<string, unknown>>()
|
|
4366
|
+
.notNull()
|
|
4367
|
+
.default({ backfill: true }),
|
|
4368
|
+
personalConnectionDelegations: jsonb("personal_connection_delegations")
|
|
4369
|
+
.$type<McpPersonalConnectionDelegation[]>()
|
|
4370
|
+
.notNull()
|
|
4371
|
+
.default([]),
|
|
4291
4372
|
reusableSessionId: uuid("reusable_session_id").references(() => sessions.id, {
|
|
4292
4373
|
onDelete: "set null",
|
|
4293
4374
|
}),
|
|
@@ -5305,3 +5386,5 @@ export const rigChanges = pgTable(
|
|
|
5305
5386
|
|
|
5306
5387
|
export * from "./workspace-instruction-policies-schema";
|
|
5307
5388
|
export * from "./preference-registry-schema";
|
|
5389
|
+
export * from "./memory-governance-schema";
|
|
5390
|
+
export * from "./scoped-knowledge-schema";
|