@hotmeshio/long-tail 0.22.2 → 0.23.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 (266) hide show
  1. package/build/api/escalations/accumulate.js +7 -1
  2. package/build/api/escalations/lookups.d.ts +9 -2
  3. package/build/api/escalations/lookups.js +15 -3
  4. package/build/api/escalations/metadata.d.ts +2 -0
  5. package/build/api/escalations/metadata.js +9 -0
  6. package/build/api/escalations/resolve-batch.d.ts +2 -1
  7. package/build/api/escalations/resolve-batch.js +6 -5
  8. package/build/api/scan-codes/locate.js +4 -0
  9. package/build/api/scan-codes/present.d.ts +1 -1
  10. package/build/api/scan-codes/present.js +43 -0
  11. package/build/api/scan-codes/verb-accumulate.js +5 -1
  12. package/build/api/scan-codes/verb-fill.js +4 -1
  13. package/build/api/scan-codes/verb-into-subject.d.ts +12 -0
  14. package/build/api/scan-codes/verb-into-subject.js +157 -0
  15. package/build/api/scan-codes/verbs-subject.d.ts +23 -4
  16. package/build/api/scan-codes/verbs-subject.js +32 -55
  17. package/build/api/scan-codes/verbs.d.ts +10 -8
  18. package/build/api/scan-codes/verbs.js +25 -16
  19. package/build/index.d.ts +1 -1
  20. package/build/index.js +3 -2
  21. package/build/sdk/index.d.ts +1 -0
  22. package/build/services/escalation/batch.d.ts +4 -4
  23. package/build/services/escalation/batch.js +7 -4
  24. package/build/services/escalation/claim-asserted.d.ts +10 -0
  25. package/build/services/escalation/claim-asserted.js +64 -0
  26. package/build/services/escalation/facets.d.ts +3 -1
  27. package/build/services/escalation/facets.js +7 -3
  28. package/build/services/escalation/index.d.ts +1 -0
  29. package/build/services/escalation/index.js +3 -1
  30. package/build/services/knowledge/lookup-cache.d.ts +16 -4
  31. package/build/services/knowledge/lookup-cache.js +53 -20
  32. package/build/services/knowledge/lookup-refs.d.ts +3 -2
  33. package/build/services/knowledge/lookup-refs.js +6 -4
  34. package/build/services/knowledge/sql.d.ts +2 -0
  35. package/build/services/knowledge/sql.js +9 -1
  36. package/build/services/mcp/server-tools.js +1 -1
  37. package/build/services/orchestrator/condition.d.ts +17 -11
  38. package/build/services/orchestrator/condition.js +12 -7
  39. package/build/services/scan-code/index.d.ts +1 -1
  40. package/build/services/scan-code/index.js +2 -1
  41. package/build/services/scan-code/validate-facts.d.ts +5 -0
  42. package/build/services/scan-code/validate-facts.js +24 -0
  43. package/build/services/scan-code/validate-query.d.ts +8 -0
  44. package/build/services/scan-code/validate-query.js +36 -0
  45. package/build/services/scan-code/validate-subject.js +29 -2
  46. package/build/services/scan-code/validate.js +17 -8
  47. package/build/shared/scan-code/gtin.d.ts +6 -0
  48. package/build/shared/scan-code/gtin.js +13 -0
  49. package/build/shared/scan-code/index.d.ts +1 -1
  50. package/build/shared/scan-code/index.js +2 -1
  51. package/build/system/mcp-servers/admin/schemas.d.ts +185 -5
  52. package/build/system/mcp-servers/admin/schemas.js +16 -3
  53. package/build/system/seed/tool-manifests-admin.d.ts +202 -1
  54. package/build/system/seed/tool-manifests-admin.js +2 -2
  55. package/build/tsconfig.tsbuildinfo +1 -1
  56. package/build/types/escalation.d.ts +23 -8
  57. package/build/types/escalation.js +18 -7
  58. package/build/types/index.d.ts +3 -3
  59. package/build/types/index.js +3 -1
  60. package/build/types/scan-code/response.d.ts +5 -0
  61. package/build/types/scan-code/rule.d.ts +32 -2
  62. package/dashboard/dist/assets/{AdminDashboard-DBW12qQt.js → AdminDashboard-DKrqLGjn.js} +2 -2
  63. package/dashboard/dist/assets/{AdminDashboard-DBW12qQt.js.map → AdminDashboard-DKrqLGjn.js.map} +1 -1
  64. package/dashboard/dist/assets/{AgentConfigPage-CmHv8U9M.js → AgentConfigPage-BoQhRW6U.js} +2 -2
  65. package/dashboard/dist/assets/{AgentConfigPage-CmHv8U9M.js.map → AgentConfigPage-BoQhRW6U.js.map} +1 -1
  66. package/dashboard/dist/assets/{AgentDetailPage-D1scIbz-.js → AgentDetailPage-DZhzuZmO.js} +2 -2
  67. package/dashboard/dist/assets/{AgentDetailPage-D1scIbz-.js.map → AgentDetailPage-DZhzuZmO.js.map} +1 -1
  68. package/dashboard/dist/assets/{AgentsPage-BA_ai9HJ.js → AgentsPage-5MynmbWX.js} +2 -2
  69. package/dashboard/dist/assets/{AgentsPage-BA_ai9HJ.js.map → AgentsPage-5MynmbWX.js.map} +1 -1
  70. package/dashboard/dist/assets/{AvailableEscalationsPage-C2_5aEFW.js → AvailableEscalationsPage-CWMyy3IL.js} +2 -2
  71. package/dashboard/dist/assets/{AvailableEscalationsPage-C2_5aEFW.js.map → AvailableEscalationsPage-CWMyy3IL.js.map} +1 -1
  72. package/dashboard/dist/assets/{BotPicker-BZo4Kp4a.js → BotPicker-C3LR6Sqy.js} +2 -2
  73. package/dashboard/dist/assets/{BotPicker-BZo4Kp4a.js.map → BotPicker-C3LR6Sqy.js.map} +1 -1
  74. package/dashboard/dist/assets/{BulkAssignModal-BFhyxY2T.js → BulkAssignModal-COjoOIIH.js} +2 -2
  75. package/dashboard/dist/assets/{BulkAssignModal-BFhyxY2T.js.map → BulkAssignModal-COjoOIIH.js.map} +1 -1
  76. package/dashboard/dist/assets/{CapabilitiesPage-CvOX6vAc.js → CapabilitiesPage-DKxLvOfB.js} +2 -2
  77. package/dashboard/dist/assets/{CapabilitiesPage-CvOX6vAc.js.map → CapabilitiesPage-DKxLvOfB.js.map} +1 -1
  78. package/dashboard/dist/assets/{CollapsibleSection-GCJsV9Oq.js → CollapsibleSection-Cz5sRx-r.js} +2 -2
  79. package/dashboard/dist/assets/{CollapsibleSection-GCJsV9Oq.js.map → CollapsibleSection-Cz5sRx-r.js.map} +1 -1
  80. package/dashboard/dist/assets/{ConfirmDeleteModal-CAgYLcef.js → ConfirmDeleteModal-Beq1vQtY.js} +2 -2
  81. package/dashboard/dist/assets/{ConfirmDeleteModal-CAgYLcef.js.map → ConfirmDeleteModal-Beq1vQtY.js.map} +1 -1
  82. package/dashboard/dist/assets/{CountdownTimer-Dik2z0M_.js → CountdownTimer-BUBl_4mP.js} +2 -2
  83. package/dashboard/dist/assets/{CountdownTimer-Dik2z0M_.js.map → CountdownTimer-BUBl_4mP.js.map} +1 -1
  84. package/dashboard/dist/assets/{CredentialsPage-twd2xCOW.js → CredentialsPage-DhiHiPsG.js} +2 -2
  85. package/dashboard/dist/assets/{CredentialsPage-twd2xCOW.js.map → CredentialsPage-DhiHiPsG.js.map} +1 -1
  86. package/dashboard/dist/assets/{CronLabel-DdnIuudX.js → CronLabel-C9SkawB-.js} +2 -2
  87. package/dashboard/dist/assets/{CronLabel-DdnIuudX.js.map → CronLabel-C9SkawB-.js.map} +1 -1
  88. package/dashboard/dist/assets/{ElapsedCell-DCctVv5R.js → ElapsedCell-BeK1SUDK.js} +2 -2
  89. package/dashboard/dist/assets/{ElapsedCell-DCctVv5R.js.map → ElapsedCell-BeK1SUDK.js.map} +1 -1
  90. package/dashboard/dist/assets/{EntityTimelinePanel-CMnskyWv.js → EntityTimelinePanel-BThdefKj.js} +2 -2
  91. package/dashboard/dist/assets/{EntityTimelinePanel-CMnskyWv.js.map → EntityTimelinePanel-BThdefKj.js.map} +1 -1
  92. package/dashboard/dist/assets/{EscalationListSchemaPage-VfCn6WDb.js → EscalationListSchemaPage-DlDIYb-p.js} +2 -2
  93. package/dashboard/dist/assets/{EscalationListSchemaPage-VfCn6WDb.js.map → EscalationListSchemaPage-DlDIYb-p.js.map} +1 -1
  94. package/dashboard/dist/assets/{EscalationListView-CGQZxcC-.js → EscalationListView-DTIVuym4.js} +2 -2
  95. package/dashboard/dist/assets/{EscalationListView-CGQZxcC-.js.map → EscalationListView-DTIVuym4.js.map} +1 -1
  96. package/dashboard/dist/assets/{EscalationSchemaPage-BX0tx-PM.js → EscalationSchemaPage-CQt-Embr.js} +2 -2
  97. package/dashboard/dist/assets/{EscalationSchemaPage-BX0tx-PM.js.map → EscalationSchemaPage-CQt-Embr.js.map} +1 -1
  98. package/dashboard/dist/assets/{EscalationTimeline-DKoSM56J.js → EscalationTimeline-DNKNp6pL.js} +2 -2
  99. package/dashboard/dist/assets/{EscalationTimeline-DKoSM56J.js.map → EscalationTimeline-DNKNp6pL.js.map} +1 -1
  100. package/dashboard/dist/assets/{EscalationTitleSelect-DWGLBOmS.js → EscalationTitleSelect-Dewrv8wX.js} +2 -2
  101. package/dashboard/dist/assets/{EscalationTitleSelect-DWGLBOmS.js.map → EscalationTitleSelect-Dewrv8wX.js.map} +1 -1
  102. package/dashboard/dist/assets/{EscalationsOverview-C2XoguaA.js → EscalationsOverview-BzH-Y-5x.js} +2 -2
  103. package/dashboard/dist/assets/{EscalationsOverview-C2XoguaA.js.map → EscalationsOverview-BzH-Y-5x.js.map} +1 -1
  104. package/dashboard/dist/assets/{EventTable-CBUWq7--.js → EventTable-C97m6IZv.js} +2 -2
  105. package/dashboard/dist/assets/{EventTable-CBUWq7--.js.map → EventTable-C97m6IZv.js.map} +1 -1
  106. package/dashboard/dist/assets/{FilterBar-8IdbleZ9.js → FilterBar-D-6xVHIw.js} +2 -2
  107. package/dashboard/dist/assets/{FilterBar-8IdbleZ9.js.map → FilterBar-D-6xVHIw.js.map} +1 -1
  108. package/dashboard/dist/assets/{GraphInvokePage-CUvoPzsW.js → GraphInvokePage-Bwi8EF9Y.js} +2 -2
  109. package/dashboard/dist/assets/{GraphInvokePage-CUvoPzsW.js.map → GraphInvokePage-Bwi8EF9Y.js.map} +1 -1
  110. package/dashboard/dist/assets/{HomePage-BP7v9GLJ.js → HomePage-Z_Q03C0z.js} +2 -2
  111. package/dashboard/dist/assets/{HomePage-BP7v9GLJ.js.map → HomePage-Z_Q03C0z.js.map} +1 -1
  112. package/dashboard/dist/assets/{ListToolbar-Cnacuwoy.js → ListToolbar-_jWTw5no.js} +2 -2
  113. package/dashboard/dist/assets/{ListToolbar-Cnacuwoy.js.map → ListToolbar-_jWTw5no.js.map} +1 -1
  114. package/dashboard/dist/assets/{McpOverview-C2JoNoDA.js → McpOverview-CjqTuP0N.js} +2 -2
  115. package/dashboard/dist/assets/{McpOverview-C2JoNoDA.js.map → McpOverview-CjqTuP0N.js.map} +1 -1
  116. package/dashboard/dist/assets/{McpQueryDetailPage-C_nih0w-.js → McpQueryDetailPage-leCsje1U.js} +2 -2
  117. package/dashboard/dist/assets/{McpQueryDetailPage-C_nih0w-.js.map → McpQueryDetailPage-leCsje1U.js.map} +1 -1
  118. package/dashboard/dist/assets/{McpQueryPage-U_wNXow2.js → McpQueryPage-C-PyXYX4.js} +2 -2
  119. package/dashboard/dist/assets/{McpQueryPage-U_wNXow2.js.map → McpQueryPage-C-PyXYX4.js.map} +1 -1
  120. package/dashboard/dist/assets/{McpRunDetailPage-DtKoJq6J.js → McpRunDetailPage-JDrr3uUQ.js} +2 -2
  121. package/dashboard/dist/assets/{McpRunDetailPage-DtKoJq6J.js.map → McpRunDetailPage-JDrr3uUQ.js.map} +1 -1
  122. package/dashboard/dist/assets/{McpRunsPage-CnYtfGhf.js → McpRunsPage-DERXQLgZ.js} +2 -2
  123. package/dashboard/dist/assets/{McpRunsPage-CnYtfGhf.js.map → McpRunsPage-DERXQLgZ.js.map} +1 -1
  124. package/dashboard/dist/assets/{OperationsPage-C7hupIer.js → OperationsPage-B2DA7n9m.js} +2 -2
  125. package/dashboard/dist/assets/{OperationsPage-C7hupIer.js.map → OperationsPage-B2DA7n9m.js.map} +1 -1
  126. package/dashboard/dist/assets/{OperatorDashboard-fVuLn2D5.js → OperatorDashboard-C8RtPv8P.js} +2 -2
  127. package/dashboard/dist/assets/{OperatorDashboard-fVuLn2D5.js.map → OperatorDashboard-C8RtPv8P.js.map} +1 -1
  128. package/dashboard/dist/assets/{PersonaDetailPage-C-4o8lPw.js → PersonaDetailPage-ChXwJ6u5.js} +2 -2
  129. package/dashboard/dist/assets/{PersonaDetailPage-C-4o8lPw.js.map → PersonaDetailPage-ChXwJ6u5.js.map} +1 -1
  130. package/dashboard/dist/assets/{PersonasPage-BL1FwLmv.js → PersonasPage-BFFxncSE.js} +2 -2
  131. package/dashboard/dist/assets/{PersonasPage-BL1FwLmv.js.map → PersonasPage-BFFxncSE.js.map} +1 -1
  132. package/dashboard/dist/assets/{PortalPage-tJG5sgb1.js → PortalPage-Xk1zVneM.js} +2 -2
  133. package/dashboard/dist/assets/{PortalPage-tJG5sgb1.js.map → PortalPage-Xk1zVneM.js.map} +1 -1
  134. package/dashboard/dist/assets/{ProcessDetailPage-Dz_jY4Yt.js → ProcessDetailPage-D7EYwW-j.js} +2 -2
  135. package/dashboard/dist/assets/{ProcessDetailPage-Dz_jY4Yt.js.map → ProcessDetailPage-D7EYwW-j.js.map} +1 -1
  136. package/dashboard/dist/assets/{ProcessesListPage-Cbn9cter.js → ProcessesListPage-CakYRtnE.js} +2 -2
  137. package/dashboard/dist/assets/{ProcessesListPage-Cbn9cter.js.map → ProcessesListPage-CakYRtnE.js.map} +1 -1
  138. package/dashboard/dist/assets/{ResolverForm-Bk8iXQ6-.js → ResolverForm-BwVOJUpJ.js} +6 -6
  139. package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js.map +1 -0
  140. package/dashboard/dist/assets/{RoleDetailPage-owPi6gI9.js → RoleDetailPage-CKbGwezP.js} +2 -2
  141. package/dashboard/dist/assets/{RoleDetailPage-owPi6gI9.js.map → RoleDetailPage-CKbGwezP.js.map} +1 -1
  142. package/dashboard/dist/assets/{RolesPage-NwmMvZFa.js → RolesPage-Czu7Zku4.js} +2 -2
  143. package/dashboard/dist/assets/{RolesPage-NwmMvZFa.js.map → RolesPage-Czu7Zku4.js.map} +1 -1
  144. package/dashboard/dist/assets/{RunAsSelector-tgEooTyU.js → RunAsSelector-6BLScYTX.js} +2 -2
  145. package/dashboard/dist/assets/{RunAsSelector-tgEooTyU.js.map → RunAsSelector-6BLScYTX.js.map} +1 -1
  146. package/dashboard/dist/assets/{ScanCodesPage-CUv_8ic6.js → ScanCodesPage-Cv9q8Bvt.js} +2 -2
  147. package/dashboard/dist/assets/{ScanCodesPage-CUv_8ic6.js.map → ScanCodesPage-Cv9q8Bvt.js.map} +1 -1
  148. package/dashboard/dist/assets/ScanSchemeDetailPage-BxazXYIc.js +2 -0
  149. package/dashboard/dist/assets/ScanSchemeDetailPage-BxazXYIc.js.map +1 -0
  150. package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js +2 -0
  151. package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js.map +1 -0
  152. package/dashboard/dist/assets/{StickyPagination-CsTI_gvJ.js → StickyPagination-DsdtYoXR.js} +2 -2
  153. package/dashboard/dist/assets/{StickyPagination-CsTI_gvJ.js.map → StickyPagination-DsdtYoXR.js.map} +1 -1
  154. package/dashboard/dist/assets/{StreamMessageDetail-auRlvjTh.js → StreamMessageDetail-CT3FQoT3.js} +2 -2
  155. package/dashboard/dist/assets/{StreamMessageDetail-auRlvjTh.js.map → StreamMessageDetail-CT3FQoT3.js.map} +1 -1
  156. package/dashboard/dist/assets/{SwimlaneTimeline-BLoVHYAd.js → SwimlaneTimeline-C8TjkJ10.js} +2 -2
  157. package/dashboard/dist/assets/{SwimlaneTimeline-BLoVHYAd.js.map → SwimlaneTimeline-C8TjkJ10.js.map} +1 -1
  158. package/dashboard/dist/assets/{TaskDetailPage-BPsZ1bK_.js → TaskDetailPage-DGUzdBFN.js} +2 -2
  159. package/dashboard/dist/assets/{TaskDetailPage-BPsZ1bK_.js.map → TaskDetailPage-DGUzdBFN.js.map} +1 -1
  160. package/dashboard/dist/assets/{TasksListPage-BNGM74yT.js → TasksListPage-BVIP6-EZ.js} +2 -2
  161. package/dashboard/dist/assets/{TasksListPage-BNGM74yT.js.map → TasksListPage-BVIP6-EZ.js.map} +1 -1
  162. package/dashboard/dist/assets/{TimeAgo-BnAHXGK7.js → TimeAgo-C-rd9F9g.js} +2 -2
  163. package/dashboard/dist/assets/{TimeAgo-BnAHXGK7.js.map → TimeAgo-C-rd9F9g.js.map} +1 -1
  164. package/dashboard/dist/assets/{TimestampCell-J4yae6mc.js → TimestampCell-DPbchDOI.js} +2 -2
  165. package/dashboard/dist/assets/{TimestampCell-J4yae6mc.js.map → TimestampCell-DPbchDOI.js.map} +1 -1
  166. package/dashboard/dist/assets/{ToolTestPanel-BdzzgXDu.js → ToolTestPanel-DAUC8DHK.js} +2 -2
  167. package/dashboard/dist/assets/{ToolTestPanel-BdzzgXDu.js.map → ToolTestPanel-DAUC8DHK.js.map} +1 -1
  168. package/dashboard/dist/assets/{TopicDetailPage-DJKg8lb7.js → TopicDetailPage-70mMKBzG.js} +2 -2
  169. package/dashboard/dist/assets/{TopicDetailPage-DJKg8lb7.js.map → TopicDetailPage-70mMKBzG.js.map} +1 -1
  170. package/dashboard/dist/assets/{TopicsPage-DQV0WxG6.js → TopicsPage-CE3hBthn.js} +2 -2
  171. package/dashboard/dist/assets/{TopicsPage-DQV0WxG6.js.map → TopicsPage-CE3hBthn.js.map} +1 -1
  172. package/dashboard/dist/assets/{UserName-Ct09nGh5.js → UserName-BDBDA-LR.js} +2 -2
  173. package/dashboard/dist/assets/{UserName-Ct09nGh5.js.map → UserName-BDBDA-LR.js.map} +1 -1
  174. package/dashboard/dist/assets/{WorkflowExecutionPage-B5WJOsee.js → WorkflowExecutionPage-BbkLZ1co.js} +2 -2
  175. package/dashboard/dist/assets/{WorkflowExecutionPage-B5WJOsee.js.map → WorkflowExecutionPage-BbkLZ1co.js.map} +1 -1
  176. package/dashboard/dist/assets/{WorkflowsDashboard-Hc87TRgD.js → WorkflowsDashboard-Bp1L7Ggz.js} +2 -2
  177. package/dashboard/dist/assets/{WorkflowsDashboard-Hc87TRgD.js.map → WorkflowsDashboard-Bp1L7Ggz.js.map} +1 -1
  178. package/dashboard/dist/assets/{WorkflowsOverview-CJQbyOj-.js → WorkflowsOverview-IeTKHAi4.js} +2 -2
  179. package/dashboard/dist/assets/{WorkflowsOverview-CJQbyOj-.js.map → WorkflowsOverview-IeTKHAi4.js.map} +1 -1
  180. package/dashboard/dist/assets/{YamlWorkflowDetailPage-BMeED677.js → YamlWorkflowDetailPage-DtKCXnKt.js} +2 -2
  181. package/dashboard/dist/assets/{YamlWorkflowDetailPage-BMeED677.js.map → YamlWorkflowDetailPage-DtKCXnKt.js.map} +1 -1
  182. package/dashboard/dist/assets/{YamlWorkflowsPage-BMMg0Id6.js → YamlWorkflowsPage-CEcZBV_3.js} +2 -2
  183. package/dashboard/dist/assets/{YamlWorkflowsPage-BMMg0Id6.js.map → YamlWorkflowsPage-CEcZBV_3.js.map} +1 -1
  184. package/dashboard/dist/assets/{agents-CdFkgFvg.js → agents-BT-sEk81.js} +2 -2
  185. package/dashboard/dist/assets/{agents-CdFkgFvg.js.map → agents-BT-sEk81.js.map} +1 -1
  186. package/dashboard/dist/assets/{bots-Mj3LHWWg.js → bots-DRoAdLek.js} +2 -2
  187. package/dashboard/dist/assets/{bots-Mj3LHWWg.js.map → bots-DRoAdLek.js.map} +1 -1
  188. package/dashboard/dist/assets/{capabilities-Dw1ObK2-.js → capabilities-Bc-nJk6y.js} +2 -2
  189. package/dashboard/dist/assets/{capabilities-Dw1ObK2-.js.map → capabilities-Bc-nJk6y.js.map} +1 -1
  190. package/dashboard/dist/assets/{controlplane-DcNE1APv.js → controlplane-aXceSIRf.js} +2 -2
  191. package/dashboard/dist/assets/{controlplane-DcNE1APv.js.map → controlplane-aXceSIRf.js.map} +1 -1
  192. package/dashboard/dist/assets/{escalation-columns-D364Trpy.js → escalation-columns-Bf09Q89t.js} +2 -2
  193. package/dashboard/dist/assets/{escalation-columns-D364Trpy.js.map → escalation-columns-Bf09Q89t.js.map} +1 -1
  194. package/dashboard/dist/assets/index-BCFEQEMC.js +2 -0
  195. package/dashboard/dist/assets/index-BCFEQEMC.js.map +1 -0
  196. package/dashboard/dist/assets/{index-Bd6-KmBE.js → index-BEPKAjna.js} +2 -2
  197. package/dashboard/dist/assets/{index-Bd6-KmBE.js.map → index-BEPKAjna.js.map} +1 -1
  198. package/dashboard/dist/assets/{index-BQeHJHYN.js → index-BUYokcrl.js} +25 -25
  199. package/dashboard/dist/assets/index-BUYokcrl.js.map +1 -0
  200. package/dashboard/dist/assets/{index-MDD4JYtu.js → index-Ba-s5Yb5.js} +2 -2
  201. package/dashboard/dist/assets/{index-MDD4JYtu.js.map → index-Ba-s5Yb5.js.map} +1 -1
  202. package/dashboard/dist/assets/{index-BRGTmoYY.js → index-C3VTJcrp.js} +2 -2
  203. package/dashboard/dist/assets/{index-BRGTmoYY.js.map → index-C3VTJcrp.js.map} +1 -1
  204. package/dashboard/dist/assets/{index-Dyotfa_k.js → index-CZyO9hRb.js} +2 -2
  205. package/dashboard/dist/assets/{index-Dyotfa_k.js.map → index-CZyO9hRb.js.map} +1 -1
  206. package/dashboard/dist/assets/{index-eDm6cz0F.js → index-CcgmR-7-.js} +2 -2
  207. package/dashboard/dist/assets/{index-eDm6cz0F.js.map → index-CcgmR-7-.js.map} +1 -1
  208. package/dashboard/dist/assets/{index-DkcI4V_H.js → index-CuBGGwXf.js} +2 -2
  209. package/dashboard/dist/assets/{index-DkcI4V_H.js.map → index-CuBGGwXf.js.map} +1 -1
  210. package/dashboard/dist/assets/index-D1mKf_qz.js +3 -0
  211. package/dashboard/dist/assets/index-D1mKf_qz.js.map +1 -0
  212. package/dashboard/dist/assets/{index-Bq5XNEzD.js → index-DBxpyIw5.js} +2 -2
  213. package/dashboard/dist/assets/{index-Bq5XNEzD.js.map → index-DBxpyIw5.js.map} +1 -1
  214. package/dashboard/dist/assets/{index-B3veJ698.js → index-DH03y-UT.js} +2 -2
  215. package/dashboard/dist/assets/{index-B3veJ698.js.map → index-DH03y-UT.js.map} +1 -1
  216. package/dashboard/dist/assets/{index-BiVce3n0.js → index-Djsoi8DI.js} +2 -2
  217. package/dashboard/dist/assets/{index-BiVce3n0.js.map → index-Djsoi8DI.js.map} +1 -1
  218. package/dashboard/dist/assets/{index-DPStdq4T.js → index-h2gX31B2.js} +2 -2
  219. package/dashboard/dist/assets/{index-DPStdq4T.js.map → index-h2gX31B2.js.map} +1 -1
  220. package/dashboard/dist/assets/{knowledge-Bafewjxk.js → knowledge-BhW8V-Hq.js} +2 -2
  221. package/dashboard/dist/assets/{knowledge-Bafewjxk.js.map → knowledge-BhW8V-Hq.js.map} +1 -1
  222. package/dashboard/dist/assets/{mcp-vLIutbnc.js → mcp-BYfSMQzh.js} +2 -2
  223. package/dashboard/dist/assets/{mcp-vLIutbnc.js.map → mcp-BYfSMQzh.js.map} +1 -1
  224. package/dashboard/dist/assets/{mcp-query-BzTtIG90.js → mcp-query-DUJoOk_q.js} +2 -2
  225. package/dashboard/dist/assets/{mcp-query-BzTtIG90.js.map → mcp-query-DUJoOk_q.js.map} +1 -1
  226. package/dashboard/dist/assets/metadata-display-B7X5hGxG.js +2 -0
  227. package/dashboard/dist/assets/metadata-display-B7X5hGxG.js.map +1 -0
  228. package/dashboard/dist/assets/{personas-WD40EDS_.js → personas-jT1O_SB4.js} +2 -2
  229. package/dashboard/dist/assets/{personas-WD40EDS_.js.map → personas-jT1O_SB4.js.map} +1 -1
  230. package/dashboard/dist/assets/{pipelines-DFwULWs3.js → pipelines-Bp-wIaz2.js} +2 -2
  231. package/dashboard/dist/assets/{pipelines-DFwULWs3.js.map → pipelines-Bp-wIaz2.js.map} +1 -1
  232. package/dashboard/dist/assets/{tasks-La_-WAUn.js → tasks-CCrvnXbz.js} +2 -2
  233. package/dashboard/dist/assets/{tasks-La_-WAUn.js.map → tasks-CCrvnXbz.js.map} +1 -1
  234. package/dashboard/dist/assets/{topics-CzYMlvqm.js → topics-Blft0I1L.js} +2 -2
  235. package/dashboard/dist/assets/{topics-CzYMlvqm.js.map → topics-Blft0I1L.js.map} +1 -1
  236. package/dashboard/dist/assets/{useDebouncedValue-C0FQyANW.js → useDebouncedValue-BYqbcism.js} +2 -2
  237. package/dashboard/dist/assets/{useDebouncedValue-C0FQyANW.js.map → useDebouncedValue-BYqbcism.js.map} +1 -1
  238. package/dashboard/dist/assets/{useNamespace-WW_XjAb3.js → useNamespace-BfxJAUgG.js} +2 -2
  239. package/dashboard/dist/assets/{useNamespace-WW_XjAb3.js.map → useNamespace-BfxJAUgG.js.map} +1 -1
  240. package/dashboard/dist/assets/{useYamlActivityEvents-B3YxPeFt.js → useYamlActivityEvents-BukJuWpb.js} +2 -2
  241. package/dashboard/dist/assets/{useYamlActivityEvents-B3YxPeFt.js.map → useYamlActivityEvents-BukJuWpb.js.map} +1 -1
  242. package/dashboard/dist/assets/{yaml-workflows-COHOjdhF.js → yaml-workflows-DeRWqMGk.js} +2 -2
  243. package/dashboard/dist/assets/{yaml-workflows-COHOjdhF.js.map → yaml-workflows-DeRWqMGk.js.map} +1 -1
  244. package/dashboard/dist/index.html +1 -1
  245. package/docs/accumulator.md +1 -1
  246. package/docs/api/sdk/escalations.md +1 -1
  247. package/docs/hitl/escalation.md +12 -0
  248. package/docs/hitl/lookups.md +27 -18
  249. package/docs/hitl/resolution.md +1 -1
  250. package/docs/hitl/x-lt-validation.md +1 -1
  251. package/docs/hitl/x-lt-widget.md +1 -1
  252. package/docs/hitl-guide.md +1 -1
  253. package/docs/scan-codes.md +86 -16
  254. package/package.json +2 -2
  255. package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +0 -1
  256. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +0 -2
  257. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +0 -1
  258. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +0 -2
  259. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +0 -1
  260. package/dashboard/dist/assets/index-BQeHJHYN.js.map +0 -1
  261. package/dashboard/dist/assets/index-BmNAVd4s.js +0 -2
  262. package/dashboard/dist/assets/index-BmNAVd4s.js.map +0 -1
  263. package/dashboard/dist/assets/index-WSm8bgE7.js +0 -3
  264. package/dashboard/dist/assets/index-WSm8bgE7.js.map +0 -1
  265. package/dashboard/dist/assets/metadata-display-COo3mMCr.js +0 -2
  266. package/dashboard/dist/assets/metadata-display-COo3mMCr.js.map +0 -1
@@ -100,11 +100,23 @@ The declaration folds into the row at creation, inside the same Leg1 commit:
100
100
  - `metadata.batch_keys` — the immutable declared list (progress = `batch_keys` minus `batch_pending`)
101
101
  - `envelope.batch_items` — the accumulated `Record<itemKey, payload>` map (payloads are plumbing, so they live on the unindexed envelope; payload keys are caller-owned)
102
102
  - `envelope.batch_filled_at` — `Record<itemKey, iso8601>`, stamped by the database clock inside each fill statement — the collection timeline as row truth
103
+ - `envelope.batch_filled_by` — `Record<itemKey, userId>`, the actor of each fill, written in the same statement (every API fill records its caller)
103
104
 
104
105
  Items are submitted via `POST /api/escalations/:id/resolve-batch-item`, `POST /api/escalations/resolve-batch-item-by-signal-key` (the deterministic home signal id — no UUID lookup, no facet duplication), or `POST /api/escalations/resolve-batch-item-by-metadata` (see [Resolution — Batch items](resolution.md)). Each item validates against the same versioned role form a single-item resolver gets, `schemaVersion` pins included. Each fill is one guarded statement: the payload lands only while its key is still pending (duplicates return `duplicate-item` untouched), and the LAST fill resolves the row, stores the assembled collection as `resolver_payload`, and wakes this wait — atomically. The completing submission's `$resolution` rides the delivered collection.
105
106
 
106
107
  `timeout` and cancellation keep their standard semantics (`false` / `null`); a plain resolve on a batch row remains an admin override that resolves the whole row with the payload given. Add `partialOnTimeout: true` (hotmesh 0.29.0+) and the timer instead resumes the wait with the items filled so far plus `$trigger: 'timeout'`, the same value the expired row stores as `resolver_payload`.
107
108
 
109
+ Entries already satisfied before the wait begins go in `filled` (hotmesh 0.31.0+), keyed by item key with their `payload`, the `at` they were satisfied (from the source of record, never a clock read in the workflow), and an optional `actor`. The row starts with that progress: those keys are left out of `batch_pending`, their payloads, times, and actors are written beside the rest, and the completing wake delivers them with the collection. Every key in `filled` must be declared in `batch`, and at least one must stay open; a `filled` that covers every key throws, so skip the wait instead.
110
+
111
+ ```typescript
112
+ const parts = await conditional<Record<'cut' | 'weld' | 'paint', StationResultV1>>(signalId, {
113
+ role: 'assembly',
114
+ metadata: { orderId },
115
+ batch: ['cut', 'weld', 'paint'],
116
+ filled: { cut: { payload: { station: 'cut-1', ok: true }, at: cutRecord.completedAt, actor: cutRecord.userId } },
117
+ });
118
+ ```
119
+
108
120
  ### Open accumulation — items arrive over time
109
121
 
110
122
  Declare `accumulate` and the escalation becomes an open container: items join it one at a time through `accumulateItem` while the row stays pending, and the wait resumes with the ordered collection when the container is full, when its window closes, or when someone resolves it by hand. A timeout is a delivery, never a failure, so the wait has no `false` branch; `conditionalAccumulator` types that contract.
@@ -1,45 +1,52 @@
1
1
  # Versioned Knowledge Lookups
2
2
 
3
- An escalation can pin **versioned knowledge lookups** — enumerated lists (select options, checklist items, cascade maps) that live once in the knowledge store and are referenced by thousands of rows. The refs ride the escalation; the content does not. Forms address the resolved content through the `lookup.*` context domain, so the full x-lt vocabulary works against it: `x-lt-options`, `x-lt-source`, `x-lt-showIf`, `x-lt-help`.
3
+ An escalation can reference **versioned knowledge lookups** — enumerated lists (select options, checklist items, cascade maps) that live once in the knowledge store and are referenced by thousands of rows. The refs ride the escalation; the content does not. Forms address the resolved content through the `lookup.*` context domain, so the full x-lt vocabulary works against it: `x-lt-options`, `x-lt-source`, `x-lt-showIf`, `x-lt-help`.
4
4
 
5
5
  ---
6
6
 
7
7
  ## The Ref
8
8
 
9
9
  ```json
10
- { "domain": "catalog", "key": "materials", "version": 2, "as": "materials" }
10
+ { "domain": "catalog", "key": "materials", "as": "materials" }
11
+ { "domain": "catalog", "key": "materials", "version": 2 }
11
12
  ```
12
13
 
13
14
  | Field | Required | Meaning |
14
15
  |-------|----------|---------|
15
16
  | `domain` | yes | Knowledge domain |
16
17
  | `key` | yes | Entry key within the domain |
17
- | `version` | yes | The immutable edition this escalation reads |
18
+ | `version` | no | An edition to pin. Absent or `"current"`, the ref follows the newest edition |
18
19
  | `as` | no | The ref's form-context address, when the key alone is ambiguous |
19
20
 
20
- `version` is required by design. A ref names an **immutable edition**, never a moving target: every escalation created against edition 2 renders edition 2 forever, however the entry evolves afterward. Refs live under the reserved `envelope.lookups` key — the unindexed, render-only bag beside `formDefaults`. They ride the engine's atomic write but never touch the GIN-indexed metadata surface: refs are form plumbing, not facets.
21
+ **Current refs** (no `version`, or `"current"`) read the entry's newest edition. A pending row reads the edition in force when its form renders, so a row that stays open for days shows today's list. A resolved or cancelled row reads the edition that was current when it closed, so its history shows the list its work was done against. Form schemas stay pinned (`schemaVersion`); the lists they read follow the knowledge entry.
22
+
23
+ **Pinned refs** (`version: N`) name an immutable edition: every escalation created against edition 2 renders edition 2 forever, however the entry evolves afterward. Pin when the form must read one exact edition.
24
+
25
+ A value picked from a current list is validated against the edition in force at submit, so an option removed while the form was open is refused with the canonical 422 and the person picks again.
26
+
27
+ Refs live under the reserved `envelope.lookups` key — the unindexed, render-only bag beside `formDefaults`. They ride the engine's atomic write but never touch the GIN-indexed metadata surface: refs are form plumbing, not facets.
21
28
 
22
29
  ## Creating an Escalation with Lookups
23
30
 
24
- Pass `lookups` to `conditional` — the same compile-time-literal discipline as `schemaVersion`:
31
+ Pass `lookups` to `conditional`:
25
32
 
26
33
  ```typescript
27
34
  const decision = await conditional<CascadeResolverV1>(signalId, {
28
35
  role: 'catalog-picker',
29
36
  description: 'Pick a material for this order',
30
37
  lookups: [
31
- { domain: 'catalog', key: 'materials', version: 2 },
32
- { domain: 'catalog', key: 'geo', version: 1 },
38
+ { domain: 'catalog', key: 'materials' }, // the newest edition
39
+ { domain: 'catalog', key: 'geo', version: 1 }, // pinned
33
40
  ],
34
41
  schemaVersion: 1,
35
42
  });
36
43
  ```
37
44
 
38
- The refs fold into `envelope.lookups` as a pure transform — a pinned wait costs exactly what an unpinned one does. A malformed ref (missing field, non-integer version) throws before the row is written; over the HTTP create surface the same validation answers with a 400.
45
+ The refs fold into `envelope.lookups` as a pure transform — a wait with refs costs exactly what one without does. A malformed ref (missing field, a version that is not a positive integer or `"current"`) throws before the row is written; over the HTTP create surface the same validation answers with a 400.
39
46
 
40
47
  ## Pinning on a Workflow Config
41
48
 
42
- An invoke form pins editions the same way. Declare `inputLookups` beside `inputSchema` on the worker config and the form reads them under `lookup.<as ?? key>`:
49
+ An invoke form references editions the same way. Declare `inputLookups` beside `inputSchema` on the worker config and the form reads them under `lookup.<as ?? key>`:
43
50
 
44
51
  ```typescript
45
52
  const fleetToolsConfig: LTWorkerConfig = {
@@ -54,29 +61,31 @@ const fleetToolsConfig: LTWorkerConfig = {
54
61
  "serialNumber": { "type": "string", "title": "Serial", "x-lt-options": "lookup.serials.items" }
55
62
  ```
56
63
 
57
- The Invoke Tool page fetches `GET /api/workflows/:type/input-lookups` once per workflow; the grant is the invoke predicate, so whoever may start the workflow reads exactly the pinned editions. The invoke API resolves the same refs into the gate, so a value outside the edition is refused with the canonical 422. The registry detail page edits the refs under **Lookups** in its Invocation column; the preview renders against the resolved editions.
64
+ The Invoke Tool page fetches `GET /api/workflows/:type/input-lookups` each time the form opens; the grant is the invoke predicate, so whoever may start the workflow reads exactly the entries the config names. The invoke API resolves the same refs into the gate, so a value outside the edition is refused with the canonical 422. The registry detail page edits the refs under **Lookups** in its Invocation column; the preview renders against the resolved editions.
58
65
 
59
- The refs are checked twice on save. Shape first: a missing `domain` or `key`, a `version` that is not a positive integer, or an empty `as` answers `400` with the field named. Existence second: a ref whose edition does not exist answers `400` naming the editions that do (`Lookup ref fleet/serial-numbers v3 names no edition (editions: v1, v2)`), from `PUT /api/workflows/:type/config` and from the MCP `upsert_workflow_config` tool alike. On the worker boot path a malformed ref fails the boot; a ref whose edition is not yet written logs a warning, since seeds commonly run after registration. At run time the resolver reads each edition once and holds it in memory (editions are immutable), a missing edition answers `missing: true` for that ref without failing the batch, the Invoke Tool page shows which pinned editions are unavailable, and the fields that read them follow the `x-lt-options` rules: a plain path falls back to the typed input, an interpolated path stays a disabled select and fails closed.
66
+ The refs are checked twice on save. Shape first: a missing `domain` or `key`, a `version` that is not a positive integer or `"current"`, or an empty `as` answers `400` with the field named. Existence second: a ref with no edition behind it answers `400` naming the editions that do (`Lookup ref fleet/serial-numbers v3 names no edition (editions: v1, v2)`; a current ref to an entry with no editions says `current`), from `PUT /api/workflows/:type/config` and from the MCP `upsert_workflow_config` tool alike. On the worker boot path a malformed ref fails the boot; a ref whose edition is not yet written logs a warning, since seeds commonly run after registration. At run time the resolver holds each edition in memory once read (editions are immutable; a current ref first looks up which edition is newest), a missing edition answers `missing: true` for that ref without failing the batch, the Invoke Tool page shows which editions are unavailable, and the fields that read them follow the `x-lt-options` rules: a plain path falls back to the typed input, an interpolated path stays a disabled select and fails closed.
60
67
 
61
68
  ## Versioning
62
69
 
63
70
  Every knowledge entry carries a `current_version`, and every write that changes its data mints an immutable snapshot automatically — no publish step:
64
71
 
65
72
  1. **Add items** — write the entry (`storeEntry`, `set_knowledge_field`, the dashboard editor). The data change bumps `current_version` and snapshots the new edition. Writes that leave the data unchanged mint nothing.
66
- 2. **Repin** — update the workflow's `lookups` literal to the new version, evolving the resolver payload type alongside when the new items change what the form can answer.
67
- 3. **Rows in flight keep their edition** — an escalation pinned to v1 renders v1's list even after v5 exists.
73
+ 2. **Current refs follow** — every pending row with a current ref shows the new edition on its next render. Nothing to repin.
74
+ 3. **Pinned rows keep their edition** — an escalation pinned to v1 renders v1's list even after v5 exists. Repin the literal (and evolve the resolver payload type) when a pinned form should move.
68
75
 
69
76
  Inspect the lineage with `GET /api/knowledge/entry/versions?domain=catalog&key=materials`, `ltc kb versions catalog materials`, or the `list_knowledge_versions` MCP tool. Fetch a specific edition with `?version=N` on the entry endpoint.
70
77
 
71
78
  ## The Grant
72
79
 
73
- The refs on the row ARE the grant. Any user who may read the escalation may fetch exactly the pinned editions it names:
80
+ The refs on the row ARE the grant. Any user who may read the escalation may fetch exactly the entries it names, at the editions those refs resolve to:
74
81
 
75
82
  ```
76
83
  GET /api/escalations/:id/lookups
77
- → { "lookups": [{ "domain": "catalog", "key": "materials", "version": 2, "data": { "items": [...] } }] }
84
+ → { "lookups": [{ "domain": "catalog", "key": "materials", "version": 4, "current": true, "data": { "items": [...] } }] }
78
85
  ```
79
86
 
87
+ `version` is the edition served; `current: true` marks a ref that follows the newest edition.
88
+
80
89
  The general knowledge API (`/api/knowledge/*`) is a builder surface — superadmin or engineer. A member never queries the knowledge store directly; the escalation-scoped endpoint serves them precisely the editions their work item carries, and nothing else. A ref whose snapshot does not exist answers with `missing: true` for that ref — the batch never fails.
81
90
 
82
91
  ## Form Addressing
@@ -113,7 +122,7 @@ Option entries are scalars or `{ value, label }` objects (`{ id, label }` accept
113
122
 
114
123
  The select renders the labels, the submitted answer is the value, and mixed arrays resolve each entry independently (a scalar is both).
115
124
 
116
- Membership is enforced on both sides of the wire: the dashboard constrains the choices, and an `enforce_schema` role's server gate re-resolves the same pinned editions and rejects an out-of-edition value with the canonical 422.
125
+ Membership is enforced on both sides of the wire: the dashboard constrains the choices, and an `enforce_schema` role's server gate re-resolves the same refs (a current ref at the edition in force at submit) and rejects an out-of-edition value with the canonical 422.
117
126
 
118
127
  ## Cascading Selects
119
128
 
@@ -162,9 +171,9 @@ A lookup-sourced checklist can declare `"x-lt-default-checked": true` to start e
162
171
  ## Efficiency
163
172
 
164
173
  - **Refs, not content, ride the rows.** Thousands of escalations sharing one list each store a three-field ref; the list lives once per edition.
165
- - **One fetch per page.** The resolve UI batch-fetches all refs in a single `GET /:id/lookups` call at load. Pinned editions are immutable, so the response caches for the whole session.
174
+ - **One fetch per page.** The resolve UI batch-fetches all refs in a single `GET /:id/lookups` call each time the page opens (never on focus or a timer), so a current ref shows the newest edition on the next open.
166
175
  - **Zero network during execution.** Cascade levels resolve locally from the already-fetched entry data — every keystroke re-resolves in memory.
167
- - **Server-side, snapshots cache indefinitely.** Enforcement reads come from an in-process LRU keyed by `(domain, key, version)`; the first row referencing an edition pays the read, every later row hits memory.
176
+ - **Server-side, snapshots cache indefinitely.** Enforcement reads come from an in-process LRU keyed by `(domain, key, version)`; the first row referencing an edition pays the read, every later row hits memory. A current ref adds one indexed read (the newest edition by primary key) per resolution.
168
177
 
169
178
  ## Reference Example
170
179
 
@@ -107,7 +107,7 @@ Interim items return `accepted` with the remaining count and publish `escalation
107
107
 
108
108
  Each item validates against the same versioned role form a single-item resolve uses, canonical 422 included. Batch fills are claim-agnostic — a batch collects contributions from multiple principals, the same rationale as the signal-key path — while `assertClaim: true` (by-id form) opts into the caller's own live-claim assertion inside the guarded statement.
109
109
 
110
- Item keys are non-empty strings up to 128 characters; prefer URL-friendly names (`u1-L`). Payload keys inside each item are caller-owned — the platform reserves no names inside `batch_items` values. Every fill stamps `envelope.batch_filled_at[itemKey]` with the database clock in the same statement, so the row carries the collection timeline as row truth. After an SLA expiry (`conditional` returns `false`) the terminal row retains the partial `batch_items` and their timestamps — read them back with `GET /api/escalations/:id` or `getEscalationBySignalKey` from an activity.
110
+ Item keys are non-empty strings up to 128 characters; prefer URL-friendly names (`u1-L`). Payload keys inside each item are caller-owned — the platform reserves no names inside `batch_items` values. Every fill stamps `envelope.batch_filled_at[itemKey]` with the database clock and `envelope.batch_filled_by[itemKey]` with the caller in the same statement, so the row carries the collection timeline and who filled each item as row truth. After an SLA expiry (`conditional` returns `false`) the terminal row retains the partial `batch_items` and their timestamps — read them back with `GET /api/escalations/:id` or `getEscalationBySignalKey` from an activity.
111
111
 
112
112
  ### Accumulator items
113
113
 
@@ -143,7 +143,7 @@ When the envelope carries `left_quantity_options: [0, 1, 2, 3]`, the field rende
143
143
  - While the current value is outside the option list (an empty init, options that shrank per-row), the select opens on an explicit disabled **Choose…** placeholder — never an implicit first option.
144
144
  - When no path resolves (missing, empty array, no valid entries) the field renders as the plain input for its type and membership is not enforced for that submission — unless any path embeds `{{domain.path}}` interpolation, in which case the field stays a disabled select and a present value fails closed (a cascade child never becomes free text).
145
145
  - Membership is enforced on both sides of the wire — always on the option VALUE, never the label: the dashboard constrains the choices, and an enforced role's server gate rejects a payload whose value is outside the row's resolved list with the canonical 422 (`Must be one of: 0, 1, 2, 3`).
146
- - Option lists can also come from version-pinned knowledge entries (the `lookup` domain), and paths may embed `{{domain.path}}` interpolation segments for cascading selects — a dependent select whose parent is unanswered renders disabled and fails closed. See [lookups.md](lookups.md).
146
+ - Option lists can also come from versioned knowledge entries (the `lookup` domain), and paths may embed `{{domain.path}}` interpolation segments for cascading selects — a dependent select whose parent is unanswered renders disabled and fails closed. See [lookups.md](lookups.md).
147
147
 
148
148
  ---
149
149
 
@@ -172,7 +172,7 @@ The field type must be `"object"`. The submitted value is `Record<string, boolea
172
172
  `x-lt-source` uses the `"domain.path"` convention (same as `x-lt-showIf` and `x-lt-help` tokens), and may embed `{{domain.path}}` interpolation segments. The token is a single path or an **ordered array of paths** — the first that resolves to items wins, so a lookup-backed row and an envelope-embedded row render the same shared schema interchangeably. The renderer expects an array of `{ id: string; label: string; required?: boolean }` objects at the resolved path.
173
173
 
174
174
  - `"envelope"` — for item definitions that are render data only (no query cost). The workflow puts them in `conditional`'s `envelope` parameter.
175
- - `"lookup"` — for item sets shared by many rows: a version-pinned knowledge edition (see [lookups.md](lookups.md)).
175
+ - `"lookup"` — for item sets shared by many rows: a versioned knowledge edition, pinned or current (see [lookups.md](lookups.md)).
176
176
  - `"metadata"` — only when items need to be GIN-indexed and searchable as facets. Adds index cost.
177
177
 
178
178
  ### First-load default (`x-lt-default-checked`)
@@ -70,7 +70,7 @@ When you author a HITL-backed workflow, the platform handles:
70
70
  - **AI triage** — optional auto-resolution for common patterns
71
71
  - **Credential security** — password fields use ephemeral tokens, never stored in plain text
72
72
  - **Schema enforcement** — roles with `enforce_schema` validate every resolver payload server-side (dashboard, API, MCP, CLI alike) with the same pass the form runs, rejecting violations as a structured 422 (see [schema-enforcement.md](schema-enforcement.md))
73
- - **Versioned lookups** — escalations pin immutable knowledge editions for their option lists; the refs grant readers exactly those editions, and cascading selects resolve locally from one batch fetch (see [lookups.md](hitl/lookups.md))
73
+ - **Versioned lookups** — escalations reference knowledge entries for their option lists, following the newest edition or pinned to one; the refs grant readers exactly those entries, and cascading selects resolve locally from one batch fetch (see [lookups.md](hitl/lookups.md))
74
74
  - **Telemetry** — trace IDs link escalations to OpenTelemetry traces
75
75
  - **Bulk operations** — bulk claim, assign, triage, and cancel for queue management
76
76
  - **Cancellation** — cancel pending escalations from the API or dashboard
@@ -88,7 +88,8 @@ Each step:
88
88
  "roles": ["printer-fleet"], // expected queue(s)
89
89
  "status": "pending", // pending | resolved | cancelled
90
90
  "availability": "available", // available | claimed | mine | any
91
- "facets": { "state": "printing" } // extra metadata guards
91
+ "facets": { "state": "printing" }, // extra metadata guards
92
+ "subtypes": ["open"] // optional: types / subtypes the row must have
92
93
  },
93
94
  "cardinality": "first", // first | many
94
95
  "verb": "resolve",
@@ -97,6 +98,14 @@ Each step:
97
98
  }
98
99
  ```
99
100
 
101
+ `query.types` and `query.subtypes` narrow steps that locate a row and then
102
+ act on it by id: `show-detail`, `show-list`, `present` (with any choice; each
103
+ choice writes the row shown), `hold`, `fill`, and `accumulate`
104
+ (container-locate mode narrows the container). Claim, cancel, release,
105
+ resolve and escalate steps locate by the target facet inside their atomic
106
+ statement, so the upsert refuses types/subtypes on them; to narrow one, offer
107
+ it as a `present` choice. With `availability: "mine"` each takes one entry.
108
+
100
109
  Verbs are the canonical escalation actions:
101
110
 
102
111
  | Verb | Effect | Params |
@@ -219,10 +228,32 @@ unsatisfied. Picking one calls `POST /api/scan-codes/execute-choice` with a
219
228
  pointer (scheme, category, step index, choice index, escalation id) — and a
220
229
  pointer is never authority: the server re-reads live config, re-locates the
221
230
  row under the step's query, re-applies the identity gate, and runs the verb
222
- through the same atomic executors a direct scan uses. A resolve choice
223
- resolves the exact row the screen presented, re-checked under the step's
224
- query in the same statement. A row that moved on between render and tap
225
- answers `conflict`, exactly as a lost double-scan.
231
+ through the same atomic executors a direct scan uses. Every choice writes
232
+ the exact row the screen presented, by id: claim, cancel, resolve and an
233
+ escalate's `closeCurrent` re-check that row (pending, the scanned code, the
234
+ step's roles, no live claim by someone else) in the same statement, and
235
+ release releases that row when it is the actor's claim. When one code names
236
+ several pending rows, the write never lands on a different one. A row that
237
+ moved on between render and tap answers `conflict`, exactly as a lost
238
+ double-scan.
239
+
240
+ A `present` step names the facts the station states about the row with
241
+ `facts`: up to 12 labeled templates, rendered server-side against the row
242
+ (`{item.<facet>}`) and the scan tokens, shown in order. A token the row cannot
243
+ fill renders as a dash.
244
+
245
+ ```jsonc
246
+ "facts": [
247
+ { "label": "Bin", "value": "{item.binCode}" },
248
+ { "label": "Clinic", "value": "{item.facilityName}" },
249
+ { "label": "Bags", "value": "{item.memberCount}" }
250
+ ]
251
+ ```
252
+
253
+ Without `facts`, the station lists the row's metadata, leaving out the
254
+ bookkeeping a bench never acts on: scan provenance (`scannedAt`,
255
+ `scanScheme`, `scanCategory`, `scanStation`, `scanActionName`),
256
+ `resolved_by`, `schema_version`, and the accumulate and batch counters.
226
257
 
227
258
  A choice's `code` is a short printable token (letters, digits, underscore,
228
259
  dash) enabling double-scan selection: scan the object, then scan an action
@@ -271,8 +302,9 @@ set one ("Take the new label from the printer and stick it on C-12").
271
302
  Any step that writes may carry `done: { markdown }`: the copy the station shows,
272
303
  large, once the write lands and until the next scan ("Place it in
273
304
  **{container.containerCode}**. All good."). It reads the same bags its refusal copy
274
- reads. A fill that leaves items to scan shows its done copy as the progress
275
- line under the hold.
305
+ reads. A fill or an into-subject add that leaves slots open shows its done
306
+ copy under the hold; without done copy the station shows the count ("2 of 5
307
+ checked off" for a fill, "2 of 5 added" for an add).
276
308
 
277
309
  The server trusts nothing about the subject. Each request re-parses its
278
310
  code, re-reads the row under the station's read scope, requires the row to
@@ -287,8 +319,8 @@ row.
287
319
  | Step | What the container scan does |
288
320
  |---|---|
289
321
  | `accumulate` with `accumulate.from: "subject"` | The held item joins the accumulator the scan names (found by the scheme facet, narrowed by `accumulate.container`). The held row is written as the reciprocal in the same statement, so a held row parked as a one-slot accumulator completes and its workflow wakes. `params.itemKey` names the item, e.g. `{subject.itemId}`. |
290
- | `accumulate` with `accumulate.into: "subject"` | The held row collects the scanned code (`itemKey` defaults to `{scan.target}`). Use it when the container has no row yet: the first item for a container tells the workflow which container was scanned. |
291
- | `fill` with `fill.into: "subject"` | One expected item is checked off: the held row is a batch whose keys are codes, and the scan fills the first open key for its code. A code expected twice is declared `<code>#1`, `<code>#2` and takes two scans; a third is refused. The answer carries `progress: { filled, total, remaining }`, the subject stays held while items remain, and the last fill completes the row. `fill.into: "scanned"` fills the row the scan itself names. |
322
+ | `accumulate` with `accumulate.into: "subject"` | The held row collects the scanned code (`itemKey` defaults to `{scan.target}`). Use it when the container has no row yet: the first item for a container tells the workflow which container was scanned. With `accumulate.item`, the scanned code's own pending row is written as the reciprocal in the same statement (see below). On a bounded accumulator the answer carries `progress` and the subject stays held while slots remain. |
323
+ | `fill` with `fill.into: "subject"` | One expected item is checked off: the held row is a batch whose keys are codes, and the scan fills the first open key for its code. A code expected twice is declared `<code>#1`, `<code>#2` and takes two scans; a third is refused. The answer carries `progress: { filled, total, remaining }`, the subject stays held while items remain, and the last fill completes the row. On a `gtin` scheme a refusal's `expected` lists codes as the package prints them (EAN-13, or EAN-8), not the stored 14-digit form. `fill.into: "scanned"` fills the row the scan itself names. |
292
324
 
293
325
  **`match` and `refuse`** check the pairing before anything is written.
294
326
  `match.target` lists templates the scanned target must equal (e.g.
@@ -304,6 +336,37 @@ declares `refuse.conflict` also clears the subject so the next item scan
304
336
  reads fresh state. Exactly one of two racing acts wins whenever both name
305
337
  the same row: the reciprocal statement writes both rows or neither.
306
338
 
339
+ **The item's own row on an into-subject add.** A held container that collects
340
+ item codes (a box being packed from a bin) often has items that each wait on
341
+ their own row. `accumulate.item` locates that row and writes it as the
342
+ reciprocal of the container's entry, so the two land together or not at all:
343
+
344
+ ```jsonc
345
+ // 11:0, item label, while the box is held
346
+ { "query": { "roles": ["packing"], "status": "pending" }, "verb": "accumulate",
347
+ "requireActingIdentity": true, "subject": { "schemes": [14] },
348
+ "match": { "target": ["{subject.memberCodes}"] },
349
+ "refuse": { "markdown": "Not one of this bin's items.",
350
+ "missing": "That item is not waiting to be packed." },
351
+ "done": { "markdown": "{item.itemCode} is in. {container.accumulate_count} of {container.accumulate_max}." },
352
+ "params": { "itemKey": "{scan.target}",
353
+ "accumulate": { "into": "subject", "item": { "roles": ["ship"], "facets": { "shape": "consolidated" } } } } }
354
+ ```
355
+
356
+ The item row is a pending accumulator whose scheme facet equals the scanned
357
+ target (a plain row carrying the same code is not a candidate: only an
358
+ accumulator can take the reciprocal entry), in `item.roles` (intersected with the actor's read scope), narrowed by
359
+ `item.types`, `item.subtypes` and `item.facets`; the held row is never a
360
+ candidate. Parked as `max: 1`, it completes in the same statement and its
361
+ workflow wakes with the container's id in `$accumulated`. No such row answers
362
+ `refused` with `refuse.missing` (or falls through without it); two answer
363
+ `conflict`. An item already placed elsewhere is refused with the box still
364
+ held, an item scanned twice into it answers `already` with the box still
365
+ held, and a live claim on the item row by someone else refuses with their
366
+ name (checked before the write; the statement itself does not re-check it). `{item.<facet>}` reads the item row in `itemKey`, the payload,
367
+ metadata and copy; `{container.<facet>}` in the copy reads the held row as the
368
+ add left it.
369
+
307
370
  **One rule, several kinds of held item.** `subject.facets` makes a step
308
371
  apply only while the held row carries those facet values; otherwise the step
309
372
  is skipped and the next one runs. A placing bench uses it to tell an item
@@ -444,7 +507,10 @@ signed-in user is a **member of exactly that one role** — the station-login
444
507
  shape — the dashboard locks the viewport: the left nav is gone entirely, the
445
508
  role's escalation list is home (`/` and every other surface redirect to it),
446
509
  and the session is held to the list, the escalation detail page, the role's
447
- portals, and the scan screens (choice, badge). A role that declares
510
+ portals, and the scan screens (choice, badge). The list with neither a
511
+ `role` nor a `facets` filter is every queue at once, so it redirects home
512
+ too, including right after sign-in; a scan's `show-list` (narrowed by
513
+ facets) stays. A role that declares
448
514
  [portals](./hitl/portal.md) lands on its first one as home instead of the list. The header toolbar and event feed remain. A user
449
515
  holding more than one role, or an admin-type grant, always gets full chrome —
450
516
  kiosk is for the single-role floor login, never a way to hide the product from
@@ -470,12 +536,16 @@ submit opens a badge prompt naming that claimant. The resolve fires the moment
470
536
  a matching badge primes; a badge that is not the claimant's is named and the
471
537
  submit is held.
472
538
 
473
- The gate is on **use**, not on grant lifetime. Acting grants are single-use:
474
- the claim already spent the grant it was minted with, so the submit owes a
475
- fresh tap — every write consumes its own grant. A held token proves nothing
476
- about whether a submit can succeed, so the surface never lets one skip the
477
- badge. Editing persists nothing locally, so the identity gate sits at the one
478
- place a record actually changes, once per change.
539
+ The gate is on **use**, not on grant lifetime. A live grant that names the
540
+ claimant and has uses left carries the submit and spends one use, as a scan
541
+ act does (release, cancel and escalate always ask); the badge prompt shows only when no such grant is held. The station
542
+ holds a grant only while it has uses left, so a single-use badge spent by the
543
+ claim makes the submit ask for a fresh tap, while a role's
544
+ `badge_grant: { ttl_seconds: 600, max_uses: 0 }` lets one badge claim and
545
+ submit for ten minutes. A grant bound to a scanned subject (`grant_scope:
546
+ "subject"`) belongs to that scan and still asks. Editing persists nothing
547
+ locally, so the identity gate sits at the one place a record actually
548
+ changes, once per change.
479
549
 
480
550
  Mutations attribute to the badged person (`assigned_to`, `resolved_by`)
481
551
  with the device recorded beside them (`scanStation` in the scan
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hotmeshio/long-tail",
3
- "version": "0.22.2",
3
+ "version": "0.23.0",
4
4
  "description": "Long Tail Workflows — Durable AI workflows with human-in-the-loop escalation. Powered by PostgreSQL.",
5
5
  "main": "./build/index.js",
6
6
  "types": "./build/index.d.ts",
@@ -75,7 +75,7 @@
75
75
  "@anthropic-ai/sdk": "^0.92.0",
76
76
  "@aws-sdk/client-s3": "^3.1017.0",
77
77
  "@aws-sdk/s3-request-presigner": "^3.1045.0",
78
- "@hotmeshio/hotmesh": "^0.30.0",
78
+ "@hotmeshio/hotmesh": "^0.31.0",
79
79
  "@modelcontextprotocol/sdk": "^1.27.1",
80
80
  "@opentelemetry/exporter-trace-otlp-proto": "^0.215.0",
81
81
  "@opentelemetry/resources": "^2.5.1",