Explorar el Código

docs(进件): 前端半边的交付提交读数 + 台子 README(跑法原先只在 git-ignored 台账里)

后端半边早有「交付提交上」的读数(652 绿),前端只有 R-7c 当时的 `pnpm build` exit 0 且没写明
跑在哪个提交;四支验证台的**命令行**也只存在于 git-ignored 的 SDD 台账里 ⇒ 台账不随交付走,
验收者手上只有 .mjs 文件、没有跑法。本轮补齐这两件。

一、前端半边的交付提交读数(在 frontend/ 内跑,同机)

- `pnpm build`(= vite build):**exit 0 / `✓ built in 58.66s`**,dist/ 260 文件。
  配了**同谓词正控**:产物里能查到本批进件页的 5 条独有中文 UI 串,各命中 1 个文件且全在同一个
  chunk `js/index.BJKmxGsh.js`;负对照 2 条各 0。⇒ 「构建成功」不是「构建了一份不含本页的旧产物」。
  第 6 条探针 `级联数据加载失败:` = 0,**不是缺陷**:它只在 `index.vue:591` 的 console.warn 里,
  而 `vite.config.ts:124` 是 `drop_console: true` ⇒ 按配置本就该不在产物里(两个转义变体也量过,都是 0)。
- `pnpm ts:check`:exit 2 / 287 个 error TS / 51449 B / sha16 `98934f0a0c307bc1`
  —— 与本批早前记下的基线**逐字节相同**。本仓 ts:check 有非零历史基线,「跑绿了」不成立,
  只能同机前后差分 ⇒ sha 相同即全批零新增类型错误。

二、四支台子在交付提交上复跑(从新位置、仓库根为 cwd)

task-9-fix1 `pass=25 fail=0`、fe-update-harness `pass=43 fail=0`、keycheck `全绿`、mutate restore rc=0;
跑前跑后 `git status -- frontend/` 均 0 脏文件、无残留 .mut-bak。

三、新增 .claude/plan/…-harness/README.md

写给验收者:确切命令行、**判成败只读 SUMMARY 行**、每支钉什么、已知局限、restore 与变异的安全边界、
两种行尾的指纹对照表;内容全按实跑读数写。并实测一条省事的用法:stderr 丢掉后 stdout 只剩 PASS 与 SUMMARY。

★ 顺带订正交付说明一处措辞:「exit code 恒 0」只对**传对参数**的调用成立(台子故意不设
process.exitCode);**漏传页面路径**时那两支会当场崩在 compileSfc 的 readFileSync、**退 1**。
判据仍只看 SUMMARY,但补了「退 1 且栈顶是 readFileSync = 参数没传,不是台子坏了」。

本轮未动任何生产码。
alphaH hace 3 semanas
padre
commit
c638dea7c7

+ 115 - 0
.claude/plan/2026-09-23-lsy-onboarding-B-harness/README.md

@@ -0,0 +1,115 @@
+# 批次三-B 的四支验证台 —— 怎么跑、看什么
+
+这四支是**验收用**的:不连库、不连上游、**不发任何网络请求**,也不需要登录凭据。
+它们直接编译真的 Vue SFC、跑 `frontend/` 里那份真的 `vue`、驱动页面的真 `setup()`,
+只把 `@/api` 与上传子组件桩掉。
+
+来源与搬迁经过见 `.claude/plan/2026-09-23-lsy-onboarding-B-交付说明.md` §四 4。
+**本 README 的每一条命令与读数都是 2026-09-23 在交付提交 `20a222b` 上实跑取的,不是转述。**
+
+---
+
+## 0. 公共前提
+
+- Node:实测 `v22.22.3`。
+- 工作目录:README 里的命令以**仓库根** `D:/project2/payment-platform` 为 cwd 写。
+  台子内部用的是绝对路径,换 cwd 不影响结果(已实测:从 `D:\` 跑同样通过)。
+- 依赖 `frontend/node_modules`:台子用 `createRequire` 指到 `frontend/package.json` 来加载 `vue`
+  与 `@vue/compiler-sfc` ⇒ 那个目录不存在时**加载这一关就过不去**,先 `pnpm i`。
+- **跑之前 `git status -- frontend/` 应当是干净的**,跑完还应当是干净的(下面每支都不写生产文件,
+  `fe-update-mutate` 的 `restore` 分支也一样)。
+
+## 1. 两支要传页面路径的台子(**不传会崩**)
+
+这两支把目标页面当**命令行参数**读(`process.argv[2]`):
+
+```bash
+PG="D:/project2/payment-platform/frontend/src/views/module_payment/collection/onboarding/index.vue"
+
+node .claude/plan/2026-09-23-lsy-onboarding-B-harness/task-9-fix1-harness.mjs "$PG"
+node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-harness.mjs "$PG"
+```
+
+**忘了传参数会怎样**:立刻崩,`TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string ... Received undefined`
+(栈顶是 `compileSfc` 里的 `readFileSync`),**退出码 1**。看到这个就是漏了页面路径,不是台子坏了。
+
+### 判成败只看 `SUMMARY` 行
+
+两支都会在最后打一行汇总。**不要看退出码**:台子**故意不设** `process.exitCode`
+(`fe-update-harness.mjs` 第 14 行的注释就是这么写的),所以**有 `FAIL` 也退 0**;
+唯一会给出非 0 退出码的情况是上面那种「参数没传」的崩溃。
+
+所以判据是这两行里的 `fail=`:
+
+```
+SUMMARY <页面路径>: pass=25 fail=0      ← task-9-fix1-harness.mjs
+SUMMARY <页面路径>: pass=43 fail=0      ← fe-update-harness.mjs
+```
+
+有失败时同一行会追加失败用例名:`... fail=2 -> <用例名> | <用例名>`。
+
+交付提交 `20a222b` 上的实测读数就是上面这两个(各 1 次,`exit=0`,`frontend/` 跑完仍干净)。
+
+★ 顺手可以把 stderr 丢掉,屏幕只剩 PASS 与 `SUMMARY`(实测:`2>/dev/null` 后 stdout 为 27 行
+且不含 `[Vue warn]`)—— 台子的告警与桩报错**都在 stderr**,stdout 是干净的判据流。
+
+### 各自钉什么
+
+- **`task-9-fix1-harness.mjs`(25 条)**:进件页 Task 9 那处修复(商户号回显 / 警示)的判定逻辑,
+  含两条**正对照**(G4「正常商户号 ⇒ 显示出来」、G5「正常商户号 ⇒ 不置警示」)
+  —— 没有正对照的话「一律不显示」也会全绿。
+- **`fe-update-harness.mjs`(43 条)**:R-7c「建号 / 更新」两个模式各自的报文形状
+  (U1/U1b 更新报文不含 `merchant_name_business`;Z5/Z6 更新集与建号集里都没有
+  `category` / `tenant_id` / `rate_code`)。
+
+### 已知局限(别把它的绿读大)
+
+- **模板不渲染** ⇒ 它证明的是**函数判定逻辑**,**不证明浏览器里的表现**。
+- stderr 上会出现一条 `[Vue warn]: onMounted is called when there is no active component instance...`
+  —— 这是桩环境没有组件实例导致的,**预期内**,不是失败。
+- stderr 上还会有一段桩出来的报错(例如 `级联数据加载失败: Error: 网络挂了`),
+  那是**故意注入的网络失败**用例在走错误分支,同样不是失败。
+  (这两条都实测过只在 stderr:`2>/dev/null` 之后 stdout 里一个都没有。)
+
+## 2. 静态键名核对台(不需要参数)
+
+```bash
+node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-keycheck.mjs
+```
+
+**退出码 0** + 末行 `SUMMARY keycheck: 全绿`。它比对前后端两侧的字段键名集合,
+确认没有拼错的键(跨端键名拼错在运行时只会表现为「字段悄悄没发出去」)。
+
+★ 这支是四支里**唯一搬过家时改过内容**的一支:原先写死了兄弟台子的工作区绝对路径,
+搬完就成了一个已删除的文件 ⇒ 改成按**自身位置**相对定位
+(`fileURLToPath(new URL("./fe-update-harness.mjs", import.meta.url))`)。
+所以它必须与 `fe-update-harness.mjs` **待在同一个目录**里。
+
+## 3. 变异驱动(跑之前先看清楚)
+
+```bash
+node .claude/plan/2026-09-23-lsy-onboarding-B-harness/fe-update-mutate.mjs restore
+```
+
+- `restore`:把备份 `.mut-bak` 还原回生产文件。**没有备份时什么都不做,退出码 0。**
+- 传其它任何 id(`M-U1` / `M-U2` / `M-U3` / `M-U5` / `M-T1` / `M-T2`):**会真的改生产前端文件**
+  (`frontend/src/views/module_payment/collection/onboarding/index.vue` 与
+  `frontend/src/api/module_payment/onboarding.ts`),并在同目录留 `.mut-bak`。
+  跑完**必须**用 `restore` 还原,再用 `git status -- frontend/` 确认干净。
+
+**验收不需要跑变异。** 想跑的话按「先 `git status` 干净 → 变异 → 跑第 1 节的两支台子看读数变化 → `restore` → 再 `git status` 干净」的顺序。
+
+## 4. 核指纹时注意行尾
+
+本仓 `core.autocrlf = true` 且**没有 `.gitattributes`** ⇒ **重新 checkout 会把工作区文件抹成 CRLF**。
+两种形态**都实测过**,不是按行数推算的(LF 即当前工作区形态):
+
+| 文件 | LF 字节 | LF sha256 |
+|---|---|---|
+| `task-9-fix1-harness.mjs` | 10796 | `7f07de4099c96a23c56c1238aeb002857ed8bc10c83458feab5b979cac5bc095` |
+| `fe-update-harness.mjs` | 12783 | `5b91fa4b452d6aa6816ec523c2c057d28422a3a055d2e725c87af74b63984dad` |
+| `fe-update-keycheck.mjs` | 6874 | `3d4033167ed8950cda71c3396d77fe4968f70aafef915f2616193a675eba1767` |
+| `fe-update-mutate.mjs` | 4197 | `a3e68dff6d58fd86a6b219c2de50f98493434bc929c544d9f77bb1af9565a330` |
+
+CRLF 形态:11049 / 13057 / 7002 / 4294 字节,sha256 见交付说明 §四 4。
+**核出 CRLF 那组数不是文件被改过,是行尾。**

+ 25 - 0
.claude/plan/2026-09-23-lsy-onboarding-B-交付说明.md

@@ -207,6 +207,16 @@
    keycheck **7002 B / `2e1eb43d829ea7e4aabc330c77d4a5605c4b4672a580d21ace255fbfa26325e4`**、
    mutate **4294 B / `fafacc0c8e41091a870054098c2de20dc46f90670890983dcd5101f9d8d65621`**。
    ⇒ 你若核出这几个数,**不是文件被改过,是行尾**。
+   ★ **2026-09-23 在交付提交上把四支各复跑一遍**(从新位置、仓库根为 cwd):
+   `task-9-fix1-harness.mjs` **`pass=25 fail=0`**、`fe-update-harness.mjs` **`pass=43 fail=0`**、
+   `fe-update-keycheck.mjs` **`SUMMARY keycheck: 全绿`**、`fe-update-mutate.mjs restore` **rc=0**;
+   跑前跑后 `git status -- frontend/` 均 **0 个脏文件**(没有残留 `.mut-bak`)。
+   ★ **同目录新增 `README.md`**:四支怎么跑、读哪一行、各钉什么、已知局限、两种行尾的指纹。
+   写它的理由是**跑法原先只存在于 git-ignored 的 SDD 台账里**,而台账不随交付走 ⇒ 验收者拿不到命令。
+   ★ **一处措辞要收窄**:上文那句「**exit code 恒 0**」对**传对参数**的调用成立
+   (台子**故意不设** `process.exitCode`,失败也退 0);但**漏传页面路径**时那两支会当场崩在
+   `compileSfc` 的 `readFileSync`(`ERR_INVALID_ARG_TYPE`)并**退 1**。
+   ⇒ 「判成败只读 `SUMMARY`」这条不变,补一句:**退 1 且栈顶是 `readFileSync` = 参数没传,不是台子坏了。**
    ★ **若你要的其实是 ①「收编」**(那是新工作:得先给 `frontend/` 引入测试入口),说一声即可 ——
    本行按「现方案走」读作 ②,是因为 ① 会**改变仓库内容**,与「按现方案走」相反。
 
@@ -471,6 +481,21 @@
   ★ **能这样说的依据是实测不是推断**:`git diff --name-only 1af6ef2..HEAD -- 'java/**'` = **0 个文件**
   (即 R-7c 之后 java/ 一个字没动;同一支命令在 `663156f..HEAD` 上量到 **36** 个文件 ⇒ 量具是活的)。
   ⇒ 本条的用处:给出**交付提交上的读数**(上面那条 652 没写明跑在哪个提交)。
+- ★ **前端半边的交付提交读数**(2026-09-23,同机、在 `frontend/` 内跑;此前只有后端半边有「交付提交上」的读数):
+  ① **`pnpm build`(= `vite build`):exit 0 / `✓ built in 58.66s`**(`dist/` 共 260 个文件)。
+     ★ 配了**同谓词正控** —— 产物里能查到本批新增进件页的**独有中文 UI 串**:
+     `三联单合同照片`、`对私账户身份证反面照片`、`尚未选到最末一级`、`结算银行支行联行号`、
+     `其他证明材料(选填)`,**各命中 1 个文件、且全在同一个 chunk `js/index.BJKmxGsh.js`**;
+     负对照 2 条各 **0** 命中。⇒ 「构建成功」不是「构建了一份不含本页的旧产物」,这是关键区别。
+     ★ 第 6 条探针 `级联数据加载失败:` 命中 **0**,**这一个解释得通、不是缺陷**:它只出现在
+     `index.vue:591` 的 `console.warn(...)` 里,而 `vite.config.ts:124` 是 `drop_console: true`
+     (注释即「生产环境去除 console.log, console.warn, console.error 等」)⇒ 按配置它本就该不在产物里。
+     (旁证:同一串在台子运行时的 stderr 里**确实打出来了**,说明它只在运行时、不在产物里。)
+  ② **`pnpm ts:check`(重定向 only):exit 2 / 287 个 `error TS` / 51449 B / sha16 `98934f0a0c307bc1`**
+     —— 与本批**早前记下的基线逐字节相同**(台账那两次读数:51449 B、同 sha16)。
+     本仓 ts:check 有**非零历史基线**,「跑绿了」在这里不成立,只能同机前后差分 ⇒
+     这次 sha 相同 = **全批零新增类型错误**,且旧读数被逐字节复核。
+     (`dist/` 由根 `.gitignore:10 frontend/dist/` 忽略,构建不会往仓库里留东西。)
 - **两个注释修复提交 `70bb22a`、`2663020` 也都是 645 绿**(BUILD SUCCESS)。
   两者**「逐字节无行为变化」的完整证据**(`2663020` 这一版**两侧的 class 读数都是我自己采的**):
   ① 行数不变(CR=1485 / LF=1485,无孤立 CR/LF,行尾仍 CRLF)⇒ `LineNumberTable` 不变;