@pisell/private-materials 6.12.166 → 6.12.167

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 (144) 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 +1 -1
  8. package/es/components/HDLKiosk/app/views.js +2 -1
  9. package/es/components/HDLKiosk/app/workflow/barcode.js +15 -32
  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 +46 -37
  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 +2 -2
  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 +88 -28
  29. package/es/components/HDLKiosk/kernel/workflow/compiler.js +28 -29
  30. package/es/components/HDLKiosk/kernel/workflow/selectors.js +9 -0
  31. package/es/components/HDLKiosk/runtime/HDLKioskWorkflowView.js +8 -7
  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 +7 -9
  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/components/BookingFloatingPanel/useBookingPanelController.js +1 -0
  57. package/es/components/bigSale/components/TimeBar/index.js +1 -0
  58. package/es/components/bigSale/dialog.js +1 -0
  59. package/es/components/bigSale/hooks/useBigSaleContext.js +1 -0
  60. package/es/components/bigSale/hooks/useSelectFloorMapResourceForBigSale.js +1 -0
  61. package/es/components/bigSale/index.js +1 -0
  62. package/es/components/bigSale/templates/HDLKiosk/auth/HDLKioskIdentityAuthPanel.js +17 -2
  63. package/es/components/bigSale/templates/Kiosk/index.js +1 -0
  64. package/es/components/sharedSecondaryBigSale/SharedSecondaryBigSaleReceiver.js +1 -0
  65. package/es/index.js +2 -0
  66. package/es/plus/pisellReservation/data/bookingToReservationTables.js +1 -1
  67. package/es/plus/pisellReservation/floorMap/floorPlanApi.js +1 -1
  68. package/es/plus/pisellReservation/floorMap/reservationMock.js +1 -1
  69. package/es/plus/pisellReservation/index.js +17 -0
  70. package/es/plus/saleDetail/Base.js +1 -0
  71. package/es/plus/saleDetail/components/Client/hooks/useClientSelectorProps.js +1 -0
  72. package/es/plus/saleDetail/components/DetailActions/index.js +1 -0
  73. package/es/plus/saleDetail/components/SummaryFinancialSections/index.js +1 -0
  74. package/es/plus/saleDetail/index.js +1 -0
  75. package/es/plus/saleDetail/tmpl/B/components/Dish/index.js +1 -0
  76. package/es/plus/saleDetail/tmpl/B/index.js +1 -0
  77. package/es/plus/salesSdk/index.js +52 -0
  78. package/es/plus/salesSdk/utils/addProductWithFlowDebounced.js +1 -1
  79. package/es/plus/salesSdk/utils/bookingDate.js +1 -1
  80. package/es/plus/salesSdk/utils/customerAuthGate.js +1 -1
  81. package/es/plus/salesSdk/utils/enrichCartLineHolderDisplay.js +1 -1
  82. package/es/pro/Login2.0/AuthModal.d.ts +1 -1
  83. package/es/pro/Login2.0/Login2.d.ts +2 -0
  84. package/es/pro/Login2.0/Login2.js +9 -1
  85. package/es/pro/Login2.0/Register2.d.ts +2 -0
  86. package/es/pro/Login2.0/Register2.js +9 -1
  87. package/es/pro/Login2.0/index.d.ts +2 -1
  88. package/es/pro/Login2.0/shared/types.d.ts +1 -1
  89. package/lib/components/HDLKiosk/app/ScreenRenderer.js +1 -1
  90. package/lib/components/HDLKiosk/app/views.js +2 -1
  91. package/lib/components/HDLKiosk/app/workflow/barcode.js +14 -31
  92. package/lib/components/HDLKiosk/app/workflow/{guards.js → predicates.js} +9 -9
  93. package/lib/components/HDLKiosk/app/workflow/quick.js +3 -6
  94. package/lib/components/HDLKiosk/app/workflow/registry.js +1 -1
  95. package/lib/components/HDLKiosk/app/workflow/scale.js +3 -12
  96. package/lib/components/HDLKiosk/components/shell/HDLKioskBottomBarHost/index.js +12 -10
  97. package/lib/components/HDLKiosk/components/shell/HDLKioskShell/index.js +1 -0
  98. package/lib/components/HDLKiosk/docs/00-/346/226/207/344/273/266/345/257/274/350/210/252.md +7 -7
  99. 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 +46 -37
  100. 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
  101. package/lib/components/HDLKiosk/docs/05-/344/272/244/346/230/223/345/256/211/345/205/250.md +1 -1
  102. package/lib/components/HDLKiosk/docs/07-/345/220/216/347/273/255/345/267/245/344/275/234.md +1 -1
  103. package/lib/components/HDLKiosk/docs/README.md +2 -2
  104. package/lib/components/HDLKiosk/docs//345/256/236/346/226/275/350/277/233/345/272/246.md +3 -3
  105. package/lib/components/HDLKiosk/docs//346/236/266/346/236/204/350/256/276/350/256/241.md +11 -11
  106. package/lib/components/HDLKiosk/index.js +0 -1
  107. package/lib/components/HDLKiosk/kernel/README.md +8 -9
  108. package/lib/components/HDLKiosk/kernel/application/defineApplication.js +18 -19
  109. package/lib/components/HDLKiosk/kernel/application/defineSlice.js +8 -14
  110. package/lib/components/HDLKiosk/kernel/workflow/actor.js +88 -28
  111. package/lib/components/HDLKiosk/kernel/workflow/compiler.js +28 -29
  112. package/lib/components/HDLKiosk/kernel/workflow/selectors.js +10 -0
  113. package/lib/components/HDLKiosk/runtime/HDLKioskWorkflowView.js +8 -7
  114. package/lib/components/HDLKiosk/runtime/controllers/useHDLKioskCustomerController.js +1 -1
  115. package/lib/components/HDLKiosk/runtime/createWorkflowSession.js +3 -3
  116. package/lib/components/HDLKiosk/runtime/domainTransitionRunner.js +9 -9
  117. package/lib/components/HDLKiosk/runtime/workflowEvent.js +9 -4
  118. package/lib/components/HDLKiosk/runtime/workflowLifecycle.js +3 -3
  119. package/lib/components/HDLKiosk/slices/catalog/PrimaryProductPromptDialog/index.js +1 -2
  120. package/lib/components/HDLKiosk/slices/catalog/Screen/index.js +13 -40
  121. package/lib/components/HDLKiosk/slices/catalog/Screen/model.js +0 -5
  122. package/lib/components/HDLKiosk/slices/catalog/slice.js +2 -15
  123. package/lib/components/HDLKiosk/slices/catalog/view.js +4 -6
  124. package/lib/components/HDLKiosk/slices/customization/Screen/index.js +7 -9
  125. package/lib/components/HDLKiosk/slices/customization/operation.js +23 -3
  126. package/lib/components/HDLKiosk/slices/customization/slice.js +3 -7
  127. package/lib/components/HDLKiosk/slices/customization/view.js +3 -2
  128. package/lib/components/HDLKiosk/slices/fulfillment/Screen/index.js +6 -6
  129. package/lib/components/HDLKiosk/slices/fulfillment/slice.js +4 -7
  130. package/lib/components/HDLKiosk/slices/identity/Screen/index.js +17 -11
  131. package/lib/components/HDLKiosk/slices/identity/slice.js +4 -11
  132. package/lib/components/HDLKiosk/slices/index.js +2 -1
  133. package/lib/components/HDLKiosk/slices/payment/Screen/index.js +5 -5
  134. package/lib/components/HDLKiosk/slices/payment/slice.js +6 -7
  135. package/lib/components/HDLKiosk/slices/primaryProductPrompt/slice.js +14 -0
  136. package/lib/components/HDLKiosk/slices/primaryProductPrompt/view.js +25 -0
  137. package/lib/components/HDLKiosk/utils.js +3 -2
  138. package/lib/components/bigSale/templates/HDLKiosk/auth/HDLKioskIdentityAuthPanel.js +16 -1
  139. package/lib/pro/Login2.0/Login2.d.ts +2 -0
  140. package/lib/pro/Login2.0/Login2.js +9 -1
  141. package/lib/pro/Login2.0/Register2.d.ts +2 -0
  142. package/lib/pro/Login2.0/Register2.js +9 -1
  143. package/package.json +3 -3
  144. package/es/private-materials/lowcode/authmodal/meta.d.ts +0 -1
@@ -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 外三入口页面
@@ -61,7 +61,6 @@ function HDLKioskContent({ host, config, isActive = true, entryDataPreparing = f
61
61
  config,
62
62
  isActive,
63
63
  starting,
64
- session,
65
64
  sessionRef,
66
65
  activeRef,
67
66
  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
+ skip: 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({
@@ -1,27 +1,22 @@
1
1
  import { _objectSpread2 } from "../../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
2
  //#region src/components/HDLKiosk/kernel/application/defineSlice.ts
3
- const back = () => Object.freeze({
4
- kind: "complete",
5
- navigate: "previous"
6
- });
7
- const guard = (guardId, options = {}) => Object.freeze({
8
- kind: "guard",
9
- guard: guardId,
3
+ const intentPrecondition = (predicate, options = {}) => Object.freeze({
4
+ kind: "precondition",
5
+ predicate,
10
6
  navigate: options.navigate
11
7
  });
12
8
  const effect = (operation, options = {}) => Object.freeze({
13
9
  kind: "effect",
14
10
  operation,
15
- when: options.when,
16
- guard: options.guard,
11
+ precondition: options.precondition,
17
12
  navigate: options.navigate
18
13
  });
19
14
  function defineSlice(slice) {
20
15
  var _slice$guards;
21
16
  if (!slice.id.trim()) throw new Error("Kiosk Slice id cannot be empty");
22
17
  if (!slice.screen.id.trim()) throw new Error(`Kiosk Slice ${slice.id} screen id cannot be empty`);
23
- Object.entries(slice.outcomes).forEach(([outcome]) => {
24
- if (!outcome.trim()) throw new Error(`Kiosk Slice ${slice.id} has an empty outcome`);
18
+ Object.entries(slice.intents).forEach(([intent]) => {
19
+ if (!intent.trim()) throw new Error(`Kiosk Slice ${slice.id} has an empty intent`);
25
20
  });
26
21
  Object.entries((_slice$guards = slice.guards) !== null && _slice$guards !== void 0 ? _slice$guards : {}).forEach(([phase, navigationGuard]) => {
27
22
  if (phase !== "beforeEnter") throw new Error(`Kiosk Slice ${slice.id} has an unknown navigation guard phase: ${phase}`);
@@ -29,11 +24,11 @@ function defineSlice(slice) {
29
24
  });
30
25
  return Object.freeze(_objectSpread2(_objectSpread2({}, slice), {}, {
31
26
  screen: Object.freeze(_objectSpread2({}, slice.screen)),
32
- outcomes: Object.freeze(_objectSpread2({}, slice.outcomes)),
27
+ intents: Object.freeze(_objectSpread2({}, slice.intents)),
33
28
  guards: slice.guards ? Object.freeze(_objectSpread2({}, slice.guards)) : void 0,
34
29
  commands: slice.commands ? Object.freeze(_objectSpread2({}, slice.commands)) : void 0,
35
30
  requirements: slice.requirements ? Object.freeze([...slice.requirements]) : void 0
36
31
  }));
37
32
  }
38
33
  //#endregion
39
- export { back, defineSlice, effect, guard };
34
+ export { defineSlice, effect, intentPrecondition };
@@ -24,6 +24,15 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
24
24
  let navigationTurnLocked = false;
25
25
  const repeatCounts = /* @__PURE__ */ new Map();
26
26
  const completedStepIds = /* @__PURE__ */ new Set();
27
+ const stepResolutions = /* @__PURE__ */ new Map();
28
+ let navigationHistory = [];
29
+ const readStepResolutions = () => {
30
+ const resolutions = {};
31
+ stepResolutions.forEach((resolution, stepId) => {
32
+ resolutions[stepId] = resolution;
33
+ });
34
+ return resolutions;
35
+ };
27
36
  const configuredStartingNodeId = initialNodeId && definition.nodes[initialNodeId] ? initialNodeId : definition.initial;
28
37
  const stepLocation = (stepId) => {
29
38
  const node = definition.nodes[stepId];
@@ -34,6 +43,20 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
34
43
  guardPhases: node.guardPhases
35
44
  };
36
45
  };
46
+ const resolveResumableTarget = (initialStepId) => {
47
+ let stepId = initialStepId;
48
+ const visited = /* @__PURE__ */ new Set();
49
+ while (!visited.has(stepId)) {
50
+ visited.add(stepId);
51
+ const node = definition.nodes[stepId];
52
+ const storedResolution = stepResolutions.get(stepId);
53
+ if (!node || !storedResolution || node.visitPolicy !== "reuseResolution" && node.visitPolicy !== "once") return stepId;
54
+ const transition = node.on[storedResolution];
55
+ if (!transition) return stepId;
56
+ stepId = transition.target;
57
+ }
58
+ throw new Error("Workflow resumable Step cycle");
59
+ };
37
60
  const resolveNavigation = ({ target, fromNodeId, candidateContext, candidateCompletedStepIds, intentId, direction: requestedDirection }) => {
38
61
  navigationSequence += 1;
39
62
  const navigationId = `${definition.id}:${sessionEpoch}:navigation:${navigationSequence}`;
@@ -67,7 +90,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
67
90
  type: "external",
68
91
  to: nextTarget
69
92
  };
70
- if (decision.type === "cancel" || decision.type === "skip") return { type: "cancel" };
93
+ if (decision.type === "cancel" || decision.type === "bypass") return { type: "cancel" };
71
94
  if (decision.type === "redirect") return resolveTarget(decision.to, redirectCount + 1, direction);
72
95
  if (decision.type === "defer") return {
73
96
  type: "defer",
@@ -93,6 +116,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
93
116
  const direction = !fromNodeId ? "initial" : delta < 0 ? "backward" : "forward";
94
117
  for (let candidateIndex = targetIndex; candidateIndex >= 0 && candidateIndex < definition.stepOrder.length; candidateIndex += delta) {
95
118
  const candidateStepId = definition.stepOrder[candidateIndex];
119
+ if (definition.nodes[candidateStepId].visitPolicy === "once" && stepResolutions.has(candidateStepId)) continue;
96
120
  const decision = beforeEach({
97
121
  navigationId,
98
122
  intentId,
@@ -151,12 +175,16 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
151
175
  status: initialError || initialResolutionError || startingNode.end === "blocked" ? "blocked" : startingNode.end === "success" ? "finished" : "idle",
152
176
  context: Object.freeze(_objectSpread2({}, context)),
153
177
  completedStepIds: Object.freeze([]),
178
+ stepResolutions: Object.freeze({}),
179
+ navigationHistory: Object.freeze([]),
154
180
  lastError: (_ref2 = initialError !== null && initialError !== void 0 ? initialError : initialResolutionError) !== null && _ref2 !== void 0 ? _ref2 : startingNode.end === "blocked" ? createWorkflowError("workflowEndedBlocked", "staff") : void 0
155
181
  });
156
182
  const publish = (next) => {
157
183
  snapshot = Object.freeze(_objectSpread2(_objectSpread2({}, next), {}, {
158
184
  context: Object.freeze(_objectSpread2({}, next.context)),
159
185
  completedStepIds: Object.freeze([...next.completedStepIds]),
186
+ stepResolutions: Object.freeze(_objectSpread2({}, next.stepResolutions)),
187
+ navigationHistory: Object.freeze([...next.navigationHistory]),
160
188
  pendingNavigation: next.pendingNavigation ? Object.freeze(_objectSpread2(_objectSpread2({}, next.pendingNavigation), {}, {
161
189
  to: Object.freeze(_objectSpread2({}, next.pendingNavigation.to)),
162
190
  request: Object.freeze(_objectSpread2({}, next.pendingNavigation.request))
@@ -174,6 +202,8 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
174
202
  status: blocked || node.end === "blocked" ? "blocked" : node.end === "success" ? "finished" : "idle",
175
203
  context: nextContext,
176
204
  completedStepIds: Object.freeze([...completedStepIds]),
205
+ stepResolutions: Object.freeze(readStepResolutions()),
206
+ navigationHistory: Object.freeze([...navigationHistory]),
177
207
  pendingNavigation: void 0,
178
208
  confirmedCheckout: confirmedCheckout !== null && confirmedCheckout !== void 0 ? confirmedCheckout : snapshot.confirmedCheckout,
179
209
  activeOperation: void 0,
@@ -194,7 +224,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
194
224
  const workflowError = createWorkflowError(code, "staff", cause);
195
225
  lifecycle.runtimeError({
196
226
  stepId: fromNodeId,
197
- outcome: event.outcome,
227
+ intent: event.intent,
198
228
  error: workflowError
199
229
  });
200
230
  yield commit(fromNodeId, fromNodeId, event, snapshot.context, true, workflowError);
@@ -209,10 +239,22 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
209
239
  if (disposed || snapshot.status === "finished" || snapshot.status === "blocked") return;
210
240
  const fromNodeId = snapshot.nodeId;
211
241
  const node = definition.nodes[fromNodeId];
212
- if (event.type !== "ACTIVITY_OUTCOME" || event.stepId !== fromNodeId || event.activityId !== node.activity) return;
213
- const transition = node.on[event.outcome];
214
- if (!transition || !event.intentId.trim()) return;
215
- const repeatKey = `${fromNodeId}:${event.outcome}:${transition.target}`;
242
+ if (event.stepId !== fromNodeId || event.activityId !== node.activity) return;
243
+ if (!event.intentId.trim()) return;
244
+ if (event.type === "NAVIGATE_BACK") {
245
+ const previousStepId = navigationHistory[navigationHistory.length - 1];
246
+ yield handleDirectNavigation(previousStepId ? {
247
+ kind: "step",
248
+ stepId: previousStepId
249
+ } : {
250
+ kind: "sessionExit",
251
+ reason: "workflowBoundary"
252
+ }, event.intentId);
253
+ return;
254
+ }
255
+ const transition = node.on[event.intent];
256
+ if (!transition) return;
257
+ const repeatKey = `${fromNodeId}:${event.intent}:${transition.target}`;
216
258
  if (transition.repeat && ((_repeatCounts$get = repeatCounts.get(repeatKey)) !== null && _repeatCounts$get !== void 0 ? _repeatCounts$get : 0) >= transition.repeat.max) {
217
259
  yield blockForRuntimeError(fromNodeId, event, "workflowRepeatLimitExceeded");
218
260
  return;
@@ -222,16 +264,24 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
222
264
  if (!transition.repeat) return;
223
265
  repeatCounts.set(repeatKey, ((_repeatCounts$get2 = repeatCounts.get(repeatKey)) !== null && _repeatCounts$get2 !== void 0 ? _repeatCounts$get2 : 0) + 1);
224
266
  };
225
- const nextContext = reduceContext(snapshot.context, event.contextPatch);
267
+ const previousContext = snapshot.context;
268
+ const nextContext = reduceContext(previousContext, event.contextPatch);
269
+ let requestedTarget = transition.target;
270
+ try {
271
+ requestedTarget = resolveResumableTarget(requestedTarget);
272
+ } catch (cause) {
273
+ yield blockForRuntimeError(fromNodeId, event, "workflowResumeCycle", cause);
274
+ return;
275
+ }
226
276
  const fromIndex = definition.stepOrder.indexOf(fromNodeId);
227
- const movesForward = definition.stepOrder.indexOf(transition.target) > fromIndex;
277
+ const movesForward = definition.stepOrder.indexOf(requestedTarget) > fromIndex;
228
278
  const candidateCompletedStepIds = movesForward ? [...new Set([...completedStepIds, fromNodeId])] : [...completedStepIds];
229
279
  let navigationResolution;
230
280
  try {
231
281
  navigationResolution = resolveNavigation({
232
282
  target: {
233
283
  kind: "step",
234
- stepId: transition.target
284
+ stepId: requestedTarget
235
285
  },
236
286
  fromNodeId,
237
287
  candidateContext: nextContext,
@@ -245,10 +295,10 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
245
295
  if (navigationResolution.type === "block") {
246
296
  lifecycle.runtimeError({
247
297
  stepId: fromNodeId,
248
- outcome: event.outcome,
298
+ intent: event.intent,
249
299
  error: navigationResolution.error
250
300
  });
251
- yield commit(fromNodeId, fromNodeId, event, snapshot.context, true, navigationResolution.error);
301
+ yield commit(fromNodeId, fromNodeId, event, previousContext, true, navigationResolution.error);
252
302
  return;
253
303
  }
254
304
  if (navigationResolution.type === "cancel") return;
@@ -268,9 +318,9 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
268
318
  return;
269
319
  }
270
320
  const resolvedTarget = navigationResolution.stepId;
271
- const operationInput = "operationInput" in event ? event.operationInput : void 0;
321
+ "operationInput" in event && event.operationInput;
272
322
  const command = (_transition$exitPolic = transition.exitPolicy) === null || _transition$exitPolic === void 0 ? void 0 : _transition$exitPolic.command;
273
- const commandWillRun = Boolean(command && (command.when !== "inputPresent" || operationInput != null));
323
+ const commandWillRun = Boolean(command);
274
324
  executionSequence += 1;
275
325
  const executionId = `${definition.id}:${snapshot.sessionEpoch}:${executionSequence}`;
276
326
  if (commandWillRun && command) publish(_objectSpread2(_objectSpread2({}, snapshot), {}, {
@@ -303,21 +353,29 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
303
353
  if (result.status === "advance") {
304
354
  recordRepeat();
305
355
  if (movesForward) completedStepIds.add(fromNodeId);
356
+ stepResolutions.set(fromNodeId, event.intent);
357
+ if (event.intent === "complete" && node.presentation.mode === "page" && movesForward && node.visitPolicy !== "once") {
358
+ navigationHistory = navigationHistory.filter((stepId) => stepId !== fromNodeId);
359
+ navigationHistory.push(fromNodeId);
360
+ } else if (event.intent === "skip") navigationHistory = navigationHistory.filter((stepId) => stepId !== fromNodeId);
306
361
  yield commit(fromNodeId, resolvedTarget, event, nextContext, false, void 0, result.confirmedCheckout);
307
362
  return;
308
363
  }
309
364
  if (result.status === "blocked") {
310
- yield commit(fromNodeId, fromNodeId, event, nextContext, true, result.lastError);
365
+ yield commit(fromNodeId, fromNodeId, event, previousContext, true, result.lastError);
311
366
  return;
312
367
  }
313
- yield commit(fromNodeId, fromNodeId, event, nextContext, false, result.lastError);
368
+ yield commit(fromNodeId, fromNodeId, event, previousContext, false, result.lastError);
314
369
  });
315
370
  return function handleEvent(_x12) {
316
371
  return _ref5.apply(this, arguments);
317
372
  };
318
373
  }();
319
- const handleDirectNavigation = function() {
320
- var _ref6 = _asyncToGenerator(function* (target, intentId) {
374
+ function handleDirectNavigation(_x13, _x14) {
375
+ return _handleDirectNavigation.apply(this, arguments);
376
+ }
377
+ function _handleDirectNavigation() {
378
+ _handleDirectNavigation = _asyncToGenerator(function* (target, intentId) {
321
379
  if (!intentId.trim()) return;
322
380
  const fromNodeId = snapshot.nodeId;
323
381
  let resolution;
@@ -333,7 +391,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
333
391
  } catch (cause) {
334
392
  yield blockForRuntimeError(fromNodeId, {
335
393
  intentId,
336
- outcome: "directNavigation"
394
+ intent: "directNavigation"
337
395
  }, "workflowBeforeEachGuardFailed", cause);
338
396
  return;
339
397
  }
@@ -341,19 +399,23 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
341
399
  if (resolution.type === "block") {
342
400
  lifecycle.runtimeError({
343
401
  stepId: fromNodeId,
344
- outcome: "directNavigation",
402
+ intent: "directNavigation",
345
403
  error: resolution.error
346
404
  });
347
405
  yield commit(fromNodeId, fromNodeId, {
348
406
  intentId,
349
- outcome: "directNavigation"
407
+ intent: "directNavigation"
350
408
  }, snapshot.context, true, resolution.error);
351
409
  return;
352
410
  }
353
411
  if (resolution.type === "step") {
412
+ const fromIndex = definition.stepOrder.indexOf(fromNodeId);
413
+ if (definition.stepOrder.indexOf(resolution.stepId) < fromIndex) stepResolutions.delete(fromNodeId);
414
+ const historyIndex = navigationHistory.lastIndexOf(resolution.stepId);
415
+ if (historyIndex >= 0) navigationHistory = navigationHistory.slice(0, historyIndex);
354
416
  yield commit(fromNodeId, resolution.stepId, {
355
417
  intentId,
356
- outcome: "directNavigation"
418
+ intent: "directNavigation"
357
419
  }, snapshot.context, false);
358
420
  return;
359
421
  }
@@ -370,12 +432,10 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
370
432
  lastError: void 0
371
433
  }));
372
434
  });
373
- return function handleDirectNavigation(_x13, _x14) {
374
- return _ref6.apply(this, arguments);
375
- };
376
- }();
435
+ return _handleDirectNavigation.apply(this, arguments);
436
+ }
377
437
  const drain = function() {
378
- var _ref7 = _asyncToGenerator(function* () {
438
+ var _ref6 = _asyncToGenerator(function* () {
379
439
  if (processing || disposed) return;
380
440
  processing = true;
381
441
  try {
@@ -388,7 +448,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
388
448
  }
389
449
  });
390
450
  return function drain() {
391
- return _ref7.apply(this, arguments);
451
+ return _ref6.apply(this, arguments);
392
452
  };
393
453
  }();
394
454
  return {
@@ -430,7 +490,7 @@ function createWorkflowActor({ definition, context, sessionEpoch, transitionRunn
430
490
  const fromNodeId = snapshot.nodeId;
431
491
  commit(fromNodeId, fromNodeId, {
432
492
  intentId,
433
- outcome: "systemBlocked"
493
+ intent: "systemBlocked"
434
494
  }, snapshot.context, true, error);
435
495
  },
436
496
  dispose: () => {