领域层:新增会员自然月账期与并发上限纯函数

- membership_cycle.rs:北京时间锚点解析、自然月推进与月末夹取(1/31 → 2/28 → 3/31,从原始锚点重算)、期窗口、到期日、本期剩余微秒
- membership_limits.rs:并发上限哨兵 MEMBERSHIP_UNLIMITED_CONCURRENCY = 128 与 is_unlimited_concurrency
- lib.rs 注册并导出两个模块
- 单测覆盖闰年、跨年、窗口连续性、零索引归一、哨兵判定
- 设计文档同步:membership_cycle_window 去掉无用的 cycle_kind 形参并列出账期推进基元

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-10-02 14:09:04 +08:00
parent 741b179ca5
commit 969ee329d7
4 changed files with 227 additions and 2 deletions
@@ -252,8 +252,13 @@ pub struct RuntimeProfileMembershipUpgradeQuote {
纯函数(无 IO,可单测):
- `membership_cycle_window(anchor_micros, index, cycle_kind) -> (start, reset)`:
北京时间锚点 + 自然月推进 + 月末夹取,**从原始锚点重算**(1/31 → 2/28 → 3/31)。
- `membership_cycle_window(anchor_micros, index) -> (start, reset)`:
北京时间锚点 + 自然月推进 + 月末夹取,**从原始锚点重算**(1/31 → 2/28 → 3/31);
窗口本身与周期类型无关,总期数由 `cycle_kind.cycle_count()` 给出,`expires_at` 取第 `cycle_count` 期的边界。
- 账期推进基元(复用 `civil_calendar` 的公历换算,不读系统时区):
`advance_beijing_months_clamped(anchor, months)`、`beijing_local_date_parts(micros) -> (年月日, 当日微秒)`、
`beijing_local_micros(年月日, 当日微秒)`、`membership_expires_at(anchor, cycle_kind)`、
`membership_cycle_remaining_micros(resets_at, now)`。
- `quote_membership_upgrade(current, target, now) -> quote`:
金额向上取到分、补点向下取整;月付 / 年付分支见 §6;年价取目录 `year_price_cents`。
- `apply_membership_upgrade(row, quote) -> row'`:`cycle_remaining += 补点`、