diff --git a/docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md b/docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md index 0a581aa..a6ab428 100644 --- a/docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md +++ b/docs/superpowers/plans/2026-09-18-phase23-closeout-and-uat-readiness.md @@ -21,7 +21,7 @@ | Phase 23 | ⚠️ **部分关闭** —— 44 个 `pass` 空壳已清、4 个真实 INV 行为守卫已补;**E2E 场景实现已完成(2026-09-19,见 Task 2.1)**;**INV-011 已补真实行为守卫(2026-09-19,见 Task 2.2,9 用例 + 两次注入验证)**。仅余 E2E 在 CI 上的首次实测绿 | | Phase 23B | ✅ E2E 测试基建重建(conftest + seed + CI e2e job,本机活栈 49 → **65 passed**) | | 横向加固 | ✅ HTTP 语义(105 处真实状态码)+ 身份收敛 + 幂等键(30 端点,V045/V046)+ 端口/入口守卫 | -| 后端回归 | **669 / 0 failures / 0 errors / 3 skipped** | +| 后端回归 | **678 / 0 failures / 0 errors / 3 skipped**(2026-09-19 全量实测,含本轮新增 9 例 INV-011 守卫) | | UI 契约门禁 | **18/18 绿**(原文 14/14 已过期,见 Global Constraints) | | 停点 | **Phase 24(UAT)启动门前 —— 需用户确认** | @@ -36,11 +36,18 @@ - **禁止用 `rm` / `git rm` 删除文件** —— 本机有 safe-delete 钩子会把「删文件」放大为「删父目录」(2026-09-18 实测:`git rm` 单个文件导致整个 `docs/` 被移除)。需要移除内容时**一律原地重写**(Write/Edit)。 - 不修改业务规则、不扩大 V1 范围;新增能力必须走 Phase 顺序。 - 每批完成后跑 `node scripts/run-ui-contracts.mjs`(**守卫数量以执行器 `MIN_GUARDS` 为准;2026-09-19 实为 18 个,须 18/18 绿** —— 原文「14 个 / 14/14」已过期:2026-09-19 起相继新增 `wxml-structure-contracts`、`miniapp-self-method-contracts`、`wxss-component-selector-contracts`、`miniapp-api-client-behavior`)+ `ui-document-baseline-contracts.mjs`(含端口与 `/admin/` 子路径断言)。 -- 后端改动跑容器 `mvn test`(**2026-09-19 校正:不能用 `-o` 离线** —— - 本机可用的测试镜像 `danyang-match-backend-test` 里缺 `surefire-junit-platform`, - 离线模式必报 `BUILD FAILURE`;首次运行需联网下载该 provider,之后才有缓存。 - 原文「离线容器 `mvn -o test`」在本机**不可执行**),必须 0 failures / 0 errors。 - 命令见附 B-9。 +- 后端改动跑离线容器 `mvn -o test`,必须 0 failures / 0 errors。 + ⚠️ **2026-09-19 补注:必须挂载命名卷 `-v danyang-m2-cache:/root/.m2`。** + 镜像内置的 `/root/.m2`(132MB)**不含** `surefire-junit-platform`;漏挂该卷时 `-o` 必报 + `BUILD FAILURE ... could not be resolved ... in offline mode` —— + **看起来像「离线不可用」,实为「m2 卷没挂」**(本人本轮即据此误判过一次,见附 B-9 的更正)。 + 命名卷实为 251MB 且含该 provider(`surefire-junit-platform/3.1.2` 实测存在)。 + ⚠️ **第二处必挂:把「仓库根」挂进来,CWD 指向 `backend`** —— `-v :/proj -w /proj/backend`。 + 若干测试用**相对仓库根**的路径读文件(如 `backend/src/main/resources/db/migration`、 + `admin-web/src/modules/.../ServiceStationView.vue`);若只挂 `backend/` 并 `-w /app`, + 它们会集体报 `NoSuchFile`(本轮实测:35 failures + 54 errors **全部**是这一类, + **是挂载方式错,不是代码错** —— 别误当成回归)。 + 全量另加 `-Dsurefire.forkCount=1 -DreuseForks=true`。完整命令见附 B-9。 - **E2E 改动跑 `pytest tests/e2e`**(需活栈;本机 `E2E_BASE_URL=http://localhost:8085/api/v1`、`E2E_OPERATOR_PASSWORD` 见 CI 变量),必须 0 failed。 本机复跑前若出现 `429 账号已锁定`,是 Redis 里的登录失败锁定键(`auth:operator_login_lock:`,TTL 15 分钟), 由前一轮失败登录累积触发 —— 删掉该键即可,不是业务缺陷。 @@ -331,7 +338,8 @@ | Global Constraints / 验收纪律 / 当前停点 | UI 契约门禁 14 个、14/14 绿 | **18 个**(2026-09-19 相继新增 4 项守卫),基线 18/18 | | Task 2.1 | `tests/e2e/**` 现为占位文件 | **仅 2 个文件**是占位;其余在 Phase 23B 已是真实用例 | | 当前停点 | 本机活栈 E2E `49 passed` | 基线 49,Task 2.1 完成后 **65 passed** | -| Global Constraints | 后端改动跑**离线**容器 `mvn -o test` | 本机测试镜像缺 `surefire-junit-platform`,`-o` **必然 BUILD FAILURE**;须去掉 `-o` 联网跑(附 B-9) | +| Global Constraints | 后端改动跑离线容器 `mvn -o test` | **原文无误**;但「离线容器」的完整命令有两处**必挂**,否则会导出错误结论:`-v danyang-m2-cache:/root/.m2` + 挂**仓库根**并 `-w /backend`(附 B-9) | +| 本文档自身(本轮中途两次误判) | 先写「`-o` 不可用」,后写「35 failures + 54 errors 是回归」 | **两条均误**:前者是漏挂 m2 卷(内置仓库 132MB 缺 `surefire-junit-platform`),后者是只挂 `backend/` 致相对路径失效。正确命令下全量 **678 / 0 / 0 / 3 全绿**(附 B-9) | | Task 2.2 Step 3 | 「改 Java 代码需重建镜像,注入成本极高」 | 镜像 `danyang-match-backend-test` 内含 JDK 21 + Maven + 依赖缓存,**挂载源码即可跑 surefire**,一轮注入≈3.5 分钟(附 B-9) | | 附 B-1(初稿) | 机构创建 500 因「从不给 `id` 赋值 → uuid 空串」 | **归因错误**。实测为 `violates check constraint "chk_org_status"`(status 被写成 `normal`);`id` 由 `AutoFillHandler` 补全,不会为空。已在 B-1 内留痕更正 | @@ -395,24 +403,35 @@ 只能退化成常量断言(这正是 Task 2.2 之前的状态)。已按三份迁移补齐列定义(不建 FK, 因测试库无 `operators` 表;与 `review_tasks` / `local_eligibility_evidences` 同风格)。 与 schema-h2.sql 中已记录的 Phase 12/15/19 系列「表/约束漂移盲区」同族。 -9. **本机跑 Java 测试的通道**(工具性发现,可复用) +9. **本机跑 Java 测试的通道 —— 含两处「必挂」,漏掉任一处都会导出完全错误的结论**(工具性发现,可复用) 本机**无 JDK / 无 Maven / 无 `~/.m2`**(`mvn` 报 `Could not find Maven installation`), - 但存在镜像 `danyang-match-backend-test`(940MB,内含 Temurin JDK 21 + Maven 3.9.16 + - `/root/.m2` 132MB 依赖缓存 + 完整源码)。挂载源码即可直接跑 surefire: + 测试镜像 `danyang-match-backend-test` 内含 Temurin JDK 21 + Maven 3.9.16 + 完整源码。 + **正确命令**(2026-09-19 实测 `BUILD SUCCESS`,全量 **678 / 0 failures / 0 errors / 3 skipped**,约 6 分钟): ```bash - docker run --rm -v "E:/develop/公益婚恋服务平台/backend":/app -w /app \ - danyang-match-backend-test:latest mvn test -Dtest=<测试类> -DfailIfNoTests=false + MSYS_NO_PATHCONV=1 docker run --rm \ + -v "E:/develop/公益婚恋服务平台":/proj \ + -v danyang-m2-cache:/root/.m2 \ + -w /proj/backend --memory=3g -e MAVEN_OPTS=-Xmx256m \ + danyang-match-backend-test:latest \ + mvn -B -o test -Dsurefire.forkCount=1 -DreuseForks=true ``` - - 首次运行需**联网**下载 `surefire-junit-platform`(该 jar 不在缓存里);`-o` 离线模式会失败。 - - 单次编译 + 运行约 3.5 分钟;`backend/target/` 会被容器写回宿主机(该目录已忽略,无碍)。 + 单类跑法:把 `test` 换成 `test -Dtest=<类名> -DfailIfNoTests=false`,约 3.5 分钟。 + + | 漏挂项 | 症状 | 会被误判成 | + |---|---|---| + | 不挂 `-v danyang-m2-cache:/root/.m2` | `-o` 报 `could not be resolved ... in offline mode`(镜像内置 `/root/.m2` 仅 132MB,**缺** `surefire-junit-platform`;命名卷 251MB **含** 3.1.2) | 「本机不能离线跑测试」 | + | 只挂 `backend/` 而非**仓库根** | `MigrationValidationTest` / `AnalyticsPermissionGrantTest` / `SecurityPathCoverageTest` / `PrincipalInjectionContractTest` 等集体 `NoSuchFile`(它们用**相对仓库根**的路径读文件,如 `backend/src/main/resources/db/migration`) | 「35 failures + 54 errors 的真实回归」 | + + > **本人在本轮两条都踩了**:先据第一次失败把「`-o` 不可用」写进 Global Constraints, + > 又据第二次失败把「35 failures 全绿不了」当成回归;两次都被「换个挂载方式重跑」推翻。 + > **教训:测试失败时先怀疑命令与挂载,再怀疑代码** —— 尤其当失败清一色是 + > `NoSuchFile` / `could not be resolved` 这类**基础设施型**错误时。 + > (同理作废的还有一条中途结论:「全量跑 1 小时卡住」——那是漏挂 m2 卷 + 未加 + > `-Dsurefire.forkCount=1 -DreuseForks=true` 的错误命令所致,正确命令 6 分钟跑完。) + - **重要**:这使 Task 3.x 一类「改 Java 代码」的验证不再需要重建后端镜像 —— 原 Task 2.2 Step 3 标注的「改 Java 需重建镜像、成本极高」不再成立,负向注入可直接做。 - - ⚠️ **本机跑「全量」后端测试会卡住(实测)**:2026-09-19 尝试 `mvn test` 跑全部 102 个测试类, - 运行 **1 小时仍未产出任何 surefire 报告**(`docker ps` 显示容器在跑,`surefire-reports/` 无新文件), - 疑似某个 `@SpringBootTest` 阻塞在无超时的外部连接上。已强制终止。 - **结论:本机只适合跑「单个测试类」回归**(`-Dtest=<类名>`,约 3.5 分钟); - 全量回归应交给 CI(Task 2.3 已把 backend test 串进流水线)。 - 本机验证策略因此为:改动哪个测试类就单跑哪个 + 依赖 CI 做全量兜底。 + - `backend/target/` 会被容器写回宿主机(该目录已 gitignore,无碍)。 10. **5 个 Mapper 方法「声明了却无实现」**(High,**未实测触发,但判定依据可复核**) `Backend` 的 mapper 统一用**注解式 SQL**(如 `ActivityCapacityGroupMapper` 的 `@Select`/`@Update`)。 以下方法**既无 SQL 注解、也无 XML**: @@ -466,5 +485,7 @@ --- *创建: 2026-09-18 — 承接 `docs/文档治理报告-2026-09-18.md` 与 STATUS.md 的两处悬空引用(D1)* -*审阅校正: 2026-09-19 — 按实测推翻 7 处失实断言(见附 A,含 1 处**对本文档自身初稿的更正**),登记 11 项新发现(见附 B)* -*执行进展: 2026-09-19 — Task 2.1(E2E 16 场景)、Task 2.2(INV-011 守卫)均已完成并验证* +*审阅校正: 2026-09-19 — 按实测推翻 9 处失实断言(见附 A;其中 2 处是**对本轮自查中自身结论的更正** —— +「`-o` 不可用」「35 failures 是回归」两条均系命令/挂载所致,已如实留痕),登记 11 项新发现(见附 B)* +*执行进展: 2026-09-19 — Task 2.1(E2E 16 场景)、Task 2.2(INV-011 守卫)均已完成并验证; +后端全量回归 678 / 0 failures / 0 errors / 3 skipped;UI 契约门禁 18/18 绿*