docs: 履约匹配逻辑深度分析(§21 痛点 P1-P8 + 优化建议分档)

- 匹配链路全貌:91 item → 三路匹配 → 路由(规则/优先级/manual_review) → planner 动态 profile
- 8 个痛点:P1 精确映射排在名字模糊匹配之后(可信度倒挂)、P2 productNo 未拆 ---- 后缀、P3 映射键无归一化、P4 缺名字兜底、P5 余额不参与路由、P6 双轨配置冲突、P7 重复计算、P8 命名语义误导
- 优化建议分档:快赢档 P1-P3 / 中档 P4 / 后档 P5-P8;按用户指示先分析不改代码
This commit is contained in:
yml2213
2026-08-05 16:14:35 +08:00
parent 7fc3d60588
commit 5f5506bb19
@@ -559,3 +559,56 @@ order_site 处理要求:
**处理顺序设计**:去重闸门放在「找到任务」之后 —— 任务未建/已删时返回 404 让对方重试,而不是被 eventId 去重永久拦截;找到任务后冲突才视为重复投递直接 200。
**验证**typecheck 通过;后端全量 212 测试通过;脚本验证前置错误分支——缺签名头 401 / 时间戳超容差 401 / 验签失败 401 / 缺订单号 400 全部正确;「任务不存在→404」及幂等/同步路径依赖真实 DB,留待阶段 6 端到端演练(本沙箱无 postgres)。
---
## 21. 履约匹配逻辑深度分析(v2.6)
### 21.1 匹配链路全貌
```
91 订单 itemninetyone/order-service.ts:40-95
├─ externalSkuCode = productNo ← 91 商品编码(可能含 "----店铺ID" 后缀,parseOpen91ProductNo 拆分)
├─ externalSkuName = productName ← 91 商品名
├─ snapshot.productNo = productNo
└─ snapshot.productName = productName
▼ resolveConfiguredItemCandidateproduct-resolution-service.ts:212
├─ cloudtentaclesMatch = 商品名归一化模糊匹配(网络 listSku)
├─ kuaishouFeifeiMatch = 商品名规则 contains
└─ affiliateDashMatch = skuMapping[productNo] 精确映射(resolveAffiliateDashSkuByProductNo
▼ resolveFulfillmentRouterouting-config-service.ts:136
① 商品路由规则 rulesexact/contains,按商品名)→ ② 全局优先级
kuaishou_cloud → kuaishou_feifei → affiliate_dash → ③ manual_review 兜底
▼ planner.resolveDynamicAffiliateDashProfileplanner.ts:397
snapshot.affiliateDash.sku → profileconfigId: "affiliate_dash:<sku>"
```
### 21.2 痛点清单
| # | 痛点 | 影响 | 证据 |
| --- | --- | --- | --- |
| P1 | **优先级与可信度倒挂**affiliate_dash 是精确编码映射(运营显式配置、高可信),却排在 cloudtentacles / feifei 的**名字模糊匹配**之后 | 91 商品名若同时像 cloudtentacles 商品,会被 cloud 抢单走错通道;映射白配 | `DEFAULT_EXECUTOR_PRIORITY`routing-config-service.ts:74-78);阶段 3 联调能走对仅因当时 cloud/feifei 未命中 |
| P2 | **productNo 未拆分 `----` 后缀**`resolveAffiliateDashSkuByProductNo` 直接用 `snapshot.productNo` 原值查映射,而 open-91 的 productNo 可能为 `商品名----店铺ID``parseOpen91ProductNo` 专门拆它,但该函数未进解析链) | 带后缀的 91 编码精确匹配 miss → 直接落 manual_review | product-resolution-service.ts:305-330ninetyone/order-service.ts:30 |
| P3 | **匹配键无归一化**skuMapping key 只做原样精确匹配,无 trim/大小写/变体处理 | 编码大小写变体(`x91-lucky-90` vs `X91-LUCKY-90`miss | product-resolution-service.ts:317-318 |
| P4 | **缺名字兜底**affiliate_dash 有 33 个商品(含 displayName),但匹配只有编码精确映射;cloudtentacles / feifei 都有名字匹配,唯独 affiliate_dash 没有 | 新 91 商品未配映射即 manual_review,无法像 feifei 那样按名字自动兜底 | product-service.ts:58-75displayName 未被用于匹配) |
| P5 | **余额/健康度不参与路由决策**affiliate_dash 候选 available 只看映射命中;余额不足时选中 → prepare 预检失败 → manual_review,不会自动切下一通道 | 单通道阻塞,无自动降级 | 阶段 3 仅在 prepare 前预检(getAffiliateDashWallet |
| P6 | **双轨配置冲突**:路由规则(商品名→executor)与 skuMapping(编码→sku)两套独立配置,同一商品可能被两种规则重复描述、运营维护两处 | 配置漂移、规则打架 | routing-config-service.ts:159-177 vs product-resolution-service.ts:305-330 |
| P7 | **重复计算**`hasConfiguredOrderItems`(下单前)与 `resolveOrderItemForFulfillment`(履约时)各跑一次 `resolveConfiguredItemCandidate`cloudtentacles 名字匹配是**网络调用**(listSku) | 同一订单解析两次、重复拉商品列表 | product-resolution-service.ts:181-195cloudtentacles-name-match-service.ts:111 |
| P8 | **命名语义误导**`skuMapping`productNo→sku)实际 key 是 **91 外部编码**、value 是 **affiliate_dash sku**;文档/代码里 productNo 一词混用两套体系 | 运营配置时易搞反 | product-resolution-service.ts:40-45;文档 §12 |
### 21.3 优化建议(分档)
- **快赢档(P1/P2/P3,改动集中 product-resolution-service.ts,低风险)**
- P1`resolveConfiguredItemCandidate` 中 affiliateDashMatch 精确命中时**直接优先选择 affiliate_dash**(映射命中视为运营显式意图),不受全局优先级影响;或把 `DEFAULT_EXECUTOR_PRIORITY` 调整为 affiliate_dash 前置。建议加开关「映射命中优先」(默认开)。
- P2productNo 先走 `parseOpen91ProductNo` 拆掉 `----店铺ID` 再用 productName 段查映射。
- P3:映射查询前 trim + 大小写归一;可选支持 contains 前缀匹配。
- **中档(P4**affiliate_dash 商品 displayName 归一化名字匹配兜底(仿 cloudtentacles 匹配器),开关控制,避免误配。
- **后档(P5-P8)**:候选层余额/健康度(带缓存)、路由与映射配置合一、解析结果缓存去重、命名修正。
### 21.4 待验证点
- 91 卡券(91kaquan/kuaishou)真实 productNo 是否带 `----店铺ID` 后缀(决定 P2 是否为实际故障)。
- 33 个 affiliate_dash 商品 displayName 与 91 商品名的重合度(决定 P4 兜底收益)。