Ver Fonte

feat(kb.lowSidePatch): T1/L2-2 条件致病菌低侧判读补充(人工)作为统一知识库独立可查询子键

- 种子(resources/knowledge-base/统一知识库.json)新增顶层模块键,8 节纯增量 33 行,元数据未动
- UnifiedKnowledgeBaseService:MODULE_LOW_SIDE_PATCH + MODULE_KEYS 12→13 + getLowSideJudgmentPatch()
- HealthKnowledgeBaseController:POST /api/health/knowledge/unified/low-side-patch
- 验收测试 UnifiedKnowledgeBaseLowSidePatchTest 4 用例(21 断言镜像全部通过)+ API_REFERENCE 端点记录
- 验证:mvn compile BUILD SUCCESS;端到端 VERIFY PASS(21/21);cfc-web build 通过
- 附带 C 档 4 项探测结论报告(Adapter/KB加载/L4引擎/合规门禁挂载点)
Agnes Agent há 3 dias atrás
pai
commit
b70e24ec50

+ 11 - 1
cfc-backend/src/main/java/com/etotem/cfc/controller/HealthKnowledgeBaseController.java

@@ -161,7 +161,7 @@ public class HealthKnowledgeBaseController {
 
     // ==================== 统一知识库端点(knowledge_base_section 表,DB为源) ====================
 
-    @Operation(summary = "统一知识库-模块概览(全部12模块及条目数)")
+    @Operation(summary = "统一知识库-模块概览(全部13模块及条目数)")
     @PostMapping("/unified/overview")
     public Result<Map<String, Object>> unifiedOverview() {
         return Result.success(unifiedKnowledgeBaseService.getModuleOverview());
@@ -304,6 +304,16 @@ public class HealthKnowledgeBaseController {
         return Result.success(unifiedKnowledgeBaseService.getHealthScoreStandard());
     }
 
+    @Operation(summary = "统一知识库-低侧判读补丁块(条件致病菌低侧判读补充·人工:判读铁律/四机制/报告口径)")
+    @PostMapping("/unified/low-side-patch")
+    public Result<Map<String, Object>> unifiedLowSidePatch() {
+        Map<String, Object> data = unifiedKnowledgeBaseService.getLowSideJudgmentPatch();
+        if (data == null) {
+            return Result.error("模块不存在: " + UnifiedKnowledgeBaseService.MODULE_LOW_SIDE_PATCH);
+        }
+        return Result.success(data);
+    }
+
     @Operation(summary = "统一知识库-从classpath种子重新导入(force=true强制覆盖DB)")
     @PostMapping("/unified/import")
     public Result<String> unifiedImport(@RequestBody(required = false) Map<String, String> params) {

+ 18 - 3
cfc-backend/src/main/java/com/etotem/cfc/service/UnifiedKnowledgeBaseService.java

@@ -15,7 +15,7 @@ import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * 统一知识库服务 — 12 个顶层模块按 JSON 存储于 knowledge_base_section 表
+ * 统一知识库服务 — 13 个顶层模块按 JSON 存储于 knowledge_base_section 表
  *
  * 数据源:DB(knowledge_base_section)为查询源,classpath 种子文件兜底。
  * 启动时:加载 DB 全部模块;若 DB 为空则从 classpath 统一知识库.json 导入并落库。
@@ -38,11 +38,15 @@ public class UnifiedKnowledgeBaseService {
     /** classpath 种子文件(与 docs/参考资料/知识库/统一知识库.json 同源) */
     private static final String SEED_CLASSPATH = "/knowledge-base/统一知识库.json";
 
-    /** 12 个顶层模块键(顺序固定) */
+    /** 低侧判读补丁块模块键(L2-2/T1:条件致病菌低侧判读补充(人工),判读铁律/四机制/报告口径) */
+    public static final String MODULE_LOW_SIDE_PATCH = "条件致病菌低侧判读补充(人工)";
+
+    /** 13 个顶层模块键(顺序固定) */
     private static final List<String> MODULE_KEYS = Arrays.asList(
             "元数据", "食物营养库", "菌-疾病关联", "营养素参考", "营养素标准参考",
             "菌种综合信息", "菌种功能详细描述", "菌属功能库", "报告指标分级标准",
-            "菌属-食材映射", "菌属-食材映射_元数据", "健康评分标准");
+            "菌属-食材映射", "菌属-食材映射_元数据", "健康评分标准",
+            MODULE_LOW_SIDE_PATCH);
 
     /** 模块键 → 模块内容 Map(原始 JSON 结构) */
     private final Map<String, Map<String, Object>> sectionMap = new ConcurrentHashMap<>();
@@ -508,6 +512,17 @@ public class UnifiedKnowledgeBaseService {
         return sectionMap.keySet();
     }
 
+    /**
+     * 低侧判读补丁块(L2-2/T1):{@code 条件致病菌低侧判读补充(人工)}
+     * ——判读铁律(U 型双向) / 大肠杆菌偏低侧四机制 / 报告原文口径引用,
+     * 供 L4 归因引擎(AttributionAnalysisService 管线)与合规门禁(AttributionComplianceGate/G-1)直接取用。
+     *
+     * @return 补丁块完整内容(含 判读铁律/四机制/报告口径 等全部子节);模块未加载时返回 null
+     */
+    public Map<String, Object> getLowSideJudgmentPatch() {
+        return sectionMap.get(MODULE_LOW_SIDE_PATCH);
+    }
+
     /**
      * 获取全部模块摘要(键 + 条目数)
      */

+ 33 - 0
cfc-backend/src/main/resources/knowledge-base/统一知识库.json

@@ -9087,5 +9087,38 @@
     "肠道年龄": {
       "说明": "与实际年龄比较,反映肠道菌群的衰老/年轻程度"
     }
+  },
+  "条件致病菌低侧判读补充(人工)": {
+    "补丁说明": "2026-11-08 人工补丁:仅当知识库既有键缺字段/为空时填充,非空内容一律不覆盖。本键收录「条件致病菌偏低侧」判读口径(关联非因果层),归因与解读可直接引用。",
+    "判读铁律(U型双向)": {
+      "健康区间是范围而非单向": "同一种菌偏离人群参考区间两端(过高或过低)都可能关联异常;\"低就是好\"不成立。条件致病菌(如大肠杆菌)并非越少越好,报告从不标注其\"偏低超标\",因为人群参考下限即 0。",
+      "参考范围下限为 0": "大肠杆菌参考范围下限为 0(新版 0–9.3023,旧版 0–0.8466);ND 仅表示低于最低检出丰度,不是异常标签。",
+      "16S 粒度": "16S 只测到属/种,测不到菌株;\"条件致病\"是菌株×宿主情境的属性,不能凭属/种丰度断言\"这个人的大肠杆菌会致病\"。",
+      "偏低不推荐补菌": "暂无成熟证据支持\"缺大肠杆菌→补大肠杆菌\";Nissle 1917 等特定共存株属药品级干预,不构成常规生活建议,⛔ 禁止桥接推荐补剂/产品。",
+      "证据等级": "低侧机制多为体外/动物/人群关联研究,写入归因必标\"关联非因果\"。"
+    },
+    "大肠杆菌(Escherichia coli)偏低侧影响": {
+      "耗氧维持肠腔厌氧": "共生株消耗氧气,帮助维持肠腔厌氧环境,与产丁酸梭菌等协作,限制氧/硝酸盐外溢;丰度过低时厌氧群落保护力减弱(Cell Host Microbe 2019,PMID 30629913;PMC5448087)。",
+      "定植抵抗与生态位": "占位、铁载体竞争、黏蛋白降解利用等抑制致病菌过度定植;过低削弱定植屏障(MDPI Pathogens 2024 综述)。",
+      "维生素合成": "部分菌株参与维生素 K2/B 族合成,偏低时该来源贡献减少。",
+      "免疫训练": "低剂量 LPS 可经 IFN-γ 通路、IL-10 维持免疫稳态;极端缺乏的免疫后果仍在研究中(PMC5448087)。",
+      "综合提示": "上述机制建立在\"共生株/非产毒株\"前提上;实际该菌在人群中检出率 99.52%,是极常见共栖菌,偏低侧多为伴随性观察,不应单独下结论。"
+    },
+    "报告原文引用(仅结构性口径,个人实测值不入库)": {
+      "章节": "「肠道菌群重要菌种-大肠杆菌」",
+      "原文口径": "说明:正常菌属,机会致病菌,过多致病;参考范围下限为 0;99.52% 正常人有检出。",
+      "用法": "引用时保留\"正常菌属、机会致病菌、99.52% 正常人有检出、参考下限 0\",用于纠正\"条件致病菌=有害→越低越好\"的误读;不带入任何个人实测丰度。"
+    },
+    "菌属功能库分组矛盾说明": {
+      "[40] 埃希氏菌属": "旧库分组标\"有害菌属\",与功能说明\"正常菌属,条件致病菌,过多致病\"矛盾;正确归属为\"条件致病菌(正常共栖)\":健康人普遍携带(人群检出率 99.52%),致病与否取决于菌株与宿主情境。",
+      "[72] 大肠杆菌 / [73] 脆弱拟杆菌": "功能说明原为空,已按物种功能库补全;脆弱拟杆菌同为双刃剑(非产毒株诱导 Treg,产毒株降解 E-cadherin)。"
+    },
+    "菌种综合信息补充": {
+      "埃希氏菌属 Escherichia": "已新增\"偏低侧影响\":共生/非产毒株耗氧维持肠腔厌氧、占位定植抵抗、参与维生素K2/B族合成、低剂量LPS免疫训练;丰度过低时这些保护减弱。"
+    },
+    "艾德范思参考补充": {
+      "条件致病菌参考-大肠杆菌": "已新增\"健康定植说明\":健康人群共栖菌、人群中 99.52% 有检出、参考范围下限为 0;共生株有耗氧供厌氧、定植抵抗与屏障保护作用。\"检出\"不等于\"有害\",致病取决于特定菌株(致泻型/UPEC/AIEC/pks+)与宿主情境。"
+    },
+    "引用红线": "本补丁所有\"偏低侧\"表述均为人群/文献关联(关联非因果);禁写\"缺大肠杆菌→致病/需补充\",禁把调整建议写成处方。"
   }
 }

+ 124 - 0
cfc-backend/src/test/java/com/etotem/cfc/unit/UnifiedKnowledgeBaseLowSidePatchTest.java

@@ -0,0 +1,124 @@
+package com.etotem.cfc.unit;
+
+import com.etotem.cfc.mapper.KnowledgeBaseSectionMapper;
+import com.etotem.cfc.service.UnifiedKnowledgeBaseService;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Field;
+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.Mockito.mock;
+
+/**
+ * 低侧判读补丁块子键可查询验收(平台修改计划 T1 / L2-2,P0)。
+ *
+ * <p>验证 {@code 条件致病菌低侧判读补充(人工)} 作为统一知识库独立可查询子键:
+ * 判读铁律(U 型双向)/ 大肠杆菌偏低侧四机制 / 报告原文口径引用——供 L4 归因引擎
+ * 与合规门禁直接取用;KB 查询(getLowSideJudgmentPatch / getSection)须返回子键完整内容。
+ *
+ * <p>测试策略:mock 掉 DB(mapper 默认返回空/0,等效降级内存模式),
+ * 由 classpath 种子 {@code /knowledge-base/统一知识库.json} 加载后断言子键内容完整。
+ */
+class UnifiedKnowledgeBaseLowSidePatchTest {
+
+    private static final String MODULE = UnifiedKnowledgeBaseService.MODULE_LOW_SIDE_PATCH;
+    private static final String KEY_IRON_RULES = "判读铁律(U型双向)";
+    private static final String KEY_FOUR_MECHANISMS = "大肠杆菌(Escherichia coli)偏低侧影响";
+    private static final String KEY_REPORT_CALIBER = "报告原文引用(仅结构性口径,个人实测值不入库)";
+
+    @Test
+    void lowSidePatch_独立可查询_返回完整子键内容() throws Exception {
+        UnifiedKnowledgeBaseService service = buildServiceFromSeed();
+
+        Map<String, Object> patch = service.getLowSideJudgmentPatch();
+        assertNotNull(patch, "低侧判读补丁块子键必须可从统一知识库查询");
+        assertEquals(patch, service.getSection(MODULE), "getLowSideJudgmentPatch 与 getSection 子键返回一致");
+
+        // 8 个顶层节完整存在(补丁说明/判读铁律/四机制/报告口径/分组矛盾/菌种综合信息/艾德范思参考/引用红线)
+        assertEquals(8, patch.size(), "子键须含完整 8 节");
+        assertTrue(patch.containsKey("补丁说明"), "应含补丁说明");
+        assertTrue(patch.containsKey(KEY_IRON_RULES), "应含判读铁律");
+        assertTrue(patch.containsKey(KEY_FOUR_MECHANISMS), "应含大肠杆菌偏低侧四机制");
+        assertTrue(patch.containsKey(KEY_REPORT_CALIBER), "应含报告原文口径引用");
+        assertTrue(patch.containsKey("引用红线"), "应含引用红线");
+    }
+
+    @Test
+    void lowSidePatch_判读铁律_含U型双向与不推荐补菌() throws Exception {
+        UnifiedKnowledgeBaseService service = buildServiceFromSeed();
+        Map<String, Object> iron = castMap(service.getLowSideJudgmentPatch().get(KEY_IRON_RULES));
+
+        assertEquals(5, iron.size(), "判读铁律 5 条:U 型双向/参考下限0/16S粒度/不推荐补菌/证据等级");
+        assertTrue(iron.containsKey("健康区间是范围而非单向"), "U 型双向:低就是好不成立");
+        assertTrue(iron.containsKey("参考范围下限为 0"), "参考下限 0");
+        assertTrue(iron.containsKey("16S 粒度"), "16S 粒度声明");
+        assertTrue(iron.containsKey("偏低不推荐补菌"), "不推荐补菌");
+        assertTrue(iron.containsKey("证据等级"), "证据等级");
+        assertTrue(String.valueOf(iron.get("证据等级")).contains("关联非因果"), "证据等级标注关联非因果");
+    }
+
+    @Test
+    void lowSidePatch_四机制_含耗氧定植抵抗维生素免疫训练() throws Exception {
+        UnifiedKnowledgeBaseService service = buildServiceFromSeed();
+        Map<String, Object> mech = castMap(service.getLowSideJudgmentPatch().get(KEY_FOUR_MECHANISMS));
+
+        assertEquals(5, mech.size(), "四机制 + 综合提示:耗氧维持厌氧/定植抵抗/维生素合成/免疫训练/综合提示");
+        assertTrue(mech.containsKey("耗氧维持肠腔厌氧"), "机制① 耗氧维持肠腔厌氧");
+        assertTrue(mech.containsKey("定植抵抗与生态位"), "机制② 定植抵抗与生态位");
+        assertTrue(mech.containsKey("维生素合成"), "机制③ 维生素 K2/B 合成");
+        assertTrue(mech.containsKey("免疫训练"), "机制④ 低剂量 LPS 免疫训练");
+        assertTrue(mech.containsKey("综合提示"), "综合提示(共生株/非产毒株前提)");
+    }
+
+    @Test
+    void lowSidePatch_报告口径_仅结构性引用且禁因果() throws Exception {
+        UnifiedKnowledgeBaseService service = buildServiceFromSeed();
+        Map<String, Object> caliber = castMap(service.getLowSideJudgmentPatch().get(KEY_REPORT_CALIBER));
+
+        assertTrue(caliber.containsKey("章节"), "报告口径含章节定位");
+        assertTrue(caliber.containsKey("原文口径"), "报告口径含原文口径");
+        String usage = String.valueOf(caliber.get("用法"));
+        assertTrue(usage.contains("参考下限 0") && usage.contains("99.52%"), "用法保留参考下限0与人群检出率");
+        assertTrue(usage.contains("个人实测"), "报告口径明确不携带个人实测值");
+
+        String redline = String.valueOf(service.getLowSideJudgmentPatch().get("引用红线"));
+        assertTrue(redline.contains("关联非因果"), "引用红线标关联非因果");
+        assertTrue(redline.contains("缺大肠杆菌→致病/需补充"), "引用红线禁缺X桥接");
+        assertTrue(redline.contains("禁把调整建议写成处方"), "引用红线禁止处方化表述");
+    }
+
+    /** 构建 DB 降级(classpath 种子内存模式)的统一知识库服务 */
+    private static UnifiedKnowledgeBaseService buildServiceFromSeed() throws Exception {
+        UnifiedKnowledgeBaseService service = new UnifiedKnowledgeBaseService();
+        KnowledgeBaseSectionMapper mapper = mock(KnowledgeBaseSectionMapper.class); // 未打桩 → 空/0,走种子导入
+        inject(service, "knowledgeBaseSectionMapper", mapper);
+        inject(service, "objectMapper", new ObjectMapper());
+        service.load();
+        return service;
+    }
+
+    @SuppressWarnings("unchecked")
+    private static Map<String, Object> castMap(Object o) {
+        assertNotNull(o, "子节内容不能为空");
+        return (Map<String, Object>) o;
+    }
+
+    private static void inject(Object target, String fieldName, Object value) throws Exception {
+        Class<?> type = target.getClass();
+        while (type != null) {
+            try {
+                Field f = type.getDeclaredField(fieldName);
+                f.setAccessible(true);
+                f.set(target, value);
+                return;
+            } catch (NoSuchFieldException e) {
+                type = type.getSuperclass();
+            }
+        }
+        throw new NoSuchFieldException(fieldName);
+    }
+}

+ 1 - 0
docs/superpowers/api/API_REFERENCE.md

@@ -3024,6 +3024,7 @@ W0.2 双配置中心合并:`product_config` 已并入 `service_config`(唯
 | `POST /api/admin/knowledge-base/vector/documents`、`/stats`、`/sync`、`/delete-source`、`/update-document` | 向量库管理(`KnowledgeBaseVectorController`) |
 | `POST /api/admin/knowledge-tag/list`、`/save`、`/delete` | 知识标签字典(`KnowledgeTagController`) |
 | `POST /api/admin/knowledge-base/unified/overview`、`/section`、`/update`、`/reset` | 统一知识库(`AdminUnifiedKnowledgeController`) |
+| `POST /api/health/knowledge/unified/low-side-patch` | 低侧判读补丁块子键「条件致病菌低侧判读补充(人工)」(判读铁律/四机制/报告口径),供 L4 归因引擎与合规门禁直接取用(T1/L2-2) |
 
 #### 4.60.9 维度配置与维度注册(`DimensionAdminController` `/api/admin/dimension` + `DimensionConfigController` + `DimensionRegistryController`,SC-A-09/A-25)
 

+ 42 - 0
docs/tdd/orchestration/report-dev-2026-11-09-0708.md

@@ -0,0 +1,42 @@
+# 开发报告:条件致病菌低侧判读补充(人工)子键落地(T1 / L2-2)
+
+- 日期:2026-11-09
+- 任务:平台修改计划 T1(L2-2)——将「条件致病菌低侧判读补充(人工)」作为统一知识库独立可查询子键(判读铁律/四机制/报告口径),供 L4 归因引擎与合规门禁直接取用
+- 规格:`docs/superpowers/plans/2026-11-08-浠艾福平台程序修改计划.md`(T1/L2-2)+ `docs/参考资料/浠艾福-平台程序修改计划-v1.0.md`(C 档 4 项定义)
+- 分支:`cfclub`(直接在主分支工作,未新建分支)
+
+## 改动清单(仅本次任务文件,共 6 个)
+
+| 文件 | 改动 |
+|------|------|
+| `cfc-backend/src/main/resources/knowledge-base/统一知识库.json` | 平台种子新增顶层模块键「条件致病菌低侧判读补充(人工)」(8 节:补丁说明/判读铁律(U型双向)5条/大肠杆菌偏低侧5节/报告原文引用/菌属功能库分组矛盾说明/菌种综合信息补充/艾德范思参考补充/引用红线),33 行纯增量、元数据与其他模块未动 |
+| `cfc-backend/src/main/java/com/etotem/cfc/service/UnifiedKnowledgeBaseService.java` | 新增 `MODULE_LOW_SIDE_PATCH` 常量 + MODULE_KEYS 12→13 + `getLowSideJudgmentPatch()` 模块级查询方法(javadoc 12→13) |
+| `cfc-backend/src/main/java/com/etotem/cfc/controller/HealthKnowledgeBaseController.java` | 新端点 `POST /api/health/knowledge/unified/low-side-patch`(返回子键完整内容,模块缺失时报错);overview 注释 12→13 |
+| `cfc-backend/src/test/java/com/etotem/cfc/unit/UnifiedKnowledgeBaseLowSidePatchTest.java` | 验收测试 4 用例:独立可查询(与 getSection 一致+8节)/判读铁律(U型双向+不推荐补菌)/四机制(耗氧/定植抵抗/维生素/免疫训练)/报告口径(仅结构性+禁因果+禁处方化) |
+| `docs/superpowers/api/API_REFERENCE.md` | 追加端点记录一行 |
+| `docs/tdd/orchestration/report-dev-2026-11-09-0708.md` | 本报告 |
+
+## 验证结果
+
+| 验证 | 结果 |
+|------|------|
+| `mvn -f cfc-backend/pom.xml compile` | BUILD SUCCESS(`target` 默认目录,热增量路径) |
+| 端到端验证 `LowSidePatchVerifyMain`(隔离 `target-verify`,javac + java) | **VERIFY PASS**:21/21 断言通过;`getLowSideJudgmentPatch()` 返回 8 节完整内容(判读铁律 5 条/四机制+综合提示/报告口径/引用红线均命中);overview 模块数=13 |
+| 验收测试类单类编译(javac,隔离 test-classes) | 通过(无编译错误;全量 surefire 被并发的未跟踪坏测试文件 `ConditionalPathogenLowSideRuleTest.java` 阻塞,非本任务问题) |
+| `cfc-web` build(`npx vue-cli-service build`,绕过 prebuild 的 version/changelog 噪音) | Build complete(42s,EXIT=0,dist 为 gitignore) |
+
+说明:验证所用 `target-verify/classes/knowledge-base/统一知识库.json` 与 `src/main/resources` 版 SHA256 一致,验证权威。
+
+## C 档 4 项探测结论(写入记录,不阻塞派发)
+
+| C 档项 | 探测结论 |
+|--------|----------|
+| ① Adapter 形态 | 无统一 Python Adapter 接口;平台报告解析走 `ReportParserService` + `report_fingerprint` 表(`parse_method` 区分指纹脚本/LangGraph),外部 python 指纹脚本 `docs/scripts/fingerprint_engine.py`(+ `parsers/` 副本),LangGraph `cfc-langgraph`(生产 `ai.etotem.com.cn`) |
+| ② KB 加载方式 | `UnifiedKnowledgeBaseService`:classpath 种子 `resources/knowledge-base/统一知识库.json` + DB `knowledge_base_section`(查询源)+ 12 固定 `MODULE_KEYS`(本任务后 13)+ 自动回填/导入(幂等);本次采用"种子新增顶层模块键 = 子键名"方案,未引入整个「谷禾2026新版扩展知识」(属 T9 范围) |
+| ③ L4 引擎存在性 | 已存在确定性规则引擎 `service/attribution/*`(NormCompareEngine/FiveDimAttributionEngine/MainCauseChain/Falsification + AI 叙述规则兜底),非纯 prompt 驱动;本任务不改动 Attribution 管线(T3/T5 范围) |
+| ④ 合规门禁挂载点 | 已存在 `AttributionComplianceGate` + `AttributionLowSideRules`(G-1),挂载于 `AttributionAnalysisServiceImpl` L4 出结论前(enforceLowSide)与 L5 叙述后(scan),报告侧 `sections.complianceGate/redlines` 暴露;子键经 `getLowSideJudgmentPatch()` 可被该门禁/引擎直接取用 |
+
+## git 状态说明
+
+- 提交前已 fetch,origin/cfclub 最新为 `66cd7eba5`(本地 HEAD 落后 2、超前 0);本次以 `git reset --soft origin/cfclub` + `git commit -- <paths>` 部分提交,仅含上述 6 个文件,工作区他人未提交改动保持原样。
+- 任务范围 = 计划文档 T1(L2-2),不含 T3/T5/T9;未合并其他分支。