SmsSender Protocol(fake/tencent)+ 验证码生命周期(哈希存储/一次性/ 5 次作废)+ 号码-IP-设备三重频控 + 掩码纪律(FR-ACC-04/14,TD-32; 真实发送待签名审核)。 实现:packages/identity/sms_login.py(SmsStore/SmsSender 双 Protocol、 FakeSmsSender 打日志、TencentSmsSender 包官方 SDK 失败映射 61000、 SmsAuthService 验证码生命周期 + UTC+8 时段桶频控);路由 POST /auth/sms/send、POST /auth/sms/verify(provider="phone" 映射 + issue_session + TokenPairResponse,与华为通道零耦合)。测试:单测 37 个 (内存 dict 实现 store、注入时钟模拟 TTL;号码规范化/掩码/频控矩阵/ 验证码四要素/腾讯通道桩测),集成 7 个(send→verify 双令牌闭环、同号 同 user、脚本化刷量 11 发第 11 次 42911、IP/设备维度、错 5 次作废)。 门禁:ruff/mypy(identity+apps/api)/lint-imports 全绿,单测 275 通过、 集成 23 通过。 偏差说明: 1. SmsSender.send_code 收 (phone, masked, code) 三参而非单一「掩码键」: 腾讯通道下发必须有真实号码(掩码/哈希无法投递);防泄漏由「实现层 不得记录 phone」约定 + structlog 全局手机号脱敏兜底。 2. 频控计数按「请求」计(含被拒请求)且在限额检查前自增:否则被拒 请求不烧额度,攻击者可无限试探;同时这是「连发 11 次第 11 次 42911」脚本化验收在真实时钟下成立的前提。 3. request_code 对 sender 逃逸的非 AppError 异常兜底包成 61000: 通道故障不得以 5xxxx 内部错误形式稀释告警(TencentSmsSender 自身 映射为主,此处仅接漏网)。 4. wire 请求模型(SmsSendRequest/SmsVerifyRequest)定义在 sms_login.py 内(任务文档允许的两选一,未新建 sms_schemas.py)。
tests/
| 目录 | 内容 | 依赖 |
|---|---|---|
unit/ |
领域逻辑、LLM 网关、脱敏、错误码 | 无。不许连库、不许发网络请求 |
integration/ |
带 PostgreSQL / Redis 的链路 | make up,或 testcontainers |
golden/ |
黄金集回归(检索 / 规则 / 报告) | 尚未建立,见下 |
make test-unit # 默认只跑 unit(integration 自动跳过)
MEIDA_RUN_INTEGRATION=1 uv run pytest -m integration
覆盖率门槛
pytest 对 packages/llm 与 packages/domain 统计覆盖率,低于阈值即失败。
这两个包是 mypy strict 的范围,也是业务正确性的核心,其他层靠集成测试覆盖。
绝对不要做的事
- 不要在单测里调用真实的 DeepSeek。
scripts/smoke.sh是唯一会真的花钱的 入口。单测用httpx.MockTransport或tests/unit/test_gateway.py里的FakeProvider。 - 不要
time.sleep()。熔断器、预算闸门都支持注入时钟。 - 不要断言日志文本。断言行为。
黄金集(还没建,但这是最重要的一道防线)
架构 §16.2:
AI 改代码时最容易破坏的是那些「没有断言保护的隐性行为」。检索链路和规则引擎 必须有一套固定输入 → 期望输出的样本集。
M2 落地知识库时必须同步建立(FR-KB-11,≥ 100 条用例): 检索 Top-5 命中率 ≥ 80%、硬过滤零漏、规则命中正确性、报告结构完整性、 硬性禁忌违反数 = 0。指标退化即阻断合并。
已覆盖的关键不变量
| 测试 | 保护的是什么 |
|---|---|
test_prompt_cache_prefix.py |
固定前缀不含易变 token,否则输入成本翻数倍 |
test_daily_budget.py |
日成本超限时拒绝非关键调用,不是只告警 |
test_gateway.py |
路由、故障转移、熔断、结构化重试、每次调用都记成本 |
test_quota_domain.py |
预扣三段式;退还幂等;服务端硬校验 |
test_task_state.py |
任务状态机没有非法跃迁 |
test_log_redaction.py |
手机号 / 令牌 / 密钥 / 诊断结论不进日志 |
test_response_envelope.py |
每个错误码都有文案;配额文案不含价格字样 |