@hotmeshio/long-tail 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (356) hide show
  1. package/build/api/escalations/accumulate.d.ts +10 -1
  2. package/build/api/escalations/accumulate.js +121 -34
  3. package/build/api/escalations/metadata.d.ts +5 -0
  4. package/build/api/escalations/metadata.js +6 -2
  5. package/build/api/escalations/resolve-batch.js +18 -11
  6. package/build/api/roles.js +4 -0
  7. package/build/api/scan-codes/badge-policy.d.ts +10 -0
  8. package/build/api/scan-codes/badge-policy.js +72 -0
  9. package/build/api/scan-codes/choice.js +18 -11
  10. package/build/api/scan-codes/context.d.ts +45 -1
  11. package/build/api/scan-codes/context.js +51 -3
  12. package/build/api/scan-codes/execute.js +73 -35
  13. package/build/api/scan-codes/grant.d.ts +27 -0
  14. package/build/api/scan-codes/grant.js +67 -0
  15. package/build/api/scan-codes/hold.d.ts +10 -0
  16. package/build/api/scan-codes/hold.js +98 -0
  17. package/build/api/scan-codes/identity.d.ts +5 -2
  18. package/build/api/scan-codes/identity.js +26 -8
  19. package/build/api/scan-codes/subject.d.ts +15 -0
  20. package/build/api/scan-codes/subject.js +68 -0
  21. package/build/api/scan-codes/verb-accumulate.d.ts +24 -0
  22. package/build/api/scan-codes/verb-accumulate.js +147 -0
  23. package/build/api/scan-codes/verb-fill.d.ts +6 -0
  24. package/build/api/scan-codes/verb-fill.js +152 -0
  25. package/build/api/scan-codes/verbs-subject.d.ts +14 -0
  26. package/build/api/scan-codes/verbs-subject.js +270 -0
  27. package/build/api/scan-codes/verbs.d.ts +7 -22
  28. package/build/api/scan-codes/verbs.js +35 -114
  29. package/build/api/workflows/invocation.d.ts +8 -4
  30. package/build/api/workflows/invocation.js +26 -9
  31. package/build/index.d.ts +1 -0
  32. package/build/index.js +8 -2
  33. package/build/lib/cli/commands/workflows.js +9 -4
  34. package/build/lib/db/schemas/037_scan_gtin_and_subject_grants.sql +27 -0
  35. package/build/routes/escalations/accumulate.js +13 -6
  36. package/build/routes/escalations/acting.d.ts +5 -0
  37. package/build/routes/escalations/acting.js +8 -1
  38. package/build/routes/scan-codes.js +3 -0
  39. package/build/sdk/index.d.ts +3 -0
  40. package/build/services/escalation/crud.d.ts +2 -2
  41. package/build/services/escalation/crud.js +4 -2
  42. package/build/services/escalation/facet-sql.js +8 -0
  43. package/build/services/escalation/sql.d.ts +4 -2
  44. package/build/services/escalation/sql.js +10 -2
  45. package/build/services/export/index.d.ts +8 -3
  46. package/build/services/export/index.js +15 -21
  47. package/build/services/iam/acting-identity.d.ts +29 -4
  48. package/build/services/iam/acting-identity.js +60 -17
  49. package/build/services/iam/ephemeral.d.ts +21 -0
  50. package/build/services/iam/ephemeral.js +32 -1
  51. package/build/services/iam/sql.d.ts +10 -0
  52. package/build/services/iam/sql.js +32 -3
  53. package/build/services/pipelines/events.js +2 -1
  54. package/build/services/pipelines/execution-builder.js +2 -1
  55. package/build/services/pipelines/queries.js +2 -1
  56. package/build/services/role/badge-grant.d.ts +5 -0
  57. package/build/services/role/badge-grant.js +36 -0
  58. package/build/services/role/seed.js +5 -0
  59. package/build/services/role/types.d.ts +14 -0
  60. package/build/services/role/types.js +5 -0
  61. package/build/services/scan-code/index.d.ts +3 -2
  62. package/build/services/scan-code/index.js +7 -1
  63. package/build/services/scan-code/parse.d.ts +23 -20
  64. package/build/services/scan-code/parse.js +45 -90
  65. package/build/services/scan-code/read.js +1 -0
  66. package/build/services/scan-code/sql.d.ts +3 -3
  67. package/build/services/scan-code/sql.js +11 -8
  68. package/build/services/scan-code/validate-subject.d.ts +7 -0
  69. package/build/services/scan-code/validate-subject.js +158 -0
  70. package/build/services/scan-code/validate.d.ts +7 -0
  71. package/build/services/scan-code/validate.js +111 -16
  72. package/build/services/scan-code/write.d.ts +1 -0
  73. package/build/services/scan-code/write.js +9 -3
  74. package/build/services/workflow-state.d.ts +21 -0
  75. package/build/services/workflow-state.js +39 -0
  76. package/build/shared/form-validation/field-validator.js +4 -0
  77. package/build/shared/form-validation/index.d.ts +1 -0
  78. package/build/shared/form-validation/index.js +1 -0
  79. package/build/shared/form-validation/x-lt-scan.d.ts +52 -0
  80. package/build/shared/form-validation/x-lt-scan.js +166 -0
  81. package/build/shared/scan-code/gtin.d.ts +5 -0
  82. package/build/shared/scan-code/gtin.js +25 -0
  83. package/build/shared/scan-code/index.d.ts +2 -0
  84. package/build/shared/scan-code/index.js +10 -0
  85. package/build/shared/scan-code/parse.d.ts +46 -0
  86. package/build/shared/scan-code/parse.js +133 -0
  87. package/build/shared/workflow-state.d.ts +17 -0
  88. package/build/shared/workflow-state.js +29 -0
  89. package/build/system/mcp-servers/admin/escalations.js +8 -4
  90. package/build/system/mcp-servers/admin/scan-codes.js +10 -4
  91. package/build/system/mcp-servers/admin/schemas.d.ts +792 -23
  92. package/build/system/mcp-servers/admin/schemas.js +61 -4
  93. package/build/system/mcp-servers/admin/workflows.js +20 -31
  94. package/build/system/mcp-servers/human-queue-schemas.d.ts +6 -6
  95. package/build/system/seed/tool-manifests-admin.d.ts +94 -0
  96. package/build/system/seed/tool-manifests-admin.js +3 -3
  97. package/build/tsconfig.tsbuildinfo +1 -1
  98. package/build/types/escalation.d.ts +2 -0
  99. package/build/types/escalation.js +3 -1
  100. package/build/types/facets.d.ts +14 -0
  101. package/build/types/index.d.ts +3 -3
  102. package/build/types/index.js +8 -1
  103. package/build/types/scan-code/constants.d.ts +182 -0
  104. package/build/types/{scan-code.js → scan-code/constants.js} +62 -12
  105. package/build/types/scan-code/index.d.ts +3 -0
  106. package/build/types/scan-code/index.js +17 -0
  107. package/build/types/scan-code/response.d.ts +140 -0
  108. package/build/types/scan-code/response.js +2 -0
  109. package/build/types/scan-code/rule.d.ts +199 -0
  110. package/build/types/scan-code/rule.js +2 -0
  111. package/build/types/startup.d.ts +3 -1
  112. package/dashboard/dist/assets/{AdminDashboard-Covdam48.js → AdminDashboard-DBW12qQt.js} +2 -2
  113. package/dashboard/dist/assets/{AdminDashboard-Covdam48.js.map → AdminDashboard-DBW12qQt.js.map} +1 -1
  114. package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js → AgentConfigPage-CmHv8U9M.js} +2 -2
  115. package/dashboard/dist/assets/{AgentConfigPage-CE1k6J5r.js.map → AgentConfigPage-CmHv8U9M.js.map} +1 -1
  116. package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js → AgentDetailPage-D1scIbz-.js} +3 -3
  117. package/dashboard/dist/assets/{AgentDetailPage-CWJZIZP1.js.map → AgentDetailPage-D1scIbz-.js.map} +1 -1
  118. package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js → AgentsPage-BA_ai9HJ.js} +2 -2
  119. package/dashboard/dist/assets/{AgentsPage---Dg5ufF.js.map → AgentsPage-BA_ai9HJ.js.map} +1 -1
  120. package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js +2 -0
  121. package/dashboard/dist/assets/AvailableEscalationsPage-C2_5aEFW.js.map +1 -0
  122. package/dashboard/dist/assets/{BotPicker-D3drO3-T.js → BotPicker-BZo4Kp4a.js} +2 -2
  123. package/dashboard/dist/assets/{BotPicker-D3drO3-T.js.map → BotPicker-BZo4Kp4a.js.map} +1 -1
  124. package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js → BulkAssignModal-BFhyxY2T.js} +2 -2
  125. package/dashboard/dist/assets/{BulkAssignModal-BOAWsViq.js.map → BulkAssignModal-BFhyxY2T.js.map} +1 -1
  126. package/dashboard/dist/assets/CapabilitiesPage-CvOX6vAc.js +2 -0
  127. package/dashboard/dist/assets/{CapabilitiesPage-RGgD3YZO.js.map → CapabilitiesPage-CvOX6vAc.js.map} +1 -1
  128. package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js → CollapsibleSection-GCJsV9Oq.js} +2 -2
  129. package/dashboard/dist/assets/{CollapsibleSection-DNkZn87n.js.map → CollapsibleSection-GCJsV9Oq.js.map} +1 -1
  130. package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js → ConfirmDeleteModal-CAgYLcef.js} +2 -2
  131. package/dashboard/dist/assets/{ConfirmDeleteModal-BqzOwhPr.js.map → ConfirmDeleteModal-CAgYLcef.js.map} +1 -1
  132. package/dashboard/dist/assets/CountdownTimer-Dik2z0M_.js +2 -0
  133. package/dashboard/dist/assets/{CountdownTimer-BaexQMK6.js.map → CountdownTimer-Dik2z0M_.js.map} +1 -1
  134. package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js → CredentialsPage-twd2xCOW.js} +2 -2
  135. package/dashboard/dist/assets/{CredentialsPage-D7abp0aS.js.map → CredentialsPage-twd2xCOW.js.map} +1 -1
  136. package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js → CronLabel-DdnIuudX.js} +2 -2
  137. package/dashboard/dist/assets/{CronLabel-DZiWmTwJ.js.map → CronLabel-DdnIuudX.js.map} +1 -1
  138. package/dashboard/dist/assets/{DropZone-f1o-GLM8.js → DropZone-B1Tdfddc.js} +2 -2
  139. package/dashboard/dist/assets/{DropZone-f1o-GLM8.js.map → DropZone-B1Tdfddc.js.map} +1 -1
  140. package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js → ElapsedCell-DCctVv5R.js} +2 -2
  141. package/dashboard/dist/assets/{ElapsedCell-BdGO_w4v.js.map → ElapsedCell-DCctVv5R.js.map} +1 -1
  142. package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js → EntityTimelinePanel-CMnskyWv.js} +2 -2
  143. package/dashboard/dist/assets/{EntityTimelinePanel-DIDcF5Yu.js.map → EntityTimelinePanel-CMnskyWv.js.map} +1 -1
  144. package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js → EscalationListSchemaPage-VfCn6WDb.js} +3 -3
  145. package/dashboard/dist/assets/{EscalationListSchemaPage-C28rn9XC.js.map → EscalationListSchemaPage-VfCn6WDb.js.map} +1 -1
  146. package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js → EscalationListView-CGQZxcC-.js} +2 -2
  147. package/dashboard/dist/assets/{EscalationListView-CkBnkpDJ.js.map → EscalationListView-CGQZxcC-.js.map} +1 -1
  148. package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js +9 -0
  149. package/dashboard/dist/assets/EscalationSchemaPage-BX0tx-PM.js.map +1 -0
  150. package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js +2 -0
  151. package/dashboard/dist/assets/EscalationTimeline-DKoSM56J.js.map +1 -0
  152. package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js → EscalationTitleSelect-DWGLBOmS.js} +2 -2
  153. package/dashboard/dist/assets/{EscalationTitleSelect-CzKfavri.js.map → EscalationTitleSelect-DWGLBOmS.js.map} +1 -1
  154. package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js → EscalationsOverview-C2XoguaA.js} +2 -2
  155. package/dashboard/dist/assets/{EscalationsOverview-Tdu3Yx2c.js.map → EscalationsOverview-C2XoguaA.js.map} +1 -1
  156. package/dashboard/dist/assets/{EventTable-DiIxOJwO.js → EventTable-CBUWq7--.js} +2 -2
  157. package/dashboard/dist/assets/{EventTable-DiIxOJwO.js.map → EventTable-CBUWq7--.js.map} +1 -1
  158. package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js → FilterBar-8IdbleZ9.js} +2 -2
  159. package/dashboard/dist/assets/{FilterBar-CvMBCVIo.js.map → FilterBar-8IdbleZ9.js.map} +1 -1
  160. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js +2 -0
  161. package/dashboard/dist/assets/GrantScopeField-BzWGzBfA.js.map +1 -0
  162. package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js → GraphInvokePage-CUvoPzsW.js} +2 -2
  163. package/dashboard/dist/assets/{GraphInvokePage-DO-yyhi6.js.map → GraphInvokePage-CUvoPzsW.js.map} +1 -1
  164. package/dashboard/dist/assets/{HomePage-DSS3eHR2.js → HomePage-BP7v9GLJ.js} +2 -2
  165. package/dashboard/dist/assets/{HomePage-DSS3eHR2.js.map → HomePage-BP7v9GLJ.js.map} +1 -1
  166. package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js → ListToolbar-Cnacuwoy.js} +2 -2
  167. package/dashboard/dist/assets/{ListToolbar-C3-Tqqub.js.map → ListToolbar-Cnacuwoy.js.map} +1 -1
  168. package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js → McpOverview-C2JoNoDA.js} +2 -2
  169. package/dashboard/dist/assets/{McpOverview-DEJmsdVi.js.map → McpOverview-C2JoNoDA.js.map} +1 -1
  170. package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js +5 -0
  171. package/dashboard/dist/assets/McpQueryDetailPage-C_nih0w-.js.map +1 -0
  172. package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js → McpQueryPage-U_wNXow2.js} +2 -2
  173. package/dashboard/dist/assets/{McpQueryPage-BBcG_UuU.js.map → McpQueryPage-U_wNXow2.js.map} +1 -1
  174. package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js → McpRunDetailPage-DtKoJq6J.js} +2 -2
  175. package/dashboard/dist/assets/{McpRunDetailPage-C6xw0kBg.js.map → McpRunDetailPage-DtKoJq6J.js.map} +1 -1
  176. package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js → McpRunsPage-CnYtfGhf.js} +2 -2
  177. package/dashboard/dist/assets/{McpRunsPage-CRQqrF4Q.js.map → McpRunsPage-CnYtfGhf.js.map} +1 -1
  178. package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js → NamespacePill-DwM5pNA4.js} +2 -2
  179. package/dashboard/dist/assets/{NamespacePill-DADRJOUl.js.map → NamespacePill-DwM5pNA4.js.map} +1 -1
  180. package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js → OperationsPage-C7hupIer.js} +2 -2
  181. package/dashboard/dist/assets/{OperationsPage-Dlfwzf-0.js.map → OperationsPage-C7hupIer.js.map} +1 -1
  182. package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js → OperatorDashboard-fVuLn2D5.js} +2 -2
  183. package/dashboard/dist/assets/{OperatorDashboard-DoiDGZ9R.js.map → OperatorDashboard-fVuLn2D5.js.map} +1 -1
  184. package/dashboard/dist/assets/{PageHeader-Csq434-v.js → PageHeader-CMd3f4bz.js} +2 -2
  185. package/dashboard/dist/assets/{PageHeader-Csq434-v.js.map → PageHeader-CMd3f4bz.js.map} +1 -1
  186. package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js → PageHeaderWithStats-DHj8Mqox.js} +2 -2
  187. package/dashboard/dist/assets/{PageHeaderWithStats-CSnk1p5A.js.map → PageHeaderWithStats-DHj8Mqox.js.map} +1 -1
  188. package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js → PersonaDetailPage-C-4o8lPw.js} +2 -2
  189. package/dashboard/dist/assets/{PersonaDetailPage-BzbA4Prr.js.map → PersonaDetailPage-C-4o8lPw.js.map} +1 -1
  190. package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js → PersonasPage-BL1FwLmv.js} +2 -2
  191. package/dashboard/dist/assets/{PersonasPage-B36yn4hU.js.map → PersonasPage-BL1FwLmv.js.map} +1 -1
  192. package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js → PortalPage-tJG5sgb1.js} +2 -2
  193. package/dashboard/dist/assets/{PortalPage-BkD4YfDf.js.map → PortalPage-tJG5sgb1.js.map} +1 -1
  194. package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js → ProcessDetailPage-Dz_jY4Yt.js} +2 -2
  195. package/dashboard/dist/assets/{ProcessDetailPage-BT0eiBWY.js.map → ProcessDetailPage-Dz_jY4Yt.js.map} +1 -1
  196. package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js → ProcessesListPage-Cbn9cter.js} +2 -2
  197. package/dashboard/dist/assets/{ProcessesListPage-BEqeeNae.js.map → ProcessesListPage-Cbn9cter.js.map} +1 -1
  198. package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js +8 -0
  199. package/dashboard/dist/assets/ResolverForm-Bk8iXQ6-.js.map +1 -0
  200. package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js +8 -0
  201. package/dashboard/dist/assets/RoleDetailPage-owPi6gI9.js.map +1 -0
  202. package/dashboard/dist/assets/{RolePill-BafrASDX.js → RolePill-Di2CAHuD.js} +2 -2
  203. package/dashboard/dist/assets/{RolePill-BafrASDX.js.map → RolePill-Di2CAHuD.js.map} +1 -1
  204. package/dashboard/dist/assets/{RolesPage-80quJU5-.js → RolesPage-NwmMvZFa.js} +2 -2
  205. package/dashboard/dist/assets/{RolesPage-80quJU5-.js.map → RolesPage-NwmMvZFa.js.map} +1 -1
  206. package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js → RunAsSelector-tgEooTyU.js} +2 -2
  207. package/dashboard/dist/assets/{RunAsSelector-BoePhWVD.js.map → RunAsSelector-tgEooTyU.js.map} +1 -1
  208. package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js +2 -0
  209. package/dashboard/dist/assets/ScanCodesPage-CUv_8ic6.js.map +1 -0
  210. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js +2 -0
  211. package/dashboard/dist/assets/ScanSchemeDetailPage-YHqbu7oK.js.map +1 -0
  212. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js +2 -0
  213. package/dashboard/dist/assets/ScanStationPage-B275l6r_.js.map +1 -0
  214. package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js → ScopeBadge-CSItPVOH.js} +2 -2
  215. package/dashboard/dist/assets/{ScopeBadge-b6MIBiYD.js.map → ScopeBadge-CSItPVOH.js.map} +1 -1
  216. package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js → StickyPagination-CsTI_gvJ.js} +2 -2
  217. package/dashboard/dist/assets/{StickyPagination-9ITrei_d.js.map → StickyPagination-CsTI_gvJ.js.map} +1 -1
  218. package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js → StreamMessageDetail-auRlvjTh.js} +2 -2
  219. package/dashboard/dist/assets/{StreamMessageDetail-BkYvEHFY.js.map → StreamMessageDetail-auRlvjTh.js.map} +1 -1
  220. package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js → SwimlaneTimeline-BLoVHYAd.js} +2 -2
  221. package/dashboard/dist/assets/{SwimlaneTimeline-B1rotFix.js.map → SwimlaneTimeline-BLoVHYAd.js.map} +1 -1
  222. package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js → TagInput-CAgdLN_b.js} +2 -2
  223. package/dashboard/dist/assets/{TagInput-ZrIIrEUP.js.map → TagInput-CAgdLN_b.js.map} +1 -1
  224. package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js → TaskDetailPage-BPsZ1bK_.js} +2 -2
  225. package/dashboard/dist/assets/{TaskDetailPage-zhn_U_eC.js.map → TaskDetailPage-BPsZ1bK_.js.map} +1 -1
  226. package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js → TaskQueuePill-h0oorVMe.js} +2 -2
  227. package/dashboard/dist/assets/{TaskQueuePill-DkQ1uc6y.js.map → TaskQueuePill-h0oorVMe.js.map} +1 -1
  228. package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js → TasksListPage-BNGM74yT.js} +2 -2
  229. package/dashboard/dist/assets/{TasksListPage-CNbNeagx.js.map → TasksListPage-BNGM74yT.js.map} +1 -1
  230. package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js → TimeAgo-BnAHXGK7.js} +2 -2
  231. package/dashboard/dist/assets/{TimeAgo-0YVMBwls.js.map → TimeAgo-BnAHXGK7.js.map} +1 -1
  232. package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js → TimestampCell-J4yae6mc.js} +2 -2
  233. package/dashboard/dist/assets/{TimestampCell-DB7r3np8.js.map → TimestampCell-J4yae6mc.js.map} +1 -1
  234. package/dashboard/dist/assets/{ToolPill-Baxm02L6.js → ToolPill-CQCsVdzD.js} +2 -2
  235. package/dashboard/dist/assets/{ToolPill-Baxm02L6.js.map → ToolPill-CQCsVdzD.js.map} +1 -1
  236. package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js → ToolTestPanel-BdzzgXDu.js} +2 -2
  237. package/dashboard/dist/assets/{ToolTestPanel-BLfA02wv.js.map → ToolTestPanel-BdzzgXDu.js.map} +1 -1
  238. package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js → TopicDetailPage-DJKg8lb7.js} +4 -4
  239. package/dashboard/dist/assets/{TopicDetailPage-eAqPKShq.js.map → TopicDetailPage-DJKg8lb7.js.map} +1 -1
  240. package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js → TopicsPage-DQV0WxG6.js} +2 -2
  241. package/dashboard/dist/assets/{TopicsPage-BNNWD-zl.js.map → TopicsPage-DQV0WxG6.js.map} +1 -1
  242. package/dashboard/dist/assets/{UserName-Pw46tO_k.js → UserName-Ct09nGh5.js} +2 -2
  243. package/dashboard/dist/assets/{UserName-Pw46tO_k.js.map → UserName-Ct09nGh5.js.map} +1 -1
  244. package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js → WorkflowExecutionPage-B5WJOsee.js} +2 -2
  245. package/dashboard/dist/assets/{WorkflowExecutionPage-DvA51lT3.js.map → WorkflowExecutionPage-B5WJOsee.js.map} +1 -1
  246. package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js → WorkflowPill-Dg7BDTyM.js} +2 -2
  247. package/dashboard/dist/assets/{WorkflowPill-ZepbO_ny.js.map → WorkflowPill-Dg7BDTyM.js.map} +1 -1
  248. package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js → WorkflowsDashboard-Hc87TRgD.js} +2 -2
  249. package/dashboard/dist/assets/{WorkflowsDashboard-DFDTwnhn.js.map → WorkflowsDashboard-Hc87TRgD.js.map} +1 -1
  250. package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js → WorkflowsOverview-CJQbyOj-.js} +2 -2
  251. package/dashboard/dist/assets/{WorkflowsOverview-5i2Tcy-p.js.map → WorkflowsOverview-CJQbyOj-.js.map} +1 -1
  252. package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js → YamlWorkflowDetailPage-BMeED677.js} +8 -8
  253. package/dashboard/dist/assets/{YamlWorkflowDetailPage-p4VEYZS0.js.map → YamlWorkflowDetailPage-BMeED677.js.map} +1 -1
  254. package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js → YamlWorkflowsPage-BMMg0Id6.js} +2 -2
  255. package/dashboard/dist/assets/{YamlWorkflowsPage-Cq-hMVxl.js.map → YamlWorkflowsPage-BMMg0Id6.js.map} +1 -1
  256. package/dashboard/dist/assets/{agents-EyBPJMYa.js → agents-CdFkgFvg.js} +2 -2
  257. package/dashboard/dist/assets/{agents-EyBPJMYa.js.map → agents-CdFkgFvg.js.map} +1 -1
  258. package/dashboard/dist/assets/{bots-DX6jjqtF.js → bots-Mj3LHWWg.js} +2 -2
  259. package/dashboard/dist/assets/{bots-DX6jjqtF.js.map → bots-Mj3LHWWg.js.map} +1 -1
  260. package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js → capabilities-Dw1ObK2-.js} +2 -2
  261. package/dashboard/dist/assets/{capabilities-ZdLv9xBQ.js.map → capabilities-Dw1ObK2-.js.map} +1 -1
  262. package/dashboard/dist/assets/{controlplane-CpvZaJuw.js → controlplane-DcNE1APv.js} +2 -2
  263. package/dashboard/dist/assets/{controlplane-CpvZaJuw.js.map → controlplane-DcNE1APv.js.map} +1 -1
  264. package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js → escalation-columns-D364Trpy.js} +2 -2
  265. package/dashboard/dist/assets/{escalation-columns-Mvsze5eV.js.map → escalation-columns-D364Trpy.js.map} +1 -1
  266. package/dashboard/dist/assets/{index-Cn8uJsd7.js → index-B3veJ698.js} +2 -2
  267. package/dashboard/dist/assets/{index-Cn8uJsd7.js.map → index-B3veJ698.js.map} +1 -1
  268. package/dashboard/dist/assets/index-BQeHJHYN.js +67 -0
  269. package/dashboard/dist/assets/index-BQeHJHYN.js.map +1 -0
  270. package/dashboard/dist/assets/{index-D-Xs4rAW.js → index-BRGTmoYY.js} +2 -2
  271. package/dashboard/dist/assets/{index-D-Xs4rAW.js.map → index-BRGTmoYY.js.map} +1 -1
  272. package/dashboard/dist/assets/{index-DkrBFFSO.js → index-Bd6-KmBE.js} +3 -3
  273. package/dashboard/dist/assets/{index-DkrBFFSO.js.map → index-Bd6-KmBE.js.map} +1 -1
  274. package/dashboard/dist/assets/{index-Bhb89oHH.js → index-BiVce3n0.js} +2 -2
  275. package/dashboard/dist/assets/{index-Bhb89oHH.js.map → index-BiVce3n0.js.map} +1 -1
  276. package/dashboard/dist/assets/{index-z5Hpeidu.js → index-BmNAVd4s.js} +2 -2
  277. package/dashboard/dist/assets/{index-z5Hpeidu.js.map → index-BmNAVd4s.js.map} +1 -1
  278. package/dashboard/dist/assets/{index-BbCjGO3M.js → index-Bq5XNEzD.js} +2 -2
  279. package/dashboard/dist/assets/{index-BbCjGO3M.js.map → index-Bq5XNEzD.js.map} +1 -1
  280. package/dashboard/dist/assets/{index-DGmzBY9D.js → index-DPStdq4T.js} +2 -2
  281. package/dashboard/dist/assets/{index-DGmzBY9D.js.map → index-DPStdq4T.js.map} +1 -1
  282. package/dashboard/dist/assets/index-DcppjzP5.css +1 -0
  283. package/dashboard/dist/assets/{index-PfSRKerc.js → index-DkcI4V_H.js} +2 -2
  284. package/dashboard/dist/assets/{index-PfSRKerc.js.map → index-DkcI4V_H.js.map} +1 -1
  285. package/dashboard/dist/assets/{index-oFKUFGQL.js → index-Dyotfa_k.js} +2 -2
  286. package/dashboard/dist/assets/{index-oFKUFGQL.js.map → index-Dyotfa_k.js.map} +1 -1
  287. package/dashboard/dist/assets/{index-Eo-l3Lqo.js → index-MDD4JYtu.js} +2 -2
  288. package/dashboard/dist/assets/{index-Eo-l3Lqo.js.map → index-MDD4JYtu.js.map} +1 -1
  289. package/dashboard/dist/assets/index-WSm8bgE7.js +3 -0
  290. package/dashboard/dist/assets/index-WSm8bgE7.js.map +1 -0
  291. package/dashboard/dist/assets/{index-DZhtP2Ok.js → index-eDm6cz0F.js} +2 -2
  292. package/dashboard/dist/assets/{index-DZhtP2Ok.js.map → index-eDm6cz0F.js.map} +1 -1
  293. package/dashboard/dist/assets/{knowledge-CgloEkaf.js → knowledge-Bafewjxk.js} +2 -2
  294. package/dashboard/dist/assets/{knowledge-CgloEkaf.js.map → knowledge-Bafewjxk.js.map} +1 -1
  295. package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js → mcp-query-BzTtIG90.js} +2 -2
  296. package/dashboard/dist/assets/{mcp-query-o-sGX2ST.js.map → mcp-query-BzTtIG90.js.map} +1 -1
  297. package/dashboard/dist/assets/{mcp-Bix7QYO7.js → mcp-vLIutbnc.js} +2 -2
  298. package/dashboard/dist/assets/{mcp-Bix7QYO7.js.map → mcp-vLIutbnc.js.map} +1 -1
  299. package/dashboard/dist/assets/{personas-30azkJ_s.js → personas-WD40EDS_.js} +2 -2
  300. package/dashboard/dist/assets/{personas-30azkJ_s.js.map → personas-WD40EDS_.js.map} +1 -1
  301. package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js → pipelines-DFwULWs3.js} +2 -2
  302. package/dashboard/dist/assets/{pipelines-Bfk2GFK7.js.map → pipelines-DFwULWs3.js.map} +1 -1
  303. package/dashboard/dist/assets/{tasks-CpdopewW.js → tasks-La_-WAUn.js} +2 -2
  304. package/dashboard/dist/assets/{tasks-CpdopewW.js.map → tasks-La_-WAUn.js.map} +1 -1
  305. package/dashboard/dist/assets/{topics--bvCV9Yp.js → topics-CzYMlvqm.js} +2 -2
  306. package/dashboard/dist/assets/{topics--bvCV9Yp.js.map → topics-CzYMlvqm.js.map} +1 -1
  307. package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js → useDebouncedValue-C0FQyANW.js} +2 -2
  308. package/dashboard/dist/assets/{useDebouncedValue-Da0lPmj3.js.map → useDebouncedValue-C0FQyANW.js.map} +1 -1
  309. package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js → useNamespace-WW_XjAb3.js} +2 -2
  310. package/dashboard/dist/assets/{useNamespace-DD_Esl6n.js.map → useNamespace-WW_XjAb3.js.map} +1 -1
  311. package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js → useYamlActivityEvents-B3YxPeFt.js} +2 -2
  312. package/dashboard/dist/assets/{useYamlActivityEvents-AeAhZJJk.js.map → useYamlActivityEvents-B3YxPeFt.js.map} +1 -1
  313. package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js → vendor-icons-CeVtUKyP.js} +2 -2
  314. package/dashboard/dist/assets/{vendor-icons-B7OcUM6b.js.map → vendor-icons-CeVtUKyP.js.map} +1 -1
  315. package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js → yaml-workflows-COHOjdhF.js} +2 -2
  316. package/dashboard/dist/assets/{yaml-workflows-BHAOOGvn.js.map → yaml-workflows-COHOjdhF.js.map} +1 -1
  317. package/dashboard/dist/index.html +3 -3
  318. package/docs/accumulator.md +37 -1
  319. package/docs/api/mcp/admin.md +3 -2
  320. package/docs/api/sdk/escalations.md +6 -0
  321. package/docs/api/sdk/exports.md +1 -1
  322. package/docs/api/sdk/workflows.md +23 -4
  323. package/docs/cli.md +1 -1
  324. package/docs/dashboard.md +2 -2
  325. package/docs/faceted-routing.md +2 -0
  326. package/docs/hitl/x-lt-scan.md +51 -0
  327. package/docs/hitl/x-lt-widget.md +5 -0
  328. package/docs/hitl-guide.md +2 -0
  329. package/docs/scan-codes.md +252 -19
  330. package/package.json +1 -1
  331. package/build/types/scan-code.d.ts +0 -308
  332. package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js +0 -2
  333. package/dashboard/dist/assets/AvailableEscalationsPage-CpbC8oTN.js.map +0 -1
  334. package/dashboard/dist/assets/CapabilitiesPage-RGgD3YZO.js +0 -2
  335. package/dashboard/dist/assets/CountdownTimer-BaexQMK6.js +0 -2
  336. package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js +0 -9
  337. package/dashboard/dist/assets/EscalationSchemaPage-W5r0A1kj.js.map +0 -1
  338. package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js +0 -2
  339. package/dashboard/dist/assets/EscalationTimeline-DKyTz6sM.js.map +0 -1
  340. package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js +0 -5
  341. package/dashboard/dist/assets/McpQueryDetailPage-DYJr16l7.js.map +0 -1
  342. package/dashboard/dist/assets/ResolverForm-BwgjIX97.js +0 -7
  343. package/dashboard/dist/assets/ResolverForm-BwgjIX97.js.map +0 -1
  344. package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js +0 -8
  345. package/dashboard/dist/assets/RoleDetailPage-BFuLNJXa.js.map +0 -1
  346. package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js +0 -2
  347. package/dashboard/dist/assets/ScanCodesPage-Cu1bKEix.js.map +0 -1
  348. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js +0 -2
  349. package/dashboard/dist/assets/ScanSchemeDetailPage-D9AbS6UY.js.map +0 -1
  350. package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js +0 -2
  351. package/dashboard/dist/assets/ScanStationPage-gcZGefvT.js.map +0 -1
  352. package/dashboard/dist/assets/index-B_GT23TE.js +0 -3
  353. package/dashboard/dist/assets/index-B_GT23TE.js.map +0 -1
  354. package/dashboard/dist/assets/index-CgUcYveM.js +0 -67
  355. package/dashboard/dist/assets/index-CgUcYveM.js.map +0 -1
  356. package/dashboard/dist/assets/index-Dh8MJl3L.css +0 -1
@@ -1,4 +1,4 @@
1
- import type { AccumulatedItem, LTEscalationRecord } from '../../types';
1
+ import type { AccumulatedItem, ContainerSelector, LTEscalationRecord } from '../../types';
2
2
  import type { LTApiAuth, LTApiResult } from '../../types/sdk';
3
3
  /** Names the second row of a reciprocal add or removal. Exactly one selector. */
4
4
  export interface ReciprocalInput {
@@ -16,6 +16,11 @@ export interface AccumulateItemInput {
16
16
  metadata?: Record<string, any>;
17
17
  assertClaim?: boolean;
18
18
  reciprocal?: ReciprocalInput;
19
+ /**
20
+ * The person who caused the add, when a trusted service performs it for
21
+ * them. Recorded as the entry's actor; the caller's rights still gate the write.
22
+ */
23
+ initiatedBy?: string;
19
24
  }
20
25
  /**
21
26
  * Add ONE item to an accumulator escalation (a `conditional` wait declared
@@ -59,10 +64,14 @@ export declare function accumulateItemByMetadata(input: {
59
64
  key: string;
60
65
  value: string;
61
66
  restrictRoles?: string[];
67
+ /** Narrows the container beyond the facet: type, subtype, extra facet guards. */
68
+ container?: ContainerSelector;
62
69
  } & Omit<AccumulateItemInput, 'assertClaim'>, auth: LTApiAuth): Promise<LTApiResult>;
63
70
  export interface RemoveItemInput {
64
71
  itemKey: string;
65
72
  reciprocal?: Omit<ReciprocalInput, 'payload'>;
73
+ /** The person who caused the removal; see {@link AccumulateItemInput.initiatedBy}. */
74
+ initiatedBy?: string;
66
75
  }
67
76
  /**
68
77
  * Remove ONE held item from a pending accumulator escalation, one guarded
@@ -44,6 +44,8 @@ exports.getEscalationItems = getEscalationItems;
44
44
  exports.getEscalationItemsBySignalKey = getEscalationItemsBySignalKey;
45
45
  const escalationService = __importStar(require("../../services/escalation"));
46
46
  const resolver_validation_1 = require("../../services/escalation/resolver-validation");
47
+ const userService = __importStar(require("../../services/user"));
48
+ const uuid_1 = require("../../lib/uuid");
47
49
  const enforcement_cache_1 = require("../../services/role/enforcement-cache");
48
50
  const escalation_1 = require("../../types/escalation");
49
51
  const helpers_1 = require("./helpers");
@@ -66,23 +68,73 @@ function isBatch(escalation) {
66
68
  return Array.isArray(escalation.metadata?.[escalation_1.ESCALATION_BATCH_KEYS.PENDING]);
67
69
  }
68
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
+ }
69
80
  /**
70
81
  * The container a facet names: the highest priority pending row that carries
71
82
  * the facet AND the accumulator declaration, within the given roles (null =
72
- * unscoped). A release or remediation row sharing the facet is never a
73
- * candidate, so a by-facet add lands on the open container or nowhere.
83
+ * unscoped) and the selector's guards. A release or remediation row sharing
84
+ * the facet is never a candidate, and neither is the add's own reciprocal row,
85
+ * so a by-facet add lands on the open container or nowhere.
74
86
  */
75
- async function pickAccumulatorByFacet(key, value, roles) {
87
+ async function pickAccumulatorByFacet(key, value, roles, selector, excludeId) {
76
88
  if (roles !== null && roles.length === 0)
77
89
  return null;
78
90
  const found = await escalationService.searchByFacets({
79
91
  roles: roles ?? undefined,
80
- facets: { [key]: value },
92
+ types: selector?.types,
93
+ subtypes: selector?.subtypes,
94
+ facets: { ...selector?.facets, [key]: value },
81
95
  status: 'pending',
82
96
  exists: [escalation_1.ESCALATION_ACCUMULATE_KEYS.COUNT],
83
- limit: 1,
97
+ limit: excludeId ? 2 : 1,
84
98
  });
85
- return found.escalations[0] ?? null;
99
+ return found.escalations.find((row) => row.id !== excludeId) ?? null;
100
+ }
101
+ const isStringList = (v) => Array.isArray(v) && v.every((s) => typeof s === 'string' && s.length > 0);
102
+ /** The selector's shape error, or null when it is absent or well formed. */
103
+ function containerSelectorError(selector) {
104
+ if (selector === undefined)
105
+ return null;
106
+ if (!selector || typeof selector !== 'object' || Array.isArray(selector))
107
+ return 'container must be an object';
108
+ if (selector.types !== undefined && !isStringList(selector.types))
109
+ return 'container.types must be an array of strings';
110
+ if (selector.subtypes !== undefined && !isStringList(selector.subtypes))
111
+ return 'container.subtypes must be an array of strings';
112
+ if (selector.facets !== undefined && (!selector.facets || typeof selector.facets !== 'object' || Array.isArray(selector.facets))) {
113
+ return 'container.facets must be an object';
114
+ }
115
+ return null;
116
+ }
117
+ function isNarrowed(selector) {
118
+ return !!(selector?.types?.length || selector?.subtypes?.length
119
+ || (selector?.facets && Object.keys(selector.facets).length));
120
+ }
121
+ /**
122
+ * The entry's actor: the caller, or the user a global-access caller names as
123
+ * the initiator. Attribution only; it never widens what the caller may write.
124
+ */
125
+ async function resolveActor(initiatedBy, auth) {
126
+ if (initiatedBy === undefined || initiatedBy === auth.userId)
127
+ return { actor: auth.userId };
128
+ if (typeof initiatedBy !== 'string' || !(0, uuid_1.isUuid)(initiatedBy)) {
129
+ return { error: { status: 400, error: 'initiatedBy must be a user id' } };
130
+ }
131
+ if (!(await userService.hasGlobalEscalationAccess(auth.userId))) {
132
+ return { error: { status: 403, error: 'initiatedBy requires global escalation access' } };
133
+ }
134
+ if (!(await userService.getUser(initiatedBy))) {
135
+ return { error: { status: 400, error: 'initiatedBy names no user' } };
136
+ }
137
+ return { actor: initiatedBy };
86
138
  }
87
139
  function reciprocalSelectorCount(r) {
88
140
  return (r.id ? 1 : 0) + (r.signalKey ? 1 : 0) + (r.key !== undefined ? 1 : 0);
@@ -156,15 +208,22 @@ async function gatePayload(escalation, payload, userId) {
156
208
  async function accumulateItem(input, auth) {
157
209
  try {
158
210
  const { id, itemKey, metadata } = input;
159
- if (!itemKey)
160
- return { status: 400, error: 'itemKey is required' };
211
+ const keyError = itemKeyError(itemKey);
212
+ if (keyError)
213
+ return keyError;
214
+ const initiator = await resolveActor(input.initiatedBy, auth);
215
+ if ('error' in initiator)
216
+ return initiator.error;
161
217
  const escalation = await escalationService.getEscalation(id);
162
218
  if (!escalation)
163
219
  return { status: 404, error: 'Escalation not found' };
164
- if (escalation.status === 'cancelled')
165
- return { status: 409, error: 'Escalation is cancelled' };
166
- if (escalation.status !== 'pending')
167
- 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
+ }
168
227
  if (!isAccumulator(escalation))
169
228
  return { status: 400, error: 'Escalation is not an accumulator' };
170
229
  if (await (0, helpers_1.assertReadAccess)(auth.userId, escalation)) {
@@ -183,7 +242,7 @@ async function accumulateItem(input, auth) {
183
242
  itemKey,
184
243
  payload: payload.payload,
185
244
  metadata: { ...metadata, resolved_by: auth.userId },
186
- actor: auth.userId,
245
+ actor: initiator.actor,
187
246
  assertClaim: input.assertClaim ? auth.userId : undefined,
188
247
  resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
189
248
  reciprocal: reciprocal.reciprocal,
@@ -204,8 +263,12 @@ async function accumulateItemBySignalKey(input, auth) {
204
263
  const { signalKey, itemKey, metadata } = input;
205
264
  if (!signalKey)
206
265
  return { status: 400, error: 'signalKey is required' };
207
- if (!itemKey)
208
- return { status: 400, error: 'itemKey is required' };
266
+ const keyError = itemKeyError(itemKey);
267
+ if (keyError)
268
+ return keyError;
269
+ const initiator = await resolveActor(input.initiatedBy, auth);
270
+ if ('error' in initiator)
271
+ return initiator.error;
209
272
  const escalation = await escalationService.getEscalationBySignalKey(signalKey);
210
273
  if (!escalation)
211
274
  return { status: 404, error: 'Escalation not found' };
@@ -226,7 +289,7 @@ async function accumulateItemBySignalKey(input, auth) {
226
289
  itemKey,
227
290
  payload: payload.payload,
228
291
  metadata: { ...metadata, resolved_by: auth.userId },
229
- actor: auth.userId,
292
+ actor: initiator.actor,
230
293
  resolvedBy: await (0, resolve_1.resolverIdentity)(auth),
231
294
  reciprocal: reciprocal.reciprocal,
232
295
  });
@@ -252,8 +315,15 @@ async function accumulateItemByMetadata(input, auth) {
252
315
  const { key, value, itemKey, metadata } = input;
253
316
  if (!key || !value)
254
317
  return { status: 400, error: 'key and value are required' };
255
- if (!itemKey)
256
- return { status: 400, error: 'itemKey is required' };
318
+ const keyError = itemKeyError(itemKey);
319
+ if (keyError)
320
+ return keyError;
321
+ const initiator = await resolveActor(input.initiatedBy, auth);
322
+ if ('error' in initiator)
323
+ return initiator.error;
324
+ const selectorError = containerSelectorError(input.container);
325
+ if (selectorError)
326
+ return { status: 400, error: selectorError };
257
327
  const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
258
328
  const allowedRoles = (0, metadata_1.restrictScopeRoles)(writeScope.allRoles, writeScope.global, input.restrictRoles);
259
329
  const reciprocal = await gateReciprocal(input.reciprocal, auth);
@@ -261,13 +331,17 @@ async function accumulateItemByMetadata(input, auth) {
261
331
  return reciprocal.error;
262
332
  const resolvedBy = await (0, resolve_1.resolverIdentity)(auth);
263
333
  const outcome = { ...metadata, resolved_by: auth.userId };
334
+ // A narrowed selector picks in Long Tail, then adds by id; the by-id
335
+ // statement re-checks pending under its lock, and type, subtype and the
336
+ // accumulator declaration are fixed at creation.
264
337
  const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
265
- if (enforcing.size === 0 || input.payload === undefined) {
338
+ const narrowed = isNarrowed(input.container);
339
+ if (!narrowed && (enforcing.size === 0 || input.payload === undefined)) {
266
340
  const result = await escalationService.accumulateItemByMetadata(key, value, {
267
341
  itemKey,
268
342
  payload: input.payload,
269
343
  metadata: outcome,
270
- actor: auth.userId,
344
+ actor: initiator.actor,
271
345
  resolvedBy,
272
346
  roles: allowedRoles ?? undefined,
273
347
  reciprocal: reciprocal.reciprocal,
@@ -276,7 +350,7 @@ async function accumulateItemByMetadata(input, auth) {
276
350
  return { status: 404, error: NO_ACCUMULATOR_FOR_FACET };
277
351
  return accumulateOutcomeResult(result, itemKey, result.escalation?.workflow_id ?? null);
278
352
  }
279
- const row = await pickAccumulatorByFacet(key, value, allowedRoles);
353
+ const row = await pickAccumulatorByFacet(key, value, allowedRoles, input.container, reciprocal.reciprocal?.id);
280
354
  if (!row)
281
355
  return { status: 404, error: NO_ACCUMULATOR_FOR_FACET };
282
356
  if (!isAccumulator(row))
@@ -288,7 +362,7 @@ async function accumulateItemByMetadata(input, auth) {
288
362
  itemKey,
289
363
  payload: payload.payload,
290
364
  metadata: outcome,
291
- actor: auth.userId,
365
+ actor: initiator.actor,
292
366
  resolvedBy,
293
367
  reciprocal: reciprocal.reciprocal,
294
368
  });
@@ -311,6 +385,9 @@ async function removeItem(input, auth) {
311
385
  const { id, itemKey } = input;
312
386
  if (!itemKey)
313
387
  return { status: 400, error: 'itemKey is required' };
388
+ const initiator = await resolveActor(input.initiatedBy, auth);
389
+ if ('error' in initiator)
390
+ return initiator.error;
314
391
  const escalation = await escalationService.getEscalation(id);
315
392
  if (!escalation)
316
393
  return { status: 404, error: 'Escalation not found' };
@@ -328,7 +405,7 @@ async function removeItem(input, auth) {
328
405
  if ('error' in reciprocal)
329
406
  return reciprocal.error;
330
407
  const result = await escalationService.removeAccumulatedItem(escalation.id, {
331
- itemKey, actor: auth.userId, reciprocal: reciprocal.reciprocal,
408
+ itemKey, actor: initiator.actor, reciprocal: reciprocal.reciprocal,
332
409
  });
333
410
  return removeOutcomeResult(result, itemKey);
334
411
  }
@@ -343,6 +420,9 @@ async function removeItemBySignalKey(input, auth) {
343
420
  return { status: 400, error: 'signalKey is required' };
344
421
  if (!itemKey)
345
422
  return { status: 400, error: 'itemKey is required' };
423
+ const initiator = await resolveActor(input.initiatedBy, auth);
424
+ if ('error' in initiator)
425
+ return initiator.error;
346
426
  const escalation = await escalationService.getEscalationBySignalKey(signalKey);
347
427
  if (!escalation)
348
428
  return { status: 404, error: 'Escalation not found' };
@@ -357,7 +437,7 @@ async function removeItemBySignalKey(input, auth) {
357
437
  if ('error' in reciprocal)
358
438
  return reciprocal.error;
359
439
  const result = await escalationService.removeAccumulatedItemBySignalKey(signalKey, {
360
- itemKey, actor: auth.userId, reciprocal: reciprocal.reciprocal,
440
+ itemKey, actor: initiator.actor, reciprocal: reciprocal.reciprocal,
361
441
  });
362
442
  return removeOutcomeResult(result, itemKey);
363
443
  }
@@ -372,13 +452,16 @@ async function removeItemByMetadata(input, auth) {
372
452
  return { status: 400, error: 'key and value are required' };
373
453
  if (!itemKey)
374
454
  return { status: 400, error: 'itemKey is required' };
455
+ const initiator = await resolveActor(input.initiatedBy, auth);
456
+ if ('error' in initiator)
457
+ return initiator.error;
375
458
  const writeScope = await (0, helpers_1.getEscalationWriteScope)(auth.userId);
376
459
  const allowedRoles = (0, metadata_1.restrictScopeRoles)(writeScope.allRoles, writeScope.global, input.restrictRoles);
377
460
  const reciprocal = await gateReciprocal(input.reciprocal, auth);
378
461
  if ('error' in reciprocal)
379
462
  return reciprocal.error;
380
463
  const result = await escalationService.removeAccumulatedItemByMetadata(key, value, {
381
- itemKey, actor: auth.userId, roles: allowedRoles ?? undefined, reciprocal: reciprocal.reciprocal,
464
+ itemKey, actor: initiator.actor, roles: allowedRoles ?? undefined, reciprocal: reciprocal.reciprocal,
382
465
  });
383
466
  if (result.outcome === 'not-found')
384
467
  return { status: 404, error: NO_ACCUMULATOR_FOR_FACET };
@@ -506,21 +589,21 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
506
589
  },
507
590
  };
508
591
  case 'duplicate-item':
509
- 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' } };
510
593
  case 'full':
511
- 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' } };
512
595
  case 'claimed-by-other':
513
- 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' } };
514
597
  case 'claim-expired':
515
- 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' } };
516
599
  case 'not-found':
517
- return { status: 404, error: 'Escalation not found' };
600
+ return { status: 404, error: 'Escalation not found', data: { error: 'Escalation not found', outcome: 'not-found' } };
518
601
  case 'not-accumulator':
519
- 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' } };
520
603
  case 'reciprocal-not-found':
521
- 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' } };
522
605
  case 'reciprocal-not-accumulator':
523
- 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' } };
524
607
  case 'reciprocal-duplicate':
525
608
  return { status: 409, error: 'Reciprocal escalation already holds this container', data: { error: 'Reciprocal escalation already holds this container', outcome: result.outcome } };
526
609
  case 'reciprocal-full':
@@ -528,7 +611,11 @@ function accumulateOutcomeResult(result, itemKey, workflowId) {
528
611
  case 'reciprocal-terminal':
529
612
  return { status: 409, error: 'Reciprocal escalation is no longer pending', data: { error: 'Reciprocal escalation is no longer pending', outcome: result.outcome } };
530
613
  default:
531
- 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
+ };
532
619
  }
533
620
  }
534
621
  function removeOutcomeResult(result, itemKey) {
@@ -1,5 +1,6 @@
1
1
  import { type ProvisionIfAbsent } from './helpers';
2
2
  import type { LTApiAuth, LTApiResult } from '../../types/sdk';
3
+ import type { ScanAvailability } from '../../types';
3
4
  /**
4
5
  * Intersect the caller's scope roles with an optional caller-supplied
5
6
  * restriction (e.g. a scan step's expected queues). Global scope with no
@@ -57,4 +58,8 @@ export declare function resolveByMetadata(input: {
57
58
  metadata?: Record<string, any>;
58
59
  restrictRoles?: string[];
59
60
  extraFacets?: Record<string, any>;
61
+ /** Narrows the pick to a claim state; 'mine' is the resolver's live claim. */
62
+ availability?: ScanAvailability;
63
+ /** Resolves only this row, when it still matches every other condition. */
64
+ assertId?: string;
60
65
  }, auth: LTApiAuth): Promise<LTApiResult>;
@@ -42,6 +42,7 @@ const helpers_1 = require("./helpers");
42
42
  const resolver_validation_1 = require("../../services/escalation/resolver-validation");
43
43
  const enforcement_cache_1 = require("../../services/role/enforcement-cache");
44
44
  const resolve_1 = require("./resolve");
45
+ const uuid_1 = require("../../lib/uuid");
45
46
  /**
46
47
  * Intersect the caller's scope roles with an optional caller-supplied
47
48
  * restriction (e.g. a scan step's expected queues). Global scope with no
@@ -138,6 +139,9 @@ async function resolveByMetadata(input, auth) {
138
139
  if (!input.resolverPayload) {
139
140
  return { status: 400, error: 'resolverPayload is required' };
140
141
  }
142
+ if (input.assertId !== undefined && !(0, uuid_1.isUuid)(input.assertId)) {
143
+ return { status: 404, error: 'No pending escalation found for this metadata, or insufficient role permissions' };
144
+ }
141
145
  const resolved = await (0, helpers_1.resolveAssignee)(input.assignee, auth);
142
146
  if ('error' in resolved)
143
147
  return resolved.error;
@@ -159,12 +163,12 @@ async function resolveByMetadata(input, auth) {
159
163
  // writing; the payload validates here, then a second asserted pass claims
160
164
  // + resolves the same row with pending re-checked inside the statement.
161
165
  const enforcing = await (0, enforcement_cache_1.getEnforcingRoles)();
162
- let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, null, input.extraFacets);
166
+ let result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, enforcing.size > 0 ? [...enforcing] : null, input.assertId ?? null, input.extraFacets, input.availability);
163
167
  if (result.outcome === 'validation_required' && result.row) {
164
168
  const report = await (0, resolver_validation_1.checkResolverPayload)(result.row, input.resolverPayload, undefined, resolveUserId);
165
169
  if (report)
166
170
  return (0, resolve_1.validationFailure)(report);
167
- result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets);
171
+ result = await escalationService.resolveByMetadataAtomic(input.key, input.value, resolveUserId, input.resolverPayload, input.metadata, writeAllRoles, writeSelfRoles, null, result.row.id, input.extraFacets, input.availability);
168
172
  // The asserted row left pending between the two passes — a concurrent
169
173
  // resolution won the row; surface it as the conflict it is.
170
174
  if (result.outcome === 'not_found') {
@@ -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))) {
@@ -110,13 +112,18 @@ async function executeScanChoice(input, auth) {
110
112
  // showed. A row that moved on (resolved, claimed away, re-routed) is the
111
113
  // same double-actor race a second scan loses.
112
114
  const located = await (0, locate_1.locateForStep)(step, ctx, 2);
113
- if (!located || !located.escalations.some((e) => e.id === input.escalationId)) {
115
+ const presented = located?.escalations.find((e) => e.id === input.escalationId);
116
+ if (!presented) {
114
117
  return decorate((0, context_1.conflict)('the item is no longer in the presented state'), ctx, input);
115
118
  }
116
119
  // 6. Dispatch through the same atomic executors a direct scan uses.
117
120
  const synthesized = { query: step.query, verb: choice.verb, params: choice.params };
118
- const result = await (0, verbs_1.dispatchChoiceVerb)(synthesized, ctx, located.escalations[0]);
119
- 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;
120
127
  }
121
128
  catch (err) {
122
129
  return { status: 500, error: err.message };