@hotmeshio/long-tail 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (267) hide show
  1. package/build/api/escalations/create.js +45 -0
  2. package/build/api/escalations/index.d.ts +1 -1
  3. package/build/api/escalations/index.js +2 -1
  4. package/build/api/escalations/list.d.ts +3 -0
  5. package/build/api/escalations/list.js +14 -0
  6. package/build/api/roles.d.ts +17 -0
  7. package/build/api/roles.js +46 -0
  8. package/build/bin/ltc.js +1 -0
  9. package/build/lib/cli/commands/escalations.d.ts +1 -0
  10. package/build/lib/cli/commands/escalations.js +2 -0
  11. package/build/lib/db/migrate.js +22 -2
  12. package/build/lib/db/schemas/014_roles_v2.sql +19 -0
  13. package/build/lib/db/schemas/015_role_ops.sql +50 -0
  14. package/build/lib/db/schemas/016_station_metrics_indexes.sql +13 -0
  15. package/build/lib/events/system-events.js +3 -0
  16. package/build/modules/auth.d.ts +9 -0
  17. package/build/modules/auth.js +38 -1
  18. package/build/routes/escalations/list.js +10 -0
  19. package/build/routes/roles.js +16 -5
  20. package/build/scripts/ortho-populate.d.ts +37 -0
  21. package/build/scripts/ortho-populate.js +228 -0
  22. package/build/sdk/index.d.ts +4 -0
  23. package/build/sdk/index.js +2 -0
  24. package/build/services/escalation/client.js +93 -2
  25. package/build/services/escalation/crud.js +18 -9
  26. package/build/services/escalation/metrics-cache.d.ts +14 -0
  27. package/build/services/escalation/metrics-cache.js +53 -0
  28. package/build/services/escalation/queries.d.ts +14 -2
  29. package/build/services/escalation/queries.js +121 -11
  30. package/build/services/escalation/sql.d.ts +29 -2
  31. package/build/services/escalation/sql.js +156 -27
  32. package/build/services/escalation/types.d.ts +17 -0
  33. package/build/services/escalation/types.js +1 -0
  34. package/build/services/interceptor/completion.js +17 -12
  35. package/build/services/mcp/external-server.js +5 -1
  36. package/build/services/orchestrator/condition.d.ts +20 -0
  37. package/build/services/orchestrator/condition.js +20 -0
  38. package/build/services/role/index.d.ts +22 -3
  39. package/build/services/role/index.js +50 -2
  40. package/build/services/role/sql.d.ts +11 -1
  41. package/build/services/role/sql.js +38 -1
  42. package/build/services/role/types.d.ts +32 -0
  43. package/build/system/mcp-servers/admin/escalations.js +8 -7
  44. package/build/system/mcp-servers/admin/index.js +5 -3
  45. package/build/system/mcp-servers/admin/ortho.d.ts +10 -0
  46. package/build/system/mcp-servers/admin/ortho.js +242 -0
  47. package/build/system/mcp-servers/admin/schemas.d.ts +40 -3
  48. package/build/system/mcp-servers/admin/schemas.js +17 -4
  49. package/build/system/mcp-servers/admin/users.js +31 -0
  50. package/build/system/seed/tool-manifests-admin.d.ts +4016 -712
  51. package/build/system/seed/tool-manifests-admin.js +14 -1
  52. package/build/tsconfig.tsbuildinfo +1 -1
  53. package/build/types/escalation.d.ts +3 -1
  54. package/dashboard/dist/assets/{AdminDashboard-C5gfVEeL.js → AdminDashboard-Bg1HgukI.js} +2 -2
  55. package/dashboard/dist/assets/{AdminDashboard-C5gfVEeL.js.map → AdminDashboard-Bg1HgukI.js.map} +1 -1
  56. package/dashboard/dist/assets/{AgentConfigPage-CWEnuiGN.js → AgentConfigPage-HBe_YDU_.js} +6 -6
  57. package/dashboard/dist/assets/{AgentConfigPage-CWEnuiGN.js.map → AgentConfigPage-HBe_YDU_.js.map} +1 -1
  58. package/dashboard/dist/assets/{AgentDetailPage-B6IE27iK.js → AgentDetailPage-BsaiYbwL.js} +4 -4
  59. package/dashboard/dist/assets/{AgentDetailPage-B6IE27iK.js.map → AgentDetailPage-BsaiYbwL.js.map} +1 -1
  60. package/dashboard/dist/assets/AgentsPage-DhN2lIBh.js +2 -0
  61. package/dashboard/dist/assets/{AgentsPage-Blhh2RsK.js.map → AgentsPage-DhN2lIBh.js.map} +1 -1
  62. package/dashboard/dist/assets/AvailableEscalationsPage-_xcWvlIz.js +2 -0
  63. package/dashboard/dist/assets/AvailableEscalationsPage-_xcWvlIz.js.map +1 -0
  64. package/dashboard/dist/assets/{BotPicker-DSozotGk.js → BotPicker-DY6iUVC9.js} +2 -2
  65. package/dashboard/dist/assets/{BotPicker-DSozotGk.js.map → BotPicker-DY6iUVC9.js.map} +1 -1
  66. package/dashboard/dist/assets/{CapabilitiesPage-CrS_DTA1.js → CapabilitiesPage-w1owqsmN.js} +2 -2
  67. package/dashboard/dist/assets/{CapabilitiesPage-CrS_DTA1.js.map → CapabilitiesPage-w1owqsmN.js.map} +1 -1
  68. package/dashboard/dist/assets/{CollapsibleSection-1i6bOQ1L.js → CollapsibleSection-DIMGjlJ-.js} +2 -2
  69. package/dashboard/dist/assets/{CollapsibleSection-1i6bOQ1L.js.map → CollapsibleSection-DIMGjlJ-.js.map} +1 -1
  70. package/dashboard/dist/assets/{CredentialsPage-BxJio06E.js → CredentialsPage-D1OmMHux.js} +2 -2
  71. package/dashboard/dist/assets/{CredentialsPage-BxJio06E.js.map → CredentialsPage-D1OmMHux.js.map} +1 -1
  72. package/dashboard/dist/assets/{CronLabel-BAfIHHz4.js → CronLabel-CQy3DrUQ.js} +2 -2
  73. package/dashboard/dist/assets/{CronLabel-BAfIHHz4.js.map → CronLabel-CQy3DrUQ.js.map} +1 -1
  74. package/dashboard/dist/assets/{CustomDurationPicker-BLF0NFJK.js → CustomDurationPicker-BoBkl9tw.js} +2 -2
  75. package/dashboard/dist/assets/{CustomDurationPicker-BLF0NFJK.js.map → CustomDurationPicker-BoBkl9tw.js.map} +1 -1
  76. package/dashboard/dist/assets/{DropZone-CEx_wk-g.js → DropZone-QXbiuU0b.js} +2 -2
  77. package/dashboard/dist/assets/{DropZone-CEx_wk-g.js.map → DropZone-QXbiuU0b.js.map} +1 -1
  78. package/dashboard/dist/assets/{ElapsedCell-nKGJvznH.js → ElapsedCell-Donjm9gT.js} +2 -2
  79. package/dashboard/dist/assets/{ElapsedCell-nKGJvznH.js.map → ElapsedCell-Donjm9gT.js.map} +1 -1
  80. package/dashboard/dist/assets/{EscalationsOverview-bNNVA6R2.js → EscalationsOverview-CvHIJ_GG.js} +2 -2
  81. package/dashboard/dist/assets/{EscalationsOverview-bNNVA6R2.js.map → EscalationsOverview-CvHIJ_GG.js.map} +1 -1
  82. package/dashboard/dist/assets/{EventTable-BCuDdqlU.js → EventTable-DpAXMmT3.js} +2 -2
  83. package/dashboard/dist/assets/{EventTable-BCuDdqlU.js.map → EventTable-DpAXMmT3.js.map} +1 -1
  84. package/dashboard/dist/assets/{GraphInvokePage-BPAvqHls.js → GraphInvokePage-De1XVx5d.js} +2 -2
  85. package/dashboard/dist/assets/{GraphInvokePage-BPAvqHls.js.map → GraphInvokePage-De1XVx5d.js.map} +1 -1
  86. package/dashboard/dist/assets/HomePage-BYR5VXXw.js +2 -0
  87. package/dashboard/dist/assets/HomePage-BYR5VXXw.js.map +1 -0
  88. package/dashboard/dist/assets/{ListToolbar-DIJZfEgu.js → ListToolbar-Bx7jGzPA.js} +2 -2
  89. package/dashboard/dist/assets/{ListToolbar-DIJZfEgu.js.map → ListToolbar-Bx7jGzPA.js.map} +1 -1
  90. package/dashboard/dist/assets/{McpOverview-DCfSCfPg.js → McpOverview-DXRKcJN0.js} +2 -2
  91. package/dashboard/dist/assets/{McpOverview-DCfSCfPg.js.map → McpOverview-DXRKcJN0.js.map} +1 -1
  92. package/dashboard/dist/assets/{McpQueryDetailPage-mb7rmtNe.js → McpQueryDetailPage-CmW15w5e.js} +2 -2
  93. package/dashboard/dist/assets/{McpQueryDetailPage-mb7rmtNe.js.map → McpQueryDetailPage-CmW15w5e.js.map} +1 -1
  94. package/dashboard/dist/assets/{McpQueryPage-D9b1T0I3.js → McpQueryPage-BE6I011z.js} +2 -2
  95. package/dashboard/dist/assets/{McpQueryPage-D9b1T0I3.js.map → McpQueryPage-BE6I011z.js.map} +1 -1
  96. package/dashboard/dist/assets/{McpRunDetailPage-Bz2UyuNm.js → McpRunDetailPage-Dsa3G3XQ.js} +2 -2
  97. package/dashboard/dist/assets/{McpRunDetailPage-Bz2UyuNm.js.map → McpRunDetailPage-Dsa3G3XQ.js.map} +1 -1
  98. package/dashboard/dist/assets/{McpRunsPage-Dw7w_ZO-.js → McpRunsPage-uTbym66Y.js} +2 -2
  99. package/dashboard/dist/assets/{McpRunsPage-Dw7w_ZO-.js.map → McpRunsPage-uTbym66Y.js.map} +1 -1
  100. package/dashboard/dist/assets/{NamespacePill-D27vqDXy.js → NamespacePill-BGf0jHwE.js} +2 -2
  101. package/dashboard/dist/assets/{NamespacePill-D27vqDXy.js.map → NamespacePill-BGf0jHwE.js.map} +1 -1
  102. package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js +2 -0
  103. package/dashboard/dist/assets/OperationsPage-CAmiFHI6.js.map +1 -0
  104. package/dashboard/dist/assets/{OperatorDashboard-CTzSDW3N.js → OperatorDashboard-i8cxaDlk.js} +2 -2
  105. package/dashboard/dist/assets/{OperatorDashboard-CTzSDW3N.js.map → OperatorDashboard-i8cxaDlk.js.map} +1 -1
  106. package/dashboard/dist/assets/{PageHeader-B_1zTx2q.js → PageHeader-BZJsEVOC.js} +2 -2
  107. package/dashboard/dist/assets/{PageHeader-B_1zTx2q.js.map → PageHeader-BZJsEVOC.js.map} +1 -1
  108. package/dashboard/dist/assets/{PageHeaderWithStats-D-cPg7UD.js → PageHeaderWithStats-BWuD7s9c.js} +2 -2
  109. package/dashboard/dist/assets/{PageHeaderWithStats-D-cPg7UD.js.map → PageHeaderWithStats-BWuD7s9c.js.map} +1 -1
  110. package/dashboard/dist/assets/{ProcessDetailPage-olG2CS-h.js → ProcessDetailPage-CP7GZhgs.js} +2 -2
  111. package/dashboard/dist/assets/{ProcessDetailPage-olG2CS-h.js.map → ProcessDetailPage-CP7GZhgs.js.map} +1 -1
  112. package/dashboard/dist/assets/{ProcessesListPage-CUZSL06Y.js → ProcessesListPage-btsU6hBR.js} +2 -2
  113. package/dashboard/dist/assets/{ProcessesListPage-CUZSL06Y.js.map → ProcessesListPage-btsU6hBR.js.map} +1 -1
  114. package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js +16 -0
  115. package/dashboard/dist/assets/RoleDetailPage-BB_e330f.js.map +1 -0
  116. package/dashboard/dist/assets/{RolePill-B-V-31lC.js → RolePill-Pb9TKSQN.js} +2 -2
  117. package/dashboard/dist/assets/{RolePill-B-V-31lC.js.map → RolePill-Pb9TKSQN.js.map} +1 -1
  118. package/dashboard/dist/assets/RolesPage-1DBoEMsb.js +2 -0
  119. package/dashboard/dist/assets/RolesPage-1DBoEMsb.js.map +1 -0
  120. package/dashboard/dist/assets/{RunAsSelector-BoLHF4fy.js → RunAsSelector-Cp6j3FEY.js} +2 -2
  121. package/dashboard/dist/assets/{RunAsSelector-BoLHF4fy.js.map → RunAsSelector-Cp6j3FEY.js.map} +1 -1
  122. package/dashboard/dist/assets/StatusBadge-D9MeQHrh.js +2 -0
  123. package/dashboard/dist/assets/StatusBadge-D9MeQHrh.js.map +1 -0
  124. package/dashboard/dist/assets/{StickyPagination-BEMY1L-H.js → StickyPagination-Pr8kawv8.js} +2 -2
  125. package/dashboard/dist/assets/{StickyPagination-BEMY1L-H.js.map → StickyPagination-Pr8kawv8.js.map} +1 -1
  126. package/dashboard/dist/assets/StreamMessageDetail-BqmQ-N3y.js +2 -0
  127. package/dashboard/dist/assets/{StreamMessageDetail-CVRVWXcU.js.map → StreamMessageDetail-BqmQ-N3y.js.map} +1 -1
  128. package/dashboard/dist/assets/{SwimlaneTimeline-DDpU0-Jn.js → SwimlaneTimeline-y1YmXrsj.js} +2 -2
  129. package/dashboard/dist/assets/{SwimlaneTimeline-DDpU0-Jn.js.map → SwimlaneTimeline-y1YmXrsj.js.map} +1 -1
  130. package/dashboard/dist/assets/{TagInput-BHVfG307.js → TagInput-Df4myuYF.js} +2 -2
  131. package/dashboard/dist/assets/{TagInput-BHVfG307.js.map → TagInput-Df4myuYF.js.map} +1 -1
  132. package/dashboard/dist/assets/{TaskDetailPage-B_xQtJMg.js → TaskDetailPage-CT5rXHK5.js} +2 -2
  133. package/dashboard/dist/assets/{TaskDetailPage-B_xQtJMg.js.map → TaskDetailPage-CT5rXHK5.js.map} +1 -1
  134. package/dashboard/dist/assets/{TaskQueuePill-CGlxXqWt.js → TaskQueuePill-YalYdCNo.js} +2 -2
  135. package/dashboard/dist/assets/{TaskQueuePill-CGlxXqWt.js.map → TaskQueuePill-YalYdCNo.js.map} +1 -1
  136. package/dashboard/dist/assets/{TasksListPage-CsrdIOKk.js → TasksListPage-DOy6JlKS.js} +2 -2
  137. package/dashboard/dist/assets/{TasksListPage-CsrdIOKk.js.map → TasksListPage-DOy6JlKS.js.map} +1 -1
  138. package/dashboard/dist/assets/{TimeAgo-DmicaxjT.js → TimeAgo-BAQwZSpq.js} +2 -2
  139. package/dashboard/dist/assets/{TimeAgo-DmicaxjT.js.map → TimeAgo-BAQwZSpq.js.map} +1 -1
  140. package/dashboard/dist/assets/{TimestampCell-DeK89eRV.js → TimestampCell-BK_jufns.js} +2 -2
  141. package/dashboard/dist/assets/{TimestampCell-DeK89eRV.js.map → TimestampCell-BK_jufns.js.map} +1 -1
  142. package/dashboard/dist/assets/{ToolPill-NV7PxSpA.js → ToolPill-VGpT6Quy.js} +2 -2
  143. package/dashboard/dist/assets/{ToolPill-NV7PxSpA.js.map → ToolPill-VGpT6Quy.js.map} +1 -1
  144. package/dashboard/dist/assets/{ToolTestPanel-D3s2n9-9.js → ToolTestPanel-5PMQyUCe.js} +2 -2
  145. package/dashboard/dist/assets/{ToolTestPanel-D3s2n9-9.js.map → ToolTestPanel-5PMQyUCe.js.map} +1 -1
  146. package/dashboard/dist/assets/{TopicDetailPage-qyv7UWT_.js → TopicDetailPage-Cn1ShfR8.js} +3 -3
  147. package/dashboard/dist/assets/{TopicDetailPage-qyv7UWT_.js.map → TopicDetailPage-Cn1ShfR8.js.map} +1 -1
  148. package/dashboard/dist/assets/{TopicsPage-CEUfMoed.js → TopicsPage-D67tjS8L.js} +2 -2
  149. package/dashboard/dist/assets/{TopicsPage-CEUfMoed.js.map → TopicsPage-D67tjS8L.js.map} +1 -1
  150. package/dashboard/dist/assets/{UserName-Bn_BxI8K.js → UserName-Dsu1Jk4N.js} +2 -2
  151. package/dashboard/dist/assets/{UserName-Bn_BxI8K.js.map → UserName-Dsu1Jk4N.js.map} +1 -1
  152. package/dashboard/dist/assets/{WorkflowExecutionPage-DAk2RqpB.js → WorkflowExecutionPage-BwQoOmUE.js} +2 -2
  153. package/dashboard/dist/assets/{WorkflowExecutionPage-DAk2RqpB.js.map → WorkflowExecutionPage-BwQoOmUE.js.map} +1 -1
  154. package/dashboard/dist/assets/{WorkflowPill-DDR0B6DN.js → WorkflowPill-pPUqmx6Q.js} +2 -2
  155. package/dashboard/dist/assets/{WorkflowPill-DDR0B6DN.js.map → WorkflowPill-pPUqmx6Q.js.map} +1 -1
  156. package/dashboard/dist/assets/{WorkflowsDashboard-DfBgM80t.js → WorkflowsDashboard-D3z7COgH.js} +2 -2
  157. package/dashboard/dist/assets/{WorkflowsDashboard-DfBgM80t.js.map → WorkflowsDashboard-D3z7COgH.js.map} +1 -1
  158. package/dashboard/dist/assets/{WorkflowsOverview--Dkoo9Jq.js → WorkflowsOverview-C15JcxyY.js} +2 -2
  159. package/dashboard/dist/assets/{WorkflowsOverview--Dkoo9Jq.js.map → WorkflowsOverview-C15JcxyY.js.map} +1 -1
  160. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B6HYbfFj.js → YamlWorkflowDetailPage-BYq3t7E-.js} +2 -2
  161. package/dashboard/dist/assets/{YamlWorkflowDetailPage-B6HYbfFj.js.map → YamlWorkflowDetailPage-BYq3t7E-.js.map} +1 -1
  162. package/dashboard/dist/assets/YamlWorkflowsPage-B44WgwE_.js +2 -0
  163. package/dashboard/dist/assets/{YamlWorkflowsPage-CJE-PxC0.js.map → YamlWorkflowsPage-B44WgwE_.js.map} +1 -1
  164. package/dashboard/dist/assets/{agents-DUciUZpt.js → agents-BRmmK6Y9.js} +2 -2
  165. package/dashboard/dist/assets/{agents-DUciUZpt.js.map → agents-BRmmK6Y9.js.map} +1 -1
  166. package/dashboard/dist/assets/{bots-BnyqCfuC.js → bots-BD75mzGG.js} +2 -2
  167. package/dashboard/dist/assets/{bots-BnyqCfuC.js.map → bots-BD75mzGG.js.map} +1 -1
  168. package/dashboard/dist/assets/{capabilities-CkTWWT0q.js → capabilities-DDgC_Kds.js} +2 -2
  169. package/dashboard/dist/assets/{capabilities-CkTWWT0q.js.map → capabilities-DDgC_Kds.js.map} +1 -1
  170. package/dashboard/dist/assets/controlplane-BJh12lMv.js +2 -0
  171. package/dashboard/dist/assets/controlplane-BJh12lMv.js.map +1 -0
  172. package/dashboard/dist/assets/{escalation-De9JnTKI.js → escalation-DIJt2sgn.js} +2 -2
  173. package/dashboard/dist/assets/{escalation-De9JnTKI.js.map → escalation-DIJt2sgn.js.map} +1 -1
  174. package/dashboard/dist/assets/{escalation-columns-Df7Pluzg.js → escalation-columns-zl6E94Up.js} +2 -2
  175. package/dashboard/dist/assets/{escalation-columns-Df7Pluzg.js.map → escalation-columns-zl6E94Up.js.map} +1 -1
  176. package/dashboard/dist/assets/{index-Cqjf-yVP.js → index-B0kmiSmt.js} +2 -2
  177. package/dashboard/dist/assets/{index-Cqjf-yVP.js.map → index-B0kmiSmt.js.map} +1 -1
  178. package/dashboard/dist/assets/index-BRtKQtQZ.css +1 -0
  179. package/dashboard/dist/assets/{index-BxdiKgnH.js → index-BUbzfEA9.js} +2 -2
  180. package/dashboard/dist/assets/{index-BxdiKgnH.js.map → index-BUbzfEA9.js.map} +1 -1
  181. package/dashboard/dist/assets/{index-DpAS4-DA.js → index-BhznDv-4.js} +2 -2
  182. package/dashboard/dist/assets/{index-DpAS4-DA.js.map → index-BhznDv-4.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-BAhkWcOq.js → index-CDPBXB4e.js} +4 -4
  184. package/dashboard/dist/assets/{index-BAhkWcOq.js.map → index-CDPBXB4e.js.map} +1 -1
  185. package/dashboard/dist/assets/{index-CgD9fA9P.js → index-CV4lEd4I.js} +2 -2
  186. package/dashboard/dist/assets/{index-CgD9fA9P.js.map → index-CV4lEd4I.js.map} +1 -1
  187. package/dashboard/dist/assets/{index-DjxTV3cn.js → index-CknKy4RA.js} +2 -2
  188. package/dashboard/dist/assets/{index-DjxTV3cn.js.map → index-CknKy4RA.js.map} +1 -1
  189. package/dashboard/dist/assets/{index-DNugmBs7.js → index-CpgV4Kkp.js} +2 -2
  190. package/dashboard/dist/assets/{index-DNugmBs7.js.map → index-CpgV4Kkp.js.map} +1 -1
  191. package/dashboard/dist/assets/{index-B1kc6itM.js → index-CtDf8vvQ.js} +24 -24
  192. package/dashboard/dist/assets/index-CtDf8vvQ.js.map +1 -0
  193. package/dashboard/dist/assets/{index-BzMsh6Ui.js → index-DU7YumVJ.js} +2 -2
  194. package/dashboard/dist/assets/{index-BzMsh6Ui.js.map → index-DU7YumVJ.js.map} +1 -1
  195. package/dashboard/dist/assets/{index-BsIaUbKD.js → index-DVVIeBBk.js} +2 -2
  196. package/dashboard/dist/assets/{index-BsIaUbKD.js.map → index-DVVIeBBk.js.map} +1 -1
  197. package/dashboard/dist/assets/index-DccCwyZl.js +6 -0
  198. package/dashboard/dist/assets/{index-CN0efCE9.js.map → index-DccCwyZl.js.map} +1 -1
  199. package/dashboard/dist/assets/{index-7hqtQI43.js → index-DrUkTcn-.js} +2 -2
  200. package/dashboard/dist/assets/{index-7hqtQI43.js.map → index-DrUkTcn-.js.map} +1 -1
  201. package/dashboard/dist/assets/{index-B07xLlyz.js → index-j-C7g_Ej.js} +2 -2
  202. package/dashboard/dist/assets/{index-B07xLlyz.js.map → index-j-C7g_Ej.js.map} +1 -1
  203. package/dashboard/dist/assets/{knowledge-D4SvdNv5.js → knowledge-pNDWACXB.js} +2 -2
  204. package/dashboard/dist/assets/{knowledge-D4SvdNv5.js.map → knowledge-pNDWACXB.js.map} +1 -1
  205. package/dashboard/dist/assets/{mcp-query-CLP9EnnU.js → mcp-query-CmNjvxTG.js} +2 -2
  206. package/dashboard/dist/assets/{mcp-query-CLP9EnnU.js.map → mcp-query-CmNjvxTG.js.map} +1 -1
  207. package/dashboard/dist/assets/{mcp-DVxt4T9J.js → mcp-xddLBwUW.js} +2 -2
  208. package/dashboard/dist/assets/{mcp-DVxt4T9J.js.map → mcp-xddLBwUW.js.map} +1 -1
  209. package/dashboard/dist/assets/pipelines-B05sd2nB.js +2 -0
  210. package/dashboard/dist/assets/pipelines-B05sd2nB.js.map +1 -0
  211. package/dashboard/dist/assets/roles-bRgaMcdy.js +2 -0
  212. package/dashboard/dist/assets/roles-bRgaMcdy.js.map +1 -0
  213. package/dashboard/dist/assets/tasks-Bm1OKrJA.js +2 -0
  214. package/dashboard/dist/assets/{tasks-1eTuP02d.js.map → tasks-Bm1OKrJA.js.map} +1 -1
  215. package/dashboard/dist/assets/{topics-B3p8K0PW.js → topics-BVIqtmd4.js} +2 -2
  216. package/dashboard/dist/assets/{topics-B3p8K0PW.js.map → topics-BVIqtmd4.js.map} +1 -1
  217. package/dashboard/dist/assets/useEventHooks-_qCzU74s.js +2 -0
  218. package/dashboard/dist/assets/useEventHooks-_qCzU74s.js.map +1 -0
  219. package/dashboard/dist/assets/{useNamespace-Dx81_JM0.js → useNamespace-CDnCSFpG.js} +2 -2
  220. package/dashboard/dist/assets/{useNamespace-Dx81_JM0.js.map → useNamespace-CDnCSFpG.js.map} +1 -1
  221. package/dashboard/dist/assets/{useYamlActivityEvents-D5T3TbE7.js → useYamlActivityEvents-zrHMhaFM.js} +2 -2
  222. package/dashboard/dist/assets/{useYamlActivityEvents-D5T3TbE7.js.map → useYamlActivityEvents-zrHMhaFM.js.map} +1 -1
  223. package/dashboard/dist/assets/{users-BEMysNdR.js → users-BPBMZg27.js} +2 -2
  224. package/dashboard/dist/assets/{users-BEMysNdR.js.map → users-BPBMZg27.js.map} +1 -1
  225. package/dashboard/dist/assets/{vendor-icons--Ivmp-RX.js → vendor-icons-C1zVP_dv.js} +125 -115
  226. package/dashboard/dist/assets/vendor-icons-C1zVP_dv.js.map +1 -0
  227. package/dashboard/dist/assets/workflows-CT6nTL1I.js +2 -0
  228. package/dashboard/dist/assets/workflows-CT6nTL1I.js.map +1 -0
  229. package/dashboard/dist/assets/{yaml-workflows-4rJ5v5rJ.js → yaml-workflows-CdfjkOKU.js} +2 -2
  230. package/dashboard/dist/assets/{yaml-workflows-4rJ5v5rJ.js.map → yaml-workflows-CdfjkOKU.js.map} +1 -1
  231. package/dashboard/dist/index.html +3 -3
  232. package/docs/api/http/escalations.md +82 -6
  233. package/docs/api/http/roles.md +82 -3
  234. package/docs/api/mcp/admin.md +127 -1
  235. package/docs/api/sdk/escalations.md +65 -4
  236. package/docs/api/sdk/roles.md +81 -0
  237. package/docs/cli.md +2 -0
  238. package/docs/dashboard.md +17 -2
  239. package/docs/hitl-guide.md +12 -3
  240. package/docs/operations.md +113 -0
  241. package/package.json +3 -2
  242. package/dashboard/dist/assets/AgentsPage-Blhh2RsK.js +0 -2
  243. package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js +0 -2
  244. package/dashboard/dist/assets/AvailableEscalationsPage-ClwAle76.js.map +0 -1
  245. package/dashboard/dist/assets/HomePage-BZ1YTrjR.js +0 -2
  246. package/dashboard/dist/assets/HomePage-BZ1YTrjR.js.map +0 -1
  247. package/dashboard/dist/assets/RolesPage-DLnaW6iD.js +0 -2
  248. package/dashboard/dist/assets/RolesPage-DLnaW6iD.js.map +0 -1
  249. package/dashboard/dist/assets/StatusBadge-Bl3FXVmF.js +0 -2
  250. package/dashboard/dist/assets/StatusBadge-Bl3FXVmF.js.map +0 -1
  251. package/dashboard/dist/assets/StreamMessageDetail-CVRVWXcU.js +0 -2
  252. package/dashboard/dist/assets/YamlWorkflowsPage-CJE-PxC0.js +0 -2
  253. package/dashboard/dist/assets/controlplane-D9HaFZsC.js +0 -2
  254. package/dashboard/dist/assets/controlplane-D9HaFZsC.js.map +0 -1
  255. package/dashboard/dist/assets/index-B1kc6itM.js.map +0 -1
  256. package/dashboard/dist/assets/index-CN0efCE9.js +0 -6
  257. package/dashboard/dist/assets/index-nO0cim3_.css +0 -1
  258. package/dashboard/dist/assets/pipelines-C_x0LTBN.js +0 -2
  259. package/dashboard/dist/assets/pipelines-C_x0LTBN.js.map +0 -1
  260. package/dashboard/dist/assets/roles-QaGFZQ58.js +0 -2
  261. package/dashboard/dist/assets/roles-QaGFZQ58.js.map +0 -1
  262. package/dashboard/dist/assets/tasks-1eTuP02d.js +0 -2
  263. package/dashboard/dist/assets/useEventHooks-BNZky4xM.js +0 -2
  264. package/dashboard/dist/assets/useEventHooks-BNZky4xM.js.map +0 -1
  265. package/dashboard/dist/assets/vendor-icons--Ivmp-RX.js.map +0 -1
  266. package/dashboard/dist/assets/workflows-C4rjvQbI.js +0 -2
  267. package/dashboard/dist/assets/workflows-C4rjvQbI.js.map +0 -1
@@ -36,13 +36,13 @@ GET /api/escalations
36
36
 
37
37
  | Parameter | Type | Description |
38
38
  |-----------|------|-------------|
39
- | `status` | `string` | `pending`, `resolved`, or `cancelled` |
39
+ | `status` | `string` | `pending`, `resolved`, `cancelled`, or `expired` |
40
40
  | `role` | `string` | Filter by target role |
41
41
  | `type` | `string` | Filter by escalation type |
42
42
  | `subtype` | `string` | Filter by subtype |
43
43
  | `assigned_to` | `string` | Filter by claimer's user ID |
44
44
  | `priority` | `integer` | Filter by priority (1–4) |
45
- | `search` | `string` | Free-text across description/type/role/ids/metadata values (server-side) |
45
+ | `search` | `string` | Exact-match by correlation id — escalation id, workflow id, or origin id (server-side, index-served). To match a value inside metadata, use `facets` |
46
46
  | `sort_by` / `order` | `string` | Single-column sort + direction (`asc`/`desc`) |
47
47
  | `limit` | `integer` | Max results (default: 50) |
48
48
  | `offset` | `integer` | Pagination offset (default: 0) |
@@ -419,6 +419,82 @@ Returns distinct escalation type values across all escalations.
419
419
  }
420
420
  ```
421
421
 
422
+ ## Station Metrics
423
+
424
+ ```
425
+ GET /api/escalations/station-metrics
426
+ ```
427
+
428
+ Per-role operational metrics for all visible stations. Returns queue depth, throughput efficiency, wait time (creation → claim) and work time (claim → resolution) at multiple percentiles. This drives the Operations pace chart and station detail panel.
429
+
430
+ RBAC: `superadmin` sees all stations; other roles see only stations for their assigned roles.
431
+
432
+ **Query parameters:**
433
+
434
+ | Parameter | Type | Default | Description |
435
+ |-----------|------|---------|-------------|
436
+ | `period` | `string` | `24h` | Lookback window for resolved/wait/work metrics. One of `15m`, `1h`, `24h`, `7d`, `30d` |
437
+
438
+ **Response 200:**
439
+
440
+ ```json
441
+ {
442
+ "stations": [
443
+ {
444
+ "role": "reviewer",
445
+ "pending": 12,
446
+ "claimed": 3,
447
+ "resolved": 45,
448
+ "in_arrears": 2,
449
+ "throughput_pct": 112.5,
450
+ "wait": {
451
+ "p99": 18.3,
452
+ "p50": 4.1,
453
+ "avg": 5.2,
454
+ "max": 22.0
455
+ },
456
+ "work": {
457
+ "p99": 28.7,
458
+ "p50": 14.0,
459
+ "avg": 15.3,
460
+ "max": 35.1
461
+ }
462
+ }
463
+ ]
464
+ }
465
+ ```
466
+
467
+ **Response fields:**
468
+
469
+ | Field | Type | Description |
470
+ |-------|------|-------------|
471
+ | `role` | `string` | Role key |
472
+ | `pending` | `number` | Escalations currently pending (real-time) |
473
+ | `claimed` | `number` | Escalations actively claimed (real-time) |
474
+ | `resolved` | `number` | Escalations resolved within the selected period |
475
+ | `in_arrears` | `number` | Pending escalations that have exceeded the role's `sla_minutes` target |
476
+ | `throughput_pct` | `number \| null` | `resolved / (target_per_hour × period_hours) × 100`. `null` when the role has no `target_per_hour` set |
477
+ | `wait.p99` | `number \| null` | 99th-percentile wait time in minutes (creation → first claim) within the period. `null` when no resolved items |
478
+ | `wait.p50` | `number \| null` | Median wait time in minutes |
479
+ | `wait.avg` | `number \| null` | Mean wait time in minutes |
480
+ | `wait.max` | `number \| null` | Max wait time in minutes |
481
+ | `work.p99` | `number \| null` | 99th-percentile work time in minutes (claim → resolution) |
482
+ | `work.p50` | `number \| null` | Median work time |
483
+ | `work.avg` | `number \| null` | Mean work time |
484
+ | `work.max` | `number \| null` | Max work time |
485
+
486
+ **Notes:**
487
+ - `pending` and `claimed` reflect the live queue state, not the selected period.
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.
490
+ - Time values are in decimal minutes.
491
+
492
+ **Example:** Fetch station metrics for the last hour:
493
+
494
+ ```
495
+ GET /api/escalations/station-metrics?period=1h
496
+ ```
497
+
422
498
  ## Get escalation stats
423
499
 
424
500
  ```
@@ -431,7 +507,7 @@ Aggregated escalation statistics. RBAC-scoped: superadmins see all; others see o
431
507
 
432
508
  | Parameter | Type | Description |
433
509
  |-----------|------|-------------|
434
- | `period` | `string` | Time period filter (e.g., `24h`, `7d`) |
510
+ | `period` | `string` | Counting window for created/resolved. One of `1h`, `24h`, `7d`, `30d` (default `24h`; other values fall back to `24h`). Station metrics additionally support `15m` |
435
511
 
436
512
  **Response 200:**
437
513
 
@@ -804,7 +880,7 @@ Release a claimed escalation back to the available pool. Only the user who holds
804
880
  | `subtype` | `string` | Subcategory for finer routing |
805
881
  | `modality` | `string` | Modality from workflow config |
806
882
  | `description` | `string` | Human-readable reason |
807
- | `status` | `string` | `pending`, `resolved`, or `cancelled` |
883
+ | `status` | `string` | `pending`, `resolved`, `cancelled`, or `expired` |
808
884
  | `priority` | `integer` | Numeric priority |
809
885
  | `task_id` | `UUID` | FK to the task that triggered this escalation |
810
886
  | `origin_id` | `string` | Correlation ID from the parent orchestrator |
@@ -828,7 +904,7 @@ See [Data Model](../data.md) for the full SQL schema and index strategy.
828
904
 
829
905
  ## Metadata Candidate Key Operations
830
906
 
831
- These endpoints find, claim, and resolve escalations using a business-domain key stored in the `metadata` JSONB column (e.g., `orderId`). No raw SQL needed the GIN index makes lookups fast.
907
+ These endpoints find, claim, and resolve escalations using a business-domain key stored in the `metadata` JSONB column (e.g., `orderId`). Lookups go straight through the GIN index on `metadata`, so they stay fast at any scale.
832
908
 
833
909
  All three endpoints accept an optional `assignee` field — an `external_id` from your auth system. Long Tail resolves it to an internal userId. When omitted, the authenticated caller is used.
834
910
 
@@ -844,7 +920,7 @@ Scoped to the caller's read access. A `member` with `read_scope=self` matches on
844
920
  |-----------|------|-------------|
845
921
  | `key` | `string` | **Required.** Metadata field name |
846
922
  | `value` | `string` | **Required.** Metadata field value |
847
- | `status` | `string` | Filter by status (`pending`, `resolved`, `cancelled`) |
923
+ | `status` | `string` | Filter by status (`pending`, `resolved`, `cancelled`, `expired`) |
848
924
  | `limit` | `integer` | Max results (default 50) |
849
925
  | `offset` | `integer` | Pagination offset (default 0) |
850
926
 
@@ -231,19 +231,49 @@ Returns all distinct role names known to the system.
231
231
  GET /api/roles/details
232
232
  ```
233
233
 
234
- Returns all roles with usage counts.
234
+ Returns all roles with metadata and usage counts.
235
235
 
236
236
  **Response 200:**
237
237
 
238
238
  ```json
239
239
  {
240
240
  "roles": [
241
- { "role": "reviewer", "user_count": 5 },
242
- { "role": "senior-reviewer", "user_count": 2 }
241
+ {
242
+ "role": "reviewer",
243
+ "title": "Document Reviewer",
244
+ "description": "Reviews flagged documents for compliance",
245
+ "form_schema": null,
246
+ "metadata_schema": null,
247
+ "properties": {},
248
+ "ops_visible": true,
249
+ "parent_role": null,
250
+ "sla_minutes": 30,
251
+ "target_per_hour": 20,
252
+ "worker_count": 4,
253
+ "user_count": 5,
254
+ "chain_count": 2,
255
+ "workflow_count": 3
256
+ }
243
257
  ]
244
258
  }
245
259
  ```
246
260
 
261
+ | Field | Type | Description |
262
+ |-------|------|-------------|
263
+ | `title` | `string \| null` | Display name separate from the technical role key |
264
+ | `description` | `string \| null` | Human-readable summary |
265
+ | `form_schema` | `object \| null` | JSON Schema for the escalation resolve form (overridden per-workflow by `resolver_schema`) |
266
+ | `metadata_schema` | `object \| null` | JSON Schema declaring the expected shape of `lt_escalations.metadata` for this role. Drives faceted-query key autocomplete and creation-time validation |
267
+ | `properties` | `object` | Free user-owned bag — icons, colors, tags, etc. No reserved keys |
268
+ | `ops_visible` | `boolean` | When `true`, the role appears as a station on the `/operations` view |
269
+ | `parent_role` | `string \| null` | Parent role in the process dependency graph; `null` for root stations |
270
+ | `sla_minutes` | `number \| null` | Target resolution time in minutes (capacity setting) |
271
+ | `target_per_hour` | `number \| null` | Intended throughput — items resolved per hour (capacity setting) |
272
+ | `worker_count` | `number \| null` | Capacity at this station — staff or machine count (capacity setting) |
273
+ | `user_count` | `number` | Number of users assigned this role |
274
+ | `chain_count` | `number` | Number of escalation chain entries referencing this role |
275
+ | `workflow_count` | `number` | Number of workflow configs that reference this role |
276
+
247
277
  ### Create a role
248
278
 
249
279
  ```
@@ -306,6 +336,55 @@ Delete a role if it has no references. Requires admin.
306
336
  { "error": "Cannot delete role" }
307
337
  ```
308
338
 
339
+ ### Update a role
340
+
341
+ ```
342
+ PATCH /api/roles/:role
343
+ ```
344
+
345
+ Update role metadata. Only provided fields are changed; omitted fields remain unchanged. `form_schema`, `metadata_schema`, and `parent_role` can be explicitly set to `null` to clear them. Requires role manager (admin type, superadmin, or engineer).
346
+
347
+ **Path parameters:**
348
+
349
+ | Parameter | Description |
350
+ |-----------|-------------|
351
+ | `role` | Role key to update |
352
+
353
+ **Request body** (all fields optional):
354
+
355
+ | Field | Type | Description |
356
+ |-------|------|-------------|
357
+ | `title` | `string \| null` | Display name |
358
+ | `description` | `string \| null` | Short description |
359
+ | `form_schema` | `object \| null` | JSON Schema for the resolve form |
360
+ | `metadata_schema` | `object \| null` | JSON Schema for `lt_escalations.metadata` |
361
+ | `properties` | `object \| null` | Free user-owned bag |
362
+ | `ops_visible` | `boolean` | Include in the `/operations` view |
363
+ | `parent_role` | `string \| null` | Parent in the process dependency graph |
364
+ | `sla_minutes` | `number \| null` | SLA target in minutes |
365
+ | `target_per_hour` | `number \| null` | Throughput target (items per hour) |
366
+ | `worker_count` | `number \| null` | Station capacity |
367
+
368
+ **Example request** — configure a role as a station in the ops view:
369
+
370
+ ```json
371
+ {
372
+ "title": "Document Reviewer",
373
+ "ops_visible": true,
374
+ "sla_minutes": 30,
375
+ "target_per_hour": 20,
376
+ "worker_count": 4
377
+ }
378
+ ```
379
+
380
+ **Response 200:** Updated `RoleDetail` object (same shape as `GET /api/roles/details`).
381
+
382
+ **Response 404:**
383
+
384
+ ```json
385
+ { "error": "Role 'unknown-role' not found" }
386
+ ```
387
+
309
388
  ---
310
389
 
311
390
  ## Escalation Chains
@@ -74,7 +74,7 @@ including `metadata`, workflow linkage, assignment, and `signal_key`.
74
74
  | type | string | No | Filter by type |
75
75
  | subtype | string | No | Filter by subtype |
76
76
  | assigned_to | string | No | Filter by assigned user UUID (active claim holder) |
77
- | search | string | No | Free-text search across description, type/subtype, role, workflow/origin id, and metadata values (e.g. a correlation key like an order id). Server-side over the full result set. |
77
+ | search | string | No | Exact-match lookup by correlation id — escalation id, workflow id, or origin id (order/ticket). Index-served, server-side over the full result set. To match a value inside metadata (e.g. an order id), use `facets`. |
78
78
  | priority | integer | No | Filter by priority |
79
79
  | sort_by | string | No | Sort column: created_at, priority, updated_at |
80
80
  | order | string | No | Sort direction (asc, desc) for sort_by |
@@ -722,6 +722,30 @@ Create a new role. Lowercase alphanumeric with hyphens/underscores.
722
722
  |-------|------|----------|-------------|
723
723
  | role | string | Yes | Role name |
724
724
 
725
+ ### update_role
726
+
727
+ Update a role's metadata: display name, description, form schema, metadata schema, free properties bag, operations visibility, process parent, and the typed operational targets (SLA minutes, throughput goal, worker count). Only provided fields are changed.
728
+
729
+ | | |
730
+ |---|---|
731
+ | Read-safe | No |
732
+
733
+ **Parameters:**
734
+
735
+ | Field | Type | Required | Description |
736
+ |-------|------|----------|-------------|
737
+ | `role` | `string` | Yes | Role key to update |
738
+ | `title` | `string \| null` | No | Display name |
739
+ | `description` | `string \| null` | No | Short description |
740
+ | `form_schema` | `object \| null` | No | JSON Schema for the escalation resolve form |
741
+ | `metadata_schema` | `object \| null` | No | JSON Schema for `lt_escalations.metadata` shape validation |
742
+ | `properties` | `object \| null` | No | Free user-owned bag (icon, color, tags, etc.) |
743
+ | `ops_visible` | `boolean` | No | When `true`, role appears as a station on the Operations view |
744
+ | `parent_role` | `string \| null` | No | Parent role in the process dependency graph |
745
+ | `sla_minutes` | `number \| null` | No | Target resolution time in minutes |
746
+ | `target_per_hour` | `number \| null` | No | Throughput goal (items resolved per hour) |
747
+ | `worker_count` | `number \| null` | No | Station capacity (staff or machines) |
748
+
725
749
  ### add_escalation_chain
726
750
 
727
751
  Define an escalation path from one role to another.
@@ -1428,3 +1452,105 @@ Return the numeric status semaphore for a workflow.
1428
1452
  | Field | Type | Required | Description |
1429
1453
  |-------|------|----------|-------------|
1430
1454
  | workflow_id | string | Yes | Workflow ID |
1455
+
1456
+ ## Ortho Pipeline
1457
+
1458
+ AI-operable tools for driving the orthotic manufacturing pipeline. Each order passes through eight sequential stages (design → review → print → grind → glue → finish → qa → ship). The pipeline is a HotMesh durable workflow; each stage suspends at a `conditionLT` checkpoint until an escalation is resolved.
1459
+
1460
+ A Claude agent loop calls `ortho_submit` to start an order, polls `ortho_pending` to see what's waiting, drives each stage forward with `ortho_complete_stage`, and monitors progress with `ortho_status`.
1461
+
1462
+ ### ortho_submit
1463
+
1464
+ Start a new orthotic manufacturing order through the 8-stage pipeline.
1465
+
1466
+ | | |
1467
+ |---|---|
1468
+ | Read-safe | No |
1469
+
1470
+ **Parameters:**
1471
+
1472
+ | Field | Type | Required | Description |
1473
+ |-------|------|----------|-------------|
1474
+ | `order_id` | `string` | Yes | Unique order identifier (e.g. `"ORD-001"`) |
1475
+ | `item_type` | `string` | Yes | Item type (e.g. `"insole-standard"`, `"insole-diabetic"`) |
1476
+ | `stages` | `string[]` | No | Override the stage sequence. Default: `["design","review","print","grind","glue","finish","qa","ship"]` |
1477
+ | `metadata` | `object` | No | Additional order metadata passed through to each stage escalation |
1478
+
1479
+ **Returns:** `{ workflow_id, order_id, item_type, stages, message }`
1480
+
1481
+ ---
1482
+
1483
+ ### ortho_pending
1484
+
1485
+ List open ortho-pipeline stage escalations waiting to be completed.
1486
+
1487
+ | | |
1488
+ |---|---|
1489
+ | Read-safe | Yes |
1490
+
1491
+ **Parameters:**
1492
+
1493
+ | Field | Type | Required | Description |
1494
+ |-------|------|----------|-------------|
1495
+ | `stage` | `string` | No | Filter to a specific stage (e.g. `"design"`). Omit to see all stages |
1496
+ | `limit` | `integer` | No | Max results (default: 50) |
1497
+
1498
+ **Returns:** `{ count, escalations }` where each escalation includes `id`, `stage`, `order_id`, `item_type`, `description`, `created_at`, `workflow_id`.
1499
+
1500
+ ---
1501
+
1502
+ ### ortho_complete_stage
1503
+
1504
+ Complete a pending ortho pipeline stage. Claims the escalation and resolves it with notes and outcome data. Resolving automatically advances the workflow — a new escalation for the next stage appears within seconds.
1505
+
1506
+ | | |
1507
+ |---|---|
1508
+ | Read-safe | No |
1509
+
1510
+ **Parameters:**
1511
+
1512
+ | Field | Type | Required | Description |
1513
+ |-------|------|----------|-------------|
1514
+ | `escalation_id` | `string` | Yes | Escalation ID from `ortho_pending` |
1515
+ | `notes` | `string` | Yes | Completion notes — what was done, any decisions made |
1516
+ | `outcome` | `object` | No | Structured outcome data specific to this stage |
1517
+
1518
+ **Returns:** `{ resolved, escalation_id, status, message }`
1519
+
1520
+ ---
1521
+
1522
+ ### ortho_status
1523
+
1524
+ Get the current status and completed stage results for an ortho pipeline workflow.
1525
+
1526
+ | | |
1527
+ |---|---|
1528
+ | Read-safe | Yes |
1529
+
1530
+ **Parameters:**
1531
+
1532
+ | Field | Type | Required | Description |
1533
+ |-------|------|----------|-------------|
1534
+ | `workflow_id` | `string` | Yes | Workflow ID from `ortho_submit` |
1535
+
1536
+ **Returns:** `{ workflow_id, status }` where `status` is `"running"` while in progress or `"complete"` with `result` containing all stage outputs once finished.
1537
+
1538
+ ---
1539
+
1540
+ **Agent loop example:**
1541
+
1542
+ ```
1543
+ ortho_submit({ order_id: "ORD-042", item_type: "insole-diabetic" })
1544
+ → { workflow_id: "wf-abc123", stages: ["design", "review", ...] }
1545
+
1546
+ ortho_pending({ stage: "design" })
1547
+ → [{ id: "esc-001", stage: "design", order_id: "ORD-042" }]
1548
+
1549
+ ortho_complete_stage({ escalation_id: "esc-001", notes: "3mm heel, D-width approved", outcome: { spec_version: "v2" } })
1550
+ → { resolved: true }
1551
+
1552
+ ... repeat through all 8 stages ...
1553
+
1554
+ ortho_status({ workflow_id: "wf-abc123" })
1555
+ → { status: "complete", result: { order_id: "ORD-042", results: [...] } }
1556
+ ```
@@ -79,7 +79,7 @@ const faceted = await lt.escalations.list({
79
79
 
80
80
  | Field | Type | Required | Description |
81
81
  |-------|------|----------|-------------|
82
- | `status` | `string` | No | Filter by `pending`, `resolved`, or `cancelled` |
82
+ | `status` | `string` | No | Filter by `pending`, `resolved`, `cancelled`, or `expired` |
83
83
  | `role` | `string` | No | Filter by assigned role |
84
84
  | `roles` | `string[]` | No | Restrict to these roles (`role = ANY`) — narrows within the caller's scope, never widens past it |
85
85
  | `type` | `string` | No | Filter by workflow type |
@@ -91,6 +91,7 @@ const faceted = await lt.escalations.list({
91
91
  | `range` | `{ facet, op, value }[]` | No | Numeric range over a metadata facet, e.g. `{ facet: 'confidence', op: '<=', value: 0.7 }` |
92
92
  | `exists` | `string[]` | No | Metadata keys that must be present — `metadata ? key` |
93
93
  | `available` | `boolean` | No | `true` = unclaimed/expired only; `false` = held now |
94
+ | `search` | `string` | No | Exact-match by correlation id — escalation id, workflow id, or origin id (index-served). To match a value inside metadata, use `facets` instead |
94
95
  | `limit` | `number` | No | Max results (default: 50) |
95
96
  | `offset` | `number` | No | Pagination offset |
96
97
  | `sort_by` | `string` | No | Column to sort by (e.g. `created_at`, `priority`) |
@@ -365,7 +366,7 @@ Pass an escalation config as the second argument. The escalation row is written
365
366
 
366
367
  `conditionLT` returns `T | false | null`:
367
368
  - `T` — the resolver's payload (normal resolution)
368
- - `false` — the escalation timed out (if a timeout was configured)
369
+ - `false` — the SLA timer fired first (`config.timeout`); the row is now `status='expired'`
369
370
  - `null` — the escalation was cancelled (workflow terminated or explicit `POST /api/escalations/:id/cancel`)
370
371
 
371
372
  Always guard for `null` and `false` before accessing the payload:
@@ -386,16 +387,32 @@ export async function stationWorker(envelope: LTEnvelope) {
386
387
  workflowType: 'stationWorker',
387
388
  metadata: { orderId: envelope.data.orderId, station: 'qc' },
388
389
  envelope: { instructions: 'Review and approve or reject' },
390
+ timeout: '24h', // SLA for this worklist row (hotmesh 0.25.1+)
389
391
  });
390
392
 
391
- if (!decision) {
392
- // null = cancelled, false = timeout
393
+ if (decision === false) {
394
+ // SLA passed: the workflow resumed on the timer and the engine transitioned
395
+ // the row pending → expired atomically. A late resolve returns
396
+ // already-expired, and system.escalation.{id}.expired fired for dashboards.
397
+ return { type: 'return' as const, data: { autoRejected: 'sla' } };
398
+ }
399
+ if (decision === null) {
393
400
  return { type: 'return' as const, data: { cancelled: true } };
394
401
  }
395
402
  // decision is clean — the escalation was resolved by the resolve endpoint
396
403
  }
397
404
  ```
398
405
 
406
+ ### SLA-gated waits (`timeout`)
407
+
408
+ `ConditionQueueConfig.timeout` (hotmesh 0.25.1+) arms the same resume timer as
409
+ `condition(signalId, '24h')` **in the same single Leg1 write** that creates the
410
+ escalation row. The race is resolved atomically on both sides: a signal that
411
+ arrives first resolves the row normally and the timer is inert; a timer that
412
+ fires first resumes the workflow with `false` and expires the row in a guarded
413
+ UPDATE, so operators can never resolve into a workflow that already moved on.
414
+ `expiresAt`, by contrast, is display metadata on the row — it arms nothing.
415
+
399
416
  ### Two-step form
400
417
 
401
418
  Create the escalation first (e.g. to enrich routing metadata), then wait:
@@ -860,3 +877,47 @@ const result = await lt.escalations.claimByFacets({
860
877
  ```
861
878
 
862
879
  **Returns:** `LTApiResult<{ claimed }>`.
880
+
881
+ ---
882
+
883
+ ## getStationMetrics
884
+
885
+ Retrieve per-role throughput and latency metrics for all stations visible to the caller. Used by the Operations view to power the pace chart and station table.
886
+
887
+ ```typescript
888
+ const result = await lt.escalations.getStationMetrics({ period: '24h' });
889
+ ```
890
+
891
+ **Parameters:**
892
+
893
+ | Field | Type | Required | Description |
894
+ |-------|------|----------|-------------|
895
+ | `period` | `'1h' \| '24h' \| '7d' \| '30d' \| '15m'` | No | Lookback window for resolved/percentile stats (default `'24h'`) |
896
+
897
+ **Returns:** `LTApiResult<{ stations: StationMetric[] }>`
898
+
899
+ ### StationMetric type
900
+
901
+ ```typescript
902
+ interface StationMetricPeriod {
903
+ p99: number | null; // minutes
904
+ p50: number | null;
905
+ avg: number | null;
906
+ max: number | null;
907
+ }
908
+
909
+ interface StationMetric {
910
+ role: string;
911
+ pending: number; // currently queued (status = pending and not claimed)
912
+ claimed: number; // active — claimed and assignment not expired
913
+ resolved: number; // resolved within the lookback period
914
+ in_arrears: number; // pending items older than sla_minutes
915
+ throughput_pct: number | null; // resolved / (target_per_hour × hours) × 100
916
+ wait: StationMetricPeriod; // queue time: created_at → claimed_at
917
+ work: StationMetricPeriod; // processing time: claimed_at → resolved_at
918
+ }
919
+ ```
920
+
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.
922
+
923
+ **Auth:** Same RBAC as `getStats` — callers see only the stations for roles they hold.
@@ -13,6 +13,50 @@ A role is a task queue worked by its members. Each `member` assignment carries t
13
13
 
14
14
  Scope is set when a role is assigned to a user, via [`lt.users.addRole`](users.md) and [`lt.users.create`](users.md). See [Roles API — Work-Surface Scope](../http/roles.md) for the five member profiles.
15
15
 
16
+ ## RoleDetail type
17
+
18
+ `listWithDetails` and `update` return `RoleDetail` objects:
19
+
20
+ ```typescript
21
+ interface RoleDetail {
22
+ role: string;
23
+ title: string | null;
24
+ description: string | null;
25
+ form_schema: Record<string, any> | null;
26
+ metadata_schema: Record<string, any> | null;
27
+ properties: Record<string, any>;
28
+ ops_visible: boolean;
29
+ parent_role: string | null;
30
+ sla_minutes: number | null;
31
+ target_per_hour: number | null;
32
+ worker_count: number | null;
33
+ user_count: number;
34
+ chain_count: number;
35
+ workflow_count: number;
36
+ }
37
+ ```
38
+
39
+ | Field | Description |
40
+ |-------|-------------|
41
+ | `role` | Unique role key |
42
+ | `title` | Display name shown in the dashboard |
43
+ | `description` | Short description of the role's purpose |
44
+ | `form_schema` | Default JSON Schema for the resolve form; overridden per-escalation by `metadata.form_schema` |
45
+ | `metadata_schema` | JSON Schema for `lt_escalations.metadata`; used for validation and UI hints |
46
+ | `properties` | Free user-owned bag — arbitrary config stored on the role |
47
+ | `ops_visible` | When `true`, the role appears as a station on the Operations view |
48
+ | `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 |
50
+ | `target_per_hour` | Throughput target used to compute `throughput_pct` in station metrics |
51
+ | `worker_count` | Station capacity — number of workers expected to be active |
52
+ | `user_count` | Number of users currently assigned to this role |
53
+ | `chain_count` | Number of escalation chain links originating from this role |
54
+ | `workflow_count` | Number of registered workflows that target this role |
55
+
56
+ The three capacity fields (`sla_minutes`, `target_per_hour`, `worker_count`) power the Operations station detail panel. `ops_visible` controls which roles appear on the `/operations` view. `parent_role` enables the process dependency graph in the pace chart — set it to describe which upstream role feeds this one.
57
+
58
+ ---
59
+
16
60
  ## list
17
61
 
18
62
  List all distinct role names in the system.
@@ -192,3 +236,40 @@ const result = await lt.roles.replaceEscalationTargets({
192
236
  **Returns:** `LTApiResult<{ role, targets }>`
193
237
 
194
238
  **Auth:** Not required
239
+
240
+ ---
241
+
242
+ ## update
243
+
244
+ Update a role's metadata. Only provided fields are changed; omitted fields remain unchanged. `form_schema`, `metadata_schema`, and `parent_role` can be set to `null` to clear them.
245
+
246
+ ```typescript
247
+ const result = await lt.roles.update({
248
+ role: 'reviewer',
249
+ title: 'Document Reviewer',
250
+ ops_visible: true,
251
+ sla_minutes: 30,
252
+ target_per_hour: 20,
253
+ worker_count: 4,
254
+ });
255
+ ```
256
+
257
+ **Parameters:**
258
+
259
+ | Field | Type | Required | Description |
260
+ |-------|------|----------|-------------|
261
+ | `role` | `string` | Yes | Role key to update |
262
+ | `title` | `string \| null` | No | Display name |
263
+ | `description` | `string \| null` | No | Short description |
264
+ | `form_schema` | `object \| null` | No | JSON Schema for the resolve form |
265
+ | `metadata_schema` | `object \| null` | No | JSON Schema for `lt_escalations.metadata` |
266
+ | `properties` | `object \| null` | No | Free user-owned bag |
267
+ | `ops_visible` | `boolean` | No | Show as a station on the Operations view |
268
+ | `parent_role` | `string \| null` | No | Parent role in the process dependency graph |
269
+ | `sla_minutes` | `number \| null` | No | SLA target in minutes |
270
+ | `target_per_hour` | `number \| null` | No | Throughput target (items per hour) |
271
+ | `worker_count` | `number \| null` | No | Station capacity |
272
+
273
+ **Returns:** `LTApiResult<RoleDetail>` — the updated role.
274
+
275
+ **Auth:** Role manager (admin type, superadmin, or engineer)
package/docs/cli.md CHANGED
@@ -63,6 +63,8 @@ Shows pending escalations, active workers, pipeline tools, and event transport.
63
63
  ltc esc list # All escalations
64
64
  ltc esc list --status pending # Pending only
65
65
  ltc esc list --role reviewer --limit 10 # Filter by role
66
+ ltc esc list --search wf-abc123 # Exact-match by escalation / workflow / origin id
67
+ ltc esc find-by-meta orderId ORD-42 # Match a value inside metadata (any status)
66
68
  ltc esc get abc123 # Detail view
67
69
  ltc esc claim abc123 # Claim for yourself
68
70
  ltc esc claim abc123 --duration 60 # Claim for 60 minutes
package/docs/dashboard.md CHANGED
@@ -28,6 +28,7 @@ The sidebar organizes pages into five groups.
28
28
  | Page | Route | Purpose |
29
29
  |------|-------|---------|
30
30
  | **Recent Activity** | `/` | Live event stream and business process overview. |
31
+ | **Operations** | `/operations` | COO shop-floor view — pace chart of actual-vs-target flow across all ops-visible roles, station table with live metrics, and the station detail panel. Visible to any user with ops or builder access. |
31
32
  | **Capabilities** | `/capabilities` | Browse MCP servers grouped by capability category. |
32
33
  | **Agent Automations** | `/agents` | Autonomous event-driven automations. Configure subscriptions, schedules, and knowledge domains. |
33
34
  | **Topics** | `/topics` | Topic catalog — browse all known event topics with descriptions, schemas, and subscriber counts. |
@@ -197,12 +198,13 @@ User Accounts and Service Accounts live on the same page, separated by a tab tog
197
198
 
198
199
  Define roles and configure escalation chains that control how work flows between teams.
199
200
 
200
- - **Role list** — all roles in the system with their type (admin, operator, custom). Click to view assigned users.
201
+ - **Role list** — all roles in the system. Each row shows the role key, title, description, user count, chain count, workflow count, and an OPS badge if `ops_visible` is set.
202
+ - **Role detail** — click a role to open its detail panel: identity fields (title, description), escalation chains, and the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`). Edit these inline and save via `PATCH /api/roles/:role`.
201
203
  - **Create Role** — add a new role. Roles referenced in workflow configs are auto-created, but you can also create them here for organizational clarity.
202
204
  - **Scope picker** — when granting a role at `member` type, a Scope picker offers the five named work-surface profiles: full worker (`all`/`all`, default), see-all-act-own (`all`/`self`), own-items-only (`self`/`self`), read-only auditor (`all`/`none`), and read-only own (`self`/`none`). `admin` and `superadmin` grants show no Scope picker — they always work the whole queue. The picker enforces **write ⊆ read**, so a write breadth wider than the read breadth cannot be selected.
203
205
  - **Escalation chains** — define source → target role mappings. When a reviewer escalates, the chain determines which roles receive the escalation next. Chains are directional (reviewer → engineer → admin) and support multiple targets per source.
204
206
 
205
- **API:** `GET /api/roles` lists roles. `POST /api/roles` creates. `GET /api/roles/escalation-chains` lists chains. `POST /api/roles/escalation-chains` adds a chain.
207
+ **API:** `GET /api/roles` lists roles. `POST /api/roles` creates. `PATCH /api/roles/:role` updates metadata and capacity fields. `GET /api/roles/details` returns full `RoleDetail` shapes. `GET /api/roles/escalation-chains` lists chains. `POST /api/roles/escalation-chains` adds a chain.
206
208
 
207
209
  ### DB Maintenance
208
210
 
@@ -260,6 +262,19 @@ Accessible at `/escalations`. A statistics dashboard for escalation health acros
260
262
  - **Summary cards** — open (pending), claimed (in progress), created (new), and resolved counts for the selected window.
261
263
  - **Role breakdown table** — groups escalations by role so you can see which teams have the most pending work. Useful for identifying bottlenecks and rebalancing workload.
262
264
 
265
+ ### Operations
266
+
267
+ Accessible at `/operations`. The COO shop-floor view — shows actual-vs-target flow across every ops-visible role as a pace chart, with a station table and detail panel below.
268
+
269
+ - **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and the throughput metrics.
270
+ - **Pace chart** — connects all ops-visible 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. Station circles are colored by pace ratio (green ≥ 100%, amber ≥ 60%, red below), with a three-number strip per station: pending, active, resolved.
271
+ - **Station table** — one row per ops-visible role with PENDING, ACTIVE, RESOLVED, P99 WAIT, P99 WORK, and a PRESSURE mini-bar. Stations with in-arrears items show a sub-row with a link to oldest-first queue view.
272
+ - **Station detail panel** — opens on row or circle click. Shows the role's identity, an independent period toggle, and full metric breakdown (wait/work percentiles, SLA target, worker count, links to queue).
273
+
274
+ Roles appear on this view when `ops_visible = true` is set. The capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`) drive the computed metrics. Set these via `PATCH /api/roles/:role` or the Roles admin page. See [Operations](operations.md) for the full concept doc.
275
+
276
+ **API:** `GET /api/escalations/station-metrics?period=24h`
277
+
263
278
  ### Processes Overview
264
279
 
265
280
  Accessible at `/` (home page) and `/processes`. Shows all tracked business processes — each process is a group of related workflow executions sharing an origin ID.