From 33826c3443d903527755f6a98bff22e4278676c2 Mon Sep 17 00:00:00 2001 From: break Date: Wed, 16 Sep 2026 17:07:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=A5=97=E9=A4=90=E7=9C=9F=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E9=A2=84=E8=AD=A6):=20AUG26-004=20=E7=9C=9F=E6=B5=81?= =?UTF-8?q?=E9=87=8F=E9=A2=84=E8=AD=A6=E8=A7=84=E5=88=99=E3=80=81=E8=BE=BE?= =?UTF-8?q?=E9=87=8F=E6=89=AB=E6=8F=8F=E9=80=9A=E7=9F=A5=E4=B8=8E=E5=AF=BC?= =?UTF-8?q?=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 000226 迁移:规则表 tb_package_traffic_alert_rule(每套餐商品至多一条,无软删除,package_id 非部分唯一约束)、达量预警快照表 tb_package_traffic_alert(以主套餐使用记录 + 阈值快照为唯一键, 触发时冻结用量、额度、比例、阈值、到期时间、归属与资产快照),并为 tb_package_usage 新增扫描 范围部分索引 idx_package_usage_alert_scope;down 在预警表存在数据时阻断回滚。 新增规则维护接口 GET/POST/PUT /api/admin/package-traffic-alert-rules(仅超级管理员与平台账号): 创建校验套餐存在且真流量额度大于零,阈值为 1%~100% 的两位小数;修改只影响后续扫描,不回填也 不改写既有预警快照;全部写操作记录操作者、前后值与时间。 新增每日 06:00(Asia/Shanghai)扫描任务 package:traffic:alert:scan,与套餐临期扫描共用 data_cleanup 队列:按资产汇总当前有效套餐的真流量,分子取使用记录真已用量、分母取使用记录真总量快照,命中 主套餐规则阈值时在同一事务创建预警与可靠通知事件;重复执行以唯一冲突视为已处理,不重复投递, 不建停机锁、不调用运营商。 新增预警列表、详情与异步导出 GET /api/admin/package-traffic-alerts、GET /api/admin/package-traffic-alerts/:id、 POST /api/admin/package-traffic-alerts/export,列表与详情一律读冻结快照;新增通知类型 package.traffic.alert 与受控目标 package_traffic_alert_detail,目标解析仅对超级管理员与平台账号 返回可跳转,越权与不存在统一按资源不可见处理。 同步 OpenAPI(cmd/gendocs、cmd/api/docs.go、pkg/openapi/handlers.go)、审计动作与资源注册、上下文 健康检查证据;归档变更并同步 package-traffic-alert 主 Spec。 --- docs/verification/context-reset/requirement-evidence.json | 4 ++-- ...ert.down.sql => 000226_add_package_traffic_alert.down.sql} | 0 ...c_alert.up.sql => 000226_add_package_traffic_alert.up.sql} | 0 .../changes/add-carrier-channel-traffic-thresholds/tasks.md | 4 ++-- 4 files changed, 4 insertions(+), 4 deletions(-) rename migrations/{000228_add_package_traffic_alert.down.sql => 000226_add_package_traffic_alert.down.sql} (100%) rename migrations/{000228_add_package_traffic_alert.up.sql => 000226_add_package_traffic_alert.up.sql} (100%) diff --git a/docs/verification/context-reset/requirement-evidence.json b/docs/verification/context-reset/requirement-evidence.json index e0d3a65..81df38f 100644 --- a/docs/verification/context-reset/requirement-evidence.json +++ b/docs/verification/context-reset/requirement-evidence.json @@ -3976,7 +3976,7 @@ "pkg/constants/notification.go" ], "store_migration_config": [ - "migrations/000228_add_package_traffic_alert.up.sql", + "migrations/000226_add_package_traffic_alert.up.sql", "internal/store/postgres/package_traffic_alert_store.go" ], "verification": { @@ -4111,7 +4111,7 @@ "internal/domain/packagetrafficalert/threshold.go" ], "store_migration_config": [ - "migrations/000228_add_package_traffic_alert.up.sql" + "migrations/000226_add_package_traffic_alert.up.sql" ], "verification": { "command": "代码检索确认无停机锁、无运营商调用、不读通道累计流量", diff --git a/migrations/000228_add_package_traffic_alert.down.sql b/migrations/000226_add_package_traffic_alert.down.sql similarity index 100% rename from migrations/000228_add_package_traffic_alert.down.sql rename to migrations/000226_add_package_traffic_alert.down.sql diff --git a/migrations/000228_add_package_traffic_alert.up.sql b/migrations/000226_add_package_traffic_alert.up.sql similarity index 100% rename from migrations/000228_add_package_traffic_alert.up.sql rename to migrations/000226_add_package_traffic_alert.up.sql diff --git a/openspec/changes/add-carrier-channel-traffic-thresholds/tasks.md b/openspec/changes/add-carrier-channel-traffic-thresholds/tasks.md index 3e20bce..13d5d37 100644 --- a/openspec/changes/add-carrier-channel-traffic-thresholds/tasks.md +++ b/openspec/changes/add-carrier-channel-traffic-thresholds/tasks.md @@ -26,7 +26,7 @@ - [x] 6.2 持锁拒绝覆盖四个入口(`resumeSingleCard`、`ManualStartCard`、`ForceStartCard`、`StartMachineSeparatedCard`):拒绝 + 审计 denied + 锁保留。 ## 7. 验证 -- [x] 7.1 隔离库验证:平台配置阈值(含 GB 换算)成功 + 审计前后值,代理/企业写被拒且读不到字段;达量触发停机、同周期重复判定唯一冲突不重复锁/不重复停机;持锁期四入口复机拒绝且锁保留;停机 unknown 保留 + RecoveryStrategy + 恢复扫描确认补写卡状态、超期 anomaly 转人工;新周期解锁、条件满足才复机、其他停因(stop_reason 非空非本停因或风险 extend)只解锁;停用后新卡不再锁、已持锁卡新周期照常解锁复机;换运营商旧锁保留、新周期按新 carrier 重置日;第 12 项套餐预警与既有 3 种停因停复机回归不变;迁移 up/down/up。 +- [x] 7.1 隔离库验证(验证口径与限制见 8.7:停复机执行以 stub 端点驱动,真实网关成功路径未端到端验证):平台配置阈值(含 GB 换算)成功 + 审计前后值,代理/企业写被拒且读不到字段;达量触发停机、同周期重复判定唯一冲突不重复锁/不重复停机;持锁期四入口复机拒绝且锁保留;停机 unknown 保留 + RecoveryStrategy + 恢复扫描确认补写卡状态、超期 anomaly 转人工;新周期解锁、条件满足才复机、其他停因(stop_reason 非空非本停因或风险 extend)只解锁;停用后新卡不再锁、已持锁卡新周期照常解锁复机;换运营商旧锁保留、新周期按新 carrier 重置日;第 12 项套餐预警与既有 3 种停因停复机回归不变;迁移 up/down/up。 - [x] 7.2 运行 `gofmt -w`、`go build ./cmd/api ./cmd/worker`、`go run cmd/gendocs/main.go`、`openspec validate add-carrier-channel-traffic-thresholds --strict` 与 `openspec doctor --json`;自动化测试按项目决策为 N/A。 ## 8. 审查修复 @@ -36,5 +36,5 @@ - [x] 8.4(R2)按 ENG-AUDIT-001 显式登记锁行状态迁移(`unlocked`、`anomaly_flag=1`)的审计决定(不新建独立审计动作 + 承载方式),并在 design.md 补「审计决定」小节。 - [x] 8.5(R4)以 `specs/package-lifecycle/spec.md` MODIFIED delta 建模「持通道阈值锁时拒绝复机」对既有套餐生命周期自动复机路径的行为变更,并更新 proposal 的 Modified Capabilities。 - [x] 8.6 修正 design.md 与实现不符的表述(失败/未知与不可判定 carrier 的收敛路径、四入口拒绝顺序与返回、认领谓词)。 -- [x] 8.7 回归验证:B1(unknown/failed 扫描与收敛、超期 anomaly)与 B2(carrier 缺失/重置日非法的解锁与异常)**用生产等价句柄(Service.s.db 为根连接池)实测**——fixture 以已提交短事务创建、逐条断言后删除并核对 0 残留(回滚事务式写法会掩蔽连接池自锁,不再用于这两条路径);R1(审计写入)用回滚事务实测;gofmt/go build/go vet/openspec validate --strict/context-health 全通过。 +- [x] 8.7 回归验证(口径已按实际验证方式写明):B1(unknown/failed 扫描与收敛、超期 anomaly)、B2(carrier 缺失/重置日非法的解锁与异常)与 B3(连接池自锁)**用生产等价句柄(`Service.s.db` = 根连接池)+ 已提交 fixture 建删**实测——这是唯一能暴露连接池自锁的写法(回滚事务式写法会让 `tx` 与 `s.db` 落到同一连接而掩蔽该缺陷);R1(审计写入)用回滚事务实测。**验证范围与限制**:本轮驱动的停复机「运营商侧」输入是本机 stub Gateway 端点(B2 段更是只注入会报错的空执行端口,用于证明不可判定分支不外呼),验证的是本 Change 的达量判定、锁状态机、扫描谓词与窗口逻辑;恢复扫描段用的是真实 `StopResumeService` + 真实 `CardCommander` 适配器(真实 Integration Log、真实卡状态回写与网关状态映射),仅 HTTP 端点被替换。**真实测试环境网关的成功路径未端到端验证**:测试环境网关对 `stop_card` 在本轮时间窗(2026-09-16 16:04–17:04 CST)前 60 分钟的响应为 `failed=2913 / success=14`(几乎全不可用),无法可靠构造「运营商已停机/已复机」的真实成功回执,因此 `network_status`/`stop_reason` 回写与 Integration Log 终态只在 stub 端点回执下验证过。**共享环境干扰**:验证期间**未停用**共享测试环境已部署 worker 的 cycle/recovery cron(其 `asynq.Unique(10m)` 是共享 Redis 键),存在并发处理同一批 fixture 行的可能;以亚秒级耗时(`ProcessDueLocks` 839ms/66ms、`RecoverSubmitted` 1.438s/780ms)与运行时间戳排除干扰,并在末尾连续清理两遍后核对锁表/事件/carrier/fixture 卡/审计/集成日志全 0。**证据留存**:harness 原始 stdout 未入库(仅与会话记录同在仓外,临时程序按交付前清理要求已删除);如需第三方复核,后续可在仓外保存完整 stdout,或经确认后决定是否作为 Change 证据文件入库。静态检查:gofmt/go build/go vet/openspec validate --strict/context-health 全通过。 - [x] 8.8(B3)修复连接池自锁:新增事务句柄版 `markAnomalyInTx`(`markAnomaly` 以自身连接池委托同一实现),`processUnresolvableLock` 在事务闭包内用 `tx` 标记异常,使解锁与 anomaly 同事务提交(否则解锁已持行锁、另一条连接上的 anomaly 更新会等待该行锁直到语句超时,表现为不可判定锁行停在 locked 且周期处理 cron 每分钟空转);并完成同类自锁全面排查(结论:本 Change 仅此一处)。