Repository navigation
Conversation
后端已下线 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>
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>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.67.0 to 8.71.0. - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.71.0/packages/typescript-eslint) --- updated-dependencies: - dependency-name: typescript-eslint dependency-version: 8.71.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [jscpd](https://github.com/kucherenko/jscpd/tree/HEAD/rust/jscpd) from 5.2.0 to 5.4.0. - [Release notes](https://github.com/kucherenko/jscpd/releases) - [Commits](https://github.com/kucherenko/jscpd/commits/v5.4.0/rust/jscpd) --- updated-dependencies: - dependency-name: jscpd dependency-version: 5.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* 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) --------- Co-authored-by: 0xPabloLI <0xPabloLI@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>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Bumps [@aave/react](https://github.com/aave/aave-v4-sdk/tree/HEAD/packages/react) from 6.5.0 to 6.6.0. - [Release notes](https://github.com/aave/aave-v4-sdk/releases) - [Changelog](https://github.com/aave/aave-v4-sdk/blob/main/packages/react/CHANGELOG.md) - [Commits](https://github.com/aave/aave-v4-sdk/commits/@aave/react@6.6.0/packages/react) --- updated-dependencies: - dependency-name: "@aave/react" dependency-version: 6.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [sonner](https://github.com/emilkowalski/sonner) from 2.0.7 to 2.0.8. - [Release notes](https://github.com/emilkowalski/sonner/releases) - [Commits](emilkowalski/sonner@v2.0.7...v2.0.8) --- updated-dependencies: - dependency-name: sonner dependency-version: 2.0.8 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>
* 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 那条用例专门拥有(改了序就滚、没改序就不滚),删掉重复不减少覆盖。 如实记:这是一次断言放宽,依据写在代码注释与看板第十一行段。 --------- Co-authored-by: 0xPabloLI <0xPabloLI@users.noreply.github.com>
…2 updates (#746) Bumps the npm_and_yarn group with 2 updates in the / directory: [smol-toml](https://github.com/squirrelchat/smol-toml) and [source-map-js](https://github.com/7rulnik/source-map-js). Updates `smol-toml` from 1.8.0 to 1.9.0 - [Release notes](https://github.com/squirrelchat/smol-toml/releases) - [Commits](squirrelchat/smol-toml@v1.8.0...v1.9.0) Updates `source-map-js` from 1.2.1 to 1.2.2 - [Release notes](https://github.com/7rulnik/source-map-js/releases) - [Changelog](https://github.com/7rulnik/source-map-js/blob/main/CHANGELOG.md) - [Commits](7rulnik/source-map-js@v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: smol-toml dependency-version: 1.9.0 dependency-type: indirect dependency-group: npm_and_yarn - dependency-name: source-map-js dependency-version: 1.2.2 dependency-type: indirect dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* 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(session-board): 登记 qoder-1006a(远端 open PR 收口:#731 vitest 5 迁移 + #741 收窄清理) * build(deps): vitest 4→5 连同 @vitest/coverage-v8 一起升(取代 #731) #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 均在上方)。 * 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 的做法)。 --------- Co-authored-by: 0xPabloLI <0xPabloLI@users.noreply.github.com>
… 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>
…ior.md 改写为现状 (#747) * 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(session-board): 登记 qoder-1006a(远端 open PR 收口:#731 vitest 5 迁移 + #741 收窄清理) * ci(deps): 删 dependabot peer-conflicts 报告 workflow,dependabot-behavior.md 改写为现状 dependabot.yml 随 #736 离开默认分支后 Dependabot 不再产版本 PR,该 workflow 失去输入; peer 冲突判定已由 ci.yml 的 peer-dep-check(严格 npm ci,dev/main 均必填)覆盖。 保留 dependabot-auto-triage.yml:security updates 仍启用,它是真出现 security PR 时唯一的分类器。 dependabot-behavior.md 原文整份指向已不存在的 .github/dependabot.yml,改写为现状 + `dependabot/*`→main 被 branch-flow-guard 挡死的成因与两条真解(本次实测 #746 用改 base 解决)。 * docs(dependabot): 订正「删配置=停管道」——#752 实证 Dependabot 仍会开版本 PR #736 把 dependabot.yml 带离 main 约 24 小时后,#752 于 2026-10-07T11:16Z 创建, 标题与 commit trailer(dependency-type: indirect + dependency-group)都是版本升级 PR 的 形状,且复用 #746 的分支与 head commit。本文件上一版写的「不再开版本升级 PR」是错的推论。 机制不下断言(配置缓存生效延迟、或对未满足的更新继续提案都有可能),改成给判据: diff vs dev 为空 ⇒ 关闭(内容已随 #746 进 dev,等 dev→main 上线即满足);非空 ⇒ base 改 dev 走发布流;不要加 ignore 规则去压制告警面与后续合法提案。 保留 auto-triage 的理由也换成实证:#752 带着 manual-review 且 triage 检查 pass。 --------- Co-authored-by: 0xPabloLI <0xPabloLI@users.noreply.github.com>
) * 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>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
… main→dev 同步 PR 用) # Conflicts: # .github/workflows/dependabot-resolve-peer-conflicts.yml # SESSION-BOARD.md # renovate.json
Sync main → dev(补 ancestry,内容零变化)
0xPabloLI
added a commit
that referenced
this pull request
Oct 9, 2026
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 上线才生效,在那之前仍按手工流程。
0xPabloLI
added a commit
that referenced
this pull request
Oct 9, 2026
# Conflicts: # SESSION-BOARD.md
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
本次上线内容(dev → main)
44 个 commit、19 个文件,其中没有一个在
src/应用代码里(唯一的src/改动是新增测试src/test/browserProxy.test.ts,不进产物)。分类:dependabot-resolve-peer-conflicts.yml(版本 PR 归零后失去输入);renovate.json的 vitest 族分组 + eslint 上限补上eslint本体(AAV-1301 原先只管@eslint/js)@vitest/coverage-v8一起升(取代 #731 的半截提案)overrides钉postcss-selector-parser 7.1.6(GHSA-rj75-hqrm-r3gf)、handlebars 4.7.10(GHSA-8r5x-fm3f-whwj 9.8 / GHSA-p8wg-vrv2-v86f 9.2),均 dev-onlyhooksPath+node_modules守卫 +npm run check:hooks-path;e2e prewarm 现在认E2E_PROXY;pre-commit 在 typecheck 前先生成*.generateddocs/dependabot-behavior.md重写(含「删配置≠停管道」的判据)、DOCS-INDEX、cross-branch-workflow上线前的验证证据
lint/build/peer-dep-check/security-audit/content-security-check全绿,e2e 四分片e2e-desktop (1/2)、(2/2)、e2e-mobile (1/2)、(2/2)全 SUCCESS。origin/main与origin/dev,各 604 个产物文件——文件名集合完全相同,603 个逐字节一致,唯一不同的是dist/health.json,而它不同的字段是commit与builtAt(这文件本身就是用来报告线上 SHA 的)。⇒ 本次合并在浏览器侧不改变任何 JS/CSS 行为。postcss-selector-parser6→7 是跨大版本强钉(依赖只声明^6.1,6.x 无修复版),已单独证过产出 CSS 逐字节一致(index-DyVJKc4h.css内容哈希不变)。npm ci严格安装 rc=0;coverage 阈值门 rc=0(All files 73.17/66.79/64.36/75.13 vs vitest 4 基线 73.23/66.82/64.36/75.19,阈值 72/66/63/74)。aaveapy.comHTTP 200,meta[name=aaveapy-deploy-sha]=9804b530= main tip,入口资源index-DoTwNE3B.js/index-DyVJKc4h.css。如实记录:本地 e2e 有一轮 7 条失败,已归因非代码
在 dev tip 的独立 worktree 里跑
api-fields-verification等三个 spec 时出现 7 失败([data-reserve-id]120s 不可见、prewarm 超时),当时机器 load average 14.9–23(我并行跑了 curl/npm ci/两次构建)。判据不是"肯定是负载":⇒ 定性为本地环境抖动,未据此改动任何 hook 覆盖范围或断言。
上线后的验收(我会执行并回报)
aaveapy.com的 deploy-sha 应等于新的 main SHA;资源哈希应仍为index-DoTwNE3B.js/index-DyVJKc4h.css(若变化说明我上面的 A/B 判据有漏)api.aaveapy.com回滚
按流程 Phase 3 第 7 步:如生产异常,
git revert本次 merge commit 或把 main 指回9804b530,Vercel 自动重新部署。备注
staging.aaveapy.com)与本 PR 的 Vercel Preview 都是受保护部署,我这边没有登录态也没有 bypass 密钥(读.env的动作被安全策略正确地拦下,我不绕)。所以部署后的真实浏览器验证走公开的aaveapy.com;若你希望我在合并前用登录态过一遍 staging,在那个浏览器标签里登一次 Vercel 即可。public/openapi.json、src/generated/api/schemas.ts与 wrapper 均零 diff)⇒ 按docs/workflows/frontend-backend-coordinated-deployment.md的「无 API 变更时的简化流程」跳过 Phase 1-2 与 Phase 4-5。