@hotmeshio/long-tail 0.22.1 → 0.22.2
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 +38 -19
- package/build/api/escalations/resolve-batch.js +18 -11
- package/build/api/roles.js +4 -0
- package/build/api/scan-codes/badge-policy.d.ts +10 -0
- package/build/api/scan-codes/badge-policy.js +72 -0
- package/build/api/scan-codes/choice.js +16 -10
- package/build/api/scan-codes/context.d.ts +45 -1
- package/build/api/scan-codes/context.js +51 -3
- package/build/api/scan-codes/execute.js +73 -35
- package/build/api/scan-codes/grant.d.ts +27 -0
- package/build/api/scan-codes/grant.js +67 -0
- package/build/api/scan-codes/hold.d.ts +10 -0
- package/build/api/scan-codes/hold.js +98 -0
- package/build/api/scan-codes/identity.d.ts +5 -2
- package/build/api/scan-codes/identity.js +26 -8
- package/build/api/scan-codes/subject.d.ts +15 -0
- package/build/api/scan-codes/subject.js +68 -0
- package/build/api/scan-codes/verb-accumulate.d.ts +24 -0
- package/build/api/scan-codes/verb-accumulate.js +147 -0
- package/build/api/scan-codes/verb-fill.d.ts +6 -0
- package/build/api/scan-codes/verb-fill.js +152 -0
- package/build/api/scan-codes/verbs-subject.d.ts +14 -0
- package/build/api/scan-codes/verbs-subject.js +270 -0
- package/build/api/scan-codes/verbs.d.ts +1 -21
- package/build/api/scan-codes/verbs.js +26 -115
- package/build/index.d.ts +1 -0
- package/build/index.js +8 -2
- package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
- package/build/routes/escalations/acting.d.ts +5 -0
- package/build/routes/escalations/acting.js +8 -1
- package/build/routes/scan-codes.js +3 -0
- package/build/services/iam/acting-identity.d.ts +29 -4
- package/build/services/iam/acting-identity.js +60 -17
- package/build/services/iam/ephemeral.d.ts +21 -0
- package/build/services/iam/ephemeral.js +32 -1
- package/build/services/iam/sql.d.ts +10 -0
- package/build/services/iam/sql.js +32 -3
- package/build/services/role/badge-grant.d.ts +5 -0
- package/build/services/role/badge-grant.js +36 -0
- package/build/services/role/seed.js +5 -0
- package/build/services/role/types.d.ts +14 -0
- package/build/services/role/types.js +5 -0
- package/build/services/scan-code/index.d.ts +3 -2
- package/build/services/scan-code/index.js +7 -1
- package/build/services/scan-code/parse.d.ts +23 -20
- package/build/services/scan-code/parse.js +45 -90
- package/build/services/scan-code/read.js +1 -0
- package/build/services/scan-code/sql.d.ts +3 -3
- package/build/services/scan-code/sql.js +11 -8
- package/build/services/scan-code/validate-subject.d.ts +7 -0
- package/build/services/scan-code/validate-subject.js +158 -0
- package/build/services/scan-code/validate.d.ts +7 -0
- package/build/services/scan-code/validate.js +94 -18
- package/build/services/scan-code/write.d.ts +1 -0
- package/build/services/scan-code/write.js +9 -3
- package/build/shared/form-validation/field-validator.js +4 -0
- package/build/shared/form-validation/index.d.ts +1 -0
- package/build/shared/form-validation/index.js +1 -0
- package/build/shared/form-validation/x-lt-scan.d.ts +52 -0
- package/build/shared/form-validation/x-lt-scan.js +166 -0
- package/build/shared/scan-code/gtin.d.ts +5 -0
- package/build/shared/scan-code/gtin.js +25 -0
- package/build/shared/scan-code/index.d.ts +2 -0
- package/build/shared/scan-code/index.js +10 -0
- package/build/shared/scan-code/parse.d.ts +46 -0
- package/build/shared/scan-code/parse.js +133 -0
- package/build/system/mcp-servers/admin/scan-codes.js +10 -4
- package/build/system/mcp-servers/admin/schemas.d.ts +754 -23
- package/build/system/mcp-servers/admin/schemas.js +57 -4
- package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
- package/build/tsconfig.tsbuildinfo +1 -1
- package/build/types/escalation.d.ts +2 -0
- package/build/types/escalation.js +3 -1
- package/build/types/index.d.ts +2 -2
- package/build/types/index.js +8 -1
- package/build/types/scan-code/constants.d.ts +182 -0
- package/build/types/{scan-code.js → scan-code/constants.js} +72 -11
- package/build/types/scan-code/index.d.ts +3 -0
- package/build/types/scan-code/index.js +17 -0
- package/build/types/scan-code/response.d.ts +140 -0
- package/build/types/scan-code/response.js +2 -0
- package/build/types/scan-code/rule.d.ts +199 -0
- package/build/types/scan-code/rule.js +2 -0
- package/build/types/startup.d.ts +3 -1
- package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js → AdminDashboard-DBW12qQt.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js.map → AdminDashboard-DBW12qQt.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js → AgentConfigPage-CmHv8U9M.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js.map → AgentConfigPage-CmHv8U9M.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js → AgentDetailPage-D1scIbz-.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js.map → AgentDetailPage-D1scIbz-.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js → AgentsPage-BA_ai9HJ.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js.map → AgentsPage-BA_ai9HJ.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js → AvailableEscalationsPage-C2_5aEFW.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js.map → AvailableEscalationsPage-C2_5aEFW.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js → BotPicker-BZo4Kp4a.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js.map → BotPicker-BZo4Kp4a.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js → BulkAssignModal-BFhyxY2T.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js.map → BulkAssignModal-BFhyxY2T.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-CvOX6vAc.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-BxadotXn.js.map → CapabilitiesPage-CvOX6vAc.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js → CollapsibleSection-GCJsV9Oq.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js.map → CollapsibleSection-GCJsV9Oq.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js → ConfirmDeleteModal-CAgYLcef.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js.map → ConfirmDeleteModal-CAgYLcef.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-Dik2z0M_.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-CI_JOAvk.js.map → CountdownTimer-Dik2z0M_.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js → CredentialsPage-twd2xCOW.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js.map → CredentialsPage-twd2xCOW.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js → CronLabel-DdnIuudX.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js.map → CronLabel-DdnIuudX.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js → ElapsedCell-DCctVv5R.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js.map → ElapsedCell-DCctVv5R.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js → EntityTimelinePanel-CMnskyWv.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js.map → EntityTimelinePanel-CMnskyWv.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js → EscalationListSchemaPage-VfCn6WDb.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js.map → EscalationListSchemaPage-VfCn6WDb.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js → EscalationListView-CGQZxcC-.js} +2 -2
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js.map → EscalationListView-CGQZxcC-.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js → EscalationSchemaPage-BX0tx-PM.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js.map → EscalationSchemaPage-BX0tx-PM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js → EscalationTimeline-DKoSM56J.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js.map → EscalationTimeline-DKoSM56J.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js → EscalationTitleSelect-DWGLBOmS.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js.map → EscalationTitleSelect-DWGLBOmS.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js → EscalationsOverview-C2XoguaA.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js.map → EscalationsOverview-C2XoguaA.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js → EventTable-CBUWq7--.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js.map → EventTable-CBUWq7--.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js → FilterBar-8IdbleZ9.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js.map → FilterBar-8IdbleZ9.js.map} +1 -1
- package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +2 -0
- package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +1 -0
- package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js → GraphInvokePage-CUvoPzsW.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js.map → GraphInvokePage-CUvoPzsW.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js → HomePage-BP7v9GLJ.js} +2 -2
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js.map → HomePage-BP7v9GLJ.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js → ListToolbar-Cnacuwoy.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js.map → ListToolbar-Cnacuwoy.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js → McpOverview-C2JoNoDA.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js.map → McpOverview-C2JoNoDA.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js → McpQueryDetailPage-C_nih0w-.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js.map → McpQueryDetailPage-C_nih0w-.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js → McpQueryPage-U_wNXow2.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js.map → McpQueryPage-U_wNXow2.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js → McpRunDetailPage-DtKoJq6J.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js.map → McpRunDetailPage-DtKoJq6J.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js → McpRunsPage-CnYtfGhf.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js.map → McpRunsPage-CnYtfGhf.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js → OperationsPage-C7hupIer.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js.map → OperationsPage-C7hupIer.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js → OperatorDashboard-fVuLn2D5.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js.map → OperatorDashboard-fVuLn2D5.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js → PersonaDetailPage-C-4o8lPw.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js.map → PersonaDetailPage-C-4o8lPw.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js → PersonasPage-BL1FwLmv.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js.map → PersonasPage-BL1FwLmv.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js → PortalPage-tJG5sgb1.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js.map → PortalPage-tJG5sgb1.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js → ProcessDetailPage-Dz_jY4Yt.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js.map → ProcessDetailPage-Dz_jY4Yt.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js → ProcessesListPage-Cbn9cter.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js.map → ProcessesListPage-Cbn9cter.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js +8 -0
- package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +1 -0
- package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js.map +1 -0
- package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js → RolesPage-NwmMvZFa.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js.map → RolesPage-NwmMvZFa.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js → RunAsSelector-tgEooTyU.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js.map → RunAsSelector-tgEooTyU.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js +2 -0
- package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js.map +1 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +1 -0
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js → StickyPagination-CsTI_gvJ.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js.map → StickyPagination-CsTI_gvJ.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js → StreamMessageDetail-auRlvjTh.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js.map → StreamMessageDetail-auRlvjTh.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js → SwimlaneTimeline-BLoVHYAd.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js.map → SwimlaneTimeline-BLoVHYAd.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js → TaskDetailPage-BPsZ1bK_.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js.map → TaskDetailPage-BPsZ1bK_.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js → TasksListPage-BNGM74yT.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js.map → TasksListPage-BNGM74yT.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js → TimeAgo-BnAHXGK7.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js.map → TimeAgo-BnAHXGK7.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js → TimestampCell-J4yae6mc.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js.map → TimestampCell-J4yae6mc.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js → ToolTestPanel-BdzzgXDu.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js.map → ToolTestPanel-BdzzgXDu.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js → TopicDetailPage-DJKg8lb7.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js.map → TopicDetailPage-DJKg8lb7.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js → TopicsPage-DQV0WxG6.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js.map → TopicsPage-DQV0WxG6.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js → UserName-Ct09nGh5.js} +2 -2
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js.map → UserName-Ct09nGh5.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js → WorkflowExecutionPage-B5WJOsee.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js.map → WorkflowExecutionPage-B5WJOsee.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js → WorkflowsDashboard-Hc87TRgD.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js.map → WorkflowsDashboard-Hc87TRgD.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js → WorkflowsOverview-CJQbyOj-.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js.map → WorkflowsOverview-CJQbyOj-.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js → YamlWorkflowDetailPage-BMeED677.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js.map → YamlWorkflowDetailPage-BMeED677.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js → YamlWorkflowsPage-BMMg0Id6.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js.map → YamlWorkflowsPage-BMMg0Id6.js.map} +1 -1
- package/dashboard/dist/assets/{agents-v_HH3Rji.js → agents-CdFkgFvg.js} +2 -2
- package/dashboard/dist/assets/{agents-v_HH3Rji.js.map → agents-CdFkgFvg.js.map} +1 -1
- package/dashboard/dist/assets/{bots-bwvWYrXz.js → bots-Mj3LHWWg.js} +2 -2
- package/dashboard/dist/assets/{bots-bwvWYrXz.js.map → bots-Mj3LHWWg.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js → capabilities-Dw1ObK2-.js} +2 -2
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js.map → capabilities-Dw1ObK2-.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js → controlplane-DcNE1APv.js} +2 -2
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js.map → controlplane-DcNE1APv.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js → escalation-columns-D364Trpy.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js.map → escalation-columns-D364Trpy.js.map} +1 -1
- package/dashboard/dist/assets/{index-IJmtbuLh.js → index-B3veJ698.js} +2 -2
- package/dashboard/dist/assets/{index-IJmtbuLh.js.map → index-B3veJ698.js.map} +1 -1
- package/dashboard/dist/assets/index-BQeHJHYN.js +67 -0
- package/dashboard/dist/assets/index-BQeHJHYN.js.map +1 -0
- package/dashboard/dist/assets/{index-D2VKBMng.js → index-BRGTmoYY.js} +2 -2
- package/dashboard/dist/assets/{index-D2VKBMng.js.map → index-BRGTmoYY.js.map} +1 -1
- package/dashboard/dist/assets/{index-C4Lce2ET.js → index-Bd6-KmBE.js} +3 -3
- package/dashboard/dist/assets/{index-C4Lce2ET.js.map → index-Bd6-KmBE.js.map} +1 -1
- package/dashboard/dist/assets/{index-CcuvGdvf.js → index-BiVce3n0.js} +2 -2
- package/dashboard/dist/assets/{index-CcuvGdvf.js.map → index-BiVce3n0.js.map} +1 -1
- package/dashboard/dist/assets/{index-D6pBLZFu.js → index-BmNAVd4s.js} +2 -2
- package/dashboard/dist/assets/{index-D6pBLZFu.js.map → index-BmNAVd4s.js.map} +1 -1
- package/dashboard/dist/assets/{index-CjenRVX_.js → index-Bq5XNEzD.js} +2 -2
- package/dashboard/dist/assets/{index-CjenRVX_.js.map → index-Bq5XNEzD.js.map} +1 -1
- package/dashboard/dist/assets/{index-CzjUgFt_.js → index-DPStdq4T.js} +2 -2
- package/dashboard/dist/assets/{index-CzjUgFt_.js.map → index-DPStdq4T.js.map} +1 -1
- package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
- package/dashboard/dist/assets/{index-C3WutFpT.js → index-DkcI4V_H.js} +2 -2
- package/dashboard/dist/assets/{index-C3WutFpT.js.map → index-DkcI4V_H.js.map} +1 -1
- package/dashboard/dist/assets/{index-2tzsxFat.js → index-Dyotfa_k.js} +2 -2
- package/dashboard/dist/assets/{index-2tzsxFat.js.map → index-Dyotfa_k.js.map} +1 -1
- package/dashboard/dist/assets/{index-C_ISDOWJ.js → index-MDD4JYtu.js} +2 -2
- package/dashboard/dist/assets/{index-C_ISDOWJ.js.map → index-MDD4JYtu.js.map} +1 -1
- package/dashboard/dist/assets/index-WSm8bgE7.js +3 -0
- package/dashboard/dist/assets/index-WSm8bgE7.js.map +1 -0
- package/dashboard/dist/assets/{index-BLB77tc8.js → index-eDm6cz0F.js} +2 -2
- package/dashboard/dist/assets/{index-BLB77tc8.js.map → index-eDm6cz0F.js.map} +1 -1
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js → knowledge-Bafewjxk.js} +2 -2
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js.map → knowledge-Bafewjxk.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js → mcp-query-BzTtIG90.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js.map → mcp-query-BzTtIG90.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-Bb5psC61.js → mcp-vLIutbnc.js} +2 -2
- package/dashboard/dist/assets/{mcp-Bb5psC61.js.map → mcp-vLIutbnc.js.map} +1 -1
- package/dashboard/dist/assets/{personas-CDndbkp4.js → personas-WD40EDS_.js} +2 -2
- package/dashboard/dist/assets/{personas-CDndbkp4.js.map → personas-WD40EDS_.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js → pipelines-DFwULWs3.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js.map → pipelines-DFwULWs3.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js → tasks-La_-WAUn.js} +2 -2
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js.map → tasks-La_-WAUn.js.map} +1 -1
- package/dashboard/dist/assets/{topics-C0YaR9fu.js → topics-CzYMlvqm.js} +2 -2
- package/dashboard/dist/assets/{topics-C0YaR9fu.js.map → topics-CzYMlvqm.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js → useDebouncedValue-C0FQyANW.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js.map → useDebouncedValue-C0FQyANW.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js → useNamespace-WW_XjAb3.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js.map → useNamespace-WW_XjAb3.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js → useYamlActivityEvents-B3YxPeFt.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js.map → useYamlActivityEvents-B3YxPeFt.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js → yaml-workflows-COHOjdhF.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js.map → yaml-workflows-COHOjdhF.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/dashboard.md +1 -1
- package/docs/hitl/x-lt-scan.md +51 -0
- package/docs/hitl-guide.md +2 -0
- package/docs/scan-codes.md +221 -21
- package/package.json +1 -1
- package/build/types/scan-code.d.ts +0 -317
- package/dashboard/dist/assets/CapabilitiesPage-BxadotXn.js +0 -2
- package/dashboard/dist/assets/CountdownTimer-CI_JOAvk.js +0 -2
- package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js +0 -8
- package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js.map +0 -1
- package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js +0 -8
- package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js.map +0 -1
- package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js +0 -2
- package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js.map +0 -1
- package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js +0 -2
- package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js.map +0 -1
- package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js +0 -2
- package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js.map +0 -1
- package/dashboard/dist/assets/index-CT-FN6CW.js +0 -3
- package/dashboard/dist/assets/index-CT-FN6CW.js.map +0 -1
- package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
- package/dashboard/dist/assets/index-N71QQ3J5.js +0 -67
- package/dashboard/dist/assets/index-N71QQ3J5.js.map +0 -1
package/docs/scan-codes.md
CHANGED
|
@@ -23,6 +23,7 @@ canonical action surface. A scan is an **ECA rule** over that surface:
|
|
|
23
23
|
- [Rules and steps](#rules-and-steps)
|
|
24
24
|
- [Confirmation](#confirmation)
|
|
25
25
|
- [Info-choice screens](#info-choice-screens)
|
|
26
|
+
- [Holding an item: the bench motion](#holding-an-item-the-bench-motion)
|
|
26
27
|
- [Identity schemes and acting identity](#identity-schemes-and-acting-identity)
|
|
27
28
|
- [Station deployments](#station-deployments)
|
|
28
29
|
- [The fallback screen](#the-fallback-screen)
|
|
@@ -31,6 +32,7 @@ canonical action surface. A scan is an **ECA rule** over that surface:
|
|
|
31
32
|
- [Scanner setup](#scanner-setup)
|
|
32
33
|
- [Admin configuration](#admin-configuration)
|
|
33
34
|
- [The printer demo](#the-printer-demo)
|
|
35
|
+
- [The bag and bin demo](#the-bag-and-bin-demo)
|
|
34
36
|
|
|
35
37
|
## The code
|
|
36
38
|
|
|
@@ -62,6 +64,14 @@ A scheme (`lt_config_scan_schemes`, indexed 10–99) declares:
|
|
|
62
64
|
`1015949975930`. Fits UPC-A/EAN/ITF labels; a trailing check digit is
|
|
63
65
|
accepted. Two digits of version + one of category + `target_length`
|
|
64
66
|
digits of target.
|
|
67
|
+
- `gtin` — manufacturer barcodes: UPC-A, EAN-13, EAN-8 and GTIN-14, as
|
|
68
|
+
printed on products. The code carries no version or category; a valid
|
|
69
|
+
check digit identifies it. The target is the 14-digit GTIN (a UPC-A
|
|
70
|
+
`036000291452` targets `00036000291452`), `{scan.code}` keeps the code as
|
|
71
|
+
scanned, and the scheme's one rule is category `0`. A deployment has at
|
|
72
|
+
most one gtin scheme, and while it is enabled no enabled fixed scheme may
|
|
73
|
+
accept an 8, 12, 13 or 14 digit code: the scheme write is refused, naming
|
|
74
|
+
both schemes, so a digits-only code always has exactly one reading.
|
|
65
75
|
|
|
66
76
|
## Rules and steps
|
|
67
77
|
|
|
@@ -111,8 +121,8 @@ Verbs are the canonical escalation actions:
|
|
|
111
121
|
|
|
112
122
|
A `resolve` step applies it inside the atomic resolve: `mine` resolves the
|
|
113
123
|
actor's own claim, the most recently claimed first when there are several,
|
|
114
|
-
so a
|
|
115
|
-
for the same
|
|
124
|
+
so a container scan places the item in the associate's hand even when
|
|
125
|
+
another item for the same container is waiting. With no matching row the step falls through.
|
|
116
126
|
|
|
117
127
|
String values inside `itemKey`, `resolverPayload`, and `metadata` interpolate
|
|
118
128
|
`{scan.target}`, `{scan.category}`, and `{scan.scannedAt}`. Two facet bags
|
|
@@ -121,15 +131,15 @@ extend them: `{claim.<facet>}` reads the acting user's single live claim
|
|
|
121
131
|
make the step fall through), and `{item.<facet>}` reads the row an item-mode
|
|
122
132
|
`accumulate` step located. A token that cannot resolve falls through instead
|
|
123
133
|
of writing the literal, and the rule editor rejects `{item.…}` on any other
|
|
124
|
-
step.
|
|
125
|
-
`"itemKey": "{claim.
|
|
134
|
+
step. An item-first ladder therefore names the item from the claim:
|
|
135
|
+
`"itemKey": "{claim.itemId}"` on the container scan. Every mutating verb stamps
|
|
126
136
|
provenance facets onto the row it touches — `scanScheme`, `scanCategory`,
|
|
127
137
|
`scanActionName`, `scannedAt` — so scan-driven transitions stay queryable.
|
|
128
138
|
|
|
129
139
|
`accumulate` has two modes. With `params.accumulate.containerFacet` the
|
|
130
140
|
scanned target is the ITEM: the step locates the item's own pending row
|
|
131
|
-
through the scheme facet, reads that facet from the row (
|
|
132
|
-
`
|
|
141
|
+
through the scheme facet, reads that facet from the row (an item row carrying
|
|
142
|
+
`containerKey: "C-7"`), and adds the target to the pending accumulator whose
|
|
133
143
|
metadata carries the same value, writing the item's row as the reciprocal in
|
|
134
144
|
the same statement (`reciprocal: false` skips it). The container pick
|
|
135
145
|
considers only pending rows that carry the accumulator declaration, so a
|
|
@@ -138,27 +148,27 @@ release row sharing the facet during a pack-out is never the target.
|
|
|
138
148
|
|
|
139
149
|
```jsonc
|
|
140
150
|
"accumulate": {
|
|
141
|
-
"containerFacet": "
|
|
151
|
+
"containerFacet": "containerKey",
|
|
142
152
|
"container": {
|
|
143
|
-
"roles": ["
|
|
144
|
-
"types": ["
|
|
145
|
-
"subtypes": ["
|
|
153
|
+
"roles": ["packing"], // container queues (containerRoles is an alias)
|
|
154
|
+
"types": ["container"], // escalation type
|
|
155
|
+
"subtypes": ["open"], // escalation subtype
|
|
146
156
|
"facets": { "open": true } // extra metadata guards
|
|
147
157
|
}
|
|
148
158
|
}
|
|
149
159
|
```
|
|
150
160
|
|
|
151
161
|
A design that parks each item as its own accumulator in the same queue as
|
|
152
|
-
its container (
|
|
153
|
-
the container's type or subtype, so the add lands in
|
|
154
|
-
sibling's slot. The item's own row is never its container. Without it the scanned target is the CONTAINER and the step
|
|
162
|
+
its container (an item's slot beside its container, both carrying
|
|
163
|
+
`containerKey`) declares the container's type or subtype, so the add lands in
|
|
164
|
+
the container and never in a sibling's slot. The item's own row is never its container. Without it the scanned target is the CONTAINER and the step
|
|
155
165
|
adds `params.itemKey` (a template) to it. An item with no row or no container
|
|
156
166
|
facet falls through to the next step; a container already holding the item
|
|
157
167
|
reports a conflict. When the item's row exists but no pending container
|
|
158
168
|
carries its facet (the previous container closed and its successor has not
|
|
159
169
|
parked yet), the step answers `no_open_container` with the item row, the
|
|
160
170
|
facet, and the rule's fallback markdown, so the station reads "Container
|
|
161
|
-
closing, scan again" instead of the
|
|
171
|
+
closing, scan again" instead of the item with no hint.
|
|
162
172
|
|
|
163
173
|
Ordering is the power move: put the expected state first and a broad
|
|
164
174
|
`show-detail` last. A machine whose twin is in the wrong queue still answers
|
|
@@ -182,7 +192,7 @@ guarded call every other surface uses.
|
|
|
182
192
|
|
|
183
193
|
## Info-choice screens
|
|
184
194
|
|
|
185
|
-
Some objects carry one code for their whole life — an item tag,
|
|
195
|
+
Some objects carry one code for their whole life — an item tag, a record
|
|
186
196
|
label. One code, many possible intents, and the right one depends on where
|
|
187
197
|
the object is in its journey. The `present` verb closes that gap: the step
|
|
188
198
|
locates the row, states its reality, and returns a configured, labeled
|
|
@@ -231,6 +241,121 @@ duration, form on screen. An unsatisfied identity requirement never
|
|
|
231
241
|
auto-fires as the wrong actor — the scan stops over at the badge screen and
|
|
232
242
|
completes on its own once a badge primes.
|
|
233
243
|
|
|
244
|
+
## Holding an item: the bench motion
|
|
245
|
+
|
|
246
|
+
At a bench where items go into containers, every act is one item going into
|
|
247
|
+
one container, or one expected item checked off a record. The motion is three scans with nothing in between: **the item, your badge, the
|
|
248
|
+
container**. The container scan is the act. The item scan only says which
|
|
249
|
+
item; the badge says who.
|
|
250
|
+
|
|
251
|
+
**`hold`** is the item scan. The step locates the row and answers `held`
|
|
252
|
+
with a **subject**: the code that held it, the row id, a label, an expiry,
|
|
253
|
+
and what to scan next. It writes nothing and spends no badge use. The
|
|
254
|
+
station keeps the subject (device-local, in memory) and sends it back with
|
|
255
|
+
the next scans as `subject: { code, escalationId }`. Scanning another item
|
|
256
|
+
replaces it; it lapses on its own after `ttlSeconds` (default 45).
|
|
257
|
+
|
|
258
|
+
```jsonc
|
|
259
|
+
{ "query": { "roles": ["packing"] }, "verb": "hold",
|
|
260
|
+
"params": { "hold": { "ttlSeconds": 300, "label": "{scan.target}",
|
|
261
|
+
"headline": "{item.containerCode}", "subline": "{item.locationName}",
|
|
262
|
+
"expect": { "schemes": [14], "prompt": "Walk to this container and scan it.\n\n{item.labelNote}" } } } }
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**What the station shows.** With `hold.headline` the destination leads the
|
|
266
|
+
screen: the headline (e.g. `{item.containerCode}`) in very large type, `hold.subline`
|
|
267
|
+
under it (e.g. `{item.locationName}`), the held item itself as a quieter line
|
|
268
|
+
above, then the `expect.prompt`. A template that renders empty drops its line,
|
|
269
|
+
so a row-level note such as `{item.labelNote}` appears only when the workflow
|
|
270
|
+
set one ("Take the new label from the printer and stick it on C-12").
|
|
271
|
+
Any step that writes may carry `done: { markdown }`: the copy the station shows,
|
|
272
|
+
large, once the write lands and until the next scan ("Place it in
|
|
273
|
+
**{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.
|
|
276
|
+
|
|
277
|
+
The server trusts nothing about the subject. Each request re-parses its
|
|
278
|
+
code, re-reads the row under the station's read scope, requires the row to
|
|
279
|
+
still carry the code's target and to be pending. A subject that fails is
|
|
280
|
+
stale: steps that need one are skipped, and when nothing else matches the
|
|
281
|
+
answer is `subject_stale` with `clearSubject: true`.
|
|
282
|
+
|
|
283
|
+
**Subject steps** run only while a subject from one of `subject.schemes` is
|
|
284
|
+
held, and act on it. The `{subject.<facet>}` template bag reads the held
|
|
285
|
+
row.
|
|
286
|
+
|
|
287
|
+
| Step | What the container scan does |
|
|
288
|
+
|---|---|
|
|
289
|
+
| `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. |
|
|
292
|
+
|
|
293
|
+
**`match` and `refuse`** check the pairing before anything is written.
|
|
294
|
+
`match.target` lists templates the scanned target must equal (e.g.
|
|
295
|
+
`["{subject.containerCode}"]`); `match.facets` lists facets the located container
|
|
296
|
+
must share with the held row (e.g. `["containerKey"]`). A miss answers `refused`
|
|
297
|
+
with `refuse.markdown` rendered, and nothing is written. The copy may read
|
|
298
|
+
`{container.<facet>}` (the container the scan named) and `{fill.pending}`
|
|
299
|
+
(what a fill still expects), so the station says what is wrong and where the
|
|
300
|
+
item goes: "That's Acme West's container. This one goes in **C-12**." When the
|
|
301
|
+
write itself loses a race (the container closed, another bench took the free
|
|
302
|
+
container), the answer is `refused` with `refuse.conflict`, and a step that
|
|
303
|
+
declares `refuse.conflict` also clears the subject so the next item scan
|
|
304
|
+
reads fresh state. Exactly one of two racing acts wins whenever both name
|
|
305
|
+
the same row: the reciprocal statement writes both rows or neither.
|
|
306
|
+
|
|
307
|
+
**One rule, several kinds of held item.** `subject.facets` makes a step
|
|
308
|
+
apply only while the held row carries those facet values; otherwise the step
|
|
309
|
+
is skipped and the next one runs. A placing bench uses it to tell an item
|
|
310
|
+
whose destination already has a container from one that needs a free
|
|
311
|
+
container: the item row carries `placement: 'assigned'` or `'unassigned'`, and
|
|
312
|
+
the container label's rule has one step for each.
|
|
313
|
+
|
|
314
|
+
```jsonc
|
|
315
|
+
// 14:0, container label
|
|
316
|
+
[
|
|
317
|
+
{ "verb": "accumulate", "requireActingIdentity": true,
|
|
318
|
+
"subject": { "schemes": [11], "facets": { "placement": "assigned" } },
|
|
319
|
+
"match": { "target": ["{subject.containerCode}"] },
|
|
320
|
+
"refuse": { "markdown": "That's {container.locationName}'s container. This one goes in **{subject.containerCode}**." },
|
|
321
|
+
"params": { "itemKey": "{subject.itemId}",
|
|
322
|
+
"accumulate": { "from": "subject", "container": { "types": ["container"], "subtypes": ["open"] } } } },
|
|
323
|
+
{ "verb": "accumulate", "requireActingIdentity": true,
|
|
324
|
+
"subject": { "schemes": [11], "facets": { "placement": "unassigned" } },
|
|
325
|
+
"match": { "target": ["{subject.offeredContainers}"] },
|
|
326
|
+
"refuse": { "markdown": "Choose a free container: {subject.offeredContainers}.",
|
|
327
|
+
"conflict": "That container was just taken. Scan the item again.",
|
|
328
|
+
"missing": "That container was just taken. Scan the item again." },
|
|
329
|
+
"params": { "itemKey": "{subject.itemId}",
|
|
330
|
+
"accumulate": { "from": "subject", "container": { "types": ["container"], "subtypes": ["free"] } } } },
|
|
331
|
+
{ "query": { "roles": ["packing"] }, "verb": "present", "choices": [ /* Close this container, View container */ ] }
|
|
332
|
+
]
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
The workflow stamps the containers it offers on the item row (`offeredContainers`). A
|
|
336
|
+
`match.target` entry that is a lone token naming a list facet allows every
|
|
337
|
+
entry, so any offered container takes the item and any other is refused with
|
|
338
|
+
the offer listed. A free container is a `max: 1` accumulator row, so of two
|
|
339
|
+
items racing for one free container exactly one lands; the other is refused with the
|
|
340
|
+
conflict copy. `refuse.missing` covers an offered container with no open row (taken
|
|
341
|
+
a moment ago): the scan is refused instead of falling through to the next
|
|
342
|
+
step. The third step has no subject gate: scanning a container with no item
|
|
343
|
+
held offers to close it.
|
|
344
|
+
|
|
345
|
+
Someone else's live claim on the held row refuses the act with their name
|
|
346
|
+
(`subject.claimedByOther: "allow"` lifts this). An item already in the
|
|
347
|
+
scanned container answers `executed` with `already: true`, and nothing is
|
|
348
|
+
written twice.
|
|
349
|
+
|
|
350
|
+
The badge can come before the item or between the item and the container. A
|
|
351
|
+
container scan that needs a badge answers `not_primed` with
|
|
352
|
+
`replayable: true`; the station keeps the subject, asks for the badge, and
|
|
353
|
+
replays the container scan once the badge primes.
|
|
354
|
+
|
|
355
|
+
Subject steps sit beside the steps a rule already has: with no subject held
|
|
356
|
+
they are skipped, so the same rule keeps working for scans made without the
|
|
357
|
+
item scan first.
|
|
358
|
+
|
|
234
359
|
## Identity schemes and acting identity
|
|
235
360
|
|
|
236
361
|
A scheme with `kind: "identity"` is the badge layer. Its `target_facet`
|
|
@@ -247,7 +372,39 @@ scheme's policy:
|
|
|
247
372
|
| Scheme field | Meaning |
|
|
248
373
|
|---|---|
|
|
249
374
|
| `grant_ttl_seconds` | How long the grant lives (1–86400). |
|
|
250
|
-
| `grant_max_uses` | `0` = TTL-bound; `n` = the grant covers n
|
|
375
|
+
| `grant_max_uses` | `0` = TTL-bound; `n` = the grant covers n acts (a strict one-act policy is `1`). |
|
|
376
|
+
| `grant_scope` | `action` (default): each act spends one use. `subject`: the first act binds the grant to the held subject; further acts on that subject spend nothing, and the grant acts on no other subject. One badge then covers one item's whole motion (every part checked off one record) and never carries to the next item. |
|
|
377
|
+
|
|
378
|
+
**The station decides the policy.** One printed badge works at every bench,
|
|
379
|
+
but benches want different policies: a workstation grants one act per badge
|
|
380
|
+
scan (claim, then submit, takes two scans), a high-volume placing bench grants
|
|
381
|
+
ten minutes of acts. A role may declare its stations' policy in `properties.badge_grant`:
|
|
382
|
+
|
|
383
|
+
```jsonc
|
|
384
|
+
"properties": { "kiosk": true, "badge_grant": { "ttl_seconds": 600, "max_uses": 0 } }
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
A badge scanned on a device signed in as a member of that role mints under
|
|
388
|
+
it; fields left out keep the badge scheme's values (`scope` is the role's
|
|
389
|
+
`grant_scope`). A device that belongs to several roles with different
|
|
390
|
+
policies uses the role it is locked to (the dashboard sends its kiosk role as
|
|
391
|
+
`stationRole` with every scan); with no role policy, or no way to choose
|
|
392
|
+
between several, the badge scheme's own policy applies. The policy is
|
|
393
|
+
validated where the role is written: an unusable `badge_grant` is a 400 from
|
|
394
|
+
the role API and fails a code-owned role's startup apply. The role page edits
|
|
395
|
+
it under **Members → Badge at this station**.
|
|
396
|
+
|
|
397
|
+
A grant is spent by **acts**, not by looking. A scan that shows, presents,
|
|
398
|
+
holds, or refuses reads the grant without spending it; a mutating verb spends
|
|
399
|
+
one use just before it writes, and a write that does not land (the step
|
|
400
|
+
falls through, the scan is refused) gives the use back. Every scan response
|
|
401
|
+
that carried a grant reports `acting: { consumed, remaining, bound }`, and
|
|
402
|
+
the escalation work routes report the uses left in the
|
|
403
|
+
`X-LT-Acting-Remaining` header. The device retires its copy of the grant when
|
|
404
|
+
the server reports none left, or when a subject-bound grant's subject is
|
|
405
|
+
done; reads never carry the grant at all. A scan that comes back
|
|
406
|
+
`not_primed` while a grant is held drops that grant, so the next scan runs
|
|
407
|
+
unprimed instead of repeating the badge screen.
|
|
251
408
|
|
|
252
409
|
The grant rides subsequent scans as `actingToken`. Verbs then run **as the
|
|
253
410
|
badged person under their own live RBAC** — the grant confers attribution,
|
|
@@ -333,6 +490,12 @@ to continue. The badge scan primes the session and the pending action
|
|
|
333
490
|
completes on its own. With a live grant the stop-over never appears — the
|
|
334
491
|
identity layer is invisible when all is well.
|
|
335
492
|
|
|
493
|
+
A field can take a scan while the form is open: with
|
|
494
|
+
[`x-lt-scan`](hitl/x-lt-scan.md), scanning a container into a claimed form
|
|
495
|
+
fills its container field (checked against what the record expects), and
|
|
496
|
+
`x-lt-scan-submit` submits once the scan fields are filled, which raises the
|
|
497
|
+
badge prompt. A scan no field accepts runs globally as usual.
|
|
498
|
+
|
|
336
499
|
Badge tokens are printed credentials: seed them as long random strings,
|
|
337
500
|
bind them server-side (`lt_users.metadata`), and treat badge possession
|
|
338
501
|
with the same physical policy as any badge system. Unknown badges answer
|
|
@@ -347,9 +510,10 @@ renders the markdown; a configured route navigates.
|
|
|
347
510
|
|
|
348
511
|
## Executing a scan
|
|
349
512
|
|
|
350
|
-
`POST /api/scan-codes/execute` takes `{ "code": "10:1:SN-123" }`
|
|
351
|
-
|
|
352
|
-
200
|
|
513
|
+
`POST /api/scan-codes/execute` takes `{ "code": "10:1:SN-123" }` (plus
|
|
514
|
+
`actingToken` and `subject` when the station holds them) and runs as the
|
|
515
|
+
calling user under normal RBAC. Every terminal state is a structured 200
|
|
516
|
+
outcome:
|
|
353
517
|
|
|
354
518
|
| Outcome | Meaning |
|
|
355
519
|
|---------|---------|
|
|
@@ -362,6 +526,15 @@ as the calling user under normal RBAC. Every terminal state is a structured
|
|
|
362
526
|
| `invalid_code` | The string parses under no enabled scheme |
|
|
363
527
|
| `forbidden` | The caller's roles bar the matched action |
|
|
364
528
|
| `conflict` | A concurrent actor won the row |
|
|
529
|
+
| `choices` | A `present` step located its row; `escalation` + `choices` included |
|
|
530
|
+
| `held` | A `hold` step located its row; `subject` included |
|
|
531
|
+
| `refused` | The scan was understood and not acted on; nothing written; `refusal.markdown` (and `refusal.expected`) included |
|
|
532
|
+
| `subject_stale` | The held subject moved on; `clearSubject: true` |
|
|
533
|
+
| `not_primed` | The act needs a badge; `notPrimed` included, `replayable: true` when the scan may run again once one primes |
|
|
534
|
+
| `identity_primed` / `identity_unknown` | A badge scan matched a person, or did not |
|
|
535
|
+
|
|
536
|
+
A step's payload rejected by the role's form schema answers `refused` with
|
|
537
|
+
the reason, never a raw 422.
|
|
365
538
|
|
|
366
539
|
The endpoint is source-agnostic — anything that produces a string can drive
|
|
367
540
|
it: a barcode scanner, an RFID reader, a camera decode, an MCP tool
|
|
@@ -381,8 +554,18 @@ When enabled, the dashboard listens for scans globally — any page, any focus
|
|
|
381
554
|
state. A scanner paired as an HID keyboard "types" its decode and finishes
|
|
382
555
|
with Enter; capture is **pattern-anchored**: a capture-phase window listener
|
|
383
556
|
accumulates keystrokes freely, and when the terminator arrives it checks
|
|
384
|
-
whether the recent keys end with a scan-code shape
|
|
385
|
-
|
|
557
|
+
whether the recent keys end with a scan-code shape. The shapes come from the
|
|
558
|
+
configured schemes: each delimited version's `VV:C:target`, each fixed
|
|
559
|
+
scheme's exact digit lengths, and for a gtin scheme a whole 8, 12, 13 or 14
|
|
560
|
+
digit run whose check digit holds (a leading zero is part of the code). A
|
|
561
|
+
code never starts inside a longer run of digits.
|
|
562
|
+
|
|
563
|
+
- **Digits-only codes fire only at scanner speed** (avg ≤ 50 ms/key). A
|
|
564
|
+
typed PO number or count followed by Enter stays in its field, even when
|
|
565
|
+
its digits happen to form a valid barcode.
|
|
566
|
+
- **An open form can take the scan first.** A field with
|
|
567
|
+
[`x-lt-scan`](hitl/x-lt-scan.md) that accepts the scan's scheme is filled
|
|
568
|
+
instead; every other scan, and every badge, runs globally.
|
|
386
569
|
|
|
387
570
|
- On a match, the terminator is swallowed, the code's characters are
|
|
388
571
|
stripped back out of whatever editable held focus (byte-exact, at the
|
|
@@ -487,3 +670,20 @@ of each machine:
|
|
|
487
670
|
Each rule ends on a broad `show-detail` and the "no twin found" fallback.
|
|
488
671
|
Walk it hardware-free: run the twin farm, open the scan panel, and paste
|
|
489
672
|
`10:1:<a-printing-serial>`.
|
|
673
|
+
|
|
674
|
+
## The bag and bin demo
|
|
675
|
+
|
|
676
|
+
`examples/seed-scan-bins.ts` puts the bench motion on the
|
|
677
|
+
[rollup-bin](../examples/workflows/rollup-bin/) example. Start a `rollupBin`
|
|
678
|
+
with a `binKey` and a few `rollupMember` bags carrying the same `binKey`,
|
|
679
|
+
then at the scan station:
|
|
680
|
+
|
|
681
|
+
| Scan | Code | What happens |
|
|
682
|
+
|---|---|---|
|
|
683
|
+
| Bag | `12:0:<orderId>` | The station holds the bag and shows its bin, large |
|
|
684
|
+
| Badge | `11:0:<badge>` | Primes the person (before the bag works too) |
|
|
685
|
+
| Bin | `13:0:<binKey>` | The bag joins the bin and its own row completes; the station shows "Drop it in **bin-7**. All good." until the next scan |
|
|
686
|
+
|
|
687
|
+
Scan a different bin's label instead and the station refuses with the bag's
|
|
688
|
+
bin named, and nothing is written. Scan the bin before the badge and the
|
|
689
|
+
station asks for the badge, then places the bag on its own.
|
package/package.json
CHANGED