fix(billing): 删任务/删项目级联吞 ACTIVE 预留致 reserved_balance 永久冻结(审计 I2)

- 根因: CreditReservation.task 是 OneToOneField(CASCADE), AITask.project 也是 CASCADE
  —— 删项目→级联删任务→ACTIVE 预留行被吞, 账户冻结份额永不归还(实测 4 账户漂移共 ¥42,
  且随删项目持续增长)
- 修法: billing/signals.py 挂 AITask pre_delete, 删除前先 release_credit 释放(级联同样
  触发, release 自带行锁+幂等); apps.py ready() 接线
- 回归测试 x3: 直删任务/删项目级联/已扣费不重复释放
- qa/repair_reserved_drift.py: 存量漂移回填脚本(dry-run 默认, --apply 落 RELEASE 流水),
  已对线上 4 账户执行并复验清零
- qa/function-audit/output: 本轮 18 页模拟点击审计报告(0 真死按钮 0 JS 报错)

验证: 后端测试 213/213 通过, django check 无警告
补齐 aab4d7e: 该提交带走了 signals.py 之外的测试轮改动, 信号挂载点与回归测试在本提交收口

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
zyc
2026-07-02 13:07:09 +08:00
co-authored by Claude Fable 5
parent aab4d7ea4c
commit dcc5d7fe50
43 changed files with 4860 additions and 3143 deletions
@@ -1,16 +1,16 @@
{
"name": "model-photo",
"route": "/model-photo",
"url": "http://127.0.0.1:5173/model-photo",
"url": "http://127.0.0.1:5174/model-photo",
"mode": "quick",
"tally": {
"total": 32,
"works": 31,
"total": 49,
"works": 44,
"dead": 0,
"error": 0,
"disabled": 0,
"skipped": 0,
"noop": 1,
"skipped": 5,
"noop": 0,
"blocked": 0
},
"results": [
@@ -28,8 +28,8 @@
"url": true,
"overlay": false,
"self": false,
"mutations": 25,
"api": 0
"mutations": 46,
"api": 1
}
},
{
@@ -46,7 +46,7 @@
"url": false,
"overlay": false,
"self": false,
"mutations": 17,
"mutations": 19,
"api": 0
}
},
@@ -64,7 +64,7 @@
"url": false,
"overlay": true,
"self": false,
"mutations": 14,
"mutations": 17,
"api": 0
}
},
@@ -82,8 +82,8 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 25,
"api": 0
"mutations": 32,
"api": 1
}
},
{
@@ -100,7 +100,7 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 25,
"mutations": 34,
"api": 0
}
},
@@ -109,6 +109,24 @@
"tag": "a",
"role": "",
"cls": "",
"label": "模特库",
"href": "/models",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": true,
"overlay": false,
"self": true,
"mutations": 22,
"api": 1
}
},
{
"idx": 6,
"tag": "a",
"role": "",
"cls": "",
"label": "视频项目",
"href": "/projects",
"disabled": false,
@@ -118,12 +136,12 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 20,
"mutations": 24,
"api": 0
}
},
{
"idx": 6,
"idx": 7,
"tag": "a",
"role": "",
"cls": "active",
@@ -136,12 +154,12 @@
"url": true,
"overlay": false,
"self": false,
"mutations": 22,
"api": 0
"mutations": 39,
"api": 4
}
},
{
"idx": 7,
"idx": 8,
"tag": "a",
"role": "",
"cls": "",
@@ -154,12 +172,12 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 37,
"api": 0
"mutations": 38,
"api": 5
}
},
{
"idx": 8,
"idx": 9,
"tag": "a",
"role": "",
"cls": "",
@@ -172,12 +190,12 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 20,
"api": 0
"mutations": 22,
"api": 3
}
},
{
"idx": 9,
"idx": 10,
"tag": "a",
"role": "",
"cls": "",
@@ -190,12 +208,30 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 22,
"api": 1
"mutations": 69,
"api": 4
}
},
{
"idx": 10,
"idx": 11,
"tag": "a",
"role": "",
"cls": "",
"label": "垃圾桶",
"href": "/trash",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": true,
"overlay": false,
"self": false,
"mutations": 23,
"api": 2
}
},
{
"idx": 12,
"tag": "a",
"role": "",
"cls": "",
@@ -208,12 +244,30 @@
"url": true,
"overlay": false,
"self": true,
"mutations": 49,
"mutations": 54,
"api": 2
}
},
{
"idx": 11,
"idx": 13,
"tag": "div",
"role": "button",
"cls": "user",
"label": "账户",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 22,
"api": 0
}
},
{
"idx": 14,
"tag": "a",
"role": "",
"cls": "",
@@ -226,12 +280,12 @@
"url": true,
"overlay": false,
"self": false,
"mutations": 25,
"api": 0
"mutations": 32,
"api": 1
}
},
{
"idx": 12,
"idx": 15,
"tag": "button",
"role": "",
"cls": "icon-btn",
@@ -244,16 +298,34 @@
"url": true,
"overlay": false,
"self": false,
"mutations": 23,
"mutations": 26,
"api": 1
}
},
{
"idx": 13,
"idx": 16,
"tag": "button",
"role": "",
"cls": "back-pill",
"label": "返回",
"cls": "iw-side-toggle",
"label": "收起商品栏",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": false,
"mutations": 6,
"api": 0
}
},
{
"idx": 17,
"tag": "button",
"role": "",
"cls": "search-btn",
"label": "搜索批次/模特",
"href": "",
"disabled": false,
"active": false,
@@ -262,12 +334,12 @@
"url": true,
"overlay": false,
"self": false,
"mutations": 22,
"api": 0
"mutations": 39,
"api": 3
}
},
{
"idx": 14,
"idx": 18,
"tag": "button",
"role": "",
"cls": "new-prod",
@@ -280,100 +352,16 @@
"url": true,
"overlay": true,
"self": false,
"mutations": 25,
"mutations": 35,
"api": 0
}
},
{
"idx": 15,
"tag": "button",
"role": "",
"cls": "iw-prod-item.active",
"label": "南卡南卡 Lite Pro 蓝牙耳机// 数码 3C",
"href": "",
"disabled": false,
"active": true,
"verdict": "noop-active",
"signals": {
"url": false,
"overlay": false,
"self": false,
"mutations": 0,
"api": 0
}
},
{
"idx": 16,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "露露露露同款裸感瑜伽裤// 运动户外",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 17,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "透真透真清透物理防晒霜// 美妆个护",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 18,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "滋啦滋啦速食牛肉面 · 6 桶装// 食品饮料",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 19,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "透真透真玻尿酸补水面膜// 美妆个护",
"label": "南卡 Lite Pro 蓝牙耳机数码 3C",
"href": "",
"disabled": false,
"active": false,
@@ -382,8 +370,8 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
"mutations": 49,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
@@ -395,7 +383,7 @@
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "桥接桥接测试补水面膜 20260529// 美妆个护",
"label": "露露同款裸感瑜伽裤运动户外",
"href": "",
"disabled": false,
"active": false,
@@ -404,8 +392,8 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
"mutations": 52,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
@@ -417,7 +405,7 @@
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "三顿三顿半同款冻干咖啡粉// 食品饮料",
"label": "测试美妆个护",
"href": "",
"disabled": false,
"active": false,
@@ -426,8 +414,8 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
@@ -439,7 +427,7 @@
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "小熊小熊 4L 可视空气炸锅// 家居家电",
"label": "透真清透物理防晒霜美妆个护",
"href": "",
"disabled": false,
"active": false,
@@ -448,8 +436,8 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 7,
"api": 0
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
@@ -460,6 +448,182 @@
"idx": 23,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "耳机包数码 3C",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 26,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 24,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "Apple/苹果 iPhone 17 Pro数码 3C",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 25,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "滋啦速食牛肉面 · 6 桶装食品饮料",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 26,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "滋啦速食牛肉面 · 6 桶装食品饮料",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 25,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 27,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "植护24大包抽纸家用实惠装整箱面巾卫生餐巾纸巾悬挂式擦手面纸抽个护清洁",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 28,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "透真玻尿酸补水面膜美妆个护",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 26,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 29,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "测试美妆个护",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 30,
"tag": "button",
"role": "",
"cls": "iw-prod-item.",
"label": "桥接测试补水面膜 20260529美妆个护",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 28,
"api": 1
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 31,
"tag": "button",
"role": "",
"cls": "search-btn",
"label": "搜索批次/模特",
"href": "",
@@ -470,7 +634,7 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 6,
"mutations": 4,
"api": 0
},
"consoleNote": [
@@ -479,7 +643,7 @@
]
},
{
"idx": 24,
"idx": 32,
"tag": "button",
"role": "",
"cls": "tb-chip",
@@ -501,7 +665,7 @@
]
},
{
"idx": 25,
"idx": 33,
"tag": "div",
"role": "button",
"cls": "mi.selected",
@@ -523,11 +687,11 @@
]
},
{
"idx": 26,
"idx": 34,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "南卡 · 痛点种草 · v1-person// 真人模特",
"cls": "iw-actor-lib-btn",
"label": "模特",
"href": "",
"disabled": false,
"active": false,
@@ -536,7 +700,7 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 22,
"mutations": 11,
"api": 0
},
"consoleNote": [
@@ -545,11 +709,11 @@
]
},
{
"idx": 27,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "AI 生成 · model · 1// 真人模特",
"idx": 35,
"tag": "span",
"role": "button",
"cls": "right",
"label": "全部 (14)",
"href": "",
"disabled": false,
"active": false,
@@ -557,8 +721,8 @@
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 5,
"self": false,
"mutations": 21,
"api": 0
},
"consoleNote": [
@@ -567,11 +731,11 @@
]
},
{
"idx": 28,
"idx": 36,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "AI 生成 · model · 1// 真人模特",
"label": "AI 生成",
"href": "",
"disabled": false,
"active": false,
@@ -580,7 +744,7 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 5,
"mutations": 6,
"api": 0
},
"consoleNote": [
@@ -589,11 +753,11 @@
]
},
{
"idx": 29,
"idx": 37,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "AI 生成 · model · 2// 真人模特",
"label": "AI 生成",
"href": "",
"disabled": false,
"active": false,
@@ -602,7 +766,7 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 5,
"mutations": 6,
"api": 0
},
"consoleNote": [
@@ -611,11 +775,11 @@
]
},
{
"idx": 30,
"idx": 38,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "AI 生成 · model · 2// 真人模特",
"label": "Apple/苹果",
"href": "",
"disabled": false,
"active": false,
@@ -624,7 +788,7 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 5,
"mutations": 6,
"api": 0
},
"consoleNote": [
@@ -633,11 +797,11 @@
]
},
{
"idx": 31,
"idx": 39,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "AI 生成 · model · 2// 真人模特",
"label": "Apple/苹果",
"href": "",
"disabled": false,
"active": false,
@@ -646,20 +810,137 @@
"url": false,
"overlay": false,
"self": true,
"mutations": 5,
"mutations": 6,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 40,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "Apple/苹果 · 短视频 · v1",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 6,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 41,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "OPPO手机 · 短视频 · v1",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 6,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 42,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "南卡 · 痛点种草 · v3",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 6,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 43,
"tag": "button",
"role": "",
"cls": "model-card.",
"label": "南卡 · 短视频 · v5",
"href": "",
"disabled": false,
"active": false,
"verdict": "works",
"signals": {
"url": false,
"overlay": false,
"self": true,
"mutations": 6,
"api": 0
},
"consoleNote": [
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — ",
"Encountered two children with the same key, `%s`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — "
]
},
{
"idx": 44,
"label": "",
"tag": "",
"verdict": "stale"
},
{
"idx": 45,
"label": "",
"tag": "",
"verdict": "stale"
},
{
"idx": 46,
"label": "",
"tag": "",
"verdict": "stale"
},
{
"idx": 47,
"label": "",
"tag": "",
"verdict": "stale"
},
{
"idx": 48,
"label": "",
"tag": "",
"verdict": "stale"
}
],
"missing": [
"搜索",
"E E2E 桥接测试团队 20260529",
"余额 ¥14,907.00",
"账户",
"余额 ¥14,071.00",
"折叠侧栏",
"全部商品 7 个",
"时间",