@agent-vm/gateway-control-contracts 0.0.112 → 0.0.114

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,788 @@
1
- import { ControlCorrelationSchema, ControlRpcErrorSchema, ControlRpcResultBaseSchema, ControlSessionStateSchema, KnownControlDomainSchema } from "@agent-vm/control-protocol-contracts";
1
+ import { CONTROL_PROTOCOL_VERSION, ControlCorrelationSchema, ControlRpcErrorSchema, ControlRpcResultBaseSchema, ControlSessionStateSchema, KnownControlDomainSchema } from "@agent-vm/control-protocol-contracts";
2
2
  import { z } from "zod/v4";
3
+ //#region src/gateway-control-admission.ts
4
+ const GATEWAY_CONTROL_ADMISSION_LIMITS = {
5
+ authority: {
6
+ maxBytes: 1572864,
7
+ maxMessages: 96
8
+ },
9
+ diagnostic: {
10
+ maxBytes: 1048576,
11
+ maxMessages: 64
12
+ },
13
+ liveness: {
14
+ maxBytes: 1048576,
15
+ maxMessages: 64
16
+ },
17
+ maxFrameBytes: 65536,
18
+ perPrincipalAuthority: {
19
+ maxBytes: 131072,
20
+ maxMessages: 8
21
+ },
22
+ safety: {
23
+ maxBytes: 524288,
24
+ maxMessages: 32
25
+ }
26
+ };
27
+ const GATEWAY_CONTROL_PROCESS_ADMISSION_LIMITS = {
28
+ maxActiveSessions: 32,
29
+ maxNonSafetyBytes: 33554432,
30
+ maxNonSafetyMessages: 2048
31
+ };
32
+ function dequeueFirstCoalescedMessage(messages) {
33
+ const first = messages.entries().next().value;
34
+ if (first === void 0) return;
35
+ messages.delete(first[0]);
36
+ return first[1];
37
+ }
38
+ const serviceCycle = [
39
+ "safety",
40
+ "safety",
41
+ "safety",
42
+ "safety",
43
+ "safety",
44
+ "safety",
45
+ "safety",
46
+ "safety",
47
+ "authority",
48
+ "authority",
49
+ "authority",
50
+ "authority",
51
+ "liveness",
52
+ "liveness",
53
+ "diagnostic"
54
+ ];
55
+ function canReserve(accounting, byteLength, limits) {
56
+ return accounting.byteCount + byteLength <= limits.maxBytes && accounting.messageCount + 1 <= limits.maxMessages;
57
+ }
58
+ function release(accounting, byteLength) {
59
+ accounting.byteCount -= byteLength;
60
+ accounting.messageCount -= 1;
61
+ }
62
+ function requirePositiveLimit(name, value) {
63
+ if (!Number.isSafeInteger(value) || value <= 0) throw new RangeError(`${name} must be a positive safe integer.`);
64
+ }
65
+ function validateMessage(message) {
66
+ if (message.id.length === 0 || !Number.isSafeInteger(message.byteLength) || message.byteLength <= 0) return {
67
+ reason: "invalid_message",
68
+ status: "fence"
69
+ };
70
+ if (message.byteLength > GATEWAY_CONTROL_ADMISSION_LIMITS.maxFrameBytes) return {
71
+ reason: "frame_too_large",
72
+ status: "fence"
73
+ };
74
+ if (message.messageClass === "authority" && (message.stablePrincipal === void 0 || message.stablePrincipal.length === 0)) return {
75
+ reason: "invalid_message",
76
+ status: "fence"
77
+ };
78
+ if ((message.messageClass === "diagnostic" || message.messageClass === "liveness") && (message.coalesceKey === void 0 || message.coalesceKey.length === 0)) return {
79
+ reason: "invalid_message",
80
+ status: "fence"
81
+ };
82
+ }
83
+ function isGatewayControlProcessAdmissionMessage(message) {
84
+ return "zoneId" in message && typeof message.zoneId === "string";
85
+ }
86
+ function gatewayControlProcessCoalescingKey(message) {
87
+ return message.messageClass === "liveness" || message.messageClass === "diagnostic" ? `${message.messageClass}\u0000${message.coalesceKey ?? ""}` : void 0;
88
+ }
89
+ function createGatewayControlAdmissionScheduler() {
90
+ const safety = [];
91
+ const safetyAccounting = {
92
+ byteCount: 0,
93
+ messageCount: 0
94
+ };
95
+ const authorityByPrincipal = /* @__PURE__ */ new Map();
96
+ const authorityPrincipalOrder = [];
97
+ const authorityAccounting = {
98
+ byteCount: 0,
99
+ messageCount: 0
100
+ };
101
+ const livenessByKey = /* @__PURE__ */ new Map();
102
+ const livenessAccounting = {
103
+ byteCount: 0,
104
+ messageCount: 0
105
+ };
106
+ const diagnosticByKey = /* @__PURE__ */ new Map();
107
+ const diagnosticAccounting = {
108
+ byteCount: 0,
109
+ messageCount: 0
110
+ };
111
+ const inFlightMessages = /* @__PURE__ */ new Map();
112
+ let serviceCursor = 0;
113
+ let authorityPrincipalCursor = 0;
114
+ let coalescedMessages = 0;
115
+ let droppedMessages = 0;
116
+ let fencedMessages = 0;
117
+ let refusedMessages = 0;
118
+ let shedMessages = 0;
119
+ const dequeueAuthority = () => {
120
+ if (authorityPrincipalOrder.length === 0) return;
121
+ for (let offset = 0; offset < authorityPrincipalOrder.length; offset += 1) {
122
+ const index = (authorityPrincipalCursor + offset) % authorityPrincipalOrder.length;
123
+ const principal = authorityPrincipalOrder[index];
124
+ if (principal === void 0) continue;
125
+ const queue = authorityByPrincipal.get(principal);
126
+ const message = queue?.messages.shift();
127
+ if (queue === void 0 || message === void 0) continue;
128
+ authorityPrincipalCursor = (index + 1) % authorityPrincipalOrder.length;
129
+ return message;
130
+ }
131
+ };
132
+ const dequeueClass = (messageClass) => {
133
+ switch (messageClass) {
134
+ case "safety": return safety.shift();
135
+ case "authority": return dequeueAuthority();
136
+ case "liveness": return dequeueFirstCoalescedMessage(livenessByKey);
137
+ case "diagnostic": return dequeueFirstCoalescedMessage(diagnosticByKey);
138
+ }
139
+ throw new Error("unsupported gateway control admission class");
140
+ };
141
+ return {
142
+ cancelQueued() {
143
+ const cancelled = [];
144
+ for (const message of safety.splice(0)) {
145
+ release(safetyAccounting, message.byteLength);
146
+ cancelled.push(message);
147
+ }
148
+ for (const [principal, queue] of authorityByPrincipal) {
149
+ for (const message of queue.messages.splice(0)) {
150
+ release(queue, message.byteLength);
151
+ release(authorityAccounting, message.byteLength);
152
+ cancelled.push(message);
153
+ }
154
+ if (queue.messageCount === 0) authorityByPrincipal.delete(principal);
155
+ }
156
+ for (let index = authorityPrincipalOrder.length - 1; index >= 0; index -= 1) if (!authorityByPrincipal.has(authorityPrincipalOrder[index] ?? "")) authorityPrincipalOrder.splice(index, 1);
157
+ authorityPrincipalCursor = authorityPrincipalOrder.length === 0 ? 0 : Math.min(authorityPrincipalCursor, authorityPrincipalOrder.length - 1);
158
+ for (const message of livenessByKey.values()) {
159
+ release(livenessAccounting, message.byteLength);
160
+ cancelled.push(message);
161
+ }
162
+ livenessByKey.clear();
163
+ for (const message of diagnosticByKey.values()) {
164
+ release(diagnosticAccounting, message.byteLength);
165
+ cancelled.push(message);
166
+ }
167
+ diagnosticByKey.clear();
168
+ return cancelled;
169
+ },
170
+ complete(completionToken) {
171
+ const message = inFlightMessages.get(completionToken);
172
+ if (message === void 0 || !inFlightMessages.delete(completionToken)) throw new Error("gateway control admission message is not in flight");
173
+ switch (message.messageClass) {
174
+ case "safety":
175
+ release(safetyAccounting, message.byteLength);
176
+ return;
177
+ case "authority": {
178
+ const principal = message.stablePrincipal ?? "";
179
+ const queue = authorityByPrincipal.get(principal);
180
+ if (queue === void 0) throw new Error("gateway control authority principal is not admitted");
181
+ release(queue, message.byteLength);
182
+ release(authorityAccounting, message.byteLength);
183
+ if (queue.messageCount === 0) {
184
+ authorityByPrincipal.delete(principal);
185
+ const index = authorityPrincipalOrder.indexOf(principal);
186
+ if (index >= 0) {
187
+ authorityPrincipalOrder.splice(index, 1);
188
+ authorityPrincipalCursor = authorityPrincipalOrder.length === 0 ? 0 : Math.min(authorityPrincipalCursor, authorityPrincipalOrder.length - 1);
189
+ }
190
+ }
191
+ return;
192
+ }
193
+ case "liveness":
194
+ release(livenessAccounting, message.byteLength);
195
+ return;
196
+ case "diagnostic":
197
+ release(diagnosticAccounting, message.byteLength);
198
+ return;
199
+ }
200
+ },
201
+ enqueue(message) {
202
+ const invalid = validateMessage(message);
203
+ if (invalid !== void 0) {
204
+ fencedMessages += 1;
205
+ return invalid;
206
+ }
207
+ switch (message.messageClass) {
208
+ case "safety":
209
+ if (!canReserve(safetyAccounting, message.byteLength, GATEWAY_CONTROL_ADMISSION_LIMITS.safety)) {
210
+ fencedMessages += 1;
211
+ return {
212
+ reason: "safety_capacity",
213
+ status: "fence"
214
+ };
215
+ }
216
+ safety.push(message);
217
+ safetyAccounting.byteCount += message.byteLength;
218
+ safetyAccounting.messageCount += 1;
219
+ return { status: "admitted" };
220
+ case "authority": {
221
+ const principal = message.stablePrincipal ?? "";
222
+ const queue = authorityByPrincipal.get(principal) ?? {
223
+ byteCount: 0,
224
+ messageCount: 0,
225
+ messages: []
226
+ };
227
+ if (!canReserve(queue, message.byteLength, GATEWAY_CONTROL_ADMISSION_LIMITS.perPrincipalAuthority)) {
228
+ refusedMessages += 1;
229
+ return {
230
+ reason: "principal_capacity",
231
+ status: "refused"
232
+ };
233
+ }
234
+ if (!canReserve(authorityAccounting, message.byteLength, GATEWAY_CONTROL_ADMISSION_LIMITS.authority)) {
235
+ fencedMessages += 1;
236
+ return {
237
+ reason: "authority_capacity",
238
+ status: "fence"
239
+ };
240
+ }
241
+ if (!authorityByPrincipal.has(principal)) {
242
+ authorityByPrincipal.set(principal, queue);
243
+ authorityPrincipalOrder.push(principal);
244
+ }
245
+ queue.messages.push(message);
246
+ queue.byteCount += message.byteLength;
247
+ queue.messageCount += 1;
248
+ authorityAccounting.byteCount += message.byteLength;
249
+ authorityAccounting.messageCount += 1;
250
+ return { status: "admitted" };
251
+ }
252
+ case "liveness":
253
+ case "diagnostic": {
254
+ const isLiveness = message.messageClass === "liveness";
255
+ const messages = isLiveness ? livenessByKey : diagnosticByKey;
256
+ const accounting = isLiveness ? livenessAccounting : diagnosticAccounting;
257
+ const limits = isLiveness ? GATEWAY_CONTROL_ADMISSION_LIMITS.liveness : GATEWAY_CONTROL_ADMISSION_LIMITS.diagnostic;
258
+ const key = message.coalesceKey ?? "";
259
+ const prior = messages.get(key);
260
+ const nextBytes = accounting.byteCount - (prior?.byteLength ?? 0) + message.byteLength;
261
+ const nextMessages = accounting.messageCount + (prior === void 0 ? 1 : 0);
262
+ if (nextBytes > limits.maxBytes || nextMessages > limits.maxMessages) {
263
+ if (isLiveness) {
264
+ shedMessages += 1;
265
+ return {
266
+ reason: "liveness_capacity",
267
+ status: "shed"
268
+ };
269
+ }
270
+ droppedMessages += 1;
271
+ return {
272
+ reason: "diagnostic_capacity",
273
+ status: "dropped"
274
+ };
275
+ }
276
+ messages.set(key, message);
277
+ accounting.byteCount = nextBytes;
278
+ accounting.messageCount = nextMessages;
279
+ if (prior !== void 0) coalescedMessages += 1;
280
+ return prior === void 0 ? { status: "admitted" } : {
281
+ replacedMessage: prior,
282
+ status: "replaced"
283
+ };
284
+ }
285
+ }
286
+ throw new Error("unsupported gateway control admission class");
287
+ },
288
+ dequeue(options = {}) {
289
+ for (let offset = 0; offset < serviceCycle.length; offset += 1) {
290
+ const index = (serviceCursor + offset) % serviceCycle.length;
291
+ const messageClass = serviceCycle[index];
292
+ if (messageClass === void 0) continue;
293
+ if (options.allowedMessageClasses !== void 0 && !options.allowedMessageClasses.includes(messageClass)) continue;
294
+ const message = dequeueClass(messageClass);
295
+ if (message !== void 0) {
296
+ serviceCursor = (index + 1) % serviceCycle.length;
297
+ const completionToken = Object.freeze({ completionTokenId: Symbol("gateway-control-admission-completion") });
298
+ inFlightMessages.set(completionToken, message);
299
+ return {
300
+ completionToken,
301
+ message
302
+ };
303
+ }
304
+ }
305
+ },
306
+ diagnostics() {
307
+ return {
308
+ authorityBytes: authorityAccounting.byteCount,
309
+ authorityMessages: authorityAccounting.messageCount,
310
+ diagnosticBytes: diagnosticAccounting.byteCount,
311
+ diagnosticMessages: diagnosticAccounting.messageCount,
312
+ livenessBytes: livenessAccounting.byteCount,
313
+ livenessMessages: livenessAccounting.messageCount,
314
+ safetyBytes: safetyAccounting.byteCount,
315
+ safetyMessages: safetyAccounting.messageCount,
316
+ coalescedMessages,
317
+ droppedMessages,
318
+ fencedMessages,
319
+ refusedMessages,
320
+ shedMessages
321
+ };
322
+ }
323
+ };
324
+ }
325
+ function createGatewayControlProcessAdmission(options = {}) {
326
+ const maxActiveSessions = options.maxActiveSessions ?? GATEWAY_CONTROL_PROCESS_ADMISSION_LIMITS.maxActiveSessions;
327
+ const maxNonSafetyBytes = options.maxNonSafetyBytes ?? GATEWAY_CONTROL_PROCESS_ADMISSION_LIMITS.maxNonSafetyBytes;
328
+ const maxNonSafetyMessages = options.maxNonSafetyMessages ?? GATEWAY_CONTROL_PROCESS_ADMISSION_LIMITS.maxNonSafetyMessages;
329
+ const schedulersByZone = /* @__PURE__ */ new Map();
330
+ const queuedCoalescibleMessagesByZone = /* @__PURE__ */ new Map();
331
+ const inFlightMessages = /* @__PURE__ */ new Map();
332
+ const zoneOrder = [];
333
+ let zoneCursor = 0;
334
+ let nonSafetyBytes = 0;
335
+ let nonSafetyMessages = 0;
336
+ requirePositiveLimit("maxActiveSessions", maxActiveSessions);
337
+ requirePositiveLimit("maxNonSafetyBytes", maxNonSafetyBytes);
338
+ requirePositiveLimit("maxNonSafetyMessages", maxNonSafetyMessages);
339
+ return {
340
+ complete(completionToken) {
341
+ const message = inFlightMessages.get(completionToken);
342
+ if (message === void 0 || !inFlightMessages.delete(completionToken)) throw new Error("gateway control process admission message is not in flight");
343
+ const scheduler = schedulersByZone.get(message.zoneId);
344
+ if (scheduler === void 0) throw new Error("gateway control process admission zone is not registered");
345
+ scheduler.complete(completionToken);
346
+ if (message.messageClass !== "safety") {
347
+ nonSafetyMessages -= 1;
348
+ nonSafetyBytes -= message.byteLength;
349
+ }
350
+ },
351
+ registerZone(zoneId) {
352
+ if (zoneId.length === 0) return { status: "capacity_refused" };
353
+ if (schedulersByZone.has(zoneId)) return { status: "admitted" };
354
+ if (schedulersByZone.size >= maxActiveSessions) return { status: "capacity_refused" };
355
+ schedulersByZone.set(zoneId, createGatewayControlAdmissionScheduler());
356
+ queuedCoalescibleMessagesByZone.set(zoneId, /* @__PURE__ */ new Map());
357
+ zoneOrder.push(zoneId);
358
+ return { status: "admitted" };
359
+ },
360
+ unregisterZone(zoneId) {
361
+ const scheduler = schedulersByZone.get(zoneId);
362
+ if (scheduler === void 0) return;
363
+ for (;;) {
364
+ const work = scheduler.dequeue();
365
+ if (work === void 0) break;
366
+ const { completionToken, message } = work;
367
+ if (message.messageClass !== "safety") {
368
+ nonSafetyBytes -= message.byteLength;
369
+ nonSafetyMessages -= 1;
370
+ }
371
+ scheduler.complete(completionToken);
372
+ }
373
+ for (const [completionToken, message] of inFlightMessages) {
374
+ if (message.zoneId !== zoneId) continue;
375
+ inFlightMessages.delete(completionToken);
376
+ scheduler.complete(completionToken);
377
+ if (message.messageClass !== "safety") {
378
+ nonSafetyBytes -= message.byteLength;
379
+ nonSafetyMessages -= 1;
380
+ }
381
+ }
382
+ schedulersByZone.delete(zoneId);
383
+ queuedCoalescibleMessagesByZone.delete(zoneId);
384
+ const index = zoneOrder.indexOf(zoneId);
385
+ if (index >= 0) {
386
+ zoneOrder.splice(index, 1);
387
+ zoneCursor = zoneOrder.length === 0 ? 0 : Math.min(zoneCursor, zoneOrder.length - 1);
388
+ }
389
+ },
390
+ enqueue(message) {
391
+ const scheduler = schedulersByZone.get(message.zoneId);
392
+ if (scheduler === void 0) return {
393
+ reason: "global_capacity",
394
+ status: "refused"
395
+ };
396
+ const coalescingKey = gatewayControlProcessCoalescingKey(message);
397
+ const priorCoalescibleMessage = coalescingKey === void 0 ? void 0 : queuedCoalescibleMessagesByZone.get(message.zoneId)?.get(coalescingKey);
398
+ const nonSafetyMessageDelta = priorCoalescibleMessage === void 0 ? 1 : 0;
399
+ const nonSafetyByteDelta = message.byteLength - (priorCoalescibleMessage?.byteLength ?? 0);
400
+ if (message.messageClass !== "safety" && (nonSafetyMessages + nonSafetyMessageDelta > maxNonSafetyMessages || nonSafetyBytes + nonSafetyByteDelta > maxNonSafetyBytes)) return message.messageClass === "authority" ? {
401
+ reason: "global_capacity",
402
+ status: "refused"
403
+ } : message.messageClass === "liveness" ? {
404
+ reason: "global_capacity",
405
+ status: "shed"
406
+ } : {
407
+ reason: "global_capacity",
408
+ status: "dropped"
409
+ };
410
+ const before = scheduler.diagnostics();
411
+ const result = scheduler.enqueue(message);
412
+ if (message.messageClass !== "safety" && (result.status === "admitted" || result.status === "replaced")) {
413
+ const after = scheduler.diagnostics();
414
+ const beforeMessages = before.authorityMessages + before.livenessMessages + before.diagnosticMessages;
415
+ const afterMessages = after.authorityMessages + after.livenessMessages + after.diagnosticMessages;
416
+ const beforeBytes = before.authorityBytes + before.livenessBytes + before.diagnosticBytes;
417
+ const afterBytes = after.authorityBytes + after.livenessBytes + after.diagnosticBytes;
418
+ nonSafetyMessages += afterMessages - beforeMessages;
419
+ nonSafetyBytes += afterBytes - beforeBytes;
420
+ if (coalescingKey !== void 0) queuedCoalescibleMessagesByZone.get(message.zoneId)?.set(coalescingKey, message);
421
+ }
422
+ return result;
423
+ },
424
+ dequeue() {
425
+ if (zoneOrder.length === 0) return;
426
+ for (let offset = 0; offset < zoneOrder.length; offset += 1) {
427
+ const index = (zoneCursor + offset) % zoneOrder.length;
428
+ const zoneId = zoneOrder[index];
429
+ const work = (zoneId === void 0 ? void 0 : schedulersByZone.get(zoneId))?.dequeue();
430
+ if (zoneId === void 0 || work === void 0) continue;
431
+ const { completionToken, message } = work;
432
+ if (!isGatewayControlProcessAdmissionMessage(message) || message.zoneId !== zoneId) throw new Error("gateway control process admission message lost its zone identity");
433
+ const coalescingKey = gatewayControlProcessCoalescingKey(message);
434
+ if (coalescingKey !== void 0) {
435
+ const queuedMessages = queuedCoalescibleMessagesByZone.get(zoneId);
436
+ if (queuedMessages?.get(coalescingKey) === message) queuedMessages.delete(coalescingKey);
437
+ }
438
+ zoneCursor = (index + 1) % zoneOrder.length;
439
+ inFlightMessages.set(completionToken, message);
440
+ return {
441
+ completionToken,
442
+ message
443
+ };
444
+ }
445
+ },
446
+ diagnostics() {
447
+ return {
448
+ activeSessions: schedulersByZone.size,
449
+ nonSafetyBytes,
450
+ nonSafetyMessages
451
+ };
452
+ }
453
+ };
454
+ }
455
+ //#endregion
456
+ //#region src/gateway-control-admission-executor.ts
457
+ const GATEWAY_CONTROL_ADMISSION_EXECUTION_LIMITS = {
458
+ authority: 4,
459
+ diagnostic: 1,
460
+ liveness: 2,
461
+ safety: 8
462
+ };
463
+ const GATEWAY_CONTROL_ADMISSION_CLASSES = [
464
+ "authority",
465
+ "diagnostic",
466
+ "liveness",
467
+ "safety"
468
+ ];
469
+ function executionMessage(request, work) {
470
+ return {
471
+ byteLength: request.byteLength,
472
+ ...request.coalesceKey === void 0 ? {} : { coalesceKey: request.coalesceKey },
473
+ id: request.id,
474
+ messageClass: request.messageClass,
475
+ payload: work,
476
+ ...request.stablePrincipal === void 0 ? {} : { stablePrincipal: request.stablePrincipal }
477
+ };
478
+ }
479
+ function createGatewayControlAdmissionExecutor(options = {}) {
480
+ const scheduler = createGatewayControlAdmissionScheduler();
481
+ const scheduleImmediate = options.scheduleImmediate ?? ((callback) => setImmediate(callback));
482
+ const executionLimits = {
483
+ ...GATEWAY_CONTROL_ADMISSION_EXECUTION_LIMITS,
484
+ ...options.executionLimits
485
+ };
486
+ const activeByClass = {
487
+ authority: 0,
488
+ diagnostic: 0,
489
+ liveness: 0,
490
+ safety: 0
491
+ };
492
+ let pumpScheduled = false;
493
+ let admissionGeneration = 0;
494
+ let closedReason;
495
+ const activeWork = /* @__PURE__ */ new Set();
496
+ for (const messageClass of GATEWAY_CONTROL_ADMISSION_CLASSES) {
497
+ const limit = executionLimits[messageClass];
498
+ if (!Number.isSafeInteger(limit) || limit <= 0) throw new RangeError(`${messageClass} execution limit must be a positive safe integer.`);
499
+ }
500
+ const schedulePump = () => {
501
+ if (pumpScheduled || closedReason !== void 0) return;
502
+ pumpScheduled = true;
503
+ scheduleImmediate(() => {
504
+ pumpScheduled = false;
505
+ pump();
506
+ });
507
+ };
508
+ const pump = () => {
509
+ if (closedReason !== void 0) return;
510
+ for (;;) {
511
+ const allowedMessageClasses = GATEWAY_CONTROL_ADMISSION_CLASSES.filter((messageClass) => activeByClass[messageClass] < executionLimits[messageClass]);
512
+ if (allowedMessageClasses.length === 0) return;
513
+ const admittedWork = scheduler.dequeue({ allowedMessageClasses });
514
+ if (admittedWork === void 0) return;
515
+ const { completionToken, message } = admittedWork;
516
+ const messageClass = message.messageClass;
517
+ const work = message.payload;
518
+ activeByClass[messageClass] += 1;
519
+ activeWork.add(work);
520
+ (async () => {
521
+ let executionError;
522
+ try {
523
+ await work.execute();
524
+ } catch (error) {
525
+ executionError = error;
526
+ } finally {
527
+ scheduler.complete(completionToken);
528
+ activeByClass[messageClass] -= 1;
529
+ activeWork.delete(work);
530
+ schedulePump();
531
+ }
532
+ if (work.settled || work.admissionGeneration !== admissionGeneration) return;
533
+ work.settled = true;
534
+ if (executionError === void 0) {
535
+ work.resolve({ status: "executed" });
536
+ return;
537
+ }
538
+ work.reject(executionError);
539
+ })();
540
+ }
541
+ };
542
+ return {
543
+ close: (reason) => {
544
+ if (closedReason !== void 0) return;
545
+ closedReason = reason;
546
+ admissionGeneration += 1;
547
+ for (const message of scheduler.cancelQueued()) {
548
+ const work = message.payload;
549
+ if (!work.settled) {
550
+ work.settled = true;
551
+ work.onCancel?.(reason);
552
+ work.resolve({
553
+ reason,
554
+ status: "closed"
555
+ });
556
+ }
557
+ }
558
+ for (const work of activeWork) if (!work.settled) {
559
+ work.settled = true;
560
+ work.onCancel?.(reason);
561
+ work.resolve({
562
+ reason,
563
+ status: "closed"
564
+ });
565
+ }
566
+ },
567
+ diagnostics: () => ({
568
+ activeByClass: { ...activeByClass },
569
+ scheduler: scheduler.diagnostics()
570
+ }),
571
+ submit: (request) => {
572
+ if (closedReason !== void 0) {
573
+ const closed = {
574
+ reason: closedReason,
575
+ status: "closed"
576
+ };
577
+ return {
578
+ admission: closed,
579
+ completion: Promise.resolve(closed)
580
+ };
581
+ }
582
+ let resolveCompletion;
583
+ let rejectCompletion;
584
+ const completion = new Promise((resolve, reject) => {
585
+ resolveCompletion = resolve;
586
+ rejectCompletion = reject;
587
+ });
588
+ const work = {
589
+ admissionGeneration,
590
+ execute: request.execute,
591
+ ...request.onCancel === void 0 ? {} : { onCancel: request.onCancel },
592
+ payload: request.payload,
593
+ reject: rejectCompletion,
594
+ resolve: resolveCompletion,
595
+ settled: false
596
+ };
597
+ const result = scheduler.enqueue(executionMessage(request, work));
598
+ switch (result.status) {
599
+ case "admitted":
600
+ schedulePump();
601
+ return {
602
+ admission: { status: "admitted" },
603
+ completion
604
+ };
605
+ case "replaced":
606
+ if (!result.replacedMessage.payload.settled) {
607
+ result.replacedMessage.payload.settled = true;
608
+ result.replacedMessage.payload.onCancel?.("replaced");
609
+ result.replacedMessage.payload.resolve({ status: "replaced" });
610
+ }
611
+ schedulePump();
612
+ return {
613
+ admission: { status: "replaced" },
614
+ completion
615
+ };
616
+ case "dropped":
617
+ case "fence":
618
+ case "refused":
619
+ case "shed":
620
+ resolveCompletion(result);
621
+ return {
622
+ admission: result,
623
+ completion
624
+ };
625
+ }
626
+ throw new Error("unsupported gateway control admission result");
627
+ }
628
+ };
629
+ }
630
+ //#endregion
631
+ //#region src/gateway-control-admission-classification.ts
632
+ function authorityClassification(stablePrincipal) {
633
+ return stablePrincipal === void 0 || stablePrincipal.length === 0 ? {
634
+ reason: "stable_principal_required",
635
+ status: "refused"
636
+ } : {
637
+ authoritySchedulingKey: stablePrincipal,
638
+ messageClass: "authority",
639
+ stablePrincipal,
640
+ status: "classified"
641
+ };
642
+ }
643
+ function diagnosticCoalesceKey(payload) {
644
+ return JSON.stringify([
645
+ payload.eventKind,
646
+ "leaseId" in payload ? payload.leaseId : void 0,
647
+ "transitionId" in payload ? payload.transitionId : void 0,
648
+ "operation" in payload ? payload.operation : void 0,
649
+ "channelProviderId" in payload ? payload.channelProviderId : void 0
650
+ ]);
651
+ }
652
+ function classifyGatewayControlAdmission(options) {
653
+ const message = options.message;
654
+ if (message.kind === "command_result") return options.matchedPendingResult === true ? {
655
+ messageClass: "safety",
656
+ status: "classified"
657
+ } : {
658
+ reason: "forged_command_result",
659
+ status: "fence"
660
+ };
661
+ if (message.kind === "heartbeat") return {
662
+ coalesceKey: `${options.direction}:control-heartbeat`,
663
+ messageClass: "liveness",
664
+ status: "classified"
665
+ };
666
+ if (message.kind === "event") {
667
+ if (options.direction !== "gateway_to_controller") return {
668
+ reason: "direction_violation",
669
+ status: "fence"
670
+ };
671
+ switch (message.operation) {
672
+ case "runtime_status": return {
673
+ coalesceKey: `runtime-status:${message.payload.statusKind}`,
674
+ messageClass: "liveness",
675
+ status: "classified"
676
+ };
677
+ case "health_event": return {
678
+ coalesceKey: diagnosticCoalesceKey(message.payload),
679
+ messageClass: "diagnostic",
680
+ status: "classified"
681
+ };
682
+ }
683
+ }
684
+ if (message.operation === "control_ping") return {
685
+ coalesceKey: `${options.direction}:control-ping`,
686
+ messageClass: "liveness",
687
+ status: "classified"
688
+ };
689
+ if (options.direction === "controller_to_gateway") switch (message.operation) {
690
+ case "operation_cancel": return options.controllerSafetyOperation === true && message.payload.initiatedBy === "controller" ? {
691
+ messageClass: "safety",
692
+ status: "classified"
693
+ } : {
694
+ reason: "direction_violation",
695
+ status: "fence"
696
+ };
697
+ case "recovery_command": return options.controllerSafetyOperation === true ? {
698
+ messageClass: "safety",
699
+ status: "classified"
700
+ } : {
701
+ reason: "direction_violation",
702
+ status: "fence"
703
+ };
704
+ case "caller_context_register":
705
+ case "lease_create":
706
+ case "lease_get":
707
+ case "lease_peek":
708
+ case "lease_reacquire":
709
+ case "lease_release":
710
+ case "lease_renew":
711
+ case "lease_use_start":
712
+ case "lease_use_heartbeat":
713
+ case "lease_use_end":
714
+ case "tool_portal_controller_host_action": return {
715
+ reason: "direction_violation",
716
+ status: "fence"
717
+ };
718
+ }
719
+ switch (message.operation) {
720
+ case "caller_context_register": return authorityClassification(options.stablePrincipal);
721
+ case "lease_renew": return options.stablePrincipal === void 0 ? {
722
+ reason: "stable_principal_required",
723
+ status: "refused"
724
+ } : {
725
+ coalesceKey: `${options.stablePrincipal}:lease:${message.payload.leaseId}`,
726
+ messageClass: "liveness",
727
+ status: "classified"
728
+ };
729
+ case "lease_use_heartbeat": return options.stablePrincipal === void 0 ? {
730
+ reason: "stable_principal_required",
731
+ status: "refused"
732
+ } : {
733
+ coalesceKey: `${options.stablePrincipal}:lease:${message.payload.leaseId}:use:${message.payload.useId}`,
734
+ messageClass: "liveness",
735
+ status: "classified"
736
+ };
737
+ case "operation_cancel": return message.payload.initiatedBy === "gateway" ? {
738
+ reason: "unproven_gateway_cancel",
739
+ status: "refused"
740
+ } : {
741
+ reason: "direction_violation",
742
+ status: "fence"
743
+ };
744
+ case "recovery_command": return {
745
+ reason: "direction_violation",
746
+ status: "fence"
747
+ };
748
+ case "lease_create":
749
+ case "lease_get":
750
+ case "lease_peek":
751
+ case "lease_reacquire":
752
+ case "lease_release":
753
+ case "lease_use_start":
754
+ case "lease_use_end":
755
+ case "tool_portal_controller_host_action": return authorityClassification(options.stablePrincipal);
756
+ }
757
+ return {
758
+ reason: "direction_violation",
759
+ status: "fence"
760
+ };
761
+ }
762
+ //#endregion
3
763
  //#region src/index.ts
4
764
  const GatewayControlDomainSchema = z.literal("gateway_control");
765
+ const GatewayControlHelloSchema = z.object({
766
+ attachmentGeneration: z.number().int().positive(),
767
+ controllerEpoch: z.string().min(1),
768
+ domain: GatewayControlDomainSchema,
769
+ gatewayEpoch: z.string().min(1),
770
+ peerId: z.string().min(1),
771
+ processEpoch: z.string().min(1),
772
+ protocolVersion: z.literal(CONTROL_PROTOCOL_VERSION)
773
+ }).strict();
774
+ const GatewayControlHelloResponseSchema = z.object({
775
+ attachmentGeneration: z.number().int().positive(),
776
+ connectionId: z.string().uuid(),
777
+ controllerEpoch: z.string().min(1),
778
+ outcome: z.enum([
779
+ "accepted",
780
+ "rejected",
781
+ "generation_mismatch",
782
+ "stale_attachment"
783
+ ]),
784
+ sessionId: z.string().uuid()
785
+ }).strict();
5
786
  const GatewayControlRpcOperationSchema = z.enum([
6
787
  "control_ping",
7
788
  "caller_context_register",
@@ -52,6 +833,7 @@ const GatewayControlCapabilityRefSchema = z.object({
52
833
  }).strict();
53
834
  const GatewayControlToolCallCorrelationSchema = ControlCorrelationSchema.extend({ capability: GatewayControlCapabilityRefSchema.optional() }).strict();
54
835
  const GatewayControlTrustedCallerContextIdSchema = z.string().uuid();
836
+ const GatewayControlAdmissionPrincipalSchema = z.string().regex(/^[a-f0-9]{64}$/u);
55
837
  const GatewayControlTrustedLeaseContextSchema = z.object({
56
838
  agentId: z.string().min(1),
57
839
  agentWorkspaceDir: z.string().min(1),
@@ -65,6 +847,7 @@ const GatewayControlTrustedLeaseContextSchema = z.object({
65
847
  zoneId: z.string().min(1)
66
848
  }).strict();
67
849
  const GatewayControlCallerContextRefSchema = z.object({ callerContextId: GatewayControlTrustedCallerContextIdSchema }).strict();
850
+ const GatewayControlRegisteredCallerContextRefSchema = GatewayControlCallerContextRefSchema.extend({ admissionPrincipal: GatewayControlAdmissionPrincipalSchema }).strict();
68
851
  const GatewayControlCallerContextProofAlgorithmSchema = z.literal("hmac-sha256");
69
852
  const GatewayControlCallerContextProofSchema = z.object({
70
853
  algorithm: GatewayControlCallerContextProofAlgorithmSchema,
@@ -406,7 +1189,7 @@ const GatewayControlSessionStateSchema = ControlSessionStateSchema;
406
1189
  const GatewayControlToolVmSshAccessSchema = z.object({
407
1190
  host: z.string().min(1),
408
1191
  identityPem: z.string().min(1).optional(),
409
- knownHostsLine: z.string().optional(),
1192
+ knownHostsLine: z.string().min(1).optional(),
410
1193
  port: z.number().int().positive(),
411
1194
  user: z.string().min(1)
412
1195
  }).strict();
@@ -475,7 +1258,7 @@ const GatewayControlRpcBareResponsePayloadSchema = z.discriminatedUnion("result"
475
1258
  }).strict()]);
476
1259
  const GatewayControlRpcCallerContextResponsePayloadSchema = z.discriminatedUnion("result", [GatewayControlRpcResponseCorrelationSchema.extend({
477
1260
  ...GatewayControlRpcForbiddenResponseFieldsSchema,
478
- callerContext: GatewayControlCallerContextRefSchema,
1261
+ callerContext: GatewayControlRegisteredCallerContextRefSchema,
479
1262
  result: z.literal("ok")
480
1263
  }).strict(), GatewayControlRpcResponseCorrelationSchema.extend({
481
1264
  ...GatewayControlRpcForbiddenResponseFieldsSchema,
@@ -768,6 +1551,14 @@ function buildGatewayControlJsonSchemas() {
768
1551
  io: "input",
769
1552
  unrepresentable: "any"
770
1553
  }),
1554
+ hello: z.toJSONSchema(GatewayControlHelloSchema, {
1555
+ io: "input",
1556
+ unrepresentable: "any"
1557
+ }),
1558
+ helloResponse: z.toJSONSchema(GatewayControlHelloResponseSchema, {
1559
+ io: "input",
1560
+ unrepresentable: "any"
1561
+ }),
771
1562
  message: z.toJSONSchema(GatewayControlRpcMessageSchema, {
772
1563
  io: "input",
773
1564
  unrepresentable: "any"
@@ -782,6 +1573,6 @@ function assertGatewayControlDomainRegistered() {
782
1573
  return KnownControlDomainSchema.extract(["gateway_control"]).parse("gateway_control");
783
1574
  }
784
1575
  //#endregion
785
- export { ControllerInitiatedGatewayOperationCancelPayloadSchema, GatewayControlActiveOperationIdSchema, GatewayControlCallerContextAgentAuthoritySchema, GatewayControlCallerContextProofAlgorithmSchema, GatewayControlCallerContextProofSchema, GatewayControlCallerContextRefSchema, GatewayControlCallerContextRegisterPayloadSchema, GatewayControlCapabilityRefSchema, GatewayControlControllerHostProbeActionResultSchema, GatewayControlControllerHostProbePayloadSchema, GatewayControlControllerHostProbeResultSchema, GatewayControlControllerRequestHealthOperationSchema, GatewayControlDomainSchema, GatewayControlEventOnlyOperationSchema, GatewayControlForbiddenPayloadFieldSchema, GatewayControlHealthEventPayloadSchema, GatewayControlHealthEventResultSchema, GatewayControlHeartbeatPayloadSchema, GatewayControlLeaseCreateIntentPayloadSchema, GatewayControlLeaseIdPayloadSchema, GatewayControlLeaseReacquireIntentPayloadSchema, GatewayControlLeaseRejectionReasonSchema, GatewayControlLeaseSnapshotSchema, GatewayControlLeaseStaleEvidenceSchema, GatewayControlLeaseUseEndPayloadSchema, GatewayControlLeaseUseHeartbeatPayloadSchema, GatewayControlLeaseUseSnapshotSchema, GatewayControlLeaseUseStartPayloadSchema, GatewayControlOperationCancelPayloadSchema, GatewayControlPingPayloadSchema, GatewayControlProviderRuntimeHealthSchema, GatewayControlRecoveryCommandPayloadSchema, GatewayControlRpcBareResponsePayloadSchema, GatewayControlRpcCallerContextResponsePayloadSchema, GatewayControlRpcCommandMessageSchema, GatewayControlRpcCommandResultMessageSchema, GatewayControlRpcCommandResultOperationSchema, GatewayControlRpcControllerHostActionResponsePayloadSchema, GatewayControlRpcDomainCorrelationSchema, GatewayControlRpcErrorSchema, GatewayControlRpcEventMessageSchema, GatewayControlRpcLeaseResponsePayloadSchema, GatewayControlRpcLeaseUseResponsePayloadSchema, GatewayControlRpcMessageSchema, GatewayControlRpcOperationCancelResponsePayloadSchema, GatewayControlRpcOperationSchema, GatewayControlRpcResponseBasePayloadSchema, GatewayControlRpcResponsePayloadSchema, GatewayControlRpcResultSchema, GatewayControlRuntimeFindingSchema, GatewayControlRuntimeStatusPayloadSchema, GatewayControlSessionHealthOperationSchema, GatewayControlSessionStateSchema, GatewayControlToolCallCorrelationSchema, GatewayControlToolPortalControllerHostActionPayloadSchema, GatewayControlToolPortalControllerHostActionResultSchema, GatewayControlToolVmLeaseCallerContextStateSchema, GatewayControlToolVmLeaseLifecycleEventRoleSchema, GatewayControlToolVmLeaseLifecycleTransitionSchema, GatewayControlToolVmSshAccessSchema, GatewayControlToolVmSshHealthOperationSchema, GatewayControlTrustedCallerContextIdSchema, GatewayControlTrustedLeaseContextSchema, GatewayControlZoneGitCommitSummarySchema, GatewayControlZoneGitPushControllerHostActionPayloadSchema, GatewayControlZoneGitPushControllerHostActionResultSchema, GatewayControlZoneGitPushResultSchema, GatewayInitiatedOperationCancelPayloadSchema, assertGatewayControlDomainRegistered, assertGatewayControlEnvelopeDeliveryPolicy, buildGatewayControlCallerContextAgentAuthorityPayload, buildGatewayControlCallerContextProofPayload, buildGatewayControlJsonSchemas, deriveGatewayControlDeliveryPolicy, gatewayControlCommandExecutionTimeoutMsByOperation, gatewayControlDeliveryPolicyByKind, gatewayControlDeliveryPolicyByOperation };
1576
+ export { ControllerInitiatedGatewayOperationCancelPayloadSchema, GATEWAY_CONTROL_ADMISSION_EXECUTION_LIMITS, GATEWAY_CONTROL_ADMISSION_LIMITS, GATEWAY_CONTROL_PROCESS_ADMISSION_LIMITS, GatewayControlActiveOperationIdSchema, GatewayControlAdmissionPrincipalSchema, GatewayControlCallerContextAgentAuthoritySchema, GatewayControlCallerContextProofAlgorithmSchema, GatewayControlCallerContextProofSchema, GatewayControlCallerContextRefSchema, GatewayControlCallerContextRegisterPayloadSchema, GatewayControlCapabilityRefSchema, GatewayControlControllerHostProbeActionResultSchema, GatewayControlControllerHostProbePayloadSchema, GatewayControlControllerHostProbeResultSchema, GatewayControlControllerRequestHealthOperationSchema, GatewayControlDomainSchema, GatewayControlEventOnlyOperationSchema, GatewayControlForbiddenPayloadFieldSchema, GatewayControlHealthEventPayloadSchema, GatewayControlHealthEventResultSchema, GatewayControlHeartbeatPayloadSchema, GatewayControlHelloResponseSchema, GatewayControlHelloSchema, GatewayControlLeaseCreateIntentPayloadSchema, GatewayControlLeaseIdPayloadSchema, GatewayControlLeaseReacquireIntentPayloadSchema, GatewayControlLeaseRejectionReasonSchema, GatewayControlLeaseSnapshotSchema, GatewayControlLeaseStaleEvidenceSchema, GatewayControlLeaseUseEndPayloadSchema, GatewayControlLeaseUseHeartbeatPayloadSchema, GatewayControlLeaseUseSnapshotSchema, GatewayControlLeaseUseStartPayloadSchema, GatewayControlOperationCancelPayloadSchema, GatewayControlPingPayloadSchema, GatewayControlProviderRuntimeHealthSchema, GatewayControlRecoveryCommandPayloadSchema, GatewayControlRegisteredCallerContextRefSchema, GatewayControlRpcBareResponsePayloadSchema, GatewayControlRpcCallerContextResponsePayloadSchema, GatewayControlRpcCommandMessageSchema, GatewayControlRpcCommandResultMessageSchema, GatewayControlRpcCommandResultOperationSchema, GatewayControlRpcControllerHostActionResponsePayloadSchema, GatewayControlRpcDomainCorrelationSchema, GatewayControlRpcErrorSchema, GatewayControlRpcEventMessageSchema, GatewayControlRpcLeaseResponsePayloadSchema, GatewayControlRpcLeaseUseResponsePayloadSchema, GatewayControlRpcMessageSchema, GatewayControlRpcOperationCancelResponsePayloadSchema, GatewayControlRpcOperationSchema, GatewayControlRpcResponseBasePayloadSchema, GatewayControlRpcResponsePayloadSchema, GatewayControlRpcResultSchema, GatewayControlRuntimeFindingSchema, GatewayControlRuntimeStatusPayloadSchema, GatewayControlSessionHealthOperationSchema, GatewayControlSessionStateSchema, GatewayControlToolCallCorrelationSchema, GatewayControlToolPortalControllerHostActionPayloadSchema, GatewayControlToolPortalControllerHostActionResultSchema, GatewayControlToolVmLeaseCallerContextStateSchema, GatewayControlToolVmLeaseLifecycleEventRoleSchema, GatewayControlToolVmLeaseLifecycleTransitionSchema, GatewayControlToolVmSshAccessSchema, GatewayControlToolVmSshHealthOperationSchema, GatewayControlTrustedCallerContextIdSchema, GatewayControlTrustedLeaseContextSchema, GatewayControlZoneGitCommitSummarySchema, GatewayControlZoneGitPushControllerHostActionPayloadSchema, GatewayControlZoneGitPushControllerHostActionResultSchema, GatewayControlZoneGitPushResultSchema, GatewayInitiatedOperationCancelPayloadSchema, assertGatewayControlDomainRegistered, assertGatewayControlEnvelopeDeliveryPolicy, buildGatewayControlCallerContextAgentAuthorityPayload, buildGatewayControlCallerContextProofPayload, buildGatewayControlJsonSchemas, classifyGatewayControlAdmission, createGatewayControlAdmissionExecutor, createGatewayControlAdmissionScheduler, createGatewayControlProcessAdmission, deriveGatewayControlDeliveryPolicy, gatewayControlCommandExecutionTimeoutMsByOperation, gatewayControlDeliveryPolicyByKind, gatewayControlDeliveryPolicyByOperation };
786
1577
 
787
1578
  //# sourceMappingURL=index.js.map