You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
69 lines
7.9 KiB
69 lines
7.9 KiB
|
18 hours ago
|
# 02 · 返工新增端点 API 用例
|
||
|
|
|
||
|
|
Type: task
|
||
|
|
Status: resolved
|
||
|
|
|
||
|
|
Claimed: 2026-09-05 · wayfinder 工作会话(frontier 首票)
|
||
|
|
Resolved: 2026-09-05
|
||
|
|
|
||
|
|
## Question
|
||
|
|
|
||
|
|
round-1 矩阵从未覆盖的返工新增端点,设计并落用例(契约以 `.scratch/customer-module/API-SUMMARY.md` 对应节为准):
|
||
|
|
|
||
|
|
| 能力 | 端点 | 断言要点 |
|
||
|
|
|---|---|---|
|
||
|
|
| 战略协议 | POST `/api/customer/agreement/create`、`/edit?id=`、`/delete?id=`;GET `/detail?id=`、`/list?customerId=`(§2.6) | create→edit→delete 全链 + DB 快照断言(返工冒烟范式:2→3→NULL);67001/67002/67017 |
|
||
|
|
| 查重设置 | GET `/api/rule/customer/dedup`、POST `.../dedup/save`(§3) | save→get 回读;五字段(masterEnabled/nameEnabled/nameMatchMode/similarityThreshold/phoneEnabled);越界 64023 |
|
||
|
|
| 批量工商更新 | POST `/api/customer/company-lookup/batch-update?ids=`(§2.2) | 逐客户只补空缺字段;stub 恒 NO_HIT;五状态软处置 |
|
||
|
|
| 导入策略 | upload 增 `duplicateStrategy`(§2.12) | SKIP 响应回显断言;非法值 67013 |
|
||
|
|
| confirmSimilar | POST `/api/customer/quick-create` 透传(§2.3) | 命中相似未确认 needConfirm / 确认后落库 |
|
||
|
|
| viewTouch | GET `/api/customer/detail-head?id=` 副作用(§2.5) | `customer_view_log` upsert 去重(UNIQUE(user_id,customer_id)) |
|
||
|
|
| 形态偏好 | GET/POST `/api/preference/view-form/get\|save`(§2.15) | save→get 回读;viewForm 白名单 list/split/board |
|
||
|
|
| 联系人 oplog | 无独立端点——contact 写动作在 `/api/customer/oplog/page` 记 `CONTACT_ADD/EDIT/DELETE` | oplog action 值域 17 种断言(AGREEMENT_* 3 种同验) |
|
||
|
|
|
||
|
|
断言语义从 `.scratch/customer-rework/RETEST-REPORT.md` 冒烟 43 步清单重建(脚本 `tmp/smoke-t10.py` 已随换机丢失,报告是唯一存证)。
|
||
|
|
|
||
|
|
决定承载方式:并入 core/heavy vs 独立 `e2e-incr.py`(与票 01 产物协同,避免两票改同一文件打架)。
|
||
|
|
|
||
|
|
## Comments
|
||
|
|
|
||
|
|
- 2026-09-05 · 票 01 改写收官时锁定的本票精确输入:改写后静态对账([calls-r2.json](../calls-r2.json) `not_called_customer_domain`)确认客户域未覆盖 19 端点中恰 10 个归本票——agreement×5(create/edit/delete/detail/list)、`GET|POST /api/rule/customer/dedup(/save)`、`GET|POST /api/preference/view-form/(get|save)`、`POST /api/customer/company-lookup/batch-update`;其余 9 个为 round-1 维持项,不进本票票面(票 06 对账附录记录)。协同件:`e2e-heavy-r2.py` `_upload()` 已留 `duplicate_strategy` 形参 seam(F8 导入策略变体挂点);core F-12 已含 confirmSimilar 主断言,本票可引用或细化。另注意 round-1 未拆补的 `GET /api/rule/customer/reminder` 读端点不在本票范围(维持项)。
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Answer
|
||
|
|
|
||
|
|
**承载方式决定:独立 `e2e-incr.py`**(`.scratch/customer-e2e/`,620 行)。理由:① 票 04 执行序 core→heavy→增量三方产物各自独立落盘;② 零触碰票 01 冻结对账产物(matrix-r2.md / calls-r2.json 记录的是改写时点静态事实,往 core-r2 里加端点即失真);③ harness 复制惯例与 heavy 先例一致。产出:`e2e-incr-checks.json` + `specimens-incr.json`(票 06 Bruno 对账素材)+ `calls-incr.json`(对账工具 [scan_calls_incr.py](../scan_calls_incr.py) 保留可复跑,正则含模块路径常量解析——dedup/view-form 调用走常量非字面量,首版对账靠它抓出盲区)。
|
||
|
|
|
||
|
|
**用例结构**(SETUP + I-01…I-07 + TEARDOWN,夹具 = 自建 `e2c-r2i-A/B`,不碰 seed 快照;setup 幂等清残留,teardown 正门 archive + DB 兜底清扫):
|
||
|
|
|
||
|
|
| 流程 | 覆盖 |
|
||
|
|
|---|---|
|
||
|
|
| I-01 战略协议全链 | create→list→detail→edit(2→3)→**归属不可换**(dto.customerId 忽略 + B 快照不动)→delete;快照 2→3→NULL 全程 DB 断言;负例 67001(缺 customerId)/ 67002(幽灵客户防探测同码)/ 67017×5(等级越界、等级缺失、amount>64 超长、幽灵协议 detail/edit/delete);oplog AGREEMENT×3 + 等级文案 |
|
||
|
|
| I-02 联系人 oplog | CONTACT_ADD/EDIT/DELETE 与 AGREEMENT×3 六动作齐现 + 17 种值域对账 + `action=` 过滤参数生效 |
|
||
|
|
| I-03 查重设置 | save 全量覆盖(响应即保存后单例)+ save→get 回读 + 缺省语义三连(开关→0 / 方式→模糊 2 / **阈值→出厂 80 非静默保留**)+ 64023 越界×3 + 校验失败不落库 + 原值还原 |
|
||
|
|
| I-04 批量工商 | NO_HIT×2 + filledFields=0 + 档案前后全等(只补空缺的空转证据)+ 幽灵行级 NOT_FOUND + 空/101 ids → 67001 |
|
||
|
|
| I-05 viewTouch | 清预置→首访插入→再访 upsert 仍 1 行 + last_view_time 刷新→BUDDY 独立行(user 维度隔离)→自清 |
|
||
|
|
| I-06 形态偏好 | save→get 回读两跳 + 跨用户隔离 + 非法值 68001 + **pool·board 契约漂移探测**(分支设计,见下)+ 还原 |
|
||
|
|
| I-07 导入 F8 | SKIP 回显 + 重复组不写入(u=0);OVERWRITE 回显 + 末行生效(u=1);非法 67013;执行面 DB 断言(B 星级不变/变 5)+ D-05 家族 UPDATE 路径新观测分支兜底(D-08 预留续编) |
|
||
|
|
|
||
|
|
I-07 设计要点:文件仅含**已有客户按编号 UPDATE 行(零 INSERT)**,主动绕开 round-1 D-05 的 INSERT 阻断面,使 F8 语义可获得独立验证;confirm 后按任务终态分支(DONE→DB 断言 / FAILED 且 failReason 含 is_biz_negotiated→warn + D-08「UPDATE 路径亦被阻断」家族观测 / 其他 FAILED→fail + D-08)。
|
||
|
|
|
||
|
|
**confirmSimilar 处置**:引用 core F-12 主断言(needConfirm→confirmSimilar=true 落库回 id)不重做;增量夹具 `_mk_customer` 内保留 confirmSimilar 兜底重发路径作伴生覆盖。
|
||
|
|
|
||
|
|
**实现实核修正契约认知**(写用例前代码侧实锤,票 06 Bruno/API-SUMMARY 对账输入):
|
||
|
|
|
||
|
|
1. **pool·board 白名单漂移(本票最重要发现)**:API-SUMMARY §2.14 与返工票 03/05 记载「公海 board 被平台拒绝(680xx)」;实现 `ViewFormServiceImpl` 白名单仅全局三值 {list,split,board},**无 pool 特判**(crm-preference 全模块 grep 无 pool 分支)——预期实测 code=0,用例按「漂移记档 warn」分支设计不阻断,漂移非缺陷(归文档侧处置)。
|
||
|
|
2. agreement 语义实核(`CustomerAgreementServiceImpl`):67001=缺 customerId;67002=客户不存在/无权(防探测同码);67017=等级缺失/越界、amount>64、协议不存在/无权;快照=最新一条(create_time,id 倒序)回写且**不 bump version**——断言逐条对齐。
|
||
|
|
3. dedup save 响应即保存后单例(对称 reminder 族);阈值缺省回出厂 80(a7-3-3-2 §4.1 覆盖口径)。
|
||
|
|
4. batch-update:上限 100 检查先于 distinct(101 重复 id 亦 67001);空 ids 走 Spring 400(`@RequestParam` required)而非 67001——用例按分支断言。
|
||
|
|
5. view-form 为**per-user 单字符串服务端状态**(UNIQUE(user_id,scope_key),无 delete 端点,null 态不可经 API 复位)——地图 fog「UI 覆盖取舍」据此收敛:**不进 demo**,票 03 维持四入口清单(charting 拍板原文即四项;view-form/oplog 无独立 UI 语义,验证面已由 I-06/I-01/I-02 覆盖)。
|
||
|
|
|
||
|
|
**静态验收 PASS**:py_compile PASS(venv10 python);UTF-8 无 BOM;`scan_calls_incr` 对账 **20 调用端点 = 105 基准全命中零未知** + 票 02 范围 10 端点全覆盖(范围外 10 = 夹具创建/清理/oplog 读取/import 执行面/detail-head 等支撑端点,基准内)。
|
||
|
|
|
||
|
|
**移交票 04**:
|
||
|
|
|
||
|
|
- 执行环境:**venv10 缺 openpyxl**(本轮实核)——跑增量前 `& .venv10\Scripts\python.exe -m pip install openpyxl`;compile/对账均用 venv10 解释器(shell `python` 不在 PATH,exit 9009)。
|
||
|
|
- 执行序:core→heavy→incr(incr 自带夹具与清理,重跑幂等);round-1 的 heavy `duplicate_strategy` seam 保持未用(F8 归增量套件,避免两票改同一文件)。
|
||
|
|
- 增量套件 D-05 UPDATE 路径新观测分支已内置(FAILED 特征匹配→warn+D-08,不阻断);若真实出现即为 round-1 未知面新证据。
|