Skip to content

release: dev → main(Renovate dashboard autoclose + sync 工作流按 ancestry 判定 + e2e/守卫与文档) - #768

Merged
0xPabloLI merged 97 commits into
mainfrom
dev
Oct 10, 2026
Merged

0xPabloLI merged 97 commits into
mainfrom
dev

Conversation

@0xPabloLI

Copy link
Copy Markdown
Owner

dev → main 的发布 PR。按仓库规则我只创建、不合并——等 maintainer 明确说合并再在 GitHub UI 操作。

这次上线交付什么

项 内容 为什么必须到 main 才生效
renovate.json dependencyDashboardAutoclose: true Renovate 只读默认分支的配置
.github/workflows/sync-dev-with-main.yml 同步判定改为按祖先关系(旧逻辑"git diff 内容一致 ⇒ skip"正是每次上线都要手工补 ancestry 的漏口) pull_request: closed 事件读的是默认分支的工作流文件 ⇒ 它要随这次上线落地,下一次发布才自动生效
renovate-config.test.mjs 等 4 个守卫 config 漂移守卫 + e2e 等待策略守卫 随 npm test 跑,不依赖 main
e2e/*.spec.ts、scripts/lib/e2e-artifacts.mjs faq-anchor 改页面自身就绪判据(AAV-1329);pre-push 失败现场归档 本地/CI 门
docs/、SESSION-BOARD.md Dashboard 生命周期判据、出口判据 文档

合并前判据:产物输入未变

不用比资源哈希(入口 chunk 内联 commit SHA 与 Vercel 注入的 VITE_*,每次部署必换哈希)。改用更强的输入判据,两条都已实测:

  • package.json main ↔ dev:0 差异。
  • package-lock.json main ↔ dev:0 差异(两边 @aave-dao/aave-address-book 都已是 4.73.0;PR diff 里那 3/3 行是 three-dot 对 merge-base 比出来的假象)。
  • 差集里唯一落在 src/ 的文件是 src/test/architecture-guard.test.ts——grep -rn "architecture-guard" src/ 除它自己零命中,即无任何生产代码引用,不进 bundle。

⇒ 依赖图与 app 源码都没变,产物变化只应是 health.json 的 commit/builtAt 与 chunk 内联 SHA。合并后按流程仍要做现网复验:deploy-sha 对齐、/health.json(记 7 位缩写)、reserves 行数、390px 零横向溢出、模拟子行可展开、API host。

ancestry

main 目前领先 1 笔(45cf7538 bot 的 hardcode 同步,内容 = dev 已有的同一次升级),而 main 的保护是 strict=true + enforce_admins=true + 10 个必填上下文 ⇒ 本 PR 需要把 main 并回 dev 才能满足 up-to-date。我没有用 admin 豁免绕它。

0xPabloLI and others added 30 commits September 30, 2026 23:50
后端已下线 Merit:/markets 不再返回 merit 字段,OpenAPI 里 ApiMeritCampaign*
schema 也删了。前端 openapi-sync 因此长期红(codegen 出的 schemas.ts 少了
generated.ApiMeritCampaignBreakdown / Group,而手写契约与 generated types 还在引用)。

- public/openapi.json + src/generated/api/schemas.ts:取自 staging 的权威 spec
- src/shared/market-contract/schemas.ts:Merit 两个 schema 改手写 base,字段逐条
  对齐移除前的 generated 形状,三处既有放宽(campaignType 放宽、aprCap 可 null、
  group link 可选 + 递归 message + wrapper breakdowns)原样保留
- src/generated/api/types.ts:删掉两条指向已消失 schema 的别名(全仓无其他引用)

契约保留 merit 定义是有意的:灰度/回滚窗口内响应仍可能带回 merit 字段,删定义会让
它们被 zod strip 掉而静默丢数据。运行时语义零变化。
排查 AAV-1303 时发现:MeritCampaignGroupSchema / BreakdownSchema 全仓零运行时解析
测试,只有 apiSchemas.ts 引用它。契约这次从 generated 改成手写 base,没有测试就
等于「抄错字段只会在运行时静默丢数据」。

矩阵按旧契约的宽松度写:四个必填、campaignType 任意字符串、aprCap 可 null 但不可
字符串、positionCapUsd 可选但不可 null、link 可缺、递归 message、嵌套 breakdowns 走
wrapper、netPositionConstraint / crossAssetPairing 的 enum 与类型校验、未知键 strip、
空数组。其中 message 的「标量只能当 record 叶子、不能当数组元素」是既有不对称,
一并钉住(差分探针验证过新旧同拒绝,非本次引入)。
axios 1.18.1 被 12 条 OSV 命中(7 High),修复版 1.20.0。它是 openapi-zod-client →
@zodios/core 的传递 dev 依赖,不是直接依赖,所以按仓里既有形状用 npm overrides 抬。

影响面不止本分支:任何工作树从当前 lockfile 推 lovable 都会被 .husky/pre-push 的
osv-scanner 挡下,这一条同时解锁其他人。

验证:osv-scanner --lockfile package-lock.json → No issues found (exit 0);
npm run schema:check 仍 0(codegen 工具在 1.20.0 下产出逐字不变);npm test 170 files
全过。
fix(schema): 同步后端 OpenAPI(Merit 下线)并让契约脱离 generated;顺带清 osv 门
chore(openapi): 同步 merit 契约修复 + axios osv 门修复到 dev
….7 (#705)

Bumps [@testing-library/user-event](https://github.com/testing-library/user-event) from 14.6.1 to 14.6.7.
- [Release notes](https://github.com/testing-library/user-event/releases)
- [Changelog](https://github.com/testing-library/user-event/blob/main/CHANGELOG.md)
- [Commits](testing-library/user-event@v14.6.1...v14.6.7)

---
updated-dependencies:
- dependency-name: "@testing-library/user-event"
  dependency-version: 14.6.7
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…-1790783361

docs: Droid 自动审查约定 + secret 设置流程
* chore(hardcode): sync hardcoded assets and mappings (#712)

* ci: remove Dependabot config (superseded by Renovate)
Bumps [i18next](https://github.com/i18next/i18next) from 26.4.0 to 26.4.2.
- [Release notes](https://github.com/i18next/i18next/releases)
- [Changelog](https://github.com/i18next/i18next/blob/master/CHANGELOG.md)
- [Commits](i18next/i18next@v26.4.0...v26.4.2)

---
updated-dependencies:
- dependency-name: i18next
  dependency-version: 26.4.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Pablo <77742839+0xPabloLI@users.noreply.github.com>
生产每次加载有 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」表里,按文件自身规则移出。
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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。
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
0xPabloLI and others added 22 commits October 9, 2026 10:10
…pendabot 收尾)

# Conflicts:
#	SESSION-BOARD.md
)

* 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(hardcode): sync hardcoded assets and mappings (#751)

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

* fix(ci): eslint 上限补上 eslint 本体,并加 renovate.json 漂移守卫

AAV-1301 的裁定是"eslint 工具链等插件跟上之前不要 10",但落到 renovate.json 时
matchPackageNames 只写了 @eslint/js ⇒ eslint 本体仍可被升。Dependency Dashboard #715
现在排着 `update dependency eslint to v10` 就是这条漏口的直接后果。

实测 peer:eslint-plugin-import 的 peer 是 ^2..^9(没有 ^10)⇒ 升 eslint 会让严格
npm ci 失败,而 peer-dep-check 是 dev 与 main 都必填的检查;另两个
(eslint-plugin-react-hooks@7、typescript-eslint@8)已经接受 ^10,所以拦点就在
eslint-plugin-import。

同时新增 scripts/renovate-config.test.mjs:8 条只读配置的断言,逐条对应"这个字段
曾经被编辑掉过一次"的裁定(manager-scoped 的 automerge、runtime 永不 automerge、
lockFileMaintenance 关、vitest 族分组、node 两处真值分组、timestamp-optional)。
两组正对照实测会变红:上限退回只钉 @eslint/js;抽掉 npm automerge 规则的 matchManagers。

注意生效路径:Renovate 只读默认分支的配置,所以这笔要走到 main 才被读到,挡不住
下个周一窗口的 eslint v10(那笔只会红在 peer-dep-check,人工关闭即可)。

---------

Co-authored-by: 0xPabloLI <0xPabloLI@users.noreply.github.com>
… main→dev 同步 PR 用)

# Conflicts:
#	.github/workflows/dependabot-resolve-peer-conflicts.yml
#	SESSION-BOARD.md
#	renovate.json
Sync main → dev(补 ancestry,内容零变化)
wallet-connect-injected.spec.ts 里每一处状态转换都先经 waitForWalletControls
(30s、接受任意一种 header affordance、兼容桌面/移动两种布局),只有 reload 之后
那一处直接对 `Wallet 0x…` 按钮等 15s —— 于是它既比全文件其余等待短一半,又无法区分
"还在重连(显示的是 Connect wallet)"与"什么都还没渲染"。一次 pre-push 里它失败
(element(s) not found),而失败现场被下一次运行清空,根因至今无法定案。

如实标注:这条改动消除的是文件内的不一致与不可诊断性,不宣称修好根因——25s 的
/markets 延迟实测下按钮 5.3s 就出现(⇒ 不是数据加载门控),改后连跑两轮 pre-push
该用例分别 6.9s / 7.8s 通过,失败未复现。
Playwright 每次运行都会清空 test-results/,所以"偶发失败 + 紧接着跑了一次绿的"
等于现场永久丢失:本次 wallet 用例失败后被后续运行冲掉,只剩控制台文本,根因无法定案。

pre-push 门在报失败/报 flaky 之前,把带 error-context.md 或 test-failed-*.png 的
目录复制进 test-results-archive/<UTC 时间戳>/(该目录同样 gitignore)。归档函数抽到
scripts/lib/e2e-artifacts.mjs,配 scripts/e2e-artifacts.test.mjs 8 条:R2/R3 是两类
标记的正对照、R4 是负对照(只有 trace/video 的通过用例不归档)、R7 校验内容与目录树
真被复制、R8 校验两次运行不互相覆盖且早先的归档保持原样。

验证:新模块 8/8;node --test scripts/**/*.test.mjs 170/170;node --check 三个文件通过。
test(e2e)+harness: wallet 用例走 canonical 等待 + pre-push 归档失败现场
squash 式 dev→main 上线后,main 必然多一个 dev 没有的发布提交,而那一刻内容两边相同
——旧逻辑 `if git diff origin/main origin/dev --quiet → skip` 恰好命中这个状态,于是每次
上线都要手工补一笔 main→dev 同步(本次 #759 BEHIND/CONFLICTING → 手工做 #760 即其后果)。

改法:判定只看祖先(merge-base == main ⇒ 已含 ⇒ skip),不看内容是否相同;干净时自动开
sync 分支 + PR 并挂 auto-merge(MERGE),有冲突时不自动选边(main 可能有 dev 没有的 bot
直落提交),退回 head=main 的 PR 并把冲突文件写进 summary 与 warning。

对照实验(用 YAML 里抽出的脚本跑真实历史状态):
  #759 合完那一刻(内容 0 差异、dev 缺 1 祖先)旧=skip=true ← 漏口;新=main_only=1; skip=false
  现在(#761 之后)新=skip=false,符合事实:4d5f74af 至今不是 dev 的祖先,故我另开一笔同步
另:合并树与 dev 树差 0 文件,证明这类同步是纯 ancestry。
YAML/shell/JS 三段语法检查通过;两个 action 的 pin SHA 与改动前逐字一致(git diff 无 +/- 行)。

生效时差如实记录:pull_request: closed 事件读默认分支的工作流 ⇒ 本改动要随下一次 dev→main
上线才生效,在那之前仍按手工流程。
ci(sync): dev↔main 同步改为按 ancestry 判定(含本轮看板登记)
卡片由每轮 ensureIssue() 按标题维持,手工关掉不持久;源码里真正的关闭路径只有
autoclose 与 dependencyDashboard:false 两条。取前者、不拉后者:这周那个"半个 eslint
上限"正是从这张卡上看出来的,关掉它等于把 minimumReleaseAge 与排程挡住的队列重新变回黑盒。

- renovate.json: dependencyDashboardAutoclose = true
- scripts/renovate-config.test.mjs: 钉住三条(卡开着 / autoclose 开着 / 没有规则把分支
  永久停在卡里),两组正对照实测变红
- docs/dependabot-behavior.md: 新增该卡的生命周期判据(它今天还关不掉:35 条 Awaiting
  Schedule + 8 条 Pending Status Checks + 一条 replacement 条目)
全量 `npm test` 下 6 例撞 vitest 默认 5s 超时(5 条 star-import + 1 条 lib→hook
方向),pre-commit 因此假红、阻断提交。同一文件单独跑是绿的(323 passed/15s/rc=0),
CI 最近一次 `npm test` 也是 success ⇒ 不是仓库逻辑缺陷,而是「每个用例各自重走一遍
src 树 + 重读全部文件」的单例成本,在慢环境(195 个 vitest worker、FS 经 broker 拦截)
里超过 5s 预算。

- src/test/architecture-guard.test.ts:
  - globTsFiles 按目录记忆化、readFile 按路径记忆化(清单与内容语义不变,只改算几次)
  - components/lib/hooks 三份清单提到模块作用域,并在导入期把清单内文件读一遍——
    fixture 加载不是测试逻辑,留在用例里就会把成本记在某个用例的 5s 预算上
    (只做记忆化时正是「第一条」star-import 用例独吞 lib 首次读取而超时)
  - 新增 2 条缓存契约断言(重复调用返回同一实例),改前必红
- docs/specs/architecture-guard-fs-walk-cost.md:9 行场景矩阵 + 三段证据
- docs/DOCS-INDEX.md:登记新 spec;顺带删掉一条既有的孤儿残行(e2e-parallel-port-
  isolation 条目的重复片段、无列表前缀,存在于 HEAD);本行同时带上 AAV-1329 的
  spec 登记(其代码在紧随的下一个 commit)

实测:单文件 1 failed → 325 passed(15s → 7–9s);全量 `npm test` 6 failed → 0 failed
(4090 → 4098 passed,增量 = 6 例转绿 + 2 条新断言,用例数只增不减)。
不放宽 testTimeout、不改 vitest 全局配置。
`waitForLoadState('networkidle')` 等的是网络静默,但被测页面自身零取数:H1、`h2#faq`
与 12 条 FAQ 来自同一次同步渲染,而 `src/App.tsx` 在模块加载时就 prefetch `/markets`
与 side-data(与路由无关)。整条 pre-push 套件向 staging 发上百个请求的那几分钟里,
那个静默窗口永不到达 ⇒ 三个用例首步撞 60s 超时,而独立跑恒绿。

- e2e/defi-yield-tracker-faq-anchor.spec.ts:3 处等待换成内联 waitForPageReady(page)
  (H1 + h2#faq 可见);断言一行未动,不引入 skip
- scripts/e2e-wait-strategy.test.mjs:新增静态守卫(扫 e2e/ 全部 .ts,注释感知、大小写
  敏感、行内 allow 逃生阀)。随既有 `npm test` 生效,不新增 npm script、不改 hook
- docs/specs/aav-1329-faq-anchor-wait-strategy.md:14 行场景矩阵 + 沙箱拦阻留档

实测:整条 e2e 套件 3 次样本,本 spec 均 9/9 绿、单例 1.6–3.1s(改动前是 60s 超时)。
顺带撞见 `.husky/pre-push` 的失败传播缺口(`&&` 链无 `|| exit 1`,三次 rc=0 假绿),
已单独建票 AAV-1330,本 commit 不动公共 hook。
- docs/issue-roadmap.md:
  - Last inventory 改写成「AAV-1329 与 AAV-1331 同日交付关闭」(commit `3430b65b` /
    `a0c8982f`,**仅本地 lovable、尚未 push**),并补记本轮的环境阻塞与绕行
  - AAV-1329 从 Active Medium 表移出 → Recently Completed(带 3 次整条套件样本口径)
  - AAV-1331 入 Recently Completed;AAV-1330 入 Urgent/High(**保持 open**)
  - 上一版那句「AAV-1329 已交付关闭(Done)」在改前一度是**未兑现的**(提交当时还没落地),
    本 commit 是在两个提交真的落地、Linear 已流转 Done 之后才把它订正为事实
- SESSION-BOARD.md:`wb-1009a` 注销(active → done),补交付叙事、环境阻塞绕行
  (沙箱 broker 使 `eslint .` 恒 EPIPE;绕行=清空 `NODE_OPTIONS`)与遗留项
  (`origin/lovable` 未更新;`nested-scroll:38` 待用户裁是否开票)

三张票的交付记录(含测试数字、根因、沙箱偏差、未纳入项)在 Linear 评论里,是唯一权威源。
看板里「origin/lovable 未更新」已被这次推送推翻:带代理跑 pre-push 全门 PUSH_RC=0,tip=48ec366a,连带把 wb-1009a 的 AAV-1329/1331 三笔一起带走(推的是分支 ref,不是固定 SHA)。

同时记下出口判据:直连取 staging /markets 要 37.9s、第二次 90s 只传完 120,920 字节,同一 payload 经代理 1.85s;同一棵树无代理 = 3 failed/10 flaky/36.7m,有代理 = 0 failed/3.9m ⇒ 本 session 那批 e2e 红全是环境。
chore(renovate): Dashboard 队列清空后自动关 + AAV-1329/1331 守卫合流
@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 10, 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 10, 2026 9:53am UTC

@factory-droid

factory-droid Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

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


Validation pass: all 1 candidate was independently re-examined against the full diff and the workflow's strict-merge context and rejected as an edge-case P2 (the stale-sync-PR state it requires is essentially unreachable because main's strict up-to-date check blocks the next release until the sync PR merges). No verified defects remain; the release PR's workflow rewrite, e2e artifact archiver, wait-strategy guard, renovate autoclose, and architecture-guard memoization all check out.

0 inline comments posted

@0xPabloLI
0xPabloLI merged commit badd79c into main Oct 10, 2026
45 checks passed
0xPabloLI added a commit that referenced this pull request Oct 10, 2026
板上那句「未合并,等用户」已不成立:#767 用 MERGE 进 dev(5829fe54),lovable 成为 dev 祖先(behind_by=0)。

两次被门挡下的判据都指向本机出口而非代码:直连 50 passed/3 failed/36.7m(三条红全是 tbody tr[data-reserve-id] 30s 等不到;直连取 412,891 字节的 /markets 要 37.9s,第二次 90s 只传完 120,920),带代理同一棵树 64 passed/0 failed/3.9m。没加排除项、没用 --no-verify。

dev→main 建成 #768 按规则不合并;main 领先的一笔 bot 同步用 update-branch 并回 dev,前后 tree SHA 同为 ee6668b 证明零内容变更。本地两条已交付分支删除。

This branch was successfully deployed

1 active deployment
Preview — e1673fbc Deployed Oct 10, 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