16 KiB
AUG26-013 实施与验证记录
当前完成范围
- 已完成并在 Change 任务中勾选:1.1 至 4.2。3.1 至 4.2 的勾选适用下文“用户授权的完成判定”,不等同于所有运行时场景已经实际通过。
- 运行时全量验收未执行:没有在严格隔离环境完整覆盖 H5 会话、消费者联调及查询计数;历史已执行的有限只读验收及工程命令见下文。
- 未修改 Schema、迁移、套餐状态、金额、退款或外部支付/审批流程。
已执行的脱敏命令与结果
| 命令 | 结果 |
|---|---|
gofmt -w internal/query/asset/package_history.go internal/service/asset/service.go internal/handler/app/client_asset.go internal/model/dto/asset_dto.go internal/model/dto/client_asset_dto.go |
成功,无输出。 |
go build ./cmd/api ./cmd/worker |
初次因废弃的 sort 导入失败,移除后以临时可写 Go 缓存重新执行成功。 |
go run cmd/gendocs/main.go |
成功生成 docs/admin-openapi.yaml。 |
openspec validate add-asset-package-hierarchy --strict |
成功:Change 'add-asset-package-hierarchy' is valid。 |
openspec doctor --json |
成功:root healthy,status: []。 |
此前曾创建后删除一个仅测试纯函数的 internal/query/asset/package_history_smoke_test.go 并运行 go test。该行为不符合项目“自动化测试 N/A”的后续执行约束;文件已删除,结果不作为任务 3.x 的隔离环境入口验收证据。后续不再创建 *_test.go 或运行 go test。
本轮局部兼容修复
- 独立审查确认:旧 H5 历史使用的
AssetPackageResponse会无条件序列化零值order_id:0;新的ClientAssetPackageHistoryNode曾遗漏该可观察字段。 - 已仅在 H5 历史专用 DTO 恢复
OrderID uint json:"order_id",中文说明明确该接口不填充真实订单 ID,零值仍输出为0;后台 DTO、公共 DTO 和 H5 映射均未改动。 - 第二项审查结论:上述四个历史数组在生成 OpenAPI 中均误标
nullable:true,但运行时契约要求始终返回[]。已仅为AssetPackageHistoryNode.Children、ClientAssetPackageHistoryNode.Children、AssetPackagesResult.Items、AssetPackageHistoryResponse.List添加项目生成器支持的nullable:"false"tag;未扩展生成器行为,未手改 YAML。 - 独立审查最终结论为 Standards 0 项确认问题、Spec 2 项确认问题;以上两项均已按限定范围修复并由下述局部 smoke 覆盖。
本轮精确局部验证
| 命令 | 可观察结果 |
|---|---|
gofmt -w internal/model/dto/asset_dto.go internal/model/dto/client_asset_dto.go && go build ./cmd/api ./cmd/worker && go run cmd/gendocs/main.go |
命令退出成功;gofmt 无输出,Go 在构建时输出一次模块缓存 stat 写入权限诊断,但未使构建命令失败;生成器输出“成功在以下位置生成 OpenAPI 文档”。 |
go run asset_package_history_contract_smoke.go |
输出 history JSON arrays, H5 order compatibility, and four OpenAPI nonnullable arrays verified;程序随后删除。它核对后台/H5 主子 children 与空 items 均为数组、普通主项 master_usage_id:null、H5 主子 order_id:0 且不出现订单号/退款/金额/生效条件字段,并解析生成 OpenAPI 确认四个数组字段为 type: array 且非 nullable,同时确认公共 DtoAssetPackageResponse 未增加层级字段。 |
此为 DTO/JSON/生成文档的局部契约 smoke,不触发真实 API、数据库或消费者联调;不替代任务 3.x 或 4.1 的实际验收。
真实测试环境只读验收(本轮)
- 用户已明确
.env.local指向测试环境;本轮按该事实执行,未访问生产环境。 source .env.local仅在子进程内完成且未回显值。脱敏核对显示数据库、Redis、JWT 及服务地址必需项均存在;数据库与 Redis 主机均为外部主机,仅以 SHA-256 前 12 位标记记录,未记录凭据、原始库名或地址。- PostgreSQL 连接固定设置
PGOPTIONS=-c default_transaction_read_only=on;首个查询成功确认transaction_read_only=on,并确认tb_package_usage、tb_package、tb_iot_card、tb_device、tb_personal_customer存在。未执行任何迁移、DDL、DML、事务写入或外部支付/审批调用。 - 最小 API 首次以 README 所示的
go run cmd/api/main.go启动,因undefined: generateOpenAPIDocs退出;改为go run ./cmd/api后监听127.0.0.1:18181成功。启动前只读确认有 4 个启用超级管理员,因此initDefaultAdmin只会走存在检查与跳过分支。进程的日志仅写入/tmp,验收后已停止。 - 配置 Redis DB
7无既有后台或 H5 会话,复用会导致后台历史请求返回401/code=1003。按照用户批准的临时替代入口,仅本地 API 进程覆盖JUNHONG_REDIS_DB=0,复用该 DB 中已有的 15 个超级管理员会话;未调用登录、开发登录、刷新、登出,不创建 H5 会话、不写 Redis、不伪造 JWT。随后后台入口返回200/code=0。
脱敏 SQL 与 HTTP 结果
| 范围 | 只读 SQL/HTTP 摘要 | 实际结果 |
|---|---|---|
| 数据关系盘点 | 对未软删除 tb_package_usage 聚合 master_usage_id、状态、退款、父记录存在性与软删除商品 |
共 78 条主项、0 条子项;物理缺失主项、软删父项、软删商品、退款子项、待生效子项、失效/过期/用尽子项、非待生效且无生效时间子项均为 0。卡与设备均不存在任何主子关系组。 |
| 后台候选卡 | 对资产标识 SHA-256 前缀 1f0b3a3a5ee3 查询 usage;GET /api/admin/assets/<hash>/packages 使用已有超级管理员 token |
SQL 得到 3 条顶层主项,状态分布为生效中 1、失效 2,均 master_usage_id=NULL。page=1&page_size=100 返回 200/code=0、total=3、3 项、全部 children=[];返回 ID 的哈希序与 SQL created_at DESC,id DESC 完全一致。 |
| 后台分页 | 同一候选卡依次 GET page=2&page_size=1、page=99&page_size=1 |
第 2 页恰为 SQL 的第二个顶层项;超末页返回 items=[] 且保留 total=3。 |
| 后台状态筛选 | 同一候选卡 GET status=1 与无数据的 status=0 |
status=1 返回 total=1 的完整顶层项;status=0 返回 total=0/items=[]。 |
| 载体边界 | 对设备标识 SHA-256 前缀 483c5060f9a9 查询 usage 并 GET 后台历史 |
SQL 为 24 条设备 usage、0 子项、1 个世代;HTTP 返回 200/code=0、total=24、page_size=1、首项无子项。卡与设备均在各自资产范围内响应,未见跨载体内容。 |
| 当前套餐兼容 | GET /api/admin/assets/<card-hash>/current-package |
200/code=0;实际 JSON 不含 children 或 master_usage_id,未被历史层级 DTO 连带改变。修改套餐接口是写接口,受本轮只读限制未调用。 |
| 查询次数可观测性 | 只读检查 pg_stat_statements 扩展及关系 |
扩展和关系均不存在;无法在不改变数据库配置或添加日志的前提下取得本次 HTTP 的精确 SQL 调用计数。 |
先前真实数据覆盖结论(当时)
| 任务 | 结论 | 未完成的精确原因 |
|---|---|---|
| 3.1 | 后台已部分验证;当时不勾选 | 实际数据只有多主/无子项,子项总数为 0;没有多子项、子项超过页大小、异常独立项。H5 没有既有会话,不能执行该入口的真实 JSON 验收。 |
| 3.2 | 后台仅验证状态命中与无匹配;当时不勾选 | 没有任何主子组;H5 无会话,故未验证子项命中、同成员状态+类型联合、类型筛选及软删除商品资格。 |
| 3.3 | 仅观测后台顶层生效中/失效历史仍可返回;当时不勾选 | 无子项,且所需过期、用尽、退款、三桶、空生效时间和并列子项排序测试数据均不存在。 |
| 3.4 | 当时不勾选 | 物理缺失、软删父项、跨资产父项、H5 跨世代、商品缺失与存在性查询失败样本均不存在;不得造数或人为制造读取错误。 |
| 3.5 | 已实际观察卡/设备后台范围和当前套餐 JSON;当时不勾选 | 无多世代样本、无既有代理会话、无 H5 会话;金额隔离只能通过 H5 实际响应验证,不能以 DTO 或 Query 代替。修改套餐接口为写接口,未调用。 |
| 3.6 | 后台分页壳和顶层稳定排序已实际观察;当时不勾选 | H5 无会话,无法比较相同集合;pg_stat_statements 不可用,无法获得 usage/存在性/商品批量查询次数的真实计数;无主子样本也不能验证子项顺序或 N+1 边界。 |
| 3.7 | 当时不勾选 | 仓库无可联调的后台或 H5 消费者工程;未取得外部消费者对层级、默认展开、总数、整组筛选、整体错误及 API/消费者同步发布回滚的联调确认。 |
当时 tasks.md 的 3.1—3.7、4.1、4.2 均保持未勾选。未修改 Go 源码或 OpenAPI 源,故该轮未重复 gofmt、go build、gendocs、OpenSpec validate 或 doctor;第 4.x 的既有记录见上文,不能替代缺失的 H5 与主子实际验收。
H5 临时会话可行性复核(第二轮,仅代码追踪与只读 SQL)
internal/service/client_auth/service.go:940-975的DevLogin在事务内调用findOrCreateCustomer与bindAsset,不是仅写 Redis 的认证入口。- 即使 OpenID 已存在,
findOrCreateCustomer也会在service.go:718-749读取客户后无条件执行customerStore.Update(ctx, customer)(746 行);昵称、头像为空时不会改变内存字段,但仍不能排除业务表UPDATE。未命中时 799-823 行会创建个人客户和 OpenID 记录。 bindAsset转至customer_binding.Service.Bind(service.go:891-893);已有有效绑定的 PCD/PCI 分支会在customer_binding/service.go:265-288或 313-341 行返回而不创建绑定,但这不能消除前述客户UPDATE。未绑定时相应的 271-302 或 319-349 行会创建绑定、首次绑定可修改资产并写审计。- 只读 SQL 盘点:
tb_personal_customer_openid中app_id='dev_test_app' AND open_id LIKE 'dev_test_%'为 0 条、0 个客户;有 usage 的资产中,卡为 7 个(6 个已有有效 H5 绑定)、设备为 6 个(6 个已有有效 H5 绑定),但这些绑定均不属于确定的dev_test客户;所有绑定资产的子项数及多 usage 世代数均为 0。
若需继续完成 H5 真实验收,仅接受以下任一前置:
- 提供与候选资产有效绑定对应的既有、可只读复用的 H5 会话或凭据;会话获取路径不得创建客户、绑定或其他业务记录。
- 维护者明确书面授权在测试环境写入可回滚的业务 fixture,并明确 fixture 的创建、回滚负责人和范围;fixture 至少覆盖 H5 客户绑定、主子多项/跨世代/异常关系、商品类型资格、授权及金额隔离。未经该授权不得造数或调用会写业务表的认证入口。
- 因而本测试库没有“已存在确定 dev_test 客户+目标资产已有有效绑定”的安全前置,且即使该前置存在,当前实现仍无法排除个人客户表
UPDATE。本轮不调用DevLogin、不请求用户凭据、不伪造 JWT;H5 真实 GET 继续保持未验收。
已核对的生成文档
docs/admin-openapi.yaml 已包含:
-
后台
GET /api/admin/assets/{identifier}/packages的全部世代层级、顶层 total 与关系异常说明; -
H5
GET /api/c/v1/asset/package-history的当前世代、同一成员联合筛选与关系异常说明; -
DtoAssetPackageHistoryNode与DtoClientAssetPackageHistoryNode的children、expand_by_default、relationship_status、relationship_status_name字段; -
原
DtoAssetPackageResponse和当前套餐/修改套餐路由仍存在。 -
.gitignore明确忽略docs/admin-openapi.yaml,且该路径不在 Git 跟踪清单;它是本地生成产物而非提交源文件。 -
项目交付方式是
go run cmd/gendocs/main.go(等价 Make 目标docs):生成器将路由注册结果写入该固定路径。本轮已重新生成;DtoClientAssetPackageHistoryNode.order_id位于生成文件 4075—4078 行,四个非 nullable 数组位于后台节点 2652—2656 行、后台列表 2871—2875 行、H5 节点 4050—4054 行及 H5 列表 2753—2757 行。当前套餐与修改套餐路由仍以公共DtoAssetPackageResponse为输出(路由 55、64、73 行),其生成 schema 保持在 2777—2868 行。
后台 API 的有限真实 JSON 验收已见“真实测试环境只读验收”;H5 会话及主子/异常/授权测试数据缺失,运行时全量验收未执行。
用户授权的完成判定
用户已明确将本 Change 的完成门槛改为“功能实现已覆盖即可勾选”,不再要求严格隔离环境、H5 会话、消费者联调或查询次数实测。本节据此记录 3.1—4.2 的勾选依据;这些勾选不表示完整实际环境、H5 消费者联调或发布回滚已经通过,运行时全量验收未执行。
| 任务 | 勾选依据 | 未作出的运行时声明 |
|---|---|---|
| 3.1 | PackageHistoryQuery.List 先完整读取资产/世代范围内未软删除 usage、建立主子组与异常独立项,再计算顶层 total 并只切顶层页;空结果与超末页返回空数组且保留真实总数。后台、H5 都接入该 Query。 |
未在完整严格隔离环境以多子项和超页数据实际请求两端。 |
| 3.2 | 同一 matchesPackageHistoryUsage 同时判定 status 和类型资格;组内任一成员命中即保留完整组。类型资格查询使用默认软删除范围,故已软删除商品不成为 H5 类型命中。 |
未以真实 H5 会话和对应 fixture 复现全部组合。 |
| 3.3 | 三桶排序由 packageHistoryChildBucket 与 packageHistoryChildLess 固定实现:非待生效且有生效时间、非待生效空生效时间、待生效;桶内 ID 升序,顶层创建时间/ID 降序,映射直接保留原状态、退款及关联字段。 |
未在实际数据中覆盖每种失效/退款及并列排序组合。 |
| 3.4 | 未解析主 ID 只批量最小存在性核对;物理不存在生成 master_missing,存在但不在可展示集合或核对失败返回统一读取错误。商品批量读取与 usage 关系判定分离,展示映射保留 usage 名称快照并允许商品缺失回退。 |
未人为制造物理缺失、软删除、跨资产/世代或数据库失败。 |
| 3.5 | Query 仅接受 card/device 并按对应载体过滤;后台不传世代、H5 传资产当前世代且先做有效绑定校验。后台历史 DTO 仅平台填充成本价,H5 专用 DTO 未映射订单、退款、金额或生效条件;当前套餐和修改路由继续使用公共 DTO。 | 未完成代理、H5、跨世代和修改写接口的全量实际验收;存量企业授权问题未声称修复。 |
| 3.6 | 两端复用同一层级 Query 与排序;后台保留 items/total/page/page_size,H5 保留 items/total/page/size。usage 一次集合读取、未解析主 ID 去重后至多一次核对、类型资格和商品均按 ID 批量读取;后台商品读取失败快照降级,H5 返回读取失败。 |
未实测 SQL 查询计数,未以同一真实集合比对两端顺序。 |
| 3.7 | proposal 明确消费者须同步适配层级、默认展开、顶层总数、整组筛选与整体错误;两条受认证路由及其 OpenAPI 输出类型、说明均已表达该契约。design 记录 API/消费者同步发布与共同回滚为原平铺契约,且无 Schema/写入数据回滚。 | 未取得真实后台或 H5 消费者联调、同步发布或回滚确认,不宣称展示验收完成。 |
| 4.1 | 本文已有 gofmt、go build ./cmd/api ./cmd/worker、go run cmd/gendocs/main.go 成功记录,以及 DTO/JSON/生成 OpenAPI 的局部 smoke;有限后台实际 JSON 和当前套餐兼容观察也已记录。 |
本轮未重跑工程命令;H5 实际 JSON 与两端完整运行时兼容未验收。 |
| 4.2 | 本文已有 openspec validate add-asset-package-hierarchy --strict 成功与 openspec doctor --json healthy/status: [] 记录;自动化测试按项目决策为 N/A,未运行迁移或真实外部业务调用。 |
未把此前有限 smoke 表述为完整运行时验收。 |
因此,3.1—4.2 的完成状态代表源码实现、既有局部 smoke 和已记录工程命令已覆盖用户授权的完成门槛;其余尚未执行的运行时场景保持如实记录。