agentworkshop 0.8.8 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/.AgentWorkShop/prompts/host-tools.json +68 -0
  2. package/.output/.AgentWorkShop/prompts/host-tools.json +68 -0
  3. package/.output/.AgentWorkShop/schema.json +2 -0
  4. package/.output/nitro.json +1 -1
  5. package/.output/public/_nuxt/{Cdi9qfTr.js → CDO7Zey1.js} +2 -2
  6. package/.output/public/_nuxt/builds/latest.json +1 -1
  7. package/.output/public/_nuxt/builds/meta/247a0d5c-de27-46a4-8f76-3e64affe9473.json +1 -0
  8. package/.output/server/chunks/_/access.mjs +1 -1
  9. package/.output/server/chunks/_/data-export.mjs +5 -5
  10. package/.output/server/chunks/_/data-query.mjs +2 -2
  11. package/.output/server/chunks/_/eda-run.repo.mjs +3 -3
  12. package/.output/server/chunks/_/features.mjs +5 -5
  13. package/.output/server/chunks/_/golden.mjs +2 -2
  14. package/.output/server/chunks/_/host-bindings.mjs +1 -1
  15. package/.output/server/chunks/_/index.mjs +2 -2
  16. package/.output/server/chunks/_/mes-secrets.repo.mjs +1 -1
  17. package/.output/server/chunks/_/nitro.mjs +2836 -1334
  18. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  19. package/.output/server/chunks/_/spc.mjs +2 -2
  20. package/.output/server/chunks/build/_id_-CsCtnbwe.mjs +1 -1
  21. package/.output/server/chunks/build/_id_-P1W47Gqq.mjs +1 -1
  22. package/.output/server/chunks/build/_wsId_-DpOErFj6.mjs +1 -1
  23. package/.output/server/chunks/build/agents-D7CdEUTv.mjs +1 -1
  24. package/.output/server/chunks/build/aml-DRAFRcGU.mjs +1 -1
  25. package/.output/server/chunks/build/analysis-J9axLuRt.mjs +1 -1
  26. package/.output/server/chunks/build/api-B4Om0mEc.mjs +1 -1
  27. package/.output/server/chunks/build/api-BEW_ebY_.mjs +1 -1
  28. package/.output/server/chunks/build/api-BsAgXWxi.mjs +1 -1
  29. package/.output/server/chunks/build/board-CJUc032b.mjs +1 -1
  30. package/.output/server/chunks/build/channel-templates-ggsBacZF.mjs +1 -1
  31. package/.output/server/chunks/build/constants-HPHJvjne.mjs +1 -1
  32. package/.output/server/chunks/build/daq-B_dRMDw4.mjs +1 -1
  33. package/.output/server/chunks/build/data-D8uX1dnm.mjs +1 -1
  34. package/.output/server/chunks/build/dcw-D_HD_H_2.mjs +1 -1
  35. package/.output/server/chunks/build/default-CNWS6NUw.mjs +1 -1
  36. package/.output/server/chunks/build/es-Bxu10NJ2.mjs +1 -1
  37. package/.output/server/chunks/build/logs-BnYSMRXM.mjs +1 -1
  38. package/.output/server/chunks/build/monitor-Cq6hRFeQ.mjs +1 -1
  39. package/.output/server/chunks/build/ontology-ohICfVVb.mjs +1 -1
  40. package/.output/server/chunks/build/operations-4zOVhW7o.mjs +1 -1
  41. package/.output/server/chunks/build/optimizer-BlWTsM-W.mjs +1 -1
  42. package/.output/server/chunks/build/pages-DEv4ProW.mjs +1 -1
  43. package/.output/server/chunks/build/permissions-DgXQZSyx.mjs +1 -1
  44. package/.output/server/chunks/build/pipeline-CkavMBhk.mjs +1 -1
  45. package/.output/server/chunks/build/plugins-LRjaSEZy.mjs +1 -1
  46. package/.output/server/chunks/build/schedules-Hz2DJUE2.mjs +1 -1
  47. package/.output/server/chunks/build/settings-DXLJPq7d.mjs +1 -1
  48. package/.output/server/chunks/build/studio-hSqH9TYS.mjs +1 -1
  49. package/.output/server/chunks/build/teams-BbwYJyzv.mjs +1 -1
  50. package/.output/server/chunks/build/tokens-GYaGJ35Z.mjs +1 -1
  51. package/.output/server/chunks/build/tools-CnYi9cou.mjs +1 -1
  52. package/.output/server/chunks/build/town-BV-hbwb5.mjs +1 -1
  53. package/.output/server/chunks/build/town-CcoQKjMj.mjs +1 -1
  54. package/.output/server/chunks/build/types-D6J7slEa.mjs +1 -1
  55. package/.output/server/chunks/build/types-DWqIeMRP.mjs +1 -1
  56. package/.output/server/chunks/build/useAgentHarnessOptions-Dq0l0Z6d.mjs +1 -1
  57. package/.output/server/chunks/build/useAgentTemplateActions-BFOHb5-L.mjs +1 -1
  58. package/.output/server/chunks/build/useAgentTemplateDialogState-CZzpu5og.mjs +1 -1
  59. package/.output/server/chunks/build/useAgentTemplateForm-CuJPOPcK.mjs +1 -1
  60. package/.output/server/chunks/build/useAgentTemplatesCatalog-B2bIhZLA.mjs +1 -1
  61. package/.output/server/chunks/build/useAmlDatasets-DeoE1idn.mjs +1 -1
  62. package/.output/server/chunks/build/useAmlEntities-BJhvdqHJ.mjs +1 -1
  63. package/.output/server/chunks/build/useAmlEnv-CDIZ6xTe.mjs +1 -1
  64. package/.output/server/chunks/build/useAmlExperiments-Dloi834i.mjs +1 -1
  65. package/.output/server/chunks/build/useAmlFormat-C2sl3MGB.mjs +1 -1
  66. package/.output/server/chunks/build/useAmlJobs-BF9LpwXz.mjs +1 -1
  67. package/.output/server/chunks/build/useAmlModels-_bweOr3R.mjs +1 -1
  68. package/.output/server/chunks/build/useAmlNotes-DQj980iX.mjs +1 -1
  69. package/.output/server/chunks/build/useAmlPredict-DHNgDSJn.mjs +1 -1
  70. package/.output/server/chunks/build/useAnalysisFeed-BrEGV_9x.mjs +1 -1
  71. package/.output/server/chunks/build/useDaqAddNode-D_Rkju0f.mjs +1 -1
  72. package/.output/server/chunks/build/useDaqDetailBinding-DCWaLKXT.mjs +1 -1
  73. package/.output/server/chunks/build/useDaqDetailFrames-BOIcOJRB.mjs +1 -1
  74. package/.output/server/chunks/build/useDaqDetailHistory-D6WulPVs.mjs +1 -1
  75. package/.output/server/chunks/build/useDaqDetailNode-BGMRUIXN.mjs +1 -1
  76. package/.output/server/chunks/build/useDaqDetailParams-Cm9a9r5G.mjs +1 -1
  77. package/.output/server/chunks/build/useDaqFilters-zAAVlzJQ.mjs +1 -1
  78. package/.output/server/chunks/build/useDaqNodeWindow-1DWj2H5G.mjs +1 -1
  79. package/.output/server/chunks/build/useDaqOptimizations-BE_9Z2s_.mjs +1 -1
  80. package/.output/server/chunks/build/useDaqTemplates-CK37sMfi.mjs +1 -1
  81. package/.output/server/chunks/build/useDashboardCharts-D45083s_.mjs +1 -1
  82. package/.output/server/chunks/build/useDashboardData-Cw8lrPo5.mjs +1 -1
  83. package/.output/server/chunks/build/useDcwAddNode-KnocMk1m.mjs +1 -1
  84. package/.output/server/chunks/build/useDcwCards-C53IiOcg.mjs +1 -1
  85. package/.output/server/chunks/build/useDcwDetailScope-D6qXrfZu.mjs +1 -1
  86. package/.output/server/chunks/build/useDcwDetailTemplates-DPOXu1o_.mjs +1 -1
  87. package/.output/server/chunks/build/useDcwFilter-DNQ6Ivwd.mjs +1 -1
  88. package/.output/server/chunks/build/useDcwLedger-BhbUBCbi.mjs +1 -1
  89. package/.output/server/chunks/build/useDcwLineMutations-KA7VnggO.mjs +1 -1
  90. package/.output/server/chunks/build/useDcwLineRun-3zx_UCxi.mjs +1 -1
  91. package/.output/server/chunks/build/useDcwParamApprovals-DzyY6Tmi.mjs +1 -1
  92. package/.output/server/chunks/build/useDcwProducts-B05ymt3k.mjs +1 -1
  93. package/.output/server/chunks/build/useDcwQuery-vWpgpSmJ.mjs +1 -1
  94. package/.output/server/chunks/build/useDcwQuickActions-DUkLy34S.mjs +1 -1
  95. package/.output/server/chunks/build/useDcwRecipes-BAb4Yg3d.mjs +1 -1
  96. package/.output/server/chunks/build/useDcwTemplates-D2aoejps.mjs +1 -1
  97. package/.output/server/chunks/build/useDcwWrites-7w8txksD.mjs +1 -1
  98. package/.output/server/chunks/build/useExpConfirmations-BM626N4p.mjs +1 -1
  99. package/.output/server/chunks/build/useLogsFormat-B-o4MHy7.mjs +1 -1
  100. package/.output/server/chunks/build/useLogsManual-D0dvgCsP.mjs +1 -1
  101. package/.output/server/chunks/build/useLogsQuery-D7hrJ3yn.mjs +1 -1
  102. package/.output/server/chunks/build/useLogsScope-DEUyq-My.mjs +1 -1
  103. package/.output/server/chunks/build/useMonitorColumns-vVnt3r5Q.mjs +1 -1
  104. package/.output/server/chunks/build/useMonitorData-DIkiLr_h.mjs +1 -1
  105. package/.output/server/chunks/build/useMonitorFormat-CyURtH8N.mjs +1 -1
  106. package/.output/server/chunks/build/useMonitorTerminal-Dj4QwRNW.mjs +1 -1
  107. package/.output/server/chunks/build/useOperationsFeed-Ci4mZAn_.mjs +1 -1
  108. package/.output/server/chunks/build/useRecipeDispatchApprovals-BYtiqfeb.mjs +1 -1
  109. package/.output/server/chunks/build/useTeamActions-BDjU06LP.mjs +1 -1
  110. package/.output/server/chunks/build/useTeamAddMemberDialog-J3oFn3FI.mjs +1 -1
  111. package/.output/server/chunks/build/useTeamCreateDialog-fbn4ixYu.mjs +1 -1
  112. package/.output/server/chunks/build/useTeamDeployDialog-BNezMD2k.mjs +1 -1
  113. package/.output/server/chunks/build/useTeamDialogState-CFRUQxAf.mjs +1 -1
  114. package/.output/server/chunks/build/useTeamPluginDialog-BZznrOVe.mjs +1 -1
  115. package/.output/server/chunks/build/useTeamsCatalog-DuZFP3oG.mjs +1 -1
  116. package/.output/server/chunks/build/useTokenClipboard-CwQpoFeP.mjs +1 -1
  117. package/.output/server/chunks/build/useTokenCreate-Ctl0YGhL.mjs +1 -1
  118. package/.output/server/chunks/build/useTokenRename-Cm3ypSfN.mjs +1 -1
  119. package/.output/server/chunks/build/useTokenReveal-CeoWL5Mt.mjs +1 -1
  120. package/.output/server/chunks/build/useTokensList-CNIzON3u.mjs +1 -1
  121. package/.output/server/chunks/build/useWorkbenchAuth-CY-bVFMu.mjs +1 -1
  122. package/.output/server/chunks/build/useWorkbenchWorkspaces-DhZQFss9.mjs +1 -1
  123. package/.output/server/chunks/build/useWorkspaceAuth-Dlvj9csD.mjs +1 -1
  124. package/.output/server/chunks/build/useWorkspaceChannels-CPFepxTN.mjs +1 -1
  125. package/.output/server/chunks/build/useWorkspacePanels-CTwREmq0.mjs +1 -1
  126. package/.output/server/chunks/build/useWorkspaceShell-BCypjjjE.mjs +1 -1
  127. package/.output/server/chunks/build/users-DjiVC_tS.mjs +1 -1
  128. package/.output/server/chunks/build/workshop-1gKeDASV.mjs +1 -1
  129. package/.output/server/chunks/routes/api/health.get.mjs +1 -1
  130. package/.output/server/chunks/routes/api/index.get.mjs +1 -1
  131. package/.output/server/chunks/routes/api/index.post.mjs +1 -1
  132. package/.output/server/chunks/routes/api/mcp/workshop.mjs +1 -1
  133. package/.output/server/chunks/routes/api/metrics.mjs +1 -1
  134. package/.output/server/chunks/routes/api/plugins/_name/_...path_.mjs +1 -1
  135. package/.output/server/chunks/routes/api/plugins/client/_name_.get.mjs +1 -1
  136. package/.output/server/chunks/routes/api/plugins/i18n.get.mjs +1 -1
  137. package/.output/server/chunks/routes/api/plugins/manifest.get.mjs +1 -1
  138. package/.output/server/chunks/routes/api/system/backup/list.get.mjs +1 -1
  139. package/.output/server/chunks/routes/api/system/backup/run.post.mjs +3 -3
  140. package/.output/server/chunks/routes/api/system/config-groups/_id_.delete.mjs +1 -1
  141. package/.output/server/chunks/routes/api/system/config-groups/_id_.patch.mjs +1 -1
  142. package/.output/server/chunks/routes/api/system/config.get.mjs +1 -1
  143. package/.output/server/chunks/routes/api/system/index.get.mjs +1 -1
  144. package/.output/server/chunks/routes/api/system/index.patch.mjs +1 -1
  145. package/.output/server/chunks/routes/api/system/index.post.mjs +1 -1
  146. package/.output/server/chunks/routes/api/system/index2.get.mjs +1 -1
  147. package/.output/server/chunks/routes/api/system/monitor/terminal/ws.mjs +1 -1
  148. package/.output/server/chunks/routes/api/system/monitor/terminate.post.mjs +1 -1
  149. package/.output/server/chunks/routes/api/system/monitor.get.mjs +1 -1
  150. package/.output/server/chunks/routes/api/system/settings/events.get.mjs +1 -1
  151. package/.output/server/chunks/routes/api/system/settings/reset.post.mjs +1 -1
  152. package/.output/server/chunks/routes/api/system/timezone.get.mjs +1 -1
  153. package/.output/server/chunks/routes/api/users/_id_.delete.mjs +1 -1
  154. package/.output/server/chunks/routes/api/users/_id_.get.mjs +1 -1
  155. package/.output/server/chunks/routes/api/users/_id_.put.mjs +1 -1
  156. package/.output/server/chunks/routes/api/users/change-password.post.mjs +1 -1
  157. package/.output/server/chunks/routes/api/users/index.get.mjs +1 -1
  158. package/.output/server/chunks/routes/api/users/index.post.mjs +1 -1
  159. package/.output/server/chunks/routes/api/users/login.post.mjs +1 -1
  160. package/.output/server/chunks/routes/api/users/logout.post.mjs +1 -1
  161. package/.output/server/chunks/routes/api/users/me.get.mjs +1 -1
  162. package/.output/server/chunks/routes/api/users/register.post.mjs +1 -1
  163. package/.output/server/chunks/routes/api/users/setup-status.get.mjs +1 -1
  164. package/.output/server/chunks/routes/api/users/tokens/_id/token.get.mjs +1 -1
  165. package/.output/server/chunks/routes/api/users/tokens/_id_.delete.mjs +1 -1
  166. package/.output/server/chunks/routes/api/users/tokens/_id_.patch.mjs +1 -1
  167. package/.output/server/chunks/routes/api/workshop/_...path_.mjs +1 -1
  168. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.get.mjs +1 -1
  169. package/.output/server/chunks/routes/api/workshop/a2a/_agentId/index.post.mjs +1 -1
  170. package/.output/server/chunks/routes/api/workshop/a2a/send.post.mjs +1 -1
  171. package/.output/server/chunks/routes/api/workshop/agent-tools/approvals/_id/decide.post.mjs +1 -1
  172. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.delete.mjs +1 -1
  173. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/_id_.patch.mjs +1 -1
  174. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/grant.post.mjs +1 -1
  175. package/.output/server/chunks/routes/api/workshop/agent-tools/bindings/revoke.post.mjs +1 -1
  176. package/.output/server/chunks/routes/api/workshop/agent-tools/index.get.mjs +1 -1
  177. package/.output/server/chunks/routes/api/workshop/agent-tools/index.post.mjs +2 -2
  178. package/.output/server/chunks/routes/api/workshop/agent-tools/index2.get.mjs +1 -1
  179. package/.output/server/chunks/routes/api/workshop/agent-tools/invoke.post.mjs +1 -1
  180. package/.output/server/chunks/routes/api/workshop/agent-tools/list.get.mjs +1 -1
  181. package/.output/server/chunks/routes/api/workshop/agents/_id_.delete.mjs +1 -1
  182. package/.output/server/chunks/routes/api/workshop/agents/_id_.get.mjs +1 -1
  183. package/.output/server/chunks/routes/api/workshop/agents/_id_.patch.mjs +1 -1
  184. package/.output/server/chunks/routes/api/workshop/agents/subscribe.post.mjs +1 -1
  185. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id/preview.get.mjs +1 -1
  186. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.delete.mjs +1 -1
  187. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.get.mjs +1 -1
  188. package/.output/server/chunks/routes/api/workshop/aml/datasets/_id_.patch.mjs +1 -1
  189. package/.output/server/chunks/routes/api/workshop/aml/entities/prune.post.mjs +1 -1
  190. package/.output/server/chunks/routes/api/workshop/aml/env/recheck.post.mjs +1 -1
  191. package/.output/server/chunks/routes/api/workshop/aml/env/uv.post.mjs +1 -1
  192. package/.output/server/chunks/routes/api/workshop/aml/env/venv.post.mjs +1 -1
  193. package/.output/server/chunks/routes/api/workshop/aml/index.get.mjs +1 -1
  194. package/.output/server/chunks/routes/api/workshop/aml/index.post.mjs +1 -1
  195. package/.output/server/chunks/routes/api/workshop/aml/index2.get.mjs +1 -1
  196. package/.output/server/chunks/routes/api/workshop/aml/index2.post.mjs +1 -1
  197. package/.output/server/chunks/routes/api/workshop/aml/index3.get.mjs +1 -1
  198. package/.output/server/chunks/routes/api/workshop/aml/index3.post.mjs +1 -1
  199. package/.output/server/chunks/routes/api/workshop/aml/index4.get.mjs +1 -1
  200. package/.output/server/chunks/routes/api/workshop/aml/index5.get.mjs +1 -1
  201. package/.output/server/chunks/routes/api/workshop/aml/index6.get.mjs +1 -1
  202. package/.output/server/chunks/routes/api/workshop/aml/index7.get.mjs +1 -1
  203. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/cancel.post.mjs +1 -1
  204. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/logs.get.mjs +1 -1
  205. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id/retry.post.mjs +1 -1
  206. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.delete.mjs +1 -1
  207. package/.output/server/chunks/routes/api/workshop/aml/jobs/_id_.get.mjs +1 -1
  208. package/.output/server/chunks/routes/api/workshop/aml/models/_id/predict.post.mjs +1 -1
  209. package/.output/server/chunks/routes/api/workshop/aml/models/_id/promote.post.mjs +1 -1
  210. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.delete.mjs +1 -1
  211. package/.output/server/chunks/routes/api/workshop/aml/models/_id_.patch.mjs +1 -1
  212. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id/train.post.mjs +1 -1
  213. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.delete.mjs +1 -1
  214. package/.output/server/chunks/routes/api/workshop/aml/training-plans/_id_.patch.mjs +1 -1
  215. package/.output/server/chunks/routes/api/workshop/aml/twin/providers.get.mjs +1 -1
  216. package/.output/server/chunks/routes/api/workshop/analysis/_id_.delete.mjs +1 -1
  217. package/.output/server/chunks/routes/api/workshop/analysis/_id_.get.mjs +1 -1
  218. package/.output/server/chunks/routes/api/workshop/analysis/_id_.patch.mjs +1 -1
  219. package/.output/server/chunks/routes/api/workshop/approvals/_id/decide.post.mjs +1 -1
  220. package/.output/server/chunks/routes/api/workshop/assets/character/_id_.delete.mjs +1 -1
  221. package/.output/server/chunks/routes/api/workshop/assets/devices/_id_.delete.mjs +1 -1
  222. package/.output/server/chunks/routes/api/workshop/assets/index.get.mjs +1 -1
  223. package/.output/server/chunks/routes/api/workshop/assets/index.post.mjs +1 -1
  224. package/.output/server/chunks/routes/api/workshop/assets/index2.get.mjs +1 -1
  225. package/.output/server/chunks/routes/api/workshop/assets/index2.post.mjs +1 -1
  226. package/.output/server/chunks/routes/api/workshop/audit.get.mjs +1 -1
  227. package/.output/server/chunks/routes/api/workshop/caller.mjs +1 -1
  228. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +2 -2
  229. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.delete.mjs +1 -1
  230. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.get.mjs +1 -1
  231. package/.output/server/chunks/routes/api/workshop/channel-templates/_id_.patch.mjs +1 -1
  232. package/.output/server/chunks/routes/api/workshop/channel-templates/from-channel.post.mjs +1 -1
  233. package/.output/server/chunks/routes/api/workshop/channels/_id/activate.post.mjs +1 -1
  234. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.get.mjs +1 -1
  235. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/index.post.mjs +1 -1
  236. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/_memoryId_.delete.mjs +1 -1
  237. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/memories/search.post.mjs +1 -1
  238. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/model.patch.mjs +1 -1
  239. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/position.patch.mjs +1 -1
  240. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/range.patch.mjs +1 -1
  241. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/rotate-token.post.mjs +1 -1
  242. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId/stop.post.mjs +1 -1
  243. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.delete.mjs +1 -1
  244. package/.output/server/chunks/routes/api/workshop/channels/_id/agents/_agentId_.patch.mjs +1 -1
  245. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.get.mjs +1 -1
  246. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/index.post.mjs +1 -1
  247. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/messages/_messageId/read.post.mjs +1 -1
  248. package/.output/server/chunks/routes/api/workshop/channels/_id/chat/permissions.get.mjs +1 -1
  249. package/.output/server/chunks/routes/api/workshop/channels/_id/events.get.mjs +1 -1
  250. package/.output/server/chunks/routes/api/workshop/channels/_id/execution-mode.patch.mjs +1 -1
  251. package/.output/server/chunks/routes/api/workshop/channels/_id/index.get.mjs +1 -1
  252. package/.output/server/chunks/routes/api/workshop/channels/_id/index.post.mjs +1 -1
  253. package/.output/server/chunks/routes/api/workshop/channels/_id/index.put.mjs +1 -1
  254. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.get.mjs +1 -1
  255. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.post.mjs +1 -1
  256. package/.output/server/chunks/routes/api/workshop/channels/_id/index2.put.mjs +1 -1
  257. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.get.mjs +1 -1
  258. package/.output/server/chunks/routes/api/workshop/channels/_id/index3.post.mjs +1 -1
  259. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.get.mjs +1 -1
  260. package/.output/server/chunks/routes/api/workshop/channels/_id/index4.post.mjs +1 -1
  261. package/.output/server/chunks/routes/api/workshop/channels/_id/index5.get.mjs +1 -1
  262. package/.output/server/chunks/routes/api/workshop/channels/_id/index6.get.mjs +1 -1
  263. package/.output/server/chunks/routes/api/workshop/channels/_id/index7.get.mjs +1 -1
  264. package/.output/server/chunks/routes/api/workshop/channels/_id/line.put.mjs +1 -1
  265. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId/approve.post.mjs +1 -1
  266. package/.output/server/chunks/routes/api/workshop/channels/_id/members/_userId_.delete.mjs +1 -1
  267. package/.output/server/chunks/routes/api/workshop/channels/_id/members/join.post.mjs +1 -1
  268. package/.output/server/chunks/routes/api/workshop/channels/_id/members/leave.post.mjs +1 -1
  269. package/.output/server/chunks/routes/api/workshop/channels/_id/memories/_memoryId_.delete.mjs +1 -1
  270. package/.output/server/chunks/routes/api/workshop/channels/_id/queue.get.mjs +1 -1
  271. package/.output/server/chunks/routes/api/workshop/channels/_id/terminals.get.mjs +1 -1
  272. package/.output/server/chunks/routes/api/workshop/channels/_id/tools/reset.post.mjs +1 -1
  273. package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.get.mjs +1 -1
  274. package/.output/server/chunks/routes/api/workshop/channels/_id/twin-profile.patch.mjs +1 -1
  275. package/.output/server/chunks/routes/api/workshop/channels/_id_.delete.mjs +1 -1
  276. package/.output/server/chunks/routes/api/workshop/channels/index.get.mjs +1 -1
  277. package/.output/server/chunks/routes/api/workshop/channels/index.patch.mjs +1 -1
  278. package/.output/server/chunks/routes/api/workshop/channels.get.mjs +1 -1
  279. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +7 -7
  280. package/.output/server/chunks/routes/api/workshop/daq/_id/bind.post.mjs +1 -1
  281. package/.output/server/chunks/routes/api/workshop/daq/_id/bindings.put.mjs +1 -1
  282. package/.output/server/chunks/routes/api/workshop/daq/_id/frames/content.get.mjs +1 -1
  283. package/.output/server/chunks/routes/api/workshop/daq/_id/frames.get.mjs +1 -1
  284. package/.output/server/chunks/routes/api/workshop/daq/_id/ingest.post.mjs +2 -2
  285. package/.output/server/chunks/routes/api/workshop/daq/_id/samples.get.mjs +1 -1
  286. package/.output/server/chunks/routes/api/workshop/daq/_id/test.post.mjs +1 -1
  287. package/.output/server/chunks/routes/api/workshop/daq/_id_.delete.mjs +1 -1
  288. package/.output/server/chunks/routes/api/workshop/daq/_id_.patch.mjs +1 -1
  289. package/.output/server/chunks/routes/api/workshop/daq/alarms/_id/ack.post.mjs +1 -1
  290. package/.output/server/chunks/routes/api/workshop/daq/alarms.get.mjs +1 -1
  291. package/.output/server/chunks/routes/api/workshop/daq/controller.post.mjs +1 -1
  292. package/.output/server/chunks/routes/api/workshop/daq/export/_id_.get.mjs +1 -1
  293. package/.output/server/chunks/routes/api/workshop/daq/export-file.get.mjs +1 -1
  294. package/.output/server/chunks/routes/api/workshop/daq/index.get.mjs +1 -1
  295. package/.output/server/chunks/routes/api/workshop/daq/index.post.mjs +1 -1
  296. package/.output/server/chunks/routes/api/workshop/daq/index2.post.mjs +1 -1
  297. package/.output/server/chunks/routes/api/workshop/daq/infra/reconnect.post.mjs +1 -1
  298. package/.output/server/chunks/routes/api/workshop/daq/infra.get.mjs +1 -1
  299. package/.output/server/chunks/routes/api/workshop/daq/query.get.mjs +1 -1
  300. package/.output/server/chunks/routes/api/workshop/daq/storage/retention.put.mjs +1 -1
  301. package/.output/server/chunks/routes/api/workshop/daq/storage/rollup.post.mjs +1 -1
  302. package/.output/server/chunks/routes/api/workshop/daq/storage.get.mjs +1 -1
  303. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.delete.mjs +1 -1
  304. package/.output/server/chunks/routes/api/workshop/daq/templates/_key_.patch.mjs +1 -1
  305. package/.output/server/chunks/routes/api/workshop/daq/test-driver.post.mjs +1 -1
  306. package/.output/server/chunks/routes/api/workshop/dcw/_id/bind.post.mjs +1 -1
  307. package/.output/server/chunks/routes/api/workshop/dcw/_id/bindings.put.mjs +1 -1
  308. package/.output/server/chunks/routes/api/workshop/dcw/_id/param-ledger.get.mjs +1 -1
  309. package/.output/server/chunks/routes/api/workshop/dcw/_id/read.post.mjs +1 -1
  310. package/.output/server/chunks/routes/api/workshop/dcw/_id/test.post.mjs +1 -1
  311. package/.output/server/chunks/routes/api/workshop/dcw/_id/write.post.mjs +1 -1
  312. package/.output/server/chunks/routes/api/workshop/dcw/_id_.delete.mjs +1 -1
  313. package/.output/server/chunks/routes/api/workshop/dcw/_id_.patch.mjs +1 -1
  314. package/.output/server/chunks/routes/api/workshop/dcw/controller.post.mjs +1 -1
  315. package/.output/server/chunks/routes/api/workshop/dcw/index.get.mjs +1 -1
  316. package/.output/server/chunks/routes/api/workshop/dcw/index.post.mjs +1 -1
  317. package/.output/server/chunks/routes/api/workshop/dcw/index2.get.mjs +1 -1
  318. package/.output/server/chunks/routes/api/workshop/dcw/index2.post.mjs +1 -1
  319. package/.output/server/chunks/routes/api/workshop/dcw/index3.get.mjs +1 -1
  320. package/.output/server/chunks/routes/api/workshop/dcw/index3.post.mjs +1 -1
  321. package/.output/server/chunks/routes/api/workshop/dcw/index4.get.mjs +1 -1
  322. package/.output/server/chunks/routes/api/workshop/dcw/index4.post.mjs +1 -1
  323. package/.output/server/chunks/routes/api/workshop/dcw/index5.get.mjs +1 -1
  324. package/.output/server/chunks/routes/api/workshop/dcw/index5.post.mjs +1 -1
  325. package/.output/server/chunks/routes/api/workshop/dcw/index6.get.mjs +1 -1
  326. package/.output/server/chunks/routes/api/workshop/dcw/index7.get.mjs +1 -1
  327. package/.output/server/chunks/routes/api/workshop/dcw/journal/node/_nodeId/rollback.post.mjs +1 -1
  328. package/.output/server/chunks/routes/api/workshop/dcw/line/query.get.mjs +1 -1
  329. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/start.post.mjs +1 -1
  330. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id/stop.post.mjs +1 -1
  331. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.delete.mjs +1 -1
  332. package/.output/server/chunks/routes/api/workshop/dcw/lines/_id_.patch.mjs +1 -1
  333. package/.output/server/chunks/routes/api/workshop/dcw/mes-artifacts/file.get.mjs +1 -1
  334. package/.output/server/chunks/routes/api/workshop/dcw/mes-hook-test.post.mjs +1 -1
  335. package/.output/server/chunks/routes/api/workshop/dcw/mes-test-read.post.mjs +1 -1
  336. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/judge.post.mjs +1 -1
  337. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/rollback.post.mjs +1 -1
  338. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id/series.get.mjs +1 -1
  339. package/.output/server/chunks/routes/api/workshop/dcw/optimizations/_id_.get.mjs +1 -1
  340. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/read.post.mjs +1 -1
  341. package/.output/server/chunks/routes/api/workshop/dcw/params/_id/write.post.mjs +1 -1
  342. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.delete.mjs +1 -1
  343. package/.output/server/chunks/routes/api/workshop/dcw/params/_id_.patch.mjs +1 -1
  344. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.delete.mjs +1 -1
  345. package/.output/server/chunks/routes/api/workshop/dcw/products/_id_.patch.mjs +1 -1
  346. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/apply.post.mjs +1 -1
  347. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/mark-good.post.mjs +1 -1
  348. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/revert.post.mjs +1 -1
  349. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/rollback-good.post.mjs +1 -1
  350. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id/versions.get.mjs +1 -1
  351. package/.output/server/chunks/routes/api/workshop/dcw/recipes/_id_.delete.mjs +2 -2
  352. package/.output/server/chunks/routes/api/workshop/dcw/recipes/index.patch.mjs +1 -1
  353. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/close.post.mjs +1 -1
  354. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/data.get.mjs +1 -1
  355. package/.output/server/chunks/routes/api/workshop/dcw/runs/_id/rollback.post.mjs +1 -1
  356. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.delete.mjs +1 -1
  357. package/.output/server/chunks/routes/api/workshop/dcw/templates/_key_.patch.mjs +1 -1
  358. package/.output/server/chunks/routes/api/workshop/dcw/test-driver.post.mjs +1 -1
  359. package/.output/server/chunks/routes/api/workshop/device-twins/_id/control.post.mjs +1 -1
  360. package/.output/server/chunks/routes/api/workshop/device-twins/_id/telemetry.post.mjs +1 -1
  361. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.delete.mjs +1 -1
  362. package/.output/server/chunks/routes/api/workshop/device-twins/_id_.patch.mjs +1 -1
  363. package/.output/server/chunks/routes/api/workshop/eda/charts/_id_.delete.mjs +1 -1
  364. package/.output/server/chunks/routes/api/workshop/eda/charts/_id_.get.mjs +1 -1
  365. package/.output/server/chunks/routes/api/workshop/eda/charts/_id_.patch.mjs +1 -1
  366. package/.output/server/chunks/routes/api/workshop/eda/commonality.get.mjs +1 -1
  367. package/.output/server/chunks/routes/api/workshop/eda/dashboards/_id_.delete.mjs +1 -1
  368. package/.output/server/chunks/routes/api/workshop/eda/dashboards/_id_.get.mjs +1 -1
  369. package/.output/server/chunks/routes/api/workshop/eda/dashboards/_id_.patch.mjs +1 -1
  370. package/.output/server/chunks/routes/api/workshop/eda/features/jobs.get.mjs +1 -1
  371. package/.output/server/chunks/routes/api/workshop/eda/features/run.post.mjs +1 -1
  372. package/.output/server/chunks/routes/api/workshop/eda/golden/_id_.delete.mjs +1 -1
  373. package/.output/server/chunks/routes/api/workshop/eda/golden/deviation.get.mjs +1 -1
  374. package/.output/server/chunks/routes/api/workshop/eda/golden/single.get.mjs +1 -1
  375. package/.output/server/chunks/routes/api/workshop/eda/index.get.mjs +1 -1
  376. package/.output/server/chunks/routes/api/workshop/eda/index.post.mjs +1 -1
  377. package/.output/server/chunks/routes/api/workshop/eda/index2.get.mjs +1 -1
  378. package/.output/server/chunks/routes/api/workshop/eda/index2.post.mjs +1 -1
  379. package/.output/server/chunks/routes/api/workshop/eda/index3.get.mjs +1 -1
  380. package/.output/server/chunks/routes/api/workshop/eda/index3.post.mjs +1 -1
  381. package/.output/server/chunks/routes/api/workshop/eda/index4.get.mjs +1 -1
  382. package/.output/server/chunks/routes/api/workshop/eda/index4.post.mjs +1 -1
  383. package/.output/server/chunks/routes/api/workshop/eda/index5.get.mjs +1 -1
  384. package/.output/server/chunks/routes/api/workshop/eda/index5.post.mjs +1 -1
  385. package/.output/server/chunks/routes/api/workshop/eda/index6.get.mjs +1 -1
  386. package/.output/server/chunks/routes/api/workshop/eda/index6.post.mjs +1 -1
  387. package/.output/server/chunks/routes/api/workshop/eda/index7.get.mjs +1 -1
  388. package/.output/server/chunks/routes/api/workshop/eda/index7.post.mjs +1 -1
  389. package/.output/server/chunks/routes/api/workshop/eda/index8.get.mjs +1 -1
  390. package/.output/server/chunks/routes/api/workshop/eda/index8.post.mjs +1 -1
  391. package/.output/server/chunks/routes/api/workshop/eda/ocap/_id_.get.mjs +1 -1
  392. package/.output/server/chunks/routes/api/workshop/eda/ocap/_id_.patch.mjs +1 -1
  393. package/.output/server/chunks/routes/api/workshop/eda/runs/_id/labels.patch.mjs +1 -1
  394. package/.output/server/chunks/routes/api/workshop/eda/runs.get.mjs +1 -1
  395. package/.output/server/chunks/routes/api/workshop/eda/spc/_id/recompute.post.mjs +1 -1
  396. package/.output/server/chunks/routes/api/workshop/eda/spc/_id_.delete.mjs +1 -1
  397. package/.output/server/chunks/routes/api/workshop/eda/spc/_id_.get.mjs +1 -1
  398. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.delete.mjs +1 -1
  399. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.get.mjs +1 -1
  400. package/.output/server/chunks/routes/api/workshop/eda/templates/_id_.patch.mjs +1 -1
  401. package/.output/server/chunks/routes/api/workshop/eda/vm/predict.post.mjs +1 -1
  402. package/.output/server/chunks/routes/api/workshop/exp/confirmations/_id/decide.post.mjs +1 -1
  403. package/.output/server/chunks/routes/api/workshop/exp/index.get.mjs +1 -1
  404. package/.output/server/chunks/routes/api/workshop/fs/dirs.get.mjs +1 -1
  405. package/.output/server/chunks/routes/api/workshop/harnesses/_id/providers.get.mjs +1 -1
  406. package/.output/server/chunks/routes/api/workshop/harnesses.get.mjs +1 -1
  407. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +1 -1
  408. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +1 -1
  409. package/.output/server/chunks/routes/api/workshop/index.get.mjs +1 -1
  410. package/.output/server/chunks/routes/api/workshop/index.mjs +1 -1
  411. package/.output/server/chunks/routes/api/workshop/index.post.mjs +1 -1
  412. package/.output/server/chunks/routes/api/workshop/index.put.mjs +1 -1
  413. package/.output/server/chunks/routes/api/workshop/index10.get.mjs +1 -1
  414. package/.output/server/chunks/routes/api/workshop/index10.post.mjs +1 -1
  415. package/.output/server/chunks/routes/api/workshop/index11.get.mjs +1 -1
  416. package/.output/server/chunks/routes/api/workshop/index12.get.mjs +1 -1
  417. package/.output/server/chunks/routes/api/workshop/index13.get.mjs +1 -1
  418. package/.output/server/chunks/routes/api/workshop/index14.get.mjs +1 -1
  419. package/.output/server/chunks/routes/api/workshop/index15.get.mjs +1 -1
  420. package/.output/server/chunks/routes/api/workshop/index16.get.mjs +1 -1
  421. package/.output/server/chunks/routes/api/workshop/index2.get.mjs +1 -1
  422. package/.output/server/chunks/routes/api/workshop/index2.post.mjs +1 -1
  423. package/.output/server/chunks/routes/api/workshop/index3.get.mjs +1 -1
  424. package/.output/server/chunks/routes/api/workshop/index3.post.mjs +1 -1
  425. package/.output/server/chunks/routes/api/workshop/index4.get.mjs +1 -1
  426. package/.output/server/chunks/routes/api/workshop/index4.post.mjs +1 -1
  427. package/.output/server/chunks/routes/api/workshop/index5.get.mjs +1 -1
  428. package/.output/server/chunks/routes/api/workshop/index5.post.mjs +1 -1
  429. package/.output/server/chunks/routes/api/workshop/index6.get.mjs +1 -1
  430. package/.output/server/chunks/routes/api/workshop/index6.post.mjs +1 -1
  431. package/.output/server/chunks/routes/api/workshop/index7.get.mjs +1 -1
  432. package/.output/server/chunks/routes/api/workshop/index7.post.mjs +1 -1
  433. package/.output/server/chunks/routes/api/workshop/index8.get.mjs +1 -1
  434. package/.output/server/chunks/routes/api/workshop/index8.post.mjs +1 -1
  435. package/.output/server/chunks/routes/api/workshop/index9.get.mjs +1 -1
  436. package/.output/server/chunks/routes/api/workshop/index9.post.mjs +1 -1
  437. package/.output/server/chunks/routes/api/workshop/mailbox/all.get.mjs +1 -1
  438. package/.output/server/chunks/routes/api/workshop/mailbox.get.mjs +1 -1
  439. package/.output/server/chunks/routes/api/workshop/memories/maintenance.post.mjs +1 -1
  440. package/.output/server/chunks/routes/api/workshop/mes/datasets.get.mjs +1 -1
  441. package/.output/server/chunks/routes/api/workshop/mes/index.get.mjs +1 -1
  442. package/.output/server/chunks/routes/api/workshop/mes/index.put.mjs +1 -1
  443. package/.output/server/chunks/routes/api/workshop/mes/points.get.mjs +1 -1
  444. package/.output/server/chunks/routes/api/workshop/mes/preview.post.mjs +1 -1
  445. package/.output/server/chunks/routes/api/workshop/mes/secrets/_ref_.delete.mjs +1 -1
  446. package/.output/server/chunks/routes/api/workshop/notifications/read.post.mjs +1 -1
  447. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/autofix.mjs +1 -1
  448. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/compile.mjs +1 -1
  449. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/evidence.mjs +1 -1
  450. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/publish.mjs +1 -1
  451. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/approval-decision.mjs +1 -1
  452. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/approval.mjs +1 -1
  453. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/rules/_ruleId/transition.mjs +1 -1
  454. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/subgraph.mjs +1 -1
  455. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId/validate.mjs +1 -1
  456. package/.output/server/chunks/routes/api/workshop/ontology/drafts/_draftId_.mjs +1 -1
  457. package/.output/server/chunks/routes/api/workshop/ontology/export/_ontologyId_.mjs +1 -1
  458. package/.output/server/chunks/routes/api/workshop/ontology/index.mjs +1 -1
  459. package/.output/server/chunks/routes/api/workshop/ontology/scene.mjs +1 -1
  460. package/.output/server/chunks/routes/api/workshop/ontology/traces/_ontologyId_.mjs +1 -1
  461. package/.output/server/chunks/routes/api/workshop/ontology/versions/_ontologyId/compare.mjs +1 -1
  462. package/.output/server/chunks/routes/api/workshop/ontology/versions/_ontologyId_.mjs +1 -1
  463. package/.output/server/chunks/routes/api/workshop/optimization/bindings/_id_.delete.mjs +1 -1
  464. package/.output/server/chunks/routes/api/workshop/optimization/capabilities.get.mjs +1 -1
  465. package/.output/server/chunks/routes/api/workshop/optimization/index.get.mjs +1 -1
  466. package/.output/server/chunks/routes/api/workshop/optimization/index.mjs +1 -1
  467. package/.output/server/chunks/routes/api/workshop/optimization/index2.mjs +1 -1
  468. package/.output/server/chunks/routes/api/workshop/optimization/profiles/_id/publish.post.mjs +1 -1
  469. package/.output/server/chunks/routes/api/workshop/optimization/recommendations/_id/crosscheck.post.mjs +1 -1
  470. package/.output/server/chunks/routes/api/workshop/optimization/recommendations/_id/dispatch.post.mjs +1 -1
  471. package/.output/server/chunks/routes/api/workshop/optimization/solve.post.mjs +1 -1
  472. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  473. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  474. package/.output/server/chunks/routes/api/workshop/plugins/index.get.mjs +1 -1
  475. package/.output/server/chunks/routes/api/workshop/process-model/datasets.post.mjs +1 -1
  476. package/.output/server/chunks/routes/api/workshop/process-model/eligibility.mjs +1 -1
  477. package/.output/server/chunks/routes/api/workshop/process-model/experiments.mjs +370 -20
  478. package/.output/server/chunks/routes/api/workshop/process-model/experiments.mjs.map +1 -1
  479. package/.output/server/chunks/routes/api/workshop/process-model/index.mjs +1 -1
  480. package/.output/server/chunks/routes/api/workshop/process-model/specs/_id/publish.post.mjs +1 -1
  481. package/.output/server/chunks/routes/api/workshop/process-model/train.post.mjs +1 -1
  482. package/.output/server/chunks/routes/api/workshop/runtime.get.mjs +1 -1
  483. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  484. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  485. package/.output/server/chunks/routes/api/workshop/scene/layouts.get.mjs +1 -1
  486. package/.output/server/chunks/routes/api/workshop/schedules/_id/run.post.mjs +1 -1
  487. package/.output/server/chunks/routes/api/workshop/schedules/_id/runs.get.mjs +1 -1
  488. package/.output/server/chunks/routes/api/workshop/schedules/_id_.delete.mjs +1 -1
  489. package/.output/server/chunks/routes/api/workshop/schedules/_id_.get.mjs +1 -1
  490. package/.output/server/chunks/routes/api/workshop/schedules/_id_.patch.mjs +1 -1
  491. package/.output/server/chunks/routes/api/workshop/tasks/_id/complete.post.mjs +1 -1
  492. package/.output/server/chunks/routes/api/workshop/tasks/_id/dispatch.post.mjs +1 -1
  493. package/.output/server/chunks/routes/api/workshop/tasks/_id/index.post.mjs +1 -1
  494. package/.output/server/chunks/routes/api/workshop/tasks/_id/reassign.post.mjs +1 -1
  495. package/.output/server/chunks/routes/api/workshop/tasks/_id/reopen.post.mjs +1 -1
  496. package/.output/server/chunks/routes/api/workshop/tasks/_id/report.post.mjs +1 -1
  497. package/.output/server/chunks/routes/api/workshop/tasks/_id/retry.post.mjs +1 -1
  498. package/.output/server/chunks/routes/api/workshop/tasks/_id/supersede.post.mjs +1 -1
  499. package/.output/server/chunks/routes/api/workshop/tasks/_id/update.post.mjs +1 -1
  500. package/.output/server/chunks/routes/api/workshop/tasks/_id_.get.mjs +1 -1
  501. package/.output/server/chunks/routes/api/workshop/tasks.get.mjs +1 -1
  502. package/.output/server/chunks/routes/api/workshop/teams/_id/deploy.post.mjs +1 -1
  503. package/.output/server/chunks/routes/api/workshop/teams/_id/index.get.mjs +1 -1
  504. package/.output/server/chunks/routes/api/workshop/teams/_id/index.post.mjs +1 -1
  505. package/.output/server/chunks/routes/api/workshop/teams/_id/index.put.mjs +1 -1
  506. package/.output/server/chunks/routes/api/workshop/teams/_id/index2.get.mjs +1 -1
  507. package/.output/server/chunks/routes/api/workshop/teams/_id/members/_agentId_.delete.mjs +1 -1
  508. package/.output/server/chunks/routes/api/workshop/teams/_id_.delete.mjs +1 -1
  509. package/.output/server/chunks/routes/api/workshop/teams/_id_.get.mjs +1 -1
  510. package/.output/server/chunks/routes/api/workshop/teams/_id_.patch.mjs +1 -1
  511. package/.output/server/chunks/routes/api/workshop/tools/_name_.get.mjs +1 -1
  512. package/.output/server/chunks/routes/api/workshop/tools/sync.post.mjs +1 -1
  513. package/.output/server/chunks/routes/api/workshop/users/me.get.mjs +1 -1
  514. package/.output/server/chunks/routes/api/workshop/users/register.post.mjs +1 -1
  515. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +2 -2
  516. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.delete.mjs +1 -1
  517. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channels/_channelId_.post.mjs +1 -1
  518. package/.output/server/chunks/routes/api/workshop/workspaces/index.delete.mjs +1 -1
  519. package/.output/server/chunks/routes/renderer.mjs +2 -2
  520. package/.output/server/chunks/virtual/entry.mjs +5 -1
  521. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  522. package/.output/server/index.mjs +1 -1
  523. package/.output/server/package.json +1 -1
  524. package/README-zh.md +3 -3
  525. package/README.md +3 -3
  526. package/config.yml +1 -1
  527. package/docs/aml.md +112 -112
  528. package/docs/cli.en.md +4 -4
  529. package/docs/cli.md +3 -3
  530. package/docs/plugins.en.md +1 -1
  531. package/docs/plugins.md +1 -1
  532. package/docs/sdk.en.md +1 -1
  533. package/docs/sdk.md +1 -1
  534. package/i18n/locales/en.ts +2 -0
  535. package/i18n/locales/zh-CN.ts +2 -0
  536. package/package.json +1 -1
  537. package/scripts/_audit/demo-shot-studio.mjs +37 -0
  538. package/scripts/_audit/demo-shots.mjs +38 -0
  539. package/scripts/_audit/gen-demo-report.py +69 -0
  540. package/scripts/_audit/mqtt-pub.mjs +13 -0
  541. package/scripts/_audit/mqtt-topic-probe.mjs +15 -0
  542. package/scripts/_audit/proto-b3-device-4021.mjs +90 -0
  543. package/scripts/_audit/proto-doc-device-4120.mjs +53 -0
  544. package/scripts/acceptance-scientific-loop.ts +240 -0
  545. package/scripts/generate-identifiability-fixtures.ts +98 -0
  546. package/server/api/workshop/process-model/experiments.ts +28 -2
  547. package/server/plugins-builtin/diag-bridge/host/plugin.mjs +759 -753
  548. package/server/plugins-builtin/rag-bridge/index.mjs +490 -484
  549. package/server/repositories/user.repository.ts +24 -1
  550. package/server/services/user.service.ts +8 -6
  551. package/server/services/workshop/agents/host-tool-bridge/catalog.ts +2 -0
  552. package/server/services/workshop/agents/host-tool-bridge/tools/industrial.ts +4 -1
  553. package/server/services/workshop/agents/host-tool-bridge/tools/messaging.ts +5 -1
  554. package/server/services/workshop/agents/industrial/aml-dataset-tools.ts +3 -0
  555. package/server/services/workshop/agents/industrial/bench-approval-only.ts +335 -58
  556. package/server/services/workshop/agents/industrial/dcw-tools.ts +7 -1
  557. package/server/services/workshop/agents/industrial/identifiability-tools.ts +247 -0
  558. package/server/services/workshop/agents/industrial/index.ts +1 -0
  559. package/server/services/workshop/agents/industrial/manual-approval.ts +3 -1
  560. package/server/services/workshop/agents/industrial/ops-tools.ts +58 -15
  561. package/server/services/workshop/agents/industrial/optimization-tools.ts +49 -19
  562. package/server/services/workshop/agents/plugin-governance.ts +22 -2
  563. package/server/services/workshop/aml/action-coverage.ts +253 -0
  564. package/server/services/workshop/aml/causal-claim.ts +68 -0
  565. package/server/services/workshop/aml/dataset-builder.ts +19 -0
  566. package/server/services/workshop/aml/gates.ts +45 -1
  567. package/server/services/workshop/aml/identifiability.ts +335 -0
  568. package/server/services/workshop/aml/intervention-ledger.ts +289 -0
  569. package/server/services/workshop/aml/ontology-learning.ts +143 -0
  570. package/server/services/workshop/aml/twin/cross-check-service.ts +114 -0
  571. package/server/services/workshop/aml/twin/cross-check.ts +176 -0
  572. package/server/services/workshop/daq/daq-controller/contracts.ts +3 -0
  573. package/server/services/workshop/daq/daq-controller/crud.ts +12 -2
  574. package/server/services/workshop/daq/daq-controller/push.ts +22 -0
  575. package/server/services/workshop/daq/drivers/mqtt.ts +28 -0
  576. package/server/services/workshop/daq/drivers/shared.ts +6 -0
  577. package/server/services/workshop/db/database/open.ts +2 -0
  578. package/server/services/workshop/db/database/rows.ts +4 -1
  579. package/server/services/workshop/db/database/schema.ts +38 -2
  580. package/server/services/workshop/db/message.repo.ts +10 -3
  581. package/server/services/workshop/dcw/dcw-controller/write-audit.ts +21 -1
  582. package/server/services/workshop/process-model/experiment-runner.ts +437 -0
  583. package/server/services/workshop/process-model/experiment.ts +31 -10
  584. package/server/services/workshop/process-model/plan-safety.ts +69 -0
  585. package/server/services/workshop/runtime/agent-runtime/lifecycle.ts +34 -11
  586. package/server/services/workshop/runtime/agent-runtime/state.ts +6 -1
  587. package/server/services/workshop/settings.ts +4 -1
  588. package/server/services/workshop/types/a2a.ts +16 -1
  589. package/shared/config/schema.json +2 -0
  590. package/shared/dcw-protocol/closed-loop.ts +2 -0
  591. package/.output/public/_nuxt/builds/meta/1231252d-2864-43c0-83b2-4e70d3b86dea.json +0 -1
@@ -7,7 +7,7 @@ import type { DatabaseSync } from 'node:sqlite'
7
7
  import type { MessageRow } from './database'
8
8
 
9
9
  const COLS
10
- = 'id, channel_id AS channelId, task_id AS taskId, from_agent_id AS fromAgentId, to_agent_id AS toAgentId, role, parts_json AS partsJson, metadata_json AS metadataJson, state, created_at AS createdAt, consumed_at AS consumedAt'
10
+ = 'id, channel_id AS channelId, task_id AS taskId, from_agent_id AS fromAgentId, to_agent_id AS toAgentId, role, parts_json AS partsJson, metadata_json AS metadataJson, state, attempts, created_at AS createdAt, consumed_at AS consumedAt'
11
11
 
12
12
  export interface MessageCreateInput {
13
13
  /** 落库 id;缺省生成。A2A 入队时传发送方 messageId,保证 API 返回 id 与历史 id 一致 */
@@ -43,10 +43,16 @@ export function createMessageRepo(db: DatabaseSync) {
43
43
  `UPDATE messages SET state = 'consumed', consumed_at = ? WHERE id = ?`,
44
44
  )
45
45
  const resetConsumingStmt = db.prepare(
46
- `UPDATE messages SET state = 'pending' WHERE state = 'consuming'`,
46
+ // P3-4:崩溃恢复重投不复活 dead(重投上限是持久判定,重启不洗白)
47
+ `UPDATE messages SET state = 'pending' WHERE state = 'consuming' AND attempts < 3`,
47
48
  )
48
49
  const requeueStmt = db.prepare(
49
- `UPDATE messages SET state = 'pending' WHERE id = ? AND state = 'consuming'`,
50
+ // P3-4(2026-11-01):重投计数上限 —— attempts+1,达 3 次不再回 pending(→ dead)。
51
+ // steer 对忙碌 Agent 的重投之前无上限:坏消息(解析必炸/超长)会在
52
+ // "认领→steer 失败→回 pending"里无限循环,每 250ms 吃掉一个调度拍。
53
+ `UPDATE messages SET attempts = attempts + 1,
54
+ state = CASE WHEN attempts + 1 >= 3 THEN 'dead' ELSE 'pending' END
55
+ WHERE id = ? AND state = 'consuming'`,
50
56
  )
51
57
  const consumePendingByTaskStmt = db.prepare(
52
58
  `UPDATE messages SET state = 'consumed', consumed_at = ? WHERE task_id = ? AND state = 'pending'`,
@@ -78,6 +84,7 @@ export function createMessageRepo(db: DatabaseSync) {
78
84
  partsJson: JSON.stringify(input.parts),
79
85
  metadataJson: JSON.stringify(input.metadata ?? {}),
80
86
  state: 'pending',
87
+ attempts: 0,
81
88
  createdAt: now,
82
89
  consumedAt: null,
83
90
  }
@@ -9,6 +9,7 @@ import { emitDcwWrite } from '@/server/services/workshop/plugins/host.mjs'
9
9
  import { getActiveLineRun } from '../line-run'
10
10
  import { opsActorKindOf } from './helpers'
11
11
  import { recordOps } from '../../ops/ops'
12
+ import { recordIntervention } from '../../aml/intervention-ledger'
12
13
 
13
14
  /** 同节点写入去重节流表(eng+10s 窗内视为同一次下发的重试回执) */
14
15
  export const opsWriteMemo = new Map<string, { eng: number, at: number }>()
@@ -18,7 +19,7 @@ export function recordDcwWriteOps(args: {
18
19
  node: { name: string, unit?: string, lineId: string }
19
20
  eng: number
20
21
  prevValue: number | null
21
- outcome: { ok: boolean, message: string }
22
+ outcome: { ok: boolean, message: string, ack?: string, readback?: number | null }
22
23
  src: DcwWriteSource
23
24
  meta?: DcwWriteMeta
24
25
  recipeRunId: string | null
@@ -46,4 +47,23 @@ export function recordDcwWriteOps(args: {
46
47
  })
47
48
  // 插件钩子:写控 ACK 观察(与运维入册同点同去重节流)
48
49
  emitDcwWrite({ nodeId: args.id, name: args.node.name, eng: args.eng, prevValue: args.prevValue, ok: args.outcome.ok, source: args.src, lineId: args.node.lineId ?? '', at: new Date().toISOString() })
50
+ // v34 干预台账(科学探索计划 P2):全路径单点入册(与运维日志同点同去重节流)。
51
+ // 只记已受理下发;拒绝路径沿上方 recordOps 的 dcw.write.rejected 审计,不入台账。
52
+ // recordIntervention 内部自吞异常(台账失败绝不改变写结果语义)。
53
+ recordIntervention({
54
+ nodeId: args.id,
55
+ nodeName: args.node.name,
56
+ lineId: args.node.lineId ?? '',
57
+ fromValue: args.prevValue,
58
+ toValue: args.eng,
59
+ actualValue: args.outcome.readback != null && Number.isFinite(Number(args.outcome.readback)) ? Number(args.outcome.readback) : null,
60
+ ack: args.outcome.ack ?? '',
61
+ path: args.src,
62
+ actor: args.meta?.actor ?? 'user',
63
+ actorName: args.meta?.actorName ?? '',
64
+ channelId: args.meta?.channelId ?? '',
65
+ approvalId: args.meta?.approvalId ?? null,
66
+ recipeRunId: args.recipeRunId,
67
+ hypothesis: args.meta?.hypothesis ?? '',
68
+ })
49
69
  }
@@ -0,0 +1,437 @@
1
+ /**
2
+ * 参数试验计划执行器(科学探索计划 P4,docs/plans/2026-11-02-scientific-exploration-plan.md):
3
+ * 把 process_model_experiments 从"仅仿真线可建"升级为**治理分档**:
4
+ * - simulated=true → tier=sim_auto:建计划即可执行(既有行为不变);
5
+ * - 真实线 → tier=real_hitl:建计划落 awaiting_approval,须单卡 HITL 批准(卡上带成本核算)
6
+ * 后转 planned 才能执行。
7
+ * 执行语义(正交化由机制保证,不靠 Agent 自觉):
8
+ * - 步序 = repeats × levels,默认 seeded 随机化(randomizedOrder=false 时按原序);
9
+ * - 每步:写控制(走 DcwController.write 咽喉,source=agent → 步长/60s 间隔/保持窗照常生效)
10
+ * → 等 settleMs → 等 observeMs → 下一步;
11
+ * - 预算:步数上限 + 总时长上限,超限即 FAILED 并写明原因(不静默续跑);
12
+ * - abortOnAlarm:每步前查告警,命中即 FAILED(剩余步不执行);
13
+ * - 台账:写咽喉已自动落 intervention_events(hypothesis 前缀 [pexp:<id>] 建立关联),
14
+ * 计划结束时按台账汇总 verdict 分布进计划状态。
15
+ * 副作用全部经注入(测试可替换),默认实现走真实控制器/数采/告警仓储。
16
+ */
17
+ import { createHash } from 'node:crypto'
18
+ import { AppError } from '../../../utils/errors'
19
+ import { getDcwLineRepo } from '../dcw/dcw-line.repo'
20
+ import { getDcwController } from '../dcw/dcw-controller'
21
+ import { getRecipeRollBackManager } from '../dcw/recipe-rollback-manager'
22
+ import { getDaqController } from '../daq/daq-controller'
23
+ import { getAmlRuntime } from '../aml/runtime'
24
+ import { getExperimentPlan, updateExperimentStatus, type ExperimentPlanRow } from './experiment'
25
+ import { assessIdentifiability, dominantPeriod } from '../aml/identifiability'
26
+ import { attachAssessment, listInterventions, verdictCodeOf, verdictDetailOf } from '../aml/intervention-ledger'
27
+ import { backfillInterventionEvidence } from '../aml/ontology-learning'
28
+ import { assertPlanNodesSafe } from './plan-safety'
29
+
30
+ export interface ExperimentPlanBody {
31
+ version: 1
32
+ lineId: string
33
+ simSceneId: string | null
34
+ specId: string | null
35
+ levels: Record<string, number[]>
36
+ repeats: number
37
+ settleMs: number
38
+ observeMs: number
39
+ randomizedOrder: boolean
40
+ abortOnAlarm: boolean
41
+ design: string
42
+ tier?: 'sim_auto' | 'real_hitl'
43
+ /** 主控制量 → 观测目标节点(执行时读回);缺省取 spec 或首个控制量,无目标则跳过判读 */
44
+ targets?: Record<string, string>
45
+ /** 创建时核算的成本(人读 + 机读) */
46
+ cost?: ExperimentCost
47
+ /** 真实线批准凭据(approveExperimentPlan 写入) */
48
+ approvalId?: string
49
+ approvedBy?: string
50
+ approvedAt?: string
51
+ /** 人工取消凭据(运行中每步前被感知) */
52
+ cancelledBy?: string
53
+ cancelledAt?: string
54
+ note?: string
55
+ }
56
+
57
+ export interface ExperimentCost {
58
+ /** 各控制量中最大的水平数(展示用) */
59
+ levelsPerControl: number
60
+ /** 全部控制量水平数之和(步数基数) */
61
+ levelsTotal: number
62
+ controls: number
63
+ repeats: number
64
+ steps: number
65
+ perStepMs: number
66
+ totalDurationMs: number
67
+ /** 建议的单步响应窗(ms):已知主导周期时为 3×周期,否则 = settleMs */
68
+ suggestedWindowMs: number | null
69
+ dominantPeriodMs: number | null
70
+ summary: string
71
+ }
72
+
73
+ export interface ExperimentStep {
74
+ index: number
75
+ controlId: string
76
+ level: number
77
+ repeat: number
78
+ }
79
+
80
+ /** 真/仿真产线分档(不 throw:调用方按 tier 决定是否挂 HITL) */
81
+ export function resolveExperimentTier(lineId: string): { lineId: string, lineName: string, simulated: boolean, tier: 'sim_auto' | 'real_hitl', simSceneId?: string } {
82
+ const line = getDcwLineRepo().byId(lineId)
83
+ if (!line) throw new AppError(404, 'LINE_NOT_FOUND', `产线 ${lineId} 不存在`)
84
+ const simulated = line.simulated === true
85
+ return { lineId: line.id, lineName: line.name, simulated, tier: simulated ? 'sim_auto' : 'real_hitl', simSceneId: line.simSceneId }
86
+ }
87
+
88
+ /** 真实线下 60s 节点最小间隔(与 write() 的在线写联锁同口径) */
89
+ const REAL_MIN_STEP_MS = 60_000
90
+
91
+ /**
92
+ * 成本核算(创建时就算给用户看):步数 × 每步驻留。真实线每步至少 60s(写间隔联锁),
93
+ * 仿真线不受此限。已知主导周期时,建议窗 = 3×周期,单步驻留取 max(settle, 建议窗, 60s)。
94
+ */
95
+ export function estimateExperimentCost(plan: Pick<ExperimentPlanBody, 'levels' | 'repeats' | 'settleMs' | 'observeMs' | 'tier'>, opts: { dominantPeriodMs?: number | null } = {}): ExperimentCost {
96
+ const controls = Object.keys(plan.levels).length
97
+ const levelsPerControl = Math.max(0, ...Object.values(plan.levels).map(v => v.length))
98
+ // 步数 = 各控制量水平数之和 × 轮数(不是 max×控制量数 —— 控制量水平数可以不同)
99
+ const levelsTotal = Object.values(plan.levels).reduce((a, v) => a + v.length, 0)
100
+ const repeats = plan.repeats
101
+ const steps = levelsTotal * repeats
102
+ const period = opts.dominantPeriodMs ?? null
103
+ const suggestedWindowMs = period != null && period > 0 ? Math.round(3 * period) : null
104
+ const minStep = plan.tier === 'real_hitl' ? REAL_MIN_STEP_MS : 0
105
+ const holdMs = Math.max(plan.settleMs, suggestedWindowMs ?? 0, minStep)
106
+ const perStepMs = holdMs + plan.observeMs
107
+ const totalDurationMs = steps * perStepMs
108
+ const summary = `${controls} 个控制量共 ${levelsTotal} 个水平 × ${repeats} 轮 = ${steps} 步;每步 ${Math.round(perStepMs / 1000)}s(驻留 ${Math.round(holdMs / 1000)}s${
109
+ suggestedWindowMs != null ? `,含 3×主导周期 ${(suggestedWindowMs / 1000).toFixed(1)}s` : ''
110
+ }${minStep ? ',真实线 60s 写间隔下限' : ''} + 观测 ${Math.round(plan.observeMs / 1000)}s);预计总时长 ≈ ${(totalDurationMs / 3600_000).toFixed(2)} 小时`
111
+ return { levelsPerControl, levelsTotal, controls, repeats, steps, perStepMs, totalDurationMs, suggestedWindowMs, dominantPeriodMs: period, summary }
112
+ }
113
+
114
+ function seededShuffle<T>(items: T[], seed: number): T[] {
115
+ let a = seed >>> 0
116
+ const rnd = () => {
117
+ a |= 0
118
+ a = (a + 0x6D2B79F5) | 0
119
+ let t = Math.imul(a ^ (a >>> 15), 1 | a)
120
+ t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
121
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296
122
+ }
123
+ const out = [...items]
124
+ for (let i = out.length - 1; i > 0; i--) {
125
+ const j = Math.floor(rnd() * (i + 1))
126
+ const tmp = out[i]!
127
+ out[i] = out[j]!
128
+ out[j] = tmp
129
+ }
130
+ return out
131
+ }
132
+
133
+ /**
134
+ * 生成执行步序:按 repeats × (control,level) 展开,randomizedOrder 时用计划 id 派生种子洗牌
135
+ * (同一计划可复现;跨控制量也打散,避免"先把一个 MV 走完再走另一个"带来的时间混杂)。
136
+ */
137
+ export function buildExperimentSteps(plan: ExperimentPlanBody, planId: string): ExperimentStep[] {
138
+ const base: Array<{ controlId: string, level: number, repeat: number }> = []
139
+ for (let r = 0; r < plan.repeats; r++) {
140
+ for (const [controlId, levels] of Object.entries(plan.levels)) {
141
+ for (const level of levels) base.push({ controlId, level, repeat: r })
142
+ }
143
+ }
144
+ const seed = createHash('sha256').update(planId).digest().readUInt32BE(0)
145
+ const ordered = plan.randomizedOrder ? seededShuffle(base, seed) : base
146
+ return ordered.map((s, index) => ({ index, ...s }))
147
+ }
148
+
149
+ export function parsePlan(row: ExperimentPlanRow): ExperimentPlanBody {
150
+ return JSON.parse(row.planJson) as ExperimentPlanBody
151
+ }
152
+
153
+ /**
154
+ * 人工取消计划(运行中/待批准/已计划均可)。
155
+ * 执行器每步前读状态,感知到 cancelled 即停;已执行步的台账/证据保留。
156
+ */
157
+ export function cancelExperimentPlan(id: string, actor: string): ExperimentPlanRow {
158
+ const row = getExperimentPlan(id)
159
+ if (!row) throw new AppError(404, 'EXPERIMENT_PLAN_NOT_FOUND', `试验计划 ${id} 不存在`)
160
+ if (row.status === 'done' || row.status === 'failed' || row.status === 'cancelled') {
161
+ throw new AppError(409, 'EXPERIMENT_STATUS_INVALID', `计划 ${id} 已是终态 ${row.status},无需取消`)
162
+ }
163
+ const plan = parsePlan(row)
164
+ const next: ExperimentPlanBody = { ...plan, cancelledBy: actor, cancelledAt: new Date().toISOString() }
165
+ getAmlRuntime().db.prepare('UPDATE process_model_experiments SET plan_json = ?, status = \'cancelled\', updated_at = ? WHERE id = ?')
166
+ .run(JSON.stringify(next), new Date().toISOString(), id)
167
+ return getExperimentPlan(id)!
168
+ }
169
+
170
+ /** 真实线批准:awaiting_approval → planned(记录批准凭据;幂等) */
171
+ export function approveExperimentPlan(id: string, approvalId: string, approvedBy: string): ExperimentPlanRow {
172
+ const row = getExperimentPlan(id)
173
+ if (!row) throw new AppError(404, 'EXPERIMENT_PLAN_NOT_FOUND', `试验计划 ${id} 不存在`)
174
+ const plan = parsePlan(row)
175
+ if (row.status === 'planned' && plan.approvalId) return row
176
+ if (row.status !== 'awaiting_approval') {
177
+ throw new AppError(409, 'EXPERIMENT_STATUS_INVALID', `计划 ${id} 当前状态 ${row.status},只有 awaiting_approval 可批准`)
178
+ }
179
+ const next: ExperimentPlanBody = { ...plan, approvalId, approvedBy, approvedAt: new Date().toISOString() }
180
+ const db = getAmlRuntime().db
181
+ db.prepare('UPDATE process_model_experiments SET plan_json = ?, status = \'planned\', updated_at = ? WHERE id = ?')
182
+ .run(JSON.stringify(next), new Date().toISOString(), id)
183
+ return getExperimentPlan(id)!
184
+ }
185
+
186
+ // ---------- 执行 ----------
187
+
188
+ export interface ExperimentRunnerDeps {
189
+ /** 写控制(默认走 DcwController.write 咽喉;测试注入) */
190
+ write?: (controlId: string, level: number, meta: { hypothesis: string, planId: string, stepIndex: number }) => Promise<{ ok: boolean, message?: string, recordId?: string }>
191
+ /** 关闭单步调控记录(默认 judge=rollback 关闭不执行回退;测试注入) */
192
+ closeRecord?: (recordId: string, reason: string) => void
193
+ /** 读目标窗均值(默认 daq samples;测试注入) */
194
+ readTargetMean?: (targetNodeId: string, fromMs: number, toMs: number) => Promise<number | null>
195
+ /** 读目标窗序列(默认 daq samples;判定用;缺省跳过引擎判读) */
196
+ readTargetSeries?: (targetNodeId: string, fromMs: number, toMs: number) => Promise<number[]>
197
+ /** 告警检查(默认查 audit_log 最近一条 level=error 的 alarm 行;测试注入) */
198
+ alarmActive?: (lineId: string, sinceMs: number) => Promise<boolean>
199
+ sleep?: (ms: number) => Promise<void>
200
+ /** 时钟(测试可推进) */
201
+ now?: () => number
202
+ }
203
+
204
+ export interface ExperimentRunResult {
205
+ planId: string
206
+ status: 'done' | 'failed' | 'cancelled'
207
+ executedSteps: number
208
+ totalSteps: number
209
+ failedReason?: string
210
+ verdicts: Record<string, number>
211
+ startedAt: string
212
+ finishedAt: string
213
+ }
214
+
215
+ function defaultWrite(): NonNullable<ExperimentRunnerDeps['write']> {
216
+ return async (controlId, level, meta) => {
217
+ try {
218
+ const outcome = await getDcwController().write(controlId, level, null, {
219
+ source: 'agent',
220
+ actor: `plan:${meta.planId}`,
221
+ actorName: `试验计划 ${meta.planId}`,
222
+ hypothesis: meta.hypothesis,
223
+ })
224
+ return { ok: outcome.ok !== false, message: outcome.message, recordId: outcome.recordId }
225
+ }
226
+ catch (err) {
227
+ return { ok: false, message: err instanceof Error ? err.message : String(err) }
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 关闭单步的调控闭环记录(默认实现):不关闭会让下一步被"单一开放记录"守卫拒绝
234
+ * (beforeWrite: 正在优化试验中)。judge('rollback') 按设计只落判定、记录仍 open,
235
+ * 因此用 keep + takeover:关闭记录但**跳过好锚晋升**(试验步是探索,不是产能优化,
236
+ * 不应污染 keep 锚点链)。
237
+ */
238
+ function defaultCloseRecord(): NonNullable<ExperimentRunnerDeps['closeRecord']> {
239
+ return (recordId, reason) => {
240
+ try {
241
+ getRecipeRollBackManager().judge(recordId, 'keep', reason, 'system', 'experiment-plan', { takeover: true })
242
+ }
243
+ catch { /* 已关闭/记录不存在:不影响执行 */ }
244
+ }
245
+ }
246
+
247
+ const sleepReal = (ms: number) => new Promise<void>(r => setTimeout(r, ms))
248
+
249
+ export async function runExperimentPlan(id: string, deps: ExperimentRunnerDeps = {}): Promise<ExperimentRunResult> {
250
+ const row = getExperimentPlan(id)
251
+ if (!row) throw new AppError(404, 'EXPERIMENT_PLAN_NOT_FOUND', `试验计划 ${id} 不存在`)
252
+ const plan = parsePlan(row)
253
+ const tier = plan.tier ?? (resolveExperimentTier(plan.lineId).tier)
254
+ if (row.status === 'running') {
255
+ // 僵死 running 恢复:进程崩溃/重启会把状态永久停在 running(不可重跑也不可取消)。
256
+ // 超过预算上限 + 5min 无更新即判僵死 → 置 failed 并提示可重新创建计划。
257
+ const budgetRaw = JSON.parse(row.budgetJson || '{}') as { maxDurationMs?: number }
258
+ const staleMs = (budgetRaw.maxDurationMs ?? 4 * 3600_000) + 5 * 60_000
259
+ const age = Date.now() - Date.parse(row.updatedAt)
260
+ if (Number.isFinite(age) && age > staleMs) {
261
+ updateExperimentStatus(id, 'failed')
262
+ throw new AppError(409, 'EXPERIMENT_RUN_STALE', `计划 ${id} 上一次执行僵死(超过 ${Math.round(staleMs / 60000)} min 无更新),已置 failed;请重新创建计划(旧计划的台账行仍可查)`)
263
+ }
264
+ throw new AppError(409, 'EXPERIMENT_ALREADY_RUNNING', `计划 ${id} 正在执行`)
265
+ }
266
+ if (row.status !== 'planned') {
267
+ throw new AppError(409, 'EXPERIMENT_STATUS_INVALID', `计划 ${id} 当前状态 ${row.status},只有 planned 可执行${tier === 'real_hitl' ? '(真实线须先 HITL 批准)' : ''}`)
268
+ }
269
+ // 真实线执行前复核批准凭据(防"建完直接跑"绕过 HITL)
270
+ if (tier === 'real_hitl' && !plan.approvalId) {
271
+ throw new AppError(409, 'EXPERIMENT_APPROVAL_REQUIRED', `计划 ${id} 为真实产线计划,缺少 HITL 批准凭据,拒绝执行`)
272
+ }
273
+ // 执行前复核(防御深度):批准到执行之间产线/节点可能变更(换线、停用、量程调整)。
274
+ // 只对真实线强校验;仿真线计划允许过程模型 MV 逻辑名(不落设备,写入时由 write() 兜底)。
275
+ if (tier === 'real_hitl') assertPlanNodesSafe(plan)
276
+ const budget = JSON.parse(row.budgetJson) as { maxRuns?: number, maxDurationMs?: number }
277
+ const steps = buildExperimentSteps(plan, id)
278
+ if (budget.maxRuns && steps.length > budget.maxRuns) {
279
+ updateExperimentStatus(id, 'failed')
280
+ return {
281
+ planId: id, status: 'failed', executedSteps: 0, totalSteps: steps.length,
282
+ failedReason: `步数 ${steps.length} 超预算 maxRuns=${budget.maxRuns}(创建即拒绝执行)`,
283
+ verdicts: {}, startedAt: new Date().toISOString(), finishedAt: new Date().toISOString(),
284
+ }
285
+ }
286
+
287
+ const write = deps.write ?? defaultWrite()
288
+ const closeRecord = deps.closeRecord ?? defaultCloseRecord()
289
+ const readTarget = deps.readTargetMean ?? (async (nodeId, fromMs, toMs) => {
290
+ try {
291
+ const pts = await getDaqController().samples(nodeId, { fromMs, toMs, bucketMs: 1000, limit: 600 }) as Array<{ value?: number, avg?: number }>
292
+ const vals = pts.map(p => Number(p.value ?? p.avg)).filter(Number.isFinite)
293
+ return vals.length ? vals.reduce((a, b) => a + b, 0) / vals.length : null
294
+ }
295
+ catch {
296
+ return null
297
+ }
298
+ })
299
+ const alarmActive = deps.alarmActive ?? (async (lineId, sinceMs) => {
300
+ try {
301
+ const hit = getAmlRuntime().db.prepare(`SELECT id FROM audit_log WHERE line_id = ? AND level = 'error' AND created_at >= ? LIMIT 1`)
302
+ .get(lineId, new Date(sinceMs).toISOString()) as { id?: string } | undefined
303
+ return !!hit
304
+ }
305
+ catch {
306
+ return false
307
+ }
308
+ })
309
+ const readSeries = deps.readTargetSeries ?? (async (nodeId, fromMs, toMs) => {
310
+ try {
311
+ const pts = await getDaqController().samples(nodeId, { fromMs, toMs, bucketMs: 1000, limit: Math.max(60, Math.ceil((toMs - fromMs) / 1000) + 10) }) as Array<{ value?: number, avg?: number }>
312
+ return pts.map(p => Number(p.value ?? p.avg)).filter(Number.isFinite)
313
+ }
314
+ catch {
315
+ return []
316
+ }
317
+ })
318
+ const sleep = deps.sleep ?? sleepReal
319
+ const now = deps.now ?? (() => Date.now())
320
+
321
+ updateExperimentStatus(id, 'running')
322
+ const startedAt = new Date(now()).toISOString()
323
+ const started = now()
324
+ // 计划级主导周期估计:用一段长历史(≥30min 与 6×settle 的较大者)估一次,
325
+ // 逐步判定统一使用 —— 短窗局部自相关会把局部纹波当周期(事故形态)。
326
+ let expectedPeriodMs: number | undefined
327
+ const firstTarget = plan.targets ? Object.values(plan.targets)[0] : undefined
328
+ if (firstTarget) {
329
+ try {
330
+ const longMs = Math.max(30 * 60_000, plan.settleMs * 6)
331
+ const longSeries = await readSeries(firstTarget, now() - longMs, now())
332
+ if (longSeries.length >= 64) {
333
+ const p = dominantPeriod(longSeries)
334
+ // 长历史必须覆盖 ≥3 个周期才采信该估计
335
+ if (p.lagBeats != null && longSeries.length / p.lagBeats >= 3) expectedPeriodMs = p.lagBeats * 1000
336
+ }
337
+ }
338
+ catch { /* 估计失败退回逐步检测 */ }
339
+ }
340
+ let executed = 0
341
+ let failedReason: string | undefined
342
+
343
+ // 真实线每步驻留不得低于写联锁的 60s 节点间隔(否则第 2 步必被 429 打回,白跑)
344
+ const holdMs = tier === 'real_hitl' ? Math.max(plan.settleMs, REAL_MIN_STEP_MS) : plan.settleMs
345
+ for (const step of steps) {
346
+ // 取消:每步前读一次计划状态(REST cancel 是异步人工操作,必须能被及时感知)
347
+ const live = getExperimentPlan(id)
348
+ if (live?.status === 'cancelled') {
349
+ failedReason = `计划被人工取消(已执行 ${executed}/${steps.length} 步)`
350
+ break
351
+ }
352
+ // 预算:总时长超限即停(不静默续跑)
353
+ if (budget.maxDurationMs && now() - started > budget.maxDurationMs) {
354
+ failedReason = `超出预算 maxDurationMs=${budget.maxDurationMs}ms(已执行 ${executed}/${steps.length} 步)`
355
+ break
356
+ }
357
+ if (plan.abortOnAlarm && await alarmActive(plan.lineId, started)) {
358
+ failedReason = `告警中止(abortOnAlarm):第 ${executed + 1} 步前检测到产线告警,剩余 ${steps.length - executed} 步未执行`
359
+ break
360
+ }
361
+ const hypothesis = `[pexp:${id}] 试验步 ${step.index + 1}/${steps.length}:${step.controlId}=${step.level}(第 ${step.repeat + 1} 轮)`
362
+ const res = await write(step.controlId, step.level, { hypothesis, planId: id, stepIndex: step.index })
363
+ if (!res.ok) {
364
+ failedReason = `第 ${step.index + 1} 步写入被拒:${res.message ?? '未知原因'}`
365
+ break
366
+ }
367
+ executed++
368
+ const writeAt = now()
369
+ await sleep(holdMs)
370
+ // 观测窗 + 引擎判读:有目标映射时,写前窗/写后窗各取一次序列交给可辨识性引擎,
371
+ // 判定回填本步干预台账(与 optimization_explore 同口径);无目标则只驻留。
372
+ const target = plan.targets?.[step.controlId]
373
+ if (target) {
374
+ const pre = await readSeries(target, writeAt - holdMs, writeAt)
375
+ await sleep(plan.observeMs)
376
+ const post = await readSeries(target, writeAt, now())
377
+ await readTarget(target, writeAt, now())
378
+ if (pre.length >= 8 && post.length >= 8) {
379
+ try {
380
+ const v = assessIdentifiability({ pre, post, beatMs: 1000, ...(expectedPeriodMs != null ? { expectedPeriodMs } : {}) })
381
+ // 写咽喉落行时若无 targetNodeId 会标 unassessed(尚无判定)—— 两者都视为"待判定"
382
+ const row = listInterventions({ nodeId: step.controlId, limit: 50 })
383
+ .find(r => r.hypothesis.startsWith(`[pexp:${id}]`) && (r.verdict === 'pending' || r.verdict === 'unassessed'))
384
+ if (row) {
385
+ attachAssessment(row.id, {
386
+ verdict: verdictCodeOf(v),
387
+ effect: v.effect,
388
+ ciLow: v.ciLow,
389
+ ciHigh: v.ciHigh,
390
+ mde: v.mde,
391
+ targetNodeId: target,
392
+ detail: verdictDetailOf(v),
393
+ })
394
+ // P6:判定回灌本体证据(有已发布本体才落;幂等)
395
+ const updated = listInterventions({ nodeId: step.controlId, limit: 1 })[0]
396
+ if (updated) {
397
+ try {
398
+ backfillInterventionEvidence(updated)
399
+ }
400
+ catch { /* 证据登记失败不影响执行 */ }
401
+ }
402
+ }
403
+ }
404
+ catch { /* 判读失败按未判定处理 */ }
405
+ }
406
+ }
407
+ else {
408
+ await sleep(plan.observeMs)
409
+ }
410
+ // 关闭本步调控记录(否则下一步会被"单一开放记录"守卫拒绝)
411
+ if (res.recordId) closeRecord(res.recordId, `试验计划 ${id} 第 ${step.index + 1} 步执行完成,由计划执行器关闭(关闭记录不晋升锚点)`)
412
+ }
413
+
414
+ // 台账汇总:按 hypothesis 前缀 [pexp:<id>] 找本次计划的干预行
415
+ const verdicts: Record<string, number> = {}
416
+ try {
417
+ const involved = new Set(Object.keys(plan.levels))
418
+ const rows = listInterventions({ lineId: plan.lineId, limit: 200 })
419
+ .filter(r => involved.has(r.nodeId) && r.hypothesis.startsWith(`[pexp:${id}]`))
420
+ for (const r of rows) verdicts[r.verdict] = (verdicts[r.verdict] ?? 0) + 1
421
+ }
422
+ catch { /* 台账不可读不影响执行结果 */ }
423
+
424
+ const cancelled = failedReason?.includes('人工取消') ?? false
425
+ const status: ExperimentRunResult['status'] = cancelled ? 'cancelled' : (failedReason ? 'failed' : 'done')
426
+ updateExperimentStatus(id, status)
427
+ return {
428
+ planId: id,
429
+ status,
430
+ executedSteps: executed,
431
+ totalSteps: steps.length,
432
+ ...(failedReason ? { failedReason } : {}),
433
+ verdicts,
434
+ startedAt,
435
+ finishedAt: new Date(now()).toISOString(),
436
+ }
437
+ }
@@ -1,13 +1,17 @@
1
1
  /**
2
- * 模拟参数试验计划(G2.11 / C9 / A9):
3
- * - 只有 simulated=true 的产线可发起;真实线 → SIM_ONLY_VIOLATION;
4
- * - 计划只落 process_model_experiments;动作明细仍走既有 optimization_explorations/DCW 记录
2
+ * 参数试验计划(G2.11 / C9 / A9;P4 治理分档 2026-11-02):
3
+ * - simulated=true → tier=sim_auto,建计划即可执行(既有行为不变);
4
+ * - 真实线 → tier=real_hitl,创建后落 awaiting_approval,须 approveExperimentPlan
5
+ * 单卡 HITL 批准(卡上带成本核算)后才能由 runExperimentPlan 执行;
6
+ * - 计划只落 process_model_experiments;动作明细仍走既有 DCW 写咽喉/台账
5
7
  * (不制造第二套写设备账本)。
6
8
  */
7
9
  import type { DatabaseSync } from 'node:sqlite'
8
10
  import { AppError } from '../../../utils/errors'
9
11
  import { getAmlRuntime } from '../aml/runtime'
10
12
  import { getDcwLineRepo } from '../dcw/dcw-line.repo'
13
+ import { estimateExperimentCost, resolveExperimentTier, type ExperimentPlanBody, type ExperimentCost } from './experiment-runner'
14
+ import { assertPlanNodesSafe } from './plan-safety'
11
15
 
12
16
  export interface ExperimentPlanInput {
13
17
  lineId: string
@@ -21,6 +25,10 @@ export interface ExperimentPlanInput {
21
25
  abortOnAlarm?: boolean
22
26
  budget?: { maxRuns?: number, maxDurationMs?: number }
23
27
  createdBy?: string
28
+ /** MV → 观测目标节点(执行时读回;缺省不读) */
29
+ targets?: Record<string, string>
30
+ /** 已知主导扰动周期(ms;来自可辨识性引擎):成本核算按 3×周期给建议窗 */
31
+ dominantPeriodMs?: number
24
32
  }
25
33
 
26
34
  export interface ExperimentPlanRow {
@@ -44,7 +52,7 @@ export function assertSimulatedLine(lineId: string): { id: string, simSceneId?:
44
52
  }
45
53
 
46
54
  export function createExperimentPlan(input: ExperimentPlanInput): ExperimentPlanRow {
47
- const line = assertSimulatedLine(input.lineId)
55
+ const tierInfo = resolveExperimentTier(input.lineId)
48
56
  if (!Object.keys(input.levels).length) throw new AppError(422, 'EXPERIMENT_PLAN_INVALID', '至少需要 1 个 MV 的水平序列')
49
57
  for (const [id, levels] of Object.entries(input.levels)) {
50
58
  if (!Array.isArray(levels) || levels.length < 2) throw new AppError(422, 'EXPERIMENT_PLAN_INVALID', `MV ${id} 至少需要 2 个水平(阶跃/多水平)`)
@@ -54,13 +62,23 @@ export function createExperimentPlan(input: ExperimentPlanInput): ExperimentPlan
54
62
  const repeats = Math.max(1, Math.min(input.repeats ?? 1, 20))
55
63
  const settleMs = Math.max(1000, input.settleMs ?? 60_000)
56
64
  const observeMs = Math.max(1000, input.observeMs ?? 120_000)
65
+ // 上线前加固:真实线计划在**创建时**即校验节点归属(须属本线/启用/量程内,targets 须同线 DAQ)。
66
+ // 仿真线计划允许用过程模型 MV 逻辑名(不落设备),创建不校验;执行时一律强校验(见 runner)。
67
+ if (tierInfo.tier === 'real_hitl') {
68
+ assertPlanNodesSafe({ lineId: input.lineId, levels: input.levels, targets: input.targets })
69
+ }
57
70
  const db = getAmlRuntime().db
58
71
  const id = `pexp-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`
59
72
  const now = new Date().toISOString()
60
- const plan = {
73
+ // P4 成本前置:创建时就核算(真实线含 60s 写间隔下限;已知主导周期时按 3×周期建议窗)
74
+ const cost: ExperimentCost = estimateExperimentCost(
75
+ { levels: input.levels, repeats, settleMs, observeMs, tier: tierInfo.tier },
76
+ { dominantPeriodMs: input.dominantPeriodMs ?? null },
77
+ )
78
+ const plan: ExperimentPlanBody = {
61
79
  version: 1,
62
80
  lineId: input.lineId,
63
- simSceneId: line.simSceneId ?? null,
81
+ simSceneId: tierInfo.simSceneId ?? null,
64
82
  specId: input.specId ?? null,
65
83
  levels: input.levels,
66
84
  repeats,
@@ -69,12 +87,15 @@ export function createExperimentPlan(input: ExperimentPlanInput): ExperimentPlan
69
87
  randomizedOrder: input.randomizedOrder !== false,
70
88
  abortOnAlarm: input.abortOnAlarm !== false,
71
89
  design: 'stepped_multi_level',
72
- note: '动作明细写入既有 optimization_explorations/DCW 账本;本台账只保存计划与状态',
90
+ tier: tierInfo.tier,
91
+ ...(input.targets ? { targets: input.targets } : {}),
92
+ cost,
93
+ note: '动作明细经 DCW 写咽喉落 intervention_events([pexp:<id>] 前缀关联);本台账只保存计划与状态',
73
94
  }
74
- const budget = { maxRuns: input.budget?.maxRuns ?? 20, maxDurationMs: input.budget?.maxDurationMs ?? 4 * 3600_000 }
95
+ const budget = { maxRuns: input.budget?.maxRuns ?? Math.max(20, cost.steps), maxDurationMs: input.budget?.maxDurationMs ?? 4 * 3600_000 }
75
96
  db.prepare(`INSERT INTO process_model_experiments (id, line_id, plan_json, status, budget_json, created_by, created_at, updated_at)
76
- VALUES (?, ?, ?, 'planned', ?, ?, ?, ?)`)
77
- .run(id, input.lineId, JSON.stringify(plan), JSON.stringify(budget), input.createdBy ?? '', now, now)
97
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
98
+ .run(id, input.lineId, JSON.stringify(plan), tierInfo.tier === 'real_hitl' ? 'awaiting_approval' : 'planned', JSON.stringify(budget), input.createdBy ?? '', now, now)
78
99
  return this_get(db, id)!
79
100
  }
80
101
 
@@ -0,0 +1,69 @@
1
+ /**
2
+ * 试验计划安全校验(2026-11-02 上线前加固):
3
+ * 计划一旦被 HITL 批准,执行器会以平台身份直接写节点(单卡批准 = 全计划授权)。
4
+ * 因此**创建时与执行前都必须复核节点归属**,防止:
5
+ * - 跨线写:计划 lineId=A,levels 却点名 B 线的节点(越权写别的产线);
6
+ * - 类型错配:targets 写成数控节点(读不到真值)或控制量其实是数采节点;
7
+ * - 量程外水平:创建时就拒绝,避免批准后逐步被 write() 打回、白花产线时间。
8
+ * 纯校验函数,直接读控制器/节点仓(无副作用,不写库)。
9
+ */
10
+ import { AppError } from '../../../utils/errors'
11
+ import { getDcwController } from '../dcw/dcw-controller'
12
+ import { getDaqNodeRepo } from '../daq/daq-node.repo'
13
+ import type { ExperimentPlanBody } from './experiment-runner'
14
+
15
+ export interface PlanNodeIssue {
16
+ kind: 'control' | 'target' | 'level'
17
+ nodeId: string
18
+ message: string
19
+ }
20
+
21
+ /**
22
+ * 校验计划节点集合与量程。返回问题列表(空 = 通过);
23
+ * 调用方决定抛错(创建/执行前)还是仅告警。
24
+ */
25
+ export function validatePlanNodes(plan: Pick<ExperimentPlanBody, 'lineId' | 'levels' | 'targets'>): PlanNodeIssue[] {
26
+ const issues: PlanNodeIssue[] = []
27
+ const controller = getDcwController()
28
+ for (const [controlId, levels] of Object.entries(plan.levels)) {
29
+ const node = controller.byId(controlId)
30
+ if (!node) {
31
+ issues.push({ kind: 'control', nodeId: controlId, message: `控制节点 ${controlId} 不存在(须为 DCW 数控节点)` })
32
+ continue
33
+ }
34
+ if (node.lineId && node.lineId !== plan.lineId) {
35
+ issues.push({ kind: 'control', nodeId: controlId, message: `控制节点 ${controlId} 属于产线 ${node.lineId},与计划产线 ${plan.lineId} 不一致(禁止跨线试验)` })
36
+ }
37
+ if (!node.enabled) {
38
+ issues.push({ kind: 'control', nodeId: controlId, message: `控制节点 ${controlId} 已停用(控制已暂停),不能用于试验` })
39
+ }
40
+ for (const level of levels) {
41
+ if (!Number.isFinite(level)) continue
42
+ if (level < node.min || level > node.max) {
43
+ issues.push({ kind: 'level', nodeId: controlId, message: `水平 ${level} 超出节点安全量程 ${node.min}~${node.max}${node.unit ?? ''}` })
44
+ }
45
+ }
46
+ }
47
+ for (const [controlId, targetId] of Object.entries(plan.targets ?? {})) {
48
+ if (!plan.levels[controlId]) {
49
+ issues.push({ kind: 'target', nodeId: targetId, message: `观测目标绑定到了未声明的控制量 ${controlId}` })
50
+ continue
51
+ }
52
+ const daq = getDaqNodeRepo().byId(targetId)
53
+ if (!daq) {
54
+ issues.push({ kind: 'target', nodeId: targetId, message: `观测目标 ${targetId} 不是数采节点(判读需要 DAQ 序列)` })
55
+ continue
56
+ }
57
+ if (daq.lineId && daq.lineId !== plan.lineId) {
58
+ issues.push({ kind: 'target', nodeId: targetId, message: `观测目标 ${targetId} 属于产线 ${daq.lineId},与计划产线 ${plan.lineId} 不一致` })
59
+ }
60
+ }
61
+ return issues
62
+ }
63
+
64
+ /** 创建/执行前强校验:有问题即 422(消息合并,便于一次改全) */
65
+ export function assertPlanNodesSafe(plan: Pick<ExperimentPlanBody, 'lineId' | 'levels' | 'targets'>): void {
66
+ const issues = validatePlanNodes(plan)
67
+ if (issues.length === 0) return
68
+ throw new AppError(422, 'EXPERIMENT_PLAN_NODE_INVALID', `试验计划节点校验失败:${issues.map(i => i.message).join(';')}`)
69
+ }