@opengeni/db 4.3.2 → 4.3.3-canary.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.
Files changed (54) hide show
  1. package/dist/canonical-human-identities.js +3 -3
  2. package/dist/{chunk-UVBPOGA7.js → chunk-232VC2LW.js} +2 -2
  3. package/dist/{chunk-DVSLOUEI.js → chunk-2ZMTQVTR.js} +2 -2
  4. package/dist/{chunk-AI4NC6XW.js → chunk-6TKL3GQO.js} +47 -1
  5. package/dist/chunk-6TKL3GQO.js.map +1 -0
  6. package/dist/{chunk-F4BIHJ7J.js → chunk-EYF6MH6C.js} +4 -4
  7. package/dist/{chunk-I4ITNMX2.js → chunk-GVZJ7XSR.js} +16 -4
  8. package/dist/{chunk-I4ITNMX2.js.map → chunk-GVZJ7XSR.js.map} +1 -1
  9. package/dist/{chunk-XBXANJQS.js → chunk-M7PSMVFF.js} +2 -2
  10. package/dist/{chunk-PFBUHOI5.js → chunk-QLA3UQNX.js} +3 -3
  11. package/dist/{chunk-YVYBAWBU.js → chunk-THJGMEK5.js} +53 -1
  12. package/dist/chunk-THJGMEK5.js.map +1 -0
  13. package/dist/{chunk-UUPY6IGP.js → chunk-UK57QA2H.js} +2 -2
  14. package/dist/connection-token-resolver.d.ts +2 -0
  15. package/dist/database.d.ts +7 -2
  16. package/dist/editable-artifact-durable-export.js +2 -2
  17. package/dist/editable-artifacts.js +3 -3
  18. package/dist/host-mcp-bindings.d.ts +3 -1
  19. package/dist/index.d.ts +9 -0
  20. package/dist/index.js +85 -26
  21. package/dist/index.js.map +1 -1
  22. package/dist/managed-auth-session-sets.js +3 -3
  23. package/dist/mcp-operations.d.ts +95 -0
  24. package/dist/mcp-operations.js +95 -0
  25. package/dist/mcp-operations.js.map +1 -0
  26. package/dist/provision-roles.js +1 -1
  27. package/dist/retained-provider-commands.js +2 -2
  28. package/dist/runtime-posture.d.ts +3 -3
  29. package/dist/schema.d.ts +517 -0
  30. package/dist/schema.js +3 -1
  31. package/dist/session-background-commands.js +4 -4
  32. package/dist/session-command-output.js +4 -4
  33. package/dist/session-event-slices.js +2 -2
  34. package/dist/session-tenancy.js +3 -3
  35. package/dist/video-generation.js +3 -3
  36. package/dist/workspace-tool-defaults.js +4 -4
  37. package/drizzle/0459_mcp_operations.sql +396 -0
  38. package/package.json +10 -6
  39. package/src/connection-token-resolver.ts +2 -0
  40. package/src/database.ts +23 -2
  41. package/src/host-mcp-bindings.ts +14 -1
  42. package/src/index.ts +84 -4
  43. package/src/mcp-operations.ts +189 -0
  44. package/src/provision-roles.ts +6 -0
  45. package/src/runtime-posture.ts +50 -0
  46. package/src/schema.ts +46 -0
  47. package/dist/chunk-AI4NC6XW.js.map +0 -1
  48. package/dist/chunk-YVYBAWBU.js.map +0 -1
  49. /package/dist/{chunk-UVBPOGA7.js.map → chunk-232VC2LW.js.map} +0 -0
  50. /package/dist/{chunk-DVSLOUEI.js.map → chunk-2ZMTQVTR.js.map} +0 -0
  51. /package/dist/{chunk-F4BIHJ7J.js.map → chunk-EYF6MH6C.js.map} +0 -0
  52. /package/dist/{chunk-XBXANJQS.js.map → chunk-M7PSMVFF.js.map} +0 -0
  53. /package/dist/{chunk-PFBUHOI5.js.map → chunk-QLA3UQNX.js.map} +0 -0
  54. /package/dist/{chunk-UUPY6IGP.js.map → chunk-UK57QA2H.js.map} +0 -0
package/src/index.ts CHANGED
@@ -272,6 +272,7 @@ import {
272
272
  SANDBOX_PROVIDER_INSTANCE_ID_FIELDS_BY_BACKEND,
273
273
  parseWorkspaceArchiveDescriptor,
274
274
  parseWorkspaceArchiveObjectRef,
275
+ validateWorkspaceArchiveObjectRef,
275
276
  workspaceArchivePayloadPresent,
276
277
  omitInlineWorkspaceArchiveWhenObjectRefPresent,
277
278
  type WorkspaceArchiveObjectRef,
@@ -53448,13 +53449,30 @@ export async function adoptLegacyModalCheckpointArtifact(
53448
53449
  }
53449
53450
 
53450
53451
  function publishedWorkspaceArchiveFields(input: {
53452
+ accountId: string;
53453
+ workspaceId: string;
53454
+ sandboxGroupId: string;
53455
+ workspaceArchiveMeta: SandboxArchiveRevision;
53451
53456
  workspaceArchive?: string | null;
53452
53457
  workspaceArchiveRef?: WorkspaceArchiveObjectRef | null;
53453
53458
  }): {
53454
53459
  workspaceArchive?: string;
53455
53460
  workspaceArchiveRef?: WorkspaceArchiveObjectRef;
53456
53461
  } {
53457
- const ref = parseWorkspaceArchiveObjectRef(input.workspaceArchiveRef) ?? undefined;
53462
+ const ref =
53463
+ input.workspaceArchiveRef == null
53464
+ ? undefined
53465
+ : (validateWorkspaceArchiveObjectRef(input.workspaceArchiveRef, {
53466
+ accountId: input.accountId,
53467
+ workspaceId: input.workspaceId,
53468
+ sandboxGroupId: input.sandboxGroupId,
53469
+ descriptor: input.workspaceArchiveMeta,
53470
+ }) ?? undefined);
53471
+ if (input.workspaceArchiveRef != null && !ref) {
53472
+ throw new Error(
53473
+ "Invalid workspace archive object ref: publication scope or descriptor mismatch",
53474
+ );
53475
+ }
53458
53476
  const inline =
53459
53477
  typeof input.workspaceArchive === "string" && input.workspaceArchive.length > 0
53460
53478
  ? input.workspaceArchive
@@ -53475,6 +53493,30 @@ function publishedWorkspaceArchiveFields(input: {
53475
53493
  return { workspaceArchive: inline };
53476
53494
  }
53477
53495
 
53496
+ /** Object-candidate outcome from the publication transaction, independent of
53497
+ * lifecycle `wrote`. Absent for inline/provider receipts and pure CAS checks.
53498
+ * `unused` is NOT a retirement receipt: only the owner of a fresh candidate with
53499
+ * no other publication in flight may use it for immediate cleanup. Exceptions
53500
+ * give no disposition (commit may have happened). Legacy/shared keys and evicted
53501
+ * refs need durable no-reattachment evidence before deletion. */
53502
+ export type WorkspaceArchiveCandidateDisposition = "adopted" | "already_referenced" | "unused";
53503
+
53504
+ function workspaceArchiveCandidateFields(
53505
+ candidate: WorkspaceArchiveObjectRef | undefined,
53506
+ lockedResumeState: Record<string, unknown> | null | undefined,
53507
+ ): { candidateDisposition?: WorkspaceArchiveCandidateDisposition } {
53508
+ if (!candidate) return {};
53509
+ const sessionState = lockedResumeState?.sessionState as Record<string, unknown> | undefined;
53510
+ const referenced = [
53511
+ sessionState?.workspaceArchiveRef,
53512
+ sessionState?.workspaceArchivePrevRef,
53513
+ ].some((value) => {
53514
+ const ref = parseWorkspaceArchiveObjectRef(value);
53515
+ return ref?.key === candidate.key && ref.backend === candidate.backend;
53516
+ });
53517
+ return { candidateDisposition: referenced ? "already_referenced" : "unused" };
53518
+ }
53519
+
53478
53520
  export async function persistDrainSnapshot(
53479
53521
  db: Database,
53480
53522
  input: {
@@ -53511,12 +53553,14 @@ export async function persistDrainSnapshot(
53511
53553
  ): Promise<{
53512
53554
  wrote: boolean;
53513
53555
  archiveRevision: string | null;
53556
+ candidateDisposition?: WorkspaceArchiveCandidateDisposition;
53514
53557
  }> {
53515
53558
  const workspaceArchiveMeta =
53516
53559
  input.workspaceArchive === null ? null : parseArchiveRevision(input.workspaceArchiveMeta);
53517
53560
  if (input.workspaceArchive !== null && !workspaceArchiveMeta) {
53518
53561
  throw new Error("Invalid verified workspace archive descriptor");
53519
53562
  }
53563
+ const published = input.workspaceArchive === null ? null : publishedWorkspaceArchiveFields(input);
53520
53564
  if (
53521
53565
  workspaceArchiveMeta?.version === 2 &&
53522
53566
  (workspaceArchiveMeta.provider === "modal_snapshot_filesystem" ||
@@ -53575,10 +53619,15 @@ export async function persistDrainSnapshot(
53575
53619
  for update
53576
53620
  `);
53577
53621
  const row = guard[0];
53622
+ const candidateFields = workspaceArchiveCandidateFields(
53623
+ published?.workspaceArchiveRef,
53624
+ row?.resume_state,
53625
+ );
53578
53626
  if (!row) {
53579
53627
  return {
53580
53628
  wrote: false,
53581
53629
  archiveRevision: null,
53630
+ ...candidateFields,
53582
53631
  };
53583
53632
  }
53584
53633
  const sourceLeaseMatches =
@@ -53624,7 +53673,7 @@ export async function persistDrainSnapshot(
53624
53673
  lateReceipt.providerRequestId === input.providerRequestId &&
53625
53674
  !row.unsettled_mutation;
53626
53675
  if (!activePublication && !coldLatePublication) {
53627
- return { wrote: false, archiveRevision: null };
53676
+ return { wrote: false, archiveRevision: null, ...candidateFields };
53628
53677
  }
53629
53678
  const priorArchive = row.prior_archive ?? null;
53630
53679
  const priorArchivePrev = row.prior_archive_prev ?? null;
@@ -53642,7 +53691,7 @@ export async function persistDrainSnapshot(
53642
53691
  archiveRevision: null,
53643
53692
  };
53644
53693
  }
53645
- const published = publishedWorkspaceArchiveFields(input);
53694
+ if (!published) throw new Error("Missing workspace archive publication fields");
53646
53695
  const priorMeta = parseArchiveRevision(priorSessionState?.workspaceArchiveMeta);
53647
53696
  if (activePublication && row.archive_capture_published_at !== null) {
53648
53697
  // A predecessor and its successor may receive the same provider result.
@@ -53668,7 +53717,7 @@ export async function persistDrainSnapshot(
53668
53717
  )
53669
53718
  `);
53670
53719
  }
53671
- return { wrote: true, archiveRevision: priorMeta.revision };
53720
+ return { wrote: true, archiveRevision: priorMeta.revision, ...candidateFields };
53672
53721
  }
53673
53722
  const rotation = rotateWorkspaceArchives({
53674
53723
  resumeState: row.resume_state,
@@ -53729,11 +53778,13 @@ export async function persistDrainSnapshot(
53729
53778
  return {
53730
53779
  wrote: false,
53731
53780
  archiveRevision: null,
53781
+ ...candidateFields,
53732
53782
  };
53733
53783
  }
53734
53784
  return {
53735
53785
  wrote: true,
53736
53786
  archiveRevision: workspaceArchiveMeta?.revision ?? null,
53787
+ ...(published.workspaceArchiveRef ? { candidateDisposition: "adopted" as const } : {}),
53737
53788
  };
53738
53789
  },
53739
53790
  );
@@ -54132,6 +54183,7 @@ export async function persistWarmSnapshot(
54132
54183
  throttled: boolean;
54133
54184
  superseded: boolean;
54134
54185
  archiveRevision: string | null;
54186
+ candidateDisposition?: WorkspaceArchiveCandidateDisposition;
54135
54187
  }> {
54136
54188
  const capturedAtMs = input.capturedAtMs ?? Date.now();
54137
54189
  const workspaceArchiveMeta = parseArchiveRevision(input.workspaceArchiveMeta);
@@ -54201,6 +54253,26 @@ export async function persistWarmSnapshot(
54201
54253
  (attempt.outcome === "completed" ||
54202
54254
  attempt.outcome === "failed" ||
54203
54255
  attempt.outcome === "requires_action"));
54256
+ // Even a replay rejected by the attempt/epoch/capture guards may name
54257
+ // a committed current or previous object. Inspect those slots under the
54258
+ // same lease lock as publication, after the canonical workspace lock.
54259
+ // This conveys no retirement or no-future-reattachment authority.
54260
+ const candidateLease = published.workspaceArchiveRef
54261
+ ? await scopedDb.execute<{ resume_state: Record<string, unknown> | null }>(sql`
54262
+ select jsonb_build_object('sessionState', jsonb_build_object(
54263
+ 'workspaceArchiveRef', resume_state #> '{sessionState,workspaceArchiveRef}',
54264
+ 'workspaceArchivePrevRef', resume_state #> '{sessionState,workspaceArchivePrevRef}'
54265
+ )) as resume_state
54266
+ from sandbox_leases
54267
+ where workspace_id = ${input.workspaceId}
54268
+ and sandbox_group_id = ${input.sandboxGroupId}
54269
+ for update
54270
+ `)
54271
+ : [];
54272
+ const candidateFields = workspaceArchiveCandidateFields(
54273
+ published.workspaceArchiveRef,
54274
+ candidateLease[0]?.resume_state,
54275
+ );
54204
54276
  if (
54205
54277
  !attempt ||
54206
54278
  attempt.accountId !== input.accountId ||
@@ -54213,6 +54285,7 @@ export async function persistWarmSnapshot(
54213
54285
  throttled: false,
54214
54286
  superseded: true,
54215
54287
  archiveRevision: null,
54288
+ ...candidateFields,
54216
54289
  };
54217
54290
  }
54218
54291
  const guard = await scopedDb.execute<{
@@ -54270,6 +54343,7 @@ export async function persistWarmSnapshot(
54270
54343
  throttled: false,
54271
54344
  superseded: false,
54272
54345
  archiveRevision: null,
54346
+ ...candidateFields,
54273
54347
  };
54274
54348
  }
54275
54349
  const priorArchive = guard[0]!.prior_archive ?? null;
@@ -54290,6 +54364,7 @@ export async function persistWarmSnapshot(
54290
54364
  throttled: false,
54291
54365
  superseded: true,
54292
54366
  archiveRevision: null,
54367
+ ...candidateFields,
54293
54368
  };
54294
54369
  }
54295
54370
  if (
@@ -54302,6 +54377,7 @@ export async function persistWarmSnapshot(
54302
54377
  throttled: true,
54303
54378
  superseded: false,
54304
54379
  archiveRevision: null,
54380
+ ...candidateFields,
54305
54381
  };
54306
54382
  }
54307
54383
  const rotation = rotateWorkspaceArchives({
@@ -54323,6 +54399,7 @@ export async function persistWarmSnapshot(
54323
54399
  throttled: false,
54324
54400
  superseded: false,
54325
54401
  archiveRevision: null,
54402
+ ...candidateFields,
54326
54403
  };
54327
54404
  }
54328
54405
  const livenessGuard: "warm" | "draining" = rowLiveness;
@@ -54355,6 +54432,7 @@ export async function persistWarmSnapshot(
54355
54432
  throttled: false,
54356
54433
  superseded: false,
54357
54434
  archiveRevision: null,
54435
+ ...candidateFields,
54358
54436
  };
54359
54437
  }
54360
54438
  return {
@@ -54362,6 +54440,7 @@ export async function persistWarmSnapshot(
54362
54440
  throttled: false,
54363
54441
  superseded: false,
54364
54442
  archiveRevision: workspaceArchiveMeta.revision,
54443
+ ...(published.workspaceArchiveRef ? { candidateDisposition: "adopted" as const } : {}),
54365
54444
  };
54366
54445
  },
54367
54446
  );
@@ -64024,6 +64103,7 @@ export async function claimSessionWorkForAttempt(
64024
64103
  stage: "session_attempts.claim",
64025
64104
  eventTypes: ["session.turn.attempt_claimed"],
64026
64105
  maxAttempts: 3,
64106
+ organizationMembershipFence: true,
64027
64107
  },
64028
64108
  async (scopedDb) =>
64029
64109
  await withSessionActivitySavepoint(scopedDb, async (tx) => {
@@ -0,0 +1,189 @@
1
+ import { AttemptToolResult } from "@opengeni/contracts";
2
+ import { sql } from "drizzle-orm";
3
+ import { type Database, withRlsContext } from "./database";
4
+ import {
5
+ fromPostgresLosslessJson,
6
+ toPostgresLosslessJson,
7
+ LOSSLESS_CONTENT_CODEC_VERSION,
8
+ } from "./lossless-json";
9
+
10
+ /** Worker-authenticated invocation identity, never model/HTTP/request JSON.
11
+ * Possessing a DB handle or matching GUCs does NOT authenticate a caller.
12
+ * Bind this tuple only after verifying the worker invocation credential. SQL
13
+ * then derives the principal and rechecks canonical live disclosure authority. */
14
+ export type McpOperationAttempt = {
15
+ accountId: string;
16
+ workspaceId: string;
17
+ sessionId: string;
18
+ turnId: string;
19
+ attemptId: string;
20
+ executionGeneration: number;
21
+ };
22
+
23
+ /** Structurally aligned with runtime CapturedMcpOperation, without a runtime dependency. */
24
+ export type CaptureMcpOperationInput = {
25
+ operationId: string;
26
+ sourceCallId?: string;
27
+ serverId: string;
28
+ originalTool: string;
29
+ observerTool: string;
30
+ destinationDigest: string;
31
+ argumentDigest: string;
32
+ authorityDigest: string;
33
+ };
34
+ export type McpOperationSelector =
35
+ | { operationId: string }
36
+ | { sourceTurnId: string; sourceCallId: string };
37
+ export type McpOperationRecord = Omit<CaptureMcpOperationInput, "sourceCallId"> & {
38
+ sourceCallId: string | null;
39
+ accountId: string;
40
+ workspaceId: string;
41
+ sessionId: string;
42
+ sourceTurnId: string;
43
+ sourceAttemptId: string;
44
+ sourceExecutionGeneration: number;
45
+ principalKind: "subject" | "service";
46
+ principalId: string;
47
+ /** captured means possibly dispatched, NEVER permission to replay a mutation. */
48
+ originalOutcome: "captured" | "completed" | "outcome_unknown";
49
+ originalResult: AttemptToolResult | null;
50
+ observationResult: AttemptToolResult | null;
51
+ receiptRevision: string | null;
52
+ receiptDigest: string | null;
53
+ };
54
+ export type McpOperationLookup =
55
+ | { status: "found"; operation: McpOperationRecord }
56
+ | { status: "not_found" | "ambiguous" };
57
+
58
+ async function command<T>(
59
+ db: Database,
60
+ attempt: McpOperationAttempt,
61
+ action: string,
62
+ payload: object,
63
+ ): Promise<T> {
64
+ return withRlsContext(
65
+ db,
66
+ { accountId: attempt.accountId, workspaceId: attempt.workspaceId },
67
+ async (tx) => {
68
+ const result =
69
+ await tx.execute(sql`select mcp_operation_command(${JSON.stringify(attempt)}::jsonb,
70
+ ${action}::text, ${JSON.stringify(payload)}::jsonb) as value`);
71
+ const rows = Array.isArray(result) ? result : result.rows;
72
+ if (!rows?.[0]) throw new Error("MCP operation command returned no receipt");
73
+ return rows[0].value as T;
74
+ },
75
+ undefined,
76
+ "none", // SQL owns membership -> tenancy -> control -> session lock order.
77
+ );
78
+ }
79
+
80
+ export function captureMcpOperation(
81
+ db: Database,
82
+ attempt: McpOperationAttempt,
83
+ operation: CaptureMcpOperationInput,
84
+ ) {
85
+ return command<"created" | "existing">(db, attempt, "capture", operation);
86
+ }
87
+ export async function settleOriginalMcpOperation(
88
+ db: Database,
89
+ attempt: McpOperationAttempt,
90
+ input:
91
+ | { operationId: string; outcome: "completed"; result: AttemptToolResult }
92
+ | { operationId: string; outcome: "outcome_unknown" },
93
+ ): Promise<void> {
94
+ const payload =
95
+ input.outcome === "completed"
96
+ ? {
97
+ ...input,
98
+ result: toPostgresLosslessJson(AttemptToolResult.parse(input.result)),
99
+ resultCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
100
+ }
101
+ : input;
102
+ const result = await command<{ status: string }>(db, attempt, "settle_original", payload);
103
+ if (result.status !== "settled") throw new Error("Original MCP operation not found");
104
+ }
105
+ export async function readMcpOperation(
106
+ db: Database,
107
+ attempt: McpOperationAttempt,
108
+ selector: McpOperationSelector,
109
+ ): Promise<McpOperationLookup> {
110
+ const result = await command<McpOperationLookup>(db, attempt, "read", selector);
111
+ if (result.status !== "found") return result;
112
+ const { originalResultCodecVersion, observationResultCodecVersion, ...operation } =
113
+ result.operation as McpOperationRecord & {
114
+ originalResultCodecVersion: number | null;
115
+ observationResultCodecVersion: number | null;
116
+ };
117
+ return {
118
+ status: "found",
119
+ operation: {
120
+ ...operation,
121
+ originalResult: fromPostgresLosslessJson(
122
+ operation.originalResult,
123
+ originalResultCodecVersion,
124
+ ),
125
+ observationResult: fromPostgresLosslessJson(
126
+ operation.observationResult,
127
+ observationResultCodecVersion,
128
+ ),
129
+ },
130
+ };
131
+ }
132
+ /** Claims authorize only the read observer; expiry never authorizes a mutation. */
133
+ export function claimMcpOperationObservation(
134
+ db: Database,
135
+ attempt: McpOperationAttempt,
136
+ operationId: string,
137
+ ) {
138
+ return command<
139
+ { status: "claimed"; claimId: string } | { status: "busy" | "terminal" | "not_found" }
140
+ >(db, attempt, "claim_read", { operationId });
141
+ }
142
+ export function settleMcpOperationObservation(
143
+ db: Database,
144
+ attempt: McpOperationAttempt,
145
+ input: {
146
+ operationId: string;
147
+ claimId: string;
148
+ receiptRevision: string;
149
+ result: AttemptToolResult;
150
+ },
151
+ ) {
152
+ // This atomically stores one receipt, not an autonomous session notification.
153
+ // Explicit operation_read is a new ordinary tool call: its existing result
154
+ // lifecycle delivers the evidence. Repeated explicit reads legitimately have
155
+ // distinct call outputs while the original timeout and receipt stay immutable.
156
+ return command<
157
+ | { status: "settled" | "existing" | "conflict"; receiptDigest: string }
158
+ | { status: "stale_claim" | "not_found" | "original_completed" }
159
+ >(db, attempt, "settle_observation", {
160
+ ...input,
161
+ result: toPostgresLosslessJson(AttemptToolResult.parse(input.result)),
162
+ resultCodecVersion: LOSSLESS_CONTENT_CODEC_VERSION,
163
+ });
164
+ }
165
+
166
+ /** Unknown/pending/error cleanup only; never releases or replaces a receipt. */
167
+ export function releaseMcpOperationObservation(
168
+ db: Database,
169
+ attempt: McpOperationAttempt,
170
+ input: { operationId: string; claimId: string },
171
+ ) {
172
+ return command<{ status: "released" | "stale_claim" | "terminal" | "not_found" }>(
173
+ db,
174
+ attempt,
175
+ "release_read",
176
+ input,
177
+ );
178
+ }
179
+
180
+ /** Bind only inside the trusted worker, after exact invocation authentication.
181
+ * Provider authorization and immutable binding fences remain the broker's job. */
182
+ export function createMcpOperationPersistence(db: Database, attempt: McpOperationAttempt) {
183
+ const frozen = { ...attempt };
184
+ return {
185
+ capture: (operation: CaptureMcpOperationInput) => captureMcpOperation(db, frozen, operation),
186
+ settleOriginal: (input: Parameters<typeof settleOriginalMcpOperation>[2]) =>
187
+ settleOriginalMcpOperation(db, frozen, input),
188
+ };
189
+ }
@@ -618,6 +618,10 @@ DECLARE
618
618
  BEGIN
619
619
  EXECUTE format('REVOKE CREATE ON DATABASE %I FROM %I', current_database(), ${literal(role)});
620
620
  IF EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = ${literal(schema)}) THEN
621
+ IF to_regprocedure(format('%I.mcp_operation_command(jsonb,text,jsonb)', ${literal(schema)})) IS NOT NULL THEN
622
+ EXECUTE format('REVOKE ALL ON FUNCTION %I.mcp_operation_command(jsonb,text,jsonb) FROM PUBLIC', ${literal(schema)});
623
+ EXECUTE format('GRANT EXECUTE ON FUNCTION %I.mcp_operation_command(jsonb,text,jsonb) TO %I', ${literal(schema)}, ${literal(role)});
624
+ END IF;
621
625
  EXECUTE format('GRANT USAGE ON SCHEMA %I TO %I', ${literal(schema)}, ${literal(role)});
622
626
  EXECUTE format('REVOKE CREATE ON SCHEMA %I FROM %I', ${literal(schema)}, ${literal(role)});
623
627
  EXECUTE format('REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA %I FROM %I', ${literal(schema)}, ${literal(role)});
@@ -2120,6 +2124,8 @@ BEGIN
2120
2124
  EXECUTE format('REVOKE CREATE ON SCHEMA opengeni_private FROM %I', ${literal(role)});
2121
2125
  EXECUTE format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA opengeni_private TO %I', ${literal(role)});
2122
2126
  FOREACH routine_signature IN ARRAY ARRAY[
2127
+ 'guard_mcp_operation_immutable()',
2128
+ 'mcp_operation_command_scoped(jsonb,text,jsonb)',
2123
2129
  'guard_workspace_owned_skill_head_delete()',
2124
2130
  'guard_workspace_owned_skill_history_delete()'
2125
2131
  ] LOOP
@@ -51,7 +51,24 @@ const AUTOMATIC_SESSION_TITLE_FANOUT_OUTBOX_TABLE = "automatic_session_title_fan
51
51
  const AUTOMATIC_SESSION_TITLE_QUARANTINE_FENCE_ROUTINE =
52
52
  "acquire_automatic_session_title_quarantine_fences_v1(integer)";
53
53
 
54
+ const MCP_OPERATION_CAPABILITY_ROUTINE = "mcp_operation_command(jsonb, text, jsonb)";
55
+ const MCP_OPERATION_AUTHORITY_TABLES = [
56
+ "mcp_operations",
57
+ "sessions",
58
+ "session_turns",
59
+ "session_turn_attempts",
60
+ "workspaces",
61
+ "workspace_inference_controls",
62
+ "organization_memberships",
63
+ "workspace_memberships",
64
+ "external_identity_links",
65
+ "external_link_turn_authorities",
66
+ "host_mcp_turn_authorities",
67
+ "scheduled_task_runs",
68
+ ] as const;
54
69
  const OWNER_INTERNAL_PRIVATE_ROUTINES = new Set<string>([
70
+ "guard_mcp_operation_immutable()",
71
+ "mcp_operation_command_scoped(jsonb, text, jsonb)",
55
72
  "guard_workspace_owned_skill_head_delete()",
56
73
  "guard_workspace_owned_skill_history_delete()",
57
74
  ...ARTIFACT_OUTBOX_CAPABILITY_ROUTINES,
@@ -557,6 +574,7 @@ const XAI_AUTHORITY_TABLES = [
557
574
  ] as const;
558
575
 
559
576
  export const RUNTIME_TARGET_SCHEMA_CAPABILITY_ROUTINES = [
577
+ MCP_OPERATION_CAPABILITY_ROUTINE,
560
578
  "skill_apply_lifecycle(uuid, uuid, jsonb, jsonb)",
561
579
  COMPANY_BRAIN_CONTEXT_INSPECTION_ROUTINE,
562
580
  COMPANY_BRAIN_CONTEXT_SELECTION_ROUTINE,
@@ -807,6 +825,7 @@ export const FORCE_RLS_TABLES = [
807
825
  "managed_auth_login_transactions",
808
826
  "managed_auth_session_set_operations",
809
827
  "managed_auth_session_sets",
828
+ "mcp_operations",
810
829
  "memory_slack_publication_configurations",
811
830
  "memory_slack_publication_receipts",
812
831
  "memory_slack_publications",
@@ -1381,6 +1400,7 @@ export const PROTECTED_NO_DIRECT_DML_TABLES = [
1381
1400
  "managed_auth_login_transactions",
1382
1401
  "managed_auth_session_set_operations",
1383
1402
  "managed_auth_session_sets",
1403
+ "mcp_operations",
1384
1404
  "organization_company_profile_agent_policies",
1385
1405
  "organization_company_profile_agent_policy_events",
1386
1406
  "organization_invitation_binding_events",
@@ -2231,6 +2251,19 @@ export function evaluateRuntimeDatabasePosture(
2231
2251
  );
2232
2252
  }
2233
2253
  }
2254
+ } else if (routine.name === MCP_OPERATION_CAPABILITY_ROUTINE) {
2255
+ const missing = MCP_OPERATION_AUTHORITY_TABLES.filter((name) => !tableByName.has(name));
2256
+ if (missing.length > 0) {
2257
+ violations.push(`MCP operation authority tables are missing: ${missing.join(", ")}`);
2258
+ } else if (
2259
+ MCP_OPERATION_AUTHORITY_TABLES.some(
2260
+ (name) => tableByName.get(name)!.owner !== routine.owner,
2261
+ )
2262
+ ) {
2263
+ violations.push(
2264
+ `MCP operation capability ${routine.name} authority table owners do not match`,
2265
+ );
2266
+ }
2234
2267
  } else if (routine.name === KNOWLEDGE_SOURCE_SYNC_LOCK_AUTHORITY_ROUTINE) {
2235
2268
  const missingAuthorityTables = KNOWLEDGE_SOURCE_SYNC_LOCK_AUTHORITY_TABLES.filter(
2236
2269
  (tableName) => !tableByName.has(tableName),
@@ -3385,6 +3418,23 @@ export function evaluateRuntimeDatabasePosture(
3385
3418
  violations.push(`runtime role owns private routine ${routine.name}`);
3386
3419
  }
3387
3420
  const ownerInternalRoutine = OWNER_INTERNAL_PRIVATE_ROUTINES.has(routine.name);
3421
+ if (
3422
+ [
3423
+ "guard_mcp_operation_immutable()",
3424
+ "mcp_operation_command_scoped(jsonb, text, jsonb)",
3425
+ ].includes(routine.name)
3426
+ ) {
3427
+ if (routine.execute || routine.publicExecute) {
3428
+ violations.push(
3429
+ `runtime or PUBLIC has forbidden EXECUTE on MCP operation internal routine ${routine.name}`,
3430
+ );
3431
+ }
3432
+ if (routine.owner !== tableByName.get("mcp_operations")?.owner) {
3433
+ violations.push(
3434
+ `MCP operation internal routine ${routine.name} owner does not match ledger owner`,
3435
+ );
3436
+ }
3437
+ }
3388
3438
  if (
3389
3439
  [
3390
3440
  "guard_workspace_owned_skill_head_delete()",
package/src/schema.ts CHANGED
@@ -6928,6 +6928,52 @@ export const sessionRealtimeContextProjections = pgTable(
6928
6928
  // First-class ownership for one accepted execution attempt. A workflow may
6929
6929
  // preallocate id, but this row is inserted only by the activity transaction
6930
6930
  // that actually claims the logical turn and registers its exact dispatch.
6931
+ // Protected EXECUTE-only ledger. SQL owns live-attempt/principal derivation,
6932
+ // immutable settlement, bounds, RLS and source ownership constraints.
6933
+ export const mcpOperations = pgTable(
6934
+ "mcp_operations",
6935
+ {
6936
+ operationId: uuid("operation_id").primaryKey(),
6937
+ accountId: uuid("account_id").notNull(),
6938
+ workspaceId: uuid("workspace_id").notNull(),
6939
+ sessionId: uuid("session_id").notNull(),
6940
+ sourceTurnId: uuid("source_turn_id").notNull(),
6941
+ sourceAttemptId: uuid("source_attempt_id").notNull(),
6942
+ sourceExecutionGeneration: integer("source_execution_generation").notNull(),
6943
+ sourceCallId: text("source_call_id"),
6944
+ principalKind: text("principal_kind").notNull(),
6945
+ principalId: text("principal_id").notNull(),
6946
+ principalMembershipId: uuid("principal_membership_id"),
6947
+ principalMembershipRevision: bigint("principal_membership_revision", { mode: "number" }),
6948
+ serverId: text("server_id").notNull(),
6949
+ originalTool: text("original_tool").notNull(),
6950
+ observerTool: text("observer_tool").notNull(),
6951
+ argumentDigest: text("argument_digest").notNull(),
6952
+ destinationDigest: text("destination_digest").notNull(),
6953
+ authorityDigest: text("authority_digest").notNull(),
6954
+ originalOutcome: text("original_outcome").notNull().default("captured"),
6955
+ originalResult: jsonb("original_result"),
6956
+ originalResultCodecVersion: integer("original_result_codec_version"),
6957
+ observationResult: jsonb("observation_result"),
6958
+ observationResultCodecVersion: integer("observation_result_codec_version"),
6959
+ receiptRevision: text("receipt_revision"),
6960
+ receiptDigest: text("receipt_digest"),
6961
+ observationClaimId: uuid("observation_claim_id"),
6962
+ observationClaimAttemptId: uuid("observation_claim_attempt_id"),
6963
+ observationClaimExpiresAt: timestamp("observation_claim_expires_at", { withTimezone: true }),
6964
+ createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
6965
+ observedAt: timestamp("observed_at", { withTimezone: true }),
6966
+ },
6967
+ (table) => ({
6968
+ source: index("mcp_operations_source_idx").on(
6969
+ table.workspaceId,
6970
+ table.sessionId,
6971
+ table.sourceTurnId,
6972
+ table.sourceCallId,
6973
+ ),
6974
+ }),
6975
+ );
6976
+
6931
6977
  export const sessionTurnAttempts = pgTable(
6932
6978
  "session_turn_attempts",
6933
6979
  {