修复资产计费边界风险

资产生成预扣费改为 fail-closed,避免钱包异常时继续调用外部生成

新增钱包退款 outbox,退款失败时本地落盘并后台重放

拼图首图后台任务改用 SpacetimeDB claim 表实现跨实例互斥

计费 ledger id 统一绑定 request_id,并让前端重试复用 x-request-id

同步 SpacetimeDB bindings、后端架构文档和 Hermes 决策记录
This commit is contained in:
2026-06-11 15:55:23 +08:00
parent 86ea69f79d
commit f8a80cd795
34 changed files with 1678 additions and 264 deletions

View File

@@ -190,6 +190,10 @@ npm run check:server-rs-ddd
1. `creation_entry_type_config.unified_creation_spec_json` 内的 `mudPointCost` 是玩法新建草稿初始生成的泥点成本真相源,同时供入口卡展示和前端余额前置校验使用;旧契约缺失时允许按代码默认成本兜底。
2. `api-server` 执行拼图首图生成、抓大鹅完整草稿生成和汪汪声浪初始三图生成时,必须通过 `GET /api/creation-entry/config` 同源配置解析对应玩法成本后再调用钱包扣费 procedure不得继续使用前端或后端硬编码常量作为实际扣费真相。
3. 结果页单图重生成、发布、道具使用和其它独立资产操作仍按各自业务操作成本执行;不要把初始草稿成本误套到这些单次操作上。
4. 资产操作的预扣费必须 fail-closed钱包或 SpacetimeDB 预扣费不可达、超时或返回业务错误时,`api-server` 直接返回错误不允许继续调用图片、音频、GLB 等外部生成 provider。
5. 需要支持 HTTP retry 的计费 ledger id 必须包含当前请求的 `request_id`;前端 `fetchWithApiAuth` 同一次业务请求的静默刷新重试复用同一个 `x-request-id`,后端不得再使用 prompt 指纹或随机 asset id 作为扣费幂等键。
6. 外部生成已预扣费但后续失败时必须先同步调用钱包退款;若 SpacetimeDB 暂不可用,退款请求写入 `wallet-refund-outbox` 本地文件并由后台 worker 重放。默认启用,配置项为 `GENARRATIVE_WALLET_REFUND_OUTBOX_ENABLED``GENARRATIVE_WALLET_REFUND_OUTBOX_DIR``GENARRATIVE_WALLET_REFUND_OUTBOX_BATCH_SIZE``GENARRATIVE_WALLET_REFUND_OUTBOX_FLUSH_INTERVAL_MS``GENARRATIVE_WALLET_REFUND_OUTBOX_MAX_BYTES`。outbox 文件按 refund ledger id 幂等落盘;成功重放后删除,坏文件隔离为 `corrupt-*`
7. 拼图首图后台生成的跨实例互斥锁必须落在 SpacetimeDB `puzzle_background_compile_task`claim id 由 `task_id + request_id` 构成,释放时必须校验 claim id避免旧后台任务释放新请求抢到的租约。
## 外部服务与资产
@@ -640,6 +644,12 @@ npm run check:server-rs-ddd
- Rust 结构体:`PuzzleAgentSessionRow`
- 源码:`server-rs/crates/spacetime-module/src/puzzle.rs`
### `puzzle_background_compile_task`
- Rust 结构体:`PuzzleBackgroundCompileTaskRow`
- 源码:`server-rs/crates/spacetime-module/src/puzzle.rs`
- 说明:拼图首图后台生成的跨 api-server 实例互斥 claim 表,只保存活动任务租约,不表达最终生成结果;`task_id` 为主键,`claim_id` 用于释放时防止误删新租约,租约超时时间为 30 分钟。
### `puzzle_event`
- Rust 结构体:`PuzzleEvent`