Files
group_fqcd_jr/开发文档/D4.7-投顾模块恢复记录-2026-09-20.md
T
张胜宇 c91bbcbdc1 feat(ops)+docs: 密钥轮换工具 + 两份文档目录审计收口(D1.1 §23 / D2.1 v6.26)
一、密钥轮换(新增工具 + 操作手册)
- 新增 tools/rotate_api_keys.py:--check 体检 + 交互式轮换;getpass 不回显、
  自动备份 .env.bak-<时间戳>(已被 ignore 命中)、校验不过整体不写入、
  三个 Qwen 变量写同一值 / 两个 DeepSeek 变量写同一值。
  实测 --check:Qwen 三变量同值且非空、DeepSeek 两变量同值且非空。
- 新增 开发文档/D3.8-模型密钥轮换与凭据安全操作手册-2026-09-20.md(CS-OPS-2026-023):
  .env 5 个变量与读取方取证、五步流程、3 个坑、复核清单、回退方式、能力边界。
- 口径确认:model_endpoint_config.secret_ref 存变量名 ⇒ 轮换只改 .env,不动 DB;
  但必须重启 API + Worker。

二、门禁修复:docs/ 编号撞车
- tools/check_authoritative_docs.py(D3.4 N-14 登记的验收命令集之一)实测 FAIL:
  我方 docs/46 docs/47(2026-09-20 建)与投顾组 docs/46-投顾Agent需求文档.md
  docs/47-投顾Agent功能架构文档.md(2026-09-16 建)同号。
- 按「后到者让位」改名:docs/48-可改文件白名单.md / docs/49-底座会签申请单-2026-09-19.md,
  同步 8 处引用。修复后:checked 54 documents, no number collision,exit 0。

三、前端品牌残留(W12 合并静默回退)
- employee-advisor/dashboard/index.html 与 customer/advisor-plans/index.html 的
  <title> 仍是 南方财富(投顾组分支带回)→ 按 DEC-27 改为 南方基金。
- HTTP 实测两页标题已正确;全仓 app/ 复查 南方财富 = 0。

四、文档口径校准(12 处事实漂移)
- D1.1:D2.1 版本 v5.3 → v6.26(§4.0 / §4.1 / §1 / §2 四处长期错误);
  §8 四行遗留项闭合(D-5 / D-6 / D-7 / 仓库副本同步)+ 新增 §22 §23 留痕;
  §10.2「本区不在任何 git 仓库内」更正为已入库;新增两编号 ⇒ 计数 56 → 58 全量同步。
- D2.2:顶栏徽标 v2.4 与元数据 v2.5 自相矛盾 → 统一;「投顾已清除」→ 状态更新
  (模块 2026-09-20 已恢复,但客服范围裁定 §1.7 / RK-10 不变)。
- D2.3:徽标 v1.0 · 7 批次 51 项 → v1.1 · 8 批次 57 项;投顾清除后果 + §7.1 头号风险
  + 风险表 + 不触碰行全部加恢复口径。
- D2.4:v1.3 变更说明 ⑦ / §1.4 Out of scope / Q-09 加投顾恢复口径。
- D2.5:advisor_t 自相矛盾口径改写为账号表一行 + 口径更正;五项自检首选改为
  一键脚本 启动演示.bat / demo.ps1;补 D3.8 与未发布 advisor:* 白名单登记。
- D2.6:门禁数字 1856/2 → 1909/3 skipped、ruff 19 → 20、补 portal_api_check 行;
  §10 两项已闭环(密钥轮换已工具化、A-10 组 3/4 已补签);头部加 W12/W13 状态更新。
- D4.5:顶部状态更新补指向 D4.7。
- 新增 开发文档/D4.7-投顾模块恢复记录-2026-09-20.md(CS-PURGE-2026-014):
  时间线、8 项恢复动作、客服线不变的结论、DEC-19 理由更正、遗留 1 项、失误登记。
- _consistency.py(维护侧):§三 改为「投顾状态口径检查」,合法语境扩为
  清除史 / 恢复史 / 不属本 Agent 范围。

五、回归实测(全绿)
- pytest -q:1909 passed / 3 skipped / 0 failed
- ruff check app tools tests:20(与 W12 持平,未引入新债)
- mypy app:2(= 既有基线)
- tools/check_authoritative_docs.py:54 文档无编号冲突(exit 0)
- tools/e2e_smoke_test.py --read-only:31/31
- tools/portal_api_check.py:40 项 通过 35 / 失败 0 / 跳过 5
- _eval_harness/http_probe.py:11/11 succeeded
- _consistency.py:GATE PASS
- demo.ps1 -SkipStart -NoBrowser:五项自检全过、退出码 0
- 权威副本 ↔ 仓库:逐字节一致(客服agent 24 / 开发文档 52)

六、未做(如实登记)
- 投顾 config_release 工具白名单(advisor:*)仍未发布 ⇒ 投顾 Agent 工具调用 fail closed
  (实测 active_agent_tools 仅 customer_service:* 4 项 + risk:* 4 项)。与客服线无关;
  要演投顾线先跑 tools/publish_advisor_demo_config.py --apply。
- 两把 key 的实际轮换需你在控制台建新 key(无法代做),流程见 D3.8。
2026-09-20 15:27:07 +08:00

97 lines
8.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# D4.7 · 投顾模块恢复记录
> **体系编号**:`D4.7` · 域:四、清除与重建留痕 · 编号体系见 `D1.1` §4.0
> **编号**:CS-PURGE-2026-014 | **版本**:v1.0 | **日期**:2026-09-20 | **状态**:**现行(本件描述仓库现状;`D4.4`/`D4.5` 降级为历史留痕)**
> **性质**:**状态单据(现状)**。回答「投顾模块到底删了没有、现在还在不在、怎么恢复的」—— 这是答辩现场**必被追问**的一点(因为 `D4.4`/`D4.5` 两份文档的标题与结论都写着「清除」)。
> **时间线证据**:会话留痕 `D1.6` §4.37;合并提交 `e5b4d02`;远端 3 个投顾提交 `5607751` / `2fe7d0c` / `74b7d00`。
> **配套**:范围与影响面 `D4.4`(仍是有效的历史留痕);清除执行报告 `D4.5`(顶部已加状态更新);纪律凭据 `docs\48` / `docs\49`。
---
## 0. 一句话结论(现状)
**投顾模块在仓库中「有效存在」** —— 2026-09-17 曾按 `D4.4`/`D4.5` 整体清除(94 个文件),2026-09-20 合并远端组员 3 个投顾提交时,因其代码**反向依赖被删除的模块**,裁定「**组员新功能 > 本地清除**」⇒ **恢复**。
| 问题 | 答案 |
|---|---|
| 投顾代码还在吗? | **在**(`app\service\*.py` 投顾服务、`app\api\controllers\recommendations.py`、`employee-advisor/` 前端等,取远端版本) |
| `D4.4` / `D4.5` 还有效吗? | **作为历史留痕有效**;作为「仓库现状」**已失效**(`D4.5` 顶部已加状态更新指向本件) |
| 客服 Agent 受影响吗? | **不受影响**。客服的范围裁定(`D2.2` §1.7 两条业务线 / `RK-10` 不越界实现投顾)**原样成立** |
| 恢复有遗留吗? | **有 1 项**:投顾的 `config_release` 工具白名单(`advisor:*`)**尚未发布** ⇒ 投顾 Agent 工具调用 fail closed(见 §5) |
---
## 1. 时间线
| 时间 | 事件 | 依据 |
|---|---|---|
| 2026-09-16 | 组员在 `qyqy_develop` 落 **3 个投顾提交**(需求与架构文档 / 客户主动申报 + 受理出草稿 / 方案交付落点与 LLM 增强) | `5607751` `2fe7d0c` `74b7d00` |
| 2026-09-17 | 本线按 `D4.4`/`D4.5` **整体清除投顾**(94 文件删除) | `D4.5` |
| 2026-09-20 | 推送被拒(**non-fast-forward**):`fetch` 后发现远端领先 3 个提交,且新代码 `import` 了已删模块 | `D1.6` §4.37 一 |
| 2026-09-20 | **裁定恢复投顾**:合并提交 `e5b4d02`(parents = `5d0becb` + `74b7d00`) | `D1.6` §4.37 二 / 九 |
| 2026-09-20 | 补数据库夹具 + 修 1 条「远端本身就是红的」断言 ⇒ 全量回归 **1909 passed / 3 skipped / 0 failed** | `D1.6` §4.37 六/七/八 |
**为什么不能两全**:`D4.4` 在清除**之前**就预警过两条风险 —— ① 按名字清投顾会**同时删掉产品数据底座与 MVP 的硬阻断实现**;② 会**失去「改 6 个底座文件时的对照组」**。组员在**同一个模块**上落了新功能 ⇒ 清除与新功能**不可能同时成立**。裁定取「组员新功能」,依据正是 `D4.4` 自己写下的预警。
---
## 2. 恢复动作清单(做了什么)
| # | 动作 | 说明 |
|---|---|---|
| 1 | **取远端版本** | 8 处 `modify/delete` 冲突全部**取远端**:`recommendations.py`、`product_recommendation_service.py`、`employee-advisor/dashboard/` 4 文件、`tools/check_portal_modules.py`、`tools/grant_advisor_role.py` |
| 2 | **取远端版本(内容冲突 3 处)** | `app/main.py`(投顾 import + `include_router`)、`common/api-client.js`(投顾端点表)、`tests/unit/api/test_portal_frontend.py`(4 条投顾前端契约) |
| 3 | **定点保留我方改动 1 处** | `app/main.py` 解除冲突的同时,**保留**本轮「移除 `/customer-service-test` 挂载」(联调页与用例已随重构作废) |
| 4 | **语义回滚(4 处)** | 因「取消清除」而必须回滚:`app/service/agent/bootstrap.py`(`AdvisorAgent` + 5 个投顾工具注册)、`app/core/config.py`(`advisor_rollout_*`)、`app/static/portal/common/layout/app-shell.js`(投顾工作台导航 + `advisor` 角色名)、`tools/seed_test_rbac.py`(admin 全量元组授权模型) |
| 5 | **叠加我方修复** | `app/static/portal/common/api-client.js`:以远端为基准,**重新叠加**本轮的「访客令牌 `Authorization` 优先」修复(否则该修复被合并静默吃掉) |
| 6 | **数据库夹具同步** | `tools/grant_advisor_role.py` → 新建 `advisor` 角色(实测 **34 项**权限);`tools/create_test_user.py --id 9020 --username advisor_t --role advisor --password abc12345` → 重建演示账号。补夹具前 3 条投顾集成用例全红,补后 **2 passed / 1 skipped** |
| 7 | **修一条「远端本身就是红的」断言** | `tests/unit/test_advisor_migration_contract.py` 把 alembic 末端钉死在 `20260914_baseline_auto_increment`,而远端新增 `20260916_advisor_service_request` ⇒ 该断言在远端 `qyqy_develop` 上**本身就失败**(不是合并引入的)。已更新到新末端并补注释 |
| 8 | **顺带修掉一类假红** | `tools/portal_api_check.py` 新增 `empty_collection_note()`:被渲染的集合为空时判 **`SKIP`(附原因)** 而非 `FAIL` ——「没有行」与「字段没带」是两回事。改后 40 项:**通过 35 / 失败 0 / 跳过 5** |
> 🔑 **未用 `--force`**:强推会毁掉组员 3 个提交。
---
## 3. 恢复后,「客服线」的哪些结论**不变**
| 结论 | 状态 |
|---|---|
| 客服 Agent 范围 = **两条业务线**(游客线 + 客服线),不承接投顾能力 | **不变**(`D2.2` §1.7 / `RK-10`) |
| 长期记忆召回 = **关**、画像 = 客户侧字段级只读 | **不变**(`DEC-19`;理由见 §4) |
| 客服知识库三集合 / 三档可见性 / 分区隔离 | **不变**(`D2.4`;投顾知识**不进**客服知识库) |
| 五出口决策链 + 安全不变量 `INV-1`~`INV-5` | **不变**(`D3.6`) |
| 46 条金标与全部指标(转人工率 10.9% / 出口 100% / 事实 100%) | **不变**(`D3.7` / `D2.6`) |
| 全量门禁 | **更强了**:对照组回归 ⇒ 1909 passed / 3 skipped / 0 failed |
---
## 4. 一处必须更正的**理由表述**(不是结论)
`DEC-19`(长期记忆召回 = 关)的**结论不变**,但**理由**里有一条曾经写着「收益方(投顾)已整体清除」—— 该理由**随恢复失效**。
**正确理由(继续成立、且更硬)**:
1. **客服 Agent 不产生长期记忆**:`app/worker/runtime.py` 的 `NO_LONG_TERM_MEMORY_AGENT_TYPES` 显式含 `customer_service`(`W7` 发现并修回的真实合规回归 `D-10`);
2. **注入生成上下文与证据约束生成直接冲突**:`E4` 的输入必须是**证据包**(`INV-2`),把长期记忆注入进去会让答案出现证据包外的内容;
3. **`PROFILE_CANDIDATE_AGENT_TYPES` 为空集是裁定落地**,不是「重构期临时状态」—— 要重开必须**先改口径**,而不是往集合里加 `agent_type`。
---
## 5. 遗留(**1 项,与客服线无关**)
| # | 遗留 | 说明 | 怎么解 |
|---|---|---|---|
| 1 | 投顾 `config_release` 工具白名单(`advisor:*`)**未发布** | 2026-09-20 连库实测 `active_agent_tools` 只有 `customer_service:*` 与 `risk:*` 共 8 项 ⇒ 投顾 Agent 的工具调用**正确 fail closed**(代码在、白名单不在) | 要演投顾线时跑 `tools/publish_advisor_demo_config.py --apply`(该脚本由组员提交 `9c6f839` 提供)。**客服线完全不受影响** |
| 2 | 投顾演示数据未灌 | `AD011` / `A047` 需要带 `source_url` + `document_sha256` 的适当性证据行,披露文件不在仓库;`tools/seed_advisor_demo.py` 明令**不编证据**(fail closed) | 空集 `SKIP`,不是缺陷(`D1.6` §4.37 十-2) |
---
## 6. 如实登记(含我的失误)
| # | 事项 | 说明 |
|---|---|---|
| 1 | 🔴 **清理临时产物时误删 `_advisor_db_backup.sql`** | 属我的操作失误。缓解:真正的代码级备份 `_advisor_purge_backup/`(**51 文件**)与 `_cs_purge_backup/`(34 文件)**完好**;且该库投顾表本为空 |
| 2 | **本件是「补记」,不是当时的记录** | 恢复发生在 2026-09-20(`W12`),当时的留痕在 `D1.6` §4.37 与 `D4.5` 顶部状态更新。本件是 `W13` 文档审计时**补的上游单据** —— 补记的理由是:`D4.4`/`D4.5` 两份文档标题都叫「清除」,未来检索「投顾 恢复」会**查不到** |
| 3 | 「恢复」的**边界**需明确 | 恢复的是**模块代码 + 数据库夹具**;投顾的**演示数据/工具白名单**仍是空的(§5)—— 「恢复了」≠「投顾线演示已就绪」 |