Repository navigation
Conversation
* docs(agents): 记录 Droid 自动 PR 审查约定 * docs: add droid-review.md * docs: add setup-github-actions-secret.md * fix(schema): 同步后端 OpenAPI(移除 Merit)并让 merit 契约脱离 generated 后端已下线 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 掉而静默丢数据。运行时语义零变化。 * test(schema): 给 merit 契约补第一份 parse 覆盖(13 例矩阵) 排查 AAV-1303 时发现:MeritCampaignGroupSchema / BreakdownSchema 全仓零运行时解析 测试,只有 apiSchemas.ts 引用它。契约这次从 generated 改成手写 base,没有测试就 等于「抄错字段只会在运行时静默丢数据」。 矩阵按旧契约的宽松度写:四个必填、campaignType 任意字符串、aprCap 可 null 但不可 字符串、positionCapUsd 可选但不可 null、link 可缺、递归 message、嵌套 breakdowns 走 wrapper、netPositionConstraint / crossAssetPairing 的 enum 与类型校验、未知键 strip、 空数组。其中 message 的「标量只能当 record 叶子、不能当数组元素」是既有不对称, 一并钉住(差分探针验证过新旧同拒绝,非本次引入)。 * fix(deps): override axios 到 ^1.20.0(清掉 osv-scanner 门) 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 全过。 * build(deps-dev): bump @testing-library/user-event from 14.6.1 to 14.6.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> * docs: 修正安全审查阻断表述(Droid P3 发现) * chore(hardcode): sync hardcoded assets and mappings (#714) * ci: remove Dependabot config (superseded by Renovate) (#716) * chore(hardcode): sync hardcoded assets and mappings (#712) * ci: remove Dependabot config (superseded by Renovate) * build(deps): bump i18next from 26.4.0 to 26.4.2 (#703) 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> * ci(renovate): enable npm manager with 7-day release cool-down (#717) * chore(deps): update actions/github-script digest to f28e40c (#719) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update dependabot/fetch-metadata digest to 21025c7 (#720) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update zaproxy/action-baseline digest to 66042c8 (#722) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update zaproxy/action-baseline action to v0.15.0 (#723) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update reviewdog/action-eslint digest to 3ee2a45 (#721) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(hardcode): sync hardcoded assets and mappings (#737) * build(deps-dev): bump typescript-eslint from 8.67.0 to 8.71.0 (#730) 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> * build(deps-dev): bump jscpd from 5.2.0 to 5.4.0 (#732) 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> * ci(renovate): 以 dev 的接管方向为基底合并配置,并收紧 npm 自动放行面 (#735) * 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> * chore(deps): update actions/checkout action to v7 (#724) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update dependabot/fetch-metadata action to v3 (#726) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update actions/github-script action to v9 (#725) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * chore(deps): update dependency node to v24 (#727) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> * build(deps): bump @aave/react from 6.5.0 to 6.6.0 (#728) 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> * build(deps): bump sonner from 2.0.7 to 2.0.8 (#729) 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> * test(e2e): 两处「拿假设当守卫」的排序前提改成发现式(修 #736 的 e2e-desktop 2/2) (#742) * 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> * chore(hardcode): sync hardcoded assets and mappings (#745) * build(deps-dev): bump the npm_and_yarn group across 1 directory with 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> * chore(hardcode): sync hardcoded assets and mappings (#749) * chore(hardcode): sync hardcoded assets and mappings (#755) * build(deps): vitest 4→5 连同 @vitest/coverage-v8 一起升(取代 #731) (#748) * 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> * chore(harness): worktree 不再静默跳门(绝对 hooksPath)+ E2E_PROXY 覆盖 prewarm + 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> * ci(deps): 删除 Dependabot peer-conflicts 报告 workflow + dependabot-behavior.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> * fix(ci): eslint 上限补上 eslint 本体(AAV-1301 只做了一半)+ renovate.json 漂移守卫 (#758) * 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), 而它上游没有…
|
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.
|
Contributor
|
Droid finished @0xPabloLI's task —— View job This PR is a pure ancestry sync (merge main into dev so the squash-merged 4d5f74a becomes an ancestor of dev); the merge result tree is identical to origin/dev with zero content change. The candidate list was empty, so there are no findings to validate, and a full read of the PR diff (workflow/docs/deps-sync changes already reviewed in prior PRs) surfaced no new high-confidence, actionable issues. 0 inline comments posted |
3 tasks
Owner
Author
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.
作废,由 #763 取代(见下)。
这笔为什么走不通(结构性,不是冲突)
base=dev / head=main形态的同步 PR 在这个仓库里必然 BEHIND:dev 比 main 新(#761 刚合进 dev),而 main 要追上 dev 只能再上线一次 —— 于是死循环。更要紧的是gh pr update-branch在这种形态下的语义是把 dev 并进 main,等于绕过 dev→main 发布流程直接改生产分支,我没有那么做。实际解法(#763)
把
origin/main并进lovable(merge 结果与 lovable 零内容差异,纯 ancestry),随 #763 一起走 lovable→dev。dev 拿到4d5f74af作为祖先之后,下一次 dev→main 就不再 BEHIND。本轮同时验证的性质
git merge-tree origin/main origin/dev:1 处冲突(SESSION-BOARD.md,我的看板行),两侧 session 行集合相同、ours 为超集 ⇒ 取 oursgit diff --name-only <合并前 lovable> HEAD为空 ⇒ 这类同步不携带任何内容变更工作流层面的修法(旧逻辑"
git diff内容一致 ⇒ skip"正是漏口)在 #763。