From 90177308e031a05e87085c81923fc21616a58e70 Mon Sep 17 00:00:00 2001 From: Suzumiya Date: Sat, 12 Sep 2026 02:07:49 +0800 Subject: [PATCH] =?UTF-8?q?pitfalls=EF=BC=9A=E8=A1=A5=E8=AE=B0=E3=80=8C?= =?UTF-8?q?=E5=90=8C=E4=B8=80=E6=9D=A1=E5=91=BD=E4=BB=A4=E7=9A=84=E5=8F=A3?= =?UTF-8?q?=E5=BE=84=E5=B7=AE=E5=BC=82=E3=80=8D=E2=80=94=E2=80=94CI=20?= =?UTF-8?q?=E7=94=A8=E6=8F=90=E4=BA=A4=E8=8C=83=E5=9B=B4=E6=AF=94=E8=BE=83?= =?UTF-8?q?=20git=20diff=20--check?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - docs/project-memory/shared-memory/pitfalls.md:在「只跑门禁子集 → 同一天两次 CI 红」条目的「原因」里补第三类成因 - 口径差异:CI 跑 git diff --check "${base_ref}"..."${head_ref}"(提交范围),本地裸跑 git diff --check(工作树 vs 索引)在干净树上恒为空,所以本地绿不能证明 CI 这一跳会过 - 实例:pitfalls.md 末尾多出的空行(f16aa440b 引入),因前两次推送分别停在 check:git-hooks 与 check:rustfmt 而一直未被这一跳检查 --- docs/project-memory/shared-memory/pitfalls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/project-memory/shared-memory/pitfalls.md b/docs/project-memory/shared-memory/pitfalls.md index cb4f63903..740de9efb 100644 --- a/docs/project-memory/shared-memory/pitfalls.md +++ b/docs/project-memory/shared-memory/pitfalls.md @@ -5350,7 +5350,7 @@ ## 2026-09-12 只跑门禁子集 → 同一天两次 CI 红:本地必须按 npm run lint 的完整链路跑齐 - **现象**:同一天两次 Repository checks 红,都不是代码写错,而是「本地只跑了门禁的一个子集」:① `dd7cf401a` 给 lint-staged 加了 `*.rs` 键,**本地从未跑过 `check:git-hooks`**(它是 `npm run lint` 链里的一环),而 `scripts/git-hooks.test.mjs` 用 `assert.deepEqual` 钉住 lint-staged 的**整份配置形状** → CI 以 `deepStrictEqual` 失败;② 本批更早还因 `check:rustfmt` 红过一次(`15660a98b` 修掉 8 处格式偏差),成因是 pre-commit 的 lint-staged 当时只覆盖 `*.{js,mjs,cjs,ts,tsx}`,Rust 格式在本地没有任何守卫。 -- **原因**:`npm run lint` 是一条 `&&` 长链 —— `check:encoding && check:npm-workspaces && check:git-hooks && check:rustfmt && check:spacetime-schema && check:production-ops && check:preview-deployer && check:maintenance-page && lint:eslint && typecheck`(其中 `check:git-hooks` = `node --test scripts/git-hooks.test.mjs`)。**只要中间某一步失败,它之后的步骤根本不会执行**,于是「跑到第 N 步就以为本地绿了」;而 CI 的 Repository checks 跑的是 `scripts/check-repository-ci.sh` → `SPACETIME_SCHEMA_BASE_REF=… npm run lint`(外加 `appSurface.test.ts`、`npm run build`、基线到候选提交的 `git diff --check`)。更隐蔽的是:本地若因**环境原因**在中间断掉(如 Windows 上 `check:git-hooks` 第 2 个用例的 EBUSY),**后面那些本来能通过的步骤也从未被验证过**。 +- **原因**:`npm run lint` 是一条 `&&` 长链 —— `check:encoding && check:npm-workspaces && check:git-hooks && check:rustfmt && check:spacetime-schema && check:production-ops && check:preview-deployer && check:maintenance-page && lint:eslint && typecheck`(其中 `check:git-hooks` = `node --test scripts/git-hooks.test.mjs`)。**只要中间某一步失败,它之后的步骤根本不会执行**,于是「跑到第 N 步就以为本地绿了」;而 CI 的 Repository checks 跑的是 `scripts/check-repository-ci.sh` → `SPACETIME_SCHEMA_BASE_REF=… npm run lint`(外加 `appSurface.test.ts`、`npm run build`、基线到候选提交的 `git diff --check`)。更隐蔽的是:本地若因**环境原因**在中间断掉(如 Windows 上 `check:git-hooks` 第 2 个用例的 EBUSY),**后面那些本来能通过的步骤也从未被验证过**。③ 还有一类同样隐蔽的是**同一条命令的口径差异**:CI 的 `git diff --check` 跑的是**提交范围** `git diff --check "${base_ref}"..."${head_ref}"`(base 取 PR 的 base sha,CI 日志里是 `[repository-ci] base=…`),而本地裸跑 `git diff --check`(工作树 vs 索引)在干净树上**恒为空**——于是「本地 `git diff --check` 干净、exit 0」根本不能证明 CI 这一跳会过:`pitfalls.md` 末尾多出的那一个空行(`f16aa440b`)就是这样漏掉的,而且它在前两次推送里都因为链条分别停在 `check:git-hooks` / `check:rustfmt` 而从未被这一跳检查过。本地要同口径复现与自检,必须用 `git diff --check ..HEAD`,不要裸跑 `git diff --check`。 - **处理**:push 前按链路逐条跑,不要只跑子集;`&&` 链在某一步失败时,**必须把失败步之后的每一步单独再跑一遍**(上列 10 步 + `git diff --check`),逐条记 exit code(取 exit code 不要接管道)。凡改动碰到 `package.json` / `.husky/` / `scripts/` 下的门禁资产,**`check:git-hooks` 是必跑项**——它钉住 hook 与 lint-staged 配置的形状,增删键都会让它以 `deepStrictEqual` 失败。 - **验证**:本次 `check:git-hooks` 因本机 Windows EBUSY 中断后,把其后各步单独跑齐:`check:spacetime-schema` / `check:production-ops` / `check:preview-deployer` / `check:maintenance-page` / `lint:eslint` / `typecheck` / `check:encoding` 全部 `exit 0` —— 即「因为前一步红而没跑到」的部分本来是全绿的;只有 `check:rustfmt` 红,且红在别人在途的 `.rs`(`assets.rs:519` 落在其未提交 hunk `+470,62`、`commands.rs:3079` 落在其未提交 hunk `+3068,58`)。变异验证:把 `*.rs` 从 `package.json` 摘掉 → `check:git-hooks` 第 1 个用例以同样的 `deepStrictEqual` operator 变红(`# fail 2`);还原(`package.json` SHA256 与改前一致)后该用例回 `ok`。 - **关联**:`package.json` 的 `lint` / `check:git-hooks` / `check:rustfmt`、`scripts/check-repository-ci.sh`、`scripts/git-hooks.test.mjs`、`.husky/pre-commit`、提交 `dd7cf401a` / `2a7bfadd7` / `15660a98b`。