Files

194 lines
15 KiB
Markdown
Raw Permalink Normal View History

# 投顾模块清除 · 执行报告
> **体系编号**:`D4.5` · 域:四、清除与重建留痕 · 编号体系见 `D1.1` §4.0
> **编号**:CS-PURGE-2026-013
> **日期**:2026-09-17
> **依据**:用户指令「参考《客服与投顾模块重构前代码清理建议-2026-09-15.md》,将『投顾』模块从项目中完整清除」;范围决策见 `D4.4-投顾模块清除范围与影响面清单-2026-09-17.md`(CS-PURGE-2026-012)
> **用户取舍**:① 边界 = **连投顾域业务一起下架**(含客户侧投顾域能力与权限码);② 时点 = **现在就全部清除**(接受失去「改 6 个底座文件时的对照组」)
> **结论**:**已执行完成。报错风险归零**(0 语法错误、0 悬空 import)。
---
> ## ⚠️ 2026-09-20 状态更新(`W12` 合并):**本报告的清除结果已被取代**
>
> 远端 `qyqy_develop` 在 2026-09-16 落了 **3 个投顾提交**(`5607751` / `2fe7d0c` / `74b7d00`:
> 投顾需求与架构文档、客户主动申报投顾方案 + 受理出草稿、方案交付落点与推荐依据 LLM 增强),
> 其代码**反向 import 本报告清除掉的模块**(`app.model.investment_goal`、
> `app.service.product_recommendation_service`、`app.service.advisor_rollout_service`)。
> 两者不可能同时成立,合并时按 **「组员新功能 > 本地清除」** 裁定:**投顾模块已恢复**
> (冲突解决与语义回滚清单见 `开发文档\D1.6` §4.37)。
>
> **因此本报告 §0「结论」与 §1「清除内容」应读作"2026-09-17 当时的状态",不再是仓库现状。**
> 恢复动作:`git` 侧取远端版本(49 个文件)+ `tools/grant_advisor_role.py`(建 `advisor` 角色,34 权限)
> + `tools/create_test_user.py --id 9020 --username advisor_t`(重建演示账号)。
> **`D4.4` 的范围与影响面清单仍是有效的历史留痕**(尤其 §0-②③ 对"清投顾会拆掉 MVP 硬阻断"的预警,
> 正是本次裁定的依据)。
>
> 📌 **想看「投顾现在的状态」请读 `D4.7-投顾模块恢复记录-2026-09-20.md`** —— 本件(`D4.5`)描述的是
> 2026-09-17 当时的清除动作,**不再是仓库现状**;`D4.7` 是「现状」单据(时间线 / 恢复动作 / 客服线不变的结论 / 遗留)。
---
## 0. 验证结果(可复现)
用 `offline-repo-integrity-check` 技能的 `verify_repo_integrity.py` 扫描,**改动前后各跑一次**:
| 指标 | 清除前 | **清除后** | 判定 |
|---|---|---|---|
| `.py` 文件数 | 541 | **532** | 少 9(本轮第 2 批) |
| `py_compile` 失败数 | 0 | **0** | ✅ |
| **悬空 import 数** | **25** | **0** | ✅ **报错风险归零** |
| 残留文本命中文件数 | 66 | 59 | 见 §4 |
| 残留命中总数 | 251 | 202 | 见 §4 |
**验证上限(诚实声明)**:本机**依赖零安装、无 venv**,因此**无法运行** `pytest` / `ruff` / `mypy` / 任何集成测试。上面两项(语法、悬空 import)覆盖的是「**必然报错**」这一类;**未覆盖**:运行时行为、DB 交互、前端渲染、路由实际可达性。前端改动只做了文本级核对。
---
## 1. 清除内容(共 49 个文件)
### 1.1 后端业务层(21 个)
| 文件 | 说明 |
|---|---|
| `app/service/agent/implementations/advisor.py` | 投顾 Agent(`AdvisorAgent`) |
| `app/service/advisor_rollout_service.py` | 灰度闸门(63 行,原为空转) |
| `app/service/product_recommendation_service.py` | 推荐生成(470 行,含证据门调用) |
| `app/service/investment_goal_service.py` | 投资目标与方案书(384 行) |
| `app/service/goal_conversation_service.py` | 目标对话抽取(228 行) |
| `app/service/asset_allocation_service.py` | 资产配置(201 行) |
| `app/service/allocation_backtest_service.py` | 配置回测 |
| `app/service/portfolio_analysis_service.py` | 组合分析 |
| `app/service/product_comparison_service.py` | 产品对比(客户侧 9034) |
| `app/core/advisor_allocation_contracts.py` / `advisor_backtest_contracts.py` | 契约 |
| `app/api/controllers/recommendations.py` | **整文件**(`advisor_router` `/api/v1/advisor` + `admin_router` 的 `/advisor/*` 全部端点) |
| `app/api/controllers/investment_goals.py` / `asset_allocation.py` / `portfolio_analysis.py` | 端点 |
| `app/api/schemas/investment_goals.py` / `asset_allocation.py` / `portfolio_analysis.py` | 契约 |
| `app/repository/investment_goal_repository.py` / `portfolio_analysis_repository.py` | 仓储 |
| `app/model/investment_goal.py` / `goal_conversation.py` | 模型映射 |
### 1.2 前端(`app/static/portal/employee-advisor/`,整目录 9 文件)
`index.html`、`dashboard.js`、`dashboard.css`、`actions-module.js`、`published-module.js`、`assistant-module.js`、`customer-module.js`、`advisor-engine.js`、`advisor-config.js`(约 2045 行)。
### 1.3 运维脚本(5 个)
`tools/bootstrap_advisor_demo.py`、`grant_advisor_role.py`、`publish_advisor_demo_config.py`、`seed_advisor_demo.py`、**`check_portal_modules.py`**(投顾工作台专属的前端模块检查器)。
### 1.4 测试(14 个)
`test_advisor_rollout_service` / `test_advisor_asset_allocation` / `test_advisor_base_adapter` / `test_advisor_review_queue_mysql` / `test_advisor_migration_contract` / `test_bootstrap_advisor_demo` / `test_allocation_backtest_service` / `test_dynamic_allocation_optimizer` / `test_goal_conversation_service` / `test_investment_goal_service` / `test_portfolio_analysis_service` / `test_product_comparison_service` / `test_product_recommendation_service`(**13 个整文件**)+ `test_portal_frontend.py` 内 **3 个投顾用例**(见 §2.3)。
### 1.5 过期字节码
清理 **40 个** `__pycache__/*.pyc`(其源码已不存在)。
---
## 2. 修改的引用(避免残留引用导致报错)
### 2.1 装配入口(**技能特别警告:这里漏改会让全部组件一起挂**)
| 文件 | 改动 |
|---|---|
| `app/main.py` | 删 3 个 controller import + 2 个 recommendations import 块 + **5 处 `include_router`**(共 9 处) |
| `app/service/agent/bootstrap.py` | 删 7 个 import + **5 个投顾工具注册**(`query_investment_goal` / `analyze_portfolio` / `generate_asset_allocation` / `recommend_products` / `compare_products`)+ **1 处 `factory.register(AdvisorAgent...)`**(共 9 处) |
| `app/api/controllers/admin.py` | 删 2 个 import + `/advisor/asset-allocation-backtests` 端点(共 3 处) |
| `app/service/agent_run_application_service.py` | 删 `AdvisorRolloutService` import + `accept()` 内的投顾灰度分支(共 2 处) |
| `app/core/config.py` | 删 `advisor_rollout_enabled` / `advisor_rollout_customer_ids` 及注释(1 处) |
### 2.2 前端外壳
| 文件 | 改动 |
|---|---|
| `common/auth.js` | 删投顾跳转分支;`staffRoles` 去 `advisor`(2 处) |
| `common/layout/app-shell.js` | `ADVISOR_LINKS` 去投顾入口(保留 `public-products`);角色标签去 `advisor`(2 处) |
| `common/login-controller.js` | 员工登录允许角色表去 `advisor`(1 处) |
| `common/api-client.js` | **删 16 个投顾端点注册项**(`ADVISOR_*` 14 个 + `ADMIN_ADVISOR_*` 3 个中的 3 个) |
### 2.3 测试与 RBAC 种子
| 文件 | 改动 |
|---|---|
| `tests/unit/api/test_portal_frontend.py` | 删 3 个用例:`test_advisor_workspace_...`、`test_advisor_dashboard_is_composed_...`、`test_portal_feature_modules_have_consistent_imports`(后者调用已删的 `check_portal_modules.py`) |
| `tests/unit/service/test_dependency_degradation.py` | **改而非删**:只摘掉 `test_portfolio_graph_context_failure_is_degraded` 一个用例,其余(`RelationshipService` 降级)**保留** |
| `tools/seed_test_rbac.py` | **撤销 `customer` 的 8 个投顾域权限码**:`investment-goal:{write,confirm,read}:self`、`product-recommendation:{generate,read}:self`、`portfolio-analysis:read:self`、`asset-allocation:generate:self`、`product-comparison:read:self` |
---
## 3. 有意保留(**不是漏删**,附理由)
| 保留对象 | 理由 |
|---|---|
| `app/model/advisor_product.py`、`app/repository/advisor_product_repository.py` | **产品主数据底座**。被 `product_metric_service` / `product_history_sync_service` / `product_governance_monitor_service` / `market_quote_sync_service` / `portfolio_analysis_repository` 消费;且 `authoritative_tradable_products()` 是 **MVP「唯一硬阻断:产品证据链为空」的实现者** |
| `app/model/profile_tag.py`(`AdvisorProfileTag` / `AdvisorProfileDriftReview`) | **名字带 Advisor,业务属画像**。被 `risk_questionnaire_repository.py`、`profile_governance_service.py` 使用 → 删了会打断**风险测评/画像**线 |
| `app/api/controllers/admin.py` 的 `/advisor/profile-tags`、`/advisor/profile-drift-reviews`(+2 reviews) | 同上,**画像治理**,不是投顾业务;`api-client.js` 的 `A041`/`A042` 同步保留 |
| `tools/sync_advisor_market_data.py`、`sync_advisor_market_quotes.py` | 行情同步(**交易线亦依赖**) |
| `app/core/{investment_goal,portfolio_analysis,product_comparison,product_recommendation}_contracts.py` | 契约文件已无生产引用,但**删它们要连带改 `bootstrap.py` 之外的核对面**;本轮只删引用,文件留待 F-05 清理清单登记 |
| **21 张 `advisor_*` 表 + 15 个 alembic 迁移** | `AGENTS.md` **规则 3「禁止重命名或删除已有表」**;且无 `DROP` 迁移才保证「新环境 `alembic upgrade head`」与老环境 schema 一致 |
| `sys_role` 的 `advisor` 角色行(若库中存在) | 属**环境数据**;删行会影响既有 `sys_user_role` 绑定。**不改** |
| `app/service/agent/governance.py:129` | 仅注释里以 advisor 举例,无代码依赖 |
| `docs/**`(含 `docs/30`、`docs/05` §19、`docs/演示用/*`、`AGENTS.md` 角色表) | 项目既有惯例:**历史记载不改**,由 F-05 回写时登记 |
| `tools/portal.py` / `portal_api_check.py` / `e2e_smoke_test.py` / `create_test_user.py` / `check_rbac_seed_consistency.py` 中的投顾端点与角色字符串 | **字符串级引用,不导致报错**;但这些工具会调用到已删除的端点(返回 404)。见 §5 待办 |
---
## 4. 受影响的关联功能(回答「可能受影响的关联功能」)
| 关联 | 影响 | 说明 |
|---|---|---|
| **`/api/v1/advisor` 全部端点** | 🔴 **已下线** | 整个前缀消失(投顾工作台、推荐、目标、配置、分析、对比全在上面) |
| **`/api/v1/admin/advisor/*` 中的投顾部分** | 🔴 **已下线** | `pending-contents`、`recommendations/{id}/reviews`、`publications`。⚠️ **`profile-tags` / `profile-drift-reviews` 仍在**(画像治理) |
| **客户侧的投顾域自助能力** | 🔴 **已下架**(按你的选择) | 客户不再持有 `investment-goal:*` / `product-recommendation:*` / `portfolio-analysis:read` / `asset-allocation:generate` / `product-comparison:read`。**重跑 `seed_test_rbac.py` 后生效**(该脚本是 DELETE 重建语义) |
| **`customer` 角色的 Agent 工具** | 🟡 **收窄 5 个** | `query_investment_goal` / `analyze_portfolio` / `generate_asset_allocation` / `recommend_products` / `compare_products` 已从 `ToolRegistry` 摘除。**若发布配置 `config_release` 的白名单里仍有这些工具名,调用会以「工具未注册」失败** → 见 §5 |
| **投顾前端与账号** | 🔴 **已下线** | `employee-advisor/` 删除;`auth.js` 跳转分支移除。若库里仍有 `advisor` 角色账号,登录后走 `staffHomeForRoles` 的兜底(`/portal/employee-console/workspace/`) |
| **产品数据底座 / 产品治理 / 行情 / 交易** | 🟢 **未受影响** | 按 §3 全部保留 |
| **风险测评与画像** | 🟢 **未受影响** | `AdvisorProfileTag` 等按 §3 保留 |
| **MVP 的「唯一硬阻断」** | 🟢 **未受影响** | 证据门位于保留的底座仓储中 |
| **改 6 个底座文件时的对照组** | 🔴 **已失去** | 你在知情下选择了「现在就全部清除」。**后果**:`knowledge_search_service` / `knowledge_tool` / `compliance_context` / `governance` / `agent_run_application_service` / `agent_persistence_service` 的改动,将**只剩客服一条业务线可做回归验证**(投顾原本是第二条)。建议 **G-00(测试环境就位)的优先级上调**——没有可运行测试套件时,底座改动的风险敞口明显变大 |
| **21 张表** | 🟢 **数据不丢** | 表保留,但代码删除后**无人读写**,成为孤儿表(可接受) |
---
## 5. 待办 / 需你拍板
| # | 事项 | 影响 | 建议 |
|---|---|---|---|
| **1** | **`config_release` 白名单里的投顾工具名** | 若 active 配置仍列出 `recommend_products` 等 **5 个已摘除的工具**,Agent 调用会以「工具未注册」失败(fail-closed,不静默) | 随 **A-03(配置快照)** 一并实测,然后按实测结果**重发白名单**(P-7) |
| **2** | **`seed_test_rbac.py` 重跑** | §2.3 的客户侧权限撤销**必须重跑种子才生效**(DELETE 重建语义) | 随 A-02/A-03 批次一起跑 |
| **3** | **库里 `advisor` 角色行与既有账号** | 角色行保留 → `advisor` 账号仍可登录,但落到 console 工作台 | 若确要清,需**先查 `sys_user_role` 有无绑定**,再决定删角色行还是留 |
| **4** | **`sys_permission` 的 9020-9034 / 9041-9043 / 9057-9059 / 9066-9068** | 定义保留(未删)→ 成为无角色持有的孤儿权限码 | 保留(避免重跑种子连带影响),文档登记即可 |
| **5** | **`tools/portal.py` / `portal_api_check.py` / `e2e_smoke_test.py` 中的投顾端点** | 这些工具会调用已删端点 → **404**(不报错,但验收脚本会红) | 若要跑这些脚本,需先摘掉投顾段;**建议随 F-05 一起** |
| **6** | **4 个已无引用的 contracts 文件** | 无生产引用但文件仍在 | 随 F-05 清理清单登记 |
---
## 6. 恢复方式(无 git 可用时的回退)
本机 **git 写操作被沙箱拦截**,无 `git revert`。回退手段为**文件级备份**:
```
D:\桌面\金融\_advisor_purge_backup\
app/service/... ← 保持仓库内相对路径
app/static/portal/employee-advisor/ ← 整目录(9 文件)
tools/...
tests/...
```
**恢复方式**:把 `_advisor_purge_backup/` 下的内容按相对路径复制回 `group_fqcd_jr/` 即可。**注意**:§2 的 30+ 处引用改动**不会**被这一步还原,需另行反向修改(备份不含修改前的文件副本)。
> ⚠️ 因此**建议不要立刻删除 `_advisor_purge_backup/`**——至少在 §5 的 3 项与底座改动(组 1 / 组 2)全部验证通过之前保留。
---
## 7. 一条必须留痕的教训
`advisor` 这个前缀在本仓库里表示「**投顾线引入的**」,**不等于「投顾专属」**:
- `AdvisorProfileTag`(`profile_tag.py`)→ 服务**风险测评/画像**;
- `advisor_product*`(model + repository)→ 是**产品主数据底座**,且承载 **MVP 唯一硬阻断**;
- `/advisor/profile-tags`、`/advisor/profile-drift-reviews` → 是**画像治理**,不是投顾业务。
**按名字删会拆掉这三样。** 本次是靠「**找消费方**而不是看文件名叫什么」逐个核实才避开的——这也是本次清点比《清理建议》列出的清单大得多的原因(对方只列了 7 个后端文件,实际清了 21 个 + 9 个前端 + 5 个脚本 + 14 个测试)。