diff --git a/server-rs/crates/spacetime-module/src/runtime/active/profile.rs b/server-rs/crates/spacetime-module/src/runtime/active/profile.rs index 6c0850b16..b41d69eb8 100644 --- a/server-rs/crates/spacetime-module/src/runtime/active/profile.rs +++ b/server-rs/crates/spacetime-module/src/runtime/active/profile.rs @@ -4578,6 +4578,16 @@ mod tests { &settlement(None, None), &row )); + // 中文注释:存量的 `cycle_index == 0` 迁移行与投影的 `max(1)` 归一值等价, + // 不能因为「原始行还是 0」把建单快照 `Some(1)` 判成账期已变化。 + let legacy_row = ProfileMembership { + cycle_index: 0, + ..row + }; + assert!(frozen_membership_cycle_matches( + &settlement(Some(1), Some(anchor + 28 * day)), + &legacy_row + )); } #[test] @@ -9553,7 +9563,9 @@ fn frozen_membership_cycle_matches( row: &ProfileMembership, ) -> bool { if let Some(cycle_index_before) = settlement.cycle_index_before { - if cycle_index_before != row.cycle_index { + // `cycle_index == 0` 是存量「水位未初始化」哨兵;只读投影统一 `max(1)` 归一到第 1 期。 + // 结算侧同样归一,否则迁移行会被永久判成「会员状态已变化」而无法结算(评审第 20 条)。 + if cycle_index_before.max(1) != row.cycle_index.max(1) { return false; } }