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
@@ -0,0 +1,171 @@
1
+ export const RUNTIME_AUTHORITY_MATRIX = [
2
+ {
3
+ providerId: "kimi",
4
+ runtimeMode: "api",
5
+ authorities: ["read", "review", "vision", "toolCalling"],
6
+ advisory: true,
7
+ notes: "Moonshot/Kimi API is advisory; no direct workspace write/shell/merge authority.",
8
+ },
9
+ {
10
+ providerId: "kimi",
11
+ runtimeMode: "wire",
12
+ authorities: ["read", "review", "write", "patch", "vision", "toolCalling"],
13
+ advisory: false,
14
+ notes: "Kimi wire/CLI compatibility path can edit through the OMK-controlled adapter, but shell/merge still require explicit authority.",
15
+ },
16
+ {
17
+ providerId: "kimi",
18
+ runtimeMode: "cli",
19
+ authorities: ["read", "review", "write", "patch", "vision", "toolCalling"],
20
+ advisory: false,
21
+ notes: "Legacy Kimi CLI compatibility path is available only when explicitly requested; shell/merge remain separately gated.",
22
+ },
23
+ {
24
+ providerId: "mimo",
25
+ runtimeMode: "api",
26
+ authorities: ["read", "review"],
27
+ advisory: true,
28
+ notes: "MiMo API is read/review/thinking only until a write-capable runtime-mode contract exists.",
29
+ },
30
+ {
31
+ providerId: "deepseek",
32
+ runtimeMode: "api",
33
+ authorities: ["read", "review"],
34
+ advisory: true,
35
+ },
36
+ {
37
+ providerId: "glm",
38
+ runtimeMode: "api",
39
+ authorities: ["read", "review"],
40
+ advisory: true,
41
+ },
42
+ {
43
+ providerId: "codex",
44
+ runtimeMode: "cli",
45
+ authorities: ["read", "review", "write", "patch", "shell"],
46
+ advisory: false,
47
+ notes: "Codex CLI authority is bounded by OMK approval/sandbox policy; merge remains withheld.",
48
+ },
49
+ {
50
+ providerId: "opencode",
51
+ runtimeMode: "cli",
52
+ authorities: ["read", "review", "write", "patch", "shell"],
53
+ advisory: false,
54
+ },
55
+ {
56
+ providerId: "commandcode",
57
+ runtimeMode: "cli",
58
+ authorities: ["read", "review", "write", "patch", "shell"],
59
+ advisory: false,
60
+ },
61
+ {
62
+ providerId: "local-llm",
63
+ runtimeMode: "api",
64
+ authorities: ["read", "review"],
65
+ advisory: true,
66
+ },
67
+ {
68
+ providerId: "openrouter",
69
+ runtimeMode: "api",
70
+ authorities: ["read", "review", "vision", "toolCalling"],
71
+ advisory: true,
72
+ notes: "OpenRouter API is advisory unless paired with an OMK-owned write/shell adapter.",
73
+ },
74
+ {
75
+ providerId: "qwen",
76
+ runtimeMode: "api",
77
+ authorities: ["read", "review", "vision", "toolCalling"],
78
+ advisory: true,
79
+ notes: "Qwen API is advisory unless paired with an OMK-owned write/shell adapter.",
80
+ },
81
+ ];
82
+ export function runtimeProviderId(runtime) {
83
+ return runtime.providerId ?? runtime.id.split("-")[0] ?? runtime.id;
84
+ }
85
+ export function runtimeModeOf(runtime) {
86
+ if (runtime.runtimeMode)
87
+ return runtime.runtimeMode;
88
+ if (runtime.kind)
89
+ return runtime.kind;
90
+ const suffix = runtime.id.split("-").slice(1).join("-");
91
+ if (suffix === "api" || suffix === "cli" || suffix === "wire")
92
+ return suffix;
93
+ return "api";
94
+ }
95
+ export function getRuntimeAuthorityEntry(runtime) {
96
+ const providerId = runtimeProviderId(runtime);
97
+ const runtimeMode = runtimeModeOf(runtime);
98
+ return RUNTIME_AUTHORITY_MATRIX.find((entry) => entry.providerId === providerId && entry.runtimeMode === runtimeMode);
99
+ }
100
+ export function authoritiesForRuntime(runtime) {
101
+ const entry = getRuntimeAuthorityEntry(runtime);
102
+ const caps = runtime.capabilities;
103
+ if (entry) {
104
+ const granted = new Set(entry.authorities);
105
+ // Provider/mode entries remain the source of truth for write/shell/merge.
106
+ // Add only explicitly declared auxiliary capabilities so test/fake runtimes
107
+ // and future adapters can expose MCP/tool contracts without broadening
108
+ // destructive authority by provider name alone.
109
+ if (caps?.mcp === true)
110
+ granted.add("mcp");
111
+ if (caps?.vision === true)
112
+ granted.add("vision");
113
+ if (caps?.toolCalling === true || caps?.supportsToolCalling === true)
114
+ granted.add("toolCalling");
115
+ return [...granted];
116
+ }
117
+ if (!caps)
118
+ return ["read"];
119
+ const derived = [];
120
+ for (const op of ["read", "review", "write", "patch", "shell", "mcp", "merge", "vision"]) {
121
+ if (caps[op] === true)
122
+ derived.push(op);
123
+ }
124
+ if (caps.toolCalling === true || caps.supportsToolCalling === true)
125
+ derived.push("toolCalling");
126
+ return derived.length > 0 ? derived : ["read"];
127
+ }
128
+ export function runtimeIsAdvisory(runtime) {
129
+ const entry = getRuntimeAuthorityEntry(runtime);
130
+ if (entry)
131
+ return entry.advisory;
132
+ return runtime.capabilities?.advisory === true;
133
+ }
134
+ export function requiredAuthorityForTask(task) {
135
+ const required = ["read"];
136
+ const caps = task.capabilities;
137
+ if (caps.review)
138
+ required.push("review");
139
+ if (caps.write)
140
+ required.push("write");
141
+ if (caps.patch)
142
+ required.push("patch");
143
+ if (caps.shell)
144
+ required.push("shell");
145
+ if (caps.mcp)
146
+ required.push("mcp");
147
+ if (caps.merge)
148
+ required.push("merge");
149
+ if (caps.vision)
150
+ required.push("vision");
151
+ if (caps.toolCalling)
152
+ required.push("toolCalling");
153
+ return [...new Set(required)];
154
+ }
155
+ export function runtimeSatisfiesAuthority(runtime, task) {
156
+ const granted = new Set(authoritiesForRuntime(runtime));
157
+ const required = requiredAuthorityForTask(task);
158
+ const missing = required.filter((op) => !granted.has(op));
159
+ if (missing.length === 0)
160
+ return { ok: true, missing: [] };
161
+ return {
162
+ ok: false,
163
+ missing,
164
+ reason: `runtime ${runtime.id} (${runtimeProviderId(runtime)}:${runtimeModeOf(runtime)}) lacks required authority: ${missing.join(", ")}`,
165
+ };
166
+ }
167
+ export function authorityCapableProviderIds(required) {
168
+ return [...new Set(RUNTIME_AUTHORITY_MATRIX
169
+ .filter((entry) => required.every((op) => entry.authorities.includes(op)))
170
+ .map((entry) => entry.providerId))];
171
+ }
@@ -2,6 +2,9 @@ import { execSync } from "child_process";
2
2
  export function createChatAdvisoryRuntime() {
3
3
  return {
4
4
  id: "omk-advisory",
5
+ providerId: "omk",
6
+ runtimeMode: "local",
7
+ kind: "local",
5
8
  priority: 0,
6
9
  supports: () => true,
7
10
  async runNode(_capsule, _signal) {
@@ -6,6 +6,8 @@ export function createCodexCliRuntime(options) {
6
6
  const runner = createCodexCliAdvisoryTaskRunner(options);
7
7
  return {
8
8
  id: "codex-cli",
9
+ providerId: "codex",
10
+ runtimeMode: "cli",
9
11
  displayName: "Codex CLI",
10
12
  kind: "cli",
11
13
  priority: 60,
@@ -4,6 +4,7 @@
4
4
  * Spawns the `codex` CLI subprocess and bridges AgentTask / AgentResult.
5
5
  */
6
6
  import type { AgentRuntime, AgentRunResult, AgentResult, AgentTask, RuntimeCapabilities, RuntimeHealth } from "./agent-runtime.js";
7
+ import type { RuntimeHealthProbeRequest } from "./contracts/shared.js";
7
8
  import type { ContextCapsule } from "./context-capsule.js";
8
9
  export interface CodexRuntimeOptions {
9
10
  bin?: string;
@@ -16,6 +17,8 @@ export interface CodexRuntimeOptions {
16
17
  }
17
18
  export declare class CodexRuntime implements AgentRuntime {
18
19
  readonly id = "codex-cli";
20
+ readonly providerId = "codex";
21
+ readonly runtimeMode = "cli";
19
22
  readonly kind = "cli";
20
23
  readonly priority = 60;
21
24
  readonly capabilities: RuntimeCapabilities;
@@ -28,7 +31,7 @@ export declare class CodexRuntime implements AgentRuntime {
28
31
  private readonly safetyMarginTokens;
29
32
  constructor(options?: CodexRuntimeOptions);
30
33
  supports(capsule: ContextCapsule): boolean;
31
- health(): Promise<RuntimeHealth>;
34
+ health(input?: RuntimeHealthProbeRequest): Promise<RuntimeHealth>;
32
35
  runNode(capsule: ContextCapsule, signal: AbortSignal): Promise<AgentRunResult>;
33
36
  execute(task: AgentTask): Promise<AgentResult>;
34
37
  private buildPrompt;
@@ -9,8 +9,11 @@ import { sanitizeUserVisibleOutput } from "../util/user-visible-output.js";
9
9
  import { buildChildEnv } from "./child-env.js";
10
10
  import { contextPreflightErrorMessage, preflightProviderInput, } from "../providers/context-preflight.js";
11
11
  import { createRuntimeSandboxProfile } from "./sandbox-profile.js";
12
+ import { staticRuntimeHealth } from "./runtime-health-probes.js";
12
13
  export class CodexRuntime {
13
14
  id = "codex-cli";
15
+ providerId = "codex";
16
+ runtimeMode = "cli";
14
17
  kind = "cli";
15
18
  priority = 60;
16
19
  capabilities = {
@@ -68,14 +71,25 @@ export class CodexRuntime {
68
71
  }
69
72
  return true;
70
73
  }
71
- async health() {
72
- const available = await checkCommand(this.bin).catch(() => false);
73
- return {
74
+ async health(input = { probeKind: "static", highRisk: false }) {
75
+ const started = Date.now();
76
+ const runtimeOk = input.probeKind === "static"
77
+ ? await checkCommand(this.bin).catch(() => false)
78
+ : (await runShell(this.bin, ["--version"], { cwd: this.cwd, timeout: 5000 }).catch(() => ({ exitCode: 1 }))).exitCode === 0;
79
+ const available = runtimeOk;
80
+ return staticRuntimeHealth({
74
81
  runtimeId: this.id,
75
82
  available,
76
- reason: available ? undefined : "codex CLI is not available on PATH",
77
- checkedAt: new Date().toISOString(),
78
- };
83
+ reason: available ? undefined : "codex CLI is not available or failed --version probe",
84
+ runtimeOk,
85
+ authOk: runtimeOk,
86
+ modelOk: true,
87
+ quotaOk: true,
88
+ rateLimitOk: true,
89
+ latencyMs: input.probeKind === "static" ? undefined : Date.now() - started,
90
+ probeKind: input.probeKind,
91
+ ttlMs: input.probeKind === "static" ? 60_000 : 30_000,
92
+ });
79
93
  }
80
94
  async runNode(capsule, signal) {
81
95
  try {
@@ -146,12 +160,7 @@ export class CodexRuntime {
146
160
  ...(model ? { OMK_PROVIDER_MODEL: model } : {}),
147
161
  },
148
162
  });
149
- const sandboxMode = task.context.sandboxMode === "read-only" || task.context.sandboxMode === "workspace-write"
150
- ? task.context.sandboxMode
151
- :
152
- task.capabilities.write || task.capabilities.patch || task.capabilities.shell
153
- ? "workspace-write"
154
- : "read-only";
163
+ const sandboxMode = resolveCodexSandboxMode(task);
155
164
  const approvalPolicy = codexApprovalPolicy(task.context.approvalPolicy ?? task.context.env?.OMK_APPROVAL_POLICY, sandboxMode);
156
165
  const sandboxProfile = createRuntimeSandboxProfile({
157
166
  cwd: this.cwd,
@@ -254,10 +263,23 @@ export class CodexRuntime {
254
263
  return parts.join("\n");
255
264
  }
256
265
  }
266
+ function resolveCodexSandboxMode(task) {
267
+ if (task.context.sandboxMode === "read-only" || task.context.sandboxMode === "workspace-write") {
268
+ return task.context.sandboxMode;
269
+ }
270
+ // Advisory API runtimes must stay read-only even if capabilities request write.
271
+ if (task.context.env?.OMK_PROVIDER_AUTHORITY === "advisory")
272
+ return "read-only";
273
+ if (task.capabilities.write || task.capabilities.patch || task.capabilities.shell) {
274
+ return "workspace-write";
275
+ }
276
+ return "read-only";
277
+ }
257
278
  function codexApprovalPolicy(value, sandboxMode) {
258
279
  if (sandboxMode !== "read-only")
259
280
  return "on-request";
260
281
  const normalized = value?.trim().toLowerCase();
282
+ // OMK "ask" must never map to provider "never"; only explicit "never"/"yolo" does.
261
283
  if (normalized === "never" || normalized === "yolo")
262
284
  return "never";
263
285
  return "on-request";
@@ -57,18 +57,46 @@ export async function capsuleToTask(capsule, options = {}) {
57
57
  maxLatencyMs: undefined,
58
58
  };
59
59
  const capabilities = capabilitiesFromNode(capsule);
60
+ const safety = safetyFromCapsule(capsule, capabilities);
61
+ const sovereignty = routing?.freedomd
62
+ ? {
63
+ mode: (routing.freedomd.degradedMode ?? routing.freedomd.dataBoundary) ? "freedomd" : "standard",
64
+ dataBoundary: routing.freedomd.dataBoundary ?? "internal",
65
+ retentionDecision: "allow",
66
+ jurisdictionDecision: "allow",
67
+ providerCutoffRisk: 0,
68
+ localFallbackAvailable: false,
69
+ reason: routing.freedomd.sovereigntyReason ?? "from dag routing",
70
+ }
71
+ : undefined;
60
72
  const task = {
61
73
  prompt: capsule.task,
62
74
  context,
63
75
  tools,
64
76
  providerPolicy,
65
77
  capabilities,
78
+ safety,
79
+ sovereignty,
66
80
  };
67
81
  return task;
68
82
  }
69
83
  function isAbortSignal(value) {
70
84
  return "aborted" in value && typeof value.addEventListener === "function";
71
85
  }
86
+ function safetyFromCapsule(capsule, capabilities) {
87
+ const routing = capsule.node.routing;
88
+ const risk = routing?.risk ?? (capabilities.shell || capabilities.merge ? "shell" : capabilities.write || capabilities.patch ? "write" : "read");
89
+ const authorityMode = routing?.assignedProviderAuthority
90
+ ?? (routing?.readOnly === true ? "advisory" : "authority");
91
+ return {
92
+ risk,
93
+ riskTrace: routing?.riskTrace,
94
+ approvalPolicy: routing?.approvalPolicy ?? routing?.executionPrompt ?? "interactive",
95
+ sandboxMode: routing?.sandboxMode ?? (routing?.readOnly === true ? "read-only" : "workspace-write"),
96
+ evidenceRequired: routing?.evidenceRequired === true || capabilities.write || capabilities.patch || capabilities.shell || capabilities.merge,
97
+ authorityMode,
98
+ };
99
+ }
72
100
  function capabilitiesFromNode(capsule) {
73
101
  const node = capsule.node;
74
102
  const routing = node.routing;
@@ -77,7 +105,9 @@ function capabilitiesFromNode(capsule) {
77
105
  const assigned = new Set(routing?.assignedProviderCapabilities ?? []);
78
106
  const merge = assigned.has("merge") || role === "merger" || role === "integrator" || role === "orchestrator";
79
107
  const write = assigned.has("write") || merge || role === "coder" || role === "executor" || role === "refactorer";
80
- const shell = assigned.has("shell") || routing?.requiresToolCalling === true || gates.includes("command-pass") || gates.includes("test-pass");
108
+ const shell = routing?.readOnly === true
109
+ ? false
110
+ : assigned.has("shell") || routing?.requiresToolCalling === true || gates.includes("command-pass") || gates.includes("test-pass");
81
111
  const review = assigned.has("review") || role === "reviewer" || role === "qa" || role === "tester" || gates.includes("review-pass");
82
112
  const mcp = assigned.has("mcp") || routing?.requiresMcp === true;
83
113
  const vision = assigned.has("vision");
@@ -88,7 +118,7 @@ function capabilitiesFromNode(capsule) {
88
118
  mcp,
89
119
  patch: routing?.readOnly === true ? false : write,
90
120
  review,
91
- merge,
121
+ merge: routing?.readOnly === true ? false : merge,
92
122
  vision,
93
123
  toolCalling: routing?.requiresToolCalling === true || assigned.has("toolCalling"),
94
124
  maxTokens: capsule.budget.maxInputTokens,
@@ -5,11 +5,27 @@ import { mkdir, readFile, stat, writeFile } from "fs/promises";
5
5
  import { createContextBudgetOptimizer } from "./context-budget-optimizer.js";
6
6
  import { createDecisionTraceStore } from "../evidence/decision-trace.js";
7
7
  import { evaluateHeadroom } from "./headroom-policy.js";
8
+ import { getRunArtifactPath } from "../util/run-store.js";
8
9
  const DEFAULT_CONTEXT_WINDOW = 200_000;
9
10
  function resolveBudget(node) {
10
11
  const preset = node.routing?.contextBudget ?? "small";
11
12
  return CONTEXT_BUDGET_PRESETS[preset] ?? DEFAULT_CONTEXT_BUDGET;
12
13
  }
14
+ async function loadPrivatePromptPayload(node, runId, projectRoot) {
15
+ const ref = node.routing?.promptPayloadRef;
16
+ if (!ref || !runId)
17
+ return undefined;
18
+ try {
19
+ const raw = await readFile(getRunArtifactPath(runId, ref, projectRoot), "utf-8");
20
+ const parsed = JSON.parse(raw);
21
+ if (typeof parsed.compiledPrompt !== "string" || parsed.compiledPrompt.trim().length === 0)
22
+ return undefined;
23
+ return parsed.compiledPrompt;
24
+ }
25
+ catch {
26
+ return undefined;
27
+ }
28
+ }
13
29
  function collectDependencySummaries(node, state) {
14
30
  if (!state || !node.dependsOn.length)
15
31
  return [];
@@ -238,9 +254,11 @@ export function createContextBroker(options = {}) {
238
254
  nodeId: node.id,
239
255
  graphMemory,
240
256
  }).catch(() => { });
257
+ const privatePrompt = await loadPrivatePromptPayload(node, state?.runId, projectRoot);
241
258
  const task = [
242
259
  `Execute DAG node: ${node.id}`,
243
260
  `Name: ${node.name}`,
261
+ privatePrompt ? `PrivatePrompt: ${privatePrompt}` : undefined,
244
262
  `Role: ${node.role}`,
245
263
  node.routing?.actionAtom ? `ActionAtom: ${node.routing.actionAtom.id} | ${node.routing.actionAtom.label} | ${node.routing.actionAtom.verb} ${node.routing.actionAtom.object ?? "assigned scope"} | evidence=${node.routing.actionAtom.evidenceTarget} | done=${node.routing.actionAtom.doneCondition}` : undefined,
246
264
  node.routing?.skills?.length ? `Skills: ${node.routing.skills.join(", ")}` : undefined,
@@ -68,6 +68,58 @@ export interface AdapterTestResult {
68
68
  readonly score: number;
69
69
  readonly details?: string;
70
70
  }
71
+ /** Kinds of output gates that can satisfy evidence-required turns. */
72
+ export type EvidenceGateKind = "file-exists" | "test-pass" | "review-pass" | "command-pass" | "summary" | "artifact" | "diff";
73
+ /** A declared gate requirement. Declarations are not evidence. */
74
+ export interface EvidenceRequirement {
75
+ readonly gate: EvidenceGateKind;
76
+ readonly ref?: string;
77
+ readonly required: boolean;
78
+ }
79
+ /** A produced, replayable evidence observation. */
80
+ export interface EvidenceObservation {
81
+ readonly kind: EvidenceGateKind;
82
+ readonly source: "stdout" | "metadata" | "artifact" | "file";
83
+ readonly ref?: string;
84
+ readonly artifactPath?: string;
85
+ readonly timestamp: string;
86
+ readonly replayable: boolean;
87
+ readonly redacted: boolean;
88
+ /** Confidence that this observation is replayable, command-backed evidence. */
89
+ readonly confidence: number;
90
+ }
91
+ /** Result of checking whether a node/task produced required evidence. */
92
+ export interface EvidenceGateCheck {
93
+ readonly required: boolean;
94
+ readonly satisfied: boolean;
95
+ readonly gates: readonly EvidenceGateKind[];
96
+ readonly missing: readonly EvidenceGateKind[];
97
+ readonly reason: string;
98
+ readonly requirements?: readonly EvidenceRequirement[];
99
+ readonly observations?: readonly EvidenceObservation[];
100
+ }
101
+ export declare function isEvidenceGateKind(value: string | undefined): value is EvidenceGateKind;
102
+ export declare function evidenceRequirementsFromOutputs(outputs: readonly {
103
+ gate?: string;
104
+ ref?: string;
105
+ required?: boolean;
106
+ }[] | undefined): EvidenceRequirement[];
107
+ export declare function hasDeclaredEvidenceRequirement(outputs: readonly {
108
+ gate?: string;
109
+ ref?: string;
110
+ required?: boolean;
111
+ }[] | undefined): boolean;
112
+ export declare function evidenceObservationsFromResult(input: {
113
+ readonly metadata?: Record<string, unknown> | null;
114
+ readonly stdout?: string;
115
+ readonly artifactPaths?: readonly string[];
116
+ readonly timestamp?: string;
117
+ }): EvidenceObservation[];
118
+ export declare function checkEvidenceGate(required: boolean | undefined, outputs: readonly {
119
+ gate?: string;
120
+ ref?: string;
121
+ required?: boolean;
122
+ }[] | undefined, metadata?: Record<string, unknown> | null, stdout?: string, artifactPaths?: readonly string[]): EvidenceGateCheck;
71
123
  /** Per-gate check result. */
72
124
  export interface GateCheck {
73
125
  readonly gate: string;
@@ -4,4 +4,141 @@
4
4
  * Core interfaces that bridge reasoning traces, runtime decisions,
5
5
  * provider maturity, and release gates into a verifiable evidence model.
6
6
  */
7
- export {};
7
+ const EVIDENCE_GATE_KINDS = [
8
+ "file-exists",
9
+ "test-pass",
10
+ "review-pass",
11
+ "command-pass",
12
+ "summary",
13
+ "artifact",
14
+ "diff",
15
+ ];
16
+ export function isEvidenceGateKind(value) {
17
+ return Boolean(value && EVIDENCE_GATE_KINDS.includes(value.toLowerCase()));
18
+ }
19
+ export function evidenceRequirementsFromOutputs(outputs) {
20
+ const requirements = [];
21
+ for (const output of outputs ?? []) {
22
+ const kind = output.gate?.toLowerCase();
23
+ if (!isEvidenceGateKind(kind))
24
+ continue;
25
+ if (output.required === false)
26
+ continue;
27
+ requirements.push({ gate: kind, ref: output.ref, required: true });
28
+ }
29
+ return requirements;
30
+ }
31
+ export function hasDeclaredEvidenceRequirement(outputs) {
32
+ return evidenceRequirementsFromOutputs(outputs).length > 0;
33
+ }
34
+ export function evidenceObservationsFromResult(input) {
35
+ const timestamp = input.timestamp ?? new Date().toISOString();
36
+ const observations = [];
37
+ const metadata = input.metadata ?? undefined;
38
+ const metaGates = metadata?.evidenceGates;
39
+ if (Array.isArray(metaGates)) {
40
+ for (const raw of metaGates) {
41
+ const gate = typeof raw === "string" ? raw.toLowerCase() : undefined;
42
+ if (isEvidenceGateKind(gate)) {
43
+ observations.push({ kind: gate, source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
44
+ }
45
+ }
46
+ }
47
+ if (metadata?.commandPass === true || metadata?.testPass === true || metadata?.buildPass === true) {
48
+ observations.push({ kind: "command-pass", source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
49
+ }
50
+ if (metadata?.diff || metadata?.patch || metadata?.changedFiles) {
51
+ observations.push({ kind: "diff", source: "metadata", timestamp, replayable: true, redacted: true, confidence: 0.9 });
52
+ }
53
+ const artifactRef = metadata?.artifact ?? metadata?.artifactPath ?? metadata?.evidenceRef;
54
+ if (typeof artifactRef === "string" && artifactRef.trim().length > 0) {
55
+ observations.push({ kind: "artifact", source: "metadata", ref: artifactRef, artifactPath: artifactRef, timestamp, replayable: true, redacted: true, confidence: 0.95 });
56
+ }
57
+ for (const artifactPath of input.artifactPaths ?? []) {
58
+ observations.push({ kind: "artifact", source: "artifact", artifactPath, ref: artifactPath, timestamp, replayable: true, redacted: true, confidence: 0.95 });
59
+ }
60
+ const stdout = input.stdout ?? "";
61
+ if (stdout.trim().length > 0) {
62
+ const hasStructuredSummaryMarker = /^##\s+(Summary|Evidence|Verification)\b/im.test(stdout);
63
+ observations.push({
64
+ kind: "summary",
65
+ source: "stdout",
66
+ timestamp,
67
+ replayable: true,
68
+ redacted: true,
69
+ confidence: hasStructuredSummaryMarker ? 0.9 : 0.4,
70
+ });
71
+ }
72
+ if (/\b(pass(ed)?|success|ok)\b/i.test(stdout) && /\b(test|check|build|lint|command)\b/i.test(stdout)) {
73
+ observations.push({ kind: "command-pass", source: "stdout", timestamp, replayable: true, redacted: true, confidence: 0.4 });
74
+ }
75
+ return observations;
76
+ }
77
+ function minimumConfidenceFor(requirement) {
78
+ if (["command-pass", "test-pass", "summary", "review-pass"].includes(requirement.gate))
79
+ return 0.8;
80
+ return 0;
81
+ }
82
+ function observationSatisfies(requirement, observation) {
83
+ if (!observation.replayable || !observation.redacted)
84
+ return false;
85
+ if (observation.confidence < minimumConfidenceFor(requirement))
86
+ return false;
87
+ if (observation.kind === requirement.gate)
88
+ return true;
89
+ if (requirement.gate === "test-pass" && observation.kind === "command-pass")
90
+ return true;
91
+ if (requirement.gate === "review-pass" && observation.kind === "summary")
92
+ return true;
93
+ if (requirement.gate === "file-exists" && observation.kind === "artifact")
94
+ return true;
95
+ return false;
96
+ }
97
+ export function checkEvidenceGate(required, outputs, metadata, stdout, artifactPaths) {
98
+ const requirements = evidenceRequirementsFromOutputs(outputs);
99
+ const observations = evidenceObservationsFromResult({ metadata, stdout, artifactPaths });
100
+ const observedKinds = new Set(observations.map((o) => o.kind));
101
+ if (!required) {
102
+ return { required: false, satisfied: true, gates: [...observedKinds], missing: [], reason: "evidence not required", requirements, observations };
103
+ }
104
+ if (requirements.length === 0 && observations.length > 0) {
105
+ const strongObservations = observations.filter((observation) => observation.confidence >= 0.8 && observation.replayable && observation.redacted);
106
+ if (strongObservations.length > 0) {
107
+ return {
108
+ required: true,
109
+ satisfied: true,
110
+ gates: [...new Set(strongObservations.map((observation) => observation.kind))],
111
+ missing: [],
112
+ reason: `evidence satisfied by high-confidence observations without explicit gate: ${[...new Set(strongObservations.map((observation) => observation.kind))].join(", ")}`,
113
+ requirements,
114
+ observations,
115
+ };
116
+ }
117
+ }
118
+ const effectiveRequirements = requirements.length > 0
119
+ ? requirements
120
+ : EVIDENCE_GATE_KINDS.map((gate) => ({ gate, required: true }));
121
+ const missing = effectiveRequirements
122
+ .filter((requirement) => !observations.some((observation) => observationSatisfies(requirement, observation)))
123
+ .map((requirement) => requirement.gate);
124
+ if (missing.length === 0) {
125
+ return {
126
+ required: true,
127
+ satisfied: true,
128
+ gates: [...observedKinds],
129
+ missing: [],
130
+ reason: `evidence satisfied by observations: ${[...observedKinds].join(", ") || "none"}`,
131
+ requirements: effectiveRequirements,
132
+ observations,
133
+ };
134
+ }
135
+ return {
136
+ required: true,
137
+ satisfied: false,
138
+ gates: [...observedKinds],
139
+ missing,
140
+ reason: `required evidence observations missing: ${[...new Set(missing)].join(", ")}`,
141
+ requirements: effectiveRequirements,
142
+ observations,
143
+ };
144
+ }
@@ -26,9 +26,36 @@ export interface RuntimeCapabilities {
26
26
  supportsStructuredOutput?: boolean;
27
27
  supportsToolCalling?: boolean;
28
28
  }
29
+ export type HealthState = "pass" | "fail" | "unknown";
30
+ export type RuntimeHealthProbeKind = "none" | "static" | "cheap-call" | "live-call";
31
+ export interface RuntimeHealthVector {
32
+ /** Legacy boolean dimensions retained for backward compatibility. */
33
+ runtimeOk?: boolean;
34
+ authOk?: boolean;
35
+ modelOk?: boolean;
36
+ quotaOk?: boolean;
37
+ rateLimitOk?: boolean;
38
+ /** Tri-state dimensions used by health-aware routing v2. */
39
+ runtime?: HealthState;
40
+ auth?: HealthState;
41
+ model?: HealthState;
42
+ quota?: HealthState;
43
+ rateLimit?: HealthState;
44
+ latencyMs?: number;
45
+ lastProbeKind?: RuntimeHealthProbeKind;
46
+ checkedAt?: string;
47
+ expiresAt?: string;
48
+ }
49
+ export interface RuntimeHealthProbeRequest {
50
+ readonly probeKind: RuntimeHealthProbeKind;
51
+ readonly taskRisk?: string;
52
+ readonly highRisk: boolean;
53
+ }
29
54
  export interface RuntimeHealth {
30
55
  runtimeId: RuntimeId;
31
56
  available: boolean;
32
57
  reason?: string;
33
58
  checkedAt: string;
59
+ /** Structured health signals beyond a binary available flag. */
60
+ vector?: RuntimeHealthVector;
34
61
  }