# HDLKiosk 实施进度

> 文档角色：当前事实快照，不记录完整开发流水。  
> 更新日期：2026-08-20

## 1. 阶段结论

架构骨架和本地三入口运行机制已经完成。项目下一阶段不再扩展通用架构，重点转为：

1. 正式 BigSale/OS 业务桥；
2. 支付、Cart Overlay 卡券、Result 等真实业务事实；
3. Scanner/Scale/支付实机验收；
4. 按 Screen 完成 UI 还原；
5. 生产稳定性、可达性和运营能力。

当前代码可以进行端到端联调，但不能标记生产完成。

## 2. 能力状态

状态说明：

- `本地完成`：Core/Fake Host/Adapter 已有实现与自动测试；
- `待 Host`：本地结构存在，缺正式 OS 契约；
- `待实机`：代码存在，尚未完成真实设备/支付验证；
- `待业务/UI`：页面位置存在，业务或视觉尚未完成。

| 能力                  | 状态         | 当前结果                                                                                                                                                                             | 主要缺口                                                       |
| --------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------- |
| 独立物料边界          | 本地完成     | Core 不依赖 BigSale/SalesSDK                                                                                                                                                         | 持续守住依赖门禁                                               |
| BigSale 模板装配      | 本地完成     | `tmpl=HDLKiosk`、稳定 Host、动态 capability                                                                                                                                          | 真实 Context 契约验收                                          |
| Workflow Runtime      | 本地完成     | 三个 built-in workflow、compiler、actor                                                                                                                                              | 业务变化时同步 Definition 与测试                               |
| Operation/Coordinator | 本地完成     | 冲突、去重、epoch、timeout、freeze                                                                                                                                                   | 真实 OS 时序验证                                               |
| 表现层目录与边界      | 本地完成     | Screen/Dialog/Layout 独立目录与样式；Renderer/View Model 集中在 Presentation；Shell 通过 BottomBarHost 唯一挂载 FloatingBar/CartDrawer                                               | 后续逐 Screen 声明 BottomBar，不在 Screen 内重复挂载容器       |
| Quick 主商品          | 待实机       | 模板临时商品 ID 通过 OS query 获取；Fulfillment 后进入 Customization，本地保留称重/options 草稿，Next 才交给 OS 加购，价格只消费 OS Projection                                      | 正式商品 ID 配置、真秤及真实折扣验收                           |
| Barcode               | 待实机       | 无头 ScannerSessionRouter 在 active 生命周期常驻；Entry、启动中和 Flow 共用 5 项 FIFO，首码等待 Session 发布后串行加购且不导航 | 商品码专用 Host API、选择态闭环、稳定 eventId、全局反馈与实机 |
| Scale                 | 待实机       | 顶层 Runtime、自动入口；有效重量先进入 Fulfillment，再进入与 Quick 共用的 Customization，本地草稿在 Next 时提交                                                                   | 真秤全矩阵、正式商品                                           |
| Catalog               | 待实机       | HDLKiosk 模板驱动现有 retail Product Provider 正式 load 后读取快照；分类/搜索/商品卡、连续加购、订单悬浮栏及购物车 Drawer 已完成                                                     | 大目录虚拟化、复杂规格接管、实机视觉                           |
| Cart Overlay          | 待业务/实机 | 已替代独立 Review/Voucher Slice；复用全局 BottomBar，展示 Host 商品、数量、卡券入口、小计和备注能力                                                                                | 称重/定制重新编辑、价格变化反馈、促销/税/节省明细              |
| Identity 登录        | 待实机       | BigSale 内注册 H5 Login2/Register2；认证结果经 complete 进入 identity.sync，客户写入、订单一致性和重报价统一由 Adapter/Operation 完成                                                | 登录/注册实机交互、错误文案与客户搜索结果验收                  |
| 会员中途登录          | 待 Host      | Activity 级本地入口策略、customer/cart 互斥、统一 Screen Command、重新计价验证；partial/unknown 阻塞 Workflow                                                                        | 将同一 H5 认证能力接入 Shell/Cart Overlay 入口                 |
| Fulfillment           | 待 Host      | Workflow Context 已接；支付 dispatch 前的 `ensurePrepared` 统一写入并验证履约方式                                                                                                   | 当前仍允许临时模拟                                             |
| Voucher               | 已并入 Overlay | 不再是 Workflow Slice；由 Cart Overlay 展示并操作当前用户卡券                                                                                                                       | 真实券列表、应用、撤销和 quote                                 |
| Payment Method        | 待 Host/实机 | 原型首版双栏 UI、Host 应付金额、Card 安全 checkout、Cash 全屏员工等待、Shell Back                                                                                                    | Card 精确映射、Cash 员工契约和实机视觉                         |
| Payment Safety        | 待实机       | Prepared freshness 状态、stale 失效、支付 Operation 内统一 `ensurePrepared`、unknown 阻塞和危险写冻结；不再绑定 Catalog/Payment Screen                                               | 结果查询、零元、故障 E2E                                       |
| Session/Reset         | 待实机       | Exit Policy、单一 pendingExit、验证式 reset、session epoch 与原子 Session 释放                                                                                                      | 外部应用级超时策略、重启/断电后的 Host/OS 处置                  |
| Result                | 待 Host/实机 | 原型首版取餐号卡片、会员/Guest 积分卡；checkout 成功回执独立保留，内部 orderId 不再作为取餐号                                                                                       | 正式 pickup/桌号契约、真实积分和 Guest claim QR                |
| Telemetry             | 待 Host      | Core 事件接口                                                                                                                                                                        | BigSale sink 当前 no-op                                        |
| UI/多语言/可达性      | 进行中       | Entry、Identity、Fulfillment、Customization、Catalog、Cart Overlay、Payment Method/Cash Waiting、Result 已有英文/简中首版；Shell 统一 Header、会员面板、FloatingBar 和 Overlay | 真实会员二维码/SMS、繁中/日文/韩文和实机视觉                   |

## 3. 当前临时策略

| 策略                     | 当前状态 | 风险                                         | 删除条件                      |
| ------------------------ | -------- | -------------------------------------------- | ----------------------------- |
| 固定称重商品 ID          | 启用     | 当前模板常量为 `61962`；商品数据已来自 OS query | 租户/门店称重商品配置       |
| simulated fulfillment    | 启用     | 用餐方式可能未写入 OS                        | 正式 writer + 写后 Projection |
| 无跨刷新会话恢复         | 当前设计 | 支付派发窗口刷新依赖 OS 查询与员工处置       | 明确 OS 查询/幂等与业务恢复需求 |
| Barcode fingerprint 去重 | 降级启用 | 无稳定 eventId 时存在短窗误判                | OS 稳定 scan eventId          |
| Identity 登录 fallback   | 启用     | H5 模块不可用时退回二维码/SMS 静态展示       | OS 登录模块成为强制能力      |

临时策略只存在于 BigSale 装配层；独立 Core 默认保持严格契约。

## 4. 已确认的重要行为

- Catalog Screen 本身不请求商品；HDLKiosk BigSale 模板在装配边界复用现有 Product Provider `load(productLoadParams)` 激活餐牌，继续保留 retail 的餐牌筛选、客户上下文和智能报价；Screen 不直接 `queryProducts` 或维护第二份 Catalog；
- Catalog Host DTO 只新增稳定的分类路径投影，UI 在 HDLKiosk 内完成分类、子分类和搜索；加购仍从 BigSale 当前快照找回完整 `ProductData` 后调用 `addProductWithFlow`，不会创建第二套商品加载或报价链路；
- 称重主商品不再依赖本地 mock：详情直接消费 `sourceData.catalogProducts` 中的标准 ProductData；确认写入时由 operation 重新查询并校验；
- Ticket 当前 ProductList 未预载主商品时，先通过 `findByIds({ loadMissing: true, refreshCatalog: false })` 定向补拉，再回到 `queryProducts`；不会要求先进入 Retail，也不会覆盖共享 Catalog；
- 三入口统一以称重主商品查询作为会话前置能力；旧 pisellos 未提供 `queryProducts` 时全部安全关闭；
- Host/bridge 晚到不会替换 Host 或销毁活跃 Workflow；
- HDLKiosk 配置与兼容 bridge 已收回模板目录内部；BigSale 公共 Props 不再暴露或逐层透传 `hdlKioskConfig/hdlKioskHostBridge`；
- Quick/Scale 在 Customization 前确认 fulfillment，支付 dispatch 前的 `ensurePrepared` 再把该事实写入并验证；
- Shell 中途登录保持原节点并等待 customer/summary 收敛；
- Customization 将称重/options 保持为页面本地草稿，输入变化不写 OS；Next 才通过 `addProductWithFlow` 提交，加购成功后前进；底栏和 Drawer 统一读取已确认的 `summary.due/cart.lines`；
- Customization 通过本物料内的 `HDLKioskSkuOptionsSelection` 将原 ProductData 直接作为共享 `skuOptionsSelection` 的 dataSource，只转换选中结果；独立运行缺少 Engine 上下文时直接读取同一 option 结构兜底；
- HDLKiosk 已删除主商品额外业务弹窗相关的 Activity、Host Contract、Projection 和 Checkout Requirement；是否展示额外弹窗由 OS 加购流内部决定；
- Barcode 主商品询问使用独立 Modal Slice；拒绝或 Customization 跳过后直接进入 Fulfillment，Back 按真实页面历史返回 Catalog，再次前进沿用已提交的标准结果；
- Cart Mutation 以 Host consistency barrier 为权威，不再被晚一帧提交的 `consistencyPending` 展示态误判为 unknown；
- 普通 Catalog/Cart Overlay 写操作不显示全屏遮罩；Catalog 批量锁定卡片时保持原视觉，减少短操作闪烁；
- Scale Hook 在顶层单一运行，Entry 和 Customization 详情消费同一快照；Scale workflow 从 `fulfillment` 开始，再复用 `customization` 页面分支；
- Checkout callback 模糊结果保持 unknown；
- Checkout callback 明确返回 `cancelled` 时，Safety 只重发绑定原 fingerprint/应付金额的短期 token；第二次唤起前仍重新校验当前 OS 订单，订单变化或结果不明确时不会放行；
- Result 不再把内部 `orderId` 当作取餐号；支付确认后先读取 OS 本地 tempOrder，本地 `shop_full_order_number` 为空时按当前 `order_id` 异步查询只读订单详情，并通过 `sourceData.completedOrder` 直传；
- `pending/payment_processing` 是可编辑草稿，`payment_pending/processing` 是支付未决；
- OS 清理后的 `paid + 无 orderId + 空 cart` 空壳映射为 idle，不再从 Entry 锁入 blocked；
- 当前不读写会话恢复点；OS Payment Projection 和当前页面生命周期内 Checkout Safety 仍保留。
- 写后一致性已统一为“writer receipt 优先、Projection 兼容回退”：覆盖称重行、普通数量/删除、扫码、客户、Summary 与 reset，避免 React 晚一 commit 造成假失败；Checkout 仍保留独立 fail-closed 规则。

## 5. 最近关键验证

- HDLKiosk Core 与 BigSale Adapter 的主要定向回归在各业务切片中持续通过；
- 称重主商品切换到 OS `queryProducts` 后，BigSale Adapter 与称重映射 2 个测试文件、34 个用例通过；本地 mock 已退出运行时依赖；
- Ticket 真实页面验证了缺失主商品的定向 hydration、Quick Catalog Back 以及同一商品连续加购；Catalog 列表探针确认操作期间组件未卸载、商品数保持 67；
- 本轮 Core/Workflow/Adapter 定向回归 6 个测试文件、64 个用例通过；
- BigSale 公共边界收缩后，Adapter 纯逻辑定向回归 4 个测试文件、42 个用例通过；Hook 用例因工作区缺少 `@testing-library/react` 未能启动，完整 `tsc` 仍被本地 `node_modules/@types/react/index.d.ts` 的既有语法损坏阻断；本轮变更文件已通过 esbuild 语法转换检查；
- Entry 首版复用了原型主视觉和 SVG 动效，在 1080×1920 画布与原型逐项对照：Quick 卡原型 `y=773.0`、当前 `y=769.8`，卡片宽高、三卡总高度与底部工具区位置一致；同时增加 1280×720 横屏降级布局；
- Entry 的英文/简中切换与 Reach Mode 已在独立预览中验证；Reach Mode 将主操作区从约 `y=604` 下移到 `y=849`，不改变 Workflow/设备入口语义；Less 编译和 Entry esbuild bundle 通过，入口与共享展示投影 7 个用例通过；React 组件测试仍被工作区缺少 `@testing-library/react` 阻断；
- 表现层按所有权组织：业务私有 Screen/Dialog、ViewModel 与 `slice.ts`、`view.tsx` 同置于 `slices/<name>/`；跨 Slice 的 Shell、Overlay 和公共控件位于 `components/`，公共类型与纯方法分别位于根 `types.ts`、`utils.ts`；活跃会话 UI 编排位于 `ui/HDLKioskWorkflowView.tsx`；
- 组件依赖门禁递归覆盖 `slices/`、`components/` 与 `ui/entry`；Slice 业务定义不依赖 React，Workflow/Operation 纯逻辑测试不会加载物料 UI；
- Identity 已从通用 Step 拆成独立 Screen，并按原型还原沉浸式品牌区、会员利益标题、App QR、SMS 和 Skip；Shell 使用显式 `identityGate` 变体隐藏常规页头/页脚。SMS 无业务 handler，Skip 复用既有 Guest `identity.sync`；109 个纯逻辑用例、Less 编译和根入口 esbuild bundle 继续通过；
- Fulfillment 已从通用 Step 拆成独立 Screen，完成堂食/外带卡片及自动前进；BottomBar 不再假定该节点位于空订单阶段，实时购物车有商品时组合通用 `HDLKioskOrderSummary` 和可编辑 CartDrawer，显示 OS 确认的数量/金额；空车时仅保留 Back。Drawer 在此节点不伪造 Next，用户仍需在页面选择堂食或外带；
- Customization 已完成称重主商品详情首版并按原型校准：Hero 固定，只有 options 区滚动；称重栏保留状态标识与 Unit Price/Weight/Tare；规格分组 Tab 在 HDLKiosk 作用域隐藏，不修改共享 `SKUOptionsSelection`。重量/options 只保留页面本地草稿，Next 才交给 OS `addProductWithFlow`，成功后前进；底栏和 Drawer 只使用 OS `summary.due`，不自行估算折扣；
- Catalog 已按原型的信息架构完成独立 UI：固定左侧一级分类、右侧搜索与子分类胶囊、双列商品卡、不可售遮罩和加购数量圆钮。分类来自 OS `category/parent_category` 的最小只读投影，搜索不触发远端 load；BottomBar 声明中的数量、总额和会员状态只读取 Host Projection。Quick/Scale 主称重商品从补充商品目录统一排除，Barcode 的自循环 Back 不再展示无效按钮；
- Catalog 主动作统一为 `Checkout`；独立 Review/Voucher Slice 已移除，商品复核、数量/删除、卡券、备注和小计集中在 Shell 的 Cart Overlay，并继续只读取 OS Projection；
- Payment Method 已完成原型首版双栏视觉：左侧支付标题，右侧 Host Payment due、Visa/Mastercard 主选择和 Cash 次选择，Shell 底栏仅保留 Back。Cash 使用不可由顾客关闭或手动确认的全屏员工等待层，仍只有 Host `payment.succeeded` 才能推进 Result；
- 支付弹窗明确取消后允许再次唤起；所有支付 dispatch 都先通过 `ensurePrepared(currentVersion)`，事实不变时复用有效 token，变化、过期或 stale 时重新 prepare，unknown/partial payment 继续冻结；
- Result 已按原型完成首版：超大取餐号卡片、会员确认/Guest 扫码双态和 Shell 单按钮底栏；支付成功回执可跨 Host Projection 清理保留到终态，取餐号缺失时不回退内部 orderId。Workflow、ViewModel、Checkout 与 BigSale Adapter 共 4 个测试文件、69 个用例通过，Result Less lint 与组件 esbuild 语法转换通过；
- Result 已根据原型 1080 × 1920 运行页面的实测尺寸校准：保持纵向卡片结构，Guest 二维码使用 380px 深色粗边框，会员完成标识为 92px，单动作底栏宽 378px；移除原型不存在的矮视口双栏分支。Screen 定向测试 9 个用例、Less 编译、根入口 esbuild 和 `git diff --check` 通过；
- Result 的取餐号与积分卡文案按原型固定为左对齐；HDLKiosk 物料边界统一禁止英文单词内部断行，避免宿主样式把 `Mastercard` 等单词拆开。支付主卡同步收敛字号上限，为完整单词和右侧箭头保留稳定空间；
- Scale 自动入口已校准：有效重量启动后先进入 `fulfillment`，再进入与 Quick 共用的 `customization`，使用同一 `CustomizationScreen` 与 `product.syncPrimaryWeightedProduct`；入口 capability 同时要求 customization 能力；
- 本次 Scale 校准的 Workflow/Actor/ViewModel/Customization 定向回归共 5 个测试文件、40 个用例通过；HDLKiosk 汇总 Less lint、根入口 esbuild 语法打包及 `git diff --check` 通过；
- Result 取餐号只读取本地或只读详情请求返回的原始订单 `shop_full_order_number`；`paymentResult` 仅保存支付状态、来源与金额事实，不再携带或推断订单编号；
- Barcode 当前使用“激活 Session → 消费首码 → Catalog → 缺主商品时询问 → Yes 时 Fulfillment → 称重详情 → Next/OS 加购成功 → Catalog”的路径；No 保持在 Catalog 且不要求 Fulfillment，Cart Overlay 完成订单复核与卡券操作；
- 移除遗留 `hdl-shell__footer` 与 `resolveScreenBottomBar`：Fulfillment、Customization、Catalog 改为声明实时 BottomBar，由 Shell 内唯一 `HDLKioskBottomBarHost` 渲染。BottomBar 当前区分 `visible / masked / hidden`：退出确认及 Catalog 主商品询问等普通 Modal 保留底栏并由遮罩阻止交互，同时自动收起 CartDrawer；只有等待员工、支付未决和 blocked 等不可导航状态才隐藏。购物车图标已接入基于 `CompensatedPisellContainer` 的底部 Drawer，展示 Host 已确认的商品、定制摘要、数量和金额，并在三个 Catalog workflow 中复用既有改数量/删除 Operation；
- Workflow 使用线性优先的 Slice 数组：数组为 Slice Resolution 提供主路径的默认前进目标，`on` 只描述分支、合流和跳跃；Back 是独立 Navigation，并按实际页面历史解析。同一 Slice 可用 `slice:用途` 多次出现，回路必须声明有限 repeat，Actor 超限即阻塞；Resolution 同时携带 `stepId/activityId`，避免同类 Activity 的迟到实例误触发当前 Step。支付不确定是 Actor blocked 状态，不作为业务节点；
- `slices/<name>/slice.ts` 是各业务能力唯一导出的 `defineSlice` 结果：Slice `id` 标识业务 Activity，`surface.id` 标识页面类别；`view.tsx` 就地完成该 Slice 的 ViewModel 派生和组件装配，`ui/views.ts` 单独维护完整的 Activity → View 本地注册表，`ScreenRenderer` 进行同步解析。Kernel、Slice 和 Workflow 不依赖 React View；公共类型与跨 Slice 纯方法分别集中在根 `types.ts`、`utils.ts`；
- Kernel 已不依赖 HDLKiosk contracts：结构 Compiler、Actor 和通用 Coordinator 位于 `kernel/`；Application 契约位于 `app/contracts`，具体 Host Handler 与 Coordinator 位于 `runtime/operations/`，其中注入 HDLKioskHost、冲突矩阵、支付冻结、错误分类和遥测；
- HDLKiosk 阻断式 Dialog 已统一到 `HDLKioskModal → pro/compensatedPisellContainer`，默认层级高于 CartDrawer；BottomBar 的三态解析、组件依赖边界、Checkout 安全及现有 Dialog/Screen 定向用例通过，HDLKiosk 汇总 Less 编译、变更组件 esbuild 语法转换和 `git diff --check` 通过；
- Shell 中途登录统一走 `executeCommand(identity.sync)`；明确失败可在原页重试，客户写入/重报价 `partial/unknown` 会阻塞 Actor。物料不维护 idle 警告或倒计时 UI；Runtime 使用 Workflow Exit Policy 处理 Back Boundary、显式退出、支付完成与故障恢复；
- Checkout 前置业务要求由 Activity Contract 声明 ID，Compiler 按当前流程汇总，Requirement Registry 结合 Workflow Context 和 Host Projection 判断适用性与满足状态。当前默认 Registry 为空；
- 称重页的 Next 携带点击当下的商品/重量/options 草稿；点击前不同步 Host。详情页与 Scale 入口共用最小有效重量，稳定的微小残留不会启用 Next；
- Scale Runtime 以 NativeScale `onChange` 的递增采样序号区分真实新帧：断连、停止监听、读取错误、负重或超载后必须收到新帧才恢复；稳定读数不使用固定超时。Next 点击时同步复核 Runtime 最新快照，SkuDetailModal 实时 Auto 同步要求 live/stable/connected/listening；
- Barcode/Scale 是会话外部入口，不作为可前进/后退的 Workflow Activity。Barcode 首码在 Session `readyForCommands && cartWritable` 后消费，不依赖首屏类型；Scale Workflow 从 Customization 开始。两者的首页 Back 返回 Flow Boundary，并由 Runtime Exit Protocol 处理，无需入口节点特例；
- `ScannerSessionRouter` 持有 Scanner 订阅、Entry、pending Quick/Scale 与 Flow 共用的有限 FIFO；Application Session lifecycle 通过 `open/attach` 连接 Session，Attachment 在 Registry 发布后激活。支付准备是支付 dispatch 的内部前置条件；
- 临时 live-debug reporter、密钥、日志和 Collector 已清理；
- 日常验证遵守工作区规则，未使用 pnpm/npm 运行 material webpack build。
- 当前目录职责为 `kernel / app / slices / runtime / ui / components / testing`；共享阻断表面使用 `BlockingNotice`，履约写入由 Checkout Prepare 统一完成。

本地 `468867` 参考文件不再参与运行时 import；无需恢复或维护为可执行 mock。

## 6. 已知生产风险

- Fulfillment、Cart Overlay 卡券、Cash、pickup 和积分尚无完整正式 Host；
- 支付结果查询 capability 仍为 false；
- 当前不提供跨刷新会话恢复；
- 称重商品 ID 仍是联调固定值，正式门店配置尚未接入；商品结构和 options 已不再使用本地 fallback；
- Barcode 无稳定 eventId；
- Telemetry 未接真实 sink；
- Entry、Identity、Fulfillment、Customization、Catalog、Cart Overlay、Payment Method/Cash Waiting 已有首版视觉，其余 UI 及所有设备、断电和长时间运行尚未完成生产验收。

## 7. 下一步

按 [07-后续工作.md](./07-后续工作.md) 选择一个真实业务纵向切片。优先顺序：正式 Fulfillment/Customer → Payment 结果与查询 → Voucher/Result → 称重生产化 → OS add flow 实机联调 → UI Screen-by-Screen 还原。

最新调整：独立 Result Slice/Screen 已移除。`paymentCompleted` 作为支付成功终态与 `paymentMethod` 共用 Checkout Screen/View，复用旧版 `PaymentResultToastV2`，支持手动返回和 10 秒自动验证式 reset。本地取餐码为空时会异步读取订单详情，加载时间不消耗该倒计时；请求结束后再从 10 秒开始。

每项完成后只更新：

- 本文的能力状态、临时策略和最近关键验证；
- `07-后续工作.md` 的未完成项；
- 契约确有变化时更新对应主题文档。

不要恢复按 M01–M12 记录的历史流水。
