docs: 阶段一 AL-01~08 完成落账 + 文档同步——六件套反映换核完成(406 绿基线 425→406/SUIT-001~008 退役改 core_ro.check_suitability C×R 矩阵+JR-AST/FM 契约/risk_suitability_log 21 列/种子 33 客户 14 产品/risk-m1 已补打指向 3c07de6);TODO 进行中改阶段一验收门(唯一卡点=用户目视确认)+AL-09/10/11 待办;ITERATION 追加阶段一完成行;REQUIREMENTS R-02 换核标注;开发计划 M1 改已补打;入库存档《修改报告-对齐main基准.md》(阶段一执行依据)与《实现方案-风控追加需求v1.1-C4C6.md》(阶段二编码依据);吸收上会话遗留同步(分支口径 risk-control-agent/PRD v1.1 冻结标注/T-21 评审闭环/T-03/C1~C3 落账/交接文档指引)
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
# 修改报告 · 以 main 仓库为需求唯一基准的差距比对与修改方案
|
||||
|
||||
> 版本:v1.0(2026-09-07)· 依据用户拍板:**main 项目仓库内容 = 项目需求的唯一基准**
|
||||
> 分支:`risk-control-agent`(当前 67 提交领先)· 基线:425 用例(collect 已验证)
|
||||
> 比对方法:`git merge-base`(`1ddd44a`,09-05 骨架点)→ main 侧 47 文件 diff 逐一核读 → 与本分支实现逐项对照
|
||||
> **执行铁律:本报告阶段一(AL-01~AL-09,对齐 main 基准)全部完成并全量验证通过后,才允许进入阶段二(C4~C6 新增需求编码)。两阶段不得交叉进行。**
|
||||
|
||||
---
|
||||
|
||||
## 0. 基准概览:main 侧定义了什么
|
||||
|
||||
main 侧提交(Andrew 3fb0ceb「Enhance suitability assessment and documentation」+ 2c5440b 行业文档 + zhangyong a9521bc 用户手册)重新定义了 **R-02 适当性的完整契约**:
|
||||
|
||||
| 基准载体 | 内容 |
|
||||
| --- | --- |
|
||||
| `app/repository/core_ro.py`(+211 行) | `check_suitability()`:SQL 一次查(客户+产品+矩阵表)+ Python 判定;`_suitability_result()` 19 字段返回;`list_products_for_customer()`(C-11);`list_trades()`;`get_customer_l0` 扩列版 |
|
||||
| `app/model/suitability.py`(新增 55 行) | `build_suitability_log_row()`:check 结果 → risk_suitability_log INSERT 行映射(R-02 P0 契约),rule_refs 体系 JR-AST-012 / FM-01 / FM-03 / JR-AST-PRO |
|
||||
| `scripts/core/01-ddl.sql` | 新表 `core_suitability_rule`(C×R 矩阵,L0 权威);`core_customer.is_hnw`;`core_customer_risk` 加 investor_category/questionnaire_score/max_loss_tolerance_pct/investment_goal/investment_horizon/professional_approved_at/expires_at |
|
||||
| `docs/项目框架设计/表设计/01-mysql-共用底座.sql` | `risk_suitability_log` 重建:21 列(加 product_name/investor_category/match_result/mismatch_type/requires_disclosure/needs_branch_confirm/risk_was_expired/block_response_code/check_source/actor_id/rule_refs JSON)+ 6 索引 |
|
||||
| `docs/项目框架设计/表设计/07-risk_suitability_log说明.md` | P0 字段契约:match_result 五值 / mismatch_type 七值 / block_response_code 八值 / check_source 四值 / §8 P0 验收四条 |
|
||||
| 种子 SQL 03~06 | 33 客户 / 14 产品 / KYC / C×R 矩阵数据 |
|
||||
| `docs/memory/REQUIREMENTS.md` | 客户 Agent 允许「适当性匹配说明」(C-07 P1 / C-11 P2);「营销式推荐」细化不做 |
|
||||
| `docs/需求拆解/用户故事/01-客户.docx` | 用户咨询需求补至 16 条(二进制,待人工读取登记) |
|
||||
|
||||
**main 判定流程(基准语义,替换我方 SUIT-001~008):**
|
||||
```
|
||||
客户/产品不存在 → forbidden / not_found / blocked(SUIT_NOT_FOUND)
|
||||
→ 风评过期(expires_at < CURDATE(),FM-03)→ risk_expired / blocked(SUIT_RISK_EXPIRED)
|
||||
→ 专业投资者(investor_category='professional')→ professional_exempt / 放行(SUIT_PROFESSIONAL_EXEMPT)
|
||||
→ C×R 矩阵查 core_suitability_rule:forbidden 或无记录 → forbidden / blocked(SUIT_RISK_MISMATCH)
|
||||
→ allowed_with_disclosure 或产品 requires_disclosure → 需披露(SUIT_NEED_DISCLOSURE)
|
||||
→ 年龄 ≥70 且产品 R3+ → needs_branch_confirm / blocked(SUIT_AGE_CONFIRM,FM-01 网点当面确认)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 差距总览(main 基准 vs 当前实现)
|
||||
|
||||
| # | 维度 | main 基准 | 当前实现(risk-control-agent) | 差距级别 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 1 | 匹配规则来源 | `core_suitability_rule` 矩阵表(数据驱动、L0 权威) | 代码硬编码「C 序号 ≥ R 序号」(SUIT-001~005) | **重构** |
|
||||
| 2 | 判定结果粒度 | match_result 五值 + mismatch_type 七值 + requires_disclosure + needs_branch_confirm | 二值 is_matched/blocked | **重构** |
|
||||
| 3 | 风评有效期 | `expires_at` 列显式判定(FM-03) | `evaluated_at + 365 天`计算(SUIT-008,settings.risk_assessment_valid_days) | **口径替换** |
|
||||
| 4 | 专业投资者豁免 | professional 全豁免(JR-AST-PRO) | 无此概念 | **新增** |
|
||||
| 5 | 高龄处理 | age≥70 买 R3+ → **阻断**需网点确认(FM-01) | SUIT-006 age≥70 按 C3 封顶(继续判定) | **语义替换** |
|
||||
| 6 | 风险揭示书 | allowed_with_disclosure + product.requires_disclosure | 无此概念 | **新增** |
|
||||
| 7 | 起购金额 | min_subscribe_amount(mismatch_type=min_subscribe,P0 预留) | 无 | **预留** |
|
||||
| 8 | 机器响应码 | block_response_code 八值 | rule_id(SUIT-00n/SUIT-PASS) | **替换** |
|
||||
| 9 | 规则编号体系 | JR-AST-012 / FM-01 / FM-03 / JR-AST-PRO(rule_refs JSON 数组) | SUIT-001~008 单值 rule_id | **替换** |
|
||||
| 10 | risk_suitability_log | 21 列 + 6 索引 | 10 列 | **重建** |
|
||||
| 11 | 判定落库入口 | model/build_suitability_log_row 统一映射(check_source 四值) | service 内联 10 字段 dict | **重构** |
|
||||
| 12 | NotFound 语义 | 返回 forbidden/not_found 结构(不抛异常) | 抛 NotFoundError | **行为变更** |
|
||||
| 13 | 新查询能力 | list_products_for_customer(C-11)、list_trades | 无 | **新增** |
|
||||
| 14 | Core 种子 | 33 客户 / 14 产品 / KYC / 矩阵数据 | 28 客户 / 12 产品 | **更新** |
|
||||
| 15 | get_customer_l0 | `c.*` + 风评新列 + risk_is_expired | 固定 8 列 | 扩列(向后兼容) |
|
||||
| 16 | list_holdings | 无 limit,加 min_subscribe_amount/term_days 列 | limit=500 截断防护(T-04 评审) | 合并两方 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 修改任务清单(阶段一:对齐 main 基准)
|
||||
|
||||
> 依赖顺序即编号顺序;每项含方案 / 文件 / 优先级 / 验收标准。
|
||||
|
||||
### AL-01 Core 库表结构对齐(P0 · 阻塞一切)
|
||||
|
||||
- **方案**:`scripts/core/01-ddl.sql` 采纳 main 版(core_customer.is_hnw、core_customer_risk 七新列、新表 core_suitability_rule + FK);`02~06-seed*.sql` 采纳 main 版(33 客户/14 产品/KYC/矩阵);**追加我方已有内容**:core_staff 的 STAFF-90001(risk_demo)等我方种子(main 侧 02-seed-base.sql 无此账号)。
|
||||
- **涉及**:`scripts/core/01-ddl.sql`、`02-seed-base.sql`、`03-seed-customers.sql`、`04-seed-holdings.sql`、`05-seed-trades.sql`、`06-seed-nav.sql`、`scripts/core/README.md`。
|
||||
- **验收**:`reset.ps1` 全新灌库成功;`SELECT * FROM core_suitability_rule` 有 C×R 25 行矩阵;STAFF-90001/31001 存在性符合预期。
|
||||
|
||||
### AL-02 agent 库 risk_suitability_log 重建(P0)
|
||||
|
||||
- **方案**:`docs/项目框架设计/表设计/01-mysql-共用底座.sql` 中该表采纳 main 版 21 列定义;同步 `docs/项目框架设计/表设计/07-risk_suitability_log说明.md`(main 版已完整,直接采用)。
|
||||
- **涉及**:上两文件 + `tests/_ddl.py`(sqlite 测试库 DDL 同步——**注意 sqlite 无 ENUM,用 VARCHAR + CHECK 约束替代,与现有 _ddl 风格一致**)。
|
||||
- **验收**:sqlite 建表成功;手工 INSERT 一行含全部新列成功。
|
||||
|
||||
### AL-03 core_ro.py 融合(P0 · 冲突主战场)
|
||||
|
||||
- **方案**:以**我方文件为骨架**(保留 get_trade_by_id/sum_trades_on_date/list_trades_range/list_active_customers/concentration_profile 及 utils/db 引擎工厂——main 版自带 create_engine 工厂会破坏统一引擎管理,不采纳),吸收 main 四项:
|
||||
1. `get_customer_l0` 换 main 扩列版(c.* + 风评新列 + risk_is_expired)
|
||||
2. 新增 `check_suitability` + `_suitability_result`(main 原样引入,**但 SQL 中 `(r.expires_at < CURDATE())` 改为取回 expires_at 后 Python 端计算**——CURDATE() 是 MySQL 专属函数,sqlite 测试库会直接报错;`JOIN core_customer_risk` 保持 main 的 INNER JOIN 语义)
|
||||
3. 新增 `list_products_for_customer`(C-11)
|
||||
4. `list_holdings` 合并:保留我方 limit=500 截断防护 + 加 main 的 min_subscribe_amount/term_days 列
|
||||
- **涉及**:`app/repository/core_ro.py`(唯一文件,两方改动都在此)。
|
||||
- **验收**:单测通过(调用方 engine/chat_tools 零改动仍工作);check_suitability 对 sqlite 与 MySQL 双方言可执行。
|
||||
|
||||
### AL-04 引入 model/suitability.py(P0)
|
||||
|
||||
- **方案**:main 的 `app/model/suitability.py` 原样引入(build_suitability_log_row,55 行,无依赖冲突)。
|
||||
- **验收**:单测覆盖四类 mismatch 的 rule_refs 生成(JR-AST-012/FM-01/FM-03/JR-AST-PRO)。
|
||||
|
||||
### AL-05 service/suitability.py 重构(P0 · 行为核心变更)
|
||||
|
||||
- **方案**:判定内核从「纯函数矩阵」改为「调 core_ro.check_suitability」:
|
||||
- `suitability_check(customer_id, product_id, ...)` 保持**签名不变**(trade_gateway/risk.py/chat_tools 三个调用方入参不动),内部改走 check_suitability
|
||||
- 返回类型 `SuitabilityResult` 扩展:新增 match_result/mismatch_type/requires_disclosure/needs_branch_confirm/block_response_code/rule_refs 字段;保留 is_matched/blocked/reasons/block_reason(映射 reason)供旧调用方读取
|
||||
- `check_core`/`cap_by_age`/`match_by_matrix` **删除**(SUIT-006 封顶语义被 FM-01 网点确认替换;SUIT-001~005 被 JR-AST-012 矩阵替换;SUIT-008 被 FM-03 expires_at 替换)
|
||||
- `settings.risk_assessment_valid_days` 退役(改由 core_customer_risk.expires_at 数据驱动);`.env.example` 同步注释
|
||||
- NotFoundError 不再抛出:客户/产品缺失 → 返回 forbidden/not_found 结构(main 语义);trade_gateway 的 try/except NotFoundError 相应调整
|
||||
- 写库改 `build_suitability_log_row`:check_source 参数化(网关传 r02_trade、Tool 传 r02_chat);actor_id 透传(网关传 "svc-trade-suitability" 或 auth.actor_id)
|
||||
- **涉及**:`app/service/suitability.py`、`app/config/settings.py`、`.env.example`、`app/gateway/trade_gateway.py`(仅 NotFound 分支 + actor_id/check_source 传参)、`app/api/risk.py`(suitability_check_api 的响应字段扩展:match_result/block_response_code 对外)。
|
||||
- **验收**:单测覆盖 main 基准全部判定分支(not_found / risk_expired / professional_exempt / 矩阵 forbidden / allowed / allowed_with_disclosure / age_branch_confirm 七路径);A-1/A-2 等价的阻断场景全部仍阻断。
|
||||
|
||||
### AL-06 对话 Tool 与 API 响应对齐(P1)
|
||||
|
||||
- **方案**:`chat_tools.suitability_check` 返回体扩展 match_result/mismatch_type/requires_disclosure/needs_branch_confirm/block_response_code(替代现 rule_id/blocked 展示);`tool_service.summarize` 的 suitability 分支文案按新枚举重写(如「需网点当面确认(FM-01)」「需签署风险揭示书」);`risk.py::suitability_check_api` 响应体同步。
|
||||
- **涉及**:`app/service/risk/chat_tools.py`、`app/service/tool_service.py`、`app/api/risk.py`。
|
||||
- **验收**:对话问「能不能买」返回新枚举语义;A-8 单测更新后绿。
|
||||
|
||||
### AL-07 测试重建(P0 · 原 77 例断言作废)
|
||||
|
||||
- **方案**:`tests/test_suitability*.py` 按 main 契约重写:七判定路径各正反例 + build_suitability_log_row 逐字段映射断言 + rule_refs 组合(过期+等级不匹配 → ["JR-AST-012","FM-03"])+ sqlite/MySQL 双方言(fixture 注入);`tests/_ddl.py` 同步 AL-01/02 新表;`test_trade_gateway.py`/`test_risk_api.py`/`test_chat_tools.py` 中涉及旧 rule_id(SUIT-00n/SUIT-PASS)的断言改为新枚举。
|
||||
- **验收**:`python -m pytest` 全量绿(系统 Python 3.13.14);集成测试真库走新表结构。
|
||||
|
||||
### AL-08 演示库重灌与种子核对(P0 · 依赖 AL-01/02)
|
||||
|
||||
- **方案**:按新 SQL 全量重灌 jinrong_core + jinrong_agent(演示 SOP §2 流程);prepare_risk_demo.sql 核对(CUST-4001 测评等断言在新列下仍成立——**expires_at 取代 evaluated_at+365 后,演示 SQL 的测评日期写法要改写 expires_at**);AML 名单 8 条保持。
|
||||
- **验收**:演示 SOP 核查单①~⑥通过;集成测试不 skip。
|
||||
|
||||
### AL-09 文档基准同步(P1 · 合并后立即做)
|
||||
|
||||
- **方案**:与 main 分支实际合并时(git merge main)按以下口径解决 9 个冲突文件:memory 六件套 + AGENTS.md **以我方为准**(我方是 425 绿现状的权威记录),把 main 侧新增实质内容吸收进 REQUIREMENTS(C-07/C-11 行、营销式推荐细化、33 客户/14 产品口径);`02-seed-base.sql` 手工融合两方账号;`core_ro.py` 按 AL-03 融合结果落定。PRD/规则表修订单列 AL-10。
|
||||
- **验收**:merge 完成后工作区 clean;pytest 全量绿;文档 grep 无 feature/risk 残留、无 SUIT-006 残留口径。
|
||||
|
||||
### AL-10 PRD/规则表修订(P1 · 需用户确认后执行)
|
||||
|
||||
- **方案**:PRD v1.1 → v1.2:FR-2/§7 的 SUIT-001~008 体系替换为 main 契约(矩阵表驱动 + match_result 五值 + FM-01/FM-03/JR-AST-PRO/JR-AST-012 + block_response_code);§8 验收表 A-1/A-2/A-8 的 rule_id 断言改为新枚举;附-风控规则表 §1「SUIT-001~008」整节替换(SUIT-006 封顶 → FM-01 网点确认;SUIT-008 过期 → FM-03)。**此为需求基准变更,需用户逐条确认后落笔。**
|
||||
- **验收**:PRD v1.2 冻结;规则表 v1.2;A-1/A-2/A-8 测试与文档断言一致。
|
||||
|
||||
### AL-11 新增需求登记(P2)
|
||||
|
||||
- **方案**:REQUIREMENTS Wave 3 补 C-07(T-41)/C-11(T-42)两行(main 口径:客户 Agent 适当性匹配说明,须联动 R-02,非投顾推荐);`docs/需求拆解/用户故事/01-客户.docx` 的 11~16 条需求人工读取后登记进 Wave 3 或 P1 清单(docx 为二进制,需人工打开确认)。
|
||||
- **验收**:REQUIREMENTS 与 main 基准无需求遗漏。
|
||||
|
||||
---
|
||||
|
||||
## 3. 执行顺序(强制)
|
||||
|
||||
```text
|
||||
阶段一 · 对齐 main 基准(先完成已实现功能的全部修改并确认无误)
|
||||
AL-01 表结构 → AL-02 agent 表 → AL-03 core_ro 融合 → AL-04 model 引入
|
||||
→ AL-05 suitability 重构 → AL-06 Tool/API 对齐 → AL-07 测试重建
|
||||
→ AL-08 重灌演示库 → 【阶段一验收门】python -m pytest 全量绿
|
||||
+ uvicorn 冒烟(/health + /api/simulate 阻断路径 + /api/risk/suitability/check)
|
||||
+ 用户浏览器目视确认 → git commit(每个 AL 独立 commit)
|
||||
阶段二 · 新增需求(阶段一验收门通过后才允许开始)
|
||||
C5 前置联动 → C4(RISK-006)→ C5(RISK-007)→ C6(RISK-008)
|
||||
(按《实现方案-风控追加需求v1.1-C4C6.md》执行,方案需按本报告微调处:
|
||||
① C4 concentration_profile 基于 AL-03 融合后的 list_holdings(含新列);
|
||||
② AL-05 重构后 suitability_check 返回结构变化,C4/C6 方案中引用 SuitabilityResult
|
||||
字段名的地方同步核对)
|
||||
```
|
||||
|
||||
**注意**:AL-09(分支合并)建议在阶段一验收门之后、阶段二之前执行——先在我方分支完成适配实现并验证,再合 main 的文档/资料,避免双线作战。若团队要求先合并,则 AL-03 的融合工作在合并冲突解决中一并完成。
|
||||
|
||||
## 4. 待人工确认事项
|
||||
|
||||
1. **SUIT-006 封顶语义正式退役**(改 main 的 FM-01「阻断+网点确认」)——两个口径对 70 岁客户结论相反(我方放行 C3 内产品,main 一律阻断待确认),确认以 main 为准。
|
||||
2. **SUIT-001~008 编号体系退役**——PRD/规则表/测试断言全面改 JR-AST/FM 体系,PRD 升 v1.2 需授权。
|
||||
3. **settings.risk_assessment_valid_days 退役**——365 天有效期改为 core_customer_risk.expires_at 数据驱动(.env 不再可配)。
|
||||
4. risk-m1 是否补打(阶段 A 完成时漏打)。
|
||||
5. `docs/需求拆解/用户故事/01-客户.docx` 11~16 条需人工打开读取后登记。
|
||||
6. 实际合并 main 的时机(建议阶段一验收门后)。
|
||||
Reference in New Issue
Block a user