@sellable/install 0.1.611-wip.phase189.20260812.1 → 0.1.611

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.
@@ -3,13 +3,13 @@ FROM ${HERMES_IMAGE}
3
3
 
4
4
  USER root
5
5
 
6
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.611-wip.phase189.20260812.1
7
- ARG MCP_PACKAGE=@sellable/mcp@0.1.864
6
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.611
7
+ ARG MCP_PACKAGE=@sellable/mcp@0.1.866
8
8
  ARG INSTALLER_INTEGRITY
9
- ARG MCP_INTEGRITY=sha512-UevVd71zQL2FgnqYaeHBkTi73iUV0Lg5BchM5JNhUbvaFxAFQ2M1n9uSS18qVuM9Km0aGZ7a0k8M9e2AVPboAw==
9
+ ARG MCP_INTEGRITY=sha512-ry4l91gBit9s1z7aw+v2nq7ULkdugt5BGubJsZ9OPJHwNsCVe6x1iuEe/Alr5Fxr3tdSwUE1fti5PnusD2w86g==
10
10
 
11
- RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.611-wip.phase189.20260812.1" \
12
- && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.864" \
11
+ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.611" \
12
+ && test "${MCP_PACKAGE}" = "@sellable/mcp@0.1.866" \
13
13
  && test -n "${INSTALLER_INTEGRITY}" \
14
14
  && test "$(npm view "${INSTALLER_PACKAGE}" dist.integrity)" = "${INSTALLER_INTEGRITY}" \
15
15
  && test "$(npm view "${MCP_PACKAGE}" dist.integrity)" = "${MCP_INTEGRITY}" \
@@ -23,9 +23,9 @@ RUN test "${INSTALLER_PACKAGE}" = "@sellable/install@0.1.611-wip.phase189.202608
23
23
  && mkdir -p /opt/sellable-agent/install-root /opt/sellable-agent/mcp-root \
24
24
  && npm install --prefix /opt/sellable-agent/install-root --omit=dev --ignore-scripts --no-audit --no-fund "${INSTALLER_PACKAGE}" \
25
25
  && npm install --prefix /opt/sellable-agent/mcp-root --omit=dev --ignore-scripts --no-audit --no-fund "${MCP_PACKAGE}" \
26
- && node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.611-wip.phase189.20260812.1-wip.hermes-desktop.20260811160530' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.864') throw new Error('package identity rejected');" \
26
+ && node --input-type=module -e "import { readFileSync } from 'node:fs'; const install = JSON.parse(readFileSync('/opt/sellable-agent/install-root/node_modules/@sellable/install/package.json')); const mcp = JSON.parse(readFileSync('/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp/package.json')); if (install.name !== '@sellable/install' || install.version !== '0.1.609-wip.hermes-desktop.20260811160530' || mcp.name !== '@sellable/mcp' || mcp.version !== '0.1.866') throw new Error('package identity rejected');" \
27
27
  && node --input-type=module -e "import { buildExternalRuntimeClosure } from '/opt/sellable-agent/install-root/node_modules/@sellable/install/lib/sellable-agent/external-runtime-builder.mjs'; const built = buildExternalRuntimeClosure({ mcpPackageRoot: '/opt/sellable-agent/mcp-root/node_modules/@sellable/mcp', mcpNodeModulesRoot: '/opt/sellable-agent/mcp-root/node_modules', hermesSourceRoot: '/opt/hermes', ownerUid: 0, ownerGid: 0 }); if (!built.closureDigest) throw new Error('runtime closure rejected');" \
28
- && node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.611-wip.phase189.20260812.1', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.864', mcpIntegrity: process.argv[2] }; writeFileSync('/opt/sellable-agent/release.json', JSON.stringify(release) + '\\n', { mode: 0o444 }); chmodSync('/opt/sellable-agent/release.json', 0o444);" "${INSTALLER_INTEGRITY}" "${MCP_INTEGRITY}" \
28
+ && node --input-type=module -e "import { chmodSync, writeFileSync } from 'node:fs'; const release = { installerPackage: '@sellable/install@0.1.611', installerIntegrity: process.argv[1], mcpPackage: '@sellable/mcp@0.1.866', mcpIntegrity: process.argv[2] }; writeFileSync('/opt/sellable-agent/release.json', JSON.stringify(release) + '\\n', { mode: 0o444 }); chmodSync('/opt/sellable-agent/release.json', 0o444);" "${INSTALLER_INTEGRITY}" "${MCP_INTEGRITY}" \
29
29
  && npm cache clean --force
30
30
 
31
31
  COPY entrypoint.sh /usr/local/bin/sellable-agent-container-entrypoint
@@ -3,13 +3,13 @@
3
3
  This image is a dedicated Agent worker/runtime boundary beside an existing Hermes dashboard. It never replaces or reconfigures the dashboard container.
4
4
 
5
5
  Build from this directory after
6
- `@sellable/install@0.1.611-wip.phase189.20260812.1` is
6
+ `@sellable/install@0.1.611` is
7
7
  published:
8
8
 
9
9
  ```sh
10
10
  docker build --platform linux/amd64 \
11
11
  --build-arg INSTALLER_INTEGRITY='sha512-…' \
12
- --tag sellable-agent-host:0.1.611-wip.phase189.20260812.1-wip.hermes-desktop.20260811160530 .
12
+ --tag sellable-agent-host:0.1.609-wip.hermes-desktop.20260811160530 .
13
13
  ```
14
14
 
15
15
  Create a private `bootstrap/` directory owned by root with mode `0700`. It must contain `bootstrap.json`, `provider-auth`, and `slack-app`, each owned by root with mode `0600`. `bootstrap.json` contains only non-secret identities, hashes, package integrities, and the control-plane URL. The other two files contain the provider JSON and global Slack app token whose hashes are pinned by `bootstrap.json`.
@@ -28,7 +28,7 @@ import {
28
28
 
29
29
  const MANIFEST_VERSION = "sellable-agent-external-runtime-closure/v1";
30
30
  const MCP_PACKAGE = "@sellable/mcp";
31
- const MCP_VERSION = "0.1.864";
31
+ const MCP_VERSION = "0.1.866";
32
32
  const SAFE_COMPONENT = /^[A-Za-z0-9@._+-]+$/;
33
33
  const HERMES_EXCLUDES = new Set([".git", ".playwright", "node_modules"]);
34
34
 
@@ -40,7 +40,6 @@ import {
40
40
  import {
41
41
  buildAdminAgentServiceEnvironment,
42
42
  buildNativeHermesLaunch,
43
- buildRuntimeServingObservation,
44
43
  } from "../admin-artifact/node_modules/@sellable/install/lib/sellable-agent/fly-customer-worker.mjs";
45
44
  import sodium from "../admin-artifact/node_modules/libsodium-wrappers/dist/modules-esm/libsodium-wrappers.mjs";
46
45
  import { SELLABLE_ALLOWED_TOOLSETS } from "../fly-capabilities-bridge.mjs";
@@ -68,11 +67,11 @@ import {
68
67
  HERMES_SNAPSHOT_HOOKS,
69
68
  HERMES_SNAPSHOT_HOOK_ALLOWLIST_BYTES,
70
69
  applyHermesHostedBackgroundReviewPolicy,
70
+ ensureHermesOpportunitySequencesCron,
71
71
  ensureHermesSnapshotCron,
72
72
  markHermesSnapshotDirty,
73
73
  mergeHermesState,
74
74
  migrateLegacyHermesUserState,
75
- quarantineLegacyLightfieldVenv,
76
75
  reconcileHermesSnapshot,
77
76
  restoreLatestHermesSnapshot,
78
77
  } from "../hermes-memory-snapshot.mjs";
@@ -695,6 +694,10 @@ const ADMIN_LIVE_SKILLS_CONFIG_KEYS = Object.freeze([
695
694
  "disabled",
696
695
  "platform_disabled",
697
696
  ]);
697
+ const ADMIN_SEALED_SKILL_DIRECTORIES = new Set([
698
+ "sellable",
699
+ "opportunity-sequences",
700
+ ]);
698
701
 
699
702
  function adminPreservedSlackToolsets(config) {
700
703
  const platformToolsets = config?.platform_toolsets;
@@ -724,7 +727,7 @@ function adminPreservedSkillsIdentity(profileRoot) {
724
727
  const walk = (directory, relativePath = "") => {
725
728
  for (const name of readdirSync(directory).sort()) {
726
729
  const nextRelative = relativePath ? `${relativePath}/${name}` : name;
727
- if (nextRelative === "sellable") continue;
730
+ if (ADMIN_SEALED_SKILL_DIRECTORIES.has(nextRelative)) continue;
728
731
  const path = join(directory, name);
729
732
  const stat = lstatSync(path);
730
733
  if (stat.isSymbolicLink()) {
@@ -1031,12 +1034,22 @@ async function materializeAdminProfile({
1031
1034
  hermesCli: HERMES,
1032
1035
  });
1033
1036
  if (!memoryCron.ok) throw new Error(memoryCron.code);
1037
+ const opportunitySequencesCron = await ensureHermesOpportunitySequencesCron({
1038
+ profileId: profile,
1039
+ profileRoot: profileHome,
1040
+ hermesRoot: DATA_ROOT,
1041
+ statePath: layout.statePath,
1042
+ });
1043
+ if (!opportunitySequencesCron.ok) {
1044
+ throw new Error(opportunitySequencesCron.code);
1045
+ }
1034
1046
  return {
1035
1047
  stage,
1036
1048
  promotion: promoted.promotion,
1037
1049
  profile,
1038
1050
  profileHome,
1039
1051
  adminHome,
1052
+ opportunitySequencesCron,
1040
1053
  observedSoulRawSha256: promoted.observedSoulRawSha256,
1041
1054
  servers: [serverProofs.sellable, serverProofs["sellable-admin"]].map(
1042
1055
  ({ tools: _tools, ...proof }) => proof
@@ -1187,70 +1200,6 @@ function operationIdentity(claim, exchange) {
1187
1200
  };
1188
1201
  }
1189
1202
 
1190
- function operationSnapshotIdentity(claim, exchange) {
1191
- const authority = claim?.runtimeAuthority;
1192
- if (!authority) return undefined;
1193
- return {
1194
- operationId: claim.operation.id,
1195
- authorityGeneration: authority.authorityGeneration,
1196
- runtimeArtifactId: authority.assignedRuntimeArtifactId,
1197
- sourceMachineId: exchange.workerId,
1198
- sourceMachineVersion: authority.machineVersion,
1199
- sourceBootSessionId: BOOT_SESSION_ID,
1200
- profileSchemaVersion: "admin-native-profile/v2",
1201
- };
1202
- }
1203
-
1204
- function adminServingObservation(activeLaunch, activeGateway, exchange) {
1205
- try {
1206
- const authority = activeLaunch?.claim?.runtimeAuthority;
1207
- const running =
1208
- activeGateway?.child?.exitCode === null && !activeGateway.child.killed;
1209
- const productMcp = activeLaunch?.profile?.servers?.find(
1210
- (server) => server.alias === "sellable"
1211
- );
1212
- const adminMcp = activeLaunch?.profile?.servers?.find(
1213
- (server) => server.alias === "sellable-admin"
1214
- );
1215
- if (!authority || !running || !activeLaunch.slackProof) return null;
1216
- const observedAt = new Date();
1217
- return buildRuntimeServingObservation({
1218
- scope: authority.scope,
1219
- kind: "ADMIN",
1220
- operationId: activeLaunch.claim.operation.id,
1221
- workspaceId: activeLaunch.claim.operation.workspaceId,
1222
- agentId: activeLaunch.claim.operation.agentId,
1223
- runtimeId: authority.runtimeId,
1224
- authorityGeneration: authority.authorityGeneration,
1225
- runtimeArtifactId: authority.runtimeArtifactId,
1226
- machineId: exchange.workerId,
1227
- machineVersion: authority.machineVersion,
1228
- bootSessionId: BOOT_SESSION_ID,
1229
- profileIdentity: activeLaunch.profile.profile,
1230
- processIdentity: `gateway-${activeGateway.child.pid}-${activeLaunch.claim.operation.fence}`,
1231
- observedAt: observedAt.toISOString(),
1232
- expiresAt: new Date(observedAt.getTime() + 120_000).toISOString(),
1233
- slack: {
1234
- authenticated: true,
1235
- socketModeConnected: true,
1236
- apiReachable: true,
1237
- },
1238
- productMcp: {
1239
- serverInfoName: productMcp?.serverInfoName,
1240
- toolCount: productMcp?.toolCount,
1241
- },
1242
- adminMcp: {
1243
- serverInfoName: adminMcp?.serverInfoName,
1244
- toolCount: adminMcp?.toolCount,
1245
- },
1246
- nativeGateway: true,
1247
- customerRouting: false,
1248
- });
1249
- } catch {
1250
- return null;
1251
- }
1252
- }
1253
-
1254
1203
  function startOperationHeartbeat({ claim, exchange, client }) {
1255
1204
  const identity = operationIdentity(claim, exchange);
1256
1205
  let stopped = false;
@@ -1759,42 +1708,6 @@ function nativeSlackProfileInput(claim, installed) {
1759
1708
  };
1760
1709
  }
1761
1710
 
1762
- async function proveAdminSlackServing(claim, secrets) {
1763
- const slack = claim.runtimeContract?.slack;
1764
- if (!slack) throw new Error("admin_runtime_slack_contract_rejected");
1765
- const post = (method, token) =>
1766
- fetch(`https://slack.com/api/${method}`, {
1767
- method: "POST",
1768
- headers: {
1769
- authorization: `Bearer ${token}`,
1770
- "content-type": "application/x-www-form-urlencoded",
1771
- },
1772
- body: "",
1773
- signal: AbortSignal.timeout(15_000),
1774
- });
1775
- const [authResponse, socketResponse] = await Promise.all([
1776
- post("auth.test", secrets.slackBot),
1777
- post("apps.connections.open", secrets.slackApp),
1778
- ]);
1779
- const [auth, socket] = await Promise.all([
1780
- authResponse.json(),
1781
- socketResponse.json(),
1782
- ]);
1783
- if (
1784
- !authResponse.ok ||
1785
- auth?.ok !== true ||
1786
- auth.team_id !== slack.teamId ||
1787
- auth.user_id !== slack.botUserId ||
1788
- !socketResponse.ok ||
1789
- socket?.ok !== true ||
1790
- typeof socket.url !== "string" ||
1791
- !/^wss:\/\//.test(socket.url)
1792
- ) {
1793
- throw new Error("admin_runtime_slack_serving_rejected");
1794
- }
1795
- return true;
1796
- }
1797
-
1798
1711
  async function fetchDeliveryCiphertext({
1799
1712
  operation,
1800
1713
  identity,
@@ -2351,12 +2264,7 @@ function completionReceipt({
2351
2264
  };
2352
2265
  }
2353
2266
 
2354
- async function flushHermesSnapshot({
2355
- client,
2356
- profileId,
2357
- profileRoot,
2358
- operationIdentity,
2359
- }) {
2267
+ async function flushHermesSnapshot({ client, profileId, profileRoot }) {
2360
2268
  try {
2361
2269
  markHermesSnapshotDirty(profileRoot);
2362
2270
  return await reconcileHermesSnapshot({
@@ -2365,24 +2273,13 @@ async function flushHermesSnapshot({
2365
2273
  hermesRoot: DATA_ROOT,
2366
2274
  hermesVersion: "0.20.0",
2367
2275
  debounceMs: 0,
2368
- operationIdentity,
2369
- upload: ({
2370
- archiveDigest,
2371
- archiveBytes,
2372
- sourceProfileId,
2373
- bytes,
2374
- ok: _ok,
2375
- status: _status,
2376
- hermesVersion: _hermesVersion,
2377
- ...v2
2378
- }) =>
2276
+ upload: ({ archiveDigest, archiveBytes, sourceProfileId, bytes }) =>
2379
2277
  client.putMemorySnapshot(
2380
2278
  {
2381
2279
  archiveDigest,
2382
2280
  archiveBytes,
2383
2281
  hermesVersion: "0.20.0",
2384
2282
  sourceProfileId,
2385
- ...v2,
2386
2283
  },
2387
2284
  bytes
2388
2285
  ),
@@ -3095,11 +2992,6 @@ async function runAdminProduction() {
3095
2992
  callerProfileId: activeLaunch.profile.profile,
3096
2993
  }),
3097
2994
  leaseSeconds: 60,
3098
- servingObservation: adminServingObservation(
3099
- activeLaunch,
3100
- activeGateway,
3101
- exchange
3102
- ),
3103
2995
  })
3104
2996
  : await client.claim(60);
3105
2997
  } catch (error) {
@@ -3169,6 +3061,16 @@ async function runAdminProduction() {
3169
3061
  ),
3170
3062
  });
3171
3063
  }
3064
+ if (
3065
+ activeLaunch &&
3066
+ (!activeGateway ||
3067
+ activeGateway.child.exitCode !== null ||
3068
+ activeGateway.child.killed)
3069
+ ) {
3070
+ await sleep(Math.min(30_000, 500 * 2 ** Math.min(failures, 6)));
3071
+ activeGateway = await startNativeGateway(activeLaunch);
3072
+ failures = 0;
3073
+ }
3172
3074
  await sleep(1_000);
3173
3075
  continue;
3174
3076
  }
@@ -3280,14 +3182,6 @@ async function runAdminProduction() {
3280
3182
  fetchLatest: () => client.getMemorySnapshot(),
3281
3183
  });
3282
3184
  if (!memoryRestore.ok) throw new Error(memoryRestore.code);
3283
- const legacyLightfieldVenv = quarantineLegacyLightfieldVenv({
3284
- profileId: basename(profileContract.profileHome),
3285
- profileRoot: profileContract.profileHome,
3286
- hermesRoot: DATA_ROOT,
3287
- });
3288
- if (!legacyLightfieldVenv.ok) {
3289
- throw new Error(legacyLightfieldVenv.code);
3290
- }
3291
3185
  const legacyUserState = migrateLegacyHermesUserState({
3292
3186
  profileId: basename(profileContract.profileHome),
3293
3187
  profileRoot: profileContract.profileHome,
@@ -3320,7 +3214,6 @@ async function runAdminProduction() {
3320
3214
  client,
3321
3215
  profileId: profile.profile,
3322
3216
  profileRoot: profile.profileHome,
3323
- operationIdentity: operationSnapshotIdentity(claim, exchange),
3324
3217
  });
3325
3218
  const settings = settingsProof(
3326
3219
  imported.receipt.generationRoot,
@@ -3355,14 +3248,8 @@ async function runAdminProduction() {
3355
3248
  modelAuth,
3356
3249
  });
3357
3250
  operationHeartbeat.assertHealthy();
3358
- const slackProof =
3359
- desiredLifecycle === "ON"
3360
- ? await proveAdminSlackServing(claim, secrets)
3361
- : false;
3362
3251
  const candidateLaunch =
3363
- desiredLifecycle === "ON"
3364
- ? { profile, claim, installed, slackProof }
3365
- : null;
3252
+ desiredLifecycle === "ON" ? { profile, claim, installed } : null;
3366
3253
  let candidateGateway = null;
3367
3254
  try {
3368
3255
  if (candidateLaunch) {
@@ -4,9 +4,9 @@ FROM ${HERMES_IMAGE}
4
4
 
5
5
  USER root
6
6
 
7
- ARG MCP_PACKAGE=@sellable/mcp@0.1.864
8
- ARG MCP_INTEGRITY=sha512-UevVd71zQL2FgnqYaeHBkTi73iUV0Lg5BchM5JNhUbvaFxAFQ2M1n9uSS18qVuM9Km0aGZ7a0k8M9e2AVPboAw==
9
- ARG INSTALLER_PACKAGE=@sellable/install@0.1.611-wip.phase189.20260812.1
7
+ ARG MCP_PACKAGE=@sellable/mcp@0.1.866
8
+ ARG MCP_INTEGRITY=sha512-ry4l91gBit9s1z7aw+v2nq7ULkdugt5BGubJsZ9OPJHwNsCVe6x1iuEe/Alr5Fxr3tdSwUE1fti5PnusD2w86g==
9
+ ARG INSTALLER_PACKAGE=@sellable/install@0.1.611
10
10
  ARG ADMIN_MCP_PACKAGE=@sellable/admin-mcp@0.1.186-wip.phase158.20260802034727
11
11
  ARG ADMIN_MCP_INTEGRITY=sha512-qYNew5wd2IfgVcp1UYOG9QvpF/8Mx19YJ5HQtMKzvSfUf3evePjtaKsoXLf2C/GUJ5QlLlHJo84VWOI3V01+9A==
12
12
  ARG TUS_JS_CLIENT_VERSION=4.3.1
@@ -19,7 +19,6 @@ import { dirname, join } from "node:path";
19
19
  import { pathToFileURL } from "node:url";
20
20
  import {
21
21
  buildNativeHermesLaunch,
22
- buildRuntimeServingObservation,
23
22
  clearCustomerRuntimeSecrets,
24
23
  installCustomerRuntimeSecrets,
25
24
  } from "../fly-customer-worker.mjs";
@@ -46,7 +45,6 @@ import {
46
45
  ensureHermesSnapshotCron,
47
46
  markHermesSnapshotDirty,
48
47
  migrateLegacyHermesUserState,
49
- quarantineLegacyLightfieldVenv,
50
48
  reconcileHermesSnapshot,
51
49
  restoreLatestHermesSnapshot,
52
50
  } from "../hermes-memory-snapshot.mjs";
@@ -98,9 +96,9 @@ const RUNTIME_GENERATION = Number(
98
96
  const BOOT_SESSION_ID = randomUUID();
99
97
  const HERMES_VERSION = process.env.SELLABLE_AGENT_HERMES_VERSION ?? "0.20.0";
100
98
  const INSTALLER_PACKAGE =
101
- process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.611-wip.phase189.20260812.1";
99
+ process.env.SELLABLE_AGENT_INSTALLER_PACKAGE ?? "@sellable/install@0.1.611";
102
100
  const MCP_PACKAGE =
103
- process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.864";
101
+ process.env.SELLABLE_AGENT_MCP_PACKAGE ?? "@sellable/mcp@0.1.866";
104
102
 
105
103
  const sha256 = (value) => createHash("sha256").update(value).digest("hex");
106
104
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
@@ -402,59 +400,6 @@ function operationIdentity(claim, exchange) {
402
400
  };
403
401
  }
404
402
 
405
- function operationSnapshotIdentity(claim, exchange) {
406
- const authority = claim?.runtimeAuthority;
407
- if (!authority) return undefined;
408
- return {
409
- operationId: claim.operation.id,
410
- authorityGeneration: authority.authorityGeneration,
411
- runtimeArtifactId: authority.assignedRuntimeArtifactId,
412
- sourceMachineId: exchange.workerId,
413
- sourceMachineVersion: authority.machineVersion,
414
- sourceBootSessionId: BOOT_SESSION_ID,
415
- profileSchemaVersion: "native-slack-profile/v2",
416
- };
417
- }
418
-
419
- function customerServingObservation(activeRuntime, exchange) {
420
- try {
421
- const authority = activeRuntime?.claim?.runtimeAuthority;
422
- const gateway = activeRuntime?.gateway?.readback?.();
423
- if (!authority || !gateway?.running || !activeRuntime.apiServerReadiness) {
424
- return null;
425
- }
426
- const observedAt = new Date();
427
- return buildRuntimeServingObservation({
428
- scope: authority.scope,
429
- kind: "CUSTOMER",
430
- operationId: activeRuntime.claim.operation.id,
431
- workspaceId: activeRuntime.claim.operation.workspaceId,
432
- agentId: activeRuntime.claim.operation.agentId,
433
- runtimeId: authority.runtimeId,
434
- authorityGeneration: authority.authorityGeneration,
435
- runtimeArtifactId: authority.runtimeArtifactId,
436
- machineId: exchange.workerId,
437
- machineVersion: authority.machineVersion,
438
- bootSessionId: BOOT_SESSION_ID,
439
- profileIdentity: activeRuntime.desired.profileId,
440
- processIdentity: `gateway-${gateway.pid}-${activeRuntime.claim.operation.fence}`,
441
- observedAt: observedAt.toISOString(),
442
- expiresAt: new Date(observedAt.getTime() + 120_000).toISOString(),
443
- slack: {
444
- authenticated: true,
445
- socketModeConnected: true,
446
- apiReachable: true,
447
- },
448
- productMcp: { serverInfoName: "sellable-mcp", toolCount: 193 },
449
- adminMcp: null,
450
- nativeGateway: true,
451
- customerRouting: true,
452
- });
453
- } catch {
454
- return null;
455
- }
456
- }
457
-
458
403
  function startOperationHeartbeat({ claim, exchange, client }) {
459
404
  const identity = operationIdentity(claim, exchange);
460
405
  let stopped = false;
@@ -2641,12 +2586,7 @@ function completionReceipt({
2641
2586
  };
2642
2587
  }
2643
2588
 
2644
- async function flushHermesSnapshot({
2645
- client,
2646
- profileId,
2647
- profileRoot,
2648
- operationIdentity,
2649
- }) {
2589
+ async function flushHermesSnapshot({ client, profileId, profileRoot }) {
2650
2590
  try {
2651
2591
  markHermesSnapshotDirty(profileRoot);
2652
2592
  return await reconcileHermesSnapshot({
@@ -2655,24 +2595,13 @@ async function flushHermesSnapshot({
2655
2595
  hermesRoot: DATA_ROOT,
2656
2596
  hermesVersion: HERMES_VERSION,
2657
2597
  debounceMs: 0,
2658
- operationIdentity,
2659
- upload: ({
2660
- archiveDigest,
2661
- archiveBytes,
2662
- sourceProfileId,
2663
- bytes,
2664
- ok: _ok,
2665
- status: _status,
2666
- hermesVersion: _hermesVersion,
2667
- ...v2
2668
- }) =>
2598
+ upload: ({ archiveDigest, archiveBytes, sourceProfileId, bytes }) =>
2669
2599
  client.putMemorySnapshot(
2670
2600
  {
2671
2601
  archiveDigest,
2672
2602
  archiveBytes,
2673
2603
  hermesVersion: HERMES_VERSION,
2674
2604
  sourceProfileId,
2675
- ...v2,
2676
2605
  },
2677
2606
  bytes
2678
2607
  ),
@@ -2746,12 +2675,6 @@ async function processOperation({ claim, exchange, client, identity }) {
2746
2675
  fetchLatest: () => client.getMemorySnapshot(),
2747
2676
  });
2748
2677
  if (!memoryRestore.ok) throw new Error(memoryRestore.code);
2749
- const legacyLightfieldVenv = quarantineLegacyLightfieldVenv({
2750
- profileId: desired.profileId,
2751
- profileRoot,
2752
- hermesRoot: DATA_ROOT,
2753
- });
2754
- if (!legacyLightfieldVenv.ok) throw new Error(legacyLightfieldVenv.code);
2755
2678
  const legacyUserState = migrateLegacyHermesUserState({
2756
2679
  profileId: desired.profileId,
2757
2680
  profileRoot,
@@ -2803,7 +2726,6 @@ async function processOperation({ claim, exchange, client, identity }) {
2803
2726
  client,
2804
2727
  profileId: desired.profileId,
2805
2728
  profileRoot,
2806
- operationIdentity: operationSnapshotIdentity(claim, exchange),
2807
2729
  });
2808
2730
  const prove =
2809
2731
  claim.operation.action === "INSTANTIATE"
@@ -2886,7 +2808,6 @@ async function processOperation({ claim, exchange, client, identity }) {
2886
2808
  sharedAppCredentialPresent: false,
2887
2809
  });
2888
2810
  return {
2889
- claim,
2890
2811
  desired,
2891
2812
  expected: secrets.expected,
2892
2813
  secrets,
@@ -2896,7 +2817,6 @@ async function processOperation({ claim, exchange, client, identity }) {
2896
2817
  trustRootPem,
2897
2818
  action: claim.operation.action,
2898
2819
  gateway: proof.gateway ?? null,
2899
- apiServerReadiness: proof.apiServerReadiness ?? null,
2900
2820
  modelHealthReporter,
2901
2821
  };
2902
2822
  }
@@ -2999,10 +2919,6 @@ async function main() {
2999
2919
  callerProfileId: activeRuntime.desired.profileId,
3000
2920
  }),
3001
2921
  leaseSeconds: 60,
3002
- servingObservation: customerServingObservation(
3003
- activeRuntime,
3004
- exchange
3005
- ),
3006
2922
  })
3007
2923
  : await client.claim(60);
3008
2924
  } catch (error) {
@@ -3047,6 +2963,17 @@ async function main() {
3047
2963
  ),
3048
2964
  });
3049
2965
  }
2966
+ if (
2967
+ activeRuntime?.action !== "INSTANTIATE" &&
2968
+ activeRuntime?.gateway &&
2969
+ !activeRuntime.gateway.readback().running
2970
+ ) {
2971
+ activeRuntime.gateway = await startNativeGateway({
2972
+ desired: activeRuntime.desired,
2973
+ runtimeConfig: activeRuntime.runtimeConfig,
2974
+ secrets: activeRuntime.secrets,
2975
+ });
2976
+ }
3050
2977
  await sleep(1_000);
3051
2978
  continue;
3052
2979
  }
@@ -32,77 +32,6 @@ function stableJson(value) {
32
32
  return JSON.stringify(value);
33
33
  }
34
34
 
35
- // CUSTOMER and ADMIN runtimes share this one serving-observation builder.
36
- export function buildRuntimeServingObservation(input = {}) {
37
- const keys = [
38
- "scope",
39
- "kind",
40
- "operationId",
41
- "workspaceId",
42
- "agentId",
43
- "runtimeId",
44
- "authorityGeneration",
45
- "runtimeArtifactId",
46
- "machineId",
47
- "machineVersion",
48
- "bootSessionId",
49
- "profileIdentity",
50
- "processIdentity",
51
- "observedAt",
52
- "expiresAt",
53
- "slack",
54
- "productMcp",
55
- "adminMcp",
56
- "nativeGateway",
57
- "customerRouting",
58
- ];
59
- const identity = (value) =>
60
- typeof value === "string" && SAFE_ID.test(value);
61
- const mcp = (value, name, tools) =>
62
- exactKeys(value, ["serverInfoName", "toolCount"]) &&
63
- value.serverInfoName === name &&
64
- value.toolCount === tools;
65
- const observedAt = Date.parse(input.observedAt ?? "");
66
- const expiresAt = Date.parse(input.expiresAt ?? "");
67
- const kindExact =
68
- input.kind === "CUSTOMER"
69
- ? input.adminMcp === null && input.customerRouting === true
70
- : input.kind === "ADMIN" &&
71
- mcp(input.adminMcp, "sellable-admin-mcp", 46) &&
72
- input.customerRouting === false;
73
- if (
74
- !exactKeys(input, keys) ||
75
- !["ASSIGNED", "CANDIDATE"].includes(input.scope) ||
76
- !keys
77
- .slice(2, 13)
78
- .filter((key) => key !== "authorityGeneration")
79
- .every((key) => identity(input[key])) ||
80
- !Number.isSafeInteger(input.authorityGeneration) ||
81
- input.authorityGeneration < 1 ||
82
- !Number.isFinite(observedAt) ||
83
- !Number.isFinite(expiresAt) ||
84
- expiresAt <= observedAt ||
85
- expiresAt - observedAt > 5 * 60_000 ||
86
- !exactKeys(input.slack, [
87
- "authenticated",
88
- "socketModeConnected",
89
- "apiReachable",
90
- ]) ||
91
- input.slack.authenticated !== true ||
92
- input.slack.socketModeConnected !== true ||
93
- input.slack.apiReachable !== true ||
94
- !mcp(input.productMcp, "sellable-mcp", 193) ||
95
- input.nativeGateway !== true ||
96
- !kindExact
97
- ) {
98
- throw new Error("runtime_serving_observation_rejected");
99
- }
100
- return Object.freeze({
101
- schemaVersion: "sellable-agent-serving-observation/v2",
102
- ...input,
103
- });
104
- }
105
-
106
35
  export function buildAgentServiceEnvironment({
107
36
  workspaceId,
108
37
  agentId,