refactor(error): profile 错误分类全面转 typed error,删除文案匹配
- module-runtime 新增 RuntimeProfileRewardCodeRedeemErrorCode(NotFound/Disabled/NotStarted/Expired/UsesExhausted/NotAllowedForUser/InvalidReward)与 RuntimeProfileProcedureRejectionCode(聚合会员 / 兑换码两类码) - RuntimeProfileRewardCodeRedeemProcedureResult 末尾追加 error_code,spacetime-module 用 ProfileRewardCodeRedeemProcedureError 在拒绝点显式赋码,入参与钱包错误保持无码 - SpacetimeClientError::ProcedureRejected.code 改为 RuntimeProfileProcedureRejectionCode,Display 输出 [code] message,不再吞掉机器可读原因(评审第 12 条) - api-server 的 map_runtime_profile_client_error 只读变体字段,AppError.code 取 code.as_str(),删除 is_runtime_profile_domain_error / is_runtime_profile_redeem_code_domain_error 两个中文文案匹配函数 - 重新生成 Rust bindings;同步技术设计 §5.8 与 decision-log
This commit is contained in:
@@ -9674,3 +9674,12 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 决策:选 ①。`init_profile_membership_plan_catalog` 只在数据库首次创建时执行,增量发布不重跑;「表已存在但为空」的存量库必须靠读取 helper 懒播种兜底,否则目录为空会让下单 / 报价失败。保留懒播种,并把「只读入口在目录为空的首次调用会写库、表非空后幂等只读」明确写进代码注释与设计文档 §7,消除注释与实现的矛盾。
|
||||
- 未选 ②/③ 的原因:②依赖发布流程保证存量库被种上,当前没有这条保证;③改动读路径回退逻辑,风险与收益不匹配。将来若做发布期 migration,再删除懒播种。
|
||||
- 影响范围:`server-rs/crates/spacetime-module/src/runtime/active/profile.rs`(`ensure_default_profile_membership_plan` / `init_profile_membership_plan_catalog` / `membership_plan_row` / `membership_plan_records` / 报价与建单函数注释)、`docs/technical/【技术设计】泥点三池与会员计费后端设计-2026-10-02.md` §7/§10.2、本文件。
|
||||
|
||||
## 2026-10-03 兑换码链路补机器可读错误码(typed error 收口)
|
||||
|
||||
- 背景:评审第 12 项指出 `SpacetimeClientError::ProcedureRejected` 的 `Display` 丢掉 `code`,而 `api-server/src/runtime_profile.rs` 的 `is_runtime_profile_redeem_code_domain_error` 仍在精确匹配 7 条中文 `error_message` 来判断兑换码拒绝该返回 400 还是 502,文案一改就静默退化,与会员链路已落地的 typed error 不一致。
|
||||
- 决策(module 侧赋码):`module-runtime` 新增 `RuntimeProfileRewardCodeRedeemErrorCode`(`NotFound` / `Disabled` / `NotStarted` / `Expired` / `UsesExhausted` / `NotAllowedForUser` / `InvalidReward`);`RuntimeProfileRewardCodeRedeemProcedureResult` 末尾追加 `error_code: Option<...>`;`spacetime-module` 用 `ProfileRewardCodeRedeemProcedureError::{Classified, Plain}` 在拒绝点显式赋码,入参与钱包类错误保持 `error_code = null`。
|
||||
- 决策(客户端 / BFF):`SpacetimeClientError::ProcedureRejected` 的 `code` 改为 `RuntimeProfileProcedureRejectionCode`(聚合 `Membership` 与 `RewardCodeRedeem` 两类),`Display` 输出 `[code] message` 保留机器原因;`api-server` 的 `map_runtime_profile_client_error` 只读变体的 `code` / `message`,`AppError.code` 取 `code.as_str()`,删除 `is_runtime_profile_domain_error` 与 `is_runtime_profile_redeem_code_domain_error` 两个文案匹配函数。
|
||||
- 决策(行为变化):兑换码的 `兑换码不存在` / `已停用` / `未生效` / `已过期` / `次数已用完` / `不适用于当前账号` / `奖励无效` 由原来的 502 变为 400 且带机器码;procedure result 新增字段属 wire 契约变更,要求 module 与 api-server 同版本部署。
|
||||
- 影响范围:`server-rs/crates/module-runtime/src/domain.rs`、`server-rs/crates/spacetime-module/src/runtime/active/profile.rs`、`server-rs/crates/spacetime-client/src/{active.rs,active/mapper/runtime_profile.rs}`、生成绑定、`server-rs/crates/api-server/src/runtime_profile.rs`、`docs/technical/【技术设计】泥点三池与会员计费后端设计-2026-10-02.md` §5.8、本文件。
|
||||
- 验证:`npm run spacetime:generate`;`cargo check -p api-server`;`cargo test -p api-server runtime_profile::tests` 41 passed;`cargo test -p module-runtime`、`cargo test -p spacetime-client`、`cargo test -p spacetime-module` 全通过;`npm run check:spacetime-schema`、`npm run check:encoding`、`git diff --check` 通过。
|
||||
|
||||
@@ -433,23 +433,31 @@ flowchart TD
|
||||
- `npm run check:generated-bindings` 以「重新生成并与工作区逐字节比较」做门禁,防止 Rust 改了而生成文件没重跑。
|
||||
- 需要展示用派生字段(如 `totalPoints` 合计)时,在前端 `utils/mudPoints.ts` 里派生,不改 DTO。
|
||||
|
||||
### 5.8 会员错误码契约(typed error,已落地)
|
||||
### 5.8 Profile 错误码契约(typed error,已全面落地)
|
||||
|
||||
- 会员链路的业务拒绝不再靠中文 `error_message` 前缀分类。`module-runtime` 新增
|
||||
`RuntimeProfileMembershipErrorCode`(`UpgradeRejected` / `NotMember` / `AlreadyActive` /
|
||||
`CycleKindLocked` / `MembershipExpired` / `StateChanged` / `PlanNotPurchasable` /
|
||||
`PlanCatalogMissing` / `ProductIdUnparsable` / `MembershipProductRetired` / `InvalidPlanConfig`),
|
||||
在拒绝点显式产出,`RuntimeProfileMembershipUpgradeQuoteProcedureResult` /
|
||||
- Profile 链路的业务拒绝不再靠中文 `error_message` 分类,全部由 procedure 结果里的机器可读
|
||||
`error_code` 透传。
|
||||
- 会员链路:`module-runtime` 的 `RuntimeProfileMembershipErrorCode`(`UpgradeRejected` /
|
||||
`NotMember` / `AlreadyActive` / `CycleKindLocked` / `MembershipExpired` / `StateChanged` /
|
||||
`PlanNotPurchasable` / `PlanCatalogMissing` / `ProductIdUnparsable` /
|
||||
`MembershipProductRetired` / `InvalidPlanConfig`)在拒绝点显式产出,
|
||||
`RuntimeProfileMembershipUpgradeQuoteProcedureResult` /
|
||||
`RuntimeProfileRechargeCenterProcedureResult` / `RuntimeProfileMembershipPlanAdminProcedureResult`
|
||||
末尾追加 `error_code: Option<RuntimeProfileMembershipErrorCode>`(`error_message` 保留人读文案)。
|
||||
- `spacetime-client` 的 `SpacetimeClientError` 新增
|
||||
`ProcedureRejected { code, message }`;`api-server` 的 `runtime_profile` 映射据此返回 400
|
||||
(`provider = runtime-profile`),基础设施错误保持 502。字段校验类错误(如 user_id 缺失)
|
||||
不产出 `error_code`,仍按字符串错误落到 502。
|
||||
- 行为变化:`会员目录缺少档位 ...` 与「已迁移的会员商品」原先落到 502,现在有明确错误码,统一 400。
|
||||
- 兑换码链路:`module-runtime` 的 `RuntimeProfileRewardCodeRedeemErrorCode`(`NotFound` /
|
||||
`Disabled` / `NotStarted` / `Expired` / `UsesExhausted` / `NotAllowedForUser` /
|
||||
`InvalidReward`)在拒绝点显式产出,`RuntimeProfileRewardCodeRedeemProcedureResult` 末尾同样追加
|
||||
`error_code`。
|
||||
- `spacetime-client` 的 `SpacetimeClientError::ProcedureRejected { code, message }` 用
|
||||
`RuntimeProfileProcedureRejectionCode` 聚合两条链路的 typed code;`api-server` 的 `runtime_profile`
|
||||
映射直接读变体字段返回 400(`provider = runtime-profile`),`AppError.code` 取
|
||||
`code.as_str()`,基础设施错误保持 502。字段校验类错误(如 user_id 缺失)不产出 `error_code`,
|
||||
仍按字符串错误落到 502。
|
||||
- 行为变化:`会员目录缺少档位 ...`、「已迁移的会员商品」以及兑换码的 `兑换码不存在` / `已停用` /
|
||||
`未生效` / `已过期` / `次数已用完` / `不适用于当前账号` / `奖励无效` 原先落到 502,现在有明确
|
||||
错误码,统一 400。`api-server` 已删除 `is_runtime_profile_redeem_code_domain_error` 文案匹配函数。
|
||||
- 兼容边界:procedure result 是 wire 结构,新增字段要求 module 与 api-server 同版本部署;
|
||||
旧 module 不返回 `error_code` 时,新 client 绑定反序列化会失败。兑换码链路本轮未改造,
|
||||
`api-server` 仍保留一个兑换码文案匹配函数。
|
||||
旧 module 不返回 `error_code` 时,新 client 绑定反序列化会失败。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user