فهرست منبع

test(tdd): 补齐 docs/tdd 台账与 14 份巡检报告(第 11–17 轮积压送达)

- 重写 rolling 巡检报告 tdd-inspection-report.md:20 类覆盖矩阵 + 12 项缺口 + P1–P23 五要素 + 12 条门禁
- 刷新 discovery/inventory/automation-status 三份台账(203/1935 handler = 10.49%;2637 用例)
- 归档 14 份 automation-run-*.md(12:25–22:39),补 perf-reliability-review-luocheng.md 与 red-task-investigation.md
- 修正 P9 取证:tests/test-results/.last-run.json 实为 status=failed + failedTests=[],非文件缺失
E2E Test Bot 1 هفته پیش
والد
کامیت
ffd5018a1b

+ 51 - 0
docs/tdd/test/automation-run-2026-11-02-1225.md

@@ -0,0 +1,51 @@
+# TDD 自动化巡检报告 · 2026-11-02 12:25 (GMT+8)
+
+> 触发:定时自动化「执行测试任务」(TDD 多智能体研发测试调度 skill)
+> 执行范围(默认,无人值守):仅离线「发现 / 格式化 / 跟踪」——不派发、不联网、不跑测试执行、不 push 远程。
+> 基线对照:上轮 2026-11-02 11:16 巡检。
+
+## 一、本次执行
+
+| 步骤 | 命令 | 结果 |
+| --- | --- | --- |
+| 单元覆盖发现 | `discover_tests.py --project d:/cfc` | ✅ exit 0 |
+| 跨源总台账 + 自动化状态 | `test_inventory.py --project d:/cfc` | ✅ exit 0(侧车 test-progress.json 已存在未重写) |
+
+## 二、关键数据(含与 11:16 基线对照)
+
+| 维度 | 11:16 基线 | 12:25 本次 | 漂移 |
+| --- | --- | --- | --- |
+| 控制器 / handler | 357 / 1930 | 357 / 1930 | 零漂移 |
+| handler 已覆盖 | 200 (10.4%) | 200 (10.4%) | 零漂移 |
+| 覆盖分布 | c16 / p70 / u270 / nh1 | c16 / p70 / u270 / nh1 | 零漂移 |
+| 测试文件 / @Test | 189 / 1412 | 189 / 1412 | 零漂移 |
+| 多源总台账 | 2598(729md+410PW+47py+1412J+9场景) | 2598(同) | 零漂移 |
+| 已自动化 | 270 | 270 | 持平 |
+| 待自动化 | 738 | 738 | 持平 |
+| 未跟踪 | 988 | 981 | ↓7(正向) |
+| 已执行 | 0 | 0 | 持平 |
+| 通过 | 16 | 22 | ↑6(正向) |
+| 失败 | 4 | 5 | ↑1 |
+| 阻塞 | 0 | 0 | 持平 |
+| CI 接入 | 未接入 | 未接入 | 持平 |
+
+## 三、结论
+
+- **后端 handler 覆盖纹丝不动**:270 个控制器仍零覆盖(含 AdminController 65 方法、DanAssessmentController 29、AdminArticleController 22、TaskController 18)。缺口闭环无推进。
+- **测试资产总数零漂移**:2598 用例/方法,与 11:16 完全一致。
+- **执行证据正向增长**:通过 16→22(↑6)、失败 4→5(↑1)、未跟踪 988→981(↓7)。说明 11:16 后存在交互会话回填了更多执行结果(与 `tdd-inspection-report.md` 12:22 时间戳吻合),属正向进展,但仍是局部回写、非全量执行。
+- **CI 仍未接入**:未发现 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile`,脚本仅本机可跑,无持续回归。
+- **闭环保留阻塞**:`D:\cfc\.workbuddy\dispatch.py` 仍缺失 + 本运行未获联网授权 → 未跑 `--auto`,未伪造引擎(避免误驱 opencode 改生产代码)。
+
+## 四、遗留风险与下一步
+
+1. 270 控制器零覆盖缺口仍在 → 真实闭环需用户放真实 `dispatch.py`(或提供 opencode 发送协议)并**显式授权联网**。
+2. 953/981 条用例执行未跟踪 → 需对既有脚本做全量执行回写,或接入 CI 形成持续回归证据。
+3. CI 未接入 → 建议补充 `.github/workflows` 等流水线,让脚本级自动化真正持续回归。
+
+## 五、产物(已刷新,仅本地 / 团队共享台账)
+
+- `docs/tdd/test/discovery.md`(43.8 KB)· `.tdd/discovery.json`
+- `docs/tdd/test/inventory.md`(193.5 KB)· `.tdd/test-inventory.json`
+- `docs/tdd/test/automation-status.md`(200.5 KB)· `.tdd/test-progress.json`(侧车,未重写)
+- 说明:`.tdd/` 本地私有不推送;`docs/tdd/` 为团队共享台账(本运行未 push 远程)。

+ 57 - 0
docs/tdd/test/automation-run-2026-11-02-1252.md

@@ -0,0 +1,57 @@
+# TDD 自动化巡检报告 · 2026-11-02 12:52 (GMT+8)
+
+> 触发:定时自动化「执行测试任务」(TDD 多智能体研发测试调度 skill)
+> 执行范围(默认,无人值守):仅离线「发现 / 格式化 / 跟踪」——不派发、不联网、不跑测试执行、不 push 远程。
+> 基线对照:上轮 2026-11-02 12:25 巡检。
+
+## 一、本次执行
+
+| 步骤 | 命令 | 结果 |
+| --- | --- | --- |
+| 单元覆盖发现 | `discover_tests.py --project d:/cfc` | ✅ exit 0(耗时 ~7s) |
+| 跨源总台账 + 自动化状态 | `test_inventory.py --project d:/cfc` | ✅ exit 0(耗时 ~3s;侧车 test-progress.json 已存在未重写) |
+
+## 二、关键数据(含与 12:25 基线对照)
+
+| 维度 | 12:25 基线 | 12:52 本次 | 漂移 |
+| --- | --- | --- | --- |
+| 控制器 / handler | 357 / 1930 | 357 / 1930 | 零漂移 |
+| handler 已覆盖 | 200 (10.4%) | 200 (10.4%) | 零漂移 |
+| 覆盖分布 | c16 / p70 / u270 / nh1 | c16 / p70 / u270 / nh1 | 零漂移 |
+| 测试文件 / @Test | 189 / 1412 | 189 / 1412 | 零漂移 |
+| 多源总台账 | 2598(729md+410PW+47py+1412J+9场景) | 2598(同) | 零漂移 |
+| 已自动化 | 270 | 270 | 持平 |
+| 待自动化 | 738 | 738 | 持平 |
+| 未跟踪 | 981 | 981 | 持平 |
+| 已执行 | 0 | 0 | 持平 |
+| 通过 | 22 | 22 | 持平 |
+| 失败 | 5 | 5 | 持平 |
+| 阻塞 | 0 | 0 | 持平 |
+| CI 接入 | 未接入 | 未接入 | 持平 |
+
+## 三、结论
+
+- **全量零漂移**:相较 12:25 基线,所有维度完全一致。自 11:30 后回写的执行证据(通过 22 / 失败 5)本轮未被改写,侧车 `.tdd/test-progress.json`(951 条进度)按纪律未重写、保留历史回填。
+- **后端 handler 覆盖纹丝不动**:270 个控制器仍零覆盖(含 AdminController 65 方法、DanAssessmentController 29、AdminArticleController 22、TaskController 18)。缺口闭环无推进。
+- **CI 仍未接入**:未发现 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile`,脚本仅本机可跑,无持续回归。
+- **闭环保留阻塞**:`config.json` 虽标记 `tdd_mode=closed-loop`,但闭环需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub` 远端,属 execute 档 / 需显式联网授权;无人值守自动化无法取得授权,故未跑 `--auto`,未伪造引擎(避免误驱 opencode 改生产代码)。2 个 RED 任务(`health.report.createReport` / `dan.assessment.getActiveMaterial`,`manual_entry:true`)仍待人工授权后由开发角色走闭环。
+
+## 四、遗留风险与下一步(需用户/团队处置)
+
+1. **覆盖缺口仍为最大风险**:270 控制器零覆盖。真实闭环需用户放真实 `dispatch.py`(或提供 opencode 发送协议)并**显式授权联网**。
+2. **981 条用例执行未跟踪**:需对既有脚本做全量执行回写,或接入 CI 形成持续回归证据。
+3. **CI 未接入**:建议补充 `.github/workflows` 等流水线,让 270 个已脚本化用例真正持续回归。
+4. **配置口径冲突持续**:`config.json` `tdd_mode=closed-loop` 与 skill 文档「CFC 仅发现/跟踪」口径冲突;是否升级派发需用户显式授权(联网+远端推送)。
+
+## 五、产物(已刷新,仅本地 / 团队共享台账)
+
+- `docs/tdd/test/discovery.md`(43.9 KB)· `.tdd/discovery.json`
+- `docs/tdd/test/inventory.md`(193.5 KB)· `.tdd/test-inventory.json`
+- `docs/tdd/test/automation-status.md`(200.5 KB)· `.tdd/test-progress.json`(侧车,未重写)
+- 说明:`.tdd/` 本地私有不推送;`docs/tdd/` 为团队共享台账(本运行未 push 远程)。
+
+## 六、执行边界声明(重要)
+
+本自动化为**无人值守**定时任务,依据「软件测试专家团」专家硬规则与 TDD skill 纪律:
+- 未获方案确认前**不启动任何测试命令执行**;本运行仅做只读扫描(发现/编目),不运行 mvn/pytest/playwright、不派发、不联网、不推送。
+- 如需真正「跑测试 + 闭环派发」,需由用户在交互会话中**显式确认测试方案并授权联网**,且提供可达的 opencode 会话 + 远端推送权限。届时方可升级到 closed-loop。

+ 88 - 0
docs/tdd/test/automation-run-2026-11-02-1332.md

@@ -0,0 +1,88 @@
+# 自动化巡检报告 · TDD 测试任务(2026-11-02 13:34 GMT+8)
+
+> 自动化 ID:`22b6f728-ed4c-473b-9f8d-ebe7f440cc78`
+> 触发:定时自动化 `执行测试任务`(TDD 多智能体研发测试调度 skill)
+> 模式:**无人值守 · 离线「发现 / 格式化 / 跟踪」刷新**
+
+## 一、执行范围与约束(本运行默认)
+
+- 仅离线只读扫描:**`discover_tests.py` + `test_inventory.py`**,不派发、不联网、不跑测试执行、不 push 远程。
+- 依据:无人值守自动化默认范围;且 `D:\cfc\.workbuddy\dispatch.py` 缺失 + 本运行未获联网授权 → 未跑 `--auto`,未伪造派发引擎(避免误驱 opencode 改生产代码)。
+- 安全合规:全程只读,未修改任何源码、未触碰 git、未安装依赖、未输出任何密钥/口令。
+
+## 二、历史基线对照(本次 vs 上次 12:25 自动化轮)
+
+### 后端单元覆盖(discovery)
+
+| 指标 | 12:25 | 本次 13:34 | 漂移 |
+|---|---|---|---|
+| 控制器总数 | 357 | 357 | 0 |
+| handler 方法总数 | 1930 | 1932 | +2 |
+| handler 已覆盖 | 200 (10.4%) | 203 (10.5%) | **+3** |
+| 单元-全覆盖 | 16 | 16 | 0 |
+| 单元-部分覆盖 | 70 | 72 | +2 |
+| 单元-未覆盖 | 270 | 268 | **−2** |
+| 测试文件 | 189 | 192 | +3 |
+| @Test 方法 | 1412 | 1434 | **+22** |
+
+### 多源总台账(inventory)
+
+| 来源 | 12:25 | 本次 13:34 | 漂移 |
+|---|---|---|---|
+| 结构化 md 用例 | 729 | 729 | 0 |
+| Playwright | 410 | 410 | 0 |
+| Python(pytest) | 47 | 47 | 0 |
+| Java @Test | 1412 | 1434 | +22 |
+| 场景文件 | 9 | 9 | 0 |
+| **合计** | **2598** | **2620** | **+22** |
+
+### 自动化 / 执行状态(automation-status 汇总)
+
+| 指标 | 12:25 | 本次 13:34 | 漂移 |
+|---|---|---|---|
+| 已自动化 | 270 | 273 | +3 |
+| 待自动化 | 738 | 738 | 0 |
+| 未跟踪 | 981 | 984 | +3 |
+| 已执行 | 0 | 0 | 0 |
+| 通过 | 22 | 22 | 0 |
+| 失败 | 5 | 5 | 0 |
+| 阻塞 | 0 | 0 | 0 |
+
+## 三、漂移解读
+
+- **正向微增**:12:25 之后至 13:31 的交互会话(`tdd-inspection-report.md` 时间戳 13:31)新增了 ~22 个 Java `@Test` 方法,使覆盖 handler 由 200→203(10.4%→10.5%)、未覆盖控制器 270→268(−2)、部分覆盖 70→72(+2)、测试文件 189→192(+3)。
+- **执行证据持平**:通过 22 / 失败 5 不变——新增测试方法尚未回填执行结果回写(侧车 `test-progress.json` 仍为 11:59,本次未重写,符合脚本「侧车已存在未重写」逻辑)。
+- **零回退**:未出现覆盖下降或文件丢失,数据连续可信。
+
+## 四、CI / 流水线接入
+
+- ⚠ 仍未发现 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile` → 测试脚本**未接入 CI 流水线**,仅本机/本地可跑。
+- 结构化 md 用例 729 条全部待自动化;执行状态大面积「未跟踪」(984 条),覆盖证据薄弱。
+
+## 五、闭环保留阻塞(历史一致)
+
+1. `D:\cfc\.workbuddy\dispatch.py` 仍缺失 → 无法真实派发 opencode 实现使绿(YELLOW);缓存无现成模板、opencode API 协议不可推断,故**未伪造**该引擎。
+2. 本运行未获联网授权 → 未跑 `--auto` 真实闭环;真实闭环仍需用户显式授权联网 + 提供真实 dispatch.py。
+
+## 六、门禁结论(诚实口径)
+
+- **发现 / 跟踪链路健康(达标)**:离线扫描零中断、数据一致、产物已刷新并落盘;无伪造、无越权、无联网。
+- **质量门禁(未通过 · 历史结构性缺口,非本次造成)**:
+  - 后端单测覆盖率 **10.5%**(远低于常规门禁阈值,如 60%+),268 个控制器零覆盖(含 `AdminController` 65 方法、`DanAssessmentController` 29、`AdminArticleController` 22 等高危面)。
+  - **CI 未接入**:脚本级自动化无法持续回归,仅本机可跑。
+  - **执行回写空洞**:953+ 条用例/方法执行状态「未跟踪」,通过/失败证据仅来自少数已回填项。
+- 本运行**未实测**(未跑测试执行、未派发),相关维度严格标注为「未实测」,不写为通过。
+
+## 七、下一步(需用户决策)
+
+- 若需真正推进 TDD 闭环:① 提供真实 `dispatch.py`(或 opencode 发送协议,我写合规适配器);② 显式授权联网执行 `--auto` 闭环(含 git push origin,将二次确认)。
+- 若仅需跟踪覆盖趋势:本发现/跟踪轮次可持续按定时触发,建议补齐 CI 接入方案以降低「仅本机可跑」风险。
+- 全量 20 类测试覆盖矩阵 + 8 域专家审查属交互式任务,需用户在会话中明确授权范围与执行档后触发,不在本无人值守刷新范围内。
+
+## 八、本次产物(已刷新,仅本地/团队台账,未 push)
+
+- `docs/tdd/test/discovery.md`、`.tdd/discovery.json`(13:34)
+- `docs/tdd/test/inventory.md`、`.tdd/test-inventory.json`(13:34)
+- `docs/tdd/test/automation-status.md`(13:34)
+- `docs/tdd/test/automation-run-2026-11-02-1332.md`(本报告)
+- 侧车 `.tdd/test-progress.json` 未重写(仍 11:59,保留既有回写)

+ 70 - 0
docs/tdd/test/automation-run-2026-11-02-1450.md

@@ -0,0 +1,70 @@
+# 自动化巡检报告 — 2026-11-02 14:50 (GMT+8)
+
+> 触发:定时自动化 `执行测试任务`(TDD 多智能体研发测试调度 skill)。
+> 执行范围(默认,无人值守):仅离线「发现 / 格式化 / 跟踪」,不派发、不联网、不跑测试执行、不 push 远程。
+> 脚本时间戳:discover 14:50:15 / inventory 14:50:23。
+
+## 一、本轮执行动作
+
+| 步骤 | 命令 | 结果 |
+|------|------|------|
+| 单元覆盖发现 | `discover_tests.py --project /d/cfc` | ✅ exit 0,已刷新 `docs/tdd/test/discovery.md` + `.tdd/discovery.json` |
+| 跨源总台账 + 自动化状态 | `test_inventory.py --project /d/cfc` | ✅ exit 0,已刷新 `inventory.md` + `test-inventory.json` + `automation-status.md`(侧车未重写,沿用 951 条 progress)|
+
+> 闭环保留阻塞不变:`D:\cfc\.workbuddy\dispatch.py` 仍缺失 + 本运行未获联网授权 → 未跑 `--auto`,未伪造引擎。
+
+## 二、漂移对比(vs 上一轮 13:34)
+
+| 指标 | 13:34 | 14:50 | 变化 |
+|------|-------|-------|------|
+| 控制器总数 | 357 | 357 | 0 |
+| handler 方法总数 | 1932 | 1935 | **+3** |
+| handler 已覆盖 | 203 (10.5%) | 203 (10.5%) | 0 |
+| 覆盖分布 (covered/partial/uncovered/no-handler) | 16/72/268/1 | 16/72/268/1 | 0 |
+| 测试文件数 | 192 | 192 | 0 |
+| Java `@Test` 方法 | 1434 | 1434 | 0 |
+| 多源总台账(用例/方法合计) | 2620 | 2620 | 0 |
+| 结构化 md 用例 | 729 | 729 | 0 |
+| Playwright | 410 | 410 | 0 |
+| Python pytest | 47 | 47 | 0 |
+| 用户场景文件 | 9 | 9 | 0 |
+| 自动化状态:已自动化 | 273 | 273 | 0 |
+| 自动化状态:待自动化 | 738 | 738 | 0 |
+| 自动化状态:未跟踪 | 984 | 984 | 0 |
+| 执行状态:已执行 | 0 | 0 | 0 |
+| 执行状态:通过 | 22 | 22 | 0 |
+| 执行状态:失败 | 5 | 5 | 0 |
+| 执行状态:阻塞 | 0 | 0 | 0 |
+| CI 流水线接入 | 未发现 → 未接入 | 未发现 → 未接入 | 0 |
+
+## 三、漂移解读
+
+- **后端覆盖零漂移**:覆盖率 headline 仍为 10.5%(203/1935);覆盖分布完全不变(268 个控制器零覆盖缺口仍在)。
+- **唯一变化**:handler 方法总数 +3(1932→1935),但覆盖数未增 → 自 13:34 以来后端新增约 3 个 handler 方法且**未附任何测试**,属轻微「覆盖倒退」信号(总口径覆盖率实际微降,仍四舍五入为 10.5%)。
+- **执行证据持平**:通过 22 / 失败 5 / 未跟踪 984,与 13:34 完全一致;本地侧车未重写(仍 11:59 基线),本轮无新增执行回写。
+- **CI 仍缺失**:未检测到 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile`,脚本级自动化仅本机可跑,无持续回归护栏。
+
+## 四、质量门禁诚实口径
+
+- 发现 / 跟踪链路健康(达标):离线扫描可重复、零报错,基线连续可信。
+- 质量门禁**未通过**(历史结构性缺口,非本次造成,本运行未实测):
+  - 后端单测覆盖率 10.5% 远低于常规阈值(建议 ≥ 60%);
+  - 268 个控制器(如 AdminController、DanAssessmentController 等)零测试覆盖;
+  - 729 条结构化 md 用例全部待自动化、未跟踪;
+  - CI 未接入,无法自动回归。
+- 以上维度严格标「未实测」/「未授权未执行」,未写成通过。
+
+## 五、闭环保留阻塞(待用户处置)
+
+真实 TDD 闭环(`--auto` 派发 opencode 实现使绿)仍需用户:
+1. 放置真实 `D:\cfc\.workbuddy\dispatch.py`(或提供 opencode 发送协议由我写合规适配器);
+2. **显式授权联网**(派发会打到 opencode 会话 + 需 `git push origin`)。
+
+未获二者前,本自动化持续仅做「发现 / 格式化 / 跟踪」离线巡检,定期刷新共享台账以跟踪覆盖趋势。
+
+## 六、本轮产物(本地 + 团队台账,未 push)
+
+- `docs/tdd/test/discovery.md`、`.tdd/discovery.json`
+- `docs/tdd/test/inventory.md`、`.tdd/test-inventory.json`
+- `docs/tdd/test/automation-status.md`
+- `docs/tdd/test/automation-run-2026-11-02-1450.md`(本报告)

+ 17 - 0
docs/tdd/test/automation-run-2026-11-02-1512.md

@@ -0,0 +1,17 @@
+# 自动化运行记录 · 2026-11-02 15:12(第七轮)
+
+- **触发**:定时自动化(6255181e-9118-426d-887a-a897c2cbb810),用户指令「@skill:TDD 多智能体研发测试调度 执行实际测试任务」。
+- **执行模式**:只读发现 + 跨源编目(discovery-only)。理由同前六轮(详见 automation memory):`config.json` `tdd_mode=closed-loop` 需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub`,属 execute 档/需显式联网授权;无人值守自动化无法取得授权;与「软件测试专家团」硬规则(未确认方案不跑测试、未授权不联网、不推送)一致;且 TDD skill 对 CFC 的硬边界即「仅发现/跟踪,不创建/不执行测试」。
+- **执行动作**(均只读、离线、不碰 git/源码/侧车进度):
+  1. `discover_tests.py --project d:/cfc` → 刷新 `docs/tdd/test/discovery.md` 与 `.tdd/discovery.json`
+  2. `test_inventory.py --project d:/cfc` → 刷新 `docs/tdd/test/inventory.md`、`docs/tdd/test/automation-status.md`(侧车 `.tdd/test-progress.json` 未重写,保留 951 条既有进度)
+- **关键结果(本轮)**:
+  - 后端:357 控制器 / 1935 handler,已覆盖 203(10.5%)(c16/p72/u268/nh1);192 测试文件 / 1434 @Test(部分 4)。
+  - 跨源总台账 2620 用例/方法(md729/Playwright410/pytest47/Java1434/场景9)。
+  - 自动化状态:已自动化 273、待自动化 738、未跟踪 984、已执行 0、通过 22、失败 5、阻塞 0;CI 流水线**未接入**。
+  - state.json 仍登记 2 个 RED 任务(health.report.createReport / dan.assessment.getActiveMaterial,manual_entry),stage 全为 RED,无 YELLOW/GREEN/DONE 推进。
+- **相对 13:57 基线变化(近零漂移)**:handler +3(1932→1935);已覆盖 203 持平(c16/p72/u268/nh1);总用例 2620 持平;通过 22/失败 5 持平;待自动化 738/未跟踪 984 持平;CI 仍未接入。说明项目新增少量 handler,但「极低单元覆盖 + 无 CI」的总体态势未变。
+- **主要缺口(供后续)**:268 个零测试控制器(AdminController 65、DanAssessmentController 29、AdminArticleController 22、TaskController 18 等高价值后台);729 条 md 用例待补脚本;测试未接 CI。
+- **未实测项**:未运行实际测试执行(discovery-only);2 个 RED 任务闭环需人工授权后由开发角色走 closed-loop(需 alive opencode + mvn 可用 + push origin/cfclub)。
+- **配置冲突待人工裁决(持续)**:`config.json` `tdd_mode=closed-loop` 与 skill「CFC 仅发现/跟踪」口径冲突;是否升级派发需用户显式授权(联网+远端推送)。
+- **未推送**:本自动化未 push `docs/tdd/*.md`(推送属需确认操作,依专家规则保持只读不推送);如需团队共享可手动 `git add docs/tdd/test/ && git push`。

+ 50 - 0
docs/tdd/test/automation-run-2026-11-02-1618.md

@@ -0,0 +1,50 @@
+# 自动化运行台账 · 2026-11-02 16:18(第 8 次)
+
+- **触发**:定时自动化(6255181e-9118-426d-887a-a897c2cbb810),用户指令「@skill:TDD 多智能体研发测试调度 执行实际测试任务」。
+- **模式判定**:维持**只读发现+编目**执行(discovery-only)。理由同前七轮:`config.json` `tdd_mode=closed-loop` 需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub` 远端,属 execute 档/需显式联网授权;无人值守自动化无法取得授权;与「软件测试专家团」硬规则(未确认方案不跑测试、未授权不联网、不推送)一致;且 TDD skill 对 CFC 硬边界=仅发现/跟踪。未静默升级 closed-loop。
+- **执行动作**(均只读、离线、不碰 git 源码、不重写侧车进度):
+  1. `discover_tests.py --project d:/cfc` → 刷新 `docs/tdd/test/discovery.md` 与 `.tdd/discovery.json`(~5s)
+  2. `test_inventory.py --project d:/cfc` → 刷新 `docs/tdd/test/inventory.md`、`docs/tdd/test/automation-status.md`(侧车 `.tdd/test-progress.json` 未重写,保留 951 条既有进度)
+
+## 关键结果(本轮)
+
+- 后端:357 控制器 / 1935 handler,已覆盖 203(10.5%)(c16 / p72 / u268 / nh1);195 测试文件 / 1451 @Test(部分 4)。
+- 跨源总台账 2637 用例/方法(md729 / Playwright410 / pytest47 / Java1451 / 场景9)。
+- 自动化状态:已自动化 276、待自动化 738、未跟踪 987、已执行 0、通过 22、失败 5、阻塞 0;**CI 流水线未接入**(未发现 .github/workflows / .gitlab-ci.yml / Jenkinsfile)。
+- state.json 仍登记 2 个 RED 任务(`health.report.createReport` / `dan.assessment.getActiveMaterial`,`manual_entry`),`stage` 全为 RED,无 YELLOW/GREEN/DONE 推进。
+
+## 相对 15:12 基线变化(正向漂移)
+
+| 维度 | 15:12 | 16:18 | 变化 |
+|---|---|---|---|
+| 测试文件 | 192 | 195 | +3 |
+| @Test | 1434 | 1451 | +17 |
+| 总用例/方法 | 2620 | 2637 | +17(全部 Java) |
+| 已自动化 | 273 | 276 | +3 |
+| 未跟踪 | 984 | 987 | +3 |
+| 已覆盖 handler | 203 (c16/p72/u268/nh1) | 203 (c16/p72/u268/nh1) | 持平 |
+| 待自动化 | 738 | 738 | 持平 |
+| 通过 / 失败 | 22 / 5 | 22 / 5 | 持平 |
+| handler 总数 | 1935 | 1935 | 持平 |
+| CI 接入 | 未接入 | 未接入 | 持平 |
+| RED 任务 | 2(全 RED) | 2(全 RED) | 持平 |
+
+> 说明:项目新增 3 个测试文件 / 17 个 @Test 方法,但**控制器覆盖计数未变**(仍仅 203/1935 handler = 10.5%),新测试未命中此前零覆盖的控制器;「极低单元覆盖 + 无 CI」的总体态势未改变。
+
+## 主要缺口(供后续)
+
+- 268 个零测试控制器(AdminController 65 方法、DanAssessmentController 29、AdminArticleController 22、TaskController 18 等高价值后台)。
+- 729 条 md 结构化用例待补脚本(P0 含认证/文章/勋章/供应商/参数校验等)。
+- 测试未接入 CI 流水线,仅本机可跑,无法持续回归。
+
+## 未实测项
+
+- 未运行实际测试执行(discovery-only);2 个 RED 任务闭环需人工授权后由开发角色走 closed-loop(需 alive opencode + mvn 可用 + push origin/cfclub)。
+
+## 配置冲突待人工裁决(持续)
+
+`config.json` `tdd_mode=closed-loop` 与 skill「CFC 仅发现/跟踪」口径冲突;是否升级派发需用户显式授权(联网 + 远端推送)。
+
+## 未推送
+
+本自动化未 push `docs/tdd/*.md`(推送属需确认操作,依专家规则保持只读不推送);如需团队共享可手动 `git add docs/tdd/test/ && git push`。

+ 15 - 0
docs/tdd/test/automation-run-2026-11-02-1730.md

@@ -0,0 +1,15 @@
+# 自动化执行台账 · 2026-11-02 17:30(第 9 轮)
+
+- **触发**:定时自动化(6255181e-9118-426d-887a-a897c2cbb810),用户指令「@skill:TDD 多智能体研发测试调度 执行实际测试任务」。
+- **模式判定**:维持**只读发现+编目**执行(discovery-only)。理由同前八轮:`config.json` `tdd_mode=closed-loop` 需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub` 远端,属 execute 档/需显式联网授权;无人值守自动化无法取得授权;与「软件测试专家团」硬规则(未确认方案不跑测试、未授权不联网、不推送)一致;且 TDD skill 对 CFC 硬边界=仅发现/跟踪。未静默升级 closed-loop。
+- **执行动作**(均只读、离线、不碰 git 源码、不重写侧车进度):`discover_tests.py` + `test_inventory.py`(刷新 `docs/tdd/test/{discovery,inventory,automation-status}.md` 与 `.tdd/{discovery,test-inventory}.json`)。
+- **关键结果(本轮)**:
+  - 后端:357 控制器/1935 handler,已覆盖 203(10.5%)(c16/p72/u268/nh1);195 测试文件/1451 @Test(部分 4)。
+  - 跨源总台账 2637 用例/方法(md729/Playwright410/pytest47/Java1451/场景9)。
+  - 自动化状态:已自动化 276、待自动化 738、未跟踪 987、已执行 0、通过 22、失败 5、阻塞 0;**CI 流水线未接入**(未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile`)。
+  - state.json 仍登记 2 个 RED 任务(health.report.createReport / dan.assessment.getActiveMaterial,manual_entry),stage 全为 RED,无 YELLOW/GREEN/DONE 推进。
+- **相对 16:18 基线变化**:全维度**零漂移**(控制器/handler/覆盖/测试文件/@Test/总台账/自动化分类/通过/失败/CI/RED 全部一致)。说明自 16:18 以来项目源码与测试资产无新增改动,总体态势仍是「极低单元覆盖(10.5%)+ 无 CI」。
+- **主要缺口(供后续)**:268 个零测试控制器(AdminController 65、DanAssessmentController 29、AdminArticleController 22、TaskController 18 等高价值后台);729 条 md 用例待补脚本;测试未接 CI。
+- **未实测项**:未运行实际测试执行(discovery-only);2 个 RED 任务闭环需人工授权后由开发角色走 closed-loop(需 alive opencode + mvn 可用 + push origin/cfclub)。
+- **配置冲突待人工裁决(持续)**:`config.json` `tdd_mode=closed-loop` 与 skill「CFC 仅发现/跟踪」口径冲突;是否升级派发需用户显式授权(联网+远端推送)。
+- **未推送**:本自动化未 push `docs/tdd/*.md`(推送属需确认操作,依专家规则保持只读不推送);如需团队共享可手动 `git add docs/tdd/test/ && git push`。

+ 15 - 0
docs/tdd/test/automation-run-2026-11-02-1838.md

@@ -0,0 +1,15 @@
+# 自动化执行台账 · 2026-11-02 18:38(第 10 轮)
+
+- **触发**:定时自动化(6255181e-9118-426d-887a-a897c2cbb810),用户指令「@skill:TDD 多智能体研发测试调度 执行实际测试任务」。
+- **模式判定**:维持**只读发现+编目**执行(discovery-only)。理由同前九轮:`config.json` `tdd_mode=closed-loop` 需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub` 远端,属 execute 档/需显式联网授权;无人值守自动化无法取得授权;与「软件测试专家团」硬规则(未确认方案不跑测试、未授权不联网、不推送)一致;且 TDD skill 对 CFC 硬边界=仅发现/跟踪。未静默升级 closed-loop。
+- **执行动作**(均只读、离线、不碰 git 源码、不重写侧车进度):`discover_tests.py` + `test_inventory.py`(刷新 `docs/tdd/test/{discovery,inventory,automation-status}.md` 与 `.tdd/{discovery,test-inventory}.json`)。
+- **关键结果(本轮)**:
+  - 后端:357 控制器/1935 handler,已覆盖 203(10.5%)(c16/p72/u268/nh1);195 测试文件/1451 @Test(部分 4)。
+  - 跨源总台账 2637 用例/方法(md729/Playwright410/pytest47/Java1451/场景9)。
+  - 自动化状态:已自动化 276、待自动化 738、未跟踪 987、已执行 0、通过 22、失败 5、阻塞 0;**CI 流水线未接入**(未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile`)。
+  - state.json 仍登记 2 个 RED 任务(health.report.createReport / dan.assessment.getActiveMaterial,manual_entry),stage 全为 RED,无 YELLOW/GREEN/DONE 推进。
+- **相对 17:30 基线变化**:全维度**零漂移**(控制器/handler/覆盖/测试文件/@Test/总台账/自动化分类/通过/失败/CI/RED 全部一致)。说明自 17:30 以来项目源码与测试资产无新增改动,总体态势仍是「极低单元覆盖(10.5%)+ 无 CI」。
+- **主要缺口(供后续)**:268 个零测试控制器(AdminController 65、DanAssessmentController 29、AdminArticleController 22、TaskController 18 等高价值后台);729 条 md 用例待补脚本;测试未接 CI。
+- **未实测项**:未运行实际测试执行(discovery-only);2 个 RED 任务闭环需人工授权后由开发角色走 closed-loop(需 alive opencode + mvn 可用 + push origin/cfclub)。
+- **配置冲突待人工裁决(持续)**:`config.json` `tdd_mode=closed-loop` 与 skill「CFC 仅发现/跟踪」口径冲突;是否升级派发需用户显式授权(联网+远端推送)。
+- **未推送**:本自动化未 push `docs/tdd/*.md`(推送属需确认操作,依专家规则保持只读不推送);如需团队共享可手动 `git add docs/tdd/test/ && git push`。

+ 49 - 0
docs/tdd/test/automation-run-2026-11-02-1921.md

@@ -0,0 +1,49 @@
+# TDD 自动化巡检报告 · 2026-11-02 19:21 (GMT+8)
+
+> 触发:定时自动化 `执行测试任务`(TDD 多智能体研发测试调度 skill)
+> 执行范围(默认,无人值守):仅离线「发现 / 格式化 / 跟踪」,不派发、不联网、不跑测试执行、不 push 远程。
+
+## 一、发现 / 覆盖(discover_tests.py,exit 0)
+
+| 指标 | 本轮 | 对比 18:12 |
+|---|---|---|
+| 控制器 | 357 | 357(持平) |
+| handler 方法 | 1935 | 1935(持平) |
+| 已覆盖 handler | 203(10.5%) | 203(持平) |
+| 测试文件 | 195 | 195(持平) |
+| `@Test` 数 | 1451 | 1451(持平) |
+| 覆盖分布 | covered=16 / partial=72 / uncovered=268 / no-handler=1 | 完全一致 |
+
+## 二、跨源总台账(test_inventory.py,exit 0)
+
+| 来源 | 文件数 | 用例/方法 | 已自动化 | 待自动化 | 未跟踪 | 已执行 | 通过 | 失败 | 阻塞 |
+|---|---|---|---|---|---|---|---|---|---|
+| 结构化用例(md) | 9 | 729 | 0 | 729 | 729 | 0 | 0 | 0 | 0 |
+| 用户场景(md) | 9 | 0 | 0 | 9 | 9 | 0 | 0 | 0 | 0 |
+| Playwright | 70 | 410 | 70 | 0 | 60 | 0 | 7 | 3 | 0 |
+| Python(pytest) | 11 | 47 | 11 | 0 | 11 | 0 | 0 | 0 | 0 |
+| Java 后端 | 195 | 1451 | 195 | 0 | 178 | 0 | 15 | 2 | 0 |
+| **合计** | — | **2637** | **276** | **738** | **987** | **0** | **22** | **5** | **0** |
+
+- 多源总台账 **2637**(729 md + 410 Playwright + 47 pytest + 1451 Java + 9 场景),与 18:12 持平。
+- 侧车 `test-progress.json` 未重写(仍 11:59,951 条)→ 执行证据来自旧快照,通过/失败不变属预期。
+
+## 三、CI / 流水线接入
+
+- ⚠ 仍未发现 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile` → 测试脚本**未接入 CI**,仅本机可跑。
+
+## 四、闭环阻塞(保留)
+
+- `D:\cfc\.workbuddy\dispatch.py` 仍缺失(`ls` 确认 NO)+ 本运行未获联网授权 → **未跑 `--auto`,未伪造引擎**(避免误驱 opencode 改生产代码)。
+
+## 五、漂移结论
+
+后端覆盖、多源台账、自动化执行状态三方均**零漂移**(与上轮 18:12 完全一致)。仅刷新本地侧车与共享台账(时间戳 19:21)。
+- 268 控制器零覆盖缺口仍在;执行回写仍空洞(已执行 0)。
+- 门禁诚实口径:发现/跟踪链路健康(达标);质量门禁**未通过**(覆盖率 10.5% 不足 + CI 未接入 + 执行回写空洞)——历史结构性缺口,非本次造成;本运行**未实测**,严格标「未实测」。
+
+## 六、产物(仅本地 / 团队台账,未 push)
+
+- `docs/tdd/test/discovery.md`、`.tdd/discovery.json`
+- `docs/tdd/test/inventory.md`、`.tdd/test-inventory.json`
+- `docs/tdd/test/automation-status.md`

+ 49 - 0
docs/tdd/test/automation-run-2026-11-02-2025.md

@@ -0,0 +1,49 @@
+# TDD 自动化巡检报告 · 2026-11-02 20:25 (GMT+8)
+
+> 触发:定时自动化 `执行测试任务`(TDD 多智能体研发测试调度 skill)
+> 执行范围(默认,无人值守):仅离线「发现 / 格式化 / 跟踪」,不派发、不联网、不跑测试执行、不 push 远程。
+
+## 一、发现 / 覆盖(discover_tests.py,exit 0)
+
+| 指标 | 本轮 | 对比 19:21 |
+|---|---|---|
+| 控制器 | 357 | 357(持平) |
+| handler 方法 | 1935 | 1935(持平) |
+| 已覆盖 handler | 203(10.5%) | 203(持平) |
+| 测试文件 | 195 | 195(持平) |
+| `@Test` 数 | 1451 | 1451(持平) |
+| 覆盖分布 | covered=16 / partial=72 / uncovered=268 / no-handler=1 | 完全一致 |
+
+## 二、跨源总台账(test_inventory.py,exit 0)
+
+| 来源 | 文件数 | 用例/方法 | 已自动化 | 待自动化 | 未跟踪 | 已执行 | 通过 | 失败 | 阻塞 |
+|---|---|---|---|---|---|---|---|---|---|
+| 结构化用例(md) | 9 | 729 | 0 | 729 | 729 | 0 | 0 | 0 | 0 |
+| 用户场景(md) | 9 | 0 | 0 | 9 | 9 | 0 | 0 | 0 | 0 |
+| Playwright | 70 | 410 | 70 | 0 | 60 | 0 | 7 | 3 | 0 |
+| Python(pytest) | 11 | 47 | 11 | 0 | 11 | 0 | 0 | 0 | 0 |
+| Java 后端 | 195 | 1451 | 195 | 0 | 178 | 0 | 15 | 2 | 0 |
+| **合计** | — | **2637** | **276** | **738** | **987** | **0** | **22** | **5** | **0** |
+
+- 多源总台账 **2637**(729 md + 410 Playwright + 47 pytest + 1451 Java + 9 场景),与 19:21 持平。
+- 侧车 `test-progress.json` 未重写(仍 11:59,951 条)→ 执行证据来自旧快照,通过/失败不变属预期。
+
+## 三、CI / 流水线接入
+
+- ⚠ 仍未发现 `.github/workflows/` / `.gitlab-ci.yml` / `Jenkinsfile` → 测试脚本**未接入 CI**,仅本机可跑。
+
+## 四、闭环阻塞(保留)
+
+- `D:\cfc\.workbuddy\dispatch.py` 仍缺失(`ls` 确认 NO)+ 本运行未获联网授权 → **未跑 `--auto`,未伪造引擎**(避免误驱 opencode 改生产代码)。
+
+## 五、漂移结论
+
+后端覆盖、多源台账、自动化执行状态三方均**零漂移**(与上轮 19:21 完全一致)。仅刷新本地侧车与共享台账(时间戳 20:25)。
+- 268 控制器零覆盖缺口仍在;执行回写仍空洞(已执行 0)。
+- 门禁诚实口径:发现/跟踪链路健康(达标);质量门禁**未通过**(覆盖率 10.5% 不足 + CI 未接入 + 执行回写空洞)——历史结构性缺口,非本次造成;本运行**未实测**,严格标「未实测」。
+
+## 六、产物(仅本地 / 团队台账,未 push)
+
+- `docs/tdd/test/discovery.md`、`.tdd/discovery.json`
+- `docs/tdd/test/inventory.md`、`.tdd/test-inventory.json`
+- `docs/tdd/test/automation-status.md`

+ 126 - 0
docs/tdd/test/automation-run-2026-11-02-2045.md

@@ -0,0 +1,126 @@
+# 自动化执行台账 · 第 12 次(2026-11-02 20:45)
+
+> 触发:定时自动化 6255181e-9118-426d-887a-a897c2cbb810 | 指令「@skill:TDD 多智能体研发测试调度 执行实际测试任务」
+> 模式:本机 review 档**实际执行**(离线 `mvn -o test-compile`)| 未升级 closed-loop(无 opencode 派发、无 push 远端,属需显式授权的 execute 档)
+> 状态:已执行实际编译,发现**阻断性编译错误 1 个**——这是前 11 次 discovery-only 运行从未触及的真实结果。
+
+---
+
+## 一、模式判定与授权边界(无人值守默认)
+
+- 维持 discovery + inventory 基线刷新(与历史一致)。
+- **新增实际执行**:用本机已有的 Maven 离线跑 `mvn -o test-compile`,真实检验后端单测套件能否构建。
+- **不升级 closed-loop**:`config.json` 的 `tdd_mode=closed-loop` 需 alive 的 opencode 会话(127.0.0.1:4091 / 192.168.16.189:4090)+ push 到 `origin/cfclub`,属 execute 档 / 需显式联网授权;无人值守无法取得授权,与「软件测试专家团」硬规则(未确认方案不跑测试、未授权不联网、不推送)一致。
+- 全程只读:不改源码、不改测试文件、不装依赖、不碰 git、不推送。
+
+## 二、环境发现(★ 修正前序结论)
+
+前序 `red-task-investigation.md`(2026-11-02 11:48)声称:
+> "全机无 maven,且 188 个测试为 @SpringBootTest 需连库" / "src/test/java 下无任何 DanAssessmentController 测试文件(grep 命中 0)"
+
+**本次实测推翻上述两点:**
+
+| 项 | 前序结论 | 本次实测 |
+|---|---|---|
+| Maven | 全机无 | ✅ 存在 `/d/maven/apache-maven-3.6.1/bin/mvn`、`/d/tools/apache-maven-3.9.6/bin/mvn`;`JAVA_HOME=D:\jdk1.8.0_25`;`~/.m2/repository` 已缓存 Spring 依赖(可离线构建) |
+| DanAssessment 测试文件 | grep 命中 0 | ❌ 实际存在 `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java` |
+
+> 说明:前序 grep 可能因执行路径/大小写/分支差异漏检;本次以实际读文件 + 编译确认,结论以本次为准。
+
+## 三、实际执行动作与结果
+
+```bash
+cd d:/cfc/cfc-backend
+export PATH="/d/maven/apache-maven-3.6.1/bin:$PATH"
+mvn -o test-compile        # 离线编译测试源码
+# 结果:BUILD FAILURE —— COMPILATION ERROR(唯一错误)
+```
+
+**编译错误(唯一,单点):**
+```
+[ERROR] .../DanAssessmentControllerGetActiveMaterialTest.java:[48,17]
+  cannot find symbol
+    symbol:   method setName(java.lang.String)
+    location: variable material of type com.etotem.cfc.entity.AssessmentMaterial
+```
+
+- 后端测试套件总计 **195 测试文件 / 1451 @Test**,因这 **1 个文件编译失败**,**全部无法执行**(测试编译为全量编译,单文件失败即阻断整条套件)。
+- 这是 designated RED 任务 `dan.assessment.getActiveMaterial` 的测试文件。
+
+## 四、根因定位(file:line + 实体证据)
+
+- **测试侧(错)**:`DanAssessmentControllerGetActiveMaterialTest.java:48`
+  ```java
+  AssessmentMaterial material = new AssessmentMaterial();
+  material.setId(1L);
+  material.setName("2026 春季测评");   // ← 编译失败:AssessmentMaterial 无 setName
+  ```
+- **实体真实字段**:`cfc-backend/src/main/java/com/etotem/cfc/entity/AssessmentMaterial.java`
+  ```java
+  private Long id;
+  private String title;        // ← 实际是 title,不是 name
+  private String content;
+  private String coverImage;
+  private String status;
+  private Date createdAt;
+  private Date updatedAt;
+  ```
+- **控制器契约**:`DanAssessmentController.java:65` `@PostMapping("/material/active")` → `public Result<AssessmentMaterial> getActiveMaterial()`,直接序列化实体原字段(无 `name`,只有 `title`)。
+- **API 契约**:`docs/superpowers/api/API_REFERENCE.md` 中查无 dan-assessment material 条目,无法佐证应存在 `name` 字段 → 以实体为准,`name` 是测试误用。
+- 该测试用 `MockMvcBuilders.standaloneSetup`(**不加载 Spring 上下文、不需要数据库**),断言仅校验 `$.data.id`。因此这测试**本可在离线环境直接跑**,只差这一行字段名错误。
+
+## 五、影响面
+
+| 影响 | 范围 |
+|---|---|
+| 编译阻断 | 1 文件错 → 全部 195 文件 / 1451 @Test 无法编译运行 |
+| RED 任务 | `dan.assessment.getActiveMaterial`:测试已写但**编译不过**,RED 态实际为"坏测试"而非"待测" |
+| 修复收益 | 改 1 行 `setName→setTitle` 即可:① 解除整条套件编译阻断;② 该测试转为可离线运行的契约测试,使该 RED 任务具备 GREEN 候选 |
+
+## 六、五要素问题清单
+
+### 问题 P1 · RED 任务测试编译失败(阻断整条后端单测套件)
+
+| 要素 | 内容 |
+|---|---|
+| ① 问题描述 | `DanAssessmentControllerGetActiveMaterialTest` 调用 `AssessmentMaterial.setName(...)`,但实体只有 `title` 字段,导致后端测试源码**整体编译失败**,1451 个 @Test 全部无法执行。 |
+| ② 测试 bug 点 | `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java:48`(`material.setName("2026 春季测评")`) |
+| ③ 最优修改方案 | 测试角色将该行改为 `material.setTitle("2026 春季测评")`(或删除此行——断言仅校验 `$.data.id`,name/title 值不影响断言)。仅改测试文件,不动实体/实现。 |
+| ④ 修改目的 | 解除编译阻断,使 `mvn -o test` 可整体运行;并让 `dan.assessment.getActiveMaterial` 这一个 RED 任务拥有可离线执行的契约测试,推进 TDD 闭环。对齐质量目标"后端单测可构建、可回归"。 |
+| ⑤ 修改后能否闭环 | 能。改后 `mvn -o test-compile` 应通过;该 standalone MockMvc 测试无需 DB,可离线 `mvn -o test` 实跑得真实通过/失败;通过后由测试角色 `--mark-green`(需 push `origin/cfclub` 方被编排侧认,当前未授权不推送)。 |
+
+### 问题 P2 · 历史台账结论失真(过程类)
+
+| 要素 | 内容 |
+|---|---|
+| ① 问题描述 | 前序 `red-task-investigation.md` 记录"全机无 maven""该控制器无任何测试文件",与本次实测(maven 存在、测试文件存在且编译失败)矛盾,会误导后续排期与授权判断。 |
+| ② 测试 bug 点 | `docs/tdd/test/red-task-investigation.md` 第 10、29 行结论失真 |
+| ③ 最优修改方案 | 在执行环境重新核验后,于该文档追加"2026-11-02 20:45 实测更正"说明;后续调度以"实际编译结果"为准,不再依赖"无 maven"假设。 |
+| ④ 修改目的 | 避免基于错误前提做出"无法执行后端测试"的错误决策,使后续授权(装依赖/派发)判断准确。 |
+| ⑤ 修改后能否闭环 | 能(文档层级更正,不影响代码);建议下次执行直接以 `mvn -o` 实测为准。 |
+
+## 七、阻塞分类与路由建议(TDD 测试阻塞处置协议)
+
+- **本阻塞归属:测试类(test)**。根因是测试文件引用了不存在的符号(`setName`),属测试代码缺陷,非研发/需求/设计未落地。
+- 按协议应由**测试角色自行处置**(修正字段名)。本自动化为只读,不代改测试文件,仅记录并给出五要素修复方案。
+- 若业务方坚持物料应暴露 `name` 字段(而非 `title`),则转为**研发/设计类**阻塞,需研发在 `AssessmentMaterial` 增加 `name` 字段并同步契约文档;但当前无任何契约证据支持此说,默认按"测试误用"处理。
+
+## 八、未实测项 / 未推送声明
+
+- **未实测**:`mvn -o test`(实际跑用例)未执行——因 `test-compile` 已失败,套件无法进入运行阶段;修复 P1 后方可实测。
+- **未实测**:closed-loop 派发、远端 push、CI 接入均未做(需显式授权,无人值守不执行)。
+- **未推送**:本台账为本地文件,未 `git push origin/cfclub`;如需团队共享可手动 `git add docs/tdd/test/automation-run-2026-11-02-2045.md && git push`。
+
+## 九、基线刷新结果(与 19:42 第 11 次一致,零漂移)
+
+- 后端:357 控制器 / 1935 handler,已覆盖 203(10.5%)(c16/p72/u268/nh1);195 测试文件 / 1451 @Test。
+- 跨源总台账 2637(md729 / Playwright410 / pytest47 / Java1451 / 场景9)。
+- 已自动化 276、待自动化 738、未跟踪 987;CI 未接入;2 个 RED 任务全 RED。
+- 本次新增事实:其中 `dan.assessment.getActiveMaterial` 的测试**已存在但编译失败**(非"无测试")。
+
+## 十、后续推进条件(需用户显式授权)
+
+1. **解除编译阻断(测试角色)**:将 `setName`→`setTitle`(P1-③),`mvn -o test-compile` 通过后整条套件恢复可构建。
+2. **后端实测**:授权后 `mvn -o test` 实跑 1451 @Test,将侧车"已执行 0 / 通过22 / 失败5"刷新为真实数字。
+3. **闭环推送**:授权 `git push origin/cfclub` → RED/YELLOW/GREEN 证据成立,测试角色可 `--mark-green`。
+4. **另一 RED 任务** `health.report.createReport`:前序核查称"无任何测试覆盖",本次编译错误仅 1 个(非此任务),其实现存在(HealthReportController.java:219);授权后可补契约测试并实跑。

+ 34 - 0
docs/tdd/test/automation-run-2026-11-02-2133.md

@@ -0,0 +1,34 @@
+# TDD 自动化巡检报告 · 2026-11-02 21:33 (GMT+8)
+
+## 执行范围
+无人值守定时任务 `执行测试任务`(TDD 多智能体研发测试调度 skill)。
+仅离线「发现 / 格式化 / 跟踪」:重跑 `discover_tests.py` + `test_inventory.py`。
+**不派发、不联网、不跑测试执行、不 push 远程**(无人值守默认范围)。
+
+## 扫描结果(两端均 exit 0)
+
+### 后端单元覆盖(discover_tests.py)
+- 357 控制器 / 1935 handler / 203 覆盖 (10.5%) / 195 测试文件 / 1451 @Test
+- 覆盖分布:covered=16 / partial=72 / uncovered=268 / no-handler=1
+
+### 多源总台账(test_inventory.py)
+- 729 md + 410 Playwright + 47 pytest + 1451 Java + 9 场景 = **2637** 用例/方法
+
+### 自动化 / 执行状态(automation-status 合计行)
+- 已自动化 276 / 待自动化 738 / 未跟踪 987 / 已执行 0 / 通过 22 / 失败 5 / 阻塞 0
+- 侧车 `test-progress.json` 未重写(仍 951 条旧快照)→ 通过/失败数字来自旧快照,不变属预期
+
+### CI 接入
+- 未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile` → 未接入,仅本机可跑
+
+## 漂移结论
+后端覆盖、多源台账、自动化执行状态三方均**零漂移**,与上轮(20:25)完全一致。
+268 控制器零覆盖缺口仍在;执行回写仍空洞(已执行 0)。
+
+## 闭环保留阻塞
+- `D:\cfc\.workbuddy\dispatch.py` 仍缺失 + 本运行未获联网授权 → 未跑 `--auto`,未伪造引擎。
+- 真实闭环仍需用户放真实 dispatch.py(或提供 opencode 协议)并显式授权联网。
+
+## 门禁诚实口径
+- 发现/跟踪链路健康(达标)。
+- 质量门禁未通过(覆盖率 10.5% 不足 + CI 未接入 + 执行回写空洞)——历史结构性缺口,非本次造成;本运行未实测,严格标「未实测」。

+ 95 - 0
docs/tdd/test/automation-run-2026-11-02-2203.md

@@ -0,0 +1,95 @@
+# TDD 自动化执行台账 · 第 13 次运行(2026-11-02 22:03)
+
+> 触发:定时自动化 `6255181e-9118-426d-887a-a897c2cbb810`
+> 用户指令:`@skill:"TDD 多智能体研发测试调度" 执行实际测试任务`
+> 执行档:**review 档(离线,不联网,不推送远端,源码只读)**
+> 模式判定:维持**只读发现 + 编目 + 本机离线实际构建**(discovery-only 基线 + 第 12 次起的真实 `mvn -o test-compile` 实测);**未**静默升级 closed-loop(需联网 opencode 会话 + push `origin/cfclub`,属 execute 档/需显式授权,无人值守无法取得)。
+
+---
+
+## 一、本轮实际执行动作(均只读 / 离线)
+
+| # | 动作 | 命令 | 结果 |
+|---|------|------|------|
+| 1 | 测试发现扫描 | `discover_tests.py --project d:/cfc` | ✅ 刷新 `docs/tdd/test/discovery.md` + `.tdd/discovery.json` |
+| 2 | 跨源总台账 / 自动化状态 | `test_inventory.py --project d:/cfc` | ✅ 刷新 `inventory.md` / `automation-status.md`(侧车 951 条进度未重写) |
+| 3 | **实际离线构建(测试编译)** | `mvn -o test-compile`(JAVA_HOME=D:\jdk1.8.0_25,Maven 3.6.1,~/.m2 离线缓存) | ❌ **BUILD FAILURE**,1 个编译错误 |
+| 4 | 根因核实(只读) | 读取测试文件:48 与实体 `AssessmentMaterial.java` | ✅ 确认 `setName`→`setTitle` 字段误用 |
+
+> 说明:`mvn -o test` 实跑用例**无法执行**——因 `test-compile` 阶段失败,Maven 不会进入测试运行阶段。故"实际测试执行"的真实结果是"套件因编译错误整体不可运行",此即本次实测结论,非模拟。
+
+---
+
+## 二、基线快照(与 20:45 第 12 次一致,零漂移)
+
+- 后端:357 控制器 / 1935 handler,已覆盖 **203 (10.5%)**(covered=16 / partial=72 / uncovered=268 / no-handler=1)
+- 测试资产:195 测试文件 / **1451 @Test**(partial 4)
+- 跨源总台账 **2637** 用例/方法:md 729 / Playwright 410 / pytest 47 / Java 1451 / 场景文件 9
+- 自动化状态:已自动化 276 / 待自动化 738 / 未跟踪 987 / 通过 22 / 失败 5 / 阻塞 0
+- **CI 流水线未接入**(未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile`)
+- `state.json` 仍登记 2 个 RED 任务(`health.report.createReport` / `dan.assessment.getActiveMaterial`,manual_entry),stage 全 RED,无 YELLOW/GREEN/DONE 推进
+
+---
+
+## 三、实际构建执行结果(核心产出)
+
+```
+[INFO] BUILD FAILURE
+[ERROR] Failed to execute goal ...maven-compiler-plugin:3.10.1:testCompile ... Compilation failure
+[ERROR] /D:/cfc/cfc-backend/src/test/java/com/etotem/cfc/controller/
+         DanAssessmentControllerGetActiveMaterialTest.java:[48,17] cannot find symbol
+[ERROR]   symbol:   method setName(java.lang.String)
+[ERROR]   location: variable material of type com.etotem.cfc.entity.AssessmentMaterial
+```
+
+- **唯一编译错误**:`DanAssessmentControllerGetActiveMaterialTest.java:48`
+- **影响面**:测试编译是整体阶段,**1 个文件编译失败 → 后端整条套件(195 文件 / 1451 @Test)全部无法编译与运行**。
+- **根因(已核实)**:
+  - 测试 `getActiveMaterial_present_returnsMaterial()`(line 44-57)第 48 行调用 `material.setName("2026 春季测评")`。
+  - 实体 `AssessmentMaterial`(Lombok `@Data`)字段为:`id, title, content, coverImage, status, createdAt, updatedAt` —— **无 `name` 字段**,正确 setter 为 `setTitle(...)`。
+  - 该测试为 **standalone MockMvc**(`MockMvcBuilders.standaloneSetup`,不依赖 DB/Spring 上下文),离线可跑,修复 1 行即解除阻断。
+- **结论**:这是**测试源码 bug(字段名误用)**,非生产代码缺陷;研发已实现 `getActiveMaterial` 能力,测试本身写错字段。
+
+---
+
+## 四、五要素问题清单(P1)
+
+| 要素 | 内容 |
+|------|------|
+| ① 问题描述 | 后端测试套件无法编译,导致全部 195 测试文件 / 1451 @Test 无法执行;实际执行 `mvn -o test-compile` 返回 BUILD FAILURE,整条 CI/本地测试链路中断。 |
+| ② 测试 bug 点 | `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java:48` —— `material.setName(...)` 调用不存在的 setter;`AssessmentMaterial` 实体仅有 `title` 字段。 |
+| ③ 最优修改方案 | 将该行 `material.setName("2026 春季测评")` 改为 `material.setTitle("2026 春季测评")`(一行修复)。此测试为 standalone MockMvc,不需 DB,修复即离线可运行。 |
+| ④ 修改目的 | 解除整条测试套件编译阻断,使 RED 任务 `dan.assessment.getActiveMaterial` 具备 GREEN 候选,并恢复 `mvn -o test` 全量执行能力,改善当前极低单元覆盖(10.5%)的可观测性。 |
+| ⑤ 修改后能否闭环 | 修复后重跑 `mvn -o test-compile` 应 BUILD SUCCESS;再 `mvn -o test` 实跑,预期 `getActiveMaterial_present_returnsMaterial` 通过(MockMvc 校验 code=200 / data.id=1)。建议 commit 并 push `origin/cfclub` 后由测试角色 `--mark-green` 闭环。**本自动化为只读,不代改源码;修复须测试/开发角色执行(属测试类阻塞,按 TDD 协议 blocker-type=测试 自闭环)。** |
+
+---
+
+## 五、覆盖缺口清单(供后续,持续)
+
+| 缺口 | 现状 | 风险 | 建议测试设计 | 优先级 | 闭环方式 |
+|------|------|------|--------------|--------|----------|
+| 编译阻断 | 1 文件误用字段,整条套件不可编译 | 全部单测/回归无法运行,CI 形同虚设 | 改 1 行 `setName`→`setTitle` 后重跑 `mvn -o test` | **P1** | 修复→本地编译通过→push→测试校验 GREEN |
+| 零测试控制器 | 268 个控制器零测试(AdminController 65、DanAssessmentController 29、AdminArticleController 22、TaskController 18 等高价值后台) | 核心后台接口无回归保护 | 按 `discovery.md` 覆盖分布优先补 MockMvc 用例 | P2 | 每周补 N 个 → 回写侧车 → 提升 covered 计数 |
+| md 用例待脚本化 | 729 条结构化 md 用例未关联自动化脚本 | 大量用例仅文档态,无执行证据 | 将 md 用例映射到 Playwright/后端脚本并回写 `automation-status.md` | P3 | 逐批脚本化→标记已自动化 |
+| 无 CI 接入 | 未发现任何 CI 配置 | 测试不随提交自动跑,阻断长期无人发现 | 接入 GitHub Actions/GitLab CI,门禁 `mvn -o test` | P2 | 加 `.github/workflows` → 提交远端 |
+
+---
+
+## 六、未实测项(如实标注)
+
+- `mvn -o test` 未实跑(test-compile 失败,修复 P1 后方可);当前"通过 22 / 失败 5"为侧车历史回写,非本轮实测。
+- closed-loop 派发 / 远端 push / CI 接入均未做(需用户显式授权联网 + 远端推送)。
+- 台账 `docs/tdd/test/*.md` 本地生成,**未推送**(推送属需确认操作,依专家只读规则保持不推送)。
+
+---
+
+## 七、配置冲突待人工裁决(持续)
+
+`config.json` `tdd_mode=closed-loop` 与 TDD skill 对 CFC 的硬边界「仅发现/跟踪,不派发」口径冲突;且 2 个 RED 任务已 `manual_entry`。是否升级到 closed-loop 派发需用户显式授权(联网 opencode 会话 + push `origin/cfclub`)。本轮维持 discovery + 离线构建实测,未越权升级。
+
+---
+
+## 八、与历史对照
+
+- 第 12 次(20:45)首次发现并核实该 P1 编译阻断;**本轮(22:03)复测确认该阻断仍未修复**(约 1.2 小时内开发未处置),阻断持续开放。
+- 其余基线维度相对 20:45 **零漂移**(控制器/handler/覆盖/测试文件/@Test/总台账/自动化分类/通过/失败/CI/RED 全部一致)。

+ 25 - 0
docs/tdd/test/automation-run-2026-11-02-2239.md

@@ -0,0 +1,25 @@
+# 自动化巡检报告 · 2026-11-02 22:39
+
+## 触发
+定时自动化 `执行测试任务`(TDD 多智能体研发测试调度 skill)。
+
+## 执行范围(默认,无人值守)
+仅离线「发现 / 格式化 / 跟踪」,不派发、不联网、不跑测试执行、不 push 远程。
+
+## 执行结果(discover_tests.py + test_inventory.py,两端均 exit 0)
+- **后端覆盖**:357 控制器 / 1935 handler / 203 覆盖(10.5%) / 195 测试文件 / 1451 @Test;分布 covered=16 partial=72 uncovered=268 no-handler=1(与 21:33 完全一致,22:03 同为刷新、数据一致)。
+- **多源总台账**:729 md + 410 Playwright + 47 pytest + 1451 Java + 9 场景 = **2637**(与 21:33 持平)。
+- **自动化/执行状态(合计行)**:已自动化 276 / 待自动化 738 / 未跟踪 987 / 已执行 0 / 通过 22 / 失败 5 / 阻塞 0。侧车 `test-progress.json` 未重写(仍 951 条旧快照)→ 执行证据来自旧快照,通过/失败不变属预期。
+- **CI 接入**:仍未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile` → 未接入,仅本机可跑。
+
+## 漂移结论
+后端覆盖、多源台账、自动化执行状态三方均零漂移,仅刷新本地侧车与共享台账(时间戳 22:39)。268 控制器零覆盖缺口仍在;执行回写仍空洞(已执行 0)。工作树现 45 处改动(交互相产物 + 新测试),按纪律本次不 commit/push。
+
+## 闭环保留阻塞
+`D:\cfc\.workbuddy\dispatch.py` 仍缺失(本次 ls 确认 NO)+ 本运行未获联网授权 → 未跑 `--auto`,未伪造引擎。
+
+## 门禁诚实口径
+发现/跟踪链路健康(达标);质量门禁未通过(覆盖率 10.5% 不足 + CI 未接入 + 执行回写空洞)——历史结构性缺口,非本次造成;本运行未实测,严格标「未实测」。
+
+## 产物(已刷新,仅本地/团队台账,未 push)
+`docs/tdd/test/discovery.md`、`.tdd/discovery.json`、`docs/tdd/test/inventory.md`、`.tdd/test-inventory.json`、`docs/tdd/test/automation-status.md`。

+ 276 - 216
docs/tdd/test/automation-status.md

@@ -19,12 +19,12 @@
 
 
 | 来源类型 | 文件数 | 用例/方法数 | 已自动化 | 待自动化 | 未跟踪 | 已执行 | 通过 | 失败 | 阻塞 |
 | 来源类型 | 文件数 | 用例/方法数 | 已自动化 | 待自动化 | 未跟踪 | 已执行 | 通过 | 失败 | 阻塞 |
 | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
 | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
-| 结构化测试用例(md) | 9 | 678 | 0 | 678 | 678 | 0 | 0 | 0 | 0 |
-| 用户场景(md) | 8 | 0 | 0 | 8 | 8 | 0 | 0 | 0 | 0 |
-| Playwright(e2e/integration) | 70 | 410 | 70 | 0 | 67 | 0 | 1 | 2 | 0 |
+| 结构化测试用例(md) | 9 | 729 | 0 | 729 | 729 | 0 | 0 | 0 | 0 |
+| 用户场景(md) | 9 | 0 | 0 | 9 | 9 | 0 | 0 | 0 | 0 |
+| Playwright(e2e/integration) | 70 | 410 | 70 | 0 | 60 | 0 | 7 | 3 | 0 |
 | Python(pytest) | 11 | 47 | 11 | 0 | 11 | 0 | 0 | 0 | 0 |
 | Python(pytest) | 11 | 47 | 11 | 0 | 11 | 0 | 0 | 0 | 0 |
-| Java后端测试 | 187 | 1395 | 187 | 0 | 187 | 0 | 0 | 0 | 0 |
-| **合计** | — | **2530** | **268** | **686** | 951 | 0 | 1 | 2 | 0 |
+| Java后端测试 | 195 | 1451 | 195 | 0 | 178 | 0 | 15 | 2 | 0 |
+| **合计** | — | **2637** | **276** | **738** | 987 | 0 | 22 | 5 | 0 |
 
 
 ## 二、结构化测试用例自动化状态(`tests/test-cases/*.md`)
 ## 二、结构化测试用例自动化状态(`tests/test-cases/*.md`)
 
 
@@ -53,29 +53,29 @@
 | `tests/test-cases/admin.md#TC-A-21` | 网关/限流 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:接口防护;边界:误杀白名单|e2e:网关/限流 |
 | `tests/test-cases/admin.md#TC-A-21` | 网关/限流 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:接口防护;边界:误杀白名单|e2e:网关/限流 |
 | `tests/test-cases/admin.md#TC-A-22` | 模型管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:模型版本/开关;边界:下线前回退方案|e2e:模型管理 |
 | `tests/test-cases/admin.md#TC-A-22` | 模型管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:模型版本/开关;边界:下线前回退方案|e2e:模型管理 |
 | `tests/test-cases/admin.md#TC-A-23` | 知识库 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:维护营养知识;边界:同步失败重试|e2e:知识库 |
 | `tests/test-cases/admin.md#TC-A-23` | 知识库 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:维护营养知识;边界:同步失败重试|e2e:知识库 |
-| `tests/test-cases/admin.md#TC-A-01-E` | 认证 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AdminAuthController |
-| `tests/test-cases/admin.md#TC-A-02-E` | 统计 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:StatsController |
-| `tests/test-cases/admin.md#TC-A-03-E` | 方案管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理(全量) |
-| `tests/test-cases/admin.md#TC-A-04-E` | 方案激活 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案激活 |
-| `tests/test-cases/admin.md#TC-A-05-E` | 报告解析 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:AdminReportParserController |
-| `tests/test-cases/admin.md#TC-A-06-E` | 报告解析 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告类型注册 |
-| `tests/test-cases/admin.md#TC-A-07-E` | 报告解析 | 运营 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:未知聚类自学习 |
-| `tests/test-cases/admin.md#TC-A-08-E` | 文章 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:文章发布-审核 |
-| `tests/test-cases/admin.md#TC-A-09-E` | 文章·去重 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:文章标题去重 |
-| `tests/test-cases/admin.md#TC-A-10-E` | 关系类型 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:关系类型 CRUD |
-| `tests/test-cases/admin.md#TC-A-11-E` | 勋章 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:勋章管理;黑盒回归 |
-| `tests/test-cases/admin.md#TC-A-12-E` | 供应商 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:供应商管理;黑盒回归 |
-| `tests/test-cases/admin.md#TC-A-13-E` | 活动 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:活动审核撤回;黑盒回归 |
-| `tests/test-cases/admin.md#TC-A-14-E` | 知识库 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:知识库管理;黑盒回归 |
-| `tests/test-cases/admin.md#TC-A-15-E` | 数据迁移 | 运营 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:多数据源/SfmsDataSourceConfig |
-| `tests/test-cases/admin.md#TC-A-16-E` | 参数校验 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:统一 `Result<T>`+全局异常;黑盒回归 |
-| `tests/test-cases/admin.md#TC-A-17-E` | /api/admin/report-parser/* | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:/api/admin/report-parser/* |
-| `tests/test-cases/admin.md#TC-A-18-E` | 优惠券/活动管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:优惠券/活动管理 |
-| `tests/test-cases/admin.md#TC-A-19-E` | 内容安全 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:内容安全 |
-| `tests/test-cases/admin.md#TC-A-20-E` | GDPR 工单 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:GDPR 工单 |
-| `tests/test-cases/admin.md#TC-A-21-E` | 网关/限流 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:网关/限流 |
-| `tests/test-cases/admin.md#TC-A-22-E` | 模型管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:模型管理 |
-| `tests/test-cases/admin.md#TC-A-23-E` | 知识库 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:知识库 |
+| `tests/test-cases/admin.md#TC-A-01-E` | 认证 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:错误密码不签发 token 且提示次数限制/锁定;过期 token 401 跳登录;弱密码 400 拦截|e2e:AdminAuthController |
+| `tests/test-cases/admin.md#TC-A-02-E` | 统计 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级提示非500;无数据显示『暂无数据』;时间非法 400|e2e:StatsController |
+| `tests/test-cases/admin.md#TC-A-03-E` | 方案管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;非法筛选 400;仅返回有权家庭数据不串|e2e:方案管理(全量) |
+| `tests/test-cases/admin.md#TC-A-04-E` | 方案激活 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非 reviewed 激活拦截;超时回滚不残半任务;并发幂等仅生成 1 次任务|e2e:方案激活 |
+| `tests/test-cases/admin.md#TC-A-05-E` | 报告解析 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;重复 typeId 400 拒绝;路径非法 400|e2e:AdminReportParserController |
+| `tests/test-cases/admin.md#TC-A-06-E` | 报告解析 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复 typeId 拒绝;必填缺失 400;threshold 非法 400|e2e:报告类型注册 |
+| `tests/test-cases/admin.md#TC-A-07-E` | 报告解析 | 运营 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;重名类型生成被拒/提示已存在|e2e:未知聚类自学习 |
+| `tests/test-cases/admin.md#TC-A-08-E` | 文章 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:同标题 400『标题已存在』;长文提交超时重试不丢稿;注入 400 或转义|e2e:文章发布-审核 |
+| `tests/test-cases/admin.md#TC-A-09-E` | 文章·去重 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复创建被拦截提示标题已存在;空/超长 400|e2e:文章标题去重 |
+| `tests/test-cases/admin.md#TC-A-10-E` | 关系类型 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重名拒绝;停用被引用类型提示先解绑;注入 400/转义;家长端选择器同步生效仍正确|e2e:关系类型 CRUD |
+| `tests/test-cases/admin.md#TC-A-11-E` | 勋章 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复 400/幂等;非法门槛 400;并发创建各自独立不串|e2e:勋章管理;黑盒回归 |
+| `tests/test-cases/admin.md#TC-A-12-E` | 供应商 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:同手机号拒绝/可控覆盖;非法格式 400;必填缺失 400;列表 name=昵称正确|e2e:供应商管理;黑盒回归 |
+| `tests/test-cases/admin.md#TC-A-13-E` | 活动 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已发布再提交审核守卫拦截;非本人撤回 403;时间冲突 400;撤回退回草稿|e2e:活动审核撤回;黑盒回归 |
+| `tests/test-cases/admin.md#TC-A-14-E` | 知识库 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:被引用删除提示先解绑;不存在 404;并发删除幂等|e2e:知识库管理;黑盒回归 |
+| `tests/test-cases/admin.md#TC-A-15-E` | 数据迁移 | 运营 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:中断回滚+明确错误非500;锁等待超时提示;重复执行幂等/提示已迁移|e2e:多数据源/SfmsDataSourceConfig |
+| `tests/test-cases/admin.md#TC-A-16-E` | 参数校验 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:空 body 400 含具体字段提示;类型错配 400;超长 400;不再裸 500|e2e:统一 `Result<T>`+全局异常;黑盒回归 |
+| `tests/test-cases/admin.md#TC-A-17-E` | /api/admin/report-parser/* | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重名类目拒绝;未注册路径 400;先注册再解析|e2e:/api/admin/report-parser/* |
+| `tests/test-cases/admin.md#TC-A-18-E` | 优惠券/活动管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:时间冲突 400;名额超卖配置保护生效;重复提交幂等|e2e:优惠券/活动管理 |
+| `tests/test-cases/admin.md#TC-A-19-E` | 内容安全 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;命中敏感词强制拦截不放行|e2e:内容安全 |
+| `tests/test-cases/admin.md#TC-A-20-E` | GDPR 工单 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全:注销与导出按序执行不冲突;越权工单 403|e2e:GDPR 工单 |
+| `tests/test-cases/admin.md#TC-A-21-E` | 网关/限流 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:白名单不被限流;非法阈值 400;规则生效可控|e2e:网关/限流 |
+| `tests/test-cases/admin.md#TC-A-22-E` | 模型管理 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:无回退方案拦截下线;非法版本 400;上下线版控正确|e2e:模型管理 |
+| `tests/test-cases/admin.md#TC-A-23-E` | 知识库 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:同步失败自动重试非500;并发 CRUD 乐观锁不互相覆盖|e2e:知识库 |
 | `tests/test-cases/admin.md#TC-A-01-P` | 认证 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:AdminAuthController |
 | `tests/test-cases/admin.md#TC-A-01-P` | 认证 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:AdminAuthController |
 | `tests/test-cases/admin.md#TC-A-02-P` | 统计 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:StatsController |
 | `tests/test-cases/admin.md#TC-A-02-P` | 统计 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:StatsController |
 | `tests/test-cases/admin.md#TC-A-03-P` | 方案管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:方案管理(全量) |
 | `tests/test-cases/admin.md#TC-A-03-P` | 方案管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问管理端接口统一 401/403,不泄露后台数据|e2e:方案管理(全量) |
@@ -99,6 +99,12 @@
 | `tests/test-cases/admin.md#TC-A-21-P` | 网关/限流 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:网关/限流 |
 | `tests/test-cases/admin.md#TC-A-21-P` | 网关/限流 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:网关/限流 |
 | `tests/test-cases/admin.md#TC-A-22-P` | 模型管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:模型管理 |
 | `tests/test-cases/admin.md#TC-A-22-P` | 模型管理 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:模型管理 |
 | `tests/test-cases/admin.md#TC-A-23-P` | 知识库 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:知识库 |
 | `tests/test-cases/admin.md#TC-A-23-P` | 知识库 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 角色访问统一 401/403,不泄露后台数据|e2e:知识库 |
+| `tests/test-cases/admin.md#TC-A-25` | 维度/权重/上限配置 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:变更生效、后续能量按新配置;存量影响提示|e2e:DimensionConfigController`/`DimensionWeightController |
+| `tests/test-cases/admin.md#TC-A-26` | 能量/归因权重 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:全局生效;变更写审计;概览/沙盘/天盘影响可观测|e2e:EnergyController`/`AttributionWeights |
+| `tests/test-cases/admin.md#TC-A-25-E` | 维度/权重/上限配置 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 需确认/拒、不级联破坏存量 2. 400 拦截 3. 乐观锁/版本控制不互相覆盖|e2e:DimensionConfigController |
+| `tests/test-cases/admin.md#TC-A-26-E` | 能量/归因权重 | 运营 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 400 拦截 2. 展示兜底并提示、不静默错算|e2e:EnergyController`/`AttributionWeights |
+| `tests/test-cases/admin.md#TC-A-25-P` | 维度/权重/上限配置 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 操作 403|e2e:DimensionConfigController |
+| `tests/test-cases/admin.md#TC-A-26-P` | 能量/归因权重 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 改全局 403|e2e:EnergyController |
 | `tests/test-cases/admin.md#TC-A-N01` | 配置CRUD | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:列表 ≤ 2s;CRUD 即时生效|e2e:配置管理 |
 | `tests/test-cases/admin.md#TC-A-N01` | 配置CRUD | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:列表 ≤ 2s;CRUD 即时生效|e2e:配置管理 |
 | `tests/test-cases/admin.md#TC-A-N02` | 报告解析中台 | 运营 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:单条 ≤ 30s;失败进未知聚类;监控可见积压|e2e:解析中台 |
 | `tests/test-cases/admin.md#TC-A-N02` | 报告解析中台 | 运营 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:单条 ≤ 30s;失败进未知聚类;监控可见积压|e2e:解析中台 |
 | `tests/test-cases/admin.md#TC-A-N03` | 登录统计 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:聚合 ≤ 3s;支持分页/缓存;大数据不超时|e2e:统计聚合 |
 | `tests/test-cases/admin.md#TC-A-N03` | 登录统计 | 运营 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:聚合 ≤ 3s;支持分页/缓存;大数据不超时|e2e:统计聚合 |
@@ -131,29 +137,29 @@
 | `tests/test-cases/child.md#TC-C-21` | 舌诊情绪识别 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:拍照上传;边界:模糊/非照片拒绝;隐私标注|e2e:舌诊情绪识别 |
 | `tests/test-cases/child.md#TC-C-21` | 舌诊情绪识别 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:拍照上传;边界:模糊/非照片拒绝;隐私标注|e2e:舌诊情绪识别 |
 | `tests/test-cases/child.md#TC-C-22` | MallController | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:用积分换;边界:积分不足拦截;重复兑换幂等|e2e:MallController |
 | `tests/test-cases/child.md#TC-C-22` | MallController | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:用积分换;边界:积分不足拦截;重复兑换幂等|e2e:MallController |
 | `tests/test-cases/child.md#TC-C-23` | 客服 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:提反馈;边界:内容适龄过滤;敏感信息脱敏|e2e:客服 |
 | `tests/test-cases/child.md#TC-C-23` | 客服 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:提反馈;边界:内容适龄过滤;敏感信息脱敏|e2e:客服 |
-| `tests/test-cases/child.md#TC-C-01-E` | 权限/双角色 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:双角色铁律:孩子端不能切家长 |
-| `tests/test-cases/child.md#TC-C-02-E` | 任务 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController |
-| `tests/test-cases/child.md#TC-C-03-E` | 小游戏 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:pages/games/* |
-| `tests/test-cases/child.md#TC-C-04-E` | 心愿 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:WishController |
-| `tests/test-cases/child.md#TC-C-05-E` | 心愿 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:RewardController |
-| `tests/test-cases/child.md#TC-C-06-E` | 能量 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:EnergyController |
-| `tests/test-cases/child.md#TC-C-07-E` | 报告/权限 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告查看权限隔离 |
-| `tests/test-cases/child.md#TC-C-08-E` | 打卡/方案 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:健康打卡/方案进度 |
-| `tests/test-cases/child.md#TC-C-09-E` | 勋章 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:RewardController |
-| `tests/test-cases/child.md#TC-C-10-E` | 勋章提醒 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:MedalController |
-| `tests/test-cases/child.md#TC-C-11-E` | 成长记录 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:GrowthController |
-| `tests/test-cases/child.md#TC-C-12-E` | 食谱查看 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐 |
-| `tests/test-cases/child.md#TC-C-13-E` | AI 对话 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AIChatController |
-| `tests/test-cases/child.md#TC-C-14-E` | 任务重做 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController |
-| `tests/test-cases/child.md#TC-C-15-E` | 消息接收 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:消息服务 |
-| `tests/test-cases/child.md#TC-C-16-E` | 个人资料 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:AuthController |
-| `tests/test-cases/child.md#TC-C-17-E` | 退出 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController |
-| `tests/test-cases/child.md#TC-C-18-E` | 设备校验 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController |
-| `tests/test-cases/child.md#TC-C-19-E` | 消息服务 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:消息服务 |
-| `tests/test-cases/child.md#TC-C-20-E` | GrowthController | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:GrowthController |
-| `tests/test-cases/child.md#TC-C-21-E` | 舌诊情绪识别 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:舌诊情绪识别 |
-| `tests/test-cases/child.md#TC-C-22-E` | MallController | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:MallController |
-| `tests/test-cases/child.md#TC-C-23-E` | 客服 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:客服 |
+| `tests/test-cases/child.md#TC-C-01-E` | 权限/双角色 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:缺失/过期 token 统一 401 跳登录;切换/家长路由被 role 校验 403 拦截;孩子端无任何切回家长入口;模拟登录仅测试环境生效|e2e:双角色铁律:孩子端不能切家长 |
+| `tests/test-cases/child.md#TC-C-02-E` | 任务 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发双点幂等仅计 1 次、仅 1 条流水;超期提交被拒;驳回→重做→再提交仅在重做后计 1 次|e2e:TaskController |
+| `tests/test-cases/child.md#TC-C-03-E` | 小游戏 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:异常分数 400 不计入;断网不计分不卡死;重复上报幂等不重复入榜|e2e:pages/games/* |
+| `tests/test-cases/child.md#TC-C-04-E` | 心愿 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:余额不足创建拦截;超长/注入 400 校验;重复创建提示已存在不双建|e2e:WishController |
+| `tests/test-cases/child.md#TC-C-05-E` | 心愿 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:余额不足拦截且不扣负;已驳回提示不可兑换;并发幂等仅扣 1 次|e2e:RewardController |
+| `tests/test-cases/child.md#TC-C-06-E` | 能量 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级空态提示非 500;权重 0 占比兜底(0%)显示不崩;能量不为负|e2e:EnergyController |
+| `tests/test-cases/child.md#TC-C-07-E` | 报告/权限 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:删除/编辑被 role 校验 403 拒绝;孩子端 UI 无编辑/删除入口;报告内容不被改动|e2e:报告查看权限隔离 |
+| `tests/test-cases/child.md#TC-C-08-E` | 打卡/方案 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时回滚不残半任务、进度不 +1;重复打卡幂等不重复计数;非本人任务 403|e2e:健康打卡/方案进度 |
+| `tests/test-cases/child.md#TC-C-09-E` | 勋章 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复达成不重复发推送/勋章;未达成领取 400/403 拒绝|e2e:RewardController |
+| `tests/test-cases/child.md#TC-C-10-E` | 勋章提醒 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复达成幂等仅 1 次推送;数据缺失降级不推送不 500|e2e:MedalController |
+| `tests/test-cases/child.md#TC-C-11-E` | 成长记录 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:关联已删项跳过不报错;其他成员数据 403 不可见|e2e:GrowthController |
+| `tests/test-cases/child.md#TC-C-12-E` | 食谱查看 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时 Fallback 通用食谱+提示非 500;无食谱空态不 500|e2e:饮食推荐 |
+| `tests/test-cases/child.md#TC-C-13-E` | AI 对话 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:不适龄/敏感词被过滤返回适龄话术;LangGraph 不可用 Fallback 兜底、多轮连续|e2e:AIChatController |
+| `tests/test-cases/child.md#TC-C-14-E` | 任务重做 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非驳回态重做入口不可见/拦截;重做提交进入待审核仅计 1 次|e2e:TaskController |
+| `tests/test-cases/child.md#TC-C-15-E` | 消息接收 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权消息 403 不可见;不存在 404;列表分页正常|e2e:消息服务 |
+| `tests/test-cases/child.md#TC-C-16-E` | 个人资料 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:代管字段 403 不可改;昵称注入/超长 400 校验|e2e:AuthController |
+| `tests/test-cases/child.md#TC-C-17-E` | 退出 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:旧 token 失效 401;网络中断退出仍清本地缓存、下次需重登|e2e:AuthController |
+| `tests/test-cases/child.md#TC-C-18-E` | 设备校验 | 孩子 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:异常设备二次验证/拦截;旧设备 token 失效 401|e2e:AuthController |
+| `tests/test-cases/child.md#TC-C-19-E` | 消息服务 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:不存在 404;越权标记 403 不生效|e2e:消息服务 |
+| `tests/test-cases/child.md#TC-C-20-E` | GrowthController | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未成年导出 403 需家长代办;他人档案 403 不可见|e2e:GrowthController |
+| `tests/test-cases/child.md#TC-C-21-E` | 舌诊情绪识别 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非照片/模糊拒绝提示『请上传清晰舌苔照』;低置信度提示重拍;隐私标注不外露|e2e:舌诊情绪识别 |
+| `tests/test-cases/child.md#TC-C-22-E` | MallController | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:余额不足拦截不扣负;并发仅 1 次成功;重复兑换幂等仅 1 条|e2e:MallController |
+| `tests/test-cases/child.md#TC-C-23-E` | 客服 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:敏感信息脱敏存储;附件超限 400『附件不超过 10MB』|e2e:客服 |
 | `tests/test-cases/child.md#TC-C-01-P` | 权限/双角色 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:双角色铁律:孩子端不能切家长 |
 | `tests/test-cases/child.md#TC-C-01-P` | 权限/双角色 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:双角色铁律:孩子端不能切家长 |
 | `tests/test-cases/child.md#TC-C-02-P` | 任务 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:TaskController |
 | `tests/test-cases/child.md#TC-C-02-P` | 任务 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:TaskController |
 | `tests/test-cases/child.md#TC-C-03-P` | 小游戏 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:pages/games/* |
 | `tests/test-cases/child.md#TC-C-03-P` | 小游戏 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:pages/games/* |
@@ -177,6 +183,12 @@
 | `tests/test-cases/child.md#TC-C-21-P` | 舌诊情绪识别 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:舌诊情绪识别 |
 | `tests/test-cases/child.md#TC-C-21-P` | 舌诊情绪识别 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:舌诊情绪识别 |
 | `tests/test-cases/child.md#TC-C-22-P` | MallController | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:MallController |
 | `tests/test-cases/child.md#TC-C-22-P` | MallController | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:MallController |
 | `tests/test-cases/child.md#TC-C-23-P` | 客服 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:客服 |
 | `tests/test-cases/child.md#TC-C-23-P` | 客服 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据|e2e:客服 |
+| `tests/test-cases/child.md#TC-C-24` | 能量/小游戏·任务 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:对应维度 +amount、sourceType=game/task;B 自身能量页看到增长与流水|e2e:GameRecordService`/`TaskController |
+| `tests/test-cases/child.md#TC-C-25` | 能量/方案打卡 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:GrowthTaskService 打卡对应维度+;任务进度与能量同步刷新|e2e:GrowthTaskService |
+| `tests/test-cases/child.md#TC-C-24-E` | 能量/小游戏·任务 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 异常分数拦截不写能量 2. 重复上报幂等不重复加|e2e:GameRecordService |
+| `tests/test-cases/child.md#TC-C-25-E` | 能量/方案打卡 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 按业务允/拒、断言一致 2. 重复打卡幂等不重复加 3. 并发不重复计分|e2e:GrowthTaskService |
+| `tests/test-cases/child.md#TC-C-24-P` | 能量/小游戏·任务 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 他人能量 403 2. 孩子端无编辑/扣减入口、直接调被拒|e2e:JwtInterceptor`+role |
+| `tests/test-cases/child.md#TC-C-25-P` | 能量/方案打卡 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 非本人方案任务 403 2. 他人进度不可见|e2e:GrowthTaskService |
 | `tests/test-cases/child.md#TC-C-N01` | 任务打卡 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等;并发不重复计分;响应 ≤ 1s|e2e:TaskController |
 | `tests/test-cases/child.md#TC-C-N01` | 任务打卡 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等;并发不重复计分;响应 ≤ 1s|e2e:TaskController |
 | `tests/test-cases/child.md#TC-C-N02` | 消息通知 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:列表渲染 ≤ 1.5s;标记已读即时|e2e:消息中心 |
 | `tests/test-cases/child.md#TC-C-N02` | 消息通知 | 孩子 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:列表渲染 ≤ 1.5s;标记已读即时|e2e:消息中心 |
 | `tests/test-cases/child.md#TC-C-N03` | 孩子端 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:功能一致;无错位;低龄设备流畅|e2e:孩子端 |
 | `tests/test-cases/child.md#TC-C-N03` | 孩子端 | 孩子 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:功能一致;无错位;低龄设备流畅|e2e:孩子端 |
@@ -238,6 +250,15 @@
 | `tests/test-cases/cross-role-e2e.md#TC-X-16-P` | 跨角色 | P0 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-16|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-16-P` | 跨角色 | P0 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-16|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-17-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-17|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-17-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-17|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-18-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-18|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-18-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-18|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-19` | 跨角色 | P0 | 功能 | 文档用例(待自动化) | 未跟踪 | 设计:X-19|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-20` | 跨角色 | P0 | 功能 | 文档用例(待自动化) | 未跟踪 | 设计:X-20|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-21` | 跨角色 | P0 | 功能 | 文档用例(待自动化) | 未跟踪 | 设计:X-21|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-19-E` | 跨角色 | P1 | 异常 | 文档用例(待自动化) | 未跟踪 | 设计:X-19|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-20-E` | 跨角色 | P1 | 异常 | 文档用例(待自动化) | 未跟踪 | 设计:X-20|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-21-E` | 跨角色 | P1 | 异常 | 文档用例(待自动化) | 未跟踪 | 设计:X-21|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-19-P` | 跨角色 | P0 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-19|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-20-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-20|e2e:- |
+| `tests/test-cases/cross-role-e2e.md#TC-X-21-P` | 跨角色 | P1 | 权限 | 文档用例(待自动化) | 未跟踪 | 设计:X-21|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N01` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-01|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N01` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-01|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N02` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-03|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N02` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-03|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N03` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-15|e2e:- |
 | `tests/test-cases/cross-role-e2e.md#TC-X-N03` | 跨角色 | P0 | 性能 | 文档用例(待自动化) | 未跟踪 | 设计:X-15|e2e:- |
@@ -264,7 +285,7 @@
 | `tests/test-cases/deep-dive-plan-activation.md#TC-PA-06` | 拆任务/数据 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非当天过期(待确认设计)|e2e:G4 |
 | `tests/test-cases/deep-dive-plan-activation.md#TC-PA-06` | 拆任务/数据 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非当天过期(待确认设计)|e2e:G4 |
 | `tests/test-cases/guest.md#TC-G-01` | 启动/首页 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:显示引流首页,不进入任何业务页;明显展示微信/手机号/邀请登录入口|e2e:JwtInterceptor 拦截 `/api/** |
 | `tests/test-cases/guest.md#TC-G-01` | 启动/首页 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:显示引流首页,不进入任何业务页;明显展示微信/手机号/邀请登录入口|e2e:JwtInterceptor 拦截 `/api/** |
 | `tests/test-cases/guest.md#TC-G-02` | 认证 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:返回 Result 含 token+用户信息;角色默认 parent;跳转家长首页;首次登录建 User+family_members(memberType=login)|e2e:AuthController`/`API_REFERENCE` 1.1 |
 | `tests/test-cases/guest.md#TC-G-02` | 认证 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:返回 Result 含 token+用户信息;角色默认 parent;跳转家长首页;首次登录建 User+family_members(memberType=login)|e2e:AuthController`/`API_REFERENCE` 1.1 |
-| `tests/test-cases/guest.md#TC-G-03` | 认证 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:验证码正确→登录下发 token;错误→提示失败且**不产生会话**;限流生效|e2e:统一 POST/JWT |
+| `tests/test-cases/guest.md#TC-G-03` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:验证码正确→登录下发 token;错误→提示失败且**不产生会话**;限流生效 ⚠ **API 兼容保留**:小程序端无入口(登录走 SC-G-02),2026-11-01 口径|e2e:统一 POST/JWT |
 | `tests/test-cases/guest.md#TC-G-04` | 家庭/邀请 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:登录后自动归属对应家庭,成员列表出现该用户;令牌失效→「邀请已失效」|e2e:FamilyInviteController |
 | `tests/test-cases/guest.md#TC-G-04` | 家庭/邀请 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:登录后自动归属对应家庭,成员列表出现该用户;令牌失效→「邀请已失效」|e2e:FamilyInviteController |
 | `tests/test-cases/guest.md#TC-G-05` | 权限 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:业务页→401 跳登录,登录后回跳;商城/文章列表可见(公开);需登录详情被拦截|e2e:JWT;8 公开路径白名单(1.1) |
 | `tests/test-cases/guest.md#TC-G-05` | 权限 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:业务页→401 跳登录,登录后回跳;商城/文章列表可见(公开);需登录详情被拦截|e2e:JWT;8 公开路径白名单(1.1) |
 | `tests/test-cases/guest.md#TC-G-06` | 权限 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:JwtInterceptor 拦截(8 个公开路径除外);缺 token→401/403,不泄露内部错误堆栈|e2e:JwtInterceptor |
 | `tests/test-cases/guest.md#TC-G-06` | 权限 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:JwtInterceptor 拦截(8 个公开路径除外);缺 token→401/403,不泄露内部错误堆栈|e2e:JwtInterceptor |
@@ -274,18 +295,18 @@
 | `tests/test-cases/guest.md#TC-G-10` | 注册 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:引导至注册;已注册账号不重复建档|e2e:AuthController |
 | `tests/test-cases/guest.md#TC-G-10` | 注册 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:引导至注册;已注册账号不重复建档|e2e:AuthController |
 | `tests/test-cases/guest.md#TC-G-11` | 协议页/AgreementController | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:合规告知;边界:未同意不可进入注册/核心流程|e2e:协议页/AgreementController |
 | `tests/test-cases/guest.md#TC-G-11` | 协议页/AgreementController | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:合规告知;边界:未同意不可进入注册/核心流程|e2e:协议页/AgreementController |
 | `tests/test-cases/guest.md#TC-G-12` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:非微信浏览器打开小程序链接;边界:探测失败给出明确引导|e2e:config.js |
 | `tests/test-cases/guest.md#TC-G-12` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:非微信浏览器打开小程序链接;边界:探测失败给出明确引导|e2e:config.js |
-| `tests/test-cases/guest.md#TC-G-01-E` | 启动/首页 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:JwtInterceptor 拦截 `/api/** |
-| `tests/test-cases/guest.md#TC-G-02-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController`/`API_REFERENCE` 1.1 |
-| `tests/test-cases/guest.md#TC-G-03-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:统一 POST/JWT |
-| `tests/test-cases/guest.md#TC-G-04-E` | 家庭/邀请 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:FamilyInviteController |
-| `tests/test-cases/guest.md#TC-G-05-E` | 权限 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:JWT;8 公开路径白名单(1.1) |
-| `tests/test-cases/guest.md#TC-G-06-E` | 权限 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:JwtInterceptor |
-| `tests/test-cases/guest.md#TC-G-07-E` | 测试模式 | 游客 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:AGENTS.md 测试模式 |
-| `tests/test-cases/guest.md#TC-G-08-E` | 环境切换 | 游客 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:config.js |
-| `tests/test-cases/guest.md#TC-G-09-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController |
-| `tests/test-cases/guest.md#TC-G-10-E` | 注册 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController |
-| `tests/test-cases/guest.md#TC-G-11-E` | 协议页/AgreementController | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:协议页/AgreementController |
-| `tests/test-cases/guest.md#TC-G-12-E` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:config.js |
+| `tests/test-cases/guest.md#TC-G-01-E` | 启动/首页 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 不白屏、提供"稍后"/手机号登录兜底 2. 超时给重试而非 500;不泄露内部堆栈|e2e:JwtInterceptor 拦截 `/api/** |
+| `tests/test-cases/guest.md#TC-G-02-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 回退手机号登录、停留登录页不报错 2. 返回已有账号不重复建号 3. 超时提示重试、不建脏号|e2e:AuthController`/`API_REFERENCE` 1.1 |
+| `tests/test-cases/guest.md#TC-G-03-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 提示失败且不签发 token 2. 格式校验 400 拦截 3. 限流提示"操作频繁" 4. 绝不产生会话|e2e:统一 POST/JWT |
+| `tests/test-cases/guest.md#TC-G-04-E` | 家庭/邀请 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 拒绝并提示"邀请已失效" 2. 按业务规则处理(加入或被拒)、不串家庭|e2e:FamilyInviteController |
+| `tests/test-cases/guest.md#TC-G-05-E` | 权限 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 统一 401 跳登录;登录后回跳 2. 重定向登录;仅 8 公开路径放行|e2e:JWT;8 公开路径白名单(1.1) |
+| `tests/test-cases/guest.md#TC-G-06-E` | 权限 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 统一 401/403、不泄露内部错误与结构 2. 公开路径正常返回、不误拦|e2e:JwtInterceptor |
+| `tests/test-cases/guest.md#TC-G-07-E` | 测试模式 | 游客 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:1. 生产强制真授权、模拟登录被拒 2. 测试模式仅测试环境生效、不污染生产数据|e2e:AGENTS.md 测试模式 |
+| `tests/test-cases/guest.md#TC-G-08-E` | 环境切换 | 游客 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:1. 回退默认 API 地址、功能可用 2. 不因识别失败崩溃/错连|e2e:config.js |
+| `tests/test-cases/guest.md#TC-G-09-E` | 认证 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 退出后接口 401、需重登 2. 本地 token/隐私数据已清除|e2e:AuthController |
+| `tests/test-cases/guest.md#TC-G-10-E` | 注册 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 明确"未注册"并引导注册 2. 已注册不重复建档、直接登录|e2e:AuthController |
+| `tests/test-cases/guest.md#TC-G-11-E` | 协议页 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 拦截并强制先同意 2. 加载失败给重试、不绕过同意|e2e:协议页/AgreementController |
+| `tests/test-cases/guest.md#TC-G-12-E` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 给出"在微信内打开"明确引导 2. 降级静态页、核心流程可手机号兜底|e2e:config.js |
 | `tests/test-cases/guest.md#TC-G-01-P` | 启动/首页 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:JwtInterceptor 拦截 `/api/** |
 | `tests/test-cases/guest.md#TC-G-01-P` | 启动/首页 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:JwtInterceptor 拦截 `/api/** |
 | `tests/test-cases/guest.md#TC-G-02-P` | 认证 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:AuthController`/`API_REFERENCE` 1.1 |
 | `tests/test-cases/guest.md#TC-G-02-P` | 认证 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:AuthController`/`API_REFERENCE` 1.1 |
 | `tests/test-cases/guest.md#TC-G-03-P` | 认证 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:统一 POST/JWT |
 | `tests/test-cases/guest.md#TC-G-03-P` | 认证 | 游客 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:统一 POST/JWT |
@@ -299,7 +320,7 @@
 | `tests/test-cases/guest.md#TC-G-11-P` | 协议页/AgreementController | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:统一 401/403,不泄露内部错误与数据;8 个公开路径除外|e2e:协议页/AgreementController |
 | `tests/test-cases/guest.md#TC-G-11-P` | 协议页/AgreementController | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:统一 401/403,不泄露内部错误与数据;8 个公开路径除外|e2e:协议页/AgreementController |
 | `tests/test-cases/guest.md#TC-G-12-P` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:统一 401/403,不泄露内部错误与数据;8 个公开路径除外|e2e:config.js |
 | `tests/test-cases/guest.md#TC-G-12-P` | config.js | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:统一 401/403,不泄露内部错误与数据;8 个公开路径除外|e2e:config.js |
 | `tests/test-cases/guest.md#TC-G-N01` | 落地页 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:首屏 ≤ 3s;骨架屏生效;CDN 资源命中;无白屏|e2e:落地页/邀请 |
 | `tests/test-cases/guest.md#TC-G-N01` | 落地页 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:首屏 ≤ 3s;骨架屏生效;CDN 资源命中;无白屏|e2e:落地页/邀请 |
-| `tests/test-cases/guest.md#TC-G-N02` | 浏览转化 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:布局一致;微信授权正常;兜底登录可用;无错位|e2e:登录注册 |
+| `tests/test-cases/guest.md#TC-G-N02` | 浏览转化 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:布局一致;微信授权正常;兜底登录可用;无错位|e2e:登录注册(微信授权) |
 | `tests/test-cases/guest.md#TC-G-N03` | 非微信H5 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:功能可用;无微信 SDK 依赖报错;流程闭环|e2e:H5 兜底 |
 | `tests/test-cases/guest.md#TC-G-N03` | 非微信H5 | 游客 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:功能可用;无微信 SDK 依赖报错;流程闭环|e2e:H5 兜底 |
 | `tests/test-cases/guest.md#TC-G-N04` | 落地页 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:返回 401;不泄露数据与结构|e2e:接口鉴权 |
 | `tests/test-cases/guest.md#TC-G-N04` | 落地页 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:返回 401;不泄露数据与结构|e2e:接口鉴权 |
 | `tests/test-cases/guest.md#TC-G-N05` | 登录注册 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:触发限流/锁定;验证码一次性;防爆破;无撞库成功|e2e:登录限流 |
 | `tests/test-cases/guest.md#TC-G-N05` | 登录注册 | 游客 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:触发限流/锁定;验证码一次性;防爆破;无撞库成功|e2e:登录限流 |
@@ -389,92 +410,92 @@
 | `tests/test-cases/parent.md#TC-P-84` | 分享 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:共享;边界:链接失效/权限校验;越权分享被拒|e2e:分享 |
 | `tests/test-cases/parent.md#TC-P-84` | 分享 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:共享;边界:链接失效/权限校验;越权分享被拒|e2e:分享 |
 | `tests/test-cases/parent.md#TC-P-85` | AuthController | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:同账号多设备;边界:异常设备风控;退出清 token|e2e:AuthController |
 | `tests/test-cases/parent.md#TC-P-85` | AuthController | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:同账号多设备;边界:异常设备风控;退出清 token|e2e:AuthController |
 | `tests/test-cases/parent.md#TC-P-86` | 勋章/排行 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:激励;边界:数据仅本家庭可见;排名实时性|e2e:勋章/排行 |
 | `tests/test-cases/parent.md#TC-P-86` | 勋章/排行 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:激励;边界:数据仅本家庭可见;排名实时性|e2e:勋章/排行 |
-| `tests/test-cases/parent.md#TC-P-01-E` | 家庭 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:FamilyInviteController |
-| `tests/test-cases/parent.md#TC-P-02-E` | 家庭/成员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:FamilyInviteController |
-| `tests/test-cases/parent.md#TC-P-03-E` | 成员资料 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:FamilyMembersController |
-| `tests/test-cases/parent.md#TC-P-04-E` | 关系图 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:关系类型 CRUD/前端选择器 |
-| `tests/test-cases/parent.md#TC-P-05-E` | 任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController |
-| `tests/test-cases/parent.md#TC-P-06-E` | 任务审核 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController`/`PointsController |
-| `tests/test-cases/parent.md#TC-P-07-E` | 心愿 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:WishController`/`RewardController |
-| `tests/test-cases/parent.md#TC-P-08-E` | 能量 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:EnergyController |
-| `tests/test-cases/parent.md#TC-P-09-E` | 测评订单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:AssessmentAppointmentController |
-| `tests/test-cases/parent.md#TC-P-10-E` | 健康报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:健康报告上传解析 |
-| `tests/test-cases/parent.md#TC-P-11-E` | 报告查看 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告解析 |
-| `tests/test-cases/parent.md#TC-P-12-E` | 饮食推荐 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐系统 |
-| `tests/test-cases/parent.md#TC-P-13-E` | AI 方案 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AI 统一走 LangGraph;`AiGateway |
-| `tests/test-cases/parent.md#TC-P-14-E` | 方案提交 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案状态机 |
-| `tests/test-cases/parent.md#TC-P-15-E` | 双角色 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:POST /api/family/member/switch`(替代废弃 switch-mode);双角色铁律 |
-| `tests/test-cases/parent.md#TC-P-16-E` | 会员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:MembershipController`/`ProductOrderController |
-| `tests/test-cases/parent.md#TC-P-17-E` | 积分/成长 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:PointsController`/`GrowthController |
-| `tests/test-cases/parent.md#TC-P-18-E` | AI 对话 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AIChatController`;LangGraph RAG |
-| `tests/test-cases/parent.md#TC-P-19-E` | 能量配置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:维度配置 |
-| `tests/test-cases/parent.md#TC-P-20-E` | 健康报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告解析中台/`POST /api/media/upload |
-| `tests/test-cases/parent.md#TC-P-21-E` | 报告解析 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:/api/admin/report-parser/types |
-| `tests/test-cases/parent.md#TC-P-22-E` | 报告预览 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:解析中台 |
-| `tests/test-cases/parent.md#TC-P-23-E` | 报告入库 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:解析中台 |
-| `tests/test-cases/parent.md#TC-P-24-E` | 报告管理 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告管理 |
-| `tests/test-cases/parent.md#TC-P-25-E` | 报告趋势 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:成长/报告 |
-| `tests/test-cases/parent.md#TC-P-26-E` | 饮食推荐 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐系统 |
-| `tests/test-cases/parent.md#TC-P-27-E` | 家庭食谱 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐/家庭食谱 |
-| `tests/test-cases/parent.md#TC-P-28-E` | 食谱筛选 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐 |
-| `tests/test-cases/parent.md#TC-P-29-E` | 食谱收藏 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐 |
-| `tests/test-cases/parent.md#TC-P-30-E` | 食谱营养 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:饮食推荐 |
-| `tests/test-cases/parent.md#TC-P-31-E` | 测评类型 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:DanAssessmentController |
-| `tests/test-cases/parent.md#TC-P-32-E` | 测评规划师 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:测评订单 |
-| `tests/test-cases/parent.md#TC-P-33-E` | 测评下单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:AssessmentOrder |
-| `tests/test-cases/parent.md#TC-P-34-E` | 测评支付 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:支付/`AssessmentQuota |
-| `tests/test-cases/parent.md#TC-P-35-E` | 测评额度 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AssessmentQuota |
-| `tests/test-cases/parent.md#TC-P-36-E` | 测评预约 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:AssessmentAppointmentController |
-| `tests/test-cases/parent.md#TC-P-37-E` | 预约状态 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:AssessmentAppointmentController |
-| `tests/test-cases/parent.md#TC-P-38-E` | 预约取消 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:AssessmentAppointmentController |
-| `tests/test-cases/parent.md#TC-P-39-E` | DAN报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:DanAssessmentResultDTO |
-| `tests/test-cases/parent.md#TC-P-40-E` | AI方案 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AIChatController`/`AiGateway |
-| `tests/test-cases/parent.md#TC-P-41-E` | 方案迭代 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AIChatController |
-| `tests/test-cases/parent.md#TC-P-42-E` | 方案编辑 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/parent.md#TC-P-43-E` | 方案查看 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/parent.md#TC-P-44-E` | 方案确认 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案状态机 |
-| `tests/test-cases/parent.md#TC-P-45-E` | 方案发布 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/parent.md#TC-P-46-E` | 方案激活 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案激活任务分解 |
-| `tests/test-cases/parent.md#TC-P-47-E` | 方案任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:GrowthPlanController |
-| `tests/test-cases/parent.md#TC-P-48-E` | 方案版本 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/parent.md#TC-P-49-E` | AI对话 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:AIChatController |
-| `tests/test-cases/parent.md#TC-P-50-E` | 成长记录 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:GrowthController |
-| `tests/test-cases/parent.md#TC-P-51-E` | 成长里程碑 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:GrowthController |
-| `tests/test-cases/parent.md#TC-P-52-E` | 商城浏览 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:MallController`/`danshop |
-| `tests/test-cases/parent.md#TC-P-53-E` | 商品详情 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:MallController |
-| `tests/test-cases/parent.md#TC-P-54-E` | 商城下单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:MallController |
-| `tests/test-cases/parent.md#TC-P-55-E` | 订单支付 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:支付 |
-| `tests/test-cases/parent.md#TC-P-56-E` | 订单退款 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:订单服务 |
-| `tests/test-cases/parent.md#TC-P-57-E` | 优惠券 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:优惠券 |
-| `tests/test-cases/parent.md#TC-P-58-E` | 会员购买 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:MemberController |
-| `tests/test-cases/parent.md#TC-P-59-E` | 会员权益 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:MemberController |
-| `tests/test-cases/parent.md#TC-P-60-E` | 会员续费 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:MemberController |
-| `tests/test-cases/parent.md#TC-P-61-E` | 联系人 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:ContactCard`/`contact-detail |
-| `tests/test-cases/parent.md#TC-P-62-E` | 联系人导入 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:ContactImport |
-| `tests/test-cases/parent.md#TC-P-63-E` | 联系人权限 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:ContactCard |
-| `tests/test-cases/parent.md#TC-P-64-E` | 个人资料 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:AuthController |
-| `tests/test-cases/parent.md#TC-P-65-E` | 通知设置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:消息服务 |
-| `tests/test-cases/parent.md#TC-P-66-E` | 隐私设置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:隐私设置 |
-| `tests/test-cases/parent.md#TC-P-67-E` | 报告代传/report-proxy | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告代传/report-proxy |
-| `tests/test-cases/parent.md#TC-P-68-E` | 家庭天盘 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:家庭天盘 |
-| `tests/test-cases/parent.md#TC-P-69-E` | 精准营养 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:精准营养 |
-| `tests/test-cases/parent.md#TC-P-70-E` | 舌诊情绪识别 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:舌诊情绪识别 |
-| `tests/test-cases/parent.md#TC-P-71-E` | AuthController | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:AuthController |
-| `tests/test-cases/parent.md#TC-P-72-E` | 数据导出(GDPR) | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:数据导出(GDPR) |
-| `tests/test-cases/parent.md#TC-P-73-E` | 家庭/成员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:家庭/成员 |
-| `tests/test-cases/parent.md#TC-P-74-E` | 规划师绑定 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:规划师绑定 |
-| `tests/test-cases/parent.md#TC-P-75-E` | 优惠券 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:优惠券 |
-| `tests/test-cases/parent.md#TC-P-76-E` | 活动管理 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:活动管理 |
-| `tests/test-cases/parent.md#TC-P-77-E` | 活动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:活动 |
-| `tests/test-cases/parent.md#TC-P-78-E` | 消息服务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:消息服务 |
-| `tests/test-cases/parent.md#TC-P-79-E` | 消息服务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:消息服务 |
-| `tests/test-cases/parent.md#TC-P-80-E` | 会员/订单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确|e2e:会员/订单 |
-| `tests/test-cases/parent.md#TC-P-81-E` | 方案/任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务|e2e:方案/任务 |
-| `tests/test-cases/parent.md#TC-P-82-E` | 搜索 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:搜索 |
-| `tests/test-cases/parent.md#TC-P-83-E` | 客服 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据|e2e:客服 |
-| `tests/test-cases/parent.md#TC-P-84-E` | 分享 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:分享 |
-| `tests/test-cases/parent.md#TC-P-85-E` | AuthController | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:AuthController |
-| `tests/test-cases/parent.md#TC-P-86-E` | 勋章/排行 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:勋章/排行 |
+| `tests/test-cases/parent.md#TC-P-01-E` | 家庭 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:名称空或超长返回 400 且 message 含『家庭名称』校验项;HTML/SQL 注入被转义,库内不落恶意串;不抛 500、不泄露堆栈|e2e:FamilyInviteController |
+| `tests/test-cases/parent.md#TC-P-02-E` | 家庭/成员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非法手机号 400 提示格式;已占用账号提示『已存在家庭关系』;过期码提示『邀请已失效,请重新获取』;均不建立成员关系|e2e:FamilyInviteController |
+| `tests/test-cases/parent.md#TC-P-03-E` | 成员资料 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未来生日 400;关系非法值拒绝;姓名特殊字符转义存储、不破坏查询;既有成员数据不被污染|e2e:FamilyMembersController |
+| `tests/test-cases/parent.md#TC-P-04-E` | 关系图 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复关系提示已存在、不新增节点;非法枚举 400;关系图不出现重复/幽灵节点|e2e:关系类型 CRUD/前端选择器 |
+| `tests/test-cases/parent.md#TC-P-05-E` | 任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:频率非法 400;并发双发幂等,仅生成 1 条任务、仅 1 次能量预期;超期任务拒绝提交|e2e:TaskController |
+| `tests/test-cases/parent.md#TC-P-06-E` | 任务审核 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复审批幂等不双计积分;驳回→重做→再审批仅在重做后计 1 次;超期任务审批被拒|e2e:TaskController`/`PointsController |
+| `tests/test-cases/parent.md#TC-P-07-E` | 心愿 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:余额不足拦截且不扣负积分;已取消心愿兑换提示失效;并发幂等仅扣 1 次|e2e:WishController`/`RewardController |
+| `tests/test-cases/parent.md#TC-P-08-E` | 能量 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:查询超时降级为空态提示非 500;权重为 0 时占比按兜底(0%)显示不崩;首访空态正常|e2e:EnergyController |
+| `tests/test-cases/parent.md#TC-P-09-E` | 测评订单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:回调验签失败订单保持 pending 不进待安排;余额不足回滚;重复回调幂等仅落 1 次已支付|e2e:AssessmentAppointmentController |
+| `tests/test-cases/parent.md#TC-P-10-E` | 健康报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:损坏文件识别失败进未知聚类并提示;非募极明确提示『请确认是募极生物肠道菌群报告』;超大/加密提示超限或密码保护,均非 500|e2e:健康报告上传解析 |
+| `tests/test-cases/parent.md#TC-P-11-E` | 报告查看 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:不存在/已删返回 404 提示『报告不存在』;解析中提示『报告解析中,请稍候』,不白屏不 500|e2e:报告解析 |
+| `tests/test-cases/parent.md#TC-P-12-E` | 饮食推荐 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:AiGateway Fallback 返回兜底食材清单+友好提示非 500;重复点击幂等仅生成 1 份、不重复扣费|e2e:饮食推荐系统 |
+| `tests/test-cases/parent.md#TC-P-13-E` | AI 方案 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:Fallback 兜底方案+提示;未购会员请求付费板块返回『请先开通会员』拦截,不白生成|e2e:AI 统一走 LangGraph;`AiGateway |
+| `tests/test-cases/parent.md#TC-P-14-E` | 方案提交 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:空方案提交拦截提示『方案未生成』;重复提交幂等不重复进审核|e2e:方案状态机 |
+| `tests/test-cases/parent.md#TC-P-15-E` | 双角色 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:缺失/过期 token 统一 401 跳登录;孩子端无切回家长入口;非法切换 403 被拒;模拟登录仅测试环境生效|e2e:POST /api/family/member/switch`(替代废弃 switch-mode);双角色铁律 |
+| `tests/test-cases/parent.md#TC-P-16-E` | 会员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付超时订单回滚不解锁权益;重复购买幂等仅开通 1 次、不重复扣费|e2e:MembershipController`/`ProductOrderController |
+| `tests/test-cases/parent.md#TC-P-17-E` | 积分/成长 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发刷新总量一致不重复计;关联任务已删时该成长项跳过不报错,时间格式 yyyy-MM-dd HH:mm:ss|e2e:PointsController`/`GrowthController |
+| `tests/test-cases/parent.md#TC-P-18-E` | AI 对话 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超长消息 400 提示;敏感词按合规拦截;LangGraph 不可用 Fallback 兜底回答,多轮上下文不丢|e2e:AIChatController`;LangGraph RAG |
+| `tests/test-cases/parent.md#TC-P-19-E` | 能量配置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:配置缺失展示兜底说明非 500;权重和非法 400 提示『权重合计需为 100%』|e2e:维度配置 |
+| `tests/test-cases/parent.md#TC-P-20-E` | 健康报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:损坏文件识别失败进未知聚类并提示;非募极明确提示『请确认是募极生物肠道菌群报告』;超大/加密提示超限或密码保护,均非 500|e2e:报告解析中台/`POST /api/media/upload |
+| `tests/test-cases/parent.md#TC-P-21-E` | 报告解析 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未注册类型进未知聚类待运营自学习;0 字节文件提示『文件为空』;均非 500|e2e:/api/admin/report-parser/types |
+| `tests/test-cases/parent.md#TC-P-22-E` | 报告预览 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:异常值提示『数据异常,暂不入库』不入库;超时提示解析中,不白屏|e2e:解析中台 |
+| `tests/test-cases/parent.md#TC-P-23-E` | 报告入库 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:报告已删提示『报告不存在,确认失败』;并发确认幂等仅入库 1 次、七维仅刷新 1 次|e2e:解析中台 |
+| `tests/test-cases/parent.md#TC-P-24-E` | 报告管理 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:有方案时提示『请先解除关联方案』再删;不存在 id 返回 404 不崩|e2e:报告管理 |
+| `tests/test-cases/parent.md#TC-P-25-E` | 报告趋势 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:单报告提示『至少需要 2 份报告才能看趋势』;时间轴按真实时间升序,不倒挂|e2e:成长/报告 |
+| `tests/test-cases/parent.md#TC-P-26-E` | 饮食推荐 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:AiGateway Fallback 返回兜底食材清单+友好提示非 500;重复点击幂等仅生成 1 份、不重复扣费|e2e:饮食推荐系统 |
+| `tests/test-cases/parent.md#TC-P-27-E` | 家庭食谱 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时 Fallback 通用食谱+提示;过敏食材未排除时返回 400 提示『存在过敏冲突』重算|e2e:饮食推荐/家庭食谱 |
+| `tests/test-cases/parent.md#TC-P-28-E` | 食谱筛选 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:忌口冲突提示并停止生成;非法忌口值 400;重算生效|e2e:饮食推荐 |
+| `tests/test-cases/parent.md#TC-P-29-E` | 食谱收藏 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:替换后提示『超出营养目标』不静默;重复收藏幂等仅 1 条|e2e:饮食推荐 |
+| `tests/test-cases/parent.md#TC-P-30-E` | 食谱营养 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:超标明确标红提示『超出目标 X%』;未设目标提示先设目标,不除零|e2e:饮食推荐 |
+| `tests/test-cases/parent.md#TC-P-31-E` | 测评类型 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:字典缺失时前端降级不白屏;非法 type 400;八类以字典为准|e2e:DanAssessmentController |
+| `tests/test-cases/parent.md#TC-P-32-E` | 测评规划师 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未绑定提示『请先绑定规划师』;已解绑 T 不在可选列表,选则 400|e2e:测评订单 |
+| `tests/test-cases/parent.md#TC-P-33-E` | 测评下单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:下架套餐 400『套餐不可售』;数量非法/库存不足拦截,不生成订单|e2e:AssessmentOrder |
+| `tests/test-cases/parent.md#TC-P-34-E` | 测评支付 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时回滚不生成额度;重复回调幂等仅生成 1 条额度|e2e:支付/`AssessmentQuota |
+| `tests/test-cases/parent.md#TC-P-35-E` | 测评额度 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:过期额度预约返回『额度已过期』不落预约;额度页加载降级非 500|e2e:AssessmentQuota |
+| `tests/test-cases/parent.md#TC-P-36-E` | 测评预约 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:无额度返回『额度不足或已过期』不建预约不发能量;并发双发仅落 1 条预约、能量仅发 1 次(幂等)|e2e:AssessmentAppointmentController |
+| `tests/test-cases/parent.md#TC-P-37-E` | 预约状态 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:状态机守卫拒绝非法跃迁返回 400;不存在预约 404;状态准确|e2e:AssessmentAppointmentController |
+| `tests/test-cases/parent.md#TC-P-38-E` | 预约取消 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权取消 403 被拒(CFC-AP);终态预约取消返回『不可取消』;不退款逻辑按配置|e2e:AssessmentAppointmentController |
+| `tests/test-cases/parent.md#TC-P-39-E` | DAN报告 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未录入提示『结果待录入』不白屏;缺字段校验 400 提示缺哪项|e2e:DanAssessmentResultDTO |
+| `tests/test-cases/parent.md#TC-P-40-E` | AI方案 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:Fallback 兜底方案+提示;未购会员请求付费板块返回『请先开通会员』拦截,不白生成|e2e:AIChatController`/`AiGateway |
+| `tests/test-cases/parent.md#TC-P-41-E` | 方案迭代 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:断网 Fallback 保留其他板块不丢;连续点击幂等仅 1 次重生成|e2e:AIChatController |
+| `tests/test-cases/parent.md#TC-P-42-E` | 方案编辑 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超长 400 提示;越权编辑 403 被拒;编辑后状态标记已改|e2e:方案管理 |
+| `tests/test-cases/parent.md#TC-P-43-E` | 方案查看 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:空方案展示占位不白屏;不存在 404|e2e:方案管理 |
+| `tests/test-cases/parent.md#TC-P-44-E` | 方案确认 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未确认激活拦截『请先确认』;重复确认幂等仅 1 次 reviewed|e2e:方案状态机 |
+| `tests/test-cases/parent.md#TC-P-45-E` | 方案发布 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:需审核配置时发布走审核流不直接 active;未 reviewed 发布拦截|e2e:方案管理 |
+| `tests/test-cases/parent.md#TC-P-46-E` | 方案激活 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已激活再激活幂等不重复生成任务;超时回滚不残半任务,状态回 reviewed|e2e:方案激活任务分解 |
+| `tests/test-cases/parent.md#TC-P-47-E` | 方案任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:删任务同步方案并提示;非法 id 400;任务增删与方案一致|e2e:GrowthPlanController |
+| `tests/test-cases/parent.md#TC-P-48-E` | 方案版本 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:历史版本只读返回 403『版本不可篡改』;不存在 404|e2e:方案管理 |
+| `tests/test-cases/parent.md#TC-P-49-E` | AI对话 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超长消息 400 提示;敏感词按合规拦截;LangGraph 不可用 Fallback 兜底回答,多轮上下文不丢|e2e:AIChatController |
+| `tests/test-cases/parent.md#TC-P-50-E` | 成长记录 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:关联已删项跳过不报错;首访空态正常,时间线不白屏|e2e:GrowthController |
+| `tests/test-cases/parent.md#TC-P-51-E` | 成长里程碑 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:重复标幂等仅 1 条;非法节点 400|e2e:GrowthController |
+| `tests/test-cases/parent.md#TC-P-52-E` | 商城浏览 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:注入被转义返回安全结果;下架商品不展示;不 500|e2e:MallController`/`danshop |
+| `tests/test-cases/parent.md#TC-P-53-E` | 商品详情 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:库存 0 提示『暂时缺货』;不存在 404|e2e:MallController |
+| `tests/test-cases/parent.md#TC-P-54-E` | 商城下单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超库存拦截『库存不足』;重复提交幂等仅 1 单|e2e:MallController |
+| `tests/test-cases/parent.md#TC-P-55-E` | 订单支付 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时回滚订单保持待支付;重复通知幂等仅 1 次 paid|e2e:支付 |
+| `tests/test-cases/parent.md#TC-P-56-E` | 订单退款 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已发货按规则处理/拒;重复退款拦截仅 1 次|e2e:订单服务 |
+| `tests/test-cases/parent.md#TC-P-57-E` | 优惠券 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:过期券不可用提示;未达门槛拦截『还差 X 元可用』;不重复抵扣|e2e:优惠券 |
+| `tests/test-cases/parent.md#TC-P-58-E` | 会员购买 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:失败回滚不解锁;重复购买幂等仅 1 次、不双扣|e2e:MemberController |
+| `tests/test-cases/parent.md#TC-P-59-E` | 会员权益 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:过期提示『会员已失效』;越权 403;权益随档位|e2e:MemberController |
+| `tests/test-cases/parent.md#TC-P-60-E` | 会员续费 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:未到期续费叠加计算正确(延期);负金额 400|e2e:MemberController |
+| `tests/test-cases/parent.md#TC-P-61-E` | 联系人 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复号码去重提示;非法格式 400;不建重复|e2e:ContactCard`/`contact-detail |
+| `tests/test-cases/parent.md#TC-P-62-E` | 联系人导入 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:错误行跳过并报告『第 N 行格式错误』;非 CSV 拒绝;正确行入库|e2e:ContactImport |
+| `tests/test-cases/parent.md#TC-P-63-E` | 联系人权限 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权查看 403;非法权限值 400;最小权限保底|e2e:ContactCard |
+| `tests/test-cases/parent.md#TC-P-64-E` | 个人资料 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:手机格式 400;昵称超长/非法字符拦截;保存生效|e2e:AuthController |
+| `tests/test-cases/parent.md#TC-P-65-E` | 通知设置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:关键安全通知仍推送不被关;非法时间 400|e2e:消息服务 |
+| `tests/test-cases/parent.md#TC-P-66-E` | 隐私设置 | 家长 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:非法范围 400;敏感字段最小权限保底不外露|e2e:隐私设置 |
+| `tests/test-cases/parent.md#TC-P-67-E` | 报告代传/report-proxy | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:越权代传他人孩子 403 被拒;报告归属校验失败不入档;授权令牌失效提示|e2e:报告代传/report-proxy |
+| `tests/test-cases/parent.md#TC-P-68-E` | 家庭天盘 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:缺失项降级展示不白屏;非成员访问 403;仅本家庭可见|e2e:家庭天盘 |
+| `tests/test-cases/parent.md#TC-P-69-E` | 精准营养 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:负/超上限 400『热量需在合理区间』;非数字 400;目标生效影响食谱|e2e:精准营养 |
+| `tests/test-cases/parent.md#TC-P-70-E` | 舌诊情绪识别 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非照片/模糊拒绝提示『请上传清晰舌苔照』;低置信度提示『识别不清晰,建议重拍』;隐私标注不外露|e2e:舌诊情绪识别 |
+| `tests/test-cases/parent.md#TC-P-71-E` | AuthController | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:有在途订单拦截『请先处理进行中订单』;注销后 token 失效 401 不可登录|e2e:AuthController |
+| `tests/test-cases/parent.md#TC-P-72-E` | 数据导出(GDPR) | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权导出 403;频次限制提示『导出过于频繁』;敏感字段脱敏|e2e:数据导出(GDPR) |
+| `tests/test-cases/parent.md#TC-P-73-E` | 家庭/成员 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非本家庭孩子不可选 400;切换保持各孩子上下文隔离不串|e2e:家庭/成员 |
+| `tests/test-cases/parent.md#TC-P-74-E` | 规划师绑定 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:在途未完成提示『请先处理在途服务』;非本家庭 T 绑定 400 被拒|e2e:规划师绑定 |
+| `tests/test-cases/parent.md#TC-P-75-E` | 优惠券 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:库存 0 提示『已领完』;重复领幂等仅入卡包 1 张|e2e:优惠券 |
+| `tests/test-cases/parent.md#TC-P-76-E` | 活动管理 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:并发超卖拦截仅 1 人成功(CFC 已修 bug 回归);满额拒『名额已满』;重复报名幂等|e2e:活动管理 |
+| `tests/test-cases/parent.md#TC-P-77-E` | 活动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复打卡幂等仅计 1 次;刷量风控拦截;进度累计正确|e2e:活动 |
+| `tests/test-cases/parent.md#TC-P-78-E` | 消息服务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权消息不可见 403;不存在 404;分页正常|e2e:消息服务 |
+| `tests/test-cases/parent.md#TC-P-79-E` | 消息服务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:关键安全通知不可关;非法时间 400|e2e:消息服务 |
+| `tests/test-cases/parent.md#TC-P-80-E` | 会员/订单 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已消费不退提示;重复退拦截;发票信息校验缺失字段 400|e2e:会员/订单 |
+| `tests/test-cases/parent.md#TC-P-81-E` | 方案/任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:过期草稿提示『草稿已失效』;并发存后者覆盖且提示冲突|e2e:方案/任务 |
+| `tests/test-cases/parent.md#TC-P-82-E` | 搜索 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权结果过滤不可见;空结果不报错提示『请输入关键词』|e2e:搜索 |
+| `tests/test-cases/parent.md#TC-P-83-E` | 客服 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:敏感信息脱敏存储;附件超限 400『附件不超过 10MB』|e2e:客服 |
+| `tests/test-cases/parent.md#TC-P-84-E` | 分享 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:失效链接提示『分享已失效』;越权分享 403 被拒|e2e:分享 |
+| `tests/test-cases/parent.md#TC-P-85-E` | AuthController | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:异常设备二次验证/拦截;退出后旧 token 失效 401|e2e:AuthController |
+| `tests/test-cases/parent.md#TC-P-86-E` | 勋章/排行 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非本家庭榜不可见 403;排名仅本家庭数据,刷新即更新|e2e:勋章/排行 |
 | `tests/test-cases/parent.md#TC-P-01-P` | 家庭 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyInviteController |
 | `tests/test-cases/parent.md#TC-P-01-P` | 家庭 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyInviteController |
 | `tests/test-cases/parent.md#TC-P-02-P` | 家庭/成员 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyInviteController |
 | `tests/test-cases/parent.md#TC-P-02-P` | 家庭/成员 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyInviteController |
 | `tests/test-cases/parent.md#TC-P-03-P` | 成员资料 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyMembersController |
 | `tests/test-cases/parent.md#TC-P-03-P` | 成员资料 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:FamilyMembersController |
@@ -561,6 +582,27 @@
 | `tests/test-cases/parent.md#TC-P-84-P` | 分享 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:分享 |
 | `tests/test-cases/parent.md#TC-P-84-P` | 分享 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:分享 |
 | `tests/test-cases/parent.md#TC-P-85-P` | AuthController | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:AuthController |
 | `tests/test-cases/parent.md#TC-P-85-P` | AuthController | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:AuthController |
 | `tests/test-cases/parent.md#TC-P-86-P` | 勋章/排行 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:勋章/排行 |
 | `tests/test-cases/parent.md#TC-P-86-P` | 勋章/排行 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒|e2e:勋章/排行 |
+| `tests/test-cases/parent.md#TC-P-87` | 能量/任务 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:B 对应维度 balance/totalEarned +amount;EnergyLog.sourceType=task、balanceAfter 正确;概览/沙盘随新值刷新|e2e:EnergyRuleEngine`/`TaskController |
+| `tests/test-cases/parent.md#TC-P-88` | 能量/心愿 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:扣减成功,EnergyLog 负 amount、balanceAfter=balance-额;balance/totalSpent 同步;心愿已兑换|e2e:EnergyController`/`RewardController |
+| `tests/test-cases/parent.md#TC-P-89` | 能量/手动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:指定维度 +amount;EnergyLog.sourceType=manual 留痕;balanceAfter 更新|e2e:EnergyController |
+| `tests/test-cases/parent.md#TC-P-90` | 能量/日上限 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:累计达 N 后新增触发不再累加(或截断到上限);跨日 00:00 清零可重新获取|e2e:DimensionDailyLimit |
+| `tests/test-cases/parent.md#TC-P-91` | 能量/健康报告 | 家长 | P0 | 文档用例(待自动化) | 未跟踪 | 设计:七维/六维评分刷新;概览/沙盘/score-history 按新值重算;时间序列反映改善|e2e:HealthReportController |
+| `tests/test-cases/parent.md#TC-P-92` | 能量/配置 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:按新口径重算并展示;存量重算提示|e2e:EnergyController`/维度配置 |
+| `tests/test-cases/parent.md#TC-P-93` | 能量/文章·活动 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:对应维度 +amount;sourceType=article/activity;balanceAfter 更新|e2e:ArticleService`/`ActivityService |
+| `tests/test-cases/parent.md#TC-P-87-E` | 能量/任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 重复审批幂等不重复加、无第二条 EnergyLog 2. 无归因维度不 500、按规则落 sourceType 或不加 3. 参数非法统一 400、不改动能量 4. 规则异常告警、不写脏流水|e2e:EnergyRuleEngine |
+| `tests/test-cases/parent.md#TC-P-88-E` | 能量/心愿 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 余额不足明确"能量不足"、心愿保持待审批、无负余额 2. 并发仅一次成功、二次幂等拒 3. 已兑换再提交拒、无负流水 4. 参数非法 400、不扣减|e2e:EnergyController`/`RewardController |
+| `tests/test-cases/parent.md#TC-P-89-E` | 能量/手动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 400 拦截不发放 2. 400 不写脏数据 3. 按幂等/业务规则不重复加|e2e:EnergyController |
+| `tests/test-cases/parent.md#TC-P-90-E` | 能量/日上限 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 触顶后其余来源同维度受限 2. 手动口径断言一致 3. 以服务端日期为准、不绕过 4. 上限 0/负 拒绝配置或按 0、不崩溃|e2e:DimensionDailyLimit |
+| `tests/test-cases/parent.md#TC-P-91-E` | 能量/健康报告 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 不刷新、原评分保留 2. 类型不一致不可比/提示、不串维度 3. 该维度保持上一值或空态、不 500 4. 重复入库幂等不重复刷新|e2e:HealthReportController |
+| `tests/test-cases/parent.md#TC-P-92-E` | 能量/配置 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 报警并拒或归一化、不静默错算 2. 展示兜底旧值并提示"同步中"、不显示错乱 3. 400 拦截|e2e:EnergyController`/维度配置 |
+| `tests/test-cases/parent.md#TC-P-93-E` | 能量/文章·活动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 风控拦截不计能量 2. 触顶不累加 3. 按规则回收或保留、不双发 4. 参与被拒不发放|e2e:ArticleService`/`ActivityService |
+| `tests/test-cases/parent.md#TC-P-87-P` | 能量/任务 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 非本家庭能量访问 403 2. 孩子端无 grant 入口、直接调被 role 校验拒|e2e:JwtInterceptor`+role |
+| `tests/test-cases/parent.md#TC-P-88-P` | 能量/心愿 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 非本家庭心愿 403 2. 孩子端无扣减入口、直接调被拒|e2e:EnergyController |
+| `tests/test-cases/parent.md#TC-P-89-P` | 能量/手动 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 非本家庭 grant 403 2. 孩子端拒|e2e:JwtInterceptor`+role |
+| `tests/test-cases/parent.md#TC-P-90-P` | 能量/日上限 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 他人累计不可见 403 2. 越权改配置 403|e2e:DimensionDailyLimit |
+| `tests/test-cases/parent.md#TC-P-91-P` | 能量/健康报告 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本家庭健康维度数据 403、不泄露|e2e:HealthReportController |
+| `tests/test-cases/parent.md#TC-P-92-P` | 能量/配置 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非 admin 改全局 403|e2e:EnergyController |
+| `tests/test-cases/parent.md#TC-P-93-P` | 能量/文章·活动 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非本家庭流水 403|e2e:ArticleService`/`ActivityService |
 | `tests/test-cases/parent.md#TC-P-N01` | 健康报告 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:上传+解析 ≤ 30s;超时走 AiGateway 友好降级而非 500;进度可见|e2e:健康报告上传解析 |
 | `tests/test-cases/parent.md#TC-P-N01` | 健康报告 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:上传+解析 ≤ 30s;超时走 AiGateway 友好降级而非 500;进度可见|e2e:健康报告上传解析 |
 | `tests/test-cases/parent.md#TC-P-N02` | AI 方案 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:各方案独立完整、数据不串;单请求 P95 ≤ 15s;LangGraph 超时回退 Fallback|e2e:AiGateway/LangGraph |
 | `tests/test-cases/parent.md#TC-P-N02` | AI 方案 | 家长 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:各方案独立完整、数据不串;单请求 P95 ≤ 15s;LangGraph 超时回退 Fallback|e2e:AiGateway/LangGraph |
 | `tests/test-cases/parent.md#TC-P-N03` | 任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:首屏 ≤ 2s;翻页流畅;分页/虚拟滚动生效|e2e:TaskController |
 | `tests/test-cases/parent.md#TC-P-N03` | 任务 | 家长 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:首屏 ≤ 2s;翻页流畅;分页/虚拟滚动生效|e2e:TaskController |
@@ -603,35 +645,35 @@
 | `tests/test-cases/teacher.md#TC-T-27` | 家庭天盘 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:给家庭看聚合视图并解读;边界:仅绑定家庭可见|e2e:家庭天盘 |
 | `tests/test-cases/teacher.md#TC-T-27` | 家庭天盘 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:给家庭看聚合视图并解读;边界:仅绑定家庭可见|e2e:家庭天盘 |
 | `tests/test-cases/teacher.md#TC-T-28` | 内容安全 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:复核 AI 敏感内容;边界:命中即拦截|e2e:内容安全 |
 | `tests/test-cases/teacher.md#TC-T-28` | 内容安全 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:复核 AI 敏感内容;边界:命中即拦截|e2e:内容安全 |
 | `tests/test-cases/teacher.md#TC-T-29` | 数据导出(GDPR) | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:导出客户数据;边界:授权/脱敏;越权拒|e2e:数据导出(GDPR) |
 | `tests/test-cases/teacher.md#TC-T-29` | 数据导出(GDPR) | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:导出客户数据;边界:授权/脱敏;越权拒|e2e:数据导出(GDPR) |
-| `tests/test-cases/teacher.md#TC-T-01-E` | 认证/双角色 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController`;规划师可切回家长 |
-| `tests/test-cases/teacher.md#TC-T-02-E` | 家庭绑定 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:FamilyInviteController |
-| `tests/test-cases/teacher.md#TC-T-03-E` | 健康报告 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告上传解析;规划师代传 |
-| `tests/test-cases/teacher.md#TC-T-04-E` | 报告审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告审核 |
-| `tests/test-cases/teacher.md#TC-T-05-E` | 方案管理 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理;黑盒回归项 |
-| `tests/test-cases/teacher.md#TC-T-06-E` | 方案审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案状态机 |
-| `tests/test-cases/teacher.md#TC-T-07-E` | 方案激活 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:激活拆任务 |
-| `tests/test-cases/teacher.md#TC-T-08-E` | 方案激活·幂等 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:幂等约束(黑盒回归) |
-| `tests/test-cases/teacher.md#TC-T-09-E` | 任务审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController |
-| `tests/test-cases/teacher.md#TC-T-10-E` | 测评录入 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退|e2e:AssessmentAppointmentController`/`DanAssessmentController |
-| `tests/test-cases/teacher.md#TC-T-11-E` | 成长计划 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:GrowthPlanController`;黑盒回归 |
-| `tests/test-cases/teacher.md#TC-T-12-E` | 套餐 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:GuidePackageController |
-| `tests/test-cases/teacher.md#TC-T-13-E` | 数据隔离 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:控制器内 role 检查 |
-| `tests/test-cases/teacher.md#TC-T-14-E` | 方案编辑 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/teacher.md#TC-T-15-E` | 套餐任务 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:GuidePackageController |
-| `tests/test-cases/teacher.md#TC-T-16-E` | 健康总览 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:仪表板 |
-| `tests/test-cases/teacher.md#TC-T-17-E` | 计划进度 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:GrowthPlanController |
-| `tests/test-cases/teacher.md#TC-T-18-E` | 批量任务 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500|e2e:TaskController |
-| `tests/test-cases/teacher.md#TC-T-19-E` | 消息推送 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:消息服务 |
-| `tests/test-cases/teacher.md#TC-T-20-E` | 退出/切换 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效|e2e:AuthController |
-| `tests/test-cases/teacher.md#TC-T-21-E` | 报告对比 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告管理 |
-| `tests/test-cases/teacher.md#TC-T-22-E` | 方案归档 | 规划师 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务|e2e:方案管理 |
-| `tests/test-cases/teacher.md#TC-T-23-E` | 报告代传/report-proxy | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:报告代传/report-proxy |
-| `tests/test-cases/teacher.md#TC-T-24-E` | 规划师绑定 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:规划师绑定 |
-| `tests/test-cases/teacher.md#TC-T-25-E` | 舌诊情绪识别 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:舌诊情绪识别 |
-| `tests/test-cases/teacher.md#TC-T-26-E` | 精准营养 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:精准营养 |
-| `tests/test-cases/teacher.md#TC-T-27-E` | 家庭天盘 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:家庭天盘 |
-| `tests/test-cases/teacher.md#TC-T-28-E` | 内容安全 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务|e2e:内容安全 |
-| `tests/test-cases/teacher.md#TC-T-29-E` | 数据导出(GDPR) | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务|e2e:数据导出(GDPR) |
+| `tests/test-cases/teacher.md#TC-T-01-E` | 认证/双角色 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:缺失/过期 token 统一 401 跳登录;非绑定家庭路由 403 被拒;模拟登录开关仅在测试环境可开|e2e:AuthController`;规划师可切回家长 |
+| `tests/test-cases/teacher.md#TC-T-02-E` | 家庭绑定 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:错码/过期提示『邀请码无效或已失效』;重复绑定幂等不双建;注销家庭不可绑|e2e:FamilyInviteController |
+| `tests/test-cases/teacher.md#TC-T-03-E` | 健康报告 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:损坏/非募极提示明确(非募极提示请确认募极生物);超大超限提示;解析超时进草稿非500;非绑定孩子 403|e2e:报告上传解析;规划师代传 |
+| `tests/test-cases/teacher.md#TC-T-04-E` | 报告审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已删草稿提示『不存在』;解析中确认提示稍候;非绑定家庭草稿 403 不可操作|e2e:报告审核 |
+| `tests/test-cases/teacher.md#TC-T-05-E` | 方案管理 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:列表超时降级提示非500;黑盒回归:函数不再未定义、不白屏;空列表正常占位|e2e:方案管理;黑盒回归项 |
+| `tests/test-cases/teacher.md#TC-T-06-E` | 方案审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非 generated 态批准拦截(状态机守卫);并发双批准幂等仅 1 次状态跃迁|e2e:方案状态机 |
+| `tests/test-cases/teacher.md#TC-T-07-E` | 方案激活 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时回滚不残半任务、状态回 reviewed;已激活再激活幂等不重复生成任务;非 reviewed 激活拦截|e2e:激活拆任务 |
+| `tests/test-cases/teacher.md#TC-T-08-E` | 方案激活·幂等 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:第二次幂等返回现状、不重复生成引导/模板任务;任务数与首次一致|e2e:幂等约束(黑盒回归) |
+| `tests/test-cases/teacher.md#TC-T-09-E` | 任务审核 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭 403;并发双审幂等仅计 1 次积分;超期任务审核被拒|e2e:TaskController |
+| `tests/test-cases/teacher.md#TC-T-10-E` | 测评录入 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:必填缺失 400 不生成半成品;重复录入覆盖非新增;越界 400 不写脏分;非指派 confirm 返回『您不是被指派测评师』|e2e:AssessmentAppointmentController`/`DanAssessmentController |
+| `tests/test-cases/teacher.md#TC-T-11-E` | 成长计划 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;空列表正常;非绑定家庭 403|e2e:GrowthPlanController`;黑盒回归 |
+| `tests/test-cases/teacher.md#TC-T-12-E` | 套餐 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:空任务项拦截上架;审核超时回退草稿非500;重复提交幂等|e2e:GuidePackageController |
+| `tests/test-cases/teacher.md#TC-T-13-E` | 数据隔离 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭统一 403;不泄露他人数据;并发越权同样 403|e2e:控制器内 role 检查 |
+| `tests/test-cases/teacher.md#TC-T-14-E` | 方案编辑 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:归档方案编辑拦截;非绑定家庭 403;超长 400|e2e:方案管理 |
+| `tests/test-cases/teacher.md#TC-T-15-E` | 套餐任务 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重算超时降级提示非500;空套餐拦截;并发增删各自生效不丢项|e2e:GuidePackageController |
+| `tests/test-cases/teacher.md#TC-T-16-E` | 健康总览 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:缺失项降级展示不白屏;超时降级提示非500;仅绑定家庭数据|e2e:仪表板 |
+| `tests/test-cases/teacher.md#TC-T-17-E` | 计划进度 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:超时降级非500;进度按任务状态实时计算、一致|e2e:GrowthPlanController |
+| `tests/test-cases/teacher.md#TC-T-18-E` | 批量任务 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:部分失败不影响其他成员独立落库;并发批量各自独立不串|e2e:TaskController |
+| `tests/test-cases/teacher.md#TC-T-19-E` | 消息推送 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:已注销客户跳过不报错;内容转义不执行脚本;免打扰不推送|e2e:消息服务 |
+| `tests/test-cases/teacher.md#TC-T-20-E` | 退出/切换 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:旧 token 失效 401;网络中断退出清缓存、下次需重登;切回家长正常|e2e:AuthController |
+| `tests/test-cases/teacher.md#TC-T-21-E` | 报告对比 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:类型不一致提示不可比;不存在 id 404;差异清晰标注|e2e:报告管理 |
+| `tests/test-cases/teacher.md#TC-T-22-E` | 方案归档 | 规划师 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:归档后编辑/激活拦截;不存在 404|e2e:方案管理 |
+| `tests/test-cases/teacher.md#TC-T-23-E` | 报告代传/report-proxy | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭 403 拒;损坏/非募极提示明确;识别失败进草稿非500|e2e:报告代传/report-proxy |
+| `tests/test-cases/teacher.md#TC-T-24-E` | 规划师绑定 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:在途未完成提示先处理;非平台家庭绑定 400 拒|e2e:规划师绑定 |
+| `tests/test-cases/teacher.md#TC-T-25-E` | 舌诊情绪识别 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:类型校验拒绝(.php/.html)不执行;非照片/模糊拒;低置信度提示重拍|e2e:舌诊情绪识别 |
+| `tests/test-cases/teacher.md#TC-T-26-E` | 精准营养 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:负/超上限 400『热量需在合理区间』;脚本转义存储不执行|e2e:精准营养 |
+| `tests/test-cases/teacher.md#TC-T-27-E` | 家庭天盘 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭 403;缺失项降级展示不白屏|e2e:家庭天盘 |
+| `tests/test-cases/teacher.md#TC-T-28-E` | 内容安全 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:命中即拦截不放行;超时 Fallback 兜底、友好提示非500|e2e:内容安全 |
+| `tests/test-cases/teacher.md#TC-T-29-E` | 数据导出(GDPR) | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越权导出 403;频次限制提示『导出过于频繁』;敏感字段脱敏|e2e:数据导出(GDPR) |
 | `tests/test-cases/teacher.md#TC-T-01-P` | 认证/双角色 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:AuthController`;规划师可切回家长 |
 | `tests/test-cases/teacher.md#TC-T-01-P` | 认证/双角色 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:AuthController`;规划师可切回家长 |
 | `tests/test-cases/teacher.md#TC-T-02-P` | 家庭绑定 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:FamilyInviteController |
 | `tests/test-cases/teacher.md#TC-T-02-P` | 家庭绑定 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:FamilyInviteController |
 | `tests/test-cases/teacher.md#TC-T-03-P` | 健康报告 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:报告上传解析;规划师代传 |
 | `tests/test-cases/teacher.md#TC-T-03-P` | 健康报告 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复)|e2e:报告上传解析;规划师代传 |
@@ -661,6 +703,15 @@
 | `tests/test-cases/teacher.md#TC-T-27-P` | 家庭天盘 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:家庭天盘 |
 | `tests/test-cases/teacher.md#TC-T-27-P` | 家庭天盘 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:家庭天盘 |
 | `tests/test-cases/teacher.md#TC-T-28-P` | 内容安全 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:内容安全 |
 | `tests/test-cases/teacher.md#TC-T-28-P` | 内容安全 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:内容安全 |
 | `tests/test-cases/teacher.md#TC-T-29-P` | 数据导出(GDPR) | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:数据导出(GDPR) |
 | `tests/test-cases/teacher.md#TC-T-29-P` | 数据导出(GDPR) | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒|e2e:数据导出(GDPR) |
+| `tests/test-cases/teacher.md#TC-T-30` | 测评/五维 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:八类分→五维刷新;生成 generated 方案;概览/沙盘刷新|e2e:AssessmentAppointmentService |
+| `tests/test-cases/teacher.md#TC-T-31` | 维度/手动 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:目标维度覆盖/调整并留痕;概览/沙盘随新值刷新|e2e:ManualDimensionScoreController |
+| `tests/test-cases/teacher.md#TC-T-32` | 五维/自评 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:自评微调并叠加;FiveDimensionSelfCheck 留记录;历史可查|e2e:FiveDimensionSelfCheckController |
+| `tests/test-cases/teacher.md#TC-T-30-E` | 测评/五维 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:1. 400 不生成半成品 2. 覆盖非新增、无重复记录 3. 越界 400 不写脏分|e2e:AssessmentAppointmentService |
+| `tests/test-cases/teacher.md#TC-T-31-E` | 维度/手动 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:1. 400 拦截 2. 幂等无重复痕迹;不影响其他维度(断言)|e2e:ManualDimensionScoreController |
+| `tests/test-cases/teacher.md#TC-T-32-E` | 五维/自评 | 规划师 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:400 拦截;不写脏分|e2e:FiveDimensionSelfCheckController |
+| `tests/test-cases/teacher.md#TC-T-30-P` | 测评/五维 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭录入 403|e2e:AssessmentAppointmentService |
+| `tests/test-cases/teacher.md#TC-T-31-P` | 维度/手动 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭 403|e2e:ManualDimensionScoreController |
+| `tests/test-cases/teacher.md#TC-T-32-P` | 五维/自评 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非绑定家庭 403|e2e:FiveDimensionSelfCheckController |
 | `tests/test-cases/teacher.md#TC-T-N01` | 健康报告 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:队列不堵;单份 ≤ 30s;失败重试不重复入库|e2e:报告解析中台 |
 | `tests/test-cases/teacher.md#TC-T-N01` | 健康报告 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:队列不堵;单份 ≤ 30s;失败重试不重复入库|e2e:报告解析中台 |
 | `tests/test-cases/teacher.md#TC-T-N02` | 方案审核 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:列表 ≤ 2s;筛选/排序生效|e2e:方案状态机 |
 | `tests/test-cases/teacher.md#TC-T-N02` | 方案审核 | 规划师 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:列表 ≤ 2s;筛选/排序生效|e2e:方案状态机 |
 | `tests/test-cases/teacher.md#TC-T-N03` | 绑定家庭 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:切换 ≤ 1.5s;数据隔离不串|e2e:绑定家庭 |
 | `tests/test-cases/teacher.md#TC-T-N03` | 绑定家庭 | 规划师 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:切换 ≤ 1.5s;数据隔离不串|e2e:绑定家庭 |
@@ -680,17 +731,17 @@
 | `tests/test-cases/vendor.md#TC-S-9` | 服务商集成/解析中台 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:提供解析能力;边界:跨商户隔离;鉴权|e2e:服务商集成/解析中台 |
 | `tests/test-cases/vendor.md#TC-S-9` | 服务商集成/解析中台 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:提供解析能力;边界:跨商户隔离;鉴权|e2e:服务商集成/解析中台 |
 | `tests/test-cases/vendor.md#TC-S-10` | 食谱库 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:供食谱数据;边界:数据合规;格式校验|e2e:食谱库 |
 | `tests/test-cases/vendor.md#TC-S-10` | 食谱库 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:供食谱数据;边界:数据合规;格式校验|e2e:食谱库 |
 | `tests/test-cases/vendor.md#TC-S-11` | 合规 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:授权内用数;边界:越授权拒;脱敏|e2e:合规 |
 | `tests/test-cases/vendor.md#TC-S-11` | 合规 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:达成目标:授权内用数;边界:越授权拒;脱敏|e2e:合规 |
-| `tests/test-cases/vendor.md#TC-S-01-E` | 入驻 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈|e2e:ServiceRoleApplicationController`/`AdminEcomSupplierController |
-| `tests/test-cases/vendor.md#TC-S-02-E` | 商品 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:ProductController`/`AdminProductController |
-| `tests/test-cases/vendor.md#TC-S-03-E` | 订单 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:ProductOrderController |
-| `tests/test-cases/vendor.md#TC-S-04-E` | 订单核销 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:订单服务 |
-| `tests/test-cases/vendor.md#TC-S-05-E` | 库存 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:库存服务 |
-| `tests/test-cases/vendor.md#TC-S-06-E` | 售后 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:售后 |
-| `tests/test-cases/vendor.md#TC-S-07-E` | 活动报名 | 服务商 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认|e2e:活动管理 |
-| `tests/test-cases/vendor.md#TC-S-08-E` | 对账 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等|e2e:结算 |
-| `tests/test-cases/vendor.md#TC-S-9-E` | 服务商集成/解析中台 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:服务商集成/解析中台 |
-| `tests/test-cases/vendor.md#TC-S-10-E` | 食谱库 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」|e2e:食谱库 |
-| `tests/test-cases/vendor.md#TC-S-11-E` | 合规 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规|e2e:合规 |
+| `tests/test-cases/vendor.md#TC-S-01-E` | 入驻 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:资质缺失驳回并说明缺项;重复申请幂等不双建;非法联系方式 400|e2e:ServiceRoleApplicationController`/`AdminEcomSupplierController |
+| `tests/test-cases/vendor.md#TC-S-02-E` | 商品 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:负价格/负库存/非法分类统一 400;并发改库存乐观锁不互相覆盖;下架后不可购买|e2e:ProductController`/`AdminProductController |
+| `tests/test-cases/vendor.md#TC-S-03-E` | 订单 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:支付失败订单回滚不进已发货;重复发货幂等仅 1 次;核销码校验失败拒(防冒用)|e2e:ProductOrderController |
+| `tests/test-cases/vendor.md#TC-S-04-E` | 订单核销 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复核销幂等;超期提示不可核销;非本服务商 403|e2e:订单服务 |
+| `tests/test-cases/vendor.md#TC-S-05-E` | 库存 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:负库存 400 拦截;并发超卖保护不出现负库存;同步失败重试前台一致|e2e:库存服务 |
+| `tests/test-cases/vendor.md#TC-S-06-E` | 售后 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:重复退款拦截仅 1 次;超金额 400;非本服务商 403;流水可追溯|e2e:售后 |
+| `tests/test-cases/vendor.md#TC-S-07-E` | 活动报名 | 服务商 | P3 | 文档用例(待自动化) | 未跟踪 | 设计:失效活动报名拒;重复报名幂等;非法参数 400|e2e:活动管理 |
+| `tests/test-cases/vendor.md#TC-S-08-E` | 对账 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:未到账期结算拒;重复结算幂等;异常金额告警不入账|e2e:结算 |
+| `tests/test-cases/vendor.md#TC-S-9-E` | 服务商集成/解析中台 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:跨商户隔离 403;损坏/超大文件明确提示非500;鉴权失效 401|e2e:服务商集成/解析中台 |
+| `tests/test-cases/vendor.md#TC-S-10-E` | 食谱库 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:格式校验 400;XSS 转义存储不执行;非本商户 403|e2e:食谱库 |
+| `tests/test-cases/vendor.md#TC-S-11-E` | 合规 | 服务商 | P2 | 文档用例(待自动化) | 未跟踪 | 设计:越授权 403 拒;敏感字段强制脱敏;并发越权同样 403|e2e:合规 |
 | `tests/test-cases/vendor.md#TC-S-01-P` | 入驻 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ServiceRoleApplicationController`/`AdminEcomSupplierController |
 | `tests/test-cases/vendor.md#TC-S-01-P` | 入驻 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ServiceRoleApplicationController`/`AdminEcomSupplierController |
 | `tests/test-cases/vendor.md#TC-S-02-P` | 商品 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ProductController`/`AdminProductController |
 | `tests/test-cases/vendor.md#TC-S-02-P` | 商品 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ProductController`/`AdminProductController |
 | `tests/test-cases/vendor.md#TC-S-03-P` | 订单 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ProductOrderController |
 | `tests/test-cases/vendor.md#TC-S-03-P` | 订单 | 服务商 | P1 | 文档用例(待自动化) | 未跟踪 | 设计:非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离|e2e:ProductOrderController |
@@ -723,13 +774,13 @@
 | `tests/e2e/admin-panel.spec.js` | 4 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/admin-panel.spec.js` | 4 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/admin-promotion-config.spec.js` | 2 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/admin-promotion-config.spec.js` | 2 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/ai-plan-task-flow.spec.js` | 7 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/ai-plan-task-flow.spec.js` | 7 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/api-smoke.spec.js` | 4 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/article-api.spec.js` | 7 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/contact-api.spec.js` | 6 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/energy-api.spec.js` | 8 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/family-member-api.spec.js` | 14 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/nonfunc-perf-compat.spec.js` | 5 | 已自动化(e2e) | 未跟踪 | — |
-| `tests/e2e/api/nonfunc-security.spec.js` | 11 | 已自动化(e2e) | 未跟踪 | — |
+| `tests/e2e/api/api-smoke.spec.js` | 4 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/article-api.spec.js` | 7 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/contact-api.spec.js` | 6 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/energy-api.spec.js` | 8 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/family-member-api.spec.js` | 14 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/nonfunc-perf-compat.spec.js` | 5 | 已自动化(e2e) | 通过 | — |
+| `tests/e2e/api/nonfunc-security.spec.js` | 11 | 已自动化(e2e) | 失败 | — |
 | `tests/e2e/article-management.spec.js` | 5 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/article-management.spec.js` | 5 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/assessment-appointment-functional.spec.js` | 7 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/assessment-appointment-functional.spec.js` | 7 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/assessment-appointment.spec.js` | 6 | 已自动化(e2e) | 未跟踪 | — |
 | `tests/e2e/assessment-appointment.spec.js` | 6 | 已自动化(e2e) | 未跟踪 | — |
@@ -804,40 +855,46 @@
 
 
 | 来源 | 用例数 | 自动化状态 | 执行状态 | 目标类 |
 | 来源 | 用例数 | 自动化状态 | 执行状态 | 目标类 |
 | --- | --- | --- | --- | --- |
 | --- | --- | --- | --- | --- |
-| `cfc-backend/src/test/java/com/etotem/cfc/common/AdminRolesTest.java` | 9 | 已自动化(@Test) | 未跟踪 | AdminRoles |
+| `cfc-backend/src/test/java/com/etotem/cfc/common/AdminRolesTest.java` | 9 | 已自动化(@Test) | 通过 | AdminRoles |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/TestRoles.java` | 0 | 已自动化(@Test) | 未跟踪 | TestRoles.java |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/TestRoles.java` | 0 | 已自动化(@Test) | 未跟踪 | TestRoles.java |
-| `cfc-backend/src/test/java/com/etotem/cfc/config/AttributionStage1FoundationTest.java` | 7 | 已自动化(@Test) | 未跟踪 | AttributionStage1Foundation |
-| `cfc-backend/src/test/java/com/etotem/cfc/config/DatabaseInitializerSeedTest.java` | 6 | 已自动化(@Test) | 未跟踪 | DatabaseInitializerSeed |
-| `cfc-backend/src/test/java/com/etotem/cfc/config/FamilyAccessInterceptorTest.java` | 11 | 已自动化(@Test) | 未跟踪 | FamilyAccessInterceptor |
-| `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | 5 | 已自动化(@Test) | 未跟踪 | JwtInterceptorLoginRequired |
-| `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` | 1 | 已自动化(@Test) | 未跟踪 | AttributionController |
-| `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | 3 | 已自动化(@Test) | 未跟踪 | AttributionSurveyRouting |
+| `cfc-backend/src/test/java/com/etotem/cfc/config/AttributionStage1FoundationTest.java` | 7 | 已自动化(@Test) | 通过 | AttributionStage1Foundation |
+| `cfc-backend/src/test/java/com/etotem/cfc/config/DatabaseInitializerSeedTest.java` | 6 | 已自动化(@Test) | 通过 | DatabaseInitializerSeed |
+| `cfc-backend/src/test/java/com/etotem/cfc/config/FamilyAccessInterceptorTest.java` | 11 | 已自动化(@Test) | 通过 | FamilyAccessInterceptor |
+| `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | 5 | 已自动化(@Test) | 通过 | JwtInterceptorLoginRequired |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` | 1 | 已自动化(@Test) | 通过 | AttributionController |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | 3 | 已自动化(@Test) | 通过 | AttributionSurveyRouting |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java` | 2 | 已自动化(@Test) | 未跟踪 | DanAssessmentControllerGetActiveMaterial |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerGrantEnergyTest.java` | 3 | 已自动化(@Test) | 未跟踪 | EnergyControllerGrantEnergy |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerGrantEnergyTest.java` | 3 | 已自动化(@Test) | 未跟踪 | EnergyControllerGrantEnergy |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthCheckinCfEarnCallSite |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthCheckinCfEarnCallSite |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthPlanDeleteController |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthPlanDeleteController |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerCreateReportTest.java` | 5 | 已自动化(@Test) | 未跟踪 | HealthReportControllerCreateReport |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` | 4 | 已自动化(@Test) | 未跟踪 | HealthReportControllerListPagination |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` | 4 | 已自动化(@Test) | 未跟踪 | HealthReportControllerListPagination |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthReportControllerProxyParseBinding |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthReportControllerProxyParseBinding |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | 2 | 已自动化(@Test) | 未跟踪 | IndicatorController |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | 2 | 已自动化(@Test) | 未跟踪 | IndicatorController |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | 10 | 已自动化(@Test) | 未跟踪 | IndicatorFavoriteController |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | 10 | 已自动化(@Test) | 未跟踪 | IndicatorFavoriteController |
-| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` | 4 | 已自动化(@Test) | 未跟踪 | AdminProductControllerBatchShelve |
-| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | 3 | 已自动化(@Test) | 未跟踪 | ReportParserAdminController |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminAuthWechatScanTest.java` | 11 | 已自动化(@Test) | 未跟踪 | AdminAuthWechatScan |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` | 4 | 已自动化(@Test) | 通过 | AdminProductControllerBatchShelve |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | 3 | 已自动化(@Test) | 通过 | ReportParserAdminController |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/SupplyTeamControllerInviteTest.java` | 7 | 已自动化(@Test) | 未跟踪 | SupplyTeamControllerInvite |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerAddMemberTest.java` | 7 | 已自动化(@Test) | 未跟踪 | FamilyMembersControllerAddMember |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | 4 | 已自动化(@Test) | 未跟踪 | FamilyMembersControllerList |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | 4 | 已自动化(@Test) | 未跟踪 | FamilyMembersControllerList |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` | 2 | 已自动化(@Test) | 未跟踪 | FamilyMembersControllerRenameFamily |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` | 2 | 已自动化(@Test) | 未跟踪 | FamilyMembersControllerRenameFamily |
-| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` | 1 | 已自动化(@Test) | 未跟踪 | TeacherMessageControllerMy |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` | 1 | 已自动化(@Test) | 通过 | TeacherMessageControllerMy |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TrainingPlanControllerGetPlanListTest.java` | 10 | 已自动化(@Test) | 通过 | TrainingPlanControllerGetPlanList |
 | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` | 3 | 已自动化(@Test) | 未跟踪 | ActivityDTO |
 | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` | 3 | 已自动化(@Test) | 未跟踪 | ActivityDTO |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` | 6 | 已自动化(@Test) | 未跟踪 | DailyCheckinStreakFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` | 6 | 已自动化(@Test) | 未跟踪 | DailyCheckinStreakFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | 7 | 已自动化(@Test) | 未跟踪 | EnergySystemFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | 7 | 已自动化(@Test) | 未跟踪 | EnergySystemFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GrowthRecordSyncFlowTest.java` | 10 | 已自动化(@Test) | 未跟踪 | GrowthRecordSyncFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GrowthRecordSyncFlowTest.java` | 10 | 已自动化(@Test) | 未跟踪 | GrowthRecordSyncFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GuideModuleIntegrationTest.java` | 4 | 已自动化(@Test) | 未跟踪 | GuideModule |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GuideModuleIntegrationTest.java` | 4 | 已自动化(@Test) | 未跟踪 | GuideModule |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/PlannerBindInviteFlowTest.java` | 9 | 已自动化(@Test) | 未跟踪 | PlannerBindInviteFlow |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/PlannerBindInviteFlowTest.java` | 9 | 已自动化(@Test) | 未跟踪 | PlannerBindInviteFlow |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AIChatControllerTest.java` | 17 | 已自动化(@Test) | 未跟踪 | AIChatController |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ActivityControllerTest.java` | 16 | 已自动化(@Test) | 未跟踪 | ActivityController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AIChatControllerTest.java` | 17 | 已自动化(@Test) | 通过 | AIChatController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ActivityControllerTest.java` | 16 | 已自动化(@Test) | 通过 | ActivityController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AdminFamilyOverviewControllerTest.java` | 3 | 已自动化(@Test) | 未跟踪 | AdminFamilyOverviewController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AdminFamilyOverviewControllerTest.java` | 3 | 已自动化(@Test) | 未跟踪 | AdminFamilyOverviewController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AdminSpecialPriceControllerTest.java` | 8 | 已自动化(@Test) | 未跟踪 | AdminSpecialPriceController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AdminSpecialPriceControllerTest.java` | 8 | 已自动化(@Test) | 未跟踪 | AdminSpecialPriceController |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleCategoryControllerTest.java` | 3 | 已自动化(@Test) | 未跟踪 | ArticleCategoryController |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleControllerTest.java` | 11 | 已自动化(@Test) | 未跟踪 | ArticleController |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AuthControllerTest.java` | 39 | 已自动化(@Test) | 未跟踪 | AuthController |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DailyTaskControllerTest.java` | 2 | 已自动化(@Test) | 未跟踪 | DailyTaskController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleCategoryControllerTest.java` | 3 | 已自动化(@Test) | 通过 | ArticleCategoryController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleControllerTest.java` | 11 | 已自动化(@Test) | 失败 | ArticleController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AuthControllerTest.java` | 39 | 已自动化(@Test) | 失败 | AuthController |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DailyTaskControllerTest.java` | 2 | 已自动化(@Test) | 通过 | DailyTaskController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DimensionAdminControllerTest.java` | 13 | 已自动化(@Test) | 未跟踪 | DimensionAdminController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DimensionAdminControllerTest.java` | 13 | 已自动化(@Test) | 未跟踪 | DimensionAdminController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/FamilyControllerTest.java` | 8 | 已自动化(@Test) | 未跟踪 | FamilyController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/FamilyControllerTest.java` | 8 | 已自动化(@Test) | 未跟踪 | FamilyController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideFamilyTaskControllerTest.java` | 20 | 已自动化(@Test) | 未跟踪 | GuideFamilyTaskController |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideFamilyTaskControllerTest.java` | 20 | 已自动化(@Test) | 未跟踪 | GuideFamilyTaskController |
@@ -863,7 +920,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | 21 | 已自动化(@Test) | 未跟踪 | DimensionScoreService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | 21 | 已自动化(@Test) | 未跟踪 | DimensionScoreService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | 9 | 已自动化(@Test) | 未跟踪 | FamilyFoodOverviewService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | 9 | 已自动化(@Test) | 未跟踪 | FamilyFoodOverviewService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | 2 | 已自动化(@Test) | 未跟踪 | FiveDimensionSelfCheckService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | 2 | 已自动化(@Test) | 未跟踪 | FiveDimensionSelfCheckService |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | 18 | 已自动化(@Test) | 未跟踪 | FoodRecommendService |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | 21 | 已自动化(@Test) | 未跟踪 | FoodRecommendService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | 12 | 已自动化(@Test) | 未跟踪 | FoodService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | 12 | 已自动化(@Test) | 未跟踪 | FoodService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | 4 | 已自动化(@Test) | 未跟踪 | FortuneService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | 4 | 已自动化(@Test) | 未跟踪 | FortuneService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | 8 | 已自动化(@Test) | 未跟踪 | GuideApplicationService |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | 8 | 已自动化(@Test) | 未跟踪 | GuideApplicationService |
@@ -907,6 +964,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | 4 | 已自动化(@Test) | 未跟踪 | EnergyServiceWealthIncome |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | 4 | 已自动化(@Test) | 未跟踪 | EnergyServiceWealthIncome |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | 3 | 已自动化(@Test) | 未跟踪 | FamilyAdminOverviewService |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | 3 | 已自动化(@Test) | 未跟踪 | FamilyAdminOverviewService |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyJoinRequestServiceReferrerBind |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyJoinRequestServiceReferrerBind |
+| `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyMemberServiceIsChildTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyMemberServiceIsChild |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyPlatformPointsServiceCoupon |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyPlatformPointsServiceCoupon |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` | 8 | 已自动化(@Test) | 未跟踪 | HealthReportServiceAuditConfirm |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` | 8 | 已自动化(@Test) | 未跟踪 | HealthReportServiceAuditConfirm |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | 5 | 已自动化(@Test) | 未跟踪 | HealthReportServiceBackfillResilience |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | 5 | 已自动化(@Test) | 未跟踪 | HealthReportServiceBackfillResilience |
@@ -991,6 +1049,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` | 3 | 已自动化(@Test) | 未跟踪 | TaskProgressUpdate |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` | 3 | 已自动化(@Test) | 未跟踪 | TaskProgressUpdate |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | 8 | 已自动化(@Test) | 未跟踪 | CfFormulaEvaluator |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | 8 | 已自动化(@Test) | 未跟踪 | CfFormulaEvaluator |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | 6 | 已自动化(@Test) | 未跟踪 | SpearmanUtil |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | 6 | 已自动化(@Test) | 未跟踪 | SpearmanUtil |
+| `cfc-backend/src/test/java/com/etotem/cfc/util/UserUtilTest.java` | 6 | 已自动化(@Test) | 未跟踪 | UserUtil |
 
 
 ## 六、用户场景(`tests/user-scenarios/*.md`,上游输入)
 ## 六、用户场景(`tests/user-scenarios/*.md`,上游输入)
 
 
@@ -1002,8 +1061,9 @@
 | `tests/user-scenarios/04-teacher.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 9 个 |
 | `tests/user-scenarios/04-teacher.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 9 个 |
 | `tests/user-scenarios/05-admin.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 8 个 |
 | `tests/user-scenarios/05-admin.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 8 个 |
 | `tests/user-scenarios/06-vendor.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 4 个 |
 | `tests/user-scenarios/06-vendor.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 4 个 |
+| `tests/user-scenarios/07-five-dimension.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 18 个 |
 | `tests/user-scenarios/README.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 4 个 |
 | `tests/user-scenarios/README.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 4 个 |
-| `tests/user-scenarios/应用场景总览.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 23 个 |
+| `tests/user-scenarios/应用场景总览.md` | 文件级 | 用户场景(待自动化) | 未跟踪 | 场景标题约 29 个 |
 
 
 ## 七、回写与发布流程(本地侧车 → 共享台账)
 ## 七、回写与发布流程(本地侧车 → 共享台账)
 
 

+ 39 - 23
docs/tdd/test/discovery.md

@@ -8,28 +8,27 @@
 | 指标 | 数值 |
 | 指标 | 数值 |
 | --- | --- |
 | --- | --- |
 | 控制器总数 | 357 |
 | 控制器总数 | 357 |
-| handler 方法总数 | 1933 |
-| handler 方法已覆盖 | 199 (10.3%) |
+| handler 方法总数 | 1935 |
+| handler 方法已覆盖 | 203 (10.5%) |
 | 单元-全覆盖(handler 方法) | 16 |
 | 单元-全覆盖(handler 方法) | 16 |
-| 单元-部分覆盖(handler 方法) | 69 |
-| 单元-未覆盖(handler 方法) | 271 |
+| 单元-部分覆盖(handler 方法) | 72 |
+| 单元-未覆盖(handler 方法) | 268 |
 | 单元-无handler 方法 | 1 |
 | 单元-无handler 方法 | 1 |
-| 测试文件数 | 182 |
-| @Test 方法总数 | 1379 |
+| 测试文件数 | 195 |
+| @Test 方法总数 | 1451 |
 | 含跳过/假设项(test 级 partial) | 4 |
 | 含跳过/假设项(test 级 partial) | 4 |
 
 
 ## 二、未覆盖控制器(发现「缺口」· 非发明)
 ## 二、未覆盖控制器(发现「缺口」· 非发明)
 
 
 > 以下控制器在当前测试源中**没有任何handler 方法被命中**。这是真实扫描得到的覆盖缺口。
 > 以下控制器在当前测试源中**没有任何handler 方法被命中**。这是真实扫描得到的覆盖缺口。
 
 
-共 271 个:
+共 268 个:
 
 
 - `AdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminController.java`,65 方法)
 - `AdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminController.java`,65 方法)
 - `DanAssessmentController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/DanAssessmentController.java`,29 方法)
 - `DanAssessmentController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/DanAssessmentController.java`,29 方法)
 - `AdminArticleController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminArticleController.java`,22 方法)
 - `AdminArticleController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminArticleController.java`,22 方法)
 - `TaskController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/task/TaskController.java`,18 方法)
 - `TaskController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/task/TaskController.java`,18 方法)
-- `FamilyUserController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/family/FamilyUserController.java`,17 方法)
-- `AdminInventoryController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminInventoryController.java`,16 方法)
+- `AdminInventoryController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminInventoryController.java`,15 方法)
 - `FamilyInviteController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/family/FamilyInviteController.java`,15 方法)
 - `FamilyInviteController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/family/FamilyInviteController.java`,15 方法)
 - `OrchestrationController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/OrchestrationController.java`,15 方法)
 - `OrchestrationController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/OrchestrationController.java`,15 方法)
 - `KeyPersonController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/KeyPersonController.java`,14 方法)
 - `KeyPersonController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/KeyPersonController.java`,14 方法)
@@ -47,7 +46,6 @@
 - `TeacherController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/guide/TeacherController.java`,10 方法)
 - `TeacherController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/guide/TeacherController.java`,10 方法)
 - `UserController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/UserController.java`,10 方法)
 - `UserController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/UserController.java`,10 方法)
 - `AdminButlerController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminButlerController.java`,9 方法)
 - `AdminButlerController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminButlerController.java`,9 方法)
-- `FamilyMembersController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/family/FamilyMembersController.java`,9 方法)
 - `FileRecordController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/FileRecordController.java`,9 方法)
 - `FileRecordController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/FileRecordController.java`,9 方法)
 - `GutHealthProjectController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/GutHealthProjectController.java`,9 方法)
 - `GutHealthProjectController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/GutHealthProjectController.java`,9 方法)
 - `KnowledgeBaseController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/KnowledgeBaseController.java`,9 方法)
 - `KnowledgeBaseController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/KnowledgeBaseController.java`,9 方法)
@@ -55,7 +53,6 @@
 - `PearlController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/PearlController.java`,9 方法)
 - `PearlController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/PearlController.java`,9 方法)
 - `PpointConfigAdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/PpointConfigAdminController.java`,9 方法)
 - `PpointConfigAdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/PpointConfigAdminController.java`,9 方法)
 - `AdminActivityController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminActivityController.java`,8 方法)
 - `AdminActivityController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminActivityController.java`,8 方法)
-- `AdminAuthController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminAuthController.java`,8 方法)
 - `ArticleCommentController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/content/ArticleCommentController.java`,8 方法)
 - `ArticleCommentController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/content/ArticleCommentController.java`,8 方法)
 - `ContactController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/ContactController.java`,8 方法)
 - `ContactController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/ContactController.java`,8 方法)
 - `DanReportController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/DanReportController.java`,8 方法)
 - `DanReportController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/DanReportController.java`,8 方法)
@@ -70,6 +67,7 @@
 - `AdminUnlockGateController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminUnlockGateController.java`,7 方法)
 - `AdminUnlockGateController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminUnlockGateController.java`,7 方法)
 - `AssessmentAdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AssessmentAdminController.java`,7 方法)
 - `AssessmentAdminController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AssessmentAdminController.java`,7 方法)
 - `BeijingNutritionController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/nutrition/BeijingNutritionController.java`,7 方法)
 - `BeijingNutritionController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/nutrition/BeijingNutritionController.java`,7 方法)
+- `CartController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/cart/CartController.java`,7 方法)
 - `DanAssessmentExecutionController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/dan/DanAssessmentExecutionController.java`,7 方法)
 - `DanAssessmentExecutionController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/dan/DanAssessmentExecutionController.java`,7 方法)
 - `GrowthPlanController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/growth/GrowthPlanController.java`,7 方法)
 - `GrowthPlanController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/growth/GrowthPlanController.java`,7 方法)
 - `GuideActivityController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/guide/GuideActivityController.java`,7 方法)
 - `GuideActivityController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/guide/GuideActivityController.java`,7 方法)
@@ -84,18 +82,21 @@
 - `AdminHomeBannerController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminHomeBannerController.java`,6 方法)
 - `AdminHomeBannerController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminHomeBannerController.java`,6 方法)
 - `AdminNoticeController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminNoticeController.java`,6 方法)
 - `AdminNoticeController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminNoticeController.java`,6 方法)
 - `AdminPeriodicServiceController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminPeriodicServiceController.java`,6 方法)
 - `AdminPeriodicServiceController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminPeriodicServiceController.java`,6 方法)
-- …(其余 211 个见完整扫描)
+- `AdminPromotionTierController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminPromotionTierController.java`,6 方法)
+- `AdminSystemPromptController`(`cfc-backend/src/main/java/com/etotem/cfc/controller/admin/AdminSystemPromptController.java`,6 方法)
+- …(其余 208 个见完整扫描)
 
 
 ## 三、部分覆盖控制器(已做一部分测试)
 ## 三、部分覆盖控制器(已做一部分测试)
 
 
 > 这些控制器**已有测试但只覆盖了部分handler 方法**——即用户要求的「已经做了一部分测试的情况,要能够找到」。
 > 这些控制器**已有测试但只覆盖了部分handler 方法**——即用户要求的「已经做了一部分测试的情况,要能够找到」。
 
 
-共 69 个:
+共 72 个:
 
 
 - `HealthReportController`:覆盖 1/59,未覆盖方法:createReport、getLatestReport、listFamilyReports、listAllReports、getReportIndicatorsWithPrevious、listIndicators、getMemberIndicators、getGutFlora、rebuildIndicatorCurrent、getMemberIndicatorCurrent
 - `HealthReportController`:覆盖 1/59,未覆盖方法:createReport、getLatestReport、listFamilyReports、listAllReports、getReportIndicatorsWithPrevious、listIndicators、getMemberIndicators、getGutFlora、rebuildIndicatorCurrent、getMemberIndicatorCurrent
 - `HealthKnowledgeBaseController`:覆盖 1/28,未覆盖方法:batchQuery、list、add、update、delete、importKnowledgeBase、queryBacteria、batchQueryBacteria、queryIndicator、queryFood
 - `HealthKnowledgeBaseController`:覆盖 1/28,未覆盖方法:batchQuery、list、add、update、delete、importKnowledgeBase、queryBacteria、batchQueryBacteria、queryIndicator、queryFood
 - `ProductOrderController`:覆盖 7/19,未覆盖方法:myOrderCounts、vendorConfirm、reviewUpdate、ship、applyRefund、handlePaymentSuccess、notify、activityAudit、activitySignIn、activityComplete
 - `ProductOrderController`:覆盖 7/19,未覆盖方法:myOrderCounts、vendorConfirm、reviewUpdate、ship、applyRefund、handlePaymentSuccess、notify、activityAudit、activitySignIn、activityComplete
 - `AuthController`:覆盖 14/18,未覆盖方法:setSwitchPassword、verifyToken、ssoTicket、ssoLogin
 - `AuthController`:覆盖 14/18,未覆盖方法:setSwitchPassword、verifyToken、ssoTicket、ssoLogin
+- `FamilyUserController`:覆盖 1/17,未覆盖方法:getUserInfo、updateUserInfo、joinFamily、createFamily、switchMode、switchRole、switchToFamilyMember、switchBackToParent、switchBackVerify、createFamilyMember
 - `GuideManagementController`:覆盖 3/17,未覆盖方法:resubmitApplication、getUserApplications、getApplicationRecords、generateInviteCode、getInviteCodes、validateInviteCode、getChildGuides、getAllChildGuides、getParentGuide、getGuidePackageTemplates
 - `GuideManagementController`:覆盖 3/17,未覆盖方法:resubmitApplication、getUserApplications、getApplicationRecords、generateInviteCode、getInviteCodes、validateInviteCode、getChildGuides、getAllChildGuides、getParentGuide、getGuidePackageTemplates
 - `MembershipController`:覆盖 4/17,未覆盖方法:getAllLevels、getMyMembership、getUpgradeRecords、upgradeOrder、activateTrial、createOrder、continueOrder、getPricingPlans、getMembershipCompare、paymentNotify
 - `MembershipController`:覆盖 4/17,未覆盖方法:getAllLevels、getMyMembership、getUpgradeRecords、upgradeOrder、activateTrial、createOrder、continueOrder、getPricingPlans、getMembershipCompare、paymentNotify
 - `ArticleController`:覆盖 4/16,未覆盖方法:relatedProducts、related、relatedByProduct、getArticleAudio、reportReadingTime、readingStats、dailyTip、aiQuestions、submitAnswers、publish
 - `ArticleController`:覆盖 4/16,未覆盖方法:relatedProducts、related、relatedByProduct、getArticleAudio、reportReadingTime、readingStats、dailyTip、aiQuestions、submitAnswers、publish
@@ -108,7 +109,9 @@
 - `StatsController`:覆盖 4/12,未覆盖方法:getDashboardSummary、getRevenueStats、getMembershipStats、childOverview、familySummary、pointsRanking、getTrafficAnalytics、recordProductView
 - `StatsController`:覆盖 4/12,未覆盖方法:getDashboardSummary、getRevenueStats、getMembershipStats、childOverview、familySummary、pointsRanking、getTrafficAnalytics、recordProductView
 - `WishController`:覆盖 11/12,未覆盖方法:priceAlias
 - `WishController`:覆盖 11/12,未覆盖方法:priceAlias
 - `PaymentController`:覆盖 5/11,未覆盖方法:createWechatNativePay、getPaymentStatus、getOAuth2Url、oauth2Callback、handleV3Notify、generateQrCode
 - `PaymentController`:覆盖 5/11,未覆盖方法:createWechatNativePay、getPaymentStatus、getOAuth2Url、oauth2Callback、handleV3Notify、generateQrCode
+- `AdminAuthController`:覆盖 2/10,未覆盖方法:sendCode、login、getAdminInfo、changePassword、updateInfo、resetPassword、loginByPassword、accountRoles
 - `AdminVirtualTeamController`:覆盖 1/10,未覆盖方法:list、create、update、toggle、addMember、removeMember、updateMember、userTeams、tree
 - `AdminVirtualTeamController`:覆盖 1/10,未覆盖方法:list、create、update、toggle、addMember、removeMember、updateMember、userTeams、tree
+- `FamilyMembersController`:覆盖 1/10,未覆盖方法:listMembers、switchToMember、kickMember、leaveFamily、recycleMember、updateMember、renameFamily、checkEditable、logs
 - `GuideFamilyTaskController`:覆盖 8/10,未覆盖方法:unbindFamily、getDashboardStats
 - `GuideFamilyTaskController`:覆盖 8/10,未覆盖方法:unbindFamily、getDashboardStats
 - `SubscriptionController`:覆盖 1/10,未覆盖方法:getPlans、createOrder、subscribe、cancel、setAutoRenew、getMyBenefits、checkBenefit、getTier、updateTier
 - `SubscriptionController`:覆盖 1/10,未覆盖方法:getPlans、createOrder、subscribe、cancel、setAutoRenew、getMyBenefits、checkBenefit、getTier、updateTier
 - `AIChatController`:覆盖 3/9,未覆盖方法:reportAnalyze、deleteConversation、sendNutritionMessage、sendHealthCoachMessage、sendHealthButlerMessage、transcribe
 - `AIChatController`:覆盖 3/9,未覆盖方法:reportAnalyze、deleteConversation、sendNutritionMessage、sendHealthCoachMessage、sendHealthButlerMessage、transcribe
@@ -116,11 +119,11 @@
 - `EnergyController`:覆盖 5/9,未覆盖方法:configureSourceRatios、getScoreHistory、getFamilyScoreHistory、getWealthDetail
 - `EnergyController`:覆盖 5/9,未覆盖方法:configureSourceRatios、getScoreHistory、getFamilyScoreHistory、getWealthDetail
 - `FiveDimensionSelfCheckController`:覆盖 3/9,未覆盖方法:submit、getHistory、ignoreSelfCheck、generatePlan、getTrendAnalysis、aiGenerateQuestions
 - `FiveDimensionSelfCheckController`:覆盖 3/9,未覆盖方法:submit、getHistory、ignoreSelfCheck、generatePlan、getTrendAnalysis、aiGenerateQuestions
 - `ProductController`:覆盖 6/9,未覆盖方法:updateImages、specMap、relatedProducts
 - `ProductController`:覆盖 6/9,未覆盖方法:updateImages、specMap、relatedProducts
-- `SupplyTeamController`:覆盖 1/9,未覆盖方法:listCustomers、bindCustomer、getRelation、serviceAssign、serviceTasks、customerServices、updateServiceTask、serviceCandidates
 - `CognitiveController`:覆盖 1/8,未覆盖方法:getChildCognitiveScores、getFamilyCognitiveScores、updateCognitiveScore、getRecommendations、createTaskFromRecommendation、getNorms、submitSelfTest
 - `CognitiveController`:覆盖 1/8,未覆盖方法:getChildCognitiveScores、getFamilyCognitiveScores、updateCognitiveScore、getRecommendations、createTaskFromRecommendation、getNorms、submitSelfTest
 - `GuideTeamController`:覆盖 6/8,未覆盖方法:checkStatus、leaveTeam
 - `GuideTeamController`:覆盖 6/8,未覆盖方法:checkStatus、leaveTeam
 - `DoaController`:覆盖 1/7,未覆盖方法:createStage、stageDetail、cancelStage、submitPlan、submitReview、weekList
 - `DoaController`:覆盖 1/7,未覆盖方法:createStage、stageDetail、cancelStage、submitPlan、submitReview、weekList
 - `EmotionCheckinController`:覆盖 2/7,未覆盖方法:create、list、stats、weeklyReport、recognizeEmotion
 - `EmotionCheckinController`:覆盖 2/7,未覆盖方法:create、list、stats、weeklyReport、recognizeEmotion
+- `SupplyTeamController`:覆盖 1/7,未覆盖方法:listCustomers、bindCustomer、getRelation、getInviteCode、getInviteInfo、joinByInviteCode
 - `AdminEnergyConfigController`:覆盖 1/6,未覆盖方法:sourceList、sourceSave、sourceDelete、dailyLimits、dailyLimitSave
 - `AdminEnergyConfigController`:覆盖 1/6,未覆盖方法:sourceList、sourceSave、sourceDelete、dailyLimits、dailyLimitSave
 - `AdminGuidePopupController`:覆盖 1/6,未覆盖方法:list、create、update、delete、stats
 - `AdminGuidePopupController`:覆盖 1/6,未覆盖方法:list、create、update、delete、stats
 - `AdminPlannerExamController`:覆盖 1/6,未覆盖方法:papers、createPaper、updatePaper、deletePaper、saveQuestions
 - `AdminPlannerExamController`:覆盖 1/6,未覆盖方法:papers、createPaper、updatePaper、deletePaper、saveQuestions
@@ -173,11 +176,11 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfBalanceServiceTest.java` | com | 25 | 0 | 0 | CfBalanceController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfBalanceServiceTest.java` | com | 25 | 0 | 0 | CfBalanceController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorChangeServiceTest.java` | com | 23 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorChangeServiceTest.java` | com | 23 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | com | 21 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | com | 21 | 0 | 0 | — | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | com | 21 | 1 | 0 | FoodRecommendController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideRolePermissionTest.java` | com | 21 | 6 | 9 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideRolePermissionTest.java` | com | 21 | 6 | 9 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideFamilyTaskControllerTest.java` | com | 20 | 11 | 8 | GuideFamilyTaskController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideFamilyTaskControllerTest.java` | com | 20 | 11 | 8 | GuideFamilyTaskController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorChangeServiceSemanticTest.java` | com | 20 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorChangeServiceSemanticTest.java` | com | 20 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ProductOrderControllerTest.java` | com | 20 | 3 | 7 | ProductOrderController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ProductOrderControllerTest.java` | com | 20 | 3 | 7 | ProductOrderController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | com | 18 | 0 | 0 | FoodRecommendController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/SupplySystemServiceTest.java` | com | 18 | 0 | 0 | SupplySystemController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/SupplySystemServiceTest.java` | com | 18 | 0 | 0 | SupplySystemController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AIChatControllerTest.java` | com | 17 | 17 | 3 | AIChatController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/AIChatControllerTest.java` | com | 17 | 17 | 3 | AIChatController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/MembershipServiceTest.java` | com | 17 | 0 | 0 | MembershipController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/MembershipServiceTest.java` | com | 17 | 0 | 0 | MembershipController | — |
@@ -197,6 +200,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | com | 12 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | com | 12 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorTimelineServiceTest.java` | com | 12 | 24 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorTimelineServiceTest.java` | com | 12 | 24 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/PaymentControllerTest.java` | com | 12 | 17 | 5 | PaymentController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/PaymentControllerTest.java` | com | 12 | 17 | 5 | PaymentController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminAuthWechatScanTest.java` | com | 11 | 11 | 2 | AdminAuthController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleControllerTest.java` | com | 11 | 7 | 4 | ArticleController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleControllerTest.java` | com | 11 | 7 | 4 | ArticleController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfReferralServiceSalesTierTest.java` | com | 11 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfReferralServiceSalesTierTest.java` | com | 11 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfSpendDispatchServiceTest.java` | com | 11 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfSpendDispatchServiceTest.java` | com | 11 | 0 | 0 | — | — |
@@ -205,12 +209,13 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/PdfParseServiceTest.java` | com | 11 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/PdfParseServiceTest.java` | com | 11 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ActivityAdminServiceTest.java` | com | 10 | 9 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ActivityAdminServiceTest.java` | com | 10 | 9 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ActivityAuditTest.java` | com | 10 | 4 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ActivityAuditTest.java` | com | 10 | 4 | 0 | ActivityController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ComboServiceTest.java` | com | 10 | 3 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GrowthRecordSyncFlowTest.java` | com | 10 | 9 | 4 | GrowthController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/GrowthRecordSyncFlowTest.java` | com | 10 | 9 | 4 | GrowthController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideHierarchyServiceTest.java` | com | 10 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideHierarchyServiceTest.java` | com | 10 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanReviewGuardTest.java` | com | 10 | 0 | 0 | HealthPlanController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanReviewGuardTest.java` | com | 10 | 0 | 0 | HealthPlanController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | com | 10 | 8 | 3 | IndicatorFavoriteController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | com | 10 | 8 | 3 | IndicatorFavoriteController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TrainingPlanControllerGetPlanListTest.java` | com | 10 | 0 | 0 | TrainingPlanController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/AdminRolesTest.java` | com | 9 | 0 | 0 | AdminController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/AdminRolesTest.java` | com | 9 | 0 | 0 | AdminController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/BundlePricingCalculatorTest.java` | com | 9 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | com | 9 | 9 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | com | 9 | 9 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyAccessGuardTest.java` | com | 9 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyAccessGuardTest.java` | com | 9 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideTeamControllerTest.java` | com | 9 | 6 | 5 | GuideTeamController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideTeamControllerTest.java` | com | 9 | 6 | 5 | GuideTeamController | — |
@@ -226,6 +231,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/CfBalanceControllerTest.java` | com | 8 | 7 | 3 | CfBalanceController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/CfBalanceControllerTest.java` | com | 8 | 7 | 3 | CfBalanceController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfEarnDispatchServiceTest.java` | com | 8 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfEarnDispatchServiceTest.java` | com | 8 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | com | 8 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | com | 8 | 0 | 0 | — | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ComboOfferCalculatorTest.java` | com | 8 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/FamilyControllerTest.java` | com | 8 | 1 | 3 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/FamilyControllerTest.java` | com | 8 | 1 | 3 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | com | 8 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | com | 8 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideOrderControllerTest.java` | com | 8 | 11 | 3 | GuideOrderController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/GuideOrderControllerTest.java` | com | 8 | 11 | 3 | GuideOrderController | — |
@@ -237,8 +243,10 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/config/AttributionStage1FoundationTest.java` | com | 7 | 11 | 0 | AttributionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/config/AttributionStage1FoundationTest.java` | com | 7 | 11 | 0 | AttributionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | com | 7 | 22 | 5 | EnergyController | skip×1、⚠部分 |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | com | 7 | 22 | 5 | EnergyController | skip×1、⚠部分 |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberDimensionBaseScoreServiceTest.java` | com | 7 | 10 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberDimensionBaseScoreServiceTest.java` | com | 7 | 10 | 0 | FamilyController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerAddMemberTest.java` | com | 7 | 1 | 1 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideFamilyServiceTest.java` | com | 7 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideFamilyServiceTest.java` | com | 7 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/orchestration/OrchestrationIntegrationTest.java` | com | 7 | 0 | 0 | OrchestrationController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/orchestration/OrchestrationIntegrationTest.java` | com | 7 | 0 | 0 | OrchestrationController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/SupplyTeamControllerInviteTest.java` | com | 7 | 7 | 0 | SupplyTeamController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/task/TaskCheckinWebhookReminderTaskTest.java` | com | 7 | 0 | 0 | TaskController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/task/TaskCheckinWebhookReminderTaskTest.java` | com | 7 | 0 | 0 | TaskController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ActivityRegistrationQuotaConcurrencyTest.java` | com | 6 | 0 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ActivityRegistrationQuotaConcurrencyTest.java` | com | 6 | 0 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ActivityServicePublishTest.java` | com | 6 | 0 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ActivityServicePublishTest.java` | com | 6 | 0 | 0 | ActivityController | — |
@@ -264,23 +272,25 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ServiceRoleApproveTest.java` | com | 6 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ServiceRoleApproveTest.java` | com | 6 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | com | 6 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | com | 6 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/StatsControllerTest.java` | com | 6 | 10 | 2 | StatsController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/StatsControllerTest.java` | com | 6 | 10 | 2 | StatsController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/util/UserUtilTest.java` | com | 6 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/WithdrawalServiceTest.java` | com | 6 | 0 | 0 | WithdrawalController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/WithdrawalServiceTest.java` | com | 6 | 0 | 0 | WithdrawalController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ActivityTagServiceTest.java` | com | 5 | 1 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/ActivityTagServiceTest.java` | com | 5 | 1 | 0 | ActivityController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/AttributionAdjustServiceTest.java` | com | 5 | 3 | 0 | AttributionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/AttributionAdjustServiceTest.java` | com | 5 | 3 | 0 | AttributionController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/BundlePricingServiceTest.java` | com | 5 | 0 | 0 | — | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/CartReplaceComboTest.java` | com | 5 | 0 | 0 | CartController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfLegacyLedgerWiringTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfLegacyLedgerWiringTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` | com | 5 | 0 | 0 | CommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` | com | 5 | 0 | 0 | CommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionEnergySyncServiceTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionEnergySyncServiceTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | com | 5 | 0 | 0 | FamilyController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyMemberServiceIsChildTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyNamingSupportTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyNamingSupportTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | com | 5 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanLazyBackfillTest.java` | com | 5 | 0 | 0 | HealthPlanController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanLazyBackfillTest.java` | com | 5 | 0 | 0 | HealthPlanController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerCreateReportTest.java` | com | 5 | 2 | 0 | HealthReportController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | com | 5 | 7 | 0 | HealthReportController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | com | 5 | 7 | 0 | HealthReportController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/MiniGameServiceTest.java` | com | 5 | 0 | 0 | MiniGameController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/MiniGameServiceTest.java` | com | 5 | 0 | 0 | MiniGameController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/NumSoulCalculatorTest.java` | com | 5 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/NumSoulCalculatorTest.java` | com | 5 | 0 | 0 | — | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/service/ProductOrderComboStockTest.java` | com | 5 | 0 | 0 | ProductController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductSkuComboServiceTest.java` | com | 5 | 0 | 0 | ProductSkuController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductUpdateClearTest.java` | com | 5 | 0 | 0 | ProductController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/RelationshipQuestionnaireServiceTest.java` | com | 5 | 0 | 0 | RelationshipQuestionnaireController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/RelationshipQuestionnaireServiceTest.java` | com | 5 | 0 | 0 | RelationshipQuestionnaireController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/TaskServiceMinigameTest.java` | com | 5 | 0 | 0 | TaskController | skip×1、⚠部分 |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/TaskServiceMinigameTest.java` | com | 5 | 0 | 0 | TaskController | skip×1、⚠部分 |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserServiceEffectiveFamilyIdsTest.java` | com | 5 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserServiceEffectiveFamilyIdsTest.java` | com | 5 | 0 | 0 | UserController | — |
@@ -290,6 +300,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ChallengeScoreServiceTest.java` | com | 4 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/ChallengeScoreServiceTest.java` | com | 4 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionDistService410Test.java` | com | 4 | 0 | 0 | CommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionDistService410Test.java` | com | 4 | 0 | 0 | CommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | com | 4 | 0 | 0 | EnergyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | com | 4 | 0 | 0 | EnergyController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberServiceRenameTest.java` | com | 4 | 0 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | com | 4 | 1 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | com | 4 | 1 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | com | 4 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | com | 4 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyQueryServiceTest.java` | com | 4 | 4 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyQueryServiceTest.java` | com | 4 | 4 | 0 | GuideController | — |
@@ -311,15 +322,16 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ArticleAudioServiceChunkFilterTest.java` | com | 3 | 0 | 0 | ArticleController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ArticleAudioServiceChunkFilterTest.java` | com | 3 | 0 | 0 | ArticleController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleCategoryControllerTest.java` | com | 3 | 0 | 1 | ArticleCategoryController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/ArticleCategoryControllerTest.java` | com | 3 | 0 | 1 | ArticleCategoryController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | com | 3 | 5 | 1 | AttributionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | com | 3 | 5 | 1 | AttributionController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/CartServiceTest.java` | com | 3 | 0 | 0 | CartController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfLegacyLedgerMigrationServiceTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfLegacyLedgerMigrationServiceTest.java` | com | 3 | 0 | 0 | — | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ComboOrderStockTest.java` | com | 3 | 0 | 0 | — | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerGrantEnergyTest.java` | com | 3 | 4 | 1 | EnergyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | com | 3 | 4 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | com | 3 | 4 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java` | com | 3 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java` | com | 3 | 0 | 0 | GuideController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceIndicatorsTest.java` | com | 3 | 26 | 0 | HealthReportController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceIndicatorsTest.java` | com | 3 | 26 | 0 | HealthReportController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/NormalizeIndicatorPipelineTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/NormalizeIndicatorPipelineTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/task/OrderTimeoutCancelTaskSpecialDealTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/task/OrderTimeoutCancelTaskSpecialDealTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/PaymentServiceORDRoutingTest.java` | com | 3 | 1 | 0 | PaymentController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/PaymentServiceORDRoutingTest.java` | com | 3 | 1 | 0 | PaymentController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductOrderServiceTest.java` | com | 3 | 0 | 0 | ProductController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductDTOMappingTest.java` | com | 3 | 0 | 0 | ProductController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ProductOrderServiceUpdateExpressFieldTest.java` | com | 3 | 0 | 0 | ProductController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ProductOrderServiceUpdateExpressFieldTest.java` | com | 3 | 0 | 0 | ProductController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/RepeatTaskGeneratorPassThroughTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/RepeatTaskGeneratorPassThroughTest.java` | com | 3 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | com | 3 | 0 | 1 | ReportParserAdminController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | com | 3 | 0 | 1 | ReportParserAdminController | — |
@@ -333,10 +345,13 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfCommissionServiceTest.java` | com | 2 | 0 | 0 | CfCommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CfCommissionServiceTest.java` | com | 2 | 0 | 0 | CfCommissionController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` | com | 2 | 0 | 0 | ConsigneeController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` | com | 2 | 0 | 0 | ConsigneeController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DailyTaskControllerTest.java` | com | 2 | 1 | 1 | DailyTaskController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/DailyTaskControllerTest.java` | com | 2 | 1 | 1 | DailyTaskController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java` | com | 2 | 1 | 0 | DanAssessmentController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` | com | 2 | 0 | 0 | EnergyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` | com | 2 | 0 | 0 | EnergyController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceGrantEnergyTest.java` | com | 2 | 1 | 0 | EnergyController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` | com | 2 | 1 | 0 | FamilyController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | com | 2 | 0 | 0 | FiveDimensionSelfCheckController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | com | 2 | 0 | 0 | FiveDimensionSelfCheckController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | com | 2 | 1 | 1 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | com | 2 | 1 | 1 | IndicatorController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductUpdateClearTest.java` | com | 2 | 0 | 0 | ProductController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductListNutritionTagFilterTest.java` | com | 2 | 0 | 0 | ProductController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserAddressServiceBackfillTest.java` | com | 2 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserAddressServiceBackfillTest.java` | com | 2 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserServiceFamilyNameLinkTest.java` | com | 2 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/UserServiceFamilyNameLinkTest.java` | com | 2 | 0 | 0 | UserController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/AiGatewayTimeoutTest.java` | com | 1 | 2 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/AiGatewayTimeoutTest.java` | com | 1 | 2 | 0 | — | — |
@@ -345,8 +360,9 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorCorrelationServiceTest.java` | com | 1 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorCorrelationServiceTest.java` | com | 1 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorValueMapperTest.java` | com | 1 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/IndicatorValueMapperTest.java` | com | 1 | 0 | 0 | IndicatorController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/mind/MindFortuneControllerTest.java` | com | 1 | 1 | 0 | MindFortuneController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/controller/mind/MindFortuneControllerTest.java` | com | 1 | 1 | 0 | MindFortuneController | — |
-| `cfc-backend/src/test/java/com/etotem/cfc/unit/ProductDTOMappingTest.java` | com | 1 | 0 | 0 | ProductController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/RecommendationNutritionTagTest.java` | com | 1 | 0 | 0 | RecommendController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ReportSummaryServiceCompletenessTest.java` | com | 1 | 0 | 0 | ReportSummaryController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ReportSummaryServiceCompletenessTest.java` | com | 1 | 0 | 0 | ReportSummaryController | — |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` | com | 1 | 1 | 0 | TeacherController | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/TestRoles.java` | com | 0 | 0 | 0 | — | — |
 | `cfc-backend/src/test/java/com/etotem/cfc/common/TestRoles.java` | com | 0 | 0 | 0 | — | — |
 
 
 ## 五、使用说明
 ## 五、使用说明

+ 255 - 193
docs/tdd/test/inventory.md

@@ -8,12 +8,12 @@
 
 
 | 来源类型 | 文件数 | 用例/方法数 |
 | 来源类型 | 文件数 | 用例/方法数 |
 | --- | --- | --- |
 | --- | --- | --- |
-| 结构化测试用例(md) | 9 | 678 |
-| Playwright(spec.js) | 70 | 411 |
+| 结构化测试用例(md) | 9 | 729 |
+| Playwright(spec.js) | 70 | 410 |
 | Python(pytest) | 11 | 47 |
 | Python(pytest) | 11 | 47 |
-| Java后端(测试文件) | 185 | 1390 (@Test) |
-| 用户场景(md) | 8 | 文件级 |
-| **合计** | — | **2526** 用例/方法 |
+| Java后端(测试文件) | 195 | 1451 (@Test) |
+| 用户场景(md) | 9 | 文件级 |
+| **合计** | — | **2637** 用例/方法 |
 
 
 ## 二、结构化测试用例(`tests/test-cases/*.md`)
 ## 二、结构化测试用例(`tests/test-cases/*.md`)
 
 
@@ -44,29 +44,29 @@
 | `TC-A-21` | 网关/限流 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-21` | 网关/限流 | 达成目标:接口防护;边界:误杀白名单 |
 | `TC-A-21` | 网关/限流 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-21` | 网关/限流 | 达成目标:接口防护;边界:误杀白名单 |
 | `TC-A-22` | 模型管理 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-22` | 模型管理 | 达成目标:模型版本/开关;边界:下线前回退方案 |
 | `TC-A-22` | 模型管理 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-22` | 模型管理 | 达成目标:模型版本/开关;边界:下线前回退方案 |
 | `TC-A-23` | 知识库 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-23` | 知识库 | 达成目标:维护营养知识;边界:同步失败重试 |
 | `TC-A-23` | 知识库 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-23` | 知识库 | 达成目标:维护营养知识;边界:同步失败重试 |
-| `TC-A-01-E` | 认证 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-01-E` | AdminAuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-A-02-E` | 统计 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-02-E` | StatsController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-A-03-E` | 方案管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-03-E` | 方案管理(全量) | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-A-04-E` | 方案激活 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-04-E` | 方案激活 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-A-05-E` | 报告解析 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-05-E` | AdminReportParserController | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-A-06-E` | 报告解析 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-06-E` | 报告类型注册 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-A-07-E` | 报告解析 | 运营 | P3 | 异常 | `tests/test-cases/admin.md#TC-A-07-E` | 未知聚类自学习 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-A-08-E` | 文章 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-08-E` | 文章发布-审核 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-09-E` | 文章·去重 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-09-E` | 文章标题去重 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-10-E` | 关系类型 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-10-E` | 关系类型 CRUD | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-11-E` | 勋章 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-11-E` | 勋章管理;黑盒回归 | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-A-12-E` | 供应商 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-12-E` | 供应商管理;黑盒回归 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-13-E` | 活动 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-13-E` | 活动审核撤回;黑盒回归 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-14-E` | 知识库 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-14-E` | 知识库管理;黑盒回归 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-A-15-E` | 数据迁移 | 运营 | P3 | 异常 | `tests/test-cases/admin.md#TC-A-15-E` | 多数据源/SfmsDataSourceConfig | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-A-16-E` | 参数校验 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-16-E` | 统一 `Result<T>`+全局异常;黑盒回归 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-A-17-E` | /api/admin/report-parser/* | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-17-E` | /api/admin/report-parser/* | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-A-18-E` | 优惠券/活动管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-18-E` | 优惠券/活动管理 | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-A-19-E` | 内容安全 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-19-E` | 内容安全 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-A-20-E` | GDPR 工单 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-20-E` | GDPR 工单 | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
-| `TC-A-21-E` | 网关/限流 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-21-E` | 网关/限流 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-A-22-E` | 模型管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-22-E` | 模型管理 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-A-23-E` | 知识库 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-23-E` | 知识库 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
+| `TC-A-01-E` | 认证 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-01-E` | AdminAuthController | 错误密码不签发 token 且提示次数限制/锁定;过期 token 401 跳登录;弱密码 400 拦截 |
+| `TC-A-02-E` | 统计 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-02-E` | StatsController | 超时降级提示非500;无数据显示『暂无数据』;时间非法 400 |
+| `TC-A-03-E` | 方案管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-03-E` | 方案管理(全量) | 超时降级非500;非法筛选 400;仅返回有权家庭数据不串 |
+| `TC-A-04-E` | 方案激活 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-04-E` | 方案激活 | 非 reviewed 激活拦截;超时回滚不残半任务;并发幂等仅生成 1 次任务 |
+| `TC-A-05-E` | 报告解析 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-05-E` | AdminReportParserController | 超时降级非500;重复 typeId 400 拒绝;路径非法 400 |
+| `TC-A-06-E` | 报告解析 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-06-E` | 报告类型注册 | 重复 typeId 拒绝;必填缺失 400;threshold 非法 400 |
+| `TC-A-07-E` | 报告解析 | 运营 | P3 | 异常 | `tests/test-cases/admin.md#TC-A-07-E` | 未知聚类自学习 | 超时降级非500;重名类型生成被拒/提示已存在 |
+| `TC-A-08-E` | 文章 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-08-E` | 文章发布-审核 | 同标题 400『标题已存在』;长文提交超时重试不丢稿;注入 400 或转义 |
+| `TC-A-09-E` | 文章·去重 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-09-E` | 文章标题去重 | 重复创建被拦截提示标题已存在;空/超长 400 |
+| `TC-A-10-E` | 关系类型 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-10-E` | 关系类型 CRUD | 重名拒绝;停用被引用类型提示先解绑;注入 400/转义;家长端选择器同步生效仍正确 |
+| `TC-A-11-E` | 勋章 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-11-E` | 勋章管理;黑盒回归 | 重复 400/幂等;非法门槛 400;并发创建各自独立不串 |
+| `TC-A-12-E` | 供应商 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-12-E` | 供应商管理;黑盒回归 | 同手机号拒绝/可控覆盖;非法格式 400;必填缺失 400;列表 name=昵称正确 |
+| `TC-A-13-E` | 活动 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-13-E` | 活动审核撤回;黑盒回归 | 已发布再提交审核守卫拦截;非本人撤回 403;时间冲突 400;撤回退回草稿 |
+| `TC-A-14-E` | 知识库 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-14-E` | 知识库管理;黑盒回归 | 被引用删除提示先解绑;不存在 404;并发删除幂等 |
+| `TC-A-15-E` | 数据迁移 | 运营 | P3 | 异常 | `tests/test-cases/admin.md#TC-A-15-E` | 多数据源/SfmsDataSourceConfig | 中断回滚+明确错误非500;锁等待超时提示;重复执行幂等/提示已迁移 |
+| `TC-A-16-E` | 参数校验 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-16-E` | 统一 `Result<T>`+全局异常;黑盒回归 | 空 body 400 含具体字段提示;类型错配 400;超长 400;不再裸 500 |
+| `TC-A-17-E` | /api/admin/report-parser/* | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-17-E` | /api/admin/report-parser/* | 重名类目拒绝;未注册路径 400;先注册再解析 |
+| `TC-A-18-E` | 优惠券/活动管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-18-E` | 优惠券/活动管理 | 时间冲突 400;名额超卖配置保护生效;重复提交幂等 |
+| `TC-A-19-E` | 内容安全 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-19-E` | 内容安全 | 超时降级非500;命中敏感词强制拦截不放行 |
+| `TC-A-20-E` | GDPR 工单 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-20-E` | GDPR 工单 | 并发安全:注销与导出按序执行不冲突;越权工单 403 |
+| `TC-A-21-E` | 网关/限流 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-21-E` | 网关/限流 | 白名单不被限流;非法阈值 400;规则生效可控 |
+| `TC-A-22-E` | 模型管理 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-22-E` | 模型管理 | 无回退方案拦截下线;非法版本 400;上下线版控正确 |
+| `TC-A-23-E` | 知识库 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-23-E` | 知识库 | 同步失败自动重试非500;并发 CRUD 乐观锁不互相覆盖 |
 | `TC-A-01-P` | 认证 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-01-P` | AdminAuthController | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
 | `TC-A-01-P` | 认证 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-01-P` | AdminAuthController | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
 | `TC-A-02-P` | 统计 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-02-P` | StatsController | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
 | `TC-A-02-P` | 统计 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-02-P` | StatsController | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
 | `TC-A-03-P` | 方案管理 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-03-P` | 方案管理(全量) | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
 | `TC-A-03-P` | 方案管理 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-03-P` | 方案管理(全量) | 非 admin 角色访问管理端接口统一 401/403,不泄露后台数据 |
@@ -90,6 +90,12 @@
 | `TC-A-21-P` | 网关/限流 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-21-P` | 网关/限流 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
 | `TC-A-21-P` | 网关/限流 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-21-P` | 网关/限流 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
 | `TC-A-22-P` | 模型管理 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-22-P` | 模型管理 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
 | `TC-A-22-P` | 模型管理 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-22-P` | 模型管理 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
 | `TC-A-23-P` | 知识库 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-23-P` | 知识库 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
 | `TC-A-23-P` | 知识库 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-23-P` | 知识库 | 非 admin 角色访问统一 401/403,不泄露后台数据 |
+| `TC-A-25` | 维度/权重/上限配置 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-25` | DimensionConfigController`/`DimensionWeightController | 变更生效、后续能量按新配置;存量影响提示 |
+| `TC-A-26` | 能量/归因权重 | 运营 | P1 | 功能 | `tests/test-cases/admin.md#TC-A-26` | EnergyController`/`AttributionWeights | 全局生效;变更写审计;概览/沙盘/天盘影响可观测 |
+| `TC-A-25-E` | 维度/权重/上限配置 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-25-E` | DimensionConfigController | 1. 需确认/拒、不级联破坏存量 2. 400 拦截 3. 乐观锁/版本控制不互相覆盖 |
+| `TC-A-26-E` | 能量/归因权重 | 运营 | P2 | 异常 | `tests/test-cases/admin.md#TC-A-26-E` | EnergyController`/`AttributionWeights | 1. 400 拦截 2. 展示兜底并提示、不静默错算 |
+| `TC-A-25-P` | 维度/权重/上限配置 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-25-P` | DimensionConfigController | 非 admin 操作 403 |
+| `TC-A-26-P` | 能量/归因权重 | 运营 | P1 | 权限 | `tests/test-cases/admin.md#TC-A-26-P` | EnergyController | 非 admin 改全局 403 |
 | `TC-A-N01` | 配置CRUD | 运营 | P1 | 性能 | `tests/test-cases/admin.md#TC-A-N01` | 配置管理 | 列表 ≤ 2s;CRUD 即时生效 |
 | `TC-A-N01` | 配置CRUD | 运营 | P1 | 性能 | `tests/test-cases/admin.md#TC-A-N01` | 配置管理 | 列表 ≤ 2s;CRUD 即时生效 |
 | `TC-A-N02` | 报告解析中台 | 运营 | P0 | 性能 | `tests/test-cases/admin.md#TC-A-N02` | 解析中台 | 单条 ≤ 30s;失败进未知聚类;监控可见积压 |
 | `TC-A-N02` | 报告解析中台 | 运营 | P0 | 性能 | `tests/test-cases/admin.md#TC-A-N02` | 解析中台 | 单条 ≤ 30s;失败进未知聚类;监控可见积压 |
 | `TC-A-N03` | 登录统计 | 运营 | P1 | 性能 | `tests/test-cases/admin.md#TC-A-N03` | 统计聚合 | 聚合 ≤ 3s;支持分页/缓存;大数据不超时 |
 | `TC-A-N03` | 登录统计 | 运营 | P1 | 性能 | `tests/test-cases/admin.md#TC-A-N03` | 统计聚合 | 聚合 ≤ 3s;支持分页/缓存;大数据不超时 |
@@ -122,29 +128,29 @@
 | `TC-C-21` | 舌诊情绪识别 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-21` | 舌诊情绪识别 | 达成目标:拍照上传;边界:模糊/非照片拒绝;隐私标注 |
 | `TC-C-21` | 舌诊情绪识别 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-21` | 舌诊情绪识别 | 达成目标:拍照上传;边界:模糊/非照片拒绝;隐私标注 |
 | `TC-C-22` | MallController | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-22` | MallController | 达成目标:用积分换;边界:积分不足拦截;重复兑换幂等 |
 | `TC-C-22` | MallController | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-22` | MallController | 达成目标:用积分换;边界:积分不足拦截;重复兑换幂等 |
 | `TC-C-23` | 客服 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-23` | 客服 | 达成目标:提反馈;边界:内容适龄过滤;敏感信息脱敏 |
 | `TC-C-23` | 客服 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-23` | 客服 | 达成目标:提反馈;边界:内容适龄过滤;敏感信息脱敏 |
-| `TC-C-01-E` | 权限/双角色 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-01-E` | 双角色铁律:孩子端不能切家长 | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-C-02-E` | 任务 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-02-E` | TaskController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-03-E` | 小游戏 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-03-E` | pages/games/* | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-C-04-E` | 心愿 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-04-E` | WishController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-05-E` | 心愿 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-05-E` | RewardController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-06-E` | 能量 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-06-E` | EnergyController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-07-E` | 报告/权限 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-07-E` | 报告查看权限隔离 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-C-08-E` | 打卡/方案 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-08-E` | 健康打卡/方案进度 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-C-09-E` | 勋章 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-09-E` | RewardController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-10-E` | 勋章提醒 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-10-E` | MedalController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-11-E` | 成长记录 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-11-E` | GrowthController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-12-E` | 食谱查看 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-12-E` | 饮食推荐 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-C-13-E` | AI 对话 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-13-E` | AIChatController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-C-14-E` | 任务重做 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-14-E` | TaskController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-C-15-E` | 消息接收 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-15-E` | 消息服务 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-C-16-E` | 个人资料 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-16-E` | AuthController | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-C-17-E` | 退出 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-17-E` | AuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-C-18-E` | 设备校验 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-18-E` | AuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-C-19-E` | 消息服务 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-19-E` | 消息服务 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-C-20-E` | GrowthController | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-20-E` | GrowthController | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
-| `TC-C-21-E` | 舌诊情绪识别 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-21-E` | 舌诊情绪识别 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-C-22-E` | MallController | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-22-E` | MallController | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-C-23-E` | 客服 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-23-E` | 客服 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
+| `TC-C-01-E` | 权限/双角色 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-01-E` | 双角色铁律:孩子端不能切家长 | 缺失/过期 token 统一 401 跳登录;切换/家长路由被 role 校验 403 拦截;孩子端无任何切回家长入口;模拟登录仅测试环境生效 |
+| `TC-C-02-E` | 任务 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-02-E` | TaskController | 并发双点幂等仅计 1 次、仅 1 条流水;超期提交被拒;驳回→重做→再提交仅在重做后计 1 次 |
+| `TC-C-03-E` | 小游戏 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-03-E` | pages/games/* | 异常分数 400 不计入;断网不计分不卡死;重复上报幂等不重复入榜 |
+| `TC-C-04-E` | 心愿 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-04-E` | WishController | 余额不足创建拦截;超长/注入 400 校验;重复创建提示已存在不双建 |
+| `TC-C-05-E` | 心愿 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-05-E` | RewardController | 余额不足拦截且不扣负;已驳回提示不可兑换;并发幂等仅扣 1 次 |
+| `TC-C-06-E` | 能量 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-06-E` | EnergyController | 超时降级空态提示非 500;权重 0 占比兜底(0%)显示不崩;能量不为负 |
+| `TC-C-07-E` | 报告/权限 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-07-E` | 报告查看权限隔离 | 删除/编辑被 role 校验 403 拒绝;孩子端 UI 无编辑/删除入口;报告内容不被改动 |
+| `TC-C-08-E` | 打卡/方案 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-08-E` | 健康打卡/方案进度 | 超时回滚不残半任务、进度不 +1;重复打卡幂等不重复计数;非本人任务 403 |
+| `TC-C-09-E` | 勋章 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-09-E` | RewardController | 重复达成不重复发推送/勋章;未达成领取 400/403 拒绝 |
+| `TC-C-10-E` | 勋章提醒 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-10-E` | MedalController | 重复达成幂等仅 1 次推送;数据缺失降级不推送不 500 |
+| `TC-C-11-E` | 成长记录 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-11-E` | GrowthController | 关联已删项跳过不报错;其他成员数据 403 不可见 |
+| `TC-C-12-E` | 食谱查看 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-12-E` | 饮食推荐 | 超时 Fallback 通用食谱+提示非 500;无食谱空态不 500 |
+| `TC-C-13-E` | AI 对话 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-13-E` | AIChatController | 不适龄/敏感词被过滤返回适龄话术;LangGraph 不可用 Fallback 兜底、多轮连续 |
+| `TC-C-14-E` | 任务重做 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-14-E` | TaskController | 非驳回态重做入口不可见/拦截;重做提交进入待审核仅计 1 次 |
+| `TC-C-15-E` | 消息接收 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-15-E` | 消息服务 | 越权消息 403 不可见;不存在 404;列表分页正常 |
+| `TC-C-16-E` | 个人资料 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-16-E` | AuthController | 代管字段 403 不可改;昵称注入/超长 400 校验 |
+| `TC-C-17-E` | 退出 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-17-E` | AuthController | 旧 token 失效 401;网络中断退出仍清本地缓存、下次需重登 |
+| `TC-C-18-E` | 设备校验 | 孩子 | P3 | 异常 | `tests/test-cases/child.md#TC-C-18-E` | AuthController | 异常设备二次验证/拦截;旧设备 token 失效 401 |
+| `TC-C-19-E` | 消息服务 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-19-E` | 消息服务 | 不存在 404;越权标记 403 不生效 |
+| `TC-C-20-E` | GrowthController | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-20-E` | GrowthController | 未成年导出 403 需家长代办;他人档案 403 不可见 |
+| `TC-C-21-E` | 舌诊情绪识别 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-21-E` | 舌诊情绪识别 | 非照片/模糊拒绝提示『请上传清晰舌苔照』;低置信度提示重拍;隐私标注不外露 |
+| `TC-C-22-E` | MallController | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-22-E` | MallController | 余额不足拦截不扣负;并发仅 1 次成功;重复兑换幂等仅 1 条 |
+| `TC-C-23-E` | 客服 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-23-E` | 客服 | 敏感信息脱敏存储;附件超限 400『附件不超过 10MB』 |
 | `TC-C-01-P` | 权限/双角色 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-01-P` | 双角色铁律:孩子端不能切家长 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-01-P` | 权限/双角色 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-01-P` | 双角色铁律:孩子端不能切家长 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-02-P` | 任务 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-02-P` | TaskController | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-02-P` | 任务 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-02-P` | TaskController | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-03-P` | 小游戏 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-03-P` | pages/games/* | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-03-P` | 小游戏 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-03-P` | pages/games/* | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
@@ -168,6 +174,12 @@
 | `TC-C-21-P` | 舌诊情绪识别 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-21-P` | 舌诊情绪识别 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-21-P` | 舌诊情绪识别 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-21-P` | 舌诊情绪识别 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-22-P` | MallController | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-22-P` | MallController | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-22-P` | MallController | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-22-P` | MallController | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-23-P` | 客服 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-23-P` | 客服 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
 | `TC-C-23-P` | 客服 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-23-P` | 客服 | 孩子端无编辑/删除/切家长入口;直接调用被 role 校验拒绝(403/401),不越权操作家庭数据 |
+| `TC-C-24` | 能量/小游戏·任务 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-24` | GameRecordService`/`TaskController | 对应维度 +amount、sourceType=game/task;B 自身能量页看到增长与流水 |
+| `TC-C-25` | 能量/方案打卡 | 孩子 | P1 | 功能 | `tests/test-cases/child.md#TC-C-25` | GrowthTaskService | GrowthTaskService 打卡对应维度+;任务进度与能量同步刷新 |
+| `TC-C-24-E` | 能量/小游戏·任务 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-24-E` | GameRecordService | 1. 异常分数拦截不写能量 2. 重复上报幂等不重复加 |
+| `TC-C-25-E` | 能量/方案打卡 | 孩子 | P2 | 异常 | `tests/test-cases/child.md#TC-C-25-E` | GrowthTaskService | 1. 按业务允/拒、断言一致 2. 重复打卡幂等不重复加 3. 并发不重复计分 |
+| `TC-C-24-P` | 能量/小游戏·任务 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-24-P` | JwtInterceptor`+role | 1. 他人能量 403 2. 孩子端无编辑/扣减入口、直接调被拒 |
+| `TC-C-25-P` | 能量/方案打卡 | 孩子 | P1 | 权限 | `tests/test-cases/child.md#TC-C-25-P` | GrowthTaskService | 1. 非本人方案任务 403 2. 他人进度不可见 |
 | `TC-C-N01` | 任务打卡 | 孩子 | P1 | 性能 | `tests/test-cases/child.md#TC-C-N01` | TaskController | 重复提交幂等;并发不重复计分;响应 ≤ 1s |
 | `TC-C-N01` | 任务打卡 | 孩子 | P1 | 性能 | `tests/test-cases/child.md#TC-C-N01` | TaskController | 重复提交幂等;并发不重复计分;响应 ≤ 1s |
 | `TC-C-N02` | 消息通知 | 孩子 | P2 | 性能 | `tests/test-cases/child.md#TC-C-N02` | 消息中心 | 列表渲染 ≤ 1.5s;标记已读即时 |
 | `TC-C-N02` | 消息通知 | 孩子 | P2 | 性能 | `tests/test-cases/child.md#TC-C-N02` | 消息中心 | 列表渲染 ≤ 1.5s;标记已读即时 |
 | `TC-C-N03` | 孩子端 | 孩子 | P1 | 兼容 | `tests/test-cases/child.md#TC-C-N03` | 孩子端 | 功能一致;无错位;低龄设备流畅 |
 | `TC-C-N03` | 孩子端 | 孩子 | P1 | 兼容 | `tests/test-cases/child.md#TC-C-N03` | 孩子端 | 功能一致;无错位;低龄设备流畅 |
@@ -229,6 +241,15 @@
 | `TC-X-16-P` | 跨角色 | P0 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-16-P` | - | X-16 |
 | `TC-X-16-P` | 跨角色 | P0 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-16-P` | - | X-16 |
 | `TC-X-17-P` | 跨角色 | P1 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-17-P` | - | X-17 |
 | `TC-X-17-P` | 跨角色 | P1 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-17-P` | - | X-17 |
 | `TC-X-18-P` | 跨角色 | P1 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-18-P` | - | X-18 |
 | `TC-X-18-P` | 跨角色 | P1 | 权限 | 已登录(默认 跨角色);相关前置数据就绪 | `tests/test-cases/cross-role-e2e.md#TC-X-18-P` | - | X-18 |
+| `TC-X-19` | 跨角色 | P0 | 功能 | 家庭1(A+B+C)、绑定家庭 F2(T)、无关家庭 F9 | `tests/test-cases/cross-role-e2e.md#TC-X-19` | - | X-19 |
+| `TC-X-20` | 跨角色 | P0 | 功能 | 成员 B 混合来源流水(任务/打卡/心愿扣减/手动) | `tests/test-cases/cross-role-e2e.md#TC-X-20` | - | X-20 |
+| `TC-X-21` | 跨角色 | P0 | 功能 | B 某维度当日未触顶;多触发同时到达 | `tests/test-cases/cross-role-e2e.md#TC-X-21` | - | X-21 |
+| `TC-X-19-E` | 跨角色 | P1 | 异常 | 家庭1 / F2 / F9 | `tests/test-cases/cross-role-e2e.md#TC-X-19-E` | - | X-19 |
+| `TC-X-20-E` | 跨角色 | P1 | 异常 | B 混合流水 + 造"不一致断点""负流水无对应" | `tests/test-cases/cross-role-e2e.md#TC-X-20-E` | - | X-20 |
+| `TC-X-21-E` | 跨角色 | P1 | 异常 | B 维度当日接近上限 | `tests/test-cases/cross-role-e2e.md#TC-X-21-E` | - | X-21 |
+| `TC-X-19-P` | 跨角色 | P0 | 权限 | 家庭1 / F2 / F9 | `tests/test-cases/cross-role-e2e.md#TC-X-19-P` | - | X-19 |
+| `TC-X-20-P` | 跨角色 | P1 | 权限 | 家庭1 + F9 | `tests/test-cases/cross-role-e2e.md#TC-X-20-P` | - | X-20 |
+| `TC-X-21-P` | 跨角色 | P1 | 权限 | 家庭1 + F9 | `tests/test-cases/cross-role-e2e.md#TC-X-21-P` | - | X-21 |
 | `TC-X-N01` | 跨角色 | P0 | 性能 | 多家庭并发(≥10 家庭) | `tests/test-cases/cross-role-e2e.md#TC-X-N01` | - | X-01 |
 | `TC-X-N01` | 跨角色 | P0 | 性能 | 多家庭并发(≥10 家庭) | `tests/test-cases/cross-role-e2e.md#TC-X-N01` | - | X-01 |
 | `TC-X-N02` | 跨角色 | P0 | 性能 | 多家庭同时生成方案 | `tests/test-cases/cross-role-e2e.md#TC-X-N02` | - | X-03 |
 | `TC-X-N02` | 跨角色 | P0 | 性能 | 多家庭同时生成方案 | `tests/test-cases/cross-role-e2e.md#TC-X-N02` | - | X-03 |
 | `TC-X-N03` | 跨角色 | P0 | 性能 | 活动名额 100,瞬时 500 请求 | `tests/test-cases/cross-role-e2e.md#TC-X-N03` | - | X-15 |
 | `TC-X-N03` | 跨角色 | P0 | 性能 | 活动名额 100,瞬时 500 请求 | `tests/test-cases/cross-role-e2e.md#TC-X-N03` | - | X-15 |
@@ -255,7 +276,7 @@
 | `TC-PA-06` | 拆任务/数据 | 规划师 | P2 | 数据 | `tests/test-cases/deep-dive-plan-activation.md#TC-PA-06` | G4 | 非当天过期(待确认设计) |
 | `TC-PA-06` | 拆任务/数据 | 规划师 | P2 | 数据 | `tests/test-cases/deep-dive-plan-activation.md#TC-PA-06` | G4 | 非当天过期(待确认设计) |
 | `TC-G-01` | 启动/首页 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-01` | JwtInterceptor 拦截 `/api/** | 显示引流首页,不进入任何业务页;明显展示微信/手机号/邀请登录入口 |
 | `TC-G-01` | 启动/首页 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-01` | JwtInterceptor 拦截 `/api/** | 显示引流首页,不进入任何业务页;明显展示微信/手机号/邀请登录入口 |
 | `TC-G-02` | 认证 | 游客 | P0 | 接口 | `tests/test-cases/guest.md#TC-G-02` | AuthController`/`API_REFERENCE` 1.1 | 返回 Result 含 token+用户信息;角色默认 parent;跳转家长首页;首次登录建 User+family_members(memberType=login) |
 | `TC-G-02` | 认证 | 游客 | P0 | 接口 | `tests/test-cases/guest.md#TC-G-02` | AuthController`/`API_REFERENCE` 1.1 | 返回 Result 含 token+用户信息;角色默认 parent;跳转家长首页;首次登录建 User+family_members(memberType=login) |
-| `TC-G-03` | 认证 | 游客 | P0 | 接口 | `tests/test-cases/guest.md#TC-G-03` | 统一 POST/JWT | 验证码正确→登录下发 token;错误→提示失败且**不产生会话**;限流生效 |
+| `TC-G-03` | 认证 | 游客 | P2 | 接口 | `tests/test-cases/guest.md#TC-G-03` | 统一 POST/JWT | 验证码正确→登录下发 token;错误→提示失败且**不产生会话**;限流生效 ⚠ **API 兼容保留**:小程序端无入口(登录走 SC-G-02),2026-11-01 口径 |
 | `TC-G-04` | 家庭/邀请 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-04` | FamilyInviteController | 登录后自动归属对应家庭,成员列表出现该用户;令牌失效→「邀请已失效」 |
 | `TC-G-04` | 家庭/邀请 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-04` | FamilyInviteController | 登录后自动归属对应家庭,成员列表出现该用户;令牌失效→「邀请已失效」 |
 | `TC-G-05` | 权限 | 游客 | P0 | 权限 | `tests/test-cases/guest.md#TC-G-05` | JWT;8 公开路径白名单(1.1) | 业务页→401 跳登录,登录后回跳;商城/文章列表可见(公开);需登录详情被拦截 |
 | `TC-G-05` | 权限 | 游客 | P0 | 权限 | `tests/test-cases/guest.md#TC-G-05` | JWT;8 公开路径白名单(1.1) | 业务页→401 跳登录,登录后回跳;商城/文章列表可见(公开);需登录详情被拦截 |
 | `TC-G-06` | 权限 | 游客 | P0 | 权限 | `tests/test-cases/guest.md#TC-G-06` | JwtInterceptor | JwtInterceptor 拦截(8 个公开路径除外);缺 token→401/403,不泄露内部错误堆栈 |
 | `TC-G-06` | 权限 | 游客 | P0 | 权限 | `tests/test-cases/guest.md#TC-G-06` | JwtInterceptor | JwtInterceptor 拦截(8 个公开路径除外);缺 token→401/403,不泄露内部错误堆栈 |
@@ -265,18 +286,18 @@
 | `TC-G-10` | 注册 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-10` | AuthController | 引导至注册;已注册账号不重复建档 |
 | `TC-G-10` | 注册 | 游客 | P1 | 功能 | `tests/test-cases/guest.md#TC-G-10` | AuthController | 引导至注册;已注册账号不重复建档 |
 | `TC-G-11` | 协议页/AgreementController | 游客 | P2 | 功能 | `tests/test-cases/guest.md#TC-G-11` | 协议页/AgreementController | 达成目标:合规告知;边界:未同意不可进入注册/核心流程 |
 | `TC-G-11` | 协议页/AgreementController | 游客 | P2 | 功能 | `tests/test-cases/guest.md#TC-G-11` | 协议页/AgreementController | 达成目标:合规告知;边界:未同意不可进入注册/核心流程 |
 | `TC-G-12` | config.js | 游客 | P2 | 功能 | `tests/test-cases/guest.md#TC-G-12` | config.js | 达成目标:非微信浏览器打开小程序链接;边界:探测失败给出明确引导 |
 | `TC-G-12` | config.js | 游客 | P2 | 功能 | `tests/test-cases/guest.md#TC-G-12` | config.js | 达成目标:非微信浏览器打开小程序链接;边界:探测失败给出明确引导 |
-| `TC-G-01-E` | 启动/首页 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-01-E` | JwtInterceptor 拦截 `/api/** | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-G-02-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-02-E` | AuthController`/`API_REFERENCE` 1.1 | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-03-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-03-E` | 统一 POST/JWT | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-04-E` | 家庭/邀请 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-04-E` | FamilyInviteController | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-G-05-E` | 权限 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-05-E` | JWT;8 公开路径白名单(1.1) | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-06-E` | 权限 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-06-E` | JwtInterceptor | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-07-E` | 测试模式 | 游客 | P3 | 异常 | `tests/test-cases/guest.md#TC-G-07-E` | AGENTS.md 测试模式 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-G-08-E` | 环境切换 | 游客 | P3 | 异常 | `tests/test-cases/guest.md#TC-G-08-E` | config.js | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-09-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-09-E` | AuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-10-E` | 注册 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-10-E` | AuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-G-11-E` | 协议页/AgreementController | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-11-E` | 协议页/AgreementController | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-G-12-E` | config.js | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-12-E` | config.js | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
+| `TC-G-01-E` | 启动/首页 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-01-E` | JwtInterceptor 拦截 `/api/** | 1. 不白屏、提供"稍后"/手机号登录兜底 2. 超时给重试而非 500;不泄露内部堆栈 |
+| `TC-G-02-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-02-E` | AuthController`/`API_REFERENCE` 1.1 | 1. 回退手机号登录、停留登录页不报错 2. 返回已有账号不重复建号 3. 超时提示重试、不建脏号 |
+| `TC-G-03-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-03-E` | 统一 POST/JWT | 1. 提示失败且不签发 token 2. 格式校验 400 拦截 3. 限流提示"操作频繁" 4. 绝不产生会话 |
+| `TC-G-04-E` | 家庭/邀请 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-04-E` | FamilyInviteController | 1. 拒绝并提示"邀请已失效" 2. 按业务规则处理(加入或被拒)、不串家庭 |
+| `TC-G-05-E` | 权限 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-05-E` | JWT;8 公开路径白名单(1.1) | 1. 统一 401 跳登录;登录后回跳 2. 重定向登录;仅 8 公开路径放行 |
+| `TC-G-06-E` | 权限 | 游客 | P1 | 异常 | `tests/test-cases/guest.md#TC-G-06-E` | JwtInterceptor | 1. 统一 401/403、不泄露内部错误与结构 2. 公开路径正常返回、不误拦 |
+| `TC-G-07-E` | 测试模式 | 游客 | P3 | 异常 | `tests/test-cases/guest.md#TC-G-07-E` | AGENTS.md 测试模式 | 1. 生产强制真授权、模拟登录被拒 2. 测试模式仅测试环境生效、不污染生产数据 |
+| `TC-G-08-E` | 环境切换 | 游客 | P3 | 异常 | `tests/test-cases/guest.md#TC-G-08-E` | config.js | 1. 回退默认 API 地址、功能可用 2. 不因识别失败崩溃/错连 |
+| `TC-G-09-E` | 认证 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-09-E` | AuthController | 1. 退出后接口 401、需重登 2. 本地 token/隐私数据已清除 |
+| `TC-G-10-E` | 注册 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-10-E` | AuthController | 1. 明确"未注册"并引导注册 2. 已注册不重复建档、直接登录 |
+| `TC-G-11-E` | 协议页 | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-11-E` | 协议页/AgreementController | 1. 拦截并强制先同意 2. 加载失败给重试、不绕过同意 |
+| `TC-G-12-E` | config.js | 游客 | P2 | 异常 | `tests/test-cases/guest.md#TC-G-12-E` | config.js | 1. 给出"在微信内打开"明确引导 2. 降级静态页、核心流程可手机号兜底 |
 | `TC-G-01-P` | 启动/首页 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-01-P` | JwtInterceptor 拦截 `/api/** | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-G-01-P` | 启动/首页 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-01-P` | JwtInterceptor 拦截 `/api/** | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-G-02-P` | 认证 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-02-P` | AuthController`/`API_REFERENCE` 1.1 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-G-02-P` | 认证 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-02-P` | AuthController`/`API_REFERENCE` 1.1 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-G-03-P` | 认证 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-03-P` | 统一 POST/JWT | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-G-03-P` | 认证 | 游客 | P1 | 权限 | `tests/test-cases/guest.md#TC-G-03-P` | 统一 POST/JWT | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
@@ -290,7 +311,7 @@
 | `TC-G-11-P` | 协议页/AgreementController | 游客 | P2 | 权限 | `tests/test-cases/guest.md#TC-G-11-P` | 协议页/AgreementController | 统一 401/403,不泄露内部错误与数据;8 个公开路径除外 |
 | `TC-G-11-P` | 协议页/AgreementController | 游客 | P2 | 权限 | `tests/test-cases/guest.md#TC-G-11-P` | 协议页/AgreementController | 统一 401/403,不泄露内部错误与数据;8 个公开路径除外 |
 | `TC-G-12-P` | config.js | 游客 | P2 | 权限 | `tests/test-cases/guest.md#TC-G-12-P` | config.js | 统一 401/403,不泄露内部错误与数据;8 个公开路径除外 |
 | `TC-G-12-P` | config.js | 游客 | P2 | 权限 | `tests/test-cases/guest.md#TC-G-12-P` | config.js | 统一 401/403,不泄露内部错误与数据;8 个公开路径除外 |
 | `TC-G-N01` | 落地页 | 游客 | P2 | 性能 | `tests/test-cases/guest.md#TC-G-N01` | 落地页/邀请 | 首屏 ≤ 3s;骨架屏生效;CDN 资源命中;无白屏 |
 | `TC-G-N01` | 落地页 | 游客 | P2 | 性能 | `tests/test-cases/guest.md#TC-G-N01` | 落地页/邀请 | 首屏 ≤ 3s;骨架屏生效;CDN 资源命中;无白屏 |
-| `TC-G-N02` | 浏览转化 | 游客 | P2 | 兼容 | `tests/test-cases/guest.md#TC-G-N02` | 登录注册 | 布局一致;微信授权正常;兜底登录可用;无错位 |
+| `TC-G-N02` | 浏览转化 | 游客 | P2 | 兼容 | `tests/test-cases/guest.md#TC-G-N02` | 登录注册(微信授权) | 布局一致;微信授权正常;兜底登录可用;无错位 |
 | `TC-G-N03` | 非微信H5 | 游客 | P2 | 兼容 | `tests/test-cases/guest.md#TC-G-N03` | H5 兜底 | 功能可用;无微信 SDK 依赖报错;流程闭环 |
 | `TC-G-N03` | 非微信H5 | 游客 | P2 | 兼容 | `tests/test-cases/guest.md#TC-G-N03` | H5 兜底 | 功能可用;无微信 SDK 依赖报错;流程闭环 |
 | `TC-G-N04` | 落地页 | 游客 | P0 | 安全 | `tests/test-cases/guest.md#TC-G-N04` | 接口鉴权 | 返回 401;不泄露数据与结构 |
 | `TC-G-N04` | 落地页 | 游客 | P0 | 安全 | `tests/test-cases/guest.md#TC-G-N04` | 接口鉴权 | 返回 401;不泄露数据与结构 |
 | `TC-G-N05` | 登录注册 | 游客 | P0 | 安全 | `tests/test-cases/guest.md#TC-G-N05` | 登录限流 | 触发限流/锁定;验证码一次性;防爆破;无撞库成功 |
 | `TC-G-N05` | 登录注册 | 游客 | P0 | 安全 | `tests/test-cases/guest.md#TC-G-N05` | 登录限流 | 触发限流/锁定;验证码一次性;防爆破;无撞库成功 |
@@ -380,92 +401,92 @@
 | `TC-P-84` | 分享 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-84` | 分享 | 达成目标:共享;边界:链接失效/权限校验;越权分享被拒 |
 | `TC-P-84` | 分享 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-84` | 分享 | 达成目标:共享;边界:链接失效/权限校验;越权分享被拒 |
 | `TC-P-85` | AuthController | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-85` | AuthController | 达成目标:同账号多设备;边界:异常设备风控;退出清 token |
 | `TC-P-85` | AuthController | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-85` | AuthController | 达成目标:同账号多设备;边界:异常设备风控;退出清 token |
 | `TC-P-86` | 勋章/排行 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-86` | 勋章/排行 | 达成目标:激励;边界:数据仅本家庭可见;排名实时性 |
 | `TC-P-86` | 勋章/排行 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-86` | 勋章/排行 | 达成目标:激励;边界:数据仅本家庭可见;排名实时性 |
-| `TC-P-01-E` | 家庭 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-01-E` | FamilyInviteController | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-P-02-E` | 家庭/成员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-02-E` | FamilyInviteController | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-P-03-E` | 成员资料 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-03-E` | FamilyMembersController | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-04-E` | 关系图 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-04-E` | 关系类型 CRUD/前端选择器 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-P-05-E` | 任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-05-E` | TaskController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-06-E` | 任务审核 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-06-E` | TaskController`/`PointsController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-07-E` | 心愿 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-07-E` | WishController`/`RewardController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-08-E` | 能量 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-08-E` | EnergyController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-09-E` | 测评订单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-09-E` | AssessmentAppointmentController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-10-E` | 健康报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-10-E` | 健康报告上传解析 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-11-E` | 报告查看 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-11-E` | 报告解析 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-12-E` | 饮食推荐 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-12-E` | 饮食推荐系统 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-13-E` | AI 方案 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-13-E` | AI 统一走 LangGraph;`AiGateway | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-14-E` | 方案提交 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-14-E` | 方案状态机 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-15-E` | 双角色 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-15-E` | POST /api/family/member/switch`(替代废弃 switch-mode);双角色铁律 | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-P-16-E` | 会员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-16-E` | MembershipController`/`ProductOrderController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-17-E` | 积分/成长 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-17-E` | PointsController`/`GrowthController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-18-E` | AI 对话 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-18-E` | AIChatController`;LangGraph RAG | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-19-E` | 能量配置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-19-E` | 维度配置 | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-20-E` | 健康报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-20-E` | 报告解析中台/`POST /api/media/upload | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-21-E` | 报告解析 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-21-E` | /api/admin/report-parser/types | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-22-E` | 报告预览 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-22-E` | 解析中台 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-23-E` | 报告入库 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-23-E` | 解析中台 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-24-E` | 报告管理 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-24-E` | 报告管理 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-25-E` | 报告趋势 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-25-E` | 成长/报告 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-26-E` | 饮食推荐 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-26-E` | 饮食推荐系统 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-27-E` | 家庭食谱 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-27-E` | 饮食推荐/家庭食谱 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-28-E` | 食谱筛选 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-28-E` | 饮食推荐 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-29-E` | 食谱收藏 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-29-E` | 饮食推荐 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-30-E` | 食谱营养 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-30-E` | 饮食推荐 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-31-E` | 测评类型 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-31-E` | DanAssessmentController | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-P-32-E` | 测评规划师 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-32-E` | 测评订单 | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-P-33-E` | 测评下单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-33-E` | AssessmentOrder | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-34-E` | 测评支付 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-34-E` | 支付/`AssessmentQuota | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-35-E` | 测评额度 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-35-E` | AssessmentQuota | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-36-E` | 测评预约 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-36-E` | AssessmentAppointmentController | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-P-37-E` | 预约状态 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-37-E` | AssessmentAppointmentController | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-P-38-E` | 预约取消 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-38-E` | AssessmentAppointmentController | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-P-39-E` | DAN报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-39-E` | DanAssessmentResultDTO | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-40-E` | AI方案 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-40-E` | AIChatController`/`AiGateway | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-41-E` | 方案迭代 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-41-E` | AIChatController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-42-E` | 方案编辑 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-42-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-43-E` | 方案查看 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-43-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-44-E` | 方案确认 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-44-E` | 方案状态机 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-45-E` | 方案发布 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-45-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-46-E` | 方案激活 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-46-E` | 方案激活任务分解 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-47-E` | 方案任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-47-E` | GrowthPlanController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-48-E` | 方案版本 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-48-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-49-E` | AI对话 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-49-E` | AIChatController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-50-E` | 成长记录 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-50-E` | GrowthController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-51-E` | 成长里程碑 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-51-E` | GrowthController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-P-52-E` | 商城浏览 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-52-E` | MallController`/`danshop | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-53-E` | 商品详情 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-53-E` | MallController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-54-E` | 商城下单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-54-E` | MallController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-55-E` | 订单支付 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-55-E` | 支付 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-56-E` | 订单退款 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-56-E` | 订单服务 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-57-E` | 优惠券 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-57-E` | 优惠券 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-P-58-E` | 会员购买 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-58-E` | MemberController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-P-59-E` | 会员权益 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-59-E` | MemberController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-60-E` | 会员续费 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-60-E` | MemberController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-P-61-E` | 联系人 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-61-E` | ContactCard`/`contact-detail | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-62-E` | 联系人导入 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-62-E` | ContactImport | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-63-E` | 联系人权限 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-63-E` | ContactCard | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-64-E` | 个人资料 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-64-E` | AuthController | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-65-E` | 通知设置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-65-E` | 消息服务 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-66-E` | 隐私设置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-66-E` | 隐私设置 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-67-E` | 报告代传/report-proxy | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-67-E` | 报告代传/report-proxy | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-68-E` | 家庭天盘 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-68-E` | 家庭天盘 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-69-E` | 精准营养 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-69-E` | 精准营养 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-70-E` | 舌诊情绪识别 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-70-E` | 舌诊情绪识别 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-71-E` | AuthController | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-71-E` | AuthController | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
-| `TC-P-72-E` | 数据导出(GDPR) | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-72-E` | 数据导出(GDPR) | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-73-E` | 家庭/成员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-73-E` | 家庭/成员 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-74-E` | 规划师绑定 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-74-E` | 规划师绑定 | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
-| `TC-P-75-E` | 优惠券 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-75-E` | 优惠券 | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-P-76-E` | 活动管理 | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-76-E` | 活动管理 | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-P-77-E` | 活动 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-77-E` | 活动 | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-P-78-E` | 消息服务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-78-E` | 消息服务 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-79-E` | 消息服务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-79-E` | 消息服务 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-80-E` | 会员/订单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-80-E` | 会员/订单 | 支付失败回滚不生成额度/订单;并发超卖拦截;重复提交幂等;库存/名额边界正确 |
-| `TC-P-81-E` | 方案/任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-81-E` | 方案/任务 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务 |
-| `TC-P-82-E` | 搜索 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-82-E` | 搜索 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-83-E` | 客服 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-83-E` | 客服 | 字段格式校验拦截;重复去重;最小权限保底;保存失败不污染既有数据 |
-| `TC-P-84-E` | 分享 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-84-E` | 分享 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-P-85-E` | AuthController | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-85-E` | AuthController | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
-| `TC-P-86-E` | 勋章/排行 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-86-E` | 勋章/排行 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
+| `TC-P-01-E` | 家庭 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-01-E` | FamilyInviteController | 名称空或超长返回 400 且 message 含『家庭名称』校验项;HTML/SQL 注入被转义,库内不落恶意串;不抛 500、不泄露堆栈 |
+| `TC-P-02-E` | 家庭/成员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-02-E` | FamilyInviteController | 非法手机号 400 提示格式;已占用账号提示『已存在家庭关系』;过期码提示『邀请已失效,请重新获取』;均不建立成员关系 |
+| `TC-P-03-E` | 成员资料 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-03-E` | FamilyMembersController | 未来生日 400;关系非法值拒绝;姓名特殊字符转义存储、不破坏查询;既有成员数据不被污染 |
+| `TC-P-04-E` | 关系图 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-04-E` | 关系类型 CRUD/前端选择器 | 重复关系提示已存在、不新增节点;非法枚举 400;关系图不出现重复/幽灵节点 |
+| `TC-P-05-E` | 任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-05-E` | TaskController | 频率非法 400;并发双发幂等,仅生成 1 条任务、仅 1 次能量预期;超期任务拒绝提交 |
+| `TC-P-06-E` | 任务审核 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-06-E` | TaskController`/`PointsController | 重复审批幂等不双计积分;驳回→重做→再审批仅在重做后计 1 次;超期任务审批被拒 |
+| `TC-P-07-E` | 心愿 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-07-E` | WishController`/`RewardController | 余额不足拦截且不扣负积分;已取消心愿兑换提示失效;并发幂等仅扣 1 次 |
+| `TC-P-08-E` | 能量 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-08-E` | EnergyController | 查询超时降级为空态提示非 500;权重为 0 时占比按兜底(0%)显示不崩;首访空态正常 |
+| `TC-P-09-E` | 测评订单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-09-E` | AssessmentAppointmentController | 回调验签失败订单保持 pending 不进待安排;余额不足回滚;重复回调幂等仅落 1 次已支付 |
+| `TC-P-10-E` | 健康报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-10-E` | 健康报告上传解析 | 损坏文件识别失败进未知聚类并提示;非募极明确提示『请确认是募极生物肠道菌群报告』;超大/加密提示超限或密码保护,均非 500 |
+| `TC-P-11-E` | 报告查看 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-11-E` | 报告解析 | 不存在/已删返回 404 提示『报告不存在』;解析中提示『报告解析中,请稍候』,不白屏不 500 |
+| `TC-P-12-E` | 饮食推荐 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-12-E` | 饮食推荐系统 | AiGateway Fallback 返回兜底食材清单+友好提示非 500;重复点击幂等仅生成 1 份、不重复扣费 |
+| `TC-P-13-E` | AI 方案 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-13-E` | AI 统一走 LangGraph;`AiGateway | Fallback 兜底方案+提示;未购会员请求付费板块返回『请先开通会员』拦截,不白生成 |
+| `TC-P-14-E` | 方案提交 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-14-E` | 方案状态机 | 空方案提交拦截提示『方案未生成』;重复提交幂等不重复进审核 |
+| `TC-P-15-E` | 双角色 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-15-E` | POST /api/family/member/switch`(替代废弃 switch-mode);双角色铁律 | 缺失/过期 token 统一 401 跳登录;孩子端无切回家长入口;非法切换 403 被拒;模拟登录仅测试环境生效 |
+| `TC-P-16-E` | 会员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-16-E` | MembershipController`/`ProductOrderController | 支付超时订单回滚不解锁权益;重复购买幂等仅开通 1 次、不重复扣费 |
+| `TC-P-17-E` | 积分/成长 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-17-E` | PointsController`/`GrowthController | 并发刷新总量一致不重复计;关联任务已删时该成长项跳过不报错,时间格式 yyyy-MM-dd HH:mm:ss |
+| `TC-P-18-E` | AI 对话 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-18-E` | AIChatController`;LangGraph RAG | 超长消息 400 提示;敏感词按合规拦截;LangGraph 不可用 Fallback 兜底回答,多轮上下文不丢 |
+| `TC-P-19-E` | 能量配置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-19-E` | 维度配置 | 配置缺失展示兜底说明非 500;权重和非法 400 提示『权重合计需为 100%』 |
+| `TC-P-20-E` | 健康报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-20-E` | 报告解析中台/`POST /api/media/upload | 损坏文件识别失败进未知聚类并提示;非募极明确提示『请确认是募极生物肠道菌群报告』;超大/加密提示超限或密码保护,均非 500 |
+| `TC-P-21-E` | 报告解析 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-21-E` | /api/admin/report-parser/types | 未注册类型进未知聚类待运营自学习;0 字节文件提示『文件为空』;均非 500 |
+| `TC-P-22-E` | 报告预览 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-22-E` | 解析中台 | 异常值提示『数据异常,暂不入库』不入库;超时提示解析中,不白屏 |
+| `TC-P-23-E` | 报告入库 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-23-E` | 解析中台 | 报告已删提示『报告不存在,确认失败』;并发确认幂等仅入库 1 次、七维仅刷新 1 次 |
+| `TC-P-24-E` | 报告管理 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-24-E` | 报告管理 | 有方案时提示『请先解除关联方案』再删;不存在 id 返回 404 不崩 |
+| `TC-P-25-E` | 报告趋势 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-25-E` | 成长/报告 | 单报告提示『至少需要 2 份报告才能看趋势』;时间轴按真实时间升序,不倒挂 |
+| `TC-P-26-E` | 饮食推荐 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-26-E` | 饮食推荐系统 | AiGateway Fallback 返回兜底食材清单+友好提示非 500;重复点击幂等仅生成 1 份、不重复扣费 |
+| `TC-P-27-E` | 家庭食谱 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-27-E` | 饮食推荐/家庭食谱 | 超时 Fallback 通用食谱+提示;过敏食材未排除时返回 400 提示『存在过敏冲突』重算 |
+| `TC-P-28-E` | 食谱筛选 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-28-E` | 饮食推荐 | 忌口冲突提示并停止生成;非法忌口值 400;重算生效 |
+| `TC-P-29-E` | 食谱收藏 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-29-E` | 饮食推荐 | 替换后提示『超出营养目标』不静默;重复收藏幂等仅 1 条 |
+| `TC-P-30-E` | 食谱营养 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-30-E` | 饮食推荐 | 超标明确标红提示『超出目标 X%』;未设目标提示先设目标,不除零 |
+| `TC-P-31-E` | 测评类型 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-31-E` | DanAssessmentController | 字典缺失时前端降级不白屏;非法 type 400;八类以字典为准 |
+| `TC-P-32-E` | 测评规划师 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-32-E` | 测评订单 | 未绑定提示『请先绑定规划师』;已解绑 T 不在可选列表,选则 400 |
+| `TC-P-33-E` | 测评下单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-33-E` | AssessmentOrder | 下架套餐 400『套餐不可售』;数量非法/库存不足拦截,不生成订单 |
+| `TC-P-34-E` | 测评支付 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-34-E` | 支付/`AssessmentQuota | 超时回滚不生成额度;重复回调幂等仅生成 1 条额度 |
+| `TC-P-35-E` | 测评额度 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-35-E` | AssessmentQuota | 过期额度预约返回『额度已过期』不落预约;额度页加载降级非 500 |
+| `TC-P-36-E` | 测评预约 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-36-E` | AssessmentAppointmentController | 无额度返回『额度不足或已过期』不建预约不发能量;并发双发仅落 1 条预约、能量仅发 1 次(幂等) |
+| `TC-P-37-E` | 预约状态 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-37-E` | AssessmentAppointmentController | 状态机守卫拒绝非法跃迁返回 400;不存在预约 404;状态准确 |
+| `TC-P-38-E` | 预约取消 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-38-E` | AssessmentAppointmentController | 越权取消 403 被拒(CFC-AP);终态预约取消返回『不可取消』;不退款逻辑按配置 |
+| `TC-P-39-E` | DAN报告 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-39-E` | DanAssessmentResultDTO | 未录入提示『结果待录入』不白屏;缺字段校验 400 提示缺哪项 |
+| `TC-P-40-E` | AI方案 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-40-E` | AIChatController`/`AiGateway | Fallback 兜底方案+提示;未购会员请求付费板块返回『请先开通会员』拦截,不白生成 |
+| `TC-P-41-E` | 方案迭代 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-41-E` | AIChatController | 断网 Fallback 保留其他板块不丢;连续点击幂等仅 1 次重生成 |
+| `TC-P-42-E` | 方案编辑 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-42-E` | 方案管理 | 超长 400 提示;越权编辑 403 被拒;编辑后状态标记已改 |
+| `TC-P-43-E` | 方案查看 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-43-E` | 方案管理 | 空方案展示占位不白屏;不存在 404 |
+| `TC-P-44-E` | 方案确认 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-44-E` | 方案状态机 | 未确认激活拦截『请先确认』;重复确认幂等仅 1 次 reviewed |
+| `TC-P-45-E` | 方案发布 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-45-E` | 方案管理 | 需审核配置时发布走审核流不直接 active;未 reviewed 发布拦截 |
+| `TC-P-46-E` | 方案激活 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-46-E` | 方案激活任务分解 | 已激活再激活幂等不重复生成任务;超时回滚不残半任务,状态回 reviewed |
+| `TC-P-47-E` | 方案任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-47-E` | GrowthPlanController | 删任务同步方案并提示;非法 id 400;任务增删与方案一致 |
+| `TC-P-48-E` | 方案版本 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-48-E` | 方案管理 | 历史版本只读返回 403『版本不可篡改』;不存在 404 |
+| `TC-P-49-E` | AI对话 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-49-E` | AIChatController | 超长消息 400 提示;敏感词按合规拦截;LangGraph 不可用 Fallback 兜底回答,多轮上下文不丢 |
+| `TC-P-50-E` | 成长记录 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-50-E` | GrowthController | 关联已删项跳过不报错;首访空态正常,时间线不白屏 |
+| `TC-P-51-E` | 成长里程碑 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-51-E` | GrowthController | 重复标幂等仅 1 条;非法节点 400 |
+| `TC-P-52-E` | 商城浏览 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-52-E` | MallController`/`danshop | 注入被转义返回安全结果;下架商品不展示;不 500 |
+| `TC-P-53-E` | 商品详情 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-53-E` | MallController | 库存 0 提示『暂时缺货』;不存在 404 |
+| `TC-P-54-E` | 商城下单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-54-E` | MallController | 超库存拦截『库存不足』;重复提交幂等仅 1 单 |
+| `TC-P-55-E` | 订单支付 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-55-E` | 支付 | 超时回滚订单保持待支付;重复通知幂等仅 1 次 paid |
+| `TC-P-56-E` | 订单退款 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-56-E` | 订单服务 | 已发货按规则处理/拒;重复退款拦截仅 1 次 |
+| `TC-P-57-E` | 优惠券 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-57-E` | 优惠券 | 过期券不可用提示;未达门槛拦截『还差 X 元可用』;不重复抵扣 |
+| `TC-P-58-E` | 会员购买 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-58-E` | MemberController | 失败回滚不解锁;重复购买幂等仅 1 次、不双扣 |
+| `TC-P-59-E` | 会员权益 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-59-E` | MemberController | 过期提示『会员已失效』;越权 403;权益随档位 |
+| `TC-P-60-E` | 会员续费 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-60-E` | MemberController | 未到期续费叠加计算正确(延期);负金额 400 |
+| `TC-P-61-E` | 联系人 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-61-E` | ContactCard`/`contact-detail | 重复号码去重提示;非法格式 400;不建重复 |
+| `TC-P-62-E` | 联系人导入 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-62-E` | ContactImport | 错误行跳过并报告『第 N 行格式错误』;非 CSV 拒绝;正确行入库 |
+| `TC-P-63-E` | 联系人权限 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-63-E` | ContactCard | 越权查看 403;非法权限值 400;最小权限保底 |
+| `TC-P-64-E` | 个人资料 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-64-E` | AuthController | 手机格式 400;昵称超长/非法字符拦截;保存生效 |
+| `TC-P-65-E` | 通知设置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-65-E` | 消息服务 | 关键安全通知仍推送不被关;非法时间 400 |
+| `TC-P-66-E` | 隐私设置 | 家长 | P3 | 异常 | `tests/test-cases/parent.md#TC-P-66-E` | 隐私设置 | 非法范围 400;敏感字段最小权限保底不外露 |
+| `TC-P-67-E` | 报告代传/report-proxy | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-67-E` | 报告代传/report-proxy | 越权代传他人孩子 403 被拒;报告归属校验失败不入档;授权令牌失效提示 |
+| `TC-P-68-E` | 家庭天盘 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-68-E` | 家庭天盘 | 缺失项降级展示不白屏;非成员访问 403;仅本家庭可见 |
+| `TC-P-69-E` | 精准营养 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-69-E` | 精准营养 | 负/超上限 400『热量需在合理区间』;非数字 400;目标生效影响食谱 |
+| `TC-P-70-E` | 舌诊情绪识别 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-70-E` | 舌诊情绪识别 | 非照片/模糊拒绝提示『请上传清晰舌苔照』;低置信度提示『识别不清晰,建议重拍』;隐私标注不外露 |
+| `TC-P-71-E` | AuthController | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-71-E` | AuthController | 有在途订单拦截『请先处理进行中订单』;注销后 token 失效 401 不可登录 |
+| `TC-P-72-E` | 数据导出(GDPR) | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-72-E` | 数据导出(GDPR) | 越权导出 403;频次限制提示『导出过于频繁』;敏感字段脱敏 |
+| `TC-P-73-E` | 家庭/成员 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-73-E` | 家庭/成员 | 非本家庭孩子不可选 400;切换保持各孩子上下文隔离不串 |
+| `TC-P-74-E` | 规划师绑定 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-74-E` | 规划师绑定 | 在途未完成提示『请先处理在途服务』;非本家庭 T 绑定 400 被拒 |
+| `TC-P-75-E` | 优惠券 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-75-E` | 优惠券 | 库存 0 提示『已领完』;重复领幂等仅入卡包 1 张 |
+| `TC-P-76-E` | 活动管理 | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-76-E` | 活动管理 | 并发超卖拦截仅 1 人成功(CFC 已修 bug 回归);满额拒『名额已满』;重复报名幂等 |
+| `TC-P-77-E` | 活动 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-77-E` | 活动 | 重复打卡幂等仅计 1 次;刷量风控拦截;进度累计正确 |
+| `TC-P-78-E` | 消息服务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-78-E` | 消息服务 | 越权消息不可见 403;不存在 404;分页正常 |
+| `TC-P-79-E` | 消息服务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-79-E` | 消息服务 | 关键安全通知不可关;非法时间 400 |
+| `TC-P-80-E` | 会员/订单 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-80-E` | 会员/订单 | 已消费不退提示;重复退拦截;发票信息校验缺失字段 400 |
+| `TC-P-81-E` | 方案/任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-81-E` | 方案/任务 | 过期草稿提示『草稿已失效』;并发存后者覆盖且提示冲突 |
+| `TC-P-82-E` | 搜索 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-82-E` | 搜索 | 越权结果过滤不可见;空结果不报错提示『请输入关键词』 |
+| `TC-P-83-E` | 客服 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-83-E` | 客服 | 敏感信息脱敏存储;附件超限 400『附件不超过 10MB』 |
+| `TC-P-84-E` | 分享 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-84-E` | 分享 | 失效链接提示『分享已失效』;越权分享 403 被拒 |
+| `TC-P-85-E` | AuthController | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-85-E` | AuthController | 异常设备二次验证/拦截;退出后旧 token 失效 401 |
+| `TC-P-86-E` | 勋章/排行 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-86-E` | 勋章/排行 | 非本家庭榜不可见 403;排名仅本家庭数据,刷新即更新 |
 | `TC-P-01-P` | 家庭 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-01-P` | FamilyInviteController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-01-P` | 家庭 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-01-P` | FamilyInviteController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-02-P` | 家庭/成员 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-02-P` | FamilyInviteController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-02-P` | 家庭/成员 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-02-P` | FamilyInviteController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-03-P` | 成员资料 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-03-P` | FamilyMembersController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-03-P` | 成员资料 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-03-P` | FamilyMembersController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
@@ -552,6 +573,27 @@
 | `TC-P-84-P` | 分享 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-84-P` | 分享 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-84-P` | 分享 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-84-P` | 分享 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-85-P` | AuthController | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-85-P` | AuthController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-85-P` | AuthController | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-85-P` | AuthController | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-86-P` | 勋章/排行 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-86-P` | 勋章/排行 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
 | `TC-P-86-P` | 勋章/排行 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-86-P` | 勋章/排行 | 非归属数据访问统一 403/401,不泄露他人数据;横向越权被拒 |
+| `TC-P-87` | 能量/任务 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-87` | EnergyRuleEngine`/`TaskController | B 对应维度 balance/totalEarned +amount;EnergyLog.sourceType=task、balanceAfter 正确;概览/沙盘随新值刷新 |
+| `TC-P-88` | 能量/心愿 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-88` | EnergyController`/`RewardController | 扣减成功,EnergyLog 负 amount、balanceAfter=balance-额;balance/totalSpent 同步;心愿已兑换 |
+| `TC-P-89` | 能量/手动 | 家长 | P2 | 功能 | `tests/test-cases/parent.md#TC-P-89` | EnergyController | 指定维度 +amount;EnergyLog.sourceType=manual 留痕;balanceAfter 更新 |
+| `TC-P-90` | 能量/日上限 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-90` | DimensionDailyLimit | 累计达 N 后新增触发不再累加(或截断到上限);跨日 00:00 清零可重新获取 |
+| `TC-P-91` | 能量/健康报告 | 家长 | P0 | 功能 | `tests/test-cases/parent.md#TC-P-91` | HealthReportController | 七维/六维评分刷新;概览/沙盘/score-history 按新值重算;时间序列反映改善 |
+| `TC-P-92` | 能量/配置 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-92` | EnergyController`/维度配置 | 按新口径重算并展示;存量重算提示 |
+| `TC-P-93` | 能量/文章·活动 | 家长 | P1 | 功能 | `tests/test-cases/parent.md#TC-P-93` | ArticleService`/`ActivityService | 对应维度 +amount;sourceType=article/activity;balanceAfter 更新 |
+| `TC-P-87-E` | 能量/任务 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-87-E` | EnergyRuleEngine | 1. 重复审批幂等不重复加、无第二条 EnergyLog 2. 无归因维度不 500、按规则落 sourceType 或不加 3. 参数非法统一 400、不改动能量 4. 规则异常告警、不写脏流水 |
+| `TC-P-88-E` | 能量/心愿 | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-88-E` | EnergyController`/`RewardController | 1. 余额不足明确"能量不足"、心愿保持待审批、无负余额 2. 并发仅一次成功、二次幂等拒 3. 已兑换再提交拒、无负流水 4. 参数非法 400、不扣减 |
+| `TC-P-89-E` | 能量/手动 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-89-E` | EnergyController | 1. 400 拦截不发放 2. 400 不写脏数据 3. 按幂等/业务规则不重复加 |
+| `TC-P-90-E` | 能量/日上限 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-90-E` | DimensionDailyLimit | 1. 触顶后其余来源同维度受限 2. 手动口径断言一致 3. 以服务端日期为准、不绕过 4. 上限 0/负 拒绝配置或按 0、不崩溃 |
+| `TC-P-91-E` | 能量/健康报告 | 家长 | P1 | 异常 | `tests/test-cases/parent.md#TC-P-91-E` | HealthReportController | 1. 不刷新、原评分保留 2. 类型不一致不可比/提示、不串维度 3. 该维度保持上一值或空态、不 500 4. 重复入库幂等不重复刷新 |
+| `TC-P-92-E` | 能量/配置 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-92-E` | EnergyController`/维度配置 | 1. 报警并拒或归一化、不静默错算 2. 展示兜底旧值并提示"同步中"、不显示错乱 3. 400 拦截 |
+| `TC-P-93-E` | 能量/文章·活动 | 家长 | P2 | 异常 | `tests/test-cases/parent.md#TC-P-93-E` | ArticleService`/`ActivityService | 1. 风控拦截不计能量 2. 触顶不累加 3. 按规则回收或保留、不双发 4. 参与被拒不发放 |
+| `TC-P-87-P` | 能量/任务 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-87-P` | JwtInterceptor`+role | 1. 非本家庭能量访问 403 2. 孩子端无 grant 入口、直接调被 role 校验拒 |
+| `TC-P-88-P` | 能量/心愿 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-88-P` | EnergyController | 1. 非本家庭心愿 403 2. 孩子端无扣减入口、直接调被拒 |
+| `TC-P-89-P` | 能量/手动 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-89-P` | JwtInterceptor`+role | 1. 非本家庭 grant 403 2. 孩子端拒 |
+| `TC-P-90-P` | 能量/日上限 | 家长 | P2 | 权限 | `tests/test-cases/parent.md#TC-P-90-P` | DimensionDailyLimit | 1. 他人累计不可见 403 2. 越权改配置 403 |
+| `TC-P-91-P` | 能量/健康报告 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-91-P` | HealthReportController | 非本家庭健康维度数据 403、不泄露 |
+| `TC-P-92-P` | 能量/配置 | 家长 | P1 | 权限 | `tests/test-cases/parent.md#TC-P-92-P` | EnergyController | 非 admin 改全局 403 |
+| `TC-P-93-P` | 能量/文章·活动 | 家长 | P2 | 权限 | `tests/test-cases/parent.md#TC-P-93-P` | ArticleService`/`ActivityService | 非本家庭流水 403 |
 | `TC-P-N01` | 健康报告 | 家长 | P1 | 性能 | `tests/test-cases/parent.md#TC-P-N01` | 健康报告上传解析 | 上传+解析 ≤ 30s;超时走 AiGateway 友好降级而非 500;进度可见 |
 | `TC-P-N01` | 健康报告 | 家长 | P1 | 性能 | `tests/test-cases/parent.md#TC-P-N01` | 健康报告上传解析 | 上传+解析 ≤ 30s;超时走 AiGateway 友好降级而非 500;进度可见 |
 | `TC-P-N02` | AI 方案 | 家长 | P1 | 性能 | `tests/test-cases/parent.md#TC-P-N02` | AiGateway/LangGraph | 各方案独立完整、数据不串;单请求 P95 ≤ 15s;LangGraph 超时回退 Fallback |
 | `TC-P-N02` | AI 方案 | 家长 | P1 | 性能 | `tests/test-cases/parent.md#TC-P-N02` | AiGateway/LangGraph | 各方案独立完整、数据不串;单请求 P95 ≤ 15s;LangGraph 超时回退 Fallback |
 | `TC-P-N03` | 任务 | 家长 | P2 | 性能 | `tests/test-cases/parent.md#TC-P-N03` | TaskController | 首屏 ≤ 2s;翻页流畅;分页/虚拟滚动生效 |
 | `TC-P-N03` | 任务 | 家长 | P2 | 性能 | `tests/test-cases/parent.md#TC-P-N03` | TaskController | 首屏 ≤ 2s;翻页流畅;分页/虚拟滚动生效 |
@@ -594,35 +636,35 @@
 | `TC-T-27` | 家庭天盘 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-27` | 家庭天盘 | 达成目标:给家庭看聚合视图并解读;边界:仅绑定家庭可见 |
 | `TC-T-27` | 家庭天盘 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-27` | 家庭天盘 | 达成目标:给家庭看聚合视图并解读;边界:仅绑定家庭可见 |
 | `TC-T-28` | 内容安全 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-28` | 内容安全 | 达成目标:复核 AI 敏感内容;边界:命中即拦截 |
 | `TC-T-28` | 内容安全 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-28` | 内容安全 | 达成目标:复核 AI 敏感内容;边界:命中即拦截 |
 | `TC-T-29` | 数据导出(GDPR) | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-29` | 数据导出(GDPR) | 达成目标:导出客户数据;边界:授权/脱敏;越权拒 |
 | `TC-T-29` | 数据导出(GDPR) | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-29` | 数据导出(GDPR) | 达成目标:导出客户数据;边界:授权/脱敏;越权拒 |
-| `TC-T-01-E` | 认证/双角色 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-01-E` | AuthController`;规划师可切回家长 | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-T-02-E` | 家庭绑定 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-02-E` | FamilyInviteController | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-T-03-E` | 健康报告 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-03-E` | 报告上传解析;规划师代传 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-04-E` | 报告审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-04-E` | 报告审核 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-05-E` | 方案管理 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-05-E` | 方案管理;黑盒回归项 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-06-E` | 方案审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-06-E` | 方案状态机 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-07-E` | 方案激活 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-07-E` | 激活拆任务 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-08-E` | 方案激活·幂等 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-08-E` | 幂等约束(黑盒回归) | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-09-E` | 任务审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-09-E` | TaskController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-T-10-E` | 测评录入 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-10-E` | AssessmentAppointmentController`/`DanAssessmentController | 额度不足/过期直接报错不落预约;并发重复提交被拒(幂等);状态机守卫非法回退 |
-| `TC-T-11-E` | 成长计划 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-11-E` | GrowthPlanController`;黑盒回归 | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-T-12-E` | 套餐 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-12-E` | GuidePackageController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-13-E` | 数据隔离 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-13-E` | 控制器内 role 检查 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-T-14-E` | 方案编辑 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-14-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-15-E` | 套餐任务 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-15-E` | GuidePackageController | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-16-E` | 健康总览 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-16-E` | 仪表板 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-T-17-E` | 计划进度 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-17-E` | GrowthPlanController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-T-18-E` | 批量任务 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-18-E` | TaskController | 重复提交幂等不重复计分;驳回可重做;超期不可操作;能量不为负、流水可追溯;空态/缺数据降级非 500 |
-| `TC-T-19-E` | 消息推送 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-19-E` | 消息服务 | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-T-20-E` | 退出/切换 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-20-E` | AuthController | token 过期/缺失统一 401 跳登录;孩子端无切回家长入口;越权切换被拒;模拟登录仅测试环境生效 |
-| `TC-T-21-E` | 报告对比 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-21-E` | 报告管理 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-22-E` | 方案归档 | 规划师 | P3 | 异常 | `tests/test-cases/teacher.md#TC-T-22-E` | 方案管理 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活/确认/购买幂等不重复生成任务/扣费;失败回滚不残半任务 |
-| `TC-T-23-E` | 报告代传/report-proxy | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-23-E` | 报告代传/report-proxy | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-24-E` | 规划师绑定 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-24-E` | 规划师绑定 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-25-E` | 舌诊情绪识别 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-25-E` | 舌诊情绪识别 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-26-E` | 精准营养 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-26-E` | 精准营养 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-27-E` | 家庭天盘 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-27-E` | 家庭天盘 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-T-28-E` | 内容安全 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-28-E` | 内容安全 | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务 |
-| `TC-T-29-E` | 数据导出(GDPR) | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-29-E` | 数据导出(GDPR) | LangGraph 不可用时 AiGateway Fallback 兜底,前端友好提示而非 500;重复激活幂等不重复生成任务;失败回滚不残半任务 |
+| `TC-T-01-E` | 认证/双角色 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-01-E` | AuthController`;规划师可切回家长 | 缺失/过期 token 统一 401 跳登录;非绑定家庭路由 403 被拒;模拟登录开关仅在测试环境可开 |
+| `TC-T-02-E` | 家庭绑定 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-02-E` | FamilyInviteController | 错码/过期提示『邀请码无效或已失效』;重复绑定幂等不双建;注销家庭不可绑 |
+| `TC-T-03-E` | 健康报告 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-03-E` | 报告上传解析;规划师代传 | 损坏/非募极提示明确(非募极提示请确认募极生物);超大超限提示;解析超时进草稿非500;非绑定孩子 403 |
+| `TC-T-04-E` | 报告审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-04-E` | 报告审核 | 已删草稿提示『不存在』;解析中确认提示稍候;非绑定家庭草稿 403 不可操作 |
+| `TC-T-05-E` | 方案管理 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-05-E` | 方案管理;黑盒回归项 | 列表超时降级提示非500;黑盒回归:函数不再未定义、不白屏;空列表正常占位 |
+| `TC-T-06-E` | 方案审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-06-E` | 方案状态机 | 非 generated 态批准拦截(状态机守卫);并发双批准幂等仅 1 次状态跃迁 |
+| `TC-T-07-E` | 方案激活 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-07-E` | 激活拆任务 | 超时回滚不残半任务、状态回 reviewed;已激活再激活幂等不重复生成任务;非 reviewed 激活拦截 |
+| `TC-T-08-E` | 方案激活·幂等 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-08-E` | 幂等约束(黑盒回归) | 第二次幂等返回现状、不重复生成引导/模板任务;任务数与首次一致 |
+| `TC-T-09-E` | 任务审核 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-09-E` | TaskController | 非绑定家庭 403;并发双审幂等仅计 1 次积分;超期任务审核被拒 |
+| `TC-T-10-E` | 测评录入 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-10-E` | AssessmentAppointmentController`/`DanAssessmentController | 必填缺失 400 不生成半成品;重复录入覆盖非新增;越界 400 不写脏分;非指派 confirm 返回『您不是被指派测评师』 |
+| `TC-T-11-E` | 成长计划 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-11-E` | GrowthPlanController`;黑盒回归 | 超时降级非500;空列表正常;非绑定家庭 403 |
+| `TC-T-12-E` | 套餐 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-12-E` | GuidePackageController | 空任务项拦截上架;审核超时回退草稿非500;重复提交幂等 |
+| `TC-T-13-E` | 数据隔离 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-13-E` | 控制器内 role 检查 | 非绑定家庭统一 403;不泄露他人数据;并发越权同样 403 |
+| `TC-T-14-E` | 方案编辑 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-14-E` | 方案管理 | 归档方案编辑拦截;非绑定家庭 403;超长 400 |
+| `TC-T-15-E` | 套餐任务 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-15-E` | GuidePackageController | 重算超时降级提示非500;空套餐拦截;并发增删各自生效不丢项 |
+| `TC-T-16-E` | 健康总览 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-16-E` | 仪表板 | 缺失项降级展示不白屏;超时降级提示非500;仅绑定家庭数据 |
+| `TC-T-17-E` | 计划进度 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-17-E` | GrowthPlanController | 超时降级非500;进度按任务状态实时计算、一致 |
+| `TC-T-18-E` | 批量任务 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-18-E` | TaskController | 部分失败不影响其他成员独立落库;并发批量各自独立不串 |
+| `TC-T-19-E` | 消息推送 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-19-E` | 消息服务 | 已注销客户跳过不报错;内容转义不执行脚本;免打扰不推送 |
+| `TC-T-20-E` | 退出/切换 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-20-E` | AuthController | 旧 token 失效 401;网络中断退出清缓存、下次需重登;切回家长正常 |
+| `TC-T-21-E` | 报告对比 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-21-E` | 报告管理 | 类型不一致提示不可比;不存在 id 404;差异清晰标注 |
+| `TC-T-22-E` | 方案归档 | 规划师 | P3 | 异常 | `tests/test-cases/teacher.md#TC-T-22-E` | 方案管理 | 归档后编辑/激活拦截;不存在 404 |
+| `TC-T-23-E` | 报告代传/report-proxy | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-23-E` | 报告代传/report-proxy | 非绑定家庭 403 拒;损坏/非募极提示明确;识别失败进草稿非500 |
+| `TC-T-24-E` | 规划师绑定 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-24-E` | 规划师绑定 | 在途未完成提示先处理;非平台家庭绑定 400 拒 |
+| `TC-T-25-E` | 舌诊情绪识别 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-25-E` | 舌诊情绪识别 | 类型校验拒绝(.php/.html)不执行;非照片/模糊拒;低置信度提示重拍 |
+| `TC-T-26-E` | 精准营养 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-26-E` | 精准营养 | 负/超上限 400『热量需在合理区间』;脚本转义存储不执行 |
+| `TC-T-27-E` | 家庭天盘 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-27-E` | 家庭天盘 | 非绑定家庭 403;缺失项降级展示不白屏 |
+| `TC-T-28-E` | 内容安全 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-28-E` | 内容安全 | 命中即拦截不放行;超时 Fallback 兜底、友好提示非500 |
+| `TC-T-29-E` | 数据导出(GDPR) | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-29-E` | 数据导出(GDPR) | 越权导出 403;频次限制提示『导出过于频繁』;敏感字段脱敏 |
 | `TC-T-01-P` | 认证/双角色 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-01-P` | AuthController`;规划师可切回家长 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
 | `TC-T-01-P` | 认证/双角色 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-01-P` | AuthController`;规划师可切回家长 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
 | `TC-T-02-P` | 家庭绑定 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-02-P` | FamilyInviteController | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
 | `TC-T-02-P` | 家庭绑定 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-02-P` | FamilyInviteController | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
 | `TC-T-03-P` | 健康报告 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-03-P` | 报告上传解析;规划师代传 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
 | `TC-T-03-P` | 健康报告 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-03-P` | 报告上传解析;规划师代传 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒(高危越权修复) |
@@ -652,6 +694,15 @@
 | `TC-T-27-P` | 家庭天盘 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-27-P` | 家庭天盘 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
 | `TC-T-27-P` | 家庭天盘 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-27-P` | 家庭天盘 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
 | `TC-T-28-P` | 内容安全 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-28-P` | 内容安全 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
 | `TC-T-28-P` | 内容安全 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-28-P` | 内容安全 | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
 | `TC-T-29-P` | 数据导出(GDPR) | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-29-P` | 数据导出(GDPR) | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
 | `TC-T-29-P` | 数据导出(GDPR) | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-29-P` | 数据导出(GDPR) | 非绑定家庭数据统一 403;confirm/cancel 增加归属校验,非指派调用被拒 |
+| `TC-T-30` | 测评/五维 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-30` | AssessmentAppointmentService | 八类分→五维刷新;生成 generated 方案;概览/沙盘刷新 |
+| `TC-T-31` | 维度/手动 | 规划师 | P1 | 功能 | `tests/test-cases/teacher.md#TC-T-31` | ManualDimensionScoreController | 目标维度覆盖/调整并留痕;概览/沙盘随新值刷新 |
+| `TC-T-32` | 五维/自评 | 规划师 | P2 | 功能 | `tests/test-cases/teacher.md#TC-T-32` | FiveDimensionSelfCheckController | 自评微调并叠加;FiveDimensionSelfCheck 留记录;历史可查 |
+| `TC-T-30-E` | 测评/五维 | 规划师 | P1 | 异常 | `tests/test-cases/teacher.md#TC-T-30-E` | AssessmentAppointmentService | 1. 400 不生成半成品 2. 覆盖非新增、无重复记录 3. 越界 400 不写脏分 |
+| `TC-T-31-E` | 维度/手动 | 规划师 | P2 | 异常 | `tests/test-cases/teacher.md#TC-T-31-E` | ManualDimensionScoreController | 1. 400 拦截 2. 幂等无重复痕迹;不影响其他维度(断言) |
+| `TC-T-32-E` | 五维/自评 | 规划师 | P3 | 异常 | `tests/test-cases/teacher.md#TC-T-32-E` | FiveDimensionSelfCheckController | 400 拦截;不写脏分 |
+| `TC-T-30-P` | 测评/五维 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-30-P` | AssessmentAppointmentService | 非绑定家庭录入 403 |
+| `TC-T-31-P` | 维度/手动 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-31-P` | ManualDimensionScoreController | 非绑定家庭 403 |
+| `TC-T-32-P` | 五维/自评 | 规划师 | P1 | 权限 | `tests/test-cases/teacher.md#TC-T-32-P` | FiveDimensionSelfCheckController | 非绑定家庭 403 |
 | `TC-T-N01` | 健康报告 | 规划师 | P1 | 性能 | `tests/test-cases/teacher.md#TC-T-N01` | 报告解析中台 | 队列不堵;单份 ≤ 30s;失败重试不重复入库 |
 | `TC-T-N01` | 健康报告 | 规划师 | P1 | 性能 | `tests/test-cases/teacher.md#TC-T-N01` | 报告解析中台 | 队列不堵;单份 ≤ 30s;失败重试不重复入库 |
 | `TC-T-N02` | 方案审核 | 规划师 | P1 | 性能 | `tests/test-cases/teacher.md#TC-T-N02` | 方案状态机 | 列表 ≤ 2s;筛选/排序生效 |
 | `TC-T-N02` | 方案审核 | 规划师 | P1 | 性能 | `tests/test-cases/teacher.md#TC-T-N02` | 方案状态机 | 列表 ≤ 2s;筛选/排序生效 |
 | `TC-T-N03` | 绑定家庭 | 规划师 | P2 | 性能 | `tests/test-cases/teacher.md#TC-T-N03` | 绑定家庭 | 切换 ≤ 1.5s;数据隔离不串 |
 | `TC-T-N03` | 绑定家庭 | 规划师 | P2 | 性能 | `tests/test-cases/teacher.md#TC-T-N03` | 绑定家庭 | 切换 ≤ 1.5s;数据隔离不串 |
@@ -671,17 +722,17 @@
 | `TC-S-9` | 服务商集成/解析中台 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-9` | 服务商集成/解析中台 | 达成目标:提供解析能力;边界:跨商户隔离;鉴权 |
 | `TC-S-9` | 服务商集成/解析中台 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-9` | 服务商集成/解析中台 | 达成目标:提供解析能力;边界:跨商户隔离;鉴权 |
 | `TC-S-10` | 食谱库 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-10` | 食谱库 | 达成目标:供食谱数据;边界:数据合规;格式校验 |
 | `TC-S-10` | 食谱库 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-10` | 食谱库 | 达成目标:供食谱数据;边界:数据合规;格式校验 |
 | `TC-S-11` | 合规 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-11` | 合规 | 达成目标:授权内用数;边界:越授权拒;脱敏 |
 | `TC-S-11` | 合规 | 服务商 | P1 | 功能 | `tests/test-cases/vendor.md#TC-S-11` | 合规 | 达成目标:授权内用数;边界:越授权拒;脱敏 |
-| `TC-S-01-E` | 入驻 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-01-E` | ServiceRoleApplicationController`/`AdminEcomSupplierController | 系统给出明确错误提示而非 500;关键操作可重试或回滚;不泄露内部堆栈 |
-| `TC-S-02-E` | 商品 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-02-E` | ProductController`/`AdminProductController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-03-E` | 订单 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-03-E` | ProductOrderController | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-04-E` | 订单核销 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-04-E` | 订单服务 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-05-E` | 库存 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-05-E` | 库存服务 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-06-E` | 售后 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-06-E` | 售后 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-07-E` | 活动报名 | 服务商 | P3 | 异常 | `tests/test-cases/vendor.md#TC-S-07-E` | 活动管理 | 标题/名称重复被拦截;参数非法统一 400 非 500;长文稳定无超时;操作可逆或有确认 |
-| `TC-S-08-E` | 对账 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-08-E` | 结算 | 支付失败订单回滚不进入已支付;重复提交幂等;负价格/负库存/参数非法统一 400 拦截;重复核销/退款幂等 |
-| `TC-S-9-E` | 服务商集成/解析中台 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-9-E` | 服务商集成/解析中台 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-S-10-E` | 食谱库 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-10-E` | 食谱库 | 识别失败或解析超时给出明确提示,进入未知聚类/草稿而非 500;非募极报告明确提示「请确认是募极生物肠道菌群报告」 |
-| `TC-S-11-E` | 合规 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-11-E` | 合规 | 并发安全;重复操作幂等;异常设备二次验证;数据归档/导出脱敏合规 |
+| `TC-S-01-E` | 入驻 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-01-E` | ServiceRoleApplicationController`/`AdminEcomSupplierController | 资质缺失驳回并说明缺项;重复申请幂等不双建;非法联系方式 400 |
+| `TC-S-02-E` | 商品 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-02-E` | ProductController`/`AdminProductController | 负价格/负库存/非法分类统一 400;并发改库存乐观锁不互相覆盖;下架后不可购买 |
+| `TC-S-03-E` | 订单 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-03-E` | ProductOrderController | 支付失败订单回滚不进已发货;重复发货幂等仅 1 次;核销码校验失败拒(防冒用) |
+| `TC-S-04-E` | 订单核销 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-04-E` | 订单服务 | 重复核销幂等;超期提示不可核销;非本服务商 403 |
+| `TC-S-05-E` | 库存 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-05-E` | 库存服务 | 负库存 400 拦截;并发超卖保护不出现负库存;同步失败重试前台一致 |
+| `TC-S-06-E` | 售后 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-06-E` | 售后 | 重复退款拦截仅 1 次;超金额 400;非本服务商 403;流水可追溯 |
+| `TC-S-07-E` | 活动报名 | 服务商 | P3 | 异常 | `tests/test-cases/vendor.md#TC-S-07-E` | 活动管理 | 失效活动报名拒;重复报名幂等;非法参数 400 |
+| `TC-S-08-E` | 对账 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-08-E` | 结算 | 未到账期结算拒;重复结算幂等;异常金额告警不入账 |
+| `TC-S-9-E` | 服务商集成/解析中台 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-9-E` | 服务商集成/解析中台 | 跨商户隔离 403;损坏/超大文件明确提示非500;鉴权失效 401 |
+| `TC-S-10-E` | 食谱库 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-10-E` | 食谱库 | 格式校验 400;XSS 转义存储不执行;非本商户 403 |
+| `TC-S-11-E` | 合规 | 服务商 | P2 | 异常 | `tests/test-cases/vendor.md#TC-S-11-E` | 合规 | 越授权 403 拒;敏感字段强制脱敏;并发越权同样 403 |
 | `TC-S-01-P` | 入驻 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-01-P` | ServiceRoleApplicationController`/`AdminEcomSupplierController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
 | `TC-S-01-P` | 入驻 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-01-P` | ServiceRoleApplicationController`/`AdminEcomSupplierController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
 | `TC-S-02-P` | 商品 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-02-P` | ProductController`/`AdminProductController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
 | `TC-S-02-P` | 商品 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-02-P` | ProductController`/`AdminProductController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
 | `TC-S-03-P` | 订单 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-03-P` | ProductOrderController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
 | `TC-S-03-P` | 订单 | 服务商 | P1 | 权限 | `tests/test-cases/vendor.md#TC-S-03-P` | ProductOrderController | 非本服务商资源操作被拒;核销码校验防冒用;跨商户数据隔离 |
@@ -719,7 +770,7 @@
 | `tests/e2e/api/api-smoke.spec.js` | 4 | `tests/e2e/api/api-smoke.spec.js` |
 | `tests/e2e/api/api-smoke.spec.js` | 4 | `tests/e2e/api/api-smoke.spec.js` |
 | `tests/e2e/api/article-api.spec.js` | 7 | `tests/e2e/api/article-api.spec.js` |
 | `tests/e2e/api/article-api.spec.js` | 7 | `tests/e2e/api/article-api.spec.js` |
 | `tests/e2e/api/contact-api.spec.js` | 6 | `tests/e2e/api/contact-api.spec.js` |
 | `tests/e2e/api/contact-api.spec.js` | 6 | `tests/e2e/api/contact-api.spec.js` |
-| `tests/e2e/api/energy-api.spec.js` | 9 | `tests/e2e/api/energy-api.spec.js` |
+| `tests/e2e/api/energy-api.spec.js` | 8 | `tests/e2e/api/energy-api.spec.js` |
 | `tests/e2e/api/family-member-api.spec.js` | 14 | `tests/e2e/api/family-member-api.spec.js` |
 | `tests/e2e/api/family-member-api.spec.js` | 14 | `tests/e2e/api/family-member-api.spec.js` |
 | `tests/e2e/api/nonfunc-perf-compat.spec.js` | 5 | `tests/e2e/api/nonfunc-perf-compat.spec.js` |
 | `tests/e2e/api/nonfunc-perf-compat.spec.js` | 5 | `tests/e2e/api/nonfunc-perf-compat.spec.js` |
 | `tests/e2e/api/nonfunc-security.spec.js` | 11 | `tests/e2e/api/nonfunc-security.spec.js` |
 | `tests/e2e/api/nonfunc-security.spec.js` | 11 | `tests/e2e/api/nonfunc-security.spec.js` |
@@ -807,17 +858,24 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | cfc-backend | 5 | JwtInterceptorLoginRequired | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` | cfc-backend | 5 | JwtInterceptorLoginRequired | `cfc-backend/src/test/java/com/etotem/cfc/config/JwtInterceptorLoginRequiredTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` | cfc-backend | 1 | AttributionController | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` | cfc-backend | 1 | AttributionController | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | cfc-backend | 3 | AttributionSurveyRouting | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` | cfc-backend | 3 | AttributionSurveyRouting | `cfc-backend/src/test/java/com/etotem/cfc/controller/AttributionSurveyRoutingTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java` | cfc-backend | 2 | DanAssessmentControllerGetActiveMaterial | `cfc-backend/src/test/java/com/etotem/cfc/controller/DanAssessmentControllerGetActiveMaterialTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerGrantEnergyTest.java` | cfc-backend | 3 | EnergyControllerGrantEnergy | `cfc-backend/src/test/java/com/etotem/cfc/controller/EnergyControllerGrantEnergyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` | cfc-backend | 6 | HealthCheckinCfEarnCallSite | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` | cfc-backend | 6 | HealthCheckinCfEarnCallSite | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthCheckinCfEarnCallSiteTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` | cfc-backend | 6 | HealthPlanDeleteController | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` | cfc-backend | 6 | HealthPlanDeleteController | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthPlanDeleteControllerTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerCreateReportTest.java` | cfc-backend | 5 | HealthReportControllerCreateReport | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerCreateReportTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` | cfc-backend | 4 | HealthReportControllerListPagination | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` | cfc-backend | 4 | HealthReportControllerListPagination | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerListPaginationTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` | cfc-backend | 6 | HealthReportControllerProxyParseBinding | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` | cfc-backend | 6 | HealthReportControllerProxyParseBinding | `cfc-backend/src/test/java/com/etotem/cfc/controller/HealthReportControllerProxyParseBindingTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | cfc-backend | 2 | IndicatorController | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` | cfc-backend | 2 | IndicatorController | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | cfc-backend | 10 | IndicatorFavoriteController | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` | cfc-backend | 10 | IndicatorFavoriteController | `cfc-backend/src/test/java/com/etotem/cfc/controller/IndicatorFavoriteControllerTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminAuthWechatScanTest.java` | cfc-backend | 11 | AdminAuthWechatScan | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminAuthWechatScanTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` | cfc-backend | 4 | AdminProductControllerBatchShelve | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` | cfc-backend | 4 | AdminProductControllerBatchShelve | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/AdminProductControllerBatchShelveTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | cfc-backend | 3 | ReportParserAdminController | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` | cfc-backend | 3 | ReportParserAdminController | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/ReportParserAdminControllerTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/SupplyTeamControllerInviteTest.java` | cfc-backend | 7 | SupplyTeamControllerInvite | `cfc-backend/src/test/java/com/etotem/cfc/controller/admin/SupplyTeamControllerInviteTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerAddMemberTest.java` | cfc-backend | 7 | FamilyMembersControllerAddMember | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerAddMemberTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | cfc-backend | 4 | FamilyMembersControllerList | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` | cfc-backend | 4 | FamilyMembersControllerList | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerListTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` | cfc-backend | 2 | FamilyMembersControllerRenameFamily | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` | cfc-backend | 2 | FamilyMembersControllerRenameFamily | `cfc-backend/src/test/java/com/etotem/cfc/controller/family/FamilyMembersControllerRenameFamilyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` | cfc-backend | 1 | TeacherMessageControllerMy | `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` | cfc-backend | 1 | TeacherMessageControllerMy | `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TeacherMessageControllerMyTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TrainingPlanControllerGetPlanListTest.java` | cfc-backend | 10 | TrainingPlanControllerGetPlanList | `cfc-backend/src/test/java/com/etotem/cfc/controller/guide/TrainingPlanControllerGetPlanListTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` | cfc-backend | 3 | ActivityDTO | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` | cfc-backend | 3 | ActivityDTO | `cfc-backend/src/test/java/com/etotem/cfc/dto/ActivityDTOTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` | cfc-backend | 6 | DailyCheckinStreakFlow | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` | cfc-backend | 6 | DailyCheckinStreakFlow | `cfc-backend/src/test/java/com/etotem/cfc/integration/DailyCheckinStreakFlowTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | cfc-backend | 7 | EnergySystemFlow | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` | cfc-backend | 7 | EnergySystemFlow | `cfc-backend/src/test/java/com/etotem/cfc/integration/EnergySystemFlowTest.java` |
@@ -857,7 +915,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | cfc-backend | 21 | DimensionScoreService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` | cfc-backend | 21 | DimensionScoreService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/DimensionScoreServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | cfc-backend | 9 | FamilyFoodOverviewService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` | cfc-backend | 9 | FamilyFoodOverviewService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FamilyFoodOverviewServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | cfc-backend | 2 | FiveDimensionSelfCheckService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` | cfc-backend | 2 | FiveDimensionSelfCheckService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FiveDimensionSelfCheckServiceTest.java` |
-| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | cfc-backend | 18 | FoodRecommendService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` | cfc-backend | 21 | FoodRecommendService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodRecommendServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | cfc-backend | 12 | FoodService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` | cfc-backend | 12 | FoodService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FoodServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | cfc-backend | 4 | FortuneService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` | cfc-backend | 4 | FortuneService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/FortuneServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | cfc-backend | 8 | GuideApplicationService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` | cfc-backend | 8 | GuideApplicationService | `cfc-backend/src/test/java/com/etotem/cfc/integration/service/GuideApplicationServiceTest.java` |
@@ -897,9 +955,11 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` | cfc-backend | 5 | CommissionServiceReferralF24 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` | cfc-backend | 5 | CommissionServiceReferralF24 | `cfc-backend/src/test/java/com/etotem/cfc/service/CommissionServiceReferralF24Test.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` | cfc-backend | 2 | ConsigneeServiceBackfill | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` | cfc-backend | 2 | ConsigneeServiceBackfill | `cfc-backend/src/test/java/com/etotem/cfc/service/ConsigneeServiceBackfillTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` | cfc-backend | 2 | EnergyServiceFamily | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` | cfc-backend | 2 | EnergyServiceFamily | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceFamilyTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceGrantEnergyTest.java` | cfc-backend | 2 | EnergyServiceGrantEnergy | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceGrantEnergyTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | cfc-backend | 4 | EnergyServiceWealthIncome | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` | cfc-backend | 4 | EnergyServiceWealthIncome | `cfc-backend/src/test/java/com/etotem/cfc/service/EnergyServiceWealthIncomeTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | cfc-backend | 3 | FamilyAdminOverviewService | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` | cfc-backend | 3 | FamilyAdminOverviewService | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyAdminOverviewServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | cfc-backend | 5 | FamilyJoinRequestServiceReferrerBind | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` | cfc-backend | 5 | FamilyJoinRequestServiceReferrerBind | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyJoinRequestServiceReferrerBindTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyMemberServiceIsChildTest.java` | cfc-backend | 5 | FamilyMemberServiceIsChild | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyMemberServiceIsChildTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | cfc-backend | 5 | FamilyPlatformPointsServiceCoupon | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` | cfc-backend | 5 | FamilyPlatformPointsServiceCoupon | `cfc-backend/src/test/java/com/etotem/cfc/service/FamilyPlatformPointsServiceCouponTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` | cfc-backend | 8 | HealthReportServiceAuditConfirm | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` | cfc-backend | 8 | HealthReportServiceAuditConfirm | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceAuditConfirmTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | cfc-backend | 5 | HealthReportServiceBackfillResilience | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` | cfc-backend | 5 | HealthReportServiceBackfillResilience | `cfc-backend/src/test/java/com/etotem/cfc/service/HealthReportServiceBackfillResilienceTest.java` |
@@ -984,6 +1044,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` | cfc-backend | 3 | TaskProgressUpdate | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` | cfc-backend | 3 | TaskProgressUpdate | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskProgressUpdateTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | cfc-backend | 8 | CfFormulaEvaluator | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` | cfc-backend | 8 | CfFormulaEvaluator | `cfc-backend/src/test/java/com/etotem/cfc/util/CfFormulaEvaluatorTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | cfc-backend | 6 | SpearmanUtil | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` | cfc-backend | 6 | SpearmanUtil | `cfc-backend/src/test/java/com/etotem/cfc/util/SpearmanUtilTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/util/UserUtilTest.java` | cfc-backend | 6 | UserUtil | `cfc-backend/src/test/java/com/etotem/cfc/util/UserUtilTest.java` |
 
 
 ## 六、用户场景(`tests/user-scenarios/*.md`,上游输入)
 ## 六、用户场景(`tests/user-scenarios/*.md`,上游输入)
 
 
@@ -995,6 +1056,7 @@
 | `tests/user-scenarios/04-teacher.md` | `tests/user-scenarios/04-teacher.md` |
 | `tests/user-scenarios/04-teacher.md` | `tests/user-scenarios/04-teacher.md` |
 | `tests/user-scenarios/05-admin.md` | `tests/user-scenarios/05-admin.md` |
 | `tests/user-scenarios/05-admin.md` | `tests/user-scenarios/05-admin.md` |
 | `tests/user-scenarios/06-vendor.md` | `tests/user-scenarios/06-vendor.md` |
 | `tests/user-scenarios/06-vendor.md` | `tests/user-scenarios/06-vendor.md` |
+| `tests/user-scenarios/07-five-dimension.md` | `tests/user-scenarios/07-five-dimension.md` |
 | `tests/user-scenarios/README.md` | `tests/user-scenarios/README.md` |
 | `tests/user-scenarios/README.md` | `tests/user-scenarios/README.md` |
 | `tests/user-scenarios/应用场景总览.md` | `tests/user-scenarios/应用场景总览.md` |
 | `tests/user-scenarios/应用场景总览.md` | `tests/user-scenarios/应用场景总览.md` |
 
 

+ 536 - 0
docs/tdd/test/perf-reliability-review-luocheng.md

@@ -0,0 +1,536 @@
+# 性能 · 可靠性维度审查报告(骆骋 / performance-reliability-reviewer)
+
+> 审查对象:`d:/cfc`(cfc-backend / cfc-langgraph / cfc-web / cfc-frontend)
+> 执行档:**review 档(离线、只读、白名单内)**。未获联网授权 → **未发起任何压测,未对任何目标环境发流量**
+> 本次仅做静态只读审查,**未修改任何代码**(临时扫描脚本已删除,`git status` 无我引入的改动)
+
+---
+
+## 结论
+
+**不通过**(针对性能 · 可靠性维度)。
+
+理由:性能侧**基线不成立**(唯一可执行阈值是单请求 8s、无分位数无并发无吞吐,且与项目自有文档矛盾),可靠性侧**关键机制存在实现级缺陷**(10 处 HTTP 客户端零超时、AI 熔断器被 17 个端点共用且半开态无并发限流、启动期 320 条 ALTER TABLE 无版本管理、后端健康探针指向不存在的 `/actuator/health`、AI 服务 gunicorn 单 worker + 2 小时超时),且**恢复能力零证据**(无备份脚本、无恢复演练、无故障注入记录)。
+
+**性能压测未授权未执行。** 下文「性能测试设计」中的所有阈值均为**建议值(待基线校准)**,不代表当前系统已达成或不达成;当前达成情况**未知**,需实测后回填。
+
+---
+
+## 关键证据
+
+### A. 性能基线(定义有了,但不可执行 / 互相矛盾)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| A1 | `tests/e2e/api/nonfunc-perf-compat.spec.js:113` | 唯一可执行延迟基线:`expect(dt).toBeLessThan(8000)`,**单次请求、无 P95/P99、无并发、无吞吐、无资源采样** |
+| A2 | `tests/test-cases/admin.md:114-117` | 文档层其实有阈值:配置列表 ≤2s、解析单条 ≤30s、统计聚合 ≤3s、压测触发限流熔断 429 |
+| A3 | `tests/test-cases/cross-role-e2e.md:126-129` | 报告链路 **P95 ≤ 40s**、活动名额 **100 / 瞬时 500 请求**、打卡 ≤1s |
+| A4 | `tests/test-cases/README.md:39-42` | 56 条非功能用例(性能 21 条)中,**性能类仅落地 5 条**,真实压测类「因需 execute 档联网授权,保留为文档化设计」 |
+| A5 | `docs/architecture/Dify替代迁移可行性分析.md:483` | `POST /api/ai/chat/send` 响应 **≤2s (P95)** —— 与实际链路(`cfc-backend/src/main/resources/application.yml:132` `read-timeout-ms: 300000`,LLM 推理 30-60s)**严重矛盾,属拍脑袋数字** |
+| A6 | 全仓 `docs/` grep `P95\|P99\|QPS\|TPS\|容量规划\|SLO` | **无任何容量测算结论**("当前容量能支撑多少用户/请求"),`docs/architecture/2026-07-20-SB3-upgrade-plan.md:858` 仅提出"取 10 次请求的 P50/P95/P99"但步骤全部未勾选 |
+
+### B. HTTP 客户端超时缺失(最严重性能风险)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| B1 | `KnowledgeBaseController.java:40`、`KnowledgeBaseVectorController.java:29`、`BodyFatScaleService.java:45`、`HealthPlanServiceImpl.java:283`/`371`/`1183`、`InsurancePolicyService.java:45`、`LanggraphSyncService.java:43`、`RecommendationService.java:44`、`VirtualPayService.java:73` | **10 处 `new RestTemplate()`**,SimpleClientHttpRequestFactory 默认**无限阻塞**。已核实这些文件内**无任何 setConnectTimeout/setReadTimeout**,且存在真实调用点(如 `KnowledgeBaseVectorController.java:45/61/81/97/126`、`VirtualPayService.java:527`) |
+| B2 | `AiGateway.java:65` | `fastTemplate` 硬编码 `factory.setReadTimeout(60000)`,与 `application.yml:132` 的 `read-timeout-ms: 300000` **不一致**;questionnaire 生成(推理 30-60s)会稳定命中 60s 超时 → 计入熔断失败 |
+| B3 | `config/RestTemplateConfig.java:17` / `:26` | 通用 bean readTimeout **180s**、langGraph bean **300s**。配合 Tomcat 默认 200 线程 → 最坏 200×180s 全站线程阻塞 |
+| B4 | `cfc-langgraph/src/graphs/emotion.py:60` | async 上下文中用**同步 `requests.get(req["image_url"], timeout=10)`** → 阻塞唯一事件循环 |
+
+### C. 熔断 / 超时 / Fallback 实现缺陷(读代码验证,非文档推断)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| C1 | `service/AiGateway.java:70-72` | `consecutiveFailures` / `lastFailureTime` / `circuitOpen` 是**实例字段**,被 `recommend`/`chat`/`chatForAnalysis`/`generateQuestionnaire`/`generateInnateReading`/`generateSelfCheckAdvice`/`generateSelfCheckTrend`/`generateSelfCheckQuestions`/`generatePortrait`/`classifyIndicator`/`recognizeFood`/`generateMenu`/`generateHealthPlan`/`analyzeEmotion`/`analyzeEmotionByUrl`/`transcribe`/`analyzeTongue`/`detectTongue`/`generateArticleQuiz` **共 20 个方法共用一个熔断器** |
+| C2 | `AiGateway.java:162`(及 `:222`/`:280`/`:330`/`:388`/`:443`/`:496`/`:527`/`:571`/`:605`/`:630`/`:659`/`:721`/`:766`/`:803`/`:834`) | 任一端点成功即 `consecutiveFailures.set(0)` → **一个慢端点(menu/generate)的超时可熔断掉完全无关的端点;反之某端点成功会掩盖另一端点的连续失败** |
+| C3 | `AiGateway.java:101-110` | 半开逻辑:reset 超时后 `circuitOpen=false; consecutiveFailures.set(0); return false` —— **无并发探测限制**,恢复瞬间全部线程同时放行(惊群) |
+| C4 | `AiGateway.java:167`/`:334`/`:364`/`:391`/`:418`/`:448`/`:499`/`:635`/`:771`/`:839` | HTTP 2xx 但响应体语义异常时**直接 `return null` 且不调用 `recordFailure()`** → 熔断触发口径不一致(只有抛异常才计数) |
+| C5 | `AiGateway.java:126`/`:180`/`:250`/… | `if (!enabled \|\| isCircuitOpen()) return null;` —— 熔断打开后**全部 AI 能力同时降级为 null**,无按端点/按能力的分级熔断 |
+
+### D. 连接池 / 线程池配置
+
+| # | 证据 | 说明 |
+|---|---|---|
+| D1 | `cfc-backend/pom.xml:102` + 本地仓库 `.m2/repository/org/apache/commons/commons-pool2/`(**不存在**) | 仅 `spring-boot-starter-data-redis`,**无 commons-pool2** → `application.yml:37-41` 的 `lettuce.pool.max-active: 8 / max-idle: 8` **静默失效**(Spring Boot 无 commons-pool2 时 Lettuce 用共享连接)。配置存在但不生效,属误导性配置 |
+| D2 | `application.yml:3-8` | Tomcat **仅配 headers**,无 `max-threads`/`min-spare-threads`/`accept-count`/`max-connections` → 全默认(200 / 10 / 100 / 8192) |
+| D3 | `config/AsyncConfig.java:18-23` | `taskExecutor`:core 8 / max 16 / queue 100 / **`CallerRunsPolicy`** → 队列打满时**由 HTTP 请求线程代跑采集任务**,请求被阻塞至整个 AI 解析完成(可达 300s) |
+| D4 | `config/AsyncConfig.java:31` | `taskScheduler` poolSize 4 —— 全部定时任务(含 `DatabaseInitializer` 之外的巡检)共用 4 线程 |
+| D5 | `application.yml:26` vs D2 | Hikari `maximum-pool-size: 50` 与 Tomcat 200 线程不匹配 → DB 慢时线程在池上排队,DB 恢复后形成惊群 |
+| D6 | `application.yml:36` | Redis `timeout: 3000ms`;`config/RateLimitInterceptor.java:34/128` **每个请求都打 Redis**(滑动窗口 Lua)→ Redis 抖动直接放大为全站延迟 |
+
+### E. N+1 与全表扫描
+
+| # | 证据 | 说明 |
+|---|---|---|
+| E1 | `controller/stats/StatsController.java:535` | `for (Article a : articleMapper.selectList(null))` —— **无 WHERE、无 LIMIT 的全表文章查询** |
+| E2 | `controller/stats/StatsController.java:669` | `for (User u : userMapper.selectList(null))` —— **全表用户查询** |
+| E3 | `controller/stats/StatsController.java:704` | `prodAgg.forEach` 内 `Product p = productMapper.selectById(pid)` —— **典型 N+1** |
+| E4 | `service/HealthFilterService.java:217` | `drugInteractionMapper.selectList(null)` —— 每次药品相互作用校验全表拉取 |
+| E5 | `service/BeijingNutritionService.java:714` → `HealthFilterService.java:245` | 循环内调 `isFoodHardBlocked` → 每次触发 `diseaseIntakeLimitMapper.selectList(null)` → **N × 全表扫描** |
+| E6 | `service/BeijingNutritionService.java:82`/`:708`、`service/HealthReportService.java:2467` | `foodMapper.selectList(null)` —— 全表食材 |
+| E7 | 全仓统计 | **`selectList(null)` 共 40 处**;循环体内 mapper 调用嫌疑 **331 处**(精筛后,含 selectById/selectList/insert/updateById) |
+| E8 | `config/MyBatisPlusConfig.java:16` | `PaginationInnerInterceptor` 已注册 —— 但上述 `selectList(null)` 路径**绕过分页插件**,分页能力形同虚设 |
+
+### F. 慢查询(前置通配 LIKE)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| F1 | 全仓统计 **91 处** MyBatis-Plus `.like()` | MyBatis-Plus `like()` 默认生成 `LIKE '%v%'`(**双侧通配**),索引失效 |
+| F2 | `service/ArticleService.java:118` / `:681` | `like(Title).or().like(Summary).or().like(Tags)` —— **三列 or-like**,最坏全表扫描 |
+| F3 | `controller/admin/AdminController.java:293-295`、`controller/growth/GrowthPlanController.java:123-125`、`controller/ContentFilterController.java:100`/`:122-127`/`:147-154` | 多列 or-like 叠加,叠加 `selectList(null)` 语义时无分页 |
+
+### G. 缓存缺失
+
+| # | 证据 | 说明 |
+|---|---|---|
+| G1 | 全仓 `@Cacheable` 命中 **仅 2 处**:`controller/nutrition/NutritionProductController.java:39`/`:46`(nutritionCategory / nutritionBrand) | 高频读(能量、任务、徽章、统计、文章、社区)**全部直连 DB**,无本地缓存无 Redis 读缓存 |
+| G2 | `config/RedisConfig.java`(`@EnableCaching` + RedisCacheManager,TTL 10min,禁空值) | 缓存基础设施**已就绪但几乎未使用** —— 属于"有配置无覆盖" |
+| G3 | `config/CfConfigCache.java` | 仅覆盖配置项,热点业务对象未纳入 |
+
+### H. 文件上传与内存
+
+| # | 证据 | 说明 |
+|---|---|---|
+| H1 | `application.yml:16-17` | `max-file-size: 50MB` / `max-request-size: 50MB` —— 无按端点细分上限 |
+| H2 | `service/PdfParseService.java:125-132` | `PDDocument.load(inputStream)` —— **整个 PDF 读入堆内存**(PDFBox 解析),50MB PDF 的堆占用放大数倍,且**在请求线程同步执行** |
+| H3 | `controller/HealthReportController.java:836` / `:874` / `:880` | 同一请求内同步完成:PDF 解析 → 建报告 → 建指标/菌群/风险 → 落快照 → 存食材 → **7 维评分刷新** → **食材推荐指数重算**;无异步化、无耗时上限 |
+| H4 | `service/AiGateway.java:706-734`(transcribe)、`:741-777`(analyzeTongue)、`:785-811`(detectTongue) | 整个文件先读成 `byte[]` 再 multipart 外发 —— 堆内双份占用 |
+| H5 | `cfc-backend/start.sh:47-52` | `-Xms512m -Xmx2g` —— 2GB 堆下跑 50MB 上传 + PDFBox + 多路 AI 并发,OOM 风险高 |
+
+### I. 数据库迁移锁表
+
+| # | 证据 | 说明 |
+|---|---|---|
+| I1 | `config/DatabaseInitializer.java:66` | `runMigrations()` 在 **CommandLineRunner 启动期**执行(每次启动) |
+| I2 | `config/DatabaseInitializer.java:155+` | **320 条 ALTER TABLE**(257 ADD COLUMN / 43 MODIFY COLUMN / **23 ADD INDEX**)+ 335 条 CREATE TABLE,每次启动全量重放 |
+| I3 | `cfc-backend/pom.xml` | **无 Flyway、无 Liquibase**(grep 无命中)→ 无版本表、无幂等保证、无 checksum 校验 |
+| I4 | `config/DatabaseInitializer.java:158-162`(及后续每条) | 每条 DDL 独立 `try/catch` **吞掉异常**,迁移失败静默;`ADD INDEX` 在 MySQL 为 INPLACE 重建,**大表上阻塞写入** |
+| I5 | `config/DatabaseInitializer.java:143` | 建表语句同样 `catch → log.warn` 静默失败 |
+
+### J. 健康检查 / 就绪探针(可靠性致命)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| J1 | `cfc-backend/pom.xml` grep `actuator` → **0 命中**;`src/main/resources/application.yml` grep `management:`/`actuator` → **0 命中**(且**只有这一个 profile 文件**,无 application-prod.yml) | **不存在 `/actuator/health`**,也就没有就绪探针 / 依赖健康(DB/Redis)暴露 |
+| J2 | `cfc-langgraph/docker-compose.yml`(cfc-backend 服务 healthcheck) | `test: ["CMD","curl","-f","http://localhost:9082/actuator/health"]` → **该探针必然失败**,后端容器恒为 unhealthy(Docker Compose 不自动重启 unhealthy 容器,但编排层会摘流量 → **后端持续被判死**) |
+| J3 | `cfc-langgraph/docker-compose.yml`(cfc-backend build 段) | `context: ../cfc-backend, dockerfile: Dockerfile` —— 但 **`cfc-backend/Dockerfile` 不存在**(全仓仅 `cfc-langgraph/Dockerfile`)→ 后端容器构建路径不可用 |
+| J4 | `cfc-langgraph/app/api/health.py` | Python 侧 `/health` 仅返回 `{"status":"ok"}` —— **恒 200,不反映依赖真实状态**(ChromaDB / SQLite checkpointer / LLM 网关均不探测) |
+
+### K. AI 服务并发模型
+
+| # | 证据 | 说明 |
+|---|---|---|
+| K1 | `cfc-langgraph/Dockerfile:39-47` | gunicorn `--worker-class uvicorn.workers.UvicornWorker` + **`--workers 1`** + **`--timeout 7200`**(2 小时)→ 单进程单事件循环;CPU 型任务(ChromaDB / deepface / faster-whisper)阻塞唯一 worker;卡死 worker 2 小时才被回收 |
+| K2 | `cfc-langgraph/start.sh:9` | `--workers 1` 同上 |
+| K3 | `cfc-langgraph/app/main.py`(`schedule_kb_sync`) | 知识库同步任务 `asyncio.create_task` 跑在**与请求同一事件循环** |
+| K4 | `cfc-langgraph/app/main.py` 注释 | 「避免 BaseHTTPMiddleware 消费 body 导致**单 worker 死锁**」—— 团队已认知单 worker 风险,但未解决 |
+| K5 | `cfc-langgraph/app/monitoring.py` | Python 侧**有** Prometheus 指标(llm_duration / rag_duration / agent_duration / java_duration)—— 基础设施具备,但 buckets 上界仅 30/60s,**无法观测 300s 级超时**;Java 侧**无任何 actuator/micrometer**(D1/J1),两侧指标口径断裂 |
+
+### L. 恢复演练 / 故障注入(零证据)
+
+| # | 证据 | 说明 |
+|---|---|---|
+| L1 | `docs/backup/README.md:1-3` | 是**文档归档目录**("存放已被新版本替代的历史需求、设计和计划文档"),**不是数据库备份策略** |
+| L2 | 全仓查找 `mysqldump` / `*backup*.sh` / `*dump*.sql` → **0 命中** | 无数据库备份脚本、无备份保留期、无异地策略 |
+| L3 | 全仓 grep `chaos\|混沌\|故障注入\|failover\|容灾\|灾备\|RTO\|RPO` → **0 命中**(业务语义命中已排除) | **无混沌工程计划、无故障注入记录、无恢复演练记录、无 RTO/RPO 指标** |
+| L4 | `cfc-langgraph/docker-compose.yml` | `mem_limit: 8g` 仅在 langgraph-svc 上;**cfc-backend 无 mem_limit/cpu_limit** |
+| L5 | `service/ReportCollectService.java:135-142` / `:147+` | 异步采集 `taskExecutor.execute(() -> collect(draftId))` —— **无持久化队列**(进程重启任务丢失)、**无重试机制**(一次失败即 `markCollectFailed` 终态)、**无幂等键**(重复提交会重复跑 LLM 并重复计费) |
+
+### M. 既有性能测试资产评估
+
+| # | 证据 | 评估 |
+|---|---|---|
+| M1 | `tests/e2e/api/nonfunc-perf-compat.spec.js` | 全仓**唯一**性能相关资产。**不可用作压测**:① `:18` `BASE` 默认 `http://cfc.iwintrue.com`(**生产共享环境**),`:31-46` 注册函数会在生产**创建真实用户**;② `:81` N=20 并发属微突发,非负载模型;③ `:113` 8s 单请求基线与 `admin.md:114` 的「列表 ≤2s」**自相矛盾**;④ 无分位数、无阶梯加压、无资源采样 |
+| M2 | `tests/e2e/api/nonfunc-perf-compat.spec.js:122-125` | 超卖压测 `test.skip` 并注明「属 execute 档(联网压测),须在用户显式授权且使用专用压测工具/隔离环境后执行,不在共享远端擅自施压」—— **此处纪律正确,应予保留** |
+| M3 | 全仓查找 `*.jmx` / `locustfile.py` / `*k6*` / `*jmeter*` / `*load*test*` / `*stress*`(排除 node_modules) | **0 命中** —— 无任何压测工具链资产 |
+
+---
+
+## 性能测试设计(未实测 · 建议阈值待基线校准)
+
+> ⚠️ **以下所有阈值均为设计建议值,不代表当前系统已达成或不达成。** 当前达成情况**未知**,需在获授权后实测并回填真实基线。
+
+### 场景设计
+
+| # | 场景 | 目标接口 | 负载模型 | 观测指标 | 通过标准(建议阈值,待基线校准) | 所需授权 |
+|---|---|---|---|---|---|---|
+| P1 | **家庭成员列表**(读热路径,压测规格已选) | `POST /api/family/member/list` | 阶梯加压 10→25→50→100 并发,每档 3min 稳态 + 5min 持续 | TP95/TP99、TPS、错误率(5xx)、Hikari active/pending、Tomcat busy threads、CPU/heap | TP95 ≤ 300ms、TP99 ≤ 800ms、错误率 0%、Hikari pending ≤ 5;吞吐随并发线性增长至拐点 | 需授权 + **隔离环境**(禁止默认打生产) |
+| P2 | **健康报告上传→解析**(长链路 + 异步队列积压) | `POST /api/report/upload-only` → `POST /api/report/parse` → `GET /api/report/collect/status` | 1) 上传:10/50 并发,文件 1MB / 20MB / 45MB 三档;2) 持续灌入使 `taskExecutor` 队列达 100 | 上传 TP95/P99、解析端到端 P95、**队列积压深度/消化速率**、堆占用(峰值/OOM)、PDFBox 解析耗时、DB 写入行数 | 上传 TP95 ≤ 8s(20MB)/≤20s(45MB);解析 P95 ≤ 40s(对齐 `cross-role-e2e.md:126`);**积压可消化**(处理速率 > 到达速率);**无 OOM**;熔断打开时降级而非 5xx | 需授权 + 隔离环境 + 专用测试库 |
+| P3 | **AI 对话 / 方案生成**(外部依赖 + 熔断行为验证) | `POST /api/ai/health-coach/send`、`POST /api/ai/plan/generate` | 1) 正常:5/10/20 并发;2) 故障注入:LangGraph 容器停机 / 网络黑洞 / 返回 500 / 返回慢响应(>300s) | AI 调用 TP95/P99、熔断状态迁移日志(开→半开→关)、Fallback 触发率、**熔断打开后无关端点是否被误伤**、Tomcat 线程占用 | 正常态 TP95 ≤ 文档目标(注意 `Dify替代迁移可行性分析.md:483` 的 2s 与实际 30-60s 推理矛盾,**须先重定基线**);故障注入下**故障端点熔断、无关端点不受影响**、系统不返回 5xx 雪崩 | 需授权 + **故障注入必须先在隔离环境演练** |
+| P4 | **运营统计面板**(全表扫描重灾区) | `GET /api/admin/stats/*`(`StatsController.java:535/669/704`) | 单用户 5 并发,**数据集放大到生产量级**(users ≥ 10万、articles ≥ 1万、reading_records ≥ 100万) | 响应 TP95/P99、**SQL 执行计划(是否走索引 / Rows_examined)**、Hikari active、DB CPU、慢查询日志 | 聚合 ≤ 3s(对齐 `admin.md:116`);**`Rows_examined / Rows_sent` ≤ 100×**;**无 `selectList(null)` 全表路径**;DB CPU ≤ 70% | 需授权 + 影子库(**禁止在生产跑全表统计**) |
+| P5 | **活动报名并发不超卖**(已被 skip 的既有用例) | 活动报名接口(`cross-role-e2e.md:128`:100 名额 / 瞬时 500 请求) | 500 并发瞬时 + 100 并发持续 30s | 接受数 vs 名额、重复报名数、DB 行锁等待/死锁数、TP95、错误率 | **不超卖**(接受数 ≤ 100 且 = 100);无重复报名;无死锁;TP95 ≤ 2s;错误率 < 0.1%(限流 429 可接受) | 需授权 + 专用活动夹具 + 隔离环境 |
+| P6 | **限流与熔断边界**(验证 `RateLimitInterceptor`) | `/api/auth/*`(10次/秒/IP)、`/api/auth/send-code`(1次/60秒/IP) | 阶梯 20→50→100→200 并发,同 IP + 多 IP | 429 比例、Redis QPS/延迟、限流误伤率、Redis 故障降级路径 | 超过阈值时 429 比例 ≥ 1;**Redis 宕机时降级到进程内限流且服务不中断**(`RateLimitInterceptor` 已实现,需实测验证) | 需授权 + 隔离环境 |
+
+### 工具选择建议(本地可跑、门槛最低)
+
+| 工具 | 适用 | 理由 | 落地步骤(最小) |
+|---|---|---|---|
+| **k6**(推荐首选) | P1/P4/P5/P6(HTTP 层) | 单二进制、JS 脚本易读、原生 `thresholds` 断言 + `p(95)`/`p(99)` 指标,无需 JVM、CI 好接 | ① `docker run --rm -i grafana/k6 run - < script.js`;② 脚本内置 `stages` 阶梯加压;③ `thresholds: { http_req_duration: ['p(95)<300','p(99)<800'], http_req_failed: ['rate<0.01'] }`;④ 输出 JSON → 归档为基线文件 |
+| **JMeter** `.jmx` | P2(含 multipart 上传) | multipart 文件上传 + 断言 + 报告最成熟,适合 50MB 文件档位 | ① 本地生成 `.jmx`(或 GUI 录制一次);② **`.jmx` 纳入仓库** `cfc-backend/src/perf/`;③ `jmeter -n -t upload.jmx -l result.jtl -e -o report/` |
+| **wrk** / `hey` | 快速摸拐点 | 零依赖、几十秒出结论,适合先定位瓶颈 | `hey -z 60s -c 50 -m POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:9082/api/family/member/list` |
+| **Playwright API**(既有资产) | 仅功能冒烟 + 回归 | **不可作压测**:无阶梯加压、无分位数、无资源采样;且默认 BASE_URL 指向生产 | 保留为冒烟,但**必须显式传 `BASE_URL` 指向本地/隔离环境**,避免生产造数据 |
+| **Java 侧定位** | 瓶颈定位(P4 必备) | 慢查询 + 火焰图 | ① MySQL 开启 `slow_query_log` + `long_query_time=0.5`;② 应用侧 async-profiler 采火焰图;③ MyBatis-Plus 开启 `PerformanceInterceptor` 打印慢 SQL |
+
+### 基线获取方式(统一口径)
+
+1. **环境等价性**:压测环境必须与生产同规格(CPU/内存/DB 版本与规格/索引一致);若不等价,报告中必须标注"环境差异"与"结论不可直接外推"。
+2. **数据集同量级**:users ≥ 生产量级、reading_records ≥ 100万、articles ≥ 1万;**禁止在生产库跑统计类全表查询**。
+3. **预热**:每档压测前 60s 预热(填 JIT + 连接池 + 缓存),预热数据不计入统计。
+4. **重复性**:同场景 **≥3 次独立重复**,取中位数;变异系数 > 10% 判定环境不稳,重测。
+5. **归档**:`perf/baseline/<日期>/<场景>.json`(k6)或 `.jtl`(JMeter)入库,作为回归基线。
+6. **回归门禁**:每次发版跑 P1/P4 冒烟档,与基线对比,**P95 劣化 > 20% 或错误率 > 0.1% 即卡门禁**。
+
+---
+
+## 问题清单(五要素)
+
+### 【P-01|阻断】10 处 HTTP 客户端零超时,下游挂起即拖垮全站
+
+① **问题描述**:`new RestTemplate()` 使用 `SimpleClientHttpRequestFactory` 默认无超时(`connectTimeout`/`readTimeout` 均为 0 = 无限阻塞)。一旦 KnowledgeBase / BodyFatScale / InsurancePolicy / LanggraphSync / Recommendation / VirtualPay / HealthPlan 任一外部依赖无响应,调用线程**永久挂起**,持续占用 Tomcat 工作线程。配合 D2(默认 200 线程)与 B3(180s/300s 读超时),少量慢请求即可耗尽线程池,**全站 502/超时**。这类故障在压测中表现为"TPS 断崖 + 线程数单调上涨不回落"。
+
+② **测试 bug 点**:
+- `service/BodyFatScaleService.java:45`(调用点 `:167`)
+- `service/InsurancePolicyService.java:45`(调用点 `:144`)
+- `service/LanggraphSyncService.java:43`(调用点 `:66`、`:82`)
+- `service/RecommendationService.java:44`(调用点 `:115`)
+- `service/VirtualPayService.java:73`(调用点 `:527`)
+- `service/impl/HealthPlanServiceImpl.java:283`、`:371`、`:1183`
+- `controller/admin/KnowledgeBaseController.java:40`(调用点 `:183`)
+- `controller/admin/KnowledgeBaseVectorController.java:29`(调用点 `:45`/`:61`/`:81`/`:97`/`:126`)
+(以上均已核实文件内无 `setConnectTimeout`/`setReadTimeout`)
+
+③ **最优修改方案**:
+- 全部改为注入 `config/RestTemplateConfig.java:14` 的 `restTemplate` Bean(已有 connect 30s / read 180s),或按需新增 Bean 并显式设超时;
+- `HealthPlanServiceImpl` 的 3 处**方法内 new** 一律改为注入;
+- 支付类(`VirtualPayService`)单独设更短超时(connect 5s / read 15s),失败必须走 fail-safe 而非阻塞;
+- 为每类调用补 `@Test` 断言:注入一个永不响应的 mock server,断言在超时窗口内返回。
+
+④ **修改目的**:达成「故障可隔离」——外部依赖慢/挂不拖垮本服务线程池,全站可用性不依赖单一外部系统。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P3 场景故障注入(mock 下游黑洞)→ 断言请求在超时窗口内返回 503/降级、Tomcat busy threads **不单调上涨**、无 5xx 雪崩。通过标准:全部 10 处调用点具备显式超时且实测超时生效。
+
+---
+
+### 【P-02|阻断】AI 熔断器被 20 个端点共用,且半开态无并发限流
+
+① **问题描述**:`AiGateway` 的熔断状态是**实例级共享字段**(C1)。后果有三:**(a) 误伤** —— `/api/v1/menu/generate` 这类慢推理路径连续 3 次超时即打开熔断,导致完全无关的 `/api/v1/recommend`、`/api/v1/self-check/*` 同时降级为 null(C5);**(b) 掩盖** —— 任一端点成功即把共享计数器清零(C2),使另一个持续失败的端点永远不熔断;**(c) 惊群** —— 半开态无并发探测上限,恢复瞬间所有线程同时打向刚恢复的服务(C3)。此外 2xx 语义异常不计入失败(C4),熔断触发口径不一致。**代码注释与日志宣称"熔断 + 超时 + Fallback",但实现层面不具备端点级隔离能力。**
+
+② **测试 bug 点**:
+- `service/AiGateway.java:70-72`(共享状态字段)
+- `service/AiGateway.java:101-110`(`isCircuitOpen()` 半开逻辑无并发限流)
+- `service/AiGateway.java:162` 等 16 处 `consecutiveFailures.set(0)`(成功即全局清零)
+- `service/AiGateway.java:167`/`:334`/`:364`/`:391`/`:418`/`:448`(2xx 语义异常不 `recordFailure`)
+- 缺失:任何针对熔断状态机的单元测试 / 集成测试(全仓无 `AiGateway` 测试文件)
+
+③ **最优修改方案**:
+- 熔断器**按下游端点(URL path)分桶**:key = `baseUrl + path`,每桶独立 `AtomicInteger` + `circuitOpen` + `lastFailureTime`;
+- 成功时**只清零对应桶**,不再全局清零;
+- 半开态加**单探针令牌**(`AtomicBoolean halfOpenProbeInFlight`),同一时刻只放 1 个请求试探,其余直接走 Fallback;
+- 2xx 语义异常也计入失败(统一口径:只有"可解析且符合契约"才算成功);
+- 补 `AiGatewayCircuitBreakerTest`:① 端点A 连续失败 3 次 → 断言仅 A 熔断、B 仍可调;② 半开态 20 并发 → 断言仅 1 个探针放行;③ 成功 1 次后 → 断言仅对应桶恢复。
+
+④ **修改目的**:达成「故障可隔离、恢复可控」——单端点故障不扩散,恢复不引发惊群。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:单元测试覆盖上述 3 条断言 + P3 场景端到端故障注入。通过标准:端点级隔离测试全绿;故障注入下无关端点成功率 100%。
+
+---
+
+### 【P-03|阻断】后端健康探针指向不存在的 `/actuator/health`,恒判 unhealthy
+
+① **问题描述**:`pom.xml` 无 `spring-boot-starter-actuator`,`application.yml` 无 `management:` 配置,且**只有单一 profile 文件**(无 application-prod.yml)→ 后端**不存在 `/actuator/health` 端点**。而 `docker-compose.yml` 把 `cfc-backend` 的 healthcheck 配成 `curl -f http://localhost:9082/actuator/health` → **该探针 100% 失败**,容器恒为 unhealthy。在 Docker Compose 下不会自动重启,但在任何按 readiness 摘流量的编排层,**后端会被持续判死并摘出负载均衡**,且因 Java 侧无 actuator/micrometer(K5),**无任何指标可供旁证健康状态**。叠加 J3(`cfc-backend/Dockerfile` 不存在但 compose 引用它),部署链路本身即不自洽。
+
+② **测试 bug 点**:
+- `cfc-backend/pom.xml`(缺 `spring-boot-starter-actuator`)
+- `cfc-backend/src/main/resources/application.yml`(缺 `management.endpoints.web.exposure.include: health`)
+- `cfc-langgraph/docker-compose.yml` cfc-backend 服务 `healthcheck.test` 段
+- `cfc-langgraph/docker-compose.yml` cfc-backend `build.dockerfile` 段(引用不存在的 Dockerfile)
+- `cfc-langgraph/app/api/health.py`(Python 侧 health 恒 200,不反映依赖)
+
+④ **最优修改方案**:
+- 补 `spring-boot-starter-actuator` 依赖 + 配置 `management.endpoints.web.exposure.include: health,info,metrics,prometheus`;
+- health 端点暴露 DB / Redis 健康明细(`management.endpoint.health.show-details: when_authorized`);
+- 补 `cfc-backend/Dockerfile`(或改 compose 改用 `start.sh` + 基础镜像),使 compose 可构建;
+- Python 侧 `/health` 改为**依赖感知**:探测 ChromaDB 路径可读、SQLite checkpointer 可写、LLM 网关可达,任一不可用返回 503;
+- 加 `HEALTHCHECK` 到后端镜像。
+
+③ **最优修改方案**(同上,此处为动作清单)
+
+④ **修改目的**:达成「就绪状态可观测、故障可被编排层正确处置」——避免健康探针恒失败导致误摘流量 / 误重启。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:`curl -f http://localhost:9082/actuator/health` 返回 200 且 `status=UP`;`docker compose ps` 两个服务均 healthy;**故意停掉 MySQL 后 health 返回 DOWN**(证明探针真实有效,而非恒 200)。通过标准:健康检查随依赖真实翻转。
+
+---
+
+### 【P-04|严重】启动期 320 条 ALTER TABLE 无版本管理,大表上阻塞写入
+
+① **问题描述**:每次应用启动都全量重放 320 条 `ALTER TABLE`(含 23 条 `ADD INDEX`)+ 335 条 `CREATE TABLE`,**无 Flyway/Liquibase 版本表**,无 checksum,无幂等保证。`ADD INDEX` 在 MySQL 是 INPLACE 算法重建索引,**对大表会持有元数据锁并阻塞读写**;多实例同时发布时争抢同一批锁,可能触发 `Lock wait timeout`。且每条 DDL 独立 try/catch 吞异常 —— **迁移失败静默**,应用照常启动,线上带着"半迁移"状态运行。`MODIFY COLUMN`(43 条)在部分场景会触发表重建(copy algorithm),风险更高。
+
+② **测试 bug 点**:
+- `config/DatabaseInitializer.java:66`(启动期调用 `runMigrations()`)
+- `config/DatabaseInitializer.java:155` 起 **320 条 ALTER TABLE**(如 `:158` ADD COLUMN tasks、`:172` ADD INDEX idx_executor、`:237` ADD INDEX idx_phone、`:244`/`:252` MODIFY COLUMN users.role)
+- `config/DatabaseInitializer.java:143`(建表异常静默 `log.warn`)
+- `cfc-backend/pom.xml`(缺 flyway-core / liquibase-core)
+
+③ **最优修改方案**:
+- 引入 **Flyway**:`flyway-core` 依赖 + `db/migration/V<n>__<desc>.sql` 版本化脚本;`DatabaseInitializer` 降级为仅做 `CREATE DATABASE IF NOT EXISTS`,**迁移全部交给 Flyway**(启动时自动执行,带 `flyway_schema_history` 版本表,重复执行自动跳过);
+- 迁移期用 `flyway.lock-retry-count` 应对多实例并发;
+- 存量 320 条 ALTER 一次性转成 baseline 脚本(`flyway baselineOnMigrate=true` + baseline version),后续新增一律走版本脚本;
+- 大表 DDL 显式加 `ALGORITHM=INPLACE, LOCK=NONE`(不在线则安排低峰窗口);
+- **迁移必须失败即启动失败**(不允许静默 continue)。
+
+④ **修改目的**:达成「发布可预期、数据结构可追溯、迁移不阻塞线上写入」。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:① 连续启动两次,第二次日志显示"无待执行迁移"且耗时 < 5s;② 在影子库对**生产量级**表集执行迁移全量,实测总耗时与锁等待(`SHOW PROCESSLIST` / `performance_schema.metadata_locks`);③ 故意写一条错误迁移 → 断言应用**启动失败**而非静默通过。通过标准:迁移幂等 + 失败可见 + 影子库迁移总耗时 ≤ 60s 且锁等待为 0。
+
+---
+
+### 【P-05|严重】异步采集任务无持久化、无重试、无幂等,且队列打满时反压到 HTTP 线程
+
+① **问题描述**:`submitAsyncCollect` 用 `taskExecutor.execute()` 提交到**内存线程池**(`AsyncConfig` core 8 / max 16 / queue 100),**无持久化队列** → 进程重启/发布时在途任务全部丢失;`collect()` **无重试**(一次失败即 `markCollectFailed` 终态,用户只能重传);**无幂等键** → 用户重复点击"开始解析"会重复触发 LLM 调用与重复计费。更严重的是 `AsyncConfig.java:23` 配置了 `CallerRunsPolicy` —— **队列满时由提交任务的 HTTP 请求线程代跑整个采集流程**(含最长 300s 的 LLM 调用),导致该 HTTP 请求同步阻塞 300s,同时占住一个 Tomcat 线程。这是典型的"反压策略选错",把异步的积压转嫁为同步的请求悬挂。
+
+② **测试 bug 点**:
+- `service/ReportCollectService.java:135-142`(`taskExecutor.execute`,无持久化/无重试)
+- `service/ReportCollectService.java:147+`(`collect()` 无重试循环、失败即终态)
+- `config/AsyncConfig.java:18-23`(core 8 / max 16 / queue 100 / **`CallerRunsPolicy`**)
+- `config/AsyncConfig.java:28-35`(`taskScheduler` poolSize 4,所有定时任务共用)
+- 缺失:无 `ReportCollectService` 的失败重试/幂等单元测试;无队列积压场景测试
+
+③ **最优修改方案**:
+- 拒绝策略改为 `AbortPolicy`(**绝不让请求线程代跑**),并对提交失败返回明确错误 + 补偿(用户侧可重试);
+- 引入**持久化任务表**(`report_collect_task`:`draft_id` 唯一索引作幂等键、状态机 `PENDING/RUNNING/FAILED/SUCCEEDED`、`retry_count`、`next_retry_at`、`last_error`),由定时扫描器认领(`SELECT ... FOR UPDATE SKIP LOCKED` 或乐观锁 CAS 认领);
+- 补**指数退避重试**(如 3 次,间隔 1s/5s/30s)+ 死信状态;
+- `draft_id` 加唯一约束实现幂等,重复提交直接返回已有任务;
+- 补队列深度指标(Micrometer Gauge `report.collect.queue.depth`),暴露给 P2 场景观测;
+- 补单测:① 重复提交同一 draftId → 只产生 1 次 LLM 调用;② LLM 连续失败 → 断言重试 3 次后进死信并标记失败原因;③ 队列满 → 断言**提交方线程不执行任务体**(请求快速返回 429/503)。
+
+④ **修改目的**:达成「异步任务不丢、可重试、可去重、积压不反压用户请求」。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P2 场景灌满队列 → 断言请求延迟不随队列深度线性增长、上传接口 P95 保持 ≤ 8s;重启进程 → 断言在途任务被恢复执行;重复提交 → 断言 LLM 调用计数为 1。通过标准:三类断言全绿。
+
+---
+
+### 【P-06|严重】N+1 与全表扫描集中在统计与营养过滤热路径
+
+① **问题描述**:`selectList(null)`(无条件全表)共 40 处,其中**热路径**上的包括:统计面板拉全量文章(`StatsController.java:535`)与全量用户(`:669`);营养推荐循环内每次全表拉药品相互作用(`HealthFilterService.java:217`)与疾病限量表(`:245`,被 `BeijingNutritionService.java:714` 在**循环内**调用 → N× 全表扫);全表食材(`BeijingNutritionService.java:82`/`:708`、`HealthReportService.java:2467`)。同时存在 N+1:`StatsController.java:704` 在 `forEach` 内逐个 `productMapper.selectById(pid)`。`MyBatisPlusConfig.java:16` 虽已注册分页插件,但这些路径**完全绕过分页**。数据量到十万级时,统计接口会直接把 DB CPU 打到 100% 并拖垮同库所有业务查询。
+
+② **测试 bug 点**:
+- `controller/stats/StatsController.java:535`、`:669`、`:704`
+- `service/HealthFilterService.java:217`、`:245`、`:263`
+- `service/BeijingNutritionService.java:82`、`:708`、`:714`
+- `service/HealthReportService.java:2467`
+- `service/BeijingNutritionService.java:647`(循环内 `dietPreferencesMapper.selectOne`)
+- 缺失:无慢 SQL 断言测试;无 `Rows_examined` 断言
+
+③ **最优修改方案**:
+- 统计类全表查 → 改**只查所需 ID 集合**(`selectBatchIds` / `IN` 子查询)或引入**聚合表 + 定时预计算**(`@Scheduled` 增量更新,读侧零查询);
+- 标题映射类需求(`:535`/`:669`)→ 用 `selectObjs("id","title")` 只取两列,或对 hot-path 做 Redis 缓存(G2 缓存基础设施已就绪);
+- `HealthFilterService` 的药品/疾病规则表 → **启动期加载进内存 + 变更时失效**(参考 `config/CfConfigCache.java` 模式),或用 `selectBatchIds` 限定候选;
+- `BeijingNutritionService.java:714` 的循环内调用 → **循环外一次性预取**规则集,循环内纯内存判断;
+- `StatsController.java:704` → 改 `productMapper.selectBatchIds(pidSet)` 批量取;
+- 所有 `selectList(null)` 逐个审计并改为带条件查询。
+
+④ **修改目的**:达成「容量可规划、热点路径不随数据量线性劣化」——统计与推荐接口的耗时应与数据量解耦。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P4 场景在生产量级影子库执行 → 断言 TP95 ≤ 3s、**慢查询日志无 `selectList(null)` 产生的全表扫描**、`Rows_examined/Rows_sent ≤ 100×`、DB CPU ≤ 70%。同时补回归守卫:静态扫描脚本(CI 内跑)禁止新增 `selectList(null)`,命中即失败。
+
+---
+
+### 【P-07|严重】PDF 上传解析全链路同步占用请求线程,50MB 上限下有 OOM 风险
+
+① **问题描述**:`POST /api/report/upload`(`HealthReportController.java:818`)在**单个 HTTP 请求内同步完成**:PDFBox `PDDocument.load` 全量读入堆(`PdfParseService.java:126`)→ 建报告 → 建指标/菌群/疾病风险 → 落 payload 快照 → 存食材 → 7 维评分刷新(`:874`)→ 食材推荐指数重算(`:880`)。50MB 上限下 PDFBox 解析的堆占用可达文件数倍,而 `start.sh` 只给 2GB 堆。并发几个 45MB 上传即可触发 OOM。同时 `AiGateway.java:706-777` 把音频/图片读成 `byte[]` 再 multipart 外发,堆内双份占用。**大文件上传 + 同步长任务 = 典型的资源耗尽型可靠性缺陷。**
+
+② **测试 bug 点**:
+- `cfc-backend/src/main/resources/application.yml:16-17`(`max-file-size: 50MB` / `max-request-size: 50MB`)
+- `service/PdfParseService.java:125-132`(`PDDocument.load(inputStream)` 同步全量入堆)
+- `controller/HealthReportController.java:836`、`:874`、`:880`(请求线程内同步串行执行)
+- `service/AiGateway.java:706-734`、`:741-777`、`:785-811`(`byte[]` 全量读入)
+- `cfc-backend/start.sh:47-52`(`-Xmx2g`)
+- 缺失:无大文件上传的内存/并发压测用例(`admin.md` 里有"大文件"前置条件,但 `nonfunc-perf-compat.spec.js` 未覆盖)
+
+③ **最优修改方案**:
+- 上传接口**只做落盘 + 建 draft + 立即返回 draftId**(项目已有 `/report/upload-only` 两阶段接口 `:912`,应**统一收敛到该路径**,把 `/report/upload` 标 `@Deprecated` —— `:1304` 已有此注释);
+- 解析全部走异步(并复用 P-05 的持久化任务表);
+- `PDDocument.load` 改为**流式/分页解析**,或移到独立解析进程/线程池,设独立堆上限;
+- `max-file-size` 下调至业务真实需要(健康报告 PDF 通常 < 10MB),并加**按端点**的上传限制;
+- `AiGateway` 的 multipart 改为**流式传递**(`InputStreamResource`)避免 `byte[]` 全量驻留;
+- 上传接口加**并发闸门**(Semaphore)与每用户上传频率限制。
+
+④ **修改目的**:达成「大文件上传不拖垮内存、不拖垮请求线程、失败可恢复」。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P2 场景 45MB 文件 × 10 并发上传 → 断言上传接口 P95 ≤ 20s、**堆峰值 < 1.2GB 且无 Full GC 风暴**、解析走异步(上传返回 draftId 而非完整报告)、OOM 次数为 0。通过标准:内存与延迟双达标。
+
+---
+
+### 【P-08|严重】AI 服务 gunicorn 单 worker + 2 小时超时 + 事件循环内同步阻塞
+
+① **问题描述**:`Dockerfile:42-43` 配置 `--workers 1` + `--timeout 7200`。后果:① **单事件循环** —— 任一 CPU 型任务(ChromaDB 向量检索、deepface 情绪识别、faster-whisper 语音转写)阻塞唯一 worker,**整个 AI 服务对所有用户不可用**(不是变慢,是全挂);② **超时 7200s** —— worker 卡死后 gunicorn 要 2 小时才回收,期间该实例持续不可用;③ `app/main.py` 的 `schedule_kb_sync` 知识库同步任务与请求共用同一事件循环;④ `src/graphs/emotion.py:60` 在 async 函数里用同步 `requests.get` —— **确定性的事件循环阻塞**;⑤ `app/main.py` 注释自述"避免单 worker 死锁",说明团队已认知该风险但未解决。同时 `cfc-langgraph/docker-compose.yml` 只给 langgraph-svc 设了 `mem_limit: 8g`,**cfc-backend 无内存/CPU 限制**,无横向扩容能力(单实例单 worker)。
+
+② **测试 bug 点**:
+- `cfc-langgraph/Dockerfile:39-47`(`--workers 1`、`--timeout 7200`)
+- `cfc-langgraph/start.sh:9`(`--workers 1`)
+- `cfc-langgraph/src/graphs/emotion.py:60`(同步 `requests.get`)
+- `cfc-langgraph/app/main.py`(`schedule_kb_sync` 与请求同循环;BaseHTTPMiddleware 死锁注释)
+- `cfc-langgraph/docker-compose.yml`(cfc-backend 无 `mem_limit`/`cpu_limit`,无 replicas)
+- `cfc-langgraph/app/monitoring.py`(histogram buckets 上界 30/60s,**观测不到 300s 级长尾**)
+- 缺失:无 AI 服务的并发/饱和测试,无「某请求卡死是否影响其他请求」的隔离性测试
+
+③ **最优修改方案**:
+- gunicorn `--workers` 提到 **2~4**(按 CPU 核数),或改用 **uvicorn 多进程 + `--timeout 90~180`**(远小于 7200);
+- **CPU 型任务隔离**:deepface / whisper / ChromaDB 检索移出事件循环(`run_in_threadpool` 或独立 worker 队列);
+- `src/graphs/emotion.py:60` 改 `httpx.AsyncClient`;
+- `schedule_kb_sync` 移到独立进程/线程,避免与请求争抢;
+- `mem_limit`/`cpu_limit` 补到 cfc-backend;
+- monitoring 的 histogram buckets 补上 120s/300s/600s 桶,否则 P99 观测失真;
+- `app/api/health.py` 改为依赖感知(见 P-03)。
+
+④ **修改目的**:达成「AI 服务不被单个慢请求拖垮、故障实例可快速摘除、容量可横向扩展」。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P3 场景 + 隔离性专项:① 发起 1 个慢请求(mock LLM 挂起 120s),断言**同时其它端点请求仍正常返回**(隔离性);② 断言 gunicorn 在超时阈值内回收僵死 worker;③ 断言 workers ≥ 2 时单 worker 被压满不影响整体可用性。通过标准:隔离性测试全绿 + 僵死 worker 回收时长 ≤ 180s。
+
+---
+
+### 【P-09|严重】性能阈值互相矛盾且与实现不符,无容量结论
+
+① **问题描述**:性能目标散落且互相打架:可执行规格写"家庭列表 ≤ 8s"(`nonfunc-perf-compat.spec.js:113`),项目自有文档写"配置列表 ≤ 2s"(`admin.md:114`)、"统计聚合 ≤ 3s"(`admin.md:116`)、"报告链路 P95 ≤ 40s"(`cross-role-e2e.md:126`),而架构文档写"`POST /api/ai/chat/send` ≤ 2s (P95)"(`Dify替代迁移可行性分析.md:483`)—— 但该链路实际 LLM 推理 30-60s(`application.yml:131-132` 注释自述),**2s 目标不可能达成,属未经验证的拍脑袋数字**。同时**全仓无任何容量测算**("当前容量能支撑多少并发/用户/日请求量"),无扩容阈值、无资源水位线、无 RTO/RPO。这使得"系统撑不撑得住"这一问题**在当前状态下无法回答**。
+
+② **测试 bug 点**:
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:113`(8s 基线)
+- `tests/test-cases/admin.md:114`、`:115`、`:116`
+- `tests/test-cases/cross-role-e2e.md:126`、`:128`、`:129`
+- `docs/architecture/Dify替代迁移可行性分析.md:483`(2s P95,与实现矛盾)
+- `docs/architecture/2026-07-20-SB3-upgrade-plan.md:858`(P50/P95/P99 采集步骤全未勾选)
+- 缺失:`docs/` 下无 SLO 文档、无容量规划文档
+
+③ **最优修改方案**:
+- 新建 `docs/performance/SLO.md`(唯一真源),结构化定义:**每个关键接口的 P95/P99 目标 + 目标并发数 + 目标 QPS + 错误率 SLO + 降级策略**;
+- **先实测后定标**:对 P1~P6 场景跑基线,用实测 P95×2 作为初始目标,再逐步收紧;把 `Dify替代迁移可行性分析.md:483` 的 2s 修正为与推理耗时一致的值(并标注该口径为"LLM 端到端"而非"网关响应");
+- 统一 `admin.md`/`cross-role-e2e.md`/`nonfunc-perf-compat.spec.js` 三处口径,**以 SLO.md 为准**,其余文档引用而非复写;
+- 补容量规划章节:`当前 2C4G × N 实例 + Hikari 50 × N` 可支撑 **X 并发 / Y QPS**,扩容触发线(水位 70%)与扩容动作;
+- 把 `nonfunc-perf-compat.spec.js` 的 8s 改为对齐 SLO,并改名为显式的"功能冒烟基线"(避免与 SLO 混淆)。
+
+④ **修改目的**:达成「阈值有据可依、口径统一、容量可规划」——让"撑不撑得住"变成可计算的问题。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:P1~P6 实测 → 用实测值回填 SLO.md → 断言 SLO.md 中每个阈值都能追溯到某次压测报告(链接归档)。通过标准:SLO.md 覆盖率 100%(所有关键接口有阈值 + 有对应压测报告链接)。
+
+---
+
+### 【P-10|一般】Redis 连接池配置静默失效,且限流器在每请求路径上
+
+① **问题描述**:`application.yml:37-41` 配了 `lettuce.pool.max-active: 8 / max-idle: 8 / min-idle: 0`,但 `pom.xml:102` 只有 `spring-boot-starter-data-redis`,**无 `commons-pool2`**(本地 `.m2` 亦无该 artifact)→ Spring Boot 的 `LettuceConnectionConfiguration` 在无 commons-pool2 时**不会创建池化 ClientResources**,改为使用**共享连接**,**这组 pool 配置完全不生效**。运维会误以为存在 8 连接的上限(实际无上限)。此外 `RateLimitInterceptor.java:34/128` 让**每个 HTTP 请求都执行一次 Redis Lua 脚本**,Redis 抖动(`timeout: 3000ms`)会直接放大为全站 3s 级延迟 —— 虽然 `:44-48` 已实现 Redis 不可用时降级到进程内限流,但该降级路径**从未被演练过**。
+
+② **测试 bug 点**:
+- `cfc-backend/src/main/resources/application.yml:37-41`(失效的 lettuce pool 配置)
+- `cfc-backend/pom.xml:102`(缺 `commons-pool2`)
+- `config/RateLimitInterceptor.java:34`、`:128`(每请求 Redis 调用)
+- `config/RateLimitInterceptor.java:44-48`(Redis 故障降级到进程内限流,**无测试覆盖**)
+- `config/RedisConfig.java`(缓存基础设施就绪但几乎未启用,见 G2)
+
+③ **最优修改方案**:
+- 二选一并明确:**加 `commons-pool2` 依赖**让池配置真实生效(并按 Tomcat 线程数重设 max-active,如 32~64),**或删除这组误导性配置**并显式注释"未启用连接池,使用共享连接";
+- 高频只读对象(能量配置、任务模板、徽章定义、会员等级、文章元数据)用 `RedisConfig` 的 CacheManager 加 `@Cacheable`(基础设施已就绪,见 G2),降低 DB 与 Redis 双压;
+- 补 **Redis 宕机降级演练**:停 Redis → 断言服务不中断、限流仍生效(进程内)、降级日志可观测。
+
+④ **修改目的**:达成「配置真实有效、限流不成为单点、缓存真正降载」。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:① 停 Redis → 断言接口可用、限流仍生效;② 恢复 Redis → 断言缓存与限流回正常;③ 断言连接池实际连接数符合配置(Redis `CLIENT LIST`)。通过标准:配置生效可观测 + 降级路径演练通过。
+
+---
+
+### 【P-11|一般】无备份脚本、无恢复演练、无故障注入记录,恢复能力不可证实
+
+① **问题描述**:`docs/backup/` 是**文档归档目录**(README 明言"存放已被新版本替代的历史需求、设计和计划文档"),**不是数据备份策略**。全仓无 `mysqldump` / 备份 shell / 定时备份配置 / 备份保留期策略;无任何恢复演练记录;grep `chaos|混沌|故障注入|failover|容灾|灾备|RTO|RPO` **零命中**。同时 `docker-compose.yml` 只给 langgraph-svc 设了 `mem_limit: 8g`,cfc-backend 无资源上限。**"有备份"都不成立,更谈不上"有恢复演练"** —— 一旦 DB 损坏或误删表,历史数据不可恢复,本项目无任何证据表明具备恢复能力。
+
+② **测试 bug 点**:
+- `docs/backup/README.md:1-3`(性质为文档归档,非备份策略)
+- 全仓无 `*backup*.sh` / `*dump*.sql` / `mysqldump` 调用
+- 无 `docs/operations/` 或等价的备份与恢复 SOP 目录
+- `cfc-langgraph/docker-compose.yml`(cfc-backend 无 `mem_limit`/`cpu_limit`;langgraph-svc 有 `mem_limit: 8g` 但无 `deploy.resources` 副本数)
+
+③ **最优修改方案**:
+- 编写 `scripts/backup/backup-mysql.sh`(`mysqldump` + gzip + 日期归档 + 保留期清理 + **校验和**)+ `scripts/backup/restore-mysql.sh`(**必须带 dry-run 与校验**);
+- 明确备份目标位置(异地对象存储,不与生产同机)、保留期(如日/周/月)、与业务窗口的错峰;
+- 定义并写入 RTO/RPO(如 RTO ≤ 4h、RPO ≤ 24h),并据此设计演练频率;
+- 建立 `docs/operations/DR.md`(故障处置 SOP:DB 故障、Redis 故障、LangGraph 故障、磁盘满、OOM);
+- **做一次真实恢复演练并留档**(这是最关键的一条 —— 未演练的备份等于没有备份);
+- 补故障注入基线:LangGraph 停机/超时/返回 500、Redis 停机、MySQL 主从切换、磁盘写满。
+
+④ **修改目的**:达成「故障可恢复、恢复能力可证实」——用一次成功的恢复演练证明数据可回来。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:在影子环境执行"备份 → 破坏 → 恢复"闭环 → 断言恢复后表行数与关键业务数据一致(RTO 实测值记录)。通过标准:**完成 ≥ 1 次有留档的恢复演练**,恢复数据抽样一致率 100%,实测 RTO 满足声明值。
+
+---
+
+### 【P-12|一般】既有性能测试资产不可用作压测,且默认指向生产
+
+① **问题描述**:`tests/e2e/api/nonfunc-perf-compat.spec.js` 是全仓唯一的性能相关资产,但:① `:18` `BASE_URL` **默认 `http://cfc.iwintrue.com`(生产共享环境)**,`:31-46` 的 `register()` 会在生产**创建真实用户**(`/api/auth/direct-register`),每次跑都污染生产数据;② `:81` 的 N=20 并发属**微突发**,非负载模型;③ `:113` 只有 8s 单请求基线,无分位数、无阶梯加压、无资源采样;④ Playwright 的 `request` fixture **不是压测工具**,无法产出吞吐/分位数曲线。全仓**无 .jmx / locustfile.py / k6 脚本 / wrk 配置**。值得肯定的是 `:122-125` 的超卖压测明确 `test.skip` 并注明"属 execute 档,须在用户显式授权且使用专用压测工具/隔离环境后执行"——**该纪律应予保留并推广**。
+
+② **测试 bug 点**:
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:18`(BASE_URL 默认生产)
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:31-46`(注册函数在生产造数据)
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:79-90`(N=20 微突发,非负载)
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:106-114`(8s 单请求基线,无分位数)
+- `tests/e2e/api/nonfunc-perf-compat.spec.js:122-125`(已 skip,需夹具与授权 —— 保留此纪律)
+- 全仓无 `.jmx` / `locustfile.py` / k6/wrk 资产
+
+③ **最优修改方案**:
+- **保留**该文件作为"功能+兼容性冒烟",但:
+  - 移除 `BASE_URL` 的生产默认值,改为**无 `BASE_URL` 直接报错退出**(强制显式指定环境);
+  - 在 `playwright.config.api.js` 加环境守卫(目标 host 命中生产域名 → 拒绝执行,除非显式 `--allow-prod`);
+  - 注册函数改为使用**专用测试账号前缀 + 后台清理钩子**(`test.afterAll` 清理),不再每次造新用户;
+- **新建 `perf/` 目录并纳入仓库**(这是本次最重要的补齐):
+  - `perf/k6/` —— P1/P4/P5/P6 脚本(含 `stages` 阶梯加压 + `thresholds` 断言)
+  - `perf/jmeter/` —— P2 上传脚本(`.jmx`)
+  - `perf/README.md` —— 工具选择、最小落地步骤、环境搭建、基线归档规范
+  - `perf/baseline/` —— 历史基线 JSON/JTL(回归对比用)
+- 提供 `perf/run.sh`:一键起本地环境(docker-compose 隔离栈 + 造数脚本)→ 跑 k6/JMeter → 输出对比报告。
+
+④ **修改目的**:达成「压测可复跑、可回归、有基线对照」——把性能从"每次重写脚本"变成"仓库资产 + 一键复跑"。
+
+⑤ **修改后能否做问题闭环**:**能**。复测:`bash perf/run.sh` 在隔离环境一键跑完 P1~P6 并产出报告;断言报告含 P95/P99/错误率/资源曲线,且与 `perf/baseline/` 中历史基线自动对比、劣化超阈值即非零退出(可直接接 CI 门禁)。通过标准:一键复跑成功 + 报告字段齐全 + 回归对比生效。
+
+---
+
+## 未实测项(明确声明)
+
+### A. 「未授权未执行」—— 因主理人未获联网授权,本次一律未执行
+
+| 项 | 状态 | 说明 |
+|---|---|---|
+| A1 | **未授权未执行** | 对生产 `http://cfc.iwintrue.com` 的任何压测/流量 |
+| A2 | **未授权未执行** | JMeter / k6 / Locust / wrk 打真实服务(含本地起服务的压测脚本执行) |
+| A3 | **未授权未执行** | AI 服务 `ai.etotem.com.cn` 的负载施压 |
+| A4 | **未授权未执行** | 故障注入(停 LangGraph 容器 / 停 Redis / 停 MySQL / 网络黑洞 / 慢响应注入) |
+| A5 | **未授权未执行** | 恢复演练(备份→破坏→恢复闭环)—— 会写/删数据,风险最高 |
+| A6 | **未授权未执行** | P1~P6 全部 6 个性能场景的实际执行 |
+
+### B. 「未实测」—— 本次全部为静态代码/配置审查,无任何运行时数据
+
+| 项 | 状态 | 说明 |
+|---|---|---|
+| B1 | **未实测** | 任何接口的真实 P95 / P99 / TPS / 错误率 —— **本报告不含任何实测性能数字** |
+| B2 | **未实测** | 当前系统的容量上限(能支撑多少并发 / QPS / 用户量)—— **无法回答"撑不撑得住"** |
+| B3 | **未实测** | 熔断器在真实故障下的状态迁移与端点间隔离行为(结论基于读码,非实测) |
+| B4 | **未实测** | 300s 读超时下 Tomcat 线程耗尽的实际发生点与恢复时间 |
+| B5 | **未实测** | 50MB PDF 并发上传的实际堆峰值与 OOM 触发条件 |
+| B6 | **未实测** | 320 条 ALTER TABLE 在生产量级表上的实际耗时与锁等待时长 |
+| B7 | **未实测** | ChromaDB 向量检索 / deepface / whisper 的实际 CPU 占用与事件循环阻塞时长 |
+| B8 | **未实测** | Redis 连接池的真实连接数(因 `commons-pool2` 缺失,配置推断为不生效,未运行时验证) |
+| B9 | **未实测** | `/actuator/health` 的实际响应(经依赖与配置判定为不存在,未发请求验证) |
+| B10 | **未实测** | `selectList(null)` 全表查询在生产量级下的真实耗时(依赖数据规模推断风险,未连生产库) |
+| B11 | **未实测** | 91 处 `.like()` 的实际执行计划与索引命中(需 `EXPLAIN`,未连生产库) |
+| B12 | **未实测** | Hikari 50 / Tomcat 200 / Lettuce 无池 三者组合的实际排队行为 |
+
+### C. 本报告结论的适用边界
+
+- 所有风险点均为**代码与配置层面的静态判定**,标注行号均可复核;其中 B3、B8、B9、B10、B11 依赖"依赖未引入 / 配置未生效"的推断,**建议在获授权后用运行时手段二次确认**(`docker exec` 查依赖树、`EXPLAIN` 查执行计划、`curl` 查端点)。
+- 「性能测试设计」中的全部阈值为**建议值**,须在 P1~P6 实测后回填校准,**不得直接作为验收标准使用**。
+- 本次**未修改任何代码**,所有"最优修改方案"均为建议,未实施。
+
+---
+
+## 附:与既有资产的协作建议(供主理人汇编时参考)
+
+- **P-12 与白樾的 E2E 资产盘点有重叠**:`nonfunc-perf-compat.spec.js` 的环境守卫改造建议已同步,建议由 E2E 域统一落地环境守卫规则,避免两套。
+- **P-09 的 SLO 文档** 建议由主理人指定单一 owner 维护,避免与 `admin.md` / `cross-role-e2e.md` 三处口径继续分叉。
+- **P-02 的熔断器测试** 属单元级,但因涉及并发状态机,建议纳入苏雅的单元测试覆盖台账(单测即可闭环,不必等压测授权)。

+ 85 - 0
docs/tdd/test/red-task-investigation.md

@@ -0,0 +1,85 @@
+# RED 任务真实现状核查与契约测试设计(2026-11-02)
+
+> 生成方式:只读核查 + 本地状态修改(`state.json` 新增 `investigation` 证据字段,**stage 维持 RED,未推送远端**)。
+> 范围说明:本环境无 `mvn`/`mvnw`(后端单测无法执行),且本次未授权联网装依赖 / 推送远端,故「实际测试工作」以**契约测试设计 + 现状核查 + 状态修改**形式交付;不谎报"已通过"。
+
+## 一、执行范围与约束
+
+| 项 | 状态 | 说明 |
+|---|---|---|
+| 后端 `mvn test` | ✗ 不可执行 | 全机无 maven,且 188 个测试为 `@SpringBootTest` 需连库 |
+| Playwright e2e | ◐ 需授权 | CLI 在(v1.64.1)但浏览器未下载,真跑需 `npx playwright install` |
+| langgraph pytest | ◐ 需授权 | 有 `test_*.py` 但无 venv/依赖,需 `pip install` |
+| 本地状态修改 | ✓ 已完成 | `state.json` 已更新 `investigation`;侧车 951 条(16 通过/4 失败/931 未跟踪) |
+| 推送远端 | ✗ 未授权 | 未 push `origin/cfclub`,closed-loop 证据暂不闭环 |
+
+## 二、2 个 RED 任务真实现状核查(只读证据)
+
+### 2.1 `health.report.createReport`
+- **实现存在**:`cfc-backend/src/main/java/com/etotem/cfc/controller/HealthReportController.java:219`
+  `@PostMapping("/report/create")` → `public Result<HealthReport> createReport(...)`
+- **契约测试缺失**:仓库内 2 个相关测试
+  `HealthReportControllerProxyParseBindingTest`、`HealthReportControllerListPaginationTest`
+  经 grep 确认**均不覆盖** `createReport`/`/report/create`。
+- **判定**:RED 确证(实现在,目标端点无契约级单测)。
+
+### 2.2 `dan.assessment.getActiveMaterial`
+- **实现存在**:`cfc-backend/src/main/java/com/etotem/cfc/controller/DanAssessmentController.java:65`
+  `@PostMapping("/material/active")` → `public Result<AssessmentMaterial> getActiveMaterial()`
+- **契约测试缺失**:`src/test/java` 下**无任何** `DanAssessmentController` 测试文件(grep 命中 0)。
+- **判定**:RED 确证(实现在,控制器零测试)。
+
+> 结论:两个任务均处于「实现已完成、测试待写」的 RED 态,符合 TDD 状态机(RED=测试待写)。
+> 二者**不需要**开发角色做 YELLOW(实现使绿),而需要**测试角色补 RED 契约测试并验证**。
+
+## 三、状态修改记录(本地,未推送)
+
+`d:/cfc/.tdd/state.json` 已为两任务新增 `investigation` 字段:
+- `impl_exists: true` / `impl_ref`(精确 file:line)
+- `contract_test_exists: false` / `existing_tests_cover_target: false`
+- `verdict` / `next`(后续动作)
+- `stage` 维持 `RED`,`updated` 刷新为 `2026-11-02 11:48:00`。
+
+## 四、「实际测试工作」交付物:契约测试设计(可直接落码)
+
+遵循项目约定:统一 `@PostMapping`、响应 `Result<T>`(code/message/data)、`JwtInterceptor` 鉴权(`Authorization` 头)、测试用 `MockMvc`(与现有 188 个测试一致)。
+
+### TC-R1 · `POST /api/health/report/create`
+测试类:`HealthReportControllerCreateReportTest`(建议置于 `cfc-backend/src/test/java/com/etotem/cfc/controller/`)
+
+| 用例 | 构造 | 断言 |
+|---|---|---|
+| R1-1 正常创建 | 合法 `HealthReport` + 指标列表,带有效 JWT | `code==200`、返回 `data.id` 非空、`healthReportService.createReport` 被调用 1 次 |
+| R1-2 参数缺失 | `report` 为 null 或必填字段缺 | 全局异常拦截返回 400 + 具体字段提示(非裸 500) |
+| R1-3 鉴权缺失 | 不带 `Authorization` | 401,跳转登录(8 个公开路径之外) |
+| R1-4 并发/幂等 | 同请求重复提交 | 依据业务是否要求幂等断言(创建成功或明确拒绝) |
+
+Mock 点:`healthReportService.createReport(...)` 用 `Mockito.when(...).thenReturn(...)` 隔离 DB。
+
+### TC-R2 · `POST /api/dan-assessment/material/active`
+测试类:`DanAssessmentControllerGetActiveMaterialTest`
+
+| 用例 | 构造 | 断言 |
+|---|---|---|
+| R2-1 正常获取 | 带有效 JWT,存在活跃物料 | `code==200`、返回 `data` 非空且为当前 active 物料 |
+| R2-2 无活跃物料 | Mock `assessmentService.getActiveMaterial()` 返回 null/空 | `code==200` 且 `data` 为空(或业务约定码),无 500 |
+| R2-3 鉴权缺失 | 不带 `Authorization` | 401 |
+| R2-4 类型契约 | 返回体字段与 `AssessmentMaterial` 对齐 | 反序列化成功、关键字段一致 |
+
+Mock 点:`assessmentService.getActiveMaterial()` 用 `Mockito` 隔离。
+
+> 注意(rail):本环境无 maven,**以上测试写完后无法在本机 run 验证**。落码需在已授权 maven 的环境执行 `mvn test` 复跑,通过且 push 至 `origin/cfclub` 后,方可由测试角色 `--mark-green` 闭环。
+
+## 五、缺口诊断(降级产出,不谎报通过)
+
+- **后端执行缺口(高)**:无 maven → 189 测试文件 / 1412 `@Test` 全部无法在本环境执行;270 个零测试控制器(AdminController 65、DanAssessmentController 29、AdminArticleController 22…)缺测试。
+  - 建议测试设计:按高风险后台接口优先补 MockMvc 契约测试(参考第四节模板)。
+- **e2e/pytest 执行缺口(中)**:Playwright 浏览器未装、langgraph 无 venv,需授权联网安装后方可实际执行。
+- **CI 缺口(高)**:未发现 `.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile`,脚本级自动化未接入持续回归。
+
+## 六、后续推进条件(需用户显式授权)
+
+1. **后端实测**:授权安装 maven + 配置测试库 → 跑 `mvn test`,将 16 通过/4 失败 之外的 931 未跟踪转为真实执行态。
+2. **e2e/pytest 实测**:授权 `npx playwright install` + 建 langgraph venv `pip install` → 实际跑 70 spec / pytest。
+3. **闭环推送**:授权 `git push origin/cfclub` → 使 RED/YELLOW/GREEN 证据成立,测试角色可 `--mark-green`。
+4. **落码契约测试**:在已授权环境将第四节 TC-R1/TC-R2 写入 `cfc-backend/src/test/java`,run 通过并 push 后推进状态机。

+ 358 - 0
docs/tdd/test/tdd-inspection-report.md

@@ -0,0 +1,358 @@
+# CFC 测试与代码审查巡检报告(滚动 · 最新一轮 · 第 17 次)
+
+- 巡检时间:2026-11-02 22:44–22:54 (GMT+8)
+- 执行主体:软件测试专家团 · 主理人(测试架构师陆谨)
+- 执行档:**review(离线只读)**|未跑 `mvn test` / `playwright` / `pytest`,未联网,未派发 opencode,未 commit / push
+- 编排角色:测试(`--role 测试`,只读查询 + 阶段登记,不派发)
+- 面向对象:CFC 全项目(`d:/cfc`,主库 `origin/cfclub`)
+- 去重声明:22:39 已有兄弟自动化产出 `automation-run-2026-11-02-2239.md`(扫描基线一致),本轮**不重复生成 run 文件**,只做增量取证 + 重写本滚动报告
+
+---
+
+## 一、历史审查记录
+
+| 轮次 | 时间 | 结论 | 遗留缺口(本轮是否改善) |
+|---|---|---|---|
+| #13 | 18:16 | 不通过 | 冒烟 tsv 基线未入库、台账未送达——**部分改善 / 仍未送达** |
+| #14 | 19:24 | 不通过 | 构建脚本缺陷、T39 零测试合入、同名类坍缩——**均未修** |
+| #15 | 20:30 | 不通过 | 离账 66 例、worktree 污染——**均未修** |
+| #16 | 21:37 | 不通过 | 仓库体积 843.76 MiB、提交噪音 67%——**均未修(噪音升至 67.6%)** |
+| **#17(本轮)** | **22:44** | **仍不通过** | 新增 P23(前端修复零验证合入);P15 第五度复现;P19 出现首个正向(tsv 入库) |
+
+- **本对象非首次审查**,以上为同一项目连续 17 轮巡检记录。历史结论**仅作对照**,本轮全部数字重新取证。
+- 「Maven 环境不可得」旧判定已在 #12 推翻,本轮**第六次独立复核成立**(IDEA 内置 `maven3/bin/mvn.cmd` 存在、`~/.m2` 含 spring-boot;`which mvn` → not in PATH)。
+
+---
+
+## 二、项目画像(本轮复核,结构无变化)
+
+| 维度 | 事实 |
+|---|---|
+| 业务定位 | 家庭教育成长平台(浠艾福 XAF):家庭成员 / 五维能量 / 测评订单 / 健康报告 / 商城 / AI 对话 |
+| 技术栈 | Spring Boot 2.7.18 + MyBatis-Plus(9082)· uni-app 小程序 · Vue2 管理端(8082)· FastAPI+LangGraph(9000)· 独立商城(8888) |
+| 模块 | `cfc-backend` / `cfc-frontend` / `cfc-web` / `dan/danshop` / `cfc-langgraph` |
+| 关键路径 | 登录鉴权(JWT)→ 家庭成员 → 测评订单支付 → 健康报告上传解析 → 能量发放 → 内容审核 |
+| 测试现状 | 195 Java 测试文件 / 1451 @Test(其中 3 文件 14 例仍仅在工作区);410 Playwright;47 pytest;729 结构化 md 用例;9 场景文件 |
+| 质量目标 | 可重复执行的后端套件全绿 + 冒烟收敛 + CI 阻断 + 覆盖率 ≥30% + P0 用例自动化 100% |
+| 环境事实 | Maven 3.9.9 **存在**但**不在 PATH**;`~/.m2` 已含 spring-boot → 性质为「**未授权执行**」而非「环境不可得」 |
+| 风险点 | 覆盖率 10.49% · 无 CI · 13 条既有红灯 · 冒烟指标不可信 · 仓库 843.76 MiB · 前端零回归护栏(本轮新增) |
+
+**本轮增量事实(21:37 → 22:44)**:4 次提交 —— `76fb7954a`(21:49 冒烟 fix=0)、`79ef4ac5c`(21:53 bump)、`c126b6c6e`(22:31 前端首页样式修复)、`e2f8c69de`(22:37 冒烟 fix=1,**首次带 tsv 差异**)。`git rev-list origin/cfclub...HEAD = 0/0`(HEAD 与远端同步);后端源码 / 测试文件**零提交**(最后仍为 `2e9eb5439` 18:41)。
+
+---
+
+## 三、20 类测试覆盖矩阵(三态 · 逐类证据)
+
+| # | 测试类型 | 状态 | 证据 / 说明 |
+|---|---|---|---|
+| 1 | 单元测试 | 已发现 | 195 文件 / 1451 @Test;仅 203/1935 handler(10.49%)被命中 |
+| 2 | 测试覆盖率 | 未发现(工具) | 无 JaCoCo / Cobertura 配置与报告;仅有静态 handler 命中率 |
+| 3 | 变异测试 | 未发现 | 无 PIT / Stryker 配置或产物 |
+| 4 | 契约测试 | 已发现(轻量) | `tests/e2e/api/*.spec.js` 做应答结构断言;无 Pact 类工具 |
+| 5 | 集成测试 | 已发现(局部) | `*Integration*` 测试类 + `4de8cb16a` 自带 3 例集成测试 |
+| 6 | 接口 API 测试 | 已发现 | 545 端点冒烟(`playwright_smoke.log`,22:34:49 轮次)+ API e2e 52 通过 |
+| 7 | 系统 / 端到端 | 已发现(受限) | 279 条 DOM 型 E2E 受 CFC-ENV-001 阻塞(远端只部署 API);**本轮新增证据:前端 38 行改动无法被任何用例验证** |
+| 8 | 验收 UAT | 已发现(文档) | `docs/REVIEW_SYSTEM_ACCEPTANCE_白樾.md` 等,全部 untracked |
+| 9 | BDD 规格 | 未发现 | 无 `.feature` / Cucumber / behave |
+| 10 | 冒烟测试 | 已发现 | 今日 28 次定时冒烟,最新 22:37(`e2f8c69de`) |
+| 11 | 回归测试 | 已发现(弱) | 依赖同一冒烟脚本;脚本内 `reg` 仍结构性失真(P8),但 **tsv 已入库可 git 比对**(P19 改善) |
+| 12 | 探索性测试 | 未发现 | 无 charter / 会话记录 |
+| 13 | 性能测试 | 已发现(轻量) | `nonfunc-perf-compat.spec.js` 5 例随冒烟实跑;无压测基线 |
+| 14 | 可靠性测试 | 未发现 | 无故障注入 / 恢复演练 |
+| 15 | 安全测试 | 已发现(轻量) | `nonfunc-security.spec.js` 11 例(2 红);无 SCA / DAST |
+| 16 | 兼容性测试 | 已发现(轻量) | 兼容断言 5 例;无设备矩阵 |
+| 17 | 可用性测试 | 待核实 | 无可用性测试记录 |
+| 18 | 无障碍测试 | 未发现 | 无 axe / pa11y 配置 |
+| 19 | QA 流程 | 已发现(弱) | 有阻塞台账 `test_blockers.md`;无准入准出定义 |
+| 20 | 质量度量 / CI | 部分 | 有 `interface_test_metrics.env`;**无 CI**(`.github/workflows` / `.gitlab-ci.yml` / `Jenkinsfile` 三者均不存在) |
+
+> 口径提醒:「未发现」仅表示本轮静态扫描未命中,**不等于项目没有该能力**;扫描未覆盖路径一律记「待核实」。
+
+---
+
+## 四、测试方案(本轮)
+
+| 项 | 内容 |
+|---|---|
+| 目标 | 判定当前质量状态、量化缺口、给出可执行修复动作与门禁结论 |
+| 范围 | 全 20 类矩阵判定 + 8 域抽查 + 增量取证(冒烟 / 套件产物 / 台账 / 仓库卫生 / 提交因果) |
+| 覆盖维度 | 单元·覆盖率·契约·集成·API·E2E·冒烟·回归·性能·安全·兼容·流程·度量·仓库卫生 |
+| 执行档 | review(离线只读) |
+| 优先级 | P0:可执行环境 / 影子测试 / 覆盖率 / CI;P1:冒烟口径 / 结果分型 / RED 闭环 / 仓库体积;P2:噪音治理 / 卫生 |
+| 排除项 | 需联网的压测与依赖漏洞扫描(未授权);源码重构方案(非本团职责) |
+
+---
+
+## 五、执行档
+
+| 档位 | 本轮状态 |
+|---|---|
+| review(离线白名单) | 已执行:`discover_tests.py`、`test_inventory.py`、`tdd_orchestrate.py --status`、git 只读取证(log/status/show/rev-list/ls-files)、md5 比对、Maven 三路探测、`Result.java` 只读复核 |
+| execute(需联网) | **未授权未执行**:`mvn test`、`playwright test`、`pytest`、依赖漏洞扫描、压测 |
+
+---
+
+## 六、覆盖缺口清单
+
+| # | 缺口类型 | 现状 | 风险 | 建议测试设计 | 优先级 | 闭环方式 |
+|---|---|---|---|---|---|---|
+| 1 | 关键控制器单测 | 268 单元零覆盖;`AdminController` 0/65、`DanAssessmentController` 0/29、`AdminArticleController` 0/22、`TaskController` 0/18 | 后台与测评主链路无回归护栏 | 按「鉴权→参数→业务→异常」四段各 1 例,MockMvc + 直接调用双风格 | P0 | 覆盖分子上升 + 套件全绿 |
+| 2 | 执行回写 | 1451 例中约 1303 从未执行(surefire 仅 17 XML,停 08:31–08:39) | 覆盖率与「通过」均不可验证 | 授权 `mvn -o -DskipITs test` 后回填 sidecar | P0 | 全量 surefire XML |
+| 3 | 文档用例自动化 | 729 条 md 用例 0 自动化,其中 P0 59 条 | 用例是纸面资产 | 批量转 Playwright API spec;TC 表加 `auto: pending\|done` | P1 | P0 自动化 100% |
+| 4 | 冒烟可信度 | `prev.tsv` 与 `report.tsv` 每轮字节相同(各 91,544 B,md5 `22719824…`) | 回归永远「无劣化」 | **改用 `git show HEAD:interface_test_report.tsv` 作基线**(tsv 已入库,无需 prev 副本) | P0 | 连续 2 轮 fix>0 或真实劣化被捕获 |
+| 5 | 结果分型 | 295 BIZ_FAIL 未分「真缺陷 / 前置条件 / 参数缺失」;`Result.error()` 恒 500 | 噪声淹没真缺陷 | `Result.error()` 分 4xx,冒烟按 `code+message` 分桶 | P1 | 真缺陷单列派单 |
+| 6 | CI 门禁 | 无 CI 配置 | 红灯可长期滞留 | workflow:`mvn -o test` + 冒烟 + `--exit-on-reg` | P0 | PR 阻断红灯 |
+| 7 | 契约测试 | 无独立契约工具 | 前后端字段漂移(F1 `data.records` vs `data.list`) | 5 条主链路加应答 schema 断言 | P2 | 字段漂移被阻断 |
+| 8 | 性能基线 | 仅 5 例轻量断言 | 无容量结论 | k6/artillery 基线(需授权) | P2 | 有基线报告 |
+| 9 | 无障碍 | 无 | 小程序 / Web 可访问性未知 | axe-core 接入 DOM 层 E2E | P2 | 无 critical 违规 |
+| 10 | 仓库卫生 | pack 843.76 MiB;HEAD 仍跟踪 74 MB 大文件(P21) | clone / CI 不可行 | 大文件迁 LFS 或移出 + 历史瘦身 | P1 | `du -sh .git` < 200 MB |
+| 11 | 提交可读性 | 自动提交占今日 **67.6%**(69/102:41 bump + 28 冒烟) | `git log` 信号被淹没 | 路径过滤 bump + 冒烟按日归档 | P2 | 自动提交占比 < 30% |
+| 12 | **前端回归护栏** | `cfc-frontend` 38 行样式修复零测试;`tests/` 下无 `index-home`/`DimensionProducts` 引用 | 前端改动只能靠人眼上线 | 前端部署到测试环境后启用 279 条 DOM 用例;短期至少补 1 条首页渲染快照 | P1 | 前端改动有可执行用例覆盖 |
+
+---
+
+## 七、域结论表
+
+| 审查维度 | 负责专家 | 结论 | 关键证据 |
+|---|---|---|---|
+| 单元·组件级 | 苏雅 | 不通过 | 195 文件 / 1451 @Test;覆盖 203/1935 = 10.49%;3 文件 14 例未入库(P3) |
+| 集成·接口级 | 柯砚 | 不通过 | 545 端点冒烟 45%(249 OK / 295 BIZ_FAIL / 1 CONN_ERR);52 通过 vs §7 69 例两套口径未统一(P11) |
+| 系统·验收级 | 白樾 | 待核实 | 279 DOM 用例受 CFC-ENV-001 阻塞;本轮前端改动因此完全无验证(P23);验收报告 untracked |
+| 测试保障级 | 闻朔 | 不通过 | 今日 28 次冒烟,fix=1 仍为抖动(P15 五度复现);`prev==report` 基线自覆盖(P8);无探索性测试记录 |
+| 性能·可靠性 | 骆骋 | 未实测 | 压测需联网未授权;仅 5 例轻量断言 |
+| 安全 | 关屿 | 不通过 | N05 未授权登录返回 500、N11 非 PDF 未拒(2 红);`Result.java:37-39` 恒 500 掩盖鉴权语义 |
+| 兼容·体验 | 阮清 | 待核实 | 无设备矩阵、无无障碍工具;DOM 层无法执行 |
+| 流程·度量·代码 | 何序 | 不通过 | 无 CI;提交噪音 67.6%;pack 843.76 MiB;`docs/tdd` 24.1h 未送达 |
+
+> 说明:白樾 / 关屿 / 骆骋 有落盘报告(均 untracked);其余域本轮为静态取证结论,**未派发深审**(无新增测试资产),「待核实」项不作通过认定。
+
+---
+
+## 八、五要素问题清单
+
+### P1【P0】后端 13 条红灯未修,套件产物停在 08:39(第 17 轮确认)
+
+1. **问题描述**:`cfc-backend/target/surefire-reports/` 仍只有 17 个 XML,最新 08:31–08:39;1451 例中约 1303 例从未执行;13 条红(8 fail + 5 error)自 08:26 起无任何修复提交(后端口最后提交 `2e9eb5439` 18:41,但含零测试)。
+2. **测试 bug 点**:`AuthControllerTest`(4 条断言停在废弃接口旧口径,实际 410/401);`ArticleControllerTest`(9 条:`doNothing()` 误用 5 error、打桩参数不匹配 2 fail、Service 未打桩 2)。
+3. **最优修改方案**:逐条改断言与打桩;`AuthControllerTest` 对齐 410/401 语义;`ArticleControllerTest` 改 `when(...).thenReturn(...)` 并对齐入参。
+4. **修改目的**:让后端套件成为可信回归基线,解除「红灯长期滞留」。
+5. **闭环**:`mvn -o -DskipITs test` 全绿(fail=0 error=0),XML 数 ≥ 测试类数,回填 sidecar。
+
+### P2【P0】可执行环境:Maven 可得但未入 PATH、未授权(第 6 轮确认)
+
+1. **问题描述**:`which mvn` 无结果;`C:/Program Files/JetBrains/IntelliJ IDEA 2025.2.5/plugins/maven/lib/maven3/bin/mvn.cmd` 存在,`~/.m2/repository/org/springframework/boot` 已有依赖 → 阻塞性质是「未授权」而非「缺工具」。
+2. **测试 bug 点**:无(流程/授权项)——影响所有 P0 闭环动作。
+3. **最优修改方案**:把 IDEA maven `bin` 加入 PATH,或 `.tdd/config.json` 的 `mvn_cmd` 指向绝对路径 `mvn.cmd`。
+4. **修改目的**:使「跑一次全量后端套件」成为可执行动作。
+5. **闭环**:`mvn -v` 返回版本 + 一次 `mvn -o -DskipITs test` 产生全量 XML。
+
+### P3【P0】影子测试:3 文件 14 例仍未入版本库(持续 6.8h)
+
+1. **问题描述**:`HealthReportControllerCreateReportTest.java`(7,335 B)、`DanAssessmentControllerGetActiveMaterialTest.java`(2,855 B)、`admin/SupplyTeamControllerInviteTest.java`(7,894 B) 全部 `??`,落盘时间均为 15:58,至今未动;`state.json` 仍 RED(更新时间 11:48)。
+2. **测试 bug 点**:三文件(2 / 5 / 7 例,共 14 例)未 commit → 按「未推送不算完成」口径,RED 未推进。
+3. **最优修改方案**:`git add` 三文件 → commit(message 含 `S-be-1` / `S-be-2` / `T38`)→ push;随后 `--mark-red <key> --commit <sha>`。
+4. **修改目的**:把 RED 契约测试变成团队可见、可复跑的真理证据。
+5. **闭环**:`git ls-files` 能列出三文件 + `git merge-base --is-ancestor` 对 `origin/cfclub` 成立。
+
+### P4【P0】扫描器漏判,覆盖分子锁死 203(第 7 轮未修)
+
+1. **问题描述**:`discover_tests.py` 用 `p in hit_paths` 做等值匹配;handler 存相对路径 `/report/create`,测试写全路径 `/api/health/report/create` → 新测试命中却判未覆盖(三影子测试 http_hits=1/2/7 仍全判 covered=false)。
+2. **测试 bug 点**:`C:/Users/iwt/.workbuddy/skills/tdd-orchestrator/scripts/discover_tests.py`(匹配逻辑处)。
+3. **最优修改方案**:改为后缀/前缀双向 `endswith` 匹配(任一方向满足即命中)。
+4. **修改目的**:让覆盖分子反映真实命中,避免指标失真掩盖投入。
+5. **闭环**:修后重扫,分子应从 203 上升(量化上限 +9 ≈ 11.0%),`covered+partial` 分布同步变化。
+
+### P5【P0】无 CI 门禁(第 17 轮确认)
+
+1. **问题描述**:仓库无 `.github/workflows/`、`.gitlab-ci.yml`、`Jenkinsfile`;冒烟与其自动提交全靠本机 cron。
+2. **测试 bug 点**:无 CI 定义文件(缺失项)。
+3. **最优修改方案**:建最小 workflow:`mvn -o -DskipITs test` + 冒烟脚本 + `reg>0` 时非 0 退出。
+4. **修改目的**:把「红灯可长期滞留」变为「红灯阻断合并」。
+5. **闭环**:提交一个故意失败的分支,CI 必须变红并阻止合并。
+
+### P6【P1】TC-P-N11 断言恒假
+
+1. **问题描述**:`nonfunc-security.spec.js` 断言原始 HTTP status ∈ 4xx,但本项目 http 恒 200、错误在 body `code`(本轮 all BIZ_FAIL 行 http=200 再次印证)。
+2. **测试 bug 点**:`tests/e2e/api/nonfunc-security.spec.js`(N11 用例)。
+3. **最优修改方案**:改断言 body `code`(或 `code!=0` 且 message 命中文件类型校验)。
+4. **修改目的**:消除永假断言,恢复该用例诊断力。
+5. **闭环**:修后能区分「校验生效」与「未生效」,并在缺陷修复后转绿。
+
+### P7【P1】冒烟 fix/reg 无因果(第 7 度复现)
+
+1. **问题描述**:今日 4 次 fix=1(13:22 / 17:01 / 18:08 / 22:37)与 3 次 reg=1(14:41 / 17:23 / 其它)**全部**落在 `/api/user/portrait/generate` 与 `/portrait/regenerate` 这对 AI 出图端点;22:37 本轮 fix=1 即 `regenerate: -1 CONN_ERR → 200 BIZ_OK`,同时 `generate` 仍在抖动;相关代码最后变更在 10-30 → 属 `AiGateway` 外部依赖抖动,非本仓库代码因果。
+2. **测试 bug 点**:`run_interface_tests_cron.sh` 的 fix/reg 差值逻辑(无稳定性门槛)。
+3. **最优修改方案**:CONN_ERR 三次重试后再计数;连续 2 轮同向变化才记 fix/reg;`reg>0` 非 0 退出。
+4. **修改目的**:让 fix/reg 只反映代码因果,不反映网络抖动。
+5. **闭环**:连续 2 轮 CONN_ERR 抖动不再产生 fix/reg 变化。
+
+### P8【P1】冒烟比对基线被自身覆盖 → 脚本内 fix/reg 结构性失真(第 4 轮复核)
+
+1. **问题描述**:22:37 采集后 `interface_test_prev.tsv` 与 `interface_test_report.tsv` **字节级完全相同**(各 91,544 B,md5 `227198248b292d69e636c511659bfb74`);`prev.tsv` 仍未入版本库(`git ls-files` 只返回 `report.tsv`)→ 脚本内部差值恒 0。
+2. **测试 bug 点**:`run_interface_tests_cron.sh` 中 prev/report 覆写顺序。
+3. **最优修改方案**:**既然 `interface_test_report.tsv` 已入库(见 P19),直接以 `git show HEAD:interface_test_report.tsv` 作为基线**,删除本地 `prev.tsv` 副本;或退化为「先 `cp report prev` 再写本轮」。
+4. **修改目的**:使「回归劣化」在机制上可被发现,且基线随 git 版本化、CI 可复现。
+5. **闭环**:连续两轮 `prev != report`(或 `git diff` 非空),且人为改坏一个端点能被 `reg` 捕获。
+
+### P9【P1】冒烟结果自相矛盾(第 17 轮复核确认,附一处前轮取证纠正)
+
+1. **问题描述**:`tests/test-results/.last-run.json`(22:51 写入)内容为 `{"status": "failed", "failedTests": []}` —— 状态已失败却无失败清单;而同轮 `INTERFACE_TEST_REPORT.md` 记「fix=1 reg=0」闭环成功、`playwright_smoke.log` 记「52 passed」。该文件**已被 git 跟踪**(`M`,HEAD 版本为 `status: passed`),等于把「failed 但无失败用例」写进版本库。
+   > **前轮取证纠正**:#17 初次核查时误用仓根路径 `.last-run.json` 与 `test-results/.last-run.json`(实为 `tests/test-results/.last-run.json`),据此曾判定「事实源消失」。该判定**不成立**,已撤回;问题性质仍是 P9 原状(自相矛盾),未改善。
+2. **测试 bug 点**:`tests/test-results/.last-run.json`(`failedTests` 恒空数组);Playwright reporter 配置。
+3. **最优修改方案**:reporter 固定输出 `json` + `list` 双 reporter,`failedTests` 写入失败用例名与错误摘要;落盘保留最近 N 轮;`failedTests` 非空时脚本非 0 退出。
+4. **修改目的**:消除同一轮「报告说成功 / 事实源说失败」的冲突,并让失败可定位。
+5. **闭环**:`status=failed` 时 `failedTests` 必有内容且退出码非 0;任一轮次能从 artifact 列出失败用例名。
+
+### P10【P1】`Result.error()` 硬编码 500(第 8 轮未修)
+
+1. **问题描述**:`common/Result.java:37-39` 本轮复核仍为 `result.setCode(500)` → 参数缺失 / 无权限全部伪装成服务器错误;连带 `SERVER_ERR` 恒 0 的假安全信号与分型噪声。
+2. **测试 bug 点**:`cfc-backend/src/main/java/com/etotem/cfc/common/Result.java:37-39`。
+3. **最优修改方案**:新增 `badRequest()/forbidden()/notFound()`,新代码先用;存量分批迁移;冒烟按 `code+message` 分桶。
+4. **修改目的**:让错误语义可判定,恢复冒烟与安全断言有效性。
+5. **闭环**:N05 返回 401/403、参数缺失返回 400,`SERVER_ERR` 只在真实 5xx 时 >0。
+
+### P11【P1】两套 E2E 口径未统一
+
+1. **问题描述**:22:37 报告记「API e2e 52 通过 / 2 failed / 3 skipped」= 57 例;`test_blockers §7` 全量 69 例(expected 59 / unexpected 7 / skipped 3),59 为 `test.fail()` → 同一套用例两套数字、总数不等。
+2. **测试 bug 点**:`INTERFACE_TEST_REPORT.md` 统计口径 vs Playwright reporter 原始计数。
+3. **最优修改方案**:报告直接引用 reporter 的 `expected/unexpected/skipped` 三数,不再另行汇总。
+4. **修改目的**:同一套用例只有一个可对账数字。
+5. **闭环**:报告总数 = 三数之和,且跨轮可比。
+
+### P12【P2】域报告落盘 3/8,全部 untracked
+
+1. **问题描述**:仅白樾(11-01 17:54)、关屿(08:13)、骆骋(08:14)有报告文件,其余 5 域结论不可追溯。
+2. **测试 bug 点**:`docs/tdd/test/*-review*.md`(3 份均 `??`)。
+3. **最优修改方案**:8 域报告统一命名纳入 `docs/tdd/test/`,随台账一起提交。
+4. **修改目的**:审查结论可追溯、可复评。
+5. **闭环**:`git ls-files docs/tdd/test` 含 8 份域报告。
+
+### P13【P0】台账从未提交,24.1h 未送达(首次跨越 24h)
+
+1. **问题描述**:`docs/tdd/` 最后一次提交仍是 `5a147887c`(11-01 22:39),至今 **24.1h**;`git rev-list origin/cfclub..HEAD = 0/0` → 缺口是「**从未 commit**」而非「已 commit 未 push」。当前 41 个 `??` + 5 个 `M`,其中含 14 份 `automation-run-*.md`、巡检报告、`red-task-investigation.md`、域报告。
+2. **测试 bug 点**:`docs/tdd/test/{discovery,inventory,automation-status}.md`(M)+ 上述 untracked 报告。
+3. **最优修改方案**:`git add docs/tdd` → commit → push(禁止 `git add -A`,避免带入 `.wt-*` 与冒烟临时 tsv)。
+4. **修改目的**:让团队共享层真正送达研发,否则连续 17 轮结论只存在于本地。
+5. **闭环**:`origin/cfclub` 上可见当日台账版本。
+
+### P14【P0】两 RED 停滞约 10.9h
+
+1. **问题描述**:`health.report.createReport`、`dan.assessment.getActiveMaterial` 自 01:06 起停 RED,`state.json` 更新停在 11:48(`Counter({'RED': 2})`);`git log --all --grep S-be-1/S-be-2` 仍空。
+2. **测试 bug 点**:`.tdd/state.json` 两键(无 git 证据)。
+3. **最优修改方案**:与 P3 合并处理——三文件(含两 RED 契约测试)入库 push,再 `--mark-red`。
+4. **修改目的**:解除 RED 长期停滞,让开发侧有可派发目标。
+5. **闭环**:两键有已推送提交 + `--mark-red` 成功。
+
+### P15【P2】缺陷与噪声未分流
+
+1. **问题描述**:295 条 BIZ_FAIL 未区分真缺陷 / 前置条件 / 参数缺失;分型产物(`INTERFACE_FAIL_CLASSIFICATION.md`、`interface_fail_classification.tsv`)未入版本库,主口径仍只报 45%。
+2. **测试 bug 点**:分类产物未入版本库、未进报告主指标。
+3. **最优修改方案**:分类结果进 `INTERFACE_TEST_REPORT.md` 主段并提交;真缺陷单列派单。
+4. **修改目的**:把「参数缺失噪声」从真缺陷中剥离。
+5. **闭环**:报告首页可见「真缺陷 N 条」,每条有责任人与状态。
+
+### P16【P2】构建脚本缺陷:bash 语法写进 npm script(第 3 轮未修)
+
+1. **问题描述**:`cfc-web/package.json` 的 `prebuild` 用 `$(node -p ...)`;Windows 下不展开 → `cfc-web/public/` 留有垃圾文件 `CHANGELOG-v$(node.undefined.md`(5,576 B),随 vue-cli 拷进 `dist/` 上线。
+2. **测试 bug 点**:`cfc-web/package.json`(prebuild)+ `cfc-web/scripts/generate-changelog.js`(依赖 `argv[2]`)。
+3. **最优修改方案**:去掉 shell 替换,由 `generate-changelog.js` 内部 `require('./package.json').version` 读取版本。
+4. **修改目的**:消除垃圾产物进入静态发布目录。
+5. **闭环**:删净该文件,连续两次 build 不再生成新垃圾文件。
+
+### P17【P1】T39 零测试合入(T38 同型复发,第 4 轮未修)
+
+1. **问题描述**:`2e9eb5439`(18:41)改 7 个后端文件(5 控制器 + `RealNameBackfillService` + `UserService`),零测试;被改控制器覆盖:`AdminController` 0/65、`SupplyManageController` 0/8、`butler/ButlerController` 0/6、`GuideManagementController` 3/17、`NutritionistController` 1/2。
+2. **测试 bug 点**:无对应测试文件(缺失项)。
+3. **最优修改方案**:补 5 条「姓名写入入口」参数化用例(含 nickname 同步回填断言)。
+4. **修改目的**:避免真实姓名回填规则再次回归。
+5. **闭环**:新增用例入主干并被 surefire 执行、通过。
+
+### P18【P2】扫描器同名类坍缩
+
+1. **问题描述**:`controller/ai/ButlerController` 与 `controller/butler/ButlerController` 同名(均有显式 `@RestController` 别名,Spring 无冲突),但 `discovery.json` 以简单类名作 unit 键 → 两份 unit 同名、direct 名匹配可交叉计数。
+2. **测试 bug 点**:`discover_tests.py` 的 unit key 生成(类名而非 FQN)。
+3. **最优修改方案**:unit 键改为包路径 + 类名(FQN),保留简单名做展示字段。
+4. **修改目的**:消除同名类覆盖统计互相污染。
+5. **闭环**:`discovery.json` 中两 unit 键不同,覆盖数各自独立可核。
+
+### P19【P1】离账测试资产 66 例 + **本轮首个正向:冒烟 tsv 已入库**
+
+1. **问题描述**:`verify/coupon-c3-fix` 6 文件 / 37 @Test、`verify/t28-fix-key-align` 2 文件 / 29 @Test(合 8 文件 66 例)仍未合入 `cfclub`;**正向变化**:`interface_test_report.tsv` 已于 13:55(`277da5627`「结果 TSV 改为提交前同步」)纳入版本控制,累计 12 次提交,22:37(`e2f8c69de`)那次带真实差异(`regeneratePortrait: -1 CONN_ERR → 200 BIZ_OK`)→ 回归差异从此可用 `git diff` 复核。
+2. **测试 bug 点**:分支 `verify/coupon-c3-fix`、`verify/t28-fix-key-align`。
+3. **最优修改方案**:① 评审后 merge 入主干,或明确标记「废弃」并删分支;② 把 P8 的脚本基线改为 `git show HEAD:interface_test_report.tsv`,让入库 tsv 真正发挥作用。
+4. **修改目的**:让台账与主干资产对账一致;让入库的 tsv 从「可 diff」升级为「被脚本使用」。
+5. **闭环**:主干测试文件数 = 台账文件数;脚本基线取自 git 而非本地副本。
+
+### P20【P2】仓内 worktree 污染 `git status`(第 3 轮未修)
+
+1. **问题描述**:`.wt-c3fix/`、`.wt-f3c/`、`.wt-t28v/` 仍以 `??` 常驻;`.gitignore` 中**无任何 `.wt-` 规则**(本轮 grep 零命中)。
+2. **测试 bug 点**:`.gitignore`。
+3. **最优修改方案**:`.gitignore` 增 `.wt-*/`;废弃 worktree 用 `git worktree remove --force` 清理。
+4. **修改目的**:降低误 `git add -A` 带入风险。
+5. **闭环**:`git status` 不再出现 `.wt-*`。
+
+### P21【P1】仓库体积失控:843.76 MiB pack,HEAD 仍跟踪 74 MB 大文件(第 2 轮未修)
+
+1. **问题描述**:`size-pack = 843.76 MiB`;`verify-pack` 大 blob:149.7 MB `.venv-packages.tar.gz`(`c28fe3008` 已删但留史)、70.8 MB `edc-contamination-chain.png`、49.6 MB `docs/参考资料/匿名…`、41.5 MB `ppt-output/preview.html`、33.3 MB `docs/菌群知识库/_chunks.jsonl`;后两者 **HEAD 仍跟踪**(74 MB / 每次 clone)。
+2. **测试 bug 点**:无代码行——属配置/流程缺口。直接后果:clone 与 CI 拉取成本 ≈843 MiB,使 P5「接入 CI」落地即被拖慢。
+3. **最优修改方案**:① `git rm --cached` 两个仍跟踪的大文件并加入 `.gitignore`,改由 LFS / 对象存储提供;② 历史瘦身(`git filter-repo --strip-blobs-bigger-than 5M`,**须先全员停推 + 备份**);③ 清理 3 个孤立 `.idx`(`385bdc8c`/`5ad8994b`/`81c73049`)。
+4. **修改目的**:把仓库降到可 CI、可协作的体积(目标 < 200 MB)。
+5. **闭环**:`git count-objects -vH` < 200 MiB;`git clone` 分钟级完成;CI 首次拉取成功。
+
+### P22【P2】提交噪音升至 67.6%
+
+1. **问题描述**:今日 **102** 次提交,其中 41 次 `auto bump version` + 28 次「接口冒烟闭环」= 69 次自动(**67.6%**,较上轮 67% 继续上升),实质变更仅 33 次;每次 bump 全量重写 `cfc-web/public/CHANGELOG-v1.0.md`(1.4 MB,位于静态托管目录,随前端发布)。
+2. **测试 bug 点**:`cfc-web/public/CHANGELOG-v1.0.md`(构建产物入库)+ 无 CI 导致无「仅 docs/chore 变更不触发 bump」约束。
+3. **最优修改方案**:① CHANGELOG 产物移出 `public/` 或只在发布时生成(不入 git);② bump 增加路径过滤——仅当 `cfc-web/` 实质变更才 bump;③ 冒烟自动提交按日归档。
+4. **修改目的**:恢复 `git log` 信号比,使「测试资产是否变化」可在数秒内判定(17 轮巡检均需先剔除数十条噪音)。
+5. **闭环**:一周内自动提交占比 < 30%;`git log --oneline -20` 中实质变更 ≥ 12 条。
+
+### P23【P1·本轮新发现】前端修复零验证合入,前端无任何回归护栏
+
+1. **问题描述**:`c126b6c6e`(22:31)「fix(ui): 首页全局样式泄漏阻断 DimensionProducts 商城卡片布局」改 `cfc-frontend/pages/index-home/index.vue` 38 行(19 增 19 删),**零测试**;`tests/` 全目录 grep `index-home` / `DimensionProducts` **零命中**;同时 279 条 DOM 型 E2E 因 CFC-ENV-001(远端只部署 API、无 H5/Web 前端)全部无法执行 → 该修复除了「人眼看首页」,没有任何机器验证手段,样式泄漏类缺陷可随时复发。
+2. **测试 bug 点**:无对应测试文件(缺失项);`INTERFACE_TEST_REPORT.md` 已自陈「279 项 DOM 型 E2E 无法执行」。
+3. **最优修改方案**:① 近期可行——把 H5 构建产物部署到测试环境(或用 `uni-app` H5 dev server + Playwright `webServer` 本地起),让 279 条 DOM 用例至少跑首页/商城卡片这 1 条主链路;② 中期——给 `index-home` 加视觉/结构快照(Playwright `toHaveScreenshot` 或 DOM 结构断言),样式泄漏即被捕获;③ 与 P14/T39 合并成统一准入规则:**UI 修复必须附 1 条可执行用例**。
+4. **修改目的**:给前端改动一条最小可执行护栏,避免「修一个样式、破另一个卡片」的静默回归。
+5. **闭环**:首页改动提交时,CI/本地能跑出 1 条覆盖 `index-home` 的用例;故意注入样式泄漏时该用例变红。
+
+---
+
+## 九、门禁结论
+
+**结论:不通过(FAIL)**
+
+| 门槛 | 判定 | 依据 |
+|---|---|---|
+| G1 可执行环境(mvn 可用) | **部分** | Maven 3.9.9 存在但未入 PATH、未授权 → 可执行性未验证 |
+| G2 后端套件全绿 | 未达成 | 13 条红灯未修;1303/1451 例从未执行 |
+| G3 覆盖率 ≥ 30% | 未达成 | 10.49%(203/1935);扫描器漏判(P4)使真实值不可确定 |
+| G4 新增测试可追溯 | 未达成 | 3 文件 14 例仍 `??`(6.8h);T38/T39 连续零测试合入;本轮再增前端零测试合入 |
+| G5 安全冒烟 11/11 | 未达成 | N05(未授权返回 500)、N11(非 PDF 未拒)2 红 |
+| G6 结果分型落地 | 未达成 | `Result.error()` 恒 500;295 BIZ_FAIL 未分流 |
+| G7 冒烟计数可信 | 未达成(**有改善**) | 脚本内 `prev==report` 字节相同仍致失真;但 tsv 已入库,可改 git 基线 |
+| G8 P0 用例自动化 100% | 未达成 | 59 条 P0 文档用例 0 自动化 |
+| G9 CI 阻断红灯 | 未达成 | 无任何 CI 配置(且受 G10 拖累) |
+| G10 仓库可 CI 化 | 未达成 | pack 843.76 MiB,HEAD 仍跟踪 74 MB 大文件 |
+| G11 台账/域报告送达 | 未达成(**恶化**) | `docs/tdd/` 24.1h 未提交,41 `??` + 5 `M` 积压 |
+| G12 RED 闭环推进 | 未达成 | 两键停滞 ≈10.9h,无已推送证据 |
+
+**最快翻盘顺序(按投入产出比)**:① `git add` 三影子测试 + push + `--mark-red` → 一次解 G4/G12;② `git add docs/tdd` 并提交推送 → 解 G11;③ 授权 `mvn -o -DskipITs test`(已无环境障碍)→ 解 G1/G2 并产生真实覆盖率;④ 把 P8 基线改为 `git show HEAD:interface_test_report.tsv`(tsv 已入库,**改动量仅数行**)→ 解 G7;⑤ 大文件移出 + 历史瘦身 → 解 G10,为 G9 铺路;⑥ 建最小 CI → 解 G9。
+
+---
+
+## 十、未实测项(如实标注)
+
+- 未运行 `mvn test`(Maven 可得、未入 PATH、**未授权**);未运行 `playwright test`;未运行 `pytest`。
+- 无 JaCoCo,Java **行覆盖率未测**;矩阵 #2 覆盖率工具维度为「未发现」,10.49% 是**静态 handler 命中率**,不是行覆盖。
+- 性能压测、依赖漏洞扫描需联网,**未授权未执行**;性能/可靠性域结论为「未实测」。
+- 8 域深审本轮未派发(无新增测试资产);5 域为静态取证,标「待核实」。
+- 3 个影子测试能否编译 / 通过**未验证**(本机未授权构建)。
+- 冒烟 22:37 轮次的失败明细**无法定位**(`tests/test-results/.last-run.json` 写 `status=failed` 但 `failedTests` 为空数组,P9)。
+- P21 中 3 个孤立 `.idx` 的影响面仅以 `git fsck --connectivity-only`(历史通过)为界,本轮未重跑;pack 内各文件压缩占比未逐项统计。
+- 前端首页样式修复(`c126b6c6e`)**视觉效果未验证**(无 H5 部署、无 DOM 执行环境)。
+
+---
+
+## 十一、疑似提示注入
+
+本轮扫描的仓库文件(`.md` 用例、`test_blockers.md`、`INTERFACE_TEST_REPORT.md`、提交信息、构建脚本注释、`state.json`)中**未发现**试图改变审查行为的指令性内容。若后续发现,将在本节单列并保持自身约束不变。

+ 40 - 0
docs/tdd/test/test_blockers.md

@@ -30,12 +30,15 @@
 | R2 | API 契约疑似不一致 | 此前发现 `/api/articles/report-reading-time` 返回 `biz=500` 但 `message="success"`(字段语义矛盾);执行 E2E 进一步暴露:① butler 列表返回 `data.list` 而 activity 列表返回 `data.records`(F1);② `POST /api/admin/commission/config` 更新配置返回 **400**(F2,真实接口响应) | 自动化断言无法稳定判定成功/失败,易误报;写操作 E2E 大面积受 envelope 不一致牵连 | 研发在 `cfc.iwintrue.com` 复测确认,明确 `biz` 与 `message` 语义并修复或文档化契约;统一列表 envelopes(F1);排查 commission update config 400(F2) |
 | R2 | API 契约疑似不一致 | 此前发现 `/api/articles/report-reading-time` 返回 `biz=500` 但 `message="success"`(字段语义矛盾);执行 E2E 进一步暴露:① butler 列表返回 `data.list` 而 activity 列表返回 `data.records`(F1);② `POST /api/admin/commission/config` 更新配置返回 **400**(F2,真实接口响应) | 自动化断言无法稳定判定成功/失败,易误报;写操作 E2E 大面积受 envelope 不一致牵连 | 研发在 `cfc.iwintrue.com` 复测确认,明确 `biz` 与 `message` 语义并修复或文档化契约;统一列表 envelopes(F1);排查 commission update config 400(F2) |
 | R3 | 测试环境无可用测试管理员账号 | `tests/e2e/admin-activity-review.spec.js` 等依赖 `/api/admin-auth/login-by-password` 登录取 `Bearer` token;仓库内已硬编码测试账号 `13800138000` | E2E 在登录步即失败,**无法推进带登录态的端到端测试** | **已解决(2026-11-01):已确认测试账号 `13800138000`,实跑 E2E 登录+鉴权+API 全部可达** |
 | R3 | 测试环境无可用测试管理员账号 | `tests/e2e/admin-activity-review.spec.js` 等依赖 `/api/admin-auth/login-by-password` 登录取 `Bearer` token;仓库内已硬编码测试账号 `13800138000` | E2E 在登录步即失败,**无法推进带登录态的端到端测试** | **已解决(2026-11-01):已确认测试账号 `13800138000`,实跑 E2E 登录+鉴权+API 全部可达** |
 | R4 | 无 CI 流水线 / 无测试门禁 | 仓库无 `.github/workflows` 等 CI 配置;测试未纳入合并门禁 | 回归无自动拦截,已写测试随改动腐化 | 建 CI:`mvn test` + `pytest` + `playwright`(接 `cfc.iwintrue.com`)作为合并门禁 |
 | R4 | 无 CI 流水线 / 无测试门禁 | 仓库无 `.github/workflows` 等 CI 配置;测试未纳入合并门禁 | 回归无自动拦截,已写测试随改动腐化 | 建 CI:`mvn test` + `pytest` + `playwright`(接 `cfc.iwintrue.com`)作为合并门禁 |
+| R5 | 未授权访问后台登录接口暴露 500 | `POST /api/admin-auth/login`(无 token / 空 body)返回 **500**(`message="手机号和验证码不能为空"`),应为 401/403 | 鉴权前置缺失,异常信息泄露;安全测试无法断言"被拒",存在 5xx 雪崩风险 | 在 `cfc.iwintrue.com` 复测;`admin-auth` 登录对未授权/非法请求统一返回 401/403,缺失参数走参数校验而非抛异常 |
+| R6 | 报告上传未做文件类型 / 安全校验 | `POST` 上传非 PDF(错误/恶意类型)内容**未被拒**(非 4xx) | 存在恶意文件上传与存储风险;安全合规测试无法断言"被拒" | 报告上传增加 MIME/扩展名/内容校验,非 PDF 或异常内容一律 4xx 拒绝 |
 
 
 ## 3. 新增测试侧阻碍(执行中暴露,直接处理)
 ## 3. 新增测试侧阻碍(执行中暴露,直接处理)
 
 
 | 编号 | 阻碍 | 证据 | 处理 |
 | 编号 | 阻碍 | 证据 | 处理 |
 |---|---|---|---|
 |---|---|---|---|
 | T4 | 主配置 `globalSetup`(`e2e/helpers/db.js`)**强制**连内网 MySQL `192.168.16.251` 做 DB 重置+灌种子,无跳过开关,失败即 `process.exit(1)` | 远程只读 E2E 不需要重置内网库;本沙箱路由不到该内网地址 → `Access denied` 阻断一切 E2E | 已用**临时无重置配置**(`playwright.config.noreset.js`,不提交)绕过;**建议研发给 `db.js` 加 `SKIP_DB_RESET` 开关**,使针对远程测试环境的只读 E2E 可跳过本地库重置 |
 | T4 | 主配置 `globalSetup`(`e2e/helpers/db.js`)**强制**连内网 MySQL `192.168.16.251` 做 DB 重置+灌种子,无跳过开关,失败即 `process.exit(1)` | 远程只读 E2E 不需要重置内网库;本沙箱路由不到该内网地址 → `Access denied` 阻断一切 E2E | 已用**临时无重置配置**(`playwright.config.noreset.js`,不提交)绕过;**建议研发给 `db.js` 加 `SKIP_DB_RESET` 开关**,使针对远程测试环境的只读 E2E 可跳过本地库重置 |
+| T5 | 远程测试环境未托管前端 SPA | `cfc.iwintrue.com` 仅部署后端 API(Spring Boot);非 API 路径返回白标 404(见 `e2e/helpers/api.js` 注释) | 约 38 个依赖 `page.goto`/DOM 的 UI 级 `e2e/*.spec.js` 在远程无法运行,会全部失败于"无前端" | 已识别并**排除执行**,避免误导性失败噪音;UI 级 E2E 需在部署了前端的测试环境或本地执行 |
 
 
 ## 4. 已执行 E2E 结果(只读子集,2026-11-01)
 ## 4. 已执行 E2E 结果(只读子集,2026-11-01)
 
 
@@ -88,3 +91,40 @@
 - **测试侧**:R3 已解决,T1/T2/T3 已执行,T4 已临时绕过(建议研发加 `SKIP_DB_RESET` 开关);写操作 E2E 已按授权跑完(见 §5)。可继续扩大 E2E 覆盖(其余 64 个 `e2e/*.spec.js`)或转向 Java 单测 / Python pytest(本机执行)。
 - **测试侧**:R3 已解决,T1/T2/T3 已执行,T4 已临时绕过(建议研发加 `SKIP_DB_RESET` 开关);写操作 E2E 已按授权跑完(见 §5)。可继续扩大 E2E 覆盖(其余 64 个 `e2e/*.spec.js`)或转向 Java 单测 / Python pytest(本机执行)。
 - **研发侧**:请认领 R1、R2(含 **F1** butler envelope 不一致、**F2** commission update config 400)、R4,并确认 F1/F2 的正确形态。
 - **研发侧**:请认领 R1、R2(含 **F1** butler envelope 不一致、**F2** commission update config 400)、R4,并确认 F1/F2 的正确形态。
 - **本机执行项**(Java 单测 / Python pytest):按 `runbook.md` §3.1–§3.3 在开发机执行,结果回填 `.tdd/test-progress.json` 后刷新共享台账。
 - **本机执行项**(Java 单测 / Python pytest):按 `runbook.md` §3.1–§3.3 在开发机执行,结果回填 `.tdd/test-progress.json` 后刷新共享台账。
+
+## 7. 全量 API 级 E2E 实跑结果(2026-11-02,step 1 复跑)
+
+- 范围:对 `cfc.iwintrue.com` 跑**全部可在远程执行的 API 级 spec**(共 10 个:`e2e/api/` 下 7 个 + 3 个 `admin-*.spec.js`),使用测试账号 `13800138000` + 临时无重置配置 `playwright.config.noreset.js`。**69 个用例**,耗时 106s。
+- 权威统计(Playwright `stats`):`expected=59` / `unexpected=7` / `skipped=3`(**无 `passed`**)。
+  - `expected`(59) = 标注 `test.fail()`「预期失败」的用例——用例本就**预期失败**(documenting 已知缺陷),并非功能正常的正向确认。
+  - `unexpected`(7) = **真实失败**(预期应通过却失败,即真实缺陷)。
+  - **结论:整套 API 级 E2E 没有 1 个用例在正向确认功能可用**;59 个"预期失败"只是把已知缺陷固定为 `test.fail()` 标注,CI 即便跑过也是"绿灯"但功能实际是坏的。
+- 注:§4–§5(2026-11-01)按约定把 `test.fail()` 标注用例计为"通过";本次以 Playwright 真实 `stats` 重述:`admin-activity-review`(2)、`admin-butler-review`(2 预期+4 真实)、`admin-commission-config`(3 预期+1 真实) 等"通过"项实为**预期失败(已知缺陷)**,全 10 个 spec 无正向通过。
+
+### 7.1 真实缺陷(unexpected=7,需研发处理)
+
+| 文件 | 用例 | 实际失败 | 根因 / 归属 |
+|---|---|---|---|
+| admin-butler-review | list pending | 断言 `data.records`,接口返回 `data.list` | **F1 复跑确认**:butler 列表 envelope 不一致(R2/F1),**仍未修复** |
+| admin-butler-review | list approved for assignment | 同上 | F1,**仍未修复** |
+| admin-butler-review | review action (approve) | `data.records[0]` 取空崩溃(TypeError) | F1 连带:写请求卡在取数未发出,无副作用 |
+| admin-butler-review | assign member to approved butler | `data.records[0]` 取空崩溃 | F1 连带,无副作用 |
+| admin-commission-config | update config | `POST` 返回 **400**(期望 200) | **F2 复跑确认**:commission update config 400,**仍未修复**(真实接口响应) |
+| api/nonfunc-security | TC-A-N05 非管理员访问后台接口被拒 | 未登录 `/api/admin-auth/login` 返回 **500**(应为 401/403,msg=手机号和验证码不能为空) | **新缺陷 R5**:未授权/admin-auth 登录未做鉴权前置,异常暴露 500 |
+| api/nonfunc-security | TC-P-N11 报告上传非 PDF 被拒 | 上传非 PDF 报告未被拒(非 4xx) | **新缺陷 R6**:报告上传未做文件类型/安全校验 |
+
+### 7.2 测试侧阻碍更新
+
+- **T5(新增)**:`cfc.iwintrue.com` 仅部署后端 API,未托管前端 SPA(非 API 路径返回白标 404)。约 38 个依赖 `page.goto`/DOM 的 UI 级 `e2e/*.spec.js` 在远程**无法运行**,已排除执行;这些 UI 用例需在**部署了前端的测试环境**或**本地**执行。
+- T4 仍有效(建议研发给 `db.js` 加 `SKIP_DB_RESET` 开关)。
+
+### 7.3 测试成熟度结论(重要)
+
+当前 `e2e/api/*` 与 `admin-*` 全部以 `test.fail()` 标注运行:文章(7)/联系人(6)/能量(8)/家庭成员(13)/性能兼容(5)/安全(9) 等模块端到端**整体处于"预期失败"状态**,无正向断言确认功能可用。建议研发/测试协同:
+- 对**已修复**功能:翻转 `test.fail()` → 真实断言,使 CI 能回归拦截;
+- 对**确实缺陷**:保留 `test.fail()` 但单独登记为缺陷(如 F1/F2/R5/R6)跟踪,避免"绿灯但功能坏"的假象。
+
+### 7.4 下一步
+
+- 测试侧:T5 已识别;可转向本机执行 Java 单测 / Python pytest(runbook §3.1–§3.3),结果回填 sidecar。
+- 研发侧:认领 **R5(N05 500)、R6(N11 非 PDF 上传未拒)** 两个新安全/合规缺陷;**F1、F2 复跑确认仍未修复**(R2 项)。