@hotmeshio/long-tail 0.18.0 → 0.19.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 (283) hide show
  1. package/build/api/escalations/index.d.ts +1 -1
  2. package/build/api/escalations/index.js +2 -1
  3. package/build/api/escalations/list.d.ts +11 -0
  4. package/build/api/escalations/list.js +31 -2
  5. package/build/api/settings.js +2 -0
  6. package/build/api/users.d.ts +11 -0
  7. package/build/api/users.js +19 -0
  8. package/build/index.js +6 -0
  9. package/build/lib/uuid.d.ts +11 -0
  10. package/build/lib/uuid.js +20 -0
  11. package/build/modules/search.d.ts +21 -0
  12. package/build/modules/search.js +55 -0
  13. package/build/routes/escalations/list.js +10 -1
  14. package/build/routes/users.js +9 -0
  15. package/build/scripts/ortho-populate.d.ts +3 -1
  16. package/build/scripts/ortho-populate.js +15 -5
  17. package/build/sdk/index.d.ts +1 -0
  18. package/build/services/escalation/batch.js +3 -0
  19. package/build/services/escalation/bulk.js +8 -0
  20. package/build/services/escalation/crud.js +26 -0
  21. package/build/services/escalation/queries.d.ts +14 -1
  22. package/build/services/escalation/queries.js +49 -7
  23. package/build/services/escalation/sql.d.ts +4 -2
  24. package/build/services/escalation/sql.js +4 -0
  25. package/build/services/role/types.d.ts +18 -0
  26. package/build/services/role/types.js +6 -0
  27. package/build/services/user/auth.js +2 -2
  28. package/build/services/user/crud.d.ts +13 -0
  29. package/build/services/user/crud.js +26 -3
  30. package/build/services/user/index.d.ts +1 -1
  31. package/build/services/user/index.js +2 -1
  32. package/build/services/user/sql.d.ts +11 -5
  33. package/build/services/user/sql.js +18 -6
  34. package/build/start/adapters.js +2 -0
  35. package/build/tsconfig.tsbuildinfo +1 -1
  36. package/build/types/startup.d.ts +12 -1
  37. package/dashboard/dist/assets/{AdminDashboard-mULAQuHV.js → AdminDashboard-DPkWtPc1.js} +2 -2
  38. package/dashboard/dist/assets/{AdminDashboard-mULAQuHV.js.map → AdminDashboard-DPkWtPc1.js.map} +1 -1
  39. package/dashboard/dist/assets/{AgentConfigPage-DHdzgXcr.js → AgentConfigPage-DRfnLiQS.js} +6 -6
  40. package/dashboard/dist/assets/{AgentConfigPage-DHdzgXcr.js.map → AgentConfigPage-DRfnLiQS.js.map} +1 -1
  41. package/dashboard/dist/assets/{AgentDetailPage-Du_33U2u.js → AgentDetailPage-CufRZXnT.js} +3 -3
  42. package/dashboard/dist/assets/{AgentDetailPage-Du_33U2u.js.map → AgentDetailPage-CufRZXnT.js.map} +1 -1
  43. package/dashboard/dist/assets/{AgentsPage-4KkQO2Hl.js → AgentsPage-CoCWGhUd.js} +2 -2
  44. package/dashboard/dist/assets/{AgentsPage-4KkQO2Hl.js.map → AgentsPage-CoCWGhUd.js.map} +1 -1
  45. package/dashboard/dist/assets/AvailableEscalationsPage-BSqOctep.js +2 -0
  46. package/dashboard/dist/assets/AvailableEscalationsPage-BSqOctep.js.map +1 -0
  47. package/dashboard/dist/assets/{BotPicker-BaFiLa-H.js → BotPicker-DMojDLlV.js} +2 -2
  48. package/dashboard/dist/assets/{BotPicker-BaFiLa-H.js.map → BotPicker-DMojDLlV.js.map} +1 -1
  49. package/dashboard/dist/assets/BulkAssignModal-DYbM_6Or.js +2 -0
  50. package/dashboard/dist/assets/BulkAssignModal-DYbM_6Or.js.map +1 -0
  51. package/dashboard/dist/assets/CapabilitiesPage-CDQ5JHNP.js +2 -0
  52. package/dashboard/dist/assets/{CapabilitiesPage-Cewd6Uku.js.map → CapabilitiesPage-CDQ5JHNP.js.map} +1 -1
  53. package/dashboard/dist/assets/{CollapsibleSection-D1WIbyDa.js → CollapsibleSection-D4VlCEbD.js} +2 -2
  54. package/dashboard/dist/assets/{CollapsibleSection-D1WIbyDa.js.map → CollapsibleSection-D4VlCEbD.js.map} +1 -1
  55. package/dashboard/dist/assets/{ConfirmDeleteModal-CQsJUzEa.js → ConfirmDeleteModal-DnNHjJtD.js} +2 -2
  56. package/dashboard/dist/assets/{ConfirmDeleteModal-CQsJUzEa.js.map → ConfirmDeleteModal-DnNHjJtD.js.map} +1 -1
  57. package/dashboard/dist/assets/CountdownTimer-DPHMBmgz.js +2 -0
  58. package/dashboard/dist/assets/CountdownTimer-DPHMBmgz.js.map +1 -0
  59. package/dashboard/dist/assets/CredentialsPage-CSYZw-rL.js +2 -0
  60. package/dashboard/dist/assets/{CredentialsPage-CwtkQUG3.js.map → CredentialsPage-CSYZw-rL.js.map} +1 -1
  61. package/dashboard/dist/assets/{CronLabel-CRC_uNuC.js → CronLabel-CpmqDrlJ.js} +2 -2
  62. package/dashboard/dist/assets/{CronLabel-CRC_uNuC.js.map → CronLabel-CpmqDrlJ.js.map} +1 -1
  63. package/dashboard/dist/assets/{DropZone-Pv-v5RAs.js → DropZone-BbXlQnYB.js} +2 -2
  64. package/dashboard/dist/assets/{DropZone-Pv-v5RAs.js.map → DropZone-BbXlQnYB.js.map} +1 -1
  65. package/dashboard/dist/assets/{ElapsedCell-CxAi0zN0.js → ElapsedCell-Cul22qBS.js} +2 -2
  66. package/dashboard/dist/assets/{ElapsedCell-CxAi0zN0.js.map → ElapsedCell-Cul22qBS.js.map} +1 -1
  67. package/dashboard/dist/assets/EntityTimelinePanel-CtzpJ-j2.js +2 -0
  68. package/dashboard/dist/assets/EntityTimelinePanel-CtzpJ-j2.js.map +1 -0
  69. package/dashboard/dist/assets/{EscalationListSchemaPage--yZfsE8s.js → EscalationListSchemaPage-BZQ8Y_UH.js} +3 -3
  70. package/dashboard/dist/assets/{EscalationListSchemaPage--yZfsE8s.js.map → EscalationListSchemaPage-BZQ8Y_UH.js.map} +1 -1
  71. package/dashboard/dist/assets/{EscalationSchemaPage-CmoVqaS7.js → EscalationSchemaPage-CydTtq_A.js} +3 -3
  72. package/dashboard/dist/assets/{EscalationSchemaPage-CmoVqaS7.js.map → EscalationSchemaPage-CydTtq_A.js.map} +1 -1
  73. package/dashboard/dist/assets/{EscalationsOverview-DDQTW6Jo.js → EscalationsOverview-DSYC0nI7.js} +2 -2
  74. package/dashboard/dist/assets/{EscalationsOverview-DDQTW6Jo.js.map → EscalationsOverview-DSYC0nI7.js.map} +1 -1
  75. package/dashboard/dist/assets/{EventTable-C5jN7XT7.js → EventTable-s48cTXIw.js} +2 -2
  76. package/dashboard/dist/assets/{EventTable-C5jN7XT7.js.map → EventTable-s48cTXIw.js.map} +1 -1
  77. package/dashboard/dist/assets/{FilterBar-CcIgQH9h.js → FilterBar-B61qKmFD.js} +2 -2
  78. package/dashboard/dist/assets/{FilterBar-CcIgQH9h.js.map → FilterBar-B61qKmFD.js.map} +1 -1
  79. package/dashboard/dist/assets/GraphInvokePage-DxZv_KC2.js +2 -0
  80. package/dashboard/dist/assets/{GraphInvokePage-LACIxaiH.js.map → GraphInvokePage-DxZv_KC2.js.map} +1 -1
  81. package/dashboard/dist/assets/HomePage-zK3VP_9g.js +2 -0
  82. package/dashboard/dist/assets/HomePage-zK3VP_9g.js.map +1 -0
  83. package/dashboard/dist/assets/{ListToolbar-CLwSkmUH.js → ListToolbar-DaxloPQc.js} +2 -2
  84. package/dashboard/dist/assets/{ListToolbar-CLwSkmUH.js.map → ListToolbar-DaxloPQc.js.map} +1 -1
  85. package/dashboard/dist/assets/{McpOverview-C2U1XfQw.js → McpOverview-Ciq8r6-p.js} +2 -2
  86. package/dashboard/dist/assets/{McpOverview-C2U1XfQw.js.map → McpOverview-Ciq8r6-p.js.map} +1 -1
  87. package/dashboard/dist/assets/{McpQueryDetailPage-DYOK8A4D.js → McpQueryDetailPage-DIC0FEEb.js} +3 -3
  88. package/dashboard/dist/assets/{McpQueryDetailPage-DYOK8A4D.js.map → McpQueryDetailPage-DIC0FEEb.js.map} +1 -1
  89. package/dashboard/dist/assets/McpQueryPage-BBy0NSNg.js +2 -0
  90. package/dashboard/dist/assets/{McpQueryPage-Ck75ikSd.js.map → McpQueryPage-BBy0NSNg.js.map} +1 -1
  91. package/dashboard/dist/assets/{McpRunDetailPage-CA9gWQ4L.js → McpRunDetailPage-BqKNmIyW.js} +2 -2
  92. package/dashboard/dist/assets/{McpRunDetailPage-CA9gWQ4L.js.map → McpRunDetailPage-BqKNmIyW.js.map} +1 -1
  93. package/dashboard/dist/assets/{McpRunsPage-BhPshset.js → McpRunsPage-D0RlOpzR.js} +2 -2
  94. package/dashboard/dist/assets/{McpRunsPage-BhPshset.js.map → McpRunsPage-D0RlOpzR.js.map} +1 -1
  95. package/dashboard/dist/assets/NamespacePill-Dbtm9R2T.js +2 -0
  96. package/dashboard/dist/assets/{NamespacePill-DONj6eUU.js.map → NamespacePill-Dbtm9R2T.js.map} +1 -1
  97. package/dashboard/dist/assets/OperationsPage-BX0SFizr.js +3 -0
  98. package/dashboard/dist/assets/OperationsPage-BX0SFizr.js.map +1 -0
  99. package/dashboard/dist/assets/OperatorDashboard-vXG0TjAQ.js +2 -0
  100. package/dashboard/dist/assets/{OperatorDashboard-DZOfHRE7.js.map → OperatorDashboard-vXG0TjAQ.js.map} +1 -1
  101. package/dashboard/dist/assets/{PageHeader-CFVw67M6.js → PageHeader-xB92ELs3.js} +2 -2
  102. package/dashboard/dist/assets/{PageHeader-CFVw67M6.js.map → PageHeader-xB92ELs3.js.map} +1 -1
  103. package/dashboard/dist/assets/{PageHeaderWithStats-D9tQxILm.js → PageHeaderWithStats-DVo_qqn1.js} +2 -2
  104. package/dashboard/dist/assets/{PageHeaderWithStats-D9tQxILm.js.map → PageHeaderWithStats-DVo_qqn1.js.map} +1 -1
  105. package/dashboard/dist/assets/PersonaDetailPage-w5TXcn4Q.js +2 -0
  106. package/dashboard/dist/assets/{PersonaDetailPage-eyHDupL0.js.map → PersonaDetailPage-w5TXcn4Q.js.map} +1 -1
  107. package/dashboard/dist/assets/PersonasPage-Dzcinl1L.js +2 -0
  108. package/dashboard/dist/assets/PersonasPage-Dzcinl1L.js.map +1 -0
  109. package/dashboard/dist/assets/{ProcessDetailPage-CKiAlpOc.js → ProcessDetailPage-BVXieFX1.js} +2 -2
  110. package/dashboard/dist/assets/{ProcessDetailPage-CKiAlpOc.js.map → ProcessDetailPage-BVXieFX1.js.map} +1 -1
  111. package/dashboard/dist/assets/{ProcessesListPage-C4ueZJxU.js → ProcessesListPage-CKKNpk4z.js} +2 -2
  112. package/dashboard/dist/assets/{ProcessesListPage-C4ueZJxU.js.map → ProcessesListPage-CKKNpk4z.js.map} +1 -1
  113. package/dashboard/dist/assets/RoleDetailPage-BytSo-YE.js +8 -0
  114. package/dashboard/dist/assets/RoleDetailPage-BytSo-YE.js.map +1 -0
  115. package/dashboard/dist/assets/{RolePill-Di_5hfvw.js → RolePill-CYpL3a2d.js} +2 -2
  116. package/dashboard/dist/assets/{RolePill-Di_5hfvw.js.map → RolePill-CYpL3a2d.js.map} +1 -1
  117. package/dashboard/dist/assets/RolesPage-eayR9H4f.js +2 -0
  118. package/dashboard/dist/assets/{RolesPage-B3-9Ek0F.js.map → RolesPage-eayR9H4f.js.map} +1 -1
  119. package/dashboard/dist/assets/{RunAsSelector-1k1J1_cv.js → RunAsSelector-D7RPwaAl.js} +2 -2
  120. package/dashboard/dist/assets/{RunAsSelector-1k1J1_cv.js.map → RunAsSelector-D7RPwaAl.js.map} +1 -1
  121. package/dashboard/dist/assets/{ScanCodesPage-CeuVKnpu.js → ScanCodesPage-C8-ZBXF5.js} +2 -2
  122. package/dashboard/dist/assets/{ScanCodesPage-CeuVKnpu.js.map → ScanCodesPage-C8-ZBXF5.js.map} +1 -1
  123. package/dashboard/dist/assets/ScanSchemeDetailPage-tQhEgFKf.js +2 -0
  124. package/dashboard/dist/assets/{ScanSchemeDetailPage-BnivPUJY.js.map → ScanSchemeDetailPage-tQhEgFKf.js.map} +1 -1
  125. package/dashboard/dist/assets/ScanStationPage-CuhqsBKo.js +2 -0
  126. package/dashboard/dist/assets/{ScanStationPage-DCSA7pcV.js.map → ScanStationPage-CuhqsBKo.js.map} +1 -1
  127. package/dashboard/dist/assets/{ScopeBadge-CqIIeWjK.js → ScopeBadge-BmNzZlSj.js} +2 -2
  128. package/dashboard/dist/assets/{ScopeBadge-CqIIeWjK.js.map → ScopeBadge-BmNzZlSj.js.map} +1 -1
  129. package/dashboard/dist/assets/{StickyPagination-BWuKz8uB.js → StickyPagination-BIVTAMnP.js} +2 -2
  130. package/dashboard/dist/assets/{StickyPagination-BWuKz8uB.js.map → StickyPagination-BIVTAMnP.js.map} +1 -1
  131. package/dashboard/dist/assets/{StreamMessageDetail-Cq6AGhgJ.js → StreamMessageDetail-CYSC2cO1.js} +2 -2
  132. package/dashboard/dist/assets/{StreamMessageDetail-Cq6AGhgJ.js.map → StreamMessageDetail-CYSC2cO1.js.map} +1 -1
  133. package/dashboard/dist/assets/{SwimlaneTimeline-DM88avgt.js → SwimlaneTimeline-BMZAs_2K.js} +2 -2
  134. package/dashboard/dist/assets/{SwimlaneTimeline-DM88avgt.js.map → SwimlaneTimeline-BMZAs_2K.js.map} +1 -1
  135. package/dashboard/dist/assets/{TagInput-BLwxTNsI.js → TagInput-D1uszNd2.js} +2 -2
  136. package/dashboard/dist/assets/{TagInput-BLwxTNsI.js.map → TagInput-D1uszNd2.js.map} +1 -1
  137. package/dashboard/dist/assets/{TaskDetailPage-Caqe3fG8.js → TaskDetailPage-CVUDUU5Q.js} +2 -2
  138. package/dashboard/dist/assets/{TaskDetailPage-Caqe3fG8.js.map → TaskDetailPage-CVUDUU5Q.js.map} +1 -1
  139. package/dashboard/dist/assets/{TaskQueuePill-DVgcqd-h.js → TaskQueuePill-C2H8oRfn.js} +2 -2
  140. package/dashboard/dist/assets/{TaskQueuePill-DVgcqd-h.js.map → TaskQueuePill-C2H8oRfn.js.map} +1 -1
  141. package/dashboard/dist/assets/{TasksListPage-DlQwpXOL.js → TasksListPage-DEQymbXC.js} +2 -2
  142. package/dashboard/dist/assets/{TasksListPage-DlQwpXOL.js.map → TasksListPage-DEQymbXC.js.map} +1 -1
  143. package/dashboard/dist/assets/{TimeAgo-BinTjiVC.js → TimeAgo-CCxP67Rb.js} +2 -2
  144. package/dashboard/dist/assets/{TimeAgo-BinTjiVC.js.map → TimeAgo-CCxP67Rb.js.map} +1 -1
  145. package/dashboard/dist/assets/{TimestampCell-DDcfSVeQ.js → TimestampCell-CE5ZUYhV.js} +2 -2
  146. package/dashboard/dist/assets/{TimestampCell-DDcfSVeQ.js.map → TimestampCell-CE5ZUYhV.js.map} +1 -1
  147. package/dashboard/dist/assets/{ToolPill-C6hkOqPx.js → ToolPill-D-h8AoB8.js} +2 -2
  148. package/dashboard/dist/assets/{ToolPill-C6hkOqPx.js.map → ToolPill-D-h8AoB8.js.map} +1 -1
  149. package/dashboard/dist/assets/ToolTestPanel-BHuQTyBY.js +2 -0
  150. package/dashboard/dist/assets/{ToolTestPanel-CZvegH_w.js.map → ToolTestPanel-BHuQTyBY.js.map} +1 -1
  151. package/dashboard/dist/assets/{TopicDetailPage-CShiCwz8.js → TopicDetailPage-SFuiludx.js} +3 -3
  152. package/dashboard/dist/assets/{TopicDetailPage-CShiCwz8.js.map → TopicDetailPage-SFuiludx.js.map} +1 -1
  153. package/dashboard/dist/assets/{TopicsPage-CAYxRRbI.js → TopicsPage-DO8pUmng.js} +2 -2
  154. package/dashboard/dist/assets/{TopicsPage-CAYxRRbI.js.map → TopicsPage-DO8pUmng.js.map} +1 -1
  155. package/dashboard/dist/assets/UserName-CsLnT75E.js +2 -0
  156. package/dashboard/dist/assets/UserName-CsLnT75E.js.map +1 -0
  157. package/dashboard/dist/assets/{WorkflowExecutionPage-DNdXEFcB.js → WorkflowExecutionPage-BttnEvOd.js} +2 -2
  158. package/dashboard/dist/assets/{WorkflowExecutionPage-DNdXEFcB.js.map → WorkflowExecutionPage-BttnEvOd.js.map} +1 -1
  159. package/dashboard/dist/assets/{WorkflowPill-CN-952iI.js → WorkflowPill-CZvBbkn4.js} +2 -2
  160. package/dashboard/dist/assets/{WorkflowPill-CN-952iI.js.map → WorkflowPill-CZvBbkn4.js.map} +1 -1
  161. package/dashboard/dist/assets/{WorkflowsDashboard-D7DPDeuQ.js → WorkflowsDashboard-BRboBhlK.js} +2 -2
  162. package/dashboard/dist/assets/{WorkflowsDashboard-D7DPDeuQ.js.map → WorkflowsDashboard-BRboBhlK.js.map} +1 -1
  163. package/dashboard/dist/assets/{WorkflowsOverview-C7Z0SpDH.js → WorkflowsOverview-CDFTYeQo.js} +2 -2
  164. package/dashboard/dist/assets/{WorkflowsOverview-C7Z0SpDH.js.map → WorkflowsOverview-CDFTYeQo.js.map} +1 -1
  165. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Bxklswko.js → YamlWorkflowDetailPage-CmnZFevp.js} +11 -11
  166. package/dashboard/dist/assets/{YamlWorkflowDetailPage-Bxklswko.js.map → YamlWorkflowDetailPage-CmnZFevp.js.map} +1 -1
  167. package/dashboard/dist/assets/{YamlWorkflowsPage-CkArsPbi.js → YamlWorkflowsPage-Qq1jfcrH.js} +2 -2
  168. package/dashboard/dist/assets/{YamlWorkflowsPage-CkArsPbi.js.map → YamlWorkflowsPage-Qq1jfcrH.js.map} +1 -1
  169. package/dashboard/dist/assets/{agents-Ca0hOp2Y.js → agents-C7vUIO7e.js} +2 -2
  170. package/dashboard/dist/assets/{agents-Ca0hOp2Y.js.map → agents-C7vUIO7e.js.map} +1 -1
  171. package/dashboard/dist/assets/{bots-9GtbGtH9.js → bots-BaOblnW4.js} +2 -2
  172. package/dashboard/dist/assets/{bots-9GtbGtH9.js.map → bots-BaOblnW4.js.map} +1 -1
  173. package/dashboard/dist/assets/{capabilities-C0RpEvyY.js → capabilities-RZpmDWoy.js} +2 -2
  174. package/dashboard/dist/assets/{capabilities-C0RpEvyY.js.map → capabilities-RZpmDWoy.js.map} +1 -1
  175. package/dashboard/dist/assets/{controlplane-ClQiKGyQ.js → controlplane-BwGdcwXR.js} +2 -2
  176. package/dashboard/dist/assets/{controlplane-ClQiKGyQ.js.map → controlplane-BwGdcwXR.js.map} +1 -1
  177. package/dashboard/dist/assets/escalation-columns-B4DG_5v8.js +2 -0
  178. package/dashboard/dist/assets/escalation-columns-B4DG_5v8.js.map +1 -0
  179. package/dashboard/dist/assets/index-8LIpvj2e.js +3 -0
  180. package/dashboard/dist/assets/index-8LIpvj2e.js.map +1 -0
  181. package/dashboard/dist/assets/index-BICLHYJJ.js +2 -0
  182. package/dashboard/dist/assets/{index-BLLK2mzy.js.map → index-BICLHYJJ.js.map} +1 -1
  183. package/dashboard/dist/assets/{index-BLCFN3YR.js → index-BQPUlmmz.js} +2 -2
  184. package/dashboard/dist/assets/{index-BLCFN3YR.js.map → index-BQPUlmmz.js.map} +1 -1
  185. package/dashboard/dist/assets/index-BaC3sbJH.js +67 -0
  186. package/dashboard/dist/assets/index-BaC3sbJH.js.map +1 -0
  187. package/dashboard/dist/assets/index-BuqpU6ow.js +2 -0
  188. package/dashboard/dist/assets/{index-DEr9QjVv.js.map → index-BuqpU6ow.js.map} +1 -1
  189. package/dashboard/dist/assets/index-CD6jtND1.css +1 -0
  190. package/dashboard/dist/assets/{index-Ba3UsZzz.js → index-CsIw-ZLk.js} +4 -4
  191. package/dashboard/dist/assets/{index-Ba3UsZzz.js.map → index-CsIw-ZLk.js.map} +1 -1
  192. package/dashboard/dist/assets/index-CtJkvX9e.js +5 -0
  193. package/dashboard/dist/assets/{index-Ct_8Tpec.js.map → index-CtJkvX9e.js.map} +1 -1
  194. package/dashboard/dist/assets/index-D9NtDRtp.js +2 -0
  195. package/dashboard/dist/assets/{index-BoQirCxt.js.map → index-D9NtDRtp.js.map} +1 -1
  196. package/dashboard/dist/assets/{index-CeHOGQM4.js → index-DU9-flEo.js} +2 -2
  197. package/dashboard/dist/assets/{index-CeHOGQM4.js.map → index-DU9-flEo.js.map} +1 -1
  198. package/dashboard/dist/assets/{index-P1g8r09L.js → index-G3NmdMjt.js} +2 -2
  199. package/dashboard/dist/assets/{index-P1g8r09L.js.map → index-G3NmdMjt.js.map} +1 -1
  200. package/dashboard/dist/assets/index-IWufkcH9.js +2 -0
  201. package/dashboard/dist/assets/{index-DlzW75L4.js.map → index-IWufkcH9.js.map} +1 -1
  202. package/dashboard/dist/assets/index-iegzyfMv.js +2 -0
  203. package/dashboard/dist/assets/{index-B-Qpr29t.js.map → index-iegzyfMv.js.map} +1 -1
  204. package/dashboard/dist/assets/index-xNFTmmsv.js +2 -0
  205. package/dashboard/dist/assets/{index-CG8oLNHo.js.map → index-xNFTmmsv.js.map} +1 -1
  206. package/dashboard/dist/assets/{knowledge-DzueDGkw.js → knowledge-CjwCbm3E.js} +2 -2
  207. package/dashboard/dist/assets/{knowledge-DzueDGkw.js.map → knowledge-CjwCbm3E.js.map} +1 -1
  208. package/dashboard/dist/assets/{mcp-CCOzN8dH.js → mcp-C-DMktCT.js} +2 -2
  209. package/dashboard/dist/assets/{mcp-CCOzN8dH.js.map → mcp-C-DMktCT.js.map} +1 -1
  210. package/dashboard/dist/assets/{mcp-query-UeMDiM6I.js → mcp-query-KBeBNHb4.js} +2 -2
  211. package/dashboard/dist/assets/{mcp-query-UeMDiM6I.js.map → mcp-query-KBeBNHb4.js.map} +1 -1
  212. package/dashboard/dist/assets/{personas-CKcrzaQX.js → personas-B32sSCxm.js} +2 -2
  213. package/dashboard/dist/assets/{personas-CKcrzaQX.js.map → personas-B32sSCxm.js.map} +1 -1
  214. package/dashboard/dist/assets/{pipelines-orE-1gpj.js → pipelines-DNLwDumm.js} +2 -2
  215. package/dashboard/dist/assets/{pipelines-orE-1gpj.js.map → pipelines-DNLwDumm.js.map} +1 -1
  216. package/dashboard/dist/assets/{tasks-ZOmzxynB.js → tasks-DrWSrjmj.js} +2 -2
  217. package/dashboard/dist/assets/{tasks-ZOmzxynB.js.map → tasks-DrWSrjmj.js.map} +1 -1
  218. package/dashboard/dist/assets/{topics-CdYaOCi_.js → topics-DgzGU-vR.js} +2 -2
  219. package/dashboard/dist/assets/{topics-CdYaOCi_.js.map → topics-DgzGU-vR.js.map} +1 -1
  220. package/dashboard/dist/assets/{useDebouncedValue-D-uGnSj5.js → useDebouncedValue-DG5JOj1F.js} +2 -2
  221. package/dashboard/dist/assets/{useDebouncedValue-D-uGnSj5.js.map → useDebouncedValue-DG5JOj1F.js.map} +1 -1
  222. package/dashboard/dist/assets/{useNamespace-DMrjlrJJ.js → useNamespace-CdgF7Jxo.js} +2 -2
  223. package/dashboard/dist/assets/{useNamespace-DMrjlrJJ.js.map → useNamespace-CdgF7Jxo.js.map} +1 -1
  224. package/dashboard/dist/assets/{useYamlActivityEvents-ByyQgu8S.js → useYamlActivityEvents-BEaOtgSZ.js} +2 -2
  225. package/dashboard/dist/assets/{useYamlActivityEvents-ByyQgu8S.js.map → useYamlActivityEvents-BEaOtgSZ.js.map} +1 -1
  226. package/dashboard/dist/assets/{vendor-icons-h-jlRSb9.js → vendor-icons-BCWsItQ7.js} +138 -133
  227. package/dashboard/dist/assets/{vendor-icons-h-jlRSb9.js.map → vendor-icons-BCWsItQ7.js.map} +1 -1
  228. package/dashboard/dist/assets/{workflows-CLn05FRV.js → workflows-CX_oarls.js} +2 -2
  229. package/dashboard/dist/assets/{workflows-CLn05FRV.js.map → workflows-CX_oarls.js.map} +1 -1
  230. package/dashboard/dist/assets/{yaml-workflows-DFD_HO__.js → yaml-workflows-YASUDPo0.js} +2 -2
  231. package/dashboard/dist/assets/{yaml-workflows-DFD_HO__.js.map → yaml-workflows-YASUDPo0.js.map} +1 -1
  232. package/dashboard/dist/index.html +3 -3
  233. package/docs/dashboard.md +164 -69
  234. package/docs/faceted-routing.md +38 -0
  235. package/docs/hitl/x-lt-list-schema.md +3 -0
  236. package/docs/operations.md +61 -60
  237. package/docs/scan-codes.md +18 -0
  238. package/package.json +1 -1
  239. package/dashboard/dist/assets/AvailableEscalationsPage-CjcAIm-d.js +0 -2
  240. package/dashboard/dist/assets/AvailableEscalationsPage-CjcAIm-d.js.map +0 -1
  241. package/dashboard/dist/assets/BulkAssignModal-DNmji4l-.js +0 -2
  242. package/dashboard/dist/assets/BulkAssignModal-DNmji4l-.js.map +0 -1
  243. package/dashboard/dist/assets/CapabilitiesPage-Cewd6Uku.js +0 -2
  244. package/dashboard/dist/assets/CountdownTimer-BKMmFie6.js +0 -2
  245. package/dashboard/dist/assets/CountdownTimer-BKMmFie6.js.map +0 -1
  246. package/dashboard/dist/assets/CredentialsPage-CwtkQUG3.js +0 -2
  247. package/dashboard/dist/assets/EntityTimelinePanel-DzMuV7ZX.js +0 -2
  248. package/dashboard/dist/assets/EntityTimelinePanel-DzMuV7ZX.js.map +0 -1
  249. package/dashboard/dist/assets/GraphInvokePage-LACIxaiH.js +0 -2
  250. package/dashboard/dist/assets/HomePage-DP9Q-x4a.js +0 -2
  251. package/dashboard/dist/assets/HomePage-DP9Q-x4a.js.map +0 -1
  252. package/dashboard/dist/assets/McpQueryPage-Ck75ikSd.js +0 -2
  253. package/dashboard/dist/assets/Modal-BU7No9NH.js +0 -2
  254. package/dashboard/dist/assets/Modal-BU7No9NH.js.map +0 -1
  255. package/dashboard/dist/assets/NamespacePill-DONj6eUU.js +0 -2
  256. package/dashboard/dist/assets/OperationsPage-MlMzl0Bf.js +0 -3
  257. package/dashboard/dist/assets/OperationsPage-MlMzl0Bf.js.map +0 -1
  258. package/dashboard/dist/assets/OperatorDashboard-DZOfHRE7.js +0 -2
  259. package/dashboard/dist/assets/PersonaDetailPage-eyHDupL0.js +0 -2
  260. package/dashboard/dist/assets/PersonasPage-CCtRkWiP.js +0 -2
  261. package/dashboard/dist/assets/PersonasPage-CCtRkWiP.js.map +0 -1
  262. package/dashboard/dist/assets/RoleDetailPage-BOccQCkx.js +0 -8
  263. package/dashboard/dist/assets/RoleDetailPage-BOccQCkx.js.map +0 -1
  264. package/dashboard/dist/assets/RolesPage-B3-9Ek0F.js +0 -2
  265. package/dashboard/dist/assets/ScanSchemeDetailPage-BnivPUJY.js +0 -2
  266. package/dashboard/dist/assets/ScanStationPage-DCSA7pcV.js +0 -2
  267. package/dashboard/dist/assets/ToolTestPanel-CZvegH_w.js +0 -2
  268. package/dashboard/dist/assets/UserName-BovQxdSY.js +0 -2
  269. package/dashboard/dist/assets/UserName-BovQxdSY.js.map +0 -1
  270. package/dashboard/dist/assets/escalation-columns-CZ12_oQF.js +0 -2
  271. package/dashboard/dist/assets/escalation-columns-CZ12_oQF.js.map +0 -1
  272. package/dashboard/dist/assets/index-B-Qpr29t.js +0 -2
  273. package/dashboard/dist/assets/index-BLLK2mzy.js +0 -2
  274. package/dashboard/dist/assets/index-BoQirCxt.js +0 -2
  275. package/dashboard/dist/assets/index-C1oOLjdF.js +0 -3
  276. package/dashboard/dist/assets/index-C1oOLjdF.js.map +0 -1
  277. package/dashboard/dist/assets/index-CG8oLNHo.js +0 -2
  278. package/dashboard/dist/assets/index-CdavRyaX.js +0 -67
  279. package/dashboard/dist/assets/index-CdavRyaX.js.map +0 -1
  280. package/dashboard/dist/assets/index-Ct_8Tpec.js +0 -5
  281. package/dashboard/dist/assets/index-DEr9QjVv.js +0 -2
  282. package/dashboard/dist/assets/index-DlzW75L4.js +0 -2
  283. package/dashboard/dist/assets/index-fUqvRHOe.css +0 -1
package/docs/dashboard.md CHANGED
@@ -10,12 +10,15 @@ The sidebar organizes pages into six groups.
10
10
 
11
11
  The reactive, event-driven surface — where operations watch the floor and builders configure choreography.
12
12
 
13
- | Page | Route | Purpose |
14
- |------|-------|---------|
15
- | **Pace Board** | `/operations` | COO shop-floor view pace chart of actual-vs-target flow across every station role, station table with live metrics, and the station detail panel. Readable by every login (aggregate counts and trends) while `features.publicPaceBoard`, default on, stands. |
16
- | **Event Topics** | `/topics` | Topic catalogbrowse all known event topics with descriptions, schemas, and subscriber counts. |
17
- | **Agents** | `/agents` | Autonomous event-driven automations (labeled **Automations** when AI is not configured). Configure subscriptions, schedules, and knowledge domains. |
18
- | **Capabilities** | `/capabilities` | Browse MCP tools grouped by capability category, with a live run panel. |
13
+ | Page | Route | Icon | Purpose |
14
+ |------|-------|------|---------|
15
+ | **Pace Board** | `/pace` | Gauge | Actual-vs-target flow across a segment of roles a pace chart over the sequence, a live role table, and a role detail panel. Readable by every login (aggregate counts and trends) while `features.publicPaceBoard`, default on, stands. |
16
+ | **Trend Board** | `/trends` | TrendingUp | Where the time went the entity lens over a metadata facet (`serialNumber`, `orderId`): a state-mix summary, dwell rankings, and per-entity cross-queue timelines. Shares the combined board selector with the Pace Board. |
17
+ | **Event Topics** | `/topics` | Radio | Topic catalog browse all known event topics with descriptions, schemas, and subscriber counts. |
18
+ | **Agents** | `/agents` | Bot | Autonomous event-driven automations (labeled **Automations** when AI is not configured). Configure subscriptions, schedules, and knowledge domains. |
19
+ | **Capabilities** | `/capabilities` | Zap | Browse MCP tools grouped by capability category, with a live run panel. |
20
+
21
+ Pace Board and Trend Board are two anchors on one page — the pathname picks the board, and the shared board selector switches between a Pace segment and a Trend lens without a reload. `/operations` redirects to `/pace`. Both entries appear only for logins that may read the board (admins, superadmins, and every login while `features.publicPaceBoard` stands).
19
22
 
20
23
  ### Orchestrate
21
24
 
@@ -49,7 +52,7 @@ The LLM authoring add-on. Appears when an Anthropic key is configured.
49
52
  | Page | Route | Purpose |
50
53
  |------|-------|---------|
51
54
  | **Files** | `/files` | Browse and manage files in connected storage (MinIO/S3/GCS). |
52
- | **Knowledge** | `/knowledge` | Knowledge base entries for workflow context and retrieval. |
55
+ | **Knowledge** | `/knowledge` | Versioned knowledge base domain data (catalogs, reference tables, cascade options) that workflows and resolver forms read at runtime, every edit an immutable edition. |
53
56
 
54
57
  ### Identity & Access
55
58
 
@@ -58,6 +61,7 @@ The LLM authoring add-on. Appears when an Anthropic key is configured.
58
61
  | **Accounts** | `/admin/users` | User accounts and service accounts (bots). Create, edit, assign roles, manage API keys. |
59
62
  | **Roles** | `/admin/roles` | Define roles — the queues, forms, and membership that connect workflows to people. Pace Board dials, capacity settings, versioned schemas, members, and default pins live here. |
60
63
  | **Personas** | `/admin/personas` | Bundle roles into named, one-step assignments. Each linked role carries a relationship scope (write-all, write-self, read-all); assigning a persona composes the member's whole surface from its roles' pins and schemas. |
64
+ | **Scan Codes** | `/admin/scan-codes` | Configure barcode schemes and their scan-driven rules (event-condition-action over escalations). Shown when `features.scanCodes` stands. |
61
65
 
62
66
  ### Infrastructure
63
67
 
@@ -74,11 +78,13 @@ Builder-only.
74
78
  The top navigation bar contains:
75
79
 
76
80
  - **Home logo** — links to the home page (`/`), Recent Activity.
81
+ - **Search bar** — the opt-in global lookup: type an id or facet value, pick a facet, and land on the matching escalation or a filtered queue. Off by default; enable via `search` in `start()` config or `LT_SEARCH_BAR`. See [Global search](#global-search).
77
82
  - **all** — links to `/escalations/available` with a live count of unclaimed escalations.
78
83
  - **mine** — links to `/escalations/queue` with a live count of escalations assigned to you.
84
+ - **scan** (Barcode icon) — opens the scan panel for manual code entry and capture settings, shown when `features.scanCodes` stands. See [Scan Codes](#scan-codes).
79
85
  - **events** — toggles the live event feed (builders and ops; doubles as the connection indicator).
80
86
  - **docs** (BookOpen icon) — toggles the in-app documentation drawer. Each page also has a contextual docs link next to its title that opens the drawer to the relevant section.
81
- - **User menu** — Credentials, theme picker (five accent themes), and Sign Out.
87
+ - **User menu** — **Credentials** (OAuth connections and API keys), **Link variables** (per-device facet bindings that scope pins and the Pace Board — see [Faceted Routing](faceted-routing.md#link-variables)), the **theme picker** (five accent themes), and **Sign Out**.
82
88
 
83
89
  ## Home — Recent Activity
84
90
 
@@ -121,15 +127,16 @@ workers: [
121
127
 
122
128
  ### Invoke Workflow
123
129
 
124
- A two-panel page for starting any invocable procedural workflow. The left panel lists invocable workflows grouped by task queue, with a queue select and search in the filter bar. Workflows with active cron schedules show a clock icon. Selecting a workflow opens the invocation form on the right:
130
+ Accessible at `/workflows/durable/invoke`. A two-panel page for starting any invocable procedural workflow. The left panel lists invocable workflows grouped by task queue, with a queue select and search in the filter bar; each row carries its tier badge, and workflows with an active cron schedule show a clock icon. Selecting a workflow syncs `?type=<WorkflowType>` to the URL and opens the invocation form on the right:
125
131
 
126
- - **Identity summary** — shows who will execute (current user, configured bot, or admin override).
127
- - **Envelope editor** — dual-mode input: a structured form view (when `envelope_schema.data` has scalar fields) or a raw JSON editor. The form auto-generates fields from the schema with inferred types.
128
- - **Start Workflow** button invokes the workflow and navigates to the executions page.
132
+ - **Identity summary** — who will execute: the current user, the workflow's configured `execute_as` bot ("configured default"), or, for admins and superadmins, an override chosen from the bot picker ("admin override"). The invocation runs under that identity's `_scope`.
133
+ - **Certification checkbox** — for a certified workflow, stamps `metadata.certified` on this one run.
134
+ - **Envelope editor** — the envelope is `{ data, metadata }`: `data` holds the workflow input, `metadata` optional context. Two modes that stay in sync: a **Form view** that auto-generates a field per `envelope_schema.data` key (type inferred — text, number, boolean, object) and a raw **JSON view**. When a workflow has no `envelope_schema`, a banner links to the registry to add one.
135
+ - **Start Workflow** button — calls the invoke endpoint and navigates to the executions list.
129
136
 
130
- Recurring (cron) execution is owned by Automations — schedule workflows from the Agents page.
137
+ Recurring (cron) execution is owned by Automations — schedule workflows from the Agents page. The graph equivalent, **Graph → Invoke** (`/mcp/workflows/invoke`), starts a compiled YAML flow from the same shape.
131
138
 
132
- **API:** `POST /api/workflows/:type/invoke` starts a workflow.
139
+ **API:** `POST /api/workflows/:type/invoke` starts a workflow (body `{ data, metadata?, execute_as? }`, returns `202` with the workflow id). `GET /api/workflows/discovered` backs the list; `GET /api/workflows/:type/config` supplies the envelope schema and identity.
133
140
 
134
141
  ### MCP Tool Designer
135
142
 
@@ -193,16 +200,18 @@ Execution history for all graph runs — both dynamic (agentic LLM loops) and co
193
200
 
194
201
  ### Procedural Executions
195
202
 
196
- Lists all procedural workflow runs across the system.
203
+ Accessible at `/workflows/executions`. Lists procedural workflow runs from one HotMesh namespace.
197
204
 
198
- - **Tier filter** (top) switch between All, Certified, and Durable to focus on specific workflow types.
199
- - **Columns:** Workflow name, workflow ID, status (running/completed/failed), start time, and duration.
200
- - **Click any row** to see the full execution detail: the swimlane timeline and events fill the main column, and a full-height side panel carries the record's facts. The main header stays quiet — just the title and a panel toggle; status, the refresh/copy toolbar, and the **Actions** menu (a small caret anchor at the right of the panel's icon row) all live in the panel. The panel and main column share the width as a flex set — the main column narrows as the panel expands.
201
- - **Details** status, workflow identity (type, ID, parent), task queue, start/end times, duration, history size, and activity counts.
202
- - **Escalations** every escalation the workflow raised, each a row with type, role, age, and status badge, so multiple escalations across the run's lifecycle read as a table rather than running on; related child tasks list the same way below.
203
- - **Duration** is computed from start to completion useful for identifying slow workflows or comparing performance across versions.
205
+ - **Namespace** — the `?namespace=` query param names the Postgres schema (HotMesh `app_id`) the list reads from; procedural runs live in `durable`, so the page defaults to `?namespace=durable`. Graph runs live in their own per-app namespaces and are browsed at [Graph Executions](#graph-executions) (`/mcp/executions`).
206
+ - **Tier filter** — All, Certified, or Durable. Certified narrows to workflows with a certified config; Durable narrows to those with none.
207
+ - **Type / Status / Search** filter by workflow type, run status (running / completed / failed), or a workflow-id keyword.
208
+ - **Columns:** Workflow ID (status dot + id), Type (pill with tier variant), Created, Updated, Duration, and hover Actions (filter-by-type, filter-by-status, and for superadmins — a jump to the workflow's registry entry).
209
+ - **Click any row** to open the execution detail (`/workflows/executions/:workflowId`). A tabbed main column — **Details** (input/output envelopes), **Execution Timeline** (the swimlane of activities, signals, timers, and child workflows), **Events** (the raw event stream) sits beside a full-height side panel that carries the record's facts. The panel and main column share the width as a flex set.
210
+ - **Details** (panel) status, workflow identity (type, id, parent), task queue, start/end times, duration, history size, and activity counts.
211
+ - **Escalations** (panel) — every escalation the workflow raised as a row (status dot, type, role, age), each linking to its detail page; related child tasks list below. Empty reads "This workflow has not escalated."
212
+ - **Actions** menu — Restart (prefills a fresh invoke from the start event), Terminate (running runs only), Compile into Pipeline (runs with tool calls), and jumps to worker / engine stream messages.
204
213
 
205
- **API:** `GET /api/workflows/executions` lists runs with tier, status, and pagination filters.
214
+ **API:** `GET /api/workflow-states/jobs?namespace=durable` lists runs (params `entity` for type, `status`, `search`, `registered` for tier, `sort_by`, `order`, `limit`, `offset`). `GET /api/workflow-states/:workflowId/execution` returns the detail. `POST /api/workflows/:workflowId/terminate` stops a running one.
206
215
 
207
216
  ### Accounts
208
217
 
@@ -219,11 +228,11 @@ User Accounts and Service Accounts live on the same page, separated by a tab tog
219
228
 
220
229
  Roles are the system's central organizer and gatekeeper: every hand-off between the digital side (running workflows) and the outside world crosses a role. When a workflow needs something only a person or external actor can provide, it raises an escalation into exactly one role's queue and pauses. Membership in the role grants access to that queue and every escalation it contains; each member's scopes determine which specific combinations of activities they may perform via those escalations — which items appear, which they can claim, resolve, or forward. Resolving an item resumes the workflow exactly where it paused.
221
230
 
222
- Because roles carry the queue, the form schema, the membership, and the capacity targets in one place, they are also the unit everything else is built on: [Accounts](#accounts) grant them, escalation views filter by them, and the [Pace Board](#pace-board) renders them as stations.
231
+ Because roles carry the queue, the form schema, the membership, and the capacity targets in one place, they are also the unit everything else is built on: [Accounts](#accounts) grant them, escalation views filter by them, and the [Pace Board](#pace-board) charts them.
223
232
 
224
233
  **Master list** (`/admin/roles`) — one row per role:
225
234
 
226
- - **Role** — an ops status dot (green marks roles that appear as stations on the [Pace Board](#pace-board)) beside the display name: the user-set title, else Title Case derived from the key.
235
+ - **Role** — an ops status dot (green marks roles shown on the [Pace Board](#pace-board)) beside the display name: the user-set title, else Title Case derived from the key.
227
236
  - **Key** — the exact technical role id.
228
237
  - **Description** — the role's human-facing summary.
229
238
  - **Preceded By** — the role's prior step (`parent_role`), linked. Prior steps compose the Pace Board's sequences.
@@ -238,15 +247,15 @@ Search filters by key, label, or description. **+ Add Role** creates a role here
238
247
 
239
248
  Accessible at `/admin/roles/:role`. One page per role — a quiet header carrying the role's identity, with the configuration organized into a five-section left sub-nav: **Identity · Pace Board · Schemas · Members · Pins**. The active section rides the URL (`?section=pace-board`), so deep links land on the right concern. One draft spans every section — switching sections never loses edits — and the **Save** button sits in the sub-nav footer, visible from every section. (Members, Pins, and Upstream Inputs save live.)
240
249
 
241
- **Identity** — display name and description, shown on role rows and station labels. The danger zone lives here too: a role nothing references can be deleted.
250
+ **Identity** — display name and description, shown on role rows and Pace Board labels. The danger zone lives here too: a role nothing references can be deleted.
242
251
 
243
252
  **Pace Board** — everything the board consumes about this role, in one column:
244
253
 
245
- - **Station** — the toggle that shows the role as a station on the [Pace Board](#pace-board).
254
+ - **Show this role on the Pace Board** — the visibility toggle (`ops_visible`) that charts the role on the [Pace Board](#pace-board).
246
255
  - **Capacity** — `sla_minutes`, `target_per_hour`, and `worker_count`; enter any two and the section hints the derived third (`throughput = workers / (sla / 60)`).
247
- - **Priority** — `priority_threshold_minutes` and the age facet (`priority_facet`) driving the Pace Board priority count and the jeopardy filter (blank = `sla_minutes` and `created_at`). The dials stay editable while the station is hidden — they also drive jeopardy in the queues.
248
- - **Entity** — the metadata key naming what moves through this station (`entity_facet`, e.g. `serialNumber`, `orderId`). Roles sharing a key form that entity's system: the [entity lens](operations.md#entity-lens), per-entity dwell, and timelines all derive from it. Once a key is set, the **States from** picker (`entity_state_source`) chooses how the station names the entity's state — **Station** (being here is one state, e.g. a servicing queue) or **Subtypes** (this one role holds several states named by each escalation's subtype, e.g. a fleet role parking `idle` / `printing`).
249
- - **Sequence** — board geometry, shown while the station is visible: **Prior Step** (places the role in one Pace Board sequence; a role with no prior step starts its own), **Upstream Inputs** (the roles this station also draws from in other sequences — mixin-like, many allowed, saved live, rendered as a merge glyph on the station, never a bend in the line), and **Home Segment** (lead the home Pace Board with this role's sequence; one role holds this).
256
+ - **Priority** — `priority_threshold_minutes` and the age facet (`priority_facet`) driving the Pace Board jeopardy count and the jeopardy filter (blank = `sla_minutes` and `created_at`). The dials stay editable while the role is hidden — they also drive jeopardy in the queues.
257
+ - **Entity** — the metadata key naming what moves through this role (`entity_facet`, e.g. `serialNumber`, `orderId`). Roles sharing a key form that entity's system: the [Trend Board](#trend-board) lens, per-entity dwell, and timelines all derive from it. Once a key is set, the **States from** picker (`entity_state_source`) chooses how the role names the entity's state — **Role** (being here is one state, e.g. a servicing queue) or **Subtypes** (this one role holds several states named by each escalation's subtype, e.g. a fleet role parking `idle` / `printing`).
258
+ - **Sequence** — board geometry, shown while the role is visible: **Prior Step** (places the role in one Pace Board segment; a role with no prior step starts its own), **Upstream Inputs** (the roles this role also draws from in other segments — mixin-like, many allowed, saved live, rendered as a merge glyph, never a bend in the line), and **Home Segment** (lead the home Pace Board with this role's segment; one role holds this).
250
259
 
251
260
  **Schemas** — the role's contracts:
252
261
 
@@ -257,7 +266,7 @@ Accessible at `/admin/roles/:role`. One page per role — a quiet header carryin
257
266
 
258
267
  **Members** — who holds the role: admins manage it; members work its queue according to their read/write work-surface scope (read = which items appear; write = which they can claim and resolve). A `member` grant carries a scope chosen from five named 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`). The picker enforces **write ⊆ read**. `admin` and `superadmin` grants always work the whole queue.
259
268
 
260
- **Pins** — the pinned-view seeds this role hands its members (`default_pins`): label, dashboard-relative URL, optional badge. Members see them in their Pinned nav section from first login (marked role-provided) and may promote, hide, or reorder them via preferences. Live-save.
269
+ **Pins** — two live-save groups. **Link Variables** leads: the facet names members bind per device (`properties.link_variables` — name, optional label, optional default). A pin below may reference a variable as a facet value, `facets={"facility":"{lt:facility}"}`; each member device opens it scoped to its own binding (set from the user menu → Link variables), falling back to the declared default or, unbound, applying no filter. A caption under each templated pin previews the binding on the viewing device (`facility = 'soleful'` / `facility = <empty>`). **Default Pins** follows — the pinned-view seeds this role hands its members (`default_pins`): label, dashboard-relative URL, optional badge. Members see them in their Pinned nav section from first login (marked role-provided) and may promote, hide, or reorder them via preferences; promoting a templated pin copies the template, so it keeps following the device's bindings. See [Faceted Routing — Link variables](faceted-routing.md#link-variables).
261
270
 
262
271
  **API:** `PATCH /api/roles/:role` updates identity, Pace Board dials, placement, schemas, and pins.
263
272
 
@@ -293,6 +302,26 @@ Accessible at `/admin/personas` for admins, superadmins, and engineers — the s
293
302
 
294
303
  **API:** `GET /api/personas` lists. `POST /api/personas` creates; `PATCH`/`DELETE /api/personas/:key` edit and remove. `PUT`/`DELETE /api/personas/:key/roles/:role` manage links. `POST /api/personas/seed` applies a declarative spec set idempotently.
295
304
 
305
+ ### Scan Codes
306
+
307
+ Scan codes turn a barcode into an action on an escalation — a floor operator scans a printed code and an item is claimed, resolved, escalated, or opened, with no keyboard. The dashboard captures scans globally: an HID scanner types like a keyboard, and a pattern-anchored wedge accumulates keystrokes and fires on a terminator or a quiet period (scanner-speed keys plus a short silence auto-fire; hand-typed codes need Enter). The matched code is stripped byte-exact from whatever field had focus, so a scan never leaks into a form. The whole surface is gated by `features.scanCodes` in `start()` config (a per-browser toggle in the Features panel flips it for testing); the execute and config APIs work regardless.
308
+
309
+ A code encodes **`version:category:target`** (e.g. `10:1:SN-12345`):
310
+
311
+ - **version** (two digits) selects the **scheme** — how the target is parsed and which metadata facet it matches (`serialNumber`, `assetTag`).
312
+ - **category** (one digit) selects the **rule** under that scheme.
313
+ - **target** is the value matched against the scheme's facet.
314
+
315
+ **Rules are ECA over escalations.** A rule is an ordered list of event-condition-action steps, first match wins: the event is the scanned code, the condition is a query against the escalation (role, status, availability, metadata facets), and the action is a canonical verb (`show-detail`, `show-list`, `claim`, `claim-show-detail`, `release`, `resolve`, `escalate`, `cancel`, `present`). Mutations ride single-statement by-metadata operations under the caller's own role scope, and stamp provenance facets (`scanScheme`, `scanCategory`, `scanActionName`, `scannedAt`) on every transition. Ordering is the design: put the expected state first and a broad fallback last, since a scan is also a state query.
316
+
317
+ **Admin config** lives at `/admin/scan-codes` (scheme list) and `/admin/scan-codes/:version` (a scheme with its rules) — builder-gated (admin, engineer, superadmin). A scheme carries a name, its target facet, encoding, and — for identity schemes — a grant policy.
318
+
319
+ **Station surface.** `/scan/station` is a full-screen scan surface with an idle prompt, an info/choice screen (the current reality plus labeled choices when a rule presents options), and a badge prompt when identity is required. In **kiosk mode** — a login holding exactly one role whose `properties.kiosk` is set — the chrome falls away and only the role's list, escalation detail, and this scan screen are reachable. The header **scan** panel offers the same manual entry and capture settings on any page.
320
+
321
+ **Badge scanning grants acting identity.** A scheme of kind `identity` binds a badge value to a person (via a facet on `lt_users.metadata`). Scanning a badge primes an **ephemeral acting grant** minted through the internal keystore; it rides subsequent scans as the `X-LT-Acting-Token` header, and verbs then run **as the badged person under their own RBAC** — attribution, never privilege escalation. A badge on a work form belongs to the submission: the form names who will submit, holds if the wrong badge scans, and consumes the single-use grant on the write. A dead grant (expired, exhausted, revoked) fails loudly rather than executing silently.
322
+
323
+ **API:** `POST /api/scan-codes/execute` runs a code (`{ code, actingToken?, previousActingToken? }`, returning a structured outcome); `POST /api/scan-codes/execute-choice` runs a presented choice (the server re-validates config, row, identity, and RBAC). `GET/PUT/DELETE /api/scan-codes/schemes/:version` and `/schemes/:version/actions/:category` manage schemes and rules. See [Scan Codes](scan-codes.md) for the full concept doc and the four-corner printer demo.
324
+
296
325
  ### DB Maintenance
297
326
 
298
327
  Database housekeeping tools for keeping PostgreSQL healthy under sustained workflow load.
@@ -331,20 +360,39 @@ Messages are read-only. Status is derived from timestamps: pending (no timestamp
331
360
 
332
361
  ### All Escalations
333
362
 
334
- The central queue for all escalation activity across every workflow.
363
+ Accessible at `/escalations/available`. The central queue for escalation activity across every workflow — every place a running workflow paused to wait on a person or external actor.
364
+
365
+ - **Title = queue selector** — the page title reads as the selected role's friendly title, or "All Escalations" when unfiltered; clicking it switches queues over the same `?role=` param the filter bar mirrors.
366
+ - **Filter bar** — status (available / claimed / resolved / cancelled / expired), role, workflow type, priority, and time window. `available` means pending and either unclaimed or past its claim expiry.
367
+ - **Columns:** a **Summary** cell (status dot + description or type), **Assignee** (claimant, or `—`), **Role** pill, **Priority**, and **Created**. The status dot distinguishes pending, claimed, resolved, cancelled, and expired; notification escalations show a bell.
368
+ - **Faceted query** — beyond the filter bar, the queue takes a structured metadata query, all URL-backed so a query copy-pastes: `?facets={"orderId":"..."}` (equality, AND-ed), `?block=` (exclude), `?range=` (numeric bounds), `?exists=` (key present), `?roles=` (union of role queues), and `?orderBy=` (JSON sort). `?jeopardy=1` narrows to rows past the role's age threshold. List rows omit the envelope by default; `?include=envelope` pulls the full envelope and payload columns for rich views.
369
+ - **Metadata value affordances** — each metadata key/value row carries a three-icon triad on hover: **filter** (scope the current role's queue to `key = value`), **search** (the same facet match across all roles), and **history** (open the entity's cross-queue interval timeline in the right panel — every role this value moved through, with durations and gaps). Filter-present, search-present, history-past. History renders for string values, since the timeline's GIN containment match serves JSON-string facets.
370
+ - **View modes** (`?view=`) — `table` (the columns above), `timeline` (100 rows per page of cross-queue movement), and `rich`. When a role owns a [list schema](#escalations-list-schema), the list defaults to the role-authored `rich` view (the live item as a card, plus a load-on-demand history) with a **Table view** toggle back.
371
+ - **Claim** — the claim action locks an item to your user for a claim window (default 30 min). Only members of the role see its pending items; a member scoped `read_self` lands directly on their own assigned item rather than browsing the queue. Re-claiming your own expired item extends it rather than failing.
372
+ - **Bulk actions (admin)** — row checkboxes surface a selection bar: **Claim**, **Assign**, **Unassign**, **Escalate** (move to another role), and **Cancel**. Assign opens a modal for the target user and claim duration; rows under a live claim are skipped unless the modal's takeover checkbox (shown when the selection includes live claims) reassigns them — admin/superadmin only. Unassign returns claimed rows to the pool. Each response reports how many rows were skipped and why. Scoped to a single role, the Cancel verb and its confirmation speak the role form's `x-lt-labels.cancel` vocabulary (`false` hides it). Assign also accepts a faceted query instead of an id list, so "claim everything matching this facet" is one call.
373
+
374
+ **API:** `GET /api/escalations` lists with filters; `POST /api/escalations/search-by-facets` backs the faceted query. `POST /api/escalations/bulk-claim`, `/bulk-assign`, `/bulk-unassign`, `PATCH /api/escalations/bulk-escalate`, `POST /api/escalations/bulk-cancel` drive the selection bar.
375
+
376
+ ### My Escalations
335
377
 
336
- - **Title = queue selector** — the page title reads as the selected role's friendly title, or "All Escalations" when unfiltered; clicking it switches queues over the same `?role=` param the filter bar mirrors. The **My Escalations** personal inbox (`/escalations/queue`) carries the identical control, titling itself "My Escalations" or the filtered role's title.
337
- - **Filter bar** — filter by status (pending/claimed/resolved), role, workflow type, priority, and time window.
338
- - **Columns:** Escalation ID, workflow type, role, status, priority, created time, and claimed-by user.
339
- - **Metadata value affordances** — each metadata key/value row in the list carries a three-icon triad on hover: **filter** (filter the current role's queue to rows where the key equals this value), **search** (the same facet match across all roles), and **history** (open the entity's cross-queue interval timeline in the right panel — every station this value has moved through, with durations and gaps). Filter-present, search-present, history-past. The history affordance renders for string values, since the timeline's GIN containment match serves JSON-string facets.
340
- - **Rich list view** — when the list is scoped to exactly one role (`?role=<role>`) and that role owns a [list schema](#escalations-list-schema), a role-authored view renders in place of the table (the live item as a card, plus a load-on-demand history), with a **Table view** toggle back to the columns.
341
- - **Claim** — click the claim action to lock an escalation to your user. Only users with matching roles see pending escalations. The queue list and aggregate stats reflect `read_all` memberships — a member scoped to `read_self` lands directly on their own assigned item in user mode rather than browsing the full queue.
342
- - **Bulk actions (admin)** — row checkboxes surface a selection bar with **Claim**, **Assign**, **Unassign**, **Escalate** (move to another role), and **Cancel**. Assign opens a modal to pick the target user and claim duration; rows under a live claim are skipped unless the modal's takeover checkbox (shown when the selection includes live claims) is checked, which reassigns them — admin/superadmin only. Unassign returns claimed rows to the available pool. The response reports how many rows were skipped. When the list is scoped to a single role, the Cancel button and its confirmation speak the role form's `x-lt-labels.cancel` vocabulary (`false` hides the verb).
343
- - **Admin claim override (detail page)** — when an item is claimed by someone else, admins and superadmins see **Reassign…** (hand the claim to another user via the assign modal, takeover implied) and **Return to queue** (unassign) in the action bar.
344
- - **Resolve** — after claiming, submit a resolver payload. The form is pre-filled from the role's versioned `form_schema` field defaults and from the workflow's seeded `envelope.formDefaults` (reverse-mapped through each field's `x-lt-bind`). The dashboard maps the flat form to the nested payload via `x-lt-bind` and the submitted payload is stored as-is. Resolution triggers a workflow re-run with the resolver data injected. A `member` whose `write_scope` is `self` can resolve only items already assigned to them; `write_scope=none` is read-only.
345
- - **Side panel** — a slide-in beside the resolve form with switchable views, selected by the icon set at its top: **Help** (the form's `x-lt-help` markdown, `{{domain.path}}`-interpolated against the live record, or a state-aware hint such as "Claim this escalation to enable the form"), **Details** (status, role, priority, claim provenance, timestamps, and — for builders — identifier links), **AI Analysis** (what triage diagnosed and corrected — shown when AI is enabled and triage data is present), **Metadata** (the row's metadata values), **Context** (input envelope, escalation context, resolver payload), and **Record** (the raw escalation JSON, builders only). The panel and form share the width as a flex set — the form column narrows as the panel expands. It opens expanded on Help when the form carries `x-lt-help`, stays hidden otherwise, and the page-header panel button toggles it either way.
378
+ Accessible at `/escalations/queue`. The personal inbox — the items currently assigned to you across your roles. It carries the same title-as-role-selector, the same rich/table views, and the same metadata affordances as All Escalations, minus the bulk selection bar (every row is already yours). A **Claim expiry** column counts down each item's remaining window. The shell also auto-navigates here on hand-off: when a workflow assigns a follow-on escalation to you (`assigned_to = you`), the dashboard opens that item's detail directly.
346
379
 
347
- **API:** `GET /api/escalations` lists with filters. `POST /api/escalations/:id/claim` claims. `POST /api/escalations/:id/resolve` resolves.
380
+ ### Escalation Detail & Resolve Form
381
+
382
+ Accessible at `/escalations/detail/:id`. Where a person completes the work the workflow is waiting on. The main column is the resolve form; a switchable side panel carries context.
383
+
384
+ - **Lifecycle** — pending → claimed → resolved (or cancelled / expired). The sticky action bar shows the verbs valid for the current state: **Claim**, **Submit** (resolve), **Release**, **Cancel**. The form is read-only until you hold a live claim.
385
+ - **Form contract** — the form is the target role's versioned [`form_schema`](#escalation-schema), rendered flat. Fields pre-fill from two sources: the workflow's `envelope.formDefaults` (reverse-mapped through each field's `x-lt-bind` path) and the schema's own field defaults. On submit, the dashboard rebuilds the nested payload from the flat form via `x-lt-bind` and posts it as the resolver payload; password fields are redacted to short-lived ephemeral tokens before storage.
386
+ - **Validation** — one isomorphic pass runs on the client (to gate submit) and again on the server when the role sets `enforce_schema`, returning a canonical `422` with field-level errors. It covers required/type/enum/bounds, dynamic `x-lt-minimum`/`x-lt-maximum` (with `{{token}}` interpolation), and the root-level `x-lt-require-any` / `x-lt-require-sum` groups. Fields hidden by `x-lt-showIf` never block submission.
387
+ - **Resumption** — resolving resumes the paused workflow. When the escalation was created by `conditional()` (a HotMesh Leg1 write), the resolve is the signal: the run resumes in place with the payload injected, in one atomic Postgres statement — no re-run. A **notification** escalation (no `workflowType`) has no run to resume; **Acknowledge** still validates and submits the full form payload, resolving it atomically.
388
+ - **Canned actions** — a form may declare `x-lt-actions`: extra action-bar buttons that submit a preset payload in one click (Approve / Reject / Skip), bypassing field editing.
389
+ - **Submit guard** — `x-lt-submit-guard` gates a parent on a child query (e.g. "every item in this batch must resolve first"): the dashboard disables Submit with a live count while rows remain, and the server re-checks the guard atomically inside the resolving `UPDATE` so no race slips through. `autoResolveWhenEmpty` submits the parent the moment the query empties.
390
+ - **Transition hand-off** — `x-lt-transition` replaces the return-to-previous-page jump with a short wait screen: the workflow assigns a follow-on escalation back to the submitter, the screen detects it and navigates onward (or falls back to `x-lt-transition-done` after a bounded wait). This is the submit → side-effect → next-step chain (submit, a label prints, the harvest task opens).
391
+ - **Batch resolution** — a `conditional({ batch })` escalation accumulates N items on one row; `POST /api/escalations/:id/resolve-batch-item` submits each (claim-agnostic by default, `assertClaim` to require your own live claim), and the last item wakes the workflow with the full collection.
392
+ - **Side panel** — switchable views selected by the icon strip: **Help** (the form's `x-lt-help` markdown, `{{domain.path}}`-interpolated against the live record — escalation, metadata, envelope, payload, resolver, and `lookup.*` — or a state-aware hint like "Claim this escalation to enable the form"), **Details** (status, role, priority, claim provenance, timestamps, and for builders the identifier links), **AI Analysis** (what triage diagnosed and corrected, when AI is on), **Metadata** (the row's facets, with the same triad), **Context** (input envelope, escalation context, resolver payload), **Record** (the raw JSON, builders only), and **Errors** (the last submit's validation failures). The panel and form share the width as a flex set; it opens expanded on Help when the form carries `x-lt-help`.
393
+ - **Admin claim override** — when an item is held by someone else, admins and superadmins see **Reassign…** (hand the claim to another user, takeover implied) and **Return to queue** (unassign) in the action bar.
394
+
395
+ **API:** `POST /api/escalations/:id/claim` claims, `/release` releases, `/resolve` resolves; `/resolve-batch-item` submits one batch item; `/escalate` moves; `/cancel` cancels. The role's form and its versions come from `GET /api/roles/:role/schema`.
348
396
 
349
397
  ### Escalations Overview
350
398
 
@@ -352,28 +400,51 @@ Accessible at `/escalations`. A statistics dashboard for escalation health acros
352
400
 
353
401
  - **Time window selector** — toggle between 1h, 24h, 7d, and 30d views.
354
402
  - **Summary cards** — open (pending), claimed (in progress), created (new), and resolved counts for the selected window.
355
- - **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.
403
+ - **Role breakdown table** — groups escalations by role so you can see which teams have the most pending work; cells link into the filtered queue. Useful for identifying bottlenecks and rebalancing workload.
356
404
 
357
405
  ### Pace Board
358
406
 
359
- Accessible at `/operations`. The COO shop-floor view of the roles system: actual-vs-target flow across every station, rendered as a pace chart with a station table and detail panel below.
407
+ Accessible at `/pace`. The live picture of how work flows across a segment of roles: actual-vs-target throughput, rendered as a pace chart over a role table with a role detail panel. It answers the question a COO actually asks — *are we keeping up, and where is work backing up?*
408
+
409
+ The board is [Roles](#roles) end-to-end. Every role on it has **Visible in Operations** on; segments are composed from each role's **Prior Step** (`parent_role`); cross-segment feeds come from **Upstream Inputs**; the target line comes from each role's capacity settings. Configuring the board *is* configuring roles — the **Configure** action opens [Role Detail](#role-detail). See [Operations](operations.md) for the full concept doc.
410
+
411
+ **Segments.** A segment is a sequence of roles. A role with no prior step (or whose prior step lies outside the visible set) starts a segment, followed by its `parent_role` descendants in dependency order; the longest segment leads. The table is the ground truth of the queues; the chart is the line drawn through them.
412
+
413
+ **The combined board selector.** One menu switches views. Its **Pace Board** group lists the segments (each row: the segment title, its role count, pending total, and a jeopardy count); its **Trend Board** group lists the entity [lenses](#trend-board) (each `by <facet>`, with a live in-queue count). Choosing a segment stays on `/pace`; choosing a lens navigates to `/trends`. The collapsed button reads the active segment title, or `by <facet>` on a lens.
414
+
415
+ - **Segment deep link** — the active segment rides `?fragment=<origin role>`; each switch is a history entry, so a shared URL opens the same segment and back/forward walk them.
416
+ - **Period** — `15m`, `1h`, `24h`, `7d`, `30d`, default `1h`. It is deep-linked as `?period=` (the default stays out of the URL for clean links) and carries across a Pace↔Trend switch. It bounds resolved counts and the percentile metrics; `pending` is always the live count.
417
+ - **Pace chart** — the segment's roles on the X axis in dependency order. A muted-gray dashed **target** polyline sits at each role's expected count (`target_per_hour × window hours`); a green **actual** (resolved) curve with a faint area fill reads against it. The live queue shows as two faint stacked bands beneath — **claimed/worked** (orange) and **waiting/unclaimed** (sky). Each role is a circle on the resolved curve whose radius grows with volume; the selected role gets a ring. A `lin | log` toggle switches the Y axis (log by default, so small and large queues stay legible together).
418
+ - **Jeopardy** — a role with unclaimed items past its age threshold carries a jeopardy count (warning triangle) in its row and on the segment menu. Age is measured from the role's **priority facet** (a metadata timestamp such as an order's authorized date; `created_at` when unset) against its **priority threshold** (`sla_minutes` when unset). Clicking it opens the jeopardy deep link — `/escalations/available?role=<r>&jeopardy=1&view=table&orderBy=[{…,"direction":"asc"}]` — the table filtered to exactly the counted items (one server-side predicate feeds both the count and the list, so totals always match), oldest-first by the same facet. A jeopardy pill above the list names the filter; clearing it widens back to the full queue.
419
+ - **Merge glyph** — a role that declares upstream inputs shows a small dashed merge glyph at its floor position: deliberately a symbol, never a bend in the line, because the upstream is an input, not a descendant. Hover names the feeding roles; click jumps to their segment.
420
+ - **Role table** — columns in order: **NAME**, **ROLE** (the id, wide viewports), **TARGET/H** and **SLA/M** (edit inline), **WORKERS** (derived — `workers = target ÷ (60 ÷ sla)`), then **PENDING**, **CLAIMED**, **RESOLVED** tinted with the chart's hues (each cell links into the queue filtered by that status), **P99 WAIT** and **P99 WORK** (wide viewports), a **MIX** time-in-state bar, a **TREND** mini-bar, and **ACTIONS** (view queue, configure, jeopardy). The TREND bar reads pending-to-target ratio: amber above 1.0 (backlog), gray below 0.2 (idle), green between.
421
+ - **Role detail panel** — opens on a row or circle click: the role's identity, its own independent period toggle, the full wait/work percentile breakdown, SLA target and worker count, the time-in-state mix and per-entity timelines inline, and links into the queue.
422
+ - **Scope pill** — when your roles declare [link variables](faceted-routing.md#link-variables), a scope pill sits in the header. Your device binding (`facility = north`) narrows the whole board — counts, mix, and every timeline — to that facet, or reads `All` when unbound. It opens the Link variables modal; the value picker's choices come from `GET /api/escalations/facet-values?key=<facet>`.
423
+ - **Live updates** — escalation events invalidate the metrics and analytics through the shared realtime scheduler (SUMMARY tier, coalesced); the refresh button forces a reload. Every login may read the board while `features.publicPaceBoard` (default on) stands; turning it off narrows metrics to role membership and the board to admins and superadmins.
360
424
 
361
- The board is [Roles](#roles) end-to-end. Every station is a role with its **Ops** toggle on; sequences are composed from each role's Prior Step (`parent_role`); cross-sequence feeds come from Upstream Inputs; the red target line comes from each role's capacity settings. Configuring the board *is* configuring roles the **Configure** button in the header goes straight there.
425
+ A role joins the board from its [Role Detail Pace Board](#role-detail) section: the visibility toggle, the capacity settings (`sla_minutes`, `target_per_hour`, `worker_count`), the priority dials (`priority_threshold_minutes`, `priority_facet`), and the sequence placement (`parent_role`, upstream inputs).
362
426
 
363
- Execution is a graph; this page tells its story as **sequences**. Each station role with no prior step (or whose prior step is outside the station set) starts a sequence, followed by its `parent_role` descendants in dependency order. The longest sequence leads. The table is always the ground truth of the queues; the SVG is the narrative line drawn through them.
427
+ **API:** `GET /api/escalations/station-metrics?period=<window>&facets=<json>` returns the per-role live counts and windowed percentiles.
364
428
 
365
- - **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.
366
- - **Period selector** — `15m`, `1h`, `24h`, `7d`, `30d`. Controls the lookback window for resolved counts, percentile metrics, and throughput.
367
- - **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).
368
- - **Priority badge (jeopardy)** — 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 the **jeopardy deep link**: `/escalations/available?role=<r>&jeopardy=1&view=table&orderBy=[{"field":…,"direction":"asc"}]` — the table view filtered to exactly the counted items (the same server-side predicate produces the count and the list, so the totals always match), ordered oldest-first by the same facet. A red `in jeopardy · > <limit>` pill above the list names the active filter; its ✕ widens back to the full queue. The operator home's Task Queue cards carry the same pill and link.
369
- - **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.
370
- - **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.
371
- - **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).
372
- - **Live updates** — escalation events refresh the metrics push-driven and debounced; the header's refresh button forces a reload.
429
+ ### Trend Board
373
430
 
374
- 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.
431
+ Accessible at `/trends`. The entity lens — *where did the time go?* Instead of role-by-role throughput, it follows one **entity** (a `serialNumber`, an `orderId`) through every role that handles it and shows how its time splits across states. It shares the [combined board selector](#pace-board), the period, and the scope pill with the Pace Board.
375
432
 
376
- **API:** `GET /api/escalations/station-metrics?period=24h`
433
+ The lens is driven by two dials on each role's [Role Detail → Pace Board](#role-detail) section:
434
+
435
+ - **`entity_facet`** — the `metadata` key naming what moves through the role (`serialNumber`, `orderId`). Roles sharing a key form that entity's **system**. Each distinct facet becomes one lens, deep-linked as `?lens=<facet>` (default: the first facet).
436
+ - **`entity_state_source`** — how a role names the entity's state: **Station** (being in this role is one state, e.g. a servicing queue) or **Subtypes** (one role holds several states named by each escalation's subtype, e.g. a fleet role parking `idle` / `printing`).
437
+
438
+ Three tiers, aggregate to individual:
439
+
440
+ - **Where the time went** — a ranked-bar legend of states by total dwell over the window (top rows, with a "+N more stages" fold), beside an insight panel: the leader's share as a headline percentage, `<state> is the biggest time sink`, and `across N stages · M <entity> in queue now` for the selected period.
441
+ - **Slice by** — `?slice=<facet>` splits the system into small-multiple columns, one per value of that key (e.g. `model` → `p1s` vs `h2s`), ranked by dwell. `?sliceValue=<value>` focuses one value with a paginated entity list.
442
+ - **Entity table** — one row per entity, ranked by tracked time: the entity value, a current-state dot, its own dwell band, its total tracked time, and a history action. A **find** box (`?find=<prefix>`) prefix-filters the entities.
443
+ - **Per-entity timeline** — `?entity=<value>` opens that entity's cross-queue interval timeline in the right panel: every role it moved through, with durations and gaps. The panel's copy-link emits a shareable `/trends?lens=<facet>&entity=<value>` URL.
444
+
445
+ The aggregate bands are counts-only and readable by any login while the public board flag stands; the slice and per-entity tiers group by facet values and require full (`read_all`) access to the system's queues.
446
+
447
+ **API:** `POST /api/escalations/aggregate-by-facets` (the state-mix and rankings) and `POST /api/escalations/timeline-by-facet` (the per-entity intervals). See [Escalation Analytics](escalation-analytics.md) for the query contract.
377
448
 
378
449
  ### Processes Overview
379
450
 
@@ -398,28 +469,30 @@ This is the primary view for understanding how a multi-step workflow progresses
398
469
 
399
470
  ### Files
400
471
 
401
- Browse and manage files in connected storage backends (MinIO locally, S3/GCS in production).
472
+ Accessible at `/files`. Browse and manage files in the connected storage backend (MinIO locally, S3/GCS in production).
402
473
 
403
- - **File browser** — navigate directories with breadcrumbs. View files in a list with name, size, type, and last modified date.
404
- - **Preview panel** — click a file to preview it in the side panel. Supports images, text, JSON, and PDF.
405
- - **Upload** — drag and drop or click to upload files to the current directory.
406
- - **Sidebar** — collapsible file tree for quick navigation across the storage hierarchy.
474
+ - **File browser** — navigate directories with breadcrumbs; the list shows name, size, and last-modified. Paginated via a continuation token.
475
+ - **Preview panel** — click a file to preview it in the side panel: images inline, text and code inline, JSON, and a PDF open-in-tab. Everything else downloads.
476
+ - **Upload** — drag and drop, or the file input, into the current prefix; a confirmation names the target path.
477
+ - **Signed URLs** — generate a time-boxed download link for a file (expiry from a fixed set, 1h to 30d).
407
478
 
408
- Storage backend is selected by the `STORAGE_BACKEND` env var. The same interface works against MinIO (local dev), S3, or GCS no code changes needed.
479
+ The backend is selected by the `LT_STORAGE_BACKEND` env var `local` (filesystem) or `s3` (S3-compatible, including MinIO). The same interface serves every backend; only env changes.
409
480
 
410
- **API:** `GET /api/files` lists files. `POST /api/files/upload` uploads. `GET /api/files/download/:path` downloads.
481
+ **API:** `GET /api/file-browser/browse?prefix=<path>` lists. `POST /api/file-browser/upload?path=<path>` uploads raw bytes. `GET /api/file-browser/download/<path>` downloads; `DELETE /api/file-browser/delete/<path>` removes; `POST /api/file-browser/signed-url` mints a link. Token-scoped serving is at `GET /api/files/<path>?token=<jwt>`.
411
482
 
412
483
  ### Knowledge
413
484
 
414
- Knowledge base for storing and retrieving domain-specific information used by workflows and MCP tools.
485
+ Accessible at `/knowledge` (builder-only superadmin or the `engineer` role). A **versioned** store of domain data that workflows and resolver forms read at runtime: product catalogs, reference tables, cascade option sets. An entry is keyed by `domain` + `key` and holds a JSON `data` value plus `tags`.
486
+
487
+ **Versioning is the defining property.** Every write that changes an entry's `data` mints an immutable edition and advances `current_version`; writes that leave the data identical (or touch only tags) are no-ops that never bump the version. The live entry is the current edition; past editions are retained and read-only.
415
488
 
416
- - **Entry list** — browse knowledge entries by domain and key. Each entry stores structured data that workflows can query at runtime.
417
- - **Create/Edit** — add or update knowledge entries with a domain, key, and JSON value.
418
- - **Search** — filter entries by domain or key prefix.
489
+ - **Browse** — All Domains a domain's entries (each row shows key, tags, field count, and current version) an entry detail with a full JSON editor.
490
+ - **Version rail** — the entry detail's version dropdown lists every edition, newest first, the current one marked. Selecting a past edition sets `?version=<N>` and shows an immutable, read-only snapshot with a "back to current" affordance.
491
+ - **Field-level edits** — set or remove a value at a dot-path (`jsonb_set` / path delete) without clobbering sibling keys; each still mints an edition when the data changes.
419
492
 
420
- Knowledge entries are accessed by workflows via the `get_knowledge` MCP tool. This is how workflows retrieve domain context (product catalogs, configuration data, reference tables) without hardcoding values.
493
+ **How workflows and forms consume it.** A workflow pins knowledge onto an escalation as versioned lookup refs on the reserved `envelope.lookups` key `{ domain, key, version, as? }`. Because the ref names an exact edition, the resolver always sees the data the workflow was written against, even as the entry later evolves. Resolving those refs (`GET /api/escalations/:id/lookups`, in-process LRU cached) exposes a `lookup.<key>` domain to the form: a field's `x-lt-options` reads `lookup.materials.items`, and cascades interpolate the live form — `lookup.geo.regions.{{resolver.country}}` narrows the second select from the first. The reader needs no separate knowledge grant; the ref on an escalation they can read *is* the grant. Agents reach the same data through the `get_knowledge` MCP tool (with an optional `version`).
421
494
 
422
- **API:** `GET /api/knowledge` lists entries. `PUT /api/knowledge/:domain/:key` creates or updates. `DELETE /api/knowledge/:domain/:key` removes.
495
+ **API:** `GET /api/knowledge/domains` and `/entries?domain=` list; `GET /api/knowledge/entry?domain=&key=&version=` fetches the live entry or a pinned edition; `GET /api/knowledge/entry/versions?domain=&key=` returns the lineage. `POST /api/knowledge/entry` creates or merges, `PUT /api/knowledge/field` sets a path, `DELETE /api/knowledge/field` removes one, `DELETE /api/knowledge/entry` deletes (cascading its editions). See [Knowledge HTTP API](api/http/knowledge.md).
423
496
 
424
497
  ### Topic Catalog
425
498
 
@@ -480,6 +553,28 @@ markdown body. Each user dismisses per-browser.
480
553
  Role targeting scopes display, never access: the live event reaches every
481
554
  authenticated subscriber, so announcement bodies must never carry secrets.
482
555
 
556
+ ### Global search
557
+
558
+ An opt-in header search bar for one-gesture lookups across every escalation
559
+ of any status. Configure it in the `start()` config —
560
+ `search: { enabled: true, facets: ['orderId', 'po'] }` — or by env
561
+ (`LT_SEARCH_BAR=true`, `LT_SEARCH_FACETS=orderId,po`; env wins). The picklist
562
+ always offers `escalationId` and `workflowId` (long-tail-owned lookups) ahead
563
+ of the configured metadata facets, and remembers the last-used facet per
564
+ device.
565
+
566
+ - A metadata facet lands on the escalation list filtered by that facet across
567
+ all statuses, newest first (the same deep link as clicking a facet value).
568
+ - `escalationId` opens the escalation detail directly; an unknown id shows an
569
+ inline notice without navigating.
570
+ - `workflowId` opens the workflow's single escalation, lists several to pick
571
+ from, or links straight to the workflow execution when none exist.
572
+
573
+ Kiosk sessions see the bar too — a station can dump a PO or order id and jump
574
+ straight to it; RBAC read scope bounds what any search can return. See
575
+ [Faceted Routing](faceted-routing.md) — a search is a one-gesture facet deep
576
+ link.
577
+
483
578
  ### Inbox
484
579
 
485
580
  The Inbox icon in the header shows a badge count when the current user has pending escalations assigned to their roles. The count updates live via NATS — no polling needed.
@@ -91,6 +91,44 @@ const groups = await searchGroups(query, { sizeFacet: 'orderSize', limit: 10 });
91
91
  const inFlight = await countByFacets({ role: 'print-farm-diabetic', available: false });
92
92
  ```
93
93
 
94
+ ## Link variables
95
+
96
+ A role may declare **link variables** — facet names its members bind per
97
+ device — in `properties.link_variables`:
98
+
99
+ ```json
100
+ { "link_variables": [ { "name": "facility", "label": "Facility", "default": "main" } ] }
101
+ ```
102
+
103
+ A pinned URL references a variable as the ENTIRE value of a facet inside the
104
+ `facets` param:
105
+
106
+ ```
107
+ /escalations/available?role=gluer&facets={"facility":"{lt:facility}"}&status=available
108
+ ```
109
+
110
+ The dashboard substitutes at render time, so every link in the DOM is already
111
+ concrete. Resolution order per variable: the device's bound value → the
112
+ declared `default` → **drop the facet** (unbound means no filter, never an
113
+ empty-string match). Members bind values from the user menu ("Link
114
+ variables"); bindings live in device localStorage (`lt:station:link-vars:{userId}`),
115
+ so a shared workstation keeps its scope across reloads and account switches.
116
+ A shared URL still carrying a raw `{lt:name}` placeholder is resolved against
117
+ the opening device the moment the list page mounts (address bar rewritten in
118
+ place).
119
+
120
+ Values are strings — jsonb containment is type-sensitive, so numeric facets
121
+ are not templatable. Link variables are a view convenience: RBAC read scope
122
+ still governs what any query can return.
123
+
124
+ A bound link variable also **scopes the Pace Board** — the same device value
125
+ narrows the board's station counts, time-in-state mix, and entity timelines,
126
+ not just the pins. See [Operations — Scoping the board](operations.md#scoping-the-board).
127
+
128
+ The dashboard's [global search bar](dashboard.md#global-search) is the
129
+ one-gesture sibling of this surface: a configured facet name plus a value
130
+ lands on the same all-status faceted list a deep link produces.
131
+
94
132
  ## Atomic claims
95
133
 
96
134
  Two claim primitives, both `FOR UPDATE SKIP LOCKED` so many consumers run without
@@ -23,6 +23,8 @@ Every string is a markdown/text template run through the same `{{domain.path}}`
23
23
 
24
24
  `format: "age"` on a `facet-table` column or `facet-board` field renders a timestamp as a compact age (`12m`, `3h`, `2d`) with the absolute time as its tooltip, repainted each minute — aging interim states are scannable at a glance.
25
25
 
26
+ `format: "user"` resolves a user-id token — `{{escalation.assigned_to}}` — to that person's display name. Resolution is batched: every id on a page is coalesced into one `POST /api/users/names` request returning display fields only (no secrets, scopes, or metadata), cached by id for the session and not refetched on window focus; a user edit invalidates the cache. It truncates with an ellipsis and carries the full name on hover; an unassigned row shows a quiet em dash. `assigned_to` is the claimant while the item is worked and stays as the resolver once it is resolved, so one column reads correctly across the row's whole life. The built-in table and timeline views carry this user column by default; authored templates opt in per column.
27
+
26
28
  The **active** item is the first non-terminal escalation. The **history** column is lazy-loaded — a "Load full history" link fetches resolved items on demand (`status` defaults to `"resolved"`, `limit` to 25). Unknown or absent `x-lt-layout` is a safe no-op that falls back to the table.
27
29
 
28
30
  ### Row action (`x-lt-row-action`)
@@ -94,6 +96,7 @@ Use when the queue contains many concurrent rows and the role's context is best
94
96
  { "label": "Heel cup", "value": "{{metadata.heelCup}}" },
95
97
  { "label": "PDAC", "value": "{{metadata.pdac}}" },
96
98
  { "label": "Station", "value": "{{metadata.station}}" },
99
+ { "label": "Assignee", "value": "{{escalation.assigned_to}}", "format": "user" },
97
100
  { "label": "Priority", "value": "{{escalation.priority}}" },
98
101
  { "label": "Created", "value": "{{escalation.created_at}}" }
99
102
  ]