Repository navigation
GitHub Release body 超 125k 上限:spec 的 rc 段已达 343k,RC 窗口内每次发布都会在 createGithubReleases 处失败(npm 已发出、Docker 被连带跳过) #4900
Description
Activity
- added a commit that references this issue
on Aug 4, 2026 ⛔ 认领:
session_015W6nhsDrz6zWQc8je12a1t(cloud 分片 + objectstack:identity 车道 PM,本条为维护者点名的跨车道代管),分支claude/issue-4900-release-body-limit,os-dev 单点派发。维护者 2026-08-04 裁定:本条进 v17 前处理。 它不是功能缺陷而是发版机器本身的故障:RC 窗口内每一次发布都会在同一处失败(spec 的 rc 段 342,911 字符 vs 上限 125,000,超 2.7 倍),且每次都以同样方式连带丢掉 Docker 镜像;17.0.0 GA 那一次只会更大。
方向取 1(自建 Release 并截断):不用 action 自带的
createGithubReleases,发布后自己调 API 建 Release,body 超限时截断并附 CHANGELOG 锚点链接。理由:方向 2 污染仓库里的 CHANGELOG 内容(本单自己不推荐),方向 3 会让 ADR-0087 D4 的spec-changes.json失去挂载点(需先给产物找新家,那是另一件事)。方向 1 彻底消除该类失败且保住 D4。同时按本单尾部记录修掉 #4899 recovery 步骤的两个缺陷:不带状态函数的
if:被 GitHub 隐式包了success()(导致 changesets 步骤失败时它被 skipped,恰好漏掉本场景);以及把它的契约从「缺失就补发」改为守「当前版本必须在 npm 上且必须有对应镜像」这个不变量。
Generated by Claude Code
PM 验收(第 19 轮,objectstack):ACCEPT — PR #5290,CI 绿后合入
按裁定的方向 1 落地,复核通过。两条最重的主张我在 GitHub API 上独立验证,均属实:
tag 我实测的 HTTP @objectstack/spec@16.1.0200 @objectstack/spec@17.0.0-rc.0404 @objectstack/spec@17.0.0-rc.1404 @objectstack/spec@17.0.0-rc.2404 这比本单立案时的描述严重:我以为是 rc.2 那一次失败,实际上 spec 的 Release 从 rc.0 起就没建成过 ——
gh release upload需要一个已存在的 Release 作为落点,所以 ADR-0087 D4 的spec-changes.json在整个 v17 RC 窗口里一直是没挂上的。这条同时也是方向 3(直接关掉createGithubReleases)不可行的实锤。另核实 #4901(db82f2e)确已在 main,dev 没有重复修那两个 recovery 缺陷,只在其上做扩展 —— 正确。验收要点:
- 对 action 行为的忠实性有硬证据:body 提取是
getChangelogEntry的逐行移植(含跳过代码围栏的逻辑,本仓 changeset 正文里真有## FROM → TO这种二级标题),并拿线上真实的@objectstack/cli@17.0.0-rc.2release body 逐字节比对,73,993 字符完全一致。这是「不改变现有行为」这类主张少见的强证明。 - 补上的三条性质都对:①有界 —— 按行边界截断,截断处若切开代码围栏会补闭合围栏(否则说明文字和 CHANGELOG 链接会被吞进代码块,截断唯一欠读者的东西恰好渲染不出来),不切代理对,计量用 UTF-16 code unit(对任何字符串 ≥ code point 数,无论 API 怎么理解「字符」都只会高估);②幂等 —— 先按 tag 查,存在 PATCH、不存在 POST,理由说得很实在:rc.2 那次 70 个里已经建成约 69 个,「在半成品集合上重跑」是常态不是例外;③按包隔离 —— action 原本把整组丢进一个
Promise.all,第一个 reject 就丢掉其余,所以某个包的坏 changelog 会连累 spec 拿不到 Release、D4 拿不到落点。顺序执行 + 收集失败 + 仍非零退出。 - D4 的挂载点保住了,而且比原来强:新步骤排在
Attach spec-changes.json之前(顺序 load-bearing,注释写明);release-spec-changes.sh新增RELEASE_VERSION兜底,使恢复路径也能挂上 D4 —— 旧代码里那句 warning 明说「这条路径不产生 Release 和 D4 附件」,现在做到了。为此把published(=docker 必须构建,原义未动)与新增的npm-published(=这里确实发了包,因此欠 Release)拆成两个语义,version改为无条件输出(原来只在「镜像缺失」分支才写,于是「npm 补发了但镜像恰好存在」这条路径上版本号会丢)。这几处的语义拆分是对的。 - 顺带解掉 chore: version packages #2191 的成因:关掉
createGithubReleases同时关掉了 action 自己的逐个 taggit push(它们在同一个if块内),而release-publish.sh早就用一次原子git push --tags抢在它前面 —— 那个 workaround 的成因本身没了(脚本保留)。这是收益不是损失,同意。 - 验证走真实代码路径:
pnpm check:release-body(=--self-test)49 条断言,用真实的packages/spec/CHANGELOG.mdrc.2 段落(342,893 → 123,938 ≤ 125,000);另有对着桩 GitHub API 跑真实main()(按 GitHub 规则真的在 125,000 处返回 422)与全工作区--dry-run(69 个包全部规划成功、只有 spec 一个被截断,其余 body 长度与线上已发布 release 逐个吻合:cli 73,993 / runtime 44,532 / types 6,433 / verify 10,426 / trigger-schedule 3,650)。 - 证据边界诚实:新增两个
if:的隐式success()行为依据 GitHub 文档与 ci(release): 让发布完整性守卫真的能触发,并把镜像也纳入它守的不变量 (#4900) #4901 已在真实 run 上确认的同一现象,未用act或真实 run 验证 —— 明说了。真正的证明是下一次发布。
⏳ 合入动作(draft→ready + auto-merge)需走 GraphQL,额度刚耗尽(数分钟后恢复),恢复即执行。
Generated by Claude Code
- 对 action 行为的忠实性有硬证据:body 提取是
PM 更正:关于 changeset 的返工指示,我错了 —— dev 的处置正确
Check Changeset 红了之后,我发了返工单,并且在里面写「如果没有包需要发版就用空 frontmatter 的 changeset(门禁明说这是正式声明,与
skip-changeset标签等价)」。这条指示是错的,dev 没有照做,而是用了skip-changeset标签,并把理由讲清楚了。我核实后确认它对:空 changeset 恰恰是 #4898 的致命输入。 #4898 的标题就写着「空 changeset 会静默卡死已 version 的发布:Release run 全绿,但 npm 和 Docker 什么都没发」——
changesets/action的分派逻辑在hasChangesets && !hasNonEmptyChangesets时走「All changesets are empty; not creating PR」那条 0 秒分支,于是版本号进了仓库、包没进注册表、流水线报绿。17.0.0-rc.2 就是这么卡住的。在一个专门修发布机器的 PR 里再种一个空 changeset,是本轮最不该犯的错。 门禁的提示文案把两者说成等价,但它们在
changesets/action眼里根本不等价 —— 标签是闸门层面的豁免,空 changeset 是喂给 action 的真实输入。这个提示文案本身值得改(我会另立单记),但我不该照着它开药方。另一个选项(加非空 changeset)更差:会把 fixed 组 69 个包全部 bump 一版,在 RC 窗口内为一个纯 CI 修复凭空多发一个 rc 号,并在版本记录里留下一次并不存在的产物变更。
skip-changeset标签已应用(labels 现为ci/cd, size/xl, dependencies, tooling, skip-changeset),同类的 #4899/#4901 也都是这么走的。验收维持 ACCEPT,CI 绿即合入。
Generated by Claude Code
- added a commit that references this issue
on Aug 4, 2026 - added a commit that references this issue
on Aug 4, 2026 - added a commit that references this issue
on Oct 7, 2026
现象
Release run 30823919428(
89d2a4e)第 16 步Create Release Pull Request or Publish to npm跑了 7 分 44 秒后 failure:失败发生在 npm 发布完成之后。实测注册表:
即包全发出去了、tag 也推了,只有 GitHub Release 创建失败 —— 但它把整个 step 标红,于是
published输出没置为'true',dockerjob 按if: needs.release.outputs.published == 'true'被跳过。17.0.0-rc.2 的运行时镜像因此没发(已用docker-publish.yml的workflow_dispatch手动补发)。根因:changelog 段落早已超出 API 上限
createGithubReleases: true把对应版本的 changelog 段落原样塞进 Release body。spec 作为 fixed 组里条目最密集的包,rc 段已经远超上限。这不是一次性故障:段落只会随 RC 窗口推进继续变大,所以窗口内每一次发布都会在同一处失败,并且每次都以同样的方式连带丢掉 Docker 镜像。17.0.0 GA 那一次只会更大。
可选方向(未决,需要维护者拍板)
createGithubReleases,改为发布后自己调 API 建 Release,body 超限时截断并附CHANGELOG.md的链接/锚点。彻底消除这类失败,且保住 ADR-0087 D4 —— spec-changes.json 仍有 Release 可挂。改动最大。createGithubReleases:最省事,但 ADR-0087 D4 的 spec-changes.json 是附到 spec 的 GitHub Release 上的,没有 Release 就没有落点 —— 需要先给那个产物找新家。与 #4898 的关系
#4898/#4899 修的是「空 changeset 导致 action 根本不进 publish 分支」,与本 issue 是不同的失败:那次是压根没发,这次是发了但 Release 创建失败。两者的共同后果都是
published != 'true'→ Docker 丢失,这一点由 #4899 引入的 recovery 步骤负责兜底 —— 但该步骤当前有两个缺陷,会另行修复:if:被 GitHub 隐式包了一层success(),所以 changesets 步骤失败后它被 skipped,恰恰漏掉了本 issue 这个场景;published置真、救不回 Docker。应改为守「当前版本必须在 npm 上且必须有对应镜像」这个不变量。