cross_supplier_fallback 把订单派给结构上不支持该国家的供应商,产生确定性 INVALID_COUNTRY 失败——7/14 上线 otpsell 时曾把它放大成 7/17 转化崩盘(当日 8.2%),至今仍在 5sim/lubansms 上每天白烧 ~150 次尝试。已定位到 routing.go 根因,附修复方案。
利润偏低主因是当日订单量处于区间低位(周末效应,7/19 为周日且当日未走完),非转化或质量问题——转化率 17.1% 实际高于近 7 日均值。基本盘无异常。
| 日期 | GA4 Sessions | GA4 Organic | DB 新注册 | DB 新买家 | DB 订单 |
|---|---|---|---|---|---|
| 07-13 | 1,850 | 746 | 475 | 144 | 2,046 |
| 07-14 | 1,601 | 698 | 473 | 128 | 1,424 |
| 07-15 | 1,566 | 662 | 463 | 123 | 1,905 |
| 07-16 | 968 ↓ | 392 ↓ | 442 | 123 | 1,821 |
| 07-17 | 1,002 ↓ | 411 ↓ | 515 | 128 | 4,072* |
| 07-18 | 808 ↓ | 328 ↓ | 442 | 127 | 1,527 |
| 07-19 | 764 ↓ | 224 ↓ | 336 | 73 | 1,218 |
逻辑:若流量真的 -50%,新注册与新买家必然同比例下降(访客→注册几乎同会话完成,无滞后)。但它们在 7/16–7/18 持平(注册 442/515/442,新买家 123/128/127)。因此 GA4 的下滑是埋点/采集问题(Google 侧 bot 过滤、consent/tag 变更或采样),不是真实需求。
动作建议:业务侧无需恐慌;但需修复 GA4 采集,否则营销/SEO 决策会「盲飞」。7/15–16 无前端埋点相关部署,倾向 Google 侧或第三方拦截,建议检查 GA4 DebugView + consent 逻辑。
* 7/17 的 4,072 单是刷量尖峰(GA4 仅 1,002 会话),见下一节。
INVALID_COUNTRY("unknown canonical country code")失败——100% 集中在 canonical_fallback 执行路径。供应商结构上不支持某国家,路由却仍派单过去,供应商秒拒,白烧一次取号尝试 + 延迟预算。
| 供应商 | 路径 | INVALID_COUNTRY 次数 | 窗口 | 状态 |
|---|---|---|---|---|
| otpsell.shop | canonical_fallback | 2,173 | 7/15–7/17(3 天) | 已禁用 |
| 5sim.net | canonical_fallback | 2,117 | 近 14 天(≈150/天) | 启用中 |
| lubansms.com | canonical_fallback | 89 | 近 48h | 启用中 |
派错的国家样本:5sim → JP/TR/SG/KR/RU/UA/CH…;lubansms → OM/CU/SY/NU/AL…(均为这些聚合器 catalog 里根本没有的 canonical country)。
commit fd620c70 enable optsell.shop 于 7/14 启用 otpsell(定位仅「补充印度号源」)。它一上线就被 cross_supplier_fallback 派去接它不支持的 TW/JP/GB/KR 等国订单,3 天内 2,173 次 INVALID_COUNTRY。当日影响触目惊心:
单个错配供应商把「正常的一天」拖成 4,072 单 / 8.2% 的灾难日,估算损失 ~280 个本可完成的订单。otpsell 之后被人工禁用(现 APIError 态,7/17 17:16 起无流量)——但根因未修,下一个新供应商上线仍会踩坑。
这 251 单是「无任何可用供应商的国家/服务组合」的必死订单——用户下了单,路由把所有启用供应商轮一遍,不支持的返 INVALID_COUNTRY、支持的返 NO_NUMBERS,最终 100% 失败。这暴露两层问题:
① 路由效率:给不支持的供应商派单是纯浪费(API 调用 + 延迟预算,直接关联 #629 lubansms 15s 取号超时事故——白跳转会吃掉取号 deadline,导致本可成功的订单反被拖超时);
② 可售目录覆盖:我们在对外售卖根本无法履约的国家组合(值得单独治理 sellable catalog)。
候选供应商在 backend/internal/service/supplier/routing.go 的 cross_supplier_fallback 分支被枚举,仅经 supportsCanonicalFallback(sup, country) 过滤:
| 供应商类型 | country 级检查 | 结果 |
|---|---|---|
| 自营池 PoolSupplier(isptelecom) | 有 PoolSupplier.SupportsCountry() | 不支持的国家被正确跳过 ✓ |
| 外部聚合器(5sim / lubansms / otpsell…) | 无 仅一个布尔 SupportsCanonicalFallback() | 无条件放行 → INVALID_COUNTRY ✗ |
注释里假设「聚合器 catalog 已按 country 筛过」,但 canonical_fallback 恰恰是 catalog 没有 offer 时才走的兜底路径——此处 catalog 筛选不成立,于是漏放行。自营池已有对等硬闸(2026-07-13 为 ISP 加的 SupportsCountry),外部供应商缺同款。
CanonicalFallbackCapable 供应商补一个与 PoolSupplier.SupportsCountry 对等的 country 预过滤:新增可选接口 CanonicalCountrySupport{ SupportsCanonicalCountry(country) bool },在 supportsCanonicalFallback() 里对外部供应商调用;实现只读已缓存的 catalog snapshot(如 5sim 的 snapshot.countryByCanonical),严禁触发抓取,snapshot 未加载时默认放行。
AllocateNumber 内部判 INVALID_COUNTRY 的同一份 snapshot——被跳过的候选本来就会失败,不会误杀任何本可成功的候选;snapshot 冷时默认放行 = 退回现状。canonical_fallback:SELECT supplier_slug, execution_path, count(*) FROM supplier_execution_attempts WHERE error_code='INVALID_COUNTRY' AND started_at>=now()-'14 days'::interval GROUP BY 1,2