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

docs(specs): 家庭归因问卷阶段一+二系统设计与任务分解(数据地基+核心闭环③→⑤)

Agnes Agent 2 недель назад
Родитель
Сommit
3f3abd4995

+ 1038 - 0
docs/superpowers/specs/2026-10-28-family-attribution-architecture-stage1-2.md

@@ -0,0 +1,1038 @@
+# 家庭归因分析问卷小程序落地 · 阶段一(数据地基)+ 阶段二(核心闭环 ③→⑤)系统设计与任务分解
+
+> **作者**:Bob(架构师 software-architect-2)|**日期**:2026-10-28
+> **定位**:本设计是「归因分析 → 调整方案 → 任务生成」链路在小程序落地的**增量设计**(阶段一 + 阶段二),供派发实例(后端 lan-248 / 前端 lan-204 / pub-iwintrue)按任务列表实现。**只读调研产物,不含任何业务代码改动。**
+> **输入依据**:
+> 1. 目标态需求解读 PRD:`docs/superpowers/specs/2026-10-27-family-attribution-questionnaire-prd.md`(§A 16 条问题表 / §B 7 章骨架 / §C 6 阶段状态机 / §D 10 条红线 / §E 开放问题)
+> 2. 现状核查与整改方案 v1.1:`docs/superpowers/specs/2026-10-27-family-attribution-questionnaire-remediation.md`(§2 现状矩阵+缺口 G1-G10 / §3 阶段一/二 A1-A4、B1-B4 / §5 拍板记录)
+> 3. 源文档:`docs/参考资料/家庭归因分析-孟凡锐-马智强-马昕源-马安扬-v1.1.html`(第八章=问诊清单)、`docs/参考资料/全家干预方案-妈妈-女儿-儿子-v1.1.html`(7 章模板)
+> 4. 现状代码证据(本机实证,路径+行号见 §5 与各节)
+
+## 主理人已拍板约束(设计红线,不可违背)
+
+| 编号 | 拍板结论 | 对设计的硬约束 |
+|------|----------|----------------|
+| **E12** | 合规后置,技术开发先行 | 阶段一/二**仅 mock/测试数据**;真实用户放行 = 阶段四 D1 完成日。全流程入口需可开关(`app.attribution.enabled=false` 默认,仅测试环境/mock 开启) |
+| **E4** | 高风险项弱提示 | Q11/Q12/Q13 命中仅标记「建议专业评估 + 转介信息露出 + 家长确认」,**问卷不阻断**;合规收口前真实用户环境不得上线 |
+| **E7** | 品牌级展示 | 方案直接展示 Enagic 还原水/姜黄、PHGG、益生菌株名(长双歧 BB536、乳双歧 HN019、布拉氏酵母菌);**品牌露出不得附带功效承诺**(P1-5「不宣称治疗」仍强制) |
+| **E6** | 跟随源文档 3 人 | 调整方案仅覆盖**妈妈/女儿/儿子**;爸爸链外(另有《胰腺炎糖尿病进阶方案》);角色确认走 `family_relationships`/`generation`,不默认系统推断 |
+
+---
+
+# Part A:系统设计
+
+## 1. 实现方案(Implementation Approach)
+
+### 1.1 核心难点
+
+1. **归因推理引擎(G1)**:现有 `HealthPlanService.generatePlanResult` 是「通用健康方案生成」(调 LangGraph `/api/v1/health/plan/generate`,见 `HealthPlanServiceImpl.java:276-321`),**无归因推理**(常模比对 → 指标解读 → 五维归因 → 主因链 → 被证伪项)。这是阶段二最大难点,必须新建纯规则引擎,而非复用 LangGraph 健康方案链路。
+2. **动态确认问卷条件路由(G2)**:`SurveyController` 只有静态模板提交(`SurveyController.java:26-57`),无「按对象/结论条件下发」。第八章 16 条明显条件化(Q2 乳杆菌异常 / Q4 铁偏低 / Q9 无 DAN / Q10-13 女儿 / Q14-15 儿子)。
+3. **自然语言调整→结构化回填(G3)**:`AIChatController` + `AiGateway` 对话已有,但缺「对话结论回填归因结构化字段 + ⑤ 失效重生成」编排。
+4. **7 章方案 schema(G4)**:`health_plans.planJson` 无「分人×层级(P0/P1/日常/P2)×动作×产品×具体做法×复盘钩子」约定与渲染。
+5. **常模参照(G10)**:710 条菌群常模 + DAN 常模现随报告/知识库,无后端独立常模表。
+6. **合规红线(G9)**:10 条红线(测评≠诊断 / 不调药 / 儿童剂量医生定 / 不贴标签 / 不宣称治疗 / 先医后补 / 服药间隔 / 铁餐纪律)需在生成时**硬编码注入**,且按 E7 为品牌级口径。
+
+### 1.2 框架/库选型(沿用既有技术栈,不引入新框架)
+
+| 层面 | 选型 | 理由 |
+|------|------|------|
+| 后端框架 | Spring Boot + MyBatis-Plus(`cfc-backend`) | 现状即此栈,全部实体用 `@TableName` + `@TableId` + `@TableField` 范式 |
+| 数据库 | MySQL(`zxyj` 库,`DatabaseInitializer` 幂等迁移) | 迁移写入点唯一入口 `runMigrations()`,`ensureColumn` 幂等加列 |
+| 规则引擎 | **纯 Java 无框架**(分层 Pipeline) | 归因推理需确定性、可单测、可控合规;不引入 Drools 等重框架(过度设计) |
+| AI 叙述 | 复用 `AiGateway`(`service/AiGateway.java`) | 已含熔断/超时/PII 脱敏/Fallback;归因叙述走规则骨架 + AI 润色,AI 失败规则兜底 |
+| 对话 | 复用 `AIChatController` + `aiService`(`/api/ai/chat/send`) | ④ 自然语言调整直接复用,注入归因专用 prompt(七层 Socratic) |
+| JSON 解析 | Jackson `ObjectMapper`(已全局注入) | 解析 questionsJson / planJson / condition 表达式 |
+| 常量/枚举 | Java 常量类 + `@TableName` 可选表 | A4 红线建议常量类(纯后端、可单测、合规后置期零数据风险) |
+
+### 1.3 架构模式
+
+- **分层 Pipeline + 门面服务**:`AttributionAnalysisService` 为门面,内部 5 段确定性规则引擎(NormCompare → IndicatorInterpret → FiveDimAttribution → MainCauseChain → Falsification)+ 1 段 AI 叙述(Narrative)。
+- **状态机驱动**:归因流程状态机(`① Submitted → ② Confirmed → ③ Ready → ④ Confirmed → ⑤ Generated → ⑥ TaskConfirmed`,见 §4.2 Mermaid),每阶段一个 Service 门面,状态落库 `attribution_reports.status`。
+- **合规即服务(compliance-as-code)**:红线文案全部来自 `AttributionRedlines` 常量,AI 只负责叙述、**不负责合规**——合规由规则层硬注入,AI 无法越权。
+- **面向接口**:`AttributionAnalysisService` / `AttributionAdjustService` / `AttributionPlanService` / `ConditionEvaluatorService` 均为接口 + `impl` 实现(沿用 `DimensionScoreService` 接口范式)。
+
+---
+
+## 2. 文件清单(File List,相对 `cfc-backend/src/main/java/com/etotem/cfc/`)
+
+### 2.1 阶段一(数据地基,A1-A4)
+
+| 相对路径 | 动作 | 归属 |
+|----------|------|------|
+| `config/DatabaseInitializer.java` | 修改:`runMigrations()` 追加 `migrateHealthPlansPlanType()`(迁移 424)+ 常模/红线种子 | A1/A3/A4 |
+| `resources/schema.sql` | 修改:`health_plans` 加 `plan_type` 列;新建 `attribution_norm_values` / `attribution_redlines` 建表语句 | A1/A3/A4 |
+| `entity/HealthPlan.java` | 修改:加 `@TableField("plan_type") private String planType;` | A1 |
+| `entity/AttributionNormValue.java` | 新建:常模实体 | A3 |
+| `mapper/AttributionNormValueMapper.java` | 新建:常模 Mapper | A3 |
+| `entity/AttributionRedline.java` | 新建:红线实体(可选表方案)/ 或常量 | A4 |
+| `constant/AttributionRedlines.java` | 新建:10 条红线常量类(**推荐**,P0/P1/P2 分级 + 品牌级口径) | A4 |
+| `resources/norm/attribution_norm_gut_flora.json` | 新建:菌群 710 常模可配置 JSON 导入模板(空壳 + 说明,待业务侧导入真实数据) | A3 |
+
+> 注:`survey_templates` 无需 DDL 改动——`questionsJson` 是 TEXT,schema 扩展为**纯 JSON 约定**(A2),不迁移数据库。
+
+### 2.2 阶段二(核心闭环 ③→⑤,B1-B4)
+
+| 相对路径 | 动作 | 归属 |
+|----------|------|------|
+| `service/AttributionAnalysisService.java` | 新建(接口):归因门面 | B1 |
+| `service/impl/AttributionAnalysisServiceImpl.java` | 新建(实现):门面 + 流程编排 | B1 |
+| `service/attribution/NormCompareEngine.java` | 新建:常模比对段(确定性) | B1 |
+| `service/attribution/IndicatorInterpretEngine.java` | 新建:指标解读段(确定性) | B1 |
+| `service/attribution/FiveDimAttributionEngine.java` | 新建:五维归因段(确定性) | B1 |
+| `service/attribution/MainCauseChainEngine.java` | 新建:主因链段(确定性) | B1 |
+| `service/attribution/FalsificationEngine.java` | 新建:被证伪项段(确定性) | B1 |
+| `service/attribution/AttributionNarrativeService.java` | 新建:AI 叙述段(复用 `AiGateway`,失败规则兜底) | B1 |
+| `service/ConditionEvaluatorService.java` | 新建(接口 + impl):condition 表达式求值 | B2 |
+| `controller/SurveyController.java` | 修改:加 `POST /api/survey/attribution/confirm-questions`;submit 扩展 riskLevel 命中 | B2 |
+| `service/AttributionAdjustService.java` | 新建(接口):自然语言调整编排 | B3 |
+| `service/impl/AttributionAdjustServiceImpl.java` | 新建(实现):对话 + 回填 + 失效重生成 | B3 |
+| `service/AttributionPlanService.java` | 新建(接口):7 章方案生成 | B4 |
+| `service/impl/AttributionPlanServiceImpl.java` | 新建(实现):归因结论 → planJson | B4 |
+| `entity/AttributionReport.java` | 新建:归因报告聚合根(存 report_json + status + redline_hits) | B1 |
+| `mapper/AttributionReportMapper.java` | 新建:报告 Mapper | B1 |
+| `controller/AttributionController.java` | 新建:归因入口(analyze / confirm-questions / adjust / confirm-adjust / plan) | B1/B3/B4 |
+| `dto/AttributionInput.java` / `AttributionReportVO.java` / `AdjustResult.java` / `FamilyPlanVO.java` | 新建:DTO/VO | B1/B3/B4 |
+
+> 注:`AiGateway.java` / `AIChatController.java` / `HealthPlanController.java` / `HealthPlanService.java` / `FamilyContextService.java` **复用不改**(或仅注入归因专用 prompt 常量)。
+
+---
+
+## 3. 数据结构与接口(Data Structures & Interfaces)
+
+### 3.1 A1:`health_plans.plan_type` 迁移
+
+- **最新迁移编号**:423(`DatabaseInitializer.java:3340` 注释「迁移423: 体脂秤测量记录表」;实测 `createBodyFatScaleRecordsTable()` 为 `runMigrations()` 末尾调用)。**新迁移 = 424**。
+- **写入点**:`runMigrations()` 末尾(423 之后,`DatabaseInitializer.java:3341` `createBodyFatScaleRecordsTable();` 后追加)调用新增私有方法 `migrateHealthPlansPlanType()`:
+
+```java
+private void migrateHealthPlansPlanType() {
+    // 迁移424: health_plans 加 plan_type(区分健康方案/家庭归因干预方案;G5)
+    ensureColumn("health_plans", "plan_type",
+        "VARCHAR(32) DEFAULT 'health_plan' COMMENT '方案类型: health_plan(健康方案)/family_attribution_plan(家庭归因干预方案)'");
+}
+```
+
+- **同步 `schema.sql`**:`health_plans` 建表语句(`schema.sql:5082-5101`)加一行:
+  `plan_type VARCHAR(32) DEFAULT 'health_plan' COMMENT '方案类型: health_plan/family_attribution_plan',`
+- **`HealthPlan.java`** 加字段(`entity/HealthPlan.java`,`plan_json` 之后):
+
+```java
+/** 方案类型: health_plan(健康方案)/family_attribution_plan(家庭归因干预方案) */
+@TableField("plan_type") private String planType;
+```
+
+- **列值枚举**:`health_plan`(默认,存量行自动命中)/ `family_attribution_plan`。
+
+### 3.2 A2:`SurveyTemplate.questionsJson` schema 扩展(纯 JSON 约定,不改表)
+
+**扩展后 JSON 顶层结构**:
+
+```json
+{
+  "schemaVersion": "1.1",
+  "target": "family_attribution",
+  "audience": ["妈妈", "女儿", "儿子", "爸爸", "四人", "全家"],
+  "questions": [ { "id":"...", "code":"...", "group":"...", "title":"...",
+                   "type":"single", "options":[...], "unit":null, "required":true,
+                   "condition":null, "riskLevel":"none", "refRange":null } ]
+}
+```
+
+**字段定义表**:
+
+| 字段 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `id` | string | ✔ | 问题稳定标识,如 `Q1a` / `Q11`;`Q` 前缀保证与源文档对应 |
+| `code` | string | ✔ | 采集变量名(条件求值键),如 `l.reuteriSupp` / `ironLow`;蛇形 |
+| `group` | string | ✔ | 对象分组:`四人`/`孟凡锐`/`马智强`/`马昕源`/`马安扬`/`全家`(或语义化 `dad`/`mom`/`daughter`/`son`/`all`/`family`) |
+| `title` | string | ✔ | 题面(必问项原文) |
+| `type` | enum | ✔ | `date` / `single`(单选) / `multi`(多选) / `number` / `scale`(量表 1-5) / `text` / `boolean` / `image` / `photoBatch`(多图) |
+| `options` | array | 条件 | 单选/多选选项,如 `["是","否"]` / `["0-1","1-2","2-3",">3"]` |
+| `unit` | string | 条件 | 单位,如 `%` / `h` / `岁` / `次/周` |
+| `required` | boolean | ✔ | 是否必答(`required=false` 用于「尽量」如 Q16) |
+| `condition` | object/null | 条件 | 条件表达式(见下);`null`=无条件恒发 |
+| `riskLevel` | enum | ✔ | `none` / `low` / `high`(`high`=Q11/Q12/Q13,涉未成年人心理/自伤/欺凌/进食) |
+| `refRange` | string | 条件 | 参考范围提示(如 Q4 铁餐纪律、Q9 DAN 意愿),可内嵌合规文案 |
+
+**condition 表达式求值方式**(`ConditionEvaluatorService`):
+
+```json
+{ "op": "==", "var": "l.reuteriAbnormal", "val": true }
+```
+
+- **操作符(op)**:`==` / `!=` / `>` / `>=` / `<` / `<=` / `contains`(数组含值) / `in`(值在数组) / `exists`(var 非空) / `anyOf`(OR 数组)。
+- **上下文(context)**:由对象档案 + 归因中间态 + 已作答构造。归因中间态键(由 B1 计算后供 B2 引用):`l.reuteriAbnormal`、`ironLow`(铁<阈值)、`hasDan`、`isFemaleTeen`(女性青少年)、`ageBand`、`role`、`zincDeficient`、`gutDiversityAbnormal`、`bowelBarrierAbnormal`、`bileAcidHigh`、`gasHigh` 等。
+- **组合**:`condition: { "op": "anyOf", "items": [ {...}, {...} ] }` 支持 OR;AND 用嵌套对象(缺省默认 AND 语义)。
+- **求值器签名**:`boolean evaluate(JsonNode condition, Map<String, Object> context)`;`condition==null` 恒真;未知 var 返回 `false`(保守下发,避免误发敏感题)。
+
+**riskLevel 枚举**:`none`(Q1-Q10/Q14-Q16 默认)/ `low`(需注意但非高风险)/ `high`(Q11 自伤/拒学/失眠、Q12 欺凌、Q13 进食风险)。命中 `high` 由前端标记「建议专业评估 + 转介信息露出 + 家长确认」(E4 弱提示,不阻断)。
+
+**第八章 16 条完整 JSON 样例(可直接入库 `questionsJson`)**:
+
+```json
+{
+  "schemaVersion": "1.1",
+  "target": "family_attribution",
+  "audience": ["四人", "孟凡锐", "马智强", "马昕源", "马安扬", "全家"],
+  "questions": [
+    { "id": "Q1a", "code": "sampleDate", "group": "四人", "title": "采样日期",
+      "type": "date", "options": null, "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q1b", "code": "antibioticUsed30d", "group": "四人", "title": "采样前 1 个月是否用过抗生素",
+      "type": "single", "options": ["是", "否"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "决定菌群失衡是结构问题还是药物印记" },
+    { "id": "Q1c", "code": "acidSuppressantUsed30d", "group": "四人", "title": "采样前 1 个月是否用过抑酸药",
+      "type": "single", "options": ["是", "否"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q1d", "code": "laxativeUsed30d", "group": "四人", "title": "采样前 1 个月是否用过泻药",
+      "type": "single", "options": ["是", "否"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q2", "code": "l.reuteriSupp", "group": "孟凡锐", "title": "是否在服含罗伊氏乳杆菌的益生菌?",
+      "type": "single", "options": ["是", "否"], "unit": null, "required": true,
+      "condition": { "op": "==", "var": "l.reuteriAbnormal", "val": true },
+      "riskLevel": "none", "refRange": "乳杆菌 7.268% 异常高,可能是补充剂印记,属可撤回项" },
+    { "id": "Q2b", "code": "l.reuteriDuration", "group": "孟凡锐", "title": "服了多久?",
+      "type": "text", "options": null, "unit": "月", "required": false,
+      "condition": { "op": "==", "var": "l.reuteriSupp", "val": "是" },
+      "riskLevel": "none", "refRange": null },
+
+    { "id": "Q3a", "code": "fatigue", "group": "孟凡锐", "title": "疲劳程度",
+      "type": "scale", "options": ["无", "轻度", "中度", "重度"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "铁 8 是否已有体征" },
+    { "id": "Q3b", "code": "bloating", "group": "孟凡锐", "title": "腹胀程度",
+      "type": "scale", "options": ["无", "轻度", "中度", "重度"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "产气 94 是否已有体征" },
+    { "id": "Q3c", "code": "bowelFreq", "group": "孟凡锐", "title": "排便频率",
+      "type": "single", "options": ["<1次/天", "1次/天", "2-3次/天", ">3次/天"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q3d", "code": "bowelForm", "group": "孟凡锐", "title": "排便形态(Bristol)",
+      "type": "single", "options": ["1", "2", "3", "4", "5", "6", "7"], "unit": "Bristol分", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "3-4 为理想" },
+    { "id": "Q3e", "code": "headacheRash", "group": "孟凡锐", "title": "头痛/皮疹",
+      "type": "multi", "options": ["头痛", "皮疹", "无"], "unit": null, "required": false,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q3f", "code": "allergyHx", "group": "孟凡锐", "title": "过敏史",
+      "type": "text", "options": null, "unit": null, "required": false,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q4a", "code": "ironMealWithMilkTea", "group": "孟凡锐", "title": "含铁餐是否与奶/茶/咖啡同餐",
+      "type": "single", "options": ["是", "否"], "unit": null, "required": true,
+      "condition": { "op": "==", "var": "ironLow", "val": true },
+      "riskLevel": "none", "refRange": "决定铁吸收是否被自己堵死;铁餐与奶/茶/咖啡错开≥2h、配维C" },
+    { "id": "Q4b", "code": "breakfastComposition", "group": "孟凡锐", "title": "早餐结构",
+      "type": "text", "options": null, "unit": null, "required": false,
+      "condition": { "op": "==", "var": "ironLow", "val": true },
+      "riskLevel": "none", "refRange": null },
+
+    { "id": "Q5a", "code": "diabetesDuration", "group": "马智强", "title": "糖尿病病程",
+      "type": "number", "options": null, "unit": "年", "required": true,
+      "condition": { "op": "==", "var": "hasDiabetes", "val": true },
+      "riskLevel": "low", "refRange": "⚠️临床项:决定 P0 随访紧迫度(本文不调药)" },
+    { "id": "Q5b", "code": "diabetesMeds", "group": "马智强", "title": "目前用药",
+      "type": "text", "options": null, "unit": null, "required": true,
+      "condition": { "op": "==", "var": "hasDiabetes", "val": true },
+      "riskLevel": "low", "refRange": null },
+    { "id": "Q5c", "code": "hba1cLatest", "group": "马智强", "title": "最近一次糖化血红蛋白",
+      "type": "number", "options": null, "unit": "%", "required": true,
+      "condition": { "op": "==", "var": "hasDiabetes", "val": true },
+      "riskLevel": "low", "refRange": "⚠️临床项" },
+
+    { "id": "Q6a", "code": "heightCm", "group": "马智强", "title": "身高",
+      "type": "number", "options": null, "unit": "cm", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "体重目标由医生定,但基线必须有" },
+    { "id": "Q6b", "code": "weightKg", "group": "马智强", "title": "体重",
+      "type": "number", "options": null, "unit": "kg", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q6c", "code": "waistCm", "group": "马智强", "title": "腰围",
+      "type": "number", "options": null, "unit": "cm", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "算 BMI 与中心性肥胖" },
+
+    { "id": "Q7a", "code": "alcoholFreq", "group": "马智强", "title": "饮酒频率",
+      "type": "single", "options": ["从不", "<1次/周", "1-3次/周", "≥4次/周"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q7b", "code": "lateNightTakeoutFreq", "group": "马智强", "title": "夜宵/外卖频率",
+      "type": "number", "options": null, "unit": "次/周", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "高脂高蛋白主要来源" },
+    { "id": "Q7c", "code": "banquetPattern", "group": "马智强", "title": "应酬结构",
+      "type": "text", "options": null, "unit": null, "required": false,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q8a", "code": "sleepHours", "group": "马智强", "title": "睡眠时长",
+      "type": "number", "options": null, "unit": "h", "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "与血糖控制、日间疲劳强相关" },
+    { "id": "Q8b", "code": "snoringApnea", "group": "马智强", "title": "是否打鼾/憋气(OSA 线索)",
+      "type": "single", "options": ["从不", "偶尔", "经常", "几乎每天"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q9", "code": "danConsent", "group": "马智强", "title": "是否愿意做 DAN(情绪+认知)",
+      "type": "single", "options": ["愿意", "暂缓", "不愿意"], "unit": null, "required": true,
+      "condition": { "op": "==", "var": "hasDan", "val": false },
+      "riskLevel": "none", "refRange": "补家庭系统最后一角;⚠️意愿项" },
+
+    { "id": "Q10a", "code": "menarcheAge", "group": "马昕源", "title": "初潮时间",
+      "type": "number", "options": null, "unit": "岁", "required": true,
+      "condition": { "op": "==", "var": "isFemaleTeen", "val": true },
+      "riskLevel": "none", "refRange": "14岁女性,铁42但需排除月经相关波动" },
+    { "id": "Q10b", "code": "menstrualRegularity", "group": "马昕源", "title": "周期规律",
+      "type": "single", "options": ["规律", "不规律"], "unit": null, "required": true,
+      "condition": { "op": "==", "var": "isFemaleTeen", "val": true },
+      "riskLevel": "none", "refRange": null },
+
+    { "id": "Q11a", "code": "mood3m", "group": "马昕源", "title": "近3个月情绪状态",
+      "type": "scale", "options": ["平稳", "波动", "低落", "明显低落"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "⚠️高风险红线:P0 转介判断依据" },
+    { "id": "Q11b", "code": "sleep3m", "group": "马昕源", "title": "近3个月睡眠",
+      "type": "scale", "options": ["正常", "偶尔失眠", "频繁失眠", "持续失眠"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "持续失眠→立即就医(E4弱提示+家长确认)" },
+    { "id": "Q11c", "code": "schoolRefusal", "group": "马昕源", "title": "是否拒学",
+      "type": "single", "options": ["无", "偶尔", "频繁"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "拒学→立即就医" },
+    { "id": "Q11d", "code": "selfHarmIdea", "group": "马昕源", "title": "是否有自伤念头",
+      "type": "single", "options": ["无", "有"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "自伤→立即就医,不靠产品硬扛" },
+
+    { "id": "Q12a", "code": "schoolStressors", "group": "马昕源", "title": "学校压力源",
+      "type": "multi", "options": ["学业", "同伴", "师生", "家庭", "无"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "解释同伴亲近 3.3%ile" },
+    { "id": "Q12b", "code": "peerRelation", "group": "马昕源", "title": "同伴关系",
+      "type": "text", "options": null, "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "同伴依恋项判定无效,需人工确认" },
+    { "id": "Q12c", "code": "bullied", "group": "马昕源", "title": "是否被排挤/欺凌",
+      "type": "single", "options": ["无", "偶尔", "频繁"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "⚠️敏感项" },
+
+    { "id": "Q13a", "code": "dietingConcern", "group": "马昕源", "title": "是否节食/在意体重",
+      "type": "single", "options": ["无", "轻度在意", "明显在意", "正在节食"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "排除进食行为风险(躯体外貌 5.4%ile)" },
+    { "id": "Q13b", "code": "bodyWeightConcern", "group": "马昕源", "title": "体重关注程度",
+      "type": "scale", "options": ["0", "1", "2", "3", "4", "5"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "high", "refRange": "⚠️进食风险筛查" },
+
+    { "id": "Q14a", "code": "birthMode", "group": "马安扬", "title": "出生方式",
+      "type": "single", "options": ["顺产", "剖腹产"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": "解释铁锌缺乏与 GABA 1" },
+    { "id": "Q14b", "code": "feedingHx", "group": "马安扬", "title": "喂养史",
+      "type": "single", "options": ["母乳", "混合", "配方"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q14c", "code": "antibioticHx", "group": "马安扬", "title": "抗生素史",
+      "type": "single", "options": ["无", "有"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q14d", "code": "eczemaRhinAsthma", "group": "马安扬", "title": "湿疹/鼻炎/哮喘",
+      "type": "multi", "options": ["湿疹", "鼻炎", "哮喘", "无"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q15a", "code": "teacherFeedback", "group": "马安扬", "title": "老师反馈(注意力)",
+      "type": "text", "options": null, "unit": null, "required": false,
+      "condition": null, "riskLevel": "low", "refRange": "区分注意力问题与营养缺口" },
+    { "id": "Q15b", "code": "bowelHabit", "group": "马安扬", "title": "排便习惯",
+      "type": "single", "options": ["<1次/天", "1次/天", "2-3次/天", ">3次/天"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+    { "id": "Q15c", "code": "pickyFoodList", "group": "马安扬", "title": "挑食清单",
+      "type": "multi", "options": ["蔬菜", "肉", "蛋", "奶", "豆", "无"], "unit": null, "required": true,
+      "condition": null, "riskLevel": "none", "refRange": null },
+
+    { "id": "Q16", "code": "weeklyMealPhotos", "group": "全家", "title": "一周典型三餐照片(连拍7天)",
+      "type": "photoBatch", "options": null, "unit": "张", "required": false,
+      "condition": null, "riskLevel": "none", "refRange": "验证一个厨房的口味基线;负担最重,建议放宽为尽量" }
+  ]
+}
+```
+
+> **说明**:源文档「16 条」按变量展开为 39 个采集项(`Q1a`…`Q16`);每条仍保留源文档的 `Q` 编号归属,`code` 为条件求值键。条件依赖的归因中间态键(`l.reuteriAbnormal` / `ironLow` / `hasDan` / `isFemaleTeen` / `hasDiabetes`)由 B1 常模比对段计算后注入 context(B2)。
+
+### 3.3 A3:`attribution_norm_values` 常模表(G10)
+
+**DDL**:
+
+```sql
+CREATE TABLE IF NOT EXISTS attribution_norm_values (
+    id              BIGINT AUTO_INCREMENT PRIMARY KEY,
+    norm_type       VARCHAR(20) NOT NULL COMMENT '常模类型: gut_flora(菌群)/dan(DAN测评)',
+    definition_id   BIGINT NULL COMMENT 'FK→indicator_definitions.id(归一化后关联,可空)',
+    code            VARCHAR(64) NOT NULL COMMENT '指标编码(菌种学名如Bifidobacterium 或 DAN维度key如emotionScore)',
+    display_name    VARCHAR(100) COMMENT '显示名',
+    member_age_band VARCHAR(32) NOT NULL COMMENT '年龄段带: 0-3/4-6/7-12/13-18/19-45/46-65/66+/all',
+    gender          VARCHAR(10) DEFAULT 'all' COMMENT '性别: male/female/all',
+    p5              DECIMAL(10,4) NULL COMMENT 'P5百分位值',
+    p25             DECIMAL(10,4) NULL COMMENT 'P25百分位值',
+    p50             DECIMAL(10,4) NULL COMMENT 'P50百分位值(中位数)',
+    p75             DECIMAL(10,4) NULL COMMENT 'P75百分位值',
+    p95             DECIMAL(10,4) NULL COMMENT 'P95百分位值',
+    unit            VARCHAR(20) COMMENT '单位(如 %)',
+    norm_version    VARCHAR(20) NOT NULL DEFAULT 'v1' COMMENT '常模版本',
+    source          VARCHAR(200) COMMENT '数据来源(谷禾710常模/DAN常模/导入文件名)',
+    status          TINYINT DEFAULT 1 COMMENT '0=禁用 1=启用',
+    created_at      DATETIME DEFAULT CURRENT_TIMESTAMP,
+    updated_at      DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    UNIQUE KEY uk_type_code_band_gender_ver (norm_type, code, member_age_band, gender, norm_version),
+    INDEX idx_type_code (norm_type, code),
+    INDEX idx_def (definition_id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='家庭归因常模值';
+```
+
+**Entity `AttributionNormValue.java`**(MyBatis-Plus 范式,同 `CognitiveNorm`):
+
+```java
+@Data
+@TableName("attribution_norm_values")
+public class AttributionNormValue implements Serializable {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+    private String normType;       // gut_flora / dan
+    private Long definitionId;     // 可空,关联 indicator_definitions
+    private String code;           // 菌种学名 或 DAN 维度 key
+    private String displayName;
+    private String memberAgeBand;  // 年龄段带
+    private String gender;         // male/female/all
+    private BigDecimal p5;
+    private BigDecimal p25;
+    private BigDecimal p50;
+    private BigDecimal p75;
+    private BigDecimal p95;
+    private String unit;
+    private String normVersion;
+    private String source;
+    private Integer status;
+    private Date createdAt;
+    private Date updatedAt;
+}
+```
+
+**Mapper `AttributionNormValueMapper.java`**:`public interface AttributionNormValueMapper extends BaseMapper<AttributionNormValue> {}`(沿用现有 Mapper 空接口范式)。
+
+**常模数据来源(⚠️ 需明确标注「未检索到的东西」)**:
+
+| 常模 | 现状 | 结构化源是否已存在 |
+|------|------|--------------------|
+| **菌群 710 条常模**(谷禾 21 维度 × 分龄/分性百分位) | 仅随报告(`health_gut_flora.populationLevel` 存**单条**人群百分位字符串)+ 知识库 | ❌ **未检索到**独立 p5-p95 结构化表/JSON。知识库 `统一知识库.json` 有 `菌种综合信息`(功能/关联疾病/检出报告数)、`菌属功能库`、`报告指标分级标准`(142 指标标准范围/状态分级,非 p5-p95)。→ **设计为「可配置 JSON 导入」**:`resources/norm/attribution_norm_gut_flora.json` 空壳模板(`[{code,memberAgeBand,gender,p5,p25,p50,p75,p95,unit,source,normVersion}]`),由业务侧/教练侧填充真实 710 条后导入 |
+| **DAN 常模**(情绪/大五/认知 p5-p95) | `cognitive_norms` 表已有(`CognitiveNorm.java`:dimensionKey/gender/ageMin(月)/ageMax(月)/p5-p95)+ `health_norm_reference` 表已有(`HealthNormReference.java`:dimension/gender/ageMin/ageMax/p5-p95,含 emotion/bigFive/drive/selfConcept/action/wealth 种子 18 条) | ✅ 已存在,**可直接复用**:B1 常模比对段优先查 `cognitive_norms`/`health_norm_reference`,缺失时才落 `attribution_norm_values` |
+
+> **设计取舍**:`attribution_norm_values` 作为**归因专用统一常模视图**,兼容两类 norm_type;DAN 常模优先复用既有 `cognitive_norms`/`health_norm_reference`(避免双写),仅在 DAN 需「年龄段带+性别」维度不满足时用 `attribution_norm_values` 补位。菌群 710 常模**必须**落 `attribution_norm_values`(当前无任何落点)。
+
+### 3.4 A4:合规红线模板(G9,10 条,按 PRD §D 分级 + E7 品牌级口径)
+
+**推荐:常量类 `constant/AttributionRedlines.java`**(纯后端、可单测、零数据风险,符合 E12 合规后置)。提供枚举 `Redline` 与 `LEVEL`:
+
+```java
+public final class AttributionRedlines {
+    public enum Level { P0, P1, P2 }
+    public static final class Redline {
+        public final String code;   // RL01..RL10
+        public final Level level;
+        public final String title;
+        public final String message;   // 品牌级口径文案
+        public final String scope;     // appliesTo: 归因报告/调整方案/任务/全部
+    }
+    public static List<Redline> all() { ... }
+    public static List<Redline> byLevel(Level l) { ... }
+}
+```
+
+**10 条红线明细**(`code`/`level`/`title`/`message(品牌级口径)`/`scope`):
+
+| code | level | title | message(E7 品牌级口径,品牌露出不附带功效承诺) | scope |
+|------|-------|-------|--------------------------------------------------|-------|
+| RL01 | P0 | 测评≠诊断 | 菌群「相似度」是模式比对,不是疾病;DAN 不是智力测验也不是临床诊断。所有关联均为关联,非因果。 | 全部 |
+| RL02 | P0 | 情绪红线 | 0.9 百分位的情绪总分不是谈心能处理的量级;出现自伤、拒学、持续失眠 → 立即就医。本方案不做情绪处理,角色是「识别+转介」。 | ③④ |
+| RL03 | P0 | 儿童补剂红线 | 儿童补铁补锌必须由儿科/儿保科按体重与检验结果定剂量,铁过量有毒,严禁自行加量。方案不出现儿童剂量数字,只写「医生定」。 | ⑤⑥ |
+| RL04 | P0 | 糖尿病红线 | 不调药、不荐药、不设血糖目标值。随访节奏、用药、减重目标全部由内分泌科定;教练只做生活方式支持与「让他去随访」。 | ③⑤ |
+| RL05 | P1 | 产品非治疗 | Enagic 还原水/姜黄、瓜尔豆益生元 PHGG、益生菌均为膳食或食品级支持,不宣称治疗任何疾病、不替代药物;有特殊病史(胆结石、抗凝药、肾功异常等)先咨询医生。 | ⑤ |
+| RL06 | P1 | 标签红线 | 不在孩子面前使用「多动症」「抑郁」「天才」「学霸」等定性词。 | ③⑤⑥ |
+| RL07 | P1 | 先医后补 | 所有涉及查血、补剂的动作都「先医后补」,不自行下诊断、不给剂量。P0 动作全部是查血/评估/随访,而非补。 | ⑤⑥ |
+| RL08 | P1 | 教练禁忌 | 永远不对家长说「你缺某一维」;不替家长做决定;不用评判式语言;不硬套模型。 | ④ |
+| RL09 | P2 | 服药间隔纪律 | 还原水不与药物同服(间隔≥1h);益生菌与抗生素间隔≥2h;PHGG 不与抗生素同服,用后停纤维 3-5 天再做菌群重建。 | ⑤ |
+| RL10 | P2 | 铁餐纪律 | 铁餐与奶/茶/咖啡错开≥2h、配维 C。 | ⑤ |
+
+**可选表方案**:如需管理端可编辑,提供 `attribution_redlines` 表(`id/code/level/title/message/scope/status/updated_at`),由 `runMigrations()` 迁移 424 段幂等建表 + 种子;**默认走常量类**,表方案为低优先级备选。
+
+### 3.5 B1:`AttributionAnalysisService` 归因引擎
+
+**接口签名**:
+
+```java
+public interface AttributionAnalysisService {
+    /** 核心入口:输入档案+确认问卷+检测数据+常模 → 十节归因报告 */
+    AttributionReportVO analyze(AttributionInput input);
+    /** 取报告(含十节结构) */
+    AttributionReportVO getReport(Long attributionId);
+    /** ④调整后重算(B3 回填后调用;作废⑤由 AttributionPlanService 处理) */
+    AttributionReportVO recompute(Long attributionId, Map<String,Object> fieldDeltas);
+}
+```
+
+**`AttributionInput` 字段**:`familyId`、`memberIds`(List<Long>,3 人:妈妈/女儿/儿子,E6)、`gutReportIds`(菌群报告ID列表,桥接 `health_gut_flora`)、`danResultIds`(DAN 结果ID列表)、`confirmSurveyRecordId`(确认问卷记录,桥接 `survey_records.answersJson`)、`planId`(关联 health_plans,可空)。
+
+**数据流**(菌群JSON + DAN + 常模 + 确认问卷 → 十节归因报告):
+
+```
+[菌群 reportId→health_gut_flora]  [DAN danResultId→dan_assessment_results]
+        │                                     │
+        ▼                                     ▼
+   ┌──────────────────────────────────────────────────────────┐
+   │ AttributionAnalysisServiceImpl.analyze(input)             │
+   │  Pipeline: 5 段确定性规则 + 1 段 AI 叙述                   │
+   │                                                            │
+   │ ① NormCompareEngine     常模比对 → 每指标 percentileBand + status│
+   │ ② IndicatorInterpretEngine 指标解读 → 五维含义(异常/偏离/可撤回) │
+   │ ③ FiveDimAttributionEngine 逐人+家庭 五维归因(0-100 教练相对刻度) │
+   │ ④ MainCauseChainEngine  主因链(把四人的问题串成一条链)         │
+   │ ⑤ FalsificationEngine   被证伪项(同伴依恋无效/乳杆菌可撤回等)   │
+   │ ⑥ AttributionNarrativeService 十节叙述(AI润色+规则兜底)       │
+   └──────────────────────────────────────────────────────────┘
+        │
+        ▼ 红线注入(RL01-RL08 由规则层硬注入,非 AI)
+   AttributionReportVO {
+     status: ANALYZING→READY,
+     reportJson: { 结论先行 / 数据速览 / 逐人归因 / 家庭系统归因
+                   (五维地图+主因链+被证伪项) / 应对方案 / 12周目标 /
+                   教练提问序列 / 问诊清单(已回收v1.2) / 红线与转介 / 一句话收尾 },
+     redlineHits: [RL02...],
+     intermediateState: { l.reuteriAbnormal, ironLow, hasDan, ... }  // 供B2/B3
+   }
+```
+
+**十节报告结构(对齐《归因分析 v1.1》一~十)**:
+
+| 节 | 标题 | 生成方式 | 关键字段 |
+|----|------|----------|----------|
+| 一 | 结论先行 | AI 叙述 + 规则事实注入 | `conclusionHeadline`(如「四条表象,两个主因维」) |
+| 二 | 四人数据速览 | 规则 | `overview[]`:指标×成员×百分位×干预含义 |
+| 三 | 逐人归因(表象→本质→五维归因→应对) | 规则主体 + AI 润色 | `perMember[]`:memberId/role/surface/essence/fiveDim/action |
+| 四 | 家庭系统归因(五维地图+主因链+被证伪项) | 规则 | `familyMap`/`mainCauseChain`/`falsified[]` |
+| 五 | 应对方案 | 规则(三条通道,主因维结构性动作) | `channels[]` |
+| 六 | 12 周可检验目标 | 规则 | `goals[]`:指标/现在/12周目标 |
+| 七 | 教练提问序列(七层 Socratic) | **AI 叙述**(复用 AiGateway) | `coachQuestions[]` |
+| 八 | 问诊清单(已回收→v1.2) | 规则(复用 A2 JSON) | `questionnaire` 引用 |
+| 九 | 红线与转介 | 规则(RL01-RL08) | `redlines[]` |
+| 十 | 一句话收尾 | AI 叙述 | `closingLine` |
+
+**AI 混合策略(`AiGateway`,`service/AiGateway.java` 已含熔断/超时/PII/Fallback)**:
+
+| 内容 | 规则 | AI(`AiGateway`) | AI 失败 fallback |
+|------|------|-------------------|------------------|
+| 一 结论先行 | 事实注入 | `generateHealthPlan` 或新增归因 prompt | 规则模板句 + 事实(如「四条表象,两个主因维」) |
+| 三 逐人归因叙述 | 主体结构化 | 润色 | 结构化字段直接渲染 |
+| 七 教练提问序列 | 七层骨架 | `aiGateway.chatForAnalysis`(归因 Socratic prompt) | 内置七层模板问题 |
+| 十 一句话收尾 | — | AI | 内置收尾模板 |
+| 二/四/五/六/八/九 | 纯规则 | — | —(不依赖 AI) |
+
+> **关键合规**:红线(RL01-RL08)、儿童剂量「医生定」、品牌「不宣称功效」**全部由规则层硬注入**,AI 仅产叙述,不能覆盖合规文案。AI 关闭/熔断/超时 → 规则模板兜底,**流程永不阻断**(对齐 `generatePlanResult` 的 `buildSamplePlan` fallback 范式)。
+
+**报告存储**:`attribution_reports` 表 + `AttributionReport` 实体(`id/family_id/member_ids/plan_id/status(ANALYZING/READY/ADJUSTING/ADJUSTED/CONFIRMED/GENERATED/INVALIDATED)/report_json/redline_hits/intermediate_state/created_at/updated_at`)。状态机见 §4.2。
+
+### 3.6 B2:动态确认问卷条件路由
+
+**新端点**(`controller/SurveyController.java` 扩展):
+
+```
+POST /api/survey/attribution/confirm-questions
+Body: { familyId, memberId, attributionId, answeredSummary? }
+Resp: { templateId, questions: [ {id,code,group,title,type,options,unit,required,riskLevel,refRange} ] }
+```
+
+**逻辑**:
+1. 取 `survey_templates` 中 `target='family_attribution'` 的模板 `questionsJson`(A2 结构)。
+2. 构造 context:`memberRole/gender/ageBand`(来自 `family_members` + `family_relationships`,E10)+ 归因中间态 `intermediateState`(来自 `attribution_reports.intermediate_state`,B1 产出)+ 已作答摘要。
+3. `ConditionEvaluatorService.evaluate(question.condition, context)` 逐条求值,`condition==null` 恒发;命中返回子集。
+4. 按对象过滤:仅下发该对象(group 匹配)+ 家庭级(四人/全家)题目。
+
+**`ConditionEvaluatorService`**(新建):
+
+```java
+public interface ConditionEvaluatorService {
+    boolean evaluate(JsonNode condition, Map<String,Object> context);
+    Map<String,Object> buildContext(Long familyId, Long memberId, Long attributionId);
+}
+```
+
+> 求值器归属:**`ConditionEvaluatorService` 独立服务**(非归因引擎内),供 B2 路由与 B3 回填共用;关联归因中间态通过 `attribution_reports.intermediate_state` 读取。
+
+### 3.7 B3:`AttributionAdjustService` 自然语言调整编排
+
+**接口**:
+
+```java
+public interface AttributionAdjustService {
+    /** 对话式调整:用户消息 → AI 回答 + 结构化回填(可空增量) */
+    AdjustResult adjust(Long attributionId, Long userId, String message, String conversationId);
+    /** 用户确认调整:回填生效 → 报告 CONFIRMED;若有已生成方案则作废重生成 */
+    AdjustResult confirm(Long attributionId, Long userId);
+}
+```
+
+**接口**:`POST /api/attribution/adjust`(body:`attributionId/userId/message/conversationId`),`POST /api/attribution/confirm-adjust`(body:`attributionId`)。
+
+**数据流**(复用 `AIChatController` + `AiGateway`):
+1. 组装归因上下文(`attribution_reports.report_json` + 成员数据 + 红线 RL08 提示词),注入**归因教练 prompt**(七层 Socratic:澄清→探因→假设→证据→替代→行动→复盘)。
+2. `aiGateway.chat(query, userId, conversationId, inputs)` 对话。
+3. 解析 AI 回答中的**结构化结论标记**(如 `[ATTR_DELTA]{"ironLow":false,"l.reuteriAbnormal":false}`)→ 回填 `attribution_reports.intermediate_state` 与报告结构化字段。
+4. **红线校验**:若回填命中 RL02(自伤/拒学/持续失眠)→ 报告状态置 `ADJUSTED` 但标记 `redline_terminate=true` + 转介信息露出 + 家长确认(E4 弱提示,不阻断但需家长签名确认),**流程不自动终止**(E4 已拍板弱提示)。
+5. 若已有 `plan_id` 关联且 `status=GENERATED` → 作废置 `INVALIDATED`(⑤ 失效重生成,对齐状态机「④ 结论再变 → ⑤ Invalidated」)。
+
+### 3.8 B4:全家干预方案 7 章生成
+
+**接口**:
+
+```java
+public interface AttributionPlanService {
+    /** 归因结论(attribution_id) → planJson(7章结构),存 health_plans.plan_json(plan_type=family_attribution_plan) */
+    String generateFamilyPlan(Long attributionId, Long userId);
+    /** 按层级提取动作表,供⑥筛选确认成任务(阶段三复用) */
+    List<ActionItem> extractActionTable(String planJson, String level);
+}
+```
+
+**planJson 7 章 schema**(对齐《全家干预方案 v1.1》骨架 + B 模板 4 属性):
+
+```json
+{
+  "schemaVersion": "1.0",
+  "planType": "family_attribution_plan",
+  "header": {
+    "summary": "一句话摘要", "scope": ["妈妈","女儿","儿子"],
+    "dataSources": ["谷禾菌群3份","DAN2份","父亲进阶方案(背景)"],
+    "relation": "归因报告负责定位+转介;本方案负责可执行的产品+营养+生活方式",
+    "redlines": ["RL01...","RL03...","RL05..."]   // 红线前置,先读
+  },
+  "chapters": [
+    { "no": 1, "title": "三人干预相关数据速览",
+      "rows": [ { "indicator":"双歧杆菌属%", "mom":"0.504(偏低)", "daughter":"0.074(极低)", "son":"1.208(相对正常)", "meaning":"妈妈、女儿重点补双歧" } ] },
+    { "no": 2, "title": "主线产品:作用原理·合规口径·用法",
+      "products": [ { "name":"Enagic还原水", "brand":"Enagic", "what":"电解还原水…",
+                       "why":"三人都存在水合与冲泡介质需求", "how":"日常直饮+做饭+冲泡(≤40℃)",
+                       "compliance":["RL05","RL09"] } ] },
+    { "no": 3, "title": "分人方案",
+      "members": [ { "member":"妈妈", "direction":"减负担+通吸收",
+                      "actions": [ { "level":"P0", "action":"查血不自行补铁", "product":null,
+                                       "how":"血常规+血清铁+铁蛋白", "reviewHook":"4-8周复查" },
+                                    { "level":"P1", "action":"降胆汁酸", "product":"厨房改造+PHGG",
+                                       "how":"油炸/外食≤1次/周", "reviewHook":"12周复测<95" } ] } ] },
+    { "no": 4, "title": "家庭厨房与饮水改造(共享基座)",
+      "channels": [ { "channel":"饮水通道", "minStep":"全屋切换还原水", "owner":"妈妈", "reviewHook":"一周饮水量自评" } ] },
+    { "no": 5, "title": "12周执行节奏与可检验目标",
+      "weeks": [ { "week":"第1-2周", "family":"还原水入户", "mom":"查血", "daughter":"DAN复测", "son":"儿科查铁锌" } ],
+      "goals": [ { "indicator":"女儿双歧/多样性/大肠杆菌", "now":"0.074%/39/15.04%", "target":"双歧≥0.19%;多样性↑;大肠杆菌↓" } ] },
+    { "no": 6, "title": "红线与转介(再强调)", "redlines": ["RL01","RL03","RL04","RL05","RL06","RL09","RL10"] },
+    { "no": 7, "title": "附录:产品选购与用法提示",
+      "appendix": [ { "product":"瓜尔豆益生元PHGG", "select":"食品级部分水解瓜尔胶", "use":"5g/天起", "pitfall":"不与抗生素同服" } ] }
+  ]
+}
+```
+
+**结构要点(继承源模板 4 属性)**:
+1. **分级动作**:`level ∈ {P0(先做/多为就医转介), P1(本周), daily(日常), P2}` —— 天然对应流程⑥的「筛选确认成任务」;
+2. **复盘钩子**:每动作带 `reviewHook`(可验证目标,如「一周≥5天按纸上时间做」);
+3. **先共享基座后精准**:第 4 章(家庭共享)先于第 3 章(分人)?——源文档实际顺序是 三(分人) 在 四(共享) 前,但**执行顺序**强调「先共享基座后精准」;设计上:`chapters[3]=分人方案` 在前(展示顺序),但**第 4 章共享基座标注为「先做」**,且 `header.order` 注明「先共享基座后精准」,避免展示顺序与执行顺序混淆;
+4. **红线前置**:`header.redlines` + `chapters[5]`(第 6 章)再强调;生成时注入 RL01-RL10 文案(A4)。
+
+**生成函数数据流**(归因结论 → planJson):
+```
+attribution_reports(report_json + intermediate_state)
+   → ① 提取三人归因结论(五维/主因链/指标)
+   → ② 产品映射(品牌级: Enagic还原水/姜黄、PHGG、益生菌株名) —— 由规则表驱动,不调 AI
+   → ③ 分人×层级动作表(规则模板 + 指标驱动开关)
+   → ④ 共享基座通道(4通道) + 12周节奏 + 附录
+   → ⑤ 红线前置注入(RL01-RL10, E7 品牌级口径)
+   → ⑥ planJson 落 health_plans(plan_type=family_attribution_plan)
+```
+
+> **E6 人范围**:`generateFamilyPlan` 仅处理 `memberIds=[妈妈,女儿,儿子]`;爸爸不生成(另有进阶方案),若传入爸爸 memberId 直接跳过并记 warning。**E7 品牌级**:产品名直接展示品牌(Enagic 还原水/姜黄、PHGG、长双歧 BB536 等),但 `compliance` 强制带 RL05「不宣称治疗」+ RL03「儿童剂量医生定」。
+
+### 3.9 类图(Mermaid classDiagram)
+
+```mermaid
+classDiagram
+    class HealthPlan {
+        +Long id
+        +Long familyId
+        +String memberIds
+        +String dimensions
+        +String planJson
+        +String status
+        +String planType  "A1: health_plan/family_attribution_plan"
+        +Integer totalDays
+    }
+    class SurveyTemplate {
+        +Long id
+        +String title
+        +String dimension
+        +String questionsJson  "A2: 扩展JSON(schemaVersion/target/questions)"
+        +String cycleType
+    }
+    class SurveyRecord {
+        +Long id
+        +Long familyId
+        +Long memberId
+        +Long templateId
+        +String answersJson
+    }
+    class AttributionNormValue {
+        +Long id
+        +String normType
+        +Long definitionId
+        +String code
+        +String memberAgeBand
+        +String gender
+        +BigDecimal p5
+        +BigDecimal p25
+        +BigDecimal p50
+        +BigDecimal p75
+        +BigDecimal p95
+        +String normVersion
+        +String source
+    }
+    class AttributionReport {
+        +Long id
+        +Long familyId
+        +String memberIds
+        +Long planId
+        +String status  "ANALYZING/READY/ADJUSTING/ADJUSTED/CONFIRMED/GENERATED/INVALIDATED"
+        +String reportJson  "十节结构"
+        +String redlineHits
+        +String intermediateState  "供B2/B3"
+    }
+    class AttributionRedlines {
+        <<final>>
+        +List~Redline~ all()
+        +List~Redline~ byLevel(Level)
+    }
+    class AiGateway {
+        +Map chat(query,userId,conversationId,inputs)
+        +Map chatForAnalysis(query,userId,conversationId,inputs)
+        +String generateHealthPlan(inputs)
+    }
+    class AIChatController {
+        +Result sendMessage(userId,params)
+    }
+    class ConditionEvaluatorService {
+        <<interface>>
+        +boolean evaluate(JsonNode condition, Map context)
+        +Map buildContext(familyId,memberId,attributionId)
+    }
+    class AttributionAnalysisService {
+        <<interface>>
+        +AttributionReportVO analyze(AttributionInput input)
+        +AttributionReportVO getReport(attributionId)
+        +AttributionReportVO recompute(attributionId, fieldDeltas)
+    }
+    class AttributionAnalysisServiceImpl {
+        +analyze(input)
+        -runPipeline(input)
+    }
+    class NormCompareEngine { +compare(input) List~IndicatorReading~ }
+    class IndicatorInterpretEngine { +interpret(readings) Map }
+    class FiveDimAttributionEngine { +attribute(interpreted) Map }
+    class MainCauseChainEngine { +chain(fiveDim) List~Link~ }
+    class FalsificationEngine { +falsify(chain) List~Falsified~ }
+    class AttributionNarrativeService { +narrate(sections, readings) String }
+    class AttributionAdjustService {
+        <<interface>>
+        +AdjustResult adjust(attributionId,userId,message,conversationId)
+        +AdjustResult confirm(attributionId,userId)
+    }
+    class AttributionAdjustServiceImpl
+    class AttributionPlanService {
+        <<interface>>
+        +String generateFamilyPlan(attributionId,userId)
+        +List~ActionItem~ extractActionTable(planJson,level)
+    }
+    class AttributionPlanServiceImpl
+    class SurveyController {
+        +Result confirmQuestions(params,userId,currentMemberId)
+        +Result submit(params,userId,currentMemberId)
+    }
+    class AttributionController {
+        +Result analyze(params,userId,familyId)
+        +Result confirmQuestions(params,userId,familyId)
+        +Result adjust(params,userId,familyId)
+        +Result generatePlan(params,userId,familyId)
+    }
+
+    AttributionAnalysisServiceImpl --> NormCompareEngine
+    AttributionAnalysisServiceImpl --> IndicatorInterpretEngine
+    AttributionAnalysisServiceImpl --> FiveDimAttributionEngine
+    AttributionAnalysisServiceImpl --> MainCauseChainEngine
+    AttributionAnalysisServiceImpl --> FalsificationEngine
+    AttributionAnalysisServiceImpl --> AttributionNarrativeService
+    AttributionNarrativeService ..> AiGateway
+    AttributionAnalysisServiceImpl ..> AttributionNormValue
+    AttributionAnalysisServiceImpl ..> AttributionRedlines
+    AttributionAnalysisServiceImpl ..> SurveyRecord
+    AttributionAdjustServiceImpl ..> AttributionReport
+    AttributionAdjustServiceImpl ..> AIChatController
+    AttributionAdjustServiceImpl ..> AttributionRedlines
+    AttributionPlanServiceImpl ..> AttributionReport
+    AttributionPlanServiceImpl ..> HealthPlan
+    AttributionPlanServiceImpl ..> AttributionRedlines
+    SurveyController ..> ConditionEvaluatorService
+    SurveyController ..> SurveyTemplate
+    AttributionController ..> AttributionAnalysisService
+    AttributionController ..> AttributionAdjustService
+    AttributionController ..> AttributionPlanService
+    AttributionController ..> SurveyController
+    HealthPlan "1" --> "1" AttributionReport : planId
+```
+
+---
+
+## 4. 程序调用流程(Program Call Flow)
+
+### 4.1 核心闭环 ③→⑤ 时序图(Mermaid sequenceDiagram)
+
+```mermaid
+sequenceDiagram
+    autonumber
+    actor U as 用户(家长)
+    participant C as AttributionController
+    participant S as SurveyController
+    participant AS as AttributionAnalysisService
+    participant CE as ConditionEvaluatorService
+    participant NE as NormCompareEngine
+    participant NV as AttributionNarrativeService
+    participant AI as AiGateway
+    participant AD as AttributionAdjustService
+    participant PS as AttributionPlanService
+    participant HP as HealthPlan
+
+    Note over U,HP: ② 动态确认问卷(B2)
+    U->>C: POST /api/survey/attribution/confirm-questions {familyId,memberId,attributionId}
+    C->>S: confirmQuestions(params)
+    S->>CE: buildContext(familyId,memberId,attributionId)
+    CE-->>S: context(role/ageBand/intermediateState)
+    S->>CE: evaluate(question.condition, context) 逐条
+    CE-->>S: 下发子集(仅该对象+家庭级)
+    S-->>U: questions[] (含riskLevel)
+
+    U->>S: POST /api/survey/submit {answersJson,riskHits}
+    S-->>C: 确认问卷已回收(→v1.2)
+
+    Note over U,HP: ③ 归因分析(B1)
+    U->>C: POST /api/attribution/analyze {familyId,memberIds,gutReportIds,danResultIds,confirmSurveyRecordId}
+    C->>AS: analyze(input)
+    AS->>NE: compare(input) 常模比对(attribution_norm_values/cognitive_norms)
+    NE-->>AS: IndicatorReading[](percentileBand/status)
+    AS->>AS: IndicatorInterpretEngine → FiveDimAttributionEngine → MainCauseChainEngine → FalsificationEngine
+    AS->>NV: narrate(sections, readings)
+    NV->>AI: chatForAnalysis(归因叙述prompt)
+    AI-->>NV: 叙述 或 null(熔断/超时)
+    NV-->>AS: 规则模板兜底(若null)
+    AS->>AS: 红线注入(RL01-RL08)
+    AS-->>U: AttributionReportVO{status:READY, reportJson, intermediateState}
+
+    Note over U,HP: ④ 自然语言调整(B3)
+    U->>C: POST /api/attribution/adjust {attributionId,message,conversationId}
+    C->>AD: adjust(attributionId,userId,message,conversationId)
+    AD->>AI: chat(归因Socratic prompt)
+    AI-->>AD: answer + [ATTR_DELTA]标记
+    AD->>AD: 解析回填intermediateState/report字段
+    AD->>AD: 红线校验(RL02自伤/拒学/持续失眠→标记建议专业评估+家长确认,E4)
+    AD->>AD: 若有GENERATED方案→置INVALIDATED
+    AD-->>U: AdjustResult{answer,fieldDeltas,redlineTerminate}
+    U->>C: POST /api/attribution/confirm-adjust {attributionId}
+    C->>AD: confirm(attributionId,userId)
+    AD-->>U: status=CONFIRMED
+
+    Note over U,HP: ⑤ 调整方案(B4)
+    U->>C: POST /api/attribution/plan {attributionId}
+    C->>PS: generateFamilyPlan(attributionId,userId)
+    PS->>PS: 归因结论→产品映射(品牌级,E7)+分人×层级动作+共享基座+12周+红线前置
+    PS->>HP: 存health_plans(plan_type=family_attribution_plan)
+    HP-->>U: planJson 7章
+```
+
+### 4.2 归因流程状态机(Mermaid stateDiagram,对齐 PRD §C)
+
+```mermaid
+stateDiagram-v2
+    [*] --> Submitted : ① 基本问卷提交
+    Submitted --> Pending : 归因中间态就绪(待确认问题)
+    Pending --> Confirmed : ② 确认问卷回收(含riskLevel命中标记)
+    Confirmed --> Analyzing : ③ 触发归因
+    Analyzing --> Ready : 规则引擎完成(常模比对→五维→主因链→被证伪)
+    Ready --> Adjusting : ④ 用户发起调整
+    Adjusting --> Adjusted : AI回填增量
+    Adjusted --> Confirmed : 用户确认(回填生效)
+    Confirmed --> Generated : ⑤ 生成调整方案(7章)
+    Generated --> TaskConfirmed : ⑥ 筛选确认成任务(阶段三)
+    Confirmed --> Invalidated : ④结论再变(作废⑤)
+    Generated --> Invalidated : 回退调整
+    Invalidated --> Adjusting : 重新调整
+    Ready --> Confirmed : 用户直接确认(跳过调整)
+    Analyzing --> Ready : mock兜底(AI失败不阻断)
+```
+
+---
+
+## 5. Anything UNCLEAR(未确定 / 假设 / 未检索到)
+
+1. **⚠️ 菌群 710 条常模结构化源未检索到**:`health_gut_flora.populationLevel` 存单条百分位;知识库 `统一知识库.json` 仅有 `菌种综合信息`/`菌属功能库`/`报告指标分级标准`(142 指标标准范围/状态分级,非 p5-p95)。→ A3 设计为**可配置 JSON 导入**(`resources/norm/attribution_norm_gut_flora.json` 空壳),真实 710 条需业务侧/教练侧提供并填充后导入。**这是最大数据不确定性**,建议阶段一先落空壳 + 导入器,阶段二 B1 常模比对段对缺失常模返回「待补」状态(不猜值,对齐源文档「待补」项不猜测)。
+2. **五维归因的权重/阈值未在源文档给出数值**:文档只给「教练定位用相对刻度(0-100)」与「主因维」概念,未给分维权重表。→ 设计为 `AttributionWeights` 常量类(规则层集中配置),默认值按源文档语义(行/身 双主因示例),**具体数值待教练侧确认**(阶段四 D1 或后续校准),当前用保守默认。
+3. **归因 prompt 是否在 LangGraph 有对应图**:`AiGateway.generateHealthPlan` 走 `/api/v1/health/plan/generate`(通用健康方案);归因叙述需**新增归因专用 prompt 模板**(`PromptConfig` 注入),LangGraph 侧图/端点是否已有 **未检索到**。→ B1 设计为:优先走 `chatForAnalysis`(已有 `/api/v1/chat`),无归因图时用规则模板兜底;**不强依赖 LangGraph 新增端点**。
+4. **Q16 21 张照片上传**:`health_gut_flora` 无照片通道;Q16 走 `file_record`/OSS 复用现有上传链路,**照片-归因关联**属阶段三 C3 数据源桥接,本设计仅定义 `photoBatch` 类型 + `required=false`(负担最重,建议放宽为「尽量」)。
+5. **角色确认(E10)**:`family_relationships`(generation/relationship_key) 是角色来源,但源文档承认「按姓名年龄推断、未见关系证明」是盲区。→ B2 context 构建用 `family_relationships`,**用户须主动确认角色**(前端阶段三加确认步),本设计不默认系统推断。
+6. **合规后置边界**:E12 要求仅 mock/测试数据。→ 全流程加配置开关 `app.attribution.enabled`(默认 false,仅测试环境开启),`AttributionController` 入口统一校验;真实用户放行 = 阶段四 D1。
+7. **A4 表 vs 常量类取舍**:默认常量类(零数据风险);`attribution_redlines` 表为管理端可编辑备选,**阶段一不建表**(除非需求方明确要运营可改)。
+8. **主工作树排除**:`E:/cfc` 本机主工作树不作为派发目标;本设计文档单独 `git add <该文件>` 提交,不用 `add -A`(他人未提交改动,见 §7 纪律)。
+
+---
+
+# Part B:任务分解(Task Decomposition)
+
+## 6. 所需第三方包(Required Packages)
+
+阶段一/二**纯后端增量,无新增第三方依赖**——全部复用现有栈:
+- Spring Boot 2.x / Spring Web / `spring-boot-starter-jdbc`
+- MyBatis-Plus(`com.baomidou:mybatis-plus-boot-starter`)——实体/Mapper 范式已用
+- Jackson(`com.fasterxml.jackson.core:jackson-databind`)——JSON 解析
+- Lombok —— `@Data`/`@TableName`/`@TableField`
+- 无前端依赖(阶段三才涉及前端框架/组件)
+
+## 7. 任务列表(Task List,按实现顺序 + 依赖)
+
+> 建议派发实例:后端 `lan-248`(DB/Java 后端);前端 `lan-204`;综合 `pub-iwintrue`。阶段一/二**全部后端**,建议 `lan-248` 主责,`pub-iwintrue` 协审(只读 review)。
+
+### 阶段一(数据地基,无依赖,可独立上线)
+
+#### ATT-S1-A1|health_plans.plan_type 迁移(G5)
+- **目标文件**:`cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java`、`cfc-backend/src/main/resources/schema.sql`、`cfc-backend/src/main/java/com/etotem/cfc/entity/HealthPlan.java`
+- **实现要点**:
+  1. `runMigrations()` 末尾(`createBodyFatScaleRecordsTable();` 之后,`DatabaseInitializer.java:3341`)追加 `migrateHealthPlansPlanType()`;
+  2. 用 `ensureColumn("health_plans","plan_type","VARCHAR(32) DEFAULT 'health_plan' COMMENT '...'")`(**幂等**,列已存在跳过);
+  3. 同步 `schema.sql:5082` health_plans 建表加 `plan_type` 行;
+  4. `HealthPlan.java` 加 `@TableField("plan_type") private String planType;`
+- **验收标准**:① 启动后 `SHOW COLUMNS FROM health_plans` 含 `plan_type`;② 存量行默认 `health_plan`;③ 实体映射 `getPlanType()/setPlanType()` 可用;④ `git diff` 仅涉 3 文件。
+- **派发**:`lan-248`
+
+#### ATT-S1-A2|SurveyTemplate.questionsJson schema 扩展 + 第八章 16 条 JSON 样例(G2 半)
+- **目标文件**:`cfc-backend/src/main/resources/`(或 `config/`)下新增问题模板种子(`family_attribution_questions.json` 或经 `runMigrations()` 幂等写入 `survey_templates` 一行 `target='family_attribution'`)、`service/ConditionEvaluatorService.java`(接口+impl,含 ops 求值)
+- **实现要点**:
+  1. 按 §3.2 定义扩展 JSON 结构(`schemaVersion/target/questions`,字段 `id/code/group/title/type/options/unit/required/condition/riskLevel/refRange`);
+  2. 写入 16 条(39 采集项)完整 JSON 样例(§3.2 代码块,可直接入库 `questionsJson`);
+  3. `ConditionEvaluatorService`:`evaluate(JsonNode,Map)` 支持 `==/!=/>/>=/</<=/contains/in/exists/anyOf`;`buildContext` 组装 role/ageBand/intermediateState;
+  4. 幂等种子:`survey_templates` 按 `title`/`target` 判重,避免重复插入。
+- **验收标准**:① 模板 `questionsJson` 解析为 §3.2 结构;② `ConditionEvaluatorService.evaluate` 对 `{var:"l.reuteriAbnormal",op:"==",val:true}` 在 context 命中时返回 true;③ 单测覆盖 6 种操作符 + null 恒真 + 未知 var 保守 false。
+- **派发**:`lan-248`
+
+#### ATT-S1-A3|attribution_norm_values 常模表 + 可配置 JSON 导入(G10)
+- **目标文件**:`cfc-backend/src/main/java/com/etotem/cfc/entity/AttributionNormValue.java`、`cfc-backend/src/main/java/com/etotem/cfc/mapper/AttributionNormValueMapper.java`、`cfc-backend/src/main/resources/schema.sql`、`cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java`、`cfc-backend/src/main/resources/norm/attribution_norm_gut_flora.json`
+- **实现要点**:
+  1. DDL(§3.3)幂等建表 + 唯一键 `uk_type_code_band_gender_ver`;
+  2. Entity + Mapper(MyBatis-Plus 范式);
+  3. 常模导入器:启动时读 `classpath:norm/attribution_norm_gut_flora.json`(空壳)幂等导入 `norm_type=gut_flora`;DAN 常模**优先复用** `cognitive_norms`/`health_norm_reference`,不重复建;
+  4. `attribution_norm_gut_flora.json` 空壳模板含字段说明 + `{"placeholder":true,"note":"真实710条待业务侧填充"}`。
+- **验收标准**:① 表存在且唯一键生效;② 空壳导入不报错(0 行导入);③ 填充样例行后可查;④ `git diff` 仅涉上述文件。
+- **⚠️ 未检索到**:710 条真实常模数据源,本任务只交付导入器 + 空壳;真实数据为业务侧前置条件。
+- **派发**:`lan-248`
+
+#### ATT-S1-A4|合规红线模板(10 条,P0/P1/P2 分级 + E7 品牌级)(G9)
+- **目标文件**:`cfc-backend/src/main/java/com/etotem/cfc/constant/AttributionRedlines.java`(+ 可选 `entity/AttributionRedline.java`)
+- **实现要点**:
+  1. 枚举 `Level{P0,P1,P2}` + 内部类 `Redline{code,level,title,message,scope}`;
+  2. 10 条红线按 §3.4 明细硬编码(RL01-RL10),**E7 品牌级口径**(品牌露出不附带功效承诺)+ **E4 弱提示**(RL02 措辞改为「建议专业评估+转介信息露出+家长确认」而非「阻断」);
+  3. `all()` / `byLevel(Level)` / `byScope(String)`;
+  4. 单测:10 条完整、level 分布 P0×4/P1×4/P2×2、每条 message 非空且不含「治愈/根治」等禁词。
+- **验收标准**:① 10 条全覆盖;② 单测通过;③ `byLevel(P0)` 返回 4 条(RL01-RL04)。
+- **派发**:`lan-248`
+
+### 阶段二(核心闭环 ③→⑤,依赖阶段一 A1-A4)
+
+#### ATT-S2-B1|归因分析引擎 AttributionAnalysisService(G1/G7/G8 半)
+- **目标文件**:`service/AttributionAnalysisService.java`、`service/impl/AttributionAnalysisServiceImpl.java`、`service/attribution/{NormCompareEngine,IndicatorInterpretEngine,FiveDimAttributionEngine,MainCauseChainEngine,FalsificationEngine}.java`、`service/attribution/AttributionNarrativeService.java`、`entity/AttributionReport.java`、`mapper/AttributionReportMapper.java`、`dto/{AttributionInput,AttributionReportVO}.java`、`controller/AttributionController.java`(analyze)、`resources/schema.sql`(attribution_reports 建表)、`config/DatabaseInitializer.java`(建表)
+- **实现要点**:
+  1. 5 段确定性 Pipeline(常模比对→指标解读→五维归因→主因链→被证伪项),纯 Java 无框架;
+  2. `AttributionNarrativeService` 走 `AiGateway.chatForAnalysis`(或 `generateHealthPlan` 归因 prompt),AI null → 规则模板兜底(永不阻断);
+  3. 红线 RL01-RL08 由规则层硬注入(非 AI);
+  4. 报告存 `attribution_reports`(status + report_json + intermediate_state + redline_hits);
+  5. `app.attribution.enabled` 开关(默认 false,仅 mock/测试数据,E12);
+  6. 常模缺失 → 指标返回「待补」不猜值。
+- **验收标准**:① mock 4 人家庭跑通 analyze 产出十节结构;② AI 关闭时产出规则模板报告(不 null);③ 红线注入 RL01/RL02 存在;④ intermediate_state 含 `l.reuteriAbnormal/ironLow/hasDan/isFemaleTeen/hasDiabetes` 键;⑤ 状态 ANALYZING→READY。
+- **派发**:`lan-248`(主)+ `pub-iwintrue`(协审)
+
+#### ATT-S2-B2|动态确认问卷条件路由(G2)
+- **目标文件**:`controller/SurveyController.java`(扩展)、`service/ConditionEvaluatorService.java`(复用)、`dto/ConfirmQuestionVO.java`
+- **实现要点**:
+  1. `POST /api/survey/attribution/confirm-questions`:按 familyId+memberId+attributionId 条件下发 16 条子集;
+  2. `ConditionEvaluatorService.buildContext` 读 `attribution_reports.intermediate_state`;
+  3. 按对象(group 匹配)+ 家庭级(四人/全家)过滤;
+  4. `submit` 扩展接收 `riskHits`(Q11/12/13 命中标记,E4 弱提示不阻断)。
+- **验收标准**:① 女儿成员下发含 Q10-13;② 铁偏低时发 Q4;③ 无 DAN 时发 Q9;④ Q11/12/13 带 `riskLevel=high`。
+- **派发**:`lan-248`
+
+#### ATT-S2-B3|自然语言调整编排 AttributionAdjustService(G3)
+- **目标文件**:`service/AttributionAdjustService.java`、`service/impl/AttributionAdjustServiceImpl.java`、`dto/AdjustResult.java`、`controller/AttributionController.java`(adjust/confirm-adjust)、`config/PromptConfig.java`(归因 Socratic prompt 注入)
+- **实现要点**:
+  1. 复用 `AIChatController` + `AiGateway` 对话,注入归因教练 prompt(七层 Socratic);
+  2. 解析 `[ATTR_DELTA]{...}` 标记 → 回填 `attribution_reports` 结构化字段 + intermediate_state;
+  3. 红线校验(RL02 命中 → 标记建议专业评估 + 转介信息露出 + 家长确认,E4 弱提示);
+  4. 若关联方案 status=GENERATED → 置 INVALIDATED(⑤ 失效重生成);
+  5. `confirm-adjust` 置 CONFIRMED。
+- **验收标准**:① 对话返回 answer + fieldDeltas;② 回填写库;③ 关联方案自动 INVALIDATED;④ RL02 命中输出 `redlineTerminate=true` 但流程不阻断(E4)。
+- **派发**:`lan-248`
+
+#### ATT-S2-B4|全家干预方案 7 章生成(G4/G5/G6 半)
+- **目标文件**:`service/AttributionPlanService.java`、`service/impl/AttributionPlanServiceImpl.java`、`dto/FamilyPlanVO.java`、`controller/AttributionController.java`(plan)、`config/DatabaseInitializer.java`(plan_type 已 A1 就绪)
+- **实现要点**:
+  1. 归因结论 → 产品映射(品牌级 Enagic/PHGG/益生菌株名,E7);
+  2. 分人×层级(P0/P1/日常/P2)×动作×产品×具体做法×复盘钩子 结构化;
+  3. 先共享基座后精准(第 4 章标注「先做」+ header.order 注明);
+  4. 红线前置(header.redlines + 第 6 章 RL01-RL10,A4 注入);
+  5. 人范围 E6:仅妈妈/女儿/儿子,爸爸跳过;
+  6. 存 `health_plans`(plan_type=family_attribution_plan)。
+- **验收标准**:① planJson 含 7 章 + header;② 每动作带 level/reviewHook;③ 产品名含品牌但 compliance 带 RL05「不宣称治疗」;④ 儿童动作带「医生定」无剂量数字;⑤ 不含爸爸成员。
+- **派发**:`lan-248`
+
+> **任务总数 = 8 个**(≤ 建议上限;阶段一 4 个无依赖、阶段二 4 个依赖阶段一)。每组任务文件分组按功能模块,未按单文件拆分。
+
+## 8. 共享知识(Shared Knowledge,跨任务约定)
+
+- **API 响应格式**:统一 `Result{code,data,message}`(`common/Result.java`);错误码 4001=付费墙/权限,4000=参数错。
+- **请求身份**:`@RequestAttribute("userId")` / `("familyId")` / `("currentMemberId")` / `("role")` 从 JWT 注入(与 `SurveyController`/`HealthPlanController` 一致)。
+- **迁移纪律**:所有 DDL 迁移**只经** `DatabaseInitializer.runMigrations()` 唯一入口,用 `ensureColumn`/`tableExists` 幂等;迁移编号**递增**(新=424,423 已占用);不同时用 `add -A` 卷入他会话未提交内容。
+- **合规红线(不可谈判)**:RL01-RL10 由规则层硬注入;AI 只产叙述;`app.attribution.enabled=false` 默认(E12 合规后置),真实用户放行 = 阶段四 D1。
+- **常模口径**:常模缺失 → 指标「待补」不猜值;DAN 常模优先复用 `cognitive_norms`/`health_norm_reference`;菌群 710 常模落 `attribution_norm_values`(可配置 JSON 导入)。
+- **日期**:ISO 8601 UTC 存储;`Date` 类型沿用现有 `DATETIME DEFAULT CURRENT_TIMESTAMP`。
+- **JSON 字段**:`questionsJson`/`planJson`/`report_json` 均为 TEXT 列,schema 走 JSON 约定(Jackson),不改表结构(除 A1/A3 明确新增列/表)。
+- **人范围(E6)**:成员角色经 `family_relationships` 确认;爸爸链外不生成方案。
+
+## 9. 任务依赖图(Task Dependency Graph)
+
+```mermaid
+graph TD
+    A1[ATT-S1-A1 plan_type迁移] --> B1[ATT-S2-B1 归因引擎]
+    A1 --> B4[ATT-S2-B4 7章方案]
+    A2[ATT-S1-A2 questionsJson+条件求值] --> B1
+    A2 --> B2[ATT-S2-B2 动态确认路由]
+    A2 --> B3[ATT-S2-B3 调整编排]
+    A3[ATT-S1-A3 常模表+导入] --> B1
+    A4[ATT-S1-A4 红线模板] --> B1
+    A4 --> B3
+    A4 --> B4
+    B1 --> B2
+    B1 --> B3
+    B1 --> B4
+    B2 --> B3
+    B3 --> B4
+```
+
+> 依赖说明:阶段一 A1-A4 无相互依赖(可并行);阶段二 B1 依赖 A1-A4;B2 依赖 A2+A1(归因中间态落库);B3 依赖 A2+A4+B1;B4 依赖 A1+A4+B1(+B3 结论确认)。
+
+---
+
+# 附录:阶段三/四 建议性边界(供后续参考,暂不设计)
+
+> 本设计只覆盖阶段一(数据地基)+ 阶段二(核心闭环 ③→⑤)。以下为阶段三/四**建议边界**,供主理人与后续设计参考,**非本次派发范围**。
+
+## 阶段三:任务化 + 前端(⑥ + ①-⑥ 编排)
+- **C1** 方案→任务扩展:`HealthPlanController.confirm` 增加 P0 强制不可跳过 + 任务携带复盘钩子/时间窗/优先级(复用 `planTasks`→`List<Task>`)。
+- **C2** 前端 6 步向导:`family-attribution/` 目录(basic-survey / confirm-survey / result / adjust / plan / tasks),复用 `SurveyTemplate` 渲染 + `ai/chat.vue` 对话 + `planJson` 展示;含角色确认步(E10)。
+- **C3** 数据源桥接:菌群/DAN/常模按家庭成员绑定到归因方案(`health_gut_flora`/`dan_assessment_results` → `attribution_reports`)。
+
+## 阶段四:合规 + 验证(真实用户放行唯一闸门)
+- **D1** 合规收口:① E4 高风险项复审(弱提示 + 转介信息露出 + 家长确认);② E7 品牌级展示广告法/医疗合规审查;③ 未成年人敏感数据保护 + 隐私声明。**真实用户放行 = D1 完成日**(E12)。
+- **D2** 端到端验证:mock 4 人家庭(含 1 父亲无 DAN、1 青春期女儿)跑通 ①→⑥。
+- **D3** 教师复核链可选接入(`pending-review/*`)。
+
+---
+
+*文档说明:本设计为增量设计(阶段一+二),只读调研产物,不含业务代码改动;已标注未检索到的数据源(菌群 710 常模结构化源、LangGraph 归因图端点)。*