ci(release): gate the release PR on objectui pin freshness (#3340) - #4944
Merged
xuyushun441-sys merged 1 commit intoAug 3, 2026
Merged
Conversation
The frontend enters the changesets pipeline exactly once: when .objectui-sha moves and bump-objectui.sh writes the @objectstack/console changeset for the range it crossed. Everything objectui merged AFTER the pin is outside that range by construction — no changeset, no changelog, no release page — and a complete-looking release record is indistinguishable from a complete one. Cutting v16 that way lost four frontend changes, two of them minor features, while objectui main sat 4 commits and 21 pending changesets ahead of the pin. scripts/check-objectui-pin-fresh.mjs is red when the pin is not objectui main (or a named --ref), and names both the commits ahead and the .changeset/*.md files declared after the pin. git ls-remote alone decides the verdict, so the three GitHub API calls only itemize an already-established lag: a rate-limited or unreachable API degrades the report — loudly — and can never turn red into green. An unreachable remote is verdict `unreadable`, never a pass. Wired as the `Console Pin Freshness` job in a new workflow. It runs on every PR so the context always reports and can therefore be required in branch protection, but blocks only on the changesets Version Packages / release PR: a pin lagging between bumps is the normal state of an ordinary code PR, and failing every PR over it would train everyone to ignore the check. Not to be confused with ci.yml's Console Pin Gate (#4290), which proves the pinned SHA still BUILDS; this one proves the pin is still CURRENT. Either can be green while the other is red. The distinction is spelled out in the script header, in both workflows' output text and in docs/releases-maintenance.md. --self-test covers: a lagging pin is red and lists the changesets by name; a current pin is green; pending unbundled changesets are judged on their own; a diverged/behind pin is red; an unreadable API still yields red with the reason printed; a network failure never renders as FRESH in either mode. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 17:03
xuyushun441-sys
deleted the
claude/issue-3340-objectui-pin-freshness-gate
branch
August 3, 2026 17:13
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 #3340 (仅 P0;P1 auto-bump 与 P2 覆盖对账不在本次范围内 —— P1「换判据源」已由 #4731 / #4843 落地)。
为什么
前端只有一次机会进入 changesets 流水线:
.objectui-sha移动、bump-objectui.sh为它跨过的区间写下@objectstack/consolechangeset。pin 之后 objectui 合并的一切,按构造就在这个区间之外 —— 没有 changeset、没有 changelog、没有 release page。而一份「看起来完整」的发布记录,和一份真正完整的记录,读者无法分辨。v16 就是这样切的:发版时 objectui
main领先 pin 4 个提交 / 21 个 pending changeset,四条前端变更(其中两条minor特性)整体缺席,事后靠 #3331 手工补。#4731 / #4843 已经让两个消费者改读 objectui 声明的 changeset 而不是猜提交标题 —— 但一个正确的读者读一个过早停止的区间,给出的仍然是「看起来完整」的不完整清单。本 PR 堵的就是剩下的这个盲区。判红条件
scripts/check-objectui-pin-fresh.mjs(pnpm check:objectui-pin-fresh):main,--ref可指定 tag)—— 落后多少个提交、都是哪些提交,逐条列出;diverged/ pin 反超 ref 各自单独出声。.changeset/*.md—— 逐个文件名列出。第 2 条独立判定而不是挂在第 1 条下面:两者哪天不一致,就是其中一个错了,只看第 1 条的门禁不会发现。
挂载点
.github/workflows/objectui-pin-freshness.yml,job 名 = 分支保护 context 名:Console Pin Freshness。if:、没有 paths filter,因此在每个 PR 上都会汇报 —— 一个不运行的 check 什么也不报,而一个「required 却不汇报」的 context 会让每个 PR 永远卡在 Expected — waiting for status。changeset-release/main,或标题chore: version packages,两者都查,免得将来改了一个就静默解除)时判红阻挡;其余普通 PR 传--advisory,报告照打全文,只是不拦。普通代码 PR 期间 pin 落后是常态而非缺陷,每个 PR 都红只会训练所有人无视这个 check。workflow_dispatch手动跑按 enforcing 处理。workflow 不能把自己设成 required。 需要维护者在
main的分支保护里手动勾选:在此之前,本 workflow 在 release PR 上会汇报、会变红,但不会锁住 merge 按钮。这一点在 workflow 头部注释里也写明了,不假装 workflow 一己完成了强制。
与
Console Pin Gate(#4290)的区别 —— 名字相近,问的是相反的两件事ci.yml)main比两个门禁可以一个绿一个红:一个两个月前的 pin 构建得好好的(Pin Gate 绿),同时把两个月的前端发布挡在发布记录之外(本门禁红)。谁也不能替代谁。这段区别写在三处:脚本头部注释、两种判定的输出文案、
docs/releases-maintenance.md—— 防止后人当成重复实现删掉其中一个。网络失败绝不判绿
判据分层是刻意的:
git ls-remote独自决定判决 —— head == pin 判绿,head != pin 判红。pin 是最新的时候,一次 API 都不调。compare/< pin >...< head >+ 两端.changeset目录列表)只负责把已经成立的落后展开成清单。所以 API 被限流 / 被代理挡掉 / 挂了,只会让报告降级(并把原因原样打出来),永远不可能把红变成绿。ls-remote本身失败 → 判决unreadable:enforcing 模式 exit 1,advisory 模式打::warning::并 exit 0 —— 任何模式下都不会渲染成 FRESH。一个因网络错误而变绿的新鲜度门禁,和没有门禁等价,它同样会放过 v16 那次。本地
../objectui检出只用于进一步丰富报告(用 #4731/#4843 共享的classifyRange()走完整 log-walk),同样不参与判决;没有检出时出声说明远端那份 pending 清单只是端点 diff 的下界,不静默跳过(#4690 那一族)。双向证明(真实数据,非构造)
判红 —— 用一个真实的历史 pin
785b8a5d432c:判红 —— 本分支上
main当前真实的 pin(f5bc4c78be76),门禁今天就在响:注意其中两条带
!(breaking)。这正是当前若开一次 release PR 会被静默漏掉的内容。判绿 —— 把 pin 临时指向 objectui
mainHEAD(91757a79f2fe),验证后已还原:(
git status已确认.objectui-sha未被本 PR 改动。)--self-test(仓内 10 个 check 脚本的惯例)29 条断言全绿,覆盖题目要求的四类 + 端到端跑真实 CLI(含退出码):
--fixture < file >(自测专用,把远端状态从 JSON 读入,好让真实 CLI 的退出码也能被断言)每次运行都会先打一行⚠ REMOTE STATE READ FROM FIXTURE … — self-test output, not a real verdict.,不可能冒充真实判决。其他验证
pnpm exec eslint scripts/check-objectui-pin-fresh.mjs --no-inline-config—— 无输出(干净)。pnpm check:objectui-changeset(共享的classifyRange()消费者)仍全绿。pnpm check:nul-bytes/check:doc-authoring/check:published-files全绿。触碰的共享文件
package.json—— 只新增一行check:objectui-pin-fresh(紧邻check:objectui-changeset)。.github/workflows/ci.yml、未改lint.yml、未改release.yml—— 新增独立 workflow 文件,避开同批 测试替身比真实实现宽松:四个缺陷因此带着绿灯发布——需要一条把替身钉在真实契约上的闸门 #4550 / CI:Test Corestalls mid-suite with frozen log output — three occurrences in one day, each costing a manual diagnosis + rerun #4250 的并发冲突面。content/docs/releases/。changeset 用空 frontmatter(release-nothing)惯例。