# b2f
> 文档版本：v1.26
> 最后更新：2026-04-03 19:18:34


说明：

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

---

## 待确认

### B2F-038

- 时间：2026-04-03 19:13:57
- 谁提的：backend
- 当前事实：
  - backend 已按“活动卡片列表最小产品化第一刀”补齐以下返回中的活动卡片最小摘要字段：
    - `GET /cards`
    - `GET /home`
    - `GET /me/entry-home`
  - 当前最小摘要字段为：
    - `summary`
    - `status`
    - `statusCode`
    - `timeWindow`
    - `ctaText`
    - `isDefaultExperience`
    - `eventType`
    - `currentPresentation`
    - `currentContentBundle`
  - backend 当前希望 frontend 这轮优先做的是：
    - 活动列表页按这组字段完成最小接线
    - 详情页继续沿用：
      - `play.canLaunch`
      - `currentPresentation`
      - `currentContentBundle`
      这组已发布 release 语义
    - 联调时继续通过 frontend 调试日志回传以下事实：
      - 列表页实际拿到的 `cardEventIds`
      - 点击卡片后的 `eventId`
      - 详情页实际显示的 `status / canLaunch / currentPresentation / currentContentBundle`
- 需要对方确认什么：
  - frontend 请按这组字段完成活动卡片列表最小实现，并回写：
    - 当前字段是否足够
    - 列表页是否还缺必需字段
    - 最新日志里是否已能稳定看到：
      - `cardEventIds`
      - `clickedEventId`
      - `detail.status`
      - `detail.canLaunch`
- 是否已解决：否

### B2F-037

- 时间：2026-04-03 22:52:10
- 谁提的：backend
- 当前事实：
  - backend 已根据 frontend 在 `F2B-013` 的结构化日志，确认 manual 多赛道当前不显示赛道选择区的根因不在 frontend 展示层
  - 当前 frontend 日志事实为：
    - `event-play.pageEventId = evt_demo_variant_manual_001`
    - `event-play.variantCount = 0`
    - `event-prepare.variantCount = 0`
    - `event-prepare.selectableVariantCount = 0`
    - `event-prepare.showVariantSelector = false`
  - backend 进一步核对当前数据库里的该活动当前发布 release：
    - `eventPublicID = evt_demo_variant_manual_001`
    - `releaseId = rel_69d4778bdbb398b4`
    - 该 release 的 `payload_jsonb` 当前缺少：
      - `play.assignmentMode`
      - `play.courseVariants`
  - 根因是：
    - manual demo 的 source/build 数据此前仍按单赛道顺序赛模板生成
    - 导致后续 publish 出来的新 release 没把多赛道配置带进去
  - backend 已修复：
    - `Bootstrap Demo` 准备 manual demo source/build 时，会显式写入：
      - `play.assignmentMode = manual`
      - `play.courseVariants = [variant_a, variant_b]`
- 需要对方确认什么：
  - 无，当前这条已通过本轮联调日志确认
- 是否已解决：是

### B2F-036

- 时间：2026-04-03 22:34:08
- 谁提的：backend
- 当前事实：
  - backend 已按活动卡片列表最小产品化第一刀，统一补齐以下返回里的卡片摘要字段：
    - `GET /cards`
    - `GET /home`
    - `GET /me/entry-home`
  - 当前新增/补齐字段为：
    - `summary`
    - `status`
    - `statusCode`
    - `timeWindow`
    - `ctaText`
    - `isDefaultExperience`
    - `eventType`
    - `currentPresentation`
    - `currentContentBundle`
  - 当前口径固定如下：
    - `summary` 缺失时回退：`当前暂无活动摘要`
    - `timeWindow` 缺失时回退：`时间待公布`
    - `ctaText` 当前由 backend 派生：
      - 默认体验活动：`进入体验`
      - 进行中：`进入活动`
      - 已结束：`查看回顾`
      - 其余：`查看详情`
    - `currentPresentation / currentContentBundle` 继续表示当前已发布 release 摘要，不是 event 草稿默认值
  - backend 已给 `cards` 落显式字段：
    - `is_default_experience`
  - 当前 demo 数据已标记：
    - 顺序赛为默认体验活动
    - 积分赛、多赛道为普通活动
- 需要对方确认什么：
  - frontend 可按以上字段和降级规则开始活动卡片列表最小产品化第一刀
  - frontend 请回写：
    - 当前字段是否足够启动列表页最小实现
    - 是否还缺列表页必需名称摘要
- 是否已解决：否

### B2F-035

- 时间：2026-04-03 18:16:19
- 谁提的：backend
- 当前事实：
  - backend 已根据 frontend 在 `F2B-012` 的反馈，正式收紧 `play.canLaunch` 和 `POST /events/{eventPublicID}/launch` 的前置条件
  - 当前规则已改为：
    - 仅当当前 event 满足以下条件时，`play.canLaunch = true`
      - event `status = active`
      - 已存在当前发布 release
      - 当前发布 release 有 `manifest`
      - 当前发布 release 已绑定 `runtime`
      - 当前发布 release 已绑定 `presentation`
      - 当前发布 release 已绑定 `content bundle`
  - 当前若缺任一项，backend 会返回更明确原因，例如：
    - `current published release is missing runtime binding`
    - `current published release is missing presentation binding`
    - `current published release is missing content bundle binding`
  - `launch` 当前也已按同一套规则阻断，避免出现：
    - `play.canLaunch = false`
    - 但直接调用 `launch` 仍能进局
- 需要对方确认什么：
  - frontend 请在 backend 重启后复验：
    - 当 `currentPresentation / currentContentBundle / runtime` 任意缺失时，`play.canLaunch` 是否已变为 `false`
    - `play.reason` 是否已返回更具体缺失原因
  - frontend 页面当前可继续沿用：
    - `canLaunch=false` 时禁用进入动作
    - 同时展示 backend 返回的 `reason`
- 是否已解决：否

### B2F-034

- 时间：2026-04-03 18:05:19
- 谁提的：backend
- 当前事实：
  - backend 当前已确认一个需要 frontend 明确区分的语义：
    - `currentPresentation`
    - `currentContentBundle`
    当前表示的是“当前已发布 release 上实际绑定的展示版本 / 内容包版本摘要”
  - 它们当前不是：
    - 活动草稿默认值
    - event 默认绑定草稿态
  - 这也解释了为什么：
    - 后台未完成导入 + 默认绑定 + publish 之前，这两项可能为空
    - 一旦跑过后台发布链，它们就会开始显示
  - backend 当前正式规则也已明确：
    - 玩家进入游戏必须基于“已发布 release”
    - 不能基于未发布默认配置直接放行
- 需要对方确认什么：
  - frontend 请按以下口径调整页面语义：
    - 文案优先改成：
      - `当前发布展示版本`
      - `当前发布内容包版本`
    - 玩家能否继续进入，优先只看：
      - `play.canLaunch`
    - 当这两项为空时，优先解释为：
      - 当前发布 release 未绑定
      - 或当前尚未发布
    - 不要把它们展示成“活动默认配置已存在，只是未显示”
- 是否已解决：否

### B2F-032

- 时间：2026-04-03 16:43:25
- 谁提的：backend
- 当前事实：
  - backend 已收到 frontend 最新一轮结构化调试日志，并确认积分赛主链已打通
  - 当前日志事实一致指向：
    - `entry-home.cardEventIds` 已包含 `evt_demo_score_o_001`
    - `event-play.pageEventId = evt_demo_score_o_001`
    - `event-prepare.pageEventId = evt_demo_score_o_001`
    - `launch.response.releaseId = rel_74bb47a0d0d3d252`
    - `runtime-compiler.details.game.mode = score-o`
    - `runtime-compiler.details.playfield.kind = control-set`
  - 当前 backend 没再看到“明明选积分赛却实际跑成顺序赛”的问题
  - 当前日志链还有 3 个口径优化项：
    - 非多赛道玩法时，`assignmentMode` 现在是空字符串 `\"\"`
    - `variantId` 为空时，`runtimeCourseVariantId` 仍可能有值，前端展示层不要把两者混为“用户选了赛道”
    - `occurredAt` 和 `receivedAt` 会有轻微时钟漂移，排查顺序时建议增加前端本地递增序号
- 需要对方确认什么：
  - frontend 后续日志上报请优化为：
    - 非多赛道玩法时：
      - `assignmentMode = null` 或不传
      - `variantId = null` 或不传
    - 新增：
      - `details.seq`
    - 如需展示赛道来源，请区分：
      - `launchVariantId`
      - `runtimeCourseVariantId`
- 是否已解决：否

### B2F-031

- 时间：2026-04-03 16:37:41
- 谁提的：backend
- 当前事实：
  - backend 已收到 frontend 新增的结构化调试日志
  - 这批日志已经明确说明：本轮前端实际进入的是经典顺序赛，不是积分赛
  - 关键事实如下：
    - `entry-home.cardEventIds = [evt_demo_001, evt_demo_variant_manual_001]`
    - `event-play.pageEventId = evt_demo_001`
    - `event-prepare.pageEventId = evt_demo_001`
    - `launch.response.releaseId = rel_demo_001`
    - `runtime-compiler.details.game.mode = classic-sequential`
  - backend 已确认根因不是积分赛 release 缺失，而是 demo 首页卡片入口配置错误：
    - 当前首页卡片查询只取 `home_primary`
    - score-o demo 卡此前被种到了 `home_secondary`
    - 所以前端首页根本拿不到积分赛入口
  - backend 已修复：
    - `card_demo_score_o_001` 改为 `home_primary`
    - 同时把优先级调高到 `98`
- 需要对方确认什么：
  - frontend 请在 backend 重启后重新执行：
    - `Bootstrap Demo`
    - 进入首页再看 `cardEventIds`
  - 并确认首页卡片中是否已经出现：
    - `evt_demo_score_o_001`
- 是否已解决：否

### B2F-030

- 时间：2026-04-03 16:16:38
- 谁提的：backend
- 当前事实：
  - backend 已新增 dev 调试接口：
    - `POST /dev/client-logs`
    - `GET /dev/client-logs`
    - `DELETE /dev/client-logs`
  - workbench 已新增：
    - `前端调试日志`
    - `拉取前端日志`
    - `清空前端日志`
  - 这套能力只用于联调，不参与正式生产日志链路
  - backend 当前建议 frontend 在关键阶段主动上报日志，至少覆盖：
    - launch 返回后
    - 地图页拿到最终 manifest 后
    - 运行时编译完成后
    - 发现缓存命中 / 恢复 session / 模式不符时
- 需要对方确认什么：
  - frontend 请按最小字段约定接入并回传一轮：
    - `source`
    - `level`
    - `category`
    - `message`
    - `eventId`
    - `releaseId`
    - `sessionId`
    - `manifestUrl`
    - `route`
    - `details.schemaVersion`
    - `details.playfield.kind`
    - `details.game.mode`
    - `details.phase`
- 是否已解决：否

### B2F-029

- 时间：2026-04-03 15:44:32
- 谁提的：backend
- 当前事实：
  - backend 已确认一个具体问题：
    - 所有“带 `Bootstrap Demo` 的一键按钮”，此前都会先把默认 demo 数据重新写回表单
    - 这会把前面已经选好的积分赛入口再次冲回顺序赛默认链
  - 受影响的不只是：
    - `整条链一键验收`
  - 还包括：
    - `看首页是否正常`
    - `快速进一局`
    - `发布活动配置（自动补 Runtime）`
  - backend 已修复为：
    - 这些一键流在调用 `Bootstrap Demo` 后，会按当前已选中的 `event` 回填对应的 `source / build / release / runtime`
    - 不再无条件回退到 `evt_demo_001`
- 需要对方确认什么：
  - frontend 请重启 backend 后复验：
    - `Use Score-O Demo`
    - `整条链一键验收`
  - 并确认地图信息面板里是否已切到：
    - `eventPublicID = evt_demo_score_o_001`
    - `game.mode = score-o`
    - `playfield.kind = control-set`
- 是否已解决：否

### B2F-028

- 时间：2026-04-03 15:29:07
- 谁提的：backend
- 当前事实：
  - backend 已核对积分赛 demo 当前发布链，以下 3 层结果一致：
    - 本地源配置 [score-o.json](D:/dev/cmr-mini/event/score-o.json)
    - OSS 配置 [score-o.json](https://oss-mbh5.colormaprun.com/gotomars/event/score-o.json)
    - 当前 event `evt_demo_score_o_001` 的正式 release manifest
  - 当前后端确认值为：
    - `schemaVersion = 1`
    - `playfield.kind = control-set`
    - `game.mode = score-o`
  - 当前积分赛正式 release 为：
    - `eventPublicID = evt_demo_score_o_001`
    - `releaseId = rel_1c7601964d7f3d00`
    - `manifestUrl = https://oss-mbh5.colormaprun.com/gotomars/event/releases/evt_demo_score_o_001/rel_1c7601964d7f3d00/manifest.json`
  - 如果 frontend 当前跑出来仍是顺序赛，优先怀疑“实际消费的不是当前 launch 返回的 manifest”，或“运行时仍走旧缓存/旧默认逻辑”
  - backend 已在 workbench 新增：
    - `当前 Launch 实际配置摘要`
  - 该摘要会由 backend 代读当前 launch 对应 manifest，并直接显示：
    - `configUrl`
    - `releaseId`
    - `manifestUrl`
    - `schemaVersion`
    - `playfield.kind`
    - `game.mode`
  - 这块摘要只用于联调排查，不参与正式客户端运行链路
- 需要对方确认什么：
  - frontend 请先排查并回传这 4 项事实：
    - `POST /events/{eventPublicID}/launch` 响应里的：
      - `launch.config.configUrl`
      - `launch.resolvedRelease.manifestUrl`
      - `launch.config.releaseId`
    - 地图页/运行时真正读取的最终 manifest URL
    - 最终加载后的 manifest 摘要：
      - `schemaVersion`
      - `playfield.kind`
      - `game.mode`
    - 如仍表现为顺序赛，请同时给出：
      - 控制台日志
      - 网络请求日志
      - 是否存在本地缓存/上次 session 恢复痕迹
- 是否已解决：否

### 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-033

- 时间：2026-04-03 17:25:35
- 谁提的：backend
- 当前事实：
  - backend 已把玩法切换对应的联调资源补齐到 workbench：
    - `presentation schema`
    - `content manifest`
    - `asset manifest`
  - 玩法切换现在会自动填真实 dev 资源地址，不再继续保留 `example.com` 占位：
    - `GET /dev/demo-assets/presentations/{demoKey}`
    - `GET /dev/demo-assets/content-manifests/{demoKey}`
  - 当前联调样例文案也已统一成中文活动样例，便于 frontend 直接核对页面显示与日志事实
- 需要对方确认什么：
  - frontend 如需核对当前玩法对应的展示/内容输入，可直接对照 workbench 当前表单值与上述两条 dev 资源地址
- 是否已解决：是

### B2F-027

- 时间：2026-04-03 14:37:00
- 谁提的：backend
- 当前事实：
  - workbench 已提供 3 个显式玩法测试入口：
    - `Use Classic Demo`
    - `Use Score-O Demo`
    - `Use Manual Variant Demo`
  - 对应联调 event 为：
    - `evt_demo_001`
    - `evt_demo_score_o_001`
    - `evt_demo_variant_manual_001`
  - 积分赛入口已固定到：
    - `rel_demo_score_o_001`
    - `score-o.json`
- 需要对方确认什么：
  - frontend 后续若要测顺序赛或积分赛，优先使用上述显式入口，而不是自行猜 event/release
- 是否已解决：是

### B2F-026

- 时间：2026-04-03 14:29:42
- 谁提的：backend
- 当前事实：
  - backend 已把 manual 多赛道 demo 的赛道输入切到真实 KML
  - 当前 `Bootstrap Demo` 会准备两条真实赛道输入：
    - `variant_a -> c01.kml`
    - `variant_b -> c02.kml`
  - 当前地图仍继续共用同一组真实 tiles / mapmeta，这符合当前多赛道联调阶段的实际需要
- 需要对方确认什么：
  - frontend 如需回归 manual 多赛道，请先重新执行一次 `Bootstrap Demo`
- 是否已解决：是

### B2F-025

- 时间：2026-04-03 14:21:24
- 谁提的：backend
- 当前事实：
  - backend 已开始“真实输入替换第一刀”
  - 当前 `Bootstrap Demo` 不再给生产骨架使用 `example.com` 占位赛道/地图地址
  - 当前已改成真实可访问输入：
    - `CourseSource.fileUrl = https://oss-mbh5.colormaprun.com/gotomars/kml/lxcb-001/10/c01.kml`
    - `TileRelease.tileBaseUrl = https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/`
    - `TileRelease.metaUrl = https://oss-mbh5.colormaprun.com/gotomars/map/lxcb-001/tiles/meta.json`
  - 这批真实输入仍走同一条一键回归链，不要求 frontend 改联调方式
- 需要对方确认什么：
  - frontend 如需复验真实输入，请重新执行一次 `Bootstrap Demo`
- 是否已解决：是

### 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` 标具体接口和返回值
- 是否已解决：否


