@pisell/private-materials 6.12.167 → 6.12.169

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 (231) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/meta.js +1 -1
  5. package/build/lowcode/render/default/view.css +1 -1
  6. package/build/lowcode/render/default/view.js +10 -10
  7. package/build/lowcode/view.css +1 -1
  8. package/build/lowcode/view.js +10 -10
  9. package/es/components/HDLKiosk/{contracts → app/contracts}/config.js +1 -1
  10. package/es/components/HDLKiosk/app/manifest.js +11 -11
  11. package/es/components/HDLKiosk/app/operations.js +92 -0
  12. package/es/components/HDLKiosk/app/workflow/barcode.js +11 -13
  13. package/es/components/HDLKiosk/app/workflow/index.js +16 -0
  14. package/es/components/HDLKiosk/app/workflow/predicates.js +1 -1
  15. package/es/components/HDLKiosk/app/workflow/quick.js +1 -1
  16. package/es/components/HDLKiosk/app/workflow/registry.js +4 -4
  17. package/es/components/HDLKiosk/app/workflow/scale.js +5 -1
  18. package/es/components/HDLKiosk/docs/00-/346/226/207/344/273/266/345/257/274/350/210/252.md +104 -167
  19. package/es/components/HDLKiosk/docs/01-/346/240/270/345/277/203/350/277/220/350/241/214/346/234/272/345/210/266.md +105 -101
  20. package/es/components/HDLKiosk/docs/03-/344/270/232/345/212/241/346/265/201/347/250/213/344/270/216/344/272/244/344/272/222/350/247/204/345/210/231.md +2 -2
  21. package/es/components/HDLKiosk/docs/04-/350/256/276/345/244/207/344/270/216/347/247/260/351/207/215.md +43 -26
  22. package/es/components/HDLKiosk/docs/05-/344/272/244/346/230/223/345/256/211/345/205/250.md +2 -0
  23. package/es/components/HDLKiosk/docs/07-/345/220/216/347/273/255/345/267/245/344/275/234.md +1 -1
  24. package/es/components/HDLKiosk/docs/08-/346/227/240/345/244/264Application/350/277/220/350/241/214/346/227/266/351/207/215/346/236/204/350/256/276/350/256/241.md +719 -0
  25. package/es/components/HDLKiosk/docs/09-Entry/350/256/276/345/244/207/344/272/213/344/273/266/351/207/215/346/236/204/344/277/256/345/244/215/346/212/245/345/221/212.md +187 -0
  26. package/es/components/HDLKiosk/docs/README.md +6 -2
  27. package/es/components/HDLKiosk/docs//345/256/236/346/226/275/350/277/233/345/272/246.md +8 -7
  28. package/es/components/HDLKiosk/docs//346/236/266/346/236/204/350/256/276/350/256/241.md +16 -18
  29. package/es/components/HDLKiosk/index.js +22 -28
  30. package/es/components/HDLKiosk/index.less +1 -1
  31. package/es/components/HDLKiosk/kernel/README.md +14 -13
  32. package/es/components/HDLKiosk/kernel/application/defineApplication.js +63 -24
  33. package/es/components/HDLKiosk/kernel/application/defineSlice.js +6 -6
  34. package/es/components/HDLKiosk/kernel/application/runtime.js +237 -0
  35. package/es/components/HDLKiosk/kernel/operations/coordinator.js +1 -1
  36. package/es/components/HDLKiosk/kernel/operations/registry.js +3 -3
  37. package/es/components/HDLKiosk/kernel/operations/sessionEpoch.js +1 -1
  38. package/es/components/HDLKiosk/kernel/operations/types.js +7 -3
  39. package/es/components/HDLKiosk/kernel/workflow/actor.js +51 -22
  40. package/es/components/HDLKiosk/kernel/workflow/compiler.js +23 -30
  41. package/es/components/HDLKiosk/runtime/createRuntime.js +238 -0
  42. package/es/components/HDLKiosk/{devices → runtime/devices}/dedupeStore.js +1 -1
  43. package/es/components/HDLKiosk/{devices → runtime/devices}/scaleIngress.js +1 -1
  44. package/es/components/HDLKiosk/{devices/scale/runtime.js → runtime/devices/scaleStore.js} +18 -24
  45. package/es/components/HDLKiosk/{devices → runtime/devices}/scannerIngress.js +1 -1
  46. package/es/components/HDLKiosk/runtime/devices/scannerSessionPort.js +60 -0
  47. package/es/components/HDLKiosk/runtime/devices/scannerSessionRouter.js +212 -0
  48. package/es/components/HDLKiosk/runtime/operations/barcode.js +18 -0
  49. package/es/components/HDLKiosk/runtime/operations/cart.js +44 -0
  50. package/es/components/HDLKiosk/{app → runtime}/operations/cartConsistency.js +1 -1
  51. package/es/components/HDLKiosk/{app → runtime}/operations/checkout.js +95 -110
  52. package/es/components/HDLKiosk/{app → runtime}/operations/checkoutRequirements.js +1 -1
  53. package/es/components/HDLKiosk/{app → runtime}/operations/checkoutSafety.js +1 -1
  54. package/es/components/HDLKiosk/{app → runtime}/operations/coordinator.js +2 -2
  55. package/es/components/HDLKiosk/runtime/operations/customization.js +70 -0
  56. package/es/components/HDLKiosk/{app → runtime}/operations/errors.js +1 -1
  57. package/es/components/HDLKiosk/runtime/operations/fulfillment.js +6 -0
  58. package/es/components/HDLKiosk/runtime/operations/identity.js +55 -0
  59. package/es/components/HDLKiosk/runtime/operations/registry.js +34 -0
  60. package/es/components/HDLKiosk/runtime/operations/session.js +29 -0
  61. package/es/components/HDLKiosk/runtime/operations/types.js +13 -0
  62. package/es/components/HDLKiosk/runtime/session/blockPolicy.js +14 -0
  63. package/es/components/HDLKiosk/runtime/{createWorkflowSession.js → session/createSession.js} +67 -17
  64. package/es/components/HDLKiosk/runtime/{domainTransitionRunner.js → session/transitionRunner.js} +10 -5
  65. package/es/components/HDLKiosk/runtime/{workflowContext.js → session/workflowContext.js} +2 -2
  66. package/es/components/HDLKiosk/runtime/{workflowLifecycle.js → session/workflowLifecycle.js} +2 -2
  67. package/es/components/HDLKiosk/runtime/triggers.js +28 -0
  68. package/es/components/HDLKiosk/slices/catalog/Screen/index.js +15 -8
  69. package/es/components/HDLKiosk/slices/catalog/Screen/index.less +74 -13
  70. package/es/components/HDLKiosk/slices/catalog/slice.js +2 -2
  71. package/es/components/HDLKiosk/slices/customization/Screen/index.js +37 -38
  72. package/es/components/HDLKiosk/slices/customization/Screen/index.less +5 -0
  73. package/es/components/HDLKiosk/slices/customization/slice.js +3 -4
  74. package/es/components/HDLKiosk/slices/fulfillment/slice.js +2 -2
  75. package/es/components/HDLKiosk/slices/fulfillment/view.js +1 -1
  76. package/es/components/HDLKiosk/slices/identity/Screen/index.js +2 -2
  77. package/es/components/HDLKiosk/slices/identity/slice.js +3 -3
  78. package/es/components/HDLKiosk/slices/identity/view.js +1 -1
  79. package/es/components/HDLKiosk/slices/payment/slice.js +3 -3
  80. package/es/components/HDLKiosk/slices/primaryProductPrompt/slice.js +2 -2
  81. package/es/components/HDLKiosk/slices/primaryProductPrompt/view.js +2 -2
  82. package/es/components/HDLKiosk/{runtime → ui}/HDLKioskWorkflowView.js +45 -131
  83. package/es/components/HDLKiosk/ui/ScaleSimulatorConsole/index.js +387 -0
  84. package/es/components/HDLKiosk/ui/ScaleSimulatorConsole/index.less +621 -0
  85. package/es/components/HDLKiosk/{app → ui}/ScreenRenderer.js +7 -7
  86. package/es/components/HDLKiosk/ui/controllers/useHDLKioskActionDispatcher.js +66 -0
  87. package/es/components/HDLKiosk/{runtime → ui}/controllers/useHDLKioskCustomerController.js +1 -1
  88. package/es/components/HDLKiosk/ui/controllers/useHDLKioskDeviceController.js +25 -0
  89. package/es/components/HDLKiosk/ui/controllers/useHDLKioskExitController.js +53 -0
  90. package/es/components/HDLKiosk/{runtime → ui}/controllers/useHDLKioskScreenData.js +1 -1
  91. package/es/components/HDLKiosk/ui/controllers/useHDLKioskSessionController.js +39 -0
  92. package/es/components/HDLKiosk/{app → ui}/entry/Screen/index.js +8 -6
  93. package/es/components/HDLKiosk/{app → ui}/entry/model.js +2 -2
  94. package/es/components/HDLKiosk/ui/scale.js +20 -0
  95. package/es/components/HDLKiosk/{runtime/useHostSnapshot.js → ui/snapshots.js} +6 -8
  96. package/es/components/HDLKiosk/{app → ui}/views.js +1 -1
  97. package/es/components/HDLKiosk/{runtime → ui}/workflowEvent.js +1 -1
  98. package/es/components/HDLKiosk/utils.js +4 -4
  99. package/es/components/bigSale/templates/HDLKiosk/adapter/HDLKioskPaymentRuntime.js +2 -1
  100. package/es/components/bigSale/templates/HDLKiosk/adapter/capabilities.js +1 -1
  101. package/es/components/bigSale/templates/HDLKiosk/adapter/projection.js +21 -11
  102. package/es/components/bigSale/templates/HDLKiosk/adapter/sales.js +21 -3
  103. package/es/components/bigSale/templates/HDLKiosk/adapter/scaleTrigger.js +20 -5
  104. package/es/components/bigSale/templates/HDLKiosk/adapter/useBigSaleHDLKioskHost.js +3 -0
  105. package/es/components/bigSale/templates/HDLKiosk/index.js +3 -3
  106. package/lib/components/HDLKiosk/{contracts → app/contracts}/config.js +1 -1
  107. package/lib/components/HDLKiosk/app/manifest.js +18 -19
  108. package/lib/components/HDLKiosk/app/operations.js +105 -0
  109. package/lib/components/HDLKiosk/app/workflow/barcode.js +11 -13
  110. package/lib/components/HDLKiosk/app/workflow/index.js +16 -0
  111. package/lib/components/HDLKiosk/app/workflow/predicates.js +1 -0
  112. package/lib/components/HDLKiosk/app/workflow/quick.js +1 -1
  113. package/lib/components/HDLKiosk/app/workflow/registry.js +3 -3
  114. package/lib/components/HDLKiosk/app/workflow/scale.js +5 -1
  115. package/lib/components/HDLKiosk/docs/00-/346/226/207/344/273/266/345/257/274/350/210/252.md +104 -167
  116. package/lib/components/HDLKiosk/docs/01-/346/240/270/345/277/203/350/277/220/350/241/214/346/234/272/345/210/266.md +105 -101
  117. package/lib/components/HDLKiosk/docs/03-/344/270/232/345/212/241/346/265/201/347/250/213/344/270/216/344/272/244/344/272/222/350/247/204/345/210/231.md +2 -2
  118. package/lib/components/HDLKiosk/docs/04-/350/256/276/345/244/207/344/270/216/347/247/260/351/207/215.md +43 -26
  119. package/lib/components/HDLKiosk/docs/05-/344/272/244/346/230/223/345/256/211/345/205/250.md +2 -0
  120. package/lib/components/HDLKiosk/docs/07-/345/220/216/347/273/255/345/267/245/344/275/234.md +1 -1
  121. package/lib/components/HDLKiosk/docs/08-/346/227/240/345/244/264Application/350/277/220/350/241/214/346/227/266/351/207/215/346/236/204/350/256/276/350/256/241.md +719 -0
  122. package/lib/components/HDLKiosk/docs/09-Entry/350/256/276/345/244/207/344/272/213/344/273/266/351/207/215/346/236/204/344/277/256/345/244/215/346/212/245/345/221/212.md +187 -0
  123. package/lib/components/HDLKiosk/docs/README.md +6 -2
  124. package/lib/components/HDLKiosk/docs//345/256/236/346/226/275/350/277/233/345/272/246.md +8 -7
  125. package/lib/components/HDLKiosk/docs//346/236/266/346/236/204/350/256/276/350/256/241.md +16 -18
  126. package/lib/components/HDLKiosk/index.js +25 -31
  127. package/lib/components/HDLKiosk/index.less +1 -1
  128. package/lib/components/HDLKiosk/kernel/README.md +14 -13
  129. package/lib/components/HDLKiosk/kernel/application/defineApplication.js +65 -25
  130. package/lib/components/HDLKiosk/kernel/application/defineSlice.js +6 -6
  131. package/lib/components/HDLKiosk/kernel/application/runtime.js +237 -0
  132. package/lib/components/HDLKiosk/kernel/operations/coordinator.js +1 -1
  133. package/lib/components/HDLKiosk/kernel/operations/registry.js +3 -3
  134. package/lib/components/HDLKiosk/kernel/operations/sessionEpoch.js +1 -1
  135. package/lib/components/HDLKiosk/kernel/operations/types.js +8 -3
  136. package/lib/components/HDLKiosk/kernel/workflow/actor.js +51 -22
  137. package/lib/components/HDLKiosk/kernel/workflow/compiler.js +23 -30
  138. package/lib/components/HDLKiosk/runtime/createRuntime.js +239 -0
  139. package/lib/components/HDLKiosk/{devices → runtime/devices}/dedupeStore.js +1 -1
  140. package/lib/components/HDLKiosk/{devices → runtime/devices}/scaleIngress.js +1 -1
  141. package/lib/components/HDLKiosk/{devices/scale/runtime.js → runtime/devices/scaleStore.js} +17 -27
  142. package/lib/components/HDLKiosk/{devices → runtime/devices}/scannerIngress.js +1 -1
  143. package/lib/components/HDLKiosk/runtime/devices/scannerSessionPort.js +60 -0
  144. package/lib/components/HDLKiosk/runtime/devices/scannerSessionRouter.js +212 -0
  145. package/lib/components/HDLKiosk/runtime/operations/barcode.js +17 -0
  146. package/lib/components/HDLKiosk/runtime/operations/cart.js +46 -0
  147. package/lib/components/HDLKiosk/{app → runtime}/operations/cartConsistency.js +1 -1
  148. package/lib/components/HDLKiosk/{app → runtime}/operations/checkout.js +97 -112
  149. package/lib/components/HDLKiosk/{app → runtime}/operations/checkoutRequirements.js +1 -1
  150. package/lib/components/HDLKiosk/{app → runtime}/operations/checkoutSafety.js +1 -1
  151. package/lib/components/HDLKiosk/{app → runtime}/operations/coordinator.js +2 -2
  152. package/lib/components/HDLKiosk/runtime/operations/customization.js +73 -0
  153. package/lib/components/HDLKiosk/{app → runtime}/operations/errors.js +1 -1
  154. package/lib/components/HDLKiosk/runtime/operations/fulfillment.js +5 -0
  155. package/lib/components/HDLKiosk/runtime/operations/identity.js +55 -0
  156. package/lib/components/HDLKiosk/runtime/operations/registry.js +34 -0
  157. package/lib/components/HDLKiosk/runtime/operations/session.js +30 -0
  158. package/lib/components/HDLKiosk/runtime/operations/types.js +14 -0
  159. package/lib/components/HDLKiosk/runtime/session/blockPolicy.js +14 -0
  160. package/lib/components/HDLKiosk/runtime/{createWorkflowSession.js → session/createSession.js} +71 -21
  161. package/lib/components/HDLKiosk/runtime/{domainTransitionRunner.js → session/transitionRunner.js} +10 -5
  162. package/lib/components/HDLKiosk/runtime/{workflowContext.js → session/workflowContext.js} +2 -2
  163. package/lib/components/HDLKiosk/runtime/{workflowLifecycle.js → session/workflowLifecycle.js} +2 -2
  164. package/lib/components/HDLKiosk/runtime/triggers.js +28 -0
  165. package/lib/components/HDLKiosk/slices/catalog/Screen/index.js +15 -8
  166. package/lib/components/HDLKiosk/slices/catalog/Screen/index.less +74 -13
  167. package/lib/components/HDLKiosk/slices/catalog/slice.js +3 -3
  168. package/lib/components/HDLKiosk/slices/customization/Screen/index.js +38 -39
  169. package/lib/components/HDLKiosk/slices/customization/Screen/index.less +5 -0
  170. package/lib/components/HDLKiosk/slices/customization/slice.js +5 -6
  171. package/lib/components/HDLKiosk/slices/fulfillment/slice.js +3 -3
  172. package/lib/components/HDLKiosk/slices/fulfillment/view.js +1 -1
  173. package/lib/components/HDLKiosk/slices/identity/Screen/index.js +2 -2
  174. package/lib/components/HDLKiosk/slices/identity/slice.js +4 -4
  175. package/lib/components/HDLKiosk/slices/identity/view.js +1 -1
  176. package/lib/components/HDLKiosk/slices/payment/slice.js +5 -5
  177. package/lib/components/HDLKiosk/slices/primaryProductPrompt/slice.js +2 -2
  178. package/lib/components/HDLKiosk/slices/primaryProductPrompt/view.js +2 -2
  179. package/lib/components/HDLKiosk/{runtime → ui}/HDLKioskWorkflowView.js +46 -132
  180. package/lib/components/HDLKiosk/ui/ScaleSimulatorConsole/index.js +390 -0
  181. package/lib/components/HDLKiosk/ui/ScaleSimulatorConsole/index.less +621 -0
  182. package/lib/components/HDLKiosk/{app → ui}/ScreenRenderer.js +7 -7
  183. package/lib/components/HDLKiosk/ui/controllers/useHDLKioskActionDispatcher.js +67 -0
  184. package/lib/components/HDLKiosk/{runtime → ui}/controllers/useHDLKioskCustomerController.js +1 -1
  185. package/lib/components/HDLKiosk/ui/controllers/useHDLKioskDeviceController.js +26 -0
  186. package/lib/components/HDLKiosk/ui/controllers/useHDLKioskExitController.js +54 -0
  187. package/lib/components/HDLKiosk/{runtime → ui}/controllers/useHDLKioskScreenData.js +1 -1
  188. package/lib/components/HDLKiosk/ui/controllers/useHDLKioskSessionController.js +40 -0
  189. package/lib/components/HDLKiosk/{app → ui}/entry/Screen/index.js +8 -6
  190. package/lib/components/HDLKiosk/{app → ui}/entry/model.js +2 -2
  191. package/lib/components/HDLKiosk/ui/scale.js +24 -0
  192. package/lib/components/HDLKiosk/{runtime/useHostSnapshot.js → ui/snapshots.js} +6 -7
  193. package/lib/components/HDLKiosk/{app → ui}/views.js +1 -1
  194. package/lib/components/HDLKiosk/{runtime → ui}/workflowEvent.js +1 -1
  195. package/lib/components/HDLKiosk/utils.js +4 -4
  196. package/lib/components/bigSale/templates/HDLKiosk/adapter/HDLKioskPaymentRuntime.js +2 -1
  197. package/lib/components/bigSale/templates/HDLKiosk/adapter/capabilities.js +1 -1
  198. package/lib/components/bigSale/templates/HDLKiosk/adapter/projection.js +21 -10
  199. package/lib/components/bigSale/templates/HDLKiosk/adapter/sales.js +20 -2
  200. package/lib/components/bigSale/templates/HDLKiosk/adapter/scaleTrigger.js +19 -4
  201. package/lib/components/bigSale/templates/HDLKiosk/adapter/useBigSaleHDLKioskHost.js +3 -0
  202. package/lib/components/bigSale/templates/HDLKiosk/index.js +4 -4
  203. package/package.json +2 -2
  204. package/es/components/HDLKiosk/app/constants.js +0 -9
  205. package/es/components/HDLKiosk/app/operations/barcode.js +0 -22
  206. package/es/components/HDLKiosk/app/operations/cart.js +0 -60
  207. package/es/components/HDLKiosk/app/operations/fulfillment.js +0 -11
  208. package/es/components/HDLKiosk/app/operations/session.js +0 -41
  209. package/es/components/HDLKiosk/app/operations/types.js +0 -11
  210. package/es/components/HDLKiosk/devices/entryArbiter.js +0 -33
  211. package/es/components/HDLKiosk/runtime/controllers/useHDLKioskDeviceController.js +0 -75
  212. package/es/components/HDLKiosk/runtime/controllers/useHDLKioskScannerController.js +0 -160
  213. package/es/components/HDLKiosk/runtime/controllers/useHDLKioskSessionController.js +0 -185
  214. package/es/components/HDLKiosk/runtime/useWorkflowSnapshot.js +0 -12
  215. package/es/components/HDLKiosk/slices/customization/operation.js +0 -80
  216. package/es/components/HDLKiosk/slices/identity/operation.js +0 -60
  217. package/lib/components/HDLKiosk/app/constants.js +0 -9
  218. package/lib/components/HDLKiosk/app/operations/barcode.js +0 -21
  219. package/lib/components/HDLKiosk/app/operations/cart.js +0 -62
  220. package/lib/components/HDLKiosk/app/operations/fulfillment.js +0 -10
  221. package/lib/components/HDLKiosk/app/operations/session.js +0 -42
  222. package/lib/components/HDLKiosk/app/operations/types.js +0 -12
  223. package/lib/components/HDLKiosk/devices/entryArbiter.js +0 -33
  224. package/lib/components/HDLKiosk/runtime/controllers/useHDLKioskDeviceController.js +0 -76
  225. package/lib/components/HDLKiosk/runtime/controllers/useHDLKioskScannerController.js +0 -161
  226. package/lib/components/HDLKiosk/runtime/controllers/useHDLKioskSessionController.js +0 -186
  227. package/lib/components/HDLKiosk/runtime/useWorkflowSnapshot.js +0 -13
  228. package/lib/components/HDLKiosk/slices/customization/operation.js +0 -83
  229. package/lib/components/HDLKiosk/slices/identity/operation.js +0 -60
  230. /package/es/components/HDLKiosk/{app → ui}/entry/Screen/index.less +0 -0
  231. /package/lib/components/HDLKiosk/{app → ui}/entry/Screen/index.less +0 -0
@@ -0,0 +1,719 @@
1
+ # 无头 Application Runtime 重构设计
2
+
3
+ > 文档角色:定义通用 Application、Trigger、Runtime、Workflow Session 和能力绑定的实现边界。
4
+ > 文档状态:核心运行路径已实现;未完成项在本文单独列出。
5
+ > 更新日期:2026-08-24
6
+
7
+ ## 1. 背景与目标
8
+
9
+ HDLKiosk 已把通用基础包、HDLKiosk Application Definition、Runtime Binding、
10
+ Workflow Session 和 React Components 分开。相同 Definition 可以在纯
11
+ JavaScript、自动化测试和 React 中运行;React Session Controller 只是 Runtime Adapter。
12
+
13
+ 本次重构目标:
14
+
15
+ 1. Kernel 不认识 HDLKiosk、React、Screen、商品、扫码、称重和支付;
16
+ 2. `app/` 只声明 HDLKiosk 业务能力协议和编排关系,不携带 Host/SDK 实现;
17
+ 3. `runtime/` 绑定 Host、Trigger Adapter 和 Operation Handler,产出可独立运行的 Runtime;
18
+ 4. Workflow 可由 manual、设备、定时等 Trigger 启动;
19
+ 5. Workflow 运行后的 Command/Intent 可完全脱离 UI 执行;
20
+ 6. React 只订阅 Snapshot,并向 Session 派发与纯 JS 相同的指令;
21
+ 7. 一个 Application 可以包含多个 Workflow,Runtime Policy 决定允许多少个活跃 Session;
22
+ 8. 当前自动 Trigger 与 Workflow 一对一;重复绑定 fail-closed。
23
+
24
+ 非目标:
25
+
26
+ - 不建设 BPMN 或远端低代码平台;
27
+ - 不允许远端 JavaScript;
28
+ - 不让 Workflow Kernel 解释购物车、支付或设备业务;
29
+ - 不用隐式优先级、注册顺序或“第一个匹配”解决 Trigger 歧义;
30
+ - 不要求第一阶段立即支持持久化和跨进程调度,但协议必须允许后续注入。
31
+ - 当前不实现多 Workflow 共用自动 Trigger,也不实现 Workflow 嵌套调用;数据结构不阻断以后显式扩展。
32
+
33
+ ## 2. 核心概念
34
+
35
+ ### 2.1 Application Definition
36
+
37
+ `defineApplication()` 产生不可变、无运行状态、无外部副作用的应用蓝图。
38
+
39
+ 它可以包含业务语义 ID,例如 `catalog`、`cart.addProduct`、`checkout.open`;不同 Application 正是通过这些语义区分。但它不能包含这些能力如何调用 Host、SDK、数据库或设备的实现。
40
+
41
+ ```ts
42
+ const application = defineApplication({
43
+ id: 'hdl-kiosk',
44
+ activities,
45
+ workflows,
46
+ triggers,
47
+ operations,
48
+ policies,
49
+ });
50
+ ```
51
+
52
+ Application Definition 负责:
53
+
54
+ - Activity 可接受的 Command 和 Intent;
55
+ - Workflow 拓扑、起点、终点和 Trigger Binding;
56
+ - Trigger Contract;
57
+ - Operation Contract;
58
+ - 静态 Policy 和协议引用完整性。
59
+
60
+ Application Definition 不负责:
61
+
62
+ - 创建 Actor 或 Workflow Session;
63
+ - 订阅扫码枪或称重设备;
64
+ - 执行 Operation;
65
+ - 持有当前订单和页面状态;
66
+ - 注册 React Component;
67
+ - 连接 Host、SDK、HTTP 或数据库。
68
+
69
+ ### 2.2 Application Runtime
70
+
71
+ `createApplicationRuntime(options)` 把一份 Application Definition 绑定到一个具体运行环境。
72
+
73
+ ```ts
74
+ const runtime = createApplicationRuntime({
75
+ definition: application,
76
+ triggerAdapters,
77
+ sessionFactory,
78
+ maxActiveSessions: 1,
79
+ });
80
+ ```
81
+
82
+ Runtime 负责:
83
+
84
+ - 编译并校验 Application;
85
+ - 激活、释放自动 Trigger Adapter;
86
+ - 接收 manual start;
87
+ - 将 Trigger Occurrence 路由到唯一 Workflow;
88
+ - Trigger 幂等、并发仲裁和 Admission Policy;
89
+ - 创建、保存和查询 Workflow Session;
90
+ - 绑定 Operation Handler;
91
+ - 发布 Session 生命周期和 Runtime Snapshot;
92
+ - Runtime 级 dispose。
93
+
94
+ 同一个 Definition 可以创建多个 Runtime,例如生产、测试、模拟器或两台不同设备上的运行实例。
95
+
96
+ ### 2.3 Workflow Session
97
+
98
+ Workflow Session 是某一 Workflow Definition 的一次具体执行实例。Kernel 内部持有 Workflow Instance/Actor;外部通过 Session Handle 使用它。
99
+
100
+ ```ts
101
+ interface WorkflowSession {
102
+ readonly id: string;
103
+ readonly workflowId: string;
104
+
105
+ getSnapshot(): WorkflowSessionSnapshot;
106
+ subscribe(listener: () => void): () => void;
107
+ dispatch(instruction: WorkflowInstruction): Promise<DispatchResult>;
108
+ cancel(reason?: string): Promise<CancelResult>;
109
+ }
110
+ ```
111
+
112
+ 一个 Runtime 可以管理零到多个 Session。HDLKiosk 使用 Runtime Admission Policy 限制同一设备最多一个活跃 Session;这不是 Kernel 固有限制。
113
+
114
+ 为避免和销售 Host 的会话混淆:
115
+
116
+ - Kernel/Runtime 使用 `WorkflowSession` 或 `WorkflowInstance`;
117
+ - 销售侧使用 `CommerceSession` 或 `HostSession`;
118
+ - 不再用裸 `session` 同时指代两种生命周期。
119
+
120
+ ### 2.4 Presentation Binding
121
+
122
+ Presentation 是可选 Adapter,不进入 Application Definition 和 Runtime 必需依赖。
123
+
124
+ ```ts
125
+ const presentation = definePresentationBindings({
126
+ identity: IdentityScreen,
127
+ catalog: CatalogScreen,
128
+ paymentMethod: PaymentScreen,
129
+ });
130
+ ```
131
+
132
+ 无 Presentation 时,Application 仍可启动 Session、执行 Command/Intent 并完成 Workflow。
133
+
134
+ ## 3. 总体关系
135
+
136
+ ```text
137
+ Application Definition
138
+ ├── Activity Contracts
139
+ ├── Workflow Definitions
140
+ ├── Trigger Contracts / Bindings
141
+ ├── Operation Contracts
142
+ └── Static Policies
143
+ │
144
+ │ createApplicationRuntime(definition, bindings)
145
+ ▼
146
+ Application Runtime
147
+ ├── Trigger Adapters
148
+ ├── Admission / Idempotency
149
+ ├── Session Registry
150
+ └── Workflow Sessions
151
+ ├── quick #1
152
+ ├── barcodeScan #2
153
+ └── weighingProduct #3
154
+
155
+ Presentation Bindings ──订阅 Runtime/Session──► React UI
156
+ Pure JavaScript ────────调用 start/dispatch───► Runtime/Session
157
+ ```
158
+
159
+ 生命周期关系:
160
+
161
+ ```text
162
+ Definition:进程/模块级,不执行副作用
163
+ Runtime:设备、页面容器或服务实例级
164
+ Session:单次 Workflow 执行级
165
+ React Component:Presentation 生命周期;不得拥有 Session 的事实生命周期
166
+ ```
167
+
168
+ ## 4. Instruction 模型
169
+
170
+ UI、测试和纯 JavaScript 必须使用同一套 Instruction API。
171
+
172
+ ### 4.1 Command
173
+
174
+ Command 请求当前 Activity 执行一项业务能力,但不天然表示完成当前节点。
175
+
176
+ ```ts
177
+ await session.dispatch({
178
+ type: 'command',
179
+ activityId: 'catalog',
180
+ command: 'selectProduct',
181
+ input: { productId: 'p1', quantity: 1 },
182
+ idempotencyKey: 'select:p1:1',
183
+ });
184
+ ```
185
+
186
+ 登录、选择商品、更新数量和流程内扫码通常属于 Command。
187
+
188
+ ### 4.2 Intent
189
+
190
+ Intent 请求当前 Activity 产生 Resolution,并可能触发节点迁移。
191
+
192
+ ```ts
193
+ await session.dispatch({
194
+ type: 'intent',
195
+ activityId: 'catalog',
196
+ intent: 'complete',
197
+ idempotencyKey: 'catalog:complete:1',
198
+ });
199
+ ```
200
+
201
+ Runtime 必须验证 Activity、当前 Step、Session Epoch、允许的 Command/Intent 和幂等键,调用方不能直接按 Operation ID 绕过 Activity Contract。
202
+
203
+ ## 5. Trigger 模型
204
+
205
+ ### 5.1 三个不同概念
206
+
207
+ ```text
208
+ Trigger Contract
209
+ 定义一种启动信号协议,例如 manual、onScan、onWeightChanged
210
+
211
+ Trigger Adapter
212
+ 在具体 Runtime 中连接按钮之外的外部来源,例如 device.subscribe
213
+
214
+ Trigger Occurrence
215
+ 某一次具体点击、扫码、称重边沿或定时到达
216
+ ```
217
+
218
+ Trigger 是创建新 Workflow Session 的桥梁,不负责向已有 Session 派发业务 Command。
219
+
220
+ 入口扫码与流程内扫码必须分离:
221
+
222
+ ```text
223
+ 没有活跃 Session:扫码 → onScan Trigger → 创建 barcodeScan Session
224
+ 已有业务 Session:扫码 → consumeBarcode Command → 当前 Session
225
+ ```
226
+
227
+ 称重同理:
228
+
229
+ ```text
230
+ Entry 阶段重量边沿 → onWeight Trigger → 创建 weighingProduct Session
231
+ Workflow 内持续读数 → updateWeight Command/Projection → 当前 Session
232
+ ```
233
+
234
+ ### 5.2 Workflow 默认 manual
235
+
236
+ 作者未声明 `start` 时,等价于绑定内置 `manual` Trigger:
237
+
238
+ ```ts
239
+ defineWorkflow({
240
+ id: 'quick',
241
+ steps,
242
+ });
243
+ ```
244
+
245
+ 等价于:
246
+
247
+ ```ts
248
+ defineWorkflow({
249
+ id: 'quick',
250
+ start: {
251
+ trigger: 'manual',
252
+ channel: 'quick',
253
+ },
254
+ steps,
255
+ });
256
+ ```
257
+
258
+ 默认值只允许存在于作者 DSL。Compiler 必须把它显式化到编译结果。
259
+
260
+ Manual 调用必须指定 Workflow,不能提供有歧义的 `application.start(payload)`:
261
+
262
+ ```ts
263
+ const session = await runtime.workflow('quick').start(payload);
264
+ ```
265
+
266
+ 内部仍统一转换为一次定向的 manual Trigger Occurrence。
267
+
268
+ ### 5.3 Trigger 节点是作者侧虚拟节点
269
+
270
+ 编排器可以把 Trigger 表现成开始节点,但它不能成为 Actor 中的普通 Step。Trigger 发生前 Session 尚不存在,不可能先创建 Actor 再等待一个负责创建 Actor 的节点。
271
+
272
+ ```text
273
+ 作者视图:Manual Start → Identity → Catalog → Payment
274
+ 编译结果:startBinding=manual/quick,initial=identity,nodes 不含 Trigger
275
+ ```
276
+
277
+ Trigger 不进入导航历史、completed steps 或 Activity Surface。
278
+
279
+ ## 6. Channel 与自动 Trigger 唯一绑定
280
+
281
+ ### 6.1 唯一地址
282
+
283
+ `triggerType + channel` 构成启动地址:
284
+
285
+ ```ts
286
+ defineWorkflow({
287
+ id: 'barcodeScan',
288
+ start: {
289
+ trigger: 'onScan',
290
+ channel: 'product',
291
+ },
292
+ steps,
293
+ });
294
+ ```
295
+
296
+ 当前强约束更简单:除内置 manual 外,一个自动 Trigger 只能属于一个 Workflow。
297
+ 即使 Channel 不同,重复绑定也在 Application 定义阶段失败。Channel 仍被保留为稳定的
298
+ 逻辑入口地址,避免未来扩展时改变 Trigger Occurrence 和 Session Cause 协议。
299
+
300
+ ### 6.2 Channel 不必来自原始设备事件
301
+
302
+ Channel 是 Application Runtime 的逻辑路由键,不要求物理事件天然携带它。
303
+
304
+ 原始称重事件通常只有:
305
+
306
+ ```ts
307
+ {
308
+ type: 'weightChanged',
309
+ grams: 1260,
310
+ deviceId: 'scale-1',
311
+ }
312
+ ```
313
+
314
+ 它没有 `channel` 并不影响当前实现。HDLKiosk Scale Trigger Adapter 在绑定时固定发出
315
+ `weighing-product` Channel;物理设备和 Workflow 不互相认识。
316
+
317
+ ### 6.3 称重事件实现
318
+
319
+ 同一把秤在当前 Runtime 中通常只有一个入口用途。由装配配置指定逻辑 Channel:
320
+
321
+ ```ts
322
+ createHDLKioskEntryTriggerAdapters(host, config)
323
+ ```
324
+
325
+ 对应 Workflow:
326
+
327
+ ```ts
328
+ defineWorkflow({
329
+ id: 'weighingProduct',
330
+ start: {
331
+ trigger: 'onWeight',
332
+ channel: 'weighing-product',
333
+ },
334
+ steps,
335
+ });
336
+ ```
337
+
338
+ 如果以后需要一个 Trigger 绑定多个 Workflow,必须新增显式路由/启动计划语义;当前不会
339
+ 根据 Channel、注册顺序或优先级自动推断。
340
+
341
+ ### 6.4 Trigger Adapter 单例与 Admission
342
+
343
+ 同一种物理 Trigger Adapter 在一个 Runtime 内只订阅一次,不能因为三个 Workflow 引用 `onWeight` 就注册三次设备监听。
344
+
345
+ Trigger 路由顺序:
346
+
347
+ ```text
348
+ External Event
349
+ → Adapter normalize/deduplicate
350
+ → resolve Channel
351
+ → find unique Workflow Binding
352
+ → Runtime Admission Policy
353
+ → create Session
354
+ → publish Session Started
355
+ ```
356
+
357
+ HDLKiosk 已有活跃 Session 时,入口 Trigger 默认被 Admission Policy 拒绝。Trigger 不会把事件自动转发给当前 Session;流程内事件必须通过显式 Command 通道处理。
358
+
359
+ ## 7. 自动 Trigger 启动后的 Session 获取
360
+
361
+ Manual start 可以直接返回 Session:
362
+
363
+ ```ts
364
+ const session = await runtime.workflow('quick').start(payload);
365
+ ```
366
+
367
+ 自动 Trigger 没有同步业务调用方,因此 Runtime 必须拥有 Session Registry 和可回放生命周期观察接口:
368
+
369
+ ```ts
370
+ runtime.sessions.subscribe((event) => {
371
+ if (event.type !== 'started') return;
372
+ const session = runtime.sessions.get(event.sessionId);
373
+ });
374
+
375
+ runtime.sessions.listActive();
376
+ runtime.sessions.findActive({ workflowId: 'barcodeScan' });
377
+ runtime.sessions.get(sessionId);
378
+ ```
379
+
380
+ Runtime 应先允许消费者订阅,再通过 `activate()` 激活自动 Trigger:
381
+
382
+ ```ts
383
+ const runtime = createApplicationRuntime(application, bindings);
384
+ const unsubscribe = runtime.sessions.subscribe(listener);
385
+ runtime.activate();
386
+ ```
387
+
388
+ 即使消费者晚到,也可以通过 `listActive()` 或 Runtime Snapshot 找回 Session,不能只依赖一次性事件。
389
+
390
+ Session started 事件至少包含:
391
+
392
+ ```ts
393
+ interface WorkflowSessionStartedEvent {
394
+ readonly type: 'started';
395
+ readonly sessionId: string;
396
+ readonly workflowId: string;
397
+ readonly workflowVersion: string;
398
+ readonly trigger: {
399
+ readonly type: string;
400
+ readonly channel: string;
401
+ readonly occurrenceId: string;
402
+ };
403
+ }
404
+ ```
405
+
406
+ Trigger Adapter 的 `emit()` 可以返回 `sessionId`、duplicate/rejected 状态供设备确认和遥测使用,但不把完整 Session Handle 暴露给 Adapter。Adapter 不负责继续驱动业务流程。
407
+
408
+ ## 8. Operation Contract 与 Handler 分离
409
+
410
+ 当前带 `execute` 的 Operation 同时承担协议和 Host 业务实现,必须拆分。
411
+
412
+ ### 8.1 Application 中的 Contract
413
+
414
+ ```ts
415
+ const cartAddProduct = defineOperationContract<
416
+ CartAddProductInput,
417
+ CartMutationResult
418
+ >({
419
+ id: 'cart.addProduct',
420
+ effect: 'write',
421
+ conflictScope: 'cart',
422
+ retry: 'explicit-user',
423
+ timeoutMs: 20_000,
424
+ });
425
+ ```
426
+
427
+ Contract 可以声明影响编排安全的稳定元数据:
428
+
429
+ - 输入/输出类型;
430
+ - read/write effect;
431
+ - conflict scope;
432
+ - timeout;
433
+ - retry/idempotency 语义;
434
+ - policy tags。
435
+
436
+ Contract 不包含 `execute`、Host、SDK 或数据库实例。
437
+
438
+ ### 8.2 Runtime 中的 Handler
439
+
440
+ ```ts
441
+ const cartAddProductHandler = bindOperation(
442
+ cartAddProduct,
443
+ async ({ services }, input, signal) =>
444
+ services.sales.addProduct(input, signal)
445
+ );
446
+ ```
447
+
448
+ Handler 负责:
449
+
450
+ - 调用 Host/SDK/HTTP/数据库;
451
+ - 具体一致性屏障;
452
+ - 错误归一;
453
+ - 写后验证;
454
+ - 生产实现差异。
455
+
456
+ 同一个 Definition 可以绑定 production、fake 和 simulation Handler。
457
+
458
+ ## 9. Trigger Contract 与 Adapter 分离
459
+
460
+ Application 只声明 Trigger 协议:
461
+
462
+ ```ts
463
+ const onWeight = defineTriggerContract<WeightOccurrence>({
464
+ id: 'onWeight',
465
+ mode: 'automatic',
466
+ });
467
+ ```
468
+
469
+ Runtime Binding 才允许订阅设备:
470
+
471
+ ```ts
472
+ const onWeightAdapter = bindTriggerAdapter(
473
+ onWeight,
474
+ ({ services, emit }) => services.scale.subscribe(/* ... */)
475
+ );
476
+ ```
477
+
478
+ `defineApplication()` 不执行 `subscribe()`;`runtime.activate()` 才安装订阅,`runtime.dispose()` 必须释放订阅。
479
+
480
+ 内置 `manual` Trigger 不需要 Adapter。
481
+
482
+ ## 10. Activity 与 UI 分离
483
+
484
+ 目标 Activity Contract:
485
+
486
+ ```ts
487
+ const catalog = defineActivity({
488
+ id: 'catalog',
489
+ commands: {
490
+ selectProduct: cartAddProduct,
491
+ consumeBarcode: barcodeConsume,
492
+ },
493
+ intents: {
494
+ complete: {
495
+ precondition: 'cart.notEmpty',
496
+ navigate: 'next',
497
+ },
498
+ },
499
+ });
500
+ ```
501
+
502
+ Activity 不强制声明 `surface.id`。React View 在独立 Presentation Binding 中注册。Activity 的数据读取应通过 Runtime Snapshot、Query/Projection Contract 或外部 selector 提供,不把 React Props 模型写入 Kernel。作者 API 已统一使用 `defineApplication()` 和中性的 Application/Slice 类型;Kernel 仅携带 `surfaceId`,不解释 Screen。
503
+
504
+ ## 11. 目标 API 草案
505
+
506
+ ```ts
507
+ const definition = defineApplication({
508
+ id: 'hdl-kiosk',
509
+ activities: [identity, catalog, paymentMethod, paymentCompleted],
510
+ workflows: {
511
+ quick,
512
+ barcodeScan,
513
+ weighingProduct,
514
+ },
515
+ triggers: [manual, onScan, onWeight],
516
+ operations: [
517
+ identityLogin,
518
+ cartAddProduct,
519
+ barcodeConsume,
520
+ checkoutOpen,
521
+ ],
522
+ policies: {
523
+ maxActiveSessions: 1,
524
+ },
525
+ });
526
+
527
+ const runtime = createApplicationRuntime(definition, {
528
+ operations: productionOperationHandlers,
529
+ triggers: {
530
+ onScan: scannerAdapter,
531
+ onWeight: weighingEntryAdapter,
532
+ },
533
+ predicates: productionPredicates,
534
+ services: { sales, devices, telemetry },
535
+ });
536
+
537
+ runtime.sessions.subscribe(renderOrObserveSession);
538
+ runtime.activate();
539
+
540
+ const quick = await runtime.workflow('quick').start({ locale: 'en' });
541
+
542
+ await quick.dispatch({
543
+ type: 'command',
544
+ activityId: 'catalog',
545
+ command: 'selectProduct',
546
+ input: { productId: 'p1' },
547
+ idempotencyKey: 'select:p1:1',
548
+ });
549
+ ```
550
+
551
+ ## 12. 编译和激活校验
552
+
553
+ ### 12.1 Definition 编译期
554
+
555
+ 至少校验:
556
+
557
+ - Workflow、Activity、Operation、Trigger ID 唯一;
558
+ - 所有引用已注册;
559
+ - 默认 manual 已显式化;
560
+ - `(triggerType, channel)` 唯一;
561
+ - 自动 Trigger Binding 有非空 Channel;
562
+ - manual Channel 可稳定定位 Workflow;
563
+ - Trigger 虚拟节点不进入 Actor nodes;
564
+ - Workflow initial、可达性、终点和 transition 合法;
565
+ - Activity Command 只引用 Operation Contract;
566
+ - Definition 不含 Presentation/Host 实现。
567
+
568
+ ### 12.2 Runtime 激活期
569
+
570
+ 至少校验:
571
+
572
+ - 所有非 manual Trigger Contract 有 Adapter;
573
+ - 所有 Operation Contract 有 Handler;
574
+ - Predicate/Guard Provider 完整;
575
+ - 一个 Trigger Adapter 不被重复激活;
576
+ - Runtime Profile 的静态 Channel 存在唯一 Workflow Binding;
577
+ - Adapter setup 失败时 Runtime 不进入 active;
578
+ - 已安装订阅在部分激活失败时全部回滚。
579
+
580
+ ### 12.3 Occurrence 运行期
581
+
582
+ 至少校验:
583
+
584
+ - occurrence ID 非空且在 Trigger 范围内幂等;
585
+ - Channel 路由结果唯一;
586
+ - Binding 存在;
587
+ - Admission Policy 允许新建 Session;
588
+ - payload 通过目标 Workflow start contract;
589
+ - Runtime 未 disposed;
590
+ - 同一 Occurrence 重放返回 duplicate/existing,不重复创建 Session。
591
+
592
+ ## 13. 安全不变量
593
+
594
+ 1. Trigger 只创建 Session,不驱动已有 Session 的业务 Command;
595
+ 2. 不能唯一选择 Workflow 时,一个 Session 都不创建;
596
+ 3. 不使用数组顺序、注册顺序或默认 priority 消除歧义;
597
+ 4. 同一 Trigger Adapter 在一个 Runtime 中至多一个有效订阅;
598
+ 5. Runtime 拥有 Session 生命周期,React 卸载不天然终止 Session;
599
+ 6. Command 必须通过当前 Activity Contract,不能直接执行任意 Operation ID;
600
+ 7. Application Definition 不持有 Host/SDK/React/设备实例;
601
+ 8. Operation Contract 与 Handler 分离;
602
+ 9. Trigger Contract 与 Adapter 分离;
603
+ 10. 自动启动的 Session 必须进入 Registry,并可由迟到消费者查询;
604
+ 11. Terminal 仅表示结构终点,业务完成条件由 Application Policy、Predicate 和 Operation 结果保证;
605
+ 12. Runtime dispose 后拒绝新的 Trigger、start 和 dispatch,并释放所有订阅与执行资源。
606
+
607
+ ## 14. 实际目录与依赖边界
608
+
609
+ ```text
610
+ kernel/
611
+ ├── application/ # 通用 Application、Slice、Trigger、Runtime/Registry 协议
612
+ ├── workflow/ # Compiler、Actor、Transition 原语
613
+ └── operations/ # 与业务无关的 Operation 调度原语
614
+
615
+ app/
616
+ ├── manifest.ts # HDLKiosk Application Definition 实例
617
+ ├── contracts/ # Application 对 Host/Runtime 的稳定业务端口
618
+ ├── operations.ts # HDLKiosk Operation Contracts,无 Handler
619
+ └── workflow/ # quick/barcode/scale 业务拓扑与策略
620
+
621
+ slices/ # 按 feature 并置 slice.ts 协议与 React View/Screen
622
+
623
+ runtime/
624
+ ├── createRuntime.ts # 绑定 Host 并产出可执行 Runtime
625
+ ├── triggers.ts # Scanner/Scale Trigger Adapter
626
+ ├── devices/ # 无 UI 设备 ingress、去重与 Scale Store
627
+ ├── operations/ # Host Operation Handler
628
+ └── session/ # Session/Actor/Context/Lifecycle 具体组合
629
+
630
+ ui/
631
+ ├── controllers/ # React 对 Runtime/Session 的适配
632
+ ├── entry/ # Workflow 外的手动入口 UI
633
+ ├── ScreenRenderer.tsx
634
+ └── views.ts # Activity → React View
635
+
636
+ components/ # 跨 Slice 的 common/shell/overlay 视觉组件
637
+ ```
638
+
639
+ 固定依赖方向是:
640
+
641
+ ```text
642
+ kernel ← app ← runtime ← ui
643
+ ↑ ↑
644
+ slices ───────────┘
645
+ ```
646
+
647
+ `app/contracts` 归 HDLKiosk Application 所有;`app` 可依赖通用 `kernel`,并且
648
+ 只通过 `slices/*/slice.ts` 使用 Activity 协议,不可依赖 `runtime` 或 React。
649
+ `runtime` 可依赖 `app/kernel` 并绑定具体 Host Port,但不可依赖 React。`ui` 和
650
+ `components` 是可选消费者。`architectureBoundary.test.ts`、
651
+ `kernel/dependencyBoundary.test.ts` 和 `components/dependencyBoundary.test.ts` 共同守住这些规则。
652
+
653
+ ## 15. 实现状态
654
+
655
+ 已经实现:
656
+
657
+ 1. 默认 manual、显式自动 Trigger 和当前唯一绑定校验;
658
+ 2. 无 React Application Runtime、统一启动管道、Session Registry、幂等和单会话准入;
659
+ 3. HDLKiosk manual/Scanner/Scale 的无头启动,Scanner/Scale 由 Runtime Adapter 直接订阅 Host;
660
+ 4. React Session Controller 改为 Runtime Adapter;
661
+ 5. Operation Contract 与 Runtime Handler 完全分离;
662
+ 6. Activity 的 Surface Contract 可选;
663
+ 7. 自动 Session 可通过 Registry 和 lifecycle event 获取。
664
+ 8. 物理目录已经按通用基础包、HDLKiosk App、无头 Runtime、React UI 分层;Slice 协议与 UI 按 feature 并置;
665
+ 9. 业务 Actor 集成测试移出 Kernel,Kernel 单元测试不再借用 HDLKiosk 错误模型。
666
+ 10. 作者 API 已去除 `Kiosk*` 命名,Kernel 中的 `screenId` 与 Checkout 专用字段已改为中性协议。
667
+
668
+ 仍需完成:
669
+
670
+ 1. 让 Runtime 在激活时显式校验全部 Operation Handler/Predicate Binding;
671
+ 2. 增加一个完整无 UI Command + Intent 到 Terminal 的 E2E。
672
+
673
+ ## 16. 验收标准
674
+
675
+ ### 16.1 无头执行
676
+
677
+ - 不加载 React 即可创建 Runtime;
678
+ - manual 启动 Quick 并通过 Command/Intent 完成流程;
679
+ - Fake Handler 能替换全部 Host Handler;
680
+ - Runtime Snapshot 与 React 环境一致。
681
+
682
+ ### 16.2 Trigger
683
+
684
+ - 未声明 Trigger 的 Workflow 编译为 manual;
685
+ - 多个 manual Workflow 可由显式 Workflow Handle 各自启动;
686
+ - 同一自动 Trigger 被两个 Workflow 引用时定义失败;
687
+ - 称重物理事件不带 Channel 仍能由 Adapter 启动唯一 Scale Workflow;
688
+ - 同一 occurrence 重放不重复创建 Session;
689
+ - Runtime dispose 后设备事件不能启动 Session。
690
+
691
+ ### 16.3 Session 获取
692
+
693
+ - manual start 直接返回 Session;
694
+ - automatic start 发布包含 occurrence correlation 的 started 事件;
695
+ - 晚挂载消费者可以从 Registry 找到活跃 Session;
696
+ - React 卸载/重挂不丢失 Runtime 拥有的 Session;
697
+ - HDLKiosk 单 Session Admission 在扫码、称重、manual 并发时只接受一个。
698
+
699
+ ### 16.4 解耦
700
+
701
+ - Kernel 不 import HDLKiosk contracts、React 或 BigSale;
702
+ - Application Definition 不出现 `execute`、`host`、React Component 或设备实例;
703
+ - Presentation 缺失不阻止无头 Workflow 执行;
704
+ - Operation/Trigger 的生产、Fake 和模拟 Binding 可互换。
705
+
706
+ ## 17. 首期明确决策
707
+
708
+ 以下决策在实施过程中不再重复开放:
709
+
710
+ 1. Workflow 默认 Trigger 是 manual;
711
+ 2. Manual API 始终显式选择 Workflow;
712
+ 3. Trigger 在作者侧可显示为节点,编译后是 start binding,不进入 Actor;
713
+ 4. Channel 是逻辑路由键,不要求来自物理事件;
714
+ 5. 当前一个自动 Trigger 只绑定一个 Workflow;
715
+ 6. Channel 由 Trigger Adapter 提供,不要求物理事件携带;
716
+ 7. 当前不支持 broadcast 或 Workflow 嵌套,未来扩展不得绕过统一启动管道;
717
+ 8. 自动 Session 通过 Runtime Registry 和生命周期事件暴露;
718
+ 9. Application Definition 声明 Contract,Runtime Binding 提供实现;
719
+ 10. UI 是可选 Presentation Adapter,不拥有业务执行和 Session 生命周期。