@hotmeshio/long-tail 0.7.4 → 0.8.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 (244) hide show
  1. package/build/api/roles.d.ts +4 -0
  2. package/build/api/roles.js +7 -1
  3. package/build/api/workflows/config.d.ts +7 -1
  4. package/build/api/workflows/config.js +7 -1
  5. package/build/api/workflows/discovery.js +1 -4
  6. package/build/lib/db/schemas/019_role_priority.sql +28 -0
  7. package/build/lib/db/schemas/020_workflow_certified.sql +34 -0
  8. package/build/modules/ltconfig.d.ts +3 -2
  9. package/build/modules/ltconfig.js +4 -4
  10. package/build/routes/roles.js +1 -1
  11. package/build/routes/workflows/config.js +1 -0
  12. package/build/scripts/ortho-populate.d.ts +7 -1
  13. package/build/scripts/ortho-populate.js +21 -6
  14. package/build/services/config/cache.js +1 -0
  15. package/build/services/config/read.js +2 -0
  16. package/build/services/config/sql.d.ts +2 -2
  17. package/build/services/config/sql.js +6 -5
  18. package/build/services/config/write.js +13 -0
  19. package/build/services/escalation/bulk.d.ts +3 -1
  20. package/build/services/escalation/bulk.js +3 -1
  21. package/build/services/escalation/crud.d.ts +4 -3
  22. package/build/services/escalation/crud.js +4 -3
  23. package/build/services/escalation/facet-sql.d.ts +1 -0
  24. package/build/services/escalation/facet-sql.js +7 -6
  25. package/build/services/escalation/queries.js +27 -5
  26. package/build/services/escalation/sql.d.ts +19 -2
  27. package/build/services/escalation/sql.js +32 -9
  28. package/build/services/escalation/types.d.ts +7 -1
  29. package/build/services/role/index.js +2 -0
  30. package/build/services/role/sql.d.ts +4 -4
  31. package/build/services/role/sql.js +12 -6
  32. package/build/services/role/types.d.ts +14 -0
  33. package/build/start/workers.js +1 -0
  34. package/build/system/mcp-servers/admin/schemas.d.ts +9 -0
  35. package/build/system/mcp-servers/admin/schemas.js +6 -1
  36. package/build/system/mcp-servers/admin/users.js +4 -1
  37. package/build/system/mcp-servers/admin/workflow-config.js +1 -0
  38. package/build/system/seed/tool-manifests-admin.d.ts +152 -0
  39. package/build/system/seed/tool-manifests-admin.js +1 -1
  40. package/build/types/config.d.ts +16 -0
  41. package/build/types/startup.d.ts +11 -1
  42. package/dashboard/dist/assets/{AdminDashboard-C9eE1VEp.js → AdminDashboard-9JLg41f-.js} +2 -2
  43. package/dashboard/dist/assets/{AdminDashboard-C9eE1VEp.js.map → AdminDashboard-9JLg41f-.js.map} +1 -1
  44. package/dashboard/dist/assets/{AgentConfigPage-Ba8QfXM2.js → AgentConfigPage-D5P1hcOc.js} +6 -6
  45. package/dashboard/dist/assets/{AgentConfigPage-Ba8QfXM2.js.map → AgentConfigPage-D5P1hcOc.js.map} +1 -1
  46. package/dashboard/dist/assets/{AgentDetailPage-DVmec0CP.js → AgentDetailPage-DrijeAV8.js} +4 -4
  47. package/dashboard/dist/assets/{AgentDetailPage-DVmec0CP.js.map → AgentDetailPage-DrijeAV8.js.map} +1 -1
  48. package/dashboard/dist/assets/{AgentsPage-DNiCYMh3.js → AgentsPage-BW5d0JOt.js} +2 -2
  49. package/dashboard/dist/assets/{AgentsPage-DNiCYMh3.js.map → AgentsPage-BW5d0JOt.js.map} +1 -1
  50. package/dashboard/dist/assets/{AvailableEscalationsPage-gDIF8ocC.js → AvailableEscalationsPage-CoZ4Lufr.js} +2 -2
  51. package/dashboard/dist/assets/{AvailableEscalationsPage-gDIF8ocC.js.map → AvailableEscalationsPage-CoZ4Lufr.js.map} +1 -1
  52. package/dashboard/dist/assets/{BotPicker-3wBcBavT.js → BotPicker-xGUCxJo-.js} +2 -2
  53. package/dashboard/dist/assets/{BotPicker-3wBcBavT.js.map → BotPicker-xGUCxJo-.js.map} +1 -1
  54. package/dashboard/dist/assets/{CapabilitiesPage-WoPkND2y.js → CapabilitiesPage-ChaRJiyg.js} +2 -2
  55. package/dashboard/dist/assets/{CapabilitiesPage-WoPkND2y.js.map → CapabilitiesPage-ChaRJiyg.js.map} +1 -1
  56. package/dashboard/dist/assets/{CollapsibleSection-Cx99mqNN.js → CollapsibleSection-CXMPecjj.js} +2 -2
  57. package/dashboard/dist/assets/{CollapsibleSection-Cx99mqNN.js.map → CollapsibleSection-CXMPecjj.js.map} +1 -1
  58. package/dashboard/dist/assets/{CredentialsPage-DbNaoPbF.js → CredentialsPage-BbdfZh1D.js} +2 -2
  59. package/dashboard/dist/assets/{CredentialsPage-DbNaoPbF.js.map → CredentialsPage-BbdfZh1D.js.map} +1 -1
  60. package/dashboard/dist/assets/{CronLabel-DLW4_Zg4.js → CronLabel-CJUL50eO.js} +2 -2
  61. package/dashboard/dist/assets/{CronLabel-DLW4_Zg4.js.map → CronLabel-CJUL50eO.js.map} +1 -1
  62. package/dashboard/dist/assets/{CustomDurationPicker-BRUFjkiu.js → CustomDurationPicker-id6Tq64R.js} +2 -2
  63. package/dashboard/dist/assets/{CustomDurationPicker-BRUFjkiu.js.map → CustomDurationPicker-id6Tq64R.js.map} +1 -1
  64. package/dashboard/dist/assets/{DropZone-DEX0BBqt.js → DropZone-CZDmNBn-.js} +2 -2
  65. package/dashboard/dist/assets/{DropZone-DEX0BBqt.js.map → DropZone-CZDmNBn-.js.map} +1 -1
  66. package/dashboard/dist/assets/{ElapsedCell-BtmDQaym.js → ElapsedCell-B8TrnyT5.js} +2 -2
  67. package/dashboard/dist/assets/{ElapsedCell-BtmDQaym.js.map → ElapsedCell-B8TrnyT5.js.map} +1 -1
  68. package/dashboard/dist/assets/{EscalationSchemaPage-Bm4yBEGN.js → EscalationSchemaPage-C6UuZgCD.js} +2 -2
  69. package/dashboard/dist/assets/{EscalationSchemaPage-Bm4yBEGN.js.map → EscalationSchemaPage-C6UuZgCD.js.map} +1 -1
  70. package/dashboard/dist/assets/{EscalationsOverview-B3xZwTQA.js → EscalationsOverview-CjLyujJ3.js} +2 -2
  71. package/dashboard/dist/assets/{EscalationsOverview-B3xZwTQA.js.map → EscalationsOverview-CjLyujJ3.js.map} +1 -1
  72. package/dashboard/dist/assets/{EventTable-Bh9FKXLI.js → EventTable-D_rNmyGG.js} +2 -2
  73. package/dashboard/dist/assets/{EventTable-Bh9FKXLI.js.map → EventTable-D_rNmyGG.js.map} +1 -1
  74. package/dashboard/dist/assets/{GraphInvokePage-ov_ANlaE.js → GraphInvokePage-BMyrTnI6.js} +2 -2
  75. package/dashboard/dist/assets/{GraphInvokePage-ov_ANlaE.js.map → GraphInvokePage-BMyrTnI6.js.map} +1 -1
  76. package/dashboard/dist/assets/{HomePage-D0DV6izb.js → HomePage-MBv6pwk4.js} +2 -2
  77. package/dashboard/dist/assets/{HomePage-D0DV6izb.js.map → HomePage-MBv6pwk4.js.map} +1 -1
  78. package/dashboard/dist/assets/{ListToolbar-FpcvqNkN.js → ListToolbar--FkPpYDY.js} +2 -2
  79. package/dashboard/dist/assets/{ListToolbar-FpcvqNkN.js.map → ListToolbar--FkPpYDY.js.map} +1 -1
  80. package/dashboard/dist/assets/{McpOverview-DcuRiAff.js → McpOverview-CtAFXv-T.js} +2 -2
  81. package/dashboard/dist/assets/{McpOverview-DcuRiAff.js.map → McpOverview-CtAFXv-T.js.map} +1 -1
  82. package/dashboard/dist/assets/{McpQueryDetailPage-BcYl67KP.js → McpQueryDetailPage-5Jzz2q2g.js} +2 -2
  83. package/dashboard/dist/assets/{McpQueryDetailPage-BcYl67KP.js.map → McpQueryDetailPage-5Jzz2q2g.js.map} +1 -1
  84. package/dashboard/dist/assets/{McpQueryPage-C3GDzqZM.js → McpQueryPage-DveeRF5I.js} +2 -2
  85. package/dashboard/dist/assets/{McpQueryPage-C3GDzqZM.js.map → McpQueryPage-DveeRF5I.js.map} +1 -1
  86. package/dashboard/dist/assets/{McpRunDetailPage-SzOyhDBW.js → McpRunDetailPage-BYIxBcA7.js} +2 -2
  87. package/dashboard/dist/assets/{McpRunDetailPage-SzOyhDBW.js.map → McpRunDetailPage-BYIxBcA7.js.map} +1 -1
  88. package/dashboard/dist/assets/{McpRunsPage-BwgB6mRV.js → McpRunsPage-Cgke6ask.js} +2 -2
  89. package/dashboard/dist/assets/{McpRunsPage-BwgB6mRV.js.map → McpRunsPage-Cgke6ask.js.map} +1 -1
  90. package/dashboard/dist/assets/{NamespacePill-CwKdoyRM.js → NamespacePill-DlqBTvFR.js} +2 -2
  91. package/dashboard/dist/assets/{NamespacePill-CwKdoyRM.js.map → NamespacePill-DlqBTvFR.js.map} +1 -1
  92. package/dashboard/dist/assets/OperationsPage-D2i7xrAI.js +2 -0
  93. package/dashboard/dist/assets/OperationsPage-D2i7xrAI.js.map +1 -0
  94. package/dashboard/dist/assets/{OperatorDashboard-DSXh-yYw.js → OperatorDashboard-DMQwodfo.js} +2 -2
  95. package/dashboard/dist/assets/{OperatorDashboard-DSXh-yYw.js.map → OperatorDashboard-DMQwodfo.js.map} +1 -1
  96. package/dashboard/dist/assets/{PageHeader-BhaWTWcM.js → PageHeader-CFta2VaS.js} +2 -2
  97. package/dashboard/dist/assets/{PageHeader-BhaWTWcM.js.map → PageHeader-CFta2VaS.js.map} +1 -1
  98. package/dashboard/dist/assets/{PageHeaderWithStats-yex5WmHB.js → PageHeaderWithStats-CcVAji-7.js} +2 -2
  99. package/dashboard/dist/assets/{PageHeaderWithStats-yex5WmHB.js.map → PageHeaderWithStats-CcVAji-7.js.map} +1 -1
  100. package/dashboard/dist/assets/{ProcessDetailPage-iIB1rwEt.js → ProcessDetailPage-Dodrk5-z.js} +2 -2
  101. package/dashboard/dist/assets/{ProcessDetailPage-iIB1rwEt.js.map → ProcessDetailPage-Dodrk5-z.js.map} +1 -1
  102. package/dashboard/dist/assets/{ProcessesListPage-BrqWR2zr.js → ProcessesListPage-BVtkWVLY.js} +2 -2
  103. package/dashboard/dist/assets/{ProcessesListPage-BrqWR2zr.js.map → ProcessesListPage-BVtkWVLY.js.map} +1 -1
  104. package/dashboard/dist/assets/RoleDetailPage-8NldZI49.js +11 -0
  105. package/dashboard/dist/assets/RoleDetailPage-8NldZI49.js.map +1 -0
  106. package/dashboard/dist/assets/{RolePill-Cl71eDUA.js → RolePill-CXEyPMqb.js} +2 -2
  107. package/dashboard/dist/assets/{RolePill-Cl71eDUA.js.map → RolePill-CXEyPMqb.js.map} +1 -1
  108. package/dashboard/dist/assets/{RolesPage-Bzp9FhAl.js → RolesPage-BJBjtFNY.js} +2 -2
  109. package/dashboard/dist/assets/{RolesPage-Bzp9FhAl.js.map → RolesPage-BJBjtFNY.js.map} +1 -1
  110. package/dashboard/dist/assets/{RunAsSelector-DXbHRxQs.js → RunAsSelector-Cc1i017Z.js} +2 -2
  111. package/dashboard/dist/assets/{RunAsSelector-DXbHRxQs.js.map → RunAsSelector-Cc1i017Z.js.map} +1 -1
  112. package/dashboard/dist/assets/{StickyPagination-D8XuMSWD.js → StickyPagination-GQKFFTjL.js} +2 -2
  113. package/dashboard/dist/assets/{StickyPagination-D8XuMSWD.js.map → StickyPagination-GQKFFTjL.js.map} +1 -1
  114. package/dashboard/dist/assets/{StreamMessageDetail-D5v95pmz.js → StreamMessageDetail-BYzfjWe_.js} +2 -2
  115. package/dashboard/dist/assets/{StreamMessageDetail-D5v95pmz.js.map → StreamMessageDetail-BYzfjWe_.js.map} +1 -1
  116. package/dashboard/dist/assets/{SwimlaneTimeline-CUEf2R5R.js → SwimlaneTimeline-DLVmRrd-.js} +2 -2
  117. package/dashboard/dist/assets/{SwimlaneTimeline-CUEf2R5R.js.map → SwimlaneTimeline-DLVmRrd-.js.map} +1 -1
  118. package/dashboard/dist/assets/{TagInput-B_WQiuer.js → TagInput-CQg-TrV9.js} +2 -2
  119. package/dashboard/dist/assets/{TagInput-B_WQiuer.js.map → TagInput-CQg-TrV9.js.map} +1 -1
  120. package/dashboard/dist/assets/{TaskDetailPage-BJvKNwEe.js → TaskDetailPage-HzQpzp6D.js} +2 -2
  121. package/dashboard/dist/assets/{TaskDetailPage-BJvKNwEe.js.map → TaskDetailPage-HzQpzp6D.js.map} +1 -1
  122. package/dashboard/dist/assets/{TaskQueuePill-Lgn2obNU.js → TaskQueuePill-DyvtL8X4.js} +2 -2
  123. package/dashboard/dist/assets/{TaskQueuePill-Lgn2obNU.js.map → TaskQueuePill-DyvtL8X4.js.map} +1 -1
  124. package/dashboard/dist/assets/{TasksListPage-CM7BWh_h.js → TasksListPage-DpqevgTz.js} +2 -2
  125. package/dashboard/dist/assets/{TasksListPage-CM7BWh_h.js.map → TasksListPage-DpqevgTz.js.map} +1 -1
  126. package/dashboard/dist/assets/{TimeAgo-D1K7xKq5.js → TimeAgo-CftB8aJE.js} +2 -2
  127. package/dashboard/dist/assets/{TimeAgo-D1K7xKq5.js.map → TimeAgo-CftB8aJE.js.map} +1 -1
  128. package/dashboard/dist/assets/{TimestampCell-7G0echgP.js → TimestampCell-BSKj1jqT.js} +2 -2
  129. package/dashboard/dist/assets/{TimestampCell-7G0echgP.js.map → TimestampCell-BSKj1jqT.js.map} +1 -1
  130. package/dashboard/dist/assets/{ToolPill-uVqcbHPE.js → ToolPill-miuRcj1Q.js} +2 -2
  131. package/dashboard/dist/assets/{ToolPill-uVqcbHPE.js.map → ToolPill-miuRcj1Q.js.map} +1 -1
  132. package/dashboard/dist/assets/{ToolTestPanel-LxuJvURK.js → ToolTestPanel-DVQICZUQ.js} +2 -2
  133. package/dashboard/dist/assets/{ToolTestPanel-LxuJvURK.js.map → ToolTestPanel-DVQICZUQ.js.map} +1 -1
  134. package/dashboard/dist/assets/{TopicDetailPage-JvAX6rrR.js → TopicDetailPage-B2LAQDEg.js} +2 -2
  135. package/dashboard/dist/assets/{TopicDetailPage-JvAX6rrR.js.map → TopicDetailPage-B2LAQDEg.js.map} +1 -1
  136. package/dashboard/dist/assets/{TopicsPage-tFT2AcTz.js → TopicsPage-SwPAnN2C.js} +2 -2
  137. package/dashboard/dist/assets/{TopicsPage-tFT2AcTz.js.map → TopicsPage-SwPAnN2C.js.map} +1 -1
  138. package/dashboard/dist/assets/{UserName-Djz0nmaZ.js → UserName-Ce9gvlT5.js} +2 -2
  139. package/dashboard/dist/assets/{UserName-Djz0nmaZ.js.map → UserName-Ce9gvlT5.js.map} +1 -1
  140. package/dashboard/dist/assets/{WorkflowExecutionPage-f53hilbI.js → WorkflowExecutionPage-BI9NzeaH.js} +2 -2
  141. package/dashboard/dist/assets/{WorkflowExecutionPage-f53hilbI.js.map → WorkflowExecutionPage-BI9NzeaH.js.map} +1 -1
  142. package/dashboard/dist/assets/{WorkflowPill-IDjTRfQ8.js → WorkflowPill-BuNkWUVM.js} +2 -2
  143. package/dashboard/dist/assets/WorkflowPill-BuNkWUVM.js.map +1 -0
  144. package/dashboard/dist/assets/{WorkflowsDashboard-DM9Xe665.js → WorkflowsDashboard-CvWSgQdE.js} +2 -2
  145. package/dashboard/dist/assets/{WorkflowsDashboard-DM9Xe665.js.map → WorkflowsDashboard-CvWSgQdE.js.map} +1 -1
  146. package/dashboard/dist/assets/{WorkflowsOverview-CUGSrx9N.js → WorkflowsOverview-CjBWlwlH.js} +2 -2
  147. package/dashboard/dist/assets/{WorkflowsOverview-CUGSrx9N.js.map → WorkflowsOverview-CjBWlwlH.js.map} +1 -1
  148. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B1_yqxAw.js → YamlWorkflowDetailPage-Ds5o1UK9.js} +2 -2
  149. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B1_yqxAw.js.map → YamlWorkflowDetailPage-Ds5o1UK9.js.map} +1 -1
  150. package/dashboard/dist/assets/{YamlWorkflowsPage-NtGvqiu7.js → YamlWorkflowsPage-ChwvZS4Z.js} +2 -2
  151. package/dashboard/dist/assets/{YamlWorkflowsPage-NtGvqiu7.js.map → YamlWorkflowsPage-ChwvZS4Z.js.map} +1 -1
  152. package/dashboard/dist/assets/{agents-tML6AjDj.js → agents-A1U43853.js} +2 -2
  153. package/dashboard/dist/assets/{agents-tML6AjDj.js.map → agents-A1U43853.js.map} +1 -1
  154. package/dashboard/dist/assets/{bots-Cb0WTwhY.js → bots-CyzN6Uxi.js} +2 -2
  155. package/dashboard/dist/assets/{bots-Cb0WTwhY.js.map → bots-CyzN6Uxi.js.map} +1 -1
  156. package/dashboard/dist/assets/{capabilities-BGZogsi_.js → capabilities-BE1X5FVI.js} +2 -2
  157. package/dashboard/dist/assets/{capabilities-BGZogsi_.js.map → capabilities-BE1X5FVI.js.map} +1 -1
  158. package/dashboard/dist/assets/{controlplane-B7VJTlZD.js → controlplane-BrwK_MT8.js} +2 -2
  159. package/dashboard/dist/assets/{controlplane-B7VJTlZD.js.map → controlplane-BrwK_MT8.js.map} +1 -1
  160. package/dashboard/dist/assets/{escalation-Bl-SQV_u.js → escalation-DDdt7UdU.js} +2 -2
  161. package/dashboard/dist/assets/{escalation-Bl-SQV_u.js.map → escalation-DDdt7UdU.js.map} +1 -1
  162. package/dashboard/dist/assets/{escalation-columns-BlJOswRx.js → escalation-columns-D_zFY1zF.js} +2 -2
  163. package/dashboard/dist/assets/{escalation-columns-BlJOswRx.js.map → escalation-columns-D_zFY1zF.js.map} +1 -1
  164. package/dashboard/dist/assets/{index-DcbEIXit.js → index-6MALVAEY.js} +2 -2
  165. package/dashboard/dist/assets/{index-DcbEIXit.js.map → index-6MALVAEY.js.map} +1 -1
  166. package/dashboard/dist/assets/{index-CBv3UxF2.js → index-BNWKksZ6.js} +2 -2
  167. package/dashboard/dist/assets/{index-CBv3UxF2.js.map → index-BNWKksZ6.js.map} +1 -1
  168. package/dashboard/dist/assets/{index-DfDfJivY.js → index-BtrNxebh.js} +2 -2
  169. package/dashboard/dist/assets/{index-DfDfJivY.js.map → index-BtrNxebh.js.map} +1 -1
  170. package/dashboard/dist/assets/{index-BorpZbZA.js → index-C-rJQ-vB.js} +2 -2
  171. package/dashboard/dist/assets/{index-BorpZbZA.js.map → index-C-rJQ-vB.js.map} +1 -1
  172. package/dashboard/dist/assets/{index-Il_g7kw5.js → index-CGUBekEU.js} +2 -2
  173. package/dashboard/dist/assets/{index-Il_g7kw5.js.map → index-CGUBekEU.js.map} +1 -1
  174. package/dashboard/dist/assets/{index-Dgw1KKpq.js → index-CKXSKsVZ.js} +4 -4
  175. package/dashboard/dist/assets/{index-Dgw1KKpq.js.map → index-CKXSKsVZ.js.map} +1 -1
  176. package/dashboard/dist/assets/{index-Wny0bRgq.css → index-CZ6-l8_0.css} +1 -1
  177. package/dashboard/dist/assets/{index--WeZDfeN.js → index-D2dDPGNk.js} +2 -2
  178. package/dashboard/dist/assets/{index--WeZDfeN.js.map → index-D2dDPGNk.js.map} +1 -1
  179. package/dashboard/dist/assets/{index-0o71lRuY.js → index-D4U--3Xo.js} +2 -2
  180. package/dashboard/dist/assets/{index-0o71lRuY.js.map → index-D4U--3Xo.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-e97M6GoI.js → index-D4gAsCGh.js} +2 -2
  182. package/dashboard/dist/assets/{index-e97M6GoI.js.map → index-D4gAsCGh.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-SCrD3l-K.js → index-DEXouwBQ.js} +2 -2
  184. package/dashboard/dist/assets/{index-SCrD3l-K.js.map → index-DEXouwBQ.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-3A_5CL81.js → index-NnGsWGNS.js} +2 -2
  186. package/dashboard/dist/assets/{index-3A_5CL81.js.map → index-NnGsWGNS.js.map} +1 -1
  187. package/dashboard/dist/assets/index-U27KBbTV.js +9 -0
  188. package/dashboard/dist/assets/index-U27KBbTV.js.map +1 -0
  189. package/dashboard/dist/assets/index-fwHQSJCp.js +6 -0
  190. package/dashboard/dist/assets/index-fwHQSJCp.js.map +1 -0
  191. package/dashboard/dist/assets/{knowledge-CDzw4E6q.js → knowledge-B3ZIRTeu.js} +2 -2
  192. package/dashboard/dist/assets/{knowledge-CDzw4E6q.js.map → knowledge-B3ZIRTeu.js.map} +1 -1
  193. package/dashboard/dist/assets/{mcp-D_-NQtnG.js → mcp-BJjWiHdc.js} +2 -2
  194. package/dashboard/dist/assets/{mcp-D_-NQtnG.js.map → mcp-BJjWiHdc.js.map} +1 -1
  195. package/dashboard/dist/assets/{mcp-query-BqZXdf9A.js → mcp-query-ksjBztwq.js} +2 -2
  196. package/dashboard/dist/assets/{mcp-query-BqZXdf9A.js.map → mcp-query-ksjBztwq.js.map} +1 -1
  197. package/dashboard/dist/assets/{pipelines-CNLhgj8b.js → pipelines-DT1astmP.js} +2 -2
  198. package/dashboard/dist/assets/{pipelines-CNLhgj8b.js.map → pipelines-DT1astmP.js.map} +1 -1
  199. package/dashboard/dist/assets/{roles-CFD2eYap.js → roles-UboiQxXT.js} +2 -2
  200. package/dashboard/dist/assets/roles-UboiQxXT.js.map +1 -0
  201. package/dashboard/dist/assets/{tasks-DcSvF636.js → tasks-aL0K8WW3.js} +2 -2
  202. package/dashboard/dist/assets/{tasks-DcSvF636.js.map → tasks-aL0K8WW3.js.map} +1 -1
  203. package/dashboard/dist/assets/{topics-DI8TFSZv.js → topics-CZO06VJl.js} +2 -2
  204. package/dashboard/dist/assets/{topics-DI8TFSZv.js.map → topics-CZO06VJl.js.map} +1 -1
  205. package/dashboard/dist/assets/{useEventHooks-DcIgMDh3.js → useEventHooks-DlWkui_n.js} +2 -2
  206. package/dashboard/dist/assets/{useEventHooks-DcIgMDh3.js.map → useEventHooks-DlWkui_n.js.map} +1 -1
  207. package/dashboard/dist/assets/{useNamespace-C88ZxGoX.js → useNamespace-BBzCmCIN.js} +2 -2
  208. package/dashboard/dist/assets/{useNamespace-C88ZxGoX.js.map → useNamespace-BBzCmCIN.js.map} +1 -1
  209. package/dashboard/dist/assets/{useYamlActivityEvents-D2-yVjJ7.js → useYamlActivityEvents-ZS6wRSSc.js} +2 -2
  210. package/dashboard/dist/assets/{useYamlActivityEvents-D2-yVjJ7.js.map → useYamlActivityEvents-ZS6wRSSc.js.map} +1 -1
  211. package/dashboard/dist/assets/{users-C0WV36X8.js → users-Dzh04pRB.js} +2 -2
  212. package/dashboard/dist/assets/{users-C0WV36X8.js.map → users-Dzh04pRB.js.map} +1 -1
  213. package/dashboard/dist/assets/{vendor-icons-CEWCGPeJ.js → vendor-icons-BaQqUm-e.js} +2 -2
  214. package/dashboard/dist/assets/{vendor-icons-CEWCGPeJ.js.map → vendor-icons-BaQqUm-e.js.map} +1 -1
  215. package/dashboard/dist/assets/{workflows-CkPv7xk-.js → workflows-BTkHs6VT.js} +2 -2
  216. package/dashboard/dist/assets/workflows-BTkHs6VT.js.map +1 -0
  217. package/dashboard/dist/assets/{yaml-workflows-BjrMQLTK.js → yaml-workflows-Df8u3lgx.js} +2 -2
  218. package/dashboard/dist/assets/{yaml-workflows-BjrMQLTK.js.map → yaml-workflows-Df8u3lgx.js.map} +1 -1
  219. package/dashboard/dist/index.html +3 -3
  220. package/docs/api/http/escalations.md +6 -6
  221. package/docs/api/http/roles.md +6 -0
  222. package/docs/api/http/workflows.md +2 -1
  223. package/docs/api/mcp/admin.md +15 -7
  224. package/docs/api/sdk/escalations.md +5 -3
  225. package/docs/api/sdk/roles.md +7 -1
  226. package/docs/api/sdk/workflows.md +3 -2
  227. package/docs/architecture.md +2 -2
  228. package/docs/dashboard.md +11 -9
  229. package/docs/data.md +2 -0
  230. package/docs/iam.md +3 -3
  231. package/docs/operations.md +16 -3
  232. package/docs/workflows.md +7 -5
  233. package/package.json +2 -2
  234. package/dashboard/dist/assets/OperationsPage-BCr21p8I.js +0 -2
  235. package/dashboard/dist/assets/OperationsPage-BCr21p8I.js.map +0 -1
  236. package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js +0 -11
  237. package/dashboard/dist/assets/RoleDetailPage-DS37tJhq.js.map +0 -1
  238. package/dashboard/dist/assets/WorkflowPill-IDjTRfQ8.js.map +0 -1
  239. package/dashboard/dist/assets/index-D0-8byNu.js +0 -6
  240. package/dashboard/dist/assets/index-D0-8byNu.js.map +0 -1
  241. package/dashboard/dist/assets/index-TiKh2Ctj.js +0 -9
  242. package/dashboard/dist/assets/index-TiKh2Ctj.js.map +0 -1
  243. package/dashboard/dist/assets/roles-CFD2eYap.js.map +0 -1
  244. package/dashboard/dist/assets/workflows-CkPv7xk-.js.map +0 -1
@@ -1,2 +1,2 @@
1
- import{u as n,b as t,c as u}from"./vendor-query-B2UbickB.js";import{d as s}from"./index-Dgw1KKpq.js";function f(){return n({queryKey:["activeWorkers"],queryFn:async()=>(await s("/workflows/workers")).workers})}function w(){return n({queryKey:["discoveredWorkflows"],queryFn:async()=>(await s("/workflows/discovered")).workflows})}function l(){return n({queryKey:["workflowConfigs"],queryFn:async()=>(await s("/workflows/config")).workflows})}function d(){return n({queryKey:["cronStatus"],queryFn:async()=>(await s("/workflows/cron/status")).schedules})}function k(e){return n({queryKey:["workflowExecution",e],queryFn:()=>s(`/workflow-states/${e}/execution`),enabled:!!e})}function m(e,o){const r=new URLSearchParams;return e.limit&&r.set("limit",String(e.limit)),e.offset!==void 0&&r.set("offset",String(e.offset)),e.entity&&r.set("entity",e.entity),e.search&&r.set("search",e.search),e.status&&r.set("status",e.status),e.sort_by&&r.set("sort_by",e.sort_by),e.order&&r.set("order",e.order),e.registered&&r.set("registered",e.registered),e.namespace&&r.set("namespace",e.namespace),n({queryKey:["jobs",e],queryFn:()=>s(`/workflow-states/jobs?${r}`),enabled:(o==null?void 0:o.enabled)??!0})}function q(){const e=t();return u({mutationFn:o=>s(`/workflows/${o}/terminate`,{method:"POST"}),onSuccess:(o,r)=>{e.invalidateQueries({queryKey:["workflowExecution",r],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}function g(){const e=t();return u({mutationFn:({workflow_type:o,...r})=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"PUT",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function h(){const e=t();return u({mutationFn:o=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function b(){const e=t();return u({mutationFn:({workflowType:o,data:r,metadata:i,execute_as:a})=>s(`/workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:r,metadata:i,...a?{execute_as:a}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}export{k as a,m as b,b as c,w as d,d as e,q as f,f as g,h,g as i,l as u};
2
- //# sourceMappingURL=workflows-CkPv7xk-.js.map
1
+ import{u as n,b as t,c as u}from"./vendor-query-B2UbickB.js";import{d as s}from"./index-CKXSKsVZ.js";function f(){return n({queryKey:["activeWorkers"],queryFn:async()=>(await s("/workflows/workers")).workers})}function w(){return n({queryKey:["discoveredWorkflows"],queryFn:async()=>(await s("/workflows/discovered")).workflows})}function l(){return n({queryKey:["workflowConfigs"],queryFn:async()=>(await s("/workflows/config")).workflows})}function d(){return n({queryKey:["cronStatus"],queryFn:async()=>(await s("/workflows/cron/status")).schedules})}function k(e){return n({queryKey:["workflowExecution",e],queryFn:()=>s(`/workflow-states/${e}/execution`),enabled:!!e})}function m(e,o){const r=new URLSearchParams;return e.limit&&r.set("limit",String(e.limit)),e.offset!==void 0&&r.set("offset",String(e.offset)),e.entity&&r.set("entity",e.entity),e.search&&r.set("search",e.search),e.status&&r.set("status",e.status),e.sort_by&&r.set("sort_by",e.sort_by),e.order&&r.set("order",e.order),e.registered&&r.set("registered",e.registered),e.namespace&&r.set("namespace",e.namespace),n({queryKey:["jobs",e],queryFn:()=>s(`/workflow-states/jobs?${r}`),enabled:(o==null?void 0:o.enabled)??!0})}function q(){const e=t();return u({mutationFn:o=>s(`/workflows/${o}/terminate`,{method:"POST"}),onSuccess:(o,r)=>{e.invalidateQueries({queryKey:["workflowExecution",r],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}function g(){const e=t();return u({mutationFn:({workflow_type:o,...r})=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"PUT",body:JSON.stringify(r)}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function h(){const e=t();return u({mutationFn:o=>s(`/workflows/${encodeURIComponent(o)}/config`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["workflowConfigs"],refetchType:"all"})}})}function b(){const e=t();return u({mutationFn:({workflowType:o,data:r,metadata:i,execute_as:a})=>s(`/workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:r,metadata:i,...a?{execute_as:a}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["tasks"],refetchType:"all"}),e.invalidateQueries({queryKey:["jobs"],refetchType:"all"})}})}export{k as a,m as b,b as c,w as d,d as e,q as f,f as g,h,g as i,l as u};
2
+ //# sourceMappingURL=workflows-BTkHs6VT.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflows-BTkHs6VT.js","sources":["../../src/api/workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { ActiveWorker, CronScheduleEntry, DiscoveredWorkflow, LTJob, LTWorkflowConfig, WorkflowExecution } from './types';\n\nexport function useActiveWorkers() {\n return useQuery<ActiveWorker[]>({\n queryKey: ['activeWorkers'],\n queryFn: async () => {\n const res = await apiFetch<{ workers: ActiveWorker[] }>('/workflows/workers');\n return res.workers;\n },\n });\n}\n\nexport function useDiscoveredWorkflows() {\n return useQuery<DiscoveredWorkflow[]>({\n queryKey: ['discoveredWorkflows'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: DiscoveredWorkflow[] }>('/workflows/discovered');\n return res.workflows;\n },\n });\n}\n\nexport function useWorkflowConfigs() {\n return useQuery<LTWorkflowConfig[]>({\n queryKey: ['workflowConfigs'],\n queryFn: async () => {\n const res = await apiFetch<{ workflows: LTWorkflowConfig[] }>('/workflows/config');\n return res.workflows;\n },\n });\n}\n\nexport function useCronStatus() {\n return useQuery<CronScheduleEntry[]>({\n queryKey: ['cronStatus'],\n queryFn: async () => {\n const res = await apiFetch<{ schedules: CronScheduleEntry[] }>('/workflows/cron/status');\n return res.schedules;\n },\n });\n}\n\nexport function useWorkflowExecution(workflowId: string) {\n return useQuery<WorkflowExecution>({\n queryKey: ['workflowExecution', workflowId],\n queryFn: () =>\n apiFetch(`/workflow-states/${workflowId}/execution`),\n enabled: !!workflowId,\n });\n}\n\nexport function useWorkflowState(workflowId: string) {\n return useQuery<{ workflow_id: string; state: Record<string, unknown> }>({\n queryKey: ['workflowState', workflowId],\n queryFn: () => apiFetch(`/workflow-states/${workflowId}/state`),\n enabled: !!workflowId,\n });\n}\n\nexport function useJobs(filters: {\n limit?: number;\n offset?: number;\n entity?: string;\n search?: string;\n status?: string;\n sort_by?: string;\n order?: string;\n registered?: string;\n namespace?: string;\n}, options?: { enabled?: boolean }) {\n const params = new URLSearchParams();\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n if (filters.entity) params.set('entity', filters.entity);\n if (filters.search) params.set('search', filters.search);\n if (filters.status) params.set('status', filters.status);\n if (filters.sort_by) params.set('sort_by', filters.sort_by);\n if (filters.order) params.set('order', filters.order);\n if (filters.registered) params.set('registered', filters.registered);\n if (filters.namespace) params.set('namespace', filters.namespace);\n\n return useQuery<{ jobs: LTJob[]; total: number }>({\n queryKey: ['jobs', filters],\n queryFn: () => apiFetch(`/workflow-states/jobs?${params}`),\n enabled: options?.enabled ?? true,\n });\n}\n\nexport function useTerminateWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (workflowId: string) =>\n apiFetch(`/workflows/${workflowId}/terminate`, { method: 'POST' }),\n onSuccess: (_data, workflowId) => {\n queryClient.invalidateQueries({ queryKey: ['workflowExecution', workflowId], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpsertWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n {\n workflow_type: string;\n description?: string | null;\n\n invocable?: boolean;\n certified?: boolean;\n task_queue?: string | null;\n default_role?: string;\n roles?: string[];\n invocation_roles?: string[];\n consumes?: string[];\n envelope_schema?: Record<string, unknown> | null;\n resolver_schema?: Record<string, unknown> | null;\n cron_schedule?: string | null;\n execute_as?: string | null;\n }\n >({\n mutationFn: ({ workflow_type, ...body }) =>\n apiFetch(`/workflows/${encodeURIComponent(workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify(body),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteWorkflowConfig() {\n const queryClient = useQueryClient();\n return useMutation<{ deleted: boolean; workflow_type: string }, Error, string>({\n mutationFn: (workflowType) =>\n apiFetch(`/workflows/${encodeURIComponent(workflowType)}/config`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n },\n });\n}\n\nexport function useSetCronSchedule() {\n const queryClient = useQueryClient();\n return useMutation<\n LTWorkflowConfig,\n Error,\n { config: LTWorkflowConfig; cron_schedule: string | null; envelope_schema?: Record<string, unknown> | null }\n >({\n mutationFn: ({ config, cron_schedule, envelope_schema }) =>\n apiFetch(`/workflows/${encodeURIComponent(config.workflow_type)}/config`, {\n method: 'PUT',\n body: JSON.stringify({\n ...config,\n cron_schedule,\n ...(envelope_schema !== undefined ? { envelope_schema } : {}),\n }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['workflowConfigs'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['cronStatus'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeWorkflow() {\n const queryClient = useQueryClient();\n return useMutation<\n { workflowId: string; message: string },\n Error,\n { workflowType: string; data: Record<string, unknown>; metadata?: Record<string, unknown>; execute_as?: string }\n >({\n mutationFn: ({ workflowType, data, metadata, execute_as }) =>\n apiFetch(`/workflows/${workflowType}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, metadata, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['tasks'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['jobs'], refetchType: 'all' });\n },\n });\n}\n"],"names":["useActiveWorkers","useQuery","apiFetch","useDiscoveredWorkflows","useWorkflowConfigs","useCronStatus","useWorkflowExecution","workflowId","useJobs","filters","options","params","useTerminateWorkflow","queryClient","useQueryClient","useMutation","_data","useUpsertWorkflowConfig","workflow_type","body","useDeleteWorkflowConfig","workflowType","useInvokeWorkflow","data","metadata","execute_as"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-Dgw1KKpq.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
- //# sourceMappingURL=yaml-workflows-BjrMQLTK.js.map
1
+ import{u as l,b as a,c as s}from"./vendor-query-B2UbickB.js";import{d as r}from"./index-CKXSKsVZ.js";function f(e={}){const o=new URLSearchParams;return e.status&&o.set("status",e.status),e.graph_topic&&o.set("graph_topic",e.graph_topic),e.app_id&&o.set("app_id",e.app_id),e.search&&o.set("search",e.search),e.set_id&&o.set("set_id",e.set_id),e.limit&&o.set("limit",String(e.limit)),e.offset!==void 0&&o.set("offset",String(e.offset)),l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows?${o}`)})}function m(){return l({queryKey:["yamlWorkflowAppIds"],queryFn:()=>r("/yaml-workflows/app-ids")})}function c(e){return l({queryKey:["yamlWorkflows",e],queryFn:()=>r(`/yaml-workflows/${e}`),enabled:!!e})}function w(){const e=a();return s({mutationFn:o=>r("/yaml-workflows",{method:"POST",body:JSON.stringify(o)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function k(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/deploy`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function p(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/activate`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function d(){const e=a();return s({mutationFn:({id:o,data:t,sync:n,execute_as:u})=>r(`/yaml-workflows/${o}/invoke`,{method:"POST",body:JSON.stringify({data:t,sync:n,...u?{execute_as:u}:{}})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function h(){const e=a();return s({mutationFn:({id:o,task_queue:t,compilation_feedback:n})=>r(`/yaml-workflows/${o}/regenerate`,{method:"POST",body:JSON.stringify({task_queue:t,compilation_feedback:n})}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function q(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/archive`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function W(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}/restore`,{method:"POST"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"}),e.invalidateQueries({queryKey:["yamlWorkflow"],refetchType:"all"})}})}function S(){const e=a();return s({mutationFn:({id:o,...t})=>r(`/yaml-workflows/${o}`,{method:"PUT",body:JSON.stringify(t)}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function v(){const e=a();return s({mutationFn:o=>r(`/yaml-workflows/${o}`,{method:"DELETE"}),onSuccess:()=>{e.invalidateQueries({queryKey:["yamlWorkflows"],refetchType:"all"})}})}function T(e){return l({queryKey:["yamlWorkflows",e,"versions"],queryFn:()=>r(`/yaml-workflows/${e}/versions`),enabled:!!e})}function F(e,o){return l({queryKey:["yamlWorkflows",e,"versions",o],queryFn:()=>r(`/yaml-workflows/${e}/versions/${o}`),enabled:!!e&&o!==null})}export{m as a,S as b,c,T as d,k as e,p as f,q as g,W as h,v as i,h as j,F as k,d as l,w as m,f as u};
2
+ //# sourceMappingURL=yaml-workflows-Df8u3lgx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"yaml-workflows-BjrMQLTK.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
1
+ {"version":3,"file":"yaml-workflows-Df8u3lgx.js","sources":["../../src/api/yaml-workflows.ts"],"sourcesContent":["import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\nimport { apiFetch } from './client';\nimport type { LTYamlWorkflowRecord, LTYamlWorkflowStatus, LTYamlWorkflowVersion } from './types';\n\ninterface YamlWorkflowListResponse {\n workflows: LTYamlWorkflowRecord[];\n total: number;\n}\n\ninterface YamlWorkflowFilters {\n status?: LTYamlWorkflowStatus;\n graph_topic?: string;\n app_id?: string;\n search?: string;\n set_id?: string;\n limit?: number;\n offset?: number;\n}\n\nexport function useYamlWorkflows(filters: YamlWorkflowFilters = {}) {\n const params = new URLSearchParams();\n if (filters.status) params.set('status', filters.status);\n if (filters.graph_topic) params.set('graph_topic', filters.graph_topic);\n if (filters.app_id) params.set('app_id', filters.app_id);\n if (filters.search) params.set('search', filters.search);\n if (filters.set_id) params.set('set_id', filters.set_id);\n if (filters.limit) params.set('limit', String(filters.limit));\n if (filters.offset !== undefined) params.set('offset', String(filters.offset));\n\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', filters],\n queryFn: () => apiFetch(`/yaml-workflows?${params}`),\n });\n}\n\nexport function useYamlWorkflowAppIds() {\n return useQuery<{ app_ids: string[] }>({\n queryKey: ['yamlWorkflowAppIds'],\n queryFn: () => apiFetch('/yaml-workflows/app-ids'),\n });\n}\n\nexport function useYamlWorkflowByTopic(graphTopic: string | undefined, appId?: string) {\n return useQuery<YamlWorkflowListResponse>({\n queryKey: ['yamlWorkflows', 'byTopic', graphTopic, appId],\n queryFn: () => {\n const params = new URLSearchParams({ graph_topic: graphTopic!, limit: '1' });\n if (appId) params.set('app_id', appId);\n return apiFetch(`/yaml-workflows?${params}`);\n },\n enabled: !!graphTopic,\n });\n}\n\nexport function useYamlWorkflow(id: string) {\n return useQuery<LTYamlWorkflowRecord>({\n queryKey: ['yamlWorkflows', id],\n queryFn: () => apiFetch(`/yaml-workflows/${id}`),\n enabled: !!id,\n });\n}\n\nexport function useCreateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (input: {\n workflow_id: string;\n task_queue: string;\n workflow_name: string;\n name: string;\n description?: string;\n app_id?: string;\n subscribes?: string;\n tags?: string[];\n compilation_feedback?: string;\n }) =>\n apiFetch<LTYamlWorkflowRecord>('/yaml-workflows', {\n method: 'POST',\n body: JSON.stringify(input),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeployYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/deploy`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useActivateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/activate`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useInvokeYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, data, sync, execute_as }: { id: string; data: Record<string, unknown>; sync?: boolean; execute_as?: string }) =>\n apiFetch<{ result?: unknown; job_id?: string }>(`/yaml-workflows/${id}/invoke`, {\n method: 'POST',\n body: JSON.stringify({ data, sync, ...(execute_as ? { execute_as } : {}) }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRegenerateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, task_queue, compilation_feedback }: { id: string; task_queue?: string; compilation_feedback?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/regenerate`, {\n method: 'POST',\n body: JSON.stringify({ task_queue, compilation_feedback }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useArchiveYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/archive`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useRestoreYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/restore`, {\n method: 'POST',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflow'], refetchType: 'all' });\n },\n });\n}\n\nexport function useUpdateYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, ...updates }: { id: string; yaml_content?: string; name?: string; description?: string; input_schema?: Record<string, unknown>; output_schema?: Record<string, unknown>; tags?: string[]; app_id?: string; graph_topic?: string }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}`, {\n method: 'PUT',\n body: JSON.stringify(updates),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useDeleteYamlWorkflow() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<{ deleted: boolean }>(`/yaml-workflows/${id}`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Cron scheduling ─────────────────────────────────────────────\n\nexport function useSetYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: ({ id, cron_schedule, cron_envelope, execute_as }: {\n id: string;\n cron_schedule: string;\n cron_envelope?: Record<string, unknown> | null;\n execute_as?: string | null;\n }) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'PUT',\n body: JSON.stringify({ cron_schedule, cron_envelope, execute_as }),\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\nexport function useClearYamlCron() {\n const queryClient = useQueryClient();\n return useMutation({\n mutationFn: (id: string) =>\n apiFetch<LTYamlWorkflowRecord>(`/yaml-workflows/${id}/cron`, {\n method: 'DELETE',\n }),\n onSuccess: () => {\n queryClient.invalidateQueries({ queryKey: ['yamlWorkflows'], refetchType: 'all' });\n },\n });\n}\n\n// ── Version history ─────────────────────────────────────────────\n\nexport function useYamlWorkflowVersions(id: string) {\n return useQuery<{ versions: LTYamlWorkflowVersion[]; total: number }>({\n queryKey: ['yamlWorkflows', id, 'versions'],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions`),\n enabled: !!id,\n });\n}\n\nexport function useYamlWorkflowVersion(id: string, version: number | null) {\n return useQuery<LTYamlWorkflowVersion>({\n queryKey: ['yamlWorkflows', id, 'versions', version],\n queryFn: () => apiFetch(`/yaml-workflows/${id}/versions/${version}`),\n enabled: !!id && version !== null,\n });\n}\n"],"names":["useYamlWorkflows","filters","params","useQuery","apiFetch","useYamlWorkflowAppIds","useYamlWorkflow","id","useCreateYamlWorkflow","queryClient","useQueryClient","useMutation","input","useDeployYamlWorkflow","useActivateYamlWorkflow","useInvokeYamlWorkflow","data","sync","execute_as","useRegenerateYamlWorkflow","task_queue","compilation_feedback","useArchiveYamlWorkflow","useRestoreYamlWorkflow","useUpdateYamlWorkflow","updates","useDeleteYamlWorkflow","useYamlWorkflowVersions","useYamlWorkflowVersion","version"],"mappings":"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"}
@@ -8,11 +8,11 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com" />
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
11
- <script type="module" crossorigin src="./assets/index-Dgw1KKpq.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-CKXSKsVZ.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/vendor-query-B2UbickB.js">
13
13
  <link rel="modulepreload" crossorigin href="./assets/vendor-react-CXumBFUA.js">
14
- <link rel="modulepreload" crossorigin href="./assets/vendor-icons-CEWCGPeJ.js">
15
- <link rel="stylesheet" crossorigin href="./assets/index-Wny0bRgq.css">
14
+ <link rel="modulepreload" crossorigin href="./assets/vendor-icons-BaQqUm-e.js">
15
+ <link rel="stylesheet" crossorigin href="./assets/index-CZ6-l8_0.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -445,7 +445,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
445
445
  "pending": 12,
446
446
  "claimed": 3,
447
447
  "resolved": 45,
448
- "in_arrears": 2,
448
+ "priority_count": 2,
449
449
  "throughput_pct": 112.5,
450
450
  "wait": {
451
451
  "p99": 18.3,
@@ -472,7 +472,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
472
472
  | `pending` | `number` | Escalations currently pending (real-time) |
473
473
  | `claimed` | `number` | Escalations actively claimed (real-time) |
474
474
  | `resolved` | `number` | Escalations resolved within the selected period |
475
- | `in_arrears` | `number` | Pending escalations that have exceeded the role's `sla_minutes` target |
475
+ | `priority_count` | `number` | Pending, unclaimed escalations past the role's age threshold — the Pace Board rebalance signal |
476
476
  | `throughput_pct` | `number \| null` | `resolved / (target_per_hour × period_hours) × 100`. `null` when the role has no `target_per_hour` set |
477
477
  | `wait.p99` | `number \| null` | 99th-percentile wait time in minutes (creation → first claim) within the period. `null` when no resolved items |
478
478
  | `wait.p50` | `number \| null` | Median wait time in minutes |
@@ -486,7 +486,7 @@ RBAC: `superadmin` sees all stations; other roles see only stations for their as
486
486
  **Notes:**
487
487
  - `pending` and `claimed` reflect the live queue state, not the selected period.
488
488
  - `throughput_pct` above 100 means the station resolved more than its target — ahead of schedule. Below 100 means behind.
489
- - `in_arrears` counts items whose age exceeds the role's `sla_minutes`; it is 0 when `sla_minutes` is not configured for the role.
489
+ - `priority_count` measures age from the role's `priority_facet` metadata timestamp (`created_at` when unset) against `priority_threshold_minutes` (`sla_minutes` when unset); it is 0 when neither threshold is configured. Claimed items are excluded. With a facet configured, items missing the key or holding an unparseable value are not counted.
490
490
  - Time values are in decimal minutes.
491
491
 
492
492
  **Example:** Fetch station metrics for the last hour:
@@ -667,7 +667,7 @@ Reassign multiple escalations to a different role. Requires admin or superadmin
667
667
  POST /api/escalations/bulk-triage
668
668
  ```
669
669
 
670
- Resolve multiple escalations and start AI triage workflows (mcpTriage) for each. Requires admin or superadmin permission for the escalation roles.
670
+ Resolve multiple escalations and start AI triage workflows (mcpTriage) for each. Rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from `triaged` — settle those individually via `POST /:id/resolve`, which carries the workflow's wake. Requires admin or superadmin permission for the escalation roles.
671
671
 
672
672
  **Request body:**
673
673
 
@@ -1044,7 +1044,7 @@ Single atomic query finds the pending escalation by metadata, auto-claims if unc
1044
1044
  POST /api/escalations/resolve-by-ids
1045
1045
  ```
1046
1046
 
1047
- Resolve many escalations in one guarded statement — the set-based sibling of `POST /:id/resolve`. Used for bookkeeping rows that are woken collectively (it does not deliver a per-row signal). RBAC: a scoped caller may only resolve rows whose role they hold (global principals are unrestricted).
1047
+ Resolve many escalations in one guarded statement — the set-based sibling of `POST /:id/resolve`. Used for bookkeeping rows that are woken collectively (it does not deliver a per-row signal). The store enforces this: rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from the response — settle those via `POST /:id/resolve`, which carries the wake. RBAC: a scoped caller may only resolve rows whose role they hold (global principals are unrestricted).
1048
1048
 
1049
1049
  | Field | Type | Required | Description |
1050
1050
  |-------|------|----------|-------------|
@@ -1052,7 +1052,7 @@ Resolve many escalations in one guarded statement — the set-based sibling of `
1052
1052
  | `resolverPayload` | `object` | yes | Payload applied to every row |
1053
1053
  | `metadata` | `object` | no | Outcome patch merged into each row's GIN-indexed metadata |
1054
1054
 
1055
- **Response 200:** `{ "resolved": <count>, "escalationIds": [...] }` — only the rows that were still `pending` are resolved and returned.
1055
+ **Response 200:** `{ "resolved": <count>, "escalationIds": [...] }` — only still-`pending` rows without a `signal_key` are resolved and returned.
1056
1056
 
1057
1057
  ## Faceted search
1058
1058
 
@@ -250,6 +250,8 @@ Returns all roles with metadata and usage counts.
250
250
  "sla_minutes": 30,
251
251
  "target_per_hour": 20,
252
252
  "worker_count": 4,
253
+ "priority_threshold_minutes": null,
254
+ "priority_facet": null,
253
255
  "user_count": 5,
254
256
  "chain_count": 2,
255
257
  "workflow_count": 3
@@ -270,6 +272,8 @@ Returns all roles with metadata and usage counts.
270
272
  | `sla_minutes` | `number \| null` | Target resolution time in minutes (capacity setting) |
271
273
  | `target_per_hour` | `number \| null` | Intended throughput — items resolved per hour (capacity setting) |
272
274
  | `worker_count` | `number \| null` | Capacity at this station — staff or machine count (capacity setting) |
275
+ | `priority_threshold_minutes` | `number \| null` | Max age (minutes) before a pending unclaimed item counts toward `priority_count` in station metrics; falls back to `sla_minutes` |
276
+ | `priority_facet` | `string \| null` | Escalation metadata key holding the age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`); falls back to `created_at` |
273
277
  | `user_count` | `number` | Number of users assigned this role |
274
278
  | `chain_count` | `number` | Number of escalation chain entries referencing this role |
275
279
  | `workflow_count` | `number` | Number of workflow configs that reference this role |
@@ -366,6 +370,8 @@ When the update changes `form_schema` or `metadata_schema`, the new pair is snap
366
370
  | `sla_minutes` | `number \| null` | SLA target in minutes |
367
371
  | `target_per_hour` | `number \| null` | Throughput target (items per hour) |
368
372
  | `worker_count` | `number \| null` | Station capacity |
373
+ | `priority_threshold_minutes` | `number \| null` | Priority age threshold in minutes; falls back to `sla_minutes` |
374
+ | `priority_facet` | `string \| null` | Metadata key for the priority age origin (letters, numbers, underscores); falls back to `created_at` |
369
375
  | `upstream_roles` | `string[] \| null` | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear). Every entry must name an existing role other than this one. Distinct from `parent_role`, which places the role in its own sequence. |
370
376
  | `change_summary` | `string` | Label recorded on the schema version snapshot when this update changes a schema field |
371
377
 
@@ -130,10 +130,11 @@ PUT /api/workflows/:type/config
130
130
  | Field | Type | Default | Description |
131
131
  |-------|------|---------|-------------|
132
132
  | `invocable` | `boolean` | `false` | Allow this workflow to be started via `POST /api/workflows/:type/invoke` |
133
+ | `certified` | `boolean` | derived | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
133
134
  | `task_queue` | `string \| null` | `null` | Task queue name (required for invocable workflows) |
134
135
  | `default_role` | `string` | `"reviewer"` | Role assigned to escalations when the workflow doesn't specify one |
135
136
  | `description` | `string \| null` | `null` | Human-readable description |
136
- | `roles` | `string[]` | `[]` | Roles allowed to claim escalations for this workflow |
137
+ | `roles` | `string[]` | `[]` | Interceptor default for who can claim interceptor-raised escalations. Escalations raised in workflow code choose their own role, whose versioned schema takes precedence. |
137
138
  | `invocation_roles` | `string[]` | `[]` | Roles allowed to invoke via API. Empty = any authenticated user. |
138
139
  | `consumes` | `string[]` | `[]` | Workflow types whose completed data this workflow receives via `envelope.lt.providers` |
139
140
  | `execute_as` | `string \| null` | `null` | Service account `external_id` to run as (overrides invoker identity) |
@@ -15,7 +15,7 @@ Each tool below is marked **Read-safe**. A service-account key scoped `mcp:read`
15
15
 
16
16
  ## Compile Hints
17
17
 
18
- Admin tools modify system configuration. certify_workflow and decertify_workflow change interceptor behavior.
18
+ Admin tools modify system configuration. upsert_workflow_config's `certified` flag and delete_workflow_config change interceptor behavior.
19
19
 
20
20
  ## Tasks
21
21
 
@@ -231,7 +231,10 @@ Release all escalation claims that exceeded their lock duration.
231
231
 
232
232
  ### bulk_triage
233
233
 
234
- Resolve escalations for triage and start mcpTriage workflows.
234
+ Resolve escalations for triage and start mcpTriage workflows. Rows backing a
235
+ live `condition()` waiter (`signal_key` set) stay `pending` and are excluded
236
+ from the result — settle those with the targeted resolve, which carries the
237
+ workflow's wake.
235
238
 
236
239
  | | |
237
240
  |---|---|
@@ -400,11 +403,12 @@ Create or replace a workflow configuration (certify). Activates the interceptor
400
403
  |-------|------|----------|-------------|
401
404
  | workflow_type | string | Yes | Workflow type identifier |
402
405
  | invocable | boolean | No | Whether the workflow can be invoked externally |
406
+ | certified | boolean | No | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
403
407
  | task_queue | string | No | HotMesh task queue |
404
408
  | default_role | string | No | Default escalation role |
405
409
  | description | string | No | Workflow description |
406
410
  | execute_as | string | No | Execution identity |
407
- | roles | string[] | No | Allowed roles |
411
+ | roles | string[] | No | Interceptor default for who resolves interceptor-raised escalations |
408
412
  | invocation_roles | string[] | No | Roles allowed to invoke |
409
413
  | consumes | string[] | No | Event topics consumed |
410
414
  | tool_tags | string[] | No | Tool tags for routing |
@@ -412,7 +416,7 @@ Create or replace a workflow configuration (certify). Activates the interceptor
412
416
 
413
417
  ### delete_workflow_config
414
418
 
415
- De-certify a workflow by removing its config entry.
419
+ Unregister a workflow by deleting its config entry. To demote certified → registered while keeping the registration, use `upsert_workflow_config` with `certified: false`.
416
420
 
417
421
  | | |
418
422
  |---|---|
@@ -745,6 +749,8 @@ Update a role's metadata: display name, description, form schema, metadata schem
745
749
  | `sla_minutes` | `number \| null` | No | Target resolution time in minutes |
746
750
  | `target_per_hour` | `number \| null` | No | Throughput goal (items resolved per hour) |
747
751
  | `worker_count` | `number \| null` | No | Station capacity (staff or machines) |
752
+ | `priority_threshold_minutes` | `number \| null` | No | Priority age threshold in minutes; falls back to `sla_minutes` |
753
+ | `priority_facet` | `string \| null` | No | Metadata key for the priority age origin (ISO 8601 UTC); falls back to `created_at` |
748
754
  | `upstream_roles` | `string[] \| null` | No | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear) |
749
755
  | `change_summary` | `string` | No | Label recorded on the schema version snapshot when this update changes a schema field |
750
756
 
@@ -1158,10 +1164,12 @@ happened and where to look, not how to "fix" a job.
1158
1164
  **Read this first — what is and isn't a problem.** A workflow suspended at a
1159
1165
  `condition()` / `waitFor()` / `sleepFor()` can sit idle for days legitimately,
1160
1166
  and HotMesh only bumps `updated_at` when a job's status changes. A frozen
1161
- `updated_at` is therefore the *normal* signature of a wait, **not** a fault. The
1167
+ `updated_at` is therefore the *normal* signature of a wait, **not** a fault. A
1168
+ reservation whose holder died self-heals: the message redelivers once the
1169
+ reclaim window lapses (~90s worst case) and the activity re-executes. The
1162
1170
  genuinely broken signals are: a dead-lettered message (retries exhausted), a
1163
- reservation leak (claimed but never ACK'd past the reclaim window), and a
1164
- suspended waiter with **no** escalation row.
1171
+ reservation still held past several reclaim windows, and a suspended waiter
1172
+ with **no** escalation row.
1165
1173
 
1166
1174
  **Recommended flow:** start fleet-wide with `find_orphaned_signals` (the
1167
1175
  genuinely-broken case) or `find_stalled_jobs` (candidates worth a look), then run
@@ -635,6 +635,8 @@ Trigger AI triage for multiple escalations.
635
635
 
636
636
  Resolves each escalation and starts a triage workflow that uses MCP tools to analyze and potentially auto-resolve the issue.
637
637
 
638
+ Rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from `triaged` — their resolution must carry the workflow's wake, which only the targeted `resolve` delivers. Settle those individually with `resolve` or `cancel`.
639
+
638
640
  ```typescript
639
641
  const result = await lt.escalations.bulkTriage({
640
642
  ids: ['esc_1', 'esc_2'],
@@ -803,7 +805,7 @@ const result = await lt.escalations.resolveByMetadata({
803
805
 
804
806
  ## resolveByIds
805
807
 
806
- Resolve a set of escalations by id in one guarded statement (the set-based sibling of `resolve`). For bookkeeping rows woken collectively — it does not deliver a per-row signal. RBAC: a scoped caller may only resolve rows whose role they hold.
808
+ Resolve a set of escalations by id in one guarded statement (the set-based sibling of `resolve`). For bookkeeping rows woken collectively — it does not deliver a per-row signal, and the store enforces that: rows backing a live `condition()` waiter (`signal_key` set) stay `pending` and are excluded from the result. Settle waiter rows individually with `resolve`, which carries the wake. RBAC: a scoped caller may only resolve rows whose role they hold.
807
809
 
808
810
  ```typescript
809
811
  const result = await lt.escalations.resolveByIds({
@@ -911,13 +913,13 @@ interface StationMetric {
911
913
  pending: number; // currently queued (status = pending and not claimed)
912
914
  claimed: number; // active — claimed and assignment not expired
913
915
  resolved: number; // resolved within the lookback period
914
- in_arrears: number; // pending items older than sla_minutes
916
+ priority_count: number; // pending unclaimed items past the role's age threshold
915
917
  throughput_pct: number | null; // resolved / (target_per_hour × hours) × 100
916
918
  wait: StationMetricPeriod; // queue time: created_at → claimed_at
917
919
  work: StationMetricPeriod; // processing time: claimed_at → resolved_at
918
920
  }
919
921
  ```
920
922
 
921
- `pending` reflects the live queue depth regardless of period. `claimed`, `resolved`, and both percentile objects use the lookback window. `in_arrears` is computed from `sla_minutes` on the role — stations without `sla_minutes` always return `0`. `throughput_pct` is `null` when `target_per_hour` is not set.
923
+ `pending` reflects the live queue depth regardless of period. `claimed`, `resolved`, and both percentile objects use the lookback window. `priority_count` covers pending, unclaimed items whose age exceeds the role's threshold age from the `priority_facet` metadata timestamp (`created_at` when unset) against `priority_threshold_minutes` (`sla_minutes` when unset); stations with neither threshold always return `0`. `throughput_pct` is `null` when `target_per_hour` is not set.
922
924
 
923
925
  **Auth:** Same RBAC as `getStats` — callers see only the stations for roles they hold.
@@ -30,6 +30,8 @@ interface RoleDetail {
30
30
  sla_minutes: number | null;
31
31
  target_per_hour: number | null;
32
32
  worker_count: number | null;
33
+ priority_threshold_minutes: number | null;
34
+ priority_facet: string | null;
33
35
  user_count: number;
34
36
  chain_count: number;
35
37
  workflow_count: number;
@@ -46,9 +48,11 @@ interface RoleDetail {
46
48
  | `properties` | Free user-owned bag — arbitrary config stored on the role |
47
49
  | `ops_visible` | When `true`, the role appears as a station on the Operations view |
48
50
  | `parent_role` | Parent role in the process dependency graph; drives the pace chart dependency ordering |
49
- | `sla_minutes` | SLA target in minutes — items older than this appear in `in_arrears` in station metrics |
51
+ | `sla_minutes` | SLA target in minutes — the default age threshold for `priority_count` in station metrics |
50
52
  | `target_per_hour` | Throughput target used to compute `throughput_pct` in station metrics |
51
53
  | `worker_count` | Station capacity — number of workers expected to be active |
54
+ | `priority_threshold_minutes` | Max age before a pending unclaimed item counts toward `priority_count`; falls back to `sla_minutes` |
55
+ | `priority_facet` | Escalation metadata key holding the age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`); falls back to `created_at` |
52
56
  | `user_count` | Number of users currently assigned to this role |
53
57
  | `chain_count` | Number of escalation chain links originating from this role |
54
58
  | `workflow_count` | Number of registered workflows that target this role |
@@ -269,6 +273,8 @@ const result = await lt.roles.update({
269
273
  | `sla_minutes` | `number \| null` | No | SLA target in minutes |
270
274
  | `target_per_hour` | `number \| null` | No | Throughput target (items per hour) |
271
275
  | `worker_count` | `number \| null` | No | Station capacity |
276
+ | `priority_threshold_minutes` | `number \| null` | No | Priority age threshold in minutes; falls back to `sla_minutes` |
277
+ | `priority_facet` | `string \| null` | No | Metadata key for the priority age origin; falls back to `created_at` |
272
278
  | `upstream_roles` | `string[] \| null` | No | Replace the set of roles this station draws input from across other Operations sequences (omitted = preserve; `null` or `[]` = clear). Distinct from `parent_role`, which places the role in its own sequence |
273
279
  | `change_summary` | `string` | No | Label recorded on the schema version snapshot when this update changes a schema field |
274
280
 
@@ -152,7 +152,7 @@ const result = await lt.workflows.listDiscovered({ include_system: false });
152
152
  |-------|------|----------|-------------|
153
153
  | `include_system` | `boolean` | No | Include system workflows (default: false) |
154
154
 
155
- **Returns:** `LTApiResult<{ workflows: [{ workflow_type, task_queue, registered, active, invocable, system, description, roles, invocation_roles, execute_as }] }>`
155
+ **Returns:** `LTApiResult<{ workflows: [{ workflow_type, task_queue, tier, registered, active, invocable, system, description, roles, invocation_roles, execute_as }] }>` — `tier` is `certified`, `registered`, or `durable`.
156
156
 
157
157
  **Auth:** Not required
158
158
 
@@ -232,11 +232,12 @@ const result = await lt.workflows.upsertConfig({
232
232
  |-------|------|----------|-------------|
233
233
  | `type` | `string` | Yes | Workflow type name |
234
234
  | `invocable` | `boolean` | No | Whether the workflow can be started via the API |
235
+ | `certified` | `boolean` | No | Explicit HITL certification (interceptor treatment). Omitted → derived from roles/consumes presence. |
235
236
  | `task_queue` | `string \| null` | No | HotMesh task queue |
236
237
  | `default_role` | `string` | No | Default escalation role |
237
238
  | `description` | `string \| null` | No | Human-readable description |
238
239
  | `execute_as` | `string \| null` | No | Service account for proxy invocation |
239
- | `roles` | `string[]` | No | Roles that can resolve escalations |
240
+ | `roles` | `string[]` | No | Interceptor default for who resolves interceptor-raised escalations |
240
241
  | `invocation_roles` | `string[]` | No | Roles that can invoke this workflow |
241
242
  | `consumes` | `string[]` | No | Workflow types whose data this workflow consumes |
242
243
  | `tool_tags` | `string[]` | No | MCP tool tags for discovery |
@@ -112,7 +112,7 @@ A durable workflow has no entry in `lt_config_workflows`. It runs, but without i
112
112
 
113
113
  ### Certified
114
114
 
115
- A certified workflow is durable plus the full Long Tail control plane. It has an entry in `lt_config_workflows`, which activates:
115
+ A certified workflow is durable plus the full Long Tail control plane. It has an entry in `lt_config_workflows` with `certified: true`, which activates:
116
116
 
117
117
  - **Interceptor wrapping** — every execution is tracked as a task in `lt_tasks` with full audit trail.
118
118
  - **Escalation chains** — returning `{ type: 'escalation' }` creates a reviewable record, routes to the correct role, and triggers re-runs on resolution.
@@ -120,7 +120,7 @@ A certified workflow is durable plus the full Long Tail control plane. It has an
120
120
  - **Invocation controls** — `invocable: true` exposes the workflow for external invocation via the API and dashboard.
121
121
  - **Execution identity** — roles, default assignees, and `execute_as` overrides are defined in the config.
122
122
 
123
- In the dashboard, certified workflows display a **ShieldCheck** icon with a "Certified" label in accent blue. Promote a durable workflow to certified by creating a config entry; de-certify by removing it. The workflow code does not change.
123
+ In the dashboard, certified workflows display a **ShieldCheck** icon with a "Certified" label in accent blue. A registration without certification ("Registered" tier) keeps invocation controls and schema-driven forms while skipping the interceptor. Certification is the `certified` flag on the registration: promote by checking Certify (or `certified: true` in the config), demote by unchecking it — escalation roles and dependencies stay on the row. Unregistering deletes the entry entirely. The workflow code does not change.
124
124
 
125
125
  ### Pipeline
126
126
 
package/docs/dashboard.md CHANGED
@@ -64,15 +64,15 @@ The top navigation bar contains:
64
64
 
65
65
  ### Workflow Registry
66
66
 
67
- Shows every workflow the system has discovered across all registered workers. Each workflow displays one of three tiers:
67
+ Shows every workflow the system has discovered across all registered workers. Each workflow displays one of three tiers — direct states of the registration:
68
68
 
69
- - **Certified** (ShieldCheck icon) — has an `lt_config_workflows` entry with roles or consumes. Full interceptor tracking, escalation chains, and invocation controls.
70
- - **Configured** (Settings icon) — has a config entry but no roles. Invocation controls and schema-driven forms, but no automatic escalation routing.
71
- - **Durable** (Wrench icon) — registered as a HotMesh worker but not configured. Checkpointed execution and retries, but no interceptor wrapping.
69
+ - **Certified** (ShieldCheck icon) — has an `lt_config_workflows` entry with `certified: true`. Full interceptor tracking, escalation defaults, and invocation controls.
70
+ - **Registered** (Settings icon) — has a registration with `certified: false`. Invocation controls and schema-driven forms, without interceptor wrapping.
71
+ - **Durable** (Wrench icon) — runs as a HotMesh worker with no registration. Checkpointed execution and retries only.
72
72
 
73
73
  **Columns:** Workflow (pill + description), Queue (bordered pill), Tier (icon + label), Access (escalation roles with shield icon, invocation roles with user-check icon).
74
74
 
75
- **Row actions** (on hover): Play (invoke), Wrench (configure durable), ShieldPlus (certify configured), ShieldOff (de-certify).
75
+ **Row actions** (on hover): Play (invoke), Wrench (register durable), ShieldPlus (certify registered), ShieldOff (unregister — deletes the registration). To demote certified → registered, open the workflow and uncheck **Certify for HITL Escalation**; escalation roles, dependencies, and schemas stay on the registration.
76
76
 
77
77
  **Inline config via `start()`:** Developers can declare workflow profiles directly in the `start()` config by adding a `config` block to any worker entry. This auto-seeds the workflow into `lt_config_workflows` at startup — no manual API calls or dashboard wizard needed. Roles referenced in the config are auto-created.
78
78
 
@@ -84,6 +84,7 @@ workers: [
84
84
  config: {
85
85
  description: 'My workflow description',
86
86
  invocable: true,
87
+ certified: true,
87
88
  roles: ['reviewer', 'admin'],
88
89
  envelopeSchema: { data: { field1: '', field2: 0 } },
89
90
  resolverSchema: { approved: true, notes: '' },
@@ -217,7 +218,7 @@ Search filters by key, label, or description. **+ Add Role** creates a role here
217
218
 
218
219
  Accessible at `/admin/roles/:role`. One page per role — a header plus three columns covering identity, routing and people, and schemas.
219
220
 
220
- **Header** — the role key with its prior step, the capacity set, and the **Ops** toggle that shows the role as a station on the [Pace Board](#pace-board). The capacity set holds `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the header hints the derived third (`throughput = workers / (sla / 60)`). Save applies header and identity edits via `PATCH /api/roles/:role`.
221
+ **Header** — the role key with its prior step, the capacity set, and the **Ops** toggle that shows the role as a station on the [Pace Board](#pace-board). The capacity set holds `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the header hints the derived third (`throughput = workers / (sla / 60)`). Beside it, the priority set holds `priority_threshold_minutes` and `priority_facet` — the age threshold and metadata timestamp key driving the Pace Board priority count (blank = `sla_minutes` and `created_at`). Save applies header and identity edits via `PATCH /api/roles/:role`.
221
222
 
222
223
  **Identity** — display name and description, shown on role rows and station labels.
223
224
 
@@ -314,13 +315,14 @@ Execution is a graph; this page tells its story as **sequences**. Each station r
314
315
 
315
316
  - **Sequence picker** — when more than one sequence exists, tabs appear above the chart, one per sequence, named by its origin role with the station count alongside. The active sequence is deep-linked (`?fragment=<origin role>`) and each switch is a browser-history entry, so a shared URL opens the same sequence and back/forward walks between them.
316
317
  - **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and throughput.
317
- - **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below); a station with items past SLA carries a dashed red ring.
318
+ - **Pace chart** — connects the active sequence's stations in process dependency order and plots absolute counts for the selected window: a straight red target polyline (`target_per_hour × window hours`) against a smooth actual (resolved) curve with a light area fill. The queue splits into two stacked bands — claimed-and-worked (indigo) and waiting-unclaimed (sky). Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below).
319
+ - **Priority badge** — a station with unclaimed items past its age threshold carries a powder-blue circle with the count. Age is measured from the role's priority facet (a metadata timestamp such as the order's authorized date; `created_at` when unset) against its priority threshold (`sla_minutes` when unset). Clicking the badge opens that station's queue ordered oldest-first by the same facet — the counted items sit at the top, ready to pull to the front of the rack.
318
320
  - **Merge affordance** — a station that declares upstream inputs shows a small dashed merge glyph at its floor position. It is deliberately a symbol, never a bend in the line: the upstream is an input, not a descendant. Hover names the feeding roles; click jumps to their sequence.
319
- - **Station table** — one row per station: ROLE (with a merge icon marking cross-sequence inputs), TARGET/H, then PENDING, ACTIVE, RESOLVED in column bands carrying the chart's hues, P99 WAIT, P99 WORK, and a TREND mini-bar. TREND shows the live backlog-to-target ratio while the queue has items; when the queue is idle it shows the period's throughput efficiency, marked with `↩`. Stations with past-SLA items show a sub-row linking to the oldest-first queue view.
321
+ - **Station table** — one row per station: ROLE (with a merge icon marking cross-sequence inputs), TARGET/H, then PENDING, ACTIVE, RESOLVED in column bands carrying the chart's hues, P99 WAIT, P99 WORK, and a TREND mini-bar. TREND shows the live backlog-to-target ratio while the queue has items; when the queue is idle it shows the period's throughput efficiency, marked with `↩`. Stations with priority items show a powder-blue sub-row linking to the queue ordered oldest-first by the priority facet.
320
322
  - **Station detail panel** — opens on row or circle click. Shows the role's identity, an independent period toggle, and the full metric breakdown (wait/work percentiles, SLA target, worker count, links to the queue).
321
323
  - **Live updates** — escalation events refresh the metrics push-driven and debounced; the header's refresh button forces a reload.
322
324
 
323
- A role joins the board via the **Ops** toggle on its [Role Detail](#role-detail) page; the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) drive the computed metrics. See [Operations](operations.md) for the full concept doc.
325
+ A role joins the board via the **Ops** toggle on its [Role Detail](#role-detail) page; the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) and the priority dials (`priority_threshold_minutes`, `priority_facet`) drive the computed metrics. See [Operations](operations.md) for the full concept doc.
324
326
 
325
327
  **API:** `GET /api/escalations/station-metrics?period=24h`
326
328
 
package/docs/data.md CHANGED
@@ -22,6 +22,8 @@ Canonical role registry. Roles referenced by other tables are seeded here.
22
22
  | `sla_minutes` | `NUMERIC` | — | Target resolution time |
23
23
  | `target_per_hour` | `NUMERIC` | — | Throughput target |
24
24
  | `worker_count` | `NUMERIC` | — | Station capacity |
25
+ | `priority_threshold_minutes` | `NUMERIC` | — | Priority age threshold; falls back to `sla_minutes` |
26
+ | `priority_facet` | `TEXT` | — | Escalation metadata key holding the priority age origin (ISO 8601 UTC); falls back to `created_at` |
25
27
  | `created_at` | `TIMESTAMPTZ NOT NULL` | `NOW()` | Row creation time |
26
28
 
27
29
  **Seeds:** `reviewer`, `engineer`, `admin`, `superadmin`.
package/docs/iam.md CHANGED
@@ -51,11 +51,11 @@ Long Tail has three workflow types (see the [Workflows Guide](workflows.md#three
51
51
 
52
52
  **Durable workflows** are the baseline. Every workflow registered with HotMesh is durable: checkpointed to Postgres, restartable after crashes, with full IAM context. If an activity throws, the workflow fails.
53
53
 
54
- **Certified workflows** add the interceptor. The interceptor wraps every execution so that failures escalate to a human reviewer instead of throwing. A certified workflow has an entry in `lt_config_workflows` that defines its escalation chain, invocation roles, and optional `execute_as` service account. It gets never-fail guarantees — when an LLM call returns garbage or an API is down, the workflow pauses and creates a human task rather than dying.
54
+ **Certified workflows** add the interceptor. The interceptor wraps every execution so that failures escalate to a human reviewer instead of throwing. A certified workflow has an entry in `lt_config_workflows` with `certified: true` that defines its escalation defaults, invocation roles, and optional `execute_as` service account. It gets never-fail guarantees — when an LLM call returns garbage or an API is down, the workflow pauses and creates a human task rather than dying.
55
55
 
56
56
  **Pipeline workflows** are compiled deterministic workflows that execute tool calls without an LLM. They inherit the IAM context of the invoking workflow — the principal, credentials, and trace lineage all propagate through the YAML DAG execution.
57
57
 
58
- Any durable workflow can be promoted to certified through the Workflow Registry in the dashboard. Registration adds the interceptor config; de-registration removes it. The workflow code does not change.
58
+ Any durable workflow can be promoted through the Workflow Registry in the dashboard: registering creates the config entry (invocation + schemas), and the Certify checkbox turns on the interceptor. Unchecking Certify demotes to registered and keeps the config; unregistering deletes it. The workflow code does not change.
59
59
 
60
60
  ## Service Accounts
61
61
 
@@ -196,7 +196,7 @@ When an activity calls `getCredential('anthropic')` and no credential exists in
196
196
 
197
197
  The dashboard surfaces IAM across four pages:
198
198
 
199
- **Workflow Registry** (`/workflows/registry`) — lists all discovered workflows. Certified workflows display a ShieldCheck badge in accent blue; pipeline workflows display a Wand2 icon in purple; durable workflows show the standard Workflow icon. Use ShieldPlus to certify a durable workflow or ShieldOff to de-certify.
199
+ **Workflow Registry** (`/workflows/registry`) — lists all discovered workflows. Certified workflows display a ShieldCheck badge in accent blue; pipeline workflows display a Wand2 icon in purple; durable workflows show the standard Workflow icon. Use ShieldPlus to certify a registered workflow, the Certify checkbox on the detail page to promote or demote, and ShieldOff to unregister.
200
200
 
201
201
  **Accounts** (`/admin/users`) — unified management for User Accounts and Service Accounts via tab toggle. Create service accounts, assign roles, generate API keys. The key generation flow displays the raw key once; it cannot be retrieved after dismissal.
202
202
 
@@ -14,12 +14,25 @@ Each station has three settings that define what "healthy" looks like — knowin
14
14
 
15
15
  | Field | Description |
16
16
  |-------|-------------|
17
- | `sla_minutes` | Target resolution time in minutes. Items older than this are counted as `in_arrears`. |
17
+ | `sla_minutes` | Target resolution time in minutes. The default age threshold for the priority count. |
18
18
  | `target_per_hour` | Intended throughput — how many items should resolve per hour. Used to compute `throughput_pct` and the station's expected count on the pace chart. |
19
19
  | `worker_count` | Capacity at this station — number of staff or machines expected to be active. |
20
20
 
21
21
  These are set via `PATCH /api/roles/:role` or the Roles admin page.
22
22
 
23
+ ## Priority count
24
+
25
+ Every station carries one age signal: `priority_count`, the number of **pending, unclaimed** items older than the station's threshold. It is deliberately a count, not a re-sorted queue — the floor rebalances coarsely, pulling the counted items to the front of the rack, rather than continuously re-ordering everything.
26
+
27
+ Two per-role dials shape it, each with a fallback so the count works from `sla_minutes` alone:
28
+
29
+ | Dial | Description |
30
+ |------|-------------|
31
+ | `priority_facet` | `lt_escalations.metadata` key holding each item's age origin as an ISO 8601 UTC timestamp (e.g. `authorized_at`, the date the order was authorized). Blank = age from `created_at`. When set, items missing the key or holding an unparseable value are not counted. |
32
+ | `priority_threshold_minutes` | Max age before an item counts as priority. Blank = the station's `sla_minutes`. |
33
+
34
+ Claimed items are excluded — they are already in someone's hands; the count is what still needs pulling forward. On the pace chart the count renders as a powder-blue circle at the station; clicking it (or the sub-row link in the station table) opens the station's queue ordered oldest-first by the same facet, so the counted items sit at the top.
35
+
23
36
  ## Pace chart
24
37
 
25
38
  The chart is the centrepiece. It plots **absolute counts for the selected window** across the pipeline — every station in dependency order (parent before children, breadth-first) on the X axis.
@@ -63,7 +76,7 @@ Below the chart, a flat table lists every station with its live numbers:
63
76
  | P99 WORK | 99th-percentile processing time (claimed → resolved) in minutes |
64
77
  | TREND | Mini fill bar + percentage — live backlog ratio while items queue, period throughput efficiency when idle |
65
78
 
66
- If a station has `in_arrears > 0`, a sub-row appears: `⚠ N items past SLA view oldest first →`. The link opens the escalation queue sorted by `created_at` ascending, filtered to that role.
79
+ If a station has `priority_count > 0`, a powder-blue sub-row appears: `N prioritypull oldest first →`. The link opens the escalation queue filtered to that role and ordered oldest-first by the station's priority facet (`created_at` when no facet is configured), so the counted items sit at the top.
67
80
 
68
81
  Clicking any row opens the station detail panel.
69
82
 
@@ -79,7 +92,7 @@ Close the panel with × or by clicking another row.
79
92
 
80
93
  ## Data source
81
94
 
82
- All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for `sla_minutes` and `target_per_hour`): a live-counts pass over the pending backlog, and a window-bounded percentile pass over resolved rows (`PERCENTILE_CONT` in Postgres, served by the `idx_hmsh_esc_resolved_cover` index). Updates reach the page as push events — every escalation write invalidates the metrics through the Socket.IO event system.
95
+ All station metrics come from `GET /api/escalations/station-metrics?period=<period>`. The endpoint runs two queries against `public.hmsh_escalations` joined to `lt_roles` (for the priority dials and `target_per_hour`): a live-counts pass over the pending backlog, and a window-bounded percentile pass over resolved rows (`PERCENTILE_CONT` in Postgres, served by the `idx_hmsh_esc_resolved_cover` index). Updates reach the page as push events — every escalation write invalidates the metrics through the Socket.IO event system.
83
96
 
84
97
  `pending` is always the live count regardless of period. `resolved`, percentiles, and `throughput_pct` are scoped to the lookback window. See [`lt.escalations.getStationMetrics`](api/sdk/escalations.md#getstationmetrics) for the full response shape.
85
98