fix(ci): TypeScript Type Check 走 merge base,补上缺失的 fetch-depth: 0 (#6359) - #6459
Merged
Conversation
`lint.yml` 的 `typecheck` job 用 `actions/checkout@v7` 的默认 `fetch-depth: 1`, 于是 `resolveSurfaceBase()` 里的 `merge-base HEAD origin/main` 在这个 job 里 永远走不通,每次都落到 origin/main 的 tip。而合并 ref 随 main 前进而陈旧, tip != merge base,「main 新增的键」就被读成「本 PR 删掉的键」——方向恰好反了。 同文件的 ESLint job 已有同一句 `fetch-depth: 0`,但失效方向不同:那道门 shallow 时降级为不校验(假绿),这道门 shallow 时降级为误报红。 一并把 shallow 那行日志从「静默降级说明」改成点名方向的诊断:tip 锚下 main 新增 == 本分支删除,且若在 CI 则该 job 的 checkout 需要 fetch-depth: 0。 判决逻辑一行未动;把 fallback 本身显式化的那一半爆炸半径过大,拆到 #6452。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
hotlong
marked this pull request as ready for review
August 7, 2026 22:34
os-project-manager
added a commit
that referenced
this pull request
Aug 7, 2026
#6459 (#6359's stop-gap) landed the shallow diagnostic this PR's fallback replaces. Resolution keeps the re-anchor branch and hands #6359's wording to the one arm it still describes — the tip fallback, reached only when no upstream anchor is usable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AZgRyPVwi1jLb1mNNuUQ9o
This was referenced Aug 7, 2026
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.
Fixes #6359
.github/workflows/lint.yml的typecheckjob 用actions/checkout@v7的默认fetch-depth: 1,于是resolveSurfaceBase()(packages/spec/scripts/build-schemas.ts)里的merge-base HEAD origin/main在这个 job 里永远走不通,每次都落到 origin/main 的 tip。合并 ref 随 main 前进而陈旧 ⇒ tip ≠ merge base ⇒ 「main 上新增的键」被读成「本 PR 删掉的键」。同文件的 ESLint job(lint.yml:32-38)早有同一句fetch-depth: 0;1. 根因复现 —— checkout 深度与门内
--depth=1的相互作用(实测)这是本单最容易「看起来修了实际没修」的地方:门自己有一句
它会不会抵消 checkout 的
fetch-depth: 0?在隔离 sandbox 里按resolveSurfaceBase()的 git 序列逐字复现(⛔ 没有在 worktree 里跑--depth=1—— 那会把共享.git弄成 shallow):结论(实测):答案是有条件的否,而条件恰恰是本 PR 依赖的那一条。C 证明这句
--depth=1确实有能力把一个全量仓库变成 shallow 并弄坏merge-base;A 证明它被git rev-parse --verify --quiet origin/main^{commit}这个探针守着,而fetch-depth: 0恰好保证该引用存在 ⇒ 那句 fetch 一次都不会执行。所以本 PR 不是白做,但这个守卫是承重的 —— 已在resolveSurfaceBase()上方把这一点写成注释,免得下一个人「顺手」把它改成无条件 fetch 或把深度提上去。本地对照:本容器的 checkout 自身就是 shallow(
git rev-parse --is-shallow-repository⇒true),但本分支直接坐在origin/main之上,所需的 walk 是平凡的,所以merge-base仍成功、check:authorable-surfaceEXIT=0 且没有打印 shallow 那行。CI 里 HEAD 是合并 ref,depth=1 一刀就切在祖先上 —— 这就是差别。2. 范围 (2) 的评估结论:拆出 #6452,本 PR 只留纯诊断的一半
立单人建议一并把
resolveSurfaceBase()的 tip fallback 显式化。评估后拆开,依据是量到的爆炸半径:resolveSurfaceBase()的是build-schemas.ts的顶层裸块,没有if (CHECK)守卫(CHECK常量在 :109);process.exit(1)结束(:1907),同样不受CHECK守卫;gen:schema是@objectstack/spec的build的第一步(package.json:185)。⇒ 每一个 shallow checkout 且会构建 spec 的 job 都走这条 fallback:
ci.yml的build-core/test-gate/temporal-conformance/dogfood*(ci.yml:150那个fetch-depth: 0只属于testjob)、docker-publish/release/publish-smoke/showcase-smoke/scaffold-e2e/coverage-nightly/spec-liveness-check等。于是 issue 建议的两条处置各自撞上一条硬约束,不是「成本高」而是「方向错」:
resolveSurfaceBase()自己的文档注释早已判它死刑:「a deletion check that silently skips is the #4650 bypass with extra steps」真正稳妥的第三条路(改锚到 in-tree
authorable-surface.base.json的baseRev,而不是改判)需要重排verifyCommittedSurfaceBase()的验证互动 —— 否则会走进rev === resolved.rev快路径拿文件验文件,比现状更弱。那是一道有 #4650 / #5235 / #5358 / #5370 / #5847 / #5898 六单历史的门的设计决定,不该由一张「加一行fetch-depth」的卡顺手拍 ⇒ 按 PD#10 立 #6452(未认领,交分诊;正文带上面这份爆炸半径测量)。本 PR 保留的是纯诊断的一半:shallow 那行日志从「静默降级说明」改成点名方向的诊断。判决逻辑一行未动 ⇒ 行为零变更 ⇒ 爆炸半径为零。实测渲染(截自下面 B-before 那次真实运行,位置恰在假红正上方):
3. checkout 耗时 before/after(实测)
最干净的对照来自同一个 run 的两个 job(同一 commit、同一时刻、同一 runner 池),差别只有
fetch-depth:fetch-depth: 0)⇒ 预期增幅约 +7 s,落在一个 ~15 分钟的 job 上约 +0.8%,远低于 60 s 的折中阈值。本 PR 自己 run 上的实测值见下方「CI 实测」一节(本 PR 就是该 job 的活体测试)。⛔ 未改用有界
fetch-depth(50之类)—— 那是把「永远走不通」换成「偶尔走不通」,是更难诊断的同类缺陷。4. 反向验证 A / B / C(先申报、后执行)
三条断言的极性先写明:A 是否定式(结构上不会红:它断言某行日志不再出现)、B 是否定式 + 一个肯定式对照、C 是肯定式(必须红且点名)。
声明 A —— merge base 真的走得通
merge-base HEAD origin/main返回真实分叉点而非退化到 tip;最有判别力的证据是门自陈的那行日志:改前打印 shallow 锚点行,改后不再打印。merge-baseexit=0 且等于真实分叉点、跑完仍is-shallow=false。本地check:authorable-surfaceEXIT=0 且grep -c "shallow history|no merge base is walkable"= 0。本 PR run 上的真实 job 日志见「CI 实测」。check:authorable-surface有完整的 1613 schema 生成输出与merge base字样,不是空跑。声明 B —— 假红场景不再发生
申报:构造「分叉点落后于某个新增 authorable key 的提交」⇒ 改前该门误报删除、改后不报。
实测(端到端,不是论证):用
build-schemas-check-mode.test.ts既有的 git 沙箱 harness(写.git/shallow造截断),跑真实的门:status=1,门把 main 新增的键报成删除,与 CI:TypeScript Type Check缺fetch-depth: 0,authorable-surface 删除门把「main 新增的键」误判成「本 PR 删了键」 #6359 现场逐字同形:status=0,锚点落在真实分叉点,output不含deleted without proof、也不含该键。.git/shallow的有无。两次都跑到了门并产生了完整输出。说明:这四个探针用例是临时加入该文件跑完即撤的,未提交 —— 见下面「不在本 PR 里」的理由。
声明 C —— 真删除仍被抓(⛔ 最重要:本单绝不放宽删除门)
status=1,点名:status=0。这证明 C 的红是那条删除造成的,而不是环境里的既有红。@objectstack/spec全量 339 个测试文件 / 8641 个用例通过,其中build-schemas-check-mode.test.ts的 55 个用例(含多条deleted without proof的肯定式红断言)全绿 —— 删除门的判决面一行未动。5. 门禁 EXIT 表(均在
git add之后跑)pnpm check:workflow-status-functions(改 workflow 必跑)if:全部合规typecheck与lint两个 job 解析出的with都是{"fetch-depth":0}pnpm check:nul-bytesgrep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'(三个改动文件)pnpm --filter @objectstack/spec typecheckpackages/specbuild-schemas-check-mode.test.ts(55 用例)pnpm --filter @objectstack/spec check:authorable-surface(即 CI 那一步)6. 不在本 PR 里
resolveSurfaceBase()的 tip fallback 是静默的正确性降级 —— 拿不到 merge base 时它照样把「删除」判成违规并exit 1#6452(爆炸半径见第 2 节)。resolveSurfaceBase()的 tip fallback 是静默的正确性降级 —— 拿不到 merge base 时它照样把「删除」判成违规并exit 1#6452 的职责恰恰是把它消掉。所以探针用例只作证据跑,跑完撤回;resolveSurfaceBase()的 tip fallback 是静默的正确性降级 —— 拿不到 merge base 时它照样把「删除」判成违规并exit 1#6452 的验收里写明了新行为该在同一个 harness 里被钉住。fetch-depth⇒ ⛔ 明确不做(理由见第 3 节)。pr-automation.yml—— fix(ci): Check Changeset 的 skip-changeset 判定加一次「结算读」,首跑不再结构性必红 (#6378) #6429 在队列改它);未动 required 集;未动content/docs/releases/**。skip-changeset标签。Generated by Claude Code