@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.
Files changed (331) hide show
  1. package/build/api/escalations/accumulate.js +38 -19
  2. package/build/api/escalations/lookups.d.ts +9 -2
  3. package/build/api/escalations/lookups.js +15 -3
  4. package/build/api/escalations/metadata.d.ts +2 -0
  5. package/build/api/escalations/metadata.js +9 -0
  6. package/build/api/escalations/resolve-batch.js +18 -11
  7. package/build/api/roles.js +4 -0
  8. package/build/api/scan-codes/badge-policy.d.ts +10 -0
  9. package/build/api/scan-codes/badge-policy.js +72 -0
  10. package/build/api/scan-codes/choice.js +16 -10
  11. package/build/api/scan-codes/context.d.ts +45 -1
  12. package/build/api/scan-codes/context.js +51 -3
  13. package/build/api/scan-codes/execute.js +73 -35
  14. package/build/api/scan-codes/grant.d.ts +27 -0
  15. package/build/api/scan-codes/grant.js +67 -0
  16. package/build/api/scan-codes/hold.d.ts +10 -0
  17. package/build/api/scan-codes/hold.js +98 -0
  18. package/build/api/scan-codes/identity.d.ts +5 -2
  19. package/build/api/scan-codes/identity.js +26 -8
  20. package/build/api/scan-codes/locate.js +4 -0
  21. package/build/api/scan-codes/present.d.ts +1 -1
  22. package/build/api/scan-codes/present.js +43 -0
  23. package/build/api/scan-codes/subject.d.ts +15 -0
  24. package/build/api/scan-codes/subject.js +68 -0
  25. package/build/api/scan-codes/verb-accumulate.d.ts +24 -0
  26. package/build/api/scan-codes/verb-accumulate.js +151 -0
  27. package/build/api/scan-codes/verb-fill.d.ts +6 -0
  28. package/build/api/scan-codes/verb-fill.js +155 -0
  29. package/build/api/scan-codes/verb-into-subject.d.ts +12 -0
  30. package/build/api/scan-codes/verb-into-subject.js +157 -0
  31. package/build/api/scan-codes/verbs-subject.d.ts +33 -0
  32. package/build/api/scan-codes/verbs-subject.js +247 -0
  33. package/build/api/scan-codes/verbs.d.ts +11 -29
  34. package/build/api/scan-codes/verbs.js +51 -131
  35. package/build/index.d.ts +1 -0
  36. package/build/index.js +9 -2
  37. package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
  38. package/build/routes/escalations/acting.d.ts +5 -0
  39. package/build/routes/escalations/acting.js +8 -1
  40. package/build/routes/scan-codes.js +3 -0
  41. package/build/sdk/index.d.ts +1 -0
  42. package/build/services/escalation/claim-asserted.d.ts +10 -0
  43. package/build/services/escalation/claim-asserted.js +64 -0
  44. package/build/services/escalation/facets.d.ts +3 -1
  45. package/build/services/escalation/facets.js +7 -3
  46. package/build/services/escalation/index.d.ts +1 -0
  47. package/build/services/escalation/index.js +3 -1
  48. package/build/services/iam/acting-identity.d.ts +29 -4
  49. package/build/services/iam/acting-identity.js +60 -17
  50. package/build/services/iam/ephemeral.d.ts +21 -0
  51. package/build/services/iam/ephemeral.js +32 -1
  52. package/build/services/iam/sql.d.ts +10 -0
  53. package/build/services/iam/sql.js +32 -3
  54. package/build/services/knowledge/lookup-cache.d.ts +16 -4
  55. package/build/services/knowledge/lookup-cache.js +53 -20
  56. package/build/services/knowledge/lookup-refs.d.ts +3 -2
  57. package/build/services/knowledge/lookup-refs.js +6 -4
  58. package/build/services/knowledge/sql.d.ts +2 -0
  59. package/build/services/knowledge/sql.js +9 -1
  60. package/build/services/mcp/server-tools.js +1 -1
  61. package/build/services/orchestrator/condition.d.ts +13 -10
  62. package/build/services/orchestrator/condition.js +8 -6
  63. package/build/services/role/badge-grant.d.ts +5 -0
  64. package/build/services/role/badge-grant.js +36 -0
  65. package/build/services/role/seed.js +5 -0
  66. package/build/services/role/types.d.ts +14 -0
  67. package/build/services/role/types.js +5 -0
  68. package/build/services/scan-code/index.d.ts +3 -2
  69. package/build/services/scan-code/index.js +8 -1
  70. package/build/services/scan-code/parse.d.ts +23 -20
  71. package/build/services/scan-code/parse.js +45 -90
  72. package/build/services/scan-code/read.js +1 -0
  73. package/build/services/scan-code/sql.d.ts +3 -3
  74. package/build/services/scan-code/sql.js +11 -8
  75. package/build/services/scan-code/validate-facts.d.ts +5 -0
  76. package/build/services/scan-code/validate-facts.js +24 -0
  77. package/build/services/scan-code/validate-query.d.ts +8 -0
  78. package/build/services/scan-code/validate-query.js +36 -0
  79. package/build/services/scan-code/validate-subject.d.ts +7 -0
  80. package/build/services/scan-code/validate-subject.js +185 -0
  81. package/build/services/scan-code/validate.d.ts +7 -0
  82. package/build/services/scan-code/validate.js +103 -18
  83. package/build/services/scan-code/write.d.ts +1 -0
  84. package/build/services/scan-code/write.js +9 -3
  85. package/build/shared/form-validation/field-validator.js +4 -0
  86. package/build/shared/form-validation/index.d.ts +1 -0
  87. package/build/shared/form-validation/index.js +1 -0
  88. package/build/shared/form-validation/x-lt-scan.d.ts +52 -0
  89. package/build/shared/form-validation/x-lt-scan.js +166 -0
  90. package/build/shared/scan-code/gtin.d.ts +11 -0
  91. package/build/shared/scan-code/gtin.js +38 -0
  92. package/build/shared/scan-code/index.d.ts +2 -0
  93. package/build/shared/scan-code/index.js +11 -0
  94. package/build/shared/scan-code/parse.d.ts +46 -0
  95. package/build/shared/scan-code/parse.js +133 -0
  96. package/build/system/mcp-servers/admin/scan-codes.js +10 -4
  97. package/build/system/mcp-servers/admin/schemas.d.ts +939 -28
  98. package/build/system/mcp-servers/admin/schemas.js +72 -6
  99. package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
  100. package/build/system/seed/tool-manifests-admin.d.ts +202 -1
  101. package/build/system/seed/tool-manifests-admin.js +2 -2
  102. package/build/tsconfig.tsbuildinfo +1 -1
  103. package/build/types/escalation.d.ts +16 -8
  104. package/build/types/escalation.js +18 -7
  105. package/build/types/index.d.ts +4 -4
  106. package/build/types/index.js +10 -1
  107. package/build/types/scan-code/constants.d.ts +182 -0
  108. package/build/types/{scan-code.js → scan-code/constants.js} +72 -11
  109. package/build/types/scan-code/index.d.ts +3 -0
  110. package/build/types/scan-code/index.js +17 -0
  111. package/build/types/scan-code/response.d.ts +145 -0
  112. package/build/types/scan-code/response.js +2 -0
  113. package/build/types/scan-code/rule.d.ts +229 -0
  114. package/build/types/scan-code/rule.js +2 -0
  115. package/build/types/startup.d.ts +3 -1
  116. package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js → AdminDashboard-hI5-kKpL.js} +2 -2
  117. package/dashboard/dist/assets/{AdminDashboard-BbWve-Ax.js.map → AdminDashboard-hI5-kKpL.js.map} +1 -1
  118. package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js → AgentConfigPage-DetU4HZe.js} +2 -2
  119. package/dashboard/dist/assets/{AgentConfigPage-M-9eTKhP.js.map → AgentConfigPage-DetU4HZe.js.map} +1 -1
  120. package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js → AgentDetailPage-DrGXo8KQ.js} +3 -3
  121. package/dashboard/dist/assets/{AgentDetailPage-CsakSlx5.js.map → AgentDetailPage-DrGXo8KQ.js.map} +1 -1
  122. package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js → AgentsPage-D4md5BzM.js} +2 -2
  123. package/dashboard/dist/assets/{AgentsPage-Cj_cRTT1.js.map → AgentsPage-D4md5BzM.js.map} +1 -1
  124. package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js → AvailableEscalationsPage-B2bS2ZJy.js} +2 -2
  125. package/dashboard/dist/assets/{AvailableEscalationsPage-BXJmMBM1.js.map → AvailableEscalationsPage-B2bS2ZJy.js.map} +1 -1
  126. package/dashboard/dist/assets/{BotPicker-CGB16rYU.js → BotPicker-BXtey255.js} +2 -2
  127. package/dashboard/dist/assets/{BotPicker-CGB16rYU.js.map → BotPicker-BXtey255.js.map} +1 -1
  128. package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js → BulkAssignModal-CSL_PeZv.js} +2 -2
  129. package/dashboard/dist/assets/{BulkAssignModal-MjxcU7N1.js.map → BulkAssignModal-CSL_PeZv.js.map} +1 -1
  130. package/dashboard/dist/assets/CapabilitiesPage-5scufTHW.js +2 -0
  131. package/dashboard/dist/assets/{CapabilitiesPage-BxadotXn.js.map → CapabilitiesPage-5scufTHW.js.map} +1 -1
  132. package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js → CollapsibleSection-DjjDGxP_.js} +2 -2
  133. package/dashboard/dist/assets/{CollapsibleSection-BBNpP-6h.js.map → CollapsibleSection-DjjDGxP_.js.map} +1 -1
  134. package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js → ConfirmDeleteModal-DJSmsHQM.js} +2 -2
  135. package/dashboard/dist/assets/{ConfirmDeleteModal-D_kAbT_D.js.map → ConfirmDeleteModal-DJSmsHQM.js.map} +1 -1
  136. package/dashboard/dist/assets/CountdownTimer-C5ZRYPfF.js +2 -0
  137. package/dashboard/dist/assets/{CountdownTimer-CI_JOAvk.js.map → CountdownTimer-C5ZRYPfF.js.map} +1 -1
  138. package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js → CredentialsPage-CV6e60yC.js} +2 -2
  139. package/dashboard/dist/assets/{CredentialsPage-C9OA1Q2J.js.map → CredentialsPage-CV6e60yC.js.map} +1 -1
  140. package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js → CronLabel-CnqhqW0B.js} +2 -2
  141. package/dashboard/dist/assets/{CronLabel-sxLLBf2I.js.map → CronLabel-CnqhqW0B.js.map} +1 -1
  142. package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js → ElapsedCell-C1IOn-tj.js} +2 -2
  143. package/dashboard/dist/assets/{ElapsedCell-jH9m8Dgl.js.map → ElapsedCell-C1IOn-tj.js.map} +1 -1
  144. package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js → EntityTimelinePanel-Dz6Liig4.js} +2 -2
  145. package/dashboard/dist/assets/{EntityTimelinePanel-Dl3Nr2kk.js.map → EntityTimelinePanel-Dz6Liig4.js.map} +1 -1
  146. package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js → EscalationListSchemaPage-bgdmLmrh.js} +3 -3
  147. package/dashboard/dist/assets/{EscalationListSchemaPage-DAK6It5J.js.map → EscalationListSchemaPage-bgdmLmrh.js.map} +1 -1
  148. package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js → EscalationListView-CrlD3ZGt.js} +2 -2
  149. package/dashboard/dist/assets/{EscalationListView-CAHbdxKR.js.map → EscalationListView-CrlD3ZGt.js.map} +1 -1
  150. package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js → EscalationSchemaPage-dxXO_T3t.js} +3 -3
  151. package/dashboard/dist/assets/{EscalationSchemaPage-DotfAMCL.js.map → EscalationSchemaPage-dxXO_T3t.js.map} +1 -1
  152. package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js → EscalationTimeline-C3WQZQuM.js} +2 -2
  153. package/dashboard/dist/assets/{EscalationTimeline-DqmFydnU.js.map → EscalationTimeline-C3WQZQuM.js.map} +1 -1
  154. package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js → EscalationTitleSelect-CTtcETUO.js} +2 -2
  155. package/dashboard/dist/assets/{EscalationTitleSelect-BpRquguO.js.map → EscalationTitleSelect-CTtcETUO.js.map} +1 -1
  156. package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js → EscalationsOverview-DAjZ7JY2.js} +2 -2
  157. package/dashboard/dist/assets/{EscalationsOverview-DtGOqnP4.js.map → EscalationsOverview-DAjZ7JY2.js.map} +1 -1
  158. package/dashboard/dist/assets/{EventTable-DSHqKyX2.js → EventTable-B72DQP_v.js} +2 -2
  159. package/dashboard/dist/assets/{EventTable-DSHqKyX2.js.map → EventTable-B72DQP_v.js.map} +1 -1
  160. package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js → FilterBar-CCTaA_LH.js} +2 -2
  161. package/dashboard/dist/assets/{FilterBar-Dxd0wNSW.js.map → FilterBar-CCTaA_LH.js.map} +1 -1
  162. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +2 -0
  163. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +1 -0
  164. package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js → GraphInvokePage-CAsCgFo3.js} +2 -2
  165. package/dashboard/dist/assets/{GraphInvokePage-ChqqGkro.js.map → GraphInvokePage-CAsCgFo3.js.map} +1 -1
  166. package/dashboard/dist/assets/{HomePage-ByKesG8w.js → HomePage-DseE_iSr.js} +2 -2
  167. package/dashboard/dist/assets/{HomePage-ByKesG8w.js.map → HomePage-DseE_iSr.js.map} +1 -1
  168. package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js → ListToolbar-1zdqnjW6.js} +2 -2
  169. package/dashboard/dist/assets/{ListToolbar-Ddz_S2av.js.map → ListToolbar-1zdqnjW6.js.map} +1 -1
  170. package/dashboard/dist/assets/{McpOverview-CVe13tEv.js → McpOverview-DS_JXDW5.js} +2 -2
  171. package/dashboard/dist/assets/{McpOverview-CVe13tEv.js.map → McpOverview-DS_JXDW5.js.map} +1 -1
  172. package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js → McpQueryDetailPage-BeMUGcv3.js} +2 -2
  173. package/dashboard/dist/assets/{McpQueryDetailPage-BQYF2Mjq.js.map → McpQueryDetailPage-BeMUGcv3.js.map} +1 -1
  174. package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js → McpQueryPage-CeiLO_LR.js} +2 -2
  175. package/dashboard/dist/assets/{McpQueryPage-DZi5lm7s.js.map → McpQueryPage-CeiLO_LR.js.map} +1 -1
  176. package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js → McpRunDetailPage-DYp1uZK2.js} +2 -2
  177. package/dashboard/dist/assets/{McpRunDetailPage-DreARTE1.js.map → McpRunDetailPage-DYp1uZK2.js.map} +1 -1
  178. package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js → McpRunsPage-VeaDzcL4.js} +2 -2
  179. package/dashboard/dist/assets/{McpRunsPage-DmO0YVhT.js.map → McpRunsPage-VeaDzcL4.js.map} +1 -1
  180. package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js → OperationsPage-DK2mgaXf.js} +2 -2
  181. package/dashboard/dist/assets/{OperationsPage-DpjCO85T.js.map → OperationsPage-DK2mgaXf.js.map} +1 -1
  182. package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js → OperatorDashboard-BNjLF0f7.js} +2 -2
  183. package/dashboard/dist/assets/{OperatorDashboard-Vv_MEBkv.js.map → OperatorDashboard-BNjLF0f7.js.map} +1 -1
  184. package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js → PersonaDetailPage-IQ2fZLa6.js} +2 -2
  185. package/dashboard/dist/assets/{PersonaDetailPage-CW-2uBHY.js.map → PersonaDetailPage-IQ2fZLa6.js.map} +1 -1
  186. package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js → PersonasPage-DpGFEcU-.js} +2 -2
  187. package/dashboard/dist/assets/{PersonasPage-CO6yYQdm.js.map → PersonasPage-DpGFEcU-.js.map} +1 -1
  188. package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js → PortalPage-D07xyvG_.js} +2 -2
  189. package/dashboard/dist/assets/{PortalPage-DcNqhBlg.js.map → PortalPage-D07xyvG_.js.map} +1 -1
  190. package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js → ProcessDetailPage-t8EEYSMk.js} +2 -2
  191. package/dashboard/dist/assets/{ProcessDetailPage-BuipGZcC.js.map → ProcessDetailPage-t8EEYSMk.js.map} +1 -1
  192. package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js → ProcessesListPage-BDUXLFdb.js} +2 -2
  193. package/dashboard/dist/assets/{ProcessesListPage-D9DYntvl.js.map → ProcessesListPage-BDUXLFdb.js.map} +1 -1
  194. package/dashboard/dist/assets/ResolverForm-BwWOYv_Z.js +8 -0
  195. package/dashboard/dist/assets/ResolverForm-BwWOYv_Z.js.map +1 -0
  196. package/dashboard/dist/assets/RoleDetailPage-zMF3x2xi.js +8 -0
  197. package/dashboard/dist/assets/RoleDetailPage-zMF3x2xi.js.map +1 -0
  198. package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js → RolesPage-CEBp_PpL.js} +2 -2
  199. package/dashboard/dist/assets/{RolesPage-0QJOBSzF.js.map → RolesPage-CEBp_PpL.js.map} +1 -1
  200. package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js → RunAsSelector-CC_EHN3z.js} +2 -2
  201. package/dashboard/dist/assets/{RunAsSelector-Dh4lyyRo.js.map → RunAsSelector-CC_EHN3z.js.map} +1 -1
  202. package/dashboard/dist/assets/ScanCodesPage-DD4uU-jY.js +2 -0
  203. package/dashboard/dist/assets/ScanCodesPage-DD4uU-jY.js.map +1 -0
  204. package/dashboard/dist/assets/ScanSchemeDetailPage-CUW8gYFh.js +2 -0
  205. package/dashboard/dist/assets/ScanSchemeDetailPage-CUW8gYFh.js.map +1 -0
  206. package/dashboard/dist/assets/ScanStationPage-DpO_ESuf.js +2 -0
  207. package/dashboard/dist/assets/ScanStationPage-DpO_ESuf.js.map +1 -0
  208. package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js → StickyPagination-cNqSDm5f.js} +2 -2
  209. package/dashboard/dist/assets/{StickyPagination-BSUyf5ja.js.map → StickyPagination-cNqSDm5f.js.map} +1 -1
  210. package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js → StreamMessageDetail-C4oZqQdB.js} +2 -2
  211. package/dashboard/dist/assets/{StreamMessageDetail--tp7l2Sd.js.map → StreamMessageDetail-C4oZqQdB.js.map} +1 -1
  212. package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js → SwimlaneTimeline-BjBiV7GT.js} +2 -2
  213. package/dashboard/dist/assets/{SwimlaneTimeline-CxBZ2THh.js.map → SwimlaneTimeline-BjBiV7GT.js.map} +1 -1
  214. package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js → TaskDetailPage-pO_AnVS1.js} +2 -2
  215. package/dashboard/dist/assets/{TaskDetailPage-BJ1QrmPH.js.map → TaskDetailPage-pO_AnVS1.js.map} +1 -1
  216. package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js → TasksListPage-DKDHlWP7.js} +2 -2
  217. package/dashboard/dist/assets/{TasksListPage-5BydGWmt.js.map → TasksListPage-DKDHlWP7.js.map} +1 -1
  218. package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js → TimeAgo-D2qchUuJ.js} +2 -2
  219. package/dashboard/dist/assets/{TimeAgo-CCnz84Y4.js.map → TimeAgo-D2qchUuJ.js.map} +1 -1
  220. package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js → TimestampCell-DeswZGGo.js} +2 -2
  221. package/dashboard/dist/assets/{TimestampCell-D0ru7Lya.js.map → TimestampCell-DeswZGGo.js.map} +1 -1
  222. package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js → ToolTestPanel-DJh7PIUa.js} +2 -2
  223. package/dashboard/dist/assets/{ToolTestPanel-3Kpofmen.js.map → ToolTestPanel-DJh7PIUa.js.map} +1 -1
  224. package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js → TopicDetailPage-CsgDJ4Z4.js} +2 -2
  225. package/dashboard/dist/assets/{TopicDetailPage-BaBXD_AK.js.map → TopicDetailPage-CsgDJ4Z4.js.map} +1 -1
  226. package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js → TopicsPage-tBRZDVDN.js} +2 -2
  227. package/dashboard/dist/assets/{TopicsPage-Cnm1AAjh.js.map → TopicsPage-tBRZDVDN.js.map} +1 -1
  228. package/dashboard/dist/assets/{UserName-CXsdPiMZ.js → UserName-B-5JcDck.js} +2 -2
  229. package/dashboard/dist/assets/{UserName-CXsdPiMZ.js.map → UserName-B-5JcDck.js.map} +1 -1
  230. package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js → WorkflowExecutionPage-BPHVnhp6.js} +2 -2
  231. package/dashboard/dist/assets/{WorkflowExecutionPage-zx3AUJFd.js.map → WorkflowExecutionPage-BPHVnhp6.js.map} +1 -1
  232. package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js → WorkflowsDashboard-CxLlfZmY.js} +2 -2
  233. package/dashboard/dist/assets/{WorkflowsDashboard-DfAGK1l7.js.map → WorkflowsDashboard-CxLlfZmY.js.map} +1 -1
  234. package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js → WorkflowsOverview-C4az5rwp.js} +2 -2
  235. package/dashboard/dist/assets/{WorkflowsOverview-QIYvoa13.js.map → WorkflowsOverview-C4az5rwp.js.map} +1 -1
  236. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js → YamlWorkflowDetailPage-BmhlAUFQ.js} +8 -8
  237. package/dashboard/dist/assets/{YamlWorkflowDetailPage-DGgO3hyB.js.map → YamlWorkflowDetailPage-BmhlAUFQ.js.map} +1 -1
  238. package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js → YamlWorkflowsPage-CSbG5o2V.js} +2 -2
  239. package/dashboard/dist/assets/{YamlWorkflowsPage-CEsHm0B9.js.map → YamlWorkflowsPage-CSbG5o2V.js.map} +1 -1
  240. package/dashboard/dist/assets/{agents-v_HH3Rji.js → agents-BohEn7vw.js} +2 -2
  241. package/dashboard/dist/assets/{agents-v_HH3Rji.js.map → agents-BohEn7vw.js.map} +1 -1
  242. package/dashboard/dist/assets/{bots-bwvWYrXz.js → bots-BG2EO-Wi.js} +2 -2
  243. package/dashboard/dist/assets/{bots-bwvWYrXz.js.map → bots-BG2EO-Wi.js.map} +1 -1
  244. package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js → capabilities-CeFrBmYX.js} +2 -2
  245. package/dashboard/dist/assets/{capabilities-D4vaw_nQ.js.map → capabilities-CeFrBmYX.js.map} +1 -1
  246. package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js → controlplane-Dhvt8l8F.js} +2 -2
  247. package/dashboard/dist/assets/{controlplane-CiiZ6LJF.js.map → controlplane-Dhvt8l8F.js.map} +1 -1
  248. package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js → escalation-columns-BWMNxImp.js} +2 -2
  249. package/dashboard/dist/assets/{escalation-columns-Dv-MB3eC.js.map → escalation-columns-BWMNxImp.js.map} +1 -1
  250. package/dashboard/dist/assets/{index-CzjUgFt_.js → index-Bd_dgyfJ.js} +2 -2
  251. package/dashboard/dist/assets/{index-CzjUgFt_.js.map → index-Bd_dgyfJ.js.map} +1 -1
  252. package/dashboard/dist/assets/{index-IJmtbuLh.js → index-C8VlM2Oe.js} +2 -2
  253. package/dashboard/dist/assets/{index-IJmtbuLh.js.map → index-C8VlM2Oe.js.map} +1 -1
  254. package/dashboard/dist/assets/{index-CcuvGdvf.js → index-CiqSVDga.js} +2 -2
  255. package/dashboard/dist/assets/{index-CcuvGdvf.js.map → index-CiqSVDga.js.map} +1 -1
  256. package/dashboard/dist/assets/{index-C3WutFpT.js → index-Cl_YXEdp.js} +2 -2
  257. package/dashboard/dist/assets/{index-C3WutFpT.js.map → index-Cl_YXEdp.js.map} +1 -1
  258. package/dashboard/dist/assets/index-CtZWpy22.js +2 -0
  259. package/dashboard/dist/assets/index-CtZWpy22.js.map +1 -0
  260. package/dashboard/dist/assets/{index-CjenRVX_.js → index-D90D9y0J.js} +2 -2
  261. package/dashboard/dist/assets/{index-CjenRVX_.js.map → index-D90D9y0J.js.map} +1 -1
  262. package/dashboard/dist/assets/{index-BLB77tc8.js → index-DABkM7s-.js} +2 -2
  263. package/dashboard/dist/assets/{index-BLB77tc8.js.map → index-DABkM7s-.js.map} +1 -1
  264. package/dashboard/dist/assets/index-Dbwu51xm.js +3 -0
  265. package/dashboard/dist/assets/index-Dbwu51xm.js.map +1 -0
  266. package/dashboard/dist/assets/{index-2tzsxFat.js → index-Dc3Om6G3.js} +2 -2
  267. package/dashboard/dist/assets/{index-2tzsxFat.js.map → index-Dc3Om6G3.js.map} +1 -1
  268. package/dashboard/dist/assets/{index-D2VKBMng.js → index-Dc_zWK23.js} +2 -2
  269. package/dashboard/dist/assets/{index-D2VKBMng.js.map → index-Dc_zWK23.js.map} +1 -1
  270. package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
  271. package/dashboard/dist/assets/{index-C_ISDOWJ.js → index-Y-bdW8vo.js} +2 -2
  272. package/dashboard/dist/assets/{index-C_ISDOWJ.js.map → index-Y-bdW8vo.js.map} +1 -1
  273. package/dashboard/dist/assets/{index-C4Lce2ET.js → index-dYKgd06u.js} +3 -3
  274. package/dashboard/dist/assets/{index-C4Lce2ET.js.map → index-dYKgd06u.js.map} +1 -1
  275. package/dashboard/dist/assets/index-fUsx_gYx.js +67 -0
  276. package/dashboard/dist/assets/index-fUsx_gYx.js.map +1 -0
  277. package/dashboard/dist/assets/{knowledge-D1YP2NzS.js → knowledge-CCcTidNV.js} +2 -2
  278. package/dashboard/dist/assets/{knowledge-D1YP2NzS.js.map → knowledge-CCcTidNV.js.map} +1 -1
  279. package/dashboard/dist/assets/{mcp-Bb5psC61.js → mcp-CLA1z7Pg.js} +2 -2
  280. package/dashboard/dist/assets/{mcp-Bb5psC61.js.map → mcp-CLA1z7Pg.js.map} +1 -1
  281. package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js → mcp-query-CWG0WMAs.js} +2 -2
  282. package/dashboard/dist/assets/{mcp-query-D5jUdZwN.js.map → mcp-query-CWG0WMAs.js.map} +1 -1
  283. package/dashboard/dist/assets/metadata-display-B7X5hGxG.js +2 -0
  284. package/dashboard/dist/assets/metadata-display-B7X5hGxG.js.map +1 -0
  285. package/dashboard/dist/assets/{personas-CDndbkp4.js → personas-8jURIzx6.js} +2 -2
  286. package/dashboard/dist/assets/{personas-CDndbkp4.js.map → personas-8jURIzx6.js.map} +1 -1
  287. package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js → pipelines-hVVRAXqG.js} +2 -2
  288. package/dashboard/dist/assets/{pipelines-Dq3kNhKu.js.map → pipelines-hVVRAXqG.js.map} +1 -1
  289. package/dashboard/dist/assets/{tasks-BlpDsWCy.js → tasks-BE1O57Bf.js} +2 -2
  290. package/dashboard/dist/assets/{tasks-BlpDsWCy.js.map → tasks-BE1O57Bf.js.map} +1 -1
  291. package/dashboard/dist/assets/{topics-C0YaR9fu.js → topics-Bg96Wp1r.js} +2 -2
  292. package/dashboard/dist/assets/{topics-C0YaR9fu.js.map → topics-Bg96Wp1r.js.map} +1 -1
  293. package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js → useDebouncedValue-DmEveyEy.js} +2 -2
  294. package/dashboard/dist/assets/{useDebouncedValue-B-KC5ba3.js.map → useDebouncedValue-DmEveyEy.js.map} +1 -1
  295. package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js → useNamespace-DHgkzIuL.js} +2 -2
  296. package/dashboard/dist/assets/{useNamespace-Dkr5g2Ac.js.map → useNamespace-DHgkzIuL.js.map} +1 -1
  297. package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js → useYamlActivityEvents-RU0PvU8S.js} +2 -2
  298. package/dashboard/dist/assets/{useYamlActivityEvents-BANBOshA.js.map → useYamlActivityEvents-RU0PvU8S.js.map} +1 -1
  299. package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js → yaml-workflows-DQWE9ijc.js} +2 -2
  300. package/dashboard/dist/assets/{yaml-workflows-BLYoJfmB.js.map → yaml-workflows-DQWE9ijc.js.map} +1 -1
  301. package/dashboard/dist/index.html +2 -2
  302. package/docs/dashboard.md +1 -1
  303. package/docs/hitl/lookups.md +27 -18
  304. package/docs/hitl/x-lt-scan.md +51 -0
  305. package/docs/hitl/x-lt-validation.md +1 -1
  306. package/docs/hitl/x-lt-widget.md +1 -1
  307. package/docs/hitl-guide.md +3 -1
  308. package/docs/scan-codes.md +303 -33
  309. package/package.json +1 -1
  310. package/build/types/scan-code.d.ts +0 -317
  311. package/dashboard/dist/assets/CapabilitiesPage-BxadotXn.js +0 -2
  312. package/dashboard/dist/assets/CountdownTimer-CI_JOAvk.js +0 -2
  313. package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js +0 -8
  314. package/dashboard/dist/assets/ResolverForm-BVG8X0sS.js.map +0 -1
  315. package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js +0 -8
  316. package/dashboard/dist/assets/RoleDetailPage-KCXDqoJz.js.map +0 -1
  317. package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js +0 -2
  318. package/dashboard/dist/assets/ScanCodesPage-CUhCz-Yr.js.map +0 -1
  319. package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js +0 -2
  320. package/dashboard/dist/assets/ScanSchemeDetailPage-qzXKNqJK.js.map +0 -1
  321. package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js +0 -2
  322. package/dashboard/dist/assets/ScanStationPage-D8e8cG3t.js.map +0 -1
  323. package/dashboard/dist/assets/index-CT-FN6CW.js +0 -3
  324. package/dashboard/dist/assets/index-CT-FN6CW.js.map +0 -1
  325. package/dashboard/dist/assets/index-D6pBLZFu.js +0 -2
  326. package/dashboard/dist/assets/index-D6pBLZFu.js.map +0 -1
  327. package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
  328. package/dashboard/dist/assets/index-N71QQ3J5.js +0 -67
  329. package/dashboard/dist/assets/index-N71QQ3J5.js.map +0 -1
  330. package/dashboard/dist/assets/metadata-display-COo3mMCr.js +0 -2
  331. package/dashboard/dist/assets/metadata-display-COo3mMCr.js.map +0 -1
@@ -68,6 +68,15 @@ function isBatch(escalation) {
68
68
  return Array.isArray(escalation.metadata?.[escalation_1.ESCALATION_BATCH_KEYS.PENDING]);
69
69
  }
70
70
  const NO_ACCUMULATOR_FOR_FACET = 'No pending accumulator found for this metadata';
71
+ /** The add's item-key error, or null when the key is usable. */
72
+ function itemKeyError(itemKey) {
73
+ if (!itemKey)
74
+ return { status: 400, error: 'itemKey is required' };
75
+ if (typeof itemKey !== 'string' || itemKey.length > escalation_1.ESCALATION_ITEM_KEY_MAX_LENGTH) {
76
+ return { status: 400, error: `itemKey must be a string of at most ${escalation_1.ESCALATION_ITEM_KEY_MAX_LENGTH} characters` };
77
+ }
78
+ return null;
79
+ }
71
80
  /**
72
81
  * The container a facet names: the highest priority pending row that carries
73
82
  * the facet AND the accumulator declaration, within the given roles (null =
@@ -199,18 +208,22 @@ async function gatePayload(escalation, payload, userId) {
199
208
  async function accumulateItem(input, auth) {
200
209
  try {
201
210
  const { id, itemKey, metadata } = input;
202
- if (!itemKey)
203
- return { status: 400, error: 'itemKey is required' };
211
+ const keyError = itemKeyError(itemKey);
212
+ if (keyError)
213
+ return keyError;
204
214
  const initiator = await resolveActor(input.initiatedBy, auth);
205
215
  if ('error' in initiator)
206
216
  return initiator.error;
207
217
  const escalation = await escalationService.getEscalation(id);
208
218
  if (!escalation)
209
219
  return { status: 404, error: 'Escalation not found' };
210
- if (escalation.status === 'cancelled')
211
- return { status: 409, error: 'Escalation is cancelled' };
212
- if (escalation.status !== 'pending')
213
- return { status: 409, error: 'Escalation not available for accumulation' };
220
+ if (escalation.status === 'cancelled') {
221
+ return { status: 409, error: 'Escalation is cancelled', data: { error: 'Escalation is cancelled', outcome: 'already-cancelled' } };
222
+ }
223
+ if (escalation.status !== 'pending') {
224
+ const error = 'Escalation not available for accumulation';
225
+ return { status: 409, error, data: { error, outcome: `already-${escalation.status}` } };
226
+ }
214
227
  if (!isAccumulator(escalation))
215
228
  return { status: 400, error: 'Escalation is not an accumulator' };
216
229
  if (await (0, helpers_1.assertReadAccess)(auth.userId, escalation)) {
@@ -250,8 +263,9 @@ async function accumulateItemBySignalKey(input, auth) {
250
263
  const { signalKey, itemKey, metadata } = input;
251
264
  if (!signalKey)
252
265
  return { status: 400, error: 'signalKey is required' };
253
- if (!itemKey)
254
- return { status: 400, error: 'itemKey is required' };
266
+ const keyError = itemKeyError(itemKey);
267
+ if (keyError)
268
+ return keyError;
255
269
  const initiator = await resolveActor(input.initiatedBy, auth);
256
270
  if ('error' in initiator)
257
271
  return initiator.error;
@@ -301,8 +315,9 @@ async function accumulateItemByMetadata(input, auth) {
301
315
  const { key, value, itemKey, metadata } = input;
302
316
  if (!key || !value)
303
317
  return { status: 400, error: 'key and value are required' };
304
- if (!itemKey)
305
- return { status: 400, error: 'itemKey is required' };
318
+ const keyError = itemKeyError(itemKey);
319
+ if (keyError)
320
+ return keyError;
306
321
  const initiator = await resolveActor(input.initiatedBy, auth);
307
322
  if ('error' in initiator)
308
323
  return initiator.error;
@@ -574,21 +589,21 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
574
589
  },
575
590
  };
576
591
  case 'duplicate-item':
577
- return { status: 409, error: 'Item already held', data: { error: 'Item already held', itemKey } };
592
+ return { status: 409, error: 'Item already held', data: { error: 'Item already held', itemKey, outcome: 'duplicate-item' } };
578
593
  case 'full':
579
- return { status: 409, error: 'Accumulator is full', data: { error: 'Accumulator is full', itemKey } };
594
+ return { status: 409, error: 'Accumulator is full', data: { error: 'Accumulator is full', itemKey, outcome: 'full' } };
580
595
  case 'claimed-by-other':
581
- return { status: 409, error: 'Escalation is claimed by another user' };
596
+ return { status: 409, error: 'Escalation is claimed by another user', data: { error: 'Escalation is claimed by another user', outcome: 'claimed-by-other' } };
582
597
  case 'claim-expired':
583
- return { status: 409, error: 'Your claim has expired; re-claim this escalation to add to it' };
598
+ return { status: 409, error: 'Your claim has expired; re-claim this escalation to add to it', data: { error: 'Your claim has expired; re-claim this escalation to add to it', outcome: 'claim-expired' } };
584
599
  case 'not-found':
585
- return { status: 404, error: 'Escalation not found' };
600
+ return { status: 404, error: 'Escalation not found', data: { error: 'Escalation not found', outcome: 'not-found' } };
586
601
  case 'not-accumulator':
587
- return { status: 400, error: 'Escalation is not an accumulator' };
602
+ return { status: 400, error: 'Escalation is not an accumulator', data: { error: 'Escalation is not an accumulator', outcome: 'not-accumulator' } };
588
603
  case 'reciprocal-not-found':
589
- return { status: 404, error: 'Reciprocal escalation not found' };
604
+ return { status: 404, error: 'Reciprocal escalation not found', data: { error: 'Reciprocal escalation not found', outcome: 'reciprocal-not-found' } };
590
605
  case 'reciprocal-not-accumulator':
591
- return { status: 400, error: 'Reciprocal escalation is not an accumulator' };
606
+ return { status: 400, error: 'Reciprocal escalation is not an accumulator', data: { error: 'Reciprocal escalation is not an accumulator', outcome: 'reciprocal-not-accumulator' } };
592
607
  case 'reciprocal-duplicate':
593
608
  return { status: 409, error: 'Reciprocal escalation already holds this container', data: { error: 'Reciprocal escalation already holds this container', outcome: result.outcome } };
594
609
  case 'reciprocal-full':
@@ -596,7 +611,11 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
596
611
  case 'reciprocal-terminal':
597
612
  return { status: 409, error: 'Reciprocal escalation is no longer pending', data: { error: 'Reciprocal escalation is no longer pending', outcome: result.outcome } };
598
613
  default:
599
- return { status: 409, error: 'Escalation not available for accumulation' };
614
+ return {
615
+ status: 409,
616
+ error: 'Escalation not available for accumulation',
617
+ data: { error: 'Escalation not available for accumulation', outcome: result.outcome },
618
+ };
600
619
  }
601
620
  }
602
621
  function removeOutcomeResult(result, itemKey) {
@@ -1,15 +1,22 @@
1
1
  import { type EscalationLookupRef } from '../../types/escalation';
2
+ import type { LTEscalationRecord } from '../../types';
2
3
  import type { LTApiResult, LTApiAuth } from '../../types/sdk';
3
4
  /** The refs riding the row's envelope under the reserved key, or []. */
4
5
  export declare function readLookupRefs(envelope: string | null | undefined): EscalationLookupRef[];
6
+ /**
7
+ * When a current ref is read: now for a pending row, the moment it closed
8
+ * otherwise, so a closed row shows the edition its work was done against.
9
+ */
10
+ export declare function lookupAsOf(escalation: Pick<LTEscalationRecord, 'status' | 'resolved_at' | 'updated_at'>): string | null;
5
11
  /**
6
12
  * Resolve an escalation's versioned knowledge lookups.
7
13
  *
8
14
  * The refs on `envelope.lookups` ARE the grant: any user who may read the
9
15
  * escalation may read exactly the pinned editions it names — nothing else in
10
16
  * the knowledge store. Snapshots are immutable, so responses are served from
11
- * an in-process cache after the first read; a ref whose snapshot does not
12
- * exist answers with `missing: true` rather than failing the batch.
17
+ * an in-process cache after the first read; a current ref reads the newest
18
+ * edition (as of the close, for a closed row). A ref with no edition answers
19
+ * with `missing: true` rather than failing the batch.
13
20
  *
14
21
  * @param input.id — escalation UUID
15
22
  * @param auth — authenticated user context (must hold the escalation's role)
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.readLookupRefs = readLookupRefs;
37
+ exports.lookupAsOf = lookupAsOf;
37
38
  exports.getEscalationLookups = getEscalationLookups;
38
39
  const escalationService = __importStar(require("../../services/escalation"));
39
40
  const knowledge_1 = require("../../services/knowledge");
@@ -55,14 +56,25 @@ function readLookupRefs(envelope) {
55
56
  return [];
56
57
  }
57
58
  }
59
+ /**
60
+ * When a current ref is read: now for a pending row, the moment it closed
61
+ * otherwise, so a closed row shows the edition its work was done against.
62
+ */
63
+ function lookupAsOf(escalation) {
64
+ if (escalation.status === 'pending')
65
+ return null;
66
+ const closed = escalation.resolved_at ?? escalation.updated_at;
67
+ return closed ? new Date(closed).toISOString() : null;
68
+ }
58
69
  /**
59
70
  * Resolve an escalation's versioned knowledge lookups.
60
71
  *
61
72
  * The refs on `envelope.lookups` ARE the grant: any user who may read the
62
73
  * escalation may read exactly the pinned editions it names — nothing else in
63
74
  * the knowledge store. Snapshots are immutable, so responses are served from
64
- * an in-process cache after the first read; a ref whose snapshot does not
65
- * exist answers with `missing: true` rather than failing the batch.
75
+ * an in-process cache after the first read; a current ref reads the newest
76
+ * edition (as of the close, for a closed row). A ref with no edition answers
77
+ * with `missing: true` rather than failing the batch.
66
78
  *
67
79
  * @param input.id — escalation UUID
68
80
  * @param auth — authenticated user context (must hold the escalation's role)
@@ -81,7 +93,7 @@ async function getEscalationLookups(input, auth) {
81
93
  if (refs.length === 0) {
82
94
  return { status: 200, data: { lookups: [] } };
83
95
  }
84
- const lookups = await (0, knowledge_1.resolveLookupRefs)(refs);
96
+ const lookups = await (0, knowledge_1.resolveLookupRefs)(refs, lookupAsOf(escalation));
85
97
  return { status: 200, data: { lookups } };
86
98
  }
87
99
  catch (err) {
@@ -37,6 +37,8 @@ export declare function claimByMetadata(input: {
37
37
  metadata?: Record<string, any>;
38
38
  provisionIfAbsent?: ProvisionIfAbsent;
39
39
  restrictRoles?: string[];
40
+ /** Claims only this row, when it still matches every other condition. */
41
+ assertId?: string;
40
42
  }, auth: LTApiAuth): Promise<LTApiResult>;
41
43
  /**
42
44
  * Resolve an escalation by metadata key-value pair.
@@ -94,6 +94,9 @@ async function claimByMetadata(input, auth) {
94
94
  if (!input.key || !input.value) {
95
95
  return { status: 400, error: 'key and value are required' };
96
96
  }
97
+ if (input.assertId !== undefined && !(0, uuid_1.isUuid)(input.assertId)) {
98
+ return { status: 404, error: 'No pending escalation found for this metadata' };
99
+ }
97
100
  const resolved = await (0, helpers_1.resolveAssignee)(input.assignee, auth, input.provisionIfAbsent);
98
101
  if ('error' in resolved)
99
102
  return resolved.error;
@@ -105,6 +108,12 @@ async function claimByMetadata(input, auth) {
105
108
  // (expected queues) intersects with the scope inside the same SQL filter.
106
109
  const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
107
110
  const allowedRoles = restrictScopeRoles(writeScope.allRoles, writeScope.global, input.restrictRoles);
111
+ if (input.assertId !== undefined) {
112
+ const asserted = await escalationService.claimAssertedByMetadata(input.assertId, input.key, input.value, claimUserId, input.durationMinutes, input.metadata, allowedRoles);
113
+ if (!asserted)
114
+ return { status: 404, error: 'No pending escalation found for this metadata' };
115
+ return { status: 200, data: asserted };
116
+ }
108
117
  const result = await escalationService.claimByMetadata(input.key, input.value, claimUserId, input.durationMinutes, input.metadata, allowedRoles);
109
118
  if (!result) {
110
119
  // No rows matched. Check if candidates existed (role mismatch vs no match).
@@ -70,10 +70,13 @@ async function resolveBatchItem(input, auth) {
70
70
  const escalation = await escalationService.getEscalation(id);
71
71
  if (!escalation)
72
72
  return { status: 404, error: 'Escalation not found' };
73
- if (escalation.status === 'cancelled')
74
- return { status: 409, error: 'Escalation is cancelled' };
75
- if (escalation.status !== 'pending')
76
- return { status: 409, error: 'Escalation not available for resolution' };
73
+ if (escalation.status === 'cancelled') {
74
+ return { status: 409, error: 'Escalation is cancelled', data: { error: 'Escalation is cancelled', outcome: 'already-cancelled' } };
75
+ }
76
+ if (escalation.status !== 'pending') {
77
+ const error = 'Escalation not available for resolution';
78
+ return { status: 409, error, data: { error, outcome: `already-${escalation.status}` } };
79
+ }
77
80
  // Advisory shape gate — cheap, readable rejection. The SDK's guarded
78
81
  // statement re-checks and is the atomic arbiter (outcome 'not-batch').
79
82
  const pending = escalation.metadata?.[escalation_1.ESCALATION_BATCH_KEYS.PENDING];
@@ -228,20 +231,24 @@ function batchOutcomeResult(result, itemKey, workflowId) {
228
231
  return {
229
232
  status: 409,
230
233
  error: 'Batch item already submitted',
231
- data: { error: 'Batch item already submitted', itemKey },
234
+ data: { error: 'Batch item already submitted', itemKey, outcome: 'duplicate-item' },
232
235
  };
233
236
  case 'claimed-by-other':
234
- return { status: 409, error: 'Escalation is claimed by another user' };
237
+ return { status: 409, error: 'Escalation is claimed by another user', data: { error: 'Escalation is claimed by another user', outcome: 'claimed-by-other' } };
235
238
  case 'claim-expired':
236
- return { status: 409, error: 'Your claim has expired — re-claim this escalation to resolve it' };
239
+ return { status: 409, error: 'Your claim has expired — re-claim this escalation to resolve it', data: { error: 'Your claim has expired — re-claim this escalation to resolve it', outcome: 'claim-expired' } };
237
240
  case 'not-found':
238
- return { status: 404, error: 'Escalation not found' };
241
+ return { status: 404, error: 'Escalation not found', data: { error: 'Escalation not found', outcome: 'not-found' } };
239
242
  case 'unknown-item':
240
- return { status: 400, error: 'itemKey is not in the declared batch' };
243
+ return { status: 400, error: 'itemKey is not in the declared batch', data: { error: 'itemKey is not in the declared batch', outcome: 'unknown-item' } };
241
244
  case 'not-batch':
242
- return { status: 400, error: 'Escalation is not a batch' };
245
+ return { status: 400, error: 'Escalation is not a batch', data: { error: 'Escalation is not a batch', outcome: 'not-batch' } };
243
246
  default:
244
247
  // already-resolved / already-cancelled / already-expired
245
- return { status: 409, error: 'Escalation not available for resolution' };
248
+ return {
249
+ status: 409,
250
+ error: 'Escalation not available for resolution',
251
+ data: { error: 'Escalation not available for resolution', outcome: result.outcome },
252
+ };
246
253
  }
247
254
  }
@@ -49,6 +49,7 @@ exports.listRoleListSchemaVersions = listRoleListSchemaVersions;
49
49
  exports.deleteRole = deleteRole;
50
50
  const roleService = __importStar(require("../services/role"));
51
51
  const types_1 = require("../services/role/types");
52
+ const badge_grant_1 = require("../services/role/badge-grant");
52
53
  const facet_sql_1 = require("../services/escalation/facet-sql");
53
54
  /**
54
55
  * List all distinct role names in the system.
@@ -291,6 +292,9 @@ async function updateRole(input) {
291
292
  return { status: 400, error: 'default_pins must be [{ label, url, badge? }] with dashboard-relative urls' };
292
293
  }
293
294
  }
295
+ const grantError = (0, badge_grant_1.badgeGrantError)(input.properties?.[types_1.ROLE_PROPERTY_KEYS.BADGE_GRANT]);
296
+ if (grantError)
297
+ return { status: 400, error: grantError };
294
298
  if (input.portals != null && !isPortalList(input.portals)) {
295
299
  return {
296
300
  status: 400,
@@ -0,0 +1,10 @@
1
+ import { type ScanGrantScope, type ScanScheme } from '../../types';
2
+ export interface GrantPolicy {
3
+ ttlSeconds: number;
4
+ maxUses: number;
5
+ scope: ScanGrantScope;
6
+ /** The station role whose policy applied; absent when the scheme's did. */
7
+ role?: string;
8
+ }
9
+ /** The policy a badge scanned on this device mints under. */
10
+ export declare function stationGrantPolicy(scheme: ScanScheme, stationUserId: string, stationRole?: string): Promise<GrantPolicy>;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.stationGrantPolicy = stationGrantPolicy;
37
+ const roleService = __importStar(require("../../services/role"));
38
+ const userService = __importStar(require("../../services/user"));
39
+ const badge_grant_1 = require("../../services/role/badge-grant");
40
+ const types_1 = require("../../types");
41
+ function schemePolicy(scheme) {
42
+ return {
43
+ ttlSeconds: scheme.grant_ttl_seconds ?? 0,
44
+ maxUses: scheme.grant_max_uses ?? 0,
45
+ scope: scheme.grant_scope ?? types_1.SCAN_GRANT_SCOPES.ACTION,
46
+ };
47
+ }
48
+ /** The policy a badge scanned on this device mints under. */
49
+ async function stationGrantPolicy(scheme, stationUserId, stationRole) {
50
+ const fallback = schemePolicy(scheme);
51
+ const user = await userService.getUser(stationUserId);
52
+ const memberRoles = (user?.roles ?? []).map((r) => r.role);
53
+ const candidates = stationRole
54
+ ? memberRoles.filter((r) => r === stationRole)
55
+ : memberRoles;
56
+ const declared = [];
57
+ for (const role of candidates) {
58
+ const grant = (0, badge_grant_1.readBadgeGrant)(await roleService.getRoleProperties(role));
59
+ if (grant)
60
+ declared.push({ role, grant });
61
+ }
62
+ const distinct = new Set(declared.map((d) => JSON.stringify(d.grant)));
63
+ if (distinct.size !== 1)
64
+ return fallback;
65
+ const { role, grant } = declared[0];
66
+ return {
67
+ ttlSeconds: grant.ttl_seconds ?? fallback.ttlSeconds,
68
+ maxUses: grant.max_uses ?? fallback.maxUses,
69
+ scope: grant.scope ?? fallback.scope,
70
+ role,
71
+ };
72
+ }
@@ -38,6 +38,7 @@ const scanCodeService = __importStar(require("../../services/scan-code"));
38
38
  const escalationService = __importStar(require("../../services/escalation"));
39
39
  const types_1 = require("../../types");
40
40
  const identity_1 = require("./identity");
41
+ const grant_1 = require("./grant");
41
42
  const context_1 = require("./context");
42
43
  const locate_1 = require("./locate");
43
44
  const verbs_1 = require("./verbs");
@@ -69,19 +70,19 @@ async function executeScanChoice(input, auth) {
69
70
  data: { outcome: types_1.SCAN_OUTCOMES.UNCONFIGURED, error: 'the presented choice is no longer configured' },
70
71
  };
71
72
  }
72
- // 2. The acting grant, exchanged before anything reads or writes.
73
+ // 2. The acting grant, read (not spent) before anything reads or writes.
73
74
  let effectiveAuth = auth;
74
- let acting = false;
75
+ let grant;
75
76
  if (input.actingToken) {
76
- const resolved = await (0, identity_1.resolveActingAuth)(input.actingToken);
77
- if (!resolved.ok) {
77
+ const peeked = await (0, grant_1.peekGrant)(input.actingToken);
78
+ if (!peeked.ok) {
78
79
  return {
79
80
  status: 200,
80
- data: { outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED, notPrimed: rule.notPrimed, error: resolved.error },
81
+ data: { outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED, notPrimed: rule.notPrimed, replayable: true, error: peeked.error },
81
82
  };
82
83
  }
83
- effectiveAuth = resolved.auth;
84
- acting = true;
84
+ effectiveAuth = peeked.auth;
85
+ grant = peeked.grant;
85
86
  }
86
87
  // 3. The row anchors the target: the scheme's facet on the escalation the
87
88
  // screen presented. A missing binding is loud misconfiguration.
@@ -100,7 +101,8 @@ async function executeScanChoice(input, auth) {
100
101
  scannedAt: new Date().toISOString(),
101
102
  auth: effectiveAuth,
102
103
  stationAuth: auth,
103
- acting,
104
+ acting: !!grant,
105
+ grant,
104
106
  };
105
107
  // 4. The identity gate, per the choice.
106
108
  if (choice.requireActingIdentity && !(await (0, identity_1.actingIdentitySatisfied)(step, ctx))) {
@@ -116,8 +118,12 @@ async function executeScanChoice(input, auth) {
116
118
  }
117
119
  // 6. Dispatch through the same atomic executors a direct scan uses.
118
120
  const synthesized = { query: step.query, verb: choice.verb, params: choice.params };
119
- const result = await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, presented);
120
- return decorate(result, ctx, input);
121
+ const result = decorate(await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, presented), ctx, input);
122
+ // 7. Settle the badge: refund a spend whose act did not land
123
+ const acting = await (0, grant_1.settleGrant)(ctx, result);
124
+ if (acting && result.data)
125
+ result.data = { ...result.data, acting };
126
+ return result;
121
127
  }
122
128
  catch (err) {
123
129
  return { status: 500, error: err.message };
@@ -1,11 +1,34 @@
1
1
  import * as scanCodeService from '../../services/scan-code';
2
2
  import { type LTEscalationRecord, type ParsedScanCode, type ScanExecuteResponse, type ScanRule, type ScanScheme, type ScanStep } from '../../types';
3
3
  import type { LTApiAuth, LTApiResult } from '../../types/sdk';
4
+ /** The held subject, re-derived from the client's pointer on this request. */
5
+ export interface HeldSubject {
6
+ row: LTEscalationRecord;
7
+ parsed: ParsedScanCode;
8
+ scheme: ScanScheme;
9
+ code: string;
10
+ }
11
+ /** The acting grant riding the request, and whether this request spent it. */
12
+ export interface GrantLedger {
13
+ token: string;
14
+ /** Before this request touched it. */
15
+ peeked: {
16
+ remaining: number | null;
17
+ bound: boolean;
18
+ };
19
+ /** Set once this request spends a use; null until then. */
20
+ spent: {
21
+ remaining: number | null;
22
+ bound: boolean;
23
+ } | null;
24
+ }
4
25
  /** Everything a step executor needs about the scan that reached it. */
5
26
  export interface StepContext {
6
27
  scheme: ScanScheme;
7
28
  rule: ScanRule;
8
29
  parsed: ParsedScanCode;
30
+ /** The code as the station scanned it; absent when a choice re-derived the target. */
31
+ rawCode?: string;
9
32
  scannedAt: string;
10
33
  /** The effective actor — the acting (badged) user when a grant rode the request. */
11
34
  auth: LTApiAuth;
@@ -13,9 +36,17 @@ export interface StepContext {
13
36
  stationAuth: LTApiAuth;
14
37
  /** True when `auth` came from an acting-identity grant. */
15
38
  acting: boolean;
39
+ /** The grant behind `acting`; spent only when an act lands. */
40
+ grant?: GrantLedger;
41
+ /** The subject the station holds, when its pointer still checks out. */
42
+ subject?: HeldSubject;
43
+ /** The station sent a subject pointer that no longer checks out. */
44
+ subjectStale?: boolean;
16
45
  }
17
46
  export declare function targetFilter(step: ScanStep, ctx: StepContext): Record<string, any>;
18
47
  export declare function templateContext(ctx: StepContext): scanCodeService.ScanTemplateContext;
48
+ /** The `{subject.x}` bag: the held row's metadata plus its id. */
49
+ export declare function subjectBag(row: LTEscalationRecord): Record<string, unknown>;
19
50
  /**
20
51
  * The metadata of the acting user's single live claim, or undefined when
21
52
  * they hold none or more than one. One scoped list query, read before the
@@ -34,4 +65,17 @@ export declare function interpolatedMetadata(step: ScanStep, ctx: StepContext, t
34
65
  export declare function executed(escalation: LTEscalationRecord | Record<string, any> | undefined, step: Pick<ScanStep, 'verb'>): LTApiResult<ScanExecuteResponse>;
35
66
  export declare function forbidden(error?: string): LTApiResult<ScanExecuteResponse>;
36
67
  export declare function conflict(error?: string): LTApiResult<ScanExecuteResponse>;
37
- export declare function notPrimed(ctx: StepContext): LTApiResult<ScanExecuteResponse>;
68
+ export declare function notPrimed(ctx: StepContext, error?: string): LTApiResult<ScanExecuteResponse>;
69
+ /** Nothing was written; say why, and name what the step expected. */
70
+ export declare function refused(markdown: string, extra?: Partial<ScanExecuteResponse>): LTApiResult<ScanExecuteResponse>;
71
+ /**
72
+ * Interpolates a step's params, or falls through when a `{claim.…}` or
73
+ * `{item.…}` token has nothing to read: a literal token never reaches a row.
74
+ */
75
+ export declare function templated<T>(step: ScanStep, ctx: StepContext, render: (tpl: scanCodeService.ScanTemplateContext) => T, item?: LTEscalationRecord): Promise<T | null>;
76
+ /**
77
+ * Attach the step's `done` copy to a write that landed. `tpl` carries the
78
+ * bags the copy may read (the container a subject step located, a fill's
79
+ * batch); an unreadable token renders empty rather than failing the act.
80
+ */
81
+ export declare function withDone(result: LTApiResult<ScanExecuteResponse>, step: ScanStep, tpl: scanCodeService.ScanTemplateContext): LTApiResult<ScanExecuteResponse>;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.targetFilter = targetFilter;
37
37
  exports.templateContext = templateContext;
38
+ exports.subjectBag = subjectBag;
38
39
  exports.liveClaimMetadata = liveClaimMetadata;
39
40
  exports.stepTemplate = stepTemplate;
40
41
  exports.provenance = provenance;
@@ -43,6 +44,9 @@ exports.executed = executed;
43
44
  exports.forbidden = forbidden;
44
45
  exports.conflict = conflict;
45
46
  exports.notPrimed = notPrimed;
47
+ exports.refused = refused;
48
+ exports.templated = templated;
49
+ exports.withDone = withDone;
46
50
  const scanCodeService = __importStar(require("../../services/scan-code"));
47
51
  const escalationService = __importStar(require("../../services/escalation"));
48
52
  const types_1 = require("../../types");
@@ -50,7 +54,17 @@ function targetFilter(step, ctx) {
50
54
  return { [ctx.scheme.target_facet]: ctx.parsed.target, ...(step.query?.facets ?? {}) };
51
55
  }
52
56
  function templateContext(ctx) {
53
- return { target: ctx.parsed.target, category: ctx.parsed.category, scannedAt: ctx.scannedAt };
57
+ return {
58
+ target: ctx.parsed.target,
59
+ category: ctx.parsed.category,
60
+ scannedAt: ctx.scannedAt,
61
+ code: ctx.parsed.raw ?? ctx.parsed.target,
62
+ ...(ctx.subject ? { subject: subjectBag(ctx.subject.row) } : {}),
63
+ };
64
+ }
65
+ /** The `{subject.x}` bag: the held row's metadata plus its id. */
66
+ function subjectBag(row) {
67
+ return { ...(row.metadata ?? {}), id: row.id };
54
68
  }
55
69
  /**
56
70
  * The metadata of the acting user's single live claim, or undefined when
@@ -102,13 +116,47 @@ function forbidden(error) {
102
116
  function conflict(error) {
103
117
  return { status: 200, data: { outcome: types_1.SCAN_OUTCOMES.CONFLICT, error } };
104
118
  }
105
- function notPrimed(ctx) {
119
+ function notPrimed(ctx, error) {
106
120
  return {
107
121
  status: 200,
108
122
  data: {
109
123
  outcome: types_1.SCAN_OUTCOMES.NOT_PRIMED,
110
124
  notPrimed: ctx.rule.notPrimed,
111
- error: 'an acting identity is required — scan your badge',
125
+ replayable: true,
126
+ error: error ?? 'an acting identity is required — scan your badge',
112
127
  },
113
128
  };
114
129
  }
130
+ /** Nothing was written; say why, and name what the step expected. */
131
+ function refused(markdown, extra = {}) {
132
+ return {
133
+ status: 200,
134
+ data: { outcome: types_1.SCAN_OUTCOMES.REFUSED, refusal: { markdown }, error: markdown, ...extra },
135
+ };
136
+ }
137
+ /**
138
+ * Interpolates a step's params, or falls through when a `{claim.…}` or
139
+ * `{item.…}` token has nothing to read: a literal token never reaches a row.
140
+ */
141
+ async function templated(step, ctx, render, item) {
142
+ const tpl = await stepTemplate(step, ctx, item);
143
+ try {
144
+ return render(tpl);
145
+ }
146
+ catch (err) {
147
+ if (err instanceof scanCodeService.ScanTemplateError)
148
+ return null;
149
+ throw err;
150
+ }
151
+ }
152
+ /**
153
+ * Attach the step's `done` copy to a write that landed. `tpl` carries the
154
+ * bags the copy may read (the container a subject step located, a fill's
155
+ * batch); an unreadable token renders empty rather than failing the act.
156
+ */
157
+ function withDone(result, step, tpl) {
158
+ const data = result.data;
159
+ if (!step.done || !data || data.outcome !== types_1.SCAN_OUTCOMES.EXECUTED || data.already || data.done)
160
+ return result;
161
+ return { ...result, data: { ...data, done: { markdown: scanCodeService.renderScanCopy(step.done.markdown, tpl) } } };
162
+ }