@hotmeshio/long-tail 0.22.1 → 0.22.3
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/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.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/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/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 +151 -0
- package/build/api/scan-codes/verb-fill.d.ts +6 -0
- package/build/api/scan-codes/verb-fill.js +155 -0
- 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 +33 -0
- package/build/api/scan-codes/verbs-subject.js +247 -0
- package/build/api/scan-codes/verbs.d.ts +11 -29
- package/build/api/scan-codes/verbs.js +51 -131
- package/build/index.d.ts +1 -0
- package/build/index.js +9 -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/sdk/index.d.ts +1 -0
- 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/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/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 +13 -10
- package/build/services/orchestrator/condition.js +8 -6
- 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 +8 -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-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.d.ts +7 -0
- package/build/services/scan-code/validate-subject.js +185 -0
- package/build/services/scan-code/validate.d.ts +7 -0
- package/build/services/scan-code/validate.js +103 -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 +11 -0
- package/build/shared/scan-code/gtin.js +38 -0
- package/build/shared/scan-code/index.d.ts +2 -0
- package/build/shared/scan-code/index.js +11 -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 +939 -28
- package/build/system/mcp-servers/admin/schemas.js +72 -6
- package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
- 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 +16 -8
- package/build/types/escalation.js +18 -7
- package/build/types/index.d.ts +4 -4
- package/build/types/index.js +10 -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 +145 -0
- package/build/types/scan-code/response.js +2 -0
- package/build/types/scan-code/rule.d.ts +229 -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-hI5-kKpL.js} +2 -2
- package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js.map → AdminDashboard-hI5-kKpL.js.map} +1 -1
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js → AgentConfigPage-DetU4HZe.js} +2 -2
- package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js.map → AgentConfigPage-DetU4HZe.js.map} +1 -1
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js → AgentDetailPage-DrGXo8KQ.js} +3 -3
- package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js.map → AgentDetailPage-DrGXo8KQ.js.map} +1 -1
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js → AgentsPage-D4md5BzM.js} +2 -2
- package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js.map → AgentsPage-D4md5BzM.js.map} +1 -1
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js → AvailableEscalationsPage-B2bS2ZJy.js} +2 -2
- package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js.map → AvailableEscalationsPage-B2bS2ZJy.js.map} +1 -1
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js → BotPicker-BXtey255.js} +2 -2
- package/dashboard/dist/assets/{BotPicker-CGB16rYU.js.map → BotPicker-BXtey255.js.map} +1 -1
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js → BulkAssignModal-CSL_PeZv.js} +2 -2
- package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js.map → BulkAssignModal-CSL_PeZv.js.map} +1 -1
- package/dashboard/dist/assets/CapabilitiesPage-5scufTHW.js +2 -0
- package/dashboard/dist/assets/{CapabilitiesPage-BxadotXn.js.map → CapabilitiesPage-5scufTHW.js.map} +1 -1
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js → CollapsibleSection-DjjDGxP_.js} +2 -2
- package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js.map → CollapsibleSection-DjjDGxP_.js.map} +1 -1
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js → ConfirmDeleteModal-DJSmsHQM.js} +2 -2
- package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js.map → ConfirmDeleteModal-DJSmsHQM.js.map} +1 -1
- package/dashboard/dist/assets/CountdownTimer-C5ZRYPfF.js +2 -0
- package/dashboard/dist/assets/{CountdownTimer-CI_JOAvk.js.map → CountdownTimer-C5ZRYPfF.js.map} +1 -1
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js → CredentialsPage-CV6e60yC.js} +2 -2
- package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js.map → CredentialsPage-CV6e60yC.js.map} +1 -1
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js → CronLabel-CnqhqW0B.js} +2 -2
- package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js.map → CronLabel-CnqhqW0B.js.map} +1 -1
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js → ElapsedCell-C1IOn-tj.js} +2 -2
- package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js.map → ElapsedCell-C1IOn-tj.js.map} +1 -1
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js → EntityTimelinePanel-Dz6Liig4.js} +2 -2
- package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js.map → EntityTimelinePanel-Dz6Liig4.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js → EscalationListSchemaPage-bgdmLmrh.js} +3 -3
- package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js.map → EscalationListSchemaPage-bgdmLmrh.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js → EscalationListView-CrlD3ZGt.js} +2 -2
- package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js.map → EscalationListView-CrlD3ZGt.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js → EscalationSchemaPage-dxXO_T3t.js} +3 -3
- package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js.map → EscalationSchemaPage-dxXO_T3t.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js → EscalationTimeline-C3WQZQuM.js} +2 -2
- package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js.map → EscalationTimeline-C3WQZQuM.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js → EscalationTitleSelect-CTtcETUO.js} +2 -2
- package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js.map → EscalationTitleSelect-CTtcETUO.js.map} +1 -1
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js → EscalationsOverview-DAjZ7JY2.js} +2 -2
- package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js.map → EscalationsOverview-DAjZ7JY2.js.map} +1 -1
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js → EventTable-B72DQP_v.js} +2 -2
- package/dashboard/dist/assets/{EventTable-DSHqKyX2.js.map → EventTable-B72DQP_v.js.map} +1 -1
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js → FilterBar-CCTaA_LH.js} +2 -2
- package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js.map → FilterBar-CCTaA_LH.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-CAsCgFo3.js} +2 -2
- package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js.map → GraphInvokePage-CAsCgFo3.js.map} +1 -1
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js → HomePage-DseE_iSr.js} +2 -2
- package/dashboard/dist/assets/{HomePage-ByKesG8w.js.map → HomePage-DseE_iSr.js.map} +1 -1
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js → ListToolbar-1zdqnjW6.js} +2 -2
- package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js.map → ListToolbar-1zdqnjW6.js.map} +1 -1
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js → McpOverview-DS_JXDW5.js} +2 -2
- package/dashboard/dist/assets/{McpOverview-CVe13tEv.js.map → McpOverview-DS_JXDW5.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js → McpQueryDetailPage-BeMUGcv3.js} +2 -2
- package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js.map → McpQueryDetailPage-BeMUGcv3.js.map} +1 -1
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js → McpQueryPage-CeiLO_LR.js} +2 -2
- package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js.map → McpQueryPage-CeiLO_LR.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js → McpRunDetailPage-DYp1uZK2.js} +2 -2
- package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js.map → McpRunDetailPage-DYp1uZK2.js.map} +1 -1
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js → McpRunsPage-VeaDzcL4.js} +2 -2
- package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js.map → McpRunsPage-VeaDzcL4.js.map} +1 -1
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js → OperationsPage-DK2mgaXf.js} +2 -2
- package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js.map → OperationsPage-DK2mgaXf.js.map} +1 -1
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js → OperatorDashboard-BNjLF0f7.js} +2 -2
- package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js.map → OperatorDashboard-BNjLF0f7.js.map} +1 -1
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js → PersonaDetailPage-IQ2fZLa6.js} +2 -2
- package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js.map → PersonaDetailPage-IQ2fZLa6.js.map} +1 -1
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js → PersonasPage-DpGFEcU-.js} +2 -2
- package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js.map → PersonasPage-DpGFEcU-.js.map} +1 -1
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js → PortalPage-D07xyvG_.js} +2 -2
- package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js.map → PortalPage-D07xyvG_.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js → ProcessDetailPage-t8EEYSMk.js} +2 -2
- package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js.map → ProcessDetailPage-t8EEYSMk.js.map} +1 -1
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js → ProcessesListPage-BDUXLFdb.js} +2 -2
- package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js.map → ProcessesListPage-BDUXLFdb.js.map} +1 -1
- package/dashboard/dist/assets/ResolverForm-BwWOYv_Z.js +8 -0
- package/dashboard/dist/assets/ResolverForm-BwWOYv_Z.js.map +1 -0
- package/dashboard/dist/assets/RoleDetailPage-zMF3x2xi.js +8 -0
- package/dashboard/dist/assets/RoleDetailPage-zMF3x2xi.js.map +1 -0
- package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js → RolesPage-CEBp_PpL.js} +2 -2
- package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js.map → RolesPage-CEBp_PpL.js.map} +1 -1
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js → RunAsSelector-CC_EHN3z.js} +2 -2
- package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js.map → RunAsSelector-CC_EHN3z.js.map} +1 -1
- package/dashboard/dist/assets/ScanCodesPage-DD4uU-jY.js +2 -0
- package/dashboard/dist/assets/ScanCodesPage-DD4uU-jY.js.map +1 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-CUW8gYFh.js +2 -0
- package/dashboard/dist/assets/ScanSchemeDetailPage-CUW8gYFh.js.map +1 -0
- package/dashboard/dist/assets/ScanStationPage-DpO_ESuf.js +2 -0
- package/dashboard/dist/assets/ScanStationPage-DpO_ESuf.js.map +1 -0
- package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js → StickyPagination-cNqSDm5f.js} +2 -2
- package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js.map → StickyPagination-cNqSDm5f.js.map} +1 -1
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js → StreamMessageDetail-C4oZqQdB.js} +2 -2
- package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js.map → StreamMessageDetail-C4oZqQdB.js.map} +1 -1
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js → SwimlaneTimeline-BjBiV7GT.js} +2 -2
- package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js.map → SwimlaneTimeline-BjBiV7GT.js.map} +1 -1
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js → TaskDetailPage-pO_AnVS1.js} +2 -2
- package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js.map → TaskDetailPage-pO_AnVS1.js.map} +1 -1
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js → TasksListPage-DKDHlWP7.js} +2 -2
- package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js.map → TasksListPage-DKDHlWP7.js.map} +1 -1
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js → TimeAgo-D2qchUuJ.js} +2 -2
- package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js.map → TimeAgo-D2qchUuJ.js.map} +1 -1
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js → TimestampCell-DeswZGGo.js} +2 -2
- package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js.map → TimestampCell-DeswZGGo.js.map} +1 -1
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js → ToolTestPanel-DJh7PIUa.js} +2 -2
- package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js.map → ToolTestPanel-DJh7PIUa.js.map} +1 -1
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js → TopicDetailPage-CsgDJ4Z4.js} +2 -2
- package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js.map → TopicDetailPage-CsgDJ4Z4.js.map} +1 -1
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js → TopicsPage-tBRZDVDN.js} +2 -2
- package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js.map → TopicsPage-tBRZDVDN.js.map} +1 -1
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js → UserName-B-5JcDck.js} +2 -2
- package/dashboard/dist/assets/{UserName-CXsdPiMZ.js.map → UserName-B-5JcDck.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js → WorkflowExecutionPage-BPHVnhp6.js} +2 -2
- package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js.map → WorkflowExecutionPage-BPHVnhp6.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js → WorkflowsDashboard-CxLlfZmY.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js.map → WorkflowsDashboard-CxLlfZmY.js.map} +1 -1
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js → WorkflowsOverview-C4az5rwp.js} +2 -2
- package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js.map → WorkflowsOverview-C4az5rwp.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js → YamlWorkflowDetailPage-BmhlAUFQ.js} +8 -8
- package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js.map → YamlWorkflowDetailPage-BmhlAUFQ.js.map} +1 -1
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js → YamlWorkflowsPage-CSbG5o2V.js} +2 -2
- package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js.map → YamlWorkflowsPage-CSbG5o2V.js.map} +1 -1
- package/dashboard/dist/assets/{agents-v_HH3Rji.js → agents-BohEn7vw.js} +2 -2
- package/dashboard/dist/assets/{agents-v_HH3Rji.js.map → agents-BohEn7vw.js.map} +1 -1
- package/dashboard/dist/assets/{bots-bwvWYrXz.js → bots-BG2EO-Wi.js} +2 -2
- package/dashboard/dist/assets/{bots-bwvWYrXz.js.map → bots-BG2EO-Wi.js.map} +1 -1
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js → capabilities-CeFrBmYX.js} +2 -2
- package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js.map → capabilities-CeFrBmYX.js.map} +1 -1
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js → controlplane-Dhvt8l8F.js} +2 -2
- package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js.map → controlplane-Dhvt8l8F.js.map} +1 -1
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js → escalation-columns-BWMNxImp.js} +2 -2
- package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js.map → escalation-columns-BWMNxImp.js.map} +1 -1
- package/dashboard/dist/assets/{index-CzjUgFt_.js → index-Bd_dgyfJ.js} +2 -2
- package/dashboard/dist/assets/{index-CzjUgFt_.js.map → index-Bd_dgyfJ.js.map} +1 -1
- package/dashboard/dist/assets/{index-IJmtbuLh.js → index-C8VlM2Oe.js} +2 -2
- package/dashboard/dist/assets/{index-IJmtbuLh.js.map → index-C8VlM2Oe.js.map} +1 -1
- package/dashboard/dist/assets/{index-CcuvGdvf.js → index-CiqSVDga.js} +2 -2
- package/dashboard/dist/assets/{index-CcuvGdvf.js.map → index-CiqSVDga.js.map} +1 -1
- package/dashboard/dist/assets/{index-C3WutFpT.js → index-Cl_YXEdp.js} +2 -2
- package/dashboard/dist/assets/{index-C3WutFpT.js.map → index-Cl_YXEdp.js.map} +1 -1
- package/dashboard/dist/assets/index-CtZWpy22.js +2 -0
- package/dashboard/dist/assets/index-CtZWpy22.js.map +1 -0
- package/dashboard/dist/assets/{index-CjenRVX_.js → index-D90D9y0J.js} +2 -2
- package/dashboard/dist/assets/{index-CjenRVX_.js.map → index-D90D9y0J.js.map} +1 -1
- package/dashboard/dist/assets/{index-BLB77tc8.js → index-DABkM7s-.js} +2 -2
- package/dashboard/dist/assets/{index-BLB77tc8.js.map → index-DABkM7s-.js.map} +1 -1
- package/dashboard/dist/assets/index-Dbwu51xm.js +3 -0
- package/dashboard/dist/assets/index-Dbwu51xm.js.map +1 -0
- package/dashboard/dist/assets/{index-2tzsxFat.js → index-Dc3Om6G3.js} +2 -2
- package/dashboard/dist/assets/{index-2tzsxFat.js.map → index-Dc3Om6G3.js.map} +1 -1
- package/dashboard/dist/assets/{index-D2VKBMng.js → index-Dc_zWK23.js} +2 -2
- package/dashboard/dist/assets/{index-D2VKBMng.js.map → index-Dc_zWK23.js.map} +1 -1
- package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
- package/dashboard/dist/assets/{index-C_ISDOWJ.js → index-Y-bdW8vo.js} +2 -2
- package/dashboard/dist/assets/{index-C_ISDOWJ.js.map → index-Y-bdW8vo.js.map} +1 -1
- package/dashboard/dist/assets/{index-C4Lce2ET.js → index-dYKgd06u.js} +3 -3
- package/dashboard/dist/assets/{index-C4Lce2ET.js.map → index-dYKgd06u.js.map} +1 -1
- package/dashboard/dist/assets/index-fUsx_gYx.js +67 -0
- package/dashboard/dist/assets/index-fUsx_gYx.js.map +1 -0
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js → knowledge-CCcTidNV.js} +2 -2
- package/dashboard/dist/assets/{knowledge-D1YP2NzS.js.map → knowledge-CCcTidNV.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-Bb5psC61.js → mcp-CLA1z7Pg.js} +2 -2
- package/dashboard/dist/assets/{mcp-Bb5psC61.js.map → mcp-CLA1z7Pg.js.map} +1 -1
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js → mcp-query-CWG0WMAs.js} +2 -2
- package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js.map → mcp-query-CWG0WMAs.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-CDndbkp4.js → personas-8jURIzx6.js} +2 -2
- package/dashboard/dist/assets/{personas-CDndbkp4.js.map → personas-8jURIzx6.js.map} +1 -1
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js → pipelines-hVVRAXqG.js} +2 -2
- package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js.map → pipelines-hVVRAXqG.js.map} +1 -1
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js → tasks-BE1O57Bf.js} +2 -2
- package/dashboard/dist/assets/{tasks-BlpDsWCy.js.map → tasks-BE1O57Bf.js.map} +1 -1
- package/dashboard/dist/assets/{topics-C0YaR9fu.js → topics-Bg96Wp1r.js} +2 -2
- package/dashboard/dist/assets/{topics-C0YaR9fu.js.map → topics-Bg96Wp1r.js.map} +1 -1
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js → useDebouncedValue-DmEveyEy.js} +2 -2
- package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js.map → useDebouncedValue-DmEveyEy.js.map} +1 -1
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js → useNamespace-DHgkzIuL.js} +2 -2
- package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js.map → useNamespace-DHgkzIuL.js.map} +1 -1
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js → useYamlActivityEvents-RU0PvU8S.js} +2 -2
- package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js.map → useYamlActivityEvents-RU0PvU8S.js.map} +1 -1
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js → yaml-workflows-DQWE9ijc.js} +2 -2
- package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js.map → yaml-workflows-DQWE9ijc.js.map} +1 -1
- package/dashboard/dist/index.html +2 -2
- package/docs/dashboard.md +1 -1
- package/docs/hitl/lookups.md +27 -18
- package/docs/hitl/x-lt-scan.md +51 -0
- package/docs/hitl/x-lt-validation.md +1 -1
- package/docs/hitl/x-lt-widget.md +1 -1
- package/docs/hitl-guide.md +3 -1
- package/docs/scan-codes.md +303 -33
- 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-D6pBLZFu.js +0 -2
- package/dashboard/dist/assets/index-D6pBLZFu.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/dashboard/dist/assets/metadata-display-COo3mMCr.js +0 -2
- package/dashboard/dist/assets/metadata-display-COo3mMCr.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
|
|
|
@@ -78,7 +88,8 @@ Each step:
|
|
|
78
88
|
"roles": ["printer-fleet"], // expected queue(s)
|
|
79
89
|
"status": "pending", // pending | resolved | cancelled
|
|
80
90
|
"availability": "available", // available | claimed | mine | any
|
|
81
|
-
"facets": { "state": "printing" }
|
|
91
|
+
"facets": { "state": "printing" }, // extra metadata guards
|
|
92
|
+
"subtypes": ["open"] // optional: types / subtypes the row must have
|
|
82
93
|
},
|
|
83
94
|
"cardinality": "first", // first | many
|
|
84
95
|
"verb": "resolve",
|
|
@@ -87,6 +98,14 @@ Each step:
|
|
|
87
98
|
}
|
|
88
99
|
```
|
|
89
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
|
+
|
|
90
109
|
Verbs are the canonical escalation actions:
|
|
91
110
|
|
|
92
111
|
| Verb | Effect | Params |
|
|
@@ -111,8 +130,8 @@ Verbs are the canonical escalation actions:
|
|
|
111
130
|
|
|
112
131
|
A `resolve` step applies it inside the atomic resolve: `mine` resolves the
|
|
113
132
|
actor's own claim, the most recently claimed first when there are several,
|
|
114
|
-
so a
|
|
115
|
-
for the same
|
|
133
|
+
so a container scan places the item in the associate's hand even when
|
|
134
|
+
another item for the same container is waiting. With no matching row the step falls through.
|
|
116
135
|
|
|
117
136
|
String values inside `itemKey`, `resolverPayload`, and `metadata` interpolate
|
|
118
137
|
`{scan.target}`, `{scan.category}`, and `{scan.scannedAt}`. Two facet bags
|
|
@@ -121,15 +140,15 @@ extend them: `{claim.<facet>}` reads the acting user's single live claim
|
|
|
121
140
|
make the step fall through), and `{item.<facet>}` reads the row an item-mode
|
|
122
141
|
`accumulate` step located. A token that cannot resolve falls through instead
|
|
123
142
|
of writing the literal, and the rule editor rejects `{item.…}` on any other
|
|
124
|
-
step.
|
|
125
|
-
`"itemKey": "{claim.
|
|
143
|
+
step. An item-first ladder therefore names the item from the claim:
|
|
144
|
+
`"itemKey": "{claim.itemId}"` on the container scan. Every mutating verb stamps
|
|
126
145
|
provenance facets onto the row it touches — `scanScheme`, `scanCategory`,
|
|
127
146
|
`scanActionName`, `scannedAt` — so scan-driven transitions stay queryable.
|
|
128
147
|
|
|
129
148
|
`accumulate` has two modes. With `params.accumulate.containerFacet` the
|
|
130
149
|
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
|
-
`
|
|
150
|
+
through the scheme facet, reads that facet from the row (an item row carrying
|
|
151
|
+
`containerKey: "C-7"`), and adds the target to the pending accumulator whose
|
|
133
152
|
metadata carries the same value, writing the item's row as the reciprocal in
|
|
134
153
|
the same statement (`reciprocal: false` skips it). The container pick
|
|
135
154
|
considers only pending rows that carry the accumulator declaration, so a
|
|
@@ -138,27 +157,27 @@ release row sharing the facet during a pack-out is never the target.
|
|
|
138
157
|
|
|
139
158
|
```jsonc
|
|
140
159
|
"accumulate": {
|
|
141
|
-
"containerFacet": "
|
|
160
|
+
"containerFacet": "containerKey",
|
|
142
161
|
"container": {
|
|
143
|
-
"roles": ["
|
|
144
|
-
"types": ["
|
|
145
|
-
"subtypes": ["
|
|
162
|
+
"roles": ["packing"], // container queues (containerRoles is an alias)
|
|
163
|
+
"types": ["container"], // escalation type
|
|
164
|
+
"subtypes": ["open"], // escalation subtype
|
|
146
165
|
"facets": { "open": true } // extra metadata guards
|
|
147
166
|
}
|
|
148
167
|
}
|
|
149
168
|
```
|
|
150
169
|
|
|
151
170
|
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
|
|
171
|
+
its container (an item's slot beside its container, both carrying
|
|
172
|
+
`containerKey`) declares the container's type or subtype, so the add lands in
|
|
173
|
+
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
174
|
adds `params.itemKey` (a template) to it. An item with no row or no container
|
|
156
175
|
facet falls through to the next step; a container already holding the item
|
|
157
176
|
reports a conflict. When the item's row exists but no pending container
|
|
158
177
|
carries its facet (the previous container closed and its successor has not
|
|
159
178
|
parked yet), the step answers `no_open_container` with the item row, the
|
|
160
179
|
facet, and the rule's fallback markdown, so the station reads "Container
|
|
161
|
-
closing, scan again" instead of the
|
|
180
|
+
closing, scan again" instead of the item with no hint.
|
|
162
181
|
|
|
163
182
|
Ordering is the power move: put the expected state first and a broad
|
|
164
183
|
`show-detail` last. A machine whose twin is in the wrong queue still answers
|
|
@@ -182,7 +201,7 @@ guarded call every other surface uses.
|
|
|
182
201
|
|
|
183
202
|
## Info-choice screens
|
|
184
203
|
|
|
185
|
-
Some objects carry one code for their whole life — an item tag,
|
|
204
|
+
Some objects carry one code for their whole life — an item tag, a record
|
|
186
205
|
label. One code, many possible intents, and the right one depends on where
|
|
187
206
|
the object is in its journey. The `present` verb closes that gap: the step
|
|
188
207
|
locates the row, states its reality, and returns a configured, labeled
|
|
@@ -209,10 +228,32 @@ unsatisfied. Picking one calls `POST /api/scan-codes/execute-choice` with a
|
|
|
209
228
|
pointer (scheme, category, step index, choice index, escalation id) — and a
|
|
210
229
|
pointer is never authority: the server re-reads live config, re-locates the
|
|
211
230
|
row under the step's query, re-applies the identity gate, and runs the verb
|
|
212
|
-
through the same atomic executors a direct scan uses.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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.
|
|
216
257
|
|
|
217
258
|
A choice's `code` is a short printable token (letters, digits, underscore,
|
|
218
259
|
dash) enabling double-scan selection: scan the object, then scan an action
|
|
@@ -231,6 +272,153 @@ duration, form on screen. An unsatisfied identity requirement never
|
|
|
231
272
|
auto-fires as the wrong actor — the scan stops over at the badge screen and
|
|
232
273
|
completes on its own once a badge primes.
|
|
233
274
|
|
|
275
|
+
## Holding an item: the bench motion
|
|
276
|
+
|
|
277
|
+
At a bench where items go into containers, every act is one item going into
|
|
278
|
+
one container, or one expected item checked off a record. The motion is three scans with nothing in between: **the item, your badge, the
|
|
279
|
+
container**. The container scan is the act. The item scan only says which
|
|
280
|
+
item; the badge says who.
|
|
281
|
+
|
|
282
|
+
**`hold`** is the item scan. The step locates the row and answers `held`
|
|
283
|
+
with a **subject**: the code that held it, the row id, a label, an expiry,
|
|
284
|
+
and what to scan next. It writes nothing and spends no badge use. The
|
|
285
|
+
station keeps the subject (device-local, in memory) and sends it back with
|
|
286
|
+
the next scans as `subject: { code, escalationId }`. Scanning another item
|
|
287
|
+
replaces it; it lapses on its own after `ttlSeconds` (default 45).
|
|
288
|
+
|
|
289
|
+
```jsonc
|
|
290
|
+
{ "query": { "roles": ["packing"] }, "verb": "hold",
|
|
291
|
+
"params": { "hold": { "ttlSeconds": 300, "label": "{scan.target}",
|
|
292
|
+
"headline": "{item.containerCode}", "subline": "{item.locationName}",
|
|
293
|
+
"expect": { "schemes": [14], "prompt": "Walk to this container and scan it.\n\n{item.labelNote}" } } } }
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
**What the station shows.** With `hold.headline` the destination leads the
|
|
297
|
+
screen: the headline (e.g. `{item.containerCode}`) in very large type, `hold.subline`
|
|
298
|
+
under it (e.g. `{item.locationName}`), the held item itself as a quieter line
|
|
299
|
+
above, then the `expect.prompt`. A template that renders empty drops its line,
|
|
300
|
+
so a row-level note such as `{item.labelNote}` appears only when the workflow
|
|
301
|
+
set one ("Take the new label from the printer and stick it on C-12").
|
|
302
|
+
Any step that writes may carry `done: { markdown }`: the copy the station shows,
|
|
303
|
+
large, once the write lands and until the next scan ("Place it in
|
|
304
|
+
**{container.containerCode}**. All good."). It reads the same bags its refusal copy
|
|
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).
|
|
308
|
+
|
|
309
|
+
The server trusts nothing about the subject. Each request re-parses its
|
|
310
|
+
code, re-reads the row under the station's read scope, requires the row to
|
|
311
|
+
still carry the code's target and to be pending. A subject that fails is
|
|
312
|
+
stale: steps that need one are skipped, and when nothing else matches the
|
|
313
|
+
answer is `subject_stale` with `clearSubject: true`.
|
|
314
|
+
|
|
315
|
+
**Subject steps** run only while a subject from one of `subject.schemes` is
|
|
316
|
+
held, and act on it. The `{subject.<facet>}` template bag reads the held
|
|
317
|
+
row.
|
|
318
|
+
|
|
319
|
+
| Step | What the container scan does |
|
|
320
|
+
|---|---|
|
|
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}`. |
|
|
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. |
|
|
324
|
+
|
|
325
|
+
**`match` and `refuse`** check the pairing before anything is written.
|
|
326
|
+
`match.target` lists templates the scanned target must equal (e.g.
|
|
327
|
+
`["{subject.containerCode}"]`); `match.facets` lists facets the located container
|
|
328
|
+
must share with the held row (e.g. `["containerKey"]`). A miss answers `refused`
|
|
329
|
+
with `refuse.markdown` rendered, and nothing is written. The copy may read
|
|
330
|
+
`{container.<facet>}` (the container the scan named) and `{fill.pending}`
|
|
331
|
+
(what a fill still expects), so the station says what is wrong and where the
|
|
332
|
+
item goes: "That's Acme West's container. This one goes in **C-12**." When the
|
|
333
|
+
write itself loses a race (the container closed, another bench took the free
|
|
334
|
+
container), the answer is `refused` with `refuse.conflict`, and a step that
|
|
335
|
+
declares `refuse.conflict` also clears the subject so the next item scan
|
|
336
|
+
reads fresh state. Exactly one of two racing acts wins whenever both name
|
|
337
|
+
the same row: the reciprocal statement writes both rows or neither.
|
|
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
|
+
|
|
370
|
+
**One rule, several kinds of held item.** `subject.facets` makes a step
|
|
371
|
+
apply only while the held row carries those facet values; otherwise the step
|
|
372
|
+
is skipped and the next one runs. A placing bench uses it to tell an item
|
|
373
|
+
whose destination already has a container from one that needs a free
|
|
374
|
+
container: the item row carries `placement: 'assigned'` or `'unassigned'`, and
|
|
375
|
+
the container label's rule has one step for each.
|
|
376
|
+
|
|
377
|
+
```jsonc
|
|
378
|
+
// 14:0, container label
|
|
379
|
+
[
|
|
380
|
+
{ "verb": "accumulate", "requireActingIdentity": true,
|
|
381
|
+
"subject": { "schemes": [11], "facets": { "placement": "assigned" } },
|
|
382
|
+
"match": { "target": ["{subject.containerCode}"] },
|
|
383
|
+
"refuse": { "markdown": "That's {container.locationName}'s container. This one goes in **{subject.containerCode}**." },
|
|
384
|
+
"params": { "itemKey": "{subject.itemId}",
|
|
385
|
+
"accumulate": { "from": "subject", "container": { "types": ["container"], "subtypes": ["open"] } } } },
|
|
386
|
+
{ "verb": "accumulate", "requireActingIdentity": true,
|
|
387
|
+
"subject": { "schemes": [11], "facets": { "placement": "unassigned" } },
|
|
388
|
+
"match": { "target": ["{subject.offeredContainers}"] },
|
|
389
|
+
"refuse": { "markdown": "Choose a free container: {subject.offeredContainers}.",
|
|
390
|
+
"conflict": "That container was just taken. Scan the item again.",
|
|
391
|
+
"missing": "That container was just taken. Scan the item again." },
|
|
392
|
+
"params": { "itemKey": "{subject.itemId}",
|
|
393
|
+
"accumulate": { "from": "subject", "container": { "types": ["container"], "subtypes": ["free"] } } } },
|
|
394
|
+
{ "query": { "roles": ["packing"] }, "verb": "present", "choices": [ /* Close this container, View container */ ] }
|
|
395
|
+
]
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The workflow stamps the containers it offers on the item row (`offeredContainers`). A
|
|
399
|
+
`match.target` entry that is a lone token naming a list facet allows every
|
|
400
|
+
entry, so any offered container takes the item and any other is refused with
|
|
401
|
+
the offer listed. A free container is a `max: 1` accumulator row, so of two
|
|
402
|
+
items racing for one free container exactly one lands; the other is refused with the
|
|
403
|
+
conflict copy. `refuse.missing` covers an offered container with no open row (taken
|
|
404
|
+
a moment ago): the scan is refused instead of falling through to the next
|
|
405
|
+
step. The third step has no subject gate: scanning a container with no item
|
|
406
|
+
held offers to close it.
|
|
407
|
+
|
|
408
|
+
Someone else's live claim on the held row refuses the act with their name
|
|
409
|
+
(`subject.claimedByOther: "allow"` lifts this). An item already in the
|
|
410
|
+
scanned container answers `executed` with `already: true`, and nothing is
|
|
411
|
+
written twice.
|
|
412
|
+
|
|
413
|
+
The badge can come before the item or between the item and the container. A
|
|
414
|
+
container scan that needs a badge answers `not_primed` with
|
|
415
|
+
`replayable: true`; the station keeps the subject, asks for the badge, and
|
|
416
|
+
replays the container scan once the badge primes.
|
|
417
|
+
|
|
418
|
+
Subject steps sit beside the steps a rule already has: with no subject held
|
|
419
|
+
they are skipped, so the same rule keeps working for scans made without the
|
|
420
|
+
item scan first.
|
|
421
|
+
|
|
234
422
|
## Identity schemes and acting identity
|
|
235
423
|
|
|
236
424
|
A scheme with `kind: "identity"` is the badge layer. Its `target_facet`
|
|
@@ -247,7 +435,39 @@ scheme's policy:
|
|
|
247
435
|
| Scheme field | Meaning |
|
|
248
436
|
|---|---|
|
|
249
437
|
| `grant_ttl_seconds` | How long the grant lives (1–86400). |
|
|
250
|
-
| `grant_max_uses` | `0` = TTL-bound; `n` = the grant covers n
|
|
438
|
+
| `grant_max_uses` | `0` = TTL-bound; `n` = the grant covers n acts (a strict one-act policy is `1`). |
|
|
439
|
+
| `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. |
|
|
440
|
+
|
|
441
|
+
**The station decides the policy.** One printed badge works at every bench,
|
|
442
|
+
but benches want different policies: a workstation grants one act per badge
|
|
443
|
+
scan (claim, then submit, takes two scans), a high-volume placing bench grants
|
|
444
|
+
ten minutes of acts. A role may declare its stations' policy in `properties.badge_grant`:
|
|
445
|
+
|
|
446
|
+
```jsonc
|
|
447
|
+
"properties": { "kiosk": true, "badge_grant": { "ttl_seconds": 600, "max_uses": 0 } }
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
A badge scanned on a device signed in as a member of that role mints under
|
|
451
|
+
it; fields left out keep the badge scheme's values (`scope` is the role's
|
|
452
|
+
`grant_scope`). A device that belongs to several roles with different
|
|
453
|
+
policies uses the role it is locked to (the dashboard sends its kiosk role as
|
|
454
|
+
`stationRole` with every scan); with no role policy, or no way to choose
|
|
455
|
+
between several, the badge scheme's own policy applies. The policy is
|
|
456
|
+
validated where the role is written: an unusable `badge_grant` is a 400 from
|
|
457
|
+
the role API and fails a code-owned role's startup apply. The role page edits
|
|
458
|
+
it under **Members → Badge at this station**.
|
|
459
|
+
|
|
460
|
+
A grant is spent by **acts**, not by looking. A scan that shows, presents,
|
|
461
|
+
holds, or refuses reads the grant without spending it; a mutating verb spends
|
|
462
|
+
one use just before it writes, and a write that does not land (the step
|
|
463
|
+
falls through, the scan is refused) gives the use back. Every scan response
|
|
464
|
+
that carried a grant reports `acting: { consumed, remaining, bound }`, and
|
|
465
|
+
the escalation work routes report the uses left in the
|
|
466
|
+
`X-LT-Acting-Remaining` header. The device retires its copy of the grant when
|
|
467
|
+
the server reports none left, or when a subject-bound grant's subject is
|
|
468
|
+
done; reads never carry the grant at all. A scan that comes back
|
|
469
|
+
`not_primed` while a grant is held drops that grant, so the next scan runs
|
|
470
|
+
unprimed instead of repeating the badge screen.
|
|
251
471
|
|
|
252
472
|
The grant rides subsequent scans as `actingToken`. Verbs then run **as the
|
|
253
473
|
badged person under their own live RBAC** — the grant confers attribution,
|
|
@@ -287,7 +507,10 @@ signed-in user is a **member of exactly that one role** — the station-login
|
|
|
287
507
|
shape — the dashboard locks the viewport: the left nav is gone entirely, the
|
|
288
508
|
role's escalation list is home (`/` and every other surface redirect to it),
|
|
289
509
|
and the session is held to the list, the escalation detail page, the role's
|
|
290
|
-
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
|
|
291
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
|
|
292
515
|
holding more than one role, or an admin-type grant, always gets full chrome —
|
|
293
516
|
kiosk is for the single-role floor login, never a way to hide the product from
|
|
@@ -313,12 +536,16 @@ submit opens a badge prompt naming that claimant. The resolve fires the moment
|
|
|
313
536
|
a matching badge primes; a badge that is not the claimant's is named and the
|
|
314
537
|
submit is held.
|
|
315
538
|
|
|
316
|
-
The gate is on **use**, not on grant lifetime.
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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.
|
|
322
549
|
|
|
323
550
|
Mutations attribute to the badged person (`assigned_to`, `resolved_by`)
|
|
324
551
|
with the device recorded beside them (`scanStation` in the scan
|
|
@@ -333,6 +560,12 @@ to continue. The badge scan primes the session and the pending action
|
|
|
333
560
|
completes on its own. With a live grant the stop-over never appears — the
|
|
334
561
|
identity layer is invisible when all is well.
|
|
335
562
|
|
|
563
|
+
A field can take a scan while the form is open: with
|
|
564
|
+
[`x-lt-scan`](hitl/x-lt-scan.md), scanning a container into a claimed form
|
|
565
|
+
fills its container field (checked against what the record expects), and
|
|
566
|
+
`x-lt-scan-submit` submits once the scan fields are filled, which raises the
|
|
567
|
+
badge prompt. A scan no field accepts runs globally as usual.
|
|
568
|
+
|
|
336
569
|
Badge tokens are printed credentials: seed them as long random strings,
|
|
337
570
|
bind them server-side (`lt_users.metadata`), and treat badge possession
|
|
338
571
|
with the same physical policy as any badge system. Unknown badges answer
|
|
@@ -347,9 +580,10 @@ renders the markdown; a configured route navigates.
|
|
|
347
580
|
|
|
348
581
|
## Executing a scan
|
|
349
582
|
|
|
350
|
-
`POST /api/scan-codes/execute` takes `{ "code": "10:1:SN-123" }`
|
|
351
|
-
|
|
352
|
-
200
|
|
583
|
+
`POST /api/scan-codes/execute` takes `{ "code": "10:1:SN-123" }` (plus
|
|
584
|
+
`actingToken` and `subject` when the station holds them) and runs as the
|
|
585
|
+
calling user under normal RBAC. Every terminal state is a structured 200
|
|
586
|
+
outcome:
|
|
353
587
|
|
|
354
588
|
| Outcome | Meaning |
|
|
355
589
|
|---------|---------|
|
|
@@ -362,6 +596,15 @@ as the calling user under normal RBAC. Every terminal state is a structured
|
|
|
362
596
|
| `invalid_code` | The string parses under no enabled scheme |
|
|
363
597
|
| `forbidden` | The caller's roles bar the matched action |
|
|
364
598
|
| `conflict` | A concurrent actor won the row |
|
|
599
|
+
| `choices` | A `present` step located its row; `escalation` + `choices` included |
|
|
600
|
+
| `held` | A `hold` step located its row; `subject` included |
|
|
601
|
+
| `refused` | The scan was understood and not acted on; nothing written; `refusal.markdown` (and `refusal.expected`) included |
|
|
602
|
+
| `subject_stale` | The held subject moved on; `clearSubject: true` |
|
|
603
|
+
| `not_primed` | The act needs a badge; `notPrimed` included, `replayable: true` when the scan may run again once one primes |
|
|
604
|
+
| `identity_primed` / `identity_unknown` | A badge scan matched a person, or did not |
|
|
605
|
+
|
|
606
|
+
A step's payload rejected by the role's form schema answers `refused` with
|
|
607
|
+
the reason, never a raw 422.
|
|
365
608
|
|
|
366
609
|
The endpoint is source-agnostic — anything that produces a string can drive
|
|
367
610
|
it: a barcode scanner, an RFID reader, a camera decode, an MCP tool
|
|
@@ -381,8 +624,18 @@ When enabled, the dashboard listens for scans globally — any page, any focus
|
|
|
381
624
|
state. A scanner paired as an HID keyboard "types" its decode and finishes
|
|
382
625
|
with Enter; capture is **pattern-anchored**: a capture-phase window listener
|
|
383
626
|
accumulates keystrokes freely, and when the terminator arrives it checks
|
|
384
|
-
whether the recent keys end with a scan-code shape
|
|
385
|
-
|
|
627
|
+
whether the recent keys end with a scan-code shape. The shapes come from the
|
|
628
|
+
configured schemes: each delimited version's `VV:C:target`, each fixed
|
|
629
|
+
scheme's exact digit lengths, and for a gtin scheme a whole 8, 12, 13 or 14
|
|
630
|
+
digit run whose check digit holds (a leading zero is part of the code). A
|
|
631
|
+
code never starts inside a longer run of digits.
|
|
632
|
+
|
|
633
|
+
- **Digits-only codes fire only at scanner speed** (avg ≤ 50 ms/key). A
|
|
634
|
+
typed PO number or count followed by Enter stays in its field, even when
|
|
635
|
+
its digits happen to form a valid barcode.
|
|
636
|
+
- **An open form can take the scan first.** A field with
|
|
637
|
+
[`x-lt-scan`](hitl/x-lt-scan.md) that accepts the scan's scheme is filled
|
|
638
|
+
instead; every other scan, and every badge, runs globally.
|
|
386
639
|
|
|
387
640
|
- On a match, the terminator is swallowed, the code's characters are
|
|
388
641
|
stripped back out of whatever editable held focus (byte-exact, at the
|
|
@@ -487,3 +740,20 @@ of each machine:
|
|
|
487
740
|
Each rule ends on a broad `show-detail` and the "no twin found" fallback.
|
|
488
741
|
Walk it hardware-free: run the twin farm, open the scan panel, and paste
|
|
489
742
|
`10:1:<a-printing-serial>`.
|
|
743
|
+
|
|
744
|
+
## The bag and bin demo
|
|
745
|
+
|
|
746
|
+
`examples/seed-scan-bins.ts` puts the bench motion on the
|
|
747
|
+
[rollup-bin](../examples/workflows/rollup-bin/) example. Start a `rollupBin`
|
|
748
|
+
with a `binKey` and a few `rollupMember` bags carrying the same `binKey`,
|
|
749
|
+
then at the scan station:
|
|
750
|
+
|
|
751
|
+
| Scan | Code | What happens |
|
|
752
|
+
|---|---|---|
|
|
753
|
+
| Bag | `12:0:<orderId>` | The station holds the bag and shows its bin, large |
|
|
754
|
+
| Badge | `11:0:<badge>` | Primes the person (before the bag works too) |
|
|
755
|
+
| 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 |
|
|
756
|
+
|
|
757
|
+
Scan a different bin's label instead and the station refuses with the bag's
|
|
758
|
+
bin named, and nothing is written. Scan the bin before the badge and the
|
|
759
|
+
station asks for the badge, then places the bag on its own.
|
package/package.json
CHANGED