fix(douyu): 加固高价值三态迁移与状态口径

修复迁移中断重跑、旧快照回填覆盖、降级将 unknown 误写成可兑换,以及迁移前 CK 已失效账号未作废旧结论的问题。统一 CK error 的展示与筛选口径,补齐旧快照迁移和兑换兜底反向用例,并同步高价值结论时间语义。同时纳入 .gitignore 更新。
This commit is contained in:
yml2213
2026-11-06 13:25:45 +08:00
parent c9fbbdb828
commit 578e259eea
13 changed files with 286 additions and 68 deletions
+3 -2
View File
@@ -88,7 +88,8 @@ def high_value_needs_refresh_expr(
和「资料是否过期」是**两件事**:
- ``overview_queried_at`` 说「上次一键查询是什么时候」;
- ``high_value_checked_at`` 说「上次**成功读到官方商品状态**是什么时候」。
- ``high_value_checked_at`` 说「上次形成高价值结论是什么时候」;
结论可以是 ``unknown``。
两者会脱钩 —— 比如一键查询里商品接口单独失败(其它项都拿到了),
资料时间被刷新了,高价值时间却停在原地。再比如 CK 失效那段时间查不动,
@@ -103,7 +104,7 @@ def high_value_needs_refresh_expr(
而「可兑换」随时会变;
- **结论被作废**(状态是 ``unknown``,比如 CK 失效期间被作废):
按 ``unknown_seconds`` 慢速重试;
- **从来没查到过**(``checked_at IS NULL``):**不算**。那种情况要么
- **从来没形成过结论**(``checked_at IS NULL``):**不算**。那种情况要么
账号确实没查过资料(本来就该被选中),要么商品接口对这个账号稳定失败
(没配 manualID、账号没有宝典)—— 后者若每轮都重选,同一批账号会
反复撞墙,挤掉真正有新欠账的账号。它由「资料过期」那条兜着就够了。
@@ -10,9 +10,9 @@
## 为什么「是否已拥有」能直接查官方
`query_limited_goods` 返回的商品项里 `count` / `foreverCount` / `storeStatus`
是**账号维度**的(不是全局库存)—— 已用生产镜像库实测,见
`extract_high_value_goods` 的文档。
`storehome` 商品项里的账号级 `status`(0=可兑换、1=已达上限)才是唯一判据。
`count` / `foreverCount` / `storeStatus` 是全局库存或商店状态,不能拿来判断
当前账号是否已经兑换。
## 诚实边界
@@ -355,7 +355,7 @@ class OverviewMixin:
goods_query_ok = True
except Exception as exc: # noqa: BLE001
errors["limited_goods"] = _err(exc)
# 商品列表带有 status 准入状态,结合兑换记录在后文判定高价值资产
# 商品列表带有账号级 status;兑换记录只作历史展示,不参与准入判定。
pending_goods = goods_items
# ---- 角色绑定状态(三个作用域都查)----
+6 -5
View File
@@ -221,8 +221,8 @@ def invalidate_high_value(account: Account) -> None:
那条陈旧的「可换」会**重新显示成绿色**,运营就会拿着一份失效结论去兑换。
所以作废是**单向**的:写 ``unknown``,等下一次真的读到官方 ``storehome``
再写回真实的 ``available``/``owned``。``checked_at`` 保留(那确实是
「上次成功读到官方状态」的时间),但结论本身已经不算数。
再写回真实的 ``available``/``owned``。``checked_at`` 保留它作为
「上次形成结论」的时钟,但结论本身已经不算数。
"""
for key in HIGH_VALUE_KEYS:
setattr(account, f"high_value_{key}_status", HIGH_VALUE_STATUS_UNKNOWN)
@@ -236,9 +236,10 @@ def high_value_payload(
checked_at = account.high_value_checked_at
if checked_at is not None and checked_at.tzinfo is None:
checked_at = checked_at.replace(tzinfo=UTC)
# CK 失效 = 查不动了。此时缓存里的「可兑换」已经无法确认当前是否还成立,
# 只能当作待确认 —— 否则运营会拿一个过期结论去兑换。
ck_broken = (account.ck_check_status or "") in {"invalid", "error"}
# 只有明确判定 `invalid` 才降级展示。`error` 表示这次检测没查成,
# 不等于账号状态变了;若也降级,列表会显示已过期,但筛选/统计仍把
# 同一账号算作可兑换,造成同一屏两套结论。
ck_broken = (account.ck_check_status or "") == "invalid"
stale = bool(
ck_broken
or (