open-multi-agent-kit 0.79.3 → 0.80.2

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 (128) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/MATURITY.md +2 -2
  3. package/README.md +86 -39
  4. package/ROADMAP.md +20 -17
  5. package/dist/brand/night-city.theme.json +122 -24
  6. package/dist/brand/rust-forge.theme.json +1 -1
  7. package/dist/commands/chat/native-root-loop.d.ts +27 -3
  8. package/dist/commands/chat/native-root-loop.js +370 -49
  9. package/dist/commands/dag.js +45 -0
  10. package/dist/commands/init/content.d.ts +1 -1
  11. package/dist/commands/init/content.js +3 -3
  12. package/dist/commands/init.js +3 -3
  13. package/dist/commands/verify.js +59 -1
  14. package/dist/contracts/dag.d.ts +9 -1
  15. package/dist/evidence/graph-ontology-relation-gate.d.ts +10 -0
  16. package/dist/evidence/graph-ontology-relation-gate.js +46 -0
  17. package/dist/evidence/headroom-replay-verifier.d.ts +19 -0
  18. package/dist/evidence/headroom-replay-verifier.js +86 -0
  19. package/dist/memory/local-graph-memory-store.d.ts +75 -0
  20. package/dist/memory/local-graph-memory-store.js +570 -0
  21. package/dist/orchestration/dag.d.ts +22 -1
  22. package/dist/orchestration/evidence-gate.js +12 -0
  23. package/dist/orchestration/executor.js +111 -15
  24. package/dist/orchestration/loop-controller-headroom.d.ts +6 -0
  25. package/dist/orchestration/loop-controller-headroom.js +33 -0
  26. package/dist/orchestration/scheduler.d.ts +2 -0
  27. package/dist/orchestration/scheduler.js +3 -0
  28. package/dist/orchestration/task-graph.d.ts +17 -0
  29. package/dist/orchestration/task-graph.js +38 -0
  30. package/dist/providers/codex-cli-runner.js +17 -2
  31. package/dist/runtime/agent-runtime.d.ts +32 -3
  32. package/dist/runtime/agent-runtime.js +20 -7
  33. package/dist/runtime/authority-matrix.d.ts +23 -0
  34. package/dist/runtime/authority-matrix.js +171 -0
  35. package/dist/runtime/chat-advisory-runtime.js +3 -0
  36. package/dist/runtime/codex-cli-runtime.js +2 -0
  37. package/dist/runtime/codex-runtime.d.ts +4 -1
  38. package/dist/runtime/codex-runtime.js +34 -12
  39. package/dist/runtime/context-broker-converter.js +32 -2
  40. package/dist/runtime/context-broker.js +18 -0
  41. package/dist/runtime/contracts/evidence.d.ts +52 -0
  42. package/dist/runtime/contracts/evidence.js +138 -1
  43. package/dist/runtime/contracts/shared.d.ts +27 -0
  44. package/dist/runtime/data-retention-gate.d.ts +42 -0
  45. package/dist/runtime/data-retention-gate.js +123 -0
  46. package/dist/runtime/deepseek-runtime.d.ts +5 -1
  47. package/dist/runtime/deepseek-runtime.js +13 -7
  48. package/dist/runtime/external-cli-adapter.js +20 -7
  49. package/dist/runtime/freedomd-evidence-envelope.d.ts +57 -0
  50. package/dist/runtime/freedomd-evidence-envelope.js +110 -0
  51. package/dist/runtime/freedomd-exception.d.ts +32 -0
  52. package/dist/runtime/freedomd-exception.js +95 -0
  53. package/dist/runtime/freedomd-incidents.d.ts +23 -0
  54. package/dist/runtime/freedomd-incidents.js +103 -0
  55. package/dist/runtime/freedomd-policy.d.ts +35 -0
  56. package/dist/runtime/freedomd-policy.js +114 -0
  57. package/dist/runtime/freedomd-router.d.ts +66 -0
  58. package/dist/runtime/freedomd-router.js +433 -0
  59. package/dist/runtime/headroom-aware-loop-decision.d.ts +21 -0
  60. package/dist/runtime/headroom-aware-loop-decision.js +67 -0
  61. package/dist/runtime/headroom-loop-risk.d.ts +19 -0
  62. package/dist/runtime/headroom-loop-risk.js +43 -0
  63. package/dist/runtime/headroom-policy.d.ts +14 -1
  64. package/dist/runtime/headroom-policy.js +74 -12
  65. package/dist/runtime/kimi-api-runtime.d.ts +4 -1
  66. package/dist/runtime/kimi-api-runtime.js +35 -11
  67. package/dist/runtime/kimi-print-runtime.js +21 -0
  68. package/dist/runtime/kimi-wire-protocol-runtime.js +17 -1
  69. package/dist/runtime/local-llm-runtime.d.ts +5 -1
  70. package/dist/runtime/local-llm-runtime.js +14 -23
  71. package/dist/runtime/private-stderr.d.ts +13 -0
  72. package/dist/runtime/private-stderr.js +69 -0
  73. package/dist/runtime/prompt-envelope.d.ts +1 -1
  74. package/dist/runtime/provider-sovereignty.d.ts +81 -0
  75. package/dist/runtime/provider-sovereignty.js +285 -0
  76. package/dist/runtime/runtime-backed-task-runner.d.ts +1 -0
  77. package/dist/runtime/runtime-backed-task-runner.js +282 -10
  78. package/dist/runtime/runtime-bootstrap.d.ts +12 -0
  79. package/dist/runtime/runtime-bootstrap.js +54 -11
  80. package/dist/runtime/runtime-failure-classifier.d.ts +15 -0
  81. package/dist/runtime/runtime-failure-classifier.js +107 -0
  82. package/dist/runtime/runtime-health-probes.d.ts +30 -0
  83. package/dist/runtime/runtime-health-probes.js +102 -0
  84. package/dist/runtime/runtime-router.d.ts +6 -2
  85. package/dist/runtime/runtime-router.js +575 -53
  86. package/dist/runtime/structured-compaction.d.ts +107 -0
  87. package/dist/runtime/structured-compaction.js +414 -0
  88. package/dist/runtime/tool-dispatch-contracts.d.ts +7 -5
  89. package/dist/runtime/tool-dispatch-contracts.js +15 -4
  90. package/dist/runtime/tool-plane.d.ts +1 -1
  91. package/dist/runtime/tool-plane.js +49 -1
  92. package/dist/runtime/worker-manifest.js +1 -1
  93. package/dist/schema/evidence-bundle.schema.d.ts +8 -8
  94. package/dist/schema/proof-bundle.schema.d.ts +2 -2
  95. package/dist/util/hash.d.ts +2 -0
  96. package/dist/util/hash.js +13 -0
  97. package/dist/util/session.js +5 -4
  98. package/docs/2026-06-16/critical-issues.md +19 -0
  99. package/docs/2026-06-16/improvements.md +15 -0
  100. package/docs/2026-06-16/init-checklist.md +25 -0
  101. package/docs/2026-06-16/plan.md +20 -0
  102. package/docs/2026-06-17/critical-issues.md +19 -0
  103. package/docs/2026-06-17/improvements.md +15 -0
  104. package/docs/2026-06-17/init-checklist.md +25 -0
  105. package/docs/2026-06-17/plan.md +20 -0
  106. package/docs/ARCHITECTURE_ANALYSIS_CODEGRAPH.md +2 -1
  107. package/docs/GSTACK_MIGRATION.md +1 -1
  108. package/docs/algorithm-hardening-playbook.md +219 -0
  109. package/docs/claims.md +1 -1
  110. package/docs/getting-started.md +1 -1
  111. package/docs/native-root-runtime-hardening.md +42 -32
  112. package/docs/post-0793-hardening-roadmap.md +123 -0
  113. package/docs/provider-maturity.md +18 -16
  114. package/docs/versioning.md +3 -3
  115. package/docs/what-is-omk.md +1 -1
  116. package/package.json +8 -4
  117. package/readmeasset/.npmignore +2 -0
  118. package/readmeasset/ASSET_INDEX.md +2 -0
  119. package/readmeasset/ASSET_PROVENANCE.md +40 -20
  120. package/readmeasset/omk-adaptorch-ouroboros-supermemory.svg +1 -1
  121. package/readmeasset/omk-control-surfaces.svg +1 -1
  122. package/readmeasset/omk-core-loop.svg +1 -1
  123. package/readmeasset/omk-freedomd-control-plane.svg +59 -0
  124. package/readmeasset/omk-freedomd-control-plane.webp +0 -0
  125. package/readmeasset/omk-init-control-loop.svg +1 -1
  126. package/readmeasset/omk-logo-mark.svg +1 -1
  127. package/readmeasset/omk-parallel-subagents.svg +1 -1
  128. package/readmeasset/omk-release-assertions.svg +1 -1
@@ -7,9 +7,19 @@
7
7
  * 3. Historical evidence pass rates from graph-state memory
8
8
  * 4. Fallback chain with runtime.supports() check
9
9
  */
10
+ import { createHash } from "crypto";
10
11
  import { readFile } from "fs/promises";
11
12
  import { join } from "path";
13
+ import { maskSensitiveText } from "../util/secret-mask.js";
12
14
  import { createDecisionTraceStore } from "../evidence/decision-trace.js";
15
+ import { runtimeIsAdvisory, runtimeSatisfiesAuthority } from "./authority-matrix.js";
16
+ function isStrictGuardrailMode() {
17
+ const raw = process.env.OMK_STRICT_GUARDRAIL ?? "";
18
+ const normalized = raw.trim().toLowerCase();
19
+ return normalized === "1" || normalized === "true" || normalized === "on";
20
+ }
21
+ import { sanitizeRuntimeStderrResult } from "./private-stderr.js";
22
+ import { classifyRuntimeFailure } from "./runtime-failure-classifier.js";
13
23
  class UnsupportedRuntimeError extends Error {
14
24
  code = "RUNTIME_UNSUPPORTED_TASK";
15
25
  nodeId;
@@ -43,6 +53,8 @@ export function createRuntimeRouter(options = {}) {
43
53
  let runtimes = options.runtimes ?? [];
44
54
  const memoryPath = options.memoryPath;
45
55
  let evidenceCache;
56
+ const healthCache = new Map();
57
+ const circuitBreakers = new Map();
46
58
  function classifyIntent(capsule) {
47
59
  const text = `${capsule.nodeId} ${capsule.goal} ${capsule.task} ${capsule.system}`.toLowerCase();
48
60
  const role = capsule.node?.role?.toLowerCase() ?? "";
@@ -72,6 +84,8 @@ export function createRuntimeRouter(options = {}) {
72
84
  const raw = await readFile(filePath, "utf-8");
73
85
  const data = JSON.parse(raw);
74
86
  const nodes = (data.nodes ?? []);
87
+ const edges = (data.edges ?? []);
88
+ const nodeById = new Map(nodes.map((node) => [String(node.id ?? ""), node]));
75
89
  const entries = [];
76
90
  for (const n of nodes) {
77
91
  if (n.type !== "Evidence")
@@ -80,7 +94,7 @@ export function createRuntimeRouter(options = {}) {
80
94
  const kind = String(props.kind ?? "");
81
95
  if (kind !== "failure_pattern" && kind !== "successful_fix")
82
96
  continue;
83
- entries.push({
97
+ pushEvidenceHistory(entries, {
84
98
  runtime: String(props.runtime ?? "unknown"),
85
99
  intent: String(props.intent ?? "coding"),
86
100
  passed: kind === "successful_fix",
@@ -88,6 +102,44 @@ export function createRuntimeRouter(options = {}) {
88
102
  nodeId: String(props.sourceNodeId ?? ""),
89
103
  });
90
104
  }
105
+ // Audit graph v2 materializes ProviderRoute -> EVIDENCED_BY -> Evidence
106
+ // with turn-result-pass/fail evidence. Feed those observations back into
107
+ // routing scores so successful recent routes become preferred and failed
108
+ // runtime paths decay without relying on raw logs.
109
+ const evidenceEdgesByRoute = new Map();
110
+ for (const edge of edges) {
111
+ if (edge.type !== "EVIDENCED_BY")
112
+ continue;
113
+ const from = String(edge.from ?? "");
114
+ const to = String(edge.to ?? "");
115
+ const evidence = nodeById.get(to);
116
+ if (!evidence || evidence.type !== "Evidence")
117
+ continue;
118
+ const list = evidenceEdgesByRoute.get(from) ?? [];
119
+ list.push(evidence);
120
+ evidenceEdgesByRoute.set(from, list);
121
+ }
122
+ for (const route of nodes) {
123
+ if (route.type !== "ProviderRoute")
124
+ continue;
125
+ const props = (route.properties ?? {});
126
+ const runtime = routeRuntimeId(props);
127
+ if (!runtime)
128
+ continue;
129
+ for (const evidence of evidenceEdgesByRoute.get(String(route.id ?? "")) ?? []) {
130
+ const evidenceProps = (evidence.properties ?? {});
131
+ const pass = auditEvidencePassState(String(evidenceProps.kind ?? ""));
132
+ if (pass === undefined)
133
+ continue;
134
+ pushEvidenceHistory(entries, {
135
+ runtime,
136
+ intent: String(props.intent ?? props.role ?? "coding"),
137
+ passed: pass,
138
+ timestamp: String(evidence.updatedAt ?? evidence.createdAt ?? route.updatedAt ?? route.createdAt ?? ""),
139
+ nodeId: String(props.nodeId ?? evidenceProps.nodeId ?? ""),
140
+ });
141
+ }
142
+ }
91
143
  evidenceCache = entries;
92
144
  return entries;
93
145
  }
@@ -95,7 +147,7 @@ export function createRuntimeRouter(options = {}) {
95
147
  return [];
96
148
  }
97
149
  }
98
- function computeScores(runtime, intent, history) {
150
+ function computeScores(runtime, intent, history, health) {
99
151
  const runtimeHistory = history.filter((e) => e.runtime === runtime.id);
100
152
  const intentHistory = runtimeHistory.filter((e) => e.intent === intent);
101
153
  const totalAttempts = runtimeHistory.length;
@@ -114,24 +166,221 @@ export function createRuntimeRouter(options = {}) {
114
166
  const latencyScore = runtime.capabilities?.supportsStreaming === true || runtime.capabilities?.streaming === true
115
167
  ? 0.7
116
168
  : 0.6;
169
+ const healthScore = runtimeHealthScore(health);
117
170
  return {
118
171
  runtime: runtime.id,
119
172
  qualityScore,
120
173
  costScore,
121
174
  latencyScore,
175
+ healthScore,
122
176
  evidencePassRate,
123
177
  recentFailurePenalty,
178
+ ...(health && { healthAvailable: health.available }),
179
+ ...(health?.reason && { healthReason: health.reason }),
180
+ };
181
+ }
182
+ async function collectRuntimeHealth(candidates, probeKind = "static", taskRisk) {
183
+ const nowMs = Date.now();
184
+ const entries = await Promise.all(candidates.map(async (runtime) => {
185
+ const cached = healthCache.get(runtime.id);
186
+ if (cached?.vector?.expiresAt && Date.parse(cached.vector.expiresAt) > nowMs && probeRank(cached.vector.lastProbeKind) >= probeRank(probeKind)) {
187
+ return [runtime.id, cached];
188
+ }
189
+ if (!runtime.health) {
190
+ const now = new Date();
191
+ const health = {
192
+ runtimeId: runtime.id,
193
+ available: true,
194
+ checkedAt: now.toISOString(),
195
+ vector: {
196
+ runtimeOk: true,
197
+ authOk: true,
198
+ modelOk: true,
199
+ quotaOk: true,
200
+ rateLimitOk: true,
201
+ runtime: "pass",
202
+ auth: "pass",
203
+ model: "pass",
204
+ quota: "unknown",
205
+ rateLimit: "unknown",
206
+ lastProbeKind: "none",
207
+ checkedAt: now.toISOString(),
208
+ expiresAt: new Date(now.getTime() + 30_000).toISOString(),
209
+ },
210
+ };
211
+ healthCache.set(runtime.id, health);
212
+ return [runtime.id, health];
213
+ }
214
+ try {
215
+ const health = normalizeRuntimeHealth(await runtime.health({ probeKind, taskRisk, highRisk: probeKind !== "static" }));
216
+ healthCache.set(runtime.id, health);
217
+ return [runtime.id, health];
218
+ }
219
+ catch (err) {
220
+ const now = new Date();
221
+ const reason = maskSensitiveText(err instanceof Error ? err.message : String(err));
222
+ const health = {
223
+ runtimeId: runtime.id,
224
+ available: false,
225
+ reason,
226
+ checkedAt: now.toISOString(),
227
+ vector: {
228
+ runtimeOk: false,
229
+ authOk: true,
230
+ modelOk: true,
231
+ quotaOk: true,
232
+ rateLimitOk: true,
233
+ runtime: "fail",
234
+ auth: "unknown",
235
+ model: "unknown",
236
+ quota: "unknown",
237
+ rateLimit: "unknown",
238
+ lastProbeKind: probeKind,
239
+ checkedAt: now.toISOString(),
240
+ expiresAt: new Date(now.getTime() + 30_000).toISOString(),
241
+ },
242
+ };
243
+ healthCache.set(runtime.id, health);
244
+ return [runtime.id, health];
245
+ }
246
+ }));
247
+ return new Map(entries);
248
+ }
249
+ function requiredProbeForTask(task) {
250
+ const risk = task.safety?.risk;
251
+ if (risk === "merge")
252
+ return "live-call";
253
+ if (risk === "write" || risk === "shell" || task.capabilities.write || task.capabilities.patch || task.capabilities.shell || task.capabilities.merge) {
254
+ return "cheap-call";
255
+ }
256
+ return "static";
257
+ }
258
+ function requiredProbeForCapsule(capsule) {
259
+ const risk = capsule.node.routing?.risk;
260
+ if (risk === "merge")
261
+ return "live-call";
262
+ if (risk === "write" || risk === "shell")
263
+ return "cheap-call";
264
+ return "static";
265
+ }
266
+ function runtimeHealthy(runtime, healthMap, probeKind = "static") {
267
+ const health = healthMap.get(runtime.id);
268
+ if (!health)
269
+ return true;
270
+ if (health.available === false)
271
+ return false;
272
+ const vector = health.vector;
273
+ if (!vector)
274
+ return true;
275
+ const highRiskProbe = probeRank(probeKind) >= probeRank("cheap-call");
276
+ const hardDimensionsOk = highRiskProbe
277
+ ? statePassStrict(vector.runtime, vector.runtimeOk)
278
+ && statePassStrict(vector.auth, vector.authOk)
279
+ && statePassStrict(vector.model, vector.modelOk)
280
+ : statePassOrUnknown(vector.runtime, vector.runtimeOk)
281
+ && statePassOrUnknown(vector.auth, vector.authOk)
282
+ && statePassOrUnknown(vector.model, vector.modelOk);
283
+ return hardDimensionsOk
284
+ && statePassOrUnknown(vector.quota, vector.quotaOk)
285
+ && statePassOrUnknown(vector.rateLimit, vector.rateLimitOk);
286
+ }
287
+ function runtimeCircuitOpen(runtime) {
288
+ const state = circuitBreakers.get(runtime.id);
289
+ if (!state)
290
+ return undefined;
291
+ if (state.expiresAt <= Date.now()) {
292
+ circuitBreakers.delete(runtime.id);
293
+ return undefined;
294
+ }
295
+ return state;
296
+ }
297
+ function clearRuntimeCircuit(runtime) {
298
+ circuitBreakers.delete(runtime.id);
299
+ }
300
+ function recordRuntimeFailure(runtime, result) {
301
+ const classification = classifyRuntimeFailure({
302
+ exitCode: result.exitCode,
303
+ stdout: result.stdout,
304
+ stderr: result.stderr,
305
+ metadata: result.metadata,
306
+ });
307
+ if (classification.failureClass === "none")
308
+ return result;
309
+ const opened = maybeOpenRuntimeCircuit(runtime.id, classification);
310
+ return {
311
+ ...result,
312
+ metadata: {
313
+ ...(result.metadata ?? {}),
314
+ failureClass: classification.failureClass,
315
+ failureRetryable: classification.retryable,
316
+ failureReason: classification.reason,
317
+ ...(opened && {
318
+ circuitBreaker: {
319
+ runtimeId: opened.runtimeId,
320
+ failureClass: opened.failureClass,
321
+ retryable: opened.retryable,
322
+ failureCount: opened.failureCount,
323
+ openedAt: new Date(opened.openedAt).toISOString(),
324
+ expiresAt: new Date(opened.expiresAt).toISOString(),
325
+ reason: opened.reason,
326
+ },
327
+ }),
328
+ },
124
329
  };
125
330
  }
126
- function selectByIntent(capsule, history) {
331
+ function maybeOpenRuntimeCircuit(runtimeId, classification) {
332
+ if (!classification.circuitBreaker || classification.cooldownMs <= 0)
333
+ return undefined;
334
+ const now = Date.now();
335
+ const previous = circuitBreakers.get(runtimeId);
336
+ const state = {
337
+ runtimeId,
338
+ failureClass: classification.failureClass,
339
+ retryable: classification.retryable,
340
+ openedAt: now,
341
+ expiresAt: now + classification.cooldownMs,
342
+ failureCount: (previous?.failureCount ?? 0) + 1,
343
+ reason: classification.reason,
344
+ };
345
+ circuitBreakers.set(runtimeId, state);
346
+ return state;
347
+ }
348
+ function circuitOpenResult(runtime, state, fallbackChain, intent) {
349
+ return {
350
+ success: false,
351
+ exitCode: 78,
352
+ stdout: "",
353
+ stderr: `Runtime ${runtime.id} skipped by circuit breaker: ${state.failureClass}`,
354
+ metadata: {
355
+ runtime: runtime.id,
356
+ selectedRuntime: runtime.id,
357
+ intent,
358
+ fallbackChain: fallbackChain.map((candidate) => candidate.id),
359
+ failureClass: state.failureClass,
360
+ failureRetryable: state.retryable,
361
+ circuitBreakerOpen: true,
362
+ circuitBreaker: {
363
+ runtimeId: state.runtimeId,
364
+ failureClass: state.failureClass,
365
+ retryable: state.retryable,
366
+ failureCount: state.failureCount,
367
+ openedAt: new Date(state.openedAt).toISOString(),
368
+ expiresAt: new Date(state.expiresAt).toISOString(),
369
+ reason: state.reason,
370
+ },
371
+ },
372
+ };
373
+ }
374
+ function selectByIntent(capsule, history, healthMap, probeKind = "static") {
127
375
  const intent = classifyIntent(capsule);
128
376
  const sorted = [...runtimes].sort((a, b) => b.priority - a.priority);
129
377
  const supporting = sorted.filter((runtime) => runtime.supports(capsule) &&
130
- runtimeAllowedByLegacyPolicy(runtime, { preferredProviders: [], fallbackChain: options.fallbackChain }));
378
+ runtimeAllowedByLegacyPolicy(runtime, { preferredProviders: [], fallbackChain: options.fallbackChain }) &&
379
+ (healthMap ? runtimeHealthy(runtime, healthMap, probeKind) : true));
131
380
  if (supporting.length === 0) {
132
381
  throw new UnsupportedRuntimeError(capsule, detectedRuntimeLabels(sorted));
133
382
  }
134
- const scores = supporting.map((r) => computeScores(r, intent, history));
383
+ const scores = supporting.map((r) => computeScores(r, intent, history, healthMap?.get(r.id)));
135
384
  const scored = supporting.map((r, i) => ({
136
385
  runtime: r,
137
386
  score: scores[i],
@@ -146,6 +395,7 @@ export function createRuntimeRouter(options = {}) {
146
395
  `intent=${intent}`,
147
396
  `quality=${bestScore.qualityScore.toFixed(2)}`,
148
397
  `evidencePassRate=${bestScore.evidencePassRate.toFixed(2)}`,
398
+ `health=${bestScore.healthScore.toFixed(2)}`,
149
399
  `recentPenalty=${bestScore.recentFailurePenalty.toFixed(2)}`,
150
400
  ].join("; ");
151
401
  return { runtime: primary, reason, fallbacks, intent, scores };
@@ -178,9 +428,11 @@ export function createRuntimeRouter(options = {}) {
178
428
  }
179
429
  async function runNode(capsule, signal) {
180
430
  const history = await loadEvidenceHistory();
431
+ const probeKind = requiredProbeForCapsule(capsule);
432
+ const healthMap = await collectRuntimeHealth(runtimes, probeKind, capsule.node.routing?.risk);
181
433
  let decision;
182
434
  try {
183
- decision = selectByIntent(capsule, history);
435
+ decision = selectByIntent(capsule, history, healthMap, probeKind);
184
436
  }
185
437
  catch (err) {
186
438
  if (err instanceof UnsupportedRuntimeError) {
@@ -219,30 +471,38 @@ export function createRuntimeRouter(options = {}) {
219
471
  metadata: { runtime: runtime.id, aborted: true },
220
472
  };
221
473
  }
474
+ const openCircuit = runtimeCircuitOpen(runtime);
475
+ if (openCircuit) {
476
+ lastError = circuitOpenResult(runtime, openCircuit, allCandidates, decision.intent);
477
+ continue;
478
+ }
222
479
  try {
223
480
  const result = await runtime.runNode(capsule, signal);
224
- if (result.success) {
225
- return {
226
- ...result,
227
- metadata: {
228
- ...result.metadata,
229
- selectedRuntime: runtime.id,
230
- intent: decision.intent,
231
- fallbackChain: allCandidates.map((r) => r.id),
232
- scores: decision.scores,
233
- },
234
- };
481
+ const routedResult = sanitizeAgentRunResult({
482
+ ...result,
483
+ metadata: {
484
+ ...result.metadata,
485
+ selectedRuntime: runtime.id,
486
+ intent: decision.intent,
487
+ fallbackChain: allCandidates.map((r) => r.id),
488
+ scores: decision.scores,
489
+ },
490
+ }, stderrArtifactOptions({ runId: capsule.runId, nodeId: capsule.nodeId, runtimeId: runtime.id, root: process.cwd(), env: process.env }));
491
+ if (routedResult.success) {
492
+ clearRuntimeCircuit(runtime);
493
+ return routedResult;
235
494
  }
236
- lastError = result;
495
+ lastError = recordRuntimeFailure(runtime, routedResult);
237
496
  }
238
497
  catch (err) {
239
- lastError = {
498
+ const error = maskSensitiveText(String(err));
499
+ lastError = recordRuntimeFailure(runtime, sanitizeAgentRunResult({
240
500
  success: false,
241
501
  exitCode: 1,
242
502
  stdout: "",
243
- stderr: String(err),
244
- metadata: { runtime: runtime.id, error: String(err) },
245
- };
503
+ stderr: error,
504
+ metadata: { runtime: runtime.id, error },
505
+ }, stderrArtifactOptions({ runId: capsule.runId, nodeId: capsule.nodeId, runtimeId: runtime.id, root: process.cwd(), env: process.env })));
246
506
  }
247
507
  }
248
508
  return (lastError ?? {
@@ -255,9 +515,11 @@ export function createRuntimeRouter(options = {}) {
255
515
  }
256
516
  async function executeTask(task, capsule, signal) {
257
517
  const history = await loadEvidenceHistory();
518
+ const probeKind = requiredProbeForTask(task);
519
+ const healthMap = await collectRuntimeHealth(runtimes, probeKind, task.safety?.risk);
258
520
  let decision;
259
521
  try {
260
- decision = selectByIntent(capsule, history);
522
+ decision = selectByIntent(capsule, history, healthMap, probeKind);
261
523
  }
262
524
  catch (err) {
263
525
  if (err instanceof UnsupportedRuntimeError) {
@@ -266,8 +528,39 @@ export function createRuntimeRouter(options = {}) {
266
528
  throw err;
267
529
  }
268
530
  const allCandidates = [decision.runtime, ...decision.fallbacks];
531
+ // Record runtime-router decision trace for executeTask, the native runtime pipeline path.
532
+ const runId = capsule.runId;
533
+ const attemptNumber = (capsule.node?.attempts?.length ?? 0) + 1;
534
+ const attemptId = `${capsule.nodeId}__${attemptNumber}`;
535
+ if (runId && !runId.startsWith("local-")) {
536
+ const traceStore = createDecisionTraceStore();
537
+ traceStore.record(runId, {
538
+ component: "runtime-router",
539
+ inputSummary: `node=${capsule.nodeId} intent=${decision.intent} path=executeTask`,
540
+ outputDecision: `runtime=${decision.runtime.id} fallbacks=${decision.fallbacks.map((r) => r.id).join(",")}`,
541
+ reason: decision.reason,
542
+ scores: decision.scores.reduce((acc, s) => {
543
+ acc[s.runtime] = computeComposite(s, allCandidates.find((candidate) => candidate.id === s.runtime) ?? decision.runtime, decision.intent);
544
+ return acc;
545
+ }, {}),
546
+ nodeId: capsule.nodeId,
547
+ attemptId,
548
+ });
549
+ }
550
+ const executionCandidates = allCandidates.filter((runtime) => {
551
+ const boundary = runtimeSatisfiesAdvisoryBoundary(runtime, task);
552
+ if (!boundary.ok) {
553
+ if (decision.reason && !decision.reason.includes("advisory boundary")) {
554
+ decision = {
555
+ ...decision,
556
+ reason: `${decision.reason}; advisory boundary excluded ${runtime.id}`,
557
+ };
558
+ }
559
+ }
560
+ return boundary.ok;
561
+ });
269
562
  let lastError;
270
- for (const runtime of allCandidates) {
563
+ for (const runtime of executionCandidates) {
271
564
  if (signal.aborted) {
272
565
  return {
273
566
  success: false,
@@ -277,34 +570,54 @@ export function createRuntimeRouter(options = {}) {
277
570
  metadata: { runtime: runtime.id, selectedRuntime: runtime.id, aborted: true },
278
571
  };
279
572
  }
573
+ const openCircuit = runtimeCircuitOpen(runtime);
574
+ if (openCircuit) {
575
+ lastError = circuitOpenResult(runtime, openCircuit, executionCandidates, decision.intent);
576
+ continue;
577
+ }
280
578
  try {
281
579
  const result = runtime.execute
282
580
  ? agentResultToRunResult(await runtime.execute(task), runtime.id)
283
581
  : await runtime.runNode(capsule, signal);
284
- const routedResult = {
582
+ const routedResult = sanitizeAgentRunResult({
285
583
  ...result,
286
584
  metadata: {
287
585
  ...result.metadata,
288
586
  selectedRuntime: runtime.id,
289
587
  intent: decision.intent,
290
- fallbackChain: allCandidates.map((r) => r.id),
588
+ fallbackChain: executionCandidates.map((r) => r.id),
291
589
  scores: decision.scores,
292
590
  },
293
- };
294
- if (routedResult.success)
591
+ }, stderrArtifactOptions({ runId: task.context.runId, nodeId: task.context.nodeId, runtimeId: runtime.id, root: task.context.cwd, env: task.context.env ?? process.env }));
592
+ if (routedResult.success) {
593
+ clearRuntimeCircuit(runtime);
295
594
  return routedResult;
296
- lastError = routedResult;
595
+ }
596
+ lastError = recordRuntimeFailure(runtime, routedResult);
297
597
  }
298
598
  catch (err) {
299
- lastError = {
599
+ const error = maskSensitiveText(String(err));
600
+ lastError = recordRuntimeFailure(runtime, sanitizeAgentRunResult({
300
601
  success: false,
301
602
  exitCode: 1,
302
603
  stdout: "",
303
- stderr: String(err),
304
- metadata: { runtime: runtime.id, selectedRuntime: runtime.id, error: String(err) },
305
- };
604
+ stderr: error,
605
+ metadata: { runtime: runtime.id, selectedRuntime: runtime.id, error },
606
+ }, stderrArtifactOptions({ runId: task.context.runId, nodeId: task.context.nodeId, runtimeId: runtime.id, root: task.context.cwd, env: task.context.env ?? process.env })));
306
607
  }
307
608
  }
609
+ if (executionCandidates.length === 0 && allCandidates.length > 0) {
610
+ const advisoryFailures = allCandidates
611
+ .map((runtime) => runtimeSatisfiesAdvisoryBoundary(runtime, task))
612
+ .filter((boundary) => !boundary.ok);
613
+ return {
614
+ success: false,
615
+ exitCode: 78,
616
+ stdout: "",
617
+ stderr: advisoryFailures.map((boundary) => boundary.reason).join("\n") || "All candidate runtimes are advisory-only for this task",
618
+ metadata: { authorityMode: "advisory", advisoryBoundaryFailures: advisoryFailures.map((boundary) => boundary.reason) },
619
+ };
620
+ }
308
621
  return (lastError ?? {
309
622
  success: false,
310
623
  exitCode: 1,
@@ -332,15 +645,48 @@ export function createRuntimeRouter(options = {}) {
332
645
  if (preferredProviders.length > 0) {
333
646
  candidates = candidates.filter((runtime) => preferredProviders.some((provider) => runtimeMatchesProvider(runtime, provider)));
334
647
  }
648
+ const probeKind = requiredProbeForTask(task);
649
+ const healthMap = await collectRuntimeHealth(candidates, probeKind, task.safety?.risk);
650
+ candidates = candidates.filter((runtime) => runtimeHealthy(runtime, healthMap, probeKind));
651
+ const advisoryBoundaryFailures = [];
652
+ const nonAdvisoryCandidates = candidates.filter((runtime) => {
653
+ const boundary = runtimeSatisfiesAdvisoryBoundary(runtime, task);
654
+ if (!boundary.ok)
655
+ advisoryBoundaryFailures.push(`${runtime.id}: ${boundary.reason}`);
656
+ return boundary.ok;
657
+ });
658
+ if (nonAdvisoryCandidates.length > 0) {
659
+ candidates = nonAdvisoryCandidates;
660
+ }
661
+ else if (advisoryBoundaryFailures.length > 0) {
662
+ return {
663
+ success: false,
664
+ exitCode: 78,
665
+ stdout: "",
666
+ stderr: `Advisory runtime boundary blocked execution:\n${advisoryBoundaryFailures.join("\n")}`,
667
+ metadata: { authorityMode: "advisory", advisoryBoundaryFailures },
668
+ };
669
+ }
335
670
  if (candidates.length === 0) {
336
671
  const mcpBlocked = task.capabilities.mcp || task.capabilities.toolCalling;
337
672
  if (mcpBlocked && runtimes.length > 0) {
338
673
  const runtime = runtimes[0];
339
674
  throw new Error(`Node requires MCP authority. ${runtimeDisplayName(runtime)} runtime does not receive OMK MCP authority.`);
340
675
  }
676
+ if (advisoryBoundaryFailures.length > 0) {
677
+ return {
678
+ success: false,
679
+ exitCode: 78,
680
+ stdout: "",
681
+ stderr: `Advisory runtime boundary blocked execution:\n${advisoryBoundaryFailures.join("\n")}`,
682
+ metadata: { authorityMode: "advisory", advisoryBoundaryFailures },
683
+ };
684
+ }
341
685
  throw new UnsupportedRuntimeError(capsule, detectedRuntimeLabels(runtimes));
342
686
  }
343
687
  const preferredRuntimeIds = task.providerPolicy?.fallbackChain ?? options.fallbackChain ?? [];
688
+ const history = await loadEvidenceHistory();
689
+ const scoreByRuntime = new Map(candidates.map((runtime) => [runtime, computeScores(runtime, intent, history, healthMap.get(runtime.id))]));
344
690
  const capabilityScoreCache = buildCapabilityScoreCache(candidates, intent);
345
691
  candidates.sort((a, b) => {
346
692
  const runtimeDelta = runtimePreferenceIndex(a.id, preferredRuntimeIds)
@@ -353,7 +699,9 @@ export function createRuntimeRouter(options = {}) {
353
699
  if (providerDelta !== 0)
354
700
  return providerDelta;
355
701
  }
356
- return compareRuntimeCandidates(a, b, intent, capabilityScoreCache);
702
+ const aScore = scoreByRuntime.get(a) ?? computeScores(a, intent, history, healthMap.get(a.id));
703
+ const bScore = scoreByRuntime.get(b) ?? computeScores(b, intent, history, healthMap.get(b.id));
704
+ return compareScoredRuntimes({ runtime: a, composite: computeComposite(aScore, a, intent) }, { runtime: b, composite: computeComposite(bScore, b, intent) }, intent, capabilityScoreCache);
357
705
  });
358
706
  let lastError;
359
707
  for (const runtime of candidates) {
@@ -366,31 +714,40 @@ export function createRuntimeRouter(options = {}) {
366
714
  metadata: { runtime: runtime.id, selectedRuntime: runtime.id, aborted: true },
367
715
  };
368
716
  }
717
+ const openCircuit = runtimeCircuitOpen(runtime);
718
+ if (openCircuit) {
719
+ lastError = circuitOpenResult(runtime, openCircuit, candidates, intent);
720
+ continue;
721
+ }
369
722
  try {
370
723
  const result = runtime.execute
371
724
  ? agentResultToRunResult(await runtime.execute(task), runtime.id)
372
725
  : await runtime.runNode(capsule, signal);
373
- const routedResult = {
726
+ const routedResult = sanitizeAgentRunResult({
374
727
  ...result,
375
728
  metadata: {
376
729
  ...result.metadata,
377
730
  selectedRuntime: runtime.id,
378
731
  intent,
379
732
  fallbackChain: candidates.map((candidate) => candidate.id),
733
+ scores: candidates.map((candidate) => scoreByRuntime.get(candidate)).filter((score) => score !== undefined),
380
734
  },
381
- };
382
- if (routedResult.success)
735
+ }, stderrArtifactOptions({ runId: task.context.runId, nodeId: task.context.nodeId, runtimeId: runtime.id, root: task.context.cwd, env: task.context.env ?? process.env }));
736
+ if (routedResult.success) {
737
+ clearRuntimeCircuit(runtime);
383
738
  return routedResult;
384
- lastError = routedResult;
739
+ }
740
+ lastError = recordRuntimeFailure(runtime, routedResult);
385
741
  }
386
742
  catch (err) {
387
- lastError = {
743
+ const error = maskSensitiveText(String(err));
744
+ lastError = recordRuntimeFailure(runtime, sanitizeAgentRunResult({
388
745
  success: false,
389
746
  exitCode: 1,
390
747
  stdout: "",
391
- stderr: String(err),
392
- metadata: { runtime: runtime.id, selectedRuntime: runtime.id, error: String(err) },
393
- };
748
+ stderr: error,
749
+ metadata: { runtime: runtime.id, selectedRuntime: runtime.id, error },
750
+ }, stderrArtifactOptions({ runId: task.context.runId, nodeId: task.context.nodeId, runtimeId: runtime.id, root: task.context.cwd, env: task.context.env ?? process.env })));
394
751
  }
395
752
  }
396
753
  return lastError ?? {
@@ -423,20 +780,30 @@ export function createRuntimeRouter(options = {}) {
423
780
  }
424
781
  function capsuleFromTask(task) {
425
782
  const nodeId = task.context.nodeId || "runtime-task";
783
+ const promptHash = createHash("sha256").update(task.prompt).digest("hex");
784
+ const publicLabel = `runtime task:${promptHash.slice(0, 12)}`;
426
785
  return {
427
786
  runId: task.context.runId || "local-runtime-router",
428
787
  nodeId,
429
- goal: task.context.goal || task.prompt,
788
+ goal: task.context.goal || publicLabel,
430
789
  task: task.prompt,
431
790
  system: task.context.system || "",
432
791
  node: {
433
792
  id: nodeId,
434
- name: task.prompt,
793
+ name: publicLabel,
435
794
  role: task.context.role || "coder",
436
795
  dependsOn: [],
437
796
  status: "running",
438
797
  retries: 0,
439
798
  maxRetries: 1,
799
+ routing: {
800
+ promptHash,
801
+ promptMode: "synthetic-private",
802
+ risk: task.safety?.risk,
803
+ approvalPolicy: task.safety?.approvalPolicy,
804
+ sandboxMode: task.safety?.sandboxMode,
805
+ evidenceRequired: task.safety?.evidenceRequired,
806
+ },
440
807
  },
441
808
  dependencySummaries: [],
442
809
  evidenceRequirements: [],
@@ -446,6 +813,25 @@ function capsuleFromTask(task) {
446
813
  budget: { maxInputTokens: 0, compression: "small" },
447
814
  };
448
815
  }
816
+ function pushEvidenceHistory(entries, entry) {
817
+ if (!entry.runtime || entry.runtime === "unknown")
818
+ return;
819
+ entries.push(entry);
820
+ }
821
+ function routeRuntimeId(props) {
822
+ const selectedRuntime = String(props.selectedRuntime ?? "").trim();
823
+ if (selectedRuntime && selectedRuntime !== "unknown")
824
+ return selectedRuntime;
825
+ const provider = String(props.provider ?? "").trim();
826
+ return provider && provider !== "unknown" ? provider : undefined;
827
+ }
828
+ function auditEvidencePassState(kind) {
829
+ if (kind === "turn-result-pass" || kind === "command-pass" || kind === "test-pass")
830
+ return true;
831
+ if (kind === "turn-result-fail" || kind === "command-fail" || kind === "test-fail")
832
+ return false;
833
+ return undefined;
834
+ }
449
835
  function detectedRuntimeLabels(runtimes) {
450
836
  return [...new Set(runtimes.map((runtime) => isLegacyRuntime(runtime) ? "legacy-external-runtime" : runtime.id))];
451
837
  }
@@ -472,6 +858,37 @@ function runtimeSatisfiesTask(runtime, task) {
472
858
  return false;
473
859
  return true;
474
860
  }
861
+ /**
862
+ * Detect advisory-only runtimes that claim broad capabilities but are not allowed
863
+ * to execute write/shell/merge/patch/tool-calling authority. If a non-read-only
864
+ * task reaches such a runtime, reroute it to the first non-advisory fallback.
865
+ */
866
+ function runtimeSatisfiesAdvisoryBoundary(runtime, task) {
867
+ const authority = runtimeSatisfiesAuthority(runtime, task);
868
+ if (!authority.ok) {
869
+ return { ok: false, reason: authority.reason };
870
+ }
871
+ if (!runtimeIsAdvisory(runtime))
872
+ return { ok: true };
873
+ const required = task.capabilities;
874
+ if (required.write ||
875
+ required.patch ||
876
+ required.shell ||
877
+ required.merge ||
878
+ required.mcp) {
879
+ return {
880
+ ok: false,
881
+ reason: `advisory runtime ${runtime.id} cannot execute write/shell/merge/patch/MCP authority`,
882
+ };
883
+ }
884
+ if (required.toolCalling && isStrictGuardrailMode()) {
885
+ return {
886
+ ok: false,
887
+ reason: `advisory runtime ${runtime.id} cannot execute tool-calling authority unless agent-freedom mode is enabled`,
888
+ };
889
+ }
890
+ return { ok: true };
891
+ }
475
892
  function runtimeMatchesProvider(runtime, provider) {
476
893
  const normalizedProvider = normalizeRuntimeToken(provider);
477
894
  if (normalizedProvider.length === 0)
@@ -556,7 +973,7 @@ function unsupportedRuntimeResult(err) {
556
973
  }
557
974
  function agentResultToRunResult(result, runtimeId) {
558
975
  const success = result.exitCode === 0;
559
- return {
976
+ return sanitizeAgentRunResult({
560
977
  success,
561
978
  exitCode: result.exitCode,
562
979
  stdout: result.output,
@@ -568,16 +985,121 @@ function agentResultToRunResult(result, runtimeId) {
568
985
  },
569
986
  tokenUsage: result.tokenUsage,
570
987
  toolCalls: result.toolCalls,
571
- };
988
+ });
989
+ }
990
+ function stderrArtifactOptions(input) {
991
+ return input;
992
+ }
993
+ function sanitizeAgentRunResult(result, options = {}) {
994
+ return sanitizeRuntimeStderrResult(result, options);
572
995
  }
996
+ const NORMALIZED_COMPOSITE_WEIGHTS = {
997
+ quality: 0.28,
998
+ evidence: 0.18,
999
+ health: 0.16,
1000
+ cost: 0.10,
1001
+ latency: 0.08,
1002
+ recentSuccess: 0.10,
1003
+ capability: 0.07,
1004
+ priority: 0.03,
1005
+ };
573
1006
  function computeComposite(score, runtime, intent) {
574
- return (0.35 * score.qualityScore +
575
- 0.25 * score.evidencePassRate +
576
- 0.15 * score.costScore +
577
- 0.1 * score.latencyScore +
578
- 0.15 * (1 - score.recentFailurePenalty) +
579
- 0.15 * computeRuntimeCapabilityScore(runtime, intent) +
580
- 0.05 * runtimePriorityScore(runtime));
1007
+ return (NORMALIZED_COMPOSITE_WEIGHTS.quality * score.qualityScore +
1008
+ NORMALIZED_COMPOSITE_WEIGHTS.evidence * score.evidencePassRate +
1009
+ NORMALIZED_COMPOSITE_WEIGHTS.health * score.healthScore +
1010
+ NORMALIZED_COMPOSITE_WEIGHTS.cost * score.costScore +
1011
+ NORMALIZED_COMPOSITE_WEIGHTS.latency * score.latencyScore +
1012
+ NORMALIZED_COMPOSITE_WEIGHTS.recentSuccess * (1 - score.recentFailurePenalty) +
1013
+ NORMALIZED_COMPOSITE_WEIGHTS.capability * computeRuntimeCapabilityScore(runtime, intent) +
1014
+ NORMALIZED_COMPOSITE_WEIGHTS.priority * runtimePriorityScore(runtime));
1015
+ }
1016
+ function normalizeRuntimeHealth(health) {
1017
+ const now = new Date();
1018
+ const checkedAt = health.checkedAt ?? now.toISOString();
1019
+ const vector = health.vector;
1020
+ if (!vector) {
1021
+ return {
1022
+ ...health,
1023
+ vector: {
1024
+ runtimeOk: health.available,
1025
+ authOk: health.available,
1026
+ modelOk: health.available,
1027
+ quotaOk: true,
1028
+ rateLimitOk: true,
1029
+ runtime: health.available ? "pass" : "fail",
1030
+ auth: health.available ? "pass" : "fail",
1031
+ model: health.available ? "pass" : "fail",
1032
+ quota: "unknown",
1033
+ rateLimit: "unknown",
1034
+ lastProbeKind: "none",
1035
+ checkedAt,
1036
+ expiresAt: new Date(Date.parse(checkedAt) + 30_000).toISOString(),
1037
+ },
1038
+ };
1039
+ }
1040
+ return {
1041
+ ...health,
1042
+ vector: {
1043
+ ...vector,
1044
+ runtime: vector.runtime ?? legacyBoolToState(vector.runtimeOk),
1045
+ auth: vector.auth ?? legacyBoolToState(vector.authOk),
1046
+ model: vector.model ?? legacyBoolToState(vector.modelOk),
1047
+ quota: vector.quota ?? legacyBoolToState(vector.quotaOk),
1048
+ rateLimit: vector.rateLimit ?? legacyBoolToState(vector.rateLimitOk),
1049
+ lastProbeKind: vector.lastProbeKind ?? "static",
1050
+ checkedAt: vector.checkedAt ?? checkedAt,
1051
+ expiresAt: vector.expiresAt ?? new Date(Date.parse(checkedAt) + 60_000).toISOString(),
1052
+ },
1053
+ };
1054
+ }
1055
+ function probeRank(kind) {
1056
+ switch (kind) {
1057
+ case "live-call":
1058
+ return 3;
1059
+ case "cheap-call":
1060
+ return 2;
1061
+ case "static":
1062
+ return 1;
1063
+ default:
1064
+ return 0;
1065
+ }
1066
+ }
1067
+ function legacyBoolToState(value) {
1068
+ if (value === true)
1069
+ return "pass";
1070
+ if (value === false)
1071
+ return "fail";
1072
+ return "unknown";
1073
+ }
1074
+ function statePassOrUnknown(state, legacy) {
1075
+ const normalized = state ?? legacyBoolToState(legacy);
1076
+ return normalized !== "fail";
1077
+ }
1078
+ function statePassStrict(state, legacy) {
1079
+ const normalized = state ?? legacyBoolToState(legacy);
1080
+ return normalized === "pass";
1081
+ }
1082
+ function healthStatePenalty(state, legacy, failWeight, unknownWeight) {
1083
+ const normalized = state ?? legacyBoolToState(legacy);
1084
+ if (normalized === "fail")
1085
+ return failWeight;
1086
+ if (normalized === "unknown")
1087
+ return unknownWeight;
1088
+ return 0;
1089
+ }
1090
+ function runtimeHealthScore(health) {
1091
+ if (!health)
1092
+ return 1;
1093
+ const vector = health.vector;
1094
+ if (!vector)
1095
+ return health.available ? 1 : 0;
1096
+ let score = 1;
1097
+ score -= healthStatePenalty(vector.runtime, vector.runtimeOk, 0.25, 0.08);
1098
+ score -= healthStatePenalty(vector.auth, vector.authOk, 0.25, 0.08);
1099
+ score -= healthStatePenalty(vector.model, vector.modelOk, 0.2, 0.05);
1100
+ score -= healthStatePenalty(vector.quota, vector.quotaOk, 0.2, 0.05);
1101
+ score -= healthStatePenalty(vector.rateLimit, vector.rateLimitOk, 0.1, 0.03);
1102
+ return Math.max(0, score);
581
1103
  }
582
1104
  function compareScoredRuntimes(a, b, intent, scoreCache) {
583
1105
  const compositeDelta = b.composite - a.composite;