Files
group_xinghuo_jinrong/docs/项目框架设计/修改报告-对齐main基准.md

15 KiB
Raw Permalink Blame History

修改报告 · 以 main 仓库为需求唯一基准的差距比对与修改方案

版本:v1.0(2026-09-07)· 依据用户拍板:main 项目仓库内容 = 项目需求的唯一基准 分支:risk-control-agent(当前 67 提交领先)· 基线:425 用例(collect 已验证) 比对方法:git merge-base(1ddd44a,09-05 骨架点)→ main 侧 47 文件 diff 逐一核读 → 与本分支实现逐项对照 执行铁律:本报告阶段一(AL-01AL-09,对齐 main 基准)全部完成并全量验证通过后,才允许进入阶段二(C4C6 新增需求编码)。两阶段不得交叉进行。


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-001008 体系替换为 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-001008」整节替换(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. 执行顺序(强制)

阶段一 · 对齐 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 的时机(建议阶段一验收门后)。