# 拼图运行态 `run_json` 计时字段兼容修复 2026-04-29 ## 背景 作品详情页点击“启动”时,Rust API 通过 SpacetimeDB `start_puzzle_run` procedure 拿到字符串化的 `run_json`,再在 `spacetime-client` 映射层反序列化为拼图运行态快照。 本次线上报错为: ```text puzzle run run_json 非法: missing field `started_at_ms` ``` 说明主云 procedure 已成功返回快照,但返回的 JSON 仍可能是旧字段集,没有带上后续限时与排行榜迭代新增的计时字段。 ## 根因 `PuzzleRuntimeLevelSnapshot` 在早期 PRD 中只包含关卡基础信息、棋盘和状态。后续版本新增: 1. `started_at_ms` 2. `cleared_at_ms` 3. `elapsed_ms` 4. `time_limit_ms` 5. `remaining_ms` 6. `paused_accumulated_ms` 7. `pause_started_at_ms` 8. `freeze_accumulated_ms` 9. `freeze_started_at_ms` 10. `freeze_until_ms` 11. `leaderboard_entries` 其中部分字段已经有 `serde(default)`,但 `started_at_ms`、`cleared_at_ms`、`elapsed_ms`、`leaderboard_entries` 仍按必填字段解析。只要主云旧模块或历史快照缺少这些字段,API facade 就会在映射层失败,导致详情页启动中断。 ## 修复口径 本次只做后端兼容,不改表结构,不改前端表现: 1. `module-puzzle` 的运行态快照新增字段统一允许缺省。 2. 旧 JSON 缺 `started_at_ms` 时,用当前毫秒时间作为兼容起点,保证前端倒计时不会从 `0` 时间戳开始。 3. 旧棋盘缺 `all_tiles_resolved` 时按 `false` 处理。 4. 旧 run / level 缺 `leaderboard_entries` 时按空榜单处理。 5. `spacetime-client` 增加回归测试,确保 `run_json` 缺新增计时字段仍能启动。 ## 经验结论 `procedure -> run_json/items_json -> client record` 这类链路只要返回字符串化聚合快照,新增字段就必须默认具备向后兼容能力。平台入口级操作不应因为单个新增字段缺失直接 500;能安全补默认值的字段,应在服务端契约层统一兜底。