# 计费业务流程 v2

## 正常流程

```mermaid
sequenceDiagram
  participant UI as 前端
  participant API as Gateway API
  participant DB as PostgreSQL
  participant UP as 上游模型
  participant BW as 结算 Worker

  UI->>API: 参数变化后的只读估价
  API->>DB: 读取有效计价规则
  API-->>UI: 首选预计费用 + 候选最大冻结额
  UI->>API: 正式提交（可带 Idempotency-Key）
  API->>DB: 重新计价、保存快照并冻结最大金额
  API->>DB: 领取执行租约
  API->>UP: 提交已预处理请求
  UP-->>API: 成功结果与实际用量
  API->>DB: 原子写 Attempt、任务成功、最终金额和 settle Outbox
  API-->>UI: succeeded + billingStatus=pending
  BW->>DB: SKIP LOCKED 领取 Outbox
  BW->>DB: 原子扣费、释放冻结、完成 Outbox
```

## 失败与取消

上游提交前失败、上游明确失败和用户取消均在任务终态事务内写入 `release` Outbox。Worker 使用冻结流水的幂等键释放资金。若上游请求已经进入 `submitting`，或成功响应已返回但任务终态尚未提交，租约接管必须停止自动执行；任务和对应 Outbox 转人工复核并保留冻结。

人工复核记录在管理端明确显示后续动作。上游结果不明的记录只能由 Manager 在完成外部核查后确认释放；历史成功未扣费且金额快照可用的记录可由 Manager 明确确认结算。两类操作均要求确认、`Idempotency-Key` 和审计记录，且不会再次调用上游。

## 即时估价

前端仅对影响计费的字段生成稳定签名，包括模型、生成模式、数量、质量、分辨率、时长、音频、参考素材和 Token 上限。签名变化后等待 350ms，取消旧请求，并用递增序号阻止乱序响应覆盖。

界面必须区分：

- 计算中；
- 显式免费；
- 正常预计费用与冻结上限；
- 价格不可用；
- 估价请求失败。

价格不可用或估价失败时禁止生产生成；模拟模式仍允许执行并显示原因。

## Worker 参数

- 轮询间隔：1 秒。
- 单批数量：50。
- 处理锁过期：120 秒。
- 最大自动尝试：20 次。
- 退避上限：15 分钟。

这些参数是安全默认值，可通过受控配置调整，但不得改变幂等键、快照和账务不变量。

## 发布与回滚

`BILLING_ENGINE_MODE` 支持：

- `observe`：并行计算并记录差异，不改变旧路径账务结果。
- `enforce`：启用 v2 缺价拒绝、冻结与结算闭环。
- `hold`：在调用上游前拒绝新的生产任务，已有 Outbox 继续处理。

发布先运行 24 小时 observe，补齐所有缺价和非法规则，再以 10% 流量启用 enforce，确认没有重复扣费、长期冻结和异常差额后扩大到 100%。回滚只切换到 hold，不回滚数据库增量，也不恢复隐式零价。
