
== B2b 自测 ==

  ✓ 协议包常量：engineHash 基线与幂等键格式
  ✓ 有效 manifest → 落账 + 协议常量键 + 结算凭证
  ✓ 重复 manifest → 幂等（不重复入账）
  ✓ 重启后仍识别重复（从账本重建索引）
[settle-alarm] {"at":"2026-09-17T18:17:40.200Z","kind":"ENGINE_HASH_MISMATCH","tableId":"T-4c352a9a0000","handId":"H-aa73cd700000","detail":{"got":"0000000000000000000000000000000000000000000000000000000000000000","expected":"d8b87237f4b9ec79ed9234843f6c8b1f0f610fc4220998db5bc60b409ea7726a"}}
  ✓ engineHash 不匹配 → fail closed 拒记 + 报警
[settle-alarm] {"at":"2026-09-17T18:17:40.201Z","kind":"CONSERVATION_FAILED","tableId":"T-4d352c2d0000","handId":"H-2ea386470000","detail":{"errors":["conservation.sumDeltaSat=0 与按玩家重算的 111 不一致","Σ(endStack-startStack) = 111 ≠ 0（筹码不守恒）","conservation.balanced 与实际校验结果不符（疑似伪造凭证）"]}}
  ✓ 筹码不守恒 → 拒记 + 报警
[settle-alarm] {"at":"2026-09-17T18:17:40.201Z","kind":"CONSERVATION_FAILED","tableId":"T-4a3527740000","handId":"H-dc1b9fe20000","detail":{"errors":["conservation.sumPotsSat=1000 与 pots 求和 1005 不一致","conservation.balanced 与实际校验结果不符（疑似伪造凭证）"]}}
  ✓ 伪造 balanced / pots 总数不一致 → 被检出
  ✓ 结构非法（未知字段 / 非法 tableId）→ INVALID_MANIFEST
  ✓ 逐人 delta 与 stacks 不一致 → DELTA_INCONSISTENT 拒记
  ✓ 输家冻结不足 → 拒记且零半截入账
  ✓ free 模式 → mode=free 事件、零凭证
  ✓ perHand 开关：开=生成派付指令 / 关=不生成
  ✓ rake>0：手级键用于 rake 事件（协议常量）
  ✓ 凭证链：recordPin 后 prevReceipt 串联
[settle-alarm] {"at":"2026-09-17T18:17:40.242Z","kind":"ENGINE_HASH_MISMATCH","tableId":"T-c54122080000","handId":"H-d539771e0000","detail":{"got":"1111111111111111111111111111111111111111111111111111111111111111","expected":"d8b87237f4b9ec79ed9234843f6c8b1f0f610fc4220998db5bc60b409ea7726a"}}
  ✓ HTTP：存款请求 → 链上入账 → 余额 → 买入 → 结算 → 出金 全链路
  ✓ Metalet 适配器：utxo-list 解析 / 余额求和 / 快照同步契约
  ✓ Metalet 适配器：错误路径（code≠0 / HTTP 5xx）
  ✓ 对账：R1/R2/R3 pass + R3 篡改检出 + R5 free 零链上
  ✓ LIVE（RUN_LIVE=1 时）：Metalet 主网只读核验托管地址
  ✓ CORS：OPTIONS 预检 204 + 全响应 ACAO（供 D2 客户端直连）

== 结果：20 通过 / 0 失败 ==
