# b2f
> 文档版本：v1.10
> 最后更新：2026-04-03 20:10:25


说明：

- 只写事实和请求
- 每条固定包含：时间、谁提的、当前事实、需要对方确认什么、是否已解决

---

## 待确认

### B2F-001

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - backend 当前主链已经可联调：
    - `POST /auth/login/wechat-mini`
    - `GET /me/entry-home`
    - `GET /events/{eventPublicID}/play`
    - `POST /events/{eventPublicID}/launch`
    - `POST /sessions/{sessionPublicID}/start`
    - `POST /sessions/{sessionPublicID}/finish`
    - `GET /sessions/{sessionPublicID}/result`
  - 当前建议统一使用 demo 入口：
    - `eventPublicID = evt_demo_001`
    - `channelCode = mini-demo`
    - `channelType = wechat_mini`
- 需要对方确认什么：
  - frontend 是否按这组 demo 数据作为当前唯一联调入口
- 是否已解决：否

### B2F-002

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - 进入游戏的正式流程必须以 `launch` 返回值为准
  - backend 当前约定字段：
    - `launch.resolvedRelease.releaseId`
    - `launch.resolvedRelease.manifestUrl`
    - `launch.resolvedRelease.manifestChecksumSha256`
    - `launch.config.configUrl`
    - `launch.config.configLabel`
    - `launch.config.releaseId`
    - `launch.config.routeCode`
    - `launch.business.sessionId`
    - `launch.business.sessionToken`
    - `launch.business.sessionTokenExpiresAt`
- 需要对方确认什么：
  - frontend 是否确认正式流程只消费上述字段，不再自行推断 release URL
- 是否已解决：否

### B2F-015

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已阅读前端多赛道文档：
    - [多赛道 Variant 五层设计草案](D:/dev/cmr-mini/doc/gameplay/多赛道Variant五层设计草案.md)
    - [多赛道 Variant 前后端最小契约](D:/dev/cmr-mini/doc/gameplay/多赛道Variant前后端最小契约.md)
  - backend 认可第一阶段先做“最小契约”，不先做完整后台模型
  - backend 当前建议的第一阶段正式口径为：
    - `play.assignmentMode`
    - `play.courseVariants[]`
      - `id`
      - `name`
      - `description`
      - `routeCode`
      - `selectable`
    - `launch.variant.id`
    - `launch.variant.name`
    - `launch.variant.routeCode`
    - `launch.variant.assignmentMode`
    - `session / ongoing / recent / result` 摘要中补：
      - `variantId`
      - `variantName`
      - `routeCode`
  - backend 第一阶段实现目标仍然保持保守：
    - 一个 session 只绑定一个最终 `variantId`
    - `launch` 返回最终绑定结果
    - 恢复链不重新分配 variant
  - 当前兼容性约束：
    - 如果 `assignmentMode=manual` 且前端暂时未传 `variantId`
    - backend 当前会先回退到首个可选 variant，避免旧主链直接被打断
  - backend 当前已完成第一阶段最小实现：
    - `GET /events/{eventPublicID}/play`
    - `POST /events/{eventPublicID}/launch`
    - `GET /me/entry-home`
    - `GET /sessions/{sessionPublicID}`
    - `GET /sessions/{sessionPublicID}/result`
    - `GET /me/results`
    - `GET /me/sessions`
    - 上述链路已能携带第一阶段 variant 摘要字段
- 需要对方确认什么：
  - frontend 可按这组字段开始第一阶段联调
- 是否已解决：是

---

## 已确认

### B2F-024

- 时间：2026-04-03 20:10:25
- 谁提的：backend
- 当前事实：
  - backend 已确认 `evt_demo_variant_manual_001` 曾存在历史残留的 `launched` session，导致 `play.primaryAction=continue`
  - backend 已把清理逻辑并入 `POST /dev/bootstrap-demo`
  - 现在每次准备 demo 数据时，都会自动把 demo event 下残留的：
    - `launched`
    - `running`
    session 改成 `cancelled`
  - 这意味着前端后续再用标准测试链回归时，不需要手工清理旧 demo ongoing
- 需要对方确认什么：
  - frontend 遇到这类“明明本地没有恢复快照，但后端仍返回 continue”的情况，优先先重新执行一次 `Bootstrap Demo`
- 是否已解决：是

### B2F-023

- 时间：2026-04-03 13:24:38
- 谁提的：backend
- 当前事实：
  - backend 已把标准联调回归收成一键流
  - workbench 当前新增：
    - `一键标准回归`
    - `回归结果汇总`
  - 这条链会在标准发布链之后继续自动验证：
    - `GET /events/{eventPublicID}/play`
    - `POST /events/{eventPublicID}/launch`
    - `GET /sessions/{sessionPublicID}/result`
    - `GET /me/sessions`
    - `GET /me/results`
  - 回归结果会直接显示分项通过/未通过，不再要求 frontend 自己口头判断
- 需要对方确认什么：
  - frontend 当前回归优先使用这条一键标准回归链
- 是否已解决：是

### B2F-022

- 时间：2026-04-03 13:18:42
- 谁提的：backend
- 当前事实：
  - backend 当前已进入“联调标准化阶段”
  - 当前推荐 frontend 优先使用 workbench 的：
    - `Bootstrap Demo`
    - `一键补齐 Runtime 并发布`
    作为联调回归入口
  - backend 现在提供的不是零散 demo 文本，而是一套可重复创建的真实测试对象：
    - `place`
    - `map asset`
    - `tile release`
    - `course source`
    - `course set`
    - `course variant`
    - `runtime binding`
    - `presentation`
    - `content bundle`
    - `release`
  - 如果联调失败，workbench 当前会直接给出：
    - 分步日志
    - 真实错误消息
    - stack
    - 最后一次 curl
    - 预期判定
- 需要对方确认什么：
  - frontend 回归时优先基于这条一键测试链，不再先手工拼测试数据
- 是否已解决：是

### B2F-019

- 时间：2026-04-03 12:36:15
- 谁提的：backend
- 当前事实：
  - backend 已完成活动运营域第二阶段第四刀的后台最小实现：
    - `presentation import`
    - `event 默认 active 绑定`
    - `publish` 默认继承
  - 本刀没有改前端当前稳定消费字段语义：
    - `resolvedRelease`
    - `business`
    - `variant`
    - `runtime`
    - `presentation`
    - `contentBundle`
  - 这次新增能力主要影响后台运营链和发布默认行为，不要求 frontend 立即改接入
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-018

- 时间：2026-04-03 11:22:50
- 谁提的：backend
- 当前事实：
  - backend 已进入活动运营域第二阶段第二刀
  - 当前客户端可消费新增摘要：
    - `GET /events/{eventPublicID}` 返回：
      - `currentPresentation`
      - `currentContentBundle`
    - `GET /events/{eventPublicID}/play` 返回：
      - `currentPresentation`
      - `currentContentBundle`
    - `POST /events/{eventPublicID}/launch` 返回：
      - `launch.presentation`
      - `launch.contentBundle`
  - 当前字段只做摘要透出，不下发复杂 schema
  - 当前旧字段保持完全兼容：
    - `resolvedRelease`
    - `business`
    - `variant`
    - `runtime`
- 需要对方确认什么：
  - frontend 后续如要消费活动运营域摘要，先以这些新增摘要字段为准
- 是否已解决：是

### B2F-003

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已确认 session 三态正式语义：
    - 正常完成 -> `finished`
    - 超时或规则失败 -> `failed`
    - 主动退出 / 放弃恢复 -> `cancelled`
- 需要对方确认什么：
  - frontend 按这套语义继续联调
- 是否已解决：是

### B2F-004

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - 正式联调时不应回退到本地样例配置路径
  - 不应直接读取根目录 `event/*.json`
  - 应只认 launch 返回的 `manifestUrl`
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-005

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - 接口说明优先看 workbench 里的中文 API 列表
  - 深入字段说明再看 [接口清单](D:/dev/cmr-mini/backend/docs/接口清单.md)
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-006

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已确认“放弃恢复”官方语义为 `POST /sessions/{sessionPublicID}/finish` 且 `status=cancelled`
  - 同一局的旧 `sessionToken` 在该场景允许继续用于 `finish(cancelled)`
  - `cancelled` 和 `failed` 后都不会再作为 `ongoingSession` 返回
- 需要对方确认什么：
  - frontend 可正式把“放弃恢复”接到 `finish(cancelled)`
- 是否已解决：是

### B2F-007

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已把 `start / finish` 收口成幂等处理
  - 重复 `start`：
    - `launched` -> 推进到 `running`
    - `running` / 终态 -> 直接返回当前 session
  - 重复 `finish`：
    - 已终态 -> 直接返回当前 session / result
- 需要对方确认什么：
  - frontend 继续按当前补报 / 重试逻辑联调
- 是否已解决：是

### B2F-016

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已确认 `launch` 当前关键字段为前端正式联调契约：
    - `resolvedRelease.manifestUrl`
    - `resolvedRelease.releaseId`
    - `business.sessionId`
    - `business.sessionToken`
    - `business.sessionTokenExpiresAt`
  - 当前阶段 backend 不会单边调整这些字段名或层级
  - 如后续确需调整，backend 会先在 `b2f.md` 明确通知，再安排联调变更
- 需要对方确认什么：
  - frontend 继续按当前字段接入，不做额外推断
- 是否已解决：是

### B2F-017

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已完成对 ongoing 口径的代码回归确认
  - 当前实现中：
    - 只有 `launched` 和 `running` 会被识别为 ongoing
    - `cancelled`、`failed`、`finished` 都不会再进入 ongoing
  - `/me/entry-home` 与 `/events/{eventPublicID}/play` 当前都复用同一 ongoing 判定逻辑
  - `/me/results` 当前只返回终态 session：
    - `finished`
    - `failed`
    - `cancelled`
  - 当前首页摘要、play 摘要、result 详情都会复用同一组 session 基础摘要字段：
    - `id`
    - `status`
    - `eventId`
    - `eventName`
    - `releaseId`
    - `configLabel`
    - `routeCode`
- 需要对方确认什么：
  - frontend 可以按这套 ongoing / result 口径继续回归
- 是否已解决：是

---

## 阻塞

### B2F-008

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - 如果 frontend 再出现 manifest 加载失败，backend 仅靠一句“加载失败”无法定位
- 需要对方确认什么：
  - 如再出现此类问题，请一次性提供：
    - `eventPublicID`
    - `releaseId`
    - `manifestUrl`
    - 页面报错文案
    - 控制台日志
    - 网络请求日志
- 是否已解决：否

---

## 已完成

### B2F-009

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - backend 已修复 `publish build` 只写 DB、不上传 OSS 的问题
  - 新发布的 demo release manifest 已可正常访问
  - 当前可用 release：
    - `eventPublicID = evt_demo_001`
    - `releaseId = rel_e7dd953743c5c0d2`
    - `manifestUrl = https://oss-mbh5.colormaprun.com/gotomars/event/releases/evt_demo_001/rel_e7dd953743c5c0d2/manifest.json`
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-010

- 时间：2026-04-01
- 谁提的：backend
- 当前事实：
  - backend workbench 已支持中文 API 列表
  - 当前可用于日常联调：
    - `POST /dev/bootstrap-demo`
    - `GET /dev/workbench`
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-011

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已新增后台第一版资源对象接口：
    - `/admin/maps`
    - `/admin/playfields`
    - `/admin/resource-packs`
  - backend 已新增后台 `event` 组装接口：
    - `/admin/events`
    - `/admin/events/{eventPublicID}/source`
  - 这批接口主要服务后续后台配置运营，不影响当前小程序主链联调
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-012

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已补后台运营闭环接口：
    - `GET /admin/events/{eventPublicID}/pipeline`
    - `POST /admin/sources/{sourceID}/build`
    - `GET /admin/builds/{buildID}`
    - `POST /admin/builds/{buildID}/publish`
  - 当前后台侧已经可以完成：
    - 资源对象录入
    - event source 组装
    - preview build
    - publish release
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-013

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已补后台 `rollback` 接口：
    - `POST /admin/events/{eventPublicID}/rollback`
  - 当前后台侧已具备完整最小闭环：
    - 资源对象
    - event source 组装
    - build
    - publish
    - rollback
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-018

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已补一条可联调的 `manual` 多赛道 demo 活动：
    - `eventPublicID = evt_demo_variant_manual_001`
    - `releaseId = rel_demo_variant_manual_001`
    - `channelCode = mini-demo`
    - `channelType = wechat_mini`
  - 当前 demo 配置为：
    - `assignmentMode = manual`
    - `courseVariants = [variant_a, variant_b]`
  - 当前两条可选赛道：
    - `variant_a`
      - `name = A 线`
      - `routeCode = route-variant-a`
    - `variant_b`
      - `name = B 线`
      - `routeCode = route-variant-b`
  - 该活动已由 `POST /dev/bootstrap-demo` 自动准备
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-019

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - backend 已完成 `variant_b` 的 service 层回归验证
  - 已确认从 `launch` 选定的 `variantId` 会稳定回流到：
    - `GET /me/entry-home`
    - `GET /sessions/{sessionPublicID}/result`
    - `GET /me/results`
  - 实测链路为：
    - `play.assignmentMode=manual`
    - `play.courseVariants=2`
    - `launch.variant.id=variant_b`
    - `entry-home recent.variantId=variant_b`
    - `result.session.variantId=variant_b`
    - `results[0].session.variantId=variant_b`
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-020

- 时间：2026-04-03 09:43:20
- 谁提的：backend
- 当前事实：
  - backend 已在保持旧字段不变的前提下，为 `launch` 新增兼容字段：
    - `launch.runtime`
  - 当前最小字段包括：
    - `runtimeBindingId`
    - `placeId`
    - `mapId`
    - `tileReleaseId`
    - `courseSetId`
    - `courseVariantId`
  - 这是一组新增字段，不替代也不改变现有：
    - `resolvedRelease`
    - `business`
    - `variant`
  - frontend 当前可以忽略该字段，也可以开始做观测和日志透出
- 需要对方确认什么：
  - 无
- 是否已解决：是

### B2F-021

- 时间：2026-04-03 12:14:21
- 谁提的：backend
- 当前事实：
  - backend 已完成活动运营域第二阶段第三刀第一版
  - 当前活动运营摘要已统一补齐最小字段：
    - `currentPresentation.templateKey`
    - `currentPresentation.version`
    - `currentContentBundle.bundleType`
    - `currentContentBundle.version`
    - `launch.presentation.templateKey`
    - `launch.presentation.version`
    - `launch.contentBundle.bundleType`
    - `launch.contentBundle.version`
  - 上述字段当前已在以下接口可用：
    - `GET /events/{eventPublicID}`
    - `GET /events/{eventPublicID}/play`
    - `POST /events/{eventPublicID}/launch`
  - 旧字段继续完全兼容：
    - `resolvedRelease`
    - `business`
    - `variant`
    - `runtime`
- 需要对方确认什么：
  - frontend 如果开始消费活动运营摘要细项，请优先读取新增的 `templateKey / version / bundleType`
- 是否已解决：是

---

## 下一步

### B2F-014

- 时间：2026-04-02
- 谁提的：backend
- 当前事实：
  - session P0 已完成一轮收口
  - 当前最值得继续联调确认的是：
    - 放弃恢复 -> `finish(cancelled)`
    - `failed / cancelled` 后 ongoing 消失
    - 重复 `start / finish` 不再打断主链
- 需要对方确认什么：
  - frontend 当前优先配合：
    - 用当前 demo release 回归 `play -> launch -> map load`
    - 回归“继续恢复 / 放弃恢复”两条路径
    - 如确认进入多赛道第一阶段联调，请先回复 `B2F-015`
    - 如发现状态口径不一致，直接在 `f2b.md` 标具体接口和返回值
- 是否已解决：否


