Browse Source

test(R224): 后端全量首次实跑 510类/4469例92.12%(真实红17=存量16+P0守卫1) + 越权pin转断言(SC-X-19 403/14-14绿) + 三节点浏览器33过2跳 + R223台账24TC回收

cfc-tester 5 hours ago
parent
commit
19bd9e5c0c

+ 69 - 0
docs/tdd/orchestration/notice-2026-11-16-R224-研发通知.md

@@ -0,0 +1,69 @@
+# 研发通知 · R224(2026-11-16 01:xx GMT+8)
+
+> 发起:测试负责人(软件测试专家团 · 测试架构师)|执行档:review(离线白名单)+ 内网三节点浏览器 E2E 实跑
+> 基线:`origin/cfclub` **`3ff62e324`**,本轮窗口 **0 新增提交**(R223 基线即该提交),零 SRS/场景变更
+
+## 一、需要研发处置(按优先级)
+
+### 1) 🟢 已闭环(无需处置,仅告知):SC-X-19 跨家庭越权读取已被修复
+- **实现**:`EnergyController#overview`(`cfc-backend/src/main/java/com/etotem/cfc/controller/EnergyController.java:174`)在 `d39aa5282`(S-cfc-390 `energy.ledger.guard`)加入归属校验:
+  ```java
+  if (!memberId.equals(currentMemberId) && !energyService.isMemberInFamily(memberId, familyId)) {
+      return Result.forbidden("无权访问该成员的能量数据");
+  }
+  ```
+- **测试侧已同步**:`tests/e2e/api/dimension-energy-contract.spec.js` 原「观察钉住」用例断言旧缺陷行为(跨家庭 `memberId=999999` → 200),实现修复后该用例长期假红;本轮改为断言 `code=403 / message 含「无权访问」/ 不返回能量数据` → 复跑 **14/14 绿**。
+- **给研发的提示**:新增「观察钉住(pin)」用例时请在规格或注释写明「缺陷修复后转断言」的责任人,避免 pin 变成长期噪声。
+
+### 2) 🔴 P1(流程)R223 派生用例台账未入库,已由测试侧回收
+- R223 声明派生 24 条行为级用例(`shop.review.detail` / `shop.review.my` / `shop.order.receiptTimeout`),但文件 `tests/test-cases/2026-11-16-review-detail-my-receipt-timeout.md` 只提交在本地分支 `fix/scenario-coverage`(`c1f20bc2a`),**未进 `origin/cfclub`**。
+- 本轮已随报告一并入库(资产回收)。**请研发/测试在推送时以 `origin/cfclub` 为唯一事实源**,避免台账断层导致 G12 追溯失真。
+
+### 3) 🔴 P0(环境)251 节点 langgraph 仍有 8 例环境型红(AgnesAI 免费配额 429)
+- 251(`3ff62e324`,与本轮基线同版)`pytest tests --ignore=tests/qna --ignore=tests/test_chat.py`:
+  **43 例 / 35 过 / 8 红 / 107.37s**,红集 = `test_auto_tag` ×4 + `test_intent` ×4。
+- 日志:`RateLimitError("Error code: 429 ... You've reached the API rate limit for free users ... AgnesAI_error")`;`app/middleware.py:113`;intent 分类器 429 后兜底 `chat` 导致 4 条意图断言失败。
+- **处置**:给 251 的 LLM 凭据升级 Token Plan 或轮换有配额 key(**不是改测试断言**)。
+- 补充:`intent_classifier.py` 在 429 时应显式失败/重试,而不是静默兜底 `chat` —— 静默兜底会把「上游不可用」伪装成「分类错误」,掩盖真实故障。
+
+### 4) 🔴 P1(装置 + 数据安全,本轮最重要)后端测试直连共享库 251:3306/zxyj,且每个 Spring 上下文重跑全量迁移
+- **事实链**:
+  1. `cfc-backend/src/test/resources/` **不存在**(`ls -d` 报 No such file)→ 测试无独立测试配置,直接落到 `src/main/resources/application*.yml`;
+  2. 该配置数据源为 **`jdbc:mysql://192.168.16.251:3306/zxyj`**(`createDatabaseIfNotExist=true`,两处 profile 同值)→ 即 **251 上的共享库**;
+  3. 测试启动日志 `wechat.test-mode=true in non-production profile (dev)` → 以 `dev` profile 读写该共享库;
+  4. 每次 `@SpringBootTest` 新建上下文都会跑 `DatabaseInitializer` 全量迁移:日志 `DatabaseInitializer` 输出 **24987 行**、已观察 **25+** 次上下文启动;`schema.sql` 含 **433** 条 DDL、`DatabaseInitializer` 有 **650** 处迁移段;
+  5. `jstack` 抓主线程:`main` RUNNABLE 阻塞在 `java.net.SocketInputStream.socketRead0` → `com.mysql.cj.protocol.ReadAheadInputStream` → **正在等 251 的 MySQL 网络往返**。
+- **后果**:① 全量 JUnit 从 40min 劣化到 >2h(per-class 20~200s,绝大部分耗在网络 DDL 往返);② **测试数据写进共享库**,与线上/演示数据混用,存在污染与误删风险;③ 并行会话同时跑测试时会互相锁表,表现为「随机卡在某类几分钟」。
+- **建议**(按性价比排序):
+  1. 新增 `cfc-backend/src/test/resources/application-test.yml`:指向本地 MySQL/H2 + `spring.datasource.hikari.maximum-pool-size` 调小 + 关闭自动迁移(`migration.enabled=false`),schema 由一次性 `@Sql`/`schema-test.sql` 建;
+  2. 新增 `src/test/resources/logback-test.xml`,把 `com.etotem` 降到 `WARN`(本轮日志 **14.6MB**,绝大部分是 MyBatis DEBUG SQL);
+  3. `DatabaseInitializer` 迁移加「同 JVM 只跑一次」静态闸(`AtomicBoolean`/`@PostConstruct` 单例),避免每上下文重跑;
+  4. controller 层用例改 `@WebMvcTest`,service 层用切片测试。
+- **验收**:连续 2 轮全量 ≤40min、类数/例数不变、且测试不再连 `192.168.16.251:3306`。
+
+### 5) 🟡 P2(CI)`backend-blocking-junit` 清单继续失真(G11 第 26 轮)
+- CI `BACKEND_OBSERVED_CLASSES` 仍为 33 类固定清单;本轮实测确定性红类与契约前瞻红类叠加后远超清单,**清单内多个类实际已全绿**(陈旧),清单外仍有确定性红(漏拦)。
+- **处置**:把清单改为「由 surefire 结果自动生成」,或改为 `-Dtest=!<动态清单>` + 契约前瞻类打 `@Tag("forward-contract")` 单独跑 observed。
+
+### 6) ⚪ P3(节点)189 代码版本落后
+- 189 `c:/code/cfc` HEAD = `1e3bea680`,落后 `origin/cfclub`(`3ff62e324`);但 `admin-live.spec.js` blob = `4703d73fb`(与本机同版),故本轮 189 的 5/5 结论**跨节点可比**。
+- **处置**:189 定期 `git pull --ff-only`(`cfclub` 被其他 worktree 占用时改用 `git -C` 指定 worktree 或直接 fetch+reset)。
+
+## 二、本轮无需处置但需知晓
+
+- 线上匿名 6 端点 **6/6 = 401**(`/api/mind/overview`、`/api/energy/balance`、`/api/health/plan/list`、`/api/xiaomi-health/status`、`/api/huawei-health/status`、`/api/admin/families`)→ 鉴权面稳定。
+- `/admin` 与 `/frontend` 均 302(未登录跳转),`/` 404 —— 属预期。
+- D/X 桥接两端点仍 404(`/api/health/data-sources/bridge/{list,sync-status}`,第 58 轮)——规格 `2026-11-08-dx-health-bridge.md:5` 明示「仅登记不实现」,非缺陷;建议在规格中标注 `blocked: pending implementation` 以免每轮重复判读。
+
+## 三、复测方式(研发修复后请按此复跑)
+
+```bash
+# 1) 越权隔离(已绿,回归用)
+cd tests && node node_modules/@playwright/test/cli.js test -c playwright.config.api.js api/dimension-energy-contract.spec.js
+
+# 2) langgraph(251 节点本机执行,注意不要写成「在 251 节点执行」触发 agent ssh 自身)
+cd /sc-data/cfc/cfc-langgraph && timeout 900 .venv/bin/python -m pytest tests --ignore=tests/qna --ignore=tests/test_chat.py -q
+
+# 3) 后端全量(建议先在 cfc-backend 加 application-test.yml 再跑,否则 2h+)
+cd cfc-backend && mvn -o -B test
+```

+ 240 - 0
docs/tdd/orchestration/report-test-2026-11-16-R224.md

@@ -0,0 +1,240 @@
+# 测试负责人工作汇报 R224(2026-11-16 01:30 GMT+8 · 自动化闭环)
+
+> 测试负责人:陆谨(软件测试专家团 · 测试架构师)|执行档:**review(离线白名单)** + 内网三节点浏览器 E2E 实跑 + 远程节点派发(251 langgraph / 189 admin)
+> 静默无人值守,全程未提问(按用户指令:不提问、静默完成);方案假设已在 §2 声明
+> 基线:`origin/cfclub` **`3ff62e324`**(HTTP 通道 fetch);本轮窗口 **0 新增提交**(R223 基线即该提交)→ **零 SRS / 零场景 / 零 src 变更**
+
+## 0. 历史审查记录(对照,非本次结论依据)
+
+| 项 | 内容 |
+|---|---|
+| 上次审查 | **R223(2026-11-16 00:29)**,结论「不通过(有条件)」;基线 `3ff62e324`;lg@251 31/8(去 test_graph);后端全量**未重跑**(仅 test-compile);可验证子集 895 例 95.20% |
+| 本次 | **第 224 轮,非首次审查**;基线同上(本轮窗口零提交),全部套件**重新取证** |
+| 遗留 → 本次状态 | **B-223-1(lg 8 红 429)→ 复现 8 红(同集,环境型,观察 2/3)**;**B-218-1(P0 Bean 撞名)→ 本轮全量实测确认仍未修(`ResourceBeanNameCollisionGuardTest` 1/1 红,第 4 轮)**;B-218-3(线上 502)→ 首跑即 13/13,未复现(观察 2/3);B-36(根级 16 红)→ 承袭;B-DX-1(dx 2 跳)→ 第 58 轮;B-221-4(189 HEAD 落后)→ 仍落后 `1e3bea680`;**G11(CI 清单失真)→ 仍未修(第 26 轮)** |
+| 本次新增 | **B-224-1(P2 工具)** 251 派发提示词写「在 251 节点执行」→ agent 尝试 ssh 到 251 自身,首派 15min 内无产出;**B-224-2(P1 测试资产)** 观察钉住(pin)用例在缺陷修复后未转断言 → 稳定假红(已修);**B-224-3(P1 流程)** R223 台账 24 条 TC 未入 `origin/cfclub`(已回收);**B-224-4(P2 性能)** 后端全量耗时劣化 + 日志 14.6MB DEBUG 噪音;**B-224-5(P2)** langgraph pytest summary 后进程不退出(第 22 轮) |
+
+> 历史记忆只作对照;本轮**全部套件重新取证**,未直接复用任何历史结论。
+
+---
+
+## 1. 执行总览
+
+| 套件 | R224(本轮) | R223(上轮) | 漂移 |
+|---|---|---|---|
+| 基线 | `3ff62e324`(窗口 **0 提交**) | `3ff62e324`(窗口 +28) | 无漂移 |
+| 浏览器 E2E · admin(本机) | **5/5**(1.3m) | 5/5(2.3m) | 一致 |
+| 浏览器 E2E · frontend(本机) | **6/6**(48.6s) | 6/6(48.5s) | 一致 |
+| 浏览器 E2E · admin(189) | **5/5 EXIT=0**(1.1m,spec blob `4703d73fb` = 本机) | 5/5 | 一致(B-221-4 承袭) |
+| 浏览器 E2E · shop-api | **4/4**(7.2s) | 4/4 | 一致 |
+| 浏览器 E2E · health | **13/13 首跑即全绿**(4.2s) | 13/13 | 一致(B-218-3 未复现) |
+| 浏览器 E2E · dx-bridge | **2 跳**(404,第 58 轮) | 2 跳 | 一致 |
+| 线上 API(点名 4 文件) | **36 例 / 33 过 / 0 红 / 3 跳**(39.1s+31.9s) | 32 例 25/0/7 | **红 1→0**(pin 转断言,B-224-2 已闭环) |
+| cfc-web Jest | **124 过 / 10 红 / 134**(21 套,20.4s) | 124/10/134 | **逐例零漂移** |
+| cfc-frontend Jest | **644 过 / 4 红 / 12 跳 / 660**(46 套,16.5s) | 644/4/12/660 | **逐例零漂移** |
+| 根级黑盒 Jest | **7 过 / 16 红 / 23**(5.6s) | 7/16/23 | 一致(B-36 第 100 轮) |
+| langgraph@251 | **43 例 / 35 过 / 8 红**(107.37s,`timeout` 兜底 EXIT=124) | 31/8(39 例,去 test_graph) | **口径扩大至全量 43 例**;红集同型(429) |
+| 后端 · test-compile | **BUILD SUCCESS**(517 测试源文件,03:01) | SUCCESS(515,3m58s) | 一致 |
+| 后端 · 全量 | **510 类 / 4469 例 / 4113 过 / 352 红(341F+11E)/ 4 跳 = 92.12%**(剔 skip 92.20%;剔 335 契约前瞻 = **99.62%**),`Total time: 51:50` | 未重跑(承采 R221) | **本轮首次实跑** |
+
+**全站合计(本轮全部实测,无承采)**:**5400 例 / 4989 过 / 390 红 / 21 跳 = 92.73%**(剔 skip **93.09%**;剔 349 预期红 = **99.24%**)
+- 390 红三层归因:**契约前瞻 RED 349**(后端 335 + web 10 + fe 4,TDD 先行、实现未落地)+ **存量装置缺陷 16**(8 类,逐类逐例与历史一致 → **零漂移第 36 次**)+ **守卫新增 1**(`ResourceBeanNameCollisionGuardTest` = B-218-1 P0 未修)+ **环境型 24**(根级 ECONNREFUSED 9082 ×16 + lg 429 ×8)
+- **真实产品缺陷红 = 17(后端 16 存量 + 1 P0 守卫)**;非后端 38 红中 0 例确定性产品回归
+- **双节点浏览器合计**:本机 28 过 + 2 跳 + 189 admin 5 过 = **33 过 + 2 跳**
+
+**SRS 闸门(G12)**:`docs/superpowers/specs` **204** 份、`tests/test-cases` **21** 份、`tests/user-scenarios` **11** 份,窗口**零变更** → 本轮 0 条新增用例。
+但 R223 声明的 24 条能力键用例(`shop.review.detail` / `shop.review.my` / `shop.order.receiptTimeout`)**未入 origin**(仅存于本地分支 `fix/scenario-coverage`)→ 本轮**资产回收入库**,恢复可追溯性。
+
+**测试结果有变化(R223 → R224)— 触发提交 + 通知研发**
+- 🟢 **SC-X-19 越权缺口闭环并转断言**:`EnergyController.java:174` 归属校验(`d39aa5282` S-cfc-390)已生效,跨家庭 `memberId` 由 200 → **403「无权访问该成员的能量数据」**;测试侧把「观察钉住」改为断言 → `dimension-energy-contract.spec.js` **14/14 绿**。
+- 🟢 **线上 API 点名子集红 1→0**(33/0/3)。
+- 🔴 **langgraph 8 红复现**(AgnesAI 免费配额 429,第 3 轮同型)→ 环境型,非回归。
+- 🟡 **R223 台账资产回收**(24 条 TC 入库)。
+- 🟡 **后端全量首次实跑**(R223 未做),口径见 §1 与 §7。
+
+---
+
+## 2. 项目画像(本轮视角)
+
+- **业务定位**:家庭教育 SaaS(五维能量 · 成长规划 · 测评订单 · 商城 · 健康报告解析 · 家庭工作台 · AI 教练),双端:小程序 H5 `cfc.iwintrue.com/frontend` + Web 管理端 `cfc.iwintrue.com/admin`。
+- **技术栈**:`cfc-backend` Spring Boot 2.7.18 / MyBatis-Plus / JDK 1.8(9082)· `cfc-web` Vue2 + Element UI(8082)· `cfc-frontend` uni-app 小程序(H5 预览)· `cfc-langgraph` FastAPI + LangGraph + ChromaDB(251 节点)· `dan/danshop` 独立商城(8888)。
+- **关键路径(本轮取证对象)**:登录/鉴权(JwtInterceptor 401 闸门)→ 家庭与成员 → 五维能量(overview/logs/grant/deduct + 账本守卫)→ 成长规划(plan/confirm/submit/tasks)→ 商城评价(create/detail/my)与订单收货超时 → 后台管理(用户/家庭/看板)→ AI 会话/意图/打标。
+- **测试资产现状**:后端测试源 **517** 文件、`@Test` **4454**、契约类 **237**;Playwright spec **80**(live 4 + api + func);Jest 两套(web 21 / fe 46);langgraph pytest 10 文件;用例台账 **21** 份(TC 表行 988);用户场景 **11** 份(SC 标识 **244**)。
+- **质量目标(用户口径)**:所有测试用例全部覆盖并通过对;用例覆盖全部 SRS 与用户场景(含异常流);SRS/场景变更时同步更新用例。
+- **本轮风险点**:① 后端测试**直连共享库 251:3306/zxyj** 且每上下文重跑全量迁移(51:50 耗时主因,B-224-4,兼数据污染风险);② langgraph 上游配额不稳定(429);③ CI 清单与真实红集持续失真(G11);④ B-218-1 P0 `@Resource` Bean 撞名仍未修(守卫用例 1 红)。
+
+---
+
+## 三、20 类测试覆盖矩阵
+
+| # | 测试类型 | 层次 | 状态 | 证据(本轮实测) |
+|---|---|---|---|---|
+| 1 | 单元测试 | 功能层次 | **已发现** | 后端 517 测试源 `test-compile` 成功;web 21 套 134 例、fe 46 套 660 例实跑 |
+| 2 | 组件测试 | 功能层次 | **已发现** | web views 级契约(Families/FamilyWorkbench 3 套)× fe pages 级(growth/shop 等)实跑 |
+| 3 | 集成测试 | 功能层次 | **已发现(全量实跑)** | `integration/**` 全部执行并产出 XML;红 2 类(EnergySystemFlow 6F / GuideModuleIntegration 1E,均为存量)|
+| 4 | 契约测试 | 功能层次 | **已发现(红集主体)** | 后端 237 契约类;契约红 **60 类 / 335 例**(前瞻 RED);web 10 + fe 4 同型;**越权契约 SC-X-19 已由红转绿(403 断言)** |
+| 5 | 接口 API 测试 | 功能层次 | **已发现** | 线上点名 4 文件 **36 例 33 过 3 跳**;shop 4/4;health 13/13(401 契约) |
+| 6 | 系统/端到端 | 功能保障 | **已发现(实跑)** | 本机 28 过 + 2 跳、189 admin 5 过(spec blob 同版)= 33 过 + 2 跳 |
+| 7 | 验收 UAT | 功能保障 | **部分已发现** | 场景文件 11 份 / SC 244;无人工 UAT 签署记录 |
+| 8 | BDD 规格 | 功能保障 | **未发现** | 全仓 `.feature` = 0(`find -name *.feature` 命中 0)→ 缺口 |
+| 9 | 冒烟测试 | 功能保障 | **已发现** | `playwright.config.smoke.js` 存在;线上 api-smoke 4/4 绿 |
+| 10 | 回归测试 | 功能保障 | **已发现** | web/fe/浏览器/线上 API 逐例对照**零漂移**;后端已执行段红集与历史存量集一致 |
+| 11 | 探索性测试 | 功能保障 | **未发现** | 无人值守窗口不做 chartered 探索(无 charter/记录) |
+| 12 | 性能测试 | 非功能 | **未发现(未实测)** | 无 k6/JMeter;`nonfunc-perf-compat.spec.js` 仅 7 例接口冒烟(已跑绿);execute 档未授权 → **不写通过** |
+| 13 | 可靠性测试 | 非功能 | **部分已发现** | lg 429 环境型(B-223-1/B-224 观察 2/3);health 首跑全绿;无故障注入 |
+| 14 | 安全测试 | 非功能 | **部分已发现** | 匿名 6 端点 6/6=401;`nonfunc-security.spec.js` 11/11 绿;跨家庭越权 403 断言;**无 SAST/依赖扫描(未授权联网)** |
+| 15 | 兼容性测试 | 非功能 | **部分已发现** | `nonfunc-perf-compat` 多端 UA 兼容 7 例绿;浏览器矩阵仅 Chromium 双视口 |
+| 16 | 可用性测试 | 非功能 | **未发现** | 无 SUS/任务完成率记录 |
+| 17 | 无障碍测试 | 非功能 | **未发现(有实现无断言)** | admin 密度四期 §8.F 无障碍补修(`233bb4634`/`1f4e8cac1`)**无 axe/WCAG 自动化断言** → 缺口 |
+| 18 | QA 流程 | 度量与流程 | **部分已发现** | 三节点 E2E 互备 + 派发;**251 派发提示词缺陷(B-224-1)已自处置**;CI 清单失真(G11 第 26 轮) |
+| 19 | 质量指标 | 度量与流程 | **已发现** | 通过率/红例/契约红比/场景映射四指标本轮刷新(§1、§7) |
+| 20 | 全项目代码审查 | 度量与流程 | **部分已发现** | 窗口零 src 变更 → 无新增代码可审;仅复核 `EnergyController` 越权实现与 `DatabaseInitializer` 迁移噪音(§7 B-224-4) |
+
+---
+
+## 四、覆盖缺口清单
+
+| 缺口类型 | 现状 | 风险 | 建议测试设计 | 优先级 | 闭环方式 |
+|---|---|---|---|---|---|
+| 后端全量耗时劣化 | 510 类 / 51:50(R221 505 类 / 40:06,+29%) | 回归反馈周期长,G1 难每轮实跑 | 加 `application-test.yml` 关迁移 + `logback-test` 降级 + 治理 DEBUG 日志 | P1 | 连续 2 轮 ≤40min 即闭环(B-224-4) |
+| BDD 规格 | 无 `.feature` | 需求↔用例可追溯弱 | 对 SC-P-44/45、SC-P-47 补 Gherkin | P2 | 下迭代引入 cucumber |
+| 探索性测试 | 无 charter | 未知缺陷盲区 | 每迭代 1 次 chartered 探索并留记录 | P2 | 人工窗口补 |
+| 性能/可靠性 | 无压测/故障注入 | 容量与恢复未知 | k6 打 `/api/energy/overview` + `/api/family/member/list` | P1 | 需用户授权联网(execute 档) |
+| 无障碍 | 有实现无断言 | 回归不可感知 | axe-core 扫 admin 5 页 + fe 3 页 | P2 | 补 `a11y.spec.js` |
+| 兼容性 | 单浏览器双视口 | 跨端渲染风险 | 增 Firefox/WebKit project | P3 | 加 project 即闭环 |
+| CI 清单失真 | 33 类固定清单 | 门禁必红 + 漏拦 | 由 surefire XML 自动生成清单 | P1 | G11 闭环判据:清单=实测红集 |
+| 场景 L3 链接 | 用例层 SC 引用 158/244 = 64.8% | 场景覆盖低估 | 「所属场景」列格式归一 | P1 | rollup 归一后自动上升 |
+
+---
+
+## 五、域结论表
+
+| 审查维度 | 负责专家 | 结论 | 关键证据 |
+|---|---|---|---|
+| 单元·组件级 | 苏雅 | **部分通过** | web 124/134(10 契约 RED)、fe 644/660(4 契约 RED)、后端 test-compile SUCCESS;后端后段类未跑完 |
+| 集成·接口级 | 柯砚 | **通过** | 线上 API 33/0/3;shop 4/4;health 13/13;已执行 integration 段仅 2 类存量红 |
+| 系统·验收级 | 白樾 | **通过(可验证子集)** | 本机 28+2 跳、189 5/5(spec 同版);双 URL 11/11 全绿 |
+| 测试保障级 | 闻朔 | **部分通过** | 冒烟/回归零漂移;探索性缺 charter |
+| 性能·可靠性 | 骆骋 | **部分通过(未实测压测)** | 后端耗时劣化证据链(B-224-4);lg 429 复现;无压测 |
+| 安全 | 关屿 | **通过(接口面)** | 匿名 6/6=401;越权 403 断言闭环;无 SAST(未授权) |
+| 兼容·体验 | 阮清 | **部分通过** | 多端 UA 7/7;单浏览器、无 a11y 断言 |
+| 流程·度量·代码 | 何序 | **部分通过** | 台账 988 行/SC 64.8%;CI 清单失真;窗口零 src 故无新增代码审查面 |
+
+---
+
+## 六、五要素问题清单
+
+**问题 1(B-224-2,P1 测试资产,已闭环)观察钉住用例未随实现修复转断言 → 稳定假红**
+- ① 问题描述:`tests/e2e/api/dimension-energy-contract.spec.js` 的 `_pinsObserved` 用例断言「跨家庭 `memberId=999999` 返回 200(无归属校验)」;该缺口已于 `d39aa5282` 修复,用例因此**每轮必红**,且与真实回归混在同一红色池中。
+- ② 测试 bug 点:`tests/e2e/api/dimension-energy-contract.spec.js:154-158`(原 `expect(r.code).toBe(200)`)。
+- ③ 最优修改方案:pin 转断言——改为 `expect(r.code).toBe(403)` + `message` 含「无权访问」+ `data` 为空;describe 更名「越权隔离(SC-X-19)」(已实施)。
+- ④ 修改目的:把「记录缺陷」的用例升级为「守护修复」,消除假红、恢复该文件 100% 通过。
+- ⑤ 闭环:复跑 `dimension-energy-contract.spec.js` → **14/14 绿**(31.9s),已闭环。
+
+**问题 2(B-224-1,P2 工具,已自处置)251 派发提示词致 agent ssh 自身**
+- ① 问题描述:首派提示词为「请在 251 节点执行以下 shell 命令」,而 opencode 服务本身就跑在 251 → agent 反复尝试 `ssh 192.168.16.251` 并思考 8 分钟,15min cap 内只拿到中间态,误判为「节点不可用」。
+- ② 测试 bug 点:`_r224_251_lg.cjs` 提示词首行(派发脚本层,非产品代码)。
+- ③ 最优修改方案:提示词改为「**你在本机直接执行以下命令(不要 ssh、不要连其他节点)**」;模型固定 `etotem/deepseek`(`/api/model` 校验 `status=active` 后才派发)。
+- ④ 修改目的:消除节点=执行机的语义混淆,保证派发结果可确定性取回。
+- ⑤ 闭环:修正后首派即取回完整 summary(43 例 35 过 8 红 / 107.37s)。**注:首个会话实际在 16min 后自行成功**,故判「延迟成功」而非失败,但仍须改提示词以免每轮浪费 15 分钟。
+
+**问题 3(P0 环境)langgraph 8 红为上游 429,非产品缺陷**
+- ① 问题描述:43 例中 `test_auto_tag` ×4、`test_intent` ×4 失败;红集与 R223 完全同型。
+- ② 测试 bug 点:`cfc-langgraph/app/middleware.py:113` 捕获 `RateLimitError 429 AgnesAI_error`;`app/agents/intent_classifier.py` 429 后兜底 `chat` → 4 条意图断言被联动打红。
+- ③ 最优修改方案:运维为 251 升级 Token Plan / 轮换有配额 key;研发把 429 改为「显式失败 + 可重试」,**不静默兜底**。
+- ④ 修改目的:区分「上游不可用」与「分类错误」,恢复 AI 域可验证性。
+- ⑤ 闭环:配额恢复后 251 连跑 2 轮 43/43 全绿 → 销 B-223-1(当前观察 2/3)。
+
+**问题 4(B-224-4,P1 装置 + 数据安全,本轮最重要)后端测试直连共享库 251:3306 且每上下文重跑全量迁移**
+- ① 问题描述:`mvn -o -B test` 全量 **510 类 / 4469 例 / 51:50**;`controller`/`integration` 段 20~150s/类、`service` 段 100~200s/类;日志体积 **14.6MB**,`DatabaseInitializer` 输出 **24987 行**、Spring 上下文启动 **25+** 次;`jstack 8060` 显示 `main` 线程 RUNNABLE 阻塞于 `SocketInputStream.socketRead0 → com.mysql.cj.protocol.ReadAheadInputStream`,即**在等远端 MySQL 网络往返**。
+- ② 测试 bug 点:`cfc-backend/src/test/resources/` **不存在**(无 `application-test.yml`/`logback-test.xml`)→ 测试直接继承 `src/main/resources/application*.yml:22,47` 的 **`jdbc:mysql://192.168.16.251:3306/zxyj`(createDatabaseIfNotExist=true)**,以 `dev` profile 读写共享库;每次 `@SpringBootTest` 新建上下文重跑 `schema.sql`(433 条 DDL)+ `DatabaseInitializer`(650 处迁移段)。
+- ③ 最优修改方案:① 新增 `src/test/resources/application-test.yml`(本地 MySQL/H2 + 关闭自动迁移,schema 由一次性 `schema-test.sql`/`@Sql` 建);② 新增 `logback-test.xml` 把 `com.etotem` 降 `WARN`(当前 MyBatis DEBUG SQL 全落盘);③ `DatabaseInitializer` 加「同 JVM 只跑一次」静态闸;④ controller 用例改 `@WebMvcTest`。
+- ④ 修改目的:把全量回归压到 CI 可承受窗口(目标 ≤40min),同时**消除测试对共享库的写入**(当前测试会向 251 的 `zxyj` 造用户/订单/家庭数据,存在污染与误删风险)。
+- ⑤ 闭环:连续 2 轮全量 ≤40min、类数/例数不变(510/4469±),且进程内不再出现 `192.168.16.251:3306` 连接 → 销号。
+
+**问题 5(B-224-3,P1 流程)R223 用例台账未入 origin**
+- ① 问题描述:R223 报告声明派生 24 条 TC 并写入 `tests/test-cases/2026-11-16-review-detail-my-receipt-timeout.md`,但该文件仅存在于本地分支 `fix/scenario-coverage`(`c1f20bc2a`),`origin/cfclub` 无此文件 → 台账断层。
+- ② 测试 bug 点:`tests/test-cases/2026-11-16-review-detail-my-receipt-timeout.md`(69 行)在 origin 缺失。
+- ③ 最优修改方案:随本轮报告提交入库(已实施);推送以 `origin/cfclub` 为唯一事实源。
+- ④ 修改目的:恢复 G12 可追溯性(SRS 变更 → 用例 → 执行结果闭环)。
+- ⑤ 闭环:`git ls-tree origin/cfclub tests/test-cases/` 命中该文件即闭环。
+
+**问题 6(G11,P1 流程,第 26 轮)CI 排除清单与实际红集双向失真**
+- ① 问题描述:`.gitlab-ci.yml:61` 固定 33 类 `BACKEND_OBSERVED_CLASSES`;清单外仍有确定性红(漏拦),清单内多类已全绿(陈旧)→ `backend-blocking-junit` 长期必红,门禁失效。
+- ② 测试 bug 点:`.gitlab-ci.yml:61`(静态清单)+ `145-170`(blocking job 依赖该清单)。
+- ③ 最优修改方案:清单由 surefire XML 自动生成纳入仓库(`ci/gen-observed-classes.sh`),或契约前瞻类统一 `@Tag("forward-contract")` 后 blocking 用 `-Dgroups='!forward-contract'`。
+- ④ 修改目的:让 CI 红=真实回归,恢复阻断门禁的可信度。
+- ⑤ 闭环:连续 2 轮 CI blocking 绿且清单与实测红集差集为 0。
+
+**问题 7(B-218-1,P0 仍未修,第 4 轮)`@Resource` 字段名撞 Bean 名 → 运行期 `BeanNotOfRequiredTypeException`**
+- ① 问题描述:`ResourceBeanNameCollisionGuardTest` 本轮全量实跑 **1/1 红**;`CoachRecommendService.java:71-72` 字段 `dimensionScoreService`(类型 `FamilyMemberDimensionBaseScoreService`)与 `DimensionScoreService` 的默认 Bean 名相同,`@Resource` 先按名解析 → 类型不匹配抛 `BeanNotOfRequiredTypeException`,使依赖该链路的 `@SpringBootTest` 上下文启动失败(R203 已确认是线上 `d363df8056` 回滚真因)。
+- ② 测试 bug 点:`cfc-backend/src/main/java/com/etotem/cfc/service/CoachRecommendService.java:71-72`;守卫用例 `src/test/java/com/etotem/cfc/unit/ResourceBeanNameCollisionGuardTest.java`。
+- ③ 最优修改方案:字段加显式限定(`@Resource(name = "familyMemberDimensionBaseScoreService")`)或改名 `familyMemberDimensionBaseScoreService`;同步排查同类第二处(`HealthDataSourceBridgeService.dimensionScoreService`)。
+- ④ 修改目的:消除启动期 Bean 解析失败,恢复 49 个 `@SpringBootTest` 类的可判定性,避免线上回滚复现。
+- ⑤ 闭环:守卫用例转绿 + 全量 `mvn -o -B test` 中 `BeanNotOfRequiredTypeException` 出现次数 = 0 → 销号。
+
+---
+
+## 七、门禁结论
+
+**结论:不通过(有条件)**
+
+- ✅ **G3 浏览器 E2E**:本机 28 过 + 2 跳、189 admin 5/5(spec blob 同版)= 33 过 + 2 跳
+- ✅ **G4 可构建**:后端 `test-compile` BUILD SUCCESS(517 测试源,03:01)
+- ✅ **G5 surefire 覆盖**:已执行类 510/510 全部产出 XML,无沉默类
+- ✅ **G6 浏览器不回归**:双节点、双 URL、spec 同版,逐例通过
+- ✅ **G8 鉴权面**:匿名 6 端点 6/6 = 401
+- ✅ **G10 节点可用**:本机 + 189:4090(200)+ 251:4096(200)
+- ✅ **G12 SRS 同步**:窗口零 SRS/场景变更 → 0 新增;R223 台账 24 TC 已回收入库
+- ⚠️ **G1 通过率**:全站 **5400 例 / 4989 过 / 390 红 / 21 跳 = 92.73%**(剔 skip 93.09%;**剔 349 预期红 = 99.24%**)→ 未达「全部通过」,但**真实缺陷红仅 17**(后端 16 存量 + 1 P0 守卫)
+- ⚠️ **G2 实红**:390 = 契约前瞻 349 + 存量 16 + 守卫 1 + 环境 24;**非契约非环境红 17**,与 R221 逐类逐例一致(零漂移)
+- ⚠️ **G7 AI 域**:35/43(8 红=429 环境型,观察 2/3)
+- ✅ **G13 零漂移(第 36 次)**:后端 8 类存量红(WebConfigGrowthExcludeRemoved 2E / EnergySystemFlow 6F / GuideModuleIntegration 1E / OrchestrationEngine 1F / OrchestrationIntegration 1F / MembershipPaySwitch 1F / PaymentServiceORDRouting 1F / UserServiceWechatLogin 3E)逐类逐例与 R221/R213 一致;web 10 + fe 4 契约 RED 逐例一致
+- ❌ **G9 / G14 覆盖**:用例层 SC 引用 158/244 = **64.8%**;BDD/探索/性能/可用性/无障碍 5 类未覆盖
+- ❌ **G11 CI 门禁**:清单 33 类 vs 实测红类 **69** → **漏拦 + 陈旧**双向失真(第 26 轮未修)
+
+**不通过原因**:① 用户目标「所有用例全部覆盖并通过」未达成(390 红:349 契约前瞻 + 17 真实缺陷 + 24 环境);② 「覆盖全部 SRS + 场景」未达成(SC 用例层 64.8%,BDD/探索/性能/可用性/无障碍 5 类空缺);③ CI 门禁失真使「回归可信」无法外部证明。
+
+**复评条件(4 项全绿才可转「通过」)**
+1. 后端 17 例真实缺陷红(含 B-218-1 P0 Bean 撞名)修复,且装置改造后全量 ≤40min;
+2. langgraph 251 连续 2 轮 43/43(销 B-223-1);
+3. web 10 + fe 4 契约 RED 由研发实现转绿;
+4. CI 清单与实测红集差集为 0(销 G11)。
+
+---
+
+## 附录 A:本轮命令(可复现)
+
+```bash
+# 后端(隔离 worktree,避免主工作区 20+ 未跟踪文件污染)
+git worktree add .worktrees/test-lead-R224 --detach 3ff62e324
+cd .worktrees/test-lead-R224/cfc-backend
+mvn -o -B test-compile          # BUILD SUCCESS 03:01(517 测试源)
+mvn -o -B test                  # 全量 510 类 / 4469 例,Total time: 51:50
+
+# 浏览器(每节点单任务,串行)
+cd tests && node node_modules/@playwright/test/cli.js test -c playwright.config.live.js --project=admin-desktop
+node node_modules/@playwright/test/cli.js test -c playwright.config.live.js --project=frontend-mobile
+node node_modules/@playwright/test/cli.js test -c playwright.config.live.js --project=shop-api --project=dx-bridge
+node node_modules/@playwright/test/cli.js test -c playwright.config.health.js
+
+# Jest
+cd cfc-web && node node_modules/jest/bin/jest.js --ci --silent
+cd cfc-frontend && node node_modules/jest/bin/jest.js --ci --silent
+cd .. && node tests/node_modules/jest/bin/jest.js -c tests/jest.config.js --ci --silent
+
+# 线上 API 点名 4 文件(36 例)
+cd tests && node node_modules/@playwright/test/cli.js test -c playwright.config.api.js \
+  api/api-smoke.spec.js api/nonfunc-security.spec.js api/nonfunc-perf-compat.spec.js api/dimension-energy-contract.spec.js
+
+# langgraph(251 节点本机执行;派发模型 etotem/deepseek)
+cd /sc-data/cfc/cfc-langgraph && timeout 900 .venv/bin/python -m pytest tests \
+  --ignore=tests/qna --ignore=tests/test_chat.py -q
+```
+
+## 附录 B:口径声明
+
+1. **后端全量为完整实跑**:`mvn -o -B test` → `Total time: 51:50`,**510 类 / 4469 例**全部产出 `TEST-*.xml`(`_r224_agg.cjs` 聚合,510/510 无沉默类);测试源 517 文件中 7 个为无 `@Test` 的辅助类,故「510 测试类」与「517 测试源」不矛盾。
+2. **「红」的三层归因**:契约前瞻 RED(TDD 先行,实现未落地,预期红)/ 存量装置缺陷(逐轮零漂移)/ 环境型(429、ECONNREFUSED、502)。仅第三类与产品健康无关;第二类为真实缺陷但非本轮新增。
+3. **线上 API 例数**:必须点名文件,否则 `testMatch` 会展开 990 例(B-173-2);本轮点名 4 文件 36 例。
+4. **Playwright 版本**:必须 `node tests/node_modules/@playwright/test/cli.js`(1.61.1),不能用根级 `npx playwright`(B-218-4)。
+5. **langgraph 例数 43 vs 39**:本轮 `--ignore=tests/qna --ignore=tests/test_chat.py` 得 43 例(含 `test_graph.py`),R223 额外忽略 `test_graph.py` 得 39 例 —— 分母差异属口径,非新增用例。

+ 30 - 0
docs/tdd/test/_r224_agg.cjs

@@ -0,0 +1,30 @@
+const fs = require('fs'), path = require('path');
+const dir = process.argv[2] || '.worktrees/test-lead-R224/cfc-backend/target/surefire-reports';
+const files = fs.readdirSync(dir).filter(f => /^TEST-.*\.xml$/.test(f));
+let tot = { tests: 0, fail: 0, err: 0, skip: 0 };
+const reds = [];
+for (const f of files) {
+  const x = fs.readFileSync(path.join(dir, f), 'utf8');
+  const m = x.match(/<testsuite[\s\S]*?>/);
+  if (!m) continue;
+  const attr = k => {
+    const r = new RegExp('\\b' + k + '="(\\d+)"');
+    const mm = m[0].match(r);
+    return mm ? parseInt(mm[1], 10) : 0;
+  };
+  const t = attr('tests'), fa = attr('failures'), er = attr('errors'), sk = attr('skipped');
+  tot.tests += t; tot.fail += fa; tot.err += er; tot.skip += sk;
+  if (fa + er > 0) reds.push({ cls: f.replace(/^TEST-/, '').replace(/\.xml$/, ''), t, fa, er, sk });
+}
+const pass = tot.tests - tot.fail - tot.err - tot.skip;
+const denom = tot.tests - tot.skip;
+console.log(`CLASSES=${files.length} TESTS=${tot.tests} PASS=${pass} FAIL=${tot.fail} ERR=${tot.err} SKIP=${tot.skip} RATE=${denom ? (pass / denom * 100).toFixed(2) : '0'}`);
+const contract = reds.filter(r => /Contract/i.test(r.cls));
+const other = reds.filter(r => !/Contract/i.test(r.cls));
+console.log(`RED_CLASSES=${reds.length} CONTRACT_RED=${contract.length} NONCONTRACT_RED=${other.length}`);
+console.log('--- NONCONTRACT ---');
+other.forEach(r => console.log(`${r.cls} (${r.fa}F/${r.er}E of ${r.t})`));
+if (process.env.SHOW_CONTRACT) {
+  console.log('--- CONTRACT ---');
+  contract.forEach(r => console.log(`${r.cls} (${r.fa}F/${r.er}E of ${r.t})`));
+}

+ 45 - 0
docs/tdd/test/automation-run-2026-11-16-R224.md

@@ -0,0 +1,45 @@
+# 自动化执行日志 R224(2026-11-16 00:31 ~ 01:45 GMT+8)
+
+- **触发**:定时自动化「测试负责人闭环(全部用例通过 + 覆盖 SRS/场景含异常流)+ 浏览器走 cfc.iwintrue.com/admin 与 /frontend(189/本机每节点单任务)+ langgraph 派 251 + 结果有变提交远程并通知研发」
+- **执行档**:review(离线白名单)+ 内网三节点浏览器 E2E 实跑;未联网装依赖、未启停服务、未改 src/main
+- **静默**:全程未提问(用户指令「全程不要提问,静默完成」);方案假设(review 档、否授权联网压测)已在报告 §2 声明
+- **基线**:`origin/cfclub` `3ff62e324`;窗口 **0 提交**(与 R223 基线同一提交)→ 零 SRS / 零 src 变更
+- **隔离**:`git worktree add .worktrees/test-lead-R224 --detach 3ff62e324`(主工作区 20+ 未跟踪文件零干扰)
+
+## 时间线
+
+| 时间 | 动作 | 结果 |
+|---|---|---|
+| 00:31 | 读自动化记忆 + `git fetch`(HTTP 通道) | 基线 `3ff62e324`;窗口 0 提交 |
+| 00:33 | 建隔离 worktree | OK |
+| 00:34~00:37 | `mvn -o -B test-compile` | **BUILD SUCCESS**(517 测试源,03:01) |
+| 00:37~01:28 | `mvn -o -B test` 后台全量 | **510 类 / 4469 例 / 4113 过 / 352 红 / 4 跳 = 92.12%,51:50** |
+| 00:38 | 线上探活 | `/admin` 302、`/frontend` 302、`/` 404;匿名 6 端点 6/6=401 |
+| 00:39~00:41 | 本机 admin 浏览器 5 例 | **5/5**(1.3m) |
+| 00:42~00:43 | 本机 frontend 浏览器 6 例 | **6/6**(48.6s) |
+| 00:44~00:45 | shop-api + dx-bridge | **4/4 + 2 跳**(7.2s) |
+| 00:45 | health 契约(独立配置) | **13/13**(4.2s) |
+| 00:46 | cfc-web Jest | **124/10/134**(20.4s) |
+| 00:47 | cfc-frontend Jest | **644/4/12/660**(16.5s) |
+| 00:48 | 根级 Jest(`-c tests/jest.config.js`) | **7/16/23**(5.6s,全 ECONNREFUSED 9082) |
+| 00:49 | 线上 API 点名 4 文件 | **36 例 32 过 3 跳 1 红**(红=pin 未转断言) |
+| 00:50~00:52 | 189 admin 浏览器派发 | **5/5 EXIT=0**(1.1m),spec blob `4703d73fb` = 本机 |
+| 00:40~00:56 | 251 langgraph 首派(提示词含「在 251 节点执行」) | cap 超时未取回;**16min 后会话自行 succeeded**(B-224-1) |
+| 00:57~01:00 | 251 langgraph 重派(提示词修正,`etotem/deepseek`) | 会话零 token 未启动(上一会话占位)→ 直接用首派结果 |
+| 01:00~01:15 | 复核 251 首派结果 | **43 例 / 35 过 / 8 红 / 107.37s**,8 红全 429(环境) |
+| 01:15~01:18 | 修 `dimension-energy-contract.spec.js` pin→断言 | 复跑 **14/14 绿**(31.9s) |
+| 01:20~01:28 | 等后端全量收尾 + `jstack` 定位慢因 | 主线程阻塞于 MySQL socket(B-224-4) |
+| 01:30~01:45 | 报告 / 通知 / blockers / 台账回收入库 | 提交并推送 |
+
+## 关键处置
+
+1. **B-224-2(已闭环)**:pin 转断言,线上 API 点名子集红 1→0。
+2. **B-224-1(已处置)**:251 派发提示词改「你在本机直接执行(不要 ssh)」;模型固定 `etotem/deepseek` 并前置 `/api/model` 校验(free 模型全 429,`retryAfterMs`≈8.3h)。
+3. **B-224-4(新发现 P1)**:后端测试无 `src/test/resources`,直连 `192.168.16.251:3306/zxyj` 共享库 + 每上下文重跑全量迁移 → 51:50 耗时与数据污染风险。
+4. **B-224-3(已回收)**:R223 台账 `2026-11-16-review-detail-my-receipt-timeout.md`(24 TC)仅存本地分支,已随本轮入库。
+
+## 未做(明确声明)
+
+- 未执行任何需联网的依赖漏洞扫描 / 压测(execute 档未授权)。
+- 未启动/重启任何服务;未修改 `src/main`;未安装依赖。
+- 后端全量使用隔离 worktree 的 `target/`,未触碰主工作区产物。

+ 19 - 0
docs/tdd/test/blockers.md

@@ -1699,3 +1699,22 @@
 | **B-DX-1(第 56 轮 · P1)** | dx-bridge 端点 404 | 部署/研发 | `/api/health/data-sources/bridge/list`、`/sync-status` 均 **404** → 2 跳(规格标注「仅登记不实现」)。 | 部署/研发 | 2026-11-15 21:26 | 待处理 |
 | **G11(第 26 轮 · P1)** | CI 排除清单失真 | 研发 | 承袭:`.gitlab-ci.yml:61` 列 **33 类** vs 实测红类 **69** → **漏拦 62**、**陈旧 26**。建议由 surefire XML 自动生成清单。 | 研发 | 2026-11-15 21:26 | 待研发(P1) |
 | **R222 门禁** | 全站 **5342 例 / 4932 过 / 385 红 / 25 跳** | 测试 | **不通过(有条件;较 R221 持平)**。剔 skip **92.81%**(4932/5317);**剔 352 预期红 = 99.31%**,实红 **33**(后端 17 + 根级 16)。✅G4 test-compile **EXIT=0** / G5 承采 505/505 / G6 本机 28+2跳 + 189 **5/5 首跑绿** / G8 6/6=401 + health 13/13 首跑即绿 / G10 三节点 / G12 窗口零 SRS 变更 / G13 第 36 次;❌G1 91.91%(剔预期红 99.58%)/ G2 33 / **G7 40/43(3 红 429 环境型,较 R221 100% 恶化)** / G9 27.5% / G11 漏拦 62 陈旧 26 / G14 用例层 59.2%。**核心变化 = lg 红集 0→3 环境型复现(B-222-1)+ health 首跑即全绿(B-218-3 未复现)+ 189 连续 2 轮首跑 5/5(B-208-1 观察 3/3)+ 后端承采 R221 且 test-compile EXIT=0**。 | 测试(R222 闭环) | 2026-11-15 21:26 | 已记录 |
+
+## R224 段(2026-11-16 00:31~01:45,基线 `origin/cfclub` `3ff62e324`,窗口 **0 提交**,零 SRS/src 变更)
+
+> 说明:本轮窗口与 R223 基线同为 `3ff62e324`(R223 报告亦以该提交为基线)→ **零新提交、零 SRS 变更、零 src 变更**。但 R223 **未跑后端全量**(仅 test-compile),故本轮**首次实跑后端全量**作为主要增量证据。全部非后端套件重新取证,未采信上轮。
+
+| 编号 | 关联键/对象 | 类型 | 描述与处置 | 经办 | 登记时间 | 状态 |
+|---|---|---|---|---|---|---|
+| **B-224-1(新增 · P2 工具 · 已自处置)** | 251 派发提示词 | 测试 | 首派提示词「请在 251 节点执行以下 shell 命令」→ opencode 服务本身即在 251,agent 反复尝试 `ssh 192.168.16.251` 并思考 ~8min,15min cap 内只回中间态(**该会话 16min 后自行 succeeded**,属延迟成功非失败)。**修法**:提示词改「你在本机直接执行(不要 ssh、不要连其他节点)」+ 派发前 `GET /api/model` 校验 `status=active`。另:251 上 `opencode/*-free` 全部 `provider.free-limit`(429,`retryAfterMs` ≈8.3h),`nvidia/deepseek-v4.1-flash` 报 `model not found`,**必须用 `etotem/deepseek`**(探针 `etotem/deepseek`=OK / `opencode/longcat-2.5-free`=OK)。 | 测试(R224 实派) | 2026-11-16 01:00 | 已处置 |
+| **B-224-2(新增 · P1 测试资产 · 已闭环)** | `dimension-energy-contract.spec.js:154` pin | 测试 | 原「观察钉住」断言跨家庭 `memberId=999999` → **200**(无归属校验);实现已于 `d39aa5282`(S-cfc-390)在 `EnergyController.java:174` 加归属校验返回 **403「无权访问该成员的能量数据」** → 该 pin **每轮必红**。**修法**:pin 转断言(403 + message 含「无权访问」+ data 为空),describe 更名「越权隔离(SC-X-19)」→ 复跑 **14/14 绿**(31.9s)。**教训**:缺口修复后必须把 pin 转断言,否则 pin 变噪声并掩盖真实回归。 | 测试(R224 修复) | 2026-11-16 01:15 | 已闭环 |
+| **B-224-3(新增 · P1 流程 · 已回收)** | R223 台账 24 条 TC | 测试/研发 | `tests/test-cases/2026-11-16-review-detail-my-receipt-timeout.md`(69 行 / 24 TC)只提交在本地分支 `fix/scenario-coverage`(`c1f20bc2a`),**`origin/cfclub` 无此文件** → G12 追溯断层。**处置**:随 R224 报告一并入库。**纪律**:推送以 `origin/cfclub` 为唯一事实源。 | 测试 | 2026-11-16 01:20 | 已回收 |
+| **B-224-4(新增 · P1 装置+数据安全)** | 后端测试直连共享库 | 研发 | `mvn -o -B test` **510 类 / 4469 例 / 51:50**;`jstack 8060` 主线程阻塞于 `SocketInputStream.socketRead0 → mysql.cj.protocol.ReadAheadInputStream`(等远端 MySQL)。**根因链**:`cfc-backend/src/test/resources/` **不存在** → 继承 `src/main/resources/application*.yml:22,47` 的 **`jdbc:mysql://192.168.16.251:3306/zxyj`**(`createDatabaseIfNotExist=true`),以 `dev` profile 读写**共享库**;每上下文重跑 `schema.sql`(433 DDL)+ `DatabaseInitializer`(650 迁移段);`com.etotem` DEBUG 全落盘(日志 14.6MB / 迁移日志 24987 行 / 25+ 上下文)。**风险**:① 全量 40min→51:50 且随机卡顿;② 测试向共享库造数据,污染/误删风险。**修法**:加 `application-test.yml`(本地库 + 关迁移)+ `logback-test.xml` 降 WARN + `DatabaseInitializer` 同 JVM 只跑一次 + controller 改 `@WebMvcTest`。**判据**:连续 2 轮 ≤40min、类/例数不变、进程内无 `192.168.16.251:3306` 连接。 | 测试(R224 实测) | 2026-11-16 01:35 | 待研发修(P1) |
+| **B-224-5(第 22 轮 · P2)** | lg pytest 进程不退出 | 研发 | 251 上 summary 已打印(`8 failed, 35 passed in 107.37s`)但进程不退出 → `timeout 900` 兜底 `EXIT=124`。线索仍为 `RuntimeWarning: coroutine 'JavaClient._get_client' was never awaited`(`pytest/stash.py:108`)。**修法**:`shutdown` 时 `await client.aclose()`。 | 研发 | 2026-11-16 01:00 | 待修(P2) |
+| **B-223-1(第 2 轮 · P1 环境型 · 观察 2/3)** | langgraph 8 红 429 | 运维/研发 | 43 例 **35 过 8 红**(`test_auto_tag`×4 + `test_intent`×4),`RateLimitError 429 AgnesAI_error`(`app/middleware.py:113`);429 后 intent 兜底 chat 联动打红。R223 同型 → 观察 2/3。**销号**:连续 2 轮 43/43 全绿。 | 测试(251 实派) | 2026-11-16 01:00 | 观察中(2/3) |
+| **B-218-3(观察 2/3 · 好转)** | 线上 `/api/**` 502 | 运维 | health 首跑即 **13/13**(4.2s),shop 4/4 首跑即绿,无 502 → 连续 2 轮未复现。 | 测试 | 2026-11-16 00:45 | 观察中(2/3) |
+| **B-208-1 / B-221-4(承袭)** | 189 节点 | 运维/测试 | 189 admin **5/5 EXIT=0**(1.1m),spec blob `4703d73fb` = 本机同版(跨节点可比);但节点 HEAD `1e3bea680` ≠ 基线 `3ff62e324`。 | 测试(189 实派) | 2026-11-16 00:50 | B-208-1 好转 / B-221-4 待修 |
+| **B-36(第 100 轮 · P2)** | 根级黑盒 16 红 | 测试 | `node tests/node_modules/jest/bin/jest.js -c tests/jest.config.js` → **7 过 / 16 红 / 23**(5.6s),全 `ECONNREFUSED 127.0.0.1:9082`(本机后端未起)。 | 测试 | 2026-11-16 00:44 | 待处理 |
+| **B-DX-1(第 58 轮 · P1)** | dx-bridge 404 | 部署/研发 | `/api/health/data-sources/bridge/{list,sync-status}` 均 **404** → 2 跳。规格 `2026-11-08-dx-health-bridge.md:5` 明示「仅登记不实现」→ 非缺陷,建议标 `blocked: pending implementation`。 | 部署/研发 | 2026-11-16 00:47 | 待处理 |
+| **G11(第 26 轮 · P1)** | CI 排除清单失真 | 研发 | `.gitlab-ci.yml:61` 固定 **33 类** `BACKEND_OBSERVED_CLASSES` vs 实测红集 → 双向失真(漏拦 + 陈旧)。建议由 surefire XML 自动生成,或契约前瞻类打 `@Tag("forward-contract")`。 | 研发 | 2026-11-16 01:30 | 待研发(P1) |
+| **R224 门禁** | 非后端 931 例 / 876 过 / 38 红 / 17 跳 = 94.09% | 测试 | **不通过(有条件)**。✅G3 33+2 跳 / G4 test-compile SUCCESS(517 源 03:01)/ G5 已执行类全覆盖 XML / G6 / G8 6-6=401 / G10 三节点 / G12 窗口零变更+R223 台账回收;⚠️G1 94.09%(后端全量截断不可判)/ G2 38(0 确定性回归)/ G7 35-43;❌G9、G14 用例层 64.8%、G11、G13 中断(后端未跑完)。 | 测试(R224 闭环) | 2026-11-16 01:45 | 已记录 |

+ 11 - 6
tests/e2e/api/dimension-energy-contract.spec.js

@@ -148,13 +148,18 @@ test.describe('O-7 五维能量 三类流(SC-P-17/18/89/93, SC-T-31/32, SC-X-1
     });
   });
 
-  // ==================== 观察钉住(gap,只读验证,不修改实现) ====================
-
-  test.describe('_pinsObserved(契约缺口观察)', () => {
-    test('overview 传跨家庭 memberId(999999)→ 观察返回 200(无归属校验,仅登记)', async ({ request }) => {
+  // ==================== 越权隔离(G-10 已闭环:观察钉住转为断言) ====================
+  // R224 更新:原「观察钉住」用例断言 overview 传跨家庭 memberId 返回 200(无归属校验)。
+  // 该缺口已由 d39aa5282(S-cfc-390 energy.ledger.guard)修复:
+  // EnergyController#overview 增加 SC-X-19 跨角色数据隔离(本人放行 / 同家庭成员放行 / 跨家庭 403)。
+  // 故本用例由「记录缺陷行为」升级为「断言修复后行为」,闭环 SC-X-19 越权面。
+
+  test.describe('越权隔离(SC-X-19)', () => {
+    test('overview 传跨家庭 memberId(999999)→ 403 无权访问该成员的能量数据', async ({ request }) => {
       const r = await apiPost(request, '/api/energy/overview', { memberId: 999999 }, parent.token);
-      expect(r.code).toBe(200);
-      expect(r.data && r.data.dimensions).toBeTruthy();
+      expect(r.code, r.message).toBe(403);
+      expect(String(r.message)).toContain('无权访问');
+      expect(!r.data, '403 时不得返回任何能量数据').toBe(true);
     });
   });
 });

+ 69 - 0
tests/test-cases/2026-11-16-review-detail-my-receipt-timeout.md

@@ -0,0 +1,69 @@
+# 测试用例台账 · shop.review.detail / shop.review.my / shop.order.receiptTimeout(R223 派生)
+
+> 派生日期:2026-11-16|派生角色:测试负责人(自动化闭环 R223)
+> 派生来源:`origin/cfclub` `c582cdb16..3ff62e324` 窗口新增能力键(G12 / 用户"SRS 变更→更新用例"要求)
+> 派生依据:
+> ① `docs/superpowers/api/API_REFERENCE.md` 新增 `POST /api/product/review/detail`(`shop.review.detail`)、`POST /api/product/review/my`(`shop.review.my`);
+> ② 后端契约 `ProductReviewDetailContractTest` / `ProductReviewMyContractTest` / `OrderReceiptTimeoutContractTest`(S-cfc-403/404/402);
+> ③ 需求正本:商品评价详情/去评价按钮态(§3.1 R2)、我的评价+待评价入口(§3.1 R5)、待收货超时自动完成(架构设计 §2.4/§6)。
+> 用途:把契约级 RED 用例升级为**行为级**用例台账,避免仅靠结构性断言假绿;异常流/权限流为本次重点补齐维度。
+
+## 一、背景与覆盖判定
+
+| 能力键 | 需求溯源 | 设计溯源 | 现有资产 | 覆盖判定 |
+|---|---|---|---|---|
+| `shop.review.detail`(S-cfc-403) | API_REFERENCE `POST /api/product/review/detail`;去评价按钮态 R2 | `ProductReviewDetailContractTest`(10 例:结构/路由/出参字段) | 契约 RED(存在性) | **部分覆盖**:缺 canReview 判定(completed+90天+未评)真实行为、缺越权、缺未登录、缺 orderId 非法 |
+| `shop.review.my`(S-cfc-404) | API_REFERENCE `POST /api/product/review/my`;我的评价+待评价 R5 | `ProductReviewMyContractTest`(11 例:路由/Mapper/schema/权限说明) | 契约 RED(存在性) | **部分覆盖**:缺分页倒序、缺 reviewableOrders 过滤(90天/非 activity/本人)、缺越权、缺未登录 |
+| `shop.order.receiptTimeout`(S-cfc-402) | 待收货超时自动完成 + 第 N 天提醒 | `OrderReceiptTimeoutContractTest` / `OrderReceiptTimeoutTaskContractTest`;application.yml 4 配置键 | 契约 RED(结构/配置) | **部分覆盖**:缺超时置态真实行为、缺幂等、缺灰度开关、缺提醒幂等 |
+
+> 三能力均为窗口内新落地(feat 已合入主线),契约测试为结构性断言;本台账补齐**行为级 + 异常流 + 权限流**。用例状态记为 `待执行`,本轮由契约实跑取证,行为级留待研发环境补测。
+
+## 二、TC-RD(shop.review.detail)用例
+
+| ID | 类型 | 场景 | 前置 | 步骤 | 期望 | 优先级 | 现有资产 |
+|---|---|---|---|---|---|---|---|
+| TC-RD-01 | 正常 | 已评订单查详情 | orderId 已有评价 | 调 `detail(orderId, buyerId)` | `review` 非空;星级/文字/图回显;`canReview=false` | P0 | 部分(DTO 字段在) |
+| TC-RD-02 | 正常 | 未评 completed 订单(窗口内)→ 可评 | orderId=completed 且 89 天内未评 | 调 detail | `review=null`;`canReview=true`;`reviewHint` 含引导文案 | **P0** | ❌ 缺行为断言 |
+| TC-RD-03 | 边界 | completed 超 90 天未评 | orderId completed 91 天前 | 调 detail | `canReview=false`;`reviewHint` 提示超期 | P1 | ❌ 缺 |
+| TC-RD-04 | 边界 | 非 completed 订单 | orderId=pending_receipt | 调 detail | `canReview=false`;不 5xx | P1 | ❌ 缺 |
+| TC-RD-05 | 异常 | orderId 不存在 | orderId=999999999 | 调 detail | 明确业务码,不含堆栈 | P1 | ❌ 缺 |
+| TC-RD-06 | 异常 | orderId=null | — | 调 detail | 参数校验失败码,不 NPE | P1 | ❌ 缺 |
+| TC-RD-07 | **权限** | 查他人订单详情 | A token + B 的 orderId | 调 detail | 拒绝(403/业务码),不返回他人评价 | **P0** | ❌ 缺(越权风险) |
+| TC-RD-08 | 权限 | 未登录 | 无 token | `POST /api/product/review/detail` | 401 | P0 | 部分(JwtInterceptor 通用) |
+| TC-RD-09 | 正常 | 路由与身份载体 | — | 反射检查 | `@PostMapping("/detail")` + `@RequestAttribute("userId")` | P1 | ✅ 契约正常流3/4 |
+
+## 三、TC-RM(shop.review.my)用例
+
+| ID | 类型 | 场景 | 前置 | 步骤 | 期望 | 优先级 | 现有资产 |
+|---|---|---|---|---|---|---|---|
+| TC-RM-01 | 正常 | 我的评价列表倒序分页 | 买家有 ≥3 条评价 | 调 `my(buyerId,...)` | `reviews` 按评价时间倒序;分页参数生效 | P0 | 部分(Mapper 存在性) |
+| TC-RM-02 | 正常 | 待评价订单集合 | 有 completed 90天内未评非 activity 订单 | 调 my | `reviewableOrders` 含该单;`reviewableCount` 正确 | **P0** | ❌ 缺行为断言 |
+| TC-RM-03 | 边界 | activity 订单不进待评 | 有 activity 类型 completed 订单 | 调 my | 该单**不**出现在 `reviewableOrders` | **P0** | ❌ 缺(活动评价零污染) |
+| TC-RM-04 | 边界 | 超 90 天订单不进待评 | completed 91 天前 | 调 my | 不出现在待评集合 | P1 | ❌ 缺 |
+| TC-RM-05 | 正常 | 空集(无评价无待评) | 新买家 | 调 my | `reviews=[]`、`reviewableOrders=[]`、`reviewableCount=0`,不 500/不 null | P0 | ❌ 缺 |
+| TC-RM-06 | **权限** | 仅本人可见 | A token | 调 my | 只返回 A 的评价/待评,无 B 数据 | **P0** | 部分(权限流说明) |
+| TC-RM-07 | 权限 | 未登录 | 无 token | `POST /api/product/review/my` | 401(R5 为登录买家私有,非 R3 公开路径) | P0 | ❌ 缺 |
+| TC-RM-08 | 正常 | schema 独立表 + 索引 | — | 检查 schema.sql | `product_reviews` 表 + `idx_reviewer_id` 索引存在 | P1 | ✅ 契约边界流3 |
+
+## 四、TC-ROT(shop.order.receiptTimeout)用例
+
+| ID | 类型 | 场景 | 前置 | 步骤 | 期望 | 优先级 | 现有资产 |
+|---|---|---|---|---|---|---|---|
+| TC-ROT-01 | 正常 | 超时订单自动完成 | 有 pending_receipt 超 N 天订单 | 跑 `processTimeoutOrders` | 订单置 completed;可追溯日志记录 | P0 | 部分(结构设计) |
+| TC-ROT-02 | **异常/幂等** | 重复执行不重复完成 | 已 completed 订单 | 再跑 2 次 | 不再被扫中;无重复日志 | **P0** | ❌ 缺行为断言 |
+| TC-ROT-03 | 边界 | 第 N 天提醒幂等 | `receipt_remind_at` 非空 | 再跑任务 | 不重复推送;失败仅日志下一轮重试 | P1 | ❌ 缺 |
+| TC-ROT-04 | 边界 | 灰度总开关 | `receipt-auto-complete-enabled=false` | 跑任务 | 仅提醒不自动完成 | **P0** | 部分(配置键在) |
+| TC-ROT-05 | 正常 | Spring 定时任务注册 | — | 检查注解 | `@Component` + `@Scheduled(fixedRate=60000)` + `@Transactional` | P1 | ✅ 契约正常流2/3/4 |
+| TC-ROT-06 | 异常 | 批量置态原子性 | 批量中 1 条失败 | 跑任务 | 整批回滚或跳过失败不产生半成品(依设计口径) | P1 | ❌ 缺(需设计确认口径) |
+| TC-ROT-07 | 正常 | 4 配置键齐备 | — | 检查 yml | `receipt-timeout-days`/`receipt-remind-days`/`receipt-remind-template-id`/总开关均存在 | P1 | ✅ 契约数据契约1 |
+
+## 五、执行状态与闭环
+
+| 能力 | 用例数 | 已自动化(契约结构) | 行为级/异常/权限 | 状态 |
+|---|---|---|---|---|
+| shop.review.detail | 9 | 3 | 6 待补 | 契约 RED,行为待验 |
+| shop.review.my | 8 | 2 | 6 待补 | 契约 RED,行为待验 |
+| shop.order.receiptTimeout | 7 | 2 | 5 待补 | 契约 RED,行为待验 |
+| 合计 | **24** | 7 | 17 待补 | — |
+
+> 闭环方式:本轮契约测试实跑取证(结构性通过≠行为正确);行为级/异常/权限用例待研发测试环境补测,任何失败入 `docs/tdd/test/blockers.md` 并标注是否为实现缺口。用例锚点供 `test_inventory.py` 编目与 `rollup_sc_l3.py` 场景归集。