ratelimit-hit
靶子 容器=wt_h8_tp8(端口 20098)
=== R1 · 全部通过 → 返 NULL,且【每一档】都 +1 ===
PASS 首次调用返回 NULL(放行)
PASS 两档都记了 1
PASS 第二次仍放行
PASS 两档都记到 2
=== R2 · 🔴 一档不过 → 整组不记数(顺序不偏移) ===
PASS 返回的是第一个命中上限的【code】rtpsw_daily
PASS 🔴 前一档没有被 +1(仍是 "")
=== R3 · TTL 逐档取自 RateLimitDef(不是调用点自己写的数) ===
PASS 冷却档 TTL == 60
PASS 按号日限 TTL == 86400
=== R6 · max <= 0 视为恒拒(fail-closed,不是"无限制") ===
PASS max=0 → 直接返 code
PASS 且没有记数
=== R7 · 空组 → NULL(不拿锁,不记数) ===
PASS 空 limits 返回 NULL
=== R4 · 🔴🔴 锁被别人占着 → 必须 __busy__,且一个计数都不加 ===
PASS 锁名形态正确且 ≤64 字节:ratelimit_1_cde912e1445613cf402f291b195382b3
PASS 🔴 拿不到锁时返回 __busy__(fail-closed,绝不放行)
PASS 🔴 被拒时一个计数都没加
=== R5 · 并发:20 个进程打同一组 max=1 的档 → 恰好 1 个放行 ===
PASS 恰好 1 个拿到放行(实得 1;其余 19 个被拒)
PASS 计数最终是 1,没有超发
=== K · kfRateGate(间隔档 / 速率档 / msg_count 不消耗配额) ===
PASS K1 首次放行
PASS K2 紧接着再来 → 被间隔档(2s)拒
PASS K3 放行那次确实记了速率档
PASS K4 速率档撞顶 → 拒
PASS K5 msg_count 撞上限 → 拒
PASS 🔴 K6 msg_count 撞顶时**不消耗速率配额**(msg_count 判断排在缓存两档之前)
PASS K7 守卫:清干净后又能放行(不是恒拒)
=== S · 短信链 rateLimitHit 排在 smsSend 之前(静态判据) ===
PASS S0 前置:三个地标都找得到
PASS 🔴 sendPhoneCode 里 rateLimitHit 出现在 smsSend 之前
PASS S1 前置:方法体切得出来(不是空串)
PASS 🔴 sendPhoneCode 里没有任何"手写回写短信桶"(下发之后再补记 = 又回到旧形态)
=== C · kfConvTokenMint 全局熔断撞顶 → busy(且不建会话) ===
PASS 撞顶时被拒(info==0)
PASS 没有下发 conv-token
PASS 🔴 没有新建 kf_conversation 行
PASS 还原:全局熔断计数回到跑之前的值
PASS 31 FAIL 0