Skip to content

build(deps): vitest 4→5 连同 @vitest/coverage-v8 一起升(取代 #731) - #748

Merged
0xPabloLI merged 29 commits into
devfrom
deps/vitest-5
Oct 9, 2026
Merged

0xPabloLI merged 29 commits into
devfrom
deps/vitest-5

Conversation

@0xPabloLI

Copy link
Copy Markdown
Owner

Summary

把 vitest 与 @vitest/coverage-v8 一起升到 5.0.3,取代 #731。

为什么 #731 合不进去

#731 只升了 vitest,而 vitest 5 的 peer 要求 @vitest/coverage-v8: 5.0.3(仓库钉的是 ^4.1.11)⇒ 严格 npm ci 失败。peer-dep-check 是 dev 与 main 都必填的检查,所以那笔 PR 无论怎么 rebase 都是红的。

renovate.json 的 npm 侧没有把 vitest 族分组的规则,所以换成 Renovate 也只会提同样的半截 PR——这一点是本 PR 存在的主要理由。

验证(v4 基线 vs v5,同机对照)

项目 vitest 4(lovable 基线) vitest 5(本分支)
单测 4087 passed / 14 skipped / 6 todo(194 文件) 3793 passed / 14 skipped / 6 todo(173 文件)
npm ci 严格安装 通过 通过(rc=0)
npm run typecheck 通过 通过
npm run lint 0 error / 76 warning 0 error / 76 warning(同一批既存 warning)
npm run test:coverage 阈值门 rc=0,All files 73.23 / 66.82 / 64.36 / 75.19 rc=0,All files 73.17 / 66.79 / 64.36 / 75.13(阈值 72 / 66 / 63 / 74 全在上方)
scripts/** node --test 137 passed 137 passed

少掉的 21 个文件不是回归(做过归因)

差值全部来自未被 git 跟踪的本地 skill 目录:.agent/、.agents/、.claude/、.cursor/、.codeartsdoer/、aaveapy-doc/ 下的 web-access/scripts/__tests__/*.test.mjs。vitest 4 会把它们 glob 进 npm test(这也是基线 import 耗时 179s vs v5 49s 的原因),vitest 5 不再收集点目录。

对照判据:git ls-files 里匹配的测试文件 173 个,v5 收集且被跟踪的也是 173 个,差集为空;其余 45 个跟踪文件是 e2e/*.spec.ts(Playwright 管道)与 scripts/*.test.mjs(node --test 管道),本来就不该由 vitest 收集。

大版本迁移面

vite.config.ts 的 test 段无需改动(exclude / setupFiles / coverage 键位在 v5 语义一致),源码与用例零修改即全绿——vitest 5 对本仓的破坏性变更集中在被丢弃的那批外部 skill 测试上,不在自有代码里。

推送过程如实记录(两次被挡,都按根因处理)

第一次:pre-push 的 osv-scanner 拦下 source-map-js 1.2.1(GHSA-68fv-2mgg-jv7q,8.7)——本分支的 lock 从 lovable 生成,还没带 #746 的修复。处置=git merge origin/dev(合并只动 package-lock.json,smol-toml → 1.9.0、source-map-js → 1.2.2 到位),未绕过 hook。

第二次:剩下的唯一一条是 postcss-selector-parser 6.1.4(GHSA-rj75-hqrm-r3gf,5.9,dev-only)。这就是仓库里那条至今无 PR 的 open Dependabot alert:6.x 线上没有修复版(最高 6.1.4),修复只在 7.1.6,而要求它的两个包 postcss-nested 与 tailwindcss 都声明 ^6.1.x ⇒ 正常升级路径不存在。

本 PR 采用 overrides: { "postcss-selector-parser": "7.1.6" }(与本仓既有做法一致:fast-uri/js-yaml/shell-quote/ws/brace-expansion 都是这么钉的)。跨大版本强钉的风险做了专门验证:

检查 结果
npm install 严格解析(依赖声明 ^6.1、实装 7.1.6) rc=0,lock 内 6.1.4 条目归零
npm run build(Tailwind 实际编译路径) rc=0
产出的 CSS 是否变化 逐字节一致:index-DyVJKc4h.css 与 vendor-blockchain-DR00Q9RG.css 内容哈希文件名完全相同,两份 CSS 拼接后 md5 相同(25368f2b…)
osv-scanner --lockfile package-lock.json rc=0(唯一剩下的 braces 已由 osv-scanner.toml 的 AAV-1328 条目过滤)

备选方案是在 osv-scanner.toml 加 ignoreUntil(AAV-1328 对 braces 就是这么处理的)。那条路不改产物、但放松门禁;本 PR 选的 overrides 路线有上面的 CSS 一致性证据支撑,如果你更倾向保守写法,把 overrides 那行换成 ignore 条目即可。

Test plan

  • CI 的 peer-dep-check / lint / build 三项必填转绿
  • pre-push 全门绿(ci:remote + test:e2e:pre-push + osv + semgrep + knip + dup),日志见 PR 活动
  • 合并后确认 e2e-desktop / e2e-mobile 四分片不受影响
  • 关闭 build(deps-dev): bump vitest from 4.1.11 to 5.0.3 #731(本 PR 取代它)
  • 后续可选:给 renovate.json 加 vitest 族分组规则,避免下次再出现半截大版本 PR

0xPabloLI and others added 27 commits October 1, 2026 01:17
生产每次加载有 1 条 CSP console error:Cloudflare 自动注入的 Web Analytics beacon
bootstrap 被 script-src 拦。已实测证伪「加 hash」这条路——内联块里的 r/t 每请求都变
(两次拉取值不同),Chrome 建议的那个 hash 只对当次响应有效。

不是 #693/1320 引入的回归:1320 之前 script-src 就没有 unsafe-inline 也没有 hash,
这段一直被拦;1320 的 spec 只枚举了 consent 块与 gtag.js 两类。现在把第三类写进
spec,避免下个改 CSP 的 session 再当成新发现。
osv-scanner 从 10-04 起阻断所有本地推送:braces 3.0.3 命中 CVE-2026-93687(8.7 High),
而它上游没有修复版(npm 最新就是 3.0.3;OSV ranges 只有 last_affected、没有 fixed 事件),
所以不能像三天前 axios 那次用 overrides 抬版本解决。它是 tailwindcss@3 → chokidar/micromatch
的 dev 传依赖,不在生产产物里。

只豁免这一条、带理由与 ignoreUntil=2027-01-31(实测:未来日期放行、过期后重新报错,
是真执行的时间闸)。到期若仍无修复版,走根治:换掉 tailwind v3 的 watch/glob 依赖链。
AAV-1328。
自动发现的文件名不能带点(.osv-scanner.toml 实测不生效);未知键是整份配置拒绝
加载而非忽略该条,写错等于豁免全废;ignoreUntil 需 RFC3339 且真的会过期(两个方向
都实测过);osv 只在 pre-push、CI 的 security-audit 是 --omit=dev + continue-on-error,
所以存在「CI 全绿但所有人都推不动」的形态。
相对上一版的四处调整,依据都取一手源码:

1. 取消 weekly schedule,回到引擎默认 at any time,改由 prHourlyLimit=2 +
   prConcurrentLimit=5 节流。按小时滚动才是 Renovate 的模型;把一批更新攒到周一
   是 Dependabot 的成批观感,代价是双轨期看不到任何动作、出问题也发现得晚。
   prConcurrentLimit 5 仍对齐 dependabot.yml 的 open-pull-requests-limit。

2. 纳入 devcontainer manager:.devcontainer/devcontainer.json 的
   image(mcr.microsoft.com/devcontainers/typescript-node:22)与
   features(ghcr.io/devcontainers/features/github-cli:1)此前无人看守——
   dependabot.yml 只配了 npm 与 github-actions。该 manager 同时提取 image 与
   features 两处版本(源码 manager readme),正好覆盖我们 Codespaces 的两个
   版本点。typescript-node 与 CI 的 node-version 是跨消费者契约,故一律人工评审,
   不进 automerge 标签。

3. minimumReleaseAge=7 days 只加在 github-actions 的 non-major 规则上,不是全局。
   它复刻 scripts/check-dep-release-age.mjs 的供应链等待期,而那道门的判据是
   package-lock 的 diff,看不见 workflow 里的 action 钉版 ⇒ actions 此前没有任
   何等待期保护,这里是唯一能落地该策略的位置。

4. 同时设 minimumReleaseAgeBehaviour=timestamp-optional,因为等待期依赖
   release timestamp,而源码注明 Docker 源只在 Docker Hub 取 tag_last_pushed;
   我们两个引用都在 mcr.microsoft.com 与 ghcr.io,无时间戳时默认的
   timestamp-required 会把更新判成 pending 永久搁置(util/minimum-release-age.ts
   的 isPending 分支)。devcontainer 规则因此不加等待期,只设人工评审。

automerge 仍保持 false:合并决策继续走现有 automerge.yml 的 PAT 路径,避免开出
第二条合并通道(也保住 lovable→dev MERGE / 其余 SQUASH 的策略)。

生效前提:Renovate 只读默认分支的配置,本文件需再经 lovable→dev→main 一轮。
AAV-1320 在 Linear 已 Done 却还留在「仅列 open」表里,按文件自身规则移出。
dev 已由 #716(删除 Dependabot 配置)与 #717(Renovate 接管 npm + 7 天等待期)
定下"只用 Renovate"的方向;本分支的 renovate.json 与它从同一 v1 分叉,故以 dev
的决策为基底合并,只改两处会让策略静默变形的地方:

1. 规则按 manager 分域。dev 版两条 packageRules 没有 matchManagers,npm 进入
   enabledManagers 后,npm 的非 major 升级会被打上 github_actions 标签,更紧要的是
   会拿到 automerge 标签 ⇒ 运行时依赖的 minor/patch 将被自动合入。原
   dependabot-auto-triage.yml 的门槛是 npm 只放行 direct:development 的 patch/minor,
   运行时依赖一律人工评审。这里用 matchDepTypes 复刻该门槛:devDependencies 非 major
   才进 automerge 标签,dependencies(运行时)任何类型都不给,major 一律人工。

2. 加 minimumReleaseAgeBehaviour=timestamp-optional。等待期依赖 release 时间戳,
   源码注明 Docker 数据源的 tag_last_pushed 只在 Docker Hub 可得;纳入 devcontainer
   后,我们两个引用(mcr.microsoft.com、ghcr.io)都没有时间戳,默认的
   timestamp-required 会把它们判成 pending 永久搁置(util/minimum-release-age.ts 的
   isPending 分支)。

保留 dev 的选择:weekly schedule、prHourlyLimit 0、全局 7 天等待期、npm 接管。
新增 devcontainer manager(.devcontainer/devcontainer.json 的 image 与 features 此前
无人看守;typescript-node tag 与 CI 的 node-version 是跨消费者契约,故一律人工评审)。

另:不在此刻删除 dependabot-auto-triage.yml / dependabot-resolve-peer-conflicts.yml。
dependabot.yml 只在 dev 被删、main 上仍在 ⇒ Dependabot 仍会往 dev 开 PR,这两个
workflow 目前还活着;等 dependabot.yml 离开 main 之后再收。

验证:renovate.json 无冲突标记且全部键经官方 schema 校验通过(含 matchDepTypes);
overrides 在 merge 中存活(brace-expansion 1.1.21/5.0.12、fast-uri 3.1.8);
lock 与合并后 package.json 一致(npm install 无 diff);osv-scanner rc=0;
npm audit --omit=dev 0 漏洞;check:e2e-market-names 29 spec rc=0。
node 版本在本仓有两个家:workflow 的 node-version(走 node 数据源)与 Dev Container
镜像 typescript-node(走 docker 数据源),二者之间没有任何机制保证同步。正在开的
#727 就是这个裂口的形状——它只改 6 个 workflow 到 v24,不碰 .devcontainer,合下去
CI 就跑 Node 24、Codespaces 仍是 22(本仓无 .nvmrc、package.json 无 engines,所以
这两处就是全部真值)。

做法是跨 manager 分组而不是手工拼一个 PR:后者只修这一次,前者让"必须同批"成为
配置约束——matchDatasources [node, docker] + matchPackageNames [node,
/typescript-node/] → groupName "node runtime",标签 manual-review。分组只在
devcontainer manager 生效后才有意义,故依赖同一份配置里的 enabledManagers。

另:pre-push e2e 从 workers=2 降到 1。该路径跑冷启动 dev server,两条用例
(waitForTableReady、waitForLoadState('networkidle'))在别的 agent 门禁共用本机时
会超时——2026-09-29/30 两次推送被无关红挡下,安静复跑均全绿(其中 faq-anchor
本地 9/9、board 里另一 session 独立判为负载争用)。选择降并发而不是把用例加进
grep-invert 排除名单:排除等于让门禁少测东西,而慢一点不减覆盖。CI 侧的 2 分片
不变(跑 built preview,不受影响)。

验证:renovate.json 全部键经官方 schema 校验(含 matchDatasources/matchPackageNames/
groupName),7 条规则;prettier 干净;check:e2e-market-names rc=0。
建票时把 CF 边缘注入的 __CF$cv 块误归为 Web Analytics beacon。真浏览器复现 +
逐 inline script 扫字面量证明它加载 challenge-platform/scripts/jsd,且站内
已无 cloudflareinsights 引用;zone 在 Free 计划,该检测按一手文档不可关。
#716 删 .github/dependabot.yml 时,AAV-1301 的 ignore(@eslint/js >= 10)没有去处:
npm manager 已开、10.0.1 在 npm 上,下一个窗口会重新提出那个两次让 dev 的
peer-dep-check 与 lint 变红的 bump。用 allowedVersions "<10" 复刻原裁定,9.x 照旧流动。

droid-review.md 里 review_depth / security_scan_schedule 两条 workflow 实际并未设置,
删掉;后者改写为 `on: pull_request` 无 schedule 这种文件可证的说法。
reserves-table-market-filter-pin (5) 用"第 3 行"当作"筛选后会改序"的保证。CI 在
2026-10-05 的快照里整页都是同一个 market,筛选什么都没动,于是 pin 断言量到行仍停在
第三位,两次尝试 y 值一致 —— 确定性,不是抖动。旧选择器面对同一份数据也点到同一颗
chip,所以这不是 #735 的改动引入的。

改成扫可见行的 market chip label,取第一个与首行不同的行;整页同 market 时按本仓
discovery+条件 skip 的既有形状跳过并写明原因。纯函数进 e2e/reserveDiscovery.ts,
配 8 行矩阵单测(去掉 reference 条件会红 4 条,确认断言真咬住实现)。
:393 Path B 的等待是 poll tbody 行数 > 0,消息写着"等表格重新排序",实际只证明表格存在。
supply=900 在 CI 那份快照上没让列表移动,于是"按 Clear 必然触发 pin scroll"量到 0,首跑与
retry 同因,反复挡推送门。

改成用本文件已有的 getVisibleReserveOrder + didReorder(:259 早就这么守):候选场景值逐个试
到确实改序才继续,全都不改序就 skip 并写明原因。实测 :393 从 15.9s 失败变 9.7s 通过。
位置断言与"模拟子行仍可见"两次都通过,唯独 window.scrollBy 探针读 0:重新排序把目标行
上方移走之后,仅靠布局它就已经落进锚点带,不需要滚动。那条探针断言的是机制而不是契约,
且机制归 :259 那条用例专门拥有(改了序就滚、没改序就不滚),删掉重复不减少覆盖。

如实记:这是一次断言放宽,依据写在代码注释与看板第十一行段。
#731 只升 vitest、没升 @vitest/coverage-v8,而 vitest 5 的 peer 要求 coverage-v8 同版本
⇒ 严格 npm ci 失败,peer-dep-check 是 dev 的必填项,故该 PR 合不进去。

验证:3793 单测 + 137 scripts 测试全绿;npm ci 严格安装通过;typecheck/lint 0 error;
coverage 门 rc=0(All files 73.17/66.79/64.36/75.13 vs v4 基线 73.23/66.82/64.36/75.13,
阈值 72/66/63/74 均在上方)。
…js 修复,否则 pre-push 的 osv-scanner 拦 source-map-js GHSA-68fv-2mgg-jv7q)
…osv 门

6.1.4 命中 GHSA-rj75-hqrm-r3gf(5.9,dev-only);6.x 无修复版(最高 6.1.4),修复只在 7.1.6,
而 postcss-nested / tailwindcss 均声明 ^6.1.x ⇒ 正常升级路径不存在,只能像 fast-uri/js-yaml/ws
那样用 overrides 钉。

跨大版本强钉的验证:npm run build(Tailwind 实际编译)rc=0,且产出的 CSS 逐字节一致
(index-DyVJKc4h.css / vendor-blockchain-DR00Q9RG.css 内容哈希同名,拼接 md5 相同),
osv-scanner rc=0。备选是 osv-scanner.toml 的 ignoreUntil 条目(AAV-1328 对 braces 的做法)。
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
aave-protocol-explorer Ready Ready Preview Oct 9, 2026 12:50am UTC

@factory-droid

factory-droid Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Droid finished @0xPabloLI's task —— View job


LGTM. This is a dependency-only change: vitest and @vitest/coverage-v8 move to 5.0.3 together (satisfying the strict peer requirement), the postcss-selector-parser 7.1.6 override follows the repo's established overrides pattern for an advisory unfixable in the 6.x line, CI runs Node 24 which satisfies vitest 5's engines range, and the lockfile churn removes only stale vitest-4 transitive deps while picking up smol-toml/source-map-js security fixes. No findings with a realistic trigger path.

0 inline comments posted

@0xPabloLI
0xPabloLI merged commit 10a6751 into dev Oct 9, 2026
24 checks passed
@0xPabloLI
0xPabloLI deleted the deps/vitest-5 branch October 9, 2026 00:55
0xPabloLI added a commit that referenced this pull request Oct 9, 2026
… renovate vitest 族分组 (#753)

* docs(roadmap): AAV-1320 已上线并生产复验;AAV-1303 第一段交付,next pick 转第二段

* chore(hardcode): sync hardcoded assets and mappings (#713)

* docs(csp): 记 AAV-1327(CF beacon 内联块被拦)并在 1320 spec 补第三类指针

生产每次加载有 1 条 CSP console error:Cloudflare 自动注入的 Web Analytics beacon
bootstrap 被 script-src 拦。已实测证伪「加 hash」这条路——内联块里的 r/t 每请求都变
(两次拉取值不同),Chrome 建议的那个 hash 只对当次响应有效。

不是 #693/1320 引入的回归:1320 之前 script-src 就没有 unsafe-inline 也没有 hash,
这段一直被拦;1320 的 spec 只枚举了 consent 块与 gtag.js 两类。现在把第三类写进
spec,避免下个改 CSP 的 session 再当成新发现。

* chore(security): 豁免 braces 3.0.3 的 GHSA-vfj7-8cjw-p6xm,恢复被阻断的 pre-push 门

osv-scanner 从 10-04 起阻断所有本地推送:braces 3.0.3 命中 CVE-2026-93687(8.7 High),
而它上游没有修复版(npm 最新就是 3.0.3;OSV ranges 只有 last_affected、没有 fixed 事件),
所以不能像三天前 axios 那次用 overrides 抬版本解决。它是 tailwindcss@3 → chokidar/micromatch
的 dev 传依赖,不在生产产物里。

只豁免这一条、带理由与 ignoreUntil=2027-01-31(实测:未来日期放行、过期后重新报错,
是真执行的时间闸)。到期若仍无修复版,走根治:换掉 tailwind v3 的 watch/glob 依赖链。
AAV-1328。

* docs(lessons): 记 osv-scanner 配置的四个反直觉点

自动发现的文件名不能带点(.osv-scanner.toml 实测不生效);未知键是整份配置拒绝
加载而非忽略该条,写错等于豁免全废;ignoreUntil 需 RFC3339 且真的会过期(两个方向
都实测过);osv 只在 pre-push、CI 的 security-audit 是 --omit=dev + continue-on-error,
所以存在「CI 全绿但所有人都推不动」的形态。

* chore(deps): renovate 配置改为 Renovate 自身惯用法,并纳入 Dev Container

相对上一版的四处调整,依据都取一手源码:

1. 取消 weekly schedule,回到引擎默认 at any time,改由 prHourlyLimit=2 +
   prConcurrentLimit=5 节流。按小时滚动才是 Renovate 的模型;把一批更新攒到周一
   是 Dependabot 的成批观感,代价是双轨期看不到任何动作、出问题也发现得晚。
   prConcurrentLimit 5 仍对齐 dependabot.yml 的 open-pull-requests-limit。

2. 纳入 devcontainer manager:.devcontainer/devcontainer.json 的
   image(mcr.microsoft.com/devcontainers/typescript-node:22)与
   features(ghcr.io/devcontainers/features/github-cli:1)此前无人看守——
   dependabot.yml 只配了 npm 与 github-actions。该 manager 同时提取 image 与
   features 两处版本(源码 manager readme),正好覆盖我们 Codespaces 的两个
   版本点。typescript-node 与 CI 的 node-version 是跨消费者契约,故一律人工评审,
   不进 automerge 标签。

3. minimumReleaseAge=7 days 只加在 github-actions 的 non-major 规则上,不是全局。
   它复刻 scripts/check-dep-release-age.mjs 的供应链等待期,而那道门的判据是
   package-lock 的 diff,看不见 workflow 里的 action 钉版 ⇒ actions 此前没有任
   何等待期保护,这里是唯一能落地该策略的位置。

4. 同时设 minimumReleaseAgeBehaviour=timestamp-optional,因为等待期依赖
   release timestamp,而源码注明 Docker 源只在 Docker Hub 取 tag_last_pushed;
   我们两个引用都在 mcr.microsoft.com 与 ghcr.io,无时间戳时默认的
   timestamp-required 会把更新判成 pending 永久搁置(util/minimum-release-age.ts
   的 isPending 分支)。devcontainer 规则因此不加等待期,只设人工评审。

automerge 仍保持 false:合并决策继续走现有 automerge.yml 的 PAT 路径,避免开出
第二条合并通道(也保住 lovable→dev MERGE / 其余 SQUASH 的策略)。

生效前提:Renovate 只读默认分支的配置,本文件需再经 lovable→dev→main 一轮。

* docs(roadmap): 10-05 盘点——osv 门恢复已关 AAV-1328;faq-anchor 判为负载争用

AAV-1320 在 Linear 已 Done 却还留在「仅列 open」表里,按文件自身规则移出。

* docs(board): qoder-0929b 补第二段交付(AAV-1328 关票、AAV-1327 建票、faq-anchor 判负载)

* docs(board): qoder-0929a 第五段——dev 已被 #716/#717 改写方向,改为以 dev 为基底合并并修两处放行面

* ci(renovate): 把 node 的两处真值绑成同一批,并让 pre-push e2e 单 worker

node 版本在本仓有两个家:workflow 的 node-version(走 node 数据源)与 Dev Container
镜像 typescript-node(走 docker 数据源),二者之间没有任何机制保证同步。正在开的
#727 就是这个裂口的形状——它只改 6 个 workflow 到 v24,不碰 .devcontainer,合下去
CI 就跑 Node 24、Codespaces 仍是 22(本仓无 .nvmrc、package.json 无 engines,所以
这两处就是全部真值)。

做法是跨 manager 分组而不是手工拼一个 PR:后者只修这一次,前者让"必须同批"成为
配置约束——matchDatasources [node, docker] + matchPackageNames [node,
/typescript-node/] → groupName "node runtime",标签 manual-review。分组只在
devcontainer manager 生效后才有意义,故依赖同一份配置里的 enabledManagers。

另:pre-push e2e 从 workers=2 降到 1。该路径跑冷启动 dev server,两条用例
(waitForTableReady、waitForLoadState('networkidle'))在别的 agent 门禁共用本机时
会超时——2026-09-29/30 两次推送被无关红挡下,安静复跑均全绿(其中 faq-anchor
本地 9/9、board 里另一 session 独立判为负载争用)。选择降并发而不是把用例加进
grep-invert 排除名单:排除等于让门禁少测东西,而慢一点不减覆盖。CI 侧的 2 分片
不变(跑 built preview,不受影响)。

验证:renovate.json 全部键经官方 schema 校验(含 matchDatasources/matchPackageNames/
groupName),7 条规则;prettier 干净;check:e2e-market-names rc=0。

* docs(board): qoder-0929a 第六段——Renovate 确认激活、Node 漂移用跨 manager 分组绑住、pre-push 降单 worker

* docs(csp): 订正 AAV-1327 根因——被拦的是 CF bot 检测注入,不是 analytics beacon

建票时把 CF 边缘注入的 __CF$cv 块误归为 Web Analytics beacon。真浏览器复现 +
逐 inline script 扫字面量证明它加载 challenge-platform/scripts/jsd,且站内
已无 cloudflareinsights 引用;zone 在 Free 计划,该检测按一手文档不可关。

* docs(board,roadmap): 订正 faq-anchor 判定——非负载而是 networkidle 耦合实盘,建 AAV-1329

* ci(renovate): 给 @eslint/js 的 v10 上限找新家,并删两条假配置文档

#716 删 .github/dependabot.yml 时,AAV-1301 的 ignore(@eslint/js >= 10)没有去处:
npm manager 已开、10.0.1 在 npm 上,下一个窗口会重新提出那个两次让 dev 的
peer-dep-check 与 lint 变红的 bump。用 allowedVersions "<10" 复刻原裁定,9.x 照旧流动。

droid-review.md 里 review_depth / security_scan_schedule 两条 workflow 实际并未设置,
删掉;后者改写为 `on: pull_request` 无 schedule 这种文件可证的说法。

* chore(hardcode): sync hardcoded assets and mappings (#738)

* test(e2e): 排序前提改成发现式挑行,别让实盘数据决定 market filter 用例跑不跑

reserves-table-market-filter-pin (5) 用"第 3 行"当作"筛选后会改序"的保证。CI 在
2026-10-05 的快照里整页都是同一个 market,筛选什么都没动,于是 pin 断言量到行仍停在
第三位,两次尝试 y 值一致 —— 确定性,不是抖动。旧选择器面对同一份数据也点到同一颗
chip,所以这不是 #735 的改动引入的。

改成扫可见行的 market chip label,取第一个与首行不同的行;整页同 market 时按本仓
discovery+条件 skip 的既有形状跳过并写明原因。纯函数进 e2e/reserveDiscovery.ts,
配 8 行矩阵单测(去掉 reference 条件会红 4 条,确认断言真咬住实现)。

* test(e2e): 让 scenario-pin 的 Clear 路径等到"真的改序",别拿行数冒充排序守卫

:393 Path B 的等待是 poll tbody 行数 > 0,消息写着"等表格重新排序",实际只证明表格存在。
supply=900 在 CI 那份快照上没让列表移动,于是"按 Clear 必然触发 pin scroll"量到 0,首跑与
retry 同因,反复挡推送门。

改成用本文件已有的 getVisibleReserveOrder + didReorder(:259 早就这么守):候选场景值逐个试
到确实改序才继续,全都不改序就 skip 并写明原因。实测 :393 从 15.9s 失败变 9.7s 通过。

* test(e2e): Clear 路径不再要求"必须滚过",只守"结束后停在锚点带"

位置断言与"模拟子行仍可见"两次都通过,唯独 window.scrollBy 探针读 0:重新排序把目标行
上方移走之后,仅靠布局它就已经落进锚点带,不需要滚动。那条探针断言的是机制而不是契约,
且机制归 :259 那条用例专门拥有(改了序就滚、没改序就不滚),删掉重复不减少覆盖。

如实记:这是一次断言放宽,依据写在代码注释与看板第十一行段。

* chore(hardcode): sync hardcoded assets and mappings (#744)

* chore(session-board): 登记 qoder-1006a(远端 open PR 收口:#731 vitest 5 迁移 + #741 收窄清理)

* chore(session-board): qoder-1006a 注销(#748/#747 交付 + worktree 缺 .husky/_ 导致 pre-push 整条门静默不跑 的机制发现)

* build(deps): overrides 钉 postcss-selector-parser 7.1.6 以过 pre-push 的 osv 门

6.1.4 命中 GHSA-rj75-hqrm-r3gf(5.9,dev-only);6.x 无修复版(最高 6.1.4),修复只在 7.1.6,
而 postcss-nested / tailwindcss 均声明 ^6.1.x ⇒ 正常升级路径不存在,只能像 fast-uri/js-yaml/ws
那样用 overrides 钉。

跨大版本强钉的验证:npm run build(Tailwind 实际编译)rc=0,且产出的 CSS 逐字节一致
(index-DyVJKc4h.css / vendor-blockchain-DR00Q9RG.css 内容哈希同名,拼接 md5 相同),
osv-scanner rc=0。备选是 osv-scanner.toml 的 ignoreUntil 条目(AAV-1328 对 braces 的做法)。

* chore(harness): 把 pre-commit/pre-push 钉成绝对 hooksPath,worktree 不再静默跳门

husky 写的 core.hooksPath 是相对值 .husky/_,而该目录只在 npm install 的 prepare
里生成(且自我忽略:.husky/_/.gitignore 内容是 *)。新 worktree 没这个目录 ⇒ git
找不到任何 hook ⇒ pre-commit/pre-push 整条不执行,而 commit/push 仍退出 0。
本仓有四道门只存在于 pre-push(osv-scanner / semgrep / knip / dup:check),CI 里
没有对应 job,所以这条路会产出「PR 全绿但门从没跑过」。#747 就是这样推上去的。

prepare 改为 `npx husky && node scripts/husky-hooks-path.mjs`:把共享 config 里的
hooksPath 指向主 checkout 的绝对路径,任何 worktree 都解析得到;配套在两个 hook
开头加 node_modules 守卫,缺依赖时明确报错。opt-out: HUSKY_HOOKS_PATH_ABSOLUTE=0;
自查: npm run check:hooks-path。附 17 条 node:test 覆盖判定表(不覆盖非本仓所有的
hooksPath、幂等、只认字面量 0 才关闭)。

另在 renovate.json 给 vitest 族加分组规则:vitest 5 的 peer 要求 @vitest/* 同版本,
只升一半会让严格 npm ci 在 peer-dep-check(dev/main 均必填)上失败——#731 即此病,
换成 Renovate 也会重犯,除非同批评审(照 node runtime 那条的先例)。

* fix(e2e): E2E_PROXY 也作用于 prewarm 浏览器,直连变慢时不再在第一条测试前整条中断

playwright.config 只把 proxy 放进 project 的 use,覆盖的是"测试用的浏览器";
e2e/global-setup.ts 自己 chromium.launch() 起的那个始终走直连。直连吞吐一差,
warm-up 就卡在 portfolio-mode-toggle 的 120s 预算上,整轮在任何一条测试开始之前
中止——于是文档里的 E2E_PROXY 看起来完全失效。

实测判据(2026-10-07):/markets 三次直连 ttfb 1.4–5.0s 但 total 82s/100s/150s+
都还没传完(HTTP 都 200),而本机 mixed 口 7891 用 4.2s。所以旧注释里那句
"API 已在 ~1s 返回 200"正是被证伪的前提:200 不说明传输时间。

改法是把代理判定抽成 e2e/browserProxy.ts 的单一来源,两个消费者都从这里取,
避免再次各写各的;src/test/browserProxy.test.ts 的 R8 是 wiring guard,直接断言
两处都调用 browserProxyArgs 且不再手写 process.env.E2E_PROXY。

验证:8 条用例绿、typecheck rc=0、e2e 显式 tsc rc=0(e2e 不在 lint/typecheck 覆盖内)、
E2E_PROXY 下 test:e2e:pre-push 63 passed / 1 flaky(既存:标题由实盘数据生成,
retry 后标题变化报 Test not found)/ rc=0;改前同一命令在 warm-up 处 TimeoutError 中止。

* fix(harness): pre-commit 先生成 icon/token manifest,再跑 typecheck

三个 *.generated 模块是 gitignore 的生成物:npm test 的第一步会生成它们,但 pre-commit
把 typecheck 排在 npm test **之前** ⇒ 在一个刚 npm install、还没跑过测试的 linked worktree 里,
任何提交都死在 TS2307 Cannot find module './chainIconManifest.generated',读起来完全像代码回归。

对照实验(在 /tmp 新 worktree 里做的):删掉生成物 → typecheck 报 3 条 TS2307;
跑 node scripts/generate-icon-manifests.mjs → 0 条。命令与 npm test 用的是同一个,
生成物本身仍被忽略,不会污染提交。

注:这条改动要等它进了主 checkout 的工作树才会真正被执行——绝对 hooksPath 下 git 跑的是
主 checkout 的 .husky/* 内容(PR 正文里已记这条限制)。

* build(deps): handlebars 4.7.9→4.7.10 以过 pre-push 的 osv 门

2026-10-08 新公布的通告把 openapi-zod-client 的传递依赖 handlebars 4.7.9 标成
2 条 Critical(GHSA-8r5x-fm3f-whwj 9.8 / GHSA-p8wg-vrv2-v86f 9.2)+ 1 条 Medium,
修复只有 4.7.10。这个版本在 lovable 与 dev 上早就存在,是今天才被判 vulnerable ⇒
所有人从 lovable/dev 派生的分支都推不动(osv 只在 pre-push,CI 无对应 job)。

走正常解析路径 `npm update handlebars`(父节点声明的范围允许),不新增 override;
lock 只动这一项。7 天等待期门按 direct 判定,本仓 check:dep-age 通过(0 direct、
3 transitive),所以这里没有绕策略——是 osv 与等待期此刻的方向相反,选安全侧。

---------

Co-authored-by: 0xPabloLI <0xPabloLI@users.noreply.github.com>
0xPabloLI added a commit that referenced this pull request Oct 9, 2026
…pendabot 收尾)

# Conflicts:
#	SESSION-BOARD.md

This branch was successfully deployed

1 active deployment
Preview — 11726cdc Deployed Oct 9, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant