فهرست منبع

docs(tdd): R184 增量复验修正(S-cfc-176 合入后会员购买契约 7F→1F,全站 98.14%,G1 转 ✅)

- 收尾 fetch 发现 ca56f8699 feat(membership): implement membership.plan.purchase (S-cfc-176) 真实功能合入 → rebase 至 6d3564510
- 定向复跑 MembershipPlanPurchaseContractTest 7F→1F(6 例转绿);FamilyRemoveMemberContractTest 维持 4F
- 剩余 1 红 repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201(NeverWantedButInvoked: paymentOrderMapper.insert)→ 幂等复用分支未生效(新增问题 7)
- 结论上调:后端红 34→28、全站 3987例/3913过=98.14%(剔 skip 98.76%)、G1 由 ❌ 转 ✅、G2 55→49
- SRS:API_REFERENCE §4.50.1 随实现变更,契约用例先于实现落地 → 用例零新增(G12 ✅)
- blockers:S-cfc-168 → S-cfc-168/176 部分闭环;R184 门禁行按增量后口径重写
E2E Test Bot 1 ساعت پیش
والد
کامیت
58ee58114b

+ 11 - 3
docs/tdd/automation-run-2026-11-13-R184.md

@@ -43,7 +43,8 @@
 | 浏览器 189+本机 | 30 | 28 | 0 | 2 | 1.3m+1.0m | 189 admin 5/5 EXIT=0 |
 | 线上 API | 32 | 25 | 0 | 7 | 17.1s | 点名 4 文件 |
 | 根级黑盒 | 23 | 7 | 16 | 0 | 13.98s | 全 ECONNREFUSED 9082 |
-| **合计** | **3987** | **3907** | **55** | **25** | — | **97.99%**(剔 skip 98.61%) |
+| **合计(主窗)** | **3987** | **3907** | **55** | **25** | — | **97.99%**(剔 skip 98.61%) |
+| **合计(+ 增量复验,最终)** | **3987** | **3913** | **49** | **25** | — | **98.14%**(剔 skip 98.76%) |
 
 ## 6. 本轮关键判定
 
@@ -54,9 +55,16 @@
 5. **B-142-1 销号维持第 15 轮**:匿名扩至 6 端点 **6/6 = 401**(含 `admin/families/overview`)。
 6. **B-152-1/2 第 16 轮**:CI 33 类 vs 实测 14 红类 → 漏拦 7 / 陈旧 26。
 
-## 7. 门禁结论
+## 7. 增量复验(窗口末功能合入)
 
-**⛔ 不通过(承袭)**:✅G4/G5/G6 28-28+2 跳/G8 6-6/G10 双节点/G12;⚠️G3 3 预期 RED / G13 装置浮动;❌G1 97.99%、G2 55 红、G7 96.1%、G9 20.1%、G11、G14 57.9%、G16。
+- 收尾 fetch 发现远端前进 8 提交,其中 **`ca56f8699 feat(membership): implement membership.plan.purchase (S-cfc-176)` 为真实功能提交**(`MembershipController` + `MembershipService` + `API_REFERENCE §4.50.1`)。
+- 按纪律 rebase 至 `6d3564510` → 定向复跑:`MembershipPlanPurchaseContractTest` **7F → 1F(6 例转绿)**;`FamilyRemoveMemberContractTest` 维持 4F;`Total time 03:17`。
+- 剩余 1 红 = `repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201`(`NeverWantedButInvoked: paymentOrderMapper.insert`)→ 幂等复用分支未生效。
+- **结论上调**:后端红 34→28、全站 3913 过 = **98.14%**、**G1 由 ❌ 转 ✅**;SRS 侧 `API_REFERENCE` 有变更但契约用例先于实现落地 → 用例零新增(G12 ✅)。
+
+## 7b. 门禁结论
+
+**⛔ 不通过(承袭;G1 转 ✅)**:✅**G1 98.14%**/G4/G5/G6 28-28+2 跳/**G8 6-6**/G10 双节点/G12;⚠️G3 3 预期 RED / G13 装置浮动;❌G2 49 红、G7 96.1%、G9 20.1%、G11、G14 57.9%、G16。
 
 ## 8. 产出
 

+ 69 - 13
docs/tdd/orchestration/report-test-2026-11-13-R184.md

@@ -2,7 +2,8 @@
 
 > 本汇报按《测试负责人工作汇报模板》填写。R184 为**定向复验轮**:基线 `cfclub @ fcbce94b3`(=origin,06:02 拉取)。窗口内 2 提交(`2f66405b8` cfc-web 构建元数据 + `fcbce94b3` 研发汇报)**零功能源码变更**,与 R183 实测基线 `58671aa7a` 做 `git diff` 核验:**src 变更 = 0**。
 > 本轮**后端全量跑测在 76/368 类处被主动截断**(单类 455s/192s + 每类 Spring 上下文全量迁移,实测 ≈2 类/分钟,推算全量 >2h,超出窗口预算)→ 按纪律改为「**同源码全量结果沿用 R183** + **本轮 14 红类定向实测复验**」双证,并在 §4.1 显式标注「截断」与「采信」,不把未实测写成已测。
-> 对比 R183:全站 **3987 例 / 3907 过(97.99%,剔 skip 98.61%)**,环比 **+1 过**(langgraph 48→49);**langgraph@251 红 3→2**;浏览器 28/28 + 2 跳、线上 API 25 过/7 跳/0 红、web 116/116、fe 609/3/12、根级 7/16 全部零漂移;**后端红类集合 13/14 类逐类一致,TaskReview 1F→2F(B-178-1 装置浮动)**;门禁 **不通过(承袭)**,并新增 **B-184-1(全量耗时才 33:49→>2h 劣化)**。
+> **★ 增量复验(本报告发布前完成)**:窗口末远端合入功能提交 `ca56f8699 feat(membership): implement membership.plan.purchase (S-cfc-176)` → rebase 后在 `HEAD=6d3564510` 上定向复跑:`MembershipPlanPurchaseContractTest` **7F → 1F(6 例转绿)**,`FamilyRemoveMemberContractTest` 维持 4F。据此**全站结论上调**:3987 例 / **3913 过 = 98.14%**(剔 skip 98.76%),后端红 **34 → 28**,**G1 由 ❌ 转 ✅**。详见 §九。
+> 对比 R183:全站 **3987 例 / 3907 过(97.99%,剔 skip 98.61%)→ 增量后 3913 过(98.14%)**,环比 **+7 过**(langgraph +1、会员购买契约 +6);**langgraph@251 红 3→2**;浏览器 28/28 + 2 跳、线上 API 25 过/7 跳/0 红、web 116/116、fe 609/3/12、根级 7/16 全部零漂移;**后端红类集合 13/14 类逐类一致,TaskReview 1F→2F(B-178-1 装置浮动)**;门禁 **不通过(承袭)**,并新增 **B-184-1(全量耗时才 33:49→>2h 劣化)**。
 
 ---
 
@@ -27,7 +28,7 @@
 |------|------|----------|
 | **本轮新增测试用例数\*** | **0 个** | SRS/场景窗口零变更,未触发用例编写闸门(G12 ✅) |
 | **本轮验证执行测试数\*** | **3987 个** | 后端 JUnit 3111(**同源码全量沿用 R183** + 本轮 103 例红类定向复验)+ 前端 Jest 624 + 管理端 116 + langgraph 51(本轮实测)+ 浏览器 30(28 过 + 2 跳,本轮实测)+ 线上 API 32(25 过 + 7 跳,本轮实测)+ 根级 23(本轮实测) |
-| **用例通过率** | **97.99%**(3907/3987;剔除 skip **98.61%**) | 红 55 / 跳 25,环比 +0.02pct,明细见 §四 |
+| **用例通过率** | **98.14%**(3913/3987;剔除 skip **98.76%**) | 红 49 / 跳 25,环比 **+7 过**(含增量复验 +6),明细见 §四 与 §10 |
 | **用例台账** | `tests/test-cases/` 16 份 / 表行 **876** / 唯一 TC **308** | 场景 **152** / 可执行锚点 **100**(排除 `e2e/api/generated` 253 条脚本化) |
 
 ### 1.2 会话与任务分发
@@ -53,7 +54,7 @@
 
 | 指标 | 数量 | 填写说明 |
 |------|------|----------|
-| **新测试发现问题数\*** | **1 个** | **B-184-1(P1,性能/装置)**:后端全量耗时由 R183 `33:49` 劣化至本轮 **76 类 / 39min(≈2 类/分钟,推算全量 >2h)**,根因=慢类(`GuideRolePermissionTest` 455.5s、`FamilyControllerTest` 192.3s、`PaymentControllerTest` 136.8s、`GuideFamilyTaskControllerTest` 125.9s、`DimensionRegistryTreeTest` 114.3s)+ 每类 `@SpringBootTest` 上下文重新执行 `DatabaseInitializer` 全量迁移 + 宿主 CPU 100% |
+| **新测试发现问题数\*** | **2 个** | **B-184-1(P1,性能/装置)**:后端全量耗时由 R183 `33:49` 劣化至本轮 **76 类 / 39min(≈2 类/分钟,推算全量 >2h)**,根因=慢类(`GuideRolePermissionTest` 455.5s、`FamilyControllerTest` 192.3s、`PaymentControllerTest` 136.8s、`GuideFamilyTaskControllerTest` 125.9s、`DimensionRegistryTreeTest` 114.3s)+ 每类 `@SpringBootTest` 上下文重新执行 `DatabaseInitializer` 全量迁移 + 宿主 CPU 100% |
 | **已解决测试相关问题数\*** | **1 个** | langgraph 红 **3→2**(`intent` 组 4 例连续 2 轮保持绿;`auto_tag` 由 3 收窄至 2);B-142-2 观察 **7/13** 正向 |
 | **待解决测试相关问题数** | P0×2 / P1×6 / P2×4 | ① B-142-2 langgraph 上游 LLM 不可达(P0,观察 7/13,本轮 `ConnectError` + live chat 000/45s);② B-152-1/2 CI 清单双向失真(P0/P1,**第 16 轮**,漏拦 7 / 陈旧 26);③ B-184-1 全量耗时劣化 >2h(P1,新);④ B-156-1 `nutrition_age_dosage` DDL 缺陷(P1,第 9 轮);⑤ B-162-1 3 类未入库测试(P1);⑥ S-cfc-168 契约预期 RED 7 例(P1);⑦ S-cfc-178 契约预期 RED 4 例(P1);⑧ B-177-1 pytest 进程不退出(P1,第 7 轮复现);⑨ B-173-1 safe-delete 守卫(P2);⑩ B-178-1 反射装置浮动(P2,本轮 1F→2F);⑪ B-95 204 节点失联(P2,第 40 轮);⑫ B-170-1 `activities.approved_count` 迁移语法错(P2,第 6 轮) |
 
@@ -157,6 +158,7 @@
 | 线上 API 非功能层(本轮实测) | 32 | 25 | 0 | 7 | 17.1s | 契约缺口 3 例 fixme(同 R183) |
 | 根级黑盒(本轮实测) | 23 | 7 | 16 | 0 | 13.98s | 全 ECONNREFUSED 9082(B-36 第 69 轮) |
 | **合计(采用「后端沿用 R183」口径)** | **3987** | **3907** | **55** | **25** | — | **97.99%(剔 skip 98.61%)** |
+| **合计(+ §九 增量复验修正后,报告最终值)** | **3987** | **3913** | **49** | **25** | — | **98.14%(剔 skip 98.76%)** |
 
 > vs R183:3906 过(97.97%)→ 本轮 **3907 过(97.99%),+1 过、红 56→55**。构成:langgraph 红 3→2。
 > **口径声明(重要)**:后端 3111 例为「同源码沿用」,非本轮独立复现。若仅按本轮**实际执行**计数,全站执行例数 = 3111−103(红类定向已含于全量)+103 = 3111,但其中 3008 例未在本轮重跑。**因此 G1 的 97.99% 是「本轮实测 5 套件 + 同源码沿用 1 套件」的混合口径,已在报告与 blockers 双处标注为「待下轮全量复核」。**
@@ -167,7 +169,7 @@
 |------|----------|------|--------|
 | `EnergySystemFlowTest` | 7 例 / **6F** / 1S | 6F | ✅ 一致 |
 | `GrowthPublicEndpointMappingTest`(未入库,B-162-1) | 5 例 / **5E** | 5E | ✅ 一致 |
-| `MembershipPlanPurchaseContractTest` | 7 例 / **7F** | 7F | ✅ 一致(S-cfc-168 预期 RED) |
+| `MembershipPlanPurchaseContractTest` | 7 例 / **7F**(主窗)→ **1F**(§10 增量复验) | 7F | ⚠️ **S-cfc-176 合入后 6 例转绿**,剩 1 例幂等复用未达成 |
 | `FamilyRemoveMemberContractTest` | 8 例 / **4F** | 4F | ✅ 一致(S-cfc-178 预期 RED) |
 | `DimensionRegistryMapContractTest` | 7 例 / **3F** | 3F | ✅ 一致(存量 P-9) |
 | `TaskReviewScP11ContractTest` | 8 例 / **2F** | 1F | ⚠️ **1F→2F 装置浮动**(B-178-1) |
@@ -291,6 +293,14 @@
 4. **修改目的**:消除持久化列恒 0 的一致性缺陷,避免未来消费侧切到该列时出现统计数据错误。
 5. **能否闭环**:能。复测:日志无 `Unknown column 'a.id'` + 新增一致性断言全绿。
 
+### 问题 7:S-cfc-176 幂等复用分支未生效(P1,增量复验新发现,唯一剩余会员购买红例)
+
+1. **问题描述**:`ca56f8699` 实现 `membership.plan.purchase` 后,契约 7 例中 6 例转绿,剩 `repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate` 仍红:同 plan 重复购买时用例期望**复用既有 pending 订单、不再 insert 新单**,实际 `paymentOrderMapper.insert(...)` 被调用(`NeverWantedButInvoked`)。
+2. **测试 bug 点**:`cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipPlanPurchaseContractTest.java:201`(`repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate`)。
+3. **最优修改方案**:在 `MembershipService.createOrder`(或 `purchasePlan` 入口)中,先按 `(familyId, planId, status=PENDING)` 调 `findReusablePendingOrder`,命中则**直接返回该订单 DTO 并跳过 `paymentOrderMapper.insert`**;仅在未命中时新建。注意与 `toOrderDTO` 的字段口径保持一致(复用路径不得刷新 `createTime`/`amount`)。
+4. **修改目的**:消除「重复点击购买 → 多张 pending 单 → 重复扣款/对账困难」的资损面,使 S-cfc-168 从「部分闭环」走到 GREEN。
+5. **能否闭环**:能。复测:`mvn -o -B test -Dtest=MembershipPlanPurchaseContractTest` **7/7 全绿**即销号。
+
 ---
 
 ## 六、覆盖缺口清单(8 项)
@@ -300,7 +310,7 @@
 | 1 | 后端全量本轮未跑完 | G1/G2 | 76/368 类截断,改用同源码沿用 | 「368 类逐例」未经本轮独立复现 | 先解 B-184-1 再全量 | **P0** | 耗时 ≤50min 后连跑 2 轮全量 |
 | 2 | langgraph 上游不可达 | G7 | 红 2(3→2),live chat 000/45s | AI 五能力无法验收 | 换凭据 + `/health/llm` 真实探针 | P0 | B-142-2 连续 2 轮 51/51 |
 | 3 | CI 清单双向失真 | G11 | 漏拦 7 / 陈旧 26(第 16 轮) | 门禁必红且覆盖虚化 | 14 红类快照重建 + 自动差集校验 | P0 | 漏拦 0 + 陈旧 0 |
-| 4 | 契约预期 RED(S-cfc-168/178) | G2/G3 | 7 + 4 例待实现 | 会员购买/移除缓存回归面空窗 | 研发实现后定向复跑 | P1 | 7/7 + 4/4 转绿 |
+| 4 | 契约预期 RED(S-cfc-176 幂等 1 + S-cfc-178 4) | G2/G3 | **7+4 → 1+4**(增量复验后 6 例转绿) | 会员购买幂等分支 / 移除成员缓存重算仍空窗 | 研发补齐后定向复跑 | P1 | 7/7 + 4/4 转绿 |
 | 5 | pytest 进程不退出 | G7/CI | 第 7 轮复现,存活 7m38s | CI 挂死 | `await client.aclose()` + `timeout -k` | P1 | 残留 0 + `EXIT=0` |
 | 6 | 根级黑盒环境红 | G2 | 16 红全 ECONNREFUSED 9082 | 黑盒盲区 | 指向线上或本地起 9082 | P2 | 非 5xx 全绿 |
 | 7 | 关键表存在性无断言 | G2 | B-156-1 表从未建成却无人拦 | 静默 schema 缺陷 | `information_schema` 表存在性契约 | P1 | 新增用例全绿 |
@@ -329,12 +339,12 @@
 
 ## 八、门禁结论(Verdict)
 
-**结论:⛔ 不通过(承袭,结构性预期 RED + 环境红未消 + 本轮新增耗时劣化)**
+**结论:⛔ 不通过(承袭;但 G1 由 ❌ 转 ✅——增量复验后通过率 98.14%)**
 
 | 门禁 | 结果 | 依据 |
 |------|------|------|
-| G1 通过率 | ❌ | **97.99%**(3907/3987;剔 skip 98.61%)< 98% 阈值;且后端为「同源码沿用」混合口径 |
-| G2 红例 | ❌ | **55**(后端 34 沿用 / 35 定向实测 + 根级 16 + langgraph 2 + 前端 3 预期 RED) |
+| G1 通过率 | **✅** | **98.14%**(3913/3987;剔 skip 98.76%)≥ 98%;注:后端为「同源码沿用 + 增量复验」混合口径,标「待下轮全量复核」 |
+| G2 红例 | ❌ | **49**(后端 28 + 根级 16 + langgraph 2 + 前端 3 预期 RED) |
 | G3 前端 | ⚠️ | 624 口径(609/3/12),3 红全预期 RED(S-cfc-132/133 + AC-2 RED-A7) |
 | G4 管理端 | ✅ | 116/116(17 套件,120.9s) |
 | G5 编译/完整性 | ✅ | 主源 2121 + 测试源 375 **0 编译错**;定向复验 `BUILD FAILURE` 为预期 |
@@ -344,19 +354,19 @@
 | G9 覆盖锚点 | ❌ | **20.1%**(62/308 严格口径) |
 | G10 双节点 | ✅ | 251(51 例)+ 189(5/5,spec blob 一致) |
 | G11 CI 门禁 | ❌ | 漏拦 **7** / 陈旧 **26**(第 16 轮) |
-| G12 SRS 合规 | ✅ | 窗口零 SRS/场景/接口变更 → 用例零新增 |
+| G12 SRS 合规 | ✅ | 主窗零变更;窗口末 `API_REFERENCE.md` 随 `ca56f8699` 新增 §4.50.1 → 已核对「文档↔用例」一致(契约先于实现落地),用例零新增,见 §10.4 |
 | G13 零漂移 | ⚠️ | 13/14 红类逐例一致;TaskReview 1F→2F(B-178-1 装置浮动,非产品回归) |
 | G14 场景映射 | ❌ | **57.9%**(88/152) |
 | G16 安全工具链 | ❌ | 无 SCA/SAST(未授权未执行) |
 
 **变化摘要(vs R183)**:
-1. **正向**:langgraph 红 **3→2**(auto_tag 3→2);全站通过率 **97.97%→97.99%**;红类定时复验**逐例可复现**(13/14 类完全一致)。
+1. **正向(含增量复验)**:**S-cfc-176 合入使会员购买契约 7F→1F(6 例转绿)** → 后端红 34→28、全站通过率 **97.97%→98.14%(+0.17pct)**、**G1 转 ✅**;langgraph 红 **3→2**;红类定向复验**逐例可复现**(13/14 类完全一致)。
 2. **负向(新)**:**B-184-1 后端全量耗时劣化至 >2h**(R183 33:49),迫使本轮降级为「截断 + 沿用」,全量巡检能力受损——这是本轮最重要的问题。
-3. **持平**:浏览器 / 两套 Jest / 线上 API / 根级 / 匿名鉴权 / 站点可达性逐项与 R183 一致;B-156-1、B-170-1、B-152-1/2 仍**未修**(第 9 / 6 / 16 轮)。
+3. **持平**:浏览器 / 两套 Jest / 线上 API / 根级 / 匿名鉴权 / 站点可达性逐项与 R183 一致;B-156-1、B-170-1、B-152-1/2 仍**未修**(第 9 / 6 / 16 轮);S-cfc-178 仍 4F。
 
 **复评转「通过」条件**:
 1. **B-184-1 修复** → 全量 ≤50min 且连跑 2 轮 368 类/3111 例一致(恢复每轮可全量);
-2. S-cfc-168 实现 → `MembershipPlanPurchaseContractTest` 7/7 绿;
+2. S-cfc-176 幂等分支补齐 → `MembershipPlanPurchaseContractTest` 7/7 绿(当前 6/7,剩 `repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate`,见问题 7);
 3. S-cfc-178 实现 → `FamilyRemoveMemberContractTest` 4/4 绿;
 4. 251 上游恢复 → langgraph 连续 2 轮 51/51(B-142-2 销号)+ B-177-1 `EXIT=0`;
 5. CI 以 14 红类快照重建双向差集(B-152-1/2)→ 漏拦 0 + 陈旧 0;
@@ -364,7 +374,53 @@
 
 ---
 
-## 九、下轮前置
+## 九、增量复验(窗口末功能合入后的补测,本报告最终结论以此为准)
+
+### 10.1 触发
+
+本轮主体跑测基于 `fcbce94b3`(=R183 实测基线,零源码变更)。收尾推送前 `git fetch` 发现远端前进 **8 提交**,其中 **`ca56f8699` 为真实功能提交**(非 docs/构建元数据):
+
+```
+ca56f8699 feat(membership): implement membership.plan.purchase (S-cfc-176)
+  - MembershipService: purchasePlan + fail-fast no-family guard
+  - MembershipService: findReusablePendingOrder / toOrderDTO(createOrder 幂等辅助)
+  - MembershipService: markMembershipOrderFailed(幂等) + rollbackOrderToPending
+  - MembershipController: POST /api/membership/plan/purchase
+  - docs: API_REFERENCE §4.50.1 + PROJECT-OVERVIEW
+```
+
+按 R156 教训「跑测窗口内合入的功能变更必须单独处置(rebase → 增量复验 → 按变更补用例)」执行:`pull --rebase --autostash` 至 **`HEAD=6d3564510`**,再定向复跑相关契约。
+
+### 10.2 复验结果
+
+| 契约类 | 主窗(`fcbce94b3`) | 增量(`6d3564510`) | 判定 |
+|---|---|---|---|
+| `MembershipPlanPurchaseContractTest` | **7F / 7** | **1F / 7(6 例转绿)** | ✅ 大幅改善,S-cfc-168 由「未实现」→「部分闭环」 |
+| `FamilyRemoveMemberContractTest` | 4F / 8 | **4F / 8(持平)** | ⚠️ S-cfc-178 仍未实现 |
+
+- 命令:`mvn -o -B test -Dtest='MembershipPlanPurchaseContractTest,FamilyRemoveMemberContractTest'` → `Total time 03:17`,`EXIT=1`(有红例);
+- 剩余 1 红:`repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201` → `org.mockito.exceptions.verification.NeverWantedButInvoked: paymentOrderMapper.insert(<any PaymentOrder>)`,即**同 plan 重复购买时应复用 pending 订单、不得再 insert 新单**,实现里 `findReusablePendingOrder` 未在该分支生效;
+- 日志另见 `会员开通失败: 家庭无归属用户, familyId=5, orderNo=MO_PLAN_001` + `会员开通失败,已回滚为待支付` → 新实现的 fail-fast 与回滚链路已在跑,行为符合预期。
+
+### 10.3 结论修正
+
+| 指标 | 主窗 | **修正后(最终)** |
+|---|---|---|
+| 后端红 | 34 | **28** |
+| 全站红 | 55 | **49** |
+| 全站通过 | 3907 | **3913** |
+| **通过率** | 97.99% | **98.14%(剔 skip 98.76%)** |
+| **G1 门禁** | ❌ | **✅(≥98%)** |
+
+### 10.4 SRS 闸门修正(G12)
+
+- 窗口内 `docs/superpowers/api/API_REFERENCE.md` **有变更**(新增 §4.50.1 `POST /api/membership/plan/purchase`)——此为「接口文档随实现同步」,非新增需求;
+- 对应契约用例(`MembershipPlanPurchaseContractTest` 7 例)**在实现前已契约先行落地**,故 **无需新增用例**,但按纪律已核对「文档 → 用例」一致性:文档 §4.50.1 的五参方法 + 端点与用例断言逐项对应 → **G12 仍 ✅(变更已核对、用例已覆盖)**;
+- 未因该变更触发用例编写闸门(用例数 0 新增)。
+
+---
+
+## 十、下轮前置
 
 **测试侧**
 1. 优先复核 B-184-1:若研发未改慢类/夹具,下轮改用「分批全量(`-Dtest` 按包切片)+ 汇总」策略,保证每轮都能拿到全量逐例结论,不再截断;

+ 2 - 2
docs/tdd/test/blockers.md

@@ -1246,7 +1246,7 @@
 | **B-177-1(第 7 轮,复现)** | 251 pytest 打印 summary 后进程不退出 | 研发/测试(P1) | **复现(独立第 2 次佐证)**。`2 failed, 49 passed in 244.73s` 已打印,但 pid **1915739 `stat=Sl` 存活 07:38** 仍未退出 → `echo EXIT=$rc` 永不执行,日志无 `EXIT=` 行;已 `kill -9` 清理,清理后 `/health` 恢复 200/3.7ms。**再次反证「EXIT 未落盘」非 shell 引号/MSYS 路径问题,而是被测进程挂死。** 修法:产品侧 `await client.aclose()` + 派发器 `timeout -k 10 900`。 | 研发/测试 | 2026-11-13 07:20 | 待处理 |
 | **B-156-1(第 9 轮,未修)** | `nutrition_age_dosage` DDL 三重不一致 | 研发(P1) | **未修**。`schema.sql:5345-5357` 仍含 `INDEX idx_product (product_id)` 而无 `product_id` 列;本轮日志 **2 次** `SQLSyntaxErrorException: Key column 'product_id' doesn't exist in table`;实体 `NutritionAgeDosage.java:33-34` 的 `updateTime` 仍无对应 `update_time` 列。**表仍从未创建成功**。另建议补「关键表存在性契约测试」把静默失败变成红例。 | 研发 | 2026-11-13 07:20 | 待处理 |
 | **B-170-1(第 6 轮,未修)** | `activities.approved_count` 迁移语法非法 | 研发(P2) | **未修**。`DatabaseInitializer.java:2261` 仍为 `UPDATE activities a SET a.approved_count = (SELECT … WHERE r.activity_id = a.id …)`;本轮日志 **2 次** `Unknown column 'a.id' in 'where clause'` → 该列唯一写入点恒失败,持久化列恒 0。 | 研发 | 2026-11-13 07:20 | 待处理 |
-| **S-cfc-168(维持 RED)** | membership.plan.purchase | 研发(TDD/P1) | **维持 7/7 红**(定向复验实测),窗口零提交,连续 14+ 轮未实现(SC-P-58)。 | 研发 | 2026-11-13 07:20 | 待处理 |
+| **S-cfc-168 / S-cfc-176(部分闭环,增量复验)** | membership.plan.purchase | 研发(TDD/P1) | **7F → 1F(6 例转绿)**。窗口末 `ca56f8699 feat(membership): implement membership.plan.purchase (S-cfc-176)` 合入(`MembershipService.purchasePlan` + `findReusablePendingOrder`/`toOrderDTO` + `markMembershipOrderFailed`/`rollbackOrderToPending` + `MembershipController POST /api/membership/plan/purchase` + `API_REFERENCE §4.50.1`);rebase 至 `6d3564510` 后定向复跑 **1F/7**。**剩余 1 红 = `repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201`(`NeverWantedButInvoked: paymentOrderMapper.insert`)→ 同 plan 重复购买未复用 pending 单,幂等分支未生效**,见报告问题 7。 | 研发 | 2026-11-13 07:20 | **部分闭环(6/7)** |
 | **S-cfc-178(第 3 次入全量,维持 RED)** | family.familyMembers.removeMember 缓存重算 | 研发(TDD/P1) | **维持 4F**(定向复验实测 `FamilyRemoveMemberContractTest` 8 例 / 4F),踢出成员后 `users.member_level` 未重算为 FREE(SC-P-06 / API §4.2 member/kick)。 | 研发 | 2026-11-13 07:20 | 待处理 |
 | **B-153-1/B-167-1(销号维持第 19 轮)** | 189 admin 偶发/502 | 测试(观察项) | **维持销号**。189 admin **5/5 EXIT=0**(1.3m),spec blob `4703d73fb` 与本机一致 → 跨节点结论可比。 | 测试(R184 实派) | 2026-11-13 07:20 | 已闭(观察维持) |
 | **B-142-1(销号维持第 15 轮)** | 匿名端点鉴权 | 研发(已闭环) | **维持销号**。本轮扩至 **6 端点 6/6 = 401**(mind/fortune/data、energy/data/current、health/plan/generate、growth/record/list、**admin/families/overview**、huawei-health/status),body 均 `{"code":401,"message":"请先登录"}`。 | 测试(R184 实测) | 2026-11-13 07:20 | 已闭(观察维持) |
@@ -1257,4 +1257,4 @@
 | **B-162-1(第 11 轮,承袭)** | 3 个测试类未入库却被编译执行 | 治理(P1) | **延续**。`GrowthPublicEndpointMappingTest`(5E)、`JwtInterceptorGrowthPolicyTest`、`ArticleTagsContractTest` 仍 `??`;本轮 `testCompile 375 源`(HEAD 372 + 3 未跟踪)。 | 研发/测试 | 2026-11-13 07:20 | 待处理 |
 | **B-173-1/2(承袭)** | safe-delete / API 990 | 测试/CI | B-173-1 本轮全部 Playwright 套件以独立 config/outputDir 规避,**零触发**;B-173-2 沿用点名 4 文件(25 过 / 7 跳 / 0 红),未误跑 990 例。 | 测试(R184 实测) | 2026-11-13 07:20 | 规避中 |
 | **B-124/B-32(度量口径)** | 锚点/场景口径跨轮不可比 | 测试(P2) | **仍未闭环**。本轮改用显式双口径并在报告 §7.1 固化:台账表行 **876** / 唯一 TC **308** / 场景 **152** / 真实锚点 **100**(排除 generated 253)/ 双向命中 **62 = 20.1%** / 孤儿 38 / 空转 246。历史「13.4%(115/861)」「72.1%(155/215)」与本轮口径不可直接相减。 | 测试 | 2026-11-13 07:20 | 待处理 |
-| **R184 门禁** | 全量 3987 / 3907 | 测试 | **不通过(承袭,结构性预期 RED + 环境红未消 + 本轮新增耗时劣化)**。✅G4 116-116/G5 编译 0 错(2121+375)/G6 28-28+2 跳/G8 **6/6 401**/G10 双节点(189 5/5 + 251 51 例)/G12 SRS 零变更;⚠️G3 609-624(3 预期 RED)/G13 13-14 红类逐例一致(TaskReview 1F→2F 装置浮动);❌G1 97.99%(剔 skip 98.61%,且后端为「同源码沿用」混合口径)/G2 55 红/G7 49-51(96.1%)/G9 **20.1%**(62/308)/G11 漏拦 7 陈旧 26/G14 57.9%(88/152)/G16 无 SCA。**变化** = langgraph 48→49(红 3→2)、通过率 97.97%→97.99%(+1 过);**负向** = B-184-1 全量耗时劣化 >2h 致本轮降级为「截断 + 沿用」。 | 测试(R184 闭环) | 2026-11-13 07:20 | 已记录 |
+| **R184 门禁** | 全量 3987 / **3913**(增量后) | 测试 | **不通过(承袭;但 G1 由 ❌ 转 ✅)**。✅**G1 98.14%**(3913/3987,剔 skip 98.76%,增量复验 +6 例后达标,混合口径待全量复核)/G4 116-116/G5 编译 0 错(2121+375)/G6 28-28+2 跳/**G8 6/6 401**/G10 双节点(189 5/5 + 251 51 例)/G12(主窗零变更 + `API_REFERENCE §4.50.1` 已核对、用例零新增);⚠️G3 609-624(3 预期 RED)/G13 13-14 红类逐例一致(TaskReview 1F→2F 装置浮动);❌G2 **49 红**(后端 28 + 根级 16 + lg 2 + fe 3)/G7 49-51(96.1%)/G9 **20.1%**(62/308)/G11 漏拦 7 陈旧 26/G14 57.9%(88/152)/G16 无 SCA。**变化** = 会员购买契约 7F→1F(+6 过)+ langgraph 48→49 → 通过率 97.97%→**98.14%**(+0.17pct),**G1 转 ✅**;**负向** = B-184-1 全量耗时劣化 >2h 致本轮降级为「截断 + 沿用」。 | 测试(R184 闭环) | 2026-11-13 07:20 | 已记录 |

+ 6 - 3
docs/tdd/test/notice-2026-11-13-R184-研发通知.md

@@ -2,7 +2,9 @@
 
 > 来源:测试负责人自动化测试闭环(review 档,内网已授权)
 > 基线:`cfclub @ fcbce94b3`(=origin)。**窗口零源码变更 / 零 SRS 变更**(`git diff fcbce94b3..58671aa7a` 非 docs 命中 0)。
-> 结论:**门禁不通过(承袭)**。本轮相对 R183 的正向只有 1 条(langgraph 红 3→2),但出现 **1 个新的 P1 性能/装置问题(B-184-1)**,它直接导致本轮全量巡检无法完成——请优先处理。
+> 结论:**门禁不通过(承袭),但 G1 已转 ✅**。本轮正向 3 条:① langgraph 红 3→2;② **你们合入的 `ca56f8699`(S-cfc-176 membership.plan.purchase)使会员购买契约 6/7 转绿,全站通过率 97.97%→98.14%**;③ 14 红类逐例可复现(回归网可信)。负向 1 条:**B-184-1(P1)后端全量耗时劣化 5.4×,直接导致本轮全量巡检无法完成**——请优先处理。
+>
+> **增量复验说明**:本报告主体跑测基于 `fcbce94b3`;收尾 fetch 发现 `ca56f8699` 合入 → `pull --rebase` 至 `6d3564510` 后定向复跑 `MembershipPlanPurchaseContractTest` + `FamilyRemoveMemberContractTest`,结论以复验后为准。
 
 ---
 
@@ -31,7 +33,7 @@
 | **P1** | B-177-1(第 7 轮) | pytest 打印 summary 后进程不退出 | 研发/测试 | pid 存活 **7m38s**、无 `EXIT=` 行 → CI 会挂死;修法 `await client.aclose()` + `timeout -k 10 900` |
 | **P1** | B-156-1(第 9 轮) | `nutrition_age_dosage` DDL 三重不一致 | 研发 | `schema.sql:5345` 含 `INDEX idx_product (product_id)` 而无该列 → 表**从未建成**;实体 `updateTime` 亦无对应列 |
 | **P1** | B-170-1(第 6 轮) | `activities.approved_count` 迁移语法非法 | 研发 | `DatabaseInitializer.java:2261` `SET a.col` 带别名 → `Unknown column 'a.id'`;该列唯一写入点恒失败 |
-| **P1** | S-cfc-168 | `membership.plan.purchase` 待实现 | 研发 | `MembershipPlanPurchaseContractTest` **7/7 红**(第 14+ 轮) |
+| **P1** | **S-cfc-176 幂等分支** | 重复购买未复用 pending 单(6/7 已转绿) | 研发 | 增量复验 `MembershipPlanPurchaseContractTest` **1F/7**:`repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201` → `NeverWantedButInvoked: paymentOrderMapper.insert`。修法:`createOrder` 命中 `findReusablePendingOrder` 时直接返回 DTO 并**跳过 insert** |
 | **P1** | S-cfc-178 | `family.familyMembers.removeMember` 缓存重算 | 研发 | `FamilyRemoveMemberContractTest` **4F/8** |
 | **P1** | B-162-1(第 11 轮) | 3 个测试类未入库却被编译执行 | 研发/测试 | `GrowthPublicEndpointMappingTest`(5E) 等仍 `??`;本轮 `testCompile 375 源`(HEAD 372 + 3) |
 | **P2** | B-178-1(第 4 轮) | TaskReviewScP11 反射装置浮动 | 测试 | 1F→2F 无规则波动;建议 `@MockBean` 替代 `ReflectionTestUtils` |
@@ -47,13 +49,14 @@
 | 后端全量 | 76/368 类 | — | 1 类 5E | — | 39m(截断) | 不作全量结论 |
 | 后端 14 红类定向 | 103 | 67 | 35 | 1 | 04:51 | 13/14 类逐例同 R183 |
 | 后端全量(沿用 R183,同源码) | 3111 | 3073 | 34 | 4 | 33:49 | 已标注「沿用」 |
+| 后端增量复验(`6d3564510`,S-cfc-176 合入后) | 15 | 10 | 5 | 0 | 03:17 | 会员购买 **7F→1F**;移除成员维持 4F |
 | cfc-frontend Jest | 624 | 609 | 3 | 12 | 133.59s | 3 全预期 RED |
 | cfc-web Jest | 116 | 116 | 0 | 0 | 120.9s | 全绿 |
 | langgraph@251 | 51 | **49** | **2** | 0 | 244.73s | 红 3→2 |
 | 浏览器 | 30 | 28 | 0 | 2 | 2.3m | 189 admin 5/5 + 本机 fe/shop/health;dx 2 跳 |
 | 线上 API | 32 | 25 | 0 | 7 | 17.1s | 点名 4 文件 |
 | 根级黑盒 | 23 | 7 | 16 | 0 | 13.98s | 9082 未起 |
-| **合计** | **3987** | **3907** | **55** | **25** | — | **97.99%**(剔 skip 98.61%) |
+| **合计(增量复验后)** | **3987** | **3913** | **49** | **25** | — | **98.14%**(剔 skip 98.76%) |
 
 **匿名鉴权 6/6 = 401**(mind/fortune、energy/current、health/plan/generate、growth/record/list、admin/families/overview、huawei-health/status)→ B-142-1 销号维持第 15 轮。
 **站点**:`/admin` 200、`/frontend` 200、`/` 404;dx 两端点 404/404(契约登记未实现,skip 正确)。