Skip to content

fix(scripts): release 页 Console 段改按破坏性判据分节,Breaking changes 不再结构性永不渲染 (#6294) - #6392

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-6294-release-section-by-breaking
Aug 7, 2026
Merged

fix(scripts): release 页 Console 段改按破坏性判据分节,Breaking changes 不再结构性永不渲染 (#6294)#6392
hotlong merged 1 commit into
mainfrom
claude/issue-6294-release-section-by-breaking

Conversation

@hotlong

@hotlong hotlong commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #6294

scripts/objectui-range.mjs 的分节表按声明级别分节,首项 ['major', 'Breaking changes']。objectui 在发布窗内不声明 major(破坏性一律 minor + 作者正文标注,scripts/check-changeset-no-major.mjs 刻意守这条线),因此 ### Breaking changes 这个节头结构性永不渲染,而升级者最该先读的那一类被呈现在 ### Features 标题下。

本 PR 把首节的分节判据从「声明级别 == major」改为共享判据 r.breaking判据一字未改 —— 它在 scripts/objectui-changeset-digest.mjs 里,本 PR 只消费。

1. 前提复核(在 origin/main 上)

SECTIONS 现行形状,scripts/objectui-range.mjs:119-124(改前):

/** Declared level → the release-page heading it belongs under. */
const SECTIONS = [
  ['major', 'Breaking changes'],
  ['minor', 'Features'],
  ['patch', 'Fixes'],
];

r.breaking / r.breakingSource 确实可用 —— classifyRange 已经为每条 releasing 条目算出(objectui-changeset-digest.mjs:531-539,PR #6289 落下),而本文件第 80 行本来就在 import 并调用 classifyRange:

    const annotated = hasBreakingAnnotation(body);
    releasing.push({
      
      breaking: level === 'major' || annotated,
      breakingSource: level === 'major' ? 'declared-major' : annotated ? 'annotation' : null,
    });

真实区间实测(改前,f5bc4c78be76..f995a452d2ca,与 #6099 同一现场):64 条 releasing、0 条 major,只渲染出 ### Features / ### Fixes 两节,作者亲手标注的 4 条破坏性条目全部落在 Features 下。前提成立。

2. ⚠️ 节序断言的空绿审计(本单的硬要求)

分诊的假设是::363-364 那条节序断言「今天之所以通过,很可能正是因为那个节从不渲染」。实测把这个假设证伪了 —— 如实报告,不套模板。

改前它并不是空绿。 两条独立证据:

  1. 断言本身是肯定式的。 它的第一个合取项是存在性检查 indexOf('### Breaking changes') > -1,节不存在时直接判假;不存在时也不会退化成「-1 小于 indexOf(Features)」这种平凡真。
  2. fixture 里本来就有一条 major self-test 的形状 2(refactor(layout)!)显式声明 "@object-ui/layout": major,所以该节在 fixture 中确实渲染。用探针在改前的代码上跑同一 fixture:
--- headings (BEFORE) ---
### Breaking changes
### Features
### Fixes

所以「结构性永不渲染」是生产窗口的事实(objectui 从不声明 major),不是 self-test fixture 的事实。fixture 用的是 declared-major 这条在真实发布窗内不存在的路径。

真正的缺口不是空绿,而是覆盖错位: 改前这条断言只被 declared-major 承载,而真实世界唯一会走的 annotation 路径完全无覆盖。改后如果只换判据不动 fixture,断言仍会被同一条 major 承载,新代码路径一条断言也不碰 —— 那才是这一单真正的空绿风险。

改后靠什么承载(三层,逐层加严):

  • fixture 新增形状 6:minor + 作者 **BREAKING (v17)** 标注(仿真实提交 042e09d77),于是该节同时declared-majorannotation 两条来源承载;
  • 节序断言本身加严成三节全序 —— Breaking changes 先于 Features 先于 Fixes,每个合取项都是对本 fixture 真实渲染的节的存在性检查(新增形状 7 让 ### Fixes 也首次真的渲染,改前 fixture 里根本没有 patch 条目);
  • 新增一条只有 annotation 破坏性的节序断言:把 declared-major 条目从区间里滤掉后重渲染,### Breaking changes 仍须渲染且仍须领先。这条就是真实发布窗的形状,也是判据一旦退回 major 就必然转红的那条(见下方 B)。

3. 真实区间重放(f5bc4c78be76..f995a452d2ca)

                       改前            改后
### Breaking changes   (缺席)          4 条
### Features           14 条           10 条
### Fixes              50 条           50 条
条目总数                64              64

4 条作者标注的破坏性条目逐条归位:

042e09d77  ### Features  ->  ### Breaking changes
6e794a19e  ### Features  ->  ### Breaking changes
8ec406728  ### Features  ->  ### Breaking changes
d22ae31ce  ### Features  ->  ### Breaking changes

总数 64 -> 64:无丢失、无重复,只是换了标题。

4. 反向验证(先申报后执行)

声明 A —— 节活过来

申报:改前 ### Breaking changes 不出现,改后出现且恰好收进那 4 条。

实测:符合。 见上表(真实区间)与探针 fixture:改后 level=minor breaking=true src=annotation 的条目落到 ### Breaking changes(改前落在 ### Features)。

声明 B —— 变异体

申报(执行前写下):把首节判据退回 r.level === 'major'、保留全部断言,预测 3 条转红(两条归属断言 + annotation-only 节序断言),而三节全序断言不会红,因为 fixture 里仍有一条 major,该节照样渲染、照样领先。

实测:与申报逐条吻合,3 红。

  ✓ the three sections render in page order: Breaking changes, Features, Fixes
  ✗ a `minor` entry the AUTHOR annotated breaking is under Breaking changes
  ✗ that annotated entry is NOT left under Features
  ✓ sectioning consumes the verdict, it does not restate the level: still `minor`/annotation
  ✓ a `patch` merely MENTIONING "breaking" mid-sentence stays under Fixes
  ✓ grouping never filters: every releasing entry appears exactly once
  ✗ with NO declared `major` in range, Breaking changes still renders and still leads
⛔ objectui-range --self-test: 3 failure(s)

断言极性逐条标明:

断言 极性 变异体下 为什么
三节全序(Breaking 先于 Features 先于 Fixes) 肯定式(三个存在性合取) 绿 fixture 仍有一条 major,节照样渲染并领先。它守的是节序,不是判据 —— 单靠它抓不到本回归。这是本 PR 最该说清的一点。
标注条目 Breaking changes 节内 肯定式(成员归属) 该条目退回 Features,节内找不到。
标注条目不在 Features 节内 否定式,但有内容、非结构性 条目真实存在且真的会被渲染到 Features,所以否定式在此有判别力 —— 不是「因为什么都没产生所以通过」。
annotation-only 区间下节仍渲染且领先 肯定式(存在性优先) 滤掉 declared-major 后,级别键控下该节一条都取不到,indexOf 返回 -1,第一个合取项即判假。这条是本次改动的真正守卫。
「分组永不过滤:每条恰好出现一次」 肯定式(计数) 绿 变异体下 major/minor/patch 仍完备,不丢条目。
「消费判据而不复述级别:仍是 minor/annotation」 肯定式 绿 级别与 breakingSource 未被本 PR 触碰,本就该保持绿 —— 它守的是「判据没被改写」。

变异体已完全还原(grep -n MUTANT 无命中,还原后 self-test 21/21 绿)。

声明 C —— 非 breaking 条目不误入

申报:普通 minor/patch 仍进各自节,不因改判而漂到 Breaking 节。

实测:符合。 真实区间 Fixes 50 条纹丝不动,Features 恰好少掉那 4 条。fixture 侧新增形状 7 是近似样本:一条 patch,正文只在句中提到 "breaking"(Reordering here is technically breaking for anyone who relied on the churn…,仿真实的 9e9e9a92f),既不是强调标签也不在块首 —— 断言它必须留在 ### Fixes 且不得出现在 Breaking 节。这条从消费端钉住了判据的精度,而没有改判据。

声明 D —— 下游未破

申报:objectui-range.mjs 的既有消费者行为不变,至少跑它们的 self-test 取证。

实测:符合。 消费面已枚举:package.jsoncheck:objectui-changeset(digest + range 双自测)、scripts/check-objectui-pin-fresh.mjs(仅在帮助文本里提到本脚本)、docs/releases-maintenance.md(用法文档,用法未变)。scripts/bump-objectui.sh 走的是 buildDigest,不经过 renderRange。digest self-test 与 pin-fresh self-test 均全绿(见门禁表)。CLI 的 --json 形状未变(字段直出 classifyRange),只是 markdown 的标题归属变了。

5. 门禁 EXIT 表(均在 git add 之后跑)

门禁 EXIT 结果
pnpm check:objectui-changeset 0 digest self-test 全绿;objectui-range self-test 21/21 绿(改前 14 条)
pnpm exec eslint scripts/objectui-range.mjs --no-inline-config 0 无输出
pnpm check:nul-bytes 0 自测 56 断言 + 扫描 6046 个跟踪文本文件,无裸控制字节
控制字节自扫 grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]' grep=1 无命中(本 PR 未书写任何控制字符)
node scripts/check-objectui-pin-fresh.mjs --self-test 0 11 条全绿(下游)

6. 不在本 PR 里

  • scripts/objectui-changeset-digest.mjs —— 判据所在地,本 PR 只消费,一字未动。
  • content/docs/releases/** —— CLAUDE.md 铁律,发布页集中编写,绝不在代码 PR 里改。
  • v17.mdx —— v17.mdx 缺 rc.1 之后两次 console pin 移动的窗口段落(页面自述「that range needs its own section」未兑现) #6115 另有其单。
  • ⛔ 判据本身与收录集(哪些条目算 releasing)—— 均未触碰。
  • ⛔ 未加 .changeset/:scripts/ 工具链、不发布任何包,走 skip-changeset 路线。
  • 未给 Breaking 节内条目再加 **BREAKING** 前缀标记(digest 侧 markBreaking 的做法)—— 节头已经说明了这件事,且超出本单范围。

Generated by Claude Code

…#6294)

`scripts/objectui-range.mjs` 的分节表按**声明级别**分节,首项是
`['major', 'Breaking changes']`。而 objectui 在发布窗内不声明 `major` ——
破坏性一律 `minor` 加作者正文标注,`scripts/check-changeset-no-major.mjs`
刻意守着这条线。于是该节头结构性永不渲染,破坏性条目被呈现在 `### Features`
标题下,恰好是升级者最需要先读的那一类。

改为:首节按 `classifyRange` 已经算出的共享判据 `r.breaking` 抽取(#6099 /
PR #6289 落下的那半边),其余条目仍按声明级别分入 Features / Fixes。
判据一字未改 —— 本文件只消费,不复述;这正是 #6289 把判据放进共享实现
而不是放进 `buildDigest` 的原因。分节表对剩余条目做了完备性兜底:
任何级别表放不下的条目仍会被打印,分组是呈现,永不再变成过滤器(#4843)。

实测区间 `f5bc4c78be76..f995a452d2ca`(与 #6099 同一现场):
改前 `### Breaking changes` 缺席,4 条作者标注的破坏性条目全部落在 Features;
改后该节渲染并恰好收进这 4 条,Features 14 -> 10,Fixes 50 不变,
总条目 64 -> 64(无丢失、无重复)。

self-test 从 14 条增至 21 条,fixture 增加两个真实形状:`minor` + 作者
`**BREAKING (v17)**` 标注(仿 `042e09d77`),以及正文只在句中提到 "breaking"
的 `patch` 近似样本(仿 `9e9e9a92f`),后者必须留在 Fixes。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
@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 4:31pm

Request Review

@hotlong hotlong added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 7, 2026 — with Claude
@github-actions github-actions Bot added the size/m label Aug 7, 2026
@hotlong
hotlong marked this pull request as ready for review August 7, 2026 16:52
@hotlong
hotlong added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 9766d4f Aug 7, 2026
25 of 26 checks passed
@hotlong
hotlong deleted the claude/issue-6294-release-section-by-breaking branch August 7, 2026 17:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m 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.

objectui-range 的 release 页 Console 段按声明级别分节,### Breaking changes 在发布窗内结构性永不渲染(#6099 的同源另一半)

2 participants