diff --git a/qa-reports/phase2-pilot-rc2-release-manifest.md b/qa-reports/phase2-pilot-rc2-release-manifest.md new file mode 100644 index 0000000..7259715 --- /dev/null +++ b/qa-reports/phase2-pilot-rc2-release-manifest.md @@ -0,0 +1,147 @@ +# 宠小它 Phase 2 Pilot RC2 Release Manifest + +> RC ID:`phase2-pilot-rc2` +> 冻结日期:2026-08-02 +> 状态:**Ready for Release(未部署)** +> 适用范围:3~5 家独立宠物洗护单店真实试点 +> 样本目标:约 200 次完整服务后进行 Phase 2 / 商业化决策 + +RC2 是当前唯一推荐候选。它完整继承 RC1 的应用功能与发布边界,并修正试点指标的门店集合、时间窗、对象粒度和成熟 cohort 口径。真实生产配置、备份恢复、八个迁移、TLS、live smoke、三角色验收和首份指标基线未形成证据前,不得把状态改为 `Released`。 + +## 1. RC1 取代说明 + +保留 `phase2-pilot-rc1` tag 和清单用于审计,但不再用它采集或解释试点指标。审计发现 RC1 查询存在三个决策风险: + +1. 默认 `NULL` 会覆盖全部门店,且 200 次样本闸门使用全历史,可能混入测试店或迁移回填; +2. 打开→留资用“报告数”与“线索数”混比,同一报告多个手机号会放大转化; +3. 24h 发送率把窗口末尚未观察满 24 小时的报告纳入分母,且未显式约束事件时间顺序。 + +RC2 改为默认 `@pilot_store_ids='0'`,必须显式填写 3~5 个试点门店;所有样本统一使用 `[from,to)`;报告/留资/rebook 使用同粒度 cohort;24h 分母只含成熟 cohort;新增事件时间顺序反例。RC1 未发现应用运行时代码缺陷,后端 JAR 因此与 RC1 hash 相同。 + +## 2. 冻结提交与回滚点 + +| 仓库 | RC2 commit / ref | 前一稳定应用回滚点(Phase 0 Pilot RC2) | 冻结状态 | +|---|---|---|---| +| backend | `21846dba8b2a58bebaea51a1d5ba6396ce3c5df5` | `133f61e4ad6152865a76c4e9328d96e689f53635` | `main == origin/main`,clean | +| admin | `078ae0f9d18e6598a1af13fa8bf2b5b97c25a410` | `3470b124e408501ed824b993bcb34dd40e77c293` | `main == origin/main`,clean | +| frontend | `a595ea8fa17dd0dbdfb607abea93e8c0d24b13a8` | `e11ce1aaaa602011718e300e4527a0d971f1339a` | `main == origin/main`,clean | +| docs | `refs/tags/phase2-pilot-rc2`(本清单所在 commit) | `fe92fab4dd1ced2fd9d617cfb39e75f950caa318` | tag 推送后解析并复核 clean | + +部署前必须在四仓分别解析 `phase2-pilot-rc2` 并与本表一致;任何源码变化、产物 hash 变化或 tag 不一致都必须建立新 RC,不得移动已有 tag 或覆盖本记录。 + +## 3. RC 产品范围 + +本 RC 收口以下完整业务内核: + +1. 预约客户与服务执行人身份拆分; +2. 同店 `StoreCustomer` 客户主档; +3. 不可变、幂等、低敏 `BusinessEvent` 与 `AuditLog`; +4. 服务时长快照、门店容量和连续时段占用; +5. 生产配置门禁、readiness、只读 smoke 与回滚模板; +6. 基于事实的门店行动工作台; +7. 报告 `unknown / unsent / sent` 显式发送确认; +8. 微信核验老板入驻、门店开通清单和一次性员工邀请; +9. `StoreCustomer` 低敏事实时间线; +10. `FollowUpTask` 领取/改期/终结状态机与真实预约归因; +11. 三角色验收脚本、cohort-safe 试点指标字典和只读聚合查询 v2。 + +明确排除支付、库存、储值、复杂会员、多门店组织、订单系统、泛 AI,以及未授权的任何生产写入。 + +## 4. 本地验证证据 + +验证环境: + +- macOS `26.5.2` / arm64 +- OpenJDK `21.0.10`(项目按 Java 17 release 编译) +- Maven `3.9.14` +- Node.js `v22.22.2` +- npm `10.9.7` +- Python `3.9.6` +- 隔离查询验证:MySQL `8.0.46` + +| 门禁 | 结果 | +|---|---| +| backend `mvn test` | **PASS**:219 tests,0 failure / 0 error / 0 skipped | +| backend `mvn -q -DskipTests package` | **PASS** | +| backend `bash -n deploy/*.sh` | **PASS** | +| admin `npm run build` | **PASS**:1671 modules;仅既有 >500 kB chunk warning | +| frontend `npm run build:h5` | **PASS** | +| frontend `npm run build:mp-weixin` | **PASS**;`verify-mp-app-json` PASS | +| admin/frontend 默认占位配置门禁 | **PASS**:按预期拒绝 `.invalid` | +| admin/frontend 合成 HTTPS 配置门禁 | **PASS**:只验证格式,未使用真实域名或秘密值 | +| pilot metrics v2 契约测试 | **PASS**:只读、默认门店 `0`、显式集合、成熟 cohort、四项反例、无直接标识输出 | +| pilot metrics v2 隔离 MySQL 执行 | **PASS**:语法执行成功;门店 999 与 60 天前历史被排除;窗外提交/窗内发送未混入;双 lead 单报告保持报告粒度;不足 24h 报告未入 24h 分母;四项反例为 0 | +| ontology validate | **PASS**:290 条;Action 77、Entity 29、Event 33、Relation 102、Rule 49 | +| ontology drift | **PASS**:70/70 HTTP、16/16 JPA,code-only / ontology-only / entity drift 均为 0 | +| 四仓 `git diff --check` | **PASS** | +| 四仓工作树与远端 | 清单提交及 tag 推送后再次复核 | + +隔离 MySQL 使用临时、无网络、无密码、纯合成最小 schema 与数据;执行结束即关闭和清理,没有连接或读取本机现有 MySQL 业务库。本地仍未运行最终 production profile 的 JPA `validate` 与生产库 31 项不变量,该项保留为生产 No-Go 门禁。 + +## 5. 本地构建产物与 SHA-256 + +目录 hash 算法:按相对路径以 `LC_ALL=C` 排序,对每个文件执行 SHA-256,再对完整 hash 清单执行一次 SHA-256。 + +| 产物 | 大小 | SHA-256 | 可部署性 | +|---|---:|---|---| +| `backend/target/petstore-backend-1.0.0.jar` | 50,997,803 bytes | `fda13236f0bd0e0cc920b1c38be6dfc5f083ad3b5fa28319569fe66a2bb8454e` | 候选 JAR;仍须真实配置与生产只读预检 | +| admin `dist`(27 files) | 1,536 KiB | `4a955634c32db3d8d5cc8038572faa436462b36df02044eb3e55a39490823663` | **不可部署**:当前包含 `.invalid` 占位域名,仅证明可编译 | +| H5 `dist/build/h5`(65 files) | 852 KiB | `a77241af1a6b16183f03214adea070549a534cf768939202f3caa02d071aa6a5` | **不可部署**:当前包含 `.invalid` 占位域名,仅证明可编译 | +| 微信小程序 `dist/build/mp-weixin`(142 files) | 820 KiB | `f11b3cd95fb98f8ccec6b3556107d7e7bdc4eedf1c2e2975258bc766aa05525f` | **不可上传**:当前包含 `.invalid` 占位域名,仅证明可编译 | + +正式 Admin/H5/小程序必须以权限受控的真实域名配置重新执行 release preflight 与 build,并把新 hash 追加到生产发布记录。 + +## 6. 数据库迁移冻结 + +迁移只能按下列顺序执行;每一步先核对 SHA-256,再执行脚本末尾反例查询。失败时停止,不交换顺序、不自动 down migration、不猜测性回填。 + +| 顺序 | 文件 | SHA-256 | +|---:|---|---| +| 1 | `20260801_split_service_identity.sql` | `05fa560cb59a746681057187ffaccc1db4980de8e99bbcb0c42dd6ce25a759ac` | +| 2 | `20260801_create_store_customer.sql` | `5eabfc4689d5acc9400e70fc3cbdcd0549b8e9a8763176bef7ec3715f94002dd` | +| 3 | `20260801_create_business_event.sql` | `d0a3ebe3ac2f3bd0c4c125832df4895dec66d5cc95077b4292b10055b876c184` | +| 4 | `20260801_create_booking_capacity.sql` | `25e9c8817c48a2c4854d034981f765dfe4b6ebb90f95a8f45a54513106c4ad51` | +| 5 | `20260801_create_report_send_status.sql` | `321284bc44774c69de4b584f3eb3a8f235653be6c0a5e75e3557a697f78381a2` | +| 6 | `20260802_create_store_onboarding.sql` | `40d45f382a03c35e9e9696e65553488713cdaadf90094d824f406561f196039c` | +| 7 | `20260802_create_store_customer_timeline.sql` | `5185a03f9a983823c75aae6661b0e68d51c75e226d117039b22f81f383ac7c2d` | +| 8 | `20260802_create_follow_up_task.sql` | `a1ff5176b2775745ee1fb044a15d25d1cc52dba9fef72ffb45727f430db22c09` | + +八迁移完成后,以正式 service user、最终 production 配置运行 `deploy/release-preflight.sh`。通过条件是静态配置门禁、JPA schema validate 和 31 项只读数据库不变量全部成功。 + +## 7. 生产 Go/No-Go + +- [ ] Petstore 专用 API/Admin/报告域名与 TLS 就绪,不复用或修改其他产品域名; +- [ ] 权限受控的最终配置通过 backend、admin、frontend release preflight; +- [ ] 生产全量备份完成,记录大小/hash,并在隔离库完成恢复演练; +- [ ] 八迁移依次执行,文件 hash 一致且每步末尾反例为 0; +- [ ] production JPA `validate` 与 31 项只读数据库不变量通过; +- [ ] 正式 Admin/H5/小程序重新构建,记录 hash,微信合法域名一致; +- [ ] Petstore 独立 systemd/Nginx 配置完成,`nginx -t` 通过,diff 未改 Gitea/GitLab; +- [ ] liveness、readiness、只读 production smoke 通过; +- [ ] 老板、员工、宠主三角色主链及权限/异常反例全部签署 PASS; +- [ ] 外部监控、告警联系人、值班窗口和回滚执行人已真实测试; +- [ ] Gitea/GitLab 既有入口健康,服务器端口和证书未受影响; +- [ ] 首批真实数据开始计样本时,显式填写 3~5 个门店 ID,保存指标窗口、数据库快照时间、四仓 commit、低敏结果与 hash,四项指标可靠性反例为 0。 + +任一项未完成,结论都是 `No-Go / Ready for Release`,不得标记已上线。 + +## 8. 试点验收与 Phase 2 决策 + +- 三角色执行与证据:[`试点三角色端到端验收清单-2026-08-02.md`](../试点三角色端到端验收清单-2026-08-02.md) +- 门店开通与运营边界:[`试点门店开通清单-2026-08-01.md`](../试点门店开通清单-2026-08-01.md) +- 指标口径与决策带:[`试点指标采集与Phase2决策方案-2026-08-02.md`](../试点指标采集与Phase2决策方案-2026-08-02.md) +- 只读采集脚本:`backend/db/queries/pilot_metrics.sql` +- 发布与回滚步骤:[`生产发布与回滚Runbook-2026-08-01.md`](../生产发布与回滚Runbook-2026-08-01.md) +- 监控基线:[`生产监控与告警基线-2026-08-01.md`](../生产监控与告警基线-2026-08-01.md) +- 被取代候选:[`phase2-pilot-rc1-release-manifest.md`](./phase2-pilot-rc1-release-manifest.md) + +样本闸门为 3~5 家门店、观察 4~8 周、合计至少 200 次完整服务且每家至少 25 次。达到闸门后只能形成 `Continue`、`Iterate Core` 或 `Stop/Redesign` 三类结论;在此之前不扩展支付、库存、储值、复杂会员、多门店组织、订单系统或泛 AI。 + +## 9. 已知风险与回滚边界 + +- Admin 主 bundle 的 >500 kB warning 是已知性能债;不阻断小流量试点,但正式包仍应观察首次加载和弱网体验。 +- readiness 会因数据库、磁盘、上传目录、FFmpeg/ffprobe 任一依赖异常而拒绝接流;服务器端必须逐项核验权限和路径。 +- 指标 v2 已在 MySQL 8.0.46 隔离实例执行;生产实际版本、数据量与执行计划仍须用只读账号在发布窗口复核,不得在主库高峰期首次运行。 +- 迁移均按向前兼容设计。常规故障只回退 backend/admin/H5 版本软链接及小程序平台版本,不删除列/表/索引,不自动恢复旧备份。 +- 灾难性整库恢复会丢失备份时间点后的数据,必须另获业务负责人、DBA 与隐私负责人书面授权;本 RC 不授权该操作。 +- 本地验证没有使用生产凭据、真实微信账号、真实门店数据,也没有连接或修改任何生产服务器、Gitea、GitLab、Nginx、证书或业务数据库。