@opengeni/db 4.3.2 → 4.3.3-canary.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 (64) 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/codex-selection-diagnostics.d.ts +12 -0
  15. package/dist/connection-token-resolver.d.ts +2 -0
  16. package/dist/database.d.ts +7 -2
  17. package/dist/editable-artifact-durable-export.js +2 -2
  18. package/dist/editable-artifacts.js +3 -3
  19. package/dist/host-mcp-bindings.d.ts +3 -1
  20. package/dist/index.d.ts +32 -1
  21. package/dist/index.js +345 -75
  22. package/dist/index.js.map +1 -1
  23. package/dist/managed-auth-session-sets.js +3 -3
  24. package/dist/mcp-operations.d.ts +95 -0
  25. package/dist/mcp-operations.js +95 -0
  26. package/dist/mcp-operations.js.map +1 -0
  27. package/dist/plugin-packages.d.ts +1 -0
  28. package/dist/provision-roles.js +1 -1
  29. package/dist/retained-provider-commands.js +2 -2
  30. package/dist/runtime-posture.d.ts +3 -3
  31. package/dist/sandbox-transition-wait.d.ts +10 -0
  32. package/dist/schema.d.ts +517 -0
  33. package/dist/schema.js +3 -1
  34. package/dist/session-background-commands.js +4 -4
  35. package/dist/session-command-output.js +4 -4
  36. package/dist/session-event-slices.js +2 -2
  37. package/dist/session-mcp-progress.d.ts +8 -1
  38. package/dist/session-tenancy.js +3 -3
  39. package/dist/video-generation.js +3 -3
  40. package/dist/workspace-tool-defaults.js +4 -4
  41. package/drizzle/0459_mcp_operations.sql +396 -0
  42. package/drizzle/0460_host_export_message_attribution.sql +177 -0
  43. package/package.json +10 -6
  44. package/src/codex-selection-diagnostics.ts +25 -0
  45. package/src/computer-sessions.ts +5 -1
  46. package/src/connection-token-resolver.ts +2 -0
  47. package/src/database.ts +23 -2
  48. package/src/host-mcp-bindings.ts +14 -1
  49. package/src/index.ts +370 -60
  50. package/src/mcp-operations.ts +189 -0
  51. package/src/plugin-packages.ts +3 -0
  52. package/src/provision-roles.ts +6 -0
  53. package/src/runtime-posture.ts +50 -0
  54. package/src/sandbox-transition-wait.ts +45 -0
  55. package/src/schema.ts +46 -0
  56. package/src/session-mcp-progress.ts +26 -5
  57. package/dist/chunk-AI4NC6XW.js.map +0 -1
  58. package/dist/chunk-YVYBAWBU.js.map +0 -1
  59. /package/dist/{chunk-UVBPOGA7.js.map → chunk-232VC2LW.js.map} +0 -0
  60. /package/dist/{chunk-DVSLOUEI.js.map → chunk-2ZMTQVTR.js.map} +0 -0
  61. /package/dist/{chunk-F4BIHJ7J.js.map → chunk-EYF6MH6C.js.map} +0 -0
  62. /package/dist/{chunk-XBXANJQS.js.map → chunk-M7PSMVFF.js.map} +0 -0
  63. /package/dist/{chunk-PFBUHOI5.js.map → chunk-QLA3UQNX.js.map} +0 -0
  64. /package/dist/{chunk-UUPY6IGP.js.map → chunk-UK57QA2H.js.map} +0 -0
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  replayAppliedSessionFork,
15
15
  sessionTenancyProductActivated,
16
16
  transitionSessionVisibility
17
- } from "./chunk-XBXANJQS.js";
17
+ } from "./chunk-M7PSMVFF.js";
18
18
  import {
19
19
  AgentCommandAuthorityError,
20
20
  CHILD_LIFECYCLE_DEDUPE_PREFIX,
@@ -108,7 +108,7 @@ import {
108
108
  updateSessionCommandReceiptResult,
109
109
  workspaceControlLockBudget,
110
110
  workspaceControlRequestLockTimeoutMs
111
- } from "./chunk-F4BIHJ7J.js";
111
+ } from "./chunk-EYF6MH6C.js";
112
112
  import {
113
113
  ACTIVE_VIDEO_GENERATION_STATUSES,
114
114
  VideoGenerationCapacityError,
@@ -140,7 +140,7 @@ import {
140
140
  settleVideoGenerationFailure,
141
141
  settleVideoGenerationReady,
142
142
  updateWorkspaceVideoGenerationPolicy
143
- } from "./chunk-PFBUHOI5.js";
143
+ } from "./chunk-QLA3UQNX.js";
144
144
  import {
145
145
  ManagedAuthActorMutationInFlightError,
146
146
  ManagedAuthLoginSlotAlreadyExistsError,
@@ -163,7 +163,7 @@ import {
163
163
  reapManagedAuthIsolatedSessions,
164
164
  releaseManagedAuthActorMutationLease,
165
165
  validateManagedAuthActorMutationLease
166
- } from "./chunk-UUPY6IGP.js";
166
+ } from "./chunk-UK57QA2H.js";
167
167
  import {
168
168
  migrate,
169
169
  runMigrations
@@ -190,7 +190,7 @@ import {
190
190
  inspectRuntimeDatabasePosture,
191
191
  provisionRoles,
192
192
  runtimeDatabaseReadyCheck
193
- } from "./chunk-YVYBAWBU.js";
193
+ } from "./chunk-THJGMEK5.js";
194
194
  import {
195
195
  CanonicalHumanIdentityAuthorityError,
196
196
  CanonicalHumanIdentityConflictError,
@@ -204,7 +204,7 @@ import {
204
204
  getCanonicalHumanIdentityProjection,
205
205
  synchronizeCanonicalHumanLoginBindings,
206
206
  validateCanonicalHumanSession
207
- } from "./chunk-DVSLOUEI.js";
207
+ } from "./chunk-2ZMTQVTR.js";
208
208
  import {
209
209
  EDITABLE_ARTIFACT_INTENT_MAX_BYTES,
210
210
  EDITABLE_ARTIFACT_KERNEL_TAIL_MAX_BYTES,
@@ -215,7 +215,7 @@ import {
215
215
  PostgresEditableArtifactStore,
216
216
  listEditableArtifactIdsForSession,
217
217
  touchEditableArtifactSessionLink
218
- } from "./chunk-UVBPOGA7.js";
218
+ } from "./chunk-232VC2LW.js";
219
219
  import {
220
220
  SandboxProviderReadLockUnavailableError,
221
221
  SessionEventPersistenceError,
@@ -251,7 +251,7 @@ import {
251
251
  withWorkspaceSubjectRls,
252
252
  withWorkspaceSubjectSessionActivityRls,
253
253
  withWorkspaceUsageLock
254
- } from "./chunk-I4ITNMX2.js";
254
+ } from "./chunk-GVZJ7XSR.js";
255
255
  import {
256
256
  LOSSLESS_CONTENT_CODEC_VERSION,
257
257
  LOSSLESS_JSON_STRING_PREFIX,
@@ -491,9 +491,17 @@ import {
491
491
  xaiRotationSettings,
492
492
  xaiSessionAccountPins,
493
493
  xaiSubscriptionCredentials
494
- } from "./chunk-AI4NC6XW.js";
494
+ } from "./chunk-6TKL3GQO.js";
495
495
  import "./chunk-PZ5AY32C.js";
496
496
 
497
+ // src/codex-selection-diagnostics.ts
498
+ function codexSelectionDiagnostics(input) {
499
+ const transition = input.previousCredentialId === input.credentialId ? "unchanged" : input.previousCredentialId === null ? "assigned" : "switched";
500
+ const source = input.pinnedCredentialId === input.credentialId && input.pinSource !== "policy" ? "manual_pin" : "allocator";
501
+ const reason = input.reusedLease ? "lease_reused" : transition === "unchanged" ? "affinity_reused" : transition;
502
+ return { transition, source, reason };
503
+ }
504
+
497
505
  // src/session-execution-policy.ts
498
506
  import { and, desc, eq, inArray, sql } from "drizzle-orm";
499
507
  function latestStartedSessionTurnQuery(db, workspaceId, sessionId) {
@@ -5241,7 +5249,13 @@ async function inheritChildHostMcpTurnAuthorities(db, input) {
5241
5249
  }
5242
5250
  });
5243
5251
  }
5244
- async function authorizeDirectHostMcpUse(db, request) {
5252
+ async function authorizeDirectHostMcpUse(db, request, onAuthorized) {
5253
+ const snapshot = await resolveDirectHostMcpUseAuthority(db, request);
5254
+ if (!snapshot) return false;
5255
+ onAuthorized?.(snapshot);
5256
+ return true;
5257
+ }
5258
+ async function resolveDirectHostMcpUseAuthority(db, request) {
5245
5259
  if (!request.attemptId || !request.connectionRef.hostBinding) return false;
5246
5260
  const current = await getHostMcpLiveAttempt(
5247
5261
  db,
@@ -5321,7 +5335,7 @@ async function authorizeDirectHostMcpUse(db, request) {
5321
5335
  request.sessionId,
5322
5336
  request.attemptId
5323
5337
  );
5324
- return live !== null && live.id === request.turnId && live.executionGeneration === request.executionGeneration;
5338
+ return live !== null && live.id === request.turnId && live.executionGeneration === request.executionGeneration && a;
5325
5339
  });
5326
5340
  }
5327
5341
 
@@ -9207,6 +9221,7 @@ import {
9207
9221
  SANDBOX_PROVIDER_INSTANCE_ID_FIELDS_BY_BACKEND,
9208
9222
  parseWorkspaceArchiveDescriptor,
9209
9223
  parseWorkspaceArchiveObjectRef,
9224
+ validateWorkspaceArchiveObjectRef,
9210
9225
  workspaceArchivePayloadPresent,
9211
9226
  omitInlineWorkspaceArchiveWhenObjectRefPresent,
9212
9227
  stableJson as stableJson16,
@@ -9265,14 +9280,41 @@ import {
9265
9280
  } from "@opengeni/contracts";
9266
9281
  import {
9267
9282
  environmentsEncryptionKeyBytes as environmentsEncryptionKeyBytes2,
9268
- SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS,
9269
- SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS,
9283
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS as SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS2,
9270
9284
  WORKSPACE_OPENROUTER_CONNECTION_DOMAIN as WORKSPACE_OPENROUTER_CONNECTION_DOMAIN2,
9271
9285
  WORKSPACE_OPENROUTER_CONNECTION_ROLE,
9272
9286
  VERCEL_AI_GATEWAY_CONNECTION_DOMAIN as VERCEL_AI_GATEWAY_CONNECTION_DOMAIN2,
9273
9287
  VERCEL_AI_GATEWAY_CONNECTION_ROLE
9274
9288
  } from "@opengeni/config";
9275
9289
 
9290
+ // src/sandbox-transition-wait.ts
9291
+ import {
9292
+ SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS,
9293
+ SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS
9294
+ } from "@opengeni/config";
9295
+ var SandboxTransitionWaitBudget = class {
9296
+ constructor(waitMs, startedAt) {
9297
+ this.waitMs = waitMs;
9298
+ this.hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
9299
+ this.currentDeadline = Math.min(this.hardDeadline, startedAt + waitMs);
9300
+ }
9301
+ observedCapture = false;
9302
+ currentDeadline;
9303
+ hardDeadline;
9304
+ get deadline() {
9305
+ return this.currentDeadline;
9306
+ }
9307
+ observeCapture(remainingMs, now) {
9308
+ if (this.waitMs === 0 || this.observedCapture || remainingMs === null || remainingMs === void 0 || !Number.isSafeInteger(remainingMs) || remainingMs < 0 || remainingMs > SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS)
9309
+ return;
9310
+ this.observedCapture = true;
9311
+ this.currentDeadline = Math.min(
9312
+ this.hardDeadline,
9313
+ Math.max(this.currentDeadline, now + remainingMs + SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS)
9314
+ );
9315
+ }
9316
+ };
9317
+
9276
9318
  // src/workspace-membership-permissions.ts
9277
9319
  import { Permission as PermissionSchema } from "@opengeni/contracts";
9278
9320
  function normalizeWorkspaceMembershipPermissions(value) {
@@ -10198,7 +10240,12 @@ import {
10198
10240
  // src/session-mcp-progress.ts
10199
10241
  import { sql as sql22 } from "drizzle-orm";
10200
10242
  var SESSION_MCP_PROGRESS_CHARS = 600;
10201
- var SESSION_MCP_PROGRESS_STORAGE_CHARS = LOSSLESS_JSON_STRING_PREFIX.length + Math.ceil((SESSION_MCP_PROGRESS_CHARS + 1) * 2 / 3) * 8;
10243
+ function sessionTextStoragePrefixChars(maxChars) {
10244
+ return LOSSLESS_JSON_STRING_PREFIX.length + Math.ceil((maxChars + 1) * 2 / 3) * 8;
10245
+ }
10246
+ var SESSION_MCP_PROGRESS_STORAGE_CHARS = sessionTextStoragePrefixChars(
10247
+ SESSION_MCP_PROGRESS_CHARS
10248
+ );
10202
10249
  var SESSION_MCP_PROGRESS_UTF16_BASE64_PATTERN = "([A-Za-z0-9+/]{8})*([A-Za-z0-9+/]{8}|[A-Za-z0-9+/]{2}[AEIMQUYcgkosw048]=|[A-Za-z0-9+/]{5}[AQgw]==)";
10203
10250
  function sessionMcpProgressScalarIsEncodedSql(value, codecVersion) {
10204
10251
  return sql22`coalesce(
@@ -10209,18 +10256,27 @@ function sessionMcpProgressScalarIsEncodedSql(value, codecVersion) {
10209
10256
  false
10210
10257
  )`;
10211
10258
  }
10212
- function projectSessionMcpProgressText(storedPrefix, storedChars, codecVersion, scalarIsEncoded) {
10259
+ function projectSessionTextPrefix(storedPrefix, storedChars, codecVersion, scalarIsEncoded, maxChars) {
10213
10260
  if (storedPrefix === null) return { text: null, originalChars: null };
10214
10261
  const decoded = scalarIsEncoded ? fromPostgresLosslessJson(storedPrefix, codecVersion) : storedPrefix;
10215
10262
  const chars = Array.from(decoded);
10216
10263
  const encodedPrefixWasCut = decoded !== storedPrefix && (storedChars ?? 0) > Array.from(storedPrefix).length;
10217
10264
  const originalChars = encodedPrefixWasCut ? null : decoded === storedPrefix ? storedChars : chars.length;
10218
10265
  return {
10219
- text: chars.slice(0, SESSION_MCP_PROGRESS_CHARS).join(""),
10266
+ text: chars.slice(0, maxChars).join(""),
10220
10267
  originalChars,
10221
10268
  ...encodedPrefixWasCut ? { textTruncated: true } : {}
10222
10269
  };
10223
10270
  }
10271
+ function projectSessionMcpProgressText(storedPrefix, storedChars, codecVersion, scalarIsEncoded) {
10272
+ return projectSessionTextPrefix(
10273
+ storedPrefix,
10274
+ storedChars,
10275
+ codecVersion,
10276
+ scalarIsEncoded,
10277
+ SESSION_MCP_PROGRESS_CHARS
10278
+ );
10279
+ }
10224
10280
 
10225
10281
  // src/new-session-drafts.ts
10226
10282
  import {
@@ -34154,6 +34210,7 @@ async function listInstalledPluginPackages(db, workspaceId) {
34154
34210
  return rows.map((row) => {
34155
34211
  const manifest = objectValue3(row.manifest);
34156
34212
  const sourceUrl = stringValue5(manifest.sourceUrl);
34213
+ const logoUrl = stringValue5(objectValue3(manifest.discovery).logoUrl);
34157
34214
  const bom = pluginBom(manifest);
34158
34215
  if (row.status !== "active" && row.status !== "needs_attention") {
34159
34216
  throw new Error(`Unknown installed Plugin status: ${row.status}`);
@@ -34166,6 +34223,7 @@ async function listInstalledPluginPackages(db, workspaceId) {
34166
34223
  category: row.category,
34167
34224
  tags: stringArray3(manifest.tags).length > 0 ? stringArray3(manifest.tags) : stringArray3(row.tags),
34168
34225
  sourceUrl: sourceUrl && safeHttpUrl(sourceUrl) ? sourceUrl : null,
34226
+ logoUrl: logoUrl && safeHttpUrl(logoUrl) ? logoUrl : null,
34169
34227
  manifestDigest: row.manifestDigest,
34170
34228
  installationVersion: row.installationVersion,
34171
34229
  componentCount: bom.length,
@@ -40514,7 +40572,7 @@ async function prepareComputerSessionCreate(db, input) {
40514
40572
  requestDigest: digest2,
40515
40573
  state: "prepared",
40516
40574
  actorSubjectId: input.actorSubjectId
40517
- }).onConflictDoNothing({ target: interactionOperations.operationId }).returning();
40575
+ }).onConflictDoNothing().returning();
40518
40576
  if (!insertedOperation) {
40519
40577
  const existing = await loadOperation3(tx, input.workspaceId, input.operationId);
40520
40578
  if (!existing) {
@@ -61541,6 +61599,86 @@ async function setSessionCodexPin(db, workspaceId, sessionId, pinnedCredentialId
61541
61599
  )
61542
61600
  );
61543
61601
  }
61602
+ async function recordSessionCodexSelectionForTurnAttempt(db, input) {
61603
+ return await withWorkspaceSessionEventActivityRls(db, input.workspaceId, true, async (tx) => {
61604
+ const fence = await lockTurnAttemptWriteFenceTx(tx, {
61605
+ workspaceId: input.workspaceId,
61606
+ sessionId: input.sessionId,
61607
+ turnId: input.turnId,
61608
+ executionGeneration: input.executionGeneration,
61609
+ attemptId: input.attemptId,
61610
+ sessionLock: "no_key_update"
61611
+ });
61612
+ if (!fence.allowed || !fence.session) throw new CodexCredentialLeaseAttemptFencedError();
61613
+ const key2 = `opengeni:codex-selection:${input.attemptId}`;
61614
+ const prior = await tx.select().from(sessionEvents).where(
61615
+ and56(
61616
+ eq57(sessionEvents.workspaceId, input.workspaceId),
61617
+ eq57(sessionEvents.sessionId, input.sessionId),
61618
+ inArray31(sessionEvents.clientEventId, [key2, `${key2}:switch`])
61619
+ )
61620
+ ).orderBy(asc22(sessionEvents.sequence));
61621
+ if (prior.length) {
61622
+ const receipt2 = prior.find((event) => event.type === "codex.credential.selected");
61623
+ if (!receipt2) throw new Error("Codex selection receipt missing");
61624
+ const payload = sessionEventPayloadRecord(receipt2.payload, receipt2.payloadCodecVersion);
61625
+ if (payload.credentialId !== input.credentialId)
61626
+ throw new Error("An attempt cannot record two different Codex selections");
61627
+ return {
61628
+ events: prior.map(mapEvent2),
61629
+ diagnostics: {
61630
+ transition: payload.transition,
61631
+ source: payload.source,
61632
+ reason: payload.reason
61633
+ }
61634
+ };
61635
+ }
61636
+ const previousCredentialId = fence.session.codexLastCredentialId;
61637
+ const diagnostics = codexSelectionDiagnostics({ ...input, previousCredentialId });
61638
+ const events = [];
61639
+ if (previousCredentialId !== null && previousCredentialId !== input.credentialId) {
61640
+ events.push({
61641
+ type: "codex.account.switched",
61642
+ clientEventId: `${key2}:switch`,
61643
+ payload: {
61644
+ fromAccountId: previousCredentialId,
61645
+ toAccountId: input.credentialId,
61646
+ reason: diagnostics.source === "manual_pin" ? "manual" : "rotation"
61647
+ }
61648
+ });
61649
+ }
61650
+ events.push({
61651
+ type: "codex.credential.selected",
61652
+ clientEventId: key2,
61653
+ payload: {
61654
+ credentialId: input.credentialId,
61655
+ strategy: input.strategy,
61656
+ ...diagnostics,
61657
+ previousCredentialId,
61658
+ eligibleCount: input.eligibleCount,
61659
+ connectedCount: input.connectedCount,
61660
+ reused: input.reusedLease
61661
+ }
61662
+ });
61663
+ await tx.update(sessions).set({ codexLastCredentialId: input.credentialId }).where(
61664
+ and56(
61665
+ eq57(sessions.workspaceId, input.workspaceId),
61666
+ eq57(sessions.id, input.sessionId)
61667
+ )
61668
+ );
61669
+ const appended = await appendSessionEventsForTurnAttempt(
61670
+ tx,
61671
+ input.workspaceId,
61672
+ input.sessionId,
61673
+ input.turnId,
61674
+ input.executionGeneration,
61675
+ input.attemptId,
61676
+ events
61677
+ );
61678
+ if (!appended.accepted) throw new CodexCredentialLeaseAttemptFencedError();
61679
+ return { events: appended.events, diagnostics };
61680
+ });
61681
+ }
61544
61682
  async function recordSessionActiveCodexCredential(db, workspaceId, sessionId, credentialId) {
61545
61683
  await withWorkspaceSessionActivityRls(db, workspaceId, async (scopedDb) => {
61546
61684
  await scopedDb.update(sessions).set({ codexLastCredentialId: credentialId }).where(
@@ -64983,9 +65121,95 @@ async function listSessionsForSubject(db, workspaceId, options) {
64983
65121
  }
64984
65122
  throw new Error("unreachable session list retry state");
64985
65123
  }
65124
+ async function sessionFailureDiagnostics(db, workspaceId, session) {
65125
+ if (session.status !== "failed") return null;
65126
+ const scope = and56(
65127
+ eq57(sessionEvents.workspaceId, workspaceId),
65128
+ eq57(sessionEvents.sessionId, session.id),
65129
+ lte4(sessionEvents.sequence, session.lastSequence),
65130
+ isNull16(sessionEvents.duplicateOfEventId),
65131
+ or12(
65132
+ isNull16(sessionEvents.turnAssociation),
65133
+ eq57(sessionEvents.turnAssociation, "current")
65134
+ )
65135
+ );
65136
+ const maxChars = 1024;
65137
+ const storageChars = sessionTextStoragePrefixChars(maxChars);
65138
+ const diagnosticFields = ["error", "message", "detail", "lastRetryableError", "code", "status"];
65139
+ const boundedFields = diagnosticFields.flatMap((field) => {
65140
+ const scalar = sql81`case when jsonb_typeof(${sessionEvents.payload}->${field}::text) = 'string'
65141
+ then ${sessionEvents.payload}->>${field}::text else null end`;
65142
+ return [
65143
+ sql81`${field}::text`,
65144
+ sql81`jsonb_build_object(
65145
+ 'prefix', left(${scalar}, ${storageChars}), 'chars', char_length(${scalar}),
65146
+ 'encoded', ${sessionMcpProgressScalarIsEncodedSql(scalar, sessionEvents.payloadCodecVersion)})`
65147
+ ];
65148
+ });
65149
+ const projectedPayload = sql81`jsonb_build_object(
65150
+ ${sql81.join(boundedFields, sql81`, `)},
65151
+ 'providerRecoveryCount', case when jsonb_typeof(${sessionEvents.payload}->'providerRecoveryCount') = 'number'
65152
+ and length((${sessionEvents.payload}->'providerRecoveryCount')::text) <= 16
65153
+ then ${sessionEvents.payload}->'providerRecoveryCount' else 'null'::jsonb end)`;
65154
+ const latest = async (type) => {
65155
+ const [row] = await db.select({
65156
+ id: sessionEvents.id,
65157
+ sequence: sessionEvents.sequence,
65158
+ turnId: sessionEvents.turnId,
65159
+ occurredAt: sessionEvents.occurredAt,
65160
+ codecVersion: sessionEvents.payloadCodecVersion,
65161
+ payload: projectedPayload
65162
+ }).from(sessionEvents).where(and56(scope, eq57(sessionEvents.type, type))).orderBy(desc22(sessionEvents.sequence)).limit(1);
65163
+ if (!row) return null;
65164
+ const payload = {
65165
+ providerRecoveryCount: row.payload.providerRecoveryCount
65166
+ };
65167
+ const truncatedFields = [];
65168
+ for (const field of diagnosticFields) {
65169
+ const stored = row.payload[field];
65170
+ const projected = projectSessionTextPrefix(
65171
+ stored.prefix,
65172
+ stored.chars,
65173
+ row.codecVersion,
65174
+ stored.encoded,
65175
+ maxChars
65176
+ );
65177
+ payload[field] = projected.text;
65178
+ if (projected.textTruncated || (projected.originalChars ?? 0) > maxChars)
65179
+ truncatedFields.push(field);
65180
+ }
65181
+ payload.projection = { fieldsOnly: true, fieldLimitChars: maxChars, truncatedFields };
65182
+ return { ...row, payload, occurredAt: row.occurredAt.toISOString() };
65183
+ };
65184
+ const turnFailure = await latest("turn.failed");
65185
+ const latestStatus = await latest("session.status.changed");
65186
+ const statusPayload = latestStatus?.payload;
65187
+ if (latestStatus && (!turnFailure || latestStatus.sequence > turnFailure.sequence) && typeof statusPayload?.status === "string" && statusPayload.status !== "failed")
65188
+ return null;
65189
+ const preClaimFailure = statusPayload?.status === "failed" && statusPayload.code === "pre_claim_failure" ? latestStatus : null;
65190
+ const failure = preClaimFailure && (!turnFailure || preClaimFailure.sequence > turnFailure.sequence && (!preClaimFailure.turnId || preClaimFailure.turnId !== turnFailure.turnId)) ? preClaimFailure : turnFailure;
65191
+ if (!failure) return null;
65192
+ return {
65193
+ eventId: failure.id,
65194
+ sequence: failure.sequence,
65195
+ turnId: failure.turnId ?? null,
65196
+ occurredAt: failure.occurredAt,
65197
+ payload: failure.payload
65198
+ };
65199
+ }
64986
65200
  async function getSessionForSubject(db, workspaceId, sessionId, subjectId, relatedSessionAccess = "root") {
64987
65201
  return await withWorkspaceSubjectRls(db, workspaceId, subjectId, async (scopedDb) => {
64988
- const [row] = await scopedDb.select({ session: sessions, pin: sessionPins }).from(sessions).leftJoin(
65202
+ const [row] = await scopedDb.select({
65203
+ session: sessions,
65204
+ pin: sessionPins,
65205
+ cursor: sessionEventCursors
65206
+ }).from(sessions).leftJoin(
65207
+ sessionEventCursors,
65208
+ and56(
65209
+ eq57(sessionEventCursors.workspaceId, sessions.workspaceId),
65210
+ eq57(sessionEventCursors.sessionId, sessions.id)
65211
+ )
65212
+ ).leftJoin(
64989
65213
  sessionPins,
64990
65214
  and56(
64991
65215
  eq57(sessionPins.workspaceId, workspaceId),
@@ -65007,25 +65231,36 @@ async function getSessionForSubject(db, workspaceId, sessionId, subjectId, relat
65007
65231
  )
65008
65232
  ).limit(1);
65009
65233
  if (!row) return null;
65010
- const [session] = await canonicalSessionRowsFromEventCursors(scopedDb, workspaceId, [
65011
- row.session
65012
- ]);
65234
+ if (!row.cursor || row.cursor.accountId !== row.session.accountId || row.cursor.lastSequence < row.session.lastSequence) {
65235
+ throw new Error(`Session event cursor invariant failed for session ${sessionId}`);
65236
+ }
65237
+ const [session] = await withLatestStartedSessionPolicy(
65238
+ scopedDb,
65239
+ workspaceId,
65240
+ await withCurrentSessionInputWait(scopedDb, workspaceId, [
65241
+ { ...row.session, lastSequence: row.cursor.lastSequence }
65242
+ ])
65243
+ );
65013
65244
  if (!session) throw new Error(`Session event cursor missing for session ${sessionId}`);
65014
65245
  const mcpServers = await sessionMcpServerMetadataForSessions(scopedDb, workspaceId, [
65015
65246
  sessionId
65016
65247
  ]);
65017
65248
  const tenancyActivated = await sessionTenancyProductActivated(scopedDb, workspaceId);
65249
+ const failureDiagnostics = await sessionFailureDiagnostics(scopedDb, workspaceId, session);
65018
65250
  return projectSessionForRelatedAccess(
65019
- await mapSessionWithControl(
65020
- scopedDb,
65021
- session,
65022
- mcpServers.get(sessionId) ?? [],
65023
- mapSessionPin(row.pin),
65024
- mapSessionAttention(session, row.pin),
65025
- mapSessionArchive(row.pin),
65026
- void 0,
65027
- { subjectId, activated: tenancyActivated }
65028
- ),
65251
+ {
65252
+ ...await mapSessionWithControl(
65253
+ scopedDb,
65254
+ session,
65255
+ mcpServers.get(sessionId) ?? [],
65256
+ mapSessionPin(row.pin),
65257
+ mapSessionAttention(session, row.pin),
65258
+ mapSessionArchive(row.pin),
65259
+ void 0,
65260
+ { subjectId, activated: tenancyActivated }
65261
+ ),
65262
+ failureDiagnostics
65263
+ },
65029
65264
  relatedSessionAccess
65030
65265
  );
65031
65266
  });
@@ -69862,14 +70097,7 @@ function archiveCaptureRemainingMs(row) {
69862
70097
  return null;
69863
70098
  }
69864
70099
  const remainingMs = Number(row.archive_capture_remaining_ms);
69865
- return Number.isSafeInteger(remainingMs) && remainingMs >= 0 && remainingMs <= SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS ? remainingMs : null;
69866
- }
69867
- function extendSandboxTransitionDeadline(currentDeadline, hardDeadline, remainingCaptureMs, now) {
69868
- if (remainingCaptureMs === null || remainingCaptureMs === void 0) return currentDeadline;
69869
- return Math.min(
69870
- hardDeadline,
69871
- Math.max(currentDeadline, now + remainingCaptureMs + SANDBOX_LIFECYCLE_RETRY_HANDOFF_GRACE_MS)
69872
- );
70100
+ return Number.isSafeInteger(remainingMs) && remainingMs >= 0 && remainingMs <= SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS2 ? remainingMs : null;
69873
70101
  }
69874
70102
  function providerlessLeaseBackendPredicateSql() {
69875
70103
  const providerlessBackends = Object.entries(SANDBOX_PROVIDER_INSTANCE_ID_FIELDS_BY_BACKEND).filter(([, fields]) => fields.length === 0).map(([backend]) => backend);
@@ -70345,25 +70573,19 @@ async function acquireLease(db, input) {
70345
70573
  throw new Error("Sandbox lease archive capture wait is invalid");
70346
70574
  }
70347
70575
  const startedAt = performance.now();
70348
- const hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
70349
- let deadline = Math.min(hardDeadline, startedAt + captureWaitMs);
70576
+ const waitBudget = new SandboxTransitionWaitBudget(captureWaitMs, startedAt);
70350
70577
  let delayMs = 25;
70351
70578
  for (; ; ) {
70352
70579
  const result = await acquireLeaseOnce(db, input);
70353
70580
  const now = performance.now();
70354
70581
  if (captureWaitMs > 0 && result.role === "fenced" && result.reason === "capture_in_progress") {
70355
- deadline = extendSandboxTransitionDeadline(
70356
- deadline,
70357
- hardDeadline,
70358
- result.captureRemainingMs,
70359
- now
70360
- );
70582
+ waitBudget.observeCapture(result.captureRemainingMs, now);
70361
70583
  }
70362
- if (result.role !== "fenced" || result.reason === "superseded" || result.reason === "rotation_in_progress" || now >= deadline) {
70584
+ if (result.role !== "fenced" || result.reason === "superseded" || result.reason === "rotation_in_progress" || now >= waitBudget.deadline) {
70363
70585
  return result;
70364
70586
  }
70365
70587
  await waitForSandboxTransition(
70366
- Math.min(delayMs, Math.max(1, deadline - now)),
70588
+ Math.min(delayMs, Math.max(1, waitBudget.deadline - now)),
70367
70589
  input.waitSignal,
70368
70590
  "Sandbox lease transition wait cancelled"
70369
70591
  );
@@ -74139,8 +74361,7 @@ async function advanceWorkspaceGenerationForAuthority(db, authority, operationIn
74139
74361
  throw new Error("Workspace archive capture wait is invalid");
74140
74362
  }
74141
74363
  const startedAt = performance.now();
74142
- const hardDeadline = startedAt + SANDBOX_LIFECYCLE_TRANSITION_MAX_WAIT_MS;
74143
- let deadline = Math.min(hardDeadline, startedAt + captureWaitMs);
74364
+ const waitBudget = new SandboxTransitionWaitBudget(captureWaitMs, startedAt);
74144
74365
  let delayMs = 25;
74145
74366
  let captureWaitStartedAt;
74146
74367
  let captureWaitOutcome = "failed";
@@ -74157,19 +74378,14 @@ async function advanceWorkspaceGenerationForAuthority(db, authority, operationIn
74157
74378
  } catch (error) {
74158
74379
  const now = performance.now();
74159
74380
  if (captureWaitMs > 0 && error instanceof SandboxWorkspaceMutationFencedError && error.code === "capture_in_progress") {
74160
- deadline = extendSandboxTransitionDeadline(
74161
- deadline,
74162
- hardDeadline,
74163
- error.captureRemainingMs,
74164
- now
74165
- );
74381
+ waitBudget.observeCapture(error.captureRemainingMs, now);
74166
74382
  }
74167
- if (!(error instanceof SandboxWorkspaceMutationFencedError) || error.code !== "capture_in_progress" || now >= deadline) {
74383
+ if (!(error instanceof SandboxWorkspaceMutationFencedError) || error.code !== "capture_in_progress" || now >= waitBudget.deadline) {
74168
74384
  throw error;
74169
74385
  }
74170
74386
  captureWaitStartedAt ??= performance.now();
74171
74387
  await waitForSandboxTransition(
74172
- Math.min(delayMs, Math.max(1, deadline - now)),
74388
+ Math.min(delayMs, Math.max(1, waitBudget.deadline - now)),
74173
74389
  waitSignal,
74174
74390
  "Sandbox workspace mutation wait cancelled"
74175
74391
  );
@@ -75415,7 +75631,7 @@ async function claimWorkspaceArchiveCapture(db, input) {
75415
75631
  throw new Error("Workspace archive capture timeout is invalid");
75416
75632
  }
75417
75633
  const operationId = input.operationId ?? input.captureId;
75418
- const providerRequestId = operationId;
75634
+ const providerRequestId = randomUUID12();
75419
75635
  const captureAttempt = input.attempt ?? 1;
75420
75636
  const providerReplaySafe = input.providerReplaySafe === true;
75421
75637
  const takeoverSafe = input.takeoverSafe === true;
@@ -76187,7 +76403,17 @@ async function adoptLegacyModalCheckpointArtifact(db, input) {
76187
76403
  );
76188
76404
  }
76189
76405
  function publishedWorkspaceArchiveFields(input) {
76190
- const ref = parseWorkspaceArchiveObjectRef(input.workspaceArchiveRef) ?? void 0;
76406
+ const ref = input.workspaceArchiveRef == null ? void 0 : validateWorkspaceArchiveObjectRef(input.workspaceArchiveRef, {
76407
+ accountId: input.accountId,
76408
+ workspaceId: input.workspaceId,
76409
+ sandboxGroupId: input.sandboxGroupId,
76410
+ descriptor: input.workspaceArchiveMeta
76411
+ }) ?? void 0;
76412
+ if (input.workspaceArchiveRef != null && !ref) {
76413
+ throw new Error(
76414
+ "Invalid workspace archive object ref: publication scope or descriptor mismatch"
76415
+ );
76416
+ }
76191
76417
  const inline = typeof input.workspaceArchive === "string" && input.workspaceArchive.length > 0 ? input.workspaceArchive : void 0;
76192
76418
  if (!ref && !inline) {
76193
76419
  throw new Error("workspace archive publication requires inline bytes or an object ref");
@@ -76204,11 +76430,24 @@ function publishedWorkspaceArchiveFields(input) {
76204
76430
  }
76205
76431
  return { workspaceArchive: inline };
76206
76432
  }
76433
+ function workspaceArchiveCandidateFields(candidate, lockedResumeState) {
76434
+ if (!candidate) return {};
76435
+ const sessionState = lockedResumeState?.sessionState;
76436
+ const referenced = [
76437
+ sessionState?.workspaceArchiveRef,
76438
+ sessionState?.workspaceArchivePrevRef
76439
+ ].some((value) => {
76440
+ const ref = parseWorkspaceArchiveObjectRef(value);
76441
+ return ref?.key === candidate.key && ref.backend === candidate.backend;
76442
+ });
76443
+ return { candidateDisposition: referenced ? "already_referenced" : "unused" };
76444
+ }
76207
76445
  async function persistDrainSnapshot(db, input) {
76208
76446
  const workspaceArchiveMeta = input.workspaceArchive === null ? null : parseArchiveRevision(input.workspaceArchiveMeta);
76209
76447
  if (input.workspaceArchive !== null && !workspaceArchiveMeta) {
76210
76448
  throw new Error("Invalid verified workspace archive descriptor");
76211
76449
  }
76450
+ const published = input.workspaceArchive === null ? null : publishedWorkspaceArchiveFields(input);
76212
76451
  if (workspaceArchiveMeta?.version === 2 && (workspaceArchiveMeta.provider === "modal_snapshot_filesystem" || workspaceArchiveMeta.provider === "modal_snapshot_directory") && !input.checkpointArtifactId) {
76213
76452
  throw new Error("Modal native checkpoint publication requires a registered artifact");
76214
76453
  }
@@ -76246,10 +76485,15 @@ async function persistDrainSnapshot(db, input) {
76246
76485
  for update
76247
76486
  `);
76248
76487
  const row = guard[0];
76488
+ const candidateFields = workspaceArchiveCandidateFields(
76489
+ published?.workspaceArchiveRef,
76490
+ row?.resume_state
76491
+ );
76249
76492
  if (!row) {
76250
76493
  return {
76251
76494
  wrote: false,
76252
- archiveRevision: null
76495
+ archiveRevision: null,
76496
+ ...candidateFields
76253
76497
  };
76254
76498
  }
76255
76499
  const sourceLeaseMatches = input.expectedLeaseId === void 0 || row.id === input.expectedLeaseId;
@@ -76259,7 +76503,7 @@ async function persistDrainSnapshot(db, input) {
76259
76503
  const lateReceipt = recovery.lateArchiveCapture;
76260
76504
  const coldLatePublication = input.workspaceArchive !== null && input.expectedLeaseId !== void 0 && input.providerRequestId !== void 0 && row.id === input.expectedLeaseId && row.liveness === "cold" && Number(row.refcount) === 0 && Number(row.lease_epoch) === input.expectedEpoch + 1 && row.instance_id === null && Number(row.workspace_generation) === input.expectedWorkspaceGeneration && row.archive_capture_id === null && recovery.provider.status === "missing" && recovery.provider.instanceId === input.expectedInstanceId && recovery.restore.rematerializationId === null && (recovery.restore.status === "unrecoverable" || recovery.restore.status === "degraded" || recovery.restore.status === "pending") && lateReceipt?.sourceLeaseId === input.expectedLeaseId && lateReceipt.sourceLeaseEpoch === input.expectedEpoch && lateReceipt.sourceInstanceId === input.expectedInstanceId && lateReceipt.sourceWorkspaceGeneration === input.expectedWorkspaceGeneration && lateReceipt.providerRequestId === input.providerRequestId && !row.unsettled_mutation;
76261
76505
  if (!activePublication && !coldLatePublication) {
76262
- return { wrote: false, archiveRevision: null };
76506
+ return { wrote: false, archiveRevision: null, ...candidateFields };
76263
76507
  }
76264
76508
  const priorArchive = row.prior_archive ?? null;
76265
76509
  const priorArchivePrev = row.prior_archive_prev ?? null;
@@ -76271,7 +76515,7 @@ async function persistDrainSnapshot(db, input) {
76271
76515
  archiveRevision: null
76272
76516
  };
76273
76517
  }
76274
- const published = publishedWorkspaceArchiveFields(input);
76518
+ if (!published) throw new Error("Missing workspace archive publication fields");
76275
76519
  const priorMeta = parseArchiveRevision(priorSessionState?.workspaceArchiveMeta);
76276
76520
  if (activePublication && row.archive_capture_published_at !== null) {
76277
76521
  if (priorArchive === null && priorRef === null || priorMeta === null) {
@@ -76291,7 +76535,7 @@ async function persistDrainSnapshot(db, input) {
76291
76535
  )
76292
76536
  `);
76293
76537
  }
76294
- return { wrote: true, archiveRevision: priorMeta.revision };
76538
+ return { wrote: true, archiveRevision: priorMeta.revision, ...candidateFields };
76295
76539
  }
76296
76540
  const rotation = rotateWorkspaceArchives({
76297
76541
  resumeState: row.resume_state,
@@ -76345,12 +76589,14 @@ async function persistDrainSnapshot(db, input) {
76345
76589
  if (!folded) {
76346
76590
  return {
76347
76591
  wrote: false,
76348
- archiveRevision: null
76592
+ archiveRevision: null,
76593
+ ...candidateFields
76349
76594
  };
76350
76595
  }
76351
76596
  return {
76352
76597
  wrote: true,
76353
- archiveRevision: workspaceArchiveMeta?.revision ?? null
76598
+ archiveRevision: workspaceArchiveMeta?.revision ?? null,
76599
+ ...published.workspaceArchiveRef ? { candidateDisposition: "adopted" } : {}
76354
76600
  };
76355
76601
  }
76356
76602
  );
@@ -76627,12 +76873,27 @@ async function persistWarmSnapshot(db, input) {
76627
76873
  )
76628
76874
  ).limit(1) : [];
76629
76875
  const attemptMayPersistWorkspace = attempt !== void 0 && (attempt.state === "claimed" || attempt.state === "running" ? attempt.outcome === null : attempt.state === "closed" && (attempt.outcome === "completed" || attempt.outcome === "failed" || attempt.outcome === "requires_action"));
76876
+ const candidateLease = published.workspaceArchiveRef ? await scopedDb.execute(sql81`
76877
+ select jsonb_build_object('sessionState', jsonb_build_object(
76878
+ 'workspaceArchiveRef', resume_state #> '{sessionState,workspaceArchiveRef}',
76879
+ 'workspaceArchivePrevRef', resume_state #> '{sessionState,workspaceArchivePrevRef}'
76880
+ )) as resume_state
76881
+ from sandbox_leases
76882
+ where workspace_id = ${input.workspaceId}
76883
+ and sandbox_group_id = ${input.sandboxGroupId}
76884
+ for update
76885
+ `) : [];
76886
+ const candidateFields = workspaceArchiveCandidateFields(
76887
+ published.workspaceArchiveRef,
76888
+ candidateLease[0]?.resume_state
76889
+ );
76630
76890
  if (!attempt || attempt.accountId !== input.accountId || attempt.sandboxGroupId !== input.sandboxGroupId || interruption || !attemptMayPersistWorkspace) {
76631
76891
  return {
76632
76892
  wrote: false,
76633
76893
  throttled: false,
76634
76894
  superseded: true,
76635
- archiveRevision: null
76895
+ archiveRevision: null,
76896
+ ...candidateFields
76636
76897
  };
76637
76898
  }
76638
76899
  const guard = await scopedDb.execute(sql81`
@@ -76680,7 +76941,8 @@ async function persistWarmSnapshot(db, input) {
76680
76941
  wrote: false,
76681
76942
  throttled: false,
76682
76943
  superseded: false,
76683
- archiveRevision: null
76944
+ archiveRevision: null,
76945
+ ...candidateFields
76684
76946
  };
76685
76947
  }
76686
76948
  const priorArchive = guard[0].prior_archive ?? null;
@@ -76693,7 +76955,8 @@ async function persistWarmSnapshot(db, input) {
76693
76955
  wrote: false,
76694
76956
  throttled: false,
76695
76957
  superseded: true,
76696
- archiveRevision: null
76958
+ archiveRevision: null,
76959
+ ...candidateFields
76697
76960
  };
76698
76961
  }
76699
76962
  if (input.minIntervalMs > 0 && Number.isFinite(priorAtMs) && capturedAtMs - priorAtMs < input.minIntervalMs) {
@@ -76701,7 +76964,8 @@ async function persistWarmSnapshot(db, input) {
76701
76964
  wrote: false,
76702
76965
  throttled: true,
76703
76966
  superseded: false,
76704
- archiveRevision: null
76967
+ archiveRevision: null,
76968
+ ...candidateFields
76705
76969
  };
76706
76970
  }
76707
76971
  const rotation = rotateWorkspaceArchives({
@@ -76722,7 +76986,8 @@ async function persistWarmSnapshot(db, input) {
76722
76986
  wrote: false,
76723
76987
  throttled: false,
76724
76988
  superseded: false,
76725
- archiveRevision: null
76989
+ archiveRevision: null,
76990
+ ...candidateFields
76726
76991
  };
76727
76992
  }
76728
76993
  const livenessGuard = rowLiveness;
@@ -76752,14 +77017,16 @@ async function persistWarmSnapshot(db, input) {
76752
77017
  wrote: false,
76753
77018
  throttled: false,
76754
77019
  superseded: false,
76755
- archiveRevision: null
77020
+ archiveRevision: null,
77021
+ ...candidateFields
76756
77022
  };
76757
77023
  }
76758
77024
  return {
76759
77025
  wrote: true,
76760
77026
  throttled: false,
76761
77027
  superseded: false,
76762
- archiveRevision: workspaceArchiveMeta.revision
77028
+ archiveRevision: workspaceArchiveMeta.revision,
77029
+ ...published.workspaceArchiveRef ? { candidateDisposition: "adopted" } : {}
76763
77030
  };
76764
77031
  }
76765
77032
  );
@@ -82822,7 +83089,8 @@ async function claimSessionWorkForAttempt(db, workspaceId, input) {
82822
83089
  {
82823
83090
  stage: "session_attempts.claim",
82824
83091
  eventTypes: ["session.turn.attempt_claimed"],
82825
- maxAttempts: 3
83092
+ maxAttempts: 3,
83093
+ organizationMembershipFence: true
82826
83094
  },
82827
83095
  async (scopedDb) => await withSessionActivitySavepoint(scopedDb, async (tx) => {
82828
83096
  const deliverPendingUpdates = async (accountId, turnId, turnGeneration, nextSequence, occurredAt, triggerEventId, expectedXaiAuthority, options = {}) => {
@@ -93264,6 +93532,7 @@ export {
93264
93532
  closeSessionTurnAttemptInTransaction,
93265
93533
  closeSlackInteractionDelivery,
93266
93534
  codexCapacityRefreshBackoffMs,
93535
+ codexSelectionDiagnostics,
93267
93536
  commitBrowserRevisionPublication,
93268
93537
  commitBrowserSessionSuspension,
93269
93538
  commitBrowserStateUploadInTransaction,
@@ -94234,6 +94503,7 @@ export {
94234
94503
  recordRetainedProcessReconciliationProof,
94235
94504
  recordRetainedScreenshotArtifactError,
94236
94505
  recordSessionActiveCodexCredential,
94506
+ recordSessionCodexSelectionForTurnAttempt,
94237
94507
  recordSessionGoalProgressWithEvent,
94238
94508
  recordSkippedContextCompaction,
94239
94509
  recordSlackBotInstallCallbackFailure,