test(游戏共创): 软删除×Fork 三条规则提取为纯函数并补单测
- domain.rs:新增三个不依赖 SpacetimeDB / ReducerContext 的纯函数
· `can_serve_as_fork_source(is_deleted, is_published)`:来源可用性 = 未软删除 且 已公开
· `counts_as_public_derivative(is_deleted, is_published)`:衍生计数纳入,同条件但动机不同(避免虚报热度、避免泄露「这里曾有个作品」),单独成函数以免两条规则将来互相牵连
· `fork_lineage_visible_identity(parent_available, parent_title, parent_author_name)`:父可用才透传;父不可用必须返回 (None, None),不做任何「拿不到标题就回退用行数据」的降级
- lib.rs:在既有 `pub use domain::{...}` 列表中导出上述三个函数(一行)
- spacetime-module:三处调用点改为调用纯函数,行为完全不变——来源守卫合并为一个 `if`(仍统一映射 FORK_SOURCE_NOT_AVAILABLE)、衍生计数 filter 传入两个布尔、血缘快照的父身份与根标题共用同一函数;`visibility` 判定仍由 module 侧折叠成布尔
- domain.rs 测试:新增 `fork_soft_delete_tests` 5 条——来源可用性四组合(含「已删但 visibility 仍是 published」必须 false)、计数纳入四组合、父可用透传、父不可用即使传入非空标题/作者名也必须 (None, None)、作者名三态(None→None / 空串→空串 / 只含空白原样透传)
- 技术方案 §5.1:把「权限与边界」行的说明改为已由纯函数单测覆盖的三条规则(真实栈用例仍标注待补);「软删除语义收敛 ③溯源摘要」行补上 `fork_lineage_visible_identity` 单测证据
This commit is contained in:
@@ -494,12 +494,12 @@ A 路线里有一个必须提前知道的互斥点:`create_npm_scaffold` 的
|
||||
| HTTP 端到端(BFF 路由与真实数据库连接) | `npm run dev` 整套拉起后:`/healthz` 200;`GET /api/game-distribution/games` 200(空列表,走通真实数据库查询与 envelope);`PUT …/fork-authorization` 未带 Bearer 返回 401 `UNAUTHORIZED` | ✅ 已验证 |
|
||||
| HTTP 端到端(真实登录态下的提升 / 声明血缘 / 详情页字段) | 未跑:需要真实登录态与一个已发布作品;本地开发库当前为空 | ⏳ 待补 |
|
||||
| 浏览器视觉与交互验证(详情页共创卡、我的作品授权入口、移动端布局) | 未跑:本地库无作品数据,登录态不可用,页面无法进入有效状态 | ⏳ 待补 |
|
||||
| 权限与边界(非作者 403、降级 409、父作品下架后新声明被拒) | 领域层与 procedure 校验已实现并覆盖单测;真实栈边界用例待补 | ⏳ 待补 |
|
||||
| 权限与边界(非作者 403、降级 409、父作品下架后新声明被拒、软删除边界) | 领域层与 procedure 校验已实现;**软删除×Fork 三条规则已提取为纯函数并补单测**——`can_serve_as_fork_source`(未删+已公开,四组合,含「已删但 visibility 仍 published」必须 false)、`counts_as_public_derivative`(同四组合)、`fork_lineage_visible_identity`(父可用透传;父不可用即使传入非空标题/作者名也必须返回 `(None, None)`;作者名三态)由 `cargo test -p module-game-distribution`(36 passed)覆盖。真实栈边界用例仍待补 | ⏳ 部分(单测已补,真实栈待补) |
|
||||
| **rebase 到含 #565 的新 master** | `git rebase origin/master`(新 master `6c9566058`)重放两个提交,9 个冲突文件按 §3.9.1 全部解决(两侧业务逻辑都保留),无 merge commit,未改动 master;提交信息沿用原中文提交 | ✅ 已验证 |
|
||||
| **生成物重生成** | `npm run spacetime:generate -- --rust-only` 后保留 `module_bindings/game_distribution*` 与 `module_bindings/module_bindings.rs`,rustfmt 版本差异带来的其它文件格式漂移已 `git checkout --` 还原 | ✅ 已验证 |
|
||||
| **软删除语义收敛 ①来源校验** | `resolve_game_distribution_fork_declaration_tx` 增加「来源 `deleted_at` 非空 → `FORK_SOURCE_NOT_AVAILABLE`(409)」,显式判定而不是只靠 `visibility` 复位 | ✅ 已验证(`cargo test -p api-server game_distribution`;领域错误码沿用 `FORK_*` 前缀) |
|
||||
| **软删除语义收敛 ②衍生作品数** | `game_distribution_public_fork_count` 只统计 `deleted_at.is_none() && visibility == published` 的子作品;作者删除子作品后父作品计数随之下降 | ✅ 已验证(同上) |
|
||||
| **软删除语义收敛 ③溯源摘要** | `game_distribution_lineage_snapshot` 在父(或根)作品被软删除时把 `parent_title` / `root_title` 置空、父作者名置空,api-server 原样发 `null`,TS 契约改为 `string \| null`,详情页降级为「原作品已不可用」 | ✅ 已验证(DTO parity + 前端用例;单测待补) |
|
||||
| **软删除语义收敛 ③溯源摘要** | `game_distribution_lineage_snapshot` 在父(或根)作品被软删除时把 `parent_title` / `root_title` 置空、父作者名置空,api-server 原样发 `null`,TS 契约改为 `string \| null`,详情页降级为「原作品已不可用」 | ✅ 已验证(DTO parity + 前端用例 + `fork_lineage_visible_identity` 单测,「父不可用即使传入标题也必须 `(None, None)`」已由 `cargo test -p module-game-distribution` 断言) |
|
||||
| **详情页结构对齐 #565** | 详情页改用共享 `GameDetailDisplay`,共创卡通过 `infoCards` 渲染;vitest 用例「展示共创授权、代际与溯源信息,且不提供改造入口」与「旧数据缺少授权与血缘字段时只按禁止共创渲染」通过 | ✅ 已验证 |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user