Kaynağa Gözat

test(tdd): 第156轮闭环——全量3790/3726=98.31%,后端实跑99.29%零漂移第14次,langgraph 3→10红恶化(429配额),会员门控补7例,门禁不通过

- 后端强制实跑(61:02):347类/2946例/2925过/16F+1E+4S=99.29%,10红类与R152/R154逐类逐例一致 → 零回归第14次;采信期(R155)无漏检
- langgraph@251:51例/41过/10红/126.67s(R155 48/3)→ 唯一恶化项;analyze1+auto_tag5+intent4,根因429免费额度耗尽+401记忆召回key失效,/health 200 → 环境红非代码回归
- 浏览器 28/28+2skip:189 admin 5/5(EXIT=0,spec blob 4703d73fb=本机)+本机 fe6/shop4/health13;dx 2 skip(404)
- 窗口内功能合入 3d35ab714(会员门控,前端10文件)→ 增量复验前端 624/609/3红(红例集合不变)+ 补 7 例 TC-MG-U01~U07(membershipGate 合入时零测试)
- 新增 B-156-1(nutrition_age_dosage 三重不一致:DDL 无 product_id 列却建该索引→34/34 上下文建表失败;实体 update_time 缺列;死注入)/ B-156-3(门控缺页级E2E);B-152-1/2 CI 双缺陷未修(漏拦3红类+26陈旧绿类)
- 门禁:G1 98.31%/G3/G4/G5/G6/G8/G10/G12 ✅;G2 46/G7 41-51/G9/G11/G14 ❌;G13 17 ⚠️ → 不通过(较R155收紧)
- 修 dispatch_251_pytest.cjs:改用 .venv/bin/python + 退出码先存变量再落盘(B-126 诱因)
E2E Test Bot 1 gün önce
ebeveyn
işleme
9ebfff4d44

+ 73 - 0
cfc-frontend/__tests__/utils/membershipGate.test.js

@@ -0,0 +1,73 @@
+/**
+ * 会员有效态门控(`utils/membershipGate.js`)单元测试
+ *
+ * 背景:`membershipGate.js` 随 `merge(miniprogram): 聊天/消息类入口按有效会员隐藏`
+ * (commit `3d35ab714`,2026-11-12 00:33)合入主线,**合入时零测试**。
+ * 该函数决定 9 个页面(首页/心/身/智/行/我的/应用库/详情页)的聊天·消息入口可见性,
+ * 属「越权即放行非会员」的强业务约束,必须有可执行锚点。
+ *
+ * 契约(源码注释自述,逐条断言):
+ *   - 唯一判据 = `POST /api/ai/gate` 的 `data.isActive === true`(严格等于,不看 canUse/status)
+ *   - 无 token 直接 false,**不发请求**(fail-closed)
+ *   - 接口异常 / 超时 / 字段缺失 一律 false(fail-closed)
+ *
+ * 锚点:TC-MG-U01 ~ TC-MG-U07
+ */
+jest.mock('@/utils/api.js', () => ({
+  aiGateStatus: jest.fn()
+}))
+
+import { aiGateStatus } from '@/utils/api.js'
+import { isActiveMember } from '@/utils/membershipGate.js'
+
+beforeEach(() => {
+  global.uni._storage = {}
+  aiGateStatus.mockReset()
+})
+
+describe('isActiveMember · 会员有效态(TC-MG-U01~U07)', () => {
+  it('TC-MG-U01 无 token 直接 false,且不发起 /api/ai/gate 请求', async () => {
+    const r = await isActiveMember()
+    expect(r).toBe(false)
+    expect(aiGateStatus).not.toHaveBeenCalled()
+  })
+
+  it('TC-MG-U02 有 token 且 data.isActive === true → true', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockResolvedValue({ code: 200, data: { isActive: true } })
+    await expect(isActiveMember()).resolves.toBe(true)
+    expect(aiGateStatus).toHaveBeenCalledTimes(1)
+  })
+
+  it('TC-MG-U03 有 token 且 data.isActive === false(过期会员)→ false', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockResolvedValue({ code: 200, data: { isActive: false } })
+    await expect(isActiveMember()).resolves.toBe(false)
+  })
+
+  it('TC-MG-U04 响应缺 data 字段 → false(字段缺失 fail-closed)', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockResolvedValue({ code: 200 })
+    await expect(isActiveMember()).resolves.toBe(false)
+  })
+
+  it('TC-MG-U05 isActive 为非布尔真值(后端返回 1 / "true")→ false(严格等值,不误放行)', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockResolvedValueOnce({ code: 200, data: { isActive: 1 } })
+    await expect(isActiveMember()).resolves.toBe(false)
+    aiGateStatus.mockResolvedValueOnce({ code: 200, data: { isActive: 'true' } })
+    await expect(isActiveMember()).resolves.toBe(false)
+  })
+
+  it('TC-MG-U06 接口 reject(网络异常/超时)→ false,不抛错', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockRejectedValue(new Error('timeout'))
+    await expect(isActiveMember()).resolves.toBe(false)
+  })
+
+  it('TC-MG-U07 接口 resolve 成 undefined → false(不因空响应放行)', async () => {
+    global.uni._storage.token = 'tk-abc'
+    aiGateStatus.mockResolvedValue(undefined)
+    await expect(isActiveMember()).resolves.toBe(false)
+  })
+})

+ 329 - 0
docs/tdd/orchestration/report-test-2026-11-12-R156.md

@@ -0,0 +1,329 @@
+# 测试负责人工作汇报(第 156 轮 · 2026-11-12 23:35–00:50 GMT+8)
+
+> 角色:`cfc-tester`(测试负责人 / 陆谨)|执行档:**review(离线 + 内网已授权)**——内网浏览器自动化(`cfc.iwintrue.com/admin` + `/frontend`)、langgraph 实派 `192.168.16.251:4096`、后端 `mvn -o -B clean test` **全量实跑**;**未联网装依赖、未启停服务、未改生产源码/测试**。
+> 基线 HEAD:跑测起点 `722de8f37`;**跑测窗口内远端合入 1 个功能变更** `3d35ab714 merge(miniprogram): 聊天/消息类入口按有效会员隐藏`(10 文件 +124/−29,新增 `utils/membershipGate.js`)→ 收尾 rebase 至 `c7d921bcf` 后**做了增量复验**(前端全量 624 例,见 §5.1),并按「变更→补用例」原则新增 **7 条用例**。
+> 节点分工(用户约束:每节点单任务,串行):`189:4090` = **admin-desktop 5/5**|`251:4096` = **langgraph pytest 51 例**|本机 = fe/shop/health/dx + 三套 Jest + 根级 + 后端全量。
+> **结论:⛔ 不通过**——后端 99.29%(17 红,**与 R154 逐类逐例一致 → 零回归第 14 次**);langgraph **41/51(3→10 红,本轮唯一恶化项)**;浏览器 **28/28 + 2 skip**;前端在功能合入后增量复验 **624 例 / 609 过 / 3 红(集合不变)**;全量 **3790 例 / 3726 过 = 98.31%**。
+
+---
+
+## 0. 基本信息(测试负责人模板)
+
+| 项目 | 内容 |
+|------|------|
+| 汇报人 | `cfc-tester`(测试负责人) |
+| 汇报周期 | 2026-11-12 第 156 轮(跑测窗口 23:36–00:50) |
+| 负责模块/单元 | cfc-backend(JUnit 全量实跑)· cfc-frontend(Jest)· cfc-web(Jest)· cfc-langgraph(251 实派)· 浏览器 E2E(admin@189 / fe·shop·health·dx@本机)· 根级黑盒 |
+
+### 0.1 测试用例建设与执行
+
+| 指标 | 数量 | 说明 |
+|------|------|------|
+| **本轮新增测试用例数** | **7** 个 | `cfc-frontend/__tests__/utils/membershipGate.test.js`(**TC-MG-U01~U07**),覆盖窗口内合入的 `utils/membershipGate.js`(此前**零测试**)。SRS/场景/API_REFERENCE 本身零变更,但功能合入属「场景实现落地」→ 按纪律**补用例**(未改任何生产代码) |
+| **本轮验证执行测试数** | **3790** 个 | 后端 2946 + 前端 624 + 管理端 116 + 根级 23 + langgraph 51 + 浏览器 30(含 dx 2 skip) |
+| **用例通过率** | **98.31%**(3726/3790) | 剔 skip 口径 **98.78%**(3726/3772);红 46 = 后端 17 + 根级 16 + langgraph 10 + 前端 3 |
+| **新增覆盖资产** | **1** 项 | 新增 `TC-MG-U01~U07` 可执行锚点(`membershipGate` 会员门控契约);反向核查无死资产(`tests/e2e-live` 4 个 spec 全部挂入 project,dx 2 例按 404 正确 skip) |
+| **SRS/场景变更** | **0(文档)/ 1(实现)** | SRS `specs` **201** 份 + `test-cases` **15** 份 + `API_REFERENCE.md` 窗口内**零变更**;但同日 00:33 合入会员门控实现(`3d35ab714`)→ 已有场景「聊天/消息入口按有效会员可见」实现落地,**已补 7 条用例**覆盖 |
+
+### 0.2 会话与任务分发
+
+| 指标 | 数量 | 说明 |
+|------|------|------|
+| **分派任务数** | **2** 个 | ① 189:admin-desktop(1.4m,5/5,`EXIT=0`);② 251:langgraph pytest(126.67s,41/51) |
+| **恢复智能体会话数** | 0 | 无中断重建 |
+| **当前在用会话数** | 3 | 本机(done)/ 189(done)/ 251(done) |
+
+| 会话标签 | 会话 ID | 状态 | 任务 | 耗时 | 工作目录 | 备注 |
+|----------|---------|------|------|------|----------|------|
+| 本机 | localhost | done | 后端全量 + Jest×3 + 根级 + 浏览器 fe/shop/health/dx | 61:02 | `d:\cfc` | fe 6/6、shop 4/4、health 13/13、dx 2 skip |
+| 189:4090 | `sh_1cb439b16…` | done | admin-desktop E2E | 1.4m | `C:\code\cfc\tests` | **5/5(EXIT=0)**;节点 HEAD `3c3d4b0a5`、spec blob `4703d73fb` 与本机完全一致 → 跨节点可比 |
+| 251:4096 | shell 直连(`setsid nohup` + 落盘) | done | langgraph pytest | 126.67s | `/sc-data/cfc/cfc-langgraph` | **41/51**;节点 HEAD `722de8f37` = 本机 |
+
+---
+
+## 1. 历史审查记录(对照,非本次结论依据)
+
+- **对象**:cfc 周期性自动化闭环,R148–R156 连续稳态轮。上一轮 **R155 @ 23:01** 结论 **⛔ 有条件通过**(G7 langgraph 3 红 + EXIT=124 消失、后端/前端/管理端采信 R153/R154)。
+- **遗留缺口**(沿用):后端 17 红存量、cfc-web 覆盖率 9.95%<20%(G7)、langgraph 上游 429/401、安全/性能/依赖扫描未授权、CI 硬门禁必红(G11)、admin.referral(TR-25)零覆盖、dx-bridge 未部署(G14)。
+- **本轮相对 R155 的整改核查**:R155 起「后端采信」已累计 1 轮 → 本轮**改回全量实跑**(`mvn -o -B clean test`,61:02)以排除窗口内隐式回归。结果与 R154 逐类逐例一致,**采信期无漏检**。
+- **本次非首次审查**,结论以本轮实际取证为准。
+
+---
+
+## 2. 项目画像速览(只读)
+
+- **业务**:浠艾福 XAF 家庭成长平台(家长端/孩子端/规划师端 + 管理端 + 独立商城 + AI 解析)。
+- **技术栈**:cfc-backend(Spring Boot 2.7.18 / Java 8 / MyBatis-Plus,9082)、cfc-web(Vue 2 + Element UI 管理端,8082)、cfc-frontend(uni-app 微信小程序)、cfc-langgraph(FastAPI + LangGraph + ChromaDB,9000)、`dan/danshop`(8888)。
+- **关键路径**:JWT 鉴权 `/api/**`(`JwtInterceptor`,8 个公开路径)、统一 `@PostMapping`(`@GetMapping` 仅存 8 处、`@Put/@DeleteMapping` 0 处)、`AiGateway` 调 LangGraph、健康报告 PDF 上传解析、五维能量、测评订单、家庭关系与邀请、商城价格排序。
+- **规模**:后端控制器 **366** 个、`@RestController` 366 个;测试源 **353** 份 / `@Test` **2935**;编译产出 `*.class` **2330**;浏览器 spec:`tests/e2e` 75 份 + `tests/e2e-live` 5 份。
+- **测试现状**:单元/组件/契约/集成资产齐备(后端 347 类可执行);E2E 走「线上只读浏览器 + 接口契约」双轨;**无 JaCoCo**(`pom.xml` 无 jacoco 插件)→ 后端覆盖率无法度量;CI 存在(`.gitlab-ci.yml`)但硬门禁必红。
+- **风险点**:① 后端测试装置使全量耗时 61:02(34 次 Spring 上下文 + 每次重跑 `DatabaseInitializer` 全量迁移);② langgraph 依赖单一免费额度上游(429 即整片红);③ 管理端匿名访问鉴权门缺失;④ 根级黑盒套件强依赖本机 9082。
+
+---
+
+## 3. 20 类测试覆盖矩阵(三态)
+
+| # | 测试类型 | 状态 | 本轮证据 |
+|---|----------|------|----------|
+| 1 | 单元测试 | **已实测** | 后端 347 类 / 2946 例(含单测包 `com.etotem.cfc.unit`、`service`、`util`);cfc-web 116/116;cfc-frontend 617 |
+| 2 | 组件测试 | **已实测** | `cfc-frontend/__tests__/pages/**`、`cfc-web/src/__tests__/views/**`(含 `FamiliesPlanEntry.spec.js` 等) |
+| 3 | 集成测试 | **已实测** | `com.etotem.cfc.integration.*`(EnergySystemFlow 7、DimensionRegistryMap 7、GuideModule 4、ArticleWorkflow…) |
+| 4 | 接口 API 测试 | **已实测** | `tests/e2e-live/shop-sort-api.spec.js` 4/4、`health-contract.spec.js` 13/13(直连 `/api`)、`tests/e2e/api` 契约集 |
+| 5 | 系统/端到端 | **已实测** | 浏览器 **28/28**(189 admin 5/5 + 本机 fe 6/6、shop 4/4、health 13/13) |
+| 6 | 冒烟测试 | **已实测** | langgraph@251 51 例 126.67s 正常收尾;站点 `/admin` `/frontend` 302→200 |
+| 7 | 回归测试 | **已实测** | 后端 17 红与 R154 逐类逐例一致(零漂移第 14 次);浏览器 28/28 连续零漂移;前端 3 红集合不变 |
+| 8 | 探索性测试 | **待核实** | 无 charter 文档、无会话记录(`tests/exploratory` 不存在) |
+| 9 | 契约测试 | **已实测** | `*ContractTest`(DimensionRegistryMap 3 红、UserServiceWechatLoginContract 1 红、TeamProfitCronContract 1 红);dx-bridge 2 例按 404 skip |
+| 10 | 性能测试 | **未授权未执行** | 仓库无 k6/JMeter/Locust 脚本;压测属 execute 档(需联网 + 打目标环境) |
+| 11 | 可靠性测试 | **已实测(失败面)** | 34 次 Spring 上下文重跑 + langgraph 429 熔断面;`AiGateway` 熔断/超时存在但无专项可靠性用例 |
+| 12 | 安全测试 | **未授权未执行** | 无 semgrep/DAST 配置;仅做鉴权契约 5/5(本机可达性)与匿名探针(B-142-1) |
+| 13 | 依赖漏洞扫描 | **未授权未执行** | 无 `dependency-check`/SBOM/`.sarif`;需联网拉库 |
+| 14 | 兼容性测试 | **待核实** | 无浏览器/机型矩阵;Playwright 仅 chromium(1440×900 / 375×812) |
+| 15 | 可用性测试 | **待核实** | 无可用性指标与用户测试记录 |
+| 16 | 无障碍测试 | **未发现** | `tests/**` 无 `aria`/`axe-core` 引用(0 命中) |
+| 17 | 测试覆盖率 | **已实测(部分未达标)** | cfc-web Lines **9.95%** / Branch 6.06% / Funcs 7.48%(<20% 不达标);cfc-frontend Lines **53.57%** / Branch 28.96%;**后端无 JaCoCo** |
+| 18 | 质量指标 | **已实测** | 全量 **3790 / 3726 = 98.31%**(剔 skip 98.78%);红 46 / 跳 18;新增 7 例全绿 |
+| 19 | QA 流程 | **待核实(负向证据)** | CI 存在但 `BACKEND_OBSERVED_CLASSES` 漏拦 3 个当前红类 → `backend-blocking-junit` 必然失败 |
+| 20 | 全项目代码审查 | **已实测(抽样)** | 本轮定位 `schema.sql:5354` DDL 无效、`NutritionAgeDosage` 实体/表列不一致、`NutritionProductService:48` 死注入;未做全量逐文件审查(方案排除) |
+
+---
+
+## 4. 执行范围 / 用例总数·通过·失败
+
+| 模块 | 命令 | 总数 | 通过 | 失败 | 跳过 | 结果 |
+|------|------|------|------|------|------|------|
+| **cfc-backend 全量** | `cd cfc-backend && mvn -o -B clean test`(JDK1.8.0_25 + Maven 3.6.1) | **2946** | **2925** | **17** | 4 | **99.29%**(剔 skip 99.42%),**61:02**,`BUILD FAILURE`(预期:红例存量) |
+| **浏览器 admin@189** | `playwright test -c playwright.config.live.js --project=admin-desktop` | 5 | 5 | 0 | 0 | **EXIT 0 ✅ 1.4m** |
+| **浏览器 frontend(本机)** | `--project=frontend-mobile` | 6 | 6 | 0 | 0 | **EXIT 0 ✅ 1.0m** |
+| **浏览器 shop(本机)** | `--project=shop-api` | 4 | 4 | 0 | 0 | **EXIT 0 ✅ 15.4s** |
+| **浏览器 health(本机)** | `-c playwright.config.health.js` | 13 | 13 | 0 | 0 | **EXIT 0 ✅ 14.6s** |
+| **浏览器 dx-bridge(本机)** | `--project=dx-bridge` | 2 | 0 | 0 | 2 | EXIT 0;两端点 **404** → 按设计 skip(B-DX-1 第 16 轮) |
+| **langgraph@251** | `.venv/bin/python -m pytest -q --ignore=tests/qna --ignore=tests/test_chat.py` | 51 | **41** | **10** | 0 | **10 failed / 41 passed / 126.67s**(R155 为 48/3 → **恶化 7 例**) |
+| cfc-web (Jest) | `npx jest --coverage` | 116 | 116 | 0 | 0 | **EXIT 0 ✅ 179.2s**(17 套件) |
+| cfc-frontend (Jest) | `npx jest --coverage` | **624** | **609** | 3 | 12 | EXIT 1;3 红 = 预期 RED(S-cfc-138 AC-R1/R2 + S-cfc-134 RED-A7)集合不变;含本轮新增 7 例;**合入后复验** 47.4s |
+| 根级黑盒 (Jest) | `cd tests && npx jest -c jest.config.js` | 23 | 7 | 16 | 0 | EXIT 1;16 红全 `fetch failed`(本机 9082 未启动,B-36 第 50 轮) |
+| **合计** | — | **3790** | **3726** | **46** | **18** | **98.31%**(剔 skip 98.78%) |
+
+**红例分布(46)**:后端 17 + 根级 16 + langgraph 10 + 前端 3。
+
+---
+
+## 5. 关键变化(vs R155)
+
+| 维度 | R155 | **R156** | 变化 |
+|------|------|----------|------|
+| 后端全量 | 采信 R154:2946/2925/17 | **实跑:2946/2925/17(347 类,61:02)** | ✅ 零漂移(第 14 次),采信期无漏检 |
+| langgraph@251 | 48 过 / 3 红 | **41 过 / 10 红** | ❌ **恶化 7 例**(唯一实质变化) |
+| 浏览器 | 28/28 + 2 skip | **28/28 + 2 skip** | ✅ 零漂移 |
+| cfc-web | 采信 116/116 | **实跑 116/116** | ✅ 零漂移 |
+| 前端功能合入 | — | **`3d35ab714` 会员门控(10 文件)** | ⚠️ 跑测窗口内落库 → 已做增量复验 + 补 7 例(§5.1) |
+| cfc-frontend | 采信 602/3/12 | **实跑 609/3/12(624 总)** | ✅ 零漂移 + 新增 7 例全绿(3 红集合不变) |
+| 根级黑盒 | 7/16 | **7/16** | 持平(B-36 第 50 轮) |
+| 全量通过率 | 98.91%(R155 口径) | **98.31%**(3790/3726) | ❌ 下行,全部由 langgraph 承担(分母 +7 为新增用例) |
+| 门禁结论 | 有条件通过 | **不通过** | 收紧(G7 由 ✅ 改善态回落为 ❌ 阻断) |
+
+### 5.1 跑测窗口内功能合入 → 增量复验(新增)
+
+跑测期间远端合入 `3d35ab714 merge(miniprogram): 聊天/消息类入口按有效会员隐藏`(`cfc-frontend` 10 文件 +124/−29,含新文件 `utils/membershipGate.js`)。按纪律**不把窗口内合入当成「零变更」**,收尾 rebase 至 `c7d921bcf` 后重跑前端全量:
+
+| 项 | 结果 |
+|---|---|
+| 前端全量复验 | **624 例 / 609 过 / 3 红 / 12 跳**(47.4s,EXIT 1) |
+| 红例集合 | `signature.consignee`(AC-R1/AC-R2)+ `growthHistory.dayGroupView`(RED-A7)—— **与合入前完全一致 → 功能合入零回归** |
+| 覆盖率变化 | Lines 53.57% → **53.57% 同档**;Stmts 46.16→**46.25**、Branch 28.96→**29.16**、Funcs 18.75→**18.95**(新用例带来的小幅提升) |
+| 新增用例 | `cfc-frontend/__tests__/utils/membershipGate.test.js` **7 例(TC-MG-U01~U07)全绿** |
+| 覆盖缺口闭合 | `membershipGate.js` 合入时**零测试、零用例编号**;本轮补齐 4 条契约分支(无 token 不发请求 / `isActive===true` / 非布尔真值不误放行 / 异常 fail-closed) |
+
+> 补测设计要点:该函数唯一判据是 `data.isActive === true`(**严格等值**),所以专门加了 `isActive: 1` 与 `isActive: 'true'` 两个反向用例——若后端把布尔退化成数字/字符串,用例会立刻转红而不是**静默放行非会员**。
+
+---
+
+## 6. langgraph 10 红根因定性(**环境红,非代码回归**)
+
+| 失败文件 | 例数 | 失败表征 | 日志证据 |
+|---|---|---|---|
+| `tests/test_analyze.py` | 1 | `test_analyze_missing_report` → `assert 500 == 200` | `RateLimitError 429 AgnesAI_error`(analyze 3.66s) |
+| `tests/test_auto_tag.py` | 5 | `endpoint_responds` / `valid_format` / `content_relevance` / `short_content` / `empty_content` → `assert 500 == 200` | 每次 chat 调用 9~10s 后抛 429 |
+| `tests/test_intent.py` | 4 | `classify_analysis/recommend/mind/health` → `assert <Intent...>` ≠ 期望 | `intent_classifier.py:62` 429 后**静默兜底 `chat`**(B-134-4 延续未修) |
+
+- **上游原文**:`"You have used up today's text quota and are now limited to 1 request every 3 minutes."` / `"You've reached the API rate limit for free users."`(429,AgnesAI)。
+- **叠加 401**:`chat_graph.py:148 召回记忆失败: 401 Authentication Fails, Your api key: ****ab12 is invalid`(记忆召回 key 失效,非本轮新增)。
+- **服务本身健康**:同窗口 `251:9000/health` = **200**;说明「服务活、仅 LLM 面被配额掐断」——**不可用单一指标否定另一面**。
+- **结论**:10 红全部落在 LLM 调用面,**无一条为代码回归**;但按门禁纪律**红例即红例**,G7/G2 照实判 ❌。
+
+---
+
+## 7. SRS/需求变更感知(G12)
+
+| 检查项 | 结果 |
+|---|---|
+| `docs/superpowers/specs/*.md` | **201** 份,窗口 `abf53aa0d..722de8f37` **零变更** |
+| `tests/test-cases/*.md` | **15** 份,零变更 |
+| `docs/superpowers/api/API_REFERENCE.md` | 零变更 |
+| 场景/用例度量(官方脚本 `test_report_metrics.py --scene`) | 场景 **215**;映射到 TC **155 = 72.1%**;场景 ID 字面出现在 spec **33 = 15.3%**;TC **837**;异常流 TC **498 = 59.5%**;有可执行锚点 **104**(扫描资产 523) |
+| 场景缺口台账 | `docs/tdd/test/scenario-gap-backlog.csv` **98** 条缺口(A 真缺口·需补用例为主) |
+| 实现落地(非 SRS 文档变更) | **1 项**:`3d35ab714` 会员门控(`utils/membershipGate.js` + 9 个页面入口),合入时**零测试** → 本轮补 **7** 条用例(TC-MG-U01~U07) |
+| 判定 | **G12 ✅ 合规**:SRS 文档零变更 → 不因文档变更改用例;**实现变更按纪律补用例**(7 条,见 §5.1);`admin.referral`(TR-25)仍为零用例零锚点(遗留) |
+
+---
+
+## 8. 五要素问题清单
+
+### ① 后端 17 红存量(P0 · 研发)
+- **① 问题描述**:`mvn clean test` 全量 2946 例中 16F+1E,10 个类;其中 `UserServiceWechatLoginTest`、`UserServiceWechatLoginContractTest`、`TeamProfitCronContractTest` **不在 CI 排除清单**内。
+- **② 测试 bug 点**:`cfc-backend/target/surefire-reports/`:`EnergySystemFlowTest`(7例/6F)、`DimensionRegistryMapContractTest`(7/3F)、`GuideModuleIntegrationTest`(4/1E)、`OrchestrationEngineTest`(8/1F)、`OrchestrationIntegrationTest`(7/1F)、`MembershipPaySwitchTest`(6/1F)、`PaymentServiceORDRoutingTest`(3/1F)、`UserServiceWechatLoginTest`(5/1F)、`UserServiceWechatLoginContractTest`(6/1F)、`TeamProfitCronContractTest`(22/1F)。
+- **③ 最优修改方案**:按类归因修:① 集成夹具类(EnergySystem/GuideModule)改为 `@Transactional` 回滚 + 固定种子数据;② 契约类(DimensionRegistryMap/WechatLoginContract/TeamProfitCron)由产品裁决契约后同步实现与断言;③ 装置类(Orchestration/MembershipPay/PaymentORD)去 `Thread.sleep`、外部调用打桩。
+- **④ 修改目的**:消除长期红底噪,使 G13(≤17)可收敛至 0,并为 G2(红例 ≤20)腾出额度。
+- **⑤ 闭环**:修后 `mvn -o -B clean test` 该 10 类 0 红 + 全量 0 红,连续 2 轮零漂移 → 销号。
+
+### ② CI 硬门禁漏拦 3 个红类(P0 · 研发,B-152-1 延续)
+- **① 问题描述**:`.gitlab-ci.yml` 的 `BACKEND_OBSERVED_CLASSES`(33 类)未包含本轮实测红类 `UserServiceWechatLoginTest`、`UserServiceWechatLoginContractTest`、`TeamProfitCronContractTest`。
+- **② 测试 bug 点**:`.gitlab-ci.yml:61`。
+- **③ 最优修改方案**:把上述 3 类加入 `BACKEND_OBSERVED_CLASSES`;或更优——改为「运行期生成红类快照」而非静态白名单。
+- **④ 修改目的**:让 `backend-blocking-junit` 从「必然失败」变为可信门禁,恢复 G11。
+- **⑤ 闭环**:CI 流水线跑绿一次 + 人为移除一类实现使其红、验证门禁能拦住 → 双证销号。
+
+### ③ CI 排除清单含 26 个已转绿类(P1 · 研发,B-152-2 延续)
+- **① 问题描述**:33 类白名单中 **26 类**本轮实测全绿(如 `AuthControllerTest` 239s 全绿、`ProductControllerTest`、`StatsControllerTest`、`WishControllerTest` 等),仍被永久排除 → 硬门禁覆盖被人为缩小。
+- **② 测试 bug 点**:`.gitlab-ci.yml:61`(与 ② 同一行,缺陷方向相反)。
+- **③ 最优修改方案**:按 R156 实测快照重建白名单(仅保留 10 个红类),并把「白名单衰减」写入 CI 注释要求每轮复核。
+- **④ 修改目的**:恢复这 26 类的 CI 阻断力,避免「绿了也测不到」。
+- **⑤ 闭环**:清单重建后 CI 一次跑绿 + 抽查 3 类故意改坏能拦住。
+
+### ④ `nutrition_age_dosage` 三重不一致(P2 · 研发,B-145-1 未修 + B-156-1 新增)
+- **① 问题描述**:`schema.sql:5354` 建表语句含 `INDEX idx_product (product_id)`,而表定义**没有 `product_id` 列** → 建表恒失败;本轮 34 次 Spring 上下文启动中 **34/34 失败**(`SQLSyntaxErrorException: Key column 'product_id' doesn't exist`),`DatabaseInitializer` catch 后仍打「数据表检查完成」,**该表从未创建成功**。追加发现:实体 `NutritionAgeDosage` 声明 `updateTime`(→ `update_time`),而 DDL 无此列;`NutritionProductService:48` 注入 `ageDosageMapper` 但**全类零调用**(死注入)。
+- **② 测试 bug 点**:`cfc-backend/src/main/resources/schema.sql:5354`;`cfc-backend/src/main/java/com/etotem/cfc/entity/NutritionAgeDosage.java:33-34`;`cfc-backend/src/main/java/com/etotem/cfc/service/NutritionProductService.java:48`。
+- **③ 最优修改方案**:① 删 `INDEX idx_product (product_id)`(或补 `product_id BIGINT` 列);② DDL 补 `update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`;③ 按 AGENTS.md 纪律在 `DatabaseInitializer.runMigrations()` 增加幂等迁移(`ensureColumn("nutrition_age_dosage","update_time",…)`),**并同步 schema.sql**;④ 死注入删除或补齐调用方。
+- **④ 修改目的**:消除每次启动必现的 DDL 异常(也污染全量日志与耗时);同时避免「表建好后运行期 `Unknown column 'update_time'`」的第二层失败。
+- **⑤ 闭环**:`grep -c SQLSyntaxErrorException` 归零 + 启库后 `SHOW CREATE TABLE nutrition_age_dosage` 成功 + 剂量建议接口实调 200 → 销号。
+
+### ⑤ langgraph 10 红(P0 · 运维 + 研发,B-142-2 恶化 / B-134-4 未修)
+- **① 问题描述**:51 例 10 红,全部为 LLM 面 429(免费额度耗尽)+ 401(记忆召回 key 失效);`intent_classifier.py:62` 把 429 静默兜底成 `chat`,使 4 条分类用例从「上游故障」伪装成「分类错误」。
+- **② 测试 bug 点**:`tests/test_analyze.py::test_analyze_missing_report`、`tests/test_auto_tag.py`(5 例)、`tests/test_intent.py`(4 例);`cfc-langgraph/app/agents/intent_classifier.py:62`;`app/graphs/chat_graph.py:148`。
+- **③ 最优修改方案**:① 运维为 251 的 AgnesAI key 提额/换付费 key;② `intent_classifier` 改为显式降级(抛错或返回 `degraded=true`)而非默认 `chat`;③ 修补 `chat_graph` 记忆召回 key;④ 测试侧为 LLM 依赖用例加 `pytest.mark.env_skip`(429 时 skip 而非 fail),避免环境红污染通过率。
+- **④ 修改目的**:让 langgraph 套件能反映代码质量而非配额状态,恢复 G7(≥46/51)。
+- **⑤ 闭环**:连续 2 轮 51/51 全绿(或红例全为显式 env_skip)→ 销号。
+
+### ⑥ 根级黑盒 16 红:本机 9082 不可达(P1 · 测试装置,B-36 第 50 轮)
+- **① 问题描述**:`tests/` 根级 Jest 23 例中 16 红,全部 `fetch failed`(`/api/admin-auth/login-by-password`、`/api/guide/plans/family-list`、`/api/admin/tasks/stats` 等直连 `127.0.0.1:9082`)。
+- **② 测试 bug 点**:`tests/integration/plan-chain.spec.js`、`tests/integration/mini-games-api.spec.js`。
+- **③ 最优修改方案**:加 `beforeAll` 探活 9082,不可达则 `describe.skip` 并输出 `BACKEND_UNAVAILABLE`(与 dx-bridge 的 404→skip 同构);或在 CI 中以 service 容器拉起后端后再跑。
+- **④ 修改目的**:把「环境缺失」与「功能失败」分离,避免 16 条永久红把通过率压低 0.4pt 且掩盖真实回归。
+- **⑤ 闭环**:无后端时 16 例转 skip(红 0);有后端时全绿 → 双态各验一次销号。
+
+### ⑦ 前端 3 红(P2 · 研发,预期 RED)
+- **① 问题描述**:`signature.consignee` 2 例(AC-R1 确认回调方法缺失、AC-R2 模板缺 `HandSignature` 段)、`growthHistory.dayGroupView` 1 例(RED-A7:3 条无效日期记录中 1 条未被跳过,`flat.length` 实测 **7**、期望 **6**)。
+- **② 测试 bug 点**:`cfc-frontend/__tests__/pages/signature/signature.consignee.test.js`、`cfc-frontend/__tests__/pages/growth-main/growthHistory.dayGroupView.test.js:287`。
+- **③ 最优修改方案**:① 交付 `consignee-edit.vue` 的确认回调与 `HandSignature` 内嵌段;② `groupByDate` 对 `checkinDate` 解析失败且无 `recordDate` 兜底的记录直接跳过(不改写输入)。
+- **④ 修改目的**:让契约测试转绿,同时修掉「脏日期记录泄漏进分组」的真实体验缺陷。
+- **⑤ 闭环**:前端 jest 3 红→0 且连 2 轮 0 红 → 销号(S-cfc-138 / S-cfc-134)。
+
+### ⑧ 管理端匿名访问鉴权门缺失(P1 · 安全,B-142-1 延续未修)
+- **① 问题描述**:匿名 `POST /api/admin/families/overview` → **HTTP 200 + body `code:400`**(`请求参数格式错误`);对照组 `/api/energy/overview` 等 5 个接口均 401。说明 `/api/admin/**` 未纳入 JWT 强校验,仅靠参数校验拦住。
+- **② 测试 bug 点**:`cfc-backend/src/main/java/com/etotem/cfc/config/JwtInterceptor.java`(`LOGIN_REQUIRED_PATHS` 未覆盖 `/api/admin/`)。
+- **③ 最优修改方案**:`LOGIN_REQUIRED_PATHS` 增 `/api/admin/`,admin 族控制器补 `role=admin` 校验;补一条「匿名 → 401/403」浏览器/接口契约用例。
+- **④ 修改目的**:消除越权面;顺带把「200 + 业务错误码」这种伪正常态变成可断言的红线。
+- **⑤ 闭环**:匿名探测返回 401/403(非 200)+ 新增契约用例常绿 → 销号。
+
+### ⑨ 后端全量耗时 61:02 的装置放大(P3 · 效率,B-152-3 延续)
+- **① 问题描述**:347 类耗时 61:02,其中 **34 次** `@SpringBootTest` 上下文启动,每次重跑 `DatabaseInitializer` 全量迁移(日志 `DatabaseInitializer` 命中 10715 行、`cfc-scheduler` 22365 行 = 全日志 75346 行的 **29.7%**);最慢类 `UserServiceFamilyNameLinkTest` 331s、`GuidePackageServiceTest` 307s、`GuideRolePermissionTest` 258s、`AuthControllerTest` 239s。
+- **② 测试 bug 点**:`CfcApplication:12 @EnableScheduling` + 缺 `src/test/resources/application-test.yml`(无 `spring.task.scheduling.pool.size=1` 与 `DatabaseInitializer` 开关)。
+- **③ 最优修改方案**:① 测试 profile 关闭 `DatabaseInitializer` 与 `@EnableScheduling`;② 统一 `@SpringBootTest(webEnvironment=NONE)` + `@DirtiesContext` 策略合并上下文;③ 引入 JaCoCo 顺带产出覆盖率。
+- **④ 修改目的**:把全量从 61 分钟压回 30 分钟量级,让全量可在 CI 每提交运行(G11 前置条件),并解锁 G7 后端覆盖率度量。
+- **⑤ 闭环**:连续 2 轮全量 <35:00 且红例集合不变 → 销号。
+
+---
+
+## 9. 覆盖缺口清单
+
+| 缺口 | 现状 | 风险 | 建议测试设计 | 优先级 | 闭环方式 |
+|---|---|---|---|---|---|
+| 后端覆盖率不可度量 | `pom.xml` 无 JaCoCo(0 命中) | 无法证明单测有效性 | 接 jacoco-maven-plugin + 阈值门禁 | **P0** | 出首份报告并设 `line≥60%` 门禁 |
+| cfc-web 覆盖率 | Lines 9.95% / Branch 6.06% | 管理端回归靠人眼 | 按 `views/**` 高价值页补组件测试 | P1 | 覆盖率 ≥20% 连续 2 轮 |
+| 场景→用例映射 | 215 场景,映射 TC 155(72.1%),有锚点 104 | 40 条场景无自动化 | 按 `scenario-gap-backlog.csv` 98 条逐条补 | P1 | 映射率 ≥90% |
+| 安全测试 / 依赖漏洞 | 未授权未执行(0 配置) | 漏洞不可见 | semgrep + OWASP dependency-check(需联网授权) | P1 | 高危 0 |
+| 性能 / 可靠性 | 无脚本 | 全量耗时劣化无基线 | k6 冒烟 + `/health` P95 基线 | P2 | 基线入库 + 回归对比 |
+| 兼容性 / 无障碍 | chromium 单浏览器、无 axe | 小程序机型/无障碍盲区 | Playwright 多 viewport + axe-core 冒烟 | P2 | 3 viewport × 关键 5 页 |
+| 探索性测试 | 无 charter | 脚本外缺陷遗漏 | 每轮 1 个 30 分钟 charter 并落记录 | P3 | charter + 缺陷单双证据 |
+| `admin.referral`(TR-25) | 0 用例 0 锚点 | 功能黑盒 | 补接口契约 + 后台页面 E2E | P2 | 2 条用例常绿 |
+| 会员门控页级 E2E | 函数级已补 7 例,**页面级 0 例**(9 个入口页未验渲染隐藏) | 入口可见性只在函数层受保护,模板层漏改不会被发现 | Playwright 游客态断言「聊天/消息」入口不可见 + 会员态可见 | P1 | 2 条 E2E 常绿 |
+
+---
+
+## 10. 门禁矩阵(14 条)
+
+| 门 | 阈值 | 本轮实测 | 状态 |
+|----|------|----------|------|
+| G1 全量通过率 | ≥95% | **98.31%** | ✅ |
+| G2 红例数 | ≤20 | **46**(be17 + 根16 + lg10 + fe3) | ❌ |
+| G3 前端预期 RED | 已知 3 | **3** | ✅ |
+| G4 cfc-web 零红 | 0 | **0(实跑 116/116)** | ✅ |
+| G5 编译 | EXIT 0 | **testCompile 353 源 0 错;classes 2330** | ✅ |
+| G6 浏览器 E2E | ≥26/28 | **28/28** | ✅ |
+| G7 langgraph | ≥46/51 | **41/51** | ❌(由 ✅ 回落) |
+| G8 鉴权契约 | 5 端点全 401 | **5/5 = 401** | ✅ |
+| G9 安全/依赖扫描 | 中危 0 | 未授权未执行 | ❌ |
+| G10 节点派发 | ≥1 | **3**(189 + 251 + 本机) | ✅ |
+| G11 CI 固化 | 门禁可信 | **CI 存在但必红**(漏拦 3 类) | ❌ |
+| G12 SRS 变更→用例更新 | 合规 | 零变更 → 零写入 | ✅ |
+| G13 后端红例 | ≤17 | **17** | ⚠️ 临界(零漂移) |
+| G14 dx-bridge | 已部署 | **404** 未部署(2 例 skip) | ❌ |
+
+**门禁结论:⛔ 不通过** —— 正向 G1/G3/G4/G5/G6/G8/G10/G12;阻断 G2/G7/G9/G11/G14;G13 临界。
+较 R155「有条件通过」**收紧**,唯一动因是 langgraph 红例 3→10(G7 由改善态回落)。
+
+---
+
+## 11. 变化点与推送决策
+
+- **测试结果有变化**:langgraph **48 过/3 红 → 41 过/10 红**(恶化 7 例);门禁结论由「有条件通过」转为「不通过」。
+- **其余全部零漂移**:后端 347/2946/2925/17(第 14 次)、浏览器 28/28、cfc-web 116/116、前端 602/3/12、根级 7/16。
+- **新增证据**:`nutrition_age_dosage` 34/34 建表失败(B-145-1 未修)+ 实体 `update_time` 缺列 + 死注入(B-156-1 新);后端全量装置损耗量化(B-152-3 延续)。
+- **决策**:按「测试结果有变化时提交到远程并通知研发」→ **commit + push `origin/cfclub` + 落地研发通知**。
+
+---
+
+## 12. 复评条件
+
+1. **G7**:251 LLM key 提额 / 换付费 key → langgraph 连续 2 轮 ≥46/51 且红例为显式 env_skip。
+2. **G11**:`BACKEND_OBSERVED_CLASSES` 补 3 红类并剔除 26 绿类 → CI 一次跑绿。
+3. **G2/G13**:后端 17 红清零(先修 CI 漏拦的 3 类)。
+4. **G9**:授权联网后跑 semgrep + dependency-check,中危 0。
+5. **G14**:dx-bridge 2 端点上线,2 例转 401/403 断言。
+6. **G7 覆盖率**:后端接 JaCoCo 出首份报告;cfc-web ≥20%。
+
+---
+
+## 13. 未实测项(如实登记)
+
+1. **后端覆盖率 / 变异测试**:`pom.xml` 无 JaCoCo、无 PIT → 未实测,只有执行结果无可信覆盖率。
+2. **安全测试(SAST/DAST/渗透)、依赖漏洞扫描**:execute 档需联网授权 → **未授权未执行**(G9 ❌)。
+3. **性能 / 压测 / 可靠性专项**:无脚本、需联网打目标环境 → **未授权未执行**。
+4. **登录态业务流 E2E**:无 `MACHINE_JSON_PATH` 凭据 → 仅做游客态可用性 + 鉴权契约,登录后业务流**待核实**。
+5. **兼容性 / 无障碍**:仅 chromium 单引擎、无 axe → **未发现**资产。
+6. **探索性测试**:无 charter 记录 → **待核实**。
+7. **langgraph 深度链路**(对话/RAG/whisper 全栈 `app.main`):本机不启、生产在 `ai.etotem.com.cn` → 仅验 251 节点最小服务套件。
+
+---
+
+## 附录:本轮命令与日志
+
+```bash
+# 后端全量(实跑,61:02)
+cd d:/cfc/cfc-backend && JAVA_HOME=/d/jdk1.8.0_25 /d/maven/apache-maven-3.6.1/bin/mvn -o -B clean test   # → _r156_backend.log
+# 管理端 / 小程序端 Jest
+cd d:/cfc/cfc-web && npx jest --coverage                                                                  # → _r156_web.log
+cd d:/cfc/cfc-frontend && npx jest --coverage                                                             # → _r156_fe.log
+# 增量复验(窗口内功能合入后)
+cd d:/cfc/cfc-frontend && npx jest __tests__/utils/membershipGate.test.js && npx jest --coverage           # → _r156_fe_inc.log
+# 根级黑盒
+cd d:/cfc/tests && npx jest -c jest.config.js                                                             # → _r156_root.log
+# 浏览器(189 单任务 / 本机单任务串行)
+node docs/tdd/tools/dispatch_189_admin.cjs                                                               # → _r156_189_admin.log
+cd d:/cfc/tests && npx playwright test -c playwright.config.live.js --project=frontend-mobile              # → _r156_e2e_fe.log
+cd d:/cfc/tests && npx playwright test -c playwright.config.live.js --project=shop-api                     # → _r156_e2e_shop.log
+cd d:/cfc/tests && npx playwright test -c playwright.config.health.js                                      # → _r156_e2e_health.log
+cd d:/cfc/tests && npx playwright test -c playwright.config.live.js --project=dx-bridge                    # → _r156_e2e_dx.log
+# langgraph@251
+node _r156_251.cjs kick && node _r156_251.cjs read                                                       # → /tmp/r156_pytest.log
+```

+ 40 - 0
docs/tdd/test/automation-run-2026-11-11-R155.md

@@ -0,0 +1,40 @@
+# 自动化执行记录 · 第 155 轮(2026-11-11 ~22:28 GMT+8)
+
+> 执行档 review(离线 + 内网已授权):未联网装依赖、未启停服务、未改生产代码、未提交;本轮仅新增报告/日志,仓库零源码写入。
+> 基线 `5ee173916`(window `d9866096a..5ee173916` 仅 docs/tdd 报告 + 版本 bump,零测试资产变更)。
+
+## 1. 实测数字(同 R154 口径,零漂移)
+
+| 模块 | 命令 | 结果 |
+|------|------|------|
+| cfc-web | `jest --coverage` | 17套/116例 全绿(EXIT 0,203.7s);Lines 9.95% / Branch 6.06% |
+| cfc-frontend | `jest --coverage` | 617=602过/3红/12跳(EXIT 1,108.7s);3红=预期RED非回归(S-cfc-30/52/53);Lines 53.57% |
+| cfc-backend | `mvn -o test-compile` | EXIT 0(GREEN,离线编译通过) |
+| cfc-backend 全量 | 引用 R154 基线 | 347类/2946例/2925过/17红/99.29%(测试资产零变更,零漂移第13次;MySQL3306 CLOSED 未重跑) |
+| 内网 E2E 探针 | Playwright | /admin 200「浠艾福管理后台」、/frontend 200 2/2 绿 |
+| langgraph | 引用 R154 | 51/47过/4红(429/401,未重跑) |
+
+## 2. 闭环判定
+
+- 回归:cfc-web 116/116、cfc-frontend 602/3/12 与 R154 逐字段一致,红例差集空 → **零漂移,无新增生产回归**。
+- 新增风险:**无**。
+- SRS 闸门:`find -newermt 2026-11-11 22:19` 对 `SRS.md|需求分析|specs|API_REFERENCE` 零命中 → 闭合,**跳过编写测试用例**(仓库零写入)。
+
+## 3. 降级 / 未实测(如实登记)
+
+1. 后端全量 `mvn test`+JaCoCo:MySQL3306 CLOSED 不可达,引用 R154 基线(零漂移第13次)。
+2. 安全·性能·依赖漏洞(execute 档公网未授权)→ 测试设计见主报告 §9。
+3. 登录态 E2E 业务流:无 `MACHINE_JSON_PATH` 凭据 → 待核实登录态测试设计(仅做无登录可达性探针 2/2)。
+4. LangGraph 9000:需 251 节点 + AI 凭据 → 引用 R154 51/47/4红。
+5. P-9:本轮 grep 测试源无外联命中,但 `CFC_OFFLINE` 守卫固化与覆盖率≥20% 仍待办。
+
+## 4. 结论
+
+⛔ **有条件通过**(与 R154 稳态持平,G7 覆盖率仍 ❌)。复评条件见主报告 §10(连库0真红+JaCoCo≥80% / cfc-web覆盖率≥20% / 修P-9 / 授权安全+性能+依赖扫描零高危 / 登录态E2E / CI固化(G11) / admin.referral补测 / LangGraph复验)。
+
+## 5. 交付物
+
+- `docs/tdd/orchestration/report-test-2026-11-11-R155.md`(主报告)
+- `docs/tdd/test/automation-run-2026-11-11-R155.md`(本文件)
+- 实测日志:`_jest_web_r155.log` / `_jest_fe_r155.log` / `_mvn_tc_r155.log` / `_e2e_probe_r155.log` / `_e2e_reach_result.json`
+- 仓库零写入(未改生产源码/测试、未提交、未推送)。

+ 61 - 0
docs/tdd/test/automation-run-2026-11-12-R156.md

@@ -0,0 +1,61 @@
+# 自动化执行记录 · 第 156 轮(2026-11-12 00:50 GMT+8)
+
+> 执行档 review(离线 + 内网已授权):未联网装依赖、未启停服务、未改生产源码/测试。
+> 基线:跑测起点 `722de8f37`;**窗口内远端合入 1 个功能变更** `3d35ab714`(会员门控,cfc-frontend 10 文件 +124/−29),收尾 rebase 至 `c7d921bcf` 并**增量复验前端**。
+> 本轮**全部套件实跑**(无采信):后端 61:02 全量、前端/管理端 Jest、根级黑盒、4 组浏览器、langgraph@251,另加**窗口内合入后的前端增量复验**。
+
+## 1. 实测数字
+
+| 模块 | 命令 | 结果 |
+|------|------|------|
+| cfc-backend 全量 | `cd cfc-backend && mvn -o -B clean test` | **347 类 / 2946 例 / 2925 过 / 16F+1E+4S = 99.29%**,`BUILD FAILURE`(红例存量),**61:02** |
+| cfc-web | `npx jest --coverage` | 17 套 / **116 例全绿**(EXIT 0,179.2s);Lines 9.95% / Branch 6.06% / Funcs 7.48% |
+| cfc-frontend(合入前) | `npx jest --coverage` | 617 = 602 过 / 3 红 / 12 跳(EXIT 1,88.6s) |
+| **cfc-frontend(合入后增量复验)** | `npx jest --coverage` | **624 = 609 过 / 3 红 / 12 跳**(EXIT 1,47.4s);3 红集合不变;Lines 53.57% / Branch 29.16% |
+| **新增用例** | `npx jest __tests__/utils/membershipGate.test.js` | **7/7 全绿**(TC-MG-U01~U07,覆盖 `utils/membershipGate.js`) |
+| 根级黑盒 | `cd tests && npx jest -c jest.config.js` | **23 = 7 过 / 16 红**(EXIT 1,全 `fetch failed` → 本机 9082 未启动,B-36 第 50 轮) |
+| langgraph@251 | `.venv/bin/python -m pytest -q --ignore=tests/qna --ignore=tests/test_chat.py` | **51 例 / 41 过 / 10 红 / 126.67s**(R155 为 48/3,恶化 7) |
+| 浏览器 admin@189 | `--project=admin-desktop` | **5/5(EXIT=0,1.4m)**;节点 HEAD `3c3d4b0a5`、spec blob `4703d73fb` = 本机 |
+| 浏览器 frontend(本机) | `--project=frontend-mobile` | **6/6(EXIT=0,1.0m)** |
+| 浏览器 shop(本机) | `--project=shop-api` | **4/4(EXIT=0,15.4s)** |
+| 浏览器 health(本机) | `-c playwright.config.health.js` | **13/13(EXIT=0,14.6s)** |
+| 浏览器 dx-bridge(本机) | `--project=dx-bridge` | **2 skip**(端点 404,B-DX-1 第 16 轮) |
+| 线上鉴权探针 | 5 个端点匿名 POST | **5/5 = 401**(B-69 维持销号) |
+| 线上 B-142-1 | 匿名 `POST /api/admin/families/overview` | **200 + `code:400`**(第 10 轮未修) |
+| 站点根 | `/` `/admin` `/frontend` | 404 / 302 / 302 |
+
+**合计:3790 例 / 3726 过 = 98.31%**(剔 skip 98.78%);红 46 = 后端 17 + 根级 16 + langgraph 10 + 前端 3;跳 18 = 后端 4 + 前端 12 + dx 2。
+
+## 2. 闭环判定
+
+- **零回归第 14 次**:后端 17 红(10 类)与 R152/R154 逐类逐例一致;前端 3 红集合不变;浏览器 28/28 零漂移。
+- **唯一恶化**:langgraph 3 红 → **10 红**(`test_analyze` 1 + `test_auto_tag` 5 + `test_intent` 4),根因 429 免费额度耗尽 + 401 记忆召回 key 失效 + `intent_classifier.py:62` 静默兜底 → **环境红,非代码回归**。
+- **新发现 B-156-1**:`nutrition_age_dosage` 三重不一致(DDL 无 `product_id` 列却建该索引 → 34/34 上下文建表失败;实体 `updateTime` 无对应列;`NutritionProductService:48` 死注入)。
+- **B-152-1/-2 未修**:CI `BACKEND_OBSERVED_CLASSES` 漏拦 3 个当前红类、仍含 26 个已转绿类。
+- **B-154-1 观察 2/2**:pytest 本轮 126.67s 正常收尾,无 `EXIT=124` 挂起 → 建议销号(但**退出码未落盘**,B-126 问题独立保留)。
+- **SRS 闸门**:specs 201 / test-cases 15 / API_REFERENCE 窗口零变更(G12 合规);但窗口内**实现**有 1 处落地(`3d35ab714` 会员门控)→ 按其覆盖率缺口**新增 7 条用例**(`membershipGate.test.js`),合入时该文件零测试。
+- **增量复验**:合入后前端 624 例 / 609 过 / 3 红,红例集合与合入前一致 → **功能合入零回归**。
+
+## 3. 降级 / 未实测(如实登记)
+
+1. 后端覆盖率与变异测试:`pom.xml` 无 JaCoCo、无 PIT → 未实测。
+2. 安全测试 / 依赖漏洞扫描:execute 档需联网授权 → 未授权未执行(G9 ❌)。
+3. 性能 / 压测 / 可靠性专项:无脚本、需联网 → 未授权未执行。
+4. 登录态业务流 E2E:无 `MACHINE_JSON_PATH` 凭据 → 仅游客态 + 鉴权契约。
+5. 兼容性 / 无障碍:chromium 单引擎、无 axe → 未发现资产。
+6. 探索性测试:无 charter 记录。
+7. langgraph 全栈 `app.main`(对话/RAG/whisper):本机默认不启 → 仅验 251 最小服务套件。
+
+## 4. 结论
+
+⛔ **不通过**(较 R155「有条件通过」收紧):✅G1 98.31% / G3 / G4 116 / G5 / G6 28-28 / G8 5-5 / G10 三节点 / G12;❌G2 46 / **G7 41-51** / G9 / G11 / G14;⚠️G13 17 临界。
+
+## 5. 交付物
+
+- `docs/tdd/orchestration/report-test-2026-11-12-R156.md`(主报告:测试负责人模板 + 20 类矩阵 + 9 条五要素 + 8 项缺口 + 14 门禁)
+- `docs/tdd/test/automation-run-2026-11-12-R156.md`(本文件)
+- `docs/tdd/test/notice-2026-11-12-R156-研发通知.md`(研发交接通知)
+- `cfc-frontend/__tests__/utils/membershipGate.test.js`(**新增 7 例**,TC-MG-U01~U07)
+- `docs/tdd/tools/dispatch_251_pytest.cjs`(改用 `.venv/bin/python` + 退出码先存变量再落盘,修 B-126 诱因)
+- `docs/tdd/test/blockers.md`(新增 B-156-1,更新 B-145-1/B-152-1/B-152-2/B-152-3/B-142-1/B-142-2/B-134-4/B-154-1/B-126/B-36/B-DX-1/B-69)
+- 实测日志:`_r156_backend.log` / `_r156_web.log` / `_r156_fe.log` / `_r156_root.log` / `_r156_189_admin.log` / `_r156_e2e_{fe,shop,health,dx}.log`(工作区,不入库)

+ 20 - 0
docs/tdd/test/automation-status.md

@@ -1373,3 +1373,23 @@
 | 节点 | 189:4090 ✅ / 251:4096 ✅ / 251:9000 ✅ / 204:4090 ✗ | **G10 双节点通过**(B-95 第 23 轮) |
 | CI | `.gitlab-ci.yml:61` 排除清单漏 3 红类、26 绿类未解禁(B-152-1/2 第 3 轮未修) | **G11 ❌** |
 | 门禁 | ❌ **不通过** | G1/G4/G5/G6/G8/G10/G12 ✅;G2/G7/G9/G11 ❌;G3 ⚠️ |
+
+## 附录 R156(2026-11-12 00:50,HEAD `722de8f37`,后端全量实跑 61:02)
+
+| 套件 | 实测 | 备注 |
+|------|------|------|
+| 后端全量 | **347 类 / 2946 例 / 2925 过 / 16F+1E+4S = 99.29%**(**本轮实跑** 61:02,`BUILD FAILURE`) | 与 R152/R154 逐类逐例一致 → **零漂移第 14 次**;采信期(R155)无漏检 |
+| 后端红类 | 10 类 / 17 例 | EnergySystem 6 / DimensionRegistryMap 3 / Orchestration 2 / WechatLogin 2 / MembershipPay 1 / PaymentORD 1 / TeamProfitCron 1 / GuideModule 1E |
+| 基线纯度 | 347 类(surefire XML 347) | 353 测试源编译 0 错、`*.dump` 1、classes 2330;恒等式 `@Test 2935 − @Disabled 4 + 净增 15 = 2946` |
+| 前端 Jest | **624:609 过 / 3 红 / 12 跳**(合入后复验 47.4s) | 3 红仍为预期 RED(AC-R1/AC-R2/RED-A7)集合不变;**新增 7 例(TC-MG-U01~U07)全绿** |
+| 管理端 | 116/116(17 套件,179.2s) | 零漂移;Lines 9.95% / Branch 6.06% |
+| 根级黑盒 | 23:7 过 / 16 红(2 套件) | B-36 第 50 轮(9082 未启动,全 `fetch failed`) |
+| langgraph@251 | **51 例 / 41 过 / 10 红 / 126.67s** | **恶化 7 例**(R155 48/3):analyze 1 + auto_tag 5 + intent 4;429 免费额度耗尽 + 401 `****ab12`;`/health` 200 → 服务活、仅 LLM 面被掐;无 EXIT=124 挂起(B-154-1 观察 2/2) |
+| 浏览器 | **28/28 + 2 skip** | 189 admin **5/5**(1.4m,EXIT=0,spec blob `4703d73fb` = 本机)+ 本机 fe 6 / shop 4 / health 13;dx 2 skip(404) |
+| 全量 | **3790 例 / 3726 过 = 98.31%**(剔 skip 98.78%) | 红 46 = 后端 17 + 根级 16 + langgraph 10 + 前端 3;跳 18 |
+| 新增用例数 | **7** | SRS 文档零变更(G12 合规),但窗口内合入会员门控 `3d35ab714`(`utils/membershipGate.js` 零测试)→ 补 TC-MG-U01~U07 |
+| 场景度量 | 215 场景 / 映射 TC 155 = **72.1%** / 字面 33 = 15.3% / TC 837 / 异常流 498 = 59.5% / 锚点 **104**(资产 523) | 官方脚本 `test_report_metrics.py --scene` |
+| 线上鉴权 | 5/5 匿名 POST → 401 | B-69 维持销号;`/api/admin/families/overview` 匿名 200 + code:400(B-142-1 延续未修) |
+| 节点 | 189:4090 ✅ / 251:4096 ✅ / 251:9000 ✅ | **G10 三节点通过**;204 本轮未探 |
+| CI | `.gitlab-ci.yml:61` 漏 3 红类、含 26 绿类(B-152-1/2 未修) | **G11 ❌** |
+| 门禁 | ❌ **不通过**(较 R155「有条件通过」收紧) | G1/G3/G4/G5/G6/G8/G10/G12 ✅;G2/G7/G9/G11/G14 ❌;G13 ⚠️ 17 |

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

@@ -890,3 +890,21 @@
 | **B-141-3-Update(观察)** | 站点 `/frontedn` 路径 404 | 运维(P3) | **观察**。`/frontedn` = 404、`/admin` = 302、`/frontend` = 302。疑似 nginx 无 `/frontedn` 别名(拼写 typo 用户走错路径)。 | 运维 | 2026-11-11 23:15 | 观察中 |
 | **B-148-1-Update(第 6 轮未复现)** | 网关瞬抖 502 | 运维(P3) | **未复现**。health 套件 13/13,无 502。 | 测试(R155 巡检) | 2026-11-11 23:15 | 观察中 |
 | **B-141-1(延续)** | qna 收集期缺陷 | 研发(P1) | **延续(排除项)**。pytest 口径 `--ignore=tests/qna --ignore=tests/test_chat.py`。 | 测试(R155 实派) | 2026-11-11 23:15 | 待处理 |
+
+| **B-156-1(新)** | `nutrition_age_dosage` 三重不一致 | 研发(P1) | **新登记**。① `schema.sql:5354` 建表含 `INDEX idx_product (product_id)` 但表**无该列** → 本轮 34/34 次 Spring 上下文建表全部失败,**表从未创建成功**;② 实体 `NutritionAgeDosage.java:33-34` 声明 `updateTime`(→`update_time`)而 DDL 无此列 → 即便建表成功仍会 `Unknown column`;③ `NutritionProductService.java:48` 注入 `ageDosageMapper` 但全类**零调用**(死注入)。建议:删索引或补 `product_id` 列 + DDL 补 `update_time` + `DatabaseInitializer.runMigrations()` 加幂等 `ensureColumn` 并同步 schema.sql + 清理死注入。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-145-1-Update(延续未修)** | 建表 SQL 无效 | 研发(P1) | **延续**。`SQLSyntaxErrorException: Key column 'product_id' doesn't exist` 本轮仍 **34 次**(每上下文 1 次),`DatabaseInitializer` catch 后仍打「数据表检查完成」→ 静默掩盖。合并见 B-156-1。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-152-1-Update(延续)** | CI 漏拦当前红类 | 研发(P0) | **未修**。`.gitlab-ci.yml:61` 33 类白名单**缺 3 个本轮实测红类**:`UserServiceWechatLoginTest`、`UserServiceWechatLoginContractTest`、`TeamProfitCronContractTest` → `backend-blocking-junit` 必然失败。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-152-2-Update(延续)** | CI 白名单陈旧 | 研发(P1) | **未修**。33 类中 **26 类本轮实测全绿**(`AuthControllerTest` 239s 全绿、`ProductControllerTest`、`StatsControllerTest`、`WishControllerTest` 等)仍被永久排除 → 硬门禁覆盖人为缩小。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-152-3-Update(延续)** | 测试装置放大全量耗时 | 测试装置(P3) | **延续**。后端全量 **61:02**(347 类):34 次 `@SpringBootTest` 上下文,每次重跑 `DatabaseInitializer` 全量迁移;`DatabaseInitializer` 日志 10715 行、`cfc-scheduler` 22365 行 = 全日志 75346 行 **29.7%**;最慢 `UserServiceFamilyNameLinkTest` 331s / `GuidePackageServiceTest` 307s / `GuideRolePermissionTest` 258s / `AuthControllerTest` 239s。 | 测试 | 2026-11-12 00:50 | 待处理 |
+| **B-142-2-Update(恶化)** | langgraph LLM 上游 429 | 运维(P0) | **恶化:3 红 → 10 红**(51 例 41 过)。`test_analyze` 1 + `test_auto_tag` 5 + `test_intent` 4,全部 `429 免费额度耗尽`(AgnesAI)+ `chat_graph.py:148 401 api key ****ab12 invalid`;同窗口 `/health` 200 → 服务活、仅 LLM 面被掐。**不销号,观察 0/2**。 | 运维 | 2026-11-12 00:50 | 待处理(P0) |
+| **B-134-4-Update(延续)** | 429 静默兜底 chat | 研发(P1) | **未修**。`intent_classifier.py:62` 捕获 429/401 后默认返回 `chat`,把上游故障伪装成分类错误(本轮 4 条 `test_intent` 红即由此产生「像代码错」的假象)。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-142-1-Update(延续未修)** | `/api/admin/**` 鉴权门缺失 | 研发(P1 安全) | **延续**。匿名 `POST /api/admin/families/overview` → **HTTP 200 + body `code:400`**;对照组 5 个 `/api/*` 均 401。**纪律:匿名「200 + 业务错误码」不可判为接口正常**。 | 研发 | 2026-11-12 00:50 | 待处理 |
+| **B-154-1(观察 2/2 → 建议销号)** | pytest 收尾挂起 EXIT=124 | 测试(P3) | **未复现第 2 轮**。langgraph@251 51 例 **126.67s 正常收尾**、无挂起、日志完整 308 行。建议销号;但**退出码未落盘**(见 B-126),销号需连同 B-126 一起验证。 | 测试 | 2026-11-12 00:50 | 观察 2/2(建议销号) |
+| **B-126-Update(仍复现)** | 远程派发退出码未落盘 | 测试装置(P3) | **仍复现**。`/tmp/r156_pytest.log` 无 `EXIT=` 行(308 行以 summary 结尾)。kick 命令虽用 `bash -c '...'` 单引号包裹,`$?` 仍未落盘 → **不能据 summary 判正常退出**,只能据「日志完整 + shell 返回」间接判断。修法待查:改用 `set -o pipefail` + 显式 `; exit_code=$?; echo EXIT=$exit_code`。 | 测试 | 2026-11-12 00:50 | 待处理 |
+| **B-36-Update(第 50 轮零漂移)** | 根级黑盒门控 | 测试(P1 装置) | **零漂移**。23 例 **7 过 / 16 红**,全 `fetch failed`(本机 9082 未启动)。建议 `beforeAll` 探活 → 不可达 `describe.skip` + 打印 `BACKEND_UNAVAILABLE`。 | 测试(R156 实测) | 2026-11-12 00:50 | 待处理(环境型) |
+| **B-DX-1-Update(第 16 轮)** | dx-bridge 端点 404 | 部署(P2) | **延续**。`bridge/list`、`bridge/sync-status` 均 **404**,2 例正确 skip(不假绿)。 | 部署/运维 | 2026-11-12 00:50 | 待处理 |
+| **B-69-Update(维持销号)** | 线上匿名鉴权 | 研发 | **维持销号**。mind/fortune、energy/overview、health/plan/list、huawei-health、xiaomi-health **5/5 = 401**。 | 测试(R156 实测) | 2026-11-12 00:50 | 已解除 |
+| **B-95-Update(延续)** | `204:4090` 失联 | 运维(P2) | **延续**。本轮未探 204(仅用 189:4090 + 251:4096 + 本机),189/251 均在线可用。 | 运维 | 2026-11-12 00:50 | 待处理 |
+| **R156 门禁** | 全量 3790 / 3726 | 测试 | **不通过**(较 R155「有条件通过」收紧)。✅G1 98.31%/G3/G4 116/G5/G6 28-28/G8 5-5/G10 三节点/G12;❌G2 46/**G7 41-51**/G9/G11/G14;⚠️G13 17。唯一动因:langgraph 3→10 红。 | 测试(R156 闭环) | 2026-11-12 00:50 | 已记录 |
+| **B-156-2(新·本轮自处置闭环)** | 会员门控合入零测试 | 测试(P2) | **新登记 + 测试侧自处置**。`3d35ab714` 合入 `cfc-frontend/utils/membershipGate.js`(决定 9 个页面聊天·消息入口可见性)时**零测试、零用例编号**。已补 `cfc-frontend/__tests__/utils/membershipGate.test.js` **7 例(TC-MG-U01~U07,全绿)**:无 token 不发请求 / isActive===true 放行 / isActive===false 拒绝 / data 缺失 fail-closed / 非布尔真值(1 与字符串 true)不误放行 / 接口 reject fail-closed / resolve undefined fail-closed。**未改任何生产代码**。 | 测试 | 2026-11-12 01:05 | 已闭环(函数级) |
+| **B-156-3(新)** | 会员门控缺页级 E2E | 测试(P1) | **新登记**。函数级已有 7 例保护,但 **9 个入口页的模板层隐藏未被验证**(`index-home` / `profile` / `app-library` / `action-detail` / `body-detail` / `mind-detail` / `wisdom-detail` / `ProfileMenu` / `profile/index`)→ 模板漏改不会转红。建议 Playwright 双态断言(游客态入口不可见 + 会员态可见)2 条用例。 | 测试 | 2026-11-12 01:05 | 待处理 |

+ 61 - 0
docs/tdd/test/notice-2026-11-12-R156-研发通知.md

@@ -0,0 +1,61 @@
+# 研发交接通知 · 第 156 轮(2026-11-12 00:50 GMT+8)
+
+> 来源:测试负责人(`cfc-tester`)第 156 轮自动化闭环|基线 `722de8f37`(= `origin/cfclub`,窗口零功能源码变更)
+> 本轮**全部套件实跑**(无采信):全量 **3790 例 / 3726 过 = 98.31%**,红 46 / 跳 18。窗口内合入的会员门控(`3d35ab714`)已做增量复验并补 7 条用例。
+> **门禁结论:⛔ 不通过**(较上轮「有条件通过」收紧)——动因单一:**langgraph 红例 3 → 10**。
+
+## 一、需要研发处置(按优先级)
+
+| # | 编号 | 优先级 | 问题 | 位置 | 建议动作 |
+|---|---|---|---|---|---|
+| 1 | **B-142-2(恶化)** | **P0(运维)** | langgraph@251 **10 红**:`test_analyze` 1 + `test_auto_tag` 5 + `test_intent` 4,全部 `429 免费额度耗尽`(AgnesAI);叠加 `chat_graph.py:148` 记忆召回 `401 api key ****ab12 invalid`。同窗口 `/health` 200,说明服务活、仅 LLM 面被掐 | 运维 / `cfc-langgraph` | ① 为 251 的 key 提额或换付费 key;② 修补记忆召回 key;③ 测试侧对 LLM 依赖用例加 `env_skip`,避免配额红污染通过率 |
+| 2 | **B-152-1(延续)** | **P0(CI)** | `.gitlab-ci.yml:61` `BACKEND_OBSERVED_CLASSES`(33 类)**漏拦 3 个当前红类** → `backend-blocking-junit` 必然失败 | `.gitlab-ci.yml:61` | 补入 `UserServiceWechatLoginTest` / `UserServiceWechatLoginContractTest` / `TeamProfitCronContractTest`;更优:改为运行期生成红类快照 |
+| 3 | **B-152-2(延续)** | P1(CI) | 同一清单中 **26 类已转绿仍被排除**(`AuthControllerTest` 239s 全绿、`ProductControllerTest`、`StatsControllerTest`、`WishControllerTest` 等)→ 硬门禁覆盖被人为缩小 | `.gitlab-ci.yml:61` | 按本轮实测快照重建白名单(只保留 10 个红类) |
+| 4 | **B-156-1(新)/ B-145-1(未修)** | P1(数据) | `nutrition_age_dosage` **三重不一致**:① `schema.sql:5354` 建表含 `INDEX idx_product (product_id)` 但表无该列 → **34/34 次启动全部建表失败**,表从未创建;② 实体 `NutritionAgeDosage.updateTime`(→`update_time`)DDL 无此列 → 表建好后仍会 `Unknown column`;③ `NutritionProductService:48` 注入 `ageDosageMapper` 但**全类零调用**(死注入) | `schema.sql:5354`、`entity/NutritionAgeDosage.java:33-34`、`service/NutritionProductService.java:48` | 删索引行或补 `product_id` 列;DDL 补 `update_time`;按 AGENTS.md 在 `DatabaseInitializer.runMigrations()` 加幂等 `ensureColumn` 并同步 schema.sql;清理死注入 |
+| 5 | **B-142-1(延续未修)** | P1(安全) | `/api/admin/**` 鉴权门缺失:匿名 `POST /api/admin/families/overview` → **HTTP 200 + `code:400`**(对照组 5 个 `/api/*` 均 401) | `config/JwtInterceptor.java` | `LOGIN_REQUIRED_PATHS` 增 `/api/admin/`;admin 族补角色校验;补「匿名→401/403」契约用例 |
+| 6 | **B-134-4(延续未修)** | P1 | `intent_classifier.py:62` 429/401 后**静默兜底 `chat`**,把上游故障伪装成分类结果 → 4 条分类用例红得「像代码错」 | `cfc-langgraph/app/agents/intent_classifier.py:62` | 改为显式降级(抛错或 `degraded=true`),由路由层决定 |
+| 7 | **B-36(第 47 轮)** | P1(测试装置) | `tests/` 根级黑盒 **16 红**,全 `fetch failed`(直连 `127.0.0.1:9082` 未启动)→ 长期压低通过率 0.4pt 且掩盖真实回归 | `tests/integration/plan-chain.spec.js`、`mini-games-api.spec.js` | 加 9082 探活:不可达则 `describe.skip` 并打印 `BACKEND_UNAVAILABLE`(与 dx 的 404→skip 同构);或 CI 用 service 容器拉后端 |
+| 8 | **前端 3 红(预期 RED)** | P2 | `signature.consignee` 2 例(AC-R1 确认回调缺失 / AC-R2 模板缺 `HandSignature` 段)+ `growthHistory.dayGroupView` RED-A7 1 例(3 条脏日期记录中 1 条未被跳过,`flat.length` 实测 **7** / 期望 **6**) | `__tests__/pages/signature/signature.consignee.test.js`、`__tests__/pages/growth-main/growthHistory.dayGroupView.test.js:287` | 交付 `consignee-edit.vue` + `HandSignature` 段;`groupByDate` 对解析失败且无 `recordDate` 的记录直接跳过 |
+| 9 | **B-152-3(延续)** | P3(效率) | 后端全量 **61:02**:34 次 `@SpringBootTest` 上下文,每次重跑 `DatabaseInitializer` 全量迁移(`DatabaseInitializer` 10715 行、`cfc-scheduler` 22365 行 = 全日志 29.7%);最慢类 `UserServiceFamilyNameLinkTest` 331s、`GuidePackageServiceTest` 307s、`GuideRolePermissionTest` 258s、`AuthControllerTest` 239s | `CfcApplication:12`、缺 `src/test/resources` profile | 测试 profile 关 `DatabaseInitializer` 与 `@EnableScheduling`;统一 `webEnvironment=NONE` 合并上下文;接 JaCoCo 顺带出覆盖率 |
+
+## 二、后端 17 红(10 类,与 R152/R154 逐类逐例一致 → 零回归第 14 次)
+
+| 类 | 例数 | 归因 |
+|---|---|---|
+| `integration.EnergySystemFlowTest` | 6F + 1S | 集成夹具 |
+| `integration.controller.DimensionRegistryMapContractTest` | 3F | 契约待裁决(P-9) |
+| `integration.GuideModuleIntegrationTest` | 1E | 集成夹具 |
+| `orchestration.OrchestrationEngineTest` / `OrchestrationIntegrationTest` | 1F + 1F | 装置 |
+| `service.MembershipPaySwitchTest` / `PaymentServiceORDRoutingTest` | 1F + 1F | 装置 |
+| `service.UserServiceWechatLoginTest` / `UserServiceWechatLoginContractTest` | 1F + 1F | **CI 漏拦(#2)** |
+| `unit.TeamProfitCronContractTest` | 1F | **CI 漏拦(#2)** |
+
+## 三、本轮测试结果速览
+
+| 套件 | 结果 |
+|---|---|
+| 后端全量(实跑 61:02) | 347 类 / 2946 例 / **2925 过 / 17 红 / 4 跳 = 99.29%** |
+| langgraph@251 | 51 例 / **41 过 / 10 红** / 126.67s |
+| 浏览器 E2E | **28/28**(189 admin 5/5 + 本机 fe 6/6、shop 4/4、health 13/13)+ dx 2 skip |
+| cfc-web Jest | **116/116**(Lines 9.95%) |
+| cfc-frontend Jest | **624 = 609 过 / 3 红 / 12 跳**(合入后复验;3 红=预期 RED 集合不变;含新增 7 例) |
+| 根级黑盒 | 23 = 7 过 / **16 红**(9082 未启动) |
+| 合计 | **3790 例 / 3726 过 = 98.31%**(剔 skip 98.78%) |
+
+## 四、未实测项(不影响上述结论,但请知悉)
+
+- 后端覆盖率/变异:`pom.xml` 无 JaCoCo、无 PIT → **无覆盖率数据**。
+- 安全/依赖漏洞扫描、性能压测:execute 档需联网授权 → **未授权未执行**(G9 ❌)。
+- 登录态业务流 E2E:无凭据 → 仅游客态 + 鉴权契约。
+- 兼容性/无障碍/探索性:无资产 → **待核实**。
+
+## 五、复评入口
+
+1. langgraph ≥46/51 连续 2 轮(#1)→ 恢复 G7;
+2. CI 白名单重建后跑绿一次(#2/#3)→ 恢复 G11;
+3. 后端 17 红清零(含 CI 漏拦 3 类)→ G13/G2;
+4. 授权联网后跑 semgrep + dependency-check,中危 0 → G9;
+5. dx-bridge 2 端点上线,2 例转 401/403 → G14。
+
+> 完整报告:`docs/tdd/orchestration/report-test-2026-11-12-R156.md`
+> 阻塞台账:`docs/tdd/test/blockers.md`

+ 3 - 1
docs/tdd/tools/dispatch_251_pytest.cjs

@@ -35,7 +35,9 @@ async function sh(cmd, capMs) {
 (async () => {
   const mode = process.argv[2] || 'kick';
   if (mode === 'kick') {
-    const inner = "cd " + DIR + " && python -m pytest -q --ignore=tests/qna --ignore=tests/test_chat.py > " + LOG + " 2>&1; echo EXIT=$? >> " + LOG;
+    // R156 修:251 系统 /usr/bin/python 无 pytest,必须用节点 venv(.venv/bin/python → python3.11);
+    // 退出码另存变量后再写盘(B-126:$? 直接内联在 kick 串里可能落盘失败)。
+    const inner = "cd " + DIR + " && .venv/bin/python -m pytest -q --ignore=tests/qna --ignore=tests/test_chat.py > " + LOG + " 2>&1; rc=$?; echo EXIT=$rc >> " + LOG;
     const cmd = "rm -f " + LOG + "; setsid nohup bash -c '" + inner + "' >/dev/null 2>&1 & echo KICKED";
     const r = await sh(cmd, 40000);
     console.log('KICK=' + JSON.stringify(r).slice(0, 400));