Files
junhong_cmp_fiber/openspec/specs/priority-polling-queue/spec.md
break 5ed6b39deb
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
feat(收口): 补齐 8 月迭代缺口并同步 Spec 与证据链
- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕
- 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败
- 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影
- 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序
- 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列
- 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名
- 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
2026-09-18 15:34:29 +08:00

232 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# priority-polling-queue Specification
## Purpose
在不改变既有普通轮询内容、并发上限、失败重试与外部调用保护的前提下,为购买生效、续购顺延生效、加油包生效、无有效套餐与人工加急的资产提供额外优先执行的轮询调度,并保留可追踪的加急事实。
## Requirements
### Requirement: 优先轮询触发场景与入队事实
系统 SHALL 在下列业务事实提交成功后,为关联资产的当前在用卡创建优先轮询项:主套餐购买后立即生效、排队主套餐顺延生效、加油包生效、资产无有效套餐且存在待生效的套餐使用记录。具备既有轮询手动触发权限的后台账号亦可为其数据范围内资产入队。入队 MUST 等待订单、支付与套餐使用记录提交成功;支付失败、已取消或未支付到账的订单 MUST NOT 入队。触发类型 MUST 记录为下列稳定枚举之一:`purchase_activated``renewal_activated``queue_activated``addon_activated``no_valid_package``manual_trigger`。同一载体在本次生效前已存在更早的套餐使用记录时 MUST 记为 `renewal_activated`,否则记 `purchase_activated`
#### Scenario: 主套餐购买后立即生效
- **WHEN** 一次主套餐订单支付成功,该载体当时没有在用主套餐,且套餐使用记录以生效状态提交
- **THEN** 系统为该资产的当前在用卡创建优先轮询项,触发类型为 `purchase_activated`
#### Scenario: 过期后再次购买主套餐
- **WHEN** 该载体在本次生效前已存在更早的套餐使用记录,且新的主套餐使用记录以生效状态提交
- **THEN** 触发类型记为 `renewal_activated`
#### Scenario: 排队主套餐顺延生效
- **WHEN** 一张待生效主套餐使用记录由待生效条件更新为生效,且该条件更新命中一行
- **THEN** 系统为该资产创建优先轮询项,触发类型为 `queue_activated`
#### Scenario: 加油包生效
- **WHEN** 一次加油包购买使加油包使用记录以生效状态提交
- **THEN** 系统为该资产创建优先轮询项,触发类型为 `addon_activated`
#### Scenario: 资产无有效套餐且存在待生效套餐
- **WHEN** 普通套餐轮询判定资产无有效套餐,且该载体存在待生效的套餐使用记录
- **THEN** 系统为该资产的当前在用卡创建优先轮询项,触发类型为 `no_valid_package`
#### Scenario: 无有效套餐但不存在待同步业务
- **WHEN** 普通套餐轮询判定资产无有效套餐,且该载体不存在待生效的套餐使用记录
- **THEN** 系统不创建优先轮询项,普通轮询按既有间隔继续
#### Scenario: 支付失败或订单取消
- **WHEN** 套餐订单支付失败、已取消或仍未支付到账
- **THEN** 系统不创建优先轮询项
#### Scenario: 重复支付成功回调
- **WHEN** 同一笔已生效套餐订单的支付成功回调重复投递
- **THEN** 系统不新增优先轮询项,也不产生第二次上游轮询调用
### Requirement: 入队执行对象为资产当前在用卡
优先轮询项的执行对象 MUST 是卡。触发时系统 MUST 在业务事务内冻结资产的当前在用卡快照:独立卡为卡自身,绑定设备的资产为绑定状态有效的全部在用卡。入队 MUST NOT 以设备上报的当前卡槽作为执行对象口径。同一资产存在多张在用卡时 MUST 逐卡建项,并分别记录每张卡的执行结果。
#### Scenario: 绑定设备存在多张在用卡
- **WHEN** 一个绑定设备的资产存在三张绑定状态有效的在用卡,且该资产命中触发场景
- **THEN** 系统为三张卡分别创建优先轮询项,并分别记录每张卡的执行结果
#### Scenario: 快照冻结后绑定关系变化
- **WHEN** 触发事务提交后该资产的绑定关系或设备上报的当前卡槽发生变化
- **THEN** 已冻结的执行对象不变,不追溯新增绑定卡
### Requirement: 同卡同任务类型的唯一活动项与合并
同一卡同一轮询任务类型 MUST 至多存在一条活动优先轮询项;一次优先需求对应多个既有轮询任务类型的执行。同一资产或同一卡的后续触发 MUST 合并进已存在的活动项追加触发次数、最近触发时间与来源事实MUST NOT 新建活动项、MUST NOT 重复调用同一轮上游轮询。合并 MUST NOT 因某一任务类型存在活动项而影响该卡其它任务类型的普通轮询。
#### Scenario: 自动触发与人工触发先后到达
- **WHEN** 同一卡同一任务类型已有活动优先轮询项,管理员再次手动入队
- **THEN** 系统仅追加触发来源、触发次数与最近触发时间,不创建第二条活动项,也不重复调用轮询
#### Scenario: 触发事件重放
- **WHEN** 同一触发事件被重复投递
- **THEN** 系统只合并到已有的活动项,不新增活动项
#### Scenario: 同卡不同任务类型
- **WHEN** 同一卡的某一个任务类型存在活动优先轮询项
- **THEN** 该卡其它任务类型的普通轮询执行不受该活动项影响
### Requirement: 优先调度与执行提示通道
优先轮询项 MUST 以持久化事实为权威;执行提示 MUST 通过每任务类型独立的提示通道下发MUST NOT 与既有手动触发队列共用通道键。调度器 MUST 在同一调度周期内先排空优先提示通道、再排空手动触发队列。提示通道 MUST NOT 作为活动、权限或尝试次数的判定依据。优先的强度边界 MUST 为仅调度入口领先:跳过定时队列等待并在同一周期内先入队;同一任务类型的既有执行队列 MUST NOT 被插队;分片队列背压跳过 MUST NOT 抑制优先提示入队。本能力 MUST NOT 新建调度设施、异步任务类型或队列。
#### Scenario: 提示通道丢失
- **WHEN** 执行提示通道内容丢失或缓存服务重启
- **THEN** 后续普通轮询执行仍按活动优先轮询项认领并执行,仅退化为延迟一个普通轮询周期,不丢事实也不产生第二套补偿
#### Scenario: 同一调度周期的排空顺序
- **WHEN** 优先提示通道与手动触发队列在同一调度周期都有待处理卡
- **THEN** 系统先排空优先提示通道,再排空手动触发队列
#### Scenario: 分片队列积压
- **WHEN** 某任务类型的分片队列深度超过背压阈值
- **THEN** 普通分片批次被跳过,优先提示仍按既有排空速率入队
### Requirement: 优先项认领、租约与执行前校验
领取优先轮询项 MUST 以活动项的条件更新为权威认定:仅当该项由待执行更新为执行中且该更新命中时才视为领取成功。执行中且认领租约未到期的项 MUST 拒绝其他执行重复领取。认领租约 MUST 长于既有轮询任务超时并为 90 秒;超过租约仍未被更新的执行中项 MUST 允许后续执行接管领取。执行前系统 MUST 校验该卡仍在轮询范围内(卡自身与绑定设备的轮询开关均为启用);不满足时 MUST NOT 发起上游调用MUST 以失败终态结束该项并保留可安全展示的原因。
#### Scenario: 两次执行并发到达
- **WHEN** 同一卡同一任务类型的两个执行轮次同时到达认领接缝
- **THEN** 只有一个领取成功并发起上游调用,另一个跳过该轮次并延后
#### Scenario: 领取者崩溃
- **WHEN** 一条执行中优先项超过认领租约仍未被更新
- **THEN** 相邻执行接管领取并继续执行,该卡该任务类型不被永久跳过
#### Scenario: 卡已停止轮询
- **WHEN** 该卡自身的轮询开关或绑定设备的轮询开关已关闭
- **THEN** 系统不发起上游调用,该项以失败终态出队并保留可安全展示的原因
### Requirement: 优先项尝试次数与出队
优先轮询项 SHALL 使用自身固定的最大尝试次数常量3MUST NOT 新增可维护的参数配置项MUST NOT 改变普通轮询的失败重试策略。尝试次数 MUST 只在真正发起执行后累加。未达上限的可恢复失败 MUST 回到活动状态并沿用既有轮询间隔重新排期;达到上限 MUST 记录失败终态与可安全展示的失败原因后出队。卡不存在等业务校验类失败 MUST 直接进入失败终态且不重试。执行成功 MUST 记录完成终态并出队,资产继续按普通轮询运行。
优先项 SHALL 支持人工关闭:具备卡数据权限的超级管理员与平台账号可对未完成(待执行或执行中)的项执行关闭,关闭 MUST 填写原因并 MUST 记录操作者、时间与原因审计关闭后该项进入已关闭终态并出队MUST NOT 再发起任何上游调用MUST NOT 删除既有执行结果与失败原因。
优先项 SHALL 具备有效期:有效期取值 MUST 为固定常量(本能力不新增可维护配置项),长度与尝试上限常量一并由服务端固定。入队时间起超过有效期的未完成项 MUST 转入已过期终态并出队MUST 保留触发类型、尝试次数与最近失败原因MUST NOT 自动删除事实。既有未完成项 SHALL 自本次上线时刻起算有效期MUST NOT 在上线后被批量判定为已过期。到期处理 MUST 由独立的周期任务承载MUST NOT 依赖查询或读侧隐式触发。已过期与已失败的项 SHALL 支持人工重新触发:重新触发 MUST 复用人工优先入队入口为该卡该任务类型建立新的活动项并将尝试次数置零MUST 记录操作者与原因MUST NOT 绕过既有并发上限、停复机持锁拒绝与任务类型范围。
本能力 MUST NOT 建立独立异常记录表:异常、超限与重试事实由优先项自身状态、尝试次数与执行结果承载。
#### Scenario: 可恢复失败未达上限
- **WHEN** 一次优先执行因上游调用超时、失败或响应无效而可恢复失败,且尝试次数未达上限
- **THEN** 该项回到活动状态并按既有轮询间隔重新排期
#### Scenario: 达到最大尝试次数
- **WHEN** 尝试次数达到上限仍未能成功执行
- **THEN** 该项记录失败终态与可安全展示的失败原因后出队,该卡继续普通轮询
#### Scenario: 卡不存在
- **WHEN** 优先执行时该卡已不存在
- **THEN** 该项直接进入失败终态,不重试也不发起上游调用
#### Scenario: 执行成功
- **WHEN** 优先执行按既有轮询内容完成
- **THEN** 该项记录完成终态并出队,资产继续存在于普通轮询
#### Scenario: 人工关闭
- **WHEN** 授权账号对一项待执行或执行中的优先项填写原因后执行关闭
- **THEN** 该项进入已关闭终态并出队,不再发起上游调用,原因与操作者写入审计
#### Scenario: 有效期到期
- **GIVEN** 一项优先项自入队起已超过固定有效期且仍未完成
- **WHEN** 调度或维护流程处理该项
- **THEN** 该项转入已过期终态并出队,触发类型、尝试次数与最近失败原因被保留
#### Scenario: 失败项人工重触发
- **GIVEN** 一项优先项已因达到尝试上限失败或因超期出队
- **WHEN** 授权账号填写原因后重新触发
- **THEN** 系统为该卡该任务类型建立新的活动项且尝试次数从零开始,并记录操作者与原因
#### Scenario: 重触发不绕过既有边界
- **GIVEN** 目标卡持运营商通道阈值停机锁
- **WHEN** 授权账号对该卡重新触发优先轮询
- **THEN** 系统按既有持锁拒绝语义处理,不发起复机
### Requirement: 优先轮询事实与查询的可追溯
系统 SHALL 记录入队(含合并)、领取、每次失败、重试、完成、人工关闭、超期、人工重触发与失败出队的触发类型、触发来源、操作来源、时间与结果。人工入队与人工重触发 MUST 填写原因,并与事实一同保存。
优先项事实 SHALL 持久化并可查询下列字段:资产类型与资产标识、设备号(资产绑定设备时)、卡 ICCID、店铺标识与代理归属、任务类型、触发类型与触发来源集合、触发次数与最近触发时间、尝试次数与最大尝试次数、执行开始时间、执行结束时间与执行耗时、下一次计划执行时间、入队时间、出队时间、执行结果与失败原因、接口请求与响应摘要引用复用既有集成交互日志标识MUST NOT 复制凭证或响应原文)。
系统 MUST 提供最小可读接口(列表与详情,支持筛选与分页),筛选至少支持状态、任务类型、触发类型、时间范围,以及「异常与重试」视图所需的条件(失败终态、已过期、尝试次数达到上限、存在失败原因)。该视图 MUST 复用同一事实表与同一权限MUST NOT 新增独立异常事实表。权限 MUST 与人工入队一致:超级管理员与平台账号可查询全部,代理账号仅可查询其自身及下级店铺资产,企业账号 MUST 被拒绝;查询 MUST 按数据权限下推,越权与不存在 MUST 不可区分。查询 MUST NOT 提供优先级分级;有效期、出队时间与最大尝试次数 SHALL 作为只读字段返回;人工关闭与人工重触发 SHALL 为独立受权限控制的写入口MUST NOT 由查询接口隐式触发。
#### Scenario: 代理查询范围外资产
- **WHEN** 代理账号查询不在其数据范围内的优先轮询项
- **THEN** 响应与查询不存在的优先轮询项不可区分
#### Scenario: 企业账号入队或查询
- **WHEN** 企业账号提交优先入队或查询优先轮询项
- **THEN** 系统拒绝
#### Scenario: 查询结果字段
- **WHEN** 授权账号查询优先轮询项列表或详情
- **THEN** 响应给出资产标识、设备号(适用时)、店铺与代理归属、任务类型、触发类型与来源、触发次数、尝试次数与最大尝试次数、最近与下一次执行时间、执行结果与失败原因、入队与出队时间,且不含优先级分级
#### Scenario: 异常与重试视图
- **WHEN** 授权账号以失败终态或尝试次数达到上限作为筛选条件查询优先轮询项
- **THEN** 系统返回对应项及其失败原因与尝试次数,数据来源于同一事实表
#### Scenario: 执行耗时与摘要引用
- **WHEN** 一项优先执行完成并产生上游交互
- **THEN** 该项返回执行开始与结束时间、耗时以及集成交互日志标识,且不返回上游响应原文
### Requirement: 人工优先入队不受人工触发防滥用配额约束
人工优先入队 MUST NOT 受既有手工轮询的每日触发次数上限与 24 小时去重约束;这两项是人工触发的防滥用配额,不是优先队列不变量。重复抑制 MUST 由活动项合并承担,且每次人工入队 MUST 独立记录审计事实。人工入队 MUST NOT 修改调度优先级MUST NOT 绕过既有并发上限。
#### Scenario: 当日人工触发次数已达上限
- **WHEN** 操作者当日手工轮询触发次数已达既有上限后发起优先入队
- **THEN** 优先入队仍然成功并记录审计
#### Scenario: 24 小时内重复人工入队
- **WHEN** 操作者在 24 小时内对同一卡同一任务类型再次人工入队
- **THEN** 系统合并到已有活动项并记录本次人工入队审计,而不是拒绝
### Requirement: 与运营商通道阈值停机的边界
持运营商通道流量阈值停机锁的卡 MUST 保持在普通轮询范围内。优先轮询 MUST NOT 使该类卡复机;优先执行 MUST 复用既有停复机判定与持锁拒绝语义MUST NOT 绕过停机锁。
#### Scenario: 持锁卡的优先执行
- **WHEN** 持通道阈值停机锁的卡处于优先轮询执行中
- **THEN** 系统不发起复机,并保留既有的持锁拒绝事实