Files
group_xinghuo_jinrong/docs/项目框架设计/基金转换-审查意见处置表.md
T
GaoYiYuan_0626 f056fcd007 基金转换 T+1 模型:T-1~T-6 落地(DDL/数据层/语义收窄/锁/受理事务)
AIcoding 第 5 步 todo 开发(开发计划 v2.0)前半段:

- T-1 3 张新表 DDL(core_convert_request 6 态 ENUM / core_trade_calendar /
  core_share_rule)+ 种子 + sqlite 单一事实源同步 + 列清单断言
- T-2/T-2b calc 扩展(product_round/redeem_amount/partial_qty)+ 真实净值实算回填
- T-3 convert_request_repository(6 态 + 条件 UPDATE 守卫)+ core_ro 三读方法
  + share_lot_repository.available_qty_with_inflight(R-3 在途占用推导)
- T-4 convert_repository.sync_mirror 成为 risk_convert_detail 唯一进度镜像写入口
  (旧三方法标 Deprecated,T-7 后删)
- T-5 locks.py 锁键构造器 convert_req_lock_key / convert_confirm_lock_key
- T-6 convert_service.accept_convert 受理事务(八步:锁→幂等→校验→受理日顺延
  →在途占用校验→落单→镜像+审计→202;不扣份额/不折算/不写流水)
  + tests/test_convert_accept.py(16 用例)
  + scripts/dev/verify_convert_accept.py(真库 36/36 一致)
  + trading_calendar.py 纯函数包(R-5)+ 21 用例

T-6 真库实测暴露并修复:confirm_eta 在日历数据边界抛 ValueError,会让已落库
的受理单在调用方眼里变 500;改为展示性字段容错 + 单测守护。

基线:798 passed / 10 skipped,零回归。
2026-09-11 19:21:15 +08:00

14 KiB
Raw Blame History

基金转换 · 外部审查意见处置表

⚠️ 历史参考文档(v0.x 模型,2026-09-10 产物):本表结论对应的 PRD v0.8 / 架构 v1.0 已被 T+1 受理/确认分离模型(PRD v1.1 / 架构 v2.1 / 开发计划 v2.0)取代,保留作审查方法论留档,当前以 v1.1/v2.1/v2.0 为准。

日期:2026-09-10 · 审查结论原文:❌ 不建议进入编码(33 条:B×5 / I×7 / M×7 / L×7 / S×3 + 自检九问复核) 处置原则(用户红线):逐条判定 = 接受 / 修正性接受 / 驳回;驳回与修正性接受必须给出核实过的证据。 判定基准:贴近真实业务(证监会公告〔2025〕22 号 + 10 家基金公司转换公告,见架构 §0.5 来源清单) 结果:接受 27 · 修正性接受 5 · 驳回 0 · 合并 1(S-1 并入 B-1),另自查补 2 条(X-1 / X-2) 后续:本表结论 → PRD v0.8 → 架构设计 v1.0 → 独立 AI 评审 → 第 4 步开发计划


一、阻断级(B-1~B-5)

# 审查意见 判定 处置与证据
B-1 PRD「已定稿」与架构 §0 合规查证矛盾 接受 PRD 前言改「v0.7 已冻结(架构校准发现合规问题),待出 v0.8」;架构 v0.2 加冻结声明;新增门控:PRD v0.8 未产出不得进第 4 步
B-2 申购费率种子全超法定上限 接受 按架构 §13.3 重定:货基 0 / 债基·指数 0.0030 / 其他混合 0.0050 / 主动偏股 0.0080。依据 22 号文 §8。§5.3 示例、§9 第 19 条同步重算
B-3 赎回费 7–30 日档低于法定下限、边界与 180 日不符 接受 新档:<7 日 1.5% / 7–30 日 1.0% / 30–180 日 0.5% / 180–365 日 0.25% / ≥365 日 0。依据 22 号文 §10。PRD §2.1、07 种子、§5.3、§9 同步
B-4 份额 4 位向下舍去,与真实(2 位四舍五入)不符 接受 改 2 位 ROUND_HALF_UP;rounding_diff 语义改「可正可负,在基金资产列支」。core_share_lot.remain_qty 存储精度保持 DECIMAL(18,4)(真实 TA 内部精度高于展示),计算与展示按 2 位
B-5 T+1 确认时序与真实不符 修正性接受(范围需收窄,方向需澄清) 只改「转入端新批次」的 confirmed_at = T+1。证据:PRD §4.4 表格已区分三行(转入新批次 / 普通申购新批次 / 转出·赎回不产新批次);转出批次是历史日期,hold_days = (交易日 − confirmed_at).days 恒为正,不受影响。
方向澄清:审查称「当前设计使持有期比真实多 1 天」——实际相反。真实持有期自确认日(T+1)起算,比从 T 起算少 1 天(持有期更短、费率档更严格)。PRD Q1 精确化为:「不模拟 T+1 的权益登记延迟(转入份额立即可用),但 confirmed_at 取 T+1」

二、重要级(I-1~I-7)

# 审查意见 判定 处置与证据
I-1 补差费口径未拍板(A 费率差 vs B 价外法两端差) 接受 PRD 新增 Q9:明确本期选 B(价外法两端差),理由:中国申购费标准算法即价外法(净申购额 = 金额/(1+费率)),B 与之数学自洽,且为国投瑞银/东海/华商/金鹰/鹏华新版主流;A 以 convert_diff_fee_mode 配置保留,两口径均有单测。PRD §2.1 补双口径公式与数值差异示例
I-2 hold_days 缺边界定义 接受 PRD §12 补:hold_days = (交易日 − confirmed_at).days(不含申请日);分档左闭右开 [min, max);满 7 日归 7–30 日档(1.0%),满 30 日归 30–180 日档(0.5%)。与架构 §7 同步
I-3 阶段二补偿自动/手动未声明 接受 PRD §7.1 补:一期为「监控告警 + 人工脚本补偿」(可接受简化),SLA 24h;cleanup_pending_convert.py 由定时/手动触发。另补审查未提的缺口 X-1:引擎执行时序——阶段一提交后、阶段二之前同步跑引擎;引擎失败沿用现有 engine_error 模式(架构 §X)
I-4 强制全转触发条件不清晰 接受 PRD §12 补判断流程图:① 份额足够(Σ remain_qty)→ ② 最低转出份额(申请 == 全部可转份额时豁免 min_redeem)→ ③ 余额 < min_hold_qty 才触发强制全转。审查例(持 6000、申请 5000、min_hold_qty=1000):余额 1000 不低于下限 → 不触发,正常转 5000
I-5 min_hold_action 两种模式 PRD 未回应 接受 两种都做:core_product 加 min_hold_action ENUM('force_transfer','force_redeem') DEFAULT 'force_transfer'。依据:阈值大(100/500/1000 份)→ 强制赎回(财通/汇添富);阈值小(0.1/1 份)→ 强制全转(中银/东海)
I-6 份额精度对现有 510 用例影响未评估 接受(已实测,影响 = 0) 实测 grep:现有测试仅 2 个文件触碰 core_holding(test_chat_tools.py、test_concentration_c4.py),且只断言 market_value / quantity,无任何份额精度断言 → 改动影响为 0。
但实测发现真坑:sqlite _ddl.py:53 列名 quantity,MySQL DDL 为 qty——convert 首次要 UPDATE core_holding.qty,该失配会在本次开发第一次暴露。T-1 必须补 qty/cost_amount/as_of/pnl_pct
I-7 RISK-006 转换后集中度未定义 接受 明确:引擎在阶段一提交后执行,concentration_profile 读到的是已更新持仓(含转入端新持仓、已扣减的转出端)→ 转换的集中度连带效应天然被覆盖,无需新增规则

三、中等级(M-1~M-7)

# 意见 判定 处置
M-1 重试判定 SQL 依赖 idx_convert_group 接受 开发计划门控:T-1(DDL 含索引)必须先于 T-7(幂等重试逻辑)
M-2 409 LOT_CONFLICT 重试策略缺失 接受 PRD §5.4 增行:调用方自行重试,建议最多 3 次,间隔 100/200/400ms
M-3 幂等键格式未指定 接受 客户端生成、格式自由、≤64 字符、建议含时间戳便于排查
M-4 out_amount 与 convert_amount 语义重叠 接受 §5.3 注释分组:out_amount = 原始转出额;convert_amount = 扣赎回费后可用于转入的金额
M-5 convert_batch_max_lots=200 超限无错误码 接受 超限返回 400 TOO_MANY_LOTS
M-6 pnl_pct 更新口径未同步 接受 PRD FR-C13 补:pnl_pct = (market_value − cost_amount) / cost_amount,cost_amount = 0 时置 0
M-7 PRD 与架构同步依赖未管理 接受 硬性门控写入 PRD v0.8 前言 + 架构冻结声明(已加)

四、低优先级(L-1~L-7)

# 意见 判定 处置
L-1 架构校准结论未回流 PRD 评审记录 接受 PRD v0.8 §13 新增「架构校准轮(2026-09-10)」记录,附本处置表索引
L-2 主审计应关联组而非单条 接受 input_summary 以 convert_group_id 为主键关联,附 out_trade_id / in_trade_id
L-3 响应示例字段过多 接受(可选) §5.3 按「基础 / 转出端 / 转入端 / 规则引擎 / 审计」分组注释
L-4 「仅 R-02 可阻断」表述歧义 接受 加注:503 / 409 为技术故障码,不适用「仅 R-02 可阻断」业务规则
L-5 撤单未预留字段 接受 risk_convert_detail 建表即加 status ENUM(...,'cancelled') 与 cancelled_at(新表,零 ALTER 成本)
L-6 种子版本管理 修正性接受 不单独建 CHANGELOG 文件(维护成本高、易与 SQL 漂移);改为每个种子 SQL 文件头加版本注释块(版本/日期/依据/变更摘要)
L-7 rebuild_lots.py「回滚」措辞误导 接受 改措辞为「批次快照重建,不是交易回滚」

五、结构问题(S-1~S-3)

# 意见 判定 处置
S-1 前言「已定稿」不符 — 并入 B-1 处理
S-2 评审记录过长(≈200 行,占 22%) 修正性接受 不移到附录。理由:用户红线要求「PRD 必须经独立 AI 审查、评审闭环可追溯」,删详录会破坏可追溯性。折中:正文前加「阅读导航」(新读者路径 + 每轮 3 行决策摘要表),详录保留原处
S-3 待确认项需新增 接受 新增 Q9 补差费口径 / Q10 份额精度 / Q11 T+1 建模 / Q12 min_hold_action

六、自查补充(审查未覆盖,本次一并收口)

# 发现 判定 处置
X-1 引擎执行时序未定义——PRD §7.0 七步里没有「跑规则引擎」这一步 补充 插入为第 6.5 步:阶段一(Core 提交)→ 阶段 1.5:同步跑引擎(读全量两条流水 + 更新后持仓) → 阶段二(回写 + 审计)。引擎异常沿用 engine_error + 本地日志,不阻断已成立的交易
X-2 两条流水的 trade_status——真实 T 日申请为「待确认」,T+1 才 confirmed;而 _eligible 只认 confirmed 补充 定:两条流水直接写 confirmed(沿用模拟库现有行为,否则规则引擎读不到),折算结果以 estimated=true 标识;PRD 注明此为「不模拟 T+1 权益登记延迟」的连带简化,与 Q1 一致

七、自检九问复核(审查评价 + 本轮补正)

# 问 审查评价 本轮补正
1~4 谁写 / 谁读 / 枚举 DDL / 跨库事务 ✓ 第 4 问「完整但补偿路径为手动」→ I-3 已明确一期手动 + SLA 24h
5 种子数据 ⚠️ 费率超上限 B-2 / B-3 已重定合规值
6~8 并发 / 汇总语义 / 向后兼容 ✓ —
9 示例自证 ⚠️ 数字基于错误口径 T-2b:scripts/dev/calc_convert_demo.py 用生产同一套 calc.py 实算回填,禁止手算
10 (新增)外部事实核验 — 本次 4 项合规硬伤全部源于「只做内部自洽、未做外部核验」。新增第 10 问:涉及费率 / 时限 / 资质 / 精度等行业有明文规定的量,必须联网核对现行法规与真实业务公告并列来源

八、PRD v0.8 修订范围(下一步执行清单)

序 修订点 对应条目
1 前言状态改「v0.7 已冻结,待 v0.8」+ 门控声明 B-1 / M-7
2 §1.4 非目标:撤单改「二期,字段已预留」 L-5
3 §2.1 补差费:双口径公式 + 选 B 的理由 + 数值差异例 I-1
4 §2.1 赎回费档位按 22 号文重排 B-3
5 §2.5 份额 2 位 ROUND_HALF_UP,误差在基金资产列支,rounding_diff 可正可负 B-4
6 §4.1 risk_convert_detail 加 cancelled / cancelled_at;core_fee_rule 加 to_fund_ratio L-5 / D16
7 §4.2 core_product 加 min_hold_action I-5
8 §4.3 种子费率改合规值;赎回费种子改新档 B-2 / B-3
9 §4.4 / Q1:confirmed_at = T+1(仅新批次),精确化表述 B-5
10 §5.3 响应:示例由脚本实算回填 + 分组注释 + 字段语义 B-2 / M-4 / L-3 / T-2b
11 §5.4 增 TOO_MANY_LOTS + 409 重试策略 + 503/409 非业务阻断注 M-2 / M-5 / L-4
12 §7.0 插入「阶段 1.5 跑引擎」 X-1
13 §7.1 补偿路径:一期手动 + SLA 24h + 触发者 I-3
14 §7.3 审计关联 convert_group_id L-2
15 §10 新增 Q9~Q12 S-3
16 §12 补 hold_days 定义 + 强制全转判断流程图 I-2 / I-4
17 §13 新增「架构校准轮」评审记录 L-1
18 种子 SQL 文件头加版本注释块 L-6
19 FR-C13 补 pnl_pct 口径;rebuild_lots.py 措辞订正 M-6 / L-7
20 全文:示例数字按新费率/精度/时序重算(脚本实算) B-2~B-5

执行状态(2026-09-10):以上 20 项已全部落于 PRD v0.8。 示例数字由 scripts/dev/calc_convert_demo.py 实算回填(口径 B:diff_fee = 252.40、in_qty = 53456.95、rounding_diff = -0.0026;口径 A 对照 253.91 / 53455.36)。 下一步:架构设计 v0.2 按本表结论转 v1.0 → 送独立 AI 评审 → 第 4 步开发计划。


九、用户拍板记录(2026-09-10)

行业多口径 2 项 + 架构取舍 3 项,用户确认「按建议」:

# 事项 拍板结果 依据
1 补差费默认口径 口径 B(价外法两端差) 与申购费价外法数学自洽;A 属近似写法,保留为 convert_diff_fee_mode 配置项
2 最低持有余额处置 两种都做(min_hold_action ENUM 两值 + 种子按产品设定) 法规无强制(22 号文不涉及最低持有余额),两种均为真实基金合同约定
3 P1 普通申赎无批次是否跳过 不跳过:批次表覆盖全部交易类型;遇历史持仓无批次 → 兜底补建,保证 FIFO 可执行、两表一致 跳过会导致批次表与持仓表永久失配
4 P2 转出归零保留还是删行 保留(remain_qty = 0),不删行 与「审计只 INSERT」精神一致,保可追溯;避免 core_convert_lot_detail 断链
5 P3 Core 侧明细是否对外查询 仅补偿,不对外查询 保持 Core 只读边界最小;对话侧走 agent 库粗粒度详情

落地位置:第 1、2 项属业务口径 → 已落 PRD v0.8(§2.1.1 / §4.2 / §10 Q9·Q12,§10 已加拍板状态说明); 第 35 项属架构层 → 将在架构设计 v1.0 落实(对应架构 v0.2 的 P1P3 待拍板项)。