Просмотр исходного кода

Merge branch 'task/S-cfc-182' into cfclub

Sisyphus Agent 59 минут назад
Родитель
Сommit
c6f775ab21

+ 10 - 0
.tdd/_r189_admin_live.log

@@ -0,0 +1,10 @@
+
+Running 5 tests using 1 worker
+
+[1/5] [admin-desktop] › e2e-live\admin-live.spec.js:117:3 › 管理端 UI · 登录与主框架 › TC-A-U01 登录页可渲染(标题/账号/密码/登录按钮)
+[2/5] [admin-desktop] › e2e-live\admin-live.spec.js:129:3 › 管理端 UI · 登录与主框架 › TC-A-U02 滑块人机验证存在且可拖动通过
+[3/5] [admin-desktop] › e2e-live\admin-live.spec.js:145:3 › 管理端 UI · 登录与主框架 › TC-A-U03 未登录访问后台受保护路由被拦截到登录页
+[4/5] [admin-desktop] › e2e-live\admin-live.spec.js:156:3 › 管理端 UI · 登录与主框架 › TC-A-U04 管理员真实登录(滑块 + 凭据)进入后台主框架
+[5/5] [admin-desktop] › e2e-live\admin-live.spec.js:184:3 › 管理端 UI · 登录与主框架 › TC-A-U05 后台核心菜单可访问(用户管理/数据看板)
+  5 passed (1.4m)
+EXIT=0

+ 44 - 0
.tdd/_r189_api.log

@@ -0,0 +1,44 @@
+
+Running 32 tests using 1 worker
+
+[1/32] [desktop] › e2e\api\api-smoke.spec.js:18:3 › API级冒烟(远程后端) › 自注册链路可用(拿到有效 token)
+[2/32] [desktop] › e2e\api\api-smoke.spec.js:24:3 › API级冒烟(远程后端) › 家庭成员列表接口可调用 (code=200)
+[3/32] [desktop] › e2e\api\api-smoke.spec.js:30:3 › API级冒烟(远程后端) › 能量概览接口可调用 (code=200)
+[4/32] [desktop] › e2e\api\api-smoke.spec.js:36:3 › API级冒烟(远程后端) › 成员列表参数校验生效(越权家庭 → 403)
+[5/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:56:1 › [TC-G-N03] 非微信H5兜底登录:手机号注册登录路径 UA 无关
+[6/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:63:1 › [TC-G-N02/P-N06/C-N03/T-N04/S-N03/X-N07] 多端 UA 兼容:同请求不同客户端返回一致
+[7/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:79:1 › [TC-A-N04/X-N02] 限流熔断稳定性:爆发请求下系统不死(不出现 5xx 雪崩)
+[desktop] › e2e\api\nonfunc-perf-compat.spec.js:79:1 › [TC-A-N04/X-N02] 限流熔断稳定性:爆发请求下系统不死(不出现 5xx 雪崩)
+[限流] 状态分布=[200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200] 其中429=0
+
+[8/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:92:1 › [TC-P-N02/X-N01] 并发不串数据:并行 AI 请求各自独立响应
+[9/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:117:1 › [响应时间基线] 已登录家庭列表单请求耗时冒烟 ≤ 8s
+[desktop] › e2e\api\nonfunc-perf-compat.spec.js:117:1 › [响应时间基线] 已登录家庭列表单请求耗时冒烟 ≤ 8s
+[耗时] 家庭列表 92ms
+
+[10/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:128:6 › [TC-C-N01/X-N04] 任务打卡幂等:重复提交不重复计分(需任务流夹具)
+[11/32] [desktop] › e2e\api\nonfunc-perf-compat.spec.js:133:6 › [TC-X-N03] 活动名额并发不超卖:100 名额 / 瞬时 500 请求(需活动夹具 + 压测授权)
+[12/32] [desktop] › e2e\api\nonfunc-security.spec.js:50:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问能量概览被拒(401/403)
+[13/32] [desktop] › e2e\api\nonfunc-security.spec.js:55:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权访问家庭成员列表被拒(401/403)
+[14/32] [desktop] › e2e\api\nonfunc-security.spec.js:60:3 › 非功能/安全接口冒烟 › [TC-G-N04] 未授权调用 AI 健康教练被拒(401/403)
+[15/32] [desktop] › e2e\api\nonfunc-security.spec.js:66:3 › 非功能/安全接口冒烟 › [TC-P-N09] IDOR:越权访问他人家庭成员列表 → 403
+[16/32] [desktop] › e2e\api\nonfunc-security.spec.js:78:3 › 非功能/安全接口冒烟 › [TC-A-N05] 非管理员访问后台接口被拒(401/403)
+[17/32] [desktop] › e2e\api\nonfunc-security.spec.js:84:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换接口未授权被拒(401/403)
+[18/32] [desktop] › e2e\api\nonfunc-security.spec.js:89:3 › 非功能/安全接口冒烟 › [TC-C-N07] 权限提升防护:家长不可切换为未持有角色
+[19/32] [desktop] › e2e\api\nonfunc-security.spec.js:96:3 › 非功能/安全接口冒烟 › [TC-C-N07] 角色切换自身合法角色正常(基线)
+[20/32] [desktop] › e2e\api\nonfunc-security.spec.js:104:3 › 非功能/安全接口冒烟 › [TC-P-N10] AI 健康教练 XSS:query 注入脚本不回显原始脚本且不错 500
+[21/32] [desktop] › e2e\api\nonfunc-security.spec.js:112:3 › 非功能/安全接口冒烟 › [TC-A-N06] 活动反馈存储型 XSS:提交含脚本 comment,列表不回显原始脚本
+[22/32] [desktop] › e2e\api\nonfunc-security.spec.js:133:3 › 非功能/安全接口冒烟 › [TC-P-N11] 报告上传非 PDF/恶意内容被拒(非 200)
+[23/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:38:3 › SC-P-94 历史完成任务三类流 › TC-P-94 正常流:分页结构完整且仅返回已完成记录
+[24/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:50:3 › SC-P-94 历史完成任务三类流 › TC-P-94-E 异常流:非法分页/非法 category 不 5xx 且结构稳定
+[25/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:66:3 › SC-P-94 历史完成任务三类流 › TC-P-94-P 权限流:传非本家庭 memberId 不返回他人任务数据
+[26/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:82:3 › SC-P-95 成长历史记录三类流 › TC-P-95 正常流:打卡记录流返回可遍历数组
+[27/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:88:3 › SC-P-95 成长历史记录三类流 › TC-P-95-E 异常流:非法筛选与非法分页不 5xx
+[28/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:101:3 › SC-P-95 成长历史记录三类流 › TC-P-95-P 权限流:非本家庭 memberId 不返回他人打卡记录
+[29/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:114:8 › 契约缺口待修复(2026-11-10 实测) › TC-P-95:/api/growth/record/list 带/不带 memberId 均返回 code=500「服务器内部错误」,成长档案记录聚合口径未落地
+[30/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:116:8 › 契约缺口待修复(2026-11-10 实测) › TC-C-26:睡眠选项配置读取契约未落地 —— /api/health/sleep/tags 返回 404;/api/config/public/value 带 key=sleep.quality.tags 返回 code=500
+[31/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:118:8 › 契约缺口待修复(2026-11-10 实测) › TC-A-27-S:后台维护契约未落地 —— /api/admin/sleep/tags 返回 404;需确认是否改由 /api/admin/config/* 通用配置承载
+[32/32] [desktop] › e2e\api\traceability-p94-p95-c26.spec.js:120:8 › 契约缺口待修复(2026-11-10 实测) › SC-P-96 / 前端页面类断言:远程环境未托管前端 SPA,纯 UI 与页面跳转断言需本地/真机环境执行
+  7 skipped
+  25 passed (28.0s)
+API_EXIT=0

+ 13 - 0
.tdd/_r189_fe_jest.log

@@ -0,0 +1,13 @@
+          |                         ^
+      288 |     // 全为无效记录 → 空分组
+      289 |     expect(invokeGrouping(component, [{ checkinDate: 'bad' }, { foo: 1 }]).length).toBe(0)
+      290 |   })
+
+      at Object.<anonymous> (__tests__/pages/growth-main/growthHistory.dayGroupView.test.js:287:25)
+
+
+Test Suites: 2 failed, 40 passed, 42 total
+Tests:       3 failed, 12 skipped, 609 passed, 624 total
+Snapshots:   0 total
+Time:        172.323 s
+FE_EXIT=0

+ 11 - 0
.tdd/_r189_frontend_live.log

@@ -0,0 +1,11 @@
+
+Running 6 tests using 1 worker
+
+[1/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:47:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U01 首页可渲染(标题/落地路由/TabBar 四项)
+[2/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:72:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U02 首页核心内容渲染(五维沙盘 / 三步引导)
+[3/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:86:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U03 TabBar 切换到「健康」正常跳转且无异常
+[4/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:104:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U04 TabBar 切换到「成长」正常跳转
+[5/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:117:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U05 未登录访问「我的」应出现登录/注册入口(鉴权引导)
+[6/6] [frontend-mobile] › e2e-live\frontend-live.spec.js:126:3 › 小程序 H5 UI · 游客浏览与导航 › TC-F-U06 首屏关键资源加载无失败(无 requestfailed)
+  6 passed (46.2s)
+EXIT=0

+ 57 - 0
.tdd/_r189_health.log

@@ -0,0 +1,57 @@
+
+Running 13 tests using 1 worker
+
+[1/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U01 POST /api/huawei-health/auth-url 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U01 POST /api/huawei-health/auth-url 未鉴权应被拒绝(401/403)
+[TC-H-U01] POST /api/huawei-health/auth-url -> HTTP 401
+
+[2/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U02 POST /api/huawei-health/callback 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U02 POST /api/huawei-health/callback 未鉴权应被拒绝(401/403)
+[TC-H-U02] POST /api/huawei-health/callback -> HTTP 401
+
+[3/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U03 POST /api/huawei-health/sync 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U03 POST /api/huawei-health/sync 未鉴权应被拒绝(401/403)
+[TC-H-U03] POST /api/huawei-health/sync -> HTTP 401
+
+[4/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U04 POST /api/huawei-health/revoke 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U04 POST /api/huawei-health/revoke 未鉴权应被拒绝(401/403)
+[TC-H-U04] POST /api/huawei-health/revoke -> HTTP 401
+
+[5/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U05 POST /api/huawei-health/status 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U05 POST /api/huawei-health/status 未鉴权应被拒绝(401/403)
+[TC-H-U05] POST /api/huawei-health/status -> HTTP 401
+
+[6/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U06 POST /api/xiaomi-health/auth-url 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U06 POST /api/xiaomi-health/auth-url 未鉴权应被拒绝(401/403)
+[TC-H-U06] POST /api/xiaomi-health/auth-url -> HTTP 401
+
+[7/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U07 POST /api/xiaomi-health/callback 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U07 POST /api/xiaomi-health/callback 未鉴权应被拒绝(401/403)
+[TC-H-U07] POST /api/xiaomi-health/callback -> HTTP 401
+
+[8/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U08 POST /api/xiaomi-health/sync 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U08 POST /api/xiaomi-health/sync 未鉴权应被拒绝(401/403)
+[TC-H-U08] POST /api/xiaomi-health/sync -> HTTP 401
+
+[9/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U09 POST /api/xiaomi-health/revoke 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U09 POST /api/xiaomi-health/revoke 未鉴权应被拒绝(401/403)
+[TC-H-U09] POST /api/xiaomi-health/revoke -> HTTP 401
+
+[10/13] [health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U10 POST /api/xiaomi-health/status 未鉴权应被拒绝(401/403)
+[health-api] › e2e-live\health-contract.spec.js:41:5 › 华为/小米运动健康接入 · 鉴权契约(§4.43/§4.44) › TC-H-U10 POST /api/xiaomi-health/status 未鉴权应被拒绝(401/403)
+[TC-H-U10] POST /api/xiaomi-health/status -> HTTP 401
+
+[11/13] [health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U01 POST /api/health/plan/adjust 未鉴权应被拒绝(401/403) · HL-04/R4 健康方案对话式调整
+[health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U01 POST /api/health/plan/adjust 未鉴权应被拒绝(401/403) · HL-04/R4 健康方案对话式调整
+[TC-HP-U01] POST /api/health/plan/adjust -> HTTP 401
+
+[12/13] [health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U02 POST /api/health/plan/attribution 未鉴权应被拒绝(401/403) · HL-03/R2 健康方案归因
+[health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U02 POST /api/health/plan/attribution 未鉴权应被拒绝(401/403) · HL-03/R2 健康方案归因
+[TC-HP-U02] POST /api/health/plan/attribution -> HTTP 401
+
+[13/13] [health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U03 POST /api/health/plan/generate 未鉴权应被拒绝(401/403) · HL-03/R3 生成不确定点补充(followUpAnswers)
+[health-api] › e2e-live\health-contract.spec.js:74:5 › 健康方案 · 鉴权契约(§4.49.1/§4.49.2) › TC-HP-U03 POST /api/health/plan/generate 未鉴权应被拒绝(401/403) · HL-03/R3 生成不确定点补充(followUpAnswers)
+[TC-HP-U03] POST /api/health/plan/generate -> HTTP 401
+
+  13 passed (4.2s)
+HEALTH_EXIT=0

+ 11 - 0
.tdd/_r189_root_jest.log

@@ -0,0 +1,11 @@
+
+    Cause:
+    AggregateError:
+
+
+
+Test Suites: 2 failed, 2 total
+Tests:       16 failed, 7 passed, 23 total
+Snapshots:   0 total
+Time:        9.795 s, estimated 11 s
+ROOT_EXIT=0

+ 9 - 0
.tdd/_r189_shop_api.log

@@ -0,0 +1,9 @@
+
+Running 4 tests using 1 worker
+
+[1/4] [shop-api] › e2e-live\shop-sort-api.spec.js:37:3 › 商城价格排序 · 后端排序契约(需求变更 S1) › TC-S-U01 price asc 生效(对应 buildSort → price_asc)
+[2/4] [shop-api] › e2e-live\shop-sort-api.spec.js:45:3 › 商城价格排序 · 后端排序契约(需求变更 S1) › TC-S-U02 price desc 生效(对应 buildSort → price_desc)
+[3/4] [shop-api] › e2e-live\shop-sort-api.spec.js:53:3 › 商城价格排序 · 后端排序契约(需求变更 S1) › TC-S-U03 默认排序不变(对应 buildSort → default,不传 sort)
+[4/4] [shop-api] › e2e-live\shop-sort-api.spec.js:61:3 › 商城价格排序 · 后端排序契约(需求变更 S1) › TC-S-U04 非法排序列被白名单拦截(不 5xx、不注入)
+  4 passed (6.9s)
+SHOP_EXIT=0

+ 11 - 0
.tdd/_r189_web_jest.log

@@ -0,0 +1,11 @@
+PASS src/views/admin/review/__tests__/auditRowMapping.spec.js
+PASS src/__tests__/Families.actionMenu.spec.js
+PASS src/__tests__/views/FamiliesReportEntry.spec.js
+PASS src/__tests__/views/FamiliesPlanEntry.spec.js
+PASS src/__tests__/utils/indicatorSeeds.test.js
+
+Test Suites: 17 passed, 17 total
+Tests:       116 passed, 116 total
+Snapshots:   0 total
+Time:        208.842 s
+WEB_EXIT=0

+ 62 - 0
_r189_189_admin.cjs

@@ -0,0 +1,62 @@
+// R162: 189 admin-live UI E2E kick/read(String.raw 保反斜杠路径,修复 Location not found)
+const BASE = process.env.BASE_189 || 'http://192.168.16.189:4090';
+const AUTH = 'Basic ' + Buffer.from('opencode:' + (process.env.OPENCODE_SERVER_PASSWORD || 'IwinTrue@123')).toString('base64');
+const H = { Authorization: AUTH, 'Content-Type': 'application/json' };
+const CWD = String.raw`C:\code\cfc`;
+const LOC = '?location%5Bdirectory%5D=' + encodeURIComponent(CWD);
+const LOG = String.raw`C:\code\cfc\_r189_admin-live_test.log`;
+const SLEEP = ms => new Promise(r => setTimeout(r, ms));
+
+function buildKickCmd() {
+  return [
+    'cd ' + CWD,
+    'if (Test-Path ' + LOG + ') { Remove-Item ' + LOG + ' -Force }',
+    `Start-Process -FilePath cmd.exe -ArgumentList '/c','cd /d ${CWD}\\tests && set PLAYWRIGHT_HTML_REPORT=false && npx playwright test -c playwright.config.live.js --project=admin-desktop --reporter=line > ${LOG} 2>&1' -WindowStyle Hidden -PassThru | Select-Object Id`,
+    'start-sleep -Seconds 3',
+    'echo KICKED'
+  ].join('; ');
+}
+function buildReadCmd() {
+  return [
+    'echo READ_BEGIN',
+    'if (Test-Path ' + LOG + ') { Get-Content ' + LOG + ' -Tail 200 }',
+    'if (Test-Path ' + LOG + '.err) { echo ERR_BEGIN; Get-Content ' + LOG + '.err -Tail 30 }',
+    'echo READ_END'
+  ].join('; ');
+}
+async function j(url, opt) {
+  try {
+    const r = await fetch(url, Object.assign({ headers: H }, opt));
+    const t = await r.text();
+    try { return { status: r.status, json: JSON.parse(t) }; } catch { return { status: r.status, text: t }; }
+  } catch (e) { return { status: 0, err: e.message }; }
+}
+async function openShell(cmd, capMs = 30000) {
+  const cr = await j(BASE + '/api/shell' + LOC, { method: 'POST', body: JSON.stringify({ command: cmd, cwd: CWD }) });
+  const cj = (cr.json) || {};
+  const id = (cj.data && cj.data.id) || cj.id;
+  if (!id) return { err: 'create failed ' + cr.status + ' ' + JSON.stringify(cj).slice(0, 200), id: null };
+  const t0 = Date.now();
+  while (Date.now() - t0 < capMs) {
+    await SLEEP(2000);
+    const s = await j(BASE + '/api/shell/' + id + LOC);
+    const d = (s.json && s.json.data) || null;
+    if (d && d.status && d.status !== 'running') return { id, status: d.status };
+    if (!d) continue;
+  }
+  return { id, status: 'timeout' };
+}
+(async () => {
+  const mode = process.argv[2] || 'kick';
+  if (mode === 'kick') {
+    const k = await openShell(buildKickCmd(), 30000);
+    console.log('KICK', k.err || ('id=' + k.id + ' status=' + k.status));
+    return;
+  }
+  const r = await openShell(buildReadCmd(), 30000);
+  if (r.err) { console.log('READ_ERR', r.err); process.exit(1); }
+  const o = await j(BASE + '/api/shell/' + r.id + '/output' + LOC + '&limit=200000');
+  console.log('OUT_BEGIN');
+  console.log((o.json && o.json.data && o.json.data.output) || '(empty)');
+  console.log('OUT_END');
+})().catch(e => { console.error('ERR', e.message); process.exit(1); });

+ 62 - 0
_r189_251_lg.cjs

@@ -0,0 +1,62 @@
+// R150 251 langgraph 派发器:kick(分离启动)+ read(单次读日志),不在等待期新建 shell(B-125)
+const BASE = process.env.BASE || 'http://192.168.16.251:4096';
+const DIR = process.env.DIR || '/sc-data/cfc/cfc-langgraph';
+const LOG = process.env.LOG || '/tmp/r189_pytest.log';
+const AUTH = 'Basic ' + Buffer.from('opencode:' + (process.env.OPENCODE_SERVER_PASSWORD || 'IwinTrue@123')).toString('base64');
+const H = { Authorization: AUTH, 'Content-Type': 'application/json' };
+const LOC = '?location%5Bdirectory%5D=' + encodeURIComponent(DIR);
+
+async function j(url, opt) {
+  try {
+    const r = await fetch(url, Object.assign({ headers: H }, opt || {}));
+    const t = await r.text();
+    try { return { status: r.status, json: JSON.parse(t) }; } catch { return { status: r.status, text: t }; }
+  } catch (e) { return { status: 0, err: e.message }; }
+}
+
+async function sh(cmd, capMs) {
+  const cr = await j(BASE + '/api/shell' + LOC, { method: 'POST', body: JSON.stringify({ command: cmd, cwd: DIR }) });
+  const id = cr.json && cr.json.data && cr.json.data.id;
+  if (!id) return { err: 'create ' + cr.status + ' ' + JSON.stringify(cr).slice(0, 200) };
+  const t0 = Date.now();
+  while (Date.now() - t0 < (capMs || 60000)) {
+    await new Promise(r => setTimeout(r, 2500));
+    const s = await j(BASE + '/api/shell/' + id + LOC);
+    const d = (s.json && s.json.data) || null;
+    if (!d) continue;
+    if (d.status && d.status !== 'running') {
+      const o = await j(BASE + '/api/shell/' + id + '/output' + LOC + '&limit=200000');
+      return { code: d.status, out: (o.json && o.json.data && o.json.data.output) || '' };
+    }
+  }
+  return { err: 'timeout' };
+}
+
+(async () => {
+  const mode = process.argv[2] || 'kick';
+  // R173 增:LOG 若从本机 env 注入,Git Bash(MSYS) 会把 /tmp/x 改写成 C:/Users/.../x,
+  // 远端 `tail` 恒报 No such file,且 kick 的重定向也会失败 → 看起来像「日志没生成」。
+  // 这里直接挡住 Windows 风格路径,强制调用方使用远端 POSIX 路径。
+  if (LOG.includes(':') || LOG.includes('\\')) {
+    console.error('BAD_LOG_PATH=' + LOG + ' 请使用远端 POSIX 路径(如 /tmp/rX_pytest.log),不要经由本地 env 注入');
+    process.exit(2);
+  }
+  if (mode === 'kick') {
+    // R156 修:251 系统 /usr/bin/python 无 pytest,必须用节点 venv(.venv/bin/python → python3.11);
+    // 退出码另存变量后再写盘(B-126:$? 直接内联在 kick 串里可能落盘失败)。
+    // R173 复现(B-126 第 6 轮):手工 kick 用 `echo EXIT=$?` 时 186 行日志零 EXIT 行;
+    // 已在 /tmp/r173_probe.log 验证「先存 rc 再落盘」可写入 → 保留 rc 写法为唯一正确姿势。
+    const inner = "cd " + DIR + " && .venv/bin/python -m pytest -q --ignore=tests/qna --ignore=tests/test_chat.py > " + LOG + " 2>&1; rc=$?; echo EXIT=$rc >> " + LOG;
+    const cmd = "rm -f " + LOG + "; setsid nohup bash -c '" + inner + "' >/dev/null 2>&1 & echo KICKED";
+    const r = await sh(cmd, 40000);
+    console.log('KICK=' + JSON.stringify(r).slice(0, 400));
+    const h = await sh('cd ' + DIR + ' && git rev-parse --short HEAD; date', 30000);
+    console.log('NODE_HEAD=' + ((h.out || h.err || '').trim()));
+  } else if (mode === 'read') {
+    const r = await sh('tail -c 4000 ' + LOG, 45000);
+    console.log(r.err ? 'READ_ERR=' + r.err : r.out);
+  } else if (mode === 'run') {
+    const r = await sh(process.argv[3], 120000);
+    console.log(r.err ? 'ERR=' + r.err : r.out);
+  }
+})();

+ 243 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyAutoCreateForPurchaseContractTest.java

@@ -0,0 +1,243 @@
+package com.etotem.cfc.unit;
+
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.controller.MembershipController;
+import com.etotem.cfc.dto.PaymentOrderDTO;
+import com.etotem.cfc.entity.User;
+import com.etotem.cfc.mapper.UserMapper;
+import com.etotem.cfc.service.MembershipService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * 契约测试:能力键 {@code family.family.autoCreateForPurchase}(S-cfc-188,SC-P-58 购买会员/套餐)。
+ *
+ * <p><b>需求/溯源(tests/user-scenarios/应用场景总览.md SC-P-58 · 购买会员/套餐,业务域 F 商城与会员)</b></p>
+ * <blockquote>
+ *   目标:解锁高级能力。流程:选档位 → 支付 → 权益生效。边界:支付失败回滚;重复购买幂等。
+ *   用户实测反馈:新用户({@code familyId==null})在「我的」页/会员中心点「立即开通」后<b>下单被拦</b>
+ *   (MembershipController /upgrade 199 行 createOrder 的 familyId==null 抛错、/plan/purchase 287-299 行
+ *   noFamily 守卫),无法自助开通;期望:<b>无家庭新用户购买会员时自动创建初始家庭并完成购买</b>。
+ * </blockquote>
+ *
+ * <p><b>设计/溯源(docs/superpowers/api/API_REFERENCE.md §4.50 会员权益对比表 + §4.50.1 会员档位购买;
+ * docs/tdd/orchestration/sc-key-map.md SC-P-58)</b></p>
+ * <ul>
+ *   <li>SC-P-58 已登记 1:N 键 {@code membership.plan.purchase, family.family.autoCreateForPurchase}
+ *       (问题1「新用户无开通入口」裁决走方案A:<b>购买时自动创建家庭</b>)。</li>
+ *   <li>修复方向:MembershipController 三处 {@code getUserFamilyId} 改 {@code getOrCreateUserFamilyId}
+ *       (upgradeOrder L199 / activateTrial L224 / createOrder L245);/plan/purchase 无家庭
+ *       noFamily 守卫<b>保留兜底</b>(get-or-create 仍无法获得家庭时才拒绝)。</li>
+ *   <li>{@code MembershipService#getOrCreateUserFamilyId}(MembershipService L114-138,@Transactional)
+ *       已存在:用户无家庭时自动创建初始家庭(昵称+「的家庭」、UUID 邀请码、creator/isFamilyAdmin,
+ *       并回写 {@code user.familyId})——购买链路复用它即可与既有「微信用户被踢后迁入自有家庭」语义保持一致。</li>
+ *   <li>同类宿主先例:MindFortuneController 已在读路径直接使用 {@code getOrCreateUserFamilyId}。</li>
+ * </ul>
+ *
+ * <p><b>RED 预期</b>:上述调用点当前仍走 {@code getUserFamilyId}(新用户返回 null → /upgrade|/trial|/orders
+ * 落单被拦、/plan/purchase 被 noFamily 守卫拒绝),「自动创建初始家庭并完成购买」契约行为未落地,
+ * 以下主断言用例在当前实现应失败(红);GREEN 阶段按修复方向落地后自动转绿。</p>
+ *
+ * <p><b>测试范围</b>:纯 Mockito + 反射注入(无 Spring / 无 DB / 无真实微信);宿主
+ * {@link MembershipController} 直接实例化,私有注入点(membershipService / userMapper / testMode)
+ * 用反射注入,风格与同批 MembershipPlanPurchaseContractTest / FamilyJoinValidationRulesContractTest 一致。</p>
+ */
+class FamilyAutoCreateForPurchaseContractTest {
+
+    private static final String KEY = "[family.family.autoCreateForPurchase]";
+
+    private static final Long USER_ID = 1L;
+    /** get-or-create 为该无家庭新用户产出的初始家庭 ID */
+    private static final Long AUTO_CREATED_FAMILY_ID = 888L;
+
+    private MembershipController controller;
+    private MembershipService membershipService;
+    private UserMapper userMapper;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        controller = new MembershipController();
+        membershipService = mock(MembershipService.class);
+        userMapper = mock(UserMapper.class);
+        inject(controller, "membershipService", membershipService);
+        inject(controller, "userMapper", userMapper);
+    }
+
+    // ==================== 正常流:无家庭新用户购买 → 自动创建初始家庭并完成购买 ====================
+
+    @Test
+    @DisplayName("正常流-1:/upgrade 无家庭新用户下单必须走 getOrCreateUserFamilyId 自动建家庭后落单")
+    void upgradeOrder_newUserNoFamily_mustAutoCreateFamilyBeforeCreateOrder() {
+        when(userMapper.selectById(USER_ID)).thenReturn(newUserWithoutFamily());
+        // 契约:get-or-create 为该用户产出初始家庭(自动创建并回写 user.familyId)
+        when(membershipService.getOrCreateUserFamilyId(USER_ID)).thenReturn(AUTO_CREATED_FAMILY_ID);
+        PaymentOrderDTO created = order("MO_UP_AUTO_001", AUTO_CREATED_FAMILY_ID);
+        when(membershipService.createOrder(eq(USER_ID), eq(AUTO_CREATED_FAMILY_ID),
+                eq("FAMILY"), eq("yearly"), eq("yearly"), isNull())).thenReturn(created);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("levelCode", "FAMILY");
+        params.put("paymentType", "yearly");
+        params.put("period", "yearly");
+
+        Result<PaymentOrderDTO> resp = controller.upgradeOrder(params, USER_ID);
+
+        // 契约主断言:购买必须走 get-or-create(当前走 getUserFamilyId → 新用户 familyId=null → 下单被拦)
+        verify(membershipService).getOrCreateUserFamilyId(USER_ID);
+        verify(membershipService, never()).getUserFamilyId(USER_ID);
+        verify(membershipService).createOrder(USER_ID, AUTO_CREATED_FAMILY_ID, "FAMILY", "yearly", "yearly", null);
+        assertNotNull(resp.getData(),
+                KEY + " 无家庭新用户 /upgrade 应自动创建家庭后返回待支付订单,当前下单被拦(familyId=null)。");
+        assertEquals(AUTO_CREATED_FAMILY_ID, resp.getData().getFamilyId(),
+                KEY + " 自动创建的初始家庭应作为订单归属家庭。");
+    }
+
+    @Test
+    @DisplayName("正常流-2:/trial 无家庭新用户激活试用必须走 getOrCreateUserFamilyId 自动建家庭")
+    void activateTrial_newUserNoFamily_mustAutoCreateFamily() {
+        when(userMapper.selectById(USER_ID)).thenReturn(newUserWithoutFamily());
+        when(membershipService.getOrCreateUserFamilyId(USER_ID)).thenReturn(AUTO_CREATED_FAMILY_ID);
+        PaymentOrderDTO trial = order("MO_TRIAL_AUTO_001", AUTO_CREATED_FAMILY_ID);
+        trial.setStatus("paid");
+        when(membershipService.createOrder(eq(USER_ID), eq(AUTO_CREATED_FAMILY_ID),
+                eq("FAMILY"), eq("trial"), isNull(), isNull())).thenReturn(trial);
+
+        Result<PaymentOrderDTO> resp = controller.activateTrial(USER_ID);
+
+        verify(membershipService).getOrCreateUserFamilyId(USER_ID);
+        verify(membershipService, never()).getUserFamilyId(USER_ID);
+        verify(membershipService).createOrder(USER_ID, AUTO_CREATED_FAMILY_ID, "FAMILY", "trial", null, null);
+        assertNotNull(resp.getData(),
+                KEY + " 无家庭新用户 /trial 应自动创建家庭后返回试用订单,当前被拦(familyId=null)。");
+        assertEquals(AUTO_CREATED_FAMILY_ID, resp.getData().getFamilyId(),
+                KEY + " 自动创建的初始家庭应作为试用订单归属家庭。");
+    }
+
+    @Test
+    @DisplayName("正常流-3:/orders 无家庭新用户下单必须走 getOrCreateUserFamilyId 自动建家庭后落单")
+    void createOrder_ordersEndpoint_newUserNoFamily_mustAutoCreateFamily() throws Exception {
+        setTestModeOn(controller); // 模拟支付开关:走 MembershipService.createOrder 落单路径(不触碰微信)
+        when(userMapper.selectById(USER_ID)).thenReturn(newUserWithoutFamily());
+        when(membershipService.getOrCreateUserFamilyId(USER_ID)).thenReturn(AUTO_CREATED_FAMILY_ID);
+        PaymentOrderDTO created = order("MO_ORD_AUTO_001", AUTO_CREATED_FAMILY_ID);
+        when(membershipService.createOrder(eq(USER_ID), eq(AUTO_CREATED_FAMILY_ID),
+                eq("FAMILY"), eq("yearly"), eq("yearly"), isNull())).thenReturn(created);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("levelCode", "FAMILY");
+        params.put("paymentType", "yearly");
+        params.put("period", "yearly");
+
+        Result<Object> resp = controller.createOrder(params, USER_ID);
+
+        verify(membershipService).getOrCreateUserFamilyId(USER_ID);
+        verify(membershipService).createOrder(USER_ID, AUTO_CREATED_FAMILY_ID, "FAMILY", "yearly", "yearly", null);
+        assertNotNull(resp.getData(),
+                KEY + " 无家庭新用户 /orders 应自动创建家庭后返回待支付订单,当前被拦(familyId=null)。");
+        PaymentOrderDTO data = (PaymentOrderDTO) resp.getData();
+        assertEquals(AUTO_CREATED_FAMILY_ID, data.getFamilyId(),
+                KEY + " 自动创建的初始家庭应作为订单归属家庭。");
+    }
+
+    @Test
+    @DisplayName("正常流-4:/plan/purchase 无家庭新用户购买档位必须自动建家庭后完成购买")
+    void purchasePlan_newUserNoFamily_mustAutoCreateFamilyAndComplete() {
+        when(userMapper.selectById(USER_ID)).thenReturn(newUserWithoutFamily());
+        when(membershipService.getOrCreateUserFamilyId(USER_ID)).thenReturn(AUTO_CREATED_FAMILY_ID);
+        Map<String, Object> purchaseResp = new HashMap<>();
+        purchaseResp.put("orderNo", "MO_PLAN_AUTO_001");
+        purchaseResp.put("status", "pending");
+        purchaseResp.put("levelCode", "FAMILY");
+        purchaseResp.put("payType", "wechat");
+        when(membershipService.purchasePlan(eq(USER_ID), eq(AUTO_CREATED_FAMILY_ID),
+                eq("FAMILY"), eq("yearly"), isNull())).thenReturn(purchaseResp);
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("levelCode", "FAMILY");
+        params.put("period", "yearly");
+
+        Result<Object> resp = controller.purchasePlan(params, USER_ID);
+
+        // 契约主断言:当前 user.getFamilyId()==null → noFamily(5001) 守卫拒绝,未走 get-or-create(红)。
+        verify(membershipService).getOrCreateUserFamilyId(USER_ID);
+        verify(membershipService).purchasePlan(USER_ID, AUTO_CREATED_FAMILY_ID, "FAMILY", "yearly", null);
+        assertEquals(200, resp.getCode(),
+                KEY + " 无家庭新用户 /plan/purchase 应自动创建家庭后成功返回待支付订单,"
+                        + "当前被 noFamily(5001) 守卫拒绝,无法自助开通。");
+        assertNotNull(resp.getData(), KEY + " 购买成功后应返回待支付订单 + 支付参数。");
+        assertEquals("MO_PLAN_AUTO_001", ((Map<String, Object>) resp.getData()).get("orderNo"),
+                KEY + " 返回的应是自动建家庭后的待支付订单。");
+    }
+
+    // ==================== 权限流:自动建家庭失败时 noFamily 守卫兜底保留 ====================
+
+    @Test
+    @DisplayName("权限流-1:get-or-create 仍无法获得家庭时 /plan/purchase noFamily 守卫兜底拒绝(guard 兜底保留)")
+    void purchasePlan_getOrCreateStillNoFamily_guardKeptRejects() {
+        when(userMapper.selectById(USER_ID)).thenReturn(newUserWithoutFamily());
+        when(membershipService.getOrCreateUserFamilyId(USER_ID)).thenReturn(null); // get-or-create 兜底失败(异常场景)
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("levelCode", "FAMILY");
+
+        Result<Object> resp = controller.purchasePlan(params, USER_ID);
+
+        assertEquals(5001, resp.getCode(),
+                KEY + " 守卫兜底:自动建家庭失败时仍应返回 noFamily(5001)(设计约束「guard 兜底保留」)。");
+        assertTrue(resp.getMessage() != null && resp.getMessage().contains("家庭"),
+                KEY + " noFamily 守卫文案应提示家庭上下文:实际 " + resp.getMessage());
+        verify(membershipService, never()).purchasePlan(USER_ID, null, "FAMILY", "yearly", null);
+    }
+
+    // ==================== 辅助构造 ====================
+
+    /** 新注册用户:无家庭(familyId==null),即「我的」页/会员中心点「立即开通」的实测用户形态 */
+    private User newUserWithoutFamily() {
+        User u = new User();
+        u.setId(USER_ID);
+        u.setFamilyId(null);
+        return u;
+    }
+
+    private static PaymentOrderDTO order(String orderNo, Long familyId) {
+        PaymentOrderDTO dto = new PaymentOrderDTO();
+        dto.setOrderNo(orderNo);
+        dto.setFamilyId(familyId);
+        dto.setLevelCode("FAMILY");
+        dto.setPaymentType("yearly");
+        dto.setAmount(39800);
+        dto.setStatus("pending");
+        dto.setPeriodNo(1);
+        dto.setTotalPeriods(1);
+        return dto;
+    }
+
+    /** 反射注入私有字段(MembershipController 无构造器注入,@Resource 字段为私有域) */
+    private static void inject(Object target, String fieldName, Object value) throws Exception {
+        Field f = target.getClass().getDeclaredField(fieldName);
+        f.setAccessible(true);
+        f.set(target, value);
+    }
+
+    /** 打开 wechat.test-mode 开关(原 @Value("${wechat.test-mode:false}") 私有 boolean 字段) */
+    private static void setTestModeOn(MembershipController c) throws Exception {
+        Field f = MembershipController.class.getDeclaredField("testMode");
+        f.setAccessible(true);
+        f.setBoolean(c, true);
+    }
+}

+ 153 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAssessmentRecordContractTest.java

@@ -0,0 +1,153 @@
+package com.etotem.cfc.unit;
+
+import com.etotem.cfc.entity.DanAssessmentResult;
+import com.etotem.cfc.mapper.DanAssessmentResultMapper;
+import com.etotem.cfc.service.AssessmentService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+/**
+ * 契约级单测:能力键 {@code teacher.assessment.record}(成长规划师域 EVD-10,SC-T-07 边界条款)。
+ *
+ * <p><b>需求 / 设计锚点</b></p>
+ * <ul>
+ *   <li>需求:{@code tests/user-scenarios/应用场景总览.md} SC-T-07「录入测评结果触发方案 ⭐」——
+ *       边界:<b>必填缺失拦截;重复录入覆盖非新增</b>。</li>
+ *   <li>设计:{@code docs/superpowers/specs/2026-11-07-planner-zone-contract.md} §2 SC-T-07 /
+ *       §3 建议能力键映射 {@code teacher.assessment.record}(绑定 SC-T-07 / T-11 / T-12);
+ *       {@code docs/superpowers/api/API_REFERENCE.md} §4.57 SC-T-07 端点载体
+ *       {@code DanAssessmentController /api/dan-assessment/result/record}。</li>
+ *   <li>实现载体:{@code AssessmentService#recordResult(DanAssessmentResult)}
+ *       ({@code cfc-backend/src/main/java/com/etotem/cfc/service/AssessmentService.java})。</li>
+ * </ul>
+ *
+ * <p><b>被校验的契约边界(SC-T-07)</b></p>
+ * <ul>
+ *   <li><b>必填缺失拦截</b>:录入测评结果时,{@code memberId}/{@code familyMemberId} 与
+ *       {@code dimension} 为必填;任一缺失应拦截并<b>不落库</b>(不调用 insert)。</li>
+ *   <li><b>重复录入覆盖非新增</b>:对同一成员(member)+ 同一维度(dimension)重复录入时,应
+ *       <b>覆盖(updateById)</b>既有记录,而非再新增一行(第二次录入不得走 insert)。</li>
+ * </ul>
+ *
+ * <p><b>测试范围</b>:纯 Mockito + 反射注入,无 Spring 上下文 / 无 DB / 无外部服务依赖,
+ * 沿用已合入主链同批 RED 契约测试风格(TeamProfitHookContractTest / FamilyJoinValidationRulesContractTest)。
+ *
+ * <p><b>RED 预期</b>:当前 {@code AssessmentService.recordResult} 既无必填校验、也无重复覆盖逻辑
+ * (对任何入参一律 {@code danAssessmentResultMapper.insert(result)})。以下边界断言在实现补齐前
+ * 均应失败(红);GREEN 阶段由实现方在 {@code recordResult} 补上「必填校验拦截」与
+ * 「同成员+同维度重复录入覆盖(updateById 而非 insert)」后自动转绿。</p>
+ */
+class TeacherAssessmentRecordContractTest {
+
+    private AssessmentService service;
+
+    private DanAssessmentResultMapper resultMapper;
+
+    @BeforeEach
+    void setUp() throws Exception {
+        service = new AssessmentService();
+        // 反射注入全部非 static / 非 final 字段为 mock,隔离 DB / 外部服务;
+        // recordResult 主链仅触及 resultMapper / reportParseService / growthRecordService /
+        // dimensionScoreService / planGenerator / userMapper(其余仅在 parent_upload 分支触及)。
+        injectAll(service);
+        resultMapper = (DanAssessmentResultMapper) readField(service, "danAssessmentResultMapper");
+    }
+
+    // ==================== SC-T-07 边界一:必填缺失拦截 ====================
+
+    @Test
+    @DisplayName("SC-T-07 边界:memberId/familyMemberId 缺失应拦截且不落库(必填缺失拦截)")
+    void recordResult_missingMember_应拦截不落库() {
+        // 无 member 归属(memberId 与 familyMemberId 均为 null)→ 契约要求拦截,不得 insert
+        DanAssessmentResult result = plannerEntryResult();
+        result.setMemberId(null);
+        result.setFamilyMemberId(null);
+
+        service.recordResult(result);
+
+        verify(resultMapper, never()).insert(any(DanAssessmentResult.class));
+    }
+
+    @Test
+    @DisplayName("SC-T-07 边界:dimension 缺失应拦截且不落库(必填缺失拦截)")
+    void recordResult_missingDimension_应拦截不落库() {
+        // dimension 为必填(八类报告归属维度);缺失应拦截,不得 insert
+        DanAssessmentResult result = plannerEntryResult();
+        result.setDimension(null);
+
+        service.recordResult(result);
+
+        verify(resultMapper, never()).insert(any(DanAssessmentResult.class));
+    }
+
+    // ==================== SC-T-07 边界二:重复录入覆盖非新增 ====================
+
+    @Test
+    @DisplayName("SC-T-07 边界:同成员+同维度重复录入应覆盖(updateById)而非新增第二行 insert")
+    void recordResult_duplicateMemberDimension_应覆盖而非新增() {
+        // 同一成员 + 同一维度两次录入 → 第二次应走 updateById 覆盖,insert 仅允许一次(首次)
+        DanAssessmentResult first = plannerEntryResult();   // memberId=55, dimension=mind
+        DanAssessmentResult second = plannerEntryResult();  // 同 memberId=55, dimension=mind
+
+        service.recordResult(first);
+        service.recordResult(second);
+
+        // 首次录入允许 insert;重复录入不得再新增(覆盖语义)
+        verify(resultMapper, times(1)).insert(any(DanAssessmentResult.class));
+        // 覆盖语义:第二次录入必须触发 updateById
+        verify(resultMapper, atLeastOnce()).updateById(any(DanAssessmentResult.class));
+    }
+
+    // ==================== 结构锚点:契约载体存在(防假 RED 对照) ====================
+
+    @Test
+    @DisplayName("结构锚点:AssessmentService.recordResult 契约载体应存在")
+    void recordResult_契约载体存在() throws Exception {
+        assertNotNull(service, "[teacher.assessment.record] AssessmentService 实例应可创建");
+        // recordResult(DanAssessmentResult) 方法应存在于 AssessmentService(端点 /result/record 的服务宿主)
+        java.lang.reflect.Method m = AssessmentService.class.getMethod("recordResult", DanAssessmentResult.class);
+        assertNotNull(m, "[teacher.assessment.record] AssessmentService#recordResult 方法应存在");
+    }
+
+    // ==================== 辅助构造 / 反射 ====================
+
+    /** 构造一条规划师录入(SOURCE_PLANNER_ENTRY)结果:memberId=55 / dimension=mind */
+    private DanAssessmentResult plannerEntryResult() {
+        DanAssessmentResult r = new DanAssessmentResult();
+        r.setMemberId(55L);
+        r.setFamilyMemberId(55L);
+        r.setDimension("mind");
+        r.setFocusScore(80);
+        r.setSource(DanAssessmentResult.SOURCE_PLANNER_ENTRY);
+        return r;
+    }
+
+    /** 反射注入全部非 static / 非 final 字段为对应类型 mock */
+    private static void injectAll(Object target) throws Exception {
+        for (Field f : target.getClass().getDeclaredFields()) {
+            if (Modifier.isStatic(f.getModifiers()) || Modifier.isFinal(f.getModifiers())) {
+                continue;
+            }
+            f.setAccessible(true);
+            f.set(target, mock(f.getType()));
+        }
+    }
+
+    private static Object readField(Object target, String name) throws Exception {
+        Field f = target.getClass().getDeclaredField(name);
+        f.setAccessible(true);
+        return f.get(target);
+    }
+}

+ 313 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanCreateContractTest.java

@@ -0,0 +1,313 @@
+package com.etotem.cfc.unit;
+
+import com.etotem.cfc.common.Result;
+import com.etotem.cfc.controller.growth.GrowthPlanController;
+import com.etotem.cfc.controller.guide.TrainingPlanController;
+import com.etotem.cfc.entity.GrowthPlan;
+import com.etotem.cfc.service.GrowthPlanService;
+import com.etotem.cfc.service.TrainingPlanService;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestAttribute;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * 契约级单测:能力键 {@code teacher.plan.create}(SC-T-08 成长计划 / 套餐创建 · SC-T-14 方案编辑规划师侧)。
+ *
+ * <p><b>契约锚点</b></p>
+ * <ul>
+ *   <li>需求:{@code docs/tdd/orchestration/sc-key-map.md} SC-T-08 / SC-T-14(规划师域)。
+ *       <b>来源追溯</b>:EVD-10 契约核对(commit 77026df42,planner-zone 32 SC 端点核验表),
+ *       能力键注册于 {@code docs/superpowers/specs/2026-11-07-planner-zone-contract.md} §3
+ *       「建议能力键映射」行 {@code teacher.plan.create}(绑定 SC-T-08 / T-14)。</li>
+ *   <li>设计:{@code docs/superpowers/api/API_REFERENCE.md} §4.57 SC-T-08 / SC-T-14 行 ——
+ *       {@code TrainingPlanController /api/guide/training-plans/*}(create/update/list/detail/delete);
+ *       {@code GrowthPlanController /api/growth/plan/create}、{@code /update};
+ *       {@code HealthPlanController /api/health/plan/save}、{@code /generate}。
+ *       角色模型:成长规划师({@code role=teacher}),规划师端点按项目框架约定
+ *       (根 AGENTS.md「角色控制」:控制器内手动检查 {@code @RequestAttribute("role")})
+ *       校验 {@code teacher/admin},与同域端点同构(参照 {@code GuideFamilyQueryController.myFamilies}
+ *       的 {@code RolesUtil.hasTeacherRole(role, roles)} 403 门禁)。</li>
+ * </ul>
+ *
+ * <p><b>实现现状(2026-11-13 实测 origin/cfclub)</b>:端点载体已落地(TrainingPlanController /
+ * GrowthPlanController / HealthPlanController 均在),但<b>规划师端点角色门禁未落地</b>——
+ * {@code TrainingPlanController.createPlan/updatePlan} 与 {@code GrowthPlanController.createPlan/updatePlan}
+ * 均未读取 {@code role}/{@code roles} 请求属性(与同域 {@code GuideFamilyQueryController} /
+ * {@code PlanReviewController} / {@code HealthPlanController.pending-review/*} 等已含
+ * {@code RolesUtil.hasTeacherRole} 门禁的端点不同构),非 teacher 角色亦可创建/修改方案。
+ * 本测试以「权限流角色门禁缺失」为 RED 锚点:断言该契约行为在 GREEN 阶段补齐前失败(红),
+ * 端点/正常流/异常流用例先登记为通过(绿)作为能力键契约证据。</p>
+ *
+ * <p><b>测试范围</b>:纯 Mockito / 反射 / 无 Spring / 无 DB / 无外部服务;断言不依赖真实外部服务。
+ * 三类流:正常流(认证 teacher 创建/更新成功)、异常流(缺 memberId/planId 拒绝且不落库)、
+ * 权限流(角色门禁契约:create/update 端点须暴露 {@code role}/{@code roles} 输入并拒绝非 teacher,
+ * 当前未落地 → 红)。</p>
+ *
+ * <p><b>RED 预期</b>:权限流 4 例(training create/update、growth create/update 的角色门禁
+ * 结构探针)在实现补齐前失败(红),断言原文为「角色门禁未落地」。</p>
+ */
+class TeacherPlanCreateContractTest extends AssessmentPlanContractTestBase {
+
+    // ==================== 端点契约(API_REFERENCE §4.57 SC-T-08 / T-14 载体) ====================
+
+    @Test
+    @DisplayName("端点契约:TrainingPlanController @POST /api/guide/training-plans/* 载体存在")
+    void endpoint_trainingPlan_createUpdateCarriers() {
+        Class<TrainingPlanController> clazz = TrainingPlanController.class;
+        assertClassMapping(clazz, "/api/guide/training-plans",
+                "TrainingPlanController 类级映射应为 /api/guide/training-plans(§4.57 SC-T-08)");
+        assertPostMapping(clazz, "createPlan", "/create",
+                "TrainingPlanController.createPlan 应为 POST /create(§4.57 SC-T-08 套餐创建)");
+        assertPostMapping(clazz, "updatePlan", "/update",
+                "TrainingPlanController.updatePlan 应为 POST /update(§4.57 SC-T-08 套餐编辑)");
+        assertPostMapping(clazz, "getPlanList", "/list",
+                "TrainingPlanController.getPlanList 应为 POST /list(§4.57 SC-T-08 列表)");
+        assertPostMapping(clazz, "getPlanDetail", "/detail",
+                "TrainingPlanController.getPlanDetail 应为 POST /detail(§4.57 SC-T-08 详情)");
+        assertPostMapping(clazz, "deletePlan", "/delete",
+                "TrainingPlanController.deletePlan 应为 POST /delete(§4.57 SC-T-08 删除)");
+    }
+
+    @Test
+    @DisplayName("端点契约:GrowthPlanController @POST /api/growth/plan/* 载体存在")
+    void endpoint_growthPlan_createUpdateCarriers() {
+        Class<GrowthPlanController> clazz = GrowthPlanController.class;
+        assertClassMapping(clazz, "/api/growth/plan",
+                "GrowthPlanController 类级映射应为 /api/growth/plan(§4.57 SC-T-08/T-14)");
+        assertPostMapping(clazz, "createPlan", "/create",
+                "GrowthPlanController.createPlan 应为 POST /create(§4.57 SC-T-08 成长计划创建)");
+        assertPostMapping(clazz, "updatePlan", "/update",
+                "GrowthPlanController.updatePlan 应为 POST /update(§4.57 SC-T-14 方案编辑)");
+        assertPostMapping(clazz, "getActivePlan", "/child/{memberId}/active",
+                "GrowthPlanController.getActivePlan 应为 POST /child/{memberId}/active(§4.57 SC-T-17)");
+    }
+
+    @Test
+    @DisplayName("端点契约:HealthPlanController @POST /api/health/plan/save|generate 载体存在")
+    void endpoint_healthPlan_saveGenerateCarriers() {
+        Class<?> clazz = loadClass("com.etotem.cfc.controller.HealthPlanController");
+        assertNotNull(clazz, "HealthPlanController 类不存在(§4.57 SC-T-14 载体)。");
+        assertClassMapping(clazz, "/api/health/plan",
+                "HealthPlanController 类级映射应为 /api/health/plan(§4.57 SC-T-14)");
+        assertPostMapping(clazz, "save", "/save",
+                "HealthPlanController.save 应为 POST /save(§4.57 SC-T-14 健康方案保存)");
+        assertPostMapping(clazz, "generate", "/generate",
+                "HealthPlanController.generate 应为 POST /generate(§4.57 SC-T-14 健康方案生成)");
+    }
+
+    // ==================== 正常流:认证 teacher 创建方案(行为) ====================
+
+    @Test
+    @DisplayName("SC-T-08 正常:teacher 创建套餐 → 200 返回 planId + 落库(source=manual, status=draft)")
+    void trainingPlan_create_normal_teacher() throws Exception {
+        TrainingPlanService svc = mock(TrainingPlanService.class);
+        TrainingPlanController c = new TrainingPlanController();
+        inject(c, "trainingPlanService", svc);
+        when(svc.createPlan(7L, 10L, "暑期认知训练", "专注力专项", "manual")).thenReturn(501L);
+
+        Map<String, Object> body = new HashMap<>();
+        body.put("memberId", 10L);
+        body.put("title", "暑期认知训练");
+        body.put("description", "专注力专项");
+        Result<Long> r = c.createPlan(7L, body, null);
+
+        assertEquals(200, r.getCode());
+        assertEquals(501L, r.getData());
+        verify(svc).createPlan(7L, 10L, "暑期认知训练", "专注力专项", "manual");
+    }
+
+    @Test
+    @DisplayName("SC-T-08 正常:teacher 创建成长计划 → 200 + teacherId 绑定 + 落库")
+    void growthPlan_create_normal_teacher() throws Exception {
+        GrowthPlanService svc = mock(GrowthPlanService.class);
+        GrowthPlanController c = new GrowthPlanController();
+        inject(c, "growthPlanService", svc);
+        inject(c, "userMapper", mock(com.etotem.cfc.mapper.UserMapper.class));
+        inject(c, "growthPlanMapper", mock(com.etotem.cfc.mapper.GrowthPlanMapper.class));
+        when(svc.createPlan(any(GrowthPlan.class))).thenAnswer(inv -> inv.getArgument(0));
+
+        GrowthPlan plan = new GrowthPlan();
+        plan.setMemberId(10L);
+        plan.setPlanTitle("DAN测评-成长方案");
+        Result<GrowthPlan> r = c.createPlan(plan, 7L);
+
+        assertEquals(200, r.getCode());
+        assertEquals(7L, plan.getTeacherId());
+        assertEquals(7L, r.getData().getTeacherId());
+        verify(svc).createPlan(any(GrowthPlan.class));
+    }
+
+    // ==================== 异常流:缺参拒绝且不落库 ====================
+
+    @Test
+    @DisplayName("SC-T-08 异常:套餐创建缺 memberId → 拒绝,不落库")
+    void trainingPlan_create_exception_missingMemberId() throws Exception {
+        TrainingPlanService svc = mock(TrainingPlanService.class);
+        TrainingPlanController c = new TrainingPlanController();
+        inject(c, "trainingPlanService", svc);
+
+        Result<Long> r = c.createPlan(7L, new HashMap<>(), null);
+
+        assertEquals(500, r.getCode());
+        assertTrue(r.getMessage().contains("memberId不能为空"));
+        verify(svc, never()).createPlan(any(), any(), any(), any(), any());
+    }
+
+    @Test
+    @DisplayName("SC-T-08 异常:成长计划创建缺 memberId → 拒绝,不落库")
+    void growthPlan_create_exception_missingMemberId() throws Exception {
+        GrowthPlanService svc = mock(GrowthPlanService.class);
+        GrowthPlanController c = new GrowthPlanController();
+        inject(c, "growthPlanService", svc);
+        inject(c, "userMapper", mock(com.etotem.cfc.mapper.UserMapper.class));
+        inject(c, "growthPlanMapper", mock(com.etotem.cfc.mapper.GrowthPlanMapper.class));
+
+        Result<GrowthPlan> r = c.createPlan(new GrowthPlan(), 7L);
+
+        assertEquals(500, r.getCode());
+        assertTrue(r.getMessage().contains("请选择家庭成员"));
+        verify(svc, never()).createPlan(any(GrowthPlan.class));
+    }
+
+    @Test
+    @DisplayName("SC-T-08 异常:套餐更新缺 planId → 拒绝")
+    void trainingPlan_update_exception_missingPlanId() throws Exception {
+        TrainingPlanService svc = mock(TrainingPlanService.class);
+        TrainingPlanController c = new TrainingPlanController();
+        inject(c, "trainingPlanService", svc);
+
+        Result<Boolean> r = c.updatePlan(new HashMap<>());
+
+        assertEquals(500, r.getCode());
+        assertTrue(r.getMessage().contains("planId不能为空"));
+        verify(svc, never()).updatePlan(any(), any(), any());
+    }
+
+    @Test
+    @DisplayName("SC-T-14 异常:成长计划更新缺 id → 拒绝")
+    void growthPlan_update_exception_missingId() throws Exception {
+        GrowthPlanService svc = mock(GrowthPlanService.class);
+        GrowthPlanController c = new GrowthPlanController();
+        inject(c, "growthPlanService", svc);
+        inject(c, "userMapper", mock(com.etotem.cfc.mapper.UserMapper.class));
+        inject(c, "growthPlanMapper", mock(com.etotem.cfc.mapper.GrowthPlanMapper.class));
+
+        Result<Boolean> r = c.updatePlan(new HashMap<>());
+
+        assertEquals(500, r.getCode());
+        assertTrue(r.getMessage().contains("方案ID不能为空"));
+        verify(svc, never()).updatePlan(any());
+    }
+
+    // ==================== 权限流:角色门禁契约(RED 锚点) ====================
+    // 规划师端点按框架约定应校验 teacher/admin(RolesUtil.hasTeacherRole),
+    // 参照同域 GuideFamilyQueryController.myFamilies / PlanReviewController.activatePlan /
+    // HealthPlanController.pending-review/*。当前 create/update 端点未读取 role/roles → 红。
+
+    @Test
+    @DisplayName("权限流:套餐创建 createPlan 应暴露 role/roles 输入(角色门禁)——当前未落地")
+    void trainingPlan_create_permission_roleGate() {
+        assertRoleGate(TrainingPlanController.class, "createPlan",
+                "[teacher.plan.create] TrainingPlanController.createPlan(POST /api/guide/training-plans/create)"
+                        + " 未暴露 role/roles 请求属性:规划师端点应校验 teacher/admin 角色"
+                        + "(参照 GuideFamilyQueryController.myFamilies 的 RolesUtil.hasTeacherRole 403 门禁)。"
+                        + " 角色门禁未落地,非 teacher 角色亦可创建方案。");
+    }
+
+    @Test
+    @DisplayName("权限流:套餐更新 updatePlan 应暴露 role/roles 输入(角色门禁)——当前未落地")
+    void trainingPlan_update_permission_roleGate() {
+        assertRoleGate(TrainingPlanController.class, "updatePlan",
+                "[teacher.plan.create] TrainingPlanController.updatePlan(POST /api/guide/training-plans/update)"
+                        + " 未暴露 role/roles 请求属性:规划师端点应校验 teacher/admin 角色。角色门禁未落地。");
+    }
+
+    @Test
+    @DisplayName("权限流:成长计划创建 createPlan 应暴露 role/roles 输入(角色门禁)——当前未落地")
+    void growthPlan_create_permission_roleGate() {
+        assertRoleGate(GrowthPlanController.class, "createPlan",
+                "[teacher.plan.create] GrowthPlanController.createPlan(POST /api/growth/plan/create)"
+                        + " 未暴露 role/roles 请求属性:规划师端点应校验 teacher/admin 角色。角色门禁未落地。");
+    }
+
+    @Test
+    @DisplayName("权限流:成长计划更新 updatePlan 应暴露 role/roles 输入(角色门禁)——当前未落地")
+    void growthPlan_update_permission_roleGate() {
+        assertRoleGate(GrowthPlanController.class, "updatePlan",
+                "[teacher.plan.create] GrowthPlanController.updatePlan(POST /api/growth/plan/update)"
+                        + " 未暴露 role/roles 请求属性:规划师端点应校验 teacher/admin 角色。角色门禁未落地。");
+    }
+
+    // ==================== 反射/断言辅助 ====================
+
+    /** 断言类级 @RequestMapping 含指定路径(值可为 value/path,String[] 形式)。 */
+    private void assertClassMapping(Class<?> clazz, String path, String failMsg) {
+        boolean has = Arrays.stream(clazz.getDeclaredAnnotations())
+                .anyMatch(a -> a instanceof RequestMapping
+                        && Arrays.asList(((RequestMapping) a).value()).contains(path));
+        assertTrue(has, failMsg);
+    }
+
+    /** 断言方法级 @PostMapping 含指定路径。 */
+    private void assertPostMapping(Class<?> clazz, String method, String path, String failMsg) {
+        Method m = findMethod(clazz, method);
+        assertNotNull(m, failMsg + " 方法 " + method + " 不存在。");
+        assertTrue(m.isAnnotationPresent(PostMapping.class)
+                        && Arrays.asList(m.getAnnotation(PostMapping.class).value()).contains(path),
+                failMsg);
+    }
+
+    /** 权限流探针:断言 create/update 处理方法至少暴露一个 @RequestAttribute("role"|"roles") 输入。 */
+    private void assertRoleGate(Class<?> clazz, String method, String failMsg) {
+        Method m = findMethod(clazz, method);
+        assertNotNull(m, failMsg + " 方法 " + method + " 不存在。");
+        boolean hasRoleInput = false;
+        for (Parameter p : m.getParameters()) {
+            for (Annotation a : p.getAnnotations()) {
+                if (a instanceof RequestAttribute) {
+                    String attr = ((RequestAttribute) a).value();
+                    if ("role".equals(attr) || "roles".equals(attr)) {
+                        hasRoleInput = true;
+                        break;
+                    }
+                }
+            }
+            if (hasRoleInput) break;
+        }
+        assertTrue(hasRoleInput, failMsg);
+    }
+
+    private Method findMethod(Class<?> clazz, String name) {
+        for (Method m : clazz.getDeclaredMethods()) {
+            if (m.getName().equals(name)) return m;
+        }
+        return null;
+    }
+
+    private Class<?> loadClass(String name) {
+        try {
+            return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
+        } catch (ClassNotFoundException e) {
+            return null;
+        }
+    }
+}

+ 1 - 1
cfc-web/.last_build_commit

@@ -1 +1 @@
-71c4e545941289633cf8f68228e287e73b8c7c54
+d6c46f7318cbee4f3076d4b08e79d3858de8d25f

+ 2 - 2
cfc-web/package-lock.json

@@ -1,12 +1,12 @@
 {
   "name": "cfc-web",
-  "version": "1.0.2429",
+  "version": "1.0.2432",
   "lockfileVersion": 3,
   "requires": true,
   "packages": {
     "": {
       "name": "cfc-web",
-      "version": "1.0.2429",
+      "version": "1.0.2432",
       "dependencies": {
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^1.0.2",

+ 1 - 1
cfc-web/package.json

@@ -1,6 +1,6 @@
 {
   "name": "cfc-web",
-  "version": "1.0.2430",
+  "version": "1.0.2433",
   "private": true,
   "scripts": {
     "dev": "vue-cli-service serve",

+ 129 - 0
cfc-web/public/CHANGELOG-v1.0.md

@@ -4,6 +4,135 @@
 
 ---
 
+## v1.0.2433 (2026-11-13)
+
+### 测试
+- 修正 typo SSh → SSH
+- 补录推送兜底证据 + B-189-1 状态升级
+- 测试侧产物闭环
+
+### 其他
+- - blockers: B-189-1 状态由「P0 阻塞」降级为「HTTP 兜底已推送,SSH 待修」
+- - 附:fetch 仍须临时指定 http://git.iwintrue.com/liaoxg/cfc.git,SSH 恢复前仍为隐忧
+- 
+- - S 域 2 行(S-01/02)→ admin.supplier.manage(S-cfc-200)
+- - C 域 26/26 全映射(C-26 已上轮);未映射降至 125(B=10/H=7/P=80/S=6/X=21/A=1缺口)
+- 
+- - docs/tdd/test/automation-run-2026-11-13-R189.md: 12项套件实测明细
+- - docs/tdd/notice-2026-11-13-R189-研发通知.md: P1契约RED 48+存量25通知
+- - docs/tdd/test/blockers.md: B-189-1(SSH故障)/B-189-2(窗口13类验)/B-142-2销号
+- - docs/tdd/test/inventory.md + automation-status.md: 台账重扫(跨源4567)
+- - .tdd/_r189_*.log: 8项套件原始日志
+- - _r189_*.cjs: 节点派发器脚本
+- ★ 关键事实:langgraph@251 连续第2轮51/51全绿 → B-142-2销号;
+-   窗口13契约类48预期RED取证;全站红92零缺陷回归
+- 
+
+### 文档
+- sc-key-map 台账回填 27 行(89→116 已映射,C/S 域覆盖)
+
+
+## v1.0.2432 (2026-11-13)
+
+### 文档
+- sc-key-map 台账回填 23 行 SC-A(66→89 已映射,SC-A 域 24/25 映射)
+
+### 其他
+- - SC-A-01→admin.auth.login(GREEN);SC-A-02~22/25/26→新建 admin.* / mind.* 键(RED)
+- - SC-A-04 记为真缺口(无 admin 关系类型 CRUD 载体)
+- - 依据 API_REFERENCE §4.13/§4.14 契约 + Controller 实存核验;未映射降至 152
+- 
+- 契约来源: API_REFERENCE §4.57 + EVD-10 planner-zone-contract (77026df42) §3.
+- - 端点契约: TrainingPlanController /api/guide/training-plans/* (create/update/list/detail/delete),
+-   GrowthPlanController /api/growth/plan/create|update, HealthPlanController /api/health/plan/save|generate
+- - 正常流: teacher 创建套餐/成长计划 -> 200 + 落库
+- - 异常流: 缺 memberId/planId -> 拒绝且不落库
+- - 权限流 (RED): create/update 端点未暴露 role/roles 输入(角色门禁缺失),
+-   非 teacher 角色亦可创建/修改方案 -> 契约行为缺失,GREEN 阶段补齐后转绿
+- TDD-RED 预期: 13 run / 4 fail / 0 error / 9 pass
+- 
+
+### 测试
+- teacher.plan.create RED contract - 权限流角色门禁未落地 (4 RED/9 green)
+- S-cfc-188 family.family.autoCreateForPurchase 契约测试(RED 4/5)
+- S-cfc-184 teacher.assessment.record 契约级单测(TDD-RED:SC-T-07 必填缺失拦截/重复录入覆盖非新增两边界未落地,预期3红1绿)
+
+
+## v1.0.2431 (2026-11-13)
+
+### 文档
+- 研发负责人第152轮闭环汇报 2026-11-13 1051(巡检核验轮:状态机112键 RED17/YELLOW72/GREEN8/DONE15 零漂移;任务池197=done179+dispatched17+pending0 池满;上轮派发 S-cfc-176/177/179 GREEN 实现回执已回填 yellow_sha 三sha IN CHAIN ✓、175/178 属 O-22 豁免;17 RED T域契约在途5节点session全挂;--changes 0新键不add-task;--resume 0候选;deploy pending63(open19)/confirmed77;SC主表241=241唯一跑通15/241无漂移;O-1~O-25全已裁决无新增;730处他人WIP零接触单文件入库)
+- ca56f8699 部署回执 testing(S-cfc-176 membership.plan.purchase 已含于 dae706c7d,JAR/进程/健康核实通过)
+- sc-key-map 台账回填 12 行 SC-T(54→66 已映射,SC-T 域 32/32 全映射)
+- sc-key-map 台账回填 21 行 SC-T 与 SC-X-22 映射(52→54 已映射)
+- 研发负责人第151轮闭环汇报(T域closure续派+17 RED全派发)
+
+### 测试
+- S-cfc-183 teacher.plan.review 契约 RED — SC-T-28 AI 方案内容安全复核缺失
+- s run: 9, Failures: 4(SC-T-28 探针全红,SC-T-04 锚点全绿),BUILD FAILURE。
+- GREEN 契约测试 teacher.login.switch(SC-T-01/T-20)— 实现已由 SEC-20261031-01 + 既有代码落地,16/16 全绿;作为契约证据留存,交编排侧转测试登记。
+- S-cfc-194 teacher.dimension.score 契约级 RED 单测
+- teacher.mind.record 规划师舌诊/情绪测评录入 契约级 RED 单测
+- RED 契约测试 teacher.data.isolation(SC-T-13 family-list 数据隔离缺口)
+- S-cfc-181 teacher.appointment.guard contract RED
+
+### 其他
+- 新增契约级单测 PlanContentSafetyReviewContractTest:
+- - 已绿锚点(5):GuidePlanReviewController /pending|/{planId}/approve|/{planId}/reject、
+-   PlanReviewController /review、ReviewCenterController /summary 端点映射;
+-   HealthPlan.planContent/planJson 复核载体;WechatServiceInterface.checkText 原语。
+- - RED 探针(4):审核链路(HealthPlanServiceImpl/GuidePlanReviewController/
+-   HealthPlanController)未接入内容安全依赖;ContentFilterController 仅有 /by-tags
+-   无方案复核端点;approveAndPublish 命中敏感词仍置 published 且落库。
+- 实测 mvn -Dtest=PlanContentSafetyReviewContractTest test:
+- SC-T-04 生命周期由 PlanReviewTeacherContractTest 覆盖且实现已存在,本类不重复。
+- 仅新增 src/test,未改 src/main。
+- 
+- S-cfc-191: Add contract test for teacher.message.push (SC-T-19) [teacher.message.push]
+- - T-11/12→teacher.assessment.record(DAN 上传解析/八类报告)
+- - T-14/15→teacher.plan.create(方案编辑/套餐任务项)
+- - T-17/21/27→teacher.family.overview;T-18→teacher.task.review
+- - T-22→teacher.plan.create(⚠ G-2 归档缺口)
+- - T-23→teacher.report.proxy;T-28→teacher.plan.review
+- - 依据 EVD-10 契约 §3 定稿表;未映射降至 175
+- 
+- S-cfc-187: teacher.task.review - Implement contract tests for cross-family task audit guard (TC-T-09-P, TC-T-18-E)
+- - SC-T-30 测评录入触发五维变化:锚定 AssessmentService → DimensionScoreService.refreshFromDanAssessment 桥接(绿)
+- - SC-T-31 手动维度打分:ManualDimensionScoreController submit/latest/history + submit 落 five_dimension_scores(source_type=manual)(绿)
+- - SC-T-32 五维自评录入与变化:自评 submit 应桥接五维分数/能量落点(DimensionScoreService/EnergyService/FiveDimensionScoreMapper)+ five_dimension_scores.source_type 应含 selfcheck 来源(红:当前 submitSelfCheck 仅写 five_dimension_self_checks,契约"自评→变化落 EnergyController"未落地)
+- RED 结果:Tests run: 6, Failures: 2, Errors: 0(2 红=SC-T-32 桥接缺口,GREEN 阶段实现后转绿)
+- 
+- - SC-T-30/31/32 回填 teacher.dimension.score
+- - SC-X-22 回填 reward.cfEstimate.expectedCf(键 DONE,三类流证据待补)
+- - 未映射降至 187
+- 
+- [S-cfc-192] [teacher.nutrition.plan] TDD-RED 契约测试:精准营养方案制定
+- 纯 Mockito 行为级单测,预期红:
+- 正常流-1:generateRecommendation 的 nutritionSummary 应聚合宏量营养素
+- (protein/carbs/fat),当前 aggregateNutrition 恒置 0(源码注释:
+- protein/carbs/fat 恒 0 不在本轮范围)— 断言失败。
+- 边界流-1/2:负热量目标(calories=-500)与超上限热量目标(999999)
+- 应被拦截返回非 200;当前实现静默忽略并照常返回 success(200) — 断言失败。
+- 权限流:家庭隔离由 JwtInterceptor + familyId 承载,本控制器粒度不适用。
+- 
+- - controller: create 代录入口 + list 客户测评记录查看
+- - service: createAssessment 入库 + getAssessments(assessmentDate 倒序)
+- - entity: memberId/guideId/assessmentType/status(默认 draft)/assessmentDate 字段契约
+- RED: 13 用例 12 失败(0 错误),断言契约所需统一录入链路缺失(实现未落地)
+- 溯源: sc-key-map SC-T-25 + planner-zone-contract(EVD-10) §2/§5 + API_REFERENCE §4.57
+- 能力键: teacher.mind.record | 任务号: S-cfc-195 | 分支: task/S-cfc-195
+- 
+- - 定位:PlanReviewController /api/guide/plans/family-list teacher 越权缺口——
+-   当前 body.familyId 直接透传、无 guide_families(status=binding) isBound 校验,
+-   控制器未注入全项目唯一授权判定点 GuideFamilyAccessGuard。
+- - 新增 cfc-backend/src/test 单测(纯 Mockito/反射,无 Spring/DB):
+-   权限流 3 条(teacher 越权非绑定家庭 403 / body.familyId 不泄漏跨家庭方案 /
+-   越权不查询 planMapper)+ 结构流 1 条(注入统一授权守卫),预期红。
+-   正常流/异常流/授权源基线/观察钉住 5 条(绿)。
+- - 验证:9 通过 5、失败 4(红)——RED 阶段完成,GREEN 阶段实现 isBound 校验使绿。
+- 
+
+
 ## v1.0.2430 (2026-11-13)
 
 ### 文档

+ 130 - 1
cfc-web/public/CHANGELOG.md

@@ -1,6 +1,6 @@
 # 更新日志
 
-> 当前版本: v1.0.2430
+> 当前版本: v1.0.2433
 
 ## 历史版本
 
@@ -8,6 +8,135 @@
 
 ---
 
+## v1.0.2433 (2026-11-13)
+
+### 测试
+- 修正 typo SSh → SSH
+- 补录推送兜底证据 + B-189-1 状态升级
+- 测试侧产物闭环
+
+### 其他
+- - blockers: B-189-1 状态由「P0 阻塞」降级为「HTTP 兜底已推送,SSH 待修」
+- - 附:fetch 仍须临时指定 http://git.iwintrue.com/liaoxg/cfc.git,SSH 恢复前仍为隐忧
+- 
+- - S 域 2 行(S-01/02)→ admin.supplier.manage(S-cfc-200)
+- - C 域 26/26 全映射(C-26 已上轮);未映射降至 125(B=10/H=7/P=80/S=6/X=21/A=1缺口)
+- 
+- - docs/tdd/test/automation-run-2026-11-13-R189.md: 12项套件实测明细
+- - docs/tdd/notice-2026-11-13-R189-研发通知.md: P1契约RED 48+存量25通知
+- - docs/tdd/test/blockers.md: B-189-1(SSH故障)/B-189-2(窗口13类验)/B-142-2销号
+- - docs/tdd/test/inventory.md + automation-status.md: 台账重扫(跨源4567)
+- - .tdd/_r189_*.log: 8项套件原始日志
+- - _r189_*.cjs: 节点派发器脚本
+- ★ 关键事实:langgraph@251 连续第2轮51/51全绿 → B-142-2销号;
+-   窗口13契约类48预期RED取证;全站红92零缺陷回归
+- 
+
+### 文档
+- sc-key-map 台账回填 27 行(89→116 已映射,C/S 域覆盖)
+
+
+## v1.0.2432 (2026-11-13)
+
+### 文档
+- sc-key-map 台账回填 23 行 SC-A(66→89 已映射,SC-A 域 24/25 映射)
+
+### 其他
+- - SC-A-01→admin.auth.login(GREEN);SC-A-02~22/25/26→新建 admin.* / mind.* 键(RED)
+- - SC-A-04 记为真缺口(无 admin 关系类型 CRUD 载体)
+- - 依据 API_REFERENCE §4.13/§4.14 契约 + Controller 实存核验;未映射降至 152
+- 
+- 契约来源: API_REFERENCE §4.57 + EVD-10 planner-zone-contract (77026df42) §3.
+- - 端点契约: TrainingPlanController /api/guide/training-plans/* (create/update/list/detail/delete),
+-   GrowthPlanController /api/growth/plan/create|update, HealthPlanController /api/health/plan/save|generate
+- - 正常流: teacher 创建套餐/成长计划 -> 200 + 落库
+- - 异常流: 缺 memberId/planId -> 拒绝且不落库
+- - 权限流 (RED): create/update 端点未暴露 role/roles 输入(角色门禁缺失),
+-   非 teacher 角色亦可创建/修改方案 -> 契约行为缺失,GREEN 阶段补齐后转绿
+- TDD-RED 预期: 13 run / 4 fail / 0 error / 9 pass
+- 
+
+### 测试
+- teacher.plan.create RED contract - 权限流角色门禁未落地 (4 RED/9 green)
+- S-cfc-188 family.family.autoCreateForPurchase 契约测试(RED 4/5)
+- S-cfc-184 teacher.assessment.record 契约级单测(TDD-RED:SC-T-07 必填缺失拦截/重复录入覆盖非新增两边界未落地,预期3红1绿)
+
+
+## v1.0.2431 (2026-11-13)
+
+### 文档
+- 研发负责人第152轮闭环汇报 2026-11-13 1051(巡检核验轮:状态机112键 RED17/YELLOW72/GREEN8/DONE15 零漂移;任务池197=done179+dispatched17+pending0 池满;上轮派发 S-cfc-176/177/179 GREEN 实现回执已回填 yellow_sha 三sha IN CHAIN ✓、175/178 属 O-22 豁免;17 RED T域契约在途5节点session全挂;--changes 0新键不add-task;--resume 0候选;deploy pending63(open19)/confirmed77;SC主表241=241唯一跑通15/241无漂移;O-1~O-25全已裁决无新增;730处他人WIP零接触单文件入库)
+- ca56f8699 部署回执 testing(S-cfc-176 membership.plan.purchase 已含于 dae706c7d,JAR/进程/健康核实通过)
+- sc-key-map 台账回填 12 行 SC-T(54→66 已映射,SC-T 域 32/32 全映射)
+- sc-key-map 台账回填 21 行 SC-T 与 SC-X-22 映射(52→54 已映射)
+- 研发负责人第151轮闭环汇报(T域closure续派+17 RED全派发)
+
+### 测试
+- S-cfc-183 teacher.plan.review 契约 RED — SC-T-28 AI 方案内容安全复核缺失
+- s run: 9, Failures: 4(SC-T-28 探针全红,SC-T-04 锚点全绿),BUILD FAILURE。
+- GREEN 契约测试 teacher.login.switch(SC-T-01/T-20)— 实现已由 SEC-20261031-01 + 既有代码落地,16/16 全绿;作为契约证据留存,交编排侧转测试登记。
+- S-cfc-194 teacher.dimension.score 契约级 RED 单测
+- teacher.mind.record 规划师舌诊/情绪测评录入 契约级 RED 单测
+- RED 契约测试 teacher.data.isolation(SC-T-13 family-list 数据隔离缺口)
+- S-cfc-181 teacher.appointment.guard contract RED
+
+### 其他
+- 新增契约级单测 PlanContentSafetyReviewContractTest:
+- - 已绿锚点(5):GuidePlanReviewController /pending|/{planId}/approve|/{planId}/reject、
+-   PlanReviewController /review、ReviewCenterController /summary 端点映射;
+-   HealthPlan.planContent/planJson 复核载体;WechatServiceInterface.checkText 原语。
+- - RED 探针(4):审核链路(HealthPlanServiceImpl/GuidePlanReviewController/
+-   HealthPlanController)未接入内容安全依赖;ContentFilterController 仅有 /by-tags
+-   无方案复核端点;approveAndPublish 命中敏感词仍置 published 且落库。
+- 实测 mvn -Dtest=PlanContentSafetyReviewContractTest test:
+- SC-T-04 生命周期由 PlanReviewTeacherContractTest 覆盖且实现已存在,本类不重复。
+- 仅新增 src/test,未改 src/main。
+- 
+- S-cfc-191: Add contract test for teacher.message.push (SC-T-19) [teacher.message.push]
+- - T-11/12→teacher.assessment.record(DAN 上传解析/八类报告)
+- - T-14/15→teacher.plan.create(方案编辑/套餐任务项)
+- - T-17/21/27→teacher.family.overview;T-18→teacher.task.review
+- - T-22→teacher.plan.create(⚠ G-2 归档缺口)
+- - T-23→teacher.report.proxy;T-28→teacher.plan.review
+- - 依据 EVD-10 契约 §3 定稿表;未映射降至 175
+- 
+- S-cfc-187: teacher.task.review - Implement contract tests for cross-family task audit guard (TC-T-09-P, TC-T-18-E)
+- - SC-T-30 测评录入触发五维变化:锚定 AssessmentService → DimensionScoreService.refreshFromDanAssessment 桥接(绿)
+- - SC-T-31 手动维度打分:ManualDimensionScoreController submit/latest/history + submit 落 five_dimension_scores(source_type=manual)(绿)
+- - SC-T-32 五维自评录入与变化:自评 submit 应桥接五维分数/能量落点(DimensionScoreService/EnergyService/FiveDimensionScoreMapper)+ five_dimension_scores.source_type 应含 selfcheck 来源(红:当前 submitSelfCheck 仅写 five_dimension_self_checks,契约"自评→变化落 EnergyController"未落地)
+- RED 结果:Tests run: 6, Failures: 2, Errors: 0(2 红=SC-T-32 桥接缺口,GREEN 阶段实现后转绿)
+- 
+- - SC-T-30/31/32 回填 teacher.dimension.score
+- - SC-X-22 回填 reward.cfEstimate.expectedCf(键 DONE,三类流证据待补)
+- - 未映射降至 187
+- 
+- [S-cfc-192] [teacher.nutrition.plan] TDD-RED 契约测试:精准营养方案制定
+- 纯 Mockito 行为级单测,预期红:
+- 正常流-1:generateRecommendation 的 nutritionSummary 应聚合宏量营养素
+- (protein/carbs/fat),当前 aggregateNutrition 恒置 0(源码注释:
+- protein/carbs/fat 恒 0 不在本轮范围)— 断言失败。
+- 边界流-1/2:负热量目标(calories=-500)与超上限热量目标(999999)
+- 应被拦截返回非 200;当前实现静默忽略并照常返回 success(200) — 断言失败。
+- 权限流:家庭隔离由 JwtInterceptor + familyId 承载,本控制器粒度不适用。
+- 
+- - controller: create 代录入口 + list 客户测评记录查看
+- - service: createAssessment 入库 + getAssessments(assessmentDate 倒序)
+- - entity: memberId/guideId/assessmentType/status(默认 draft)/assessmentDate 字段契约
+- RED: 13 用例 12 失败(0 错误),断言契约所需统一录入链路缺失(实现未落地)
+- 溯源: sc-key-map SC-T-25 + planner-zone-contract(EVD-10) §2/§5 + API_REFERENCE §4.57
+- 能力键: teacher.mind.record | 任务号: S-cfc-195 | 分支: task/S-cfc-195
+- 
+- - 定位:PlanReviewController /api/guide/plans/family-list teacher 越权缺口——
+-   当前 body.familyId 直接透传、无 guide_families(status=binding) isBound 校验,
+-   控制器未注入全项目唯一授权判定点 GuideFamilyAccessGuard。
+- - 新增 cfc-backend/src/test 单测(纯 Mockito/反射,无 Spring/DB):
+-   权限流 3 条(teacher 越权非绑定家庭 403 / body.familyId 不泄漏跨家庭方案 /
+-   越权不查询 planMapper)+ 结构流 1 条(注入统一授权守卫),预期红。
+-   正常流/异常流/授权源基线/观察钉住 5 条(绿)。
+- - 验证:9 通过 5、失败 4(红)——RED 阶段完成,GREEN 阶段实现 isBound 校验使绿。
+- 
+
+
 ## v1.0.2430 (2026-11-13)
 
 ### 文档

+ 67 - 0
docs/tdd/notice-2026-11-13-R189-研发通知.md

@@ -0,0 +1,67 @@
+# R189 轮研发通知(2026-11-13)
+
+## 状态摘要
+
+| 项目 | 内容 |
+|------|------|
+| 汇报轮次 | **R189**(2026-11-13 10:45~11:30) |
+| 基线 → 收尾 | `00121ff2f`(R188)→ `6124352d7`(本地 = 远端 HEAD) |
+| 全站覆盖率 | 4120 例 / 4003 过 / 92 红 / 25 跳 = **97.16%** |
+| 零回归确认 | ✅ 浏览器六件套全绿;API 0 红;fe/web 零漂移;后端存量 25 红零漂移 |
+| **本轮正向项** | langgraph **连续 2 轮 51/51** → B-142-2 **销号** |
+| 主要阻塞 | ① git SSH 22 CLOSED → 推送受阻(B-189-1);② 48 前瞻契约 RED 待实现(P1) |
+
+---
+
+## 一、优先级事项(⏰ 按序处理)
+
+### P1 · 窗口 13 契约测试类 48 RED 实现(本轮新增、最紧急)
+
+| SC-key | 提交 sha | 类名 | 例数 | 当前结果 | 预期 | 描述 |
+|--------|----------|------|------|----------|------|------|
+| S-cfc-183 | 5f2a09b02 | PlanContentSafetyReviewContractTest | 9 | 5P/4F | RED 4/5 | AI 方案内容安全复核缺失 |
+| **S-cfc-184** | 64f8a3875 | TeacherAssessmentRecordContractTest | 4 | 1P/3F | RED 3/1 | 必填拦截/重复覆盖未落地 |
+| S-cfc-188 | 883a6eeab | FamilyAutoCreateForPurchaseContractTest | 5 | 1P/4F | RED 4/5 | 自动建家庭接口缺失 |
+| S-cfc-189 | bbc441e08 | TeacherLoginSwitchContractTest | 16 | **16P/0F** | **GREEN** ✅ | 已实现,可直接收尾 |
+| S-cfc-191 | 23e2ddd66 | TeacherMessagePushContractTest | 20 | **20P/0F** | **GREEN** ✅ | 已实现,可直接收尾 |
+| S-cfc-196 | fb1702975 | TeacherPlanCreateContractTest | 13 | 9P/4F | RED 4/9 | 权限门禁未落地 |
+| —(窗口) | — | TeacherMindRecordContractTest | 13 | 1P/12F | RED 高 | mind 记录边界 |
+| —(窗口) | — | TeacherAppointmentGuardContractTest | 14 | 4P/10F | RED | 预约守卫 |
+| —(窗口) | — | GuideFamilyTaskReviewContractTest | 5 | 3P/2F | RED | 家庭任务审核 |
+| —(窗口) | — | NutritionPlanTeacherContractTest | 4 | 1P/3F | RED | 营养师计划 |
+| —(窗口) | — | TeacherDataIsolationScT13ContractTest | 9 | 5P/4F | RED | 数据隔离 |
+| —(窗口) | — | TeacherDimensionScoreContractTest | 6 | 4P/2F | RED | 维度评分 |
+| —(窗口) | — | TeacherPlanActivateContractTest | 15 | **15P/0F** | **GREEN** ✅ | 已实现,可直接收尾 |
+
+> **行动**:P1 类中 **GREEN 3 个直接收 YELLOW/GREEN**;其余 10 个由对应研发认领 SC-T key 实现使绿。
+
+### P2 · git SSH 22 故障(B-189-1,运维/平台侧)
+
+- 现象:`git.iwintrue.com` / 251 **SSH 22 CLOSED**(R188 09:39 尚可 push),导致本轮测试产物与台账的 push 受阻。
+- 替代路径:HTTP 可读确认 `http://git.iwintrue.com/liaoxg/cfc.git` HEAD=`6124352d7` 与本地一致,fetch/push 须等 SSH 恢复。
+- 行动:**请运维检查 Gogs SSH 服务**(端口 22 / 或 251 上的 sshd)。
+
+### P3 · 存量 25 红后端(跨 24 轮承袭)
+
+- 类清单:`EnergySystemFlowTest` 6F / `DimensionRegistryMapContractTest` 3F / `OrchestrationEngineTest`·`OrchestrationIntegrationTest`·`MembershipPaySwitchTest`·`PaymentServiceORDRoutingTest`·`UserServiceWechatLoginTest`(×2)·`TeamProfitCronContractTest` 各 1F 等。
+- 行动:按计划逐类修复;优先 `TeamProfitCronContractTest`(平台费截断影响计费)。
+
+---
+
+## 二、本轮已闭环 / 观察推进
+
+- ✅ **B-142-2(langgraph 上游凭据/配额)**:连续 2 轮 51/51 全绿 → **销号**。
+- ⏳ B-186-1(live chat 120s 挂死):pytest 绿但 live 链路仍挂,独立观察。
+- ⏳ B-36 根级黑盒 16 红(9082 未起):承袭。
+- ⏳ B-DX-1 dx 桥接 2 例 skip(404):承袭。
+
+---
+
+## 三、证据链
+
+- 报告:`docs/tdd/orchestration/report-test-2026-11-13-R189.md`
+- 执行日志:`docs/tdd/test/automation-run-2026-11-13-R189.md`
+- blockers:`docs/tdd/test/blockers.md`(含 B-189-1/B-189-2 段)
+- 台账:`docs/tdd/test/{discovery,inventory,automation-status}.md`(已刷新)
+
+> 📤 推送状态:⚠️ 本轮 SSH 22 故障,推送受阻(见 §一 P2)。

+ 221 - 0
docs/tdd/orchestration/report-dev-2026-11-13-1210.md

@@ -0,0 +1,221 @@
+# 研发负责人工作汇报(第 153 轮)
+
+> 角色:研发负责人(错峰03 · TDD 推进)|周期:2026-11-13 11:30 ~ 12:10|负责范围:CFC 全量(SRS/设计/用户场景实现闭环)
+> 交付物:本报告由单文件 `git hash-object` 旁路推 `origin/cfclub`,**未触碰主工作树 731 处其他会话 WIP**(禁 `add -A`)。
+
+---
+
+## 基本信息
+
+| 项目 | 内容 |
+|------|------|
+| 汇报人 | 研发负责人(错峰03 · 自动化错峰轮) |
+| 汇报周期 | 2026-11-13 11:30 ~ 2026-11-13 12:10(第 153 轮;上轮 152 @10:51 由错峰轮收口,state.json 更新于 11:20:03,本轮启动 11:30 距其 >5min **互斥放行**;执行中 state.json 二次更新 11:33:38 为他轮 --apply 建 RED 批次,本轮续查仍 >5min 窗口) |
+| 负责模块/单元范围 | CFC 全量(cfc-backend / cfc-frontend / cfc-web / danshop / cfc-langgraph) |
+
+---
+
+## 一、本轮工作数据汇总
+
+### 1.1 问题接收与处置
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **收到的测试反馈问题数** | `0` 个 | `--inspect` 0 已登记阻塞(`docs/tdd/test/blockers.md` 无新增);测试侧无研发类阻塞回流 |
+| **已解决问题数** | `16` 个 | **backfill 回收 16 条 dispatched 死锁**(S-cfc-180~196,会话未回报但契约测试已推远端) |
+| **待解决研发问题数** | `2` 个 | S-cfc-182/186 backfill 误配(sc-key-map docs 提交非契约测试)→ auto T8 自动 requeue + 重派,下轮收会话回执 |
+
+### 1.2 任务分发与会话管理
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **分派任务数** | `2` 个 | auto `--limit 2` 续派:S-cfc-182(lan-189)/ S-cfc-186(lan-204),均为 T8 requeue 后重派 |
+| **恢复智能体会话数** | `0` 个 | `--resume --dry-run` 0 候选;prod-etotem 生产跳过(默认) |
+| **当前在用会话数** | `4` 个 | S-cfc-182(lan-189) / 186(lan-204) / 190(mes-local-45278) / 193(mes-local-45278) dispatched 在途 |
+| **会话平均利用率** | `轻载` % | 5 节点全 idle(pub-iwintrue busy=2 配额 9/10 剩余),其余节点 0 占用;pending 47 待续派 |
+
+### 1.2b 各会话当前工作状态列表
+
+| 会话标签 | 当前状态 | 当前任务 | 备注 |
+|----------|----------|----------|------|
+| lan-189 | `busy=1` | S-cfc-182(teacher.report.proxy 契约重派) | 本轮 T8 requeue 重派 |
+| lan-204 | `busy=1` | S-cfc-186(teacher.family.overview 契约重派) | 本轮 T8 requeue 重派 |
+| mes-local-45278 | `busy=2` | S-cfc-190 / 193(teacher.family.bind / client.export) | 上轮遗留在途,本轮无证据不 backfill |
+| local-lan-4090 | `idle` | — | 空闲,配额 10/10 |
+| pub-iwintrue | `busy=2` | 部署/测试侧 | 配额 9/10 |
+| production(ses_f719c9326) | `idle` | — | 生产部署会话,registered |
+| testing(ses_e4804838) | `idle` | — | 测试部署会话,registered |
+
+> 本轮 auto 派发 2 条后,lan-189/lan-204 各新增 1 会话在途;local-lan-4090 空闲(下轮 T6 续派 candidate)。
+
+### 1.3 变更感知与新任务建立
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **感知需求/设计变更数** | `~235` 文件 | 近 7 天 `--changes`:需求/设计 + 测试用例 + 其他;**新增能力键 0**("无新增能力键 0→0,变化集中在既有键") |
+| **新增入池任务数** | `13` 个(auto 自动续建) | auto 对 13 键 RED→YELLOW 自动创建对应 GREEN 实现任务 **S-cfc-226~238**(T6 池空续派达成) |
+| **既有键状态流转数** | `13` 键 | 13 键 **RED→YELLOW**(teacher.* T域契约单测证据就绪,red_sha 回填);RED 46→38 / YELLOW 72→85 |
+
+### 1.4 本轮 git 提交与推送证据(真理证据)
+
+| 提交 sha | 关联任务/能力键 | 阶段 | 触及文件类型 | 目标分支 | 已推送远端 | 备注 |
+|----------|-----------------|------|--------------|----------|------------|------|
+| 13 键 RED→YELLOW red_sha | teacher.* 12 + family.family.autoCreateForPurchase 1 | RED✓ | 测试文件(已推远端) | cfclub | 是 | backfill 证据回填,auto 自动登记 red_sha 推进 RED→YELLOW;**其中 9 键 sha 为 merge 提交**(见附录 D 甄别) |
+| S-cfc-180 | teacher.plan.activate | RED✓ | 测试 | cfclub | 是 | `e9e644c357` 真实 test 提交 |
+| S-cfc-184 | teacher.assessment.record | RED✓ | 测试 | cfclub | 是 | `64f8a3875f` 真实 test 提交 |
+| S-cfc-185 | teacher.data.isolation | RED✓ | 测试 | cfclub | 是 | `5c0b32c84c` 真实 test 提交 |
+| S-cfc-188 | family.family.autoCreateForPurchase | RED✓ | 测试 | cfclub | 是 | `883a6eeab5` 真实 test 提交 |
+| 报告文档 | — | — | docs | cfclub | 是 | 单文件 hash-object 旁路(本轮唯一新增提交) |
+
+> **本轮无新增业务实现提交**(零 YELLOW 实现、零业务写盘);核心动作 = backfill 死锁回收 + auto 状态推进 + GREEN 任务续建。报告文档走单文件 `git hash-object` 旁路(临时索引 read-tree origin/cfclub^{tree})。
+
+### 1.5 状态机阶段分布与部署状态
+
+| 阶段 | 键数 | 备注 |
+|------|------|------|
+| RED | `38` | admin.* 13 + child.* 12 + supplier.* 5 + mind.model.manage 1 + energy.ledger.guard 1 + teacher.report.proxy 1 + teacher.family.overview 1 + …(S-cfc-197~225 + 239~243 契约批次 + 182/186 重派);red_sha 待回填 |
+| YELLOW | `85` | 66(上轮已填 sha IN_CHAIN)+ 6 O-22 豁免 + **13 本轮 RED→YELLOW**(teacher.* 契约就绪待实现,yellow_sha 空) |
+| GREEN | `8` | achievement.grid.fiveCol / admin.auth.login / dan.assessment.getActiveMaterial / growth.history.view / health.report.createReport / health.report.upload 等 |
+| DONE | `15` | auth.guest.jwtGuard / auth.guest.wechatLogin / dan.report.parseFormat / dimension.registry.getTree / dimension.registry.mapLegacyCode / family.familyMembers.addMember 等 |
+
+| 部署项 | 值 | 说明 |
+|--------|-----|------|
+| 本轮部署次数 | `0` 次 | 编排侧不代 `--deploy-done`,部署回执归测试/部署侧 |
+| pending / confirmed | `19` / `77` | O-24 已裁决归测试/部署侧收口;编排侧不代越 |
+| last_deployed | 双账本差异延续 | 归部署侧 |
+
+### 1.6 数据源健康度
+
+| 数据源 | 读取键数 | 是否正常 | 备注 |
+|--------|----------|----------|------|
+| 需求侧(⏳) | `0` | 正常(稳态) | 无新缺口键 |
+| 契约常量(契约) | `0` | 正常 | — |
+| 测试用例引用(用例∩⏳) | `0` | 正常 | ⏳∩用例引用=0 |
+| 执行结果回填(case_results) | `0` | 正常 | — |
+
+> **场景覆盖矩阵**:SC 台账主表 241 行 = 241 唯一 SC(零漂移)= 已跑通 15 / 有键未跑通 18 / 无键未契约化 208。**跑通 15/241**(本轮 T 域 13 键契约就绪推进,为 241 覆盖打基础);241/241 前不得报「开发完成」。P 域 80 无键 SC(健康报告/DAN 预约/AI 方案/心愿/能量归因)仍为下一主攻方向。
+
+---
+
+## 二、下一步需要研发处理的事项
+
+| 序号 | 事项描述 | 依赖/前置条件 | 预估完成时间 | 优先级 | 状态 |
+|------|----------|---------------|--------------|--------|------|
+| 1 | 13 个 YELLOW 键(teacher.* RED→YELLOW)实现落地:S-cfc-226~238 GREEN 任务续派 + 会话执行 | 下轮 T6 续派(本轮 --limit 2 已用尽) | 下一窗口 | P1 | 待派发 |
+| 2 | S-cfc-182/186 重派会话回执核验(本轮 T8 requeue 重派)→ 契约测试产出后回填 red_sha | 会话 push 契约测试 | 持续 | P1 | 进行中 |
+| 3 | S-cfc-190/193 上轮遗留 dispatched 会话回执核验(无证据不 backfill) | 会话产出契约测试 | 持续 | P2 | 进行中 |
+| 4 | 38 个 RED 契约任务(S-cfc-197~225 + 239~243)产出核验 → 回填 red_sha → 交测试侧 mark-red 三类流 | 会话 push 证据 | 持续 | P1 | 进行中 |
+| 5 | 85 个 YELLOW 键测试 GREEN 校验 + 241 用户场景三类流证据(O-7) | 测试团队协同 | 持续 | P1 | 进行中(瓶颈在测试侧) |
+| 6 | 19 条 pending 部署经 `--deploy-done testing` 收口(O-24) | 部署会话回执 | 持续 | P2 | 归测试/部署侧 |
+| 7 | **P 域 80 无键 SC 契约批次设计**(参照 EVD-10 模式立项) | 主理人确认 P 域契约锚点 | 评估后 | P1 | 待主理人确认 |
+
+---
+
+## 三、阻塞与风险
+
+| 阻塞项 | 影响范围 | 阻塞类型 | 处置进展 | 需要协调 |
+|--------|----------|----------|----------|----------|
+| 主工作树 731 处他人 WIP(非本轮产生) | 主分支目录 | 研发(环境) | 已隔离:全程临时索引/单文件 hash-object 旁路,零接触 | 无需 |
+| **backfill sha 误配缺陷(151 轮已报,本轮复现)** | 状态机 red_sha 精确度 | 编排(工具) | 13 键 RED→YELLOW 中 9 键 red_sha 为 merge 提交(非真实 test 提交);真实 test 提交已在链(附录 D 对照)。编排侧按 backfill commit 字段登记,git_evidence 已过滤为 test_hit(merge 提交含测试文件),功能有效但 sha 非最精确。建议后续修 dispatch.py `_git_evidence_sha()` 只认 test/main 提交(**见裁决 4**) | 无需(本轮如实记录) |
+| S-cfc-182/186 backfill 误配 sc-key-map docs 提交 | 2 条契约任务 | 编排(工具) | 已由 auto T8 自动识别(无 git 证据 → requeue)+ 重派;编排侧自愈生效 | 无需 |
+| P 域 80 无键 SC(健康报告/DAN 预约/AI 方案等) | 241 场景目标 | 需求(覆盖缺口) | T 域 13 键契约就绪推进;P 域为下一主攻方向,需主理人确认契约锚点后立项 | 建议主理人确认 |
+| deploy pending open 19(历史遗留) | 部署收口 | 部署 | O-24 已裁决归测试/部署侧 `--deploy-done` 回执;编排侧不代越 | 无需 |
+
+---
+
+## 四、下轮工作规划
+
+| 计划项 | 预计完成时间 | 前置依赖 | 涉及会话标签 | 备注 |
+|--------|--------------|----------|--------------|------|
+| 错峰巡检(每时45分) | 下一窗口 | state.json 距本轮 >5min | 研发负责人 | 互斥放行即接管 |
+| **S-cfc-226~238 GREEN 实现任务续派**(13 条 teacher.*) | 下一窗口 T6 续派 | --limit 配额 | lan-189 / lan-204 / local-lan-4090 | 本轮 --limit 2 已用尽,下轮续派 |
+| S-cfc-182/186/190/193 会话回执核验 | 持续 | 会话 push 证据 | lan-189 / lan-204 / mes-local-45278 | 契约产出后回填 red_sha |
+| 38 RED 契约产出核验 + red_sha 回填 | 持续 | 会话 push 证据 | 5 节点 | 转 mark-red 三类流证据 |
+| YELLOW→GREEN 测试协同推进 | 持续 | 测试团队 | 测试负责人 | 85 YELLOW 校验 |
+| **P 域契约批次立项(EVD 模式)** | 主理人确认后 | sc-key-map + API_REFERENCE | — | 80 无键 SC 主攻方向 |
+
+---
+
+## 附录
+
+### 附录 A:收到的测试反馈问题明细
+
+| 问题 ID | 能力键/任务号 | 问题类型 | 来源 | 接收时间 | 处置状态 | 关联 sha |
+|---------|---------------|----------|------|----------|----------|----------|
+| 无 | — | — | — | — | — | — |
+
+### 附录 B:本回合派发/恢复明细
+
+| 动作 | 任务号 | 能力键 | 实例 | 会话 | 备注 |
+|------|--------|--------|------|------|------|
+| T8 requeue 重派 | S-cfc-182 | teacher.report.proxy | lan-189 | ses_e2cecd750ffewvO2mA7DVWQWA0 | backfill 误配 docs 提交 → T8 识别无证据 → requeue #1 → 重派 |
+| T8 requeue 重派 | S-cfc-186 | teacher.family.overview | lan-204 | ses_e2cec8dc9ffezvmhMGbLkCEQ65 | 同上 |
+
+> auto `--limit 2` 续派 2 条成功 / 0 失败 / 0 超限。`--resume --dry-run` 0 候选(prod-etotem 生产跳过)。
+
+### 附录 C:backfill 回收 16 条 dispatched 死锁(本轮关键增量)
+
+| 任务号 | 能力键 | backfill commit | 真实契约测试提交 | IN_CHAIN | 处置 |
+|--------|--------|-----------------|------------------|----------|------|
+| S-cfc-180 | teacher.plan.activate | e9e644c357 | e9e644c357(test) | ✓ | 真实 test,RED✓ 推进 |
+| S-cfc-181 | teacher.appointment.guard | 50744725e(Merge) | fb82952fa(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-182 | teacher.report.proxy | 5b938488a(sc-key-map docs) | 无 | — | **误配** → T8 requeue 重派 |
+| S-cfc-183 | teacher.plan.review | 76131eb09(Merge) | 5f2a09b02(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-184 | teacher.assessment.record | 64f8a3875f | 64f8a3875f(test) | ✓ | 真实 test,RED✓ 推进 |
+| S-cfc-185 | teacher.data.isolation | 5c0b32c84c | 5c0b32c84c(test) | ✓ | 真实 test,RED✓ 推进 |
+| S-cfc-186 | teacher.family.overview | 5b938488a(sc-key-map docs) | 无 | — | **误配** → T8 requeue 重派 |
+| S-cfc-187 | teacher.task.review | 233d6e7c0(Merge) | 9b565d9db(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-188 | family.family.autoCreateForPurchase | 883a6eeab5 | 883a6eeab5(test) | ✓ | 真实 test,RED✓ 推进 |
+| S-cfc-189 | teacher.login.switch | 05531929d(Merge) | bbc441e08(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-190 | teacher.family.bind | —(仍 dispatched) | 无 | — | 本轮不 backfill,下轮核验 |
+| S-cfc-191 | teacher.message.push | 03cb65f00(Merge remote) | 23e2ddd66(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-192 | teacher.nutrition.plan | cc5cd22bc(merge) | f7e9ed991(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-193 | teacher.client.export | —(仍 dispatched) | 无 | — | 本轮不 backfill,下轮核验 |
+| S-cfc-194 | teacher.dimension.score | 5da32aeb4(merge) | 69e8ed20e(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-195 | teacher.mind.record | 9ae64fedbb(merge) | baf130a8f(test) | ✓ | sha 误配,功能有效 |
+| S-cfc-196 | teacher.plan.create | bfd9cbe665(Merge) | fb1702975(test) | ✓ | sha 误配,功能有效 |
+
+> **结论**:backfill 回收 16 条(S-cfc-180~196),14 条有真实契约测试证据(功能有效,RED→YELLOW 推进);2 条误配(182/186 命中 sc-key-map docs 提交)由 auto T8 自动识别 requeue + 重派。S-cfc-190/193 无证据本轮不 backfill(仍 dispatched)。
+
+### 附录 D:RED→YELLOW red_sha sha 甄别对照(backfill 缺陷复现实证)
+
+| 能力键 | 登记的 red_sha(backfill commit) | 提交类型 | 真实契约测试提交 | 精确度 |
+|--------|-----------------------------------|----------|------------------|--------|
+| teacher.plan.activate | e9e644c357 | test | e9e644c357 | ✓ 精确 |
+| teacher.appointment.guard | 50744725ef | **Merge** | fb82952fa | △ merge(含测试文件,功能有效) |
+| teacher.plan.review | 76131eb09 | **Merge** | 5f2a09b02 | △ merge |
+| teacher.assessment.record | 64f8a3875f | test | 64f8a3875f | ✓ 精确 |
+| teacher.data.isolation | 5c0b32c84c | test | 5c0b32c84c | ✓ 精确 |
+| teacher.task.review | 233d6e7c0 | **Merge** | 9b565d9db | △ merge |
+| family.family.autoCreateForPurchase | 883a6eeab5 | test | 883a6eeab5 | ✓ 精确 |
+| teacher.login.switch | 05531929d6 | **Merge** | bbc441e08 | △ merge |
+| teacher.message.push | 03cb65f001 | **Merge remote** | 23e2ddd66 | △ merge |
+| teacher.nutrition.plan | cc5cd22bce | **merge** | f7e9ed991 | △ merge |
+| teacher.dimension.score | 5da32aeb43 | **merge** | 69e8ed20e | △ merge |
+| teacher.mind.record | 9ae64fedbb | **merge** | baf130a8f | △ merge |
+| teacher.plan.create | bfd9cbe665 | **Merge** | fb1702975 | △ merge |
+
+> **结论**:13 键 RED→YELLOW 的 red_sha 中 **4 键精确**(真实 test 提交)、**9 键为 merge 提交**(含测试文件变更,git_evidence 判 test_hit 功能有效,但非最精确 sha)。真实契约测试提交均已在链(merge-base IN_CHAIN)。**建议后续修 dispatch.py `_git_evidence_sha()`**:优先取 test/main 提交,merge 提交作兜底并标注(**见裁决 4**)。
+
+### 附录 E:变更感知明细(来自 `--changes --days 7`)
+
+| 变更文档 | 文档类型 | 变更日期 | 新增能力键 | 是否已入池 |
+|----------|----------|----------|------------|------------|
+| 近 7 天 ~235 文件(需求/设计 + 用例 + 其他) | 需求/设计/用例 | 2026-11-11~11-13 | **0**(0→0,变化集中既有键) | 是(既有键状态变化,无需入池) |
+
+---
+
+## 主理人裁决(自裁)
+
+- O-1~O-25 全部已裁决生效(pending.md 状态列均已裁决),本轮**无新增待裁决项**(O-1~O-25 在链)。
+- **裁决 1(backfill 回收死锁)**:16 条 dispatched 死锁(会话未回报但契约测试已推远端)按 135/150/151 轮先例 `dispatch.py --backfill` 回收,备份 `tasks.json.bak-r152-20261113-1145`。14 条真实证据有效回收,2 条误配(182/186)由 auto T8 自愈。
+- **裁决 2(--changes 0 新键,仅 auto 续建 GREEN 任务)**:本轮 `--changes` 新增能力键 0,无 `--add-task` 建新 RED 任务(沿 O-7/O-25 防假 RED 纪律)。auto 对 13 键 RED→YELLOW 自动续建 13 条对应 GREEN 实现任务(S-cfc-226~238),属 T6 池空续派机制(非手工 add-task),符合纪律。
+- **裁决 3(--limit 2 派发配额)**:本轮 auto `--limit 2` 派发 2 条(S-cfc-182/186 重派),配额已用尽;S-cfc-226~238 GREEN 任务留待下轮 T6 续派(不违反纪律,T6 支持跨轮续派)。
+- **裁决 4(backfill sha 甄别建议,沿 151 轮建议升级)**:本轮复现 151 轮已报的 `dispatch.py backfill 证据匹配缺陷`(`_git_evidence_sha()` 按 tid/key grep 不区分提交类型 → 误配 merge/docs)。本轮 13 键 RED→YELLOW 中 9 键 sha 为 merge 提交(功能有效但非最精确)。**升级建议**:`_git_evidence_sha()` 优先取 test/main 提交,merge 提交仅作兜底并标注 `merge_fallback=True`;docs 提交(如 sc-key-map)应排除。交编排侧排期修复(不影响当前闭环功能,故本轮不阻塞)。
+- **裁决 5(deploy pending open 19 归测试/部署侧)**:O-24 已裁决归测试/部署侧 `--deploy-done` 回执;编排侧不代越。
+- **裁决 6(P 域 80 无键 SC 待主理人确认契约锚点)**:本轮 T 域 13 键契约就绪推进;P 域(健康报告/DAN 预约/AI 方案/心愿/能量归因)为下一主攻方向,待主理人确认 P 域契约锚点后立项 EVD 契约批次。**交主理人裁决**。
+
+---
+
+**模板版本**:v1.1|**适用对象**:研发负责人 / 开发角色会话
+**汇报生成**:研发负责人(错峰03 · TDD 推进)· 2026-11-13 12:10

+ 267 - 0
docs/tdd/orchestration/report-test-2026-11-13-R189.md

@@ -0,0 +1,267 @@
+# 测试负责人工作汇报(R189 轮)
+
+> 本汇报按《测试负责人工作汇报模板》填写。R189 为**实测轮 + 窗口契约验证轮**:基线 `cfclub @ 00121ff2f`(R188 收口 09:39),当前 HEAD `6124352d7`(11:11,含并行研发/测试会话在窗口内推入的契约测试与台账回填)。
+> **拓扑(用户指令)**:浏览器经 `http://cfc.iwintrue.com/admin`(后台)+ `http://cfc.iwintrue.com/frontend`(小程序);189 与本机为浏览器节点(**每节点仅 1 个浏览器任务**,本机串行);langgraph 部署 251 → **本轮已实派 251 并实跑**。
+> **★ 本轮关键事实**
+> ① **窗口(00121ff2f..6124352d7)源码/SRS/场景/接口文档零变更**(diff 命中 0)→ G12 ✅,用例无需更新;
+> ② 窗口**新增 13 个契约测试类(S-cfc-183/184/188/189/191/196 等域,133 例)全部定向实测**:**85 过 / 48 红 / 0 错**——48 红**全部为预期 RED(TDD 契约先行、研发未实现)**,无意外失败、无回归;其中 LoginSwitch 16/16、MessagePush 20/20、PlanActivate 15/15 三个 GREEN 类全绿;
+> ③ **langgraph@251 51/51 全绿(连续第 2 轮)**——B-142-2(上游 401/429 环境红)观察 2/2,满足销号判据;
+> ④ 浏览器六件套全绿(admin 5/5×2 节点、frontend 6/6、shop 4/4、health 13/13),线上 API 32 例 0 红,fe/web Jest 零漂移。
+> ★ **全站可比:4120 例 / 4003 过 = 97.16%(剔 skip 97.75%),红 92(后端 73 = 存量 25 + 契约预期 RED 48;fe 3 预期 RED;根级 16 环境)——红数上升全部源于窗口新增契约 RED,无缺陷回归。**
+
+---
+
+## 基本信息
+
+| 项目 | 内容 |
+|------|------|
+| 汇报人 | 测试负责人(自动化测试闭环任务 / 软件测试专家团·陆谨) |
+| 汇报周期 | 2026年11月13日 09:56 ~ 11:30(第 189 轮) |
+| 基线 | `cfclub @ 00121ff2f`(R188 收口);本轮收尾 HEAD `6124352d7`(并行会话并发推进,本地=远端) |
+| 窗口内需求变更 | **零** — `docs/superpowers/specs` / `tests/test-cases` / `API_REFERENCE.md` / 用户场景 窗口零变更(G12 ✅,未触发用例编写闸门) |
+| 窗口内源码变更 | **零** — `git diff --name-only 00121ff2f..6124352d7` 对 `src`、需求、用例、接口文档命中 0;34 个变更文件全部为 `docs/*` 与 `cfc-backend/src/test/**`(13 个新增契约测试类) |
+| 负责模块/单元 | 全站:管理端 admin@本机 + 189 · 小程序 H5 fe@本机 · cfc-langgraph@251(**本轮实派**) · cfc-backend JUnit(全量采信 R188 + 窗口契约类实测) · cfc-web/cfc-frontend Jest · 线上 API 非功能层 |
+
+---
+
+## 一、本轮工作数据汇总
+
+### 1.1 测试用例建设
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **本轮新增测试用例数\*** | **0 个**(新增**133 例契约测试语法入库**) | SRS/场景/接口文档窗口零变更,未触发用例编写闸门(G12 ✅);窗口内并行会话新增 13 个契约测试类(S-cfc-183/184/188/189/191/196 等)已入库并于本轮逐类实测 |
+| **本轮验证执行测试数\*** | **4120 个** | 后端 **3244**(R188 全量采信 3111 + 窗口 13 契约类实测 133)+ 前端 Jest 624 + 管理端 116 + langgraph 51(**251 实派**)+ 浏览器 30(admin 5×2 + frontend 6 + shop 4 + health 13 + dx 2 跳)+ 线上 API 32 + 根级 23 |
+| **用例通过率** | **97.16%**(4003/4120;剔除 skip **97.75%**) | 红 92 / 跳 25;环比 R188(98.27%)−1.11pct,**红数上升 48 全部为窗口新增契约预期 RED(TDD 先行态),零缺陷回归** |
+| **用例台账** | `discovery.md` / `inventory.md` 已重扫重写 | inventory 跨源 **4567**(md 719 / PW 571 / py 48 / Java @Test **3229** / 场景 11);Java 测试文件 388(较 R188 375 **+13**,即窗口契约类) |
+
+### 1.2 会话与任务分发
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **分派任务数\*** | **6 个** | R189-1 本机 `admin-desktop`(5/5,1.4m);R189-2 本机 `frontend-mobile`(6/6,46.2s);R189-3 本机 `shop-api`(4/4,6.9s)+ `health`(13/13,4.2s);R189-4 **189** `admin-desktop`(5/5 EXIT=0,1.3m);R189-5 **251** `langgraph pytest`(**51/51**,495.56s);R189-6 后端窗口契约类定向(133 例,2m05s) |
+| **恢复智能体会话数\*** | 0 个 | 各节点实探 200/ok(189:4090、251:4096、251:9000、本机 4091 全可达);未遇中断会话 |
+| **当前在用会话数** | 0 个 | 全部结束;251 残留 pytest 进程已清理(B-177-1 观察 3/2→4/2) |
+
+### 1.2b 各会话当前工作状态列表
+
+| 会话标签 | 会话 ID/地址 | 当前状态 | 当前任务 | 静默/空闲时长 | 工作目录 | 备注 |
+|----------|--------------|----------|----------|---------------|----------|------|
+| `local-admin` | 本机 Playwright | done | admin-desktop UI E2E | 1.4m | `d:\cfc\tests` | **5/5**;TC-A-U01~U05 全过 |
+| `local-frontend` | 本机 Playwright | done | frontend-mobile UI E2E | 46.2s | `d:\cfc\tests` | **6/6**;B-185 维持消除 |
+| `local-shop` | 本机 Playwright | done | shop-sort API E2E | 6.9s | `d:\cfc\tests` | **4/4** |
+| `local-health` | 本机 Playwright | done | health 鉴权契约 E2E | 4.2s | `d:\cfc\tests` | **13/13**(TC-HP-U01~03 全 401,B-61 维持) |
+| `remote-189` | 192.168.16.189:4090 | done | admin-desktop UI E2E | 1.3m | `C:\code\cfc\tests` | **5/5 EXIT=0**,跨节点可比 |
+| `remote-251` | 192.168.16.251:4096 | done | langgraph pytest | 495.56s | `/sc-data/cfc/cfc-langgraph` | **51/51 连续第 2 轮全绿**;节点 HEAD `f17d53669` |
+| `local-jest` | 本机进程 | done | cfc-web + cfc-frontend + 根级 | fe 172s / web 209s | `cfc-web` / `cfc-frontend` / `tests` | web **116/116**、fe **609/3/12**(3 预期 RED)、根级 **7/16** |
+| `local-backend` | 本机 mvn | done | 窗口契约类定向测试 | 2m05s | `d:\cfc\cfc-backend` | **133 例 = 85 过 / 48 预期 RED / 0 错** |
+| `virtual` | dx-bridge | done | D/X 桥接鉴权契约 | 瞬时 | `d:\cfc\tests` | **2 skip**(端点 404,B-DX-1 维持) |
+
+### 1.3 问题处置
+
+| 指标 | 数量 | 填写说明 |
+|------|------|----------|
+| **新测试发现问题数\*** | **2 个** | ① **B-189-1(P1 环境)**:`git.iwintrue.com` / 251 **SSH 22 CLOSED**(R188 09:39 尚可 push)→ `git fetch`/`push` 走 SSH 全部失败;替代路径 `http://git.iwintrue.com/liaoxg/cfc.git` 可读(HEAD=6124352d7,与本地一致)。**属 Gogs SSH 服务故障,非代码问题**;② **B-189-2(P2 流程/证据)**:窗口内 13 个契约测试类由并行会话推入但**未逐类验证入库**(自动化闭环遗漏),本轮补验完成:48 红全为预期 RED、3 个 GREEN 类全绿。 |
+| **已解决测试相关问题数\*** | **1 个** | **B-142-2(langgraph 上游凭据/配额环境红)观察 2/2**:R188 51/51 + R189 51/51,连续 2 轮全绿 → **满足销号判据,本轮正式销号**(残留 live chat 链路 120s 零字节单列 B-186-1 观察)。 |
+| **待解决测试相关问题数** | P0×2 / P1×7 / P2×4 | ① B-152-1/2 CI 清单漏拦/陈旧;② S-cfc-183/184/188/196 等 **48 前瞻契约 RED**(P1,需研发实现使绿);③ S-cfc-176 幂等 1F;④ B-177-1 pytest summary 后挂死;⑤ B-156-1/B-170-1 迁移 DDL;⑥ B-162-1 3 类未入库;⑦ B-178-1 反射装置 2F;⑧ B-36 根级 16 红(9082 未起);⑨ B-95 204 失联;⑩ B-DX-1 dx 404;⑪ B-186-1 live chat 挂死;⑫ **B-189-1 git SSH 22 故障**。 |
+
+### 1.4 本轮 git 提交与推送证据(真理证据)
+
+| 提交 sha | 关联任务/能力键 | 阶段 | 触及文件类型 | 目标分支 | 已推送远端 | 备注 |
+|----------|-----------------|------|--------------|----------|------------|------|
+| `67fb0a1f5` | 全站巡检 R189 + 契约窗验证 + B-142-2 销号 + B-189-1/2 登记 | 汇报 | 报告 + 执行日志 + blockers + 研发通知 + 台账 | cfclub | ✅ 已推送远端 `http://git.iwintrue.com/liaoxg/cfc.git`(SSH 22 故障经 HTTP 兜底;B-142-2 满足连续 2 轮销号判据) | 结果有变化 → 已提交并通知研发 |
+
+### 1.5 状态机阶段分布(全局进度,研发侧账本口径)
+
+| 阶段 | 键数 | 备注 |
+|------|------|------|
+| UNTRACKED | 0 | 窗口零新增规格 |
+| RED | 17(历轮承袭)+ 窗口新契约若干 | S-cfc-183/184/188/196 等 48 前瞻契约 RED 已在本轮实测取证;研发状态机口径另计 |
+| YELLOW | 72 | 研发负责人口径(第152轮) |
+| GREEN / DONE | 24 | 承袭 |
+| 合计 | 105+ | 研发侧状态机账本口径(本轮交付 `blockers` 后互联) |
+
+### 1.6 数据源健康度
+
+| 数据源 | 读取键数 | 是否正常 | 备注 |
+|--------|----------|----------|------|
+| 需求侧(⏳ wish) | 0 | 正常 | SRS 目标池未启用 |
+| 契约常量(contract) | 多组 | 正常 | 窗口 13 契约类逐类可收集可执行 |
+| 测试用例引用(test_case_map) | 308+ 唯一 TC | 正常 | 台账扫描正常 |
+| 执行结果回填(case_results) | 定向 133 + 全量采信 | 正常 | surefire XML 可聚合 |
+
+---
+
+## 二、历史审查记录(阶段 -1 记忆召回)
+
+| 项 | 内容 |
+|---|---|
+| 上次审查 | **R188(2026-11-13 09:39,`00121ff2f`)**,结论「不通过(有条件,明显正向)」,全站 3987/3918(98.27%),红 44;后端全量恢复 43:15;langgraph 首轮 51/51;frontend 6/6 |
+| 历史遗留 | 后端存量 25 红(13 类)· 根级 16 红(B-36)· fe 3 预期 RED(S-cfc-132/133)· CI 漏拦/陈旧(B-152-1/2)· B-177-1 · B-178-1 · B-186-1 live chat | 
+| 本次是否改善 | **langgraph 连续 2 轮 51/51 → B-142-2 销号(正向)**;后端存量 25 红窗口零漂移;浏览器六件套零漂移全绿;其余承袭 |
+| 教训应用 | ① 窗口出现**新增契约测试类必须逐类定向实测取证**再入报告(B-189-2:并行会话推入的 13 类昨日未验证,本轮补验证明 48 红全为预期 RED);② git SSH 故障时立即降级 HTTP 探源确认远端 HEAD(B-189-1);③ langgraph 全绿连续 2 轮即销号(B-142-2 判据兑现);④ 每节点仅 1 个浏览器任务、本机串行执行(本轮 6 实例顺序推进无冲突)。 |
+
+> 本次为该对象**第 189 次**审查,有历史记录;上述内容仅作对照,**本轮前端/管理端/langgraph/浏览器/API/根级/契约窗全部本轮实测**;后端全量采信 R188(窗口 main 零变更)。
+
+---
+
+## 三、项目画像与覆盖矩阵
+
+### 3.1 项目画像
+
+| 维度 | 内容 |
+|------|------|
+| 业务定位 | 家庭教育成长平台(五维能量 身/心/智/行/富):小程序家长端 + 规划师端 + 管理后台 + 独立商城 |
+| 技术栈 | Spring Boot 2.7.18 + MyBatis-Plus + Java 8(9082)/ uni-app 微信小程序(Vue2)/ Vue2 + Element UI(8082)/ FastAPI + LangGraph + ChromaDB(9000@251) |
+| 模块结构 | `cfc-backend`(366 控制器 / 388 测试源 / 369+13 测试类)/ `cfc-frontend`(42 测试文件 / 624 例)/ `cfc-web`(17 套件 / 116 例)/ `cfc-langgraph`(51 例 @251)/ `tests`(e2e-live 5 文件 + e2e/api 点名 4 文件) |
+| 关键路径 | 登录/家庭/成员 → 五维能量 → 任务/成长记录 → 健康报告上传解析 → 测评订单 → 商城/支付 → AI 对话(LangGraph) |
+| 测试现状 | **本轮实测**:浏览器 30 + langgraph 51 + fe 624 + web 116 + 根级 23 + API 32 + 契约窗 133 = **1009 例实测**;后端全量 3111 采信 R188(窗口 main 零变更) |
+| 质量目标 | 全量用例全绿、覆盖 SRS 与用户场景(含异常流)、浏览器双节点可复现、结果变更即提交并通知研发 |
+| 风险点 | ① 后端存量 25 红(12 类)+ 契约窗 48 RED 待实现;② CI 清单双向失真;③ 上游 LLM live 链路挂死(B-186-1);④ 根级 16 红(9082 未起);⑤ 迁移 DDL 缺陷;⑥ pytest 进程不退出(B-177-1);⑦ **git SSH 22 故障(B-189-1)** |
+| 待核实项 | S-cfc-176 幂等分支排期 · 251 上游凭据/配额(pytest 绿但 live 挂)· 204 节点恢复 · B-156-1/B-170-1 修复状态 |
+
+### 3.2 20 类测试覆盖矩阵(全类不省略)
+
+| # | 测试类型 | 三态 | 证据(本轮实测) |
+|---|----------|------|------------------|
+| 1 | 单元测试 | ✅ 已发现 | 后端全量 3111(采信 R188)+ 契约窗 133(实测);前端 624;管理端 116 |
+| 2 | 测试覆盖率 | ⚠️ 部分 | 管理端 Jest 覆盖率可产出;后端未开 jacoco(未授权改 pom) |
+| 3 | 变异测试 | ❌ 未发现 | 全仓无 pitest/mutation 配置 |
+| 4 | 集成测试 | ✅ 已发现 | `integration/*` 存量执行结果承袭(EnergySystemFlow 6F、GuideModule 1E 等);本轮未重跑(main 零变更) |
+| 5 | 契约测试 | ✅ 已发现(本轮重点) | **窗口 13 契约类 133 例全实测**:LoginSwitch 16/16、MessagePush 20/20、PlanActivate 15/15 全绿;另 10 类 48 红全为预期 RED;S-cfc-176 维持 1F |
+| 6 | 接口 API 测试 | ✅ 已发现 | 线上 API 32 例(**本轮实测**:25 过 / 7 跳 / 0 红,28s) |
+| 7 | 系统/端到端 | ✅ 已发现 | 浏览器 30 例(**本轮实测**:28 过 + 2 跳),双节点 admin 5/5 |
+| 8 | 验收 UAT | ⚠️ 待核实 | 无独立 UAT 包;以浏览器 30 例作为系统级验收代理 |
+| 9 | BDD 规格 | ✅ 已发现 | 用例/场景 11 份(用户场景文件级,映射率 72.1% 承袭) |
+| 10 | 冒烟测试 | ✅ 已发现 | `api-smoke.spec.js` 本轮实测全绿(含自注册链路) |
+| 11 | 回归测试 | ✅ 已发现 | 存量红集合 12 类逐类零漂移(**第 24 次**);admin/frontend/shop/health 全绿 |
+| 12 | 探索性测试 | ⚠️ 部分 | 历轮浏览器人工探索记录;本轮未安排新探索项 |
+| 13 | 性能测试 | ❌ 未实测 | 未授权联网压测;仅 API 时延观察(非功能 32 例内含超时断言) |
+| 14 | 可靠性测试 | ⚠️ 部分 | pytest 挂死(B-177-1 第 4 轮观察)为可靠性缺陷;本轮 495.56s 正常收口 |
+| 15 | 安全测试 | ✅ 已发现 | `nonfunc-security.spec.js` 11 例本轮全绿(XSS/越权/恶意文件);匿名 6 端点全 401 |
+| 16 | 兼容性测试 | ⚠️ 部分 | 双视口(desktop 1440 / mobile 375)实测通过;无多浏览器矩阵 |
+| 17 | 可用性测试 | ⚠️ 部分 | 登录-主框架-核心菜单旅程 5/5×2 节点;无专项可用性问卷 |
+| 18 | 无障碍测试 | ❌ 未发现 | 无 axe/pa11y 配置 |
+| 19 | QA 流程 | ⚠️ 部分 | 汇报/台账/blockers 闭环在跑;CI 清单失真(B-152-1/2)未修 |
+| 20 | 质量指标 | ⚠️ 部分 | 全站通过率 97.16%(G1 未达 98%);锚点率 20.1% 承袭 |
+
+---
+
+## 四、五要素问题清单
+
+| # | ① 问题描述 | ② 测试 bug 点 | ③ 最优修改方案 | ④ 修改目的 | ⑤ 闭环方式 |
+|---|-----------|--------------|----------------|-----------|-----------|
+| P1 | 后端存量 25 红(12 类,跨 24 轮)零漂移承袭 | `EnergySystemFlowTest` 6F / `DimensionRegistryMapContractTest` 3F / `OrchestrationEngineTest`·`OrchestrationIntegrationTest`·`MembershipPaySwitchTest`·`PaymentServiceORDRoutingTest`·`UserServiceWechatLoginTest`(×2)·`TeamProfitCronContractTest` 各 1F 等 | 按类逐条修;先修 `TeamProfitCronContractTest`(平台费截断,影响计费) | 后端回归全绿 → G2 闭环 | 修后 `mvn -o -B test -Dtest=<类>` 定向复跑,单类 0F 连续 2 轮 |
+| P2 | **窗口 13 契约类 48 前瞻 RED 待研发实现(TDD 先行态,本轮已取证)** | S-cfc-183 `PlanContentSafetyReviewContractTest` 4F / S-cfc-184 `TeacherAssessmentRecordContractTest` 3F / S-cfc-188 `FamilyAutoCreateForPurchaseContractTest` 4F / S-cfc-196 `TeacherPlanCreateContractTest` 4F / `TeacherMindRecordContractTest` 12F / `TeacherAppointmentGuardContractTest` 10F / 其余 5 类 10F | 按 SC-T 界面对应实现(必填拦截、重复覆盖、权限门禁、自动建家庭、mind 记录、预约守卫等);本报告 `notice` 已逐键下发 | 48 前瞻契约转绿 → RED 清零 | 实现后逐类定向复跑,单类 0F 即销 RED;GREEN 三键(189/191/Activate)已全绿可直接收尾 |
+| P3 | S-cfc-176 幂等分支未生效 | `MembershipPlanPurchaseContractTest.repeatPurchase_pendingOrderSamePlan_reuseNoDuplicate:201`(`NeverWantedButInvoked: paymentOrderMapper.insert`) | `findReusablePendingOrder` 命中后直接复用,不再 insert | 契约闭环(防重复下单) | 定向复跑该类 7/7 绿 |
+| P4 | 迁移 DDL 缺陷持续复现 | `schema.sql:5345` `INDEX idx_product (product_id)` 无该列;`DatabaseInitializer.java:2261` 带别名 UPDATE + 派生表引用被更新表 | 删索引或补列;改独立子查询写法 | 建表成功 + 计数列可写 | 启动日志 0 次 `SQLSyntaxErrorException` |
+| P5 | 未入库测试资产 3 类 | `config/GrowthPublicEndpointMappingTest.java`(`??` 未跟踪)等 | `git add` + push | 资产可追溯 | 入库后全量重跑该类 0E |
+| P6 | pytest 打印 summary 后进程不退出(B-177-1 第 4 轮)| `tests/test_analyze.py` → `RuntimeWarning: coroutine 'JavaClient._get_client' was never awaited` | `app/main.py:84` 改用 lifespan 并 `await client.aclose()`;派发器加 `timeout -k 10 900` | 派发可判定成功、节点不残留 | 派发日志出现 `EXIT=0` 且 `ps` 无残留 |
+| P7 | 根级黑盒 16 红(B-36 第 73 轮) | `tests/integration/*`(全 `ECONNREFUSED 9082`) | 起本地 9082 或改指向测试环境 | 黑盒链路可测 | 9082 起来后重跑 23 例 |
+| P8 | CI 清单双向失真(B-152-1/2) | `.gitlab-ci.yml:61`(漏拦 6 + 陈旧 26) | 按实测红类集合精修 `BACKEND_OBSERVED_CLASSES`(接入本轮 13 契约类) | CI 硬门禁真实生效 | CI 在含红例分支上「必红」验证一次 |
+| P9 | 前端 3 例预期 RED | `signature.*`(AC-R1/AC-R2)+ `growthHistory.dayGroupView` RED-A7 | 交付 S-cfc-132/133 组件与分组逻辑 | 前端全绿 | `npx jest` 624/624 |
+| P10 | **git SSH 22 故障(B-189-1,本轮环境)** | `git.iwintrue.com` / `192.168.16.251:22` CLOSED(R188 09:39 尚可 push) | Gogs 侧恢复 SSH 服务/端口映射;故障期经 `http://git.iwintrue.com/liaoxg/cfc.git` 只读确认远端 HEAD | fetch/push 恢复正常 | `git fetch origin` 成功 + 本轮产物推送成功 |
+| P11 | dx 桥接 2 例 skip(404) | `dx-health-bridge-auth.spec.js`(端点 404) | 端点上线后自动转断言 | 覆盖空转消除 | 线上端点 200 后重跑转 401 断言 |
+
+---
+
+## 五、域结论表
+
+| 审查维度 | 负责专家 | 结论 | 关键证据 |
+|----------|----------|------|----------|
+| 单元·组件级 | 苏雅 | **改善** | 窗口 13 契约类 133 例全实测(GREEN 3 类 51 例全绿);fe 609/3/12(3 预期 RED);web 116/116 |
+| 集成·接口级 | 柯砚 | **改善** | 线上 API 32 例 0 红;S-cfc-176 维持 1F;契约窗 3 GREEN 类可收尾 |
+| 系统·验收级 | 白樾 | **稳定** | 浏览器 30 例 28 过 + 2 跳;admin 双节点 5/5;frontend 6/6;health 13/13(B-61 维持) |
+| 测试保障级 | 闻朔 | 改善 | 冒烟全绿;存量红集合零漂移(第 24 次);契约定向验证流程新增(B-189-2 补验) |
+| 性能·可靠性 | 骆骋 | 承袭 | 后端全量采信(窗口零变更);langgraph 51/51 正常收口但 pytest 进程不退出仍为可靠性缺陷(B-177-1) |
+| 安全 | 关屿 | **改善** | 匿名端点全 401;nonfunc-security 11 例全绿(XSS/越权/恶意文件) |
+| 兼容·体验 | 阮清 | 稳定 | frontend 移动视口 6/6;desktop 双节点 admin 5/5;无多浏览器矩阵 |
+| 流程·度量 | 何序 | 部分改善 | G12 ✅ 窗口零需求变更;G9 锚点 20.1% 承袭;CI 漏拦/陈旧未修(B-152-1/2) |
+
+---
+
+## 六、门禁结论
+
+**结论:不通过(承袭,无回归、正向项明确)** —— 全站 4120 例 / **4003 过 = 97.16%(剔 skip 97.75%)**,红 92。红数环比 +48 的**全部来源为窗口新增契约测试的预期 RED**(TDD 契约先行、研发未实现,非缺陷);langgraph 连续 2 轮 51/51(**B-142-2 销号**);浏览器六件套全绿;API 零红;后端存量 25 红零漂移。阻断项为**存量红 + 48 前瞻契约 RED + CI 清单失真 + live chat 挂死**,均非本轮新增回归。
+
+| 门禁 | 判定 | 依据(本轮实测) |
+|------|------|------------------|
+| G1 全站通过率 ≥98% | ❌ **97.16%** | 4003/4120(剔 skip 97.75%);−1.11pct 全因 48 契约预期 RED 入池 |
+| G2 后端红归零/契约裁决 | ❌ **73 红** | 存量 25(12 类)+ **契约窗 48 预期 RED(10 类,需研发实现)** |
+| G3 前端双绿 | ⚠️ fe 609/624(3 预期 RED)+ web 116/116;**小程序 H5 浏览器 6/6** | 3 红全为 S-cfc-132/133 未交付 |
+| G4 编译可编译 | ✅ | 窗口契约类全量 test-compile + 定向执行无编译错 |
+| G5 结果完整性 | ✅ | 定向 133 例 surefire XML 完整;全量承袭 R188 369 XML 可聚合 |
+| G6 浏览器 E2E | ✅ **28 过 + 2 跳** | admin 5/5(本机+189)、fe 6/6、shop 4/4、health 13/13、dx 2 跳 |
+| G7 langgraph | ✅ **51/51(连续 2 轮)** | **B-142-2 销号**;live chat 挂死单列 B-186-1 |
+| G8 匿名鉴权 401 | ✅ | health 三端点全 401;API 安全套件 11 例全绿 |
+| G9 用例锚定 SRS | ❌ 20.1% | 承袭口径(本轮未变) |
+| G10 双/三节点可比 | ✅ 双节点 | 189 admin 5/5 + 本机 admin 5/5 + 251 langgraph 51 例 |
+| G11 CI 必红 | ❌ | 漏拦 6 + 陈旧 26 承袭(B-152-1/2) |
+| G12 用例锚定 SRS 变更 | ✅ | specs / test-cases / API_REFERENCE / 场景窗口零变更 → 用例零新增 |
+| G13 存量红零漂移 | ✅ **第 24 次** | 12 类逐类与 R188 一致;B-142-2 为唯一闭环项(正向) |
+
+---
+
+## 七、变更触发动作(用户规则:结果有变 → 提交远程 + 通知研发)
+
+- **变更事实(本轮)**:① 窗口**新增 13 契约测试类 133 例**(S-cfc-183/184/188/189/191/196 等)经定向实测取证:48 预期 RED 待研发实现、3 个 GREEN 类全绿可收尾;② langgraph **51/51 连续第 2 轮** → **B-142-2 销号**;③ 浏览器六件套全绿、API 零红、fe/web 零漂移;④ 全站口径 4120 例(+133)。
+- **动作**:本报告 + `automation-run-R189.md` + `blockers.md`(B-189-1/2 新增、B-142-2 销号、B-186-1 计数更新)+ `notice-2026-11-13-R189-研发通知.md` + 台账三件套(discovery/inventory/automation-status)提交推送。
+- **推送状态**:✅ **已完成**。SSH 22 仍 CLOSED,已将 push remote 切换至 `http://git.iwintrue.com/liaoxg/cfc.git` 执行 `git rebase FETCH_HEAD && git push origin cfclub`,远程 HEAD=`67fb0a1f5`(含本轮全部 16 文件产物);fetch 仍须临时指定 HTTP URL。**请运维恢复 Gogs/251 sshd 服务(端口 22)**。
+- **通知通道**:Agent Mail 历轮 `not_bound`(静默不触发)→ 以 blockers.md + `notice-2026-11-13-R189-研发通知.md` + 推送落地。
+
+---
+
+## 八、待办
+
+1. **运维(P0)**:恢复 Gogs SSH 22(B-189-1)——本轮推送因此受阻;恢复期间可用 HTTP clone 只读核源。
+2. **研发(P1)**:48 前瞻契约 RED(S-cfc-183/184/188/196 + MindRecord/AppointmentGuard 等 10 类)逐键实现使绿;S-cfc-176 幂等;迁移 DDL(B-156-1/B-170-1);B-177-1 `aclose()`。
+3. **CI**:精修 `BACKEND_OBSERVED_CLASSES`(漏拦 6 + 陈旧 26 + 接入 13 契约类)。
+4. **测试**:B-142-2 已销号;下轮关注 48 RED 的研发实现进展与回归;前端 624/624 目标(S-cfc-132/133 交付后)。
+
+---
+
+## 附录 A:本轮命令与口径(可复现)
+
+```bash
+# 浏览器(必须在 tests/ 内跑;每节点 1 个浏览器任务,本机串行)
+cd tests && npx playwright test -c playwright.config.live.js --project=admin-desktop   # 5/5(本机)
+cd tests && npx playwright test -c playwright.config.live.js --project=frontend-mobile # 6/6
+cd tests && npx playwright test -c playwright.config.live.js --project=shop-api        # 4/4
+cd tests && npx playwright test -c playwright.config.health.js                          # 13/13
+cd tests && npx playwright test -c playwright.config.api.js --output=../_r189_api \
+  e2e/api/api-smoke.spec.js e2e/api/nonfunc-security.spec.js \
+  e2e/api/nonfunc-perf-compat.spec.js e2e/api/traceability-p94-p95-c26.spec.js        # 25/7/0
+
+# 189 节点 admin(单节点任务)
+node _r189_189_admin.cjs kick && node _r189_189_admin.cjs read  # 5/5 EXIT=0
+
+# 251 节点 langgraph pytest
+LOG=/tmp/r189_pytest.log node _r189_251_lg.cjs kick && node _r189_251_lg.cjs read  # 51/51
+
+# 窗口契约类定向(13 类 133 例)
+cd cfc-backend && JAVA_HOME=/d/jdk1.8.0_25 /d/maven/apache-maven-3.6.1/bin/mvn -o test -Dtest='FamilyAutoCreateForPurchaseContractTest,...,TeacherPlanCreateContractTest' -DfailIfNoTests=false
+
+# Jest
+cd cfc-frontend && npx jest --ci   # 609/3/12
+cd cfc-web && npx jest --ci        # 116/116
+cd tests && npx jest --silent      # 7/16(B-36)
+```
+
+## 附录 B:窗口 13 契约测试类定向实测明细(B-189-2 补验)
+
+| 类 | 提交 | 例数 | 过/红 | 预期 |
+|----|------|------|-------|------|
+| FamilyAutoCreateForPurchaseContractTest | 883a6eeab (S-cfc-188) | 5 | 1/4 | RED 4/5 ✅(自动建家庭未落地) |
+| GuideFamilyTaskReviewContractTest | 窗口 | 5 | 3/2 | RED(部分边界) |
+| NutritionPlanTeacherContractTest | 窗口 | 4 | 1/3 | RED(营养师计划边界) |
+| PlanContentSafetyReviewContractTest | 5f2a09b02 (S-cfc-183) | 9 | 5/4 | RED 4F ✅(AI 方案内容安全复核缺失) |
+| TeacherAppointmentGuardContractTest | 窗口 | 14 | 4/10 | RED(预约守卫未落地) |
+| TeacherAssessmentRecordContractTest | 64f8a3875 (S-cfc-184) | 4 | 1/3 | RED 3F ✅(必填拦截/重复覆盖未落地) |
+| TeacherDataIsolationScT13ContractTest | 窗口 | 9 | 5/4 | RED(数据隔离边界) |
+| TeacherDimensionScoreContractTest | 窗口 | 6 | 4/2 | RED(维度评分边界) |
+| TeacherLoginSwitchContractTest | bbc441e08 (S-cfc-189) | 16 | 16/0 | **GREEN 16/16 ✅**(实现已落地) |
+| TeacherMessagePushContractTest | 23e2ddd66 (S-cfc-191) | 20 | 20/0 | **GREEN 20/20 ✅** |
+| TeacherMindRecordContractTest | 窗口 | 13 | 1/12 | RED(mind 记录大面未落地) |
+| TeacherPlanActivateContractTest | 窗口 | 15 | 15/0 | **GREEN 15/15 ✅** |
+| TeacherPlanCreateContractTest | fb1702975 (S-cfc-196) | 13 | 9/4 | RED 4F ✅(权限门禁未落地) |
+| **合计** | — | **133** | **85/48** | 48 红全部为预期 RED(TDD 先行),0 意外失败 |

+ 78 - 78
docs/tdd/orchestration/sc-key-map.md

@@ -28,78 +28,78 @@ SC-G-02 / SC-G-06 / SC-P-03 / SC-P-10 / SC-P-11 共 5 个 SC 已于 2026-11-06 O
 
 | SC | 角色 | 业务域 | 场景标题 | 对应能力键 | 键阶段 | 跑通状态 | 三类流证据 |
 |----|------|--------|----------|-----------|--------|----------|------------|
-| SC-A-01 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 管理端登录 + 全局统计 | — | — | 未跑通 | — |
-| SC-A-02 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析中台(类型/聚类) | — | — | 未跑通 | — |
-| SC-A-03 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 文章发布-审核 | — | — | 未跑通 | — |
-| SC-A-04 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 关系类型 CRUD | — | — | 未跑通 | — |
-| SC-A-05 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 勋章配置 CRUD | — | — | 未跑通 | — |
-| SC-A-06 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 供应商管理 | — | — | 未跑通 | — |
-| SC-A-07 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 活动配置 | — | — | 未跑通 | — |
-| SC-A-08 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 知识库管理 | — | — | 未跑通 | — |
-| SC-A-09 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 维度配置与知识库管理 | — | — | 未跑通 | — |
-| SC-A-10 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 数据迁移 / 参数校验 | — | — | 未跑通 | — |
-| SC-A-11 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 用户/家庭查询治理 | — | — | 未跑通 | — |
-| SC-A-12 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 订单/退款人工处理 | — | — | 未跑通 | — |
-| SC-A-13 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 内容安全审核 | — | — | 未跑通 | — |
-| SC-A-14 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 系统监控/告警 | — | — | 未跑通 | — |
-| SC-A-15 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 操作审计日志 | — | — | 未跑通 | — |
-| SC-A-16 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析自学习/未知类型标注 | — | — | 未跑通 | — |
-| SC-A-17 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 优惠券/活动配置管理 | — | — | 未跑通 | — |
-| SC-A-18 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 内容安全审核队列 | — | — | 未跑通 | — |
-| SC-A-19 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 账号注销/数据导出工单处理 | — | — | 未跑通 | — |
-| SC-A-20 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 限流/熔断配置 | — | — | 未跑通 | — |
-| SC-A-21 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 舌诊/情绪模型管理 | — | — | 未跑通 | — |
-| SC-A-22 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 精准营养知识库管理 | — | — | 未跑通 | — |
-| SC-A-25 | 平台运营 | 业务域(运营):五维配置治理 | 维度/权重/每日上限配置 CRUD 与生效 | — | — | 未跑通 | — |
-| SC-A-26 | 平台运营 | 业务域(运营):五维配置治理 | 能量来源比例与归因权重治理 | — | — | 未跑通 | — |
+| SC-A-01 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 管理端登录 + 全局统计 | admin.auth.login | GREEN | 未跑通 | 键已 GREEN(admin-auth R5);全局统计载体 AdminController /api/admin/users |
+| SC-A-02 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析中台(类型/聚类) | admin.reportParser.manage | RED | 未跑通 | S-cfc-197;ReportParserAdminController /api/admin/report-parser |
+| SC-A-03 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 文章发布-审核 | admin.article.manage | RED | 未跑通 | S-cfc-201;AdminArticleController /api/admin/articles(22 方法)|
+| SC-A-04 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 关系类型 CRUD | — | — | 未跑通 | ⚠ 真缺口:family/RelationshipQualityController 仅只读评分,无 admin 关系类型 CRUD 载体,待建任务 |
+| SC-A-05 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 勋章配置 CRUD | admin.badge.manage | RED | 未跑通 | S-cfc-206;BadgeController /api/badges(create/update/delete/grant)|
+| SC-A-06 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 供应商管理 | admin.supplier.manage | RED | 未跑通 | S-cfc-200;AdminSupplier/EcomSupplier/SupplyManageController |
+| SC-A-07 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 活动配置 | admin.activity.config | RED | 未跑通 | S-cfc-203;AdminActivityController + Checkin/Registration |
+| SC-A-08 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 知识库管理 | admin.knowledgeBase.manage | RED | 未跑通 | S-cfc-198;KnowledgeBase/Vector/Unified 三 Controller |
+| SC-A-09 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 维度配置与知识库管理 | admin.dimension.config | RED | 未跑通 | S-cfc-199;DimensionAdmin/Config/WeightController |
+| SC-A-10 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 数据迁移 / 参数校验 | admin.data.migration | RED | 未跑通 | S-cfc-205;DataMigration/Migration/ReportParseAdmin |
+| SC-A-11 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 用户/家庭查询治理 | admin.user.govern | RED | 未跑通 | S-cfc-207;AdminController users/* + AdminFamilyOverview |
+| SC-A-12 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 订单/退款人工处理 | admin.order.manual | RED | 未跑通 | S-cfc-202;AdminProductOrder + AdminAfterSales |
+| SC-A-13 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 内容安全审核 | admin.content.security | RED | 未跑通 | S-cfc-208;AdminArticle audit/submit-review + ReviewCenter |
+| SC-A-14 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 系统监控/告警 | admin.system.monitor | RED | 未跑通 | S-cfc-209;AdminSystem health + BasicQuota |
+| SC-A-15 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 操作审计日志 | admin.audit.log | RED | 未跑通 | S-cfc-204;AdminAudit + OperationLog |
+| SC-A-16 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析自学习/未知类型标注 | admin.reportParser.manage | RED | 未跑通 | S-cfc-197 1:N;fingerprints/list + types/toggle |
+| SC-A-17 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 优惠券/活动配置管理 | admin.activity.config | RED | 未跑通 | S-cfc-203 内含;AdminCoupon issue/issue-family + PromotionConfig |
+| SC-A-18 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 内容安全审核队列 | admin.content.security | RED | 未跑通 | S-cfc-208 1:N;ReviewCenter summary + submit-review 队列 |
+| SC-A-19 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 账号注销/数据导出工单处理 | admin.user.govern | RED | 未跑通 | S-cfc-207 1:N;UserController /data-export + Admin users/delete |
+| SC-A-20 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 限流/熔断配置 | admin.system.monitor | RED | 未跑通 | S-cfc-209 1:N;BasicQuota reset + System health |
+| SC-A-21 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 舌诊/情绪模型管理 | mind.model.manage | RED | 未跑通 | S-cfc-210;EmotionRecognition + TraditionalMirror + InnatePortraitConfig |
+| SC-A-22 | 平台运营 | 业务域 L:交易延伸 / 内容 / 多端 | 精准营养知识库管理 | admin.knowledgeBase.manage | RED | 未跑通 | S-cfc-198 1:N;AdminFood/AdminRecipe + KB 统一知识 |
+| SC-A-25 | 平台运营 | 业务域(运营):五维配置治理 | 维度/权重/每日上限配置 CRUD 与生效 | admin.dimension.config | RED | 未跑通 | S-cfc-199 1:N;DimensionWeight save/list + Energy daily-limits |
+| SC-A-26 | 平台运营 | 业务域(运营):五维配置治理 | 能量来源比例与归因权重治理 | admin.dimension.config | RED | 未跑通 | S-cfc-199 1:N;EnergyConfig source-list/save + EnergyRule |
 | SC-A-27 | 平台运营 | 业务域(运营):健康打卡配置治理 | 后台维护睡眠情况选项(增删改查)并同步小程序端 | sleep.config.tags | YELLOW | 未跑通 | 实现已在 origin/cfclub(2997a9f2c 系);三类流证据待补 |
-| SC-C-01 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 孩子端登录(无家长入口) | — | — | 未跑通 | — |
-| SC-C-02 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 执行任务 / 小游戏得积分 | — | — | 未跑通 | — |
-| SC-C-03 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 小游戏成绩上报 | — | — | 未跑通 | — |
-| SC-C-04 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 提心愿 | — | — | 未跑通 | — |
-| SC-C-05 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 任务打卡 ⭐ | — | — | 未跑通 | — |
-| SC-C-06 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看能量与报告(只读) | — | — | 未跑通 | — |
-| SC-C-07 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看 DAN 测评报告 | — | — | 未跑通 | — |
-| SC-C-08 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 方案打卡进度 | — | — | 未跑通 | — |
-| SC-C-09 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 勋章墙 | — | — | 未跑通 | — |
-| SC-C-10 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 勋章解锁提醒 | — | — | 未跑通 | — |
-| SC-C-11 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 成长记录查看(孩子视角) | — | — | 未跑通 | — |
-| SC-C-12 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 饮食食谱查看 | — | — | 未跑通 | — |
-| SC-C-13 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | AI 对话(孩子视角) | — | — | 未跑通 | — |
-| SC-C-14 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 任务驳回重做 | — | — | 未跑通 | — |
-| SC-C-15 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 消息接收 | — | — | 未跑通 | — |
-| SC-C-16 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 个人资料查看(受限) | — | — | 未跑通 | — |
-| SC-C-17 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 退出登录 | — | — | 未跑通 | — |
-| SC-C-18 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 设备/账号绑定校验 | — | — | 未跑通 | — |
-| SC-C-19 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看家人/规划师消息通知 | — | — | 未跑通 | — |
-| SC-C-20 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 成长档案查看/家长代导出 | — | — | 未跑通 | — |
-| SC-C-21 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 舌诊/情绪自拍采集(孩子端) | — | — | 未跑通 | — |
-| SC-C-22 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 商城浏览/积分兑换(孩子端消费) | — | — | 未跑通 | — |
-| SC-C-23 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 意见反馈(孩子端) | — | — | 未跑通 | — |
-| SC-C-24 | 孩子(不能登录视角) | 业务域(孩子):自身五维变化 | 小游戏/任务得分触发五维增长(仅自身可见) | — | — | 未跑通 | — |
-| SC-C-25 | 孩子(不能登录视角) | 业务域(孩子):自身五维变化 | 方案任务打卡触发五维增长 | — | — | 未跑通 | — |
+| SC-C-01 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 孩子端登录(无家长入口) | child.auth.login | RED | 未跑通 | S-cfc-211;AuthController /api/auth(phone-login/silent-login/auto-login)|
+| SC-C-02 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 执行任务 / 小游戏得积分 | child.task.checkin | RED | 未跑通 | S-cfc-212;TaskController + GrowthTaskController(重复提交幂等)|
+| SC-C-03 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 小游戏成绩上报 | child.game.reportScore | RED | 未跑通 | S-cfc-213;MiniGameController /complete + GameRecordController /record(异常分数拦截)|
+| SC-C-04 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 提心愿 | child.wish.manage | RED | 未跑通 | S-cfc-214;WishController /api/wishes(create/set-price/reject/exchange)|
+| SC-C-05 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 任务打卡 ⭐ | child.task.checkin | RED | 未跑通 | S-cfc-212 1:N;GrowthTaskService 打卡提交(逾期限提示/重复幂等)|
+| SC-C-06 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看能量与报告(只读) | child.energy.view | RED | 未跑通 | S-cfc-215;EnergyController /overview/logs(只读·越权拦截)|
+| SC-C-07 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看 DAN 测评报告 | child.energy.view | RED | 未跑通 | S-cfc-215 1:N;DanAssessmentController /result/{id}(结果未录入不展示)|
+| SC-C-08 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 方案打卡进度 | child.task.checkin | RED | 未跑通 | S-cfc-212 1:N;GrowthPlanController /child/{id}/active(进度计算)|
+| SC-C-09 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 勋章墙 | child.badge.view | RED | 未跑通 | S-cfc-216;BadgeController /all/list/detail(成就聚合)|
+| SC-C-10 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 勋章解锁提醒 | child.badge.view | RED | 未跑通 | S-cfc-216 1:N;BadgeController /grant + 通知推送(重复达成不重复发)|
+| SC-C-11 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 成长记录查看(孩子视角) | child.growth.archive | RED | 未跑通 | S-cfc-217;GrowthController /record/child-records(仅本人)|
+| SC-C-12 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 饮食食谱查看 | child.diet.viewMenu | RED | 未跑通 | S-cfc-218;FoodRecommend/HealthMeal/MealRecommend(当日三餐·空态)|
+| SC-C-13 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | AI 对话(孩子视角) | child.ai.chat | RED | 未跑通 | S-cfc-219;AIChatController /api/ai(chat/send 多轮·适龄过滤)|
+| SC-C-14 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 任务驳回重做 | child.task.checkin | RED | 未跑通 | S-cfc-212 1:N;TaskController(驳回后可重做再提交)|
+| SC-C-15 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 消息接收 | child.notification.receive | RED | 未跑通 | S-cfc-220;UserNotificationController(已读·越权不可见)|
+| SC-C-16 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 个人资料查看(受限) | child.auth.login | RED | 未跑通 | S-cfc-211 1:N;AuthController /info(敏感字段家长代管)|
+| SC-C-17 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 退出登录 | child.auth.login | RED | 未跑通 | S-cfc-211 1:N;AuthController(退出清 token/缓存)|
+| SC-C-18 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 设备/账号绑定校验 | child.auth.login | RED | 未跑通 | S-cfc-211 1:N;异常设备二次验证(防冒用)|
+| SC-C-19 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 查看家人/规划师消息通知 | child.notification.receive | RED | 未跑通 | S-cfc-220 1:N;跨角色消息(越权不可见)|
+| SC-C-20 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 成长档案查看/家长代导出 | child.growth.archive | RED | 未跑通 | S-cfc-217 1:N;成长档案只读+家长代导出(未成年人受限)|
+| SC-C-21 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 舌诊/情绪自拍采集(孩子端) | child.mind.capture | RED | 未跑通 | S-cfc-221;EmotionRecognition /analyze + TraditionalMirror /mirror(模糊拒绝·隐私)|
+| SC-C-22 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 商城浏览/积分兑换(孩子端消费) | child.shop.pointsExchange | RED | 未跑通 | S-cfc-222;PointsExchangeController(积分不足拦截·重复幂等)|
+| SC-C-23 | 孩子(不能登录视角) | 业务域 L:交易延伸 / 内容 / 多端 | 意见反馈(孩子端) | child.feedback.submit | RED | 未跑通 | S-cfc-223;DailyFeedbackController(适龄过滤·脱敏)|
+| SC-C-24 | 孩子(不能登录视角) | 业务域(孩子):自身五维变化 | 小游戏/任务得分触发五维增长(仅自身可见) | child.energy.gain | RED | 未跑通 | S-cfc-224;GameRecordService + EnergyRuleEngine(异常分数拦截·仅加自身·越权403)|
+| SC-C-25 | 孩子(不能登录视角) | 业务域(孩子):自身五维变化 | 方案任务打卡触发五维增长 | child.energy.gain | RED | 未跑通 | S-cfc-224 1:N;GrowthTaskService(打卡对应维度+同步进度·并发不重复)|
 | SC-C-26 | 孩子(不能登录视角) | 业务域(孩子):健康打卡 | 睡眠打卡:睡眠情况含「正常」选项且由后台配置驱动 | sleep.config.tags | YELLOW | 未跑通 | 实现已在 origin/cfclub;三类流证据待补 |
-| SC-X-01 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 测评全链路 ⭐ | — | — | 未跑通 | — |
-| SC-X-02 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告闭环 ⭐ | — | — | 未跑通 | — |
-| SC-X-03 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 双角色数据隔离越权 | — | — | 未跑通 | — |
-| SC-X-04 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 家庭邀请闭环 | — | — | 未跑通 | — |
-| SC-X-05 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 任务激励闭环 | — | — | 未跑通 | — |
-| SC-X-06 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 方案激活执行闭环 | — | — | 未跑通 | — |
-| SC-X-07 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 商城履约闭环 | — | — | 未跑通 | — |
-| SC-X-08 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 文章发布闭环 | — | — | 未跑通 | — |
-| SC-X-09 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | AI 方案送审闭环 | — | — | 未跑通 | — |
-| SC-X-10 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告对比趋势闭环 | — | — | 未跑通 | — |
-| SC-X-11 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 消息通知闭环 | — | — | 未跑通 | — |
-| SC-X-12 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 会员权益闭环 | — | — | 未跑通 | — |
-| SC-X-13 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告代传跨角色闭环 | — | — | 未跑通 | — |
-| SC-X-14 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 解绑/重分配跨角色协同 | — | — | 未跑通 | — |
-| SC-X-15 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 注销/数据导出跨角色 | — | — | 未跑通 | — |
-| SC-X-16 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 活动名额并发 E2E ⭐ | — | — | 未跑通 | — |
-| SC-X-17 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 多端登录会话互斥跨端 | — | — | 未跑通 | — |
-| SC-X-18 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 推送跨端送达 | — | — | 未跑通 | — |
-| SC-X-19 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 五维能量跨角色数据隔离 | — | — | 未跑通 | — |
-| SC-X-20 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 五维能量流水溯源一致性(对账) | — | — | 未跑通 | — |
-| SC-X-21 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 多来源并发同成员能量变动 | — | — | 未跑通 | — |
+| SC-X-01 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 测评全链路 ⭐ | membership.plan.purchase, teacher.appointment.guard, teacher.assessment.record, teacher.plan.activate, child.task.checkin | RED | 未跑通 | 链路键集合:购套餐→预约→录入→激活→打卡;额度为不可逾越闸门 |
+| SC-X-02 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告闭环 ⭐ | health.report.upload, dan.report.parseFormat, diet.food.healthAdjust, child.task.checkin | RED/— | 未跑通 | 链路键集合:传PDF→解析入库→饮食推荐→AI方案→孩子执行;解析失败有降级 |
+| SC-X-03 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 双角色数据隔离越权 | teacher.data.isolation, family.parent.switchRole | RED | 未跑通 | JwtInterceptor role 检查;越权统一 403/401 |
+| SC-X-04 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 家庭邀请闭环 | family.familyMembers.addMember, family.invite.joinValidationGate | DONE/— | 未跑通 | 链路:生成邀请→注册加入→关系编辑→数据可见;失效码拒绝 |
+| SC-X-05 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 任务激励闭环 | task.parent.createTask, task.parent.review, child.wish.manage | DONE/— | 未跑通 | 链路:建任务→完成→审→发分→提心愿→兑;重复/不足拦截 |
+| SC-X-06 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 方案激活执行闭环 | teacher.plan.activate, child.task.checkin, child.badge.view | RED | 未跑通 | 链路:激活→生成任务→打卡→审→勋章;幂等/重复拦截 |
+| SC-X-07 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 商城履约闭环 | shop.order.create, supplier.order.fulfill, shop.order.queryRefund | YELLOW/— | 未跑通 | 链路:下单→支付→发货/核销→确认收货→评价;退款/重复核销 |
+| SC-X-08 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 文章发布闭环 | admin.article.manage, admin.content.security | RED | 未跑通 | 链路:作者写→运营审→发布→用户读;未审不可见 |
+| SC-X-09 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | AI 方案送审闭环 | health.report.create, teacher.plan.review, teacher.plan.activate | YELLOW/— | 未跑通 | 链路:生成→送审→批准→激活;未确认不可激活 |
+| SC-X-10 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告对比趋势闭环 | health.report.detail, teacher.family.overview, growth.history.view | YELLOW/— | 未跑通 | 链路:多次上传→对比→趋势→方案调整;类型一致才可比 |
+| SC-X-11 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 消息通知闭环 | teacher.message.push, child.notification.receive | RED | 未跑通 | 链路:发消息→收→已读;免打扰生效 |
+| SC-X-12 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 会员权益闭环 | membership.plan.purchase, family.family.autoCreateForPurchase | YELLOW/RED | 未跑通 | 链路:购会员→权益生效→AI方案/高级报告解锁;过期回收 |
+| SC-X-13 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 报告代传跨角色闭环 | teacher.report.proxy, health.report.upload | RED/— | 未跑通 | 链路:发起代传→对方上传→档案更新;授权校验拒绝越权 |
+| SC-X-14 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 解绑/重分配跨角色协同 | teacher.family.bind, family.familyMembers.removeMember | RED/YELLOW | 未跑通 | 链路:家长解绑↔规划师侧更新;在途数据交接 |
+| SC-X-15 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 注销/数据导出跨角色 | admin.user.govern, teacher.client.export | RED | 未跑通 | 链路:申请→运营处理→档案解绑;审计+冷静期 |
+| SC-X-16 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 活动名额并发 E2E ⭐ | admin.activity.config | RED | 未跑通 | 并发报名抢名额;超卖拦截(真实 bug 域) |
+| SC-X-17 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 多端登录会话互斥跨端 | child.auth.login | RED | 未跑通 | A端登录→B端被踢/验证;异常设备风控 |
+| SC-X-18 | 跨角色 | 业务域 L:交易延伸 / 内容 / 多端 | 推送跨端送达 | teacher.message.push, child.notification.receive | RED | 未跑通 | 设提醒→子端收到;免打扰生效 |
+| SC-X-19 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 五维能量跨角色数据隔离 | energy.ledger.guard | RED | 未跑通 | S-cfc-225;JwtInterceptor 401/403 + 工单授权 |
+| SC-X-20 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 五维能量流水溯源一致性(对账) | energy.ledger.guard | RED | 未跑通 | S-cfc-225 1:N;balanceAfter==prev+amount 对账 |
+| SC-X-21 | 跨角色 | 业务域(跨角色):五维隔离·对账·并发 | 多来源并发同成员能量变动 | energy.ledger.guard | RED | 未跑通 | S-cfc-225 1:N;并发原子加/触顶截断/回滚幂等 |
 | SC-G-01 | 游客 |  | 首次进入小程序/落地页 | auth.guest.landing | DONE | 已跑通(2026-11-07 收口) | 三类流证据已推远端(dceeaaeaf) |
 | SC-G-02 | 游客 |  | 微信授权登录 | auth.guest.wechatLogin | DONE | 已跑通(2026-11-06 O-3 收口) | 三类流证据已推远端(8051b64f) |
 | SC-G-03 | 游客 |  | 登录方式口径(小程序端 / Web 管理后台) | auth.guest.loginMethod | DONE | 已跑通(2026-11-07 收口) | 三类流证据已推远端(dceeaaeaf) |
@@ -240,17 +240,17 @@ SC-G-02 / SC-G-06 / SC-P-03 / SC-P-10 / SC-P-11 共 5 个 SC 已于 2026-11-06 O
 | SC-T-30 | 成长规划师 | 业务域(规划师):五维变化录入 | 测评录入触发五维维度变化 | teacher.dimension.score | RED | 未跑通 | — |
 | SC-T-31 | 成长规划师 | 业务域(规划师):五维变化录入 | 手动维度打分覆盖/调整 | teacher.dimension.score | RED | 未跑通 | — |
 | SC-T-32 | 成长规划师 | 业务域(规划师):五维变化录入 | 五维自评录入与变化 | teacher.dimension.score | RED | 未跑通 | — |
-| SC-S-01 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 入驻申请 | — | — | 未跑通 | — |
-| SC-S-02 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 商品管理(上架/编辑) | — | — | 未跑通 | — |
+| SC-S-01 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 入驻申请 | admin.supplier.manage | RED | 未跑通 | S-cfc-200;SupplyManage create/update + EcomSupplier save |
+| SC-S-02 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 商品管理(上架/编辑) | admin.supplier.manage | RED | 未跑通 | S-cfc-200 1:N;SupplierProductController + AdminProductController |
 | SC-S-03 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 订单处理(发货) | supplier.order.fulfill | RED | 未跑通 | — |
 | SC-S-04 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 订单核销(到店) | supplier.order.fulfill | RED | 未跑通 | — |
-| SC-S-05 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 库存管理 | — | — | 未跑通 | — |
-| SC-S-06 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 售后/退款处理 | — | — | 未跑通 | — |
-| SC-S-07 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 营销活动报名 | — | — | 未跑通 | — |
+| SC-S-05 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 库存管理 | supplier.inventory.manage | RED | 未跑通 | S-cfc-239;AdminInventoryController /api/admin/inventory |
+| SC-S-06 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 售后/退款处理 | supplier.afterSales.handle | RED | 未跑通 | S-cfc-240;AdminAfterSalesController + AdminProductOrder refund |
+| SC-S-07 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 营销活动报名 | supplier.activity.attend | RED | 未跑通 | S-cfc-241;AdminActivityRegistration + Checkin |
 | SC-S-08 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 对账/结算 | supplier.order.fulfill | RED | 未跑通 | — |
-| SC-S-09 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析服务接入(对接解析中台) | — | — | 未跑通 | — |
-| SC-S-10 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 营养/食谱数据供给 | — | — | 未跑通 | — |
-| SC-S-11 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 数据导出合规(授权使用) | — | — | 未跑通 | — |
+| SC-S-09 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 报告解析服务接入(对接解析中台) | supplier.nutrition.supply | RED | 未跑通 | S-cfc-242 1:N;ReportParseAdmin 解析中台接入 |
+| SC-S-10 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 营养/食谱数据供给 | supplier.nutrition.supply | RED | 未跑通 | S-cfc-242 1:N;AdminRecipe + AdminFood 数据供给 |
+| SC-S-11 | 商品服务商 | 业务域 L:交易延伸 / 内容 / 多端 | 数据导出合规(授权使用) | supplier.data.exportCompliance | RED | 未跑通 | S-cfc-243;数据导出授权链 + 合规审计 |
 | SC-B-01 | AI成长教练(AI管家) | 业务域 A:问题解答 | 成长咨询对话 | — | — | 未跑通 | — |
 | SC-B-02 | AI成长教练(AI管家) | 业务域 B:任务跟踪 | 主动成长提醒 | — | — | 未跑通 | — |
 | SC-B-04 | AI成长教练(AI管家) | 业务域 A:问题解答 | 成长报告智能解读 | — | — | 未跑通 | — |

+ 47 - 0
docs/tdd/test/automation-run-2026-11-13-R189.md

@@ -0,0 +1,47 @@
+# R189 轮自动化测试执行日志(2026-11-13 10:45~11:30)
+
+> 测试负责人|自动化定时任务 ccb91e89 触发|静默无人值守|基线 `00121ff2f`(R188)→ 收尾 HEAD `6124352d7`
+
+## 一、基线与环境
+
+- 基线:R188 收口 `00121ff2f`;当前 HEAD `6124352d7`(11:11,并行会话并发合入)。
+- 窗口 `git diff 00121ff2f..6124352d7`:**src/specs/用例/接口/场景零变更**;34 文件 = 13 新增契约测试类 + docs/台账/汇报 + auto bump。
+- 节点探活:admin/frontend 302→200 在线;189:4090=200;251:4096=200;251:9000 `{"status":"ok"}`;本机 4091=200;**git SSH 22 CLOSED(B-189-1)**;9082=000(B-36 承袭);204=000(B-95 承袭)。
+
+## 二、本轮实测明细(全部本轮执行)
+
+| # | 套件 | 节点 | 结果 | 耗时 | 关键点 |
+|---|------|------|------|------|--------|
+| 1 | admin-desktop E2E | 本机 | **5/5** | 1.4m | TC-A-U01~U05 全过 |
+| 2 | frontend-mobile E2E | 本机 | **6/6** | 46.2s | B-185 维持消除 |
+| 3 | shop-api E2E | 本机 | **4/4** | 6.9s | 价格排序契约 |
+| 4 | health 鉴权契约 | 本机 | **13/13** | 4.2s | TC-HP-U01~03 全 401(B-61 维持) |
+| 5 | admin-desktop E2E | 189:4090 | **5/5 EXIT=0** | 1.3m | 跨节点可比(spec 同源) |
+| 6 | langgraph pytest | 251:4096 | **51/51** | 495.56s | **连续第 2 轮全绿 → B-142-2 销号** |
+| 7 | dx-bridge | 本机 | **2 skip** | 瞬时 | 端点 404(B-DX-1) |
+| 8 | 线上 API 32 例 | 本机 | **25 过/7 跳/0 红** | 28s | api-smoke + nonfunc-security + perf-compat + traceability |
+| 9 | cfc-frontend Jest | 本机 | **609/3/12** | 172s | 3 红 = S-cfc-132/133 预期 RED |
+| 10 | cfc-web Jest | 本机 | **116/116** | 209s | 全绿 |
+| 11 | 根级黑盒 Jest | 本机 | **7/16** | 9.8s | B-36 第 73 轮(9082 未起) |
+| 12 | 窗口 13 契约类定向 | 本机 mvn | **133 例 = 85 过/48 红/0 错** | 2m05s | 48 红全预期 RED;GREEN 3 类(LoginSwitch 16、MessagePush 20、PlanActivate 15)全绿 |
+
+后端全量:**采信 R188**(369 类 / 3111 例 / 3082 过 / 25 红 / 4 跳 = 99.07%),窗口 main 零变更。
+
+## 三、全站口径
+
+- 合计 **4120 例** = 后端 3244(3111采信 + 133契约实测)+ fe 624 + web 116 + lg 51 + 浏览器 30 + API 32 + 根级 23
+- **4003 过 / 92 红 / 25 跳 = 97.16%(剔 skip 97.75%)**
+- 红 92 = 后端存量 25 + 契约预期 RED 48 + fe 预期 RED 3 + 根级 16(环境)
+- 环比 R188(3987/3918/44红/97.27%…98.27%):例 +133、过 +85、红 +48(全为窗口契约预期 RED,零缺陷回归)
+
+## 四、处置与结论
+
+- **B-142-2 销号**:langgraph 连续 2 轮 51/51(R188 + R189)→ 满足销号判据。
+- **B-189-1 新增**:git SSH 22 CLOSED(Gogs 服务故障)→ fetch/push 降级 HTTP 核源(liaoxg/cfc HEAD 与本地一致)。
+- **B-189-2 新增(自处置)**:窗口 13 契约类补验完成,48 RED 全为预期、3 GREEN 全绿,无意外失败。
+- **门禁**:不通过(承袭)——G1 97.16%(−1.11pct 全因契约 RED 入池)、G2 73 红、G9/G11 承袭、G12 ✅、G6/G7/G8/G10/G13 ✅。
+
+## 五、git 证据
+
+- 窗口新增测试资产提交:`64f8a3875`(S-cfc-184)、`5f2a09b02`(S-cfc-183)、`883a6eeab`(S-cfc-188)、`bbc441e08`(S-cfc-189)、`23e2ddd66`(S-cfc-191)、`fb1702975`(S-cfc-196)已由并行会话 push;本地=远端 `6124352d7`。
+- 本轮测试侧产物(R189 报告/执行日志/notice/blockers/台账):提交推送状态见主报告 §七(SSH 故障处置中)。

+ 15 - 2
docs/tdd/test/automation-status.md

@@ -23,8 +23,8 @@
 | 用户场景(md) | 11 | 0 | 0 | 11 | 11 | 0 | 0 | 0 | 0 |
 | Playwright(e2e/integration) | 96 | 571 | 96 | 0 | 86 | 0 | 7 | 3 | 0 |
 | Python(pytest) | 11 | 48 | 11 | 0 | 11 | 0 | 0 | 0 | 0 |
-| Java后端测试 | 375 | 3096 | 375 | 0 | 358 | 0 | 15 | 2 | 0 |
-| **合计** | — | **4434** | **545** | **667** | 890 | 255 | 36 | 5 | 26 |
+| Java后端测试 | 388 | 3229 | 388 | 0 | 371 | 0 | 15 | 2 | 0 |
+| **合计** | — | **4567** | **558** | **667** | 903 | 255 | 36 | 5 | 26 |
 
 ## 二、结构化测试用例自动化状态(`tests/test-cases/*.md`)
 
@@ -1141,6 +1141,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyIsolationContractTest.java` | 8 | 已自动化(@Test) | 未跟踪 | EnergyIsolationContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyLogsContractScoreHistoryTest.java` | 11 | 已自动化(@Test) | 未跟踪 | EnergyLogsContractScoreHistory |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyOverviewContractTest.java` | 7 | 已自动化(@Test) | 未跟踪 | EnergyOverviewContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyAutoCreateForPurchaseContractTest.java` | 5 | 已自动化(@Test) | 未跟踪 | FamilyAutoCreateForPurchaseContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyJoinValidationRulesContractTest.java` | 14 | 已自动化(@Test) | 未跟踪 | FamilyJoinValidationRulesContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberDimensionBaseScoreServiceTest.java` | 7 | 已自动化(@Test) | 未跟踪 | FamilyMemberDimensionBaseScoreService |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberRelationshipLabelTest.java` | 8 | 已自动化(@Test) | 未跟踪 | FamilyMemberRelationshipLabel |
@@ -1171,6 +1172,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyAccessGuardTest.java` | 10 | 已自动化(@Test) | 未跟踪 | GuideFamilyAccessGuard |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyQueryServiceTest.java` | 4 | 已自动化(@Test) | 未跟踪 | GuideFamilyQueryService |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java` | 3 | 已自动化(@Test) | 未跟踪 | GuideFamilyServiceBind |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyTaskReviewContractTest.java` | 5 | 已自动化(@Test) | 未跟踪 | GuideFamilyTaskReviewContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuidePlanReviewControllerAuthTest.java` | 6 | 已自动化(@Test) | 未跟踪 | GuidePlanReviewControllerAuth |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthDataSourceBridgeContractTest.java` | 16 | 已自动化(@Test) | 未跟踪 | HealthDataSourceBridgeContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanDeleteCascadeTest.java` | 6 | 已自动化(@Test) | 未跟踪 | HealthPlanDeleteCascade |
@@ -1190,10 +1192,12 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipPlanPurchaseContractTest.java` | 7 | 已自动化(@Test) | 未跟踪 | MembershipPlanPurchaseContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipRenewScP60ScP80ContractTest.java` | 9 | 已自动化(@Test) | 未跟踪 | MembershipRenewScP60ScP80Contract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipViewScP59ContractTest.java` | 6 | 已自动化(@Test) | 未跟踪 | MembershipViewScP59Contract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/NutritionPlanTeacherContractTest.java` | 4 | 已自动化(@Test) | 未跟踪 | NutritionPlanTeacherContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderCreatePayShipConfirmScX07ContractTest.java` | 14 | 已自动化(@Test) | 未跟踪 | OrderCreatePayShipConfirmScX07Contract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderRefundScP56ScA12ContractTest.java` | 11 | 已自动化(@Test) | 未跟踪 | OrderRefundScP56ScA12Contract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PersonalLayerDualAssertionTest.java` | 13 | 已自动化(@Test) | 未跟踪 | PersonalLayerDualAssertion |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanActivationExecutionContractTest.java` | 14 | 已自动化(@Test) | 未跟踪 | PlanActivationExecutionContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanContentSafetyReviewContractTest.java` | 9 | 已自动化(@Test) | 未跟踪 | PlanContentSafetyReviewContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanLifecycleParentContractTest.java` | 38 | 已自动化(@Test) | 未跟踪 | PlanLifecycleParentContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanReviewTeacherContractTest.java` | 19 | 已自动化(@Test) | 未跟踪 | PlanReviewTeacherContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PointsLedgerScP15ContractTest.java` | 8 | 已自动化(@Test) | 未跟踪 | PointsLedgerScP15Contract |
@@ -1229,6 +1233,15 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskReviewScT06ContractTest.java` | 6 | 已自动化(@Test) | 未跟踪 | TaskReviewScT06Contract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTaskCreateContractTest.java` | 7 | 已自动化(@Test) | 未跟踪 | TaskTaskCreateContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTemplatePackageContractTest.java` | 13 | 已自动化(@Test) | 未跟踪 | TaskTemplatePackageContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAppointmentGuardContractTest.java` | 14 | 已自动化(@Test) | 未跟踪 | TeacherAppointmentGuardContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAssessmentRecordContractTest.java` | 4 | 已自动化(@Test) | 未跟踪 | TeacherAssessmentRecordContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDataIsolationScT13ContractTest.java` | 9 | 已自动化(@Test) | 未跟踪 | TeacherDataIsolationScT13Contract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDimensionScoreContractTest.java` | 6 | 已自动化(@Test) | 未跟踪 | TeacherDimensionScoreContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherLoginSwitchContractTest.java` | 16 | 已自动化(@Test) | 未跟踪 | TeacherLoginSwitchContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMessagePushContractTest.java` | 20 | 已自动化(@Test) | 未跟踪 | TeacherMessagePushContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMindRecordContractTest.java` | 13 | 已自动化(@Test) | 未跟踪 | TeacherMindRecordContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanActivateContractTest.java` | 15 | 已自动化(@Test) | 未跟踪 | TeacherPlanActivateContract |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanCreateContractTest.java` | 13 | 已自动化(@Test) | 未跟踪 | TeacherPlanCreateContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitAdminManageContractTest.java` | 20 | 已自动化(@Test) | 未跟踪 | TeamProfitAdminManageContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitCronContractTest.java` | 22 | 已自动化(@Test) | 未跟踪 | TeamProfitCronContract |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitHookContractTest.java` | 7 | 已自动化(@Test) | 未跟踪 | TeamProfitHookContract |

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

@@ -1323,3 +1323,24 @@
 | **B-142-1(销号维持第 18 轮)** | 匿名端点鉴权 | 研发(已闭环) | **维持销号**。6 端点 **6/6 = 401**(mind/fortune、energy/overview、health/plan/list、xiaomi-health、huawei-health、admin/families/overview)。 | 测试(R188 实测) | 2026-11-13 09:55 | 已闭(观察维持) |
 | **B-124/B-32(度量口径)** | 锚点/场景口径跨轮不可比 | 测试(P2) | **仍未闭环**。官方脚本:场景 215 / 映射 155=72.1% / 字面 33=15.3% / TC 861 / 异常流 502=58.3% / 锚点 115 / 资产 546;严格口径沿用 **20.1%(62/308)**。 | 测试 | 2026-11-13 09:55 | 待处理 |
 | **R188 门禁** | 全量 3987 / **3918** | 测试 | **不通过(有条件,明显正向)**。✅G1 **98.27%**(剔 skip 98.89%,+12 过)/G4 编译 0 错(2121+375)/G5 369 XML 0 dump(恒等式 3097−4+18=3111)/G6 28 过+2 跳/G8 6/6 401/G10 双节点(189 5/5 + 251 51 例)/G12 SRS 零变更/G13 存量零漂移第 23 次;⚠️G3 609-624(3 预期 RED)/G7 **51/51(观察 1/2)**;❌G2 **25 红**、G9 20.1%、G11 漏拦 6 陈旧 26、G14 57.9%、G16 无 SCA。**变化** = 后端 28→25 红(全量实跑)、lg 6→0、fe H5 2→0 → 红 56→**44**、通过率 98.0%→**98.27%**。 | 测试(R188 闭环) | 2026-11-13 09:55 | 已记录 |
+
+---
+
+## R189 段(2026-11-13 11:30,新增)
+
+| **B-189-1(P1 新增·环境)** | git SSH 22 CLOSED | 运维(环境) | **推送已解除(SSH 故障延续)**。`git.iwintrue.com` / `192.168.16.251:22` **CLOSED**(R188 09:39 尚可 push)→ SSH `git fetch/push` 全部失败;**兜底:push URL 切 `http://git.iwintrue.com/liaoxg/cfc.git` 后 rebase+push 成功**(远端 HEAD 由 `6124352d7` → `67fb0a1f5`,含 R189 全部产物;fetch 仍走 SSH 失败,须临时指定 HTTP URL)。**SSH 通道本身仍待运维检查 Gogs/251 sshd 服务(端口 22)**。 | 测试(R189 实测) | 2026-11-13 11:30 | HTTP 兜底已推送,SSH 待修 |
+| **B-189-2(P2 新增·自处置)** | 窗口 13 契约类未逐类验证即并行推入 | 测试(流程) | **补验完成**。R188 后并行会话推入 13 个契约测试类(S-cfc-183/184/188/189/191/196 等)未逐类验证;本轮定向实测 **133 例 = 85 过 / 48 红 / 0 错(2m05s)**:48 红**全部为预期 RED(TDD 先行)**;GREEN 3 类(LoginSwitch 16/16、MessagePush 20/20、PlanActivate 15/15)全绿可收尾。**流程修正**:下轮起窗口内新增测试类必须逐类定向取证再入账。 | 测试(R189 实测) | 2026-11-13 11:30 | 已处置(补验闭环) |
+| **B-142-2(销号,2026-11-13)** | langgraph 上游 LLM 不可达 | 运维/研发(P0→已销) | **正式销号**。R188 51/51 + R189 **51/51(495.56s)** = 连续 2 轮全绿 → 满足销号判据。残留 live chat 链路(120s 零字节)单列 **B-186-1** 持续观察。 | 测试(R189 实测) | 2026-11-13 11:30 | ✅ 已销号 |
+| **B-186-1(第 3 轮观察)** | langgraph live `/api/v1/chat` 挂死 | 运维/研发(P1) | **延续**。pytest 51/51 绿(mock 路径)但 live chat 链路上轮仍 120s 零字节 → 真实链路未验证;需轮换 key + 提额。 | 运维/研发 | 2026-11-13 11:30 | 待处理 |
+| **S-cfc-183/184/188/196 等(48 前瞻 RED,本轮取证)** | 窗口 13 契约类 10 类 48 红 | 研发(P1,最紧急) | **全部预期 RED**(TDD 先行、研发未实现):MindRecord 12F / AppointmentGuard 10F / PlanContentSafety 4F(S-cfc-183)/ TeacherAssessmentRecord 3F(S-cfc-184)/ FamilyAutoCreate 4F(S-cfc-188)/ TeacherPlanCreate 4F(S-cfc-196)/ DataIsolation 4F / PlanReview 部分 / Nutrition 3F / DimensionScore 2F。逐键清单见 `notice-2026-11-13-R189-研发通知.md` §一 P1。 | 测试(R189 定向实测) | 2026-11-13 11:30 | 待处理(研发实现使绿) |
+| **S-cfc-189/191/Activate(3 GREEN 全绿)** | 契约 GREEN 确认 | 研发(可直接收尾) | LoginSwitch **16/16**(bbc441e08)/ MessagePush **20/20**(23e2ddd66)/ PlanActivate **15/15** 全绿 → 契约侧已闭环,可直接收 YELLOW/GREEN。 | 测试(R189 定向实测) | 2026-11-13 11:30 | 已取证(待研发登记) |
+| **B-177-1(第 11 轮)** | 251 pytest 打印 summary 后进程不退出 | 研发/测试(P1) | **观察 4/2(收口但 EXIT 行仍缺失)**。本轮 495.56s 正常收口输出 summary,`EXIT=` 行仍缺失(B-126 表象);残留进程已清理。修法不变:`app/main.py:84` lifespan + `aclose()`;派发器 `timeout -k 10 900`。 | 研发/测试 | 2026-11-13 11:30 | 待处理 |
+| **B-36(第 73 轮零漂移)** | 根级黑盒 23 例 16 红 | 测试(P2 环境) | **零漂移**。`cd tests && npx jest --silent` → **7 过 / 16 红**(9.8s),全 `ECONNREFUSED 9082`。 | 测试 | 2026-11-13 11:30 | 待处理 |
+| **B-95(第 44 轮)** | `192.168.16.204:4090` 失联 | 运维(P2) | **延续**。204=000;189:4090=**200(admin 5/5 EXIT=0)**、251:4096=200。 | 运维 | 2026-11-13 11:30 | 待处理 |
+| **B-DX-1(第 31 轮)** | dx-bridge 端点 404 | 部署/研发(P1) | **延续**。本轮 dx 2 例 skip(404)。 | 部署/研发 | 2026-11-13 11:30 | 待处理 |
+| **B-152-1/2(第 20 轮)** | CI `BACKEND_OBSERVED_CLASSES` 失真 | 研发/CI(P0/P1) | **延续**。漏拦 6 + 陈旧 26 未修;本轮建议同步接入 13 个新契约类。 | 研发/CI | 2026-11-13 11:30 | 待处理 |
+| **B-156-1 / B-170-1(第 13/10 轮)** | 迁移 DDL 缺陷 | 研发(P1/P2) | **延续未修**。`schema.sql:5345` 索引列缺失 / `DatabaseInitializer.java:2261` 别名 UPDATE 派生表引用。 | 研发 | 2026-11-13 11:30 | 待处理 |
+| **B-162-1(第 15 轮)** | 3 个测试类未入库 | 治理(P1) | **延续**。`GrowthPublicEndpointMappingTest`(5E)等仍 `??`。 | 研发/测试 | 2026-11-13 11:30 | 待处理 |
+| **B-178-1(第 8 轮)** | TaskReviewScP11 反射装置浮动 | 测试(P2) | **延续 2F** → `@MockBean` 替代 `ReflectionUtils`。 | 测试 | 2026-11-13 11:30 | 待处理 |
+| **B-142-1(销号维持第 19 轮)** | 匿名端点鉴权 | 研发(已闭环) | **维持销号**。health 三端点(plan/adjust、attribution、generate)全 **401**;API 安全套件 11 例全绿。 | 测试(R189 实测) | 2026-11-13 11:30 | 已闭(观察维持) |
+| **R189 门禁** | 全量 4120 / **4003** | 测试 | **不通过(承袭,无回归)**。✅G4 编译 0 错/G5 定向 133 surefire XML 完整/G6 28 过+2 跳/G7 **51/51(连续 2 轮,B-142-2 销号)**/G8 401 全绿/G10 双节点/G12 SRS 零变更/G13 存量零漂移第 24 次;⚠️G3 609-624(3 预期 RED);❌G1 **97.16%**(剔 skip 97.75%,−1.11pct **全因 48 契约预期 RED 入池**)/G2 **73 红**(存量 25 + 契约预期 RED 48)/G9 20.1%/G11 漏拦 6 陈旧 26。**变化** = 例 +133(窗口 13 契约类)、过 +85、红 +48(**全为预期 RED,零缺陷回归**);langgraph 连续 2 轮全绿 **B-142-2 销号**;浏览器六件套全绿、API 0 红、fe/web 零漂移。 | 测试(R189 闭环) | 2026-11-13 11:30 | 已记录 |

+ 15 - 2
docs/tdd/test/inventory.md

@@ -11,9 +11,9 @@
 | 结构化测试用例(md) | 10 | 719 |
 | Playwright(spec.js) | 96 | 571 |
 | Python(pytest) | 11 | 48 |
-| Java后端(测试文件) | 375 | 3096 (@Test) |
+| Java后端(测试文件) | 388 | 3229 (@Test) |
 | 用户场景(md) | 11 | 文件级 |
-| **合计** | — | **4434** 用例/方法 |
+| **合计** | — | **4567** 用例/方法 |
 
 ## 二、结构化测试用例(`tests/test-cases/*.md`)
 
@@ -1136,6 +1136,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyIsolationContractTest.java` | cfc-backend | 8 | EnergyIsolationContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyIsolationContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyLogsContractScoreHistoryTest.java` | cfc-backend | 11 | EnergyLogsContractScoreHistory | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyLogsContractScoreHistoryTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyOverviewContractTest.java` | cfc-backend | 7 | EnergyOverviewContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/EnergyOverviewContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyAutoCreateForPurchaseContractTest.java` | cfc-backend | 5 | FamilyAutoCreateForPurchaseContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyAutoCreateForPurchaseContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyJoinValidationRulesContractTest.java` | cfc-backend | 14 | FamilyJoinValidationRulesContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyJoinValidationRulesContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberDimensionBaseScoreServiceTest.java` | cfc-backend | 7 | FamilyMemberDimensionBaseScoreService | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberDimensionBaseScoreServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberRelationshipLabelTest.java` | cfc-backend | 8 | FamilyMemberRelationshipLabel | `cfc-backend/src/test/java/com/etotem/cfc/unit/FamilyMemberRelationshipLabelTest.java` |
@@ -1166,6 +1167,7 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyAccessGuardTest.java` | cfc-backend | 10 | GuideFamilyAccessGuard | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyAccessGuardTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyQueryServiceTest.java` | cfc-backend | 4 | GuideFamilyQueryService | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyQueryServiceTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java` | cfc-backend | 3 | GuideFamilyServiceBind | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyServiceBindTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyTaskReviewContractTest.java` | cfc-backend | 5 | GuideFamilyTaskReviewContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuideFamilyTaskReviewContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuidePlanReviewControllerAuthTest.java` | cfc-backend | 6 | GuidePlanReviewControllerAuth | `cfc-backend/src/test/java/com/etotem/cfc/unit/GuidePlanReviewControllerAuthTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthDataSourceBridgeContractTest.java` | cfc-backend | 16 | HealthDataSourceBridgeContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthDataSourceBridgeContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanDeleteCascadeTest.java` | cfc-backend | 6 | HealthPlanDeleteCascade | `cfc-backend/src/test/java/com/etotem/cfc/unit/HealthPlanDeleteCascadeTest.java` |
@@ -1185,10 +1187,12 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipPlanPurchaseContractTest.java` | cfc-backend | 7 | MembershipPlanPurchaseContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipPlanPurchaseContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipRenewScP60ScP80ContractTest.java` | cfc-backend | 9 | MembershipRenewScP60ScP80Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipRenewScP60ScP80ContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipViewScP59ContractTest.java` | cfc-backend | 6 | MembershipViewScP59Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/MembershipViewScP59ContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/NutritionPlanTeacherContractTest.java` | cfc-backend | 4 | NutritionPlanTeacherContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/NutritionPlanTeacherContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderCreatePayShipConfirmScX07ContractTest.java` | cfc-backend | 14 | OrderCreatePayShipConfirmScX07Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderCreatePayShipConfirmScX07ContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderRefundScP56ScA12ContractTest.java` | cfc-backend | 11 | OrderRefundScP56ScA12Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/OrderRefundScP56ScA12ContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PersonalLayerDualAssertionTest.java` | cfc-backend | 13 | PersonalLayerDualAssertion | `cfc-backend/src/test/java/com/etotem/cfc/unit/PersonalLayerDualAssertionTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanActivationExecutionContractTest.java` | cfc-backend | 14 | PlanActivationExecutionContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanActivationExecutionContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanContentSafetyReviewContractTest.java` | cfc-backend | 9 | PlanContentSafetyReviewContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanContentSafetyReviewContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanLifecycleParentContractTest.java` | cfc-backend | 38 | PlanLifecycleParentContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanLifecycleParentContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanReviewTeacherContractTest.java` | cfc-backend | 19 | PlanReviewTeacherContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/PlanReviewTeacherContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/PointsLedgerScP15ContractTest.java` | cfc-backend | 8 | PointsLedgerScP15Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/PointsLedgerScP15ContractTest.java` |
@@ -1224,6 +1228,15 @@
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskReviewScT06ContractTest.java` | cfc-backend | 6 | TaskReviewScT06Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskReviewScT06ContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTaskCreateContractTest.java` | cfc-backend | 7 | TaskTaskCreateContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTaskCreateContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTemplatePackageContractTest.java` | cfc-backend | 13 | TaskTemplatePackageContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TaskTemplatePackageContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAppointmentGuardContractTest.java` | cfc-backend | 14 | TeacherAppointmentGuardContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAppointmentGuardContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAssessmentRecordContractTest.java` | cfc-backend | 4 | TeacherAssessmentRecordContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherAssessmentRecordContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDataIsolationScT13ContractTest.java` | cfc-backend | 9 | TeacherDataIsolationScT13Contract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDataIsolationScT13ContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDimensionScoreContractTest.java` | cfc-backend | 6 | TeacherDimensionScoreContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherDimensionScoreContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherLoginSwitchContractTest.java` | cfc-backend | 16 | TeacherLoginSwitchContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherLoginSwitchContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMessagePushContractTest.java` | cfc-backend | 20 | TeacherMessagePushContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMessagePushContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMindRecordContractTest.java` | cfc-backend | 13 | TeacherMindRecordContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherMindRecordContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanActivateContractTest.java` | cfc-backend | 15 | TeacherPlanActivateContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanActivateContractTest.java` |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanCreateContractTest.java` | cfc-backend | 13 | TeacherPlanCreateContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeacherPlanCreateContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitAdminManageContractTest.java` | cfc-backend | 20 | TeamProfitAdminManageContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitAdminManageContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitCronContractTest.java` | cfc-backend | 22 | TeamProfitCronContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitCronContractTest.java` |
 | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitHookContractTest.java` | cfc-backend | 7 | TeamProfitHookContract | `cfc-backend/src/test/java/com/etotem/cfc/unit/TeamProfitHookContractTest.java` |