@pisell/private-materials 6.12.166 → 6.12.168

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 (115) 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.js +11 -11
  6. package/build/lowcode/view.js +11 -11
  7. package/es/components/HDLKiosk/app/ScreenRenderer.js +7 -7
  8. package/es/components/HDLKiosk/app/views.js +2 -1
  9. package/es/components/HDLKiosk/app/workflow/barcode.js +12 -35
  10. package/es/components/HDLKiosk/app/workflow/{guards.js → predicates.js} +9 -9
  11. package/es/components/HDLKiosk/app/workflow/quick.js +3 -6
  12. package/es/components/HDLKiosk/app/workflow/registry.js +1 -1
  13. package/es/components/HDLKiosk/app/workflow/scale.js +3 -12
  14. package/es/components/HDLKiosk/components/shell/HDLKioskBottomBarHost/index.js +12 -10
  15. package/es/components/HDLKiosk/components/shell/HDLKioskShell/index.js +1 -0
  16. package/es/components/HDLKiosk/docs/00-/346/226/207/344/273/266/345/257/274/350/210/252.md +7 -7
  17. 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 +47 -40
  18. 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 +3 -3
  19. package/es/components/HDLKiosk/docs/05-/344/272/244/346/230/223/345/256/211/345/205/250.md +1 -1
  20. package/es/components/HDLKiosk/docs/07-/345/220/216/347/273/255/345/267/245/344/275/234.md +1 -1
  21. package/es/components/HDLKiosk/docs/README.md +2 -2
  22. package/es/components/HDLKiosk/docs//345/256/236/346/226/275/350/277/233/345/272/246.md +3 -3
  23. package/es/components/HDLKiosk/docs//346/236/266/346/236/204/350/256/276/350/256/241.md +11 -11
  24. package/es/components/HDLKiosk/index.js +0 -1
  25. package/es/components/HDLKiosk/kernel/README.md +8 -9
  26. package/es/components/HDLKiosk/kernel/application/defineApplication.js +18 -19
  27. package/es/components/HDLKiosk/kernel/application/defineSlice.js +8 -13
  28. package/es/components/HDLKiosk/kernel/workflow/actor.js +118 -28
  29. package/es/components/HDLKiosk/kernel/workflow/compiler.js +35 -41
  30. package/es/components/HDLKiosk/kernel/workflow/selectors.js +9 -0
  31. package/es/components/HDLKiosk/runtime/HDLKioskWorkflowView.js +10 -9
  32. package/es/components/HDLKiosk/runtime/controllers/useHDLKioskCustomerController.js +1 -1
  33. package/es/components/HDLKiosk/runtime/createWorkflowSession.js +3 -3
  34. package/es/components/HDLKiosk/runtime/domainTransitionRunner.js +9 -9
  35. package/es/components/HDLKiosk/runtime/workflowEvent.js +9 -4
  36. package/es/components/HDLKiosk/runtime/workflowLifecycle.js +3 -3
  37. package/es/components/HDLKiosk/slices/catalog/PrimaryProductPromptDialog/index.js +1 -2
  38. package/es/components/HDLKiosk/slices/catalog/Screen/index.js +11 -38
  39. package/es/components/HDLKiosk/slices/catalog/Screen/model.js +1 -5
  40. package/es/components/HDLKiosk/slices/catalog/slice.js +4 -16
  41. package/es/components/HDLKiosk/slices/catalog/view.js +4 -6
  42. package/es/components/HDLKiosk/slices/customization/Screen/index.js +9 -11
  43. package/es/components/HDLKiosk/slices/customization/operation.js +23 -4
  44. package/es/components/HDLKiosk/slices/customization/slice.js +5 -9
  45. package/es/components/HDLKiosk/slices/customization/view.js +3 -2
  46. package/es/components/HDLKiosk/slices/fulfillment/Screen/index.js +6 -6
  47. package/es/components/HDLKiosk/slices/fulfillment/slice.js +5 -8
  48. package/es/components/HDLKiosk/slices/identity/Screen/index.js +18 -12
  49. package/es/components/HDLKiosk/slices/identity/slice.js +4 -11
  50. package/es/components/HDLKiosk/slices/index.js +3 -2
  51. package/es/components/HDLKiosk/slices/payment/Screen/index.js +5 -5
  52. package/es/components/HDLKiosk/slices/payment/slice.js +7 -8
  53. package/es/components/HDLKiosk/slices/primaryProductPrompt/slice.js +14 -0
  54. package/es/components/HDLKiosk/slices/primaryProductPrompt/view.js +23 -0
  55. package/es/components/HDLKiosk/utils.js +3 -2
  56. package/es/components/bigSale/templates/HDLKiosk/auth/HDLKioskIdentityAuthPanel.js +17 -2
  57. package/es/pro/Login2.0/Login2.d.ts +2 -0
  58. package/es/pro/Login2.0/Login2.js +9 -1
  59. package/es/pro/Login2.0/Register2.d.ts +2 -0
  60. package/es/pro/Login2.0/Register2.js +9 -1
  61. package/lib/components/HDLKiosk/app/ScreenRenderer.js +7 -7
  62. package/lib/components/HDLKiosk/app/views.js +2 -1
  63. package/lib/components/HDLKiosk/app/workflow/barcode.js +11 -34
  64. package/lib/components/HDLKiosk/app/workflow/{guards.js → predicates.js} +9 -9
  65. package/lib/components/HDLKiosk/app/workflow/quick.js +3 -6
  66. package/lib/components/HDLKiosk/app/workflow/registry.js +1 -1
  67. package/lib/components/HDLKiosk/app/workflow/scale.js +3 -12
  68. package/lib/components/HDLKiosk/components/shell/HDLKioskBottomBarHost/index.js +12 -10
  69. package/lib/components/HDLKiosk/components/shell/HDLKioskShell/index.js +1 -0
  70. package/lib/components/HDLKiosk/docs/00-/346/226/207/344/273/266/345/257/274/350/210/252.md +7 -7
  71. 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 +47 -40
  72. 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 +3 -3
  73. package/lib/components/HDLKiosk/docs/05-/344/272/244/346/230/223/345/256/211/345/205/250.md +1 -1
  74. package/lib/components/HDLKiosk/docs/07-/345/220/216/347/273/255/345/267/245/344/275/234.md +1 -1
  75. package/lib/components/HDLKiosk/docs/README.md +2 -2
  76. package/lib/components/HDLKiosk/docs//345/256/236/346/226/275/350/277/233/345/272/246.md +3 -3
  77. package/lib/components/HDLKiosk/docs//346/236/266/346/236/204/350/256/276/350/256/241.md +11 -11
  78. package/lib/components/HDLKiosk/index.js +0 -1
  79. package/lib/components/HDLKiosk/kernel/README.md +8 -9
  80. package/lib/components/HDLKiosk/kernel/application/defineApplication.js +18 -19
  81. package/lib/components/HDLKiosk/kernel/application/defineSlice.js +8 -14
  82. package/lib/components/HDLKiosk/kernel/workflow/actor.js +118 -28
  83. package/lib/components/HDLKiosk/kernel/workflow/compiler.js +35 -41
  84. package/lib/components/HDLKiosk/kernel/workflow/selectors.js +10 -0
  85. package/lib/components/HDLKiosk/runtime/HDLKioskWorkflowView.js +10 -9
  86. package/lib/components/HDLKiosk/runtime/controllers/useHDLKioskCustomerController.js +1 -1
  87. package/lib/components/HDLKiosk/runtime/createWorkflowSession.js +3 -3
  88. package/lib/components/HDLKiosk/runtime/domainTransitionRunner.js +9 -9
  89. package/lib/components/HDLKiosk/runtime/workflowEvent.js +9 -4
  90. package/lib/components/HDLKiosk/runtime/workflowLifecycle.js +3 -3
  91. package/lib/components/HDLKiosk/slices/catalog/PrimaryProductPromptDialog/index.js +1 -2
  92. package/lib/components/HDLKiosk/slices/catalog/Screen/index.js +13 -40
  93. package/lib/components/HDLKiosk/slices/catalog/Screen/model.js +0 -5
  94. package/lib/components/HDLKiosk/slices/catalog/slice.js +2 -15
  95. package/lib/components/HDLKiosk/slices/catalog/view.js +4 -6
  96. package/lib/components/HDLKiosk/slices/customization/Screen/index.js +9 -11
  97. package/lib/components/HDLKiosk/slices/customization/operation.js +23 -3
  98. package/lib/components/HDLKiosk/slices/customization/slice.js +3 -7
  99. package/lib/components/HDLKiosk/slices/customization/view.js +3 -2
  100. package/lib/components/HDLKiosk/slices/fulfillment/Screen/index.js +6 -6
  101. package/lib/components/HDLKiosk/slices/fulfillment/slice.js +4 -7
  102. package/lib/components/HDLKiosk/slices/identity/Screen/index.js +17 -11
  103. package/lib/components/HDLKiosk/slices/identity/slice.js +4 -11
  104. package/lib/components/HDLKiosk/slices/index.js +2 -1
  105. package/lib/components/HDLKiosk/slices/payment/Screen/index.js +5 -5
  106. package/lib/components/HDLKiosk/slices/payment/slice.js +6 -7
  107. package/lib/components/HDLKiosk/slices/primaryProductPrompt/slice.js +14 -0
  108. package/lib/components/HDLKiosk/slices/primaryProductPrompt/view.js +25 -0
  109. package/lib/components/HDLKiosk/utils.js +3 -2
  110. package/lib/components/bigSale/templates/HDLKiosk/auth/HDLKioskIdentityAuthPanel.js +16 -1
  111. package/lib/pro/Login2.0/Login2.d.ts +2 -0
  112. package/lib/pro/Login2.0/Login2.js +9 -1
  113. package/lib/pro/Login2.0/Register2.d.ts +2 -0
  114. package/lib/pro/Login2.0/Register2.js +9 -1
  115. package/package.json +4 -4
@@ -13,11 +13,11 @@ HDLKiosk Core 不是 BigSale 的另一套页面,也不是本地订单 Store。
13
13
  ↓
14
14
  Runtime Controller 决定是否启动会话或消费设备事件
15
15
  ↓
16
- Screen 内部动作走 Command;离开步骤才产生 Activity Outcome
16
+ Screen 内部动作走 Command;离开步骤产生 Activity Intent,返回产生 Navigation
17
17
  ↓
18
- Workflow Actor 根据 Outcome 选择静态 Transition并管理串行状态
18
+ Workflow Actor 根据 Intent 选择静态 Transition,并按页面历史处理 Back Navigation
19
19
  ↓
20
- HDLKiosk Transition Runner 执行本地 Guard / Exit Command并解释交易结果
20
+ HDLKiosk Transition Runner 求值本地 Predicate、执行 Exit Command 并解释交易结果
21
21
  ↓
22
22
  Operation Coordinator 安全执行 Screen Command 或 Exit Command
23
23
  ↓
@@ -36,7 +36,7 @@ Screen Renderer 根据当前节点与最新 Projection 渲染
36
36
  | 流程状态 | entry、nodeId、fulfillment 本地选择、session epoch | Workflow Runtime | 只回答“顾客处于哪一步”,不能证明订单已写成功 |
37
37
  | 展示输入 | options 选中项、搜索词、Modal 内选择 | Screen | 可以随页面销毁,不得成为结账依据 |
38
38
 
39
- 核心规则是“流程、命令与事实分离”:Screen Command/Exit Command 发起业务写入;writer receipt 证明本次写入完成了什么;Projection 提供当前 UI 可观察事实;Workflow Definition 只描述 Activity Outcome 到目标节点的关系。
39
+ 核心规则是“流程、命令与事实分离”:Screen Command/Exit Command 发起业务写入;writer receipt 证明本次写入完成了什么;Projection 提供当前 UI 可观察事实;Workflow Definition 只描述 Activity Intent 到目标节点的关系,Back Navigation 不写入 Definition。
40
40
 
41
41
  ## 2. 目录与运行时角色
42
42
 
@@ -49,10 +49,10 @@ Screen Renderer 根据当前节点与最新 Projection 渲染
49
49
  | [`app/workflow/`](../app/workflow) | 三入口业务编排与本地策略 | Activity 数组与特殊分支 | Quick/Barcode/Scale Definition | 流程顺序集中在应用目录,不和 Slice 实现混杂 |
50
50
  | [`runtime/createWorkflowSession.ts`](../runtime/createWorkflowSession.ts) | 一次点餐会话的组合根 | entry、Host、locale、可选 Lifecycle 扩展 | Kernel 与 HDLKiosk 业务实现的稳定组合 | 避免页面各自创建状态机或副作用执行器 |
51
51
  | [`app/workflow/registry.ts`](../app/workflow/registry.ts) | Activity Registry 类型视图 | Application Manifest | 带 HDLKiosk 字面量类型的 Registry | Runtime 不再维护第二份 Activity 清单 |
52
- | [`kernel/workflow/compiler.ts`](../kernel/workflow/compiler.ts) | Definition 结构校验 | Workflow Definition + 注入的 Registry | 冻结后的可执行 Definition 或 issues | 防止未知 Outcome、非法跳转和无界循环进入 Actor |
52
+ | [`kernel/workflow/compiler.ts`](../kernel/workflow/compiler.ts) | Definition 结构校验 | Workflow Definition + 注入的 Registry | 冻结后的可执行 Definition 或 issues | 防止未知 Intent、非法跳转和无界循环进入 Actor |
53
53
  | [`app/workflow/policy.ts`](../app/workflow/policy.ts) | HDLKiosk 业务策略校验 | 编译后的 Definition | 支付门禁等业务 issues | 结构规则不与具体交易策略混在一起 |
54
- | [`kernel/workflow/actor.ts`](../kernel/workflow/actor.ts) | 单会话流程执行器 | Activity Outcome、Definition、Runner | WorkflowSnapshot、Transition | 解决双击、乱序导航和 Exit Command 完成前跳页 |
55
- | [`runtime/domainTransitionRunner.ts`](../runtime/domainTransitionRunner.ts) | Activity 离开策略执行器 | Exit Policy、Host Projection、Coordinator | advance/stay/blocked、支付回执 | Actor 不理解 Guard、购物车和支付 Operation |
54
+ | [`kernel/workflow/actor.ts`](../kernel/workflow/actor.ts) | 单会话流程执行器 | Activity Intent、Navigation、Definition、Runner | WorkflowSnapshot、Transition | 解决双击、乱序导航和 Exit Command 完成前跳页 |
55
+ | [`runtime/domainTransitionRunner.ts`](../runtime/domainTransitionRunner.ts) | Activity 离开策略执行器 | Exit Policy、Host Projection、Coordinator | advance/stay/blocked、支付回执 | Actor 不理解 Predicate、购物车和支付 Operation |
56
56
  | [`runtime/workflowLifecycle.ts`](../runtime/workflowLifecycle.ts) | 已提交状态的业务生命周期出口 | Actor 提交后的 Snapshot | telemetry | 诊断不进入状态机内核 |
57
57
  | [`kernel/operations/coordinator.ts`](../kernel/operations/coordinator.ts) | 通用副作用调度器 | Operation request + 应用 Policy | 规范化 OperationResult | 解决重复 intent、排队、超时和旧 Promise;不认识支付 |
58
58
  | [`app/operations.ts`](../app/operations.ts) | 共享 Operation 公共入口 | 跨 Slice Operation 与执行策略 | 稳定的统一导出面 | 避免消费者穿透私有实现目录 |
@@ -172,34 +172,39 @@ Workflow 用有序 Slice 数组描述静态编排。数组顺序是默认主路
172
172
  {
173
173
  id: 'hdl.barcode',
174
174
  steps: [
175
+ catalogSlice,
175
176
  {
176
- slice: catalogWithPrimaryProductPromptSlice,
177
- on: { completed: 'paymentMethod' },
177
+ slice: primaryProductPromptSlice,
178
+ presentation: { mode: 'modal' },
179
+ visitPolicy: 'once',
180
+ on: { omit: 'fulfillment' },
178
181
  },
179
- { slice: customizationSlice, on: { completed: 'catalogWithPrimaryProductPrompt' } },
180
- { slice: paymentMethodSlice, on: { back: 'catalogWithPrimaryProductPrompt' } },
181
- // ...
182
+ customizationSlice,
183
+ fulfillmentSlice,
184
+ paymentMethodSlice,
182
185
  { slice: paymentCompletedSlice, end: 'success' },
183
186
  ],
184
187
  }
185
188
  ```
186
189
 
187
- Workflow 作者不会填写 Screen、Guard、Operation 或 failureTarget;这些由 Slice 引用带入本地可信 Manifest。Compiler 使用的规范化结构只保留 Activity ID、presentation 与目标,不携带 React 组件、Host 方法或订单对象。Quick、Barcode、Scale 的差异只保留在 [`app/workflow/`](../app/workflow)。
190
+ Workflow 作者不会填写 Screen、Predicate、Operation 或 failureTarget;这些由 Slice 引用带入本地可信 Manifest。Compiler 使用的规范化结构只保留 Activity ID、presentation 与目标,不携带 React 组件、Host 方法或订单对象。Quick、Barcode、Scale 的差异只保留在 [`app/workflow/`](../app/workflow)。
188
191
 
189
192
  四个概念必须分开:
190
193
 
191
- - **Slice**:开发者定义的完整业务能力,包含 Screen、Outcome、Command 和退出 Effect;
194
+ - **Slice**:开发者定义的完整业务能力,包含 Screen、Intent、Command 和退出 Effect;
192
195
  - **Activity**:Slice 暴露给 Actor 的无 UI 运行契约,例如 `catalog`;
193
196
  - **Step**:Activity 在一条流程中的一次出现,是编排和运行时定位的稳定位置;
194
197
  - **Screen**:Activity 的本地 UI 实现,不属于 Workflow Definition。
195
198
 
196
199
  Slice 在一条流程只出现一次时,Step ID 默认就是 Slice ID;同一 Slice 多次出现时,每次必须显式使用 `slice:用途`,例如 `catalog:initial`、`catalog:final`。这样既保持常规流程易读,也不会把复用能力误认为同一个运行位置。
197
200
 
198
- Slice Outcome 使用 `next()` / `back()`,或在 `guard/effect` 上声明 `navigate`,决定相邻 Step 的默认移动。不会移动的 Outcome 只在 Workflow `on` 中指定特殊目标。没有下一项的 Step 不会被推测为成功,必须声明 `end: 'success' | 'blocked'`。
201
+ Slice Intent 使用 `next()`,或在 `intentPrecondition/effect` 上声明 `navigate: 'next'`,决定相邻 Step 的默认移动。不会自动前进的 Intent 只在 Workflow `on` 中指定目标。Back 是独立 Navigation,由 Actor 的实际页面历史解析。没有下一项的 Step 不会被推测为成功,必须声明 `end: 'success' | 'blocked'`。
199
202
 
200
- 条件式步骤在 Slice `guards` 中声明本地纯函数,Workflow occurrence 使用 `{ slice: identitySlice, useGuards: ['beforeEnter'] }` 选择启用阶段。Application 为函数生成稳定 Guard ID;编译后 Node 只保留 `guardPhases` 数组,不保留函数或 Guard ID。Actor 的全局 `beforeEach` 管线在初始进入、前进、后退和显式目标跳转时都接收 `to` / `from` / `direction`。守卫返回结构化决策 `allow | skip | cancel | redirect | defer | block`;`skip` 才会按当前方向继续解析,不再用含义模糊的 boolean。Kernel 不读取 Identity、Fulfillment 等业务名称。
203
+ Predicate 是本地可信的纯真假判断,例如 `cart.notEmpty`;Intent Precondition 表示某个 Intent 提交前必须满足的 Predicate。作者 API 使用 `intentPrecondition(predicateId)`,底层行为记录 `{ kind: 'precondition', predicate }`,编译后存入 `exitPolicy.precondition`。Predicate 只返回 boolean;它与能返回 `allow | bypass | cancel | redirect | defer | block` 的 Navigation Guard 是两套独立能力。
201
204
 
202
- Actor 记录的是已成功向前离开的 **Step ID**,而不是 Slice ID。因此同一 Slice 可在 Flow 中出现多次,每个 occurrence 都可独立声明 `useGuards`;第一个被守卫跳过,不会影响第二个未启用守卫的 Step。导航在执行 Activity Exit Effect 之前完成解析;被 cancel/defer 的导航不会先写 Host。
205
+ 业务 Workflow 当前不启用 Slice `beforeEnter` 守卫。Actor 仍保留全局 `beforeEach` 管线,用于 `sessionExit` 等会话安全策略;它不承载 Identity、Fulfillment 等步骤的业务进入条件。
206
+
207
+ Actor 分别记录已成功向前离开的 Step、每个 Step 已提交的 `complete | omit` Resolution,以及用户实际访问过的页面历史。`complete` 保留页面的 Back 路径;`omit` 表示将该 Step 从当前流程路径中排除,后续遇到时沿已提交的 `omit` transition 继续,也不写入 Back 历史。Modal 不写入页面历史;历史为空时 Back 进入会话退出导航。Workflow occurrence 只有 `visitPolicy: 'always' | 'once'`:`always` 保留已 `complete` Step 的正常访问,`once` 表示任意 Resolution 提交后不再进入且不写入 Back 历史。用户通过 Back 退出一个已解决页面时,其旧 Resolution 失效。导航在执行 Activity Exit Effect 之前完成解析;被 cancel/defer 的导航不会先写 Host。
203
208
 
204
209
  退出流程也是导航目标 `{ kind: 'sessionExit' }`。全局 `beforeEach` 对它返回 `defer({ kind: 'confirmEndOrder' })`,Actor 保存带唯一 `navigationId` 的 `pendingNavigation`。Shell 只根据该 request 展示确认;旧 ID 不能恢复后来的导航。
205
210
 
@@ -210,38 +215,38 @@ Step ID 只标识“一次出现”。Runtime 判断加载哪类数据、是否
210
215
  [`slices/<name>/slice.ts`](../slices) 是本地可信 Slice 定义,每个 Slice 声明:
211
216
 
212
217
  - 业务 Activity 使用哪个 `screen.id`,以及该 Screen 的 `view`;
213
- - 可以产生哪些 Outcome;
218
+ - 可以接受哪些 Intent;
214
219
  - 支持 page 还是 modal;
215
- - 某个 Outcome 是否需要纯 Guard;
220
+ - 某个 Intent 是否需要纯 Predicate 作为 Precondition;
216
221
  - 离开 Slice 前是否需要执行 Effect;
217
222
  - Screen 内有哪些不会离开节点的 Command;
218
223
  - 使用该 Slice 的流程在支付前需要哪些业务事实。
219
224
 
220
- 例如 `identity.skipped` 的本地 Exit Policy 执行 `identity.sync`,`customization.completed` 检查 `customization.primaryReady`,`paymentMethod.cardSelected` 执行 `checkout.open`。`defineKioskApplication` 从 Slice 自动生成 Activity Contract 与 Operation 注册信息;未来后台只会看到 `Slice ID + Outcome → target`,不能替换这些安全规则。
225
+ 例如 `identity.complete` / `identity.omit` 可在携带输入时执行 `identity.sync`,`customization.complete` 执行主商品同步,`paymentMethod.complete` 检查 Host 已确认支付成功。EFTPOS 派发和店员支付授权是 Payment 页面 Command,不作为流程 Intent。`defineKioskApplication` 从 Slice 自动生成 Activity Contract 与 Operation 注册信息;远端定义只看到 `Slice ID + 标准 Intent → target`,不能替换这些安全规则。
221
226
 
222
227
  Slice 的业务定义与 React View 分离:Slice `id` 是 Workflow 和 Actor 使用的业务 Activity;`screen.id` 会被 Compiler 复制为 Workflow Node 的 `screenId`,供 Shell、Controller 和数据加载策略使用;`app/views.ts` 按 Activity 注册本地可信 View。各 Slice 的 `view.tsx` 仍负责 ViewModel 派生与组件装配,但不会进入 `defineSlice` 或 Workflow Definition。
223
228
 
224
229
  | Slice 定义 | 编译/运行期形态 | 唯一用途 |
225
230
  | --- | --- | --- |
226
- | `id` | Node `activity` | 业务状态、Outcome 和流程编排 |
231
+ | `id` | Node `activity` | 业务状态、Intent 和流程编排 |
227
232
  | `screen.id` | Node `screenId` | Shell 变体、数据加载和页面类别判断 |
228
233
  | `app/views.ts` 中的 Activity 映射 | 仅应用展示层使用 | React UI 渲染 |
229
234
 
230
- 因此 `id`、`screen` 和 `view` 不互相替代:`catalogWithPrimaryProductPrompt` 与 `catalog` 是两个 Slice ID,但共享 `screen.id = 'catalog'` 和同一个 View。店员支付授权不改变当前页面,因此是 `paymentMethod` 的 Screen Command,而不是独立 Activity。Application Manifest 是业务运行 Contract 的唯一索引,`app/views.ts` 是展示实现的唯一索引。View 使用同步本地组件引用,不产生运行期 UI chunk;纯 Compiler/Actor 依赖链也不会加载该注册表。Renderer 若发现 View 缺失,仍使用 `BlockingNotice` fail closed,且不会改变 Workflow。
235
+ 因此 `id`、`screen` 和 `view` 不互相替代:`catalog` 是商品浏览页面,`primaryProductPrompt` 是覆盖在 Catalog 上的独立 Modal Slice。店员支付授权不改变当前页面,因此是 `paymentMethod` 的 Screen Command,而不是独立 Activity。Application Manifest 是业务运行 Contract 的唯一索引,`app/views.ts` 是展示实现的唯一索引。View 使用同步本地组件引用,不产生运行期 UI chunk;纯 Compiler/Actor 依赖链也不会加载该注册表。Renderer 若发现 View 缺失,仍使用 `BlockingNotice` fail closed,且不会改变 Workflow。
231
236
 
232
237
  `slices/index.ts` 对整套 Slice 清单执行一次类型约束:`screen.id` 只能取 HDLKiosk 的非 Entry `ScreenId`。`app/views.ts` 使用完整的 `Record<ActivityId, HDLKioskSliceView>`,因此新增 Activity 若没有注册 View 会产生类型错误。Kernel 的 `defineSlice` 同时拒绝空 `screen.id`。
233
238
 
234
239
  Compiler 从实际使用的 Slice 汇总 Checkout Requirement ID,但不把判断函数或 Host 字段写入 Workflow。当前 HDLKiosk 默认注册表为空;未来增加其他业务要求时仍由 [`checkoutRequirements.ts`](../app/operations/checkoutRequirements.ts) 集中判断。
235
240
 
236
- `WorkflowEvent` 同时约束 Activity、Outcome 和必要输入:例如 `identity.skipped` 必须携带身份输入,`fulfillment.completed` 必须携带 fulfillment context patch。Barcode 入口的条码输入不是 Workflow Event,而是 Session Controller 在发布会话前交给 `barcode.consume` 的 Command 输入。Screen Command 由 `OperationInputMap` 约束 Command ID 与输入类型,不再通过 `unknown` 保持隐式默契。
241
+ `WorkflowEvent` 同时约束 Activity、Intent 和必要输入:例如 `identity.omit` 必须携带身份输入,`fulfillment.complete` 必须携带 fulfillment context patch。Back 使用不携带业务输入的 `NAVIGATE_BACK`。Barcode 入口的条码输入不是 Workflow Event,而是 Session Controller 在发布会话前交给 `barcode.consume` 的 Command 输入。Screen Command 由 `OperationInputMap` 约束 Command ID 与输入类型。
237
242
 
238
243
  Step 可选声明 Modal 展示关系:
239
244
 
240
245
  ```ts
241
- presentation: { mode: 'modal', base: 'customization' }
246
+ presentation: { mode: 'modal' }
242
247
  ```
243
248
 
244
- 这只控制渲染层级。Compiler 会拒绝缺失、自引用或嵌套 Modal base。
249
+ 这只控制渲染层级。Actor Surface 保留进入 Modal 前实际展示的 Page,Workflow 不指定背景 Step。Compiler 会拒绝以 Modal 作为首节点或 Modal 直接进入另一个 Modal。
245
250
 
246
251
  ### 6.3 结构 Compiler 与业务 Policy 校验
247
252
 
@@ -249,7 +254,7 @@ presentation: { mode: 'modal', base: 'customization' }
249
254
 
250
255
  - workflow id、Step 数组及数量/transition 上限;
251
256
  - Activity 是否存在;重复 Activity 是否具有稳定且不冲突的 Step ID;
252
- - Outcome 是否由 Activity Contract 暴露;
257
+ - Intent 是否由 Activity Contract 暴露;
253
258
  - Definition 是否夹带 screen/guard/operation/failureTarget;
254
259
  - 默认相邻导航和显式 target 是否有效,所有 Step 是否从首项可达;
255
260
  - 无后继 Step 是否声明结束语义,首项是否能到达成功终点;
@@ -264,16 +269,16 @@ session 创建前完成,但结构错误与业务安全错误保持独立。
264
269
 
265
270
  数组天然只有一个首项;不可达 Step 会被拒绝。显式业务回路必须声明 `repeat.max`,Actor 按会话计数,超过限制进入阻塞态。普通 Back 属于用户导航,不计入业务回路限制。校验通过后,Compiler 把数组转成 Actor 查询高效的冻结节点 Map;运行中的 session 不替换 Definition。
266
271
 
267
- ### 6.4 Actor 如何处理 Activity Outcome
272
+ ### 6.4 Actor 如何处理 Activity Intent 与 Navigation
268
273
 
269
274
  Actor 使用单 mailbox:
270
275
 
271
276
  1. 忽略 success end、blocked 或 disposed 后的新事件;
272
277
  2. 同时校验事件的 `stepId` 和 `activityId`,拒绝旧 Screen 或同类 Activity 旧实例的迟到回调;
273
- 3. 校验 Outcome 是否由当前 Activity 暴露,并查找 Transition;
278
+ 3. 校验 Intent 是否由当前 Activity 暴露,并查找 Transition;Back 则读取页面历史;
274
279
  4. 通过注入的 Context Reducer 合并受限 contextPatch;
275
280
  5. 把 Exit Policy 交给 HDLKiosk Transition Runner;
276
- 6. Runner 用最新 Sales Projection 执行 Guard,并通过 Coordinator 执行 Exit Command;
281
+ 6. Runner 用最新 Sales Projection 求值 Precondition Predicate,并通过 Coordinator 执行 Exit Command;
277
282
  7. Runner 将结果归一为 `advance / stay / blocked`,支付成功回执也由 Runner 解释;
278
283
  8. Actor 只负责提交 target、当前 Step 或 blocked,并清理 active operation;
279
284
  9. 已提交 Snapshot 交给 Workflow Lifecycle 记录 telemetry;外层可组合额外观察器。
@@ -301,7 +306,7 @@ Coordinator 现在有两个明确调用来源:
301
306
  - Screen Command:Catalog 加购、Cart Overlay 数量修改、称重草稿同步等;由 `session.executeCommand` 执行,成功后 Actor 节点不变;
302
307
  - Activity Exit Command:Guest 同步、Checkout Prepare/Open 等;由 Transition Runner 从本地 Exit Policy 发起,只有 succeeded 才允许 Actor 转移。
303
308
 
304
- partialFailure/unknown 的 Screen Command 会通过 Actor 的 system block 入口 fail closed;它不是伪造一个 Activity Outcome。
309
+ partialFailure/unknown 的 Screen Command 会通过 Actor 的 system block 入口 fail closed;它不伪造 Activity Intent。
305
310
 
306
311
  当前 Operation 组:
307
312
 
@@ -313,6 +318,7 @@ partialFailure/unknown 的 Screen Command 会通过 Actor 的 system block 入
313
318
  | `cart.addProduct` | cart | — | 调宿主商品 Flow,等待规格或其它业务选择后验证写入 |
314
319
  | `cart.update/remove` | cart | 15s | 数量修改/删除、summary 重算和目标行验证 |
315
320
  | `product.syncPrimaryWeightedProduct` | cart | — | 首次写入可能等待 OS 额外业务弹窗;更新或写入后验证重量/options 和写后证据 |
321
+ | `product.removePrimaryProduct` | cart | 15s | 将主商品置为不存在;本来不存在时直接成功,存在时验证删除结果 |
316
322
  | `checkout.prepare*` | checkout | 20s | fulfillment、cart、summary 稳定性与 token |
317
323
  | `checkout.open` | checkout | 120s | 消费 token、冻结危险写并打开 Host 支付 |
318
324
 
@@ -389,22 +395,22 @@ Host command
389
395
  - 尚无活跃或启动中的 session;
390
396
  - 支付状态未冻结。
391
397
 
392
- 通过 ScannerIngress/ScaleIngress 完成 eventId 去重、阈值检查和拒绝原因遥测。Device Controller 不向 Actor 发送 `detected` Outcome;Barcode 把条码作为 start request 的一部分,Scale 只发起 Scale session。
398
+ 通过 ScannerIngress/ScaleIngress 完成 eventId 去重、阈值检查和拒绝原因遥测。Device Controller 不向 Actor 发送流程 Intent;Barcode 把条码作为 start request 的一部分,Scale 只发起 Scale session。
393
399
 
394
400
  ### 8.3 Customer Controller
395
401
 
396
- Identity 节点内的登录是 Activity Outcome,不是 Screen 直接写订单:
402
+ Identity 节点内的登录是 Activity Intent,不是 Screen 直接写订单:
397
403
 
398
404
  ```text
399
405
  BigSale Login2/Register2
400
406
  → 暂存已认证 customer
401
- → identity.memberRecognized(customerId)
407
+ → identity.complete(customerId)
402
408
  → identity.sync Exit Effect
403
409
  → Adapter customer.select + consistency + repricing
404
410
  → 成功后进入下一节点
405
411
  ```
406
412
 
407
- 认证 UI 通过 HDLKiosk 应用展示层插槽注入,不进入 `defineSlice`、View 注册表或 Kernel。Slice 只声明 `memberRecognized` 在携带输入时执行 `identity.sync`;已登录客户的自动略过不携带输入,因此不会重复写客户。
413
+ 认证 UI 通过 HDLKiosk 应用展示层插槽注入,不进入 `defineSlice`、View 注册表或 Kernel。Slice 的 `complete` 在携带输入时执行 `identity.sync`;已登录客户的自动略过使用 `omit` 且不携带输入,因此不会重复写客户。
408
414
 
409
415
  Shell 登录不是 Workflow 跳转,而是 session-level 插入 Operation:
410
416
 
@@ -421,7 +427,7 @@ Shell Login
421
427
 
422
428
  ### 8.4 Screen Data Controller
423
429
 
424
- 只在相关节点加载 Catalog、Weighted Product 或 Customization DTO;使用 AbortController 防止离开页面后的结果写回。Modal Step 通过 `presentation.base` 继续复用底层页面数据,避免称重读数和 options 被重置。
430
+ 只在相关节点加载 Catalog、Weighted Product 或 Customization DTO;使用 AbortController 防止离开页面后的结果写回。Modal 激活时,Screen Data Controller 继续使用 Actor Surface 中保留的 `pageStepId`,底层 Page 保持挂载和原数据,不按 Modal Activity 清空或重新加载。
425
431
 
426
432
  ### 8.5 返回 Entry 能力接口
427
433
 
@@ -475,8 +481,9 @@ HDLKiosk root
475
481
  → components/shell + components/overlays + components/common
476
482
  → Activity Action callback
477
483
  → HDLKioskWorkflowView
478
- ├─ Outcome → Workflow Actor
479
- │ → HDLKiosk Transition Runner(Guard / Exit Command)
484
+ ├─ Intent → Workflow Actor
485
+ ├─ Back → Workflow Navigation
486
+ │ → HDLKiosk Transition Runner(Predicate / Exit Command)
480
487
  ├─ Command → session.executeCommand → Coordinator
481
488
  └─ Session Action → reset controller
482
489
  ```
@@ -499,7 +506,7 @@ Screen 只做三件事:
499
506
 
500
507
  1. 渲染 View DTO;
501
508
  2. 维护局部输入;
502
- 3. 内部业务写入发送 Screen Command,离开步骤发送 Activity Outcome。
509
+ 3. 内部业务写入发送 Screen Command,离开步骤发送 Activity Intent,返回发送 Navigation。
503
510
 
504
511
  Screen 不得:
505
512
 
@@ -515,13 +522,13 @@ CartDrawer 也遵循“Screen 声明、Shell 挂载”:Screen 只请求打开
515
522
 
516
523
  Customization 的规格 UI 通过 `components/common/HDLKioskSkuOptionsSelection` 接入共享 `skuOptionsSelection`。查询所得 ProductData 本身直接作为 `dataSource`,兼容层不再复制或重命名 option group/item,只在选择器 `SkuValue` 与业务命令所需 `HDLProductOptionSelection[]` 之间转换“用户选中结果”。临时独立运行缺少 Engine 上下文时,退化为直接读取同一 `option_group/option_item` 的单选控件。
517
524
 
518
- 称重主商品在 Customization 中先保持页面本地草稿。重量或 options 变化不写 Host;点击 Next 时才将当下完整草稿作为 `customization.completed` 的 Exit Effect 交给 `product.syncPrimaryWeightedProduct`。OS 完成其内部业务判断并返回加购成功,且 writer receipt/Projection 验证通过后,Actor 才进入下一节点。失败或取消留在当前页面,`partial/unknown` 阻断。底栏和 Drawer 仍只消费 Host `summary.due/cart.lines`,不在本地构造未确认的购物车。
525
+ 称重主商品在 Customization 中先保持页面本地草稿。重量或 options 变化不写 Host;点击 Next 时才将当下完整草稿作为 `customization.complete` 的 Exit Effect 交给 `product.syncPrimaryWeightedProduct`。OS 完成其内部业务判断并返回加购成功,且 writer receipt/Projection 验证通过后,Actor 才进入下一节点。失败或取消留在当前页面,`partial/unknown` 阻断。底栏和 Drawer 仍只消费 Host `summary.due/cart.lines`,不在本地构造未确认的购物车。
519
526
 
520
527
  Workflow View 负责控制器组合、自动推进和会话级 Dialog;Renderer 只负责选择要展示的组件。普通 `cart.add/update/remove` 和防抖的 `product.syncPrimaryWeightedProduct` 是 Screen Command,保持当前 Activity 挂载,只禁用冲突操作,不产生 transition;会员重报价和 Checkout 等 Activity Exit Command 才阻断整个 surface。
521
528
 
522
529
  OS 加购过程中的内部弹窗和业务判断不属于 HDLKiosk Activity、Host Contract 或 Checkout Requirement。HDLKiosk 不读写相关业务事实,只根据主商品加购操作的最终结果决定是否跳转。
523
530
 
524
- Barcode 的主商品询问采用相同原则,但它属于 `catalogWithPrimaryProductPrompt` Activity 的局部 Dialog:No 产生 `completed`,Yes 产生 `primaryProductRequested`。是否打开 Dialog 只由当前购物车是否包含主商品决定,不形成 `primaryProductPrompt` Workflow 节点。
531
+ Barcode 的主商品询问是独立 `primaryProductPrompt` Modal Slice:Yes 发出 `complete`,No 发出 `omit`。Prompt 声明 `visitPolicy: 'once'`,因此任一选择成功提交后不再询问;关闭 Modal 只执行 Back,没有 Resolution,下次仍会展示。Customization 使用缺省 `always`:`complete` 后保留 Back 编辑能力;`omit` 会先通过本地 Exit Effect 删除已有主商品,再将该 Step 从后续路径和 Back 历史中排除。
525
532
 
526
533
  ## 11. 四条端到端调用链
527
534
 
@@ -26,7 +26,7 @@ Entry → Identity → Customization → Catalog → Fulfillment
26
26
  → Payment Method / Payment Completed → Entry
27
27
  ```
28
28
 
29
- - Identity Slice 在 `guards.beforeEnter` 中声明进入条件,Quick 只在该 occurrence 配置 `useGuards: ['beforeEnter']`。本 Step 登录或 Skip 成功后守卫返回 `skip`,因此后退会跳过它。Fulfillment Back 因没有更早的可进入 Step,导航目标变为 `sessionExit`;全局守卫返回 `defer(confirmEndOrder)` 并打开结束订单确认。确认后返回 Entry,取消则留在当前页。
29
+ - Quick 的 Identity occurrence 显式声明 `visitPolicy: 'once'`。登录或 Omit 成功后,该 Step 在本会话不再进入,也不写入 Back 页面历史。当没有更早的已访问页面时,Back 的导航目标为 `sessionExit`;全局会话策略返回 `defer(confirmEndOrder)` 并打开结束订单确认。确认后返回 Entry,取消则留在当前页。
30
30
  - Fulfillment 统一位于 Payment 之前确认堂食/外带。
31
31
  - Customization 只在稳定正净重且必选 options 完整时启用 Next。
32
32
  - “I don't need Malatang” 直接跳过主商品并进入 Catalog;如果正在编辑已确认主商品,则先移除该行。
@@ -67,7 +67,7 @@ Entry 消费第一个有效重量边沿后启动以 Fulfillment 为首节点的
67
67
 
68
68
  ## 6. 会员中途插入
69
69
 
70
- Identity 的 Skip 只表示当前以 Guest 继续。Shell 可在本地策略允许的页面执行 `identity.sync`。登录、Customer 写入、重报价和 Projection 验证成功后仍留在原节点;`partial`/`unknown` 不得带着未确认价格继续。
70
+ Identity 的 Omit 只表示当前以 Guest 继续。Shell 可在本地策略允许的页面执行 `identity.sync`。登录、Customer 写入、重报价和 Projection 验证成功后仍留在原节点;`partial`/`unknown` 不得带着未确认价格继续。
71
71
 
72
72
  ## 7. UI 和修改规则
73
73
 
@@ -76,6 +76,6 @@ Identity 的 Skip 只表示当前以 Guest 继续。Shell 可在本地策略允
76
76
  - 尺寸校准以上线环境的实际渲染值反推:当 72px 在目标倍率下实测为 100px,而原型目标为 108px 时,当前自有视觉值统一乘以 `108 / 100 = 1.08`;外部生产组件不参与这一次修正。
77
77
  - Screen 不得直接 import BigSale/SalesSDK,也不本地计算最终金额。
78
78
  - Screen 内部写操作使用 Screen Command;离开节点的写操作使用 Activity Exit Effect。
79
- - `product.syncPrimaryWeightedProduct` 属于 Customization `completed` 的 Exit Effect,不是输入变化时的 Screen Command。
79
+ - `product.syncPrimaryWeightedProduct` 属于 Customization `complete` 的 Exit Effect,不是输入变化时的 Screen Command。
80
80
  - Shell 的购物车、金额和 Drawer 只消费 Host 已确认 Projection。
81
81
  - 调整节点顺序时同步更新 Workflow Definition、compiler/definition/actor/Screen 测试和实施进度。
@@ -31,7 +31,7 @@ Host 无法证明写后事实时,Operation 不能返回 succeeded。Cart 和 C
31
31
 
32
32
  ## 3. Checkout Prepared Freshness
33
33
 
34
- Prepare 不是某个页面之前或某个 Workflow outcome 的固定副作用。Checkout Coordinator 把它作为所有支付 dispatch 的前置条件,对当前事实版本执行 `ensurePrepared(currentVersion)`。
34
+ Prepare 不是某个页面之前或某个 Workflow Intent 的固定副作用。Checkout Coordinator 把它作为所有支付 dispatch 的前置条件,对当前事实版本执行 `ensurePrepared(currentVersion)`。
35
35
 
36
36
  事实版本至少包括 session epoch、cart fingerprint、customer/voucher/promotion revision、Summary 应付金额/币种、Requirement 集合和支付能力上下文。状态为:
37
37
 
@@ -35,7 +35,7 @@
35
35
  ### P1-1 商品和 Catalog
36
36
 
37
37
  - 将模板内临时固定商品 ID 改为租户/门店正式称重商品配置;商品结构已经切换为 OS `queryProducts`,不得恢复本地 fallback;
38
- - 确认 Quick 是否允许跳过称重主商品;若不允许,从 `customization` Activity Contract/Workflow 中删除 `skipped` Outcome;
38
+ - 确认 Quick 是否允许排除称重主商品;若不允许,从 `customization` Activity Contract/Workflow 中移除 `omit` Intent;
39
39
  - 大目录分页/虚拟滚动与分类切换性能;分类、子分类和本地搜索首版已完成;
40
40
  - 缺货、下架、菜单不可用、价格变化;
41
41
  - Barcode 细分 added/requiresSelection/notFound/cancelled;
@@ -9,7 +9,7 @@
9
9
 
10
10
  1. [架构设计.md](./架构设计.md):理解独立物料边界、依赖方向和全局不变量;
11
11
  2. [00-文件导航.md](./00-文件导航.md):快速查找每个目录和关键文件的角色、调用方与修改落点;
12
- 3. [01-核心运行机制.md](./01-核心运行机制.md):沿 Activity Contract、Outcome Actor、Command Coordinator、Controller 和 Screen 的真实调用链理解 Core;
12
+ 3. [01-核心运行机制.md](./01-核心运行机制.md):沿 Activity Contract、Intent/Navigation Actor、Command Coordinator、Controller 和 Screen 的真实调用链理解 Core;
13
13
  4. [02-Host 适配与业务数据.md](./02-Host适配与业务数据.md):理解 BigSale 兼容层每个文件解决的问题、字段映射和当前缺口;
14
14
  5. [实施进度.md](./实施进度.md):确认当前已完成能力、临时策略和已知风险;
15
15
  6. [03-业务流程与交互规则.md](./03-业务流程与交互规则.md):理解三入口和当前权威流程;
@@ -31,7 +31,7 @@
31
31
  | ------------------------------------------------------- | ------------------------------------------------------------------------------ | ---------------------- |
32
32
  | [00-文件导航.md](./00-文件导航.md) | 目录职责、关键文件角色、调用关系和常见修改落点 | 详细业务顺序和字段定义 |
33
33
  | [架构设计.md](./架构设计.md) | 边界、总图、状态所有权、不变量 | 实施流水账 |
34
- | [01-核心运行机制.md](./01-核心运行机制.md) | Core 代码地图、Activity/Outcome/Command/Actor/Controller 调用链、修改落点 | BigSale 原始字段 |
34
+ | [01-核心运行机制.md](./01-核心运行机制.md) | Core 代码地图、Activity/Intent/Navigation/Command/Actor/Controller 调用链、修改落点 | BigSale 原始字段 |
35
35
  | [02-Host 适配与业务数据.md](./02-Host适配与业务数据.md) | BigSale 兼容层代码地图、痛点与形式、Projection/Command/商品/设备映射、真实缺口 | Screen 导航 |
36
36
  | [03-业务流程与交互规则.md](./03-业务流程与交互规则.md) | 三入口、会员、主商品提交、页面行为、UI 基线 | OS 内部实现 |
37
37
  | [04-设备与称重.md](./04-设备与称重.md) | Scanner、任意页面扫码方案、Scale、事件仲裁和称重商品 | 支付实现细节 |
@@ -36,7 +36,7 @@
36
36
  | Scale | 待实机 | 顶层 Runtime、自动入口;有效重量先进入 Fulfillment,再进入与 Quick 共用的 Customization,本地草稿在 Next 时提交 | 真秤全矩阵、正式商品 |
37
37
  | Catalog | 待实机 | HDLKiosk 模板驱动现有 retail Product Provider 正式 load 后读取快照;分类/搜索/商品卡、连续加购、订单悬浮栏及购物车 Drawer 已完成 | 大目录虚拟化、复杂规格接管、实机视觉 |
38
38
  | Cart Overlay | 待业务/实机 | 已替代独立 Review/Voucher Slice;复用全局 BottomBar,展示 Host 商品、数量、卡券入口、小计和备注能力 | 称重/定制重新编辑、价格变化反馈、促销/税/节省明细 |
39
- | Identity 登录 | 待实机 | BigSale 内注册 H5 Login2/Register2;认证结果经 memberRecognized 进入 identity.sync,客户写入、订单一致性和重报价统一由 Adapter/Operation 完成 | 登录/注册实机交互、错误文案与客户搜索结果验收 |
39
+ | Identity 登录 | 待实机 | BigSale 内注册 H5 Login2/Register2;认证结果经 complete 进入 identity.sync,客户写入、订单一致性和重报价统一由 Adapter/Operation 完成 | 登录/注册实机交互、错误文案与客户搜索结果验收 |
40
40
  | 会员中途登录 | 待 Host | Activity 级本地入口策略、customer/cart 互斥、统一 Screen Command、重新计价验证;partial/unknown 阻塞 Workflow | 将同一 H5 认证能力接入 Shell/Cart Overlay 入口 |
41
41
  | Fulfillment | 待 Host | Workflow Context 已接;支付 dispatch 前的 `ensurePrepared` 统一写入并验证履约方式 | 当前仍允许临时模拟 |
42
42
  | Voucher | 已并入 Overlay | 不再是 Workflow Slice;由 Cart Overlay 展示并操作当前用户卡券 | 真实券列表、应用、撤销和 quote |
@@ -73,7 +73,7 @@
73
73
  - Customization 将称重/options 保持为页面本地草稿,输入变化不写 OS;Next 才通过 `addProductWithFlow` 提交,加购成功后前进;底栏和 Drawer 统一读取已确认的 `summary.due/cart.lines`;
74
74
  - Customization 通过本物料内的 `HDLKioskSkuOptionsSelection` 将原 ProductData 直接作为共享 `skuOptionsSelection` 的 dataSource,只转换选中结果;独立运行缺少 Engine 上下文时直接读取同一 option 结构兜底;
75
75
  - HDLKiosk 已删除主商品额外业务弹窗相关的 Activity、Host Contract、Projection 和 Checkout Requirement;是否展示额外弹窗由 OS 加购流内部决定;
76
- - Customization 称重/options 只保持本地草稿,Next 才调用 `addProductWithFlow`,加购成功后才前进;Barcode 主商品询问仍归入 `catalogWithPrimaryProductPrompt` Activity 内部;
76
+ - Barcode 主商品询问使用独立 Modal Slice;拒绝或 Customization 跳过后直接进入 Fulfillment,Back 按真实页面历史返回 Catalog,再次前进沿用已提交的标准结果;
77
77
  - Cart Mutation 以 Host consistency barrier 为权威,不再被晚一帧提交的 `consistencyPending` 展示态误判为 unknown;
78
78
  - 普通 Catalog/Cart Overlay 写操作不显示全屏遮罩;Catalog 批量锁定卡片时保持原视觉,减少短操作闪烁;
79
79
  - Scale Hook 在顶层单一运行,Entry 和 Customization 详情消费同一快照;Scale workflow 从 `fulfillment` 开始,再复用 `customization` 页面分支;
@@ -111,7 +111,7 @@
111
111
  - Result 取餐号只读取当前订单或匹配 `salesDetail.header` 的 `shop_full_order_number`;支付成功后 Projection 仍缺号时按已确认 `orderId` 回查订单详情,始终不从支付结果猜测字段,也不以其它订单编号降级;
112
112
  - Barcode 当前使用“激活 Session → 消费首码 → Catalog → 缺主商品时询问 → Yes 时 Fulfillment → 称重详情 → Next/OS 加购成功 → Catalog”的路径;No 保持在 Catalog 且不要求 Fulfillment,Cart Overlay 完成订单复核与卡券操作;
113
113
  - 移除遗留 `hdl-shell__footer` 与 `resolveScreenBottomBar`:Fulfillment、Customization、Catalog 改为声明实时 BottomBar,由 Shell 内唯一 `HDLKioskBottomBarHost` 渲染。BottomBar 当前区分 `visible / masked / hidden`:退出确认及 Catalog 主商品询问等普通 Modal 保留底栏并由遮罩阻止交互,同时自动收起 CartDrawer;只有等待员工、支付未决和 blocked 等不可导航状态才隐藏。购物车图标已接入基于 `CompensatedPisellContainer` 的底部 Drawer,展示 Host 已确认的商品、定制摘要、数量和金额,并在三个 Catalog workflow 中复用既有改数量/删除 Operation;
114
- - Workflow 使用线性优先的 Slice 数组:数组表达主路径,Slice Outcome 通过 `next()` / `back()` 或带方向的 Guard/Effect 补齐默认相邻移动,`on` 只描述分支、合流和跳跃;同一 Slice 可用 `slice:用途` 多次出现。非 Back 回路必须声明有限 repeat,Actor 超限即阻塞;Outcome 同时携带 `stepId/activityId`,避免同类 Activity 的旧实例误触发当前 Step。支付不确定是 Actor blocked 状态,不作为业务节点;
114
+ - Workflow 使用线性优先的 Slice 数组:数组表达主路径,Slice Intent 通过 `next()` 或 `navigate: 'next'` 补齐默认前进,`on` 只描述分支、合流和跳跃;Back 是独立 Navigation,并按实际页面历史解析。同一 Slice 可用 `slice:用途` 多次出现,回路必须声明有限 repeat,Actor 超限即阻塞;Intent 同时携带 `stepId/activityId`,避免同类 Activity 的迟到实例误触发当前 Step。支付不确定是 Actor blocked 状态,不作为业务节点;
115
115
  - `slices/<name>/slice.ts` 是各业务能力唯一导出的 `defineSlice` 结果:Slice `id` 标识业务 Activity,`screen.id` 标识页面类别;`view.tsx` 就地完成该 Slice 的 ViewModel 派生和组件装配,`app/views.ts` 单独维护完整的 Activity → View 本地注册表,`ScreenRenderer` 进行同步解析。Kernel、Slice 和 Workflow 不依赖 React View;公共类型与跨 Slice 纯方法分别集中在根 `types.ts`、`utils.ts`;
116
116
  - Kernel 已不依赖 HDLKiosk contracts:结构 Compiler、Actor 和通用 Coordinator 位于 `kernel/`;`app/operations.ts` 是共享业务副作用的公共入口,私有实现位于 `app/operations/`,其中 Coordinator 注入 HDLKioskHost、冲突矩阵、支付冻结、错误分类和遥测。Slice 专属 Operation 与对应 Slice 同置;
117
117
  - HDLKiosk 阻断式 Dialog 已统一到 `HDLKioskModal → PisellModal`,默认层级高于 CartDrawer;BottomBar 的三态解析、组件依赖边界、Checkout 安全及现有 Dialog/Screen 定向用例通过,HDLKiosk 汇总 Less 编译、变更组件 esbuild 语法转换和 `git diff --check` 通过;
@@ -71,7 +71,7 @@ flowchart TB
71
71
  HOST --> OPS
72
72
  PROJ --> CONTROLLER
73
73
  PROJ --> VIEW --> UI
74
- UI -->|"Activity Outcome"| VIEW
74
+ UI -->|"Activity Intent / Navigation"| VIEW
75
75
  VIEW --> ACTOR
76
76
  UI -->|"Screen Command"| VIEW
77
77
  VIEW --> COORD
@@ -106,20 +106,20 @@ Kernel ✕ HDLKiosk contracts / BigSale / SalesSDK / merchant workflows / Screen
106
106
  | ----------------------- | -------------------------------------------------------------------- | --------------------------------------------- |
107
107
  | Contracts/Ports | HDLKiosk 自有 DTO、能力和结果语义 | BigSale 字段兼容 |
108
108
  | Projection | 标准化 Host 可观察事实 | 发业务命令 |
109
- | Slice | 将 Screen、合法 Outcome、局部 Command、退出 Effect 和 Requirement 收敛为业务能力 | 前后节点和 Host 实现 |
109
+ | Slice | 将 Screen、合法 Intent、局部 Command、退出 Effect 和 Requirement 收敛为业务能力 | 前后节点和 Host 实现 |
110
110
  | Application Manifest | 汇总 Slice、Workflow 和 Operation 引用并生成可信注册表 | React 生命周期和订单事实 |
111
111
  | Structural Compiler | Step ID、相邻导航、可达性、终点、Modal 和有界循环 | 支付和购物车策略 |
112
112
  | HDLKiosk Policy | 编译后检查支付来源和 Checkout Prepare 等交易约束 | 修改节点结构 |
113
- | Workflow Actor | mailbox、step/activity 防迟到、running/blocked、节点提交和循环计数 | Host、Guard、Operation、支付解释和持久化 |
114
- | Transition Runner | 执行 Guard/Exit Command,把结果归一为 advance/stay/blocked | React、节点数组位置 |
113
+ | Workflow Actor | mailbox、step/activity 防迟到、running/blocked、节点提交和循环计数 | Host、Predicate、Operation、支付解释和持久化 |
114
+ | Transition Runner | 求值 Predicate/执行 Exit Command,将结果归一为 advance/stay/blocked | React、节点数组位置 |
115
115
  | Operations | 封装业务 Command 和写后验证 | Screen 导航 |
116
116
  | Requirement Registry | 判断支付前业务要求对当前订单是否适用,并校验 Host Projection | Workflow 节点编排和 UI |
117
117
  | Kernel Coordinator | 用应用注入的 Context/Scope/Policy 处理冲突、去重、timeout 和 epoch | 支付含义、Host、业务错误和节点目标 |
118
118
  | HDLKiosk Operation Policy | 注入 Host Context、冲突矩阵、支付 freeze、错误分类和遥测 | Screen 导航 |
119
119
  | Workflow | 用有序 Slice 数组表达主路径,以 `on` 描述分支、合流和受限回路 | Screen 内部动作和订单事实 |
120
120
  | Controllers | session/device/customer 生命周期;提供验证式 `returnToEntry` | OS 字段转换、决定自动返回时机 |
121
- | View assembly | 把 Activity 节点和 Projection 转换为组件输入,并路由 Outcome/Command | 决定目标节点 |
122
- | Screens/Dialogs/Layouts | 展示、局部输入、Screen Command 和 Activity Outcome | 直接调用 Host、Actor 或 Controller |
121
+ | View assembly | 把 Activity 节点和 Projection 转换为组件输入,并路由 Intent/Navigation/Command | 决定目标节点 |
122
+ | Screens/Dialogs/Layouts | 展示、局部输入、Screen Command、Activity Intent 和 Back Navigation | 直接调用 Host、Actor 或 Controller |
123
123
  | BigSale Adapter | DTO 转换、callback、插件、capability | 决定流程节点 |
124
124
 
125
125
  ## 5. Host 契约
@@ -157,9 +157,9 @@ Screen:输入和展示状态
157
157
 
158
158
  1. Core 不 import BigSale、SalesSDK、Engine plugin 或 raw tempOrder。
159
159
  2. Adapter 不决定 Workflow 目标节点。
160
- 3. Screen 不直接调用 Host;内部写操作发送 Command,离开步骤发送 Activity Outcome。
161
- 4. Slice 是 Screen、Outcome、Command 和退出策略的唯一业务定义;Activity Registry 和 Operation Registry 从 Application Manifest 派生,不维护平行清单。
162
- 5. Workflow 作者只排列已注册 Slice;规范化后的运行结构不得包含 Screen、Guard、Operation 或 failureTarget。重复 Slice 必须使用 `slice:用途` 标识每次出现。
160
+ 3. Screen 不直接调用 Host;内部写操作发送 Command,离开步骤发送 Activity Intent,返回发送 Navigation。
161
+ 4. Slice 是 Screen、Intent、Command 和退出策略的唯一业务定义;Activity Registry 和 Operation Registry 从 Application Manifest 派生,不维护平行清单。
162
+ 5. Workflow 作者只排列已注册 Slice;规范化后的运行结构不得包含 Screen、Predicate、Operation 或 failureTarget。重复 Slice 必须使用 `slice:用途` 标识每次出现。
163
163
  6. 只有可被业务编排者独立排序或分支的里程碑才成为节点;Dialog 内部询问、选择和等待阶段留在 Activity 内。
164
164
  7. Operation 不渲染 UI,不直接切 Screen。
165
165
  8. Cart/Customer/Summary/Payment 以 Host Projection 为权威。
@@ -186,7 +186,7 @@ Scale ───────┘
186
186
 
187
187
  入口定义不同顺序,复用 Identity、Fulfillment、Customization、Catalog、Cart、Checkout 等 Screen/Operation。会员中途登录是共享 session 行为,不复制到每个 Workflow 节点。
188
188
 
189
- Barcode/Scale 是外部 ingress,不放入 Step 数组。Barcode 首码先归属并激活 Session,在 Session `readyForCommands && cartWritable` 后通过 `barcode.consume` 完成;首屏类型由 Workflow Definition 决定,Scanner 不依赖 Catalog。Scale 当前从 Fulfillment 开始。Slice 在 `guards` 中声明纯函数,Workflow occurrence 用 `useGuards` 选择启用阶段,Compiler 只在 Node 中保留 `guardPhases`。Actor 的全局 `beforeEach` 管线对初始进入、前进、后退、显式目标和 `sessionExit` 使用同一套 `to/from` 导航判定。退出确认是全局 guard 的 `defer` 决策,Shell 只消费 `pendingNavigation.request`,不在 View 或 Kernel 中判断具体 Activity 名称。
189
+ Barcode/Scale 是外部 ingress,不放入 Step 数组。Barcode 首码先归属并激活 Session,在 Session `readyForCommands && cartWritable` 后通过 `barcode.consume` 完成;首屏类型由 Workflow Definition 决定,Scanner 不依赖 Catalog。Scale 当前从 Fulfillment 开始。业务 Step 当前不启用本地 `beforeEnter`;Identity 通过 Workflow 中可见的 `visitPolicy: 'once'` 表达会话内只进入一次。Actor 的全局 `beforeEach` 管线仅承载会话安全策略。退出确认由其返回 `defer`,Shell 只消费 `pendingNavigation.request`,不在 View 或 Kernel 中判断具体 Activity 名称。
190
190
 
191
191
  权威节点顺序见 [03-业务流程与交互规则.md](./03-业务流程与交互规则.md)。
192
192
 
@@ -222,7 +222,7 @@ HDLKiosk 无法独立保证:
222
222
  ```text
223
223
  components/HDLKiosk/
224
224
  ├── app/ # 应用清单、三入口流程、共享 Operation 入口和节点渲染装配
225
- │ ├── workflow/ # Quick / Barcode / Scale + registry / guards / policy
225
+ │ ├── workflow/ # Quick / Barcode / Scale + registry / predicates / navigation guards / policy
226
226
  │ ├── operations.ts # 跨 Slice Operation 的唯一公共导入面
227
227
  │ ├── operations/ # 公共入口背后的私有实现与测试
228
228
  │ └── entry/ # Workflow 外三入口页面
@@ -63,7 +63,6 @@ function HDLKioskContent({ host, config, isActive = true, entryDataPreparing = f
63
63
  config,
64
64
  isActive,
65
65
  starting,
66
- session,
67
66
  sessionRef,
68
67
  activeRef,
69
68
  scannerIngress,
@@ -10,10 +10,9 @@
10
10
  const identity = defineSlice({
11
11
  id: 'identity',
12
12
  screen: { id: 'identity' },
13
- outcomes: {
14
- identified: effect(identifyCustomer, { navigate: 'next' }),
15
- skipped: next(),
16
- back: back(),
13
+ intents: {
14
+ complete: effect(identifyCustomer, { navigate: 'next' }),
15
+ omit: next(),
17
16
  },
18
17
  commands: {
19
18
  requestSmsCode,
@@ -40,11 +39,11 @@ const views = {
40
39
  ```
41
40
 
42
41
  - `defineSlice`:把业务 Activity、Screen 描述、语义出口、Screen 内 Command 和离开时 Effect 放在一起;
43
- - `next()` / `back()`:声明默认相邻移动,不再额外维护 navigation 清单;
42
+ - `next()`:声明默认前进;Back 由独立 Navigation 和页面历史处理;
44
43
  - `defineWorkflow`:数组只表达 Slice 顺序,`on` 只处理跳跃、分支、合流和有界回路;
45
44
  - `defineKioskApplication`:汇总 Slice、Workflow 与应用级 Operation,并自动生成 Activity/Operation Manifest。
46
45
 
47
- Slice 的 `outcomes` 是“业务活动对流程公开的结果”,不是按钮或 DOM 事件。不会离开 Screen 的动作放进 `commands`。支付门禁、设备监听、购物车写入验证等商家规则不进入 Kernel。
46
+ Slice 的 `intents` 是“业务活动请求流程执行的意图”,不是按钮或 DOM 事件。Back 使用独立 Navigation;不会离开 Screen 的动作放进 `commands`。支付门禁、设备监听、购物车写入验证等商家规则不进入 Kernel。
48
47
 
49
48
  三个标识的职责固定如下:Slice `id` 是 Workflow 引用的业务 Activity;`screen.id` 是 Shell、数据加载和展示策略使用的页面类别;React View 由应用层按 Activity 单独注册。不导航的业务操作声明为当前 Slice 的 Command,例如 `paymentMethod` 内的店员支付授权。
50
49
 
@@ -54,8 +53,8 @@ Compiler 只把 `screen.id` 复制为节点的 `screenId`。Renderer 再按节
54
53
 
55
54
  | 目录 | 负责 | 由应用注入 |
56
55
  | --- | --- | --- |
57
- | `application/` | Slice/Workflow/Application 作者 API、Manifest 生成 | Screen 描述、Outcome、Operation 引用 |
58
- | `workflow/` | 结构编译、Actor mailbox、节点提交、有界循环 | Activity Registry、Guard Registry、Transition Runner、Context Reducer |
56
+ | `application/` | Slice/Workflow/Application 作者 API、Manifest 生成 | Screen 描述、Intent、Operation 引用 |
57
+ | `workflow/` | 结构编译、Actor mailbox、节点提交、有界循环 | Activity Registry、Predicate Registry、Navigation Guard Registry、Transition Runner、Context Reducer |
59
58
  | `operations/` | 排队、冲突仲裁、intent 去重、timeout、Abort、session epoch | Context factory、错误分类、冲突规则、业务 Policy、观察器 |
60
59
  | `lifecycle.ts` | 组合 Actor 提交后的只读观察器 | telemetry、审计或持久化观察器 |
61
60
 
@@ -71,7 +70,7 @@ Workflow ┘ │
71
70
  Structural Compiler ─ Actor
72
71
  │
73
72
  Screen Command ───────────────────── Operation Coordinator
74
- Activity Outcome ─ Transition Runner ───────────┘
73
+ Activity Intent ─ Transition Runner ────────────┘
75
74
  ```
76
75
 
77
76
  当前会话只在内存中运行,不包含 checkpoint 或恢复策略。需要恢复时,由应用层读取 OS 事实和持久化证据,形成 Actor 初始化输入;Kernel 只保留 Lifecycle 和初始化参数这些扩展点。
@@ -27,10 +27,10 @@ function defineKioskApplication(definition) {
27
27
  var _slice$commands;
28
28
  if (slices.has(slice.id)) throw new Error(`Duplicate Kiosk Slice: ${slice.id}`);
29
29
  const operationIds = /* @__PURE__ */ new Set();
30
- Object.values(slice.outcomes).forEach((outcome) => {
31
- if (outcome.kind !== "effect") return;
32
- registerOperation(outcome.operation);
33
- operationIds.add(outcome.operation.id);
30
+ Object.values(slice.intents).forEach((intent) => {
31
+ if (intent.kind !== "effect") return;
32
+ registerOperation(intent.operation);
33
+ operationIds.add(intent.operation.id);
34
34
  });
35
35
  Object.values((_slice$commands = slice.commands) !== null && _slice$commands !== void 0 ? _slice$commands : {}).forEach((operation) => {
36
36
  registerOperation(operation);
@@ -77,31 +77,30 @@ function createApplicationActivityRegistry(application) {
77
77
  const contracts = /* @__PURE__ */ new Map();
78
78
  application.slices.forEach(({ definition }) => {
79
79
  var _definition$presentat, _definition$additiona;
80
- const exitPolicies = Object.fromEntries(Object.entries(definition.outcomes).flatMap(([outcome, behavior]) => {
80
+ const exitPolicies = {};
81
+ Object.entries(definition.intents).forEach(([intent, behavior]) => {
81
82
  let policy;
82
- if (behavior.kind === "guard") policy = { guard: behavior.guard };
83
+ if (behavior.kind === "precondition") policy = { precondition: behavior.predicate };
83
84
  else if (behavior.kind === "effect") policy = {
84
- guard: behavior.guard,
85
- command: {
86
- id: behavior.operation.id,
87
- when: behavior.when
88
- }
85
+ precondition: behavior.precondition,
86
+ command: { id: behavior.operation.id }
89
87
  };
90
- return policy ? [[outcome, Object.freeze(policy)]] : [];
91
- }));
88
+ if (policy) exitPolicies[intent] = Object.freeze(policy);
89
+ });
92
90
  const primaryPresentation = (_definition$presentat = definition.presentation) !== null && _definition$presentat !== void 0 ? _definition$presentat : "page";
93
91
  contracts.set(definition.id, Object.freeze({
94
92
  id: definition.id,
95
93
  screenId: definition.screen.id,
96
- outcomes: Object.freeze(Object.keys(definition.outcomes)),
94
+ intents: Object.freeze(Object.keys(definition.intents)),
97
95
  exitPolicies: Object.freeze(exitPolicies),
98
- navigationGuards: definition.guards ? Object.freeze(Object.fromEntries(Object.keys(definition.guards).map((phase) => [phase, getKioskSliceNavigationGuardId(definition.id, phase)]))) : void 0,
96
+ navigationGuards: definition.guards ? Object.freeze(Object.keys(definition.guards).reduce((guards, rawPhase) => {
97
+ const phase = rawPhase;
98
+ guards[phase] = getKioskSliceNavigationGuardId(definition.id, phase);
99
+ return guards;
100
+ }, {})) : void 0,
99
101
  allowedPresentations: Object.freeze([...new Set([primaryPresentation, ...(_definition$additiona = definition.additionalPresentations) !== null && _definition$additiona !== void 0 ? _definition$additiona : []])]),
100
102
  requirements: definition.requirements ? Object.freeze([...definition.requirements]) : void 0,
101
- navigation: Object.freeze({
102
- forward: Object.freeze(Object.entries(definition.outcomes).filter(([, behavior]) => behavior.navigate === "next").map(([outcome]) => outcome)),
103
- backward: Object.freeze(Object.entries(definition.outcomes).filter(([, behavior]) => behavior.navigate === "previous").map(([outcome]) => outcome))
104
- })
103
+ navigation: Object.freeze({ forward: Object.freeze(Object.entries(definition.intents).filter(([, behavior]) => behavior.navigate === "next").map(([intent]) => intent)) })
105
104
  }));
106
105
  });
107
106
  return Object.freeze({