一、密钥轮换(新增工具 + 操作手册) - 新增 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。
97 lines
8.6 KiB
Markdown
97 lines
8.6 KiB
Markdown
# 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)—— 「恢复了」≠「投顾线演示已就绪」 |
|