@hotmeshio/long-tail 0.27.0 → 0.28.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 (339) hide show
  1. package/README.md +9 -2
  2. package/build/api/settings.d.ts +4 -1
  3. package/build/api/settings.js +7 -1
  4. package/build/index.js +9 -4
  5. package/build/lib/db/config-lock.d.ts +10 -0
  6. package/build/lib/db/config-lock.js +28 -0
  7. package/build/lib/db/schemas/041_machine_lines.sql +26 -0
  8. package/build/lib/events/browser-view.js +8 -2
  9. package/build/lib/events/publish.d.ts +33 -0
  10. package/build/lib/events/publish.js +52 -1
  11. package/build/lib/machines/line.d.ts +4 -1
  12. package/build/lib/machines/line.js +18 -1
  13. package/build/lib/machines/protocol/codec.d.ts +8 -0
  14. package/build/lib/machines/protocol/codec.js +9 -0
  15. package/build/lib/machines/protocol/constants.d.ts +1 -1
  16. package/build/lib/machines/protocol/constants.js +1 -1
  17. package/build/lib/machines/protocol/contract.js +2 -2
  18. package/build/lib/machines/site/mosquitto-conf.d.ts +5 -4
  19. package/build/lib/machines/site/mosquitto-conf.js +31 -16
  20. package/build/lib/machines/site/site-conf.d.ts +9 -2
  21. package/build/lib/machines/site/site-conf.js +27 -8
  22. package/build/lib/machines/transport/callback-feed.d.ts +1 -0
  23. package/build/lib/machines/transport/callback-feed.js +4 -1
  24. package/build/lib/machines/transport/memory.d.ts +2 -0
  25. package/build/lib/machines/transport/memory.js +6 -0
  26. package/build/lib/machines/transport/mqtt-bus.d.ts +2 -0
  27. package/build/lib/machines/transport/mqtt-bus.js +4 -0
  28. package/build/lib/machines/transport/nats-bus.d.ts +1 -0
  29. package/build/lib/machines/transport/nats-bus.js +3 -0
  30. package/build/lib/machines/transport/nats-feed.d.ts +1 -0
  31. package/build/lib/machines/transport/nats-feed.js +4 -1
  32. package/build/lib/machines/transport/pubsub-feed.d.ts +1 -0
  33. package/build/lib/machines/transport/pubsub-feed.js +4 -1
  34. package/build/lib/machines/transport/stream-bus.d.ts +2 -0
  35. package/build/lib/machines/transport/stream-bus.js +5 -1
  36. package/build/modules/machines.d.ts +8 -0
  37. package/build/modules/machines.js +16 -0
  38. package/build/routes/index.js +2 -0
  39. package/build/routes/machines.d.ts +2 -0
  40. package/build/routes/machines.js +220 -0
  41. package/build/services/machines/commands.d.ts +5 -5
  42. package/build/services/machines/commands.js +3 -2
  43. package/build/services/machines/config.d.ts +2 -1
  44. package/build/services/machines/config.js +1 -1
  45. package/build/services/machines/contracts.d.ts +10 -0
  46. package/build/services/machines/gateway/actions.d.ts +1 -0
  47. package/build/services/machines/gateway/admission.d.ts +15 -3
  48. package/build/services/machines/gateway/admission.js +29 -14
  49. package/build/services/machines/gateway/dispatcher.d.ts +3 -0
  50. package/build/services/machines/gateway/dispatcher.js +12 -4
  51. package/build/services/machines/gateway/executor.d.ts +11 -2
  52. package/build/services/machines/gateway/executor.js +68 -29
  53. package/build/services/machines/gateway/gateway.d.ts +16 -1
  54. package/build/services/machines/gateway/gateway.js +55 -23
  55. package/build/services/machines/gateway/index.d.ts +3 -0
  56. package/build/services/machines/gateway/index.js +3 -0
  57. package/build/services/machines/gateway/inspect.d.ts +17 -0
  58. package/build/services/machines/gateway/inspect.js +68 -0
  59. package/build/services/machines/gateway/log.d.ts +8 -0
  60. package/build/services/machines/gateway/log.js +18 -0
  61. package/build/services/machines/gateway/pacing.js +1 -0
  62. package/build/services/machines/gateway/plan-escalation.js +8 -3
  63. package/build/services/machines/gateway/plan-machine.js +16 -6
  64. package/build/services/machines/gateway/project.d.ts +9 -0
  65. package/build/services/machines/gateway/project.js +55 -0
  66. package/build/services/machines/gateway/receipts.d.ts +3 -0
  67. package/build/services/machines/gateway/receipts.js +3 -1
  68. package/build/services/machines/gateway/reconcile.js +3 -3
  69. package/build/services/machines/gateway/registration.js +1 -1
  70. package/build/services/machines/gateway/reply-waiter.d.ts +6 -3
  71. package/build/services/machines/gateway/reply-waiter.js +37 -16
  72. package/build/services/machines/gateway/state.d.ts +29 -3
  73. package/build/services/machines/gateway/state.js +61 -7
  74. package/build/services/machines/gateway/wire.d.ts +58 -0
  75. package/build/services/machines/gateway/wire.js +171 -0
  76. package/build/services/machines/index.d.ts +3 -0
  77. package/build/services/machines/index.js +2 -0
  78. package/build/services/machines/line-index.d.ts +16 -0
  79. package/build/services/machines/line-index.js +39 -0
  80. package/build/services/machines/registry-sql.d.ts +31 -0
  81. package/build/services/machines/registry-sql.js +110 -0
  82. package/build/services/machines/registry-sync.d.ts +31 -0
  83. package/build/services/machines/registry-sync.js +81 -0
  84. package/build/services/machines/registry.d.ts +77 -0
  85. package/build/services/machines/registry.js +158 -0
  86. package/build/services/machines/rows.js +10 -1
  87. package/build/services/machines/surface.d.ts +45 -5
  88. package/build/services/machines/surface.js +95 -15
  89. package/build/start/apply-report.d.ts +1 -1
  90. package/build/start/apply-report.js +3 -25
  91. package/build/start/index.js +16 -4
  92. package/build/system/index.js +13 -0
  93. package/build/system/mcp-servers/admin/schemas.d.ts +22 -22
  94. package/build/system/mcp-servers/human-queue-schemas.d.ts +7 -7
  95. package/build/system/mcp-servers/machines-schemas.d.ts +35 -0
  96. package/build/system/mcp-servers/machines-schemas.js +35 -0
  97. package/build/system/mcp-servers/machines.d.ts +20 -0
  98. package/build/system/mcp-servers/machines.js +154 -0
  99. package/build/system/seed/tool-manifests-machines.d.ts +2 -0
  100. package/build/system/seed/tool-manifests-machines.js +88 -0
  101. package/build/tsconfig.tsbuildinfo +1 -1
  102. package/build/types/events.d.ts +6 -1
  103. package/build/types/index.d.ts +1 -0
  104. package/build/types/machines-view.d.ts +159 -0
  105. package/build/types/machines-view.js +7 -0
  106. package/build/types/machines.d.ts +4 -0
  107. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js → AdminDashboard-Bm7VG65H.js} +2 -2
  108. package/dashboard/dist/assets/{AdminDashboard-DlItqxFS.js.map → AdminDashboard-Bm7VG65H.js.map} +1 -1
  109. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js → AgentConfigPage-aJF7Sdbc.js} +6 -6
  110. package/dashboard/dist/assets/{AgentConfigPage-BUmT4a7n.js.map → AgentConfigPage-aJF7Sdbc.js.map} +1 -1
  111. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js → AgentDetailPage-GwwghhxT.js} +3 -3
  112. package/dashboard/dist/assets/{AgentDetailPage-Cww8rlBi.js.map → AgentDetailPage-GwwghhxT.js.map} +1 -1
  113. package/dashboard/dist/assets/AgentsPage-DVvCzZyg.js +2 -0
  114. package/dashboard/dist/assets/{AgentsPage-C9UuUKhr.js.map → AgentsPage-DVvCzZyg.js.map} +1 -1
  115. package/dashboard/dist/assets/AvailableEscalationsPage-Cxmcji_K.js +2 -0
  116. package/dashboard/dist/assets/{AvailableEscalationsPage-DrvfXz70.js.map → AvailableEscalationsPage-Cxmcji_K.js.map} +1 -1
  117. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js → BotPicker-CofRxk4L.js} +2 -2
  118. package/dashboard/dist/assets/{BotPicker-CDq9XRMp.js.map → BotPicker-CofRxk4L.js.map} +1 -1
  119. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js → BulkAssignModal-BARWuz4L.js} +2 -2
  120. package/dashboard/dist/assets/{BulkAssignModal-jsvqtrEA.js.map → BulkAssignModal-BARWuz4L.js.map} +1 -1
  121. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js → CapabilitiesPage-BJAWVNEx.js} +2 -2
  122. package/dashboard/dist/assets/{CapabilitiesPage-CSCrI6B1.js.map → CapabilitiesPage-BJAWVNEx.js.map} +1 -1
  123. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js → CollapsibleSection-CtgoaG75.js} +2 -2
  124. package/dashboard/dist/assets/{CollapsibleSection-uD9mn-CQ.js.map → CollapsibleSection-CtgoaG75.js.map} +1 -1
  125. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js → ConfirmDeleteModal-BYXXBWs6.js} +2 -2
  126. package/dashboard/dist/assets/{ConfirmDeleteModal-BRmx2hA4.js.map → ConfirmDeleteModal-BYXXBWs6.js.map} +1 -1
  127. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js → ConnectedAppsPage-D0JkzWa7.js} +2 -2
  128. package/dashboard/dist/assets/{ConnectedAppsPage-DlMzE5a-.js.map → ConnectedAppsPage-D0JkzWa7.js.map} +1 -1
  129. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js → CountdownTimer-BcFxdZYN.js} +2 -2
  130. package/dashboard/dist/assets/{CountdownTimer-sRuM4eM5.js.map → CountdownTimer-BcFxdZYN.js.map} +1 -1
  131. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js → CredentialsPage-DPSY20rV.js} +2 -2
  132. package/dashboard/dist/assets/{CredentialsPage-bLYydwqa.js.map → CredentialsPage-DPSY20rV.js.map} +1 -1
  133. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js → CronLabel-Dg_Oew_Y.js} +2 -2
  134. package/dashboard/dist/assets/{CronLabel-D_ATDL2N.js.map → CronLabel-Dg_Oew_Y.js.map} +1 -1
  135. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js → DropZone-Cl_Flb16.js} +2 -2
  136. package/dashboard/dist/assets/{DropZone-u1JGfR9G.js.map → DropZone-Cl_Flb16.js.map} +1 -1
  137. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js → ElapsedCell-Dm3G5fK2.js} +2 -2
  138. package/dashboard/dist/assets/{ElapsedCell-groSMfqB.js.map → ElapsedCell-Dm3G5fK2.js.map} +1 -1
  139. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js → EntityTimelinePanel-CrEEP04e.js} +2 -2
  140. package/dashboard/dist/assets/{EntityTimelinePanel-D-F3_A9m.js.map → EntityTimelinePanel-CrEEP04e.js.map} +1 -1
  141. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js → EscalationListSchemaPage-wOInXcjs.js} +3 -3
  142. package/dashboard/dist/assets/{EscalationListSchemaPage-Bad6Jrmr.js.map → EscalationListSchemaPage-wOInXcjs.js.map} +1 -1
  143. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js → EscalationSchemaPage-CrIj_g9d.js} +3 -3
  144. package/dashboard/dist/assets/{EscalationSchemaPage-BKi_npI9.js.map → EscalationSchemaPage-CrIj_g9d.js.map} +1 -1
  145. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js → EscalationTimeline-CeAsl5IT.js} +2 -2
  146. package/dashboard/dist/assets/{EscalationTimeline-DQUUm3b1.js.map → EscalationTimeline-CeAsl5IT.js.map} +1 -1
  147. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js → EscalationTitleSelect-D8qpCYiy.js} +2 -2
  148. package/dashboard/dist/assets/{EscalationTitleSelect-3mhXh77a.js.map → EscalationTitleSelect-D8qpCYiy.js.map} +1 -1
  149. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js → EscalationsOverview-CvaqVPsr.js} +2 -2
  150. package/dashboard/dist/assets/{EscalationsOverview-Qaov-uML.js.map → EscalationsOverview-CvaqVPsr.js.map} +1 -1
  151. package/dashboard/dist/assets/{EventTable-V4RF_n58.js → EventTable-Be0JuEl6.js} +2 -2
  152. package/dashboard/dist/assets/{EventTable-V4RF_n58.js.map → EventTable-Be0JuEl6.js.map} +1 -1
  153. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js +2 -0
  154. package/dashboard/dist/assets/FilterBar-BVyAjIgv.js.map +1 -0
  155. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js → GraphInvokePage-D_QigJeD.js} +2 -2
  156. package/dashboard/dist/assets/{GraphInvokePage-Djslhf96.js.map → GraphInvokePage-D_QigJeD.js.map} +1 -1
  157. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js → HomePage-C1haeuNy.js} +2 -2
  158. package/dashboard/dist/assets/{HomePage-EjcNxlKx.js.map → HomePage-C1haeuNy.js.map} +1 -1
  159. package/dashboard/dist/assets/LinePage-CWD5pv1g.js +5 -0
  160. package/dashboard/dist/assets/LinePage-CWD5pv1g.js.map +1 -0
  161. package/dashboard/dist/assets/LinesPage-NqChsKcO.js +3 -0
  162. package/dashboard/dist/assets/LinesPage-NqChsKcO.js.map +1 -0
  163. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js → ListToolbar-BZCNrTh6.js} +2 -2
  164. package/dashboard/dist/assets/{ListToolbar-RrEAePOX.js.map → ListToolbar-BZCNrTh6.js.map} +1 -1
  165. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js → McpOverview-yJTYnh1z.js} +2 -2
  166. package/dashboard/dist/assets/{McpOverview-8gqiL3Vj.js.map → McpOverview-yJTYnh1z.js.map} +1 -1
  167. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js → McpQueryDetailPage-ChuLpJ4u.js} +3 -3
  168. package/dashboard/dist/assets/{McpQueryDetailPage-COyn6Ak5.js.map → McpQueryDetailPage-ChuLpJ4u.js.map} +1 -1
  169. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js → McpQueryPage-9S-v9soF.js} +2 -2
  170. package/dashboard/dist/assets/{McpQueryPage-Dj6Qj72w.js.map → McpQueryPage-9S-v9soF.js.map} +1 -1
  171. package/dashboard/dist/assets/McpRunDetailPage-BhrcfxD5.js +2 -0
  172. package/dashboard/dist/assets/{McpRunDetailPage-80fQn9iX.js.map → McpRunDetailPage-BhrcfxD5.js.map} +1 -1
  173. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js → McpRunsPage-C5_i8_Zx.js} +2 -2
  174. package/dashboard/dist/assets/{McpRunsPage-DaSsI-EM.js.map → McpRunsPage-C5_i8_Zx.js.map} +1 -1
  175. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js → NamespacePill-OTZD2hzt.js} +2 -2
  176. package/dashboard/dist/assets/{NamespacePill-C5epAgq6.js.map → NamespacePill-OTZD2hzt.js.map} +1 -1
  177. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js → OperationsPage-C03CeU5P.js} +2 -2
  178. package/dashboard/dist/assets/{OperationsPage-BSu1o2gB.js.map → OperationsPage-C03CeU5P.js.map} +1 -1
  179. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js → OperatorDashboard-BzC134Jt.js} +2 -2
  180. package/dashboard/dist/assets/{OperatorDashboard-HFI4WGIV.js.map → OperatorDashboard-BzC134Jt.js.map} +1 -1
  181. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js → PageHeader-Hx8APPwE.js} +2 -2
  182. package/dashboard/dist/assets/{PageHeader-BSWIspNB.js.map → PageHeader-Hx8APPwE.js.map} +1 -1
  183. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js → PageHeaderWithStats-BEQYYBJv.js} +2 -2
  184. package/dashboard/dist/assets/{PageHeaderWithStats-DDjopQ-k.js.map → PageHeaderWithStats-BEQYYBJv.js.map} +1 -1
  185. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js → PersonaDetailPage-D0mY9L6j.js} +2 -2
  186. package/dashboard/dist/assets/{PersonaDetailPage-D0qlBuGi.js.map → PersonaDetailPage-D0mY9L6j.js.map} +1 -1
  187. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js → PersonasPage-FFlm5Eug.js} +2 -2
  188. package/dashboard/dist/assets/{PersonasPage-BJClu-5H.js.map → PersonasPage-FFlm5Eug.js.map} +1 -1
  189. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js → PortalPage-Cpc25uO-.js} +2 -2
  190. package/dashboard/dist/assets/{PortalPage-CucNZn_w.js.map → PortalPage-Cpc25uO-.js.map} +1 -1
  191. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js → ProcessDetailPage-Di2J7KwY.js} +2 -2
  192. package/dashboard/dist/assets/{ProcessDetailPage-B9wMw0RV.js.map → ProcessDetailPage-Di2J7KwY.js.map} +1 -1
  193. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js → ProcessesListPage-BEXwU3Z0.js} +2 -2
  194. package/dashboard/dist/assets/{ProcessesListPage-B6k4RpmR.js.map → ProcessesListPage-BEXwU3Z0.js.map} +1 -1
  195. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js → ResolverForm-2ks-3jXC.js} +6 -6
  196. package/dashboard/dist/assets/{ResolverForm-ZVufJ4G-.js.map → ResolverForm-2ks-3jXC.js.map} +1 -1
  197. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js → RoleDetailPage-DqoOk0xc.js} +3 -3
  198. package/dashboard/dist/assets/{RoleDetailPage-CTbq0mz4.js.map → RoleDetailPage-DqoOk0xc.js.map} +1 -1
  199. package/dashboard/dist/assets/{RolePill-CoETDpjF.js → RolePill-R5_ctGFy.js} +2 -2
  200. package/dashboard/dist/assets/{RolePill-CoETDpjF.js.map → RolePill-R5_ctGFy.js.map} +1 -1
  201. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js → RolesPage-CPmo8Srr.js} +2 -2
  202. package/dashboard/dist/assets/{RolesPage-DBKxeam4.js.map → RolesPage-CPmo8Srr.js.map} +1 -1
  203. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js → RosterWidget-D2yovCKw.js} +2 -2
  204. package/dashboard/dist/assets/{RosterWidget-BkLAwEYB.js.map → RosterWidget-D2yovCKw.js.map} +1 -1
  205. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js → RunAsSelector-CMv96On6.js} +2 -2
  206. package/dashboard/dist/assets/{RunAsSelector-D2DC4iDf.js.map → RunAsSelector-CMv96On6.js.map} +1 -1
  207. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js → ScanCodesPage-CA6cTT-M.js} +2 -2
  208. package/dashboard/dist/assets/{ScanCodesPage-BlKleaT0.js.map → ScanCodesPage-CA6cTT-M.js.map} +1 -1
  209. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js → ScanSchemeDetailPage-DnctN5-H.js} +2 -2
  210. package/dashboard/dist/assets/{ScanSchemeDetailPage-CTW6gofi.js.map → ScanSchemeDetailPage-DnctN5-H.js.map} +1 -1
  211. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js → ScanStationPage-Bk8RwkKL.js} +2 -2
  212. package/dashboard/dist/assets/{ScanStationPage-DPRjSPyT.js.map → ScanStationPage-Bk8RwkKL.js.map} +1 -1
  213. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js → ScopeBadge-BXZ084nD.js} +2 -2
  214. package/dashboard/dist/assets/{ScopeBadge-CGsTtqFr.js.map → ScopeBadge-BXZ084nD.js.map} +1 -1
  215. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js → StickyPagination-B0FSuUgs.js} +2 -2
  216. package/dashboard/dist/assets/{StickyPagination-CkmX3-Gu.js.map → StickyPagination-B0FSuUgs.js.map} +1 -1
  217. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js → StreamMessageDetail-BwZEvMpP.js} +2 -2
  218. package/dashboard/dist/assets/{StreamMessageDetail-Xm_n510s.js.map → StreamMessageDetail-BwZEvMpP.js.map} +1 -1
  219. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js → SwimlaneTimeline-BDVQEaMw.js} +2 -2
  220. package/dashboard/dist/assets/{SwimlaneTimeline-De48aJan.js.map → SwimlaneTimeline-BDVQEaMw.js.map} +1 -1
  221. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js → TagInput-DjPUDp2M.js} +2 -2
  222. package/dashboard/dist/assets/{TagInput-S7UuVT_M.js.map → TagInput-DjPUDp2M.js.map} +1 -1
  223. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js → TaskDetailPage-BOlv3iGB.js} +2 -2
  224. package/dashboard/dist/assets/{TaskDetailPage-HycMx3O9.js.map → TaskDetailPage-BOlv3iGB.js.map} +1 -1
  225. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js → TaskQueuePill-D-4Ynf3K.js} +2 -2
  226. package/dashboard/dist/assets/{TaskQueuePill-BlHNpYiZ.js.map → TaskQueuePill-D-4Ynf3K.js.map} +1 -1
  227. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js → TasksListPage-e2teY0bD.js} +2 -2
  228. package/dashboard/dist/assets/{TasksListPage-OIcFFp1C.js.map → TasksListPage-e2teY0bD.js.map} +1 -1
  229. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js → TimeAgo-Cvkpf_b3.js} +2 -2
  230. package/dashboard/dist/assets/{TimeAgo-OTC_55oZ.js.map → TimeAgo-Cvkpf_b3.js.map} +1 -1
  231. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js → TimestampCell-B3btAV0N.js} +2 -2
  232. package/dashboard/dist/assets/{TimestampCell-CAwIj_AI.js.map → TimestampCell-B3btAV0N.js.map} +1 -1
  233. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js → ToolPill-GsKQ80CO.js} +2 -2
  234. package/dashboard/dist/assets/{ToolPill-D40uLM_v.js.map → ToolPill-GsKQ80CO.js.map} +1 -1
  235. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js → ToolTestPanel-B03nebR7.js} +2 -2
  236. package/dashboard/dist/assets/{ToolTestPanel-8Vf6pfw4.js.map → ToolTestPanel-B03nebR7.js.map} +1 -1
  237. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js → TopicDetailPage-DBRWne3O.js} +3 -3
  238. package/dashboard/dist/assets/{TopicDetailPage-iZW8rK9L.js.map → TopicDetailPage-DBRWne3O.js.map} +1 -1
  239. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js → TopicsPage-CVe2M9HD.js} +2 -2
  240. package/dashboard/dist/assets/{TopicsPage-CqiEcj-W.js.map → TopicsPage-CVe2M9HD.js.map} +1 -1
  241. package/dashboard/dist/assets/{UserName-DQFjuoib.js → UserName-B_q_qp6V.js} +2 -2
  242. package/dashboard/dist/assets/{UserName-DQFjuoib.js.map → UserName-B_q_qp6V.js.map} +1 -1
  243. package/dashboard/dist/assets/WorkflowExecutionPage-Bh_dr9tM.js +2 -0
  244. package/dashboard/dist/assets/{WorkflowExecutionPage-Di08wCbs.js.map → WorkflowExecutionPage-Bh_dr9tM.js.map} +1 -1
  245. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js → WorkflowPill-D7244fKp.js} +2 -2
  246. package/dashboard/dist/assets/{WorkflowPill-DJLcK_CM.js.map → WorkflowPill-D7244fKp.js.map} +1 -1
  247. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js → WorkflowsDashboard-DA6Mj7qH.js} +2 -2
  248. package/dashboard/dist/assets/{WorkflowsDashboard-Bb8HlrTJ.js.map → WorkflowsDashboard-DA6Mj7qH.js.map} +1 -1
  249. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js → WorkflowsOverview-B1kBLj-a.js} +2 -2
  250. package/dashboard/dist/assets/{WorkflowsOverview-Dta1kurk.js.map → WorkflowsOverview-B1kBLj-a.js.map} +1 -1
  251. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js → YamlWorkflowDetailPage-6GJM8QIX.js} +8 -8
  252. package/dashboard/dist/assets/{YamlWorkflowDetailPage-CfAajg68.js.map → YamlWorkflowDetailPage-6GJM8QIX.js.map} +1 -1
  253. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js → YamlWorkflowsPage-Bu811C7f.js} +2 -2
  254. package/dashboard/dist/assets/{YamlWorkflowsPage-CQFUzT4t.js.map → YamlWorkflowsPage-Bu811C7f.js.map} +1 -1
  255. package/dashboard/dist/assets/{agents-PuftRTB2.js → agents-MPk_GnYz.js} +2 -2
  256. package/dashboard/dist/assets/{agents-PuftRTB2.js.map → agents-MPk_GnYz.js.map} +1 -1
  257. package/dashboard/dist/assets/{bots-BmEiPAWY.js → bots-2RihE2Tc.js} +2 -2
  258. package/dashboard/dist/assets/{bots-BmEiPAWY.js.map → bots-2RihE2Tc.js.map} +1 -1
  259. package/dashboard/dist/assets/{capabilities-CRii4Soa.js → capabilities-CC4iwJ1P.js} +2 -2
  260. package/dashboard/dist/assets/{capabilities-CRii4Soa.js.map → capabilities-CC4iwJ1P.js.map} +1 -1
  261. package/dashboard/dist/assets/{controlplane-DO_czaYo.js → controlplane-Bmkic8BH.js} +2 -2
  262. package/dashboard/dist/assets/{controlplane-DO_czaYo.js.map → controlplane-Bmkic8BH.js.map} +1 -1
  263. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js → escalation-columns-B0lhUUrQ.js} +2 -2
  264. package/dashboard/dist/assets/{escalation-columns-CzCquCPh.js.map → escalation-columns-B0lhUUrQ.js.map} +1 -1
  265. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js → escalation-items-7WFpPo46.js} +2 -2
  266. package/dashboard/dist/assets/{escalation-items-Cy0ZgJqV.js.map → escalation-items-7WFpPo46.js.map} +1 -1
  267. package/dashboard/dist/assets/index-B9uv-euR.css +1 -0
  268. package/dashboard/dist/assets/{index-DhSCCpqM.js → index-B_XV1rwu.js} +2 -2
  269. package/dashboard/dist/assets/{index-DhSCCpqM.js.map → index-B_XV1rwu.js.map} +1 -1
  270. package/dashboard/dist/assets/{index-Cx8xb-oU.js → index-C2CLfGwL.js} +2 -2
  271. package/dashboard/dist/assets/{index-Cx8xb-oU.js.map → index-C2CLfGwL.js.map} +1 -1
  272. package/dashboard/dist/assets/{index-Cga5IW3D.js → index-C3AeFihz.js} +2 -2
  273. package/dashboard/dist/assets/{index-Cga5IW3D.js.map → index-C3AeFihz.js.map} +1 -1
  274. package/dashboard/dist/assets/{index-DiaRlFYI.js → index-CBri8fYM.js} +2 -2
  275. package/dashboard/dist/assets/{index-DiaRlFYI.js.map → index-CBri8fYM.js.map} +1 -1
  276. package/dashboard/dist/assets/{index-CL_1VpGb.js → index-CRWsB7ZC.js} +2 -2
  277. package/dashboard/dist/assets/{index-CL_1VpGb.js.map → index-CRWsB7ZC.js.map} +1 -1
  278. package/dashboard/dist/assets/{index-XntldBd0.js → index-CTOv3G7a.js} +2 -2
  279. package/dashboard/dist/assets/{index-XntldBd0.js.map → index-CTOv3G7a.js.map} +1 -1
  280. package/dashboard/dist/assets/{index-CfP2nKRc.js → index-CcArGkzI.js} +3 -3
  281. package/dashboard/dist/assets/{index-CfP2nKRc.js.map → index-CcArGkzI.js.map} +1 -1
  282. package/dashboard/dist/assets/{index-Dz6R8-Dw.js → index-CkMHS-hG.js} +25 -25
  283. package/dashboard/dist/assets/index-CkMHS-hG.js.map +1 -0
  284. package/dashboard/dist/assets/index-CmsmwCyv.js +2 -0
  285. package/dashboard/dist/assets/{index-4YaDUcKd.js.map → index-CmsmwCyv.js.map} +1 -1
  286. package/dashboard/dist/assets/{index-2SM2_onB.js → index-CvJsvqIc.js} +2 -2
  287. package/dashboard/dist/assets/{index-2SM2_onB.js.map → index-CvJsvqIc.js.map} +1 -1
  288. package/dashboard/dist/assets/{index-Rwqrflm-.js → index-D-ilRyfy.js} +2 -2
  289. package/dashboard/dist/assets/{index-Rwqrflm-.js.map → index-D-ilRyfy.js.map} +1 -1
  290. package/dashboard/dist/assets/{index-CZ7A3AcD.js → index-DSUtfDXx.js} +2 -2
  291. package/dashboard/dist/assets/{index-CZ7A3AcD.js.map → index-DSUtfDXx.js.map} +1 -1
  292. package/dashboard/dist/assets/{index-jL2K6us4.js → index-Da6ycKyf.js} +2 -2
  293. package/dashboard/dist/assets/{index-jL2K6us4.js.map → index-Da6ycKyf.js.map} +1 -1
  294. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js → knowledge-Bpbg20DC.js} +2 -2
  295. package/dashboard/dist/assets/{knowledge-CeUqGPuo.js.map → knowledge-Bpbg20DC.js.map} +1 -1
  296. package/dashboard/dist/assets/machines-BqOZZU-3.js +2 -0
  297. package/dashboard/dist/assets/machines-BqOZZU-3.js.map +1 -0
  298. package/dashboard/dist/assets/{mcp-Cx96NTeD.js → mcp-CmcUXYce.js} +2 -2
  299. package/dashboard/dist/assets/{mcp-Cx96NTeD.js.map → mcp-CmcUXYce.js.map} +1 -1
  300. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js → mcp-query-C8buQxN9.js} +2 -2
  301. package/dashboard/dist/assets/{mcp-query-XAzWl0gm.js.map → mcp-query-C8buQxN9.js.map} +1 -1
  302. package/dashboard/dist/assets/{personas--4kjwyOw.js → personas-C2n5oDmY.js} +2 -2
  303. package/dashboard/dist/assets/{personas--4kjwyOw.js.map → personas-C2n5oDmY.js.map} +1 -1
  304. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js → pipelines-RKpSkFz7.js} +2 -2
  305. package/dashboard/dist/assets/{pipelines-PgkwvG7f.js.map → pipelines-RKpSkFz7.js.map} +1 -1
  306. package/dashboard/dist/assets/{tasks-CcYxdBa3.js → tasks-Dab4hExW.js} +2 -2
  307. package/dashboard/dist/assets/{tasks-CcYxdBa3.js.map → tasks-Dab4hExW.js.map} +1 -1
  308. package/dashboard/dist/assets/{topics-_lik7cNY.js → topics-FTMNP7r3.js} +2 -2
  309. package/dashboard/dist/assets/{topics-_lik7cNY.js.map → topics-FTMNP7r3.js.map} +1 -1
  310. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js → useDebouncedValue-B_1u1YIk.js} +2 -2
  311. package/dashboard/dist/assets/{useDebouncedValue-Bm_AoxVx.js.map → useDebouncedValue-B_1u1YIk.js.map} +1 -1
  312. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js → useNamespace-HUeAI7Qb.js} +2 -2
  313. package/dashboard/dist/assets/{useNamespace-DgXXKdx5.js.map → useNamespace-HUeAI7Qb.js.map} +1 -1
  314. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js → useYamlActivityEvents-Cax54qHH.js} +2 -2
  315. package/dashboard/dist/assets/{useYamlActivityEvents-Dj2qtGSd.js.map → useYamlActivityEvents-Cax54qHH.js.map} +1 -1
  316. package/dashboard/dist/assets/{validate-FlXCBBT6.js → validate-DxOaV7QS.js} +2 -2
  317. package/dashboard/dist/assets/{validate-FlXCBBT6.js.map → validate-DxOaV7QS.js.map} +1 -1
  318. package/dashboard/dist/assets/{vendor-icons-DUYcKTjP.js → vendor-icons-fxBvvHBi.js} +187 -182
  319. package/dashboard/dist/assets/vendor-icons-fxBvvHBi.js.map +1 -0
  320. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js → yaml-workflows-BgY1XHJx.js} +2 -2
  321. package/dashboard/dist/assets/{yaml-workflows-B0_JxRYQ.js.map → yaml-workflows-BgY1XHJx.js.map} +1 -1
  322. package/dashboard/dist/index.html +3 -3
  323. package/docs/architecture.md +1 -0
  324. package/docs/code-owned-configuration.md +6 -0
  325. package/docs/dashboard.md +1 -0
  326. package/docs/events.md +34 -1
  327. package/docs/machines.md +93 -16
  328. package/docs/mcp.md +19 -0
  329. package/package.json +1 -1
  330. package/dashboard/dist/assets/AgentsPage-C9UuUKhr.js +0 -2
  331. package/dashboard/dist/assets/AvailableEscalationsPage-DrvfXz70.js +0 -2
  332. package/dashboard/dist/assets/FilterBar-BygWrnB1.js +0 -2
  333. package/dashboard/dist/assets/FilterBar-BygWrnB1.js.map +0 -1
  334. package/dashboard/dist/assets/McpRunDetailPage-80fQn9iX.js +0 -2
  335. package/dashboard/dist/assets/WorkflowExecutionPage-Di08wCbs.js +0 -2
  336. package/dashboard/dist/assets/index-4YaDUcKd.js +0 -2
  337. package/dashboard/dist/assets/index-CnU7Jjz3.css +0 -1
  338. package/dashboard/dist/assets/index-Dz6R8-Dw.js.map +0 -1
  339. package/dashboard/dist/assets/vendor-icons-DUYcKTjP.js.map +0 -1
@@ -4,6 +4,7 @@
4
4
  * reads escalation events (a new handoff row means "dispatch"), reads every
5
5
  * machine message on the line (a receipt means "resolve"), and performs the
6
6
  * verbs a person would, as the machine. Neither side knows about the other.
7
+ * Every message read or sent is recorded on the wire (wire.ts).
7
8
  */
8
9
  Object.defineProperty(exports, "__esModule", { value: true });
9
10
  exports.MachineGateway = void 0;
@@ -15,14 +16,18 @@ const address_book_1 = require("./address-book");
15
16
  const admission_1 = require("./admission");
16
17
  const protocol_1 = require("../../../lib/machines/protocol");
17
18
  const transport_1 = require("../../../lib/machines/transport");
19
+ const publish_1 = require("../../../lib/events/publish");
18
20
  const reply_waiter_1 = require("./reply-waiter");
19
21
  const executor_1 = require("./executor");
22
+ const dispatcher_1 = require("./dispatcher");
23
+ const inspect_1 = require("./inspect");
20
24
  const log_1 = require("./log");
21
25
  const plan_escalation_1 = require("./plan-escalation");
22
26
  const pacing_1 = require("./pacing");
23
27
  const plan_machine_1 = require("./plan-machine");
24
28
  const state_1 = require("./state");
25
29
  const receipts_1 = require("./receipts");
30
+ const wire_1 = require("./wire");
26
31
  class MachineGateway {
27
32
  constructor(deps) {
28
33
  this.deps = deps;
@@ -32,18 +37,20 @@ class MachineGateway {
32
37
  this.codec = deps.codec ?? (0, protocol_1.genericCodec)({ root: deps.settings.topicRoot, line: deps.line });
33
38
  this.state.unitsPerDispatch = this.codec.unitsPerDispatch;
34
39
  this.state.dispatchOnArrival = this.codec.dispatchOn === protocol_1.DISPATCH_ON.ARRIVAL;
40
+ this.state.rowOps = (0, protocol_1.declaredRowOps)(this.codec);
35
41
  this.state.lifecycle = deps.settings.lifecycle === true;
36
42
  this.state.retainedAlarms = this.codec.retainedAlarms === true;
37
43
  this.state.progressStep = deps.settings.progressStep ?? this.state.progressStep;
38
44
  this.addresses = deps.addresses ?? new address_book_1.MemoryAddressBook();
45
+ this.wire = new wire_1.WireRecorder(deps.line, deps.wire ?? publish_1.publishMachineWireEvent, { telemetry: deps.settings.wireTelemetry === true });
39
46
  this.executor = new executor_1.Executor({
40
- addresses: this.addresses,
47
+ addresses: this.addresses, wire: this.wire,
41
48
  bus: deps.bus, lt: deps.lt, replies: new reply_waiter_1.ReplyWaiter(), state: this.state, line: deps.line,
42
49
  codec: this.codec, replyTimeoutMs: deps.settings.replyTimeoutMs,
43
50
  dispatchAttempts: deps.settings.dispatchAttempts, offlineDebounceMs: deps.settings.offlineDebounceMs, log: this.log,
44
51
  });
45
52
  this.admission = { state: this.state, line: deps.line, executor: this.executor, log: this.log, pace: () => this.pace() };
46
- this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log });
53
+ this.receipts = new receipts_1.ReceiptBatcher({ bus: deps.bus, codec: this.codec, delayMs: deps.settings.receiptDelayMs ?? DEFAULT_RECEIPT_DELAY_MS, log: this.log, wire: this.wire });
47
54
  }
48
55
  async start() {
49
56
  await this.deps.bus.connect();
@@ -61,10 +68,17 @@ class MachineGateway {
61
68
  }
62
69
  this.log.info(log_1.GATEWAY_LOG.STARTED, { site: this.deps.line.siteId, line: this.deps.line.lineId });
63
70
  }
71
+ /**
72
+ * Hand the line over cleanly: nothing new is raised or sent, a message
73
+ * still being handled is nak'd for the next leader if it would make a row,
74
+ * receipts for what was applied go out, then the sessions close.
75
+ */
64
76
  async stop() {
65
77
  if (this.quietTimer)
66
78
  clearInterval(this.quietTimer);
67
79
  this.executor.stop();
80
+ await this.deps.feed.unsubscribe();
81
+ await this.deps.bus.unsubscribe();
68
82
  await this.executor.idle();
69
83
  await this.receipts.flush();
70
84
  await this.deps.feed.close();
@@ -81,6 +95,10 @@ class MachineGateway {
81
95
  idle() {
82
96
  return this.executor.idle();
83
97
  }
98
+ /** A dry run of one message on a copy of the state: nothing is applied (inspect.ts). */
99
+ inspect(msg) {
100
+ return (0, inspect_1.dryRun)({ state: this.state, line: this.deps.line, codec: this.codec, dispatchTtlMs: this.deps.settings.dispatchTtlMs }, { ...msg, deliveries: 1 });
101
+ }
84
102
  /**
85
103
  * On taking the line: open handoff and command rows (a dispatch or command
86
104
  * interrupted by a restart is sent again with the same cmdId), the gateway's
@@ -138,16 +156,21 @@ class MachineGateway {
138
156
  const active = new Set();
139
157
  this.state.readingRetained = true;
140
158
  try {
141
- for (const msg of await this.deps.bus.retained((0, protocol_1.lineFilter)(this.codec.root, line.siteId, line.lineId))) {
142
- for (const raw of this.decode(msg.topic, msg.payload, true)) {
159
+ for (const read of await this.deps.bus.retained((0, protocol_1.lineFilter)(this.codec.root, line.siteId, line.lineId))) {
160
+ const msg = { ...read, retained: true };
161
+ for (const raw of this.decode(msg)) {
143
162
  if (!raw.parsed)
144
163
  continue;
145
- const seen = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
146
- if (!('parsed' in seen) || !seen.parsed)
164
+ const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
165
+ if (!('seen' in admitted)) {
166
+ this.wire.inbound(msg, raw, admitted, 1, admitted.sender);
147
167
  continue;
168
+ }
169
+ const { seen } = admitted;
148
170
  if (seen.parsed.kind === protocol_1.MESSAGE_KIND.ALARM && seen.body?.body?.active)
149
171
  active.add(this.state.alarmKey(seen.parsed.ident.machineId, seen.parsed.key));
150
- await this.applyMachine(msg.topic, seen.parsed, seen.body);
172
+ const applied = await this.applyMachine(msg.topic, seen.parsed, seen.body);
173
+ this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, 1);
151
174
  }
152
175
  }
153
176
  }
@@ -170,7 +193,8 @@ class MachineGateway {
170
193
  return transport_1.DISPOSITION.ACK;
171
194
  }
172
195
  catch (err) {
173
- this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { event: event.type, error: err.message });
196
+ if (!(err instanceof dispatcher_1.GatewayStopped))
197
+ this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { event: event.type, error: err.message });
174
198
  return transport_1.DISPOSITION.NAK;
175
199
  }
176
200
  }
@@ -188,19 +212,21 @@ class MachineGateway {
188
212
  return { ...event, role: row.role, data: row };
189
213
  }
190
214
  async onMachine(msg) {
191
- const decoded = this.decode(msg.topic, msg.payload, msg.retained);
215
+ const decoded = this.decode(msg);
192
216
  const acted = [];
193
217
  let outcome = transport_1.DISPOSITION.TERM;
194
218
  let failed = false;
195
219
  for (const raw of decoded) {
196
220
  if (!raw.parsed)
197
221
  continue;
198
- const seen = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
199
- if (!('parsed' in seen)) {
200
- failed ||= seen.failed;
201
- outcome = worse(outcome, seen.disposition);
222
+ const admitted = await (0, admission_1.admitSender)(this.admission, msg.topic, raw);
223
+ if (!('seen' in admitted)) {
224
+ failed ||= admitted.failed;
225
+ outcome = worse(outcome, admitted.disposition);
226
+ this.wire.inbound(msg, raw, admitted, msg.deliveries, admitted.sender);
202
227
  continue;
203
228
  }
229
+ const { seen } = admitted;
204
230
  acted.push(seen);
205
231
  if (seen.violations.length && msg.deliveries === 1) {
206
232
  this.log.warn(log_1.GATEWAY_LOG.CONTRACT_VIOLATION, { topic: msg.topic, violations: seen.violations });
@@ -210,9 +236,10 @@ class MachineGateway {
210
236
  : await this.applyMachine(msg.topic, seen.parsed, seen.body);
211
237
  failed ||= applied.failed;
212
238
  outcome = worse(outcome, applied.disposition);
239
+ this.wire.inbound(msg, seen, { ...applied, actions: [...admitted.actions, ...applied.actions] }, msg.deliveries);
213
240
  }
214
241
  // No row has claimed it after this many tries, so it is not racing its row: stop. A failed verb always retries.
215
- if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= MAX_DELIVERIES) {
242
+ if (outcome === transport_1.DISPOSITION.NAK && !failed && msg.deliveries >= wire_1.MAX_DELIVERIES) {
216
243
  this.log.warn(log_1.GATEWAY_LOG.UNMATCHED, { topic: msg.topic, deliveries: msg.deliveries });
217
244
  outcome = transport_1.DISPOSITION.TERM;
218
245
  }
@@ -221,14 +248,19 @@ class MachineGateway {
221
248
  return outcome;
222
249
  }
223
250
  /** A message the codec cannot read is not retried: it is logged and has no effect. */
224
- decode(topic, payload, retained) {
251
+ decode(msg) {
252
+ let decoded;
225
253
  try {
226
- return this.codec.decode(topic, payload, retained);
254
+ decoded = this.codec.decode(msg.topic, msg.payload, msg.retained);
227
255
  }
228
256
  catch (err) {
229
- this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
257
+ this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic: msg.topic, error: err.message });
258
+ this.wire.unreadable(msg, err.message);
230
259
  return [];
231
260
  }
261
+ if (!decoded.length)
262
+ this.wire.unreadable(msg, 'not a machine message', 'none');
263
+ return decoded;
232
264
  }
233
265
  /** Done with the message: confirm each id its codec asked to confirm. */
234
266
  confirm(decoded) {
@@ -247,21 +279,21 @@ class MachineGateway {
247
279
  }
248
280
  catch (err) {
249
281
  this.log.warn(log_1.GATEWAY_LOG.UNREADABLE, { topic, error: err.message });
250
- return { disposition: transport_1.DISPOSITION.TERM, failed: false };
282
+ return { disposition: transport_1.DISPOSITION.TERM, failed: false, actions: [{ verb: 'unreadable', detail: err.message }] };
251
283
  }
252
284
  try {
253
- await this.executor.apply(plan.actions);
285
+ const actions = await this.executor.apply(plan.actions);
254
286
  await this.pace();
255
- return { disposition: plan.disposition, failed: false };
287
+ return { disposition: plan.disposition, failed: false, actions };
256
288
  }
257
289
  catch (err) {
258
- this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
259
- return { disposition: transport_1.DISPOSITION.NAK, failed: true };
290
+ if (!(err instanceof dispatcher_1.GatewayStopped))
291
+ this.log.error(log_1.GATEWAY_LOG.VERB_FAILED, { topic, error: err.message });
292
+ return { disposition: transport_1.DISPOSITION.NAK, failed: true, actions: [] };
260
293
  }
261
294
  }
262
295
  }
263
296
  exports.MachineGateway = MachineGateway;
264
- const MAX_DELIVERIES = 30;
265
297
  const DEFAULT_RECEIPT_DELAY_MS = 250;
266
298
  const RANK = { [transport_1.DISPOSITION.TERM]: 0, [transport_1.DISPOSITION.ACK]: 1, [transport_1.DISPOSITION.NAK]: 2 };
267
299
  /** One wire message may decode to several; any that must be retried retries the message. */
@@ -8,3 +8,6 @@ export * from './provision';
8
8
  export * from './state';
9
9
  export * from './address-book';
10
10
  export * from './registration';
11
+ export * from './wire';
12
+ export * from './project';
13
+ export * from './inspect';
@@ -24,3 +24,6 @@ __exportStar(require("./provision"), exports);
24
24
  __exportStar(require("./state"), exports);
25
25
  __exportStar(require("./address-book"), exports);
26
26
  __exportStar(require("./registration"), exports);
27
+ __exportStar(require("./wire"), exports);
28
+ __exportStar(require("./project"), exports);
29
+ __exportStar(require("./inspect"), exports);
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A dry run of one wire message: what the codec reads and what the gateway
3
+ * would do, planned on a copy of the state so the line is untouched and no
4
+ * row is created or changed.
5
+ */
6
+ import type { LineDef } from '../../../lib/machines/line';
7
+ import type { LineCodec } from '../../../lib/machines/protocol';
8
+ import type { InboundMessage } from '../../../lib/machines/transport';
9
+ import type { InspectResult } from '../../../types/machines-view';
10
+ import type { GatewayState } from './state';
11
+ export interface DryRunContext {
12
+ state: GatewayState;
13
+ line: LineDef;
14
+ codec: LineCodec;
15
+ dispatchTtlMs: number;
16
+ }
17
+ export declare function dryRun(ctx: DryRunContext, msg: InboundMessage): InspectResult;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * A dry run of one wire message: what the codec reads and what the gateway
4
+ * would do, planned on a copy of the state so the line is untouched and no
5
+ * row is created or changed.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.dryRun = dryRun;
9
+ const plan_machine_1 = require("./plan-machine");
10
+ const registration_1 = require("./registration");
11
+ const wire_1 = require("./wire");
12
+ /** What admitting the sender would do, or null when the message would be acted on. */
13
+ function admission(state, line, raw) {
14
+ const sender = (0, registration_1.resolveSender)(state, line, raw);
15
+ if (sender.status === registration_1.SENDER.BOUND)
16
+ return { seen: sender.seen, actions: [{ verb: 'ack', detail: `bind ${sender.machineId} to ${sender.address}` }] };
17
+ if (sender.seen)
18
+ return { seen: sender.seen, actions: [] };
19
+ if (sender.status === registration_1.SENDER.UNKNOWN)
20
+ return { seen: null, actions: [{ verb: 'none', detail: `${sender.address} claims no station on this line` }] };
21
+ const raised = state.claimRaised(sender.address, sender.machineId);
22
+ return {
23
+ seen: null,
24
+ actions: [raised
25
+ ? { verb: 'none', detail: `${sender.address} says it is ${sender.machineId}; waiting for a person` }
26
+ : { verb: 'create-row', detail: `${sender.address} says it is ${sender.machineId}; a person decides` }],
27
+ };
28
+ }
29
+ function planOne(ctx, state, raw) {
30
+ const admitted = admission(state, ctx.line, raw);
31
+ if (!admitted.seen)
32
+ return admitted.actions;
33
+ if (raw.violations.length && ctx.codec.strict)
34
+ return [...admitted.actions, { verb: 'hold', detail: raw.violations.join('; ') }];
35
+ try {
36
+ const plan = (0, plan_machine_1.planMachineMessage)(state, admitted.seen.parsed, admitted.seen.body, ctx.dispatchTtlMs);
37
+ const actions = [...admitted.actions, ...plan.actions.map(wire_1.plannedAction)];
38
+ return (0, wire_1.appliedActions)({ disposition: plan.disposition, failed: false, actions }, 1);
39
+ }
40
+ catch (err) {
41
+ return [...admitted.actions, { verb: 'unreadable', detail: err.message }];
42
+ }
43
+ }
44
+ function dryRun(ctx, msg) {
45
+ let decoded;
46
+ try {
47
+ decoded = ctx.codec.decode(msg.topic, msg.payload, msg.retained);
48
+ }
49
+ catch (err) {
50
+ return { kind: null, event: null, summary: err.message, inspections: [], violations: [], actions: [{ verb: 'unreadable', detail: err.message }] };
51
+ }
52
+ if (!decoded.length) {
53
+ return { kind: null, event: null, summary: 'not a machine message', inspections: [], violations: [], actions: [{ verb: 'none', detail: 'not a machine message' }] };
54
+ }
55
+ const state = ctx.state.clone();
56
+ const actions = [];
57
+ const violations = [];
58
+ for (const raw of decoded) {
59
+ violations.push(...raw.violations);
60
+ if (raw.parsed)
61
+ actions.push(...planOne(ctx, state, raw));
62
+ }
63
+ const [first] = decoded;
64
+ return {
65
+ kind: first.parsed?.kind ?? null, event: (0, wire_1.eventOf)(first), summary: (0, wire_1.summarize)(first),
66
+ inspections: decoded, violations, actions: actions.length ? actions : [{ verb: 'unreadable', detail: 'unknown topic' }],
67
+ };
68
+ }
@@ -1,3 +1,4 @@
1
+ import { publishMachineLogEvent } from '../../../lib/events/publish';
1
2
  export declare const GATEWAY_LOG: {
2
3
  readonly STARTED: "machine_gateway.started";
3
4
  readonly RECONCILED: "machine_gateway.reconciled";
@@ -39,3 +40,10 @@ export interface GatewayLog {
39
40
  }
40
41
  export declare const consoleLog: GatewayLog;
41
42
  export declare const silentLog: GatewayLog;
43
+ /** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
44
+ export declare function eventsLog(line: {
45
+ siteId: string;
46
+ lineId: string;
47
+ }, publish?: typeof publishMachineLogEvent): GatewayLog;
48
+ /** Every entry goes to each log in turn. */
49
+ export declare function composeLogs(...logs: GatewayLog[]): GatewayLog;
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.silentLog = exports.consoleLog = exports.GATEWAY_LOG = void 0;
4
+ exports.eventsLog = eventsLog;
5
+ exports.composeLogs = composeLogs;
6
+ const publish_1 = require("../../../lib/events/publish");
4
7
  exports.GATEWAY_LOG = {
5
8
  STARTED: 'machine_gateway.started',
6
9
  RECONCILED: 'machine_gateway.reconciled',
@@ -40,3 +43,18 @@ exports.consoleLog = {
40
43
  error: (event, context) => console.error(JSON.stringify({ level: 'error', event, ...context })),
41
44
  };
42
45
  exports.silentLog = { info: () => undefined, warn: () => undefined, error: () => undefined };
46
+ /** Each entry published as `machine.log.<site>.<line>.<event>` with its context, for the line's dashboard view. */
47
+ function eventsLog(line, publish = publish_1.publishMachineLogEvent) {
48
+ const emit = (level) => (event, context) => {
49
+ publish({ siteId: line.siteId, lineId: line.lineId, level, event, context }).catch(() => undefined);
50
+ };
51
+ return { info: emit('info'), warn: emit('warn'), error: emit('error') };
52
+ }
53
+ /** Every entry goes to each log in turn. */
54
+ function composeLogs(...logs) {
55
+ const each = (level) => (event, context) => {
56
+ for (const log of logs)
57
+ log[level](event, context);
58
+ };
59
+ return { info: each('info'), warn: each('warn'), error: each('error') };
60
+ }
@@ -39,6 +39,7 @@ function dispatchArgs(row, expiresAt) {
39
39
  expiresAt: (0, protocol_1.isoTs)(expiresAt),
40
40
  ...(row.artifactUrl ? { artifact: { url: row.artifactUrl, sha256: row.artifactSha256 } } : {}),
41
41
  ...(row.parameters ? { parameters: row.parameters } : {}),
42
+ ...(row.refs ? { refs: row.refs } : {}),
42
43
  };
43
44
  }
44
45
  /**
@@ -93,8 +93,9 @@ function commandRefusal(state, line, c, role) {
93
93
  const own = (0, line_1.machineRole)((0, line_1.machineById)(line, c.machineId));
94
94
  if (role !== own)
95
95
  return `commands for ${c.machineId} are parked on ${own}, not ${role}`;
96
- if (!protocol_1.CONTROL_OPS.includes(c.op))
97
- return `${c.op} is not a command a row may ask for; one of ${protocol_1.CONTROL_OPS.join(', ')}`;
96
+ const allowed = rowOps(state);
97
+ if (!allowed.includes(c.op))
98
+ return `${c.op} is not a command a row may ask for; one of ${allowed.join(', ')}`;
98
99
  if (c.op === protocol_1.OP.CANCEL && typeof c.args.jobId !== 'string')
99
100
  return `${protocol_1.OP.CANCEL} needs args.jobId, the job to withdraw or stop`;
100
101
  if (!(0, registration_1.reachable)(state, line, c.machineId))
@@ -110,7 +111,7 @@ function planCommandRow(state, line, event) {
110
111
  if (event.verb !== VERB.CREATED && event.verb !== VERB.CLAIMED)
111
112
  return [];
112
113
  const c = (0, commands_1.readCommandFacets)(event.data?.metadata);
113
- if (!c || !state.trackCommand(id))
114
+ if (!c || !state.trackCommand(id, c.machineId))
114
115
  return [];
115
116
  const refusal = commandRefusal(state, line, c, event.role);
116
117
  if (refusal) {
@@ -119,6 +120,10 @@ function planCommandRow(state, line, event) {
119
120
  const createdAt = event.data?.created_at ? new Date(event.data.created_at).getTime() : NaN;
120
121
  return [{ kind: 'control', rowId: id, machineId: c.machineId, op: c.op, args: c.args, ...(Number.isFinite(createdAt) ? { createdAt } : {}) }];
121
122
  }
123
+ /** The ops a machine-command row may ask for: the control ops, a snapshot, and the codec's own. */
124
+ function rowOps(state) {
125
+ return [...protocol_1.CONTROL_OPS, protocol_1.OP.SNAPSHOT, ...state.rowOps];
126
+ }
122
127
  function onLine(line, machineId) {
123
128
  return !!machineId && line.machines.some((m) => m.machineId === machineId);
124
129
  }
@@ -36,7 +36,7 @@ function planMachineMessage(state, parsed, env, dispatchTtlMs) {
36
36
  function planByKind(state, m, parsed, env, b, ttl) {
37
37
  switch (parsed.kind) {
38
38
  case protocol_1.MESSAGE_KIND.REPLY:
39
- return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason }]);
39
+ return ack([{ kind: 'settleReply', cmdId: b.cmdId, status: b.status, reason: b.reason, ...(typeof b.code === 'string' ? { code: b.code } : {}) }]);
40
40
  case protocol_1.MESSAGE_KIND.JOB:
41
41
  return planJob(state, m, b, env?.at, ttl);
42
42
  case protocol_1.MESSAGE_KIND.ALARM:
@@ -139,7 +139,8 @@ function planJob(state, m, b, at, ttl) {
139
139
  if (b.result === protocol_1.JOB_RESULT.OK)
140
140
  return ack([released]);
141
141
  return ack([released, ...(0, plan_shared_1.failHandoff)(state, row, m, {
142
- received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED, reason: b.reason ?? null, detail: `${m} finished ${unitId}: ${b.result}${b.reason ? ` (${b.reason})` : ''}`,
142
+ received: false, unitId, errorCode: contracts_1.HANDOFF_ERROR.SENDER_REJECTED, result: b.result, reason: b.reason ?? null,
143
+ detail: `${m} finished ${unitId}: ${b.result}${b.reason ? ` (${b.reason})` : ''}`,
143
144
  })]);
144
145
  }
145
146
  if (b.event === protocol_1.JOB_EVENT.TRANSFER_FAILED) {
@@ -198,7 +199,7 @@ function planAlarm(state, parsed, alarmId, env) {
198
199
  const superseded = known?.rowId && known.open
199
200
  ? [{ kind: 'resolve', as: actions_1.CONTROLLER, rowId: known.rowId, payload: { decision: contracts_1.DECISION.CLEARED, note: `${m} raised ${alarmId} again; this one ended` } }]
200
201
  : [];
201
- const track = { machineId: m, alarmId, raisedAt: b.raisedAt, open: true };
202
+ const track = { machineId: m, alarmId, raisedAt: b.raisedAt, level: b.level, open: true };
202
203
  state.alarms.set(key, track);
203
204
  return ack([...superseded, ...(0, lifecycle_1.notePause)(state, track, b), {
204
205
  kind: 'createAlarmRow', machineId: m, alarmId,
@@ -222,10 +223,12 @@ function catalogEnvelope(catalog) {
222
223
  }
223
224
  function planPresence(state, m, b) {
224
225
  const link = state.link(m);
226
+ const session = typeof b.sessionId === 'string' ? b.sessionId : undefined;
225
227
  if (b.online !== true) {
226
228
  if (link.online)
227
229
  link.since = Date.now();
228
230
  link.online = false;
231
+ link.reason = typeof b.reason === 'string' ? b.reason : undefined;
229
232
  if (link.rowId || link.watching)
230
233
  return ack();
231
234
  link.watching = true;
@@ -234,12 +237,17 @@ function planPresence(state, m, b) {
234
237
  if (b.software)
235
238
  link.software = b.software;
236
239
  const wasOffline = !link.online;
240
+ // A new session while online: the machine reconnected before its offline presence was heard.
241
+ const reconnected = !!session && !!link.sessionId && session !== link.sessionId;
237
242
  link.online = true;
238
243
  link.watching = false;
244
+ link.reason = undefined;
245
+ if (session)
246
+ link.sessionId = session;
239
247
  const actions = [];
240
248
  // Back from a drop: ask for the full state rather than wait for the next heartbeat.
241
- if (wasOffline)
242
- actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${link.since}`, args: {} });
249
+ if (wasOffline || reconnected)
250
+ actions.push({ kind: 'command', machineId: m, op: protocol_1.OP.SNAPSHOT, cmdId: `${m}:resync:${session ?? link.since}`, args: {} });
243
251
  if (link.rowId) {
244
252
  actions.push({ kind: 'resolve', as: actions_1.CONTROLLER, rowId: link.rowId, payload: { decision: contracts_1.DECISION.RESTORED, note: `${m} back online` } });
245
253
  link.rowId = undefined;
@@ -252,8 +260,10 @@ function planSnapshot(state, m, b, ttl) {
252
260
  if (b.software)
253
261
  link.software = b.software;
254
262
  const jobIds = Array.isArray(b.jobs) ? b.jobs.map((j) => j?.jobId).filter((id) => typeof id === 'string') : [];
255
- if (Array.isArray(b.jobs))
263
+ if (Array.isArray(b.jobs)) {
256
264
  state.keepHeld(m, new Set(jobIds));
265
+ link.jobs = b.jobs;
266
+ }
257
267
  const fresh = !state.retainedAlarms && !state.readingRetained && Array.isArray(b.alarms);
258
268
  const cleared = fresh ? alarmsNoLongerListed(state, m, b.alarms) : [];
259
269
  const answer = { kind: 'settleSnapshot', machineId: m, jobIds };
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The line as its leader sees it, for the dashboard: each machine's link,
3
+ * held units, open rows and alarms from the gateway state, and the claims
4
+ * waiting for a person. Pure: reads the state and the line, changes nothing.
5
+ */
6
+ import { type LineDef } from '../../../lib/machines/line';
7
+ import type { LineView } from '../../../types/machines-view';
8
+ import type { GatewayState } from './state';
9
+ export declare function projectLine(state: GatewayState, line: LineDef): LineView;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ /**
3
+ * The line as its leader sees it, for the dashboard: each machine's link,
4
+ * held units, open rows and alarms from the gateway state, and the claims
5
+ * waiting for a person. Pure: reads the state and the line, changes nothing.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.projectLine = projectLine;
9
+ const line_1 = require("../../../lib/machines/line");
10
+ const protocol_1 = require("../../../lib/machines/protocol");
11
+ const at = (ms) => (ms ? (0, protocol_1.isoTs)(ms) : null);
12
+ function addressOf(state, line, def) {
13
+ if ((0, line_1.learnsAddress)(line, def.machineId))
14
+ return state.learnedAddress(def.machineId) ?? null;
15
+ return def.address ?? def.machineId;
16
+ }
17
+ function alarmsOf(state, machineId) {
18
+ return [...state.alarms.values()]
19
+ .filter((track) => track.machineId === machineId)
20
+ .map((track) => ({ alarmId: track.alarmId, level: track.level ?? '', raisedAt: track.raisedAt ?? '', rowId: track.rowId ?? null }));
21
+ }
22
+ /** The handoff that brought a unit into a machine: open first, then the recently closed one. */
23
+ function rowCarrying(state, machineId, unitId) {
24
+ const into = (r) => r.toMachine === machineId;
25
+ return state.openFor(unitId, into) ?? state.closedFor(unitId, into);
26
+ }
27
+ function machineView(state, line, def) {
28
+ const m = def.machineId;
29
+ const link = state.links.get(m);
30
+ const open = state.open();
31
+ return {
32
+ machineId: m, process: def.process, role: (0, line_1.machineRole)(def), address: addressOf(state, line, def),
33
+ online: link ? link.online : null, since: at(link?.since), lastSeen: at(link?.lastSeen),
34
+ software: link?.software ?? null, bootId: link?.bootId ?? null, sessionId: link?.sessionId ?? null,
35
+ heldUnits: state.heldUnitsAt(m).map(({ unitId }) => {
36
+ const row = rowCarrying(state, m, unitId);
37
+ return { unitId, carrierId: row?.units.find((u) => u.unitId === unitId)?.carrierId ?? null, rowId: row?.id ?? '' };
38
+ }),
39
+ rows: {
40
+ handoff: open.filter((r) => r.toMachine === m).length,
41
+ command: state.openCommandsFor(m),
42
+ alarm: [...state.alarms.values()].filter((t) => t.machineId === m && t.open && !!t.rowId).length,
43
+ offlineRowId: link?.rowId ?? null, quietRowId: link?.quietRowId ?? null,
44
+ },
45
+ alarms: alarmsOf(state, m),
46
+ jobs: link?.jobs ?? [],
47
+ };
48
+ }
49
+ function projectLine(state, line) {
50
+ return {
51
+ siteId: line.siteId, lineId: line.lineId, leading: true, takenAt: at(state.takenAt),
52
+ machines: line.machines.map((def) => machineView(state, line, def)),
53
+ contested: state.contested(),
54
+ };
55
+ }
@@ -9,6 +9,7 @@
9
9
  import { type LineCodec, type MachineIdent } from '../../../lib/machines/protocol';
10
10
  import type { MachineBus } from '../../../lib/machines/transport';
11
11
  import { type GatewayLog } from './log';
12
+ import type { WireRecorder } from './wire';
12
13
  /** Most message ids one receipt carries. */
13
14
  export declare const MAX_RECEIPT_IDS = 100;
14
15
  export interface ReceiptDeps {
@@ -17,6 +18,8 @@ export interface ReceiptDeps {
17
18
  /** How long ids gather before a receipt goes out. */
18
19
  delayMs: number;
19
20
  log: GatewayLog;
21
+ /** Records each receipt the gateway sends, for the line's wire view. */
22
+ wire?: Pick<WireRecorder, 'receipt'>;
20
23
  }
21
24
  export declare class ReceiptBatcher {
22
25
  private readonly d;
@@ -58,8 +58,10 @@ class ReceiptBatcher {
58
58
  this.sending.add(work);
59
59
  }
60
60
  async publish(ident, ids) {
61
- for (const wire of this.d.codec.receipt(ident, ids))
61
+ for (const wire of this.d.codec.receipt(ident, ids)) {
62
62
  await this.d.bus.publish(wire.topic, wire.payload);
63
+ this.d.wire?.receipt(ident, ids, wire);
64
+ }
63
65
  }
64
66
  }
65
67
  exports.ReceiptBatcher = ReceiptBatcher;
@@ -22,8 +22,8 @@ async function restoreLineRows(state, lt, line) {
22
22
  const [alarms, offline, quiet, registrations] = await Promise.all([contracts_1.ROW_TYPE.ALARM, contracts_1.ROW_TYPE.MACHINE_OFFLINE, contracts_1.ROW_TYPE.MACHINE_QUIET, contracts_1.ROW_TYPE.MACHINE_REGISTRATION]
23
23
  .map(async (type) => (await lt.listOpen({ type, role })).filter(mine)));
24
24
  for (const row of alarms) {
25
- const { machineId, alarmId, raisedAt } = row.metadata;
26
- state.alarms.set(state.alarmKey(machineId, alarmId), { machineId, alarmId, raisedAt, rowId: row.id, open: true });
25
+ const { machineId, alarmId, raisedAt, level } = row.metadata;
26
+ state.alarms.set(state.alarmKey(machineId, alarmId), { machineId, alarmId, raisedAt, level, rowId: row.id, open: true });
27
27
  }
28
28
  for (const row of offline) {
29
29
  const link = state.link(row.metadata.machineId);
@@ -33,7 +33,7 @@ async function restoreLineRows(state, lt, line) {
33
33
  for (const row of quiet)
34
34
  state.link(row.metadata.machineId).quietRowId = row.id;
35
35
  for (const row of registrations)
36
- state.raiseClaim(row.metadata.address, row.metadata.machineId);
36
+ state.raiseClaim(row.metadata.address, row.metadata.machineId, row.id);
37
37
  return { alarms: alarms.length, offline: offline.length, quiet: quiet.length, registrations: registrations.length };
38
38
  }
39
39
  /** The addresses the line learned before, for the stations that still learn theirs. */
@@ -106,7 +106,7 @@ function planRegistrationRow(state, line, event) {
106
106
  if (typeof md.machineId !== 'string' || typeof md.address !== 'string')
107
107
  return [];
108
108
  if (event.verb === 'created') {
109
- state.raiseClaim(md.address, md.machineId);
109
+ state.raiseClaim(md.address, md.machineId, event.escalationId);
110
110
  return [];
111
111
  }
112
112
  state.settleClaim(md.address, md.machineId);
@@ -1,12 +1,15 @@
1
1
  /**
2
2
  * Command replies by cmdId, and machine snapshots by machine. A wait registers
3
3
  * before the command is published and resolves with the reply, or null at the
4
- * deadline.
4
+ * deadline. Several waits on one key are all settled by the next answer, so
5
+ * two dispatches asking one machine what it holds share its next snapshot.
5
6
  */
6
7
  export interface CommandReply {
7
8
  cmdId: string;
8
9
  status: string;
9
10
  reason: string;
11
+ /** The machine's structured code for the outcome, when its reply carried one. */
12
+ code?: string;
10
13
  }
11
14
  /** The jobs a machine reports holding, queued or in work. */
12
15
  export type HeldJobs = Set<string>;
@@ -16,9 +19,9 @@ export declare class ReplyWaiter {
16
19
  wait(cmdId: string, timeoutMs: number): Promise<CommandReply | null>;
17
20
  /** True when a waiter took the reply. */
18
21
  settle(reply: CommandReply): boolean;
19
- /** The next snapshot from `machineId`, or null at the deadline. */
22
+ /** The next snapshot from `machineId`, or null at the deadline; every wait in flight for the machine gets it. */
20
23
  waitSnapshot(machineId: string, timeoutMs: number): Promise<HeldJobs | null>;
21
- /** Answer a status query in flight; null when there is nothing to wait for. */
24
+ /** Answer the status queries in flight; null when there is nothing to wait for. */
22
25
  settleSnapshot(machineId: string, jobs: HeldJobs | null): void;
23
26
  cancelAll(): void;
24
27
  }