@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.
- package/build/api/escalations/accumulate.js +7 -1
- package/build/api/escalations/lookups.d.ts +9 -2
- package/build/api/escalations/lookups.js +15 -3
- package/build/api/escalations/metadata.d.ts +2 -0
- package/build/api/escalations/metadata.js +9 -0
- package/build/api/escalations/resolve-batch.d.ts +2 -1
- package/build/api/escalations/resolve-batch.js +6 -5
- package/build/api/scan-codes/locate.js +4 -0
- package/build/api/scan-codes/present.d.ts +1 -1
- package/build/api/scan-codes/present.js +43 -0
- package/build/api/scan-codes/verb-accumulate.js +5 -1
- package/build/api/scan-codes/verb-fill.js +4 -1
- package/build/api/scan-codes/verb-into-subject.d.ts +12 -0
- package/build/api/scan-codes/verb-into-subject.js +157 -0
- package/build/api/scan-codes/verbs-subject.d.ts +23 -4
- package/build/api/scan-codes/verbs-subject.js +32 -55
- package/build/api/scan-codes/verbs.d.ts +10 -8
- package/build/api/scan-codes/verbs.js +25 -16
- package/build/index.d.ts +1 -1
- package/build/index.js +3 -2
- package/build/sdk/index.d.ts +1 -0
- package/build/services/escalation/batch.d.ts +4 -4
- package/build/services/escalation/batch.js +7 -4
- package/build/services/escalation/claim-asserted.d.ts +10 -0
- package/build/services/escalation/claim-asserted.js +64 -0
- package/build/services/escalation/facets.d.ts +3 -1
- package/build/services/escalation/facets.js +7 -3
- package/build/services/escalation/index.d.ts +1 -0
- package/build/services/escalation/index.js +3 -1
- package/build/services/knowledge/lookup-cache.d.ts +16 -4
- package/build/services/knowledge/lookup-cache.js +53 -20
- package/build/services/knowledge/lookup-refs.d.ts +3 -2
- package/build/services/knowledge/lookup-refs.js +6 -4
- package/build/services/knowledge/sql.d.ts +2 -0
- package/build/services/knowledge/sql.js +9 -1
- package/build/services/mcp/server-tools.js +1 -1
- package/build/services/orchestrator/condition.d.ts +17 -11
- package/build/services/orchestrator/condition.js +12 -7
- package/build/services/scan-code/index.d.ts +1 -1
- package/build/services/scan-code/index.js +2 -1
- package/build/services/scan-code/validate-facts.d.ts +5 -0
- package/build/services/scan-code/validate-facts.js +24 -0
- package/build/services/scan-code/validate-query.d.ts +8 -0
- package/build/services/scan-code/validate-query.js +36 -0
- package/build/services/scan-code/validate-subject.js +29 -2
- package/build/services/scan-code/validate.js +17 -8
- package/build/shared/scan-code/gtin.d.ts +6 -0
- package/build/shared/scan-code/gtin.js +13 -0
- package/build/shared/scan-code/index.d.ts +1 -1
- package/build/shared/scan-code/index.js +2 -1
- package/build/system/mcp-servers/admin/schemas.d.ts +185 -5
- package/build/system/mcp-servers/admin/schemas.js +16 -3
- package/build/system/seed/tool-manifests-admin.d.ts +202 -1
- package/build/system/seed/tool-manifests-admin.js +2 -2
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +23 -8
- package/build/types/escalation.js +18 -7
- package/build/types/index.d.ts +3 -3
- package/build/types/index.js +3 -1
- package/build/types/scan-code/response.d.ts +5 -0
- package/build/types/scan-code/rule.d.ts +32 -2
- package/dashboard/dist/assets/{AdminDashboard-DBW12qQt.js → AdminDashboard-DKrqLGjn.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-DBW12qQt.js.map → AdminDashboard-DKrqLGjn.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-CmHv8U9M.js → AgentConfigPage-BoQhRW6U.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-CmHv8U9M.js.map → AgentConfigPage-BoQhRW6U.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-D1scIbz-.js → AgentDetailPage-DZhzuZmO.js} +2 -2
- package/dashboard/dist/assets/{AgentDetailPage-D1scIbz-.js.map → AgentDetailPage-DZhzuZmO.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-BA_ai9HJ.js → AgentsPage-5MynmbWX.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-BA_ai9HJ.js.map → AgentsPage-5MynmbWX.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-C2_5aEFW.js → AvailableEscalationsPage-CWMyy3IL.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-C2_5aEFW.js.map → AvailableEscalationsPage-CWMyy3IL.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-BZo4Kp4a.js → BotPicker-C3LR6Sqy.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-BZo4Kp4a.js.map → BotPicker-C3LR6Sqy.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-BFhyxY2T.js → BulkAssignModal-COjoOIIH.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-BFhyxY2T.js.map → BulkAssignModal-COjoOIIH.js.map} +1 -1
- package/dashboard/dist/assets/{CapabilitiesPage-CvOX6vAc.js → CapabilitiesPage-DKxLvOfB.js} +2 -2
- package/dashboard/dist/assets/{CapabilitiesPage-CvOX6vAc.js.map → CapabilitiesPage-DKxLvOfB.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-GCJsV9Oq.js → CollapsibleSection-Cz5sRx-r.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-GCJsV9Oq.js.map → CollapsibleSection-Cz5sRx-r.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-CAgYLcef.js → ConfirmDeleteModal-Beq1vQtY.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-CAgYLcef.js.map → ConfirmDeleteModal-Beq1vQtY.js.map} +1 -1
- package/dashboard/dist/assets/{CountdownTimer-Dik2z0M_.js → CountdownTimer-BUBl_4mP.js} +2 -2
- package/dashboard/dist/assets/{CountdownTimer-Dik2z0M_.js.map → CountdownTimer-BUBl_4mP.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-twd2xCOW.js → CredentialsPage-DhiHiPsG.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-twd2xCOW.js.map → CredentialsPage-DhiHiPsG.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-DdnIuudX.js → CronLabel-C9SkawB-.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-DdnIuudX.js.map → CronLabel-C9SkawB-.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-DCctVv5R.js → ElapsedCell-BeK1SUDK.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-DCctVv5R.js.map → ElapsedCell-BeK1SUDK.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-CMnskyWv.js → EntityTimelinePanel-BThdefKj.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-CMnskyWv.js.map → EntityTimelinePanel-BThdefKj.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-VfCn6WDb.js → EscalationListSchemaPage-DlDIYb-p.js} +2 -2
- package/dashboard/dist/assets/{EscalationListSchemaPage-VfCn6WDb.js.map → EscalationListSchemaPage-DlDIYb-p.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListView-CGQZxcC-.js → EscalationListView-DTIVuym4.js} +2 -2
- package/dashboard/dist/assets/{EscalationListView-CGQZxcC-.js.map → EscalationListView-DTIVuym4.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-BX0tx-PM.js → EscalationSchemaPage-CQt-Embr.js} +2 -2
- package/dashboard/dist/assets/{EscalationSchemaPage-BX0tx-PM.js.map → EscalationSchemaPage-CQt-Embr.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DKoSM56J.js → EscalationTimeline-DNKNp6pL.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DKoSM56J.js.map → EscalationTimeline-DNKNp6pL.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-DWGLBOmS.js → EscalationTitleSelect-Dewrv8wX.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-DWGLBOmS.js.map → EscalationTitleSelect-Dewrv8wX.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-C2XoguaA.js → EscalationsOverview-BzH-Y-5x.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-C2XoguaA.js.map → EscalationsOverview-BzH-Y-5x.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-CBUWq7--.js → EventTable-C97m6IZv.js} +2 -2
- package/dashboard/dist/assets/{EventTable-CBUWq7--.js.map → EventTable-C97m6IZv.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-8IdbleZ9.js → FilterBar-D-6xVHIw.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-8IdbleZ9.js.map → FilterBar-D-6xVHIw.js.map} +1 -1
- package/dashboard/dist/assets/{GraphInvokePage-CUvoPzsW.js → GraphInvokePage-Bwi8EF9Y.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-CUvoPzsW.js.map → GraphInvokePage-Bwi8EF9Y.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-BP7v9GLJ.js → HomePage-Z_Q03C0z.js} +2 -2
- package/dashboard/dist/assets/{HomePage-BP7v9GLJ.js.map → HomePage-Z_Q03C0z.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Cnacuwoy.js → ListToolbar-_jWTw5no.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Cnacuwoy.js.map → ListToolbar-_jWTw5no.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-C2JoNoDA.js → McpOverview-CjqTuP0N.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-C2JoNoDA.js.map → McpOverview-CjqTuP0N.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-C_nih0w-.js → McpQueryDetailPage-leCsje1U.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-C_nih0w-.js.map → McpQueryDetailPage-leCsje1U.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-U_wNXow2.js → McpQueryPage-C-PyXYX4.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-U_wNXow2.js.map → McpQueryPage-C-PyXYX4.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DtKoJq6J.js → McpRunDetailPage-JDrr3uUQ.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DtKoJq6J.js.map → McpRunDetailPage-JDrr3uUQ.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-CnYtfGhf.js → McpRunsPage-DERXQLgZ.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-CnYtfGhf.js.map → McpRunsPage-DERXQLgZ.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-C7hupIer.js → OperationsPage-B2DA7n9m.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-C7hupIer.js.map → OperationsPage-B2DA7n9m.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-fVuLn2D5.js → OperatorDashboard-C8RtPv8P.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-fVuLn2D5.js.map → OperatorDashboard-C8RtPv8P.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-C-4o8lPw.js → PersonaDetailPage-ChXwJ6u5.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-C-4o8lPw.js.map → PersonaDetailPage-ChXwJ6u5.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-BL1FwLmv.js → PersonasPage-BFFxncSE.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-BL1FwLmv.js.map → PersonasPage-BFFxncSE.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-tJG5sgb1.js → PortalPage-Xk1zVneM.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-tJG5sgb1.js.map → PortalPage-Xk1zVneM.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-Dz_jY4Yt.js → ProcessDetailPage-D7EYwW-j.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-Dz_jY4Yt.js.map → ProcessDetailPage-D7EYwW-j.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-Cbn9cter.js → ProcessesListPage-CakYRtnE.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-Cbn9cter.js.map → ProcessesListPage-CakYRtnE.js.map} +1 -1
- package/dashboard/dist/assets/{ResolverForm-Bk8iXQ6-.js → ResolverForm-BwVOJUpJ.js} +6 -6
- package/dashboard/dist/assets/ResolverForm-BwVOJUpJ.js.map +1 -0
- package/dashboard/dist/assets/{RoleDetailPage-owPi6gI9.js → RoleDetailPage-CKbGwezP.js} +2 -2
- package/dashboard/dist/assets/{RoleDetailPage-owPi6gI9.js.map → RoleDetailPage-CKbGwezP.js.map} +1 -1
- package/dashboard/dist/assets/{RolesPage-NwmMvZFa.js → RolesPage-Czu7Zku4.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-NwmMvZFa.js.map → RolesPage-Czu7Zku4.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-tgEooTyU.js → RunAsSelector-6BLScYTX.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-tgEooTyU.js.map → RunAsSelector-6BLScYTX.js.map} +1 -1
- package/dashboard/dist/assets/{ScanCodesPage-CUv_8ic6.js → ScanCodesPage-Cv9q8Bvt.js} +2 -2
- package/dashboard/dist/assets/{ScanCodesPage-CUv_8ic6.js.map → ScanCodesPage-Cv9q8Bvt.js.map} +1 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-BxazXYIc.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-BxazXYIc.js.map +1 -0
- package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-Cg8LCFR7.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-CsTI_gvJ.js → StickyPagination-DsdtYoXR.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-CsTI_gvJ.js.map → StickyPagination-DsdtYoXR.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail-auRlvjTh.js → StreamMessageDetail-CT3FQoT3.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail-auRlvjTh.js.map → StreamMessageDetail-CT3FQoT3.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-BLoVHYAd.js → SwimlaneTimeline-C8TjkJ10.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-BLoVHYAd.js.map → SwimlaneTimeline-C8TjkJ10.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BPsZ1bK_.js → TaskDetailPage-DGUzdBFN.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BPsZ1bK_.js.map → TaskDetailPage-DGUzdBFN.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-BNGM74yT.js → TasksListPage-BVIP6-EZ.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-BNGM74yT.js.map → TasksListPage-BVIP6-EZ.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-BnAHXGK7.js → TimeAgo-C-rd9F9g.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-BnAHXGK7.js.map → TimeAgo-C-rd9F9g.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-J4yae6mc.js → TimestampCell-DPbchDOI.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-J4yae6mc.js.map → TimestampCell-DPbchDOI.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-BdzzgXDu.js → ToolTestPanel-DAUC8DHK.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-BdzzgXDu.js.map → ToolTestPanel-DAUC8DHK.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-DJKg8lb7.js → TopicDetailPage-70mMKBzG.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-DJKg8lb7.js.map → TopicDetailPage-70mMKBzG.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-DQV0WxG6.js → TopicsPage-CE3hBthn.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-DQV0WxG6.js.map → TopicsPage-CE3hBthn.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-Ct09nGh5.js → UserName-BDBDA-LR.js} +2 -2
- package/dashboard/dist/assets/{UserName-Ct09nGh5.js.map → UserName-BDBDA-LR.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-B5WJOsee.js → WorkflowExecutionPage-BbkLZ1co.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-B5WJOsee.js.map → WorkflowExecutionPage-BbkLZ1co.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-Hc87TRgD.js → WorkflowsDashboard-Bp1L7Ggz.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-Hc87TRgD.js.map → WorkflowsDashboard-Bp1L7Ggz.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-CJQbyOj-.js → WorkflowsOverview-IeTKHAi4.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-CJQbyOj-.js.map → WorkflowsOverview-IeTKHAi4.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BMeED677.js → YamlWorkflowDetailPage-DtKCXnKt.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-BMeED677.js.map → YamlWorkflowDetailPage-DtKCXnKt.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-BMMg0Id6.js → YamlWorkflowsPage-CEcZBV_3.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-BMMg0Id6.js.map → YamlWorkflowsPage-CEcZBV_3.js.map} +1 -1
- package/dashboard/dist/assets/{agents-CdFkgFvg.js → agents-BT-sEk81.js} +2 -2
- package/dashboard/dist/assets/{agents-CdFkgFvg.js.map → agents-BT-sEk81.js.map} +1 -1
- package/dashboard/dist/assets/{bots-Mj3LHWWg.js → bots-DRoAdLek.js} +2 -2
- package/dashboard/dist/assets/{bots-Mj3LHWWg.js.map → bots-DRoAdLek.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-Dw1ObK2-.js → capabilities-Bc-nJk6y.js} +2 -2
- package/dashboard/dist/assets/{capabilities-Dw1ObK2-.js.map → capabilities-Bc-nJk6y.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-DcNE1APv.js → controlplane-aXceSIRf.js} +2 -2
- package/dashboard/dist/assets/{controlplane-DcNE1APv.js.map → controlplane-aXceSIRf.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-D364Trpy.js → escalation-columns-Bf09Q89t.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-D364Trpy.js.map → escalation-columns-Bf09Q89t.js.map} +1 -1
- package/dashboard/dist/assets/index-BCFEQEMC.js +2 -0
- package/dashboard/dist/assets/index-BCFEQEMC.js.map +1 -0
- package/dashboard/dist/assets/{index-Bd6-KmBE.js → index-BEPKAjna.js} +2 -2
- package/dashboard/dist/assets/{index-Bd6-KmBE.js.map → index-BEPKAjna.js.map} +1 -1
- package/dashboard/dist/assets/{index-BQeHJHYN.js → index-BUYokcrl.js} +25 -25
- package/dashboard/dist/assets/index-BUYokcrl.js.map +1 -0
- package/dashboard/dist/assets/{index-MDD4JYtu.js → index-Ba-s5Yb5.js} +2 -2
- package/dashboard/dist/assets/{index-MDD4JYtu.js.map → index-Ba-s5Yb5.js.map} +1 -1
- package/dashboard/dist/assets/{index-BRGTmoYY.js → index-C3VTJcrp.js} +2 -2
- package/dashboard/dist/assets/{index-BRGTmoYY.js.map → index-C3VTJcrp.js.map} +1 -1
- package/dashboard/dist/assets/{index-Dyotfa_k.js → index-CZyO9hRb.js} +2 -2
- package/dashboard/dist/assets/{index-Dyotfa_k.js.map → index-CZyO9hRb.js.map} +1 -1
- package/dashboard/dist/assets/{index-eDm6cz0F.js → index-CcgmR-7-.js} +2 -2
- package/dashboard/dist/assets/{index-eDm6cz0F.js.map → index-CcgmR-7-.js.map} +1 -1
- package/dashboard/dist/assets/{index-DkcI4V_H.js → index-CuBGGwXf.js} +2 -2
- package/dashboard/dist/assets/{index-DkcI4V_H.js.map → index-CuBGGwXf.js.map} +1 -1
- package/dashboard/dist/assets/index-D1mKf_qz.js +3 -0
- package/dashboard/dist/assets/index-D1mKf_qz.js.map +1 -0
- package/dashboard/dist/assets/{index-Bq5XNEzD.js → index-DBxpyIw5.js} +2 -2
- package/dashboard/dist/assets/{index-Bq5XNEzD.js.map → index-DBxpyIw5.js.map} +1 -1
- package/dashboard/dist/assets/{index-B3veJ698.js → index-DH03y-UT.js} +2 -2
- package/dashboard/dist/assets/{index-B3veJ698.js.map → index-DH03y-UT.js.map} +1 -1
- package/dashboard/dist/assets/{index-BiVce3n0.js → index-Djsoi8DI.js} +2 -2
- package/dashboard/dist/assets/{index-BiVce3n0.js.map → index-Djsoi8DI.js.map} +1 -1
- package/dashboard/dist/assets/{index-DPStdq4T.js → index-h2gX31B2.js} +2 -2
- package/dashboard/dist/assets/{index-DPStdq4T.js.map → index-h2gX31B2.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-Bafewjxk.js → knowledge-BhW8V-Hq.js} +2 -2
- package/dashboard/dist/assets/{knowledge-Bafewjxk.js.map → knowledge-BhW8V-Hq.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-vLIutbnc.js → mcp-BYfSMQzh.js} +2 -2
- package/dashboard/dist/assets/{mcp-vLIutbnc.js.map → mcp-BYfSMQzh.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-BzTtIG90.js → mcp-query-DUJoOk_q.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-BzTtIG90.js.map → mcp-query-DUJoOk_q.js.map} +1 -1
- package/dashboard/dist/assets/metadata-display-B7X5hGxG.js +2 -0
- package/dashboard/dist/assets/metadata-display-B7X5hGxG.js.map +1 -0
- package/dashboard/dist/assets/{personas-WD40EDS_.js → personas-jT1O_SB4.js} +2 -2
- package/dashboard/dist/assets/{personas-WD40EDS_.js.map → personas-jT1O_SB4.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-DFwULWs3.js → pipelines-Bp-wIaz2.js} +2 -2
- package/dashboard/dist/assets/{pipelines-DFwULWs3.js.map → pipelines-Bp-wIaz2.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-La_-WAUn.js → tasks-CCrvnXbz.js} +2 -2
- package/dashboard/dist/assets/{tasks-La_-WAUn.js.map → tasks-CCrvnXbz.js.map} +1 -1
- package/dashboard/dist/assets/{topics-CzYMlvqm.js → topics-Blft0I1L.js} +2 -2
- package/dashboard/dist/assets/{topics-CzYMlvqm.js.map → topics-Blft0I1L.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-C0FQyANW.js → useDebouncedValue-BYqbcism.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-C0FQyANW.js.map → useDebouncedValue-BYqbcism.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-WW_XjAb3.js → useNamespace-BfxJAUgG.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-WW_XjAb3.js.map → useNamespace-BfxJAUgG.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-B3YxPeFt.js → useYamlActivityEvents-BukJuWpb.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-B3YxPeFt.js.map → useYamlActivityEvents-BukJuWpb.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-COHOjdhF.js → yaml-workflows-DeRWqMGk.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-COHOjdhF.js.map → yaml-workflows-DeRWqMGk.js.map} +1 -1
- package/dashboard/dist/index.html +1 -1
- package/docs/accumulator.md +1 -1
- package/docs/api/sdk/escalations.md +1 -1
- package/docs/hitl/escalation.md +12 -0
- package/docs/hitl/lookups.md +27 -18
- package/docs/hitl/resolution.md +1 -1
- package/docs/hitl/x-lt-validation.md +1 -1
- package/docs/hitl/x-lt-widget.md +1 -1
- package/docs/hitl-guide.md +1 -1
- package/docs/scan-codes.md +86 -16
- package/package.json +2 -2
- package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +0 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +0 -2
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +0 -1
- package/dashboard/dist/assets/index-BQeHJHYN.js.map +0 -1
- package/dashboard/dist/assets/index-BmNAVd4s.js +0 -2
- package/dashboard/dist/assets/index-BmNAVd4s.js.map +0 -1
- package/dashboard/dist/assets/index-WSm8bgE7.js +0 -3
- package/dashboard/dist/assets/index-WSm8bgE7.js.map +0 -1
- package/dashboard/dist/assets/metadata-display-COo3mMCr.js +0 -2
- package/dashboard/dist/assets/metadata-display-COo3mMCr.js.map +0 -1
package/docs/hitl/escalation.md
CHANGED
|
@@ -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.
|
package/docs/hitl/lookups.md
CHANGED
|
@@ -1,45 +1,52 @@
|
|
|
1
1
|
# Versioned Knowledge Lookups
|
|
2
2
|
|
|
3
|
-
An escalation can
|
|
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", "
|
|
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` |
|
|
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`
|
|
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
|
|
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',
|
|
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
|
|
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
|
|
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`
|
|
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
|
|
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. **
|
|
67
|
-
3. **
|
|
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
|
|
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":
|
|
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
|
|
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
|
|
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
|
|
package/docs/hitl/resolution.md
CHANGED
|
@@ -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
|
|
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
|
|
package/docs/hitl/x-lt-widget.md
CHANGED
|
@@ -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
|
|
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`)
|
package/docs/hitl-guide.md
CHANGED
|
@@ -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
|
|
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
|
package/docs/scan-codes.md
CHANGED
|
@@ -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" }
|
|
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.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
|
275
|
-
|
|
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).
|
|
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.
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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.
|
|
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.
|
|
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",
|