open-multi-agent-kit 0.99.0 → 1.0.0

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 (271) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +3 -3
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js +1 -0
  5. package/dist/bun/cli.js.map +1 -1
  6. package/dist/bun/register-bundled-coding-agent.d.ts +10 -0
  7. package/dist/bun/register-bundled-coding-agent.d.ts.map +1 -0
  8. package/dist/bun/register-bundled-coding-agent.js +12 -0
  9. package/dist/bun/register-bundled-coding-agent.js.map +1 -0
  10. package/dist/cli/args.d.ts +1 -1
  11. package/dist/cli/args.d.ts.map +1 -1
  12. package/dist/cli/args.js +1 -1
  13. package/dist/cli/args.js.map +1 -1
  14. package/dist/cli/help.d.ts.map +1 -1
  15. package/dist/cli/help.js +1 -1
  16. package/dist/cli/help.js.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +14 -2
  19. package/dist/cli.js.map +1 -1
  20. package/dist/commands/neo-cli.d.ts +9 -0
  21. package/dist/commands/neo-cli.d.ts.map +1 -0
  22. package/dist/commands/neo-cli.js +61 -0
  23. package/dist/commands/neo-cli.js.map +1 -0
  24. package/dist/core/agent-session.d.ts +29 -2
  25. package/dist/core/agent-session.d.ts.map +1 -1
  26. package/dist/core/agent-session.js +107 -30
  27. package/dist/core/agent-session.js.map +1 -1
  28. package/dist/core/bundled-skills.d.ts +4 -0
  29. package/dist/core/bundled-skills.d.ts.map +1 -0
  30. package/dist/core/bundled-skills.js +32 -0
  31. package/dist/core/bundled-skills.js.map +1 -0
  32. package/dist/core/cli-diagnostics.d.ts +6 -0
  33. package/dist/core/cli-diagnostics.d.ts.map +1 -0
  34. package/dist/core/cli-diagnostics.js +20 -0
  35. package/dist/core/cli-diagnostics.js.map +1 -0
  36. package/dist/core/context-budget-headroom.d.ts +12 -0
  37. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  38. package/dist/core/context-budget-headroom.js +35 -0
  39. package/dist/core/context-budget-headroom.js.map +1 -1
  40. package/dist/core/context-budget-v2-input-validation.d.ts +4 -0
  41. package/dist/core/context-budget-v2-input-validation.d.ts.map +1 -0
  42. package/dist/core/context-budget-v2-input-validation.js +79 -0
  43. package/dist/core/context-budget-v2-input-validation.js.map +1 -0
  44. package/dist/core/context-budget-v2-observability.d.ts +15 -0
  45. package/dist/core/context-budget-v2-observability.d.ts.map +1 -0
  46. package/dist/core/context-budget-v2-observability.js +35 -0
  47. package/dist/core/context-budget-v2-observability.js.map +1 -0
  48. package/dist/core/context-budget-v2-planned-items.d.ts +5 -0
  49. package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -0
  50. package/dist/core/context-budget-v2-planned-items.js +40 -0
  51. package/dist/core/context-budget-v2-planned-items.js.map +1 -0
  52. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  53. package/dist/core/context-budget-v2-planner.js +57 -38
  54. package/dist/core/context-budget-v2-planner.js.map +1 -1
  55. package/dist/core/context-budget-v2-selection.d.ts +19 -3
  56. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  57. package/dist/core/context-budget-v2-selection.js +35 -57
  58. package/dist/core/context-budget-v2-selection.js.map +1 -1
  59. package/dist/core/context-budget-v2-tiers.d.ts.map +1 -1
  60. package/dist/core/context-budget-v2-tiers.js +9 -42
  61. package/dist/core/context-budget-v2-tiers.js.map +1 -1
  62. package/dist/core/context-budget-v2-types.d.ts +8 -1
  63. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  64. package/dist/core/context-budget-v2-types.js.map +1 -1
  65. package/dist/core/extensions/bundled-virtual-modules.d.ts +15 -0
  66. package/dist/core/extensions/bundled-virtual-modules.d.ts.map +1 -0
  67. package/dist/core/extensions/bundled-virtual-modules.js +63 -0
  68. package/dist/core/extensions/bundled-virtual-modules.js.map +1 -0
  69. package/dist/core/extensions/loader.d.ts.map +1 -1
  70. package/dist/core/extensions/loader.js +2 -42
  71. package/dist/core/extensions/loader.js.map +1 -1
  72. package/dist/core/extensions/runner.d.ts +1 -0
  73. package/dist/core/extensions/runner.d.ts.map +1 -1
  74. package/dist/core/extensions/runner.js +6 -0
  75. package/dist/core/extensions/runner.js.map +1 -1
  76. package/dist/core/extensions/types.d.ts +10 -0
  77. package/dist/core/extensions/types.d.ts.map +1 -1
  78. package/dist/core/extensions/types.js.map +1 -1
  79. package/dist/core/index.d.ts +2 -1
  80. package/dist/core/index.d.ts.map +1 -1
  81. package/dist/core/index.js +2 -1
  82. package/dist/core/index.js.map +1 -1
  83. package/dist/core/loadout-runtime.d.ts +2 -8
  84. package/dist/core/loadout-runtime.d.ts.map +1 -1
  85. package/dist/core/loadout-runtime.js.map +1 -1
  86. package/dist/core/mcp/client.d.ts +27 -6
  87. package/dist/core/mcp/client.d.ts.map +1 -1
  88. package/dist/core/mcp/client.js +80 -20
  89. package/dist/core/mcp/client.js.map +1 -1
  90. package/dist/core/mcp/manager.d.ts +10 -1
  91. package/dist/core/mcp/manager.d.ts.map +1 -1
  92. package/dist/core/mcp/manager.js +68 -9
  93. package/dist/core/mcp/manager.js.map +1 -1
  94. package/dist/core/mcp/protocol.d.ts +9 -3
  95. package/dist/core/mcp/protocol.d.ts.map +1 -1
  96. package/dist/core/mcp/protocol.js +61 -15
  97. package/dist/core/mcp/protocol.js.map +1 -1
  98. package/dist/core/mcp/stdio-transport.d.ts +12 -1
  99. package/dist/core/mcp/stdio-transport.d.ts.map +1 -1
  100. package/dist/core/mcp/stdio-transport.js +30 -2
  101. package/dist/core/mcp/stdio-transport.js.map +1 -1
  102. package/dist/core/mcp-descriptor-injection.d.ts +26 -0
  103. package/dist/core/mcp-descriptor-injection.d.ts.map +1 -0
  104. package/dist/core/mcp-descriptor-injection.js +25 -0
  105. package/dist/core/mcp-descriptor-injection.js.map +1 -0
  106. package/dist/core/mcp-public-presets.d.ts +1 -3
  107. package/dist/core/mcp-public-presets.d.ts.map +1 -1
  108. package/dist/core/mcp-public-presets.js +3 -15
  109. package/dist/core/mcp-public-presets.js.map +1 -1
  110. package/dist/core/model-registry.d.ts.map +1 -1
  111. package/dist/core/model-registry.js +24 -3
  112. package/dist/core/model-registry.js.map +1 -1
  113. package/dist/core/neo/catalog.d.ts +20 -0
  114. package/dist/core/neo/catalog.d.ts.map +1 -0
  115. package/dist/core/neo/catalog.js +50 -0
  116. package/dist/core/neo/catalog.js.map +1 -0
  117. package/dist/core/neo/setup.d.ts +3 -0
  118. package/dist/core/neo/setup.d.ts.map +1 -0
  119. package/dist/core/neo/setup.js +47 -0
  120. package/dist/core/neo/setup.js.map +1 -0
  121. package/dist/core/provider-default-models.d.ts +1 -0
  122. package/dist/core/provider-default-models.d.ts.map +1 -1
  123. package/dist/core/provider-default-models.js +1 -0
  124. package/dist/core/provider-default-models.js.map +1 -1
  125. package/dist/core/provider-display-names.d.ts.map +1 -1
  126. package/dist/core/provider-display-names.js +1 -0
  127. package/dist/core/provider-display-names.js.map +1 -1
  128. package/dist/core/provider-error-classification.d.ts +57 -0
  129. package/dist/core/provider-error-classification.d.ts.map +1 -0
  130. package/dist/core/provider-error-classification.js +103 -0
  131. package/dist/core/provider-error-classification.js.map +1 -0
  132. package/dist/core/provider-resilience.d.ts +10 -0
  133. package/dist/core/provider-resilience.d.ts.map +1 -1
  134. package/dist/core/provider-resilience.js +36 -3
  135. package/dist/core/provider-resilience.js.map +1 -1
  136. package/dist/core/provider-usage-commandcode.d.ts +9 -0
  137. package/dist/core/provider-usage-commandcode.d.ts.map +1 -0
  138. package/dist/core/provider-usage-commandcode.js +198 -0
  139. package/dist/core/provider-usage-commandcode.js.map +1 -0
  140. package/dist/core/provider-usage-devin.d.ts +5 -3
  141. package/dist/core/provider-usage-devin.d.ts.map +1 -1
  142. package/dist/core/provider-usage-devin.js +15 -5
  143. package/dist/core/provider-usage-devin.js.map +1 -1
  144. package/dist/core/provider-usage-types.d.ts +1 -1
  145. package/dist/core/provider-usage-types.d.ts.map +1 -1
  146. package/dist/core/provider-usage-types.js.map +1 -1
  147. package/dist/core/provider-usage.d.ts.map +1 -1
  148. package/dist/core/provider-usage.js +6 -0
  149. package/dist/core/provider-usage.js.map +1 -1
  150. package/dist/core/resource-admission.d.ts +36 -0
  151. package/dist/core/resource-admission.d.ts.map +1 -1
  152. package/dist/core/resource-admission.js +59 -0
  153. package/dist/core/resource-admission.js.map +1 -1
  154. package/dist/core/resource-loader.d.ts.map +1 -1
  155. package/dist/core/resource-loader.js +2 -2
  156. package/dist/core/resource-loader.js.map +1 -1
  157. package/dist/core/run-usage-ledger.d.ts +47 -0
  158. package/dist/core/run-usage-ledger.d.ts.map +1 -0
  159. package/dist/core/run-usage-ledger.js +162 -0
  160. package/dist/core/run-usage-ledger.js.map +1 -0
  161. package/dist/core/run-usage-operation.d.ts +8 -0
  162. package/dist/core/run-usage-operation.d.ts.map +1 -0
  163. package/dist/core/run-usage-operation.js +12 -0
  164. package/dist/core/run-usage-operation.js.map +1 -0
  165. package/dist/core/sdk.d.ts.map +1 -1
  166. package/dist/core/sdk.js +5 -6
  167. package/dist/core/sdk.js.map +1 -1
  168. package/dist/core/session-failure-cause.d.ts.map +1 -1
  169. package/dist/core/session-failure-cause.js +14 -5
  170. package/dist/core/session-failure-cause.js.map +1 -1
  171. package/dist/core/session-prompt-lifecycle.d.ts +6 -0
  172. package/dist/core/session-prompt-lifecycle.d.ts.map +1 -1
  173. package/dist/core/session-prompt-lifecycle.js +47 -2
  174. package/dist/core/session-prompt-lifecycle.js.map +1 -1
  175. package/dist/core/session-termination.d.ts.map +1 -1
  176. package/dist/core/session-termination.js +4 -2
  177. package/dist/core/session-termination.js.map +1 -1
  178. package/dist/core/subagent-lane-authority.d.ts +28 -0
  179. package/dist/core/subagent-lane-authority.d.ts.map +1 -0
  180. package/dist/core/subagent-lane-authority.js +119 -0
  181. package/dist/core/subagent-lane-authority.js.map +1 -0
  182. package/dist/core/subagent-lane-contract.d.ts +114 -0
  183. package/dist/core/subagent-lane-contract.d.ts.map +1 -0
  184. package/dist/core/subagent-lane-contract.js +18 -0
  185. package/dist/core/subagent-lane-contract.js.map +1 -0
  186. package/dist/core/subagent-lane-launcher.d.ts +3 -6
  187. package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
  188. package/dist/core/subagent-lane-launcher.js +53 -12
  189. package/dist/core/subagent-lane-launcher.js.map +1 -1
  190. package/dist/core/subagent-orchestration.d.ts +4 -17
  191. package/dist/core/subagent-orchestration.d.ts.map +1 -1
  192. package/dist/core/subagent-orchestration.js.map +1 -1
  193. package/dist/core/verified-run/broker.d.ts.map +1 -1
  194. package/dist/core/verified-run/broker.js +4 -1
  195. package/dist/core/verified-run/broker.js.map +1 -1
  196. package/dist/core/workload-permit-pool.d.ts +1 -1
  197. package/dist/core/workload-permit-pool.d.ts.map +1 -1
  198. package/dist/core/workload-permit-pool.js +3 -0
  199. package/dist/core/workload-permit-pool.js.map +1 -1
  200. package/dist/guardrails/strict-evidence-approval-adapter.d.ts +34 -0
  201. package/dist/guardrails/strict-evidence-approval-adapter.d.ts.map +1 -0
  202. package/dist/guardrails/strict-evidence-approval-adapter.js +70 -0
  203. package/dist/guardrails/strict-evidence-approval-adapter.js.map +1 -0
  204. package/dist/index.d.ts +3 -0
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +1 -0
  207. package/dist/index.js.map +1 -1
  208. package/dist/main.d.ts.map +1 -1
  209. package/dist/main.js +11 -18
  210. package/dist/main.js.map +1 -1
  211. package/dist/modes/acp/acp-agent.d.ts +24 -0
  212. package/dist/modes/acp/acp-agent.d.ts.map +1 -0
  213. package/dist/modes/acp/acp-agent.js +133 -0
  214. package/dist/modes/acp/acp-agent.js.map +1 -0
  215. package/dist/modes/acp/acp-mode.d.ts +4 -0
  216. package/dist/modes/acp/acp-mode.d.ts.map +1 -0
  217. package/dist/modes/acp/acp-mode.js +34 -0
  218. package/dist/modes/acp/acp-mode.js.map +1 -0
  219. package/dist/modes/acp/acp-session.d.ts +4 -0
  220. package/dist/modes/acp/acp-session.d.ts.map +1 -0
  221. package/dist/modes/acp/acp-session.js +76 -0
  222. package/dist/modes/acp/acp-session.js.map +1 -0
  223. package/dist/modes/acp/acp-transport.d.ts +5 -0
  224. package/dist/modes/acp/acp-transport.d.ts.map +1 -0
  225. package/dist/modes/acp/acp-transport.js +90 -0
  226. package/dist/modes/acp/acp-transport.js.map +1 -0
  227. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  228. package/dist/modes/interactive/interactive-mode.js +1 -0
  229. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  230. package/docs/audit-revalidation-2026-09-17.md +77 -0
  231. package/docs/devin-harness.md +33 -4
  232. package/docs/ecraf-normalization.md +83 -0
  233. package/docs/model-catalog-refresh.md +51 -1
  234. package/docs/models.md +1 -1
  235. package/docs/neo.md +134 -0
  236. package/docs/providers.md +72 -6
  237. package/docs/run-usage-ledger.md +56 -0
  238. package/docs/runtime-algorithms.md +44 -0
  239. package/docs/skills.md +1 -1
  240. package/docs/usage.md +2 -1
  241. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  242. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  243. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  244. package/examples/extensions/gondolin/package-lock.json +2 -2
  245. package/examples/extensions/gondolin/package.json +1 -1
  246. package/examples/extensions/sandbox/package-lock.json +2 -2
  247. package/examples/extensions/sandbox/package.json +1 -1
  248. package/examples/extensions/subagent/adaptive-agent-runtime.ts +14 -1
  249. package/examples/extensions/subagent/graph-result.ts +48 -0
  250. package/examples/extensions/subagent/index.ts +246 -111
  251. package/examples/extensions/subagent/managed-process-tree.ts +42 -0
  252. package/examples/extensions/subagent/managed-process.test.ts +24 -0
  253. package/examples/extensions/subagent/managed-process.ts +93 -112
  254. package/examples/extensions/subagent/subagent-runtime-types.ts +17 -1
  255. package/examples/extensions/subagent/subagent-stream.ts +161 -0
  256. package/examples/extensions/terminal-browser/README.md +54 -0
  257. package/examples/extensions/terminal-browser/bridge-protocol.ts +29 -0
  258. package/examples/extensions/terminal-browser/bridge.ts +219 -0
  259. package/examples/extensions/terminal-browser/browser-surface.ts +288 -0
  260. package/examples/extensions/terminal-browser/index.ts +215 -0
  261. package/examples/extensions/terminal-browser/placeholders.ts +49 -0
  262. package/examples/extensions/with-deps/package-lock.json +2 -2
  263. package/examples/extensions/with-deps/package.json +1 -1
  264. package/npm-shrinkwrap.json +18 -18
  265. package/package.json +8 -7
  266. package/resources/neo/skills/omk-browser/SKILL.md +32 -0
  267. package/resources/neo/skills/omk-code-review/SKILL.md +24 -0
  268. package/resources/neo/skills/omk-computeruse/SKILL.md +34 -0
  269. package/resources/neo/skills/omk-mcp-setup/SKILL.md +48 -0
  270. package/resources/neo/skills/omk-research/SKILL.md +24 -0
  271. package/resources/neo/skills/omk-site/SKILL.md +28 -0
@@ -1,6 +1,7 @@
1
1
  import { type LaneContextInheritanceMode, type LaneEvidenceGate, type LaneSpawnReceipt, type SubagentLaneGrant } from "./loadout-runtime.ts";
2
- import { type CapabilityInventory, type LoadoutAuthority, type LoadoutRole } from "./loadouts.ts";
3
- export type SubagentOrchestrationRole = "planner" | "architect" | "executor" | "critic" | "visual-qa" | "rhwp-doc" | "security" | "package-maintainer";
2
+ import { type CapabilityInventory, type LoadoutRole } from "./loadouts.ts";
3
+ import type { SubagentLaneSpec, SubagentOrchestrationRole } from "./subagent-lane-contract.ts";
4
+ export type { SubagentOrchestrationRole };
4
5
  export type SubagentSchedulerTopology = "serial" | "parallel" | "map-reduce" | "hybrid";
5
6
  export interface SubagentRoleAssignment {
6
7
  readonly role: SubagentOrchestrationRole;
@@ -11,21 +12,7 @@ export interface SubagentRoleAssignment {
11
12
  readonly evidenceGates: readonly LaneEvidenceGate[];
12
13
  readonly writesProductFiles: boolean;
13
14
  }
14
- export interface SubagentLaneSpec {
15
- readonly id: string;
16
- readonly role: SubagentOrchestrationRole;
17
- readonly task: string;
18
- readonly dependsOn?: readonly string[];
19
- readonly readScope?: readonly string[];
20
- readonly writeScope?: readonly string[];
21
- readonly acceptance?: readonly string[];
22
- readonly evidenceOutput?: string;
23
- readonly blockedPaths?: readonly string[];
24
- readonly contextInheritance?: LaneContextInheritanceMode;
25
- readonly grantAuthority?: LoadoutAuthority;
26
- readonly loadoutName?: string;
27
- readonly agentName?: string;
28
- }
15
+ export type { SubagentLaneSpec };
29
16
  export interface SpawnGateDecision {
30
17
  readonly outcome: "allowed" | "rejected";
31
18
  readonly reason: string;
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-orchestration.d.ts","sourceRoot":"","sources":["../../src/core/subagent-orchestration.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tbuildSubagentLaneGrant,\n\ttype LaneContextInheritanceMode,\n\ttype LaneEvidenceGate,\n\ttype LaneSpawnReceipt,\n\ttype SubagentLaneGrant,\n} from \"./loadout-runtime.ts\";\nimport {\n\tapplyLoadoutProfile,\n\tBUILTIN_LOADOUTS,\n\ttype CapabilityInventory,\n\tderiveSchedulerFields,\n\ttype LoadoutAuthority,\n\ttype LoadoutProfile,\n\ttype LoadoutRole,\n} from \"./loadouts.ts\";\n\nexport type SubagentOrchestrationRole =\n\t| \"planner\"\n\t| \"architect\"\n\t| \"executor\"\n\t| \"critic\"\n\t| \"visual-qa\"\n\t| \"rhwp-doc\"\n\t| \"security\"\n\t| \"package-maintainer\";\n\nexport type SubagentSchedulerTopology = \"serial\" | \"parallel\" | \"map-reduce\" | \"hybrid\";\n\nexport interface SubagentRoleAssignment {\n\treadonly role: SubagentOrchestrationRole;\n\treadonly loadoutRole: LoadoutRole;\n\treadonly loadoutName: string;\n\treadonly agentName: string;\n\treadonly contextInheritance: LaneContextInheritanceMode;\n\treadonly evidenceGates: readonly LaneEvidenceGate[];\n\treadonly writesProductFiles: boolean;\n}\n\nexport interface SubagentLaneSpec {\n\treadonly id: string;\n\treadonly role: SubagentOrchestrationRole;\n\treadonly task: string;\n\treadonly dependsOn?: readonly string[];\n\treadonly readScope?: readonly string[];\n\treadonly writeScope?: readonly string[];\n\treadonly acceptance?: readonly string[];\n\treadonly evidenceOutput?: string;\n\treadonly blockedPaths?: readonly string[];\n\treadonly contextInheritance?: LaneContextInheritanceMode;\n\treadonly grantAuthority?: LoadoutAuthority;\n\treadonly loadoutName?: string;\n\treadonly agentName?: string;\n}\n\nexport interface SpawnGateDecision {\n\treadonly outcome: \"allowed\" | \"rejected\";\n\treadonly reason: string;\n\treadonly planRequired: boolean;\n\treadonly missingFields: readonly string[];\n}\n\nexport interface SubagentScheduleBatch {\n\treadonly index: number;\n\treadonly laneIds: readonly string[];\n\treadonly reason: \"ready-parallel\" | \"serialized-writer\" | \"parallel-limit\";\n}\n\nexport interface SubagentRouteFeatures {\n\treadonly topology: SubagentSchedulerTopology;\n\treadonly width: number;\n\treadonly criticalDepth: number;\n\treadonly couplingDensity: number;\n\treadonly parallelRatio: number;\n\treadonly nodeCount: number;\n\treadonly edgeCount: number;\n}\n\nexport interface BuildSubagentOrchestrationPlanInput {\n\treadonly runId: string;\n\treadonly lanes: readonly SubagentLaneSpec[];\n\treadonly inventory: CapabilityInventory;\n\treadonly spawnPlan?: LaneSpawnReceipt;\n\treadonly spawnThreshold?: number;\n\treadonly maxParallelLanes?: number;\n}\n\nexport interface SubagentOrchestrationPlan {\n\treadonly laneGrants: readonly SubagentLaneGrant[];\n\treadonly batches: readonly SubagentScheduleBatch[];\n\treadonly route: SubagentRouteFeatures;\n\treadonly spawnGate: SpawnGateDecision;\n\treadonly blockers: readonly string[];\n\treadonly warnings: readonly string[];\n}\n\nconst DEFAULT_SPAWN_THRESHOLD = 4;\n\nconst ROLE_ASSIGNMENTS: Readonly<Record<SubagentOrchestrationRole, SubagentRoleAssignment>> = {\n\tplanner: {\n\t\trole: \"planner\",\n\t\tloadoutRole: \"planner\",\n\t\tloadoutName: \"plan\",\n\t\tagentName: \"omk-planner\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\tarchitect: {\n\t\trole: \"architect\",\n\t\tloadoutRole: \"architect\",\n\t\tloadoutName: \"architect\",\n\t\tagentName: \"omk-architect\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\texecutor: {\n\t\trole: \"executor\",\n\t\tloadoutRole: \"executor\",\n\t\tloadoutName: \"executor\",\n\t\tagentName: \"omk-executor\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tcritic: {\n\t\trole: \"critic\",\n\t\tloadoutRole: \"critic\",\n\t\tloadoutName: \"critic\",\n\t\tagentName: \"omk-critic\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"visual-qa\": {\n\t\trole: \"visual-qa\",\n\t\tloadoutRole: \"visual-qa\",\n\t\tloadoutName: \"visual-qa\",\n\t\tagentName: \"omk-visual-qa\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"rhwp-doc\": {\n\t\trole: \"rhwp-doc\",\n\t\tloadoutRole: \"rhwp-doc\",\n\t\tloadoutName: \"rhwp-doc\",\n\t\tagentName: \"omk-rhwp-doc\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tsecurity: {\n\t\trole: \"security\",\n\t\tloadoutRole: \"security\",\n\t\tloadoutName: \"security\",\n\t\tagentName: \"omk-security\",\n\t\tcontextInheritance: \"none\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"package-maintainer\": {\n\t\trole: \"package-maintainer\",\n\t\tloadoutRole: \"package-maintainer\",\n\t\tloadoutName: \"package-maintainer\",\n\t\tagentName: \"omk-package-maintainer\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n};\n\nconst REQUIRED_SPAWN_PLAN_STRING_FIELDS = [\n\t\"whyParallel\",\n\t\"whyNotLocal\",\n\t\"independence\",\n\t\"expectedReceiptShape\",\n] as const;\n\ninterface PreparedLane {\n\treadonly index: number;\n\treadonly spec: SubagentLaneSpec;\n\treadonly grant: SubagentLaneGrant;\n\treadonly dependsOn: readonly string[];\n}\n\nexport function resolveSubagentRoleAssignment(role: SubagentOrchestrationRole): SubagentRoleAssignment {\n\treturn ROLE_ASSIGNMENTS[role];\n}\n\nexport function buildSubagentOrchestrationPlan(input: BuildSubagentOrchestrationPlanInput): SubagentOrchestrationPlan {\n\tif (\n\t\tinput.maxParallelLanes !== undefined &&\n\t\t(!Number.isInteger(input.maxParallelLanes) || input.maxParallelLanes < 1)\n\t) {\n\t\tthrow new RangeError(\"maxParallelLanes must be a positive integer\");\n\t}\n\n\tconst blockers: string[] = [];\n\tconst warnings: string[] = [];\n\tblockers.push(...validateLaneIntake(input.lanes));\n\tconst spawnGate = evaluateSpawnGate({\n\t\tchildCount: input.lanes.length,\n\t\tplan: input.spawnPlan,\n\t\tthreshold: input.spawnThreshold ?? DEFAULT_SPAWN_THRESHOLD,\n\t});\n\tif (spawnGate.outcome === \"rejected\") blockers.push(spawnGate.reason);\n\n\tconst prepared = input.lanes.map((lane, index) =>\n\t\tprepareLane(lane, index, input.runId, input.inventory, input.spawnPlan, blockers, warnings),\n\t);\n\tblockers.push(...findDependencyBlockers(prepared));\n\n\tconst scheduledLanes = applyReceiptConsumerDependencies(prepared);\n\tconst batches = schedulePreparedLanes(scheduledLanes, input.maxParallelLanes, blockers);\n\tconst route = buildRouteFeatures(scheduledLanes, batches);\n\n\treturn {\n\t\tlaneGrants: scheduledLanes.map((lane) => lane.grant),\n\t\tbatches,\n\t\troute,\n\t\tspawnGate,\n\t\tblockers: uniqueSorted(blockers),\n\t\twarnings: uniqueSorted(warnings),\n\t};\n}\n\nexport function evaluateSpawnGate(request: {\n\treadonly childCount: number;\n\treadonly plan?: LaneSpawnReceipt;\n\treadonly threshold?: number;\n}): SpawnGateDecision {\n\tconst threshold = request.threshold ?? DEFAULT_SPAWN_THRESHOLD;\n\tif (!Number.isInteger(request.childCount) || request.childCount < 0) {\n\t\tthrow new RangeError(\"childCount must be a non-negative integer\");\n\t}\n\tif (!Number.isInteger(threshold) || threshold < 1) {\n\t\tthrow new RangeError(\"threshold must be a positive integer\");\n\t}\n\n\tconst planRequired = request.childCount > threshold;\n\tif (!planRequired) {\n\t\treturn {\n\t\t\toutcome: \"allowed\",\n\t\t\treason: `batch of ${request.childCount} is at or below threshold ${threshold}`,\n\t\t\tplanRequired: false,\n\t\t\tmissingFields: [],\n\t\t};\n\t}\n\n\tconst missingFields = findMissingSpawnPlanFields(request.plan);\n\tif (missingFields.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"rejected\",\n\t\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and the spawn-plan receipt is ${\n\t\t\t\trequest.plan ? `incomplete (${missingFields.join(\", \")})` : \"missing\"\n\t\t\t}`,\n\t\t\tplanRequired: true,\n\t\t\tmissingFields,\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allowed\",\n\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and a complete spawn-plan receipt was provided`,\n\t\tplanRequired: true,\n\t\tmissingFields: [],\n\t};\n}\n\nexport function findMissingSpawnPlanFields(plan: LaneSpawnReceipt | undefined): string[] {\n\tif (!plan) return [...REQUIRED_SPAWN_PLAN_STRING_FIELDS, \"maxInlineTokens\"];\n\tconst missing: string[] = [];\n\tfor (const field of REQUIRED_SPAWN_PLAN_STRING_FIELDS) {\n\t\tconst value = plan[field];\n\t\tif (value.trim().length === 0) missing.push(field);\n\t}\n\tif (!Number.isFinite(plan.maxInlineTokens) || plan.maxInlineTokens <= 0) {\n\t\tmissing.push(\"maxInlineTokens\");\n\t}\n\treturn missing;\n}\n\nfunction validateLaneIntake(lanes: readonly SubagentLaneSpec[]): string[] {\n\tconst blockers: string[] = [];\n\tconst seenIds = new Map<string, number>();\n\n\tfor (const [index, lane] of lanes.entries()) {\n\t\tconst id = lane.id.trim();\n\t\tconst label = id === \"\" ? `lane at index ${index}` : `lane ${id}`;\n\t\tif (id === \"\") {\n\t\t\tblockers.push(`lane at index ${index} has empty id`);\n\t\t} else {\n\t\t\tconst firstIndex = seenIds.get(id);\n\t\t\tif (firstIndex === undefined) {\n\t\t\t\tseenIds.set(id, index);\n\t\t\t} else {\n\t\t\t\tblockers.push(`duplicate lane id ${id} at indexes ${firstIndex} and ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tif (lane.task.trim() === \"\") {\n\t\t\tblockers.push(`${label} has empty task`);\n\t\t}\n\n\t\tconst seenDependencies = new Set<string>();\n\t\tfor (const dependency of lane.dependsOn ?? []) {\n\t\t\tconst dependencyId = dependency.trim();\n\t\t\tif (dependencyId === \"\") {\n\t\t\t\tblockers.push(`${label} has empty dependency id`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (dependencyId === id) {\n\t\t\t\tblockers.push(`${label} depends on itself`);\n\t\t\t}\n\t\t\tif (seenDependencies.has(dependencyId)) {\n\t\t\t\tblockers.push(`${label} repeats dependency ${dependencyId}`);\n\t\t\t}\n\t\t\tseenDependencies.add(dependencyId);\n\t\t}\n\t}\n\n\treturn blockers;\n}\n\nfunction prepareLane(\n\tspec: SubagentLaneSpec,\n\tindex: number,\n\trunId: string,\n\tinventory: CapabilityInventory,\n\tspawnReceipt: LaneSpawnReceipt | undefined,\n\tblockers: string[],\n\twarnings: string[],\n): PreparedLane {\n\tconst assignment = resolveSubagentRoleAssignment(spec.role);\n\tif ((spec.writeScope?.length ?? 0) > 0 && !assignment.writesProductFiles) {\n\t\tblockers.push(`lane ${spec.id} role ${spec.role} cannot write product files`);\n\t}\n\tconst dependsOn = uniqueSorted(spec.dependsOn ?? []);\n\n\tconst profile = resolveLoadoutProfile(spec, assignment, blockers);\n\tconst applied = applyLoadoutProfile(profile, inventory, { grantAuthority: spec.grantAuthority });\n\tblockers.push(...applied.blockers.map((blocker) => `lane ${spec.id}: ${blocker}`));\n\twarnings.push(...applied.warnings.map((warning) => `lane ${spec.id}: ${warning}`));\n\n\tconst schedulerFields = deriveSchedulerFields({\n\t\trole: assignment.loadoutRole,\n\t\tassignedReadPaths: spec.readScope,\n\t\tassignedWritePaths: spec.writeScope,\n\t});\n\n\tconst grant = buildSubagentLaneGrant(spec.id, assignment.loadoutRole, spec.task, applied, schedulerFields, {\n\t\tallowedReadPaths: spec.readScope,\n\t\tallowedWritePaths: spec.writeScope,\n\t\tblockedPaths: spec.blockedPaths,\n\t\tevidenceOutputPattern: spec.evidenceOutput ?? profile.evidence?.outputPattern,\n\t\trunId,\n\t\tprofile,\n\t\tagentName: spec.agentName ?? assignment.agentName,\n\t\tcontextInheritance: spec.contextInheritance ?? assignment.contextInheritance,\n\t\tspawnReceipt,\n\t\tevidenceGates: assignment.evidenceGates,\n\t\tdependsOn,\n\t\tacceptance: spec.acceptance,\n\t});\n\n\treturn { index, spec, grant, dependsOn };\n}\n\nfunction resolveLoadoutProfile(\n\tspec: SubagentLaneSpec,\n\tassignment: SubagentRoleAssignment,\n\tblockers: string[],\n): LoadoutProfile {\n\tconst loadoutName = spec.loadoutName ?? assignment.loadoutName;\n\tconst profile = BUILTIN_LOADOUTS[loadoutName];\n\tif (profile) return profile;\n\tblockers.push(`lane ${spec.id}: unknown loadout ${loadoutName}`);\n\treturn BUILTIN_LOADOUTS.none;\n}\n\nfunction findDependencyBlockers(lanes: readonly PreparedLane[]): string[] {\n\tconst ids = new Set(lanes.map((lane) => lane.spec.id));\n\tconst blockers: string[] = [];\n\tfor (const lane of lanes) {\n\t\tfor (const dependency of lane.dependsOn) {\n\t\t\tif (!ids.has(dependency)) {\n\t\t\t\tblockers.push(`lane ${lane.spec.id} depends on missing lane ${dependency}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn blockers;\n}\n\nfunction applyReceiptConsumerDependencies(lanes: readonly PreparedLane[]): PreparedLane[] {\n\tconst receiptProducerIds = lanes\n\t\t.filter((lane) => lane.grant.evidenceOutput !== undefined && !isReceiptConsumerRole(lane.spec.role))\n\t\t.map((lane) => lane.spec.id);\n\n\treturn lanes.map((lane) => {\n\t\tif (!isReceiptReadingConsumer(lane) || receiptProducerIds.length === 0) return lane;\n\t\tconst dependsOn = uniqueSorted([\n\t\t\t...lane.dependsOn,\n\t\t\t...receiptProducerIds.filter((producerId) => producerId !== lane.spec.id),\n\t\t]);\n\t\tif (arrayEquals(dependsOn, lane.dependsOn)) return lane;\n\t\treturn {\n\t\t\t...lane,\n\t\t\tdependsOn,\n\t\t\tgrant: {\n\t\t\t\t...lane.grant,\n\t\t\t\tdependsOn,\n\t\t\t},\n\t\t};\n\t});\n}\n\nfunction isReceiptReadingConsumer(lane: PreparedLane): boolean {\n\tif (!isReceiptConsumerRole(lane.spec.role)) return false;\n\treturn (lane.spec.readScope ?? []).some(isReceiptPath);\n}\n\nfunction isReceiptConsumerRole(role: SubagentOrchestrationRole): boolean {\n\treturn role === \"critic\" || role === \"visual-qa\" || role === \"rhwp-doc\";\n}\n\nfunction isReceiptPath(path: string): boolean {\n\tconst normalized = normalizePath(path);\n\treturn normalized === \".omk/runs\" || normalized.startsWith(\".omk/runs/\") || normalized.includes(\"/.omk/runs/\");\n}\n\nfunction schedulePreparedLanes(\n\tlanes: readonly PreparedLane[],\n\tmaxParallelLanes: number | undefined,\n\tblockers: string[],\n): SubagentScheduleBatch[] {\n\tconst scheduled = new Set<string>();\n\tconst batches: SubagentScheduleBatch[] = [];\n\n\twhile (scheduled.size < lanes.length) {\n\t\tconst ready = lanes\n\t\t\t.filter(\n\t\t\t\t(lane) => !scheduled.has(lane.spec.id) && lane.dependsOn.every((dependency) => scheduled.has(dependency)),\n\t\t\t)\n\t\t\t.sort((left, right) => (left.spec.id < right.spec.id ? -1 : left.spec.id > right.spec.id ? 1 : 0));\n\t\tif (ready.length === 0) {\n\t\t\tconst remaining = lanes.filter((lane) => !scheduled.has(lane.spec.id)).map((lane) => lane.spec.id);\n\t\t\tblockers.push(`lane dependency cycle or unsatisfied dependency among: ${remaining.join(\", \")}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst serialized = ready.find((lane) => !lane.grant.scheduler.parallelizable);\n\t\tif (serialized) {\n\t\t\tbatches.push({\n\t\t\t\tindex: batches.length,\n\t\t\t\tlaneIds: [serialized.spec.id],\n\t\t\t\treason: \"serialized-writer\",\n\t\t\t});\n\t\t\tscheduled.add(serialized.spec.id);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst selected: PreparedLane[] = [];\n\t\tfor (const lane of ready) {\n\t\t\tif (maxParallelLanes !== undefined && selected.length >= maxParallelLanes) break;\n\t\t\tif (!selected.some((selectedLane) => lanesConflict(selectedLane, lane))) {\n\t\t\t\tselected.push(lane);\n\t\t\t}\n\t\t}\n\t\tconst batchLanes = selected.length > 0 ? selected : [ready[0]];\n\t\tfor (const lane of batchLanes) scheduled.add(lane.spec.id);\n\t\tbatches.push({\n\t\t\tindex: batches.length,\n\t\t\tlaneIds: batchLanes.map((lane) => lane.spec.id),\n\t\t\treason:\n\t\t\t\tmaxParallelLanes !== undefined && ready.length > batchLanes.length ? \"parallel-limit\" : \"ready-parallel\",\n\t\t});\n\t}\n\n\treturn batches;\n}\n\nfunction lanesConflict(left: PreparedLane, right: PreparedLane): boolean {\n\treturn (\n\t\tpathsConflict(\n\t\t\tleft.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...right.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...right.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t) ||\n\t\tpathsConflict(\n\t\t\tright.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...left.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...left.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t)\n\t);\n}\n\nfunction pathsConflict(writers: readonly string[], candidates: readonly string[]): boolean {\n\tfor (const writer of writers) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (pathIntersects(writer, candidate)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction pathIntersects(left: string, right: string): boolean {\n\tconst normalizedLeft = normalizePath(left);\n\tconst normalizedRight = normalizePath(right);\n\treturn (\n\t\tnormalizedLeft === normalizedRight ||\n\t\tnormalizedLeft.startsWith(`${normalizedRight}/`) ||\n\t\tnormalizedRight.startsWith(`${normalizedLeft}/`)\n\t);\n}\n\nfunction buildRouteFeatures(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n): SubagentRouteFeatures {\n\tconst nodeCount = lanes.length;\n\tconst edgeCount = lanes.reduce((sum, lane) => sum + lane.dependsOn.length, 0);\n\tconst width = batches.reduce((max, batch) => Math.max(max, batch.laneIds.length), 0);\n\tconst criticalDepth = batches.length;\n\tconst parallelizable = lanes.filter((lane) => lane.grant.scheduler.parallelizable).length;\n\tconst parallelRatio = nodeCount === 0 ? 1 : parallelizable / nodeCount;\n\tconst couplingDensity = nodeCount <= 1 ? 0 : edgeCount / (nodeCount * (nodeCount - 1));\n\tconst topology = selectTopology(lanes, batches, width, criticalDepth, edgeCount);\n\n\treturn {\n\t\ttopology,\n\t\twidth,\n\t\tcriticalDepth,\n\t\tcouplingDensity: round(couplingDensity),\n\t\tparallelRatio: round(parallelRatio),\n\t\tnodeCount,\n\t\tedgeCount,\n\t};\n}\n\nfunction selectTopology(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n\twidth: number,\n\tcriticalDepth: number,\n\tedgeCount: number,\n): SubagentSchedulerTopology {\n\tif (lanes.length <= 1 || width <= 1) return \"serial\";\n\tif (edgeCount === 0 && criticalDepth === 1) return \"parallel\";\n\tif (isMapReduceShape(lanes, batches)) return \"map-reduce\";\n\treturn \"hybrid\";\n}\n\nfunction isMapReduceShape(lanes: readonly PreparedLane[], batches: readonly SubagentScheduleBatch[]): boolean {\n\tif (batches.length < 2) return false;\n\tconst firstBatch = batches[0];\n\tconst finalBatch = batches[batches.length - 1];\n\tif (firstBatch.laneIds.length < 2 || finalBatch.laneIds.length !== 1) return false;\n\tconst finalLane = lanes.find((lane) => lane.spec.id === finalBatch.laneIds[0]);\n\tif (!finalLane) return false;\n\treturn firstBatch.laneIds.every((laneId) => finalLane.dependsOn.includes(laneId));\n}\n\nfunction normalizePath(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\");\n}\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000;\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n\t\t.map((value) => value.trim())\n\t\t.filter((value) => value !== \"\")\n\t\t.sort();\n}\n\nfunction arrayEquals(left: readonly string[], right: readonly string[]): boolean {\n\treturn left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
1
+ {"version":3,"file":"subagent-orchestration.d.ts","sourceRoot":"","sources":["../../src/core/subagent-orchestration.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tbuildSubagentLaneGrant,\n\ttype LaneContextInheritanceMode,\n\ttype LaneEvidenceGate,\n\ttype LaneSpawnReceipt,\n\ttype SubagentLaneGrant,\n} from \"./loadout-runtime.ts\";\nimport {\n\tapplyLoadoutProfile,\n\tBUILTIN_LOADOUTS,\n\ttype CapabilityInventory,\n\tderiveSchedulerFields,\n\ttype LoadoutProfile,\n\ttype LoadoutRole,\n} from \"./loadouts.ts\";\nimport type { SubagentLaneSpec, SubagentOrchestrationRole } from \"./subagent-lane-contract.ts\";\n\nexport type { SubagentOrchestrationRole };\n\nexport type SubagentSchedulerTopology = \"serial\" | \"parallel\" | \"map-reduce\" | \"hybrid\";\n\nexport interface SubagentRoleAssignment {\n\treadonly role: SubagentOrchestrationRole;\n\treadonly loadoutRole: LoadoutRole;\n\treadonly loadoutName: string;\n\treadonly agentName: string;\n\treadonly contextInheritance: LaneContextInheritanceMode;\n\treadonly evidenceGates: readonly LaneEvidenceGate[];\n\treadonly writesProductFiles: boolean;\n}\n\nexport type { SubagentLaneSpec };\n\nexport interface SpawnGateDecision {\n\treadonly outcome: \"allowed\" | \"rejected\";\n\treadonly reason: string;\n\treadonly planRequired: boolean;\n\treadonly missingFields: readonly string[];\n}\n\nexport interface SubagentScheduleBatch {\n\treadonly index: number;\n\treadonly laneIds: readonly string[];\n\treadonly reason: \"ready-parallel\" | \"serialized-writer\" | \"parallel-limit\";\n}\n\nexport interface SubagentRouteFeatures {\n\treadonly topology: SubagentSchedulerTopology;\n\treadonly width: number;\n\treadonly criticalDepth: number;\n\treadonly couplingDensity: number;\n\treadonly parallelRatio: number;\n\treadonly nodeCount: number;\n\treadonly edgeCount: number;\n}\n\nexport interface BuildSubagentOrchestrationPlanInput {\n\treadonly runId: string;\n\treadonly lanes: readonly SubagentLaneSpec[];\n\treadonly inventory: CapabilityInventory;\n\treadonly spawnPlan?: LaneSpawnReceipt;\n\treadonly spawnThreshold?: number;\n\treadonly maxParallelLanes?: number;\n}\n\nexport interface SubagentOrchestrationPlan {\n\treadonly laneGrants: readonly SubagentLaneGrant[];\n\treadonly batches: readonly SubagentScheduleBatch[];\n\treadonly route: SubagentRouteFeatures;\n\treadonly spawnGate: SpawnGateDecision;\n\treadonly blockers: readonly string[];\n\treadonly warnings: readonly string[];\n}\n\nconst DEFAULT_SPAWN_THRESHOLD = 4;\n\nconst ROLE_ASSIGNMENTS: Readonly<Record<SubagentOrchestrationRole, SubagentRoleAssignment>> = {\n\tplanner: {\n\t\trole: \"planner\",\n\t\tloadoutRole: \"planner\",\n\t\tloadoutName: \"plan\",\n\t\tagentName: \"omk-planner\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\tarchitect: {\n\t\trole: \"architect\",\n\t\tloadoutRole: \"architect\",\n\t\tloadoutName: \"architect\",\n\t\tagentName: \"omk-architect\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\texecutor: {\n\t\trole: \"executor\",\n\t\tloadoutRole: \"executor\",\n\t\tloadoutName: \"executor\",\n\t\tagentName: \"omk-executor\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tcritic: {\n\t\trole: \"critic\",\n\t\tloadoutRole: \"critic\",\n\t\tloadoutName: \"critic\",\n\t\tagentName: \"omk-critic\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"visual-qa\": {\n\t\trole: \"visual-qa\",\n\t\tloadoutRole: \"visual-qa\",\n\t\tloadoutName: \"visual-qa\",\n\t\tagentName: \"omk-visual-qa\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"rhwp-doc\": {\n\t\trole: \"rhwp-doc\",\n\t\tloadoutRole: \"rhwp-doc\",\n\t\tloadoutName: \"rhwp-doc\",\n\t\tagentName: \"omk-rhwp-doc\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tsecurity: {\n\t\trole: \"security\",\n\t\tloadoutRole: \"security\",\n\t\tloadoutName: \"security\",\n\t\tagentName: \"omk-security\",\n\t\tcontextInheritance: \"none\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"package-maintainer\": {\n\t\trole: \"package-maintainer\",\n\t\tloadoutRole: \"package-maintainer\",\n\t\tloadoutName: \"package-maintainer\",\n\t\tagentName: \"omk-package-maintainer\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n};\n\nconst REQUIRED_SPAWN_PLAN_STRING_FIELDS = [\n\t\"whyParallel\",\n\t\"whyNotLocal\",\n\t\"independence\",\n\t\"expectedReceiptShape\",\n] as const;\n\ninterface PreparedLane {\n\treadonly index: number;\n\treadonly spec: SubagentLaneSpec;\n\treadonly grant: SubagentLaneGrant;\n\treadonly dependsOn: readonly string[];\n}\n\nexport function resolveSubagentRoleAssignment(role: SubagentOrchestrationRole): SubagentRoleAssignment {\n\treturn ROLE_ASSIGNMENTS[role];\n}\n\nexport function buildSubagentOrchestrationPlan(input: BuildSubagentOrchestrationPlanInput): SubagentOrchestrationPlan {\n\tif (\n\t\tinput.maxParallelLanes !== undefined &&\n\t\t(!Number.isInteger(input.maxParallelLanes) || input.maxParallelLanes < 1)\n\t) {\n\t\tthrow new RangeError(\"maxParallelLanes must be a positive integer\");\n\t}\n\n\tconst blockers: string[] = [];\n\tconst warnings: string[] = [];\n\tblockers.push(...validateLaneIntake(input.lanes));\n\tconst spawnGate = evaluateSpawnGate({\n\t\tchildCount: input.lanes.length,\n\t\tplan: input.spawnPlan,\n\t\tthreshold: input.spawnThreshold ?? DEFAULT_SPAWN_THRESHOLD,\n\t});\n\tif (spawnGate.outcome === \"rejected\") blockers.push(spawnGate.reason);\n\n\tconst prepared = input.lanes.map((lane, index) =>\n\t\tprepareLane(lane, index, input.runId, input.inventory, input.spawnPlan, blockers, warnings),\n\t);\n\tblockers.push(...findDependencyBlockers(prepared));\n\n\tconst scheduledLanes = applyReceiptConsumerDependencies(prepared);\n\tconst batches = schedulePreparedLanes(scheduledLanes, input.maxParallelLanes, blockers);\n\tconst route = buildRouteFeatures(scheduledLanes, batches);\n\n\treturn {\n\t\tlaneGrants: scheduledLanes.map((lane) => lane.grant),\n\t\tbatches,\n\t\troute,\n\t\tspawnGate,\n\t\tblockers: uniqueSorted(blockers),\n\t\twarnings: uniqueSorted(warnings),\n\t};\n}\n\nexport function evaluateSpawnGate(request: {\n\treadonly childCount: number;\n\treadonly plan?: LaneSpawnReceipt;\n\treadonly threshold?: number;\n}): SpawnGateDecision {\n\tconst threshold = request.threshold ?? DEFAULT_SPAWN_THRESHOLD;\n\tif (!Number.isInteger(request.childCount) || request.childCount < 0) {\n\t\tthrow new RangeError(\"childCount must be a non-negative integer\");\n\t}\n\tif (!Number.isInteger(threshold) || threshold < 1) {\n\t\tthrow new RangeError(\"threshold must be a positive integer\");\n\t}\n\n\tconst planRequired = request.childCount > threshold;\n\tif (!planRequired) {\n\t\treturn {\n\t\t\toutcome: \"allowed\",\n\t\t\treason: `batch of ${request.childCount} is at or below threshold ${threshold}`,\n\t\t\tplanRequired: false,\n\t\t\tmissingFields: [],\n\t\t};\n\t}\n\n\tconst missingFields = findMissingSpawnPlanFields(request.plan);\n\tif (missingFields.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"rejected\",\n\t\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and the spawn-plan receipt is ${\n\t\t\t\trequest.plan ? `incomplete (${missingFields.join(\", \")})` : \"missing\"\n\t\t\t}`,\n\t\t\tplanRequired: true,\n\t\t\tmissingFields,\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allowed\",\n\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and a complete spawn-plan receipt was provided`,\n\t\tplanRequired: true,\n\t\tmissingFields: [],\n\t};\n}\n\nexport function findMissingSpawnPlanFields(plan: LaneSpawnReceipt | undefined): string[] {\n\tif (!plan) return [...REQUIRED_SPAWN_PLAN_STRING_FIELDS, \"maxInlineTokens\"];\n\tconst missing: string[] = [];\n\tfor (const field of REQUIRED_SPAWN_PLAN_STRING_FIELDS) {\n\t\tconst value = plan[field];\n\t\tif (value.trim().length === 0) missing.push(field);\n\t}\n\tif (!Number.isFinite(plan.maxInlineTokens) || plan.maxInlineTokens <= 0) {\n\t\tmissing.push(\"maxInlineTokens\");\n\t}\n\treturn missing;\n}\n\nfunction validateLaneIntake(lanes: readonly SubagentLaneSpec[]): string[] {\n\tconst blockers: string[] = [];\n\tconst seenIds = new Map<string, number>();\n\n\tfor (const [index, lane] of lanes.entries()) {\n\t\tconst id = lane.id.trim();\n\t\tconst label = id === \"\" ? `lane at index ${index}` : `lane ${id}`;\n\t\tif (id === \"\") {\n\t\t\tblockers.push(`lane at index ${index} has empty id`);\n\t\t} else {\n\t\t\tconst firstIndex = seenIds.get(id);\n\t\t\tif (firstIndex === undefined) {\n\t\t\t\tseenIds.set(id, index);\n\t\t\t} else {\n\t\t\t\tblockers.push(`duplicate lane id ${id} at indexes ${firstIndex} and ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tif (lane.task.trim() === \"\") {\n\t\t\tblockers.push(`${label} has empty task`);\n\t\t}\n\n\t\tconst seenDependencies = new Set<string>();\n\t\tfor (const dependency of lane.dependsOn ?? []) {\n\t\t\tconst dependencyId = dependency.trim();\n\t\t\tif (dependencyId === \"\") {\n\t\t\t\tblockers.push(`${label} has empty dependency id`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (dependencyId === id) {\n\t\t\t\tblockers.push(`${label} depends on itself`);\n\t\t\t}\n\t\t\tif (seenDependencies.has(dependencyId)) {\n\t\t\t\tblockers.push(`${label} repeats dependency ${dependencyId}`);\n\t\t\t}\n\t\t\tseenDependencies.add(dependencyId);\n\t\t}\n\t}\n\n\treturn blockers;\n}\n\nfunction prepareLane(\n\tspec: SubagentLaneSpec,\n\tindex: number,\n\trunId: string,\n\tinventory: CapabilityInventory,\n\tspawnReceipt: LaneSpawnReceipt | undefined,\n\tblockers: string[],\n\twarnings: string[],\n): PreparedLane {\n\tconst assignment = resolveSubagentRoleAssignment(spec.role);\n\tif ((spec.writeScope?.length ?? 0) > 0 && !assignment.writesProductFiles) {\n\t\tblockers.push(`lane ${spec.id} role ${spec.role} cannot write product files`);\n\t}\n\tconst dependsOn = uniqueSorted(spec.dependsOn ?? []);\n\n\tconst profile = resolveLoadoutProfile(spec, assignment, blockers);\n\tconst applied = applyLoadoutProfile(profile, inventory, { grantAuthority: spec.grantAuthority });\n\tblockers.push(...applied.blockers.map((blocker) => `lane ${spec.id}: ${blocker}`));\n\twarnings.push(...applied.warnings.map((warning) => `lane ${spec.id}: ${warning}`));\n\n\tconst schedulerFields = deriveSchedulerFields({\n\t\trole: assignment.loadoutRole,\n\t\tassignedReadPaths: spec.readScope,\n\t\tassignedWritePaths: spec.writeScope,\n\t});\n\n\tconst grant = buildSubagentLaneGrant(spec.id, assignment.loadoutRole, spec.task, applied, schedulerFields, {\n\t\tallowedReadPaths: spec.readScope,\n\t\tallowedWritePaths: spec.writeScope,\n\t\tblockedPaths: spec.blockedPaths,\n\t\tevidenceOutputPattern: spec.evidenceOutput ?? profile.evidence?.outputPattern,\n\t\trunId,\n\t\tprofile,\n\t\tagentName: spec.agentName ?? assignment.agentName,\n\t\tcontextInheritance: spec.contextInheritance ?? assignment.contextInheritance,\n\t\tspawnReceipt,\n\t\tevidenceGates: assignment.evidenceGates,\n\t\tdependsOn,\n\t\tacceptance: spec.acceptance,\n\t});\n\n\treturn { index, spec, grant, dependsOn };\n}\n\nfunction resolveLoadoutProfile(\n\tspec: SubagentLaneSpec,\n\tassignment: SubagentRoleAssignment,\n\tblockers: string[],\n): LoadoutProfile {\n\tconst loadoutName = spec.loadoutName ?? assignment.loadoutName;\n\tconst profile = BUILTIN_LOADOUTS[loadoutName];\n\tif (profile) return profile;\n\tblockers.push(`lane ${spec.id}: unknown loadout ${loadoutName}`);\n\treturn BUILTIN_LOADOUTS.none;\n}\n\nfunction findDependencyBlockers(lanes: readonly PreparedLane[]): string[] {\n\tconst ids = new Set(lanes.map((lane) => lane.spec.id));\n\tconst blockers: string[] = [];\n\tfor (const lane of lanes) {\n\t\tfor (const dependency of lane.dependsOn) {\n\t\t\tif (!ids.has(dependency)) {\n\t\t\t\tblockers.push(`lane ${lane.spec.id} depends on missing lane ${dependency}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn blockers;\n}\n\nfunction applyReceiptConsumerDependencies(lanes: readonly PreparedLane[]): PreparedLane[] {\n\tconst receiptProducerIds = lanes\n\t\t.filter((lane) => lane.grant.evidenceOutput !== undefined && !isReceiptConsumerRole(lane.spec.role))\n\t\t.map((lane) => lane.spec.id);\n\n\treturn lanes.map((lane) => {\n\t\tif (!isReceiptReadingConsumer(lane) || receiptProducerIds.length === 0) return lane;\n\t\tconst dependsOn = uniqueSorted([\n\t\t\t...lane.dependsOn,\n\t\t\t...receiptProducerIds.filter((producerId) => producerId !== lane.spec.id),\n\t\t]);\n\t\tif (arrayEquals(dependsOn, lane.dependsOn)) return lane;\n\t\treturn {\n\t\t\t...lane,\n\t\t\tdependsOn,\n\t\t\tgrant: {\n\t\t\t\t...lane.grant,\n\t\t\t\tdependsOn,\n\t\t\t},\n\t\t};\n\t});\n}\n\nfunction isReceiptReadingConsumer(lane: PreparedLane): boolean {\n\tif (!isReceiptConsumerRole(lane.spec.role)) return false;\n\treturn (lane.spec.readScope ?? []).some(isReceiptPath);\n}\n\nfunction isReceiptConsumerRole(role: SubagentOrchestrationRole): boolean {\n\treturn role === \"critic\" || role === \"visual-qa\" || role === \"rhwp-doc\";\n}\n\nfunction isReceiptPath(path: string): boolean {\n\tconst normalized = normalizePath(path);\n\treturn normalized === \".omk/runs\" || normalized.startsWith(\".omk/runs/\") || normalized.includes(\"/.omk/runs/\");\n}\n\nfunction schedulePreparedLanes(\n\tlanes: readonly PreparedLane[],\n\tmaxParallelLanes: number | undefined,\n\tblockers: string[],\n): SubagentScheduleBatch[] {\n\tconst scheduled = new Set<string>();\n\tconst batches: SubagentScheduleBatch[] = [];\n\n\twhile (scheduled.size < lanes.length) {\n\t\tconst ready = lanes\n\t\t\t.filter(\n\t\t\t\t(lane) => !scheduled.has(lane.spec.id) && lane.dependsOn.every((dependency) => scheduled.has(dependency)),\n\t\t\t)\n\t\t\t.sort((left, right) => (left.spec.id < right.spec.id ? -1 : left.spec.id > right.spec.id ? 1 : 0));\n\t\tif (ready.length === 0) {\n\t\t\tconst remaining = lanes.filter((lane) => !scheduled.has(lane.spec.id)).map((lane) => lane.spec.id);\n\t\t\tblockers.push(`lane dependency cycle or unsatisfied dependency among: ${remaining.join(\", \")}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst serialized = ready.find((lane) => !lane.grant.scheduler.parallelizable);\n\t\tif (serialized) {\n\t\t\tbatches.push({\n\t\t\t\tindex: batches.length,\n\t\t\t\tlaneIds: [serialized.spec.id],\n\t\t\t\treason: \"serialized-writer\",\n\t\t\t});\n\t\t\tscheduled.add(serialized.spec.id);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst selected: PreparedLane[] = [];\n\t\tfor (const lane of ready) {\n\t\t\tif (maxParallelLanes !== undefined && selected.length >= maxParallelLanes) break;\n\t\t\tif (!selected.some((selectedLane) => lanesConflict(selectedLane, lane))) {\n\t\t\t\tselected.push(lane);\n\t\t\t}\n\t\t}\n\t\tconst batchLanes = selected.length > 0 ? selected : [ready[0]];\n\t\tfor (const lane of batchLanes) scheduled.add(lane.spec.id);\n\t\tbatches.push({\n\t\t\tindex: batches.length,\n\t\t\tlaneIds: batchLanes.map((lane) => lane.spec.id),\n\t\t\treason:\n\t\t\t\tmaxParallelLanes !== undefined && ready.length > batchLanes.length ? \"parallel-limit\" : \"ready-parallel\",\n\t\t});\n\t}\n\n\treturn batches;\n}\n\nfunction lanesConflict(left: PreparedLane, right: PreparedLane): boolean {\n\treturn (\n\t\tpathsConflict(\n\t\t\tleft.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...right.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...right.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t) ||\n\t\tpathsConflict(\n\t\t\tright.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...left.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...left.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t)\n\t);\n}\n\nfunction pathsConflict(writers: readonly string[], candidates: readonly string[]): boolean {\n\tfor (const writer of writers) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (pathIntersects(writer, candidate)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction pathIntersects(left: string, right: string): boolean {\n\tconst normalizedLeft = normalizePath(left);\n\tconst normalizedRight = normalizePath(right);\n\treturn (\n\t\tnormalizedLeft === normalizedRight ||\n\t\tnormalizedLeft.startsWith(`${normalizedRight}/`) ||\n\t\tnormalizedRight.startsWith(`${normalizedLeft}/`)\n\t);\n}\n\nfunction buildRouteFeatures(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n): SubagentRouteFeatures {\n\tconst nodeCount = lanes.length;\n\tconst edgeCount = lanes.reduce((sum, lane) => sum + lane.dependsOn.length, 0);\n\tconst width = batches.reduce((max, batch) => Math.max(max, batch.laneIds.length), 0);\n\tconst criticalDepth = batches.length;\n\tconst parallelizable = lanes.filter((lane) => lane.grant.scheduler.parallelizable).length;\n\tconst parallelRatio = nodeCount === 0 ? 1 : parallelizable / nodeCount;\n\tconst couplingDensity = nodeCount <= 1 ? 0 : edgeCount / (nodeCount * (nodeCount - 1));\n\tconst topology = selectTopology(lanes, batches, width, criticalDepth, edgeCount);\n\n\treturn {\n\t\ttopology,\n\t\twidth,\n\t\tcriticalDepth,\n\t\tcouplingDensity: round(couplingDensity),\n\t\tparallelRatio: round(parallelRatio),\n\t\tnodeCount,\n\t\tedgeCount,\n\t};\n}\n\nfunction selectTopology(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n\twidth: number,\n\tcriticalDepth: number,\n\tedgeCount: number,\n): SubagentSchedulerTopology {\n\tif (lanes.length <= 1 || width <= 1) return \"serial\";\n\tif (edgeCount === 0 && criticalDepth === 1) return \"parallel\";\n\tif (isMapReduceShape(lanes, batches)) return \"map-reduce\";\n\treturn \"hybrid\";\n}\n\nfunction isMapReduceShape(lanes: readonly PreparedLane[], batches: readonly SubagentScheduleBatch[]): boolean {\n\tif (batches.length < 2) return false;\n\tconst firstBatch = batches[0];\n\tconst finalBatch = batches[batches.length - 1];\n\tif (firstBatch.laneIds.length < 2 || finalBatch.laneIds.length !== 1) return false;\n\tconst finalLane = lanes.find((lane) => lane.spec.id === finalBatch.laneIds[0]);\n\tif (!finalLane) return false;\n\treturn firstBatch.laneIds.every((laneId) => finalLane.dependsOn.includes(laneId));\n}\n\nfunction normalizePath(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\");\n}\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000;\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n\t\t.map((value) => value.trim())\n\t\t.filter((value) => value !== \"\")\n\t\t.sort();\n}\n\nfunction arrayEquals(left: readonly string[], right: readonly string[]): boolean {\n\treturn left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"subagent-orchestration.js","sourceRoot":"","sources":["../../src/core/subagent-orchestration.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tbuildSubagentLaneGrant,\n\ttype LaneContextInheritanceMode,\n\ttype LaneEvidenceGate,\n\ttype LaneSpawnReceipt,\n\ttype SubagentLaneGrant,\n} from \"./loadout-runtime.ts\";\nimport {\n\tapplyLoadoutProfile,\n\tBUILTIN_LOADOUTS,\n\ttype CapabilityInventory,\n\tderiveSchedulerFields,\n\ttype LoadoutAuthority,\n\ttype LoadoutProfile,\n\ttype LoadoutRole,\n} from \"./loadouts.ts\";\n\nexport type SubagentOrchestrationRole =\n\t| \"planner\"\n\t| \"architect\"\n\t| \"executor\"\n\t| \"critic\"\n\t| \"visual-qa\"\n\t| \"rhwp-doc\"\n\t| \"security\"\n\t| \"package-maintainer\";\n\nexport type SubagentSchedulerTopology = \"serial\" | \"parallel\" | \"map-reduce\" | \"hybrid\";\n\nexport interface SubagentRoleAssignment {\n\treadonly role: SubagentOrchestrationRole;\n\treadonly loadoutRole: LoadoutRole;\n\treadonly loadoutName: string;\n\treadonly agentName: string;\n\treadonly contextInheritance: LaneContextInheritanceMode;\n\treadonly evidenceGates: readonly LaneEvidenceGate[];\n\treadonly writesProductFiles: boolean;\n}\n\nexport interface SubagentLaneSpec {\n\treadonly id: string;\n\treadonly role: SubagentOrchestrationRole;\n\treadonly task: string;\n\treadonly dependsOn?: readonly string[];\n\treadonly readScope?: readonly string[];\n\treadonly writeScope?: readonly string[];\n\treadonly acceptance?: readonly string[];\n\treadonly evidenceOutput?: string;\n\treadonly blockedPaths?: readonly string[];\n\treadonly contextInheritance?: LaneContextInheritanceMode;\n\treadonly grantAuthority?: LoadoutAuthority;\n\treadonly loadoutName?: string;\n\treadonly agentName?: string;\n}\n\nexport interface SpawnGateDecision {\n\treadonly outcome: \"allowed\" | \"rejected\";\n\treadonly reason: string;\n\treadonly planRequired: boolean;\n\treadonly missingFields: readonly string[];\n}\n\nexport interface SubagentScheduleBatch {\n\treadonly index: number;\n\treadonly laneIds: readonly string[];\n\treadonly reason: \"ready-parallel\" | \"serialized-writer\" | \"parallel-limit\";\n}\n\nexport interface SubagentRouteFeatures {\n\treadonly topology: SubagentSchedulerTopology;\n\treadonly width: number;\n\treadonly criticalDepth: number;\n\treadonly couplingDensity: number;\n\treadonly parallelRatio: number;\n\treadonly nodeCount: number;\n\treadonly edgeCount: number;\n}\n\nexport interface BuildSubagentOrchestrationPlanInput {\n\treadonly runId: string;\n\treadonly lanes: readonly SubagentLaneSpec[];\n\treadonly inventory: CapabilityInventory;\n\treadonly spawnPlan?: LaneSpawnReceipt;\n\treadonly spawnThreshold?: number;\n\treadonly maxParallelLanes?: number;\n}\n\nexport interface SubagentOrchestrationPlan {\n\treadonly laneGrants: readonly SubagentLaneGrant[];\n\treadonly batches: readonly SubagentScheduleBatch[];\n\treadonly route: SubagentRouteFeatures;\n\treadonly spawnGate: SpawnGateDecision;\n\treadonly blockers: readonly string[];\n\treadonly warnings: readonly string[];\n}\n\nconst DEFAULT_SPAWN_THRESHOLD = 4;\n\nconst ROLE_ASSIGNMENTS: Readonly<Record<SubagentOrchestrationRole, SubagentRoleAssignment>> = {\n\tplanner: {\n\t\trole: \"planner\",\n\t\tloadoutRole: \"planner\",\n\t\tloadoutName: \"plan\",\n\t\tagentName: \"omk-planner\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\tarchitect: {\n\t\trole: \"architect\",\n\t\tloadoutRole: \"architect\",\n\t\tloadoutName: \"architect\",\n\t\tagentName: \"omk-architect\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\texecutor: {\n\t\trole: \"executor\",\n\t\tloadoutRole: \"executor\",\n\t\tloadoutName: \"executor\",\n\t\tagentName: \"omk-executor\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tcritic: {\n\t\trole: \"critic\",\n\t\tloadoutRole: \"critic\",\n\t\tloadoutName: \"critic\",\n\t\tagentName: \"omk-critic\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"visual-qa\": {\n\t\trole: \"visual-qa\",\n\t\tloadoutRole: \"visual-qa\",\n\t\tloadoutName: \"visual-qa\",\n\t\tagentName: \"omk-visual-qa\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"rhwp-doc\": {\n\t\trole: \"rhwp-doc\",\n\t\tloadoutRole: \"rhwp-doc\",\n\t\tloadoutName: \"rhwp-doc\",\n\t\tagentName: \"omk-rhwp-doc\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tsecurity: {\n\t\trole: \"security\",\n\t\tloadoutRole: \"security\",\n\t\tloadoutName: \"security\",\n\t\tagentName: \"omk-security\",\n\t\tcontextInheritance: \"none\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"package-maintainer\": {\n\t\trole: \"package-maintainer\",\n\t\tloadoutRole: \"package-maintainer\",\n\t\tloadoutName: \"package-maintainer\",\n\t\tagentName: \"omk-package-maintainer\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n};\n\nconst REQUIRED_SPAWN_PLAN_STRING_FIELDS = [\n\t\"whyParallel\",\n\t\"whyNotLocal\",\n\t\"independence\",\n\t\"expectedReceiptShape\",\n] as const;\n\ninterface PreparedLane {\n\treadonly index: number;\n\treadonly spec: SubagentLaneSpec;\n\treadonly grant: SubagentLaneGrant;\n\treadonly dependsOn: readonly string[];\n}\n\nexport function resolveSubagentRoleAssignment(role: SubagentOrchestrationRole): SubagentRoleAssignment {\n\treturn ROLE_ASSIGNMENTS[role];\n}\n\nexport function buildSubagentOrchestrationPlan(input: BuildSubagentOrchestrationPlanInput): SubagentOrchestrationPlan {\n\tif (\n\t\tinput.maxParallelLanes !== undefined &&\n\t\t(!Number.isInteger(input.maxParallelLanes) || input.maxParallelLanes < 1)\n\t) {\n\t\tthrow new RangeError(\"maxParallelLanes must be a positive integer\");\n\t}\n\n\tconst blockers: string[] = [];\n\tconst warnings: string[] = [];\n\tblockers.push(...validateLaneIntake(input.lanes));\n\tconst spawnGate = evaluateSpawnGate({\n\t\tchildCount: input.lanes.length,\n\t\tplan: input.spawnPlan,\n\t\tthreshold: input.spawnThreshold ?? DEFAULT_SPAWN_THRESHOLD,\n\t});\n\tif (spawnGate.outcome === \"rejected\") blockers.push(spawnGate.reason);\n\n\tconst prepared = input.lanes.map((lane, index) =>\n\t\tprepareLane(lane, index, input.runId, input.inventory, input.spawnPlan, blockers, warnings),\n\t);\n\tblockers.push(...findDependencyBlockers(prepared));\n\n\tconst scheduledLanes = applyReceiptConsumerDependencies(prepared);\n\tconst batches = schedulePreparedLanes(scheduledLanes, input.maxParallelLanes, blockers);\n\tconst route = buildRouteFeatures(scheduledLanes, batches);\n\n\treturn {\n\t\tlaneGrants: scheduledLanes.map((lane) => lane.grant),\n\t\tbatches,\n\t\troute,\n\t\tspawnGate,\n\t\tblockers: uniqueSorted(blockers),\n\t\twarnings: uniqueSorted(warnings),\n\t};\n}\n\nexport function evaluateSpawnGate(request: {\n\treadonly childCount: number;\n\treadonly plan?: LaneSpawnReceipt;\n\treadonly threshold?: number;\n}): SpawnGateDecision {\n\tconst threshold = request.threshold ?? DEFAULT_SPAWN_THRESHOLD;\n\tif (!Number.isInteger(request.childCount) || request.childCount < 0) {\n\t\tthrow new RangeError(\"childCount must be a non-negative integer\");\n\t}\n\tif (!Number.isInteger(threshold) || threshold < 1) {\n\t\tthrow new RangeError(\"threshold must be a positive integer\");\n\t}\n\n\tconst planRequired = request.childCount > threshold;\n\tif (!planRequired) {\n\t\treturn {\n\t\t\toutcome: \"allowed\",\n\t\t\treason: `batch of ${request.childCount} is at or below threshold ${threshold}`,\n\t\t\tplanRequired: false,\n\t\t\tmissingFields: [],\n\t\t};\n\t}\n\n\tconst missingFields = findMissingSpawnPlanFields(request.plan);\n\tif (missingFields.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"rejected\",\n\t\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and the spawn-plan receipt is ${\n\t\t\t\trequest.plan ? `incomplete (${missingFields.join(\", \")})` : \"missing\"\n\t\t\t}`,\n\t\t\tplanRequired: true,\n\t\t\tmissingFields,\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allowed\",\n\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and a complete spawn-plan receipt was provided`,\n\t\tplanRequired: true,\n\t\tmissingFields: [],\n\t};\n}\n\nexport function findMissingSpawnPlanFields(plan: LaneSpawnReceipt | undefined): string[] {\n\tif (!plan) return [...REQUIRED_SPAWN_PLAN_STRING_FIELDS, \"maxInlineTokens\"];\n\tconst missing: string[] = [];\n\tfor (const field of REQUIRED_SPAWN_PLAN_STRING_FIELDS) {\n\t\tconst value = plan[field];\n\t\tif (value.trim().length === 0) missing.push(field);\n\t}\n\tif (!Number.isFinite(plan.maxInlineTokens) || plan.maxInlineTokens <= 0) {\n\t\tmissing.push(\"maxInlineTokens\");\n\t}\n\treturn missing;\n}\n\nfunction validateLaneIntake(lanes: readonly SubagentLaneSpec[]): string[] {\n\tconst blockers: string[] = [];\n\tconst seenIds = new Map<string, number>();\n\n\tfor (const [index, lane] of lanes.entries()) {\n\t\tconst id = lane.id.trim();\n\t\tconst label = id === \"\" ? `lane at index ${index}` : `lane ${id}`;\n\t\tif (id === \"\") {\n\t\t\tblockers.push(`lane at index ${index} has empty id`);\n\t\t} else {\n\t\t\tconst firstIndex = seenIds.get(id);\n\t\t\tif (firstIndex === undefined) {\n\t\t\t\tseenIds.set(id, index);\n\t\t\t} else {\n\t\t\t\tblockers.push(`duplicate lane id ${id} at indexes ${firstIndex} and ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tif (lane.task.trim() === \"\") {\n\t\t\tblockers.push(`${label} has empty task`);\n\t\t}\n\n\t\tconst seenDependencies = new Set<string>();\n\t\tfor (const dependency of lane.dependsOn ?? []) {\n\t\t\tconst dependencyId = dependency.trim();\n\t\t\tif (dependencyId === \"\") {\n\t\t\t\tblockers.push(`${label} has empty dependency id`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (dependencyId === id) {\n\t\t\t\tblockers.push(`${label} depends on itself`);\n\t\t\t}\n\t\t\tif (seenDependencies.has(dependencyId)) {\n\t\t\t\tblockers.push(`${label} repeats dependency ${dependencyId}`);\n\t\t\t}\n\t\t\tseenDependencies.add(dependencyId);\n\t\t}\n\t}\n\n\treturn blockers;\n}\n\nfunction prepareLane(\n\tspec: SubagentLaneSpec,\n\tindex: number,\n\trunId: string,\n\tinventory: CapabilityInventory,\n\tspawnReceipt: LaneSpawnReceipt | undefined,\n\tblockers: string[],\n\twarnings: string[],\n): PreparedLane {\n\tconst assignment = resolveSubagentRoleAssignment(spec.role);\n\tif ((spec.writeScope?.length ?? 0) > 0 && !assignment.writesProductFiles) {\n\t\tblockers.push(`lane ${spec.id} role ${spec.role} cannot write product files`);\n\t}\n\tconst dependsOn = uniqueSorted(spec.dependsOn ?? []);\n\n\tconst profile = resolveLoadoutProfile(spec, assignment, blockers);\n\tconst applied = applyLoadoutProfile(profile, inventory, { grantAuthority: spec.grantAuthority });\n\tblockers.push(...applied.blockers.map((blocker) => `lane ${spec.id}: ${blocker}`));\n\twarnings.push(...applied.warnings.map((warning) => `lane ${spec.id}: ${warning}`));\n\n\tconst schedulerFields = deriveSchedulerFields({\n\t\trole: assignment.loadoutRole,\n\t\tassignedReadPaths: spec.readScope,\n\t\tassignedWritePaths: spec.writeScope,\n\t});\n\n\tconst grant = buildSubagentLaneGrant(spec.id, assignment.loadoutRole, spec.task, applied, schedulerFields, {\n\t\tallowedReadPaths: spec.readScope,\n\t\tallowedWritePaths: spec.writeScope,\n\t\tblockedPaths: spec.blockedPaths,\n\t\tevidenceOutputPattern: spec.evidenceOutput ?? profile.evidence?.outputPattern,\n\t\trunId,\n\t\tprofile,\n\t\tagentName: spec.agentName ?? assignment.agentName,\n\t\tcontextInheritance: spec.contextInheritance ?? assignment.contextInheritance,\n\t\tspawnReceipt,\n\t\tevidenceGates: assignment.evidenceGates,\n\t\tdependsOn,\n\t\tacceptance: spec.acceptance,\n\t});\n\n\treturn { index, spec, grant, dependsOn };\n}\n\nfunction resolveLoadoutProfile(\n\tspec: SubagentLaneSpec,\n\tassignment: SubagentRoleAssignment,\n\tblockers: string[],\n): LoadoutProfile {\n\tconst loadoutName = spec.loadoutName ?? assignment.loadoutName;\n\tconst profile = BUILTIN_LOADOUTS[loadoutName];\n\tif (profile) return profile;\n\tblockers.push(`lane ${spec.id}: unknown loadout ${loadoutName}`);\n\treturn BUILTIN_LOADOUTS.none;\n}\n\nfunction findDependencyBlockers(lanes: readonly PreparedLane[]): string[] {\n\tconst ids = new Set(lanes.map((lane) => lane.spec.id));\n\tconst blockers: string[] = [];\n\tfor (const lane of lanes) {\n\t\tfor (const dependency of lane.dependsOn) {\n\t\t\tif (!ids.has(dependency)) {\n\t\t\t\tblockers.push(`lane ${lane.spec.id} depends on missing lane ${dependency}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn blockers;\n}\n\nfunction applyReceiptConsumerDependencies(lanes: readonly PreparedLane[]): PreparedLane[] {\n\tconst receiptProducerIds = lanes\n\t\t.filter((lane) => lane.grant.evidenceOutput !== undefined && !isReceiptConsumerRole(lane.spec.role))\n\t\t.map((lane) => lane.spec.id);\n\n\treturn lanes.map((lane) => {\n\t\tif (!isReceiptReadingConsumer(lane) || receiptProducerIds.length === 0) return lane;\n\t\tconst dependsOn = uniqueSorted([\n\t\t\t...lane.dependsOn,\n\t\t\t...receiptProducerIds.filter((producerId) => producerId !== lane.spec.id),\n\t\t]);\n\t\tif (arrayEquals(dependsOn, lane.dependsOn)) return lane;\n\t\treturn {\n\t\t\t...lane,\n\t\t\tdependsOn,\n\t\t\tgrant: {\n\t\t\t\t...lane.grant,\n\t\t\t\tdependsOn,\n\t\t\t},\n\t\t};\n\t});\n}\n\nfunction isReceiptReadingConsumer(lane: PreparedLane): boolean {\n\tif (!isReceiptConsumerRole(lane.spec.role)) return false;\n\treturn (lane.spec.readScope ?? []).some(isReceiptPath);\n}\n\nfunction isReceiptConsumerRole(role: SubagentOrchestrationRole): boolean {\n\treturn role === \"critic\" || role === \"visual-qa\" || role === \"rhwp-doc\";\n}\n\nfunction isReceiptPath(path: string): boolean {\n\tconst normalized = normalizePath(path);\n\treturn normalized === \".omk/runs\" || normalized.startsWith(\".omk/runs/\") || normalized.includes(\"/.omk/runs/\");\n}\n\nfunction schedulePreparedLanes(\n\tlanes: readonly PreparedLane[],\n\tmaxParallelLanes: number | undefined,\n\tblockers: string[],\n): SubagentScheduleBatch[] {\n\tconst scheduled = new Set<string>();\n\tconst batches: SubagentScheduleBatch[] = [];\n\n\twhile (scheduled.size < lanes.length) {\n\t\tconst ready = lanes\n\t\t\t.filter(\n\t\t\t\t(lane) => !scheduled.has(lane.spec.id) && lane.dependsOn.every((dependency) => scheduled.has(dependency)),\n\t\t\t)\n\t\t\t.sort((left, right) => (left.spec.id < right.spec.id ? -1 : left.spec.id > right.spec.id ? 1 : 0));\n\t\tif (ready.length === 0) {\n\t\t\tconst remaining = lanes.filter((lane) => !scheduled.has(lane.spec.id)).map((lane) => lane.spec.id);\n\t\t\tblockers.push(`lane dependency cycle or unsatisfied dependency among: ${remaining.join(\", \")}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst serialized = ready.find((lane) => !lane.grant.scheduler.parallelizable);\n\t\tif (serialized) {\n\t\t\tbatches.push({\n\t\t\t\tindex: batches.length,\n\t\t\t\tlaneIds: [serialized.spec.id],\n\t\t\t\treason: \"serialized-writer\",\n\t\t\t});\n\t\t\tscheduled.add(serialized.spec.id);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst selected: PreparedLane[] = [];\n\t\tfor (const lane of ready) {\n\t\t\tif (maxParallelLanes !== undefined && selected.length >= maxParallelLanes) break;\n\t\t\tif (!selected.some((selectedLane) => lanesConflict(selectedLane, lane))) {\n\t\t\t\tselected.push(lane);\n\t\t\t}\n\t\t}\n\t\tconst batchLanes = selected.length > 0 ? selected : [ready[0]];\n\t\tfor (const lane of batchLanes) scheduled.add(lane.spec.id);\n\t\tbatches.push({\n\t\t\tindex: batches.length,\n\t\t\tlaneIds: batchLanes.map((lane) => lane.spec.id),\n\t\t\treason:\n\t\t\t\tmaxParallelLanes !== undefined && ready.length > batchLanes.length ? \"parallel-limit\" : \"ready-parallel\",\n\t\t});\n\t}\n\n\treturn batches;\n}\n\nfunction lanesConflict(left: PreparedLane, right: PreparedLane): boolean {\n\treturn (\n\t\tpathsConflict(\n\t\t\tleft.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...right.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...right.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t) ||\n\t\tpathsConflict(\n\t\t\tright.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...left.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...left.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t)\n\t);\n}\n\nfunction pathsConflict(writers: readonly string[], candidates: readonly string[]): boolean {\n\tfor (const writer of writers) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (pathIntersects(writer, candidate)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction pathIntersects(left: string, right: string): boolean {\n\tconst normalizedLeft = normalizePath(left);\n\tconst normalizedRight = normalizePath(right);\n\treturn (\n\t\tnormalizedLeft === normalizedRight ||\n\t\tnormalizedLeft.startsWith(`${normalizedRight}/`) ||\n\t\tnormalizedRight.startsWith(`${normalizedLeft}/`)\n\t);\n}\n\nfunction buildRouteFeatures(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n): SubagentRouteFeatures {\n\tconst nodeCount = lanes.length;\n\tconst edgeCount = lanes.reduce((sum, lane) => sum + lane.dependsOn.length, 0);\n\tconst width = batches.reduce((max, batch) => Math.max(max, batch.laneIds.length), 0);\n\tconst criticalDepth = batches.length;\n\tconst parallelizable = lanes.filter((lane) => lane.grant.scheduler.parallelizable).length;\n\tconst parallelRatio = nodeCount === 0 ? 1 : parallelizable / nodeCount;\n\tconst couplingDensity = nodeCount <= 1 ? 0 : edgeCount / (nodeCount * (nodeCount - 1));\n\tconst topology = selectTopology(lanes, batches, width, criticalDepth, edgeCount);\n\n\treturn {\n\t\ttopology,\n\t\twidth,\n\t\tcriticalDepth,\n\t\tcouplingDensity: round(couplingDensity),\n\t\tparallelRatio: round(parallelRatio),\n\t\tnodeCount,\n\t\tedgeCount,\n\t};\n}\n\nfunction selectTopology(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n\twidth: number,\n\tcriticalDepth: number,\n\tedgeCount: number,\n): SubagentSchedulerTopology {\n\tif (lanes.length <= 1 || width <= 1) return \"serial\";\n\tif (edgeCount === 0 && criticalDepth === 1) return \"parallel\";\n\tif (isMapReduceShape(lanes, batches)) return \"map-reduce\";\n\treturn \"hybrid\";\n}\n\nfunction isMapReduceShape(lanes: readonly PreparedLane[], batches: readonly SubagentScheduleBatch[]): boolean {\n\tif (batches.length < 2) return false;\n\tconst firstBatch = batches[0];\n\tconst finalBatch = batches[batches.length - 1];\n\tif (firstBatch.laneIds.length < 2 || finalBatch.laneIds.length !== 1) return false;\n\tconst finalLane = lanes.find((lane) => lane.spec.id === finalBatch.laneIds[0]);\n\tif (!finalLane) return false;\n\treturn firstBatch.laneIds.every((laneId) => finalLane.dependsOn.includes(laneId));\n}\n\nfunction normalizePath(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\");\n}\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000;\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n\t\t.map((value) => value.trim())\n\t\t.filter((value) => value !== \"\")\n\t\t.sort();\n}\n\nfunction arrayEquals(left: readonly string[], right: readonly string[]): boolean {\n\treturn left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
1
+ {"version":3,"file":"subagent-orchestration.js","sourceRoot":"","sources":["../../src/core/subagent-orchestration.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tbuildSubagentLaneGrant,\n\ttype LaneContextInheritanceMode,\n\ttype LaneEvidenceGate,\n\ttype LaneSpawnReceipt,\n\ttype SubagentLaneGrant,\n} from \"./loadout-runtime.ts\";\nimport {\n\tapplyLoadoutProfile,\n\tBUILTIN_LOADOUTS,\n\ttype CapabilityInventory,\n\tderiveSchedulerFields,\n\ttype LoadoutProfile,\n\ttype LoadoutRole,\n} from \"./loadouts.ts\";\nimport type { SubagentLaneSpec, SubagentOrchestrationRole } from \"./subagent-lane-contract.ts\";\n\nexport type { SubagentOrchestrationRole };\n\nexport type SubagentSchedulerTopology = \"serial\" | \"parallel\" | \"map-reduce\" | \"hybrid\";\n\nexport interface SubagentRoleAssignment {\n\treadonly role: SubagentOrchestrationRole;\n\treadonly loadoutRole: LoadoutRole;\n\treadonly loadoutName: string;\n\treadonly agentName: string;\n\treadonly contextInheritance: LaneContextInheritanceMode;\n\treadonly evidenceGates: readonly LaneEvidenceGate[];\n\treadonly writesProductFiles: boolean;\n}\n\nexport type { SubagentLaneSpec };\n\nexport interface SpawnGateDecision {\n\treadonly outcome: \"allowed\" | \"rejected\";\n\treadonly reason: string;\n\treadonly planRequired: boolean;\n\treadonly missingFields: readonly string[];\n}\n\nexport interface SubagentScheduleBatch {\n\treadonly index: number;\n\treadonly laneIds: readonly string[];\n\treadonly reason: \"ready-parallel\" | \"serialized-writer\" | \"parallel-limit\";\n}\n\nexport interface SubagentRouteFeatures {\n\treadonly topology: SubagentSchedulerTopology;\n\treadonly width: number;\n\treadonly criticalDepth: number;\n\treadonly couplingDensity: number;\n\treadonly parallelRatio: number;\n\treadonly nodeCount: number;\n\treadonly edgeCount: number;\n}\n\nexport interface BuildSubagentOrchestrationPlanInput {\n\treadonly runId: string;\n\treadonly lanes: readonly SubagentLaneSpec[];\n\treadonly inventory: CapabilityInventory;\n\treadonly spawnPlan?: LaneSpawnReceipt;\n\treadonly spawnThreshold?: number;\n\treadonly maxParallelLanes?: number;\n}\n\nexport interface SubagentOrchestrationPlan {\n\treadonly laneGrants: readonly SubagentLaneGrant[];\n\treadonly batches: readonly SubagentScheduleBatch[];\n\treadonly route: SubagentRouteFeatures;\n\treadonly spawnGate: SpawnGateDecision;\n\treadonly blockers: readonly string[];\n\treadonly warnings: readonly string[];\n}\n\nconst DEFAULT_SPAWN_THRESHOLD = 4;\n\nconst ROLE_ASSIGNMENTS: Readonly<Record<SubagentOrchestrationRole, SubagentRoleAssignment>> = {\n\tplanner: {\n\t\trole: \"planner\",\n\t\tloadoutRole: \"planner\",\n\t\tloadoutName: \"plan\",\n\t\tagentName: \"omk-planner\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\tarchitect: {\n\t\trole: \"architect\",\n\t\tloadoutRole: \"architect\",\n\t\tloadoutName: \"architect\",\n\t\tagentName: \"omk-architect\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\texecutor: {\n\t\trole: \"executor\",\n\t\tloadoutRole: \"executor\",\n\t\tloadoutName: \"executor\",\n\t\tagentName: \"omk-executor\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tcritic: {\n\t\trole: \"critic\",\n\t\tloadoutRole: \"critic\",\n\t\tloadoutName: \"critic\",\n\t\tagentName: \"omk-critic\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"visual-qa\": {\n\t\trole: \"visual-qa\",\n\t\tloadoutRole: \"visual-qa\",\n\t\tloadoutName: \"visual-qa\",\n\t\tagentName: \"omk-visual-qa\",\n\t\tcontextInheritance: \"receipt\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"rhwp-doc\": {\n\t\trole: \"rhwp-doc\",\n\t\tloadoutRole: \"rhwp-doc\",\n\t\tloadoutName: \"rhwp-doc\",\n\t\tagentName: \"omk-rhwp-doc\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n\tsecurity: {\n\t\trole: \"security\",\n\t\tloadoutRole: \"security\",\n\t\tloadoutName: \"security\",\n\t\tagentName: \"omk-security\",\n\t\tcontextInheritance: \"none\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: false,\n\t},\n\t\"package-maintainer\": {\n\t\trole: \"package-maintainer\",\n\t\tloadoutRole: \"package-maintainer\",\n\t\tloadoutName: \"package-maintainer\",\n\t\tagentName: \"omk-package-maintainer\",\n\t\tcontextInheritance: \"bounded\",\n\t\tevidenceGates: [\"plan-reread\", \"automated-verification\", \"manual-qa\", \"adversarial-qa\", \"cleanup\"],\n\t\twritesProductFiles: true,\n\t},\n};\n\nconst REQUIRED_SPAWN_PLAN_STRING_FIELDS = [\n\t\"whyParallel\",\n\t\"whyNotLocal\",\n\t\"independence\",\n\t\"expectedReceiptShape\",\n] as const;\n\ninterface PreparedLane {\n\treadonly index: number;\n\treadonly spec: SubagentLaneSpec;\n\treadonly grant: SubagentLaneGrant;\n\treadonly dependsOn: readonly string[];\n}\n\nexport function resolveSubagentRoleAssignment(role: SubagentOrchestrationRole): SubagentRoleAssignment {\n\treturn ROLE_ASSIGNMENTS[role];\n}\n\nexport function buildSubagentOrchestrationPlan(input: BuildSubagentOrchestrationPlanInput): SubagentOrchestrationPlan {\n\tif (\n\t\tinput.maxParallelLanes !== undefined &&\n\t\t(!Number.isInteger(input.maxParallelLanes) || input.maxParallelLanes < 1)\n\t) {\n\t\tthrow new RangeError(\"maxParallelLanes must be a positive integer\");\n\t}\n\n\tconst blockers: string[] = [];\n\tconst warnings: string[] = [];\n\tblockers.push(...validateLaneIntake(input.lanes));\n\tconst spawnGate = evaluateSpawnGate({\n\t\tchildCount: input.lanes.length,\n\t\tplan: input.spawnPlan,\n\t\tthreshold: input.spawnThreshold ?? DEFAULT_SPAWN_THRESHOLD,\n\t});\n\tif (spawnGate.outcome === \"rejected\") blockers.push(spawnGate.reason);\n\n\tconst prepared = input.lanes.map((lane, index) =>\n\t\tprepareLane(lane, index, input.runId, input.inventory, input.spawnPlan, blockers, warnings),\n\t);\n\tblockers.push(...findDependencyBlockers(prepared));\n\n\tconst scheduledLanes = applyReceiptConsumerDependencies(prepared);\n\tconst batches = schedulePreparedLanes(scheduledLanes, input.maxParallelLanes, blockers);\n\tconst route = buildRouteFeatures(scheduledLanes, batches);\n\n\treturn {\n\t\tlaneGrants: scheduledLanes.map((lane) => lane.grant),\n\t\tbatches,\n\t\troute,\n\t\tspawnGate,\n\t\tblockers: uniqueSorted(blockers),\n\t\twarnings: uniqueSorted(warnings),\n\t};\n}\n\nexport function evaluateSpawnGate(request: {\n\treadonly childCount: number;\n\treadonly plan?: LaneSpawnReceipt;\n\treadonly threshold?: number;\n}): SpawnGateDecision {\n\tconst threshold = request.threshold ?? DEFAULT_SPAWN_THRESHOLD;\n\tif (!Number.isInteger(request.childCount) || request.childCount < 0) {\n\t\tthrow new RangeError(\"childCount must be a non-negative integer\");\n\t}\n\tif (!Number.isInteger(threshold) || threshold < 1) {\n\t\tthrow new RangeError(\"threshold must be a positive integer\");\n\t}\n\n\tconst planRequired = request.childCount > threshold;\n\tif (!planRequired) {\n\t\treturn {\n\t\t\toutcome: \"allowed\",\n\t\t\treason: `batch of ${request.childCount} is at or below threshold ${threshold}`,\n\t\t\tplanRequired: false,\n\t\t\tmissingFields: [],\n\t\t};\n\t}\n\n\tconst missingFields = findMissingSpawnPlanFields(request.plan);\n\tif (missingFields.length > 0) {\n\t\treturn {\n\t\t\toutcome: \"rejected\",\n\t\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and the spawn-plan receipt is ${\n\t\t\t\trequest.plan ? `incomplete (${missingFields.join(\", \")})` : \"missing\"\n\t\t\t}`,\n\t\t\tplanRequired: true,\n\t\t\tmissingFields,\n\t\t};\n\t}\n\n\treturn {\n\t\toutcome: \"allowed\",\n\t\treason: `batch of ${request.childCount} exceeds threshold ${threshold} and a complete spawn-plan receipt was provided`,\n\t\tplanRequired: true,\n\t\tmissingFields: [],\n\t};\n}\n\nexport function findMissingSpawnPlanFields(plan: LaneSpawnReceipt | undefined): string[] {\n\tif (!plan) return [...REQUIRED_SPAWN_PLAN_STRING_FIELDS, \"maxInlineTokens\"];\n\tconst missing: string[] = [];\n\tfor (const field of REQUIRED_SPAWN_PLAN_STRING_FIELDS) {\n\t\tconst value = plan[field];\n\t\tif (value.trim().length === 0) missing.push(field);\n\t}\n\tif (!Number.isFinite(plan.maxInlineTokens) || plan.maxInlineTokens <= 0) {\n\t\tmissing.push(\"maxInlineTokens\");\n\t}\n\treturn missing;\n}\n\nfunction validateLaneIntake(lanes: readonly SubagentLaneSpec[]): string[] {\n\tconst blockers: string[] = [];\n\tconst seenIds = new Map<string, number>();\n\n\tfor (const [index, lane] of lanes.entries()) {\n\t\tconst id = lane.id.trim();\n\t\tconst label = id === \"\" ? `lane at index ${index}` : `lane ${id}`;\n\t\tif (id === \"\") {\n\t\t\tblockers.push(`lane at index ${index} has empty id`);\n\t\t} else {\n\t\t\tconst firstIndex = seenIds.get(id);\n\t\t\tif (firstIndex === undefined) {\n\t\t\t\tseenIds.set(id, index);\n\t\t\t} else {\n\t\t\t\tblockers.push(`duplicate lane id ${id} at indexes ${firstIndex} and ${index}`);\n\t\t\t}\n\t\t}\n\n\t\tif (lane.task.trim() === \"\") {\n\t\t\tblockers.push(`${label} has empty task`);\n\t\t}\n\n\t\tconst seenDependencies = new Set<string>();\n\t\tfor (const dependency of lane.dependsOn ?? []) {\n\t\t\tconst dependencyId = dependency.trim();\n\t\t\tif (dependencyId === \"\") {\n\t\t\t\tblockers.push(`${label} has empty dependency id`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (dependencyId === id) {\n\t\t\t\tblockers.push(`${label} depends on itself`);\n\t\t\t}\n\t\t\tif (seenDependencies.has(dependencyId)) {\n\t\t\t\tblockers.push(`${label} repeats dependency ${dependencyId}`);\n\t\t\t}\n\t\t\tseenDependencies.add(dependencyId);\n\t\t}\n\t}\n\n\treturn blockers;\n}\n\nfunction prepareLane(\n\tspec: SubagentLaneSpec,\n\tindex: number,\n\trunId: string,\n\tinventory: CapabilityInventory,\n\tspawnReceipt: LaneSpawnReceipt | undefined,\n\tblockers: string[],\n\twarnings: string[],\n): PreparedLane {\n\tconst assignment = resolveSubagentRoleAssignment(spec.role);\n\tif ((spec.writeScope?.length ?? 0) > 0 && !assignment.writesProductFiles) {\n\t\tblockers.push(`lane ${spec.id} role ${spec.role} cannot write product files`);\n\t}\n\tconst dependsOn = uniqueSorted(spec.dependsOn ?? []);\n\n\tconst profile = resolveLoadoutProfile(spec, assignment, blockers);\n\tconst applied = applyLoadoutProfile(profile, inventory, { grantAuthority: spec.grantAuthority });\n\tblockers.push(...applied.blockers.map((blocker) => `lane ${spec.id}: ${blocker}`));\n\twarnings.push(...applied.warnings.map((warning) => `lane ${spec.id}: ${warning}`));\n\n\tconst schedulerFields = deriveSchedulerFields({\n\t\trole: assignment.loadoutRole,\n\t\tassignedReadPaths: spec.readScope,\n\t\tassignedWritePaths: spec.writeScope,\n\t});\n\n\tconst grant = buildSubagentLaneGrant(spec.id, assignment.loadoutRole, spec.task, applied, schedulerFields, {\n\t\tallowedReadPaths: spec.readScope,\n\t\tallowedWritePaths: spec.writeScope,\n\t\tblockedPaths: spec.blockedPaths,\n\t\tevidenceOutputPattern: spec.evidenceOutput ?? profile.evidence?.outputPattern,\n\t\trunId,\n\t\tprofile,\n\t\tagentName: spec.agentName ?? assignment.agentName,\n\t\tcontextInheritance: spec.contextInheritance ?? assignment.contextInheritance,\n\t\tspawnReceipt,\n\t\tevidenceGates: assignment.evidenceGates,\n\t\tdependsOn,\n\t\tacceptance: spec.acceptance,\n\t});\n\n\treturn { index, spec, grant, dependsOn };\n}\n\nfunction resolveLoadoutProfile(\n\tspec: SubagentLaneSpec,\n\tassignment: SubagentRoleAssignment,\n\tblockers: string[],\n): LoadoutProfile {\n\tconst loadoutName = spec.loadoutName ?? assignment.loadoutName;\n\tconst profile = BUILTIN_LOADOUTS[loadoutName];\n\tif (profile) return profile;\n\tblockers.push(`lane ${spec.id}: unknown loadout ${loadoutName}`);\n\treturn BUILTIN_LOADOUTS.none;\n}\n\nfunction findDependencyBlockers(lanes: readonly PreparedLane[]): string[] {\n\tconst ids = new Set(lanes.map((lane) => lane.spec.id));\n\tconst blockers: string[] = [];\n\tfor (const lane of lanes) {\n\t\tfor (const dependency of lane.dependsOn) {\n\t\t\tif (!ids.has(dependency)) {\n\t\t\t\tblockers.push(`lane ${lane.spec.id} depends on missing lane ${dependency}`);\n\t\t\t}\n\t\t}\n\t}\n\treturn blockers;\n}\n\nfunction applyReceiptConsumerDependencies(lanes: readonly PreparedLane[]): PreparedLane[] {\n\tconst receiptProducerIds = lanes\n\t\t.filter((lane) => lane.grant.evidenceOutput !== undefined && !isReceiptConsumerRole(lane.spec.role))\n\t\t.map((lane) => lane.spec.id);\n\n\treturn lanes.map((lane) => {\n\t\tif (!isReceiptReadingConsumer(lane) || receiptProducerIds.length === 0) return lane;\n\t\tconst dependsOn = uniqueSorted([\n\t\t\t...lane.dependsOn,\n\t\t\t...receiptProducerIds.filter((producerId) => producerId !== lane.spec.id),\n\t\t]);\n\t\tif (arrayEquals(dependsOn, lane.dependsOn)) return lane;\n\t\treturn {\n\t\t\t...lane,\n\t\t\tdependsOn,\n\t\t\tgrant: {\n\t\t\t\t...lane.grant,\n\t\t\t\tdependsOn,\n\t\t\t},\n\t\t};\n\t});\n}\n\nfunction isReceiptReadingConsumer(lane: PreparedLane): boolean {\n\tif (!isReceiptConsumerRole(lane.spec.role)) return false;\n\treturn (lane.spec.readScope ?? []).some(isReceiptPath);\n}\n\nfunction isReceiptConsumerRole(role: SubagentOrchestrationRole): boolean {\n\treturn role === \"critic\" || role === \"visual-qa\" || role === \"rhwp-doc\";\n}\n\nfunction isReceiptPath(path: string): boolean {\n\tconst normalized = normalizePath(path);\n\treturn normalized === \".omk/runs\" || normalized.startsWith(\".omk/runs/\") || normalized.includes(\"/.omk/runs/\");\n}\n\nfunction schedulePreparedLanes(\n\tlanes: readonly PreparedLane[],\n\tmaxParallelLanes: number | undefined,\n\tblockers: string[],\n): SubagentScheduleBatch[] {\n\tconst scheduled = new Set<string>();\n\tconst batches: SubagentScheduleBatch[] = [];\n\n\twhile (scheduled.size < lanes.length) {\n\t\tconst ready = lanes\n\t\t\t.filter(\n\t\t\t\t(lane) => !scheduled.has(lane.spec.id) && lane.dependsOn.every((dependency) => scheduled.has(dependency)),\n\t\t\t)\n\t\t\t.sort((left, right) => (left.spec.id < right.spec.id ? -1 : left.spec.id > right.spec.id ? 1 : 0));\n\t\tif (ready.length === 0) {\n\t\t\tconst remaining = lanes.filter((lane) => !scheduled.has(lane.spec.id)).map((lane) => lane.spec.id);\n\t\t\tblockers.push(`lane dependency cycle or unsatisfied dependency among: ${remaining.join(\", \")}`);\n\t\t\tbreak;\n\t\t}\n\n\t\tconst serialized = ready.find((lane) => !lane.grant.scheduler.parallelizable);\n\t\tif (serialized) {\n\t\t\tbatches.push({\n\t\t\t\tindex: batches.length,\n\t\t\t\tlaneIds: [serialized.spec.id],\n\t\t\t\treason: \"serialized-writer\",\n\t\t\t});\n\t\t\tscheduled.add(serialized.spec.id);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst selected: PreparedLane[] = [];\n\t\tfor (const lane of ready) {\n\t\t\tif (maxParallelLanes !== undefined && selected.length >= maxParallelLanes) break;\n\t\t\tif (!selected.some((selectedLane) => lanesConflict(selectedLane, lane))) {\n\t\t\t\tselected.push(lane);\n\t\t\t}\n\t\t}\n\t\tconst batchLanes = selected.length > 0 ? selected : [ready[0]];\n\t\tfor (const lane of batchLanes) scheduled.add(lane.spec.id);\n\t\tbatches.push({\n\t\t\tindex: batches.length,\n\t\t\tlaneIds: batchLanes.map((lane) => lane.spec.id),\n\t\t\treason:\n\t\t\t\tmaxParallelLanes !== undefined && ready.length > batchLanes.length ? \"parallel-limit\" : \"ready-parallel\",\n\t\t});\n\t}\n\n\treturn batches;\n}\n\nfunction lanesConflict(left: PreparedLane, right: PreparedLane): boolean {\n\treturn (\n\t\tpathsConflict(\n\t\t\tleft.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...right.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...right.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t) ||\n\t\tpathsConflict(\n\t\t\tright.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t[\n\t\t\t\t...left.grant.scheduler.readSet.map((entry) => entry.path),\n\t\t\t\t...left.grant.scheduler.writeSet.map((entry) => entry.path),\n\t\t\t],\n\t\t)\n\t);\n}\n\nfunction pathsConflict(writers: readonly string[], candidates: readonly string[]): boolean {\n\tfor (const writer of writers) {\n\t\tfor (const candidate of candidates) {\n\t\t\tif (pathIntersects(writer, candidate)) return true;\n\t\t}\n\t}\n\treturn false;\n}\n\nfunction pathIntersects(left: string, right: string): boolean {\n\tconst normalizedLeft = normalizePath(left);\n\tconst normalizedRight = normalizePath(right);\n\treturn (\n\t\tnormalizedLeft === normalizedRight ||\n\t\tnormalizedLeft.startsWith(`${normalizedRight}/`) ||\n\t\tnormalizedRight.startsWith(`${normalizedLeft}/`)\n\t);\n}\n\nfunction buildRouteFeatures(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n): SubagentRouteFeatures {\n\tconst nodeCount = lanes.length;\n\tconst edgeCount = lanes.reduce((sum, lane) => sum + lane.dependsOn.length, 0);\n\tconst width = batches.reduce((max, batch) => Math.max(max, batch.laneIds.length), 0);\n\tconst criticalDepth = batches.length;\n\tconst parallelizable = lanes.filter((lane) => lane.grant.scheduler.parallelizable).length;\n\tconst parallelRatio = nodeCount === 0 ? 1 : parallelizable / nodeCount;\n\tconst couplingDensity = nodeCount <= 1 ? 0 : edgeCount / (nodeCount * (nodeCount - 1));\n\tconst topology = selectTopology(lanes, batches, width, criticalDepth, edgeCount);\n\n\treturn {\n\t\ttopology,\n\t\twidth,\n\t\tcriticalDepth,\n\t\tcouplingDensity: round(couplingDensity),\n\t\tparallelRatio: round(parallelRatio),\n\t\tnodeCount,\n\t\tedgeCount,\n\t};\n}\n\nfunction selectTopology(\n\tlanes: readonly PreparedLane[],\n\tbatches: readonly SubagentScheduleBatch[],\n\twidth: number,\n\tcriticalDepth: number,\n\tedgeCount: number,\n): SubagentSchedulerTopology {\n\tif (lanes.length <= 1 || width <= 1) return \"serial\";\n\tif (edgeCount === 0 && criticalDepth === 1) return \"parallel\";\n\tif (isMapReduceShape(lanes, batches)) return \"map-reduce\";\n\treturn \"hybrid\";\n}\n\nfunction isMapReduceShape(lanes: readonly PreparedLane[], batches: readonly SubagentScheduleBatch[]): boolean {\n\tif (batches.length < 2) return false;\n\tconst firstBatch = batches[0];\n\tconst finalBatch = batches[batches.length - 1];\n\tif (firstBatch.laneIds.length < 2 || finalBatch.laneIds.length !== 1) return false;\n\tconst finalLane = lanes.find((lane) => lane.spec.id === finalBatch.laneIds[0]);\n\tif (!finalLane) return false;\n\treturn firstBatch.laneIds.every((laneId) => finalLane.dependsOn.includes(laneId));\n}\n\nfunction normalizePath(path: string): string {\n\treturn path.replace(/\\\\/g, \"/\").replace(/\\/+$/g, \"\");\n}\n\nfunction round(value: number): number {\n\treturn Math.round(value * 1000) / 1000;\n}\n\nfunction uniqueSorted(values: readonly string[]): string[] {\n\treturn [...new Set(values)]\n\t\t.map((value) => value.trim())\n\t\t.filter((value) => value !== \"\")\n\t\t.sort();\n}\n\nfunction arrayEquals(left: readonly string[], right: readonly string[]): boolean {\n\treturn left.length === right.length && left.every((value, index) => value === right[index]);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"broker.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/broker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAsCjE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AACD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAE,QAAQ,GAAG,UAAqB,GAAG,MAAM,CA0ChH;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C;AAED,0GAA0G;AAC1G,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqGvF","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { performance } from \"node:perf_hooks\";\nimport type { RunContract } from \"omk-protocol\";\nimport type { NamespaceIdentity } from \"./namespace-identity.ts\";\nimport { identityFromSandboxInfo, PROCESS_GATE_ARGV } from \"./process-gate.ts\";\nimport { digestBytes, digestObject, VerifiedRunError } from \"./storage.ts\";\n\nconst BWRAP = \"/usr/bin/bwrap\";\nconst SYSTEM_ARGS = [\n\t\"--unshare-all\",\n\t\"--die-with-parent\",\n\t\"--new-session\",\n\t\"--cap-drop\",\n\t\"ALL\",\n\t\"--clearenv\",\n\t\"--ro-bind\",\n\t\"/usr\",\n\t\"/usr\",\n\t\"--symlink\",\n\t\"usr/bin\",\n\t\"/bin\",\n\t\"--symlink\",\n\t\"usr/lib\",\n\t\"/lib\",\n\t\"--symlink\",\n\t\"usr/lib64\",\n\t\"/lib64\",\n\t\"--proc\",\n\t\"/proc\",\n\t\"--dev\",\n\t\"/dev\",\n\t\"--tmpfs\",\n\t\"/tmp\",\n\t\"--setenv\",\n\t\"PATH\",\n\t\"/usr/bin:/bin\",\n\t\"--setenv\",\n\t\"LANG\",\n\t\"C.UTF-8\",\n] as const;\n\nexport interface SandboxExecution {\n\treadonly workspace: string;\n\treadonly argv: readonly string[];\n\treadonly writable: boolean;\n\treadonly timeoutMs: number;\n\treadonly cleanupMs: number;\n\treadonly maxOutputBytes: number;\n\treadonly signal?: AbortSignal;\n\treadonly onReady?: (identity: NamespaceIdentity) => void | Promise<void>;\n}\nexport interface SandboxOutcome {\n\treadonly stdout: Buffer;\n\treadonly stderr: Buffer;\n\treadonly exitCode: number | null;\n\treadonly failure: string | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n}\n\nexport function commandEnvironmentDigest(contract: RunContract, driver: \"legacy\" | \"gated-v1\" = \"legacy\"): string {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tlet writers: readonly (readonly string[])[];\n\tswitch (contract.profile) {\n\t\tcase \"linux-command-v1\":\n\t\t\twriters = [contract.writer];\n\t\t\tbreak;\n\t\tcase \"linux-scripted-agent-v1\":\n\t\t\twriters = contract.writer.steps;\n\t\t\tbreak;\n\t\tcase \"linux-command-dag-v1\":\n\t\t\twriters = contract.writer.tasks.flatMap((task) => task.attempts);\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\tconst exhaustive: never = contract;\n\t\t\tthrow new VerifiedRunError(String(exhaustive));\n\t\t}\n\t}\n\tconst binaries = [\n\t\t...new Set([\n\t\t\tBWRAP,\n\t\t\t...writers.map((argv) => argv[0]),\n\t\t\t...contract.checks.map((check) => check.argv[0]),\n\t\t\t...(driver === \"gated-v1\" ? [PROCESS_GATE_ARGV[0]] : []),\n\t\t]),\n\t];\n\tconst materials = binaries.map((binary) => {\n\t\tif (!binary || (!binary.startsWith(\"/usr/bin/\") && !binary.startsWith(\"/bin/\")))\n\t\t\tthrow new VerifiedRunError(\"unsupported_executable\");\n\t\tconst path = realpathSync(binary);\n\t\tif (!path.startsWith(\"/usr/\")) throw new VerifiedRunError(\"unsupported_executable\");\n\t\treturn { path, digest: digestBytes(readFileSync(path)) };\n\t});\n\treturn digestObject({\n\t\tprofile: contract.profile,\n\t\tplatform: process.platform,\n\t\tarchitecture: process.arch,\n\t\tkernel: release(),\n\t\tsandbox: SYSTEM_ARGS,\n\t\t...(driver === \"gated-v1\" ? { gate: PROCESS_GATE_ARGV, infoFd: 3 } : {}),\n\t\tbinaries: materials,\n\t});\n}\n\nexport function probeVerifiedSandbox(): void {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tconst probe = spawnSync(BWRAP, [...SYSTEM_ARGS, \"--\", \"/bin/true\"], {\n\t\tenv: {},\n\t\ttimeout: 3000,\n\t\tmaxBuffer: 4096,\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t});\n\tif (probe.error || probe.status !== 0) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** The only process dispatch port; close means the PID namespace and its inherited pipes have drained. */\nexport async function executeSandbox(request: SandboxExecution): Promise<SandboxOutcome> {\n\tif (request.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\tif (request.timeoutMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tconst started = performance.now();\n\tconst startedAt = new Date().toISOString();\n\tconst argv = [\n\t\t...SYSTEM_ARGS,\n\t\trequest.writable ? \"--bind\" : \"--ro-bind\",\n\t\trequest.workspace,\n\t\t\"/workspace\",\n\t\t\"--chdir\",\n\t\t\"/workspace\",\n\t\t...(request.onReady ? [\"--info-fd\", \"3\", \"--\", ...PROCESS_GATE_ARGV] : [\"--\"]),\n\t\t...request.argv,\n\t];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = request.onReady\n\t\t\t? spawn(BWRAP, argv, { env: {}, stdio: [\"pipe\", \"pipe\", \"pipe\", \"pipe\"] })\n\t\t\t: spawn(BWRAP, argv, { env: {}, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet gateFailed = false;\n\t\tlet gateError: unknown;\n\t\tconst stdout: Buffer[] = [];\n\t\tconst stderr: Buffer[] = [];\n\t\tlet size = 0;\n\t\tlet failure: string | null = null;\n\t\tlet cleanup: ReturnType<typeof setTimeout> | undefined;\n\t\tlet finished = false;\n\t\tconst stop = (reason: string): void => {\n\t\t\tif (finished || failure) return;\n\t\t\tfailure = reason;\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t\tcleanup = setTimeout(() => reject(new VerifiedRunError(\"unsettled\")), request.cleanupMs);\n\t\t};\n\t\tconst deadline = setTimeout(() => stop(\"deadline\"), request.timeoutMs);\n\t\tconst abort = (): void => stop(\"cancelled\");\n\t\trequest.signal?.addEventListener(\"abort\", abort, { once: true });\n\t\tif (request.signal?.aborted) abort();\n\t\tconst collect = (target: Buffer[], chunk: Buffer): void => {\n\t\t\tif (failure) return;\n\t\t\tsize += chunk.length;\n\t\t\tif (size > request.maxOutputBytes) {\n\t\t\t\tstop(\"output_limit\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttarget.push(chunk);\n\t\t};\n\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => collect(stdout, chunk));\n\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => collect(stderr, chunk));\n\t\tif (request.onReady) {\n\t\t\tconst info = child.stdio[3];\n\t\t\tlet metadata = \"\";\n\t\t\tif (!info || !child.stdin) {\n\t\t\t\tgateFailed = true;\n\t\t\t\tgateError = new VerifiedRunError(\"process_identity\");\n\t\t\t\tstop(\"process_identity\");\n\t\t\t} else {\n\t\t\t\tchild.stdin.on(\"error\", () => stop(\"execution_failed\"));\n\t\t\t\tinfo.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tmetadata += chunk.toString(\"utf8\");\n\t\t\t\t\tif (metadata.length > 4096) stop(\"process_identity\");\n\t\t\t\t});\n\t\t\t\tinfo.once(\"end\", async () => {\n\t\t\t\t\tif (finished || failure) return;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait request.onReady?.(identityFromSandboxInfo(metadata));\n\t\t\t\t\t\tif (performance.now() - started >= request.timeoutMs || request.signal?.aborted)\n\t\t\t\t\t\t\tstop(request.signal?.aborted ? \"cancelled\" : \"deadline\");\n\t\t\t\t\t\tif (!finished && !failure) child.stdin?.end(\"go\\n\");\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tgateFailed = true;\n\t\t\t\t\t\tgateError = error;\n\t\t\t\t\t\tstop(\"process_identity\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tchild.once(\"error\", () => {\n\t\t\tfailure = \"execution_failed\";\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tfinished = true;\n\t\t\tclearTimeout(deadline);\n\t\t\tclearTimeout(cleanup);\n\t\t\trequest.signal?.removeEventListener(\"abort\", abort);\n\t\t\tif (gateFailed) {\n\t\t\t\treject(gateError);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst durationMs = Math.max(0, Math.round(performance.now() - started));\n\t\t\tresolve({\n\t\t\t\tstdout: Buffer.concat(stdout),\n\t\t\t\tstderr: Buffer.concat(stderr),\n\t\t\t\texitCode,\n\t\t\t\tfailure: failure ?? (exitCode === 0 ? null : \"execution_failed\"),\n\t\t\t\tstartedAt,\n\t\t\t\t// Project the finish instant from the start's wall reference and monotonic elapsed time.\n\t\t\t\tfinishedAt: new Date(Date.parse(startedAt) + durationMs).toISOString(),\n\t\t\t\tdurationMs,\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
1
+ {"version":3,"file":"broker.d.ts","sourceRoot":"","sources":["../../../src/core/verified-run/broker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAsCjE,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,iBAAiB,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzE;AACD,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,WAAW,EAAE,MAAM,GAAE,QAAQ,GAAG,UAAqB,GAAG,MAAM,CA0ChH;AAED,wBAAgB,oBAAoB,IAAI,IAAI,CAS3C;AAED,0GAA0G;AAC1G,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CA8GvF","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { performance } from \"node:perf_hooks\";\nimport type { RunContract } from \"omk-protocol\";\nimport type { NamespaceIdentity } from \"./namespace-identity.ts\";\nimport { identityFromSandboxInfo, PROCESS_GATE_ARGV } from \"./process-gate.ts\";\nimport { digestBytes, digestObject, VerifiedRunError } from \"./storage.ts\";\n\nconst BWRAP = \"/usr/bin/bwrap\";\nconst SYSTEM_ARGS = [\n\t\"--unshare-all\",\n\t\"--die-with-parent\",\n\t\"--new-session\",\n\t\"--cap-drop\",\n\t\"ALL\",\n\t\"--clearenv\",\n\t\"--ro-bind\",\n\t\"/usr\",\n\t\"/usr\",\n\t\"--symlink\",\n\t\"usr/bin\",\n\t\"/bin\",\n\t\"--symlink\",\n\t\"usr/lib\",\n\t\"/lib\",\n\t\"--symlink\",\n\t\"usr/lib64\",\n\t\"/lib64\",\n\t\"--proc\",\n\t\"/proc\",\n\t\"--dev\",\n\t\"/dev\",\n\t\"--tmpfs\",\n\t\"/tmp\",\n\t\"--setenv\",\n\t\"PATH\",\n\t\"/usr/bin:/bin\",\n\t\"--setenv\",\n\t\"LANG\",\n\t\"C.UTF-8\",\n] as const;\n\nexport interface SandboxExecution {\n\treadonly workspace: string;\n\treadonly argv: readonly string[];\n\treadonly writable: boolean;\n\treadonly timeoutMs: number;\n\treadonly cleanupMs: number;\n\treadonly maxOutputBytes: number;\n\treadonly signal?: AbortSignal;\n\treadonly onReady?: (identity: NamespaceIdentity) => void | Promise<void>;\n}\nexport interface SandboxOutcome {\n\treadonly stdout: Buffer;\n\treadonly stderr: Buffer;\n\treadonly exitCode: number | null;\n\treadonly failure: string | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n}\n\nexport function commandEnvironmentDigest(contract: RunContract, driver: \"legacy\" | \"gated-v1\" = \"legacy\"): string {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tlet writers: readonly (readonly string[])[];\n\tswitch (contract.profile) {\n\t\tcase \"linux-command-v1\":\n\t\t\twriters = [contract.writer];\n\t\t\tbreak;\n\t\tcase \"linux-scripted-agent-v1\":\n\t\t\twriters = contract.writer.steps;\n\t\t\tbreak;\n\t\tcase \"linux-command-dag-v1\":\n\t\t\twriters = contract.writer.tasks.flatMap((task) => task.attempts);\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\tconst exhaustive: never = contract;\n\t\t\tthrow new VerifiedRunError(String(exhaustive));\n\t\t}\n\t}\n\tconst binaries = [\n\t\t...new Set([\n\t\t\tBWRAP,\n\t\t\t...writers.map((argv) => argv[0]),\n\t\t\t...contract.checks.map((check) => check.argv[0]),\n\t\t\t...(driver === \"gated-v1\" ? [PROCESS_GATE_ARGV[0]] : []),\n\t\t]),\n\t];\n\tconst materials = binaries.map((binary) => {\n\t\tif (!binary || (!binary.startsWith(\"/usr/bin/\") && !binary.startsWith(\"/bin/\")))\n\t\t\tthrow new VerifiedRunError(\"unsupported_executable\");\n\t\tconst path = realpathSync(binary);\n\t\tif (!path.startsWith(\"/usr/\")) throw new VerifiedRunError(\"unsupported_executable\");\n\t\treturn { path, digest: digestBytes(readFileSync(path)) };\n\t});\n\treturn digestObject({\n\t\tprofile: contract.profile,\n\t\tplatform: process.platform,\n\t\tarchitecture: process.arch,\n\t\tkernel: release(),\n\t\tsandbox: SYSTEM_ARGS,\n\t\t...(driver === \"gated-v1\" ? { gate: PROCESS_GATE_ARGV, infoFd: 3 } : {}),\n\t\tbinaries: materials,\n\t});\n}\n\nexport function probeVerifiedSandbox(): void {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tconst probe = spawnSync(BWRAP, [...SYSTEM_ARGS, \"--\", \"/bin/true\"], {\n\t\tenv: {},\n\t\ttimeout: 3000,\n\t\tmaxBuffer: 4096,\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t});\n\tif (probe.error || probe.status !== 0) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** The only process dispatch port; close means the PID namespace and its inherited pipes have drained. */\nexport async function executeSandbox(request: SandboxExecution): Promise<SandboxOutcome> {\n\tif (request.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\tif (request.timeoutMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tconst started = performance.now();\n\tconst startedAt = new Date().toISOString();\n\tconst argv = [\n\t\t...SYSTEM_ARGS,\n\t\trequest.writable ? \"--bind\" : \"--ro-bind\",\n\t\trequest.workspace,\n\t\t\"/workspace\",\n\t\t\"--chdir\",\n\t\t\"/workspace\",\n\t\t...(request.onReady ? [\"--info-fd\", \"3\", \"--\", ...PROCESS_GATE_ARGV] : [\"--\"]),\n\t\t...request.argv,\n\t];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = request.onReady\n\t\t\t? spawn(BWRAP, argv, { env: {}, stdio: [\"pipe\", \"pipe\", \"pipe\", \"pipe\"] })\n\t\t\t: spawn(BWRAP, argv, { env: {}, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet gateFailed = false;\n\t\tlet gateError: unknown;\n\t\tconst stdout: Buffer[] = [];\n\t\tconst stderr: Buffer[] = [];\n\t\tlet size = 0;\n\t\tlet failure: string | null = null;\n\t\tlet cleanup: ReturnType<typeof setTimeout> | undefined;\n\t\tlet finished = false;\n\t\tconst stop = (reason: string): void => {\n\t\t\tif (finished || failure) return;\n\t\t\tfailure = reason;\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t// When the gate already failed, surface its real cause rather than a\n\t\t\t// generic unsettled — the close handler may still arrive first, and\n\t\t\t// either path must report the same error.\n\t\t\tcleanup = setTimeout(\n\t\t\t\t() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\tgateFailed ? (gateError ?? new VerifiedRunError(\"unsettled\")) : new VerifiedRunError(\"unsettled\"),\n\t\t\t\t\t),\n\t\t\t\trequest.cleanupMs,\n\t\t\t);\n\t\t};\n\t\tconst deadline = setTimeout(() => stop(\"deadline\"), request.timeoutMs);\n\t\tconst abort = (): void => stop(\"cancelled\");\n\t\trequest.signal?.addEventListener(\"abort\", abort, { once: true });\n\t\tif (request.signal?.aborted) abort();\n\t\tconst collect = (target: Buffer[], chunk: Buffer): void => {\n\t\t\tif (failure) return;\n\t\t\tsize += chunk.length;\n\t\t\tif (size > request.maxOutputBytes) {\n\t\t\t\tstop(\"output_limit\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttarget.push(chunk);\n\t\t};\n\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => collect(stdout, chunk));\n\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => collect(stderr, chunk));\n\t\tif (request.onReady) {\n\t\t\tconst info = child.stdio[3];\n\t\t\tlet metadata = \"\";\n\t\t\tif (!info || !child.stdin) {\n\t\t\t\tgateFailed = true;\n\t\t\t\tgateError = new VerifiedRunError(\"process_identity\");\n\t\t\t\tstop(\"process_identity\");\n\t\t\t} else {\n\t\t\t\tchild.stdin.on(\"error\", () => stop(\"execution_failed\"));\n\t\t\t\tinfo.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tmetadata += chunk.toString(\"utf8\");\n\t\t\t\t\tif (metadata.length > 4096) stop(\"process_identity\");\n\t\t\t\t});\n\t\t\t\tinfo.once(\"end\", async () => {\n\t\t\t\t\tif (finished || failure) return;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait request.onReady?.(identityFromSandboxInfo(metadata));\n\t\t\t\t\t\tif (performance.now() - started >= request.timeoutMs || request.signal?.aborted)\n\t\t\t\t\t\t\tstop(request.signal?.aborted ? \"cancelled\" : \"deadline\");\n\t\t\t\t\t\tif (!finished && !failure) child.stdin?.end(\"go\\n\");\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tgateFailed = true;\n\t\t\t\t\t\tgateError = error;\n\t\t\t\t\t\tstop(\"process_identity\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tchild.once(\"error\", () => {\n\t\t\tfailure = \"execution_failed\";\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tfinished = true;\n\t\t\tclearTimeout(deadline);\n\t\t\tclearTimeout(cleanup);\n\t\t\trequest.signal?.removeEventListener(\"abort\", abort);\n\t\t\tif (gateFailed) {\n\t\t\t\treject(gateError);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst durationMs = Math.max(0, Math.round(performance.now() - started));\n\t\t\tresolve({\n\t\t\t\tstdout: Buffer.concat(stdout),\n\t\t\t\tstderr: Buffer.concat(stderr),\n\t\t\t\texitCode,\n\t\t\t\tfailure: failure ?? (exitCode === 0 ? null : \"execution_failed\"),\n\t\t\t\tstartedAt,\n\t\t\t\t// Project the finish instant from the start's wall reference and monotonic elapsed time.\n\t\t\t\tfinishedAt: new Date(Date.parse(startedAt) + durationMs).toISOString(),\n\t\t\t\tdurationMs,\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
@@ -129,7 +129,10 @@ export async function executeSandbox(request) {
129
129
  return;
130
130
  failure = reason;
131
131
  child.kill("SIGKILL");
132
- cleanup = setTimeout(() => reject(new VerifiedRunError("unsettled")), request.cleanupMs);
132
+ // When the gate already failed, surface its real cause rather than a
133
+ // generic unsettled — the close handler may still arrive first, and
134
+ // either path must report the same error.
135
+ cleanup = setTimeout(() => reject(gateFailed ? (gateError ?? new VerifiedRunError("unsettled")) : new VerifiedRunError("unsettled")), request.cleanupMs);
133
136
  };
134
137
  const deadline = setTimeout(() => stop("deadline"), request.timeoutMs);
135
138
  const abort = () => stop("cancelled");
@@ -1 +1 @@
1
- {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../../src/core/verified-run/broker.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { performance } from \"node:perf_hooks\";\nimport type { RunContract } from \"omk-protocol\";\nimport type { NamespaceIdentity } from \"./namespace-identity.ts\";\nimport { identityFromSandboxInfo, PROCESS_GATE_ARGV } from \"./process-gate.ts\";\nimport { digestBytes, digestObject, VerifiedRunError } from \"./storage.ts\";\n\nconst BWRAP = \"/usr/bin/bwrap\";\nconst SYSTEM_ARGS = [\n\t\"--unshare-all\",\n\t\"--die-with-parent\",\n\t\"--new-session\",\n\t\"--cap-drop\",\n\t\"ALL\",\n\t\"--clearenv\",\n\t\"--ro-bind\",\n\t\"/usr\",\n\t\"/usr\",\n\t\"--symlink\",\n\t\"usr/bin\",\n\t\"/bin\",\n\t\"--symlink\",\n\t\"usr/lib\",\n\t\"/lib\",\n\t\"--symlink\",\n\t\"usr/lib64\",\n\t\"/lib64\",\n\t\"--proc\",\n\t\"/proc\",\n\t\"--dev\",\n\t\"/dev\",\n\t\"--tmpfs\",\n\t\"/tmp\",\n\t\"--setenv\",\n\t\"PATH\",\n\t\"/usr/bin:/bin\",\n\t\"--setenv\",\n\t\"LANG\",\n\t\"C.UTF-8\",\n] as const;\n\nexport interface SandboxExecution {\n\treadonly workspace: string;\n\treadonly argv: readonly string[];\n\treadonly writable: boolean;\n\treadonly timeoutMs: number;\n\treadonly cleanupMs: number;\n\treadonly maxOutputBytes: number;\n\treadonly signal?: AbortSignal;\n\treadonly onReady?: (identity: NamespaceIdentity) => void | Promise<void>;\n}\nexport interface SandboxOutcome {\n\treadonly stdout: Buffer;\n\treadonly stderr: Buffer;\n\treadonly exitCode: number | null;\n\treadonly failure: string | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n}\n\nexport function commandEnvironmentDigest(contract: RunContract, driver: \"legacy\" | \"gated-v1\" = \"legacy\"): string {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tlet writers: readonly (readonly string[])[];\n\tswitch (contract.profile) {\n\t\tcase \"linux-command-v1\":\n\t\t\twriters = [contract.writer];\n\t\t\tbreak;\n\t\tcase \"linux-scripted-agent-v1\":\n\t\t\twriters = contract.writer.steps;\n\t\t\tbreak;\n\t\tcase \"linux-command-dag-v1\":\n\t\t\twriters = contract.writer.tasks.flatMap((task) => task.attempts);\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\tconst exhaustive: never = contract;\n\t\t\tthrow new VerifiedRunError(String(exhaustive));\n\t\t}\n\t}\n\tconst binaries = [\n\t\t...new Set([\n\t\t\tBWRAP,\n\t\t\t...writers.map((argv) => argv[0]),\n\t\t\t...contract.checks.map((check) => check.argv[0]),\n\t\t\t...(driver === \"gated-v1\" ? [PROCESS_GATE_ARGV[0]] : []),\n\t\t]),\n\t];\n\tconst materials = binaries.map((binary) => {\n\t\tif (!binary || (!binary.startsWith(\"/usr/bin/\") && !binary.startsWith(\"/bin/\")))\n\t\t\tthrow new VerifiedRunError(\"unsupported_executable\");\n\t\tconst path = realpathSync(binary);\n\t\tif (!path.startsWith(\"/usr/\")) throw new VerifiedRunError(\"unsupported_executable\");\n\t\treturn { path, digest: digestBytes(readFileSync(path)) };\n\t});\n\treturn digestObject({\n\t\tprofile: contract.profile,\n\t\tplatform: process.platform,\n\t\tarchitecture: process.arch,\n\t\tkernel: release(),\n\t\tsandbox: SYSTEM_ARGS,\n\t\t...(driver === \"gated-v1\" ? { gate: PROCESS_GATE_ARGV, infoFd: 3 } : {}),\n\t\tbinaries: materials,\n\t});\n}\n\nexport function probeVerifiedSandbox(): void {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tconst probe = spawnSync(BWRAP, [...SYSTEM_ARGS, \"--\", \"/bin/true\"], {\n\t\tenv: {},\n\t\ttimeout: 3000,\n\t\tmaxBuffer: 4096,\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t});\n\tif (probe.error || probe.status !== 0) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** The only process dispatch port; close means the PID namespace and its inherited pipes have drained. */\nexport async function executeSandbox(request: SandboxExecution): Promise<SandboxOutcome> {\n\tif (request.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\tif (request.timeoutMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tconst started = performance.now();\n\tconst startedAt = new Date().toISOString();\n\tconst argv = [\n\t\t...SYSTEM_ARGS,\n\t\trequest.writable ? \"--bind\" : \"--ro-bind\",\n\t\trequest.workspace,\n\t\t\"/workspace\",\n\t\t\"--chdir\",\n\t\t\"/workspace\",\n\t\t...(request.onReady ? [\"--info-fd\", \"3\", \"--\", ...PROCESS_GATE_ARGV] : [\"--\"]),\n\t\t...request.argv,\n\t];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = request.onReady\n\t\t\t? spawn(BWRAP, argv, { env: {}, stdio: [\"pipe\", \"pipe\", \"pipe\", \"pipe\"] })\n\t\t\t: spawn(BWRAP, argv, { env: {}, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet gateFailed = false;\n\t\tlet gateError: unknown;\n\t\tconst stdout: Buffer[] = [];\n\t\tconst stderr: Buffer[] = [];\n\t\tlet size = 0;\n\t\tlet failure: string | null = null;\n\t\tlet cleanup: ReturnType<typeof setTimeout> | undefined;\n\t\tlet finished = false;\n\t\tconst stop = (reason: string): void => {\n\t\t\tif (finished || failure) return;\n\t\t\tfailure = reason;\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t\tcleanup = setTimeout(() => reject(new VerifiedRunError(\"unsettled\")), request.cleanupMs);\n\t\t};\n\t\tconst deadline = setTimeout(() => stop(\"deadline\"), request.timeoutMs);\n\t\tconst abort = (): void => stop(\"cancelled\");\n\t\trequest.signal?.addEventListener(\"abort\", abort, { once: true });\n\t\tif (request.signal?.aborted) abort();\n\t\tconst collect = (target: Buffer[], chunk: Buffer): void => {\n\t\t\tif (failure) return;\n\t\t\tsize += chunk.length;\n\t\t\tif (size > request.maxOutputBytes) {\n\t\t\t\tstop(\"output_limit\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttarget.push(chunk);\n\t\t};\n\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => collect(stdout, chunk));\n\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => collect(stderr, chunk));\n\t\tif (request.onReady) {\n\t\t\tconst info = child.stdio[3];\n\t\t\tlet metadata = \"\";\n\t\t\tif (!info || !child.stdin) {\n\t\t\t\tgateFailed = true;\n\t\t\t\tgateError = new VerifiedRunError(\"process_identity\");\n\t\t\t\tstop(\"process_identity\");\n\t\t\t} else {\n\t\t\t\tchild.stdin.on(\"error\", () => stop(\"execution_failed\"));\n\t\t\t\tinfo.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tmetadata += chunk.toString(\"utf8\");\n\t\t\t\t\tif (metadata.length > 4096) stop(\"process_identity\");\n\t\t\t\t});\n\t\t\t\tinfo.once(\"end\", async () => {\n\t\t\t\t\tif (finished || failure) return;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait request.onReady?.(identityFromSandboxInfo(metadata));\n\t\t\t\t\t\tif (performance.now() - started >= request.timeoutMs || request.signal?.aborted)\n\t\t\t\t\t\t\tstop(request.signal?.aborted ? \"cancelled\" : \"deadline\");\n\t\t\t\t\t\tif (!finished && !failure) child.stdin?.end(\"go\\n\");\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tgateFailed = true;\n\t\t\t\t\t\tgateError = error;\n\t\t\t\t\t\tstop(\"process_identity\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tchild.once(\"error\", () => {\n\t\t\tfailure = \"execution_failed\";\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tfinished = true;\n\t\t\tclearTimeout(deadline);\n\t\t\tclearTimeout(cleanup);\n\t\t\trequest.signal?.removeEventListener(\"abort\", abort);\n\t\t\tif (gateFailed) {\n\t\t\t\treject(gateError);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst durationMs = Math.max(0, Math.round(performance.now() - started));\n\t\t\tresolve({\n\t\t\t\tstdout: Buffer.concat(stdout),\n\t\t\t\tstderr: Buffer.concat(stderr),\n\t\t\t\texitCode,\n\t\t\t\tfailure: failure ?? (exitCode === 0 ? null : \"execution_failed\"),\n\t\t\t\tstartedAt,\n\t\t\t\t// Project the finish instant from the start's wall reference and monotonic elapsed time.\n\t\t\t\tfinishedAt: new Date(Date.parse(startedAt) + durationMs).toISOString(),\n\t\t\t\tdurationMs,\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
1
+ {"version":3,"file":"broker.js","sourceRoot":"","sources":["../../../src/core/verified-run/broker.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, realpathSync } from \"node:fs\";\nimport { release } from \"node:os\";\nimport { performance } from \"node:perf_hooks\";\nimport type { RunContract } from \"omk-protocol\";\nimport type { NamespaceIdentity } from \"./namespace-identity.ts\";\nimport { identityFromSandboxInfo, PROCESS_GATE_ARGV } from \"./process-gate.ts\";\nimport { digestBytes, digestObject, VerifiedRunError } from \"./storage.ts\";\n\nconst BWRAP = \"/usr/bin/bwrap\";\nconst SYSTEM_ARGS = [\n\t\"--unshare-all\",\n\t\"--die-with-parent\",\n\t\"--new-session\",\n\t\"--cap-drop\",\n\t\"ALL\",\n\t\"--clearenv\",\n\t\"--ro-bind\",\n\t\"/usr\",\n\t\"/usr\",\n\t\"--symlink\",\n\t\"usr/bin\",\n\t\"/bin\",\n\t\"--symlink\",\n\t\"usr/lib\",\n\t\"/lib\",\n\t\"--symlink\",\n\t\"usr/lib64\",\n\t\"/lib64\",\n\t\"--proc\",\n\t\"/proc\",\n\t\"--dev\",\n\t\"/dev\",\n\t\"--tmpfs\",\n\t\"/tmp\",\n\t\"--setenv\",\n\t\"PATH\",\n\t\"/usr/bin:/bin\",\n\t\"--setenv\",\n\t\"LANG\",\n\t\"C.UTF-8\",\n] as const;\n\nexport interface SandboxExecution {\n\treadonly workspace: string;\n\treadonly argv: readonly string[];\n\treadonly writable: boolean;\n\treadonly timeoutMs: number;\n\treadonly cleanupMs: number;\n\treadonly maxOutputBytes: number;\n\treadonly signal?: AbortSignal;\n\treadonly onReady?: (identity: NamespaceIdentity) => void | Promise<void>;\n}\nexport interface SandboxOutcome {\n\treadonly stdout: Buffer;\n\treadonly stderr: Buffer;\n\treadonly exitCode: number | null;\n\treadonly failure: string | null;\n\treadonly startedAt: string;\n\treadonly finishedAt: string;\n\treadonly durationMs: number;\n}\n\nexport function commandEnvironmentDigest(contract: RunContract, driver: \"legacy\" | \"gated-v1\" = \"legacy\"): string {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tlet writers: readonly (readonly string[])[];\n\tswitch (contract.profile) {\n\t\tcase \"linux-command-v1\":\n\t\t\twriters = [contract.writer];\n\t\t\tbreak;\n\t\tcase \"linux-scripted-agent-v1\":\n\t\t\twriters = contract.writer.steps;\n\t\t\tbreak;\n\t\tcase \"linux-command-dag-v1\":\n\t\t\twriters = contract.writer.tasks.flatMap((task) => task.attempts);\n\t\t\tbreak;\n\t\tdefault: {\n\t\t\tconst exhaustive: never = contract;\n\t\t\tthrow new VerifiedRunError(String(exhaustive));\n\t\t}\n\t}\n\tconst binaries = [\n\t\t...new Set([\n\t\t\tBWRAP,\n\t\t\t...writers.map((argv) => argv[0]),\n\t\t\t...contract.checks.map((check) => check.argv[0]),\n\t\t\t...(driver === \"gated-v1\" ? [PROCESS_GATE_ARGV[0]] : []),\n\t\t]),\n\t];\n\tconst materials = binaries.map((binary) => {\n\t\tif (!binary || (!binary.startsWith(\"/usr/bin/\") && !binary.startsWith(\"/bin/\")))\n\t\t\tthrow new VerifiedRunError(\"unsupported_executable\");\n\t\tconst path = realpathSync(binary);\n\t\tif (!path.startsWith(\"/usr/\")) throw new VerifiedRunError(\"unsupported_executable\");\n\t\treturn { path, digest: digestBytes(readFileSync(path)) };\n\t});\n\treturn digestObject({\n\t\tprofile: contract.profile,\n\t\tplatform: process.platform,\n\t\tarchitecture: process.arch,\n\t\tkernel: release(),\n\t\tsandbox: SYSTEM_ARGS,\n\t\t...(driver === \"gated-v1\" ? { gate: PROCESS_GATE_ARGV, infoFd: 3 } : {}),\n\t\tbinaries: materials,\n\t});\n}\n\nexport function probeVerifiedSandbox(): void {\n\tif (process.platform !== \"linux\" || !existsSync(BWRAP)) throw new VerifiedRunError(\"unsupported\");\n\tconst probe = spawnSync(BWRAP, [...SYSTEM_ARGS, \"--\", \"/bin/true\"], {\n\t\tenv: {},\n\t\ttimeout: 3000,\n\t\tmaxBuffer: 4096,\n\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t});\n\tif (probe.error || probe.status !== 0) throw new VerifiedRunError(\"unsupported\");\n}\n\n/** The only process dispatch port; close means the PID namespace and its inherited pipes have drained. */\nexport async function executeSandbox(request: SandboxExecution): Promise<SandboxOutcome> {\n\tif (request.signal?.aborted) throw new VerifiedRunError(\"cancelled\");\n\tif (request.timeoutMs <= 0) throw new VerifiedRunError(\"deadline\");\n\tconst started = performance.now();\n\tconst startedAt = new Date().toISOString();\n\tconst argv = [\n\t\t...SYSTEM_ARGS,\n\t\trequest.writable ? \"--bind\" : \"--ro-bind\",\n\t\trequest.workspace,\n\t\t\"/workspace\",\n\t\t\"--chdir\",\n\t\t\"/workspace\",\n\t\t...(request.onReady ? [\"--info-fd\", \"3\", \"--\", ...PROCESS_GATE_ARGV] : [\"--\"]),\n\t\t...request.argv,\n\t];\n\treturn new Promise((resolve, reject) => {\n\t\tconst child = request.onReady\n\t\t\t? spawn(BWRAP, argv, { env: {}, stdio: [\"pipe\", \"pipe\", \"pipe\", \"pipe\"] })\n\t\t\t: spawn(BWRAP, argv, { env: {}, stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n\t\tlet gateFailed = false;\n\t\tlet gateError: unknown;\n\t\tconst stdout: Buffer[] = [];\n\t\tconst stderr: Buffer[] = [];\n\t\tlet size = 0;\n\t\tlet failure: string | null = null;\n\t\tlet cleanup: ReturnType<typeof setTimeout> | undefined;\n\t\tlet finished = false;\n\t\tconst stop = (reason: string): void => {\n\t\t\tif (finished || failure) return;\n\t\t\tfailure = reason;\n\t\t\tchild.kill(\"SIGKILL\");\n\t\t\t// When the gate already failed, surface its real cause rather than a\n\t\t\t// generic unsettled — the close handler may still arrive first, and\n\t\t\t// either path must report the same error.\n\t\t\tcleanup = setTimeout(\n\t\t\t\t() =>\n\t\t\t\t\treject(\n\t\t\t\t\t\tgateFailed ? (gateError ?? new VerifiedRunError(\"unsettled\")) : new VerifiedRunError(\"unsettled\"),\n\t\t\t\t\t),\n\t\t\t\trequest.cleanupMs,\n\t\t\t);\n\t\t};\n\t\tconst deadline = setTimeout(() => stop(\"deadline\"), request.timeoutMs);\n\t\tconst abort = (): void => stop(\"cancelled\");\n\t\trequest.signal?.addEventListener(\"abort\", abort, { once: true });\n\t\tif (request.signal?.aborted) abort();\n\t\tconst collect = (target: Buffer[], chunk: Buffer): void => {\n\t\t\tif (failure) return;\n\t\t\tsize += chunk.length;\n\t\t\tif (size > request.maxOutputBytes) {\n\t\t\t\tstop(\"output_limit\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttarget.push(chunk);\n\t\t};\n\t\tchild.stdout?.on(\"data\", (chunk: Buffer) => collect(stdout, chunk));\n\t\tchild.stderr?.on(\"data\", (chunk: Buffer) => collect(stderr, chunk));\n\t\tif (request.onReady) {\n\t\t\tconst info = child.stdio[3];\n\t\t\tlet metadata = \"\";\n\t\t\tif (!info || !child.stdin) {\n\t\t\t\tgateFailed = true;\n\t\t\t\tgateError = new VerifiedRunError(\"process_identity\");\n\t\t\t\tstop(\"process_identity\");\n\t\t\t} else {\n\t\t\t\tchild.stdin.on(\"error\", () => stop(\"execution_failed\"));\n\t\t\t\tinfo.on(\"data\", (chunk: Buffer) => {\n\t\t\t\t\tmetadata += chunk.toString(\"utf8\");\n\t\t\t\t\tif (metadata.length > 4096) stop(\"process_identity\");\n\t\t\t\t});\n\t\t\t\tinfo.once(\"end\", async () => {\n\t\t\t\t\tif (finished || failure) return;\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait request.onReady?.(identityFromSandboxInfo(metadata));\n\t\t\t\t\t\tif (performance.now() - started >= request.timeoutMs || request.signal?.aborted)\n\t\t\t\t\t\t\tstop(request.signal?.aborted ? \"cancelled\" : \"deadline\");\n\t\t\t\t\t\tif (!finished && !failure) child.stdin?.end(\"go\\n\");\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tgateFailed = true;\n\t\t\t\t\t\tgateError = error;\n\t\t\t\t\t\tstop(\"process_identity\");\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tchild.once(\"error\", () => {\n\t\t\tfailure = \"execution_failed\";\n\t\t});\n\t\tchild.once(\"close\", (exitCode) => {\n\t\t\tfinished = true;\n\t\t\tclearTimeout(deadline);\n\t\t\tclearTimeout(cleanup);\n\t\t\trequest.signal?.removeEventListener(\"abort\", abort);\n\t\t\tif (gateFailed) {\n\t\t\t\treject(gateError);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst durationMs = Math.max(0, Math.round(performance.now() - started));\n\t\t\tresolve({\n\t\t\t\tstdout: Buffer.concat(stdout),\n\t\t\t\tstderr: Buffer.concat(stderr),\n\t\t\t\texitCode,\n\t\t\t\tfailure: failure ?? (exitCode === 0 ? null : \"execution_failed\"),\n\t\t\t\tstartedAt,\n\t\t\t\t// Project the finish instant from the start's wall reference and monotonic elapsed time.\n\t\t\t\tfinishedAt: new Date(Date.parse(startedAt) + durationMs).toISOString(),\n\t\t\t\tdurationMs,\n\t\t\t});\n\t\t});\n\t});\n}\n"]}
@@ -33,7 +33,7 @@ export interface WorkloadPermitPoolSnapshot {
33
33
  readonly activeWeight: number;
34
34
  readonly queuedCount: number;
35
35
  }
36
- export type WorkloadPermitErrorCode = "queue_overflow" | "timeout" | "aborted" | "over_capacity_weight";
36
+ export type WorkloadPermitErrorCode = "queue_overflow" | "timeout" | "aborted" | "over_capacity_weight" | "invalid_weight";
37
37
  export declare class WorkloadPermitError extends Error {
38
38
  readonly code: WorkloadPermitErrorCode;
39
39
  readonly requestId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"workload-permit-pool.d.ts","sourceRoot":"","sources":["../../src/core/workload-permit-pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,uBAAuB,GAAG,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,sBAAsB,CAAC;AAExG,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,YAAY,IAAI,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAK3D;CACD;AAUD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,MAAM,MAAM,yBAAyB,GAAG;IACvC,uEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CACjB,CAAC;AAEF,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAK;IAE3B,YAAY,OAAO,CAAC,EAAE,yBAAyB,EAI9C;IAED;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGlC;IAED,+EAA+E;IAC/E,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CA8B7D;IAED,QAAQ,IAAI,0BAA0B,CAErC;IAED,uEAAsE;IACtE,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED,OAAO,CAAC,KAAK;IAmBb,gFAA+E;IAC/E,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,aAAa;CAUrB","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { WorkloadClass } from \"./workload-classifier.ts\";\n\n/**\n * Shared workload permit pool (OMK v0.97.x roadmap §10, M3/PR5).\n *\n * Bounds concurrent heavy/cpu subprocesses independently of tool concurrency\n * (§10.1: 4 concurrent reads != 4 concurrent `npm test` processes). One pool\n * instance is shared by a session and, later, its child subagents (§14.1) —\n * a child creating its own pool would oversubscribe the host.\n *\n * §10.3 rules implemented here: strict FIFO (§10.4), abort- and\n * timeout-aware waiting, exactly-once release with double-release recorded\n * as a diagnostic no-op, immediate rejection of requests wider than\n * capacity, and a hard queue cap whose overflow surfaces as a structured\n * error code (§15.4 `queue_overflow`). Waiter timers stay ref'd — a permit\n * wait is actively awaited work — and are cleared on settle.\n */\n\nexport interface WorkloadPermitRequest {\n\treadonly requestId: string;\n\treadonly promptRunId: string;\n\treadonly workloadClass: WorkloadClass;\n\treadonly weight: 1 | 2;\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n}\n\nexport interface WorkloadPermit {\n\treadonly permitId: string;\n\treadonly requestId: string;\n\treadonly acquiredAt: string;\n\trelease(): void;\n}\n\nexport interface WorkloadPermitPoolSnapshot {\n\treadonly capacity: number;\n\treadonly activeWeight: number;\n\treadonly queuedCount: number;\n}\n\nexport type WorkloadPermitErrorCode = \"queue_overflow\" | \"timeout\" | \"aborted\" | \"over_capacity_weight\";\n\nexport class WorkloadPermitError extends Error {\n\treadonly code: WorkloadPermitErrorCode;\n\treadonly requestId: string;\n\n\tconstructor(code: WorkloadPermitErrorCode, requestId: string) {\n\t\tsuper(`workload permit ${code} (request ${requestId})`);\n\t\tthis.name = \"WorkloadPermitError\";\n\t\tthis.code = code;\n\t\tthis.requestId = requestId;\n\t}\n}\n\ninterface Waiter {\n\treadonly request: WorkloadPermitRequest;\n\treadonly resolve: (permit: WorkloadPermit) => void;\n\treadonly reject: (error: WorkloadPermitError) => void;\n\ttimer: ReturnType<typeof setTimeout> | null;\n\tabortListener: (() => void) | null;\n}\n\nexport const DEFAULT_PERMIT_QUEUE_CAP = 32;\n\nexport type WorkloadPermitPoolOptions = {\n\t/** Concurrent weight budget; §7.2 heavy caps feed this. Default 2. */\n\tcapacity?: number;\n\t/** §10.3 queue length hard cap. Default 32. */\n\tmaxQueue?: number;\n\t/** Injectable clock for deterministic tests. */\n\tnow?: () => Date;\n};\n\nexport class WorkloadPermitPool {\n\tprivate capacity: number;\n\tprivate readonly maxQueue: number;\n\tprivate readonly now: () => Date;\n\tprivate activeWeight = 0;\n\tprivate readonly queue: Waiter[] = [];\n\tprivate doubleReleases = 0;\n\n\tconstructor(options?: WorkloadPermitPoolOptions) {\n\t\tthis.capacity = sanitizeCapacity(options?.capacity, 2);\n\t\tthis.maxQueue = sanitizeCapacity(options?.maxQueue, DEFAULT_PERMIT_QUEUE_CAP);\n\t\tthis.now = options?.now ?? (() => new Date());\n\t}\n\n\t/**\n\t * Update capacity from a new admission decision. In-flight permits are\n\t * never revoked; a reduction only delays future grants until active\n\t * weight drains below the new capacity.\n\t */\n\tsetCapacity(capacity: number): void {\n\t\tthis.capacity = sanitizeCapacity(capacity, this.capacity);\n\t\tthis.grantWhilePossible();\n\t}\n\n\t/** Acquire a permit. Strict FIFO; rejects with {@link WorkloadPermitError}. */\n\tacquire(input: WorkloadPermitRequest): Promise<WorkloadPermit> {\n\t\tconst request = { ...input };\n\t\tif (request.weight > this.capacity) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"over_capacity_weight\", request.requestId));\n\t\t}\n\t\tif (request.signal?.aborted) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"aborted\", request.requestId));\n\t\t}\n\t\tif (this.queue.length === 0 && this.activeWeight + request.weight <= this.capacity) {\n\t\t\treturn Promise.resolve(this.grant(request));\n\t\t}\n\t\tif (this.queue.length >= this.maxQueue) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"queue_overflow\", request.requestId));\n\t\t}\n\t\treturn new Promise<WorkloadPermit>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = { request, resolve, reject, timer: null, abortListener: null };\n\t\t\tif (typeof request.timeoutMs === \"number\" && Number.isFinite(request.timeoutMs) && request.timeoutMs > 0) {\n\t\t\t\twaiter.timer = setTimeout(() => {\n\t\t\t\t\tthis.evict(waiter, \"timeout\");\n\t\t\t\t}, request.timeoutMs);\n\t\t\t}\n\t\t\tif (request.signal) {\n\t\t\t\tconst signal = request.signal;\n\t\t\t\twaiter.abortListener = () => {\n\t\t\t\t\tthis.evict(waiter, \"aborted\");\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", waiter.abortListener, { once: true });\n\t\t\t}\n\t\t\tthis.queue.push(waiter);\n\t\t});\n\t}\n\n\tsnapshot(): WorkloadPermitPoolSnapshot {\n\t\treturn { capacity: this.capacity, activeWeight: this.activeWeight, queuedCount: this.queue.length };\n\t}\n\n\t/** Diagnostic count of double releases (§10.3 no-op + diagnostic). */\n\tget doubleReleaseCount(): number {\n\t\treturn this.doubleReleases;\n\t}\n\n\tprivate grant(request: WorkloadPermitRequest): WorkloadPermit {\n\t\tconst acquiredAt = this.now().toISOString();\n\t\tconst permitId = `permit-${randomUUID()}`;\n\t\tthis.activeWeight += request.weight;\n\t\tlet released = false;\n\t\tconst release = (): void => {\n\t\t\t// §10.3 exactly-once: a late or repeated settlement must not return\n\t\t\t// weight it no longer owns.\n\t\t\tif (released) {\n\t\t\t\tthis.doubleReleases += 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treleased = true;\n\t\t\tthis.activeWeight -= request.weight;\n\t\t\tthis.grantWhilePossible();\n\t\t};\n\t\treturn { permitId, requestId: request.requestId, acquiredAt, release };\n\t}\n\n\t/** Grant queued waiters strictly in FIFO order while the head fits (§10.4). */\n\tprivate grantWhilePossible(): void {\n\t\twhile (this.queue.length > 0) {\n\t\t\tconst head = this.queue[0];\n\t\t\tif (head.request.weight > this.capacity) {\n\t\t\t\t// Capacity shrank below the head's weight: reject rather than\n\t\t\t\t// starving everyone behind it forever.\n\t\t\t\tthis.queue.shift();\n\t\t\t\tthis.settleCleanup(head);\n\t\t\t\thead.reject(new WorkloadPermitError(\"over_capacity_weight\", head.request.requestId));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this.activeWeight + head.request.weight > this.capacity) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.queue.shift();\n\t\t\tthis.settleCleanup(head);\n\t\t\thead.resolve(this.grant(head.request));\n\t\t}\n\t}\n\n\tprivate evict(waiter: Waiter, code: WorkloadPermitErrorCode): void {\n\t\tconst index = this.queue.indexOf(waiter);\n\t\tif (index === -1) {\n\t\t\treturn; // Already granted or already evicted.\n\t\t}\n\t\tthis.queue.splice(index, 1);\n\t\tthis.settleCleanup(waiter);\n\t\twaiter.reject(new WorkloadPermitError(code, waiter.request.requestId));\n\t\tthis.grantWhilePossible();\n\t}\n\n\tprivate settleCleanup(waiter: Waiter): void {\n\t\tif (waiter.timer !== null) {\n\t\t\tclearTimeout(waiter.timer);\n\t\t\twaiter.timer = null;\n\t\t}\n\t\tif (waiter.abortListener !== null) {\n\t\t\twaiter.request.signal?.removeEventListener(\"abort\", waiter.abortListener);\n\t\t\twaiter.abortListener = null;\n\t\t}\n\t}\n}\n\nfunction sanitizeCapacity(value: number | undefined, fallback: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(value);\n}\n"]}
1
+ {"version":3,"file":"workload-permit-pool.d.ts","sourceRoot":"","sources":["../../src/core/workload-permit-pool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,MAAM,WAAW,0BAA0B;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,uBAAuB,GAChC,gBAAgB,GAChB,SAAS,GACT,SAAS,GACT,sBAAsB,GACtB,gBAAgB,CAAC;AAEpB,qBAAa,mBAAoB,SAAQ,KAAK;IAC7C,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,YAAY,IAAI,EAAE,uBAAuB,EAAE,SAAS,EAAE,MAAM,EAK3D;CACD;AAUD,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,MAAM,MAAM,yBAAyB,GAAG;IACvC,uEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CACjB,CAAC;AAEF,qBAAa,kBAAkB;IAC9B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAa;IACjC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IACtC,OAAO,CAAC,cAAc,CAAK;IAE3B,YAAY,OAAO,CAAC,EAAE,yBAAyB,EAI9C;IAED;;;;OAIG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGlC;IAED,+EAA+E;IAC/E,OAAO,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,cAAc,CAAC,CAiC7D;IAED,QAAQ,IAAI,0BAA0B,CAErC;IAED,uEAAsE;IACtE,IAAI,kBAAkB,IAAI,MAAM,CAE/B;IAED,OAAO,CAAC,KAAK;IAmBb,gFAA+E;IAC/E,OAAO,CAAC,kBAAkB;IAoB1B,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,aAAa;CAUrB","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type { WorkloadClass } from \"./workload-classifier.ts\";\n\n/**\n * Shared workload permit pool (OMK v0.97.x roadmap §10, M3/PR5).\n *\n * Bounds concurrent heavy/cpu subprocesses independently of tool concurrency\n * (§10.1: 4 concurrent reads != 4 concurrent `npm test` processes). One pool\n * instance is shared by a session and, later, its child subagents (§14.1) —\n * a child creating its own pool would oversubscribe the host.\n *\n * §10.3 rules implemented here: strict FIFO (§10.4), abort- and\n * timeout-aware waiting, exactly-once release with double-release recorded\n * as a diagnostic no-op, immediate rejection of requests wider than\n * capacity, and a hard queue cap whose overflow surfaces as a structured\n * error code (§15.4 `queue_overflow`). Waiter timers stay ref'd — a permit\n * wait is actively awaited work — and are cleared on settle.\n */\n\nexport interface WorkloadPermitRequest {\n\treadonly requestId: string;\n\treadonly promptRunId: string;\n\treadonly workloadClass: WorkloadClass;\n\treadonly weight: 1 | 2;\n\treadonly signal?: AbortSignal;\n\treadonly timeoutMs?: number;\n}\n\nexport interface WorkloadPermit {\n\treadonly permitId: string;\n\treadonly requestId: string;\n\treadonly acquiredAt: string;\n\trelease(): void;\n}\n\nexport interface WorkloadPermitPoolSnapshot {\n\treadonly capacity: number;\n\treadonly activeWeight: number;\n\treadonly queuedCount: number;\n}\n\nexport type WorkloadPermitErrorCode =\n\t| \"queue_overflow\"\n\t| \"timeout\"\n\t| \"aborted\"\n\t| \"over_capacity_weight\"\n\t| \"invalid_weight\";\n\nexport class WorkloadPermitError extends Error {\n\treadonly code: WorkloadPermitErrorCode;\n\treadonly requestId: string;\n\n\tconstructor(code: WorkloadPermitErrorCode, requestId: string) {\n\t\tsuper(`workload permit ${code} (request ${requestId})`);\n\t\tthis.name = \"WorkloadPermitError\";\n\t\tthis.code = code;\n\t\tthis.requestId = requestId;\n\t}\n}\n\ninterface Waiter {\n\treadonly request: WorkloadPermitRequest;\n\treadonly resolve: (permit: WorkloadPermit) => void;\n\treadonly reject: (error: WorkloadPermitError) => void;\n\ttimer: ReturnType<typeof setTimeout> | null;\n\tabortListener: (() => void) | null;\n}\n\nexport const DEFAULT_PERMIT_QUEUE_CAP = 32;\n\nexport type WorkloadPermitPoolOptions = {\n\t/** Concurrent weight budget; §7.2 heavy caps feed this. Default 2. */\n\tcapacity?: number;\n\t/** §10.3 queue length hard cap. Default 32. */\n\tmaxQueue?: number;\n\t/** Injectable clock for deterministic tests. */\n\tnow?: () => Date;\n};\n\nexport class WorkloadPermitPool {\n\tprivate capacity: number;\n\tprivate readonly maxQueue: number;\n\tprivate readonly now: () => Date;\n\tprivate activeWeight = 0;\n\tprivate readonly queue: Waiter[] = [];\n\tprivate doubleReleases = 0;\n\n\tconstructor(options?: WorkloadPermitPoolOptions) {\n\t\tthis.capacity = sanitizeCapacity(options?.capacity, 2);\n\t\tthis.maxQueue = sanitizeCapacity(options?.maxQueue, DEFAULT_PERMIT_QUEUE_CAP);\n\t\tthis.now = options?.now ?? (() => new Date());\n\t}\n\n\t/**\n\t * Update capacity from a new admission decision. In-flight permits are\n\t * never revoked; a reduction only delays future grants until active\n\t * weight drains below the new capacity.\n\t */\n\tsetCapacity(capacity: number): void {\n\t\tthis.capacity = sanitizeCapacity(capacity, this.capacity);\n\t\tthis.grantWhilePossible();\n\t}\n\n\t/** Acquire a permit. Strict FIFO; rejects with {@link WorkloadPermitError}. */\n\tacquire(input: WorkloadPermitRequest): Promise<WorkloadPermit> {\n\t\tconst request = { ...input };\n\t\tif (request.weight !== 1 && request.weight !== 2) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"invalid_weight\", request.requestId));\n\t\t}\n\t\tif (request.weight > this.capacity) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"over_capacity_weight\", request.requestId));\n\t\t}\n\t\tif (request.signal?.aborted) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"aborted\", request.requestId));\n\t\t}\n\t\tif (this.queue.length === 0 && this.activeWeight + request.weight <= this.capacity) {\n\t\t\treturn Promise.resolve(this.grant(request));\n\t\t}\n\t\tif (this.queue.length >= this.maxQueue) {\n\t\t\treturn Promise.reject(new WorkloadPermitError(\"queue_overflow\", request.requestId));\n\t\t}\n\t\treturn new Promise<WorkloadPermit>((resolve, reject) => {\n\t\t\tconst waiter: Waiter = { request, resolve, reject, timer: null, abortListener: null };\n\t\t\tif (typeof request.timeoutMs === \"number\" && Number.isFinite(request.timeoutMs) && request.timeoutMs > 0) {\n\t\t\t\twaiter.timer = setTimeout(() => {\n\t\t\t\t\tthis.evict(waiter, \"timeout\");\n\t\t\t\t}, request.timeoutMs);\n\t\t\t}\n\t\t\tif (request.signal) {\n\t\t\t\tconst signal = request.signal;\n\t\t\t\twaiter.abortListener = () => {\n\t\t\t\t\tthis.evict(waiter, \"aborted\");\n\t\t\t\t};\n\t\t\t\tsignal.addEventListener(\"abort\", waiter.abortListener, { once: true });\n\t\t\t}\n\t\t\tthis.queue.push(waiter);\n\t\t});\n\t}\n\n\tsnapshot(): WorkloadPermitPoolSnapshot {\n\t\treturn { capacity: this.capacity, activeWeight: this.activeWeight, queuedCount: this.queue.length };\n\t}\n\n\t/** Diagnostic count of double releases (§10.3 no-op + diagnostic). */\n\tget doubleReleaseCount(): number {\n\t\treturn this.doubleReleases;\n\t}\n\n\tprivate grant(request: WorkloadPermitRequest): WorkloadPermit {\n\t\tconst acquiredAt = this.now().toISOString();\n\t\tconst permitId = `permit-${randomUUID()}`;\n\t\tthis.activeWeight += request.weight;\n\t\tlet released = false;\n\t\tconst release = (): void => {\n\t\t\t// §10.3 exactly-once: a late or repeated settlement must not return\n\t\t\t// weight it no longer owns.\n\t\t\tif (released) {\n\t\t\t\tthis.doubleReleases += 1;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\treleased = true;\n\t\t\tthis.activeWeight -= request.weight;\n\t\t\tthis.grantWhilePossible();\n\t\t};\n\t\treturn { permitId, requestId: request.requestId, acquiredAt, release };\n\t}\n\n\t/** Grant queued waiters strictly in FIFO order while the head fits (§10.4). */\n\tprivate grantWhilePossible(): void {\n\t\twhile (this.queue.length > 0) {\n\t\t\tconst head = this.queue[0];\n\t\t\tif (head.request.weight > this.capacity) {\n\t\t\t\t// Capacity shrank below the head's weight: reject rather than\n\t\t\t\t// starving everyone behind it forever.\n\t\t\t\tthis.queue.shift();\n\t\t\t\tthis.settleCleanup(head);\n\t\t\t\thead.reject(new WorkloadPermitError(\"over_capacity_weight\", head.request.requestId));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (this.activeWeight + head.request.weight > this.capacity) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.queue.shift();\n\t\t\tthis.settleCleanup(head);\n\t\t\thead.resolve(this.grant(head.request));\n\t\t}\n\t}\n\n\tprivate evict(waiter: Waiter, code: WorkloadPermitErrorCode): void {\n\t\tconst index = this.queue.indexOf(waiter);\n\t\tif (index === -1) {\n\t\t\treturn; // Already granted or already evicted.\n\t\t}\n\t\tthis.queue.splice(index, 1);\n\t\tthis.settleCleanup(waiter);\n\t\twaiter.reject(new WorkloadPermitError(code, waiter.request.requestId));\n\t\tthis.grantWhilePossible();\n\t}\n\n\tprivate settleCleanup(waiter: Waiter): void {\n\t\tif (waiter.timer !== null) {\n\t\t\tclearTimeout(waiter.timer);\n\t\t\twaiter.timer = null;\n\t\t}\n\t\tif (waiter.abortListener !== null) {\n\t\t\twaiter.request.signal?.removeEventListener(\"abort\", waiter.abortListener);\n\t\t\twaiter.abortListener = null;\n\t\t}\n\t}\n}\n\nfunction sanitizeCapacity(value: number | undefined, fallback: number): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n\t\treturn fallback;\n\t}\n\treturn Math.floor(value);\n}\n"]}
@@ -34,6 +34,9 @@ export class WorkloadPermitPool {
34
34
  /** Acquire a permit. Strict FIFO; rejects with {@link WorkloadPermitError}. */
35
35
  acquire(input) {
36
36
  const request = { ...input };
37
+ if (request.weight !== 1 && request.weight !== 2) {
38
+ return Promise.reject(new WorkloadPermitError("invalid_weight", request.requestId));
39
+ }
37
40
  if (request.weight > this.capacity) {
38
41
  return Promise.reject(new WorkloadPermitError("over_capacity_weight", request.requestId));
39
42
  }