文档:T-8 回写 + 全仓进度一致性复核(订正 5 处漏同步)

本轮在 T-8 提交(57f16a5)后做文档回写,并对全仓「同一事实的副本」做一致性扫描,
发现并当场订正 5 处漏同步(均属上次改了主状态位、漏改副本):

- AGENTS.md 入口引用(最重要,属项目记忆已强调的「全仓同步入口引用」漏项):
  T-1~T-6 ✅/797 基线/下一步 T-7 → T-1~T-8 ✅/829 基线/下一步 T-9;
  T-6 真库 verify_convert_accept.py 36/36 → 37/37,并并列 83/83、39/39。
- docs/memory/TODO.md:汇总待办行「T-8 ~ T-17(含已完成之引擎时机)」→「T-9 ~ T-17」;
  为 v0.x 线引用块加编号歧义提示(其 T-11/T-12 与新线同号且均涉 amount_view,易混)。
- docs/memory/MEMORY.md:自检问答第 6 问进度 T-1~T-7 ✅/827 → T-1~T-8 ✅/829。
- 开发计划(T-8 执行期订正,承 57f16a5 代码提交):
  就地订正 T-7 执行记录第 2 条「T-8 剩余仅为 rules.amount_view」之误(F-10 明确 T-8 不动去重口径,属 T-11);
  新增 T-8「执行记录」5 条差异裁定;DoD 全勾。

不入库但同批完成(交接文档.md 受 .gitignore 忽略):
  - 顶部版本 v3.7 → v3.8;§③ 表格行;§B.11 状态块(T-8 完成 + 两处订正);
  - 开工纪律行 T-1~T-6 → T-1~T-8;
  - §B.11「未落地(T-1 起执行)」立项期清单 → 「已落地」并附实测行号
    (01-ddl.sql 272/297/305 行;已进 reset.ps1 与 verify_convert_seed.py 清单),原文折叠留痕。

复核:全量 pytest -q → 829 passed / 10 skipped(16.37s,零失败)。
This commit is contained in:
2026-09-11 19:53:31 +08:00
parent 57f16a50a1
commit 9f28633e55
4 changed files with 47 additions and 14 deletions
@@ -487,9 +487,12 @@
2. **新增三个共用模块**(计划未列):`format.py`(`D2/D4/new_id/q` 展示规格唯一出口)、
`audit.py`(`write_convert_audit` 唯一审计写入点)、`engine_call.py`
(`run_convert_engine` 引擎唯一调用点)。理由:受理段与确认段共用同一套量化 / 审计 /
引擎口径,若两段各写一份必然漂移。`engine_call.py` 的引入**同时完成了 T-8 的「引擎时机改」**
(调用点已迁到确认事务 commit 之后,且全仓恰 1 处调用)—— T-8 剩余工作仅为
`rules.amount_view` 与三处消费方同步。
引擎口径,若两段各写一份必然漂移。`engine_call.py` 的引入完成了 T-8「引擎时机」的
**实现部分**(调用点已迁到确认事务 commit 之后,且全仓恰 1 处调用)。
⚠️ **订正(2026-09-11,T-8 执行期发现)**:本行原写「T-8 剩余工作仅为 `rules.amount_view`
与三处消费方同步」——**错**。F-10 已明确 T-8 **不动**去重口径(`amount_view` 三处消费方
**原样不动**,属 T-11 的范围)。T-8 剩余的是**验证面**:调用点唯一性守护 + 受理不触引擎用例
+ 确认链路真引擎出单 / RISK-002 不翻倍的真库断言。详见下方 T-8「执行记录」。
3. **`nav.py` 未改**:确认段直接调 `core_ro.get_nav_on(product, T)`(T-3 已新增的精确匹配口径),
无需经 `nav.py`。计划第 4 条要删的「取 T−1 路径」(`_nav_as_of`)属 v1.0 `convert_fund`,
该函数已标 `⛔ Deprecated`,随 T-9 一并删除。
@@ -522,15 +525,43 @@
**依赖**:无(引擎时机改动不与 T-7 强绑定前置,但联调在 T-7 DoD 覆盖)
**DoD**:
- [ ] grep:`process_convert_event(` 全仓恰 1 处调用(确认段)
- [ ] 受理路径用例:受理后 `risk_alert` 0 新增(验收 29 前半)
- [ ] 确认路径用例:引擎跑一次、RISK-002 计一次(验收 5/7)
- [ ] RISK-001/003 仍见两条(去重未删行,验收 6)
- [ ] pytest 全绿
- [x] grep:`process_convert_event(` 全仓恰 1 处调用(确认段)
- [x] 受理路径用例:受理后 `risk_alert` 0 新增(验收 29 前半)
- [x] 确认路径用例:引擎跑一次、RISK-002 计一次(验收 5/7)
- [x] RISK-001/003 仍见两条(去重未删行,验收 6)
- [x] pytest 全绿
**风险**:调用点漏清(旧受理段残留)→ DoD 1 守护
**回滚点**:单点改动,git 回退即还原
**执行记录(2026-09-11 · 提交 `57f16a5`)**
真库 `verify_convert_engine.py` **39 项一致 / 0 不一致**(A0/A/B/C/D/E/F 七组);
全量 pytest **829 passed / 10 skipped**(T-7 基线 827,+2);复跑 T-6 `verify_convert_accept.py`
**37/37**、T-7 `verify_convert_confirm.py` **83/83**、v1.0 链路 `verify_convert_service.py` **35/35**,均零失败。
**本轮实际范围(与任务书字面的差异,已留痕)**:
1. **引擎时机的「实现」在 T-7 已完成,本轮只做「守护 + 端到端验证」**。T-7 抽出
`engine_call.run_convert_engine` 时即把调用点放在确认事务 commit 之后,且全仓仅此一处;
`accept_convert` 自 T-6 实现起就不含引擎调用(阶段 1.5 属 v1.0 `convert_fund`,不在受理段内)。
故 R-7 的两条要求(受理不触引擎 / 确认后唯一调用点)在 T-7 已成立,本轮补的是**可回归的守护**。
2. **DoD 1 的 grep 改用 AST 实现**。字符串匹配会被 `engine_call.py` 的说明段
(「`process_convert_event(` 全仓应恰 1 处调用」)误判为第二处调用 —— 该守护若用 grep 写,
会恒红或被迫加脆弱的排除规则。改用 AST 统计 `Call` 节点,并同时断言宿主函数为
`run_convert_engine`(防「文件对但函数被搬走」)。**已做突变验证**:
临时追加第二处调用 → 断言变红 → 还原。
3. **`convert_fund` 的阶段 1.5 调用点本轮不动**。该函数是 v1.0 实时模型的全流程入口
(已被 4 个测试文件 + gateway 依赖),T-9 切换 API 后整体删除。本轮若只摘掉它的引擎调用,
会让过渡函数变成「扣了份额但不出预警单」——**风控缺失比时机错更危险**,故保留,
由 T-9 随函数一并清除。
4. **确认链路的真引擎断言采用「正证 + 反证」双断言**。仅断言「RISK-002 不命中」无法区分
「去重生效」与「引擎根本没跑」;故正证(阈值夹逼 → 不命中)之外补反证
(阈值下调 → 命中),并做突变验证(禁用引擎调用 → 变红)。
5. **真库脚本踩坑(已钉进脚本注释)**:`confirm_one(thresholds=...)` 必须**显式传阈值**,
缺省退回 `RiskThresholds.from_settings()`;settings 的 `daily_total` 一旦低于单条金额,
RISK-002 就会「命中」,**症状看着像去重失效,实为阈值口径没传**(首轮实跑被 B 组断言捕获)。
---
### T-9 · api 层(redeem 份额申报 + 撤单/确认/查询接口 + 网关分派)