feat(devx): 给 check:dev-prereqs 补上「陈旧 dist」判定(内容指纹,非 mtime) (#5864) - #6892
Merged
Merged
Conversation
check:dev-prereqs 此前只判存在性,#5726 的另一半——dist 在盘上但内容陈旧——仍无门禁, 而绿灯还替它作了一次没挣来的反向保证。 packages/spec 的 build 现在把自身构建输入的 sha256 打进 dist/.build-input-hash, 门禁重算并比对:两者不等即陈旧。判据是内容而非 mtime,所以 git worktree add / git checkout / touch / 时钟偏移都不会误报——这正是 PR #5863 拒绝做这半边的原因。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F8q5J1MQyocgtNspb15fSn
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 112 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
os-project-manager
marked this pull request as ready for review
August 9, 2026 03:20
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 #5864
问题
PR #5863 给
pnpm dev加了构建完整性前置,判据是存在性。这拦住了 #5726 的一半——产物缺失,它会大声失败。另一半没拦住:产物在盘上但陈旧,它不失败,它撒谎,而且撒的是别人代码的谎。#5726 那 20+ 条「看起来非常像真实类型契约漂移」的错误,每一条都是陈旧packages/spec/dist的假象——isAppResolvedDefaultToken自始至终好好地导出在src/里。更糟的是存在性门禁让这半边更具误导性:开发者刚被绿灯告知工作区没问题,随后出现的假漂移就更像真 bug。绿灯提供了一个它没挣来的反向保证——这正是本单立单的读数。
今晚 #6371 给这条留了一张新收据:仓库自己的 dev 契约现在开篇就写着「typecheck 前必须先构建依赖闭包,否则 tsc 读到的是别人留下的陈旧
dist/*.d.ts,而且它两个方向都会骗人」。陈旧的定义,以及它两个方向各会错在哪
戳由包自己的 build 脚本在最后一步写入(
node ../../scripts/check-dev-prereqs.mjs --stamp),门禁重算后比对。形状照抄scripts/check-console-sha.mjs(packages/console/dist/.objectui-sha对committed.objectui-sha)。输入集:
src/下全部文件、包清单、包自己的 tsconfig / tsup 配置,以及 turbo.json 的globalDependencies——最后一项是读出来的而不是抄一份,所以构建对「什么算全局输入」的声明也就是门禁的声明,两者无法悄悄漂移。缺席的文件按「缺席」入哈希,所以新建一个 tsconfig 也算变更。为什么是内容不是 mtime。 PR #5863 拒绝做这半边的理由是:检出会重写源文件 mtime,
src 比 dist 新会因为与构建无关的原因触发,而一个开局就误报的门禁会被第一个被它耽误的人关掉。内容指纹对这一切免疫——git worktree add、git checkout、恢复的备份、时钟偏移、touch,没有一个会改变文件字节。会误绿(说新鲜,其实不是) —— 全部写进文件头,不留隐含知识:
pnpm-lock.yaml刻意不是输入。锁文件几乎每次合并都动,把它入哈希就等于每次合并都强制重建放大器——正是本设计要避免的例行误报;而它能抓到的失败(依赖类型变了但 dist 其余部分是新的)不是 objectstack dev 在工作区未构建时刷 12 段无关命令的 MODULE_NOT_FOUND,唯一可执行的那条却指向错误修法 #5726 的形态。那一条仍由 AGENTS.md §9 的常备处方负责。OS_SKIP_DTS=1。该构建只出 JS、留下上一次的.d.ts,然后打戳。JS 确实新鲜,声明文件可能不是。本门禁从来不探.d.ts(dev 启动需要的是 JS),AGENTS.md §9 也已点名这个 flag——记录下来,而不是默默继承。会误红(说陈旧,其实没事):
pnpm dev会红。这条值得说清楚:它不是误报——dev 是从 dist 启动工作区的,改了但没重建的packages/spec确实在提供旧契约。重建,或者按文件头写的那样直接绕过(pnpm --filter @objectstack/example-showcase dev)。未打戳 = 红,不是警告,这是本 PR 唯一一处刻意偏离
check-console-sha的降级:后者的主体是可选的(CLI 没有它也能降级运行),重建是一次独立且慢的pnpm objectui:build;放大器的 dist 两条都不成立(它的缺失本来就是红,补救就是一句pnpm build)。降级成警告还会恰好豁免掉产生 #5726 的那棵树——一个由早于本戳的构建产出的 dist,而那正是本单的全部主题。找不到判据不是 exit 0 的许可(#4690)。为什么是声明清单而不是全部包。 实测:哈希
packages/spec/src约 30ms(687 文件 / 9.7MB),哈希全部包的源约 125ms——所以成本不是理由。理由在打戳侧:只有 build 会写戳的包才能被断言新鲜,而把这一行铺进 60+ 个 build 脚本,是在改每个包的构建方式,而那些包的陈旧 dist 是大声失败而不是撒谎。AGENTS.md §9 的表里只有一个 dist 会以别人的契约漂移的形态出现,就是packages/spec。两个方向都锁死,谁也漏不掉:列进 AMPLIFIERS 但 build 脚本不打戳 ⇒ 门禁按覆盖错误报红;从未列入的包调
--stamp⇒ 退出 1。反向验证(先写预测,再记实测)
全仓构建后在真实树上做,不是 fixture:
e82ed158…两次一致packages/spec/src/index.ts追加一个导出、不重建--stampC 与 F 是同一棵树上的同一时刻:
grep isAppResolvedDefaultToken5864在src/index.ts命中 1 次、在dist/index.mjs命中 0 次——旧门禁打印✓ 67 package build artifacts present并 exit 0,新门禁报红并给出唯一的 fix。绿灯确实在替陈旧背书,这是现场读数而非推理。绿灯措辞:声明范围,不越界
刻意没做
docs/adr/**。pnpm-lock.yaml入哈希(见上,例行误报)。.d.ts:本门禁从来不探,这次也没开始。自测
--self-test从 7 例扩到 16 例。新增的钉子里有三个是本设计的要害:第 10 例钉住 mtime 不是判据(字节相同、mtime 拨到未来 ⇒ 仍新鲜),第 13 例钉住声明即执行的双向,第 16 例钉住存在性优先于新鲜度(未构建的工作区只报一个前置条件,而且是构建那个)。变更集
@objectstack/specpatch:无 API / 类型 / 运行时变化;发布产物多一个 65 字节的dist/.build-input-hash,是构建自身的输入摘要,只被本仓的 dev 门禁读取。🤖 Generated with Claude Code
https://claude.ai/code/session_01F8q5J1MQyocgtNspb15fSn
Generated by Claude Code