Jelajahi Sumber

docs: 记录HIS路由最终验证结果

WangKang 5 hari lalu
induk
melakukan
c79b63cfc6

+ 45 - 45
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/HIS多医院路由实施计划.md

@@ -3,7 +3,7 @@ doc_id: DEV-202606-006
 feature_id: FEAT-202606-005-saas-tenant-isolation
 type: dev-progress
 title: HIS 多医院动态路由实施计划
-status: reviewing
+status: implemented
 owner: 医梦研发团队
 created_at: 2026-06-27
 updated_at: 2026-06-27
@@ -43,12 +43,12 @@ Mockito、AssertJ、Maven。
 
 ## 范围门禁
 
-- [ ] 不修改现有 HTTP URL、方法、请求体和响应结构。
-- [ ] 不接受前端覆盖租户或项目。
-- [ ] 不在配置文件写入 HIS 密钥、Token、密码和私钥。
-- [ ] 不执行任何 DDL/DML;如实现发现 SQL 需求,只更新数据库 Runbook。
-- [ ] 不改动 Workflow、RAG、Agent、Card 已有隔离语义。
-- [ ] 严格模式不允许跨医院回退。
+- [x] 不修改现有 HTTP URL、方法、请求体和响应结构。
+- [x] 不接受前端覆盖租户或项目。
+- [x] 不在配置文件写入 HIS 密钥、Token、密码和私钥。
+- [x] 不执行任何 DDL/DML;如实现发现 SQL 需求,只更新数据库 Runbook。
+- [x] 不改动 Workflow、RAG、Agent、Card 已有隔离语义。
+- [x] 严格模式不允许跨医院回退。
 
 ## 文件结构
 
@@ -84,7 +84,7 @@ Mockito、AssertJ、Maven。
 - Test:
   `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/mcp/his/routing/HisClientRouterTest.java`
 
-- [ ] **Step 1: 写精确匹配红灯测试**
+- [x] **Step 1: 写精确匹配红灯测试**
 
 ```java
 @Test
@@ -131,7 +131,7 @@ private HisRoutingProperties properties(boolean strict, boolean fallbackEnabled,
 }
 ```
 
-- [ ] **Step 2: 运行测试确认失败**
+- [x] **Step 2: 运行测试确认失败**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
@@ -141,7 +141,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
 
 预期:因路由类不存在而编译失败。
 
-- [ ] **Step 3: 实现最小路由对象和 SPI**
+- [x] **Step 3: 实现最小路由对象和 SPI**
 
 ```java
 public record HisRouteContext(String tenantId, String projectId, String hospitalId) {
@@ -166,7 +166,7 @@ public interface HisClientProvider {
 
 `HisClientRouter.route` 必须按三个字段完整匹配,禁止单字段或通配符匹配。
 
-- [ ] **Step 4: 补严格模式和回退测试**
+- [x] **Step 4: 补严格模式和回退测试**
 
 ```java
 @Test
@@ -193,7 +193,7 @@ void compatibilityModeUsesLegacyClientWhenRouteIsMissing() {
 }
 ```
 
-- [ ] **Step 5: 实现严格模式、回退和配置校验**
+- [x] **Step 5: 实现严格模式、回退和配置校验**
 
 `HisClientRouter` 构造时建立不可变索引并校验:
 
@@ -213,11 +213,11 @@ HIS_PROVIDER_NOT_FOUND
 HIS_ROUTE_DUPLICATED
 ```
 
-- [ ] **Step 6: 运行路由测试确认通过**
+- [x] **Step 6: 运行路由测试确认通过**
 
 运行 Step 2 命令,预期全部通过。
 
-- [ ] **Step 7: 提交路由核心**
+- [x] **Step 7: 提交路由核心**
 
 ```bash
 git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
@@ -239,7 +239,7 @@ git commit -m "feat: 增加HIS多医院路由核心"
 - Test:
   `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/mcp/his/application/HisToolInvokeServiceTest.java`
 
-- [ ] **Step 1: 写请求上下文路由红灯测试**
+- [x] **Step 1: 写请求上下文路由红灯测试**
 
 ```java
 @Test
@@ -261,7 +261,7 @@ void invokesHospitalClientResolvedFromRequestScope() {
 }
 ```
 
-- [ ] **Step 2: 运行测试确认失败**
+- [x] **Step 2: 运行测试确认失败**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
@@ -271,7 +271,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
 
 预期:`HisToolInvokeService` 仍直接使用单一 `HisClient`。
 
-- [ ] **Step 3: 将 dispatch 改为显式客户端**
+- [x] **Step 3: 将 dispatch 改为显式客户端**
 
 ```java
 HisRouteContext routeContext = new HisRouteContext(
@@ -285,7 +285,7 @@ Map<String, Object> result = dispatch(
 
 `dispatch`、`markMockPaid` 和 `result` 接收本次路由得到的客户端,不使用共享可变上下文。
 
-- [ ] **Step 4: 修正 Mock 标记**
+- [x] **Step 4: 修正 Mock 标记**
 
 在 `HisClient` 增加:
 
@@ -298,11 +298,11 @@ default boolean isMock() {
 现有两个 Mock 客户端覆盖为 `true`。工具响应使用 `hisClient.isMock()`,真实 Provider
 不得被标记为 Mock。
 
-- [ ] **Step 5: 运行 MCP 应用测试**
+- [x] **Step 5: 运行 MCP 应用测试**
 
 运行 Step 2 命令,预期全部通过。
 
-- [ ] **Step 6: 提交标准入口路由**
+- [x] **Step 6: 提交标准入口路由**
 
 ```bash
 git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
@@ -318,7 +318,7 @@ git commit -m "feat: 接入MCP工具医院路由"
 - Test:
   `emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp/src/test/java/com/emoon/ai/mcp/application/McpToolServiceTest.java`
 
-- [ ] **Step 1: 写带上下文调用红灯测试**
+- [x] **Step 1: 写带上下文调用红灯测试**
 
 ```java
 @Test
@@ -333,7 +333,7 @@ void queryDepartmentsUsesScopedHospitalClient() {
 }
 ```
 
-- [ ] **Step 2: 运行测试确认失败**
+- [x] **Step 2: 运行测试确认失败**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
@@ -343,7 +343,7 @@ mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
 
 预期:不存在带 `HisRouteContext` 的重载。
 
-- [ ] **Step 3: 增加上下文重载并保留旧方法**
+- [x] **Step 3: 增加上下文重载并保留旧方法**
 
 以下方法增加末尾 `HisRouteContext context` 重载:
 
@@ -375,7 +375,7 @@ public List<HisDepartment> queryDepartments(HisRouteContext context) {
 
 支付、挂号响应中的 `mock` 使用实际路由客户端的 `isMock()`。
 
-- [ ] **Step 4: 验证旧方法仍使用兼容回退**
+- [x] **Step 4: 验证旧方法仍使用兼容回退**
 
 ```java
 @Test
@@ -385,11 +385,11 @@ void legacyMethodUsesCompatibilityFallback() {
 }
 ```
 
-- [ ] **Step 5: 运行测试确认通过**
+- [x] **Step 5: 运行测试确认通过**
 
 运行 Step 2 命令,预期全部通过。
 
-- [ ] **Step 6: 提交 Agent 工具重载**
+- [x] **Step 6: 提交 Agent 工具重载**
 
 ```bash
 git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp
@@ -415,7 +415,7 @@ git commit -m "feat: 补充HIS路由上下文重载"
 - Test:
   `emoon-openplatform/src/test/java/com/emoon/openplatform/service/impl/AgentChatApplicationServiceImplTest.java`
 
-- [ ] **Step 1: 写会话作用域查询红灯测试**
+- [x] **Step 1: 写会话作用域查询红灯测试**
 
 ```java
 @Test
@@ -430,7 +430,7 @@ void findByScopeRequiresConversationProjectAndTenant() {
 }
 ```
 
-- [ ] **Step 2: 实现 `findByScope`**
+- [x] **Step 2: 实现 `findByScope`**
 
 在 `AiConversationMapper` 新增:
 
@@ -450,7 +450,7 @@ AiConversation selectByConversationAndScope(
 
 `findByScope` 调用该方法。项目 ID 非数字、参数为空或记录不存在时返回空,不回退到仅会话查询。
 
-- [ ] **Step 3: 写卡片动作医院路由红灯测试**
+- [x] **Step 3: 写卡片动作医院路由红灯测试**
 
 ```java
 @Test
@@ -470,12 +470,12 @@ void scopedCardActionUsesHospitalFromTenantConversation() {
 }
 ```
 
-- [ ] **Step 4: 在 Orchestrator 中一次解析上下文**
+- [x] **Step 4: 在 Orchestrator 中一次解析上下文**
 
 每次 `execute` 开始时,通过作用域会话生成 `HisRouteContext`,后续所有 HIS 查询和写操作
 复用该不可变对象。会话不属于当前租户时,不得调用 HIS。
 
-- [ ] **Step 5: 对话降级查询使用命令医院上下文**
+- [x] **Step 5: 对话降级查询使用命令医院上下文**
 
 `AgentChatApplicationServiceImpl` 已持有可信项目和租户,并从会话创建链得到
 `command.hospitalId()`。`buildFallbackDepartmentData` 和
@@ -487,7 +487,7 @@ new HisRouteContext(tenantId, projectId, command.hospitalId())
 
 不修改 `AgentChatRequest`、Controller URL 或响应结构。
 
-- [ ] **Step 6: 运行 Agent 和 OpenPlatform 目标测试**
+- [x] **Step 6: 运行 Agent 和 OpenPlatform 目标测试**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent \
@@ -501,7 +501,7 @@ mvn -pl emoon-openplatform \
 
 预期全部通过。
 
-- [ ] **Step 7: 提交主链路上下文**
+- [x] **Step 7: 提交主链路上下文**
 
 ```bash
 git add emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent emoon-openplatform
@@ -523,7 +523,7 @@ git commit -m "feat: 贯通Agent与Card医院路由上下文"
 - Modify:
   `docs/initiatives/FEAT-202606-005-saas-tenant-isolation/专题索引.md`
 
-- [ ] **Step 1: 增加无真实医院数据的默认配置**
+- [x] **Step 1: 增加无真实医院数据的默认配置**
 
 ```yaml
 emoon:
@@ -536,7 +536,7 @@ emoon:
 
 不得提交 endpoint、credentialRef 实值或真实医院标识。
 
-- [ ] **Step 2: 更新交接文档**
+- [x] **Step 2: 更新交接文档**
 
 记录:
 
@@ -548,7 +548,7 @@ emoon:
 自动化测试结果
 ```
 
-- [ ] **Step 3: 审核 SQL 影响**
+- [x] **Step 3: 审核 SQL 影响**
 
 本方案预期无新增 DDL/DML。在数据库 Runbook 增加明确结论:
 
@@ -559,7 +559,7 @@ HIS 配置文件 + Provider SPI 不新增表,不需要执行 SQL。
 
 不得连接数据库或执行文档中的任何 SQL。
 
-- [ ] **Step 4: 检查接口影响**
+- [x] **Step 4: 检查接口影响**
 
 执行:
 
@@ -569,7 +569,7 @@ git diff -- docs/api docs/initiatives/FEAT-202606-001-unified-entry-client/对
 
 预期无外部接口契约差异。如出现差异,停止提交并先更新专题接口说明。
 
-- [ ] **Step 5: 提交配置和文档**
+- [x] **Step 5: 提交配置和文档**
 
 ```bash
 git add emoon-openplatform/src/main/resources/application.yml \
@@ -583,34 +583,34 @@ git commit -m "docs: 更新HIS多医院路由交接说明"
 
 - Modify only when verification reveals a defect directly caused by Tasks 1-5.
 
-- [ ] **Step 1: MCP 全量测试**
+- [x] **Step 1: MCP 全量测试**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-mcp \
   -DskipTests=false -Dprofiles.active= test
 ```
 
-- [ ] **Step 2: Agent 全量测试**
+- [x] **Step 2: Agent 全量测试**
 
 ```bash
 mvn -pl emoon-infra/emoon-modules/emoon-ai/emoon-ai-agent \
   -DskipTests=false -Dprofiles.active= test
 ```
 
-- [ ] **Step 3: Reactor 编译**
+- [x] **Step 3: Reactor 编译**
 
 ```bash
 mvn -pl emoon-openplatform -am -DskipTests compile
 ```
 
-- [ ] **Step 4: 架构测试**
+- [x] **Step 4: 架构测试**
 
 ```bash
 mvn -pl emoon-admin -DskipTests=false -Dprofiles.active= \
   -Dtest=AiPlatformArchitectureTest test
 ```
 
-- [ ] **Step 5: 已知失败复核**
+- [x] **Step 5: 已知失败复核**
 
 ```bash
 mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
@@ -619,7 +619,7 @@ mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
 必须分别记录本次新增失败和既有失败。不得把既有
 `TerminalMvpAcceptanceTest`、Weaviate 配置错误描述为本次通过。
 
-- [ ] **Step 6: 差异和安全审查**
+- [x] **Step 6: 差异和安全审查**
 
 检查:
 
@@ -632,7 +632,7 @@ mvn -pl emoon-openplatform -DskipTests=false -Dprofiles.active= test
 无 SQL 实际执行记录
 ```
 
-- [ ] **Step 7: 更新最终验证记录并提交**
+- [x] **Step 7: 更新最终验证记录并提交**
 
 ```bash
 git diff --check

+ 2 - 2
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/HIS多医院路由详细设计.md

@@ -116,8 +116,8 @@ emoon:
           provider: vendor-a
           endpoint: ${HIS_HOSPITAL_A_ENDPOINT:}
           credential-ref: ${HIS_HOSPITAL_A_CREDENTIAL_REF:}
-          connect-timeout-ms: 3000
-          read-timeout-ms: 10000
+          connect-timeout: 3s
+          read-timeout: 10s
 ```
 
 约束:

+ 13 - 3
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/SaaS化代码改造与下游交接说明.md

@@ -276,14 +276,24 @@ emoon:
 却配置 Surefire groups 而提前失败。本轮通过先安装当前依赖、再单独运行目标测试规避,
 该构建配置问题不属于本次 SaaS 代码改造。
 
-`emoon-openplatform` 全量测试共执行 56 个,失败 3 个、错误 3 个:
+最终验证(2026-06-27):
+
+| 命令 | 结果 |
+|---|---|
+| `emoon-ai-mcp test` | 64 个通过 |
+| `emoon-ai-agent test` | 78 个通过 |
+| `emoon-openplatform -am -DskipTests compile` | 49 个 reactor 模块通过 |
+| `AiPlatformArchitectureTest` | 1 个通过,新增违规 0 |
+| `emoon-openplatform test` | 57 个执行,3 个失败、3 个错误 |
+
+`emoon-openplatform` 全量测试失败集合与改造前已记录集合一致:
 
 - 3 个失败仍是前文记录的 `TerminalMvpAcceptanceTest` 降级引擎未创建卡片。
 - `IModelServiceImplTest` 因缺少 `weaviate.className` 配置,Spring 上下文加载失败。
 - `OpenAdminClientTest`、`RagServiceImplTest` 复用同一失败上下文而报错。
 
-本轮直接相关的 Controller、Agent、Card 测试均通过,但上述 6 项关闭前不能宣称
-OpenPlatform 全量回归通过。
+本轮新增的路由、MCP、Agent、Card 和对话降级测试均通过,没有新增失败;但上述
+6 项关闭前不能宣称 OpenPlatform 全量回归通过。
 
 ## 7. 尚未完成的代码工作
 

+ 1 - 1
docs/initiatives/FEAT-202606-005-saas-tenant-isolation/专题索引.md

@@ -39,7 +39,7 @@ tags:
 |---|---|---|---|
 | 需求录入 | [需求录入.md](需求录入.md) | approved | 记录目标、边界和交付方式 |
 | 详细设计 | [HIS多医院路由详细设计.md](HIS多医院路由详细设计.md) | reviewing | P0 多医院 HIS 路由、Provider SPI 和安全约束 |
-| 实施计划 | [HIS多医院路由实施计划.md](HIS多医院路由实施计划.md) | reviewing | P0 多医院 HIS 路由 TDD 实施步骤 |
+| 实施计划 | [HIS多医院路由实施计划.md](HIS多医院路由实施计划.md) | implemented | P0 多医院 HIS 路由 TDD 实施步骤 |
 | 开发进度 | [SaaS化代码改造与下游交接说明.md](SaaS化代码改造与下游交接说明.md) | reviewing | 代码改动、验证结果、遗留项和联调步骤 |
 | Runbook | [SaaS化数据库候选变更与执行清单.md](SaaS化数据库候选变更与执行清单.md) | reviewing | 数据库盘点、候选 SQL、执行顺序和校验 |