All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m57s
- 提交写事务内先取事务级 advisory lock,再校验既有未删除账号/店铺与其它待审批申请: 手机号 1014、用户名 1013、店铺编号 1031、待审批占用 1007,冲突不落库且不消费短信验证码 - 已驳回(含通过后撤销)与已通过的终态记录不阻塞重新注册,形成新记录与新审批实例 - 并发同关键字段提交串行裁决,同一关键字段至多一条待审批记录 - 审批通过建店建号前复检关键字段,冲突返回可定位错误并整体回滚,不再以裸数据库错误收场 - 归档 Change fix-agent-distribution-registration-duplicate-guard 并同步主 Spec 验证:junhong_cmp_test + Redis DB 6 受控脚手架 37 项通过 / 0 项失败(含 6 路并发仅 1 条落库、 审批冲突回滚与无冲突建店回归),清理后 fixture 残留 0;gofmt/go build/go vet 全绿; openspec validate --all 35 项通过、doctor healthy、context-health 通过
7.6 KiB
7.6 KiB
1. 关键字段唯一性门禁
- 1.1
internal/application/distributionwithdrawal/registration.go新增三个内部函数并写明中文注释:lockRegistrationKeyScopes(按 key 字符串升序对phone/username/shop_code取pg_advisory_xact_lock(hashtext(:key)),key 前缀agent-distribution-registration:,注释说明行锁无法覆盖首次并发提交、升序避免死锁环);ensureRegistrationKeysAvailable(用 GORM 默认软删除范围查tb_account.phone、tb_account.username、tb_shop.shop_code,分别返回CodePhoneExists「手机号已被使用」、CodeUsernameExists「用户名已存在」、CodeShopCodeExists「店铺编号已存在」,查询失败返回CodeDatabaseError);ensureNoPendingRegistration(查status=0且phone/username/shop_code任一命中的最早记录,命中后按字段返回CodeConflict与区分字段的中文提示)。验证:三个函数位于registration.go:152-235,lockRegistrationKeyScopes使用slices.Sort(keys)排序后逐个Exec("SELECT pg_advisory_xact_lock(hashtext(?))", key),ensureRegistrationKeysAvailable依次以registrationKeyTaken校验三个字段并返回三个既有错误码。 - 1.2
Register的写事务内按「取串行化点 → 校验既有账号/店铺 → 校验待审批记录 → 创建注册记录 → 创建审批实例 → 回写实例 ID」顺序接入 1.1 的三个函数,使校验与插入同事务;失败整体回滚,事务外既有的验证码消费不执行。同步更新Register与相关函数的文档注释(冲突失败原因、已驳回/已通过记录不阻塞重新注册、软删除账号/店铺不占用关键字段)。验证:registration.go:107-120事务体开头依次调用三个函数;受控脚手架中三类冲突场景均断言「不落库 + 验证码仍存在」,驳回后重注册场景断言验证码被消费。 - 1.3
internal/application/distributionwithdrawal/registration_approval.go的applyApproved在loadEnabledParentShop之后、创建店铺与账号之前调用ensureRegistrationKeysAvailable:关键字段已被既有账号或店铺占用时返回 1.1 的可定位错误并整体回滚,注册记录保持待审批,不产生半套店铺/账号/钱包;注释写明该复检只把裸数据库错误换成稳定错误码,审批路径不取 advisory lock 的理由。验证:registration_approval.go:107-113;受控脚手架断言冲突审批返回1014、注册记录仍为status=0、无店铺与账号落库。 - 1.4
internal/routes/agent_distribution_public.go的Description增补失败原因(关键字段与既有账号/店铺或其他待审批申请重复时返回各自提示,且不消费验证码);运行go run cmd/gendocs/main.go重新生成docs/admin-openapi.yaml,确认该路由描述与工作区文件一致且未改写其它路由。验证:go run cmd/gendocs/main.go输出「成功在以下位置生成 OpenAPI 文档」,生成文件/api/c/v1/agent-distribution-registrations的description已包含新增失败原因(该文件被.gitignore忽略,为生成产物)。 - 1.5 运行
gofmt -w覆盖全部变更 Go 文件,并运行go build ./cmd/api ./cmd/worker、go vet ./internal/... ./pkg/...,确认无错误输出。验证:gofmt -l对四个变更 Go 文件输出为空;go build ./cmd/api ./cmd/worker退出码 0;go vet ./internal/... ./pkg/...退出码 0(唯余go自身对/Users/break/go/pkg/mod/cache/download无写权限的stat cache提示,与本次变更无关)。
2. 验证
- 2.1 按 ENG-TEST-001 在
junhong_cmp_testPostgreSQL + Redis DB 6 以一次性受控脚手架(驱动真实RegistrationService与真实DistributionApprovalHandler,事后删除且不在仓库留下测试入口)验证提交侧门禁:手机号与既有未删除账号冲突、用户名与既有账号冲突、店铺编号与既有店铺冲突分别返回1014/1013/1031与对应提示;软删除账号/店铺占用的关键字段可重新注册;手机号/用户名/店铺编号与既有status=0记录冲突分别返回1007与区分字段的中文提示;上一次申请为status=2(驳回)时同一手机号、用户名、店铺编号可成功提交为新记录与新审批实例;所有拒绝场景下注册记录与审批实例均未落库,且失败后同一验证码可直接重试成功;并发发起 N 路同关键字段提交时仅 1 条待审批记录落库、其余返回1007。fixture 只创建与删除本 Change 自己的记录(手机号/用户名/店铺编号带可识别前缀),不重置整库。验证:go run ./cmd/tmpverify_dupguard(.env.local显式DB_*=junhong_cmp_test、Redis DB 6 显式覆盖)输出 37 项通过 / 0 项失败,覆盖上述全部断言;并发 6 路同手机号/用户名/店铺编号提交仅 1 条成功、待审批记录恰 1 条,失败方错误码为1007(串行点后看到待审批记录)与1183(验证码已被胜者消费);三类冲突场景均验证验证码未被消费,驳回后重注册成功且验证码被消费。脚手架驱动的审批渠道为受控桩(真实approval.Port.Prepare需要调用企业微信,AGENTS.md 禁止对真实外部审批系统做自动验证),审计 Writer 用受控桩以避免在共享测试环境留下审计残留。 - 2.2 以同一脚手架验证审批侧:关键字段已被占用的待审批记录在受控
TerminalDecisionEvent(通过)下整体回滚,注册记录仍为status=0,错误码为 1.1 的可定位错误,且tb_shop/tb_account/tb_agent_wallet无半套实体;对无冲突待审批记录验证通过路径仍正常建店、建号、建钱包与层级(回归)。验证:冲突审批返回1014,注册记录仍为待审批,按店铺编号与用户名查询均为 0 行;无冲突审批成功建店(parent_id为上级、level为上级 +1、生成新的非空分销码)、建代理主账号(归属新店铺、is_primary、手机号一致)、建两个钱包,注册记录标记已通过。脚手架清理后按前缀复核残留:注册记录 0 / 店铺 0 / 账号 0 / 钱包 0(经 dbhub 只读查询tb_shop、tb_account、tb_agent_distribution_registration、tb_agent_wallet确认),脚手架文件已删除。 - 2.3 运行
openspec validate fix-agent-distribution-registration-duplicate-guard --strict、openspec doctor --json与./scripts/context-health.sh,确认 Change 校验通过、仓库健康;自动化测试按项目决策为 N/A,不新增测试入口。验证:openspec validate ... --strict输出Change 'fix-agent-distribution-registration-duplicate-guard' is valid;openspec doctor --json为"healthy": true且status为空;./scripts/context-health.sh输出「Context 健康检查通过」。 - 2.4 清理修复前产生的重复待审批记录(维护者指令):测试环境
tb_agent_distribution_registration中id8893 六条91 为渠道提交失败、92~93 为企业微信已通过但关键字段被占用无法建店);注册记录与审批实例的既有渠道事实不改写,status=0记录的关键字段均已与既有店铺或账号冲突(shop_code全部被既有店铺占用),在修复后的门禁下不可能通过审批,已人工标记为status=2并写入可区分来源的中文驳回原因(88id=94已由企业微信回调按既有链路驳回。验证:dbhub 只读查询确认七条记录状态均为status=2,无status=0记录遗留;本次为测试环境数据清理,不改写迁移、不新增审计入口。