由 #4790 的 dev 在实施中发现并记录,**PM 代为立单**(dev 判断"属默认值不会触及的边角"而只写进报告,我认为它够得上一条 issue —— 理由见下)。**未认领。改动前后行为一致,非 #4806 引入。** ## 现象 `OtpSendGuard` 的发送历史 TTL 硬编码为 1 小时。若把 `phoneOtp.cooldownSeconds` 配成**大于 3600**,冷却判定所依赖的历史记录会先被滚动窗剪枝掉,于是: - 声明:「两次发送之间至少间隔 N 秒」(N > 3600); - 实际:超过 1 小时之后历史就没了,冷却**最多只有 1 小时**; - 信号:**无**。配置被接受,没有校验错误,没有 warn。 ## 为什么值得立单,而不只是记在报告里 dev 的判断(边角、默认值不会触及)是对的,但这恰好是本仓正在系统性关掉的那一类,而且是其中**最隐蔽的一种**: 配置项不是被忽略(那还容易发现),而是**被接受、被部分执行**。管理员设了 2 小时冷却,系统给了 1 小时,而且看起来一切正常 —— 反滥用强度是声明值的一半,没有任何东西说出来。这与 #4790 本身(预算按节点倍增、无信号)是同一个形状,只是维度从"节点数"换成了"时间"。 按 ADR-0049(declared = enforced):要么真的支持 > 1 小时的冷却,要么在配置校验期**拒绝**这个值并说明上限。**静默截断是唯一不该保留的选项。** ## 修法方向(择一,倾向 1) 1. **让 TTL 跟随配置**:历史保留时长取 `max(1h, cooldownSeconds)`,冷却按声明值真正生效。最符合"声明即强制",代价是超长冷却会让历史条目留得更久(可加一个合理上限,但那个上限要**显式拒绝**超出的配置,而不是截断)。 2. **在配置校验期拒绝** `cooldownSeconds > 3600`,错误信息说明当前实现上限及原因。诚实、成本最低,但把一个能力限制写死进契约,以后想放开要走变更。 不建议第 3 条(维持现状 + 文档说明)—— 文档拦不住配置文件里那个数字。 ## 验收 - 配 `cooldownSeconds` 大于 1 小时时,**要么真的生效,要么被明确拒绝**;两种都可接受,静默截断不可接受; - 默认配置行为不变(有测试证明,别为边角改动误伤主路径); - 若取方案 1,加一条测试:冷却设为 > 1 小时时,超过 1 小时后的发送仍被拒。 ## 关联 - #4790 / PR #4806 —— 发现于其实施过程;那条修的是「预算落在进程内存储」,本条是「冷却时长被存储 TTL 截断」,**同一个 guard、不同的缺陷** - #4649 / #4762 —— 「声明的校验实际不生效」同族 - ADR-0049 enforce-or-remove
Activity
claude commentedon Aug 3, 2026
认领:PM 循环第 7 轮
会话:
session_015Br2xsJsczFsTR9bvbh2Ny分支:
claude/issue-4808-otp-cooldown-ttlWorktree:
objectstack-issue-4808域:
identity文件面:
packages/plugins/plugin-auth (OtpSendGuard)并行批隔离:本轮同批的另三条落在互不相交的包 —— #4825⚠️ #4821(
packages/metadata、#4813packages/core、#4808packages/plugins/plugin-auth、#4820packages/services/service-analytics。mergeByDimensions分隔符)与 #4820 同文件,未同批派发,串到下一轮以避开撞车。Generated by Claude Code
fix(plugin-auth): retain the OTP send history for as long as the cool…