agent-embassy 1.6.1 → 1.7.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 (105) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +9 -9
  3. package/README.zh-CN.md +9 -9
  4. package/SECURITY.md +34 -77
  5. package/dist/src/gateway/acp-client.d.ts +117 -0
  6. package/dist/src/gateway/acp-client.js +382 -0
  7. package/dist/src/gateway/acp-client.js.map +1 -0
  8. package/dist/src/gateway/acp-provider.d.ts +65 -0
  9. package/dist/src/gateway/acp-provider.js +163 -0
  10. package/dist/src/gateway/acp-provider.js.map +1 -0
  11. package/dist/src/gateway/claude-helper-protocol.d.ts +3 -1
  12. package/dist/src/gateway/claude-helper-protocol.js +15 -5
  13. package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
  14. package/dist/src/gateway/claude-helper-supervisor.d.ts +3 -1
  15. package/dist/src/gateway/claude-helper-supervisor.js +16 -2
  16. package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
  17. package/dist/src/gateway/claude-helper.js +4 -3
  18. package/dist/src/gateway/claude-helper.js.map +1 -1
  19. package/dist/src/gateway/claude-peer.d.ts +1 -1
  20. package/dist/src/gateway/claude-peer.js +11 -13
  21. package/dist/src/gateway/claude-peer.js.map +1 -1
  22. package/dist/src/gateway/claude-runtime.d.ts +0 -20
  23. package/dist/src/gateway/claude-runtime.js +6 -127
  24. package/dist/src/gateway/claude-runtime.js.map +1 -1
  25. package/dist/src/gateway/cli-copy.d.ts +1 -1
  26. package/dist/src/gateway/cli-copy.en.d.ts +3 -1
  27. package/dist/src/gateway/cli-copy.en.js +5 -2
  28. package/dist/src/gateway/cli-copy.en.js.map +1 -1
  29. package/dist/src/gateway/cli-copy.js +2 -0
  30. package/dist/src/gateway/cli-copy.js.map +1 -1
  31. package/dist/src/gateway/cli-copy.zh-CN.d.ts +3 -1
  32. package/dist/src/gateway/cli-copy.zh-CN.js +5 -2
  33. package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
  34. package/dist/src/gateway/cli.d.ts +2 -2
  35. package/dist/src/gateway/cli.js +73 -6
  36. package/dist/src/gateway/cli.js.map +1 -1
  37. package/dist/src/gateway/codex-app-server.d.ts +5 -74
  38. package/dist/src/gateway/codex-app-server.js +9 -599
  39. package/dist/src/gateway/codex-app-server.js.map +1 -1
  40. package/dist/src/gateway/codex-doctor.d.ts +33 -0
  41. package/dist/src/gateway/codex-doctor.js +148 -0
  42. package/dist/src/gateway/codex-doctor.js.map +1 -0
  43. package/dist/src/gateway/codex-local-transport.d.ts +13 -26
  44. package/dist/src/gateway/codex-local-transport.js +31 -76
  45. package/dist/src/gateway/codex-local-transport.js.map +1 -1
  46. package/dist/src/gateway/compatibility.d.ts +6 -66
  47. package/dist/src/gateway/compatibility.js +14 -296
  48. package/dist/src/gateway/compatibility.js.map +1 -1
  49. package/dist/src/gateway/config.d.ts +9 -0
  50. package/dist/src/gateway/config.js +6 -2
  51. package/dist/src/gateway/config.js.map +1 -1
  52. package/dist/src/gateway/control.d.ts +16 -1
  53. package/dist/src/gateway/control.js +128 -59
  54. package/dist/src/gateway/control.js.map +1 -1
  55. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  56. package/dist/src/gateway/dashboard-copy.en.d.ts +19 -44
  57. package/dist/src/gateway/dashboard-copy.en.js +42 -67
  58. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  59. package/dist/src/gateway/dashboard-copy.js +19 -44
  60. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  61. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +19 -44
  62. package/dist/src/gateway/dashboard-copy.zh-CN.js +42 -67
  63. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  64. package/dist/src/gateway/dashboard-model.d.ts +41 -76
  65. package/dist/src/gateway/dashboard-model.js +167 -257
  66. package/dist/src/gateway/dashboard-model.js.map +1 -1
  67. package/dist/src/gateway/dashboard.d.ts +0 -3
  68. package/dist/src/gateway/dashboard.js +77 -76
  69. package/dist/src/gateway/dashboard.js.map +1 -1
  70. package/dist/src/gateway/deepseek-detect.d.ts +7 -6
  71. package/dist/src/gateway/deepseek-detect.js +31 -115
  72. package/dist/src/gateway/deepseek-detect.js.map +1 -1
  73. package/dist/src/gateway/live-dashboard-app/app.js +175 -621
  74. package/dist/src/gateway/live-dashboard-command.js +2 -4
  75. package/dist/src/gateway/live-dashboard-command.js.map +1 -1
  76. package/dist/src/gateway/live-dashboard-http.d.ts +1 -2
  77. package/dist/src/gateway/live-dashboard-http.js +14 -15
  78. package/dist/src/gateway/live-dashboard-http.js.map +1 -1
  79. package/dist/src/gateway/progress-watch-machine.d.ts +1 -4
  80. package/dist/src/gateway/progress-watch-machine.js.map +1 -1
  81. package/dist/src/gateway/provenance-envelope.d.ts +3 -2
  82. package/dist/src/gateway/provenance-envelope.js +44 -11
  83. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  84. package/dist/src/gateway/providers.d.ts +19 -85
  85. package/dist/src/gateway/providers.js +132 -835
  86. package/dist/src/gateway/providers.js.map +1 -1
  87. package/dist/src/gateway/server.d.ts +8 -9
  88. package/dist/src/gateway/server.js +63 -99
  89. package/dist/src/gateway/server.js.map +1 -1
  90. package/dist/src/gateway/service.d.ts +48 -51
  91. package/dist/src/gateway/service.js +748 -540
  92. package/dist/src/gateway/service.js.map +1 -1
  93. package/dist/src/gateway/store.d.ts +20 -29
  94. package/dist/src/gateway/store.js +306 -838
  95. package/dist/src/gateway/store.js.map +1 -1
  96. package/dist/src/gateway/types.d.ts +63 -54
  97. package/dist/src/gateway/types.js +51 -91
  98. package/dist/src/gateway/types.js.map +1 -1
  99. package/docs/CONFIGURATION.md +11 -10
  100. package/docs/CONFIGURATION.zh-CN.md +10 -9
  101. package/docs/DASHBOARD.md +4 -38
  102. package/docs/DASHBOARD.zh-CN.md +4 -2
  103. package/docs/GATEWAY-ARCHITECTURE.md +61 -119
  104. package/package.json +1 -1
  105. package/skills/embassy-peer/SKILL.md +6 -6
@@ -1,13 +1,12 @@
1
1
  import path from "node:path";
2
- import { chmod, lstat, mkdir, mkdtemp, readdir, realpath, rmdir, } from "node:fs/promises";
3
2
  import { BridgeError } from "../errors.js";
4
3
  import { CLAUDE_PEER_COMPATIBILITY, ClaudePeerAdapter, } from "./claude-peer.js";
5
- import { certifiedCompatibilityVersions, compatibilityCoversWrites, compatibilityProbeNames, evaluateCompatibilityAttestation, isCompatibilityAttestation, isCompatibilityVersion, sharesCompatibilityMajor, UNKNOWN_COMPATIBILITY_VERSION, } from "./compatibility.js";
6
- import { CODEX_APP_SERVER_WRITABLE_VERSIONS, CodexAppServerConnector, CodexConnectorError, codexWriteProbeFailure, } from "./codex-app-server.js";
4
+ import { CodexAppServerConnector, CodexConnectorError, } from "./codex-app-server.js";
7
5
  import { LocalCodexTransportError } from "./codex-local-transport.js";
8
6
  import { ClaudeNativeHelperSupervisor, } from "./claude-helper-supervisor.js";
9
7
  import { isDashboardLocale } from "./locale.js";
10
8
  import { composeProvenanceEnvelope } from "./provenance-envelope.js";
9
+ import { gatewayRegistrationIngressPrefixes } from "./types.js";
11
10
  const LOCAL_HOST = "this-mac";
12
11
  const STABLE_CLAUDE_ENDPOINT_GENERATION = "claude_local_endpoint";
13
12
  const NATIVE_CLAUDE_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
@@ -23,14 +22,8 @@ const DEFAULT_CODEX_CLEANUP_TIMEOUT_MS = 5_000;
23
22
  const DEFAULT_CODEX_CLEANUP_POLL_MS = 25;
24
23
  const DEFAULT_CODEX_RECOVERY_INITIAL_MS = 250;
25
24
  const DEFAULT_CODEX_RECOVERY_MAX_MS = 5_000;
25
+ const DEFAULT_CODEX_OBSERVATION_POLL_MS = 15_000;
26
26
  const MAX_CODEX_ENDPOINT_REFRESH_CANDIDATES = 3;
27
- const COMPATIBILITY_PROBE_THREAD_ID = "00000000-0000-7000-8000-000000000000";
28
- const CODEX_WRITE_PROBE_DIRECTORY_PREFIX = ".codex-write-probe-";
29
- const CODEX_WRITE_PROBE_ROOT = "write-probes";
30
- const MAX_CODEX_WRITE_PROBE_ATTEMPTS = 16;
31
- const CODEX_WRITE_PROBE_TRANSIENT_ERRNOS = new Set([
32
- "EAGAIN", "EIO", "EMFILE", "ENFILE",
33
- ]);
34
27
  const CLAUDE_CLEAN_PREWRITE_RETRY_CODES = new Set([
35
28
  "CLAUDE_PEER_TARGET_UNKNOWN",
36
29
  "CLAUDE_PEER_TARGET_STALE",
@@ -86,105 +79,6 @@ function claudeCleanPrewriteResult(error) {
86
79
  : "CLAUDE_DISPATCH_PREWRITE_FAILED",
87
80
  };
88
81
  }
89
- function passedProbe(name) {
90
- return { name, outcome: "pass" };
91
- }
92
- function failedProbe(name, safeErrorCode) {
93
- return { name, outcome: "fail", safeErrorCode };
94
- }
95
- function systemErrorCode(error) {
96
- return typeof error === "object" &&
97
- error !== null &&
98
- "code" in error &&
99
- typeof error.code === "string"
100
- ? error.code
101
- : undefined;
102
- }
103
- function transientCodexWriteProbeError(error) {
104
- return CODEX_WRITE_PROBE_TRANSIENT_ERRNOS.has(systemErrorCode(error) ?? "");
105
- }
106
- function safeCodexWriteProbeFilesystemFailure(error) {
107
- return (transientCodexWriteProbeError(error) ||
108
- systemErrorCode(error) === "ENOTEMPTY" ||
109
- (error instanceof BridgeError &&
110
- error.code === "CODEX_WRITE_PROBE_THREAD_SETUP_FAILED"));
111
- }
112
- async function attestCodexWriteProbeDirectory(directory) {
113
- try {
114
- const resolved = path.resolve(directory);
115
- const [metadata, canonical, entries] = await Promise.all([
116
- lstat(resolved, { bigint: true }),
117
- realpath(resolved),
118
- readdir(resolved),
119
- ]);
120
- const uid = process.getuid?.();
121
- if (uid === undefined ||
122
- !metadata.isDirectory() ||
123
- canonical !== resolved ||
124
- metadata.uid !== BigInt(uid) ||
125
- (metadata.mode & 511n) !== 448n) {
126
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory crossed its ownership, mode, or canonical-path boundary.");
127
- }
128
- if (entries.length !== 0) {
129
- throw new BridgeError("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", "The disposable Codex probe directory was not empty.");
130
- }
131
- return {
132
- dev: metadata.dev,
133
- ino: metadata.ino,
134
- mode: metadata.mode & 511n,
135
- mtimeNs: metadata.mtimeNs,
136
- uid: metadata.uid,
137
- };
138
- }
139
- catch (error) {
140
- if (error instanceof BridgeError)
141
- throw error;
142
- if (transientCodexWriteProbeError(error)) {
143
- throw new BridgeError("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", "A transient filesystem error prevented disposable probe attestation.");
144
- }
145
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be attested safely.");
146
- }
147
- }
148
- async function attestCodexWriteProbeRoot(root) {
149
- try {
150
- const resolved = path.resolve(root);
151
- const [metadata, canonical] = await Promise.all([
152
- lstat(resolved, { bigint: true }),
153
- realpath(resolved),
154
- ]);
155
- const uid = process.getuid?.();
156
- if (uid === undefined ||
157
- !metadata.isDirectory() ||
158
- canonical !== resolved ||
159
- metadata.uid !== BigInt(uid) ||
160
- (metadata.mode & 511n) !== 448n) {
161
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root changed outside its exact owned-directory boundary.");
162
- }
163
- return {
164
- dev: metadata.dev,
165
- ino: metadata.ino,
166
- mode: metadata.mode & 511n,
167
- uid: metadata.uid,
168
- };
169
- }
170
- catch (error) {
171
- if (error instanceof BridgeError)
172
- throw error;
173
- if (transientCodexWriteProbeError(error)) {
174
- return null;
175
- }
176
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root could not be attested.");
177
- }
178
- }
179
- function sameCodexWriteProbeDirectory(before, after) {
180
- return sameCodexWriteProbeRoot(before, after) && before.mtimeNs === after.mtimeNs;
181
- }
182
- function sameCodexWriteProbeRoot(before, after) {
183
- return (before.dev === after.dev &&
184
- before.ino === after.ino &&
185
- before.mode === after.mode &&
186
- before.uid === after.uid);
187
- }
188
82
  function exactLocalHost(hostId) {
189
83
  if ((hostId ?? LOCAL_HOST) !== LOCAL_HOST) {
190
84
  throw new BridgeError("GATEWAY_REMOTE_PROVIDER_DISABLED", "This provider is restricted to the exact local host boundary.");
@@ -226,18 +120,6 @@ function invokeCallback(operation) {
226
120
  }
227
121
  }
228
122
  function validateAttestedClaudeRuntime(runtime) {
229
- if (runtime.versionEvidenceFailure !== undefined) {
230
- throw new BridgeError(runtime.versionEvidenceFailure, "The local Claude provider requires bounded, internally consistent runtime version evidence.");
231
- }
232
- const majorEvidence = runtime.claudeCodeVersion === UNKNOWN_COMPATIBILITY_VERSION
233
- ? runtime.launcherVersionEvidence
234
- : runtime.claudeCodeVersion;
235
- if (majorEvidence === undefined ||
236
- !sharesCompatibilityMajor(majorEvidence, CLAUDE_PEER_COMPATIBILITY.claudeCodeVersion)) {
237
- throw new BridgeError(majorEvidence === undefined
238
- ? "CLAUDE_VERSION_UNPARSEABLE"
239
- : "CLAUDE_PEER_VERSION_UNSUPPORTED", "The local Claude provider requires a positively observed supported runtime major.");
240
- }
241
123
  validateClaudeRuntimePathEvidence(runtime);
242
124
  }
243
125
  function validateClaudeRuntimePathEvidence(runtime) {
@@ -286,135 +168,17 @@ function isClaudeRegistryAvailabilityError(error) {
286
168
  error.code === "EPERM" ||
287
169
  error.code === "UNSAFE_PEER_DIRECTORY");
288
170
  }
289
- /**
290
- * A bounded observation-only surface for an installed provider generation
291
- * whose protocol cannot be used safely. It deliberately performs no provider
292
- * discovery, listener construction, route selection, or message write.
293
- */
294
- export class IncompatibleGatewayProvider {
295
- identity;
296
- protocol = "not-attested";
297
- protocolVersion = "unknown";
298
- version;
299
- probes;
300
- safeErrorCode;
301
- initialized = false;
302
- closed = false;
303
- constructor(options) {
304
- const attestation = evaluateCompatibilityAttestation({
305
- surface: options.identity.provider,
306
- version: options.version,
307
- checkedAt: "2000-01-01T00:00:00.000Z",
308
- certifiedVersions: certifiedCompatibilityVersions[options.identity.provider],
309
- probes: options.probes,
310
- });
311
- if (attestation.tier !== "incompatible" ||
312
- attestation.safeErrorCode !== options.safeErrorCode) {
313
- throw new BridgeError("INCOMPATIBLE_PROVIDER_EVIDENCE_INVALID", "A disabled provider requires exact bounded incompatibility evidence.");
314
- }
315
- exactLocalHost(options.identity.hostId);
316
- this.identity = Object.freeze({ ...options.identity });
317
- this.version = options.version;
318
- this.probes = Object.freeze(options.probes.map((probe) => Object.freeze({ ...probe })));
319
- this.safeErrorCode = options.safeErrorCode;
320
- }
321
- compatibilitySurface() {
322
- return { surface: this.identity.provider, version: this.version };
323
- }
324
- async runCompatibilityProbes() {
325
- return this.probes;
326
- }
327
- acceptCompatibilityAttestation(attestation) {
328
- if (!isCompatibilityAttestation(attestation) ||
329
- attestation.surface !== this.identity.provider ||
330
- attestation.version !== this.version ||
331
- attestation.tier !== "incompatible" ||
332
- attestation.safeErrorCode !== this.safeErrorCode ||
333
- attestation.probes.length !== this.probes.length ||
334
- attestation.probes.some((probe, index) => probe.name !== this.probes[index]?.name ||
335
- probe.outcome !== this.probes[index]?.outcome ||
336
- probe.safeErrorCode !== this.probes[index]?.safeErrorCode)) {
337
- throw new BridgeError("INCOMPATIBLE_PROVIDER_ATTESTATION_MISMATCH", "The compatibility attestation does not match this disabled provider surface.");
338
- }
339
- }
340
- async initialize(_callbacks) {
341
- if (this.closed || this.initialized) {
342
- throw new BridgeError("INCOMPATIBLE_PROVIDER_UNAVAILABLE", "The disabled provider surface cannot be initialized again.");
343
- }
344
- this.initialized = true;
345
- return {
346
- health: "degraded",
347
- compatibility: "incompatible",
348
- safeErrorCode: this.safeErrorCode,
349
- };
350
- }
351
- async discoverClaudePeers() {
352
- throw this.unavailable();
353
- }
354
- async selectRoute(_input) {
355
- throw this.unavailable();
356
- }
357
- async assertWorkspaceDisjoint(_routeHandle, _stateRoot) {
358
- throw this.unavailable();
359
- }
360
- async resolveReplyAddress(_address) {
361
- throw this.unavailable();
362
- }
363
- async advertiseNativeCodexPeer(_input) {
364
- throw this.unavailable();
365
- }
366
- async dispatch(_input) {
367
- throw this.unavailable();
368
- }
369
- async releaseRoute(_routeHandle) { }
370
- async close() {
371
- this.closed = true;
372
- }
373
- unavailable() {
374
- return new BridgeError(this.safeErrorCode, "This provider surface is observation-only because its compatibility boundary did not pass.");
375
- }
376
- }
377
- export function createIncompatibleClaudeGatewayProvider(options) {
378
- validateClaudeRuntimePathEvidence(options.runtime);
379
- const [launcher, version, ...unobserved] = compatibilityProbeNames.claude;
380
- return new IncompatibleGatewayProvider({
381
- identity: {
382
- provider: "claude",
383
- hostId: LOCAL_HOST,
384
- endpointGeneration: STABLE_CLAUDE_ENDPOINT_GENERATION,
385
- },
386
- version: options.version,
387
- probes: [
388
- passedProbe(launcher),
389
- failedProbe(version, options.safeErrorCode),
390
- ...unobserved.map((name) => failedProbe(name, options.safeErrorCode)),
391
- ],
392
- safeErrorCode: options.safeErrorCode,
393
- });
394
- }
395
- export function createIncompatibleCodexGatewayProvider(options) {
396
- const [installation, ...unobserved] = compatibilityProbeNames.codex;
397
- return new IncompatibleGatewayProvider({
398
- identity: options.identity,
399
- version: options.version,
400
- probes: [
401
- passedProbe(installation),
402
- ...unobserved.map((name) => failedProbe(name, options.safeErrorCode)),
403
- ],
404
- safeErrorCode: options.safeErrorCode,
405
- });
406
- }
407
171
  export class LocalClaudeGatewayProvider {
408
172
  identity;
409
173
  protocol = "claude-peer";
410
174
  protocolVersion = `${CLAUDE_PEER_COMPATIBILITY.peerProtocol}`;
411
175
  peer;
412
- runtimeVersion;
413
176
  maxPending;
414
177
  discoveryPollMs;
415
178
  now;
416
179
  selectedStateRoots = new Map();
417
180
  nativeHelpers;
181
+ nativeHelperSourceProvider;
418
182
  discovered = new Map();
419
183
  selected = new Map();
420
184
  /** Exact live same-UID sessions observed through native inbound frames. */
@@ -448,25 +212,12 @@ export class LocalClaudeGatewayProvider {
448
212
  retiredNativeCodexListener;
449
213
  /** Fences discovery callbacks and monitor restarts across listener rotation. */
450
214
  nativeCodexSuccessionFreeze;
451
- /** A completed failed probe set fences every authority-bearing operation. */
452
- compatibilityBlocked = false;
453
- compatibilityFailureCode;
215
+ /** External registry trust/availability failures degrade Claude only. */
216
+ unavailableCode;
454
217
  initialized = false;
455
218
  closed = false;
456
219
  constructor(options) {
457
220
  validateAttestedClaudeRuntime(options.runtime);
458
- const compatibilityVersion = options.compatibilityVersion ??
459
- (options.runtime.claudeCodeVersion === UNKNOWN_COMPATIBILITY_VERSION
460
- ? options.runtime.launcherVersionEvidence
461
- : options.runtime.claudeCodeVersion);
462
- if (compatibilityVersion === undefined ||
463
- !isCompatibilityVersion(compatibilityVersion) ||
464
- (compatibilityVersion !== options.runtime.claudeCodeVersion &&
465
- !(options.runtime.claudeCodeVersion ===
466
- UNKNOWN_COMPATIBILITY_VERSION &&
467
- options.runtime.launcherVersionEvidence === compatibilityVersion))) {
468
- throw new BridgeError("CLAUDE_RUNTIME_ATTESTATION_INVALID", "Claude compatibility classification requires exact bounded launcher evidence.");
469
- }
470
221
  if (options.locale !== undefined && !isDashboardLocale(options.locale)) {
471
222
  throw new BridgeError("DASHBOARD_LOCALE_UNSUPPORTED", "The Claude provider notice locale is unsupported.");
472
223
  }
@@ -476,15 +227,12 @@ export class LocalClaudeGatewayProvider {
476
227
  hostId,
477
228
  endpointGeneration: STABLE_CLAUDE_ENDPOINT_GENERATION,
478
229
  };
479
- this.runtimeVersion = compatibilityVersion;
480
230
  this.maxPending = positiveBounded(options.maxPendingMessages, MAX_CLAUDE_PENDING, 4_096);
481
231
  this.discoveryPollMs = positiveBounded(options.discoveryPollMs, DEFAULT_CLAUDE_DISCOVERY_POLL_MS, 30_000);
482
232
  this.now = options.now ?? Date.now;
483
233
  const protocolRuntime = {
484
234
  claudeExecutable: options.runtime.claudeExecutable,
485
- claudeCodeVersion: options.runtime.claudeCodeVersion === UNKNOWN_COMPATIBILITY_VERSION
486
- ? options.runtime.launcherVersionEvidence
487
- : options.runtime.claudeCodeVersion,
235
+ claudeCodeVersion: options.runtime.claudeCodeVersion,
488
236
  sessionsDir: options.runtime.sessionsDir,
489
237
  socketDir: options.runtime.socketDir,
490
238
  };
@@ -506,60 +254,19 @@ export class LocalClaudeGatewayProvider {
506
254
  deliveryNotices: options.deliveryNotices ?? "merged",
507
255
  maxPendingMessages: this.maxPending,
508
256
  maxHelpers: positiveBounded(options.nativeHelpers.maxHelpers, 256, 128),
509
- callbacks: () => this.compatibilityBlocked ? undefined : this.callbacks,
257
+ callbacks: () => this.callbacks,
510
258
  ...(options.nativeHelpers.factory === undefined
511
259
  ? {}
512
260
  : { factory: options.nativeHelpers.factory }),
513
261
  });
514
- }
515
- compatibilitySurface() {
516
- return { surface: "claude", version: this.runtimeVersion };
517
- }
518
- async runCompatibilityProbes() {
519
- const [launcher, version, registry, socket, protocol] = compatibilityProbeNames.claude;
520
- try {
521
- const discovery = await this.peer.discover();
522
- this.registryObservation = claudeRegistryObservation(discovery);
523
- return [
524
- passedProbe(launcher),
525
- passedProbe(version),
526
- passedProbe(registry),
527
- passedProbe(socket),
528
- passedProbe(protocol),
529
- ];
530
- }
531
- catch (error) {
532
- if (!isClaudeRegistryAvailabilityError(error))
533
- throw error;
534
- this.registryObservation = unavailableClaudeRegistryObservation();
535
- // A missing or unreadable registry is provider-local incompatibility:
536
- // keep the broker and the other surface alive, but fence this provider
537
- // before listener construction can turn the same missing path into a
538
- // broker-wide startup failure.
539
- return [
540
- passedProbe(launcher),
541
- passedProbe(version),
542
- failedProbe(registry, "CLAUDE_REGISTRY_UNAVAILABLE"),
543
- failedProbe(socket, "CLAUDE_REGISTRY_UNAVAILABLE"),
544
- passedProbe(protocol),
545
- ];
546
- }
262
+ this.nativeHelperSourceProvider = options.nativeHelperSourceProvider;
547
263
  }
548
264
  latestRegistryObservation() {
549
265
  return this.registryObservation;
550
266
  }
551
- acceptCompatibilityAttestation(attestation) {
552
- if (!isCompatibilityAttestation(attestation) ||
553
- attestation.surface !== "claude" ||
554
- attestation.version !== this.runtimeVersion) {
555
- throw new BridgeError("CLAUDE_COMPATIBILITY_ATTESTATION_MISMATCH", "The Claude compatibility attestation does not match this runtime.");
556
- }
557
- this.compatibilityBlocked = attestation.tier === "incompatible";
558
- this.compatibilityFailureCode = attestation.safeErrorCode;
559
- if (this.compatibilityBlocked) {
560
- if (this.monitorTimer !== undefined)
561
- clearTimeout(this.monitorTimer);
562
- this.monitorTimer = undefined;
267
+ activateEndpointGeneration(endpointGeneration) {
268
+ if (endpointGeneration !== this.identity.endpointGeneration) {
269
+ throw new BridgeError("CLAUDE_ENDPOINT_ACTIVATION_MISMATCH", "Only the exact current Claude endpoint generation can be activated.");
563
270
  }
564
271
  }
565
272
  async initialize(callbacks) {
@@ -570,17 +277,9 @@ export class LocalClaudeGatewayProvider {
570
277
  throw new BridgeError("CLAUDE_PROVIDER_ALREADY_INITIALIZED", "The local Claude provider can be initialized only once.");
571
278
  }
572
279
  this.callbacks = callbacks;
573
- if (this.compatibilityBlocked) {
574
- this.initialized = true;
575
- return {
576
- health: "degraded",
577
- compatibility: "incompatible",
578
- safeErrorCode: this.compatibilityFailureCode ?? "CLAUDE_COMPATIBILITY_CHECK_FAILED",
579
- };
580
- }
581
280
  if (this.nativeHelpers !== undefined) {
582
281
  this.initialized = true;
583
- return { health: "healthy", compatibility: "compatible" };
282
+ return { health: "healthy" };
584
283
  }
585
284
  try {
586
285
  let listenerGeneration;
@@ -615,18 +314,16 @@ export class LocalClaudeGatewayProvider {
615
314
  }
616
315
  this.activeNativeCodexListener = listenerGeneration;
617
316
  this.initialized = true;
618
- return { health: "healthy", compatibility: "compatible" };
317
+ return { health: "healthy" };
619
318
  }
620
319
  catch (error) {
621
320
  if (error instanceof BridgeError &&
622
321
  error.code === "UNSAFE_PEER_DIRECTORY") {
623
- this.compatibilityBlocked = true;
624
- this.compatibilityFailureCode = "CLAUDE_REGISTRY_UNAVAILABLE";
322
+ this.unavailableCode = "CLAUDE_REGISTRY_UNAVAILABLE";
625
323
  this.registryObservation = unavailableClaudeRegistryObservation();
626
324
  this.initialized = true;
627
325
  return {
628
326
  health: "degraded",
629
- compatibility: "incompatible",
630
327
  safeErrorCode: "CLAUDE_REGISTRY_UNAVAILABLE",
631
328
  };
632
329
  }
@@ -671,12 +368,16 @@ export class LocalClaudeGatewayProvider {
671
368
  }
672
369
  return { routeHandle: resolved.targetId };
673
370
  }
674
- async advertiseNativeCodexPeer(input) {
371
+ async advertiseNativeSourcePeer(input) {
675
372
  if (this.nativeHelpers !== undefined) {
676
373
  this.assertReady();
677
374
  await this.nativeHelpers.advertise(input);
678
375
  return;
679
376
  }
377
+ if (input.sourceProvider !== "codex" &&
378
+ input.sourceProvider !== this.nativeHelperSourceProvider) {
379
+ throw new BridgeError("CLAUDE_NATIVE_HELPER_UNAVAILABLE", "A non-Codex source requires a supervised native Claude helper.", true);
380
+ }
680
381
  const registration = this.nativeCodexRegistration(input);
681
382
  await this.serializeNativeCodexRegistration(async () => {
682
383
  this.assertReady();
@@ -763,7 +464,7 @@ export class LocalClaudeGatewayProvider {
763
464
  this.retiredNativeCodexListener !== undefined) {
764
465
  throw new BridgeError("CODEX_PEER_SUCCESSION_CAPACITY", "Only one distinct prepared or retired Codex generation is allowed.");
765
466
  }
766
- const registration = this.nativeCodexRegistration(input);
467
+ const registration = this.nativeCodexRegistration({ ...input, sourceProvider: "codex" });
767
468
  this.nativeCodexPreparationInFlight = input.generation;
768
469
  let prepared;
769
470
  try {
@@ -1027,7 +728,7 @@ export class LocalClaudeGatewayProvider {
1027
728
  }
1028
729
  return purged;
1029
730
  }
1030
- async unadvertiseNativeCodexPeer(alias) {
731
+ async unadvertiseNativeSourcePeer(alias) {
1031
732
  if (this.nativeHelpers !== undefined) {
1032
733
  await this.nativeHelpers.unadvertise(alias);
1033
734
  return;
@@ -1043,7 +744,7 @@ export class LocalClaudeGatewayProvider {
1043
744
  active.provisionalIngressForwarded = false;
1044
745
  });
1045
746
  }
1046
- async updateNativeCodexPeerStatus(alias, status) {
747
+ async updateNativeSourcePeerStatus(alias, status) {
1047
748
  if (this.nativeHelpers !== undefined) {
1048
749
  await this.nativeHelpers.updateStatus(alias, status);
1049
750
  return;
@@ -1105,10 +806,10 @@ export class LocalClaudeGatewayProvider {
1105
806
  active.inboundQuiesced = true;
1106
807
  }
1107
808
  async dispatch(input) {
1108
- if (this.compatibilityBlocked) {
809
+ if (this.unavailableCode !== undefined) {
1109
810
  return {
1110
811
  state: "failed",
1111
- safeErrorCode: this.compatibilityFailureCode ?? "CLAUDE_COMPATIBILITY_CHECK_FAILED",
812
+ safeErrorCode: this.unavailableCode,
1112
813
  };
1113
814
  }
1114
815
  if (this.nativeHelpers !== undefined) {
@@ -1182,7 +883,8 @@ export class LocalClaudeGatewayProvider {
1182
883
  return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
1183
884
  }
1184
885
  }
1185
- if (activeListener.registration?.alias !== input.sourceAlias) {
886
+ if (activeListener.registration?.alias !== input.sourceAlias ||
887
+ activeListener.registration.sourceProvider !== input.sourceProvider) {
1186
888
  return { state: "failed", safeErrorCode: "CLAUDE_ROUTE_UNAVAILABLE" };
1187
889
  }
1188
890
  if (this.activeNativeCodexListener !== activeListener ||
@@ -1201,7 +903,8 @@ export class LocalClaudeGatewayProvider {
1201
903
  let content;
1202
904
  try {
1203
905
  content = composeProvenanceEnvelope({
1204
- direction: "claude",
906
+ sourceProvider: input.sourceProvider,
907
+ recipientProvider: this.identity.provider,
1205
908
  sourceAlias: input.sourceAlias,
1206
909
  targetAlias: input.targetAlias,
1207
910
  conversationId: input.conversationId,
@@ -1392,7 +1095,7 @@ export class LocalClaudeGatewayProvider {
1392
1095
  }
1393
1096
  }
1394
1097
  assertReady() {
1395
- if (!this.initialized || this.closed || this.compatibilityBlocked) {
1098
+ if (!this.initialized || this.closed || this.unavailableCode !== undefined) {
1396
1099
  throw new BridgeError("CLAUDE_PROVIDER_UNAVAILABLE", "The local Claude provider is not available.", true);
1397
1100
  }
1398
1101
  }
@@ -1407,13 +1110,14 @@ export class LocalClaudeGatewayProvider {
1407
1110
  throw new BridgeError("INVALID_CODEX_PEER_ALIAS", "The native Codex peer alias must target this host.");
1408
1111
  }
1409
1112
  const name = input.alias.slice(0, -suffix.length);
1410
- if (!name.startsWith("codex-") || !NATIVE_CLAUDE_NAME.test(name)) {
1411
- throw new BridgeError("INVALID_CODEX_PEER_ALIAS", "The native Codex peer alias must start with codex-.");
1113
+ const prefix = gatewayRegistrationIngressPrefixes[input.sourceProvider];
1114
+ if (prefix === undefined || !name.startsWith(prefix) || !NATIVE_CLAUDE_NAME.test(name)) {
1115
+ throw new BridgeError("INVALID_CODEX_PEER_ALIAS", "The native source peer alias must use its provider prefix.");
1412
1116
  }
1413
1117
  if (!path.isAbsolute(input.cwd) || input.cwd.includes("\0")) {
1414
1118
  throw new BridgeError("INVALID_CODEX_PEER_CWD", "A native Codex peer requires an absolute working directory.");
1415
1119
  }
1416
- return { alias: input.alias, cwd: input.cwd, name };
1120
+ return { alias: input.alias, sourceProvider: input.sourceProvider, cwd: input.cwd, name };
1417
1121
  }
1418
1122
  requireActiveNativeCodexListener() {
1419
1123
  this.assertReady();
@@ -1451,7 +1155,7 @@ export class LocalClaudeGatewayProvider {
1451
1155
  await this.rejectNativeInboundReceipt(listenerGeneration, message.receiptHandle, diagnosticCode);
1452
1156
  }
1453
1157
  };
1454
- if (this.compatibilityBlocked ||
1158
+ if (this.unavailableCode !== undefined ||
1455
1159
  this.closed ||
1456
1160
  listenerGeneration.listener.closed ||
1457
1161
  !this.ownsNativeCodexListener(listenerGeneration)) {
@@ -1801,7 +1505,6 @@ export class LocalClaudeGatewayProvider {
1801
1505
  routeHandle: peer.targetId,
1802
1506
  kind: "interactive",
1803
1507
  state: claudeRouteState(peer),
1804
- compatibility: "compatible",
1805
1508
  };
1806
1509
  this.discovered.set(peer.targetId, row);
1807
1510
  rows.push(row);
@@ -1891,65 +1594,15 @@ export class LocalClaudeGatewayProvider {
1891
1594
  export function createLocalClaudeGatewayProvider(options) {
1892
1595
  return new LocalClaudeGatewayProvider(options);
1893
1596
  }
1894
- function codexVersionFailureCode(version) {
1895
- if (version === UNKNOWN_COMPATIBILITY_VERSION) {
1896
- return "CODEX_APP_SERVER_VERSION_UNPARSEABLE";
1897
- }
1898
- if (!isCompatibilityVersion(version)) {
1899
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex factory version evidence is malformed.");
1900
- }
1901
- return CODEX_APP_SERVER_WRITABLE_VERSIONS.some((certifiedVersion) => sharesCompatibilityMajor(certifiedVersion, version))
1902
- ? undefined
1903
- : "CODEX_APP_SERVER_VERSION_UNSUPPORTED";
1904
- }
1905
- function validateCodexFactory(factory, options = {}) {
1906
- const schema = factory.schemaCompatibility;
1907
- const write = factory.writeCompatibility;
1908
- const versionFailure = codexVersionFailureCode(factory.appServerVersion);
1909
- const certified = CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(factory.appServerVersion);
1910
- const schemaCandidate = schema.observedSchemaCandidate === true &&
1911
- CODEX_APP_SERVER_WRITABLE_VERSIONS.some((version) => sharesCompatibilityMajor(version, factory.appServerVersion));
1912
- const unsupportedVersionInvalid = versionFailure !== undefined &&
1913
- (options.allowUnsupportedVersion !== true ||
1914
- write !== null ||
1915
- factory.writableReady);
1916
- const supportedSchemaInvalid = versionFailure === undefined &&
1917
- ((!certified &&
1918
- (!schemaCandidate || write !== null || factory.writableReady)) ||
1919
- schema.protocol !== "app-server-v2-stable" ||
1920
- schema.steering?.method !== "turn/steer" ||
1921
- schema.steering.requestSchema !== "expected-turn-id-text-v1" ||
1922
- schema.steering.deliveryBoundary !== "next-tool-call-boundary" ||
1923
- (write !== null &&
1924
- (write.appServerVersion !== schema.appServerVersion ||
1925
- write.endpointGeneration !== schema.endpointGeneration ||
1926
- write.protocol !== schema.protocol ||
1927
- write.observedSchemaCandidate !== schema.observedSchemaCandidate ||
1928
- write.steering?.method !== schema.steering.method ||
1929
- write.steering.requestSchema !== schema.steering.requestSchema ||
1930
- write.steering.deliveryBoundary !==
1931
- schema.steering.deliveryBoundary)) ||
1932
- factory.writableReady !== (write !== null));
1597
+ function validateCodexFactory(factory) {
1933
1598
  if (factory.hostId !== LOCAL_HOST ||
1934
1599
  factory.protocol !== "codex-app-server" ||
1935
1600
  factory.protocolVersion !== factory.appServerVersion ||
1936
- schema.appServerVersion !== factory.appServerVersion ||
1937
- schema.endpointGeneration !== factory.endpointGeneration ||
1938
- unsupportedVersionInvalid ||
1939
- supportedSchemaInvalid) {
1940
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex provider requires exact schema and write attestations.");
1601
+ factory.appServerVersion.length === 0 ||
1602
+ factory.endpointGeneration.length === 0) {
1603
+ throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The local Codex provider requires exact managed endpoint identity.");
1941
1604
  }
1942
1605
  }
1943
- function codexFactoryWritesEnabled(factory, attestation, writeProbePassed = false) {
1944
- return ((attestation.tier === "certified" &&
1945
- CODEX_APP_SERVER_WRITABLE_VERSIONS.includes(attestation.version) &&
1946
- factory.writableReady &&
1947
- factory.writeCompatibility !== null) ||
1948
- (!factory.writableReady &&
1949
- factory.writeCompatibility === null &&
1950
- writeProbePassed &&
1951
- compatibilityCoversWrites(attestation)));
1952
- }
1953
1606
  function codexRouteState(observation) {
1954
1607
  if (observation.connection !== "ready")
1955
1608
  return "stale";
@@ -1971,9 +1624,6 @@ function codexRouteSafeCode(observation) {
1971
1624
  if (codexRouteState(observation) === "stale") {
1972
1625
  return "CODEX_ROUTE_STALE";
1973
1626
  }
1974
- if (!observation.writableReady) {
1975
- return "CODEX_WRITES_DISABLED";
1976
- }
1977
1627
  return undefined;
1978
1628
  }
1979
1629
  export class LocalCodexGatewayProvider {
@@ -1986,6 +1636,7 @@ export class LocalCodexGatewayProvider {
1986
1636
  cleanupTimeoutMs;
1987
1637
  recoveryInitialMs;
1988
1638
  recoveryMaxMs;
1639
+ observationPollMs;
1989
1640
  now;
1990
1641
  routes = new Map();
1991
1642
  /** Exact public alias authority retained across internal route recovery. */
@@ -1997,6 +1648,8 @@ export class LocalCodexGatewayProvider {
1997
1648
  routeRecoveries = new Map();
1998
1649
  routesRequiringRecovery = new Set();
1999
1650
  trackedRoutes = new Set();
1651
+ observationTimer;
1652
+ observationInFlight;
2000
1653
  retiredEndpointGeneration;
2001
1654
  expectsReply = new Map();
2002
1655
  callbackQueue = [];
@@ -2007,14 +1660,7 @@ export class LocalCodexGatewayProvider {
2007
1660
  endpointActivationRetry;
2008
1661
  endpointActivationRetryTimer;
2009
1662
  callbackDrainFrozen = false;
2010
- writeProbeObservationsByGeneration = new Map();
2011
- writeProbeResults = new Map();
2012
- writeProbeDecline;
2013
- writeProbeOverflow;
2014
- compatibilityAttested;
2015
- compatibilityFailureCode;
2016
1663
  endpointUnavailable = false;
2017
- pendingEndpointAttestation;
2018
1664
  pendingEndpointRefreshEvent;
2019
1665
  pendingEndpointRefreshSelectorClaimed = false;
2020
1666
  initialized = false;
@@ -2025,9 +1671,6 @@ export class LocalCodexGatewayProvider {
2025
1671
  this.factory = options.factory;
2026
1672
  this.refreshFactory = options.refreshFactory;
2027
1673
  exactLocalHost(options.factory.hostId);
2028
- this.compatibilityAttested =
2029
- options.factory.writableReady &&
2030
- options.factory.writeCompatibility !== null;
2031
1674
  this.maxCallbacks = positiveBounded(options.maxCallbackEvents, MAX_CODEX_CALLBACKS, 4_096);
2032
1675
  this.maxRoutes = positiveBounded(options.maxRoutes, MAX_CODEX_ROUTES, 256);
2033
1676
  this.maxReplyBytes = positiveBounded(options.maxReplyBytes, MAX_TRANSIENT_REPLY_BYTES, 1024 * 1024);
@@ -2041,6 +1684,7 @@ export class LocalCodexGatewayProvider {
2041
1684
  if (this.recoveryInitialMs > this.recoveryMaxMs) {
2042
1685
  throw new BridgeError("INVALID_GATEWAY_PROVIDER_CONFIGURATION", "The Codex recovery initial delay cannot exceed its capped delay.");
2043
1686
  }
1687
+ this.observationPollMs = positiveBounded(options.observationPollMs, DEFAULT_CODEX_OBSERVATION_POLL_MS, 60_000);
2044
1688
  this.now = options.now ?? (() => new Date());
2045
1689
  }
2046
1690
  get identity() {
@@ -2056,352 +1700,39 @@ export class LocalCodexGatewayProvider {
2056
1700
  get protocolVersion() {
2057
1701
  return this.factory.protocolVersion;
2058
1702
  }
2059
- compatibilitySurface() {
2060
- return { surface: "codex", version: this.factory.appServerVersion };
2061
- }
2062
- acceptCompatibilityAttestation(attestation) {
2063
- const pending = this.pendingEndpointAttestation;
2064
- const pendingMatches = pending === undefined ||
2065
- (attestation.checkedAt === pending.checkedAt &&
2066
- attestation.tier === pending.tier &&
2067
- attestation.safeErrorCode === pending.safeErrorCode &&
2068
- attestation.probes.length === pending.probes.length &&
2069
- attestation.probes.every((probe, index) => probe.name === pending.probes[index]?.name &&
2070
- probe.outcome === pending.probes[index]?.outcome &&
2071
- probe.safeErrorCode === pending.probes[index]?.safeErrorCode));
2072
- if (!isCompatibilityAttestation(attestation) ||
2073
- attestation.surface !== "codex" ||
2074
- attestation.version !== this.factory.appServerVersion ||
2075
- !pendingMatches) {
2076
- throw new BridgeError("CODEX_COMPATIBILITY_ATTESTATION_MISMATCH", "The Codex compatibility attestation does not match this endpoint.");
2077
- }
2078
- if (attestation.tier === "incompatible") {
2079
- this.pendingEndpointAttestation = undefined;
2080
- this.pendingEndpointRefreshEvent = undefined;
2081
- this.pendingEndpointRefreshSelectorClaimed = false;
2082
- this.clearEndpointActivationRetry();
2083
- this.compatibilityAttested = false;
2084
- this.endpointUnavailable = true;
2085
- this.compatibilityFailureCode =
2086
- attestation.safeErrorCode ?? "CODEX_COMPATIBILITY_CHECK_FAILED";
2087
- return;
2088
- }
2089
- const writesEnabled = codexFactoryWritesEnabled(this.factory, attestation, this.latestWriteCompatibilityProbeObservation(this.factory.endpointGeneration)?.outcome === "pass");
2090
- const schemaObserved = attestation.tier === "schema_attested" &&
2091
- !this.factory.writableReady &&
2092
- this.factory.writeCompatibility === null;
2093
- if ((!writesEnabled && !schemaObserved) ||
2094
- (this.endpointUnavailable && pending === undefined) ||
2095
- !pendingMatches) {
2096
- throw new BridgeError("CODEX_COMPATIBILITY_ATTESTATION_MISMATCH", "The Codex compatibility attestation does not match this endpoint.");
1703
+ activateEndpointGeneration(endpointGeneration) {
1704
+ const event = this.pendingEndpointRefreshEvent;
1705
+ if (event === undefined ||
1706
+ event.current.endpointGeneration !== endpointGeneration ||
1707
+ this.factory.endpointGeneration !== endpointGeneration) {
1708
+ throw new BridgeError("CODEX_ENDPOINT_ACTIVATION_MISMATCH", "Only the exact pending managed Codex generation can be activated.");
2097
1709
  }
2098
- this.pendingEndpointAttestation = undefined;
2099
1710
  this.pendingEndpointRefreshEvent = undefined;
2100
1711
  this.pendingEndpointRefreshSelectorClaimed = false;
2101
1712
  this.clearEndpointActivationRetry();
2102
- this.compatibilityAttested = writesEnabled;
2103
- this.endpointUnavailable = !writesEnabled;
2104
- this.compatibilityFailureCode = undefined;
1713
+ this.endpointUnavailable = false;
2105
1714
  }
2106
1715
  releaseEndpointRefreshSelectorClaim(endpointGeneration) {
2107
1716
  const event = this.pendingEndpointRefreshEvent;
2108
- if (event?.current.endpointGeneration === endpointGeneration &&
2109
- this.pendingEndpointAttestation !== undefined) {
1717
+ if (event?.current.endpointGeneration === endpointGeneration) {
2110
1718
  this.pendingEndpointRefreshSelectorClaimed = false;
2111
1719
  }
2112
1720
  }
2113
1721
  rearmEndpointRefreshActivation(endpointGeneration) {
2114
1722
  const event = this.pendingEndpointRefreshEvent;
2115
1723
  if (event?.current.endpointGeneration === endpointGeneration &&
2116
- this.pendingEndpointAttestation !== undefined &&
2117
1724
  !this.closing &&
2118
1725
  !this.closed) {
2119
1726
  this.publishEndpointRefresh(event);
2120
1727
  }
2121
1728
  }
2122
- latestWriteCompatibilityProbeObservation(endpointGeneration) {
2123
- return (this.writeProbeObservationsByGeneration.get(endpointGeneration) ??
2124
- (this.writeProbeOverflow?.endpointGeneration === endpointGeneration
2125
- ? this.writeProbeOverflow.observation
2126
- : undefined) ??
2127
- (this.writeProbeDecline?.endpointGeneration === endpointGeneration
2128
- ? this.writeProbeDecline.observation
2129
- : undefined));
2130
- }
2131
- async runCompatibilityProbes(context) {
2132
- return await this.runCompatibilityProbesFor(this.factory, context === undefined
2133
- ? undefined
2134
- : {
2135
- stateRoot: path.resolve(context.stateRoot),
2136
- forbiddenCodexThreadIds: [...context.forbiddenCodexThreadIds],
2137
- });
2138
- }
2139
- async runCompatibilityProbesFor(factory, context) {
2140
- const [installation, control, initialize, threadList] = compatibilityProbeNames.codex;
2141
- let transport;
2142
- let connector;
2143
- let stage = "transport";
2144
- try {
2145
- transport = await factory.connectTransport();
2146
- stage = "initialize";
2147
- connector = await CodexAppServerConnector.connect({
2148
- compatibility: factory.schemaCompatibility,
2149
- ...(context === undefined
2150
- ? {}
2151
- : { writeCompatibilityProbe: true }),
2152
- writesEnabled: false,
2153
- route: {
2154
- endpointGeneration: factory.endpointGeneration,
2155
- threadId: COMPATIBILITY_PROBE_THREAD_ID,
2156
- },
2157
- transport,
2158
- maxReplyBytes: this.maxReplyBytes,
2159
- now: this.now,
2160
- onEvent: () => undefined,
2161
- onTurnResult: () => undefined,
2162
- });
2163
- stage = "thread_list";
2164
- await connector.observeLoadedThread(connector.guard());
2165
- const requiredProbes = [
2166
- passedProbe(installation),
2167
- passedProbe(control),
2168
- passedProbe(initialize),
2169
- passedProbe(threadList),
2170
- ];
2171
- if (context === undefined)
2172
- return requiredProbes;
2173
- const result = await this.runCodexWriteProbe(factory, connector, context);
2174
- return result.outcome === "pass"
2175
- ? [...requiredProbes, passedProbe("write_attestation")]
2176
- : requiredProbes;
2177
- }
2178
- catch (error) {
2179
- if (this.isEndpointGenerationChanged(error) ||
2180
- (error instanceof BridgeError &&
2181
- error.code === "CODEX_FACTORY_ATTESTATION_INVALID")) {
2182
- throw error;
2183
- }
2184
- if (stage === "transport") {
2185
- const availabilityFailure = error instanceof LocalCodexTransportError &&
2186
- [
2187
- "MANAGED_CODEX_UNAVAILABLE",
2188
- "LOCAL_APP_SERVER_NOT_RUNNING",
2189
- "SPAWN_FAILED",
2190
- "SPAWN_TIMEOUT",
2191
- "PROXY_STDERR_LIMIT",
2192
- "TRANSPORT_CONNECT_FAILED",
2193
- ].includes(error.code);
2194
- if (!availabilityFailure)
2195
- throw error;
2196
- const installationUnavailable = error instanceof LocalCodexTransportError &&
2197
- error.code === "MANAGED_CODEX_UNAVAILABLE";
2198
- return [
2199
- installationUnavailable
2200
- ? failedProbe(installation, "CODEX_INSTALLATION_INVALID")
2201
- : passedProbe(installation),
2202
- failedProbe(control, installationUnavailable
2203
- ? "CODEX_COMPAT_PROBE_BLOCKED"
2204
- : "CODEX_CONTROL_SOCKET_UNAVAILABLE"),
2205
- failedProbe(initialize, "CODEX_COMPAT_PROBE_BLOCKED"),
2206
- failedProbe(threadList, "CODEX_COMPAT_PROBE_BLOCKED"),
2207
- ];
2208
- }
2209
- return [
2210
- passedProbe(installation),
2211
- passedProbe(control),
2212
- stage === "initialize"
2213
- ? failedProbe(initialize, "CODEX_INITIALIZE_SCHEMA_REJECTED")
2214
- : passedProbe(initialize),
2215
- failedProbe(threadList, "CODEX_THREAD_LIST_SCHEMA_REJECTED"),
2216
- ];
2217
- }
2218
- finally {
2219
- if (connector !== undefined) {
2220
- await connector.close();
2221
- }
2222
- else if (transport !== undefined) {
2223
- await transport.close();
2224
- }
2225
- }
2226
- }
2227
- async runCodexWriteProbe(factory, connector, context) {
2228
- const key = `${factory.appServerVersion}\0${factory.endpointGeneration}`;
2229
- const cached = this.writeProbeResults.get(key);
2230
- if (cached !== undefined)
2231
- return await cached;
2232
- if (this.writeProbeOverflow?.key === key) {
2233
- if (this.writeProbeResults.size >= MAX_CODEX_WRITE_PROBE_ATTEMPTS) {
2234
- return this.writeProbeOverflow.observation;
2235
- }
2236
- this.writeProbeOverflow = undefined;
2237
- }
2238
- if (this.writeProbeResults.size >= MAX_CODEX_WRITE_PROBE_ATTEMPTS) {
2239
- const observation = Object.freeze(codexWriteProbeFailure("CODEX_WRITE_PROBE_CAPACITY_EXHAUSTED"));
2240
- this.writeProbeOverflow = Object.freeze({
2241
- endpointGeneration: factory.endpointGeneration,
2242
- key,
2243
- observation,
2244
- });
2245
- if (this.callbacks !== undefined) {
2246
- invokeCallback(() => this.callbacks?.onProtocolNotice?.({
2247
- code: observation.safeErrorCode,
2248
- }));
2249
- }
2250
- return observation;
2251
- }
2252
- const pending = this.executeCodexWriteProbe(connector, context).then((result) => {
2253
- const observation = Object.freeze({ ...result });
2254
- if (observation.outcome === "fail" &&
2255
- (observation.safeErrorCode ===
2256
- "CODEX_WRITE_PROBE_MODEL_PIN_UNAVAILABLE" ||
2257
- observation.safeErrorCode ===
2258
- "CODEX_WRITE_PROBE_RATE_LIMIT_CONSTRAINED")) {
2259
- this.writeProbeResults.delete(key);
2260
- this.writeProbeDecline = Object.freeze({
2261
- endpointGeneration: factory.endpointGeneration,
2262
- observation,
2263
- });
2264
- }
2265
- else {
2266
- this.writeProbeObservationsByGeneration.set(factory.endpointGeneration, observation);
2267
- }
2268
- if (observation.outcome === "fail" && this.callbacks !== undefined) {
2269
- invokeCallback(() => this.callbacks?.onProtocolNotice?.({
2270
- code: observation.safeErrorCode,
2271
- }));
2272
- }
2273
- return observation;
2274
- });
2275
- this.writeProbeResults.set(key, pending);
2276
- return await pending;
2277
- }
2278
- async executeCodexWriteProbe(connector, context) {
2279
- const stateRoot = path.resolve(context.stateRoot);
2280
- const rootBefore = await attestCodexWriteProbeRoot(stateRoot);
2281
- if (rootBefore === null) {
2282
- return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
2283
- }
2284
- const probeRoot = path.join(stateRoot, CODEX_WRITE_PROBE_ROOT);
2285
- let probeRootBefore;
2286
- try {
2287
- let created = false;
2288
- try {
2289
- await mkdir(probeRoot, { mode: 0o700 });
2290
- created = true;
2291
- }
2292
- catch (error) {
2293
- if (systemErrorCode(error) !== "EEXIST")
2294
- throw error;
2295
- }
2296
- if (created)
2297
- await chmod(probeRoot, 0o700);
2298
- const evidence = await attestCodexWriteProbeRoot(probeRoot);
2299
- if (evidence === null) {
2300
- return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
2301
- }
2302
- probeRootBefore = evidence;
2303
- }
2304
- catch (error) {
2305
- if (error instanceof BridgeError &&
2306
- error.code === "CODEX_FACTORY_ATTESTATION_INVALID") {
2307
- throw error;
2308
- }
2309
- if (transientCodexWriteProbeError(error)) {
2310
- return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
2311
- }
2312
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The controller-owned Codex probe root could not be established safely.");
2313
- }
2314
- let cwd;
2315
- let before;
2316
- let result = codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
2317
- try {
2318
- cwd = await mkdtemp(path.join(probeRoot, CODEX_WRITE_PROBE_DIRECTORY_PREFIX));
2319
- if (path.dirname(cwd) !== probeRoot) {
2320
- throw new Error("probe directory escaped its dedicated root");
2321
- }
2322
- await chmod(cwd, 0o700);
2323
- before = await attestCodexWriteProbeDirectory(cwd);
2324
- result = await connector.runWriteCompatibilityProbe({
2325
- cwd,
2326
- forbiddenThreadIds: [
2327
- ...new Set([
2328
- COMPATIBILITY_PROBE_THREAD_ID,
2329
- ...context.forbiddenCodexThreadIds,
2330
- ...this.trackedRoutes,
2331
- ]),
2332
- ],
2333
- });
2334
- }
2335
- catch (error) {
2336
- if (!safeCodexWriteProbeFilesystemFailure(error)) {
2337
- if (error instanceof BridgeError)
2338
- throw error;
2339
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be established safely.");
2340
- }
2341
- result = codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED");
2342
- }
2343
- let unchanged = false;
2344
- let removed = false;
2345
- if (cwd !== undefined && before !== undefined) {
2346
- try {
2347
- const after = await attestCodexWriteProbeDirectory(cwd);
2348
- unchanged = sameCodexWriteProbeDirectory(before, after);
2349
- await rmdir(cwd);
2350
- try {
2351
- await lstat(cwd);
2352
- }
2353
- catch (error) {
2354
- removed = systemErrorCode(error) === "ENOENT";
2355
- }
2356
- }
2357
- catch (error) {
2358
- if (!safeCodexWriteProbeFilesystemFailure(error)) {
2359
- if (error instanceof BridgeError)
2360
- throw error;
2361
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The disposable Codex probe directory could not be re-attested safely.");
2362
- }
2363
- // Never remove a path after its exact ownership evidence changed.
2364
- }
2365
- }
2366
- if (cwd !== undefined && !removed) {
2367
- result = codexWriteProbeFailure("CODEX_WRITE_PROBE_CLEANUP_UNCONFIRMED", result);
2368
- }
2369
- else if (cwd !== undefined && !unchanged) {
2370
- result = codexWriteProbeFailure("CODEX_WRITE_PROBE_TOOL_ACTIVITY_OBSERVED", result);
2371
- }
2372
- const [probeRootAfter, rootAfter] = await Promise.all([
2373
- attestCodexWriteProbeRoot(probeRoot),
2374
- attestCodexWriteProbeRoot(stateRoot),
2375
- ]);
2376
- if (probeRootAfter === null || rootAfter === null) {
2377
- return codexWriteProbeFailure("CODEX_WRITE_PROBE_THREAD_SETUP_FAILED", result);
2378
- }
2379
- if (!sameCodexWriteProbeRoot(probeRootBefore, probeRootAfter) ||
2380
- !sameCodexWriteProbeRoot(rootBefore, rootAfter)) {
2381
- throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "A controller-owned Codex probe root changed while the disposable probe ran.");
2382
- }
2383
- return result;
2384
- }
2385
1729
  async initialize(callbacks) {
2386
1730
  if (this.closed || this.initialized) {
2387
1731
  throw new BridgeError("CODEX_PROVIDER_INITIALIZATION_REJECTED", "The local Codex provider cannot be initialized in this state.");
2388
1732
  }
2389
1733
  this.callbacks = callbacks;
2390
1734
  this.initialized = true;
2391
- if (this.compatibilityFailureCode !== undefined) {
2392
- return {
2393
- health: "degraded",
2394
- compatibility: "incompatible",
2395
- safeErrorCode: this.compatibilityFailureCode,
2396
- };
2397
- }
2398
- return !this.compatibilityAttested
2399
- ? {
2400
- health: "degraded",
2401
- compatibility: "compatible",
2402
- safeErrorCode: "CODEX_MONITOR_ONLY",
2403
- }
2404
- : { health: "healthy", compatibility: "compatible" };
1735
+ return { health: "healthy" };
2405
1736
  }
2406
1737
  async selectRoute(input) {
2407
1738
  if (!this.initialized || this.closing || this.closed) {
@@ -2423,9 +1754,8 @@ export class LocalCodexGatewayProvider {
2423
1754
  let selectorRefreshReserved = false;
2424
1755
  let route;
2425
1756
  const stageRefreshedRoute = async (result) => {
2426
- if (result === undefined ||
2427
- result.event.outcome !== "compatible") {
2428
- throw new BridgeError("CODEX_ROUTE_SETUP_REJECTED", "The exact Codex endpoint replacement was not compatibility-attested.");
1757
+ if (result === undefined) {
1758
+ throw new BridgeError("CODEX_ROUTE_SETUP_REJECTED", "The exact Codex endpoint replacement could not be established.");
2429
1759
  }
2430
1760
  refreshResult = result;
2431
1761
  selectorRefreshReserved = this.reserveSelectorRefresh(result);
@@ -2448,7 +1778,7 @@ export class LocalCodexGatewayProvider {
2448
1778
  route = await stageRefreshedRoute(retainedEndpointRefresh);
2449
1779
  }
2450
1780
  else if (this.endpointUnavailable &&
2451
- this.pendingEndpointAttestation === undefined) {
1781
+ this.pendingEndpointRefreshEvent === undefined) {
2452
1782
  route = await stageRefreshedRoute(await this.refreshEndpoint("selector"));
2453
1783
  }
2454
1784
  else {
@@ -2502,6 +1832,7 @@ export class LocalCodexGatewayProvider {
2502
1832
  throw new BridgeError("CODEX_ROUTE_SETUP_REJECTED", "The exact Codex task connection closed during route selection.");
2503
1833
  }
2504
1834
  this.trackedRoutes.add(input.routeHandle);
1835
+ this.scheduleCodexObservation();
2505
1836
  this.routeAliases.set(input.routeHandle, input.alias);
2506
1837
  if (refreshResult === undefined) {
2507
1838
  this.queueRouteObservation(route, observation);
@@ -2566,7 +1897,6 @@ export class LocalCodexGatewayProvider {
2566
1897
  this.closed ||
2567
1898
  this.endpointUnavailable ||
2568
1899
  this.endpointRefresh !== undefined ||
2569
- !this.compatibilityAttested ||
2570
1900
  input.authorization !== "selected_route" ||
2571
1901
  !sameEndpoint(input.binding, this.identity)) {
2572
1902
  return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
@@ -2580,9 +1910,6 @@ export class LocalCodexGatewayProvider {
2580
1910
  return { state: "failed", safeErrorCode: "CODEX_ROUTE_UNAVAILABLE" };
2581
1911
  }
2582
1912
  const guard = route.connector.guard();
2583
- if (!guard.writableReady) {
2584
- return { state: "failed", safeErrorCode: "CODEX_WRITES_DISABLED" };
2585
- }
2586
1913
  if (strictDeadline(input.deadlineAt, this.now().getTime()) === undefined) {
2587
1914
  return { state: "failed", safeErrorCode: "MESSAGE_EXPIRED" };
2588
1915
  }
@@ -2592,7 +1919,8 @@ export class LocalCodexGatewayProvider {
2592
1919
  let content;
2593
1920
  try {
2594
1921
  content = composeProvenanceEnvelope({
2595
- direction: "codex",
1922
+ sourceProvider: input.sourceProvider,
1923
+ recipientProvider: this.identity.provider,
2596
1924
  sourceAlias: input.sourceAlias,
2597
1925
  targetAlias: input.targetAlias,
2598
1926
  conversationId: input.conversationId,
@@ -2658,6 +1986,10 @@ export class LocalCodexGatewayProvider {
2658
1986
  throw new BridgeError("CODEX_ENDPOINT_ACTIVATION_PENDING", "The exact Codex route still belongs to an unaccepted endpoint transition.", true);
2659
1987
  }
2660
1988
  this.trackedRoutes.delete(routeHandle);
1989
+ if (this.trackedRoutes.size === 0 && this.observationTimer !== undefined) {
1990
+ clearTimeout(this.observationTimer);
1991
+ this.observationTimer = undefined;
1992
+ }
2661
1993
  this.cancelRouteRecovery(routeHandle);
2662
1994
  const recovery = this.routeRecoveries.get(routeHandle);
2663
1995
  if (recovery !== undefined)
@@ -2695,6 +2027,10 @@ export class LocalCodexGatewayProvider {
2695
2027
  if (this.closed || this.closing)
2696
2028
  return;
2697
2029
  this.closing = true;
2030
+ if (this.observationTimer !== undefined) {
2031
+ clearTimeout(this.observationTimer);
2032
+ this.observationTimer = undefined;
2033
+ }
2698
2034
  for (const timer of this.routeRecoveryTimers.values())
2699
2035
  clearTimeout(timer);
2700
2036
  this.routeRecoveryTimers.clear();
@@ -2702,7 +2038,6 @@ export class LocalCodexGatewayProvider {
2702
2038
  this.clearEndpointActivationRetry();
2703
2039
  this.pendingEndpointRefreshEvent = undefined;
2704
2040
  this.pendingEndpointRefreshSelectorClaimed = false;
2705
- this.pendingEndpointAttestation = undefined;
2706
2041
  const refreshResult = this.endpointRefresh === undefined
2707
2042
  ? []
2708
2043
  : await Promise.allSettled([this.endpointRefresh]);
@@ -2711,6 +2046,9 @@ export class LocalCodexGatewayProvider {
2711
2046
  await Promise.allSettled([
2712
2047
  ...this.routeRecoveries.values(),
2713
2048
  ...this.routeCreations.values(),
2049
+ ...(this.observationInFlight === undefined
2050
+ ? []
2051
+ : [this.observationInFlight]),
2714
2052
  ]);
2715
2053
  this.drainCallbackQueue();
2716
2054
  if (refreshResult.some((result) => result.status === "rejected") ||
@@ -2728,7 +2066,6 @@ export class LocalCodexGatewayProvider {
2728
2066
  this.closed = true;
2729
2067
  this.closing = false;
2730
2068
  this.callbackQueue.length = 0;
2731
- this.pendingEndpointAttestation = undefined;
2732
2069
  this.pendingEndpointRefreshEvent = undefined;
2733
2070
  this.pendingEndpointRefreshSelectorClaimed = false;
2734
2071
  this.trackedRoutes.clear();
@@ -2741,13 +2078,12 @@ export class LocalCodexGatewayProvider {
2741
2078
  this.closing ||
2742
2079
  this.closed ||
2743
2080
  this.endpointUnavailable ||
2744
- this.endpointRefresh !== undefined ||
2745
- !this.compatibilityAttested) {
2081
+ this.endpointRefresh !== undefined) {
2746
2082
  throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider is unavailable.", true);
2747
2083
  }
2748
2084
  }
2749
- async ensureRoute(threadId, queueInitialObservation = true, allowPendingEndpointAttestation = false) {
2750
- if (allowPendingEndpointAttestation) {
2085
+ async ensureRoute(threadId, queueInitialObservation = true, allowPendingEndpointActivation = false) {
2086
+ if (allowPendingEndpointActivation) {
2751
2087
  if (!this.initialized || this.closing || this.closed) {
2752
2088
  throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider is unavailable.", true);
2753
2089
  }
@@ -2758,7 +2094,7 @@ export class LocalCodexGatewayProvider {
2758
2094
  const pendingRelease = this.routeReleases.get(threadId);
2759
2095
  if (pendingRelease !== undefined) {
2760
2096
  await pendingRelease;
2761
- return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointAttestation);
2097
+ return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointActivation);
2762
2098
  }
2763
2099
  const existing = this.routes.get(threadId);
2764
2100
  if (existing !== undefined) {
@@ -2770,7 +2106,7 @@ export class LocalCodexGatewayProvider {
2770
2106
  // a fresh one. The identity-checked release lets automatic recovery and
2771
2107
  // an explicit selector join the same cleanup safely.
2772
2108
  await this.releaseRouteInternal(threadId);
2773
- return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointAttestation);
2109
+ return await this.ensureRoute(threadId, queueInitialObservation, allowPendingEndpointActivation);
2774
2110
  }
2775
2111
  const pending = this.routeCreations.get(threadId);
2776
2112
  if (pending !== undefined)
@@ -2780,14 +2116,12 @@ export class LocalCodexGatewayProvider {
2780
2116
  }
2781
2117
  const admittedFactory = this.factory;
2782
2118
  const creation = (async () => {
2783
- const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation, this.pendingEndpointAttestation === undefined
2784
- ? this.compatibilityAttested
2785
- : codexFactoryWritesEnabled(admittedFactory, this.pendingEndpointAttestation, this.latestWriteCompatibilityProbeObservation(admittedFactory.endpointGeneration)?.outcome === "pass"));
2119
+ const route = await this.createRoute(threadId, admittedFactory, queueInitialObservation);
2786
2120
  if (this.closing || this.closed) {
2787
2121
  await this.closeRoute(route);
2788
2122
  throw new BridgeError("CODEX_PROVIDER_UNAVAILABLE", "The local Codex provider closed during route creation.");
2789
2123
  }
2790
- if (!allowPendingEndpointAttestation &&
2124
+ if (!allowPendingEndpointActivation &&
2791
2125
  (this.endpointUnavailable ||
2792
2126
  this.endpointRefresh !== undefined ||
2793
2127
  admittedFactory !== this.factory ||
@@ -2806,15 +2140,14 @@ export class LocalCodexGatewayProvider {
2806
2140
  this.routeCreations.delete(threadId);
2807
2141
  }
2808
2142
  }
2809
- async createRoute(threadId, factory, queueInitialObservation, writesEnabled) {
2143
+ async createRoute(threadId, factory, queueInitialObservation) {
2810
2144
  let transport;
2811
2145
  let connector;
2812
2146
  const generation = Symbol(threadId);
2813
2147
  try {
2814
2148
  transport = await factory.connectTransport();
2815
2149
  connector = await CodexAppServerConnector.connect({
2816
- compatibility: factory.writeCompatibility ?? factory.schemaCompatibility,
2817
- writesEnabled,
2150
+ compatibility: { endpointGeneration: factory.endpointGeneration },
2818
2151
  route: {
2819
2152
  endpointGeneration: factory.endpointGeneration,
2820
2153
  threadId,
@@ -2885,6 +2218,49 @@ export class LocalCodexGatewayProvider {
2885
2218
  this.scheduleRouteRecovery(threadId);
2886
2219
  }
2887
2220
  }
2221
+ scheduleCodexObservation() {
2222
+ if (this.closed ||
2223
+ this.closing ||
2224
+ this.trackedRoutes.size === 0 ||
2225
+ this.observationTimer !== undefined ||
2226
+ this.observationInFlight !== undefined) {
2227
+ return;
2228
+ }
2229
+ const timer = setTimeout(() => {
2230
+ if (this.observationTimer !== timer)
2231
+ return;
2232
+ this.observationTimer = undefined;
2233
+ const observation = this.refreshCodexObservations().catch(() => {
2234
+ // Unexpected provider-local observation failures must not kill re-arm.
2235
+ });
2236
+ this.observationInFlight = observation;
2237
+ void observation.finally(() => {
2238
+ if (this.observationInFlight === observation) {
2239
+ this.observationInFlight = undefined;
2240
+ }
2241
+ this.scheduleCodexObservation();
2242
+ });
2243
+ }, this.observationPollMs);
2244
+ timer.unref();
2245
+ this.observationTimer = timer;
2246
+ }
2247
+ async refreshCodexObservations() {
2248
+ for (const [threadId, route] of [...this.routes]) {
2249
+ if (this.closed ||
2250
+ this.closing ||
2251
+ !this.trackedRoutes.has(threadId) ||
2252
+ route.connector.observation().requestInFlight) {
2253
+ continue;
2254
+ }
2255
+ try {
2256
+ await route.connector.observeLoadedThread(route.connector.guard());
2257
+ }
2258
+ catch {
2259
+ // Connector events carry the provider-local failure evidence. One
2260
+ // route's failed observation must not stop later routes or the timer.
2261
+ }
2262
+ }
2263
+ }
2888
2264
  scheduleRouteRecovery(threadId) {
2889
2265
  if (this.closed ||
2890
2266
  this.closing ||
@@ -2919,12 +2295,11 @@ export class LocalCodexGatewayProvider {
2919
2295
  }
2920
2296
  try {
2921
2297
  if (this.endpointUnavailable) {
2922
- if (this.pendingEndpointAttestation !== undefined) {
2298
+ if (this.pendingEndpointRefreshEvent !== undefined) {
2923
2299
  throw new BridgeError("CODEX_ENDPOINT_REFRESH_PENDING", "The replacement Codex endpoint is awaiting controller activation.", true);
2924
2300
  }
2925
2301
  const refreshed = await this.refreshEndpoint("callback");
2926
- if (refreshed?.event.outcome === "compatible" &&
2927
- refreshed.event.routes.some((route) => route.routeHandle === threadId)) {
2302
+ if (refreshed?.event.routes.some((route) => route.routeHandle === threadId)) {
2928
2303
  this.routesRequiringRecovery.delete(threadId);
2929
2304
  this.routeRecoveryAttempts.delete(threadId);
2930
2305
  return;
@@ -2954,8 +2329,7 @@ export class LocalCodexGatewayProvider {
2954
2329
  if (this.isEndpointGenerationChanged(error)) {
2955
2330
  this.endpointUnavailable = true;
2956
2331
  const refreshed = await this.refreshEndpoint("callback").catch(() => undefined);
2957
- if (refreshed?.event.outcome === "compatible" &&
2958
- refreshed.event.routes.some((route) => route.routeHandle === threadId)) {
2332
+ if (refreshed?.event.routes.some((route) => route.routeHandle === threadId)) {
2959
2333
  this.routesRequiringRecovery.delete(threadId);
2960
2334
  this.routeRecoveryAttempts.delete(threadId);
2961
2335
  return;
@@ -2986,7 +2360,6 @@ export class LocalCodexGatewayProvider {
2986
2360
  const event = this.pendingEndpointRefreshEvent;
2987
2361
  if (event === undefined ||
2988
2362
  this.pendingEndpointRefreshSelectorClaimed ||
2989
- this.pendingEndpointAttestation === undefined ||
2990
2363
  event.current.endpointGeneration !== this.factory.endpointGeneration) {
2991
2364
  return undefined;
2992
2365
  }
@@ -3033,40 +2406,7 @@ export class LocalCodexGatewayProvider {
3033
2406
  try {
3034
2407
  const resolved = await this.resolveEndpointRefreshCandidate(refreshFactory, previousFactory, previous);
3035
2408
  candidate = resolved.factory;
3036
- const { attestation, identity: candidateIdentity } = resolved;
3037
2409
  await this.retireEndpointGeneration(previousFactory, previous.endpointGeneration);
3038
- if (attestation.tier === "incompatible") {
3039
- await candidate.close();
3040
- candidate = undefined;
3041
- this.compatibilityAttested = false;
3042
- this.pendingEndpointAttestation = undefined;
3043
- this.pendingEndpointRefreshEvent = undefined;
3044
- this.pendingEndpointRefreshSelectorClaimed = false;
3045
- for (const routeHandle of this.trackedRoutes) {
3046
- this.routesRequiringRecovery.add(routeHandle);
3047
- }
3048
- if (this.closing || this.closed)
3049
- return undefined;
3050
- const result = {
3051
- event: {
3052
- outcome: "incompatible",
3053
- previous,
3054
- candidate: candidateIdentity,
3055
- attestation,
3056
- },
3057
- delivery: "callback",
3058
- selectorClaimed: true,
3059
- published: false,
3060
- };
3061
- result.published = true;
3062
- this.emitEndpointRefresh(result.event);
3063
- for (const routeHandle of this.routesRequiringRecovery) {
3064
- if (this.trackedRoutes.has(routeHandle)) {
3065
- this.scheduleRouteRecovery(routeHandle);
3066
- }
3067
- }
3068
- return result;
3069
- }
3070
2410
  if (this.closing || this.closed) {
3071
2411
  await candidate.close();
3072
2412
  candidate = undefined;
@@ -3079,7 +2419,7 @@ export class LocalCodexGatewayProvider {
3079
2419
  if (this.closing || this.closed)
3080
2420
  break;
3081
2421
  try {
3082
- const route = await this.createRoute(routeHandle, replacementFactory, false, codexFactoryWritesEnabled(replacementFactory, attestation, this.latestWriteCompatibilityProbeObservation(replacementFactory.endpointGeneration)?.outcome === "pass"));
2422
+ const route = await this.createRoute(routeHandle, replacementFactory, false);
3083
2423
  if (this.closing || this.closed) {
3084
2424
  await this.closeRoute(route);
3085
2425
  break;
@@ -3105,9 +2445,7 @@ export class LocalCodexGatewayProvider {
3105
2445
  this.factory = replacementFactory;
3106
2446
  candidate = undefined;
3107
2447
  this.retiredEndpointGeneration = undefined;
3108
- this.compatibilityAttested = false;
3109
2448
  this.endpointUnavailable = true;
3110
- this.pendingEndpointAttestation = attestation;
3111
2449
  for (const staged of stagedRoutes) {
3112
2450
  this.routes.set(staged.routeHandle, staged.route);
3113
2451
  this.routesRequiringRecovery.delete(staged.routeHandle);
@@ -3119,20 +2457,16 @@ export class LocalCodexGatewayProvider {
3119
2457
  }
3120
2458
  const result = {
3121
2459
  event: {
3122
- outcome: "compatible",
3123
2460
  previous,
3124
2461
  current: this.identity,
3125
- attestation,
3126
2462
  routes: refreshedRoutes,
3127
2463
  },
3128
2464
  delivery: this.endpointRefreshDelivery ?? "callback",
3129
2465
  selectorClaimed: false,
3130
2466
  published: false,
3131
2467
  };
3132
- if (result.event.outcome === "compatible") {
3133
- this.pendingEndpointRefreshEvent = result.event;
3134
- this.pendingEndpointRefreshSelectorClaimed = false;
3135
- }
2468
+ this.pendingEndpointRefreshEvent = result.event;
2469
+ this.pendingEndpointRefreshSelectorClaimed = false;
3136
2470
  if (result.delivery === "callback") {
3137
2471
  result.selectorClaimed = true;
3138
2472
  result.published = true;
@@ -3163,10 +2497,7 @@ export class LocalCodexGatewayProvider {
3163
2497
  let candidate;
3164
2498
  try {
3165
2499
  candidate = await refreshFactory();
3166
- const versionFailure = codexVersionFailureCode(candidate.appServerVersion);
3167
- validateCodexFactory(candidate, {
3168
- allowUnsupportedVersion: versionFailure !== undefined,
3169
- });
2500
+ validateCodexFactory(candidate);
3170
2501
  if (candidate.hostId !== previous.hostId ||
3171
2502
  candidate.protocol !== previousFactory.protocol) {
3172
2503
  throw new BridgeError("CODEX_FACTORY_ATTESTATION_INVALID", "The replacement Codex factory moved outside its pinned boundary.");
@@ -3176,41 +2507,12 @@ export class LocalCodexGatewayProvider {
3176
2507
  if (candidate !== previousFactory)
3177
2508
  await candidate.close();
3178
2509
  candidate = undefined;
3179
- if (this.endpointUnavailable &&
3180
- this.compatibilityFailureCode === undefined &&
3181
- !this.factory.writableReady &&
3182
- this.factory.writeCompatibility === null) {
3183
- throw new BridgeError("CODEX_MONITOR_ONLY", "This Codex App Server remains monitor-only until a write-attested generation is available.");
3184
- }
3185
2510
  if (attempt + 1 < MAX_CODEX_ENDPOINT_REFRESH_CANDIDATES) {
3186
2511
  continue;
3187
2512
  }
3188
2513
  throw new BridgeError("CODEX_ENDPOINT_GENERATION_CHURN", "The Codex endpoint did not stabilize within its bounded refresh window.", true);
3189
2514
  }
3190
- // Endpoint generations never inherit cached compatibility. A version
3191
- // outside the tested major is classified from OS-attested factory
3192
- // evidence alone; no connector or transport may touch that protocol.
3193
- const probes = versionFailure === undefined
3194
- ? await this.runCompatibilityProbesFor(candidate)
3195
- : compatibilityProbeNames.codex.map((name, index) => index === 0
3196
- ? passedProbe(name)
3197
- : failedProbe(name, versionFailure));
3198
- const attestation = evaluateCompatibilityAttestation({
3199
- surface: "codex",
3200
- version: candidate.appServerVersion,
3201
- checkedAt: this.now().toISOString(),
3202
- certifiedVersions: certifiedCompatibilityVersions.codex,
3203
- probes,
3204
- });
3205
- return {
3206
- factory: candidate,
3207
- identity: {
3208
- provider: "codex",
3209
- hostId: previous.hostId,
3210
- endpointGeneration: candidate.endpointGeneration,
3211
- },
3212
- attestation,
3213
- };
2515
+ return { factory: candidate };
3214
2516
  }
3215
2517
  catch (error) {
3216
2518
  if (candidate !== undefined && candidate !== previousFactory) {
@@ -3266,7 +2568,6 @@ export class LocalCodexGatewayProvider {
3266
2568
  return;
3267
2569
  let event = result.event;
3268
2570
  if (staleRouteHandle !== undefined &&
3269
- event.outcome === "compatible" &&
3270
2571
  event.routes.some((route) => route.routeHandle === staleRouteHandle)) {
3271
2572
  event = {
3272
2573
  ...event,
@@ -3280,9 +2581,7 @@ export class LocalCodexGatewayProvider {
3280
2581
  }
3281
2582
  publishEndpointRefresh(event) {
3282
2583
  this.emitEndpointRefresh(event);
3283
- if (event.outcome === "compatible") {
3284
- this.armEndpointActivationRetry(event);
3285
- }
2584
+ this.armEndpointActivationRetry(event);
3286
2585
  }
3287
2586
  armEndpointActivationRetry(event) {
3288
2587
  this.clearEndpointActivationRetry();
@@ -3295,8 +2594,7 @@ export class LocalCodexGatewayProvider {
3295
2594
  this.closing ||
3296
2595
  this.closed ||
3297
2596
  pending.attempt >= 3 ||
3298
- (pending.event.outcome === "compatible" &&
3299
- this.pendingEndpointAttestation === undefined)) {
2597
+ this.pendingEndpointRefreshEvent !== pending.event) {
3300
2598
  this.clearEndpointActivationRetry();
3301
2599
  return;
3302
2600
  }
@@ -3308,8 +2606,7 @@ export class LocalCodexGatewayProvider {
3308
2606
  const current = this.endpointActivationRetry;
3309
2607
  if (current === undefined || current.event !== pending.event)
3310
2608
  return;
3311
- if (current.event.outcome === "compatible" &&
3312
- this.pendingEndpointAttestation === undefined) {
2609
+ if (this.pendingEndpointRefreshEvent !== current.event) {
3313
2610
  this.clearEndpointActivationRetry();
3314
2611
  return;
3315
2612
  }