Skip to content

fix(deps): OSV override 选择器上界改到 major 边界,以后只挪 target - #6117

Merged
qq9340100 merged 2 commits into
mainfrom
claude/issue-6095-override-upper-bounds
Aug 7, 2026
Merged

fix(deps): OSV override 选择器上界改到 major 边界,以后只挪 target#6117
qq9340100 merged 2 commits into
mainfrom
claude/issue-6095-override-upper-bounds

Conversation

@qq9340100

Copy link
Copy Markdown
Collaborator

Part of #6095 —— 只做 PM 在单上切出的可派发那一半(事实一里非 better-auth 的 OSV 类 override 上界重整)。#6095 保持 open,两项维护者决策仍挂在上面。

一、前提复核(先在最新 origin/main 实测,不照抄正文)

体检脚本 PR #6093 尚未合并,所以 origin/main 上还跑不出那份两栏报告。改用 PR #6093 的 head 版脚本作为只读探针(拷进 worktree 跑完即删,git status 干净,本 PR 不含 scripts/ 任何改动)对 f7f54a960 实测:

[report] Self-expiring selectors: 26 of 28 override(s) use a selector that excludes their own target.
[report] Consumer census: 4 of 28 override(s) name a package NOTHING in the dependency tree depends on.

26 / 28 与 4 条空转都成立,@hono/node-server 那条严格更差的也被单独标了 (gap: 2.0.5 .. 2.0.10 matches nothing)。前提有效。

三处成员数与出处的更正(实测口径;派发文案与 issue 正文都按 issue 的说法写了「12 条 better-auth / 14 条非 better-auth」):

说法 实测 说明
better-auth 家族 12 条 11 条 better-auth + core/scim/oauth-provider/sso + 6 个 adapter/telemetry
非 better-auth 命中 14 条 15 条 26 − 11 = 15
「AGENTS.md 明文写着」 AGENTS.md 没有这条 规则实际在 .claude/agents/os-dev.md:120 与本文件 undici 注释块里(两处成文,这也正是它属于「恢复既述不变量」而非新判断的依据)

15 条里再扣掉派发明确划为「零字节」的 3 条零消费者 override(@tootallnate/once / react-router / @sveltejs/kit,#5835 未表态),本 PR 实改 12 条。数字与派发文案的 14 对不上,是上面那条 11/12 的口径差 + 3 条零消费者两处叠加,按实测口径落地并在此记明,没有为了凑数把不该动的动了。

二、改了什么

12 条,上界一律移到 target 之上的 major 边界(0.x 线取 caret 边界 —— semver 的兼容性断点在那里):

minimatch@<10.2.3              -> minimatch@<11.0.0
tar@>=2.0.0 <7.5.11            -> tar@>=2.0.0 <8.0.0
form-data@<4.0.6               -> form-data@<5.0.0
undici@>=7.23.0 <7.29.0        -> undici@>=7.23.0 <8.0.0
uuid@<11.1.1                   -> uuid@<12.0.0
postcss@<8.5.10                -> postcss@<9.0.0
cookie@<0.7.0                  -> cookie@<0.8.0
brace-expansion@>=5.0.0 <5.0.9 -> brace-expansion@>=5.0.0 <6.0.0
sharp@>=0.34.0 <0.35.0         -> sharp@>=0.34.0 <0.36.0
@hono/node-server@<2.0.5       -> @hono/node-server@<3.0.0
fast-uri@<3.1.5                -> fast-uri@<4.0.0
hono@<4.12.34                  -> hono@<5.0.0

@hono/node-server 那条顺带修掉了严格更差的空窗:上界原本低于 target 下限,2.0.5 .. 2.0.10 谁都不覆盖。

⚠️ 两条 target 由精确版本改成 caret —— 这不是顺手,是不改就会造出新缺陷

minimatch: '10.2.3'cookie: '0.7.0' 的 target 是精确版本。只挪上界、留精确 target,会把 override 从「下限 pin」变成「把整个 major 钉死在那个旧版本」的天花板。实测不是假想:树里现有 minimatch 10.2.3 / 10.2.5 / 10.2.6 三份,minimatch@<11.0.0 配精确 target 10.2.3 会把 10.2.5 和 10.2.6 拽回 10.2.3 —— 当场违反本单「解析版本零位移」硬条款。

OSV pin 声明的是下限(「不许低于修复线」),所以 target 必须是能在 major 内向上浮的 range。改为 ^10.2.3 / ^0.7.0 后语义不变(仍是同一条修复线的下限),只是不再兼任天花板。这与文件里两条本来就没被报出的 override 同形(esbuild: '>=0.28.1'svelte: '^5.55.7',target 都是 range)。

注释

全部保留,只订正被本次改动变成事实错误的三处:undici 注释里「两份 undici 都在 selector 之外、现在什么都匹配不上」(<8.0.0 之后 7.29.0 那份回到范围内了)、brace-expansion 的「bound moves to <5.0.9」(现在动的是 target)、以及在 overrides 段首把这条选择器形状规则成文写进文件,连同两处刻意保留旧形状的 carve-out。better-auth 的 1.7.0 收口注记、scim 落后一档的注记等一字未动。

三、硬条款验收

1. 解析版本零位移(逐行证明)

pnpm-lock.yaml 全文 diff 只有 32 行,拆开是:

  • 12 行 override key(预期内)
  • 4 行 specifier: —— 见下
  • 0 行 version:。逐行比对:diff <(grep '^\s*version:' 基线) <(grep '^\s*version:' 本分支) 输出为空。

那 4 行 specifier:importers: 段里 override 生效后记录的声明 spec,不是解析结果:

apps/docs          postcss           ^8.5.25 -> ^8.5.10   (解析仍为 8.5.25)
(某包)             tar               ^7.5.22 -> ^7.5.11   (解析仍为 7.5.22)
plugin-hono-server @hono/node-server ^2.0.12 -> ^2.0.10   (解析仍为 2.0.12)
(另一处 devDep)    @hono/node-server ^2.0.12 -> ^2.0.10   (解析仍为 2.0.12)

这三个直接声明现在落进了加宽后的 selector 范围,于是 spec 被改写成 override target;target 是 caret,浮到 major 内最新,恰好就是原本解析到的那一版,所以解析零位移。这个「直接声明的 spec 被记成 override target」的行为是本文件既有且已被接受的:基线里 esbuild 那条(无 selector、全局生效)在 importers 里记的就是 specifier: '>=0.28.1'。本次只是把同一行为扩到另外 4 处。

顺带的正效果:check-override-consistency.mjs 主规则覆盖的已发布清单声明数从 2 条升到 5 条,且 5 条全部 resolve 到 override target —— 也就是「workspace 测一套、下游装另一套」这条护栏的覆盖面变大了

2. 门禁

门禁 结果
pnpm install --frozen-lockfile 通过(提交锁文件后复跑)
node scripts/check-override-consistency.mjs exit 0,✓ 5 published-manifest declaration(s) ... all resolve to their override targets.
PR #6093 探针(改后) 自失效上界一栏 26 → 14,@hono/node-server 的 gap 行消失;剩下的 14 条恰好就是刻意保留的两处 carve-out(11 条 better-auth + 3 条零消费者),exit 仍 0
node scripts/check-osv-exemptions.mjs(含 --self-test) 通过,零豁免
node scripts/check-nul-bytes.mjs OK(5857 个文件)
grep -naP 自查改动文件控制字节 无命中

3. osv-scanner —— 安全姿态不变(按 PR #6091 的离线库先例)

容器里 api.osv.dev 被代理拒(403),改用 workflow 同版本 osv-scanner v2.3.8 + --offline-vulnerabilities --download-offline-databases,对改前基线本分支各扫一次:

基线   (origin/main 的 pnpm-lock.yaml): found 1387 packages ... No issues found   exit 0
本分支 (pnpm-lock.yaml):                 found 1387 packages ... No issues found   exit 0

包数与结论完全一致 —— 这本就是零解析位移的必然推论:osv-scanner 读的是 packages: / snapshots: 里的 name@version,根本不读 overrides: 段。

四、反向验证 —— 方向在跑之前先写死

这里不是常规的「改前绿 / 改后红」:本单是能力增益,所以预言的方向是「旧形状会静默漏掉一份带洞的副本,新形状不会」。

场景:在 minimatch 上重演 #5032。假装 10.2.5 刚出公告,于是只把 target 抬到 ^10.2.6(这正是新形状承诺你可以只做的那一步)。树里 eslint@10.8.0 声明的是一条 ^10.x 范围,解析到 10.2.5。

配置 预言 实测 结果
A 旧上界 minimatch@<10.2.3 + target ^10.2.6 10.2.5 存活(^10.x 不是 <10.2.3 的子集,抬了 target 也够不着它) 锁文件里 minimatch@10.2.5minimatch@10.2.6 并存 ✅ 盲区复现
B 新上界 minimatch@<11.0.0 + 同一 target ^10.2.6 10.2.5 消失,10.x 全部落到 10.2.6 锁文件里只剩 minimatch@10.2.6 ✅ 盲区闭合
两者 10.2.3 都应消失(它满足不了 ^10.2.6) 两次都消失

A 里那份 10.2.5 就是「只挪 target」在旧形状下静默留下的带洞副本。跑完两轮后 pnpm-workspace.yaml / pnpm-lock.yaml 已逐字节还原(diff 为空),再复跑一次 --frozen-lockfile 与两个 check 确认。

补一条没有做成的反向验证,免得读成已验:undici 那条的等价实验跑不了 —— registry 上 7.x 的最高版本就是 7.29.0,没有更高的 7.x 可以拿来当「被抬上去的 target」。所以 undici 的收益是按 @ai-sdk/provider-utils 实际声明的 undici: ^7.28.0 出来的(^7.28.0 不是 <7.29.0 的子集、却是 <8.0.0 的子集),不是跑出来的;minimatch 那组才是跑出来的实证。

五、范围与 changeset

  • 只改 2 个文件:pnpm-workspace.yamlpnpm-lock.yaml
  • 未触碰:better-auth 家族 11 条;@tootallnate/once / react-router / @sveltejs/kit 三条零消费者 override;scripts/check-override-consistency*;content/docs/releases/未删除任何 override
  • 无 changeset:override 住在 workspace 配置里,不进任何已发布 manifest;本 PR 没有改动任何 package.json(git diff --name-only | grep -c package.json = 0),不发版。故需要 skip-changeset 标签 —— 按本单派发指令「do not self-apply labels」,本 agent 未自行打标,留给 PM。

Generated by Claude Code

12 条非 better-auth 的 OSV 类 override,排他上界从「钉死在自己 target 的版本线上」
改到 target 之上的 major 边界(0.x 线取 caret 边界)。这恢复的是 #4961 / #5032 已经
写死的仓规:上界压在 target 版本线上的形状,会在 target 自身出公告、需要往上挪的那天
当场失配 —— `undici@>=7.23.0 <7.28.0` 就是活体标本。

一并修正 `@hono/node-server@<2.0.5 -> ^2.0.10` 这条严格更差的:上界低于 target 下限,
2.0.5 .. 2.0.10 这段谁都不覆盖。现为 `<3.0.0 -> ^2.0.10`。

minimatch / cookie 两条的 target 由精确版本改为 caret(`10.2.3` -> `^10.2.3`,
`0.7.0` -> `^0.7.0`)。只挪上界而留精确 target,会把整个 major 钉死在那个旧版本上 ——
实测会把树里的 minimatch 10.2.5 / 10.2.6 拽回 10.2.3。OSV pin 声明的是下限,不是上限。

⛔ 未触碰:better-auth 家族 11 条(预发布兼容 pin,维护者裁决未定)、
@tootallnate/once / react-router / @sveltejs/kit 三条零消费者 override(#5835 未表态)。
未删除任何 override。

解析版本零位移:pnpm-lock.yaml 中没有任何一行 `version:` 变化,osv-scanner 离线库
扫描前后同为 1387 包、No issues found。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wbxm29qPKnLf44AbSxizqW
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 7, 2026 2:38am

Request Review

@github-actions github-actions Bot added size/s dependencies Pull requests that update a dependency file labels Aug 7, 2026
拉入 PR #6093(0664488)落地的 check-override-consistency 消费者体检,
以便用合入后的真体检报告复核本单枚举的 12 条成员。

Copy link
Copy Markdown
Collaborator Author

复核补记 —— PR #6093 已合入 main,枚举依据改用真体检报告重取

PM 在飞拦截提醒:#6093(0664488a8)在本单开工后合入了 origin/main,pnpm check:override-consistency 命令链与体检从此是真的。本分支已 git merge origin/main(合并提交 680617108,pnpm-lock.yaml / pnpm-workspace.yaml 零冲突 —— main 上锁文件最后一次改动仍是 #6091 d1151ac7a,早于本分支起点)。

先说结论:成员一致,原枚举不需要修正。

落地版脚本与本单此前用的只读探针逐字节相同:

diff <PR #6093 head 版探针> scripts/check-override-consistency.mjs   → 无差异

也就是说本 PR 正文第一节那份 26/28 的 BEFORE 报告,当时就是用合入的那个脚本跑出来的。

合并后用真命令复跑(两侧都取)

BEFORE —— 把 origin/mainpnpm-workspace.yaml / pnpm-lock.yaml 取回原地跑,跑完逐字节还原(git status 空):

[report] Consumer census: 4 of 28 override(s) name a package NOTHING in the dependency tree depends on.
[report] Self-expiring selectors: 26 of 28 override(s) use a selector that excludes their own target.
  - '@hono/node-server@<2.0.5' -> '^2.0.10'   (gap: 2.0.5 .. 2.0.10 matches nothing)
✓ 2 published-manifest declaration(s) covered ... all resolve to their override targets.

AFTER —— 本分支,pnpm check:override-consistency(含 --self-test),exit 0:

✓ self-test passed (17 assertions): consumers present are not reported,
  zero-consumer and self-expiring overrides are, and the manifest rule still
  separates reachable declarations from unreachable ones.

[report] Consumer census: 4 of 28 ...
[report] Self-expiring selectors: 14 of 28 override(s) use a selector that excludes their own target.
  - 'better-auth@<1.7.0-rc.2' ... (11 条 better-auth 家族)
  - '@tootallnate/once@<2.0.1' -> '2.0.1'
  - 'react-router@<8.3.0' -> '^8.3.0'
  - '@sveltejs/kit@<2.69.1' -> '^2.69.1'
✓ 5 published-manifest declaration(s) covered ... all resolve to their override targets.

26 → 14,@hono/node-servergap 行消失,剩下的 14 条逐条核对正是两处刻意保留的 carve-out(11 条 better-auth 预发布兼容 pin + 3 条 #5835 未表态的零消费者 override),一条不多一条不少 —— 本 PR 实改 12 条与之互为补集。已发布清单覆盖数 2 → 5(护栏覆盖面变大)。

⚠️ 派发文案里的「14 条」仍是按 issue 正文「12 条 better-auth」推的;实测 better-auth 家族是 11 条,故非 better-auth 命中为 15 条,再扣掉划为零字节的 3 条零消费者 = 实改 12 条。见正文第一节的更正表。巧合的是,改后剩余的自失效条目也正好是 14 条,和派发文案里那个 14 不是同一个 14,读的时候别串了。

合并前那一轮 CI(bb4b42623)

ESLint ✅、TypeScript Type Check ✅、Validate Package Dependencies ✅(这一条含真库 osv-scanner + check-override-consistency)、Build Core / Test Core / Dogfood Regression Gate 全绿。唯一红的是 Check Changeset —— 本 PR 零 package.json 改动、不发版,需要 skip-changeset 标签;按本单派发指令「do not self-apply labels」未自行打标,留给 PM。合并提交这一轮 CI 结果同理。


Generated by Claude Code


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

⚠️ 合并后那一跑的 Check Changeset 绿是假绿 —— 别当验收

合并 origin/main 之后重跑,全部 24 个 check 转绿,包括先前红的 Check Changeset这条绿不成立,本 PR 依然需要 skip-changeset

同一个 PR、同一份 diff(仍是零 package.json、零 .changeset/*.md),前后两跑判了相反的结果:

head 时间 Check for a changeset added by this PR
1 bb4b42623 02:22Z failure(正确)
2 680617108 02:39Z success(假绿)

原因不在本 PR:门禁数的是 git diff --diff-filter=A $BASE_SHA HEAD -- '.changeset/*.md',其中 BASE_SHA 是 PR 创建时钉死的 base.sha,而 HEADactions/checkout 默认签出的 merge ref(head 与当前 main tip 的合并)。这 17 分钟里 main 合进了 2 个带 changeset 的别人的 PR,它们就被算成了「本 PR 新增的 changeset」:

$ git diff --name-only --diff-filter=A 6513c1749 origin/main -- '.changeset/*.md'
.changeset/last-admin-guard-permission-set-row.md
.changeset/seed-autonumber-read-outage.md

两个都不是本 PR 写的。已按 Prime Directive #10 单开 #6129 记录该门禁缺陷(未认领、未在本 PR 里顺手修)。

对本 PR 的结论不变:两个真正的把关门禁 —— ESLint ✅ 与 TypeScript Type Check ✅ —— 以及本单最相关的 Validate Package Dependencies ✅(含真库 osv-scanner + pnpm check:override-consistency 命令链)在两跑里都是绿的,那些是实打实的。只有 Check Changeset 这一格的绿要按红来读,skip-changeset 标签仍需补上(按派发指令未自行打标)。


Generated by Claude Code


Generated by Claude Code

@qq9340100 qq9340100 added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 7, 2026 — with Claude
@qq9340100
qq9340100 marked this pull request as ready for review August 7, 2026 02:54
@qq9340100
qq9340100 added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 8195184 Aug 7, 2026
28 checks passed
@qq9340100
qq9340100 deleted the claude/issue-6095-override-upper-bounds branch August 7, 2026 03:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants