docs: add bark battle backend BDD and TDD

This commit is contained in:
2026-05-11 16:17:22 +08:00
parent fa61eeb0b0
commit bf72c2e48d

View File

@@ -671,70 +671,326 @@ BarkBattleService
- `rate_limited`
- `impossible_bark_count`
## 9. TDD / 验收顺序与命令
## 9. BDD 行为场景、TDD 落地顺序与验收命令
本任务只写方案,不执行代码实现。后续落地建议按以下顺序:
本任务只写方案,不执行代码实现。后续落地必须先用 BDD 锁定可观察行为,再按 TDD 做 RED-GREEN-REFACTOR。没有先失败的测试不进入生产代码实现。
### 9.1 domain 纯函数测试
### 9.1 BDD 场景清单
先实现 `module-bark-battle`
以下场景用于约束后端行为,场景标题应映射到后续 Rust 测试名、API 测试名或 smoke 用例名。
#### 功能: bark-battle 发布态作品运行配置
```gherkin
功能: bark-battle 发布态作品运行配置
背景:
假如 playTypeId "bark-battle"
场景: 玩家请求已发布作品的 runtime config
假如 published
而且 configVersion
bark-battle runtime config
那么 BarkBattleRuntimeConfig
而且 workId ID
而且 playTypeId "bark-battle"
而且稿
场景: 玩家请求未发布作品的 runtime config
假如 draft
bark-battle runtime config
那么
而且 runtime run
场景: 玩家携带过期配置版本进入 runtime
假如 configVersion 3
使 configVersion 2 runtime
那么
而且
```
#### 功能: bark-battle runtime start 与统一游玩埋点
```gherkin
功能: bark-battle runtime start 与统一游玩埋点
bark-battle work_play_start
场景: 玩家成功开始已发布作品运行态
假如 bark-battle
而且
start runtime
那么 started run
而且 runId runToken runtimeConfig
而且 work_play_start
而且 scope_kind work
而且 scope_id ID
而且 metadata playTypeworkIdsourceRoute userId
场景: 无权限玩家尝试开始运行态
假如访
start runtime
那么
而且 run
而且 work_play_start
```
#### 功能: bark-battle runtime finish 派生成绩提交
```gherkin
功能: bark-battle runtime finish 派生成绩提交
场景: 玩家完成一局并提交合法派生指标
假如 start runtime
而且 run started
而且 runToken start
elapsedMsfinalEnergy BarkBattleDerivedMetrics
那么
而且 serverWinnerscore ScoreSummary
而且 run finished
而且 accepted true
而且
场景: 玩家重复提交同一个 run 的 finish
假如 run finished
finish
那么
而且
而且
场景: 玩家提交不合理的时长
假如 durationMs 30000
elapsedMs
那么 rejected accepted_with_flags
而且 antiCheatFlags elapsed_too_short
而且
场景: 玩家提交超出范围的声音指标
假如 start runtime
peakVolumeMax 1 validBarkCount
那么 flag
而且 antiCheatFlags metric_out_of_range impossible_bark_count
```
#### 功能: bark-battle 排行榜投影
```gherkin
功能: bark-battle 排行榜投影
场景: 作品开启排行榜且成绩被接受
假如 leaderboardEnabled true
而且 finish accepted true
那么
而且 score
场景: 作品关闭排行榜
假如 leaderboardEnabled false
那么 run score
而且 entry
场景: 带反作弊 flag 的成绩不进入默认榜单
假如 accepted_with_flags
那么
而且 run
```
#### 功能: bark-battle 隐私边界
```gherkin
功能: bark-battle 隐私边界
场景: finish 请求包含原始音频字段
假如 audioaudioBase64waveform pcmSamples
finish
那么
而且
场景: 正常 finish 只提交派生聚合指标
假如 bark-battle
finish
那么
而且
```
### 9.2 BDD 到测试映射
| BDD 场景 | 测试层级 | 建议目标文件 | RED 期望 |
| --- | --- | --- | --- |
| 玩家请求已发布作品的 runtime config | contract + API | `server-rs/crates/shared-contracts/src/bark_battle.rs``server-rs/crates/api-server/src/bark_battle.rs` | 新 DTO / route 不存在导致编译或断言失败 |
| 玩家请求未发布作品的 runtime config | domain + API | `server-rs/crates/module-bark-battle/src/domain.rs``server-rs/crates/api-server/src/bark_battle.rs` | 未发布状态未被拒绝 |
| 玩家携带过期配置版本进入 runtime | domain | `server-rs/crates/module-bark-battle/src/domain.rs` | configVersion mismatch 未返回错误 |
| 玩家成功开始已发布作品运行态 | API + integration | `server-rs/crates/api-server/src/bark_battle.rs` | start 未返回 runToken 或未写 tracking draft |
| 无权限玩家尝试开始运行态 | API | `server-rs/crates/api-server/src/bark_battle.rs` | 无权限仍创建 run 或写埋点 |
| 玩家完成一局并提交合法派生指标 | domain + facade | `server-rs/crates/module-bark-battle/src/domain.rs``server-rs/crates/spacetime-client/src/bark_battle.rs` | score / serverWinner 未由后端计算 |
| 玩家重复提交同一个 run 的 finish | SpacetimeDB reducer / facade | `server-rs/crates/spacetime-module/src/...``server-rs/crates/spacetime-client/src/bark_battle.rs` | duplicate finish 被接受 |
| 玩家提交不合理的时长 | domain | `server-rs/crates/module-bark-battle/src/domain.rs` | 未产生 elapsed_too_short flag |
| 玩家提交超出范围的声音指标 | domain | `server-rs/crates/module-bark-battle/src/domain.rs` | 未产生 metric_out_of_range / impossible_bark_count |
| 作品开启排行榜且成绩被接受 | domain + projection | `server-rs/crates/module-bark-battle/src/domain.rs`、SpacetimeDB reducer 测试 | accepted 成绩未生成 leaderboard projection |
| 作品关闭排行榜 | domain + projection | `server-rs/crates/module-bark-battle/src/domain.rs`、SpacetimeDB reducer 测试 | leaderboardEnabled=false 仍写榜 |
| 带反作弊 flag 的成绩不进入默认榜单 | domain | `server-rs/crates/module-bark-battle/src/domain.rs` | flagged 成绩仍进入默认榜 |
| finish 请求包含原始音频字段 | contract + API | `server-rs/crates/shared-contracts/src/bark_battle.rs`、API 反序列化测试 | DTO 接受或持久化原始音频字段 |
| 正常 finish 只提交派生聚合指标 | contract | `server-rs/crates/shared-contracts/src/bark_battle.rs` | DTO 缺字段或包含隐私风险字段 |
### 9.3 TDD RED-GREEN-REFACTOR 切片
每个切片必须先写失败测试并运行到预期失败,再写最小实现。
#### Slice 1: shared contracts 固定请求/响应形状
RED
```bash
cd server-rs
cargo test -p module-bark-battle
cargo test -p shared-contracts bark_battle_contract_uses_camel_case --no-default-features
```
测试覆盖
先新增测试,断言
- runtime config 校验
- finish metrics 范围校验
- 胜负判定
- score / grade / leaderboard score 计算。
- 反作弊 flags。
- `BarkBattleRunStartRequest` 序列化为 `workId``configVersion``sourceRoute`
- `BarkBattleRunFinishRequest` 只包含 `runId``runToken``workId``configVersion``elapsedMs``finalEnergy``clientWinner``metrics`
- `metrics` 只包含派生聚合字段,不包含 `audio``audioBase64``waveform``pcmSamples`
### 9.2 contracts 测试
GREEN新增 `shared-contracts/src/bark_battle.rs``lib.rs` 导出,让测试通过。
再实现 shared contracts
REFACTOR统一枚举命名、字段注释和默认值策略。
#### Slice 2: domain 校验 runtime config 与 finish metrics
RED
```bash
cd server-rs
cargo test -p shared-contracts bark_battle
cargo check -p shared-contracts
cargo test -p module-bark-battle validates_runtime_config_and_finish_metrics --no-default-features
```
验收
先新增测试,断言
- DTO 可序列化 / 反序列化
- 枚举值稳定
- 可选字段向后兼容
- TypeScript mirror 或契约生成产物与 Rust contract 对齐
- `playTypeId` 必须为 `bark-battle`
- `durationMs``energyMin``energyMax``barkThreshold` 必须在合法范围
- `peakVolumeMax``peakVolumeAvg` 必须在 `0..1`
- 过短时长产生 `elapsed_too_short`
- 不可能叫声次数产生 `impossible_bark_count`
### 9.3 SpacetimeDB / api-server check
GREEN新增 `module-bark-battle` 纯领域类型与校验函数。
实现表、reducer、migration 与 facade 后:
REFACTOR把常量收敛为领域常量避免 magic number 分散。
#### Slice 3: domain 重新裁决成绩与排行榜资格
RED
```bash
cd server-rs
cargo check -p spacetime-module
cargo check -p spacetime-client
cargo check -p api-server
cargo test -p api-server bark_battle
cargo test -p module-bark-battle scores_finish_result_and_filters_leaderboard --no-default-features
```
如仓库有统一命令,以统一命令为准,例如
先新增测试,断言
- 后端根据 `finalEnergy` 重算 `serverWinner`,不直接信任 `clientWinner`
- 合法胜利生成 `accepted=true` 与稳定 `ScoreSummary`
- 带 flag 的结果默认 `leaderboardEligible=false`
- `leaderboardEnabled=false` 时不生成榜单投影。
GREEN`score_finish_result(...)``is_leaderboard_eligible(...)` 等纯函数。
REFACTOR拆分 score、winner、anti-cheat、leaderboard 四组小函数。
#### Slice 4: SpacetimeDB 表、reducer 与 migration
RED
```bash
cd server-rs
cargo test --workspace
cargo check -p spacetime-module --no-default-features
cargo test -p spacetime-client bark_battle_facade_maps_run_records --no-default-features
```
验收:
先新增 facade / mapper 测试或编译断言,预期因绑定、表或 reducer 缺失失败。
- migration.rs 包含新增表与变更
- 绑定由生成命令产出,未手改生成物。
- api-server route handler 只做编排,不内嵌复杂计分规则。
GREEN新增表、reducer/procedure、`migration.rs`、生成绑定、`spacetime-client` facade
### 9.4 前端 contract 对齐
REFACTOR确保 api-server 不直接依赖 generated bindingsmapper 命名与现有玩法一致。
#### Slice 5: api-server start / finish BFF
RED
```bash
cd server-rs
cargo test -p api-server bark_battle_start_records_work_play_start --no-default-features
cargo test -p api-server bark_battle_finish_rejects_duplicate_or_invalid_metrics --no-default-features
```
先新增 API 测试,断言:
- start 成功返回 `runId``runToken``runtimeConfig`
- start 成功后主动补写 `work_play_start`,不只依赖 route-level 兜底。
- finish 重复提交被拒绝。
- finish 不接受非法 metrics。
GREEN新增 Axum route、handler、错误映射、tracking 调用。
REFACTORhandler 只做编排,把规则留在 domain把持久化留在 facade。
#### Slice 6: 前端 contract 对齐
RED
```bash
npm run test -- bark-battle
npm run typecheck
```
先新增前端 contract / client 测试,预期因 TS 类型或 client 缺失失败。
GREEN补前端共享 contract mirror、runtime client 调用 start / finish。
REFACTOR删除重复类型保持后端 DTO 为事实源。
### 9.4 后端验收命令
按切片逐步运行,不要等全部实现后一次性补测:
```bash
cd server-rs
cargo test -p shared-contracts bark_battle --no-default-features
cargo test -p module-bark-battle --no-default-features
cargo check -p spacetime-module --no-default-features
cargo check -p spacetime-client --no-default-features
cargo test -p api-server bark_battle --no-default-features
```
如涉及 API smoke
```bash
npm run api-server
# 另开终端执行对应 bark-battle start / finish smoke 或项目既有 API 测试脚本
```
每次表结构变更后必须同步:
1. 更新 `migration.rs`
2. 重新生成 SpacetimeDB bindings。
3. 检查 generated bindings 变更只来自生成命令。
4. 运行 `cargo check -p spacetime-module -p spacetime-client --no-default-features`
### 9.5 前端 contract 对齐验收
前端只在后端 contract 稳定后接入:
@@ -750,7 +1006,7 @@ npm run build
- 前端 result panel 展示后端 `RunResult`
- 前端本地结算只作为即时反馈,正式结果以后端返回为准。
### 9.5 手工验收清单
### 9.6 手工验收清单
- 可以创建并保存 bark-battle 草稿。
- 可以发布成稳定作品 ID`playTypeId = bark-battle`