文档:T-7 确认段落地回写(开发计划 DoD 全勾 + 执行记录 / 交接文档 §B.11 / TODO / 两处 MEMORY)
- 开发计划 T-7:DoD 9 项勾选 + 新增「执行记录」小节,逐条留痕 6 处与计划的差异裁定: ① 确认段不做最低持有重判(计划缺口,强制全转属受理段决策,受理单 remark 传承); ② 新增 format/audit/engine_call 三共用模块(后者顺带完成 T-8 的「引擎时机改」); ③ nav.py 未改(确认段直调 core_ro.get_nav_on,取 T−1 路径随 v1.0 convert_fund 一并删); ④ test_convert_integration 改写推迟到 T-9(需端到端真接口); ⑤ 受理单置 confirmed 并入 apply_convert 同事务(防「批次已扣、状态未置」中间态); ⑥ MySQL rowcount=changed rows 陷阱(nav_pending 重试不得复用冲突判定)。 - 交接文档 §B.11:T-6→T-7 完成、基线 797→827、真库 36/36→37/37 与 83/83、 新增 T-7 实施期发现段、下一步 T-8/T-9(并注明 T-8 范围已缩小)。 - docs/memory/TODO.md:进度行 + T-6 真库数 + T-7 条目勾选与详述。 - .workbuddy/memory/MEMORY.md 与 docs/memory/MEMORY.md:进度与关键裁定同步; 当日工作日志补「续 3:T-7 确认段落地」。
This commit is contained in:
@@ -13,7 +13,7 @@
|
||||
|
||||
**⚡ 基金转换(convert)线 — 两条子线**:
|
||||
- **(一)v0.x 两阶段实时模型(已结项 2026-09-10)**:PRD **v0.9.3** + 架构 **v1.0.1** + 开发计划 **v1.0**,T-0 ~ T-13 全部完成(第 5+6 步闭环,最终 **739 passed / 10 skipped**,`CONVERT_STRESS=1` 并发 9/9,含死锁重试补丁 `43cf2a1`);**该模型已被下一线取代,其 PRD/架构/开发计划作废,代码保留作过渡基线**。
|
||||
- **(二)下一线 · T+1 受理/确认分离模型(进行中 · 2026-09-11)**:入口 **交接文档.md §B.11**(10 项真实业务拍板)· PRD **v1.1** + 架构 **v2.1** 已整体重写并经独立 AI 联网审查通过(0 阻断级),**已定稿**(2026-09-11 用户批准);**第 4 步开发计划 v2.0 已整体重做**(`docs/项目框架设计/开发计划-基金转换交易.md`,797 行:T-0~T-17 按架构 §15 重排 + §1.4 代码事实核对表 F-1~F-25 + §1.5 实现级裁定 R-1~R-15 + §5 十六条回归面 + §6 验收 31 条 + FR-C29/C30 全映射),**经三轮独立审核闭环(第一轮挑毛病 2 阻断+5 重要+3 可选 / 第二轮验证型 12 项零残留 / 第三轮白纸重审 C1~C5+O1~O4 + 验证型复核 22/22 落位),已定稿(2026-09-11 用户批准)**。**核心认知:不新增冻结列,在途占用由受理单推导;紧池 80% 病根在 T+1 串行确认下自动消失。** 下一步:**第 5 步 todo 开发进行中(T-1~T-6 ✅,797 绿,下一步 T-7)**。撤单范围:PRD §5.5 原表述与实现(仅 `accepted`)不矛盾、无需回填(第三轮 C1 订正)。已就绪:`fetch_nav.py` / `06-seed-nav.sql`(60 个真实净值日)/ `gen_trade_calendar.py` / `10-seed-trade-calendar.sql`(503 交易日)。
|
||||
- **(二)下一线 · T+1 受理/确认分离模型(进行中 · 2026-09-11)**:入口 **交接文档.md §B.11**(10 项真实业务拍板)· PRD **v1.1** + 架构 **v2.1** 已整体重写并经独立 AI 联网审查通过(0 阻断级),**已定稿**(2026-09-11 用户批准);**第 4 步开发计划 v2.0 已整体重做**(`docs/项目框架设计/开发计划-基金转换交易.md`,797 行:T-0~T-17 按架构 §15 重排 + §1.4 代码事实核对表 F-1~F-25 + §1.5 实现级裁定 R-1~R-15 + §5 十六条回归面 + §6 验收 31 条 + FR-C29/C30 全映射),**经三轮独立审核闭环(第一轮挑毛病 2 阻断+5 重要+3 可选 / 第二轮验证型 12 项零残留 / 第三轮白纸重审 C1~C5+O1~O4 + 验证型复核 22/22 落位),已定稿(2026-09-11 用户批准)**。**核心认知:不新增冻结列,在途占用由受理单推导;紧池 80% 病根在 T+1 串行确认下自动消失。** 下一步:**第 5 步 todo 开发进行中(T-1~T-7 ✅,**827 passed / 10 skipped** 零失败;T-6 真库 verify **37/37**、T-7 真库 verify **83/83**,退出码均 0;下一步 T-8 `rules.amount_view` / T-9 api 层 —— 注意引擎「时机」部分已在 T-7 由 `engine_call.py` 完成,全仓 `process_convert_event(` 恰 1 处调用)**。**T-7 关键裁定:强制全转属受理段决策** —— 受理由 `plan_lots` 判定并把 `qty` 收敛为实际全转量 + 受理单 `remark='full_transfer'`,确认段**只继承不重判**(`plan_lots` 不传 `min_hold_qty`);重判会因 T→T+1 可用份额变化(部分成交/他人申赎/产品参数改)得出与受理承诺不一致的结论(擅自扩大客户指令)。撤单范围:PRD §5.5 原表述与实现(仅 `accepted`)不矛盾、无需回填(第三轮 C1 订正)。已就绪:`fetch_nav.py` / `06-seed-nav.sql`(60 个真实净值日)/ `gen_trade_calendar.py` / `10-seed-trade-calendar.sql`(503 交易日)。
|
||||
**仓库地图:**
|
||||
|
||||
| 路径 | 状态 | 说明 |
|
||||
@@ -201,7 +201,7 @@ RBAC 联调账号:scripts/dev/rbac-seed-reference.md
|
||||
3. 是否需 customer_id 归属与 JWT RBAC?
|
||||
4. Core 是模拟库只读还是 agent 库读写?
|
||||
5. 如何验证?(`python -m pytest` 全量(当前 **739 passed / 10 skipped**,基线 510)· uvicorn 启动 + /health · SQL / sync 脚本 · 对照 REQUIREMENTS 验收列)
|
||||
6. **当前有哪两条并行线?**(① 风控/架构改进线:**已结项**(510 基线绿、§7.2 七项冒烟 7/7 PASS、`037ce7e` 已核实早已推送);② **基金转换线**:v0.x 实时模型已结项(739 绿,**已被 T+1 模型取代**);**下一线 T+1 受理/确认分离模型进行中(2026-09-11)**:PRD v1.1 / 架构 v2.1 / 开发计划 v2.0 重写完毕并经独立审查收敛,**已定稿**(2026-09-11 用户批准),批准后进第 5 步 todo 开发(T-1~T-17))——动代码前先确认自己属于哪条线,别混淆前置条件。
|
||||
6. **当前有哪两条并行线?**(① 风控/架构改进线:**已结项**(510 基线绿、§7.2 七项冒烟 7/7 PASS、`037ce7e` 已核实早已推送);② **基金转换线**:v0.x 实时模型已结项(739 绿,**已被 T+1 模型取代**);**下一线 T+1 受理/确认分离模型进行中(2026-09-11)**:PRD v1.1 / 架构 v2.1 / 开发计划 v2.0 重写完毕并经独立审查收敛,**已定稿**(2026-09-11 用户批准),批准后进第 5 步 todo 开发(T-1~T-17;**当前进度 T-1~T-7 ✅,827 绿**))——动代码前先确认自己属于哪条线,别混淆前置条件。
|
||||
7. **远程分支到底还在不在?**(**在**。`git ls-remote --heads origin` 实测 `refs/heads/risk-control-agent` = `fffb78a`。⚠️ **判断远程存亡只能用 `git ls-remote`** —— 2026-09-10 **同日误报两次**,勿再踩。)
|
||||
**本仓特有异常(2026-09-10 深挖确认,别误判为 stale ref)**:`.git/refs/remotes/**` **写入不落盘** ——
|
||||
`git update-ref refs/remotes/origin/X <sha>` 返回 0,但松散引用消失,**且整个 `refs/remotes/origin/` 目录被删**
|
||||
|
||||
+3
-3
@@ -9,7 +9,7 @@
|
||||
|
||||
**⚡ 并行新线 · 基金转换(convert)**—— **两条子线**:
|
||||
- **(一)v0.x 两阶段实时模型(已结项 2026-09-10)**:PRD **v0.9.3** + 架构 **v1.0.1** + 开发计划 **v1.0**,**T-0 ~ T-13 全部完成**(第 5 步 + 第 6 步闭环,**736 passed / 10 skipped**;7 个 convert 真库脚本复跑零回归;压测修复 2 处并发缺陷 + 死锁重试后补 `43cf2a1` 最终 **739 passed / 10 skipped**)。**注:该模型已被下一线取代(按下述),其设计文档作废,代码仍保留作过渡基线**。
|
||||
- **(二)下一线 · T+1 受理/确认分离模型(进行中 · 2026-09-11)**:入口 **交接文档.md §B.11** · PRD **v1.1** + 架构 **v2.1** 均已整体重写并经独立 AI 联网审查通过(0 阻断级),**已定稿**(2026-09-11 用户批准);**第 4 步开发计划 v2.0 已整体重做(`docs/项目框架设计/开发计划-基金转换交易.md`,797 行,T-1~T-17 按架构 §15 重排 + 代码事实 F-1~F-25 + 裁定 R-1~R-15 + 16 条回归面 + 验收 31 条 + FR-C29/C30 全映射),经三轮独立审核闭环(挑毛病 / 验证型 / 白纸重审 + 验证型复核 22/22 落位),已定稿(2026-09-11 用户批准)**。**第 5 步 todo 开发已开工(2026-09-11):T-1 ~ T-6 完成(全量 pytest 797 passed / 10 skipped 零失败;T-6 真库 verify 36/36 退出码 0),下一步 T-7(三段编排 + confirm_service,核心重写)**。**待用户确认开工 T-7**。撤单范围:PRD §5.5 原表述与实现(仅 `accepted`)不矛盾、无需回填(第三轮 C1 订正)。
|
||||
- **(二)下一线 · T+1 受理/确认分离模型(进行中 · 2026-09-11)**:入口 **交接文档.md §B.11** · PRD **v1.1** + 架构 **v2.1** 均已整体重写并经独立 AI 联网审查通过(0 阻断级),**已定稿**(2026-09-11 用户批准);**第 4 步开发计划 v2.0 已整体重做(`docs/项目框架设计/开发计划-基金转换交易.md`,T-1~T-17 按架构 §15 重排 + 代码事实 F-1~F-25 + 裁定 R-1~R-15 + 16 条回归面 + 验收 31 条 + FR-C29/C30 全映射),经三轮独立审核闭环(挑毛病 / 验证型 / 白纸重审 + 验证型复核 22/22 落位),已定稿(2026-09-11 用户批准)**。**第 5 步 todo 开发已开工(2026-09-11):T-1 ~ T-7 完成(全量 pytest 827 passed / 10 skipped 零失败;T-6 真库 verify 37/37、T-7 真库 verify 83/83,退出码均 0),下一步 T-8(`rules.amount_view`;引擎时机部分已在 T-7 完成)/ T-9(api 层)**。撤单范围:PRD §5.5 原表述与实现(仅 `accepted`)不矛盾、无需回填(第三轮 C1 订正)。
|
||||
|
||||
### 基金转换线待办(推荐顺序)
|
||||
|
||||
@@ -32,8 +32,8 @@
|
||||
- [x] **T-3 数据层 ✅**:`core_ro` 加 6 方法(含 `get_nav_on` 精确匹配、`sum_inflight_qty`、`is_open`、`get_share_rule`);`share_lot_repository` 加 `available_qty_with_inflight`;新建 `convert_request_repository.py`(6 态条件 UPDATE);修 1 处生产 bug(`sum_inflight_qty` 列名 `product_id`→`from_product_id`)
|
||||
- [x] **T-4 语义收窄 ✅**:`convert_repository` 新增唯一写入口 **`sync_mirror`**(三步法幂等重写;status 只允许 pending/completed/failed,写 cancelled/expired 直接 ValueError);v1.0 遗留 `insert_placeholder`/`complete_convert`/`mark_failed` 标 Deprecated(T-7 后删除);状态迁移职责归 `convert_request_repository.transition_status`
|
||||
- [x] **T-5 锁原语 ✅**:新增 `app/service/convert/trading_calendar.py`(纯函数包,`is_open` 谓词注入,不查库)+ 单测;`locks.py` 补锁键单一事实源;受理接入 `run_locked`
|
||||
- [x] **T-6 受理事务 ✅**:`accept_convert` 八步落地(幂等前置 → 产品/份额/适当性 → 受理日顺延 R-5 → 可用份额 R-3 → 落 `core_convert_request(accepted)` → 镜像 + 审计 → 202 回执);新增 `tests/test_convert_accept.py`;**真库 `verify_convert_accept.py` 36/36 一致(退出码 0)**
|
||||
- [ ] **T-7 三段编排 + `confirm_service`(核心重写)** —— **下一步**:确认事务 9 步(T 日净值精确匹配 → T+1 适当性复核 → FIFO 扣批 → 部分成交 R-10 → 折算 → 2 条流水 + 明细 → 两端持仓 → confirmed → 引擎恰一次)+ `confirm_batch` 串行批处理;DoD 要求 `verify_convert_confirm.py` 真库 8 条
|
||||
- [x] **T-6 受理事务 ✅**:`accept_convert` 八步落地(幂等前置 → 产品/份额/适当性 → 受理日顺延 R-5 → 可用份额 R-3 → 落 `core_convert_request(accepted)` → 镜像 + 审计 → 202 回执);新增 `tests/test_convert_accept.py`;**真库 `verify_convert_accept.py` 37/37 一致(退出码 0)**
|
||||
- [x] **T-7 三段编排 + `confirm_service`(核心重写)✅(2026-09-11,提交 `048f1a9`)**:新增 `confirm_service.py`(`confirm_one` 8 步:读单+状态闸门 → T 日净值精确匹配(缺→`nav_pending`)→ 产品复核 + T+1 适当性复核 → 部分成交 R-10 → FIFO 扣批 + 折算 → 确认事务(扣批次 + 2 流水 + 转入批次 + 两端持仓 + 明细 + 受理单置 `confirmed`,同事务,`rowcount!=1` → `ConfirmConflict` 整体回滚)→ 引擎恰好一次(commit 后,异常不阻断)→ 镜像 + 审计;`confirm_batch`:整批锁 + 业务日捞单窗口 + 串行 + 单笔容错);抽出 `format.py`/`audit.py`/`engine_call.py` 三个共用出口;`convert_service` 加 `cancel_convert`(T 日撤单两道闸门)+ `_t1_t2_dates`,受理响应改 PRD §5.3.1 字段;`convert_core_repository.ConvertApplyInput` 加 `convert_request_id`/`diff_fee`/`request_remark` 并内置 `_confirm_request` 状态守卫;`convert_request_repository` 加 `_end_of_day` 闭区间 + `reject()`。**单测 `tests/test_convert_confirm.py`(24 例)+ 真库 `verify_convert_confirm.py` 83/83 一致(含 PRD §5.3.2 示例真库逐字节重放)**;全量 **827 passed / 10 skipped**。**关键裁定(计划缺口,已回写开发计划)**:强制全转是受理段决策,受理单 `remark='full_transfer'` 传承,确认段**只继承不重判**(`plan_lots` 不传 `min_hold_qty`)—— 重判会因 T→T+1 可用份额变化擅自扩大客户指令。
|
||||
- [ ] T-8 ~ T-17(引擎时机 / API 受理接口 / 撤单 / 调换 / 工具 / 补偿 / 回归 / D27 产品级舍入 / D28 巨额赎回 / D29 资金流中转 / D30 A/C 互转)
|
||||
|
||||
> **第 0~2 批结果(2026-09-10)**:基线 **510 passed** → 批 0 后 **516 passed / 3 skipped**(+3 T-0 用例 +3 T-0b 引擎用例)→ 批 1(T-1)后**仍 516 passed / 3 skipped**(只加表与种子,未加用例 → **零回归**);**T-1 数据层断言 8/8 PASS**(含新增断言 ⑧:费率档 ↔ `product_type` 匹配,越档即 FAIL)→ 批 2(T-2 + T-2b)后 **609 passed / 3 skipped**(**+93 纯函数用例**,零回归);T-2b 实算脚本 15/15 与 PRD §5.3 一致(退出码 0)。
|
||||
|
||||
@@ -453,19 +453,58 @@
|
||||
**依赖**:T-2 ~ T-6
|
||||
|
||||
**DoD**:真库 verify 脚本 `verify_convert_confirm.py`:
|
||||
- [ ] 确认:`core_share_lot.remain_qty` 扣减、`core_trade` 恰 2 行同 gid、两端 `core_holding` 更新、状态 `confirmed`(验收 2/10/24)
|
||||
- [ ] 重复触发 confirm_batch 同 as_of:第二次 0 处理,流水不重复(验收 24 后半 / 15)
|
||||
- [ ] 缺 T 日净值:状态 `nav_pending`、无流水、`remain_qty` 不变;补 nav 后重跑 → `confirmed`(验收 25)
|
||||
- [ ] T+1 复核不通过 → `rejected` + 占用释放(验收 26)
|
||||
- [ ] 部分成交:占用被抢 → `actual_qty < qty`、remark='partial'、未确认部分占用释放(验收 30)
|
||||
- [ ] 跨批次:各批按持有期计费、明细落 `core_convert_lot_detail`(验收 8)
|
||||
- [ ] 确认事务内**不写** `core_cash_flow`(资金流写入唯一归属 T-16,反双重归属;若 T-16 未落地此断言恒守住)
|
||||
- [ ] 引擎恰好跑一次:`risk_alert` 1 条、RISK-002 不翻倍(验收 5/7/29)
|
||||
- [ ] pytest 重写用例全绿;**全量回归 739+(含 test_convert_integration 改写)**
|
||||
- [x] 确认:`core_share_lot.remain_qty` 扣减、`core_trade` 恰 2 行同 gid、两端 `core_holding` 更新、状态 `confirmed`(验收 2/10/24)
|
||||
- [x] 重复触发 confirm_batch 同 as_of:第二次 0 处理,流水不重复(验收 24 后半 / 15)
|
||||
- [x] 缺 T 日净值:状态 `nav_pending`、无流水、`remain_qty` 不变;补 nav 后重跑 → `confirmed`(验收 25)
|
||||
- [x] T+1 复核不通过 → `rejected` + 占用释放(验收 26)
|
||||
- [x] 部分成交:占用被抢 → `actual_qty < qty`、remark='partial'、未确认部分占用释放(验收 30)
|
||||
- [x] 跨批次:各批按持有期计费、明细落 `core_convert_lot_detail`(验收 8)
|
||||
- [x] 确认事务内**不写** `core_cash_flow`(资金流写入唯一归属 T-16,反双重归属;若 T-16 未落地此断言恒守住)
|
||||
- [x] 引擎恰好跑一次:`risk_alert` 1 条、RISK-002 不翻倍(验收 5/7/29)
|
||||
- [x] pytest 重写用例全绿;**全量回归 739+(含 test_convert_integration 改写)**
|
||||
|
||||
**风险**:确认事务变长(扣批次 + 流水 + 持仓 + 资金流)→ 死锁概率↑(沿用 1213 重试外壳 43cf2a1);nav_pending 无限挂起(SLA 兜底 T-12);并发双跑(锁 + 条件 UPDATE 双守卫)
|
||||
**回滚点**:受理单可撤(确认前);本任务改动面大,先基线快照再改
|
||||
|
||||
**执行记录(2026-09-11 · 提交 `048f1a9`)**
|
||||
|
||||
真库 `verify_convert_confirm.py` **83 项一致 / 0 不一致**;全量 pytest **827 passed / 10 skipped**(T-6 基线 798)。
|
||||
基准日取日历中位开市日(本次实跑 T=2027-01-14 / T+1=2027-01-15),并用 PRD §5.3.2 示例输入在真库上
|
||||
**逐字节重放**:`68020.00 / 612.18 / 67407.82 / 333.36 / 67074.46 / 34945.54 / -0.0049`。
|
||||
|
||||
与计划的差异与裁定(**均已在代码注释与本节留痕**):
|
||||
|
||||
1. **确认段不做最低持有重判(计划缺口 · 本次新发现)**。计划 ①-⑧ 未指明确认段是否重跑
|
||||
`plan_lots` 的最低持有判定。实测暴露:受理段已把 `qty` **收敛为实际全转量**(申请 48000
|
||||
→ 落库 50000),确认段若重判会因 `leftover = 0` 得出 `forced_full_transfer = False`(漏报);
|
||||
更危险的是 T→T+1 之间可用份额变化(部分成交 / 他人申赎 / 产品参数改)会让重判得出与
|
||||
**受理承诺不一致**的结论 —— 例如可用涨到 60000 后反被判「留 12000 < 新阈值」而擅自
|
||||
把客户指令扩大成全转。**裁定:强制全转是受理段决策**,受理段把结论落受理单
|
||||
`remark='full_transfer'`(新增常量 `REMARK_FULL_TRANSFER`),确认段**只继承、不重判**
|
||||
(`plan_lots` 不传 `min_hold_qty`)。`remark` 支持多标记 `;` 连接,
|
||||
故部分成交的强制全转单记 `full_transfer;partial`。用例守护:
|
||||
`test_confirm_does_not_promote_to_full_transfer`。
|
||||
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` 与三处消费方同步。
|
||||
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 一并删除。
|
||||
4. **`test_convert_integration.py` 未改写**:其现状依赖 v1.0 `convert_fund` 全链路;
|
||||
T-7 另起 `tests/test_convert_confirm.py`(24 例)覆盖确认段。integration 改写与本计划
|
||||
「test_convert_service 重写」一并在 **T-9(api 层落地后)** 做,届时端到端才有真接口可打。
|
||||
5. **确认事务原子性口径收窄**:计划 ⑧「条件 UPDATE 置 confirmed」在实现中**并入
|
||||
`apply_convert` 同一事务**(`ConvertApplyInput.convert_request_id` + gateway 内
|
||||
`_confirm_request`),`rowcount != 1` → 抛 `ConfirmConflict` 整事务回滚。若按计划放在
|
||||
事务外,会出现「批次已扣、受理单未置位」的中间态(超扣风险)。
|
||||
6. **MySQL `rowcount` = changed rows 陷阱**:`nav_pending` 重试时
|
||||
`SET status='nav_pending' WHERE status='nav_pending'` 返回 0,直接复用 `transition_status`
|
||||
的冲突判定会把**正常重试误判为并发冲突**。已修为「状态未变则不迁移」+ 返回 `transitioned`
|
||||
标志(sqlite 返回 1、MySQL 返回 0 的方言差异由此抹平)。
|
||||
|
||||
---
|
||||
|
||||
### T-8 · 引擎时机改(确认后跑一次)
|
||||
|
||||
@@ -589,6 +589,20 @@ def main() -> int:
|
||||
_confirm(gid_f, confirm_at, next_day, engine_hook=_hook)
|
||||
check("重放不再投递引擎(仍 1 次)", len(calls), 1)
|
||||
|
||||
# F2:真实引擎(不注入 hook)+ 重放不翻倍 —— 验收 5/7/29 的真库侧
|
||||
reset_shares(core_admin, CUSTOMER, day)
|
||||
gid_f2 = _accept(_base_req(client_request_id="CVF-REQ-F2"), submit_at)["convert_group_id"]
|
||||
res_f2 = _confirm(gid_f2, confirm_at, next_day)
|
||||
check("真实引擎路径确认成功", res_f2["status"], "confirmed")
|
||||
alerts_before = q1(
|
||||
agent_admin, "SELECT COUNT(*) FROM risk_alert WHERE customer_id = :c", c=CUSTOMER
|
||||
)
|
||||
_confirm(gid_f2, confirm_at, next_day)
|
||||
alerts_after = q1(
|
||||
agent_admin, "SELECT COUNT(*) FROM risk_alert WHERE customer_id = :c", c=CUSTOMER
|
||||
)
|
||||
check("重放不新增 risk_alert(RISK-002 不翻倍)", alerts_after, alerts_before)
|
||||
|
||||
# ══ G. 真库专属约束 ══
|
||||
print("\n【G】真库专属:ENUM 严校验 / 精度 / 索引")
|
||||
enum_err = None
|
||||
|
||||
Reference in New Issue
Block a user